diff --git a/.gitignore b/.gitignore index 814b7661bc61..b91db5ec1bc9 100644 --- a/.gitignore +++ b/.gitignore @@ -9,10 +9,16 @@ __pycache__/ *~ *.swp *.swo +*.kdev4 *# # QtCreator CMakeLists.txt.user +*.config +*.files +*.includes +*.creator +*.creator.user # ms-windows Thumbs.db diff --git a/.gitmodules b/.gitmodules index 2f52bfce372b..7af9169dfa32 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,20 +1,20 @@ [submodule "release/scripts/addons"] path = release/scripts/addons - url = ../blender-addons.git + url = https://github.com/UPBGE/blender-addons.git ignore = all branch = master [submodule "release/scripts/addons_contrib"] path = release/scripts/addons_contrib - url = ../blender-addons-contrib.git + url = git://git.blender.org/blender-addons-contrib.git ignore = all branch = master [submodule "release/datafiles/locale"] path = release/datafiles/locale - url = ../blender-translations.git + url = git://git.blender.org/blender-translations.git ignore = all branch = master [submodule "source/tools"] path = source/tools - url = ../blender-dev-tools.git + url = git://git.blender.org/blender-dev-tools.git ignore = all branch = master diff --git a/CMakeLists.txt b/CMakeLists.txt index 697f7345d4bd..8e96b12e01d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -209,7 +209,7 @@ mark_as_advanced(WITH_BLENDER) option(WITH_INTERNATIONAL "Enable I18N (International fonts and text)" ON) option(WITH_PYTHON "Enable Embedded Python API (only disable for development)" ON) -option(WITH_PYTHON_SECURITY "Disables execution of scripts within blend files by default" ON) +option(WITH_PYTHON_SECURITY "Disables execution of scripts within blend files by default" OFF) mark_as_advanced(WITH_PYTHON) # dont want people disabling this unless they really know what they are doing. mark_as_advanced(WITH_PYTHON_SECURITY) # some distributions see this as a security issue, rather than have them patch it, make a build option. @@ -239,12 +239,23 @@ option(WITH_BULLET "Enable Bullet (Physics Engine)" ON) option(WITH_SYSTEM_BULLET "Use the systems bullet library (currently unsupported due to missing features in upstream!)" ) mark_as_advanced(WITH_SYSTEM_BULLET) option(WITH_GAMEENGINE "Enable Game Engine" ${_init_GAMEENGINE}) + +option(WITH_GAMEENGINE_SECURITY "Disable game engine python debugging tools" OFF) +mark_as_advanced(WITH_GAMEENGINE_SECURITY) + +option(WITH_GAMEENGINE_GPU_SYNC "Enable GPU synchronization for VideoTexture module image rendering (ImageRender)" OFF) +mark_as_advanced(WITH_GAMEENGINE_GPU_SYNC) + if(APPLE) set(WITH_GAMEENGINE_DECKLINK OFF) else() option(WITH_GAMEENGINE_DECKLINK "Support BlackMagicDesign DeckLink cards in the Game Engine" ON) endif() -option(WITH_PLAYER "Build Player" OFF) + +option(WITH_GAMEENGINE_BPPLAYER "Enable Blend encrypted (from BPPlayer application) reading capabilities" ON) +mark_as_advanced(WITH_GAMEENGINE_BPPLAYER) + +option(WITH_PLAYER "Build Player" ON) option(WITH_OPENCOLORIO "Enable OpenColorIO color management" ${_init_OPENCOLORIO}) # Compositor @@ -289,6 +300,7 @@ endif() if(WITH_X11) option(WITH_X11_XINPUT "Enable X11 Xinput (tablet support and unicode input)" ON) + option(WITH_X11_XINERAMA "Enable multi-monitor support" ON) option(WITH_X11_XF86VMODE "Enable X11 video mode switching" ON) option(WITH_X11_XFIXES "Enable X11 XWayland cursor warping workaround" ON) option(WITH_X11_ALPHA "Enable X11 transparent background" ON) @@ -428,7 +440,11 @@ mark_as_advanced(WITH_CYCLES_DEBUG) mark_as_advanced(WITH_CYCLES_NATIVE_ONLY) option(WITH_CYCLES_DEVICE_CUDA "Enable Cycles CUDA compute support" ON) -option(WITH_CYCLES_DEVICE_OPENCL "Enable Cycles OpenCL compute support" ON) +if(APPLE) + option(WITH_CYCLES_DEVICE_OPENCL "Enable Cycles OpenCL compute support" OFF) # Disabling OpenCL for MacOSX to avoid crashes (temporary) +else() + option(WITH_CYCLES_DEVICE_OPENCL "Enable Cycles OpenCL compute support" ON) +endif() option(WITH_CYCLES_NETWORK "Enable Cycles compute over network support (EXPERIMENTAL and unfinished)" OFF) mark_as_advanced(WITH_CYCLES_DEVICE_CUDA) mark_as_advanced(WITH_CYCLES_DEVICE_OPENCL) @@ -520,6 +536,16 @@ if(CMAKE_COMPILER_IS_GNUCC) mark_as_advanced(WITH_LINKER_GOLD) endif() +# GCCFilter, if appliciable +if(CMAKE_COMPILER_IS_GNUCC) + option(WITH_COLOR_GCC "Use GCCFilter to color compiler output messages" OFF) + set(COLOR_GCC_OPTIONS "-c -r -w" CACHE STRING "Arguments that are passed to gccfilter when output coloring is switchend on. Defaults to -c -r -w.") + mark_as_advanced(COLOR_GCC_OPTIONS) + if(WITH_COLOR_GCC) + set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_SOURCE_DIR}/build_files/utils/gccfilter ${COLOR_GCC_OPTIONS}") + endif() +endif() + if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") option(WITH_COMPILER_ASAN "Build and link against address sanitizer (only for Debug & RelWithDebInfo targets)." OFF) mark_as_advanced(WITH_COMPILER_ASAN) @@ -638,9 +664,6 @@ if(NOT WITH_AUDASPACE) message(WARNING "WITH_JACK requires WITH_AUDASPACE which is disabled") set(WITH_JACK OFF) endif() - if(WITH_GAMEENGINE) - message(FATAL_ERROR "WITH_GAMEENGINE requires WITH_AUDASPACE") - endif() endif() if(NOT WITH_SDL AND WITH_GHOST_SDL) @@ -726,6 +749,7 @@ endif() if(WITH_GHOST_SDL OR WITH_HEADLESS) set(WITH_X11 OFF) set(WITH_X11_XINPUT OFF) + set(WITH_X11_XINERAMA OFF) set(WITH_X11_XF86VMODE OFF) set(WITH_X11_XFIXES OFF) set(WITH_X11_ALPHA OFF) @@ -890,6 +914,14 @@ if(WITH_X11) endif() endif() + if(WITH_X11_XINERAMA) + if(X11_Xinerama_LIB) + list(APPEND PLATFORM_LINKLIBS ${X11_Xinerama_LIB}) + else() + set(WITH_X11_XINERAMA OFF) + endif() + endif() + if(WITH_X11_XF86VMODE) # XXX, why dont cmake make this available? find_library(X11_Xxf86vmode_LIB Xxf86vm ${X11_LIB_SEARCH_PATH}) @@ -1287,7 +1319,7 @@ if(WITH_BULLET AND WITH_SYSTEM_BULLET) set(WITH_BULLET OFF) endif() else() - set(BULLET_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/extern/bullet2/src") + set(BULLET_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/extern/bullet/src") # set(BULLET_LIBRARIES "") endif() @@ -1723,7 +1755,9 @@ if(FIRST_RUN) info_cfg_text("Build Options:") info_cfg_option(WITH_GAMEENGINE) + info_cfg_option(WITH_GAMEENGINE_SECURITY) info_cfg_option(WITH_PLAYER) + info_cfg_option(WITH_GAMEENGINE_GPU_SYNC) info_cfg_option(WITH_BULLET) info_cfg_option(WITH_IK_SOLVER) info_cfg_option(WITH_IK_ITASC) @@ -1748,6 +1782,7 @@ if(FIRST_RUN) info_cfg_option(WITH_X11_XF86VMODE) info_cfg_option(WITH_X11_XFIXES) info_cfg_option(WITH_X11_XINPUT) + info_cfg_option(WITH_X11_XINERAMA) info_cfg_option(WITH_MEM_JEMALLOC) info_cfg_option(WITH_MEM_VALGRIND) info_cfg_option(WITH_SYSTEM_GLEW) diff --git a/README.md b/README.md new file mode 100644 index 000000000000..f7c2f668f9f0 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +![](doc/readme/GitHub_Readme1.png) + +UPBGE (**Uchronia Project Blender Game Engine**) is a fork of Blender created by Porteries Tristan (a Blender Game Engine developer) and some of his friends in September 2015. + +It's an independent branch, and its aim is to clean up and improve current Blender Game Engine (BGE) code, experiment with new features, and implement forgotten features that currently exist but have not been merged with the official Blender trunk. + +Currently, after the Blender Foundation's decision to delete BGE from next 2.8 release UPBGE becomes, de facto, the only one to follow the development of the Game Engine. This gives us even more freedom, if possible, to make certain decisions, since we will never, in any way, come into conflict with the official version. + +Its development cycle spans the course of 4 months: 3 months to add new features and refactors and 1 months to fix bugs. Then a new release is made available for download (around 3 or 4 per year). + +Regularly, the UPBGE merges the official Blender new patches, to stay up-to-date with the last Blender evolutions. + +The UPBGE team is composed of volunteers; BGE users who are interested in the game engine development, a web developer, and a communication manager. + +## What's new? +You can take a look at the release notes to see all the new features: +[UPBGE **Release Notes**](https://github.com/UPBGE/blender/wiki/Release-notes) + +## From The Team +We hope that new users will join the project, to help us test new features, report bugs, provide feedback and ideas to improve UPBGE (https://github.com/UPBGE/blender/issues), and that new developers will join the team to help us develop shiny new features for the game engine. + diff --git a/build_files/build_environment/cmake/ffmpeg.cmake b/build_files/build_environment/cmake/ffmpeg.cmake index 5c8347cd40e1..1a16c1ab1809 100644 --- a/build_files/build_environment/cmake/ffmpeg.cmake +++ b/build_files/build_environment/cmake/ffmpeg.cmake @@ -43,6 +43,7 @@ else() --enable-static --disable-shared --enable-libopenjpeg + --disable-sndio ) endif() @@ -112,6 +113,7 @@ ExternalProject_Add(external_ffmpeg --disable-indev=alsa --disable-outdev=alsa --disable-crystalhd + --disable-sndio BUILD_COMMAND ${CONFIGURE_ENV_NO_PERL} && cd ${BUILD_DIR}/ffmpeg/src/external_ffmpeg/ && make -j${MAKE_THREADS} INSTALL_COMMAND ${CONFIGURE_ENV_NO_PERL} && cd ${BUILD_DIR}/ffmpeg/src/external_ffmpeg/ && make install CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/ffmpeg ${DEFAULT_CMAKE_FLAGS} diff --git a/build_files/build_environment/cmake/sdl.cmake b/build_files/build_environment/cmake/sdl.cmake index 8383c5a5a79f..ab81ad130e88 100644 --- a/build_files/build_environment/cmake/sdl.cmake +++ b/build_files/build_environment/cmake/sdl.cmake @@ -25,6 +25,7 @@ else() -DSDL_STATIC=ON -DSDL_SHARED=OFF -DSDL_VIDEO=OFF + -DSNDIO=OFF ) endif() diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index 54a41f958199..d810bf766588 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -530,6 +530,8 @@ function(setup_liblinks #target_link_libraries(${target} ${PLATFORM_LINKLIBS} ${CMAKE_DL_LIBS}) target_link_libraries(${target} ${PLATFORM_LINKLIBS}) + + target_link_libraries(${target} ${TBB_LIBRARIES}) endfunction() @@ -607,6 +609,24 @@ function(SETUP_BLENDER_SORTED_LIBS) bf_editor_mask bf_editor_io + ge_blen_routines + ge_launcher + ge_blen_routines + ge_logic_ketsji + ge_converter + ge_phys_dummy + ge_phys_bullet + ge_logic_ketsji + ge_logic + ge_device + ge_rasterizer + ge_oglrasterizer + ge_common + ge_logic_expressions + ge_scenegraph + ge_logic_network + ge_videotex + bf_render bf_python bf_python_ext @@ -623,49 +643,45 @@ function(SETUP_BLENDER_SORTED_LIBS) bf_physics bf_nodes bf_rna + bf_dna bf_imbuf bf_blenlib bf_depsgraph - bf_intern_ghost - bf_intern_string bf_avi bf_imbuf_cineon bf_imbuf_openexr bf_imbuf_openimageio bf_imbuf_dds bf_collada + bf_blenfont + bf_blentranslation + + bf_intern_ghost + bf_intern_string + bf_intern_audaspace + bf_intern_mikktspace + bf_intern_dualcon + bf_intern_cycles bf_intern_elbeem bf_intern_memutil bf_intern_guardedalloc bf_intern_ctr bf_intern_utfconv - ge_blen_routines - ge_converter - ge_phys_dummy - ge_phys_bullet bf_intern_smoke + bf_intern_opencolorio + bf_intern_eigen + bf_intern_libmv + bf_intern_glew_mx + bf_intern_clog + extern_lzma extern_curve_fit_nd - ge_logic_ketsji extern_recastnavigation - ge_logic - ge_rasterizer - ge_oglrasterizer - ge_logic_expressions - ge_scenegraph - ge_logic_network - ge_logic_ngnetwork - ge_logic_loopbacknetwork - bf_intern_moto extern_openjpeg - ge_videotex - bf_dna - bf_blenfont - bf_blentranslation - bf_intern_audaspace - bf_intern_mikktspace - bf_intern_dualcon - bf_intern_cycles + extern_rangetree + extern_wcwidth + extern_sdlew + cycles_render cycles_graph cycles_bvh @@ -673,15 +689,6 @@ function(SETUP_BLENDER_SORTED_LIBS) cycles_kernel cycles_util cycles_subd - bf_intern_opencolorio - bf_intern_eigen - extern_rangetree - extern_wcwidth - bf_intern_libmv - extern_sdlew - - bf_intern_glew_mx - bf_intern_clog ) if(NOT WITH_SYSTEM_GLOG) @@ -747,13 +754,17 @@ function(SETUP_BLENDER_SORTED_LIBS) endif() if(WITH_BULLET AND NOT WITH_SYSTEM_BULLET) - list_insert_after(BLENDER_SORTED_LIBS "ge_logic_ngnetwork" "extern_bullet") + list(APPEND BLENDER_SORTED_LIBS extern_bullet) endif() if(WITH_GAMEENGINE_DECKLINK) list(APPEND BLENDER_SORTED_LIBS bf_intern_decklink) endif() + if(WITH_GAMEENGINE_BPPLAYER) + list(APPEND BLENDER_SORTED_LIBS bf_intern_spindle) + endif() + if(WIN32) list(APPEND BLENDER_SORTED_LIBS bf_intern_gpudirect) endif() diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake index b9c898e60d8f..286c9d8e7d07 100644 --- a/build_files/cmake/platform/platform_apple.cmake +++ b/build_files/cmake/platform/platform_apple.cmake @@ -86,7 +86,7 @@ endif() if(WITH_PYTHON) # we use precompiled libraries for py 3.5 and up by default - set(PYTHON_VERSION 3.6) + set(PYTHON_VERSION 3.7) if(NOT WITH_PYTHON_MODULE AND NOT WITH_PYTHON_FRAMEWORK) # normally cached but not since we include them with blender set(PYTHON_INCLUDE_DIR "${LIBDIR}/python/include/python${PYTHON_VERSION}m") @@ -331,6 +331,11 @@ if(WITH_OPENVDB) set(OPENVDB_DEFINITIONS) endif() +if(WITH_GAMEENGINE) + set(TBB_LIBRARIES ${LIBDIR}/tbb/lib/libtbb.a) + set(TBB_INCLUDE_DIR ${LIBDIR}/tbb/include) +endif() + if(WITH_LLVM) set(LLVM_ROOT_DIR ${LIBDIR}/llvm) set(LLVM_VERSION 3.4) diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index bc6ebeab97c4..219c703b7003 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -55,6 +55,7 @@ find_package_wrapper(JPEG REQUIRED) find_package_wrapper(PNG REQUIRED) find_package_wrapper(ZLIB REQUIRED) find_package_wrapper(Freetype REQUIRED) +find_package_wrapper(TBB REQUIRED) if(WITH_LZO AND WITH_SYSTEM_LZO) find_package_wrapper(LZO) diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake index 793e24d0c615..636c61e935db 100644 --- a/build_files/cmake/platform/platform_win32.cmake +++ b/build_files/cmake/platform/platform_win32.cmake @@ -527,6 +527,11 @@ if(WITH_SDL) set(SDL_LIBRARY ${SDL_LIBPATH}/SDL2.lib) endif() +if(WITH_GAMEENGINE) + set(TBB_LIBRARIES optimized ${LIBDIR}/tbb/lib/tbb.lib debug ${LIBDIR}/tbb/lib/tbb_debug.lib) + set(TBB_INCLUDE_DIR ${LIBDIR}/tbb/include) +endif() + # Audio IO if(WITH_SYSTEM_AUDASPACE) set(AUDASPACE_INCLUDE_DIRS ${LIBDIR}/audaspace/include/audaspace) diff --git a/build_files/utils/gccfilter b/build_files/utils/gccfilter new file mode 100755 index 000000000000..93e828aef65e --- /dev/null +++ b/build_files/utils/gccfilter @@ -0,0 +1,530 @@ +#!/usr/bin/perl -w + +=head1 NAME + +gccfilter - A filter for gcc diagnostic messages. + +=head1 SYNOPSIS + + gccfilter [ GCCFILTER SPECIFIC OPTIONS ] [ GCC COMMAND ] + +=head1 DESCRIPTION + +gccfilter is a filter to colorize and simplify (or expand) +gcc diagnostic messages. gccfilter is particularly aimed at g++ +(i.e. regarding C++) messages which can contain lot of +template-related errors or warnings difficult to understand. + +=head1 USAGE + +gccfilter takes as command line arguments, in that order, (1) gccfilter +specific options (documented in this page), followed by (2) a gcc command +(usally g++) with all it options and source files. + +=head1 EXAMPLE + +To compile F + + gccfilter --colorize --remove-template-args g++ -I./include test.cpp + +or, short version + + gccfilter -c -a g++ -I./include test.cpp + +To use in a Makefile, one can define the variable CXX as + + CXX="gccfilter -c -a g++" + +=head1 OPTIONS + +These are gccfilter specific options. These options can be stored in +a configuration file. See L. + +=over + +=item B<--help>|B<-h> + +display a short help message. + +=item B<--man>|B<-m> + +display the man page. + +=item B<--colorize>|B<-c> + +colorize output. + +=item B<--force-colorize>|B<-f> + +colorize output even if output is not a terminal. + +=item B<--remove-path>|B<-p> + +remove the path before source filenames (the path is replaced by C<...>). + +=item B<--remove-template-args>|B<-a> + +remove the template arguments between angle brackets. + +=item B<--replace-template-args>|B<-r> + +replace the template arguments with their values displayed in the with clause. + +=item B<--heide_with_clause>|B<-w> + +do not display the with clause. + +=item B<--hide-custom> I + +remove all lines that match any regex in I in the ORIGINAL output. +Be careful when escaping your regexes. + +=item B<--remove-namespaces>|B<-n> + +remove the namespaces specified by the B<--namespaces> option. +If the B<--namespaces> option is not given, removes all namespaces. + +=item B<--namespaces>|B<-s> I + +list of namepaces to remove with the B<--remove-namespaces> option. + +=item B<--remove-instantiated-from>|B<-i> + +remove all the "instantiated from I" lines. + +=back + +=head2 Color options + +These options specify the colors for each element of the diagnostic message. +The color specification I is a string of color attributes as defined +in L. To sum up: foreground color attributes are black, +red, green, yellow, blue, magenta, cyan, and white. Background color attributes +are on_black, on_red, on_green, on_yellow, on_blue, on_magenta, on_cyan, +and on_white. Non-color attributes are clear (or reset), bold, dark (or faint), +underline (or underscore), blink, reverse, and concealed. Case is not significant. +The options are: + +=over + +=item B<--color-filename>|B<-cf> I + +=item B<--color-linenum>|B<-cl> I + +=item B<--color-code>|B<-cc> I + +=item B<--color-withclause>|B<-cw> I + +=item B<--color-error-keyw>|B<-cek> I + +=item B<--color-error-mesg>|B<-cem> I + +=item B<--color-warning-keyw>|B<-cwk> I + +=item B<--color-warning-mesg>|B<-cwm> I + +=item B<--color-note-keyw>|B<-cnk> I + +=item B<--color-note-mesg>|B<-cnm> I + +=back + +Where keyw stands for keyword (C, C or C, depending on the type +of diagnostic) and mesg stands for message (the body of the diagnostic). Example of a +(flashy) colors specification: + + colorgcc -c --color-filename 'bold blink green on_red' g++ test.cpp + +=head1 FILES + +gccfilter uses L to allow the storage of commonly used options +in configuration files. gccfilter searches for configuration files named F<.gccfilter> +in the current working directory and then, if unsuccesfull in the home directory. The +format of the file is simple: it contains the options, as if thy were entered in the +command line (see L). + +=over + +=item F<$PWD/.gccfilter> + +Per directory configuration file. + +=item F<$HOME/.gccfilter> + +User's configuration file if the previous file does not exist. + +=back + +=head1 EXIT STATUS + +gccfilter exits with the status of the gcc command issued. + +=head1 LIMITATIONS + +gcc diagnostic messages are usually subject to localization. gccfilter does not +handle that and invokes gcc in the "C" locale. + +=head1 SEE ALSO + +gccfilter depends on the following perl modules: L, +L, L, L. + +The idea of gccfilter commes from L, a tool to colorize gcc output, +which seens to be unmaintained for years now. Yet the two programs do not share +a single line of code. + +=head1 AUTHOR + +Emmanuel Le Trong, L. + +=head1 CONTRIBUTORS + +Various GitHub users contributed to this project. +This version of gccfilter was obtained from +https://github.com/dichlofos/gccfilter + +Please do not hestiate to submit pull requests. + +=head1 COPYRIGHT + +Copyright 2010 by Emmanuel Le Trong. + +This is free software; see the source for copying conditions. +There is NO warranty; not even for MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. + +=cut + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 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, see . + +use warnings; +use strict; +use feature 'state'; +use File::Basename; +use IPC::Open3; +use IO::Select; +use Symbol; + +BEGIN{ push @INC, dirname(__FILE__) }; + +use Regexp::Common qw/balanced/; +use Getopt::ArgvFile (home=>1, current=>1); +use Getopt::Long qw/:config pass_through require_order/; +use Term::ANSIColor; + +my ( + $opt_remove_template_args, + $opt_remove_template_with, + $opt_remove_path, + $opt_remove_namespace, + $opt_colorize, + $opt_force_colorize, + @opt_namespaces, + $opt_expand_templates, + $opt_hide_with, + $opt_remove_inst, + @hide_custom, +); + +my %color = ( + file => 'bold black', + line => 'magenta', + code => 'cyan', + with => 'bold cyan', + error_keyw => 'bold red', + error_mesg => 'red', + warning_keyw => 'bold yellow', + warning_mesg => 'yellow', + note_keyw => 'bold green', + note_mesg => 'green', +); + +GetOptions ( + "colorize|c!" => \$opt_colorize, + "force-colorize|f!" => \$opt_force_colorize, + "remove-path|p!" => \$opt_remove_path, + "remove-instantiated-from|i!" => \$opt_remove_inst, + "remove-template-args|a!" => \$opt_remove_template_args, + "replace-template-args|r!" => \$opt_expand_templates, + "hide-with-clause|w!" => \$opt_hide_with, + "remove-namespaces|n!" => \$opt_remove_namespace, + "namespaces|s=s" => \@opt_namespaces, + + 'hide-custom|=s@{1,}' => \@hide_custom, + + "color-filename|cf=s" => \$color{file}, + "color-linenum|cl=s" => \$color{line}, + "color-code|cc=s" => \$color{code}, + "color-withclause|cw=s" => \$color{with}, + "color-error-keyw|cek=s" => \$color{error_keyw}, + "color-error-mesg|cem=s" => \$color{error_mesg}, + "color-warning-keyw|cwk=s" => \$color{warning_keyw}, + "color-warning-mesg|cwm=s" => \$color{warning_mesg}, + "color-note-keyw|cnk=s" => \$color{note_keyw}, + "color-note-mesg|cnm=s" => \$color{note_mesg}, + + "man|m!" => sub { + exec "pod2man $0 | man -l -"; + }, + + "help|h!" => sub { + print "Usage: gccfilter [options] [gcc command]\n". + "With options:\n". + " --help -h\n". + " --man -m (display man page)\n". + " --colorize -c\n". + " --force-colorize -f\n". + " --remove-path -p\n". + " --remove-template-args -a\n". + " --replace-templates-args -r\n". + " --hide-with-clause -w\n". + " --remove-namespaces -n\n". + " --namespaces -s \n". + " --hide-custom \n". + " --color-filename -cf \n". + " --color-linenum -cl \n". + " --color-code -cc \n". + " --color-withclause -cw \n". + " --color-error-keyw -cek \n". + " --color-error-mesg -cem \n". + " --color-warning-keyw -cwk \n". + " --color-warning-mesg -cwm \n". + " --color-note-keyw -cnk \n". + " --color-note-mesg -cnm \n"; + exit; + }, +); +@opt_namespaces = split(/,/,join(',',@opt_namespaces)); + +my %data; + +my $c_code = color ($color{code}); +my $c_reset = color ('reset'); +my %c; +$c{error} = color ($color{error_mesg}); +$c{warning} = color ($color{warning_mesg}); +$c{note} = color ($color{note_mesg}); + +sub col { + my $k = shift; + return '' unless $data{$k}; + return colored ($data{$k}, $color{$k}); +} +sub col_k { + my $k = shift; + return colored ($k, $color{$k.'_keyw'}); +} +sub col_m { + my $k = shift; + return '' unless $data{mesg}; + return colored ($data{mesg}, $color{$k.'_mesg'}); +} + +sub colorize { + $data{'file'} = col ('file'); + $data{'line'} = col ('line'); + + if ($_ = $data{keyw}){ + $data{keyw} = col_k ($_); + $data{mesg} = col_m ($_); + $data{'mesg'} =~ s/'(.+?)'/'$c_code$1$c_reset$c{$_}'/g; + } else { + $data{'mesg'} =~ s/'(.+?)'/'$c_code$1$c_reset'/g if $data{mesg}; + } +} + +sub remove_template_arg { + $data{'mesg'} =~ s/$RE{balanced}{-parens=>'<>'}/<>/g; + map { s/$RE{balanced}{-parens=>'<>'}/<>/g } values %{$data{'templates'}}; +} + +sub remove_custom { + foreach my $regex (@hide_custom){ + if($data{'orig'} =~ m/$regex/){ + $data{'ordr'} = 0; + return; + } + } +} + +sub remove_namespace { + my $re = join ('|', @opt_namespaces); + $data{'mesg'} =~ s/(?:$re):://g if $re; +} + +sub remove_path { + $data{'file'} =~ s/.+\//...\//g; +} + +# 2009-12-25: remove ellipsis of variadic templ. args. when expanding. +sub expand_templates { + foreach my $t (keys %{$data{'templates'}}) { + $data{'mesg'} =~ s/$t/$data{'templates'}->{$t}/g; + } +} + +sub build_with { + return unless defined $data{'templates'} && %{$data{'templates'}}; + if ($opt_colorize || $opt_force_colorize){ + $data{'with'} = " with " . join ('; ', + map { + colored ($_, $color{with}) . " = " . + colored ($data{'templates'}{$_}, $color{'with'}) + } keys %{$data{'templates'}}); + } else { + $data{'with'} = " with " . join ('; ', + map { "$_ = $data{'templates'}{$_}" } keys %{$data{'templates'}}); + } +} + +sub remove_instantiated { + state $on = 0; + if ($data{'mesg'} =~ /\s+instantiated from '/){ + if ($on) { + @data{'mesg', 'file', 'line', 'with', 'keyw'} = (''); + return; + } + @data{'file', 'line', 'with', 'keyw', 'mesg'} = ("(instantiation chain skipped)"); + $on = 1; + return; + } + $on = 0; +} + +# 2009-12-24: value ($v) can be an empty string! +# 2009-12-24: variadic template arguments : value of the last templ arg +# can be a comma-separated list ! +sub parse_with_clause { + my $str = shift; + my %data; + my $last_key = ''; + while ($str) { + # key + unless ($str =~ s/([^=]+) = //){ + $data{$last_key} .= ", $str"; + last; + } + (my $k = $1) =~ s/\w+ (\w+)/$1/; + $last_key = $k; + # value + my $v = ''; + my $prev_str = ''; + for (;;) { + last if $str eq '' || $str =~ /^[,;]/; + $str =~ s/[\w\*&:]*(?:$RE{balanced}{-parens=>'<>{}()'})?\s?//; + $v .= $&; + last if $str eq $prev_str; # str was immune to regexp, bail out + $prev_str = $str; + } + $data{$k} = $v; + $str =~ s/(?:[,;] )?//; + } + \%data; +} + +sub execute_program { + my @args = @_; + $ENV{'LANG'} = 'C'; + # http://stackoverflow.com/questions/10029406/why-does-ipcopen3-get-deadlocked + my @stdout; + my @stderr; + my $pid = open3(my $in, my $out, my $err = gensym(), @ARGV); + my $sel = new IO::Select; + $sel->add($out, $err); + while (my @fhs = $sel->can_read) { + foreach my $fh (@fhs) { + my $line = <$fh>; + unless (defined $line) { + $sel->remove($fh); + next; + } + if ($fh == $out) { + push @stdout, $line; + } elsif ($fh == $err) { + push @stderr, $line; + } else { + die "[ERROR]: This should never execute!"; + } + } + } + waitpid($pid, 0); + return (\@stdout, \@stderr, $? >> 8); +} + +if (! -t STDOUT) +{ + $opt_colorize = 0; +} + +my ($gcc_stdout_ref, $gcc_stderr_ref, $gcc_exit_code) = execute_program(@ARGV); + +# print gcc stdout without any processing +for (@$gcc_stdout_ref) { + print "$_"; +} + +# main parser +for (@$gcc_stderr_ref) { + # things like "In file included from ..." + if (/^([\w\s]+from) ([^:]+):(\d+)(:|,)$/){ + %data = ( + orig => $_, + mesg => $1, + file => $2, + line => $3, + eoli => $4, + ordr => 2 + ); + } elsif (/^([^:]+):(?:((?:\d+:)?\d+): | )(?:(error|warning|note): )?(.+)$/) { + %data = ( + orig => $_, + ordr => 1, + file => $1, + ); + $data{'line'} = $2 if defined $2; + $data{'keyw'} = $3 if defined $3; + my $rest = $4; + if ($rest =~ s/ \[with (.+?)\]//) { + my $with = $1; + $data{'templates'} = parse_with_clause ($with); + } + $data{'mesg'} = $rest; + } else { + print STDERR "$_"; + next; + } + + remove_custom () if @hide_custom; + expand_templates () if $opt_expand_templates; + remove_template_arg () if $opt_remove_template_args; + remove_namespace () if $opt_remove_namespace; + remove_path () if $opt_remove_path; + build_with () unless $opt_hide_with; + remove_instantiated () if $opt_remove_inst; + colorize () if $opt_colorize || $opt_force_colorize; + + my $str; + if ($data{'ordr'} == 1) { + $str = "$data{'file'}:" if $data{file}; + $str .= "$data{'line'}: " if $data{line}; + $str .= "$data{'keyw'}: " if $data{keyw}; + $str .= "$data{'mesg'}" if $data{mesg}; + $str .= "$data{'with'}" if $data{with}; + } elsif ($data{'ordr'} == 2) { + $str = "$data{'mesg'} $data{'file'}:$data{line}$data{'eoli'}"; + } + print STDERR "$str\n" if $str; +} +exit($gcc_exit_code); + diff --git a/doc/python_api/rst/bge.app.rst b/doc/python_api/rst/bge.app.rst index e8b91ffbcafb..ed9de67b0443 100644 --- a/doc/python_api/rst/bge.app.rst +++ b/doc/python_api/rst/bge.app.rst @@ -29,6 +29,21 @@ Module to access application values that remain unchanged during runtime. :type: str +.. data:: upbge_version + + The UPBGE version as a tuple of 3 ints, eg. (0, 0, 3). + + .. note:: Version tuples can be compared simply with (in)equality symbols; + for example, ``(0, 0, 2) <= (0, 0, 3)`` returns True (lexical order). + + :type: tuple of three ints + +.. data:: upbge_version_string + + The UPBGE version formatted as a string, eg. "0.0 (sub 3)". + + :type: str + .. data:: has_texture_ffmpeg True if the BGE has been built with FFmpeg support, diff --git a/doc/python_api/rst/bge.constraints.rst b/doc/python_api/rst/bge.constraints.rst index 3cca22e9cff4..d4ef2c611d30 100644 --- a/doc/python_api/rst/bge.constraints.rst +++ b/doc/python_api/rst/bge.constraints.rst @@ -81,6 +81,16 @@ Functions :return: A constraint wrapper. :rtype: :class:`~bge.types.KX_ConstraintWrapper` +.. function:: createVehicle(physicsid) + + Creates a vehicle constraint. + + :arg physicsid: The physics id of the chassis object in constraint. + :type physicsid: int + + :return: A vehicle constraint wrapper. + :rtype: :class:`~bge.types.KX_VehicleWrapper` + .. function:: exportBulletFile(filename) Exports a file representing the dynamics world (usually using ``.bullet`` extension). diff --git a/doc/python_api/rst/bge.events.rst b/doc/python_api/rst/bge.events.rst index 42135926fdab..93d41ca76528 100644 --- a/doc/python_api/rst/bge.events.rst +++ b/doc/python_api/rst/bge.events.rst @@ -20,7 +20,7 @@ This module holds key constants for the SCA_KeyboardSensor. sensor = co.sensors["Keyboard"] sensor.key = bge.events.F1KEY - code-block:: python +.. code-block:: python # Do the all keys thing import bge @@ -29,9 +29,9 @@ This module holds key constants for the SCA_KeyboardSensor. # 'Keyboard' is a keyboard sensor sensor = co.sensors["Keyboard"] - for key,status in sensor.events: - # key[0] == bge.events.keycode, key[1] = status - if status == bge.logic.KX_INPUT_JUST_ACTIVATED: + for key, input in sensor.inputs: + # key[0] == bge.events.keycode = event.type, key[1] = input + if bge.logic.KX_INPUT_JUST_ACTIVATED in input.queue: if key == bge.events.WKEY: # Activate Forward! if key == bge.events.SKEY: @@ -41,7 +41,7 @@ This module holds key constants for the SCA_KeyboardSensor. if key == bge.events.DKEY: # Activate Right! - code-block:: python +.. code-block:: python # The all keys thing without a keyboard sensor (but you will # need an always sensor with pulse mode on) @@ -51,13 +51,13 @@ This module holds key constants for the SCA_KeyboardSensor. keyboard = bge.logic.keyboard JUST_ACTIVATED = bge.logic.KX_INPUT_JUST_ACTIVATED - if keyboard.events[bge.events.WKEY] == JUST_ACTIVATED: + if JUST_ACTIVATED in keyboard.inputs[bge.events.WKEY].queue: print("Activate Forward!") - if keyboard.events[bge.events.SKEY] == JUST_ACTIVATED: + if JUST_ACTIVATED in keyboard.inputs[bge.events.SKEY].queue: print("Activate Backward!") - if keyboard.events[bge.events.AKEY] == JUST_ACTIVATED: + if JUST_ACTIVATED in keyboard.inputs[bge.events.AKEY].queue: print("Activate Left!") - if keyboard.events[bge.events.DKEY] == JUST_ACTIVATED: + if JUST_ACTIVATED in keyboard.inputs[bge.events.DKEY].queue: print("Activate Right!") diff --git a/doc/python_api/rst/bge.logic.rst b/doc/python_api/rst/bge.logic.rst index 5cdb8ebfee91..7e57ada58678 100644 --- a/doc/python_api/rst/bge.logic.rst +++ b/doc/python_api/rst/bge.logic.rst @@ -42,7 +42,7 @@ See the sensor's reference for available methods: * :class:`~bge.types.KX_NetworkMessageSensor` * :class:`~bge.types.KX_RadarSensor` * :class:`~bge.types.KX_RaySensor` - * :class:`~bge.types.KX_TouchSensor` + * :class:`~bge.types.KX_CollisionSensor` * :class:`~bge.types.SCA_DelaySensor` * :class:`~bge.types.SCA_JoystickSensor` * :class:`~bge.types.SCA_KeyboardSensor` @@ -156,6 +156,12 @@ General functions .. note:: Scenes in your blend file that have not been converted wont be in this list. This list will only contain scenes such as overlays scenes. +.. function:: getInactiveSceneNames() + + Gets a list of the scene's names not loaded in the game engine. + + :rtype: list of string + .. function:: loadGlobalDict() Loads bge.logic.globalDict from a file. @@ -179,7 +185,7 @@ General functions Restarts the current game by reloading the .blend file (the last saved version, not what is currently running). -.. function:: LibLoad(blend, type, data, load_actions=False, verbose=False, load_scripts=True, async=False) +.. function:: LibLoad(blend, type, data, load_actions=False, verbose=False, load_scripts=True, asynchronous=False, scene=None) Converts the all of the datablocks of the given type from the given blend. @@ -195,8 +201,10 @@ General functions :type verbose: bool :arg load_scripts: Whether or not to load text datablocks as well (can be disabled for some extra security) :type load_scripts: bool - :arg async: Whether or not to do the loading asynchronously (in another thread). Only the "Scene" type is currently supported for this feature. - :type async: bool + :arg asynchronous: Whether or not to do the loading asynchronously (in another thread). Only the "Scene" type is currently supported for this feature. + :type asynchronous: bool + :arg scene: Scene to merge loaded data to, if `None` use the current scene. + :type scene: :class:`bge.types.KX_Scene` or string :rtype: :class:`bge.types.KX_LibLoadStatus` @@ -261,7 +269,7 @@ General functions :arg gravity: gravity vector :type gravity: Vector((fx, fy, fz)) -.. function:: getSpectrum() +.. function:: getSpectrum() (Deprecated) Returns a 512 point list from the sound card. This only works if the fmod sound driver is being used. @@ -338,28 +346,6 @@ General functions .. warning: Not implimented yet -.. function:: getAnimRecordFrame() - - Gets the current frame number used for recording animations. This - number is incremented automatically by Blender when the "Record - animation" feature is turned on. - - :rtype: int - -.. function:: setAnimRecordFrame(framenr) - - Sets the current frame number used for recording animations. This - number is automatically incremented by Blender when the "Record - animation" feature is turned on. - - The frame number Must be non-negative, unless Blender has - :attr:`bpy.types.UserPreferencesEdit.use_negative_frames` enabled - in its user preferences. Only use non-negative numbers to be on - the safe side, unless you know what you are doing. - - :arg framenr: The new frame number. - :type framenr: int - .. function:: getExitKey() Gets the key used to exit the game engine @@ -1319,6 +1305,8 @@ Navigation Mesh Draw Modes Shader ------ +.. _shader-defined-uniform: + .. data:: VIEWMATRIX .. data:: VIEWMATRIX_INVERSE .. data:: VIEWMATRIX_INVERSETRANSPOSE @@ -1337,6 +1325,8 @@ Shader .. data:: CONSTANT_TIMER +.. data:: EYE + User a timer for the uniform value. .. data:: SHD_TANGENT diff --git a/doc/python_api/rst/bge.render.rst b/doc/python_api/rst/bge.render.rst index 02c3beef6727..03a9463089ff 100644 --- a/doc/python_api/rst/bge.render.rst +++ b/doc/python_api/rst/bge.render.rst @@ -58,14 +58,20 @@ Constants .. data:: KX_TEXFACE_MATERIAL + Deprecated. + Materials as defined by the texture face settings. .. data:: KX_BLENDER_MULTITEX_MATERIAL + Deprecated. + Materials approximating blender materials with multitexturing. .. data:: KX_BLENDER_GLSL_MATERIAL + Deprecated. + Materials approximating blender materials with GLSL. .. DATA:: VSYNC_OFF @@ -90,48 +96,23 @@ Constants Right eye being used during stereoscopic rendering. -.. data:: RAS_OFS_RENDER_BUFFER - - The pixel buffer for offscreen render is a RenderBuffer. Argument to :func:`offScreenCreate` - -.. data:: RAS_OFS_RENDER_TEXTURE - - The pixel buffer for offscreen render is a Texture. Argument to :func:`offScreenCreate` - - -***** -Types -***** - -.. class:: RASOffScreen - - An off-screen render buffer object. +.. _render-hdr: - Use :func:`offScreenCreate` to create it. - Currently it can only be used in the :class:`bge.texture.ImageRender` - constructor to render on a FBO rather than the default viewport. +--- +HDR +--- - .. attribute:: width +.. data:: HDR_NONE - The width in pixel of the FBO + Use 8 bit per channel image format. - :type: integer +.. data:: HDR_HALF_FLOAT - .. attribute:: height + Use 16 bit float per channel image format. - The height in pixel of the FBO - - :type: integer - - .. attribute:: color - - The underlying OpenGL bind code of the texture object that holds - the rendered image, 0 if the FBO is using RenderBuffer. - The choice between RenderBuffer and Texture is determined - by the target argument of :func:`offScreenCreate`. - - :type: integer +.. data:: HDR_FULL_FLOAT + Use 32 bit float per channel image format. ********* Functions @@ -188,7 +169,7 @@ Functions .. function:: makeScreenshot(filename) - Writes an image file with the current displayed frame. + Writes an image file with the displayed image at the frame end. The image is written to *'filename'*. The path may be absolute (eg. ``/home/foo/image``) or relative when started with @@ -232,7 +213,7 @@ Functions .. function:: setBackgroundColor(rgba) - Deprecated and no longer functional. Use :py:meth:`bge.types.KX_WorldInfo.backgroundColor` instead. + Deprecated and no longer functional. Use :data:`bge.types.KX_WorldInfo.horizonColor` or :data:`bge.types.KX_WorldInfo.zenithColor` instead. .. function:: setEyeSeparation(eyesep) @@ -274,6 +255,8 @@ Functions .. function:: setMaterialMode(mode) + Deprecated and no longer functional. + Set the material mode to use for OpenGL rendering. :arg mode: material mode @@ -284,6 +267,8 @@ Functions .. function:: getMaterialMode(mode) + Deprecated and no longer functional. + Get the material mode to use for OpenGL rendering. :rtype: KX_TEXFACE_MATERIAL, KX_BLENDER_MULTITEX_MATERIAL, KX_BLENDER_GLSL_MATERIAL @@ -345,7 +330,7 @@ Functions :arg toVec: the end of the line :type toVec: list [x, y, z] :arg color: the color of the line - :type color: list [r, g, b] + :type color: list [r, g, b, a] .. function:: enableMotionBlur(factor) @@ -404,22 +389,3 @@ Functions Get the current vsync value :rtype: One of VSYNC_OFF, VSYNC_ON, VSYNC_ADAPTIVE - -.. function:: offScreenCreate(width,height[,samples=0][,target=bge.render.RAS_OFS_RENDER_BUFFER]) - - Create a Off-screen render buffer object. - - :arg width: the width of the buffer in pixels - :type width: integer - :arg height: the height of the buffer in pixels - :type height: integer - :arg samples: the number of multisample for anti-aliasing (MSAA), 0 to disable MSAA - :type samples: integer - :arg target: the pixel storage: :data:`RAS_OFS_RENDER_BUFFER` to render on RenderBuffers (the default), - :data:`RAS_OFS_RENDER_TEXTURE` to render on texture. - The later is interesting if you want to access the texture directly (see :attr:`RASOffScreen.color`). - Otherwise the default is preferable as it's more widely supported by GPUs and more efficient. - If the GPU does not support MSAA+Texture (e.g. Intel HD GPU), MSAA will be disabled. - :type target: integer - :rtype: :class:`RASOffScreen` - diff --git a/doc/python_api/rst/bge.texture.rst b/doc/python_api/rst/bge.texture.rst index cd99cde0bc89..9d4937b28c7e 100644 --- a/doc/python_api/rst/bge.texture.rst +++ b/doc/python_api/rst/bge.texture.rst @@ -407,7 +407,7 @@ Image classes :type: bool -.. class:: ImageMirror(scene, observer, mirror, material=0) +.. class:: ImageMirror(scene, observer, mirror, material=0, width, height, samples, hdr) Image source from mirror. @@ -420,6 +420,14 @@ Image classes :type mirror: :class:`~bge.types.KX_GameObject` :arg material: ID of the mirror's material to be used for mirroring. (optional) :type material: int + :arg width: Off-screen render buffer width (optional). + :type width: integer + :arg height: Off-screen render buffer height (optional). + :type height: integer + :arg samples: Off-screen render buffer samples (optional). + :type samples: integer + :arg hdr: Off-screen image format (optional). + :type hdr: One of :ref:`these constants` .. attribute:: alpha @@ -427,11 +435,35 @@ Image classes :type: bool + .. attribute:: horizon + + Horizon color. + + :type: float list [r, g, b, a] in [0.0, 1.0] + + .. attribute:: zenith + + Zenith color. + + :type: float list [r, g, b, a] in [0.0, 1.0] + .. attribute:: background - Background color. + :type: float list [r, g, b, a] in [0.0, 1.0] + + Deprecated use :py:meth:`bge.texture.ImageMirror.horizon` or :py:meth:`bge.texture.ImageMirror.zenith` instead. + + .. attribute:: updateShadow + + Choose to force shadow buffer update if there is a gap beetween image rendered and shadows. + + :type: bool + + .. attribute:: colorBindCode + + Off-screen color texture bind code. - :type: int or float list [r, g, b, a] in [0.0, 255.0] + :type: integer .. attribute:: capsize @@ -624,7 +656,7 @@ Image classes :type: bool -.. class:: ImageRender(scene, camera) +.. class:: ImageRender(scene, camera, width, height, samples, hdr) Image source from a render of a non active camera. The render is done on a custom framebuffer object if fbo is specified, @@ -634,8 +666,14 @@ Image classes :type scene: :class:`~bge.types.KX_Scene` :arg camera: Camera from which the image has to be taken. :type camera: :class:`~bge.types.KX_Camera` - :arg fbo: Off-screen render buffer object (optional) - :type fbo: :class:`~bge.render.RASOffScreen` + :arg width: Off-screen render buffer width (optional). + :type width: integer + :arg height: Off-screen render buffer height (optional). + :type height: integer + :arg samples: Off-screen render buffer samples (optional). + :type samples: integer + :arg hdr: Off-screen image format (optional). + :type hdr: One of :ref:`these constants` .. attribute:: alpha @@ -643,11 +681,37 @@ Image classes :type: bool + .. attribute:: horizon + + Horizon color. + + :type: float list [r, g, b, a] in [0.0, 1.0] + + .. attribute:: zenith + + Zenith color. + + :type: float list [r, g, b, a] in [0.0, 1.0] + .. attribute:: background Background color. - :type: int or float list [r, g, b, a] in [0.0, 255.0] + :type: float list [r, g, b, a] in [0.0, 1.0] + + Deprecated use :py:meth:`bge.texture.ImageRender.horizon` or :py:meth:`bge.texture.ImageRender.zenith` instead. + + .. attribute:: updateShadow + + Choose to force shadow buffer update if there is a gap beetween image rendered and shadows. + + :type: bool + + .. attribute:: colorBindCode + + Off-screen color texture bind code. + + :type: integer .. attribute:: capsize @@ -1032,6 +1096,7 @@ Image classes :rtype: bool + *************** Texture classes *************** diff --git a/doc/python_api/rst/bge_types/bge.types.BL_ActionActuator.rst b/doc/python_api/rst/bge_types/bge.types.BL_ActionActuator.rst index c761a0d4e446..f4ef46f3cc04 100644 --- a/doc/python_api/rst/bge_types/bge.types.BL_ActionActuator.rst +++ b/doc/python_api/rst/bge_types/bge.types.BL_ActionActuator.rst @@ -49,12 +49,6 @@ base class --- :class:`SCA_IActuator` :type: string - .. attribute:: blendTime - - Sets the internal frame timer. This property must be in the range from 0.0 to blendIn. - - :type: float - .. attribute:: mode The operation mode of the actuator. Can be one of :ref:`these constants`. diff --git a/doc/python_api/rst/bge_types/bge.types.BL_ArmatureBone.rst b/doc/python_api/rst/bge_types/bge.types.BL_ArmatureBone.rst index 0200c9c513bd..fd6a00aad7d3 100644 --- a/doc/python_api/rst/bge_types/bge.types.BL_ArmatureBone.rst +++ b/doc/python_api/rst/bge_types/bge.types.BL_ArmatureBone.rst @@ -1,9 +1,9 @@ -BL_ArmatureBone(PyObjectPlus) -============================= +BL_ArmatureBone(EXP_PyObjectPlus) +================================= -base class --- :class:`PyObjectPlus` +base class --- :class:`EXP_PyObjectPlus` -.. class:: BL_ArmatureBone(PyObjectPlus) +.. class:: BL_ArmatureBone(EXP_PyObjectPlus) Proxy to Blender bone structure. All fields are read-only and comply to RNA names. All space attribute correspond to the rest pose. diff --git a/doc/python_api/rst/bge_types/bge.types.BL_ArmatureChannel.rst b/doc/python_api/rst/bge_types/bge.types.BL_ArmatureChannel.rst index d8fcfa8cbe49..ba5f9fa3d339 100644 --- a/doc/python_api/rst/bge_types/bge.types.BL_ArmatureChannel.rst +++ b/doc/python_api/rst/bge_types/bge.types.BL_ArmatureChannel.rst @@ -1,9 +1,9 @@ -BL_ArmatureChannel(PyObjectPlus) -================================ +BL_ArmatureChannel(EXP_PyObjectPlus) +==================================== -base class --- :class:`PyObjectPlus` +base class --- :class:`EXP_PyObjectPlus` -.. class:: BL_ArmatureChannel(PyObjectPlus) +.. class:: BL_ArmatureChannel(EXP_PyObjectPlus) Proxy to armature pose channel. Allows to read and set armature pose. The attributes are identical to RNA attributes, but mostly in read-only mode. diff --git a/doc/python_api/rst/bge_types/bge.types.BL_ArmatureConstraint.rst b/doc/python_api/rst/bge_types/bge.types.BL_ArmatureConstraint.rst index 8a62d2d688ff..1f8f732ad16b 100644 --- a/doc/python_api/rst/bge_types/bge.types.BL_ArmatureConstraint.rst +++ b/doc/python_api/rst/bge_types/bge.types.BL_ArmatureConstraint.rst @@ -1,9 +1,9 @@ -BL_ArmatureConstraint(PyObjectPlus) -=================================== +BL_ArmatureConstraint(EXP_PyObjectPlus) +======================================= -base class --- :class:`PyObjectPlus` +base class --- :class:`EXP_PyObjectPlus` -.. class:: BL_ArmatureConstraint(PyObjectPlus) +.. class:: BL_ArmatureConstraint(EXP_PyObjectPlus) Proxy to Armature Constraint. Allows to change constraint on the fly. Obtained through :class:`BL_ArmatureObject`.constraints. diff --git a/doc/python_api/rst/bge_types/bge.types.BL_ArmatureObject.rst b/doc/python_api/rst/bge_types/bge.types.BL_ArmatureObject.rst index 336ae29daacc..b22c63177486 100644 --- a/doc/python_api/rst/bge_types/bge.types.BL_ArmatureObject.rst +++ b/doc/python_api/rst/bge_types/bge.types.BL_ArmatureObject.rst @@ -29,3 +29,6 @@ base class --- :class:`KX_GameObject` This action is unecessary if a KX_ArmatureActuator with mode run is active or if an action is playing. Use this function in other cases. It must be called on each frame to ensure that the armature is updated continously. + .. method:: draw() + + Draw lines that represent armature to view it in real time. diff --git a/doc/python_api/rst/bge_types/bge.types.BL_Shader.rst b/doc/python_api/rst/bge_types/bge.types.BL_Shader.rst index 535449784824..781b1da31698 100644 --- a/doc/python_api/rst/bge_types/bge.types.BL_Shader.rst +++ b/doc/python_api/rst/bge_types/bge.types.BL_Shader.rst @@ -1,13 +1,37 @@ -BL_Shader(PyObjectPlus) -======================= +BL_Shader(EXP_PyObjectPlus) +=========================== -base class --- :class:`PyObjectPlus` +base class --- :class:`EXP_PyObjectPlus` -.. class:: BL_Shader(PyObjectPlus) +.. class:: BL_Shader(EXP_PyObjectPlus) - BL_Shader GLSL shaders. + BL_Shader is a class used to compile and use custom shaders scripts. It supports vertex, fragment and geometry shader scripts. + The shader is compiled with a generated header for the three shaders scripts. + This header set the ``#version`` directive, so the user must not define his own `#version`. - TODO - Description + .. attribute:: enabled + + Set shader enabled to use. + + :type: boolean + + .. attribute:: objectCallbacks + + The list of python callbacks executed when the shader is used to render an object. + All the functions can expect as argument the object currently rendered. + + .. code-block:: python + + def callback(object): + print("render object %r" % object.name) + + :type: list of functions and/or methods + + .. attribute:: bindCallbacks + + The list of python callbacks executed when the shader is begin used to render. + + :type: list of functions and/or methods .. method:: setUniformfv(name, fList) @@ -50,13 +74,6 @@ base class --- :class:`PyObjectPlus` :arg enum: attribute location value :type enum: integer - .. method:: setNumberOfPasses( max_pass ) - - Set the maximum number of passes. Not used a.t.m. - - :arg max_pass: the maximum number of passes - :type max_pass: integer - .. method:: setSampler(name, index) Set uniform texture sample index. @@ -66,7 +83,7 @@ base class --- :class:`PyObjectPlus` :arg index: Texture sample index. :type index: integer - .. method:: setSource(vertexProgram, fragmentProgram) + .. method:: setSource(vertexProgram, fragmentProgram, apply) Set the vertex and fragment programs @@ -74,6 +91,28 @@ base class --- :class:`PyObjectPlus` :type vertexProgram: string :arg fragmentProgram: Fragment program :type fragmentProgram: string + :arg apply: Enable the shader. + :type apply: boolean + + .. method:: setSourceList(sources, apply) + + Set the vertex, fragment and geometry shader programs. + + :arg sources: Dictionary of all programs. The keys :data:`vertex`, :data:`fragment` and :data:`geometry` represent shader programs of the same name. + :data:`geometry` is an optional program. + This dictionary can be similar to: + + .. code-block:: python + + sources = { + "vertex" : vertexProgram, + "fragment" : fragmentProgram, + "geometry" : geometryProgram + } + + :type sources: dict + :arg apply: Enable the shader. + :type apply: boolean .. method:: setUniform1f(name, fx) @@ -178,8 +217,8 @@ base class --- :class:`PyObjectPlus` :arg name: the uniform name :type name: string - :arg type: uniform type - :type type: UNI_NONE, UNI_INT, UNI_FLOAT, UNI_INT2, UNI_FLOAT2, UNI_INT3, UNI_FLOAT3, UNI_INT4, UNI_FLOAT4, UNI_MAT3, UNI_MAT4, UNI_MAX + :arg type: uniform type, one of :ref:`these constants ` + :type type: integer .. method:: setUniformMatrix3(name, mat, transpose) diff --git a/doc/python_api/rst/bge_types/bge.types.BL_ShapeActionActuator.rst b/doc/python_api/rst/bge_types/bge.types.BL_ShapeActionActuator.rst deleted file mode 100644 index 4c8d113ad876..000000000000 --- a/doc/python_api/rst/bge_types/bge.types.BL_ShapeActionActuator.rst +++ /dev/null @@ -1,68 +0,0 @@ -BL_ShapeActionActuator(SCA_IActuator) -===================================== - -base class --- :class:`SCA_IActuator` - -.. class:: BL_ShapeActionActuator(SCA_IActuator) - - ShapeAction Actuators apply an shape action to an mesh object. - - .. attribute:: action - - The name of the action to set as the current shape action. - - :type: string - - .. attribute:: frameStart - - Specifies the starting frame of the shape animation. - - :type: float - - .. attribute:: frameEnd - - Specifies the ending frame of the shape animation. - - :type: float - - .. attribute:: blendIn - - Specifies the number of frames of animation to generate when making transitions between actions. - - :type: float - - .. attribute:: priority - - Sets the priority of this actuator. Actuators will lower priority numbers will override actuators with higher numbers. - - :type: integer - - .. attribute:: frame - - Sets the current frame for the animation. - - :type: float - - .. attribute:: propName - - Sets the property to be used in FromProp playback mode. - - :type: string - - .. attribute:: blendTime - - Sets the internal frame timer. This property must be in the range from 0.0 to blendin. - - :type: float - - .. attribute:: mode - - The operation mode of the actuator. Can be one of :ref:`these constants`. - - :type: integer - - .. attribute:: framePropName - - The name of the property that is set to the current frame number. - - :type: string diff --git a/doc/python_api/rst/bge_types/bge.types.BL_Texture.rst b/doc/python_api/rst/bge_types/bge.types.BL_Texture.rst new file mode 100644 index 000000000000..eb52c155f3fa --- /dev/null +++ b/doc/python_api/rst/bge_types/bge.types.BL_Texture.rst @@ -0,0 +1,122 @@ +BL_Texture(EXP_Value) +===================== + +base class --- :class:`EXP_Value` + +.. class:: BL_Texture(EXP_Value) + + A texture object that contains attributes of a material texture. + + .. attribute:: diffuseIntensity + + Amount texture affects diffuse reflectivity. + + :type: float + + .. attribute:: diffuseFactor + + Amount texture affects diffuse color. + + :type: float + + .. attribute:: alpha + + Amount texture affects alpha. + + :type: float + + .. attribute:: specularIntensity + + Amount texture affects specular reflectivity. + + :type: float + + .. attribute:: specularFactor + + Amount texture affects specular color. + + :type: float + + .. attribute:: hardness + + Amount texture affects hardness. + + :type: float + + .. attribute:: emit + + Amount texture affects emission. + + :type: float + + .. attribute:: mirror + + Amount texture affects mirror color. + + :type: float + + .. attribute:: normal + + Amount texture affects normal values. + + :type: float + + .. attribute:: parallaxBump + + Height of parallax occlusion mapping. + + :type: float + + .. attribute:: parallaxStep + + Number of steps to achieve parallax effect. + + :type: float + + .. attribute:: lodBias + + Amount bias on mipmapping. + + :type: float + + .. attribute:: bindCode + + Texture bind code/Id/number. + + :type: integer + + .. attribute:: renderer + + Texture renderer of this texture. + + :type: :class:`KX_CubeMap`, :class:`KX_PlanarMap` or None + + .. attribute:: ior + + Index Of Refraction used to compute refraction. + + :type: float (1.0 to 50.0) + + .. attribute:: refractionRatio + + Amount refraction mixed with reflection. + + :type: float (0.0 to 1.0) + + .. attribute:: uvOffset + + Offset applied to texture UV coordinates (mainly translation on U and V axis). + + :type: :class:`mathutils.Vector` + + .. attribute:: uvSize + + Scale applied to texture UV coordinates. + + :type: :class:`mathutils.Vector` + + .. attribute:: uvRotation + + Rotation applied to texture UV coordinates. + + :type: float (radians) diff --git a/doc/python_api/rst/bge_types/bge.types.CPropValue.rst b/doc/python_api/rst/bge_types/bge.types.CPropValue.rst deleted file mode 100644 index 67fc2c4fafd8..000000000000 --- a/doc/python_api/rst/bge_types/bge.types.CPropValue.rst +++ /dev/null @@ -1,8 +0,0 @@ -CPropValue(CValue) -================== - -base class --- :class:`CValue` - -.. class:: CPropValue(CValue) - - This class has no python functions diff --git a/doc/python_api/rst/bge_types/bge.types.CValue.rst b/doc/python_api/rst/bge_types/bge.types.CValue.rst deleted file mode 100644 index 3255471daf20..000000000000 --- a/doc/python_api/rst/bge_types/bge.types.CValue.rst +++ /dev/null @@ -1,15 +0,0 @@ -CValue(PyObjectPlus) -==================== - -base class --- :class:`PyObjectPlus` - -.. class:: CValue(PyObjectPlus) - - This class is a basis for other classes. - - .. attribute:: name - - The name of this CValue derived object (read-only). - - :type: string - diff --git a/doc/python_api/rst/bge_types/bge.types.CListValue.rst b/doc/python_api/rst/bge_types/bge.types.EXP_ListValue.rst similarity index 75% rename from doc/python_api/rst/bge_types/bge.types.CListValue.rst rename to doc/python_api/rst/bge_types/bge.types.EXP_ListValue.rst index e47cf351f604..6841e754474b 100644 --- a/doc/python_api/rst/bge_types/bge.types.CListValue.rst +++ b/doc/python_api/rst/bge_types/bge.types.EXP_ListValue.rst @@ -1,13 +1,13 @@ -CListValue(CPropValue) -====================== +EXP_ListValue(EXP_PropValue) +============================ -base class --- :class:`CPropValue` +base class --- :class:`EXP_PropValue` -.. class:: CListValue(CPropValue) +.. class:: EXP_ListValue(EXP_PropValue) This is a list like object used in the game engine internally that behaves similar to a python list in most ways. - As well as the normal index lookup (``val= clist[i]``), CListValue supports string lookups (``val= scene.objects["Cube"]``) + As well as the normal index lookup (``val= clist[i]``), EXP_ListValue supports string lookups (``val= scene.objects["Cube"]``) Other operations such as ``len(clist)``, ``list(clist)``, ``clist[0:10]`` are also supported. @@ -43,11 +43,18 @@ base class --- :class:`CPropValue` :return: The key value or a default. + .. method:: filter(name, prop) + + Return a list of items with name matching `name` regex and with a property matching `prop` regex. + If `name` is empty every items are checked, if `prop` is empty no property check is proceeded. + + :return: The list of matching items. + .. method:: from_id(id) This is a funtion especially for the game engine to return a value with a spesific id. - Since object names are not always unique, the id of an object can be used to get an object from the CValueList. + Since object names are not always unique, the id of an object can be used to get an object from the EXP_ValueList. Example: diff --git a/doc/python_api/rst/bge_types/bge.types.EXP_PropValue.rst b/doc/python_api/rst/bge_types/bge.types.EXP_PropValue.rst new file mode 100644 index 000000000000..85ee422b8319 --- /dev/null +++ b/doc/python_api/rst/bge_types/bge.types.EXP_PropValue.rst @@ -0,0 +1,9 @@ +EXP_PropValue(EXP_Value) +======================== + +base class --- :class:`EXP_Value` + +.. class:: EXP_PropValue(EXP_Value) + + This class has no python functions + diff --git a/doc/python_api/rst/bge_types/bge.types.PyObjectPlus.rst b/doc/python_api/rst/bge_types/bge.types.EXP_PyObjectPlus.rst similarity index 79% rename from doc/python_api/rst/bge_types/bge.types.PyObjectPlus.rst rename to doc/python_api/rst/bge_types/bge.types.EXP_PyObjectPlus.rst index 4c8ddb9bcf5e..10752167c032 100644 --- a/doc/python_api/rst/bge_types/bge.types.PyObjectPlus.rst +++ b/doc/python_api/rst/bge_types/bge.types.EXP_PyObjectPlus.rst @@ -1,9 +1,9 @@ -PyObjectPlus -============ +EXP_PyObjectPlus +================ -.. class:: PyObjectPlus +.. class:: EXP_PyObjectPlus - PyObjectPlus base class of most other types in the Game Engine. + EXP_PyObjectPlus base class of most other types in the Game Engine. .. attribute:: invalid diff --git a/doc/python_api/rst/bge_types/bge.types.EXP_Value.rst b/doc/python_api/rst/bge_types/bge.types.EXP_Value.rst new file mode 100644 index 000000000000..f86942eeff27 --- /dev/null +++ b/doc/python_api/rst/bge_types/bge.types.EXP_Value.rst @@ -0,0 +1,15 @@ +EXP_Value(EXP_PyObjectPlus) +=========================== + +base class --- :class:`EXP_PyObjectPlus` + +.. class:: EXP_Value(EXP_PyObjectPlus) + + This class is a basis for other classes. + + .. attribute:: name + + The name of this EXP_Value derived object (read-only). + + :type: string + diff --git a/doc/python_api/rst/bge_types/bge.types.KX_2DFilter.rst b/doc/python_api/rst/bge_types/bge.types.KX_2DFilter.rst new file mode 100644 index 000000000000..ff36d8e34aa3 --- /dev/null +++ b/doc/python_api/rst/bge_types/bge.types.KX_2DFilter.rst @@ -0,0 +1,90 @@ +KX_2DFilter(BL_Shader) +====================== + +base class --- :class:`BL_Shader` + +.. class:: KX_2DFilter(BL_Shader) + + 2D filter shader object. Can be alterated with :class:`BL_Shader`'s functions. + + .. warning:: + + The vertex shader must not apply modelview and projection transformation. It should be similar to: + + .. code-block:: glsl + + void main() + { + gl_Position = gl_Vertex; + } + + .. attribute:: mipmap + + Request mipmap generation of the render `bgl_RenderedTexture` texture. Accessing mipmapping level is similar to: + + .. code-block:: glsl + + uniform sampler2D bgl_RenderedTexture; + + void main() + { + float level = 2.0; // mipmap level + gl_FragColor = textureLod(bgl_RenderedTexture, gl_TexCoord[0].st, level); + } + + :type: boolean + + .. attribute:: offScreen + + The custom off screen the filter render to (read-only). + + :type: :class:`bge.types.KX_2DFilterOffScreen` or None + + .. method:: setTexture(index, bindCode, samplerName="") + + Set specified texture bind code :data:`bindCode` in specified slot :data:`index`. Any call to :data:`setTexture` + should be followed by a call to :data:`BL_Shader.setSampler` with the same :data:`index` if :data:`sampleName` is not specified. + + :arg index: The texture slot. + :type index: integer + :arg bindCode: The texture bind code/Id. + :type bindCode: integer + :arg samplerName: The shader sampler name set to :data:`index` if :data:`samplerName` is passed in the function. (optional) + :type samplerName: string + + .. method:: setCubeMap(index, bindCode, samplerName="") + + Set specified cube map texture bind code :data:`bindCode` in specified slot :data:`index`. Any call to :data:`setCubeMap` + should be followed by a call to :data:`BL_Shader.setSampler` with the same :data:`index` if :data:`sampleName` is not specified. + + :arg index: The texture slot. + :type index: integer + :arg bindCode: The cube map texture bind code/Id. + :type bindCode: integer + :arg samplerName: The shader sampler name set to :data:`index` if :data:`samplerName` is passed in the function. (optional) + :type samplerName: string + + .. method:: addOffScreen(slots, depth=False, width=-1, height=-1, hdr=bge.render.HDR_NONE, mipmap=False) + + Register a custom off screen to render the filter to. + + :arg slots: The number of color texture attached to the off screen, between 0 and 8 excluded. + :type slots: integer + :arg depth: True of the off screen use a depth texture (optional). + :type depth: boolean + :arg width: The off screen width, -1 if it can be resized dynamically when the viewport dimensions changed (optional). + :type width: integer + :arg height: The off screen height, -1 if it can be resized dynamically when the viewport dimensions changed (optional). + :type height: integer + :arg hdr: The image quality HDR of the color textures (optional). + :type hdr: one of :ref:`these constants` + :arg mipmap: True if the color texture generate mipmap at the end of the filter rendering (optional). + :type mipmap: boolean + + .. note:: + If the off screen is created using a dynamic size (`width` and `height` to -1) its bind codes will be unavailable before + the next render of the filter and the it can change when the viewport is resized. + + .. method:: removeOffScreen() + + Unregister the custom off screen the filter render to. diff --git a/doc/python_api/rst/bge_types/bge.types.KX_2DFilterManager.rst b/doc/python_api/rst/bge_types/bge.types.KX_2DFilterManager.rst new file mode 100644 index 000000000000..f6ca79d43b88 --- /dev/null +++ b/doc/python_api/rst/bge_types/bge.types.KX_2DFilterManager.rst @@ -0,0 +1,54 @@ +KX_2DFilterManager(EXP_PyObjectPlus) +==================================== + +base class --- :class:`EXP_PyObjectPlus` + +.. class:: KX_2DFilterManager(EXP_PyObjectPlus) + + 2D filter manager used to add, remove and find filters in a scene. + + .. method:: addFilter(index, type, fragmentProgram) + + Add a filter to the pass index :data:`index`, type :data:`type` and fragment program if custom filter. + + :arg index: The filter pass index. + :type index: integer + :arg type: The filter type, one of: + + * :data:`bge.logic.RAS_2DFILTER_BLUR` + * :data:`bge.logic.RAS_2DFILTER_DILATION` + * :data:`bge.logic.RAS_2DFILTER_EROSION` + * :data:`bge.logic.RAS_2DFILTER_SHARPEN` + * :data:`bge.logic.RAS_2DFILTER_LAPLACIAN` + * :data:`bge.logic.RAS_2DFILTER_PREWITT` + * :data:`bge.logic.RAS_2DFILTER_SOBEL` + * :data:`bge.logic.RAS_2DFILTER_GRAYSCALE` + * :data:`bge.logic.RAS_2DFILTER_SEPIA` + * :data:`bge.logic.RAS_2DFILTER_CUSTOMFILTER` + + :type type: integer + :arg fragmentProgram: The filter shader fragment program. + Used only if :data:`type` is :data:`bge.logic.RAS_2DFILTER_CUSTOMFILTER`, if empty or not specified the filter is created without shader, waiting call to :data:`BL_Shader.setSourceList`. (optional) + :type fragmentProgram: string + :return: The 2D Filter. + :rtype: :class:`KX_2DFilter` + + .. method:: removeFilter(index) + + Remove filter to the pass index :data:`index`. + + :arg index: The filter pass index. + :type index: integer + + .. method:: getFilter(index) + + Return filter to the pass index :data:`index`. + + :warning: If the 2D Filter is added with a :class:`SCA_2DFilterActuator`, the filter will + be available only after the 2D Filter program is linked. The python script to get the filter + has to be executed one frame later. A delay sensor can be used. + + :arg index: The filter pass index. + :type index: integer + :return: The filter in the specified pass index or None. + :rtype: :class:`KX_2DFilter` or None diff --git a/doc/python_api/rst/bge_types/bge.types.KX_2DFilterOffScreen.rst b/doc/python_api/rst/bge_types/bge.types.KX_2DFilterOffScreen.rst new file mode 100644 index 000000000000..b1f4782d8691 --- /dev/null +++ b/doc/python_api/rst/bge_types/bge.types.KX_2DFilterOffScreen.rst @@ -0,0 +1,36 @@ +KX_2DFilterOffScreen(EXP_Value) +=============================== + +base class --- :class:`EXP_Value` + +.. class:: KX_2DFilterOffScreen(EXP_Value) + + 2D filter custom off screen. + + .. attribute:: width + + The off screen width, -1 if the off screen can be resized dynamically (read-only). + + :type: integer + + .. attribute:: height + + The off screen height, -1 if the off screen can be resized dynamically (read-only). + + :type: integer + + .. attribute:: colorBindCodes + + The bind code of the color textures attached to the off screen (read-only). + + .. warning:: If the off screen can be resized dynamically (:data:`width` of :data:`height` equal to -1), the bind codes may change. + + :type: list of 8 integers + + .. attribute:: depthBindCode + + The bind code of the depth texture attached to the off screen (read-only). + + .. warning:: If the off screen can be resized dynamically (:data:`width` of :data:`height` equal to -1), the bind code may change. + + :type: integer diff --git a/doc/python_api/rst/bge_types/bge.types.KX_BatchGroup.rst b/doc/python_api/rst/bge_types/bge.types.KX_BatchGroup.rst new file mode 100644 index 000000000000..fd198c09a4dd --- /dev/null +++ b/doc/python_api/rst/bge_types/bge.types.KX_BatchGroup.rst @@ -0,0 +1,53 @@ +KX_BatchGroup(EXP_Value) +======================== + +base class --- :class:`EXP_Value` + +.. class:: KX_BatchGroup(EXP_Value) + + The batch group is class containing a mesh resulting of the merging of meshes used by objects. + The meshes are merged with the transformation of the objects using it. + An instance of this class is not owned by one object but shared between objects. + In consideration an instance of :class:`KX_BatchGroup` have to instanced with as argument a list of at least one object containing the meshes to merge. + This can be done in a way similar to: + + .. code-block:: python + + import bge + + scene = bge.logic.getCurrentScene() + + batchGroup = types.KX_BatchGroup([scene.objects["Cube"], scene.objects["Plane"]]) + + .. warning:: + + Rendering settings unique to objects such as :data:`KX_GameObject.layer` and :data:`KX_GameObject.color` are shared when using batch groups. + These settings are taken from object :attr:`referenceObject`. + + .. attribute:: objects + + The list of the objects merged. (read only) + + :type: :class:`EXP_ListValue` of :class:`KX_GameObject` + + .. attribute:: referenceObject + + The object used for object rendering settings (layer, color...). + + .. method:: merge(objects) + + Merge meshes using the transformation of the objects using them. + + :arg objects: The objects to merge. + :type object: :class:`EXP_ListValue` of :class:`KX_GameObject` + + .. method:: split(objects) + + Split the meshes of the objects using them and restore their original meshes. + + :arg objects: The objects to unmerge. + :type object: :class:`EXP_ListValue` of :class:`KX_GameObject` + + .. method:: destruct() + + Destruct the batch group and restore all the objects to their original meshes. diff --git a/doc/python_api/rst/bge_types/bge.types.KX_BlenderMaterial.rst b/doc/python_api/rst/bge_types/bge.types.KX_BlenderMaterial.rst index fd3bbc58a7cb..00c4effe4748 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_BlenderMaterial.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_BlenderMaterial.rst @@ -1,9 +1,9 @@ -KX_BlenderMaterial(PyObjectPlus) -================================ +KX_BlenderMaterial(EXP_PyObjectPlus) +==================================== -base class --- :class:`PyObjectPlus` +base class --- :class:`EXP_PyObjectPlus` -.. class:: KX_BlenderMaterial(PyObjectPlus) +.. class:: KX_BlenderMaterial(EXP_PyObjectPlus) This is the interface to materials in the game engine. @@ -74,12 +74,6 @@ base class --- :class:`PyObjectPlus` :type: (integer, integer) - .. attribute:: material_index - - The material's index. - - :type: integer - .. method:: getShader() Returns the material's shader. @@ -91,6 +85,8 @@ base class --- :class:`PyObjectPlus` Returns the material's texture OpenGL bind code/id/number/name. + .. deprecated:: use :py:meth:`bge.types.BL_Texture.bindCode` + :arg textureslot: Specifies the texture slot number :type textureslot: integer :return: the material's texture OpenGL bind code/id/number/name @@ -114,6 +110,18 @@ base class --- :class:`PyObjectPlus` :type: float between 0.0 and 2.0 inclusive + .. attribute:: ambient + + Amount of ambient light on the material. + + :type: float between 0.0 and 1.0 inclusive + + .. attribute:: specularAlpha + + Alpha transparency for specular areas. + + :type: float between 0.0 and 1.0 inclusive (alpha must be < 1.0) + .. attribute:: specularIntensity How intense (bright) the material's specular reflection is. @@ -138,6 +146,12 @@ base class --- :class:`PyObjectPlus` :type: :class:`mathutils.Color` + .. attribute:: textures + + List of all material's textures. + + :type: List of :class:`BL_Texture` (read only) + .. method:: setBlending(src, dest) Set the pixel color arithmetic functions. @@ -173,10 +187,3 @@ base class --- :class:`PyObjectPlus` * :data:`~bgl.GL_SRC_ALPHA_SATURATE` :type dest: int - - .. method:: getMaterialIndex() - - Returns the material's index. - - :return: the material's index - :rtype: integer diff --git a/doc/python_api/rst/bge_types/bge.types.KX_BoundingBox.rst b/doc/python_api/rst/bge_types/bge.types.KX_BoundingBox.rst new file mode 100644 index 000000000000..ceed88b2ce58 --- /dev/null +++ b/doc/python_api/rst/bge_types/bge.types.KX_BoundingBox.rst @@ -0,0 +1,55 @@ +KX_BoundingBox(EXP_PyObjectPlus) +================================ + +base class --- :class:`EXP_PyObjectPlus` + +.. class:: KX_BoundingBox(EXP_PyObjectPlus) + + A bounding volume box of a game object. Used to get and alterate the volume box or AABB. + + .. code-block:: python + + from bge import logic + from mathutils import Vector + + owner = logic.getCurrentController().owner + box = owner.cullingBox + + # Disable auto update to allow modify the box. + box.autoUpdate = False + + print(box) + # Increase the height of the box of 1. + box.max = box.max + Vector((0, 0, 1)) + + print(box) + + .. attribute:: min + + The minimal point in x, y and z axis of the bounding box. + + :type: :class:`mathutils.Vector` + + .. attribute:: max + + The maximal point in x, y and z axis of the bounding box. + + :type: :class:`mathutils.Vector` + + .. attribute:: center + + The center of the bounding box. (read only) + + :type: :class:`mathutils.Vector` + + .. attribute:: radius + + The radius of the bounding box. (read only) + + :type: float + + .. attribute:: autoUpdate + + Allow to update the bounding box if the mesh is modified. + + :type: boolean diff --git a/doc/python_api/rst/bge_types/bge.types.KX_Camera.rst b/doc/python_api/rst/bge_types/bge.types.KX_Camera.rst index 8c8c68fc0515..c0cb60bcd947 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_Camera.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_Camera.rst @@ -25,6 +25,14 @@ base class --- :class:`KX_GameObject` :type: float + .. attribute:: lodDistanceFactor + + The factor to multiply distance to camera to adjust levels of detail. + A float < 1.0f will make the distance to camera used to compute + levels of detail decrease. + + :type: float + .. attribute:: fov The camera's field of view value. @@ -73,6 +81,12 @@ base class --- :class:`KX_GameObject` :type: boolean + .. attribute:: activityCulling + + True if this camera is used to compute object distance for object activity culling. + + :type: boolean + .. attribute:: projection_matrix This camera's 4x4 projection matrix. diff --git a/doc/python_api/rst/bge_types/bge.types.KX_CharacterWrapper.rst b/doc/python_api/rst/bge_types/bge.types.KX_CharacterWrapper.rst index df95b842b5d4..f4b12ed75b3a 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_CharacterWrapper.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_CharacterWrapper.rst @@ -1,9 +1,9 @@ -KX_CharacterWrapper(PyObjectPlus) -================================= +KX_CharacterWrapper(EXP_PyObjectPlus) +===================================== -base class --- :class:`PyObjectPlus` +base class --- :class:`EXP_PyObjectPlus` -.. class:: KX_CharacterWrapper(PyObjectPlus) +.. class:: KX_CharacterWrapper(EXP_PyObjectPlus) A wrapper to expose character physics options. @@ -17,6 +17,12 @@ base class --- :class:`PyObjectPlus` The gravity value used for the character. + :type: :class:`mathutils.Vector` + + .. attribute:: fallSpeed + + The character falling speed. + :type: float .. attribute:: maxJumps @@ -31,6 +37,18 @@ base class --- :class:`PyObjectPlus` :type: int + .. attribute:: jumpSpeed + + The character jumping speed. + + :type: float + + .. attribute:: maxSlope + + The maximum slope which the character can climb. + + :type: float + .. attribute:: walkDirection The speed and direction the character is traveling in using world coordinates. This should be used instead of applyMovement() to properly move the character. @@ -40,3 +58,21 @@ base class --- :class:`PyObjectPlus` .. method:: jump() The character jumps based on it's jump speed. + .. method:: setVelocity(velocity, time, local=False) + + Sets the character's linear velocity for a given period. + + This method sets character's velocity through it's center of mass during a period. + + :arg velocity: Linear velocity vector. + :type velocity: 3D Vector + :arg time: Period while applying linear velocity. + :type time: float + :arg local: + * False: you get the "global" velocity ie: relative to world orientation. + * True: you get the "local" velocity ie: relative to object orientation. + :type local: boolean + + .. method:: reset() + + Resets the character velocity and walk direction. diff --git a/doc/python_api/rst/bge_types/bge.types.KX_CollisionContactPoint.rst b/doc/python_api/rst/bge_types/bge.types.KX_CollisionContactPoint.rst new file mode 100644 index 000000000000..cc0ed116af79 --- /dev/null +++ b/doc/python_api/rst/bge_types/bge.types.KX_CollisionContactPoint.rst @@ -0,0 +1,77 @@ +KX_CollisionContactPoint(EXP_Value) +=================================== + +base class --- :class:`EXP_Value` + +.. class:: KX_CollisionContactPoint(EXP_Value) + + A collision contact point passed to the collision callbacks. + + .. code-block:: python + + import bge + + def oncollision(object, point, normal, points): + print("Hit by", object) + for point in points: + print(point.localPointA) + print(point.localPointB) + print(point.worldPoint) + print(point.normal) + print(point.combinedFriction) + print(point.combinedRestitution) + print(point.appliedImpulse) + + cont = bge.logic.getCurrentController() + own = cont.owner + own.collisionCallbacks = [oncollision] + + .. attribute:: localPointA + + The contact point in the owner object space. + + :type: :class:`mathutils.Vector` + + .. attribute:: localPointB + + The contact point in the collider object space. + + :type: :class:`mathutils.Vector` + + .. attribute:: worldPoint + + The contact point in world space. + + :type: :class:`mathutils.Vector` + + .. attribute:: normal + + The contact normal in owner object space. + + :type: :class:`mathutils.Vector` + + .. attribute:: combinedFriction + + The combined friction of the owner and collider object. + + :type: float + + .. attribute:: combinedRollingFriction + + The combined rolling friction of the owner and collider object. + + :type: float + + .. attribute:: combinedRestitution + + The combined restitution of the owner and collider object. + + :type: float + + .. attribute:: appliedImpulse + + The applied impulse to the owner object. + + :type: float + + diff --git a/doc/python_api/rst/bge_types/bge.types.KX_TouchSensor.rst b/doc/python_api/rst/bge_types/bge.types.KX_CollisionSensor.rst similarity index 77% rename from doc/python_api/rst/bge_types/bge.types.KX_TouchSensor.rst rename to doc/python_api/rst/bge_types/bge.types.KX_CollisionSensor.rst index 79fd1a631518..74ffb9f349bc 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_TouchSensor.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_CollisionSensor.rst @@ -1,11 +1,11 @@ -KX_TouchSensor(SCA_ISensor) -=========================== +KX_CollisionSensor(SCA_ISensor) +=============================== base class --- :class:`SCA_ISensor` -.. class:: KX_TouchSensor(SCA_ISensor) +.. class:: KX_CollisionSensor(SCA_ISensor) - Touch sensor detects collisions between objects. + Collision sensor detects collisions between objects. .. attribute:: propName @@ -35,7 +35,7 @@ base class --- :class:`SCA_ISensor` A list of colliding objects. (read-only). - :type: :class:`CListValue` of :class:`KX_GameObject` + :type: :class:`EXP_ListValue` of :class:`KX_GameObject` .. attribute:: hitMaterial diff --git a/doc/python_api/rst/bge_types/bge.types.KX_ConstraintActuator.rst b/doc/python_api/rst/bge_types/bge.types.KX_ConstraintActuator.rst index 56c87cc110ec..eda0a14ce18e 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_ConstraintActuator.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_ConstraintActuator.rst @@ -23,7 +23,7 @@ base class --- :class:`SCA_IActuator` The reference direction in world coordinate for the orientation constraint. - :type: 3-tuple of float: (x, y, z) + :type: :class:`mathutils.Vector` .. attribute:: option diff --git a/doc/python_api/rst/bge_types/bge.types.KX_ConstraintWrapper.rst b/doc/python_api/rst/bge_types/bge.types.KX_ConstraintWrapper.rst index 77eec6bde787..5ffa4077f235 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_ConstraintWrapper.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_ConstraintWrapper.rst @@ -1,9 +1,9 @@ -KX_ConstraintWrapper(PyObjectPlus) -================================== +KX_ConstraintWrapper(EXP_PyObjectPlus) +====================================== -base class --- :class:`PyObjectPlus` +base class --- :class:`EXP_PyObjectPlus` -.. class:: KX_ConstraintWrapper(PyObjectPlus) +.. class:: KX_ConstraintWrapper(EXP_PyObjectPlus) KX_ConstraintWrapper @@ -138,3 +138,14 @@ base class --- :class:`PyObjectPlus` - :class:`~bge.constraints.CONETWIST_CONSTRAINT` - :class:`~bge.constraints.VEHICLE_CONSTRAINT` - :class:`~bge.constraints.GENERIC_6DOF_CONSTRAINT` + .. attribute:: breakingThreshold + + The impulse threshold breaking the constraint, if the constraint is broken :data:`enabled` is set to `False`. + + :type: float greater or equal to 0 + + .. attribute:: enabled + + The status of the constraint. Set to `True` to restore a constraint after breaking. + + :type: boolean diff --git a/doc/python_api/rst/bge_types/bge.types.KX_CubeMap.rst b/doc/python_api/rst/bge_types/bge.types.KX_CubeMap.rst new file mode 100644 index 000000000000..47c158f20ada --- /dev/null +++ b/doc/python_api/rst/bge_types/bge.types.KX_CubeMap.rst @@ -0,0 +1,35 @@ +KX_CubeMap(KX_TextureRenderer) +============================== + +base class --- :class:`KX_TextureRenderer` + +.. class:: KX_CubeMap(KX_TextureRenderer) + + Python API for realtime cube map textures. + + .. code-block:: python + + import bge + + scene = bge.logic.getCurrentScene() + # The object using a realtime cube map in its material. + obj = scene.objects["Suzanne"] + + mat = obj.meshes[0].materials[0] + # Obtain the realtime cube map from the material texture. + cubemap = mat.textures[0].renderer + + # Set the render position to the "Cube" object position. + cubemap.viewpointObject = scene.objects["Cube"] + + # Change the culling clip start and clip end. + cubemap.clipStart = 5.0 + cubemap.clipEnd = 20.0 + + # Disable render on third layer. + cubemap.ignoreLayers = (1 << 2) + + # Disable per frame update. + cubemap.autoUpdate = False + # Ask to update for this frame only. + cubemap.update() diff --git a/doc/python_api/rst/bge_types/bge.types.KX_FontObject.rst b/doc/python_api/rst/bge_types/bge.types.KX_FontObject.rst index f02609af0faf..c0678109fc9f 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_FontObject.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_FontObject.rst @@ -27,3 +27,29 @@ base class --- :class:`KX_GameObject` The text displayed by this Font object. :type: string + .. attribute:: resolution + + The resolution of the font police. + + .. warning:: + + High resolution can use a lot of memory and may crash. + + :type: float (0.1 to 50.0) + + .. attribute:: size + + The size (scale factor) of the font object, scaled from font object origin (affects text resolution). + + .. warning:: + + High size can use a lot of memory and may crash. + + :type: float (0.0001 to 40.0) + + .. attribute:: dimensions + + The size (width and height) of the current text in Blender Units. + + :type: :class:`mathutils.Vector` + diff --git a/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst b/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst index 2797e8ef3612..4198641416f9 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst @@ -62,7 +62,7 @@ base class --- :class:`SCA_IObject` .. attribute:: name - The object's name. (read-only). + The object's name. :type: string @@ -176,7 +176,7 @@ base class --- :class:`SCA_IObject` Returns the list of group members if the object is a group object (dupli group instance), otherwise None is returned. - :type: :class:`CListValue` of :class:`KX_GameObject` or None + :type: :class:`EXP_ListValue` of :class:`KX_GameObject` or None .. attribute:: groupObject @@ -202,13 +202,17 @@ base class --- :class:`SCA_IObject` :type: list of functions and/or methods - Callbacks should either accept one argument `(object)`, or three - arguments `(object, point, normal)`. For simplicity, per - colliding object only the first collision point is reported. + Callbacks should either accept one argument `(object)`, or four + arguments `(object, point, normal, points)`. For simplicity, per + colliding object the first collision point is reported in second + and third argument. .. code-block:: python # Function form + def callback_four(object, point, normal, points): + print('Hit by %r with %i contacts points' % (object.name, len(points))) + def callback_three(object, point, normal): print('Hit by %r at %s with normal %s' % (object.name, point, normal)) @@ -216,6 +220,7 @@ base class --- :class:`SCA_IObject` print('Hit by %r' % object.name) def register_callback(controller): + controller.owner.collisionCallbacks.append(callback_four) controller.owner.collisionCallbacks.append(callback_three) controller.owner.collisionCallbacks.append(callback_one) @@ -223,9 +228,13 @@ base class --- :class:`SCA_IObject` # Method form class YourGameEntity(bge.types.KX_GameObject): def __init__(self, old_owner): + self.collisionCallbacks.append(self.on_collision_four) self.collisionCallbacks.append(self.on_collision_three) self.collisionCallbacks.append(self.on_collision_one) + def on_collision_four(self, object, point, normal, points): + print('Hit by %r with %i contacts points' % (object.name, len(points))) + def on_collision_three(self, object, point, normal): print('Hit by %r at %s with normal %s' % (object.name, point, normal)) @@ -236,7 +245,7 @@ base class --- :class:`SCA_IObject` For backward compatibility, a callback with variable number of arguments (using `*args`) will be passed only the `object` argument. Only when there is more than one fixed argument (not - counting `self` for methods) will the three-argument form be + counting `self` for methods) will the four-argument form be used. .. attribute:: scene @@ -255,11 +264,27 @@ base class --- :class:`SCA_IObject` Game logic will still run for invisible objects. - .. attribute:: record_animation + .. attribute:: layer - Record animation for this object. + The layer mask used for shadow and real-time cube map render. - :type: boolean + :type: bitfield + + .. attribute:: cullingBox + + The object's bounding volume box used for culling. + + :type: :class:`KX_BoundingBox` + + .. attribute:: culled + + Returns True if the object is culled, else False. + + .. warning:: + + This variable returns an invalid value if it is called outside the scene's callbacks :data:`KX_Scene.pre_draw` and :data:`KX_Scene.post_draw`. + + :type: boolean (read only) .. attribute:: color @@ -273,6 +298,32 @@ base class --- :class:`SCA_IObject` :type: boolean + .. attribute:: physicsCulling + + True if the object suspends its physics depending on its nearest distance to any camera. + + :type: boolean + + .. attribute:: logicCulling + + True if the object suspends its logic and animation depending on its nearest distance to any camera. + + :type: boolean + + .. attribute:: physicsCullingRadius + + Suspend object's physics if this radius is smaller than its nearest distance to any camera + and :data:`physicsCulling` set to `True`. + + :type: float + + .. attribute:: logicCullingRadius + + Suspend object's logic and animation if this radius is smaller than its nearest distance to any camera + and :data:`logicCulling` set to `True`. + + :type: float + .. attribute:: position The object's position. [x, y, z] On write: local position, on read: world position @@ -369,6 +420,12 @@ base class --- :class:`SCA_IObject` :type: :class:`mathutils.Vector` + .. attribute:: gravity + + The object's gravity. [x, y, z] + + :type: :class:`mathutils.Vector` + .. attribute:: timeOffset adjust the slowparent delay at runtime. @@ -385,7 +442,7 @@ base class --- :class:`SCA_IObject` a list meshes for this object. - :type: list of :class:`KX_MeshProxy` + :type: list of :class:`KX_Mesh` .. note:: @@ -395,6 +452,12 @@ base class --- :class:`SCA_IObject` Changes to this list will not update the KX_GameObject. + .. attribute:: batchGroup + + The object batch group containing the batched mesh. + + :type: :class:`KX_BatchGroup` + .. attribute:: sensors a sequence of :class:`SCA_ISensor` objects with string/index lookups and iterator support. @@ -443,22 +506,27 @@ base class --- :class:`SCA_IObject` :type: dict + .. attribute:: components + + All python components. + + :type: :class:`EXP_ListValue` of :class:`KX_PythonComponent`'s + .. attribute:: children direct children of this object, (read-only). - :type: :class:`CListValue` of :class:`KX_GameObject`'s + :type: :class:`EXP_ListValue` of :class:`KX_GameObject`'s .. attribute:: childrenRecursive all children of this object including children's children, (read-only). - :type: :class:`CListValue` of :class:`KX_GameObject`'s + :type: :class:`EXP_ListValue` of :class:`KX_GameObject`'s .. attribute:: life - The number of seconds until the object ends, assumes 50fps. - (when added with an add object actuator), (read-only). + The number of frames until the object ends, assumes one frame is 1/50 second (read-only). :type: float @@ -480,6 +548,15 @@ base class --- :class:`SCA_IObject` :type: int + .. attribute:: lodManager + + Return the lod manager of this object. + Needed to access to lod manager to set attributes of levels of detail of this object. + The lod manager is shared between instance objects and can be changed to use the lod levels of an other object. + If the lod manager is set to `None` the object's mesh backs to the mesh of the previous first lod level. + + :type: :class:`KX_LodManager` + .. method:: endObject() Delete this object, can be used in place of the EndObject Actuator. @@ -497,22 +574,22 @@ base class --- :class:`SCA_IObject` :arg usePhysicsMesh: when enabled the physics mesh will be replaced (optional argument). :type usePhysicsMesh: boolean - .. method:: setVisible(visible, recursive) + .. method:: setVisible(visible[, recursive]) Sets the game object's visible flag. :arg visible: the visible state to set. :type visible: boolean - :arg recursive: optional argument to set all childrens visibility flag too. + :arg recursive: optional argument to set all childrens visibility flag too, defaults to False if no value passed. :type recursive: boolean - .. method:: setOcclusion(occlusion, recursive) + .. method:: setOcclusion(occlusion[, recursive]) Sets the game object's occlusion capability. :arg occlusion: the state to set the occlusion to. :type occlusion: boolean - :arg recursive: optional argument to set all childrens occlusion flag too. + :arg recursive: optional argument to set all childrens occlusion flag too, defaults to False if no value passed. :type recursive: boolean .. method:: alignAxisToVect(vect, axis=2, factor=1.0) @@ -542,29 +619,35 @@ base class --- :class:`SCA_IObject` :return: The vector in relation to the objects rotation. :rtype: 3d vector. - .. method:: applyMovement(movement, local=False) + .. method:: applyMovement(movement[, local]) Sets the game object's movement. :arg movement: movement vector. :type movement: 3D Vector :arg local: - * False: you get the "global" movement ie: relative to world orientation. - * True: you get the "local" movement ie: relative to object orientation. + + * False: get the "global" movement ie: relative to world orientation. + * True: get the "local" movement ie: relative to object orientation. + + Default to False if not passed. :arg local: boolean - .. method:: applyRotation(rotation, local=False) + .. method:: applyRotation(rotation[, local]) Sets the game object's rotation. :arg rotation: rotation vector. :type rotation: 3D Vector :arg local: - * False: you get the "global" rotation ie: relative to world orientation. - * True: you get the "local" rotation ie: relative to object orientation. + + * False: get the "global" rotation ie: relative to world orientation. + * True: get the "local" rotation ie: relative to object orientation. + + Default to False if not passed. :arg local: boolean - .. method:: applyForce(force, local=False) + .. method:: applyForce(force[, local]) Sets the game object's force. @@ -573,11 +656,14 @@ base class --- :class:`SCA_IObject` :arg force: force vector. :type force: 3D Vector :arg local: - * False: you get the "global" force ie: relative to world orientation. - * True: you get the "local" force ie: relative to object orientation. + + * False: get the "global" force ie: relative to world orientation. + * True: get the "local" force ie: relative to object orientation. + + Default to False if not passed. :type local: boolean - .. method:: applyTorque(torque, local=False) + .. method:: applyTorque(torque[, local]) Sets the game object's torque. @@ -586,24 +672,30 @@ base class --- :class:`SCA_IObject` :arg torque: torque vector. :type torque: 3D Vector :arg local: - * False: you get the "global" torque ie: relative to world orientation. - * True: you get the "local" torque ie: relative to object orientation. + + * False: get the "global" torque ie: relative to world orientation. + * True: get the "local" torque ie: relative to object orientation. + + Default to False if not passed. :type local: boolean - .. method:: getLinearVelocity(local=False) + .. method:: getLinearVelocity([local]) Gets the game object's linear velocity. This method returns the game object's velocity through it's center of mass, ie no angular velocity component. :arg local: - * False: you get the "global" velocity ie: relative to world orientation. - * True: you get the "local" velocity ie: relative to object orientation. + + * False: get the "global" velocity ie: relative to world orientation. + * True: get the "local" velocity ie: relative to object orientation. + + Default to False if not passed. :type local: boolean :return: the object's linear velocity. :rtype: Vector((vx, vy, vz)) - .. method:: setLinearVelocity(velocity, local=False) + .. method:: setLinearVelocity(velocity[, local]) Sets the game object's linear velocity. @@ -615,22 +707,28 @@ base class --- :class:`SCA_IObject` :arg velocity: linear velocity vector. :type velocity: 3D Vector :arg local: - * False: you get the "global" velocity ie: relative to world orientation. - * True: you get the "local" velocity ie: relative to object orientation. + + * False: get the "global" velocity ie: relative to world orientation. + * True: get the "local" velocity ie: relative to object orientation. + + Default to False if not passed. :type local: boolean - .. method:: getAngularVelocity(local=False) + .. method:: getAngularVelocity([local]) Gets the game object's angular velocity. :arg local: - * False: you get the "global" velocity ie: relative to world orientation. - * True: you get the "local" velocity ie: relative to object orientation. + + * False: get the "global" velocity ie: relative to world orientation. + * True: get the "local" velocity ie: relative to object orientation. + + Default to False if not passed. :type local: boolean :return: the object's angular velocity. :rtype: Vector((vx, vy, vz)) - .. method:: setAngularVelocity(velocity, local=False) + .. method:: setAngularVelocity(velocity[, local]) Sets the game object's angular velocity. @@ -639,17 +737,20 @@ base class --- :class:`SCA_IObject` :arg velocity: angular velocity vector. :type velocity: boolean :arg local: - * False: you get the "global" velocity ie: relative to world orientation. - * True: you get the "local" velocity ie: relative to object orientation. - .. method:: getVelocity(point=(0, 0, 0)) + * False: get the "global" velocity ie: relative to world orientation. + * True: get the "local" velocity ie: relative to object orientation. + + Default to False if not passed. + + .. method:: getVelocity([point]) Gets the game object's velocity at the specified point. Gets the game object's velocity at the specified point, including angular components. - :arg point: optional point to return the velocity for, in local coordinates. + :arg point: optional point to return the velocity for, in local coordinates, defaults to (0, 0, 0) if no value passed. :type point: 3D Vector :return: the velocity at the specified point. :rtype: Vector((vx, vy, vz)) @@ -668,7 +769,7 @@ base class --- :class:`SCA_IObject` This is not implimented at the moment. - .. method:: applyImpulse(point, impulse, local=False) + .. method:: applyImpulse(point, impulse[, local]) Applies an impulse to the game object. @@ -681,8 +782,11 @@ base class --- :class:`SCA_IObject` :arg impulse: impulse vector. :type impulse: 3D Vector :arg local: - * False: you get the "global" impulse ie: relative to world coordinates with world orientation. - * True: you get the "local" impulse ie: relative to local coordinates with object orientation. + + * False: get the "global" impulse ie: relative to world coordinates with world orientation. + * True: get the "local" impulse ie: relative to local coordinates with object orientation. + + Default to False if not passed. :type local: boolean .. method:: setDamping(linear_damping, angular_damping) @@ -694,10 +798,22 @@ base class --- :class:`SCA_IObject` :arg angular_damping: Angular ("rotational") damping factor. :type angular_damping: float ∈ [0, 1] - .. method:: suspendDynamics([ghost]) + .. method:: suspendPhysics([freeConstraints]) Suspends physics for this object. + :arg freeConstraints: When set to `True` physics constraints used by the object are deleted. + Else when `False` (the default) constraints are restored when restoring physics. + :type freeConstraints: bool + + .. method:: restorePhysics() + + Resumes physics for this object. Also reinstates collisions. + + .. method:: suspendDynamics([ghost]) + + Suspends dynamics physics for this object. + :arg ghost: When set to `True`, collisions with the object will be ignored, similar to the "ghost" checkbox in Blender. When `False` (the default), the object becomes static but still collide with other objects. :type ghost: bool @@ -706,7 +822,7 @@ base class --- :class:`SCA_IObject` .. method:: restoreDynamics() - Resumes physics for this object. Also reinstates collisions; the object will no longer be a ghost. + Resumes dynamics physics for this object. Also reinstates collisions; the object will no longer be a ghost. .. note:: @@ -780,7 +896,7 @@ base class --- :class:`SCA_IObject` :return: (distance, globalVector(3), localVector(3)) :rtype: 3-tuple (float, 3-tuple (x, y, z), 3-tuple (x, y, z)) - .. method:: rayCastTo(other, dist, prop) + .. method:: rayCastTo(other, dist=0, prop="") Look towards another point/object and find first object hit within dist that matches prop. @@ -797,7 +913,7 @@ base class --- :class:`SCA_IObject` :return: the first object hit or None if no object or object does not match prop :rtype: :class:`KX_GameObject` - .. method:: rayCast(objto, objfrom, dist, prop, face, xray, poly, mask) + .. method:: rayCast(objto, objfrom=None, dist=0, prop="", face=False, xray=False, poly=0, mask=0xFFFF) Look from a point/object to another point/object and find first object hit within dist that matches prop. if poly is 0, returns a 3-tuple with object reference, hit point and hit normal or (None, None, None) if no hit. @@ -867,6 +983,19 @@ base class --- :class:`SCA_IObject` The ray ignores the object on which the method is called. It is casted from/to object center or explicit [x, y, z] points. + .. method:: collide(obj) + + Test if this object collides object :data:`obj`. + + :arg obj: the object to test collision with + :type obj: string or :class:`KX_GameObject` + :return: (collide, points) + + * collide, True if this object collides object :data:`obj` + * points, contact point data of the collision or None + + :rtype: 2-tuple (boolean, list of :class:`KX_CollisionContactPoint` or None) + .. method:: setCollisionMargin(margin) Set the objects collision margin. @@ -889,7 +1018,7 @@ base class --- :class:`SCA_IObject` :arg to: The name of the object to send the message to (optional) :type to: string - .. method:: reinstancePhysicsMesh(gameObject, meshObject) + .. method:: reinstancePhysicsMesh(gameObject, meshObject, dupli) Updates the physics system with the changed mesh. @@ -899,6 +1028,8 @@ base class --- :class:`SCA_IObject` :type gameObject: string, :class:`KX_GameObject` or None :arg meshObject: optional argument, set the physics shape from this mesh. :type meshObject: string, :class:`MeshProxy` or None + :arg dupli: optional argument, duplicate the physics shape. + :type dupli: boolean :return: True if reinstance succeeded, False if it failed. :rtype: boolean @@ -923,9 +1054,23 @@ base class --- :class:`SCA_IObject` Rebuilding the physics mesh can be slow, running many times per second will give a performance hit. - .. method:: get(key, default=None) + .. warning:: + + Duplicate the physics mesh can use much more memory, use this option only for duplicated meshes else use :py:meth:`replacePhysicsShape`. + + .. method:: replacePhysicsShape(gameObject) + + Replace the current physics shape. + + :arg gameObject: set the physics shape from this gameObjets. + :type gameObject: string, :class:`KX_GameObject` + + .. method:: get(key[, default]) Return the value matching key, or the default value if its not found. + :arg key: the matching key + :type key: string + :arg default: optional default value is the key isn't matching, defaults to None if no value passed. :return: The key value or a default. .. method:: playAction(name, start_frame, end_frame, layer=0, priority=0, blendin=0, play_mode=KX_ACTION_MODE_PLAY, layer_weight=0.0, ipo_flags=0, speed=1.0, blend_mode=KX_ACTION_BLEND_BLEND) @@ -955,57 +1100,57 @@ base class --- :class:`SCA_IObject` :arg blend_mode: how to blend this layer with previous layers :type blend_mode: one of :ref:`these constants ` - .. method:: stopAction(layer=0) + .. method:: stopAction([layer]) Stop playing the action on the given layer. - :arg layer: The layer to stop playing. + :arg layer: The layer to stop playing, defaults to 0 if no value passed. :type layer: integer - .. method:: getActionFrame(layer=0) + .. method:: getActionFrame([layer]) Gets the current frame of the action playing in the supplied layer. - :arg layer: The layer that you want to get the frame from. + :arg layer: The layer that you want to get the frame from, defaults to 0 if no value passed. :type layer: integer :return: The current frame of the action :rtype: float - .. method:: getActionName(layer=0) + .. method:: getActionName([layer]) Gets the name of the current action playing in the supplied layer. - :arg layer: The layer that you want to get the action name from. + :arg layer: The layer that you want to get the action name from, defaults to 0 if no value passed. :type layer: integer :return: The name of the current action :rtype: string - .. method:: setActionFrame(frame, layer=0) + .. method:: setActionFrame(frame[, layer]) Set the current frame of the action playing in the supplied layer. - :arg layer: The layer where you want to set the frame + :arg layer: The layer where you want to set the frame, default to 0 if no value passed. :type layer: integer :arg frame: The frame to set the action to :type frame: float - .. method:: isPlayingAction(layer=0) + .. method:: isPlayingAction([layer]) Checks to see if there is an action playing in the given layer. - :arg layer: The layer to check for a playing action. + :arg layer: The layer to check for a playing action, defaults to 0 if no value passed. :type layer: integer :return: Whether or not the action is playing :rtype: boolean - .. method:: addDebugProperty (name, debug = True) + .. method:: addDebugProperty (name[, debug]) Adds a single debug property to the debug list. :arg name: name of the property that added to the debug list. :type name: string - :arg debug: the debug state. + :arg debug: the debug state, default to True is no value passed. :type debug: boolean diff --git a/doc/python_api/rst/bge_types/bge.types.KX_LibLoadStatus.rst b/doc/python_api/rst/bge_types/bge.types.KX_LibLoadStatus.rst index 3e7d370476e3..1fef7a9d119a 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_LibLoadStatus.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_LibLoadStatus.rst @@ -1,9 +1,9 @@ -KX_LibLoadStatus(PyObjectPlus) -============================== +KX_LibLoadStatus(EXP_PyObjectPlus) +================================== -base class --- :class:`PyObjectPlus` +base class --- :class:`EXP_PyObjectPlus` -.. class:: KX_LibLoadStatus(PyObjectPlus) +.. class:: KX_LibLoadStatus(EXP_PyObjectPlus) An object providing information about a LibLoad() operation. @@ -15,7 +15,7 @@ base class --- :class:`PyObjectPlus` def finished_cb(status): print("Library (%s) loaded in %.2fms." % (status.libraryName, status.timeTaken)) - bge.logic.LibLoad('myblend.blend', 'Scene', async=True).onFinish = finished_cb + bge.logic.LibLoad('myblend.blend', 'Scene', asynchronous=True).onFinish = finished_cb .. attribute:: onFinish diff --git a/doc/python_api/rst/bge_types/bge.types.KX_LightObject.rst b/doc/python_api/rst/bge_types/bge.types.KX_LightObject.rst index ca4e4eaf1b35..082d499cfa07 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_LightObject.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_LightObject.rst @@ -30,16 +30,14 @@ base class --- :class:`KX_GameObject` A point light source. See attribute :data:`type` + .. data:: HEMI + + A hemi light source. See attribute :data:`type` + .. attribute:: type The type of light - must be SPOT, SUN or NORMAL - .. attribute:: layer - - The layer mask that this light affects object on. - - :type: bitfield - .. attribute:: energy The brightness of this light. @@ -159,3 +157,13 @@ base class --- :class:`KX_GameObject` .. note:: Higher values result in a more focused light source. + + .. attribute:: staticShadow + + Enables static shadows. By default (staticShadow=False) the shadow cast by the lamp is recalculated every frame. When this is not needed, set staticShadow=True. In that case, call :py:meth:`updateShadow` to request a shadow update. + + :type: boolean. + + .. method:: updateShadow() + + Set the shadow to be updated next frame if the lamp uses a static shadow, see :data:`staticShadow`. diff --git a/doc/python_api/rst/bge_types/bge.types.KX_LodLevel.rst b/doc/python_api/rst/bge_types/bge.types.KX_LodLevel.rst new file mode 100644 index 000000000000..e6c91fbd38ea --- /dev/null +++ b/doc/python_api/rst/bge_types/bge.types.KX_LodLevel.rst @@ -0,0 +1,50 @@ +KX_LodLevel(EXP_PyObjectPlus) +============================= + +base class --- :class:`EXP_PyObjectPlus` + +.. class:: KX_LodLevel(EXP_PyObjectPlus) + + A single lod level for a game object lod manager. + + .. attribute:: mesh + + The mesh used for this lod level. (read only) + + :type: :class:`RAS_MeshObject` + + .. attribute:: level + + The number of the lod level. (read only) + + :type: integer + + .. attribute:: distance + + Distance to begin using this level of detail. (read only) + + :type: float (0.0 to infinite) + + .. attribute:: hysteresis + + Minimum distance factor change required to transition to the previous level of detail in percent. (read only) + + :type: float [0.0 to 100.0] + + .. attribute:: useMesh + + Return True if the lod level uses a different mesh than the original object mesh. (read only) + + :type: boolean + + .. attribute:: useMaterial + + Return True if the lod level uses a different material than the original object mesh material. (read only) + + :type: boolean + + .. attribute:: useHysteresis + + Return true if the lod level uses hysteresis override. (read only) + + :type: boolean diff --git a/doc/python_api/rst/bge_types/bge.types.KX_LodManager.rst b/doc/python_api/rst/bge_types/bge.types.KX_LodManager.rst new file mode 100644 index 000000000000..dd04b0008afe --- /dev/null +++ b/doc/python_api/rst/bge_types/bge.types.KX_LodManager.rst @@ -0,0 +1,20 @@ +KX_LodManager(EXP_PyObjectPlus) +=============================== + +base class --- :class:`EXP_PyObjectPlus` + +.. class:: KX_LodManager(EXP_PyObjectPlus) + + This class contains a list of all levels of detail used by a game object. + + .. attribute:: levels + + Return the list of all levels of detail of the lod manager. + + :type: list of :class:`KX_LodLevel` + + .. attribute:: distanceFactor + + Method to multiply the distance to the camera. + + :type: float diff --git a/doc/python_api/rst/bge_types/bge.types.KX_MeshProxy.rst b/doc/python_api/rst/bge_types/bge.types.KX_Mesh.rst similarity index 74% rename from doc/python_api/rst/bge_types/bge.types.KX_MeshProxy.rst rename to doc/python_api/rst/bge_types/bge.types.KX_Mesh.rst index c009db17e4d2..346e782e31f5 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_MeshProxy.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_Mesh.rst @@ -1,9 +1,9 @@ -KX_MeshProxy(SCA_IObject) -========================= +KX_Mesh(EXP_Value) +================== -base class --- :class:`SCA_IObject` +base class --- :class:`EXP_Value` -.. class:: KX_MeshProxy(SCA_IObject) +.. class:: KX_Mesh(EXP_Value) A mesh object. @@ -59,6 +59,12 @@ base class --- :class:`SCA_IObject` :type: integer + .. attribute:: polygons + + Returns the list of polygons of this mesh. + + :type: :class:`KX_PolyProxy` list (read only) + .. method:: getMaterialName(matid) Gets the name of the specified material. @@ -129,3 +135,37 @@ base class --- :class:`SCA_IObject` :type uv_index: integer :arg uv_index_from: optional uv index to copy from, -1 to transform the current uv. :type uv_index_from: integer + .. method:: replaceMaterial(matid, material) + + Replace the material in slot :data:`matid` by the material :data:`material`. + + :arg matid: The material index. + :type matid: integer + :arg material: The material replacement. + :type material: :class:`KX_BlenderMaterial` + + .. warning:: + + Changing the material of a mesh used by many objects can be slow. This function should be not called every frames + + .. method:: copy() + + Return a duplicated mesh. + + :return: a duplicated mesh of the current used. + :rtype: :class:`KX_Mesh`. + + .. method:: constructBvh(transform=mathutils.Matrix.Identity(4), epsilon=0) + + Return a BVH tree based on mesh geometry. Indices of tree elements match polygons indices. + + :arg transform: The transform 4x4 matrix applied to vertices. + :type transform: :class:`mathutils.Matrix` + :arg epsilon: The tree distance epsilon. + :type epsilon: float + :return: A BVH tree based on mesh geometry. + :rtype: :class:`mathutils.bvhtree.BVHTree` + + .. method:: destruct() + + Destruct the mesh. diff --git a/doc/python_api/rst/bge_types/bge.types.KX_MouseActuator.rst b/doc/python_api/rst/bge_types/bge.types.KX_MouseActuator.rst index e0fe32baa2b3..7bef4dac5cfd 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_MouseActuator.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_MouseActuator.rst @@ -33,7 +33,7 @@ base class --- :class:`SCA_IActuator` Amount of movement from the mouse required before rotation is triggered. - :type: list (vector of 2 floats) + :type: :class:`mathutils.Vector` The values in the list should be between 0.0 and 0.5. @@ -75,7 +75,7 @@ base class --- :class:`SCA_IActuator` The amount of rotation caused by mouse movement along the x and y axis. - :type: list (vector of 2 floats) + :type: :class:`mathutils.Vector` Negative values invert the rotation. @@ -84,17 +84,17 @@ base class --- :class:`SCA_IActuator` The minimum and maximum angle of rotation caused by mouse movement along the x axis in degrees. limit_x[0] is minimum, limit_x[1] is maximum. - :type: list (vector of 2 floats) + :type: :class:`mathutils.Vector` .. attribute:: limit_y The minimum and maximum angle of rotation caused by mouse movement along the y axis in degrees. limit_y[0] is minimum, limit_y[1] is maximum. - :type: list (vector of 2 floats) + :type: :class:`mathutils.Vector` .. attribute:: angle The current rotational offset caused by the mouse actuator in degrees. - :type: list (vector of 2 floats) + :type: :class:`mathutils.Vector` diff --git a/doc/python_api/rst/bge_types/bge.types.KX_MouseFocusSensor.rst b/doc/python_api/rst/bge_types/bge.types.KX_MouseFocusSensor.rst index 1d7eb007c1e3..983f63b44591 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_MouseFocusSensor.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_MouseFocusSensor.rst @@ -68,6 +68,13 @@ base class --- :class:`SCA_MouseSensor` :type: boolean + .. attribute:: mask + + The collision mask (16 layers mapped to a 16-bit integer) combined with each object's collision group, to hit only a subset of the + objects in the scene. Only those objects for which ``collisionGroup & mask`` is true can be hit. + + :type: bitfield + .. attribute:: propName The property or material the sensor is looking for. diff --git a/doc/python_api/rst/bge_types/bge.types.KX_NearSensor.rst b/doc/python_api/rst/bge_types/bge.types.KX_NearSensor.rst index 91969dfc79d6..f15b4f1b2fe3 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_NearSensor.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_NearSensor.rst @@ -1,9 +1,9 @@ -KX_NearSensor(KX_TouchSensor) -============================= +KX_NearSensor(KX_CollisionSensor) +================================= -base class --- :class:`KX_TouchSensor` +base class --- :class:`KX_CollisionSensor` -.. class:: KX_NearSensor(KX_TouchSensor) +.. class:: KX_NearSensor(KX_CollisionSensor) A near sensor is a specialised form of touch sensor. diff --git a/doc/python_api/rst/bge_types/bge.types.KX_PlanarMap.rst b/doc/python_api/rst/bge_types/bge.types.KX_PlanarMap.rst new file mode 100644 index 000000000000..ec2617dd1839 --- /dev/null +++ b/doc/python_api/rst/bge_types/bge.types.KX_PlanarMap.rst @@ -0,0 +1,14 @@ +KX_PlanarMap(KX_TextureRenderer) +================================ + +base class --- :class:`KX_TextureRenderer` + +.. class:: KX_PlanarMap(KX_TextureRenderer) + + Python API for realtime planar map textures. + + .. attribute:: normal + + Plane normal used to compute the reflection or refraction orientation of the render camera. + + :type: :class:`mathutils.Vector` diff --git a/doc/python_api/rst/bge_types/bge.types.KX_PolyProxy.rst b/doc/python_api/rst/bge_types/bge.types.KX_PolyProxy.rst index 68baff8d45c9..0fcbf25e598d 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_PolyProxy.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_PolyProxy.rst @@ -55,8 +55,7 @@ base class --- :class:`SCA_IObject` .. attribute:: v4 - Vertex index of the fourth vertex of the polygon, 0 if polygon has only 3 vertex - Use this to retrieve vertex proxy from mesh proxy. + .. deprecated:: polygons are triangles. :type: integer @@ -72,6 +71,12 @@ base class --- :class:`SCA_IObject` :type: integer + .. attribute:: vertices + + Returns the list of vertices of this polygon. + + :type: :class:`KX_VertexProxy` list (read only) + .. method:: getMaterialName() Returns the polygon material name with MA prefix @@ -101,7 +106,7 @@ base class --- :class:`SCA_IObject` Returns the number of vertex of the polygon. - :return: number of vertex, 3 or 4. + :return: number of vertex. :rtype: integer .. method:: isVisible() @@ -123,7 +128,7 @@ base class --- :class:`SCA_IObject` Returns the mesh vertex index of a polygon vertex This index and the one returned by getMaterialIndex() are needed to retrieve the vertex proxy from :class:`MeshProxy`. - :arg vertex: index of the vertex in the polygon: 0->3 + :arg vertex: index of the vertex in the polygon: 0->2 :arg vertex: integer :return: mesh vertex index :rtype: integer diff --git a/doc/python_api/rst/bge_types/bge.types.KX_PythonComponent.rst b/doc/python_api/rst/bge_types/bge.types.KX_PythonComponent.rst new file mode 100644 index 000000000000..dbf64c10fe88 --- /dev/null +++ b/doc/python_api/rst/bge_types/bge.types.KX_PythonComponent.rst @@ -0,0 +1,149 @@ +KX_PythonComponent(EXP_Value) +============================= + +base class --- :class:`EXP_Value` + +.. class:: KX_PythonComponent(EXP_Value) + + Python component can be compared to python logic bricks with parameters. + The python component is a script loaded in the UI, this script defined a component class by inheriting from :class:`KX_PythonComponent`. + This class must contain a dictionary of properties: :attr:`args` and two default functions: :meth:`start` and :meth:`update`. + + The script must have .py extension. + + The component properties are loaded from the :attr:`args` attribute from the UI at loading time. + When the game start the function :meth:`start` is called with as arguments a dictionary of the properties' name and value. + The :meth:`update` function is called every frames during the logic stage before running logics bricks, + the goal of this function is to handle and process everything. + + The following component example moves and rotates the object when pressing the keys W, A, S and D. + + .. code-block:: python + + import bge + from collections import OrderedDict + + class ThirdPerson(bge.types.KX_PythonComponent): + """Basic third person controls + + W: move forward + A: turn left + S: move backward + D: turn right + + """ + + # + + args = OrderedDict([ + ("Move Speed", 0.1), + ("Turn Speed", 0.04) + ]) + + def start(self, args): + self.move_speed = args['Move Speed'] + self.turn_speed = args['Turn Speed'] + + def update(self): + keyboard = bge.logic.keyboard.events + + move = 0 + rotate = 0 + + if keyboard[bge.events.WKEY]: + move += self.move_speed + if keyboard[bge.events.SKEY]: + move -= self.move_speed + + if keyboard[bge.events.AKEY]: + rotate += self.turn_speed + if keyboard[bge.events.DKEY]: + rotate -= self.turn_speed + + self.object.applyMovement((0, move, 0), True) + self.object.applyRotation((0, 0, rotate), True) + + Since the components are loaded for the first time outside the bge, then :attr:`bge` is a fake module that contains only the class + :class:`KX_PythonComponent` to avoid importing all the bge modules. + This behavior is safer but creates some issues at loading when the user want to use functions or attributes from the bge modules other + than the :class:`KX_PythonComponent` class. The way is to not call these functions at loading outside the bge. To detect it, the bge + module contains the attribute :attr:`__component__` when it's imported outside the bge. + + The following component example add a "Cube" object at initialization and move it along x for each update. It shows that the user can + use functions from scene and load the component outside the bge by setting global attributes in a condition at the beginning of the + script. + + .. code-block:: python + + import bge + + if not hasattr(bge, "__component__"): + global scene + scene = bge.logic.getCurrentScene() + + class Component(bge.types.KX_PythonComponent): + args = {} + + def start(self, args): + scene.addObject("Cube") + + def update(self): + scene.objects["Cube"].worldPosition.x += 0.1 + + The property types supported are float, integer, boolean, string, set (for enumeration) and Vector 2D, 3D and 4D. The following example + show all of these property types. + + .. code-block:: python + + from bge import * + from mathutils import * + from collections import OrderedDict + + class Component(types.KX_PythonComponent): + args = OrderedDict([ + ("Float", 58.6), + ("Integer", 150), + ("Boolean", True), + ("String", "Cube"), + ("Enum", {"Enum 1", "Enum 2", "Enum 3"}), + ("Vector 2D", Vector((0.8, 0.7))), + ("Vector 3D", Vector((0.4, 0.3, 0.1))), + ("Vector 4D", Vector((0.5, 0.2, 0.9, 0.6))) + ]) + + def start(self, args): + print(args) + + def update(self): + pass + + .. attribute:: object + + The object owner of the component. + + :type: :class:`KX_GameObject` + + .. attribute:: args + + Dictionary of the component properties, the keys are string and the value can be: float, integer, Vector(2D/3D/4D), set, string. + + :type: dict + + .. method:: start(args) + + Initialize the component. + + :arg args: The dictionary of the properties' name and value. + :type args: dict + + .. warning:: + + This function must be inherited in the python component class. + + .. method:: update() + + Process the logic of the component. + + .. warning:: + + This function must be inherited in the python component class. diff --git a/doc/python_api/rst/bge_types/bge.types.KX_RadarSensor.rst b/doc/python_api/rst/bge_types/bge.types.KX_RadarSensor.rst index 82028cfc1861..955893bd5c3b 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_RadarSensor.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_RadarSensor.rst @@ -11,13 +11,13 @@ base class --- :class:`KX_NearSensor` The origin of the cone with which to test. The origin is in the middle of the cone. (read-only). - :type: list of floats [x, y, z] + :type: :class:`mathutils.Vector` .. attribute:: coneTarget The center of the bottom face of the cone with which to test. (read-only). - :type: list of floats [x, y, z] + :type: :class:`mathutils.Vector` .. attribute:: distance diff --git a/doc/python_api/rst/bge_types/bge.types.KX_RaySensor.rst b/doc/python_api/rst/bge_types/bge.types.KX_RaySensor.rst index 75e171dd6124..0e2722bd04c7 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_RaySensor.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_RaySensor.rst @@ -31,6 +31,13 @@ base class --- :class:`SCA_ISensor` :type: boolean + .. attribute:: mask + + The collision mask (16 layers mapped to a 16-bit integer) combined with each object's collision group, to hit only a subset of the + objects in the scene. Only those objects for which ``collisionGroup & mask`` is true can be hit. + + :type: bitfield + .. attribute:: hitObject The game object that was hit by the ray. (read-only). @@ -41,13 +48,13 @@ base class --- :class:`SCA_ISensor` The position (in worldcoordinates) where the object was hit by the ray. (read-only). - :type: list [x, y, z] + :type: :class:`mathutils.Vector` .. attribute:: hitNormal The normal (in worldcoordinates) of the object at the location where the object was hit by the ray. (read-only). - :type: list [x, y, z] + :type: :class:`mathutils.Vector` .. attribute:: hitMaterial @@ -59,7 +66,7 @@ base class --- :class:`SCA_ISensor` The direction from the ray (in worldcoordinates). (read-only). - :type: list [x, y, z] + :type: :class:`mathutils.Vector` .. attribute:: axis diff --git a/doc/python_api/rst/bge_types/bge.types.KX_SCA_AddObjectActuator.rst b/doc/python_api/rst/bge_types/bge.types.KX_SCA_AddObjectActuator.rst index 9b7d2ad874ad..89a7585249fa 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_SCA_AddObjectActuator.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_SCA_AddObjectActuator.rst @@ -31,7 +31,7 @@ base class --- :class:`SCA_IActuator` the lifetime of added objects, in frames. Set to 0 to disable automatic deletion. - :type: integer + :type: float .. attribute:: linearVelocity diff --git a/doc/python_api/rst/bge_types/bge.types.KX_Scene.rst b/doc/python_api/rst/bge_types/bge.types.KX_Scene.rst index 7e632d2c8d45..a0da33a4d894 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_Scene.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_Scene.rst @@ -1,9 +1,9 @@ -KX_Scene(PyObjectPlus) -====================== +KX_Scene(EXP_PyObjectPlus) +========================== -base class --- :class:`PyObjectPlus` +base class --- :class:`EXP_PyObjectPlus` -.. class:: KX_Scene(PyObjectPlus) +.. class:: KX_Scene(EXP_PyObjectPlus) An active scene that gives access to objects, cameras, lights and scene attributes. @@ -51,59 +51,71 @@ base class --- :class:`PyObjectPlus` A list of objects in the scene, (read-only). - :type: :class:`CListValue` of :class:`KX_GameObject` + :type: :class:`EXP_ListValue` of :class:`KX_GameObject` .. attribute:: objectsInactive A list of objects on background layers (used for the addObject actuator), (read-only). - :type: :class:`CListValue` of :class:`KX_GameObject` + :type: :class:`EXP_ListValue` of :class:`KX_GameObject` .. attribute:: lights A list of lights in the scene, (read-only). - :type: :class:`CListValue` of :class:`KX_LightObject` + :type: :class:`EXP_ListValue` of :class:`KX_LightObject` .. attribute:: cameras A list of cameras in the scene, (read-only). - :type: :class:`CListValue` of :class:`KX_Camera` + :type: :class:`EXP_ListValue` of :class:`KX_Camera` + + .. attribute:: texts + + A list of texts in the scene, (read-only). + + :type: :class:`EXP_ListValue` of :class:`KX_FontObject` .. attribute:: active_camera The current active camera. :type: :class:`KX_Camera` - + .. note:: - + This can be set directly from python to avoid using the :class:`KX_SceneActuator`. + .. attribute:: overrideCullingCamera + + The override camera used for scene culling, if set to None the culling is proceeded with the camera used to render. + + :type: :class:`KX_Camera` or None + .. attribute:: world The current active world, (read-only). :type: :class:`KX_WorldInfo` - .. attribute:: suspended + .. attribute:: filterManager - True if the scene is suspended, (read-only). + The scene's 2D filter manager, (read-only). - :type: boolean + :type: :class:`KX_2DFilterManager` - .. attribute:: activity_culling + .. attribute:: suspended - True if the scene is activity culling. + True if the scene is suspended, (read-only). :type: boolean - .. attribute:: activity_culling_radius + .. attribute:: activityCulling - The distance outside which to do activity culling. Measured in manhattan distance. + True if the scene allow object activity culling. - :type: float + :type: boolean .. attribute:: dbvt_culling @@ -113,7 +125,7 @@ base class --- :class:`PyObjectPlus` .. attribute:: pre_draw - A list of callables to be run before the render step. + A list of callables to be run before the render step. The callbacks can take as argument the rendered camera. :type: list @@ -126,6 +138,19 @@ base class --- :class:`PyObjectPlus` .. attribute:: pre_draw_setup A list of callables to be run before the drawing setup (i.e., before the model view and projection matrices are computed). + The callbacks can take as argument the rendered camera, the camera could be temporary in case of stereo rendering. + + :type: list + + .. attribute:: onRemove + + A list of callables to run when the scene is destroyed. + + .. code-block:: python + + @scene.onRemove.append + def callback(scene): + print('exiting %s...' % scene.name) :type: list @@ -135,7 +160,7 @@ base class --- :class:`PyObjectPlus` :type: Vector((gx, gy, gz)) - .. method:: addObject(object, reference, time=0) + .. method:: addObject(object, reference, time=0.0) Adds an object to the scene like the Add Object Actuator would. @@ -143,8 +168,8 @@ base class --- :class:`PyObjectPlus` :type object: :class:`KX_GameObject` or string :arg reference: The (name of the) object which position, orientation, and scale to copy (optional), if the object to add is a light and there is not reference the light's layer will be the same that the active layer in the blender scene. :type reference: :class:`KX_GameObject` or string - :arg time: The lifetime of the added object, in frames. A time of 0 means the object will last forever (optional). - :type time: integer + :arg time: The lifetime of the added object, in frames (assumes one frame is 1/50 second). A time of 0.0 means the object will last forever (optional). + :type time: float :return: The newly added object. :rtype: :class:`KX_GameObject` diff --git a/doc/python_api/rst/bge_types/bge.types.KX_SteeringActuator.rst b/doc/python_api/rst/bge_types/bge.types.KX_SteeringActuator.rst index 9e2f2a427a13..f4672f6b9cac 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_SteeringActuator.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_SteeringActuator.rst @@ -66,3 +66,8 @@ base class --- :class:`SCA_IActuator` Path update period :type: int + .. attribute:: path + + Path point list. + + :type: list of :class:`mathutils.Vector` diff --git a/doc/python_api/rst/bge_types/bge.types.KX_TextureRenderer.rst b/doc/python_api/rst/bge_types/bge.types.KX_TextureRenderer.rst new file mode 100644 index 000000000000..dddce7f09c63 --- /dev/null +++ b/doc/python_api/rst/bge_types/bge.types.KX_TextureRenderer.rst @@ -0,0 +1,56 @@ +KX_TextureRenderer(EXP_Value) +============================= + +base class --- :class:`EXP_Value` + +.. class:: KX_TextureRenderer(EXP_Value) + + Python API for object doing a render stored in a texture. + + .. attribute:: autoUpdate + + Choose to update automatically each frame the texture renderer or not. + + :type: boolean + + .. attribute:: viewpointObject + + The object where the texture renderer will render the scene. + + :type: :class:`KX_GameObject` + + .. attribute:: enabled + + Enable the texture renderer to render the scene. + + :type: boolean + + .. attribute:: ignoreLayers + + The layers to ignore when rendering. + + :type: bitfield + + .. attribute:: clipStart + + The projection view matrix near plane, used for culling. + + :type: float + + .. attribute:: clipEnd + + The projection view matrix far plane, used for culling. + + :type: float + + .. attribute:: lodDistanceFactor + + The factor to multiply distance to camera to adjust levels of detail. + A float < 1.0f will make the distance to camera used to compute + levels of detail decrease. + + :type: float + + .. method:: update() + + Request to update this texture renderer during the rendering stage. This function is effective only when :data:`autoUpdate` is disabled. diff --git a/doc/python_api/rst/bge_types/bge.types.KX_VehicleWrapper.rst b/doc/python_api/rst/bge_types/bge.types.KX_VehicleWrapper.rst index 0d7b7103ba43..991c5afed998 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_VehicleWrapper.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_VehicleWrapper.rst @@ -1,9 +1,9 @@ -KX_VehicleWrapper(PyObjectPlus) -=============================== +KX_VehicleWrapper(EXP_PyObjectPlus) +=================================== -base class --- :class:`PyObjectPlus` +base class --- :class:`EXP_PyObjectPlus` -.. class:: KX_VehicleWrapper(PyObjectPlus) +.. class:: KX_VehicleWrapper(EXP_PyObjectPlus) KX_VehicleWrapper @@ -161,3 +161,8 @@ base class --- :class:`PyObjectPlus` :arg wheelIndex: the wheel index :type wheelIndex: integer + .. attribute:: rayMask + + Set ray cast mask. + + :type: bitfield diff --git a/doc/python_api/rst/bge_types/bge.types.KX_VertexProxy.rst b/doc/python_api/rst/bge_types/bge.types.KX_VertexProxy.rst index f6b52affa274..9d02120ce43e 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_VertexProxy.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_VertexProxy.rst @@ -23,6 +23,12 @@ base class --- :class:`SCA_IObject` :type: Vector((u, v)) + .. attribute:: uvs + + The texture coordinates list of the vertex. + + :type: list of Vector((u, v)) + .. attribute:: normal The normal of the vertex. @@ -37,6 +43,12 @@ base class --- :class:`SCA_IObject` Black = [0.0, 0.0, 0.0, 1.0], White = [1.0, 1.0, 1.0, 1.0] + .. attribute:: colors + + The color list of the vertex. + + :type: list of Vector((r, g, b, a)) + .. attribute:: x The x coordinate of the vertex. diff --git a/doc/python_api/rst/bge_types/bge.types.KX_WorldInfo.rst b/doc/python_api/rst/bge_types/bge.types.KX_WorldInfo.rst index d96d1c1190fc..92dd651d3c8e 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_WorldInfo.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_WorldInfo.rst @@ -1,9 +1,9 @@ -KX_WorldInfo(PyObjectPlus) -============================= +KX_WorldInfo(EXP_PyObjectPlus) +============================== -base class --- :class:`PyObjectPlus` +base class --- :class:`EXP_PyObjectPlus` -.. class:: KX_WorldInfo(PyObjectPlus) +.. class:: KX_WorldInfo(EXP_PyObjectPlus) A world object. @@ -63,15 +63,53 @@ base class --- :class:`PyObjectPlus` :type: :class:`mathutils.Color` - .. attribute:: backgroundColor + .. attribute:: horizonColor - The color of the background. Black = [0.0, 0.0, 0.0], White = [1.0, 1.0, 1.0]. - Mist and background color sould always set to the same color. + The horizon color. Black = [0.0, 0.0, 0.0, 1.0], White = [1.0, 1.0, 1.0, 1.0]. + Mist and horizon color should always be set to the same color. - :type: :class:`mathutils.Color` + :type: :class:`mathutils.Vector` + + .. attribute:: zenithColor + + The zenith color. Black = [0.0, 0.0, 0.0, 1.0], White = [1.0, 1.0, 1.0, 1.0]. + + :type: :class:`mathutils.Vector` .. attribute:: ambientColor The color of the ambient light. Black = [0.0, 0.0, 0.0], White = [1.0, 1.0, 1.0]. :type: :class:`mathutils.Color` + + .. attribute:: exposure + + Amount of exponential color correction for light. + + :type: float between 0.0 and 1.0 inclusive + + .. attribute:: range + + The color range that will be mapped to 0 - 1. + + :type: float between 0.2 and 5.0 inclusive + + .. attribute:: envLightEnergy + + The environment light energy. + + :type: float from 0.0 to infinite + + .. attribute:: envLightEnabled + + Returns True if Environment Lighting is enabled. Else returns False + + :type: bool (read only) + + .. attribute:: envLightColor + + White: returns 0 + SkyColor: returns 1 + SkyTexture: returns 2 + + :type: int (read only) diff --git a/doc/python_api/rst/bge_types/bge.types.SCA_ILogicBrick.rst b/doc/python_api/rst/bge_types/bge.types.SCA_ILogicBrick.rst index e8d9413d7e56..598d797d991f 100644 --- a/doc/python_api/rst/bge_types/bge.types.SCA_ILogicBrick.rst +++ b/doc/python_api/rst/bge_types/bge.types.SCA_ILogicBrick.rst @@ -1,9 +1,9 @@ -SCA_ILogicBrick(CValue) -======================= +SCA_ILogicBrick(EXP_Value) +========================== -base class --- :class:`CValue` +base class --- :class:`EXP_Value` -.. class:: SCA_ILogicBrick(CValue) +.. class:: SCA_ILogicBrick(EXP_Value) Base class for all logic bricks. diff --git a/doc/python_api/rst/bge_types/bge.types.SCA_IObject.rst b/doc/python_api/rst/bge_types/bge.types.SCA_IObject.rst index a3080879fd0b..098ce65643b4 100644 --- a/doc/python_api/rst/bge_types/bge.types.SCA_IObject.rst +++ b/doc/python_api/rst/bge_types/bge.types.SCA_IObject.rst @@ -1,8 +1,8 @@ -SCA_IObject(CValue) -=================== +SCA_IObject(EXP_Value) +====================== -base class --- :class:`CValue` +base class --- :class:`EXP_Value` -.. class:: SCA_IObject(CValue) +.. class:: SCA_IObject(EXP_Value) This class has no python functions diff --git a/doc/python_api/rst/bge_types/bge.types.SCA_InputEvent.rst b/doc/python_api/rst/bge_types/bge.types.SCA_InputEvent.rst new file mode 100644 index 000000000000..3a1f70b9624a --- /dev/null +++ b/doc/python_api/rst/bge_types/bge.types.SCA_InputEvent.rst @@ -0,0 +1,76 @@ +SCA_InputEvent(EXP_PyObjectPlus) +================================ + +base class --- :class:`EXP_PyObjectPlus` + +.. class:: SCA_InputEvent(EXP_PyObjectPlus) + + Events for a keyboard or mouse input. + + .. attribute:: status + + A list of existing status of the input from the last frame. + Can contain :data:`bge.logic.KX_INPUT_NONE` and :data:`bge.logic.KX_INPUT_ACTIVE`. + The list always contains one value. + The first value of the list is the last value of the list in the last frame. (read-only) + + :type: list of integer. + + .. attribute:: queue + + A list of existing events of the input from the last frame. + Can contain :data:`bge.logic.KX_INPUT_JUST_ACTIVATED` and :data:`bge.logic.KX_INPUT_JUST_RELEASED`. + The list can be empty. (read-only) + + :type: list of integer. + + .. attribute:: values + + A list of existing value of the input from the last frame. + For keyboard it contains 1 or 0 and for mouse the coordinate of the mouse or the movement of the wheel mouse. + The list contains always one value, the size of the list is the same than :data:`queue` + 1 only for keyboard inputs. + The first value of the list is the last value of the list in the last frame. (read-only) + + Example to get the non-normalized mouse coordinates: + + .. code-block:: python + + import bge + + x = bge.logic.mouse.inputs[bge.events.MOUSEX].values[-1] + y = bge.logic.mouse.inputs[bge.events.MOUSEY].values[-1] + + print("Mouse non-normalized position: x: {0}, y: {1}".format(x, y)) + + :type: list of integer. + + .. attribute:: inactive + + True if the input was inactive from the last frame. + + :type: boolean + + .. attribute:: active + + True if the input was active from the last frame. + + :type: boolean + + .. attribute:: activated + + True if the input was activated from the last frame. + + :type: boolean + + .. attribute:: released + + True if the input was released from the last frame. + + :type: boolean + + .. attribute:: type + + The type of the input. + One of :ref:`these constants` + + :type: integer diff --git a/doc/python_api/rst/bge_types/bge.types.SCA_JoystickSensor.rst b/doc/python_api/rst/bge_types/bge.types.SCA_JoystickSensor.rst index 824b9932dc1a..2a107bcedf39 100644 --- a/doc/python_api/rst/bge_types/bge.types.SCA_JoystickSensor.rst +++ b/doc/python_api/rst/bge_types/bge.types.SCA_JoystickSensor.rst @@ -31,7 +31,7 @@ base class --- :class:`SCA_ISensor` Only use this for "Single Axis" type sensors otherwise it will raise an error. - .. attribute:: hatValues + .. attribute:: hatValues (Deprecated. Use :data:button instead) The state of the joysticks hats as a list of values :data:`numHats` long. (read-only). @@ -51,7 +51,7 @@ base class --- :class:`SCA_ISensor` * 12:Down - Left * 9:Up - Left - .. attribute:: hatSingle + .. attribute:: hatSingle (Deprecated. Use :data:button instead) Like :data:`hatValues` but returns a single hat direction value that is set by the sensor. (read-only). @@ -69,7 +69,7 @@ base class --- :class:`SCA_ISensor` :type: integer - .. attribute:: numHats + .. attribute:: numHats (Deprecated. Use :data:numButtons instead) The number of hats for the joystick at this index. (read-only). @@ -108,7 +108,7 @@ base class --- :class:`SCA_ISensor` :type: [integer, integer] - .. attribute:: hat + .. attribute:: hat (Deprecated. Use :data:button instead) The hat the sensor reacts to, as a list of two values: [hatIndex, hatDirection] diff --git a/doc/python_api/rst/bge_types/bge.types.SCA_KeyboardSensor.rst b/doc/python_api/rst/bge_types/bge.types.SCA_KeyboardSensor.rst index 7450d9c19bbf..e0caa921938c 100644 --- a/doc/python_api/rst/bge_types/bge.types.SCA_KeyboardSensor.rst +++ b/doc/python_api/rst/bge_types/bge.types.SCA_KeyboardSensor.rst @@ -45,10 +45,18 @@ base class --- :class:`SCA_ISensor` :type: boolean + .. attribute:: inputs + + A list of pressed input keys that have either been pressed, or just released, or are active this frame. (read-only). + + :type: dictionary {:ref:`keycode`::class:`SCA_InputEvent`, ...} + .. attribute:: events a list of pressed keys that have either been pressed, or just released, or are active this frame. (read-only). + .. deprecated:: use :data:`inputs` + :type: list [[:ref:`keycode`, :ref:`status`], ...] .. method:: getKeyStatus(keycode) diff --git a/doc/python_api/rst/bge_types/bge.types.SCA_PythonJoystick.rst b/doc/python_api/rst/bge_types/bge.types.SCA_PythonJoystick.rst index a8867ee7f962..84912f0245df 100644 --- a/doc/python_api/rst/bge_types/bge.types.SCA_PythonJoystick.rst +++ b/doc/python_api/rst/bge_types/bge.types.SCA_PythonJoystick.rst @@ -1,9 +1,9 @@ -SCA_PythonJoystick(PyObjectPlus) -================================ +SCA_PythonJoystick(EXP_PyObjectPlus) +==================================== -base class --- :class:`PyObjectPlus` +base class --- :class:`EXP_PyObjectPlus` -.. class:: SCA_PythonJoystick(PyObjectPlus) +.. class:: SCA_PythonJoystick(EXP_PyObjectPlus) A Python interface to a joystick. @@ -35,7 +35,7 @@ base class --- :class:`PyObjectPlus` * up:[0.0, -1.0, ...] * down:[0.0, 1.0, ...] - .. attribute:: hatValues + .. attribute:: hatValues (Deprecated. Use :data:`activeButtons` instead) The state of the joysticks hats as a list of values :data:`numHats` long. (read-only). @@ -67,7 +67,7 @@ base class --- :class:`PyObjectPlus` :type: integer - .. attribute:: numHats + .. attribute:: numHats (Deprecated. Use :data:`numButtons` instead) The number of hats for the joystick at this index. (read-only). diff --git a/doc/python_api/rst/bge_types/bge.types.SCA_PythonKeyboard.rst b/doc/python_api/rst/bge_types/bge.types.SCA_PythonKeyboard.rst index 59a3d99efc2c..571a9a2ab567 100644 --- a/doc/python_api/rst/bge_types/bge.types.SCA_PythonKeyboard.rst +++ b/doc/python_api/rst/bge_types/bge.types.SCA_PythonKeyboard.rst @@ -1,24 +1,45 @@ -SCA_PythonKeyboard(PyObjectPlus) -================================ +SCA_PythonKeyboard(EXP_PyObjectPlus) +==================================== -base class --- :class:`PyObjectPlus` +base class --- :class:`EXP_PyObjectPlus` -.. class:: SCA_PythonKeyboard(PyObjectPlus) +.. class:: SCA_PythonKeyboard(EXP_PyObjectPlus) The current keyboard. + .. attribute:: inputs + + A dictionary containing the input of each keyboard key. (read-only). + + :type: dictionary {:ref:`keycode`::class:`SCA_InputEvent`, ...} + .. attribute:: events A dictionary containing the status of each keyboard event or key. (read-only). + .. deprecated:: use :data:`inputs` + :type: dictionary {:ref:`keycode`::ref:`status`, ...} + .. attribute:: activeInputs + + A dictionary containing the input of only the active keyboard keys. (read-only). + + :type: dictionary {:ref:`keycode`::class:`SCA_InputEvent`, ...} + .. attribute:: active_events A dictionary containing the status of only the active keyboard events or keys. (read-only). + .. deprecated:: use :data:`activeInputs` + :type: dictionary {:ref:`keycode`::ref:`status`, ...} + .. attribute:: text + + The typed unicode text from the last frame. + + :type: string .. method:: getClipboard() diff --git a/doc/python_api/rst/bge_types/bge.types.SCA_PythonMouse.rst b/doc/python_api/rst/bge_types/bge.types.SCA_PythonMouse.rst index 6088d785eeb9..e5249f187fe6 100644 --- a/doc/python_api/rst/bge_types/bge.types.SCA_PythonMouse.rst +++ b/doc/python_api/rst/bge_types/bge.types.SCA_PythonMouse.rst @@ -1,22 +1,55 @@ -SCA_PythonMouse(PyObjectPlus) -============================= +SCA_PythonMouse(EXP_PyObjectPlus) +================================= -base class --- :class:`PyObjectPlus` +base class --- :class:`EXP_PyObjectPlus` -.. class:: SCA_PythonMouse(PyObjectPlus) +.. class:: SCA_PythonMouse(EXP_PyObjectPlus) The current mouse. + .. warning:: + + Mouse normalization is using the maximum coordinate in width and height, whether `bge.render.getWindowWidth() - 1` or `bge.render.getWindowHeight() - 1`. + + A script setting the mouse at center is similar to the following example: + + .. code-block:: python + + import bge + + w, h = bge.render.getWindowWidth() - 1, bge.render.getWindowHeight() - 1 + center_x, center_y = (w // 2) / w, (h // 2) / h + + bge.logic.mouse.position = center_x, center_y + + Note the usage of floor division to round an existing coordinate. + + .. attribute:: inputs + + A dictionary containing the input of each mouse event. (read-only). + + :type: dictionary {:ref:`keycode`::class:`SCA_InputEvent`, ...} + .. attribute:: events a dictionary containing the status of each mouse event. (read-only). + .. deprecated:: use :data:`inputs` + :type: dictionary {:ref:`keycode`::ref:`status`, ...} + .. attribute:: activeInputs + + A dictionary containing the input of only the active mouse events. (read-only). + + :type: dictionary {:ref:`keycode`::class:`SCA_InputEvent`, ...} + .. attribute:: active_events a dictionary containing the status of only the active mouse events. (read-only). + .. deprecated:: use :data:`activeInputs` + :type: dictionary {:ref:`keycode`::ref:`status`, ...} .. attribute:: position diff --git a/doc/python_api/rst/bge_types/bge.types.SCA_VibrationActuator.rst b/doc/python_api/rst/bge_types/bge.types.SCA_VibrationActuator.rst new file mode 100644 index 000000000000..84cd82154dd5 --- /dev/null +++ b/doc/python_api/rst/bge_types/bge.types.SCA_VibrationActuator.rst @@ -0,0 +1,58 @@ +SCA_VibrationActuator(SCA_IActuator) +==================================== + +base class --- :class:`SCA_IActuator` + +.. class:: SCA_VibrationActuator(SCA_IActuator) + + Vibration Actuator. + + .. attribute:: joyindex + + Joystick index. + + :type: integer (0 to 7) + + .. attribute:: strengthLeft + + Strength of the Low frequency joystick's motor (placed at left position usually). + + :type: float (0.0 to 1.0) + + .. attribute:: strengthRight + + Strength of the High frequency joystick's motor (placed at right position usually). + + :type: float (0.0 to 1.0) + + .. attribute:: duration + + Duration of the vibration in milliseconds. + + :type: integer (0 to infinite) + + .. attribute:: isVibrating + + Check status of joystick vibration + + :type: bool (true vibrating and false stopped) + + .. attribute:: hasVibration + + Check if the joystick supports vibration + + :type: bool (true supported and false not supported) + + .. method:: startVibration() + + Starts the vibration. + + :return: None + + .. method:: stopVibration() + + Stops the vibration. + + :return: None + + diff --git a/doc/readme/GitHub_Readme1.png b/doc/readme/GitHub_Readme1.png new file mode 100644 index 000000000000..aacb5afd9cc0 Binary files /dev/null and b/doc/readme/GitHub_Readme1.png differ diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt index 2e8589ffd176..cc463cb2337a 100644 --- a/extern/CMakeLists.txt +++ b/extern/CMakeLists.txt @@ -42,7 +42,7 @@ add_subdirectory(wcwidth) if(WITH_BULLET) if(NOT WITH_SYSTEM_BULLET) - add_subdirectory(bullet2) + add_subdirectory(bullet) endif() endif() diff --git a/extern/bullet/AUTHORS.txt b/extern/bullet/AUTHORS.txt new file mode 100644 index 000000000000..1bff63207795 --- /dev/null +++ b/extern/bullet/AUTHORS.txt @@ -0,0 +1,45 @@ +Bullet Physics is created by Erwin Coumans with contributions from the following authors / copyright holders: + +AMD +Apple +Yunfei Bai +Steve Baker +Gino van den Bergen +Jeff Bingham +Nicola Candussi +Erin Catto +Lawrence Chai +Erwin Coumans +Disney Animation +Benjamin Ellenberger +Christer Ericson +Google +Dirk Gregorius +Marcus Hennix +Jasmine Hsu +MBSim Development Team +Takahiro Harada +Simon Hobbs +John Hsu +Ole Kniemeyer +Jay Lee +Francisco Leon +lunkhound +Vsevolod Klementjev +Phil Knight +John McCutchan +Steven Peters +Roman Ponomarev +Nathanael Presson +Gabor PUHR +Arthur Shek +Russel Smith +Sony +Jakub Stephien +Marten Svanfeldt +Jie Tan +Pierre Terdiman +Steven Thompson +Tamas Umenhoffer + +If your name is missing, please send an email to erwin.coumans@gmail.com or file an issue at http://github.com/bulletphysics/bullet3 diff --git a/extern/bullet2/CMakeLists.txt b/extern/bullet/CMakeLists.txt similarity index 63% rename from extern/bullet2/CMakeLists.txt rename to extern/bullet/CMakeLists.txt index 949a8b01bd2a..f18c04a369b3 100644 --- a/extern/bullet2/CMakeLists.txt +++ b/extern/bullet/CMakeLists.txt @@ -29,26 +29,74 @@ set(INC ) set(INC_SYS - + ${TBB_INCLUDE_DIR} ) set(SRC + src/Bullet3Collision/BroadPhaseCollision/b3DynamicBvhBroadphase.cpp + src/Bullet3Collision/BroadPhaseCollision/b3DynamicBvh.cpp + src/Bullet3Collision/BroadPhaseCollision/b3OverlappingPairCache.cpp + src/Bullet3Collision/NarrowPhaseCollision/b3ConvexUtility.cpp + src/Bullet3Collision/NarrowPhaseCollision/b3CpuNarrowPhase.cpp + src/Bullet3Common/b3AlignedAllocator.cpp + src/Bullet3Common/b3Logging.cpp + src/Bullet3Common/b3Vector3.cpp + src/Bullet3Dynamics/b3CpuRigidBodyPipeline.cpp + src/Bullet3Dynamics/ConstraintSolver/b3FixedConstraint.cpp + src/Bullet3Dynamics/ConstraintSolver/b3Generic6DofConstraint.cpp + src/Bullet3Dynamics/ConstraintSolver/b3PgsJacobiSolver.cpp + src/Bullet3Dynamics/ConstraintSolver/b3Point2PointConstraint.cpp + src/Bullet3Dynamics/ConstraintSolver/b3TypedConstraint.cpp + src/Bullet3Geometry/b3ConvexHullComputer.cpp + src/Bullet3Geometry/b3GeometryUtil.cpp + src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.cpp + src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.cpp + src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp + src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.cpp + src/Bullet3OpenCL/Initialize/b3OpenCLUtils.cpp + src/Bullet3OpenCL/NarrowphaseCollision/b3ContactCache.cpp + src/Bullet3OpenCL/NarrowphaseCollision/b3ConvexHullContact.cpp + src/Bullet3OpenCL/NarrowphaseCollision/b3GjkEpa.cpp + src/Bullet3OpenCL/NarrowphaseCollision/b3OptimizedBvh.cpp + src/Bullet3OpenCL/NarrowphaseCollision/b3QuantizedBvh.cpp + src/Bullet3OpenCL/NarrowphaseCollision/b3StridingMeshInterface.cpp + src/Bullet3OpenCL/NarrowphaseCollision/b3TriangleCallback.cpp + src/Bullet3OpenCL/NarrowphaseCollision/b3TriangleIndexVertexArray.cpp + src/Bullet3OpenCL/NarrowphaseCollision/b3VoronoiSimplexSolver.cpp + src/Bullet3OpenCL/ParallelPrimitives/b3BoundSearchCL.cpp + src/Bullet3OpenCL/ParallelPrimitives/b3FillCL.cpp + src/Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.cpp + src/Bullet3OpenCL/ParallelPrimitives/b3PrefixScanCL.cpp + src/Bullet3OpenCL/ParallelPrimitives/b3PrefixScanFloat4CL.cpp + src/Bullet3OpenCL/ParallelPrimitives/b3RadixSort32CL.cpp + src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp + src/Bullet3OpenCL/RigidBody/b3GpuGenericConstraint.cpp + src/Bullet3OpenCL/RigidBody/b3GpuJacobiContactSolver.cpp + src/Bullet3OpenCL/RigidBody/b3GpuNarrowPhase.cpp + src/Bullet3OpenCL/RigidBody/b3GpuPgsConstraintSolver.cpp + src/Bullet3OpenCL/RigidBody/b3GpuPgsContactSolver.cpp + src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.cpp + src/Bullet3OpenCL/RigidBody/b3Solver.cpp + src/Bullet3Serialize/Bullet2FileLoader/b3BulletFile.cpp + src/Bullet3Serialize/Bullet2FileLoader/b3Chunk.cpp + src/Bullet3Serialize/Bullet2FileLoader/b3DNA.cpp + src/Bullet3Serialize/Bullet2FileLoader/b3File.cpp + src/Bullet3Serialize/Bullet2FileLoader/b3Serializer.cpp src/BulletCollision/BroadphaseCollision/btAxisSweep3.cpp src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp src/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.cpp - src/BulletCollision/BroadphaseCollision/btDbvt.cpp src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp + src/BulletCollision/BroadphaseCollision/btDbvt.cpp src/BulletCollision/BroadphaseCollision/btDispatcher.cpp - src/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.cpp src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp src/BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp - src/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp src/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.cpp src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp src/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.cpp src/BulletCollision/CollisionDispatch/btBoxBoxDetector.cpp src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp + src/BulletCollision/CollisionDispatch/btCollisionDispatcherMt.cpp src/BulletCollision/CollisionDispatch/btCollisionObject.cpp src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp @@ -69,6 +117,7 @@ set(SRC src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp src/BulletCollision/CollisionDispatch/btUnionFind.cpp + src/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp src/BulletCollision/CollisionShapes/btBox2dShape.cpp src/BulletCollision/CollisionShapes/btBoxShape.cpp src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp @@ -88,8 +137,8 @@ set(SRC src/BulletCollision/CollisionShapes/btEmptyShape.cpp src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp src/BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp - src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp src/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.cpp + src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp src/BulletCollision/CollisionShapes/btOptimizedBvh.cpp src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp src/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.cpp @@ -106,11 +155,11 @@ set(SRC src/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp src/BulletCollision/CollisionShapes/btUniformScalingShape.cpp src/BulletCollision/Gimpact/btContactProcessing.cpp + src/BulletCollision/Gimpact/btGenericPoolAllocator.cpp src/BulletCollision/Gimpact/btGImpactBvh.cpp src/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.cpp src/BulletCollision/Gimpact/btGImpactQuantizedBvh.cpp src/BulletCollision/Gimpact/btGImpactShape.cpp - src/BulletCollision/Gimpact/btGenericPoolAllocator.cpp src/BulletCollision/Gimpact/btTriangleShapeEx.cpp src/BulletCollision/Gimpact/gim_box_set.cpp src/BulletCollision/Gimpact/gim_contact.cpp @@ -128,7 +177,6 @@ set(SRC src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp - src/BulletDynamics/Character/btKinematicCharacterController.cpp src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp @@ -146,54 +194,213 @@ set(SRC src/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.cpp src/BulletDynamics/ConstraintSolver/btTypedConstraint.cpp src/BulletDynamics/ConstraintSolver/btUniversalConstraint.cpp - src/BulletDynamics/Dynamics/Bullet-C-API.cpp src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp + src/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.cpp src/BulletDynamics/Dynamics/btRigidBody.cpp src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp - src/BulletDynamics/Featherstone/btMultiBody.cpp + src/BulletDynamics/Dynamics/btSimulationIslandManagerMt.cpp + src/BulletDynamics/Dynamics/Bullet-C-API.cpp src/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp + src/BulletDynamics/Featherstone/btMultiBody.cpp src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp + src/BulletDynamics/Featherstone/btMultiBodyFixedConstraint.cpp + src/BulletDynamics/Featherstone/btMultiBodyGearConstraint.cpp src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp src/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp + src/BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp src/BulletDynamics/MLCPSolvers/btDantzigLCP.cpp src/BulletDynamics/MLCPSolvers/btLemkeAlgorithm.cpp src/BulletDynamics/MLCPSolvers/btMLCPSolver.cpp src/BulletDynamics/Vehicle/btRaycastVehicle.cpp src/BulletDynamics/Vehicle/btWheelInfo.cpp - + src/BulletInverseDynamics/details/MultiBodyTreeImpl.cpp + src/BulletInverseDynamics/details/MultiBodyTreeInitCache.cpp + src/BulletInverseDynamics/IDMath.cpp + src/BulletInverseDynamics/MultiBodyTree.cpp src/BulletSoftBody/btDefaultSoftBodySolver.cpp - src/BulletSoftBody/btSoftBody.cpp src/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.cpp + src/BulletSoftBody/btSoftBody.cpp src/BulletSoftBody/btSoftBodyHelpers.cpp src/BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.cpp + src/BulletSoftBody/btSoftMultiBodyDynamicsWorld.cpp src/BulletSoftBody/btSoftRigidCollisionAlgorithm.cpp src/BulletSoftBody/btSoftRigidDynamicsWorld.cpp + src/BulletSoftBody/btSoftRigidDynamicsWorldMt.cpp src/BulletSoftBody/btSoftSoftCollisionAlgorithm.cpp - src/LinearMath/btAlignedAllocator.cpp - src/LinearMath/btConvexHull.cpp src/LinearMath/btConvexHullComputer.cpp + src/LinearMath/btConvexHull.cpp src/LinearMath/btGeometryUtil.cpp src/LinearMath/btPolarDecomposition.cpp src/LinearMath/btQuickprof.cpp + src/LinearMath/btSerializer64.cpp src/LinearMath/btSerializer.cpp + src/LinearMath/btThreads.cpp src/LinearMath/btVector3.cpp + src/btBulletCollisionCommon.h + src/btBulletDynamicsCommon.h + src/Bullet3Collision/BroadPhaseCollision/b3BroadphaseCallback.h + src/Bullet3Collision/BroadPhaseCollision/b3DynamicBvhBroadphase.h + src/Bullet3Collision/BroadPhaseCollision/b3DynamicBvh.h + src/Bullet3Collision/BroadPhaseCollision/b3OverlappingPairCache.h + src/Bullet3Collision/BroadPhaseCollision/b3OverlappingPair.h + src/Bullet3Collision/BroadPhaseCollision/shared/b3Aabb.h + src/Bullet3Collision/NarrowPhaseCollision/b3Config.h + src/Bullet3Collision/NarrowPhaseCollision/b3Contact4.h + src/Bullet3Collision/NarrowPhaseCollision/b3ConvexUtility.h + src/Bullet3Collision/NarrowPhaseCollision/b3CpuNarrowPhase.h + src/Bullet3Collision/NarrowPhaseCollision/b3RaycastInfo.h + src/Bullet3Collision/NarrowPhaseCollision/b3RigidBodyCL.h + src/Bullet3Collision/NarrowPhaseCollision/shared/b3BvhSubtreeInfoData.h + src/Bullet3Collision/NarrowPhaseCollision/shared/b3BvhTraversal.h + src/Bullet3Collision/NarrowPhaseCollision/shared/b3ClipFaces.h + src/Bullet3Collision/NarrowPhaseCollision/shared/b3Collidable.h + src/Bullet3Collision/NarrowPhaseCollision/shared/b3Contact4Data.h + src/Bullet3Collision/NarrowPhaseCollision/shared/b3ContactConvexConvexSAT.h + src/Bullet3Collision/NarrowPhaseCollision/shared/b3ContactSphereSphere.h + src/Bullet3Collision/NarrowPhaseCollision/shared/b3ConvexPolyhedronData.h + src/Bullet3Collision/NarrowPhaseCollision/shared/b3FindConcaveSatAxis.h + src/Bullet3Collision/NarrowPhaseCollision/shared/b3FindSeparatingAxis.h + src/Bullet3Collision/NarrowPhaseCollision/shared/b3MprPenetration.h + src/Bullet3Collision/NarrowPhaseCollision/shared/b3NewContactReduction.h + src/Bullet3Collision/NarrowPhaseCollision/shared/b3QuantizedBvhNodeData.h + src/Bullet3Collision/NarrowPhaseCollision/shared/b3ReduceContacts.h + src/Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h + src/Bullet3Collision/NarrowPhaseCollision/shared/b3UpdateAabbs.h + src/Bullet3Common/b3AlignedAllocator.h + src/Bullet3Common/b3AlignedObjectArray.h + src/Bullet3Common/b3CommandLineArgs.h + src/Bullet3Common/b3FileUtils.h + src/Bullet3Common/b3HashMap.h + src/Bullet3Common/b3Logging.h + src/Bullet3Common/b3Matrix3x3.h + src/Bullet3Common/b3MinMax.h + src/Bullet3Common/b3PoolAllocator.h + src/Bullet3Common/b3QuadWord.h + src/Bullet3Common/b3Quaternion.h + src/Bullet3Common/b3Random.h + src/Bullet3Common/b3ResizablePool.h + src/Bullet3Common/b3Scalar.h + src/Bullet3Common/b3StackAlloc.h + src/Bullet3Common/b3Transform.h + src/Bullet3Common/b3TransformUtil.h + src/Bullet3Common/b3Vector3.h + src/Bullet3Common/shared/b3Float4.h + src/Bullet3Common/shared/b3Int2.h + src/Bullet3Common/shared/b3Int4.h + src/Bullet3Common/shared/b3Mat3x3.h + src/Bullet3Common/shared/b3PlatformDefinitions.h + src/Bullet3Common/shared/b3Quat.h + src/Bullet3Dynamics/b3CpuRigidBodyPipeline.h + src/Bullet3Dynamics/ConstraintSolver/b3ContactSolverInfo.h + src/Bullet3Dynamics/ConstraintSolver/b3FixedConstraint.h + src/Bullet3Dynamics/ConstraintSolver/b3Generic6DofConstraint.h + src/Bullet3Dynamics/ConstraintSolver/b3JacobianEntry.h + src/Bullet3Dynamics/ConstraintSolver/b3PgsJacobiSolver.h + src/Bullet3Dynamics/ConstraintSolver/b3Point2PointConstraint.h + src/Bullet3Dynamics/ConstraintSolver/b3SolverBody.h + src/Bullet3Dynamics/ConstraintSolver/b3SolverConstraint.h + src/Bullet3Dynamics/ConstraintSolver/b3TypedConstraint.h + src/Bullet3Dynamics/shared/b3ContactConstraint4.h + src/Bullet3Dynamics/shared/b3ConvertConstraint4.h + src/Bullet3Dynamics/shared/b3Inertia.h + src/Bullet3Dynamics/shared/b3IntegrateTransforms.h + src/Bullet3Geometry/b3AabbUtil.h + src/Bullet3Geometry/b3ConvexHullComputer.h + src/Bullet3Geometry/b3GeometryUtil.h + src/Bullet3Geometry/b3GrahamScan2dConvexHull.h + src/Bullet3OpenCL/BroadphaseCollision/b3GpuBroadphaseInterface.h + src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.h + src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h + src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h + src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.h + src/Bullet3OpenCL/BroadphaseCollision/b3SapAabb.h + src/Bullet3OpenCL/BroadphaseCollision/kernels/gridBroadphaseKernels.h + src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h + src/Bullet3OpenCL/BroadphaseCollision/kernels/sapKernels.h + src/Bullet3OpenCL/Initialize/b3OpenCLInclude.h + src/Bullet3OpenCL/Initialize/b3OpenCLUtils.h + src/Bullet3OpenCL/NarrowphaseCollision/b3BvhInfo.h + src/Bullet3OpenCL/NarrowphaseCollision/b3ContactCache.h + src/Bullet3OpenCL/NarrowphaseCollision/b3ConvexHullContact.h + src/Bullet3OpenCL/NarrowphaseCollision/b3ConvexPolyhedronCL.h + src/Bullet3OpenCL/NarrowphaseCollision/b3GjkEpa.h + src/Bullet3OpenCL/NarrowphaseCollision/b3OptimizedBvh.h + src/Bullet3OpenCL/NarrowphaseCollision/b3QuantizedBvh.h + src/Bullet3OpenCL/NarrowphaseCollision/b3StridingMeshInterface.h + src/Bullet3OpenCL/NarrowphaseCollision/b3SupportMappings.h + src/Bullet3OpenCL/NarrowphaseCollision/b3TriangleCallback.h + src/Bullet3OpenCL/NarrowphaseCollision/b3TriangleIndexVertexArray.h + src/Bullet3OpenCL/NarrowphaseCollision/b3VectorFloat4.h + src/Bullet3OpenCL/NarrowphaseCollision/b3VoronoiSimplexSolver.h + src/Bullet3OpenCL/NarrowphaseCollision/kernels/bvhTraversal.h + src/Bullet3OpenCL/NarrowphaseCollision/kernels/mprKernels.h + src/Bullet3OpenCL/NarrowphaseCollision/kernels/primitiveContacts.h + src/Bullet3OpenCL/NarrowphaseCollision/kernels/satClipHullContacts.h + src/Bullet3OpenCL/NarrowphaseCollision/kernels/satConcaveKernels.h + src/Bullet3OpenCL/NarrowphaseCollision/kernels/satKernels.h + src/Bullet3OpenCL/ParallelPrimitives/b3BoundSearchCL.h + src/Bullet3OpenCL/ParallelPrimitives/b3BufferInfoCL.h + src/Bullet3OpenCL/ParallelPrimitives/b3FillCL.h + src/Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.h + src/Bullet3OpenCL/ParallelPrimitives/b3OpenCLArray.h + src/Bullet3OpenCL/ParallelPrimitives/b3PrefixScanCL.h + src/Bullet3OpenCL/ParallelPrimitives/b3PrefixScanFloat4CL.h + src/Bullet3OpenCL/ParallelPrimitives/b3RadixSort32CL.h + src/Bullet3OpenCL/ParallelPrimitives/kernels/BoundSearchKernelsCL.h + src/Bullet3OpenCL/ParallelPrimitives/kernels/CopyKernelsCL.h + src/Bullet3OpenCL/ParallelPrimitives/kernels/FillKernelsCL.h + src/Bullet3OpenCL/ParallelPrimitives/kernels/PrefixScanKernelsCL.h + src/Bullet3OpenCL/ParallelPrimitives/kernels/PrefixScanKernelsFloat4CL.h + src/Bullet3OpenCL/ParallelPrimitives/kernels/RadixSort32KernelsCL.h + src/Bullet3OpenCL/Raycast/b3GpuRaycast.h + src/Bullet3OpenCL/Raycast/kernels/rayCastKernels.h + src/Bullet3OpenCL/RigidBody/b3GpuConstraint4.h + src/Bullet3OpenCL/RigidBody/b3GpuGenericConstraint.h + src/Bullet3OpenCL/RigidBody/b3GpuJacobiContactSolver.h + src/Bullet3OpenCL/RigidBody/b3GpuNarrowPhase.h + src/Bullet3OpenCL/RigidBody/b3GpuNarrowPhaseInternalData.h + src/Bullet3OpenCL/RigidBody/b3GpuPgsConstraintSolver.h + src/Bullet3OpenCL/RigidBody/b3GpuPgsContactSolver.h + src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.h + src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipelineInternalData.h + src/Bullet3OpenCL/RigidBody/b3GpuSolverBody.h + src/Bullet3OpenCL/RigidBody/b3GpuSolverConstraint.h + src/Bullet3OpenCL/RigidBody/b3Solver.h + src/Bullet3OpenCL/RigidBody/kernels/batchingKernels.h + src/Bullet3OpenCL/RigidBody/kernels/batchingKernelsNew.h + src/Bullet3OpenCL/RigidBody/kernels/integrateKernel.h + src/Bullet3OpenCL/RigidBody/kernels/jointSolver.h + src/Bullet3OpenCL/RigidBody/kernels/solveContact.h + src/Bullet3OpenCL/RigidBody/kernels/solveFriction.h + src/Bullet3OpenCL/RigidBody/kernels/solverSetup2.h + src/Bullet3OpenCL/RigidBody/kernels/solverSetup.h + src/Bullet3OpenCL/RigidBody/kernels/solverUtils.h + src/Bullet3OpenCL/RigidBody/kernels/updateAabbsKernel.h + src/Bullet3Serialize/Bullet2FileLoader/autogenerated/bullet2.h + src/Bullet3Serialize/Bullet2FileLoader/b3BulletFile.h + src/Bullet3Serialize/Bullet2FileLoader/b3Chunk.h + src/Bullet3Serialize/Bullet2FileLoader/b3Common.h + src/Bullet3Serialize/Bullet2FileLoader/b3Defines.h + src/Bullet3Serialize/Bullet2FileLoader/b3DNA.h + src/Bullet3Serialize/Bullet2FileLoader/b3File.h + src/Bullet3Serialize/Bullet2FileLoader/b3Serializer.h + src/Bullet-C-Api.h src/BulletCollision/BroadphaseCollision/btAxisSweep3.h + src/BulletCollision/BroadphaseCollision/btAxisSweep3Internal.h src/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h src/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h - src/BulletCollision/BroadphaseCollision/btDbvt.h src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h + src/BulletCollision/BroadphaseCollision/btDbvt.h src/BulletCollision/BroadphaseCollision/btDispatcher.h - src/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.h src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h src/BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h src/BulletCollision/BroadphaseCollision/btQuantizedBvh.h src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.h - src/BulletCollision/CollisionDispatch/SphereTriangleDetector.h src/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.h src/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.h @@ -201,6 +408,7 @@ set(SRC src/BulletCollision/CollisionDispatch/btCollisionConfiguration.h src/BulletCollision/CollisionDispatch/btCollisionCreateFunc.h src/BulletCollision/CollisionDispatch/btCollisionDispatcher.h + src/BulletCollision/CollisionDispatch/btCollisionDispatcherMt.h src/BulletCollision/CollisionDispatch/btCollisionObject.h src/BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h src/BulletCollision/CollisionDispatch/btCollisionWorld.h @@ -222,6 +430,7 @@ set(SRC src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.h src/BulletCollision/CollisionDispatch/btUnionFind.h + src/BulletCollision/CollisionDispatch/SphereTriangleDetector.h src/BulletCollision/CollisionShapes/btBox2dShape.h src/BulletCollision/CollisionShapes/btBoxShape.h src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h @@ -243,8 +452,8 @@ set(SRC src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h src/BulletCollision/CollisionShapes/btMaterial.h src/BulletCollision/CollisionShapes/btMinkowskiSumShape.h - src/BulletCollision/CollisionShapes/btMultiSphereShape.h src/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h + src/BulletCollision/CollisionShapes/btMultiSphereShape.h src/BulletCollision/CollisionShapes/btOptimizedBvh.h src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h src/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h @@ -266,13 +475,16 @@ set(SRC src/BulletCollision/Gimpact/btClipPolygon.h src/BulletCollision/Gimpact/btCompoundFromGimpact.h src/BulletCollision/Gimpact/btContactProcessing.h + src/BulletCollision/Gimpact/btContactProcessingStructs.h + src/BulletCollision/Gimpact/btGenericPoolAllocator.h + src/BulletCollision/Gimpact/btGeometryOperations.h src/BulletCollision/Gimpact/btGImpactBvh.h + src/BulletCollision/Gimpact/btGImpactBvhStructs.h src/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h src/BulletCollision/Gimpact/btGImpactMassUtil.h src/BulletCollision/Gimpact/btGImpactQuantizedBvh.h + src/BulletCollision/Gimpact/btGImpactQuantizedBvhStructs.h src/BulletCollision/Gimpact/btGImpactShape.h - src/BulletCollision/Gimpact/btGenericPoolAllocator.h - src/BulletCollision/Gimpact/btGeometryOperations.h src/BulletCollision/Gimpact/btQuantization.h src/BulletCollision/Gimpact/btTriangleShapeEx.h src/BulletCollision/Gimpact/gim_array.h @@ -282,8 +494,8 @@ set(SRC src/BulletCollision/Gimpact/gim_box_set.h src/BulletCollision/Gimpact/gim_clip_polygon.h src/BulletCollision/Gimpact/gim_contact.h - src/BulletCollision/Gimpact/gim_geom_types.h src/BulletCollision/Gimpact/gim_geometry.h + src/BulletCollision/Gimpact/gim_geom_types.h src/BulletCollision/Gimpact/gim_hash_table.h src/BulletCollision/Gimpact/gim_linear_math.h src/BulletCollision/Gimpact/gim_math.h @@ -311,7 +523,6 @@ set(SRC src/BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h - src/BulletDynamics/Character/btCharacterControllerInterface.h src/BulletDynamics/Character/btKinematicCharacterController.h src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h @@ -337,19 +548,24 @@ set(SRC src/BulletDynamics/ConstraintSolver/btUniversalConstraint.h src/BulletDynamics/Dynamics/btActionInterface.h src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h + src/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h src/BulletDynamics/Dynamics/btDynamicsWorld.h src/BulletDynamics/Dynamics/btRigidBody.h src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.h - src/BulletDynamics/Featherstone/btMultiBody.h + src/BulletDynamics/Dynamics/btSimulationIslandManagerMt.h src/BulletDynamics/Featherstone/btMultiBodyConstraint.h src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h + src/BulletDynamics/Featherstone/btMultiBodyFixedConstraint.h + src/BulletDynamics/Featherstone/btMultiBodyGearConstraint.h + src/BulletDynamics/Featherstone/btMultiBody.h src/BulletDynamics/Featherstone/btMultiBodyJointFeedback.h src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.h src/BulletDynamics/Featherstone/btMultiBodyJointMotor.h - src/BulletDynamics/Featherstone/btMultiBodyLink.h src/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h + src/BulletDynamics/Featherstone/btMultiBodyLink.h src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.h + src/BulletDynamics/Featherstone/btMultiBodySliderConstraint.h src/BulletDynamics/Featherstone/btMultiBodySolverConstraint.h src/BulletDynamics/MLCPSolvers/btDantzigLCP.h src/BulletDynamics/MLCPSolvers/btDantzigSolver.h @@ -362,26 +578,27 @@ set(SRC src/BulletDynamics/Vehicle/btRaycastVehicle.h src/BulletDynamics/Vehicle/btVehicleRaycaster.h src/BulletDynamics/Vehicle/btWheelInfo.h - src/BulletSoftBody/btDefaultSoftBodySolver.h - src/BulletSoftBody/btSoftBody.h src/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.h src/BulletSoftBody/btSoftBodyData.h + src/BulletSoftBody/btSoftBody.h src/BulletSoftBody/btSoftBodyHelpers.h src/BulletSoftBody/btSoftBodyInternals.h src/BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h - src/BulletSoftBody/btSoftBodySolverVertexBuffer.h src/BulletSoftBody/btSoftBodySolvers.h + src/BulletSoftBody/btSoftBodySolverVertexBuffer.h + src/BulletSoftBody/btSoftMultiBodyDynamicsWorld.h src/BulletSoftBody/btSoftRigidCollisionAlgorithm.h src/BulletSoftBody/btSoftRigidDynamicsWorld.h + src/BulletSoftBody/btSoftRigidDynamicsWorldMt.h src/BulletSoftBody/btSoftSoftCollisionAlgorithm.h src/BulletSoftBody/btSparseSDF.h - + src/clew/clew.h src/LinearMath/btAabbUtil2.h src/LinearMath/btAlignedAllocator.h src/LinearMath/btAlignedObjectArray.h - src/LinearMath/btConvexHull.h src/LinearMath/btConvexHullComputer.h + src/LinearMath/btConvexHull.h src/LinearMath/btCpuFeatureUtility.h src/LinearMath/btDefaultMotionState.h src/LinearMath/btGeometryUtil.h @@ -403,13 +620,16 @@ set(SRC src/LinearMath/btSerializer.h src/LinearMath/btSpatialAlgebra.h src/LinearMath/btStackAlloc.h + src/LinearMath/btThreads.h src/LinearMath/btTransform.h src/LinearMath/btTransformUtil.h src/LinearMath/btVector3.h +) - src/btBulletCollisionCommon.h - src/btBulletDynamicsCommon.h - src/Bullet-C-Api.h +add_definitions( + -DBT_THREADSAFE + -DBT_USE_TBB + -DB3_USE_CLEW ) if(CMAKE_COMPILER_IS_GNUCXX) diff --git a/extern/bullet/LICENSE.txt b/extern/bullet/LICENSE.txt new file mode 100644 index 000000000000..319c84e349f6 --- /dev/null +++ b/extern/bullet/LICENSE.txt @@ -0,0 +1,15 @@ + +The files in this repository are licensed under the zlib license, except for the files under 'Extras' and examples/ThirdPartyLibs. + +Bullet Continuous Collision Detection and Physics Library +http://bulletphysics.org + +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. diff --git a/extern/bullet/README.md b/extern/bullet/README.md new file mode 100644 index 000000000000..3bbc2e2c7b89 --- /dev/null +++ b/extern/bullet/README.md @@ -0,0 +1,119 @@ + +[![Travis Build Status](https://api.travis-ci.org/bulletphysics/bullet3.png?branch=master)](https://travis-ci.org/bulletphysics/bullet3) +[![Appveyor Build status](https://ci.appveyor.com/api/projects/status/6sly9uxajr6xsstq)](https://ci.appveyor.com/project/erwincoumans/bullet3) + +# Bullet Physics SDK + +This is the official C++ source code repository of the Bullet Physics SDK: real-time collision detection and multi-physics simulation for VR, games, visual effects, robotics, machine learning etc. + +New in Bullet 2.85: pybullet Python bindings, improved support for robotics and VR. Use pip install pybullet and see [PyBullet Quickstart Guide](https://docs.google.com/document/d/10sXEhzFRSnvFcl3XxNGhnD4N2SedqwdAvK3dsihxVUA/edit#heading=h.2ye70wns7io3). + +The Bullet 2 API will stay default and up-to-date while slowly moving to a new API. +The steps towards a new API is in a nutshell: + +1. The old Bullet2 demos are being merged into the examples/ExampleBrowser +2. A new physics-engine agnostic C-API is created, see examples/SharedMemory/PhysicsClientC_API.h +3. Python bindings in pybullet are on top of this C-API, see examples/pybullet +4. A Virtual Reality sandbox using openvr for HTC Vive and Oculus Rift is available +5. The OpenCL examples in the ExampleBrowser can be enabled using --enable_experimental_opencl + +You can still use svn or svn externals using the github git repository: use svn co https://github.com/bulletphysics/bullet3/trunk + +## Requirements for Bullet 2 + +A C++ compiler for C++ 2003. The library is tested on Windows, Linux, Mac OSX, iOS, Android, +but should likely work on any platform with C++ compiler. +Some optional demos require OpenGL 2 or OpenGL 3, there are some non-graphical demos and unit tests too. + +## Contributors and Coding Style information + +https://docs.google.com/document/d/1u9vyzPtrVoVhYqQOGNWUgjRbfwfCdIts_NzmvgiJ144/edit + +## Requirements for experimental OpenCL GPGPU support + +The entire collision detection and rigid body dynamics can be executed on the GPU. + +A high-end desktop GPU, such as an AMD Radeon 7970 or NVIDIA GTX 680 or better. +We succesfully tested the software under Windows, Linux and Mac OSX. +The software currently doesn't work on OpenCL CPU devices. It might run +on a laptop GPU but performance will not likely be very good. Note that +often an OpenCL drivers fails to compile a kernel. Some unit tests exist to +track down the issue, but more work is required to cover all OpenCL kernels. + +## License + +All source code files are licensed under the permissive zlib license +(http://opensource.org/licenses/Zlib) unless marked differently in a particular folder/file. + +## Build instructions for Bullet using premake. You can also use cmake instead. + +**Windows** + +Click on build_visual_studio_vr_pybullet_double.bat and open build3/vs2010/0MySolution.sln +When asked, convert the projects to a newer version of Visual Studio. +If you installed Python in the C:\ root directory, the batch file should find it automatically. +Otherwise, edit this batch file to choose where Python include/lib directories are located. + +**Windows Virtual Reality sandbox for HTC Vive and Oculus Rift** + +Build and run the App_SharedMemoryPhysics_VR project, preferably in Release/optimized build. +You can connect from Python pybullet to the sandbox using: + +``` +import pybullet as p +p.connect(p.SHARED_MEMORY) #or (p.TCP, "localhost", 6667) or (p.UDP, "192.168.86.10",1234) +``` + +**Linux and Mac OSX gnu make** + +Make sure cmake is installed (sudo apt-get install cmake, brew install cmake, or https://cmake.org) + +In a terminal type: + + ./build_cmake_pybullet_double.sh + +This script will invoke cmake and build in the build_cmake directory. You can find pybullet in Bullet/examples/pybullet. +The BulletExampleBrowser binary will be in Bullet/examples/ExampleBrowser. + +You can also build Bullet using premake. There are premake executables in the build3 folder. +Depending on your system (Linux 32bit, 64bit or Mac OSX) use one of the following lines +Using premake: +``` + cd build3 + ./premake4_linux --double gmake + ./premake4_linux64 --double gmake + ./premake4_osx --double --enable_pybullet gmake +``` +Then +``` + cd gmake + make +``` + +Note that on Linux, you need to use cmake to build pybullet, since the compiler has issues of mixing shared and static libraries. + +**Mac OSX Xcode** + +Click on build3/xcode4.command or in a terminal window execute + + ./premake_osx xcode4 + +## Usage + +The App_ExampleBrowser executables will be located in the bin folder. +You can just run it though a terminal/command prompt, or by clicking it. + + +``` +[--start_demo_name="Demo Name"] Start with a selected demo +[--mp4=moviename.mp4] Create a mp4 movie of the window, requires ffmpeg installed +[--mouse_move_multiplier=0.400000] Set the mouse move sensitivity +[--mouse_wheel_multiplier=0.01] Set the mouse wheel sensitivity +[--background_color_red= 0.9] Set the red component for background color. Same for green and blue +[--fixed_timestep= 0.0] Use either a real-time delta time (0.0) or a fixed step size (0.016666) +``` + +You can use mouse picking to grab objects. When holding the ALT or CONTROL key, you have Maya style camera mouse controls. +Press F1 to create a series of screenshots. Hit ESCAPE to exit the demo app. + +Check out the docs folder and the Bullet physics forums for further information. diff --git a/extern/bullet/VERSION b/extern/bullet/VERSION new file mode 100644 index 000000000000..663ae72bcc57 --- /dev/null +++ b/extern/bullet/VERSION @@ -0,0 +1 @@ +2.88 diff --git a/extern/bullet/patches/blender.patch b/extern/bullet/patches/blender.patch new file mode 100644 index 000000000000..346b870320f7 --- /dev/null +++ b/extern/bullet/patches/blender.patch @@ -0,0 +1,957 @@ +From 82c5544df857605aef7fb1b8b85da5b9f41044ef Mon Sep 17 00:00:00 2001 +From: tristan +Date: Fri, 12 Oct 2018 13:16:12 +0200 +Subject: [PATCH] temp + +temp +--- + extern/bullet/src/Bullet-C-Api.h | 187 +++++++ + .../CollisionDispatch/btCollisionWorld.h | 2 +- + .../CollisionShapes/btConvexHullShape.cpp | 6 +- + .../CollisionShapes/btConvexShape.cpp | 6 +- + .../CollisionShapes/btMultiSphereShape.cpp | 6 +- + .../btPolyhedralConvexShape.cpp | 6 +- + .../ConstraintSolver/btSolverBody.h | 7 +- + .../BulletDynamics/Dynamics/Bullet-C-API.cpp | 469 ++++++++++++++++++ + .../BulletDynamics/Dynamics/btRigidBody.cpp | 54 +- + .../src/BulletDynamics/Dynamics/btRigidBody.h | 2 + + .../src/LinearMath/btConvexHullComputer.cpp | 2 + + .../src/LinearMath/btConvexHullComputer.h | 1 + + extern/bullet/src/LinearMath/btScalar.h | 5 +- + extern/bullet/src/LinearMath/btVector3.cpp | 6 +- + 14 files changed, 708 insertions(+), 51 deletions(-) + create mode 100644 extern/bullet/src/Bullet-C-Api.h + create mode 100644 extern/bullet/src/BulletDynamics/Dynamics/Bullet-C-API.cpp + +diff --git a/extern/bullet/src/Bullet-C-Api.h b/extern/bullet/src/Bullet-C-Api.h +new file mode 100644 +index 00000000000..5d00f7e3ac3 +--- /dev/null ++++ b/extern/bullet/src/Bullet-C-Api.h +@@ -0,0 +1,187 @@ ++/* ++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. ++*/ ++ ++/* ++ Draft high-level generic physics C-API. For low-level access, use the physics SDK native API's. ++ Work in progress, functionality will be added on demand. ++ ++ If possible, use the richer Bullet C++ API, by including "btBulletDynamicsCommon.h" ++*/ ++ ++#ifndef BULLET_C_API_H ++#define BULLET_C_API_H ++ ++#define PL_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name ++ ++#ifdef BT_USE_DOUBLE_PRECISION ++typedef double plReal; ++#else ++typedef float plReal; ++#endif ++ ++typedef plReal plVector3[3]; ++typedef plReal plQuaternion[4]; ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/** Particular physics SDK (C-API) */ ++ PL_DECLARE_HANDLE(plPhysicsSdkHandle); ++ ++/** Dynamics world, belonging to some physics SDK (C-API)*/ ++ PL_DECLARE_HANDLE(plDynamicsWorldHandle); ++ ++/** Rigid Body that can be part of a Dynamics World (C-API)*/ ++ PL_DECLARE_HANDLE(plRigidBodyHandle); ++ ++/** Collision Shape/Geometry, property of a Rigid Body (C-API)*/ ++ PL_DECLARE_HANDLE(plCollisionShapeHandle); ++ ++/** Constraint for Rigid Bodies (C-API)*/ ++ PL_DECLARE_HANDLE(plConstraintHandle); ++ ++/** Triangle Mesh interface (C-API)*/ ++ PL_DECLARE_HANDLE(plMeshInterfaceHandle); ++ ++/** Broadphase Scene/Proxy Handles (C-API)*/ ++ PL_DECLARE_HANDLE(plCollisionBroadphaseHandle); ++ PL_DECLARE_HANDLE(plBroadphaseProxyHandle); ++ PL_DECLARE_HANDLE(plCollisionWorldHandle); ++ ++/** ++ Create and Delete a Physics SDK ++*/ ++ ++ extern plPhysicsSdkHandle plNewBulletSdk(void); //this could be also another sdk, like ODE, PhysX etc. ++ extern void plDeletePhysicsSdk(plPhysicsSdkHandle physicsSdk); ++ ++/** Collision World, not strictly necessary, you can also just create a Dynamics World with Rigid Bodies which internally manages the Collision World with Collision Objects */ ++ ++ typedef void(*btBroadphaseCallback)(void* clientData, void* object1,void* object2); ++ ++ extern plCollisionBroadphaseHandle plCreateSapBroadphase(btBroadphaseCallback beginCallback,btBroadphaseCallback endCallback); ++ ++ extern void plDestroyBroadphase(plCollisionBroadphaseHandle bp); ++ ++ extern plBroadphaseProxyHandle plCreateProxy(plCollisionBroadphaseHandle bp, void* clientData, plReal minX,plReal minY,plReal minZ, plReal maxX,plReal maxY, plReal maxZ); ++ ++ extern void plDestroyProxy(plCollisionBroadphaseHandle bp, plBroadphaseProxyHandle proxyHandle); ++ ++ extern void plSetBoundingBox(plBroadphaseProxyHandle proxyHandle, plReal minX,plReal minY,plReal minZ, plReal maxX,plReal maxY, plReal maxZ); ++ ++/* todo: add pair cache support with queries like add/remove/find pair */ ++ ++ extern plCollisionWorldHandle plCreateCollisionWorld(plPhysicsSdkHandle physicsSdk); ++ ++/* todo: add/remove objects */ ++ ++ ++/* Dynamics World */ ++ ++ extern plDynamicsWorldHandle plCreateDynamicsWorld(plPhysicsSdkHandle physicsSdk); ++ ++ extern void plDeleteDynamicsWorld(plDynamicsWorldHandle world); ++ ++ extern void plStepSimulation(plDynamicsWorldHandle, plReal timeStep); ++ ++ extern void plAddRigidBody(plDynamicsWorldHandle world, plRigidBodyHandle object); ++ ++ extern void plRemoveRigidBody(plDynamicsWorldHandle world, plRigidBodyHandle object); ++ ++ ++/* Rigid Body */ ++ ++ extern plRigidBodyHandle plCreateRigidBody( void* user_data, float mass, plCollisionShapeHandle cshape ); ++ ++ extern void plDeleteRigidBody(plRigidBodyHandle body); ++ ++ ++/* Collision Shape definition */ ++ ++ extern plCollisionShapeHandle plNewSphereShape(plReal radius); ++ extern plCollisionShapeHandle plNewBoxShape(plReal x, plReal y, plReal z); ++ extern plCollisionShapeHandle plNewCapsuleShape(plReal radius, plReal height); ++ extern plCollisionShapeHandle plNewConeShape(plReal radius, plReal height); ++ extern plCollisionShapeHandle plNewCylinderShape(plReal radius, plReal height); ++ extern plCollisionShapeHandle plNewCompoundShape(void); ++ extern void plAddChildShape(plCollisionShapeHandle compoundShape,plCollisionShapeHandle childShape, plVector3 childPos,plQuaternion childOrn); ++ ++ extern void plDeleteShape(plCollisionShapeHandle shape); ++ ++ /* Convex Meshes */ ++ extern plCollisionShapeHandle plNewConvexHullShape(void); ++ extern void plAddVertex(plCollisionShapeHandle convexHull, plReal x,plReal y,plReal z); ++/* Concave static triangle meshes */ ++ extern plMeshInterfaceHandle plNewMeshInterface(void); ++ extern void plAddTriangle(plMeshInterfaceHandle meshHandle, plVector3 v0,plVector3 v1,plVector3 v2); ++ extern plCollisionShapeHandle plNewStaticTriangleMeshShape(plMeshInterfaceHandle); ++ ++ extern void plSetScaling(plCollisionShapeHandle shape, plVector3 scaling); ++ ++/* SOLID has Response Callback/Table/Management */ ++/* PhysX has Triggers, User Callbacks and filtering */ ++/* ODE has the typedef void dNearCallback (void *data, dGeomID o1, dGeomID o2); */ ++ ++/* typedef void plUpdatedPositionCallback(void* userData, plRigidBodyHandle rbHandle, plVector3 pos); */ ++/* typedef void plUpdatedOrientationCallback(void* userData, plRigidBodyHandle rbHandle, plQuaternion orientation); */ ++ ++ /* get world transform */ ++ extern void plGetOpenGLMatrix(plRigidBodyHandle object, plReal* matrix); ++ extern void plGetPosition(plRigidBodyHandle object,plVector3 position); ++ extern void plGetOrientation(plRigidBodyHandle object,plQuaternion orientation); ++ ++ /* set world transform (position/orientation) */ ++ extern void plSetPosition(plRigidBodyHandle object, const plVector3 position); ++ extern void plSetOrientation(plRigidBodyHandle object, const plQuaternion orientation); ++ extern void plSetEuler(plReal yaw,plReal pitch,plReal roll, plQuaternion orient); ++ extern void plSetOpenGLMatrix(plRigidBodyHandle object, plReal* matrix); ++ ++ typedef struct plRayCastResult { ++ plRigidBodyHandle m_body; ++ plCollisionShapeHandle m_shape; ++ plVector3 m_positionWorld; ++ plVector3 m_normalWorld; ++ } plRayCastResult; ++ ++ extern int plRayCast(plDynamicsWorldHandle world, const plVector3 rayStart, const plVector3 rayEnd, plRayCastResult res); ++ ++ /* Sweep API */ ++ ++ /* extern plRigidBodyHandle plObjectCast(plDynamicsWorldHandle world, const plVector3 rayStart, const plVector3 rayEnd, plVector3 hitpoint, plVector3 normal); */ ++ ++ /* Continuous Collision Detection API */ ++ ++ // needed for source/blender/blenkernel/intern/collision.c ++ double plNearestPoints(float p1[3], float p2[3], float p3[3], float q1[3], float q2[3], float q3[3], float *pa, float *pb, float normal[3]); ++ ++ ++ /* Convex Hull */ ++ PL_DECLARE_HANDLE(plConvexHull); ++ plConvexHull plConvexHullCompute(float (*coords)[3], int count); ++ void plConvexHullDelete(plConvexHull hull); ++ int plConvexHullNumVertices(plConvexHull hull); ++ int plConvexHullNumFaces(plConvexHull hull); ++ void plConvexHullGetVertex(plConvexHull hull, int n, float coords[3], int *original_index); ++ int plConvexHullGetFaceSize(plConvexHull hull, int n); ++ void plConvexHullGetFaceVertices(plConvexHull hull, int n, int *vertices); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++ ++#endif //BULLET_C_API_H ++ +diff --git a/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorld.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorld.h +index eede2b28ca4..4a3bf0f7e1e 100644 +--- a/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorld.h ++++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorld.h +@@ -15,7 +15,7 @@ subject to the following restrictions: + + + /** +- * @mainpage Bullet Documentation ++ * @page Bullet Documentation + * + * @section intro_sec Introduction + * 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 ). +diff --git a/extern/bullet/src/BulletCollision/CollisionShapes/btConvexHullShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btConvexHullShape.cpp +index a7a9598406a..eec2b8d769e 100644 +--- a/extern/bullet/src/BulletCollision/CollisionShapes/btConvexHullShape.cpp ++++ b/extern/bullet/src/BulletCollision/CollisionShapes/btConvexHullShape.cpp +@@ -13,9 +13,9 @@ subject to the following restrictions: + 3. This notice may not be removed or altered from any source distribution. + */ + +-#if defined (_WIN32) || defined (__i386__) +-#define BT_USE_SSE_IN_API +-#endif ++//#if defined (_WIN32) || defined (__i386__) ++//#define BT_USE_SSE_IN_API ++//#endif + + #include "btConvexHullShape.h" + #include "BulletCollision/CollisionShapes/btCollisionMargin.h" +diff --git a/extern/bullet/src/BulletCollision/CollisionShapes/btConvexShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btConvexShape.cpp +index 8d7fb054d6b..b31fbdcf237 100644 +--- a/extern/bullet/src/BulletCollision/CollisionShapes/btConvexShape.cpp ++++ b/extern/bullet/src/BulletCollision/CollisionShapes/btConvexShape.cpp +@@ -13,9 +13,9 @@ subject to the following restrictions: + 3. This notice may not be removed or altered from any source distribution. + */ + +-#if defined (_WIN32) || defined (__i386__) +-#define BT_USE_SSE_IN_API +-#endif ++//#if defined (_WIN32) || defined (__i386__) ++//#define BT_USE_SSE_IN_API ++//#endif + + #include "btConvexShape.h" + #include "btTriangleShape.h" +diff --git a/extern/bullet/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp +index 4195fa31388..d5bf6d60fe3 100644 +--- a/extern/bullet/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp ++++ b/extern/bullet/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp +@@ -13,9 +13,9 @@ subject to the following restrictions: + 3. This notice may not be removed or altered from any source distribution. + */ + +-#if defined (_WIN32) || defined (__i386__) +-#define BT_USE_SSE_IN_API +-#endif ++//#if defined (_WIN32) || defined (__i386__) ++//#define BT_USE_SSE_IN_API ++//#endif + + #include "btMultiSphereShape.h" + #include "BulletCollision/CollisionShapes/btCollisionMargin.h" +diff --git a/extern/bullet/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp +index 4854f370f73..9095c592d87 100644 +--- a/extern/bullet/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp ++++ b/extern/bullet/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp +@@ -12,9 +12,9 @@ subject to the following restrictions: + 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. + */ +-#if defined (_WIN32) || defined (__i386__) +-#define BT_USE_SSE_IN_API +-#endif ++//#if defined (_WIN32) || defined (__i386__) ++//#define BT_USE_SSE_IN_API ++//#endif + + #include "BulletCollision/CollisionShapes/btPolyhedralConvexShape.h" + #include "btConvexPolyhedron.h" +diff --git a/extern/bullet/src/BulletDynamics/ConstraintSolver/btSolverBody.h b/extern/bullet/src/BulletDynamics/ConstraintSolver/btSolverBody.h +index 27ccefe4169..8e4456e617a 100644 +--- a/extern/bullet/src/BulletDynamics/ConstraintSolver/btSolverBody.h ++++ b/extern/bullet/src/BulletDynamics/ConstraintSolver/btSolverBody.h +@@ -37,8 +37,13 @@ struct btSimdScalar + { + + } +- ++/* workaround for clang 3.4 ( == apple clang 5.1 ) issue, friction would fail with forced inlining */ ++#if (defined(__clang__) && defined(__apple_build_version__) && (__clang_major__ == 5) && (__clang_minor__ == 1)) \ ++|| (defined(__clang__) && !defined(__apple_build_version__) && (__clang_major__ == 3) && (__clang_minor__ == 4)) ++ inline __attribute__ ((noinline)) btSimdScalar(float fl) ++#else + SIMD_FORCE_INLINE btSimdScalar(float fl) ++#endif + :m_vec128 (_mm_set1_ps(fl)) + { + } +diff --git a/extern/bullet/src/BulletDynamics/Dynamics/Bullet-C-API.cpp b/extern/bullet/src/BulletDynamics/Dynamics/Bullet-C-API.cpp +new file mode 100644 +index 00000000000..e1f69afe101 +--- /dev/null ++++ b/extern/bullet/src/BulletDynamics/Dynamics/Bullet-C-API.cpp +@@ -0,0 +1,469 @@ ++/* ++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. ++*/ ++ ++/* ++ Draft high-level generic physics C-API. For low-level access, use the physics SDK native API's. ++ Work in progress, functionality will be added on demand. ++ ++ If possible, use the richer Bullet C++ API, by including ++*/ ++ ++#include "Bullet-C-Api.h" ++#include "btBulletDynamicsCommon.h" ++#include "LinearMath/btAlignedAllocator.h" ++#include "LinearMath/btConvexHullComputer.h" ++ ++ ++#include "LinearMath/btVector3.h" ++#include "LinearMath/btScalar.h" ++#include "LinearMath/btMatrix3x3.h" ++#include "LinearMath/btTransform.h" ++#include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" ++#include "BulletCollision/CollisionShapes/btTriangleShape.h" ++#include "BulletCollision/Gimpact/btTriangleShapeEx.h" ++ ++#include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" ++#include "BulletCollision/NarrowPhaseCollision/btPointCollector.h" ++#include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" ++#include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" ++#include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h" ++#include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h" ++#include "BulletCollision/CollisionShapes/btMinkowskiSumShape.h" ++#include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" ++#include "BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h" ++#include "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h" ++ ++ ++/* ++ Create and Delete a Physics SDK ++*/ ++ ++struct btPhysicsSdk ++{ ++ ++// btDispatcher* m_dispatcher; ++// btOverlappingPairCache* m_pairCache; ++// btConstraintSolver* m_constraintSolver ++ ++ btVector3 m_worldAabbMin; ++ btVector3 m_worldAabbMax; ++ ++ ++ //todo: version, hardware/optimization settings etc? ++ btPhysicsSdk() ++ :m_worldAabbMin(-1000,-1000,-1000), ++ m_worldAabbMax(1000,1000,1000) ++ { ++ ++ } ++ ++ ++}; ++ ++plPhysicsSdkHandle plNewBulletSdk() ++{ ++ void* mem = btAlignedAlloc(sizeof(btPhysicsSdk),16); ++ return (plPhysicsSdkHandle)new (mem)btPhysicsSdk; ++} ++ ++void plDeletePhysicsSdk(plPhysicsSdkHandle physicsSdk) ++{ ++ btPhysicsSdk* phys = reinterpret_cast(physicsSdk); ++ btAlignedFree(phys); ++} ++ ++ ++/* Dynamics World */ ++plDynamicsWorldHandle plCreateDynamicsWorld(plPhysicsSdkHandle physicsSdkHandle) ++{ ++ btPhysicsSdk* physicsSdk = reinterpret_cast(physicsSdkHandle); ++ void* mem = btAlignedAlloc(sizeof(btDefaultCollisionConfiguration),16); ++ btDefaultCollisionConfiguration* collisionConfiguration = new (mem)btDefaultCollisionConfiguration(); ++ mem = btAlignedAlloc(sizeof(btCollisionDispatcher),16); ++ btDispatcher* dispatcher = new (mem)btCollisionDispatcher(collisionConfiguration); ++ mem = btAlignedAlloc(sizeof(btAxisSweep3),16); ++ btBroadphaseInterface* pairCache = new (mem)btAxisSweep3(physicsSdk->m_worldAabbMin,physicsSdk->m_worldAabbMax); ++ mem = btAlignedAlloc(sizeof(btSequentialImpulseConstraintSolver),16); ++ btConstraintSolver* constraintSolver = new(mem) btSequentialImpulseConstraintSolver(); ++ ++ mem = btAlignedAlloc(sizeof(btDiscreteDynamicsWorld),16); ++ return (plDynamicsWorldHandle) new (mem)btDiscreteDynamicsWorld(dispatcher,pairCache,constraintSolver,collisionConfiguration); ++} ++void plDeleteDynamicsWorld(plDynamicsWorldHandle world) ++{ ++ //todo: also clean up the other allocations, axisSweep, pairCache,dispatcher,constraintSolver,collisionConfiguration ++ btDynamicsWorld* dynamicsWorld = reinterpret_cast< btDynamicsWorld* >(world); ++ btAlignedFree(dynamicsWorld); ++} ++ ++void plStepSimulation(plDynamicsWorldHandle world, plReal timeStep) ++{ ++ btDynamicsWorld* dynamicsWorld = reinterpret_cast< btDynamicsWorld* >(world); ++ btAssert(dynamicsWorld); ++ dynamicsWorld->stepSimulation(timeStep); ++} ++ ++void plAddRigidBody(plDynamicsWorldHandle world, plRigidBodyHandle object) ++{ ++ btDynamicsWorld* dynamicsWorld = reinterpret_cast< btDynamicsWorld* >(world); ++ btAssert(dynamicsWorld); ++ btRigidBody* body = reinterpret_cast< btRigidBody* >(object); ++ btAssert(body); ++ ++ dynamicsWorld->addRigidBody(body); ++} ++ ++void plRemoveRigidBody(plDynamicsWorldHandle world, plRigidBodyHandle object) ++{ ++ btDynamicsWorld* dynamicsWorld = reinterpret_cast< btDynamicsWorld* >(world); ++ btAssert(dynamicsWorld); ++ btRigidBody* body = reinterpret_cast< btRigidBody* >(object); ++ btAssert(body); ++ ++ dynamicsWorld->removeRigidBody(body); ++} ++ ++/* Rigid Body */ ++ ++plRigidBodyHandle plCreateRigidBody( void* user_data, float mass, plCollisionShapeHandle cshape ) ++{ ++ btTransform trans; ++ trans.setIdentity(); ++ btVector3 localInertia(0,0,0); ++ btCollisionShape* shape = reinterpret_cast( cshape); ++ btAssert(shape); ++ if (mass) ++ { ++ shape->calculateLocalInertia(mass,localInertia); ++ } ++ void* mem = btAlignedAlloc(sizeof(btRigidBody),16); ++ btRigidBody::btRigidBodyConstructionInfo rbci(mass, 0,shape,localInertia); ++ btRigidBody* body = new (mem)btRigidBody(rbci); ++ body->setWorldTransform(trans); ++ body->setUserPointer(user_data); ++ return (plRigidBodyHandle) body; ++} ++ ++void plDeleteRigidBody(plRigidBodyHandle cbody) ++{ ++ btRigidBody* body = reinterpret_cast< btRigidBody* >(cbody); ++ btAssert(body); ++ btAlignedFree( body); ++} ++ ++ ++/* Collision Shape definition */ ++ ++plCollisionShapeHandle plNewSphereShape(plReal radius) ++{ ++ void* mem = btAlignedAlloc(sizeof(btSphereShape),16); ++ return (plCollisionShapeHandle) new (mem)btSphereShape(radius); ++ ++} ++ ++plCollisionShapeHandle plNewBoxShape(plReal x, plReal y, plReal z) ++{ ++ void* mem = btAlignedAlloc(sizeof(btBoxShape),16); ++ return (plCollisionShapeHandle) new (mem)btBoxShape(btVector3(x,y,z)); ++} ++ ++plCollisionShapeHandle plNewCapsuleShape(plReal radius, plReal height) ++{ ++ //capsule is convex hull of 2 spheres, so use btMultiSphereShape ++ ++ const int numSpheres = 2; ++ btVector3 positions[numSpheres] = {btVector3(0,height,0),btVector3(0,-height,0)}; ++ btScalar radi[numSpheres] = {radius,radius}; ++ void* mem = btAlignedAlloc(sizeof(btMultiSphereShape),16); ++ return (plCollisionShapeHandle) new (mem)btMultiSphereShape(positions,radi,numSpheres); ++} ++plCollisionShapeHandle plNewConeShape(plReal radius, plReal height) ++{ ++ void* mem = btAlignedAlloc(sizeof(btConeShape),16); ++ return (plCollisionShapeHandle) new (mem)btConeShape(radius,height); ++} ++ ++plCollisionShapeHandle plNewCylinderShape(plReal radius, plReal height) ++{ ++ void* mem = btAlignedAlloc(sizeof(btCylinderShape),16); ++ return (plCollisionShapeHandle) new (mem)btCylinderShape(btVector3(radius,height,radius)); ++} ++ ++/* Convex Meshes */ ++plCollisionShapeHandle plNewConvexHullShape() ++{ ++ void* mem = btAlignedAlloc(sizeof(btConvexHullShape),16); ++ return (plCollisionShapeHandle) new (mem)btConvexHullShape(); ++} ++ ++ ++/* Concave static triangle meshes */ ++plMeshInterfaceHandle plNewMeshInterface() ++{ ++ return 0; ++} ++ ++plCollisionShapeHandle plNewCompoundShape() ++{ ++ void* mem = btAlignedAlloc(sizeof(btCompoundShape),16); ++ return (plCollisionShapeHandle) new (mem)btCompoundShape(); ++} ++ ++void plAddChildShape(plCollisionShapeHandle compoundShapeHandle,plCollisionShapeHandle childShapeHandle, plVector3 childPos,plQuaternion childOrn) ++{ ++ btCollisionShape* colShape = reinterpret_cast(compoundShapeHandle); ++ btAssert(colShape->getShapeType() == COMPOUND_SHAPE_PROXYTYPE); ++ btCompoundShape* compoundShape = reinterpret_cast(colShape); ++ btCollisionShape* childShape = reinterpret_cast(childShapeHandle); ++ btTransform localTrans; ++ localTrans.setIdentity(); ++ localTrans.setOrigin(btVector3(childPos[0],childPos[1],childPos[2])); ++ localTrans.setRotation(btQuaternion(childOrn[0],childOrn[1],childOrn[2],childOrn[3])); ++ compoundShape->addChildShape(localTrans,childShape); ++} ++ ++void plSetEuler(plReal yaw,plReal pitch,plReal roll, plQuaternion orient) ++{ ++ btQuaternion orn; ++ orn.setEuler(yaw,pitch,roll); ++ orient[0] = orn.getX(); ++ orient[1] = orn.getY(); ++ orient[2] = orn.getZ(); ++ orient[3] = orn.getW(); ++ ++} ++ ++ ++// extern void plAddTriangle(plMeshInterfaceHandle meshHandle, plVector3 v0,plVector3 v1,plVector3 v2); ++// extern plCollisionShapeHandle plNewStaticTriangleMeshShape(plMeshInterfaceHandle); ++ ++ ++void plAddVertex(plCollisionShapeHandle cshape, plReal x,plReal y,plReal z) ++{ ++ btCollisionShape* colShape = reinterpret_cast( cshape); ++ (void)colShape; ++ btAssert(colShape->getShapeType()==CONVEX_HULL_SHAPE_PROXYTYPE); ++ btConvexHullShape* convexHullShape = reinterpret_cast( cshape); ++ convexHullShape->addPoint(btVector3(x,y,z)); ++ ++} ++ ++void plDeleteShape(plCollisionShapeHandle cshape) ++{ ++ btCollisionShape* shape = reinterpret_cast( cshape); ++ btAssert(shape); ++ btAlignedFree(shape); ++} ++void plSetScaling(plCollisionShapeHandle cshape, plVector3 cscaling) ++{ ++ btCollisionShape* shape = reinterpret_cast( cshape); ++ btAssert(shape); ++ btVector3 scaling(cscaling[0],cscaling[1],cscaling[2]); ++ shape->setLocalScaling(scaling); ++} ++ ++ ++ ++void plSetPosition(plRigidBodyHandle object, const plVector3 position) ++{ ++ btRigidBody* body = reinterpret_cast< btRigidBody* >(object); ++ btAssert(body); ++ btVector3 pos(position[0],position[1],position[2]); ++ btTransform worldTrans = body->getWorldTransform(); ++ worldTrans.setOrigin(pos); ++ body->setWorldTransform(worldTrans); ++} ++ ++void plSetOrientation(plRigidBodyHandle object, const plQuaternion orientation) ++{ ++ btRigidBody* body = reinterpret_cast< btRigidBody* >(object); ++ btAssert(body); ++ btQuaternion orn(orientation[0],orientation[1],orientation[2],orientation[3]); ++ btTransform worldTrans = body->getWorldTransform(); ++ worldTrans.setRotation(orn); ++ body->setWorldTransform(worldTrans); ++} ++ ++void plSetOpenGLMatrix(plRigidBodyHandle object, plReal* matrix) ++{ ++ btRigidBody* body = reinterpret_cast< btRigidBody* >(object); ++ btAssert(body); ++ btTransform& worldTrans = body->getWorldTransform(); ++ worldTrans.setFromOpenGLMatrix(matrix); ++} ++ ++void plGetOpenGLMatrix(plRigidBodyHandle object, plReal* matrix) ++{ ++ btRigidBody* body = reinterpret_cast< btRigidBody* >(object); ++ btAssert(body); ++ body->getWorldTransform().getOpenGLMatrix(matrix); ++ ++} ++ ++void plGetPosition(plRigidBodyHandle object,plVector3 position) ++{ ++ btRigidBody* body = reinterpret_cast< btRigidBody* >(object); ++ btAssert(body); ++ const btVector3& pos = body->getWorldTransform().getOrigin(); ++ position[0] = pos.getX(); ++ position[1] = pos.getY(); ++ position[2] = pos.getZ(); ++} ++ ++void plGetOrientation(plRigidBodyHandle object,plQuaternion orientation) ++{ ++ btRigidBody* body = reinterpret_cast< btRigidBody* >(object); ++ btAssert(body); ++ const btQuaternion& orn = body->getWorldTransform().getRotation(); ++ orientation[0] = orn.getX(); ++ orientation[1] = orn.getY(); ++ orientation[2] = orn.getZ(); ++ orientation[3] = orn.getW(); ++} ++ ++ ++ ++//plRigidBodyHandle plRayCast(plDynamicsWorldHandle world, const plVector3 rayStart, const plVector3 rayEnd, plVector3 hitpoint, plVector3 normal); ++ ++// extern plRigidBodyHandle plObjectCast(plDynamicsWorldHandle world, const plVector3 rayStart, const plVector3 rayEnd, plVector3 hitpoint, plVector3 normal); ++ ++double plNearestPoints(float p1[3], float p2[3], float p3[3], float q1[3], float q2[3], float q3[3], float *pa, float *pb, float normal[3]) ++{ ++ btVector3 vp(p1[0], p1[1], p1[2]); ++ btTriangleShapeEx trishapeA(vp, ++ btVector3(p2[0], p2[1], p2[2]), ++ btVector3(p3[0], p3[1], p3[2])); ++ trishapeA.setMargin(0.000001f); ++ btVector3 vq(q1[0], q1[1], q1[2]); ++ btTriangleShapeEx trishapeB(vq, ++ btVector3(q2[0], q2[1], q2[2]), ++ btVector3(q3[0], q3[1], q3[2])); ++ trishapeB.setMargin(0.000001f); ++ ++ // btVoronoiSimplexSolver sGjkSimplexSolver; ++ // btGjkEpaPenetrationDepthSolver penSolverPtr; ++ ++ /*static*/ btSimplexSolverInterface sGjkSimplexSolver; ++ sGjkSimplexSolver.reset(); ++ ++ /*static*/ btGjkEpaPenetrationDepthSolver Solver0; ++ /*static*/ btMinkowskiPenetrationDepthSolver Solver1; ++ ++ btConvexPenetrationDepthSolver* Solver = NULL; ++ ++ Solver = &Solver1; ++ ++ btGjkPairDetector convexConvex(&trishapeA ,&trishapeB,&sGjkSimplexSolver,Solver); ++ ++ convexConvex.m_catchDegeneracies = 1; ++ ++ // btGjkPairDetector convexConvex(&trishapeA ,&trishapeB,&sGjkSimplexSolver,0); ++ ++ btPointCollector gjkOutput; ++ btGjkPairDetector::ClosestPointInput input; ++ ++ ++ btTransform tr; ++ tr.setIdentity(); ++ ++ input.m_transformA = tr; ++ input.m_transformB = tr; ++ ++ convexConvex.getClosestPoints(input, gjkOutput, 0); ++ ++ ++ if (gjkOutput.m_hasResult) ++ { ++ ++ pb[0] = pa[0] = gjkOutput.m_pointInWorld[0]; ++ pb[1] = pa[1] = gjkOutput.m_pointInWorld[1]; ++ pb[2] = pa[2] = gjkOutput.m_pointInWorld[2]; ++ ++ pb[0]+= gjkOutput.m_normalOnBInWorld[0] * gjkOutput.m_distance; ++ pb[1]+= gjkOutput.m_normalOnBInWorld[1] * gjkOutput.m_distance; ++ pb[2]+= gjkOutput.m_normalOnBInWorld[2] * gjkOutput.m_distance; ++ ++ normal[0] = gjkOutput.m_normalOnBInWorld[0]; ++ normal[1] = gjkOutput.m_normalOnBInWorld[1]; ++ normal[2] = gjkOutput.m_normalOnBInWorld[2]; ++ ++ return gjkOutput.m_distance; ++ } ++ return -1.0f; ++} ++ ++// Convex hull ++plConvexHull plConvexHullCompute(float (*coords)[3], int count) ++{ ++ btConvexHullComputer *computer = new btConvexHullComputer; ++ computer->compute(reinterpret_cast< float* >(coords), ++ sizeof(*coords), count, 0, 0); ++ return reinterpret_cast(computer); ++} ++ ++void plConvexHullDelete(plConvexHull hull) ++{ ++ btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull)); ++ delete computer; ++} ++ ++int plConvexHullNumVertices(plConvexHull hull) ++{ ++ btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull)); ++ return computer->vertices.size(); ++} ++ ++int plConvexHullNumFaces(plConvexHull hull) ++{ ++ btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull)); ++ return computer->faces.size(); ++} ++ ++void plConvexHullGetVertex(plConvexHull hull, int n, float coords[3], ++ int *original_index) ++{ ++ btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull)); ++ const btVector3 &v(computer->vertices[n]); ++ coords[0] = v[0]; ++ coords[1] = v[1]; ++ coords[2] = v[2]; ++ (*original_index) = computer->original_vertex_index[n]; ++} ++ ++int plConvexHullGetFaceSize(plConvexHull hull, int n) ++{ ++ btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull)); ++ const btConvexHullComputer::Edge *e_orig, *e; ++ int count; ++ ++ for (e_orig = &computer->edges[computer->faces[n]], e = e_orig, count = 0; ++ count == 0 || e != e_orig; ++ e = e->getNextEdgeOfFace(), count++); ++ return count; ++} ++ ++void plConvexHullGetFaceVertices(plConvexHull hull, int n, int *vertices) ++{ ++ btConvexHullComputer *computer(reinterpret_cast< btConvexHullComputer* >(hull)); ++ const btConvexHullComputer::Edge *e_orig, *e; ++ int count; ++ ++ for (e_orig = &computer->edges[computer->faces[n]], e = e_orig, count = 0; ++ count == 0 || e != e_orig; ++ e = e->getNextEdgeOfFace(), count++) ++ { ++ vertices[count] = e->getTargetVertex(); ++ } ++} +diff --git a/extern/bullet/src/BulletDynamics/Dynamics/btRigidBody.cpp b/extern/bullet/src/BulletDynamics/Dynamics/btRigidBody.cpp +index ca0714fcfa8..a9f27496212 100644 +--- a/extern/bullet/src/BulletDynamics/Dynamics/btRigidBody.cpp ++++ b/extern/bullet/src/BulletDynamics/Dynamics/btRigidBody.cpp +@@ -427,50 +427,38 @@ void btRigidBody::setCenterOfMassTransform(const btTransform& xform) + } + + ++bool btRigidBody::checkCollideWithOverride(const btCollisionObject* co) const ++{ ++ const btRigidBody* otherRb = btRigidBody::upcast(co); ++ if (!otherRb) ++ return true; ++ ++ for (int i = 0; i < m_constraintRefs.size(); ++i) ++ { ++ const btTypedConstraint* c = m_constraintRefs[i]; ++ if (c->isEnabled()) ++ if (&c->getRigidBodyA() == otherRb || &c->getRigidBodyB() == otherRb) ++ return false; ++ } ++ ++ return true; ++} + + + + void btRigidBody::addConstraintRef(btTypedConstraint* c) + { +- ///disable collision with the 'other' body +- + int index = m_constraintRefs.findLinearSearch(c); +- //don't add constraints that are already referenced +- //btAssert(index == m_constraintRefs.size()); + if (index == m_constraintRefs.size()) +- { +- m_constraintRefs.push_back(c); +- btCollisionObject* colObjA = &c->getRigidBodyA(); +- btCollisionObject* colObjB = &c->getRigidBodyB(); +- if (colObjA == this) +- { +- colObjA->setIgnoreCollisionCheck(colObjB, true); +- } +- else +- { +- colObjB->setIgnoreCollisionCheck(colObjA, true); +- } +- } ++ m_constraintRefs.push_back(c); ++ ++ m_checkCollideWith = true; + } + + void btRigidBody::removeConstraintRef(btTypedConstraint* c) + { +- int index = m_constraintRefs.findLinearSearch(c); +- //don't remove constraints that are not referenced +- if(index < m_constraintRefs.size()) +- { +- m_constraintRefs.remove(c); +- btCollisionObject* colObjA = &c->getRigidBodyA(); +- btCollisionObject* colObjB = &c->getRigidBodyB(); +- if (colObjA == this) +- { +- colObjA->setIgnoreCollisionCheck(colObjB, false); +- } +- else +- { +- colObjB->setIgnoreCollisionCheck(colObjA, false); +- } +- } ++ m_constraintRefs.remove(c); ++ m_checkCollideWith = m_constraintRefs.size() > 0; + } + + int btRigidBody::calculateSerializeBufferSize() const +diff --git a/extern/bullet/src/BulletDynamics/Dynamics/btRigidBody.h b/extern/bullet/src/BulletDynamics/Dynamics/btRigidBody.h +index 372245031b1..dbbf9958618 100644 +--- a/extern/bullet/src/BulletDynamics/Dynamics/btRigidBody.h ++++ b/extern/bullet/src/BulletDynamics/Dynamics/btRigidBody.h +@@ -512,6 +512,8 @@ public: + return (getBroadphaseProxy() != 0); + } + ++ virtual bool checkCollideWithOverride(const btCollisionObject* co) const; ++ + void addConstraintRef(btTypedConstraint* c); + void removeConstraintRef(btTypedConstraint* c); + +diff --git a/extern/bullet/src/LinearMath/btConvexHullComputer.cpp b/extern/bullet/src/LinearMath/btConvexHullComputer.cpp +index 2ea22cbe3ba..efe9a171bec 100644 +--- a/extern/bullet/src/LinearMath/btConvexHullComputer.cpp ++++ b/extern/bullet/src/LinearMath/btConvexHullComputer.cpp +@@ -2678,6 +2678,7 @@ btScalar btConvexHullComputer::compute(const void* coords, bool doubleCoords, in + } + + vertices.resize(0); ++ original_vertex_index.resize(0); + edges.resize(0); + faces.resize(0); + +@@ -2688,6 +2689,7 @@ btScalar btConvexHullComputer::compute(const void* coords, bool doubleCoords, in + { + btConvexHullInternal::Vertex* v = oldVertices[copied]; + vertices.push_back(hull.getCoordinates(v)); ++ original_vertex_index.push_back(v->point.index); + btConvexHullInternal::Edge* firstEdge = v->edges; + if (firstEdge) + { +diff --git a/extern/bullet/src/LinearMath/btConvexHullComputer.h b/extern/bullet/src/LinearMath/btConvexHullComputer.h +index 7240ac4fb52..6871ce80e00 100644 +--- a/extern/bullet/src/LinearMath/btConvexHullComputer.h ++++ b/extern/bullet/src/LinearMath/btConvexHullComputer.h +@@ -67,6 +67,7 @@ class btConvexHullComputer + + // Vertices of the output hull + btAlignedObjectArray vertices; ++ btAlignedObjectArray original_vertex_index; + + // Edges of the output hull + btAlignedObjectArray edges; +diff --git a/extern/bullet/src/LinearMath/btScalar.h b/extern/bullet/src/LinearMath/btScalar.h +index bffb2ce274e..47b00385057 100644 +--- a/extern/bullet/src/LinearMath/btScalar.h ++++ b/extern/bullet/src/LinearMath/btScalar.h +@@ -14,6 +14,9 @@ subject to the following restrictions: + + #ifndef BT_SCALAR_H + #define BT_SCALAR_H ++#if defined(_MSC_VER) && defined(__clang__) /* clang supplies it's own overloads already */ ++#define BT_NO_SIMD_OPERATOR_OVERLOADS ++#endif + + #ifdef BT_MANAGED_CODE + //Aligned data types not supported in managed code +@@ -101,7 +104,7 @@ inline int btGetVersion() + #ifdef BT_USE_SSE + + #if (_MSC_FULL_VER >= 170050727)//Visual Studio 2012 can compile SSE4/FMA3 (but SSE4/FMA3 is not enabled by default) +- #define BT_ALLOW_SSE4 ++ //#define BT_ALLOW_SSE4 //disable this cause blender targets sse2 + #endif //(_MSC_FULL_VER >= 160040219) + + //BT_USE_SSE_IN_API is disabled under Windows by default, because +diff --git a/extern/bullet/src/LinearMath/btVector3.cpp b/extern/bullet/src/LinearMath/btVector3.cpp +index e05bdccd67e..dbcf2b6ab57 100644 +--- a/extern/bullet/src/LinearMath/btVector3.cpp ++++ b/extern/bullet/src/LinearMath/btVector3.cpp +@@ -15,9 +15,9 @@ + This source version has been altered. + */ + +-#if defined (_WIN32) || defined (__i386__) +-#define BT_USE_SSE_IN_API +-#endif ++//#if defined (_WIN32) || defined (__i386__) ++//#define BT_USE_SSE_IN_API ++//#endif + + + #include "btVector3.h" +-- +2.18.0 + diff --git a/extern/bullet/patches/character-ghost.patch b/extern/bullet/patches/character-ghost.patch new file mode 100644 index 000000000000..4aa5532168c6 --- /dev/null +++ b/extern/bullet/patches/character-ghost.patch @@ -0,0 +1,131 @@ +From 3f6c099a3a9f78c7862448f42df61df9b1cd41cb Mon Sep 17 00:00:00 2001 +From: tristan +Date: Fri, 12 Oct 2018 19:26:23 +0200 +Subject: [PATCH] temp + +--- + .../btKinematicCharacterController.cpp | 32 +++++++++++-------- + .../btKinematicCharacterController.h | 8 ++--- + 2 files changed, 23 insertions(+), 17 deletions(-) + +diff --git a/extern/bullet/src/BulletDynamics/Character/btKinematicCharacterController.cpp b/extern/bullet/src/BulletDynamics/Character/btKinematicCharacterController.cpp +index cb1aa71a14e..4a6ce16a4e2 100644 +--- a/extern/bullet/src/BulletDynamics/Character/btKinematicCharacterController.cpp ++++ b/extern/bullet/src/BulletDynamics/Character/btKinematicCharacterController.cpp +@@ -132,7 +132,7 @@ btVector3 btKinematicCharacterController::perpindicularComponent (const btVector + return direction - parallelComponent(direction, normal); + } + +-btKinematicCharacterController::btKinematicCharacterController (btPairCachingGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, const btVector3& up) ++btKinematicCharacterController::btKinematicCharacterController (btGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, const btVector3& up) + { + m_ghostObject = ghostObject; + m_up.setValue(0.0f, 0.0f, 1.0f); +@@ -170,7 +170,7 @@ btKinematicCharacterController::~btKinematicCharacterController () + { + } + +-btPairCachingGhostObject* btKinematicCharacterController::getGhostObject() ++btGhostObject* btKinematicCharacterController::getGhostObject() + { + return m_ghostObject; + } +@@ -194,26 +194,32 @@ bool btKinematicCharacterController::recoverFromPenetration ( btCollisionWorld* + + bool penetration = false; + +- collisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_ghostObject->getOverlappingPairCache(), collisionWorld->getDispatchInfo(), collisionWorld->getDispatcher()); +- + m_currentPosition = m_ghostObject->getWorldTransform().getOrigin(); +- ++ ++ btOverlappingPairCache *pairCache = collisionWorld->getPairCache(); ++ const unsigned int numPairs = m_ghostObject->getNumOverlappingObjects(); ++ + // btScalar maxPen = btScalar(0.0); +- for (int i = 0; i < m_ghostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++) ++ for (int i = 0; i < numPairs; i++) + { +- m_manifoldArray.resize(0); ++ btCollisionObject *obj0 = m_ghostObject; ++ btCollisionObject *obj1 = m_ghostObject->getOverlappingObject(i); + +- btBroadphasePair* collisionPair = &m_ghostObject->getOverlappingPairCache()->getOverlappingPairArray()[i]; ++ btBroadphaseProxy *proxy0 = obj0->getBroadphaseHandle(); ++ btBroadphaseProxy *proxy1 = obj1->getBroadphaseHandle(); + +- btCollisionObject* obj0 = static_cast(collisionPair->m_pProxy0->m_clientObject); +- btCollisionObject* obj1 = static_cast(collisionPair->m_pProxy1->m_clientObject); ++ btBroadphasePair* collisionPair = pairCache->findPair(proxy0, proxy1); ++ ++ btAssert(collisionPair); + + if ((obj0 && !obj0->hasContactResponse()) || (obj1 && !obj1->hasContactResponse())) + continue; + + if (!needsCollision(obj0, obj1)) + continue; +- ++ ++ m_manifoldArray.resize(0); ++ + if (collisionPair->m_algorithm) + collisionPair->m_algorithm->getAllContactManifolds(m_manifoldArray); + +@@ -688,11 +694,11 @@ void btKinematicCharacterController::reset ( btCollisionWorld* collisionWorld ) + m_velocityTimeInterval = 0.0; + + //clear pair cache +- btHashedOverlappingPairCache *cache = m_ghostObject->getOverlappingPairCache(); ++ /*btHashedOverlappingPairCache *cache = m_ghostObject->getOverlappingPairCache(); + while (cache->getOverlappingPairArray().size() > 0) + { + cache->removeOverlappingPair(cache->getOverlappingPairArray()[0].m_pProxy0, cache->getOverlappingPairArray()[0].m_pProxy1, collisionWorld->getDispatcher()); +- } ++ }*/ + } + + void btKinematicCharacterController::warp (const btVector3& origin) +diff --git a/extern/bullet/src/BulletDynamics/Character/btKinematicCharacterController.h b/extern/bullet/src/BulletDynamics/Character/btKinematicCharacterController.h +index 3d677e647e2..2dd12eaa5f1 100644 +--- a/extern/bullet/src/BulletDynamics/Character/btKinematicCharacterController.h ++++ b/extern/bullet/src/BulletDynamics/Character/btKinematicCharacterController.h +@@ -29,7 +29,7 @@ class btConvexShape; + class btRigidBody; + class btCollisionWorld; + class btCollisionDispatcher; +-class btPairCachingGhostObject; ++class btGhostObject; + + ///btKinematicCharacterController is an object that supports a sliding motion in a world. + ///It uses a ghost object and convex sweep test to test for upcoming collisions. This is combined with discrete collision detection to recover from penetrations. +@@ -40,7 +40,7 @@ protected: + + btScalar m_halfHeight; + +- btPairCachingGhostObject* m_ghostObject; ++ btGhostObject* m_ghostObject; + btConvexShape* m_convexShape;//is also in m_ghostObject, but it needs to be convex, so we store it here to avoid upcast + + btScalar m_maxPenetrationDepth; +@@ -117,7 +117,7 @@ public: + + BT_DECLARE_ALIGNED_ALLOCATOR(); + +- btKinematicCharacterController (btPairCachingGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, const btVector3& up = btVector3(1.0,0.0,0.0)); ++ btKinematicCharacterController (btGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, const btVector3& up = btVector3(1.0,0.0,0.0)); + ~btKinematicCharacterController (); + + +@@ -191,7 +191,7 @@ public: + void setMaxPenetrationDepth(btScalar d); + btScalar getMaxPenetrationDepth() const; + +- btPairCachingGhostObject* getGhostObject(); ++ btGhostObject* getGhostObject(); + void setUseGhostSweepTest(bool useGhostObjectSweepTest) + { + m_useGhostObjectSweepTest = useGhostObjectSweepTest; +-- +2.18.0 + diff --git a/extern/bullet/patches/softrigid-world-mt.patch b/extern/bullet/patches/softrigid-world-mt.patch new file mode 100644 index 000000000000..0cc37cbd0d93 --- /dev/null +++ b/extern/bullet/patches/softrigid-world-mt.patch @@ -0,0 +1,501 @@ +From 02c5a7ccf91a1ad0c29ae1b181f19713892f5d05 Mon Sep 17 00:00:00 2001 +From: tristan +Date: Fri, 12 Oct 2018 19:16:04 +0200 +Subject: [PATCH] temp + +--- + .../btSoftRigidDynamicsWorldMt.cpp | 367 ++++++++++++++++++ + .../btSoftRigidDynamicsWorldMt.h | 107 +++++ + 2 files changed, 474 insertions(+) + create mode 100644 extern/bullet/src/BulletSoftBody/btSoftRigidDynamicsWorldMt.cpp + create mode 100644 extern/bullet/src/BulletSoftBody/btSoftRigidDynamicsWorldMt.h + +diff --git a/extern/bullet/src/BulletSoftBody/btSoftRigidDynamicsWorldMt.cpp b/extern/bullet/src/BulletSoftBody/btSoftRigidDynamicsWorldMt.cpp +new file mode 100644 +index 00000000000..bd3625a751c +--- /dev/null ++++ b/extern/bullet/src/BulletSoftBody/btSoftRigidDynamicsWorldMt.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 "btSoftRigidDynamicsWorldMt.h" ++#include "LinearMath/btQuickprof.h" ++ ++//softbody & helpers ++#include "btSoftBody.h" ++#include "btSoftBodyHelpers.h" ++#include "btSoftBodySolvers.h" ++#include "btDefaultSoftBodySolver.h" ++#include "LinearMath/btSerializer.h" ++ ++ ++btSoftRigidDynamicsWorldMt::btSoftRigidDynamicsWorldMt( ++ btDispatcher* dispatcher, ++ btBroadphaseInterface* pairCache, ++ btConstraintSolverPoolMt* constraintSolver, ++ btCollisionConfiguration* collisionConfiguration, ++ btSoftBodySolver *softBodySolver ) : ++ btDiscreteDynamicsWorldMt(dispatcher,pairCache,constraintSolver,collisionConfiguration), ++ m_softBodySolver( softBodySolver ), ++ m_ownsSolver(false) ++{ ++ if( !m_softBodySolver ) ++ { ++ void* ptr = btAlignedAlloc(sizeof(btDefaultSoftBodySolver),16); ++ m_softBodySolver = new(ptr) btDefaultSoftBodySolver(); ++ m_ownsSolver = true; ++ } ++ ++ m_drawFlags = fDrawFlags::Std; ++ m_drawNodeTree = true; ++ m_drawFaceTree = false; ++ m_drawClusterTree = false; ++ m_sbi.m_broadphase = pairCache; ++ m_sbi.m_dispatcher = dispatcher; ++ m_sbi.m_sparsesdf.Initialize(); ++ m_sbi.m_sparsesdf.Reset(); ++ ++ m_sbi.air_density = (btScalar)1.2; ++ m_sbi.water_density = 0; ++ m_sbi.water_offset = 0; ++ m_sbi.water_normal = btVector3(0,0,0); ++ m_sbi.m_gravity.setValue(0,-10,0); ++ ++ m_sbi.m_sparsesdf.Initialize(); ++ ++ ++} ++ ++btSoftRigidDynamicsWorldMt::~btSoftRigidDynamicsWorldMt() ++{ ++ if (m_ownsSolver) ++ { ++ m_softBodySolver->~btSoftBodySolver(); ++ btAlignedFree(m_softBodySolver); ++ } ++} ++ ++void btSoftRigidDynamicsWorldMt::predictUnconstraintMotion(btScalar timeStep) ++{ ++ btDiscreteDynamicsWorldMt::predictUnconstraintMotion( timeStep ); ++ { ++ BT_PROFILE("predictUnconstraintMotionSoftBody"); ++ m_softBodySolver->predictMotion( float(timeStep) ); ++ } ++} ++ ++void btSoftRigidDynamicsWorldMt::internalSingleStepSimulation( btScalar timeStep ) ++{ ++ ++ // Let the solver grab the soft bodies and if necessary optimize for it ++ m_softBodySolver->optimize( getSoftBodyArray() ); ++ ++ if( !m_softBodySolver->checkInitialized() ) ++ { ++ btAssert( "Solver initialization failed\n" ); ++ } ++ ++ btDiscreteDynamicsWorldMt::internalSingleStepSimulation( timeStep ); ++ ++ ///solve soft bodies constraints ++ solveSoftBodiesConstraints( timeStep ); ++ ++ //self collisions ++ for ( int i=0;idefaultCollisionHandler(psb); ++ } ++ ++ ///update soft bodies ++ m_softBodySolver->updateSoftBodies( ); ++ ++ // End solver-wise simulation step ++ // /////////////////////////////// ++ ++} ++ ++void btSoftRigidDynamicsWorldMt::solveSoftBodiesConstraints( btScalar timeStep ) ++{ ++ BT_PROFILE("solveSoftConstraints"); ++ ++ if(m_softBodies.size()) ++ { ++ btSoftBody::solveClusters(m_softBodies); ++ } ++ ++ // Solve constraints solver-wise ++ m_softBodySolver->solveConstraints( timeStep * m_softBodySolver->getTimeScale() ); ++ ++} ++ ++void btSoftRigidDynamicsWorldMt::addSoftBody(btSoftBody* body, int collisionFilterGroup, int collisionFilterMask) ++{ ++ m_softBodies.push_back(body); ++ ++ // Set the soft body solver that will deal with this body ++ // to be the world's solver ++ body->setSoftBodySolver( m_softBodySolver ); ++ ++ btCollisionWorld::addCollisionObject(body, ++ collisionFilterGroup, ++ collisionFilterMask); ++ ++} ++ ++void btSoftRigidDynamicsWorldMt::removeSoftBody(btSoftBody* body) ++{ ++ m_softBodies.remove(body); ++ ++ btCollisionWorld::removeCollisionObject(body); ++} ++ ++void btSoftRigidDynamicsWorldMt::removeCollisionObject(btCollisionObject* collisionObject) ++{ ++ btSoftBody* body = btSoftBody::upcast(collisionObject); ++ if (body) ++ removeSoftBody(body); ++ else ++ btDiscreteDynamicsWorldMt::removeCollisionObject(collisionObject); ++} ++ ++void btSoftRigidDynamicsWorldMt::debugDrawWorld() ++{ ++ btDiscreteDynamicsWorldMt::debugDrawWorld(); ++ ++ if (getDebugDrawer()) ++ { ++ int i; ++ for ( i=0;im_softBodies.size();i++) ++ { ++ btSoftBody* psb=(btSoftBody*)this->m_softBodies[i]; ++ if (getDebugDrawer() && (getDebugDrawer()->getDebugMode() & (btIDebugDraw::DBG_DrawWireframe))) ++ { ++ btSoftBodyHelpers::DrawFrame(psb,m_debugDrawer); ++ btSoftBodyHelpers::Draw(psb,m_debugDrawer,m_drawFlags); ++ } ++ ++ if (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawAabb)) ++ { ++ if(m_drawNodeTree) btSoftBodyHelpers::DrawNodeTree(psb,m_debugDrawer); ++ if(m_drawFaceTree) btSoftBodyHelpers::DrawFaceTree(psb,m_debugDrawer); ++ if(m_drawClusterTree) btSoftBodyHelpers::DrawClusterTree(psb,m_debugDrawer); ++ } ++ } ++ } ++} ++ ++ ++ ++ ++struct btSoftSingleRayCallback : public btBroadphaseRayCallback ++{ ++ btVector3 m_rayFromWorld; ++ btVector3 m_rayToWorld; ++ btTransform m_rayFromTrans; ++ btTransform m_rayToTrans; ++ btVector3 m_hitNormal; ++ ++ const btSoftRigidDynamicsWorldMt* m_world; ++ btCollisionWorld::RayResultCallback& m_resultCallback; ++ ++ btSoftSingleRayCallback(const btVector3& rayFromWorld,const btVector3& rayToWorld,const btSoftRigidDynamicsWorldMt* world,btCollisionWorld::RayResultCallback& resultCallback) ++ :m_rayFromWorld(rayFromWorld), ++ m_rayToWorld(rayToWorld), ++ m_world(world), ++ m_resultCallback(resultCallback) ++ { ++ m_rayFromTrans.setIdentity(); ++ m_rayFromTrans.setOrigin(m_rayFromWorld); ++ m_rayToTrans.setIdentity(); ++ m_rayToTrans.setOrigin(m_rayToWorld); ++ ++ btVector3 rayDir = (rayToWorld-rayFromWorld); ++ ++ rayDir.normalize (); ++ ///what about division by zero? --> just set rayDirection[i] to INF/1e30 ++ m_rayDirectionInverse[0] = rayDir[0] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[0]; ++ m_rayDirectionInverse[1] = rayDir[1] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[1]; ++ m_rayDirectionInverse[2] = rayDir[2] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[2]; ++ m_signs[0] = m_rayDirectionInverse[0] < 0.0; ++ m_signs[1] = m_rayDirectionInverse[1] < 0.0; ++ m_signs[2] = m_rayDirectionInverse[2] < 0.0; ++ ++ m_lambda_max = rayDir.dot(m_rayToWorld-m_rayFromWorld); ++ ++ } ++ ++ ++ ++ virtual bool process(const btBroadphaseProxy* proxy) ++ { ++ ///terminate further ray tests, once the closestHitFraction reached zero ++ if (m_resultCallback.m_closestHitFraction == btScalar(0.f)) ++ return false; ++ ++ btCollisionObject* collisionObject = (btCollisionObject*)proxy->m_clientObject; ++ ++ //only perform raycast if filterMask matches ++ if(m_resultCallback.needsCollision(collisionObject->getBroadphaseHandle())) ++ { ++ //RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject(); ++ //btVector3 collisionObjectAabbMin,collisionObjectAabbMax; ++#if 0 ++#ifdef RECALCULATE_AABB ++ btVector3 collisionObjectAabbMin,collisionObjectAabbMax; ++ collisionObject->getCollisionShape()->getAabb(collisionObject->getWorldTransform(),collisionObjectAabbMin,collisionObjectAabbMax); ++#else ++ //getBroadphase()->getAabb(collisionObject->getBroadphaseHandle(),collisionObjectAabbMin,collisionObjectAabbMax); ++ const btVector3& collisionObjectAabbMin = collisionObject->getBroadphaseHandle()->m_aabbMin; ++ const btVector3& collisionObjectAabbMax = collisionObject->getBroadphaseHandle()->m_aabbMax; ++#endif ++#endif ++ //btScalar hitLambda = m_resultCallback.m_closestHitFraction; ++ //culling already done by broadphase ++ //if (btRayAabb(m_rayFromWorld,m_rayToWorld,collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,m_hitNormal)) ++ { ++ m_world->rayTestSingle(m_rayFromTrans,m_rayToTrans, ++ collisionObject, ++ collisionObject->getCollisionShape(), ++ collisionObject->getWorldTransform(), ++ m_resultCallback); ++ } ++ } ++ return true; ++ } ++}; ++ ++void btSoftRigidDynamicsWorldMt::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) const ++{ ++ BT_PROFILE("rayTest"); ++ /// use the broadphase to accelerate the search for objects, based on their aabb ++ /// and for each object with ray-aabb overlap, perform an exact ray test ++ btSoftSingleRayCallback rayCB(rayFromWorld,rayToWorld,this,resultCallback); ++ ++#ifndef USE_BRUTEFORCE_RAYBROADPHASE ++ m_broadphasePairCache->rayTest(rayFromWorld,rayToWorld,rayCB); ++#else ++ for (int i=0;igetNumCollisionObjects();i++) ++ { ++ rayCB.process(m_collisionObjects[i]->getBroadphaseHandle()); ++ } ++#endif //USE_BRUTEFORCE_RAYBROADPHASE ++ ++} ++ ++ ++void btSoftRigidDynamicsWorldMt::rayTestSingle(const btTransform& rayFromTrans,const btTransform& rayToTrans, ++ btCollisionObject* collisionObject, ++ const btCollisionShape* collisionShape, ++ const btTransform& colObjWorldTransform, ++ RayResultCallback& resultCallback) ++{ ++ if (collisionShape->isSoftBody()) { ++ btSoftBody* softBody = btSoftBody::upcast(collisionObject); ++ if (softBody) { ++ btSoftBody::sRayCast softResult; ++ if (softBody->rayTest(rayFromTrans.getOrigin(), rayToTrans.getOrigin(), softResult)) ++ { ++ ++ if (softResult.fraction<= resultCallback.m_closestHitFraction) ++ { ++ ++ btCollisionWorld::LocalShapeInfo shapeInfo; ++ shapeInfo.m_shapePart = 0; ++ shapeInfo.m_triangleIndex = softResult.index; ++ // get the normal ++ btVector3 rayDir = rayToTrans.getOrigin() - rayFromTrans.getOrigin(); ++ btVector3 normal=-rayDir; ++ normal.normalize(); ++ ++ if (softResult.feature == btSoftBody::eFeature::Face) ++ { ++ normal = softBody->m_faces[softResult.index].m_normal; ++ if (normal.dot(rayDir) > 0) { ++ // normal always point toward origin of the ray ++ normal = -normal; ++ } ++ } ++ ++ btCollisionWorld::LocalRayResult rayResult ++ (collisionObject, ++ &shapeInfo, ++ normal, ++ softResult.fraction); ++ bool normalInWorldSpace = true; ++ resultCallback.addSingleResult(rayResult,normalInWorldSpace); ++ } ++ } ++ } ++ } ++ else { ++ btCollisionWorld::rayTestSingle(rayFromTrans,rayToTrans,collisionObject,collisionShape,colObjWorldTransform,resultCallback); ++ } ++} ++ ++ ++void btSoftRigidDynamicsWorldMt::serializeSoftBodies(btSerializer* serializer) ++{ ++ int i; ++ //serialize all collision objects ++ for (i=0;igetInternalType() & btCollisionObject::CO_SOFT_BODY) ++ { ++ int len = colObj->calculateSerializeBufferSize(); ++ btChunk* chunk = serializer->allocate(len,1); ++ const char* structType = colObj->serialize(chunk->m_oldPtr, serializer); ++ serializer->finalizeChunk(chunk,structType,BT_SOFTBODY_CODE,colObj); ++ } ++ } ++ ++} ++ ++void btSoftRigidDynamicsWorldMt::serialize(btSerializer* serializer) ++{ ++ ++ serializer->startSerialization(); ++ ++ serializeDynamicsWorldInfo( serializer); ++ ++ serializeSoftBodies(serializer); ++ ++ serializeRigidBodies(serializer); ++ ++ serializeCollisionObjects(serializer); ++ ++ serializer->finishSerialization(); ++} ++ ++ +diff --git a/extern/bullet/src/BulletSoftBody/btSoftRigidDynamicsWorldMt.h b/extern/bullet/src/BulletSoftBody/btSoftRigidDynamicsWorldMt.h +new file mode 100644 +index 00000000000..be3b98c3361 +--- /dev/null ++++ b/extern/bullet/src/BulletSoftBody/btSoftRigidDynamicsWorldMt.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 BT_SOFT_RIGID_DYNAMICS_WORLD_H ++#define BT_SOFT_RIGID_DYNAMICS_WORLD_H ++ ++#include "BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h" ++#include "btSoftBody.h" ++ ++typedef btAlignedObjectArray btSoftBodyArray; ++ ++class btSoftBodySolver; ++ ++class btSoftRigidDynamicsWorldMt : public btDiscreteDynamicsWorldMt ++{ ++ ++ btSoftBodyArray m_softBodies; ++ int m_drawFlags; ++ bool m_drawNodeTree; ++ bool m_drawFaceTree; ++ bool m_drawClusterTree; ++ btSoftBodyWorldInfo m_sbi; ++ ///Solver classes that encapsulate multiple soft bodies for solving ++ btSoftBodySolver *m_softBodySolver; ++ bool m_ownsSolver; ++ ++protected: ++ ++ virtual void predictUnconstraintMotion(btScalar timeStep); ++ ++ virtual void internalSingleStepSimulation( btScalar timeStep); ++ ++ void solveSoftBodiesConstraints( btScalar timeStep ); ++ ++ void serializeSoftBodies(btSerializer* serializer); ++ ++public: ++ ++ btSoftRigidDynamicsWorldMt(btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btConstraintSolverPoolMt* constraintSolver, btCollisionConfiguration* collisionConfiguration, btSoftBodySolver *softBodySolver = 0 ); ++ ++ virtual ~btSoftRigidDynamicsWorldMt(); ++ ++ virtual void debugDrawWorld(); ++ ++ void addSoftBody(btSoftBody* body, int collisionFilterGroup=btBroadphaseProxy::DefaultFilter, int collisionFilterMask=btBroadphaseProxy::AllFilter); ++ ++ void removeSoftBody(btSoftBody* body); ++ ++ ///removeCollisionObject will first check if it is a rigid body, if so call removeRigidBody otherwise call btDiscreteDynamicsWorld::removeCollisionObject ++ virtual void removeCollisionObject(btCollisionObject* collisionObject); ++ ++ int getDrawFlags() const { return(m_drawFlags); } ++ void setDrawFlags(int f) { m_drawFlags=f; } ++ ++ btSoftBodyWorldInfo& getWorldInfo() ++ { ++ return m_sbi; ++ } ++ const btSoftBodyWorldInfo& getWorldInfo() const ++ { ++ return m_sbi; ++ } ++ ++ virtual btDynamicsWorldType getWorldType() const ++ { ++ return BT_SOFT_RIGID_DYNAMICS_WORLD; ++ } ++ ++ btSoftBodyArray& getSoftBodyArray() ++ { ++ return m_softBodies; ++ } ++ ++ const btSoftBodyArray& getSoftBodyArray() const ++ { ++ return m_softBodies; ++ } ++ ++ ++ virtual void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) const; ++ ++ /// 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); ++ ++ virtual void serialize(btSerializer* serializer); ++ ++}; ++ ++#endif //BT_SOFT_RIGID_DYNAMICS_WORLD_H +-- +2.18.0 + diff --git a/extern/bullet2/src/Bullet-C-Api.h b/extern/bullet/src/Bullet-C-Api.h similarity index 100% rename from extern/bullet2/src/Bullet-C-Api.h rename to extern/bullet/src/Bullet-C-Api.h diff --git a/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/b3BroadphaseCallback.h b/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/b3BroadphaseCallback.h new file mode 100644 index 000000000000..1bc56cf80a5a --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/b3BroadphaseCallback.h @@ -0,0 +1,40 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org + +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 B3_BROADPHASE_CALLBACK_H +#define B3_BROADPHASE_CALLBACK_H + +#include "Bullet3Common/b3Vector3.h" +struct b3BroadphaseProxy; + + +struct b3BroadphaseAabbCallback +{ + virtual ~b3BroadphaseAabbCallback() {} + virtual bool process(const b3BroadphaseProxy* proxy) = 0; +}; + + +struct b3BroadphaseRayCallback : public b3BroadphaseAabbCallback +{ + ///added some cached data to accelerate ray-AABB tests + b3Vector3 m_rayDirectionInverse; + unsigned int m_signs[3]; + b3Scalar m_lambda_max; + + virtual ~b3BroadphaseRayCallback() {} +}; + +#endif //B3_BROADPHASE_CALLBACK_H diff --git a/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/b3DynamicBvh.cpp b/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/b3DynamicBvh.cpp new file mode 100644 index 000000000000..0f04efe3311c --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/b3DynamicBvh.cpp @@ -0,0 +1,1325 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org + +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. +*/ +///b3DynamicBvh implementation by Nathanael Presson + +#include "b3DynamicBvh.h" + +// +typedef b3AlignedObjectArray b3NodeArray; +typedef b3AlignedObjectArray b3ConstNodeArray; + +// +struct b3DbvtNodeEnumerator : b3DynamicBvh::ICollide +{ + b3ConstNodeArray nodes; + void Process(const b3DbvtNode* n) { nodes.push_back(n); } +}; + +// +static B3_DBVT_INLINE int b3IndexOf(const b3DbvtNode* node) +{ + return(node->parent->childs[1]==node); +} + +// +static B3_DBVT_INLINE b3DbvtVolume b3Merge( const b3DbvtVolume& a, + const b3DbvtVolume& b) +{ +#if (B3_DBVT_MERGE_IMPL==B3_DBVT_IMPL_SSE) + B3_ATTRIBUTE_ALIGNED16(char locals[sizeof(b3DbvtAabbMm)]); + b3DbvtVolume& res=*(b3DbvtVolume*)locals; +#else + b3DbvtVolume res; +#endif + b3Merge(a,b,res); + return(res); +} + +// volume+edge lengths +static B3_DBVT_INLINE b3Scalar b3Size(const b3DbvtVolume& a) +{ + const b3Vector3 edges=a.Lengths(); + return( edges.x*edges.y*edges.z+ + edges.x+edges.y+edges.z); +} + +// +static void b3GetMaxDepth(const b3DbvtNode* node,int depth,int& maxdepth) +{ + if(node->isinternal()) + { + b3GetMaxDepth(node->childs[0],depth+1,maxdepth); + b3GetMaxDepth(node->childs[1],depth+1,maxdepth); + } else maxdepth=b3Max(maxdepth,depth); +} + +// +static B3_DBVT_INLINE void b3DeleteNode( b3DynamicBvh* pdbvt, + b3DbvtNode* node) +{ + b3AlignedFree(pdbvt->m_free); + pdbvt->m_free=node; +} + +// +static void b3RecurseDeleteNode( b3DynamicBvh* pdbvt, + b3DbvtNode* node) +{ + if(!node->isleaf()) + { + b3RecurseDeleteNode(pdbvt,node->childs[0]); + b3RecurseDeleteNode(pdbvt,node->childs[1]); + } + if(node==pdbvt->m_root) pdbvt->m_root=0; + b3DeleteNode(pdbvt,node); +} + +// +static B3_DBVT_INLINE b3DbvtNode* b3CreateNode( b3DynamicBvh* pdbvt, + b3DbvtNode* parent, + void* data) +{ + b3DbvtNode* node; + if(pdbvt->m_free) + { node=pdbvt->m_free;pdbvt->m_free=0; } + else + { node=new(b3AlignedAlloc(sizeof(b3DbvtNode),16)) b3DbvtNode(); } + node->parent = parent; + node->data = data; + node->childs[1] = 0; + return(node); +} + +// +static B3_DBVT_INLINE b3DbvtNode* b3CreateNode( b3DynamicBvh* pdbvt, + b3DbvtNode* parent, + const b3DbvtVolume& volume, + void* data) +{ + b3DbvtNode* node=b3CreateNode(pdbvt,parent,data); + node->volume=volume; + return(node); +} + +// +static B3_DBVT_INLINE b3DbvtNode* b3CreateNode( b3DynamicBvh* pdbvt, + b3DbvtNode* parent, + const b3DbvtVolume& volume0, + const b3DbvtVolume& volume1, + void* data) +{ + b3DbvtNode* node=b3CreateNode(pdbvt,parent,data); + b3Merge(volume0,volume1,node->volume); + return(node); +} + +// +static void b3InsertLeaf( b3DynamicBvh* pdbvt, + b3DbvtNode* root, + b3DbvtNode* leaf) +{ + if(!pdbvt->m_root) + { + pdbvt->m_root = leaf; + leaf->parent = 0; + } + else + { + if(!root->isleaf()) + { + do { + root=root->childs[b3Select( leaf->volume, + root->childs[0]->volume, + root->childs[1]->volume)]; + } while(!root->isleaf()); + } + b3DbvtNode* prev=root->parent; + b3DbvtNode* node=b3CreateNode(pdbvt,prev,leaf->volume,root->volume,0); + if(prev) + { + prev->childs[b3IndexOf(root)] = node; + node->childs[0] = root;root->parent=node; + node->childs[1] = leaf;leaf->parent=node; + do { + if(!prev->volume.Contain(node->volume)) + b3Merge(prev->childs[0]->volume,prev->childs[1]->volume,prev->volume); + else + break; + node=prev; + } while(0!=(prev=node->parent)); + } + else + { + node->childs[0] = root;root->parent=node; + node->childs[1] = leaf;leaf->parent=node; + pdbvt->m_root = node; + } + } +} + +// +static b3DbvtNode* b3RemoveLeaf( b3DynamicBvh* pdbvt, + b3DbvtNode* leaf) +{ + if(leaf==pdbvt->m_root) + { + pdbvt->m_root=0; + return(0); + } + else + { + b3DbvtNode* parent=leaf->parent; + b3DbvtNode* prev=parent->parent; + b3DbvtNode* sibling=parent->childs[1-b3IndexOf(leaf)]; + if(prev) + { + prev->childs[b3IndexOf(parent)]=sibling; + sibling->parent=prev; + b3DeleteNode(pdbvt,parent); + while(prev) + { + const b3DbvtVolume pb=prev->volume; + b3Merge(prev->childs[0]->volume,prev->childs[1]->volume,prev->volume); + if(b3NotEqual(pb,prev->volume)) + { + prev=prev->parent; + } else break; + } + return(prev?prev:pdbvt->m_root); + } + else + { + pdbvt->m_root=sibling; + sibling->parent=0; + b3DeleteNode(pdbvt,parent); + return(pdbvt->m_root); + } + } +} + +// +static void b3FetchLeaves(b3DynamicBvh* pdbvt, + b3DbvtNode* root, + b3NodeArray& leaves, + int depth=-1) +{ + if(root->isinternal()&&depth) + { + b3FetchLeaves(pdbvt,root->childs[0],leaves,depth-1); + b3FetchLeaves(pdbvt,root->childs[1],leaves,depth-1); + b3DeleteNode(pdbvt,root); + } + else + { + leaves.push_back(root); + } +} + +static bool b3LeftOfAxis( const b3DbvtNode* node, + const b3Vector3& org, + const b3Vector3& axis) +{ + return b3Dot(axis,node->volume.Center()-org) <= 0; +} + +// Partitions leaves such that leaves[0, n) are on the +// left of axis, and leaves[n, count) are on the right +// of axis. returns N. +static int b3Split( b3DbvtNode** leaves, + int count, + const b3Vector3& org, + const b3Vector3& axis) +{ + int begin=0; + int end=count; + for(;;) + { + while(begin!=end && b3LeftOfAxis(leaves[begin],org,axis)) + { + ++begin; + } + + if(begin==end) + { + break; + } + + while(begin!=end && !b3LeftOfAxis(leaves[end-1],org,axis)) + { + --end; + } + + if(begin==end) + { + break; + } + + // swap out of place nodes + --end; + b3DbvtNode* temp=leaves[begin]; + leaves[begin]=leaves[end]; + leaves[end]=temp; + ++begin; + } + + return begin; +} + +// +static b3DbvtVolume b3Bounds( b3DbvtNode** leaves, + int count) +{ +#if B3_DBVT_MERGE_IMPL==B3_DBVT_IMPL_SSE + B3_ATTRIBUTE_ALIGNED16(char locals[sizeof(b3DbvtVolume)]); + b3DbvtVolume& volume=*(b3DbvtVolume*)locals; + volume=leaves[0]->volume; +#else + b3DbvtVolume volume=leaves[0]->volume; +#endif + for(int i=1,ni=count;ivolume,volume); + } + return(volume); +} + +// +static void b3BottomUp( b3DynamicBvh* pdbvt, + b3DbvtNode** leaves, + int count) +{ + while(count>1) + { + b3Scalar minsize=B3_INFINITY; + int minidx[2]={-1,-1}; + for(int i=0;ivolume,leaves[j]->volume)); + if(szvolume,n[1]->volume,0); + p->childs[0] = n[0]; + p->childs[1] = n[1]; + n[0]->parent = p; + n[1]->parent = p; + leaves[minidx[0]] = p; + leaves[minidx[1]] = leaves[count-1]; + --count; + } +} + +// +static b3DbvtNode* b3TopDown(b3DynamicBvh* pdbvt, + b3DbvtNode** leaves, + int count, + int bu_treshold) +{ + static const b3Vector3 axis[]={b3MakeVector3(1,0,0), + b3MakeVector3(0,1,0), + b3MakeVector3(0,0,1)}; + b3Assert(bu_treshold>1); + if(count>1) + { + if(count>bu_treshold) + { + const b3DbvtVolume vol=b3Bounds(leaves,count); + const b3Vector3 org=vol.Center(); + int partition; + int bestaxis=-1; + int bestmidp=count; + int splitcount[3][2]={{0,0},{0,0},{0,0}}; + int i; + for( i=0;ivolume.Center()-org; + for(int j=0;j<3;++j) + { + ++splitcount[j][b3Dot(x,axis[j])>0?1:0]; + } + } + for( i=0;i<3;++i) + { + if((splitcount[i][0]>0)&&(splitcount[i][1]>0)) + { + const int midp=(int)b3Fabs(b3Scalar(splitcount[i][0]-splitcount[i][1])); + if(midp=0) + { + partition=b3Split(leaves,count,org,axis[bestaxis]); + b3Assert(partition!=0 && partition!=count); + } + else + { + partition=count/2+1; + } + b3DbvtNode* node=b3CreateNode(pdbvt,0,vol,0); + node->childs[0]=b3TopDown(pdbvt,&leaves[0],partition,bu_treshold); + node->childs[1]=b3TopDown(pdbvt,&leaves[partition],count-partition,bu_treshold); + node->childs[0]->parent=node; + node->childs[1]->parent=node; + return(node); + } + else + { + b3BottomUp(pdbvt,leaves,count); + return(leaves[0]); + } + } + return(leaves[0]); +} + +// +static B3_DBVT_INLINE b3DbvtNode* b3Sort(b3DbvtNode* n,b3DbvtNode*& r) +{ + b3DbvtNode* p=n->parent; + b3Assert(n->isinternal()); + if(p>n) + { + const int i=b3IndexOf(n); + const int j=1-i; + b3DbvtNode* s=p->childs[j]; + b3DbvtNode* q=p->parent; + b3Assert(n==p->childs[i]); + if(q) q->childs[b3IndexOf(p)]=n; else r=n; + s->parent=n; + p->parent=n; + n->parent=q; + p->childs[0]=n->childs[0]; + p->childs[1]=n->childs[1]; + n->childs[0]->parent=p; + n->childs[1]->parent=p; + n->childs[i]=p; + n->childs[j]=s; + b3Swap(p->volume,n->volume); + return(p); + } + return(n); +} + +#if 0 +static B3_DBVT_INLINE b3DbvtNode* walkup(b3DbvtNode* n,int count) +{ + while(n&&(count--)) n=n->parent; + return(n); +} +#endif + +// +// Api +// + +// +b3DynamicBvh::b3DynamicBvh() +{ + m_root = 0; + m_free = 0; + m_lkhd = -1; + m_leaves = 0; + m_opath = 0; +} + +// +b3DynamicBvh::~b3DynamicBvh() +{ + clear(); +} + +// +void b3DynamicBvh::clear() +{ + if(m_root) + b3RecurseDeleteNode(this,m_root); + b3AlignedFree(m_free); + m_free=0; + m_lkhd = -1; + m_stkStack.clear(); + m_opath = 0; + +} + +// +void b3DynamicBvh::optimizeBottomUp() +{ + if(m_root) + { + b3NodeArray leaves; + leaves.reserve(m_leaves); + b3FetchLeaves(this,m_root,leaves); + b3BottomUp(this,&leaves[0],leaves.size()); + m_root=leaves[0]; + } +} + +// +void b3DynamicBvh::optimizeTopDown(int bu_treshold) +{ + if(m_root) + { + b3NodeArray leaves; + leaves.reserve(m_leaves); + b3FetchLeaves(this,m_root,leaves); + m_root=b3TopDown(this,&leaves[0],leaves.size(),bu_treshold); + } +} + +// +void b3DynamicBvh::optimizeIncremental(int passes) +{ + if(passes<0) passes=m_leaves; + if(m_root&&(passes>0)) + { + do { + b3DbvtNode* node=m_root; + unsigned bit=0; + while(node->isinternal()) + { + node=b3Sort(node,m_root)->childs[(m_opath>>bit)&1]; + bit=(bit+1)&(sizeof(unsigned)*8-1); + } + update(node); + ++m_opath; + } while(--passes); + } +} + +// +b3DbvtNode* b3DynamicBvh::insert(const b3DbvtVolume& volume,void* data) +{ + b3DbvtNode* leaf=b3CreateNode(this,0,volume,data); + b3InsertLeaf(this,m_root,leaf); + ++m_leaves; + return(leaf); +} + +// +void b3DynamicBvh::update(b3DbvtNode* leaf,int lookahead) +{ + b3DbvtNode* root=b3RemoveLeaf(this,leaf); + if(root) + { + if(lookahead>=0) + { + for(int i=0;(iparent;++i) + { + root=root->parent; + } + } else root=m_root; + } + b3InsertLeaf(this,root,leaf); +} + +// +void b3DynamicBvh::update(b3DbvtNode* leaf,b3DbvtVolume& volume) +{ + b3DbvtNode* root=b3RemoveLeaf(this,leaf); + if(root) + { + if(m_lkhd>=0) + { + for(int i=0;(iparent;++i) + { + root=root->parent; + } + } else root=m_root; + } + leaf->volume=volume; + b3InsertLeaf(this,root,leaf); +} + +// +bool b3DynamicBvh::update(b3DbvtNode* leaf,b3DbvtVolume& volume,const b3Vector3& velocity,b3Scalar margin) +{ + if(leaf->volume.Contain(volume)) return(false); + volume.Expand(b3MakeVector3(margin,margin,margin)); + volume.SignedExpand(velocity); + update(leaf,volume); + return(true); +} + +// +bool b3DynamicBvh::update(b3DbvtNode* leaf,b3DbvtVolume& volume,const b3Vector3& velocity) +{ + if(leaf->volume.Contain(volume)) return(false); + volume.SignedExpand(velocity); + update(leaf,volume); + return(true); +} + +// +bool b3DynamicBvh::update(b3DbvtNode* leaf,b3DbvtVolume& volume,b3Scalar margin) +{ + if(leaf->volume.Contain(volume)) return(false); + volume.Expand(b3MakeVector3(margin,margin,margin)); + update(leaf,volume); + return(true); +} + +// +void b3DynamicBvh::remove(b3DbvtNode* leaf) +{ + b3RemoveLeaf(this,leaf); + b3DeleteNode(this,leaf); + --m_leaves; +} + +// +void b3DynamicBvh::write(IWriter* iwriter) const +{ + b3DbvtNodeEnumerator nodes; + nodes.nodes.reserve(m_leaves*2); + enumNodes(m_root,nodes); + iwriter->Prepare(m_root,nodes.nodes.size()); + for(int i=0;iparent) p=nodes.nodes.findLinearSearch(n->parent); + if(n->isinternal()) + { + const int c0=nodes.nodes.findLinearSearch(n->childs[0]); + const int c1=nodes.nodes.findLinearSearch(n->childs[1]); + iwriter->WriteNode(n,i,p,c0,c1); + } + else + { + iwriter->WriteLeaf(n,i,p); + } + } +} + +// +void b3DynamicBvh::clone(b3DynamicBvh& dest,IClone* iclone) const +{ + dest.clear(); + if(m_root!=0) + { + b3AlignedObjectArray stack; + stack.reserve(m_leaves); + stack.push_back(sStkCLN(m_root,0)); + do { + const int i=stack.size()-1; + const sStkCLN e=stack[i]; + b3DbvtNode* n=b3CreateNode(&dest,e.parent,e.node->volume,e.node->data); + stack.pop_back(); + if(e.parent!=0) + e.parent->childs[i&1]=n; + else + dest.m_root=n; + if(e.node->isinternal()) + { + stack.push_back(sStkCLN(e.node->childs[0],n)); + stack.push_back(sStkCLN(e.node->childs[1],n)); + } + else + { + iclone->CloneLeaf(n); + } + } while(stack.size()>0); + } +} + +// +int b3DynamicBvh::maxdepth(const b3DbvtNode* node) +{ + int depth=0; + if(node) b3GetMaxDepth(node,1,depth); + return(depth); +} + +// +int b3DynamicBvh::countLeaves(const b3DbvtNode* node) +{ + if(node->isinternal()) + return(countLeaves(node->childs[0])+countLeaves(node->childs[1])); + else + return(1); +} + +// +void b3DynamicBvh::extractLeaves(const b3DbvtNode* node,b3AlignedObjectArray& leaves) +{ + if(node->isinternal()) + { + extractLeaves(node->childs[0],leaves); + extractLeaves(node->childs[1],leaves); + } + else + { + leaves.push_back(node); + } +} + +// +#if B3_DBVT_ENABLE_BENCHMARK + +#include +#include + + +/* +q6600,2.4ghz + +/Ox /Ob2 /Oi /Ot /I "." /I "..\.." /I "..\..\src" /D "NDEBUG" /D "_LIB" /D "_WINDOWS" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "WIN32" +/GF /FD /MT /GS- /Gy /arch:SSE2 /Zc:wchar_t- /Fp"..\..\out\release8\build\libbulletcollision\libbulletcollision.pch" +/Fo"..\..\out\release8\build\libbulletcollision\\" +/Fd"..\..\out\release8\build\libbulletcollision\bulletcollision.pdb" +/W3 /nologo /c /Wp64 /Zi /errorReport:prompt + +Benchmarking dbvt... +World scale: 100.000000 +Extents base: 1.000000 +Extents range: 4.000000 +Leaves: 8192 +sizeof(b3DbvtVolume): 32 bytes +sizeof(b3DbvtNode): 44 bytes +[1] b3DbvtVolume intersections: 3499 ms (-1%) +[2] b3DbvtVolume merges: 1934 ms (0%) +[3] b3DynamicBvh::collideTT: 5485 ms (-21%) +[4] b3DynamicBvh::collideTT self: 2814 ms (-20%) +[5] b3DynamicBvh::collideTT xform: 7379 ms (-1%) +[6] b3DynamicBvh::collideTT xform,self: 7270 ms (-2%) +[7] b3DynamicBvh::rayTest: 6314 ms (0%),(332143 r/s) +[8] insert/remove: 2093 ms (0%),(1001983 ir/s) +[9] updates (teleport): 1879 ms (-3%),(1116100 u/s) +[10] updates (jitter): 1244 ms (-4%),(1685813 u/s) +[11] optimize (incremental): 2514 ms (0%),(1668000 o/s) +[12] b3DbvtVolume notequal: 3659 ms (0%) +[13] culling(OCL+fullsort): 2218 ms (0%),(461 t/s) +[14] culling(OCL+qsort): 3688 ms (5%),(2221 t/s) +[15] culling(KDOP+qsort): 1139 ms (-1%),(7192 t/s) +[16] insert/remove batch(256): 5092 ms (0%),(823704 bir/s) +[17] b3DbvtVolume select: 3419 ms (0%) +*/ + +struct b3DbvtBenchmark +{ + struct NilPolicy : b3DynamicBvh::ICollide + { + NilPolicy() : m_pcount(0),m_depth(-B3_INFINITY),m_checksort(true) {} + void Process(const b3DbvtNode*,const b3DbvtNode*) { ++m_pcount; } + void Process(const b3DbvtNode*) { ++m_pcount; } + void Process(const b3DbvtNode*,b3Scalar depth) + { + ++m_pcount; + if(m_checksort) + { if(depth>=m_depth) m_depth=depth; else printf("wrong depth: %f (should be >= %f)\r\n",depth,m_depth); } + } + int m_pcount; + b3Scalar m_depth; + bool m_checksort; + }; + struct P14 : b3DynamicBvh::ICollide + { + struct Node + { + const b3DbvtNode* leaf; + b3Scalar depth; + }; + void Process(const b3DbvtNode* leaf,b3Scalar depth) + { + Node n; + n.leaf = leaf; + n.depth = depth; + } + static int sortfnc(const Node& a,const Node& b) + { + if(a.depthb.depth) return(-1); + return(0); + } + b3AlignedObjectArray m_nodes; + }; + struct P15 : b3DynamicBvh::ICollide + { + struct Node + { + const b3DbvtNode* leaf; + b3Scalar depth; + }; + void Process(const b3DbvtNode* leaf) + { + Node n; + n.leaf = leaf; + n.depth = dot(leaf->volume.Center(),m_axis); + } + static int sortfnc(const Node& a,const Node& b) + { + if(a.depthb.depth) return(-1); + return(0); + } + b3AlignedObjectArray m_nodes; + b3Vector3 m_axis; + }; + static b3Scalar RandUnit() + { + return(rand()/(b3Scalar)RAND_MAX); + } + static b3Vector3 RandVector3() + { + return(b3Vector3(RandUnit(),RandUnit(),RandUnit())); + } + static b3Vector3 RandVector3(b3Scalar cs) + { + return(RandVector3()*cs-b3Vector3(cs,cs,cs)/2); + } + static b3DbvtVolume RandVolume(b3Scalar cs,b3Scalar eb,b3Scalar es) + { + return(b3DbvtVolume::FromCE(RandVector3(cs),b3Vector3(eb,eb,eb)+RandVector3()*es)); + } + static b3Transform RandTransform(b3Scalar cs) + { + b3Transform t; + t.setOrigin(RandVector3(cs)); + t.setRotation(b3Quaternion(RandUnit()*B3_PI*2,RandUnit()*B3_PI*2,RandUnit()*B3_PI*2).normalized()); + return(t); + } + static void RandTree(b3Scalar cs,b3Scalar eb,b3Scalar es,int leaves,b3DynamicBvh& dbvt) + { + dbvt.clear(); + for(int i=0;i volumes; + b3AlignedObjectArray results; + volumes.resize(cfgLeaves); + results.resize(cfgLeaves); + for(int i=0;i volumes; + b3AlignedObjectArray results; + volumes.resize(cfgLeaves); + results.resize(cfgLeaves); + for(int i=0;i transforms; + b3DbvtBenchmark::NilPolicy policy; + transforms.resize(cfgBenchmark5_Iterations); + for(int i=0;i transforms; + b3DbvtBenchmark::NilPolicy policy; + transforms.resize(cfgBenchmark6_Iterations); + for(int i=0;i rayorg; + b3AlignedObjectArray raydir; + b3DbvtBenchmark::NilPolicy policy; + rayorg.resize(cfgBenchmark7_Iterations); + raydir.resize(cfgBenchmark7_Iterations); + for(int i=0;i leaves; + b3DbvtBenchmark::RandTree(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale,cfgLeaves,dbvt); + dbvt.optimizeTopDown(); + dbvt.extractLeaves(dbvt.m_root,leaves); + printf("[9] updates (teleport): "); + wallclock.reset(); + for(int i=0;i(leaves[rand()%cfgLeaves]), + b3DbvtBenchmark::RandVolume(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale)); + } + } + const int time=(int)wallclock.getTimeMilliseconds(); + const int up=cfgBenchmark9_Passes*cfgBenchmark9_Iterations; + printf("%u ms (%i%%),(%u u/s)\r\n",time,(time-cfgBenchmark9_Reference)*100/time,up*1000/time); + } + if(cfgBenchmark10_Enable) + {// Benchmark 10 + srand(380843); + b3DynamicBvh dbvt; + b3AlignedObjectArray leaves; + b3AlignedObjectArray vectors; + vectors.resize(cfgBenchmark10_Iterations); + for(int i=0;i(leaves[rand()%cfgLeaves]); + b3DbvtVolume v=b3DbvtVolume::FromMM(l->volume.Mins()+d,l->volume.Maxs()+d); + dbvt.update(l,v); + } + } + const int time=(int)wallclock.getTimeMilliseconds(); + const int up=cfgBenchmark10_Passes*cfgBenchmark10_Iterations; + printf("%u ms (%i%%),(%u u/s)\r\n",time,(time-cfgBenchmark10_Reference)*100/time,up*1000/time); + } + if(cfgBenchmark11_Enable) + {// Benchmark 11 + srand(380843); + b3DynamicBvh dbvt; + b3DbvtBenchmark::RandTree(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale,cfgLeaves,dbvt); + dbvt.optimizeTopDown(); + printf("[11] optimize (incremental): "); + wallclock.reset(); + for(int i=0;i volumes; + b3AlignedObjectArray results; + volumes.resize(cfgLeaves); + results.resize(cfgLeaves); + for(int i=0;i vectors; + b3DbvtBenchmark::NilPolicy policy; + vectors.resize(cfgBenchmark13_Iterations); + for(int i=0;i vectors; + b3DbvtBenchmark::P14 policy; + vectors.resize(cfgBenchmark14_Iterations); + for(int i=0;i vectors; + b3DbvtBenchmark::P15 policy; + vectors.resize(cfgBenchmark15_Iterations); + for(int i=0;i batch; + b3DbvtBenchmark::RandTree(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale,cfgLeaves,dbvt); + dbvt.optimizeTopDown(); + batch.reserve(cfgBenchmark16_BatchCount); + printf("[16] insert/remove batch(%u): ",cfgBenchmark16_BatchCount); + wallclock.reset(); + for(int i=0;i volumes; + b3AlignedObjectArray results; + b3AlignedObjectArray indices; + volumes.resize(cfgLeaves); + results.resize(cfgLeaves); + indices.resize(cfgLeaves); + for(int i=0;i= 1400) +#define B3_DBVT_USE_TEMPLATE 1 +#else +#define B3_DBVT_USE_TEMPLATE 0 +#endif +#else +#define B3_DBVT_USE_TEMPLATE 0 +#endif + +// Use only intrinsics instead of inline asm +#define B3_DBVT_USE_INTRINSIC_SSE 1 + +// Using memmov for collideOCL +#define B3_DBVT_USE_MEMMOVE 1 + +// Enable benchmarking code +#define B3_DBVT_ENABLE_BENCHMARK 0 + +// Inlining +#define B3_DBVT_INLINE B3_FORCE_INLINE + +// Specific methods implementation + +//SSE gives errors on a MSVC 7.1 +#if defined (B3_USE_SSE) //&& defined (_WIN32) +#define B3_DBVT_SELECT_IMPL B3_DBVT_IMPL_SSE +#define B3_DBVT_MERGE_IMPL B3_DBVT_IMPL_SSE +#define B3_DBVT_INT0_IMPL B3_DBVT_IMPL_SSE +#else +#define B3_DBVT_SELECT_IMPL B3_DBVT_IMPL_GENERIC +#define B3_DBVT_MERGE_IMPL B3_DBVT_IMPL_GENERIC +#define B3_DBVT_INT0_IMPL B3_DBVT_IMPL_GENERIC +#endif + +#if (B3_DBVT_SELECT_IMPL==B3_DBVT_IMPL_SSE)|| \ + (B3_DBVT_MERGE_IMPL==B3_DBVT_IMPL_SSE)|| \ + (B3_DBVT_INT0_IMPL==B3_DBVT_IMPL_SSE) +#include +#endif + +// +// Auto config and checks +// + +#if B3_DBVT_USE_TEMPLATE +#define B3_DBVT_VIRTUAL +#define B3_DBVT_VIRTUAL_DTOR(a) +#define B3_DBVT_PREFIX template +#define B3_DBVT_IPOLICY T& policy +#define B3_DBVT_CHECKTYPE static const ICollide& typechecker=*(T*)1;(void)typechecker; +#else +#define B3_DBVT_VIRTUAL_DTOR(a) virtual ~a() {} +#define B3_DBVT_VIRTUAL virtual +#define B3_DBVT_PREFIX +#define B3_DBVT_IPOLICY ICollide& policy +#define B3_DBVT_CHECKTYPE +#endif + +#if B3_DBVT_USE_MEMMOVE +#if !defined( __CELLOS_LV2__) && !defined(__MWERKS__) +#include +#endif +#include +#endif + +#ifndef B3_DBVT_USE_TEMPLATE +#error "B3_DBVT_USE_TEMPLATE undefined" +#endif + +#ifndef B3_DBVT_USE_MEMMOVE +#error "B3_DBVT_USE_MEMMOVE undefined" +#endif + +#ifndef B3_DBVT_ENABLE_BENCHMARK +#error "B3_DBVT_ENABLE_BENCHMARK undefined" +#endif + +#ifndef B3_DBVT_SELECT_IMPL +#error "B3_DBVT_SELECT_IMPL undefined" +#endif + +#ifndef B3_DBVT_MERGE_IMPL +#error "B3_DBVT_MERGE_IMPL undefined" +#endif + +#ifndef B3_DBVT_INT0_IMPL +#error "B3_DBVT_INT0_IMPL undefined" +#endif + +// +// Defaults volumes +// + +/* b3DbvtAabbMm */ +struct b3DbvtAabbMm +{ + B3_DBVT_INLINE b3Vector3 Center() const { return((mi+mx)/2); } + B3_DBVT_INLINE b3Vector3 Lengths() const { return(mx-mi); } + B3_DBVT_INLINE b3Vector3 Extents() const { return((mx-mi)/2); } + B3_DBVT_INLINE const b3Vector3& Mins() const { return(mi); } + B3_DBVT_INLINE const b3Vector3& Maxs() const { return(mx); } + static inline b3DbvtAabbMm FromCE(const b3Vector3& c,const b3Vector3& e); + static inline b3DbvtAabbMm FromCR(const b3Vector3& c,b3Scalar r); + static inline b3DbvtAabbMm FromMM(const b3Vector3& mi,const b3Vector3& mx); + static inline b3DbvtAabbMm FromPoints(const b3Vector3* pts,int n); + static inline b3DbvtAabbMm FromPoints(const b3Vector3** ppts,int n); + B3_DBVT_INLINE void Expand(const b3Vector3& e); + B3_DBVT_INLINE void SignedExpand(const b3Vector3& e); + B3_DBVT_INLINE bool Contain(const b3DbvtAabbMm& a) const; + B3_DBVT_INLINE int Classify(const b3Vector3& n,b3Scalar o,int s) const; + B3_DBVT_INLINE b3Scalar ProjectMinimum(const b3Vector3& v,unsigned signs) const; + B3_DBVT_INLINE friend bool b3Intersect( const b3DbvtAabbMm& a, + const b3DbvtAabbMm& b); + + B3_DBVT_INLINE friend bool b3Intersect( const b3DbvtAabbMm& a, + const b3Vector3& b); + + B3_DBVT_INLINE friend b3Scalar b3Proximity( const b3DbvtAabbMm& a, + const b3DbvtAabbMm& b); + B3_DBVT_INLINE friend int b3Select( const b3DbvtAabbMm& o, + const b3DbvtAabbMm& a, + const b3DbvtAabbMm& b); + B3_DBVT_INLINE friend void b3Merge( const b3DbvtAabbMm& a, + const b3DbvtAabbMm& b, + b3DbvtAabbMm& r); + B3_DBVT_INLINE friend bool b3NotEqual( const b3DbvtAabbMm& a, + const b3DbvtAabbMm& b); + + B3_DBVT_INLINE b3Vector3& tMins() { return(mi); } + B3_DBVT_INLINE b3Vector3& tMaxs() { return(mx); } + +private: + B3_DBVT_INLINE void AddSpan(const b3Vector3& d,b3Scalar& smi,b3Scalar& smx) const; +private: + b3Vector3 mi,mx; +}; + +// Types +typedef b3DbvtAabbMm b3DbvtVolume; + +/* b3DbvtNode */ +struct b3DbvtNode +{ + b3DbvtVolume volume; + b3DbvtNode* parent; + B3_DBVT_INLINE bool isleaf() const { return(childs[1]==0); } + B3_DBVT_INLINE bool isinternal() const { return(!isleaf()); } + union + { + b3DbvtNode* childs[2]; + void* data; + int dataAsInt; + }; +}; + +///The b3DynamicBvh class implements a fast dynamic bounding volume tree based on axis aligned bounding boxes (aabb tree). +///This b3DynamicBvh is used for soft body collision detection and for the b3DynamicBvhBroadphase. It has a fast insert, remove and update of nodes. +///Unlike the b3QuantizedBvh, nodes can be dynamically moved around, which allows for change in topology of the underlying data structure. +struct b3DynamicBvh +{ + /* Stack element */ + struct sStkNN + { + const b3DbvtNode* a; + const b3DbvtNode* b; + sStkNN() {} + sStkNN(const b3DbvtNode* na,const b3DbvtNode* nb) : a(na),b(nb) {} + }; + struct sStkNP + { + const b3DbvtNode* node; + int mask; + sStkNP(const b3DbvtNode* n,unsigned m) : node(n),mask(m) {} + }; + struct sStkNPS + { + const b3DbvtNode* node; + int mask; + b3Scalar value; + sStkNPS() {} + sStkNPS(const b3DbvtNode* n,unsigned m,b3Scalar v) : node(n),mask(m),value(v) {} + }; + struct sStkCLN + { + const b3DbvtNode* node; + b3DbvtNode* parent; + sStkCLN(const b3DbvtNode* n,b3DbvtNode* p) : node(n),parent(p) {} + }; + // Policies/Interfaces + + /* ICollide */ + struct ICollide + { + B3_DBVT_VIRTUAL_DTOR(ICollide) + B3_DBVT_VIRTUAL void Process(const b3DbvtNode*,const b3DbvtNode*) {} + B3_DBVT_VIRTUAL void Process(const b3DbvtNode*) {} + B3_DBVT_VIRTUAL void Process(const b3DbvtNode* n,b3Scalar) { Process(n); } + B3_DBVT_VIRTUAL bool Descent(const b3DbvtNode*) { return(true); } + B3_DBVT_VIRTUAL bool AllLeaves(const b3DbvtNode*) { return(true); } + }; + /* IWriter */ + struct IWriter + { + virtual ~IWriter() {} + virtual void Prepare(const b3DbvtNode* root,int numnodes)=0; + virtual void WriteNode(const b3DbvtNode*,int index,int parent,int child0,int child1)=0; + virtual void WriteLeaf(const b3DbvtNode*,int index,int parent)=0; + }; + /* IClone */ + struct IClone + { + virtual ~IClone() {} + virtual void CloneLeaf(b3DbvtNode*) {} + }; + + // Constants + enum { + B3_SIMPLE_STACKSIZE = 64, + B3_DOUBLE_STACKSIZE = B3_SIMPLE_STACKSIZE*2 + }; + + // Fields + b3DbvtNode* m_root; + b3DbvtNode* m_free; + int m_lkhd; + int m_leaves; + unsigned m_opath; + + + b3AlignedObjectArray m_stkStack; + mutable b3AlignedObjectArray m_rayTestStack; + + + // Methods + b3DynamicBvh(); + ~b3DynamicBvh(); + void clear(); + bool empty() const { return(0==m_root); } + void optimizeBottomUp(); + void optimizeTopDown(int bu_treshold=128); + void optimizeIncremental(int passes); + b3DbvtNode* insert(const b3DbvtVolume& box,void* data); + void update(b3DbvtNode* leaf,int lookahead=-1); + void update(b3DbvtNode* leaf,b3DbvtVolume& volume); + bool update(b3DbvtNode* leaf,b3DbvtVolume& volume,const b3Vector3& velocity,b3Scalar margin); + bool update(b3DbvtNode* leaf,b3DbvtVolume& volume,const b3Vector3& velocity); + bool update(b3DbvtNode* leaf,b3DbvtVolume& volume,b3Scalar margin); + void remove(b3DbvtNode* leaf); + void write(IWriter* iwriter) const; + void clone(b3DynamicBvh& dest,IClone* iclone=0) const; + static int maxdepth(const b3DbvtNode* node); + static int countLeaves(const b3DbvtNode* node); + static void extractLeaves(const b3DbvtNode* node,b3AlignedObjectArray& leaves); +#if B3_DBVT_ENABLE_BENCHMARK + static void benchmark(); +#else + static void benchmark(){} +#endif + // B3_DBVT_IPOLICY must support ICollide policy/interface + B3_DBVT_PREFIX + static void enumNodes( const b3DbvtNode* root, + B3_DBVT_IPOLICY); + B3_DBVT_PREFIX + static void enumLeaves( const b3DbvtNode* root, + B3_DBVT_IPOLICY); + B3_DBVT_PREFIX + void collideTT( const b3DbvtNode* root0, + const b3DbvtNode* root1, + B3_DBVT_IPOLICY); + + B3_DBVT_PREFIX + void collideTTpersistentStack( const b3DbvtNode* root0, + const b3DbvtNode* root1, + B3_DBVT_IPOLICY); +#if 0 + B3_DBVT_PREFIX + void collideTT( const b3DbvtNode* root0, + const b3DbvtNode* root1, + const b3Transform& xform, + B3_DBVT_IPOLICY); + B3_DBVT_PREFIX + void collideTT( const b3DbvtNode* root0, + const b3Transform& xform0, + const b3DbvtNode* root1, + const b3Transform& xform1, + B3_DBVT_IPOLICY); +#endif + + B3_DBVT_PREFIX + void collideTV( const b3DbvtNode* root, + const b3DbvtVolume& volume, + B3_DBVT_IPOLICY) const; + ///rayTest is a re-entrant ray test, and can be called in parallel as long as the b3AlignedAlloc is thread-safe (uses locking etc) + ///rayTest is slower than rayTestInternal, because it builds a local stack, using memory allocations, and it recomputes signs/rayDirectionInverses each time + B3_DBVT_PREFIX + static void rayTest( const b3DbvtNode* root, + const b3Vector3& rayFrom, + const b3Vector3& rayTo, + B3_DBVT_IPOLICY); + ///rayTestInternal is faster than rayTest, because it uses a persistent stack (to reduce dynamic memory allocations to a minimum) and it uses precomputed signs/rayInverseDirections + ///rayTestInternal is used by b3DynamicBvhBroadphase to accelerate world ray casts + B3_DBVT_PREFIX + void rayTestInternal( const b3DbvtNode* root, + const b3Vector3& rayFrom, + const b3Vector3& rayTo, + const b3Vector3& rayDirectionInverse, + unsigned int signs[3], + b3Scalar lambda_max, + const b3Vector3& aabbMin, + const b3Vector3& aabbMax, + B3_DBVT_IPOLICY) const; + + B3_DBVT_PREFIX + static void collideKDOP(const b3DbvtNode* root, + const b3Vector3* normals, + const b3Scalar* offsets, + int count, + B3_DBVT_IPOLICY); + B3_DBVT_PREFIX + static void collideOCL( const b3DbvtNode* root, + const b3Vector3* normals, + const b3Scalar* offsets, + const b3Vector3& sortaxis, + int count, + B3_DBVT_IPOLICY, + bool fullsort=true); + B3_DBVT_PREFIX + static void collideTU( const b3DbvtNode* root, + B3_DBVT_IPOLICY); + // Helpers + static B3_DBVT_INLINE int nearest(const int* i,const b3DynamicBvh::sStkNPS* a,b3Scalar v,int l,int h) + { + int m=0; + while(l>1; + if(a[i[m]].value>=v) l=m+1; else h=m; + } + return(h); + } + static B3_DBVT_INLINE int allocate( b3AlignedObjectArray& ifree, + b3AlignedObjectArray& stock, + const sStkNPS& value) + { + int i; + if(ifree.size()>0) + { i=ifree[ifree.size()-1];ifree.pop_back();stock[i]=value; } + else + { i=stock.size();stock.push_back(value); } + return(i); + } + // +private: + b3DynamicBvh(const b3DynamicBvh&) {} +}; + +// +// Inline's +// + +// +inline b3DbvtAabbMm b3DbvtAabbMm::FromCE(const b3Vector3& c,const b3Vector3& e) +{ + b3DbvtAabbMm box; + box.mi=c-e;box.mx=c+e; + return(box); +} + +// +inline b3DbvtAabbMm b3DbvtAabbMm::FromCR(const b3Vector3& c,b3Scalar r) +{ + return(FromCE(c,b3MakeVector3(r,r,r))); +} + +// +inline b3DbvtAabbMm b3DbvtAabbMm::FromMM(const b3Vector3& mi,const b3Vector3& mx) +{ + b3DbvtAabbMm box; + box.mi=mi;box.mx=mx; + return(box); +} + +// +inline b3DbvtAabbMm b3DbvtAabbMm::FromPoints(const b3Vector3* pts,int n) +{ + b3DbvtAabbMm box; + box.mi=box.mx=pts[0]; + for(int i=1;i0) mx.setX(mx.x+e[0]); else mi.setX(mi.x+e[0]); + if(e.y>0) mx.setY(mx.y+e[1]); else mi.setY(mi.y+e[1]); + if(e.z>0) mx.setZ(mx.z+e[2]); else mi.setZ(mi.z+e[2]); +} + +// +B3_DBVT_INLINE bool b3DbvtAabbMm::Contain(const b3DbvtAabbMm& a) const +{ + return( (mi.x<=a.mi.x)&& + (mi.y<=a.mi.y)&& + (mi.z<=a.mi.z)&& + (mx.x>=a.mx.x)&& + (mx.y>=a.mx.y)&& + (mx.z>=a.mx.z)); +} + +// +B3_DBVT_INLINE int b3DbvtAabbMm::Classify(const b3Vector3& n,b3Scalar o,int s) const +{ + b3Vector3 pi,px; + switch(s) + { + case (0+0+0): px=b3MakeVector3(mi.x,mi.y,mi.z); + pi=b3MakeVector3(mx.x,mx.y,mx.z);break; + case (1+0+0): px=b3MakeVector3(mx.x,mi.y,mi.z); + pi=b3MakeVector3(mi.x,mx.y,mx.z);break; + case (0+2+0): px=b3MakeVector3(mi.x,mx.y,mi.z); + pi=b3MakeVector3(mx.x,mi.y,mx.z);break; + case (1+2+0): px=b3MakeVector3(mx.x,mx.y,mi.z); + pi=b3MakeVector3(mi.x,mi.y,mx.z);break; + case (0+0+4): px=b3MakeVector3(mi.x,mi.y,mx.z); + pi=b3MakeVector3(mx.x,mx.y,mi.z);break; + case (1+0+4): px=b3MakeVector3(mx.x,mi.y,mx.z); + pi=b3MakeVector3(mi.x,mx.y,mi.z);break; + case (0+2+4): px=b3MakeVector3(mi.x,mx.y,mx.z); + pi=b3MakeVector3(mx.x,mi.y,mi.z);break; + case (1+2+4): px=b3MakeVector3(mx.x,mx.y,mx.z); + pi=b3MakeVector3(mi.x,mi.y,mi.z);break; + } + if((b3Dot(n,px)+o)<0) return(-1); + if((b3Dot(n,pi)+o)>=0) return(+1); + return(0); +} + +// +B3_DBVT_INLINE b3Scalar b3DbvtAabbMm::ProjectMinimum(const b3Vector3& v,unsigned signs) const +{ + const b3Vector3* b[]={&mx,&mi}; + const b3Vector3 p = b3MakeVector3( b[(signs>>0)&1]->x, + b[(signs>>1)&1]->y, + b[(signs>>2)&1]->z); + return(b3Dot(p,v)); +} + +// +B3_DBVT_INLINE void b3DbvtAabbMm::AddSpan(const b3Vector3& d,b3Scalar& smi,b3Scalar& smx) const +{ + for(int i=0;i<3;++i) + { + if(d[i]<0) + { smi+=mx[i]*d[i];smx+=mi[i]*d[i]; } + else + { smi+=mi[i]*d[i];smx+=mx[i]*d[i]; } + } +} + +// +B3_DBVT_INLINE bool b3Intersect( const b3DbvtAabbMm& a, + const b3DbvtAabbMm& b) +{ +#if B3_DBVT_INT0_IMPL == B3_DBVT_IMPL_SSE + const __m128 rt(_mm_or_ps( _mm_cmplt_ps(_mm_load_ps(b.mx),_mm_load_ps(a.mi)), + _mm_cmplt_ps(_mm_load_ps(a.mx),_mm_load_ps(b.mi)))); +#if defined (_WIN32) + const __int32* pu((const __int32*)&rt); +#else + const int* pu((const int*)&rt); +#endif + return((pu[0]|pu[1]|pu[2])==0); +#else + return( (a.mi.x<=b.mx.x)&& + (a.mx.x>=b.mi.x)&& + (a.mi.y<=b.mx.y)&& + (a.mx.y>=b.mi.y)&& + (a.mi.z<=b.mx.z)&& + (a.mx.z>=b.mi.z)); +#endif +} + + + +// +B3_DBVT_INLINE bool b3Intersect( const b3DbvtAabbMm& a, + const b3Vector3& b) +{ + return( (b.x>=a.mi.x)&& + (b.y>=a.mi.y)&& + (b.z>=a.mi.z)&& + (b.x<=a.mx.x)&& + (b.y<=a.mx.y)&& + (b.z<=a.mx.z)); +} + + + + + +////////////////////////////////////// + + +// +B3_DBVT_INLINE b3Scalar b3Proximity( const b3DbvtAabbMm& a, + const b3DbvtAabbMm& b) +{ + const b3Vector3 d=(a.mi+a.mx)-(b.mi+b.mx); + return(b3Fabs(d.x)+b3Fabs(d.y)+b3Fabs(d.z)); +} + + + +// +B3_DBVT_INLINE int b3Select( const b3DbvtAabbMm& o, + const b3DbvtAabbMm& a, + const b3DbvtAabbMm& b) +{ +#if B3_DBVT_SELECT_IMPL == B3_DBVT_IMPL_SSE + +#if defined (_WIN32) + static B3_ATTRIBUTE_ALIGNED16(const unsigned __int32) mask[]={0x7fffffff,0x7fffffff,0x7fffffff,0x7fffffff}; +#else + static B3_ATTRIBUTE_ALIGNED16(const unsigned int) mask[]={0x7fffffff,0x7fffffff,0x7fffffff,0x00000000 /*0x7fffffff*/}; +#endif + ///@todo: the intrinsic version is 11% slower +#if B3_DBVT_USE_INTRINSIC_SSE + + union b3SSEUnion ///NOTE: if we use more intrinsics, move b3SSEUnion into the LinearMath directory + { + __m128 ssereg; + float floats[4]; + int ints[4]; + }; + + __m128 omi(_mm_load_ps(o.mi)); + omi=_mm_add_ps(omi,_mm_load_ps(o.mx)); + __m128 ami(_mm_load_ps(a.mi)); + ami=_mm_add_ps(ami,_mm_load_ps(a.mx)); + ami=_mm_sub_ps(ami,omi); + ami=_mm_and_ps(ami,_mm_load_ps((const float*)mask)); + __m128 bmi(_mm_load_ps(b.mi)); + bmi=_mm_add_ps(bmi,_mm_load_ps(b.mx)); + bmi=_mm_sub_ps(bmi,omi); + bmi=_mm_and_ps(bmi,_mm_load_ps((const float*)mask)); + __m128 t0(_mm_movehl_ps(ami,ami)); + ami=_mm_add_ps(ami,t0); + ami=_mm_add_ss(ami,_mm_shuffle_ps(ami,ami,1)); + __m128 t1(_mm_movehl_ps(bmi,bmi)); + bmi=_mm_add_ps(bmi,t1); + bmi=_mm_add_ss(bmi,_mm_shuffle_ps(bmi,bmi,1)); + + b3SSEUnion tmp; + tmp.ssereg = _mm_cmple_ss(bmi,ami); + return tmp.ints[0]&1; + +#else + B3_ATTRIBUTE_ALIGNED16(__int32 r[1]); + __asm + { + mov eax,o + mov ecx,a + mov edx,b + movaps xmm0,[eax] + movaps xmm5,mask + addps xmm0,[eax+16] + movaps xmm1,[ecx] + movaps xmm2,[edx] + addps xmm1,[ecx+16] + addps xmm2,[edx+16] + subps xmm1,xmm0 + subps xmm2,xmm0 + andps xmm1,xmm5 + andps xmm2,xmm5 + movhlps xmm3,xmm1 + movhlps xmm4,xmm2 + addps xmm1,xmm3 + addps xmm2,xmm4 + pshufd xmm3,xmm1,1 + pshufd xmm4,xmm2,1 + addss xmm1,xmm3 + addss xmm2,xmm4 + cmpless xmm2,xmm1 + movss r,xmm2 + } + return(r[0]&1); +#endif +#else + return(b3Proximity(o,a)b.mx[i]) r.mx[i]=a.mx[i]; else r.mx[i]=b.mx[i]; + } +#endif +} + +// +B3_DBVT_INLINE bool b3NotEqual( const b3DbvtAabbMm& a, + const b3DbvtAabbMm& b) +{ + return( (a.mi.x!=b.mi.x)|| + (a.mi.y!=b.mi.y)|| + (a.mi.z!=b.mi.z)|| + (a.mx.x!=b.mx.x)|| + (a.mx.y!=b.mx.y)|| + (a.mx.z!=b.mx.z)); +} + +// +// Inline's +// + +// +B3_DBVT_PREFIX +inline void b3DynamicBvh::enumNodes( const b3DbvtNode* root, + B3_DBVT_IPOLICY) +{ + B3_DBVT_CHECKTYPE + policy.Process(root); + if(root->isinternal()) + { + enumNodes(root->childs[0],policy); + enumNodes(root->childs[1],policy); + } +} + +// +B3_DBVT_PREFIX +inline void b3DynamicBvh::enumLeaves( const b3DbvtNode* root, + B3_DBVT_IPOLICY) +{ + B3_DBVT_CHECKTYPE + if(root->isinternal()) + { + enumLeaves(root->childs[0],policy); + enumLeaves(root->childs[1],policy); + } + else + { + policy.Process(root); + } +} + +// +B3_DBVT_PREFIX +inline void b3DynamicBvh::collideTT( const b3DbvtNode* root0, + const b3DbvtNode* root1, + B3_DBVT_IPOLICY) +{ + B3_DBVT_CHECKTYPE + if(root0&&root1) + { + int depth=1; + int treshold=B3_DOUBLE_STACKSIZE-4; + b3AlignedObjectArray stkStack; + stkStack.resize(B3_DOUBLE_STACKSIZE); + stkStack[0]=sStkNN(root0,root1); + do { + sStkNN p=stkStack[--depth]; + if(depth>treshold) + { + stkStack.resize(stkStack.size()*2); + treshold=stkStack.size()-4; + } + if(p.a==p.b) + { + if(p.a->isinternal()) + { + stkStack[depth++]=sStkNN(p.a->childs[0],p.a->childs[0]); + stkStack[depth++]=sStkNN(p.a->childs[1],p.a->childs[1]); + stkStack[depth++]=sStkNN(p.a->childs[0],p.a->childs[1]); + } + } + else if(b3Intersect(p.a->volume,p.b->volume)) + { + if(p.a->isinternal()) + { + if(p.b->isinternal()) + { + stkStack[depth++]=sStkNN(p.a->childs[0],p.b->childs[0]); + stkStack[depth++]=sStkNN(p.a->childs[1],p.b->childs[0]); + stkStack[depth++]=sStkNN(p.a->childs[0],p.b->childs[1]); + stkStack[depth++]=sStkNN(p.a->childs[1],p.b->childs[1]); + } + else + { + stkStack[depth++]=sStkNN(p.a->childs[0],p.b); + stkStack[depth++]=sStkNN(p.a->childs[1],p.b); + } + } + else + { + if(p.b->isinternal()) + { + stkStack[depth++]=sStkNN(p.a,p.b->childs[0]); + stkStack[depth++]=sStkNN(p.a,p.b->childs[1]); + } + else + { + policy.Process(p.a,p.b); + } + } + } + } while(depth); + } +} + + + +B3_DBVT_PREFIX +inline void b3DynamicBvh::collideTTpersistentStack( const b3DbvtNode* root0, + const b3DbvtNode* root1, + B3_DBVT_IPOLICY) +{ + B3_DBVT_CHECKTYPE + if(root0&&root1) + { + int depth=1; + int treshold=B3_DOUBLE_STACKSIZE-4; + + m_stkStack.resize(B3_DOUBLE_STACKSIZE); + m_stkStack[0]=sStkNN(root0,root1); + do { + sStkNN p=m_stkStack[--depth]; + if(depth>treshold) + { + m_stkStack.resize(m_stkStack.size()*2); + treshold=m_stkStack.size()-4; + } + if(p.a==p.b) + { + if(p.a->isinternal()) + { + m_stkStack[depth++]=sStkNN(p.a->childs[0],p.a->childs[0]); + m_stkStack[depth++]=sStkNN(p.a->childs[1],p.a->childs[1]); + m_stkStack[depth++]=sStkNN(p.a->childs[0],p.a->childs[1]); + } + } + else if(b3Intersect(p.a->volume,p.b->volume)) + { + if(p.a->isinternal()) + { + if(p.b->isinternal()) + { + m_stkStack[depth++]=sStkNN(p.a->childs[0],p.b->childs[0]); + m_stkStack[depth++]=sStkNN(p.a->childs[1],p.b->childs[0]); + m_stkStack[depth++]=sStkNN(p.a->childs[0],p.b->childs[1]); + m_stkStack[depth++]=sStkNN(p.a->childs[1],p.b->childs[1]); + } + else + { + m_stkStack[depth++]=sStkNN(p.a->childs[0],p.b); + m_stkStack[depth++]=sStkNN(p.a->childs[1],p.b); + } + } + else + { + if(p.b->isinternal()) + { + m_stkStack[depth++]=sStkNN(p.a,p.b->childs[0]); + m_stkStack[depth++]=sStkNN(p.a,p.b->childs[1]); + } + else + { + policy.Process(p.a,p.b); + } + } + } + } while(depth); + } +} + +#if 0 +// +B3_DBVT_PREFIX +inline void b3DynamicBvh::collideTT( const b3DbvtNode* root0, + const b3DbvtNode* root1, + const b3Transform& xform, + B3_DBVT_IPOLICY) +{ + B3_DBVT_CHECKTYPE + if(root0&&root1) + { + int depth=1; + int treshold=B3_DOUBLE_STACKSIZE-4; + b3AlignedObjectArray stkStack; + stkStack.resize(B3_DOUBLE_STACKSIZE); + stkStack[0]=sStkNN(root0,root1); + do { + sStkNN p=stkStack[--depth]; + if(b3Intersect(p.a->volume,p.b->volume,xform)) + { + if(depth>treshold) + { + stkStack.resize(stkStack.size()*2); + treshold=stkStack.size()-4; + } + if(p.a->isinternal()) + { + if(p.b->isinternal()) + { + stkStack[depth++]=sStkNN(p.a->childs[0],p.b->childs[0]); + stkStack[depth++]=sStkNN(p.a->childs[1],p.b->childs[0]); + stkStack[depth++]=sStkNN(p.a->childs[0],p.b->childs[1]); + stkStack[depth++]=sStkNN(p.a->childs[1],p.b->childs[1]); + } + else + { + stkStack[depth++]=sStkNN(p.a->childs[0],p.b); + stkStack[depth++]=sStkNN(p.a->childs[1],p.b); + } + } + else + { + if(p.b->isinternal()) + { + stkStack[depth++]=sStkNN(p.a,p.b->childs[0]); + stkStack[depth++]=sStkNN(p.a,p.b->childs[1]); + } + else + { + policy.Process(p.a,p.b); + } + } + } + } while(depth); + } +} +// +B3_DBVT_PREFIX +inline void b3DynamicBvh::collideTT( const b3DbvtNode* root0, + const b3Transform& xform0, + const b3DbvtNode* root1, + const b3Transform& xform1, + B3_DBVT_IPOLICY) +{ + const b3Transform xform=xform0.inverse()*xform1; + collideTT(root0,root1,xform,policy); +} +#endif + +// +B3_DBVT_PREFIX +inline void b3DynamicBvh::collideTV( const b3DbvtNode* root, + const b3DbvtVolume& vol, + B3_DBVT_IPOLICY) const +{ + B3_DBVT_CHECKTYPE + if(root) + { + B3_ATTRIBUTE_ALIGNED16(b3DbvtVolume) volume(vol); + b3AlignedObjectArray stack; + stack.resize(0); + stack.reserve(B3_SIMPLE_STACKSIZE); + stack.push_back(root); + do { + const b3DbvtNode* n=stack[stack.size()-1]; + stack.pop_back(); + if(b3Intersect(n->volume,volume)) + { + if(n->isinternal()) + { + stack.push_back(n->childs[0]); + stack.push_back(n->childs[1]); + } + else + { + policy.Process(n); + } + } + } while(stack.size()>0); + } +} + +B3_DBVT_PREFIX +inline void b3DynamicBvh::rayTestInternal( const b3DbvtNode* root, + const b3Vector3& rayFrom, + const b3Vector3& rayTo, + const b3Vector3& rayDirectionInverse, + unsigned int signs[3], + b3Scalar lambda_max, + const b3Vector3& aabbMin, + const b3Vector3& aabbMax, + B3_DBVT_IPOLICY) const +{ + (void) rayTo; + B3_DBVT_CHECKTYPE + if(root) + { + int depth=1; + int treshold=B3_DOUBLE_STACKSIZE-2; + b3AlignedObjectArray& stack = m_rayTestStack; + stack.resize(B3_DOUBLE_STACKSIZE); + stack[0]=root; + b3Vector3 bounds[2]; + do + { + const b3DbvtNode* node=stack[--depth]; + bounds[0] = node->volume.Mins()-aabbMax; + bounds[1] = node->volume.Maxs()-aabbMin; + b3Scalar tmin=1.f,lambda_min=0.f; + unsigned int result1=false; + result1 = b3RayAabb2(rayFrom,rayDirectionInverse,signs,bounds,tmin,lambda_min,lambda_max); + if(result1) + { + if(node->isinternal()) + { + if(depth>treshold) + { + stack.resize(stack.size()*2); + treshold=stack.size()-2; + } + stack[depth++]=node->childs[0]; + stack[depth++]=node->childs[1]; + } + else + { + policy.Process(node); + } + } + } while(depth); + } +} + +// +B3_DBVT_PREFIX +inline void b3DynamicBvh::rayTest( const b3DbvtNode* root, + const b3Vector3& rayFrom, + const b3Vector3& rayTo, + B3_DBVT_IPOLICY) +{ + B3_DBVT_CHECKTYPE + if(root) + { + b3Vector3 rayDir = (rayTo-rayFrom); + rayDir.normalize (); + + ///what about division by zero? --> just set rayDirection[i] to INF/B3_LARGE_FLOAT + b3Vector3 rayDirectionInverse; + rayDirectionInverse[0] = rayDir[0] == b3Scalar(0.0) ? b3Scalar(B3_LARGE_FLOAT) : b3Scalar(1.0) / rayDir[0]; + rayDirectionInverse[1] = rayDir[1] == b3Scalar(0.0) ? b3Scalar(B3_LARGE_FLOAT) : b3Scalar(1.0) / rayDir[1]; + rayDirectionInverse[2] = rayDir[2] == b3Scalar(0.0) ? b3Scalar(B3_LARGE_FLOAT) : b3Scalar(1.0) / rayDir[2]; + unsigned int signs[3] = { rayDirectionInverse[0] < 0.0, rayDirectionInverse[1] < 0.0, rayDirectionInverse[2] < 0.0}; + + b3Scalar lambda_max = rayDir.dot(rayTo-rayFrom); +#ifdef COMPARE_BTRAY_AABB2 + b3Vector3 resultNormal; +#endif//COMPARE_BTRAY_AABB2 + + b3AlignedObjectArray stack; + + int depth=1; + int treshold=B3_DOUBLE_STACKSIZE-2; + + stack.resize(B3_DOUBLE_STACKSIZE); + stack[0]=root; + b3Vector3 bounds[2]; + do { + const b3DbvtNode* node=stack[--depth]; + + bounds[0] = node->volume.Mins(); + bounds[1] = node->volume.Maxs(); + + b3Scalar tmin=1.f,lambda_min=0.f; + unsigned int result1 = b3RayAabb2(rayFrom,rayDirectionInverse,signs,bounds,tmin,lambda_min,lambda_max); + +#ifdef COMPARE_BTRAY_AABB2 + b3Scalar param=1.f; + bool result2 = b3RayAabb(rayFrom,rayTo,node->volume.Mins(),node->volume.Maxs(),param,resultNormal); + b3Assert(result1 == result2); +#endif //TEST_BTRAY_AABB2 + + if(result1) + { + if(node->isinternal()) + { + if(depth>treshold) + { + stack.resize(stack.size()*2); + treshold=stack.size()-2; + } + stack[depth++]=node->childs[0]; + stack[depth++]=node->childs[1]; + } + else + { + policy.Process(node); + } + } + } while(depth); + + } +} + +// +B3_DBVT_PREFIX +inline void b3DynamicBvh::collideKDOP(const b3DbvtNode* root, + const b3Vector3* normals, + const b3Scalar* offsets, + int count, + B3_DBVT_IPOLICY) +{ + B3_DBVT_CHECKTYPE + if(root) + { + const int inside=(1< stack; + int signs[sizeof(unsigned)*8]; + b3Assert(count=0)?1:0)+ + ((normals[i].y>=0)?2:0)+ + ((normals[i].z>=0)?4:0); + } + stack.reserve(B3_SIMPLE_STACKSIZE); + stack.push_back(sStkNP(root,0)); + do { + sStkNP se=stack[stack.size()-1]; + bool out=false; + stack.pop_back(); + for(int i=0,j=1;(!out)&&(ivolume.Classify(normals[i],offsets[i],signs[i]); + switch(side) + { + case -1: out=true;break; + case +1: se.mask|=j;break; + } + } + } + if(!out) + { + if((se.mask!=inside)&&(se.node->isinternal())) + { + stack.push_back(sStkNP(se.node->childs[0],se.mask)); + stack.push_back(sStkNP(se.node->childs[1],se.mask)); + } + else + { + if(policy.AllLeaves(se.node)) enumLeaves(se.node,policy); + } + } + } while(stack.size()); + } +} + +// +B3_DBVT_PREFIX +inline void b3DynamicBvh::collideOCL( const b3DbvtNode* root, + const b3Vector3* normals, + const b3Scalar* offsets, + const b3Vector3& sortaxis, + int count, + B3_DBVT_IPOLICY, + bool fsort) +{ + B3_DBVT_CHECKTYPE + if(root) + { + const unsigned srtsgns=(sortaxis[0]>=0?1:0)+ + (sortaxis[1]>=0?2:0)+ + (sortaxis[2]>=0?4:0); + const int inside=(1< stock; + b3AlignedObjectArray ifree; + b3AlignedObjectArray stack; + int signs[sizeof(unsigned)*8]; + b3Assert(count=0)?1:0)+ + ((normals[i].y>=0)?2:0)+ + ((normals[i].z>=0)?4:0); + } + stock.reserve(B3_SIMPLE_STACKSIZE); + stack.reserve(B3_SIMPLE_STACKSIZE); + ifree.reserve(B3_SIMPLE_STACKSIZE); + stack.push_back(allocate(ifree,stock,sStkNPS(root,0,root->volume.ProjectMinimum(sortaxis,srtsgns)))); + do { + const int id=stack[stack.size()-1]; + sStkNPS se=stock[id]; + stack.pop_back();ifree.push_back(id); + if(se.mask!=inside) + { + bool out=false; + for(int i=0,j=1;(!out)&&(ivolume.Classify(normals[i],offsets[i],signs[i]); + switch(side) + { + case -1: out=true;break; + case +1: se.mask|=j;break; + } + } + } + if(out) continue; + } + if(policy.Descent(se.node)) + { + if(se.node->isinternal()) + { + const b3DbvtNode* pns[]={ se.node->childs[0],se.node->childs[1]}; + sStkNPS nes[]={ sStkNPS(pns[0],se.mask,pns[0]->volume.ProjectMinimum(sortaxis,srtsgns)), + sStkNPS(pns[1],se.mask,pns[1]->volume.ProjectMinimum(sortaxis,srtsgns))}; + const int q=nes[0].value0)) + { + /* Insert 0 */ + j=nearest(&stack[0],&stock[0],nes[q].value,0,stack.size()); + stack.push_back(0); +#if B3_DBVT_USE_MEMMOVE + memmove(&stack[j+1],&stack[j],sizeof(int)*(stack.size()-j-1)); +#else + for(int k=stack.size()-1;k>j;--k) stack[k]=stack[k-1]; +#endif + stack[j]=allocate(ifree,stock,nes[q]); + /* Insert 1 */ + j=nearest(&stack[0],&stock[0],nes[1-q].value,j,stack.size()); + stack.push_back(0); +#if B3_DBVT_USE_MEMMOVE + memmove(&stack[j+1],&stack[j],sizeof(int)*(stack.size()-j-1)); +#else + for(int k=stack.size()-1;k>j;--k) stack[k]=stack[k-1]; +#endif + stack[j]=allocate(ifree,stock,nes[1-q]); + } + else + { + stack.push_back(allocate(ifree,stock,nes[q])); + stack.push_back(allocate(ifree,stock,nes[1-q])); + } + } + else + { + policy.Process(se.node,se.value); + } + } + } while(stack.size()); + } +} + +// +B3_DBVT_PREFIX +inline void b3DynamicBvh::collideTU( const b3DbvtNode* root, + B3_DBVT_IPOLICY) +{ + B3_DBVT_CHECKTYPE + if(root) + { + b3AlignedObjectArray stack; + stack.reserve(B3_SIMPLE_STACKSIZE); + stack.push_back(root); + do { + const b3DbvtNode* n=stack[stack.size()-1]; + stack.pop_back(); + if(policy.Descent(n)) + { + if(n->isinternal()) + { stack.push_back(n->childs[0]);stack.push_back(n->childs[1]); } + else + { policy.Process(n); } + } + } while(stack.size()>0); + } +} + +// +// PP Cleanup +// + +#undef B3_DBVT_USE_MEMMOVE +#undef B3_DBVT_USE_TEMPLATE +#undef B3_DBVT_VIRTUAL_DTOR +#undef B3_DBVT_VIRTUAL +#undef B3_DBVT_PREFIX +#undef B3_DBVT_IPOLICY +#undef B3_DBVT_CHECKTYPE +#undef B3_DBVT_IMPL_GENERIC +#undef B3_DBVT_IMPL_SSE +#undef B3_DBVT_USE_INTRINSIC_SSE +#undef B3_DBVT_SELECT_IMPL +#undef B3_DBVT_MERGE_IMPL +#undef B3_DBVT_INT0_IMPL + +#endif diff --git a/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/b3DynamicBvhBroadphase.cpp b/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/b3DynamicBvhBroadphase.cpp new file mode 100644 index 000000000000..bc150955b838 --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/b3DynamicBvhBroadphase.cpp @@ -0,0 +1,804 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org + +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. +*/ + +///b3DynamicBvhBroadphase implementation by Nathanael Presson + +#include "b3DynamicBvhBroadphase.h" +#include "b3OverlappingPair.h" + +// +// Profiling +// + +#if B3_DBVT_BP_PROFILE||B3_DBVT_BP_ENABLE_BENCHMARK +#include +#endif + +#if B3_DBVT_BP_PROFILE +struct b3ProfileScope +{ + __forceinline b3ProfileScope(b3Clock& clock,unsigned long& value) : + m_clock(&clock),m_value(&value),m_base(clock.getTimeMicroseconds()) + { + } + __forceinline ~b3ProfileScope() + { + (*m_value)+=m_clock->getTimeMicroseconds()-m_base; + } + b3Clock* m_clock; + unsigned long* m_value; + unsigned long m_base; +}; +#define b3SPC(_value_) b3ProfileScope spc_scope(m_clock,_value_) +#else +#define b3SPC(_value_) +#endif + +// +// Helpers +// + +// +template +static inline void b3ListAppend(T* item,T*& list) +{ + item->links[0]=0; + item->links[1]=list; + if(list) list->links[0]=item; + list=item; +} + +// +template +static inline void b3ListRemove(T* item,T*& list) +{ + if(item->links[0]) item->links[0]->links[1]=item->links[1]; else list=item->links[1]; + if(item->links[1]) item->links[1]->links[0]=item->links[0]; +} + +// +template +static inline int b3ListCount(T* root) +{ + int n=0; + while(root) { ++n;root=root->links[1]; } + return(n); +} + +// +template +static inline void b3Clear(T& value) +{ + static const struct ZeroDummy : T {} zerodummy; + value=zerodummy; +} + +// +// Colliders +// + +/* Tree collider */ +struct b3DbvtTreeCollider : b3DynamicBvh::ICollide +{ + b3DynamicBvhBroadphase* pbp; + b3DbvtProxy* proxy; + b3DbvtTreeCollider(b3DynamicBvhBroadphase* p) : pbp(p) {} + void Process(const b3DbvtNode* na,const b3DbvtNode* nb) + { + if(na!=nb) + { + b3DbvtProxy* pa=(b3DbvtProxy*)na->data; + b3DbvtProxy* pb=(b3DbvtProxy*)nb->data; +#if B3_DBVT_BP_SORTPAIRS + if(pa->m_uniqueId>pb->m_uniqueId) + b3Swap(pa,pb); +#endif + pbp->m_paircache->addOverlappingPair(pa->getUid(),pb->getUid()); + ++pbp->m_newpairs; + } + } + void Process(const b3DbvtNode* n) + { + Process(n,proxy->leaf); + } +}; + +// +// b3DynamicBvhBroadphase +// + +// +b3DynamicBvhBroadphase::b3DynamicBvhBroadphase(int proxyCapacity, b3OverlappingPairCache* paircache) +{ + m_deferedcollide = false; + m_needcleanup = true; + m_releasepaircache = (paircache!=0)?false:true; + m_prediction = 0; + m_stageCurrent = 0; + m_fixedleft = 0; + m_fupdates = 1; + m_dupdates = 0; + m_cupdates = 10; + m_newpairs = 1; + m_updates_call = 0; + m_updates_done = 0; + m_updates_ratio = 0; + m_paircache = paircache? paircache : new(b3AlignedAlloc(sizeof(b3HashedOverlappingPairCache),16)) b3HashedOverlappingPairCache(); + + m_pid = 0; + m_cid = 0; + for(int i=0;i<=STAGECOUNT;++i) + { + m_stageRoots[i]=0; + } +#if B3_DBVT_BP_PROFILE + b3Clear(m_profiling); +#endif + m_proxies.resize(proxyCapacity); +} + +// +b3DynamicBvhBroadphase::~b3DynamicBvhBroadphase() +{ + if(m_releasepaircache) + { + m_paircache->~b3OverlappingPairCache(); + b3AlignedFree(m_paircache); + } +} + +// +b3BroadphaseProxy* b3DynamicBvhBroadphase::createProxy( const b3Vector3& aabbMin, + const b3Vector3& aabbMax, + int objectId, + void* userPtr, + int collisionFilterGroup, + int collisionFilterMask) +{ + b3DbvtProxy* mem = &m_proxies[objectId]; + b3DbvtProxy* proxy=new(mem) b3DbvtProxy( aabbMin,aabbMax,userPtr, + collisionFilterGroup, + collisionFilterMask); + + b3DbvtAabbMm aabb = b3DbvtVolume::FromMM(aabbMin,aabbMax); + + //bproxy->aabb = b3DbvtVolume::FromMM(aabbMin,aabbMax); + proxy->stage = m_stageCurrent; + proxy->m_uniqueId = objectId; + proxy->leaf = m_sets[0].insert(aabb,proxy); + b3ListAppend(proxy,m_stageRoots[m_stageCurrent]); + if(!m_deferedcollide) + { + b3DbvtTreeCollider collider(this); + collider.proxy=proxy; + m_sets[0].collideTV(m_sets[0].m_root,aabb,collider); + m_sets[1].collideTV(m_sets[1].m_root,aabb,collider); + } + return(proxy); +} + +// +void b3DynamicBvhBroadphase::destroyProxy( b3BroadphaseProxy* absproxy, + b3Dispatcher* dispatcher) +{ + b3DbvtProxy* proxy=(b3DbvtProxy*)absproxy; + if(proxy->stage==STAGECOUNT) + m_sets[1].remove(proxy->leaf); + else + m_sets[0].remove(proxy->leaf); + b3ListRemove(proxy,m_stageRoots[proxy->stage]); + m_paircache->removeOverlappingPairsContainingProxy(proxy->getUid(),dispatcher); + + m_needcleanup=true; +} + +void b3DynamicBvhBroadphase::getAabb(int objectId,b3Vector3& aabbMin, b3Vector3& aabbMax ) const +{ + const b3DbvtProxy* proxy=&m_proxies[objectId]; + aabbMin = proxy->m_aabbMin; + aabbMax = proxy->m_aabbMax; +} +/* +void b3DynamicBvhBroadphase::getAabb(b3BroadphaseProxy* absproxy,b3Vector3& aabbMin, b3Vector3& aabbMax ) const +{ + b3DbvtProxy* proxy=(b3DbvtProxy*)absproxy; + aabbMin = proxy->m_aabbMin; + aabbMax = proxy->m_aabbMax; +} +*/ + + +struct BroadphaseRayTester : b3DynamicBvh::ICollide +{ + b3BroadphaseRayCallback& m_rayCallback; + BroadphaseRayTester(b3BroadphaseRayCallback& orgCallback) + :m_rayCallback(orgCallback) + { + } + void Process(const b3DbvtNode* leaf) + { + b3DbvtProxy* proxy=(b3DbvtProxy*)leaf->data; + m_rayCallback.process(proxy); + } +}; + +void b3DynamicBvhBroadphase::rayTest(const b3Vector3& rayFrom,const b3Vector3& rayTo, b3BroadphaseRayCallback& rayCallback,const b3Vector3& aabbMin,const b3Vector3& aabbMax) +{ + BroadphaseRayTester callback(rayCallback); + + m_sets[0].rayTestInternal( m_sets[0].m_root, + rayFrom, + rayTo, + rayCallback.m_rayDirectionInverse, + rayCallback.m_signs, + rayCallback.m_lambda_max, + aabbMin, + aabbMax, + callback); + + m_sets[1].rayTestInternal( m_sets[1].m_root, + rayFrom, + rayTo, + rayCallback.m_rayDirectionInverse, + rayCallback.m_signs, + rayCallback.m_lambda_max, + aabbMin, + aabbMax, + callback); + +} + + +struct BroadphaseAabbTester : b3DynamicBvh::ICollide +{ + b3BroadphaseAabbCallback& m_aabbCallback; + BroadphaseAabbTester(b3BroadphaseAabbCallback& orgCallback) + :m_aabbCallback(orgCallback) + { + } + void Process(const b3DbvtNode* leaf) + { + b3DbvtProxy* proxy=(b3DbvtProxy*)leaf->data; + m_aabbCallback.process(proxy); + } +}; + +void b3DynamicBvhBroadphase::aabbTest(const b3Vector3& aabbMin,const b3Vector3& aabbMax,b3BroadphaseAabbCallback& aabbCallback) +{ + BroadphaseAabbTester callback(aabbCallback); + + const B3_ATTRIBUTE_ALIGNED16(b3DbvtVolume) bounds=b3DbvtVolume::FromMM(aabbMin,aabbMax); + //process all children, that overlap with the given AABB bounds + m_sets[0].collideTV(m_sets[0].m_root,bounds,callback); + m_sets[1].collideTV(m_sets[1].m_root,bounds,callback); + +} + + + +// +void b3DynamicBvhBroadphase::setAabb(int objectId, + const b3Vector3& aabbMin, + const b3Vector3& aabbMax, + b3Dispatcher* /*dispatcher*/) +{ + b3DbvtProxy* proxy=&m_proxies[objectId]; +// b3DbvtProxy* proxy=(b3DbvtProxy*)absproxy; + B3_ATTRIBUTE_ALIGNED16(b3DbvtVolume) aabb=b3DbvtVolume::FromMM(aabbMin,aabbMax); +#if B3_DBVT_BP_PREVENTFALSEUPDATE + if(b3NotEqual(aabb,proxy->leaf->volume)) +#endif + { + bool docollide=false; + if(proxy->stage==STAGECOUNT) + {/* fixed -> dynamic set */ + m_sets[1].remove(proxy->leaf); + proxy->leaf=m_sets[0].insert(aabb,proxy); + docollide=true; + } + else + {/* dynamic set */ + ++m_updates_call; + if(b3Intersect(proxy->leaf->volume,aabb)) + {/* Moving */ + + const b3Vector3 delta=aabbMin-proxy->m_aabbMin; + b3Vector3 velocity(((proxy->m_aabbMax-proxy->m_aabbMin)/2)*m_prediction); + if(delta[0]<0) velocity[0]=-velocity[0]; + if(delta[1]<0) velocity[1]=-velocity[1]; + if(delta[2]<0) velocity[2]=-velocity[2]; + if ( +#ifdef B3_DBVT_BP_MARGIN + m_sets[0].update(proxy->leaf,aabb,velocity,B3_DBVT_BP_MARGIN) +#else + m_sets[0].update(proxy->leaf,aabb,velocity) +#endif + ) + { + ++m_updates_done; + docollide=true; + } + } + else + {/* Teleporting */ + m_sets[0].update(proxy->leaf,aabb); + ++m_updates_done; + docollide=true; + } + } + b3ListRemove(proxy,m_stageRoots[proxy->stage]); + proxy->m_aabbMin = aabbMin; + proxy->m_aabbMax = aabbMax; + proxy->stage = m_stageCurrent; + b3ListAppend(proxy,m_stageRoots[m_stageCurrent]); + if(docollide) + { + m_needcleanup=true; + if(!m_deferedcollide) + { + b3DbvtTreeCollider collider(this); + m_sets[1].collideTTpersistentStack(m_sets[1].m_root,proxy->leaf,collider); + m_sets[0].collideTTpersistentStack(m_sets[0].m_root,proxy->leaf,collider); + } + } + } +} + + +// +void b3DynamicBvhBroadphase::setAabbForceUpdate( b3BroadphaseProxy* absproxy, + const b3Vector3& aabbMin, + const b3Vector3& aabbMax, + b3Dispatcher* /*dispatcher*/) +{ + b3DbvtProxy* proxy=(b3DbvtProxy*)absproxy; + B3_ATTRIBUTE_ALIGNED16(b3DbvtVolume) aabb=b3DbvtVolume::FromMM(aabbMin,aabbMax); + bool docollide=false; + if(proxy->stage==STAGECOUNT) + {/* fixed -> dynamic set */ + m_sets[1].remove(proxy->leaf); + proxy->leaf=m_sets[0].insert(aabb,proxy); + docollide=true; + } + else + {/* dynamic set */ + ++m_updates_call; + /* Teleporting */ + m_sets[0].update(proxy->leaf,aabb); + ++m_updates_done; + docollide=true; + } + b3ListRemove(proxy,m_stageRoots[proxy->stage]); + proxy->m_aabbMin = aabbMin; + proxy->m_aabbMax = aabbMax; + proxy->stage = m_stageCurrent; + b3ListAppend(proxy,m_stageRoots[m_stageCurrent]); + if(docollide) + { + m_needcleanup=true; + if(!m_deferedcollide) + { + b3DbvtTreeCollider collider(this); + m_sets[1].collideTTpersistentStack(m_sets[1].m_root,proxy->leaf,collider); + m_sets[0].collideTTpersistentStack(m_sets[0].m_root,proxy->leaf,collider); + } + } +} + +// +void b3DynamicBvhBroadphase::calculateOverlappingPairs(b3Dispatcher* dispatcher) +{ + collide(dispatcher); +#if B3_DBVT_BP_PROFILE + if(0==(m_pid%B3_DBVT_BP_PROFILING_RATE)) + { + printf("fixed(%u) dynamics(%u) pairs(%u)\r\n",m_sets[1].m_leaves,m_sets[0].m_leaves,m_paircache->getNumOverlappingPairs()); + unsigned int total=m_profiling.m_total; + if(total<=0) total=1; + printf("ddcollide: %u%% (%uus)\r\n",(50+m_profiling.m_ddcollide*100)/total,m_profiling.m_ddcollide/B3_DBVT_BP_PROFILING_RATE); + printf("fdcollide: %u%% (%uus)\r\n",(50+m_profiling.m_fdcollide*100)/total,m_profiling.m_fdcollide/B3_DBVT_BP_PROFILING_RATE); + printf("cleanup: %u%% (%uus)\r\n",(50+m_profiling.m_cleanup*100)/total,m_profiling.m_cleanup/B3_DBVT_BP_PROFILING_RATE); + printf("total: %uus\r\n",total/B3_DBVT_BP_PROFILING_RATE); + const unsigned long sum=m_profiling.m_ddcollide+ + m_profiling.m_fdcollide+ + m_profiling.m_cleanup; + printf("leaked: %u%% (%uus)\r\n",100-((50+sum*100)/total),(total-sum)/B3_DBVT_BP_PROFILING_RATE); + printf("job counts: %u%%\r\n",(m_profiling.m_jobcount*100)/((m_sets[0].m_leaves+m_sets[1].m_leaves)*B3_DBVT_BP_PROFILING_RATE)); + b3Clear(m_profiling); + m_clock.reset(); + } +#endif + + performDeferredRemoval(dispatcher); + +} + +void b3DynamicBvhBroadphase::performDeferredRemoval(b3Dispatcher* dispatcher) +{ + + if (m_paircache->hasDeferredRemoval()) + { + + b3BroadphasePairArray& overlappingPairArray = m_paircache->getOverlappingPairArray(); + + //perform a sort, to find duplicates and to sort 'invalid' pairs to the end + overlappingPairArray.quickSort(b3BroadphasePairSortPredicate()); + + int invalidPair = 0; + + + int i; + + b3BroadphasePair previousPair = b3MakeBroadphasePair(-1,-1); + + + + for (i=0;ileaf->volume,pb->leaf->volume); + + if (hasOverlap) + { + needsRemoval = false; + } else + { + needsRemoval = true; + } + } else + { + //remove duplicate + needsRemoval = true; + //should have no algorithm + } + + if (needsRemoval) + { + m_paircache->cleanOverlappingPair(pair,dispatcher); + + pair.x = -1; + pair.y = -1; + invalidPair++; + } + + } + + //perform a sort, to sort 'invalid' pairs to the end + overlappingPairArray.quickSort(b3BroadphasePairSortPredicate()); + overlappingPairArray.resize(overlappingPairArray.size() - invalidPair); + } +} + +// +void b3DynamicBvhBroadphase::collide(b3Dispatcher* dispatcher) +{ + /*printf("---------------------------------------------------------\n"); + printf("m_sets[0].m_leaves=%d\n",m_sets[0].m_leaves); + printf("m_sets[1].m_leaves=%d\n",m_sets[1].m_leaves); + printf("numPairs = %d\n",getOverlappingPairCache()->getNumOverlappingPairs()); + { + int i; + for (i=0;igetNumOverlappingPairs();i++) + { + printf("pair[%d]=(%d,%d),",i,getOverlappingPairCache()->getOverlappingPairArray()[i].m_pProxy0->getUid(), + getOverlappingPairCache()->getOverlappingPairArray()[i].m_pProxy1->getUid()); + } + printf("\n"); + } +*/ + + + + b3SPC(m_profiling.m_total); + /* optimize */ + m_sets[0].optimizeIncremental(1+(m_sets[0].m_leaves*m_dupdates)/100); + if(m_fixedleft) + { + const int count=1+(m_sets[1].m_leaves*m_fupdates)/100; + m_sets[1].optimizeIncremental(1+(m_sets[1].m_leaves*m_fupdates)/100); + m_fixedleft=b3Max(0,m_fixedleft-count); + } + /* dynamic -> fixed set */ + m_stageCurrent=(m_stageCurrent+1)%STAGECOUNT; + b3DbvtProxy* current=m_stageRoots[m_stageCurrent]; + if(current) + { + b3DbvtTreeCollider collider(this); + do { + b3DbvtProxy* next=current->links[1]; + b3ListRemove(current,m_stageRoots[current->stage]); + b3ListAppend(current,m_stageRoots[STAGECOUNT]); +#if B3_DBVT_BP_ACCURATESLEEPING + m_paircache->removeOverlappingPairsContainingProxy(current,dispatcher); + collider.proxy=current; + b3DynamicBvh::collideTV(m_sets[0].m_root,current->aabb,collider); + b3DynamicBvh::collideTV(m_sets[1].m_root,current->aabb,collider); +#endif + m_sets[0].remove(current->leaf); + B3_ATTRIBUTE_ALIGNED16(b3DbvtVolume) curAabb=b3DbvtVolume::FromMM(current->m_aabbMin,current->m_aabbMax); + current->leaf = m_sets[1].insert(curAabb,current); + current->stage = STAGECOUNT; + current = next; + } while(current); + m_fixedleft=m_sets[1].m_leaves; + m_needcleanup=true; + } + /* collide dynamics */ + { + b3DbvtTreeCollider collider(this); + if(m_deferedcollide) + { + b3SPC(m_profiling.m_fdcollide); + m_sets[0].collideTTpersistentStack(m_sets[0].m_root,m_sets[1].m_root,collider); + } + if(m_deferedcollide) + { + b3SPC(m_profiling.m_ddcollide); + m_sets[0].collideTTpersistentStack(m_sets[0].m_root,m_sets[0].m_root,collider); + } + } + /* clean up */ + if(m_needcleanup) + { + b3SPC(m_profiling.m_cleanup); + b3BroadphasePairArray& pairs=m_paircache->getOverlappingPairArray(); + if(pairs.size()>0) + { + + int ni=b3Min(pairs.size(),b3Max(m_newpairs,(pairs.size()*m_cupdates)/100)); + for(int i=0;ileaf->volume,pb->leaf->volume)) + { +#if B3_DBVT_BP_SORTPAIRS + if(pa->m_uniqueId>pb->m_uniqueId) + b3Swap(pa,pb); +#endif + m_paircache->removeOverlappingPair(pa->getUid(),pb->getUid(),dispatcher); + --ni;--i; + } + } + if(pairs.size()>0) m_cid=(m_cid+ni)%pairs.size(); else m_cid=0; + } + } + ++m_pid; + m_newpairs=1; + m_needcleanup=false; + if(m_updates_call>0) + { m_updates_ratio=m_updates_done/(b3Scalar)m_updates_call; } + else + { m_updates_ratio=0; } + m_updates_done/=2; + m_updates_call/=2; +} + +// +void b3DynamicBvhBroadphase::optimize() +{ + m_sets[0].optimizeTopDown(); + m_sets[1].optimizeTopDown(); +} + +// +b3OverlappingPairCache* b3DynamicBvhBroadphase::getOverlappingPairCache() +{ + return(m_paircache); +} + +// +const b3OverlappingPairCache* b3DynamicBvhBroadphase::getOverlappingPairCache() const +{ + return(m_paircache); +} + +// +void b3DynamicBvhBroadphase::getBroadphaseAabb(b3Vector3& aabbMin,b3Vector3& aabbMax) const +{ + + B3_ATTRIBUTE_ALIGNED16(b3DbvtVolume) bounds; + + if(!m_sets[0].empty()) + if(!m_sets[1].empty()) b3Merge( m_sets[0].m_root->volume, + m_sets[1].m_root->volume,bounds); + else + bounds=m_sets[0].m_root->volume; + else if(!m_sets[1].empty()) bounds=m_sets[1].m_root->volume; + else + bounds=b3DbvtVolume::FromCR(b3MakeVector3(0,0,0),0); + aabbMin=bounds.Mins(); + aabbMax=bounds.Maxs(); +} + +void b3DynamicBvhBroadphase::resetPool(b3Dispatcher* dispatcher) +{ + + int totalObjects = m_sets[0].m_leaves + m_sets[1].m_leaves; + if (!totalObjects) + { + //reset internal dynamic tree data structures + m_sets[0].clear(); + m_sets[1].clear(); + + m_deferedcollide = false; + m_needcleanup = true; + m_stageCurrent = 0; + m_fixedleft = 0; + m_fupdates = 1; + m_dupdates = 0; + m_cupdates = 10; + m_newpairs = 1; + m_updates_call = 0; + m_updates_done = 0; + m_updates_ratio = 0; + + m_pid = 0; + m_cid = 0; + for(int i=0;i<=STAGECOUNT;++i) + { + m_stageRoots[i]=0; + } + } +} + +// +void b3DynamicBvhBroadphase::printStats() +{} + +// +#if B3_DBVT_BP_ENABLE_BENCHMARK + +struct b3BroadphaseBenchmark +{ + struct Experiment + { + const char* name; + int object_count; + int update_count; + int spawn_count; + int iterations; + b3Scalar speed; + b3Scalar amplitude; + }; + struct Object + { + b3Vector3 center; + b3Vector3 extents; + b3BroadphaseProxy* proxy; + b3Scalar time; + void update(b3Scalar speed,b3Scalar amplitude,b3BroadphaseInterface* pbi) + { + time += speed; + center[0] = b3Cos(time*(b3Scalar)2.17)*amplitude+ + b3Sin(time)*amplitude/2; + center[1] = b3Cos(time*(b3Scalar)1.38)*amplitude+ + b3Sin(time)*amplitude; + center[2] = b3Sin(time*(b3Scalar)0.777)*amplitude; + pbi->setAabb(proxy,center-extents,center+extents,0); + } + }; + static int UnsignedRand(int range=RAND_MAX-1) { return(rand()%(range+1)); } + static b3Scalar UnitRand() { return(UnsignedRand(16384)/(b3Scalar)16384); } + static void OutputTime(const char* name,b3Clock& c,unsigned count=0) + { + const unsigned long us=c.getTimeMicroseconds(); + const unsigned long ms=(us+500)/1000; + const b3Scalar sec=us/(b3Scalar)(1000*1000); + if(count>0) + printf("%s : %u us (%u ms), %.2f/s\r\n",name,us,ms,count/sec); + else + printf("%s : %u us (%u ms)\r\n",name,us,ms); + } +}; + +void b3DynamicBvhBroadphase::benchmark(b3BroadphaseInterface* pbi) +{ + static const b3BroadphaseBenchmark::Experiment experiments[]= + { + {"1024o.10%",1024,10,0,8192,(b3Scalar)0.005,(b3Scalar)100}, + /*{"4096o.10%",4096,10,0,8192,(b3Scalar)0.005,(b3Scalar)100}, + {"8192o.10%",8192,10,0,8192,(b3Scalar)0.005,(b3Scalar)100},*/ + }; + static const int nexperiments=sizeof(experiments)/sizeof(experiments[0]); + b3AlignedObjectArray objects; + b3Clock wallclock; + /* Begin */ + for(int iexp=0;iexpcenter[0]=b3BroadphaseBenchmark::UnitRand()*50; + po->center[1]=b3BroadphaseBenchmark::UnitRand()*50; + po->center[2]=b3BroadphaseBenchmark::UnitRand()*50; + po->extents[0]=b3BroadphaseBenchmark::UnitRand()*2+2; + po->extents[1]=b3BroadphaseBenchmark::UnitRand()*2+2; + po->extents[2]=b3BroadphaseBenchmark::UnitRand()*2+2; + po->time=b3BroadphaseBenchmark::UnitRand()*2000; + po->proxy=pbi->createProxy(po->center-po->extents,po->center+po->extents,0,po,1,1,0,0); + objects.push_back(po); + } + b3BroadphaseBenchmark::OutputTime("\tInitialization",wallclock); + /* First update */ + wallclock.reset(); + for(int i=0;iupdate(speed,amplitude,pbi); + } + b3BroadphaseBenchmark::OutputTime("\tFirst update",wallclock); + /* Updates */ + wallclock.reset(); + for(int i=0;iupdate(speed,amplitude,pbi); + } + pbi->calculateOverlappingPairs(0); + } + b3BroadphaseBenchmark::OutputTime("\tUpdate",wallclock,experiment.iterations); + /* Clean up */ + wallclock.reset(); + for(int i=0;idestroyProxy(objects[i]->proxy,0); + delete objects[i]; + } + objects.resize(0); + b3BroadphaseBenchmark::OutputTime("\tRelease",wallclock); + } + +} +#else +/*void b3DynamicBvhBroadphase::benchmark(b3BroadphaseInterface*) +{} +*/ +#endif + +#if B3_DBVT_BP_PROFILE +#undef b3SPC +#endif + diff --git a/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/b3DynamicBvhBroadphase.h b/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/b3DynamicBvhBroadphase.h new file mode 100644 index 000000000000..7ac085d90cda --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/b3DynamicBvhBroadphase.h @@ -0,0 +1,206 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org + +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. +*/ + +///b3DynamicBvhBroadphase implementation by Nathanael Presson +#ifndef B3_DBVT_BROADPHASE_H +#define B3_DBVT_BROADPHASE_H + +#include "Bullet3Collision/BroadPhaseCollision/b3DynamicBvh.h" +#include "Bullet3Collision/BroadPhaseCollision/b3OverlappingPairCache.h" +#include "Bullet3Common/b3AlignedObjectArray.h" + +#include "b3BroadphaseCallback.h" + +// +// Compile time config +// + +#define B3_DBVT_BP_PROFILE 0 +//#define B3_DBVT_BP_SORTPAIRS 1 +#define B3_DBVT_BP_PREVENTFALSEUPDATE 0 +#define B3_DBVT_BP_ACCURATESLEEPING 0 +#define B3_DBVT_BP_ENABLE_BENCHMARK 0 +#define B3_DBVT_BP_MARGIN (b3Scalar)0.05 + +#if B3_DBVT_BP_PROFILE +#define B3_DBVT_BP_PROFILING_RATE 256 + +#endif + + + + +B3_ATTRIBUTE_ALIGNED16(struct) b3BroadphaseProxy +{ + +B3_DECLARE_ALIGNED_ALLOCATOR(); + + ///optional filtering to cull potential collisions + enum CollisionFilterGroups + { + DefaultFilter = 1, + StaticFilter = 2, + KinematicFilter = 4, + DebrisFilter = 8, + SensorTrigger = 16, + CharacterFilter = 32, + AllFilter = -1 //all bits sets: DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter | SensorTrigger + }; + + //Usually the client b3CollisionObject or Rigidbody class + void* m_clientObject; + int m_collisionFilterGroup; + int m_collisionFilterMask; + int m_uniqueId;//m_uniqueId is introduced for paircache. could get rid of this, by calculating the address offset etc. + + b3Vector3 m_aabbMin; + b3Vector3 m_aabbMax; + + B3_FORCE_INLINE int getUid() const + { + return m_uniqueId; + } + + //used for memory pools + b3BroadphaseProxy() :m_clientObject(0) + { + } + + b3BroadphaseProxy(const b3Vector3& aabbMin,const b3Vector3& aabbMax,void* userPtr, int collisionFilterGroup, int collisionFilterMask) + :m_clientObject(userPtr), + m_collisionFilterGroup(collisionFilterGroup), + m_collisionFilterMask(collisionFilterMask), + m_aabbMin(aabbMin), + m_aabbMax(aabbMax) + { + } +}; + + + + + +// +// b3DbvtProxy +// +struct b3DbvtProxy : b3BroadphaseProxy +{ + /* Fields */ + //b3DbvtAabbMm aabb; + b3DbvtNode* leaf; + b3DbvtProxy* links[2]; + int stage; + /* ctor */ + + explicit b3DbvtProxy() {} + b3DbvtProxy(const b3Vector3& aabbMin,const b3Vector3& aabbMax,void* userPtr, int collisionFilterGroup, int collisionFilterMask) : + b3BroadphaseProxy(aabbMin,aabbMax,userPtr,collisionFilterGroup,collisionFilterMask) + { + links[0]=links[1]=0; + } +}; + +typedef b3AlignedObjectArray b3DbvtProxyArray; + +///The b3DynamicBvhBroadphase implements a broadphase using two dynamic AABB bounding volume hierarchies/trees (see b3DynamicBvh). +///One tree is used for static/non-moving objects, and another tree is used for dynamic objects. Objects can move from one tree to the other. +///This is a very fast broadphase, especially for very dynamic worlds where many objects are moving. Its insert/add and remove of objects is generally faster than the sweep and prune broadphases b3AxisSweep3 and b332BitAxisSweep3. +struct b3DynamicBvhBroadphase +{ + /* Config */ + enum { + DYNAMIC_SET = 0, /* Dynamic set index */ + FIXED_SET = 1, /* Fixed set index */ + STAGECOUNT = 2 /* Number of stages */ + }; + /* Fields */ + b3DynamicBvh m_sets[2]; // Dbvt sets + b3DbvtProxy* m_stageRoots[STAGECOUNT+1]; // Stages list + + b3AlignedObjectArray m_proxies; + b3OverlappingPairCache* m_paircache; // Pair cache + b3Scalar m_prediction; // Velocity prediction + int m_stageCurrent; // Current stage + int m_fupdates; // % of fixed updates per frame + int m_dupdates; // % of dynamic updates per frame + int m_cupdates; // % of cleanup updates per frame + int m_newpairs; // Number of pairs created + int m_fixedleft; // Fixed optimization left + unsigned m_updates_call; // Number of updates call + unsigned m_updates_done; // Number of updates done + b3Scalar m_updates_ratio; // m_updates_done/m_updates_call + int m_pid; // Parse id + int m_cid; // Cleanup index + bool m_releasepaircache; // Release pair cache on delete + bool m_deferedcollide; // Defere dynamic/static collision to collide call + bool m_needcleanup; // Need to run cleanup? +#if B3_DBVT_BP_PROFILE + b3Clock m_clock; + struct { + unsigned long m_total; + unsigned long m_ddcollide; + unsigned long m_fdcollide; + unsigned long m_cleanup; + unsigned long m_jobcount; + } m_profiling; +#endif + /* Methods */ + b3DynamicBvhBroadphase(int proxyCapacity, b3OverlappingPairCache* paircache=0); + virtual ~b3DynamicBvhBroadphase(); + void collide(b3Dispatcher* dispatcher); + void optimize(); + + /* b3BroadphaseInterface Implementation */ + b3BroadphaseProxy* createProxy(const b3Vector3& aabbMin,const b3Vector3& aabbMax,int objectIndex,void* userPtr, int collisionFilterGroup, int collisionFilterMask); + virtual void destroyProxy(b3BroadphaseProxy* proxy,b3Dispatcher* dispatcher); + virtual void setAabb(int objectId,const b3Vector3& aabbMin,const b3Vector3& aabbMax,b3Dispatcher* dispatcher); + virtual void rayTest(const b3Vector3& rayFrom,const b3Vector3& rayTo, b3BroadphaseRayCallback& rayCallback, const b3Vector3& aabbMin=b3MakeVector3(0,0,0), const b3Vector3& aabbMax = b3MakeVector3(0,0,0)); + virtual void aabbTest(const b3Vector3& aabbMin, const b3Vector3& aabbMax, b3BroadphaseAabbCallback& callback); + + //virtual void getAabb(b3BroadphaseProxy* proxy,b3Vector3& aabbMin, b3Vector3& aabbMax ) const; + virtual void getAabb(int objectId,b3Vector3& aabbMin, b3Vector3& aabbMax ) const; + virtual void calculateOverlappingPairs(b3Dispatcher* dispatcher=0); + virtual b3OverlappingPairCache* getOverlappingPairCache(); + virtual const b3OverlappingPairCache* getOverlappingPairCache() const; + virtual void getBroadphaseAabb(b3Vector3& aabbMin,b3Vector3& aabbMax) const; + virtual void printStats(); + + + ///reset broadphase internal structures, to ensure determinism/reproducability + virtual void resetPool(b3Dispatcher* dispatcher); + + void performDeferredRemoval(b3Dispatcher* dispatcher); + + void setVelocityPrediction(b3Scalar prediction) + { + m_prediction = prediction; + } + b3Scalar getVelocityPrediction() const + { + return m_prediction; + } + + ///this setAabbForceUpdate is similar to setAabb but always forces the aabb update. + ///it is not part of the b3BroadphaseInterface but specific to b3DynamicBvhBroadphase. + ///it bypasses certain optimizations that prevent aabb updates (when the aabb shrinks), see + ///http://code.google.com/p/bullet/issues/detail?id=223 + void setAabbForceUpdate( b3BroadphaseProxy* absproxy,const b3Vector3& aabbMin,const b3Vector3& aabbMax,b3Dispatcher* /*dispatcher*/); + + //static void benchmark(b3BroadphaseInterface*); + + +}; + +#endif diff --git a/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/b3OverlappingPair.h b/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/b3OverlappingPair.h new file mode 100644 index 000000000000..39bf27de3e36 --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/b3OverlappingPair.h @@ -0,0 +1,72 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org + +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 B3_OVERLAPPING_PAIR_H +#define B3_OVERLAPPING_PAIR_H + +#include "Bullet3Common/shared/b3Int4.h" + +#define B3_NEW_PAIR_MARKER -1 +#define B3_REMOVED_PAIR_MARKER -2 + +typedef b3Int4 b3BroadphasePair; + +inline b3Int4 b3MakeBroadphasePair(int xx,int yy) +{ + b3Int4 pair; + + if (xx < yy) + { + pair.x = xx; + pair.y = yy; + } + else + { + pair.x = yy; + pair.y = xx; + } + pair.z = B3_NEW_PAIR_MARKER; + pair.w = B3_NEW_PAIR_MARKER; + return pair; +} + +/*struct b3BroadphasePair : public b3Int4 +{ + explicit b3BroadphasePair(){} + +}; +*/ + +class b3BroadphasePairSortPredicate +{ + public: + + bool operator() ( const b3BroadphasePair& a, const b3BroadphasePair& b ) const + { + const int uidA0 = a.x; + const int uidB0 = b.x; + const int uidA1 = a.y; + const int uidB1 = b.y; + return uidA0 > uidB0 || (uidA0 == uidB0 && uidA1 > uidB1); + } +}; + +B3_FORCE_INLINE bool operator==(const b3BroadphasePair& a, const b3BroadphasePair& b) +{ + return (a.x == b.x ) && (a.y == b.y ); +} + +#endif //B3_OVERLAPPING_PAIR_H + diff --git a/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/b3OverlappingPairCache.cpp b/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/b3OverlappingPairCache.cpp new file mode 100644 index 000000000000..e4bda61624ad --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/b3OverlappingPairCache.cpp @@ -0,0 +1,638 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org + +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 "b3OverlappingPairCache.h" + +//#include "b3Dispatcher.h" +//#include "b3CollisionAlgorithm.h" +#include "Bullet3Geometry/b3AabbUtil.h" + +#include + +int b3g_overlappingPairs = 0; +int b3g_removePairs =0; +int b3g_addedPairs =0; +int b3g_findPairs =0; + + + + +b3HashedOverlappingPairCache::b3HashedOverlappingPairCache(): + m_overlapFilterCallback(0) +//, m_blockedForChanges(false) +{ + int initialAllocatedSize= 2; + m_overlappingPairArray.reserve(initialAllocatedSize); + growTables(); +} + + + + +b3HashedOverlappingPairCache::~b3HashedOverlappingPairCache() +{ +} + + + +void b3HashedOverlappingPairCache::cleanOverlappingPair(b3BroadphasePair& pair,b3Dispatcher* dispatcher) +{ +/* if (pair.m_algorithm) + { + { + pair.m_algorithm->~b3CollisionAlgorithm(); + dispatcher->freeCollisionAlgorithm(pair.m_algorithm); + pair.m_algorithm=0; + } + } + */ + +} + + + + +void b3HashedOverlappingPairCache::cleanProxyFromPairs(int proxy,b3Dispatcher* dispatcher) +{ + + class CleanPairCallback : public b3OverlapCallback + { + int m_cleanProxy; + b3OverlappingPairCache* m_pairCache; + b3Dispatcher* m_dispatcher; + + public: + CleanPairCallback(int cleanProxy,b3OverlappingPairCache* pairCache,b3Dispatcher* dispatcher) + :m_cleanProxy(cleanProxy), + m_pairCache(pairCache), + m_dispatcher(dispatcher) + { + } + virtual bool processOverlap(b3BroadphasePair& pair) + { + if ((pair.x == m_cleanProxy) || + (pair.y == m_cleanProxy)) + { + m_pairCache->cleanOverlappingPair(pair,m_dispatcher); + } + return false; + } + + }; + + CleanPairCallback cleanPairs(proxy,this,dispatcher); + + processAllOverlappingPairs(&cleanPairs,dispatcher); + +} + + + + +void b3HashedOverlappingPairCache::removeOverlappingPairsContainingProxy(int proxy,b3Dispatcher* dispatcher) +{ + + class RemovePairCallback : public b3OverlapCallback + { + int m_obsoleteProxy; + + public: + RemovePairCallback(int obsoleteProxy) + :m_obsoleteProxy(obsoleteProxy) + { + } + virtual bool processOverlap(b3BroadphasePair& pair) + { + return ((pair.x == m_obsoleteProxy) || + (pair.y == m_obsoleteProxy)); + } + + }; + + + RemovePairCallback removeCallback(proxy); + + processAllOverlappingPairs(&removeCallback,dispatcher); +} + + + + + +b3BroadphasePair* b3HashedOverlappingPairCache::findPair(int proxy0, int proxy1) +{ + b3g_findPairs++; + if(proxy0 >proxy1) + b3Swap(proxy0,proxy1); + int proxyId1 = proxy0; + int proxyId2 = proxy1; + + /*if (proxyId1 > proxyId2) + b3Swap(proxyId1, proxyId2);*/ + + int hash = static_cast(getHash(static_cast(proxyId1), static_cast(proxyId2)) & (m_overlappingPairArray.capacity()-1)); + + if (hash >= m_hashTable.size()) + { + return NULL; + } + + int index = m_hashTable[hash]; + while (index != B3_NULL_PAIR && equalsPair(m_overlappingPairArray[index], proxyId1, proxyId2) == false) + { + index = m_next[index]; + } + + if (index == B3_NULL_PAIR) + { + return NULL; + } + + b3Assert(index < m_overlappingPairArray.size()); + + return &m_overlappingPairArray[index]; +} + +//#include + +void b3HashedOverlappingPairCache::growTables() +{ + + int newCapacity = m_overlappingPairArray.capacity(); + + if (m_hashTable.size() < newCapacity) + { + //grow hashtable and next table + int curHashtableSize = m_hashTable.size(); + + m_hashTable.resize(newCapacity); + m_next.resize(newCapacity); + + + int i; + + for (i= 0; i < newCapacity; ++i) + { + m_hashTable[i] = B3_NULL_PAIR; + } + for (i = 0; i < newCapacity; ++i) + { + m_next[i] = B3_NULL_PAIR; + } + + for(i=0;i proxyId2) + b3Swap(proxyId1, proxyId2);*/ + int hashValue = static_cast(getHash(static_cast(proxyId1),static_cast(proxyId2)) & (m_overlappingPairArray.capacity()-1)); // New hash value with new mask + m_next[i] = m_hashTable[hashValue]; + m_hashTable[hashValue] = i; + } + + + } +} + +b3BroadphasePair* b3HashedOverlappingPairCache::internalAddPair(int proxy0, int proxy1) +{ + if(proxy0>proxy1) + b3Swap(proxy0,proxy1); + int proxyId1 = proxy0; + int proxyId2 = proxy1; + + /*if (proxyId1 > proxyId2) + b3Swap(proxyId1, proxyId2);*/ + + int hash = static_cast(getHash(static_cast(proxyId1),static_cast(proxyId2)) & (m_overlappingPairArray.capacity()-1)); // New hash value with new mask + + + b3BroadphasePair* pair = internalFindPair(proxy0, proxy1, hash); + if (pair != NULL) + { + return pair; + } + /*for(int i=0;i%u\r\n",proxyId1,proxyId2); + internalFindPair(proxy0, proxy1, hash); + } + }*/ + int count = m_overlappingPairArray.size(); + int oldCapacity = m_overlappingPairArray.capacity(); + pair = &m_overlappingPairArray.expandNonInitializing(); + + //this is where we add an actual pair, so also call the 'ghost' +// if (m_ghostPairCallback) +// m_ghostPairCallback->addOverlappingPair(proxy0,proxy1); + + int newCapacity = m_overlappingPairArray.capacity(); + + if (oldCapacity < newCapacity) + { + growTables(); + //hash with new capacity + hash = static_cast(getHash(static_cast(proxyId1),static_cast(proxyId2)) & (m_overlappingPairArray.capacity()-1)); + } + + *pair = b3MakeBroadphasePair(proxy0,proxy1); + +// pair->m_pProxy0 = proxy0; +// pair->m_pProxy1 = proxy1; + //pair->m_algorithm = 0; + //pair->m_internalTmpValue = 0; + + + m_next[count] = m_hashTable[hash]; + m_hashTable[hash] = count; + + return pair; +} + + + +void* b3HashedOverlappingPairCache::removeOverlappingPair(int proxy0, int proxy1,b3Dispatcher* dispatcher) +{ + b3g_removePairs++; + if(proxy0>proxy1) + b3Swap(proxy0,proxy1); + int proxyId1 = proxy0; + int proxyId2 = proxy1; + + /*if (proxyId1 > proxyId2) + b3Swap(proxyId1, proxyId2);*/ + + int hash = static_cast(getHash(static_cast(proxyId1),static_cast(proxyId2)) & (m_overlappingPairArray.capacity()-1)); + + b3BroadphasePair* pair = internalFindPair(proxy0, proxy1, hash); + if (pair == NULL) + { + return 0; + } + + cleanOverlappingPair(*pair,dispatcher); + + + + int pairIndex = int(pair - &m_overlappingPairArray[0]); + b3Assert(pairIndex < m_overlappingPairArray.size()); + + // Remove the pair from the hash table. + int index = m_hashTable[hash]; + b3Assert(index != B3_NULL_PAIR); + + int previous = B3_NULL_PAIR; + while (index != pairIndex) + { + previous = index; + index = m_next[index]; + } + + if (previous != B3_NULL_PAIR) + { + b3Assert(m_next[previous] == pairIndex); + m_next[previous] = m_next[pairIndex]; + } + else + { + m_hashTable[hash] = m_next[pairIndex]; + } + + // We now move the last pair into spot of the + // pair being removed. We need to fix the hash + // table indices to support the move. + + int lastPairIndex = m_overlappingPairArray.size() - 1; + + //if (m_ghostPairCallback) + // m_ghostPairCallback->removeOverlappingPair(proxy0, proxy1,dispatcher); + + // If the removed pair is the last pair, we are done. + if (lastPairIndex == pairIndex) + { + m_overlappingPairArray.pop_back(); + return 0; + } + + // Remove the last pair from the hash table. + const b3BroadphasePair* last = &m_overlappingPairArray[lastPairIndex]; + /* missing swap here too, Nat. */ + int lastHash = static_cast(getHash(static_cast(last->x), static_cast(last->y)) & (m_overlappingPairArray.capacity()-1)); + + index = m_hashTable[lastHash]; + b3Assert(index != B3_NULL_PAIR); + + previous = B3_NULL_PAIR; + while (index != lastPairIndex) + { + previous = index; + index = m_next[index]; + } + + if (previous != B3_NULL_PAIR) + { + b3Assert(m_next[previous] == lastPairIndex); + m_next[previous] = m_next[lastPairIndex]; + } + else + { + m_hashTable[lastHash] = m_next[lastPairIndex]; + } + + // Copy the last pair into the remove pair's spot. + m_overlappingPairArray[pairIndex] = m_overlappingPairArray[lastPairIndex]; + + // Insert the last pair into the hash table + m_next[pairIndex] = m_hashTable[lastHash]; + m_hashTable[lastHash] = pairIndex; + + m_overlappingPairArray.pop_back(); + + return 0; +} +//#include + +void b3HashedOverlappingPairCache::processAllOverlappingPairs(b3OverlapCallback* callback,b3Dispatcher* dispatcher) +{ + + int i; + +// printf("m_overlappingPairArray.size()=%d\n",m_overlappingPairArray.size()); + for (i=0;iprocessOverlap(*pair)) + { + removeOverlappingPair(pair->x,pair->y,dispatcher); + + b3g_overlappingPairs--; + } else + { + i++; + } + } +} + + + + + +void b3HashedOverlappingPairCache::sortOverlappingPairs(b3Dispatcher* dispatcher) +{ + ///need to keep hashmap in sync with pair address, so rebuild all + b3BroadphasePairArray tmpPairs; + int i; + for (i=0;iremoveOverlappingPair(proxy0, proxy1,dispatcher); + + m_overlappingPairArray.swap(findIndex,m_overlappingPairArray.capacity()-1); + m_overlappingPairArray.pop_back(); + return 0; + } + } + + return 0; +} + + + + + + + + +b3BroadphasePair* b3SortedOverlappingPairCache::addOverlappingPair(int proxy0,int proxy1) +{ + //don't add overlap with own + b3Assert(proxy0 != proxy1); + + if (!needsBroadphaseCollision(proxy0,proxy1)) + return 0; + + b3BroadphasePair* pair = &m_overlappingPairArray.expandNonInitializing(); + *pair = b3MakeBroadphasePair(proxy0,proxy1); + + + b3g_overlappingPairs++; + b3g_addedPairs++; + +// if (m_ghostPairCallback) +// m_ghostPairCallback->addOverlappingPair(proxy0, proxy1); + return pair; + +} + +///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 + b3BroadphasePair* b3SortedOverlappingPairCache::findPair(int proxy0,int proxy1) +{ + if (!needsBroadphaseCollision(proxy0,proxy1)) + return 0; + + b3BroadphasePair tmpPair = b3MakeBroadphasePair(proxy0,proxy1); + int findIndex = m_overlappingPairArray.findLinearSearch(tmpPair); + + if (findIndex < m_overlappingPairArray.size()) + { + //b3Assert(it != m_overlappingPairSet.end()); + b3BroadphasePair* pair = &m_overlappingPairArray[findIndex]; + return pair; + } + return 0; +} + + + + + + + + + + +//#include + +void b3SortedOverlappingPairCache::processAllOverlappingPairs(b3OverlapCallback* callback,b3Dispatcher* dispatcher) +{ + + int i; + + for (i=0;iprocessOverlap(*pair)) + { + cleanOverlappingPair(*pair,dispatcher); + pair->x = -1; + pair->y = -1; + m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1); + m_overlappingPairArray.pop_back(); + b3g_overlappingPairs--; + } else + { + i++; + } + } +} + + + + +b3SortedOverlappingPairCache::b3SortedOverlappingPairCache(): + m_blockedForChanges(false), + m_hasDeferredRemoval(true), + m_overlapFilterCallback(0) + +{ + int initialAllocatedSize= 2; + m_overlappingPairArray.reserve(initialAllocatedSize); +} + +b3SortedOverlappingPairCache::~b3SortedOverlappingPairCache() +{ +} + +void b3SortedOverlappingPairCache::cleanOverlappingPair(b3BroadphasePair& pair,b3Dispatcher* dispatcher) +{ +/* if (pair.m_algorithm) + { + { + pair.m_algorithm->~b3CollisionAlgorithm(); + dispatcher->freeCollisionAlgorithm(pair.m_algorithm); + pair.m_algorithm=0; + b3g_removePairs--; + } + } + */ +} + + +void b3SortedOverlappingPairCache::cleanProxyFromPairs(int proxy,b3Dispatcher* dispatcher) +{ + + class CleanPairCallback : public b3OverlapCallback + { + int m_cleanProxy; + b3OverlappingPairCache* m_pairCache; + b3Dispatcher* m_dispatcher; + + public: + CleanPairCallback(int cleanProxy,b3OverlappingPairCache* pairCache,b3Dispatcher* dispatcher) + :m_cleanProxy(cleanProxy), + m_pairCache(pairCache), + m_dispatcher(dispatcher) + { + } + virtual bool processOverlap(b3BroadphasePair& pair) + { + if ((pair.x == m_cleanProxy) || + (pair.y == m_cleanProxy)) + { + m_pairCache->cleanOverlappingPair(pair,m_dispatcher); + } + return false; + } + + }; + + CleanPairCallback cleanPairs(proxy,this,dispatcher); + + processAllOverlappingPairs(&cleanPairs,dispatcher); + +} + + +void b3SortedOverlappingPairCache::removeOverlappingPairsContainingProxy(int proxy,b3Dispatcher* dispatcher) +{ + + class RemovePairCallback : public b3OverlapCallback + { + int m_obsoleteProxy; + + public: + RemovePairCallback(int obsoleteProxy) + :m_obsoleteProxy(obsoleteProxy) + { + } + virtual bool processOverlap(b3BroadphasePair& pair) + { + return ((pair.x == m_obsoleteProxy) || + (pair.y == m_obsoleteProxy)); + } + + }; + + RemovePairCallback removeCallback(proxy); + + processAllOverlappingPairs(&removeCallback,dispatcher); +} + +void b3SortedOverlappingPairCache::sortOverlappingPairs(b3Dispatcher* dispatcher) +{ + //should already be sorted +} + diff --git a/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/b3OverlappingPairCache.h b/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/b3OverlappingPairCache.h new file mode 100644 index 000000000000..f67eb676f1d6 --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/b3OverlappingPairCache.h @@ -0,0 +1,474 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org + +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 B3_OVERLAPPING_PAIR_CACHE_H +#define B3_OVERLAPPING_PAIR_CACHE_H + +#include "Bullet3Common/shared/b3Int2.h" +#include "Bullet3Common/b3AlignedObjectArray.h" + +class b3Dispatcher; +#include "b3OverlappingPair.h" + + + +typedef b3AlignedObjectArray b3BroadphasePairArray; + +struct b3OverlapCallback +{ + virtual ~b3OverlapCallback() + {} + //return true for deletion of the pair + virtual bool processOverlap(b3BroadphasePair& pair) = 0; + +}; + +struct b3OverlapFilterCallback +{ + virtual ~b3OverlapFilterCallback() + {} + // return true when pairs need collision + virtual bool needBroadphaseCollision(int proxy0,int proxy1) const = 0; +}; + + + + + + + +extern int b3g_removePairs; +extern int b3g_addedPairs; +extern int b3g_findPairs; + +const int B3_NULL_PAIR=0xffffffff; + +///The b3OverlappingPairCache provides an interface for overlapping pair management (add, remove, storage), used by the b3BroadphaseInterface broadphases. +///The b3HashedOverlappingPairCache and b3SortedOverlappingPairCache classes are two implementations. +class b3OverlappingPairCache +{ +public: + virtual ~b3OverlappingPairCache() {} // this is needed so we can get to the derived class destructor + + virtual b3BroadphasePair* getOverlappingPairArrayPtr() = 0; + + virtual const b3BroadphasePair* getOverlappingPairArrayPtr() const = 0; + + virtual b3BroadphasePairArray& getOverlappingPairArray() = 0; + + virtual void cleanOverlappingPair(b3BroadphasePair& pair,b3Dispatcher* dispatcher) = 0; + + virtual int getNumOverlappingPairs() const = 0; + + virtual void cleanProxyFromPairs(int proxy,b3Dispatcher* dispatcher) = 0; + + virtual void setOverlapFilterCallback(b3OverlapFilterCallback* callback) = 0; + + virtual void processAllOverlappingPairs(b3OverlapCallback*,b3Dispatcher* dispatcher) = 0; + + virtual b3BroadphasePair* findPair(int proxy0, int proxy1) = 0; + + virtual bool hasDeferredRemoval() = 0; + + //virtual void setInternalGhostPairCallback(b3OverlappingPairCallback* ghostPairCallback)=0; + + virtual b3BroadphasePair* addOverlappingPair(int proxy0,int proxy1)=0; + virtual void* removeOverlappingPair(int proxy0,int proxy1,b3Dispatcher* dispatcher)=0; + virtual void removeOverlappingPairsContainingProxy(int /*proxy0*/,b3Dispatcher* /*dispatcher*/)=0; + + virtual void sortOverlappingPairs(b3Dispatcher* dispatcher) = 0; + + +}; + +/// Hash-space based Pair Cache, thanks to Erin Catto, Box2D, http://www.box2d.org, and Pierre Terdiman, Codercorner, http://codercorner.com +class b3HashedOverlappingPairCache : public b3OverlappingPairCache +{ + b3BroadphasePairArray m_overlappingPairArray; + b3OverlapFilterCallback* m_overlapFilterCallback; +// bool m_blockedForChanges; + + +public: + b3HashedOverlappingPairCache(); + virtual ~b3HashedOverlappingPairCache(); + + + virtual void removeOverlappingPairsContainingProxy(int proxy,b3Dispatcher* dispatcher); + + virtual void* removeOverlappingPair(int proxy0,int proxy1,b3Dispatcher* dispatcher); + + B3_FORCE_INLINE bool needsBroadphaseCollision(int proxy0,int proxy1) const + { + if (m_overlapFilterCallback) + return m_overlapFilterCallback->needBroadphaseCollision(proxy0,proxy1); + + bool collides = true;//(proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0; + //collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask); + + return collides; + } + + // Add a pair and return the new pair. If the pair already exists, + // no new pair is created and the old one is returned. + virtual b3BroadphasePair* addOverlappingPair(int proxy0,int proxy1) + { + b3g_addedPairs++; + + if (!needsBroadphaseCollision(proxy0,proxy1)) + return 0; + + return internalAddPair(proxy0,proxy1); + } + + + + void cleanProxyFromPairs(int proxy,b3Dispatcher* dispatcher); + + + virtual void processAllOverlappingPairs(b3OverlapCallback*,b3Dispatcher* dispatcher); + + virtual b3BroadphasePair* getOverlappingPairArrayPtr() + { + return &m_overlappingPairArray[0]; + } + + const b3BroadphasePair* getOverlappingPairArrayPtr() const + { + return &m_overlappingPairArray[0]; + } + + b3BroadphasePairArray& getOverlappingPairArray() + { + return m_overlappingPairArray; + } + + const b3BroadphasePairArray& getOverlappingPairArray() const + { + return m_overlappingPairArray; + } + + void cleanOverlappingPair(b3BroadphasePair& pair,b3Dispatcher* dispatcher); + + + + b3BroadphasePair* findPair(int proxy0, int proxy1); + + int GetCount() const { return m_overlappingPairArray.size(); } +// b3BroadphasePair* GetPairs() { return m_pairs; } + + b3OverlapFilterCallback* getOverlapFilterCallback() + { + return m_overlapFilterCallback; + } + + void setOverlapFilterCallback(b3OverlapFilterCallback* callback) + { + m_overlapFilterCallback = callback; + } + + int getNumOverlappingPairs() const + { + return m_overlappingPairArray.size(); + } +private: + + b3BroadphasePair* internalAddPair(int proxy0,int proxy1); + + void growTables(); + + B3_FORCE_INLINE bool equalsPair(const b3BroadphasePair& pair, int proxyId1, int proxyId2) + { + return pair.x == proxyId1 && pair.y == proxyId2; + } + + /* + // Thomas Wang's hash, see: http://www.concentric.net/~Ttwang/tech/inthash.htm + // This assumes proxyId1 and proxyId2 are 16-bit. + B3_FORCE_INLINE int getHash(int proxyId1, int proxyId2) + { + int key = (proxyId2 << 16) | proxyId1; + key = ~key + (key << 15); + key = key ^ (key >> 12); + key = key + (key << 2); + key = key ^ (key >> 4); + key = key * 2057; + key = key ^ (key >> 16); + return key; + } + */ + + + + B3_FORCE_INLINE unsigned int getHash(unsigned int proxyId1, unsigned int proxyId2) + { + int key = static_cast(((unsigned int)proxyId1) | (((unsigned int)proxyId2) <<16)); + // Thomas Wang's hash + + key += ~(key << 15); + key ^= (key >> 10); + key += (key << 3); + key ^= (key >> 6); + key += ~(key << 11); + key ^= (key >> 16); + return static_cast(key); + } + + + + + + B3_FORCE_INLINE b3BroadphasePair* internalFindPair(int proxy0, int proxy1, int hash) + { + int proxyId1 = proxy0; + int proxyId2 = proxy1; + #if 0 // wrong, 'equalsPair' use unsorted uids, copy-past devil striked again. Nat. + if (proxyId1 > proxyId2) + b3Swap(proxyId1, proxyId2); + #endif + + int index = m_hashTable[hash]; + + while( index != B3_NULL_PAIR && equalsPair(m_overlappingPairArray[index], proxyId1, proxyId2) == false) + { + index = m_next[index]; + } + + if ( index == B3_NULL_PAIR ) + { + return NULL; + } + + b3Assert(index < m_overlappingPairArray.size()); + + return &m_overlappingPairArray[index]; + } + + virtual bool hasDeferredRemoval() + { + return false; + } + +/* virtual void setInternalGhostPairCallback(b3OverlappingPairCallback* ghostPairCallback) + { + m_ghostPairCallback = ghostPairCallback; + } + */ + + virtual void sortOverlappingPairs(b3Dispatcher* dispatcher); + + +protected: + + b3AlignedObjectArray m_hashTable; + b3AlignedObjectArray m_next; +// b3OverlappingPairCallback* m_ghostPairCallback; + +}; + + + + +///b3SortedOverlappingPairCache maintains the objects with overlapping AABB +///Typically managed by the Broadphase, Axis3Sweep or b3SimpleBroadphase +class b3SortedOverlappingPairCache : public b3OverlappingPairCache +{ + protected: + //avoid brute-force finding all the time + b3BroadphasePairArray m_overlappingPairArray; + + //during the dispatch, check that user doesn't destroy/create proxy + bool m_blockedForChanges; + + ///by default, do the removal during the pair traversal + bool m_hasDeferredRemoval; + + //if set, use the callback instead of the built in filter in needBroadphaseCollision + b3OverlapFilterCallback* m_overlapFilterCallback; + +// b3OverlappingPairCallback* m_ghostPairCallback; + + public: + + b3SortedOverlappingPairCache(); + virtual ~b3SortedOverlappingPairCache(); + + virtual void processAllOverlappingPairs(b3OverlapCallback*,b3Dispatcher* dispatcher); + + void* removeOverlappingPair(int proxy0,int proxy1,b3Dispatcher* dispatcher); + + void cleanOverlappingPair(b3BroadphasePair& pair,b3Dispatcher* dispatcher); + + b3BroadphasePair* addOverlappingPair(int proxy0,int proxy1); + + b3BroadphasePair* findPair(int proxy0,int proxy1); + + + void cleanProxyFromPairs(int proxy,b3Dispatcher* dispatcher); + + virtual void removeOverlappingPairsContainingProxy(int proxy,b3Dispatcher* dispatcher); + + + inline bool needsBroadphaseCollision(int proxy0,int proxy1) const + { + if (m_overlapFilterCallback) + return m_overlapFilterCallback->needBroadphaseCollision(proxy0,proxy1); + + bool collides = true;//(proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0; + //collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask); + + return collides; + } + + b3BroadphasePairArray& getOverlappingPairArray() + { + return m_overlappingPairArray; + } + + const b3BroadphasePairArray& getOverlappingPairArray() const + { + return m_overlappingPairArray; + } + + + + + b3BroadphasePair* getOverlappingPairArrayPtr() + { + return &m_overlappingPairArray[0]; + } + + const b3BroadphasePair* getOverlappingPairArrayPtr() const + { + return &m_overlappingPairArray[0]; + } + + int getNumOverlappingPairs() const + { + return m_overlappingPairArray.size(); + } + + b3OverlapFilterCallback* getOverlapFilterCallback() + { + return m_overlapFilterCallback; + } + + void setOverlapFilterCallback(b3OverlapFilterCallback* callback) + { + m_overlapFilterCallback = callback; + } + + virtual bool hasDeferredRemoval() + { + return m_hasDeferredRemoval; + } + +/* virtual void setInternalGhostPairCallback(b3OverlappingPairCallback* ghostPairCallback) + { + m_ghostPairCallback = ghostPairCallback; + } + */ + virtual void sortOverlappingPairs(b3Dispatcher* dispatcher); + + +}; + + + +///b3NullPairCache skips add/removal of overlapping pairs. Userful for benchmarking and unit testing. +class b3NullPairCache : public b3OverlappingPairCache +{ + + b3BroadphasePairArray m_overlappingPairArray; + +public: + + virtual b3BroadphasePair* getOverlappingPairArrayPtr() + { + return &m_overlappingPairArray[0]; + } + const b3BroadphasePair* getOverlappingPairArrayPtr() const + { + return &m_overlappingPairArray[0]; + } + b3BroadphasePairArray& getOverlappingPairArray() + { + return m_overlappingPairArray; + } + + virtual void cleanOverlappingPair(b3BroadphasePair& /*pair*/,b3Dispatcher* /*dispatcher*/) + { + + } + + virtual int getNumOverlappingPairs() const + { + return 0; + } + + virtual void cleanProxyFromPairs(int /*proxy*/,b3Dispatcher* /*dispatcher*/) + { + + } + + virtual void setOverlapFilterCallback(b3OverlapFilterCallback* /*callback*/) + { + } + + virtual void processAllOverlappingPairs(b3OverlapCallback*,b3Dispatcher* /*dispatcher*/) + { + } + + virtual b3BroadphasePair* findPair(int /*proxy0*/, int /*proxy1*/) + { + return 0; + } + + virtual bool hasDeferredRemoval() + { + return true; + } + +// virtual void setInternalGhostPairCallback(b3OverlappingPairCallback* /* ghostPairCallback */) +// { +// +// } + + virtual b3BroadphasePair* addOverlappingPair(int /*proxy0*/,int /*proxy1*/) + { + return 0; + } + + virtual void* removeOverlappingPair(int /*proxy0*/,int /*proxy1*/,b3Dispatcher* /*dispatcher*/) + { + return 0; + } + + virtual void removeOverlappingPairsContainingProxy(int /*proxy0*/,b3Dispatcher* /*dispatcher*/) + { + } + + virtual void sortOverlappingPairs(b3Dispatcher* dispatcher) + { + (void) dispatcher; + } + + +}; + + +#endif //B3_OVERLAPPING_PAIR_CACHE_H + + diff --git a/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/shared/b3Aabb.h b/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/shared/b3Aabb.h new file mode 100644 index 000000000000..7f9bf990bfc2 --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/BroadPhaseCollision/shared/b3Aabb.h @@ -0,0 +1,59 @@ + +#ifndef B3_AABB_H +#define B3_AABB_H + + +#include "Bullet3Common/shared/b3Float4.h" +#include "Bullet3Common/shared/b3Mat3x3.h" + +typedef struct b3Aabb b3Aabb_t; + +struct b3Aabb +{ + union + { + float m_min[4]; + b3Float4 m_minVec; + int m_minIndices[4]; + }; + union + { + float m_max[4]; + b3Float4 m_maxVec; + int m_signedMaxIndices[4]; + }; +}; + +inline void b3TransformAabb2(b3Float4ConstArg localAabbMin,b3Float4ConstArg localAabbMax, float margin, + b3Float4ConstArg pos, + b3QuatConstArg orn, + b3Float4* aabbMinOut,b3Float4* aabbMaxOut) +{ + b3Float4 localHalfExtents = 0.5f*(localAabbMax-localAabbMin); + localHalfExtents+=b3MakeFloat4(margin,margin,margin,0.f); + b3Float4 localCenter = 0.5f*(localAabbMax+localAabbMin); + b3Mat3x3 m; + m = b3QuatGetRotationMatrix(orn); + b3Mat3x3 abs_b = b3AbsoluteMat3x3(m); + b3Float4 center = b3TransformPoint(localCenter,pos,orn); + + b3Float4 extent = b3MakeFloat4(b3Dot3F4(localHalfExtents,b3GetRow(abs_b,0)), + b3Dot3F4(localHalfExtents,b3GetRow(abs_b,1)), + b3Dot3F4(localHalfExtents,b3GetRow(abs_b,2)), + 0.f); + *aabbMinOut = center-extent; + *aabbMaxOut = center+extent; +} + +/// conservative test for overlap between two aabbs +inline bool b3TestAabbAgainstAabb(b3Float4ConstArg aabbMin1,b3Float4ConstArg aabbMax1, + b3Float4ConstArg aabbMin2, b3Float4ConstArg aabbMax2) +{ + bool overlap = true; + overlap = (aabbMin1.x > aabbMax2.x || aabbMax1.x < aabbMin2.x) ? false : overlap; + overlap = (aabbMin1.z > aabbMax2.z || aabbMax1.z < aabbMin2.z) ? false : overlap; + overlap = (aabbMin1.y > aabbMax2.y || aabbMax1.y < aabbMin2.y) ? false : overlap; + return overlap; +} + +#endif //B3_AABB_H diff --git a/extern/bullet/src/Bullet3Collision/CMakeLists.txt b/extern/bullet/src/Bullet3Collision/CMakeLists.txt new file mode 100644 index 000000000000..130095cc04ec --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/CMakeLists.txt @@ -0,0 +1,93 @@ + +INCLUDE_DIRECTORIES( + ${BULLET_PHYSICS_SOURCE_DIR}/src +) + +SET(Bullet3Collision_SRCS + BroadPhaseCollision/b3DynamicBvh.cpp + BroadPhaseCollision/b3DynamicBvhBroadphase.cpp + BroadPhaseCollision/b3OverlappingPairCache.cpp + NarrowPhaseCollision/b3ConvexUtility.cpp + NarrowPhaseCollision/b3CpuNarrowPhase.cpp +) + +SET(Bullet3CollisionBroadPhase_HDRS + BroadPhaseCollision/b3BroadphaseCallback.h + BroadPhaseCollision/b3DynamicBvh.h + BroadPhaseCollision/b3DynamicBvhBroadphase.h + BroadPhaseCollision/b3OverlappingPair.h + BroadPhaseCollision/b3OverlappingPairCache.h +) +SET(Bullet3CollisionBroadPhaseShared_HDRS + BroadPhaseCollision/shared/b3Aabb.h +) + +SET(Bullet3CollisionNarrowPhase_HDRS + NarrowPhaseCollision/b3Config.h + NarrowPhaseCollision/b3Contact4.h + NarrowPhaseCollision/b3ConvexUtility.h + NarrowPhaseCollision/b3CpuNarrowPhase.h + NarrowPhaseCollision/b3RaycastInfo.h + NarrowPhaseCollision/b3RigidBodyCL.h +) +SET(Bullet3CollisionNarrowPhaseShared_HDRS + + NarrowPhaseCollision/shared/b3BvhSubtreeInfoData.h + NarrowPhaseCollision/shared/b3BvhTraversal.h + NarrowPhaseCollision/shared/b3ClipFaces.h + NarrowPhaseCollision/shared/b3Collidable.h + NarrowPhaseCollision/shared/b3Contact4Data.h + NarrowPhaseCollision/shared/b3ContactConvexConvexSAT.h + NarrowPhaseCollision/shared/b3ContactSphereSphere.h + NarrowPhaseCollision/shared/b3ConvexPolyhedronData.h + NarrowPhaseCollision/shared/b3FindConcaveSatAxis.h + NarrowPhaseCollision/shared/b3FindSeparatingAxis.h + NarrowPhaseCollision/shared/b3MprPenetration.h + NarrowPhaseCollision/shared/b3NewContactReduction.h + NarrowPhaseCollision/shared/b3QuantizedBvhNodeData.h + NarrowPhaseCollision/shared/b3ReduceContacts.h + NarrowPhaseCollision/shared/b3RigidBodyData.h + NarrowPhaseCollision/shared/b3UpdateAabbs.h +) + +SET(Bullet3Collision_HDRS + ${Bullet3CollisionBroadPhase_HDRS} + ${Bullet3CollisionBroadPhaseShared_HDRS} + ${Bullet3CollisionNarrowPhaseShared_HDRS} + ${Bullet3CollisionNarrowPhase_HDRS} +) + +ADD_LIBRARY(Bullet3Collision ${Bullet3Collision_SRCS} ${Bullet3Collision_HDRS}) +if (BUILD_SHARED_LIBS) + target_link_libraries(Bullet3Collision Bullet3Geometry) +endif () +SET_TARGET_PROPERTIES(Bullet3Collision PROPERTIES VERSION ${BULLET_VERSION}) +SET_TARGET_PROPERTIES(Bullet3Collision PROPERTIES SOVERSION ${BULLET_VERSION}) + +IF (INSTALL_LIBS) + IF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) + #FILES_MATCHING requires CMake 2.6 + IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS Bullet3Collision DESTINATION .) + ELSE (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS Bullet3Collision + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib${LIB_SUFFIX} + ARCHIVE DESTINATION lib${LIB_SUFFIX}) + INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.h" PATTERN +".svn" EXCLUDE PATTERN "CMakeFiles" EXCLUDE) + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + SET_TARGET_PROPERTIES(Bullet3Collision PROPERTIES FRAMEWORK true) + SET_TARGET_PROPERTIES(Bullet3Collision PROPERTIES PUBLIC_HEADER "${Bullet3Collision_HDRS}") + # Have to list out sub-directories manually: + #todo + #SET_PROPERTY(SOURCE ${Bullet3CollisionBroadPhase_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/BroadPhaseCollision) + + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) +ENDIF (INSTALL_LIBS) diff --git a/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/b3Config.h b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/b3Config.h new file mode 100644 index 000000000000..65d4a21613a5 --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/b3Config.h @@ -0,0 +1,41 @@ +#ifndef B3_CONFIG_H +#define B3_CONFIG_H + +struct b3Config +{ + int m_maxConvexBodies; + int m_maxConvexShapes; + int m_maxBroadphasePairs; + int m_maxContactCapacity; + int m_compoundPairCapacity; + + int m_maxVerticesPerFace; + int m_maxFacesPerShape; + int m_maxConvexVertices; + int m_maxConvexIndices; + int m_maxConvexUniqueEdges; + + int m_maxCompoundChildShapes; + + int m_maxTriConvexPairCapacity; + + b3Config() + :m_maxConvexBodies(128*1024), + m_maxVerticesPerFace(64), + m_maxFacesPerShape(12), + m_maxConvexVertices(8192), + m_maxConvexIndices(81920), + m_maxConvexUniqueEdges(8192), + m_maxCompoundChildShapes(8192), + m_maxTriConvexPairCapacity(256*1024) + { + m_maxConvexShapes = m_maxConvexBodies; + m_maxBroadphasePairs = 16*m_maxConvexBodies; + m_maxContactCapacity = m_maxBroadphasePairs; + m_compoundPairCapacity = 1024*1024; + } +}; + + +#endif//B3_CONFIG_H + diff --git a/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/b3Contact4.h b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/b3Contact4.h new file mode 100644 index 000000000000..fb2516567316 --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/b3Contact4.h @@ -0,0 +1,46 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org + +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 B3_CONTACT4_H +#define B3_CONTACT4_H + +#include "Bullet3Common/b3Vector3.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3Contact4Data.h" + +B3_ATTRIBUTE_ALIGNED16(struct) b3Contact4 : public b3Contact4Data +{ + B3_DECLARE_ALIGNED_ALLOCATOR(); + + int getBodyA()const {return abs(m_bodyAPtrAndSignBit);} + int getBodyB()const {return abs(m_bodyBPtrAndSignBit);} + bool isBodyAFixed()const { return m_bodyAPtrAndSignBit<0;} + bool isBodyBFixed()const { return m_bodyBPtrAndSignBit<0;} + // todo. make it safer + int& getBatchIdx() { return m_batchIdx; } + const int& getBatchIdx() const { return m_batchIdx; } + float getRestituitionCoeff() const { return ((float)m_restituitionCoeffCmp/(float)0xffff); } + void setRestituitionCoeff( float c ) { b3Assert( c >= 0.f && c <= 1.f ); m_restituitionCoeffCmp = (unsigned short)(c*0xffff); } + float getFrictionCoeff() const { return ((float)m_frictionCoeffCmp/(float)0xffff); } + void setFrictionCoeff( float c ) { b3Assert( c >= 0.f && c <= 1.f ); m_frictionCoeffCmp = (unsigned short)(c*0xffff); } + + //float& getNPoints() { return m_worldNormal[3]; } + int getNPoints() const { return (int) m_worldNormalOnB.w; } + + float getPenetration(int idx) const { return m_worldPosB[idx].w; } + + bool isInvalid() const { return (getBodyA()==0 || getBodyB()==0); } +}; + +#endif //B3_CONTACT4_H diff --git a/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/b3ConvexUtility.cpp b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/b3ConvexUtility.cpp new file mode 100644 index 000000000000..55706fa63136 --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/b3ConvexUtility.cpp @@ -0,0 +1,520 @@ +/* +Copyright (c) 2012 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Erwin Coumans + + +#include "b3ConvexUtility.h" +#include "Bullet3Geometry/b3ConvexHullComputer.h" +#include "Bullet3Geometry/b3GrahamScan2dConvexHull.h" +#include "Bullet3Common/b3Quaternion.h" +#include "Bullet3Common/b3HashMap.h" + + + + + +b3ConvexUtility::~b3ConvexUtility() +{ +} + +bool b3ConvexUtility::initializePolyhedralFeatures(const b3Vector3* orgVertices, int numPoints, bool mergeCoplanarTriangles) +{ + + + + b3ConvexHullComputer conv; + conv.compute(&orgVertices[0].getX(), sizeof(b3Vector3),numPoints,0.f,0.f); + + b3AlignedObjectArray faceNormals; + int numFaces = conv.faces.size(); + faceNormals.resize(numFaces); + b3ConvexHullComputer* convexUtil = &conv; + + + b3AlignedObjectArray tmpFaces; + tmpFaces.resize(numFaces); + + int numVertices = convexUtil->vertices.size(); + m_vertices.resize(numVertices); + for (int p=0;pvertices[p]; + } + + + for (int i=0;ifaces[i]; + //printf("face=%d\n",face); + const b3ConvexHullComputer::Edge* firstEdge = &convexUtil->edges[face]; + const b3ConvexHullComputer::Edge* edge = firstEdge; + + b3Vector3 edges[3]; + int numEdges = 0; + //compute face normals + + do + { + + int src = edge->getSourceVertex(); + tmpFaces[i].m_indices.push_back(src); + int targ = edge->getTargetVertex(); + b3Vector3 wa = convexUtil->vertices[src]; + + b3Vector3 wb = convexUtil->vertices[targ]; + b3Vector3 newEdge = wb-wa; + newEdge.normalize(); + if (numEdges<2) + edges[numEdges++] = newEdge; + + edge = edge->getNextEdgeOfFace(); + } while (edge!=firstEdge); + + b3Scalar planeEq = 1e30f; + + + if (numEdges==2) + { + faceNormals[i] = edges[0].cross(edges[1]); + faceNormals[i].normalize(); + tmpFaces[i].m_plane[0] = faceNormals[i].getX(); + tmpFaces[i].m_plane[1] = faceNormals[i].getY(); + tmpFaces[i].m_plane[2] = faceNormals[i].getZ(); + tmpFaces[i].m_plane[3] = planeEq; + + } + else + { + b3Assert(0);//degenerate? + faceNormals[i].setZero(); + } + + for (int v=0;veq) + { + planeEq=eq; + } + } + tmpFaces[i].m_plane[3] = -planeEq; + } + + //merge coplanar faces and copy them to m_polyhedron + + b3Scalar faceWeldThreshold= 0.999f; + b3AlignedObjectArray todoFaces; + for (int i=0;i coplanarFaceGroup; + int refFace = todoFaces[todoFaces.size()-1]; + + coplanarFaceGroup.push_back(refFace); + b3MyFace& faceA = tmpFaces[refFace]; + todoFaces.pop_back(); + + b3Vector3 faceNormalA = b3MakeVector3(faceA.m_plane[0],faceA.m_plane[1],faceA.m_plane[2]); + for (int j=todoFaces.size()-1;j>=0;j--) + { + int i = todoFaces[j]; + b3MyFace& faceB = tmpFaces[i]; + b3Vector3 faceNormalB = b3MakeVector3(faceB.m_plane[0],faceB.m_plane[1],faceB.m_plane[2]); + if (faceNormalA.dot(faceNormalB)>faceWeldThreshold) + { + coplanarFaceGroup.push_back(i); + todoFaces.remove(i); + } + } + + + bool did_merge = false; + if (coplanarFaceGroup.size()>1) + { + //do the merge: use Graham Scan 2d convex hull + + b3AlignedObjectArray orgpoints; + b3Vector3 averageFaceNormal = b3MakeVector3(0,0,0); + + for (int i=0;im_faces.push_back(tmpFaces[coplanarFaceGroup[i]]); + + b3MyFace& face = tmpFaces[coplanarFaceGroup[i]]; + b3Vector3 faceNormal = b3MakeVector3(face.m_plane[0],face.m_plane[1],face.m_plane[2]); + averageFaceNormal+=faceNormal; + for (int f=0;f hull; + + averageFaceNormal.normalize(); + b3GrahamScanConvexHull2D(orgpoints,hull,averageFaceNormal); + + for (int i=0;i1e-6 || fabsf(v.getY())>1e-6 || fabsf(v.getZ())>1e-6) return false; + return true; +} + +struct b3InternalVertexPair +{ + b3InternalVertexPair(short int v0,short int v1) + :m_v0(v0), + m_v1(v1) + { + if (m_v1>m_v0) + b3Swap(m_v0,m_v1); + } + short int m_v0; + short int m_v1; + int getHash() const + { + return m_v0+(m_v1<<16); + } + bool equals(const b3InternalVertexPair& other) const + { + return m_v0==other.m_v0 && m_v1==other.m_v1; + } +}; + +struct b3InternalEdge +{ + b3InternalEdge() + :m_face0(-1), + m_face1(-1) + { + } + short int m_face0; + short int m_face1; +}; + +// + +#ifdef TEST_INTERNAL_OBJECTS +bool b3ConvexUtility::testContainment() const +{ + for(int p=0;p<8;p++) + { + b3Vector3 LocalPt; + if(p==0) LocalPt = m_localCenter + b3Vector3(m_extents[0], m_extents[1], m_extents[2]); + else if(p==1) LocalPt = m_localCenter + b3Vector3(m_extents[0], m_extents[1], -m_extents[2]); + else if(p==2) LocalPt = m_localCenter + b3Vector3(m_extents[0], -m_extents[1], m_extents[2]); + else if(p==3) LocalPt = m_localCenter + b3Vector3(m_extents[0], -m_extents[1], -m_extents[2]); + else if(p==4) LocalPt = m_localCenter + b3Vector3(-m_extents[0], m_extents[1], m_extents[2]); + else if(p==5) LocalPt = m_localCenter + b3Vector3(-m_extents[0], m_extents[1], -m_extents[2]); + else if(p==6) LocalPt = m_localCenter + b3Vector3(-m_extents[0], -m_extents[1], m_extents[2]); + else if(p==7) LocalPt = m_localCenter + b3Vector3(-m_extents[0], -m_extents[1], -m_extents[2]); + + for(int i=0;i0.0f) + return false; + } + } + return true; +} +#endif + +void b3ConvexUtility::initialize() +{ + + b3HashMap edges; + + b3Scalar TotalArea = 0.0f; + + m_localCenter.setValue(0, 0, 0); + for(int i=0;im_face0>=0); + // b3Assert(edptr->m_face1<0); + edptr->m_face1 = i; + } else + { + b3InternalEdge ed; + ed.m_face0 = i; + edges.insert(vp,ed); + } + } + } + +#ifdef USE_CONNECTED_FACES + for(int i=0;im_face0>=0); + b3Assert(edptr->m_face1>=0); + + int connectedFace = (edptr->m_face0==i)?edptr->m_face1:edptr->m_face0; + m_faces[i].m_connectedFaces[j] = connectedFace; + } + } +#endif//USE_CONNECTED_FACES + + for(int i=0;iMaxX) MaxX = pt.getX(); + if(pt.getY()MaxY) MaxY = pt.getY(); + if(pt.getZ()MaxZ) MaxZ = pt.getZ(); + } + mC.setValue(MaxX+MinX, MaxY+MinY, MaxZ+MinZ); + mE.setValue(MaxX-MinX, MaxY-MinY, MaxZ-MinZ); + + + +// const b3Scalar r = m_radius / sqrtf(2.0f); + const b3Scalar r = m_radius / sqrtf(3.0f); + const int LargestExtent = mE.maxAxis(); + const b3Scalar Step = (mE[LargestExtent]*0.5f - r)/1024.0f; + m_extents[0] = m_extents[1] = m_extents[2] = r; + m_extents[LargestExtent] = mE[LargestExtent]*0.5f; + bool FoundBox = false; + for(int j=0;j<1024;j++) + { + if(testContainment()) + { + FoundBox = true; + break; + } + + m_extents[LargestExtent] -= Step; + } + if(!FoundBox) + { + m_extents[0] = m_extents[1] = m_extents[2] = r; + } + else + { + // Refine the box + const b3Scalar Step = (m_radius - r)/1024.0f; + const int e0 = (1< m_indices; + b3Scalar m_plane[4]; +}; + +B3_ATTRIBUTE_ALIGNED16(class) b3ConvexUtility +{ + public: + B3_DECLARE_ALIGNED_ALLOCATOR(); + + b3Vector3 m_localCenter; + b3Vector3 m_extents; + b3Vector3 mC; + b3Vector3 mE; + b3Scalar m_radius; + + b3AlignedObjectArray m_vertices; + b3AlignedObjectArray m_faces; + b3AlignedObjectArray m_uniqueEdges; + + + b3ConvexUtility() + { + } + virtual ~b3ConvexUtility(); + + bool initializePolyhedralFeatures(const b3Vector3* orgVertices, int numVertices, bool mergeCoplanarTriangles=true); + + void initialize(); + bool testContainment() const; + + + +}; +#endif + \ No newline at end of file diff --git a/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/b3CpuNarrowPhase.cpp b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/b3CpuNarrowPhase.cpp new file mode 100644 index 000000000000..c3134b2c6594 --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/b3CpuNarrowPhase.cpp @@ -0,0 +1,323 @@ +#include "b3CpuNarrowPhase.h" +#include "Bullet3Collision/NarrowPhaseCollision/b3ConvexUtility.h" +#include "Bullet3Collision/NarrowPhaseCollision/b3Config.h" + +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3ConvexPolyhedronData.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3ContactConvexConvexSAT.h" + + +struct b3CpuNarrowPhaseInternalData +{ + b3AlignedObjectArray m_localShapeAABBCPU; + b3AlignedObjectArray m_collidablesCPU; + b3AlignedObjectArray m_convexData; + b3Config m_config; + + + b3AlignedObjectArray m_convexPolyhedra; + b3AlignedObjectArray m_uniqueEdges; + b3AlignedObjectArray m_convexVertices; + b3AlignedObjectArray m_convexIndices; + b3AlignedObjectArray m_convexFaces; + + b3AlignedObjectArray m_contacts; + + int m_numAcceleratedShapes; +}; + + +const b3AlignedObjectArray& b3CpuNarrowPhase::getContacts() const +{ + return m_data->m_contacts; +} + +b3Collidable& b3CpuNarrowPhase::getCollidableCpu(int collidableIndex) +{ + return m_data->m_collidablesCPU[collidableIndex]; +} + +const b3Collidable& b3CpuNarrowPhase::getCollidableCpu(int collidableIndex) const +{ + return m_data->m_collidablesCPU[collidableIndex]; +} + + +b3CpuNarrowPhase::b3CpuNarrowPhase(const struct b3Config& config) +{ + m_data = new b3CpuNarrowPhaseInternalData; + m_data->m_config = config; + m_data->m_numAcceleratedShapes = 0; +} + +b3CpuNarrowPhase::~b3CpuNarrowPhase() +{ + delete m_data; +} + +void b3CpuNarrowPhase::computeContacts(b3AlignedObjectArray& pairs, b3AlignedObjectArray& aabbsWorldSpace, b3AlignedObjectArray& bodies) +{ + int nPairs = pairs.size(); + int numContacts = 0; + int maxContactCapacity = m_data->m_config.m_maxContactCapacity; + m_data->m_contacts.resize(maxContactCapacity); + + for (int i=0;im_collidablesCPU[collidableIndexA].m_shapeType == SHAPE_SPHERE && + m_data->m_collidablesCPU[collidableIndexB].m_shapeType == SHAPE_CONVEX_HULL) + { +// computeContactSphereConvex(i,bodyIndexA,bodyIndexB,collidableIndexA,collidableIndexB,&bodies[0], +// &m_data->m_collidablesCPU[0],&hostConvexData[0],&hostVertices[0],&hostIndices[0],&hostFaces[0],&hostContacts[0],nContacts,maxContactCapacity); + } + + if (m_data->m_collidablesCPU[collidableIndexA].m_shapeType == SHAPE_CONVEX_HULL && + m_data->m_collidablesCPU[collidableIndexB].m_shapeType == SHAPE_SPHERE) + { +// computeContactSphereConvex(i,bodyIndexB,bodyIndexA,collidableIndexB,collidableIndexA,&bodies[0], +// &m_data->m_collidablesCPU[0],&hostConvexData[0],&hostVertices[0],&hostIndices[0],&hostFaces[0],&hostContacts[0],nContacts,maxContactCapacity); + //printf("convex-sphere\n"); + + } + + if (m_data->m_collidablesCPU[collidableIndexA].m_shapeType == SHAPE_CONVEX_HULL && + m_data->m_collidablesCPU[collidableIndexB].m_shapeType == SHAPE_PLANE) + { +// computeContactPlaneConvex(i,bodyIndexB,bodyIndexA,collidableIndexB,collidableIndexA,&bodies[0], +// &m_data->m_collidablesCPU[0],&hostConvexData[0],&hostVertices[0],&hostIndices[0],&hostFaces[0],&hostContacts[0],nContacts,maxContactCapacity); +// printf("convex-plane\n"); + + } + + if (m_data->m_collidablesCPU[collidableIndexA].m_shapeType == SHAPE_PLANE && + m_data->m_collidablesCPU[collidableIndexB].m_shapeType == SHAPE_CONVEX_HULL) + { +// computeContactPlaneConvex(i,bodyIndexA,bodyIndexB,collidableIndexA,collidableIndexB,&bodies[0], +// &m_data->m_collidablesCPU[0],&hostConvexData[0],&hostVertices[0],&hostIndices[0],&hostFaces[0],&hostContacts[0],nContacts,maxContactCapacity); +// printf("plane-convex\n"); + + } + + if (m_data->m_collidablesCPU[collidableIndexA].m_shapeType == SHAPE_COMPOUND_OF_CONVEX_HULLS && + m_data->m_collidablesCPU[collidableIndexB].m_shapeType == SHAPE_COMPOUND_OF_CONVEX_HULLS) + { +// computeContactCompoundCompound(i,bodyIndexB,bodyIndexA,collidableIndexB,collidableIndexA,&bodies[0], +// &m_data->m_collidablesCPU[0],&hostConvexData[0],&cpuChildShapes[0], hostAabbsWorldSpace,hostAabbsLocalSpace,hostVertices,hostUniqueEdges,hostIndices,hostFaces,&hostContacts[0], +// nContacts,maxContactCapacity,treeNodesCPU,subTreesCPU,bvhInfoCPU); +// printf("convex-plane\n"); + + } + + + if (m_data->m_collidablesCPU[collidableIndexA].m_shapeType == SHAPE_COMPOUND_OF_CONVEX_HULLS && + m_data->m_collidablesCPU[collidableIndexB].m_shapeType == SHAPE_PLANE) + { +// computeContactPlaneCompound(i,bodyIndexB,bodyIndexA,collidableIndexB,collidableIndexA,&bodies[0], +// &m_data->m_collidablesCPU[0],&hostConvexData[0],&cpuChildShapes[0], &hostVertices[0],&hostIndices[0],&hostFaces[0],&hostContacts[0],nContacts,maxContactCapacity); +// printf("convex-plane\n"); + + } + + if (m_data->m_collidablesCPU[collidableIndexA].m_shapeType == SHAPE_PLANE && + m_data->m_collidablesCPU[collidableIndexB].m_shapeType == SHAPE_COMPOUND_OF_CONVEX_HULLS) + { +// computeContactPlaneCompound(i,bodyIndexA,bodyIndexB,collidableIndexA,collidableIndexB,&bodies[0], +// &m_data->m_collidablesCPU[0],&hostConvexData[0],&cpuChildShapes[0],&hostVertices[0],&hostIndices[0],&hostFaces[0],&hostContacts[0],nContacts,maxContactCapacity); +// printf("plane-convex\n"); + + } + + if (m_data->m_collidablesCPU[collidableIndexA].m_shapeType == SHAPE_CONVEX_HULL && + m_data->m_collidablesCPU[collidableIndexB].m_shapeType == SHAPE_CONVEX_HULL) + { + //printf("pairs[i].z=%d\n",pairs[i].z); + //int contactIndex = computeContactConvexConvex2(i,bodyIndexA,bodyIndexB,collidableIndexA,collidableIndexB,bodies, + // m_data->m_collidablesCPU,hostConvexData,hostVertices,hostUniqueEdges,hostIndices,hostFaces,hostContacts,nContacts,maxContactCapacity,oldHostContacts); + int contactIndex = b3ContactConvexConvexSAT(i,bodyIndexA,bodyIndexB,collidableIndexA,collidableIndexB,bodies, + m_data->m_collidablesCPU,m_data->m_convexPolyhedra,m_data->m_convexVertices,m_data->m_uniqueEdges,m_data->m_convexIndices,m_data->m_convexFaces,m_data->m_contacts,numContacts,maxContactCapacity); + + + if (contactIndex>=0) + { + pairs[i].z = contactIndex; + } +// printf("plane-convex\n"); + + } + + + } + + m_data->m_contacts.resize(numContacts); +} + +int b3CpuNarrowPhase::registerConvexHullShape(b3ConvexUtility* utilPtr) +{ + int collidableIndex = allocateCollidable(); + if (collidableIndex<0) + return collidableIndex; + + + b3Collidable& col = m_data->m_collidablesCPU[collidableIndex]; + col.m_shapeType = SHAPE_CONVEX_HULL; + col.m_shapeIndex = -1; + + + { + b3Vector3 localCenter=b3MakeVector3(0,0,0); + for (int i=0;im_vertices.size();i++) + localCenter+=utilPtr->m_vertices[i]; + localCenter*= (1.f/utilPtr->m_vertices.size()); + utilPtr->m_localCenter = localCenter; + + col.m_shapeIndex = registerConvexHullShapeInternal(utilPtr,col); + } + + if (col.m_shapeIndex>=0) + { + b3Aabb aabb; + + b3Vector3 myAabbMin=b3MakeVector3(1e30f,1e30f,1e30f); + b3Vector3 myAabbMax=b3MakeVector3(-1e30f,-1e30f,-1e30f); + + for (int i=0;im_vertices.size();i++) + { + myAabbMin.setMin(utilPtr->m_vertices[i]); + myAabbMax.setMax(utilPtr->m_vertices[i]); + } + aabb.m_min[0] = myAabbMin[0]; + aabb.m_min[1] = myAabbMin[1]; + aabb.m_min[2] = myAabbMin[2]; + aabb.m_minIndices[3] = 0; + + aabb.m_max[0] = myAabbMax[0]; + aabb.m_max[1] = myAabbMax[1]; + aabb.m_max[2] = myAabbMax[2]; + aabb.m_signedMaxIndices[3] = 0; + + m_data->m_localShapeAABBCPU.push_back(aabb); + + } + + return collidableIndex; +} + +int b3CpuNarrowPhase::allocateCollidable() +{ + int curSize = m_data->m_collidablesCPU.size(); + if (curSizem_config.m_maxConvexShapes) + { + m_data->m_collidablesCPU.expand(); + return curSize; + } + else + { + b3Error("allocateCollidable out-of-range %d\n",m_data->m_config.m_maxConvexShapes); + } + return -1; + +} + +int b3CpuNarrowPhase::registerConvexHullShape(const float* vertices, int strideInBytes, int numVertices, const float* scaling) +{ + b3AlignedObjectArray verts; + + unsigned char* vts = (unsigned char*) vertices; + for (int i=0;iinitializePolyhedralFeatures(&verts[0],verts.size(),merge); + } + + int collidableIndex = registerConvexHullShape(utilPtr); + + delete utilPtr; + return collidableIndex; +} + + +int b3CpuNarrowPhase::registerConvexHullShapeInternal(b3ConvexUtility* convexPtr,b3Collidable& col) +{ + + m_data->m_convexData.resize(m_data->m_numAcceleratedShapes+1); + m_data->m_convexPolyhedra.resize(m_data->m_numAcceleratedShapes+1); + + + b3ConvexPolyhedronData& convex = m_data->m_convexPolyhedra.at(m_data->m_convexPolyhedra.size()-1); + convex.mC = convexPtr->mC; + convex.mE = convexPtr->mE; + convex.m_extents= convexPtr->m_extents; + convex.m_localCenter = convexPtr->m_localCenter; + convex.m_radius = convexPtr->m_radius; + + convex.m_numUniqueEdges = convexPtr->m_uniqueEdges.size(); + int edgeOffset = m_data->m_uniqueEdges.size(); + convex.m_uniqueEdgesOffset = edgeOffset; + + m_data->m_uniqueEdges.resize(edgeOffset+convex.m_numUniqueEdges); + + //convex data here + int i; + for ( i=0;im_uniqueEdges.size();i++) + { + m_data->m_uniqueEdges[edgeOffset+i] = convexPtr->m_uniqueEdges[i]; + } + + int faceOffset = m_data->m_convexFaces.size(); + convex.m_faceOffset = faceOffset; + convex.m_numFaces = convexPtr->m_faces.size(); + + m_data->m_convexFaces.resize(faceOffset+convex.m_numFaces); + + + for (i=0;im_faces.size();i++) + { + m_data->m_convexFaces[convex.m_faceOffset+i].m_plane = b3MakeVector3(convexPtr->m_faces[i].m_plane[0], + convexPtr->m_faces[i].m_plane[1], + convexPtr->m_faces[i].m_plane[2], + convexPtr->m_faces[i].m_plane[3]); + + + int indexOffset = m_data->m_convexIndices.size(); + int numIndices = convexPtr->m_faces[i].m_indices.size(); + m_data->m_convexFaces[convex.m_faceOffset+i].m_numIndices = numIndices; + m_data->m_convexFaces[convex.m_faceOffset+i].m_indexOffset = indexOffset; + m_data->m_convexIndices.resize(indexOffset+numIndices); + for (int p=0;pm_convexIndices[indexOffset+p] = convexPtr->m_faces[i].m_indices[p]; + } + } + + convex.m_numVertices = convexPtr->m_vertices.size(); + int vertexOffset = m_data->m_convexVertices.size(); + convex.m_vertexOffset =vertexOffset; + + m_data->m_convexVertices.resize(vertexOffset+convex.m_numVertices); + for (int i=0;im_vertices.size();i++) + { + m_data->m_convexVertices[vertexOffset+i] = convexPtr->m_vertices[i]; + } + + (m_data->m_convexData)[m_data->m_numAcceleratedShapes] = convexPtr; + + + + return m_data->m_numAcceleratedShapes++; +} + +const b3Aabb& b3CpuNarrowPhase::getLocalSpaceAabb(int collidableIndex) const +{ + return m_data->m_localShapeAABBCPU[collidableIndex]; +} diff --git a/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/b3CpuNarrowPhase.h b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/b3CpuNarrowPhase.h new file mode 100644 index 000000000000..528be3346de7 --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/b3CpuNarrowPhase.h @@ -0,0 +1,105 @@ +#ifndef B3_CPU_NARROWPHASE_H +#define B3_CPU_NARROWPHASE_H + +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3Collidable.h" +#include "Bullet3Common/b3AlignedObjectArray.h" +#include "Bullet3Common/b3Vector3.h" +#include "Bullet3Collision/BroadPhaseCollision/shared/b3Aabb.h" +#include "Bullet3Common/shared/b3Int4.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3Contact4Data.h" + +class b3CpuNarrowPhase +{ +protected: + + struct b3CpuNarrowPhaseInternalData* m_data; + int m_acceleratedCompanionShapeIndex; + int m_planeBodyIndex; + int m_static0Index; + + int registerConvexHullShapeInternal(class b3ConvexUtility* convexPtr,b3Collidable& col); + int registerConcaveMeshShape(b3AlignedObjectArray* vertices, b3AlignedObjectArray* indices, b3Collidable& col, const float* scaling); + +public: + + + + + b3CpuNarrowPhase(const struct b3Config& config); + + virtual ~b3CpuNarrowPhase(void); + + int registerSphereShape(float radius); + int registerPlaneShape(const b3Vector3& planeNormal, float planeConstant); + + int registerCompoundShape(b3AlignedObjectArray* childShapes); + int registerFace(const b3Vector3& faceNormal, float faceConstant); + + int registerConcaveMesh(b3AlignedObjectArray* vertices, b3AlignedObjectArray* indices,const float* scaling); + + //do they need to be merged? + + int registerConvexHullShape(b3ConvexUtility* utilPtr); + int registerConvexHullShape(const float* vertices, int strideInBytes, int numVertices, const float* scaling); + + //int registerRigidBody(int collidableIndex, float mass, const float* position, const float* orientation, const float* aabbMin, const float* aabbMax,bool writeToGpu); + void setObjectTransform(const float* position, const float* orientation , int bodyIndex); + + void writeAllBodiesToGpu(); + void reset(); + void readbackAllBodiesToCpu(); + bool getObjectTransformFromCpu(float* position, float* orientation , int bodyIndex) const; + + void setObjectTransformCpu(float* position, float* orientation , int bodyIndex); + void setObjectVelocityCpu(float* linVel, float* angVel, int bodyIndex); + + + //virtual void computeContacts(cl_mem broadphasePairs, int numBroadphasePairs, cl_mem aabbsWorldSpace, int numObjects); + virtual void computeContacts(b3AlignedObjectArray& pairs, b3AlignedObjectArray& aabbsWorldSpace, b3AlignedObjectArray& bodies); + + + + const struct b3RigidBodyData* getBodiesCpu() const; + //struct b3RigidBodyData* getBodiesCpu(); + + int getNumBodiesGpu() const; + + + int getNumBodyInertiasGpu() const; + + + const struct b3Collidable* getCollidablesCpu() const; + int getNumCollidablesGpu() const; + + + /*const struct b3Contact4* getContactsCPU() const; + + + int getNumContactsGpu() const; + */ + + const b3AlignedObjectArray& getContacts() const; + + + int getNumRigidBodies() const; + + int allocateCollidable(); + + int getStatic0Index() const + { + return m_static0Index; + } + b3Collidable& getCollidableCpu(int collidableIndex); + const b3Collidable& getCollidableCpu(int collidableIndex) const; + + const b3CpuNarrowPhaseInternalData* getInternalData() const + { + return m_data; + } + + const struct b3Aabb& getLocalSpaceAabb(int collidableIndex) const; +}; + +#endif //B3_CPU_NARROWPHASE_H + diff --git a/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/b3RaycastInfo.h b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/b3RaycastInfo.h new file mode 100644 index 000000000000..fba8bd07a4fd --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/b3RaycastInfo.h @@ -0,0 +1,24 @@ + +#ifndef B3_RAYCAST_INFO_H +#define B3_RAYCAST_INFO_H + +#include "Bullet3Common/b3Vector3.h" + +B3_ATTRIBUTE_ALIGNED16(struct) b3RayInfo +{ + b3Vector3 m_from; + b3Vector3 m_to; +}; + +B3_ATTRIBUTE_ALIGNED16(struct) b3RayHit +{ + b3Scalar m_hitFraction; + int m_hitBody; + int m_hitResult1; + int m_hitResult2; + b3Vector3 m_hitPoint; + b3Vector3 m_hitNormal; +}; + +#endif //B3_RAYCAST_INFO_H + diff --git a/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/b3RigidBodyCL.h b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/b3RigidBodyCL.h new file mode 100644 index 000000000000..d58f71802f7f --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/b3RigidBodyCL.h @@ -0,0 +1,30 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org + +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 B3_RIGID_BODY_CL +#define B3_RIGID_BODY_CL + +#include "Bullet3Common/b3Scalar.h" +#include "Bullet3Common/b3Matrix3x3.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" + + +inline float b3GetInvMass(const b3RigidBodyData& body) +{ + return body.m_invMass; +} + + +#endif//B3_RIGID_BODY_CL diff --git a/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3BvhSubtreeInfoData.h b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3BvhSubtreeInfoData.h new file mode 100644 index 000000000000..8788ccbb4711 --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3BvhSubtreeInfoData.h @@ -0,0 +1,20 @@ + +#ifndef B3_BVH_SUBTREE_INFO_DATA_H +#define B3_BVH_SUBTREE_INFO_DATA_H + +typedef struct b3BvhSubtreeInfoData b3BvhSubtreeInfoData_t; + +struct b3BvhSubtreeInfoData +{ + //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]; +}; + +#endif //B3_BVH_SUBTREE_INFO_DATA_H + diff --git a/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3BvhTraversal.h b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3BvhTraversal.h new file mode 100644 index 000000000000..2618da24bca5 --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3BvhTraversal.h @@ -0,0 +1,126 @@ + + +#include "Bullet3Common/shared/b3Int4.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3Collidable.h" +#include "Bullet3Collision/BroadPhaseCollision/shared/b3Aabb.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3BvhSubtreeInfoData.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3QuantizedBvhNodeData.h" + + + +// work-in-progress +void b3BvhTraversal( __global const b3Int4* pairs, + __global const b3RigidBodyData* rigidBodies, + __global const b3Collidable* collidables, + __global b3Aabb* aabbs, + __global b3Int4* concavePairsOut, + __global volatile int* numConcavePairsOut, + __global const b3BvhSubtreeInfo* subtreeHeadersRoot, + __global const b3QuantizedBvhNode* quantizedNodesRoot, + __global const b3BvhInfo* bvhInfos, + int numPairs, + int maxNumConcavePairsCapacity, + int id) +{ + + int bodyIndexA = pairs[id].x; + int bodyIndexB = pairs[id].y; + int collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx; + int collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx; + + //once the broadphase avoids static-static pairs, we can remove this test + if ((rigidBodies[bodyIndexA].m_invMass==0) &&(rigidBodies[bodyIndexB].m_invMass==0)) + { + return; + } + + if (collidables[collidableIndexA].m_shapeType!=SHAPE_CONCAVE_TRIMESH) + return; + + int shapeTypeB = collidables[collidableIndexB].m_shapeType; + + if (shapeTypeB!=SHAPE_CONVEX_HULL && + shapeTypeB!=SHAPE_SPHERE && + shapeTypeB!=SHAPE_COMPOUND_OF_CONVEX_HULLS + ) + return; + + b3BvhInfo bvhInfo = bvhInfos[collidables[collidableIndexA].m_numChildShapes]; + + b3Float4 bvhAabbMin = bvhInfo.m_aabbMin; + b3Float4 bvhAabbMax = bvhInfo.m_aabbMax; + b3Float4 bvhQuantization = bvhInfo.m_quantization; + int numSubtreeHeaders = bvhInfo.m_numSubTrees; + __global const b3BvhSubtreeInfoData* subtreeHeaders = &subtreeHeadersRoot[bvhInfo.m_subTreeOffset]; + __global const b3QuantizedBvhNodeData* quantizedNodes = &quantizedNodesRoot[bvhInfo.m_nodeOffset]; + + + unsigned short int quantizedQueryAabbMin[3]; + unsigned short int quantizedQueryAabbMax[3]; + b3QuantizeWithClamp(quantizedQueryAabbMin,aabbs[bodyIndexB].m_minVec,false,bvhAabbMin, bvhAabbMax,bvhQuantization); + b3QuantizeWithClamp(quantizedQueryAabbMax,aabbs[bodyIndexB].m_maxVec,true ,bvhAabbMin, bvhAabbMax,bvhQuantization); + + for (int i=0;i= 0, so output intersection + ppVtxOut[numVertsOut++] = b3Lerp3(firstVertex, endVertex,(ds * 1.f/(ds - de)) ); + } + } + else + { + if (de<0) + { + // Start >= 0, end < 0 so output intersection and end + ppVtxOut[numVertsOut++] = b3Lerp3(firstVertex, endVertex,(ds * 1.f/(ds - de)) ); + ppVtxOut[numVertsOut++] = endVertex; + } + } + firstVertex = endVertex; + ds = de; + } + return numVertsOut; +} + + +__kernel void clipFacesAndFindContactsKernel( __global const b3Float4* separatingNormals, + __global const int* hasSeparatingAxis, + __global b3Int4* clippingFacesOut, + __global b3Float4* worldVertsA1, + __global b3Float4* worldNormalsA1, + __global b3Float4* worldVertsB1, + __global b3Float4* worldVertsB2, + int vertexFaceCapacity, + int pairIndex + ) +{ +// int i = get_global_id(0); + //int pairIndex = i; + int i = pairIndex; + + float minDist = -1e30f; + float maxDist = 0.02f; + +// if (i=0) + { + + + + // clip polygon to back of planes of all faces of hull A that are adjacent to witness face + + for(int e0=0;e0m_worldNormalOnB.w; +}; + +inline void b3Contact4Data_setNumPoints(struct b3Contact4Data* contact, int numPoints) +{ + contact->m_worldNormalOnB.w = (float)numPoints; +}; + + + +#endif //B3_CONTACT4DATA_H \ No newline at end of file diff --git a/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3ContactConvexConvexSAT.h b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3ContactConvexConvexSAT.h new file mode 100644 index 000000000000..f295f01a6c3e --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3ContactConvexConvexSAT.h @@ -0,0 +1,520 @@ + +#ifndef B3_CONTACT_CONVEX_CONVEX_SAT_H +#define B3_CONTACT_CONVEX_CONVEX_SAT_H + + +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3Contact4Data.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3FindSeparatingAxis.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3ReduceContacts.h" + +#define B3_MAX_VERTS 1024 + + + +inline b3Float4 b3Lerp3(const b3Float4& a,const b3Float4& b, float t) +{ + return b3MakeVector3( a.x + (b.x - a.x) * t, + a.y + (b.y - a.y) * t, + a.z + (b.z - a.z) * t, + 0.f); +} + + +// Clips a face to the back of a plane, return the number of vertices out, stored in ppVtxOut +inline int b3ClipFace(const b3Float4* pVtxIn, int numVertsIn, b3Float4& planeNormalWS,float planeEqWS, b3Float4* ppVtxOut) +{ + + int ve; + float ds, de; + int numVertsOut = 0; + if (numVertsIn < 2) + return 0; + + b3Float4 firstVertex=pVtxIn[numVertsIn-1]; + b3Float4 endVertex = pVtxIn[0]; + + ds = b3Dot3F4(planeNormalWS,firstVertex)+planeEqWS; + + for (ve = 0; ve < numVertsIn; ve++) + { + endVertex=pVtxIn[ve]; + + de = b3Dot3F4(planeNormalWS,endVertex)+planeEqWS; + + if (ds<0) + { + if (de<0) + { + // Start < 0, end < 0, so output endVertex + ppVtxOut[numVertsOut++] = endVertex; + } + else + { + // Start < 0, end >= 0, so output intersection + ppVtxOut[numVertsOut++] = b3Lerp3(firstVertex, endVertex,(ds * 1.f/(ds - de)) ); + } + } + else + { + if (de<0) + { + // Start >= 0, end < 0 so output intersection and end + ppVtxOut[numVertsOut++] = b3Lerp3(firstVertex, endVertex,(ds * 1.f/(ds - de)) ); + ppVtxOut[numVertsOut++] = endVertex; + } + } + firstVertex = endVertex; + ds = de; + } + return numVertsOut; +} + + +inline int b3ClipFaceAgainstHull(const b3Float4& separatingNormal, const b3ConvexPolyhedronData* hullA, + const b3Float4& posA, const b3Quaternion& ornA, b3Float4* worldVertsB1, int numWorldVertsB1, + b3Float4* worldVertsB2, int capacityWorldVertsB2, + const float minDist, float maxDist, + const b3AlignedObjectArray& verticesA, const b3AlignedObjectArray& facesA, const b3AlignedObjectArray& indicesA, + //const b3Float4* verticesB, const b3GpuFace* facesB, const int* indicesB, + b3Float4* contactsOut, + int contactCapacity) +{ + int numContactsOut = 0; + + b3Float4* pVtxIn = worldVertsB1; + b3Float4* pVtxOut = worldVertsB2; + + int numVertsIn = numWorldVertsB1; + int numVertsOut = 0; + + int closestFaceA=-1; + { + float dmin = FLT_MAX; + for(int face=0;facem_numFaces;face++) + { + const b3Float4 Normal = b3MakeVector3( + facesA[hullA->m_faceOffset+face].m_plane.x, + facesA[hullA->m_faceOffset+face].m_plane.y, + facesA[hullA->m_faceOffset+face].m_plane.z,0.f); + const b3Float4 faceANormalWS = b3QuatRotate(ornA,Normal); + + float d = b3Dot3F4(faceANormalWS,separatingNormal); + if (d < dmin) + { + dmin = d; + closestFaceA = face; + } + } + } + if (closestFaceA<0) + return numContactsOut; + + b3GpuFace polyA = facesA[hullA->m_faceOffset+closestFaceA]; + + // clip polygon to back of planes of all faces of hull A that are adjacent to witness face + //int numContacts = numWorldVertsB1; + int numVerticesA = polyA.m_numIndices; + for(int e0=0;e0m_vertexOffset+indicesA[polyA.m_indexOffset+e0]]; + const b3Float4 b = verticesA[hullA->m_vertexOffset+indicesA[polyA.m_indexOffset+((e0+1)%numVerticesA)]]; + const b3Float4 edge0 = a - b; + const b3Float4 WorldEdge0 = b3QuatRotate(ornA,edge0); + b3Float4 planeNormalA = b3MakeFloat4(polyA.m_plane.x,polyA.m_plane.y,polyA.m_plane.z,0.f); + b3Float4 worldPlaneAnormal1 = b3QuatRotate(ornA,planeNormalA); + + b3Float4 planeNormalWS1 = -b3Cross3(WorldEdge0,worldPlaneAnormal1); + b3Float4 worldA1 = b3TransformPoint(a,posA,ornA); + float planeEqWS1 = -b3Dot3F4(worldA1,planeNormalWS1); + + b3Float4 planeNormalWS = planeNormalWS1; + float planeEqWS=planeEqWS1; + + //clip face + //clipFace(*pVtxIn, *pVtxOut,planeNormalWS,planeEqWS); + numVertsOut = b3ClipFace(pVtxIn, numVertsIn, planeNormalWS,planeEqWS, pVtxOut); + + //btSwap(pVtxIn,pVtxOut); + b3Float4* tmp = pVtxOut; + pVtxOut = pVtxIn; + pVtxIn = tmp; + numVertsIn = numVertsOut; + numVertsOut = 0; + } + + + // only keep points that are behind the witness face + { + b3Float4 localPlaneNormal = b3MakeFloat4(polyA.m_plane.x,polyA.m_plane.y,polyA.m_plane.z,0.f); + float localPlaneEq = polyA.m_plane.w; + b3Float4 planeNormalWS = b3QuatRotate(ornA,localPlaneNormal); + float planeEqWS=localPlaneEq-b3Dot3F4(planeNormalWS,posA); + for (int i=0;i& verticesA, const b3AlignedObjectArray& facesA, const b3AlignedObjectArray& indicesA, + const b3AlignedObjectArray& verticesB, const b3AlignedObjectArray& facesB, const b3AlignedObjectArray& indicesB, + + b3Float4* contactsOut, + int contactCapacity) +{ + int numContactsOut = 0; + int numWorldVertsB1= 0; + + B3_PROFILE("clipHullAgainstHull"); + + //float curMaxDist=maxDist; + int closestFaceB=-1; + float dmax = -FLT_MAX; + + { + //B3_PROFILE("closestFaceB"); + if (hullB.m_numFaces!=1) + { + //printf("wtf\n"); + } + static bool once = true; + //printf("separatingNormal=%f,%f,%f\n",separatingNormal.x,separatingNormal.y,separatingNormal.z); + + for(int face=0;facem_numIndices;i++) + { + b3Float4 vert = verticesB[hullB.m_vertexOffset+indicesB[faceB->m_indexOffset+i]]; + printf("vert[%d] = %f,%f,%f\n",i,vert.x,vert.y,vert.z); + } + } +#endif //BT_DEBUG_SAT_FACE + //if (facesB[hullB.m_faceOffset+face].m_numIndices>2) + { + const b3Float4 Normal = b3MakeVector3(facesB[hullB.m_faceOffset+face].m_plane.x, + facesB[hullB.m_faceOffset+face].m_plane.y, facesB[hullB.m_faceOffset+face].m_plane.z,0.f); + const b3Float4 WorldNormal = b3QuatRotate(ornB, Normal); +#ifdef BT_DEBUG_SAT_FACE + if (once) + printf("faceNormal = %f,%f,%f\n",Normal.x,Normal.y,Normal.z); +#endif + float d = b3Dot3F4(WorldNormal,separatingNormal); + if (d > dmax) + { + dmax = d; + closestFaceB = face; + } + } + } + once = false; + } + + + b3Assert(closestFaceB>=0); + { + //B3_PROFILE("worldVertsB1"); + const b3GpuFace& polyB = facesB[hullB.m_faceOffset+closestFaceB]; + const int numVertices = polyB.m_numIndices; + for(int e0=0;e0=0) + { + //B3_PROFILE("clipFaceAgainstHull"); + numContactsOut = b3ClipFaceAgainstHull((b3Float4&)separatingNormal, &hullA, + posA,ornA, + worldVertsB1,numWorldVertsB1,worldVertsB2,capacityWorldVerts, minDist, maxDist, + verticesA, facesA, indicesA, + contactsOut,contactCapacity); + } + + return numContactsOut; +} + + + + +inline int b3ClipHullHullSingle( + int bodyIndexA, int bodyIndexB, + const b3Float4& posA, + const b3Quaternion& ornA, + const b3Float4& posB, + const b3Quaternion& ornB, + + int collidableIndexA, int collidableIndexB, + + const b3AlignedObjectArray* bodyBuf, + b3AlignedObjectArray* globalContactOut, + int& nContacts, + + const b3AlignedObjectArray& hostConvexDataA, + const b3AlignedObjectArray& hostConvexDataB, + + const b3AlignedObjectArray& verticesA, + const b3AlignedObjectArray& uniqueEdgesA, + const b3AlignedObjectArray& facesA, + const b3AlignedObjectArray& indicesA, + + const b3AlignedObjectArray& verticesB, + const b3AlignedObjectArray& uniqueEdgesB, + const b3AlignedObjectArray& facesB, + const b3AlignedObjectArray& indicesB, + + const b3AlignedObjectArray& hostCollidablesA, + const b3AlignedObjectArray& hostCollidablesB, + const b3Vector3& sepNormalWorldSpace, + int maxContactCapacity ) +{ + int contactIndex = -1; + b3ConvexPolyhedronData hullA, hullB; + + b3Collidable colA = hostCollidablesA[collidableIndexA]; + hullA = hostConvexDataA[colA.m_shapeIndex]; + //printf("numvertsA = %d\n",hullA.m_numVertices); + + + b3Collidable colB = hostCollidablesB[collidableIndexB]; + hullB = hostConvexDataB[colB.m_shapeIndex]; + //printf("numvertsB = %d\n",hullB.m_numVertices); + + + b3Float4 contactsOut[B3_MAX_VERTS]; + int localContactCapacity = B3_MAX_VERTS; + +#ifdef _WIN32 + b3Assert(_finite(bodyBuf->at(bodyIndexA).m_pos.x)); + b3Assert(_finite(bodyBuf->at(bodyIndexB).m_pos.x)); +#endif + + + { + + b3Float4 worldVertsB1[B3_MAX_VERTS]; + b3Float4 worldVertsB2[B3_MAX_VERTS]; + int capacityWorldVerts = B3_MAX_VERTS; + + b3Float4 hostNormal = b3MakeFloat4(sepNormalWorldSpace.x,sepNormalWorldSpace.y,sepNormalWorldSpace.z,0.f); + int shapeA = hostCollidablesA[collidableIndexA].m_shapeIndex; + int shapeB = hostCollidablesB[collidableIndexB].m_shapeIndex; + + b3Scalar minDist = -1; + b3Scalar maxDist = 0.; + + + + b3Transform trA,trB; + { + //B3_PROFILE("b3TransformPoint computation"); + //trA.setIdentity(); + trA.setOrigin(b3MakeVector3(posA.x,posA.y,posA.z)); + trA.setRotation(b3Quaternion(ornA.x,ornA.y,ornA.z,ornA.w)); + + //trB.setIdentity(); + trB.setOrigin(b3MakeVector3(posB.x,posB.y,posB.z)); + trB.setRotation(b3Quaternion(ornB.x,ornB.y,ornB.z,ornB.w)); + } + + b3Quaternion trAorn = trA.getRotation(); + b3Quaternion trBorn = trB.getRotation(); + + int numContactsOut = b3ClipHullAgainstHull(hostNormal, + hostConvexDataA.at(shapeA), + hostConvexDataB.at(shapeB), + (b3Float4&)trA.getOrigin(), (b3Quaternion&)trAorn, + (b3Float4&)trB.getOrigin(), (b3Quaternion&)trBorn, + worldVertsB1,worldVertsB2,capacityWorldVerts, + minDist, maxDist, + verticesA, facesA,indicesA, + verticesB, facesB,indicesB, + + contactsOut,localContactCapacity); + + if (numContactsOut>0) + { + B3_PROFILE("overlap"); + + b3Float4 normalOnSurfaceB = (b3Float4&)hostNormal; +// b3Float4 centerOut; + + b3Int4 contactIdx; + contactIdx.x = 0; + contactIdx.y = 1; + contactIdx.z = 2; + contactIdx.w = 3; + + int numPoints = 0; + + { + B3_PROFILE("extractManifold"); + numPoints = b3ReduceContacts(contactsOut, numContactsOut, normalOnSurfaceB, &contactIdx); + } + + b3Assert(numPoints); + + if (nContactsexpand(); + b3Contact4Data& contact = globalContactOut->at(nContacts); + contact.m_batchIdx = 0;//i; + contact.m_bodyAPtrAndSignBit = (bodyBuf->at(bodyIndexA).m_invMass==0)? -bodyIndexA:bodyIndexA; + contact.m_bodyBPtrAndSignBit = (bodyBuf->at(bodyIndexB).m_invMass==0)? -bodyIndexB:bodyIndexB; + + contact.m_frictionCoeffCmp = 45874; + contact.m_restituitionCoeffCmp = 0; + + // float distance = 0.f; + for (int p=0;p& rigidBodies, + const b3AlignedObjectArray& collidables, + const b3AlignedObjectArray& convexShapes, + const b3AlignedObjectArray& convexVertices, + const b3AlignedObjectArray& uniqueEdges, + const b3AlignedObjectArray& convexIndices, + const b3AlignedObjectArray& faces, + b3AlignedObjectArray& globalContactsOut, + int& nGlobalContactsOut, + int maxContactCapacity) +{ + int contactIndex = -1; + + + b3Float4 posA = rigidBodies[bodyIndexA].m_pos; + b3Quaternion ornA = rigidBodies[bodyIndexA].m_quat; + b3Float4 posB = rigidBodies[bodyIndexB].m_pos; + b3Quaternion ornB = rigidBodies[bodyIndexB].m_quat; + + + b3ConvexPolyhedronData hullA, hullB; + + b3Float4 sepNormalWorldSpace; + + + + b3Collidable colA = collidables[collidableIndexA]; + hullA = convexShapes[colA.m_shapeIndex]; + //printf("numvertsA = %d\n",hullA.m_numVertices); + + + b3Collidable colB = collidables[collidableIndexB]; + hullB = convexShapes[colB.m_shapeIndex]; + //printf("numvertsB = %d\n",hullB.m_numVertices); + + + + +#ifdef _WIN32 + b3Assert(_finite(rigidBodies[bodyIndexA].m_pos.x)); + b3Assert(_finite(rigidBodies[bodyIndexB].m_pos.x)); +#endif + + bool foundSepAxis = b3FindSeparatingAxis(hullA,hullB, + posA, + ornA, + posB, + ornB, + + convexVertices,uniqueEdges,faces,convexIndices, + convexVertices,uniqueEdges,faces,convexIndices, + + sepNormalWorldSpace + ); + + + if (foundSepAxis) + { + + + contactIndex = b3ClipHullHullSingle( + bodyIndexA, bodyIndexB, + posA,ornA, + posB,ornB, + collidableIndexA, collidableIndexB, + &rigidBodies, + &globalContactsOut, + nGlobalContactsOut, + + convexShapes, + convexShapes, + + convexVertices, + uniqueEdges, + faces, + convexIndices, + + convexVertices, + uniqueEdges, + faces, + convexIndices, + + collidables, + collidables, + sepNormalWorldSpace, + maxContactCapacity); + + } + + return contactIndex; +} + +#endif //B3_CONTACT_CONVEX_CONVEX_SAT_H diff --git a/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3ContactSphereSphere.h b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3ContactSphereSphere.h new file mode 100644 index 000000000000..a3fa82287b82 --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3ContactSphereSphere.h @@ -0,0 +1,162 @@ + +#ifndef B3_CONTACT_SPHERE_SPHERE_H +#define B3_CONTACT_SPHERE_SPHERE_H + + + + + +void computeContactSphereConvex(int pairIndex, + int bodyIndexA, int bodyIndexB, + int collidableIndexA, int collidableIndexB, + const b3RigidBodyData* rigidBodies, + const b3Collidable* collidables, + const b3ConvexPolyhedronData* convexShapes, + const b3Vector3* convexVertices, + const int* convexIndices, + const b3GpuFace* faces, + b3Contact4* globalContactsOut, + int& nGlobalContactsOut, + int maxContactCapacity) +{ + + float radius = collidables[collidableIndexA].m_radius; + float4 spherePos1 = rigidBodies[bodyIndexA].m_pos; + b3Quaternion sphereOrn = rigidBodies[bodyIndexA].m_quat; + + + + float4 pos = rigidBodies[bodyIndexB].m_pos; + + + b3Quaternion quat = rigidBodies[bodyIndexB].m_quat; + + b3Transform tr; + tr.setIdentity(); + tr.setOrigin(pos); + tr.setRotation(quat); + b3Transform trInv = tr.inverse(); + + float4 spherePos = trInv(spherePos1); + + int collidableIndex = rigidBodies[bodyIndexB].m_collidableIdx; + int shapeIndex = collidables[collidableIndex].m_shapeIndex; + int numFaces = convexShapes[shapeIndex].m_numFaces; + float4 closestPnt = b3MakeVector3(0, 0, 0, 0); + float4 hitNormalWorld = b3MakeVector3(0, 0, 0, 0); + float minDist = -1000000.f; // TODO: What is the largest/smallest float? + bool bCollide = true; + int region = -1; + float4 localHitNormal; + for ( int f = 0; f < numFaces; f++ ) + { + b3GpuFace face = faces[convexShapes[shapeIndex].m_faceOffset+f]; + float4 planeEqn; + float4 localPlaneNormal = b3MakeVector3(face.m_plane.x,face.m_plane.y,face.m_plane.z,0.f); + float4 n1 = localPlaneNormal;//quatRotate(quat,localPlaneNormal); + planeEqn = n1; + planeEqn[3] = face.m_plane.w; + + float4 pntReturn; + float dist = signedDistanceFromPointToPlane(spherePos, planeEqn, &pntReturn); + + if ( dist > radius) + { + bCollide = false; + break; + } + + if ( dist > 0 ) + { + //might hit an edge or vertex + b3Vector3 out; + + bool isInPoly = IsPointInPolygon(spherePos, + &face, + &convexVertices[convexShapes[shapeIndex].m_vertexOffset], + convexIndices, + &out); + if (isInPoly) + { + if (dist>minDist) + { + minDist = dist; + closestPnt = pntReturn; + localHitNormal = planeEqn; + region=1; + } + } else + { + b3Vector3 tmp = spherePos-out; + b3Scalar l2 = tmp.length2(); + if (l2minDist) + { + minDist = dist; + closestPnt = out; + localHitNormal = tmp/dist; + region=2; + } + + } else + { + bCollide = false; + break; + } + } + } + else + { + if ( dist > minDist ) + { + minDist = dist; + closestPnt = pntReturn; + localHitNormal = planeEqn; + region=3; + } + } + } + static int numChecks = 0; + numChecks++; + + if (bCollide && minDist > -10000) + { + + float4 normalOnSurfaceB1 = tr.getBasis()*localHitNormal;//-hitNormalWorld; + float4 pOnB1 = tr(closestPnt); + //printf("dist ,%f,",minDist); + float actualDepth = minDist-radius; + if (actualDepth<0) + { + //printf("actualDepth = ,%f,", actualDepth); + //printf("normalOnSurfaceB1 = ,%f,%f,%f,", normalOnSurfaceB1.x,normalOnSurfaceB1.y,normalOnSurfaceB1.z); + //printf("region=,%d,\n", region); + pOnB1[3] = actualDepth; + + int dstIdx; +// dstIdx = nGlobalContactsOut++;//AppendInc( nGlobalContactsOut, dstIdx ); + + if (nGlobalContactsOut < maxContactCapacity) + { + dstIdx=nGlobalContactsOut; + nGlobalContactsOut++; + + b3Contact4* c = &globalContactsOut[dstIdx]; + c->m_worldNormalOnB = normalOnSurfaceB1; + c->setFrictionCoeff(0.7); + c->setRestituitionCoeff(0.f); + + c->m_batchIdx = pairIndex; + c->m_bodyAPtrAndSignBit = rigidBodies[bodyIndexA].m_invMass==0?-bodyIndexA:bodyIndexA; + c->m_bodyBPtrAndSignBit = rigidBodies[bodyIndexB].m_invMass==0?-bodyIndexB:bodyIndexB; + c->m_worldPosB[0] = pOnB1; + int numPoints = 1; + c->m_worldNormalOnB.w = (b3Scalar)numPoints; + }//if (dstIdx < numPairs) + } + }//if (hasCollision) + +} +#endif //B3_CONTACT_SPHERE_SPHERE_H diff --git a/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3ConvexPolyhedronData.h b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3ConvexPolyhedronData.h new file mode 100644 index 000000000000..5c5f4e297fcf --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3ConvexPolyhedronData.h @@ -0,0 +1,40 @@ + +#ifndef B3_CONVEX_POLYHEDRON_DATA_H +#define B3_CONVEX_POLYHEDRON_DATA_H + + + +#include "Bullet3Common/shared/b3Float4.h" +#include "Bullet3Common/shared/b3Quat.h" + +typedef struct b3GpuFace b3GpuFace_t; +struct b3GpuFace +{ + b3Float4 m_plane; + int m_indexOffset; + int m_numIndices; + int m_unusedPadding1; + int m_unusedPadding2; +}; + +typedef struct b3ConvexPolyhedronData b3ConvexPolyhedronData_t; + +struct b3ConvexPolyhedronData +{ + b3Float4 m_localCenter; + b3Float4 m_extents; + b3Float4 mC; + b3Float4 mE; + + float m_radius; + int m_faceOffset; + int m_numFaces; + int m_numVertices; + + int m_vertexOffset; + int m_uniqueEdgesOffset; + int m_numUniqueEdges; + int m_unused; +}; + +#endif //B3_CONVEX_POLYHEDRON_DATA_H diff --git a/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3FindConcaveSatAxis.h b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3FindConcaveSatAxis.h new file mode 100644 index 000000000000..89993f35654a --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3FindConcaveSatAxis.h @@ -0,0 +1,832 @@ +#ifndef B3_FIND_CONCAVE_SEPARATING_AXIS_H +#define B3_FIND_CONCAVE_SEPARATING_AXIS_H + +#define B3_TRIANGLE_NUM_CONVEX_FACES 5 + + +#include "Bullet3Common/shared/b3Int4.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3Collidable.h" +#include "Bullet3Collision/BroadPhaseCollision/shared/b3Aabb.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3BvhSubtreeInfoData.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3QuantizedBvhNodeData.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3ConvexPolyhedronData.h" + + +inline void b3Project(__global const b3ConvexPolyhedronData* hull, b3Float4ConstArg pos, b3QuatConstArg orn, +const b3Float4* dir, __global const b3Float4* vertices, float* min, float* max) +{ + min[0] = FLT_MAX; + max[0] = -FLT_MAX; + int numVerts = hull->m_numVertices; + + const b3Float4 localDir = b3QuatRotate(b3QuatInverse(orn),*dir); + float offset = b3Dot(pos,*dir); + for(int i=0;im_vertexOffset+i],localDir); + if(dp < min[0]) + min[0] = dp; + if(dp > max[0]) + max[0] = dp; + } + if(min[0]>max[0]) + { + float tmp = min[0]; + min[0] = max[0]; + max[0] = tmp; + } + min[0] += offset; + max[0] += offset; +} + + +inline bool b3TestSepAxis(const b3ConvexPolyhedronData* hullA, __global const b3ConvexPolyhedronData* hullB, + b3Float4ConstArg posA,b3QuatConstArg ornA, + b3Float4ConstArg posB,b3QuatConstArg ornB, + b3Float4* sep_axis, const b3Float4* verticesA, __global const b3Float4* verticesB,float* depth) +{ + float Min0,Max0; + float Min1,Max1; + b3Project(hullA,posA,ornA,sep_axis,verticesA, &Min0, &Max0); + b3Project(hullB,posB,ornB, sep_axis,verticesB, &Min1, &Max1); + + if(Max0m_numFaces*hullB->m_numVertices; + curFaceVertexAB+= hullB->m_numFaces*hullA->m_numVertices; + + if (curFaceVertexAB>maxFaceVertex) + { + maxFaceVertex = curFaceVertexAB; + printf("curFaceVertexAB = %d\n",curFaceVertexAB); + printf("hullA->m_numFaces = %d\n",hullA->m_numFaces); + printf("hullA->m_numVertices = %d\n",hullA->m_numVertices); + printf("hullB->m_numVertices = %d\n",hullB->m_numVertices); + } +*/ + + int curPlaneTests=0; + { + int numFacesA = hullA->m_numFaces; + // Test normals from hullA + for(int i=0;im_faceOffset+i].m_plane; + b3Float4 faceANormalWS = b3QuatRotate(ornA,normal); + if (b3Dot(DeltaC2,faceANormalWS)<0) + faceANormalWS*=-1.f; + curPlaneTests++; + float d; + if(!b3TestSepAxis( hullA, hullB, posA,ornA,posB,ornB,&faceANormalWS, verticesA, verticesB,&d)) + return false; + if(d<*dmin) + { + *dmin = d; + *sep = faceANormalWS; + } + } + } + if((b3Dot(-DeltaC2,*sep))>0.0f) + { + *sep = -(*sep); + } + return true; +} + + +b3Vector3 unitSphere162[]= +{ + b3MakeVector3(0.000000,-1.000000,0.000000), +b3MakeVector3(0.203181,-0.967950,0.147618), +b3MakeVector3(-0.077607,-0.967950,0.238853), +b3MakeVector3(0.723607,-0.447220,0.525725), +b3MakeVector3(0.609547,-0.657519,0.442856), +b3MakeVector3(0.812729,-0.502301,0.295238), +b3MakeVector3(-0.251147,-0.967949,0.000000), +b3MakeVector3(-0.077607,-0.967950,-0.238853), +b3MakeVector3(0.203181,-0.967950,-0.147618), +b3MakeVector3(0.860698,-0.251151,0.442858), +b3MakeVector3(-0.276388,-0.447220,0.850649), +b3MakeVector3(-0.029639,-0.502302,0.864184), +b3MakeVector3(-0.155215,-0.251152,0.955422), +b3MakeVector3(-0.894426,-0.447216,0.000000), +b3MakeVector3(-0.831051,-0.502299,0.238853), +b3MakeVector3(-0.956626,-0.251149,0.147618), +b3MakeVector3(-0.276388,-0.447220,-0.850649), +b3MakeVector3(-0.483971,-0.502302,-0.716565), +b3MakeVector3(-0.436007,-0.251152,-0.864188), +b3MakeVector3(0.723607,-0.447220,-0.525725), +b3MakeVector3(0.531941,-0.502302,-0.681712), +b3MakeVector3(0.687159,-0.251152,-0.681715), +b3MakeVector3(0.687159,-0.251152,0.681715), +b3MakeVector3(-0.436007,-0.251152,0.864188), +b3MakeVector3(-0.956626,-0.251149,-0.147618), +b3MakeVector3(-0.155215,-0.251152,-0.955422), +b3MakeVector3(0.860698,-0.251151,-0.442858), +b3MakeVector3(0.276388,0.447220,0.850649), +b3MakeVector3(0.483971,0.502302,0.716565), +b3MakeVector3(0.232822,0.657519,0.716563), +b3MakeVector3(-0.723607,0.447220,0.525725), +b3MakeVector3(-0.531941,0.502302,0.681712), +b3MakeVector3(-0.609547,0.657519,0.442856), +b3MakeVector3(-0.723607,0.447220,-0.525725), +b3MakeVector3(-0.812729,0.502301,-0.295238), +b3MakeVector3(-0.609547,0.657519,-0.442856), +b3MakeVector3(0.276388,0.447220,-0.850649), +b3MakeVector3(0.029639,0.502302,-0.864184), +b3MakeVector3(0.232822,0.657519,-0.716563), +b3MakeVector3(0.894426,0.447216,0.000000), +b3MakeVector3(0.831051,0.502299,-0.238853), +b3MakeVector3(0.753442,0.657515,0.000000), +b3MakeVector3(-0.232822,-0.657519,0.716563), +b3MakeVector3(-0.162456,-0.850654,0.499995), +b3MakeVector3(0.052790,-0.723612,0.688185), +b3MakeVector3(0.138199,-0.894429,0.425321), +b3MakeVector3(0.262869,-0.525738,0.809012), +b3MakeVector3(0.361805,-0.723611,0.587779), +b3MakeVector3(0.531941,-0.502302,0.681712), +b3MakeVector3(0.425323,-0.850654,0.309011), +b3MakeVector3(0.812729,-0.502301,-0.295238), +b3MakeVector3(0.609547,-0.657519,-0.442856), +b3MakeVector3(0.850648,-0.525736,0.000000), +b3MakeVector3(0.670817,-0.723611,-0.162457), +b3MakeVector3(0.670817,-0.723610,0.162458), +b3MakeVector3(0.425323,-0.850654,-0.309011), +b3MakeVector3(0.447211,-0.894428,0.000001), +b3MakeVector3(-0.753442,-0.657515,0.000000), +b3MakeVector3(-0.525730,-0.850652,0.000000), +b3MakeVector3(-0.638195,-0.723609,0.262864), +b3MakeVector3(-0.361801,-0.894428,0.262864), +b3MakeVector3(-0.688189,-0.525736,0.499997), +b3MakeVector3(-0.447211,-0.723610,0.525729), +b3MakeVector3(-0.483971,-0.502302,0.716565), +b3MakeVector3(-0.232822,-0.657519,-0.716563), +b3MakeVector3(-0.162456,-0.850654,-0.499995), +b3MakeVector3(-0.447211,-0.723611,-0.525727), +b3MakeVector3(-0.361801,-0.894429,-0.262863), +b3MakeVector3(-0.688189,-0.525736,-0.499997), +b3MakeVector3(-0.638195,-0.723609,-0.262863), +b3MakeVector3(-0.831051,-0.502299,-0.238853), +b3MakeVector3(0.361804,-0.723612,-0.587779), +b3MakeVector3(0.138197,-0.894429,-0.425321), +b3MakeVector3(0.262869,-0.525738,-0.809012), +b3MakeVector3(0.052789,-0.723611,-0.688186), +b3MakeVector3(-0.029639,-0.502302,-0.864184), +b3MakeVector3(0.956626,0.251149,0.147618), +b3MakeVector3(0.956626,0.251149,-0.147618), +b3MakeVector3(0.951058,-0.000000,0.309013), +b3MakeVector3(1.000000,0.000000,0.000000), +b3MakeVector3(0.947213,-0.276396,0.162458), +b3MakeVector3(0.951058,0.000000,-0.309013), +b3MakeVector3(0.947213,-0.276396,-0.162458), +b3MakeVector3(0.155215,0.251152,0.955422), +b3MakeVector3(0.436007,0.251152,0.864188), +b3MakeVector3(-0.000000,-0.000000,1.000000), +b3MakeVector3(0.309017,0.000000,0.951056), +b3MakeVector3(0.138199,-0.276398,0.951055), +b3MakeVector3(0.587786,0.000000,0.809017), +b3MakeVector3(0.447216,-0.276398,0.850648), +b3MakeVector3(-0.860698,0.251151,0.442858), +b3MakeVector3(-0.687159,0.251152,0.681715), +b3MakeVector3(-0.951058,-0.000000,0.309013), +b3MakeVector3(-0.809018,0.000000,0.587783), +b3MakeVector3(-0.861803,-0.276396,0.425324), +b3MakeVector3(-0.587786,0.000000,0.809017), +b3MakeVector3(-0.670819,-0.276397,0.688191), +b3MakeVector3(-0.687159,0.251152,-0.681715), +b3MakeVector3(-0.860698,0.251151,-0.442858), +b3MakeVector3(-0.587786,-0.000000,-0.809017), +b3MakeVector3(-0.809018,-0.000000,-0.587783), +b3MakeVector3(-0.670819,-0.276397,-0.688191), +b3MakeVector3(-0.951058,0.000000,-0.309013), +b3MakeVector3(-0.861803,-0.276396,-0.425324), +b3MakeVector3(0.436007,0.251152,-0.864188), +b3MakeVector3(0.155215,0.251152,-0.955422), +b3MakeVector3(0.587786,-0.000000,-0.809017), +b3MakeVector3(0.309017,-0.000000,-0.951056), +b3MakeVector3(0.447216,-0.276398,-0.850648), +b3MakeVector3(0.000000,0.000000,-1.000000), +b3MakeVector3(0.138199,-0.276398,-0.951055), +b3MakeVector3(0.670820,0.276396,0.688190), +b3MakeVector3(0.809019,-0.000002,0.587783), +b3MakeVector3(0.688189,0.525736,0.499997), +b3MakeVector3(0.861804,0.276394,0.425323), +b3MakeVector3(0.831051,0.502299,0.238853), +b3MakeVector3(-0.447216,0.276397,0.850649), +b3MakeVector3(-0.309017,-0.000001,0.951056), +b3MakeVector3(-0.262869,0.525738,0.809012), +b3MakeVector3(-0.138199,0.276397,0.951055), +b3MakeVector3(0.029639,0.502302,0.864184), +b3MakeVector3(-0.947213,0.276396,-0.162458), +b3MakeVector3(-1.000000,0.000001,0.000000), +b3MakeVector3(-0.850648,0.525736,-0.000000), +b3MakeVector3(-0.947213,0.276397,0.162458), +b3MakeVector3(-0.812729,0.502301,0.295238), +b3MakeVector3(-0.138199,0.276397,-0.951055), +b3MakeVector3(-0.309016,-0.000000,-0.951057), +b3MakeVector3(-0.262869,0.525738,-0.809012), +b3MakeVector3(-0.447215,0.276397,-0.850649), +b3MakeVector3(-0.531941,0.502302,-0.681712), +b3MakeVector3(0.861804,0.276396,-0.425322), +b3MakeVector3(0.809019,0.000000,-0.587782), +b3MakeVector3(0.688189,0.525736,-0.499997), +b3MakeVector3(0.670821,0.276397,-0.688189), +b3MakeVector3(0.483971,0.502302,-0.716565), +b3MakeVector3(0.077607,0.967950,0.238853), +b3MakeVector3(0.251147,0.967949,0.000000), +b3MakeVector3(0.000000,1.000000,0.000000), +b3MakeVector3(0.162456,0.850654,0.499995), +b3MakeVector3(0.361800,0.894429,0.262863), +b3MakeVector3(0.447209,0.723612,0.525728), +b3MakeVector3(0.525730,0.850652,0.000000), +b3MakeVector3(0.638194,0.723610,0.262864), +b3MakeVector3(-0.203181,0.967950,0.147618), +b3MakeVector3(-0.425323,0.850654,0.309011), +b3MakeVector3(-0.138197,0.894430,0.425320), +b3MakeVector3(-0.361804,0.723612,0.587778), +b3MakeVector3(-0.052790,0.723612,0.688185), +b3MakeVector3(-0.203181,0.967950,-0.147618), +b3MakeVector3(-0.425323,0.850654,-0.309011), +b3MakeVector3(-0.447210,0.894429,0.000000), +b3MakeVector3(-0.670817,0.723611,-0.162457), +b3MakeVector3(-0.670817,0.723611,0.162457), +b3MakeVector3(0.077607,0.967950,-0.238853), +b3MakeVector3(0.162456,0.850654,-0.499995), +b3MakeVector3(-0.138197,0.894430,-0.425320), +b3MakeVector3(-0.052790,0.723612,-0.688185), +b3MakeVector3(-0.361804,0.723612,-0.587778), +b3MakeVector3(0.361800,0.894429,-0.262863), +b3MakeVector3(0.638194,0.723610,-0.262864), +b3MakeVector3(0.447209,0.723612,-0.525728) +}; + + +bool b3FindSeparatingAxisEdgeEdge( const b3ConvexPolyhedronData* hullA, __global const b3ConvexPolyhedronData* hullB, + b3Float4ConstArg posA1, + b3QuatConstArg ornA, + b3Float4ConstArg posB1, + b3QuatConstArg ornB, + b3Float4ConstArg DeltaC2, + const b3Float4* verticesA, + const b3Float4* uniqueEdgesA, + const b3GpuFace* facesA, + const int* indicesA, + __global const b3Float4* verticesB, + __global const b3Float4* uniqueEdgesB, + __global const b3GpuFace* facesB, + __global const int* indicesB, + b3Float4* sep, + float* dmin, + bool searchAllEdgeEdge) +{ + + + b3Float4 posA = posA1; + posA.w = 0.f; + b3Float4 posB = posB1; + posB.w = 0.f; + +// int curPlaneTests=0; + + int curEdgeEdge = 0; + // Test edges + static int maxEdgeTests = 0; + int curEdgeTests = hullA->m_numUniqueEdges * hullB->m_numUniqueEdges; + if (curEdgeTests >maxEdgeTests ) + { + maxEdgeTests = curEdgeTests ; + printf("maxEdgeTests = %d\n",maxEdgeTests ); + printf("hullA->m_numUniqueEdges = %d\n",hullA->m_numUniqueEdges); + printf("hullB->m_numUniqueEdges = %d\n",hullB->m_numUniqueEdges); + + } + + + if (searchAllEdgeEdge) + { + for(int e0=0;e0m_numUniqueEdges;e0++) + { + const b3Float4 edge0 = uniqueEdgesA[hullA->m_uniqueEdgesOffset+e0]; + b3Float4 edge0World = b3QuatRotate(ornA,edge0); + + for(int e1=0;e1m_numUniqueEdges;e1++) + { + const b3Float4 edge1 = uniqueEdgesB[hullB->m_uniqueEdgesOffset+e1]; + b3Float4 edge1World = b3QuatRotate(ornB,edge1); + + + b3Float4 crossje = b3Cross(edge0World,edge1World); + + curEdgeEdge++; + if(!b3IsAlmostZero(crossje)) + { + crossje = b3Normalized(crossje); + if (b3Dot(DeltaC2,crossje)<0) + crossje *= -1.f; + + float dist; + bool result = true; + { + float Min0,Max0; + float Min1,Max1; + b3Project(hullA,posA,ornA,&crossje,verticesA, &Min0, &Max0); + b3Project(hullB,posB,ornB,&crossje,verticesB, &Min1, &Max1); + + if(Max00) + { + float dist; + bool result = true; + { + float Min0,Max0; + float Min1,Max1; + b3Project(hullA,posA,ornA,&crossje,verticesA, &Min0, &Max0); + b3Project(hullB,posB,ornB,&crossje,verticesB, &Min1, &Max1); + + if(Max00.0f) + { + *sep = -(*sep); + } + return true; +} + + + +inline int b3FindClippingFaces(b3Float4ConstArg separatingNormal, + __global const b3ConvexPolyhedronData_t* hullA, __global const b3ConvexPolyhedronData_t* hullB, + b3Float4ConstArg posA, b3QuatConstArg ornA,b3Float4ConstArg posB, b3QuatConstArg ornB, + __global b3Float4* worldVertsA1, + __global b3Float4* worldNormalsA1, + __global b3Float4* worldVertsB1, + int capacityWorldVerts, + const float minDist, float maxDist, + __global const b3Float4* verticesA, + __global const b3GpuFace_t* facesA, + __global const int* indicesA, + __global const b3Float4* verticesB, + __global const b3GpuFace_t* facesB, + __global const int* indicesB, + + __global b3Int4* clippingFaces, int pairIndex) +{ + int numContactsOut = 0; + int numWorldVertsB1= 0; + + + int closestFaceB=-1; + float dmax = -FLT_MAX; + + { + for(int face=0;facem_numFaces;face++) + { + const b3Float4 Normal = b3MakeFloat4(facesB[hullB->m_faceOffset+face].m_plane.x, + facesB[hullB->m_faceOffset+face].m_plane.y, facesB[hullB->m_faceOffset+face].m_plane.z,0.f); + const b3Float4 WorldNormal = b3QuatRotate(ornB, Normal); + float d = b3Dot(WorldNormal,separatingNormal); + if (d > dmax) + { + dmax = d; + closestFaceB = face; + } + } + } + + { + const b3GpuFace_t polyB = facesB[hullB->m_faceOffset+closestFaceB]; + const int numVertices = polyB.m_numIndices; + for(int e0=0;e0m_vertexOffset+indicesB[polyB.m_indexOffset+e0]]; + worldVertsB1[pairIndex*capacityWorldVerts+numWorldVertsB1++] = b3TransformPoint(b,posB,ornB); + } + } + + int closestFaceA=-1; + { + float dmin = FLT_MAX; + for(int face=0;facem_numFaces;face++) + { + const b3Float4 Normal = b3MakeFloat4( + facesA[hullA->m_faceOffset+face].m_plane.x, + facesA[hullA->m_faceOffset+face].m_plane.y, + facesA[hullA->m_faceOffset+face].m_plane.z, + 0.f); + const b3Float4 faceANormalWS = b3QuatRotate(ornA,Normal); + + float d = b3Dot(faceANormalWS,separatingNormal); + if (d < dmin) + { + dmin = d; + closestFaceA = face; + worldNormalsA1[pairIndex] = faceANormalWS; + } + } + } + + int numVerticesA = facesA[hullA->m_faceOffset+closestFaceA].m_numIndices; + for(int e0=0;e0m_vertexOffset+indicesA[facesA[hullA->m_faceOffset+closestFaceA].m_indexOffset+e0]]; + worldVertsA1[pairIndex*capacityWorldVerts+e0] = b3TransformPoint(a, posA,ornA); + } + + clippingFaces[pairIndex].x = closestFaceA; + clippingFaces[pairIndex].y = closestFaceB; + clippingFaces[pairIndex].z = numVerticesA; + clippingFaces[pairIndex].w = numWorldVertsB1; + + + return numContactsOut; +} + + + + +__kernel void b3FindConcaveSeparatingAxisKernel( __global b3Int4* concavePairs, + __global const b3RigidBodyData* rigidBodies, + __global const b3Collidable* collidables, + __global const b3ConvexPolyhedronData* convexShapes, + __global const b3Float4* vertices, + __global const b3Float4* uniqueEdges, + __global const b3GpuFace* faces, + __global const int* indices, + __global const b3GpuChildShape* gpuChildShapes, + __global b3Aabb* aabbs, + __global b3Float4* concaveSeparatingNormalsOut, + __global b3Int4* clippingFacesOut, + __global b3Vector3* worldVertsA1Out, + __global b3Vector3* worldNormalsA1Out, + __global b3Vector3* worldVertsB1Out, + __global int* hasSeparatingNormals, + int vertexFaceCapacity, + int numConcavePairs, + int pairIdx + ) +{ + int i = pairIdx; +/* int i = get_global_id(0); + if (i>=numConcavePairs) + return; + int pairIdx = i; + */ + + int bodyIndexA = concavePairs[i].x; + int bodyIndexB = concavePairs[i].y; + + int collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx; + int collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx; + + int shapeIndexA = collidables[collidableIndexA].m_shapeIndex; + int shapeIndexB = collidables[collidableIndexB].m_shapeIndex; + + if (collidables[collidableIndexB].m_shapeType!=SHAPE_CONVEX_HULL&& + collidables[collidableIndexB].m_shapeType!=SHAPE_COMPOUND_OF_CONVEX_HULLS) + { + concavePairs[pairIdx].w = -1; + return; + } + + hasSeparatingNormals[i] = 0; + +// int numFacesA = convexShapes[shapeIndexA].m_numFaces; + int numActualConcaveConvexTests = 0; + + int f = concavePairs[i].z; + + bool overlap = false; + + b3ConvexPolyhedronData convexPolyhedronA; + + //add 3 vertices of the triangle + convexPolyhedronA.m_numVertices = 3; + convexPolyhedronA.m_vertexOffset = 0; + b3Float4 localCenter = b3MakeFloat4(0.f,0.f,0.f,0.f); + + b3GpuFace face = faces[convexShapes[shapeIndexA].m_faceOffset+f]; + b3Aabb triAabb; + triAabb.m_minVec = b3MakeFloat4(1e30f,1e30f,1e30f,0.f); + triAabb.m_maxVec = b3MakeFloat4(-1e30f,-1e30f,-1e30f,0.f); + + b3Float4 verticesA[3]; + for (int i=0;i<3;i++) + { + int index = indices[face.m_indexOffset+i]; + b3Float4 vert = vertices[convexShapes[shapeIndexA].m_vertexOffset+index]; + verticesA[i] = vert; + localCenter += vert; + + triAabb.m_minVec = b3MinFloat4(triAabb.m_minVec,vert); + triAabb.m_maxVec = b3MaxFloat4(triAabb.m_maxVec,vert); + + } + + overlap = true; + overlap = (triAabb.m_minVec.x > aabbs[bodyIndexB].m_maxVec.x || triAabb.m_maxVec.x < aabbs[bodyIndexB].m_minVec.x) ? false : overlap; + overlap = (triAabb.m_minVec.z > aabbs[bodyIndexB].m_maxVec.z || triAabb.m_maxVec.z < aabbs[bodyIndexB].m_minVec.z) ? false : overlap; + overlap = (triAabb.m_minVec.y > aabbs[bodyIndexB].m_maxVec.y || triAabb.m_maxVec.y < aabbs[bodyIndexB].m_minVec.y) ? false : overlap; + + if (overlap) + { + float dmin = FLT_MAX; + int hasSeparatingAxis=5; + b3Float4 sepAxis=b3MakeFloat4(1,2,3,4); + + // int localCC=0; + numActualConcaveConvexTests++; + + //a triangle has 3 unique edges + convexPolyhedronA.m_numUniqueEdges = 3; + convexPolyhedronA.m_uniqueEdgesOffset = 0; + b3Float4 uniqueEdgesA[3]; + + uniqueEdgesA[0] = (verticesA[1]-verticesA[0]); + uniqueEdgesA[1] = (verticesA[2]-verticesA[1]); + uniqueEdgesA[2] = (verticesA[0]-verticesA[2]); + + + convexPolyhedronA.m_faceOffset = 0; + + b3Float4 normal = b3MakeFloat4(face.m_plane.x,face.m_plane.y,face.m_plane.z,0.f); + + b3GpuFace facesA[B3_TRIANGLE_NUM_CONVEX_FACES]; + int indicesA[3+3+2+2+2]; + int curUsedIndices=0; + int fidx=0; + + //front size of triangle + { + facesA[fidx].m_indexOffset=curUsedIndices; + indicesA[0] = 0; + indicesA[1] = 1; + indicesA[2] = 2; + curUsedIndices+=3; + float c = face.m_plane.w; + facesA[fidx].m_plane.x = normal.x; + facesA[fidx].m_plane.y = normal.y; + facesA[fidx].m_plane.z = normal.z; + facesA[fidx].m_plane.w = c; + facesA[fidx].m_numIndices=3; + } + fidx++; + //back size of triangle + { + facesA[fidx].m_indexOffset=curUsedIndices; + indicesA[3]=2; + indicesA[4]=1; + indicesA[5]=0; + curUsedIndices+=3; + float c = b3Dot(normal,verticesA[0]); + // float c1 = -face.m_plane.w; + facesA[fidx].m_plane.x = -normal.x; + facesA[fidx].m_plane.y = -normal.y; + facesA[fidx].m_plane.z = -normal.z; + facesA[fidx].m_plane.w = c; + facesA[fidx].m_numIndices=3; + } + fidx++; + + bool addEdgePlanes = true; + if (addEdgePlanes) + { + int numVertices=3; + int prevVertex = numVertices-1; + for (int i=0;i& vertices, b3Scalar& min, b3Scalar& max) +{ + min = FLT_MAX; + max = -FLT_MAX; + int numVerts = hull.m_numVertices; + + const b3Float4 localDir = b3QuatRotate(orn.inverse(),dir); + + b3Scalar offset = b3Dot3F4(pos,dir); + + for(int i=0;i max) max = dp; + } + if(min>max) + { + b3Scalar tmp = min; + min = max; + max = tmp; + } + min += offset; + max += offset; +} + + +inline bool b3TestSepAxis(const b3ConvexPolyhedronData& hullA, const b3ConvexPolyhedronData& hullB, + const b3Float4& posA,const b3Quaternion& ornA, + const b3Float4& posB,const b3Quaternion& ornB, + const b3Float4& sep_axis, const b3AlignedObjectArray& verticesA,const b3AlignedObjectArray& verticesB,b3Scalar& depth) +{ + b3Scalar Min0,Max0; + b3Scalar Min1,Max1; + b3ProjectAxis(hullA,posA,ornA,sep_axis,verticesA, Min0, Max0); + b3ProjectAxis(hullB,posB,ornB, sep_axis,verticesB, Min1, Max1); + + if(Max0=0.0f); + b3Scalar d1 = Max1 - Min0; + b3Assert(d1>=0.0f); + depth = d0& verticesA, + const b3AlignedObjectArray& uniqueEdgesA, + const b3AlignedObjectArray& facesA, + const b3AlignedObjectArray& indicesA, + const b3AlignedObjectArray& verticesB, + const b3AlignedObjectArray& uniqueEdgesB, + const b3AlignedObjectArray& facesB, + const b3AlignedObjectArray& indicesB, + + b3Vector3& sep) +{ + B3_PROFILE("findSeparatingAxis"); + + b3Float4 posA = posA1; + posA.w = 0.f; + b3Float4 posB = posB1; + posB.w = 0.f; +//#ifdef TEST_INTERNAL_OBJECTS + b3Float4 c0local = (b3Float4&)hullA.m_localCenter; + + b3Float4 c0 = b3TransformPoint(c0local, posA, ornA); + b3Float4 c1local = (b3Float4&)hullB.m_localCenter; + b3Float4 c1 = b3TransformPoint(c1local,posB,ornB); + const b3Float4 deltaC2 = c0 - c1; +//#endif + + b3Scalar dmin = FLT_MAX; + int curPlaneTests=0; + + int numFacesA = hullA.m_numFaces; + // Test normals from hullA + for(int i=0;i0.0f) + sep = -sep; + + return true; +} + +#endif //B3_FIND_SEPARATING_AXIS_H + diff --git a/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3MprPenetration.h b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3MprPenetration.h new file mode 100644 index 000000000000..6c3ad7c9dd9b --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3MprPenetration.h @@ -0,0 +1,920 @@ + +/*** + * --------------------------------- + * Copyright (c)2012 Daniel Fiser + * + * This file was ported from mpr.c file, part of libccd. + * The Minkoski Portal Refinement implementation was ported + * to OpenCL by Erwin Coumans for the Bullet 3 Physics library. + * at http://github.com/erwincoumans/bullet3 + * + * Distributed under the OSI-approved BSD License (the "License"); + * see . + * This software is distributed WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the License for more information. + */ + + + + +#ifndef B3_MPR_PENETRATION_H +#define B3_MPR_PENETRATION_H + +#include "Bullet3Common/shared/b3PlatformDefinitions.h" +#include "Bullet3Common/shared/b3Float4.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3ConvexPolyhedronData.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3Collidable.h" + + + + +#ifdef __cplusplus +#define B3_MPR_SQRT sqrtf +#else +#define B3_MPR_SQRT sqrt +#endif +#define B3_MPR_FMIN(x, y) ((x) < (y) ? (x) : (y)) +#define B3_MPR_FABS fabs + +#define B3_MPR_TOLERANCE 1E-6f +#define B3_MPR_MAX_ITERATIONS 1000 + +struct _b3MprSupport_t +{ + b3Float4 v; //!< Support point in minkowski sum + b3Float4 v1; //!< Support point in obj1 + b3Float4 v2; //!< Support point in obj2 +}; +typedef struct _b3MprSupport_t b3MprSupport_t; + +struct _b3MprSimplex_t +{ + b3MprSupport_t ps[4]; + int last; //!< index of last added point +}; +typedef struct _b3MprSimplex_t b3MprSimplex_t; + +inline b3MprSupport_t* b3MprSimplexPointW(b3MprSimplex_t *s, int idx) +{ + return &s->ps[idx]; +} + +inline void b3MprSimplexSetSize(b3MprSimplex_t *s, int size) +{ + s->last = size - 1; +} + + +inline int b3MprSimplexSize(const b3MprSimplex_t *s) +{ + return s->last + 1; +} + + +inline const b3MprSupport_t* b3MprSimplexPoint(const b3MprSimplex_t* s, int idx) +{ + // here is no check on boundaries + return &s->ps[idx]; +} + +inline void b3MprSupportCopy(b3MprSupport_t *d, const b3MprSupport_t *s) +{ + *d = *s; +} + +inline void b3MprSimplexSet(b3MprSimplex_t *s, size_t pos, const b3MprSupport_t *a) +{ + b3MprSupportCopy(s->ps + pos, a); +} + + +inline void b3MprSimplexSwap(b3MprSimplex_t *s, size_t pos1, size_t pos2) +{ + b3MprSupport_t supp; + + b3MprSupportCopy(&supp, &s->ps[pos1]); + b3MprSupportCopy(&s->ps[pos1], &s->ps[pos2]); + b3MprSupportCopy(&s->ps[pos2], &supp); +} + + +inline int b3MprIsZero(float val) +{ + return B3_MPR_FABS(val) < FLT_EPSILON; +} + + + +inline int b3MprEq(float _a, float _b) +{ + float ab; + float a, b; + + ab = B3_MPR_FABS(_a - _b); + if (B3_MPR_FABS(ab) < FLT_EPSILON) + return 1; + + a = B3_MPR_FABS(_a); + b = B3_MPR_FABS(_b); + if (b > a){ + return ab < FLT_EPSILON * b; + }else{ + return ab < FLT_EPSILON * a; + } +} + + +inline int b3MprVec3Eq(const b3Float4* a, const b3Float4 *b) +{ + return b3MprEq((*a).x, (*b).x) + && b3MprEq((*a).y, (*b).y) + && b3MprEq((*a).z, (*b).z); +} + + + +inline b3Float4 b3LocalGetSupportVertex(b3Float4ConstArg supportVec,__global const b3ConvexPolyhedronData_t* hull, b3ConstArray(b3Float4) verticesA) +{ + b3Float4 supVec = b3MakeFloat4(0,0,0,0); + float maxDot = -B3_LARGE_FLOAT; + + if( 0 < hull->m_numVertices ) + { + const b3Float4 scaled = supportVec; + int index = b3MaxDot(scaled, &verticesA[hull->m_vertexOffset], hull->m_numVertices, &maxDot); + return verticesA[hull->m_vertexOffset+index]; + } + + return supVec; + +} + + +B3_STATIC void b3MprConvexSupport(int pairIndex,int bodyIndex, b3ConstArray(b3RigidBodyData_t) cpuBodyBuf, + b3ConstArray(b3ConvexPolyhedronData_t) cpuConvexData, + b3ConstArray(b3Collidable_t) cpuCollidables, + b3ConstArray(b3Float4) cpuVertices, + __global b3Float4* sepAxis, + const b3Float4* _dir, b3Float4* outp, int logme) +{ + //dir is in worldspace, move to local space + + b3Float4 pos = cpuBodyBuf[bodyIndex].m_pos; + b3Quat orn = cpuBodyBuf[bodyIndex].m_quat; + + b3Float4 dir = b3MakeFloat4((*_dir).x,(*_dir).y,(*_dir).z,0.f); + + const b3Float4 localDir = b3QuatRotate(b3QuatInverse(orn),dir); + + + //find local support vertex + int colIndex = cpuBodyBuf[bodyIndex].m_collidableIdx; + + b3Assert(cpuCollidables[colIndex].m_shapeType==SHAPE_CONVEX_HULL); + __global const b3ConvexPolyhedronData_t* hull = &cpuConvexData[cpuCollidables[colIndex].m_shapeIndex]; + + b3Float4 pInA; + if (logme) + { + + + // b3Float4 supVec = b3MakeFloat4(0,0,0,0); + float maxDot = -B3_LARGE_FLOAT; + + if( 0 < hull->m_numVertices ) + { + const b3Float4 scaled = localDir; + int index = b3MaxDot(scaled, &cpuVertices[hull->m_vertexOffset], hull->m_numVertices, &maxDot); + pInA = cpuVertices[hull->m_vertexOffset+index]; + + } + + + } else + { + pInA = b3LocalGetSupportVertex(localDir,hull,cpuVertices); + } + + //move vertex to world space + *outp = b3TransformPoint(pInA,pos,orn); + +} + +inline void b3MprSupport(int pairIndex,int bodyIndexA, int bodyIndexB, b3ConstArray(b3RigidBodyData_t) cpuBodyBuf, + b3ConstArray(b3ConvexPolyhedronData_t) cpuConvexData, + b3ConstArray(b3Collidable_t) cpuCollidables, + b3ConstArray(b3Float4) cpuVertices, + __global b3Float4* sepAxis, + const b3Float4* _dir, b3MprSupport_t *supp) +{ + b3Float4 dir; + dir = *_dir; + b3MprConvexSupport(pairIndex,bodyIndexA,cpuBodyBuf,cpuConvexData,cpuCollidables,cpuVertices,sepAxis,&dir, &supp->v1,0); + dir = *_dir*-1.f; + b3MprConvexSupport(pairIndex,bodyIndexB,cpuBodyBuf,cpuConvexData,cpuCollidables,cpuVertices,sepAxis,&dir, &supp->v2,0); + supp->v = supp->v1 - supp->v2; +} + + + + + + + + + +inline void b3FindOrigin(int bodyIndexA, int bodyIndexB, b3ConstArray(b3RigidBodyData_t) cpuBodyBuf, b3MprSupport_t *center) +{ + + center->v1 = cpuBodyBuf[bodyIndexA].m_pos; + center->v2 = cpuBodyBuf[bodyIndexB].m_pos; + center->v = center->v1 - center->v2; +} + +inline void b3MprVec3Set(b3Float4 *v, float x, float y, float z) +{ + (*v).x = x; + (*v).y = y; + (*v).z = z; + (*v).w = 0.f; +} + +inline void b3MprVec3Add(b3Float4 *v, const b3Float4 *w) +{ + (*v).x += (*w).x; + (*v).y += (*w).y; + (*v).z += (*w).z; +} + +inline void b3MprVec3Copy(b3Float4 *v, const b3Float4 *w) +{ + *v = *w; +} + +inline void b3MprVec3Scale(b3Float4 *d, float k) +{ + *d *= k; +} + +inline float b3MprVec3Dot(const b3Float4 *a, const b3Float4 *b) +{ + float dot; + + dot = b3Dot3F4(*a,*b); + return dot; +} + + +inline float b3MprVec3Len2(const b3Float4 *v) +{ + return b3MprVec3Dot(v, v); +} + +inline void b3MprVec3Normalize(b3Float4 *d) +{ + float k = 1.f / B3_MPR_SQRT(b3MprVec3Len2(d)); + b3MprVec3Scale(d, k); +} + +inline void b3MprVec3Cross(b3Float4 *d, const b3Float4 *a, const b3Float4 *b) +{ + *d = b3Cross3(*a,*b); + +} + + +inline void b3MprVec3Sub2(b3Float4 *d, const b3Float4 *v, const b3Float4 *w) +{ + *d = *v - *w; +} + +inline void b3PortalDir(const b3MprSimplex_t *portal, b3Float4 *dir) +{ + b3Float4 v2v1, v3v1; + + b3MprVec3Sub2(&v2v1, &b3MprSimplexPoint(portal, 2)->v, + &b3MprSimplexPoint(portal, 1)->v); + b3MprVec3Sub2(&v3v1, &b3MprSimplexPoint(portal, 3)->v, + &b3MprSimplexPoint(portal, 1)->v); + b3MprVec3Cross(dir, &v2v1, &v3v1); + b3MprVec3Normalize(dir); +} + + +inline int portalEncapsulesOrigin(const b3MprSimplex_t *portal, + const b3Float4 *dir) +{ + float dot; + dot = b3MprVec3Dot(dir, &b3MprSimplexPoint(portal, 1)->v); + return b3MprIsZero(dot) || dot > 0.f; +} + +inline int portalReachTolerance(const b3MprSimplex_t *portal, + const b3MprSupport_t *v4, + const b3Float4 *dir) +{ + float dv1, dv2, dv3, dv4; + float dot1, dot2, dot3; + + // find the smallest dot product of dir and {v1-v4, v2-v4, v3-v4} + + dv1 = b3MprVec3Dot(&b3MprSimplexPoint(portal, 1)->v, dir); + dv2 = b3MprVec3Dot(&b3MprSimplexPoint(portal, 2)->v, dir); + dv3 = b3MprVec3Dot(&b3MprSimplexPoint(portal, 3)->v, dir); + dv4 = b3MprVec3Dot(&v4->v, dir); + + dot1 = dv4 - dv1; + dot2 = dv4 - dv2; + dot3 = dv4 - dv3; + + dot1 = B3_MPR_FMIN(dot1, dot2); + dot1 = B3_MPR_FMIN(dot1, dot3); + + return b3MprEq(dot1, B3_MPR_TOLERANCE) || dot1 < B3_MPR_TOLERANCE; +} + +inline int portalCanEncapsuleOrigin(const b3MprSimplex_t *portal, + const b3MprSupport_t *v4, + const b3Float4 *dir) +{ + float dot; + dot = b3MprVec3Dot(&v4->v, dir); + return b3MprIsZero(dot) || dot > 0.f; +} + +inline void b3ExpandPortal(b3MprSimplex_t *portal, + const b3MprSupport_t *v4) +{ + float dot; + b3Float4 v4v0; + + b3MprVec3Cross(&v4v0, &v4->v, &b3MprSimplexPoint(portal, 0)->v); + dot = b3MprVec3Dot(&b3MprSimplexPoint(portal, 1)->v, &v4v0); + if (dot > 0.f){ + dot = b3MprVec3Dot(&b3MprSimplexPoint(portal, 2)->v, &v4v0); + if (dot > 0.f){ + b3MprSimplexSet(portal, 1, v4); + }else{ + b3MprSimplexSet(portal, 3, v4); + } + }else{ + dot = b3MprVec3Dot(&b3MprSimplexPoint(portal, 3)->v, &v4v0); + if (dot > 0.f){ + b3MprSimplexSet(portal, 2, v4); + }else{ + b3MprSimplexSet(portal, 1, v4); + } + } +} + + + +B3_STATIC int b3DiscoverPortal(int pairIndex, int bodyIndexA, int bodyIndexB, b3ConstArray(b3RigidBodyData_t) cpuBodyBuf, + b3ConstArray(b3ConvexPolyhedronData_t) cpuConvexData, + b3ConstArray(b3Collidable_t) cpuCollidables, + b3ConstArray(b3Float4) cpuVertices, + __global b3Float4* sepAxis, + __global int* hasSepAxis, + b3MprSimplex_t *portal) +{ + b3Float4 dir, va, vb; + float dot; + int cont; + + + + // vertex 0 is center of portal + b3FindOrigin(bodyIndexA,bodyIndexB,cpuBodyBuf, b3MprSimplexPointW(portal, 0)); + // vertex 0 is center of portal + b3MprSimplexSetSize(portal, 1); + + + + b3Float4 zero = b3MakeFloat4(0,0,0,0); + b3Float4* b3mpr_vec3_origin = &zero; + + if (b3MprVec3Eq(&b3MprSimplexPoint(portal, 0)->v, b3mpr_vec3_origin)){ + // Portal's center lies on origin (0,0,0) => we know that objects + // intersect but we would need to know penetration info. + // So move center little bit... + b3MprVec3Set(&va, FLT_EPSILON * 10.f, 0.f, 0.f); + b3MprVec3Add(&b3MprSimplexPointW(portal, 0)->v, &va); + } + + + // vertex 1 = support in direction of origin + b3MprVec3Copy(&dir, &b3MprSimplexPoint(portal, 0)->v); + b3MprVec3Scale(&dir, -1.f); + b3MprVec3Normalize(&dir); + + + b3MprSupport(pairIndex,bodyIndexA,bodyIndexB,cpuBodyBuf,cpuConvexData,cpuCollidables,cpuVertices, sepAxis,&dir, b3MprSimplexPointW(portal, 1)); + + b3MprSimplexSetSize(portal, 2); + + // test if origin isn't outside of v1 + dot = b3MprVec3Dot(&b3MprSimplexPoint(portal, 1)->v, &dir); + + + if (b3MprIsZero(dot) || dot < 0.f) + return -1; + + + // vertex 2 + b3MprVec3Cross(&dir, &b3MprSimplexPoint(portal, 0)->v, + &b3MprSimplexPoint(portal, 1)->v); + if (b3MprIsZero(b3MprVec3Len2(&dir))){ + if (b3MprVec3Eq(&b3MprSimplexPoint(portal, 1)->v, b3mpr_vec3_origin)){ + // origin lies on v1 + return 1; + }else{ + // origin lies on v0-v1 segment + return 2; + } + } + + b3MprVec3Normalize(&dir); + b3MprSupport(pairIndex,bodyIndexA,bodyIndexB,cpuBodyBuf,cpuConvexData,cpuCollidables,cpuVertices, sepAxis,&dir, b3MprSimplexPointW(portal, 2)); + + dot = b3MprVec3Dot(&b3MprSimplexPoint(portal, 2)->v, &dir); + if (b3MprIsZero(dot) || dot < 0.f) + return -1; + + b3MprSimplexSetSize(portal, 3); + + // vertex 3 direction + b3MprVec3Sub2(&va, &b3MprSimplexPoint(portal, 1)->v, + &b3MprSimplexPoint(portal, 0)->v); + b3MprVec3Sub2(&vb, &b3MprSimplexPoint(portal, 2)->v, + &b3MprSimplexPoint(portal, 0)->v); + b3MprVec3Cross(&dir, &va, &vb); + b3MprVec3Normalize(&dir); + + // it is better to form portal faces to be oriented "outside" origin + dot = b3MprVec3Dot(&dir, &b3MprSimplexPoint(portal, 0)->v); + if (dot > 0.f){ + b3MprSimplexSwap(portal, 1, 2); + b3MprVec3Scale(&dir, -1.f); + } + + while (b3MprSimplexSize(portal) < 4){ + b3MprSupport(pairIndex,bodyIndexA,bodyIndexB,cpuBodyBuf,cpuConvexData,cpuCollidables,cpuVertices, sepAxis,&dir, b3MprSimplexPointW(portal, 3)); + + dot = b3MprVec3Dot(&b3MprSimplexPoint(portal, 3)->v, &dir); + if (b3MprIsZero(dot) || dot < 0.f) + return -1; + + cont = 0; + + // test if origin is outside (v1, v0, v3) - set v2 as v3 and + // continue + b3MprVec3Cross(&va, &b3MprSimplexPoint(portal, 1)->v, + &b3MprSimplexPoint(portal, 3)->v); + dot = b3MprVec3Dot(&va, &b3MprSimplexPoint(portal, 0)->v); + if (dot < 0.f && !b3MprIsZero(dot)){ + b3MprSimplexSet(portal, 2, b3MprSimplexPoint(portal, 3)); + cont = 1; + } + + if (!cont){ + // test if origin is outside (v3, v0, v2) - set v1 as v3 and + // continue + b3MprVec3Cross(&va, &b3MprSimplexPoint(portal, 3)->v, + &b3MprSimplexPoint(portal, 2)->v); + dot = b3MprVec3Dot(&va, &b3MprSimplexPoint(portal, 0)->v); + if (dot < 0.f && !b3MprIsZero(dot)){ + b3MprSimplexSet(portal, 1, b3MprSimplexPoint(portal, 3)); + cont = 1; + } + } + + if (cont){ + b3MprVec3Sub2(&va, &b3MprSimplexPoint(portal, 1)->v, + &b3MprSimplexPoint(portal, 0)->v); + b3MprVec3Sub2(&vb, &b3MprSimplexPoint(portal, 2)->v, + &b3MprSimplexPoint(portal, 0)->v); + b3MprVec3Cross(&dir, &va, &vb); + b3MprVec3Normalize(&dir); + }else{ + b3MprSimplexSetSize(portal, 4); + } + } + + return 0; +} + + +B3_STATIC int b3RefinePortal(int pairIndex,int bodyIndexA, int bodyIndexB, b3ConstArray(b3RigidBodyData_t) cpuBodyBuf, + b3ConstArray(b3ConvexPolyhedronData_t) cpuConvexData, + b3ConstArray(b3Collidable_t) cpuCollidables, + b3ConstArray(b3Float4) cpuVertices, + __global b3Float4* sepAxis, + b3MprSimplex_t *portal) +{ + b3Float4 dir; + b3MprSupport_t v4; + + for (int i=0;iv, + &b3MprSimplexPoint(portal, 2)->v); + b[0] = b3MprVec3Dot(&vec, &b3MprSimplexPoint(portal, 3)->v); + + b3MprVec3Cross(&vec, &b3MprSimplexPoint(portal, 3)->v, + &b3MprSimplexPoint(portal, 2)->v); + b[1] = b3MprVec3Dot(&vec, &b3MprSimplexPoint(portal, 0)->v); + + b3MprVec3Cross(&vec, &b3MprSimplexPoint(portal, 0)->v, + &b3MprSimplexPoint(portal, 1)->v); + b[2] = b3MprVec3Dot(&vec, &b3MprSimplexPoint(portal, 3)->v); + + b3MprVec3Cross(&vec, &b3MprSimplexPoint(portal, 2)->v, + &b3MprSimplexPoint(portal, 1)->v); + b[3] = b3MprVec3Dot(&vec, &b3MprSimplexPoint(portal, 0)->v); + + sum = b[0] + b[1] + b[2] + b[3]; + + if (b3MprIsZero(sum) || sum < 0.f){ + b[0] = 0.f; + + b3MprVec3Cross(&vec, &b3MprSimplexPoint(portal, 2)->v, + &b3MprSimplexPoint(portal, 3)->v); + b[1] = b3MprVec3Dot(&vec, &dir); + b3MprVec3Cross(&vec, &b3MprSimplexPoint(portal, 3)->v, + &b3MprSimplexPoint(portal, 1)->v); + b[2] = b3MprVec3Dot(&vec, &dir); + b3MprVec3Cross(&vec, &b3MprSimplexPoint(portal, 1)->v, + &b3MprSimplexPoint(portal, 2)->v); + b[3] = b3MprVec3Dot(&vec, &dir); + + sum = b[1] + b[2] + b[3]; + } + + inv = 1.f / sum; + + b3MprVec3Copy(&p1, b3mpr_vec3_origin); + b3MprVec3Copy(&p2, b3mpr_vec3_origin); + for (i = 0; i < 4; i++){ + b3MprVec3Copy(&vec, &b3MprSimplexPoint(portal, i)->v1); + b3MprVec3Scale(&vec, b[i]); + b3MprVec3Add(&p1, &vec); + + b3MprVec3Copy(&vec, &b3MprSimplexPoint(portal, i)->v2); + b3MprVec3Scale(&vec, b[i]); + b3MprVec3Add(&p2, &vec); + } + b3MprVec3Scale(&p1, inv); + b3MprVec3Scale(&p2, inv); + + b3MprVec3Copy(pos, &p1); + b3MprVec3Add(pos, &p2); + b3MprVec3Scale(pos, 0.5); +} + +inline float b3MprVec3Dist2(const b3Float4 *a, const b3Float4 *b) +{ + b3Float4 ab; + b3MprVec3Sub2(&ab, a, b); + return b3MprVec3Len2(&ab); +} + +inline float _b3MprVec3PointSegmentDist2(const b3Float4 *P, + const b3Float4 *x0, + const b3Float4 *b, + b3Float4 *witness) +{ + // The computation comes from solving equation of segment: + // S(t) = x0 + t.d + // where - x0 is initial point of segment + // - d is direction of segment from x0 (|d| > 0) + // - t belongs to <0, 1> interval + // + // Than, distance from a segment to some point P can be expressed: + // D(t) = |x0 + t.d - P|^2 + // which is distance from any point on segment. Minimization + // of this function brings distance from P to segment. + // Minimization of D(t) leads to simple quadratic equation that's + // solving is straightforward. + // + // Bonus of this method is witness point for free. + + float dist, t; + b3Float4 d, a; + + // direction of segment + b3MprVec3Sub2(&d, b, x0); + + // precompute vector from P to x0 + b3MprVec3Sub2(&a, x0, P); + + t = -1.f * b3MprVec3Dot(&a, &d); + t /= b3MprVec3Len2(&d); + + if (t < 0.f || b3MprIsZero(t)){ + dist = b3MprVec3Dist2(x0, P); + if (witness) + b3MprVec3Copy(witness, x0); + }else if (t > 1.f || b3MprEq(t, 1.f)){ + dist = b3MprVec3Dist2(b, P); + if (witness) + b3MprVec3Copy(witness, b); + }else{ + if (witness){ + b3MprVec3Copy(witness, &d); + b3MprVec3Scale(witness, t); + b3MprVec3Add(witness, x0); + dist = b3MprVec3Dist2(witness, P); + }else{ + // recycling variables + b3MprVec3Scale(&d, t); + b3MprVec3Add(&d, &a); + dist = b3MprVec3Len2(&d); + } + } + + return dist; +} + + +inline float b3MprVec3PointTriDist2(const b3Float4 *P, + const b3Float4 *x0, const b3Float4 *B, + const b3Float4 *C, + b3Float4 *witness) +{ + // Computation comes from analytic expression for triangle (x0, B, C) + // T(s, t) = x0 + s.d1 + t.d2, where d1 = B - x0 and d2 = C - x0 and + // Then equation for distance is: + // D(s, t) = | T(s, t) - P |^2 + // This leads to minimization of quadratic function of two variables. + // The solution from is taken only if s is between 0 and 1, t is + // between 0 and 1 and t + s < 1, otherwise distance from segment is + // computed. + + b3Float4 d1, d2, a; + float u, v, w, p, q, r; + float s, t, dist, dist2; + b3Float4 witness2; + + b3MprVec3Sub2(&d1, B, x0); + b3MprVec3Sub2(&d2, C, x0); + b3MprVec3Sub2(&a, x0, P); + + u = b3MprVec3Dot(&a, &a); + v = b3MprVec3Dot(&d1, &d1); + w = b3MprVec3Dot(&d2, &d2); + p = b3MprVec3Dot(&a, &d1); + q = b3MprVec3Dot(&a, &d2); + r = b3MprVec3Dot(&d1, &d2); + + s = (q * r - w * p) / (w * v - r * r); + t = (-s * r - q) / w; + + if ((b3MprIsZero(s) || s > 0.f) + && (b3MprEq(s, 1.f) || s < 1.f) + && (b3MprIsZero(t) || t > 0.f) + && (b3MprEq(t, 1.f) || t < 1.f) + && (b3MprEq(t + s, 1.f) || t + s < 1.f)){ + + if (witness){ + b3MprVec3Scale(&d1, s); + b3MprVec3Scale(&d2, t); + b3MprVec3Copy(witness, x0); + b3MprVec3Add(witness, &d1); + b3MprVec3Add(witness, &d2); + + dist = b3MprVec3Dist2(witness, P); + }else{ + dist = s * s * v; + dist += t * t * w; + dist += 2.f * s * t * r; + dist += 2.f * s * p; + dist += 2.f * t * q; + dist += u; + } + }else{ + dist = _b3MprVec3PointSegmentDist2(P, x0, B, witness); + + dist2 = _b3MprVec3PointSegmentDist2(P, x0, C, &witness2); + if (dist2 < dist){ + dist = dist2; + if (witness) + b3MprVec3Copy(witness, &witness2); + } + + dist2 = _b3MprVec3PointSegmentDist2(P, B, C, &witness2); + if (dist2 < dist){ + dist = dist2; + if (witness) + b3MprVec3Copy(witness, &witness2); + } + } + + return dist; +} + + +B3_STATIC void b3FindPenetr(int pairIndex,int bodyIndexA, int bodyIndexB, b3ConstArray(b3RigidBodyData_t) cpuBodyBuf, + b3ConstArray(b3ConvexPolyhedronData_t) cpuConvexData, + b3ConstArray(b3Collidable_t) cpuCollidables, + b3ConstArray(b3Float4) cpuVertices, + __global b3Float4* sepAxis, + b3MprSimplex_t *portal, + float *depth, b3Float4 *pdir, b3Float4 *pos) +{ + b3Float4 dir; + b3MprSupport_t v4; + unsigned long iterations; + + b3Float4 zero = b3MakeFloat4(0,0,0,0); + b3Float4* b3mpr_vec3_origin = &zero; + + + iterations = 1UL; + for (int i=0;i find penetration info + if (portalReachTolerance(portal, &v4, &dir) + || iterations ==B3_MPR_MAX_ITERATIONS) + { + *depth = b3MprVec3PointTriDist2(b3mpr_vec3_origin,&b3MprSimplexPoint(portal, 1)->v,&b3MprSimplexPoint(portal, 2)->v,&b3MprSimplexPoint(portal, 3)->v,pdir); + *depth = B3_MPR_SQRT(*depth); + + if (b3MprIsZero((*pdir).x) && b3MprIsZero((*pdir).y) && b3MprIsZero((*pdir).z)) + { + + *pdir = dir; + } + b3MprVec3Normalize(pdir); + + // barycentric coordinates: + b3FindPos(portal, pos); + + + return; + } + + b3ExpandPortal(portal, &v4); + + iterations++; + } +} + +B3_STATIC void b3FindPenetrTouch(b3MprSimplex_t *portal,float *depth, b3Float4 *dir, b3Float4 *pos) +{ + // Touching contact on portal's v1 - so depth is zero and direction + // is unimportant and pos can be guessed + *depth = 0.f; + b3Float4 zero = b3MakeFloat4(0,0,0,0); + b3Float4* b3mpr_vec3_origin = &zero; + + + b3MprVec3Copy(dir, b3mpr_vec3_origin); + + b3MprVec3Copy(pos, &b3MprSimplexPoint(portal, 1)->v1); + b3MprVec3Add(pos, &b3MprSimplexPoint(portal, 1)->v2); + b3MprVec3Scale(pos, 0.5); +} + +B3_STATIC void b3FindPenetrSegment(b3MprSimplex_t *portal, + float *depth, b3Float4 *dir, b3Float4 *pos) +{ + + // Origin lies on v0-v1 segment. + // Depth is distance to v1, direction also and position must be + // computed + + b3MprVec3Copy(pos, &b3MprSimplexPoint(portal, 1)->v1); + b3MprVec3Add(pos, &b3MprSimplexPoint(portal, 1)->v2); + b3MprVec3Scale(pos, 0.5f); + + + b3MprVec3Copy(dir, &b3MprSimplexPoint(portal, 1)->v); + *depth = B3_MPR_SQRT(b3MprVec3Len2(dir)); + b3MprVec3Normalize(dir); +} + + + +inline int b3MprPenetration(int pairIndex, int bodyIndexA, int bodyIndexB, + b3ConstArray(b3RigidBodyData_t) cpuBodyBuf, + b3ConstArray(b3ConvexPolyhedronData_t) cpuConvexData, + b3ConstArray(b3Collidable_t) cpuCollidables, + b3ConstArray(b3Float4) cpuVertices, + __global b3Float4* sepAxis, + __global int* hasSepAxis, + float *depthOut, b3Float4* dirOut, b3Float4* posOut) +{ + + b3MprSimplex_t portal; + + +// if (!hasSepAxis[pairIndex]) + // return -1; + + hasSepAxis[pairIndex] = 0; + int res; + + // Phase 1: Portal discovery + res = b3DiscoverPortal(pairIndex,bodyIndexA,bodyIndexB,cpuBodyBuf,cpuConvexData,cpuCollidables,cpuVertices,sepAxis,hasSepAxis, &portal); + + + //sepAxis[pairIndex] = *pdir;//or -dir? + + switch (res) + { + case 0: + { + // Phase 2: Portal refinement + + res = b3RefinePortal(pairIndex,bodyIndexA,bodyIndexB,cpuBodyBuf,cpuConvexData,cpuCollidables,cpuVertices, sepAxis,&portal); + if (res < 0) + return -1; + + // Phase 3. Penetration info + b3FindPenetr(pairIndex,bodyIndexA,bodyIndexB,cpuBodyBuf,cpuConvexData,cpuCollidables,cpuVertices, sepAxis,&portal, depthOut, dirOut, posOut); + hasSepAxis[pairIndex] = 1; + sepAxis[pairIndex] = -*dirOut; + break; + } + case 1: + { + // Touching contact on portal's v1. + b3FindPenetrTouch(&portal, depthOut, dirOut, posOut); + break; + } + case 2: + { + + b3FindPenetrSegment( &portal, depthOut, dirOut, posOut); + break; + } + default: + { + hasSepAxis[pairIndex]=0; + //if (res < 0) + //{ + // Origin isn't inside portal - no collision. + return -1; + //} + } + }; + + return 0; +}; + + + +#endif //B3_MPR_PENETRATION_H diff --git a/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3NewContactReduction.h b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3NewContactReduction.h new file mode 100644 index 000000000000..718222ebcae9 --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3NewContactReduction.h @@ -0,0 +1,196 @@ + +#ifndef B3_NEW_CONTACT_REDUCTION_H +#define B3_NEW_CONTACT_REDUCTION_H + +#include "Bullet3Common/shared/b3Float4.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3Contact4Data.h" + +#define GET_NPOINTS(x) (x).m_worldNormalOnB.w + + +int b3ExtractManifoldSequentialGlobal(__global const b3Float4* p, int nPoints, b3Float4ConstArg nearNormal, b3Int4* contactIdx) +{ + if( nPoints == 0 ) + return 0; + + if (nPoints <=4) + return nPoints; + + + if (nPoints >64) + nPoints = 64; + + b3Float4 center = b3MakeFloat4(0,0,0,0); + { + + for (int i=0;i0) + { + + __global b3Float4* pointsIn = &worldVertsB2[pairIndex*vertexFaceCapacity]; + b3Float4 normal = -separatingNormals[i]; + + int nReducedContacts = b3ExtractManifoldSequentialGlobal(pointsIn, nPoints, normal, &contactIdx); + + int dstIdx; + dstIdx = b3AtomicInc( nGlobalContactsOut); + +//#if 0 + b3Assert(dstIdx < contactCapacity); + if (dstIdx < contactCapacity) + { + + __global struct b3Contact4Data* c = &globalContactsOut[dstIdx]; + c->m_worldNormalOnB = -normal; + c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff); + c->m_batchIdx = pairIndex; + int bodyA = pairs[pairIndex].x; + int bodyB = pairs[pairIndex].y; + + pairs[pairIndex].w = dstIdx; + + c->m_bodyAPtrAndSignBit = rigidBodies[bodyA].m_invMass==0?-bodyA:bodyA; + c->m_bodyBPtrAndSignBit = rigidBodies[bodyB].m_invMass==0?-bodyB:bodyB; + c->m_childIndexA =-1; + c->m_childIndexB =-1; + + switch (nReducedContacts) + { + case 4: + c->m_worldPosB[3] = pointsIn[contactIdx.w]; + case 3: + c->m_worldPosB[2] = pointsIn[contactIdx.z]; + case 2: + c->m_worldPosB[1] = pointsIn[contactIdx.y]; + case 1: + c->m_worldPosB[0] = pointsIn[contactIdx.x]; + default: + { + } + }; + + GET_NPOINTS(*c) = nReducedContacts; + + } + + +//#endif + + }// if (numContactsOut>0) + }// if (hasSeparatingAxis[i]) + }// if (im_escapeIndexOrTriangleIndex&~(y)); +} + +inline int b3IsLeaf(const b3QuantizedBvhNodeData* rootNode) +{ + //skipindex is negative (internal node), triangleindex >=0 (leafnode) + return (rootNode->m_escapeIndexOrTriangleIndex >= 0)? 1 : 0; +} + +inline int b3GetEscapeIndex(const b3QuantizedBvhNodeData* rootNode) +{ + return -rootNode->m_escapeIndexOrTriangleIndex; +} + +inline void b3QuantizeWithClamp(unsigned short* out, b3Float4ConstArg point2,int isMax, b3Float4ConstArg bvhAabbMin, b3Float4ConstArg bvhAabbMax, b3Float4ConstArg bvhQuantization) +{ + b3Float4 clampedPoint = b3MaxFloat4(point2,bvhAabbMin); + clampedPoint = b3MinFloat4 (clampedPoint, bvhAabbMax); + + b3Float4 v = (clampedPoint - bvhAabbMin) * bvhQuantization; + if (isMax) + { + out[0] = (unsigned short) (((unsigned short)(v.x+1.f) | 1)); + out[1] = (unsigned short) (((unsigned short)(v.y+1.f) | 1)); + out[2] = (unsigned short) (((unsigned short)(v.z+1.f) | 1)); + } else + { + out[0] = (unsigned short) (((unsigned short)(v.x) & 0xfffe)); + out[1] = (unsigned short) (((unsigned short)(v.y) & 0xfffe)); + out[2] = (unsigned short) (((unsigned short)(v.z) & 0xfffe)); + } + +} + + +inline int b3TestQuantizedAabbAgainstQuantizedAabbSlow( + const unsigned short int* aabbMin1, + const unsigned short int* aabbMax1, + const unsigned short int* aabbMin2, + const unsigned short int* aabbMax2) +{ + //int overlap = 1; + if (aabbMin1[0] > aabbMax2[0]) + return 0; + if (aabbMax1[0] < aabbMin2[0]) + return 0; + if (aabbMin1[1] > aabbMax2[1]) + return 0; + if (aabbMax1[1] < aabbMin2[1]) + return 0; + if (aabbMin1[2] > aabbMax2[2]) + return 0; + if (aabbMax1[2] < aabbMin2[2]) + return 0; + return 1; + //overlap = ((aabbMin1[0] > aabbMax2[0]) || (aabbMax1[0] < aabbMin2[0])) ? 0 : overlap; + //overlap = ((aabbMin1[2] > aabbMax2[2]) || (aabbMax1[2] < aabbMin2[2])) ? 0 : overlap; + //overlap = ((aabbMin1[1] > aabbMax2[1]) || (aabbMax1[1] < aabbMin2[1])) ? 0 : overlap; + //return overlap; +} + + +#endif //B3_QUANTIZED_BVH_NODE_H diff --git a/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3ReduceContacts.h b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3ReduceContacts.h new file mode 100644 index 000000000000..35b51970063e --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/NarrowPhaseCollision/shared/b3ReduceContacts.h @@ -0,0 +1,97 @@ +#ifndef B3_REDUCE_CONTACTS_H +#define B3_REDUCE_CONTACTS_H + +inline int b3ReduceContacts(const b3Float4* p, int nPoints, const b3Float4& nearNormal, b3Int4* contactIdx) +{ + if( nPoints == 0 ) + return 0; + + if (nPoints <=4) + return nPoints; + + + if (nPoints >64) + nPoints = 64; + + b3Float4 center = b3MakeFloat4(0,0,0,0); + { + + for (int i=0;im_pos; + b3Quat orientation = body->m_quat; + + int collidableIndex = body->m_collidableIdx; + int shapeIndex = collidables[collidableIndex].m_shapeIndex; + + if (shapeIndex>=0) + { + + b3Aabb_t localAabb = localShapeAABB[collidableIndex]; + b3Aabb_t worldAabb; + + b3Float4 aabbAMinOut,aabbAMaxOut; + float margin = 0.f; + b3TransformAabb2(localAabb.m_minVec,localAabb.m_maxVec,margin,position,orientation,&aabbAMinOut,&aabbAMaxOut); + + worldAabb.m_minVec =aabbAMinOut; + worldAabb.m_minIndices[3] = bodyId; + worldAabb.m_maxVec = aabbAMaxOut; + worldAabb.m_signedMaxIndices[3] = body[bodyId].m_invMass==0.f? 0 : 1; + worldAabbs[bodyId] = worldAabb; + } +} + +#endif //B3_UPDATE_AABBS_H diff --git a/extern/bullet/src/Bullet3Collision/premake4.lua b/extern/bullet/src/Bullet3Collision/premake4.lua new file mode 100644 index 000000000000..0b47f8ea5b83 --- /dev/null +++ b/extern/bullet/src/Bullet3Collision/premake4.lua @@ -0,0 +1,13 @@ + project "Bullet3Collision" + + language "C++" + + kind "StaticLib" + + includedirs {".."} + + + files { + "**.cpp", + "**.h" + } \ No newline at end of file diff --git a/extern/bullet/src/Bullet3Common/CMakeLists.txt b/extern/bullet/src/Bullet3Common/CMakeLists.txt new file mode 100644 index 000000000000..e899e67d944e --- /dev/null +++ b/extern/bullet/src/Bullet3Common/CMakeLists.txt @@ -0,0 +1,63 @@ + +INCLUDE_DIRECTORIES( + ${BULLET_PHYSICS_SOURCE_DIR}/src +) + +SET(Bullet3Common_SRCS + b3AlignedAllocator.cpp + b3Vector3.cpp + b3Logging.cpp +) + +SET(Bullet3Common_HDRS + b3AlignedAllocator.h + b3AlignedObjectArray.h + b3CommandLineArgs.h + b3HashMap.h + b3Logging.h + b3Matrix3x3.h + b3MinMax.h + b3PoolAllocator.h + b3QuadWord.h + b3Quaternion.h + b3Random.h + b3Scalar.h + b3StackAlloc.h + b3Transform.h + b3TransformUtil.h + b3Vector3.h + shared/b3Float4 + shared/b3Int2.h + shared/b3Int4.h + shared/b3Mat3x3.h + shared/b3PlatformDefinitions + shared/b3Quat.h +) + +ADD_LIBRARY(Bullet3Common ${Bullet3Common_SRCS} ${Bullet3Common_HDRS}) +SET_TARGET_PROPERTIES(Bullet3Common PROPERTIES VERSION ${BULLET_VERSION}) +SET_TARGET_PROPERTIES(Bullet3Common PROPERTIES SOVERSION ${BULLET_VERSION}) + +IF (INSTALL_LIBS) + IF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) + #FILES_MATCHING requires CMake 2.6 + IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS Bullet3Common DESTINATION .) + ELSE (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS Bullet3Common + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib${LIB_SUFFIX} + ARCHIVE DESTINATION lib${LIB_SUFFIX}) + INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.h" PATTERN +".svn" EXCLUDE PATTERN "CMakeFiles" EXCLUDE) + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + SET_TARGET_PROPERTIES(Bullet3Common PROPERTIES FRAMEWORK true) + SET_TARGET_PROPERTIES(Bullet3Common PROPERTIES PUBLIC_HEADER "${Bullet3Common_HDRS}") + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) +ENDIF (INSTALL_LIBS) diff --git a/extern/bullet/src/Bullet3Common/b3AlignedAllocator.cpp b/extern/bullet/src/Bullet3Common/b3AlignedAllocator.cpp new file mode 100644 index 000000000000..b98e2b4d33ec --- /dev/null +++ b/extern/bullet/src/Bullet3Common/b3AlignedAllocator.cpp @@ -0,0 +1,181 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org + +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 "b3AlignedAllocator.h" + +int b3g_numAlignedAllocs = 0; +int b3g_numAlignedFree = 0; +int b3g_totalBytesAlignedAllocs = 0;//detect memory leaks + +static void *b3AllocDefault(size_t size) +{ + return malloc(size); +} + +static void b3FreeDefault(void *ptr) +{ + free(ptr); +} + +static b3AllocFunc* b3s_allocFunc = b3AllocDefault; +static b3FreeFunc* b3s_freeFunc = b3FreeDefault; + + + +#if defined (B3_HAS_ALIGNED_ALLOCATOR) +#include +static void *b3AlignedAllocDefault(size_t size, int alignment) +{ + return _aligned_malloc(size, (size_t)alignment); +} + +static void b3AlignedFreeDefault(void *ptr) +{ + _aligned_free(ptr); +} +#elif defined(__CELLOS_LV2__) +#include + +static inline void *b3AlignedAllocDefault(size_t size, int alignment) +{ + return memalign(alignment, size); +} + +static inline void b3AlignedFreeDefault(void *ptr) +{ + free(ptr); +} +#else + + + + + +static inline void *b3AlignedAllocDefault(size_t size, int alignment) +{ + void *ret; + char *real; + real = (char *)b3s_allocFunc(size + sizeof(void *) + (alignment-1)); + if (real) { + ret = b3AlignPointer(real + sizeof(void *),alignment); + *((void **)(ret)-1) = (void *)(real); + } else { + ret = (void *)(real); + } + return (ret); +} + +static inline void b3AlignedFreeDefault(void *ptr) +{ + void* real; + + if (ptr) { + real = *((void **)(ptr)-1); + b3s_freeFunc(real); + } +} +#endif + + +static b3AlignedAllocFunc* b3s_alignedAllocFunc = b3AlignedAllocDefault; +static b3AlignedFreeFunc* b3s_alignedFreeFunc = b3AlignedFreeDefault; + +void b3AlignedAllocSetCustomAligned(b3AlignedAllocFunc *allocFunc, b3AlignedFreeFunc *freeFunc) +{ + b3s_alignedAllocFunc = allocFunc ? allocFunc : b3AlignedAllocDefault; + b3s_alignedFreeFunc = freeFunc ? freeFunc : b3AlignedFreeDefault; +} + +void b3AlignedAllocSetCustom(b3AllocFunc *allocFunc, b3FreeFunc *freeFunc) +{ + b3s_allocFunc = allocFunc ? allocFunc : b3AllocDefault; + b3s_freeFunc = freeFunc ? freeFunc : b3FreeDefault; +} + +#ifdef B3_DEBUG_MEMORY_ALLOCATIONS +//this generic allocator provides the total allocated number of bytes +#include + +void* b3AlignedAllocInternal (size_t size, int alignment,int line,char* filename) +{ + void *ret; + char *real; + + b3g_totalBytesAlignedAllocs += size; + b3g_numAlignedAllocs++; + + + real = (char *)b3s_allocFunc(size + 2*sizeof(void *) + (alignment-1)); + if (real) { + ret = (void*) b3AlignPointer(real + 2*sizeof(void *), alignment); + *((void **)(ret)-1) = (void *)(real); + *((int*)(ret)-2) = size; + + } else { + ret = (void *)(real);//?? + } + + b3Printf("allocation#%d at address %x, from %s,line %d, size %d\n",b3g_numAlignedAllocs,real, filename,line,size); + + int* ptr = (int*)ret; + *ptr = 12; + return (ret); +} + +void b3AlignedFreeInternal (void* ptr,int line,char* filename) +{ + + void* real; + b3g_numAlignedFree++; + + if (ptr) { + real = *((void **)(ptr)-1); + int size = *((int*)(ptr)-2); + b3g_totalBytesAlignedAllocs -= size; + + b3Printf("free #%d at address %x, from %s,line %d, size %d\n",b3g_numAlignedFree,real, filename,line,size); + + b3s_freeFunc(real); + } else + { + b3Printf("NULL ptr\n"); + } +} + +#else //B3_DEBUG_MEMORY_ALLOCATIONS + +void* b3AlignedAllocInternal (size_t size, int alignment) +{ + b3g_numAlignedAllocs++; + void* ptr; + ptr = b3s_alignedAllocFunc(size, alignment); +// b3Printf("b3AlignedAllocInternal %d, %x\n",size,ptr); + return ptr; +} + +void b3AlignedFreeInternal (void* ptr) +{ + if (!ptr) + { + return; + } + + b3g_numAlignedFree++; +// b3Printf("b3AlignedFreeInternal %x\n",ptr); + b3s_alignedFreeFunc(ptr); +} + +#endif //B3_DEBUG_MEMORY_ALLOCATIONS + diff --git a/extern/bullet/src/Bullet3Common/b3AlignedAllocator.h b/extern/bullet/src/Bullet3Common/b3AlignedAllocator.h new file mode 100644 index 000000000000..be418bd55f94 --- /dev/null +++ b/extern/bullet/src/Bullet3Common/b3AlignedAllocator.h @@ -0,0 +1,107 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org + +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 B3_ALIGNED_ALLOCATOR +#define B3_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 "b3Scalar.h" +//#define B3_DEBUG_MEMORY_ALLOCATIONS 1 +#ifdef B3_DEBUG_MEMORY_ALLOCATIONS + +#define b3AlignedAlloc(a,b) \ + b3AlignedAllocInternal(a,b,__LINE__,__FILE__) + +#define b3AlignedFree(ptr) \ + b3AlignedFreeInternal(ptr,__LINE__,__FILE__) + +void* b3AlignedAllocInternal (size_t size, int alignment,int line,char* filename); + +void b3AlignedFreeInternal (void* ptr,int line,char* filename); + +#else + void* b3AlignedAllocInternal (size_t size, int alignment); + void b3AlignedFreeInternal (void* ptr); + + #define b3AlignedAlloc(size,alignment) b3AlignedAllocInternal(size,alignment) + #define b3AlignedFree(ptr) b3AlignedFreeInternal(ptr) + +#endif +typedef int btSizeType; + +typedef void *(b3AlignedAllocFunc)(size_t size, int alignment); +typedef void (b3AlignedFreeFunc)(void *memblock); +typedef void *(b3AllocFunc)(size_t size); +typedef void (b3FreeFunc)(void *memblock); + +///The developer can let all Bullet memory allocations go through a custom memory allocator, using b3AlignedAllocSetCustom +void b3AlignedAllocSetCustom(b3AllocFunc *allocFunc, b3FreeFunc *freeFunc); +///If the developer has already an custom aligned allocator, then b3AlignedAllocSetCustomAligned can be used. The default aligned allocator pre-allocates extra memory using the non-aligned allocator, and instruments it. +void b3AlignedAllocSetCustomAligned(b3AlignedAllocFunc *allocFunc, b3AlignedFreeFunc *freeFunc); + + +///The b3AlignedAllocator is a portable class for aligned memory allocations. +///Default implementations for unaligned and aligned allocations can be overridden by a custom allocator using b3AlignedAllocSetCustom and b3AlignedAllocSetCustomAligned. +template < typename T , unsigned Alignment > +class b3AlignedAllocator { + + typedef b3AlignedAllocator< T , Alignment > self_type; + +public: + + //just going down a list: + b3AlignedAllocator() {} + /* + b3AlignedAllocator( const self_type & ) {} + */ + + template < typename Other > + b3AlignedAllocator( const b3AlignedAllocator< 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 ( btSizeType n , const_pointer * hint = 0 ) { + (void)hint; + return reinterpret_cast< pointer >(b3AlignedAlloc( sizeof(value_type) * n , Alignment )); + } + void construct ( pointer ptr , const value_type & value ) { new (ptr) value_type( value ); } + void deallocate( pointer ptr ) { + b3AlignedFree( reinterpret_cast< void * >( ptr ) ); + } + void destroy ( pointer ptr ) { ptr->~value_type(); } + + + template < typename O > struct rebind { + typedef b3AlignedAllocator< O , Alignment > other; + }; + template < typename O > + self_type & operator=( const b3AlignedAllocator< O , Alignment > & ) { return *this; } + + friend bool operator==( const self_type & , const self_type & ) { return true; } +}; + + + +#endif //B3_ALIGNED_ALLOCATOR + diff --git a/extern/bullet/src/Bullet3Common/b3AlignedObjectArray.h b/extern/bullet/src/Bullet3Common/b3AlignedObjectArray.h new file mode 100644 index 000000000000..947362d08ecc --- /dev/null +++ b/extern/bullet/src/Bullet3Common/b3AlignedObjectArray.h @@ -0,0 +1,533 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org + +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 B3_OBJECT_ARRAY__ +#define B3_OBJECT_ARRAY__ + +#include "b3Scalar.h" // has definitions like B3_FORCE_INLINE +#include "b3AlignedAllocator.h" + +///If the platform doesn't support placement new, you can disable B3_USE_PLACEMENT_NEW +///then the b3AlignedObjectArray doesn't support objects with virtual methods, and non-trivial constructors/destructors +///You can enable B3_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 B3_USE_PLACEMENT_NEW 1 +//#define B3_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... +#define B3_ALLOW_ARRAY_COPY_OPERATOR // enabling this can accidently perform deep copies of data if you are not careful + +#ifdef B3_USE_MEMCPY +#include +#include +#endif //B3_USE_MEMCPY + +#ifdef B3_USE_PLACEMENT_NEW +#include //for placement new +#endif //B3_USE_PLACEMENT_NEW + + +///The b3AlignedObjectArray template class uses a subset of the stl::vector interface for its methods +///It is developed to replace stl::vector to avoid portability issues, including STL alignment issues to add SIMD/SSE data +template +//template +class b3AlignedObjectArray +{ + b3AlignedAllocator m_allocator; + + int m_size; + int m_capacity; + T* m_data; + //PCK: added this line + bool m_ownsMemory; + +#ifdef B3_ALLOW_ARRAY_COPY_OPERATOR +public: + B3_FORCE_INLINE b3AlignedObjectArray& operator=(const b3AlignedObjectArray &other) + { + copyFromArray(other); + return *this; + } +#else//B3_ALLOW_ARRAY_COPY_OPERATOR +private: + B3_FORCE_INLINE b3AlignedObjectArray& operator=(const b3AlignedObjectArray &other); +#endif//B3_ALLOW_ARRAY_COPY_OPERATOR + +protected: + B3_FORCE_INLINE int allocSize(int size) + { + return (size ? size*2 : 1); + } + B3_FORCE_INLINE void copy(int start,int end, T* dest) const + { + int i; + for (i=start;i=0); + b3Assert(n=0); + b3Assert(n=0); + b3Assert(n=0); + b3Assert(n0); + m_size--; + m_data[m_size].~T(); + } + + + ///resize changes the number of elements in the array. If the new size is larger, the new elements will be constructed using the optional second argument. + ///when the new number of elements is smaller, the destructor will be called, but memory will not be freed, to reduce performance overhead of run-time memory (de)allocations. + B3_FORCE_INLINE void resizeNoInitialize(int newsize) + { + int curSize = size(); + + if (newsize < curSize) + { + } else + { + if (newsize > size()) + { + reserve(newsize); + } + //leave this uninitialized + } + m_size = newsize; + } + + B3_FORCE_INLINE void resize(int newsize, const T& fillData=T()) + { + int curSize = size(); + + if (newsize < curSize) + { + for(int i = newsize; i < curSize; i++) + { + m_data[i].~T(); + } + } else + { + if (newsize > size()) + { + reserve(newsize); + } +#ifdef B3_USE_PLACEMENT_NEW + for (int i=curSize;i + void quickSortInternal(const L& CompareFunc,int lo, int hi) + { + // lo is the lower index, hi is the upper index + // of the region of array a that is to be sorted + int i=lo, j=hi; + T x=m_data[(lo+hi)/2]; + + // partition + do + { + while (CompareFunc(m_data[i],x)) + i++; + while (CompareFunc(x,m_data[j])) + j--; + if (i<=j) + { + swap(i,j); + i++; j--; + } + } while (i<=j); + + // recursion + if (lo + void quickSort(const L& CompareFunc) + { + //don't sort 0 or 1 elements + if (size()>1) + { + quickSortInternal(CompareFunc,0,size()-1); + } + } + + + ///heap sort from http://www.csse.monash.edu.au/~lloyd/tildeAlgDS/Sort/Heap/ + template + void downHeap(T *pArr, int k, int n, const 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 B3_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 //B3_USE_PLACEMENT_NEW + + } + + template + void heapSort(const 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()-1; + + //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 +#include +#include +#include +#include +class b3CommandLineArgs +{ +protected: + + std::map pairs; + +public: + + // Constructor + b3CommandLineArgs(int argc, char **argv) + { + addArgs(argc,argv); + } + + void addArgs(int argc, char**argv) + { + for (int i = 1; i < argc; i++) + { + std::string arg = argv[i]; + + if ((arg.length() < 2) || (arg[0] != '-') || (arg[1] != '-')) { + continue; + } + + std::string::size_type pos; + std::string key, val; + if ((pos = arg.find( '=')) == std::string::npos) { + key = std::string(arg, 2, arg.length() - 2); + val = ""; + } else { + key = std::string(arg, 2, pos - 2); + val = std::string(arg, pos + 1, arg.length() - 1); + } + + //only add new keys, don't replace existing + if(pairs.find(key) == pairs.end()) + { + pairs[key] = val; + } + } + } + + bool CheckCmdLineFlag(const char* arg_name) + { + std::map::iterator itr; + if ((itr = pairs.find(arg_name)) != pairs.end()) { + return true; + } + return false; + } + + template + bool GetCmdLineArgument(const char *arg_name, T &val); + + int ParsedArgc() + { + return pairs.size(); + } +}; + +template +inline bool b3CommandLineArgs::GetCmdLineArgument(const char *arg_name, T &val) +{ + std::map::iterator itr; + if ((itr = pairs.find(arg_name)) != pairs.end()) { + std::istringstream strstream(itr->second); + strstream >> val; + return true; + } + return false; +} + +template <> +inline bool b3CommandLineArgs::GetCmdLineArgument(const char* arg_name, char* &val) +{ + std::map::iterator itr; + if ((itr = pairs.find(arg_name)) != pairs.end()) { + + std::string s = itr->second; + val = (char*) malloc(sizeof(char) * (s.length() + 1)); + std::strcpy(val, s.c_str()); + return true; + } else { + val = NULL; + } + return false; +} + + +#endif //COMMAND_LINE_ARGS_H diff --git a/extern/bullet/src/Bullet3Common/b3FileUtils.h b/extern/bullet/src/Bullet3Common/b3FileUtils.h new file mode 100644 index 000000000000..1a331029ea65 --- /dev/null +++ b/extern/bullet/src/Bullet3Common/b3FileUtils.h @@ -0,0 +1,138 @@ +#ifndef B3_FILE_UTILS_H +#define B3_FILE_UTILS_H + +#include +#include "b3Scalar.h" +#include //ptrdiff_h +#include + +struct b3FileUtils +{ + b3FileUtils() + { + } + virtual ~b3FileUtils() + { + } + + static bool findFile(const char* orgFileName, char* relativeFileName, int maxRelativeFileNameMaxLen) + { + FILE* f=0; + f = fopen(orgFileName,"rb"); + if (f) + { + //printf("original file found: [%s]\n", orgFileName); + sprintf(relativeFileName,"%s", orgFileName); + fclose(f); + return true; + } + + //printf("Trying various directories, relative to current working directory\n"); + const char* prefix[]={"./","./data/","../data/","../../data/","../../../data/","../../../../data/"}; + int numPrefixes = sizeof(prefix)/sizeof(const char*); + + f=0; + bool fileFound = false; + + for (int i=0;!f && i0); + if (maxPathLength>0) + { + path[len] = 0; + } + } + return len; + } + + static char toLowerChar(const char t) + { + if (t>=(char)'A' && t<=(char)'Z') + return t + ((char)'a' - (char)'A'); + else + return t; + } + + + static void toLower(char* str) + { + int len=strlen(str); + for (int i=0;i + +///very basic hashable string implementation, compatible with b3HashMap +struct b3HashString +{ + std::string m_string; + unsigned int m_hash; + + B3_FORCE_INLINE unsigned int getHash()const + { + return m_hash; + } + + + b3HashString(const char* name) + :m_string(name) + { + + /* magic numbers from http://www.isthe.com/chongo/tech/comp/fnv/ */ + static const unsigned int InitialFNV = 2166136261u; + static const unsigned int FNVMultiple = 16777619u; + + /* Fowler / Noll / Vo (FNV) Hash */ + unsigned int hash = InitialFNV; + int len = m_string.length(); + for(int i = 0; i 0 ) + ret = 1 ; + + return( ret ); + } + + bool equals(const b3HashString& other) const + { + return (m_string == other.m_string); + } + +}; + + +const int B3_HASH_NULL=0xffffffff; + + +class b3HashInt +{ + int m_uid; +public: + b3HashInt(int uid) :m_uid(uid) + { + } + + int getUid1() const + { + return m_uid; + } + + void setUid1(int uid) + { + m_uid = uid; + } + + bool equals(const b3HashInt& other) const + { + return getUid1() == other.getUid1(); + } + //to our success + B3_FORCE_INLINE unsigned int getHash()const + { + int key = m_uid; + // Thomas Wang's hash + key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); + return key; + } +}; + + + +class b3HashPtr +{ + + union + { + const void* m_pointer; + int m_hashValues[2]; + }; + +public: + + b3HashPtr(const void* ptr) + :m_pointer(ptr) + { + } + + const void* getPointer() const + { + return m_pointer; + } + + bool equals(const b3HashPtr& other) const + { + return getPointer() == other.getPointer(); + } + + //to our success + B3_FORCE_INLINE unsigned int getHash()const + { + const bool VOID_IS_8 = ((sizeof(void*)==8)); + + int key = VOID_IS_8? m_hashValues[0]+m_hashValues[1] : m_hashValues[0]; + + // Thomas Wang's hash + key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); + return key; + } + + +}; + + +template +class b3HashKeyPtr +{ + int m_uid; +public: + + b3HashKeyPtr(int uid) :m_uid(uid) + { + } + + int getUid1() const + { + return m_uid; + } + + bool equals(const b3HashKeyPtr& other) const + { + return getUid1() == other.getUid1(); + } + + //to our success + B3_FORCE_INLINE unsigned int getHash()const + { + int key = m_uid; + // Thomas Wang's hash + key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); + return key; + } + + +}; + + +template +class b3HashKey +{ + int m_uid; +public: + + b3HashKey(int uid) :m_uid(uid) + { + } + + int getUid1() const + { + return m_uid; + } + + bool equals(const b3HashKey& other) const + { + return getUid1() == other.getUid1(); + } + //to our success + B3_FORCE_INLINE unsigned int getHash()const + { + int key = m_uid; + // Thomas Wang's hash + key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); + return key; + } +}; + + +///The b3HashMap template class implements a generic and lightweight hashmap. +///A basic sample of how to use b3HashMap is located in Demos\BasicDemo\main.cpp +template +class b3HashMap +{ + +protected: + b3AlignedObjectArray m_hashTable; + b3AlignedObjectArray m_next; + + b3AlignedObjectArray m_valueArray; + b3AlignedObjectArray m_keyArray; + + void growTables(const Key& /*key*/) + { + int newCapacity = m_valueArray.capacity(); + + if (m_hashTable.size() < newCapacity) + { + //grow hashtable and next table + int curHashtableSize = m_hashTable.size(); + + m_hashTable.resize(newCapacity); + m_next.resize(newCapacity); + + int i; + + for (i= 0; i < newCapacity; ++i) + { + m_hashTable[i] = B3_HASH_NULL; + } + for (i = 0; i < newCapacity; ++i) + { + m_next[i] = B3_HASH_NULL; + } + + for(i=0;i= (unsigned int)m_hashTable.size()) + { + return B3_HASH_NULL; + } + + int index = m_hashTable[hash]; + while ((index != B3_HASH_NULL) && key.equals(m_keyArray[index]) == false) + { + index = m_next[index]; + } + return index; + } + + void clear() + { + m_hashTable.clear(); + m_next.clear(); + m_valueArray.clear(); + m_keyArray.clear(); + } + +}; + +#endif //B3_HASH_MAP_H diff --git a/extern/bullet/src/Bullet3Common/b3Logging.cpp b/extern/bullet/src/Bullet3Common/b3Logging.cpp new file mode 100644 index 000000000000..a8e950715551 --- /dev/null +++ b/extern/bullet/src/Bullet3Common/b3Logging.cpp @@ -0,0 +1,160 @@ +/* +Copyright (c) 2013 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Erwin Coumans + +#include "b3Logging.h" + +#include +#include + +#ifdef _WIN32 +#include +#endif //_WIN32 + + +void b3PrintfFuncDefault(const char* msg) +{ +#ifdef _WIN32 + OutputDebugStringA(msg); +#endif + printf("%s",msg); + //is this portable? + fflush(stdout); +} + +void b3WarningMessageFuncDefault(const char* msg) +{ +#ifdef _WIN32 + OutputDebugStringA(msg); +#endif + printf("%s",msg); + //is this portable? + fflush(stdout); + +} + + +void b3ErrorMessageFuncDefault(const char* msg) +{ +#ifdef _WIN32 + OutputDebugStringA(msg); +#endif + printf("%s",msg); + + //is this portable? + fflush(stdout); + +} + + + +static b3PrintfFunc* b3s_printfFunc = b3PrintfFuncDefault; +static b3WarningMessageFunc* b3s_warningMessageFunc = b3WarningMessageFuncDefault; +static b3ErrorMessageFunc* b3s_errorMessageFunc = b3ErrorMessageFuncDefault; + + +///The developer can route b3Printf output using their own implementation +void b3SetCustomPrintfFunc(b3PrintfFunc* printfFunc) +{ + b3s_printfFunc = printfFunc; +} +void b3SetCustomWarningMessageFunc(b3PrintfFunc* warningMessageFunc) +{ + b3s_warningMessageFunc = warningMessageFunc; +} +void b3SetCustomErrorMessageFunc(b3PrintfFunc* errorMessageFunc) +{ + b3s_errorMessageFunc = errorMessageFunc; +} + +//#define B3_MAX_DEBUG_STRING_LENGTH 2048 +#define B3_MAX_DEBUG_STRING_LENGTH 32768 + + +void b3OutputPrintfVarArgsInternal(const char *str, ...) +{ + char strDebug[B3_MAX_DEBUG_STRING_LENGTH]={0}; + va_list argList; + va_start(argList, str); +#ifdef _MSC_VER + vsprintf_s(strDebug,B3_MAX_DEBUG_STRING_LENGTH,str,argList); +#else + vsnprintf(strDebug,B3_MAX_DEBUG_STRING_LENGTH,str,argList); +#endif + (b3s_printfFunc)(strDebug); + va_end(argList); +} +void b3OutputWarningMessageVarArgsInternal(const char *str, ...) +{ + char strDebug[B3_MAX_DEBUG_STRING_LENGTH]={0}; + va_list argList; + va_start(argList, str); +#ifdef _MSC_VER + vsprintf_s(strDebug,B3_MAX_DEBUG_STRING_LENGTH,str,argList); +#else + vsnprintf(strDebug,B3_MAX_DEBUG_STRING_LENGTH,str,argList); +#endif + (b3s_warningMessageFunc)(strDebug); + va_end(argList); +} +void b3OutputErrorMessageVarArgsInternal(const char *str, ...) +{ + + char strDebug[B3_MAX_DEBUG_STRING_LENGTH]={0}; + va_list argList; + va_start(argList, str); +#ifdef _MSC_VER + vsprintf_s(strDebug,B3_MAX_DEBUG_STRING_LENGTH,str,argList); +#else + vsnprintf(strDebug,B3_MAX_DEBUG_STRING_LENGTH,str,argList); +#endif + (b3s_errorMessageFunc)(strDebug); + va_end(argList); + +} + + +void b3EnterProfileZoneDefault(const char* name) +{ +} +void b3LeaveProfileZoneDefault() +{ +} +static b3EnterProfileZoneFunc* b3s_enterFunc = b3EnterProfileZoneDefault; +static b3LeaveProfileZoneFunc* b3s_leaveFunc = b3LeaveProfileZoneDefault; +void b3EnterProfileZone(const char* name) +{ + (b3s_enterFunc)(name); +} +void b3LeaveProfileZone() +{ + (b3s_leaveFunc)(); +} + +void b3SetCustomEnterProfileZoneFunc(b3EnterProfileZoneFunc* enterFunc) +{ + b3s_enterFunc = enterFunc; +} +void b3SetCustomLeaveProfileZoneFunc(b3LeaveProfileZoneFunc* leaveFunc) +{ + b3s_leaveFunc = leaveFunc; +} + + + + +#ifndef _MSC_VER +#undef vsprintf_s +#endif + diff --git a/extern/bullet/src/Bullet3Common/b3Logging.h b/extern/bullet/src/Bullet3Common/b3Logging.h new file mode 100644 index 000000000000..b302effe4354 --- /dev/null +++ b/extern/bullet/src/Bullet3Common/b3Logging.h @@ -0,0 +1,77 @@ + +#ifndef B3_LOGGING_H +#define B3_LOGGING_H + +#ifdef __cplusplus +extern "C" { +#endif + +///We add the do/while so that the statement "if (condition) b3Printf("test"); else {...}" would fail +///You can also customize the message by uncommenting out a different line below +#define b3Printf(...) b3OutputPrintfVarArgsInternal(__VA_ARGS__) +//#define b3Printf(...) do {b3OutputPrintfVarArgsInternal("b3Printf[%s,%d]:",__FILE__,__LINE__);b3OutputPrintfVarArgsInternal(__VA_ARGS__); } while(0) +//#define b3Printf b3OutputPrintfVarArgsInternal +//#define b3Printf(...) printf(__VA_ARGS__) +//#define b3Printf(...) + +#define b3Warning(...) do {b3OutputWarningMessageVarArgsInternal("b3Warning[%s,%d]:\n",__FILE__,__LINE__);b3OutputWarningMessageVarArgsInternal(__VA_ARGS__); }while(0) +#define b3Error(...) do {b3OutputErrorMessageVarArgsInternal("b3Error[%s,%d]:\n",__FILE__,__LINE__);b3OutputErrorMessageVarArgsInternal(__VA_ARGS__); } while(0) + + +#ifndef B3_NO_PROFILE + +void b3EnterProfileZone(const char* name); +void b3LeaveProfileZone(); +#ifdef __cplusplus + +class b3ProfileZone +{ +public: + b3ProfileZone(const char* name) + { + b3EnterProfileZone( name ); + } + + ~b3ProfileZone() + { + b3LeaveProfileZone(); + } +}; + +#define B3_PROFILE( name ) b3ProfileZone __profile( name ) +#endif + +#else //B3_NO_PROFILE + +#define B3_PROFILE( name ) +#define b3StartProfile(a) +#define b3StopProfile + +#endif //#ifndef B3_NO_PROFILE + + +typedef void (b3PrintfFunc)(const char* msg); +typedef void (b3WarningMessageFunc)(const char* msg); +typedef void (b3ErrorMessageFunc)(const char* msg); +typedef void (b3EnterProfileZoneFunc)(const char* msg); +typedef void (b3LeaveProfileZoneFunc)(); + +///The developer can route b3Printf output using their own implementation +void b3SetCustomPrintfFunc(b3PrintfFunc* printfFunc); +void b3SetCustomWarningMessageFunc(b3WarningMessageFunc* warningMsgFunc); +void b3SetCustomErrorMessageFunc(b3ErrorMessageFunc* errorMsgFunc); + +///Set custom profile zone functions (zones can be nested) +void b3SetCustomEnterProfileZoneFunc(b3EnterProfileZoneFunc* enterFunc); +void b3SetCustomLeaveProfileZoneFunc(b3LeaveProfileZoneFunc* leaveFunc); + +///Don't use those internal functions directly, use the b3Printf or b3SetCustomPrintfFunc instead (or warning/error version) +void b3OutputPrintfVarArgsInternal(const char *str, ...); +void b3OutputWarningMessageVarArgsInternal(const char *str, ...); +void b3OutputErrorMessageVarArgsInternal(const char *str, ...); + +#ifdef __cplusplus + } +#endif + +#endif//B3_LOGGING_H \ No newline at end of file diff --git a/extern/bullet/src/Bullet3Common/b3Matrix3x3.h b/extern/bullet/src/Bullet3Common/b3Matrix3x3.h new file mode 100644 index 000000000000..89b57cf59a94 --- /dev/null +++ b/extern/bullet/src/Bullet3Common/b3Matrix3x3.h @@ -0,0 +1,1362 @@ +/* +Copyright (c) 2003-2013 Gino van den Bergen / Erwin Coumans http://bulletphysics.org + +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 B3_MATRIX3x3_H +#define B3_MATRIX3x3_H + +#include "b3Vector3.h" +#include "b3Quaternion.h" +#include + +#ifdef B3_USE_SSE +//const __m128 B3_ATTRIBUTE_ALIGNED16(b3v2220) = {2.0f, 2.0f, 2.0f, 0.0f}; +const __m128 B3_ATTRIBUTE_ALIGNED16(b3vMPPP) = {-0.0f, +0.0f, +0.0f, +0.0f}; +#endif + +#if defined(B3_USE_SSE) || defined(B3_USE_NEON) +const b3SimdFloat4 B3_ATTRIBUTE_ALIGNED16(b3v1000) = {1.0f, 0.0f, 0.0f, 0.0f}; +const b3SimdFloat4 B3_ATTRIBUTE_ALIGNED16(b3v0100) = {0.0f, 1.0f, 0.0f, 0.0f}; +const b3SimdFloat4 B3_ATTRIBUTE_ALIGNED16(b3v0010) = {0.0f, 0.0f, 1.0f, 0.0f}; +#endif + +#ifdef B3_USE_DOUBLE_PRECISION +#define b3Matrix3x3Data b3Matrix3x3DoubleData +#else +#define b3Matrix3x3Data b3Matrix3x3FloatData +#endif //B3_USE_DOUBLE_PRECISION + + +/**@brief The b3Matrix3x3 class implements a 3x3 rotation matrix, to perform linear algebra in combination with b3Quaternion, b3Transform and b3Vector3. +* Make sure to only include a pure orthogonal matrix without scaling. */ +B3_ATTRIBUTE_ALIGNED16(class) b3Matrix3x3 { + + ///Data storage for the matrix, each vector is a row of the matrix + b3Vector3 m_el[3]; + +public: + /** @brief No initializaion constructor */ + b3Matrix3x3 () {} + + // explicit b3Matrix3x3(const b3Scalar *m) { setFromOpenGLSubMatrix(m); } + + /**@brief Constructor from Quaternion */ + explicit b3Matrix3x3(const b3Quaternion& q) { setRotation(q); } + /* + template + Matrix3x3(const b3Scalar& yaw, const b3Scalar& pitch, const b3Scalar& roll) + { + setEulerYPR(yaw, pitch, roll); + } + */ + /** @brief Constructor with row major formatting */ + b3Matrix3x3(const b3Scalar& xx, const b3Scalar& xy, const b3Scalar& xz, + const b3Scalar& yx, const b3Scalar& yy, const b3Scalar& yz, + const b3Scalar& zx, const b3Scalar& zy, const b3Scalar& zz) + { + setValue(xx, xy, xz, + yx, yy, yz, + zx, zy, zz); + } + +#if (defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE))|| defined (B3_USE_NEON) + B3_FORCE_INLINE b3Matrix3x3 (const b3SimdFloat4 v0, const b3SimdFloat4 v1, const b3SimdFloat4 v2 ) + { + m_el[0].mVec128 = v0; + m_el[1].mVec128 = v1; + m_el[2].mVec128 = v2; + } + + B3_FORCE_INLINE b3Matrix3x3 (const b3Vector3& v0, const b3Vector3& v1, const b3Vector3& v2 ) + { + m_el[0] = v0; + m_el[1] = v1; + m_el[2] = v2; + } + + // Copy constructor + B3_FORCE_INLINE b3Matrix3x3(const b3Matrix3x3& rhs) + { + m_el[0].mVec128 = rhs.m_el[0].mVec128; + m_el[1].mVec128 = rhs.m_el[1].mVec128; + m_el[2].mVec128 = rhs.m_el[2].mVec128; + } + + // Assignment Operator + B3_FORCE_INLINE b3Matrix3x3& operator=(const b3Matrix3x3& m) + { + m_el[0].mVec128 = m.m_el[0].mVec128; + m_el[1].mVec128 = m.m_el[1].mVec128; + m_el[2].mVec128 = m.m_el[2].mVec128; + + return *this; + } + +#else + + /** @brief Copy constructor */ + B3_FORCE_INLINE b3Matrix3x3 (const b3Matrix3x3& other) + { + m_el[0] = other.m_el[0]; + m_el[1] = other.m_el[1]; + m_el[2] = other.m_el[2]; + } + + /** @brief Assignment Operator */ + B3_FORCE_INLINE b3Matrix3x3& operator=(const b3Matrix3x3& other) + { + m_el[0] = other.m_el[0]; + m_el[1] = other.m_el[1]; + m_el[2] = other.m_el[2]; + return *this; + } + +#endif + + /** @brief Get a column of the matrix as a vector + * @param i Column number 0 indexed */ + B3_FORCE_INLINE b3Vector3 getColumn(int i) const + { + return b3MakeVector3(m_el[0][i],m_el[1][i],m_el[2][i]); + } + + + /** @brief Get a row of the matrix as a vector + * @param i Row number 0 indexed */ + B3_FORCE_INLINE const b3Vector3& getRow(int i) const + { + b3FullAssert(0 <= i && i < 3); + return m_el[i]; + } + + /** @brief Get a mutable reference to a row of the matrix as a vector + * @param i Row number 0 indexed */ + B3_FORCE_INLINE b3Vector3& operator[](int i) + { + b3FullAssert(0 <= i && i < 3); + return m_el[i]; + } + + /** @brief Get a const reference to a row of the matrix as a vector + * @param i Row number 0 indexed */ + B3_FORCE_INLINE const b3Vector3& operator[](int i) const + { + b3FullAssert(0 <= i && i < 3); + return m_el[i]; + } + + /** @brief Multiply by the target matrix on the right + * @param m Rotation matrix to be applied + * Equivilant to this = this * m */ + b3Matrix3x3& operator*=(const b3Matrix3x3& m); + + /** @brief Adds by the target matrix on the right + * @param m matrix to be applied + * Equivilant to this = this + m */ + b3Matrix3x3& operator+=(const b3Matrix3x3& m); + + /** @brief Substractss by the target matrix on the right + * @param m matrix to be applied + * Equivilant to this = this - m */ + b3Matrix3x3& operator-=(const b3Matrix3x3& m); + + /** @brief Set from the rotational part of a 4x4 OpenGL matrix + * @param m A pointer to the beginning of the array of scalars*/ + void setFromOpenGLSubMatrix(const b3Scalar *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]); + + } + /** @brief Set the values of the matrix explicitly (row major) + * @param xx Top left + * @param xy Top Middle + * @param xz Top Right + * @param yx Middle Left + * @param yy Middle Middle + * @param yz Middle Right + * @param zx Bottom Left + * @param zy Bottom Middle + * @param zz Bottom Right*/ + void setValue(const b3Scalar& xx, const b3Scalar& xy, const b3Scalar& xz, + const b3Scalar& yx, const b3Scalar& yy, const b3Scalar& yz, + const b3Scalar& zx, const b3Scalar& zy, const b3Scalar& zz) + { + m_el[0].setValue(xx,xy,xz); + m_el[1].setValue(yx,yy,yz); + m_el[2].setValue(zx,zy,zz); + } + + /** @brief Set the matrix from a quaternion + * @param q The Quaternion to match */ + void setRotation(const b3Quaternion& q) + { + b3Scalar d = q.length2(); + b3FullAssert(d != b3Scalar(0.0)); + b3Scalar s = b3Scalar(2.0) / d; + + #if defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + __m128 vs, Q = q.get128(); + __m128i Qi = b3CastfTo128i(Q); + __m128 Y, Z; + __m128 V1, V2, V3; + __m128 V11, V21, V31; + __m128 NQ = _mm_xor_ps(Q, b3vMzeroMask); + __m128i NQi = b3CastfTo128i(NQ); + + V1 = b3CastiTo128f(_mm_shuffle_epi32 (Qi, B3_SHUFFLE(1,0,2,3))); // Y X Z W + V2 = _mm_shuffle_ps(NQ, Q, B3_SHUFFLE(0,0,1,3)); // -X -X Y W + V3 = b3CastiTo128f(_mm_shuffle_epi32 (Qi, B3_SHUFFLE(2,1,0,3))); // Z Y X W + V1 = _mm_xor_ps(V1, b3vMPPP); // change the sign of the first element + + V11 = b3CastiTo128f(_mm_shuffle_epi32 (Qi, B3_SHUFFLE(1,1,0,3))); // Y Y X W + V21 = _mm_unpackhi_ps(Q, Q); // Z Z W W + V31 = _mm_shuffle_ps(Q, NQ, B3_SHUFFLE(0,2,0,3)); // X Z -X -W + + V2 = V2 * V1; // + V1 = V1 * V11; // + V3 = V3 * V31; // + + V11 = _mm_shuffle_ps(NQ, Q, B3_SHUFFLE(2,3,1,3)); // -Z -W Y W + V11 = V11 * V21; // + V21 = _mm_xor_ps(V21, b3vMPPP); // change the sign of the first element + V31 = _mm_shuffle_ps(Q, NQ, B3_SHUFFLE(3,3,1,3)); // W W -Y -W + V31 = _mm_xor_ps(V31, b3vMPPP); // change the sign of the first element + Y = b3CastiTo128f(_mm_shuffle_epi32 (NQi, B3_SHUFFLE(3,2,0,3))); // -W -Z -X -W + Z = b3CastiTo128f(_mm_shuffle_epi32 (Qi, B3_SHUFFLE(1,0,1,3))); // Y X Y W + + vs = _mm_load_ss(&s); + V21 = V21 * Y; + V31 = V31 * Z; + + V1 = V1 + V11; + V2 = V2 + V21; + V3 = V3 + V31; + + vs = b3_splat3_ps(vs, 0); + // s ready + V1 = V1 * vs; + V2 = V2 * vs; + V3 = V3 * vs; + + V1 = V1 + b3v1000; + V2 = V2 + b3v0100; + V3 = V3 + b3v0010; + + m_el[0] = b3MakeVector3(V1); + m_el[1] = b3MakeVector3(V2); + m_el[2] = b3MakeVector3(V3); + #else + b3Scalar xs = q.getX() * s, ys = q.getY() * s, zs = q.getZ() * s; + b3Scalar wx = q.getW() * xs, wy = q.getW() * ys, wz = q.getW() * zs; + b3Scalar xx = q.getX() * xs, xy = q.getX() * ys, xz = q.getX() * zs; + b3Scalar yy = q.getY() * ys, yz = q.getY() * zs, zz = q.getZ() * zs; + setValue( + b3Scalar(1.0) - (yy + zz), xy - wz, xz + wy, + xy + wz, b3Scalar(1.0) - (xx + zz), yz - wx, + xz - wy, yz + wx, b3Scalar(1.0) - (xx + yy)); + #endif + } + + + /** @brief Set the matrix from euler angles using YPR around YXZ respectively + * @param yaw Yaw about Y axis + * @param pitch Pitch about X axis + * @param roll Roll about Z axis + */ + void setEulerYPR(const b3Scalar& yaw, const b3Scalar& pitch, const b3Scalar& roll) + { + setEulerZYX(roll, pitch, yaw); + } + + /** @brief Set the matrix from euler angles YPR around ZYX axes + * @param eulerX Roll about X axis + * @param eulerY Pitch around Y axis + * @param eulerZ Yaw aboud Z axis + * + * 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(b3Scalar eulerX,b3Scalar eulerY,b3Scalar eulerZ) { + ///@todo proposed to reverse this since it's labeled zyx but takes arguments xyz and it will match all other parts of the code + b3Scalar ci ( b3Cos(eulerX)); + b3Scalar cj ( b3Cos(eulerY)); + b3Scalar ch ( b3Cos(eulerZ)); + b3Scalar si ( b3Sin(eulerX)); + b3Scalar sj ( b3Sin(eulerY)); + b3Scalar sh ( b3Sin(eulerZ)); + b3Scalar cc = ci * ch; + b3Scalar cs = ci * sh; + b3Scalar sc = si * ch; + b3Scalar 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); + } + + /**@brief Set the matrix to the identity */ + void setIdentity() + { +#if (defined(B3_USE_SSE_IN_API)&& defined (B3_USE_SSE)) || defined(B3_USE_NEON) + m_el[0] = b3MakeVector3(b3v1000); + m_el[1] = b3MakeVector3(b3v0100); + m_el[2] = b3MakeVector3(b3v0010); +#else + setValue(b3Scalar(1.0), b3Scalar(0.0), b3Scalar(0.0), + b3Scalar(0.0), b3Scalar(1.0), b3Scalar(0.0), + b3Scalar(0.0), b3Scalar(0.0), b3Scalar(1.0)); +#endif + } + + static const b3Matrix3x3& getIdentity() + { +#if (defined(B3_USE_SSE_IN_API)&& defined (B3_USE_SSE)) || defined(B3_USE_NEON) + static const b3Matrix3x3 + identityMatrix(b3v1000, b3v0100, b3v0010); +#else + static const b3Matrix3x3 + identityMatrix( + b3Scalar(1.0), b3Scalar(0.0), b3Scalar(0.0), + b3Scalar(0.0), b3Scalar(1.0), b3Scalar(0.0), + b3Scalar(0.0), b3Scalar(0.0), b3Scalar(1.0)); +#endif + return identityMatrix; + } + + /**@brief Fill the rotational part of an OpenGL matrix and clear the shear/perspective + * @param m The array to be filled */ + void getOpenGLSubMatrix(b3Scalar *m) const + { +#if defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + __m128 v0 = m_el[0].mVec128; + __m128 v1 = m_el[1].mVec128; + __m128 v2 = m_el[2].mVec128; // x2 y2 z2 w2 + __m128 *vm = (__m128 *)m; + __m128 vT; + + v2 = _mm_and_ps(v2, b3vFFF0fMask); // x2 y2 z2 0 + + vT = _mm_unpackhi_ps(v0, v1); // z0 z1 * * + v0 = _mm_unpacklo_ps(v0, v1); // x0 x1 y0 y1 + + v1 = _mm_shuffle_ps(v0, v2, B3_SHUFFLE(2, 3, 1, 3) ); // y0 y1 y2 0 + v0 = _mm_shuffle_ps(v0, v2, B3_SHUFFLE(0, 1, 0, 3) ); // x0 x1 x2 0 + v2 = b3CastdTo128f(_mm_move_sd(b3CastfTo128d(v2), b3CastfTo128d(vT))); // z0 z1 z2 0 + + vm[0] = v0; + vm[1] = v1; + vm[2] = v2; +#elif defined(B3_USE_NEON) + // note: zeros the w channel. We can preserve it at the cost of two more vtrn instructions. + static const uint32x2_t zMask = (const uint32x2_t) {-1, 0 }; + float32x4_t *vm = (float32x4_t *)m; + float32x4x2_t top = vtrnq_f32( m_el[0].mVec128, m_el[1].mVec128 ); // {x0 x1 z0 z1}, {y0 y1 w0 w1} + float32x2x2_t bl = vtrn_f32( vget_low_f32(m_el[2].mVec128), vdup_n_f32(0.0f) ); // {x2 0 }, {y2 0} + float32x4_t v0 = vcombine_f32( vget_low_f32(top.val[0]), bl.val[0] ); + float32x4_t v1 = vcombine_f32( vget_low_f32(top.val[1]), bl.val[1] ); + float32x2_t q = (float32x2_t) vand_u32( (uint32x2_t) vget_high_f32( m_el[2].mVec128), zMask ); + float32x4_t v2 = vcombine_f32( vget_high_f32(top.val[0]), q ); // z0 z1 z2 0 + + vm[0] = v0; + vm[1] = v1; + vm[2] = v2; +#else + m[0] = b3Scalar(m_el[0].getX()); + m[1] = b3Scalar(m_el[1].getX()); + m[2] = b3Scalar(m_el[2].getX()); + m[3] = b3Scalar(0.0); + m[4] = b3Scalar(m_el[0].getY()); + m[5] = b3Scalar(m_el[1].getY()); + m[6] = b3Scalar(m_el[2].getY()); + m[7] = b3Scalar(0.0); + m[8] = b3Scalar(m_el[0].getZ()); + m[9] = b3Scalar(m_el[1].getZ()); + m[10] = b3Scalar(m_el[2].getZ()); + m[11] = b3Scalar(0.0); +#endif + } + + /**@brief Get the matrix represented as a quaternion + * @param q The quaternion which will be set */ + void getRotation(b3Quaternion& q) const + { +#if (defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE))|| defined (B3_USE_NEON) + b3Scalar trace = m_el[0].getX() + m_el[1].getY() + m_el[2].getZ(); + b3Scalar s, x; + + union { + b3SimdFloat4 vec; + b3Scalar f[4]; + } temp; + + if (trace > b3Scalar(0.0)) + { + x = trace + b3Scalar(1.0); + + temp.f[0]=m_el[2].getY() - m_el[1].getZ(); + temp.f[1]=m_el[0].getZ() - m_el[2].getX(); + temp.f[2]=m_el[1].getX() - m_el[0].getY(); + temp.f[3]=x; + //temp.f[3]= s * b3Scalar(0.5); + } + else + { + int i, j, k; + if(m_el[0].getX() < m_el[1].getY()) + { + if( m_el[1].getY() < m_el[2].getZ() ) + { i = 2; j = 0; k = 1; } + else + { i = 1; j = 2; k = 0; } + } + else + { + if( m_el[0].getX() < m_el[2].getZ()) + { i = 2; j = 0; k = 1; } + else + { i = 0; j = 1; k = 2; } + } + + x = m_el[i][i] - m_el[j][j] - m_el[k][k] + b3Scalar(1.0); + + temp.f[3] = (m_el[k][j] - m_el[j][k]); + temp.f[j] = (m_el[j][i] + m_el[i][j]); + temp.f[k] = (m_el[k][i] + m_el[i][k]); + temp.f[i] = x; + //temp.f[i] = s * b3Scalar(0.5); + } + + s = b3Sqrt(x); + q.set128(temp.vec); + s = b3Scalar(0.5) / s; + + q *= s; +#else + b3Scalar trace = m_el[0].getX() + m_el[1].getY() + m_el[2].getZ(); + + b3Scalar temp[4]; + + if (trace > b3Scalar(0.0)) + { + b3Scalar s = b3Sqrt(trace + b3Scalar(1.0)); + temp[3]=(s * b3Scalar(0.5)); + s = b3Scalar(0.5) / s; + + temp[0]=((m_el[2].getY() - m_el[1].getZ()) * s); + temp[1]=((m_el[0].getZ() - m_el[2].getX()) * s); + temp[2]=((m_el[1].getX() - m_el[0].getY()) * s); + } + else + { + int i = m_el[0].getX() < m_el[1].getY() ? + (m_el[1].getY() < m_el[2].getZ() ? 2 : 1) : + (m_el[0].getX() < m_el[2].getZ() ? 2 : 0); + int j = (i + 1) % 3; + int k = (i + 2) % 3; + + b3Scalar s = b3Sqrt(m_el[i][i] - m_el[j][j] - m_el[k][k] + b3Scalar(1.0)); + temp[i] = s * b3Scalar(0.5); + s = b3Scalar(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]); +#endif + } + + /**@brief Get the matrix represented as euler angles around YXZ, roundtrip with setEulerYPR + * @param yaw Yaw around Y axis + * @param pitch Pitch around X axis + * @param roll around Z axis */ + void getEulerYPR(b3Scalar& yaw, b3Scalar& pitch, b3Scalar& roll) const + { + + // first use the normal calculus + yaw = b3Scalar(b3Atan2(m_el[1].getX(), m_el[0].getX())); + pitch = b3Scalar(b3Asin(-m_el[2].getX())); + roll = b3Scalar(b3Atan2(m_el[2].getY(), m_el[2].getZ())); + + // on pitch = +/-HalfPI + if (b3Fabs(pitch)==B3_HALF_PI) + { + if (yaw>0) + yaw-=B3_PI; + else + yaw+=B3_PI; + + if (roll>0) + roll-=B3_PI; + else + roll+=B3_PI; + } + }; + + + /**@brief Get the matrix represented as euler angles around ZYX + * @param yaw Yaw around X axis + * @param pitch Pitch around Y axis + * @param roll around X axis + * @param solution_number Which solution of two possible solutions ( 1 or 2) are possible values*/ + void getEulerZYX(b3Scalar& yaw, b3Scalar& pitch, b3Scalar& roll, unsigned int solution_number = 1) const + { + struct Euler + { + b3Scalar yaw; + b3Scalar pitch; + b3Scalar roll; + }; + + Euler euler_out; + Euler euler_out2; //second solution + //get the pointer to the raw data + + // Check that pitch is not at a singularity + if (b3Fabs(m_el[2].getX()) >= 1) + { + euler_out.yaw = 0; + euler_out2.yaw = 0; + + // From difference of angles formula + b3Scalar delta = b3Atan2(m_el[0].getX(),m_el[0].getZ()); + if (m_el[2].getX() > 0) //gimbal locked up + { + euler_out.pitch = B3_PI / b3Scalar(2.0); + euler_out2.pitch = B3_PI / b3Scalar(2.0); + euler_out.roll = euler_out.pitch + delta; + euler_out2.roll = euler_out.pitch + delta; + } + else // gimbal locked down + { + euler_out.pitch = -B3_PI / b3Scalar(2.0); + euler_out2.pitch = -B3_PI / b3Scalar(2.0); + euler_out.roll = -euler_out.pitch + delta; + euler_out2.roll = -euler_out.pitch + delta; + } + } + else + { + euler_out.pitch = - b3Asin(m_el[2].getX()); + euler_out2.pitch = B3_PI - euler_out.pitch; + + euler_out.roll = b3Atan2(m_el[2].getY()/b3Cos(euler_out.pitch), + m_el[2].getZ()/b3Cos(euler_out.pitch)); + euler_out2.roll = b3Atan2(m_el[2].getY()/b3Cos(euler_out2.pitch), + m_el[2].getZ()/b3Cos(euler_out2.pitch)); + + euler_out.yaw = b3Atan2(m_el[1].getX()/b3Cos(euler_out.pitch), + m_el[0].getX()/b3Cos(euler_out.pitch)); + euler_out2.yaw = b3Atan2(m_el[1].getX()/b3Cos(euler_out2.pitch), + m_el[0].getX()/b3Cos(euler_out2.pitch)); + } + + if (solution_number == 1) + { + yaw = euler_out.yaw; + pitch = euler_out.pitch; + roll = euler_out.roll; + } + else + { + yaw = euler_out2.yaw; + pitch = euler_out2.pitch; + roll = euler_out2.roll; + } + } + + /**@brief Create a scaled copy of the matrix + * @param s Scaling vector The elements of the vector will scale each column */ + + b3Matrix3x3 scaled(const b3Vector3& s) const + { +#if (defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE))|| defined (B3_USE_NEON) + return b3Matrix3x3(m_el[0] * s, m_el[1] * s, m_el[2] * s); +#else + return b3Matrix3x3( + m_el[0].getX() * s.getX(), m_el[0].getY() * s.getY(), m_el[0].getZ() * s.getZ(), + m_el[1].getX() * s.getX(), m_el[1].getY() * s.getY(), m_el[1].getZ() * s.getZ(), + m_el[2].getX() * s.getX(), m_el[2].getY() * s.getY(), m_el[2].getZ() * s.getZ()); +#endif + } + + /**@brief Return the determinant of the matrix */ + b3Scalar determinant() const; + /**@brief Return the adjoint of the matrix */ + b3Matrix3x3 adjoint() const; + /**@brief Return the matrix with all values non negative */ + b3Matrix3x3 absolute() const; + /**@brief Return the transpose of the matrix */ + b3Matrix3x3 transpose() const; + /**@brief Return the inverse of the matrix */ + b3Matrix3x3 inverse() const; + + b3Matrix3x3 transposeTimes(const b3Matrix3x3& m) const; + b3Matrix3x3 timesTranspose(const b3Matrix3x3& m) const; + + B3_FORCE_INLINE b3Scalar tdotx(const b3Vector3& v) const + { + return m_el[0].getX() * v.getX() + m_el[1].getX() * v.getY() + m_el[2].getX() * v.getZ(); + } + B3_FORCE_INLINE b3Scalar tdoty(const b3Vector3& v) const + { + return m_el[0].getY() * v.getX() + m_el[1].getY() * v.getY() + m_el[2].getY() * v.getZ(); + } + B3_FORCE_INLINE b3Scalar tdotz(const b3Vector3& v) const + { + return m_el[0].getZ() * v.getX() + m_el[1].getZ() * v.getY() + m_el[2].getZ() * v.getZ(); + } + + + /**@brief diagonalizes this matrix by the Jacobi method. + * @param rot stores the rotation from the coordinate system in which the matrix is diagonal to the original + * coordinate system, i.e., old_this = rot * new_this * rot^T. + * @param threshold See iteration + * @param iteration The iteration stops when all off-diagonal elements are less than the threshold multiplied + * by the sum of the absolute values of the diagonal, or when maxSteps have been executed. + * + * Note that this matrix is assumed to be symmetric. + */ + void diagonalize(b3Matrix3x3& rot, b3Scalar threshold, int maxSteps) + { + rot.setIdentity(); + for (int step = maxSteps; step > 0; step--) + { + // find off-diagonal element [p][q] with largest magnitude + int p = 0; + int q = 1; + int r = 2; + b3Scalar max = b3Fabs(m_el[0][1]); + b3Scalar v = b3Fabs(m_el[0][2]); + if (v > max) + { + q = 2; + r = 1; + max = v; + } + v = b3Fabs(m_el[1][2]); + if (v > max) + { + p = 1; + q = 2; + r = 0; + max = v; + } + + b3Scalar t = threshold * (b3Fabs(m_el[0][0]) + b3Fabs(m_el[1][1]) + b3Fabs(m_el[2][2])); + if (max <= t) + { + if (max <= B3_EPSILON * t) + { + return; + } + step = 1; + } + + // compute Jacobi rotation J which leads to a zero for element [p][q] + b3Scalar mpq = m_el[p][q]; + b3Scalar theta = (m_el[q][q] - m_el[p][p]) / (2 * mpq); + b3Scalar theta2 = theta * theta; + b3Scalar cos; + b3Scalar sin; + if (theta2 * theta2 < b3Scalar(10 / B3_EPSILON)) + { + t = (theta >= 0) ? 1 / (theta + b3Sqrt(1 + theta2)) + : 1 / (theta - b3Sqrt(1 + theta2)); + cos = 1 / b3Sqrt(1 + t * t); + sin = cos * t; + } + else + { + // approximation for large theta-value, i.e., a nearly diagonal matrix + t = 1 / (theta * (2 + b3Scalar(0.5) / theta2)); + cos = 1 - b3Scalar(0.5) * t * t; + sin = cos * t; + } + + // apply rotation to matrix (this = J^T * this * J) + m_el[p][q] = m_el[q][p] = 0; + m_el[p][p] -= t * mpq; + m_el[q][q] += t * mpq; + b3Scalar mrp = m_el[r][p]; + b3Scalar mrq = m_el[r][q]; + m_el[r][p] = m_el[p][r] = cos * mrp - sin * mrq; + m_el[r][q] = m_el[q][r] = cos * mrq + sin * mrp; + + // apply rotation to rot (rot = rot * J) + for (int i = 0; i < 3; i++) + { + b3Vector3& row = rot[i]; + mrp = row[p]; + mrq = row[q]; + row[p] = cos * mrp - sin * mrq; + row[q] = cos * mrq + sin * mrp; + } + } + } + + + + + /**@brief Calculate the matrix cofactor + * @param r1 The first row to use for calculating the cofactor + * @param c1 The first column to use for calculating the cofactor + * @param r1 The second row to use for calculating the cofactor + * @param c1 The second column to use for calculating the cofactor + * See http://en.wikipedia.org/wiki/Cofactor_(linear_algebra) for more details + */ + b3Scalar 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]; + } + + void serialize(struct b3Matrix3x3Data& dataOut) const; + + void serializeFloat(struct b3Matrix3x3FloatData& dataOut) const; + + void deSerialize(const struct b3Matrix3x3Data& dataIn); + + void deSerializeFloat(const struct b3Matrix3x3FloatData& dataIn); + + void deSerializeDouble(const struct b3Matrix3x3DoubleData& dataIn); + +}; + + +B3_FORCE_INLINE b3Matrix3x3& +b3Matrix3x3::operator*=(const b3Matrix3x3& m) +{ +#if defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + __m128 rv00, rv01, rv02; + __m128 rv10, rv11, rv12; + __m128 rv20, rv21, rv22; + __m128 mv0, mv1, mv2; + + rv02 = m_el[0].mVec128; + rv12 = m_el[1].mVec128; + rv22 = m_el[2].mVec128; + + mv0 = _mm_and_ps(m[0].mVec128, b3vFFF0fMask); + mv1 = _mm_and_ps(m[1].mVec128, b3vFFF0fMask); + mv2 = _mm_and_ps(m[2].mVec128, b3vFFF0fMask); + + // rv0 + rv00 = b3_splat_ps(rv02, 0); + rv01 = b3_splat_ps(rv02, 1); + rv02 = b3_splat_ps(rv02, 2); + + rv00 = _mm_mul_ps(rv00, mv0); + rv01 = _mm_mul_ps(rv01, mv1); + rv02 = _mm_mul_ps(rv02, mv2); + + // rv1 + rv10 = b3_splat_ps(rv12, 0); + rv11 = b3_splat_ps(rv12, 1); + rv12 = b3_splat_ps(rv12, 2); + + rv10 = _mm_mul_ps(rv10, mv0); + rv11 = _mm_mul_ps(rv11, mv1); + rv12 = _mm_mul_ps(rv12, mv2); + + // rv2 + rv20 = b3_splat_ps(rv22, 0); + rv21 = b3_splat_ps(rv22, 1); + rv22 = b3_splat_ps(rv22, 2); + + rv20 = _mm_mul_ps(rv20, mv0); + rv21 = _mm_mul_ps(rv21, mv1); + rv22 = _mm_mul_ps(rv22, mv2); + + rv00 = _mm_add_ps(rv00, rv01); + rv10 = _mm_add_ps(rv10, rv11); + rv20 = _mm_add_ps(rv20, rv21); + + m_el[0].mVec128 = _mm_add_ps(rv00, rv02); + m_el[1].mVec128 = _mm_add_ps(rv10, rv12); + m_el[2].mVec128 = _mm_add_ps(rv20, rv22); + +#elif defined(B3_USE_NEON) + + float32x4_t rv0, rv1, rv2; + float32x4_t v0, v1, v2; + float32x4_t mv0, mv1, mv2; + + v0 = m_el[0].mVec128; + v1 = m_el[1].mVec128; + v2 = m_el[2].mVec128; + + mv0 = (float32x4_t) vandq_s32((int32x4_t)m[0].mVec128, b3vFFF0Mask); + mv1 = (float32x4_t) vandq_s32((int32x4_t)m[1].mVec128, b3vFFF0Mask); + mv2 = (float32x4_t) vandq_s32((int32x4_t)m[2].mVec128, b3vFFF0Mask); + + rv0 = vmulq_lane_f32(mv0, vget_low_f32(v0), 0); + rv1 = vmulq_lane_f32(mv0, vget_low_f32(v1), 0); + rv2 = vmulq_lane_f32(mv0, vget_low_f32(v2), 0); + + rv0 = vmlaq_lane_f32(rv0, mv1, vget_low_f32(v0), 1); + rv1 = vmlaq_lane_f32(rv1, mv1, vget_low_f32(v1), 1); + rv2 = vmlaq_lane_f32(rv2, mv1, vget_low_f32(v2), 1); + + rv0 = vmlaq_lane_f32(rv0, mv2, vget_high_f32(v0), 0); + rv1 = vmlaq_lane_f32(rv1, mv2, vget_high_f32(v1), 0); + rv2 = vmlaq_lane_f32(rv2, mv2, vget_high_f32(v2), 0); + + m_el[0].mVec128 = rv0; + m_el[1].mVec128 = rv1; + m_el[2].mVec128 = rv2; +#else + 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])); +#endif + return *this; +} + +B3_FORCE_INLINE b3Matrix3x3& +b3Matrix3x3::operator+=(const b3Matrix3x3& m) +{ +#if (defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE))|| defined (B3_USE_NEON) + m_el[0].mVec128 = m_el[0].mVec128 + m.m_el[0].mVec128; + m_el[1].mVec128 = m_el[1].mVec128 + m.m_el[1].mVec128; + m_el[2].mVec128 = m_el[2].mVec128 + m.m_el[2].mVec128; +#else + setValue( + m_el[0][0]+m.m_el[0][0], + m_el[0][1]+m.m_el[0][1], + m_el[0][2]+m.m_el[0][2], + m_el[1][0]+m.m_el[1][0], + m_el[1][1]+m.m_el[1][1], + m_el[1][2]+m.m_el[1][2], + m_el[2][0]+m.m_el[2][0], + m_el[2][1]+m.m_el[2][1], + m_el[2][2]+m.m_el[2][2]); +#endif + return *this; +} + +B3_FORCE_INLINE b3Matrix3x3 +operator*(const b3Matrix3x3& m, const b3Scalar & k) +{ +#if (defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE)) + __m128 vk = b3_splat_ps(_mm_load_ss((float *)&k), 0x80); + return b3Matrix3x3( + _mm_mul_ps(m[0].mVec128, vk), + _mm_mul_ps(m[1].mVec128, vk), + _mm_mul_ps(m[2].mVec128, vk)); +#elif defined(B3_USE_NEON) + return b3Matrix3x3( + vmulq_n_f32(m[0].mVec128, k), + vmulq_n_f32(m[1].mVec128, k), + vmulq_n_f32(m[2].mVec128, k)); +#else + return b3Matrix3x3( + m[0].getX()*k,m[0].getY()*k,m[0].getZ()*k, + m[1].getX()*k,m[1].getY()*k,m[1].getZ()*k, + m[2].getX()*k,m[2].getY()*k,m[2].getZ()*k); +#endif +} + +B3_FORCE_INLINE b3Matrix3x3 +operator+(const b3Matrix3x3& m1, const b3Matrix3x3& m2) +{ +#if (defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE))|| defined (B3_USE_NEON) + return b3Matrix3x3( + m1[0].mVec128 + m2[0].mVec128, + m1[1].mVec128 + m2[1].mVec128, + m1[2].mVec128 + m2[2].mVec128); +#else + return b3Matrix3x3( + m1[0][0]+m2[0][0], + m1[0][1]+m2[0][1], + m1[0][2]+m2[0][2], + + m1[1][0]+m2[1][0], + m1[1][1]+m2[1][1], + m1[1][2]+m2[1][2], + + m1[2][0]+m2[2][0], + m1[2][1]+m2[2][1], + m1[2][2]+m2[2][2]); +#endif +} + +B3_FORCE_INLINE b3Matrix3x3 +operator-(const b3Matrix3x3& m1, const b3Matrix3x3& m2) +{ +#if (defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE))|| defined (B3_USE_NEON) + return b3Matrix3x3( + m1[0].mVec128 - m2[0].mVec128, + m1[1].mVec128 - m2[1].mVec128, + m1[2].mVec128 - m2[2].mVec128); +#else + return b3Matrix3x3( + m1[0][0]-m2[0][0], + m1[0][1]-m2[0][1], + m1[0][2]-m2[0][2], + + m1[1][0]-m2[1][0], + m1[1][1]-m2[1][1], + m1[1][2]-m2[1][2], + + m1[2][0]-m2[2][0], + m1[2][1]-m2[2][1], + m1[2][2]-m2[2][2]); +#endif +} + + +B3_FORCE_INLINE b3Matrix3x3& +b3Matrix3x3::operator-=(const b3Matrix3x3& m) +{ +#if (defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE))|| defined (B3_USE_NEON) + m_el[0].mVec128 = m_el[0].mVec128 - m.m_el[0].mVec128; + m_el[1].mVec128 = m_el[1].mVec128 - m.m_el[1].mVec128; + m_el[2].mVec128 = m_el[2].mVec128 - m.m_el[2].mVec128; +#else + setValue( + m_el[0][0]-m.m_el[0][0], + m_el[0][1]-m.m_el[0][1], + m_el[0][2]-m.m_el[0][2], + m_el[1][0]-m.m_el[1][0], + m_el[1][1]-m.m_el[1][1], + m_el[1][2]-m.m_el[1][2], + m_el[2][0]-m.m_el[2][0], + m_el[2][1]-m.m_el[2][1], + m_el[2][2]-m.m_el[2][2]); +#endif + return *this; +} + + +B3_FORCE_INLINE b3Scalar +b3Matrix3x3::determinant() const +{ + return b3Triple((*this)[0], (*this)[1], (*this)[2]); +} + + +B3_FORCE_INLINE b3Matrix3x3 +b3Matrix3x3::absolute() const +{ +#if (defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE)) + return b3Matrix3x3( + _mm_and_ps(m_el[0].mVec128, b3vAbsfMask), + _mm_and_ps(m_el[1].mVec128, b3vAbsfMask), + _mm_and_ps(m_el[2].mVec128, b3vAbsfMask)); +#elif defined(B3_USE_NEON) + return b3Matrix3x3( + (float32x4_t)vandq_s32((int32x4_t)m_el[0].mVec128, b3v3AbsMask), + (float32x4_t)vandq_s32((int32x4_t)m_el[1].mVec128, b3v3AbsMask), + (float32x4_t)vandq_s32((int32x4_t)m_el[2].mVec128, b3v3AbsMask)); +#else + return b3Matrix3x3( + b3Fabs(m_el[0].getX()), b3Fabs(m_el[0].getY()), b3Fabs(m_el[0].getZ()), + b3Fabs(m_el[1].getX()), b3Fabs(m_el[1].getY()), b3Fabs(m_el[1].getZ()), + b3Fabs(m_el[2].getX()), b3Fabs(m_el[2].getY()), b3Fabs(m_el[2].getZ())); +#endif +} + +B3_FORCE_INLINE b3Matrix3x3 +b3Matrix3x3::transpose() const +{ +#if (defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE)) + __m128 v0 = m_el[0].mVec128; + __m128 v1 = m_el[1].mVec128; + __m128 v2 = m_el[2].mVec128; // x2 y2 z2 w2 + __m128 vT; + + v2 = _mm_and_ps(v2, b3vFFF0fMask); // x2 y2 z2 0 + + vT = _mm_unpackhi_ps(v0, v1); // z0 z1 * * + v0 = _mm_unpacklo_ps(v0, v1); // x0 x1 y0 y1 + + v1 = _mm_shuffle_ps(v0, v2, B3_SHUFFLE(2, 3, 1, 3) ); // y0 y1 y2 0 + v0 = _mm_shuffle_ps(v0, v2, B3_SHUFFLE(0, 1, 0, 3) ); // x0 x1 x2 0 + v2 = b3CastdTo128f(_mm_move_sd(b3CastfTo128d(v2), b3CastfTo128d(vT))); // z0 z1 z2 0 + + + return b3Matrix3x3( v0, v1, v2 ); +#elif defined(B3_USE_NEON) + // note: zeros the w channel. We can preserve it at the cost of two more vtrn instructions. + static const uint32x2_t zMask = (const uint32x2_t) {-1, 0 }; + float32x4x2_t top = vtrnq_f32( m_el[0].mVec128, m_el[1].mVec128 ); // {x0 x1 z0 z1}, {y0 y1 w0 w1} + float32x2x2_t bl = vtrn_f32( vget_low_f32(m_el[2].mVec128), vdup_n_f32(0.0f) ); // {x2 0 }, {y2 0} + float32x4_t v0 = vcombine_f32( vget_low_f32(top.val[0]), bl.val[0] ); + float32x4_t v1 = vcombine_f32( vget_low_f32(top.val[1]), bl.val[1] ); + float32x2_t q = (float32x2_t) vand_u32( (uint32x2_t) vget_high_f32( m_el[2].mVec128), zMask ); + float32x4_t v2 = vcombine_f32( vget_high_f32(top.val[0]), q ); // z0 z1 z2 0 + return b3Matrix3x3( v0, v1, v2 ); +#else + return b3Matrix3x3( m_el[0].getX(), m_el[1].getX(), m_el[2].getX(), + m_el[0].getY(), m_el[1].getY(), m_el[2].getY(), + m_el[0].getZ(), m_el[1].getZ(), m_el[2].getZ()); +#endif +} + +B3_FORCE_INLINE b3Matrix3x3 +b3Matrix3x3::adjoint() const +{ + return b3Matrix3x3(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)); +} + +B3_FORCE_INLINE b3Matrix3x3 +b3Matrix3x3::inverse() const +{ + b3Vector3 co = b3MakeVector3(cofac(1, 1, 2, 2), cofac(1, 2, 2, 0), cofac(1, 0, 2, 1)); + b3Scalar det = (*this)[0].dot(co); + b3FullAssert(det != b3Scalar(0.0)); + b3Scalar s = b3Scalar(1.0) / det; + return b3Matrix3x3(co.getX() * s, cofac(0, 2, 2, 1) * s, cofac(0, 1, 1, 2) * s, + co.getY() * s, cofac(0, 0, 2, 2) * s, cofac(0, 2, 1, 0) * s, + co.getZ() * s, cofac(0, 1, 2, 0) * s, cofac(0, 0, 1, 1) * s); +} + +B3_FORCE_INLINE b3Matrix3x3 +b3Matrix3x3::transposeTimes(const b3Matrix3x3& m) const +{ +#if (defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE)) + // zeros w +// static const __m128i xyzMask = (const __m128i){ -1ULL, 0xffffffffULL }; + __m128 row = m_el[0].mVec128; + __m128 m0 = _mm_and_ps( m.getRow(0).mVec128, b3vFFF0fMask ); + __m128 m1 = _mm_and_ps( m.getRow(1).mVec128, b3vFFF0fMask); + __m128 m2 = _mm_and_ps( m.getRow(2).mVec128, b3vFFF0fMask ); + __m128 r0 = _mm_mul_ps(m0, _mm_shuffle_ps(row, row, 0)); + __m128 r1 = _mm_mul_ps(m0, _mm_shuffle_ps(row, row, 0x55)); + __m128 r2 = _mm_mul_ps(m0, _mm_shuffle_ps(row, row, 0xaa)); + row = m_el[1].mVec128; + r0 = _mm_add_ps( r0, _mm_mul_ps(m1, _mm_shuffle_ps(row, row, 0))); + r1 = _mm_add_ps( r1, _mm_mul_ps(m1, _mm_shuffle_ps(row, row, 0x55))); + r2 = _mm_add_ps( r2, _mm_mul_ps(m1, _mm_shuffle_ps(row, row, 0xaa))); + row = m_el[2].mVec128; + r0 = _mm_add_ps( r0, _mm_mul_ps(m2, _mm_shuffle_ps(row, row, 0))); + r1 = _mm_add_ps( r1, _mm_mul_ps(m2, _mm_shuffle_ps(row, row, 0x55))); + r2 = _mm_add_ps( r2, _mm_mul_ps(m2, _mm_shuffle_ps(row, row, 0xaa))); + return b3Matrix3x3( r0, r1, r2 ); + +#elif defined B3_USE_NEON + // zeros w + static const uint32x4_t xyzMask = (const uint32x4_t){ -1, -1, -1, 0 }; + float32x4_t m0 = (float32x4_t) vandq_u32( (uint32x4_t) m.getRow(0).mVec128, xyzMask ); + float32x4_t m1 = (float32x4_t) vandq_u32( (uint32x4_t) m.getRow(1).mVec128, xyzMask ); + float32x4_t m2 = (float32x4_t) vandq_u32( (uint32x4_t) m.getRow(2).mVec128, xyzMask ); + float32x4_t row = m_el[0].mVec128; + float32x4_t r0 = vmulq_lane_f32( m0, vget_low_f32(row), 0); + float32x4_t r1 = vmulq_lane_f32( m0, vget_low_f32(row), 1); + float32x4_t r2 = vmulq_lane_f32( m0, vget_high_f32(row), 0); + row = m_el[1].mVec128; + r0 = vmlaq_lane_f32( r0, m1, vget_low_f32(row), 0); + r1 = vmlaq_lane_f32( r1, m1, vget_low_f32(row), 1); + r2 = vmlaq_lane_f32( r2, m1, vget_high_f32(row), 0); + row = m_el[2].mVec128; + r0 = vmlaq_lane_f32( r0, m2, vget_low_f32(row), 0); + r1 = vmlaq_lane_f32( r1, m2, vget_low_f32(row), 1); + r2 = vmlaq_lane_f32( r2, m2, vget_high_f32(row), 0); + return b3Matrix3x3( r0, r1, r2 ); +#else + return b3Matrix3x3( + m_el[0].getX() * m[0].getX() + m_el[1].getX() * m[1].getX() + m_el[2].getX() * m[2].getX(), + m_el[0].getX() * m[0].getY() + m_el[1].getX() * m[1].getY() + m_el[2].getX() * m[2].getY(), + m_el[0].getX() * m[0].getZ() + m_el[1].getX() * m[1].getZ() + m_el[2].getX() * m[2].getZ(), + m_el[0].getY() * m[0].getX() + m_el[1].getY() * m[1].getX() + m_el[2].getY() * m[2].getX(), + m_el[0].getY() * m[0].getY() + m_el[1].getY() * m[1].getY() + m_el[2].getY() * m[2].getY(), + m_el[0].getY() * m[0].getZ() + m_el[1].getY() * m[1].getZ() + m_el[2].getY() * m[2].getZ(), + m_el[0].getZ() * m[0].getX() + m_el[1].getZ() * m[1].getX() + m_el[2].getZ() * m[2].getX(), + m_el[0].getZ() * m[0].getY() + m_el[1].getZ() * m[1].getY() + m_el[2].getZ() * m[2].getY(), + m_el[0].getZ() * m[0].getZ() + m_el[1].getZ() * m[1].getZ() + m_el[2].getZ() * m[2].getZ()); +#endif +} + +B3_FORCE_INLINE b3Matrix3x3 +b3Matrix3x3::timesTranspose(const b3Matrix3x3& m) const +{ +#if (defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE)) + __m128 a0 = m_el[0].mVec128; + __m128 a1 = m_el[1].mVec128; + __m128 a2 = m_el[2].mVec128; + + b3Matrix3x3 mT = m.transpose(); // we rely on transpose() zeroing w channel so that we don't have to do it here + __m128 mx = mT[0].mVec128; + __m128 my = mT[1].mVec128; + __m128 mz = mT[2].mVec128; + + __m128 r0 = _mm_mul_ps(mx, _mm_shuffle_ps(a0, a0, 0x00)); + __m128 r1 = _mm_mul_ps(mx, _mm_shuffle_ps(a1, a1, 0x00)); + __m128 r2 = _mm_mul_ps(mx, _mm_shuffle_ps(a2, a2, 0x00)); + r0 = _mm_add_ps(r0, _mm_mul_ps(my, _mm_shuffle_ps(a0, a0, 0x55))); + r1 = _mm_add_ps(r1, _mm_mul_ps(my, _mm_shuffle_ps(a1, a1, 0x55))); + r2 = _mm_add_ps(r2, _mm_mul_ps(my, _mm_shuffle_ps(a2, a2, 0x55))); + r0 = _mm_add_ps(r0, _mm_mul_ps(mz, _mm_shuffle_ps(a0, a0, 0xaa))); + r1 = _mm_add_ps(r1, _mm_mul_ps(mz, _mm_shuffle_ps(a1, a1, 0xaa))); + r2 = _mm_add_ps(r2, _mm_mul_ps(mz, _mm_shuffle_ps(a2, a2, 0xaa))); + return b3Matrix3x3( r0, r1, r2); + +#elif defined B3_USE_NEON + float32x4_t a0 = m_el[0].mVec128; + float32x4_t a1 = m_el[1].mVec128; + float32x4_t a2 = m_el[2].mVec128; + + b3Matrix3x3 mT = m.transpose(); // we rely on transpose() zeroing w channel so that we don't have to do it here + float32x4_t mx = mT[0].mVec128; + float32x4_t my = mT[1].mVec128; + float32x4_t mz = mT[2].mVec128; + + float32x4_t r0 = vmulq_lane_f32( mx, vget_low_f32(a0), 0); + float32x4_t r1 = vmulq_lane_f32( mx, vget_low_f32(a1), 0); + float32x4_t r2 = vmulq_lane_f32( mx, vget_low_f32(a2), 0); + r0 = vmlaq_lane_f32( r0, my, vget_low_f32(a0), 1); + r1 = vmlaq_lane_f32( r1, my, vget_low_f32(a1), 1); + r2 = vmlaq_lane_f32( r2, my, vget_low_f32(a2), 1); + r0 = vmlaq_lane_f32( r0, mz, vget_high_f32(a0), 0); + r1 = vmlaq_lane_f32( r1, mz, vget_high_f32(a1), 0); + r2 = vmlaq_lane_f32( r2, mz, vget_high_f32(a2), 0); + return b3Matrix3x3( r0, r1, r2 ); + +#else + return b3Matrix3x3( + 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])); +#endif +} + +B3_FORCE_INLINE b3Vector3 +operator*(const b3Matrix3x3& m, const b3Vector3& v) +{ +#if (defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE))|| defined (B3_USE_NEON) + return v.dot3(m[0], m[1], m[2]); +#else + return b3MakeVector3(m[0].dot(v), m[1].dot(v), m[2].dot(v)); +#endif +} + + +B3_FORCE_INLINE b3Vector3 +operator*(const b3Vector3& v, const b3Matrix3x3& m) +{ +#if (defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE)) + + const __m128 vv = v.mVec128; + + __m128 c0 = b3_splat_ps( vv, 0); + __m128 c1 = b3_splat_ps( vv, 1); + __m128 c2 = b3_splat_ps( vv, 2); + + c0 = _mm_mul_ps(c0, _mm_and_ps(m[0].mVec128, b3vFFF0fMask) ); + c1 = _mm_mul_ps(c1, _mm_and_ps(m[1].mVec128, b3vFFF0fMask) ); + c0 = _mm_add_ps(c0, c1); + c2 = _mm_mul_ps(c2, _mm_and_ps(m[2].mVec128, b3vFFF0fMask) ); + + return b3MakeVector3(_mm_add_ps(c0, c2)); +#elif defined(B3_USE_NEON) + const float32x4_t vv = v.mVec128; + const float32x2_t vlo = vget_low_f32(vv); + const float32x2_t vhi = vget_high_f32(vv); + + float32x4_t c0, c1, c2; + + c0 = (float32x4_t) vandq_s32((int32x4_t)m[0].mVec128, b3vFFF0Mask); + c1 = (float32x4_t) vandq_s32((int32x4_t)m[1].mVec128, b3vFFF0Mask); + c2 = (float32x4_t) vandq_s32((int32x4_t)m[2].mVec128, b3vFFF0Mask); + + c0 = vmulq_lane_f32(c0, vlo, 0); + c1 = vmulq_lane_f32(c1, vlo, 1); + c2 = vmulq_lane_f32(c2, vhi, 0); + c0 = vaddq_f32(c0, c1); + c0 = vaddq_f32(c0, c2); + + return b3MakeVector3(c0); +#else + return b3MakeVector3(m.tdotx(v), m.tdoty(v), m.tdotz(v)); +#endif +} + +B3_FORCE_INLINE b3Matrix3x3 +operator*(const b3Matrix3x3& m1, const b3Matrix3x3& m2) +{ +#if (defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE)) + + __m128 m10 = m1[0].mVec128; + __m128 m11 = m1[1].mVec128; + __m128 m12 = m1[2].mVec128; + + __m128 m2v = _mm_and_ps(m2[0].mVec128, b3vFFF0fMask); + + __m128 c0 = b3_splat_ps( m10, 0); + __m128 c1 = b3_splat_ps( m11, 0); + __m128 c2 = b3_splat_ps( m12, 0); + + c0 = _mm_mul_ps(c0, m2v); + c1 = _mm_mul_ps(c1, m2v); + c2 = _mm_mul_ps(c2, m2v); + + m2v = _mm_and_ps(m2[1].mVec128, b3vFFF0fMask); + + __m128 c0_1 = b3_splat_ps( m10, 1); + __m128 c1_1 = b3_splat_ps( m11, 1); + __m128 c2_1 = b3_splat_ps( m12, 1); + + c0_1 = _mm_mul_ps(c0_1, m2v); + c1_1 = _mm_mul_ps(c1_1, m2v); + c2_1 = _mm_mul_ps(c2_1, m2v); + + m2v = _mm_and_ps(m2[2].mVec128, b3vFFF0fMask); + + c0 = _mm_add_ps(c0, c0_1); + c1 = _mm_add_ps(c1, c1_1); + c2 = _mm_add_ps(c2, c2_1); + + m10 = b3_splat_ps( m10, 2); + m11 = b3_splat_ps( m11, 2); + m12 = b3_splat_ps( m12, 2); + + m10 = _mm_mul_ps(m10, m2v); + m11 = _mm_mul_ps(m11, m2v); + m12 = _mm_mul_ps(m12, m2v); + + c0 = _mm_add_ps(c0, m10); + c1 = _mm_add_ps(c1, m11); + c2 = _mm_add_ps(c2, m12); + + return b3Matrix3x3(c0, c1, c2); + +#elif defined(B3_USE_NEON) + + float32x4_t rv0, rv1, rv2; + float32x4_t v0, v1, v2; + float32x4_t mv0, mv1, mv2; + + v0 = m1[0].mVec128; + v1 = m1[1].mVec128; + v2 = m1[2].mVec128; + + mv0 = (float32x4_t) vandq_s32((int32x4_t)m2[0].mVec128, b3vFFF0Mask); + mv1 = (float32x4_t) vandq_s32((int32x4_t)m2[1].mVec128, b3vFFF0Mask); + mv2 = (float32x4_t) vandq_s32((int32x4_t)m2[2].mVec128, b3vFFF0Mask); + + rv0 = vmulq_lane_f32(mv0, vget_low_f32(v0), 0); + rv1 = vmulq_lane_f32(mv0, vget_low_f32(v1), 0); + rv2 = vmulq_lane_f32(mv0, vget_low_f32(v2), 0); + + rv0 = vmlaq_lane_f32(rv0, mv1, vget_low_f32(v0), 1); + rv1 = vmlaq_lane_f32(rv1, mv1, vget_low_f32(v1), 1); + rv2 = vmlaq_lane_f32(rv2, mv1, vget_low_f32(v2), 1); + + rv0 = vmlaq_lane_f32(rv0, mv2, vget_high_f32(v0), 0); + rv1 = vmlaq_lane_f32(rv1, mv2, vget_high_f32(v1), 0); + rv2 = vmlaq_lane_f32(rv2, mv2, vget_high_f32(v2), 0); + + return b3Matrix3x3(rv0, rv1, rv2); + +#else + return b3Matrix3x3( + 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])); +#endif +} + +/* +B3_FORCE_INLINE b3Matrix3x3 b3MultTransposeLeft(const b3Matrix3x3& m1, const b3Matrix3x3& m2) { +return b3Matrix3x3( +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]); +} +*/ + +/**@brief Equality operator between two matrices +* It will test all elements are equal. */ +B3_FORCE_INLINE bool operator==(const b3Matrix3x3& m1, const b3Matrix3x3& m2) +{ +#if (defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE)) + + __m128 c0, c1, c2; + + c0 = _mm_cmpeq_ps(m1[0].mVec128, m2[0].mVec128); + c1 = _mm_cmpeq_ps(m1[1].mVec128, m2[1].mVec128); + c2 = _mm_cmpeq_ps(m1[2].mVec128, m2[2].mVec128); + + c0 = _mm_and_ps(c0, c1); + c0 = _mm_and_ps(c0, c2); + + return (0x7 == _mm_movemask_ps((__m128)c0)); +#else + return + ( m1[0][0] == m2[0][0] && m1[1][0] == m2[1][0] && m1[2][0] == m2[2][0] && + m1[0][1] == m2[0][1] && m1[1][1] == m2[1][1] && m1[2][1] == m2[2][1] && + m1[0][2] == m2[0][2] && m1[1][2] == m2[1][2] && m1[2][2] == m2[2][2] ); +#endif +} + +///for serialization +struct b3Matrix3x3FloatData +{ + b3Vector3FloatData m_el[3]; +}; + +///for serialization +struct b3Matrix3x3DoubleData +{ + b3Vector3DoubleData m_el[3]; +}; + + + + +B3_FORCE_INLINE void b3Matrix3x3::serialize(struct b3Matrix3x3Data& dataOut) const +{ + for (int i=0;i<3;i++) + m_el[i].serialize(dataOut.m_el[i]); +} + +B3_FORCE_INLINE void b3Matrix3x3::serializeFloat(struct b3Matrix3x3FloatData& dataOut) const +{ + for (int i=0;i<3;i++) + m_el[i].serializeFloat(dataOut.m_el[i]); +} + + +B3_FORCE_INLINE void b3Matrix3x3::deSerialize(const struct b3Matrix3x3Data& dataIn) +{ + for (int i=0;i<3;i++) + m_el[i].deSerialize(dataIn.m_el[i]); +} + +B3_FORCE_INLINE void b3Matrix3x3::deSerializeFloat(const struct b3Matrix3x3FloatData& dataIn) +{ + for (int i=0;i<3;i++) + m_el[i].deSerializeFloat(dataIn.m_el[i]); +} + +B3_FORCE_INLINE void b3Matrix3x3::deSerializeDouble(const struct b3Matrix3x3DoubleData& dataIn) +{ + for (int i=0;i<3;i++) + m_el[i].deSerializeDouble(dataIn.m_el[i]); +} + +#endif //B3_MATRIX3x3_H + diff --git a/extern/bullet/src/Bullet3Common/b3MinMax.h b/extern/bullet/src/Bullet3Common/b3MinMax.h new file mode 100644 index 000000000000..73af23a4f97d --- /dev/null +++ b/extern/bullet/src/Bullet3Common/b3MinMax.h @@ -0,0 +1,71 @@ +/* +Copyright (c) 2003-2013 Gino van den Bergen / Erwin Coumans http://bulletphysics.org + +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 B3_GEN_MINMAX_H +#define B3_GEN_MINMAX_H + +#include "b3Scalar.h" + +template +B3_FORCE_INLINE const T& b3Min(const T& a, const T& b) +{ + return a < b ? a : b ; +} + +template +B3_FORCE_INLINE const T& b3Max(const T& a, const T& b) +{ + return a > b ? a : b; +} + +template +B3_FORCE_INLINE const T& b3Clamped(const T& a, const T& lb, const T& ub) +{ + return a < lb ? lb : (ub < a ? ub : a); +} + +template +B3_FORCE_INLINE void b3SetMin(T& a, const T& b) +{ + if (b < a) + { + a = b; + } +} + +template +B3_FORCE_INLINE void b3SetMax(T& a, const T& b) +{ + if (a < b) + { + a = b; + } +} + +template +B3_FORCE_INLINE void b3Clamp(T& a, const T& lb, const T& ub) +{ + if (a < lb) + { + a = lb; + } + else if (ub < a) + { + a = ub; + } +} + +#endif //B3_GEN_MINMAX_H diff --git a/extern/bullet/src/Bullet3Common/b3PoolAllocator.h b/extern/bullet/src/Bullet3Common/b3PoolAllocator.h new file mode 100644 index 000000000000..2fcdcf5b2491 --- /dev/null +++ b/extern/bullet/src/Bullet3Common/b3PoolAllocator.h @@ -0,0 +1,121 @@ +/* +Copyright (c) 2003-2013 Gino van den Bergen / Erwin Coumans http://bulletphysics.org + +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_POOL_ALLOCATOR_H +#define _BT_POOL_ALLOCATOR_H + +#include "b3Scalar.h" +#include "b3AlignedAllocator.h" + +///The b3PoolAllocator class allows to efficiently allocate a large pool of objects, instead of dynamically allocating them separately. +class b3PoolAllocator +{ + int m_elemSize; + int m_maxElements; + int m_freeCount; + void* m_firstFree; + unsigned char* m_pool; + +public: + + b3PoolAllocator(int elemSize, int maxElements) + :m_elemSize(elemSize), + m_maxElements(maxElements) + { + m_pool = (unsigned char*) b3AlignedAlloc( static_cast(m_elemSize*m_maxElements),16); + + unsigned char* p = m_pool; + m_firstFree = p; + m_freeCount = m_maxElements; + int count = m_maxElements; + while (--count) { + *(void**)p = (p + m_elemSize); + p += m_elemSize; + } + *(void**)p = 0; + } + + ~b3PoolAllocator() + { + b3AlignedFree( m_pool); + } + + int getFreeCount() const + { + return m_freeCount; + } + + int getUsedCount() const + { + return m_maxElements - m_freeCount; + } + + int getMaxCount() const + { + return m_maxElements; + } + + void* allocate(int size) + { + // release mode fix + (void)size; + b3Assert(!size || size<=m_elemSize); + b3Assert(m_freeCount>0); + void* result = m_firstFree; + m_firstFree = *(void**)m_firstFree; + --m_freeCount; + return result; + } + + bool validPtr(void* ptr) + { + if (ptr) { + if (((unsigned char*)ptr >= m_pool && (unsigned char*)ptr < m_pool + m_maxElements * m_elemSize)) + { + return true; + } + } + return false; + } + + void freeMemory(void* ptr) + { + if (ptr) { + b3Assert((unsigned char*)ptr >= m_pool && (unsigned char*)ptr < m_pool + m_maxElements * m_elemSize); + + *(void**)ptr = m_firstFree; + m_firstFree = ptr; + ++m_freeCount; + } + } + + int getElementSize() const + { + return m_elemSize; + } + + unsigned char* getPoolAddress() + { + return m_pool; + } + + const unsigned char* getPoolAddress() const + { + return m_pool; + } + +}; + +#endif //_BT_POOL_ALLOCATOR_H diff --git a/extern/bullet/src/Bullet3Common/b3QuadWord.h b/extern/bullet/src/Bullet3Common/b3QuadWord.h new file mode 100644 index 000000000000..65c95819775c --- /dev/null +++ b/extern/bullet/src/Bullet3Common/b3QuadWord.h @@ -0,0 +1,245 @@ +/* +Copyright (c) 2003-2013 Gino van den Bergen / Erwin Coumans http://bulletphysics.org + +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 B3_SIMD_QUADWORD_H +#define B3_SIMD_QUADWORD_H + +#include "b3Scalar.h" +#include "b3MinMax.h" + + + + + +#if defined (__CELLOS_LV2) && defined (__SPU__) +#include +#endif + +/**@brief The b3QuadWord class is base class for b3Vector3 and b3Quaternion. + * Some issues under PS3 Linux with IBM 2.1 SDK, gcc compiler prevent from using aligned quadword. + */ +#ifndef USE_LIBSPE2 +B3_ATTRIBUTE_ALIGNED16(class) b3QuadWord +#else +class b3QuadWord +#endif +{ +protected: + +#if defined (__SPU__) && defined (__CELLOS_LV2__) + union { + vec_float4 mVec128; + b3Scalar m_floats[4]; + }; +public: + vec_float4 get128() const + { + return mVec128; + } + +#else //__CELLOS_LV2__ __SPU__ + +#if defined(B3_USE_SSE) || defined(B3_USE_NEON) +public: + union { + b3SimdFloat4 mVec128; + b3Scalar m_floats[4]; + struct {b3Scalar x,y,z,w;}; + }; +public: + B3_FORCE_INLINE b3SimdFloat4 get128() const + { + return mVec128; + } + B3_FORCE_INLINE void set128(b3SimdFloat4 v128) + { + mVec128 = v128; + } +#else +public: + union + { + b3Scalar m_floats[4]; + struct {b3Scalar x,y,z,w;}; + }; +#endif // B3_USE_SSE + +#endif //__CELLOS_LV2__ __SPU__ + + public: + +#if defined(B3_USE_SSE) || defined(B3_USE_NEON) + + // Set Vector + B3_FORCE_INLINE b3QuadWord(const b3SimdFloat4 vec) + { + mVec128 = vec; + } + + // Copy constructor + B3_FORCE_INLINE b3QuadWord(const b3QuadWord& rhs) + { + mVec128 = rhs.mVec128; + } + + // Assignment Operator + B3_FORCE_INLINE b3QuadWord& + operator=(const b3QuadWord& v) + { + mVec128 = v.mVec128; + + return *this; + } + +#endif + + /**@brief Return the x value */ + B3_FORCE_INLINE const b3Scalar& getX() const { return m_floats[0]; } + /**@brief Return the y value */ + B3_FORCE_INLINE const b3Scalar& getY() const { return m_floats[1]; } + /**@brief Return the z value */ + B3_FORCE_INLINE const b3Scalar& getZ() const { return m_floats[2]; } + /**@brief Set the x value */ + B3_FORCE_INLINE void setX(b3Scalar _x) { m_floats[0] = _x;}; + /**@brief Set the y value */ + B3_FORCE_INLINE void setY(b3Scalar _y) { m_floats[1] = _y;}; + /**@brief Set the z value */ + B3_FORCE_INLINE void setZ(b3Scalar _z) { m_floats[2] = _z;}; + /**@brief Set the w value */ + B3_FORCE_INLINE void setW(b3Scalar _w) { m_floats[3] = _w;}; + /**@brief Return the x value */ + + + //B3_FORCE_INLINE b3Scalar& operator[](int i) { return (&m_floats[0])[i]; } + //B3_FORCE_INLINE const b3Scalar& operator[](int i) const { return (&m_floats[0])[i]; } + ///operator b3Scalar*() replaces operator[], using implicit conversion. We added operator != and operator == to avoid pointer comparisons. + B3_FORCE_INLINE operator b3Scalar *() { return &m_floats[0]; } + B3_FORCE_INLINE operator const b3Scalar *() const { return &m_floats[0]; } + + B3_FORCE_INLINE bool operator==(const b3QuadWord& other) const + { +#ifdef B3_USE_SSE + return (0xf == _mm_movemask_ps((__m128)_mm_cmpeq_ps(mVec128, other.mVec128))); +#else + return ((m_floats[3]==other.m_floats[3]) && + (m_floats[2]==other.m_floats[2]) && + (m_floats[1]==other.m_floats[1]) && + (m_floats[0]==other.m_floats[0])); +#endif + } + + B3_FORCE_INLINE bool operator!=(const b3QuadWord& other) const + { + return !(*this == other); + } + + /**@brief Set x,y,z and zero w + * @param x Value of x + * @param y Value of y + * @param z Value of z + */ + B3_FORCE_INLINE void setValue(const b3Scalar& _x, const b3Scalar& _y, const b3Scalar& _z) + { + m_floats[0]=_x; + m_floats[1]=_y; + m_floats[2]=_z; + m_floats[3] = 0.f; + } + +/* void getValue(b3Scalar *m) const + { + m[0] = m_floats[0]; + m[1] = m_floats[1]; + m[2] = m_floats[2]; + } +*/ +/**@brief Set the values + * @param x Value of x + * @param y Value of y + * @param z Value of z + * @param w Value of w + */ + B3_FORCE_INLINE void setValue(const b3Scalar& _x, const b3Scalar& _y, const b3Scalar& _z,const b3Scalar& _w) + { + m_floats[0]=_x; + m_floats[1]=_y; + m_floats[2]=_z; + m_floats[3]=_w; + } + /**@brief No initialization constructor */ + B3_FORCE_INLINE b3QuadWord() + // :m_floats[0](b3Scalar(0.)),m_floats[1](b3Scalar(0.)),m_floats[2](b3Scalar(0.)),m_floats[3](b3Scalar(0.)) + { + } + + /**@brief Three argument constructor (zeros w) + * @param x Value of x + * @param y Value of y + * @param z Value of z + */ + B3_FORCE_INLINE b3QuadWord(const b3Scalar& _x, const b3Scalar& _y, const b3Scalar& _z) + { + m_floats[0] = _x, m_floats[1] = _y, m_floats[2] = _z, m_floats[3] = 0.0f; + } + +/**@brief Initializing constructor + * @param x Value of x + * @param y Value of y + * @param z Value of z + * @param w Value of w + */ + B3_FORCE_INLINE b3QuadWord(const b3Scalar& _x, const b3Scalar& _y, const b3Scalar& _z,const b3Scalar& _w) + { + m_floats[0] = _x, m_floats[1] = _y, m_floats[2] = _z, m_floats[3] = _w; + } + + /**@brief Set each element to the max of the current values and the values of another b3QuadWord + * @param other The other b3QuadWord to compare with + */ + B3_FORCE_INLINE void setMax(const b3QuadWord& other) + { + #ifdef B3_USE_SSE + mVec128 = _mm_max_ps(mVec128, other.mVec128); + #elif defined(B3_USE_NEON) + mVec128 = vmaxq_f32(mVec128, other.mVec128); + #else + b3SetMax(m_floats[0], other.m_floats[0]); + b3SetMax(m_floats[1], other.m_floats[1]); + b3SetMax(m_floats[2], other.m_floats[2]); + b3SetMax(m_floats[3], other.m_floats[3]); + #endif + } + /**@brief Set each element to the min of the current values and the values of another b3QuadWord + * @param other The other b3QuadWord to compare with + */ + B3_FORCE_INLINE void setMin(const b3QuadWord& other) + { + #ifdef B3_USE_SSE + mVec128 = _mm_min_ps(mVec128, other.mVec128); + #elif defined(B3_USE_NEON) + mVec128 = vminq_f32(mVec128, other.mVec128); + #else + b3SetMin(m_floats[0], other.m_floats[0]); + b3SetMin(m_floats[1], other.m_floats[1]); + b3SetMin(m_floats[2], other.m_floats[2]); + b3SetMin(m_floats[3], other.m_floats[3]); + #endif + } + + + +}; + +#endif //B3_SIMD_QUADWORD_H diff --git a/extern/bullet/src/Bullet3Common/b3Quaternion.h b/extern/bullet/src/Bullet3Common/b3Quaternion.h new file mode 100644 index 000000000000..ad2054334879 --- /dev/null +++ b/extern/bullet/src/Bullet3Common/b3Quaternion.h @@ -0,0 +1,918 @@ +/* +Copyright (c) 2003-2013 Gino van den Bergen / Erwin Coumans http://bulletphysics.org + +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 B3_SIMD__QUATERNION_H_ +#define B3_SIMD__QUATERNION_H_ + + +#include "b3Vector3.h" +#include "b3QuadWord.h" + + + + + +#ifdef B3_USE_SSE + +const __m128 B3_ATTRIBUTE_ALIGNED16(b3vOnes) = {1.0f, 1.0f, 1.0f, 1.0f}; + +#endif + +#if defined(B3_USE_SSE) || defined(B3_USE_NEON) + +const b3SimdFloat4 B3_ATTRIBUTE_ALIGNED16(b3vQInv) = {-0.0f, -0.0f, -0.0f, +0.0f}; +const b3SimdFloat4 B3_ATTRIBUTE_ALIGNED16(b3vPPPM) = {+0.0f, +0.0f, +0.0f, -0.0f}; + +#endif + +/**@brief The b3Quaternion implements quaternion to perform linear algebra rotations in combination with b3Matrix3x3, b3Vector3 and b3Transform. */ +class b3Quaternion : public b3QuadWord { +public: + /**@brief No initialization constructor */ + b3Quaternion() {} + +#if (defined(B3_USE_SSE_IN_API) && defined(B3_USE_SSE))|| defined(B3_USE_NEON) + // Set Vector + B3_FORCE_INLINE b3Quaternion(const b3SimdFloat4 vec) + { + mVec128 = vec; + } + + // Copy constructor + B3_FORCE_INLINE b3Quaternion(const b3Quaternion& rhs) + { + mVec128 = rhs.mVec128; + } + + // Assignment Operator + B3_FORCE_INLINE b3Quaternion& + operator=(const b3Quaternion& v) + { + mVec128 = v.mVec128; + + return *this; + } + +#endif + + // template + // explicit Quaternion(const b3Scalar *v) : Tuple4(v) {} + /**@brief Constructor from scalars */ + b3Quaternion(const b3Scalar& _x, const b3Scalar& _y, const b3Scalar& _z, const b3Scalar& _w) + : b3QuadWord(_x, _y, _z, _w) + { + //b3Assert(!((_x==1.f) && (_y==0.f) && (_z==0.f) && (_w==0.f))); + } + /**@brief Axis angle Constructor + * @param axis The axis which the rotation is around + * @param angle The magnitude of the rotation around the angle (Radians) */ + b3Quaternion(const b3Vector3& _axis, const b3Scalar& _angle) + { + setRotation(_axis, _angle); + } + /**@brief Constructor from Euler angles + * @param yaw Angle around Y unless B3_EULER_DEFAULT_ZYX defined then Z + * @param pitch Angle around X unless B3_EULER_DEFAULT_ZYX defined then Y + * @param roll Angle around Z unless B3_EULER_DEFAULT_ZYX defined then X */ + b3Quaternion(const b3Scalar& yaw, const b3Scalar& pitch, const b3Scalar& roll) + { +#ifndef B3_EULER_DEFAULT_ZYX + setEuler(yaw, pitch, roll); +#else + setEulerZYX(yaw, pitch, roll); +#endif + } + /**@brief Set the rotation using axis angle notation + * @param axis The axis around which to rotate + * @param angle The magnitude of the rotation in Radians */ + void setRotation(const b3Vector3& axis, const b3Scalar& _angle) + { + b3Scalar d = axis.length(); + b3Assert(d != b3Scalar(0.0)); + b3Scalar s = b3Sin(_angle * b3Scalar(0.5)) / d; + setValue(axis.getX() * s, axis.getY() * s, axis.getZ() * s, + b3Cos(_angle * b3Scalar(0.5))); + } + /**@brief Set the quaternion using Euler angles + * @param yaw Angle around Y + * @param pitch Angle around X + * @param roll Angle around Z */ + void setEuler(const b3Scalar& yaw, const b3Scalar& pitch, const b3Scalar& roll) + { + b3Scalar halfYaw = b3Scalar(yaw) * b3Scalar(0.5); + b3Scalar halfPitch = b3Scalar(pitch) * b3Scalar(0.5); + b3Scalar halfRoll = b3Scalar(roll) * b3Scalar(0.5); + b3Scalar cosYaw = b3Cos(halfYaw); + b3Scalar sinYaw = b3Sin(halfYaw); + b3Scalar cosPitch = b3Cos(halfPitch); + b3Scalar sinPitch = b3Sin(halfPitch); + b3Scalar cosRoll = b3Cos(halfRoll); + b3Scalar sinRoll = b3Sin(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); + } + + /**@brief Set the quaternion using euler angles + * @param yaw Angle around Z + * @param pitch Angle around Y + * @param roll Angle around X */ + void setEulerZYX(const b3Scalar& yawZ, const b3Scalar& pitchY, const b3Scalar& rollX) + { + b3Scalar halfYaw = b3Scalar(yawZ) * b3Scalar(0.5); + b3Scalar halfPitch = b3Scalar(pitchY) * b3Scalar(0.5); + b3Scalar halfRoll = b3Scalar(rollX) * b3Scalar(0.5); + b3Scalar cosYaw = b3Cos(halfYaw); + b3Scalar sinYaw = b3Sin(halfYaw); + b3Scalar cosPitch = b3Cos(halfPitch); + b3Scalar sinPitch = b3Sin(halfPitch); + b3Scalar cosRoll = b3Cos(halfRoll); + b3Scalar sinRoll = b3Sin(halfRoll); + setValue(sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw, //x + cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw, //y + cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw, //z + cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw); //formerly yzx + normalize(); + } + + /**@brief Get the euler angles from this quaternion + * @param yaw Angle around Z + * @param pitch Angle around Y + * @param roll Angle around X */ + void getEulerZYX(b3Scalar& yawZ, b3Scalar& pitchY, b3Scalar& rollX) const + { + b3Scalar squ; + b3Scalar sqx; + b3Scalar sqy; + b3Scalar sqz; + b3Scalar sarg; + sqx = m_floats[0] * m_floats[0]; + sqy = m_floats[1] * m_floats[1]; + sqz = m_floats[2] * m_floats[2]; + squ = m_floats[3] * m_floats[3]; + rollX = b3Atan2(2 * (m_floats[1] * m_floats[2] + m_floats[3] * m_floats[0]), squ - sqx - sqy + sqz); + sarg = b3Scalar(-2.) * (m_floats[0] * m_floats[2] - m_floats[3] * m_floats[1]); + pitchY = sarg <= b3Scalar(-1.0) ? b3Scalar(-0.5) * B3_PI: (sarg >= b3Scalar(1.0) ? b3Scalar(0.5) * B3_PI : b3Asin(sarg)); + yawZ = b3Atan2(2 * (m_floats[0] * m_floats[1] + m_floats[3] * m_floats[2]), squ + sqx - sqy - sqz); + } + + /**@brief Add two quaternions + * @param q The quaternion to add to this one */ + B3_FORCE_INLINE b3Quaternion& operator+=(const b3Quaternion& q) + { +#if defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + mVec128 = _mm_add_ps(mVec128, q.mVec128); +#elif defined(B3_USE_NEON) + mVec128 = vaddq_f32(mVec128, q.mVec128); +#else + m_floats[0] += q.getX(); + m_floats[1] += q.getY(); + m_floats[2] += q.getZ(); + m_floats[3] += q.m_floats[3]; +#endif + return *this; + } + + /**@brief Subtract out a quaternion + * @param q The quaternion to subtract from this one */ + b3Quaternion& operator-=(const b3Quaternion& q) + { +#if defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + mVec128 = _mm_sub_ps(mVec128, q.mVec128); +#elif defined(B3_USE_NEON) + mVec128 = vsubq_f32(mVec128, q.mVec128); +#else + m_floats[0] -= q.getX(); + m_floats[1] -= q.getY(); + m_floats[2] -= q.getZ(); + m_floats[3] -= q.m_floats[3]; +#endif + return *this; + } + + /**@brief Scale this quaternion + * @param s The scalar to scale by */ + b3Quaternion& operator*=(const b3Scalar& s) + { +#if defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + __m128 vs = _mm_load_ss(&s); // (S 0 0 0) + vs = b3_pshufd_ps(vs, 0); // (S S S S) + mVec128 = _mm_mul_ps(mVec128, vs); +#elif defined(B3_USE_NEON) + mVec128 = vmulq_n_f32(mVec128, s); +#else + m_floats[0] *= s; + m_floats[1] *= s; + m_floats[2] *= s; + m_floats[3] *= s; +#endif + return *this; + } + + /**@brief Multiply this quaternion by q on the right + * @param q The other quaternion + * Equivilant to this = this * q */ + b3Quaternion& operator*=(const b3Quaternion& q) + { +#if defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + __m128 vQ2 = q.get128(); + + __m128 A1 = b3_pshufd_ps(mVec128, B3_SHUFFLE(0,1,2,0)); + __m128 B1 = b3_pshufd_ps(vQ2, B3_SHUFFLE(3,3,3,0)); + + A1 = A1 * B1; + + __m128 A2 = b3_pshufd_ps(mVec128, B3_SHUFFLE(1,2,0,1)); + __m128 B2 = b3_pshufd_ps(vQ2, B3_SHUFFLE(2,0,1,1)); + + A2 = A2 * B2; + + B1 = b3_pshufd_ps(mVec128, B3_SHUFFLE(2,0,1,2)); + B2 = b3_pshufd_ps(vQ2, B3_SHUFFLE(1,2,0,2)); + + B1 = B1 * B2; // A3 *= B3 + + mVec128 = b3_splat_ps(mVec128, 3); // A0 + mVec128 = mVec128 * vQ2; // A0 * B0 + + A1 = A1 + A2; // AB12 + mVec128 = mVec128 - B1; // AB03 = AB0 - AB3 + A1 = _mm_xor_ps(A1, b3vPPPM); // change sign of the last element + mVec128 = mVec128+ A1; // AB03 + AB12 + +#elif defined(B3_USE_NEON) + + float32x4_t vQ1 = mVec128; + float32x4_t vQ2 = q.get128(); + float32x4_t A0, A1, B1, A2, B2, A3, B3; + float32x2_t vQ1zx, vQ2wx, vQ1yz, vQ2zx, vQ2yz, vQ2xz; + + { + float32x2x2_t tmp; + tmp = vtrn_f32( vget_high_f32(vQ1), vget_low_f32(vQ1) ); // {z x}, {w y} + vQ1zx = tmp.val[0]; + + tmp = vtrn_f32( vget_high_f32(vQ2), vget_low_f32(vQ2) ); // {z x}, {w y} + vQ2zx = tmp.val[0]; + } + vQ2wx = vext_f32(vget_high_f32(vQ2), vget_low_f32(vQ2), 1); + + vQ1yz = vext_f32(vget_low_f32(vQ1), vget_high_f32(vQ1), 1); + + vQ2yz = vext_f32(vget_low_f32(vQ2), vget_high_f32(vQ2), 1); + vQ2xz = vext_f32(vQ2zx, vQ2zx, 1); + + A1 = vcombine_f32(vget_low_f32(vQ1), vQ1zx); // X Y z x + B1 = vcombine_f32(vdup_lane_f32(vget_high_f32(vQ2), 1), vQ2wx); // W W W X + + A2 = vcombine_f32(vQ1yz, vget_low_f32(vQ1)); + B2 = vcombine_f32(vQ2zx, vdup_lane_f32(vget_low_f32(vQ2), 1)); + + A3 = vcombine_f32(vQ1zx, vQ1yz); // Z X Y Z + B3 = vcombine_f32(vQ2yz, vQ2xz); // Y Z x z + + A1 = vmulq_f32(A1, B1); + A2 = vmulq_f32(A2, B2); + A3 = vmulq_f32(A3, B3); // A3 *= B3 + A0 = vmulq_lane_f32(vQ2, vget_high_f32(vQ1), 1); // A0 * B0 + + A1 = vaddq_f32(A1, A2); // AB12 = AB1 + AB2 + A0 = vsubq_f32(A0, A3); // AB03 = AB0 - AB3 + + // change the sign of the last element + A1 = (b3SimdFloat4)veorq_s32((int32x4_t)A1, (int32x4_t)b3vPPPM); + A0 = vaddq_f32(A0, A1); // AB03 + AB12 + + mVec128 = A0; +#else + setValue( + m_floats[3] * q.getX() + m_floats[0] * q.m_floats[3] + m_floats[1] * q.getZ() - m_floats[2] * q.getY(), + m_floats[3] * q.getY() + m_floats[1] * q.m_floats[3] + m_floats[2] * q.getX() - m_floats[0] * q.getZ(), + m_floats[3] * q.getZ() + m_floats[2] * q.m_floats[3] + m_floats[0] * q.getY() - m_floats[1] * q.getX(), + m_floats[3] * q.m_floats[3] - m_floats[0] * q.getX() - m_floats[1] * q.getY() - m_floats[2] * q.getZ()); +#endif + return *this; + } + /**@brief Return the dot product between this quaternion and another + * @param q The other quaternion */ + b3Scalar dot(const b3Quaternion& q) const + { +#if defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + __m128 vd; + + vd = _mm_mul_ps(mVec128, q.mVec128); + + __m128 t = _mm_movehl_ps(vd, vd); + vd = _mm_add_ps(vd, t); + t = _mm_shuffle_ps(vd, vd, 0x55); + vd = _mm_add_ss(vd, t); + + return _mm_cvtss_f32(vd); +#elif defined(B3_USE_NEON) + float32x4_t vd = vmulq_f32(mVec128, q.mVec128); + float32x2_t x = vpadd_f32(vget_low_f32(vd), vget_high_f32(vd)); + x = vpadd_f32(x, x); + return vget_lane_f32(x, 0); +#else + return m_floats[0] * q.getX() + + m_floats[1] * q.getY() + + m_floats[2] * q.getZ() + + m_floats[3] * q.m_floats[3]; +#endif + } + + /**@brief Return the length squared of the quaternion */ + b3Scalar length2() const + { + return dot(*this); + } + + /**@brief Return the length of the quaternion */ + b3Scalar length() const + { + return b3Sqrt(length2()); + } + + /**@brief Normalize the quaternion + * Such that x^2 + y^2 + z^2 +w^2 = 1 */ + b3Quaternion& normalize() + { +#if defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + __m128 vd; + + vd = _mm_mul_ps(mVec128, mVec128); + + __m128 t = _mm_movehl_ps(vd, vd); + vd = _mm_add_ps(vd, t); + t = _mm_shuffle_ps(vd, vd, 0x55); + vd = _mm_add_ss(vd, t); + + vd = _mm_sqrt_ss(vd); + vd = _mm_div_ss(b3vOnes, vd); + vd = b3_pshufd_ps(vd, 0); // splat + mVec128 = _mm_mul_ps(mVec128, vd); + + return *this; +#else + return *this /= length(); +#endif + } + + /**@brief Return a scaled version of this quaternion + * @param s The scale factor */ + B3_FORCE_INLINE b3Quaternion + operator*(const b3Scalar& s) const + { +#if defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + __m128 vs = _mm_load_ss(&s); // (S 0 0 0) + vs = b3_pshufd_ps(vs, 0x00); // (S S S S) + + return b3Quaternion(_mm_mul_ps(mVec128, vs)); +#elif defined(B3_USE_NEON) + return b3Quaternion(vmulq_n_f32(mVec128, s)); +#else + return b3Quaternion(getX() * s, getY() * s, getZ() * s, m_floats[3] * s); +#endif + } + + /**@brief Return an inversely scaled versionof this quaternion + * @param s The inverse scale factor */ + b3Quaternion operator/(const b3Scalar& s) const + { + b3Assert(s != b3Scalar(0.0)); + return *this * (b3Scalar(1.0) / s); + } + + /**@brief Inversely scale this quaternion + * @param s The scale factor */ + b3Quaternion& operator/=(const b3Scalar& s) + { + b3Assert(s != b3Scalar(0.0)); + return *this *= b3Scalar(1.0) / s; + } + + /**@brief Return a normalized version of this quaternion */ + b3Quaternion normalized() const + { + return *this / length(); + } + /**@brief Return the angle between this quaternion and the other + * @param q The other quaternion */ + b3Scalar angle(const b3Quaternion& q) const + { + b3Scalar s = b3Sqrt(length2() * q.length2()); + b3Assert(s != b3Scalar(0.0)); + return b3Acos(dot(q) / s); + } + /**@brief Return the angle of rotation represented by this quaternion */ + b3Scalar getAngle() const + { + b3Scalar s = b3Scalar(2.) * b3Acos(m_floats[3]); + return s; + } + + /**@brief Return the axis of the rotation represented by this quaternion */ + b3Vector3 getAxis() const + { + b3Scalar s_squared = 1.f-m_floats[3]*m_floats[3]; + + if (s_squared < b3Scalar(10.) * B3_EPSILON) //Check for divide by zero + return b3MakeVector3(1.0, 0.0, 0.0); // Arbitrary + b3Scalar s = 1.f/b3Sqrt(s_squared); + return b3MakeVector3(m_floats[0] * s, m_floats[1] * s, m_floats[2] * s); + } + + /**@brief Return the inverse of this quaternion */ + b3Quaternion inverse() const + { +#if defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + return b3Quaternion(_mm_xor_ps(mVec128, b3vQInv)); +#elif defined(B3_USE_NEON) + return b3Quaternion((b3SimdFloat4)veorq_s32((int32x4_t)mVec128, (int32x4_t)b3vQInv)); +#else + return b3Quaternion(-m_floats[0], -m_floats[1], -m_floats[2], m_floats[3]); +#endif + } + + /**@brief Return the sum of this quaternion and the other + * @param q2 The other quaternion */ + B3_FORCE_INLINE b3Quaternion + operator+(const b3Quaternion& q2) const + { +#if defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + return b3Quaternion(_mm_add_ps(mVec128, q2.mVec128)); +#elif defined(B3_USE_NEON) + return b3Quaternion(vaddq_f32(mVec128, q2.mVec128)); +#else + const b3Quaternion& q1 = *this; + return b3Quaternion(q1.getX() + q2.getX(), q1.getY() + q2.getY(), q1.getZ() + q2.getZ(), q1.m_floats[3] + q2.m_floats[3]); +#endif + } + + /**@brief Return the difference between this quaternion and the other + * @param q2 The other quaternion */ + B3_FORCE_INLINE b3Quaternion + operator-(const b3Quaternion& q2) const + { +#if defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + return b3Quaternion(_mm_sub_ps(mVec128, q2.mVec128)); +#elif defined(B3_USE_NEON) + return b3Quaternion(vsubq_f32(mVec128, q2.mVec128)); +#else + const b3Quaternion& q1 = *this; + return b3Quaternion(q1.getX() - q2.getX(), q1.getY() - q2.getY(), q1.getZ() - q2.getZ(), q1.m_floats[3] - q2.m_floats[3]); +#endif + } + + /**@brief Return the negative of this quaternion + * This simply negates each element */ + B3_FORCE_INLINE b3Quaternion operator-() const + { +#if defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + return b3Quaternion(_mm_xor_ps(mVec128, b3vMzeroMask)); +#elif defined(B3_USE_NEON) + return b3Quaternion((b3SimdFloat4)veorq_s32((int32x4_t)mVec128, (int32x4_t)b3vMzeroMask) ); +#else + const b3Quaternion& q2 = *this; + return b3Quaternion( - q2.getX(), - q2.getY(), - q2.getZ(), - q2.m_floats[3]); +#endif + } + /**@todo document this and it's use */ + B3_FORCE_INLINE b3Quaternion farthest( const b3Quaternion& qd) const + { + b3Quaternion diff,sum; + diff = *this - qd; + sum = *this + qd; + if( diff.dot(diff) > sum.dot(sum) ) + return qd; + return (-qd); + } + + /**@todo document this and it's use */ + B3_FORCE_INLINE b3Quaternion nearest( const b3Quaternion& qd) const + { + b3Quaternion diff,sum; + diff = *this - qd; + sum = *this + qd; + if( diff.dot(diff) < sum.dot(sum) ) + return qd; + return (-qd); + } + + + /**@brief Return the quaternion which is the result of Spherical Linear Interpolation between this and the other quaternion + * @param q The other quaternion to interpolate with + * @param t The ratio between this and q to interpolate. If t = 0 the result is this, if t=1 the result is q. + * Slerp interpolates assuming constant velocity. */ + b3Quaternion slerp(const b3Quaternion& q, const b3Scalar& t) const + { + b3Scalar magnitude = b3Sqrt(length2() * q.length2()); + b3Assert(magnitude > b3Scalar(0)); + + b3Scalar product = dot(q) / magnitude; + if (b3Fabs(product) < b3Scalar(1)) + { + // Take care of long angle case see http://en.wikipedia.org/wiki/Slerp + const b3Scalar sign = (product < 0) ? b3Scalar(-1) : b3Scalar(1); + + const b3Scalar theta = b3Acos(sign * product); + const b3Scalar s1 = b3Sin(sign * t * theta); + const b3Scalar d = b3Scalar(1.0) / b3Sin(theta); + const b3Scalar s0 = b3Sin((b3Scalar(1.0) - t) * theta); + + return b3Quaternion( + (m_floats[0] * s0 + q.getX() * s1) * d, + (m_floats[1] * s0 + q.getY() * s1) * d, + (m_floats[2] * s0 + q.getZ() * s1) * d, + (m_floats[3] * s0 + q.m_floats[3] * s1) * d); + } + else + { + return *this; + } + } + + static const b3Quaternion& getIdentity() + { + static const b3Quaternion identityQuat(b3Scalar(0.),b3Scalar(0.),b3Scalar(0.),b3Scalar(1.)); + return identityQuat; + } + + B3_FORCE_INLINE const b3Scalar& getW() const { return m_floats[3]; } + + +}; + + + + + +/**@brief Return the product of two quaternions */ +B3_FORCE_INLINE b3Quaternion +operator*(const b3Quaternion& q1, const b3Quaternion& q2) +{ +#if defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + __m128 vQ1 = q1.get128(); + __m128 vQ2 = q2.get128(); + __m128 A0, A1, B1, A2, B2; + + A1 = b3_pshufd_ps(vQ1, B3_SHUFFLE(0,1,2,0)); // X Y z x // vtrn + B1 = b3_pshufd_ps(vQ2, B3_SHUFFLE(3,3,3,0)); // W W W X // vdup vext + + A1 = A1 * B1; + + A2 = b3_pshufd_ps(vQ1, B3_SHUFFLE(1,2,0,1)); // Y Z X Y // vext + B2 = b3_pshufd_ps(vQ2, B3_SHUFFLE(2,0,1,1)); // z x Y Y // vtrn vdup + + A2 = A2 * B2; + + B1 = b3_pshufd_ps(vQ1, B3_SHUFFLE(2,0,1,2)); // z x Y Z // vtrn vext + B2 = b3_pshufd_ps(vQ2, B3_SHUFFLE(1,2,0,2)); // Y Z x z // vext vtrn + + B1 = B1 * B2; // A3 *= B3 + + A0 = b3_splat_ps(vQ1, 3); // A0 + A0 = A0 * vQ2; // A0 * B0 + + A1 = A1 + A2; // AB12 + A0 = A0 - B1; // AB03 = AB0 - AB3 + + A1 = _mm_xor_ps(A1, b3vPPPM); // change sign of the last element + A0 = A0 + A1; // AB03 + AB12 + + return b3Quaternion(A0); + +#elif defined(B3_USE_NEON) + + float32x4_t vQ1 = q1.get128(); + float32x4_t vQ2 = q2.get128(); + float32x4_t A0, A1, B1, A2, B2, A3, B3; + float32x2_t vQ1zx, vQ2wx, vQ1yz, vQ2zx, vQ2yz, vQ2xz; + + { + float32x2x2_t tmp; + tmp = vtrn_f32( vget_high_f32(vQ1), vget_low_f32(vQ1) ); // {z x}, {w y} + vQ1zx = tmp.val[0]; + + tmp = vtrn_f32( vget_high_f32(vQ2), vget_low_f32(vQ2) ); // {z x}, {w y} + vQ2zx = tmp.val[0]; + } + vQ2wx = vext_f32(vget_high_f32(vQ2), vget_low_f32(vQ2), 1); + + vQ1yz = vext_f32(vget_low_f32(vQ1), vget_high_f32(vQ1), 1); + + vQ2yz = vext_f32(vget_low_f32(vQ2), vget_high_f32(vQ2), 1); + vQ2xz = vext_f32(vQ2zx, vQ2zx, 1); + + A1 = vcombine_f32(vget_low_f32(vQ1), vQ1zx); // X Y z x + B1 = vcombine_f32(vdup_lane_f32(vget_high_f32(vQ2), 1), vQ2wx); // W W W X + + A2 = vcombine_f32(vQ1yz, vget_low_f32(vQ1)); + B2 = vcombine_f32(vQ2zx, vdup_lane_f32(vget_low_f32(vQ2), 1)); + + A3 = vcombine_f32(vQ1zx, vQ1yz); // Z X Y Z + B3 = vcombine_f32(vQ2yz, vQ2xz); // Y Z x z + + A1 = vmulq_f32(A1, B1); + A2 = vmulq_f32(A2, B2); + A3 = vmulq_f32(A3, B3); // A3 *= B3 + A0 = vmulq_lane_f32(vQ2, vget_high_f32(vQ1), 1); // A0 * B0 + + A1 = vaddq_f32(A1, A2); // AB12 = AB1 + AB2 + A0 = vsubq_f32(A0, A3); // AB03 = AB0 - AB3 + + // change the sign of the last element + A1 = (b3SimdFloat4)veorq_s32((int32x4_t)A1, (int32x4_t)b3vPPPM); + A0 = vaddq_f32(A0, A1); // AB03 + AB12 + + return b3Quaternion(A0); + +#else + return b3Quaternion( + q1.getW() * q2.getX() + q1.getX() * q2.getW() + q1.getY() * q2.getZ() - q1.getZ() * q2.getY(), + q1.getW() * q2.getY() + q1.getY() * q2.getW() + q1.getZ() * q2.getX() - q1.getX() * q2.getZ(), + q1.getW() * q2.getZ() + q1.getZ() * q2.getW() + q1.getX() * q2.getY() - q1.getY() * q2.getX(), + q1.getW() * q2.getW() - q1.getX() * q2.getX() - q1.getY() * q2.getY() - q1.getZ() * q2.getZ()); +#endif +} + +B3_FORCE_INLINE b3Quaternion +operator*(const b3Quaternion& q, const b3Vector3& w) +{ +#if defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + __m128 vQ1 = q.get128(); + __m128 vQ2 = w.get128(); + __m128 A1, B1, A2, B2, A3, B3; + + A1 = b3_pshufd_ps(vQ1, B3_SHUFFLE(3,3,3,0)); + B1 = b3_pshufd_ps(vQ2, B3_SHUFFLE(0,1,2,0)); + + A1 = A1 * B1; + + A2 = b3_pshufd_ps(vQ1, B3_SHUFFLE(1,2,0,1)); + B2 = b3_pshufd_ps(vQ2, B3_SHUFFLE(2,0,1,1)); + + A2 = A2 * B2; + + A3 = b3_pshufd_ps(vQ1, B3_SHUFFLE(2,0,1,2)); + B3 = b3_pshufd_ps(vQ2, B3_SHUFFLE(1,2,0,2)); + + A3 = A3 * B3; // A3 *= B3 + + A1 = A1 + A2; // AB12 + A1 = _mm_xor_ps(A1, b3vPPPM); // change sign of the last element + A1 = A1 - A3; // AB123 = AB12 - AB3 + + return b3Quaternion(A1); + +#elif defined(B3_USE_NEON) + + float32x4_t vQ1 = q.get128(); + float32x4_t vQ2 = w.get128(); + float32x4_t A1, B1, A2, B2, A3, B3; + float32x2_t vQ1wx, vQ2zx, vQ1yz, vQ2yz, vQ1zx, vQ2xz; + + vQ1wx = vext_f32(vget_high_f32(vQ1), vget_low_f32(vQ1), 1); + { + float32x2x2_t tmp; + + tmp = vtrn_f32( vget_high_f32(vQ2), vget_low_f32(vQ2) ); // {z x}, {w y} + vQ2zx = tmp.val[0]; + + tmp = vtrn_f32( vget_high_f32(vQ1), vget_low_f32(vQ1) ); // {z x}, {w y} + vQ1zx = tmp.val[0]; + } + + vQ1yz = vext_f32(vget_low_f32(vQ1), vget_high_f32(vQ1), 1); + + vQ2yz = vext_f32(vget_low_f32(vQ2), vget_high_f32(vQ2), 1); + vQ2xz = vext_f32(vQ2zx, vQ2zx, 1); + + A1 = vcombine_f32(vdup_lane_f32(vget_high_f32(vQ1), 1), vQ1wx); // W W W X + B1 = vcombine_f32(vget_low_f32(vQ2), vQ2zx); // X Y z x + + A2 = vcombine_f32(vQ1yz, vget_low_f32(vQ1)); + B2 = vcombine_f32(vQ2zx, vdup_lane_f32(vget_low_f32(vQ2), 1)); + + A3 = vcombine_f32(vQ1zx, vQ1yz); // Z X Y Z + B3 = vcombine_f32(vQ2yz, vQ2xz); // Y Z x z + + A1 = vmulq_f32(A1, B1); + A2 = vmulq_f32(A2, B2); + A3 = vmulq_f32(A3, B3); // A3 *= B3 + + A1 = vaddq_f32(A1, A2); // AB12 = AB1 + AB2 + + // change the sign of the last element + A1 = (b3SimdFloat4)veorq_s32((int32x4_t)A1, (int32x4_t)b3vPPPM); + + A1 = vsubq_f32(A1, A3); // AB123 = AB12 - AB3 + + return b3Quaternion(A1); + +#else + return b3Quaternion( + q.getW() * w.getX() + q.getY() * w.getZ() - q.getZ() * w.getY(), + q.getW() * w.getY() + q.getZ() * w.getX() - q.getX() * w.getZ(), + q.getW() * w.getZ() + q.getX() * w.getY() - q.getY() * w.getX(), + -q.getX() * w.getX() - q.getY() * w.getY() - q.getZ() * w.getZ()); +#endif +} + +B3_FORCE_INLINE b3Quaternion +operator*(const b3Vector3& w, const b3Quaternion& q) +{ +#if defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + __m128 vQ1 = w.get128(); + __m128 vQ2 = q.get128(); + __m128 A1, B1, A2, B2, A3, B3; + + A1 = b3_pshufd_ps(vQ1, B3_SHUFFLE(0,1,2,0)); // X Y z x + B1 = b3_pshufd_ps(vQ2, B3_SHUFFLE(3,3,3,0)); // W W W X + + A1 = A1 * B1; + + A2 = b3_pshufd_ps(vQ1, B3_SHUFFLE(1,2,0,1)); + B2 = b3_pshufd_ps(vQ2, B3_SHUFFLE(2,0,1,1)); + + A2 = A2 *B2; + + A3 = b3_pshufd_ps(vQ1, B3_SHUFFLE(2,0,1,2)); + B3 = b3_pshufd_ps(vQ2, B3_SHUFFLE(1,2,0,2)); + + A3 = A3 * B3; // A3 *= B3 + + A1 = A1 + A2; // AB12 + A1 = _mm_xor_ps(A1, b3vPPPM); // change sign of the last element + A1 = A1 - A3; // AB123 = AB12 - AB3 + + return b3Quaternion(A1); + +#elif defined(B3_USE_NEON) + + float32x4_t vQ1 = w.get128(); + float32x4_t vQ2 = q.get128(); + float32x4_t A1, B1, A2, B2, A3, B3; + float32x2_t vQ1zx, vQ2wx, vQ1yz, vQ2zx, vQ2yz, vQ2xz; + + { + float32x2x2_t tmp; + + tmp = vtrn_f32( vget_high_f32(vQ1), vget_low_f32(vQ1) ); // {z x}, {w y} + vQ1zx = tmp.val[0]; + + tmp = vtrn_f32( vget_high_f32(vQ2), vget_low_f32(vQ2) ); // {z x}, {w y} + vQ2zx = tmp.val[0]; + } + vQ2wx = vext_f32(vget_high_f32(vQ2), vget_low_f32(vQ2), 1); + + vQ1yz = vext_f32(vget_low_f32(vQ1), vget_high_f32(vQ1), 1); + + vQ2yz = vext_f32(vget_low_f32(vQ2), vget_high_f32(vQ2), 1); + vQ2xz = vext_f32(vQ2zx, vQ2zx, 1); + + A1 = vcombine_f32(vget_low_f32(vQ1), vQ1zx); // X Y z x + B1 = vcombine_f32(vdup_lane_f32(vget_high_f32(vQ2), 1), vQ2wx); // W W W X + + A2 = vcombine_f32(vQ1yz, vget_low_f32(vQ1)); + B2 = vcombine_f32(vQ2zx, vdup_lane_f32(vget_low_f32(vQ2), 1)); + + A3 = vcombine_f32(vQ1zx, vQ1yz); // Z X Y Z + B3 = vcombine_f32(vQ2yz, vQ2xz); // Y Z x z + + A1 = vmulq_f32(A1, B1); + A2 = vmulq_f32(A2, B2); + A3 = vmulq_f32(A3, B3); // A3 *= B3 + + A1 = vaddq_f32(A1, A2); // AB12 = AB1 + AB2 + + // change the sign of the last element + A1 = (b3SimdFloat4)veorq_s32((int32x4_t)A1, (int32x4_t)b3vPPPM); + + A1 = vsubq_f32(A1, A3); // AB123 = AB12 - AB3 + + return b3Quaternion(A1); + +#else + return b3Quaternion( + +w.getX() * q.getW() + w.getY() * q.getZ() - w.getZ() * q.getY(), + +w.getY() * q.getW() + w.getZ() * q.getX() - w.getX() * q.getZ(), + +w.getZ() * q.getW() + w.getX() * q.getY() - w.getY() * q.getX(), + -w.getX() * q.getX() - w.getY() * q.getY() - w.getZ() * q.getZ()); +#endif +} + +/**@brief Calculate the dot product between two quaternions */ +B3_FORCE_INLINE b3Scalar +b3Dot(const b3Quaternion& q1, const b3Quaternion& q2) +{ + return q1.dot(q2); +} + + +/**@brief Return the length of a quaternion */ +B3_FORCE_INLINE b3Scalar +b3Length(const b3Quaternion& q) +{ + return q.length(); +} + +/**@brief Return the angle between two quaternions*/ +B3_FORCE_INLINE b3Scalar +b3Angle(const b3Quaternion& q1, const b3Quaternion& q2) +{ + return q1.angle(q2); +} + +/**@brief Return the inverse of a quaternion*/ +B3_FORCE_INLINE b3Quaternion +b3Inverse(const b3Quaternion& q) +{ + return q.inverse(); +} + +/**@brief Return the result of spherical linear interpolation betwen two quaternions + * @param q1 The first quaternion + * @param q2 The second quaternion + * @param t The ration between q1 and q2. t = 0 return q1, t=1 returns q2 + * Slerp assumes constant velocity between positions. */ +B3_FORCE_INLINE b3Quaternion +b3Slerp(const b3Quaternion& q1, const b3Quaternion& q2, const b3Scalar& t) +{ + return q1.slerp(q2, t); +} + +B3_FORCE_INLINE b3Quaternion +b3QuatMul(const b3Quaternion& rot0, const b3Quaternion& rot1) +{ + return rot0*rot1; +} + +B3_FORCE_INLINE b3Quaternion +b3QuatNormalized(const b3Quaternion& orn) +{ + return orn.normalized(); +} + + + +B3_FORCE_INLINE b3Vector3 +b3QuatRotate(const b3Quaternion& rotation, const b3Vector3& v) +{ + b3Quaternion q = rotation * v; + q *= rotation.inverse(); +#if defined (B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + return b3MakeVector3(_mm_and_ps(q.get128(), b3vFFF0fMask)); +#elif defined(B3_USE_NEON) + return b3MakeVector3((float32x4_t)vandq_s32((int32x4_t)q.get128(), b3vFFF0Mask)); +#else + return b3MakeVector3(q.getX(),q.getY(),q.getZ()); +#endif +} + +B3_FORCE_INLINE b3Quaternion +b3ShortestArcQuat(const b3Vector3& v0, const b3Vector3& v1) // Game Programming Gems 2.10. make sure v0,v1 are normalized +{ + b3Vector3 c = v0.cross(v1); + b3Scalar d = v0.dot(v1); + + if (d < -1.0 + B3_EPSILON) + { + b3Vector3 n,unused; + b3PlaneSpace1(v0,n,unused); + return b3Quaternion(n.getX(),n.getY(),n.getZ(),0.0f); // just pick any vector that is orthogonal to v0 + } + + b3Scalar s = b3Sqrt((1.0f + d) * 2.0f); + b3Scalar rs = 1.0f / s; + + return b3Quaternion(c.getX()*rs,c.getY()*rs,c.getZ()*rs,s * 0.5f); + +} + +B3_FORCE_INLINE b3Quaternion +b3ShortestArcQuatNormalize2(b3Vector3& v0,b3Vector3& v1) +{ + v0.normalize(); + v1.normalize(); + return b3ShortestArcQuat(v0,v1); +} + +#endif //B3_SIMD__QUATERNION_H_ + + + diff --git a/extern/bullet/src/Bullet3Common/b3Random.h b/extern/bullet/src/Bullet3Common/b3Random.h new file mode 100644 index 000000000000..dc040f15626d --- /dev/null +++ b/extern/bullet/src/Bullet3Common/b3Random.h @@ -0,0 +1,50 @@ +/* +Copyright (c) 2003-2013 Gino van den Bergen / Erwin Coumans http://bulletphysics.org + +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 B3_GEN_RANDOM_H +#define B3_GEN_RANDOM_H + +#include "b3Scalar.h" + +#ifdef MT19937 + +#include +#include + +#define B3_RAND_MAX UINT_MAX + +B3_FORCE_INLINE void b3Srand(unsigned int seed) { init_genrand(seed); } +B3_FORCE_INLINE unsigned int b3rand() { return genrand_int32(); } + +#else + +#include + +#define B3_RAND_MAX RAND_MAX + +B3_FORCE_INLINE void b3Srand(unsigned int seed) { srand(seed); } +B3_FORCE_INLINE unsigned int b3rand() { return rand(); } + +#endif + +inline b3Scalar b3RandRange(b3Scalar minRange, b3Scalar maxRange) +{ + return (b3rand() / (b3Scalar(B3_RAND_MAX) + b3Scalar(1.0))) * (maxRange - minRange) + minRange; +} + + +#endif //B3_GEN_RANDOM_H + diff --git a/extern/bullet/src/Bullet3Common/b3ResizablePool.h b/extern/bullet/src/Bullet3Common/b3ResizablePool.h new file mode 100644 index 000000000000..06ad8a778d38 --- /dev/null +++ b/extern/bullet/src/Bullet3Common/b3ResizablePool.h @@ -0,0 +1,182 @@ + +#ifndef B3_RESIZABLE_POOL_H +#define B3_RESIZABLE_POOL_H + +#include "Bullet3Common/b3AlignedObjectArray.h" + +enum +{ + B3_POOL_HANDLE_TERMINAL_FREE=-1, + B3_POOL_HANDLE_TERMINAL_USED =-2 +}; + +template +struct b3PoolBodyHandle : public U +{ + B3_DECLARE_ALIGNED_ALLOCATOR(); + + int m_nextFreeHandle; + void setNextFree(int next) + { + m_nextFreeHandle = next; + } + int getNextFree() const + { + return m_nextFreeHandle; + } +}; + +template +class b3ResizablePool +{ + +protected: + b3AlignedObjectArray m_bodyHandles; + int m_numUsedHandles; // number of active handles + int m_firstFreeHandle; // free handles list + + T* getHandleInternal(int handle) + { + return &m_bodyHandles[handle]; + + } + const T* getHandleInternal(int handle) const + { + return &m_bodyHandles[handle]; + } + +public: + + b3ResizablePool() + { + initHandles(); + } + + virtual ~b3ResizablePool() + { + exitHandles(); + } +///handle management + + int getNumHandles() const + { + return m_bodyHandles.size(); + } + + void getUsedHandles(b3AlignedObjectArray& usedHandles) const + { + + for (int i=0;i=0); + b3Assert(handle=m_bodyHandles.size())) + { + return 0; + } + + if (m_bodyHandles[handle].getNextFree()==B3_POOL_HANDLE_TERMINAL_USED) + { + return &m_bodyHandles[handle]; + } + return 0; + + } + const T* getHandle(int handle) const + { + b3Assert(handle>=0); + b3Assert(handle=m_bodyHandles.size())) + { + return 0; + } + + if (m_bodyHandles[handle].getNextFree()==B3_POOL_HANDLE_TERMINAL_USED) + { + return &m_bodyHandles[handle]; + } + return 0; + } + + void increaseHandleCapacity(int extraCapacity) + { + int curCapacity = m_bodyHandles.size(); + //b3Assert(curCapacity == m_numUsedHandles); + int newCapacity = curCapacity + extraCapacity; + m_bodyHandles.resize(newCapacity); + + { + for (int i = curCapacity; i < newCapacity; i++) + m_bodyHandles[i].setNextFree(i + 1); + + + m_bodyHandles[newCapacity - 1].setNextFree(-1); + } + m_firstFreeHandle = curCapacity; + } + void initHandles() + { + m_numUsedHandles = 0; + m_firstFreeHandle = -1; + + increaseHandleCapacity(1); + } + + void exitHandles() + { + m_bodyHandles.resize(0); + m_firstFreeHandle = -1; + m_numUsedHandles = 0; + } + + int allocHandle() + { + b3Assert(m_firstFreeHandle>=0); + + int handle = m_firstFreeHandle; + m_firstFreeHandle = getHandleInternal(handle)->getNextFree(); + m_numUsedHandles++; + + if (m_firstFreeHandle<0) + { + //int curCapacity = m_bodyHandles.size(); + int additionalCapacity= m_bodyHandles.size(); + increaseHandleCapacity(additionalCapacity); + + + getHandleInternal(handle)->setNextFree(m_firstFreeHandle); + } + getHandleInternal(handle)->setNextFree(B3_POOL_HANDLE_TERMINAL_USED); + getHandleInternal(handle)->clear(); + return handle; + } + + + void freeHandle(int handle) + { + b3Assert(handle >= 0); + + if (m_bodyHandles[handle].getNextFree()==B3_POOL_HANDLE_TERMINAL_USED) + { + getHandleInternal(handle)->clear(); + getHandleInternal(handle)->setNextFree(m_firstFreeHandle); + m_firstFreeHandle = handle; + m_numUsedHandles--; + } + } +}; + ///end handle management + + #endif //B3_RESIZABLE_POOL_H + \ No newline at end of file diff --git a/extern/bullet/src/Bullet3Common/b3Scalar.h b/extern/bullet/src/Bullet3Common/b3Scalar.h new file mode 100644 index 000000000000..dbc7fea397d8 --- /dev/null +++ b/extern/bullet/src/Bullet3Common/b3Scalar.h @@ -0,0 +1,663 @@ +/* +Copyright (c) 2003-2013 Gino van den Bergen / Erwin Coumans http://bulletphysics.org + +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 B3_SCALAR_H +#define B3_SCALAR_H + +#ifdef B3_MANAGED_CODE +//Aligned data types not supported in managed code +#pragma unmanaged +#endif + + + +#include +#include //size_t for MSVC 6.0 +#include + +//Original repository is at http://github.com/erwincoumans/bullet3 +#define B3_BULLET_VERSION 300 + +inline int b3GetVersion() +{ + return B3_BULLET_VERSION; +} + +#if defined(DEBUG) || defined (_DEBUG) +#define B3_DEBUG +#endif + +#include "b3Logging.h"//for b3Error + + +#ifdef _WIN32 + + #if defined(__MINGW32__) || defined(__CYGWIN__) || (defined (_MSC_VER) && _MSC_VER < 1300) + + #define B3_FORCE_INLINE inline + #define B3_ATTRIBUTE_ALIGNED16(a) a + #define B3_ATTRIBUTE_ALIGNED64(a) a + #define B3_ATTRIBUTE_ALIGNED128(a) a + #else + //#define B3_HAS_ALIGNED_ALLOCATOR + #pragma warning(disable : 4324) // disable padding warning +// #pragma warning(disable:4530) // Disable the exception disable but used in MSCV Stl warning. + #pragma warning(disable:4996) //Turn off warnings about deprecated C routines +// #pragma warning(disable:4786) // Disable the "debug name too long" warning + + #define B3_FORCE_INLINE __forceinline + #define B3_ATTRIBUTE_ALIGNED16(a) __declspec(align(16)) a + #define B3_ATTRIBUTE_ALIGNED64(a) __declspec(align(64)) a + #define B3_ATTRIBUTE_ALIGNED128(a) __declspec (align(128)) a + #ifdef _XBOX + #define B3_USE_VMX128 + + #include + #define B3_HAVE_NATIVE_FSEL + #define b3Fsel(a,b,c) __fsel((a),(b),(c)) + #else + +#if (defined (_WIN32) && (_MSC_VER) && _MSC_VER >= 1400) && (!defined (B3_USE_DOUBLE_PRECISION)) + #if (defined (_M_IX86) || defined (_M_X64)) + #define B3_USE_SSE + #ifdef B3_USE_SSE + //B3_USE_SSE_IN_API is disabled under Windows by default, because + //it makes it harder to integrate Bullet into your application under Windows + //(structured embedding Bullet structs/classes need to be 16-byte aligned) + //with relatively little performance gain + //If you are not embedded Bullet data in your classes, or make sure that you align those classes on 16-byte boundaries + //you can manually enable this line or set it in the build system for a bit of performance gain (a few percent, dependent on usage) + //#define B3_USE_SSE_IN_API + #endif //B3_USE_SSE + #include + #endif +#endif + + #endif//_XBOX + + #endif //__MINGW32__ + +#ifdef B3_DEBUG + #ifdef _MSC_VER + #include + #define b3Assert(x) { if(!(x)){b3Error("Assert "__FILE__ ":%u ("#x")\n", __LINE__);__debugbreak(); }} + #else//_MSC_VER + #include + #define b3Assert assert + #endif//_MSC_VER +#else + #define b3Assert(x) +#endif + //b3FullAssert is optional, slows down a lot + #define b3FullAssert(x) + + #define b3Likely(_c) _c + #define b3Unlikely(_c) _c + +#else + +#if defined (__CELLOS_LV2__) + #define B3_FORCE_INLINE inline __attribute__((always_inline)) + #define B3_ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16))) + #define B3_ATTRIBUTE_ALIGNED64(a) a __attribute__ ((aligned (64))) + #define B3_ATTRIBUTE_ALIGNED128(a) a __attribute__ ((aligned (128))) + #ifndef assert + #include + #endif +#ifdef B3_DEBUG +#ifdef __SPU__ +#include +#define printf spu_printf + #define b3Assert(x) {if(!(x)){b3Error("Assert "__FILE__ ":%u ("#x")\n", __LINE__);spu_hcmpeq(0,0);}} +#else + #define b3Assert assert +#endif + +#else + #define b3Assert(x) +#endif + //b3FullAssert is optional, slows down a lot + #define b3FullAssert(x) + + #define b3Likely(_c) _c + #define b3Unlikely(_c) _c + +#else + +#ifdef USE_LIBSPE2 + + #define B3_FORCE_INLINE __inline + #define B3_ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16))) + #define B3_ATTRIBUTE_ALIGNED64(a) a __attribute__ ((aligned (64))) + #define B3_ATTRIBUTE_ALIGNED128(a) a __attribute__ ((aligned (128))) + #ifndef assert + #include + #endif +#ifdef B3_DEBUG + #define b3Assert assert +#else + #define b3Assert(x) +#endif + //b3FullAssert is optional, slows down a lot + #define b3FullAssert(x) + + + #define b3Likely(_c) __builtin_expect((_c), 1) + #define b3Unlikely(_c) __builtin_expect((_c), 0) + + +#else + //non-windows systems + +#if (defined (__APPLE__) && (!defined (B3_USE_DOUBLE_PRECISION))) + #if defined (__i386__) || defined (__x86_64__) + #define B3_USE_SSE + //B3_USE_SSE_IN_API is enabled on Mac OSX by default, because memory is automatically aligned on 16-byte boundaries + //if apps run into issues, we will disable the next line + #define B3_USE_SSE_IN_API + #ifdef B3_USE_SSE + // include appropriate SSE level + #if defined (__SSE4_1__) + #include + #elif defined (__SSSE3__) + #include + #elif defined (__SSE3__) + #include + #else + #include + #endif + #endif //B3_USE_SSE + #elif defined( __armv7__ ) + #ifdef __clang__ + #define B3_USE_NEON 1 + + #if defined B3_USE_NEON && defined (__clang__) + #include + #endif//B3_USE_NEON + #endif //__clang__ + #endif//__arm__ + + #define B3_FORCE_INLINE inline __attribute__ ((always_inline)) +///@todo: check out alignment methods for other platforms/compilers + #define B3_ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16))) + #define B3_ATTRIBUTE_ALIGNED64(a) a __attribute__ ((aligned (64))) + #define B3_ATTRIBUTE_ALIGNED128(a) a __attribute__ ((aligned (128))) + #ifndef assert + #include + #endif + + #if defined(DEBUG) || defined (_DEBUG) + #if defined (__i386__) || defined (__x86_64__) + #include + #define b3Assert(x)\ + {\ + if(!(x))\ + {\ + b3Error("Assert %s in line %d, file %s\n",#x, __LINE__, __FILE__);\ + asm volatile ("int3");\ + }\ + } + #else//defined (__i386__) || defined (__x86_64__) + #define b3Assert assert + #endif//defined (__i386__) || defined (__x86_64__) + #else//defined(DEBUG) || defined (_DEBUG) + #define b3Assert(x) + #endif//defined(DEBUG) || defined (_DEBUG) + + //b3FullAssert is optional, slows down a lot + #define b3FullAssert(x) + #define b3Likely(_c) _c + #define b3Unlikely(_c) _c + +#else + + #define B3_FORCE_INLINE inline + ///@todo: check out alignment methods for other platforms/compilers + #define B3_ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16))) + #define B3_ATTRIBUTE_ALIGNED64(a) a __attribute__ ((aligned (64))) + #define B3_ATTRIBUTE_ALIGNED128(a) a __attribute__ ((aligned (128))) + ///#define B3_ATTRIBUTE_ALIGNED16(a) a + ///#define B3_ATTRIBUTE_ALIGNED64(a) a + ///#define B3_ATTRIBUTE_ALIGNED128(a) a + #ifndef assert + #include + #endif + +#if defined(DEBUG) || defined (_DEBUG) + #define b3Assert assert +#else + #define b3Assert(x) +#endif + + //b3FullAssert is optional, slows down a lot + #define b3FullAssert(x) + #define b3Likely(_c) _c + #define b3Unlikely(_c) _c +#endif //__APPLE__ + +#endif // LIBSPE2 + +#endif //__CELLOS_LV2__ +#endif + + +///The b3Scalar type abstracts floating point numbers, to easily switch between double and single floating point precision. +#if defined(B3_USE_DOUBLE_PRECISION) +typedef double b3Scalar; +//this number could be bigger in double precision +#define B3_LARGE_FLOAT 1e30 +#else +typedef float b3Scalar; +//keep B3_LARGE_FLOAT*B3_LARGE_FLOAT < FLT_MAX +#define B3_LARGE_FLOAT 1e18f +#endif + +#ifdef B3_USE_SSE +typedef __m128 b3SimdFloat4; +#endif//B3_USE_SSE + +#if defined B3_USE_SSE_IN_API && defined (B3_USE_SSE) +#ifdef _WIN32 + +#ifndef B3_NAN +static int b3NanMask = 0x7F800001; +#define B3_NAN (*(float*)&b3NanMask) +#endif + +#ifndef B3_INFINITY_MASK +static int b3InfinityMask = 0x7F800000; +#define B3_INFINITY_MASK (*(float*)&b3InfinityMask) +#endif + +inline __m128 operator + (const __m128 A, const __m128 B) +{ + return _mm_add_ps(A, B); +} + +inline __m128 operator - (const __m128 A, const __m128 B) +{ + return _mm_sub_ps(A, B); +} + +inline __m128 operator * (const __m128 A, const __m128 B) +{ + return _mm_mul_ps(A, B); +} + +#define b3CastfTo128i(a) (_mm_castps_si128(a)) +#define b3CastfTo128d(a) (_mm_castps_pd(a)) +#define b3CastiTo128f(a) (_mm_castsi128_ps(a)) +#define b3CastdTo128f(a) (_mm_castpd_ps(a)) +#define b3CastdTo128i(a) (_mm_castpd_si128(a)) +#define b3Assign128(r0,r1,r2,r3) _mm_setr_ps(r0,r1,r2,r3) + +#else//_WIN32 + +#define b3CastfTo128i(a) ((__m128i)(a)) +#define b3CastfTo128d(a) ((__m128d)(a)) +#define b3CastiTo128f(a) ((__m128) (a)) +#define b3CastdTo128f(a) ((__m128) (a)) +#define b3CastdTo128i(a) ((__m128i)(a)) +#define b3Assign128(r0,r1,r2,r3) (__m128){r0,r1,r2,r3} +#endif//_WIN32 +#endif //B3_USE_SSE_IN_API + +#ifdef B3_USE_NEON +#include + +typedef float32x4_t b3SimdFloat4; +#define B3_INFINITY INFINITY +#define B3_NAN NAN +#define b3Assign128(r0,r1,r2,r3) (float32x4_t){r0,r1,r2,r3} +#endif + + + + + +#define B3_DECLARE_ALIGNED_ALLOCATOR() \ + B3_FORCE_INLINE void* operator new(size_t sizeInBytes) { return b3AlignedAlloc(sizeInBytes,16); } \ + B3_FORCE_INLINE void operator delete(void* ptr) { b3AlignedFree(ptr); } \ + B3_FORCE_INLINE void* operator new(size_t, void* ptr) { return ptr; } \ + B3_FORCE_INLINE void operator delete(void*, void*) { } \ + B3_FORCE_INLINE void* operator new[](size_t sizeInBytes) { return b3AlignedAlloc(sizeInBytes,16); } \ + B3_FORCE_INLINE void operator delete[](void* ptr) { b3AlignedFree(ptr); } \ + B3_FORCE_INLINE void* operator new[](size_t, void* ptr) { return ptr; } \ + B3_FORCE_INLINE void operator delete[](void*, void*) { } \ + + + +#if defined(B3_USE_DOUBLE_PRECISION) || defined(B3_FORCE_DOUBLE_FUNCTIONS) + +B3_FORCE_INLINE b3Scalar b3Sqrt(b3Scalar x) { return sqrt(x); } +B3_FORCE_INLINE b3Scalar b3Fabs(b3Scalar x) { return fabs(x); } +B3_FORCE_INLINE b3Scalar b3Cos(b3Scalar x) { return cos(x); } +B3_FORCE_INLINE b3Scalar b3Sin(b3Scalar x) { return sin(x); } +B3_FORCE_INLINE b3Scalar b3Tan(b3Scalar x) { return tan(x); } +B3_FORCE_INLINE b3Scalar b3Acos(b3Scalar x) { if (xb3Scalar(1)) x=b3Scalar(1); return acos(x); } +B3_FORCE_INLINE b3Scalar b3Asin(b3Scalar x) { if (xb3Scalar(1)) x=b3Scalar(1); return asin(x); } +B3_FORCE_INLINE b3Scalar b3Atan(b3Scalar x) { return atan(x); } +B3_FORCE_INLINE b3Scalar b3Atan2(b3Scalar x, b3Scalar y) { return atan2(x, y); } +B3_FORCE_INLINE b3Scalar b3Exp(b3Scalar x) { return exp(x); } +B3_FORCE_INLINE b3Scalar b3Log(b3Scalar x) { return log(x); } +B3_FORCE_INLINE b3Scalar b3Pow(b3Scalar x,b3Scalar y) { return pow(x,y); } +B3_FORCE_INLINE b3Scalar b3Fmod(b3Scalar x,b3Scalar y) { return fmod(x,y); } + +#else + +B3_FORCE_INLINE b3Scalar b3Sqrt(b3Scalar y) +{ +#ifdef USE_APPROXIMATION + double x, z, tempf; + unsigned long *tfptr = ((unsigned long *)&tempf) + 1; + + tempf = y; + *tfptr = (0xbfcdd90a - *tfptr)>>1; /* estimate of 1/sqrt(y) */ + x = tempf; + z = y*b3Scalar(0.5); + x = (b3Scalar(1.5)*x)-(x*x)*(x*z); /* iteration formula */ + x = (b3Scalar(1.5)*x)-(x*x)*(x*z); + x = (b3Scalar(1.5)*x)-(x*x)*(x*z); + x = (b3Scalar(1.5)*x)-(x*x)*(x*z); + x = (b3Scalar(1.5)*x)-(x*x)*(x*z); + return x*y; +#else + return sqrtf(y); +#endif +} +B3_FORCE_INLINE b3Scalar b3Fabs(b3Scalar x) { return fabsf(x); } +B3_FORCE_INLINE b3Scalar b3Cos(b3Scalar x) { return cosf(x); } +B3_FORCE_INLINE b3Scalar b3Sin(b3Scalar x) { return sinf(x); } +B3_FORCE_INLINE b3Scalar b3Tan(b3Scalar x) { return tanf(x); } +B3_FORCE_INLINE b3Scalar b3Acos(b3Scalar x) { + if (xb3Scalar(1)) + x=b3Scalar(1); + return acosf(x); +} +B3_FORCE_INLINE b3Scalar b3Asin(b3Scalar x) { + if (xb3Scalar(1)) + x=b3Scalar(1); + return asinf(x); +} +B3_FORCE_INLINE b3Scalar b3Atan(b3Scalar x) { return atanf(x); } +B3_FORCE_INLINE b3Scalar b3Atan2(b3Scalar x, b3Scalar y) { return atan2f(x, y); } +B3_FORCE_INLINE b3Scalar b3Exp(b3Scalar x) { return expf(x); } +B3_FORCE_INLINE b3Scalar b3Log(b3Scalar x) { return logf(x); } +B3_FORCE_INLINE b3Scalar b3Pow(b3Scalar x,b3Scalar y) { return powf(x,y); } +B3_FORCE_INLINE b3Scalar b3Fmod(b3Scalar x,b3Scalar y) { return fmodf(x,y); } + +#endif + +#define B3_2_PI b3Scalar(6.283185307179586232) +#define B3_PI (B3_2_PI * b3Scalar(0.5)) +#define B3_HALF_PI (B3_2_PI * b3Scalar(0.25)) +#define B3_RADS_PER_DEG (B3_2_PI / b3Scalar(360.0)) +#define B3_DEGS_PER_RAD (b3Scalar(360.0) / B3_2_PI) +#define B3_SQRT12 b3Scalar(0.7071067811865475244008443621048490) + +#define b3RecipSqrt(x) ((b3Scalar)(b3Scalar(1.0)/b3Sqrt(b3Scalar(x)))) /* reciprocal square root */ + + +#ifdef B3_USE_DOUBLE_PRECISION +#define B3_EPSILON DBL_EPSILON +#define B3_INFINITY DBL_MAX +#else +#define B3_EPSILON FLT_EPSILON +#define B3_INFINITY FLT_MAX +#endif + +B3_FORCE_INLINE b3Scalar b3Atan2Fast(b3Scalar y, b3Scalar x) +{ + b3Scalar coeff_1 = B3_PI / 4.0f; + b3Scalar coeff_2 = 3.0f * coeff_1; + b3Scalar abs_y = b3Fabs(y); + b3Scalar angle; + if (x >= 0.0f) { + b3Scalar r = (x - abs_y) / (x + abs_y); + angle = coeff_1 - coeff_1 * r; + } else { + b3Scalar r = (x + abs_y) / (abs_y - x); + angle = coeff_2 - coeff_1 * r; + } + return (y < 0.0f) ? -angle : angle; +} + +B3_FORCE_INLINE bool b3FuzzyZero(b3Scalar x) { return b3Fabs(x) < B3_EPSILON; } + +B3_FORCE_INLINE bool b3Equal(b3Scalar a, b3Scalar eps) { + return (((a) <= eps) && !((a) < -eps)); +} +B3_FORCE_INLINE bool b3GreaterEqual (b3Scalar a, b3Scalar eps) { + return (!((a) <= eps)); +} + + +B3_FORCE_INLINE int b3IsNegative(b3Scalar x) { + return x < b3Scalar(0.0) ? 1 : 0; +} + +B3_FORCE_INLINE b3Scalar b3Radians(b3Scalar x) { return x * B3_RADS_PER_DEG; } +B3_FORCE_INLINE b3Scalar b3Degrees(b3Scalar x) { return x * B3_DEGS_PER_RAD; } + +#define B3_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name + +#ifndef b3Fsel +B3_FORCE_INLINE b3Scalar b3Fsel(b3Scalar a, b3Scalar b, b3Scalar c) +{ + return a >= 0 ? b : c; +} +#endif +#define b3Fsels(a,b,c) (b3Scalar)b3Fsel(a,b,c) + + +B3_FORCE_INLINE bool b3MachineIsLittleEndian() +{ + long int i = 1; + const char *p = (const char *) &i; + if (p[0] == 1) // Lowest address contains the least significant byte + return true; + else + return false; +} + + + +///b3Select avoids branches, which makes performance much better for consoles like Playstation 3 and XBox 360 +///Thanks Phil Knight. See also http://www.cellperformance.com/articles/2006/04/more_techniques_for_eliminatin_1.html +B3_FORCE_INLINE unsigned b3Select(unsigned condition, unsigned valueIfConditionNonZero, unsigned valueIfConditionZero) +{ + // Set testNz to 0xFFFFFFFF if condition is nonzero, 0x00000000 if condition is zero + // Rely on positive value or'ed with its negative having sign bit on + // and zero value or'ed with its negative (which is still zero) having sign bit off + // Use arithmetic shift right, shifting the sign bit through all 32 bits + unsigned testNz = (unsigned)(((int)condition | -(int)condition) >> 31); + unsigned testEqz = ~testNz; + return ((valueIfConditionNonZero & testNz) | (valueIfConditionZero & testEqz)); +} +B3_FORCE_INLINE int b3Select(unsigned condition, int valueIfConditionNonZero, int valueIfConditionZero) +{ + unsigned testNz = (unsigned)(((int)condition | -(int)condition) >> 31); + unsigned testEqz = ~testNz; + return static_cast((valueIfConditionNonZero & testNz) | (valueIfConditionZero & testEqz)); +} +B3_FORCE_INLINE float b3Select(unsigned condition, float valueIfConditionNonZero, float valueIfConditionZero) +{ +#ifdef B3_HAVE_NATIVE_FSEL + return (float)b3Fsel((b3Scalar)condition - b3Scalar(1.0f), valueIfConditionNonZero, valueIfConditionZero); +#else + return (condition != 0) ? valueIfConditionNonZero : valueIfConditionZero; +#endif +} + +template B3_FORCE_INLINE void b3Swap(T& a, T& b) +{ + T tmp = a; + a = b; + b = tmp; +} + + +//PCK: endian swapping functions +B3_FORCE_INLINE unsigned b3SwapEndian(unsigned val) +{ + return (((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); +} + +B3_FORCE_INLINE unsigned short b3SwapEndian(unsigned short val) +{ + return static_cast(((val & 0xff00) >> 8) | ((val & 0x00ff) << 8)); +} + +B3_FORCE_INLINE unsigned b3SwapEndian(int val) +{ + return b3SwapEndian((unsigned)val); +} + +B3_FORCE_INLINE unsigned short b3SwapEndian(short val) +{ + return b3SwapEndian((unsigned short) val); +} + +///b3SwapFloat uses using char pointers to swap the endianness +////b3SwapFloat/b3SwapDouble will NOT return a float, because the machine might 'correct' invalid floating point values +///Not all values of sign/exponent/mantissa are valid floating point numbers according to IEEE 754. +///When a floating point unit is faced with an invalid value, it may actually change the value, or worse, throw an exception. +///In most systems, running user mode code, you wouldn't get an exception, but instead the hardware/os/runtime will 'fix' the number for you. +///so instead of returning a float/double, we return integer/long long integer +B3_FORCE_INLINE unsigned int b3SwapEndianFloat(float d) +{ + unsigned int a = 0; + unsigned char *dst = (unsigned char *)&a; + unsigned char *src = (unsigned char *)&d; + + dst[0] = src[3]; + dst[1] = src[2]; + dst[2] = src[1]; + dst[3] = src[0]; + return a; +} + +// unswap using char pointers +B3_FORCE_INLINE float b3UnswapEndianFloat(unsigned int a) +{ + float d = 0.0f; + unsigned char *src = (unsigned char *)&a; + unsigned char *dst = (unsigned char *)&d; + + dst[0] = src[3]; + dst[1] = src[2]; + dst[2] = src[1]; + dst[3] = src[0]; + + return d; +} + + +// swap using char pointers +B3_FORCE_INLINE void b3SwapEndianDouble(double d, unsigned char* dst) +{ + unsigned char *src = (unsigned char *)&d; + + dst[0] = src[7]; + dst[1] = src[6]; + dst[2] = src[5]; + dst[3] = src[4]; + dst[4] = src[3]; + dst[5] = src[2]; + dst[6] = src[1]; + dst[7] = src[0]; + +} + +// unswap using char pointers +B3_FORCE_INLINE double b3UnswapEndianDouble(const unsigned char *src) +{ + double d = 0.0; + unsigned char *dst = (unsigned char *)&d; + + dst[0] = src[7]; + dst[1] = src[6]; + dst[2] = src[5]; + dst[3] = src[4]; + dst[4] = src[3]; + dst[5] = src[2]; + dst[6] = src[1]; + dst[7] = src[0]; + + return d; +} + +// returns normalized value in range [-B3_PI, B3_PI] +B3_FORCE_INLINE b3Scalar b3NormalizeAngle(b3Scalar angleInRadians) +{ + angleInRadians = b3Fmod(angleInRadians, B3_2_PI); + if(angleInRadians < -B3_PI) + { + return angleInRadians + B3_2_PI; + } + else if(angleInRadians > B3_PI) + { + return angleInRadians - B3_2_PI; + } + else + { + return angleInRadians; + } +} + +///rudimentary class to provide type info +struct b3TypedObject +{ + b3TypedObject(int objectType) + :m_objectType(objectType) + { + } + int m_objectType; + inline int getObjectType() const + { + return m_objectType; + } +}; + + + +///align a pointer to the provided alignment, upwards +template T* b3AlignPointer(T* unalignedPtr, size_t alignment) +{ + + struct b3ConvertPointerSizeT + { + union + { + T* ptr; + size_t integer; + }; + }; + b3ConvertPointerSizeT converter; + + + const size_t bit_mask = ~(alignment - 1); + converter.ptr = unalignedPtr; + converter.integer += alignment-1; + converter.integer &= bit_mask; + return converter.ptr; +} + +#endif //B3_SCALAR_H diff --git a/extern/bullet/src/Bullet3Common/b3StackAlloc.h b/extern/bullet/src/Bullet3Common/b3StackAlloc.h new file mode 100644 index 000000000000..de7de056b507 --- /dev/null +++ b/extern/bullet/src/Bullet3Common/b3StackAlloc.h @@ -0,0 +1,116 @@ +/* +Copyright (c) 2003-2013 Gino van den Bergen / Erwin Coumans http://bulletphysics.org + +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 B3_STACK_ALLOC +#define B3_STACK_ALLOC + +#include "b3Scalar.h" //for b3Assert +#include "b3AlignedAllocator.h" + +///The b3Block class is an internal structure for the b3StackAlloc memory allocator. +struct b3Block +{ + b3Block* previous; + unsigned char* address; +}; + +///The StackAlloc class provides some fast stack-based memory allocator (LIFO last-in first-out) +class b3StackAlloc +{ +public: + + b3StackAlloc(unsigned int size) { ctor();create(size); } + ~b3StackAlloc() { destroy(); } + + inline void create(unsigned int size) + { + destroy(); + data = (unsigned char*) b3AlignedAlloc(size,16); + totalsize = size; + } + inline void destroy() + { + b3Assert(usedsize==0); + //Raise(L"StackAlloc is still in use"); + + if(usedsize==0) + { + if(!ischild && data) + b3AlignedFree(data); + + data = 0; + usedsize = 0; + } + + } + + int getAvailableMemory() const + { + return static_cast(totalsize - usedsize); + } + + unsigned char* allocate(unsigned int size) + { + const unsigned int nus(usedsize+size); + if(nusprevious = current; + pb->address = data+usedsize; + current = pb; + return(pb); + } + B3_FORCE_INLINE void endBlock(b3Block* block) + { + b3Assert(block==current); + //Raise(L"Unmatched blocks"); + if(block==current) + { + current = block->previous; + usedsize = (unsigned int)((block->address-data)-sizeof(b3Block)); + } + } + +private: + void ctor() + { + data = 0; + totalsize = 0; + usedsize = 0; + current = 0; + ischild = false; + } + unsigned char* data; + unsigned int totalsize; + unsigned int usedsize; + b3Block* current; + bool ischild; +}; + +#endif //B3_STACK_ALLOC diff --git a/extern/bullet/src/Bullet3Common/b3Transform.h b/extern/bullet/src/Bullet3Common/b3Transform.h new file mode 100644 index 000000000000..fa480759bebd --- /dev/null +++ b/extern/bullet/src/Bullet3Common/b3Transform.h @@ -0,0 +1,304 @@ +/* +Copyright (c) 2003-2013 Gino van den Bergen / Erwin Coumans http://bulletphysics.org + +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 B3_TRANSFORM_H +#define B3_TRANSFORM_H + + +#include "b3Matrix3x3.h" + +#ifdef B3_USE_DOUBLE_PRECISION +#define b3TransformData b3TransformDoubleData +#else +#define b3TransformData b3TransformFloatData +#endif + + + + +/**@brief The b3Transform class supports rigid transforms with only translation and rotation and no scaling/shear. + *It can be used in combination with b3Vector3, b3Quaternion and b3Matrix3x3 linear algebra classes. */ +B3_ATTRIBUTE_ALIGNED16(class) b3Transform { + + ///Storage for the rotation + b3Matrix3x3 m_basis; + ///Storage for the translation + b3Vector3 m_origin; + +public: + + /**@brief No initialization constructor */ + b3Transform() {} + /**@brief Constructor from b3Quaternion (optional b3Vector3 ) + * @param q Rotation from quaternion + * @param c Translation from Vector (default 0,0,0) */ + explicit B3_FORCE_INLINE b3Transform(const b3Quaternion& q, + const b3Vector3& c = b3MakeVector3(b3Scalar(0), b3Scalar(0), b3Scalar(0))) + : m_basis(q), + m_origin(c) + {} + + /**@brief Constructor from b3Matrix3x3 (optional b3Vector3) + * @param b Rotation from Matrix + * @param c Translation from Vector default (0,0,0)*/ + explicit B3_FORCE_INLINE b3Transform(const b3Matrix3x3& b, + const b3Vector3& c = b3MakeVector3(b3Scalar(0), b3Scalar(0), b3Scalar(0))) + : m_basis(b), + m_origin(c) + {} + /**@brief Copy constructor */ + B3_FORCE_INLINE b3Transform (const b3Transform& other) + : m_basis(other.m_basis), + m_origin(other.m_origin) + { + } + /**@brief Assignment Operator */ + B3_FORCE_INLINE b3Transform& operator=(const b3Transform& other) + { + m_basis = other.m_basis; + m_origin = other.m_origin; + return *this; + } + + + /**@brief Set the current transform as the value of the product of two transforms + * @param t1 Transform 1 + * @param t2 Transform 2 + * This = Transform1 * Transform2 */ + B3_FORCE_INLINE void mult(const b3Transform& t1, const b3Transform& t2) { + m_basis = t1.m_basis * t2.m_basis; + m_origin = t1(t2.m_origin); + } + +/* void multInverseLeft(const b3Transform& t1, const b3Transform& t2) { + b3Vector3 v = t2.m_origin - t1.m_origin; + m_basis = b3MultTransposeLeft(t1.m_basis, t2.m_basis); + m_origin = v * t1.m_basis; + } + */ + +/**@brief Return the transform of the vector */ + B3_FORCE_INLINE b3Vector3 operator()(const b3Vector3& x) const + { + return x.dot3(m_basis[0], m_basis[1], m_basis[2]) + m_origin; + } + + /**@brief Return the transform of the vector */ + B3_FORCE_INLINE b3Vector3 operator*(const b3Vector3& x) const + { + return (*this)(x); + } + + /**@brief Return the transform of the b3Quaternion */ + B3_FORCE_INLINE b3Quaternion operator*(const b3Quaternion& q) const + { + return getRotation() * q; + } + + /**@brief Return the basis matrix for the rotation */ + B3_FORCE_INLINE b3Matrix3x3& getBasis() { return m_basis; } + /**@brief Return the basis matrix for the rotation */ + B3_FORCE_INLINE const b3Matrix3x3& getBasis() const { return m_basis; } + + /**@brief Return the origin vector translation */ + B3_FORCE_INLINE b3Vector3& getOrigin() { return m_origin; } + /**@brief Return the origin vector translation */ + B3_FORCE_INLINE const b3Vector3& getOrigin() const { return m_origin; } + + /**@brief Return a quaternion representing the rotation */ + b3Quaternion getRotation() const { + b3Quaternion q; + m_basis.getRotation(q); + return q; + } + + + /**@brief Set from an array + * @param m A pointer to a 15 element array (12 rotation(row major padded on the right by 1), and 3 translation */ + void setFromOpenGLMatrix(const b3Scalar *m) + { + m_basis.setFromOpenGLSubMatrix(m); + m_origin.setValue(m[12],m[13],m[14]); + } + + /**@brief Fill an array representation + * @param m A pointer to a 15 element array (12 rotation(row major padded on the right by 1), and 3 translation */ + void getOpenGLMatrix(b3Scalar *m) const + { + m_basis.getOpenGLSubMatrix(m); + m[12] = m_origin.getX(); + m[13] = m_origin.getY(); + m[14] = m_origin.getZ(); + m[15] = b3Scalar(1.0); + } + + /**@brief Set the translational element + * @param origin The vector to set the translation to */ + B3_FORCE_INLINE void setOrigin(const b3Vector3& origin) + { + m_origin = origin; + } + + B3_FORCE_INLINE b3Vector3 invXform(const b3Vector3& inVec) const; + + + /**@brief Set the rotational element by b3Matrix3x3 */ + B3_FORCE_INLINE void setBasis(const b3Matrix3x3& basis) + { + m_basis = basis; + } + + /**@brief Set the rotational element by b3Quaternion */ + B3_FORCE_INLINE void setRotation(const b3Quaternion& q) + { + m_basis.setRotation(q); + } + + + /**@brief Set this transformation to the identity */ + void setIdentity() + { + m_basis.setIdentity(); + m_origin.setValue(b3Scalar(0.0), b3Scalar(0.0), b3Scalar(0.0)); + } + + /**@brief Multiply this Transform by another(this = this * another) + * @param t The other transform */ + b3Transform& operator*=(const b3Transform& t) + { + m_origin += m_basis * t.m_origin; + m_basis *= t.m_basis; + return *this; + } + + /**@brief Return the inverse of this transform */ + b3Transform inverse() const + { + b3Matrix3x3 inv = m_basis.transpose(); + return b3Transform(inv, inv * -m_origin); + } + + /**@brief Return the inverse of this transform times the other transform + * @param t The other transform + * return this.inverse() * the other */ + b3Transform inverseTimes(const b3Transform& t) const; + + /**@brief Return the product of this transform and the other */ + b3Transform operator*(const b3Transform& t) const; + + /**@brief Return an identity transform */ + static const b3Transform& getIdentity() + { + static const b3Transform identityTransform(b3Matrix3x3::getIdentity()); + return identityTransform; + } + + void serialize(struct b3TransformData& dataOut) const; + + void serializeFloat(struct b3TransformFloatData& dataOut) const; + + void deSerialize(const struct b3TransformData& dataIn); + + void deSerializeDouble(const struct b3TransformDoubleData& dataIn); + + void deSerializeFloat(const struct b3TransformFloatData& dataIn); + +}; + + +B3_FORCE_INLINE b3Vector3 +b3Transform::invXform(const b3Vector3& inVec) const +{ + b3Vector3 v = inVec - m_origin; + return (m_basis.transpose() * v); +} + +B3_FORCE_INLINE b3Transform +b3Transform::inverseTimes(const b3Transform& t) const +{ + b3Vector3 v = t.getOrigin() - m_origin; + return b3Transform(m_basis.transposeTimes(t.m_basis), + v * m_basis); +} + +B3_FORCE_INLINE b3Transform +b3Transform::operator*(const b3Transform& t) const +{ + return b3Transform(m_basis * t.m_basis, + (*this)(t.m_origin)); +} + +/**@brief Test if two transforms have all elements equal */ +B3_FORCE_INLINE bool operator==(const b3Transform& t1, const b3Transform& t2) +{ + return ( t1.getBasis() == t2.getBasis() && + t1.getOrigin() == t2.getOrigin() ); +} + + +///for serialization +struct b3TransformFloatData +{ + b3Matrix3x3FloatData m_basis; + b3Vector3FloatData m_origin; +}; + +struct b3TransformDoubleData +{ + b3Matrix3x3DoubleData m_basis; + b3Vector3DoubleData m_origin; +}; + + + +B3_FORCE_INLINE void b3Transform::serialize(b3TransformData& dataOut) const +{ + m_basis.serialize(dataOut.m_basis); + m_origin.serialize(dataOut.m_origin); +} + +B3_FORCE_INLINE void b3Transform::serializeFloat(b3TransformFloatData& dataOut) const +{ + m_basis.serializeFloat(dataOut.m_basis); + m_origin.serializeFloat(dataOut.m_origin); +} + + +B3_FORCE_INLINE void b3Transform::deSerialize(const b3TransformData& dataIn) +{ + m_basis.deSerialize(dataIn.m_basis); + m_origin.deSerialize(dataIn.m_origin); +} + +B3_FORCE_INLINE void b3Transform::deSerializeFloat(const b3TransformFloatData& dataIn) +{ + m_basis.deSerializeFloat(dataIn.m_basis); + m_origin.deSerializeFloat(dataIn.m_origin); +} + +B3_FORCE_INLINE void b3Transform::deSerializeDouble(const b3TransformDoubleData& dataIn) +{ + m_basis.deSerializeDouble(dataIn.m_basis); + m_origin.deSerializeDouble(dataIn.m_origin); +} + + +#endif //B3_TRANSFORM_H + + + + + + diff --git a/extern/bullet/src/Bullet3Common/b3TransformUtil.h b/extern/bullet/src/Bullet3Common/b3TransformUtil.h new file mode 100644 index 000000000000..6ce580c13280 --- /dev/null +++ b/extern/bullet/src/Bullet3Common/b3TransformUtil.h @@ -0,0 +1,228 @@ +/* +Copyright (c) 2003-2013 Gino van den Bergen / Erwin Coumans http://bulletphysics.org + +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 B3_TRANSFORM_UTIL_H +#define B3_TRANSFORM_UTIL_H + +#include "b3Transform.h" +#define B3_ANGULAR_MOTION_THRESHOLD b3Scalar(0.5)*B3_HALF_PI + + + + +B3_FORCE_INLINE b3Vector3 b3AabbSupport(const b3Vector3& halfExtents,const b3Vector3& supportDir) +{ + return b3MakeVector3(supportDir.getX() < b3Scalar(0.0) ? -halfExtents.getX() : halfExtents.getX(), + supportDir.getY() < b3Scalar(0.0) ? -halfExtents.getY() : halfExtents.getY(), + supportDir.getZ() < b3Scalar(0.0) ? -halfExtents.getZ() : halfExtents.getZ()); +} + + + + + + +/// Utils related to temporal transforms +class b3TransformUtil +{ + +public: + + static void integrateTransform(const b3Transform& curTrans,const b3Vector3& linvel,const b3Vector3& angvel,b3Scalar timeStep,b3Transform& predictedTransform) + { + predictedTransform.setOrigin(curTrans.getOrigin() + linvel * timeStep); +// #define QUATERNION_DERIVATIVE + #ifdef QUATERNION_DERIVATIVE + b3Quaternion predictedOrn = curTrans.getRotation(); + predictedOrn += (angvel * predictedOrn) * (timeStep * b3Scalar(0.5)); + predictedOrn.normalize(); + #else + //Exponential map + //google for "Practical Parameterization of Rotations Using the Exponential Map", F. Sebastian Grassia + + b3Vector3 axis; + b3Scalar fAngle = angvel.length(); + //limit the angular motion + if (fAngle*timeStep > B3_ANGULAR_MOTION_THRESHOLD) + { + fAngle = B3_ANGULAR_MOTION_THRESHOLD / timeStep; + } + + if ( fAngle < b3Scalar(0.001) ) + { + // use Taylor's expansions of sync function + axis = angvel*( b3Scalar(0.5)*timeStep-(timeStep*timeStep*timeStep)*(b3Scalar(0.020833333333))*fAngle*fAngle ); + } + else + { + // sync(fAngle) = sin(c*fAngle)/t + axis = angvel*( b3Sin(b3Scalar(0.5)*fAngle*timeStep)/fAngle ); + } + b3Quaternion dorn (axis.getX(),axis.getY(),axis.getZ(),b3Cos( fAngle*timeStep*b3Scalar(0.5) )); + b3Quaternion orn0 = curTrans.getRotation(); + + b3Quaternion predictedOrn = dorn * orn0; + predictedOrn.normalize(); + #endif + predictedTransform.setRotation(predictedOrn); + } + + static void calculateVelocityQuaternion(const b3Vector3& pos0,const b3Vector3& pos1,const b3Quaternion& orn0,const b3Quaternion& orn1,b3Scalar timeStep,b3Vector3& linVel,b3Vector3& angVel) + { + linVel = (pos1 - pos0) / timeStep; + b3Vector3 axis; + b3Scalar angle; + if (orn0 != orn1) + { + calculateDiffAxisAngleQuaternion(orn0,orn1,axis,angle); + angVel = axis * angle / timeStep; + } else + { + angVel.setValue(0,0,0); + } + } + + static void calculateDiffAxisAngleQuaternion(const b3Quaternion& orn0,const b3Quaternion& orn1a,b3Vector3& axis,b3Scalar& angle) + { + b3Quaternion orn1 = orn0.nearest(orn1a); + b3Quaternion dorn = orn1 * orn0.inverse(); + angle = dorn.getAngle(); + axis = b3MakeVector3(dorn.getX(),dorn.getY(),dorn.getZ()); + axis[3] = b3Scalar(0.); + //check for axis length + b3Scalar len = axis.length2(); + if (len < B3_EPSILON*B3_EPSILON) + axis = b3MakeVector3(b3Scalar(1.),b3Scalar(0.),b3Scalar(0.)); + else + axis /= b3Sqrt(len); + } + + static void calculateVelocity(const b3Transform& transform0,const b3Transform& transform1,b3Scalar timeStep,b3Vector3& linVel,b3Vector3& angVel) + { + linVel = (transform1.getOrigin() - transform0.getOrigin()) / timeStep; + b3Vector3 axis; + b3Scalar angle; + calculateDiffAxisAngle(transform0,transform1,axis,angle); + angVel = axis * angle / timeStep; + } + + static void calculateDiffAxisAngle(const b3Transform& transform0,const b3Transform& transform1,b3Vector3& axis,b3Scalar& angle) + { + b3Matrix3x3 dmat = transform1.getBasis() * transform0.getBasis().inverse(); + b3Quaternion dorn; + dmat.getRotation(dorn); + + ///floating point inaccuracy can lead to w component > 1..., which breaks + dorn.normalize(); + + angle = dorn.getAngle(); + axis = b3MakeVector3(dorn.getX(),dorn.getY(),dorn.getZ()); + axis[3] = b3Scalar(0.); + //check for axis length + b3Scalar len = axis.length2(); + if (len < B3_EPSILON*B3_EPSILON) + axis = b3MakeVector3(b3Scalar(1.),b3Scalar(0.),b3Scalar(0.)); + else + axis /= b3Sqrt(len); + } + +}; + + +///The b3ConvexSeparatingDistanceUtil can help speed up convex collision detection +///by conservatively updating a cached separating distance/vector instead of re-calculating the closest distance +class b3ConvexSeparatingDistanceUtil +{ + b3Quaternion m_ornA; + b3Quaternion m_ornB; + b3Vector3 m_posA; + b3Vector3 m_posB; + + b3Vector3 m_separatingNormal; + + b3Scalar m_boundingRadiusA; + b3Scalar m_boundingRadiusB; + b3Scalar m_separatingDistance; + +public: + + b3ConvexSeparatingDistanceUtil(b3Scalar boundingRadiusA,b3Scalar boundingRadiusB) + :m_boundingRadiusA(boundingRadiusA), + m_boundingRadiusB(boundingRadiusB), + m_separatingDistance(0.f) + { + } + + b3Scalar getConservativeSeparatingDistance() + { + return m_separatingDistance; + } + + void updateSeparatingDistance(const b3Transform& transA,const b3Transform& transB) + { + const b3Vector3& toPosA = transA.getOrigin(); + const b3Vector3& toPosB = transB.getOrigin(); + b3Quaternion toOrnA = transA.getRotation(); + b3Quaternion toOrnB = transB.getRotation(); + + if (m_separatingDistance>0.f) + { + + + b3Vector3 linVelA,angVelA,linVelB,angVelB; + b3TransformUtil::calculateVelocityQuaternion(m_posA,toPosA,m_ornA,toOrnA,b3Scalar(1.),linVelA,angVelA); + b3TransformUtil::calculateVelocityQuaternion(m_posB,toPosB,m_ornB,toOrnB,b3Scalar(1.),linVelB,angVelB); + b3Scalar maxAngularProjectedVelocity = angVelA.length() * m_boundingRadiusA + angVelB.length() * m_boundingRadiusB; + b3Vector3 relLinVel = (linVelB-linVelA); + b3Scalar relLinVelocLength = relLinVel.dot(m_separatingNormal); + if (relLinVelocLength<0.f) + { + relLinVelocLength = 0.f; + } + + b3Scalar projectedMotion = maxAngularProjectedVelocity +relLinVelocLength; + m_separatingDistance -= projectedMotion; + } + + m_posA = toPosA; + m_posB = toPosB; + m_ornA = toOrnA; + m_ornB = toOrnB; + } + + void initSeparatingDistance(const b3Vector3& separatingVector,b3Scalar separatingDistance,const b3Transform& transA,const b3Transform& transB) + { + m_separatingDistance = separatingDistance; + + if (m_separatingDistance>0.f) + { + m_separatingNormal = separatingVector; + + const b3Vector3& toPosA = transA.getOrigin(); + const b3Vector3& toPosB = transB.getOrigin(); + b3Quaternion toOrnA = transA.getRotation(); + b3Quaternion toOrnB = transB.getRotation(); + m_posA = toPosA; + m_posB = toPosB; + m_ornA = toOrnA; + m_ornB = toOrnB; + } + } + +}; + + +#endif //B3_TRANSFORM_UTIL_H + diff --git a/extern/bullet/src/Bullet3Common/b3Vector3.cpp b/extern/bullet/src/Bullet3Common/b3Vector3.cpp new file mode 100644 index 000000000000..5f5ac4ac0435 --- /dev/null +++ b/extern/bullet/src/Bullet3Common/b3Vector3.cpp @@ -0,0 +1,1631 @@ +/* + Copyright (c) 2011-213 Apple Inc. http://bulletphysics.org + + 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. + + This source version has been altered. + */ + +#if defined (_WIN32) || defined (__i386__) +#define B3_USE_SSE_IN_API +#endif + +#include "b3Vector3.h" + +#if defined (B3_USE_SSE) || defined (B3_USE_NEON) + +#ifdef __APPLE__ +#include +typedef float float4 __attribute__ ((vector_size(16))); +#else +#define float4 __m128 +#endif +//typedef uint32_t uint4 __attribute__ ((vector_size(16))); + + +#if defined B3_USE_SSE || defined _WIN32 + +#define LOG2_ARRAY_SIZE 6 +#define STACK_ARRAY_COUNT (1UL << LOG2_ARRAY_SIZE) + +#include + +long b3_maxdot_large( const float *vv, const float *vec, unsigned long count, float *dotResult ); +long b3_maxdot_large( const float *vv, const float *vec, unsigned long count, float *dotResult ) +{ + const float4 *vertices = (const float4*) vv; + static const unsigned char indexTable[16] = {(unsigned char)-1, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 }; + float4 dotMax = b3Assign128( -B3_INFINITY, -B3_INFINITY, -B3_INFINITY, -B3_INFINITY ); + float4 vvec = _mm_loadu_ps( vec ); + float4 vHi = b3CastiTo128f(_mm_shuffle_epi32( b3CastfTo128i( vvec), 0xaa )); /// zzzz + float4 vLo = _mm_movelh_ps( vvec, vvec ); /// xyxy + + long maxIndex = -1L; + + size_t segment = 0; + float4 stack_array[ STACK_ARRAY_COUNT ]; + +#if DEBUG + // memset( stack_array, -1, STACK_ARRAY_COUNT * sizeof(stack_array[0]) ); +#endif + + size_t index; + float4 max; + // Faster loop without cleanup code for full tiles + for ( segment = 0; segment + STACK_ARRAY_COUNT*4 <= count; segment += STACK_ARRAY_COUNT*4 ) + { + max = dotMax; + + for( index = 0; index < STACK_ARRAY_COUNT; index+= 4 ) + { // do four dot products at a time. Carefully avoid touching the w element. + float4 v0 = vertices[0]; + float4 v1 = vertices[1]; + float4 v2 = vertices[2]; + float4 v3 = vertices[3]; vertices += 4; + + float4 lo0 = _mm_movelh_ps( v0, v1); // x0y0x1y1 + float4 hi0 = _mm_movehl_ps( v1, v0); // z0?0z1?1 + float4 lo1 = _mm_movelh_ps( v2, v3); // x2y2x3y3 + float4 hi1 = _mm_movehl_ps( v3, v2); // z2?2z3?3 + + lo0 = lo0*vLo; + lo1 = lo1*vLo; + float4 z = _mm_shuffle_ps(hi0, hi1, 0x88); + float4 x = _mm_shuffle_ps(lo0, lo1, 0x88); + float4 y = _mm_shuffle_ps(lo0, lo1, 0xdd); + z = z*vHi; + x = x+y; + x = x+z; + stack_array[index] = x; + max = _mm_max_ps( x, max ); // control the order here so that max is never NaN even if x is nan + + v0 = vertices[0]; + v1 = vertices[1]; + v2 = vertices[2]; + v3 = vertices[3]; vertices += 4; + + lo0 = _mm_movelh_ps( v0, v1); // x0y0x1y1 + hi0 = _mm_movehl_ps( v1, v0); // z0?0z1?1 + lo1 = _mm_movelh_ps( v2, v3); // x2y2x3y3 + hi1 = _mm_movehl_ps( v3, v2); // z2?2z3?3 + + lo0 = lo0*vLo; + lo1 = lo1*vLo; + z = _mm_shuffle_ps(hi0, hi1, 0x88); + x = _mm_shuffle_ps(lo0, lo1, 0x88); + y = _mm_shuffle_ps(lo0, lo1, 0xdd); + z = z*vHi; + x = x+y; + x = x+z; + stack_array[index+1] = x; + max = _mm_max_ps( x, max ); // control the order here so that max is never NaN even if x is nan + + v0 = vertices[0]; + v1 = vertices[1]; + v2 = vertices[2]; + v3 = vertices[3]; vertices += 4; + + lo0 = _mm_movelh_ps( v0, v1); // x0y0x1y1 + hi0 = _mm_movehl_ps( v1, v0); // z0?0z1?1 + lo1 = _mm_movelh_ps( v2, v3); // x2y2x3y3 + hi1 = _mm_movehl_ps( v3, v2); // z2?2z3?3 + + lo0 = lo0*vLo; + lo1 = lo1*vLo; + z = _mm_shuffle_ps(hi0, hi1, 0x88); + x = _mm_shuffle_ps(lo0, lo1, 0x88); + y = _mm_shuffle_ps(lo0, lo1, 0xdd); + z = z*vHi; + x = x+y; + x = x+z; + stack_array[index+2] = x; + max = _mm_max_ps( x, max ); // control the order here so that max is never NaN even if x is nan + + v0 = vertices[0]; + v1 = vertices[1]; + v2 = vertices[2]; + v3 = vertices[3]; vertices += 4; + + lo0 = _mm_movelh_ps( v0, v1); // x0y0x1y1 + hi0 = _mm_movehl_ps( v1, v0); // z0?0z1?1 + lo1 = _mm_movelh_ps( v2, v3); // x2y2x3y3 + hi1 = _mm_movehl_ps( v3, v2); // z2?2z3?3 + + lo0 = lo0*vLo; + lo1 = lo1*vLo; + z = _mm_shuffle_ps(hi0, hi1, 0x88); + x = _mm_shuffle_ps(lo0, lo1, 0x88); + y = _mm_shuffle_ps(lo0, lo1, 0xdd); + z = z*vHi; + x = x+y; + x = x+z; + stack_array[index+3] = x; + max = _mm_max_ps( x, max ); // control the order here so that max is never NaN even if x is nan + + // It is too costly to keep the index of the max here. We will look for it again later. We save a lot of work this way. + } + + // If we found a new max + if( 0xf != _mm_movemask_ps( (float4) _mm_cmpeq_ps(max, dotMax))) + { + // copy the new max across all lanes of our max accumulator + max = _mm_max_ps(max, (float4) _mm_shuffle_ps( max, max, 0x4e)); + max = _mm_max_ps(max, (float4) _mm_shuffle_ps( max, max, 0xb1)); + + dotMax = max; + + // find first occurrence of that max + size_t test; + for( index = 0; 0 == (test=_mm_movemask_ps( _mm_cmpeq_ps( stack_array[index], max))); index++ ) // local_count must be a multiple of 4 + {} + // record where it is. + maxIndex = 4*index + segment + indexTable[test]; + } + } + + // account for work we've already done + count -= segment; + + // Deal with the last < STACK_ARRAY_COUNT vectors + max = dotMax; + index = 0; + + + if( b3Unlikely( count > 16) ) + { + for( ; index + 4 <= count / 4; index+=4 ) + { // do four dot products at a time. Carefully avoid touching the w element. + float4 v0 = vertices[0]; + float4 v1 = vertices[1]; + float4 v2 = vertices[2]; + float4 v3 = vertices[3]; vertices += 4; + + float4 lo0 = _mm_movelh_ps( v0, v1); // x0y0x1y1 + float4 hi0 = _mm_movehl_ps( v1, v0); // z0?0z1?1 + float4 lo1 = _mm_movelh_ps( v2, v3); // x2y2x3y3 + float4 hi1 = _mm_movehl_ps( v3, v2); // z2?2z3?3 + + lo0 = lo0*vLo; + lo1 = lo1*vLo; + float4 z = _mm_shuffle_ps(hi0, hi1, 0x88); + float4 x = _mm_shuffle_ps(lo0, lo1, 0x88); + float4 y = _mm_shuffle_ps(lo0, lo1, 0xdd); + z = z*vHi; + x = x+y; + x = x+z; + stack_array[index] = x; + max = _mm_max_ps( x, max ); // control the order here so that max is never NaN even if x is nan + + v0 = vertices[0]; + v1 = vertices[1]; + v2 = vertices[2]; + v3 = vertices[3]; vertices += 4; + + lo0 = _mm_movelh_ps( v0, v1); // x0y0x1y1 + hi0 = _mm_movehl_ps( v1, v0); // z0?0z1?1 + lo1 = _mm_movelh_ps( v2, v3); // x2y2x3y3 + hi1 = _mm_movehl_ps( v3, v2); // z2?2z3?3 + + lo0 = lo0*vLo; + lo1 = lo1*vLo; + z = _mm_shuffle_ps(hi0, hi1, 0x88); + x = _mm_shuffle_ps(lo0, lo1, 0x88); + y = _mm_shuffle_ps(lo0, lo1, 0xdd); + z = z*vHi; + x = x+y; + x = x+z; + stack_array[index+1] = x; + max = _mm_max_ps( x, max ); // control the order here so that max is never NaN even if x is nan + + v0 = vertices[0]; + v1 = vertices[1]; + v2 = vertices[2]; + v3 = vertices[3]; vertices += 4; + + lo0 = _mm_movelh_ps( v0, v1); // x0y0x1y1 + hi0 = _mm_movehl_ps( v1, v0); // z0?0z1?1 + lo1 = _mm_movelh_ps( v2, v3); // x2y2x3y3 + hi1 = _mm_movehl_ps( v3, v2); // z2?2z3?3 + + lo0 = lo0*vLo; + lo1 = lo1*vLo; + z = _mm_shuffle_ps(hi0, hi1, 0x88); + x = _mm_shuffle_ps(lo0, lo1, 0x88); + y = _mm_shuffle_ps(lo0, lo1, 0xdd); + z = z*vHi; + x = x+y; + x = x+z; + stack_array[index+2] = x; + max = _mm_max_ps( x, max ); // control the order here so that max is never NaN even if x is nan + + v0 = vertices[0]; + v1 = vertices[1]; + v2 = vertices[2]; + v3 = vertices[3]; vertices += 4; + + lo0 = _mm_movelh_ps( v0, v1); // x0y0x1y1 + hi0 = _mm_movehl_ps( v1, v0); // z0?0z1?1 + lo1 = _mm_movelh_ps( v2, v3); // x2y2x3y3 + hi1 = _mm_movehl_ps( v3, v2); // z2?2z3?3 + + lo0 = lo0*vLo; + lo1 = lo1*vLo; + z = _mm_shuffle_ps(hi0, hi1, 0x88); + x = _mm_shuffle_ps(lo0, lo1, 0x88); + y = _mm_shuffle_ps(lo0, lo1, 0xdd); + z = z*vHi; + x = x+y; + x = x+z; + stack_array[index+3] = x; + max = _mm_max_ps( x, max ); // control the order here so that max is never NaN even if x is nan + + // It is too costly to keep the index of the max here. We will look for it again later. We save a lot of work this way. + } + } + + size_t localCount = (count & -4L) - 4*index; + if( localCount ) + { +#ifdef __APPLE__ + float4 t0, t1, t2, t3, t4; + float4 * sap = &stack_array[index + localCount / 4]; + vertices += localCount; // counter the offset + size_t byteIndex = -(localCount) * sizeof(float); + //AT&T Code style assembly + asm volatile + ( ".align 4 \n\ + 0: movaps %[max], %[t2] // move max out of the way to avoid propagating NaNs in max \n\ + movaps (%[vertices], %[byteIndex], 4), %[t0] // vertices[0] \n\ + movaps 16(%[vertices], %[byteIndex], 4), %[t1] // vertices[1] \n\ + movaps %[t0], %[max] // vertices[0] \n\ + movlhps %[t1], %[max] // x0y0x1y1 \n\ + movaps 32(%[vertices], %[byteIndex], 4), %[t3] // vertices[2] \n\ + movaps 48(%[vertices], %[byteIndex], 4), %[t4] // vertices[3] \n\ + mulps %[vLo], %[max] // x0y0x1y1 * vLo \n\ + movhlps %[t0], %[t1] // z0w0z1w1 \n\ + movaps %[t3], %[t0] // vertices[2] \n\ + movlhps %[t4], %[t0] // x2y2x3y3 \n\ + mulps %[vLo], %[t0] // x2y2x3y3 * vLo \n\ + movhlps %[t3], %[t4] // z2w2z3w3 \n\ + shufps $0x88, %[t4], %[t1] // z0z1z2z3 \n\ + mulps %[vHi], %[t1] // z0z1z2z3 * vHi \n\ + movaps %[max], %[t3] // x0y0x1y1 * vLo \n\ + shufps $0x88, %[t0], %[max] // x0x1x2x3 * vLo.x \n\ + shufps $0xdd, %[t0], %[t3] // y0y1y2y3 * vLo.y \n\ + addps %[t3], %[max] // x + y \n\ + addps %[t1], %[max] // x + y + z \n\ + movaps %[max], (%[sap], %[byteIndex]) // record result for later scrutiny \n\ + maxps %[t2], %[max] // record max, restore max \n\ + add $16, %[byteIndex] // advance loop counter\n\ + jnz 0b \n\ + " + : [max] "+x" (max), [t0] "=&x" (t0), [t1] "=&x" (t1), [t2] "=&x" (t2), [t3] "=&x" (t3), [t4] "=&x" (t4), [byteIndex] "+r" (byteIndex) + : [vLo] "x" (vLo), [vHi] "x" (vHi), [vertices] "r" (vertices), [sap] "r" (sap) + : "memory", "cc" + ); + index += localCount/4; +#else + { + for( unsigned int i=0; i 16) ) + { + for( ; index + 4 <= count / 4; index+=4 ) + { // do four dot products at a time. Carefully avoid touching the w element. + float4 v0 = vertices[0]; + float4 v1 = vertices[1]; + float4 v2 = vertices[2]; + float4 v3 = vertices[3]; vertices += 4; + + float4 lo0 = _mm_movelh_ps( v0, v1); // x0y0x1y1 + float4 hi0 = _mm_movehl_ps( v1, v0); // z0?0z1?1 + float4 lo1 = _mm_movelh_ps( v2, v3); // x2y2x3y3 + float4 hi1 = _mm_movehl_ps( v3, v2); // z2?2z3?3 + + lo0 = lo0*vLo; + lo1 = lo1*vLo; + float4 z = _mm_shuffle_ps(hi0, hi1, 0x88); + float4 x = _mm_shuffle_ps(lo0, lo1, 0x88); + float4 y = _mm_shuffle_ps(lo0, lo1, 0xdd); + z = z*vHi; + x = x+y; + x = x+z; + stack_array[index] = x; + min = _mm_min_ps( x, min ); // control the order here so that min is never NaN even if x is nan + + v0 = vertices[0]; + v1 = vertices[1]; + v2 = vertices[2]; + v3 = vertices[3]; vertices += 4; + + lo0 = _mm_movelh_ps( v0, v1); // x0y0x1y1 + hi0 = _mm_movehl_ps( v1, v0); // z0?0z1?1 + lo1 = _mm_movelh_ps( v2, v3); // x2y2x3y3 + hi1 = _mm_movehl_ps( v3, v2); // z2?2z3?3 + + lo0 = lo0*vLo; + lo1 = lo1*vLo; + z = _mm_shuffle_ps(hi0, hi1, 0x88); + x = _mm_shuffle_ps(lo0, lo1, 0x88); + y = _mm_shuffle_ps(lo0, lo1, 0xdd); + z = z*vHi; + x = x+y; + x = x+z; + stack_array[index+1] = x; + min = _mm_min_ps( x, min ); // control the order here so that min is never NaN even if x is nan + + v0 = vertices[0]; + v1 = vertices[1]; + v2 = vertices[2]; + v3 = vertices[3]; vertices += 4; + + lo0 = _mm_movelh_ps( v0, v1); // x0y0x1y1 + hi0 = _mm_movehl_ps( v1, v0); // z0?0z1?1 + lo1 = _mm_movelh_ps( v2, v3); // x2y2x3y3 + hi1 = _mm_movehl_ps( v3, v2); // z2?2z3?3 + + lo0 = lo0*vLo; + lo1 = lo1*vLo; + z = _mm_shuffle_ps(hi0, hi1, 0x88); + x = _mm_shuffle_ps(lo0, lo1, 0x88); + y = _mm_shuffle_ps(lo0, lo1, 0xdd); + z = z*vHi; + x = x+y; + x = x+z; + stack_array[index+2] = x; + min = _mm_min_ps( x, min ); // control the order here so that min is never NaN even if x is nan + + v0 = vertices[0]; + v1 = vertices[1]; + v2 = vertices[2]; + v3 = vertices[3]; vertices += 4; + + lo0 = _mm_movelh_ps( v0, v1); // x0y0x1y1 + hi0 = _mm_movehl_ps( v1, v0); // z0?0z1?1 + lo1 = _mm_movelh_ps( v2, v3); // x2y2x3y3 + hi1 = _mm_movehl_ps( v3, v2); // z2?2z3?3 + + lo0 = lo0*vLo; + lo1 = lo1*vLo; + z = _mm_shuffle_ps(hi0, hi1, 0x88); + x = _mm_shuffle_ps(lo0, lo1, 0x88); + y = _mm_shuffle_ps(lo0, lo1, 0xdd); + z = z*vHi; + x = x+y; + x = x+z; + stack_array[index+3] = x; + min = _mm_min_ps( x, min ); // control the order here so that min is never NaN even if x is nan + + // It is too costly to keep the index of the min here. We will look for it again later. We save a lot of work this way. + } + } + + size_t localCount = (count & -4L) - 4*index; + if( localCount ) + { + + +#ifdef __APPLE__ + vertices += localCount; // counter the offset + float4 t0, t1, t2, t3, t4; + size_t byteIndex = -(localCount) * sizeof(float); + float4 * sap = &stack_array[index + localCount / 4]; + + asm volatile + ( ".align 4 \n\ + 0: movaps %[min], %[t2] // move min out of the way to avoid propagating NaNs in min \n\ + movaps (%[vertices], %[byteIndex], 4), %[t0] // vertices[0] \n\ + movaps 16(%[vertices], %[byteIndex], 4), %[t1] // vertices[1] \n\ + movaps %[t0], %[min] // vertices[0] \n\ + movlhps %[t1], %[min] // x0y0x1y1 \n\ + movaps 32(%[vertices], %[byteIndex], 4), %[t3] // vertices[2] \n\ + movaps 48(%[vertices], %[byteIndex], 4), %[t4] // vertices[3] \n\ + mulps %[vLo], %[min] // x0y0x1y1 * vLo \n\ + movhlps %[t0], %[t1] // z0w0z1w1 \n\ + movaps %[t3], %[t0] // vertices[2] \n\ + movlhps %[t4], %[t0] // x2y2x3y3 \n\ + movhlps %[t3], %[t4] // z2w2z3w3 \n\ + mulps %[vLo], %[t0] // x2y2x3y3 * vLo \n\ + shufps $0x88, %[t4], %[t1] // z0z1z2z3 \n\ + mulps %[vHi], %[t1] // z0z1z2z3 * vHi \n\ + movaps %[min], %[t3] // x0y0x1y1 * vLo \n\ + shufps $0x88, %[t0], %[min] // x0x1x2x3 * vLo.x \n\ + shufps $0xdd, %[t0], %[t3] // y0y1y2y3 * vLo.y \n\ + addps %[t3], %[min] // x + y \n\ + addps %[t1], %[min] // x + y + z \n\ + movaps %[min], (%[sap], %[byteIndex]) // record result for later scrutiny \n\ + minps %[t2], %[min] // record min, restore min \n\ + add $16, %[byteIndex] // advance loop counter\n\ + jnz 0b \n\ + " + : [min] "+x" (min), [t0] "=&x" (t0), [t1] "=&x" (t1), [t2] "=&x" (t2), [t3] "=&x" (t3), [t4] "=&x" (t4), [byteIndex] "+r" (byteIndex) + : [vLo] "x" (vLo), [vHi] "x" (vHi), [vertices] "r" (vertices), [sap] "r" (sap) + : "memory", "cc" + ); + index += localCount/4; +#else + { + for( unsigned int i=0; i + + +static long b3_maxdot_large_v0( const float *vv, const float *vec, unsigned long count, float *dotResult ); +static long b3_maxdot_large_v1( const float *vv, const float *vec, unsigned long count, float *dotResult ); +static long b3_maxdot_large_sel( const float *vv, const float *vec, unsigned long count, float *dotResult ); +static long b3_mindot_large_v0( const float *vv, const float *vec, unsigned long count, float *dotResult ); +static long b3_mindot_large_v1( const float *vv, const float *vec, unsigned long count, float *dotResult ); +static long b3_mindot_large_sel( const float *vv, const float *vec, unsigned long count, float *dotResult ); + +long (*b3_maxdot_large)( const float *vv, const float *vec, unsigned long count, float *dotResult ) = b3_maxdot_large_sel; +long (*b3_mindot_large)( const float *vv, const float *vec, unsigned long count, float *dotResult ) = b3_mindot_large_sel; + +extern "C" {int _get_cpu_capabilities( void );} + +static long b3_maxdot_large_sel( const float *vv, const float *vec, unsigned long count, float *dotResult ) +{ + if( _get_cpu_capabilities() & 0x2000 ) + b3_maxdot_large = _maxdot_large_v1; + else + b3_maxdot_large = _maxdot_large_v0; + + return b3_maxdot_large(vv, vec, count, dotResult); +} + +static long b3_mindot_large_sel( const float *vv, const float *vec, unsigned long count, float *dotResult ) +{ + if( _get_cpu_capabilities() & 0x2000 ) + b3_mindot_large = _mindot_large_v1; + else + b3_mindot_large = _mindot_large_v0; + + return b3_mindot_large(vv, vec, count, dotResult); +} + + + +#define vld1q_f32_aligned_postincrement( _ptr ) ({ float32x4_t _r; asm( "vld1.f32 {%0}, [%1, :128]!\n" : "=w" (_r), "+r" (_ptr) ); /*return*/ _r; }) + + +long b3_maxdot_large_v0( const float *vv, const float *vec, unsigned long count, float *dotResult ) +{ + unsigned long i = 0; + float32x4_t vvec = vld1q_f32_aligned_postincrement( vec ); + float32x2_t vLo = vget_low_f32(vvec); + float32x2_t vHi = vdup_lane_f32(vget_high_f32(vvec), 0); + float32x2_t dotMaxLo = (float32x2_t) { -B3_INFINITY, -B3_INFINITY }; + float32x2_t dotMaxHi = (float32x2_t) { -B3_INFINITY, -B3_INFINITY }; + uint32x2_t indexLo = (uint32x2_t) {0, 1}; + uint32x2_t indexHi = (uint32x2_t) {2, 3}; + uint32x2_t iLo = (uint32x2_t) {-1, -1}; + uint32x2_t iHi = (uint32x2_t) {-1, -1}; + const uint32x2_t four = (uint32x2_t) {4,4}; + + for( ; i+8 <= count; i+= 8 ) + { + float32x4_t v0 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v1 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v2 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v3 = vld1q_f32_aligned_postincrement( vv ); + + float32x2_t xy0 = vmul_f32( vget_low_f32(v0), vLo); + float32x2_t xy1 = vmul_f32( vget_low_f32(v1), vLo); + float32x2_t xy2 = vmul_f32( vget_low_f32(v2), vLo); + float32x2_t xy3 = vmul_f32( vget_low_f32(v3), vLo); + + float32x2x2_t z0 = vtrn_f32( vget_high_f32(v0), vget_high_f32(v1)); + float32x2x2_t z1 = vtrn_f32( vget_high_f32(v2), vget_high_f32(v3)); + float32x2_t zLo = vmul_f32( z0.val[0], vHi); + float32x2_t zHi = vmul_f32( z1.val[0], vHi); + + float32x2_t rLo = vpadd_f32( xy0, xy1); + float32x2_t rHi = vpadd_f32( xy2, xy3); + rLo = vadd_f32(rLo, zLo); + rHi = vadd_f32(rHi, zHi); + + uint32x2_t maskLo = vcgt_f32( rLo, dotMaxLo ); + uint32x2_t maskHi = vcgt_f32( rHi, dotMaxHi ); + dotMaxLo = vbsl_f32( maskLo, rLo, dotMaxLo); + dotMaxHi = vbsl_f32( maskHi, rHi, dotMaxHi); + iLo = vbsl_u32(maskLo, indexLo, iLo); + iHi = vbsl_u32(maskHi, indexHi, iHi); + indexLo = vadd_u32(indexLo, four); + indexHi = vadd_u32(indexHi, four); + + v0 = vld1q_f32_aligned_postincrement( vv ); + v1 = vld1q_f32_aligned_postincrement( vv ); + v2 = vld1q_f32_aligned_postincrement( vv ); + v3 = vld1q_f32_aligned_postincrement( vv ); + + xy0 = vmul_f32( vget_low_f32(v0), vLo); + xy1 = vmul_f32( vget_low_f32(v1), vLo); + xy2 = vmul_f32( vget_low_f32(v2), vLo); + xy3 = vmul_f32( vget_low_f32(v3), vLo); + + z0 = vtrn_f32( vget_high_f32(v0), vget_high_f32(v1)); + z1 = vtrn_f32( vget_high_f32(v2), vget_high_f32(v3)); + zLo = vmul_f32( z0.val[0], vHi); + zHi = vmul_f32( z1.val[0], vHi); + + rLo = vpadd_f32( xy0, xy1); + rHi = vpadd_f32( xy2, xy3); + rLo = vadd_f32(rLo, zLo); + rHi = vadd_f32(rHi, zHi); + + maskLo = vcgt_f32( rLo, dotMaxLo ); + maskHi = vcgt_f32( rHi, dotMaxHi ); + dotMaxLo = vbsl_f32( maskLo, rLo, dotMaxLo); + dotMaxHi = vbsl_f32( maskHi, rHi, dotMaxHi); + iLo = vbsl_u32(maskLo, indexLo, iLo); + iHi = vbsl_u32(maskHi, indexHi, iHi); + indexLo = vadd_u32(indexLo, four); + indexHi = vadd_u32(indexHi, four); + } + + for( ; i+4 <= count; i+= 4 ) + { + float32x4_t v0 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v1 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v2 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v3 = vld1q_f32_aligned_postincrement( vv ); + + float32x2_t xy0 = vmul_f32( vget_low_f32(v0), vLo); + float32x2_t xy1 = vmul_f32( vget_low_f32(v1), vLo); + float32x2_t xy2 = vmul_f32( vget_low_f32(v2), vLo); + float32x2_t xy3 = vmul_f32( vget_low_f32(v3), vLo); + + float32x2x2_t z0 = vtrn_f32( vget_high_f32(v0), vget_high_f32(v1)); + float32x2x2_t z1 = vtrn_f32( vget_high_f32(v2), vget_high_f32(v3)); + float32x2_t zLo = vmul_f32( z0.val[0], vHi); + float32x2_t zHi = vmul_f32( z1.val[0], vHi); + + float32x2_t rLo = vpadd_f32( xy0, xy1); + float32x2_t rHi = vpadd_f32( xy2, xy3); + rLo = vadd_f32(rLo, zLo); + rHi = vadd_f32(rHi, zHi); + + uint32x2_t maskLo = vcgt_f32( rLo, dotMaxLo ); + uint32x2_t maskHi = vcgt_f32( rHi, dotMaxHi ); + dotMaxLo = vbsl_f32( maskLo, rLo, dotMaxLo); + dotMaxHi = vbsl_f32( maskHi, rHi, dotMaxHi); + iLo = vbsl_u32(maskLo, indexLo, iLo); + iHi = vbsl_u32(maskHi, indexHi, iHi); + indexLo = vadd_u32(indexLo, four); + indexHi = vadd_u32(indexHi, four); + } + + switch( count & 3 ) + { + case 3: + { + float32x4_t v0 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v1 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v2 = vld1q_f32_aligned_postincrement( vv ); + + float32x2_t xy0 = vmul_f32( vget_low_f32(v0), vLo); + float32x2_t xy1 = vmul_f32( vget_low_f32(v1), vLo); + float32x2_t xy2 = vmul_f32( vget_low_f32(v2), vLo); + + float32x2x2_t z0 = vtrn_f32( vget_high_f32(v0), vget_high_f32(v1)); + float32x2_t zLo = vmul_f32( z0.val[0], vHi); + float32x2_t zHi = vmul_f32( vdup_lane_f32(vget_high_f32(v2), 0), vHi); + + float32x2_t rLo = vpadd_f32( xy0, xy1); + float32x2_t rHi = vpadd_f32( xy2, xy2); + rLo = vadd_f32(rLo, zLo); + rHi = vadd_f32(rHi, zHi); + + uint32x2_t maskLo = vcgt_f32( rLo, dotMaxLo ); + uint32x2_t maskHi = vcgt_f32( rHi, dotMaxHi ); + dotMaxLo = vbsl_f32( maskLo, rLo, dotMaxLo); + dotMaxHi = vbsl_f32( maskHi, rHi, dotMaxHi); + iLo = vbsl_u32(maskLo, indexLo, iLo); + iHi = vbsl_u32(maskHi, indexHi, iHi); + } + break; + case 2: + { + float32x4_t v0 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v1 = vld1q_f32_aligned_postincrement( vv ); + + float32x2_t xy0 = vmul_f32( vget_low_f32(v0), vLo); + float32x2_t xy1 = vmul_f32( vget_low_f32(v1), vLo); + + float32x2x2_t z0 = vtrn_f32( vget_high_f32(v0), vget_high_f32(v1)); + float32x2_t zLo = vmul_f32( z0.val[0], vHi); + + float32x2_t rLo = vpadd_f32( xy0, xy1); + rLo = vadd_f32(rLo, zLo); + + uint32x2_t maskLo = vcgt_f32( rLo, dotMaxLo ); + dotMaxLo = vbsl_f32( maskLo, rLo, dotMaxLo); + iLo = vbsl_u32(maskLo, indexLo, iLo); + } + break; + case 1: + { + float32x4_t v0 = vld1q_f32_aligned_postincrement( vv ); + float32x2_t xy0 = vmul_f32( vget_low_f32(v0), vLo); + float32x2_t z0 = vdup_lane_f32(vget_high_f32(v0), 0); + float32x2_t zLo = vmul_f32( z0, vHi); + float32x2_t rLo = vpadd_f32( xy0, xy0); + rLo = vadd_f32(rLo, zLo); + uint32x2_t maskLo = vcgt_f32( rLo, dotMaxLo ); + dotMaxLo = vbsl_f32( maskLo, rLo, dotMaxLo); + iLo = vbsl_u32(maskLo, indexLo, iLo); + } + break; + + default: + break; + } + + // select best answer between hi and lo results + uint32x2_t mask = vcgt_f32( dotMaxHi, dotMaxLo ); + dotMaxLo = vbsl_f32(mask, dotMaxHi, dotMaxLo); + iLo = vbsl_u32(mask, iHi, iLo); + + // select best answer between even and odd results + dotMaxHi = vdup_lane_f32(dotMaxLo, 1); + iHi = vdup_lane_u32(iLo, 1); + mask = vcgt_f32( dotMaxHi, dotMaxLo ); + dotMaxLo = vbsl_f32(mask, dotMaxHi, dotMaxLo); + iLo = vbsl_u32(mask, iHi, iLo); + + *dotResult = vget_lane_f32( dotMaxLo, 0); + return vget_lane_u32(iLo, 0); +} + + +long b3_maxdot_large_v1( const float *vv, const float *vec, unsigned long count, float *dotResult ) +{ + float32x4_t vvec = vld1q_f32_aligned_postincrement( vec ); + float32x4_t vLo = vcombine_f32(vget_low_f32(vvec), vget_low_f32(vvec)); + float32x4_t vHi = vdupq_lane_f32(vget_high_f32(vvec), 0); + const uint32x4_t four = (uint32x4_t){ 4, 4, 4, 4 }; + uint32x4_t local_index = (uint32x4_t) {0, 1, 2, 3}; + uint32x4_t index = (uint32x4_t) { -1, -1, -1, -1 }; + float32x4_t maxDot = (float32x4_t) { -B3_INFINITY, -B3_INFINITY, -B3_INFINITY, -B3_INFINITY }; + + unsigned long i = 0; + for( ; i + 8 <= count; i += 8 ) + { + float32x4_t v0 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v1 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v2 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v3 = vld1q_f32_aligned_postincrement( vv ); + + // the next two lines should resolve to a single vswp d, d + float32x4_t xy0 = vcombine_f32( vget_low_f32(v0), vget_low_f32(v1)); + float32x4_t xy1 = vcombine_f32( vget_low_f32(v2), vget_low_f32(v3)); + // the next two lines should resolve to a single vswp d, d + float32x4_t z0 = vcombine_f32( vget_high_f32(v0), vget_high_f32(v1)); + float32x4_t z1 = vcombine_f32( vget_high_f32(v2), vget_high_f32(v3)); + + xy0 = vmulq_f32(xy0, vLo); + xy1 = vmulq_f32(xy1, vLo); + + float32x4x2_t zb = vuzpq_f32( z0, z1); + float32x4_t z = vmulq_f32( zb.val[0], vHi); + float32x4x2_t xy = vuzpq_f32( xy0, xy1); + float32x4_t x = vaddq_f32(xy.val[0], xy.val[1]); + x = vaddq_f32(x, z); + + uint32x4_t mask = vcgtq_f32(x, maxDot); + maxDot = vbslq_f32( mask, x, maxDot); + index = vbslq_u32(mask, local_index, index); + local_index = vaddq_u32(local_index, four); + + v0 = vld1q_f32_aligned_postincrement( vv ); + v1 = vld1q_f32_aligned_postincrement( vv ); + v2 = vld1q_f32_aligned_postincrement( vv ); + v3 = vld1q_f32_aligned_postincrement( vv ); + + // the next two lines should resolve to a single vswp d, d + xy0 = vcombine_f32( vget_low_f32(v0), vget_low_f32(v1)); + xy1 = vcombine_f32( vget_low_f32(v2), vget_low_f32(v3)); + // the next two lines should resolve to a single vswp d, d + z0 = vcombine_f32( vget_high_f32(v0), vget_high_f32(v1)); + z1 = vcombine_f32( vget_high_f32(v2), vget_high_f32(v3)); + + xy0 = vmulq_f32(xy0, vLo); + xy1 = vmulq_f32(xy1, vLo); + + zb = vuzpq_f32( z0, z1); + z = vmulq_f32( zb.val[0], vHi); + xy = vuzpq_f32( xy0, xy1); + x = vaddq_f32(xy.val[0], xy.val[1]); + x = vaddq_f32(x, z); + + mask = vcgtq_f32(x, maxDot); + maxDot = vbslq_f32( mask, x, maxDot); + index = vbslq_u32(mask, local_index, index); + local_index = vaddq_u32(local_index, four); + } + + for( ; i + 4 <= count; i += 4 ) + { + float32x4_t v0 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v1 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v2 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v3 = vld1q_f32_aligned_postincrement( vv ); + + // the next two lines should resolve to a single vswp d, d + float32x4_t xy0 = vcombine_f32( vget_low_f32(v0), vget_low_f32(v1)); + float32x4_t xy1 = vcombine_f32( vget_low_f32(v2), vget_low_f32(v3)); + // the next two lines should resolve to a single vswp d, d + float32x4_t z0 = vcombine_f32( vget_high_f32(v0), vget_high_f32(v1)); + float32x4_t z1 = vcombine_f32( vget_high_f32(v2), vget_high_f32(v3)); + + xy0 = vmulq_f32(xy0, vLo); + xy1 = vmulq_f32(xy1, vLo); + + float32x4x2_t zb = vuzpq_f32( z0, z1); + float32x4_t z = vmulq_f32( zb.val[0], vHi); + float32x4x2_t xy = vuzpq_f32( xy0, xy1); + float32x4_t x = vaddq_f32(xy.val[0], xy.val[1]); + x = vaddq_f32(x, z); + + uint32x4_t mask = vcgtq_f32(x, maxDot); + maxDot = vbslq_f32( mask, x, maxDot); + index = vbslq_u32(mask, local_index, index); + local_index = vaddq_u32(local_index, four); + } + + switch (count & 3) { + case 3: + { + float32x4_t v0 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v1 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v2 = vld1q_f32_aligned_postincrement( vv ); + + // the next two lines should resolve to a single vswp d, d + float32x4_t xy0 = vcombine_f32( vget_low_f32(v0), vget_low_f32(v1)); + float32x4_t xy1 = vcombine_f32( vget_low_f32(v2), vget_low_f32(v2)); + // the next two lines should resolve to a single vswp d, d + float32x4_t z0 = vcombine_f32( vget_high_f32(v0), vget_high_f32(v1)); + float32x4_t z1 = vcombine_f32( vget_high_f32(v2), vget_high_f32(v2)); + + xy0 = vmulq_f32(xy0, vLo); + xy1 = vmulq_f32(xy1, vLo); + + float32x4x2_t zb = vuzpq_f32( z0, z1); + float32x4_t z = vmulq_f32( zb.val[0], vHi); + float32x4x2_t xy = vuzpq_f32( xy0, xy1); + float32x4_t x = vaddq_f32(xy.val[0], xy.val[1]); + x = vaddq_f32(x, z); + + uint32x4_t mask = vcgtq_f32(x, maxDot); + maxDot = vbslq_f32( mask, x, maxDot); + index = vbslq_u32(mask, local_index, index); + local_index = vaddq_u32(local_index, four); + } + break; + + case 2: + { + float32x4_t v0 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v1 = vld1q_f32_aligned_postincrement( vv ); + + // the next two lines should resolve to a single vswp d, d + float32x4_t xy0 = vcombine_f32( vget_low_f32(v0), vget_low_f32(v1)); + // the next two lines should resolve to a single vswp d, d + float32x4_t z0 = vcombine_f32( vget_high_f32(v0), vget_high_f32(v1)); + + xy0 = vmulq_f32(xy0, vLo); + + float32x4x2_t zb = vuzpq_f32( z0, z0); + float32x4_t z = vmulq_f32( zb.val[0], vHi); + float32x4x2_t xy = vuzpq_f32( xy0, xy0); + float32x4_t x = vaddq_f32(xy.val[0], xy.val[1]); + x = vaddq_f32(x, z); + + uint32x4_t mask = vcgtq_f32(x, maxDot); + maxDot = vbslq_f32( mask, x, maxDot); + index = vbslq_u32(mask, local_index, index); + local_index = vaddq_u32(local_index, four); + } + break; + + case 1: + { + float32x4_t v0 = vld1q_f32_aligned_postincrement( vv ); + + // the next two lines should resolve to a single vswp d, d + float32x4_t xy0 = vcombine_f32( vget_low_f32(v0), vget_low_f32(v0)); + // the next two lines should resolve to a single vswp d, d + float32x4_t z = vdupq_lane_f32(vget_high_f32(v0), 0); + + xy0 = vmulq_f32(xy0, vLo); + + z = vmulq_f32( z, vHi); + float32x4x2_t xy = vuzpq_f32( xy0, xy0); + float32x4_t x = vaddq_f32(xy.val[0], xy.val[1]); + x = vaddq_f32(x, z); + + uint32x4_t mask = vcgtq_f32(x, maxDot); + maxDot = vbslq_f32( mask, x, maxDot); + index = vbslq_u32(mask, local_index, index); + local_index = vaddq_u32(local_index, four); + } + break; + + default: + break; + } + + + // select best answer between hi and lo results + uint32x2_t mask = vcgt_f32( vget_high_f32(maxDot), vget_low_f32(maxDot)); + float32x2_t maxDot2 = vbsl_f32(mask, vget_high_f32(maxDot), vget_low_f32(maxDot)); + uint32x2_t index2 = vbsl_u32(mask, vget_high_u32(index), vget_low_u32(index)); + + // select best answer between even and odd results + float32x2_t maxDotO = vdup_lane_f32(maxDot2, 1); + uint32x2_t indexHi = vdup_lane_u32(index2, 1); + mask = vcgt_f32( maxDotO, maxDot2 ); + maxDot2 = vbsl_f32(mask, maxDotO, maxDot2); + index2 = vbsl_u32(mask, indexHi, index2); + + *dotResult = vget_lane_f32( maxDot2, 0); + return vget_lane_u32(index2, 0); + +} + +long b3_mindot_large_v0( const float *vv, const float *vec, unsigned long count, float *dotResult ) +{ + unsigned long i = 0; + float32x4_t vvec = vld1q_f32_aligned_postincrement( vec ); + float32x2_t vLo = vget_low_f32(vvec); + float32x2_t vHi = vdup_lane_f32(vget_high_f32(vvec), 0); + float32x2_t dotMinLo = (float32x2_t) { B3_INFINITY, B3_INFINITY }; + float32x2_t dotMinHi = (float32x2_t) { B3_INFINITY, B3_INFINITY }; + uint32x2_t indexLo = (uint32x2_t) {0, 1}; + uint32x2_t indexHi = (uint32x2_t) {2, 3}; + uint32x2_t iLo = (uint32x2_t) {-1, -1}; + uint32x2_t iHi = (uint32x2_t) {-1, -1}; + const uint32x2_t four = (uint32x2_t) {4,4}; + + for( ; i+8 <= count; i+= 8 ) + { + float32x4_t v0 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v1 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v2 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v3 = vld1q_f32_aligned_postincrement( vv ); + + float32x2_t xy0 = vmul_f32( vget_low_f32(v0), vLo); + float32x2_t xy1 = vmul_f32( vget_low_f32(v1), vLo); + float32x2_t xy2 = vmul_f32( vget_low_f32(v2), vLo); + float32x2_t xy3 = vmul_f32( vget_low_f32(v3), vLo); + + float32x2x2_t z0 = vtrn_f32( vget_high_f32(v0), vget_high_f32(v1)); + float32x2x2_t z1 = vtrn_f32( vget_high_f32(v2), vget_high_f32(v3)); + float32x2_t zLo = vmul_f32( z0.val[0], vHi); + float32x2_t zHi = vmul_f32( z1.val[0], vHi); + + float32x2_t rLo = vpadd_f32( xy0, xy1); + float32x2_t rHi = vpadd_f32( xy2, xy3); + rLo = vadd_f32(rLo, zLo); + rHi = vadd_f32(rHi, zHi); + + uint32x2_t maskLo = vclt_f32( rLo, dotMinLo ); + uint32x2_t maskHi = vclt_f32( rHi, dotMinHi ); + dotMinLo = vbsl_f32( maskLo, rLo, dotMinLo); + dotMinHi = vbsl_f32( maskHi, rHi, dotMinHi); + iLo = vbsl_u32(maskLo, indexLo, iLo); + iHi = vbsl_u32(maskHi, indexHi, iHi); + indexLo = vadd_u32(indexLo, four); + indexHi = vadd_u32(indexHi, four); + + v0 = vld1q_f32_aligned_postincrement( vv ); + v1 = vld1q_f32_aligned_postincrement( vv ); + v2 = vld1q_f32_aligned_postincrement( vv ); + v3 = vld1q_f32_aligned_postincrement( vv ); + + xy0 = vmul_f32( vget_low_f32(v0), vLo); + xy1 = vmul_f32( vget_low_f32(v1), vLo); + xy2 = vmul_f32( vget_low_f32(v2), vLo); + xy3 = vmul_f32( vget_low_f32(v3), vLo); + + z0 = vtrn_f32( vget_high_f32(v0), vget_high_f32(v1)); + z1 = vtrn_f32( vget_high_f32(v2), vget_high_f32(v3)); + zLo = vmul_f32( z0.val[0], vHi); + zHi = vmul_f32( z1.val[0], vHi); + + rLo = vpadd_f32( xy0, xy1); + rHi = vpadd_f32( xy2, xy3); + rLo = vadd_f32(rLo, zLo); + rHi = vadd_f32(rHi, zHi); + + maskLo = vclt_f32( rLo, dotMinLo ); + maskHi = vclt_f32( rHi, dotMinHi ); + dotMinLo = vbsl_f32( maskLo, rLo, dotMinLo); + dotMinHi = vbsl_f32( maskHi, rHi, dotMinHi); + iLo = vbsl_u32(maskLo, indexLo, iLo); + iHi = vbsl_u32(maskHi, indexHi, iHi); + indexLo = vadd_u32(indexLo, four); + indexHi = vadd_u32(indexHi, four); + } + + for( ; i+4 <= count; i+= 4 ) + { + float32x4_t v0 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v1 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v2 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v3 = vld1q_f32_aligned_postincrement( vv ); + + float32x2_t xy0 = vmul_f32( vget_low_f32(v0), vLo); + float32x2_t xy1 = vmul_f32( vget_low_f32(v1), vLo); + float32x2_t xy2 = vmul_f32( vget_low_f32(v2), vLo); + float32x2_t xy3 = vmul_f32( vget_low_f32(v3), vLo); + + float32x2x2_t z0 = vtrn_f32( vget_high_f32(v0), vget_high_f32(v1)); + float32x2x2_t z1 = vtrn_f32( vget_high_f32(v2), vget_high_f32(v3)); + float32x2_t zLo = vmul_f32( z0.val[0], vHi); + float32x2_t zHi = vmul_f32( z1.val[0], vHi); + + float32x2_t rLo = vpadd_f32( xy0, xy1); + float32x2_t rHi = vpadd_f32( xy2, xy3); + rLo = vadd_f32(rLo, zLo); + rHi = vadd_f32(rHi, zHi); + + uint32x2_t maskLo = vclt_f32( rLo, dotMinLo ); + uint32x2_t maskHi = vclt_f32( rHi, dotMinHi ); + dotMinLo = vbsl_f32( maskLo, rLo, dotMinLo); + dotMinHi = vbsl_f32( maskHi, rHi, dotMinHi); + iLo = vbsl_u32(maskLo, indexLo, iLo); + iHi = vbsl_u32(maskHi, indexHi, iHi); + indexLo = vadd_u32(indexLo, four); + indexHi = vadd_u32(indexHi, four); + } + switch( count & 3 ) + { + case 3: + { + float32x4_t v0 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v1 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v2 = vld1q_f32_aligned_postincrement( vv ); + + float32x2_t xy0 = vmul_f32( vget_low_f32(v0), vLo); + float32x2_t xy1 = vmul_f32( vget_low_f32(v1), vLo); + float32x2_t xy2 = vmul_f32( vget_low_f32(v2), vLo); + + float32x2x2_t z0 = vtrn_f32( vget_high_f32(v0), vget_high_f32(v1)); + float32x2_t zLo = vmul_f32( z0.val[0], vHi); + float32x2_t zHi = vmul_f32( vdup_lane_f32(vget_high_f32(v2), 0), vHi); + + float32x2_t rLo = vpadd_f32( xy0, xy1); + float32x2_t rHi = vpadd_f32( xy2, xy2); + rLo = vadd_f32(rLo, zLo); + rHi = vadd_f32(rHi, zHi); + + uint32x2_t maskLo = vclt_f32( rLo, dotMinLo ); + uint32x2_t maskHi = vclt_f32( rHi, dotMinHi ); + dotMinLo = vbsl_f32( maskLo, rLo, dotMinLo); + dotMinHi = vbsl_f32( maskHi, rHi, dotMinHi); + iLo = vbsl_u32(maskLo, indexLo, iLo); + iHi = vbsl_u32(maskHi, indexHi, iHi); + } + break; + case 2: + { + float32x4_t v0 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v1 = vld1q_f32_aligned_postincrement( vv ); + + float32x2_t xy0 = vmul_f32( vget_low_f32(v0), vLo); + float32x2_t xy1 = vmul_f32( vget_low_f32(v1), vLo); + + float32x2x2_t z0 = vtrn_f32( vget_high_f32(v0), vget_high_f32(v1)); + float32x2_t zLo = vmul_f32( z0.val[0], vHi); + + float32x2_t rLo = vpadd_f32( xy0, xy1); + rLo = vadd_f32(rLo, zLo); + + uint32x2_t maskLo = vclt_f32( rLo, dotMinLo ); + dotMinLo = vbsl_f32( maskLo, rLo, dotMinLo); + iLo = vbsl_u32(maskLo, indexLo, iLo); + } + break; + case 1: + { + float32x4_t v0 = vld1q_f32_aligned_postincrement( vv ); + float32x2_t xy0 = vmul_f32( vget_low_f32(v0), vLo); + float32x2_t z0 = vdup_lane_f32(vget_high_f32(v0), 0); + float32x2_t zLo = vmul_f32( z0, vHi); + float32x2_t rLo = vpadd_f32( xy0, xy0); + rLo = vadd_f32(rLo, zLo); + uint32x2_t maskLo = vclt_f32( rLo, dotMinLo ); + dotMinLo = vbsl_f32( maskLo, rLo, dotMinLo); + iLo = vbsl_u32(maskLo, indexLo, iLo); + } + break; + + default: + break; + } + + // select best answer between hi and lo results + uint32x2_t mask = vclt_f32( dotMinHi, dotMinLo ); + dotMinLo = vbsl_f32(mask, dotMinHi, dotMinLo); + iLo = vbsl_u32(mask, iHi, iLo); + + // select best answer between even and odd results + dotMinHi = vdup_lane_f32(dotMinLo, 1); + iHi = vdup_lane_u32(iLo, 1); + mask = vclt_f32( dotMinHi, dotMinLo ); + dotMinLo = vbsl_f32(mask, dotMinHi, dotMinLo); + iLo = vbsl_u32(mask, iHi, iLo); + + *dotResult = vget_lane_f32( dotMinLo, 0); + return vget_lane_u32(iLo, 0); +} + +long b3_mindot_large_v1( const float *vv, const float *vec, unsigned long count, float *dotResult ) +{ + float32x4_t vvec = vld1q_f32_aligned_postincrement( vec ); + float32x4_t vLo = vcombine_f32(vget_low_f32(vvec), vget_low_f32(vvec)); + float32x4_t vHi = vdupq_lane_f32(vget_high_f32(vvec), 0); + const uint32x4_t four = (uint32x4_t){ 4, 4, 4, 4 }; + uint32x4_t local_index = (uint32x4_t) {0, 1, 2, 3}; + uint32x4_t index = (uint32x4_t) { -1, -1, -1, -1 }; + float32x4_t minDot = (float32x4_t) { B3_INFINITY, B3_INFINITY, B3_INFINITY, B3_INFINITY }; + + unsigned long i = 0; + for( ; i + 8 <= count; i += 8 ) + { + float32x4_t v0 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v1 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v2 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v3 = vld1q_f32_aligned_postincrement( vv ); + + // the next two lines should resolve to a single vswp d, d + float32x4_t xy0 = vcombine_f32( vget_low_f32(v0), vget_low_f32(v1)); + float32x4_t xy1 = vcombine_f32( vget_low_f32(v2), vget_low_f32(v3)); + // the next two lines should resolve to a single vswp d, d + float32x4_t z0 = vcombine_f32( vget_high_f32(v0), vget_high_f32(v1)); + float32x4_t z1 = vcombine_f32( vget_high_f32(v2), vget_high_f32(v3)); + + xy0 = vmulq_f32(xy0, vLo); + xy1 = vmulq_f32(xy1, vLo); + + float32x4x2_t zb = vuzpq_f32( z0, z1); + float32x4_t z = vmulq_f32( zb.val[0], vHi); + float32x4x2_t xy = vuzpq_f32( xy0, xy1); + float32x4_t x = vaddq_f32(xy.val[0], xy.val[1]); + x = vaddq_f32(x, z); + + uint32x4_t mask = vcltq_f32(x, minDot); + minDot = vbslq_f32( mask, x, minDot); + index = vbslq_u32(mask, local_index, index); + local_index = vaddq_u32(local_index, four); + + v0 = vld1q_f32_aligned_postincrement( vv ); + v1 = vld1q_f32_aligned_postincrement( vv ); + v2 = vld1q_f32_aligned_postincrement( vv ); + v3 = vld1q_f32_aligned_postincrement( vv ); + + // the next two lines should resolve to a single vswp d, d + xy0 = vcombine_f32( vget_low_f32(v0), vget_low_f32(v1)); + xy1 = vcombine_f32( vget_low_f32(v2), vget_low_f32(v3)); + // the next two lines should resolve to a single vswp d, d + z0 = vcombine_f32( vget_high_f32(v0), vget_high_f32(v1)); + z1 = vcombine_f32( vget_high_f32(v2), vget_high_f32(v3)); + + xy0 = vmulq_f32(xy0, vLo); + xy1 = vmulq_f32(xy1, vLo); + + zb = vuzpq_f32( z0, z1); + z = vmulq_f32( zb.val[0], vHi); + xy = vuzpq_f32( xy0, xy1); + x = vaddq_f32(xy.val[0], xy.val[1]); + x = vaddq_f32(x, z); + + mask = vcltq_f32(x, minDot); + minDot = vbslq_f32( mask, x, minDot); + index = vbslq_u32(mask, local_index, index); + local_index = vaddq_u32(local_index, four); + } + + for( ; i + 4 <= count; i += 4 ) + { + float32x4_t v0 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v1 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v2 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v3 = vld1q_f32_aligned_postincrement( vv ); + + // the next two lines should resolve to a single vswp d, d + float32x4_t xy0 = vcombine_f32( vget_low_f32(v0), vget_low_f32(v1)); + float32x4_t xy1 = vcombine_f32( vget_low_f32(v2), vget_low_f32(v3)); + // the next two lines should resolve to a single vswp d, d + float32x4_t z0 = vcombine_f32( vget_high_f32(v0), vget_high_f32(v1)); + float32x4_t z1 = vcombine_f32( vget_high_f32(v2), vget_high_f32(v3)); + + xy0 = vmulq_f32(xy0, vLo); + xy1 = vmulq_f32(xy1, vLo); + + float32x4x2_t zb = vuzpq_f32( z0, z1); + float32x4_t z = vmulq_f32( zb.val[0], vHi); + float32x4x2_t xy = vuzpq_f32( xy0, xy1); + float32x4_t x = vaddq_f32(xy.val[0], xy.val[1]); + x = vaddq_f32(x, z); + + uint32x4_t mask = vcltq_f32(x, minDot); + minDot = vbslq_f32( mask, x, minDot); + index = vbslq_u32(mask, local_index, index); + local_index = vaddq_u32(local_index, four); + } + + switch (count & 3) { + case 3: + { + float32x4_t v0 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v1 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v2 = vld1q_f32_aligned_postincrement( vv ); + + // the next two lines should resolve to a single vswp d, d + float32x4_t xy0 = vcombine_f32( vget_low_f32(v0), vget_low_f32(v1)); + float32x4_t xy1 = vcombine_f32( vget_low_f32(v2), vget_low_f32(v2)); + // the next two lines should resolve to a single vswp d, d + float32x4_t z0 = vcombine_f32( vget_high_f32(v0), vget_high_f32(v1)); + float32x4_t z1 = vcombine_f32( vget_high_f32(v2), vget_high_f32(v2)); + + xy0 = vmulq_f32(xy0, vLo); + xy1 = vmulq_f32(xy1, vLo); + + float32x4x2_t zb = vuzpq_f32( z0, z1); + float32x4_t z = vmulq_f32( zb.val[0], vHi); + float32x4x2_t xy = vuzpq_f32( xy0, xy1); + float32x4_t x = vaddq_f32(xy.val[0], xy.val[1]); + x = vaddq_f32(x, z); + + uint32x4_t mask = vcltq_f32(x, minDot); + minDot = vbslq_f32( mask, x, minDot); + index = vbslq_u32(mask, local_index, index); + local_index = vaddq_u32(local_index, four); + } + break; + + case 2: + { + float32x4_t v0 = vld1q_f32_aligned_postincrement( vv ); + float32x4_t v1 = vld1q_f32_aligned_postincrement( vv ); + + // the next two lines should resolve to a single vswp d, d + float32x4_t xy0 = vcombine_f32( vget_low_f32(v0), vget_low_f32(v1)); + // the next two lines should resolve to a single vswp d, d + float32x4_t z0 = vcombine_f32( vget_high_f32(v0), vget_high_f32(v1)); + + xy0 = vmulq_f32(xy0, vLo); + + float32x4x2_t zb = vuzpq_f32( z0, z0); + float32x4_t z = vmulq_f32( zb.val[0], vHi); + float32x4x2_t xy = vuzpq_f32( xy0, xy0); + float32x4_t x = vaddq_f32(xy.val[0], xy.val[1]); + x = vaddq_f32(x, z); + + uint32x4_t mask = vcltq_f32(x, minDot); + minDot = vbslq_f32( mask, x, minDot); + index = vbslq_u32(mask, local_index, index); + local_index = vaddq_u32(local_index, four); + } + break; + + case 1: + { + float32x4_t v0 = vld1q_f32_aligned_postincrement( vv ); + + // the next two lines should resolve to a single vswp d, d + float32x4_t xy0 = vcombine_f32( vget_low_f32(v0), vget_low_f32(v0)); + // the next two lines should resolve to a single vswp d, d + float32x4_t z = vdupq_lane_f32(vget_high_f32(v0), 0); + + xy0 = vmulq_f32(xy0, vLo); + + z = vmulq_f32( z, vHi); + float32x4x2_t xy = vuzpq_f32( xy0, xy0); + float32x4_t x = vaddq_f32(xy.val[0], xy.val[1]); + x = vaddq_f32(x, z); + + uint32x4_t mask = vcltq_f32(x, minDot); + minDot = vbslq_f32( mask, x, minDot); + index = vbslq_u32(mask, local_index, index); + local_index = vaddq_u32(local_index, four); + } + break; + + default: + break; + } + + + // select best answer between hi and lo results + uint32x2_t mask = vclt_f32( vget_high_f32(minDot), vget_low_f32(minDot)); + float32x2_t minDot2 = vbsl_f32(mask, vget_high_f32(minDot), vget_low_f32(minDot)); + uint32x2_t index2 = vbsl_u32(mask, vget_high_u32(index), vget_low_u32(index)); + + // select best answer between even and odd results + float32x2_t minDotO = vdup_lane_f32(minDot2, 1); + uint32x2_t indexHi = vdup_lane_u32(index2, 1); + mask = vclt_f32( minDotO, minDot2 ); + minDot2 = vbsl_f32(mask, minDotO, minDot2); + index2 = vbsl_u32(mask, indexHi, index2); + + *dotResult = vget_lane_f32( minDot2, 0); + return vget_lane_u32(index2, 0); + +} + +#else + #error Unhandled __APPLE__ arch +#endif + +#endif /* __APPLE__ */ + + diff --git a/extern/bullet/src/Bullet3Common/b3Vector3.h b/extern/bullet/src/Bullet3Common/b3Vector3.h new file mode 100644 index 000000000000..16ec02b0eda6 --- /dev/null +++ b/extern/bullet/src/Bullet3Common/b3Vector3.h @@ -0,0 +1,1344 @@ +/* +Copyright (c) 2003-2013 Gino van den Bergen / Erwin Coumans http://bulletphysics.org + +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 B3_VECTOR3_H +#define B3_VECTOR3_H + +//#include +#include "b3Scalar.h" +#include "b3MinMax.h" +#include "b3AlignedAllocator.h" + +#ifdef B3_USE_DOUBLE_PRECISION +#define b3Vector3Data b3Vector3DoubleData +#define b3Vector3DataName "b3Vector3DoubleData" +#else +#define b3Vector3Data b3Vector3FloatData +#define b3Vector3DataName "b3Vector3FloatData" +#endif //B3_USE_DOUBLE_PRECISION + +#if defined B3_USE_SSE + +//typedef uint32_t __m128i __attribute__ ((vector_size(16))); + +#ifdef _MSC_VER +#pragma warning(disable: 4556) // value of intrinsic immediate argument '4294967239' is out of range '0 - 255' +#endif + + +#define B3_SHUFFLE(x,y,z,w) ((w)<<6 | (z)<<4 | (y)<<2 | (x)) +//#define b3_pshufd_ps( _a, _mask ) (__m128) _mm_shuffle_epi32((__m128i)(_a), (_mask) ) +#define b3_pshufd_ps( _a, _mask ) _mm_shuffle_ps((_a), (_a), (_mask) ) +#define b3_splat3_ps( _a, _i ) b3_pshufd_ps((_a), B3_SHUFFLE(_i,_i,_i, 3) ) +#define b3_splat_ps( _a, _i ) b3_pshufd_ps((_a), B3_SHUFFLE(_i,_i,_i,_i) ) + +#define b3v3AbsiMask (_mm_set_epi32(0x00000000, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF)) +#define b3vAbsMask (_mm_set_epi32( 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF)) +#define b3vFFF0Mask (_mm_set_epi32(0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF)) +#define b3v3AbsfMask b3CastiTo128f(b3v3AbsiMask) +#define b3vFFF0fMask b3CastiTo128f(b3vFFF0Mask) +#define b3vxyzMaskf b3vFFF0fMask +#define b3vAbsfMask b3CastiTo128f(b3vAbsMask) + + + +const __m128 B3_ATTRIBUTE_ALIGNED16(b3vMzeroMask) = {-0.0f, -0.0f, -0.0f, -0.0f}; +const __m128 B3_ATTRIBUTE_ALIGNED16(b3v1110) = {1.0f, 1.0f, 1.0f, 0.0f}; +const __m128 B3_ATTRIBUTE_ALIGNED16(b3vHalf) = {0.5f, 0.5f, 0.5f, 0.5f}; +const __m128 B3_ATTRIBUTE_ALIGNED16(b3v1_5) = {1.5f, 1.5f, 1.5f, 1.5f}; + +#endif + +#ifdef B3_USE_NEON + +const float32x4_t B3_ATTRIBUTE_ALIGNED16(b3vMzeroMask) = (float32x4_t){-0.0f, -0.0f, -0.0f, -0.0f}; +const int32x4_t B3_ATTRIBUTE_ALIGNED16(b3vFFF0Mask) = (int32x4_t){0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0}; +const int32x4_t B3_ATTRIBUTE_ALIGNED16(b3vAbsMask) = (int32x4_t){0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF}; +const int32x4_t B3_ATTRIBUTE_ALIGNED16(b3v3AbsMask) = (int32x4_t){0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x0}; + +#endif + +class b3Vector3; +class b3Vector4; + +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) +//#if defined (B3_USE_SSE) || defined (B3_USE_NEON) +inline b3Vector3 b3MakeVector3( b3SimdFloat4 v); +inline b3Vector4 b3MakeVector4( b3SimdFloat4 vec); +#endif + +inline b3Vector3 b3MakeVector3(b3Scalar x,b3Scalar y,b3Scalar z); +inline b3Vector3 b3MakeVector3(b3Scalar x,b3Scalar y,b3Scalar z, b3Scalar w); +inline b3Vector4 b3MakeVector4(b3Scalar x,b3Scalar y,b3Scalar z,b3Scalar w); + + +/**@brief b3Vector3 can be used to represent 3D points and vectors. + * It has an un-used w component to suit 16-byte alignment when b3Vector3 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 + */ +B3_ATTRIBUTE_ALIGNED16(class) b3Vector3 +{ +public: +#if defined (B3_USE_SSE) || defined(B3_USE_NEON) // _WIN32 || ARM + union { + b3SimdFloat4 mVec128; + float m_floats[4]; + struct {float x,y,z,w;}; + + }; +#else + union + { + float m_floats[4]; + struct {float x,y,z,w;}; + }; +#endif + + +public: + + B3_DECLARE_ALIGNED_ALLOCATOR(); + +#if defined (B3_USE_SSE) || defined(B3_USE_NEON) // _WIN32 || ARM + + /*B3_FORCE_INLINE b3Vector3() + { + } + */ + + B3_FORCE_INLINE b3SimdFloat4 get128() const + { + return mVec128; + } + B3_FORCE_INLINE void set128(b3SimdFloat4 v128) + { + mVec128 = v128; + } +#endif + + public: + + + +/**@brief Add a vector to this one + * @param The vector to add to this one */ + B3_FORCE_INLINE b3Vector3& operator+=(const b3Vector3& v) + { +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + mVec128 = _mm_add_ps(mVec128, v.mVec128); +#elif defined(B3_USE_NEON) + mVec128 = vaddq_f32(mVec128, v.mVec128); +#else + m_floats[0] += v.m_floats[0]; + m_floats[1] += v.m_floats[1]; + m_floats[2] += v.m_floats[2]; +#endif + return *this; + } + + + /**@brief Subtract a vector from this one + * @param The vector to subtract */ + B3_FORCE_INLINE b3Vector3& operator-=(const b3Vector3& v) + { +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + mVec128 = _mm_sub_ps(mVec128, v.mVec128); +#elif defined(B3_USE_NEON) + mVec128 = vsubq_f32(mVec128, v.mVec128); +#else + m_floats[0] -= v.m_floats[0]; + m_floats[1] -= v.m_floats[1]; + m_floats[2] -= v.m_floats[2]; +#endif + return *this; + } + + /**@brief Scale the vector + * @param s Scale factor */ + B3_FORCE_INLINE b3Vector3& operator*=(const b3Scalar& s) + { +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + __m128 vs = _mm_load_ss(&s); // (S 0 0 0) + vs = b3_pshufd_ps(vs, 0x80); // (S S S 0.0) + mVec128 = _mm_mul_ps(mVec128, vs); +#elif defined(B3_USE_NEON) + mVec128 = vmulq_n_f32(mVec128, s); +#else + m_floats[0] *= s; + m_floats[1] *= s; + m_floats[2] *= s; +#endif + return *this; + } + + /**@brief Inversely scale the vector + * @param s Scale factor to divide by */ + B3_FORCE_INLINE b3Vector3& operator/=(const b3Scalar& s) + { + b3FullAssert(s != b3Scalar(0.0)); + +#if 0 //defined(B3_USE_SSE_IN_API) +// this code is not faster ! + __m128 vs = _mm_load_ss(&s); + vs = _mm_div_ss(b3v1110, vs); + vs = b3_pshufd_ps(vs, 0x00); // (S S S S) + + mVec128 = _mm_mul_ps(mVec128, vs); + + return *this; +#else + return *this *= b3Scalar(1.0) / s; +#endif + } + + /**@brief Return the dot product + * @param v The other vector in the dot product */ + B3_FORCE_INLINE b3Scalar dot(const b3Vector3& v) const + { +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + __m128 vd = _mm_mul_ps(mVec128, v.mVec128); + __m128 z = _mm_movehl_ps(vd, vd); + __m128 y = _mm_shuffle_ps(vd, vd, 0x55); + vd = _mm_add_ss(vd, y); + vd = _mm_add_ss(vd, z); + return _mm_cvtss_f32(vd); +#elif defined(B3_USE_NEON) + float32x4_t vd = vmulq_f32(mVec128, v.mVec128); + float32x2_t x = vpadd_f32(vget_low_f32(vd), vget_low_f32(vd)); + x = vadd_f32(x, vget_high_f32(vd)); + return vget_lane_f32(x, 0); +#else + return m_floats[0] * v.m_floats[0] + + m_floats[1] * v.m_floats[1] + + m_floats[2] * v.m_floats[2]; +#endif + } + + /**@brief Return the length of the vector squared */ + B3_FORCE_INLINE b3Scalar length2() const + { + return dot(*this); + } + + /**@brief Return the length of the vector */ + B3_FORCE_INLINE b3Scalar length() const + { + return b3Sqrt(length2()); + } + + /**@brief Return the distance squared between the ends of this and another vector + * This is symantically treating the vector like a point */ + B3_FORCE_INLINE b3Scalar distance2(const b3Vector3& v) const; + + /**@brief Return the distance between the ends of this and another vector + * This is symantically treating the vector like a point */ + B3_FORCE_INLINE b3Scalar distance(const b3Vector3& v) const; + + B3_FORCE_INLINE b3Vector3& safeNormalize() + { + b3Scalar l2 = length2(); + //triNormal.normalize(); + if (l2 >= B3_EPSILON*B3_EPSILON) + { + (*this) /= b3Sqrt(l2); + } + else + { + setValue(1, 0, 0); + } + return *this; + } + + /**@brief Normalize this vector + * x^2 + y^2 + z^2 = 1 */ + B3_FORCE_INLINE b3Vector3& normalize() + { +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + // dot product first + __m128 vd = _mm_mul_ps(mVec128, mVec128); + __m128 z = _mm_movehl_ps(vd, vd); + __m128 y = _mm_shuffle_ps(vd, vd, 0x55); + vd = _mm_add_ss(vd, y); + vd = _mm_add_ss(vd, z); + + #if 0 + vd = _mm_sqrt_ss(vd); + vd = _mm_div_ss(b3v1110, vd); + vd = b3_splat_ps(vd, 0x80); + mVec128 = _mm_mul_ps(mVec128, vd); + #else + + // NR step 1/sqrt(x) - vd is x, y is output + y = _mm_rsqrt_ss(vd); // estimate + + // one step NR + z = b3v1_5; + vd = _mm_mul_ss(vd, b3vHalf); // vd * 0.5 + //x2 = vd; + vd = _mm_mul_ss(vd, y); // vd * 0.5 * y0 + vd = _mm_mul_ss(vd, y); // vd * 0.5 * y0 * y0 + z = _mm_sub_ss(z, vd); // 1.5 - vd * 0.5 * y0 * y0 + + y = _mm_mul_ss(y, z); // y0 * (1.5 - vd * 0.5 * y0 * y0) + + y = b3_splat_ps(y, 0x80); + mVec128 = _mm_mul_ps(mVec128, y); + + #endif + + + return *this; +#else + return *this /= length(); +#endif + } + + /**@brief Return a normalized version of this vector */ + B3_FORCE_INLINE b3Vector3 normalized() const; + + /**@brief Return a rotated version of this vector + * @param wAxis The axis to rotate about + * @param angle The angle to rotate by */ + B3_FORCE_INLINE b3Vector3 rotate( const b3Vector3& wAxis, const b3Scalar angle ) const; + + /**@brief Return the angle between this and another vector + * @param v The other vector */ + B3_FORCE_INLINE b3Scalar angle(const b3Vector3& v) const + { + b3Scalar s = b3Sqrt(length2() * v.length2()); + b3FullAssert(s != b3Scalar(0.0)); + return b3Acos(dot(v) / s); + } + + /**@brief Return a vector will the absolute values of each element */ + B3_FORCE_INLINE b3Vector3 absolute() const + { +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + return b3MakeVector3(_mm_and_ps(mVec128, b3v3AbsfMask)); +#elif defined(B3_USE_NEON) + return b3Vector3(vabsq_f32(mVec128)); +#else + return b3MakeVector3( + b3Fabs(m_floats[0]), + b3Fabs(m_floats[1]), + b3Fabs(m_floats[2])); +#endif + } + + /**@brief Return the cross product between this and another vector + * @param v The other vector */ + B3_FORCE_INLINE b3Vector3 cross(const b3Vector3& v) const + { +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + __m128 T, V; + + T = b3_pshufd_ps(mVec128, B3_SHUFFLE(1, 2, 0, 3)); // (Y Z X 0) + V = b3_pshufd_ps(v.mVec128, B3_SHUFFLE(1, 2, 0, 3)); // (Y Z X 0) + + V = _mm_mul_ps(V, mVec128); + T = _mm_mul_ps(T, v.mVec128); + V = _mm_sub_ps(V, T); + + V = b3_pshufd_ps(V, B3_SHUFFLE(1, 2, 0, 3)); + return b3MakeVector3(V); +#elif defined(B3_USE_NEON) + float32x4_t T, V; + // form (Y, Z, X, _) of mVec128 and v.mVec128 + float32x2_t Tlow = vget_low_f32(mVec128); + float32x2_t Vlow = vget_low_f32(v.mVec128); + T = vcombine_f32(vext_f32(Tlow, vget_high_f32(mVec128), 1), Tlow); + V = vcombine_f32(vext_f32(Vlow, vget_high_f32(v.mVec128), 1), Vlow); + + V = vmulq_f32(V, mVec128); + T = vmulq_f32(T, v.mVec128); + V = vsubq_f32(V, T); + Vlow = vget_low_f32(V); + // form (Y, Z, X, _); + V = vcombine_f32(vext_f32(Vlow, vget_high_f32(V), 1), Vlow); + V = (float32x4_t)vandq_s32((int32x4_t)V, b3vFFF0Mask); + + return b3Vector3(V); +#else + return b3MakeVector3( + m_floats[1] * v.m_floats[2] - m_floats[2] * v.m_floats[1], + m_floats[2] * v.m_floats[0] - m_floats[0] * v.m_floats[2], + m_floats[0] * v.m_floats[1] - m_floats[1] * v.m_floats[0]); +#endif + } + + B3_FORCE_INLINE b3Scalar triple(const b3Vector3& v1, const b3Vector3& v2) const + { +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + // cross: + __m128 T = _mm_shuffle_ps(v1.mVec128, v1.mVec128, B3_SHUFFLE(1, 2, 0, 3)); // (Y Z X 0) + __m128 V = _mm_shuffle_ps(v2.mVec128, v2.mVec128, B3_SHUFFLE(1, 2, 0, 3)); // (Y Z X 0) + + V = _mm_mul_ps(V, v1.mVec128); + T = _mm_mul_ps(T, v2.mVec128); + V = _mm_sub_ps(V, T); + + V = _mm_shuffle_ps(V, V, B3_SHUFFLE(1, 2, 0, 3)); + + // dot: + V = _mm_mul_ps(V, mVec128); + __m128 z = _mm_movehl_ps(V, V); + __m128 y = _mm_shuffle_ps(V, V, 0x55); + V = _mm_add_ss(V, y); + V = _mm_add_ss(V, z); + return _mm_cvtss_f32(V); + +#elif defined(B3_USE_NEON) + // cross: + float32x4_t T, V; + // form (Y, Z, X, _) of mVec128 and v.mVec128 + float32x2_t Tlow = vget_low_f32(v1.mVec128); + float32x2_t Vlow = vget_low_f32(v2.mVec128); + T = vcombine_f32(vext_f32(Tlow, vget_high_f32(v1.mVec128), 1), Tlow); + V = vcombine_f32(vext_f32(Vlow, vget_high_f32(v2.mVec128), 1), Vlow); + + V = vmulq_f32(V, v1.mVec128); + T = vmulq_f32(T, v2.mVec128); + V = vsubq_f32(V, T); + Vlow = vget_low_f32(V); + // form (Y, Z, X, _); + V = vcombine_f32(vext_f32(Vlow, vget_high_f32(V), 1), Vlow); + + // dot: + V = vmulq_f32(mVec128, V); + float32x2_t x = vpadd_f32(vget_low_f32(V), vget_low_f32(V)); + x = vadd_f32(x, vget_high_f32(V)); + return vget_lane_f32(x, 0); +#else + return + m_floats[0] * (v1.m_floats[1] * v2.m_floats[2] - v1.m_floats[2] * v2.m_floats[1]) + + m_floats[1] * (v1.m_floats[2] * v2.m_floats[0] - v1.m_floats[0] * v2.m_floats[2]) + + m_floats[2] * (v1.m_floats[0] * v2.m_floats[1] - v1.m_floats[1] * v2.m_floats[0]); +#endif + } + + /**@brief Return the axis with the smallest value + * Note return values are 0,1,2 for x, y, or z */ + B3_FORCE_INLINE int minAxis() const + { + return m_floats[0] < m_floats[1] ? (m_floats[0] return this, t=1 => return other) */ + B3_FORCE_INLINE b3Vector3 lerp(const b3Vector3& v, const b3Scalar& t) const + { +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + __m128 vt = _mm_load_ss(&t); // (t 0 0 0) + vt = b3_pshufd_ps(vt, 0x80); // (rt rt rt 0.0) + __m128 vl = _mm_sub_ps(v.mVec128, mVec128); + vl = _mm_mul_ps(vl, vt); + vl = _mm_add_ps(vl, mVec128); + + return b3MakeVector3(vl); +#elif defined(B3_USE_NEON) + float32x4_t vl = vsubq_f32(v.mVec128, mVec128); + vl = vmulq_n_f32(vl, t); + vl = vaddq_f32(vl, mVec128); + + return b3Vector3(vl); +#else + return + b3MakeVector3( m_floats[0] + (v.m_floats[0] - m_floats[0]) * t, + m_floats[1] + (v.m_floats[1] - m_floats[1]) * t, + m_floats[2] + (v.m_floats[2] - m_floats[2]) * t); +#endif + } + + /**@brief Elementwise multiply this vector by the other + * @param v The other vector */ + B3_FORCE_INLINE b3Vector3& operator*=(const b3Vector3& v) + { +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + mVec128 = _mm_mul_ps(mVec128, v.mVec128); +#elif defined(B3_USE_NEON) + mVec128 = vmulq_f32(mVec128, v.mVec128); +#else + m_floats[0] *= v.m_floats[0]; + m_floats[1] *= v.m_floats[1]; + m_floats[2] *= v.m_floats[2]; +#endif + return *this; + } + + /**@brief Return the x value */ + B3_FORCE_INLINE const b3Scalar& getX() const { return m_floats[0]; } + /**@brief Return the y value */ + B3_FORCE_INLINE const b3Scalar& getY() const { return m_floats[1]; } + /**@brief Return the z value */ + B3_FORCE_INLINE const b3Scalar& getZ() const { return m_floats[2]; } +/**@brief Return the w value */ + B3_FORCE_INLINE const b3Scalar& getW() const { return m_floats[3]; } + + /**@brief Set the x value */ + B3_FORCE_INLINE void setX(b3Scalar _x) { m_floats[0] = _x;}; + /**@brief Set the y value */ + B3_FORCE_INLINE void setY(b3Scalar _y) { m_floats[1] = _y;}; + /**@brief Set the z value */ + B3_FORCE_INLINE void setZ(b3Scalar _z) { m_floats[2] = _z;}; + /**@brief Set the w value */ + B3_FORCE_INLINE void setW(b3Scalar _w) { m_floats[3] = _w;}; + + //B3_FORCE_INLINE b3Scalar& operator[](int i) { return (&m_floats[0])[i]; } + //B3_FORCE_INLINE const b3Scalar& operator[](int i) const { return (&m_floats[0])[i]; } + ///operator b3Scalar*() replaces operator[], using implicit conversion. We added operator != and operator == to avoid pointer comparisons. + B3_FORCE_INLINE operator b3Scalar *() { return &m_floats[0]; } + B3_FORCE_INLINE operator const b3Scalar *() const { return &m_floats[0]; } + + B3_FORCE_INLINE bool operator==(const b3Vector3& other) const + { +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + return (0xf == _mm_movemask_ps((__m128)_mm_cmpeq_ps(mVec128, other.mVec128))); +#else + return ((m_floats[3]==other.m_floats[3]) && + (m_floats[2]==other.m_floats[2]) && + (m_floats[1]==other.m_floats[1]) && + (m_floats[0]==other.m_floats[0])); +#endif + } + + B3_FORCE_INLINE bool operator!=(const b3Vector3& other) const + { + return !(*this == other); + } + + /**@brief Set each element to the max of the current values and the values of another b3Vector3 + * @param other The other b3Vector3 to compare with + */ + B3_FORCE_INLINE void setMax(const b3Vector3& other) + { +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + mVec128 = _mm_max_ps(mVec128, other.mVec128); +#elif defined(B3_USE_NEON) + mVec128 = vmaxq_f32(mVec128, other.mVec128); +#else + b3SetMax(m_floats[0], other.m_floats[0]); + b3SetMax(m_floats[1], other.m_floats[1]); + b3SetMax(m_floats[2], other.m_floats[2]); + b3SetMax(m_floats[3], other.m_floats[3]); +#endif + } + + /**@brief Set each element to the min of the current values and the values of another b3Vector3 + * @param other The other b3Vector3 to compare with + */ + B3_FORCE_INLINE void setMin(const b3Vector3& other) + { +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + mVec128 = _mm_min_ps(mVec128, other.mVec128); +#elif defined(B3_USE_NEON) + mVec128 = vminq_f32(mVec128, other.mVec128); +#else + b3SetMin(m_floats[0], other.m_floats[0]); + b3SetMin(m_floats[1], other.m_floats[1]); + b3SetMin(m_floats[2], other.m_floats[2]); + b3SetMin(m_floats[3], other.m_floats[3]); +#endif + } + + B3_FORCE_INLINE void setValue(const b3Scalar& _x, const b3Scalar& _y, const b3Scalar& _z) + { + m_floats[0]=_x; + m_floats[1]=_y; + m_floats[2]=_z; + m_floats[3] = b3Scalar(0.f); + } + + void getSkewSymmetricMatrix(b3Vector3* v0,b3Vector3* v1,b3Vector3* v2) const + { +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + + __m128 V = _mm_and_ps(mVec128, b3vFFF0fMask); + __m128 V0 = _mm_xor_ps(b3vMzeroMask, V); + __m128 V2 = _mm_movelh_ps(V0, V); + + __m128 V1 = _mm_shuffle_ps(V, V0, 0xCE); + + V0 = _mm_shuffle_ps(V0, V, 0xDB); + V2 = _mm_shuffle_ps(V2, V, 0xF9); + + v0->mVec128 = V0; + v1->mVec128 = V1; + v2->mVec128 = V2; +#else + v0->setValue(0. ,-getZ() ,getY()); + v1->setValue(getZ() ,0. ,-getX()); + v2->setValue(-getY() ,getX() ,0.); +#endif + } + + void setZero() + { +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + mVec128 = (__m128)_mm_xor_ps(mVec128, mVec128); +#elif defined(B3_USE_NEON) + int32x4_t vi = vdupq_n_s32(0); + mVec128 = vreinterpretq_f32_s32(vi); +#else + setValue(b3Scalar(0.),b3Scalar(0.),b3Scalar(0.)); +#endif + } + + B3_FORCE_INLINE bool isZero() const + { + return m_floats[0] == b3Scalar(0) && m_floats[1] == b3Scalar(0) && m_floats[2] == b3Scalar(0); + } + + B3_FORCE_INLINE bool fuzzyZero() const + { + return length2() < B3_EPSILON; + } + + B3_FORCE_INLINE void serialize(struct b3Vector3Data& dataOut) const; + + B3_FORCE_INLINE void deSerialize(const struct b3Vector3Data& dataIn); + + B3_FORCE_INLINE void serializeFloat(struct b3Vector3FloatData& dataOut) const; + + B3_FORCE_INLINE void deSerializeFloat(const struct b3Vector3FloatData& dataIn); + + B3_FORCE_INLINE void serializeDouble(struct b3Vector3DoubleData& dataOut) const; + + B3_FORCE_INLINE void deSerializeDouble(const struct b3Vector3DoubleData& dataIn); + + /**@brief returns index of maximum dot product between this and vectors in array[] + * @param array The other vectors + * @param array_count The number of other vectors + * @param dotOut The maximum dot product */ + B3_FORCE_INLINE long maxDot( const b3Vector3 *array, long array_count, b3Scalar &dotOut ) const; + + /**@brief returns index of minimum dot product between this and vectors in array[] + * @param array The other vectors + * @param array_count The number of other vectors + * @param dotOut The minimum dot product */ + B3_FORCE_INLINE long minDot( const b3Vector3 *array, long array_count, b3Scalar &dotOut ) const; + + /* create a vector as b3Vector3( this->dot( b3Vector3 v0 ), this->dot( b3Vector3 v1), this->dot( b3Vector3 v2 )) */ + B3_FORCE_INLINE b3Vector3 dot3( const b3Vector3 &v0, const b3Vector3 &v1, const b3Vector3 &v2 ) const + { +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + + __m128 a0 = _mm_mul_ps( v0.mVec128, this->mVec128 ); + __m128 a1 = _mm_mul_ps( v1.mVec128, this->mVec128 ); + __m128 a2 = _mm_mul_ps( v2.mVec128, this->mVec128 ); + __m128 b0 = _mm_unpacklo_ps( a0, a1 ); + __m128 b1 = _mm_unpackhi_ps( a0, a1 ); + __m128 b2 = _mm_unpacklo_ps( a2, _mm_setzero_ps() ); + __m128 r = _mm_movelh_ps( b0, b2 ); + r = _mm_add_ps( r, _mm_movehl_ps( b2, b0 )); + a2 = _mm_and_ps( a2, b3vxyzMaskf); + r = _mm_add_ps( r, b3CastdTo128f (_mm_move_sd( b3CastfTo128d(a2), b3CastfTo128d(b1) ))); + return b3MakeVector3(r); + +#elif defined(B3_USE_NEON) + static const uint32x4_t xyzMask = (const uint32x4_t){ -1, -1, -1, 0 }; + float32x4_t a0 = vmulq_f32( v0.mVec128, this->mVec128); + float32x4_t a1 = vmulq_f32( v1.mVec128, this->mVec128); + float32x4_t a2 = vmulq_f32( v2.mVec128, this->mVec128); + float32x2x2_t zLo = vtrn_f32( vget_high_f32(a0), vget_high_f32(a1)); + a2 = (float32x4_t) vandq_u32((uint32x4_t) a2, xyzMask ); + float32x2_t b0 = vadd_f32( vpadd_f32( vget_low_f32(a0), vget_low_f32(a1)), zLo.val[0] ); + float32x2_t b1 = vpadd_f32( vpadd_f32( vget_low_f32(a2), vget_high_f32(a2)), vdup_n_f32(0.0f)); + return b3Vector3( vcombine_f32(b0, b1) ); +#else + return b3MakeVector3( dot(v0), dot(v1), dot(v2)); +#endif + } +}; + +/**@brief Return the sum of two vectors (Point symantics)*/ +B3_FORCE_INLINE b3Vector3 +operator+(const b3Vector3& v1, const b3Vector3& v2) +{ +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + return b3MakeVector3(_mm_add_ps(v1.mVec128, v2.mVec128)); +#elif defined(B3_USE_NEON) + return b3MakeVector3(vaddq_f32(v1.mVec128, v2.mVec128)); +#else + return b3MakeVector3( + v1.m_floats[0] + v2.m_floats[0], + v1.m_floats[1] + v2.m_floats[1], + v1.m_floats[2] + v2.m_floats[2]); +#endif +} + +/**@brief Return the elementwise product of two vectors */ +B3_FORCE_INLINE b3Vector3 +operator*(const b3Vector3& v1, const b3Vector3& v2) +{ +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + return b3MakeVector3(_mm_mul_ps(v1.mVec128, v2.mVec128)); +#elif defined(B3_USE_NEON) + return b3MakeVector3(vmulq_f32(v1.mVec128, v2.mVec128)); +#else + return b3MakeVector3( + v1.m_floats[0] * v2.m_floats[0], + v1.m_floats[1] * v2.m_floats[1], + v1.m_floats[2] * v2.m_floats[2]); +#endif +} + +/**@brief Return the difference between two vectors */ +B3_FORCE_INLINE b3Vector3 +operator-(const b3Vector3& v1, const b3Vector3& v2) +{ +#if (defined(B3_USE_SSE_IN_API) && defined(B3_USE_SSE)) + + // without _mm_and_ps this code causes slowdown in Concave moving + __m128 r = _mm_sub_ps(v1.mVec128, v2.mVec128); + return b3MakeVector3(_mm_and_ps(r, b3vFFF0fMask)); +#elif defined(B3_USE_NEON) + float32x4_t r = vsubq_f32(v1.mVec128, v2.mVec128); + return b3MakeVector3((float32x4_t)vandq_s32((int32x4_t)r, b3vFFF0Mask)); +#else + return b3MakeVector3( + v1.m_floats[0] - v2.m_floats[0], + v1.m_floats[1] - v2.m_floats[1], + v1.m_floats[2] - v2.m_floats[2]); +#endif +} + +/**@brief Return the negative of the vector */ +B3_FORCE_INLINE b3Vector3 +operator-(const b3Vector3& v) +{ +#if (defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE)) + __m128 r = _mm_xor_ps(v.mVec128, b3vMzeroMask); + return b3MakeVector3(_mm_and_ps(r, b3vFFF0fMask)); +#elif defined(B3_USE_NEON) + return b3MakeVector3((b3SimdFloat4)veorq_s32((int32x4_t)v.mVec128, (int32x4_t)b3vMzeroMask)); +#else + return b3MakeVector3(-v.m_floats[0], -v.m_floats[1], -v.m_floats[2]); +#endif +} + +/**@brief Return the vector scaled by s */ +B3_FORCE_INLINE b3Vector3 +operator*(const b3Vector3& v, const b3Scalar& s) +{ +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + __m128 vs = _mm_load_ss(&s); // (S 0 0 0) + vs = b3_pshufd_ps(vs, 0x80); // (S S S 0.0) + return b3MakeVector3(_mm_mul_ps(v.mVec128, vs)); +#elif defined(B3_USE_NEON) + float32x4_t r = vmulq_n_f32(v.mVec128, s); + return b3MakeVector3((float32x4_t)vandq_s32((int32x4_t)r, b3vFFF0Mask)); +#else + return b3MakeVector3(v.m_floats[0] * s, v.m_floats[1] * s, v.m_floats[2] * s); +#endif +} + +/**@brief Return the vector scaled by s */ +B3_FORCE_INLINE b3Vector3 +operator*(const b3Scalar& s, const b3Vector3& v) +{ + return v * s; +} + +/**@brief Return the vector inversely scaled by s */ +B3_FORCE_INLINE b3Vector3 +operator/(const b3Vector3& v, const b3Scalar& s) +{ + b3FullAssert(s != b3Scalar(0.0)); +#if 0 //defined(B3_USE_SSE_IN_API) +// this code is not faster ! + __m128 vs = _mm_load_ss(&s); + vs = _mm_div_ss(b3v1110, vs); + vs = b3_pshufd_ps(vs, 0x00); // (S S S S) + + return b3Vector3(_mm_mul_ps(v.mVec128, vs)); +#else + return v * (b3Scalar(1.0) / s); +#endif +} + +/**@brief Return the vector inversely scaled by s */ +B3_FORCE_INLINE b3Vector3 +operator/(const b3Vector3& v1, const b3Vector3& v2) +{ +#if (defined(B3_USE_SSE_IN_API)&& defined (B3_USE_SSE)) + __m128 vec = _mm_div_ps(v1.mVec128, v2.mVec128); + vec = _mm_and_ps(vec, b3vFFF0fMask); + return b3MakeVector3(vec); +#elif defined(B3_USE_NEON) + float32x4_t x, y, v, m; + + x = v1.mVec128; + y = v2.mVec128; + + v = vrecpeq_f32(y); // v ~ 1/y + m = vrecpsq_f32(y, v); // m = (2-v*y) + v = vmulq_f32(v, m); // vv = v*m ~~ 1/y + m = vrecpsq_f32(y, v); // mm = (2-vv*y) + v = vmulq_f32(v, x); // x*vv + v = vmulq_f32(v, m); // (x*vv)*(2-vv*y) = x*(vv(2-vv*y)) ~~~ x/y + + return b3Vector3(v); +#else + return b3MakeVector3( + v1.m_floats[0] / v2.m_floats[0], + v1.m_floats[1] / v2.m_floats[1], + v1.m_floats[2] / v2.m_floats[2]); +#endif +} + +/**@brief Return the dot product between two vectors */ +B3_FORCE_INLINE b3Scalar +b3Dot(const b3Vector3& v1, const b3Vector3& v2) +{ + return v1.dot(v2); +} + + +/**@brief Return the distance squared between two vectors */ +B3_FORCE_INLINE b3Scalar +b3Distance2(const b3Vector3& v1, const b3Vector3& v2) +{ + return v1.distance2(v2); +} + + +/**@brief Return the distance between two vectors */ +B3_FORCE_INLINE b3Scalar +b3Distance(const b3Vector3& v1, const b3Vector3& v2) +{ + return v1.distance(v2); +} + +/**@brief Return the angle between two vectors */ +B3_FORCE_INLINE b3Scalar +b3Angle(const b3Vector3& v1, const b3Vector3& v2) +{ + return v1.angle(v2); +} + +/**@brief Return the cross product of two vectors */ +B3_FORCE_INLINE b3Vector3 +b3Cross(const b3Vector3& v1, const b3Vector3& v2) +{ + return v1.cross(v2); +} + +B3_FORCE_INLINE b3Scalar +b3Triple(const b3Vector3& v1, const b3Vector3& v2, const b3Vector3& v3) +{ + return v1.triple(v2, v3); +} + +/**@brief Return the linear interpolation between two vectors + * @param v1 One vector + * @param v2 The other vector + * @param t The ration of this to v (t = 0 => return v1, t=1 => return v2) */ +B3_FORCE_INLINE b3Vector3 +b3Lerp(const b3Vector3& v1, const b3Vector3& v2, const b3Scalar& t) +{ + return v1.lerp(v2, t); +} + + + +B3_FORCE_INLINE b3Scalar b3Vector3::distance2(const b3Vector3& v) const +{ + return (v - *this).length2(); +} + +B3_FORCE_INLINE b3Scalar b3Vector3::distance(const b3Vector3& v) const +{ + return (v - *this).length(); +} + +B3_FORCE_INLINE b3Vector3 b3Vector3::normalized() const +{ +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + b3Vector3 norm = *this; + + return norm.normalize(); +#else + return *this / length(); +#endif +} + +B3_FORCE_INLINE b3Vector3 b3Vector3::rotate( const b3Vector3& wAxis, const b3Scalar _angle ) const +{ + // wAxis must be a unit lenght vector + +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + + __m128 O = _mm_mul_ps(wAxis.mVec128, mVec128); + b3Scalar ssin = b3Sin( _angle ); + __m128 C = wAxis.cross( b3MakeVector3(mVec128) ).mVec128; + O = _mm_and_ps(O, b3vFFF0fMask); + b3Scalar scos = b3Cos( _angle ); + + __m128 vsin = _mm_load_ss(&ssin); // (S 0 0 0) + __m128 vcos = _mm_load_ss(&scos); // (S 0 0 0) + + __m128 Y = b3_pshufd_ps(O, 0xC9); // (Y Z X 0) + __m128 Z = b3_pshufd_ps(O, 0xD2); // (Z X Y 0) + O = _mm_add_ps(O, Y); + vsin = b3_pshufd_ps(vsin, 0x80); // (S S S 0) + O = _mm_add_ps(O, Z); + vcos = b3_pshufd_ps(vcos, 0x80); // (S S S 0) + + vsin = vsin * C; + O = O * wAxis.mVec128; + __m128 X = mVec128 - O; + + O = O + vsin; + vcos = vcos * X; + O = O + vcos; + + return b3MakeVector3(O); +#else + b3Vector3 o = wAxis * wAxis.dot( *this ); + b3Vector3 _x = *this - o; + b3Vector3 _y; + + _y = wAxis.cross( *this ); + + return ( o + _x * b3Cos( _angle ) + _y * b3Sin( _angle ) ); +#endif +} + +B3_FORCE_INLINE long b3Vector3::maxDot( const b3Vector3 *array, long array_count, b3Scalar &dotOut ) const +{ +#if defined (B3_USE_SSE) || defined (B3_USE_NEON) + #if defined _WIN32 || defined (B3_USE_SSE) + const long scalar_cutoff = 10; + long b3_maxdot_large( const float *array, const float *vec, unsigned long array_count, float *dotOut ); + #elif defined B3_USE_NEON + const long scalar_cutoff = 4; + extern long (*_maxdot_large)( const float *array, const float *vec, unsigned long array_count, float *dotOut ); + #endif + if( array_count < scalar_cutoff ) +#else + +#endif//B3_USE_SSE || B3_USE_NEON + { + b3Scalar maxDot = -B3_INFINITY; + int i = 0; + int ptIndex = -1; + for( i = 0; i < array_count; i++ ) + { + b3Scalar dot = array[i].dot(*this); + + if( dot > maxDot ) + { + maxDot = dot; + ptIndex = i; + } + } + + b3Assert(ptIndex>=0); + if (ptIndex<0) + { + ptIndex = 0; + } + dotOut = maxDot; + return ptIndex; + } +#if defined (B3_USE_SSE) || defined (B3_USE_NEON) + return b3_maxdot_large( (float*) array, (float*) &m_floats[0], array_count, &dotOut ); +#endif +} + +B3_FORCE_INLINE long b3Vector3::minDot( const b3Vector3 *array, long array_count, b3Scalar &dotOut ) const +{ +#if defined (B3_USE_SSE) || defined (B3_USE_NEON) + #if defined B3_USE_SSE + const long scalar_cutoff = 10; + long b3_mindot_large( const float *array, const float *vec, unsigned long array_count, float *dotOut ); + #elif defined B3_USE_NEON + const long scalar_cutoff = 4; + extern long (*b3_mindot_large)( const float *array, const float *vec, unsigned long array_count, float *dotOut ); + #else + #error unhandled arch! + #endif + + if( array_count < scalar_cutoff ) +#endif//B3_USE_SSE || B3_USE_NEON + { + b3Scalar minDot = B3_INFINITY; + int i = 0; + int ptIndex = -1; + + for( i = 0; i < array_count; i++ ) + { + b3Scalar dot = array[i].dot(*this); + + if( dot < minDot ) + { + minDot = dot; + ptIndex = i; + } + } + + dotOut = minDot; + + return ptIndex; + } +#if defined (B3_USE_SSE) || defined (B3_USE_NEON) + return b3_mindot_large( (float*) array, (float*) &m_floats[0], array_count, &dotOut ); +#endif +} + + +class b3Vector4 : public b3Vector3 +{ +public: + + + + + + + B3_FORCE_INLINE b3Vector4 absolute4() const + { +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + return b3MakeVector4(_mm_and_ps(mVec128, b3vAbsfMask)); +#elif defined(B3_USE_NEON) + return b3Vector4(vabsq_f32(mVec128)); +#else + return b3MakeVector4( + b3Fabs(m_floats[0]), + b3Fabs(m_floats[1]), + b3Fabs(m_floats[2]), + b3Fabs(m_floats[3])); +#endif + } + + + b3Scalar getW() const { return m_floats[3];} + + + B3_FORCE_INLINE int maxAxis4() const + { + int maxIndex = -1; + b3Scalar maxVal = b3Scalar(-B3_LARGE_FLOAT); + if (m_floats[0] > maxVal) + { + maxIndex = 0; + maxVal = m_floats[0]; + } + if (m_floats[1] > maxVal) + { + maxIndex = 1; + maxVal = m_floats[1]; + } + if (m_floats[2] > maxVal) + { + maxIndex = 2; + maxVal =m_floats[2]; + } + if (m_floats[3] > maxVal) + { + maxIndex = 3; + } + + return maxIndex; + } + + + B3_FORCE_INLINE int minAxis4() const + { + int minIndex = -1; + b3Scalar minVal = b3Scalar(B3_LARGE_FLOAT); + if (m_floats[0] < minVal) + { + minIndex = 0; + minVal = m_floats[0]; + } + if (m_floats[1] < minVal) + { + minIndex = 1; + minVal = m_floats[1]; + } + if (m_floats[2] < minVal) + { + minIndex = 2; + minVal =m_floats[2]; + } + if (m_floats[3] < minVal) + { + minIndex = 3; + minVal = m_floats[3]; + } + + return minIndex; + } + + + B3_FORCE_INLINE int closestAxis4() const + { + return absolute4().maxAxis4(); + } + + + + + /**@brief Set x,y,z and zero w + * @param x Value of x + * @param y Value of y + * @param z Value of z + */ + + +/* void getValue(b3Scalar *m) const + { + m[0] = m_floats[0]; + m[1] = m_floats[1]; + m[2] =m_floats[2]; + } +*/ +/**@brief Set the values + * @param x Value of x + * @param y Value of y + * @param z Value of z + * @param w Value of w + */ + B3_FORCE_INLINE void setValue(const b3Scalar& _x, const b3Scalar& _y, const b3Scalar& _z,const b3Scalar& _w) + { + m_floats[0]=_x; + m_floats[1]=_y; + m_floats[2]=_z; + m_floats[3]=_w; + } + + +}; + + +///b3SwapVector3Endian swaps vector endianness, useful for network and cross-platform serialization +B3_FORCE_INLINE void b3SwapScalarEndian(const b3Scalar& sourceVal, b3Scalar& destVal) +{ + #ifdef B3_USE_DOUBLE_PRECISION + unsigned char* dest = (unsigned char*) &destVal; + unsigned char* src = (unsigned char*) &sourceVal; + dest[0] = src[7]; + dest[1] = src[6]; + dest[2] = src[5]; + dest[3] = src[4]; + dest[4] = src[3]; + dest[5] = src[2]; + dest[6] = src[1]; + dest[7] = src[0]; +#else + unsigned char* dest = (unsigned char*) &destVal; + unsigned char* src = (unsigned char*) &sourceVal; + dest[0] = src[3]; + dest[1] = src[2]; + dest[2] = src[1]; + dest[3] = src[0]; +#endif //B3_USE_DOUBLE_PRECISION +} +///b3SwapVector3Endian swaps vector endianness, useful for network and cross-platform serialization +B3_FORCE_INLINE void b3SwapVector3Endian(const b3Vector3& sourceVec, b3Vector3& destVec) +{ + for (int i=0;i<4;i++) + { + b3SwapScalarEndian(sourceVec[i],destVec[i]); + } + +} + +///b3UnSwapVector3Endian swaps vector endianness, useful for network and cross-platform serialization +B3_FORCE_INLINE void b3UnSwapVector3Endian(b3Vector3& vector) +{ + + b3Vector3 swappedVec; + for (int i=0;i<4;i++) + { + b3SwapScalarEndian(vector[i],swappedVec[i]); + } + vector = swappedVec; +} + +template +B3_FORCE_INLINE void b3PlaneSpace1 (const T& n, T& p, T& q) +{ + if (b3Fabs(n[2]) > B3_SQRT12) { + // choose p in y-z plane + b3Scalar a = n[1]*n[1] + n[2]*n[2]; + b3Scalar k = b3RecipSqrt (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 + b3Scalar a = n[0]*n[0] + n[1]*n[1]; + b3Scalar k = b3RecipSqrt (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; + } +} + + +struct b3Vector3FloatData +{ + float m_floats[4]; +}; + +struct b3Vector3DoubleData +{ + double m_floats[4]; + +}; + +B3_FORCE_INLINE void b3Vector3::serializeFloat(struct b3Vector3FloatData& dataOut) const +{ + ///could also do a memcpy, check if it is worth it + for (int i=0;i<4;i++) + dataOut.m_floats[i] = float(m_floats[i]); +} + +B3_FORCE_INLINE void b3Vector3::deSerializeFloat(const struct b3Vector3FloatData& dataIn) +{ + for (int i=0;i<4;i++) + m_floats[i] = b3Scalar(dataIn.m_floats[i]); +} + + +B3_FORCE_INLINE void b3Vector3::serializeDouble(struct b3Vector3DoubleData& dataOut) const +{ + ///could also do a memcpy, check if it is worth it + for (int i=0;i<4;i++) + dataOut.m_floats[i] = double(m_floats[i]); +} + +B3_FORCE_INLINE void b3Vector3::deSerializeDouble(const struct b3Vector3DoubleData& dataIn) +{ + for (int i=0;i<4;i++) + m_floats[i] = b3Scalar(dataIn.m_floats[i]); +} + + +B3_FORCE_INLINE void b3Vector3::serialize(struct b3Vector3Data& dataOut) const +{ + ///could also do a memcpy, check if it is worth it + for (int i=0;i<4;i++) + dataOut.m_floats[i] = m_floats[i]; +} + +B3_FORCE_INLINE void b3Vector3::deSerialize(const struct b3Vector3Data& dataIn) +{ + for (int i=0;i<4;i++) + m_floats[i] = dataIn.m_floats[i]; +} + + + + +inline b3Vector3 b3MakeVector3(b3Scalar x,b3Scalar y,b3Scalar z) +{ + b3Vector3 tmp; + tmp.setValue(x,y,z); + return tmp; +} + +inline b3Vector3 b3MakeVector3(b3Scalar x,b3Scalar y,b3Scalar z, b3Scalar w) +{ + b3Vector3 tmp; + tmp.setValue(x,y,z); + tmp.w = w; + return tmp; +} + +inline b3Vector4 b3MakeVector4(b3Scalar x,b3Scalar y,b3Scalar z,b3Scalar w) +{ + b3Vector4 tmp; + tmp.setValue(x,y,z,w); + return tmp; +} + +#if defined(B3_USE_SSE_IN_API) && defined (B3_USE_SSE) + +inline b3Vector3 b3MakeVector3( b3SimdFloat4 v) +{ + b3Vector3 tmp; + tmp.set128(v); + return tmp; +} + +inline b3Vector4 b3MakeVector4(b3SimdFloat4 vec) +{ + b3Vector4 tmp; + tmp.set128(vec); + return tmp; +} + +#endif + + +#endif //B3_VECTOR3_H diff --git a/extern/bullet/src/Bullet3Common/premake4.lua b/extern/bullet/src/Bullet3Common/premake4.lua new file mode 100644 index 000000000000..1331c6327e8b --- /dev/null +++ b/extern/bullet/src/Bullet3Common/premake4.lua @@ -0,0 +1,12 @@ + project "Bullet3Common" + + language "C++" + + kind "StaticLib" + + includedirs {".."} + + files { + "*.cpp", + "*.h" + } diff --git a/extern/bullet/src/Bullet3Common/shared/b3Float4.h b/extern/bullet/src/Bullet3Common/shared/b3Float4.h new file mode 100644 index 000000000000..5e4b95bcee15 --- /dev/null +++ b/extern/bullet/src/Bullet3Common/shared/b3Float4.h @@ -0,0 +1,97 @@ +#ifndef B3_FLOAT4_H +#define B3_FLOAT4_H + +#include "Bullet3Common/shared/b3PlatformDefinitions.h" + +#ifdef __cplusplus + #include "Bullet3Common/b3Vector3.h" + #define b3Float4 b3Vector3 + #define b3Float4ConstArg const b3Vector3& + #define b3Dot3F4 b3Dot + #define b3Cross3 b3Cross + #define b3MakeFloat4 b3MakeVector3 + inline b3Vector3 b3Normalized(const b3Vector3& vec) + { + return vec.normalized(); + } + + inline b3Float4 b3FastNormalized3(b3Float4ConstArg v) + { + return v.normalized(); + } + + inline b3Float4 b3MaxFloat4 (const b3Float4& a, const b3Float4& b) + { + b3Float4 tmp = a; + tmp.setMax(b); + return tmp; + } + inline b3Float4 b3MinFloat4 (const b3Float4& a, const b3Float4& b) + { + b3Float4 tmp = a; + tmp.setMin(b); + return tmp; + } + + + +#else + typedef float4 b3Float4; + #define b3Float4ConstArg const b3Float4 + #define b3MakeFloat4 (float4) + float b3Dot3F4(b3Float4ConstArg v0,b3Float4ConstArg v1) + { + float4 a1 = b3MakeFloat4(v0.xyz,0.f); + float4 b1 = b3MakeFloat4(v1.xyz,0.f); + return dot(a1, b1); + } + b3Float4 b3Cross3(b3Float4ConstArg v0,b3Float4ConstArg v1) + { + float4 a1 = b3MakeFloat4(v0.xyz,0.f); + float4 b1 = b3MakeFloat4(v1.xyz,0.f); + return cross(a1, b1); + } + #define b3MinFloat4 min + #define b3MaxFloat4 max + + #define b3Normalized(a) normalize(a) + +#endif + + + +inline bool b3IsAlmostZero(b3Float4ConstArg v) +{ + if(b3Fabs(v.x)>1e-6 || b3Fabs(v.y)>1e-6 || b3Fabs(v.z)>1e-6) + return false; + return true; +} + + +inline int b3MaxDot( b3Float4ConstArg vec, __global const b3Float4* vecArray, int vecLen, float* dotOut ) +{ + float maxDot = -B3_INFINITY; + int i = 0; + int ptIndex = -1; + for( i = 0; i < vecLen; i++ ) + { + float dot = b3Dot3F4(vecArray[i],vec); + + if( dot > maxDot ) + { + maxDot = dot; + ptIndex = i; + } + } + b3Assert(ptIndex>=0); + if (ptIndex<0) + { + ptIndex = 0; + } + *dotOut = maxDot; + return ptIndex; +} + + + +#endif //B3_FLOAT4_H diff --git a/extern/bullet/src/Bullet3Common/shared/b3Int2.h b/extern/bullet/src/Bullet3Common/shared/b3Int2.h new file mode 100644 index 000000000000..f1d01f81a570 --- /dev/null +++ b/extern/bullet/src/Bullet3Common/shared/b3Int2.h @@ -0,0 +1,64 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org + +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 B3_INT2_H +#define B3_INT2_H + +#ifdef __cplusplus + +struct b3UnsignedInt2 +{ + union + { + struct + { + unsigned int x,y; + }; + struct + { + unsigned int s[2]; + }; + }; +}; + +struct b3Int2 +{ + union + { + struct + { + int x,y; + }; + struct + { + int s[2]; + }; + }; +}; + +inline b3Int2 b3MakeInt2(int x, int y) +{ + b3Int2 v; + v.s[0] = x; v.s[1] = y; + return v; +} +#else + +#define b3UnsignedInt2 uint2 +#define b3Int2 int2 +#define b3MakeInt2 (int2) + +#endif //__cplusplus +#endif \ No newline at end of file diff --git a/extern/bullet/src/Bullet3Common/shared/b3Int4.h b/extern/bullet/src/Bullet3Common/shared/b3Int4.h new file mode 100644 index 000000000000..aa02d6beef90 --- /dev/null +++ b/extern/bullet/src/Bullet3Common/shared/b3Int4.h @@ -0,0 +1,68 @@ +#ifndef B3_INT4_H +#define B3_INT4_H + +#ifdef __cplusplus + +#include "Bullet3Common/b3Scalar.h" + + +B3_ATTRIBUTE_ALIGNED16(struct) b3UnsignedInt4 +{ + B3_DECLARE_ALIGNED_ALLOCATOR(); + + union + { + struct + { + unsigned int x,y,z,w; + }; + struct + { + unsigned int s[4]; + }; + }; +}; + +B3_ATTRIBUTE_ALIGNED16(struct) b3Int4 +{ + B3_DECLARE_ALIGNED_ALLOCATOR(); + + union + { + struct + { + int x,y,z,w; + }; + struct + { + int s[4]; + }; + }; +}; + +B3_FORCE_INLINE b3Int4 b3MakeInt4(int x, int y, int z, int w = 0) +{ + b3Int4 v; + v.s[0] = x; v.s[1] = y; v.s[2] = z; v.s[3] = w; + return v; +} + +B3_FORCE_INLINE b3UnsignedInt4 b3MakeUnsignedInt4(unsigned int x, unsigned int y, unsigned int z, unsigned int w = 0) +{ + b3UnsignedInt4 v; + v.s[0] = x; v.s[1] = y; v.s[2] = z; v.s[3] = w; + return v; +} + +#else + + +#define b3UnsignedInt4 uint4 +#define b3Int4 int4 +#define b3MakeInt4 (int4) +#define b3MakeUnsignedInt4 (uint4) + + +#endif //__cplusplus + +#endif //B3_INT4_H diff --git a/extern/bullet/src/Bullet3Common/shared/b3Mat3x3.h b/extern/bullet/src/Bullet3Common/shared/b3Mat3x3.h new file mode 100644 index 000000000000..7b1fef32f84b --- /dev/null +++ b/extern/bullet/src/Bullet3Common/shared/b3Mat3x3.h @@ -0,0 +1,179 @@ + +#ifndef B3_MAT3x3_H +#define B3_MAT3x3_H + +#include "Bullet3Common/shared/b3Quat.h" + + +#ifdef __cplusplus + +#include "Bullet3Common/b3Matrix3x3.h" + +#define b3Mat3x3 b3Matrix3x3 +#define b3Mat3x3ConstArg const b3Matrix3x3& + +inline b3Mat3x3 b3QuatGetRotationMatrix(b3QuatConstArg quat) +{ + return b3Mat3x3(quat); +} + +inline b3Mat3x3 b3AbsoluteMat3x3(b3Mat3x3ConstArg mat) +{ + return mat.absolute(); +} + +#define b3GetRow(m,row) m.getRow(row) + +__inline +b3Float4 mtMul3(b3Float4ConstArg a, b3Mat3x3ConstArg b) +{ + return b*a; +} + + +#else + +typedef struct +{ + b3Float4 m_row[3]; +}b3Mat3x3; + +#define b3Mat3x3ConstArg const b3Mat3x3 +#define b3GetRow(m,row) (m.m_row[row]) + +inline b3Mat3x3 b3QuatGetRotationMatrix(b3Quat quat) +{ + b3Float4 quat2 = (b3Float4)(quat.x*quat.x, quat.y*quat.y, quat.z*quat.z, 0.f); + b3Mat3x3 out; + + out.m_row[0].x=1-2*quat2.y-2*quat2.z; + out.m_row[0].y=2*quat.x*quat.y-2*quat.w*quat.z; + out.m_row[0].z=2*quat.x*quat.z+2*quat.w*quat.y; + out.m_row[0].w = 0.f; + + out.m_row[1].x=2*quat.x*quat.y+2*quat.w*quat.z; + out.m_row[1].y=1-2*quat2.x-2*quat2.z; + out.m_row[1].z=2*quat.y*quat.z-2*quat.w*quat.x; + out.m_row[1].w = 0.f; + + out.m_row[2].x=2*quat.x*quat.z-2*quat.w*quat.y; + out.m_row[2].y=2*quat.y*quat.z+2*quat.w*quat.x; + out.m_row[2].z=1-2*quat2.x-2*quat2.y; + out.m_row[2].w = 0.f; + + return out; +} + +inline b3Mat3x3 b3AbsoluteMat3x3(b3Mat3x3ConstArg matIn) +{ + b3Mat3x3 out; + out.m_row[0] = fabs(matIn.m_row[0]); + out.m_row[1] = fabs(matIn.m_row[1]); + out.m_row[2] = fabs(matIn.m_row[2]); + return out; +} + + +__inline +b3Mat3x3 mtZero(); + +__inline +b3Mat3x3 mtIdentity(); + +__inline +b3Mat3x3 mtTranspose(b3Mat3x3 m); + +__inline +b3Mat3x3 mtMul(b3Mat3x3 a, b3Mat3x3 b); + +__inline +b3Float4 mtMul1(b3Mat3x3 a, b3Float4 b); + +__inline +b3Float4 mtMul3(b3Float4 a, b3Mat3x3 b); + +__inline +b3Mat3x3 mtZero() +{ + b3Mat3x3 m; + m.m_row[0] = (b3Float4)(0.f); + m.m_row[1] = (b3Float4)(0.f); + m.m_row[2] = (b3Float4)(0.f); + return m; +} + +__inline +b3Mat3x3 mtIdentity() +{ + b3Mat3x3 m; + m.m_row[0] = (b3Float4)(1,0,0,0); + m.m_row[1] = (b3Float4)(0,1,0,0); + m.m_row[2] = (b3Float4)(0,0,1,0); + return m; +} + +__inline +b3Mat3x3 mtTranspose(b3Mat3x3 m) +{ + b3Mat3x3 out; + out.m_row[0] = (b3Float4)(m.m_row[0].x, m.m_row[1].x, m.m_row[2].x, 0.f); + out.m_row[1] = (b3Float4)(m.m_row[0].y, m.m_row[1].y, m.m_row[2].y, 0.f); + out.m_row[2] = (b3Float4)(m.m_row[0].z, m.m_row[1].z, m.m_row[2].z, 0.f); + return out; +} + +__inline +b3Mat3x3 mtMul(b3Mat3x3 a, b3Mat3x3 b) +{ + b3Mat3x3 transB; + transB = mtTranspose( b ); + b3Mat3x3 ans; + // why this doesn't run when 0ing in the for{} + a.m_row[0].w = 0.f; + a.m_row[1].w = 0.f; + a.m_row[2].w = 0.f; + for(int i=0; i<3; i++) + { +// a.m_row[i].w = 0.f; + ans.m_row[i].x = b3Dot3F4(a.m_row[i],transB.m_row[0]); + ans.m_row[i].y = b3Dot3F4(a.m_row[i],transB.m_row[1]); + ans.m_row[i].z = b3Dot3F4(a.m_row[i],transB.m_row[2]); + ans.m_row[i].w = 0.f; + } + return ans; +} + +__inline +b3Float4 mtMul1(b3Mat3x3 a, b3Float4 b) +{ + b3Float4 ans; + ans.x = b3Dot3F4( a.m_row[0], b ); + ans.y = b3Dot3F4( a.m_row[1], b ); + ans.z = b3Dot3F4( a.m_row[2], b ); + ans.w = 0.f; + return ans; +} + +__inline +b3Float4 mtMul3(b3Float4 a, b3Mat3x3 b) +{ + b3Float4 colx = b3MakeFloat4(b.m_row[0].x, b.m_row[1].x, b.m_row[2].x, 0); + b3Float4 coly = b3MakeFloat4(b.m_row[0].y, b.m_row[1].y, b.m_row[2].y, 0); + b3Float4 colz = b3MakeFloat4(b.m_row[0].z, b.m_row[1].z, b.m_row[2].z, 0); + + b3Float4 ans; + ans.x = b3Dot3F4( a, colx ); + ans.y = b3Dot3F4( a, coly ); + ans.z = b3Dot3F4( a, colz ); + return ans; +} + + +#endif + + + + + + +#endif //B3_MAT3x3_H diff --git a/extern/bullet/src/Bullet3Common/shared/b3PlatformDefinitions.h b/extern/bullet/src/Bullet3Common/shared/b3PlatformDefinitions.h new file mode 100644 index 000000000000..1c133fb08896 --- /dev/null +++ b/extern/bullet/src/Bullet3Common/shared/b3PlatformDefinitions.h @@ -0,0 +1,41 @@ +#ifndef B3_PLATFORM_DEFINITIONS_H +#define B3_PLATFORM_DEFINITIONS_H + +struct MyTest +{ + int bla; +}; + +#ifdef __cplusplus +//#define b3ConstArray(a) const b3AlignedObjectArray& +#define b3ConstArray(a) const a* +#define b3AtomicInc(a) ((*a)++) + +inline int b3AtomicAdd (volatile int *p, int val) +{ + int oldValue = *p; + int newValue = oldValue+val; + *p = newValue; + return oldValue; +} + +#define __global + +#define B3_STATIC static +#else +//keep B3_LARGE_FLOAT*B3_LARGE_FLOAT < FLT_MAX +#define B3_LARGE_FLOAT 1e18f +#define B3_INFINITY 1e18f +#define b3Assert(a) +#define b3ConstArray(a) __global const a* +#define b3AtomicInc atomic_inc +#define b3AtomicAdd atomic_add +#define b3Fabs fabs +#define b3Sqrt native_sqrt +#define b3Sin native_sin +#define b3Cos native_cos + +#define B3_STATIC +#endif + +#endif diff --git a/extern/bullet/src/Bullet3Common/shared/b3Quat.h b/extern/bullet/src/Bullet3Common/shared/b3Quat.h new file mode 100644 index 000000000000..f262d5e08f41 --- /dev/null +++ b/extern/bullet/src/Bullet3Common/shared/b3Quat.h @@ -0,0 +1,103 @@ +#ifndef B3_QUAT_H +#define B3_QUAT_H + +#include "Bullet3Common/shared/b3PlatformDefinitions.h" +#include "Bullet3Common/shared/b3Float4.h" + +#ifdef __cplusplus + #include "Bullet3Common/b3Quaternion.h" + #include "Bullet3Common/b3Transform.h" + + #define b3Quat b3Quaternion + #define b3QuatConstArg const b3Quaternion& + inline b3Quat b3QuatInverse(b3QuatConstArg orn) + { + return orn.inverse(); + } + + inline b3Float4 b3TransformPoint(b3Float4ConstArg point, b3Float4ConstArg translation, b3QuatConstArg orientation) + { + b3Transform tr; + tr.setOrigin(translation); + tr.setRotation(orientation); + return tr(point); + } + +#else + typedef float4 b3Quat; + #define b3QuatConstArg const b3Quat + + +inline float4 b3FastNormalize4(float4 v) +{ + v = (float4)(v.xyz,0.f); + return fast_normalize(v); +} + +inline b3Quat b3QuatMul(b3Quat a, b3Quat b); +inline b3Quat b3QuatNormalized(b3QuatConstArg in); +inline b3Quat b3QuatRotate(b3QuatConstArg q, b3QuatConstArg vec); +inline b3Quat b3QuatInvert(b3QuatConstArg q); +inline b3Quat b3QuatInverse(b3QuatConstArg q); + +inline b3Quat b3QuatMul(b3QuatConstArg a, b3QuatConstArg b) +{ + b3Quat ans; + ans = b3Cross3( a, b ); + ans += a.w*b+b.w*a; +// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z); + ans.w = a.w*b.w - b3Dot3F4(a, b); + return ans; +} + +inline b3Quat b3QuatNormalized(b3QuatConstArg in) +{ + b3Quat q; + q=in; + //return b3FastNormalize4(in); + float len = native_sqrt(dot(q, q)); + if(len > 0.f) + { + q *= 1.f / len; + } + else + { + q.x = q.y = q.z = 0.f; + q.w = 1.f; + } + return q; +} +inline float4 b3QuatRotate(b3QuatConstArg q, b3QuatConstArg vec) +{ + b3Quat qInv = b3QuatInvert( q ); + float4 vcpy = vec; + vcpy.w = 0.f; + float4 out = b3QuatMul(b3QuatMul(q,vcpy),qInv); + return out; +} + + + +inline b3Quat b3QuatInverse(b3QuatConstArg q) +{ + return (b3Quat)(-q.xyz, q.w); +} + +inline b3Quat b3QuatInvert(b3QuatConstArg q) +{ + return (b3Quat)(-q.xyz, q.w); +} + +inline float4 b3QuatInvRotate(b3QuatConstArg q, b3QuatConstArg vec) +{ + return b3QuatRotate( b3QuatInvert( q ), vec ); +} + +inline b3Float4 b3TransformPoint(b3Float4ConstArg point, b3Float4ConstArg translation, b3QuatConstArg orientation) +{ + return b3QuatRotate( orientation, point ) + (translation); +} + +#endif + +#endif //B3_QUAT_H diff --git a/extern/bullet/src/Bullet3Dynamics/CMakeLists.txt b/extern/bullet/src/Bullet3Dynamics/CMakeLists.txt new file mode 100644 index 000000000000..94c120d9b54f --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/CMakeLists.txt @@ -0,0 +1,61 @@ + +INCLUDE_DIRECTORIES( + ${BULLET_PHYSICS_SOURCE_DIR}/src +) + +SET(Bullet3Dynamics_SRCS + b3CpuRigidBodyPipeline.cpp + ConstraintSolver/b3FixedConstraint.cpp + ConstraintSolver/b3Generic6DofConstraint.cpp + ConstraintSolver/b3PgsJacobiSolver.cpp + ConstraintSolver/b3Point2PointConstraint.cpp + ConstraintSolver/b3TypedConstraint.cpp +) + +SET(Bullet3Dynamics_HDRS + b3CpuRigidBodyPipeline.h + ConstraintSolver/b3ContactSolverInfo.h + ConstraintSolver/b3FixedConstraint.h + ConstraintSolver/b3Generic6DofConstraint.h + ConstraintSolver/b3JacobianEntry.h + ConstraintSolver/b3PgsJacobiSolver.h + ConstraintSolver/b3Point2PointConstraint.h + ConstraintSolver/b3SolverBody.h + ConstraintSolver/b3SolverConstraint.h + ConstraintSolver/b3TypedConstraint.h + shared/b3ContactConstraint4.h + shared/b3ConvertConstraint4.h + shared/b3Inertia.h + shared/b3IntegrateTransforms.h +) + +ADD_LIBRARY(Bullet3Dynamics ${Bullet3Dynamics_SRCS} ${Bullet3Dynamics_HDRS}) +if (BUILD_SHARED_LIBS) + target_link_libraries(Bullet3Dynamics Bullet3Collision) +endif () +SET_TARGET_PROPERTIES(Bullet3Dynamics PROPERTIES VERSION ${BULLET_VERSION}) +SET_TARGET_PROPERTIES(Bullet3Dynamics PROPERTIES SOVERSION ${BULLET_VERSION}) + +IF (INSTALL_LIBS) + IF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) + #FILES_MATCHING requires CMake 2.6 + IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS Bullet3Dynamics DESTINATION .) + ELSE (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS Bullet3Dynamics + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib${LIB_SUFFIX} + ARCHIVE DESTINATION lib${LIB_SUFFIX}) + INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.h" PATTERN +".svn" EXCLUDE PATTERN "CMakeFiles" EXCLUDE) + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + SET_TARGET_PROPERTIES(Bullet3Dynamics PROPERTIES FRAMEWORK true) + SET_TARGET_PROPERTIES(Bullet3Dynamics PROPERTIES PUBLIC_HEADER "${Bullet3Dynamics_HDRS}") + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) +ENDIF (INSTALL_LIBS) diff --git a/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3ContactSolverInfo.h b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3ContactSolverInfo.h new file mode 100644 index 000000000000..7a12257b33c5 --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3ContactSolverInfo.h @@ -0,0 +1,159 @@ +/* +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 B3_CONTACT_SOLVER_INFO +#define B3_CONTACT_SOLVER_INFO + +#include "Bullet3Common/b3Scalar.h" + +enum b3SolverMode +{ + B3_SOLVER_RANDMIZE_ORDER = 1, + B3_SOLVER_FRICTION_SEPARATE = 2, + B3_SOLVER_USE_WARMSTARTING = 4, + B3_SOLVER_USE_2_FRICTION_DIRECTIONS = 16, + B3_SOLVER_ENABLE_FRICTION_DIRECTION_CACHING = 32, + B3_SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION = 64, + B3_SOLVER_CACHE_FRIENDLY = 128, + B3_SOLVER_SIMD = 256, + B3_SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS = 512, + B3_SOLVER_ALLOW_ZERO_LENGTH_FRICTION_DIRECTIONS = 1024 +}; + +struct b3ContactSolverInfoData +{ + + + b3Scalar m_tau; + b3Scalar m_damping;//global non-contact constraint damping, can be locally overridden by constraints during 'getInfo2'. + b3Scalar m_friction; + b3Scalar m_timeStep; + b3Scalar m_restitution; + int m_numIterations; + b3Scalar m_maxErrorReduction; + b3Scalar m_sor; + b3Scalar m_erp;//used as Baumgarte factor + b3Scalar m_erp2;//used in Split Impulse + b3Scalar m_globalCfm;//constraint force mixing + int m_splitImpulse; + b3Scalar m_splitImpulsePenetrationThreshold; + b3Scalar m_splitImpulseTurnErp; + b3Scalar m_linearSlop; + b3Scalar m_warmstartingFactor; + + int m_solverMode; + int m_restingContactRestitutionThreshold; + int m_minimumSolverBatchSize; + b3Scalar m_maxGyroscopicForce; + b3Scalar m_singleAxisRollingFrictionThreshold; + + +}; + +struct b3ContactSolverInfo : public b3ContactSolverInfoData +{ + + + + inline b3ContactSolverInfo() + { + m_tau = b3Scalar(0.6); + m_damping = b3Scalar(1.0); + m_friction = b3Scalar(0.3); + m_timeStep = b3Scalar(1.f/60.f); + m_restitution = b3Scalar(0.); + m_maxErrorReduction = b3Scalar(20.); + m_numIterations = 10; + m_erp = b3Scalar(0.2); + m_erp2 = b3Scalar(0.8); + m_globalCfm = b3Scalar(0.); + m_sor = b3Scalar(1.); + m_splitImpulse = true; + m_splitImpulsePenetrationThreshold = -.04f; + m_splitImpulseTurnErp = 0.1f; + m_linearSlop = b3Scalar(0.0); + m_warmstartingFactor=b3Scalar(0.85); + //m_solverMode = B3_SOLVER_USE_WARMSTARTING | B3_SOLVER_SIMD | B3_SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION|B3_SOLVER_USE_2_FRICTION_DIRECTIONS|B3_SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;// | B3_SOLVER_RANDMIZE_ORDER; + m_solverMode = B3_SOLVER_USE_WARMSTARTING | B3_SOLVER_SIMD;// | B3_SOLVER_RANDMIZE_ORDER; + m_restingContactRestitutionThreshold = 2;//unused as of 2.81 + m_minimumSolverBatchSize = 128; //try to combine islands until the amount of constraints reaches this limit + m_maxGyroscopicForce = 100.f; ///only used to clamp forces for bodies that have their B3_ENABLE_GYROPSCOPIC_FORCE flag set (using b3RigidBody::setFlag) + m_singleAxisRollingFrictionThreshold = 1e30f;///if the velocity is above this threshold, it will use a single constraint row (axis), otherwise 3 rows. + } +}; + +///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 +struct b3ContactSolverInfoDoubleData +{ + double m_tau; + double m_damping;//global non-contact constraint damping, can be locally overridden by constraints during 'getInfo2'. + double m_friction; + double m_timeStep; + double m_restitution; + double m_maxErrorReduction; + double m_sor; + double m_erp;//used as Baumgarte factor + double m_erp2;//used in Split Impulse + double m_globalCfm;//constraint force mixing + double m_splitImpulsePenetrationThreshold; + double m_splitImpulseTurnErp; + double m_linearSlop; + double m_warmstartingFactor; + double m_maxGyroscopicForce; + double m_singleAxisRollingFrictionThreshold; + + int m_numIterations; + int m_solverMode; + int m_restingContactRestitutionThreshold; + int m_minimumSolverBatchSize; + int m_splitImpulse; + char m_padding[4]; + +}; +///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 +struct b3ContactSolverInfoFloatData +{ + float m_tau; + float m_damping;//global non-contact constraint damping, can be locally overridden by constraints during 'getInfo2'. + float m_friction; + float m_timeStep; + + float m_restitution; + float m_maxErrorReduction; + float m_sor; + float m_erp;//used as Baumgarte factor + + float m_erp2;//used in Split Impulse + float m_globalCfm;//constraint force mixing + float m_splitImpulsePenetrationThreshold; + float m_splitImpulseTurnErp; + + float m_linearSlop; + float m_warmstartingFactor; + float m_maxGyroscopicForce; + float m_singleAxisRollingFrictionThreshold; + + int m_numIterations; + int m_solverMode; + int m_restingContactRestitutionThreshold; + int m_minimumSolverBatchSize; + + int m_splitImpulse; + char m_padding[4]; +}; + + + +#endif //B3_CONTACT_SOLVER_INFO diff --git a/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3FixedConstraint.cpp b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3FixedConstraint.cpp new file mode 100644 index 000000000000..5e11e7493575 --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3FixedConstraint.cpp @@ -0,0 +1,108 @@ + +#include "b3FixedConstraint.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" +#include "Bullet3Common/b3TransformUtil.h" +#include + + +b3FixedConstraint::b3FixedConstraint(int rbA,int rbB, const b3Transform& frameInA,const b3Transform& frameInB) +:b3TypedConstraint(B3_FIXED_CONSTRAINT_TYPE,rbA,rbB) +{ + m_pivotInA = frameInA.getOrigin(); + m_pivotInB = frameInB.getOrigin(); + m_relTargetAB = frameInA.getRotation()*frameInB.getRotation().inverse(); + +} + +b3FixedConstraint::~b3FixedConstraint () +{ +} + + +void b3FixedConstraint::getInfo1 (b3ConstraintInfo1* info,const b3RigidBodyData* bodies) +{ + info->m_numConstraintRows = 6; + info->nub = 6; +} + +void b3FixedConstraint::getInfo2 (b3ConstraintInfo2* info, const b3RigidBodyData* bodies) +{ + //fix the 3 linear degrees of freedom + + const b3Vector3& worldPosA = bodies[m_rbA].m_pos; + const b3Quaternion& worldOrnA = bodies[m_rbA].m_quat; + const b3Vector3& worldPosB= bodies[m_rbB].m_pos; + const b3Quaternion& worldOrnB = bodies[m_rbB].m_quat; + + info->m_J1linearAxis[0] = 1; + info->m_J1linearAxis[info->rowskip+1] = 1; + info->m_J1linearAxis[2*info->rowskip+2] = 1; + + b3Vector3 a1 = b3QuatRotate(worldOrnA,m_pivotInA); + { + b3Vector3* angular0 = (b3Vector3*)(info->m_J1angularAxis); + b3Vector3* angular1 = (b3Vector3*)(info->m_J1angularAxis+info->rowskip); + b3Vector3* angular2 = (b3Vector3*)(info->m_J1angularAxis+2*info->rowskip); + b3Vector3 a1neg = -a1; + a1neg.getSkewSymmetricMatrix(angular0,angular1,angular2); + } + + if (info->m_J2linearAxis) + { + info->m_J2linearAxis[0] = -1; + info->m_J2linearAxis[info->rowskip+1] = -1; + info->m_J2linearAxis[2*info->rowskip+2] = -1; + } + + b3Vector3 a2 = b3QuatRotate(worldOrnB,m_pivotInB); + + { + // b3Vector3 a2n = -a2; + b3Vector3* angular0 = (b3Vector3*)(info->m_J2angularAxis); + b3Vector3* angular1 = (b3Vector3*)(info->m_J2angularAxis+info->rowskip); + b3Vector3* angular2 = (b3Vector3*)(info->m_J2angularAxis+2*info->rowskip); + a2.getSkewSymmetricMatrix(angular0,angular1,angular2); + } + + // set right hand side for the linear dofs + b3Scalar k = info->fps * info->erp; + b3Vector3 linearError = k*(a2+worldPosB-a1-worldPosA); + int j; + for (j=0; j<3; j++) + { + info->m_constraintError[j*info->rowskip] = linearError[j]; + //printf("info->m_constraintError[%d]=%f\n",j,info->m_constraintError[j]); + } + + //fix the 3 angular degrees of freedom + + int start_row = 3; + int s = info->rowskip; + int start_index = start_row * s; + + // 3 rows to make body rotations equal + info->m_J1angularAxis[start_index] = 1; + info->m_J1angularAxis[start_index + s + 1] = 1; + info->m_J1angularAxis[start_index + s*2+2] = 1; + if ( info->m_J2angularAxis) + { + info->m_J2angularAxis[start_index] = -1; + info->m_J2angularAxis[start_index + s+1] = -1; + info->m_J2angularAxis[start_index + s*2+2] = -1; + } + + + // set right hand side for the angular dofs + + b3Vector3 diff; + b3Scalar angle; + b3Quaternion qrelCur = worldOrnA *worldOrnB.inverse(); + + b3TransformUtil::calculateDiffAxisAngleQuaternion(m_relTargetAB,qrelCur,diff,angle); + diff*=-angle; + for (j=0; j<3; j++) + { + info->m_constraintError[(3+j)*info->rowskip] = k * diff[j]; + } + +} \ No newline at end of file diff --git a/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3FixedConstraint.h b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3FixedConstraint.h new file mode 100644 index 000000000000..e884a829129d --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3FixedConstraint.h @@ -0,0 +1,35 @@ + +#ifndef B3_FIXED_CONSTRAINT_H +#define B3_FIXED_CONSTRAINT_H + +#include "b3TypedConstraint.h" + +B3_ATTRIBUTE_ALIGNED16(class) b3FixedConstraint : public b3TypedConstraint +{ + b3Vector3 m_pivotInA; + b3Vector3 m_pivotInB; + b3Quaternion m_relTargetAB; + +public: + b3FixedConstraint(int rbA,int rbB, const b3Transform& frameInA,const b3Transform& frameInB); + + virtual ~b3FixedConstraint(); + + + virtual void getInfo1 (b3ConstraintInfo1* info,const b3RigidBodyData* bodies); + + virtual void getInfo2 (b3ConstraintInfo2* info, const b3RigidBodyData* bodies); + + virtual void setParam(int num, b3Scalar value, int axis = -1) + { + b3Assert(0); + } + virtual b3Scalar getParam(int num, int axis = -1) const + { + b3Assert(0); + return 0.f; + } + +}; + +#endif //B3_FIXED_CONSTRAINT_H diff --git a/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3Generic6DofConstraint.cpp b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3Generic6DofConstraint.cpp new file mode 100644 index 000000000000..168a773d56cf --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3Generic6DofConstraint.cpp @@ -0,0 +1,807 @@ +/* +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. +*/ +/* +2007-09-09 +Refactored by Francisco Le?n +email: projectileman@yahoo.com +http://gimpact.sf.net +*/ + +#include "b3Generic6DofConstraint.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" + +#include "Bullet3Common/b3TransformUtil.h" +#include "Bullet3Common/b3TransformUtil.h" +#include + + + +#define D6_USE_OBSOLETE_METHOD false +#define D6_USE_FRAME_OFFSET true + + + + + + +b3Generic6DofConstraint::b3Generic6DofConstraint(int rbA,int rbB, const b3Transform& frameInA, const b3Transform& frameInB, bool useLinearReferenceFrameA, const b3RigidBodyData* bodies) +: b3TypedConstraint(B3_D6_CONSTRAINT_TYPE, rbA, rbB) +, m_frameInA(frameInA) +, m_frameInB(frameInB), +m_useLinearReferenceFrameA(useLinearReferenceFrameA), +m_useOffsetForConstraintFrame(D6_USE_FRAME_OFFSET), +m_flags(0) +{ + calculateTransforms(bodies); +} + + + + + + +#define GENERIC_D6_DISABLE_WARMSTARTING 1 + + + +b3Scalar btGetMatrixElem(const b3Matrix3x3& mat, int index); +b3Scalar btGetMatrixElem(const b3Matrix3x3& mat, int index) +{ + int i = index%3; + int j = index/3; + return mat[i][j]; +} + + + +///MatrixToEulerXYZ from http://www.geometrictools.com/LibFoundation/Mathematics/Wm4Matrix3.inl.html +bool matrixToEulerXYZ(const b3Matrix3x3& mat,b3Vector3& xyz); +bool matrixToEulerXYZ(const b3Matrix3x3& mat,b3Vector3& 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 + // + + b3Scalar fi = btGetMatrixElem(mat,2); + if (fi < b3Scalar(1.0f)) + { + if (fi > b3Scalar(-1.0f)) + { + xyz[0] = b3Atan2(-btGetMatrixElem(mat,5),btGetMatrixElem(mat,8)); + xyz[1] = b3Asin(btGetMatrixElem(mat,2)); + xyz[2] = b3Atan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0)); + return true; + } + else + { + // WARNING. Not unique. XA - ZA = -atan2(r10,r11) + xyz[0] = -b3Atan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4)); + xyz[1] = -B3_HALF_PI; + xyz[2] = b3Scalar(0.0); + return false; + } + } + else + { + // WARNING. Not unique. XAngle + ZAngle = atan2(r10,r11) + xyz[0] = b3Atan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4)); + xyz[1] = B3_HALF_PI; + xyz[2] = 0.0; + } + return false; +} + +//////////////////////////// b3RotationalLimitMotor //////////////////////////////////// + +int b3RotationalLimitMotor::testLimitValue(b3Scalar test_value) +{ + if(m_loLimit>m_hiLimit) + { + m_currentLimit = 0;//Free from violation + return 0; + } + if (test_value < m_loLimit) + { + m_currentLimit = 1;//low limit violation + m_currentLimitError = test_value - m_loLimit; + if(m_currentLimitError>B3_PI) + m_currentLimitError-=B3_2_PI; + else if(m_currentLimitError<-B3_PI) + m_currentLimitError+=B3_2_PI; + return 1; + } + else if (test_value> m_hiLimit) + { + m_currentLimit = 2;//High limit violation + m_currentLimitError = test_value - m_hiLimit; + if(m_currentLimitError>B3_PI) + m_currentLimitError-=B3_2_PI; + else if(m_currentLimitError<-B3_PI) + m_currentLimitError+=B3_2_PI; + return 2; + }; + + m_currentLimit = 0;//Free from violation + return 0; + +} + + + + +//////////////////////////// End b3RotationalLimitMotor //////////////////////////////////// + + + + +//////////////////////////// b3TranslationalLimitMotor //////////////////////////////////// + + +int b3TranslationalLimitMotor::testLimitValue(int limitIndex, b3Scalar test_value) +{ + b3Scalar loLimit = m_lowerLimit[limitIndex]; + b3Scalar hiLimit = m_upperLimit[limitIndex]; + if(loLimit > hiLimit) + { + m_currentLimit[limitIndex] = 0;//Free from violation + m_currentLimitError[limitIndex] = b3Scalar(0.f); + return 0; + } + + if (test_value < loLimit) + { + m_currentLimit[limitIndex] = 2;//low limit violation + m_currentLimitError[limitIndex] = test_value - loLimit; + return 2; + } + else if (test_value> hiLimit) + { + m_currentLimit[limitIndex] = 1;//High limit violation + m_currentLimitError[limitIndex] = test_value - hiLimit; + return 1; + }; + + m_currentLimit[limitIndex] = 0;//Free from violation + m_currentLimitError[limitIndex] = b3Scalar(0.f); + return 0; +} + + + +//////////////////////////// b3TranslationalLimitMotor //////////////////////////////////// + +void b3Generic6DofConstraint::calculateAngleInfo() +{ + b3Matrix3x3 relative_frame = m_calculatedTransformA.getBasis().inverse()*m_calculatedTransformB.getBasis(); + matrixToEulerXYZ(relative_frame,m_calculatedAxisAngleDiff); + // 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. + b3Vector3 axis0 = m_calculatedTransformB.getBasis().getColumn(0); + b3Vector3 axis2 = m_calculatedTransformA.getBasis().getColumn(2); + + m_calculatedAxis[1] = axis2.cross(axis0); + m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2); + m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]); + + m_calculatedAxis[0].normalize(); + m_calculatedAxis[1].normalize(); + m_calculatedAxis[2].normalize(); + +} + +static b3Transform getCenterOfMassTransform(const b3RigidBodyData& body) +{ + b3Transform tr(body.m_quat,body.m_pos); + return tr; +} + +void b3Generic6DofConstraint::calculateTransforms(const b3RigidBodyData* bodies) +{ + b3Transform transA; + b3Transform transB; + transA = getCenterOfMassTransform(bodies[m_rbA]); + transB = getCenterOfMassTransform(bodies[m_rbB]); + calculateTransforms(transA,transB,bodies); +} + +void b3Generic6DofConstraint::calculateTransforms(const b3Transform& transA,const b3Transform& transB,const b3RigidBodyData* bodies) +{ + m_calculatedTransformA = transA * m_frameInA; + m_calculatedTransformB = transB * m_frameInB; + calculateLinearInfo(); + calculateAngleInfo(); + if(m_useOffsetForConstraintFrame) + { // get weight factors depending on masses + b3Scalar miA = bodies[m_rbA].m_invMass; + b3Scalar miB = bodies[m_rbB].m_invMass; + m_hasStaticBody = (miA < B3_EPSILON) || (miB < B3_EPSILON); + b3Scalar miS = miA + miB; + if(miS > b3Scalar(0.f)) + { + m_factA = miB / miS; + } + else + { + m_factA = b3Scalar(0.5f); + } + m_factB = b3Scalar(1.0f) - m_factA; + } +} + + + + + + + +bool b3Generic6DofConstraint::testAngularLimitMotor(int axis_index) +{ + b3Scalar angle = m_calculatedAxisAngleDiff[axis_index]; + angle = b3AdjustAngleToLimits(angle, m_angularLimits[axis_index].m_loLimit, m_angularLimits[axis_index].m_hiLimit); + m_angularLimits[axis_index].m_currentPosition = angle; + //test limits + m_angularLimits[axis_index].testLimitValue(angle); + return m_angularLimits[axis_index].needApplyTorques(); +} + + + + +void b3Generic6DofConstraint::getInfo1 (b3ConstraintInfo1* info,const b3RigidBodyData* bodies) +{ + //prepare constraint + calculateTransforms(getCenterOfMassTransform(bodies[m_rbA]),getCenterOfMassTransform(bodies[m_rbB]),bodies); + info->m_numConstraintRows = 0; + info->nub = 6; + int i; + //test linear limits + for(i = 0; i < 3; i++) + { + if(m_linearLimits.needApplyForce(i)) + { + info->m_numConstraintRows++; + info->nub--; + } + } + //test angular limits + for (i=0;i<3 ;i++ ) + { + if(testAngularLimitMotor(i)) + { + info->m_numConstraintRows++; + info->nub--; + } + } +// printf("info->m_numConstraintRows=%d\n",info->m_numConstraintRows); +} + +void b3Generic6DofConstraint::getInfo1NonVirtual (b3ConstraintInfo1* info,const b3RigidBodyData* bodies) +{ + //pre-allocate all 6 + info->m_numConstraintRows = 6; + info->nub = 0; +} + + +void b3Generic6DofConstraint::getInfo2 (b3ConstraintInfo2* info,const b3RigidBodyData* bodies) +{ + + b3Transform transA = getCenterOfMassTransform(bodies[m_rbA]); + b3Transform transB = getCenterOfMassTransform(bodies[m_rbB]); + const b3Vector3& linVelA = bodies[m_rbA].m_linVel; + const b3Vector3& linVelB = bodies[m_rbB].m_linVel; + const b3Vector3& angVelA = bodies[m_rbA].m_angVel; + const b3Vector3& angVelB = bodies[m_rbB].m_angVel; + + if(m_useOffsetForConstraintFrame) + { // for stability better to solve angular limits first + int row = setAngularLimits(info, 0,transA,transB,linVelA,linVelB,angVelA,angVelB); + setLinearLimits(info, row, transA,transB,linVelA,linVelB,angVelA,angVelB); + } + else + { // leave old version for compatibility + int row = setLinearLimits(info, 0, transA,transB,linVelA,linVelB,angVelA,angVelB); + setAngularLimits(info, row,transA,transB,linVelA,linVelB,angVelA,angVelB); + } + +} + + +void b3Generic6DofConstraint::getInfo2NonVirtual (b3ConstraintInfo2* info, const b3Transform& transA,const b3Transform& transB,const b3Vector3& linVelA,const b3Vector3& linVelB,const b3Vector3& angVelA,const b3Vector3& angVelB,const b3RigidBodyData* bodies) +{ + + //prepare constraint + calculateTransforms(transA,transB,bodies); + + int i; + for (i=0;i<3 ;i++ ) + { + testAngularLimitMotor(i); + } + + if(m_useOffsetForConstraintFrame) + { // for stability better to solve angular limits first + int row = setAngularLimits(info, 0,transA,transB,linVelA,linVelB,angVelA,angVelB); + setLinearLimits(info, row, transA,transB,linVelA,linVelB,angVelA,angVelB); + } + else + { // leave old version for compatibility + int row = setLinearLimits(info, 0, transA,transB,linVelA,linVelB,angVelA,angVelB); + setAngularLimits(info, row,transA,transB,linVelA,linVelB,angVelA,angVelB); + } +} + + + +int b3Generic6DofConstraint::setLinearLimits(b3ConstraintInfo2* info, int row, const b3Transform& transA,const b3Transform& transB,const b3Vector3& linVelA,const b3Vector3& linVelB,const b3Vector3& angVelA,const b3Vector3& angVelB) +{ +// int row = 0; + //solve linear limits + b3RotationalLimitMotor limot; + for (int i=0;i<3 ;i++ ) + { + if(m_linearLimits.needApplyForce(i)) + { // re-use rotational motor code + limot.m_bounce = b3Scalar(0.f); + limot.m_currentLimit = m_linearLimits.m_currentLimit[i]; + limot.m_currentPosition = m_linearLimits.m_currentLinearDiff[i]; + limot.m_currentLimitError = m_linearLimits.m_currentLimitError[i]; + limot.m_damping = m_linearLimits.m_damping; + limot.m_enableMotor = m_linearLimits.m_enableMotor[i]; + limot.m_hiLimit = m_linearLimits.m_upperLimit[i]; + limot.m_limitSoftness = m_linearLimits.m_limitSoftness; + limot.m_loLimit = m_linearLimits.m_lowerLimit[i]; + limot.m_maxLimitForce = b3Scalar(0.f); + limot.m_maxMotorForce = m_linearLimits.m_maxMotorForce[i]; + limot.m_targetVelocity = m_linearLimits.m_targetVelocity[i]; + b3Vector3 axis = m_calculatedTransformA.getBasis().getColumn(i); + int flags = m_flags >> (i * B3_6DOF_FLAGS_AXIS_SHIFT); + limot.m_normalCFM = (flags & B3_6DOF_FLAGS_CFM_NORM) ? m_linearLimits.m_normalCFM[i] : info->cfm[0]; + limot.m_stopCFM = (flags & B3_6DOF_FLAGS_CFM_STOP) ? m_linearLimits.m_stopCFM[i] : info->cfm[0]; + limot.m_stopERP = (flags & B3_6DOF_FLAGS_ERP_STOP) ? m_linearLimits.m_stopERP[i] : info->erp; + if(m_useOffsetForConstraintFrame) + { + int indx1 = (i + 1) % 3; + int indx2 = (i + 2) % 3; + int rotAllowed = 1; // rotations around orthos to current axis + if(m_angularLimits[indx1].m_currentLimit && m_angularLimits[indx2].m_currentLimit) + { + rotAllowed = 0; + } + row += get_limit_motor_info2(&limot, transA,transB,linVelA,linVelB,angVelA,angVelB, info, row, axis, 0, rotAllowed); + } + else + { + row += get_limit_motor_info2(&limot, transA,transB,linVelA,linVelB,angVelA,angVelB, info, row, axis, 0); + } + } + } + return row; +} + + + +int b3Generic6DofConstraint::setAngularLimits(b3ConstraintInfo2 *info, int row_offset, const b3Transform& transA,const b3Transform& transB,const b3Vector3& linVelA,const b3Vector3& linVelB,const b3Vector3& angVelA,const b3Vector3& angVelB) +{ + b3Generic6DofConstraint * d6constraint = this; + int row = row_offset; + //solve angular limits + for (int i=0;i<3 ;i++ ) + { + if(d6constraint->getRotationalLimitMotor(i)->needApplyTorques()) + { + b3Vector3 axis = d6constraint->getAxis(i); + int flags = m_flags >> ((i + 3) * B3_6DOF_FLAGS_AXIS_SHIFT); + if(!(flags & B3_6DOF_FLAGS_CFM_NORM)) + { + m_angularLimits[i].m_normalCFM = info->cfm[0]; + } + if(!(flags & B3_6DOF_FLAGS_CFM_STOP)) + { + m_angularLimits[i].m_stopCFM = info->cfm[0]; + } + if(!(flags & B3_6DOF_FLAGS_ERP_STOP)) + { + m_angularLimits[i].m_stopERP = info->erp; + } + row += get_limit_motor_info2(d6constraint->getRotationalLimitMotor(i), + transA,transB,linVelA,linVelB,angVelA,angVelB, info,row,axis,1); + } + } + + return row; +} + + + + +void b3Generic6DofConstraint::updateRHS(b3Scalar timeStep) +{ + (void)timeStep; + +} + + +void b3Generic6DofConstraint::setFrames(const b3Transform& frameA, const b3Transform& frameB,const b3RigidBodyData* bodies) +{ + m_frameInA = frameA; + m_frameInB = frameB; + + calculateTransforms(bodies); +} + + + +b3Vector3 b3Generic6DofConstraint::getAxis(int axis_index) const +{ + return m_calculatedAxis[axis_index]; +} + + +b3Scalar b3Generic6DofConstraint::getRelativePivotPosition(int axisIndex) const +{ + return m_calculatedLinearDiff[axisIndex]; +} + + +b3Scalar b3Generic6DofConstraint::getAngle(int axisIndex) const +{ + return m_calculatedAxisAngleDiff[axisIndex]; +} + + + +void b3Generic6DofConstraint::calcAnchorPos(const b3RigidBodyData* bodies) +{ + b3Scalar imA = bodies[m_rbA].m_invMass; + b3Scalar imB = bodies[m_rbB].m_invMass; + b3Scalar weight; + if(imB == b3Scalar(0.0)) + { + weight = b3Scalar(1.0); + } + else + { + weight = imA / (imA + imB); + } + const b3Vector3& pA = m_calculatedTransformA.getOrigin(); + const b3Vector3& pB = m_calculatedTransformB.getOrigin(); + m_AnchorPos = pA * weight + pB * (b3Scalar(1.0) - weight); + return; +} + + + +void b3Generic6DofConstraint::calculateLinearInfo() +{ + m_calculatedLinearDiff = m_calculatedTransformB.getOrigin() - m_calculatedTransformA.getOrigin(); + m_calculatedLinearDiff = m_calculatedTransformA.getBasis().inverse() * m_calculatedLinearDiff; + for(int i = 0; i < 3; i++) + { + m_linearLimits.m_currentLinearDiff[i] = m_calculatedLinearDiff[i]; + m_linearLimits.testLimitValue(i, m_calculatedLinearDiff[i]); + } +} + + + +int b3Generic6DofConstraint::get_limit_motor_info2( + b3RotationalLimitMotor * limot, + const b3Transform& transA,const b3Transform& transB,const b3Vector3& linVelA,const b3Vector3& linVelB,const b3Vector3& angVelA,const b3Vector3& angVelB, + b3ConstraintInfo2 *info, int row, b3Vector3& ax1, int rotational,int rotAllowed) +{ + int srow = row * info->rowskip; + bool powered = limot->m_enableMotor; + int limit = limot->m_currentLimit; + if (powered || limit) + { // if the joint is powered, or has joint limits, add in the extra row + b3Scalar *J1 = rotational ? info->m_J1angularAxis : info->m_J1linearAxis; + b3Scalar *J2 = rotational ? info->m_J2angularAxis : info->m_J2linearAxis; + if (J1) + { + J1[srow+0] = ax1[0]; + J1[srow+1] = ax1[1]; + J1[srow+2] = ax1[2]; + } + if (J2) + { + J2[srow+0] = -ax1[0]; + J2[srow+1] = -ax1[1]; + J2[srow+2] = -ax1[2]; + } + if((!rotational)) + { + if (m_useOffsetForConstraintFrame) + { + b3Vector3 tmpA, tmpB, relA, relB; + // get vector from bodyB to frameB in WCS + relB = m_calculatedTransformB.getOrigin() - transB.getOrigin(); + // get its projection to constraint axis + b3Vector3 projB = ax1 * relB.dot(ax1); + // get vector directed from bodyB to constraint axis (and orthogonal to it) + b3Vector3 orthoB = relB - projB; + // same for bodyA + relA = m_calculatedTransformA.getOrigin() - transA.getOrigin(); + b3Vector3 projA = ax1 * relA.dot(ax1); + b3Vector3 orthoA = relA - projA; + // get desired offset between frames A and B along constraint axis + b3Scalar desiredOffs = limot->m_currentPosition - limot->m_currentLimitError; + // desired vector from projection of center of bodyA to projection of center of bodyB to constraint axis + b3Vector3 totalDist = projA + ax1 * desiredOffs - projB; + // get offset vectors relA and relB + relA = orthoA + totalDist * m_factA; + relB = orthoB - totalDist * m_factB; + tmpA = relA.cross(ax1); + tmpB = relB.cross(ax1); + if(m_hasStaticBody && (!rotAllowed)) + { + tmpA *= m_factA; + tmpB *= m_factB; + } + int i; + for (i=0; i<3; i++) info->m_J1angularAxis[srow+i] = tmpA[i]; + for (i=0; i<3; i++) info->m_J2angularAxis[srow+i] = -tmpB[i]; + } else + { + b3Vector3 ltd; // Linear Torque Decoupling vector + b3Vector3 c = m_calculatedTransformB.getOrigin() - transA.getOrigin(); + ltd = c.cross(ax1); + info->m_J1angularAxis[srow+0] = ltd[0]; + info->m_J1angularAxis[srow+1] = ltd[1]; + info->m_J1angularAxis[srow+2] = ltd[2]; + + c = m_calculatedTransformB.getOrigin() - transB.getOrigin(); + ltd = -c.cross(ax1); + info->m_J2angularAxis[srow+0] = ltd[0]; + info->m_J2angularAxis[srow+1] = ltd[1]; + info->m_J2angularAxis[srow+2] = ltd[2]; + } + } + // if we're limited low and high simultaneously, the joint motor is + // ineffective + if (limit && (limot->m_loLimit == limot->m_hiLimit)) powered = false; + info->m_constraintError[srow] = b3Scalar(0.f); + if (powered) + { + info->cfm[srow] = limot->m_normalCFM; + if(!limit) + { + b3Scalar tag_vel = rotational ? limot->m_targetVelocity : -limot->m_targetVelocity; + + b3Scalar mot_fact = getMotorFactor( limot->m_currentPosition, + limot->m_loLimit, + limot->m_hiLimit, + tag_vel, + info->fps * limot->m_stopERP); + info->m_constraintError[srow] += mot_fact * limot->m_targetVelocity; + info->m_lowerLimit[srow] = -limot->m_maxMotorForce; + info->m_upperLimit[srow] = limot->m_maxMotorForce; + } + } + if(limit) + { + b3Scalar k = info->fps * limot->m_stopERP; + if(!rotational) + { + info->m_constraintError[srow] += k * limot->m_currentLimitError; + } + else + { + info->m_constraintError[srow] += -k * limot->m_currentLimitError; + } + info->cfm[srow] = limot->m_stopCFM; + if (limot->m_loLimit == limot->m_hiLimit) + { // limited low and high simultaneously + info->m_lowerLimit[srow] = -B3_INFINITY; + info->m_upperLimit[srow] = B3_INFINITY; + } + else + { + if (limit == 1) + { + info->m_lowerLimit[srow] = 0; + info->m_upperLimit[srow] = B3_INFINITY; + } + else + { + info->m_lowerLimit[srow] = -B3_INFINITY; + info->m_upperLimit[srow] = 0; + } + // deal with bounce + if (limot->m_bounce > 0) + { + // calculate joint velocity + b3Scalar vel; + if (rotational) + { + vel = angVelA.dot(ax1); +//make sure that if no body -> angVelB == zero vec +// if (body1) + vel -= angVelB.dot(ax1); + } + else + { + vel = linVelA.dot(ax1); +//make sure that if no body -> angVelB == zero vec +// if (body1) + vel -= linVelB.dot(ax1); + } + // only apply bounce if the velocity is incoming, and if the + // resulting c[] exceeds what we already have. + if (limit == 1) + { + if (vel < 0) + { + b3Scalar newc = -limot->m_bounce* vel; + if (newc > info->m_constraintError[srow]) + info->m_constraintError[srow] = newc; + } + } + else + { + if (vel > 0) + { + b3Scalar newc = -limot->m_bounce * vel; + if (newc < info->m_constraintError[srow]) + info->m_constraintError[srow] = newc; + } + } + } + } + } + return 1; + } + else return 0; +} + + + + + + + ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). + ///If no axis is provided, it uses the default axis for this constraint. +void b3Generic6DofConstraint::setParam(int num, b3Scalar value, int axis) +{ + if((axis >= 0) && (axis < 3)) + { + switch(num) + { + case B3_CONSTRAINT_STOP_ERP : + m_linearLimits.m_stopERP[axis] = value; + m_flags |= B3_6DOF_FLAGS_ERP_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT); + break; + case B3_CONSTRAINT_STOP_CFM : + m_linearLimits.m_stopCFM[axis] = value; + m_flags |= B3_6DOF_FLAGS_CFM_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT); + break; + case B3_CONSTRAINT_CFM : + m_linearLimits.m_normalCFM[axis] = value; + m_flags |= B3_6DOF_FLAGS_CFM_NORM << (axis * B3_6DOF_FLAGS_AXIS_SHIFT); + break; + default : + b3AssertConstrParams(0); + } + } + else if((axis >=3) && (axis < 6)) + { + switch(num) + { + case B3_CONSTRAINT_STOP_ERP : + m_angularLimits[axis - 3].m_stopERP = value; + m_flags |= B3_6DOF_FLAGS_ERP_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT); + break; + case B3_CONSTRAINT_STOP_CFM : + m_angularLimits[axis - 3].m_stopCFM = value; + m_flags |= B3_6DOF_FLAGS_CFM_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT); + break; + case B3_CONSTRAINT_CFM : + m_angularLimits[axis - 3].m_normalCFM = value; + m_flags |= B3_6DOF_FLAGS_CFM_NORM << (axis * B3_6DOF_FLAGS_AXIS_SHIFT); + break; + default : + b3AssertConstrParams(0); + } + } + else + { + b3AssertConstrParams(0); + } +} + + ///return the local value of parameter +b3Scalar b3Generic6DofConstraint::getParam(int num, int axis) const +{ + b3Scalar retVal = 0; + if((axis >= 0) && (axis < 3)) + { + switch(num) + { + case B3_CONSTRAINT_STOP_ERP : + b3AssertConstrParams(m_flags & (B3_6DOF_FLAGS_ERP_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT))); + retVal = m_linearLimits.m_stopERP[axis]; + break; + case B3_CONSTRAINT_STOP_CFM : + b3AssertConstrParams(m_flags & (B3_6DOF_FLAGS_CFM_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT))); + retVal = m_linearLimits.m_stopCFM[axis]; + break; + case B3_CONSTRAINT_CFM : + b3AssertConstrParams(m_flags & (B3_6DOF_FLAGS_CFM_NORM << (axis * B3_6DOF_FLAGS_AXIS_SHIFT))); + retVal = m_linearLimits.m_normalCFM[axis]; + break; + default : + b3AssertConstrParams(0); + } + } + else if((axis >=3) && (axis < 6)) + { + switch(num) + { + case B3_CONSTRAINT_STOP_ERP : + b3AssertConstrParams(m_flags & (B3_6DOF_FLAGS_ERP_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT))); + retVal = m_angularLimits[axis - 3].m_stopERP; + break; + case B3_CONSTRAINT_STOP_CFM : + b3AssertConstrParams(m_flags & (B3_6DOF_FLAGS_CFM_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT))); + retVal = m_angularLimits[axis - 3].m_stopCFM; + break; + case B3_CONSTRAINT_CFM : + b3AssertConstrParams(m_flags & (B3_6DOF_FLAGS_CFM_NORM << (axis * B3_6DOF_FLAGS_AXIS_SHIFT))); + retVal = m_angularLimits[axis - 3].m_normalCFM; + break; + default : + b3AssertConstrParams(0); + } + } + else + { + b3AssertConstrParams(0); + } + return retVal; +} + + + +void b3Generic6DofConstraint::setAxis(const b3Vector3& axis1,const b3Vector3& axis2, const b3RigidBodyData* bodies) +{ + b3Vector3 zAxis = axis1.normalized(); + b3Vector3 yAxis = axis2.normalized(); + b3Vector3 xAxis = yAxis.cross(zAxis); // we want right coordinate system + + b3Transform frameInW; + frameInW.setIdentity(); + frameInW.getBasis().setValue( xAxis[0], yAxis[0], zAxis[0], + xAxis[1], yAxis[1], zAxis[1], + xAxis[2], yAxis[2], zAxis[2]); + + // now get constraint frame in local coordinate systems + m_frameInA = getCenterOfMassTransform(bodies[m_rbA]).inverse() * frameInW; + m_frameInB = getCenterOfMassTransform(bodies[m_rbB]).inverse() * frameInW; + + calculateTransforms(bodies); +} diff --git a/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3Generic6DofConstraint.h b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3Generic6DofConstraint.h new file mode 100644 index 000000000000..084d36055ccc --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3Generic6DofConstraint.h @@ -0,0 +1,550 @@ +/* +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. +*/ + +/// 2009 March: b3Generic6DofConstraint refactored by Roman Ponomarev +/// Added support for generic constraint solver through getInfo1/getInfo2 methods + +/* +2007-09-09 +b3Generic6DofConstraint Refactored by Francisco Le?n +email: projectileman@yahoo.com +http://gimpact.sf.net +*/ + + +#ifndef B3_GENERIC_6DOF_CONSTRAINT_H +#define B3_GENERIC_6DOF_CONSTRAINT_H + +#include "Bullet3Common/b3Vector3.h" +#include "b3JacobianEntry.h" +#include "b3TypedConstraint.h" + +struct b3RigidBodyData; + + + + +//! Rotation Limit structure for generic joints +class b3RotationalLimitMotor +{ +public: + //! limit_parameters + //!@{ + b3Scalar m_loLimit;//!< joint limit + b3Scalar m_hiLimit;//!< joint limit + b3Scalar m_targetVelocity;//!< target motor velocity + b3Scalar m_maxMotorForce;//!< max force on motor + b3Scalar m_maxLimitForce;//!< max force on limit + b3Scalar m_damping;//!< Damping. + b3Scalar m_limitSoftness;//! Relaxation factor + b3Scalar m_normalCFM;//!< Constraint force mixing factor + b3Scalar m_stopERP;//!< Error tolerance factor when joint is at limit + b3Scalar m_stopCFM;//!< Constraint force mixing factor when joint is at limit + b3Scalar m_bounce;//!< restitution factor + bool m_enableMotor; + + //!@} + + //! temp_variables + //!@{ + b3Scalar m_currentLimitError;//! How much is violated this limit + b3Scalar m_currentPosition; //! current value of angle + int m_currentLimit;//!< 0=free, 1=at lo limit, 2=at hi limit + b3Scalar m_accumulatedImpulse; + //!@} + + b3RotationalLimitMotor() + { + m_accumulatedImpulse = 0.f; + m_targetVelocity = 0; + m_maxMotorForce = 0.1f; + m_maxLimitForce = 300.0f; + m_loLimit = 1.0f; + m_hiLimit = -1.0f; + m_normalCFM = 0.f; + m_stopERP = 0.2f; + m_stopCFM = 0.f; + m_bounce = 0.0f; + m_damping = 1.0f; + m_limitSoftness = 0.5f; + m_currentLimit = 0; + m_currentLimitError = 0; + m_enableMotor = false; + } + + b3RotationalLimitMotor(const b3RotationalLimitMotor & limot) + { + m_targetVelocity = limot.m_targetVelocity; + m_maxMotorForce = limot.m_maxMotorForce; + m_limitSoftness = limot.m_limitSoftness; + m_loLimit = limot.m_loLimit; + m_hiLimit = limot.m_hiLimit; + m_normalCFM = limot.m_normalCFM; + m_stopERP = limot.m_stopERP; + m_stopCFM = limot.m_stopCFM; + m_bounce = limot.m_bounce; + m_currentLimit = limot.m_currentLimit; + m_currentLimitError = limot.m_currentLimitError; + m_enableMotor = limot.m_enableMotor; + } + + + + //! Is limited + bool isLimited() + { + if(m_loLimit > m_hiLimit) return false; + return true; + } + + //! Need apply correction + bool needApplyTorques() + { + if(m_currentLimit == 0 && m_enableMotor == false) return false; + return true; + } + + //! calculates error + /*! + calculates m_currentLimit and m_currentLimitError. + */ + int testLimitValue(b3Scalar test_value); + + //! apply the correction impulses for two bodies + b3Scalar solveAngularLimits(b3Scalar timeStep,b3Vector3& axis, b3Scalar jacDiagABInv,b3RigidBodyData * body0, b3RigidBodyData * body1); + +}; + + + +class b3TranslationalLimitMotor +{ +public: + b3Vector3 m_lowerLimit;//!< the constraint lower limits + b3Vector3 m_upperLimit;//!< the constraint upper limits + b3Vector3 m_accumulatedImpulse; + //! Linear_Limit_parameters + //!@{ + b3Vector3 m_normalCFM;//!< Constraint force mixing factor + b3Vector3 m_stopERP;//!< Error tolerance factor when joint is at limit + b3Vector3 m_stopCFM;//!< Constraint force mixing factor when joint is at limit + b3Vector3 m_targetVelocity;//!< target motor velocity + b3Vector3 m_maxMotorForce;//!< max force on motor + b3Vector3 m_currentLimitError;//! How much is violated this limit + b3Vector3 m_currentLinearDiff;//! Current relative offset of constraint frames + b3Scalar m_limitSoftness;//!< Softness for linear limit + b3Scalar m_damping;//!< Damping for linear limit + b3Scalar m_restitution;//! Bounce parameter for linear limit + //!@} + bool m_enableMotor[3]; + int m_currentLimit[3];//!< 0=free, 1=at lower limit, 2=at upper limit + + b3TranslationalLimitMotor() + { + m_lowerLimit.setValue(0.f,0.f,0.f); + m_upperLimit.setValue(0.f,0.f,0.f); + m_accumulatedImpulse.setValue(0.f,0.f,0.f); + m_normalCFM.setValue(0.f, 0.f, 0.f); + m_stopERP.setValue(0.2f, 0.2f, 0.2f); + m_stopCFM.setValue(0.f, 0.f, 0.f); + + m_limitSoftness = 0.7f; + m_damping = b3Scalar(1.0f); + m_restitution = b3Scalar(0.5f); + for(int i=0; i < 3; i++) + { + m_enableMotor[i] = false; + m_targetVelocity[i] = b3Scalar(0.f); + m_maxMotorForce[i] = b3Scalar(0.f); + } + } + + b3TranslationalLimitMotor(const b3TranslationalLimitMotor & other ) + { + m_lowerLimit = other.m_lowerLimit; + m_upperLimit = other.m_upperLimit; + m_accumulatedImpulse = other.m_accumulatedImpulse; + + m_limitSoftness = other.m_limitSoftness ; + m_damping = other.m_damping; + m_restitution = other.m_restitution; + m_normalCFM = other.m_normalCFM; + m_stopERP = other.m_stopERP; + m_stopCFM = other.m_stopCFM; + + for(int i=0; i < 3; i++) + { + m_enableMotor[i] = other.m_enableMotor[i]; + m_targetVelocity[i] = other.m_targetVelocity[i]; + m_maxMotorForce[i] = other.m_maxMotorForce[i]; + } + } + + //! Test limit + /*! + - free means upper < lower, + - locked means upper == lower + - limited means upper > lower + - limitIndex: first 3 are linear, next 3 are angular + */ + inline bool isLimited(int limitIndex) + { + return (m_upperLimit[limitIndex] >= m_lowerLimit[limitIndex]); + } + inline bool needApplyForce(int limitIndex) + { + if(m_currentLimit[limitIndex] == 0 && m_enableMotor[limitIndex] == false) return false; + return true; + } + int testLimitValue(int limitIndex, b3Scalar test_value); + + + b3Scalar solveLinearAxis( + b3Scalar timeStep, + b3Scalar jacDiagABInv, + b3RigidBodyData& body1,const b3Vector3 &pointInA, + b3RigidBodyData& body2,const b3Vector3 &pointInB, + int limit_index, + const b3Vector3 & axis_normal_on_a, + const b3Vector3 & anchorPos); + + +}; + +enum b36DofFlags +{ + B3_6DOF_FLAGS_CFM_NORM = 1, + B3_6DOF_FLAGS_CFM_STOP = 2, + B3_6DOF_FLAGS_ERP_STOP = 4 +}; +#define B3_6DOF_FLAGS_AXIS_SHIFT 3 // bits per axis + + +/// b3Generic6DofConstraint between two rigidbodies each with a pivotpoint that descibes the axis location in local space +/*! +b3Generic6DofConstraint can leave any of the 6 degree of freedom 'free' or 'locked'. +currently this limit supports rotational motors
+
    +
  • For Linear limits, use b3Generic6DofConstraint.setLinearUpperLimit, b3Generic6DofConstraint.setLinearLowerLimit. You can set the parameters with the b3TranslationalLimitMotor structure accsesible through the b3Generic6DofConstraint.getTranslationalLimitMotor method. +At this moment translational motors are not supported. May be in the future.
  • + +
  • For Angular limits, use the b3RotationalLimitMotor structure for configuring the limit. +This is accessible through b3Generic6DofConstraint.getLimitMotor method, +This brings support for limit parameters and motors.
  • + +
  • Angulars limits have these possible ranges: + + + + + + + + + + + + + + + + + + +
    AXISMIN ANGLEMAX ANGLE
    X-PIPI
    Y-PI/2PI/2
    Z-PIPI
    +
  • +
+ +*/ +B3_ATTRIBUTE_ALIGNED16(class) b3Generic6DofConstraint : public b3TypedConstraint +{ +protected: + + //! relative_frames + //!@{ + b3Transform m_frameInA;//!< the constraint space w.r.t body A + b3Transform m_frameInB;//!< the constraint space w.r.t body B + //!@} + + //! Jacobians + //!@{ +// b3JacobianEntry m_jacLinear[3];//!< 3 orthogonal linear constraints +// b3JacobianEntry m_jacAng[3];//!< 3 orthogonal angular constraints + //!@} + + //! Linear_Limit_parameters + //!@{ + b3TranslationalLimitMotor m_linearLimits; + //!@} + + + //! hinge_parameters + //!@{ + b3RotationalLimitMotor m_angularLimits[3]; + //!@} + + +protected: + //! temporal variables + //!@{ + b3Transform m_calculatedTransformA; + b3Transform m_calculatedTransformB; + b3Vector3 m_calculatedAxisAngleDiff; + b3Vector3 m_calculatedAxis[3]; + b3Vector3 m_calculatedLinearDiff; + b3Scalar m_timeStep; + b3Scalar m_factA; + b3Scalar m_factB; + bool m_hasStaticBody; + + b3Vector3 m_AnchorPos; // point betwen pivots of bodies A and B to solve linear axes + + bool m_useLinearReferenceFrameA; + bool m_useOffsetForConstraintFrame; + + int m_flags; + + //!@} + + b3Generic6DofConstraint& operator=(b3Generic6DofConstraint& other) + { + b3Assert(0); + (void) other; + return *this; + } + + + int setAngularLimits(b3ConstraintInfo2 *info, int row_offset,const b3Transform& transA,const b3Transform& transB,const b3Vector3& linVelA,const b3Vector3& linVelB,const b3Vector3& angVelA,const b3Vector3& angVelB); + + int setLinearLimits(b3ConstraintInfo2 *info, int row, const b3Transform& transA,const b3Transform& transB,const b3Vector3& linVelA,const b3Vector3& linVelB,const b3Vector3& angVelA,const b3Vector3& angVelB); + + + // tests linear limits + void calculateLinearInfo(); + + //! calcs the euler angles between the two bodies. + void calculateAngleInfo(); + + + +public: + + B3_DECLARE_ALIGNED_ALLOCATOR(); + + b3Generic6DofConstraint(int rbA, int rbB, const b3Transform& frameInA, const b3Transform& frameInB ,bool useLinearReferenceFrameA,const b3RigidBodyData* bodies); + + //! Calcs global transform of the offsets + /*! + Calcs the global transform for the joint offset for body A an B, and also calcs the agle differences between the bodies. + \sa b3Generic6DofConstraint.getCalculatedTransformA , b3Generic6DofConstraint.getCalculatedTransformB, b3Generic6DofConstraint.calculateAngleInfo + */ + void calculateTransforms(const b3Transform& transA,const b3Transform& transB,const b3RigidBodyData* bodies); + + void calculateTransforms(const b3RigidBodyData* bodies); + + //! Gets the global transform of the offset for body A + /*! + \sa b3Generic6DofConstraint.getFrameOffsetA, b3Generic6DofConstraint.getFrameOffsetB, b3Generic6DofConstraint.calculateAngleInfo. + */ + const b3Transform & getCalculatedTransformA() const + { + return m_calculatedTransformA; + } + + //! Gets the global transform of the offset for body B + /*! + \sa b3Generic6DofConstraint.getFrameOffsetA, b3Generic6DofConstraint.getFrameOffsetB, b3Generic6DofConstraint.calculateAngleInfo. + */ + const b3Transform & getCalculatedTransformB() const + { + return m_calculatedTransformB; + } + + const b3Transform & getFrameOffsetA() const + { + return m_frameInA; + } + + const b3Transform & getFrameOffsetB() const + { + return m_frameInB; + } + + + b3Transform & getFrameOffsetA() + { + return m_frameInA; + } + + b3Transform & getFrameOffsetB() + { + return m_frameInB; + } + + + + virtual void getInfo1 (b3ConstraintInfo1* info,const b3RigidBodyData* bodies); + + void getInfo1NonVirtual (b3ConstraintInfo1* info,const b3RigidBodyData* bodies); + + virtual void getInfo2 (b3ConstraintInfo2* info,const b3RigidBodyData* bodies); + + void getInfo2NonVirtual (b3ConstraintInfo2* info,const b3Transform& transA,const b3Transform& transB,const b3Vector3& linVelA,const b3Vector3& linVelB,const b3Vector3& angVelA,const b3Vector3& angVelB,const b3RigidBodyData* bodies); + + + void updateRHS(b3Scalar timeStep); + + //! Get the rotation axis in global coordinates + b3Vector3 getAxis(int axis_index) const; + + //! Get the relative Euler angle + /*! + \pre b3Generic6DofConstraint::calculateTransforms() must be called previously. + */ + b3Scalar getAngle(int axis_index) const; + + //! Get the relative position of the constraint pivot + /*! + \pre b3Generic6DofConstraint::calculateTransforms() must be called previously. + */ + b3Scalar getRelativePivotPosition(int axis_index) const; + + void setFrames(const b3Transform & frameA, const b3Transform & frameB, const b3RigidBodyData* bodies); + + //! Test angular limit. + /*! + Calculates angular correction and returns true if limit needs to be corrected. + \pre b3Generic6DofConstraint::calculateTransforms() must be called previously. + */ + bool testAngularLimitMotor(int axis_index); + + void setLinearLowerLimit(const b3Vector3& linearLower) + { + m_linearLimits.m_lowerLimit = linearLower; + } + + void getLinearLowerLimit(b3Vector3& linearLower) + { + linearLower = m_linearLimits.m_lowerLimit; + } + + void setLinearUpperLimit(const b3Vector3& linearUpper) + { + m_linearLimits.m_upperLimit = linearUpper; + } + + void getLinearUpperLimit(b3Vector3& linearUpper) + { + linearUpper = m_linearLimits.m_upperLimit; + } + + void setAngularLowerLimit(const b3Vector3& angularLower) + { + for(int i = 0; i < 3; i++) + m_angularLimits[i].m_loLimit = b3NormalizeAngle(angularLower[i]); + } + + void getAngularLowerLimit(b3Vector3& angularLower) + { + for(int i = 0; i < 3; i++) + angularLower[i] = m_angularLimits[i].m_loLimit; + } + + void setAngularUpperLimit(const b3Vector3& angularUpper) + { + for(int i = 0; i < 3; i++) + m_angularLimits[i].m_hiLimit = b3NormalizeAngle(angularUpper[i]); + } + + void getAngularUpperLimit(b3Vector3& angularUpper) + { + for(int i = 0; i < 3; i++) + angularUpper[i] = m_angularLimits[i].m_hiLimit; + } + + //! Retrieves the angular limit informacion + b3RotationalLimitMotor * getRotationalLimitMotor(int index) + { + return &m_angularLimits[index]; + } + + //! Retrieves the limit informacion + b3TranslationalLimitMotor * getTranslationalLimitMotor() + { + return &m_linearLimits; + } + + //first 3 are linear, next 3 are angular + void setLimit(int axis, b3Scalar lo, b3Scalar hi) + { + if(axis<3) + { + m_linearLimits.m_lowerLimit[axis] = lo; + m_linearLimits.m_upperLimit[axis] = hi; + } + else + { + lo = b3NormalizeAngle(lo); + hi = b3NormalizeAngle(hi); + m_angularLimits[axis-3].m_loLimit = lo; + m_angularLimits[axis-3].m_hiLimit = hi; + } + } + + //! Test limit + /*! + - 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) + { + if(limitIndex<3) + { + return m_linearLimits.isLimited(limitIndex); + + } + return m_angularLimits[limitIndex-3].isLimited(); + } + + virtual void calcAnchorPos(const b3RigidBodyData* bodies); // overridable + + int get_limit_motor_info2( b3RotationalLimitMotor * limot, + const b3Transform& transA,const b3Transform& transB,const b3Vector3& linVelA,const b3Vector3& linVelB,const b3Vector3& angVelA,const b3Vector3& angVelB, + b3ConstraintInfo2 *info, int row, b3Vector3& ax1, int rotational, int rotAllowed = false); + + // access for UseFrameOffset + bool getUseFrameOffset() { return m_useOffsetForConstraintFrame; } + void setUseFrameOffset(bool frameOffsetOnOff) { m_useOffsetForConstraintFrame = frameOffsetOnOff; } + + ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). + ///If no axis is provided, it uses the default axis for this constraint. + virtual void setParam(int num, b3Scalar value, int axis = -1); + ///return the local value of parameter + virtual b3Scalar getParam(int num, int axis = -1) const; + + void setAxis( const b3Vector3& axis1, const b3Vector3& axis2,const b3RigidBodyData* bodies); + + + + +}; + + + + + +#endif //B3_GENERIC_6DOF_CONSTRAINT_H diff --git a/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3JacobianEntry.h b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3JacobianEntry.h new file mode 100644 index 000000000000..a55168eb38f7 --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3JacobianEntry.h @@ -0,0 +1,155 @@ +/* +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 B3_JACOBIAN_ENTRY_H +#define B3_JACOBIAN_ENTRY_H + +#include "Bullet3Common/b3Matrix3x3.h" + + +//notes: +// Another memory optimization would be to store m_1MinvJt in the remaining 3 w components +// which makes the b3JacobianEntry 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 +B3_ATTRIBUTE_ALIGNED16(class) b3JacobianEntry +{ +public: + b3JacobianEntry() {}; + //constraint between two different rigidbodies + b3JacobianEntry( + const b3Matrix3x3& world2A, + const b3Matrix3x3& world2B, + const b3Vector3& rel_pos1,const b3Vector3& rel_pos2, + const b3Vector3& jointAxis, + const b3Vector3& inertiaInvA, + const b3Scalar massInvA, + const b3Vector3& inertiaInvB, + const b3Scalar 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); + + b3Assert(m_Adiag > b3Scalar(0.0)); + } + + //angular constraint between two different rigidbodies + b3JacobianEntry(const b3Vector3& jointAxis, + const b3Matrix3x3& world2A, + const b3Matrix3x3& world2B, + const b3Vector3& inertiaInvA, + const b3Vector3& inertiaInvB) + :m_linearJointAxis(b3MakeVector3(b3Scalar(0.),b3Scalar(0.),b3Scalar(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); + + b3Assert(m_Adiag > b3Scalar(0.0)); + } + + //angular constraint between two different rigidbodies + b3JacobianEntry(const b3Vector3& axisInA, + const b3Vector3& axisInB, + const b3Vector3& inertiaInvA, + const b3Vector3& inertiaInvB) + : m_linearJointAxis(b3MakeVector3(b3Scalar(0.),b3Scalar(0.),b3Scalar(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); + + b3Assert(m_Adiag > b3Scalar(0.0)); + } + + //constraint on one rigidbody + b3JacobianEntry( + const b3Matrix3x3& world2A, + const b3Vector3& rel_pos1,const b3Vector3& rel_pos2, + const b3Vector3& jointAxis, + const b3Vector3& inertiaInvA, + const b3Scalar 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 = b3MakeVector3(b3Scalar(0.),b3Scalar(0.),b3Scalar(0.)); + m_Adiag = massInvA + m_0MinvJt.dot(m_aJ); + + b3Assert(m_Adiag > b3Scalar(0.0)); + } + + b3Scalar getDiagonal() const { return m_Adiag; } + + // for two constraints on the same rigidbody (for example vehicle friction) + b3Scalar getNonDiagonal(const b3JacobianEntry& jacB, const b3Scalar massInvA) const + { + const b3JacobianEntry& jacA = *this; + b3Scalar lin = massInvA * jacA.m_linearJointAxis.dot(jacB.m_linearJointAxis); + b3Scalar 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) + b3Scalar getNonDiagonal(const b3JacobianEntry& jacB,const b3Scalar massInvA,const b3Scalar massInvB) const + { + const b3JacobianEntry& jacA = *this; + b3Vector3 lin = jacA.m_linearJointAxis * jacB.m_linearJointAxis; + b3Vector3 ang0 = jacA.m_0MinvJt * jacB.m_aJ; + b3Vector3 ang1 = jacA.m_1MinvJt * jacB.m_bJ; + b3Vector3 lin0 = massInvA * lin ; + b3Vector3 lin1 = massInvB * lin; + b3Vector3 sum = ang0+ang1+lin0+lin1; + return sum[0]+sum[1]+sum[2]; + } + + b3Scalar getRelativeVelocity(const b3Vector3& linvelA,const b3Vector3& angvelA,const b3Vector3& linvelB,const b3Vector3& angvelB) + { + b3Vector3 linrel = linvelA - linvelB; + b3Vector3 angvela = angvelA * m_aJ; + b3Vector3 angvelb = angvelB * m_bJ; + linrel *= m_linearJointAxis; + angvela += angvelb; + angvela += linrel; + b3Scalar rel_vel2 = angvela[0]+angvela[1]+angvela[2]; + return rel_vel2 + B3_EPSILON; + } +//private: + + b3Vector3 m_linearJointAxis; + b3Vector3 m_aJ; + b3Vector3 m_bJ; + b3Vector3 m_0MinvJt; + b3Vector3 m_1MinvJt; + //Optimization: can be stored in the w/last component of one of the vectors + b3Scalar m_Adiag; + +}; + +#endif //B3_JACOBIAN_ENTRY_H diff --git a/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3PgsJacobiSolver.cpp b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3PgsJacobiSolver.cpp new file mode 100644 index 000000000000..de729d4556a0 --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3PgsJacobiSolver.cpp @@ -0,0 +1,1815 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2012 Erwin Coumans http://bulletphysics.org + +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. +*/ + +//enable B3_SOLVER_DEBUG if you experience solver crashes +//#define B3_SOLVER_DEBUG +//#define COMPUTE_IMPULSE_DENOM 1 +//It is not necessary (redundant) to refresh contact manifolds, this refresh has been moved to the collision algorithms. + +//#define DISABLE_JOINTS + +#include "b3PgsJacobiSolver.h" +#include "Bullet3Common/b3MinMax.h" +#include "b3TypedConstraint.h" +#include +#include "Bullet3Common/b3StackAlloc.h" + +//#include "b3SolverBody.h" +//#include "b3SolverConstraint.h" +#include "Bullet3Common/b3AlignedObjectArray.h" +#include //for memset +//#include "../../dynamics/basic_demo/Stubs/AdlContact4.h" +#include "Bullet3Collision/NarrowPhaseCollision/b3Contact4.h" + + +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" + +static b3Transform getWorldTransform(b3RigidBodyData* rb) +{ + b3Transform newTrans; + newTrans.setOrigin(rb->m_pos); + newTrans.setRotation(rb->m_quat); + return newTrans; +} + +static const b3Matrix3x3& getInvInertiaTensorWorld(b3InertiaData* inertia) +{ + return inertia->m_invInertiaWorld; +} + + + +static const b3Vector3& getLinearVelocity(b3RigidBodyData* rb) +{ + return rb->m_linVel; +} + +static const b3Vector3& getAngularVelocity(b3RigidBodyData* rb) +{ + return rb->m_angVel; +} + +static b3Vector3 getVelocityInLocalPoint(b3RigidBodyData* rb, const b3Vector3& rel_pos) +{ + //we also calculate lin/ang velocity for kinematic objects + return getLinearVelocity(rb) + getAngularVelocity(rb).cross(rel_pos); + +} + +struct b3ContactPoint +{ + b3Vector3 m_positionWorldOnA; + b3Vector3 m_positionWorldOnB; + b3Vector3 m_normalWorldOnB; + b3Scalar m_appliedImpulse; + b3Scalar m_distance; + b3Scalar m_combinedRestitution; + + ///information related to friction + b3Scalar m_combinedFriction; + b3Vector3 m_lateralFrictionDir1; + b3Vector3 m_lateralFrictionDir2; + b3Scalar m_appliedImpulseLateral1; + b3Scalar m_appliedImpulseLateral2; + b3Scalar m_combinedRollingFriction; + b3Scalar m_contactMotion1; + b3Scalar m_contactMotion2; + b3Scalar m_contactCFM1; + b3Scalar m_contactCFM2; + + bool m_lateralFrictionInitialized; + + b3Vector3 getPositionWorldOnA() + { + return m_positionWorldOnA; + } + b3Vector3 getPositionWorldOnB() + { + return m_positionWorldOnB; + } + b3Scalar getDistance() + { + return m_distance; + } +}; + +void getContactPoint(b3Contact4* contact, int contactIndex, b3ContactPoint& pointOut) +{ + pointOut.m_appliedImpulse = 0.f; + pointOut.m_appliedImpulseLateral1 = 0.f; + pointOut.m_appliedImpulseLateral2 = 0.f; + pointOut.m_combinedFriction = contact->getFrictionCoeff(); + pointOut.m_combinedRestitution = contact->getRestituitionCoeff(); + pointOut.m_combinedRollingFriction = 0.f; + pointOut.m_contactCFM1 = 0.f; + pointOut.m_contactCFM2 = 0.f; + pointOut.m_contactMotion1 = 0.f; + pointOut.m_contactMotion2 = 0.f; + pointOut.m_distance = contact->getPenetration(contactIndex);//??0.01f + b3Vector3 normalOnB = contact->m_worldNormalOnB; + normalOnB.normalize();//is this needed? + + b3Vector3 l1,l2; + b3PlaneSpace1(normalOnB,l1,l2); + + pointOut.m_normalWorldOnB = normalOnB; + //printf("normalOnB = %f,%f,%f\n",normalOnB.getX(),normalOnB.getY(),normalOnB.getZ()); + pointOut.m_lateralFrictionDir1 = l1; + pointOut.m_lateralFrictionDir2 = l2; + pointOut.m_lateralFrictionInitialized = true; + + + b3Vector3 worldPosB = contact->m_worldPosB[contactIndex]; + pointOut.m_positionWorldOnB = worldPosB; + pointOut.m_positionWorldOnA = worldPosB+normalOnB*pointOut.m_distance; +} + +int getNumContacts(b3Contact4* contact) +{ + return contact->getNPoints(); +} + +b3PgsJacobiSolver::b3PgsJacobiSolver(bool usePgs) +:m_usePgs(usePgs), +m_numSplitImpulseRecoveries(0), +m_btSeed2(0) +{ + +} + +b3PgsJacobiSolver::~b3PgsJacobiSolver() +{ +} + +void b3PgsJacobiSolver::solveContacts(int numBodies, b3RigidBodyData* bodies, b3InertiaData* inertias, int numContacts, b3Contact4* contacts, int numConstraints, b3TypedConstraint** constraints) +{ + b3ContactSolverInfo infoGlobal; + infoGlobal.m_splitImpulse = false; + infoGlobal.m_timeStep = 1.f/60.f; + infoGlobal.m_numIterations = 4;//4; +// infoGlobal.m_solverMode|=B3_SOLVER_USE_2_FRICTION_DIRECTIONS|B3_SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS|B3_SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION; + //infoGlobal.m_solverMode|=B3_SOLVER_USE_2_FRICTION_DIRECTIONS|B3_SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS; + infoGlobal.m_solverMode|=B3_SOLVER_USE_2_FRICTION_DIRECTIONS; + + //if (infoGlobal.m_solverMode & B3_SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS) + //if ((infoGlobal.m_solverMode & B3_SOLVER_USE_2_FRICTION_DIRECTIONS) && (infoGlobal.m_solverMode & B3_SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION)) + + + solveGroup(bodies,inertias,numBodies,contacts,numContacts,constraints,numConstraints,infoGlobal); + + if (!numContacts) + return; +} + + + + +/// b3PgsJacobiSolver Sequentially applies impulses +b3Scalar b3PgsJacobiSolver::solveGroup(b3RigidBodyData* bodies, + b3InertiaData* inertias, + int numBodies, + b3Contact4* manifoldPtr, + int numManifolds, + b3TypedConstraint** constraints, + int numConstraints, + const b3ContactSolverInfo& infoGlobal) +{ + + B3_PROFILE("solveGroup"); + //you need to provide at least some bodies + + solveGroupCacheFriendlySetup( bodies, inertias,numBodies, manifoldPtr, numManifolds,constraints, numConstraints,infoGlobal); + + solveGroupCacheFriendlyIterations(constraints, numConstraints,infoGlobal); + + solveGroupCacheFriendlyFinish(bodies, inertias,numBodies, infoGlobal); + + return 0.f; +} + + + + + + + + + +#ifdef USE_SIMD +#include +#define b3VecSplat(x, e) _mm_shuffle_ps(x, x, _MM_SHUFFLE(e,e,e,e)) +static inline __m128 b3SimdDot3( __m128 vec0, __m128 vec1 ) +{ + __m128 result = _mm_mul_ps( vec0, vec1); + return _mm_add_ps( b3VecSplat( result, 0 ), _mm_add_ps( b3VecSplat( result, 1 ), b3VecSplat( result, 2 ) ) ); +} +#endif//USE_SIMD + +// Project Gauss Seidel or the equivalent Sequential Impulse +void b3PgsJacobiSolver::resolveSingleConstraintRowGenericSIMD(b3SolverBody& body1,b3SolverBody& body2,const b3SolverConstraint& c) +{ +#ifdef USE_SIMD + __m128 cpAppliedImp = _mm_set1_ps(c.m_appliedImpulse); + __m128 lowerLimit1 = _mm_set1_ps(c.m_lowerLimit); + __m128 upperLimit1 = _mm_set1_ps(c.m_upperLimit); + __m128 deltaImpulse = _mm_sub_ps(_mm_set1_ps(c.m_rhs), _mm_mul_ps(_mm_set1_ps(c.m_appliedImpulse),_mm_set1_ps(c.m_cfm))); + __m128 deltaVel1Dotn = _mm_add_ps(b3SimdDot3(c.m_contactNormal.mVec128,body1.internalGetDeltaLinearVelocity().mVec128), b3SimdDot3(c.m_relpos1CrossNormal.mVec128,body1.internalGetDeltaAngularVelocity().mVec128)); + __m128 deltaVel2Dotn = _mm_sub_ps(b3SimdDot3(c.m_relpos2CrossNormal.mVec128,body2.internalGetDeltaAngularVelocity().mVec128),b3SimdDot3((c.m_contactNormal).mVec128,body2.internalGetDeltaLinearVelocity().mVec128)); + deltaImpulse = _mm_sub_ps(deltaImpulse,_mm_mul_ps(deltaVel1Dotn,_mm_set1_ps(c.m_jacDiagABInv))); + deltaImpulse = _mm_sub_ps(deltaImpulse,_mm_mul_ps(deltaVel2Dotn,_mm_set1_ps(c.m_jacDiagABInv))); + b3SimdScalar sum = _mm_add_ps(cpAppliedImp,deltaImpulse); + b3SimdScalar resultLowerLess,resultUpperLess; + resultLowerLess = _mm_cmplt_ps(sum,lowerLimit1); + resultUpperLess = _mm_cmplt_ps(sum,upperLimit1); + __m128 lowMinApplied = _mm_sub_ps(lowerLimit1,cpAppliedImp); + deltaImpulse = _mm_or_ps( _mm_and_ps(resultLowerLess, lowMinApplied), _mm_andnot_ps(resultLowerLess, deltaImpulse) ); + c.m_appliedImpulse = _mm_or_ps( _mm_and_ps(resultLowerLess, lowerLimit1), _mm_andnot_ps(resultLowerLess, sum) ); + __m128 upperMinApplied = _mm_sub_ps(upperLimit1,cpAppliedImp); + deltaImpulse = _mm_or_ps( _mm_and_ps(resultUpperLess, deltaImpulse), _mm_andnot_ps(resultUpperLess, upperMinApplied) ); + c.m_appliedImpulse = _mm_or_ps( _mm_and_ps(resultUpperLess, c.m_appliedImpulse), _mm_andnot_ps(resultUpperLess, upperLimit1) ); + __m128 linearComponentA = _mm_mul_ps(c.m_contactNormal.mVec128,body1.internalGetInvMass().mVec128); + __m128 linearComponentB = _mm_mul_ps((c.m_contactNormal).mVec128,body2.internalGetInvMass().mVec128); + __m128 impulseMagnitude = deltaImpulse; + body1.internalGetDeltaLinearVelocity().mVec128 = _mm_add_ps(body1.internalGetDeltaLinearVelocity().mVec128,_mm_mul_ps(linearComponentA,impulseMagnitude)); + body1.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(body1.internalGetDeltaAngularVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentA.mVec128,impulseMagnitude)); + body2.internalGetDeltaLinearVelocity().mVec128 = _mm_sub_ps(body2.internalGetDeltaLinearVelocity().mVec128,_mm_mul_ps(linearComponentB,impulseMagnitude)); + body2.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(body2.internalGetDeltaAngularVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentB.mVec128,impulseMagnitude)); +#else + resolveSingleConstraintRowGeneric(body1,body2,c); +#endif +} + +// Project Gauss Seidel or the equivalent Sequential Impulse + void b3PgsJacobiSolver::resolveSingleConstraintRowGeneric(b3SolverBody& body1,b3SolverBody& body2,const b3SolverConstraint& c) +{ + b3Scalar deltaImpulse = c.m_rhs-b3Scalar(c.m_appliedImpulse)*c.m_cfm; + const b3Scalar deltaVel1Dotn = c.m_contactNormal.dot(body1.internalGetDeltaLinearVelocity()) + c.m_relpos1CrossNormal.dot(body1.internalGetDeltaAngularVelocity()); + const b3Scalar deltaVel2Dotn = -c.m_contactNormal.dot(body2.internalGetDeltaLinearVelocity()) + c.m_relpos2CrossNormal.dot(body2.internalGetDeltaAngularVelocity()); + +// const b3Scalar delta_rel_vel = deltaVel1Dotn-deltaVel2Dotn; + deltaImpulse -= deltaVel1Dotn*c.m_jacDiagABInv; + deltaImpulse -= deltaVel2Dotn*c.m_jacDiagABInv; + + const b3Scalar sum = b3Scalar(c.m_appliedImpulse) + deltaImpulse; + if (sum < c.m_lowerLimit) + { + deltaImpulse = c.m_lowerLimit-c.m_appliedImpulse; + c.m_appliedImpulse = c.m_lowerLimit; + } + else if (sum > c.m_upperLimit) + { + deltaImpulse = c.m_upperLimit-c.m_appliedImpulse; + c.m_appliedImpulse = c.m_upperLimit; + } + else + { + c.m_appliedImpulse = sum; + } + + body1.internalApplyImpulse(c.m_contactNormal*body1.internalGetInvMass(),c.m_angularComponentA,deltaImpulse); + body2.internalApplyImpulse(-c.m_contactNormal*body2.internalGetInvMass(),c.m_angularComponentB,deltaImpulse); +} + + void b3PgsJacobiSolver::resolveSingleConstraintRowLowerLimitSIMD(b3SolverBody& body1,b3SolverBody& body2,const b3SolverConstraint& c) +{ +#ifdef USE_SIMD + __m128 cpAppliedImp = _mm_set1_ps(c.m_appliedImpulse); + __m128 lowerLimit1 = _mm_set1_ps(c.m_lowerLimit); + __m128 upperLimit1 = _mm_set1_ps(c.m_upperLimit); + __m128 deltaImpulse = _mm_sub_ps(_mm_set1_ps(c.m_rhs), _mm_mul_ps(_mm_set1_ps(c.m_appliedImpulse),_mm_set1_ps(c.m_cfm))); + __m128 deltaVel1Dotn = _mm_add_ps(b3SimdDot3(c.m_contactNormal.mVec128,body1.internalGetDeltaLinearVelocity().mVec128), b3SimdDot3(c.m_relpos1CrossNormal.mVec128,body1.internalGetDeltaAngularVelocity().mVec128)); + __m128 deltaVel2Dotn = _mm_sub_ps(b3SimdDot3(c.m_relpos2CrossNormal.mVec128,body2.internalGetDeltaAngularVelocity().mVec128),b3SimdDot3((c.m_contactNormal).mVec128,body2.internalGetDeltaLinearVelocity().mVec128)); + deltaImpulse = _mm_sub_ps(deltaImpulse,_mm_mul_ps(deltaVel1Dotn,_mm_set1_ps(c.m_jacDiagABInv))); + deltaImpulse = _mm_sub_ps(deltaImpulse,_mm_mul_ps(deltaVel2Dotn,_mm_set1_ps(c.m_jacDiagABInv))); + b3SimdScalar sum = _mm_add_ps(cpAppliedImp,deltaImpulse); + b3SimdScalar resultLowerLess,resultUpperLess; + resultLowerLess = _mm_cmplt_ps(sum,lowerLimit1); + resultUpperLess = _mm_cmplt_ps(sum,upperLimit1); + __m128 lowMinApplied = _mm_sub_ps(lowerLimit1,cpAppliedImp); + deltaImpulse = _mm_or_ps( _mm_and_ps(resultLowerLess, lowMinApplied), _mm_andnot_ps(resultLowerLess, deltaImpulse) ); + c.m_appliedImpulse = _mm_or_ps( _mm_and_ps(resultLowerLess, lowerLimit1), _mm_andnot_ps(resultLowerLess, sum) ); + __m128 linearComponentA = _mm_mul_ps(c.m_contactNormal.mVec128,body1.internalGetInvMass().mVec128); + __m128 linearComponentB = _mm_mul_ps((c.m_contactNormal).mVec128,body2.internalGetInvMass().mVec128); + __m128 impulseMagnitude = deltaImpulse; + body1.internalGetDeltaLinearVelocity().mVec128 = _mm_add_ps(body1.internalGetDeltaLinearVelocity().mVec128,_mm_mul_ps(linearComponentA,impulseMagnitude)); + body1.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(body1.internalGetDeltaAngularVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentA.mVec128,impulseMagnitude)); + body2.internalGetDeltaLinearVelocity().mVec128 = _mm_sub_ps(body2.internalGetDeltaLinearVelocity().mVec128,_mm_mul_ps(linearComponentB,impulseMagnitude)); + body2.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(body2.internalGetDeltaAngularVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentB.mVec128,impulseMagnitude)); +#else + resolveSingleConstraintRowLowerLimit(body1,body2,c); +#endif +} + +// Project Gauss Seidel or the equivalent Sequential Impulse + void b3PgsJacobiSolver::resolveSingleConstraintRowLowerLimit(b3SolverBody& body1,b3SolverBody& body2,const b3SolverConstraint& c) +{ + b3Scalar deltaImpulse = c.m_rhs-b3Scalar(c.m_appliedImpulse)*c.m_cfm; + const b3Scalar deltaVel1Dotn = c.m_contactNormal.dot(body1.internalGetDeltaLinearVelocity()) + c.m_relpos1CrossNormal.dot(body1.internalGetDeltaAngularVelocity()); + const b3Scalar deltaVel2Dotn = -c.m_contactNormal.dot(body2.internalGetDeltaLinearVelocity()) + c.m_relpos2CrossNormal.dot(body2.internalGetDeltaAngularVelocity()); + + deltaImpulse -= deltaVel1Dotn*c.m_jacDiagABInv; + deltaImpulse -= deltaVel2Dotn*c.m_jacDiagABInv; + const b3Scalar sum = b3Scalar(c.m_appliedImpulse) + deltaImpulse; + if (sum < c.m_lowerLimit) + { + deltaImpulse = c.m_lowerLimit-c.m_appliedImpulse; + c.m_appliedImpulse = c.m_lowerLimit; + } + else + { + c.m_appliedImpulse = sum; + } + body1.internalApplyImpulse(c.m_contactNormal*body1.internalGetInvMass(),c.m_angularComponentA,deltaImpulse); + body2.internalApplyImpulse(-c.m_contactNormal*body2.internalGetInvMass(),c.m_angularComponentB,deltaImpulse); +} + + +void b3PgsJacobiSolver::resolveSplitPenetrationImpulseCacheFriendly( + b3SolverBody& body1, + b3SolverBody& body2, + const b3SolverConstraint& c) +{ + if (c.m_rhsPenetration) + { + m_numSplitImpulseRecoveries++; + b3Scalar deltaImpulse = c.m_rhsPenetration-b3Scalar(c.m_appliedPushImpulse)*c.m_cfm; + const b3Scalar deltaVel1Dotn = c.m_contactNormal.dot(body1.internalGetPushVelocity()) + c.m_relpos1CrossNormal.dot(body1.internalGetTurnVelocity()); + const b3Scalar deltaVel2Dotn = -c.m_contactNormal.dot(body2.internalGetPushVelocity()) + c.m_relpos2CrossNormal.dot(body2.internalGetTurnVelocity()); + + deltaImpulse -= deltaVel1Dotn*c.m_jacDiagABInv; + deltaImpulse -= deltaVel2Dotn*c.m_jacDiagABInv; + const b3Scalar sum = b3Scalar(c.m_appliedPushImpulse) + deltaImpulse; + if (sum < c.m_lowerLimit) + { + deltaImpulse = c.m_lowerLimit-c.m_appliedPushImpulse; + c.m_appliedPushImpulse = c.m_lowerLimit; + } + else + { + c.m_appliedPushImpulse = sum; + } + body1.internalApplyPushImpulse(c.m_contactNormal*body1.internalGetInvMass(),c.m_angularComponentA,deltaImpulse); + body2.internalApplyPushImpulse(-c.m_contactNormal*body2.internalGetInvMass(),c.m_angularComponentB,deltaImpulse); + } +} + + void b3PgsJacobiSolver::resolveSplitPenetrationSIMD(b3SolverBody& body1,b3SolverBody& body2,const b3SolverConstraint& c) +{ +#ifdef USE_SIMD + if (!c.m_rhsPenetration) + return; + + m_numSplitImpulseRecoveries++; + + __m128 cpAppliedImp = _mm_set1_ps(c.m_appliedPushImpulse); + __m128 lowerLimit1 = _mm_set1_ps(c.m_lowerLimit); + __m128 upperLimit1 = _mm_set1_ps(c.m_upperLimit); + __m128 deltaImpulse = _mm_sub_ps(_mm_set1_ps(c.m_rhsPenetration), _mm_mul_ps(_mm_set1_ps(c.m_appliedPushImpulse),_mm_set1_ps(c.m_cfm))); + __m128 deltaVel1Dotn = _mm_add_ps(b3SimdDot3(c.m_contactNormal.mVec128,body1.internalGetPushVelocity().mVec128), b3SimdDot3(c.m_relpos1CrossNormal.mVec128,body1.internalGetTurnVelocity().mVec128)); + __m128 deltaVel2Dotn = _mm_sub_ps(b3SimdDot3(c.m_relpos2CrossNormal.mVec128,body2.internalGetTurnVelocity().mVec128),b3SimdDot3((c.m_contactNormal).mVec128,body2.internalGetPushVelocity().mVec128)); + deltaImpulse = _mm_sub_ps(deltaImpulse,_mm_mul_ps(deltaVel1Dotn,_mm_set1_ps(c.m_jacDiagABInv))); + deltaImpulse = _mm_sub_ps(deltaImpulse,_mm_mul_ps(deltaVel2Dotn,_mm_set1_ps(c.m_jacDiagABInv))); + b3SimdScalar sum = _mm_add_ps(cpAppliedImp,deltaImpulse); + b3SimdScalar resultLowerLess,resultUpperLess; + resultLowerLess = _mm_cmplt_ps(sum,lowerLimit1); + resultUpperLess = _mm_cmplt_ps(sum,upperLimit1); + __m128 lowMinApplied = _mm_sub_ps(lowerLimit1,cpAppliedImp); + deltaImpulse = _mm_or_ps( _mm_and_ps(resultLowerLess, lowMinApplied), _mm_andnot_ps(resultLowerLess, deltaImpulse) ); + c.m_appliedPushImpulse = _mm_or_ps( _mm_and_ps(resultLowerLess, lowerLimit1), _mm_andnot_ps(resultLowerLess, sum) ); + __m128 linearComponentA = _mm_mul_ps(c.m_contactNormal.mVec128,body1.internalGetInvMass().mVec128); + __m128 linearComponentB = _mm_mul_ps((c.m_contactNormal).mVec128,body2.internalGetInvMass().mVec128); + __m128 impulseMagnitude = deltaImpulse; + body1.internalGetPushVelocity().mVec128 = _mm_add_ps(body1.internalGetPushVelocity().mVec128,_mm_mul_ps(linearComponentA,impulseMagnitude)); + body1.internalGetTurnVelocity().mVec128 = _mm_add_ps(body1.internalGetTurnVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentA.mVec128,impulseMagnitude)); + body2.internalGetPushVelocity().mVec128 = _mm_sub_ps(body2.internalGetPushVelocity().mVec128,_mm_mul_ps(linearComponentB,impulseMagnitude)); + body2.internalGetTurnVelocity().mVec128 = _mm_add_ps(body2.internalGetTurnVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentB.mVec128,impulseMagnitude)); +#else + resolveSplitPenetrationImpulseCacheFriendly(body1,body2,c); +#endif +} + + + +unsigned long b3PgsJacobiSolver::b3Rand2() +{ + m_btSeed2 = (1664525L*m_btSeed2 + 1013904223L) & 0xffffffff; + return m_btSeed2; +} + + + +//See ODE: adam's all-int straightforward(?) dRandInt (0..n-1) +int b3PgsJacobiSolver::b3RandInt2 (int n) +{ + // seems good; xor-fold and modulus + const unsigned long un = static_cast(n); + unsigned long r = b3Rand2(); + + // 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); +} + + + +void b3PgsJacobiSolver::initSolverBody(int bodyIndex, b3SolverBody* solverBody, b3RigidBodyData* rb) +{ + + solverBody->m_deltaLinearVelocity.setValue(0.f,0.f,0.f); + solverBody->m_deltaAngularVelocity.setValue(0.f,0.f,0.f); + solverBody->internalGetPushVelocity().setValue(0.f,0.f,0.f); + solverBody->internalGetTurnVelocity().setValue(0.f,0.f,0.f); + + if (rb) + { + solverBody->m_worldTransform = getWorldTransform(rb); + solverBody->internalSetInvMass(b3MakeVector3(rb->m_invMass,rb->m_invMass,rb->m_invMass)); + solverBody->m_originalBodyIndex = bodyIndex; + solverBody->m_angularFactor = b3MakeVector3(1,1,1); + solverBody->m_linearFactor = b3MakeVector3(1,1,1); + solverBody->m_linearVelocity = getLinearVelocity(rb); + solverBody->m_angularVelocity = getAngularVelocity(rb); + } else + { + solverBody->m_worldTransform.setIdentity(); + solverBody->internalSetInvMass(b3MakeVector3(0,0,0)); + solverBody->m_originalBodyIndex = bodyIndex; + solverBody->m_angularFactor.setValue(1,1,1); + solverBody->m_linearFactor.setValue(1,1,1); + solverBody->m_linearVelocity.setValue(0,0,0); + solverBody->m_angularVelocity.setValue(0,0,0); + } + + +} + + + + + + +b3Scalar b3PgsJacobiSolver::restitutionCurve(b3Scalar rel_vel, b3Scalar restitution) +{ + b3Scalar rest = restitution * -rel_vel; + return rest; +} + + + + + + +void b3PgsJacobiSolver::setupFrictionConstraint(b3RigidBodyData* bodies,b3InertiaData* inertias, b3SolverConstraint& solverConstraint, const b3Vector3& normalAxis,int solverBodyIdA,int solverBodyIdB,b3ContactPoint& cp,const b3Vector3& rel_pos1,const b3Vector3& rel_pos2,b3RigidBodyData* colObj0,b3RigidBodyData* colObj1, b3Scalar relaxation, b3Scalar desiredVelocity, b3Scalar cfmSlip) +{ + + + solverConstraint.m_contactNormal = normalAxis; + b3SolverBody& solverBodyA = m_tmpSolverBodyPool[solverBodyIdA]; + b3SolverBody& solverBodyB = m_tmpSolverBodyPool[solverBodyIdB]; + + b3RigidBodyData* body0 = &bodies[solverBodyA.m_originalBodyIndex]; + b3RigidBodyData* body1 = &bodies[solverBodyB.m_originalBodyIndex]; + + + solverConstraint.m_solverBodyIdA = solverBodyIdA; + solverConstraint.m_solverBodyIdB = solverBodyIdB; + + solverConstraint.m_friction = cp.m_combinedFriction; + solverConstraint.m_originalContactPoint = 0; + + solverConstraint.m_appliedImpulse = 0.f; + solverConstraint.m_appliedPushImpulse = 0.f; + + { + b3Vector3 ftorqueAxis1 = rel_pos1.cross(solverConstraint.m_contactNormal); + solverConstraint.m_relpos1CrossNormal = ftorqueAxis1; + solverConstraint.m_angularComponentA = body0 ? getInvInertiaTensorWorld(&inertias[solverBodyA.m_originalBodyIndex])*ftorqueAxis1 : b3MakeVector3(0,0,0); + } + { + b3Vector3 ftorqueAxis1 = rel_pos2.cross(-solverConstraint.m_contactNormal); + solverConstraint.m_relpos2CrossNormal = ftorqueAxis1; + solverConstraint.m_angularComponentB = body1 ? getInvInertiaTensorWorld(&inertias[solverBodyB.m_originalBodyIndex])*ftorqueAxis1 : b3MakeVector3(0,0,0); + } + + b3Scalar scaledDenom; + + { + b3Vector3 vec; + b3Scalar denom0 = 0.f; + b3Scalar denom1 = 0.f; + if (body0) + { + vec = ( solverConstraint.m_angularComponentA).cross(rel_pos1); + denom0 = body0->m_invMass + normalAxis.dot(vec); + } + if (body1) + { + vec = ( -solverConstraint.m_angularComponentB).cross(rel_pos2); + denom1 = body1->m_invMass + normalAxis.dot(vec); + } + + b3Scalar denom; + if (m_usePgs) + { + scaledDenom = denom = relaxation/(denom0+denom1); + } else + { + denom = relaxation/(denom0+denom1); + b3Scalar countA = body0->m_invMass ? b3Scalar(m_bodyCount[solverBodyA.m_originalBodyIndex]): 1.f; + b3Scalar countB = body1->m_invMass ? b3Scalar(m_bodyCount[solverBodyB.m_originalBodyIndex]): 1.f; + + scaledDenom = relaxation/(denom0*countA+denom1*countB); + } + + solverConstraint.m_jacDiagABInv = denom; + } + + { + + + b3Scalar rel_vel; + b3Scalar vel1Dotn = solverConstraint.m_contactNormal.dot(body0?solverBodyA.m_linearVelocity:b3MakeVector3(0,0,0)) + + solverConstraint.m_relpos1CrossNormal.dot(body0?solverBodyA.m_angularVelocity:b3MakeVector3(0,0,0)); + b3Scalar vel2Dotn = -solverConstraint.m_contactNormal.dot(body1?solverBodyB.m_linearVelocity:b3MakeVector3(0,0,0)) + + solverConstraint.m_relpos2CrossNormal.dot(body1?solverBodyB.m_angularVelocity:b3MakeVector3(0,0,0)); + + rel_vel = vel1Dotn+vel2Dotn; + +// b3Scalar positionalError = 0.f; + + b3SimdScalar velocityError = desiredVelocity - rel_vel; + b3SimdScalar velocityImpulse = velocityError * b3SimdScalar(scaledDenom);//solverConstraint.m_jacDiagABInv); + solverConstraint.m_rhs = velocityImpulse; + solverConstraint.m_cfm = cfmSlip; + solverConstraint.m_lowerLimit = 0; + solverConstraint.m_upperLimit = 1e10f; + + } +} + +b3SolverConstraint& b3PgsJacobiSolver::addFrictionConstraint(b3RigidBodyData* bodies,b3InertiaData* inertias, const b3Vector3& normalAxis,int solverBodyIdA,int solverBodyIdB,int frictionIndex,b3ContactPoint& cp,const b3Vector3& rel_pos1,const b3Vector3& rel_pos2,b3RigidBodyData* colObj0,b3RigidBodyData* colObj1, b3Scalar relaxation, b3Scalar desiredVelocity, b3Scalar cfmSlip) +{ + b3SolverConstraint& solverConstraint = m_tmpSolverContactFrictionConstraintPool.expandNonInitializing(); + solverConstraint.m_frictionIndex = frictionIndex; + setupFrictionConstraint(bodies,inertias,solverConstraint, normalAxis, solverBodyIdA, solverBodyIdB, cp, rel_pos1, rel_pos2, + colObj0, colObj1, relaxation, desiredVelocity, cfmSlip); + return solverConstraint; +} + + +void b3PgsJacobiSolver::setupRollingFrictionConstraint(b3RigidBodyData* bodies,b3InertiaData* inertias, b3SolverConstraint& solverConstraint, const b3Vector3& normalAxis1,int solverBodyIdA,int solverBodyIdB, + b3ContactPoint& cp,const b3Vector3& rel_pos1,const b3Vector3& rel_pos2, + b3RigidBodyData* colObj0,b3RigidBodyData* colObj1, b3Scalar relaxation, + b3Scalar desiredVelocity, b3Scalar cfmSlip) + +{ + b3Vector3 normalAxis=b3MakeVector3(0,0,0); + + + solverConstraint.m_contactNormal = normalAxis; + b3SolverBody& solverBodyA = m_tmpSolverBodyPool[solverBodyIdA]; + b3SolverBody& solverBodyB = m_tmpSolverBodyPool[solverBodyIdB]; + + b3RigidBodyData* body0 = &bodies[m_tmpSolverBodyPool[solverBodyIdA].m_originalBodyIndex]; + b3RigidBodyData* body1 = &bodies[m_tmpSolverBodyPool[solverBodyIdB].m_originalBodyIndex]; + + solverConstraint.m_solverBodyIdA = solverBodyIdA; + solverConstraint.m_solverBodyIdB = solverBodyIdB; + + solverConstraint.m_friction = cp.m_combinedRollingFriction; + solverConstraint.m_originalContactPoint = 0; + + solverConstraint.m_appliedImpulse = 0.f; + solverConstraint.m_appliedPushImpulse = 0.f; + + { + b3Vector3 ftorqueAxis1 = -normalAxis1; + solverConstraint.m_relpos1CrossNormal = ftorqueAxis1; + solverConstraint.m_angularComponentA = body0 ? getInvInertiaTensorWorld(&inertias[solverBodyA.m_originalBodyIndex])*ftorqueAxis1 : b3MakeVector3(0,0,0); + } + { + b3Vector3 ftorqueAxis1 = normalAxis1; + solverConstraint.m_relpos2CrossNormal = ftorqueAxis1; + solverConstraint.m_angularComponentB = body1 ? getInvInertiaTensorWorld(&inertias[solverBodyB.m_originalBodyIndex])*ftorqueAxis1 : b3MakeVector3(0,0,0); + } + + + { + b3Vector3 iMJaA = body0?getInvInertiaTensorWorld(&inertias[solverBodyA.m_originalBodyIndex])*solverConstraint.m_relpos1CrossNormal:b3MakeVector3(0,0,0); + b3Vector3 iMJaB = body1?getInvInertiaTensorWorld(&inertias[solverBodyB.m_originalBodyIndex])*solverConstraint.m_relpos2CrossNormal:b3MakeVector3(0,0,0); + b3Scalar sum = 0; + sum += iMJaA.dot(solverConstraint.m_relpos1CrossNormal); + sum += iMJaB.dot(solverConstraint.m_relpos2CrossNormal); + solverConstraint.m_jacDiagABInv = b3Scalar(1.)/sum; + } + + { + + + b3Scalar rel_vel; + b3Scalar vel1Dotn = solverConstraint.m_contactNormal.dot(body0?solverBodyA.m_linearVelocity:b3MakeVector3(0,0,0)) + + solverConstraint.m_relpos1CrossNormal.dot(body0?solverBodyA.m_angularVelocity:b3MakeVector3(0,0,0)); + b3Scalar vel2Dotn = -solverConstraint.m_contactNormal.dot(body1?solverBodyB.m_linearVelocity:b3MakeVector3(0,0,0)) + + solverConstraint.m_relpos2CrossNormal.dot(body1?solverBodyB.m_angularVelocity:b3MakeVector3(0,0,0)); + + rel_vel = vel1Dotn+vel2Dotn; + +// b3Scalar positionalError = 0.f; + + b3SimdScalar velocityError = desiredVelocity - rel_vel; + b3SimdScalar velocityImpulse = velocityError * b3SimdScalar(solverConstraint.m_jacDiagABInv); + solverConstraint.m_rhs = velocityImpulse; + solverConstraint.m_cfm = cfmSlip; + solverConstraint.m_lowerLimit = 0; + solverConstraint.m_upperLimit = 1e10f; + + } +} + + + + + + + + +b3SolverConstraint& b3PgsJacobiSolver::addRollingFrictionConstraint(b3RigidBodyData* bodies,b3InertiaData* inertias,const b3Vector3& normalAxis,int solverBodyIdA,int solverBodyIdB,int frictionIndex,b3ContactPoint& cp,const b3Vector3& rel_pos1,const b3Vector3& rel_pos2,b3RigidBodyData* colObj0,b3RigidBodyData* colObj1, b3Scalar relaxation, b3Scalar desiredVelocity, b3Scalar cfmSlip) +{ + b3SolverConstraint& solverConstraint = m_tmpSolverContactRollingFrictionConstraintPool.expandNonInitializing(); + solverConstraint.m_frictionIndex = frictionIndex; + setupRollingFrictionConstraint(bodies,inertias,solverConstraint, normalAxis, solverBodyIdA, solverBodyIdB, cp, rel_pos1, rel_pos2, + colObj0, colObj1, relaxation, desiredVelocity, cfmSlip); + return solverConstraint; +} + + +int b3PgsJacobiSolver::getOrInitSolverBody(int bodyIndex, b3RigidBodyData* bodies,b3InertiaData* inertias) +{ + //b3Assert(bodyIndex< m_tmpSolverBodyPool.size()); + + b3RigidBodyData& body = bodies[bodyIndex]; + int curIndex = -1; + if (m_usePgs || body.m_invMass==0.f) + { + if (m_bodyCount[bodyIndex]<0) + { + curIndex = m_tmpSolverBodyPool.size(); + b3SolverBody& solverBody = m_tmpSolverBodyPool.expand(); + initSolverBody(bodyIndex,&solverBody,&body); + solverBody.m_originalBodyIndex = bodyIndex; + m_bodyCount[bodyIndex] = curIndex; + } else + { + curIndex = m_bodyCount[bodyIndex]; + } + } else + { + b3Assert(m_bodyCount[bodyIndex]>0); + m_bodyCountCheck[bodyIndex]++; + curIndex = m_tmpSolverBodyPool.size(); + b3SolverBody& solverBody = m_tmpSolverBodyPool.expand(); + initSolverBody(bodyIndex,&solverBody,&body); + solverBody.m_originalBodyIndex = bodyIndex; + } + + b3Assert(curIndex>=0); + return curIndex; + +} +#include + + +void b3PgsJacobiSolver::setupContactConstraint(b3RigidBodyData* bodies, b3InertiaData* inertias,b3SolverConstraint& solverConstraint, + int solverBodyIdA, int solverBodyIdB, + b3ContactPoint& cp, const b3ContactSolverInfo& infoGlobal, + b3Vector3& vel, b3Scalar& rel_vel, b3Scalar& relaxation, + b3Vector3& rel_pos1, b3Vector3& rel_pos2) +{ + + const b3Vector3& pos1 = cp.getPositionWorldOnA(); + const b3Vector3& pos2 = cp.getPositionWorldOnB(); + + b3SolverBody* bodyA = &m_tmpSolverBodyPool[solverBodyIdA]; + b3SolverBody* bodyB = &m_tmpSolverBodyPool[solverBodyIdB]; + + b3RigidBodyData* rb0 = &bodies[bodyA->m_originalBodyIndex]; + b3RigidBodyData* rb1 = &bodies[bodyB->m_originalBodyIndex]; + +// b3Vector3 rel_pos1 = pos1 - colObj0->getWorldTransform().getOrigin(); +// b3Vector3 rel_pos2 = pos2 - colObj1->getWorldTransform().getOrigin(); + rel_pos1 = pos1 - bodyA->getWorldTransform().getOrigin(); + rel_pos2 = pos2 - bodyB->getWorldTransform().getOrigin(); + + relaxation = 1.f; + + b3Vector3 torqueAxis0 = rel_pos1.cross(cp.m_normalWorldOnB); + solverConstraint.m_angularComponentA = rb0 ? getInvInertiaTensorWorld(&inertias[bodyA->m_originalBodyIndex])*torqueAxis0 : b3MakeVector3(0,0,0); + b3Vector3 torqueAxis1 = rel_pos2.cross(cp.m_normalWorldOnB); + solverConstraint.m_angularComponentB = rb1 ? getInvInertiaTensorWorld(&inertias[bodyB->m_originalBodyIndex])*-torqueAxis1 : b3MakeVector3(0,0,0); + + b3Scalar scaledDenom; + { +#ifdef COMPUTE_IMPULSE_DENOM + b3Scalar denom0 = rb0->computeImpulseDenominator(pos1,cp.m_normalWorldOnB); + b3Scalar denom1 = rb1->computeImpulseDenominator(pos2,cp.m_normalWorldOnB); +#else + b3Vector3 vec; + b3Scalar denom0 = 0.f; + b3Scalar denom1 = 0.f; + if (rb0) + { + vec = ( solverConstraint.m_angularComponentA).cross(rel_pos1); + denom0 = rb0->m_invMass + cp.m_normalWorldOnB.dot(vec); + } + if (rb1) + { + vec = ( -solverConstraint.m_angularComponentB).cross(rel_pos2); + denom1 = rb1->m_invMass + cp.m_normalWorldOnB.dot(vec); + } +#endif //COMPUTE_IMPULSE_DENOM + + + b3Scalar denom; + if (m_usePgs) + { + scaledDenom = denom = relaxation/(denom0+denom1); + } else + { + denom = relaxation/(denom0+denom1); + + b3Scalar countA = rb0->m_invMass? b3Scalar(m_bodyCount[bodyA->m_originalBodyIndex]) : 1.f; + b3Scalar countB = rb1->m_invMass? b3Scalar(m_bodyCount[bodyB->m_originalBodyIndex]) : 1.f; + scaledDenom = relaxation/(denom0*countA+denom1*countB); + } + solverConstraint.m_jacDiagABInv = denom; + } + + solverConstraint.m_contactNormal = cp.m_normalWorldOnB; + solverConstraint.m_relpos1CrossNormal = torqueAxis0; + solverConstraint.m_relpos2CrossNormal = -torqueAxis1; + + b3Scalar restitution = 0.f; + b3Scalar penetration = cp.getDistance()+infoGlobal.m_linearSlop; + + { + b3Vector3 vel1,vel2; + + vel1 = rb0? getVelocityInLocalPoint(rb0,rel_pos1) : b3MakeVector3(0,0,0); + vel2 = rb1? getVelocityInLocalPoint(rb1, rel_pos2) : b3MakeVector3(0,0,0); + + // b3Vector3 vel2 = rb1 ? rb1->getVelocityInLocalPoint(rel_pos2) : b3Vector3(0,0,0); + vel = vel1 - vel2; + rel_vel = cp.m_normalWorldOnB.dot(vel); + + + + solverConstraint.m_friction = cp.m_combinedFriction; + + + restitution = restitutionCurve(rel_vel, cp.m_combinedRestitution); + if (restitution <= b3Scalar(0.)) + { + restitution = 0.f; + }; + } + + + ///warm starting (or zero if disabled) + if (infoGlobal.m_solverMode & B3_SOLVER_USE_WARMSTARTING) + { + solverConstraint.m_appliedImpulse = cp.m_appliedImpulse * infoGlobal.m_warmstartingFactor; + if (rb0) + bodyA->internalApplyImpulse(solverConstraint.m_contactNormal*bodyA->internalGetInvMass(),solverConstraint.m_angularComponentA,solverConstraint.m_appliedImpulse); + if (rb1) + bodyB->internalApplyImpulse(solverConstraint.m_contactNormal*bodyB->internalGetInvMass(),-solverConstraint.m_angularComponentB,-(b3Scalar)solverConstraint.m_appliedImpulse); + } else + { + solverConstraint.m_appliedImpulse = 0.f; + } + + solverConstraint.m_appliedPushImpulse = 0.f; + + { + b3Scalar vel1Dotn = solverConstraint.m_contactNormal.dot(rb0?bodyA->m_linearVelocity:b3MakeVector3(0,0,0)) + + solverConstraint.m_relpos1CrossNormal.dot(rb0?bodyA->m_angularVelocity:b3MakeVector3(0,0,0)); + b3Scalar vel2Dotn = -solverConstraint.m_contactNormal.dot(rb1?bodyB->m_linearVelocity:b3MakeVector3(0,0,0)) + + solverConstraint.m_relpos2CrossNormal.dot(rb1?bodyB->m_angularVelocity:b3MakeVector3(0,0,0)); + b3Scalar rel_vel = vel1Dotn+vel2Dotn; + + b3Scalar positionalError = 0.f; + b3Scalar velocityError = restitution - rel_vel;// * damping; + + + b3Scalar erp = infoGlobal.m_erp2; + if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold)) + { + erp = infoGlobal.m_erp; + } + + if (penetration>0) + { + positionalError = 0; + + velocityError -= penetration / infoGlobal.m_timeStep; + } else + { + positionalError = -penetration * erp/infoGlobal.m_timeStep; + } + + b3Scalar penetrationImpulse = positionalError*scaledDenom;//solverConstraint.m_jacDiagABInv; + b3Scalar velocityImpulse = velocityError *scaledDenom;//solverConstraint.m_jacDiagABInv; + + if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold)) + { + //combine position and velocity into rhs + solverConstraint.m_rhs = penetrationImpulse+velocityImpulse; + solverConstraint.m_rhsPenetration = 0.f; + + } else + { + //split position and velocity into rhs and m_rhsPenetration + solverConstraint.m_rhs = velocityImpulse; + solverConstraint.m_rhsPenetration = penetrationImpulse; + } + solverConstraint.m_cfm = 0.f; + solverConstraint.m_lowerLimit = 0; + solverConstraint.m_upperLimit = 1e10f; + } + + + + +} + + + +void b3PgsJacobiSolver::setFrictionConstraintImpulse( b3RigidBodyData* bodies, b3InertiaData* inertias,b3SolverConstraint& solverConstraint, + int solverBodyIdA, int solverBodyIdB, + b3ContactPoint& cp, const b3ContactSolverInfo& infoGlobal) +{ + + b3SolverBody* bodyA = &m_tmpSolverBodyPool[solverBodyIdA]; + b3SolverBody* bodyB = &m_tmpSolverBodyPool[solverBodyIdB]; + + + { + b3SolverConstraint& frictionConstraint1 = m_tmpSolverContactFrictionConstraintPool[solverConstraint.m_frictionIndex]; + if (infoGlobal.m_solverMode & B3_SOLVER_USE_WARMSTARTING) + { + frictionConstraint1.m_appliedImpulse = cp.m_appliedImpulseLateral1 * infoGlobal.m_warmstartingFactor; + if (bodies[bodyA->m_originalBodyIndex].m_invMass) + bodyA->internalApplyImpulse(frictionConstraint1.m_contactNormal*bodies[bodyA->m_originalBodyIndex].m_invMass,frictionConstraint1.m_angularComponentA,frictionConstraint1.m_appliedImpulse); + if (bodies[bodyB->m_originalBodyIndex].m_invMass) + bodyB->internalApplyImpulse(frictionConstraint1.m_contactNormal*bodies[bodyB->m_originalBodyIndex].m_invMass,-frictionConstraint1.m_angularComponentB,-(b3Scalar)frictionConstraint1.m_appliedImpulse); + } else + { + frictionConstraint1.m_appliedImpulse = 0.f; + } + } + + if ((infoGlobal.m_solverMode & B3_SOLVER_USE_2_FRICTION_DIRECTIONS)) + { + b3SolverConstraint& frictionConstraint2 = m_tmpSolverContactFrictionConstraintPool[solverConstraint.m_frictionIndex+1]; + if (infoGlobal.m_solverMode & B3_SOLVER_USE_WARMSTARTING) + { + frictionConstraint2.m_appliedImpulse = cp.m_appliedImpulseLateral2 * infoGlobal.m_warmstartingFactor; + if (bodies[bodyA->m_originalBodyIndex].m_invMass) + bodyA->internalApplyImpulse(frictionConstraint2.m_contactNormal*bodies[bodyA->m_originalBodyIndex].m_invMass,frictionConstraint2.m_angularComponentA,frictionConstraint2.m_appliedImpulse); + if (bodies[bodyB->m_originalBodyIndex].m_invMass) + bodyB->internalApplyImpulse(frictionConstraint2.m_contactNormal*bodies[bodyB->m_originalBodyIndex].m_invMass,-frictionConstraint2.m_angularComponentB,-(b3Scalar)frictionConstraint2.m_appliedImpulse); + } else + { + frictionConstraint2.m_appliedImpulse = 0.f; + } + } +} + + + + +void b3PgsJacobiSolver::convertContact(b3RigidBodyData* bodies, b3InertiaData* inertias,b3Contact4* manifold,const b3ContactSolverInfo& infoGlobal) +{ + b3RigidBodyData* colObj0=0,*colObj1=0; + + + int solverBodyIdA = getOrInitSolverBody(manifold->getBodyA(),bodies,inertias); + int solverBodyIdB = getOrInitSolverBody(manifold->getBodyB(),bodies,inertias); + +// b3RigidBody* bodyA = b3RigidBody::upcast(colObj0); +// b3RigidBody* bodyB = b3RigidBody::upcast(colObj1); + + b3SolverBody* solverBodyA = &m_tmpSolverBodyPool[solverBodyIdA]; + b3SolverBody* solverBodyB = &m_tmpSolverBodyPool[solverBodyIdB]; + + + + ///avoid collision response between two static objects + if (solverBodyA->m_invMass.isZero() && solverBodyB->m_invMass.isZero()) + return; + + int rollingFriction=1; + int numContacts = getNumContacts(manifold); + for (int j=0;jgetAngularVelocity(angVelA); + solverBodyB->getAngularVelocity(angVelB); + b3Vector3 relAngVel = angVelB-angVelA; + + if ((cp.m_combinedRollingFriction>0.f) && (rollingFriction>0)) + { + //only a single rollingFriction per manifold + rollingFriction--; + if (relAngVel.length()>infoGlobal.m_singleAxisRollingFrictionThreshold) + { + relAngVel.normalize(); + if (relAngVel.length()>0.001) + addRollingFrictionConstraint(bodies,inertias,relAngVel,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); + + } else + { + addRollingFrictionConstraint(bodies,inertias,cp.m_normalWorldOnB,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); + b3Vector3 axis0,axis1; + b3PlaneSpace1(cp.m_normalWorldOnB,axis0,axis1); + if (axis0.length()>0.001) + addRollingFrictionConstraint(bodies,inertias,axis0,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); + if (axis1.length()>0.001) + addRollingFrictionConstraint(bodies,inertias,axis1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); + + } + } + + ///Bullet has several options to set the friction directions + ///By default, each contact has only a single friction direction that is recomputed automatically very frame + ///based on the relative linear velocity. + ///If the relative velocity it zero, it will automatically compute a friction direction. + + ///You can also enable two friction directions, using the B3_SOLVER_USE_2_FRICTION_DIRECTIONS. + ///In that case, the second friction direction will be orthogonal to both contact normal and first friction direction. + /// + ///If you choose B3_SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION, then the friction will be independent from the relative projected velocity. + /// + ///The user can manually override the friction directions for certain contacts using a contact callback, + ///and set the cp.m_lateralFrictionInitialized to true + ///In that case, you can set the target relative motion in each friction direction (cp.m_contactMotion1 and cp.m_contactMotion2) + ///this will give a conveyor belt effect + /// + if (!(infoGlobal.m_solverMode & B3_SOLVER_ENABLE_FRICTION_DIRECTION_CACHING) || !cp.m_lateralFrictionInitialized) + { + cp.m_lateralFrictionDir1 = vel - cp.m_normalWorldOnB * rel_vel; + b3Scalar lat_rel_vel = cp.m_lateralFrictionDir1.length2(); + if (!(infoGlobal.m_solverMode & B3_SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION) && lat_rel_vel > B3_EPSILON) + { + cp.m_lateralFrictionDir1 *= 1.f/b3Sqrt(lat_rel_vel); + if((infoGlobal.m_solverMode & B3_SOLVER_USE_2_FRICTION_DIRECTIONS)) + { + cp.m_lateralFrictionDir2 = cp.m_lateralFrictionDir1.cross(cp.m_normalWorldOnB); + cp.m_lateralFrictionDir2.normalize();//?? + addFrictionConstraint(bodies,inertias,cp.m_lateralFrictionDir2,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); + + } + + addFrictionConstraint(bodies,inertias,cp.m_lateralFrictionDir1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); + + } else + { + b3PlaneSpace1(cp.m_normalWorldOnB,cp.m_lateralFrictionDir1,cp.m_lateralFrictionDir2); + + if ((infoGlobal.m_solverMode & B3_SOLVER_USE_2_FRICTION_DIRECTIONS)) + { + addFrictionConstraint(bodies,inertias,cp.m_lateralFrictionDir2,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); + } + + addFrictionConstraint(bodies,inertias,cp.m_lateralFrictionDir1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); + + if ((infoGlobal.m_solverMode & B3_SOLVER_USE_2_FRICTION_DIRECTIONS) && (infoGlobal.m_solverMode & B3_SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION)) + { + cp.m_lateralFrictionInitialized = true; + } + } + + } else + { + addFrictionConstraint(bodies,inertias,cp.m_lateralFrictionDir1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation,cp.m_contactMotion1, cp.m_contactCFM1); + + if ((infoGlobal.m_solverMode & B3_SOLVER_USE_2_FRICTION_DIRECTIONS)) + addFrictionConstraint(bodies,inertias,cp.m_lateralFrictionDir2,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation, cp.m_contactMotion2, cp.m_contactCFM2); + + setFrictionConstraintImpulse( bodies,inertias,solverConstraint, solverBodyIdA, solverBodyIdB, cp, infoGlobal); + } + + + + + } + } +} + +b3Scalar b3PgsJacobiSolver::solveGroupCacheFriendlySetup(b3RigidBodyData* bodies, b3InertiaData* inertias, int numBodies, b3Contact4* manifoldPtr, int numManifolds,b3TypedConstraint** constraints,int numConstraints,const b3ContactSolverInfo& infoGlobal) +{ + B3_PROFILE("solveGroupCacheFriendlySetup"); + + + m_maxOverrideNumSolverIterations = 0; + + + + m_tmpSolverBodyPool.resize(0); + + + m_bodyCount.resize(0); + m_bodyCount.resize(numBodies,0); + m_bodyCountCheck.resize(0); + m_bodyCountCheck.resize(numBodies,0); + + m_deltaLinearVelocities.resize(0); + m_deltaLinearVelocities.resize(numBodies,b3MakeVector3(0,0,0)); + m_deltaAngularVelocities.resize(0); + m_deltaAngularVelocities.resize(numBodies,b3MakeVector3(0,0,0)); + + //int totalBodies = 0; + + for (int i=0;igetRigidBodyA(); + int bodyIndexB = constraints[i]->getRigidBodyB(); + if (m_usePgs) + { + m_bodyCount[bodyIndexA]=-1; + m_bodyCount[bodyIndexB]=-1; + } else + { + //didn't implement joints with Jacobi version yet + b3Assert(0); + } + + } + for (int i=0;iinternalSetAppliedImpulse(0.0f); + } + } + + //b3RigidBody* rb0=0,*rb1=0; + //if (1) + { + { + + int totalNumRows = 0; + int i; + + m_tmpConstraintSizesPool.resizeNoInitialize(numConstraints); + //calculate the total number of contraint rows + for (i=0;igetJointFeedback(); + if (fb) + { + fb->m_appliedForceBodyA.setZero(); + fb->m_appliedTorqueBodyA.setZero(); + fb->m_appliedForceBodyB.setZero(); + fb->m_appliedTorqueBodyB.setZero(); + } + + if (constraints[i]->isEnabled()) + { + } + if (constraints[i]->isEnabled()) + { + constraints[i]->getInfo1(&info1,bodies); + } else + { + info1.m_numConstraintRows = 0; + info1.nub = 0; + } + totalNumRows += info1.m_numConstraintRows; + } + m_tmpSolverNonContactConstraintPool.resizeNoInitialize(totalNumRows); + + +#ifndef DISABLE_JOINTS + ///setup the b3SolverConstraints + int currentRow = 0; + + for (i=0;igetRigidBodyA()]; + //b3RigidBody& rbA = constraint->getRigidBodyA(); + // b3RigidBody& rbB = constraint->getRigidBodyB(); + b3RigidBodyData& rbB = bodies[ constraint->getRigidBodyB()]; + + int solverBodyIdA = getOrInitSolverBody(constraint->getRigidBodyA(),bodies,inertias); + int solverBodyIdB = getOrInitSolverBody(constraint->getRigidBodyB(),bodies,inertias); + + b3SolverBody* bodyAPtr = &m_tmpSolverBodyPool[solverBodyIdA]; + b3SolverBody* bodyBPtr = &m_tmpSolverBodyPool[solverBodyIdB]; + + + + + int overrideNumSolverIterations = constraint->getOverrideNumSolverIterations() > 0 ? constraint->getOverrideNumSolverIterations() : infoGlobal.m_numIterations; + if (overrideNumSolverIterations>m_maxOverrideNumSolverIterations) + m_maxOverrideNumSolverIterations = overrideNumSolverIterations; + + + int j; + for ( j=0;jinternalGetDeltaLinearVelocity().setValue(0.f,0.f,0.f); + bodyAPtr->internalGetDeltaAngularVelocity().setValue(0.f,0.f,0.f); + bodyAPtr->internalGetPushVelocity().setValue(0.f,0.f,0.f); + bodyAPtr->internalGetTurnVelocity().setValue(0.f,0.f,0.f); + bodyBPtr->internalGetDeltaLinearVelocity().setValue(0.f,0.f,0.f); + bodyBPtr->internalGetDeltaAngularVelocity().setValue(0.f,0.f,0.f); + bodyBPtr->internalGetPushVelocity().setValue(0.f,0.f,0.f); + bodyBPtr->internalGetTurnVelocity().setValue(0.f,0.f,0.f); + + + b3TypedConstraint::b3ConstraintInfo2 info2; + info2.fps = 1.f/infoGlobal.m_timeStep; + info2.erp = infoGlobal.m_erp; + info2.m_J1linearAxis = currentConstraintRow->m_contactNormal; + info2.m_J1angularAxis = currentConstraintRow->m_relpos1CrossNormal; + info2.m_J2linearAxis = 0; + info2.m_J2angularAxis = currentConstraintRow->m_relpos2CrossNormal; + info2.rowskip = sizeof(b3SolverConstraint)/sizeof(b3Scalar);//check this + ///the size of b3SolverConstraint needs be a multiple of b3Scalar + b3Assert(info2.rowskip*sizeof(b3Scalar)== sizeof(b3SolverConstraint)); + info2.m_constraintError = ¤tConstraintRow->m_rhs; + currentConstraintRow->m_cfm = infoGlobal.m_globalCfm; + info2.m_damping = infoGlobal.m_damping; + info2.cfm = ¤tConstraintRow->m_cfm; + info2.m_lowerLimit = ¤tConstraintRow->m_lowerLimit; + info2.m_upperLimit = ¤tConstraintRow->m_upperLimit; + info2.m_numIterations = infoGlobal.m_numIterations; + constraints[i]->getInfo2(&info2,bodies); + + ///finalize the constraint setup + for ( j=0;j=constraints[i]->getBreakingImpulseThreshold()) + { + solverConstraint.m_upperLimit = constraints[i]->getBreakingImpulseThreshold(); + } + + if (solverConstraint.m_lowerLimit<=-constraints[i]->getBreakingImpulseThreshold()) + { + solverConstraint.m_lowerLimit = -constraints[i]->getBreakingImpulseThreshold(); + } + + solverConstraint.m_originalContactPoint = constraint; + + b3Matrix3x3& invInertiaWorldA= inertias[constraint->getRigidBodyA()].m_invInertiaWorld; + { + + //b3Vector3 angularFactorA(1,1,1); + const b3Vector3& ftorqueAxis1 = solverConstraint.m_relpos1CrossNormal; + solverConstraint.m_angularComponentA = invInertiaWorldA*ftorqueAxis1;//*angularFactorA; + } + + b3Matrix3x3& invInertiaWorldB= inertias[constraint->getRigidBodyB()].m_invInertiaWorld; + { + + const b3Vector3& ftorqueAxis2 = solverConstraint.m_relpos2CrossNormal; + solverConstraint.m_angularComponentB = invInertiaWorldB*ftorqueAxis2;//*constraint->getRigidBodyB().getAngularFactor(); + } + + { + //it is ok to use solverConstraint.m_contactNormal instead of -solverConstraint.m_contactNormal + //because it gets multiplied iMJlB + b3Vector3 iMJlA = solverConstraint.m_contactNormal*rbA.m_invMass; + b3Vector3 iMJaA = invInertiaWorldA*solverConstraint.m_relpos1CrossNormal; + b3Vector3 iMJlB = solverConstraint.m_contactNormal*rbB.m_invMass;//sign of normal? + b3Vector3 iMJaB = invInertiaWorldB*solverConstraint.m_relpos2CrossNormal; + + b3Scalar sum = iMJlA.dot(solverConstraint.m_contactNormal); + sum += iMJaA.dot(solverConstraint.m_relpos1CrossNormal); + sum += iMJlB.dot(solverConstraint.m_contactNormal); + sum += iMJaB.dot(solverConstraint.m_relpos2CrossNormal); + b3Scalar fsum = b3Fabs(sum); + b3Assert(fsum > B3_EPSILON); + solverConstraint.m_jacDiagABInv = fsum>B3_EPSILON?b3Scalar(1.)/sum : 0.f; + } + + + ///fix rhs + ///todo: add force/torque accelerators + { + b3Scalar rel_vel; + b3Scalar vel1Dotn = solverConstraint.m_contactNormal.dot(rbA.m_linVel) + solverConstraint.m_relpos1CrossNormal.dot(rbA.m_angVel); + b3Scalar vel2Dotn = -solverConstraint.m_contactNormal.dot(rbB.m_linVel) + solverConstraint.m_relpos2CrossNormal.dot(rbB.m_angVel); + + rel_vel = vel1Dotn+vel2Dotn; + + b3Scalar restitution = 0.f; + b3Scalar positionalError = solverConstraint.m_rhs;//already filled in by getConstraintInfo2 + b3Scalar velocityError = restitution - rel_vel * info2.m_damping; + b3Scalar penetrationImpulse = positionalError*solverConstraint.m_jacDiagABInv; + b3Scalar velocityImpulse = velocityError *solverConstraint.m_jacDiagABInv; + solverConstraint.m_rhs = penetrationImpulse+velocityImpulse; + solverConstraint.m_appliedImpulse = 0.f; + + } + } + } + currentRow+=m_tmpConstraintSizesPool[i].m_numConstraintRows; + } +#endif //DISABLE_JOINTS + } + + + { + int i; + + for (i=0;ib3Scalar(0)) + { + solveManifold.m_lowerLimit = -(solveManifold.m_friction*totalImpulse); + solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse; + + resolveSingleConstraintRowGenericSIMD(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold); + } + } + + if (infoGlobal.m_solverMode & B3_SOLVER_USE_2_FRICTION_DIRECTIONS) + { + + b3SolverConstraint& solveManifold = m_tmpSolverContactFrictionConstraintPool[m_orderFrictionConstraintPool[c*multiplier+1]]; + + if (totalImpulse>b3Scalar(0)) + { + solveManifold.m_lowerLimit = -(solveManifold.m_friction*totalImpulse); + solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse; + + resolveSingleConstraintRowGenericSIMD(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold); + } + } + } + } + + } + else//B3_SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS + { + //solve the friction constraints after all contact constraints, don't interleave them + int numPoolConstraints = m_tmpSolverContactConstraintPool.size(); + int j; + + for (j=0;jb3Scalar(0)) + { + solveManifold.m_lowerLimit = -(solveManifold.m_friction*totalImpulse); + solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse; + + resolveSingleConstraintRowGenericSIMD(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold); + } + } + + + int numRollingFrictionPoolConstraints = m_tmpSolverContactRollingFrictionConstraintPool.size(); + for (j=0;jb3Scalar(0)) + { + b3Scalar rollingFrictionMagnitude = rollingFrictionConstraint.m_friction*totalImpulse; + if (rollingFrictionMagnitude>rollingFrictionConstraint.m_friction) + rollingFrictionMagnitude = rollingFrictionConstraint.m_friction; + + rollingFrictionConstraint.m_lowerLimit = -rollingFrictionMagnitude; + rollingFrictionConstraint.m_upperLimit = rollingFrictionMagnitude; + + resolveSingleConstraintRowGenericSIMD(m_tmpSolverBodyPool[rollingFrictionConstraint.m_solverBodyIdA],m_tmpSolverBodyPool[rollingFrictionConstraint.m_solverBodyIdB],rollingFrictionConstraint); + } + } + + + } + } + } else + { + //non-SIMD version + ///solve all joint constraints + for (int j=0;jb3Scalar(0)) + { + solveManifold.m_lowerLimit = -(solveManifold.m_friction*totalImpulse); + solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse; + + resolveSingleConstraintRowGeneric(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold); + } + } + + int numRollingFrictionPoolConstraints = m_tmpSolverContactRollingFrictionConstraintPool.size(); + for (int j=0;jb3Scalar(0)) + { + b3Scalar rollingFrictionMagnitude = rollingFrictionConstraint.m_friction*totalImpulse; + if (rollingFrictionMagnitude>rollingFrictionConstraint.m_friction) + rollingFrictionMagnitude = rollingFrictionConstraint.m_friction; + + rollingFrictionConstraint.m_lowerLimit = -rollingFrictionMagnitude; + rollingFrictionConstraint.m_upperLimit = rollingFrictionMagnitude; + + resolveSingleConstraintRowGeneric(m_tmpSolverBodyPool[rollingFrictionConstraint.m_solverBodyIdA],m_tmpSolverBodyPool[rollingFrictionConstraint.m_solverBodyIdB],rollingFrictionConstraint); + } + } + } + } + return 0.f; +} + + +void b3PgsJacobiSolver::solveGroupCacheFriendlySplitImpulseIterations(b3TypedConstraint** constraints,int numConstraints,const b3ContactSolverInfo& infoGlobal) +{ + int iteration; + if (infoGlobal.m_splitImpulse) + { + if (infoGlobal.m_solverMode & B3_SOLVER_SIMD) + { + for ( iteration = 0;iteration infoGlobal.m_numIterations? m_maxOverrideNumSolverIterations : infoGlobal.m_numIterations; + + for ( int iteration = 0 ; iteration< maxIterations ; iteration++) + //for ( int iteration = maxIterations-1 ; iteration >= 0;iteration--) + { + + solveSingleIteration(iteration, constraints,numConstraints,infoGlobal); + + + if (!m_usePgs) + { + averageVelocities(); + } + } + + } + return 0.f; +} + +void b3PgsJacobiSolver::averageVelocities() +{ + B3_PROFILE("averaging"); + //average the velocities + int numBodies = m_bodyCount.size(); + + m_deltaLinearVelocities.resize(0); + m_deltaLinearVelocities.resize(numBodies,b3MakeVector3(0,0,0)); + m_deltaAngularVelocities.resize(0); + m_deltaAngularVelocities.resize(numBodies,b3MakeVector3(0,0,0)); + + for (int i=0;im_appliedImpulse = solveManifold.m_appliedImpulse; + // float f = m_tmpSolverContactFrictionConstraintPool[solveManifold.m_frictionIndex].m_appliedImpulse; + // printf("pt->m_appliedImpulseLateral1 = %f\n", f); + pt->m_appliedImpulseLateral1 = m_tmpSolverContactFrictionConstraintPool[solveManifold.m_frictionIndex].m_appliedImpulse; + //printf("pt->m_appliedImpulseLateral1 = %f\n", pt->m_appliedImpulseLateral1); + if ((infoGlobal.m_solverMode & B3_SOLVER_USE_2_FRICTION_DIRECTIONS)) + { + pt->m_appliedImpulseLateral2 = m_tmpSolverContactFrictionConstraintPool[solveManifold.m_frictionIndex+1].m_appliedImpulse; + } + //do a callback here? + } + } + + numPoolConstraints = m_tmpSolverNonContactConstraintPool.size(); + for (j=0;jgetJointFeedback(); + if (fb) + { + b3SolverBody* bodyA = &m_tmpSolverBodyPool[solverConstr.m_solverBodyIdA]; + b3SolverBody* bodyB = &m_tmpSolverBodyPool[solverConstr.m_solverBodyIdB]; + + fb->m_appliedForceBodyA += solverConstr.m_contactNormal*solverConstr.m_appliedImpulse*bodyA->m_linearFactor/infoGlobal.m_timeStep; + fb->m_appliedForceBodyB += -solverConstr.m_contactNormal*solverConstr.m_appliedImpulse*bodyB->m_linearFactor/infoGlobal.m_timeStep; + fb->m_appliedTorqueBodyA += solverConstr.m_relpos1CrossNormal* bodyA->m_angularFactor*solverConstr.m_appliedImpulse/infoGlobal.m_timeStep; + fb->m_appliedTorqueBodyB += -solverConstr.m_relpos1CrossNormal* bodyB->m_angularFactor*solverConstr.m_appliedImpulse/infoGlobal.m_timeStep; + + } + + constr->internalSetAppliedImpulse(solverConstr.m_appliedImpulse); + if (b3Fabs(solverConstr.m_appliedImpulse)>=constr->getBreakingImpulseThreshold()) + { + constr->setEnabled(false); + } + } + + { + B3_PROFILE("write back velocities and transforms"); + for ( i=0;im_invMass) + { + if (infoGlobal.m_splitImpulse) + m_tmpSolverBodyPool[i].writebackVelocityAndTransform(infoGlobal.m_timeStep, infoGlobal.m_splitImpulseTurnErp); + else + m_tmpSolverBodyPool[i].writebackVelocity(); + + if (m_usePgs) + { + body->m_linVel = m_tmpSolverBodyPool[i].m_linearVelocity; + body->m_angVel = m_tmpSolverBodyPool[i].m_angularVelocity; + } else + { + b3Scalar factor = 1.f/b3Scalar(m_bodyCount[bodyIndex]); + + b3Vector3 deltaLinVel = m_deltaLinearVelocities[bodyIndex]*factor; + b3Vector3 deltaAngVel = m_deltaAngularVelocities[bodyIndex]*factor; + //printf("body %d\n",bodyIndex); + //printf("deltaLinVel = %f,%f,%f\n",deltaLinVel.getX(),deltaLinVel.getY(),deltaLinVel.getZ()); + //printf("deltaAngVel = %f,%f,%f\n",deltaAngVel.getX(),deltaAngVel.getY(),deltaAngVel.getZ()); + + body->m_linVel += deltaLinVel; + body->m_angVel += deltaAngVel; + } + + if (infoGlobal.m_splitImpulse) + { + body->m_pos = m_tmpSolverBodyPool[i].m_worldTransform.getOrigin(); + b3Quaternion orn; + orn = m_tmpSolverBodyPool[i].m_worldTransform.getRotation(); + body->m_quat = orn; + } + } + } + } + + + m_tmpSolverContactConstraintPool.resizeNoInitialize(0); + m_tmpSolverNonContactConstraintPool.resizeNoInitialize(0); + m_tmpSolverContactFrictionConstraintPool.resizeNoInitialize(0); + m_tmpSolverContactRollingFrictionConstraintPool.resizeNoInitialize(0); + + m_tmpSolverBodyPool.resizeNoInitialize(0); + return 0.f; +} + + + +void b3PgsJacobiSolver::reset() +{ + m_btSeed2 = 0; +} \ No newline at end of file diff --git a/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3PgsJacobiSolver.h b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3PgsJacobiSolver.h new file mode 100644 index 000000000000..d2ca307fab38 --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3PgsJacobiSolver.h @@ -0,0 +1,149 @@ +#ifndef B3_PGS_JACOBI_SOLVER +#define B3_PGS_JACOBI_SOLVER + + +struct b3Contact4; +struct b3ContactPoint; + + +class b3Dispatcher; + +#include "b3TypedConstraint.h" +#include "b3ContactSolverInfo.h" +#include "b3SolverBody.h" +#include "b3SolverConstraint.h" + +struct b3RigidBodyData; +struct b3InertiaData; + +class b3PgsJacobiSolver +{ + +protected: + b3AlignedObjectArray m_tmpSolverBodyPool; + b3ConstraintArray m_tmpSolverContactConstraintPool; + b3ConstraintArray m_tmpSolverNonContactConstraintPool; + b3ConstraintArray m_tmpSolverContactFrictionConstraintPool; + b3ConstraintArray m_tmpSolverContactRollingFrictionConstraintPool; + + b3AlignedObjectArray m_orderTmpConstraintPool; + b3AlignedObjectArray m_orderNonContactConstraintPool; + b3AlignedObjectArray m_orderFrictionConstraintPool; + b3AlignedObjectArray m_tmpConstraintSizesPool; + + b3AlignedObjectArray m_bodyCount; + b3AlignedObjectArray m_bodyCountCheck; + + b3AlignedObjectArray m_deltaLinearVelocities; + b3AlignedObjectArray m_deltaAngularVelocities; + + bool m_usePgs; + void averageVelocities(); + + int m_maxOverrideNumSolverIterations; + + int m_numSplitImpulseRecoveries; + + b3Scalar getContactProcessingThreshold(b3Contact4* contact) + { + return 0.02f; + } + void setupFrictionConstraint( b3RigidBodyData* bodies,b3InertiaData* inertias, b3SolverConstraint& solverConstraint, const b3Vector3& normalAxis,int solverBodyIdA,int solverBodyIdB, + b3ContactPoint& cp,const b3Vector3& rel_pos1,const b3Vector3& rel_pos2, + b3RigidBodyData* colObj0,b3RigidBodyData* colObj1, b3Scalar relaxation, + b3Scalar desiredVelocity=0., b3Scalar cfmSlip=0.); + + void setupRollingFrictionConstraint(b3RigidBodyData* bodies,b3InertiaData* inertias, b3SolverConstraint& solverConstraint, const b3Vector3& normalAxis,int solverBodyIdA,int solverBodyIdB, + b3ContactPoint& cp,const b3Vector3& rel_pos1,const b3Vector3& rel_pos2, + b3RigidBodyData* colObj0,b3RigidBodyData* colObj1, b3Scalar relaxation, + b3Scalar desiredVelocity=0., b3Scalar cfmSlip=0.); + + b3SolverConstraint& addFrictionConstraint(b3RigidBodyData* bodies,b3InertiaData* inertias,const b3Vector3& normalAxis,int solverBodyIdA,int solverBodyIdB,int frictionIndex,b3ContactPoint& cp,const b3Vector3& rel_pos1,const b3Vector3& rel_pos2,b3RigidBodyData* colObj0,b3RigidBodyData* colObj1, b3Scalar relaxation, b3Scalar desiredVelocity=0., b3Scalar cfmSlip=0.); + b3SolverConstraint& addRollingFrictionConstraint(b3RigidBodyData* bodies,b3InertiaData* inertias,const b3Vector3& normalAxis,int solverBodyIdA,int solverBodyIdB,int frictionIndex,b3ContactPoint& cp,const b3Vector3& rel_pos1,const b3Vector3& rel_pos2,b3RigidBodyData* colObj0,b3RigidBodyData* colObj1, b3Scalar relaxation, b3Scalar desiredVelocity=0, b3Scalar cfmSlip=0.f); + + + void setupContactConstraint(b3RigidBodyData* bodies, b3InertiaData* inertias, + b3SolverConstraint& solverConstraint, int solverBodyIdA, int solverBodyIdB, b3ContactPoint& cp, + const b3ContactSolverInfo& infoGlobal, b3Vector3& vel, b3Scalar& rel_vel, b3Scalar& relaxation, + b3Vector3& rel_pos1, b3Vector3& rel_pos2); + + void setFrictionConstraintImpulse( b3RigidBodyData* bodies, b3InertiaData* inertias,b3SolverConstraint& solverConstraint, int solverBodyIdA,int solverBodyIdB, + b3ContactPoint& cp, const b3ContactSolverInfo& infoGlobal); + + ///m_btSeed2 is used for re-arranging the constraint rows. improves convergence/quality of friction + unsigned long m_btSeed2; + + + b3Scalar restitutionCurve(b3Scalar rel_vel, b3Scalar restitution); + + void convertContact(b3RigidBodyData* bodies, b3InertiaData* inertias,b3Contact4* manifold,const b3ContactSolverInfo& infoGlobal); + + + void resolveSplitPenetrationSIMD( + b3SolverBody& bodyA,b3SolverBody& bodyB, + const b3SolverConstraint& contactConstraint); + + void resolveSplitPenetrationImpulseCacheFriendly( + b3SolverBody& bodyA,b3SolverBody& bodyB, + const b3SolverConstraint& contactConstraint); + + //internal method + int getOrInitSolverBody(int bodyIndex, b3RigidBodyData* bodies,b3InertiaData* inertias); + void initSolverBody(int bodyIndex, b3SolverBody* solverBody, b3RigidBodyData* collisionObject); + + void resolveSingleConstraintRowGeneric(b3SolverBody& bodyA,b3SolverBody& bodyB,const b3SolverConstraint& contactConstraint); + + void resolveSingleConstraintRowGenericSIMD(b3SolverBody& bodyA,b3SolverBody& bodyB,const b3SolverConstraint& contactConstraint); + + void resolveSingleConstraintRowLowerLimit(b3SolverBody& bodyA,b3SolverBody& bodyB,const b3SolverConstraint& contactConstraint); + + void resolveSingleConstraintRowLowerLimitSIMD(b3SolverBody& bodyA,b3SolverBody& bodyB,const b3SolverConstraint& contactConstraint); + +protected: + + virtual b3Scalar solveGroupCacheFriendlySetup(b3RigidBodyData* bodies, b3InertiaData* inertias,int numBodies,b3Contact4* manifoldPtr, int numManifolds,b3TypedConstraint** constraints,int numConstraints,const b3ContactSolverInfo& infoGlobal); + + + virtual b3Scalar solveGroupCacheFriendlyIterations(b3TypedConstraint** constraints,int numConstraints,const b3ContactSolverInfo& infoGlobal); + virtual void solveGroupCacheFriendlySplitImpulseIterations(b3TypedConstraint** constraints,int numConstraints,const b3ContactSolverInfo& infoGlobal); + b3Scalar solveSingleIteration(int iteration, b3TypedConstraint** constraints,int numConstraints,const b3ContactSolverInfo& infoGlobal); + + + virtual b3Scalar solveGroupCacheFriendlyFinish(b3RigidBodyData* bodies, b3InertiaData* inertias,int numBodies,const b3ContactSolverInfo& infoGlobal); + + +public: + + B3_DECLARE_ALIGNED_ALLOCATOR(); + + b3PgsJacobiSolver(bool usePgs); + virtual ~b3PgsJacobiSolver(); + +// void solveContacts(int numBodies, b3RigidBodyData* bodies, b3InertiaData* inertias, int numContacts, b3Contact4* contacts); + void solveContacts(int numBodies, b3RigidBodyData* bodies, b3InertiaData* inertias, int numContacts, b3Contact4* contacts, int numConstraints, b3TypedConstraint** constraints); + + b3Scalar solveGroup(b3RigidBodyData* bodies,b3InertiaData* inertias,int numBodies,b3Contact4* manifoldPtr, int numManifolds,b3TypedConstraint** constraints,int numConstraints,const b3ContactSolverInfo& infoGlobal); + + ///clear internal cached data and reset random seed + virtual void reset(); + + unsigned long b3Rand2(); + + int b3RandInt2 (int n); + + void setRandSeed(unsigned long seed) + { + m_btSeed2 = seed; + } + unsigned long getRandSeed() const + { + return m_btSeed2; + } + + + + +}; + +#endif //B3_PGS_JACOBI_SOLVER + diff --git a/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3Point2PointConstraint.cpp b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3Point2PointConstraint.cpp new file mode 100644 index 000000000000..02c11db32097 --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3Point2PointConstraint.cpp @@ -0,0 +1,209 @@ +/* +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 "b3Point2PointConstraint.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" + +#include + + + + + +b3Point2PointConstraint::b3Point2PointConstraint(int rbA,int rbB, const b3Vector3& pivotInA,const b3Vector3& pivotInB) +:b3TypedConstraint(B3_POINT2POINT_CONSTRAINT_TYPE,rbA,rbB),m_pivotInA(pivotInA),m_pivotInB(pivotInB), +m_flags(0) +{ + +} + +/* +b3Point2PointConstraint::b3Point2PointConstraint(int rbA,const b3Vector3& pivotInA) +:b3TypedConstraint(B3_POINT2POINT_CONSTRAINT_TYPE,rbA),m_pivotInA(pivotInA),m_pivotInB(rbA.getCenterOfMassTransform()(pivotInA)), +m_flags(0), +m_useSolveConstraintObsolete(false) +{ + +} +*/ + + +void b3Point2PointConstraint::getInfo1 (b3ConstraintInfo1* info,const b3RigidBodyData* bodies) +{ + getInfo1NonVirtual(info,bodies); +} + +void b3Point2PointConstraint::getInfo1NonVirtual (b3ConstraintInfo1* info,const b3RigidBodyData* bodies) +{ + info->m_numConstraintRows = 3; + info->nub = 3; +} + + + + +void b3Point2PointConstraint::getInfo2 (b3ConstraintInfo2* info, const b3RigidBodyData* bodies) +{ + b3Transform trA; + trA.setIdentity(); + trA.setOrigin(bodies[m_rbA].m_pos); + trA.setRotation(bodies[m_rbA].m_quat); + + b3Transform trB; + trB.setIdentity(); + trB.setOrigin(bodies[m_rbB].m_pos); + trB.setRotation(bodies[m_rbB].m_quat); + + getInfo2NonVirtual(info, trA,trB); +} + +void b3Point2PointConstraint::getInfo2NonVirtual (b3ConstraintInfo2* info, const b3Transform& body0_trans, const b3Transform& body1_trans) +{ + + //retrieve matrices + + // anchor points in global coordinates with respect to body PORs. + + // set jacobian + info->m_J1linearAxis[0] = 1; + info->m_J1linearAxis[info->rowskip+1] = 1; + info->m_J1linearAxis[2*info->rowskip+2] = 1; + + b3Vector3 a1 = body0_trans.getBasis()*getPivotInA(); + //b3Vector3 a1a = b3QuatRotate(body0_trans.getRotation(),getPivotInA()); + + { + b3Vector3* angular0 = (b3Vector3*)(info->m_J1angularAxis); + b3Vector3* angular1 = (b3Vector3*)(info->m_J1angularAxis+info->rowskip); + b3Vector3* angular2 = (b3Vector3*)(info->m_J1angularAxis+2*info->rowskip); + b3Vector3 a1neg = -a1; + a1neg.getSkewSymmetricMatrix(angular0,angular1,angular2); + } + + if (info->m_J2linearAxis) + { + info->m_J2linearAxis[0] = -1; + info->m_J2linearAxis[info->rowskip+1] = -1; + info->m_J2linearAxis[2*info->rowskip+2] = -1; + } + + b3Vector3 a2 = body1_trans.getBasis()*getPivotInB(); + + { + // b3Vector3 a2n = -a2; + b3Vector3* angular0 = (b3Vector3*)(info->m_J2angularAxis); + b3Vector3* angular1 = (b3Vector3*)(info->m_J2angularAxis+info->rowskip); + b3Vector3* angular2 = (b3Vector3*)(info->m_J2angularAxis+2*info->rowskip); + a2.getSkewSymmetricMatrix(angular0,angular1,angular2); + } + + + + // set right hand side + b3Scalar currERP = (m_flags & B3_P2P_FLAGS_ERP) ? m_erp : info->erp; + b3Scalar k = info->fps * currERP; + int j; + for (j=0; j<3; j++) + { + info->m_constraintError[j*info->rowskip] = k * (a2[j] + body1_trans.getOrigin()[j] - a1[j] - body0_trans.getOrigin()[j]); + //printf("info->m_constraintError[%d]=%f\n",j,info->m_constraintError[j]); + } + if(m_flags & B3_P2P_FLAGS_CFM) + { + for (j=0; j<3; j++) + { + info->cfm[j*info->rowskip] = m_cfm; + } + } + + b3Scalar impulseClamp = m_setting.m_impulseClamp;// + for (j=0; j<3; j++) + { + if (m_setting.m_impulseClamp > 0) + { + info->m_lowerLimit[j*info->rowskip] = -impulseClamp; + info->m_upperLimit[j*info->rowskip] = impulseClamp; + } + } + info->m_damping = m_setting.m_damping; + +} + + + +void b3Point2PointConstraint::updateRHS(b3Scalar timeStep) +{ + (void)timeStep; + +} + +///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). +///If no axis is provided, it uses the default axis for this constraint. +void b3Point2PointConstraint::setParam(int num, b3Scalar value, int axis) +{ + if(axis != -1) + { + b3AssertConstrParams(0); + } + else + { + switch(num) + { + case B3_CONSTRAINT_ERP : + case B3_CONSTRAINT_STOP_ERP : + m_erp = value; + m_flags |= B3_P2P_FLAGS_ERP; + break; + case B3_CONSTRAINT_CFM : + case B3_CONSTRAINT_STOP_CFM : + m_cfm = value; + m_flags |= B3_P2P_FLAGS_CFM; + break; + default: + b3AssertConstrParams(0); + } + } +} + +///return the local value of parameter +b3Scalar b3Point2PointConstraint::getParam(int num, int axis) const +{ + b3Scalar retVal(B3_INFINITY); + if(axis != -1) + { + b3AssertConstrParams(0); + } + else + { + switch(num) + { + case B3_CONSTRAINT_ERP : + case B3_CONSTRAINT_STOP_ERP : + b3AssertConstrParams(m_flags & B3_P2P_FLAGS_ERP); + retVal = m_erp; + break; + case B3_CONSTRAINT_CFM : + case B3_CONSTRAINT_STOP_CFM : + b3AssertConstrParams(m_flags & B3_P2P_FLAGS_CFM); + retVal = m_cfm; + break; + default: + b3AssertConstrParams(0); + } + } + return retVal; +} + diff --git a/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3Point2PointConstraint.h b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3Point2PointConstraint.h new file mode 100644 index 000000000000..681b487334c7 --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3Point2PointConstraint.h @@ -0,0 +1,159 @@ +/* +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 B3_POINT2POINTCONSTRAINT_H +#define B3_POINT2POINTCONSTRAINT_H + +#include "Bullet3Common/b3Vector3.h" +//#include "b3JacobianEntry.h" +#include "b3TypedConstraint.h" + +class b3RigidBody; + + +#ifdef B3_USE_DOUBLE_PRECISION +#define b3Point2PointConstraintData b3Point2PointConstraintDoubleData +#define b3Point2PointConstraintDataName "b3Point2PointConstraintDoubleData" +#else +#define b3Point2PointConstraintData b3Point2PointConstraintFloatData +#define b3Point2PointConstraintDataName "b3Point2PointConstraintFloatData" +#endif //B3_USE_DOUBLE_PRECISION + +struct b3ConstraintSetting +{ + b3ConstraintSetting() : + m_tau(b3Scalar(0.3)), + m_damping(b3Scalar(1.)), + m_impulseClamp(b3Scalar(0.)) + { + } + b3Scalar m_tau; + b3Scalar m_damping; + b3Scalar m_impulseClamp; +}; + +enum b3Point2PointFlags +{ + B3_P2P_FLAGS_ERP = 1, + B3_P2P_FLAGS_CFM = 2 +}; + +/// point to point constraint between two rigidbodies each with a pivotpoint that descibes the 'ballsocket' location in local space +B3_ATTRIBUTE_ALIGNED16(class) b3Point2PointConstraint : public b3TypedConstraint +{ +#ifdef IN_PARALLELL_SOLVER +public: +#endif + + b3Vector3 m_pivotInA; + b3Vector3 m_pivotInB; + + int m_flags; + b3Scalar m_erp; + b3Scalar m_cfm; + +public: + + B3_DECLARE_ALIGNED_ALLOCATOR(); + + b3ConstraintSetting m_setting; + + b3Point2PointConstraint(int rbA,int rbB, const b3Vector3& pivotInA,const b3Vector3& pivotInB); + + //b3Point2PointConstraint(int rbA,const b3Vector3& pivotInA); + + + + virtual void getInfo1 (b3ConstraintInfo1* info,const b3RigidBodyData* bodies); + + void getInfo1NonVirtual (b3ConstraintInfo1* info,const b3RigidBodyData* bodies); + + virtual void getInfo2 (b3ConstraintInfo2* info, const b3RigidBodyData* bodies); + + void getInfo2NonVirtual (b3ConstraintInfo2* info, const b3Transform& body0_trans, const b3Transform& body1_trans); + + void updateRHS(b3Scalar timeStep); + + void setPivotA(const b3Vector3& pivotA) + { + m_pivotInA = pivotA; + } + + void setPivotB(const b3Vector3& pivotB) + { + m_pivotInB = pivotB; + } + + const b3Vector3& getPivotInA() const + { + return m_pivotInA; + } + + const b3Vector3& getPivotInB() const + { + return m_pivotInB; + } + + ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). + ///If no axis is provided, it uses the default axis for this constraint. + virtual void setParam(int num, b3Scalar value, int axis = -1); + ///return the local value of parameter + virtual b3Scalar getParam(int num, int axis = -1) const; + +// virtual int calculateSerializeBufferSize() const; + + ///fills the dataBuffer and returns the struct name (and 0 on failure) +// virtual const char* serialize(void* dataBuffer, b3Serializer* serializer) const; + + +}; + +///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 +struct b3Point2PointConstraintFloatData +{ + b3TypedConstraintData m_typeConstraintData; + b3Vector3FloatData m_pivotInA; + b3Vector3FloatData m_pivotInB; +}; + +///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 +struct b3Point2PointConstraintDoubleData +{ + b3TypedConstraintData m_typeConstraintData; + b3Vector3DoubleData m_pivotInA; + b3Vector3DoubleData m_pivotInB; +}; + +/* +B3_FORCE_INLINE int b3Point2PointConstraint::calculateSerializeBufferSize() const +{ + return sizeof(b3Point2PointConstraintData); + +} + + ///fills the dataBuffer and returns the struct name (and 0 on failure) +B3_FORCE_INLINE const char* b3Point2PointConstraint::serialize(void* dataBuffer, b3Serializer* serializer) const +{ + b3Point2PointConstraintData* p2pData = (b3Point2PointConstraintData*)dataBuffer; + + b3TypedConstraint::serialize(&p2pData->m_typeConstraintData,serializer); + m_pivotInA.serialize(p2pData->m_pivotInA); + m_pivotInB.serialize(p2pData->m_pivotInB); + + return b3Point2PointConstraintDataName; +} +*/ + +#endif //B3_POINT2POINTCONSTRAINT_H diff --git a/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3SolverBody.h b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3SolverBody.h new file mode 100644 index 000000000000..0049317d981b --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3SolverBody.h @@ -0,0 +1,302 @@ +/* +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 B3_SOLVER_BODY_H +#define B3_SOLVER_BODY_H + + +#include "Bullet3Common/b3Vector3.h" +#include "Bullet3Common/b3Matrix3x3.h" + +#include "Bullet3Common/b3AlignedAllocator.h" +#include "Bullet3Common/b3TransformUtil.h" + +///Until we get other contributions, only use SIMD on Windows, when using Visual Studio 2008 or later, and not double precision +#ifdef B3_USE_SSE +#define USE_SIMD 1 +#endif // + + +#ifdef USE_SIMD + +struct b3SimdScalar +{ + B3_FORCE_INLINE b3SimdScalar() + { + + } + + B3_FORCE_INLINE b3SimdScalar(float fl) + :m_vec128 (_mm_set1_ps(fl)) + { + } + + B3_FORCE_INLINE b3SimdScalar(__m128 v128) + :m_vec128(v128) + { + } + union + { + __m128 m_vec128; + float m_floats[4]; + float x,y,z,w; + int m_ints[4]; + b3Scalar m_unusedPadding; + }; + B3_FORCE_INLINE __m128 get128() + { + return m_vec128; + } + + B3_FORCE_INLINE const __m128 get128() const + { + return m_vec128; + } + + B3_FORCE_INLINE void set128(__m128 v128) + { + m_vec128 = v128; + } + + B3_FORCE_INLINE operator __m128() + { + return m_vec128; + } + B3_FORCE_INLINE operator const __m128() const + { + return m_vec128; + } + + B3_FORCE_INLINE operator float() const + { + return m_floats[0]; + } + +}; + +///@brief Return the elementwise product of two b3SimdScalar +B3_FORCE_INLINE b3SimdScalar +operator*(const b3SimdScalar& v1, const b3SimdScalar& v2) +{ + return b3SimdScalar(_mm_mul_ps(v1.get128(),v2.get128())); +} + +///@brief Return the elementwise product of two b3SimdScalar +B3_FORCE_INLINE b3SimdScalar +operator+(const b3SimdScalar& v1, const b3SimdScalar& v2) +{ + return b3SimdScalar(_mm_add_ps(v1.get128(),v2.get128())); +} + + +#else +#define b3SimdScalar b3Scalar +#endif + +///The b3SolverBody is an internal datastructure for the constraint solver. Only necessary data is packed to increase cache coherence/performance. +B3_ATTRIBUTE_ALIGNED16 (struct) b3SolverBody +{ + B3_DECLARE_ALIGNED_ALLOCATOR(); + b3Transform m_worldTransform; + b3Vector3 m_deltaLinearVelocity; + b3Vector3 m_deltaAngularVelocity; + b3Vector3 m_angularFactor; + b3Vector3 m_linearFactor; + b3Vector3 m_invMass; + b3Vector3 m_pushVelocity; + b3Vector3 m_turnVelocity; + b3Vector3 m_linearVelocity; + b3Vector3 m_angularVelocity; + + union + { + void* m_originalBody; + int m_originalBodyIndex; + }; + + int padding[3]; + + + void setWorldTransform(const b3Transform& worldTransform) + { + m_worldTransform = worldTransform; + } + + const b3Transform& getWorldTransform() const + { + return m_worldTransform; + } + + B3_FORCE_INLINE void getVelocityInLocalPointObsolete(const b3Vector3& rel_pos, b3Vector3& velocity ) const + { + if (m_originalBody) + velocity = m_linearVelocity+m_deltaLinearVelocity + (m_angularVelocity+m_deltaAngularVelocity).cross(rel_pos); + else + velocity.setValue(0,0,0); + } + + B3_FORCE_INLINE void getAngularVelocity(b3Vector3& angVel) const + { + if (m_originalBody) + angVel =m_angularVelocity+m_deltaAngularVelocity; + else + angVel.setValue(0,0,0); + } + + + //Optimization for the iterative solver: avoid calculating constant terms involving inertia, normal, relative position + B3_FORCE_INLINE void applyImpulse(const b3Vector3& linearComponent, const b3Vector3& angularComponent,const b3Scalar impulseMagnitude) + { + if (m_originalBody) + { + m_deltaLinearVelocity += linearComponent*impulseMagnitude*m_linearFactor; + m_deltaAngularVelocity += angularComponent*(impulseMagnitude*m_angularFactor); + } + } + + B3_FORCE_INLINE void internalApplyPushImpulse(const b3Vector3& linearComponent, const b3Vector3& angularComponent,b3Scalar impulseMagnitude) + { + if (m_originalBody) + { + m_pushVelocity += linearComponent*impulseMagnitude*m_linearFactor; + m_turnVelocity += angularComponent*(impulseMagnitude*m_angularFactor); + } + } + + + + const b3Vector3& getDeltaLinearVelocity() const + { + return m_deltaLinearVelocity; + } + + const b3Vector3& getDeltaAngularVelocity() const + { + return m_deltaAngularVelocity; + } + + const b3Vector3& getPushVelocity() const + { + return m_pushVelocity; + } + + const b3Vector3& getTurnVelocity() const + { + return m_turnVelocity; + } + + + //////////////////////////////////////////////// + ///some internal methods, don't use them + + b3Vector3& internalGetDeltaLinearVelocity() + { + return m_deltaLinearVelocity; + } + + b3Vector3& internalGetDeltaAngularVelocity() + { + return m_deltaAngularVelocity; + } + + const b3Vector3& internalGetAngularFactor() const + { + return m_angularFactor; + } + + const b3Vector3& internalGetInvMass() const + { + return m_invMass; + } + + void internalSetInvMass(const b3Vector3& invMass) + { + m_invMass = invMass; + } + + b3Vector3& internalGetPushVelocity() + { + return m_pushVelocity; + } + + b3Vector3& internalGetTurnVelocity() + { + return m_turnVelocity; + } + + B3_FORCE_INLINE void internalGetVelocityInLocalPointObsolete(const b3Vector3& rel_pos, b3Vector3& velocity ) const + { + velocity = m_linearVelocity+m_deltaLinearVelocity + (m_angularVelocity+m_deltaAngularVelocity).cross(rel_pos); + } + + B3_FORCE_INLINE void internalGetAngularVelocity(b3Vector3& angVel) const + { + angVel = m_angularVelocity+m_deltaAngularVelocity; + } + + + //Optimization for the iterative solver: avoid calculating constant terms involving inertia, normal, relative position + B3_FORCE_INLINE void internalApplyImpulse(const b3Vector3& linearComponent, const b3Vector3& angularComponent,const b3Scalar impulseMagnitude) + { + //if (m_originalBody) + { + m_deltaLinearVelocity += linearComponent*impulseMagnitude*m_linearFactor; + m_deltaAngularVelocity += angularComponent*(impulseMagnitude*m_angularFactor); + } + } + + + + + void writebackVelocity() + { + //if (m_originalBody>=0) + { + m_linearVelocity +=m_deltaLinearVelocity; + m_angularVelocity += m_deltaAngularVelocity; + + //m_originalBody->setCompanionId(-1); + } + } + + + void writebackVelocityAndTransform(b3Scalar timeStep, b3Scalar splitImpulseTurnErp) + { + (void) timeStep; + if (m_originalBody) + { + m_linearVelocity += m_deltaLinearVelocity; + m_angularVelocity += m_deltaAngularVelocity; + + //correct the position/orientation based on push/turn recovery + b3Transform newTransform; + if (m_pushVelocity[0]!=0.f || m_pushVelocity[1]!=0 || m_pushVelocity[2]!=0 || m_turnVelocity[0]!=0.f || m_turnVelocity[1]!=0 || m_turnVelocity[2]!=0) + { + // b3Quaternion orn = m_worldTransform.getRotation(); + b3TransformUtil::integrateTransform(m_worldTransform,m_pushVelocity,m_turnVelocity*splitImpulseTurnErp,timeStep,newTransform); + m_worldTransform = newTransform; + } + //m_worldTransform.setRotation(orn); + //m_originalBody->setCompanionId(-1); + } + } + + + +}; + +#endif //B3_SOLVER_BODY_H + + diff --git a/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3SolverConstraint.h b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3SolverConstraint.h new file mode 100644 index 000000000000..bce83d460898 --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3SolverConstraint.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 B3_SOLVER_CONSTRAINT_H +#define B3_SOLVER_CONSTRAINT_H + + +#include "Bullet3Common/b3Vector3.h" +#include "Bullet3Common/b3Matrix3x3.h" +//#include "b3JacobianEntry.h" +#include "Bullet3Common/b3AlignedObjectArray.h" + +//#define NO_FRICTION_TANGENTIALS 1 +#include "b3SolverBody.h" + + +///1D constraint along a normal axis between bodyA and bodyB. It can be combined to solve contact and friction constraints. +B3_ATTRIBUTE_ALIGNED16 (struct) b3SolverConstraint +{ + B3_DECLARE_ALIGNED_ALLOCATOR(); + + b3Vector3 m_relpos1CrossNormal; + b3Vector3 m_contactNormal; + + b3Vector3 m_relpos2CrossNormal; + //b3Vector3 m_contactNormal2;//usually m_contactNormal2 == -m_contactNormal + + b3Vector3 m_angularComponentA; + b3Vector3 m_angularComponentB; + + mutable b3SimdScalar m_appliedPushImpulse; + mutable b3SimdScalar m_appliedImpulse; + int m_padding1; + int m_padding2; + b3Scalar m_friction; + b3Scalar m_jacDiagABInv; + b3Scalar m_rhs; + b3Scalar m_cfm; + + b3Scalar m_lowerLimit; + b3Scalar m_upperLimit; + b3Scalar m_rhsPenetration; + union + { + void* m_originalContactPoint; + b3Scalar m_unusedPadding4; + }; + + int m_overrideNumSolverIterations; + int m_frictionIndex; + int m_solverBodyIdA; + int m_solverBodyIdB; + + + enum b3SolverConstraintType + { + B3_SOLVER_CONTACT_1D = 0, + B3_SOLVER_FRICTION_1D + }; +}; + +typedef b3AlignedObjectArray b3ConstraintArray; + + +#endif //B3_SOLVER_CONSTRAINT_H + + + diff --git a/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3TypedConstraint.cpp b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3TypedConstraint.cpp new file mode 100644 index 000000000000..699c481d64a6 --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3TypedConstraint.cpp @@ -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. +*/ + + +#include "b3TypedConstraint.h" +//#include "Bullet3Common/b3Serializer.h" + + +#define B3_DEFAULT_DEBUGDRAW_SIZE b3Scalar(0.3f) + + + +b3TypedConstraint::b3TypedConstraint(b3TypedConstraintType type, int rbA,int rbB) +:b3TypedObject(type), +m_userConstraintType(-1), +m_userConstraintPtr((void*)-1), +m_breakingImpulseThreshold(B3_INFINITY), +m_isEnabled(true), +m_needsFeedback(false), +m_overrideNumSolverIterations(-1), +m_rbA(rbA), +m_rbB(rbB), +m_appliedImpulse(b3Scalar(0.)), +m_dbgDrawSize(B3_DEFAULT_DEBUGDRAW_SIZE), +m_jointFeedback(0) +{ +} + + + + +b3Scalar b3TypedConstraint::getMotorFactor(b3Scalar pos, b3Scalar lowLim, b3Scalar uppLim, b3Scalar vel, b3Scalar timeFact) +{ + if(lowLim > uppLim) + { + return b3Scalar(1.0f); + } + else if(lowLim == uppLim) + { + return b3Scalar(0.0f); + } + b3Scalar lim_fact = b3Scalar(1.0f); + b3Scalar delta_max = vel / timeFact; + if(delta_max < b3Scalar(0.0f)) + { + if((pos >= lowLim) && (pos < (lowLim - delta_max))) + { + lim_fact = (lowLim - pos) / delta_max; + } + else if(pos < lowLim) + { + lim_fact = b3Scalar(0.0f); + } + else + { + lim_fact = b3Scalar(1.0f); + } + } + else if(delta_max > b3Scalar(0.0f)) + { + if((pos <= uppLim) && (pos > (uppLim - delta_max))) + { + lim_fact = (uppLim - pos) / delta_max; + } + else if(pos > uppLim) + { + lim_fact = b3Scalar(0.0f); + } + else + { + lim_fact = b3Scalar(1.0f); + } + } + else + { + lim_fact = b3Scalar(0.0f); + } + return lim_fact; +} + + + +void b3AngularLimit::set(b3Scalar low, b3Scalar high, b3Scalar _softness, b3Scalar _biasFactor, b3Scalar _relaxationFactor) +{ + m_halfRange = (high - low) / 2.0f; + m_center = b3NormalizeAngle(low + m_halfRange); + m_softness = _softness; + m_biasFactor = _biasFactor; + m_relaxationFactor = _relaxationFactor; +} + +void b3AngularLimit::test(const b3Scalar angle) +{ + m_correction = 0.0f; + m_sign = 0.0f; + m_solveLimit = false; + + if (m_halfRange >= 0.0f) + { + b3Scalar deviation = b3NormalizeAngle(angle - m_center); + if (deviation < -m_halfRange) + { + m_solveLimit = true; + m_correction = - (deviation + m_halfRange); + m_sign = +1.0f; + } + else if (deviation > m_halfRange) + { + m_solveLimit = true; + m_correction = m_halfRange - deviation; + m_sign = -1.0f; + } + } +} + + +b3Scalar b3AngularLimit::getError() const +{ + return m_correction * m_sign; +} + +void b3AngularLimit::fit(b3Scalar& angle) const +{ + if (m_halfRange > 0.0f) + { + b3Scalar relativeAngle = b3NormalizeAngle(angle - m_center); + if (!b3Equal(relativeAngle, m_halfRange)) + { + if (relativeAngle > 0.0f) + { + angle = getHigh(); + } + else + { + angle = getLow(); + } + } + } +} + +b3Scalar b3AngularLimit::getLow() const +{ + return b3NormalizeAngle(m_center - m_halfRange); +} + +b3Scalar b3AngularLimit::getHigh() const +{ + return b3NormalizeAngle(m_center + m_halfRange); +} diff --git a/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3TypedConstraint.h b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3TypedConstraint.h new file mode 100644 index 000000000000..cf9cec0d5edf --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/ConstraintSolver/b3TypedConstraint.h @@ -0,0 +1,483 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2010 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 B3_TYPED_CONSTRAINT_H +#define B3_TYPED_CONSTRAINT_H + + +#include "Bullet3Common/b3Scalar.h" +#include "b3SolverConstraint.h" + +class b3Serializer; + +//Don't change any of the existing enum values, so add enum types at the end for serialization compatibility +enum b3TypedConstraintType +{ + B3_POINT2POINT_CONSTRAINT_TYPE=3, + B3_HINGE_CONSTRAINT_TYPE, + B3_CONETWIST_CONSTRAINT_TYPE, + B3_D6_CONSTRAINT_TYPE, + B3_SLIDER_CONSTRAINT_TYPE, + B3_CONTACT_CONSTRAINT_TYPE, + B3_D6_SPRING_CONSTRAINT_TYPE, + B3_GEAR_CONSTRAINT_TYPE, + B3_FIXED_CONSTRAINT_TYPE, + B3_MAX_CONSTRAINT_TYPE +}; + + +enum b3ConstraintParams +{ + B3_CONSTRAINT_ERP=1, + B3_CONSTRAINT_STOP_ERP, + B3_CONSTRAINT_CFM, + B3_CONSTRAINT_STOP_CFM +}; + +#if 1 + #define b3AssertConstrParams(_par) b3Assert(_par) +#else + #define b3AssertConstrParams(_par) +#endif + + +B3_ATTRIBUTE_ALIGNED16(struct) b3JointFeedback +{ + b3Vector3 m_appliedForceBodyA; + b3Vector3 m_appliedTorqueBodyA; + b3Vector3 m_appliedForceBodyB; + b3Vector3 m_appliedTorqueBodyB; +}; + + +struct b3RigidBodyData; + + +///TypedConstraint is the baseclass for Bullet constraints and vehicles +B3_ATTRIBUTE_ALIGNED16(class) b3TypedConstraint : public b3TypedObject +{ + int m_userConstraintType; + + union + { + int m_userConstraintId; + void* m_userConstraintPtr; + }; + + b3Scalar m_breakingImpulseThreshold; + bool m_isEnabled; + bool m_needsFeedback; + int m_overrideNumSolverIterations; + + + b3TypedConstraint& operator=(b3TypedConstraint& other) + { + b3Assert(0); + (void) other; + return *this; + } + +protected: + int m_rbA; + int m_rbB; + b3Scalar m_appliedImpulse; + b3Scalar m_dbgDrawSize; + b3JointFeedback* m_jointFeedback; + + ///internal method used by the constraint solver, don't use them directly + b3Scalar getMotorFactor(b3Scalar pos, b3Scalar lowLim, b3Scalar uppLim, b3Scalar vel, b3Scalar timeFact); + + +public: + + B3_DECLARE_ALIGNED_ALLOCATOR(); + + virtual ~b3TypedConstraint() {}; + b3TypedConstraint(b3TypedConstraintType type, int bodyA,int bodyB); + + struct b3ConstraintInfo1 { + int m_numConstraintRows,nub; + }; + + + + struct b3ConstraintInfo2 { + // integrator parameters: frames per second (1/stepsize), default error + // reduction parameter (0..1). + b3Scalar 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. + b3Scalar *m_J1linearAxis,*m_J1angularAxis,*m_J2linearAxis,*m_J2angularAxis; + + // 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. + b3Scalar *m_constraintError,*cfm; + + // lo and hi limits for variables (set to -/+ infinity on entry). + b3Scalar *m_lowerLimit,*m_upperLimit; + + // 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; + // number of solver iterations + int m_numIterations; + + //damping of the velocity + b3Scalar m_damping; + }; + + int getOverrideNumSolverIterations() const + { + return m_overrideNumSolverIterations; + } + + ///override the number of constraint solver iterations used to solve this constraint + ///-1 will use the default number of iterations, as specified in SolverInfo.m_numIterations + void setOverrideNumSolverIterations(int overideNumIterations) + { + m_overrideNumSolverIterations = overideNumIterations; + } + + + ///internal method used by the constraint solver, don't use them directly + virtual void setupSolverConstraint(b3ConstraintArray& ca, int solverBodyA,int solverBodyB, b3Scalar timeStep) + { + (void)ca; + (void)solverBodyA; + (void)solverBodyB; + (void)timeStep; + } + + ///internal method used by the constraint solver, don't use them directly + virtual void getInfo1 (b3ConstraintInfo1* info,const b3RigidBodyData* bodies)=0; + + ///internal method used by the constraint solver, don't use them directly + virtual void getInfo2 (b3ConstraintInfo2* info, const b3RigidBodyData* bodies)=0; + + ///internal method used by the constraint solver, don't use them directly + void internalSetAppliedImpulse(b3Scalar appliedImpulse) + { + m_appliedImpulse = appliedImpulse; + } + ///internal method used by the constraint solver, don't use them directly + b3Scalar internalGetAppliedImpulse() + { + return m_appliedImpulse; + } + + + b3Scalar getBreakingImpulseThreshold() const + { + return m_breakingImpulseThreshold; + } + + void setBreakingImpulseThreshold(b3Scalar threshold) + { + m_breakingImpulseThreshold = threshold; + } + + bool isEnabled() const + { + return m_isEnabled; + } + + void setEnabled(bool enabled) + { + m_isEnabled=enabled; + } + + + ///internal method used by the constraint solver, don't use them directly + virtual void solveConstraintObsolete(b3SolverBody& /*bodyA*/,b3SolverBody& /*bodyB*/,b3Scalar /*timeStep*/) {}; + + + int getRigidBodyA() const + { + return m_rbA; + } + int getRigidBodyB() const + { + return m_rbB; + } + + + int getRigidBodyA() + { + return m_rbA; + } + int 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() const + { + return m_userConstraintId; + } + + void setUserConstraintPtr(void* ptr) + { + m_userConstraintPtr = ptr; + } + + void* getUserConstraintPtr() + { + return m_userConstraintPtr; + } + + void setJointFeedback(b3JointFeedback* jointFeedback) + { + m_jointFeedback = jointFeedback; + } + + const b3JointFeedback* getJointFeedback() const + { + return m_jointFeedback; + } + + b3JointFeedback* getJointFeedback() + { + return m_jointFeedback; + } + + + int getUid() const + { + return m_userConstraintId; + } + + bool needsFeedback() const + { + return m_needsFeedback; + } + + ///enableFeedback will allow to read the applied linear and angular impulse + ///use getAppliedImpulse, getAppliedLinearImpulse and getAppliedAngularImpulse to read feedback information + void enableFeedback(bool needsFeedback) + { + m_needsFeedback = needsFeedback; + } + + ///getAppliedImpulse is an estimated total applied impulse. + ///This feedback could be used to determine breaking constraints or playing sounds. + b3Scalar getAppliedImpulse() const + { + b3Assert(m_needsFeedback); + return m_appliedImpulse; + } + + b3TypedConstraintType getConstraintType () const + { + return b3TypedConstraintType(m_objectType); + } + + void setDbgDrawSize(b3Scalar dbgDrawSize) + { + m_dbgDrawSize = dbgDrawSize; + } + b3Scalar getDbgDrawSize() + { + return m_dbgDrawSize; + } + + ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). + ///If no axis is provided, it uses the default axis for this constraint. + virtual void setParam(int num, b3Scalar value, int axis = -1) = 0; + + ///return the local value of parameter + virtual b3Scalar getParam(int num, int axis = -1) const = 0; + +// virtual int calculateSerializeBufferSize() const; + + ///fills the dataBuffer and returns the struct name (and 0 on failure) + //virtual const char* serialize(void* dataBuffer, b3Serializer* serializer) const; + +}; + +// returns angle in range [-B3_2_PI, B3_2_PI], closest to one of the limits +// all arguments should be normalized angles (i.e. in range [-B3_PI, B3_PI]) +B3_FORCE_INLINE b3Scalar b3AdjustAngleToLimits(b3Scalar angleInRadians, b3Scalar angleLowerLimitInRadians, b3Scalar angleUpperLimitInRadians) +{ + if(angleLowerLimitInRadians >= angleUpperLimitInRadians) + { + return angleInRadians; + } + else if(angleInRadians < angleLowerLimitInRadians) + { + b3Scalar diffLo = b3Fabs(b3NormalizeAngle(angleLowerLimitInRadians - angleInRadians)); + b3Scalar diffHi = b3Fabs(b3NormalizeAngle(angleUpperLimitInRadians - angleInRadians)); + return (diffLo < diffHi) ? angleInRadians : (angleInRadians + B3_2_PI); + } + else if(angleInRadians > angleUpperLimitInRadians) + { + b3Scalar diffHi = b3Fabs(b3NormalizeAngle(angleInRadians - angleUpperLimitInRadians)); + b3Scalar diffLo = b3Fabs(b3NormalizeAngle(angleInRadians - angleLowerLimitInRadians)); + return (diffLo < diffHi) ? (angleInRadians - B3_2_PI) : angleInRadians; + } + else + { + return angleInRadians; + } +} + +///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 +struct b3TypedConstraintData +{ + int m_bodyA; + int m_bodyB; + char *m_name; + + int m_objectType; + int m_userConstraintType; + int m_userConstraintId; + int m_needsFeedback; + + float m_appliedImpulse; + float m_dbgDrawSize; + + int m_disableCollisionsBetweenLinkedBodies; + int m_overrideNumSolverIterations; + + float m_breakingImpulseThreshold; + int m_isEnabled; + +}; + +/*B3_FORCE_INLINE int b3TypedConstraint::calculateSerializeBufferSize() const +{ + return sizeof(b3TypedConstraintData); +} +*/ + + +class b3AngularLimit +{ +private: + b3Scalar + m_center, + m_halfRange, + m_softness, + m_biasFactor, + m_relaxationFactor, + m_correction, + m_sign; + + bool + m_solveLimit; + +public: + /// Default constructor initializes limit as inactive, allowing free constraint movement + b3AngularLimit() + :m_center(0.0f), + m_halfRange(-1.0f), + m_softness(0.9f), + m_biasFactor(0.3f), + m_relaxationFactor(1.0f), + m_correction(0.0f), + m_sign(0.0f), + m_solveLimit(false) + {} + + /// Sets all limit's parameters. + /// When low > high limit becomes inactive. + /// When high - low > 2PI limit is ineffective too becouse no angle can exceed the limit + void set(b3Scalar low, b3Scalar high, b3Scalar _softness = 0.9f, b3Scalar _biasFactor = 0.3f, b3Scalar _relaxationFactor = 1.0f); + + /// Checks conastaint angle against limit. If limit is active and the angle violates the limit + /// correction is calculated. + void test(const b3Scalar angle); + + /// Returns limit's softness + inline b3Scalar getSoftness() const + { + return m_softness; + } + + /// Returns limit's bias factor + inline b3Scalar getBiasFactor() const + { + return m_biasFactor; + } + + /// Returns limit's relaxation factor + inline b3Scalar getRelaxationFactor() const + { + return m_relaxationFactor; + } + + /// Returns correction value evaluated when test() was invoked + inline b3Scalar getCorrection() const + { + return m_correction; + } + + /// Returns sign value evaluated when test() was invoked + inline b3Scalar getSign() const + { + return m_sign; + } + + /// Gives half of the distance between min and max limit angle + inline b3Scalar getHalfRange() const + { + return m_halfRange; + } + + /// Returns true when the last test() invocation recognized limit violation + inline bool isLimit() const + { + return m_solveLimit; + } + + /// Checks given angle against limit. If limit is active and angle doesn't fit it, the angle + /// returned is modified so it equals to the limit closest to given angle. + void fit(b3Scalar& angle) const; + + /// Returns correction value multiplied by sign value + b3Scalar getError() const; + + b3Scalar getLow() const; + + b3Scalar getHigh() const; + +}; + + + +#endif //B3_TYPED_CONSTRAINT_H diff --git a/extern/bullet/src/Bullet3Dynamics/b3CpuRigidBodyPipeline.cpp b/extern/bullet/src/Bullet3Dynamics/b3CpuRigidBodyPipeline.cpp new file mode 100644 index 000000000000..fbc84cc28d6e --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/b3CpuRigidBodyPipeline.cpp @@ -0,0 +1,488 @@ +#include "b3CpuRigidBodyPipeline.h" + +#include "Bullet3Dynamics/shared/b3IntegrateTransforms.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" +#include "Bullet3Collision/BroadPhaseCollision/b3DynamicBvhBroadphase.h" +#include "Bullet3Collision/NarrowPhaseCollision/b3Config.h" +#include "Bullet3Collision/NarrowPhaseCollision/b3CpuNarrowPhase.h" +#include "Bullet3Collision/BroadPhaseCollision/shared/b3Aabb.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3Collidable.h" +#include "Bullet3Common/b3Vector3.h" +#include "Bullet3Dynamics/shared/b3ContactConstraint4.h" +#include "Bullet3Dynamics/shared/b3Inertia.h" + + +struct b3CpuRigidBodyPipelineInternalData +{ + b3AlignedObjectArray m_rigidBodies; + b3AlignedObjectArray m_inertias; + b3AlignedObjectArray m_aabbWorldSpace; + + b3DynamicBvhBroadphase* m_bp; + b3CpuNarrowPhase* m_np; + b3Config m_config; +}; + + +b3CpuRigidBodyPipeline::b3CpuRigidBodyPipeline(class b3CpuNarrowPhase* narrowphase, struct b3DynamicBvhBroadphase* broadphaseDbvt, const b3Config& config) +{ + m_data = new b3CpuRigidBodyPipelineInternalData; + m_data->m_np = narrowphase; + m_data->m_bp = broadphaseDbvt; + m_data->m_config = config; +} + +b3CpuRigidBodyPipeline::~b3CpuRigidBodyPipeline() +{ + delete m_data; +} + +void b3CpuRigidBodyPipeline::updateAabbWorldSpace() +{ + + for (int i=0;igetNumBodies();i++) + { + b3RigidBodyData* body = &m_data->m_rigidBodies[i]; + b3Float4 position = body->m_pos; + b3Quat orientation = body->m_quat; + + int collidableIndex = body->m_collidableIdx; + b3Collidable& collidable = m_data->m_np->getCollidableCpu(collidableIndex); + int shapeIndex = collidable.m_shapeIndex; + + if (shapeIndex>=0) + { + + + b3Aabb localAabb = m_data->m_np->getLocalSpaceAabb(shapeIndex); + b3Aabb& worldAabb = m_data->m_aabbWorldSpace[i]; + float margin=0.f; + b3TransformAabb2(localAabb.m_minVec,localAabb.m_maxVec,margin,position,orientation,&worldAabb.m_minVec,&worldAabb.m_maxVec); + m_data->m_bp->setAabb(i,worldAabb.m_minVec,worldAabb.m_maxVec,0); + } + } +} + +void b3CpuRigidBodyPipeline::computeOverlappingPairs() +{ + int numPairs = m_data->m_bp->getOverlappingPairCache()->getNumOverlappingPairs(); + m_data->m_bp->calculateOverlappingPairs(); + numPairs = m_data->m_bp->getOverlappingPairCache()->getNumOverlappingPairs(); + printf("numPairs=%d\n",numPairs); +} + +void b3CpuRigidBodyPipeline::computeContactPoints() +{ + + b3AlignedObjectArray& pairs = m_data->m_bp->getOverlappingPairCache()->getOverlappingPairArray(); + + m_data->m_np->computeContacts(pairs,m_data->m_aabbWorldSpace, m_data->m_rigidBodies); + +} +void b3CpuRigidBodyPipeline::stepSimulation(float deltaTime) +{ + + //update world space aabb's + updateAabbWorldSpace(); + + //compute overlapping pairs + computeOverlappingPairs(); + + //compute contacts + computeContactPoints(); + + //solve contacts + + //update transforms + integrate(deltaTime); + + +} + + +static inline float b3CalcRelVel(const b3Vector3& l0, const b3Vector3& l1, const b3Vector3& a0, const b3Vector3& a1, + const b3Vector3& linVel0, const b3Vector3& angVel0, const b3Vector3& linVel1, const b3Vector3& angVel1) +{ + return b3Dot(l0, linVel0) + b3Dot(a0, angVel0) + b3Dot(l1, linVel1) + b3Dot(a1, angVel1); +} + + +static inline void b3SetLinearAndAngular(const b3Vector3& n, const b3Vector3& r0, const b3Vector3& r1, + b3Vector3& linear, b3Vector3& angular0, b3Vector3& angular1) +{ + linear = -n; + angular0 = -b3Cross(r0, n); + angular1 = b3Cross(r1, n); +} + + + +static inline void b3SolveContact(b3ContactConstraint4& cs, + const b3Vector3& posA, b3Vector3& linVelA, b3Vector3& angVelA, float invMassA, const b3Matrix3x3& invInertiaA, + const b3Vector3& posB, b3Vector3& linVelB, b3Vector3& angVelB, float invMassB, const b3Matrix3x3& invInertiaB, + float maxRambdaDt[4], float minRambdaDt[4]) +{ + + b3Vector3 dLinVelA; dLinVelA.setZero(); + b3Vector3 dAngVelA; dAngVelA.setZero(); + b3Vector3 dLinVelB; dLinVelB.setZero(); + b3Vector3 dAngVelB; dAngVelB.setZero(); + + for(int ic=0; ic<4; ic++) + { + // dont necessary because this makes change to 0 + if( cs.m_jacCoeffInv[ic] == 0.f ) continue; + + { + b3Vector3 angular0, angular1, linear; + b3Vector3 r0 = cs.m_worldPos[ic] - (b3Vector3&)posA; + b3Vector3 r1 = cs.m_worldPos[ic] - (b3Vector3&)posB; + b3SetLinearAndAngular( (const b3Vector3 &)-cs.m_linear, (const b3Vector3 &)r0, (const b3Vector3 &)r1, linear, angular0, angular1 ); + + float rambdaDt = b3CalcRelVel((const b3Vector3 &)cs.m_linear,(const b3Vector3 &) -cs.m_linear, angular0, angular1, + linVelA, angVelA, linVelB, angVelB ) + cs.m_b[ic]; + rambdaDt *= cs.m_jacCoeffInv[ic]; + + { + float prevSum = cs.m_appliedRambdaDt[ic]; + float updated = prevSum; + updated += rambdaDt; + updated = b3Max( updated, minRambdaDt[ic] ); + updated = b3Min( updated, maxRambdaDt[ic] ); + rambdaDt = updated - prevSum; + cs.m_appliedRambdaDt[ic] = updated; + } + + b3Vector3 linImp0 = invMassA*linear*rambdaDt; + b3Vector3 linImp1 = invMassB*(-linear)*rambdaDt; + b3Vector3 angImp0 = (invInertiaA* angular0)*rambdaDt; + b3Vector3 angImp1 = (invInertiaB* angular1)*rambdaDt; +#ifdef _WIN32 + b3Assert(_finite(linImp0.getX())); + b3Assert(_finite(linImp1.getX())); +#endif + { + linVelA += linImp0; + angVelA += angImp0; + linVelB += linImp1; + angVelB += angImp1; + } + } + } + + +} + + + + + +static inline void b3SolveFriction(b3ContactConstraint4& cs, + const b3Vector3& posA, b3Vector3& linVelA, b3Vector3& angVelA, float invMassA, const b3Matrix3x3& invInertiaA, + const b3Vector3& posB, b3Vector3& linVelB, b3Vector3& angVelB, float invMassB, const b3Matrix3x3& invInertiaB, + float maxRambdaDt[4], float minRambdaDt[4]) +{ + + if( cs.m_fJacCoeffInv[0] == 0 && cs.m_fJacCoeffInv[0] == 0 ) return; + const b3Vector3& center = (const b3Vector3&)cs.m_center; + + b3Vector3 n = -(const b3Vector3&)cs.m_linear; + + b3Vector3 tangent[2]; + + b3PlaneSpace1 (n, tangent[0],tangent[1]); + + b3Vector3 angular0, angular1, linear; + b3Vector3 r0 = center - posA; + b3Vector3 r1 = center - posB; + for(int i=0; i<2; i++) + { + b3SetLinearAndAngular( tangent[i], r0, r1, linear, angular0, angular1 ); + float rambdaDt = b3CalcRelVel(linear, -linear, angular0, angular1, + linVelA, angVelA, linVelB, angVelB ); + rambdaDt *= cs.m_fJacCoeffInv[i]; + + { + float prevSum = cs.m_fAppliedRambdaDt[i]; + float updated = prevSum; + updated += rambdaDt; + updated = b3Max( updated, minRambdaDt[i] ); + updated = b3Min( updated, maxRambdaDt[i] ); + rambdaDt = updated - prevSum; + cs.m_fAppliedRambdaDt[i] = updated; + } + + b3Vector3 linImp0 = invMassA*linear*rambdaDt; + b3Vector3 linImp1 = invMassB*(-linear)*rambdaDt; + b3Vector3 angImp0 = (invInertiaA* angular0)*rambdaDt; + b3Vector3 angImp1 = (invInertiaB* angular1)*rambdaDt; +#ifdef _WIN32 + b3Assert(_finite(linImp0.getX())); + b3Assert(_finite(linImp1.getX())); +#endif + linVelA += linImp0; + angVelA += angImp0; + linVelB += linImp1; + angVelB += angImp1; + } + + { // angular damping for point constraint + b3Vector3 ab = ( posB - posA ).normalized(); + b3Vector3 ac = ( center - posA ).normalized(); + if( b3Dot( ab, ac ) > 0.95f || (invMassA == 0.f || invMassB == 0.f)) + { + float angNA = b3Dot( n, angVelA ); + float angNB = b3Dot( n, angVelB ); + + angVelA -= (angNA*0.1f)*n; + angVelB -= (angNB*0.1f)*n; + } + } + +} + + + + + +struct b3SolveTask// : public ThreadPool::Task +{ + b3SolveTask(b3AlignedObjectArray& bodies, + b3AlignedObjectArray& shapes, + b3AlignedObjectArray& constraints, + int start, int nConstraints, + int maxNumBatches, + b3AlignedObjectArray* wgUsedBodies, int curWgidx + ) + : m_bodies( bodies ), m_shapes( shapes ), m_constraints( constraints ), + m_wgUsedBodies(wgUsedBodies),m_curWgidx(curWgidx), +m_start( start ), + m_nConstraints( nConstraints ), + m_solveFriction( true ), + m_maxNumBatches(maxNumBatches) + {} + + unsigned short int getType(){ return 0; } + + void run(int tIdx) + { + b3AlignedObjectArray usedBodies; + //printf("run..............\n"); + + + for (int bb=0;bb=0; ic--) + //for(int ic=0; ic& m_bodies; + b3AlignedObjectArray& m_shapes; + b3AlignedObjectArray& m_constraints; + b3AlignedObjectArray* m_wgUsedBodies; + int m_curWgidx; + int m_start; + int m_nConstraints; + bool m_solveFriction; + int m_maxNumBatches; +}; + +void b3CpuRigidBodyPipeline::solveContactConstraints() +{ + int m_nIterations = 4; + + b3AlignedObjectArray contactConstraints; +// const b3AlignedObjectArray& contacts = m_data->m_np->getContacts(); + int n = contactConstraints.size(); + //convert contacts... + + + + int maxNumBatches = 250; + + for(int iter=0; iterm_rigidBodies, m_data->m_inertias, contactConstraints, 0, n ,maxNumBatches,0,0); + task.m_solveFriction = false; + task.run(0); + } + + for(int iter=0; iterm_rigidBodies, m_data->m_inertias, contactConstraints, 0, n ,maxNumBatches,0,0); + task.m_solveFriction = true; + task.run(0); + } +} + +void b3CpuRigidBodyPipeline::integrate(float deltaTime) +{ + float angDamping=0.f; + b3Vector3 gravityAcceleration=b3MakeVector3(0,-9,0); + + //integrate transforms (external forces/gravity should be moved into constraint solver) + for (int i=0;im_rigidBodies.size();i++) + { + b3IntegrateTransform(&m_data->m_rigidBodies[i],deltaTime,angDamping,gravityAcceleration); + } + +} + +int b3CpuRigidBodyPipeline::registerPhysicsInstance(float mass, const float* position, const float* orientation, int collidableIndex, int userData) +{ + b3RigidBodyData body; + int bodyIndex = m_data->m_rigidBodies.size(); + body.m_invMass = mass ? 1.f/mass : 0.f; + body.m_angVel.setValue(0,0,0); + body.m_collidableIdx = collidableIndex; + body.m_frictionCoeff = 0.3f; + body.m_linVel.setValue(0,0,0); + body.m_pos.setValue(position[0],position[1],position[2]); + body.m_quat.setValue(orientation[0],orientation[1],orientation[2],orientation[3]); + body.m_restituitionCoeff = 0.f; + + m_data->m_rigidBodies.push_back(body); + + + if (collidableIndex>=0) + { + b3Aabb& worldAabb = m_data->m_aabbWorldSpace.expand(); + + b3Aabb localAabb = m_data->m_np->getLocalSpaceAabb(collidableIndex); + b3Vector3 localAabbMin=b3MakeVector3(localAabb.m_min[0],localAabb.m_min[1],localAabb.m_min[2]); + b3Vector3 localAabbMax=b3MakeVector3(localAabb.m_max[0],localAabb.m_max[1],localAabb.m_max[2]); + + b3Scalar margin = 0.01f; + b3Transform t; + t.setIdentity(); + t.setOrigin(b3MakeVector3(position[0],position[1],position[2])); + t.setRotation(b3Quaternion(orientation[0],orientation[1],orientation[2],orientation[3])); + b3TransformAabb(localAabbMin,localAabbMax, margin,t,worldAabb.m_minVec,worldAabb.m_maxVec); + + m_data->m_bp->createProxy(worldAabb.m_minVec,worldAabb.m_maxVec,bodyIndex,0,1,1); +// b3Vector3 aabbMin,aabbMax; + // m_data->m_bp->getAabb(bodyIndex,aabbMin,aabbMax); + + } else + { + b3Error("registerPhysicsInstance using invalid collidableIndex\n"); + } + + return bodyIndex; +} + + +const struct b3RigidBodyData* b3CpuRigidBodyPipeline::getBodyBuffer() const +{ + return m_data->m_rigidBodies.size() ? &m_data->m_rigidBodies[0] : 0; +} + +int b3CpuRigidBodyPipeline::getNumBodies() const +{ + return m_data->m_rigidBodies.size(); +} diff --git a/extern/bullet/src/Bullet3Dynamics/b3CpuRigidBodyPipeline.h b/extern/bullet/src/Bullet3Dynamics/b3CpuRigidBodyPipeline.h new file mode 100644 index 000000000000..2f3c2ae77e03 --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/b3CpuRigidBodyPipeline.h @@ -0,0 +1,67 @@ +/* +Copyright (c) 2013 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Erwin Coumans + +#ifndef B3_CPU_RIGIDBODY_PIPELINE_H +#define B3_CPU_RIGIDBODY_PIPELINE_H + + + +#include "Bullet3Common/b3AlignedObjectArray.h" +#include "Bullet3Collision/NarrowPhaseCollision/b3RaycastInfo.h" + +class b3CpuRigidBodyPipeline +{ +protected: + struct b3CpuRigidBodyPipelineInternalData* m_data; + + int allocateCollidable(); + +public: + + + b3CpuRigidBodyPipeline(class b3CpuNarrowPhase* narrowphase, struct b3DynamicBvhBroadphase* broadphaseDbvt, const struct b3Config& config); + virtual ~b3CpuRigidBodyPipeline(); + + virtual void stepSimulation(float deltaTime); + virtual void integrate(float timeStep); + virtual void updateAabbWorldSpace(); + virtual void computeOverlappingPairs(); + virtual void computeContactPoints(); + virtual void solveContactConstraints(); + + int registerConvexPolyhedron(class b3ConvexUtility* convex); + + int registerPhysicsInstance(float mass, const float* position, const float* orientation, int collisionShapeIndex, int userData); + void writeAllInstancesToGpu(); + void copyConstraintsToHost(); + void setGravity(const float* grav); + void reset(); + + int createPoint2PointConstraint(int bodyA, int bodyB, const float* pivotInA, const float* pivotInB,float breakingThreshold); + int createFixedConstraint(int bodyA, int bodyB, const float* pivotInA, const float* pivotInB, const float* relTargetAB, float breakingThreshold); + void removeConstraintByUid(int uid); + + void addConstraint(class b3TypedConstraint* constraint); + void removeConstraint(b3TypedConstraint* constraint); + + void castRays(const b3AlignedObjectArray& rays, b3AlignedObjectArray& hitResults); + + const struct b3RigidBodyData* getBodyBuffer() const; + + int getNumBodies() const; + +}; + +#endif //B3_CPU_RIGIDBODY_PIPELINE_H \ No newline at end of file diff --git a/extern/bullet/src/Bullet3Dynamics/premake4.lua b/extern/bullet/src/Bullet3Dynamics/premake4.lua new file mode 100644 index 000000000000..669336a6a1d2 --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/premake4.lua @@ -0,0 +1,15 @@ + project "Bullet3Dynamics" + + language "C++" + + kind "StaticLib" + + includedirs { + ".." + } + + + files { + "**.cpp", + "**.h" + } \ No newline at end of file diff --git a/extern/bullet/src/Bullet3Dynamics/shared/b3ContactConstraint4.h b/extern/bullet/src/Bullet3Dynamics/shared/b3ContactConstraint4.h new file mode 100644 index 000000000000..68cf65e3129e --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/shared/b3ContactConstraint4.h @@ -0,0 +1,34 @@ +#ifndef B3_CONTACT_CONSTRAINT5_H +#define B3_CONTACT_CONSTRAINT5_H + +#include "Bullet3Common/shared/b3Float4.h" + +typedef struct b3ContactConstraint4 b3ContactConstraint4_t; + + +struct b3ContactConstraint4 +{ + + b3Float4 m_linear;//normal? + b3Float4 m_worldPos[4]; + b3Float4 m_center; // friction + float m_jacCoeffInv[4]; + float m_b[4]; + float m_appliedRambdaDt[4]; + float m_fJacCoeffInv[2]; // friction + float m_fAppliedRambdaDt[2]; // friction + + unsigned int m_bodyA; + unsigned int m_bodyB; + int m_batchIdx; + unsigned int m_paddings; + +}; + +//inline void setFrictionCoeff(float value) { m_linear[3] = value; } +inline float b3GetFrictionCoeff(b3ContactConstraint4_t* constraint) +{ + return constraint->m_linear.w; +} + +#endif //B3_CONTACT_CONSTRAINT5_H diff --git a/extern/bullet/src/Bullet3Dynamics/shared/b3ConvertConstraint4.h b/extern/bullet/src/Bullet3Dynamics/shared/b3ConvertConstraint4.h new file mode 100644 index 000000000000..805a2bd3ea09 --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/shared/b3ConvertConstraint4.h @@ -0,0 +1,153 @@ + + +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3Contact4Data.h" +#include "Bullet3Dynamics/shared/b3ContactConstraint4.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" + + +void b3PlaneSpace1 (b3Float4ConstArg n, b3Float4* p, b3Float4* q); + void b3PlaneSpace1 (b3Float4ConstArg n, b3Float4* p, b3Float4* q) +{ + if (b3Fabs(n.z) > 0.70710678f) { + // choose p in y-z plane + float a = n.y*n.y + n.z*n.z; + float k = 1.f/sqrt(a); + p[0].x = 0; + p[0].y = -n.z*k; + p[0].z = n.y*k; + // set q = n x p + q[0].x = a*k; + q[0].y = -n.x*p[0].z; + q[0].z = n.x*p[0].y; + } + else { + // choose p in x-y plane + float a = n.x*n.x + n.y*n.y; + float k = 1.f/sqrt(a); + p[0].x = -n.y*k; + p[0].y = n.x*k; + p[0].z = 0; + // set q = n x p + q[0].x = -n.z*p[0].y; + q[0].y = n.z*p[0].x; + q[0].z = a*k; + } +} + + + +void setLinearAndAngular( b3Float4ConstArg n, b3Float4ConstArg r0, b3Float4ConstArg r1, b3Float4* linear, b3Float4* angular0, b3Float4* angular1) +{ + *linear = b3MakeFloat4(n.x,n.y,n.z,0.f); + *angular0 = b3Cross3(r0, n); + *angular1 = -b3Cross3(r1, n); +} + + +float calcRelVel( b3Float4ConstArg l0, b3Float4ConstArg l1, b3Float4ConstArg a0, b3Float4ConstArg a1, b3Float4ConstArg linVel0, + b3Float4ConstArg angVel0, b3Float4ConstArg linVel1, b3Float4ConstArg angVel1 ) +{ + return b3Dot3F4(l0, linVel0) + b3Dot3F4(a0, angVel0) + b3Dot3F4(l1, linVel1) + b3Dot3F4(a1, angVel1); +} + + +float calcJacCoeff(b3Float4ConstArg linear0, b3Float4ConstArg linear1, b3Float4ConstArg angular0, b3Float4ConstArg angular1, + float invMass0, const b3Mat3x3* invInertia0, float invMass1, const b3Mat3x3* invInertia1) +{ + // linear0,1 are normlized + float jmj0 = invMass0;//b3Dot3F4(linear0, linear0)*invMass0; + float jmj1 = b3Dot3F4(mtMul3(angular0,*invInertia0), angular0); + float jmj2 = invMass1;//b3Dot3F4(linear1, linear1)*invMass1; + float jmj3 = b3Dot3F4(mtMul3(angular1,*invInertia1), angular1); + return -1.f/(jmj0+jmj1+jmj2+jmj3); +} + + +void setConstraint4( b3Float4ConstArg posA, b3Float4ConstArg linVelA, b3Float4ConstArg angVelA, float invMassA, b3Mat3x3ConstArg invInertiaA, + b3Float4ConstArg posB, b3Float4ConstArg linVelB, b3Float4ConstArg angVelB, float invMassB, b3Mat3x3ConstArg invInertiaB, + __global struct b3Contact4Data* src, float dt, float positionDrift, float positionConstraintCoeff, + b3ContactConstraint4_t* dstC ) +{ + dstC->m_bodyA = abs(src->m_bodyAPtrAndSignBit); + dstC->m_bodyB = abs(src->m_bodyBPtrAndSignBit); + + float dtInv = 1.f/dt; + for(int ic=0; ic<4; ic++) + { + dstC->m_appliedRambdaDt[ic] = 0.f; + } + dstC->m_fJacCoeffInv[0] = dstC->m_fJacCoeffInv[1] = 0.f; + + + dstC->m_linear = src->m_worldNormalOnB; + dstC->m_linear.w = 0.7f ;//src->getFrictionCoeff() ); + for(int ic=0; ic<4; ic++) + { + b3Float4 r0 = src->m_worldPosB[ic] - posA; + b3Float4 r1 = src->m_worldPosB[ic] - posB; + + if( ic >= src->m_worldNormalOnB.w )//npoints + { + dstC->m_jacCoeffInv[ic] = 0.f; + continue; + } + + float relVelN; + { + b3Float4 linear, angular0, angular1; + setLinearAndAngular(src->m_worldNormalOnB, r0, r1, &linear, &angular0, &angular1); + + dstC->m_jacCoeffInv[ic] = calcJacCoeff(linear, -linear, angular0, angular1, + invMassA, &invInertiaA, invMassB, &invInertiaB ); + + relVelN = calcRelVel(linear, -linear, angular0, angular1, + linVelA, angVelA, linVelB, angVelB); + + float e = 0.f;//src->getRestituitionCoeff(); + if( relVelN*relVelN < 0.004f ) e = 0.f; + + dstC->m_b[ic] = e*relVelN; + //float penetration = src->m_worldPosB[ic].w; + dstC->m_b[ic] += (src->m_worldPosB[ic].w + positionDrift)*positionConstraintCoeff*dtInv; + dstC->m_appliedRambdaDt[ic] = 0.f; + } + } + + if( src->m_worldNormalOnB.w > 0 )//npoints + { // prepare friction + b3Float4 center = b3MakeFloat4(0.f,0.f,0.f,0.f); + for(int i=0; im_worldNormalOnB.w; i++) + center += src->m_worldPosB[i]; + center /= (float)src->m_worldNormalOnB.w; + + b3Float4 tangent[2]; + b3PlaneSpace1(src->m_worldNormalOnB,&tangent[0],&tangent[1]); + + b3Float4 r[2]; + r[0] = center - posA; + r[1] = center - posB; + + for(int i=0; i<2; i++) + { + b3Float4 linear, angular0, angular1; + setLinearAndAngular(tangent[i], r[0], r[1], &linear, &angular0, &angular1); + + dstC->m_fJacCoeffInv[i] = calcJacCoeff(linear, -linear, angular0, angular1, + invMassA, &invInertiaA, invMassB, &invInertiaB ); + dstC->m_fAppliedRambdaDt[i] = 0.f; + } + dstC->m_center = center; + } + + for(int i=0; i<4; i++) + { + if( im_worldNormalOnB.w ) + { + dstC->m_worldPos[i] = src->m_worldPosB[i]; + } + else + { + dstC->m_worldPos[i] = b3MakeFloat4(0.f,0.f,0.f,0.f); + } + } +} diff --git a/extern/bullet/src/Bullet3Dynamics/shared/b3Inertia.h b/extern/bullet/src/Bullet3Dynamics/shared/b3Inertia.h new file mode 100644 index 000000000000..96fe9f8b3983 --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/shared/b3Inertia.h @@ -0,0 +1,15 @@ + + +#ifndef B3_INERTIA_H +#define B3_INERTIA_H + +#include "Bullet3Common/shared/b3Mat3x3.h" + +struct b3Inertia +{ + b3Mat3x3 m_invInertiaWorld; + b3Mat3x3 m_initInvInertia; +}; + + +#endif //B3_INERTIA_H \ No newline at end of file diff --git a/extern/bullet/src/Bullet3Dynamics/shared/b3IntegrateTransforms.h b/extern/bullet/src/Bullet3Dynamics/shared/b3IntegrateTransforms.h new file mode 100644 index 000000000000..e96f90d3f32d --- /dev/null +++ b/extern/bullet/src/Bullet3Dynamics/shared/b3IntegrateTransforms.h @@ -0,0 +1,113 @@ + + +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" + + + +inline void integrateSingleTransform( __global b3RigidBodyData_t* bodies,int nodeID, float timeStep, float angularDamping, b3Float4ConstArg gravityAcceleration) +{ + + if (bodies[nodeID].m_invMass != 0.f) + { + float BT_GPU_ANGULAR_MOTION_THRESHOLD = (0.25f * 3.14159254f); + + //angular velocity + { + b3Float4 axis; + //add some hardcoded angular damping + bodies[nodeID].m_angVel.x *= angularDamping; + bodies[nodeID].m_angVel.y *= angularDamping; + bodies[nodeID].m_angVel.z *= angularDamping; + + b3Float4 angvel = bodies[nodeID].m_angVel; + + float fAngle = b3Sqrt(b3Dot3F4(angvel, angvel)); + + //limit the angular motion + if(fAngle*timeStep > BT_GPU_ANGULAR_MOTION_THRESHOLD) + { + fAngle = BT_GPU_ANGULAR_MOTION_THRESHOLD / timeStep; + } + if(fAngle < 0.001f) + { + // use Taylor's expansions of sync function + axis = angvel * (0.5f*timeStep-(timeStep*timeStep*timeStep)*0.020833333333f * fAngle * fAngle); + } + else + { + // sync(fAngle) = sin(c*fAngle)/t + axis = angvel * ( b3Sin(0.5f * fAngle * timeStep) / fAngle); + } + + b3Quat dorn; + dorn.x = axis.x; + dorn.y = axis.y; + dorn.z = axis.z; + dorn.w = b3Cos(fAngle * timeStep * 0.5f); + b3Quat orn0 = bodies[nodeID].m_quat; + b3Quat predictedOrn = b3QuatMul(dorn, orn0); + predictedOrn = b3QuatNormalized(predictedOrn); + bodies[nodeID].m_quat=predictedOrn; + } + //linear velocity + bodies[nodeID].m_pos += bodies[nodeID].m_linVel * timeStep; + + //apply gravity + bodies[nodeID].m_linVel += gravityAcceleration * timeStep; + + } + +} + +inline void b3IntegrateTransform( __global b3RigidBodyData_t* body, float timeStep, float angularDamping, b3Float4ConstArg gravityAcceleration) +{ + float BT_GPU_ANGULAR_MOTION_THRESHOLD = (0.25f * 3.14159254f); + + if( (body->m_invMass != 0.f)) + { + //angular velocity + { + b3Float4 axis; + //add some hardcoded angular damping + body->m_angVel.x *= angularDamping; + body->m_angVel.y *= angularDamping; + body->m_angVel.z *= angularDamping; + + b3Float4 angvel = body->m_angVel; + float fAngle = b3Sqrt(b3Dot3F4(angvel, angvel)); + //limit the angular motion + if(fAngle*timeStep > BT_GPU_ANGULAR_MOTION_THRESHOLD) + { + fAngle = BT_GPU_ANGULAR_MOTION_THRESHOLD / timeStep; + } + if(fAngle < 0.001f) + { + // use Taylor's expansions of sync function + axis = angvel * (0.5f*timeStep-(timeStep*timeStep*timeStep)*0.020833333333f * fAngle * fAngle); + } + else + { + // sync(fAngle) = sin(c*fAngle)/t + axis = angvel * ( b3Sin(0.5f * fAngle * timeStep) / fAngle); + } + b3Quat dorn; + dorn.x = axis.x; + dorn.y = axis.y; + dorn.z = axis.z; + dorn.w = b3Cos(fAngle * timeStep * 0.5f); + b3Quat orn0 = body->m_quat; + + b3Quat predictedOrn = b3QuatMul(dorn, orn0); + predictedOrn = b3QuatNormalized(predictedOrn); + body->m_quat=predictedOrn; + } + + //apply gravity + body->m_linVel += gravityAcceleration * timeStep; + + //linear velocity + body->m_pos += body->m_linVel * timeStep; + + } + +} diff --git a/extern/bullet/src/Bullet3Geometry/CMakeLists.txt b/extern/bullet/src/Bullet3Geometry/CMakeLists.txt new file mode 100644 index 000000000000..82068727054d --- /dev/null +++ b/extern/bullet/src/Bullet3Geometry/CMakeLists.txt @@ -0,0 +1,47 @@ + +INCLUDE_DIRECTORIES( + ${BULLET_PHYSICS_SOURCE_DIR}/src +) + +SET(Bullet3Geometry_SRCS + b3ConvexHullComputer.cpp + b3GeometryUtil.cpp +) + +SET(Bullet3Geometry_HDRS + b3AabbUtil.h + b3ConvexHullComputer.h + b3GeometryUtil.h + b3GrahamScan2dConvexHull.h +) + +ADD_LIBRARY(Bullet3Geometry ${Bullet3Geometry_SRCS} ${Bullet3Geometry_HDRS}) +if (BUILD_SHARED_LIBS) + target_link_libraries(Bullet3Geometry Bullet3Common) +endif() +SET_TARGET_PROPERTIES(Bullet3Geometry PROPERTIES VERSION ${BULLET_VERSION}) +SET_TARGET_PROPERTIES(Bullet3Geometry PROPERTIES SOVERSION ${BULLET_VERSION}) + +IF (INSTALL_LIBS) + IF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) + #FILES_MATCHING requires CMake 2.6 + IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS Bullet3Geometry DESTINATION .) + ELSE (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS Bullet3Geometry + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib${LIB_SUFFIX} + ARCHIVE DESTINATION lib${LIB_SUFFIX}) + INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.h" PATTERN +".svn" EXCLUDE PATTERN "CMakeFiles" EXCLUDE) + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + SET_TARGET_PROPERTIES(Bullet3Geometry PROPERTIES FRAMEWORK true) + SET_TARGET_PROPERTIES(Bullet3Geometry PROPERTIES PUBLIC_HEADER "${Bullet3Geometry_HDRS}") + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) +ENDIF (INSTALL_LIBS) diff --git a/extern/bullet/src/Bullet3Geometry/b3AabbUtil.h b/extern/bullet/src/Bullet3Geometry/b3AabbUtil.h new file mode 100644 index 000000000000..4c72d5bbfc04 --- /dev/null +++ b/extern/bullet/src/Bullet3Geometry/b3AabbUtil.h @@ -0,0 +1,232 @@ +/* +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 B3_AABB_UTIL2 +#define B3_AABB_UTIL2 + +#include "Bullet3Common/b3Transform.h" +#include "Bullet3Common/b3Vector3.h" +#include "Bullet3Common/b3MinMax.h" + + + +B3_FORCE_INLINE void b3AabbExpand (b3Vector3& aabbMin, + b3Vector3& aabbMax, + const b3Vector3& expansionMin, + const b3Vector3& expansionMax) +{ + aabbMin = aabbMin + expansionMin; + aabbMax = aabbMax + expansionMax; +} + +/// conservative test for overlap between two aabbs +B3_FORCE_INLINE bool b3TestPointAgainstAabb2(const b3Vector3 &aabbMin1, const b3Vector3 &aabbMax1, + const b3Vector3 &point) +{ + bool overlap = true; + overlap = (aabbMin1.getX() > point.getX() || aabbMax1.getX() < point.getX()) ? false : overlap; + overlap = (aabbMin1.getZ() > point.getZ() || aabbMax1.getZ() < point.getZ()) ? false : overlap; + overlap = (aabbMin1.getY() > point.getY() || aabbMax1.getY() < point.getY()) ? false : overlap; + return overlap; +} + + +/// conservative test for overlap between two aabbs +B3_FORCE_INLINE bool b3TestAabbAgainstAabb2(const b3Vector3 &aabbMin1, const b3Vector3 &aabbMax1, + const b3Vector3 &aabbMin2, const b3Vector3 &aabbMax2) +{ + bool overlap = true; + overlap = (aabbMin1.getX() > aabbMax2.getX() || aabbMax1.getX() < aabbMin2.getX()) ? false : overlap; + overlap = (aabbMin1.getZ() > aabbMax2.getZ() || aabbMax1.getZ() < aabbMin2.getZ()) ? false : overlap; + overlap = (aabbMin1.getY() > aabbMax2.getY() || aabbMax1.getY() < aabbMin2.getY()) ? false : overlap; + return overlap; +} + +/// conservative test for overlap between triangle and aabb +B3_FORCE_INLINE bool b3TestTriangleAgainstAabb2(const b3Vector3 *vertices, + const b3Vector3 &aabbMin, const b3Vector3 &aabbMax) +{ + const b3Vector3 &p1 = vertices[0]; + const b3Vector3 &p2 = vertices[1]; + const b3Vector3 &p3 = vertices[2]; + + if (b3Min(b3Min(p1[0], p2[0]), p3[0]) > aabbMax[0]) return false; + if (b3Max(b3Max(p1[0], p2[0]), p3[0]) < aabbMin[0]) return false; + + if (b3Min(b3Min(p1[2], p2[2]), p3[2]) > aabbMax[2]) return false; + if (b3Max(b3Max(p1[2], p2[2]), p3[2]) < aabbMin[2]) return false; + + if (b3Min(b3Min(p1[1], p2[1]), p3[1]) > aabbMax[1]) return false; + if (b3Max(b3Max(p1[1], p2[1]), p3[1]) < aabbMin[1]) return false; + return true; +} + + +B3_FORCE_INLINE int b3Outcode(const b3Vector3& p,const b3Vector3& 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); +} + + + +B3_FORCE_INLINE bool b3RayAabb2(const b3Vector3& rayFrom, + const b3Vector3& rayInvDirection, + const unsigned int raySign[3], + const b3Vector3 bounds[2], + b3Scalar& tmin, + b3Scalar lambda_min, + b3Scalar lambda_max) +{ + b3Scalar tmax, tymin, tymax, tzmin, tzmax; + tmin = (bounds[raySign[0]].getX() - rayFrom.getX()) * rayInvDirection.getX(); + tmax = (bounds[1-raySign[0]].getX() - rayFrom.getX()) * rayInvDirection.getX(); + tymin = (bounds[raySign[1]].getY() - rayFrom.getY()) * rayInvDirection.getY(); + tymax = (bounds[1-raySign[1]].getY() - rayFrom.getY()) * rayInvDirection.getY(); + + if ( (tmin > tymax) || (tymin > tmax) ) + return false; + + if (tymin > tmin) + tmin = tymin; + + if (tymax < tmax) + tmax = tymax; + + tzmin = (bounds[raySign[2]].getZ() - rayFrom.getZ()) * rayInvDirection.getZ(); + tzmax = (bounds[1-raySign[2]].getZ() - rayFrom.getZ()) * rayInvDirection.getZ(); + + if ( (tmin > tzmax) || (tzmin > tmax) ) + return false; + if (tzmin > tmin) + tmin = tzmin; + if (tzmax < tmax) + tmax = tzmax; + return ( (tmin < lambda_max) && (tmax > lambda_min) ); +} + +B3_FORCE_INLINE bool b3RayAabb(const b3Vector3& rayFrom, + const b3Vector3& rayTo, + const b3Vector3& aabbMin, + const b3Vector3& aabbMax, + b3Scalar& param, b3Vector3& normal) +{ + b3Vector3 aabbHalfExtent = (aabbMax-aabbMin)* b3Scalar(0.5); + b3Vector3 aabbCenter = (aabbMax+aabbMin)* b3Scalar(0.5); + b3Vector3 source = rayFrom - aabbCenter; + b3Vector3 target = rayTo - aabbCenter; + int sourceOutcode = b3Outcode(source,aabbHalfExtent); + int targetOutcode = b3Outcode(target,aabbHalfExtent); + if ((sourceOutcode & targetOutcode) == 0x0) + { + b3Scalar lambda_enter = b3Scalar(0.0); + b3Scalar lambda_exit = param; + b3Vector3 r = target - source; + int i; + b3Scalar normSign = 1; + b3Vector3 hitNormal = b3MakeVector3(0,0,0); + int bit=1; + + for (int j=0;j<2;j++) + { + for (i = 0; i != 3; ++i) + { + if (sourceOutcode & bit) + { + b3Scalar 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) + { + b3Scalar lambda = (-source[i] - aabbHalfExtent[i]*normSign) / r[i]; + b3SetMin(lambda_exit, lambda); + } + bit<<=1; + } + normSign = b3Scalar(-1.); + } + if (lambda_enter <= lambda_exit) + { + param = lambda_enter; + normal = hitNormal; + return true; + } + } + return false; +} + + + +B3_FORCE_INLINE void b3TransformAabb(const b3Vector3& halfExtents, b3Scalar margin,const b3Transform& t,b3Vector3& aabbMinOut,b3Vector3& aabbMaxOut) +{ + b3Vector3 halfExtentsWithMargin = halfExtents+b3MakeVector3(margin,margin,margin); + b3Matrix3x3 abs_b = t.getBasis().absolute(); + b3Vector3 center = t.getOrigin(); + b3Vector3 extent = halfExtentsWithMargin.dot3( abs_b[0], abs_b[1], abs_b[2] ); + aabbMinOut = center - extent; + aabbMaxOut = center + extent; +} + + +B3_FORCE_INLINE void b3TransformAabb(const b3Vector3& localAabbMin,const b3Vector3& localAabbMax, b3Scalar margin,const b3Transform& trans,b3Vector3& aabbMinOut,b3Vector3& aabbMaxOut) +{ + //b3Assert(localAabbMin.getX() <= localAabbMax.getX()); + //b3Assert(localAabbMin.getY() <= localAabbMax.getY()); + //b3Assert(localAabbMin.getZ() <= localAabbMax.getZ()); + b3Vector3 localHalfExtents = b3Scalar(0.5)*(localAabbMax-localAabbMin); + localHalfExtents+=b3MakeVector3(margin,margin,margin); + + b3Vector3 localCenter = b3Scalar(0.5)*(localAabbMax+localAabbMin); + b3Matrix3x3 abs_b = trans.getBasis().absolute(); + b3Vector3 center = trans(localCenter); + b3Vector3 extent = localHalfExtents.dot3( abs_b[0], abs_b[1], abs_b[2] ); + aabbMinOut = center-extent; + aabbMaxOut = center+extent; +} + +#define B3_USE_BANCHLESS 1 +#ifdef B3_USE_BANCHLESS + //This block replaces the block below and uses no branches, and replaces the 8 bit return with a 32 bit return for improved performance (~3x on XBox 360) + B3_FORCE_INLINE unsigned b3TestQuantizedAabbAgainstQuantizedAabb(const unsigned short int* aabbMin1,const unsigned short int* aabbMax1,const unsigned short int* aabbMin2,const unsigned short int* aabbMax2) + { + return static_cast(b3Select((unsigned)((aabbMin1[0] <= aabbMax2[0]) & (aabbMax1[0] >= aabbMin2[0]) + & (aabbMin1[2] <= aabbMax2[2]) & (aabbMax1[2] >= aabbMin2[2]) + & (aabbMin1[1] <= aabbMax2[1]) & (aabbMax1[1] >= aabbMin2[1])), + 1, 0)); + } +#else + B3_FORCE_INLINE bool b3TestQuantizedAabbAgainstQuantizedAabb(const unsigned short int* aabbMin1,const unsigned short int* aabbMax1,const unsigned short int* aabbMin2,const unsigned short int* 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; + } +#endif //B3_USE_BANCHLESS + +#endif //B3_AABB_UTIL2 + + diff --git a/extern/bullet/src/Bullet3Geometry/b3ConvexHullComputer.cpp b/extern/bullet/src/Bullet3Geometry/b3ConvexHullComputer.cpp new file mode 100644 index 000000000000..18835c38d5a9 --- /dev/null +++ b/extern/bullet/src/Bullet3Geometry/b3ConvexHullComputer.cpp @@ -0,0 +1,2755 @@ +/* +Copyright (c) 2011 Ole Kniemeyer, MAXON, www.maxon.net + +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 + +#include "b3ConvexHullComputer.h" +#include "Bullet3Common/b3AlignedObjectArray.h" +#include "Bullet3Common/b3MinMax.h" +#include "Bullet3Common/b3Vector3.h" + +#ifdef __GNUC__ + #include + typedef int32_t btInt32_t; + typedef int64_t btInt64_t; + typedef uint32_t btUint32_t; + typedef uint64_t btUint64_t; +#elif defined(_MSC_VER) + typedef __int32 btInt32_t; + typedef __int64 btInt64_t; + typedef unsigned __int32 btUint32_t; + typedef unsigned __int64 btUint64_t; +#else + typedef int btInt32_t; + typedef long long int btInt64_t; + typedef unsigned int btUint32_t; + typedef unsigned long long int btUint64_t; +#endif + + +//The definition of USE_X86_64_ASM is moved into the build system. You can enable it manually by commenting out the following lines +//#if (defined(__GNUC__) && defined(__x86_64__) && !defined(__ICL)) // || (defined(__ICL) && defined(_M_X64)) bug in Intel compiler, disable inline assembly +// #define USE_X86_64_ASM +//#endif + + +//#define DEBUG_CONVEX_HULL +//#define SHOW_ITERATIONS + +#if defined(DEBUG_CONVEX_HULL) || defined(SHOW_ITERATIONS) + #include +#endif + +// Convex hull implementation based on Preparata and Hong +// Ole Kniemeyer, MAXON Computer GmbH +class b3ConvexHullInternal +{ + public: + + class Point64 + { + public: + btInt64_t x; + btInt64_t y; + btInt64_t z; + + Point64(btInt64_t x, btInt64_t y, btInt64_t z): x(x), y(y), z(z) + { + } + + bool isZero() + { + return (x == 0) && (y == 0) && (z == 0); + } + + btInt64_t dot(const Point64& b) const + { + return x * b.x + y * b.y + z * b.z; + } + }; + + class Point32 + { + public: + btInt32_t x; + btInt32_t y; + btInt32_t z; + int index; + + Point32() + { + } + + Point32(btInt32_t x, btInt32_t y, btInt32_t z): x(x), y(y), z(z), index(-1) + { + } + + bool operator==(const Point32& b) const + { + return (x == b.x) && (y == b.y) && (z == b.z); + } + + bool operator!=(const Point32& b) const + { + return (x != b.x) || (y != b.y) || (z != b.z); + } + + bool isZero() + { + return (x == 0) && (y == 0) && (z == 0); + } + + Point64 cross(const Point32& b) const + { + return Point64(y * b.z - z * b.y, z * b.x - x * b.z, x * b.y - y * b.x); + } + + Point64 cross(const Point64& b) const + { + return Point64(y * b.z - z * b.y, z * b.x - x * b.z, x * b.y - y * b.x); + } + + btInt64_t dot(const Point32& b) const + { + return x * b.x + y * b.y + z * b.z; + } + + btInt64_t dot(const Point64& b) const + { + return x * b.x + y * b.y + z * b.z; + } + + Point32 operator+(const Point32& b) const + { + return Point32(x + b.x, y + b.y, z + b.z); + } + + Point32 operator-(const Point32& b) const + { + return Point32(x - b.x, y - b.y, z - b.z); + } + }; + + class Int128 + { + public: + btUint64_t low; + btUint64_t high; + + Int128() + { + } + + Int128(btUint64_t low, btUint64_t high): low(low), high(high) + { + } + + Int128(btUint64_t low): low(low), high(0) + { + } + + Int128(btInt64_t value): low(value), high((value >= 0) ? 0 : (btUint64_t) -1LL) + { + } + + static Int128 mul(btInt64_t a, btInt64_t b); + + static Int128 mul(btUint64_t a, btUint64_t b); + + Int128 operator-() const + { + return Int128((btUint64_t) -(btInt64_t)low, ~high + (low == 0)); + } + + Int128 operator+(const Int128& b) const + { +#ifdef USE_X86_64_ASM + Int128 result; + __asm__ ("addq %[bl], %[rl]\n\t" + "adcq %[bh], %[rh]\n\t" + : [rl] "=r" (result.low), [rh] "=r" (result.high) + : "0"(low), "1"(high), [bl] "g"(b.low), [bh] "g"(b.high) + : "cc" ); + return result; +#else + btUint64_t lo = low + b.low; + return Int128(lo, high + b.high + (lo < low)); +#endif + } + + Int128 operator-(const Int128& b) const + { +#ifdef USE_X86_64_ASM + Int128 result; + __asm__ ("subq %[bl], %[rl]\n\t" + "sbbq %[bh], %[rh]\n\t" + : [rl] "=r" (result.low), [rh] "=r" (result.high) + : "0"(low), "1"(high), [bl] "g"(b.low), [bh] "g"(b.high) + : "cc" ); + return result; +#else + return *this + -b; +#endif + } + + Int128& operator+=(const Int128& b) + { +#ifdef USE_X86_64_ASM + __asm__ ("addq %[bl], %[rl]\n\t" + "adcq %[bh], %[rh]\n\t" + : [rl] "=r" (low), [rh] "=r" (high) + : "0"(low), "1"(high), [bl] "g"(b.low), [bh] "g"(b.high) + : "cc" ); +#else + btUint64_t lo = low + b.low; + if (lo < low) + { + ++high; + } + low = lo; + high += b.high; +#endif + return *this; + } + + Int128& operator++() + { + if (++low == 0) + { + ++high; + } + return *this; + } + + Int128 operator*(btInt64_t b) const; + + b3Scalar toScalar() const + { + return ((btInt64_t) high >= 0) ? b3Scalar(high) * (b3Scalar(0x100000000LL) * b3Scalar(0x100000000LL)) + b3Scalar(low) + : -(-*this).toScalar(); + } + + int getSign() const + { + return ((btInt64_t) high < 0) ? -1 : (high || low) ? 1 : 0; + } + + bool operator<(const Int128& b) const + { + return (high < b.high) || ((high == b.high) && (low < b.low)); + } + + int ucmp(const Int128&b) const + { + if (high < b.high) + { + return -1; + } + if (high > b.high) + { + return 1; + } + if (low < b.low) + { + return -1; + } + if (low > b.low) + { + return 1; + } + return 0; + } + }; + + + class Rational64 + { + private: + btUint64_t m_numerator; + btUint64_t m_denominator; + int sign; + + public: + Rational64(btInt64_t numerator, btInt64_t denominator) + { + if (numerator > 0) + { + sign = 1; + m_numerator = (btUint64_t) numerator; + } + else if (numerator < 0) + { + sign = -1; + m_numerator = (btUint64_t) -numerator; + } + else + { + sign = 0; + m_numerator = 0; + } + if (denominator > 0) + { + m_denominator = (btUint64_t) denominator; + } + else if (denominator < 0) + { + sign = -sign; + m_denominator = (btUint64_t) -denominator; + } + else + { + m_denominator = 0; + } + } + + bool isNegativeInfinity() const + { + return (sign < 0) && (m_denominator == 0); + } + + bool isNaN() const + { + return (sign == 0) && (m_denominator == 0); + } + + int compare(const Rational64& b) const; + + b3Scalar toScalar() const + { + return sign * ((m_denominator == 0) ? B3_INFINITY : (b3Scalar) m_numerator / m_denominator); + } + }; + + + class Rational128 + { + private: + Int128 numerator; + Int128 denominator; + int sign; + bool isInt64; + + public: + Rational128(btInt64_t value) + { + if (value > 0) + { + sign = 1; + this->numerator = value; + } + else if (value < 0) + { + sign = -1; + this->numerator = -value; + } + else + { + sign = 0; + this->numerator = (btUint64_t) 0; + } + this->denominator = (btUint64_t) 1; + isInt64 = true; + } + + Rational128(const Int128& numerator, const Int128& denominator) + { + sign = numerator.getSign(); + if (sign >= 0) + { + this->numerator = numerator; + } + else + { + this->numerator = -numerator; + } + int dsign = denominator.getSign(); + if (dsign >= 0) + { + this->denominator = denominator; + } + else + { + sign = -sign; + this->denominator = -denominator; + } + isInt64 = false; + } + + int compare(const Rational128& b) const; + + int compare(btInt64_t b) const; + + b3Scalar toScalar() const + { + return sign * ((denominator.getSign() == 0) ? B3_INFINITY : numerator.toScalar() / denominator.toScalar()); + } + }; + + class PointR128 + { + public: + Int128 x; + Int128 y; + Int128 z; + Int128 denominator; + + PointR128() + { + } + + PointR128(Int128 x, Int128 y, Int128 z, Int128 denominator): x(x), y(y), z(z), denominator(denominator) + { + } + + b3Scalar xvalue() const + { + return x.toScalar() / denominator.toScalar(); + } + + b3Scalar yvalue() const + { + return y.toScalar() / denominator.toScalar(); + } + + b3Scalar zvalue() const + { + return z.toScalar() / denominator.toScalar(); + } + }; + + + class Edge; + class Face; + + class Vertex + { + public: + Vertex* next; + Vertex* prev; + Edge* edges; + Face* firstNearbyFace; + Face* lastNearbyFace; + PointR128 point128; + Point32 point; + int copy; + + Vertex(): next(NULL), prev(NULL), edges(NULL), firstNearbyFace(NULL), lastNearbyFace(NULL), copy(-1) + { + } + +#ifdef DEBUG_CONVEX_HULL + void print() + { + b3Printf("V%d (%d, %d, %d)", point.index, point.x, point.y, point.z); + } + + void printGraph(); +#endif + + Point32 operator-(const Vertex& b) const + { + return point - b.point; + } + + Rational128 dot(const Point64& b) const + { + return (point.index >= 0) ? Rational128(point.dot(b)) + : Rational128(point128.x * b.x + point128.y * b.y + point128.z * b.z, point128.denominator); + } + + b3Scalar xvalue() const + { + return (point.index >= 0) ? b3Scalar(point.x) : point128.xvalue(); + } + + b3Scalar yvalue() const + { + return (point.index >= 0) ? b3Scalar(point.y) : point128.yvalue(); + } + + b3Scalar zvalue() const + { + return (point.index >= 0) ? b3Scalar(point.z) : point128.zvalue(); + } + + void receiveNearbyFaces(Vertex* src) + { + if (lastNearbyFace) + { + lastNearbyFace->nextWithSameNearbyVertex = src->firstNearbyFace; + } + else + { + firstNearbyFace = src->firstNearbyFace; + } + if (src->lastNearbyFace) + { + lastNearbyFace = src->lastNearbyFace; + } + for (Face* f = src->firstNearbyFace; f; f = f->nextWithSameNearbyVertex) + { + b3Assert(f->nearbyVertex == src); + f->nearbyVertex = this; + } + src->firstNearbyFace = NULL; + src->lastNearbyFace = NULL; + } + }; + + + class Edge + { + public: + Edge* next; + Edge* prev; + Edge* reverse; + Vertex* target; + Face* face; + int copy; + + ~Edge() + { + next = NULL; + prev = NULL; + reverse = NULL; + target = NULL; + face = NULL; + } + + void link(Edge* n) + { + b3Assert(reverse->target == n->reverse->target); + next = n; + n->prev = this; + } + +#ifdef DEBUG_CONVEX_HULL + void print() + { + b3Printf("E%p : %d -> %d, n=%p p=%p (0 %d\t%d\t%d) -> (%d %d %d)", this, reverse->target->point.index, target->point.index, next, prev, + reverse->target->point.x, reverse->target->point.y, reverse->target->point.z, target->point.x, target->point.y, target->point.z); + } +#endif + }; + + class Face + { + public: + Face* next; + Vertex* nearbyVertex; + Face* nextWithSameNearbyVertex; + Point32 origin; + Point32 dir0; + Point32 dir1; + + Face(): next(NULL), nearbyVertex(NULL), nextWithSameNearbyVertex(NULL) + { + } + + void init(Vertex* a, Vertex* b, Vertex* c) + { + nearbyVertex = a; + origin = a->point; + dir0 = *b - *a; + dir1 = *c - *a; + if (a->lastNearbyFace) + { + a->lastNearbyFace->nextWithSameNearbyVertex = this; + } + else + { + a->firstNearbyFace = this; + } + a->lastNearbyFace = this; + } + + Point64 getNormal() + { + return dir0.cross(dir1); + } + }; + + template class DMul + { + private: + static btUint32_t high(btUint64_t value) + { + return (btUint32_t) (value >> 32); + } + + static btUint32_t low(btUint64_t value) + { + return (btUint32_t) value; + } + + static btUint64_t mul(btUint32_t a, btUint32_t b) + { + return (btUint64_t) a * (btUint64_t) b; + } + + static void shlHalf(btUint64_t& value) + { + value <<= 32; + } + + static btUint64_t high(Int128 value) + { + return value.high; + } + + static btUint64_t low(Int128 value) + { + return value.low; + } + + static Int128 mul(btUint64_t a, btUint64_t b) + { + return Int128::mul(a, b); + } + + static void shlHalf(Int128& value) + { + value.high = value.low; + value.low = 0; + } + + public: + + static void mul(UWord a, UWord b, UWord& resLow, UWord& resHigh) + { + UWord p00 = mul(low(a), low(b)); + UWord p01 = mul(low(a), high(b)); + UWord p10 = mul(high(a), low(b)); + UWord p11 = mul(high(a), high(b)); + UWord p0110 = UWord(low(p01)) + UWord(low(p10)); + p11 += high(p01); + p11 += high(p10); + p11 += high(p0110); + shlHalf(p0110); + p00 += p0110; + if (p00 < p0110) + { + ++p11; + } + resLow = p00; + resHigh = p11; + } + }; + + private: + + class IntermediateHull + { + public: + Vertex* minXy; + Vertex* maxXy; + Vertex* minYx; + Vertex* maxYx; + + IntermediateHull(): minXy(NULL), maxXy(NULL), minYx(NULL), maxYx(NULL) + { + } + + void print(); + }; + + enum Orientation {NONE, CLOCKWISE, COUNTER_CLOCKWISE}; + + template class PoolArray + { + private: + T* array; + int size; + + public: + PoolArray* next; + + PoolArray(int size): size(size), next(NULL) + { + array = (T*) b3AlignedAlloc(sizeof(T) * size, 16); + } + + ~PoolArray() + { + b3AlignedFree(array); + } + + T* init() + { + T* o = array; + for (int i = 0; i < size; i++, o++) + { + o->next = (i+1 < size) ? o + 1 : NULL; + } + return array; + } + }; + + template class Pool + { + private: + PoolArray* arrays; + PoolArray* nextArray; + T* freeObjects; + int arraySize; + + public: + Pool(): arrays(NULL), nextArray(NULL), freeObjects(NULL), arraySize(256) + { + } + + ~Pool() + { + while (arrays) + { + PoolArray* p = arrays; + arrays = p->next; + p->~PoolArray(); + b3AlignedFree(p); + } + } + + void reset() + { + nextArray = arrays; + freeObjects = NULL; + } + + void setArraySize(int arraySize) + { + this->arraySize = arraySize; + } + + T* newObject() + { + T* o = freeObjects; + if (!o) + { + PoolArray* p = nextArray; + if (p) + { + nextArray = p->next; + } + else + { + p = new(b3AlignedAlloc(sizeof(PoolArray), 16)) PoolArray(arraySize); + p->next = arrays; + arrays = p; + } + o = p->init(); + } + freeObjects = o->next; + return new(o) T(); + }; + + void freeObject(T* object) + { + object->~T(); + object->next = freeObjects; + freeObjects = object; + } + }; + + b3Vector3 scaling; + b3Vector3 center; + Pool vertexPool; + Pool edgePool; + Pool facePool; + b3AlignedObjectArray originalVertices; + int mergeStamp; + int minAxis; + int medAxis; + int maxAxis; + int usedEdgePairs; + int maxUsedEdgePairs; + + static Orientation getOrientation(const Edge* prev, const Edge* next, const Point32& s, const Point32& t); + Edge* findMaxAngle(bool ccw, const Vertex* start, const Point32& s, const Point64& rxs, const Point64& sxrxs, Rational64& minCot); + void findEdgeForCoplanarFaces(Vertex* c0, Vertex* c1, Edge*& e0, Edge*& e1, Vertex* stop0, Vertex* stop1); + + Edge* newEdgePair(Vertex* from, Vertex* to); + + void removeEdgePair(Edge* edge) + { + Edge* n = edge->next; + Edge* r = edge->reverse; + + b3Assert(edge->target && r->target); + + if (n != edge) + { + n->prev = edge->prev; + edge->prev->next = n; + r->target->edges = n; + } + else + { + r->target->edges = NULL; + } + + n = r->next; + + if (n != r) + { + n->prev = r->prev; + r->prev->next = n; + edge->target->edges = n; + } + else + { + edge->target->edges = NULL; + } + + edgePool.freeObject(edge); + edgePool.freeObject(r); + usedEdgePairs--; + } + + void computeInternal(int start, int end, IntermediateHull& result); + + bool mergeProjection(IntermediateHull& h0, IntermediateHull& h1, Vertex*& c0, Vertex*& c1); + + void merge(IntermediateHull& h0, IntermediateHull& h1); + + b3Vector3 toBtVector(const Point32& v); + + b3Vector3 getBtNormal(Face* face); + + bool shiftFace(Face* face, b3Scalar amount, b3AlignedObjectArray stack); + + public: + Vertex* vertexList; + + void compute(const void* coords, bool doubleCoords, int stride, int count); + + b3Vector3 getCoordinates(const Vertex* v); + + b3Scalar shrink(b3Scalar amount, b3Scalar clampAmount); +}; + + +b3ConvexHullInternal::Int128 b3ConvexHullInternal::Int128::operator*(btInt64_t b) const +{ + bool negative = (btInt64_t) high < 0; + Int128 a = negative ? -*this : *this; + if (b < 0) + { + negative = !negative; + b = -b; + } + Int128 result = mul(a.low, (btUint64_t) b); + result.high += a.high * (btUint64_t) b; + return negative ? -result : result; +} + +b3ConvexHullInternal::Int128 b3ConvexHullInternal::Int128::mul(btInt64_t a, btInt64_t b) +{ + Int128 result; + +#ifdef USE_X86_64_ASM + __asm__ ("imulq %[b]" + : "=a" (result.low), "=d" (result.high) + : "0"(a), [b] "r"(b) + : "cc" ); + return result; + +#else + bool negative = a < 0; + if (negative) + { + a = -a; + } + if (b < 0) + { + negative = !negative; + b = -b; + } + DMul::mul((btUint64_t) a, (btUint64_t) b, result.low, result.high); + return negative ? -result : result; +#endif +} + +b3ConvexHullInternal::Int128 b3ConvexHullInternal::Int128::mul(btUint64_t a, btUint64_t b) +{ + Int128 result; + +#ifdef USE_X86_64_ASM + __asm__ ("mulq %[b]" + : "=a" (result.low), "=d" (result.high) + : "0"(a), [b] "r"(b) + : "cc" ); + +#else + DMul::mul(a, b, result.low, result.high); +#endif + + return result; +} + +int b3ConvexHullInternal::Rational64::compare(const Rational64& b) const +{ + if (sign != b.sign) + { + return sign - b.sign; + } + else if (sign == 0) + { + return 0; + } + + // return (numerator * b.denominator > b.numerator * denominator) ? sign : (numerator * b.denominator < b.numerator * denominator) ? -sign : 0; + +#ifdef USE_X86_64_ASM + + int result; + btInt64_t tmp; + btInt64_t dummy; + __asm__ ("mulq %[bn]\n\t" + "movq %%rax, %[tmp]\n\t" + "movq %%rdx, %%rbx\n\t" + "movq %[tn], %%rax\n\t" + "mulq %[bd]\n\t" + "subq %[tmp], %%rax\n\t" + "sbbq %%rbx, %%rdx\n\t" // rdx:rax contains 128-bit-difference "numerator*b.denominator - b.numerator*denominator" + "setnsb %%bh\n\t" // bh=1 if difference is non-negative, bh=0 otherwise + "orq %%rdx, %%rax\n\t" + "setnzb %%bl\n\t" // bl=1 if difference if non-zero, bl=0 if it is zero + "decb %%bh\n\t" // now bx=0x0000 if difference is zero, 0xff01 if it is negative, 0x0001 if it is positive (i.e., same sign as difference) + "shll $16, %%ebx\n\t" // ebx has same sign as difference + : "=&b"(result), [tmp] "=&r"(tmp), "=a"(dummy) + : "a"(denominator), [bn] "g"(b.numerator), [tn] "g"(numerator), [bd] "g"(b.denominator) + : "%rdx", "cc" ); + return result ? result ^ sign // if sign is +1, only bit 0 of result is inverted, which does not change the sign of result (and cannot result in zero) + // if sign is -1, all bits of result are inverted, which changes the sign of result (and again cannot result in zero) + : 0; + +#else + + return sign * Int128::mul(m_numerator, b.m_denominator).ucmp(Int128::mul(m_denominator, b.m_numerator)); + +#endif +} + +int b3ConvexHullInternal::Rational128::compare(const Rational128& b) const +{ + if (sign != b.sign) + { + return sign - b.sign; + } + else if (sign == 0) + { + return 0; + } + if (isInt64) + { + return -b.compare(sign * (btInt64_t) numerator.low); + } + + Int128 nbdLow, nbdHigh, dbnLow, dbnHigh; + DMul::mul(numerator, b.denominator, nbdLow, nbdHigh); + DMul::mul(denominator, b.numerator, dbnLow, dbnHigh); + + int cmp = nbdHigh.ucmp(dbnHigh); + if (cmp) + { + return cmp * sign; + } + return nbdLow.ucmp(dbnLow) * sign; +} + +int b3ConvexHullInternal::Rational128::compare(btInt64_t b) const +{ + if (isInt64) + { + btInt64_t a = sign * (btInt64_t) numerator.low; + return (a > b) ? 1 : (a < b) ? -1 : 0; + } + if (b > 0) + { + if (sign <= 0) + { + return -1; + } + } + else if (b < 0) + { + if (sign >= 0) + { + return 1; + } + b = -b; + } + else + { + return sign; + } + + return numerator.ucmp(denominator * b) * sign; +} + + +b3ConvexHullInternal::Edge* b3ConvexHullInternal::newEdgePair(Vertex* from, Vertex* to) +{ + b3Assert(from && to); + Edge* e = edgePool.newObject(); + Edge* r = edgePool.newObject(); + e->reverse = r; + r->reverse = e; + e->copy = mergeStamp; + r->copy = mergeStamp; + e->target = to; + r->target = from; + e->face = NULL; + r->face = NULL; + usedEdgePairs++; + if (usedEdgePairs > maxUsedEdgePairs) + { + maxUsedEdgePairs = usedEdgePairs; + } + return e; +} + +bool b3ConvexHullInternal::mergeProjection(IntermediateHull& h0, IntermediateHull& h1, Vertex*& c0, Vertex*& c1) +{ + Vertex* v0 = h0.maxYx; + Vertex* v1 = h1.minYx; + if ((v0->point.x == v1->point.x) && (v0->point.y == v1->point.y)) + { + b3Assert(v0->point.z < v1->point.z); + Vertex* v1p = v1->prev; + if (v1p == v1) + { + c0 = v0; + if (v1->edges) + { + b3Assert(v1->edges->next == v1->edges); + v1 = v1->edges->target; + b3Assert(v1->edges->next == v1->edges); + } + c1 = v1; + return false; + } + Vertex* v1n = v1->next; + v1p->next = v1n; + v1n->prev = v1p; + if (v1 == h1.minXy) + { + if ((v1n->point.x < v1p->point.x) || ((v1n->point.x == v1p->point.x) && (v1n->point.y < v1p->point.y))) + { + h1.minXy = v1n; + } + else + { + h1.minXy = v1p; + } + } + if (v1 == h1.maxXy) + { + if ((v1n->point.x > v1p->point.x) || ((v1n->point.x == v1p->point.x) && (v1n->point.y > v1p->point.y))) + { + h1.maxXy = v1n; + } + else + { + h1.maxXy = v1p; + } + } + } + + v0 = h0.maxXy; + v1 = h1.maxXy; + Vertex* v00 = NULL; + Vertex* v10 = NULL; + btInt32_t sign = 1; + + for (int side = 0; side <= 1; side++) + { + btInt32_t dx = (v1->point.x - v0->point.x) * sign; + if (dx > 0) + { + while (true) + { + btInt32_t dy = v1->point.y - v0->point.y; + + Vertex* w0 = side ? v0->next : v0->prev; + if (w0 != v0) + { + btInt32_t dx0 = (w0->point.x - v0->point.x) * sign; + btInt32_t dy0 = w0->point.y - v0->point.y; + if ((dy0 <= 0) && ((dx0 == 0) || ((dx0 < 0) && (dy0 * dx <= dy * dx0)))) + { + v0 = w0; + dx = (v1->point.x - v0->point.x) * sign; + continue; + } + } + + Vertex* w1 = side ? v1->next : v1->prev; + if (w1 != v1) + { + btInt32_t dx1 = (w1->point.x - v1->point.x) * sign; + btInt32_t dy1 = w1->point.y - v1->point.y; + btInt32_t dxn = (w1->point.x - v0->point.x) * sign; + if ((dxn > 0) && (dy1 < 0) && ((dx1 == 0) || ((dx1 < 0) && (dy1 * dx < dy * dx1)))) + { + v1 = w1; + dx = dxn; + continue; + } + } + + break; + } + } + else if (dx < 0) + { + while (true) + { + btInt32_t dy = v1->point.y - v0->point.y; + + Vertex* w1 = side ? v1->prev : v1->next; + if (w1 != v1) + { + btInt32_t dx1 = (w1->point.x - v1->point.x) * sign; + btInt32_t dy1 = w1->point.y - v1->point.y; + if ((dy1 >= 0) && ((dx1 == 0) || ((dx1 < 0) && (dy1 * dx <= dy * dx1)))) + { + v1 = w1; + dx = (v1->point.x - v0->point.x) * sign; + continue; + } + } + + Vertex* w0 = side ? v0->prev : v0->next; + if (w0 != v0) + { + btInt32_t dx0 = (w0->point.x - v0->point.x) * sign; + btInt32_t dy0 = w0->point.y - v0->point.y; + btInt32_t dxn = (v1->point.x - w0->point.x) * sign; + if ((dxn < 0) && (dy0 > 0) && ((dx0 == 0) || ((dx0 < 0) && (dy0 * dx < dy * dx0)))) + { + v0 = w0; + dx = dxn; + continue; + } + } + + break; + } + } + else + { + btInt32_t x = v0->point.x; + btInt32_t y0 = v0->point.y; + Vertex* w0 = v0; + Vertex* t; + while (((t = side ? w0->next : w0->prev) != v0) && (t->point.x == x) && (t->point.y <= y0)) + { + w0 = t; + y0 = t->point.y; + } + v0 = w0; + + btInt32_t y1 = v1->point.y; + Vertex* w1 = v1; + while (((t = side ? w1->prev : w1->next) != v1) && (t->point.x == x) && (t->point.y >= y1)) + { + w1 = t; + y1 = t->point.y; + } + v1 = w1; + } + + if (side == 0) + { + v00 = v0; + v10 = v1; + + v0 = h0.minXy; + v1 = h1.minXy; + sign = -1; + } + } + + v0->prev = v1; + v1->next = v0; + + v00->next = v10; + v10->prev = v00; + + if (h1.minXy->point.x < h0.minXy->point.x) + { + h0.minXy = h1.minXy; + } + if (h1.maxXy->point.x >= h0.maxXy->point.x) + { + h0.maxXy = h1.maxXy; + } + + h0.maxYx = h1.maxYx; + + c0 = v00; + c1 = v10; + + return true; +} + +void b3ConvexHullInternal::computeInternal(int start, int end, IntermediateHull& result) +{ + int n = end - start; + switch (n) + { + case 0: + result.minXy = NULL; + result.maxXy = NULL; + result.minYx = NULL; + result.maxYx = NULL; + return; + case 2: + { + Vertex* v = originalVertices[start]; + Vertex* w = v + 1; + if (v->point != w->point) + { + btInt32_t dx = v->point.x - w->point.x; + btInt32_t dy = v->point.y - w->point.y; + + if ((dx == 0) && (dy == 0)) + { + if (v->point.z > w->point.z) + { + Vertex* t = w; + w = v; + v = t; + } + b3Assert(v->point.z < w->point.z); + v->next = v; + v->prev = v; + result.minXy = v; + result.maxXy = v; + result.minYx = v; + result.maxYx = v; + } + else + { + v->next = w; + v->prev = w; + w->next = v; + w->prev = v; + + if ((dx < 0) || ((dx == 0) && (dy < 0))) + { + result.minXy = v; + result.maxXy = w; + } + else + { + result.minXy = w; + result.maxXy = v; + } + + if ((dy < 0) || ((dy == 0) && (dx < 0))) + { + result.minYx = v; + result.maxYx = w; + } + else + { + result.minYx = w; + result.maxYx = v; + } + } + + Edge* e = newEdgePair(v, w); + e->link(e); + v->edges = e; + + e = e->reverse; + e->link(e); + w->edges = e; + + return; + } + } + // lint -fallthrough + case 1: + { + Vertex* v = originalVertices[start]; + v->edges = NULL; + v->next = v; + v->prev = v; + + result.minXy = v; + result.maxXy = v; + result.minYx = v; + result.maxYx = v; + + return; + } + } + + int split0 = start + n / 2; + Point32 p = originalVertices[split0-1]->point; + int split1 = split0; + while ((split1 < end) && (originalVertices[split1]->point == p)) + { + split1++; + } + computeInternal(start, split0, result); + IntermediateHull hull1; + computeInternal(split1, end, hull1); +#ifdef DEBUG_CONVEX_HULL + b3Printf("\n\nMerge\n"); + result.print(); + hull1.print(); +#endif + merge(result, hull1); +#ifdef DEBUG_CONVEX_HULL + b3Printf("\n Result\n"); + result.print(); +#endif +} + +#ifdef DEBUG_CONVEX_HULL +void b3ConvexHullInternal::IntermediateHull::print() +{ + b3Printf(" Hull\n"); + for (Vertex* v = minXy; v; ) + { + b3Printf(" "); + v->print(); + if (v == maxXy) + { + b3Printf(" maxXy"); + } + if (v == minYx) + { + b3Printf(" minYx"); + } + if (v == maxYx) + { + b3Printf(" maxYx"); + } + if (v->next->prev != v) + { + b3Printf(" Inconsistency"); + } + b3Printf("\n"); + v = v->next; + if (v == minXy) + { + break; + } + } + if (minXy) + { + minXy->copy = (minXy->copy == -1) ? -2 : -1; + minXy->printGraph(); + } +} + +void b3ConvexHullInternal::Vertex::printGraph() +{ + print(); + b3Printf("\nEdges\n"); + Edge* e = edges; + if (e) + { + do + { + e->print(); + b3Printf("\n"); + e = e->next; + } while (e != edges); + do + { + Vertex* v = e->target; + if (v->copy != copy) + { + v->copy = copy; + v->printGraph(); + } + e = e->next; + } while (e != edges); + } +} +#endif + +b3ConvexHullInternal::Orientation b3ConvexHullInternal::getOrientation(const Edge* prev, const Edge* next, const Point32& s, const Point32& t) +{ + b3Assert(prev->reverse->target == next->reverse->target); + if (prev->next == next) + { + if (prev->prev == next) + { + Point64 n = t.cross(s); + Point64 m = (*prev->target - *next->reverse->target).cross(*next->target - *next->reverse->target); + b3Assert(!m.isZero()); + btInt64_t dot = n.dot(m); + b3Assert(dot != 0); + return (dot > 0) ? COUNTER_CLOCKWISE : CLOCKWISE; + } + return COUNTER_CLOCKWISE; + } + else if (prev->prev == next) + { + return CLOCKWISE; + } + else + { + return NONE; + } +} + +b3ConvexHullInternal::Edge* b3ConvexHullInternal::findMaxAngle(bool ccw, const Vertex* start, const Point32& s, const Point64& rxs, const Point64& sxrxs, Rational64& minCot) +{ + Edge* minEdge = NULL; + +#ifdef DEBUG_CONVEX_HULL + b3Printf("find max edge for %d\n", start->point.index); +#endif + Edge* e = start->edges; + if (e) + { + do + { + if (e->copy > mergeStamp) + { + Point32 t = *e->target - *start; + Rational64 cot(t.dot(sxrxs), t.dot(rxs)); +#ifdef DEBUG_CONVEX_HULL + b3Printf(" Angle is %f (%d) for ", (float) b3Atan(cot.toScalar()), (int) cot.isNaN()); + e->print(); +#endif + if (cot.isNaN()) + { + b3Assert(ccw ? (t.dot(s) < 0) : (t.dot(s) > 0)); + } + else + { + int cmp; + if (minEdge == NULL) + { + minCot = cot; + minEdge = e; + } + else if ((cmp = cot.compare(minCot)) < 0) + { + minCot = cot; + minEdge = e; + } + else if ((cmp == 0) && (ccw == (getOrientation(minEdge, e, s, t) == COUNTER_CLOCKWISE))) + { + minEdge = e; + } + } +#ifdef DEBUG_CONVEX_HULL + b3Printf("\n"); +#endif + } + e = e->next; + } while (e != start->edges); + } + return minEdge; +} + +void b3ConvexHullInternal::findEdgeForCoplanarFaces(Vertex* c0, Vertex* c1, Edge*& e0, Edge*& e1, Vertex* stop0, Vertex* stop1) +{ + Edge* start0 = e0; + Edge* start1 = e1; + Point32 et0 = start0 ? start0->target->point : c0->point; + Point32 et1 = start1 ? start1->target->point : c1->point; + Point32 s = c1->point - c0->point; + Point64 normal = ((start0 ? start0 : start1)->target->point - c0->point).cross(s); + btInt64_t dist = c0->point.dot(normal); + b3Assert(!start1 || (start1->target->point.dot(normal) == dist)); + Point64 perp = s.cross(normal); + b3Assert(!perp.isZero()); + +#ifdef DEBUG_CONVEX_HULL + b3Printf(" Advancing %d %d (%p %p, %d %d)\n", c0->point.index, c1->point.index, start0, start1, start0 ? start0->target->point.index : -1, start1 ? start1->target->point.index : -1); +#endif + + btInt64_t maxDot0 = et0.dot(perp); + if (e0) + { + while (e0->target != stop0) + { + Edge* e = e0->reverse->prev; + if (e->target->point.dot(normal) < dist) + { + break; + } + b3Assert(e->target->point.dot(normal) == dist); + if (e->copy == mergeStamp) + { + break; + } + btInt64_t dot = e->target->point.dot(perp); + if (dot <= maxDot0) + { + break; + } + maxDot0 = dot; + e0 = e; + et0 = e->target->point; + } + } + + btInt64_t maxDot1 = et1.dot(perp); + if (e1) + { + while (e1->target != stop1) + { + Edge* e = e1->reverse->next; + if (e->target->point.dot(normal) < dist) + { + break; + } + b3Assert(e->target->point.dot(normal) == dist); + if (e->copy == mergeStamp) + { + break; + } + btInt64_t dot = e->target->point.dot(perp); + if (dot <= maxDot1) + { + break; + } + maxDot1 = dot; + e1 = e; + et1 = e->target->point; + } + } + +#ifdef DEBUG_CONVEX_HULL + b3Printf(" Starting at %d %d\n", et0.index, et1.index); +#endif + + btInt64_t dx = maxDot1 - maxDot0; + if (dx > 0) + { + while (true) + { + btInt64_t dy = (et1 - et0).dot(s); + + if (e0 && (e0->target != stop0)) + { + Edge* f0 = e0->next->reverse; + if (f0->copy > mergeStamp) + { + btInt64_t dx0 = (f0->target->point - et0).dot(perp); + btInt64_t dy0 = (f0->target->point - et0).dot(s); + if ((dx0 == 0) ? (dy0 < 0) : ((dx0 < 0) && (Rational64(dy0, dx0).compare(Rational64(dy, dx)) >= 0))) + { + et0 = f0->target->point; + dx = (et1 - et0).dot(perp); + e0 = (e0 == start0) ? NULL : f0; + continue; + } + } + } + + if (e1 && (e1->target != stop1)) + { + Edge* f1 = e1->reverse->next; + if (f1->copy > mergeStamp) + { + Point32 d1 = f1->target->point - et1; + if (d1.dot(normal) == 0) + { + btInt64_t dx1 = d1.dot(perp); + btInt64_t dy1 = d1.dot(s); + btInt64_t dxn = (f1->target->point - et0).dot(perp); + if ((dxn > 0) && ((dx1 == 0) ? (dy1 < 0) : ((dx1 < 0) && (Rational64(dy1, dx1).compare(Rational64(dy, dx)) > 0)))) + { + e1 = f1; + et1 = e1->target->point; + dx = dxn; + continue; + } + } + else + { + b3Assert((e1 == start1) && (d1.dot(normal) < 0)); + } + } + } + + break; + } + } + else if (dx < 0) + { + while (true) + { + btInt64_t dy = (et1 - et0).dot(s); + + if (e1 && (e1->target != stop1)) + { + Edge* f1 = e1->prev->reverse; + if (f1->copy > mergeStamp) + { + btInt64_t dx1 = (f1->target->point - et1).dot(perp); + btInt64_t dy1 = (f1->target->point - et1).dot(s); + if ((dx1 == 0) ? (dy1 > 0) : ((dx1 < 0) && (Rational64(dy1, dx1).compare(Rational64(dy, dx)) <= 0))) + { + et1 = f1->target->point; + dx = (et1 - et0).dot(perp); + e1 = (e1 == start1) ? NULL : f1; + continue; + } + } + } + + if (e0 && (e0->target != stop0)) + { + Edge* f0 = e0->reverse->prev; + if (f0->copy > mergeStamp) + { + Point32 d0 = f0->target->point - et0; + if (d0.dot(normal) == 0) + { + btInt64_t dx0 = d0.dot(perp); + btInt64_t dy0 = d0.dot(s); + btInt64_t dxn = (et1 - f0->target->point).dot(perp); + if ((dxn < 0) && ((dx0 == 0) ? (dy0 > 0) : ((dx0 < 0) && (Rational64(dy0, dx0).compare(Rational64(dy, dx)) < 0)))) + { + e0 = f0; + et0 = e0->target->point; + dx = dxn; + continue; + } + } + else + { + b3Assert((e0 == start0) && (d0.dot(normal) < 0)); + } + } + } + + break; + } + } +#ifdef DEBUG_CONVEX_HULL + b3Printf(" Advanced edges to %d %d\n", et0.index, et1.index); +#endif +} + + +void b3ConvexHullInternal::merge(IntermediateHull& h0, IntermediateHull& h1) +{ + if (!h1.maxXy) + { + return; + } + if (!h0.maxXy) + { + h0 = h1; + return; + } + + mergeStamp--; + + Vertex* c0 = NULL; + Edge* toPrev0 = NULL; + Edge* firstNew0 = NULL; + Edge* pendingHead0 = NULL; + Edge* pendingTail0 = NULL; + Vertex* c1 = NULL; + Edge* toPrev1 = NULL; + Edge* firstNew1 = NULL; + Edge* pendingHead1 = NULL; + Edge* pendingTail1 = NULL; + Point32 prevPoint; + + if (mergeProjection(h0, h1, c0, c1)) + { + Point32 s = *c1 - *c0; + Point64 normal = Point32(0, 0, -1).cross(s); + Point64 t = s.cross(normal); + b3Assert(!t.isZero()); + + Edge* e = c0->edges; + Edge* start0 = NULL; + if (e) + { + do + { + btInt64_t dot = (*e->target - *c0).dot(normal); + b3Assert(dot <= 0); + if ((dot == 0) && ((*e->target - *c0).dot(t) > 0)) + { + if (!start0 || (getOrientation(start0, e, s, Point32(0, 0, -1)) == CLOCKWISE)) + { + start0 = e; + } + } + e = e->next; + } while (e != c0->edges); + } + + e = c1->edges; + Edge* start1 = NULL; + if (e) + { + do + { + btInt64_t dot = (*e->target - *c1).dot(normal); + b3Assert(dot <= 0); + if ((dot == 0) && ((*e->target - *c1).dot(t) > 0)) + { + if (!start1 || (getOrientation(start1, e, s, Point32(0, 0, -1)) == COUNTER_CLOCKWISE)) + { + start1 = e; + } + } + e = e->next; + } while (e != c1->edges); + } + + if (start0 || start1) + { + findEdgeForCoplanarFaces(c0, c1, start0, start1, NULL, NULL); + if (start0) + { + c0 = start0->target; + } + if (start1) + { + c1 = start1->target; + } + } + + prevPoint = c1->point; + prevPoint.z++; + } + else + { + prevPoint = c1->point; + prevPoint.x++; + } + + Vertex* first0 = c0; + Vertex* first1 = c1; + bool firstRun = true; + + while (true) + { + Point32 s = *c1 - *c0; + Point32 r = prevPoint - c0->point; + Point64 rxs = r.cross(s); + Point64 sxrxs = s.cross(rxs); + +#ifdef DEBUG_CONVEX_HULL + b3Printf("\n Checking %d %d\n", c0->point.index, c1->point.index); +#endif + Rational64 minCot0(0, 0); + Edge* min0 = findMaxAngle(false, c0, s, rxs, sxrxs, minCot0); + Rational64 minCot1(0, 0); + Edge* min1 = findMaxAngle(true, c1, s, rxs, sxrxs, minCot1); + if (!min0 && !min1) + { + Edge* e = newEdgePair(c0, c1); + e->link(e); + c0->edges = e; + + e = e->reverse; + e->link(e); + c1->edges = e; + return; + } + else + { + int cmp = !min0 ? 1 : !min1 ? -1 : minCot0.compare(minCot1); +#ifdef DEBUG_CONVEX_HULL + b3Printf(" -> Result %d\n", cmp); +#endif + if (firstRun || ((cmp >= 0) ? !minCot1.isNegativeInfinity() : !minCot0.isNegativeInfinity())) + { + Edge* e = newEdgePair(c0, c1); + if (pendingTail0) + { + pendingTail0->prev = e; + } + else + { + pendingHead0 = e; + } + e->next = pendingTail0; + pendingTail0 = e; + + e = e->reverse; + if (pendingTail1) + { + pendingTail1->next = e; + } + else + { + pendingHead1 = e; + } + e->prev = pendingTail1; + pendingTail1 = e; + } + + Edge* e0 = min0; + Edge* e1 = min1; + +#ifdef DEBUG_CONVEX_HULL + b3Printf(" Found min edges to %d %d\n", e0 ? e0->target->point.index : -1, e1 ? e1->target->point.index : -1); +#endif + + if (cmp == 0) + { + findEdgeForCoplanarFaces(c0, c1, e0, e1, NULL, NULL); + } + + if ((cmp >= 0) && e1) + { + if (toPrev1) + { + for (Edge* e = toPrev1->next, *n = NULL; e != min1; e = n) + { + n = e->next; + removeEdgePair(e); + } + } + + if (pendingTail1) + { + if (toPrev1) + { + toPrev1->link(pendingHead1); + } + else + { + min1->prev->link(pendingHead1); + firstNew1 = pendingHead1; + } + pendingTail1->link(min1); + pendingHead1 = NULL; + pendingTail1 = NULL; + } + else if (!toPrev1) + { + firstNew1 = min1; + } + + prevPoint = c1->point; + c1 = e1->target; + toPrev1 = e1->reverse; + } + + if ((cmp <= 0) && e0) + { + if (toPrev0) + { + for (Edge* e = toPrev0->prev, *n = NULL; e != min0; e = n) + { + n = e->prev; + removeEdgePair(e); + } + } + + if (pendingTail0) + { + if (toPrev0) + { + pendingHead0->link(toPrev0); + } + else + { + pendingHead0->link(min0->next); + firstNew0 = pendingHead0; + } + min0->link(pendingTail0); + pendingHead0 = NULL; + pendingTail0 = NULL; + } + else if (!toPrev0) + { + firstNew0 = min0; + } + + prevPoint = c0->point; + c0 = e0->target; + toPrev0 = e0->reverse; + } + } + + if ((c0 == first0) && (c1 == first1)) + { + if (toPrev0 == NULL) + { + pendingHead0->link(pendingTail0); + c0->edges = pendingTail0; + } + else + { + for (Edge* e = toPrev0->prev, *n = NULL; e != firstNew0; e = n) + { + n = e->prev; + removeEdgePair(e); + } + if (pendingTail0) + { + pendingHead0->link(toPrev0); + firstNew0->link(pendingTail0); + } + } + + if (toPrev1 == NULL) + { + pendingTail1->link(pendingHead1); + c1->edges = pendingTail1; + } + else + { + for (Edge* e = toPrev1->next, *n = NULL; e != firstNew1; e = n) + { + n = e->next; + removeEdgePair(e); + } + if (pendingTail1) + { + toPrev1->link(pendingHead1); + pendingTail1->link(firstNew1); + } + } + + return; + } + + firstRun = false; + } +} + + +static bool b3PointCmp(const b3ConvexHullInternal::Point32& p, const b3ConvexHullInternal::Point32& q) +{ + return (p.y < q.y) || ((p.y == q.y) && ((p.x < q.x) || ((p.x == q.x) && (p.z < q.z)))); +} + +void b3ConvexHullInternal::compute(const void* coords, bool doubleCoords, int stride, int count) +{ + b3Vector3 min = b3MakeVector3(b3Scalar(1e30), b3Scalar(1e30), b3Scalar(1e30)), max = b3MakeVector3(b3Scalar(-1e30), b3Scalar(-1e30), b3Scalar(-1e30)); + const char* ptr = (const char*) coords; + if (doubleCoords) + { + for (int i = 0; i < count; i++) + { + const double* v = (const double*) ptr; + b3Vector3 p = b3MakeVector3((b3Scalar) v[0], (b3Scalar) v[1], (b3Scalar) v[2]); + ptr += stride; + min.setMin(p); + max.setMax(p); + } + } + else + { + for (int i = 0; i < count; i++) + { + const float* v = (const float*) ptr; + b3Vector3 p = b3MakeVector3(v[0], v[1], v[2]); + ptr += stride; + min.setMin(p); + max.setMax(p); + } + } + + b3Vector3 s = max - min; + maxAxis = s.maxAxis(); + minAxis = s.minAxis(); + if (minAxis == maxAxis) + { + minAxis = (maxAxis + 1) % 3; + } + medAxis = 3 - maxAxis - minAxis; + + s /= b3Scalar(10216); + if (((medAxis + 1) % 3) != maxAxis) + { + s *= -1; + } + scaling = s; + + if (s[0] != 0) + { + s[0] = b3Scalar(1) / s[0]; + } + if (s[1] != 0) + { + s[1] = b3Scalar(1) / s[1]; + } + if (s[2] != 0) + { + s[2] = b3Scalar(1) / s[2]; + } + + center = (min + max) * b3Scalar(0.5); + + b3AlignedObjectArray points; + points.resize(count); + ptr = (const char*) coords; + if (doubleCoords) + { + for (int i = 0; i < count; i++) + { + const double* v = (const double*) ptr; + b3Vector3 p = b3MakeVector3((b3Scalar) v[0], (b3Scalar) v[1], (b3Scalar) v[2]); + ptr += stride; + p = (p - center) * s; + points[i].x = (btInt32_t) p[medAxis]; + points[i].y = (btInt32_t) p[maxAxis]; + points[i].z = (btInt32_t) p[minAxis]; + points[i].index = i; + } + } + else + { + for (int i = 0; i < count; i++) + { + const float* v = (const float*) ptr; + b3Vector3 p = b3MakeVector3(v[0], v[1], v[2]); + ptr += stride; + p = (p - center) * s; + points[i].x = (btInt32_t) p[medAxis]; + points[i].y = (btInt32_t) p[maxAxis]; + points[i].z = (btInt32_t) p[minAxis]; + points[i].index = i; + } + } + points.quickSort(b3PointCmp); + + vertexPool.reset(); + vertexPool.setArraySize(count); + originalVertices.resize(count); + for (int i = 0; i < count; i++) + { + Vertex* v = vertexPool.newObject(); + v->edges = NULL; + v->point = points[i]; + v->copy = -1; + originalVertices[i] = v; + } + + points.clear(); + + edgePool.reset(); + edgePool.setArraySize(6 * count); + + usedEdgePairs = 0; + maxUsedEdgePairs = 0; + + mergeStamp = -3; + + IntermediateHull hull; + computeInternal(0, count, hull); + vertexList = hull.minXy; +#ifdef DEBUG_CONVEX_HULL + b3Printf("max. edges %d (3v = %d)", maxUsedEdgePairs, 3 * count); +#endif +} + +b3Vector3 b3ConvexHullInternal::toBtVector(const Point32& v) +{ + b3Vector3 p; + p[medAxis] = b3Scalar(v.x); + p[maxAxis] = b3Scalar(v.y); + p[minAxis] = b3Scalar(v.z); + return p * scaling; +} + +b3Vector3 b3ConvexHullInternal::getBtNormal(Face* face) +{ + return toBtVector(face->dir0).cross(toBtVector(face->dir1)).normalized(); +} + +b3Vector3 b3ConvexHullInternal::getCoordinates(const Vertex* v) +{ + b3Vector3 p; + p[medAxis] = v->xvalue(); + p[maxAxis] = v->yvalue(); + p[minAxis] = v->zvalue(); + return p * scaling + center; +} + +b3Scalar b3ConvexHullInternal::shrink(b3Scalar amount, b3Scalar clampAmount) +{ + if (!vertexList) + { + return 0; + } + int stamp = --mergeStamp; + b3AlignedObjectArray stack; + vertexList->copy = stamp; + stack.push_back(vertexList); + b3AlignedObjectArray faces; + + Point32 ref = vertexList->point; + Int128 hullCenterX(0, 0); + Int128 hullCenterY(0, 0); + Int128 hullCenterZ(0, 0); + Int128 volume(0, 0); + + while (stack.size() > 0) + { + Vertex* v = stack[stack.size() - 1]; + stack.pop_back(); + Edge* e = v->edges; + if (e) + { + do + { + if (e->target->copy != stamp) + { + e->target->copy = stamp; + stack.push_back(e->target); + } + if (e->copy != stamp) + { + Face* face = facePool.newObject(); + face->init(e->target, e->reverse->prev->target, v); + faces.push_back(face); + Edge* f = e; + + Vertex* a = NULL; + Vertex* b = NULL; + do + { + if (a && b) + { + btInt64_t vol = (v->point - ref).dot((a->point - ref).cross(b->point - ref)); + b3Assert(vol >= 0); + Point32 c = v->point + a->point + b->point + ref; + hullCenterX += vol * c.x; + hullCenterY += vol * c.y; + hullCenterZ += vol * c.z; + volume += vol; + } + + b3Assert(f->copy != stamp); + f->copy = stamp; + f->face = face; + + a = b; + b = f->target; + + f = f->reverse->prev; + } while (f != e); + } + e = e->next; + } while (e != v->edges); + } + } + + if (volume.getSign() <= 0) + { + return 0; + } + + b3Vector3 hullCenter; + hullCenter[medAxis] = hullCenterX.toScalar(); + hullCenter[maxAxis] = hullCenterY.toScalar(); + hullCenter[minAxis] = hullCenterZ.toScalar(); + hullCenter /= 4 * volume.toScalar(); + hullCenter *= scaling; + + int faceCount = faces.size(); + + if (clampAmount > 0) + { + b3Scalar minDist = B3_INFINITY; + for (int i = 0; i < faceCount; i++) + { + b3Vector3 normal = getBtNormal(faces[i]); + b3Scalar dist = normal.dot(toBtVector(faces[i]->origin) - hullCenter); + if (dist < minDist) + { + minDist = dist; + } + } + + if (minDist <= 0) + { + return 0; + } + + amount = b3Min(amount, minDist * clampAmount); + } + + unsigned int seed = 243703; + for (int i = 0; i < faceCount; i++, seed = 1664525 * seed + 1013904223) + { + b3Swap(faces[i], faces[seed % faceCount]); + } + + for (int i = 0; i < faceCount; i++) + { + if (!shiftFace(faces[i], amount, stack)) + { + return -amount; + } + } + + return amount; +} + +bool b3ConvexHullInternal::shiftFace(Face* face, b3Scalar amount, b3AlignedObjectArray stack) +{ + b3Vector3 origShift = getBtNormal(face) * -amount; + if (scaling[0] != 0) + { + origShift[0] /= scaling[0]; + } + if (scaling[1] != 0) + { + origShift[1] /= scaling[1]; + } + if (scaling[2] != 0) + { + origShift[2] /= scaling[2]; + } + Point32 shift((btInt32_t) origShift[medAxis], (btInt32_t) origShift[maxAxis], (btInt32_t) origShift[minAxis]); + if (shift.isZero()) + { + return true; + } + Point64 normal = face->getNormal(); +#ifdef DEBUG_CONVEX_HULL + b3Printf("\nShrinking face (%d %d %d) (%d %d %d) (%d %d %d) by (%d %d %d)\n", + face->origin.x, face->origin.y, face->origin.z, face->dir0.x, face->dir0.y, face->dir0.z, face->dir1.x, face->dir1.y, face->dir1.z, shift.x, shift.y, shift.z); +#endif + btInt64_t origDot = face->origin.dot(normal); + Point32 shiftedOrigin = face->origin + shift; + btInt64_t shiftedDot = shiftedOrigin.dot(normal); + b3Assert(shiftedDot <= origDot); + if (shiftedDot >= origDot) + { + return false; + } + + Edge* intersection = NULL; + + Edge* startEdge = face->nearbyVertex->edges; +#ifdef DEBUG_CONVEX_HULL + b3Printf("Start edge is "); + startEdge->print(); + b3Printf(", normal is (%lld %lld %lld), shifted dot is %lld\n", normal.x, normal.y, normal.z, shiftedDot); +#endif + Rational128 optDot = face->nearbyVertex->dot(normal); + int cmp = optDot.compare(shiftedDot); +#ifdef SHOW_ITERATIONS + int n = 0; +#endif + if (cmp >= 0) + { + Edge* e = startEdge; + do + { +#ifdef SHOW_ITERATIONS + n++; +#endif + Rational128 dot = e->target->dot(normal); + b3Assert(dot.compare(origDot) <= 0); +#ifdef DEBUG_CONVEX_HULL + b3Printf("Moving downwards, edge is "); + e->print(); + b3Printf(", dot is %f (%f %lld)\n", (float) dot.toScalar(), (float) optDot.toScalar(), shiftedDot); +#endif + if (dot.compare(optDot) < 0) + { + int c = dot.compare(shiftedDot); + optDot = dot; + e = e->reverse; + startEdge = e; + if (c < 0) + { + intersection = e; + break; + } + cmp = c; + } + e = e->prev; + } while (e != startEdge); + + if (!intersection) + { + return false; + } + } + else + { + Edge* e = startEdge; + do + { +#ifdef SHOW_ITERATIONS + n++; +#endif + Rational128 dot = e->target->dot(normal); + b3Assert(dot.compare(origDot) <= 0); +#ifdef DEBUG_CONVEX_HULL + b3Printf("Moving upwards, edge is "); + e->print(); + b3Printf(", dot is %f (%f %lld)\n", (float) dot.toScalar(), (float) optDot.toScalar(), shiftedDot); +#endif + if (dot.compare(optDot) > 0) + { + cmp = dot.compare(shiftedDot); + if (cmp >= 0) + { + intersection = e; + break; + } + optDot = dot; + e = e->reverse; + startEdge = e; + } + e = e->prev; + } while (e != startEdge); + + if (!intersection) + { + return true; + } + } + +#ifdef SHOW_ITERATIONS + b3Printf("Needed %d iterations to find initial intersection\n", n); +#endif + + if (cmp == 0) + { + Edge* e = intersection->reverse->next; +#ifdef SHOW_ITERATIONS + n = 0; +#endif + while (e->target->dot(normal).compare(shiftedDot) <= 0) + { +#ifdef SHOW_ITERATIONS + n++; +#endif + e = e->next; + if (e == intersection->reverse) + { + return true; + } +#ifdef DEBUG_CONVEX_HULL + b3Printf("Checking for outwards edge, current edge is "); + e->print(); + b3Printf("\n"); +#endif + } +#ifdef SHOW_ITERATIONS + b3Printf("Needed %d iterations to check for complete containment\n", n); +#endif + } + + Edge* firstIntersection = NULL; + Edge* faceEdge = NULL; + Edge* firstFaceEdge = NULL; + +#ifdef SHOW_ITERATIONS + int m = 0; +#endif + while (true) + { +#ifdef SHOW_ITERATIONS + m++; +#endif +#ifdef DEBUG_CONVEX_HULL + b3Printf("Intersecting edge is "); + intersection->print(); + b3Printf("\n"); +#endif + if (cmp == 0) + { + Edge* e = intersection->reverse->next; + startEdge = e; +#ifdef SHOW_ITERATIONS + n = 0; +#endif + while (true) + { +#ifdef SHOW_ITERATIONS + n++; +#endif + if (e->target->dot(normal).compare(shiftedDot) >= 0) + { + break; + } + intersection = e->reverse; + e = e->next; + if (e == startEdge) + { + return true; + } + } +#ifdef SHOW_ITERATIONS + b3Printf("Needed %d iterations to advance intersection\n", n); +#endif + } + +#ifdef DEBUG_CONVEX_HULL + b3Printf("Advanced intersecting edge to "); + intersection->print(); + b3Printf(", cmp = %d\n", cmp); +#endif + + if (!firstIntersection) + { + firstIntersection = intersection; + } + else if (intersection == firstIntersection) + { + break; + } + + int prevCmp = cmp; + Edge* prevIntersection = intersection; + Edge* prevFaceEdge = faceEdge; + + Edge* e = intersection->reverse; +#ifdef SHOW_ITERATIONS + n = 0; +#endif + while (true) + { +#ifdef SHOW_ITERATIONS + n++; +#endif + e = e->reverse->prev; + b3Assert(e != intersection->reverse); + cmp = e->target->dot(normal).compare(shiftedDot); +#ifdef DEBUG_CONVEX_HULL + b3Printf("Testing edge "); + e->print(); + b3Printf(" -> cmp = %d\n", cmp); +#endif + if (cmp >= 0) + { + intersection = e; + break; + } + } +#ifdef SHOW_ITERATIONS + b3Printf("Needed %d iterations to find other intersection of face\n", n); +#endif + + if (cmp > 0) + { + Vertex* removed = intersection->target; + e = intersection->reverse; + if (e->prev == e) + { + removed->edges = NULL; + } + else + { + removed->edges = e->prev; + e->prev->link(e->next); + e->link(e); + } +#ifdef DEBUG_CONVEX_HULL + b3Printf("1: Removed part contains (%d %d %d)\n", removed->point.x, removed->point.y, removed->point.z); +#endif + + Point64 n0 = intersection->face->getNormal(); + Point64 n1 = intersection->reverse->face->getNormal(); + btInt64_t m00 = face->dir0.dot(n0); + btInt64_t m01 = face->dir1.dot(n0); + btInt64_t m10 = face->dir0.dot(n1); + btInt64_t m11 = face->dir1.dot(n1); + btInt64_t r0 = (intersection->face->origin - shiftedOrigin).dot(n0); + btInt64_t r1 = (intersection->reverse->face->origin - shiftedOrigin).dot(n1); + Int128 det = Int128::mul(m00, m11) - Int128::mul(m01, m10); + b3Assert(det.getSign() != 0); + Vertex* v = vertexPool.newObject(); + v->point.index = -1; + v->copy = -1; + v->point128 = PointR128(Int128::mul(face->dir0.x * r0, m11) - Int128::mul(face->dir0.x * r1, m01) + + Int128::mul(face->dir1.x * r1, m00) - Int128::mul(face->dir1.x * r0, m10) + det * shiftedOrigin.x, + Int128::mul(face->dir0.y * r0, m11) - Int128::mul(face->dir0.y * r1, m01) + + Int128::mul(face->dir1.y * r1, m00) - Int128::mul(face->dir1.y * r0, m10) + det * shiftedOrigin.y, + Int128::mul(face->dir0.z * r0, m11) - Int128::mul(face->dir0.z * r1, m01) + + Int128::mul(face->dir1.z * r1, m00) - Int128::mul(face->dir1.z * r0, m10) + det * shiftedOrigin.z, + det); + v->point.x = (btInt32_t) v->point128.xvalue(); + v->point.y = (btInt32_t) v->point128.yvalue(); + v->point.z = (btInt32_t) v->point128.zvalue(); + intersection->target = v; + v->edges = e; + + stack.push_back(v); + stack.push_back(removed); + stack.push_back(NULL); + } + + if (cmp || prevCmp || (prevIntersection->reverse->next->target != intersection->target)) + { + faceEdge = newEdgePair(prevIntersection->target, intersection->target); + if (prevCmp == 0) + { + faceEdge->link(prevIntersection->reverse->next); + } + if ((prevCmp == 0) || prevFaceEdge) + { + prevIntersection->reverse->link(faceEdge); + } + if (cmp == 0) + { + intersection->reverse->prev->link(faceEdge->reverse); + } + faceEdge->reverse->link(intersection->reverse); + } + else + { + faceEdge = prevIntersection->reverse->next; + } + + if (prevFaceEdge) + { + if (prevCmp > 0) + { + faceEdge->link(prevFaceEdge->reverse); + } + else if (faceEdge != prevFaceEdge->reverse) + { + stack.push_back(prevFaceEdge->target); + while (faceEdge->next != prevFaceEdge->reverse) + { + Vertex* removed = faceEdge->next->target; + removeEdgePair(faceEdge->next); + stack.push_back(removed); +#ifdef DEBUG_CONVEX_HULL + b3Printf("2: Removed part contains (%d %d %d)\n", removed->point.x, removed->point.y, removed->point.z); +#endif + } + stack.push_back(NULL); + } + } + faceEdge->face = face; + faceEdge->reverse->face = intersection->face; + + if (!firstFaceEdge) + { + firstFaceEdge = faceEdge; + } + } +#ifdef SHOW_ITERATIONS + b3Printf("Needed %d iterations to process all intersections\n", m); +#endif + + if (cmp > 0) + { + firstFaceEdge->reverse->target = faceEdge->target; + firstIntersection->reverse->link(firstFaceEdge); + firstFaceEdge->link(faceEdge->reverse); + } + else if (firstFaceEdge != faceEdge->reverse) + { + stack.push_back(faceEdge->target); + while (firstFaceEdge->next != faceEdge->reverse) + { + Vertex* removed = firstFaceEdge->next->target; + removeEdgePair(firstFaceEdge->next); + stack.push_back(removed); +#ifdef DEBUG_CONVEX_HULL + b3Printf("3: Removed part contains (%d %d %d)\n", removed->point.x, removed->point.y, removed->point.z); +#endif + } + stack.push_back(NULL); + } + + b3Assert(stack.size() > 0); + vertexList = stack[0]; + +#ifdef DEBUG_CONVEX_HULL + b3Printf("Removing part\n"); +#endif +#ifdef SHOW_ITERATIONS + n = 0; +#endif + int pos = 0; + while (pos < stack.size()) + { + int end = stack.size(); + while (pos < end) + { + Vertex* kept = stack[pos++]; +#ifdef DEBUG_CONVEX_HULL + kept->print(); +#endif + bool deeper = false; + Vertex* removed; + while ((removed = stack[pos++]) != NULL) + { +#ifdef SHOW_ITERATIONS + n++; +#endif + kept->receiveNearbyFaces(removed); + while (removed->edges) + { + if (!deeper) + { + deeper = true; + stack.push_back(kept); + } + stack.push_back(removed->edges->target); + removeEdgePair(removed->edges); + } + } + if (deeper) + { + stack.push_back(NULL); + } + } + } +#ifdef SHOW_ITERATIONS + b3Printf("Needed %d iterations to remove part\n", n); +#endif + + stack.resize(0); + face->origin = shiftedOrigin; + + return true; +} + + +static int getVertexCopy(b3ConvexHullInternal::Vertex* vertex, b3AlignedObjectArray& vertices) +{ + int index = vertex->copy; + if (index < 0) + { + index = vertices.size(); + vertex->copy = index; + vertices.push_back(vertex); +#ifdef DEBUG_CONVEX_HULL + b3Printf("Vertex %d gets index *%d\n", vertex->point.index, index); +#endif + } + return index; +} + +b3Scalar b3ConvexHullComputer::compute(const void* coords, bool doubleCoords, int stride, int count, b3Scalar shrink, b3Scalar shrinkClamp) +{ + if (count <= 0) + { + vertices.clear(); + edges.clear(); + faces.clear(); + return 0; + } + + b3ConvexHullInternal hull; + hull.compute(coords, doubleCoords, stride, count); + + b3Scalar shift = 0; + if ((shrink > 0) && ((shift = hull.shrink(shrink, shrinkClamp)) < 0)) + { + vertices.clear(); + edges.clear(); + faces.clear(); + return shift; + } + + vertices.resize(0); + edges.resize(0); + faces.resize(0); + + b3AlignedObjectArray oldVertices; + getVertexCopy(hull.vertexList, oldVertices); + int copied = 0; + while (copied < oldVertices.size()) + { + b3ConvexHullInternal::Vertex* v = oldVertices[copied]; + vertices.push_back(hull.getCoordinates(v)); + b3ConvexHullInternal::Edge* firstEdge = v->edges; + if (firstEdge) + { + int firstCopy = -1; + int prevCopy = -1; + b3ConvexHullInternal::Edge* e = firstEdge; + do + { + if (e->copy < 0) + { + int s = edges.size(); + edges.push_back(Edge()); + edges.push_back(Edge()); + Edge* c = &edges[s]; + Edge* r = &edges[s + 1]; + e->copy = s; + e->reverse->copy = s + 1; + c->reverse = 1; + r->reverse = -1; + c->targetVertex = getVertexCopy(e->target, oldVertices); + r->targetVertex = copied; +#ifdef DEBUG_CONVEX_HULL + b3Printf(" CREATE: Vertex *%d has edge to *%d\n", copied, c->getTargetVertex()); +#endif + } + if (prevCopy >= 0) + { + edges[e->copy].next = prevCopy - e->copy; + } + else + { + firstCopy = e->copy; + } + prevCopy = e->copy; + e = e->next; + } while (e != firstEdge); + edges[firstCopy].next = prevCopy - firstCopy; + } + copied++; + } + + for (int i = 0; i < copied; i++) + { + b3ConvexHullInternal::Vertex* v = oldVertices[i]; + b3ConvexHullInternal::Edge* firstEdge = v->edges; + if (firstEdge) + { + b3ConvexHullInternal::Edge* e = firstEdge; + do + { + if (e->copy >= 0) + { +#ifdef DEBUG_CONVEX_HULL + b3Printf("Vertex *%d has edge to *%d\n", i, edges[e->copy].getTargetVertex()); +#endif + faces.push_back(e->copy); + b3ConvexHullInternal::Edge* f = e; + do + { +#ifdef DEBUG_CONVEX_HULL + b3Printf(" Face *%d\n", edges[f->copy].getTargetVertex()); +#endif + f->copy = -1; + f = f->reverse->prev; + } while (f != e); + } + e = e->next; + } while (e != firstEdge); + } + } + + return shift; +} + + + + + diff --git a/extern/bullet/src/Bullet3Geometry/b3ConvexHullComputer.h b/extern/bullet/src/Bullet3Geometry/b3ConvexHullComputer.h new file mode 100644 index 000000000000..6dcc931a78cf --- /dev/null +++ b/extern/bullet/src/Bullet3Geometry/b3ConvexHullComputer.h @@ -0,0 +1,103 @@ +/* +Copyright (c) 2011 Ole Kniemeyer, MAXON, www.maxon.net + +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 B3_CONVEX_HULL_COMPUTER_H +#define B3_CONVEX_HULL_COMPUTER_H + +#include "Bullet3Common/b3Vector3.h" +#include "Bullet3Common/b3AlignedObjectArray.h" + +/// Convex hull implementation based on Preparata and Hong +/// See http://code.google.com/p/bullet/issues/detail?id=275 +/// Ole Kniemeyer, MAXON Computer GmbH +class b3ConvexHullComputer +{ + private: + b3Scalar compute(const void* coords, bool doubleCoords, int stride, int count, b3Scalar shrink, b3Scalar shrinkClamp); + + public: + + class Edge + { + private: + int next; + int reverse; + int targetVertex; + + friend class b3ConvexHullComputer; + + public: + int getSourceVertex() const + { + return (this + reverse)->targetVertex; + } + + int getTargetVertex() const + { + return targetVertex; + } + + const Edge* getNextEdgeOfVertex() const // clockwise list of all edges of a vertex + { + return this + next; + } + + const Edge* getNextEdgeOfFace() const // counter-clockwise list of all edges of a face + { + return (this + reverse)->getNextEdgeOfVertex(); + } + + const Edge* getReverseEdge() const + { + return this + reverse; + } + }; + + + // Vertices of the output hull + b3AlignedObjectArray vertices; + + // Edges of the output hull + b3AlignedObjectArray edges; + + // Faces of the convex hull. Each entry is an index into the "edges" array pointing to an edge of the face. Faces are planar n-gons + b3AlignedObjectArray faces; + + /* + Compute convex hull of "count" vertices stored in "coords". "stride" is the difference in bytes + between the addresses of consecutive vertices. If "shrink" is positive, the convex hull is shrunken + by that amount (each face is moved by "shrink" length units towards the center along its normal). + If "shrinkClamp" is positive, "shrink" is clamped to not exceed "shrinkClamp * innerRadius", where "innerRadius" + is the minimum distance of a face to the center of the convex hull. + + The returned value is the amount by which the hull has been shrunken. If it is negative, the amount was so large + that the resulting convex hull is empty. + + The output convex hull can be found in the member variables "vertices", "edges", "faces". + */ + b3Scalar compute(const float* coords, int stride, int count, b3Scalar shrink, b3Scalar shrinkClamp) + { + return compute(coords, false, stride, count, shrink, shrinkClamp); + } + + // same as above, but double precision + b3Scalar compute(const double* coords, int stride, int count, b3Scalar shrink, b3Scalar shrinkClamp) + { + return compute(coords, true, stride, count, shrink, shrinkClamp); + } +}; + + +#endif //B3_CONVEX_HULL_COMPUTER_H + diff --git a/extern/bullet/src/Bullet3Geometry/b3GeometryUtil.cpp b/extern/bullet/src/Bullet3Geometry/b3GeometryUtil.cpp new file mode 100644 index 000000000000..dd80fed6bd95 --- /dev/null +++ b/extern/bullet/src/Bullet3Geometry/b3GeometryUtil.cpp @@ -0,0 +1,185 @@ +/* +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. +*/ + + + +#include "b3GeometryUtil.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 b3BulletMathProbe (); + + void b3BulletMathProbe () {} +} + + +bool b3GeometryUtil::isPointInsidePlanes(const b3AlignedObjectArray& planeEquations, const b3Vector3& point, b3Scalar margin) +{ + int numbrushes = planeEquations.size(); + for (int i=0;ib3Scalar(0.)) + { + return false; + } + } + return true; + +} + + +bool b3GeometryUtil::areVerticesBehindPlane(const b3Vector3& planeNormal, const b3AlignedObjectArray& vertices, b3Scalar margin) +{ + int numvertices = vertices.size(); + for (int i=0;ib3Scalar(0.)) + { + return false; + } + } + return true; +} + +bool notExist(const b3Vector3& planeEquation,const b3AlignedObjectArray& planeEquations); + +bool notExist(const b3Vector3& planeEquation,const b3AlignedObjectArray& planeEquations) +{ + int numbrushes = planeEquations.size(); + for (int i=0;i b3Scalar(0.999)) + { + return false; + } + } + return true; +} + +void b3GeometryUtil::getPlaneEquationsFromVertices(b3AlignedObjectArray& vertices, b3AlignedObjectArray& planeEquationsOut ) +{ + const int numvertices = vertices.size(); + // brute force: + for (int i=0;i b3Scalar(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,b3Scalar(0.01))) + { + planeEquationsOut.push_back(planeEquation); + } + } + } + normalSign = b3Scalar(-1.); + } + + } + } + } + +} + +void b3GeometryUtil::getVerticesFromPlaneEquations(const b3AlignedObjectArray& planeEquations , b3AlignedObjectArray& verticesOut ) +{ + const int numbrushes = planeEquations.size(); + // brute force: + for (int i=0;i b3Scalar(0.0001) ) && + ( n3n1.length2() > b3Scalar(0.0001) ) && + ( n1n2.length2() > b3Scalar(0.0001) ) ) + { + //point P out of 3 plane equations: + + // d1 ( N2 * N3 ) + d2 ( N3 * N1 ) + d3 ( N1 * N2 ) + //P = ------------------------------------------------------------------------- + // N1 . ( N2 * N3 ) + + + b3Scalar quotient = (N1.dot(n2n3)); + if (b3Fabs(quotient) > b3Scalar(0.000001)) + { + quotient = b3Scalar(-1.) / quotient; + n2n3 *= N1[3]; + n3n1 *= N2[3]; + n1n2 *= N3[3]; + b3Vector3 potentialVertex = n2n3; + potentialVertex += n3n1; + potentialVertex += n1n2; + potentialVertex *= quotient; + + //check if inside, and replace supportingVertexOut if needed + if (isPointInsidePlanes(planeEquations,potentialVertex,b3Scalar(0.01))) + { + verticesOut.push_back(potentialVertex); + } + } + } + } + } + } +} + diff --git a/extern/bullet/src/Bullet3Geometry/b3GeometryUtil.h b/extern/bullet/src/Bullet3Geometry/b3GeometryUtil.h new file mode 100644 index 000000000000..8b5fd7ad62e0 --- /dev/null +++ b/extern/bullet/src/Bullet3Geometry/b3GeometryUtil.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 B3_GEOMETRY_UTIL_H +#define B3_GEOMETRY_UTIL_H + +#include "Bullet3Common/b3Vector3.h" +#include "Bullet3Common/b3AlignedObjectArray.h" + +///The b3GeometryUtil helper class provides a few methods to convert between plane equations and vertices. +class b3GeometryUtil +{ + public: + + + static void getPlaneEquationsFromVertices(b3AlignedObjectArray& vertices, b3AlignedObjectArray& planeEquationsOut ); + + static void getVerticesFromPlaneEquations(const b3AlignedObjectArray& planeEquations , b3AlignedObjectArray& verticesOut ); + + static bool isInside(const b3AlignedObjectArray& vertices, const b3Vector3& planeNormal, b3Scalar margin); + + static bool isPointInsidePlanes(const b3AlignedObjectArray& planeEquations, const b3Vector3& point, b3Scalar margin); + + static bool areVerticesBehindPlane(const b3Vector3& planeNormal, const b3AlignedObjectArray& vertices, b3Scalar margin); + +}; + + +#endif //B3_GEOMETRY_UTIL_H + diff --git a/extern/bullet/src/Bullet3Geometry/b3GrahamScan2dConvexHull.h b/extern/bullet/src/Bullet3Geometry/b3GrahamScan2dConvexHull.h new file mode 100644 index 000000000000..1b933c526452 --- /dev/null +++ b/extern/bullet/src/Bullet3Geometry/b3GrahamScan2dConvexHull.h @@ -0,0 +1,117 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2011 Advanced Micro Devices, Inc. http://bulletphysics.org + +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 B3_GRAHAM_SCAN_2D_CONVEX_HULL_H +#define B3_GRAHAM_SCAN_2D_CONVEX_HULL_H + + +#include "Bullet3Common/b3Vector3.h" +#include "Bullet3Common/b3AlignedObjectArray.h" + +struct b3GrahamVector3 : public b3Vector3 +{ + b3GrahamVector3(const b3Vector3& org, int orgIndex) + :b3Vector3(org), + m_orgIndex(orgIndex) + { + } + b3Scalar m_angle; + int m_orgIndex; +}; + + +struct b3AngleCompareFunc { + b3Vector3 m_anchor; + b3AngleCompareFunc(const b3Vector3& anchor) + : m_anchor(anchor) + { + } + bool operator()(const b3GrahamVector3& a, const b3GrahamVector3& b) const { + if (a.m_angle != b.m_angle) + return a.m_angle < b.m_angle; + else + { + b3Scalar al = (a-m_anchor).length2(); + b3Scalar bl = (b-m_anchor).length2(); + if (al != bl) + return al < bl; + else + { + return a.m_orgIndex < b.m_orgIndex; + } + } + } +}; + +inline void b3GrahamScanConvexHull2D(b3AlignedObjectArray& originalPoints, b3AlignedObjectArray& hull, const b3Vector3& normalAxis) +{ + b3Vector3 axis0,axis1; + b3PlaneSpace1(normalAxis,axis0,axis1); + + + if (originalPoints.size()<=1) + { + for (int i=0;i1) { + b3Vector3& a = hull[hull.size()-2]; + b3Vector3& b = hull[hull.size()-1]; + isConvex = b3Cross(a-b,a-originalPoints[i]).dot(normalAxis)> 0; + if (!isConvex) + hull.pop_back(); + else + hull.push_back(originalPoints[i]); + } + } +} + +#endif //B3_GRAHAM_SCAN_2D_CONVEX_HULL_H diff --git a/extern/bullet/src/Bullet3Geometry/premake4.lua b/extern/bullet/src/Bullet3Geometry/premake4.lua new file mode 100644 index 000000000000..1a230f8c0101 --- /dev/null +++ b/extern/bullet/src/Bullet3Geometry/premake4.lua @@ -0,0 +1,13 @@ + project "Bullet3Geometry" + + language "C++" + + kind "StaticLib" + + includedirs {".."} + + + files { + "**.cpp", + "**.h" + } \ No newline at end of file diff --git a/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuBroadphaseInterface.h b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuBroadphaseInterface.h new file mode 100644 index 000000000000..0ed8aa823265 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuBroadphaseInterface.h @@ -0,0 +1,44 @@ + +#ifndef B3_GPU_BROADPHASE_INTERFACE_H +#define B3_GPU_BROADPHASE_INTERFACE_H + +#include "Bullet3OpenCL/Initialize/b3OpenCLInclude.h" +#include "Bullet3Common/b3Vector3.h" +#include "b3SapAabb.h" +#include "Bullet3Common/shared/b3Int2.h" +#include "Bullet3Common/shared/b3Int4.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3OpenCLArray.h" + +class b3GpuBroadphaseInterface +{ +public: + + typedef class b3GpuBroadphaseInterface* (CreateFunc)(cl_context ctx,cl_device_id device, cl_command_queue q); + + virtual ~b3GpuBroadphaseInterface() + { + } + + virtual void createProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr , int collisionFilterGroup, int collisionFilterMask)=0; + virtual void createLargeProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr , int collisionFilterGroup, int collisionFilterMask)=0; + + virtual void calculateOverlappingPairs(int maxPairs)=0; + virtual void calculateOverlappingPairsHost(int maxPairs)=0; + + //call writeAabbsToGpu after done making all changes (createProxy etc) + virtual void writeAabbsToGpu()=0; + + virtual cl_mem getAabbBufferWS()=0; + virtual int getNumOverlap()=0; + virtual cl_mem getOverlappingPairBuffer()=0; + + virtual b3OpenCLArray& getAllAabbsGPU()=0; + virtual b3AlignedObjectArray& getAllAabbsCPU()=0; + + virtual b3OpenCLArray& getOverlappingPairsGPU() = 0; + virtual b3OpenCLArray& getSmallAabbIndicesGPU() = 0; + virtual b3OpenCLArray& getLargeAabbIndicesGPU() = 0; + +}; + +#endif //B3_GPU_BROADPHASE_INTERFACE_H diff --git a/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.cpp b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.cpp new file mode 100644 index 000000000000..74d0c8056cc6 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.cpp @@ -0,0 +1,385 @@ + +#include "b3GpuGridBroadphase.h" +#include "Bullet3Geometry/b3AabbUtil.h" +#include "kernels/gridBroadphaseKernels.h" +#include "kernels/sapKernels.h" +//#include "kernels/gridBroadphase.cl" + + +#include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.h" + + + +#define B3_BROADPHASE_SAP_PATH "src/Bullet3OpenCL/BroadphaseCollision/kernels/sap.cl" +#define B3_GRID_BROADPHASE_PATH "src/Bullet3OpenCL/BroadphaseCollision/kernels/gridBroadphase.cl" + +cl_kernel kCalcHashAABB; +cl_kernel kClearCellStart; +cl_kernel kFindCellStart; +cl_kernel kFindOverlappingPairs; +cl_kernel m_copyAabbsKernel; +cl_kernel m_sap2Kernel; + + + + + +//int maxPairsPerBody = 64; +int maxBodiesPerCell = 256;//?? + +b3GpuGridBroadphase::b3GpuGridBroadphase(cl_context ctx,cl_device_id device, cl_command_queue q ) +:m_context(ctx), +m_device(device), +m_queue(q), +m_allAabbsGPU1(ctx,q), +m_smallAabbsMappingGPU(ctx,q), +m_largeAabbsMappingGPU(ctx,q), +m_gpuPairs(ctx,q), + +m_hashGpu(ctx,q), + +m_cellStartGpu(ctx,q), +m_paramsGPU(ctx,q) +{ + + + b3Vector3 gridSize = b3MakeVector3(3,3,3); + b3Vector3 invGridSize = b3MakeVector3(1.f/gridSize[0],1.f/gridSize[1],1.f/gridSize[2]); + + m_paramsCPU.m_gridSize[0] = 128; + m_paramsCPU.m_gridSize[1] = 128; + m_paramsCPU.m_gridSize[2] = 128; + m_paramsCPU.m_gridSize[3] = maxBodiesPerCell; + m_paramsCPU.setMaxBodiesPerCell(maxBodiesPerCell); + m_paramsCPU.m_invCellSize[0] = invGridSize[0]; + m_paramsCPU.m_invCellSize[1] = invGridSize[1]; + m_paramsCPU.m_invCellSize[2] = invGridSize[2]; + m_paramsCPU.m_invCellSize[3] = 0.f; + m_paramsGPU.push_back(m_paramsCPU); + + cl_int errNum=0; + + { + const char* sapSrc = sapCL; + cl_program sapProg = b3OpenCLUtils::compileCLProgramFromString(m_context,m_device,sapSrc,&errNum,"",B3_BROADPHASE_SAP_PATH); + b3Assert(errNum==CL_SUCCESS); + m_copyAabbsKernel= b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,sapSrc, "copyAabbsKernel",&errNum,sapProg ); + m_sap2Kernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,sapSrc, "computePairsKernelTwoArrays",&errNum,sapProg ); + b3Assert(errNum==CL_SUCCESS); + } + + { + + cl_program gridProg = b3OpenCLUtils::compileCLProgramFromString(m_context,m_device,gridBroadphaseCL,&errNum,"",B3_GRID_BROADPHASE_PATH); + b3Assert(errNum==CL_SUCCESS); + + kCalcHashAABB = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,gridBroadphaseCL, "kCalcHashAABB",&errNum,gridProg); + b3Assert(errNum==CL_SUCCESS); + + kClearCellStart = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,gridBroadphaseCL, "kClearCellStart",&errNum,gridProg); + b3Assert(errNum==CL_SUCCESS); + + kFindCellStart = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,gridBroadphaseCL, "kFindCellStart",&errNum,gridProg); + b3Assert(errNum==CL_SUCCESS); + + + kFindOverlappingPairs = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,gridBroadphaseCL, "kFindOverlappingPairs",&errNum,gridProg); + b3Assert(errNum==CL_SUCCESS); + + + + + } + + m_sorter = new b3RadixSort32CL(m_context,m_device,m_queue); + +} +b3GpuGridBroadphase::~b3GpuGridBroadphase() +{ + clReleaseKernel( kCalcHashAABB); + clReleaseKernel( kClearCellStart); + clReleaseKernel( kFindCellStart); + clReleaseKernel( kFindOverlappingPairs); + clReleaseKernel( m_sap2Kernel); + clReleaseKernel( m_copyAabbsKernel); + + + + delete m_sorter; +} + + + +void b3GpuGridBroadphase::createProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr , int collisionFilterGroup, int collisionFilterMask) +{ + b3SapAabb aabb; + aabb.m_minVec = aabbMin; + aabb.m_maxVec = aabbMax; + aabb.m_minIndices[3] = userPtr; + aabb.m_signedMaxIndices[3] = m_allAabbsCPU1.size();//NOT userPtr; + m_smallAabbsMappingCPU.push_back(m_allAabbsCPU1.size()); + + m_allAabbsCPU1.push_back(aabb); + +} +void b3GpuGridBroadphase::createLargeProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr , int collisionFilterGroup, int collisionFilterMask) +{ + b3SapAabb aabb; + aabb.m_minVec = aabbMin; + aabb.m_maxVec = aabbMax; + aabb.m_minIndices[3] = userPtr; + aabb.m_signedMaxIndices[3] = m_allAabbsCPU1.size();//NOT userPtr; + m_largeAabbsMappingCPU.push_back(m_allAabbsCPU1.size()); + + m_allAabbsCPU1.push_back(aabb); +} + +void b3GpuGridBroadphase::calculateOverlappingPairs(int maxPairs) +{ + B3_PROFILE("b3GpuGridBroadphase::calculateOverlappingPairs"); + + + if (0) + { + calculateOverlappingPairsHost(maxPairs); + /* + b3AlignedObjectArray cpuPairs; + m_gpuPairs.copyToHost(cpuPairs); + printf("host m_gpuPairs.size()=%d\n",m_gpuPairs.size()); + for (int i=0;i pairCount(m_context,m_queue); + pairCount.push_back(0); + m_gpuPairs.resize(maxPairs);//numSmallAabbs*maxPairsPerBody); + + { + int numLargeAabbs = m_largeAabbsMappingGPU.size(); + if (numLargeAabbs && numSmallAabbs) + { + B3_PROFILE("sap2Kernel"); + b3BufferInfoCL bInfo[] = { + b3BufferInfoCL( m_allAabbsGPU1.getBufferCL() ), + b3BufferInfoCL( m_largeAabbsMappingGPU.getBufferCL() ), + b3BufferInfoCL( m_smallAabbsMappingGPU.getBufferCL() ), + b3BufferInfoCL( m_gpuPairs.getBufferCL() ), + b3BufferInfoCL(pairCount.getBufferCL())}; + b3LauncherCL launcher(m_queue, m_sap2Kernel,"m_sap2Kernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( numLargeAabbs ); + launcher.setConst( numSmallAabbs); + launcher.setConst( 0 );//axis is not used + launcher.setConst( maxPairs ); + //@todo: use actual maximum work item sizes of the device instead of hardcoded values + launcher.launch2D( numLargeAabbs, numSmallAabbs,4,64); + + int numPairs = pairCount.at(0); + + if (numPairs >maxPairs) + { + b3Error("Error running out of pairs: numPairs = %d, maxPairs = %d.\n", numPairs, maxPairs); + numPairs =maxPairs; + } + } + } + + + + + if (numSmallAabbs) + { + B3_PROFILE("gridKernel"); + m_hashGpu.resize(numSmallAabbs); + { + B3_PROFILE("kCalcHashAABB"); + b3LauncherCL launch(m_queue,kCalcHashAABB,"kCalcHashAABB"); + launch.setConst(numSmallAabbs); + launch.setBuffer(m_allAabbsGPU1.getBufferCL()); + launch.setBuffer(m_smallAabbsMappingGPU.getBufferCL()); + launch.setBuffer(m_hashGpu.getBufferCL()); + launch.setBuffer(this->m_paramsGPU.getBufferCL()); + launch.launch1D(numSmallAabbs); + } + + m_sorter->execute(m_hashGpu); + + int numCells = this->m_paramsCPU.m_gridSize[0]*this->m_paramsCPU.m_gridSize[1]*this->m_paramsCPU.m_gridSize[2]; + m_cellStartGpu.resize(numCells); + //b3AlignedObjectArray cellStartCpu; + + + { + B3_PROFILE("kClearCellStart"); + b3LauncherCL launch(m_queue,kClearCellStart,"kClearCellStart"); + launch.setConst(numCells); + launch.setBuffer(m_cellStartGpu.getBufferCL()); + launch.launch1D(numCells); + //m_cellStartGpu.copyToHost(cellStartCpu); + //printf("??\n"); + + } + + + { + B3_PROFILE("kFindCellStart"); + b3LauncherCL launch(m_queue,kFindCellStart,"kFindCellStart"); + launch.setConst(numSmallAabbs); + launch.setBuffer(m_hashGpu.getBufferCL()); + launch.setBuffer(m_cellStartGpu.getBufferCL()); + launch.launch1D(numSmallAabbs); + //m_cellStartGpu.copyToHost(cellStartCpu); + //printf("??\n"); + + } + + { + B3_PROFILE("kFindOverlappingPairs"); + + + b3LauncherCL launch(m_queue,kFindOverlappingPairs,"kFindOverlappingPairs"); + launch.setConst(numSmallAabbs); + launch.setBuffer(m_allAabbsGPU1.getBufferCL()); + launch.setBuffer(m_smallAabbsMappingGPU.getBufferCL()); + launch.setBuffer(m_hashGpu.getBufferCL()); + launch.setBuffer(m_cellStartGpu.getBufferCL()); + + launch.setBuffer(m_paramsGPU.getBufferCL()); + //launch.setBuffer(0); + launch.setBuffer(pairCount.getBufferCL()); + launch.setBuffer(m_gpuPairs.getBufferCL()); + + launch.setConst(maxPairs); + launch.launch1D(numSmallAabbs); + + + int numPairs = pairCount.at(0); + if (numPairs >maxPairs) + { + b3Error("Error running out of pairs: numPairs = %d, maxPairs = %d.\n", numPairs, maxPairs); + numPairs =maxPairs; + } + + m_gpuPairs.resize(numPairs); + + if (0) + { + b3AlignedObjectArray pairsCpu; + m_gpuPairs.copyToHost(pairsCpu); + + int sz = m_gpuPairs.size(); + printf("m_gpuPairs.size()=%d\n",sz); + for (int i=0;im_allAabbsGPU1.getBufferCL(); +} +int b3GpuGridBroadphase::getNumOverlap() +{ + return m_gpuPairs.size(); +} +cl_mem b3GpuGridBroadphase::getOverlappingPairBuffer() +{ + return m_gpuPairs.getBufferCL(); +} + +b3OpenCLArray& b3GpuGridBroadphase::getAllAabbsGPU() +{ + return m_allAabbsGPU1; +} + +b3AlignedObjectArray& b3GpuGridBroadphase::getAllAabbsCPU() +{ + return m_allAabbsCPU1; +} + +b3OpenCLArray& b3GpuGridBroadphase::getOverlappingPairsGPU() +{ + return m_gpuPairs; +} +b3OpenCLArray& b3GpuGridBroadphase::getSmallAabbIndicesGPU() +{ + return m_smallAabbsMappingGPU; +} +b3OpenCLArray& b3GpuGridBroadphase::getLargeAabbIndicesGPU() +{ + return m_largeAabbsMappingGPU; +} + diff --git a/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.h b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.h new file mode 100644 index 000000000000..ec18c9f7165a --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.h @@ -0,0 +1,88 @@ +#ifndef B3_GPU_GRID_BROADPHASE_H +#define B3_GPU_GRID_BROADPHASE_H + +#include "b3GpuBroadphaseInterface.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3RadixSort32CL.h" + +struct b3ParamsGridBroadphaseCL +{ + + float m_invCellSize[4]; + int m_gridSize[4]; + + int getMaxBodiesPerCell() const + { + return m_gridSize[3]; + } + + void setMaxBodiesPerCell(int maxOverlap) + { + m_gridSize[3] = maxOverlap; + } +}; + + +class b3GpuGridBroadphase : public b3GpuBroadphaseInterface +{ +protected: + cl_context m_context; + cl_device_id m_device; + cl_command_queue m_queue; + + b3OpenCLArray m_allAabbsGPU1; + b3AlignedObjectArray m_allAabbsCPU1; + + b3OpenCLArray m_smallAabbsMappingGPU; + b3AlignedObjectArray m_smallAabbsMappingCPU; + + b3OpenCLArray m_largeAabbsMappingGPU; + b3AlignedObjectArray m_largeAabbsMappingCPU; + + b3AlignedObjectArray m_hostPairs; + b3OpenCLArray m_gpuPairs; + + b3OpenCLArray m_hashGpu; + b3OpenCLArray m_cellStartGpu; + + + b3ParamsGridBroadphaseCL m_paramsCPU; + b3OpenCLArray m_paramsGPU; + + class b3RadixSort32CL* m_sorter; + +public: + + b3GpuGridBroadphase(cl_context ctx,cl_device_id device, cl_command_queue q ); + virtual ~b3GpuGridBroadphase(); + + static b3GpuBroadphaseInterface* CreateFunc(cl_context ctx,cl_device_id device, cl_command_queue q) + { + return new b3GpuGridBroadphase(ctx,device,q); + } + + + + + virtual void createProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr , int collisionFilterGroup, int collisionFilterMask); + virtual void createLargeProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr , int collisionFilterGroup, int collisionFilterMask); + + virtual void calculateOverlappingPairs(int maxPairs); + virtual void calculateOverlappingPairsHost(int maxPairs); + + //call writeAabbsToGpu after done making all changes (createProxy etc) + virtual void writeAabbsToGpu(); + + virtual cl_mem getAabbBufferWS(); + virtual int getNumOverlap(); + virtual cl_mem getOverlappingPairBuffer(); + + virtual b3OpenCLArray& getAllAabbsGPU(); + virtual b3AlignedObjectArray& getAllAabbsCPU(); + + virtual b3OpenCLArray& getOverlappingPairsGPU(); + virtual b3OpenCLArray& getSmallAabbIndicesGPU(); + virtual b3OpenCLArray& getLargeAabbIndicesGPU(); + +}; + +#endif //B3_GPU_GRID_BROADPHASE_H \ No newline at end of file diff --git a/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp new file mode 100644 index 000000000000..641df9eb128e --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp @@ -0,0 +1,577 @@ +/* +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. +*/ +//Initial Author Jackson Lee, 2014 + +#include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.h" + +#include "b3GpuParallelLinearBvh.h" + +b3GpuParallelLinearBvh::b3GpuParallelLinearBvh(cl_context context, cl_device_id device, cl_command_queue queue) : + m_queue(queue), + m_radixSorter(context, device, queue), + + m_rootNodeIndex(context, queue), + m_maxDistanceFromRoot(context, queue), + m_temp(context, queue), + + m_internalNodeAabbs(context, queue), + m_internalNodeLeafIndexRanges(context, queue), + m_internalNodeChildNodes(context, queue), + m_internalNodeParentNodes(context, queue), + + m_commonPrefixes(context, queue), + m_commonPrefixLengths(context, queue), + m_distanceFromRoot(context, queue), + + m_leafNodeParentNodes(context, queue), + m_mortonCodesAndAabbIndicies(context, queue), + m_mergedAabb(context, queue), + m_leafNodeAabbs(context, queue), + + m_largeAabbs(context, queue) +{ + m_rootNodeIndex.resize(1); + m_maxDistanceFromRoot.resize(1); + m_temp.resize(1); + + // + const char CL_PROGRAM_PATH[] = "src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl"; + + const char* kernelSource = parallelLinearBvhCL; //parallelLinearBvhCL.h + cl_int error; + char* additionalMacros = 0; + m_parallelLinearBvhProgram = b3OpenCLUtils::compileCLProgramFromString(context, device, kernelSource, &error, additionalMacros, CL_PROGRAM_PATH); + b3Assert(m_parallelLinearBvhProgram); + + m_separateAabbsKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "separateAabbs", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_separateAabbsKernel); + m_findAllNodesMergedAabbKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "findAllNodesMergedAabb", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_findAllNodesMergedAabbKernel); + m_assignMortonCodesAndAabbIndiciesKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "assignMortonCodesAndAabbIndicies", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_assignMortonCodesAndAabbIndiciesKernel); + + m_computeAdjacentPairCommonPrefixKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "computeAdjacentPairCommonPrefix", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_computeAdjacentPairCommonPrefixKernel); + m_buildBinaryRadixTreeLeafNodesKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "buildBinaryRadixTreeLeafNodes", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_buildBinaryRadixTreeLeafNodesKernel); + m_buildBinaryRadixTreeInternalNodesKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "buildBinaryRadixTreeInternalNodes", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_buildBinaryRadixTreeInternalNodesKernel); + m_findDistanceFromRootKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "findDistanceFromRoot", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_findDistanceFromRootKernel); + m_buildBinaryRadixTreeAabbsRecursiveKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "buildBinaryRadixTreeAabbsRecursive", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_buildBinaryRadixTreeAabbsRecursiveKernel); + + m_findLeafIndexRangesKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "findLeafIndexRanges", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_findLeafIndexRangesKernel); + + m_plbvhCalculateOverlappingPairsKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "plbvhCalculateOverlappingPairs", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_plbvhCalculateOverlappingPairsKernel); + m_plbvhRayTraverseKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "plbvhRayTraverse", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_plbvhRayTraverseKernel); + m_plbvhLargeAabbAabbTestKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "plbvhLargeAabbAabbTest", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_plbvhLargeAabbAabbTestKernel); + m_plbvhLargeAabbRayTestKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "plbvhLargeAabbRayTest", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_plbvhLargeAabbRayTestKernel); +} + +b3GpuParallelLinearBvh::~b3GpuParallelLinearBvh() +{ + clReleaseKernel(m_separateAabbsKernel); + clReleaseKernel(m_findAllNodesMergedAabbKernel); + clReleaseKernel(m_assignMortonCodesAndAabbIndiciesKernel); + + clReleaseKernel(m_computeAdjacentPairCommonPrefixKernel); + clReleaseKernel(m_buildBinaryRadixTreeLeafNodesKernel); + clReleaseKernel(m_buildBinaryRadixTreeInternalNodesKernel); + clReleaseKernel(m_findDistanceFromRootKernel); + clReleaseKernel(m_buildBinaryRadixTreeAabbsRecursiveKernel); + + clReleaseKernel(m_findLeafIndexRangesKernel); + + clReleaseKernel(m_plbvhCalculateOverlappingPairsKernel); + clReleaseKernel(m_plbvhRayTraverseKernel); + clReleaseKernel(m_plbvhLargeAabbAabbTestKernel); + clReleaseKernel(m_plbvhLargeAabbRayTestKernel); + + clReleaseProgram(m_parallelLinearBvhProgram); +} + +void b3GpuParallelLinearBvh::build(const b3OpenCLArray& worldSpaceAabbs, const b3OpenCLArray& smallAabbIndices, + const b3OpenCLArray& largeAabbIndices) +{ + B3_PROFILE("b3ParallelLinearBvh::build()"); + + int numLargeAabbs = largeAabbIndices.size(); + int numSmallAabbs = smallAabbIndices.size(); + + //Since all AABBs(both large and small) are input as a contiguous array, + //with 2 additional arrays used to indicate the indices of large and small AABBs, + //it is necessary to separate the AABBs so that the large AABBs will not degrade the quality of the BVH. + { + B3_PROFILE("Separate large and small AABBs"); + + m_largeAabbs.resize(numLargeAabbs); + m_leafNodeAabbs.resize(numSmallAabbs); + + //Write large AABBs into m_largeAabbs + { + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( worldSpaceAabbs.getBufferCL() ), + b3BufferInfoCL( largeAabbIndices.getBufferCL() ), + + b3BufferInfoCL( m_largeAabbs.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_separateAabbsKernel, "m_separateAabbsKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numLargeAabbs); + + launcher.launch1D(numLargeAabbs); + } + + //Write small AABBs into m_leafNodeAabbs + { + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( worldSpaceAabbs.getBufferCL() ), + b3BufferInfoCL( smallAabbIndices.getBufferCL() ), + + b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_separateAabbsKernel, "m_separateAabbsKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numSmallAabbs); + + launcher.launch1D(numSmallAabbs); + } + + clFinish(m_queue); + } + + // + int numLeaves = numSmallAabbs; //Number of leaves in the BVH == Number of rigid bodies with small AABBs + int numInternalNodes = numLeaves - 1; + + if(numLeaves < 2) + { + //Number of leaf nodes is checked in calculateOverlappingPairs() and testRaysAgainstBvhAabbs(), + //so it does not matter if numLeaves == 0 and rootNodeIndex == -1 + int rootNodeIndex = numLeaves - 1; + m_rootNodeIndex.copyFromHostPointer(&rootNodeIndex, 1); + + //Since the AABBs need to be rearranged(sorted) for the BVH construction algorithm, + //m_mortonCodesAndAabbIndicies.m_value is used to map a sorted AABB index to the unsorted AABB index + //instead of directly moving the AABBs. It needs to be set for the ray cast traversal kernel to work. + //( m_mortonCodesAndAabbIndicies[].m_value == unsorted index == index of m_leafNodeAabbs ) + if(numLeaves == 1) + { + b3SortData leaf; + leaf.m_value = 0; //1 leaf so index is always 0; leaf.m_key does not need to be set + + m_mortonCodesAndAabbIndicies.resize(1); + m_mortonCodesAndAabbIndicies.copyFromHostPointer(&leaf, 1); + } + + return; + } + + // + { + m_internalNodeAabbs.resize(numInternalNodes); + m_internalNodeLeafIndexRanges.resize(numInternalNodes); + m_internalNodeChildNodes.resize(numInternalNodes); + m_internalNodeParentNodes.resize(numInternalNodes); + + m_commonPrefixes.resize(numInternalNodes); + m_commonPrefixLengths.resize(numInternalNodes); + m_distanceFromRoot.resize(numInternalNodes); + + m_leafNodeParentNodes.resize(numLeaves); + m_mortonCodesAndAabbIndicies.resize(numLeaves); + m_mergedAabb.resize(numLeaves); + } + + //Find the merged AABB of all small AABBs; this is used to define the size of + //each cell in the virtual grid for the next kernel(2^10 cells in each dimension). + { + B3_PROFILE("Find AABB of merged nodes"); + + m_mergedAabb.copyFromOpenCLArray(m_leafNodeAabbs); //Need to make a copy since the kernel modifies the array + + for(int numAabbsNeedingMerge = numLeaves; numAabbsNeedingMerge >= 2; + numAabbsNeedingMerge = numAabbsNeedingMerge / 2 + numAabbsNeedingMerge % 2) + { + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_mergedAabb.getBufferCL() ) //Resulting AABB is stored in m_mergedAabb[0] + }; + + b3LauncherCL launcher(m_queue, m_findAllNodesMergedAabbKernel, "m_findAllNodesMergedAabbKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numAabbsNeedingMerge); + + launcher.launch1D(numAabbsNeedingMerge); + } + + clFinish(m_queue); + } + + //Insert the center of the AABBs into a virtual grid, + //then convert the discrete grid coordinates into a morton code + //For each element in m_mortonCodesAndAabbIndicies, set + // m_key == morton code (value to sort by) + // m_value == small AABB index + { + B3_PROFILE("Assign morton codes"); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), + b3BufferInfoCL( m_mergedAabb.getBufferCL() ), + b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_assignMortonCodesAndAabbIndiciesKernel, "m_assignMortonCodesAndAabbIndiciesKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numLeaves); + + launcher.launch1D(numLeaves); + clFinish(m_queue); + } + + // + { + B3_PROFILE("Sort leaves by morton codes"); + + m_radixSorter.execute(m_mortonCodesAndAabbIndicies); + clFinish(m_queue); + } + + // + constructBinaryRadixTree(); + + + //Since it is a sorted binary radix tree, each internal node contains a contiguous subset of leaf node indices. + //The root node contains leaf node indices in the range [0, numLeafNodes - 1]. + //The child nodes of each node split their parent's index range into 2 contiguous halves. + // + //For example, if the root has indices [0, 31], its children might partition that range into [0, 11] and [12, 31]. + //The next level in the tree could then split those ranges into [0, 2], [3, 11], [12, 22], and [23, 31]. + // + //This property can be used for optimizing calculateOverlappingPairs(), to avoid testing each AABB pair twice + { + B3_PROFILE("m_findLeafIndexRangesKernel"); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), + b3BufferInfoCL( m_internalNodeLeafIndexRanges.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_findLeafIndexRangesKernel, "m_findLeafIndexRangesKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numInternalNodes); + + launcher.launch1D(numInternalNodes); + clFinish(m_queue); + } +} + +void b3GpuParallelLinearBvh::calculateOverlappingPairs(b3OpenCLArray& out_overlappingPairs) +{ + int maxPairs = out_overlappingPairs.size(); + b3OpenCLArray& numPairsGpu = m_temp; + + int reset = 0; + numPairsGpu.copyFromHostPointer(&reset, 1); + + // + if( m_leafNodeAabbs.size() > 1 ) + { + B3_PROFILE("PLBVH small-small AABB test"); + + int numQueryAabbs = m_leafNodeAabbs.size(); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), + + b3BufferInfoCL( m_rootNodeIndex.getBufferCL() ), + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), + b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ), + b3BufferInfoCL( m_internalNodeLeafIndexRanges.getBufferCL() ), + b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), + + b3BufferInfoCL( numPairsGpu.getBufferCL() ), + b3BufferInfoCL( out_overlappingPairs.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_plbvhCalculateOverlappingPairsKernel, "m_plbvhCalculateOverlappingPairsKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(maxPairs); + launcher.setConst(numQueryAabbs); + + launcher.launch1D(numQueryAabbs); + clFinish(m_queue); + } + + int numLargeAabbRigids = m_largeAabbs.size(); + if( numLargeAabbRigids > 0 && m_leafNodeAabbs.size() > 0 ) + { + B3_PROFILE("PLBVH large-small AABB test"); + + int numQueryAabbs = m_leafNodeAabbs.size(); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), + b3BufferInfoCL( m_largeAabbs.getBufferCL() ), + + b3BufferInfoCL( numPairsGpu.getBufferCL() ), + b3BufferInfoCL( out_overlappingPairs.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_plbvhLargeAabbAabbTestKernel, "m_plbvhLargeAabbAabbTestKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(maxPairs); + launcher.setConst(numLargeAabbRigids); + launcher.setConst(numQueryAabbs); + + launcher.launch1D(numQueryAabbs); + clFinish(m_queue); + } + + + // + int numPairs = -1; + numPairsGpu.copyToHostPointer(&numPairs, 1); + if(numPairs > maxPairs) + { + b3Error("Error running out of pairs: numPairs = %d, maxPairs = %d.\n", numPairs, maxPairs); + numPairs = maxPairs; + numPairsGpu.copyFromHostPointer(&maxPairs, 1); + } + + out_overlappingPairs.resize(numPairs); +} + + +void b3GpuParallelLinearBvh::testRaysAgainstBvhAabbs(const b3OpenCLArray& rays, + b3OpenCLArray& out_numRayRigidPairs, b3OpenCLArray& out_rayRigidPairs) +{ + B3_PROFILE("PLBVH testRaysAgainstBvhAabbs()"); + + int numRays = rays.size(); + int maxRayRigidPairs = out_rayRigidPairs.size(); + + int reset = 0; + out_numRayRigidPairs.copyFromHostPointer(&reset, 1); + + // + if( m_leafNodeAabbs.size() > 0 ) + { + B3_PROFILE("PLBVH ray test small AABB"); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), + + b3BufferInfoCL( m_rootNodeIndex.getBufferCL() ), + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), + b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ), + b3BufferInfoCL( m_internalNodeLeafIndexRanges.getBufferCL() ), + b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), + + b3BufferInfoCL( rays.getBufferCL() ), + + b3BufferInfoCL( out_numRayRigidPairs.getBufferCL() ), + b3BufferInfoCL( out_rayRigidPairs.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_plbvhRayTraverseKernel, "m_plbvhRayTraverseKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(maxRayRigidPairs); + launcher.setConst(numRays); + + launcher.launch1D(numRays); + clFinish(m_queue); + } + + int numLargeAabbRigids = m_largeAabbs.size(); + if(numLargeAabbRigids > 0) + { + B3_PROFILE("PLBVH ray test large AABB"); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_largeAabbs.getBufferCL() ), + b3BufferInfoCL( rays.getBufferCL() ), + + b3BufferInfoCL( out_numRayRigidPairs.getBufferCL() ), + b3BufferInfoCL( out_rayRigidPairs.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_plbvhLargeAabbRayTestKernel, "m_plbvhLargeAabbRayTestKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numLargeAabbRigids); + launcher.setConst(maxRayRigidPairs); + launcher.setConst(numRays); + + launcher.launch1D(numRays); + clFinish(m_queue); + } + + // + int numRayRigidPairs = -1; + out_numRayRigidPairs.copyToHostPointer(&numRayRigidPairs, 1); + + if(numRayRigidPairs > maxRayRigidPairs) + b3Error("Error running out of rayRigid pairs: numRayRigidPairs = %d, maxRayRigidPairs = %d.\n", numRayRigidPairs, maxRayRigidPairs); + +} + +void b3GpuParallelLinearBvh::constructBinaryRadixTree() +{ + B3_PROFILE("b3GpuParallelLinearBvh::constructBinaryRadixTree()"); + + int numLeaves = m_leafNodeAabbs.size(); + int numInternalNodes = numLeaves - 1; + + //Each internal node is placed in between 2 leaf nodes. + //By using this arrangement and computing the common prefix between + //these 2 adjacent leaf nodes, it is possible to quickly construct a binary radix tree. + { + B3_PROFILE("m_computeAdjacentPairCommonPrefixKernel"); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), + b3BufferInfoCL( m_commonPrefixes.getBufferCL() ), + b3BufferInfoCL( m_commonPrefixLengths.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_computeAdjacentPairCommonPrefixKernel, "m_computeAdjacentPairCommonPrefixKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numInternalNodes); + + launcher.launch1D(numInternalNodes); + clFinish(m_queue); + } + + //For each leaf node, select its parent node by + //comparing the 2 nearest internal nodes and assign child node indices + { + B3_PROFILE("m_buildBinaryRadixTreeLeafNodesKernel"); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_commonPrefixLengths.getBufferCL() ), + b3BufferInfoCL( m_leafNodeParentNodes.getBufferCL() ), + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_buildBinaryRadixTreeLeafNodesKernel, "m_buildBinaryRadixTreeLeafNodesKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numLeaves); + + launcher.launch1D(numLeaves); + clFinish(m_queue); + } + + //For each internal node, perform 2 binary searches among the other internal nodes + //to its left and right to find its potential parent nodes and assign child node indices + { + B3_PROFILE("m_buildBinaryRadixTreeInternalNodesKernel"); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_commonPrefixes.getBufferCL() ), + b3BufferInfoCL( m_commonPrefixLengths.getBufferCL() ), + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), + b3BufferInfoCL( m_internalNodeParentNodes.getBufferCL() ), + b3BufferInfoCL( m_rootNodeIndex.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_buildBinaryRadixTreeInternalNodesKernel, "m_buildBinaryRadixTreeInternalNodesKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numInternalNodes); + + launcher.launch1D(numInternalNodes); + clFinish(m_queue); + } + + //Find the number of nodes seperating each internal node and the root node + //so that the AABBs can be set using the next kernel. + //Also determine the maximum number of nodes separating an internal node and the root node. + { + B3_PROFILE("m_findDistanceFromRootKernel"); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_rootNodeIndex.getBufferCL() ), + b3BufferInfoCL( m_internalNodeParentNodes.getBufferCL() ), + b3BufferInfoCL( m_maxDistanceFromRoot.getBufferCL() ), + b3BufferInfoCL( m_distanceFromRoot.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_findDistanceFromRootKernel, "m_findDistanceFromRootKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numInternalNodes); + + launcher.launch1D(numInternalNodes); + clFinish(m_queue); + } + + //Starting from the internal nodes nearest to the leaf nodes, recursively move up + //the tree towards the root to set the AABBs of each internal node; each internal node + //checks its children and merges their AABBs + { + B3_PROFILE("m_buildBinaryRadixTreeAabbsRecursiveKernel"); + + int maxDistanceFromRoot = -1; + { + B3_PROFILE("copy maxDistanceFromRoot to CPU"); + m_maxDistanceFromRoot.copyToHostPointer(&maxDistanceFromRoot, 1); + clFinish(m_queue); + } + + for(int distanceFromRoot = maxDistanceFromRoot; distanceFromRoot >= 0; --distanceFromRoot) + { + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_distanceFromRoot.getBufferCL() ), + b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), + b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), + b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_buildBinaryRadixTreeAabbsRecursiveKernel, "m_buildBinaryRadixTreeAabbsRecursiveKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(maxDistanceFromRoot); + launcher.setConst(distanceFromRoot); + launcher.setConst(numInternalNodes); + + //It may seem inefficent to launch a thread for each internal node when a + //much smaller number of nodes is actually processed, but this is actually + //faster than determining the exact nodes that are ready to merge their child AABBs. + launcher.launch1D(numInternalNodes); + } + + clFinish(m_queue); + } +} + + \ No newline at end of file diff --git a/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h new file mode 100644 index 000000000000..effe617b7b8c --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h @@ -0,0 +1,125 @@ +/* +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. +*/ +//Initial Author Jackson Lee, 2014 + +#ifndef B3_GPU_PARALLEL_LINEAR_BVH_H +#define B3_GPU_PARALLEL_LINEAR_BVH_H + +//#include "Bullet3Collision/BroadPhaseCollision/shared/b3Aabb.h" +#include "Bullet3OpenCL/BroadphaseCollision/b3SapAabb.h" +#include "Bullet3Common/shared/b3Int2.h" +#include "Bullet3Common/shared/b3Int4.h" +#include "Bullet3Collision/NarrowPhaseCollision/b3RaycastInfo.h" + +#include "Bullet3OpenCL/ParallelPrimitives/b3FillCL.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3RadixSort32CL.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3PrefixScanCL.h" + +#include "Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h" + +#define b3Int64 cl_long + +///@brief GPU Parallel Linearized Bounding Volume Heirarchy(LBVH) that is reconstructed every frame +///@remarks +///See presentation in docs/b3GpuParallelLinearBvh.pdf for algorithm details. +///@par +///Related papers: \n +///"Fast BVH Construction on GPUs" [Lauterbach et al. 2009] \n +///"Maximizing Parallelism in the Construction of BVHs, Octrees, and k-d trees" [Karras 2012] \n +///@par +///The basic algorithm for building the BVH as presented in [Lauterbach et al. 2009] consists of 4 stages: +/// - [fully parallel] Assign morton codes for each AABB using its center (after quantizing the AABB centers into a virtual grid) +/// - [fully parallel] Sort morton codes +/// - [somewhat parallel] Build binary radix tree (assign parent/child pointers for internal nodes of the BVH) +/// - [somewhat parallel] Set internal node AABBs +///@par +///[Karras 2012] improves on the algorithm by introducing fully parallel methods for the last 2 stages. +///The BVH implementation here shares many concepts with [Karras 2012], but a different method is used for constructing the tree. +///Instead of searching for the child nodes of each internal node, we search for the parent node of each node. +///Additionally, a non-atomic traversal that starts from the leaf nodes and moves towards the root node is used to set the AABBs. +class b3GpuParallelLinearBvh +{ + cl_command_queue m_queue; + + cl_program m_parallelLinearBvhProgram; + + cl_kernel m_separateAabbsKernel; + cl_kernel m_findAllNodesMergedAabbKernel; + cl_kernel m_assignMortonCodesAndAabbIndiciesKernel; + + //Binary radix tree construction kernels + cl_kernel m_computeAdjacentPairCommonPrefixKernel; + cl_kernel m_buildBinaryRadixTreeLeafNodesKernel; + cl_kernel m_buildBinaryRadixTreeInternalNodesKernel; + cl_kernel m_findDistanceFromRootKernel; + cl_kernel m_buildBinaryRadixTreeAabbsRecursiveKernel; + + cl_kernel m_findLeafIndexRangesKernel; + + //Traversal kernels + cl_kernel m_plbvhCalculateOverlappingPairsKernel; + cl_kernel m_plbvhRayTraverseKernel; + cl_kernel m_plbvhLargeAabbAabbTestKernel; + cl_kernel m_plbvhLargeAabbRayTestKernel; + + b3RadixSort32CL m_radixSorter; + + //1 element + b3OpenCLArray m_rootNodeIndex; //Most significant bit(0x80000000) is set to indicate internal node + b3OpenCLArray m_maxDistanceFromRoot; //Max number of internal nodes between an internal node and the root node + b3OpenCLArray m_temp; //Used to hold the number of pairs in calculateOverlappingPairs() + + //1 element per internal node (number_of_internal_nodes == number_of_leaves - 1) + b3OpenCLArray m_internalNodeAabbs; + b3OpenCLArray m_internalNodeLeafIndexRanges; //x == min leaf index, y == max leaf index + b3OpenCLArray m_internalNodeChildNodes; //x == left child, y == right child; msb(0x80000000) is set to indicate internal node + b3OpenCLArray m_internalNodeParentNodes; //For parent node index, msb(0x80000000) is not set since it is always internal + + //1 element per internal node; for binary radix tree construction + b3OpenCLArray m_commonPrefixes; + b3OpenCLArray m_commonPrefixLengths; + b3OpenCLArray m_distanceFromRoot; //Number of internal nodes between this node and the root + + //1 element per leaf node (leaf nodes only include small AABBs) + b3OpenCLArray m_leafNodeParentNodes; //For parent node index, msb(0x80000000) is not set since it is always internal + b3OpenCLArray m_mortonCodesAndAabbIndicies; //m_key == morton code, m_value == aabb index in m_leafNodeAabbs + b3OpenCLArray m_mergedAabb; //m_mergedAabb[0] contains the merged AABB of all leaf nodes + b3OpenCLArray m_leafNodeAabbs; //Contains only small AABBs + + //1 element per large AABB, which is not stored in the BVH + b3OpenCLArray m_largeAabbs; + +public: + b3GpuParallelLinearBvh(cl_context context, cl_device_id device, cl_command_queue queue); + virtual ~b3GpuParallelLinearBvh(); + + ///Must be called before any other function + void build(const b3OpenCLArray& worldSpaceAabbs, const b3OpenCLArray& smallAabbIndices, + const b3OpenCLArray& largeAabbIndices); + + ///calculateOverlappingPairs() uses the worldSpaceAabbs parameter of b3GpuParallelLinearBvh::build() as the query AABBs. + ///@param out_overlappingPairs The size() of this array is used to determine the max number of pairs. + ///If the number of overlapping pairs is < out_overlappingPairs.size(), out_overlappingPairs is resized. + void calculateOverlappingPairs(b3OpenCLArray& out_overlappingPairs); + + ///@param out_numRigidRayPairs Array of length 1; contains the number of detected ray-rigid AABB intersections; + ///this value may be greater than out_rayRigidPairs.size() if out_rayRigidPairs is not large enough. + ///@param out_rayRigidPairs Contains an array of rays intersecting rigid AABBs; x == ray index, y == rigid body index. + ///If the size of this array is insufficient to hold all ray-rigid AABB intersections, additional intersections are discarded. + void testRaysAgainstBvhAabbs(const b3OpenCLArray& rays, + b3OpenCLArray& out_numRayRigidPairs, b3OpenCLArray& out_rayRigidPairs); + +private: + void constructBinaryRadixTree(); +}; + +#endif diff --git a/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.cpp b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.cpp new file mode 100644 index 000000000000..d2618024ac4b --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.cpp @@ -0,0 +1,80 @@ +/* +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. +*/ +//Initial Author Jackson Lee, 2014 + +#include "b3GpuParallelLinearBvhBroadphase.h" + +b3GpuParallelLinearBvhBroadphase::b3GpuParallelLinearBvhBroadphase(cl_context context, cl_device_id device, cl_command_queue queue) : + m_plbvh(context, device, queue), + + m_overlappingPairsGpu(context, queue), + + m_aabbsGpu(context, queue), + m_smallAabbsMappingGpu(context, queue), + m_largeAabbsMappingGpu(context, queue) +{ +} + +void b3GpuParallelLinearBvhBroadphase::createProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr, int collisionFilterGroup, int collisionFilterMask) +{ + int newAabbIndex = m_aabbsCpu.size(); + + b3SapAabb aabb; + aabb.m_minVec = aabbMin; + aabb.m_maxVec = aabbMax; + + aabb.m_minIndices[3] = userPtr; + aabb.m_signedMaxIndices[3] = newAabbIndex; + + m_smallAabbsMappingCpu.push_back(newAabbIndex); + + m_aabbsCpu.push_back(aabb); +} +void b3GpuParallelLinearBvhBroadphase::createLargeProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr, int collisionFilterGroup, int collisionFilterMask) +{ + int newAabbIndex = m_aabbsCpu.size(); + + b3SapAabb aabb; + aabb.m_minVec = aabbMin; + aabb.m_maxVec = aabbMax; + + aabb.m_minIndices[3] = userPtr; + aabb.m_signedMaxIndices[3] = newAabbIndex; + + m_largeAabbsMappingCpu.push_back(newAabbIndex); + + m_aabbsCpu.push_back(aabb); +} + +void b3GpuParallelLinearBvhBroadphase::calculateOverlappingPairs(int maxPairs) +{ + //Reconstruct BVH + m_plbvh.build(m_aabbsGpu, m_smallAabbsMappingGpu, m_largeAabbsMappingGpu); + + // + m_overlappingPairsGpu.resize(maxPairs); + m_plbvh.calculateOverlappingPairs(m_overlappingPairsGpu); +} +void b3GpuParallelLinearBvhBroadphase::calculateOverlappingPairsHost(int maxPairs) +{ + b3Assert(0); //CPU version not implemented +} + +void b3GpuParallelLinearBvhBroadphase::writeAabbsToGpu() +{ + m_aabbsGpu.copyFromHost(m_aabbsCpu); + m_smallAabbsMappingGpu.copyFromHost(m_smallAabbsMappingCpu); + m_largeAabbsMappingGpu.copyFromHost(m_largeAabbsMappingCpu); +} + + + diff --git a/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h new file mode 100644 index 000000000000..e5185006371d --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h @@ -0,0 +1,66 @@ +/* +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. +*/ +//Initial Author Jackson Lee, 2014 + +#ifndef B3_GPU_PARALLEL_LINEAR_BVH_BROADPHASE_H +#define B3_GPU_PARALLEL_LINEAR_BVH_BROADPHASE_H + +#include "Bullet3OpenCL/BroadphaseCollision/b3GpuBroadphaseInterface.h" + +#include "b3GpuParallelLinearBvh.h" + +class b3GpuParallelLinearBvhBroadphase : public b3GpuBroadphaseInterface +{ + b3GpuParallelLinearBvh m_plbvh; + + b3OpenCLArray m_overlappingPairsGpu; + + b3OpenCLArray m_aabbsGpu; + b3OpenCLArray m_smallAabbsMappingGpu; + b3OpenCLArray m_largeAabbsMappingGpu; + + b3AlignedObjectArray m_aabbsCpu; + b3AlignedObjectArray m_smallAabbsMappingCpu; + b3AlignedObjectArray m_largeAabbsMappingCpu; + +public: + b3GpuParallelLinearBvhBroadphase(cl_context context, cl_device_id device, cl_command_queue queue); + virtual ~b3GpuParallelLinearBvhBroadphase() {} + + virtual void createProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr, int collisionFilterGroup, int collisionFilterMask); + virtual void createLargeProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr, int collisionFilterGroup, int collisionFilterMask); + + virtual void calculateOverlappingPairs(int maxPairs); + virtual void calculateOverlappingPairsHost(int maxPairs); + + //call writeAabbsToGpu after done making all changes (createProxy etc) + virtual void writeAabbsToGpu(); + + virtual int getNumOverlap() { return m_overlappingPairsGpu.size(); } + virtual cl_mem getOverlappingPairBuffer() { return m_overlappingPairsGpu.getBufferCL(); } + + virtual cl_mem getAabbBufferWS() { return m_aabbsGpu.getBufferCL(); } + virtual b3OpenCLArray& getAllAabbsGPU() { return m_aabbsGpu; } + + virtual b3OpenCLArray& getOverlappingPairsGPU() { return m_overlappingPairsGpu; } + virtual b3OpenCLArray& getSmallAabbIndicesGPU() { return m_smallAabbsMappingGpu; } + virtual b3OpenCLArray& getLargeAabbIndicesGPU() { return m_largeAabbsMappingGpu; } + + virtual b3AlignedObjectArray& getAllAabbsCPU() { return m_aabbsCpu; } + + static b3GpuBroadphaseInterface* CreateFunc(cl_context context, cl_device_id device, cl_command_queue queue) + { + return new b3GpuParallelLinearBvhBroadphase(context, device, queue); + } +}; + +#endif diff --git a/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.cpp b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.cpp new file mode 100644 index 000000000000..c45fbbdcaa30 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.cpp @@ -0,0 +1,1366 @@ + +bool searchIncremental3dSapOnGpu = true; +#include +#include "b3GpuSapBroadphase.h" +#include "Bullet3Common/b3Vector3.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3PrefixScanFloat4CL.h" + + +#include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h" +#include "kernels/sapKernels.h" + +#include "Bullet3Common/b3MinMax.h" + +#define B3_BROADPHASE_SAP_PATH "src/Bullet3OpenCL/BroadphaseCollision/kernels/sap.cl" + +/* + + + + + + + b3OpenCLArray m_pairCount; + + + b3OpenCLArray m_allAabbsGPU; + b3AlignedObjectArray m_allAabbsCPU; + + virtual b3OpenCLArray& getAllAabbsGPU() + { + return m_allAabbsGPU; + } + virtual b3AlignedObjectArray& getAllAabbsCPU() + { + return m_allAabbsCPU; + } + + b3OpenCLArray m_sum; + b3OpenCLArray m_sum2; + b3OpenCLArray m_dst; + + b3OpenCLArray m_smallAabbsMappingGPU; + b3AlignedObjectArray m_smallAabbsMappingCPU; + + b3OpenCLArray m_largeAabbsMappingGPU; + b3AlignedObjectArray m_largeAabbsMappingCPU; + + + b3OpenCLArray m_overlappingPairs; + + //temporary gpu work memory + b3OpenCLArray m_gpuSmallSortData; + b3OpenCLArray m_gpuSmallSortedAabbs; + + class b3PrefixScanFloat4CL* m_prefixScanFloat4; + */ + +b3GpuSapBroadphase::b3GpuSapBroadphase(cl_context ctx,cl_device_id device, cl_command_queue q , b3GpuSapKernelType kernelType) +:m_context(ctx), +m_device(device), +m_queue(q), + +m_objectMinMaxIndexGPUaxis0(ctx,q), +m_objectMinMaxIndexGPUaxis1(ctx,q), +m_objectMinMaxIndexGPUaxis2(ctx,q), +m_objectMinMaxIndexGPUaxis0prev(ctx,q), +m_objectMinMaxIndexGPUaxis1prev(ctx,q), +m_objectMinMaxIndexGPUaxis2prev(ctx,q), +m_sortedAxisGPU0(ctx,q), +m_sortedAxisGPU1(ctx,q), +m_sortedAxisGPU2(ctx,q), +m_sortedAxisGPU0prev(ctx,q), +m_sortedAxisGPU1prev(ctx,q), +m_sortedAxisGPU2prev(ctx,q), +m_addedHostPairsGPU(ctx,q), +m_removedHostPairsGPU(ctx,q), +m_addedCountGPU(ctx,q), +m_removedCountGPU(ctx,q), +m_currentBuffer(-1), +m_pairCount(ctx,q), +m_allAabbsGPU(ctx,q), +m_sum(ctx,q), +m_sum2(ctx,q), +m_dst(ctx,q), +m_smallAabbsMappingGPU(ctx,q), +m_largeAabbsMappingGPU(ctx,q), +m_overlappingPairs(ctx,q), +m_gpuSmallSortData(ctx,q), +m_gpuSmallSortedAabbs(ctx,q) +{ + const char* sapSrc = sapCL; + + + cl_int errNum=0; + + b3Assert(m_context); + b3Assert(m_device); + cl_program sapProg = b3OpenCLUtils::compileCLProgramFromString(m_context,m_device,sapSrc,&errNum,"",B3_BROADPHASE_SAP_PATH); + b3Assert(errNum==CL_SUCCESS); + + + b3Assert(errNum==CL_SUCCESS); +#ifndef __APPLE__ + m_prefixScanFloat4 = new b3PrefixScanFloat4CL(m_context,m_device,m_queue); +#else + m_prefixScanFloat4 = 0; +#endif + m_sapKernel = 0; + + switch (kernelType) + { + case B3_GPU_SAP_KERNEL_BRUTE_FORCE_CPU: + { + m_sapKernel=0; + break; + } + case B3_GPU_SAP_KERNEL_BRUTE_FORCE_GPU: + { + m_sapKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,sapSrc, "computePairsKernelBruteForce",&errNum,sapProg ); + break; + } + + case B3_GPU_SAP_KERNEL_ORIGINAL: + { + m_sapKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,sapSrc, "computePairsKernelOriginal",&errNum,sapProg ); + break; + } + case B3_GPU_SAP_KERNEL_BARRIER: + { + m_sapKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,sapSrc, "computePairsKernelBarrier",&errNum,sapProg ); + break; + } + case B3_GPU_SAP_KERNEL_LOCAL_SHARED_MEMORY: + { + m_sapKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,sapSrc, "computePairsKernelLocalSharedMemory",&errNum,sapProg ); + break; + } + + default: + { + m_sapKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,sapSrc, "computePairsKernelLocalSharedMemory",&errNum,sapProg ); + b3Error("Unknown 3D GPU SAP provided, fallback to computePairsKernelLocalSharedMemory"); + } + }; + + + + m_sap2Kernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,sapSrc, "computePairsKernelTwoArrays",&errNum,sapProg ); + b3Assert(errNum==CL_SUCCESS); + + m_prepareSumVarianceKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,sapSrc, "prepareSumVarianceKernel",&errNum,sapProg ); + b3Assert(errNum==CL_SUCCESS); + + + m_flipFloatKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,sapSrc, "flipFloatKernel",&errNum,sapProg ); + + m_copyAabbsKernel= b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,sapSrc, "copyAabbsKernel",&errNum,sapProg ); + + m_scatterKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,sapSrc, "scatterKernel",&errNum,sapProg ); + + m_sorter = new b3RadixSort32CL(m_context,m_device,m_queue); +} + +b3GpuSapBroadphase::~b3GpuSapBroadphase() +{ + delete m_sorter; + delete m_prefixScanFloat4; + + clReleaseKernel(m_scatterKernel); + clReleaseKernel(m_flipFloatKernel); + clReleaseKernel(m_copyAabbsKernel); + clReleaseKernel(m_sapKernel); + clReleaseKernel(m_sap2Kernel); + clReleaseKernel(m_prepareSumVarianceKernel); + + +} + +/// conservative test for overlap between two aabbs +static bool TestAabbAgainstAabb2(const b3Vector3 &aabbMin1, const b3Vector3 &aabbMax1, + const b3Vector3 &aabbMin2, const b3Vector3 &aabbMax2) +{ + bool overlap = true; + overlap = (aabbMin1.getX() > aabbMax2.getX() || aabbMax1.getX() < aabbMin2.getX()) ? false : overlap; + overlap = (aabbMin1.getZ() > aabbMax2.getZ() || aabbMax1.getZ() < aabbMin2.getZ()) ? false : overlap; + overlap = (aabbMin1.getY() > aabbMax2.getY() || aabbMax1.getY() < aabbMin2.getY()) ? false : overlap; + return overlap; +} + + + +//http://stereopsis.com/radix.html +static unsigned int FloatFlip(float fl) +{ + unsigned int f = *(unsigned int*)&fl; + unsigned int mask = -(int)(f >> 31) | 0x80000000; + return f ^ mask; +}; + +void b3GpuSapBroadphase::init3dSap() +{ + if (m_currentBuffer<0) + { + m_allAabbsGPU.copyToHost(m_allAabbsCPU); + + m_currentBuffer = 0; + for (int axis=0;axis<3;axis++) + { + for (int buf=0;buf<2;buf++) + { + int totalNumAabbs = m_allAabbsCPU.size(); + int numEndPoints = 2*totalNumAabbs; + m_sortedAxisCPU[axis][buf].resize(numEndPoints); + + if (buf==m_currentBuffer) + { + for (int i=0;iexecuteHost(m_sortedAxisCPU[axis][m_currentBuffer]); + } + + for (int axis=0;axis<3;axis++) + { + //int totalNumAabbs = m_allAabbsCPU.size(); + int numEndPoints = m_sortedAxisCPU[axis][m_currentBuffer].size(); + m_objectMinMaxIndexCPU[axis][m_currentBuffer].resize(numEndPoints); + for (int i=0;i(const b3Int4& a,const b3Int4& b) +{ + return a.x > b.x || (a.x == b.x && a.y > b.y); +}; + +b3AlignedObjectArray addedHostPairs; +b3AlignedObjectArray removedHostPairs; + +b3AlignedObjectArray preAabbs; + +void b3GpuSapBroadphase::calculateOverlappingPairsHostIncremental3Sap() +{ + //static int framepje = 0; + //printf("framepje=%d\n",framepje++); + + + B3_PROFILE("calculateOverlappingPairsHostIncremental3Sap"); + + addedHostPairs.resize(0); + removedHostPairs.resize(0); + + b3Assert(m_currentBuffer>=0); + + { + preAabbs.resize(m_allAabbsCPU.size()); + for (int i=0;i allPairs; + { + B3_PROFILE("m_overlappingPairs.copyToHost"); + m_overlappingPairs.copyToHost(allPairs); + } + if (0) + { + { + printf("ab[40].min=%f,%f,%f,ab[40].max=%f,%f,%f\n", + m_allAabbsCPU[40].m_min[0], m_allAabbsCPU[40].m_min[1],m_allAabbsCPU[40].m_min[2], + m_allAabbsCPU[40].m_max[0], m_allAabbsCPU[40].m_max[1],m_allAabbsCPU[40].m_max[2]); + } + + { + printf("ab[53].min=%f,%f,%f,ab[53].max=%f,%f,%f\n", + m_allAabbsCPU[53].m_min[0], m_allAabbsCPU[53].m_min[1],m_allAabbsCPU[53].m_min[2], + m_allAabbsCPU[53].m_max[0], m_allAabbsCPU[53].m_max[1],m_allAabbsCPU[53].m_max[2]); + } + + + { + b3Int4 newPair; + newPair.x = 40; + newPair.y = 53; + int index = allPairs.findBinarySearch(newPair); + printf("hasPair(40,53)=%d out of %d\n",index, allPairs.size()); + + { + int overlap = TestAabbAgainstAabb2((const b3Vector3&)m_allAabbsCPU[40].m_min, (const b3Vector3&)m_allAabbsCPU[40].m_max,(const b3Vector3&)m_allAabbsCPU[53].m_min,(const b3Vector3&)m_allAabbsCPU[53].m_max); + printf("overlap=%d\n",overlap); + } + + if (preAabbs.size()) + { + int prevOverlap = TestAabbAgainstAabb2((const b3Vector3&)preAabbs[40].m_min, (const b3Vector3&)preAabbs[40].m_max,(const b3Vector3&)preAabbs[53].m_min,(const b3Vector3&)preAabbs[53].m_max); + printf("prevoverlap=%d\n",prevOverlap); + } else + { + printf("unknown prevoverlap\n"); + } + + } + } + + + if (0) + { + for (int i=0;iexecuteHost(m_sortedAxisCPU[axis][m_currentBuffer]); + } + +#if 0 + if (0) + { + for (int axis=0;axis<3;axis++) + { + //printf("axis %d\n",axis); + for (int i=0;i m_objectMinMaxIndexCPU[ax][m_currentBuffer][otherIndex].y) || + (m_objectMinMaxIndexCPU[ax][m_currentBuffer][i].y < m_objectMinMaxIndexCPU[ax][m_currentBuffer][otherIndex].x)) + overlap=false; + } + + // b3Assert(overlap2==overlap); + + bool prevOverlap = true; + + for (int ax=0;ax<3;ax++) + { + if ((m_objectMinMaxIndexCPU[ax][1-m_currentBuffer][i].x > m_objectMinMaxIndexCPU[ax][1-m_currentBuffer][otherIndex].y) || + (m_objectMinMaxIndexCPU[ax][1-m_currentBuffer][i].y < m_objectMinMaxIndexCPU[ax][1-m_currentBuffer][otherIndex].x)) + prevOverlap=false; + } + + + //b3Assert(overlap==overlap2); + + + + if (dmin<0) + { + if (overlap && !prevOverlap) + { + //add a pair + b3Int4 newPair; + if (i<=otherIndex) + { + newPair.x = i; + newPair.y = otherIndex; + } else + { + newPair.x = otherIndex; + newPair.y = i; + } + addedHostPairs.push_back(newPair); + } + } + else + { + if (!overlap && prevOverlap) + { + + //remove a pair + b3Int4 removedPair; + if (i<=otherIndex) + { + removedPair.x = i; + removedPair.y = otherIndex; + } else + { + removedPair.x = otherIndex; + removedPair.y = i; + } + removedHostPairs.push_back(removedPair); + } + }//otherisMax + }//if (dmin<0) + }//if (otherIndex!=i) + }//for (int j= + } + + if (dmax!=0) + { + int stepMax = dmax<0 ? -1 : 1; + for (int j=prevMaxIndex;j!=curMaxIndex;j+=stepMax) + { + int otherIndex2 = m_sortedAxisCPU[axis][otherbuffer][j].y; + int otherIndex = otherIndex2/2; + if (otherIndex!=i) + { + //bool otherIsMin = ((otherIndex2&1)==0); + //if (otherIsMin) + { + //bool overlap = TestAabbAgainstAabb2((const b3Vector3&)m_allAabbsCPU[i].m_min, (const b3Vector3&)m_allAabbsCPU[i].m_max,(const b3Vector3&)m_allAabbsCPU[otherIndex].m_min,(const b3Vector3&)m_allAabbsCPU[otherIndex].m_max); + //bool prevOverlap = TestAabbAgainstAabb2((const b3Vector3&)preAabbs[i].m_min, (const b3Vector3&)preAabbs[i].m_max,(const b3Vector3&)preAabbs[otherIndex].m_min,(const b3Vector3&)preAabbs[otherIndex].m_max); + + bool overlap = true; + + for (int ax=0;ax<3;ax++) + { + if ((m_objectMinMaxIndexCPU[ax][m_currentBuffer][i].x > m_objectMinMaxIndexCPU[ax][m_currentBuffer][otherIndex].y) || + (m_objectMinMaxIndexCPU[ax][m_currentBuffer][i].y < m_objectMinMaxIndexCPU[ax][m_currentBuffer][otherIndex].x)) + overlap=false; + } + //b3Assert(overlap2==overlap); + + bool prevOverlap = true; + + for (int ax=0;ax<3;ax++) + { + if ((m_objectMinMaxIndexCPU[ax][1-m_currentBuffer][i].x > m_objectMinMaxIndexCPU[ax][1-m_currentBuffer][otherIndex].y) || + (m_objectMinMaxIndexCPU[ax][1-m_currentBuffer][i].y < m_objectMinMaxIndexCPU[ax][1-m_currentBuffer][otherIndex].x)) + prevOverlap=false; + } + + + if (dmax>0) + { + if (overlap && !prevOverlap) + { + //add a pair + b3Int4 newPair; + if (i<=otherIndex) + { + newPair.x = i; + newPair.y = otherIndex; + } else + { + newPair.x = otherIndex; + newPair.y = i; + } + addedHostPairs.push_back(newPair); + + } + } + else + { + if (!overlap && prevOverlap) + { + //if (otherIndex2&1==0) -> min? + //remove a pair + b3Int4 removedPair; + if (i<=otherIndex) + { + removedPair.x = i; + removedPair.y = otherIndex; + } else + { + removedPair.x = otherIndex; + removedPair.y = i; + } + removedHostPairs.push_back(removedPair); + + } + } + + }//if (dmin<0) + }//if (otherIndex!=i) + }//for (int j= + } + }//for (int otherbuffer + }//for (int axis=0; + }//for (int i=0;i removedPositions; + + { + B3_PROFILE("actual removing"); + for (int i=0;i actualAddedPairs; + + { + B3_PROFILE("actual adding"); + for (int i=0;i=0) + // return calculateOverlappingPairsHostIncremental3Sap(); + + b3Assert(m_allAabbsCPU.size() == m_allAabbsGPU.size()); + m_allAabbsGPU.copyToHost(m_allAabbsCPU); + + + + int axis=0; + { + B3_PROFILE("CPU compute best variance axis"); + b3Vector3 s=b3MakeVector3(0,0,0),s2=b3MakeVector3(0,0,0); + int numRigidBodies = m_smallAabbsMappingCPU.size(); + + for(int i=0;im_allAabbsCPU[m_smallAabbsMappingCPU[i]]; + + b3Vector3 maxAabb=b3MakeVector3(aabb.m_max[0],aabb.m_max[1],aabb.m_max[2]); + b3Vector3 minAabb=b3MakeVector3(aabb.m_min[0],aabb.m_min[1],aabb.m_min[2]); + b3Vector3 centerAabb=(maxAabb+minAabb)*0.5f; + + s += centerAabb; + s2 += centerAabb*centerAabb; + } + b3Vector3 v = s2 - (s*s) / (float)numRigidBodies; + + if(v[1] > v[0]) + axis = 1; + if(v[2] > v[axis]) + axis = 2; + } + + + + + b3AlignedObjectArray hostPairs; + + { + int numSmallAabbs = m_smallAabbsMappingCPU.size(); + for (int i=0;i maxPairs) + { + hostPairs.resize(maxPairs); + } + + if (hostPairs.size()) + { + m_overlappingPairs.copyFromHost(hostPairs); + } else + { + m_overlappingPairs.resize(0); + } + + //init3dSap(); + +} + +void b3GpuSapBroadphase::reset() +{ + m_allAabbsGPU.resize(0); + m_allAabbsCPU.resize(0); + + + m_smallAabbsMappingGPU.resize(0); + m_smallAabbsMappingCPU.resize(0); + + m_pairCount.resize(0); + + m_largeAabbsMappingGPU.resize(0); + m_largeAabbsMappingCPU.resize(0); + +} + + +void b3GpuSapBroadphase::calculateOverlappingPairs(int maxPairs) +{ + if (m_sapKernel==0) + { + calculateOverlappingPairsHost(maxPairs); + return; + } + + //if (m_currentBuffer>=0) + // return calculateOverlappingPairsHostIncremental3Sap(); + + //calculateOverlappingPairsHost(maxPairs); + + B3_PROFILE("GPU 1-axis SAP calculateOverlappingPairs"); + + int axis = 0; + + { + + //bool syncOnHost = false; + + int numSmallAabbs = m_smallAabbsMappingCPU.size(); + if (m_prefixScanFloat4 && numSmallAabbs) + { + B3_PROFILE("GPU compute best variance axis"); + + if (m_dst.size()!=(numSmallAabbs+1)) + { + m_dst.resize(numSmallAabbs+128); + m_sum.resize(numSmallAabbs+128); + m_sum2.resize(numSmallAabbs+128); + m_sum.at(numSmallAabbs)=b3MakeVector3(0,0,0); //slow? + m_sum2.at(numSmallAabbs)=b3MakeVector3(0,0,0); //slow? + } + + b3LauncherCL launcher(m_queue, m_prepareSumVarianceKernel ,"m_prepareSumVarianceKernel"); + launcher.setBuffer(m_allAabbsGPU.getBufferCL()); + + launcher.setBuffer(m_smallAabbsMappingGPU.getBufferCL()); + launcher.setBuffer(m_sum.getBufferCL()); + launcher.setBuffer(m_sum2.getBufferCL()); + launcher.setConst( numSmallAabbs ); + int num = numSmallAabbs; + launcher.launch1D( num); + + + b3Vector3 s; + b3Vector3 s2; + m_prefixScanFloat4->execute(m_sum,m_dst,numSmallAabbs+1,&s); + m_prefixScanFloat4->execute(m_sum2,m_dst,numSmallAabbs+1,&s2); + + b3Vector3 v = s2 - (s*s) / (float)numSmallAabbs; + + if(v[1] > v[0]) + axis = 1; + if(v[2] > v[axis]) + axis = 2; + } + + + + m_gpuSmallSortData.resize(numSmallAabbs); + + +#if 1 + if (m_smallAabbsMappingGPU.size()) + { + + B3_PROFILE("flipFloatKernel"); + b3BufferInfoCL bInfo[] = { + b3BufferInfoCL( m_allAabbsGPU.getBufferCL(), true ), + b3BufferInfoCL( m_smallAabbsMappingGPU.getBufferCL(), true), + b3BufferInfoCL( m_gpuSmallSortData.getBufferCL())}; + b3LauncherCL launcher(m_queue, m_flipFloatKernel ,"m_flipFloatKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( numSmallAabbs ); + launcher.setConst( axis ); + + int num = numSmallAabbs; + launcher.launch1D( num); + clFinish(m_queue); + } + + if (m_gpuSmallSortData.size()) + { + B3_PROFILE("gpu radix sort"); + m_sorter->execute(m_gpuSmallSortData); + clFinish(m_queue); + } + + m_gpuSmallSortedAabbs.resize(numSmallAabbs); + if (numSmallAabbs) + { + B3_PROFILE("scatterKernel"); + + b3BufferInfoCL bInfo[] = { + b3BufferInfoCL( m_allAabbsGPU.getBufferCL(), true ), + b3BufferInfoCL( m_smallAabbsMappingGPU.getBufferCL(), true), + b3BufferInfoCL( m_gpuSmallSortData.getBufferCL(),true), + b3BufferInfoCL(m_gpuSmallSortedAabbs.getBufferCL())}; + b3LauncherCL launcher(m_queue, m_scatterKernel ,"m_scatterKernel "); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( numSmallAabbs); + int num = numSmallAabbs; + launcher.launch1D( num); + clFinish(m_queue); + + } + + + m_overlappingPairs.resize(maxPairs); + + m_pairCount.resize(0); + m_pairCount.push_back(0); + int numPairs=0; + + { + int numLargeAabbs = m_largeAabbsMappingGPU.size(); + if (numLargeAabbs && numSmallAabbs) + { + //@todo + B3_PROFILE("sap2Kernel"); + b3BufferInfoCL bInfo[] = { + b3BufferInfoCL( m_allAabbsGPU.getBufferCL() ), + b3BufferInfoCL( m_largeAabbsMappingGPU.getBufferCL() ), + b3BufferInfoCL( m_smallAabbsMappingGPU.getBufferCL() ), + b3BufferInfoCL( m_overlappingPairs.getBufferCL() ), + b3BufferInfoCL(m_pairCount.getBufferCL())}; + b3LauncherCL launcher(m_queue, m_sap2Kernel,"m_sap2Kernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( numLargeAabbs ); + launcher.setConst( numSmallAabbs); + launcher.setConst( axis ); + launcher.setConst( maxPairs ); +//@todo: use actual maximum work item sizes of the device instead of hardcoded values + launcher.launch2D( numLargeAabbs, numSmallAabbs,4,64); + + numPairs = m_pairCount.at(0); + if (numPairs >maxPairs) + { + b3Error("Error running out of pairs: numPairs = %d, maxPairs = %d.\n", numPairs, maxPairs); + numPairs =maxPairs; + } + } + } + if (m_gpuSmallSortedAabbs.size()) + { + B3_PROFILE("sapKernel"); + b3BufferInfoCL bInfo[] = { b3BufferInfoCL( m_gpuSmallSortedAabbs.getBufferCL() ), b3BufferInfoCL( m_overlappingPairs.getBufferCL() ), b3BufferInfoCL(m_pairCount.getBufferCL())}; + b3LauncherCL launcher(m_queue, m_sapKernel,"m_sapKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( numSmallAabbs ); + launcher.setConst( axis ); + launcher.setConst( maxPairs ); + + + int num = numSmallAabbs; +#if 0 + int buffSize = launcher.getSerializationBufferSize(); + unsigned char* buf = new unsigned char[buffSize+sizeof(int)]; + for (int i=0;imaxPairs) + { + b3Error("Error running out of pairs: numPairs = %d, maxPairs = %d.\n", numPairs, maxPairs); + numPairs = maxPairs; + m_pairCount.resize(0); + m_pairCount.push_back(maxPairs); + } + } + +#else + int numPairs = 0; + + + b3LauncherCL launcher(m_queue, m_sapKernel); + + const char* fileName = "m_sapKernelArgs.bin"; + FILE* f = fopen(fileName,"rb"); + if (f) + { + int sizeInBytes=0; + if (fseek(f, 0, SEEK_END) || (sizeInBytes = ftell(f)) == EOF || fseek(f, 0, SEEK_SET)) + { + printf("error, cannot get file size\n"); + exit(0); + } + + unsigned char* buf = (unsigned char*) malloc(sizeInBytes); + fread(buf,sizeInBytes,1,f); + int serializedBytes = launcher.deserializeArgs(buf, sizeInBytes,m_context); + int num = *(int*)&buf[serializedBytes]; + launcher.launch1D( num); + + b3OpenCLArray pairCount(m_context, m_queue); + int numElements = launcher.m_arrays[2]->size()/sizeof(int); + pairCount.setFromOpenCLBuffer(launcher.m_arrays[2]->getBufferCL(),numElements); + numPairs = pairCount.at(0); + //printf("overlapping pairs = %d\n",numPairs); + b3AlignedObjectArray hostOoverlappingPairs; + b3OpenCLArray tmpGpuPairs(m_context,m_queue); + tmpGpuPairs.setFromOpenCLBuffer(launcher.m_arrays[1]->getBufferCL(),numPairs ); + + tmpGpuPairs.copyToHost(hostOoverlappingPairs); + m_overlappingPairs.copyFromHost(hostOoverlappingPairs); + //printf("hello %d\n", m_overlappingPairs.size()); + free(buf); + fclose(f); + + } else { + printf("error: cannot find file %s\n",fileName); + } + + clFinish(m_queue); + + +#endif + + + m_overlappingPairs.resize(numPairs); + + }//B3_PROFILE("GPU_RADIX SORT"); + //init3dSap(); +} + +void b3GpuSapBroadphase::writeAabbsToGpu() +{ + m_smallAabbsMappingGPU.copyFromHost(m_smallAabbsMappingCPU); + m_largeAabbsMappingGPU.copyFromHost(m_largeAabbsMappingCPU); + + m_allAabbsGPU.copyFromHost(m_allAabbsCPU);//might not be necessary, the 'setupGpuAabbsFull' already takes care of this + + + +} + +void b3GpuSapBroadphase::createLargeProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr , int collisionFilterGroup, int collisionFilterMask) +{ + int index = userPtr; + b3SapAabb aabb; + for (int i=0;i<4;i++) + { + aabb.m_min[i] = aabbMin[i]; + aabb.m_max[i] = aabbMax[i]; + } + aabb.m_minIndices[3] = index; + aabb.m_signedMaxIndices[3] = m_allAabbsCPU.size(); + m_largeAabbsMappingCPU.push_back(m_allAabbsCPU.size()); + + m_allAabbsCPU.push_back(aabb); +} + +void b3GpuSapBroadphase::createProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr , int collisionFilterGroup, int collisionFilterMask) +{ + int index = userPtr; + b3SapAabb aabb; + for (int i=0;i<4;i++) + { + aabb.m_min[i] = aabbMin[i]; + aabb.m_max[i] = aabbMax[i]; + } + aabb.m_minIndices[3] = index; + aabb.m_signedMaxIndices[3] = m_allAabbsCPU.size(); + m_smallAabbsMappingCPU.push_back(m_allAabbsCPU.size()); + + + m_allAabbsCPU.push_back(aabb); +} + +cl_mem b3GpuSapBroadphase::getAabbBufferWS() +{ + return m_allAabbsGPU.getBufferCL(); +} + +int b3GpuSapBroadphase::getNumOverlap() +{ + return m_overlappingPairs.size(); +} +cl_mem b3GpuSapBroadphase::getOverlappingPairBuffer() +{ + return m_overlappingPairs.getBufferCL(); +} + +b3OpenCLArray& b3GpuSapBroadphase::getOverlappingPairsGPU() +{ + return m_overlappingPairs; +} +b3OpenCLArray& b3GpuSapBroadphase::getSmallAabbIndicesGPU() +{ + return m_smallAabbsMappingGPU; +} +b3OpenCLArray& b3GpuSapBroadphase::getLargeAabbIndicesGPU() +{ + return m_largeAabbsMappingGPU; +} diff --git a/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.h b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.h new file mode 100644 index 000000000000..8d36ac78f28c --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.h @@ -0,0 +1,151 @@ +#ifndef B3_GPU_SAP_BROADPHASE_H +#define B3_GPU_SAP_BROADPHASE_H + +#include "Bullet3OpenCL/ParallelPrimitives/b3OpenCLArray.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3FillCL.h" //b3Int2 +class b3Vector3; +#include "Bullet3OpenCL/ParallelPrimitives/b3RadixSort32CL.h" + +#include "b3SapAabb.h" +#include "Bullet3Common/shared/b3Int2.h" + +#include "b3GpuBroadphaseInterface.h" + + +class b3GpuSapBroadphase : public b3GpuBroadphaseInterface +{ + + cl_context m_context; + cl_device_id m_device; + cl_command_queue m_queue; + cl_kernel m_flipFloatKernel; + cl_kernel m_scatterKernel ; + cl_kernel m_copyAabbsKernel; + cl_kernel m_sapKernel; + cl_kernel m_sap2Kernel; + cl_kernel m_prepareSumVarianceKernel; + + + class b3RadixSort32CL* m_sorter; + + ///test for 3d SAP + b3AlignedObjectArray m_sortedAxisCPU[3][2]; + b3AlignedObjectArray m_objectMinMaxIndexCPU[3][2]; + b3OpenCLArray m_objectMinMaxIndexGPUaxis0; + b3OpenCLArray m_objectMinMaxIndexGPUaxis1; + b3OpenCLArray m_objectMinMaxIndexGPUaxis2; + b3OpenCLArray m_objectMinMaxIndexGPUaxis0prev; + b3OpenCLArray m_objectMinMaxIndexGPUaxis1prev; + b3OpenCLArray m_objectMinMaxIndexGPUaxis2prev; + + b3OpenCLArray m_sortedAxisGPU0; + b3OpenCLArray m_sortedAxisGPU1; + b3OpenCLArray m_sortedAxisGPU2; + b3OpenCLArray m_sortedAxisGPU0prev; + b3OpenCLArray m_sortedAxisGPU1prev; + b3OpenCLArray m_sortedAxisGPU2prev; + + + b3OpenCLArray m_addedHostPairsGPU; + b3OpenCLArray m_removedHostPairsGPU; + b3OpenCLArray m_addedCountGPU; + b3OpenCLArray m_removedCountGPU; + + int m_currentBuffer; + +public: + + b3OpenCLArray m_pairCount; + + + b3OpenCLArray m_allAabbsGPU; + b3AlignedObjectArray m_allAabbsCPU; + + virtual b3OpenCLArray& getAllAabbsGPU() + { + return m_allAabbsGPU; + } + virtual b3AlignedObjectArray& getAllAabbsCPU() + { + return m_allAabbsCPU; + } + + b3OpenCLArray m_sum; + b3OpenCLArray m_sum2; + b3OpenCLArray m_dst; + + b3OpenCLArray m_smallAabbsMappingGPU; + b3AlignedObjectArray m_smallAabbsMappingCPU; + + b3OpenCLArray m_largeAabbsMappingGPU; + b3AlignedObjectArray m_largeAabbsMappingCPU; + + + b3OpenCLArray m_overlappingPairs; + + //temporary gpu work memory + b3OpenCLArray m_gpuSmallSortData; + b3OpenCLArray m_gpuSmallSortedAabbs; + + class b3PrefixScanFloat4CL* m_prefixScanFloat4; + + enum b3GpuSapKernelType + { + B3_GPU_SAP_KERNEL_BRUTE_FORCE_CPU=1, + B3_GPU_SAP_KERNEL_BRUTE_FORCE_GPU, + B3_GPU_SAP_KERNEL_ORIGINAL, + B3_GPU_SAP_KERNEL_BARRIER, + B3_GPU_SAP_KERNEL_LOCAL_SHARED_MEMORY + }; + + b3GpuSapBroadphase(cl_context ctx,cl_device_id device, cl_command_queue q , b3GpuSapKernelType kernelType=B3_GPU_SAP_KERNEL_LOCAL_SHARED_MEMORY); + virtual ~b3GpuSapBroadphase(); + + static b3GpuBroadphaseInterface* CreateFuncBruteForceCpu(cl_context ctx,cl_device_id device, cl_command_queue q) + { + return new b3GpuSapBroadphase(ctx,device,q,B3_GPU_SAP_KERNEL_BRUTE_FORCE_CPU); + } + + static b3GpuBroadphaseInterface* CreateFuncBruteForceGpu(cl_context ctx,cl_device_id device, cl_command_queue q) + { + return new b3GpuSapBroadphase(ctx,device,q,B3_GPU_SAP_KERNEL_BRUTE_FORCE_GPU); + } + + static b3GpuBroadphaseInterface* CreateFuncOriginal(cl_context ctx,cl_device_id device, cl_command_queue q) + { + return new b3GpuSapBroadphase(ctx,device,q,B3_GPU_SAP_KERNEL_ORIGINAL); + } + static b3GpuBroadphaseInterface* CreateFuncBarrier(cl_context ctx,cl_device_id device, cl_command_queue q) + { + return new b3GpuSapBroadphase(ctx,device,q,B3_GPU_SAP_KERNEL_BARRIER); + } + static b3GpuBroadphaseInterface* CreateFuncLocalMemory(cl_context ctx,cl_device_id device, cl_command_queue q) + { + return new b3GpuSapBroadphase(ctx,device,q,B3_GPU_SAP_KERNEL_LOCAL_SHARED_MEMORY); + } + + + virtual void calculateOverlappingPairs(int maxPairs); + virtual void calculateOverlappingPairsHost(int maxPairs); + + void reset(); + + void init3dSap(); + virtual void calculateOverlappingPairsHostIncremental3Sap(); + + virtual void createProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr , int collisionFilterGroup, int collisionFilterMask); + virtual void createLargeProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr , int collisionFilterGroup, int collisionFilterMask); + + //call writeAabbsToGpu after done making all changes (createProxy etc) + virtual void writeAabbsToGpu(); + + virtual cl_mem getAabbBufferWS(); + virtual int getNumOverlap(); + virtual cl_mem getOverlappingPairBuffer(); + + virtual b3OpenCLArray& getOverlappingPairsGPU(); + virtual b3OpenCLArray& getSmallAabbIndicesGPU(); + virtual b3OpenCLArray& getLargeAabbIndicesGPU(); +}; + +#endif //B3_GPU_SAP_BROADPHASE_H \ No newline at end of file diff --git a/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3SapAabb.h b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3SapAabb.h new file mode 100644 index 000000000000..ea6550fedea5 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/b3SapAabb.h @@ -0,0 +1,14 @@ +#ifndef B3_SAP_AABB_H +#define B3_SAP_AABB_H + +#include "Bullet3Common/b3Scalar.h" +#include "Bullet3Collision/BroadPhaseCollision/shared/b3Aabb.h" + +///just make sure that the b3Aabb is 16-byte aligned +B3_ATTRIBUTE_ALIGNED16(struct) b3SapAabb : public b3Aabb +{ + +}; + + +#endif //B3_SAP_AABB_H diff --git a/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/kernels/gridBroadphase.cl b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/kernels/gridBroadphase.cl new file mode 100644 index 000000000000..ded4796d337d --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/kernels/gridBroadphase.cl @@ -0,0 +1,216 @@ + + +int getPosHash(int4 gridPos, __global float4* pParams) +{ + int4 gridDim = *((__global int4*)(pParams + 1)); + gridPos.x &= gridDim.x - 1; + gridPos.y &= gridDim.y - 1; + gridPos.z &= gridDim.z - 1; + int hash = gridPos.z * gridDim.y * gridDim.x + gridPos.y * gridDim.x + gridPos.x; + return hash; +} + +int4 getGridPos(float4 worldPos, __global float4* pParams) +{ + int4 gridPos; + int4 gridDim = *((__global int4*)(pParams + 1)); + gridPos.x = (int)floor(worldPos.x * pParams[0].x) & (gridDim.x - 1); + gridPos.y = (int)floor(worldPos.y * pParams[0].y) & (gridDim.y - 1); + gridPos.z = (int)floor(worldPos.z * pParams[0].z) & (gridDim.z - 1); + return gridPos; +} + + +// calculate grid hash value for each body using its AABB +__kernel void kCalcHashAABB(int numObjects, __global float4* allpAABB, __global const int* smallAabbMapping, __global int2* pHash, __global float4* pParams ) +{ + int index = get_global_id(0); + if(index >= numObjects) + { + return; + } + float4 bbMin = allpAABB[smallAabbMapping[index]*2]; + float4 bbMax = allpAABB[smallAabbMapping[index]*2 + 1]; + float4 pos; + pos.x = (bbMin.x + bbMax.x) * 0.5f; + pos.y = (bbMin.y + bbMax.y) * 0.5f; + pos.z = (bbMin.z + bbMax.z) * 0.5f; + pos.w = 0.f; + // get address in grid + int4 gridPos = getGridPos(pos, pParams); + int gridHash = getPosHash(gridPos, pParams); + // store grid hash and body index + int2 hashVal; + hashVal.x = gridHash; + hashVal.y = index; + pHash[index] = hashVal; +} + +__kernel void kClearCellStart( int numCells, + __global int* pCellStart ) +{ + int index = get_global_id(0); + if(index >= numCells) + { + return; + } + pCellStart[index] = -1; +} + +__kernel void kFindCellStart(int numObjects, __global int2* pHash, __global int* cellStart ) +{ + __local int sharedHash[513]; + int index = get_global_id(0); + int2 sortedData; + + if(index < numObjects) + { + sortedData = pHash[index]; + // Load hash data into shared memory so that we can look + // at neighboring body's hash value without loading + // two hash values per thread + sharedHash[get_local_id(0) + 1] = sortedData.x; + if((index > 0) && (get_local_id(0) == 0)) + { + // first thread in block must load neighbor body hash + sharedHash[0] = pHash[index-1].x; + } + } + barrier(CLK_LOCAL_MEM_FENCE); + if(index < numObjects) + { + if((index == 0) || (sortedData.x != sharedHash[get_local_id(0)])) + { + cellStart[sortedData.x] = index; + } + } +} + +int testAABBOverlap(float4 min0, float4 max0, float4 min1, float4 max1) +{ + return (min0.x <= max1.x)&& (min1.x <= max0.x) && + (min0.y <= max1.y)&& (min1.y <= max0.y) && + (min0.z <= max1.z)&& (min1.z <= max0.z); +} + + + + +//search for AABB 'index' against other AABBs' in this cell +void findPairsInCell( int numObjects, + int4 gridPos, + int index, + __global int2* pHash, + __global int* pCellStart, + __global float4* allpAABB, + __global const int* smallAabbMapping, + __global float4* pParams, + volatile __global int* pairCount, + __global int4* pPairBuff2, + int maxPairs + ) +{ + int4 pGridDim = *((__global int4*)(pParams + 1)); + int maxBodiesPerCell = pGridDim.w; + int gridHash = getPosHash(gridPos, pParams); + // get start of bucket for this cell + int bucketStart = pCellStart[gridHash]; + if (bucketStart == -1) + { + return; // cell empty + } + // iterate over bodies in this cell + int2 sortedData = pHash[index]; + int unsorted_indx = sortedData.y; + float4 min0 = allpAABB[smallAabbMapping[unsorted_indx]*2 + 0]; + float4 max0 = allpAABB[smallAabbMapping[unsorted_indx]*2 + 1]; + int handleIndex = as_int(min0.w); + + int bucketEnd = bucketStart + maxBodiesPerCell; + bucketEnd = (bucketEnd > numObjects) ? numObjects : bucketEnd; + for(int index2 = bucketStart; index2 < bucketEnd; index2++) + { + int2 cellData = pHash[index2]; + if (cellData.x != gridHash) + { + break; // no longer in same bucket + } + int unsorted_indx2 = cellData.y; + //if (unsorted_indx2 < unsorted_indx) // check not colliding with self + if (unsorted_indx2 != unsorted_indx) // check not colliding with self + { + float4 min1 = allpAABB[smallAabbMapping[unsorted_indx2]*2 + 0]; + float4 max1 = allpAABB[smallAabbMapping[unsorted_indx2]*2 + 1]; + if(testAABBOverlap(min0, max0, min1, max1)) + { + if (pairCount) + { + int handleIndex2 = as_int(min1.w); + if (handleIndex= numObjects) + { + return; + } + int2 sortedData = pHash[index]; + int unsorted_indx = sortedData.y; + float4 bbMin = allpAABB[smallAabbMapping[unsorted_indx]*2 + 0]; + float4 bbMax = allpAABB[smallAabbMapping[unsorted_indx]*2 + 1]; + float4 pos; + pos.x = (bbMin.x + bbMax.x) * 0.5f; + pos.y = (bbMin.y + bbMax.y) * 0.5f; + pos.z = (bbMin.z + bbMax.z) * 0.5f; + // get address in grid + int4 gridPosA = getGridPos(pos, pParams); + int4 gridPosB; + // examine only neighbouring cells + for(int z=-1; z<=1; z++) + { + gridPosB.z = gridPosA.z + z; + for(int y=-1; y<=1; y++) + { + gridPosB.y = gridPosA.y + y; + for(int x=-1; x<=1; x++) + { + gridPosB.x = gridPosA.x + x; + findPairsInCell(numObjects, gridPosB, index, pHash, pCellStart, allpAABB,smallAabbMapping, pParams, pairCount,pPairBuff2, maxPairs); + } + } + } +} + + + + + diff --git a/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/kernels/gridBroadphaseKernels.h b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/kernels/gridBroadphaseKernels.h new file mode 100644 index 000000000000..dad42477c376 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/kernels/gridBroadphaseKernels.h @@ -0,0 +1,199 @@ +//this file is autogenerated using stringify.bat (premake --stringify) in the build folder of this project +static const char* gridBroadphaseCL= \ +"int getPosHash(int4 gridPos, __global float4* pParams)\n" +"{\n" +" int4 gridDim = *((__global int4*)(pParams + 1));\n" +" gridPos.x &= gridDim.x - 1;\n" +" gridPos.y &= gridDim.y - 1;\n" +" gridPos.z &= gridDim.z - 1;\n" +" int hash = gridPos.z * gridDim.y * gridDim.x + gridPos.y * gridDim.x + gridPos.x;\n" +" return hash;\n" +"} \n" +"int4 getGridPos(float4 worldPos, __global float4* pParams)\n" +"{\n" +" int4 gridPos;\n" +" int4 gridDim = *((__global int4*)(pParams + 1));\n" +" gridPos.x = (int)floor(worldPos.x * pParams[0].x) & (gridDim.x - 1);\n" +" gridPos.y = (int)floor(worldPos.y * pParams[0].y) & (gridDim.y - 1);\n" +" gridPos.z = (int)floor(worldPos.z * pParams[0].z) & (gridDim.z - 1);\n" +" return gridPos;\n" +"}\n" +"// calculate grid hash value for each body using its AABB\n" +"__kernel void kCalcHashAABB(int numObjects, __global float4* allpAABB, __global const int* smallAabbMapping, __global int2* pHash, __global float4* pParams )\n" +"{\n" +" int index = get_global_id(0);\n" +" if(index >= numObjects)\n" +" {\n" +" return;\n" +" }\n" +" float4 bbMin = allpAABB[smallAabbMapping[index]*2];\n" +" float4 bbMax = allpAABB[smallAabbMapping[index]*2 + 1];\n" +" float4 pos;\n" +" pos.x = (bbMin.x + bbMax.x) * 0.5f;\n" +" pos.y = (bbMin.y + bbMax.y) * 0.5f;\n" +" pos.z = (bbMin.z + bbMax.z) * 0.5f;\n" +" pos.w = 0.f;\n" +" // get address in grid\n" +" int4 gridPos = getGridPos(pos, pParams);\n" +" int gridHash = getPosHash(gridPos, pParams);\n" +" // store grid hash and body index\n" +" int2 hashVal;\n" +" hashVal.x = gridHash;\n" +" hashVal.y = index;\n" +" pHash[index] = hashVal;\n" +"}\n" +"__kernel void kClearCellStart( int numCells, \n" +" __global int* pCellStart )\n" +"{\n" +" int index = get_global_id(0);\n" +" if(index >= numCells)\n" +" {\n" +" return;\n" +" }\n" +" pCellStart[index] = -1;\n" +"}\n" +"__kernel void kFindCellStart(int numObjects, __global int2* pHash, __global int* cellStart )\n" +"{\n" +" __local int sharedHash[513];\n" +" int index = get_global_id(0);\n" +" int2 sortedData;\n" +" if(index < numObjects)\n" +" {\n" +" sortedData = pHash[index];\n" +" // Load hash data into shared memory so that we can look \n" +" // at neighboring body's hash value without loading\n" +" // two hash values per thread\n" +" sharedHash[get_local_id(0) + 1] = sortedData.x;\n" +" if((index > 0) && (get_local_id(0) == 0))\n" +" {\n" +" // first thread in block must load neighbor body hash\n" +" sharedHash[0] = pHash[index-1].x;\n" +" }\n" +" }\n" +" barrier(CLK_LOCAL_MEM_FENCE);\n" +" if(index < numObjects)\n" +" {\n" +" if((index == 0) || (sortedData.x != sharedHash[get_local_id(0)]))\n" +" {\n" +" cellStart[sortedData.x] = index;\n" +" }\n" +" }\n" +"}\n" +"int testAABBOverlap(float4 min0, float4 max0, float4 min1, float4 max1)\n" +"{\n" +" return (min0.x <= max1.x)&& (min1.x <= max0.x) && \n" +" (min0.y <= max1.y)&& (min1.y <= max0.y) && \n" +" (min0.z <= max1.z)&& (min1.z <= max0.z); \n" +"}\n" +"//search for AABB 'index' against other AABBs' in this cell\n" +"void findPairsInCell( int numObjects,\n" +" int4 gridPos,\n" +" int index,\n" +" __global int2* pHash,\n" +" __global int* pCellStart,\n" +" __global float4* allpAABB, \n" +" __global const int* smallAabbMapping,\n" +" __global float4* pParams,\n" +" volatile __global int* pairCount,\n" +" __global int4* pPairBuff2,\n" +" int maxPairs\n" +" )\n" +"{\n" +" int4 pGridDim = *((__global int4*)(pParams + 1));\n" +" int maxBodiesPerCell = pGridDim.w;\n" +" int gridHash = getPosHash(gridPos, pParams);\n" +" // get start of bucket for this cell\n" +" int bucketStart = pCellStart[gridHash];\n" +" if (bucketStart == -1)\n" +" {\n" +" return; // cell empty\n" +" }\n" +" // iterate over bodies in this cell\n" +" int2 sortedData = pHash[index];\n" +" int unsorted_indx = sortedData.y;\n" +" float4 min0 = allpAABB[smallAabbMapping[unsorted_indx]*2 + 0]; \n" +" float4 max0 = allpAABB[smallAabbMapping[unsorted_indx]*2 + 1];\n" +" int handleIndex = as_int(min0.w);\n" +" \n" +" int bucketEnd = bucketStart + maxBodiesPerCell;\n" +" bucketEnd = (bucketEnd > numObjects) ? numObjects : bucketEnd;\n" +" for(int index2 = bucketStart; index2 < bucketEnd; index2++) \n" +" {\n" +" int2 cellData = pHash[index2];\n" +" if (cellData.x != gridHash)\n" +" {\n" +" break; // no longer in same bucket\n" +" }\n" +" int unsorted_indx2 = cellData.y;\n" +" //if (unsorted_indx2 < unsorted_indx) // check not colliding with self\n" +" if (unsorted_indx2 != unsorted_indx) // check not colliding with self\n" +" { \n" +" float4 min1 = allpAABB[smallAabbMapping[unsorted_indx2]*2 + 0];\n" +" float4 max1 = allpAABB[smallAabbMapping[unsorted_indx2]*2 + 1];\n" +" if(testAABBOverlap(min0, max0, min1, max1))\n" +" {\n" +" if (pairCount)\n" +" {\n" +" int handleIndex2 = as_int(min1.w);\n" +" if (handleIndex= numObjects)\n" +" {\n" +" return;\n" +" }\n" +" int2 sortedData = pHash[index];\n" +" int unsorted_indx = sortedData.y;\n" +" float4 bbMin = allpAABB[smallAabbMapping[unsorted_indx]*2 + 0];\n" +" float4 bbMax = allpAABB[smallAabbMapping[unsorted_indx]*2 + 1];\n" +" float4 pos;\n" +" pos.x = (bbMin.x + bbMax.x) * 0.5f;\n" +" pos.y = (bbMin.y + bbMax.y) * 0.5f;\n" +" pos.z = (bbMin.z + bbMax.z) * 0.5f;\n" +" // get address in grid\n" +" int4 gridPosA = getGridPos(pos, pParams);\n" +" int4 gridPosB; \n" +" // examine only neighbouring cells\n" +" for(int z=-1; z<=1; z++) \n" +" {\n" +" gridPosB.z = gridPosA.z + z;\n" +" for(int y=-1; y<=1; y++) \n" +" {\n" +" gridPosB.y = gridPosA.y + y;\n" +" for(int x=-1; x<=1; x++) \n" +" {\n" +" gridPosB.x = gridPosA.x + x;\n" +" findPairsInCell(numObjects, gridPosB, index, pHash, pCellStart, allpAABB,smallAabbMapping, pParams, pairCount,pPairBuff2, maxPairs);\n" +" }\n" +" }\n" +" }\n" +"}\n" +; diff --git a/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl new file mode 100644 index 000000000000..c375b9bf37e5 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl @@ -0,0 +1,767 @@ +/* +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. +*/ +//Initial Author Jackson Lee, 2014 + +typedef float b3Scalar; +typedef float4 b3Vector3; +#define b3Max max +#define b3Min min +#define b3Sqrt sqrt + +typedef struct +{ + unsigned int m_key; + unsigned int m_value; +} SortDataCL; + +typedef struct +{ + union + { + float4 m_min; + float m_minElems[4]; + int m_minIndices[4]; + }; + union + { + float4 m_max; + float m_maxElems[4]; + int m_maxIndices[4]; + }; +} b3AabbCL; + + +unsigned int interleaveBits(unsigned int x) +{ + //........ ........ ......12 3456789A //x + //....1..2 ..3..4.. 5..6..7. .8..9..A //x after interleaving bits + + //......12 3456789A ......12 3456789A //x ^ (x << 16) + //11111111 ........ ........ 11111111 //0x FF 00 00 FF + //......12 ........ ........ 3456789A //x = (x ^ (x << 16)) & 0xFF0000FF; + + //......12 ........ 3456789A 3456789A //x ^ (x << 8) + //......11 ........ 1111.... ....1111 //0x 03 00 F0 0F + //......12 ........ 3456.... ....789A //x = (x ^ (x << 8)) & 0x0300F00F; + + //..12..12 ....3456 3456.... 789A789A //x ^ (x << 4) + //......11 ....11.. ..11.... 11....11 //0x 03 0C 30 C3 + //......12 ....34.. ..56.... 78....9A //x = (x ^ (x << 4)) & 0x030C30C3; + + //....1212 ..3434.. 5656..78 78..9A9A //x ^ (x << 2) + //....1..1 ..1..1.. 1..1..1. .1..1..1 //0x 09 24 92 49 + //....1..2 ..3..4.. 5..6..7. .8..9..A //x = (x ^ (x << 2)) & 0x09249249; + + //........ ........ ......11 11111111 //0x000003FF + x &= 0x000003FF; //Clear all bits above bit 10 + + x = (x ^ (x << 16)) & 0xFF0000FF; + x = (x ^ (x << 8)) & 0x0300F00F; + x = (x ^ (x << 4)) & 0x030C30C3; + x = (x ^ (x << 2)) & 0x09249249; + + return x; +} +unsigned int getMortonCode(unsigned int x, unsigned int y, unsigned int z) +{ + return interleaveBits(x) << 0 | interleaveBits(y) << 1 | interleaveBits(z) << 2; +} + +__kernel void separateAabbs(__global b3AabbCL* unseparatedAabbs, __global int* aabbIndices, __global b3AabbCL* out_aabbs, int numAabbsToSeparate) +{ + int separatedAabbIndex = get_global_id(0); + if(separatedAabbIndex >= numAabbsToSeparate) return; + + int unseparatedAabbIndex = aabbIndices[separatedAabbIndex]; + out_aabbs[separatedAabbIndex] = unseparatedAabbs[unseparatedAabbIndex]; +} + +//Should replace with an optimized parallel reduction +__kernel void findAllNodesMergedAabb(__global b3AabbCL* out_mergedAabb, int numAabbsNeedingMerge) +{ + //Each time this kernel is added to the command queue, + //the number of AABBs needing to be merged is halved + // + //Example with 159 AABBs: + // numRemainingAabbs == 159 / 2 + 159 % 2 == 80 + // numMergedAabbs == 159 - 80 == 79 + //So, indices [0, 78] are merged with [0 + 80, 78 + 80] + + int numRemainingAabbs = numAabbsNeedingMerge / 2 + numAabbsNeedingMerge % 2; + int numMergedAabbs = numAabbsNeedingMerge - numRemainingAabbs; + + int aabbIndex = get_global_id(0); + if(aabbIndex >= numMergedAabbs) return; + + int otherAabbIndex = aabbIndex + numRemainingAabbs; + + b3AabbCL aabb = out_mergedAabb[aabbIndex]; + b3AabbCL otherAabb = out_mergedAabb[otherAabbIndex]; + + b3AabbCL mergedAabb; + mergedAabb.m_min = b3Min(aabb.m_min, otherAabb.m_min); + mergedAabb.m_max = b3Max(aabb.m_max, otherAabb.m_max); + out_mergedAabb[aabbIndex] = mergedAabb; +} + +__kernel void assignMortonCodesAndAabbIndicies(__global b3AabbCL* worldSpaceAabbs, __global b3AabbCL* mergedAabbOfAllNodes, + __global SortDataCL* out_mortonCodesAndAabbIndices, int numAabbs) +{ + int leafNodeIndex = get_global_id(0); //Leaf node index == AABB index + if(leafNodeIndex >= numAabbs) return; + + b3AabbCL mergedAabb = mergedAabbOfAllNodes[0]; + b3Vector3 gridCenter = (mergedAabb.m_min + mergedAabb.m_max) * 0.5f; + b3Vector3 gridCellSize = (mergedAabb.m_max - mergedAabb.m_min) / (float)1024; + + b3AabbCL aabb = worldSpaceAabbs[leafNodeIndex]; + b3Vector3 aabbCenter = (aabb.m_min + aabb.m_max) * 0.5f; + b3Vector3 aabbCenterRelativeToGrid = aabbCenter - gridCenter; + + //Quantize into integer coordinates + //floor() is needed to prevent the center cell, at (0,0,0) from being twice the size + b3Vector3 gridPosition = aabbCenterRelativeToGrid / gridCellSize; + + int4 discretePosition; + discretePosition.x = (int)( (gridPosition.x >= 0.0f) ? gridPosition.x : floor(gridPosition.x) ); + discretePosition.y = (int)( (gridPosition.y >= 0.0f) ? gridPosition.y : floor(gridPosition.y) ); + discretePosition.z = (int)( (gridPosition.z >= 0.0f) ? gridPosition.z : floor(gridPosition.z) ); + + //Clamp coordinates into [-512, 511], then convert range from [-512, 511] to [0, 1023] + discretePosition = b3Max( -512, b3Min(discretePosition, 511) ); + discretePosition += 512; + + //Interleave bits(assign a morton code, also known as a z-curve) + unsigned int mortonCode = getMortonCode(discretePosition.x, discretePosition.y, discretePosition.z); + + // + SortDataCL mortonCodeIndexPair; + mortonCodeIndexPair.m_key = mortonCode; + mortonCodeIndexPair.m_value = leafNodeIndex; + + out_mortonCodesAndAabbIndices[leafNodeIndex] = mortonCodeIndexPair; +} + +#define B3_PLVBH_TRAVERSE_MAX_STACK_SIZE 128 + +//The most significant bit(0x80000000) of a int32 is used to distinguish between leaf and internal nodes. +//If it is set, then the index is for an internal node; otherwise, it is a leaf node. +//In both cases, the bit should be cleared to access the actual node index. +int isLeafNode(int index) { return (index >> 31 == 0); } +int getIndexWithInternalNodeMarkerRemoved(int index) { return index & (~0x80000000); } +int getIndexWithInternalNodeMarkerSet(int isLeaf, int index) { return (isLeaf) ? index : (index | 0x80000000); } + +//From sap.cl +#define NEW_PAIR_MARKER -1 + +bool TestAabbAgainstAabb2(const b3AabbCL* aabb1, const b3AabbCL* aabb2) +{ + bool overlap = true; + overlap = (aabb1->m_min.x > aabb2->m_max.x || aabb1->m_max.x < aabb2->m_min.x) ? false : overlap; + overlap = (aabb1->m_min.z > aabb2->m_max.z || aabb1->m_max.z < aabb2->m_min.z) ? false : overlap; + overlap = (aabb1->m_min.y > aabb2->m_max.y || aabb1->m_max.y < aabb2->m_min.y) ? false : overlap; + return overlap; +} +//From sap.cl + +__kernel void plbvhCalculateOverlappingPairs(__global b3AabbCL* rigidAabbs, + + __global int* rootNodeIndex, + __global int2* internalNodeChildIndices, + __global b3AabbCL* internalNodeAabbs, + __global int2* internalNodeLeafIndexRanges, + + __global SortDataCL* mortonCodesAndAabbIndices, + __global int* out_numPairs, __global int4* out_overlappingPairs, + int maxPairs, int numQueryAabbs) +{ + //Using get_group_id()/get_local_id() is Faster than get_global_id(0) since + //mortonCodesAndAabbIndices[] contains rigid body indices sorted along the z-curve (more spatially coherent) + int queryBvhNodeIndex = get_group_id(0) * get_local_size(0) + get_local_id(0); + if(queryBvhNodeIndex >= numQueryAabbs) return; + + int queryRigidIndex = mortonCodesAndAabbIndices[queryBvhNodeIndex].m_value; + b3AabbCL queryAabb = rigidAabbs[queryRigidIndex]; + + int stack[B3_PLVBH_TRAVERSE_MAX_STACK_SIZE]; + + int stackSize = 1; + stack[0] = *rootNodeIndex; + + while(stackSize) + { + int internalOrLeafNodeIndex = stack[ stackSize - 1 ]; + --stackSize; + + int isLeaf = isLeafNode(internalOrLeafNodeIndex); //Internal node if false + int bvhNodeIndex = getIndexWithInternalNodeMarkerRemoved(internalOrLeafNodeIndex); + + //Optimization - if the BVH is structured as a binary radix tree, then + //each internal node corresponds to a contiguous range of leaf nodes(internalNodeLeafIndexRanges[]). + //This can be used to avoid testing each AABB-AABB pair twice, including preventing each node from colliding with itself. + { + int highestLeafIndex = (isLeaf) ? bvhNodeIndex : internalNodeLeafIndexRanges[bvhNodeIndex].y; + if(highestLeafIndex <= queryBvhNodeIndex) continue; + } + + //bvhRigidIndex is not used if internal node + int bvhRigidIndex = (isLeaf) ? mortonCodesAndAabbIndices[bvhNodeIndex].m_value : -1; + + b3AabbCL bvhNodeAabb = (isLeaf) ? rigidAabbs[bvhRigidIndex] : internalNodeAabbs[bvhNodeIndex]; + if( TestAabbAgainstAabb2(&queryAabb, &bvhNodeAabb) ) + { + if(isLeaf) + { + int4 pair; + pair.x = rigidAabbs[queryRigidIndex].m_minIndices[3]; + pair.y = rigidAabbs[bvhRigidIndex].m_minIndices[3]; + pair.z = NEW_PAIR_MARKER; + pair.w = NEW_PAIR_MARKER; + + int pairIndex = atomic_inc(out_numPairs); + if(pairIndex < maxPairs) out_overlappingPairs[pairIndex] = pair; + } + + if(!isLeaf) //Internal node + { + if(stackSize + 2 > B3_PLVBH_TRAVERSE_MAX_STACK_SIZE) + { + //Error + } + else + { + stack[ stackSize++ ] = internalNodeChildIndices[bvhNodeIndex].x; + stack[ stackSize++ ] = internalNodeChildIndices[bvhNodeIndex].y; + } + } + } + + } +} + + +//From rayCastKernels.cl +typedef struct +{ + float4 m_from; + float4 m_to; +} b3RayInfo; +//From rayCastKernels.cl + +b3Vector3 b3Vector3_normalize(b3Vector3 v) +{ + b3Vector3 normal = (b3Vector3){v.x, v.y, v.z, 0.f}; + return normalize(normal); //OpenCL normalize == vector4 normalize +} +b3Scalar b3Vector3_length2(b3Vector3 v) { return v.x*v.x + v.y*v.y + v.z*v.z; } +b3Scalar b3Vector3_dot(b3Vector3 a, b3Vector3 b) { return a.x*b.x + a.y*b.y + a.z*b.z; } + +int rayIntersectsAabb(b3Vector3 rayOrigin, b3Scalar rayLength, b3Vector3 rayNormalizedDirection, b3AabbCL aabb) +{ + //AABB is considered as 3 pairs of 2 planes( {x_min, x_max}, {y_min, y_max}, {z_min, z_max} ). + //t_min is the point of intersection with the closer plane, t_max is the point of intersection with the farther plane. + // + //if (rayNormalizedDirection.x < 0.0f), then max.x will be the near plane + //and min.x will be the far plane; otherwise, it is reversed. + // + //In order for there to be a collision, the t_min and t_max of each pair must overlap. + //This can be tested for by selecting the highest t_min and lowest t_max and comparing them. + + int4 isNegative = isless( rayNormalizedDirection, ((b3Vector3){0.0f, 0.0f, 0.0f, 0.0f}) ); //isless(x,y) returns (x < y) + + //When using vector types, the select() function checks the most signficant bit, + //but isless() sets the least significant bit. + isNegative <<= 31; + + //select(b, a, condition) == condition ? a : b + //When using select() with vector types, (condition[i]) is true if its most significant bit is 1 + b3Vector3 t_min = ( select(aabb.m_min, aabb.m_max, isNegative) - rayOrigin ) / rayNormalizedDirection; + b3Vector3 t_max = ( select(aabb.m_max, aabb.m_min, isNegative) - rayOrigin ) / rayNormalizedDirection; + + b3Scalar t_min_final = 0.0f; + b3Scalar t_max_final = rayLength; + + //Must use fmin()/fmax(); if one of the parameters is NaN, then the parameter that is not NaN is returned. + //Behavior of min()/max() with NaNs is undefined. (See OpenCL Specification 1.2 [6.12.2] and [6.12.4]) + //Since the innermost fmin()/fmax() is always not NaN, this should never return NaN. + t_min_final = fmax( t_min.z, fmax(t_min.y, fmax(t_min.x, t_min_final)) ); + t_max_final = fmin( t_max.z, fmin(t_max.y, fmin(t_max.x, t_max_final)) ); + + return (t_min_final <= t_max_final); +} + +__kernel void plbvhRayTraverse(__global b3AabbCL* rigidAabbs, + + __global int* rootNodeIndex, + __global int2* internalNodeChildIndices, + __global b3AabbCL* internalNodeAabbs, + __global int2* internalNodeLeafIndexRanges, + __global SortDataCL* mortonCodesAndAabbIndices, + + __global b3RayInfo* rays, + + __global int* out_numRayRigidPairs, + __global int2* out_rayRigidPairs, + int maxRayRigidPairs, int numRays) +{ + int rayIndex = get_global_id(0); + if(rayIndex >= numRays) return; + + // + b3Vector3 rayFrom = rays[rayIndex].m_from; + b3Vector3 rayTo = rays[rayIndex].m_to; + b3Vector3 rayNormalizedDirection = b3Vector3_normalize(rayTo - rayFrom); + b3Scalar rayLength = b3Sqrt( b3Vector3_length2(rayTo - rayFrom) ); + + // + int stack[B3_PLVBH_TRAVERSE_MAX_STACK_SIZE]; + + int stackSize = 1; + stack[0] = *rootNodeIndex; + + while(stackSize) + { + int internalOrLeafNodeIndex = stack[ stackSize - 1 ]; + --stackSize; + + int isLeaf = isLeafNode(internalOrLeafNodeIndex); //Internal node if false + int bvhNodeIndex = getIndexWithInternalNodeMarkerRemoved(internalOrLeafNodeIndex); + + //bvhRigidIndex is not used if internal node + int bvhRigidIndex = (isLeaf) ? mortonCodesAndAabbIndices[bvhNodeIndex].m_value : -1; + + b3AabbCL bvhNodeAabb = (isLeaf) ? rigidAabbs[bvhRigidIndex] : internalNodeAabbs[bvhNodeIndex]; + if( rayIntersectsAabb(rayFrom, rayLength, rayNormalizedDirection, bvhNodeAabb) ) + { + if(isLeaf) + { + int2 rayRigidPair; + rayRigidPair.x = rayIndex; + rayRigidPair.y = rigidAabbs[bvhRigidIndex].m_minIndices[3]; + + int pairIndex = atomic_inc(out_numRayRigidPairs); + if(pairIndex < maxRayRigidPairs) out_rayRigidPairs[pairIndex] = rayRigidPair; + } + + if(!isLeaf) //Internal node + { + if(stackSize + 2 > B3_PLVBH_TRAVERSE_MAX_STACK_SIZE) + { + //Error + } + else + { + stack[ stackSize++ ] = internalNodeChildIndices[bvhNodeIndex].x; + stack[ stackSize++ ] = internalNodeChildIndices[bvhNodeIndex].y; + } + } + } + } +} + +__kernel void plbvhLargeAabbAabbTest(__global b3AabbCL* smallAabbs, __global b3AabbCL* largeAabbs, + __global int* out_numPairs, __global int4* out_overlappingPairs, + int maxPairs, int numLargeAabbRigids, int numSmallAabbRigids) +{ + int smallAabbIndex = get_global_id(0); + if(smallAabbIndex >= numSmallAabbRigids) return; + + b3AabbCL smallAabb = smallAabbs[smallAabbIndex]; + for(int i = 0; i < numLargeAabbRigids; ++i) + { + b3AabbCL largeAabb = largeAabbs[i]; + if( TestAabbAgainstAabb2(&smallAabb, &largeAabb) ) + { + int4 pair; + pair.x = largeAabb.m_minIndices[3]; + pair.y = smallAabb.m_minIndices[3]; + pair.z = NEW_PAIR_MARKER; + pair.w = NEW_PAIR_MARKER; + + int pairIndex = atomic_inc(out_numPairs); + if(pairIndex < maxPairs) out_overlappingPairs[pairIndex] = pair; + } + } +} +__kernel void plbvhLargeAabbRayTest(__global b3AabbCL* largeRigidAabbs, __global b3RayInfo* rays, + __global int* out_numRayRigidPairs, __global int2* out_rayRigidPairs, + int numLargeAabbRigids, int maxRayRigidPairs, int numRays) +{ + int rayIndex = get_global_id(0); + if(rayIndex >= numRays) return; + + b3Vector3 rayFrom = rays[rayIndex].m_from; + b3Vector3 rayTo = rays[rayIndex].m_to; + b3Vector3 rayNormalizedDirection = b3Vector3_normalize(rayTo - rayFrom); + b3Scalar rayLength = b3Sqrt( b3Vector3_length2(rayTo - rayFrom) ); + + for(int i = 0; i < numLargeAabbRigids; ++i) + { + b3AabbCL rigidAabb = largeRigidAabbs[i]; + if( rayIntersectsAabb(rayFrom, rayLength, rayNormalizedDirection, rigidAabb) ) + { + int2 rayRigidPair; + rayRigidPair.x = rayIndex; + rayRigidPair.y = rigidAabb.m_minIndices[3]; + + int pairIndex = atomic_inc(out_numRayRigidPairs); + if(pairIndex < maxRayRigidPairs) out_rayRigidPairs[pairIndex] = rayRigidPair; + } + } +} + + +//Set so that it is always greater than the actual common prefixes, and never selected as a parent node. +//If there are no duplicates, then the highest common prefix is 32 or 64, depending on the number of bits used for the z-curve. +//Duplicate common prefixes increase the highest common prefix at most by the number of bits used to index the leaf node. +//Since 32 bit ints are used to index leaf nodes, the max prefix is 64(32 + 32 bit z-curve) or 96(32 + 64 bit z-curve). +#define B3_PLBVH_INVALID_COMMON_PREFIX 128 + +#define B3_PLBVH_ROOT_NODE_MARKER -1 + +#define b3Int64 long + +int computeCommonPrefixLength(b3Int64 i, b3Int64 j) { return (int)clz(i ^ j); } +b3Int64 computeCommonPrefix(b3Int64 i, b3Int64 j) +{ + //This function only needs to return (i & j) in order for the algorithm to work, + //but it may help with debugging to mask out the lower bits. + + b3Int64 commonPrefixLength = (b3Int64)computeCommonPrefixLength(i, j); + + b3Int64 sharedBits = i & j; + b3Int64 bitmask = ((b3Int64)(~0)) << (64 - commonPrefixLength); //Set all bits after the common prefix to 0 + + return sharedBits & bitmask; +} + +//Same as computeCommonPrefixLength(), but allows for prefixes with different lengths +int getSharedPrefixLength(b3Int64 prefixA, int prefixLengthA, b3Int64 prefixB, int prefixLengthB) +{ + return b3Min( computeCommonPrefixLength(prefixA, prefixB), b3Min(prefixLengthA, prefixLengthB) ); +} + +__kernel void computeAdjacentPairCommonPrefix(__global SortDataCL* mortonCodesAndAabbIndices, + __global b3Int64* out_commonPrefixes, + __global int* out_commonPrefixLengths, + int numInternalNodes) +{ + int internalNodeIndex = get_global_id(0); + if (internalNodeIndex >= numInternalNodes) return; + + //Here, (internalNodeIndex + 1) is never out of bounds since it is a leaf node index, + //and the number of internal nodes is always numLeafNodes - 1 + int leftLeafIndex = internalNodeIndex; + int rightLeafIndex = internalNodeIndex + 1; + + int leftLeafMortonCode = mortonCodesAndAabbIndices[leftLeafIndex].m_key; + int rightLeafMortonCode = mortonCodesAndAabbIndices[rightLeafIndex].m_key; + + //Binary radix tree construction algorithm does not work if there are duplicate morton codes. + //Append the index of each leaf node to each morton code so that there are no duplicates. + //The algorithm also requires that the morton codes are sorted in ascending order; this requirement + //is also satisfied with this method, as (leftLeafIndex < rightLeafIndex) is always true. + // + //upsample(a, b) == ( ((b3Int64)a) << 32) | b + b3Int64 nonduplicateLeftMortonCode = upsample(leftLeafMortonCode, leftLeafIndex); + b3Int64 nonduplicateRightMortonCode = upsample(rightLeafMortonCode, rightLeafIndex); + + out_commonPrefixes[internalNodeIndex] = computeCommonPrefix(nonduplicateLeftMortonCode, nonduplicateRightMortonCode); + out_commonPrefixLengths[internalNodeIndex] = computeCommonPrefixLength(nonduplicateLeftMortonCode, nonduplicateRightMortonCode); +} + + +__kernel void buildBinaryRadixTreeLeafNodes(__global int* commonPrefixLengths, __global int* out_leafNodeParentNodes, + __global int2* out_childNodes, int numLeafNodes) +{ + int leafNodeIndex = get_global_id(0); + if (leafNodeIndex >= numLeafNodes) return; + + int numInternalNodes = numLeafNodes - 1; + + int leftSplitIndex = leafNodeIndex - 1; + int rightSplitIndex = leafNodeIndex; + + int leftCommonPrefix = (leftSplitIndex >= 0) ? commonPrefixLengths[leftSplitIndex] : B3_PLBVH_INVALID_COMMON_PREFIX; + int rightCommonPrefix = (rightSplitIndex < numInternalNodes) ? commonPrefixLengths[rightSplitIndex] : B3_PLBVH_INVALID_COMMON_PREFIX; + + //Parent node is the highest adjacent common prefix that is lower than the node's common prefix + //Leaf nodes are considered as having the highest common prefix + int isLeftHigherCommonPrefix = (leftCommonPrefix > rightCommonPrefix); + + //Handle cases for the edge nodes; the first and last node + //For leaf nodes, leftCommonPrefix and rightCommonPrefix should never both be B3_PLBVH_INVALID_COMMON_PREFIX + if(leftCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherCommonPrefix = false; + if(rightCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherCommonPrefix = true; + + int parentNodeIndex = (isLeftHigherCommonPrefix) ? leftSplitIndex : rightSplitIndex; + out_leafNodeParentNodes[leafNodeIndex] = parentNodeIndex; + + int isRightChild = (isLeftHigherCommonPrefix); //If the left node is the parent, then this node is its right child and vice versa + + //out_childNodesAsInt[0] == int2.x == left child + //out_childNodesAsInt[1] == int2.y == right child + int isLeaf = 1; + __global int* out_childNodesAsInt = (__global int*)(&out_childNodes[parentNodeIndex]); + out_childNodesAsInt[isRightChild] = getIndexWithInternalNodeMarkerSet(isLeaf, leafNodeIndex); +} + +__kernel void buildBinaryRadixTreeInternalNodes(__global b3Int64* commonPrefixes, __global int* commonPrefixLengths, + __global int2* out_childNodes, + __global int* out_internalNodeParentNodes, __global int* out_rootNodeIndex, + int numInternalNodes) +{ + int internalNodeIndex = get_group_id(0) * get_local_size(0) + get_local_id(0); + if(internalNodeIndex >= numInternalNodes) return; + + b3Int64 nodePrefix = commonPrefixes[internalNodeIndex]; + int nodePrefixLength = commonPrefixLengths[internalNodeIndex]; + +//#define USE_LINEAR_SEARCH +#ifdef USE_LINEAR_SEARCH + int leftIndex = -1; + int rightIndex = -1; + + //Find nearest element to left with a lower common prefix + for(int i = internalNodeIndex - 1; i >= 0; --i) + { + int nodeLeftSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, commonPrefixes[i], commonPrefixLengths[i]); + if(nodeLeftSharedPrefixLength < nodePrefixLength) + { + leftIndex = i; + break; + } + } + + //Find nearest element to right with a lower common prefix + for(int i = internalNodeIndex + 1; i < numInternalNodes; ++i) + { + int nodeRightSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, commonPrefixes[i], commonPrefixLengths[i]); + if(nodeRightSharedPrefixLength < nodePrefixLength) + { + rightIndex = i; + break; + } + } + +#else //Use binary search + + //Find nearest element to left with a lower common prefix + int leftIndex = -1; + { + int lower = 0; + int upper = internalNodeIndex - 1; + + while(lower <= upper) + { + int mid = (lower + upper) / 2; + b3Int64 midPrefix = commonPrefixes[mid]; + int midPrefixLength = commonPrefixLengths[mid]; + + int nodeMidSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, midPrefix, midPrefixLength); + if(nodeMidSharedPrefixLength < nodePrefixLength) + { + int right = mid + 1; + if(right < internalNodeIndex) + { + b3Int64 rightPrefix = commonPrefixes[right]; + int rightPrefixLength = commonPrefixLengths[right]; + + int nodeRightSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, rightPrefix, rightPrefixLength); + if(nodeRightSharedPrefixLength < nodePrefixLength) + { + lower = right; + leftIndex = right; + } + else + { + leftIndex = mid; + break; + } + } + else + { + leftIndex = mid; + break; + } + } + else upper = mid - 1; + } + } + + //Find nearest element to right with a lower common prefix + int rightIndex = -1; + { + int lower = internalNodeIndex + 1; + int upper = numInternalNodes - 1; + + while(lower <= upper) + { + int mid = (lower + upper) / 2; + b3Int64 midPrefix = commonPrefixes[mid]; + int midPrefixLength = commonPrefixLengths[mid]; + + int nodeMidSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, midPrefix, midPrefixLength); + if(nodeMidSharedPrefixLength < nodePrefixLength) + { + int left = mid - 1; + if(left > internalNodeIndex) + { + b3Int64 leftPrefix = commonPrefixes[left]; + int leftPrefixLength = commonPrefixLengths[left]; + + int nodeLeftSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, leftPrefix, leftPrefixLength); + if(nodeLeftSharedPrefixLength < nodePrefixLength) + { + upper = left; + rightIndex = left; + } + else + { + rightIndex = mid; + break; + } + } + else + { + rightIndex = mid; + break; + } + } + else lower = mid + 1; + } + } +#endif + + //Select parent + { + int leftPrefixLength = (leftIndex != -1) ? commonPrefixLengths[leftIndex] : B3_PLBVH_INVALID_COMMON_PREFIX; + int rightPrefixLength = (rightIndex != -1) ? commonPrefixLengths[rightIndex] : B3_PLBVH_INVALID_COMMON_PREFIX; + + int isLeftHigherPrefixLength = (leftPrefixLength > rightPrefixLength); + + if(leftPrefixLength == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherPrefixLength = false; + else if(rightPrefixLength == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherPrefixLength = true; + + int parentNodeIndex = (isLeftHigherPrefixLength) ? leftIndex : rightIndex; + + int isRootNode = (leftIndex == -1 && rightIndex == -1); + out_internalNodeParentNodes[internalNodeIndex] = (!isRootNode) ? parentNodeIndex : B3_PLBVH_ROOT_NODE_MARKER; + + int isLeaf = 0; + if(!isRootNode) + { + int isRightChild = (isLeftHigherPrefixLength); //If the left node is the parent, then this node is its right child and vice versa + + //out_childNodesAsInt[0] == int2.x == left child + //out_childNodesAsInt[1] == int2.y == right child + __global int* out_childNodesAsInt = (__global int*)(&out_childNodes[parentNodeIndex]); + out_childNodesAsInt[isRightChild] = getIndexWithInternalNodeMarkerSet(isLeaf, internalNodeIndex); + } + else *out_rootNodeIndex = getIndexWithInternalNodeMarkerSet(isLeaf, internalNodeIndex); + } +} + +__kernel void findDistanceFromRoot(__global int* rootNodeIndex, __global int* internalNodeParentNodes, + __global int* out_maxDistanceFromRoot, __global int* out_distanceFromRoot, int numInternalNodes) +{ + if( get_global_id(0) == 0 ) atomic_xchg(out_maxDistanceFromRoot, 0); + + int internalNodeIndex = get_global_id(0); + if(internalNodeIndex >= numInternalNodes) return; + + // + int distanceFromRoot = 0; + { + int parentIndex = internalNodeParentNodes[internalNodeIndex]; + while(parentIndex != B3_PLBVH_ROOT_NODE_MARKER) + { + parentIndex = internalNodeParentNodes[parentIndex]; + ++distanceFromRoot; + } + } + out_distanceFromRoot[internalNodeIndex] = distanceFromRoot; + + // + __local int localMaxDistanceFromRoot; + if( get_local_id(0) == 0 ) localMaxDistanceFromRoot = 0; + barrier(CLK_LOCAL_MEM_FENCE); + + atomic_max(&localMaxDistanceFromRoot, distanceFromRoot); + barrier(CLK_LOCAL_MEM_FENCE); + + if( get_local_id(0) == 0 ) atomic_max(out_maxDistanceFromRoot, localMaxDistanceFromRoot); +} + +__kernel void buildBinaryRadixTreeAabbsRecursive(__global int* distanceFromRoot, __global SortDataCL* mortonCodesAndAabbIndices, + __global int2* childNodes, + __global b3AabbCL* leafNodeAabbs, __global b3AabbCL* internalNodeAabbs, + int maxDistanceFromRoot, int processedDistance, int numInternalNodes) +{ + int internalNodeIndex = get_global_id(0); + if(internalNodeIndex >= numInternalNodes) return; + + int distance = distanceFromRoot[internalNodeIndex]; + + if(distance == processedDistance) + { + int leftChildIndex = childNodes[internalNodeIndex].x; + int rightChildIndex = childNodes[internalNodeIndex].y; + + int isLeftChildLeaf = isLeafNode(leftChildIndex); + int isRightChildLeaf = isLeafNode(rightChildIndex); + + leftChildIndex = getIndexWithInternalNodeMarkerRemoved(leftChildIndex); + rightChildIndex = getIndexWithInternalNodeMarkerRemoved(rightChildIndex); + + //leftRigidIndex/rightRigidIndex is not used if internal node + int leftRigidIndex = (isLeftChildLeaf) ? mortonCodesAndAabbIndices[leftChildIndex].m_value : -1; + int rightRigidIndex = (isRightChildLeaf) ? mortonCodesAndAabbIndices[rightChildIndex].m_value : -1; + + b3AabbCL leftChildAabb = (isLeftChildLeaf) ? leafNodeAabbs[leftRigidIndex] : internalNodeAabbs[leftChildIndex]; + b3AabbCL rightChildAabb = (isRightChildLeaf) ? leafNodeAabbs[rightRigidIndex] : internalNodeAabbs[rightChildIndex]; + + b3AabbCL mergedAabb; + mergedAabb.m_min = b3Min(leftChildAabb.m_min, rightChildAabb.m_min); + mergedAabb.m_max = b3Max(leftChildAabb.m_max, rightChildAabb.m_max); + internalNodeAabbs[internalNodeIndex] = mergedAabb; + } +} + +__kernel void findLeafIndexRanges(__global int2* internalNodeChildNodes, __global int2* out_leafIndexRanges, int numInternalNodes) +{ + int internalNodeIndex = get_global_id(0); + if(internalNodeIndex >= numInternalNodes) return; + + int numLeafNodes = numInternalNodes + 1; + + int2 childNodes = internalNodeChildNodes[internalNodeIndex]; + + int2 leafIndexRange; //x == min leaf index, y == max leaf index + + //Find lowest leaf index covered by this internal node + { + int lowestIndex = childNodes.x; //childNodes.x == Left child + while( !isLeafNode(lowestIndex) ) lowestIndex = internalNodeChildNodes[ getIndexWithInternalNodeMarkerRemoved(lowestIndex) ].x; + leafIndexRange.x = lowestIndex; + } + + //Find highest leaf index covered by this internal node + { + int highestIndex = childNodes.y; //childNodes.y == Right child + while( !isLeafNode(highestIndex) ) highestIndex = internalNodeChildNodes[ getIndexWithInternalNodeMarkerRemoved(highestIndex) ].y; + leafIndexRange.y = highestIndex; + } + + // + out_leafIndexRanges[internalNodeIndex] = leafIndexRange; +} diff --git a/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h new file mode 100644 index 000000000000..5eb8f45b164e --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h @@ -0,0 +1,729 @@ +//this file is autogenerated using stringify.bat (premake --stringify) in the build folder of this project +static const char* parallelLinearBvhCL= \ +"/*\n" +"This software is provided 'as-is', without any express or implied warranty.\n" +"In no event will the authors be held liable for any damages arising from the use of this software.\n" +"Permission is granted to anyone to use this software for any purpose,\n" +"including commercial applications, and to alter it and redistribute it freely,\n" +"subject to the following restrictions:\n" +"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.\n" +"2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n" +"3. This notice may not be removed or altered from any source distribution.\n" +"*/\n" +"//Initial Author Jackson Lee, 2014\n" +"typedef float b3Scalar;\n" +"typedef float4 b3Vector3;\n" +"#define b3Max max\n" +"#define b3Min min\n" +"#define b3Sqrt sqrt\n" +"typedef struct\n" +"{\n" +" unsigned int m_key;\n" +" unsigned int m_value;\n" +"} SortDataCL;\n" +"typedef struct \n" +"{\n" +" union\n" +" {\n" +" float4 m_min;\n" +" float m_minElems[4];\n" +" int m_minIndices[4];\n" +" };\n" +" union\n" +" {\n" +" float4 m_max;\n" +" float m_maxElems[4];\n" +" int m_maxIndices[4];\n" +" };\n" +"} b3AabbCL;\n" +"unsigned int interleaveBits(unsigned int x)\n" +"{\n" +" //........ ........ ......12 3456789A //x\n" +" //....1..2 ..3..4.. 5..6..7. .8..9..A //x after interleaving bits\n" +" \n" +" //......12 3456789A ......12 3456789A //x ^ (x << 16)\n" +" //11111111 ........ ........ 11111111 //0x FF 00 00 FF\n" +" //......12 ........ ........ 3456789A //x = (x ^ (x << 16)) & 0xFF0000FF;\n" +" \n" +" //......12 ........ 3456789A 3456789A //x ^ (x << 8)\n" +" //......11 ........ 1111.... ....1111 //0x 03 00 F0 0F\n" +" //......12 ........ 3456.... ....789A //x = (x ^ (x << 8)) & 0x0300F00F;\n" +" \n" +" //..12..12 ....3456 3456.... 789A789A //x ^ (x << 4)\n" +" //......11 ....11.. ..11.... 11....11 //0x 03 0C 30 C3\n" +" //......12 ....34.. ..56.... 78....9A //x = (x ^ (x << 4)) & 0x030C30C3;\n" +" \n" +" //....1212 ..3434.. 5656..78 78..9A9A //x ^ (x << 2)\n" +" //....1..1 ..1..1.. 1..1..1. .1..1..1 //0x 09 24 92 49\n" +" //....1..2 ..3..4.. 5..6..7. .8..9..A //x = (x ^ (x << 2)) & 0x09249249;\n" +" \n" +" //........ ........ ......11 11111111 //0x000003FF\n" +" x &= 0x000003FF; //Clear all bits above bit 10\n" +" \n" +" x = (x ^ (x << 16)) & 0xFF0000FF;\n" +" x = (x ^ (x << 8)) & 0x0300F00F;\n" +" x = (x ^ (x << 4)) & 0x030C30C3;\n" +" x = (x ^ (x << 2)) & 0x09249249;\n" +" \n" +" return x;\n" +"}\n" +"unsigned int getMortonCode(unsigned int x, unsigned int y, unsigned int z)\n" +"{\n" +" return interleaveBits(x) << 0 | interleaveBits(y) << 1 | interleaveBits(z) << 2;\n" +"}\n" +"__kernel void separateAabbs(__global b3AabbCL* unseparatedAabbs, __global int* aabbIndices, __global b3AabbCL* out_aabbs, int numAabbsToSeparate)\n" +"{\n" +" int separatedAabbIndex = get_global_id(0);\n" +" if(separatedAabbIndex >= numAabbsToSeparate) return;\n" +" int unseparatedAabbIndex = aabbIndices[separatedAabbIndex];\n" +" out_aabbs[separatedAabbIndex] = unseparatedAabbs[unseparatedAabbIndex];\n" +"}\n" +"//Should replace with an optimized parallel reduction\n" +"__kernel void findAllNodesMergedAabb(__global b3AabbCL* out_mergedAabb, int numAabbsNeedingMerge)\n" +"{\n" +" //Each time this kernel is added to the command queue, \n" +" //the number of AABBs needing to be merged is halved\n" +" //\n" +" //Example with 159 AABBs:\n" +" // numRemainingAabbs == 159 / 2 + 159 % 2 == 80\n" +" // numMergedAabbs == 159 - 80 == 79\n" +" //So, indices [0, 78] are merged with [0 + 80, 78 + 80]\n" +" \n" +" int numRemainingAabbs = numAabbsNeedingMerge / 2 + numAabbsNeedingMerge % 2;\n" +" int numMergedAabbs = numAabbsNeedingMerge - numRemainingAabbs;\n" +" \n" +" int aabbIndex = get_global_id(0);\n" +" if(aabbIndex >= numMergedAabbs) return;\n" +" \n" +" int otherAabbIndex = aabbIndex + numRemainingAabbs;\n" +" \n" +" b3AabbCL aabb = out_mergedAabb[aabbIndex];\n" +" b3AabbCL otherAabb = out_mergedAabb[otherAabbIndex];\n" +" \n" +" b3AabbCL mergedAabb;\n" +" mergedAabb.m_min = b3Min(aabb.m_min, otherAabb.m_min);\n" +" mergedAabb.m_max = b3Max(aabb.m_max, otherAabb.m_max);\n" +" out_mergedAabb[aabbIndex] = mergedAabb;\n" +"}\n" +"__kernel void assignMortonCodesAndAabbIndicies(__global b3AabbCL* worldSpaceAabbs, __global b3AabbCL* mergedAabbOfAllNodes, \n" +" __global SortDataCL* out_mortonCodesAndAabbIndices, int numAabbs)\n" +"{\n" +" int leafNodeIndex = get_global_id(0); //Leaf node index == AABB index\n" +" if(leafNodeIndex >= numAabbs) return;\n" +" \n" +" b3AabbCL mergedAabb = mergedAabbOfAllNodes[0];\n" +" b3Vector3 gridCenter = (mergedAabb.m_min + mergedAabb.m_max) * 0.5f;\n" +" b3Vector3 gridCellSize = (mergedAabb.m_max - mergedAabb.m_min) / (float)1024;\n" +" \n" +" b3AabbCL aabb = worldSpaceAabbs[leafNodeIndex];\n" +" b3Vector3 aabbCenter = (aabb.m_min + aabb.m_max) * 0.5f;\n" +" b3Vector3 aabbCenterRelativeToGrid = aabbCenter - gridCenter;\n" +" \n" +" //Quantize into integer coordinates\n" +" //floor() is needed to prevent the center cell, at (0,0,0) from being twice the size\n" +" b3Vector3 gridPosition = aabbCenterRelativeToGrid / gridCellSize;\n" +" \n" +" int4 discretePosition;\n" +" discretePosition.x = (int)( (gridPosition.x >= 0.0f) ? gridPosition.x : floor(gridPosition.x) );\n" +" discretePosition.y = (int)( (gridPosition.y >= 0.0f) ? gridPosition.y : floor(gridPosition.y) );\n" +" discretePosition.z = (int)( (gridPosition.z >= 0.0f) ? gridPosition.z : floor(gridPosition.z) );\n" +" \n" +" //Clamp coordinates into [-512, 511], then convert range from [-512, 511] to [0, 1023]\n" +" discretePosition = b3Max( -512, b3Min(discretePosition, 511) );\n" +" discretePosition += 512;\n" +" \n" +" //Interleave bits(assign a morton code, also known as a z-curve)\n" +" unsigned int mortonCode = getMortonCode(discretePosition.x, discretePosition.y, discretePosition.z);\n" +" \n" +" //\n" +" SortDataCL mortonCodeIndexPair;\n" +" mortonCodeIndexPair.m_key = mortonCode;\n" +" mortonCodeIndexPair.m_value = leafNodeIndex;\n" +" \n" +" out_mortonCodesAndAabbIndices[leafNodeIndex] = mortonCodeIndexPair;\n" +"}\n" +"#define B3_PLVBH_TRAVERSE_MAX_STACK_SIZE 128\n" +"//The most significant bit(0x80000000) of a int32 is used to distinguish between leaf and internal nodes.\n" +"//If it is set, then the index is for an internal node; otherwise, it is a leaf node. \n" +"//In both cases, the bit should be cleared to access the actual node index.\n" +"int isLeafNode(int index) { return (index >> 31 == 0); }\n" +"int getIndexWithInternalNodeMarkerRemoved(int index) { return index & (~0x80000000); }\n" +"int getIndexWithInternalNodeMarkerSet(int isLeaf, int index) { return (isLeaf) ? index : (index | 0x80000000); }\n" +"//From sap.cl\n" +"#define NEW_PAIR_MARKER -1\n" +"bool TestAabbAgainstAabb2(const b3AabbCL* aabb1, const b3AabbCL* aabb2)\n" +"{\n" +" bool overlap = true;\n" +" overlap = (aabb1->m_min.x > aabb2->m_max.x || aabb1->m_max.x < aabb2->m_min.x) ? false : overlap;\n" +" overlap = (aabb1->m_min.z > aabb2->m_max.z || aabb1->m_max.z < aabb2->m_min.z) ? false : overlap;\n" +" overlap = (aabb1->m_min.y > aabb2->m_max.y || aabb1->m_max.y < aabb2->m_min.y) ? false : overlap;\n" +" return overlap;\n" +"}\n" +"//From sap.cl\n" +"__kernel void plbvhCalculateOverlappingPairs(__global b3AabbCL* rigidAabbs, \n" +" __global int* rootNodeIndex, \n" +" __global int2* internalNodeChildIndices, \n" +" __global b3AabbCL* internalNodeAabbs,\n" +" __global int2* internalNodeLeafIndexRanges,\n" +" \n" +" __global SortDataCL* mortonCodesAndAabbIndices,\n" +" __global int* out_numPairs, __global int4* out_overlappingPairs, \n" +" int maxPairs, int numQueryAabbs)\n" +"{\n" +" //Using get_group_id()/get_local_id() is Faster than get_global_id(0) since\n" +" //mortonCodesAndAabbIndices[] contains rigid body indices sorted along the z-curve (more spatially coherent)\n" +" int queryBvhNodeIndex = get_group_id(0) * get_local_size(0) + get_local_id(0);\n" +" if(queryBvhNodeIndex >= numQueryAabbs) return;\n" +" \n" +" int queryRigidIndex = mortonCodesAndAabbIndices[queryBvhNodeIndex].m_value;\n" +" b3AabbCL queryAabb = rigidAabbs[queryRigidIndex];\n" +" \n" +" int stack[B3_PLVBH_TRAVERSE_MAX_STACK_SIZE];\n" +" \n" +" int stackSize = 1;\n" +" stack[0] = *rootNodeIndex;\n" +" \n" +" while(stackSize)\n" +" {\n" +" int internalOrLeafNodeIndex = stack[ stackSize - 1 ];\n" +" --stackSize;\n" +" \n" +" int isLeaf = isLeafNode(internalOrLeafNodeIndex); //Internal node if false\n" +" int bvhNodeIndex = getIndexWithInternalNodeMarkerRemoved(internalOrLeafNodeIndex);\n" +" \n" +" //Optimization - if the BVH is structured as a binary radix tree, then\n" +" //each internal node corresponds to a contiguous range of leaf nodes(internalNodeLeafIndexRanges[]).\n" +" //This can be used to avoid testing each AABB-AABB pair twice, including preventing each node from colliding with itself.\n" +" {\n" +" int highestLeafIndex = (isLeaf) ? bvhNodeIndex : internalNodeLeafIndexRanges[bvhNodeIndex].y;\n" +" if(highestLeafIndex <= queryBvhNodeIndex) continue;\n" +" }\n" +" \n" +" //bvhRigidIndex is not used if internal node\n" +" int bvhRigidIndex = (isLeaf) ? mortonCodesAndAabbIndices[bvhNodeIndex].m_value : -1;\n" +" \n" +" b3AabbCL bvhNodeAabb = (isLeaf) ? rigidAabbs[bvhRigidIndex] : internalNodeAabbs[bvhNodeIndex];\n" +" if( TestAabbAgainstAabb2(&queryAabb, &bvhNodeAabb) )\n" +" {\n" +" if(isLeaf)\n" +" {\n" +" int4 pair;\n" +" pair.x = rigidAabbs[queryRigidIndex].m_minIndices[3];\n" +" pair.y = rigidAabbs[bvhRigidIndex].m_minIndices[3];\n" +" pair.z = NEW_PAIR_MARKER;\n" +" pair.w = NEW_PAIR_MARKER;\n" +" \n" +" int pairIndex = atomic_inc(out_numPairs);\n" +" if(pairIndex < maxPairs) out_overlappingPairs[pairIndex] = pair;\n" +" }\n" +" \n" +" if(!isLeaf) //Internal node\n" +" {\n" +" if(stackSize + 2 > B3_PLVBH_TRAVERSE_MAX_STACK_SIZE)\n" +" {\n" +" //Error\n" +" }\n" +" else\n" +" {\n" +" stack[ stackSize++ ] = internalNodeChildIndices[bvhNodeIndex].x;\n" +" stack[ stackSize++ ] = internalNodeChildIndices[bvhNodeIndex].y;\n" +" }\n" +" }\n" +" }\n" +" \n" +" }\n" +"}\n" +"//From rayCastKernels.cl\n" +"typedef struct\n" +"{\n" +" float4 m_from;\n" +" float4 m_to;\n" +"} b3RayInfo;\n" +"//From rayCastKernels.cl\n" +"b3Vector3 b3Vector3_normalize(b3Vector3 v)\n" +"{\n" +" b3Vector3 normal = (b3Vector3){v.x, v.y, v.z, 0.f};\n" +" return normalize(normal); //OpenCL normalize == vector4 normalize\n" +"}\n" +"b3Scalar b3Vector3_length2(b3Vector3 v) { return v.x*v.x + v.y*v.y + v.z*v.z; }\n" +"b3Scalar b3Vector3_dot(b3Vector3 a, b3Vector3 b) { return a.x*b.x + a.y*b.y + a.z*b.z; }\n" +"int rayIntersectsAabb(b3Vector3 rayOrigin, b3Scalar rayLength, b3Vector3 rayNormalizedDirection, b3AabbCL aabb)\n" +"{\n" +" //AABB is considered as 3 pairs of 2 planes( {x_min, x_max}, {y_min, y_max}, {z_min, z_max} ).\n" +" //t_min is the point of intersection with the closer plane, t_max is the point of intersection with the farther plane.\n" +" //\n" +" //if (rayNormalizedDirection.x < 0.0f), then max.x will be the near plane \n" +" //and min.x will be the far plane; otherwise, it is reversed.\n" +" //\n" +" //In order for there to be a collision, the t_min and t_max of each pair must overlap.\n" +" //This can be tested for by selecting the highest t_min and lowest t_max and comparing them.\n" +" \n" +" int4 isNegative = isless( rayNormalizedDirection, ((b3Vector3){0.0f, 0.0f, 0.0f, 0.0f}) ); //isless(x,y) returns (x < y)\n" +" \n" +" //When using vector types, the select() function checks the most signficant bit, \n" +" //but isless() sets the least significant bit.\n" +" isNegative <<= 31;\n" +" //select(b, a, condition) == condition ? a : b\n" +" //When using select() with vector types, (condition[i]) is true if its most significant bit is 1\n" +" b3Vector3 t_min = ( select(aabb.m_min, aabb.m_max, isNegative) - rayOrigin ) / rayNormalizedDirection;\n" +" b3Vector3 t_max = ( select(aabb.m_max, aabb.m_min, isNegative) - rayOrigin ) / rayNormalizedDirection;\n" +" \n" +" b3Scalar t_min_final = 0.0f;\n" +" b3Scalar t_max_final = rayLength;\n" +" \n" +" //Must use fmin()/fmax(); if one of the parameters is NaN, then the parameter that is not NaN is returned. \n" +" //Behavior of min()/max() with NaNs is undefined. (See OpenCL Specification 1.2 [6.12.2] and [6.12.4])\n" +" //Since the innermost fmin()/fmax() is always not NaN, this should never return NaN.\n" +" t_min_final = fmax( t_min.z, fmax(t_min.y, fmax(t_min.x, t_min_final)) );\n" +" t_max_final = fmin( t_max.z, fmin(t_max.y, fmin(t_max.x, t_max_final)) );\n" +" \n" +" return (t_min_final <= t_max_final);\n" +"}\n" +"__kernel void plbvhRayTraverse(__global b3AabbCL* rigidAabbs,\n" +" __global int* rootNodeIndex, \n" +" __global int2* internalNodeChildIndices, \n" +" __global b3AabbCL* internalNodeAabbs,\n" +" __global int2* internalNodeLeafIndexRanges,\n" +" __global SortDataCL* mortonCodesAndAabbIndices,\n" +" \n" +" __global b3RayInfo* rays,\n" +" \n" +" __global int* out_numRayRigidPairs, \n" +" __global int2* out_rayRigidPairs,\n" +" int maxRayRigidPairs, int numRays)\n" +"{\n" +" int rayIndex = get_global_id(0);\n" +" if(rayIndex >= numRays) return;\n" +" \n" +" //\n" +" b3Vector3 rayFrom = rays[rayIndex].m_from;\n" +" b3Vector3 rayTo = rays[rayIndex].m_to;\n" +" b3Vector3 rayNormalizedDirection = b3Vector3_normalize(rayTo - rayFrom);\n" +" b3Scalar rayLength = b3Sqrt( b3Vector3_length2(rayTo - rayFrom) );\n" +" \n" +" //\n" +" int stack[B3_PLVBH_TRAVERSE_MAX_STACK_SIZE];\n" +" \n" +" int stackSize = 1;\n" +" stack[0] = *rootNodeIndex;\n" +" \n" +" while(stackSize)\n" +" {\n" +" int internalOrLeafNodeIndex = stack[ stackSize - 1 ];\n" +" --stackSize;\n" +" \n" +" int isLeaf = isLeafNode(internalOrLeafNodeIndex); //Internal node if false\n" +" int bvhNodeIndex = getIndexWithInternalNodeMarkerRemoved(internalOrLeafNodeIndex);\n" +" \n" +" //bvhRigidIndex is not used if internal node\n" +" int bvhRigidIndex = (isLeaf) ? mortonCodesAndAabbIndices[bvhNodeIndex].m_value : -1;\n" +" \n" +" b3AabbCL bvhNodeAabb = (isLeaf) ? rigidAabbs[bvhRigidIndex] : internalNodeAabbs[bvhNodeIndex];\n" +" if( rayIntersectsAabb(rayFrom, rayLength, rayNormalizedDirection, bvhNodeAabb) )\n" +" {\n" +" if(isLeaf)\n" +" {\n" +" int2 rayRigidPair;\n" +" rayRigidPair.x = rayIndex;\n" +" rayRigidPair.y = rigidAabbs[bvhRigidIndex].m_minIndices[3];\n" +" \n" +" int pairIndex = atomic_inc(out_numRayRigidPairs);\n" +" if(pairIndex < maxRayRigidPairs) out_rayRigidPairs[pairIndex] = rayRigidPair;\n" +" }\n" +" \n" +" if(!isLeaf) //Internal node\n" +" {\n" +" if(stackSize + 2 > B3_PLVBH_TRAVERSE_MAX_STACK_SIZE)\n" +" {\n" +" //Error\n" +" }\n" +" else\n" +" {\n" +" stack[ stackSize++ ] = internalNodeChildIndices[bvhNodeIndex].x;\n" +" stack[ stackSize++ ] = internalNodeChildIndices[bvhNodeIndex].y;\n" +" }\n" +" }\n" +" }\n" +" }\n" +"}\n" +"__kernel void plbvhLargeAabbAabbTest(__global b3AabbCL* smallAabbs, __global b3AabbCL* largeAabbs, \n" +" __global int* out_numPairs, __global int4* out_overlappingPairs, \n" +" int maxPairs, int numLargeAabbRigids, int numSmallAabbRigids)\n" +"{\n" +" int smallAabbIndex = get_global_id(0);\n" +" if(smallAabbIndex >= numSmallAabbRigids) return;\n" +" \n" +" b3AabbCL smallAabb = smallAabbs[smallAabbIndex];\n" +" for(int i = 0; i < numLargeAabbRigids; ++i)\n" +" {\n" +" b3AabbCL largeAabb = largeAabbs[i];\n" +" if( TestAabbAgainstAabb2(&smallAabb, &largeAabb) )\n" +" {\n" +" int4 pair;\n" +" pair.x = largeAabb.m_minIndices[3];\n" +" pair.y = smallAabb.m_minIndices[3];\n" +" pair.z = NEW_PAIR_MARKER;\n" +" pair.w = NEW_PAIR_MARKER;\n" +" \n" +" int pairIndex = atomic_inc(out_numPairs);\n" +" if(pairIndex < maxPairs) out_overlappingPairs[pairIndex] = pair;\n" +" }\n" +" }\n" +"}\n" +"__kernel void plbvhLargeAabbRayTest(__global b3AabbCL* largeRigidAabbs, __global b3RayInfo* rays,\n" +" __global int* out_numRayRigidPairs, __global int2* out_rayRigidPairs,\n" +" int numLargeAabbRigids, int maxRayRigidPairs, int numRays)\n" +"{\n" +" int rayIndex = get_global_id(0);\n" +" if(rayIndex >= numRays) return;\n" +" \n" +" b3Vector3 rayFrom = rays[rayIndex].m_from;\n" +" b3Vector3 rayTo = rays[rayIndex].m_to;\n" +" b3Vector3 rayNormalizedDirection = b3Vector3_normalize(rayTo - rayFrom);\n" +" b3Scalar rayLength = b3Sqrt( b3Vector3_length2(rayTo - rayFrom) );\n" +" \n" +" for(int i = 0; i < numLargeAabbRigids; ++i)\n" +" {\n" +" b3AabbCL rigidAabb = largeRigidAabbs[i];\n" +" if( rayIntersectsAabb(rayFrom, rayLength, rayNormalizedDirection, rigidAabb) )\n" +" {\n" +" int2 rayRigidPair;\n" +" rayRigidPair.x = rayIndex;\n" +" rayRigidPair.y = rigidAabb.m_minIndices[3];\n" +" \n" +" int pairIndex = atomic_inc(out_numRayRigidPairs);\n" +" if(pairIndex < maxRayRigidPairs) out_rayRigidPairs[pairIndex] = rayRigidPair;\n" +" }\n" +" }\n" +"}\n" +"//Set so that it is always greater than the actual common prefixes, and never selected as a parent node.\n" +"//If there are no duplicates, then the highest common prefix is 32 or 64, depending on the number of bits used for the z-curve.\n" +"//Duplicate common prefixes increase the highest common prefix at most by the number of bits used to index the leaf node.\n" +"//Since 32 bit ints are used to index leaf nodes, the max prefix is 64(32 + 32 bit z-curve) or 96(32 + 64 bit z-curve).\n" +"#define B3_PLBVH_INVALID_COMMON_PREFIX 128\n" +"#define B3_PLBVH_ROOT_NODE_MARKER -1\n" +"#define b3Int64 long\n" +"int computeCommonPrefixLength(b3Int64 i, b3Int64 j) { return (int)clz(i ^ j); }\n" +"b3Int64 computeCommonPrefix(b3Int64 i, b3Int64 j) \n" +"{\n" +" //This function only needs to return (i & j) in order for the algorithm to work,\n" +" //but it may help with debugging to mask out the lower bits.\n" +" b3Int64 commonPrefixLength = (b3Int64)computeCommonPrefixLength(i, j);\n" +" b3Int64 sharedBits = i & j;\n" +" b3Int64 bitmask = ((b3Int64)(~0)) << (64 - commonPrefixLength); //Set all bits after the common prefix to 0\n" +" \n" +" return sharedBits & bitmask;\n" +"}\n" +"//Same as computeCommonPrefixLength(), but allows for prefixes with different lengths\n" +"int getSharedPrefixLength(b3Int64 prefixA, int prefixLengthA, b3Int64 prefixB, int prefixLengthB)\n" +"{\n" +" return b3Min( computeCommonPrefixLength(prefixA, prefixB), b3Min(prefixLengthA, prefixLengthB) );\n" +"}\n" +"__kernel void computeAdjacentPairCommonPrefix(__global SortDataCL* mortonCodesAndAabbIndices,\n" +" __global b3Int64* out_commonPrefixes,\n" +" __global int* out_commonPrefixLengths,\n" +" int numInternalNodes)\n" +"{\n" +" int internalNodeIndex = get_global_id(0);\n" +" if (internalNodeIndex >= numInternalNodes) return;\n" +" \n" +" //Here, (internalNodeIndex + 1) is never out of bounds since it is a leaf node index,\n" +" //and the number of internal nodes is always numLeafNodes - 1\n" +" int leftLeafIndex = internalNodeIndex;\n" +" int rightLeafIndex = internalNodeIndex + 1;\n" +" \n" +" int leftLeafMortonCode = mortonCodesAndAabbIndices[leftLeafIndex].m_key;\n" +" int rightLeafMortonCode = mortonCodesAndAabbIndices[rightLeafIndex].m_key;\n" +" \n" +" //Binary radix tree construction algorithm does not work if there are duplicate morton codes.\n" +" //Append the index of each leaf node to each morton code so that there are no duplicates.\n" +" //The algorithm also requires that the morton codes are sorted in ascending order; this requirement\n" +" //is also satisfied with this method, as (leftLeafIndex < rightLeafIndex) is always true.\n" +" //\n" +" //upsample(a, b) == ( ((b3Int64)a) << 32) | b\n" +" b3Int64 nonduplicateLeftMortonCode = upsample(leftLeafMortonCode, leftLeafIndex);\n" +" b3Int64 nonduplicateRightMortonCode = upsample(rightLeafMortonCode, rightLeafIndex);\n" +" \n" +" out_commonPrefixes[internalNodeIndex] = computeCommonPrefix(nonduplicateLeftMortonCode, nonduplicateRightMortonCode);\n" +" out_commonPrefixLengths[internalNodeIndex] = computeCommonPrefixLength(nonduplicateLeftMortonCode, nonduplicateRightMortonCode);\n" +"}\n" +"__kernel void buildBinaryRadixTreeLeafNodes(__global int* commonPrefixLengths, __global int* out_leafNodeParentNodes,\n" +" __global int2* out_childNodes, int numLeafNodes)\n" +"{\n" +" int leafNodeIndex = get_global_id(0);\n" +" if (leafNodeIndex >= numLeafNodes) return;\n" +" \n" +" int numInternalNodes = numLeafNodes - 1;\n" +" \n" +" int leftSplitIndex = leafNodeIndex - 1;\n" +" int rightSplitIndex = leafNodeIndex;\n" +" \n" +" int leftCommonPrefix = (leftSplitIndex >= 0) ? commonPrefixLengths[leftSplitIndex] : B3_PLBVH_INVALID_COMMON_PREFIX;\n" +" int rightCommonPrefix = (rightSplitIndex < numInternalNodes) ? commonPrefixLengths[rightSplitIndex] : B3_PLBVH_INVALID_COMMON_PREFIX;\n" +" \n" +" //Parent node is the highest adjacent common prefix that is lower than the node's common prefix\n" +" //Leaf nodes are considered as having the highest common prefix\n" +" int isLeftHigherCommonPrefix = (leftCommonPrefix > rightCommonPrefix);\n" +" \n" +" //Handle cases for the edge nodes; the first and last node\n" +" //For leaf nodes, leftCommonPrefix and rightCommonPrefix should never both be B3_PLBVH_INVALID_COMMON_PREFIX\n" +" if(leftCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherCommonPrefix = false;\n" +" if(rightCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherCommonPrefix = true;\n" +" \n" +" int parentNodeIndex = (isLeftHigherCommonPrefix) ? leftSplitIndex : rightSplitIndex;\n" +" out_leafNodeParentNodes[leafNodeIndex] = parentNodeIndex;\n" +" \n" +" int isRightChild = (isLeftHigherCommonPrefix); //If the left node is the parent, then this node is its right child and vice versa\n" +" \n" +" //out_childNodesAsInt[0] == int2.x == left child\n" +" //out_childNodesAsInt[1] == int2.y == right child\n" +" int isLeaf = 1;\n" +" __global int* out_childNodesAsInt = (__global int*)(&out_childNodes[parentNodeIndex]);\n" +" out_childNodesAsInt[isRightChild] = getIndexWithInternalNodeMarkerSet(isLeaf, leafNodeIndex);\n" +"}\n" +"__kernel void buildBinaryRadixTreeInternalNodes(__global b3Int64* commonPrefixes, __global int* commonPrefixLengths,\n" +" __global int2* out_childNodes,\n" +" __global int* out_internalNodeParentNodes, __global int* out_rootNodeIndex,\n" +" int numInternalNodes)\n" +"{\n" +" int internalNodeIndex = get_group_id(0) * get_local_size(0) + get_local_id(0);\n" +" if(internalNodeIndex >= numInternalNodes) return;\n" +" \n" +" b3Int64 nodePrefix = commonPrefixes[internalNodeIndex];\n" +" int nodePrefixLength = commonPrefixLengths[internalNodeIndex];\n" +" \n" +"//#define USE_LINEAR_SEARCH\n" +"#ifdef USE_LINEAR_SEARCH\n" +" int leftIndex = -1;\n" +" int rightIndex = -1;\n" +" \n" +" //Find nearest element to left with a lower common prefix\n" +" for(int i = internalNodeIndex - 1; i >= 0; --i)\n" +" {\n" +" int nodeLeftSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, commonPrefixes[i], commonPrefixLengths[i]);\n" +" if(nodeLeftSharedPrefixLength < nodePrefixLength)\n" +" {\n" +" leftIndex = i;\n" +" break;\n" +" }\n" +" }\n" +" \n" +" //Find nearest element to right with a lower common prefix\n" +" for(int i = internalNodeIndex + 1; i < numInternalNodes; ++i)\n" +" {\n" +" int nodeRightSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, commonPrefixes[i], commonPrefixLengths[i]);\n" +" if(nodeRightSharedPrefixLength < nodePrefixLength)\n" +" {\n" +" rightIndex = i;\n" +" break;\n" +" }\n" +" }\n" +" \n" +"#else //Use binary search\n" +" //Find nearest element to left with a lower common prefix\n" +" int leftIndex = -1;\n" +" {\n" +" int lower = 0;\n" +" int upper = internalNodeIndex - 1;\n" +" \n" +" while(lower <= upper)\n" +" {\n" +" int mid = (lower + upper) / 2;\n" +" b3Int64 midPrefix = commonPrefixes[mid];\n" +" int midPrefixLength = commonPrefixLengths[mid];\n" +" \n" +" int nodeMidSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, midPrefix, midPrefixLength);\n" +" if(nodeMidSharedPrefixLength < nodePrefixLength) \n" +" {\n" +" int right = mid + 1;\n" +" if(right < internalNodeIndex)\n" +" {\n" +" b3Int64 rightPrefix = commonPrefixes[right];\n" +" int rightPrefixLength = commonPrefixLengths[right];\n" +" \n" +" int nodeRightSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, rightPrefix, rightPrefixLength);\n" +" if(nodeRightSharedPrefixLength < nodePrefixLength) \n" +" {\n" +" lower = right;\n" +" leftIndex = right;\n" +" }\n" +" else \n" +" {\n" +" leftIndex = mid;\n" +" break;\n" +" }\n" +" }\n" +" else \n" +" {\n" +" leftIndex = mid;\n" +" break;\n" +" }\n" +" }\n" +" else upper = mid - 1;\n" +" }\n" +" }\n" +" \n" +" //Find nearest element to right with a lower common prefix\n" +" int rightIndex = -1;\n" +" {\n" +" int lower = internalNodeIndex + 1;\n" +" int upper = numInternalNodes - 1;\n" +" \n" +" while(lower <= upper)\n" +" {\n" +" int mid = (lower + upper) / 2;\n" +" b3Int64 midPrefix = commonPrefixes[mid];\n" +" int midPrefixLength = commonPrefixLengths[mid];\n" +" \n" +" int nodeMidSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, midPrefix, midPrefixLength);\n" +" if(nodeMidSharedPrefixLength < nodePrefixLength) \n" +" {\n" +" int left = mid - 1;\n" +" if(left > internalNodeIndex)\n" +" {\n" +" b3Int64 leftPrefix = commonPrefixes[left];\n" +" int leftPrefixLength = commonPrefixLengths[left];\n" +" \n" +" int nodeLeftSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, leftPrefix, leftPrefixLength);\n" +" if(nodeLeftSharedPrefixLength < nodePrefixLength) \n" +" {\n" +" upper = left;\n" +" rightIndex = left;\n" +" }\n" +" else \n" +" {\n" +" rightIndex = mid;\n" +" break;\n" +" }\n" +" }\n" +" else \n" +" {\n" +" rightIndex = mid;\n" +" break;\n" +" }\n" +" }\n" +" else lower = mid + 1;\n" +" }\n" +" }\n" +"#endif\n" +" \n" +" //Select parent\n" +" {\n" +" int leftPrefixLength = (leftIndex != -1) ? commonPrefixLengths[leftIndex] : B3_PLBVH_INVALID_COMMON_PREFIX;\n" +" int rightPrefixLength = (rightIndex != -1) ? commonPrefixLengths[rightIndex] : B3_PLBVH_INVALID_COMMON_PREFIX;\n" +" \n" +" int isLeftHigherPrefixLength = (leftPrefixLength > rightPrefixLength);\n" +" \n" +" if(leftPrefixLength == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherPrefixLength = false;\n" +" else if(rightPrefixLength == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherPrefixLength = true;\n" +" \n" +" int parentNodeIndex = (isLeftHigherPrefixLength) ? leftIndex : rightIndex;\n" +" \n" +" int isRootNode = (leftIndex == -1 && rightIndex == -1);\n" +" out_internalNodeParentNodes[internalNodeIndex] = (!isRootNode) ? parentNodeIndex : B3_PLBVH_ROOT_NODE_MARKER;\n" +" \n" +" int isLeaf = 0;\n" +" if(!isRootNode)\n" +" {\n" +" int isRightChild = (isLeftHigherPrefixLength); //If the left node is the parent, then this node is its right child and vice versa\n" +" \n" +" //out_childNodesAsInt[0] == int2.x == left child\n" +" //out_childNodesAsInt[1] == int2.y == right child\n" +" __global int* out_childNodesAsInt = (__global int*)(&out_childNodes[parentNodeIndex]);\n" +" out_childNodesAsInt[isRightChild] = getIndexWithInternalNodeMarkerSet(isLeaf, internalNodeIndex);\n" +" }\n" +" else *out_rootNodeIndex = getIndexWithInternalNodeMarkerSet(isLeaf, internalNodeIndex);\n" +" }\n" +"}\n" +"__kernel void findDistanceFromRoot(__global int* rootNodeIndex, __global int* internalNodeParentNodes,\n" +" __global int* out_maxDistanceFromRoot, __global int* out_distanceFromRoot, int numInternalNodes)\n" +"{\n" +" if( get_global_id(0) == 0 ) atomic_xchg(out_maxDistanceFromRoot, 0);\n" +" int internalNodeIndex = get_global_id(0);\n" +" if(internalNodeIndex >= numInternalNodes) return;\n" +" \n" +" //\n" +" int distanceFromRoot = 0;\n" +" {\n" +" int parentIndex = internalNodeParentNodes[internalNodeIndex];\n" +" while(parentIndex != B3_PLBVH_ROOT_NODE_MARKER)\n" +" {\n" +" parentIndex = internalNodeParentNodes[parentIndex];\n" +" ++distanceFromRoot;\n" +" }\n" +" }\n" +" out_distanceFromRoot[internalNodeIndex] = distanceFromRoot;\n" +" \n" +" //\n" +" __local int localMaxDistanceFromRoot;\n" +" if( get_local_id(0) == 0 ) localMaxDistanceFromRoot = 0;\n" +" barrier(CLK_LOCAL_MEM_FENCE);\n" +" \n" +" atomic_max(&localMaxDistanceFromRoot, distanceFromRoot);\n" +" barrier(CLK_LOCAL_MEM_FENCE);\n" +" \n" +" if( get_local_id(0) == 0 ) atomic_max(out_maxDistanceFromRoot, localMaxDistanceFromRoot);\n" +"}\n" +"__kernel void buildBinaryRadixTreeAabbsRecursive(__global int* distanceFromRoot, __global SortDataCL* mortonCodesAndAabbIndices,\n" +" __global int2* childNodes,\n" +" __global b3AabbCL* leafNodeAabbs, __global b3AabbCL* internalNodeAabbs,\n" +" int maxDistanceFromRoot, int processedDistance, int numInternalNodes)\n" +"{\n" +" int internalNodeIndex = get_global_id(0);\n" +" if(internalNodeIndex >= numInternalNodes) return;\n" +" \n" +" int distance = distanceFromRoot[internalNodeIndex];\n" +" \n" +" if(distance == processedDistance)\n" +" {\n" +" int leftChildIndex = childNodes[internalNodeIndex].x;\n" +" int rightChildIndex = childNodes[internalNodeIndex].y;\n" +" \n" +" int isLeftChildLeaf = isLeafNode(leftChildIndex);\n" +" int isRightChildLeaf = isLeafNode(rightChildIndex);\n" +" \n" +" leftChildIndex = getIndexWithInternalNodeMarkerRemoved(leftChildIndex);\n" +" rightChildIndex = getIndexWithInternalNodeMarkerRemoved(rightChildIndex);\n" +" \n" +" //leftRigidIndex/rightRigidIndex is not used if internal node\n" +" int leftRigidIndex = (isLeftChildLeaf) ? mortonCodesAndAabbIndices[leftChildIndex].m_value : -1;\n" +" int rightRigidIndex = (isRightChildLeaf) ? mortonCodesAndAabbIndices[rightChildIndex].m_value : -1;\n" +" \n" +" b3AabbCL leftChildAabb = (isLeftChildLeaf) ? leafNodeAabbs[leftRigidIndex] : internalNodeAabbs[leftChildIndex];\n" +" b3AabbCL rightChildAabb = (isRightChildLeaf) ? leafNodeAabbs[rightRigidIndex] : internalNodeAabbs[rightChildIndex];\n" +" \n" +" b3AabbCL mergedAabb;\n" +" mergedAabb.m_min = b3Min(leftChildAabb.m_min, rightChildAabb.m_min);\n" +" mergedAabb.m_max = b3Max(leftChildAabb.m_max, rightChildAabb.m_max);\n" +" internalNodeAabbs[internalNodeIndex] = mergedAabb;\n" +" }\n" +"}\n" +"__kernel void findLeafIndexRanges(__global int2* internalNodeChildNodes, __global int2* out_leafIndexRanges, int numInternalNodes)\n" +"{\n" +" int internalNodeIndex = get_global_id(0);\n" +" if(internalNodeIndex >= numInternalNodes) return;\n" +" \n" +" int numLeafNodes = numInternalNodes + 1;\n" +" \n" +" int2 childNodes = internalNodeChildNodes[internalNodeIndex];\n" +" \n" +" int2 leafIndexRange; //x == min leaf index, y == max leaf index\n" +" \n" +" //Find lowest leaf index covered by this internal node\n" +" {\n" +" int lowestIndex = childNodes.x; //childNodes.x == Left child\n" +" while( !isLeafNode(lowestIndex) ) lowestIndex = internalNodeChildNodes[ getIndexWithInternalNodeMarkerRemoved(lowestIndex) ].x;\n" +" leafIndexRange.x = lowestIndex;\n" +" }\n" +" \n" +" //Find highest leaf index covered by this internal node\n" +" {\n" +" int highestIndex = childNodes.y; //childNodes.y == Right child\n" +" while( !isLeafNode(highestIndex) ) highestIndex = internalNodeChildNodes[ getIndexWithInternalNodeMarkerRemoved(highestIndex) ].y;\n" +" leafIndexRange.y = highestIndex;\n" +" }\n" +" \n" +" //\n" +" out_leafIndexRanges[internalNodeIndex] = leafIndexRange;\n" +"}\n" +; diff --git a/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/kernels/sap.cl b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/kernels/sap.cl new file mode 100644 index 000000000000..93f77a643355 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/kernels/sap.cl @@ -0,0 +1,389 @@ +/* +Copyright (c) 2012 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Erwin Coumans + +#define NEW_PAIR_MARKER -1 + +typedef struct +{ + union + { + float4 m_min; + float m_minElems[4]; + int m_minIndices[4]; + }; + union + { + float4 m_max; + float m_maxElems[4]; + int m_maxIndices[4]; + }; +} btAabbCL; + + +/// conservative test for overlap between two aabbs +bool TestAabbAgainstAabb2(const btAabbCL* aabb1, __local const btAabbCL* aabb2); +bool TestAabbAgainstAabb2(const btAabbCL* aabb1, __local const btAabbCL* aabb2) +{ + bool overlap = true; + overlap = (aabb1->m_min.x > aabb2->m_max.x || aabb1->m_max.x < aabb2->m_min.x) ? false : overlap; + overlap = (aabb1->m_min.z > aabb2->m_max.z || aabb1->m_max.z < aabb2->m_min.z) ? false : overlap; + overlap = (aabb1->m_min.y > aabb2->m_max.y || aabb1->m_max.y < aabb2->m_min.y) ? false : overlap; + return overlap; +} +bool TestAabbAgainstAabb2GlobalGlobal(__global const btAabbCL* aabb1, __global const btAabbCL* aabb2); +bool TestAabbAgainstAabb2GlobalGlobal(__global const btAabbCL* aabb1, __global const btAabbCL* aabb2) +{ + bool overlap = true; + overlap = (aabb1->m_min.x > aabb2->m_max.x || aabb1->m_max.x < aabb2->m_min.x) ? false : overlap; + overlap = (aabb1->m_min.z > aabb2->m_max.z || aabb1->m_max.z < aabb2->m_min.z) ? false : overlap; + overlap = (aabb1->m_min.y > aabb2->m_max.y || aabb1->m_max.y < aabb2->m_min.y) ? false : overlap; + return overlap; +} + +bool TestAabbAgainstAabb2Global(const btAabbCL* aabb1, __global const btAabbCL* aabb2); +bool TestAabbAgainstAabb2Global(const btAabbCL* aabb1, __global const btAabbCL* aabb2) +{ + bool overlap = true; + overlap = (aabb1->m_min.x > aabb2->m_max.x || aabb1->m_max.x < aabb2->m_min.x) ? false : overlap; + overlap = (aabb1->m_min.z > aabb2->m_max.z || aabb1->m_max.z < aabb2->m_min.z) ? false : overlap; + overlap = (aabb1->m_min.y > aabb2->m_max.y || aabb1->m_max.y < aabb2->m_min.y) ? false : overlap; + return overlap; +} + + +__kernel void computePairsKernelTwoArrays( __global const btAabbCL* unsortedAabbs, __global const int* unsortedAabbMapping, __global const int* unsortedAabbMapping2, volatile __global int4* pairsOut,volatile __global int* pairCount, int numUnsortedAabbs, int numUnSortedAabbs2, int axis, int maxPairs) +{ + int i = get_global_id(0); + if (i>=numUnsortedAabbs) + return; + + int j = get_global_id(1); + if (j>=numUnSortedAabbs2) + return; + + + __global const btAabbCL* unsortedAabbPtr = &unsortedAabbs[unsortedAabbMapping[i]]; + __global const btAabbCL* unsortedAabbPtr2 = &unsortedAabbs[unsortedAabbMapping2[j]]; + + if (TestAabbAgainstAabb2GlobalGlobal(unsortedAabbPtr,unsortedAabbPtr2)) + { + int4 myPair; + + int xIndex = unsortedAabbPtr[0].m_minIndices[3]; + int yIndex = unsortedAabbPtr2[0].m_minIndices[3]; + if (xIndex>yIndex) + { + int tmp = xIndex; + xIndex=yIndex; + yIndex=tmp; + } + + myPair.x = xIndex; + myPair.y = yIndex; + myPair.z = NEW_PAIR_MARKER; + myPair.w = NEW_PAIR_MARKER; + + + int curPair = atomic_inc (pairCount); + if (curPair=numObjects) + return; + for (int j=i+1;j=numObjects) + return; + for (int j=i+1;j=numObjects && !localBreak) + { + atomic_inc(breakRequest); + localBreak = 1; + } + barrier(CLK_LOCAL_MEM_FENCE); + + if (!localBreak) + { + if (TestAabbAgainstAabb2GlobalGlobal(&aabbs[i],&aabbs[j])) + { + int4 myPair; + myPair.x = aabbs[i].m_minIndices[3]; + myPair.y = aabbs[j].m_minIndices[3]; + myPair.z = NEW_PAIR_MARKER; + myPair.w = NEW_PAIR_MARKER; + + int curPair = atomic_inc (pairCount); + if (curPair=numObjects && !localBreak) + { + atomic_inc(breakRequest); + localBreak = 1; + } + barrier(CLK_LOCAL_MEM_FENCE); + + if (!localBreak) + { + if (TestAabbAgainstAabb2(&myAabb,&localAabbs[localCount+localId+1])) + { + int4 myPair; + myPair.x = myAabb.m_minIndices[3]; + myPair.y = localAabbs[localCount+localId+1].m_minIndices[3]; + myPair.z = NEW_PAIR_MARKER; + myPair.w = NEW_PAIR_MARKER; + + int curPair = atomic_inc (pairCount); + if (curPair> 31) | 0x80000000; + return f ^ mask; +} +float IFloatFlip(unsigned int f); +float IFloatFlip(unsigned int f) +{ + unsigned int mask = ((f >> 31) - 1) | 0x80000000; + unsigned int fl = f ^ mask; + return *(float*)&fl; +} + + + + +__kernel void copyAabbsKernel( __global const btAabbCL* allAabbs, __global btAabbCL* destAabbs, int numObjects) +{ + int i = get_global_id(0); + if (i>=numObjects) + return; + int src = destAabbs[i].m_maxIndices[3]; + destAabbs[i] = allAabbs[src]; + destAabbs[i].m_maxIndices[3] = src; +} + + +__kernel void flipFloatKernel( __global const btAabbCL* allAabbs, __global const int* smallAabbMapping, __global int2* sortData, int numObjects, int axis) +{ + int i = get_global_id(0); + if (i>=numObjects) + return; + + + sortData[i].x = FloatFlip(allAabbs[smallAabbMapping[i]].m_minElems[axis]); + sortData[i].y = i; + +} + + +__kernel void scatterKernel( __global const btAabbCL* allAabbs, __global const int* smallAabbMapping, volatile __global const int2* sortData, __global btAabbCL* sortedAabbs, int numObjects) +{ + int i = get_global_id(0); + if (i>=numObjects) + return; + + sortedAabbs[i] = allAabbs[smallAabbMapping[sortData[i].y]]; +} + + + +__kernel void prepareSumVarianceKernel( __global const btAabbCL* allAabbs, __global const int* smallAabbMapping, __global float4* sum, __global float4* sum2,int numAabbs) +{ + int i = get_global_id(0); + if (i>=numAabbs) + return; + + btAabbCL smallAabb = allAabbs[smallAabbMapping[i]]; + + float4 s; + s = (smallAabb.m_max+smallAabb.m_min)*0.5f; + sum[i]=s; + sum2[i]=s*s; +} diff --git a/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/kernels/sapKernels.h b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/kernels/sapKernels.h new file mode 100644 index 000000000000..04d40fcf26ed --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/BroadphaseCollision/kernels/sapKernels.h @@ -0,0 +1,342 @@ +//this file is autogenerated using stringify.bat (premake --stringify) in the build folder of this project +static const char* sapCL= \ +"/*\n" +"Copyright (c) 2012 Advanced Micro Devices, Inc. \n" +"This software is provided 'as-is', without any express or implied warranty.\n" +"In no event will the authors be held liable for any damages arising from the use of this software.\n" +"Permission is granted to anyone to use this software for any purpose, \n" +"including commercial applications, and to alter it and redistribute it freely, \n" +"subject to the following restrictions:\n" +"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.\n" +"2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n" +"3. This notice may not be removed or altered from any source distribution.\n" +"*/\n" +"//Originally written by Erwin Coumans\n" +"#define NEW_PAIR_MARKER -1\n" +"typedef struct \n" +"{\n" +" union\n" +" {\n" +" float4 m_min;\n" +" float m_minElems[4];\n" +" int m_minIndices[4];\n" +" };\n" +" union\n" +" {\n" +" float4 m_max;\n" +" float m_maxElems[4];\n" +" int m_maxIndices[4];\n" +" };\n" +"} btAabbCL;\n" +"/// conservative test for overlap between two aabbs\n" +"bool TestAabbAgainstAabb2(const btAabbCL* aabb1, __local const btAabbCL* aabb2);\n" +"bool TestAabbAgainstAabb2(const btAabbCL* aabb1, __local const btAabbCL* aabb2)\n" +"{\n" +" bool overlap = true;\n" +" overlap = (aabb1->m_min.x > aabb2->m_max.x || aabb1->m_max.x < aabb2->m_min.x) ? false : overlap;\n" +" overlap = (aabb1->m_min.z > aabb2->m_max.z || aabb1->m_max.z < aabb2->m_min.z) ? false : overlap;\n" +" overlap = (aabb1->m_min.y > aabb2->m_max.y || aabb1->m_max.y < aabb2->m_min.y) ? false : overlap;\n" +" return overlap;\n" +"}\n" +"bool TestAabbAgainstAabb2GlobalGlobal(__global const btAabbCL* aabb1, __global const btAabbCL* aabb2);\n" +"bool TestAabbAgainstAabb2GlobalGlobal(__global const btAabbCL* aabb1, __global const btAabbCL* aabb2)\n" +"{\n" +" bool overlap = true;\n" +" overlap = (aabb1->m_min.x > aabb2->m_max.x || aabb1->m_max.x < aabb2->m_min.x) ? false : overlap;\n" +" overlap = (aabb1->m_min.z > aabb2->m_max.z || aabb1->m_max.z < aabb2->m_min.z) ? false : overlap;\n" +" overlap = (aabb1->m_min.y > aabb2->m_max.y || aabb1->m_max.y < aabb2->m_min.y) ? false : overlap;\n" +" return overlap;\n" +"}\n" +"bool TestAabbAgainstAabb2Global(const btAabbCL* aabb1, __global const btAabbCL* aabb2);\n" +"bool TestAabbAgainstAabb2Global(const btAabbCL* aabb1, __global const btAabbCL* aabb2)\n" +"{\n" +" bool overlap = true;\n" +" overlap = (aabb1->m_min.x > aabb2->m_max.x || aabb1->m_max.x < aabb2->m_min.x) ? false : overlap;\n" +" overlap = (aabb1->m_min.z > aabb2->m_max.z || aabb1->m_max.z < aabb2->m_min.z) ? false : overlap;\n" +" overlap = (aabb1->m_min.y > aabb2->m_max.y || aabb1->m_max.y < aabb2->m_min.y) ? false : overlap;\n" +" return overlap;\n" +"}\n" +"__kernel void computePairsKernelTwoArrays( __global const btAabbCL* unsortedAabbs, __global const int* unsortedAabbMapping, __global const int* unsortedAabbMapping2, volatile __global int4* pairsOut,volatile __global int* pairCount, int numUnsortedAabbs, int numUnSortedAabbs2, int axis, int maxPairs)\n" +"{\n" +" int i = get_global_id(0);\n" +" if (i>=numUnsortedAabbs)\n" +" return;\n" +" int j = get_global_id(1);\n" +" if (j>=numUnSortedAabbs2)\n" +" return;\n" +" __global const btAabbCL* unsortedAabbPtr = &unsortedAabbs[unsortedAabbMapping[i]];\n" +" __global const btAabbCL* unsortedAabbPtr2 = &unsortedAabbs[unsortedAabbMapping2[j]];\n" +" if (TestAabbAgainstAabb2GlobalGlobal(unsortedAabbPtr,unsortedAabbPtr2))\n" +" {\n" +" int4 myPair;\n" +" \n" +" int xIndex = unsortedAabbPtr[0].m_minIndices[3];\n" +" int yIndex = unsortedAabbPtr2[0].m_minIndices[3];\n" +" if (xIndex>yIndex)\n" +" {\n" +" int tmp = xIndex;\n" +" xIndex=yIndex;\n" +" yIndex=tmp;\n" +" }\n" +" \n" +" myPair.x = xIndex;\n" +" myPair.y = yIndex;\n" +" myPair.z = NEW_PAIR_MARKER;\n" +" myPair.w = NEW_PAIR_MARKER;\n" +" int curPair = atomic_inc (pairCount);\n" +" if (curPair=numObjects)\n" +" return;\n" +" for (int j=i+1;j=numObjects)\n" +" return;\n" +" for (int j=i+1;j=numObjects && !localBreak)\n" +" {\n" +" atomic_inc(breakRequest);\n" +" localBreak = 1;\n" +" }\n" +" barrier(CLK_LOCAL_MEM_FENCE);\n" +" \n" +" if (!localBreak)\n" +" {\n" +" if (TestAabbAgainstAabb2GlobalGlobal(&aabbs[i],&aabbs[j]))\n" +" {\n" +" int4 myPair;\n" +" myPair.x = aabbs[i].m_minIndices[3];\n" +" myPair.y = aabbs[j].m_minIndices[3];\n" +" myPair.z = NEW_PAIR_MARKER;\n" +" myPair.w = NEW_PAIR_MARKER;\n" +" int curPair = atomic_inc (pairCount);\n" +" if (curPair=numObjects && !localBreak)\n" +" {\n" +" atomic_inc(breakRequest);\n" +" localBreak = 1;\n" +" }\n" +" barrier(CLK_LOCAL_MEM_FENCE);\n" +" \n" +" if (!localBreak)\n" +" {\n" +" if (TestAabbAgainstAabb2(&myAabb,&localAabbs[localCount+localId+1]))\n" +" {\n" +" int4 myPair;\n" +" myPair.x = myAabb.m_minIndices[3];\n" +" myPair.y = localAabbs[localCount+localId+1].m_minIndices[3];\n" +" myPair.z = NEW_PAIR_MARKER;\n" +" myPair.w = NEW_PAIR_MARKER;\n" +" int curPair = atomic_inc (pairCount);\n" +" if (curPair> 31) | 0x80000000;\n" +" return f ^ mask;\n" +"}\n" +"float IFloatFlip(unsigned int f);\n" +"float IFloatFlip(unsigned int f)\n" +"{\n" +" unsigned int mask = ((f >> 31) - 1) | 0x80000000;\n" +" unsigned int fl = f ^ mask;\n" +" return *(float*)&fl;\n" +"}\n" +"__kernel void copyAabbsKernel( __global const btAabbCL* allAabbs, __global btAabbCL* destAabbs, int numObjects)\n" +"{\n" +" int i = get_global_id(0);\n" +" if (i>=numObjects)\n" +" return;\n" +" int src = destAabbs[i].m_maxIndices[3];\n" +" destAabbs[i] = allAabbs[src];\n" +" destAabbs[i].m_maxIndices[3] = src;\n" +"}\n" +"__kernel void flipFloatKernel( __global const btAabbCL* allAabbs, __global const int* smallAabbMapping, __global int2* sortData, int numObjects, int axis)\n" +"{\n" +" int i = get_global_id(0);\n" +" if (i>=numObjects)\n" +" return;\n" +" \n" +" \n" +" sortData[i].x = FloatFlip(allAabbs[smallAabbMapping[i]].m_minElems[axis]);\n" +" sortData[i].y = i;\n" +" \n" +"}\n" +"__kernel void scatterKernel( __global const btAabbCL* allAabbs, __global const int* smallAabbMapping, volatile __global const int2* sortData, __global btAabbCL* sortedAabbs, int numObjects)\n" +"{\n" +" int i = get_global_id(0);\n" +" if (i>=numObjects)\n" +" return;\n" +" \n" +" sortedAabbs[i] = allAabbs[smallAabbMapping[sortData[i].y]];\n" +"}\n" +"__kernel void prepareSumVarianceKernel( __global const btAabbCL* allAabbs, __global const int* smallAabbMapping, __global float4* sum, __global float4* sum2,int numAabbs)\n" +"{\n" +" int i = get_global_id(0);\n" +" if (i>=numAabbs)\n" +" return;\n" +" \n" +" btAabbCL smallAabb = allAabbs[smallAabbMapping[i]];\n" +" \n" +" float4 s;\n" +" s = (smallAabb.m_max+smallAabb.m_min)*0.5f;\n" +" sum[i]=s;\n" +" sum2[i]=s*s; \n" +"}\n" +; diff --git a/extern/bullet/src/Bullet3OpenCL/CMakeLists.txt b/extern/bullet/src/Bullet3OpenCL/CMakeLists.txt new file mode 100644 index 000000000000..1da58d4a99aa --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/CMakeLists.txt @@ -0,0 +1,77 @@ +INCLUDE_DIRECTORIES( ${BULLET_PHYSICS_SOURCE_DIR}/src ) + +ADD_DEFINITIONS(-DB3_USE_CLEW) + +SET(Bullet3OpenCL_clew_SRCS + ../clew/clew.c + BroadphaseCollision/b3GpuGridBroadphase.cpp + BroadphaseCollision/b3GpuSapBroadphase.cpp + BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.cpp + BroadphaseCollision/b3GpuParallelLinearBvh.cpp + Initialize/b3OpenCLUtils.cpp + NarrowphaseCollision/b3ContactCache.cpp + NarrowphaseCollision/b3ConvexHullContact.cpp + NarrowphaseCollision/b3GjkEpa.cpp + NarrowphaseCollision/b3OptimizedBvh.cpp + NarrowphaseCollision/b3QuantizedBvh.cpp + NarrowphaseCollision/b3StridingMeshInterface.cpp + NarrowphaseCollision/b3TriangleCallback.cpp + NarrowphaseCollision/b3TriangleIndexVertexArray.cpp + NarrowphaseCollision/b3VoronoiSimplexSolver.cpp + ParallelPrimitives/b3BoundSearchCL.cpp + ParallelPrimitives/b3FillCL.cpp + ParallelPrimitives/b3LauncherCL.cpp + ParallelPrimitives/b3PrefixScanCL.cpp + ParallelPrimitives/b3PrefixScanFloat4CL.cpp + ParallelPrimitives/b3RadixSort32CL.cpp + Raycast/b3GpuRaycast.cpp + RigidBody/b3GpuGenericConstraint.cpp + RigidBody/b3GpuJacobiContactSolver.cpp + RigidBody/b3GpuNarrowPhase.cpp + RigidBody/b3GpuPgsConstraintSolver.cpp + RigidBody/b3GpuPgsContactSolver.cpp + RigidBody/b3GpuRigidBodyPipeline.cpp + RigidBody/b3Solver.cpp +) + + +SET(Bullet3OpenCL_clew_HDRS +# ${Root_HDRS} +) + + +ADD_LIBRARY(Bullet3OpenCL_clew ${Bullet3OpenCL_clew_SRCS} ${Bullet3OpenCL_clew_HDRS}) +SET_TARGET_PROPERTIES(Bullet3OpenCL_clew PROPERTIES VERSION ${BULLET_VERSION}) +SET_TARGET_PROPERTIES(Bullet3OpenCL_clew PROPERTIES SOVERSION ${BULLET_VERSION}) +IF (BUILD_SHARED_LIBS) + TARGET_LINK_LIBRARIES(Bullet3OpenCL_clew LinearMath Bullet3Dynamics ${CMAKE_DL_LIBS}) +ENDIF (BUILD_SHARED_LIBS) + + +IF (INSTALL_LIBS) + IF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) + #INSTALL of other files requires CMake 2.6 + IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS Bullet3OpenCL_clew DESTINATION .) + ELSE (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS Bullet3OpenCL_clew RUNTIME DESTINATION bin + LIBRARY DESTINATION lib${LIB_SUFFIX} + ARCHIVE DESTINATION lib${LIB_SUFFIX}) + INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.h" PATTERN ".svn" EXCLUDE PATTERN "CMakeFiles" EXCLUDE) +# INSTALL(FILES ../btBullet3OpenCL_clewCommon.h +#DESTINATION ${INCLUDE_INSTALL_DIR}/Bullet3OpenCL_clew) + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + SET_TARGET_PROPERTIES(Bullet3OpenCL_clew PROPERTIES FRAMEWORK true) + + SET_TARGET_PROPERTIES(Bullet3OpenCL_clew PROPERTIES PUBLIC_HEADER "${Root_HDRS}") + # Have to list out sub-directories manually: + SET_PROPERTY(SOURCE ${BroadphaseCollision_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/BroadphaseCollision) + + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) +ENDIF (INSTALL_LIBS) diff --git a/extern/bullet/src/Bullet3OpenCL/Initialize/b3OpenCLInclude.h b/extern/bullet/src/Bullet3OpenCL/Initialize/b3OpenCLInclude.h new file mode 100644 index 000000000000..e79182d7cb88 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/Initialize/b3OpenCLInclude.h @@ -0,0 +1,48 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2011 Advanced Micro Devices, Inc. http://bulletphysics.org + +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 B3_OPENCL_INCLUDE_H +#define B3_OPENCL_INCLUDE_H + +#ifdef B3_USE_CLEW + #include "clew/clew.h" +#else + +#ifdef __APPLE__ +#ifdef USE_MINICL +#include +#else +#include +#include //clLogMessagesToStderrAPPLE +#endif +#else +#ifdef USE_MINICL +#include +#else +#include +#ifdef _WIN32 +#include "CL/cl_gl.h" +#endif //_WIN32 +#endif +#endif //__APPLE__ +#endif //B3_USE_CLEW + +#include +#include +#define oclCHECKERROR(a, b) if((a)!=(b)) { printf("OCL Error : %d\n", (a)); assert((a) == (b)); } + + +#endif //B3_OPENCL_INCLUDE_H + diff --git a/extern/bullet/src/Bullet3OpenCL/Initialize/b3OpenCLUtils.cpp b/extern/bullet/src/Bullet3OpenCL/Initialize/b3OpenCLUtils.cpp new file mode 100644 index 000000000000..dd194fc7ba76 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/Initialize/b3OpenCLUtils.cpp @@ -0,0 +1,1011 @@ +/* +Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org +Copyright (C) 2006 - 2011 Sony Computer Entertainment Inc. + +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. +*/ + +//Original author: Roman Ponomarev +//Mostly Reimplemented by Erwin Coumans + + +bool gDebugForceLoadingFromSource = false; +bool gDebugSkipLoadingBinary = false; + +#include "Bullet3Common/b3Logging.h" + +#include + +#ifdef _WIN32 +#pragma warning (disable:4996) +#endif +#include "b3OpenCLUtils.h" +//#include "b3OpenCLInclude.h" + +#include +#include + +#define B3_MAX_CL_DEVICES 16 //who needs 16 devices? + +#ifdef _WIN32 +#include +#endif + +#include +#define b3Assert assert +#ifndef _WIN32 +#include + +#endif + +static const char* sCachedBinaryPath="cache"; + + +//Set the preferred platform vendor using the OpenCL SDK +static const char* spPlatformVendor = +#if defined(CL_PLATFORM_MINI_CL) +"MiniCL, SCEA"; +#elif defined(CL_PLATFORM_AMD) +"Advanced Micro Devices, Inc."; +#elif defined(CL_PLATFORM_NVIDIA) +"NVIDIA Corporation"; +#elif defined(CL_PLATFORM_INTEL) +"Intel(R) Corporation"; +#elif defined(B3_USE_CLEW) +"clew (OpenCL Extension Wrangler library)"; +#else +"Unknown Vendor"; +#endif + +#ifndef CL_PLATFORM_MINI_CL +#ifdef _WIN32 +#ifndef B3_USE_CLEW +#include "CL/cl_gl.h" +#endif //B3_USE_CLEW +#endif //_WIN32 +#endif + + +void MyFatalBreakAPPLE( const char * errstr , + const void * private_info , + size_t cb , + void * user_data ) +{ + + + const char* patloc = strstr(errstr, "Warning"); + //find out if it is a warning or error, exit if error + + if (patloc) + { + b3Warning("Warning: %s\n", errstr); + } else + { + b3Error("Error: %s\n", errstr); + b3Assert(0); + } + +} + +#ifdef B3_USE_CLEW + +int b3OpenCLUtils_clewInit() +{ + int result = -1; + +#ifdef _WIN32 + const char* cl = "OpenCL.dll"; +#elif defined __APPLE__ + const char* cl = "/System/Library/Frameworks/OpenCL.framework/Versions/Current/OpenCL"; +#else//presumable Linux? + //linux (tested on Ubuntu 12.10 with Catalyst 13.4 beta drivers, not that there is no symbolic link from libOpenCL.so + const char* cl = "libOpenCL.so.1"; + result = clewInit(cl); + if (result != CLEW_SUCCESS) + { + cl = "libOpenCL.so"; + } else + { + clewExit(); + } +#endif + result = clewInit(cl); + if (result!=CLEW_SUCCESS) + { + b3Error("clewInit failed with error code %d\n",result); + } + else + { + b3Printf("clewInit succesfull using %s\n",cl); + } + return result; +} +#endif + +int b3OpenCLUtils_getNumPlatforms(cl_int* pErrNum) +{ +#ifdef B3_USE_CLEW + b3OpenCLUtils_clewInit(); +#endif + + cl_platform_id pPlatforms[10] = { 0 }; + + cl_uint numPlatforms = 0; + cl_int ciErrNum = clGetPlatformIDs(10, pPlatforms, &numPlatforms); + //cl_int ciErrNum = clGetPlatformIDs(0, NULL, &numPlatforms); + + if(ciErrNum != CL_SUCCESS) + { + if(pErrNum != NULL) + *pErrNum = ciErrNum; + } + return numPlatforms; + +} + +const char* b3OpenCLUtils_getSdkVendorName() +{ + return spPlatformVendor; +} + +void b3OpenCLUtils_setCachePath(const char* path) +{ + sCachedBinaryPath = path; +} + +cl_platform_id b3OpenCLUtils_getPlatform(int platformIndex0, cl_int* pErrNum) +{ +#ifdef B3_USE_CLEW + b3OpenCLUtils_clewInit(); +#endif + + cl_platform_id platform = 0; + unsigned int platformIndex = (unsigned int )platformIndex0; + cl_uint numPlatforms; + cl_int ciErrNum = clGetPlatformIDs(0, NULL, &numPlatforms); + + if (platformIndexm_platformVendor,NULL); + oclCHECKERROR(ciErrNum,CL_SUCCESS); + ciErrNum = clGetPlatformInfo( platform,CL_PLATFORM_NAME,B3_MAX_STRING_LENGTH,platformInfo->m_platformName,NULL); + oclCHECKERROR(ciErrNum,CL_SUCCESS); + ciErrNum = clGetPlatformInfo( platform,CL_PLATFORM_VERSION,B3_MAX_STRING_LENGTH,platformInfo->m_platformVersion,NULL); + oclCHECKERROR(ciErrNum,CL_SUCCESS); +} + +void b3OpenCLUtils_printPlatformInfo( cl_platform_id platform) +{ + b3OpenCLPlatformInfo platformInfo; + b3OpenCLUtils::getPlatformInfo (platform, &platformInfo); + b3Printf("Platform info:\n"); + b3Printf(" CL_PLATFORM_VENDOR: \t\t\t%s\n",platformInfo.m_platformVendor); + b3Printf(" CL_PLATFORM_NAME: \t\t\t%s\n",platformInfo.m_platformName); + b3Printf(" CL_PLATFORM_VERSION: \t\t\t%s\n",platformInfo.m_platformVersion); +} + + + +cl_context b3OpenCLUtils_createContextFromPlatform(cl_platform_id platform, cl_device_type deviceType, cl_int* pErrNum, void* pGLContext, void* pGLDC, int preferredDeviceIndex, int preferredPlatformIndex) +{ + cl_context retContext = 0; + cl_int ciErrNum=0; + cl_uint num_entries; + cl_device_id devices[B3_MAX_CL_DEVICES]; + cl_uint num_devices; + cl_context_properties* cprops; + + /* + * If we could find our platform, use it. Otherwise pass a NULL and get whatever the + * implementation thinks we should be using. + */ + cl_context_properties cps[7] = {0,0,0,0,0,0,0}; + cps[0] = CL_CONTEXT_PLATFORM; + cps[1] = (cl_context_properties)platform; +#ifdef _WIN32 +#ifndef B3_USE_CLEW + if (pGLContext && pGLDC) + { + cps[2] = CL_GL_CONTEXT_KHR; + cps[3] = (cl_context_properties)pGLContext; + cps[4] = CL_WGL_HDC_KHR; + cps[5] = (cl_context_properties)pGLDC; + } +#endif //B3_USE_CLEW +#endif //_WIN32 + num_entries = B3_MAX_CL_DEVICES; + + + num_devices=-1; + + ciErrNum = clGetDeviceIDs( + platform, + deviceType, + num_entries, + devices, + &num_devices); + + if (ciErrNum<0) + { + b3Printf("clGetDeviceIDs returned %d\n",ciErrNum); + return 0; + } + cprops = (NULL == platform) ? NULL : cps; + + if (!num_devices) + return 0; + + if (pGLContext) + { + //search for the GPU that relates to the OpenCL context + unsigned int i; + for (i=0;i=0 && (unsigned int)preferredDeviceIndex 0) + { + cl_platform_id* platforms = (cl_platform_id*) malloc (sizeof(cl_platform_id)*numPlatforms); + ciErrNum = clGetPlatformIDs(numPlatforms, platforms, NULL); + if(ciErrNum != CL_SUCCESS) + { + if(pErrNum != NULL) + *pErrNum = ciErrNum; + free(platforms); + return NULL; + } + + + + for ( i = 0; i < numPlatforms; ++i) + { + char pbuf[128]; + ciErrNum = clGetPlatformInfo( platforms[i], + CL_PLATFORM_VENDOR, + sizeof(pbuf), + pbuf, + NULL); + if(ciErrNum != CL_SUCCESS) + { + if(pErrNum != NULL) *pErrNum = ciErrNum; + return NULL; + } + + if (preferredPlatformIndex>=0 && i==preferredPlatformIndex) + { + cl_platform_id tmpPlatform = platforms[0]; + platforms[0] = platforms[i]; + platforms[i] = tmpPlatform; + break; + } else + { + if(!strcmp(pbuf, spPlatformVendor)) + { + cl_platform_id tmpPlatform = platforms[0]; + platforms[0] = platforms[i]; + platforms[i] = tmpPlatform; + } + } + } + + for (i = 0; i < numPlatforms; ++i) + { + cl_platform_id platform = platforms[i]; + assert(platform); + + retContext = b3OpenCLUtils_createContextFromPlatform(platform,deviceType,pErrNum,pGLContext,pGLDC,preferredDeviceIndex,preferredPlatformIndex); + + if (retContext) + { +// printf("OpenCL platform details:\n"); + b3OpenCLPlatformInfo platformInfo; + + b3OpenCLUtils::getPlatformInfo(platform, &platformInfo); + + if (retPlatformId) + *retPlatformId = platform; + + break; + } + } + + free (platforms); + } + return retContext; +} + + +////////////////////////////////////////////////////////////////////////////// +//! Gets the id of the nth device from the context +//! +//! @return the id or -1 when out of range +//! @param cxMainContext OpenCL context +//! @param device_idx index of the device of interest +////////////////////////////////////////////////////////////////////////////// +cl_device_id b3OpenCLUtils_getDevice(cl_context cxMainContext, int deviceIndex) +{ + assert(cxMainContext); + + size_t szParmDataBytes; + cl_device_id* cdDevices; + cl_device_id device ; + + // get the list of devices associated with context + clGetContextInfo(cxMainContext, CL_CONTEXT_DEVICES, 0, NULL, &szParmDataBytes); + + if( szParmDataBytes / sizeof(cl_device_id) < (unsigned int)deviceIndex ) { + return (cl_device_id)-1; + } + + cdDevices = (cl_device_id*) malloc(szParmDataBytes); + + clGetContextInfo(cxMainContext, CL_CONTEXT_DEVICES, szParmDataBytes, cdDevices, NULL); + + device = cdDevices[deviceIndex]; + free(cdDevices); + + return device; +} + +int b3OpenCLUtils_getNumDevices(cl_context cxMainContext) +{ + size_t szParamDataBytes; + int device_count; + clGetContextInfo(cxMainContext, CL_CONTEXT_DEVICES, 0, NULL, &szParamDataBytes); + device_count = (int) szParamDataBytes/ sizeof(cl_device_id); + return device_count; +} + + + +void b3OpenCLUtils::getDeviceInfo(cl_device_id device, b3OpenCLDeviceInfo* info) +{ + // CL_DEVICE_NAME + clGetDeviceInfo(device, CL_DEVICE_NAME, B3_MAX_STRING_LENGTH, &info->m_deviceName, NULL); + + // CL_DEVICE_VENDOR + clGetDeviceInfo(device, CL_DEVICE_VENDOR, B3_MAX_STRING_LENGTH, &info->m_deviceVendor, NULL); + + // CL_DRIVER_VERSION + clGetDeviceInfo(device, CL_DRIVER_VERSION, B3_MAX_STRING_LENGTH, &info->m_driverVersion, NULL); + + // CL_DEVICE_INFO + clGetDeviceInfo(device, CL_DEVICE_TYPE, sizeof(cl_device_type), &info->m_deviceType, NULL); + + // CL_DEVICE_MAX_COMPUTE_UNITS + clGetDeviceInfo(device, CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(info->m_computeUnits), &info->m_computeUnits, NULL); + + // CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS + clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, sizeof(info->m_workitemDims), &info->m_workitemDims, NULL); + + // CL_DEVICE_MAX_WORK_ITEM_SIZES + clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(info->m_workItemSize), &info->m_workItemSize, NULL); + + // CL_DEVICE_MAX_WORK_GROUP_SIZE + clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(info->m_workgroupSize), &info->m_workgroupSize, NULL); + + // CL_DEVICE_MAX_CLOCK_FREQUENCY + clGetDeviceInfo(device, CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(info->m_clockFrequency), &info->m_clockFrequency, NULL); + + // CL_DEVICE_ADDRESS_BITS + clGetDeviceInfo(device, CL_DEVICE_ADDRESS_BITS, sizeof(info->m_addressBits), &info->m_addressBits, NULL); + + // CL_DEVICE_MAX_MEM_ALLOC_SIZE + clGetDeviceInfo(device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(info->m_maxMemAllocSize), &info->m_maxMemAllocSize, NULL); + + // CL_DEVICE_GLOBAL_MEM_SIZE + clGetDeviceInfo(device, CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(info->m_globalMemSize), &info->m_globalMemSize, NULL); + + // CL_DEVICE_ERROR_CORRECTION_SUPPORT + clGetDeviceInfo(device, CL_DEVICE_ERROR_CORRECTION_SUPPORT, sizeof(info->m_errorCorrectionSupport), &info->m_errorCorrectionSupport, NULL); + + // CL_DEVICE_LOCAL_MEM_TYPE + clGetDeviceInfo(device, CL_DEVICE_LOCAL_MEM_TYPE, sizeof(info->m_localMemType), &info->m_localMemType, NULL); + + // CL_DEVICE_LOCAL_MEM_SIZE + clGetDeviceInfo(device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(info->m_localMemSize), &info->m_localMemSize, NULL); + + // CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE + clGetDeviceInfo(device, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, sizeof(info->m_constantBufferSize), &info->m_constantBufferSize, NULL); + + // CL_DEVICE_QUEUE_PROPERTIES + clGetDeviceInfo(device, CL_DEVICE_QUEUE_PROPERTIES, sizeof(info->m_queueProperties), &info->m_queueProperties, NULL); + + // CL_DEVICE_IMAGE_SUPPORT + clGetDeviceInfo(device, CL_DEVICE_IMAGE_SUPPORT, sizeof(info->m_imageSupport), &info->m_imageSupport, NULL); + + // CL_DEVICE_MAX_READ_IMAGE_ARGS + clGetDeviceInfo(device, CL_DEVICE_MAX_READ_IMAGE_ARGS, sizeof(info->m_maxReadImageArgs), &info->m_maxReadImageArgs, NULL); + + // CL_DEVICE_MAX_WRITE_IMAGE_ARGS + clGetDeviceInfo(device, CL_DEVICE_MAX_WRITE_IMAGE_ARGS, sizeof(info->m_maxWriteImageArgs), &info->m_maxWriteImageArgs, NULL); + + // CL_DEVICE_IMAGE2D_MAX_WIDTH, CL_DEVICE_IMAGE2D_MAX_HEIGHT, CL_DEVICE_IMAGE3D_MAX_WIDTH, CL_DEVICE_IMAGE3D_MAX_HEIGHT, CL_DEVICE_IMAGE3D_MAX_DEPTH + clGetDeviceInfo(device, CL_DEVICE_IMAGE2D_MAX_WIDTH, sizeof(size_t), &info->m_image2dMaxWidth, NULL); + clGetDeviceInfo(device, CL_DEVICE_IMAGE2D_MAX_HEIGHT, sizeof(size_t), &info->m_image2dMaxHeight, NULL); + clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_WIDTH, sizeof(size_t), &info->m_image3dMaxWidth, NULL); + clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_HEIGHT, sizeof(size_t), &info->m_image3dMaxHeight, NULL); + clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_DEPTH, sizeof(size_t), &info->m_image3dMaxDepth, NULL); + + // CL_DEVICE_EXTENSIONS: get device extensions, and if any then parse & log the string onto separate lines + clGetDeviceInfo(device, CL_DEVICE_EXTENSIONS, B3_MAX_STRING_LENGTH, &info->m_deviceExtensions, NULL); + + // CL_DEVICE_PREFERRED_VECTOR_WIDTH_ + clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, sizeof(cl_uint), &info->m_vecWidthChar, NULL); + clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT, sizeof(cl_uint), &info->m_vecWidthShort, NULL); + clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, sizeof(cl_uint), &info->m_vecWidthInt, NULL); + clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG, sizeof(cl_uint), &info->m_vecWidthLong, NULL); + clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, sizeof(cl_uint), &info->m_vecWidthFloat, NULL); + clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE, sizeof(cl_uint), &info->m_vecWidthDouble, NULL); +} + + +void b3OpenCLUtils_printDeviceInfo(cl_device_id device) +{ + b3OpenCLDeviceInfo info; + b3OpenCLUtils::getDeviceInfo(device,&info); + b3Printf("Device Info:\n"); + b3Printf(" CL_DEVICE_NAME: \t\t\t%s\n", info.m_deviceName); + b3Printf(" CL_DEVICE_VENDOR: \t\t\t%s\n", info.m_deviceVendor); + b3Printf(" CL_DRIVER_VERSION: \t\t\t%s\n", info.m_driverVersion); + + if( info.m_deviceType & CL_DEVICE_TYPE_CPU ) + b3Printf(" CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_CPU"); + if( info.m_deviceType & CL_DEVICE_TYPE_GPU ) + b3Printf(" CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_GPU"); + if( info.m_deviceType & CL_DEVICE_TYPE_ACCELERATOR ) + b3Printf(" CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_ACCELERATOR"); + if( info.m_deviceType & CL_DEVICE_TYPE_DEFAULT ) + b3Printf(" CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_DEFAULT"); + + b3Printf(" CL_DEVICE_MAX_COMPUTE_UNITS:\t\t%u\n", info.m_computeUnits); + b3Printf(" CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS:\t%u\n", info.m_workitemDims); + b3Printf(" CL_DEVICE_MAX_WORK_ITEM_SIZES:\t%u / %u / %u \n", info.m_workItemSize[0], info.m_workItemSize[1], info.m_workItemSize[2]); + b3Printf(" CL_DEVICE_MAX_WORK_GROUP_SIZE:\t%u\n", info.m_workgroupSize); + b3Printf(" CL_DEVICE_MAX_CLOCK_FREQUENCY:\t%u MHz\n", info.m_clockFrequency); + b3Printf(" CL_DEVICE_ADDRESS_BITS:\t\t%u\n", info.m_addressBits); + b3Printf(" CL_DEVICE_MAX_MEM_ALLOC_SIZE:\t\t%u MByte\n", (unsigned int)(info.m_maxMemAllocSize/ (1024 * 1024))); + b3Printf(" CL_DEVICE_GLOBAL_MEM_SIZE:\t\t%u MByte\n", (unsigned int)(info.m_globalMemSize/ (1024 * 1024))); + b3Printf(" CL_DEVICE_ERROR_CORRECTION_SUPPORT:\t%s\n", info.m_errorCorrectionSupport== CL_TRUE ? "yes" : "no"); + b3Printf(" CL_DEVICE_LOCAL_MEM_TYPE:\t\t%s\n", info.m_localMemType == 1 ? "local" : "global"); + b3Printf(" CL_DEVICE_LOCAL_MEM_SIZE:\t\t%u KByte\n", (unsigned int)(info.m_localMemSize / 1024)); + b3Printf(" CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE:\t%u KByte\n", (unsigned int)(info.m_constantBufferSize / 1024)); + if( info.m_queueProperties & CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE ) + b3Printf(" CL_DEVICE_QUEUE_PROPERTIES:\t\t%s\n", "CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE"); + if( info.m_queueProperties & CL_QUEUE_PROFILING_ENABLE ) + b3Printf(" CL_DEVICE_QUEUE_PROPERTIES:\t\t%s\n", "CL_QUEUE_PROFILING_ENABLE"); + + b3Printf(" CL_DEVICE_IMAGE_SUPPORT:\t\t%u\n", info.m_imageSupport); + + b3Printf(" CL_DEVICE_MAX_READ_IMAGE_ARGS:\t%u\n", info.m_maxReadImageArgs); + b3Printf(" CL_DEVICE_MAX_WRITE_IMAGE_ARGS:\t%u\n", info.m_maxWriteImageArgs); + b3Printf("\n CL_DEVICE_IMAGE "); + b3Printf("\t\t\t2D_MAX_WIDTH\t %u\n", info.m_image2dMaxWidth); + b3Printf("\t\t\t\t\t2D_MAX_HEIGHT\t %u\n", info.m_image2dMaxHeight); + b3Printf("\t\t\t\t\t3D_MAX_WIDTH\t %u\n", info.m_image3dMaxWidth); + b3Printf("\t\t\t\t\t3D_MAX_HEIGHT\t %u\n", info.m_image3dMaxHeight); + b3Printf("\t\t\t\t\t3D_MAX_DEPTH\t %u\n", info.m_image3dMaxDepth); + if (*info.m_deviceExtensions != 0) + { + b3Printf("\n CL_DEVICE_EXTENSIONS:%s\n",info.m_deviceExtensions); + } + else + { + b3Printf(" CL_DEVICE_EXTENSIONS: None\n"); + } + b3Printf(" CL_DEVICE_PREFERRED_VECTOR_WIDTH_\t"); + b3Printf("CHAR %u, SHORT %u, INT %u,LONG %u, FLOAT %u, DOUBLE %u\n\n\n", + info.m_vecWidthChar, info.m_vecWidthShort, info.m_vecWidthInt, info.m_vecWidthLong,info.m_vecWidthFloat, info.m_vecWidthDouble); + + +} + + +static const char* strip2(const char* name, const char* pattern) +{ + size_t const patlen = strlen(pattern); + size_t patcnt = 0; + const char * oriptr; + const char * patloc; + // find how many times the pattern occurs in the original string + for (oriptr = name; (patloc = strstr(oriptr, pattern)); oriptr = patloc + patlen) + { + patcnt++; + } + return oriptr; +} + +cl_program b3OpenCLUtils_compileCLProgramFromString(cl_context clContext, cl_device_id device, const char* kernelSourceOrg, cl_int* pErrNum, const char* additionalMacrosArg , const char* clFileNameForCaching, bool disableBinaryCaching) +{ + const char* additionalMacros = additionalMacrosArg?additionalMacrosArg:""; + + if (disableBinaryCaching) + { + //kernelSourceOrg = 0; + } + + cl_program m_cpProgram=0; + cl_int status; + + char binaryFileName[B3_MAX_STRING_LENGTH]; + + char deviceName[256]; + char driverVersion[256]; + const char* strippedName; + int fileUpToDate = 0; +#ifdef _WIN32 + int binaryFileValid=0; +#endif + if (!disableBinaryCaching && clFileNameForCaching) + { + clGetDeviceInfo(device, CL_DEVICE_NAME, 256, &deviceName, NULL); + clGetDeviceInfo(device, CL_DRIVER_VERSION, 256, &driverVersion, NULL); + + strippedName = strip2(clFileNameForCaching,"\\"); + strippedName = strip2(strippedName,"/"); + +#ifdef _MSVC_VER + sprintf_s(binaryFileName,B3_MAX_STRING_LENGTH,"%s/%s.%s.%s.bin",sCachedBinaryPath,strippedName, deviceName,driverVersion ); +#else + sprintf(binaryFileName,"%s/%s.%s.%s.bin",sCachedBinaryPath,strippedName, deviceName,driverVersion ); +#endif + } + if (clFileNameForCaching && !(disableBinaryCaching || gDebugSkipLoadingBinary||gDebugForceLoadingFromSource) ) + { + +#ifdef _WIN32 + char* bla=0; + + + + //printf("searching for %s\n", binaryFileName); + + + FILETIME modtimeBinary; + CreateDirectoryA(sCachedBinaryPath,0); + { + + HANDLE binaryFileHandle = CreateFileA(binaryFileName,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); + if (binaryFileHandle ==INVALID_HANDLE_VALUE) + { + DWORD errorCode; + errorCode = GetLastError(); + switch (errorCode) + { + case ERROR_FILE_NOT_FOUND: + { + b3Warning("\nCached file not found %s\n", binaryFileName); + break; + } + case ERROR_PATH_NOT_FOUND: + { + b3Warning("\nCached file path not found %s\n", binaryFileName); + break; + } + default: + { + b3Warning("\nFailed reading cached file with errorCode = %d\n", errorCode); + } + } + } else + { + if (GetFileTime(binaryFileHandle, NULL, NULL, &modtimeBinary)==0) + { + DWORD errorCode; + errorCode = GetLastError(); + b3Warning("\nGetFileTime errorCode = %d\n", errorCode); + } else + { + binaryFileValid = 1; + } + CloseHandle(binaryFileHandle); + } + + if (binaryFileValid) + { + HANDLE srcFileHandle = CreateFileA(clFileNameForCaching,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); + + if (srcFileHandle==INVALID_HANDLE_VALUE) + { + const char* prefix[]={"./","../","../../","../../../","../../../../"}; + for (int i=0;(srcFileHandle==INVALID_HANDLE_VALUE) && i<5;i++) + { + char relativeFileName[1024]; + sprintf(relativeFileName,"%s%s",prefix[i],clFileNameForCaching); + srcFileHandle = CreateFileA(relativeFileName,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); + } + + } + + + if (srcFileHandle!=INVALID_HANDLE_VALUE) + { + FILETIME modtimeSrc; + if (GetFileTime(srcFileHandle, NULL, NULL, &modtimeSrc)==0) + { + DWORD errorCode; + errorCode = GetLastError(); + b3Warning("\nGetFileTime errorCode = %d\n", errorCode); + } + if ( ( modtimeSrc.dwHighDateTime < modtimeBinary.dwHighDateTime) + ||(( modtimeSrc.dwHighDateTime == modtimeBinary.dwHighDateTime)&&(modtimeSrc.dwLowDateTime <= modtimeBinary.dwLowDateTime))) + { + fileUpToDate=1; + } else + { + b3Warning("\nCached binary file out-of-date (%s)\n",binaryFileName); + } + CloseHandle(srcFileHandle); + } + else + { +#ifdef _DEBUG + DWORD errorCode; + errorCode = GetLastError(); + switch (errorCode) + { + case ERROR_FILE_NOT_FOUND: + { + b3Warning("\nSrc file not found %s\n", clFileNameForCaching); + break; + } + case ERROR_PATH_NOT_FOUND: + { + b3Warning("\nSrc path not found %s\n", clFileNameForCaching); + break; + } + default: + { + b3Warning("\nnSrc file reading errorCode = %d\n", errorCode); + } + } + + //we should make sure the src file exists so we can verify the timestamp with binary +// assert(0); + b3Warning("Warning: cannot find OpenCL kernel %s to verify timestamp of binary cached kernel %s\n",clFileNameForCaching, binaryFileName); + fileUpToDate = true; +#else + //if we cannot find the source, assume it is OK in release builds + fileUpToDate = true; +#endif + } + } + + + } + + + +#else + fileUpToDate = true; + if (mkdir(sCachedBinaryPath,0777) == -1) + { + } + else + { + b3Printf("Succesfully created cache directory: %s\n", sCachedBinaryPath); + } +#endif //_WIN32 + } + + + if( fileUpToDate) + { +#ifdef _MSC_VER + FILE* file; + if (fopen_s(&file,binaryFileName, "rb")!=0) + file=0; +#else + FILE* file = fopen(binaryFileName, "rb"); +#endif + + if (file) + { + size_t binarySize=0; + char* binary =0; + + fseek( file, 0L, SEEK_END ); + binarySize = ftell( file ); + rewind( file ); + binary = (char*)malloc(sizeof(char)*binarySize); + int bytesRead; + bytesRead = fread( binary, sizeof(char), binarySize, file ); + fclose( file ); + + m_cpProgram = clCreateProgramWithBinary( clContext, 1,&device, &binarySize, (const unsigned char**)&binary, 0, &status ); + b3Assert( status == CL_SUCCESS ); + status = clBuildProgram( m_cpProgram, 1, &device, additionalMacros, 0, 0 ); + b3Assert( status == CL_SUCCESS ); + + if( status != CL_SUCCESS ) + { + char *build_log; + size_t ret_val_size; + clGetProgramBuildInfo(m_cpProgram, device, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size); + build_log = (char*)malloc(sizeof(char)*(ret_val_size+1)); + clGetProgramBuildInfo(m_cpProgram, device, CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL); + build_log[ret_val_size] = '\0'; + b3Error("%s\n", build_log); + free (build_log); + b3Assert(0); + m_cpProgram = 0; + + b3Warning("clBuildProgram reported failure on cached binary: %s\n",binaryFileName); + + } else + { + b3Printf("clBuildProgram successfully compiled cached binary: %s\n",binaryFileName); + } + free (binary); + + } else + { + b3Warning("Cannot open cached binary: %s\n",binaryFileName); + } + } + + + + + + + + + + if (!m_cpProgram) + { + + cl_int localErrNum; + char* compileFlags; + int flagsize; + + + + const char* kernelSource = kernelSourceOrg; + + if (!kernelSourceOrg || gDebugForceLoadingFromSource) + { + if (clFileNameForCaching) + { + + FILE* file = fopen(clFileNameForCaching, "rb"); + //in many cases the relative path is a few levels up the directory hierarchy, so try it + if (!file) + { + const char* prefix[]={"../","../../","../../../","../../../../"}; + for (int i=0;!file && i<3;i++) + { + char relativeFileName[1024]; + sprintf(relativeFileName,"%s%s",prefix[i],clFileNameForCaching); + file = fopen(relativeFileName, "rb"); + } + } + + if (file) + { + char* kernelSrc=0; + fseek( file, 0L, SEEK_END ); + int kernelSize = ftell( file ); + rewind( file ); + kernelSrc = (char*)malloc(kernelSize+1); + int readBytes; + readBytes = fread((void*)kernelSrc,1,kernelSize, file); + kernelSrc[kernelSize] = 0; + fclose(file); + kernelSource = kernelSrc; + } + } + } + + size_t program_length = kernelSource ? strlen(kernelSource) : 0; +#ifdef MAC //or __APPLE__? + char* flags = "-cl-mad-enable -DMAC "; +#else + const char* flags = ""; +#endif + + + m_cpProgram = clCreateProgramWithSource(clContext, 1, (const char**)&kernelSource, &program_length, &localErrNum); + if (localErrNum!= CL_SUCCESS) + { + if (pErrNum) + *pErrNum = localErrNum; + return 0; + } + + // Build the program with 'mad' Optimization option + + + + flagsize = sizeof(char)*(strlen(additionalMacros) + strlen(flags) + 5); + compileFlags = (char*) malloc(flagsize); +#ifdef _MSC_VER + sprintf_s(compileFlags,flagsize, "%s %s", flags, additionalMacros); +#else + sprintf(compileFlags, "%s %s", flags, additionalMacros); +#endif + localErrNum = clBuildProgram(m_cpProgram, 1, &device, compileFlags, NULL, NULL); + if (localErrNum!= CL_SUCCESS) + { + char *build_log; + size_t ret_val_size; + clGetProgramBuildInfo(m_cpProgram, device, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size); + build_log = (char*) malloc(sizeof(char)*(ret_val_size+1)); + clGetProgramBuildInfo(m_cpProgram, device, CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL); + + // to be carefully, terminate with \0 + // there's no information in the reference whether the string is 0 terminated or not + build_log[ret_val_size] = '\0'; + + + b3Error("Error in clBuildProgram, Line %u in file %s, Log: \n%s\n !!!\n\n", __LINE__, __FILE__, build_log); + free (build_log); + if (pErrNum) + *pErrNum = localErrNum; + return 0; + } + + + if( !disableBinaryCaching && clFileNameForCaching ) + { // write to binary + + cl_uint numAssociatedDevices; + status = clGetProgramInfo( m_cpProgram, CL_PROGRAM_NUM_DEVICES, sizeof(cl_uint), &numAssociatedDevices, 0 ); + b3Assert( status == CL_SUCCESS ); + if (numAssociatedDevices==1) + { + + size_t binarySize; + char* binary ; + + status = clGetProgramInfo( m_cpProgram, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binarySize, 0 ); + b3Assert( status == CL_SUCCESS ); + + binary = (char*)malloc(sizeof(char)*binarySize); + + status = clGetProgramInfo( m_cpProgram, CL_PROGRAM_BINARIES, sizeof(char*), &binary, 0 ); + b3Assert( status == CL_SUCCESS ); + + { + FILE* file=0; +#ifdef _MSC_VER + if (fopen_s(&file,binaryFileName, "wb")!=0) + file=0; +#else + file = fopen(binaryFileName, "wb"); +#endif + if (file) + { + fwrite( binary, sizeof(char), binarySize, file ); + fclose( file ); + } else + { + b3Warning("cannot write file %s\n", binaryFileName); + } + } + + free (binary); + } + } + + free(compileFlags); + + } + return m_cpProgram; +} + + +cl_kernel b3OpenCLUtils_compileCLKernelFromString(cl_context clContext, cl_device_id device, const char* kernelSource, const char* kernelName, cl_int* pErrNum, cl_program prog, const char* additionalMacros ) +{ + + cl_kernel kernel; + cl_int localErrNum; + + cl_program m_cpProgram = prog; + + b3Printf("compiling kernel %s ",kernelName); + + if (!m_cpProgram) + { + m_cpProgram = b3OpenCLUtils_compileCLProgramFromString(clContext,device,kernelSource,pErrNum, additionalMacros,0, false); + } + + + // Create the kernel + kernel = clCreateKernel(m_cpProgram, kernelName, &localErrNum); + if (localErrNum != CL_SUCCESS) + { + b3Error("Error in clCreateKernel, Line %u in file %s, cannot find kernel function %s !!!\n\n", __LINE__, __FILE__, kernelName); + assert(0); + if (pErrNum) + *pErrNum = localErrNum; + return 0; + } + + if (!prog && m_cpProgram) + { + clReleaseProgram(m_cpProgram); + } + b3Printf("ready. \n"); + + + if (pErrNum) + *pErrNum = CL_SUCCESS; + return kernel; + +} diff --git a/extern/bullet/src/Bullet3OpenCL/Initialize/b3OpenCLUtils.h b/extern/bullet/src/Bullet3OpenCL/Initialize/b3OpenCLUtils.h new file mode 100644 index 000000000000..db6466e76b20 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/Initialize/b3OpenCLUtils.h @@ -0,0 +1,194 @@ +/* +Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org +Copyright (C) 2006 - 2011 Sony Computer Entertainment Inc. + +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. +*/ + +//original author: Roman Ponomarev +//cleanup by Erwin Coumans + +#ifndef B3_OPENCL_UTILS_H +#define B3_OPENCL_UTILS_H + +#include "b3OpenCLInclude.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +///C API for OpenCL utilities: convenience functions, see below for C++ API + +/// CL Context optionally takes a GL context. This is a generic type because we don't really want this code +/// to have to understand GL types. It is a HGLRC in _WIN32 or a GLXContext otherwise. +cl_context b3OpenCLUtils_createContextFromType(cl_device_type deviceType, cl_int* pErrNum, void* pGLCtx , void* pGLDC , int preferredDeviceIndex , int preferredPlatformIndex, cl_platform_id* platformId); + +int b3OpenCLUtils_getNumDevices(cl_context cxMainContext); + +cl_device_id b3OpenCLUtils_getDevice(cl_context cxMainContext, int nr); + +void b3OpenCLUtils_printDeviceInfo(cl_device_id device); + +cl_kernel b3OpenCLUtils_compileCLKernelFromString( cl_context clContext,cl_device_id device, const char* kernelSource, const char* kernelName, cl_int* pErrNum, cl_program prog,const char* additionalMacros); + +//optional +cl_program b3OpenCLUtils_compileCLProgramFromString( cl_context clContext,cl_device_id device, const char* kernelSource, cl_int* pErrNum,const char* additionalMacros , const char* srcFileNameForCaching, bool disableBinaryCaching); + +//the following optional APIs provide access using specific platform information +int b3OpenCLUtils_getNumPlatforms(cl_int* pErrNum); + +///get the nr'th platform, where nr is in the range [0..getNumPlatforms) +cl_platform_id b3OpenCLUtils_getPlatform(int nr, cl_int* pErrNum); + + +void b3OpenCLUtils_printPlatformInfo(cl_platform_id platform); + +const char* b3OpenCLUtils_getSdkVendorName(); + +///set the path (directory/folder) where the compiled OpenCL kernel are stored +void b3OpenCLUtils_setCachePath(const char* path); + +cl_context b3OpenCLUtils_createContextFromPlatform(cl_platform_id platform, cl_device_type deviceType, cl_int* pErrNum, void* pGLCtx , void* pGLDC ,int preferredDeviceIndex , int preferredPlatformIndex); + +#ifdef __cplusplus +} + +#define B3_MAX_STRING_LENGTH 1024 + +typedef struct +{ + char m_deviceName[B3_MAX_STRING_LENGTH]; + char m_deviceVendor[B3_MAX_STRING_LENGTH]; + char m_driverVersion[B3_MAX_STRING_LENGTH]; + char m_deviceExtensions[B3_MAX_STRING_LENGTH]; + + cl_device_type m_deviceType; + cl_uint m_computeUnits; + size_t m_workitemDims; + size_t m_workItemSize[3]; + size_t m_image2dMaxWidth; + size_t m_image2dMaxHeight; + size_t m_image3dMaxWidth; + size_t m_image3dMaxHeight; + size_t m_image3dMaxDepth; + size_t m_workgroupSize; + cl_uint m_clockFrequency; + cl_ulong m_constantBufferSize; + cl_ulong m_localMemSize; + cl_ulong m_globalMemSize; + cl_bool m_errorCorrectionSupport; + cl_device_local_mem_type m_localMemType; + cl_uint m_maxReadImageArgs; + cl_uint m_maxWriteImageArgs; + + + + cl_uint m_addressBits; + cl_ulong m_maxMemAllocSize; + cl_command_queue_properties m_queueProperties; + cl_bool m_imageSupport; + cl_uint m_vecWidthChar; + cl_uint m_vecWidthShort; + cl_uint m_vecWidthInt; + cl_uint m_vecWidthLong; + cl_uint m_vecWidthFloat; + cl_uint m_vecWidthDouble; + +} b3OpenCLDeviceInfo; + +struct b3OpenCLPlatformInfo +{ + char m_platformVendor[B3_MAX_STRING_LENGTH]; + char m_platformName[B3_MAX_STRING_LENGTH]; + char m_platformVersion[B3_MAX_STRING_LENGTH]; + + b3OpenCLPlatformInfo() + { + m_platformVendor[0]=0; + m_platformName[0]=0; + m_platformVersion[0]=0; + } +}; + + +///C++ API for OpenCL utilities: convenience functions +struct b3OpenCLUtils +{ + /// CL Context optionally takes a GL context. This is a generic type because we don't really want this code + /// to have to understand GL types. It is a HGLRC in _WIN32 or a GLXContext otherwise. + static inline cl_context createContextFromType(cl_device_type deviceType, cl_int* pErrNum, void* pGLCtx = 0, void* pGLDC = 0, int preferredDeviceIndex = -1, int preferredPlatformIndex= - 1, cl_platform_id* platformId=0) + { + return b3OpenCLUtils_createContextFromType(deviceType, pErrNum, pGLCtx , pGLDC , preferredDeviceIndex, preferredPlatformIndex, platformId); + } + + static inline int getNumDevices(cl_context cxMainContext) + { + return b3OpenCLUtils_getNumDevices(cxMainContext); + } + static inline cl_device_id getDevice(cl_context cxMainContext, int nr) + { + return b3OpenCLUtils_getDevice(cxMainContext,nr); + } + + static void getDeviceInfo(cl_device_id device, b3OpenCLDeviceInfo* info); + + static inline void printDeviceInfo(cl_device_id device) + { + b3OpenCLUtils_printDeviceInfo(device); + } + + static inline cl_kernel compileCLKernelFromString( cl_context clContext,cl_device_id device, const char* kernelSource, const char* kernelName, cl_int* pErrNum=0, cl_program prog=0,const char* additionalMacros = "" ) + { + return b3OpenCLUtils_compileCLKernelFromString(clContext,device, kernelSource, kernelName, pErrNum, prog,additionalMacros); + } + + //optional + static inline cl_program compileCLProgramFromString( cl_context clContext,cl_device_id device, const char* kernelSource, cl_int* pErrNum=0,const char* additionalMacros = "" , const char* srcFileNameForCaching=0, bool disableBinaryCaching=false) + { + return b3OpenCLUtils_compileCLProgramFromString(clContext,device, kernelSource, pErrNum,additionalMacros, srcFileNameForCaching, disableBinaryCaching); + } + + //the following optional APIs provide access using specific platform information + static inline int getNumPlatforms(cl_int* pErrNum=0) + { + return b3OpenCLUtils_getNumPlatforms(pErrNum); + } + ///get the nr'th platform, where nr is in the range [0..getNumPlatforms) + static inline cl_platform_id getPlatform(int nr, cl_int* pErrNum=0) + { + return b3OpenCLUtils_getPlatform(nr,pErrNum); + } + + static void getPlatformInfo(cl_platform_id platform, b3OpenCLPlatformInfo* platformInfo); + + static inline void printPlatformInfo(cl_platform_id platform) + { + b3OpenCLUtils_printPlatformInfo(platform); + } + + static inline const char* getSdkVendorName() + { + return b3OpenCLUtils_getSdkVendorName(); + } + static inline cl_context createContextFromPlatform(cl_platform_id platform, cl_device_type deviceType, cl_int* pErrNum, void* pGLCtx = 0, void* pGLDC = 0,int preferredDeviceIndex = -1, int preferredPlatformIndex= -1) + { + return b3OpenCLUtils_createContextFromPlatform(platform, deviceType, pErrNum, pGLCtx,pGLDC,preferredDeviceIndex, preferredPlatformIndex); + } + static void setCachePath(const char* path) + { + b3OpenCLUtils_setCachePath(path); + } +}; + +#endif //__cplusplus + +#endif // B3_OPENCL_UTILS_H diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3BvhInfo.h b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3BvhInfo.h new file mode 100644 index 000000000000..872f03950649 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3BvhInfo.h @@ -0,0 +1,18 @@ +#ifndef B3_BVH_INFO_H +#define B3_BVH_INFO_H + +#include "Bullet3Common/b3Vector3.h" + +struct b3BvhInfo +{ + b3Vector3 m_aabbMin; + b3Vector3 m_aabbMax; + b3Vector3 m_quantization; + int m_numNodes; + int m_numSubTrees; + int m_nodeOffset; + int m_subTreeOffset; + +}; + +#endif //B3_BVH_INFO_H \ No newline at end of file diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3ContactCache.cpp b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3ContactCache.cpp new file mode 100644 index 000000000000..cb30ee939b87 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3ContactCache.cpp @@ -0,0 +1,258 @@ + +#if 0 +/* +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 "b3ContactCache.h" +#include "Bullet3Common/b3Transform.h" + +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3Contact4Data.h" + +b3Scalar gContactBreakingThreshold = b3Scalar(0.02); + +///gContactCalcArea3Points will approximate the convex hull area using 3 points +///when setting it to false, it will use 4 points to compute the area: it is more accurate but slower +bool gContactCalcArea3Points = true; + + + + +static inline b3Scalar calcArea4Points(const b3Vector3 &p0,const b3Vector3 &p1,const b3Vector3 &p2,const b3Vector3 &p3) +{ + // It calculates possible 3 area constructed from random 4 points and returns the biggest one. + + b3Vector3 a[3],b[3]; + a[0] = p0 - p1; + a[1] = p0 - p2; + a[2] = p0 - p3; + b[0] = p2 - p3; + b[1] = p1 - p3; + b[2] = p1 - p2; + + //todo: Following 3 cross production can be easily optimized by SIMD. + b3Vector3 tmp0 = a[0].cross(b[0]); + b3Vector3 tmp1 = a[1].cross(b[1]); + b3Vector3 tmp2 = a[2].cross(b[2]); + + return b3Max(b3Max(tmp0.length2(),tmp1.length2()),tmp2.length2()); +} +#if 0 + +//using localPointA for all points +int b3ContactCache::sortCachedPoints(const b3Vector3& 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 + b3Scalar 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 + + b3Scalar res0(b3Scalar(0.)),res1(b3Scalar(0.)),res2(b3Scalar(0.)),res3(b3Scalar(0.)); + + if (gContactCalcArea3Points) + { + if (maxPenetrationIndex != 0) + { + b3Vector3 a0 = pt.m_localPointA-m_pointCache[1].m_localPointA; + b3Vector3 b0 = m_pointCache[3].m_localPointA-m_pointCache[2].m_localPointA; + b3Vector3 cross = a0.cross(b0); + res0 = cross.length2(); + } + if (maxPenetrationIndex != 1) + { + b3Vector3 a1 = pt.m_localPointA-m_pointCache[0].m_localPointA; + b3Vector3 b1 = m_pointCache[3].m_localPointA-m_pointCache[2].m_localPointA; + b3Vector3 cross = a1.cross(b1); + res1 = cross.length2(); + } + + if (maxPenetrationIndex != 2) + { + b3Vector3 a2 = pt.m_localPointA-m_pointCache[0].m_localPointA; + b3Vector3 b2 = m_pointCache[3].m_localPointA-m_pointCache[1].m_localPointA; + b3Vector3 cross = a2.cross(b2); + res2 = cross.length2(); + } + + if (maxPenetrationIndex != 3) + { + b3Vector3 a3 = pt.m_localPointA-m_pointCache[0].m_localPointA; + b3Vector3 b3 = m_pointCache[2].m_localPointA-m_pointCache[1].m_localPointA; + b3Vector3 cross = a3.cross(b3); + res3 = cross.length2(); + } + } + else + { + if(maxPenetrationIndex != 0) { + res0 = calcArea4Points(pt.m_localPointA,m_pointCache[1].m_localPointA,m_pointCache[2].m_localPointA,m_pointCache[3].m_localPointA); + } + + if(maxPenetrationIndex != 1) { + res1 = calcArea4Points(pt.m_localPointA,m_pointCache[0].m_localPointA,m_pointCache[2].m_localPointA,m_pointCache[3].m_localPointA); + } + + if(maxPenetrationIndex != 2) { + res2 = calcArea4Points(pt.m_localPointA,m_pointCache[0].m_localPointA,m_pointCache[1].m_localPointA,m_pointCache[3].m_localPointA); + } + + if(maxPenetrationIndex != 3) { + res3 = calcArea4Points(pt.m_localPointA,m_pointCache[0].m_localPointA,m_pointCache[1].m_localPointA,m_pointCache[2].m_localPointA); + } + } + b3Vector4 maxvec(res0,res1,res2,res3); + int biggestarea = maxvec.closestAxis4(); + return biggestarea; + +} + + +int b3ContactCache::getCacheEntry(const b3Vector3& newPoint) const +{ + b3Scalar shortestDist = getContactBreakingThreshold() * getContactBreakingThreshold(); + int size = getNumContacts(); + int nearestPoint = -1; + for( int i = 0; i < size; i++ ) + { + const b3Vector3 &mp = m_pointCache[i]; + + b3Vector3 diffA = mp.m_localPointA- newPoint.m_localPointA; + const b3Scalar distToManiPoint = diffA.dot(diffA); + if( distToManiPoint < shortestDist ) + { + shortestDist = distToManiPoint; + nearestPoint = i; + } + } + return nearestPoint; +} + +int b3ContactCache::addManifoldPoint(const b3Vector3& newPoint) +{ + b3Assert(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 + clearUserCache(m_pointCache[insertIndex]); + + } else + { + m_cachedPoints++; + + + } + if (insertIndex<0) + insertIndex=0; + + //b3Assert(m_pointCache[insertIndex].m_userPersistentData==0); + m_pointCache[insertIndex] = newPoint; + return insertIndex; +} + +#endif + +bool b3ContactCache::validContactDistance(const b3Vector3& pt) +{ + return pt.w <= gContactBreakingThreshold; +} + +void b3ContactCache::removeContactPoint(struct b3Contact4Data& newContactCache,int i) +{ + int numContacts = b3Contact4Data_getNumPoints(&newContactCache); + if (i!=(numContacts-1)) + { + b3Swap(newContactCache.m_localPosA[i],newContactCache.m_localPosA[numContacts-1]); + b3Swap(newContactCache.m_localPosB[i],newContactCache.m_localPosB[numContacts-1]); + b3Swap(newContactCache.m_worldPosB[i],newContactCache.m_worldPosB[numContacts-1]); + } + b3Contact4Data_setNumPoints(&newContactCache,numContacts-1); + +} + + +void b3ContactCache::refreshContactPoints(const b3Transform& trA,const b3Transform& trB, struct b3Contact4Data& contacts) +{ + + int numContacts = b3Contact4Data_getNumPoints(&contacts); + + + int i; + /// first refresh worldspace positions and distance + for (i=numContacts-1;i>=0;i--) + { + b3Vector3 worldPosA = trA( contacts.m_localPosA[i]); + b3Vector3 worldPosB = trB( contacts.m_localPosB[i]); + contacts.m_worldPosB[i] = worldPosB; + float distance = (worldPosA - worldPosB).dot(contacts.m_worldNormalOnB); + contacts.m_worldPosB[i].w = distance; + } + + /// then + b3Scalar distance2d; + b3Vector3 projectedDifference,projectedPoint; + for (i=numContacts-1;i>=0;i--) + { + b3Vector3 worldPosA = trA( contacts.m_localPosA[i]); + b3Vector3 worldPosB = trB( contacts.m_localPosB[i]); + b3Vector3&pt = contacts.m_worldPosB[i]; + //contact becomes invalid when signed distance exceeds margin (projected on contactnormal direction) + if (!validContactDistance(pt)) + { + removeContactPoint(contacts,i); + } else + { + //contact also becomes invalid when relative movement orthogonal to normal exceeds margin + projectedPoint = worldPosA - contacts.m_worldNormalOnB * contacts.m_worldPosB[i].w; + projectedDifference = contacts.m_worldPosB[i] - projectedPoint; + distance2d = projectedDifference.dot(projectedDifference); + if (distance2d > gContactBreakingThreshold*gContactBreakingThreshold ) + { + removeContactPoint(contacts,i); + } else + { + ////contact point processed callback + //if (gContactProcessedCallback) + // (*gContactProcessedCallback)(manifoldPoint,(void*)m_body0,(void*)m_body1); + } + } + } + + +} + + + + + +#endif diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3ContactCache.h b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3ContactCache.h new file mode 100644 index 000000000000..d6c9b0a07e4e --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3ContactCache.h @@ -0,0 +1,80 @@ + +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org + +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 B3_CONTACT_CACHE_H +#define B3_CONTACT_CACHE_H + + +#include "Bullet3Common/b3Vector3.h" +#include "Bullet3Common/b3Transform.h" +#include "Bullet3Common/b3AlignedAllocator.h" + + +///maximum contact breaking and merging threshold +extern b3Scalar gContactBreakingThreshold; + + + +#define MANIFOLD_CACHE_SIZE 4 + +///b3ContactCache is a contact point cache, it stays persistent as long as objects are overlapping in the broadphase. +///Those contact points are created by the collision narrow phase. +///The cache can be empty, or hold 1,2,3 or 4 points. Some collision algorithms (GJK) might only add one point at a time. +///updates/refreshes old contact points, and throw them away if necessary (distance becomes too large) +///reduces the cache to 4 points, when more then 4 points are added, using following rules: +///the contact point with deepest penetration is always kept, and it tries to maximuze the area covered by the points +///note that some pairs of objects might have more then one contact manifold. +B3_ATTRIBUTE_ALIGNED16( class) b3ContactCache +{ + + + + + /// sort cached points so most isolated points come first + int sortCachedPoints(const b3Vector3& pt); + + + +public: + + B3_DECLARE_ALIGNED_ALLOCATOR(); + + + + int addManifoldPoint( const b3Vector3& newPoint); + + /*void replaceContactPoint(const b3Vector3& newPoint,int insertIndex) + { + b3Assert(validContactDistance(newPoint)); + m_pointCache[insertIndex] = newPoint; + } + */ + + + + static bool validContactDistance(const b3Vector3& pt); + + /// calculated new worldspace coordinates and depth, and reject points that exceed the collision margin + static void refreshContactPoints( const b3Transform& trA,const b3Transform& trB, struct b3Contact4Data& newContactCache); + + static void removeContactPoint(struct b3Contact4Data& newContactCache,int i); + + +}; + + + +#endif //B3_CONTACT_CACHE_H diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3ConvexHullContact.cpp b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3ConvexHullContact.cpp new file mode 100644 index 000000000000..fb435aa7fddc --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3ConvexHullContact.cpp @@ -0,0 +1,4733 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2011 Advanced Micro Devices, Inc. http://bulletphysics.org + +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. +*/ + +bool findSeparatingAxisOnGpu = true; +bool splitSearchSepAxisConcave = false; +bool splitSearchSepAxisConvex = true; +bool useMprGpu = true;//use mpr for edge-edge (+contact point) or sat. Needs testing on main OpenCL platforms, before enabling... +bool bvhTraversalKernelGPU = true; +bool findConcaveSeparatingAxisKernelGPU = true; +bool clipConcaveFacesAndFindContactsCPU = false;//false;//true; +bool clipConvexFacesAndFindContactsCPU = false;//false;//true; +bool reduceConcaveContactsOnGPU = true;//false; +bool reduceConvexContactsOnGPU = true;//false; +bool findConvexClippingFacesGPU = true; +bool useGjk = false;///option for CPU/host testing, when findSeparatingAxisOnGpu = false +bool useGjkContacts = false;//////option for CPU/host testing when findSeparatingAxisOnGpu = false + + +static int myframecount=0;///for testing + +///This file was written by Erwin Coumans +///Separating axis rest based on work from Pierre Terdiman, see +///And contact clipping based on work from Simon Hobbs + +//#define B3_DEBUG_SAT_FACE + +//#define CHECK_ON_HOST + +#ifdef CHECK_ON_HOST +//#define PERSISTENT_CONTACTS_HOST +#endif + +int b3g_actualSATPairTests=0; + +#include "b3ConvexHullContact.h" +#include //memcpy +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3ConvexPolyhedronData.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3MprPenetration.h" + +#include "Bullet3OpenCL/NarrowphaseCollision/b3ContactCache.h" +#include "Bullet3Geometry/b3AabbUtil.h" + +typedef b3AlignedObjectArray b3VertexArray; + + +#include //for FLT_MAX +#include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.h" +//#include "AdlQuaternion.h" + +#include "kernels/satKernels.h" +#include "kernels/mprKernels.h" + +#include "kernels/satConcaveKernels.h" + +#include "kernels/satClipHullContacts.h" +#include "kernels/bvhTraversal.h" +#include "kernels/primitiveContacts.h" + + +#include "Bullet3Geometry/b3AabbUtil.h" + +#define BT_NARROWPHASE_SAT_PATH "src/Bullet3OpenCL/NarrowphaseCollision/kernels/sat.cl" +#define BT_NARROWPHASE_SAT_CONCAVE_PATH "src/Bullet3OpenCL/NarrowphaseCollision/kernels/satConcave.cl" + +#define BT_NARROWPHASE_MPR_PATH "src/Bullet3OpenCL/NarrowphaseCollision/kernels/mpr.cl" + + +#define BT_NARROWPHASE_CLIPHULL_PATH "src/Bullet3OpenCL/NarrowphaseCollision/kernels/satClipHullContacts.cl" +#define BT_NARROWPHASE_BVH_TRAVERSAL_PATH "src/Bullet3OpenCL/NarrowphaseCollision/kernels/bvhTraversal.cl" +#define BT_NARROWPHASE_PRIMITIVE_CONTACT_PATH "src/Bullet3OpenCL/NarrowphaseCollision/kernels/primitiveContacts.cl" + + +#ifndef __global +#define __global +#endif + +#ifndef __kernel +#define __kernel +#endif + + +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3BvhTraversal.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3FindConcaveSatAxis.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3ClipFaces.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3NewContactReduction.h" + + + +#define dot3F4 b3Dot + +GpuSatCollision::GpuSatCollision(cl_context ctx,cl_device_id device, cl_command_queue q ) +:m_context(ctx), +m_device(device), +m_queue(q), + +m_findSeparatingAxisKernel(0), +m_findSeparatingAxisVertexFaceKernel(0), +m_findSeparatingAxisEdgeEdgeKernel(0), +m_unitSphereDirections(m_context,m_queue), + +m_totalContactsOut(m_context, m_queue), +m_sepNormals(m_context, m_queue), +m_dmins(m_context,m_queue), + +m_hasSeparatingNormals(m_context, m_queue), +m_concaveSepNormals(m_context, m_queue), +m_concaveHasSeparatingNormals(m_context,m_queue), +m_numConcavePairsOut(m_context, m_queue), + + +m_gpuCompoundPairs(m_context, m_queue), + + +m_gpuCompoundSepNormals(m_context, m_queue), +m_gpuHasCompoundSepNormals(m_context, m_queue), + +m_numCompoundPairsOut(m_context, m_queue) +{ + m_totalContactsOut.push_back(0); + + cl_int errNum=0; + + if (1) + { + const char* mprSrc = mprKernelsCL; + + const char* srcConcave = satConcaveKernelsCL; + char flags[1024]={0}; +//#ifdef CL_PLATFORM_INTEL +// sprintf(flags,"-g -s \"%s\"","C:/develop/bullet3_experiments2/opencl/gpu_narrowphase/kernels/sat.cl"); +//#endif + m_mprPenetrationKernel = 0; + m_findSeparatingAxisUnitSphereKernel = 0; + + if (useMprGpu) + { + cl_program mprProg = b3OpenCLUtils::compileCLProgramFromString(m_context,m_device,mprSrc,&errNum,flags,BT_NARROWPHASE_MPR_PATH); + b3Assert(errNum==CL_SUCCESS); + + m_mprPenetrationKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,mprSrc, "mprPenetrationKernel",&errNum,mprProg ); + b3Assert(m_mprPenetrationKernel); + b3Assert(errNum==CL_SUCCESS); + + m_findSeparatingAxisUnitSphereKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,mprSrc, "findSeparatingAxisUnitSphereKernel",&errNum,mprProg ); + b3Assert(m_findSeparatingAxisUnitSphereKernel); + b3Assert(errNum==CL_SUCCESS); + + + int numDirections = sizeof(unitSphere162)/sizeof(b3Vector3); + m_unitSphereDirections.resize(numDirections); + m_unitSphereDirections.copyFromHostPointer(unitSphere162,numDirections,0,true); + + + } + + + cl_program satProg = b3OpenCLUtils::compileCLProgramFromString(m_context,m_device,satKernelsCL,&errNum,flags,BT_NARROWPHASE_SAT_PATH); + b3Assert(errNum==CL_SUCCESS); + + cl_program satConcaveProg = b3OpenCLUtils::compileCLProgramFromString(m_context,m_device,srcConcave,&errNum,flags,BT_NARROWPHASE_SAT_CONCAVE_PATH); + b3Assert(errNum==CL_SUCCESS); + + m_findSeparatingAxisKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,satKernelsCL, "findSeparatingAxisKernel",&errNum,satProg ); + b3Assert(m_findSeparatingAxisKernel); + b3Assert(errNum==CL_SUCCESS); + + + m_findSeparatingAxisVertexFaceKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,satKernelsCL, "findSeparatingAxisVertexFaceKernel",&errNum,satProg ); + b3Assert(m_findSeparatingAxisVertexFaceKernel); + + m_findSeparatingAxisEdgeEdgeKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,satKernelsCL, "findSeparatingAxisEdgeEdgeKernel",&errNum,satProg ); + b3Assert(m_findSeparatingAxisVertexFaceKernel); + + + m_findConcaveSeparatingAxisKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,satKernelsCL, "findConcaveSeparatingAxisKernel",&errNum,satProg ); + b3Assert(m_findConcaveSeparatingAxisKernel); + b3Assert(errNum==CL_SUCCESS); + + m_findConcaveSeparatingAxisVertexFaceKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,srcConcave, "findConcaveSeparatingAxisVertexFaceKernel",&errNum,satConcaveProg ); + b3Assert(m_findConcaveSeparatingAxisVertexFaceKernel); + b3Assert(errNum==CL_SUCCESS); + + m_findConcaveSeparatingAxisEdgeEdgeKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,srcConcave, "findConcaveSeparatingAxisEdgeEdgeKernel",&errNum,satConcaveProg ); + b3Assert(m_findConcaveSeparatingAxisEdgeEdgeKernel); + b3Assert(errNum==CL_SUCCESS); + + + + + m_findCompoundPairsKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,satKernelsCL, "findCompoundPairsKernel",&errNum,satProg ); + b3Assert(m_findCompoundPairsKernel); + b3Assert(errNum==CL_SUCCESS); + m_processCompoundPairsKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,satKernelsCL, "processCompoundPairsKernel",&errNum,satProg ); + b3Assert(m_processCompoundPairsKernel); + b3Assert(errNum==CL_SUCCESS); + } + + if (1) + { + const char* srcClip = satClipKernelsCL; + + char flags[1024]={0}; +//#ifdef CL_PLATFORM_INTEL +// sprintf(flags,"-g -s \"%s\"","C:/develop/bullet3_experiments2/opencl/gpu_narrowphase/kernels/satClipHullContacts.cl"); +//#endif + + cl_program satClipContactsProg = b3OpenCLUtils::compileCLProgramFromString(m_context,m_device,srcClip,&errNum,flags,BT_NARROWPHASE_CLIPHULL_PATH); + b3Assert(errNum==CL_SUCCESS); + + m_clipHullHullKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,srcClip, "clipHullHullKernel",&errNum,satClipContactsProg); + b3Assert(errNum==CL_SUCCESS); + + m_clipCompoundsHullHullKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,srcClip, "clipCompoundsHullHullKernel",&errNum,satClipContactsProg); + b3Assert(errNum==CL_SUCCESS); + + + m_findClippingFacesKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,srcClip, "findClippingFacesKernel",&errNum,satClipContactsProg); + b3Assert(errNum==CL_SUCCESS); + + m_clipFacesAndFindContacts = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,srcClip, "clipFacesAndFindContactsKernel",&errNum,satClipContactsProg); + b3Assert(errNum==CL_SUCCESS); + + m_clipHullHullConcaveConvexKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,srcClip, "clipHullHullConcaveConvexKernel",&errNum,satClipContactsProg); + b3Assert(errNum==CL_SUCCESS); + +// m_extractManifoldAndAddContactKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,srcClip, "extractManifoldAndAddContactKernel",&errNum,satClipContactsProg); + // b3Assert(errNum==CL_SUCCESS); + + m_newContactReductionKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,srcClip, + "newContactReductionKernel",&errNum,satClipContactsProg); + b3Assert(errNum==CL_SUCCESS); + } + else + { + m_clipHullHullKernel=0; + m_clipCompoundsHullHullKernel = 0; + m_findClippingFacesKernel = 0; + m_newContactReductionKernel=0; + m_clipFacesAndFindContacts = 0; + m_clipHullHullConcaveConvexKernel = 0; +// m_extractManifoldAndAddContactKernel = 0; + } + + if (1) + { + const char* srcBvh = bvhTraversalKernelCL; + cl_program bvhTraversalProg = b3OpenCLUtils::compileCLProgramFromString(m_context,m_device,srcBvh,&errNum,"",BT_NARROWPHASE_BVH_TRAVERSAL_PATH); + b3Assert(errNum==CL_SUCCESS); + + m_bvhTraversalKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,srcBvh, "bvhTraversalKernel",&errNum,bvhTraversalProg,""); + b3Assert(errNum==CL_SUCCESS); + + } + + { + const char* primitiveContactsSrc = primitiveContactsKernelsCL; + cl_program primitiveContactsProg = b3OpenCLUtils::compileCLProgramFromString(m_context,m_device,primitiveContactsSrc,&errNum,"",BT_NARROWPHASE_PRIMITIVE_CONTACT_PATH); + b3Assert(errNum==CL_SUCCESS); + + m_primitiveContactsKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,primitiveContactsSrc, "primitiveContactsKernel",&errNum,primitiveContactsProg,""); + b3Assert(errNum==CL_SUCCESS); + + m_findConcaveSphereContactsKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,primitiveContactsSrc, "findConcaveSphereContactsKernel",&errNum,primitiveContactsProg ); + b3Assert(errNum==CL_SUCCESS); + b3Assert(m_findConcaveSphereContactsKernel); + + m_processCompoundPairsPrimitivesKernel = b3OpenCLUtils::compileCLKernelFromString(m_context, m_device,primitiveContactsSrc, "processCompoundPairsPrimitivesKernel",&errNum,primitiveContactsProg,""); + b3Assert(errNum==CL_SUCCESS); + b3Assert(m_processCompoundPairsPrimitivesKernel); + + } + + +} + +GpuSatCollision::~GpuSatCollision() +{ + + if (m_findSeparatingAxisVertexFaceKernel) + clReleaseKernel(m_findSeparatingAxisVertexFaceKernel); + + if (m_findSeparatingAxisEdgeEdgeKernel) + clReleaseKernel(m_findSeparatingAxisEdgeEdgeKernel); + + if (m_findSeparatingAxisUnitSphereKernel) + clReleaseKernel(m_findSeparatingAxisUnitSphereKernel); + + if (m_mprPenetrationKernel) + clReleaseKernel(m_mprPenetrationKernel); + + + if (m_findSeparatingAxisKernel) + clReleaseKernel(m_findSeparatingAxisKernel); + + if (m_findConcaveSeparatingAxisVertexFaceKernel) + clReleaseKernel(m_findConcaveSeparatingAxisVertexFaceKernel); + + + if (m_findConcaveSeparatingAxisEdgeEdgeKernel) + clReleaseKernel(m_findConcaveSeparatingAxisEdgeEdgeKernel); + + if (m_findConcaveSeparatingAxisKernel) + clReleaseKernel(m_findConcaveSeparatingAxisKernel); + + if (m_findCompoundPairsKernel) + clReleaseKernel(m_findCompoundPairsKernel); + + if (m_processCompoundPairsKernel) + clReleaseKernel(m_processCompoundPairsKernel); + + if (m_findClippingFacesKernel) + clReleaseKernel(m_findClippingFacesKernel); + + if (m_clipFacesAndFindContacts) + clReleaseKernel(m_clipFacesAndFindContacts); + if (m_newContactReductionKernel) + clReleaseKernel(m_newContactReductionKernel); + if (m_primitiveContactsKernel) + clReleaseKernel(m_primitiveContactsKernel); + + if (m_findConcaveSphereContactsKernel) + clReleaseKernel(m_findConcaveSphereContactsKernel); + + if (m_processCompoundPairsPrimitivesKernel) + clReleaseKernel(m_processCompoundPairsPrimitivesKernel); + + if (m_clipHullHullKernel) + clReleaseKernel(m_clipHullHullKernel); + if (m_clipCompoundsHullHullKernel) + clReleaseKernel(m_clipCompoundsHullHullKernel); + + if (m_clipHullHullConcaveConvexKernel) + clReleaseKernel(m_clipHullHullConcaveConvexKernel); +// if (m_extractManifoldAndAddContactKernel) + // clReleaseKernel(m_extractManifoldAndAddContactKernel); + + if (m_bvhTraversalKernel) + clReleaseKernel(m_bvhTraversalKernel); + +} + +struct MyTriangleCallback : public b3NodeOverlapCallback +{ + int m_bodyIndexA; + int m_bodyIndexB; + + virtual void processNode(int subPart, int triangleIndex) + { + printf("bodyIndexA %d, bodyIndexB %d\n",m_bodyIndexA,m_bodyIndexB); + printf("triangleIndex %d\n", triangleIndex); + } +}; + + +#define float4 b3Vector3 +#define make_float4(x,y,z,w) b3MakeVector3(x,y,z,w) + +float signedDistanceFromPointToPlane(const float4& point, const float4& planeEqn, float4* closestPointOnFace) +{ + float4 n = planeEqn; + n[3] = 0.f; + float dist = dot3F4(n, point) + planeEqn[3]; + *closestPointOnFace = point - dist * n; + return dist; +} + + + +#define cross3(a,b) (a.cross(b)) +b3Vector3 transform(const b3Vector3* v, const b3Vector3* pos, const b3Quaternion* orn) +{ + b3Transform tr; + tr.setIdentity(); + tr.setOrigin(*pos); + tr.setRotation(*orn); + b3Vector3 res = tr(*v); + return res; +} + + +inline bool IsPointInPolygon(const float4& p, + const b3GpuFace* face, + const float4* baseVertex, + const int* convexIndices, + float4* out) +{ + float4 a; + float4 b; + float4 ab; + float4 ap; + float4 v; + + float4 plane = b3MakeVector3(face->m_plane.x,face->m_plane.y,face->m_plane.z,0.f); + + if (face->m_numIndices<2) + return false; + + + float4 v0 = baseVertex[convexIndices[face->m_indexOffset + face->m_numIndices-1]]; + b = v0; + + for(unsigned i=0; i != face->m_numIndices; ++i) + { + a = b; + float4 vi = baseVertex[convexIndices[face->m_indexOffset + i]]; + b = vi; + ab = b-a; + ap = p-a; + v = cross3(ab,plane); + + if (b3Dot(ap, v) > 0.f) + { + float ab_m2 = b3Dot(ab, ab); + float rt = ab_m2 != 0.f ? b3Dot(ab, ap) / ab_m2 : 0.f; + if (rt <= 0.f) + { + *out = a; + } + else if (rt >= 1.f) + { + *out = b; + } + else + { + float s = 1.f - rt; + out[0].x = s * a.x + rt * b.x; + out[0].y = s * a.y + rt * b.y; + out[0].z = s * a.z + rt * b.z; + } + return false; + } + } + return true; +} + +#define normalize3(a) (a.normalize()) + + +int extractManifoldSequentialGlobal( const float4* p, int nPoints, const float4& nearNormal, b3Int4* contactIdx) +{ + if( nPoints == 0 ) + return 0; + + if (nPoints <=4) + return nPoints; + + + if (nPoints >64) + nPoints = 64; + + float4 center = b3MakeVector3(0,0,0,0); + { + + for (int i=0;i& vertices, b3Scalar& min, b3Scalar& max) +{ + min = FLT_MAX; + max = -FLT_MAX; + int numVerts = hull.m_numVertices; + + const float4 localDir = b3QuatRotate(orn.inverse(),dir); + + b3Scalar offset = dot3F4(pos,dir); + + for(int i=0;i max) max = dp; + } + if(min>max) + { + b3Scalar tmp = min; + min = max; + max = tmp; + } + min += offset; + max += offset; +} + + +static bool TestSepAxis(const b3ConvexPolyhedronData& hullA, const b3ConvexPolyhedronData& hullB, + const float4& posA,const b3Quaternion& ornA, + const float4& posB,const b3Quaternion& ornB, + const float4& sep_axis, const b3AlignedObjectArray& verticesA,const b3AlignedObjectArray& verticesB,b3Scalar& depth) +{ + b3Scalar Min0,Max0; + b3Scalar Min1,Max1; + project(hullA,posA,ornA,sep_axis,verticesA, Min0, Max0); + project(hullB,posB,ornB, sep_axis,verticesB, Min1, Max1); + + if(Max0=0.0f); + b3Scalar d1 = Max1 - Min0; + assert(d1>=0.0f); + depth = d01e-6 || fabsf(v.y)>1e-6 || fabsf(v.z)>1e-6) return false; + return true; +} + + +static bool findSeparatingAxis( const b3ConvexPolyhedronData& hullA, const b3ConvexPolyhedronData& hullB, + const float4& posA1, + const b3Quaternion& ornA, + const float4& posB1, + const b3Quaternion& ornB, + const b3AlignedObjectArray& verticesA, + const b3AlignedObjectArray& uniqueEdgesA, + const b3AlignedObjectArray& facesA, + const b3AlignedObjectArray& indicesA, + const b3AlignedObjectArray& verticesB, + const b3AlignedObjectArray& uniqueEdgesB, + const b3AlignedObjectArray& facesB, + const b3AlignedObjectArray& indicesB, + + b3Vector3& sep) +{ + B3_PROFILE("findSeparatingAxis"); + + b3g_actualSATPairTests++; + float4 posA = posA1; + posA.w = 0.f; + float4 posB = posB1; + posB.w = 0.f; +//#ifdef TEST_INTERNAL_OBJECTS + float4 c0local = (float4&)hullA.m_localCenter; + float4 c0 = transform(&c0local, &posA, &ornA); + float4 c1local = (float4&)hullB.m_localCenter; + float4 c1 = transform(&c1local,&posB,&ornB); + const float4 deltaC2 = c0 - c1; +//#endif + + b3Scalar dmin = FLT_MAX; + int curPlaneTests=0; + + int numFacesA = hullA.m_numFaces; + // Test normals from hullA + for(int i=0;i0.0f) + sep = -sep; + + return true; +} + + +bool findSeparatingAxisEdgeEdge( __global const b3ConvexPolyhedronData* hullA, __global const b3ConvexPolyhedronData* hullB, + const b3Float4& posA1, + const b3Quat& ornA, + const b3Float4& posB1, + const b3Quat& ornB, + const b3Float4& DeltaC2, + __global const b3AlignedObjectArray& vertices, + __global const b3AlignedObjectArray& uniqueEdges, + __global const b3AlignedObjectArray& faces, + __global const b3AlignedObjectArray& indices, + float4* sep, + float* dmin) +{ +// int i = get_global_id(0); + + float4 posA = posA1; + posA.w = 0.f; + float4 posB = posB1; + posB.w = 0.f; + + //int curPlaneTests=0; + + int curEdgeEdge = 0; + // Test edges + for(int e0=0;e0m_numUniqueEdges;e0++) + { + const float4 edge0 = uniqueEdges[hullA->m_uniqueEdgesOffset+e0]; + float4 edge0World = b3QuatRotate(ornA,edge0); + + for(int e1=0;e1m_numUniqueEdges;e1++) + { + const float4 edge1 = uniqueEdges[hullB->m_uniqueEdgesOffset+e1]; + float4 edge1World = b3QuatRotate(ornB,edge1); + + + float4 crossje = cross3(edge0World,edge1World); + + curEdgeEdge++; + if(!IsAlmostZero(crossje)) + { + crossje = normalize3(crossje); + if (dot3F4(DeltaC2,crossje)<0) + crossje*=-1.f; + + float dist; + bool result = true; + { + float Min0,Max0; + float Min1,Max1; + project(*hullA,posA,ornA,crossje,vertices, Min0, Max0); + project(*hullB,posB,ornB,crossje,vertices, Min1, Max1); + + if(Max00.0f) + { + *sep = -(*sep); + } + return true; +} + + +__inline float4 lerp3(const float4& a,const float4& b, float t) +{ + return b3MakeVector3( a.x + (b.x - a.x) * t, + a.y + (b.y - a.y) * t, + a.z + (b.z - a.z) * t, + 0.f); +} + + +// Clips a face to the back of a plane, return the number of vertices out, stored in ppVtxOut +int clipFace(const float4* pVtxIn, int numVertsIn, float4& planeNormalWS,float planeEqWS, float4* ppVtxOut) +{ + + int ve; + float ds, de; + int numVertsOut = 0; + if (numVertsIn < 2) + return 0; + + float4 firstVertex=pVtxIn[numVertsIn-1]; + float4 endVertex = pVtxIn[0]; + + ds = dot3F4(planeNormalWS,firstVertex)+planeEqWS; + + for (ve = 0; ve < numVertsIn; ve++) + { + endVertex=pVtxIn[ve]; + + de = dot3F4(planeNormalWS,endVertex)+planeEqWS; + + if (ds<0) + { + if (de<0) + { + // Start < 0, end < 0, so output endVertex + ppVtxOut[numVertsOut++] = endVertex; + } + else + { + // Start < 0, end >= 0, so output intersection + ppVtxOut[numVertsOut++] = lerp3(firstVertex, endVertex,(ds * 1.f/(ds - de)) ); + } + } + else + { + if (de<0) + { + // Start >= 0, end < 0 so output intersection and end + ppVtxOut[numVertsOut++] = lerp3(firstVertex, endVertex,(ds * 1.f/(ds - de)) ); + ppVtxOut[numVertsOut++] = endVertex; + } + } + firstVertex = endVertex; + ds = de; + } + return numVertsOut; +} + + +int clipFaceAgainstHull(const float4& separatingNormal, const b3ConvexPolyhedronData* hullA, + const float4& posA, const b3Quaternion& ornA, float4* worldVertsB1, int numWorldVertsB1, + float4* worldVertsB2, int capacityWorldVertsB2, + const float minDist, float maxDist, + const b3AlignedObjectArray& verticesA, const b3AlignedObjectArray& facesA, const b3AlignedObjectArray& indicesA, + //const float4* verticesB, const b3GpuFace* facesB, const int* indicesB, + float4* contactsOut, + int contactCapacity) +{ + int numContactsOut = 0; + + float4* pVtxIn = worldVertsB1; + float4* pVtxOut = worldVertsB2; + + int numVertsIn = numWorldVertsB1; + int numVertsOut = 0; + + int closestFaceA=-1; + { + float dmin = FLT_MAX; + for(int face=0;facem_numFaces;face++) + { + const float4 Normal = b3MakeVector3( + facesA[hullA->m_faceOffset+face].m_plane.x, + facesA[hullA->m_faceOffset+face].m_plane.y, + facesA[hullA->m_faceOffset+face].m_plane.z,0.f); + const float4 faceANormalWS = b3QuatRotate(ornA,Normal); + + float d = dot3F4(faceANormalWS,separatingNormal); + if (d < dmin) + { + dmin = d; + closestFaceA = face; + } + } + } + if (closestFaceA<0) + return numContactsOut; + + b3GpuFace polyA = facesA[hullA->m_faceOffset+closestFaceA]; + + // clip polygon to back of planes of all faces of hull A that are adjacent to witness face +// int numContacts = numWorldVertsB1; + int numVerticesA = polyA.m_numIndices; + for(int e0=0;e0m_vertexOffset+indicesA[polyA.m_indexOffset+e0]]; + const float4 b = verticesA[hullA->m_vertexOffset+indicesA[polyA.m_indexOffset+((e0+1)%numVerticesA)]]; + const float4 edge0 = a - b; + const float4 WorldEdge0 = b3QuatRotate(ornA,edge0); + float4 planeNormalA = make_float4(polyA.m_plane.x,polyA.m_plane.y,polyA.m_plane.z,0.f); + float4 worldPlaneAnormal1 = b3QuatRotate(ornA,planeNormalA); + + float4 planeNormalWS1 = -cross3(WorldEdge0,worldPlaneAnormal1); + float4 worldA1 = transform(&a,&posA,&ornA); + float planeEqWS1 = -dot3F4(worldA1,planeNormalWS1); + + float4 planeNormalWS = planeNormalWS1; + float planeEqWS=planeEqWS1; + + //clip face + //clipFace(*pVtxIn, *pVtxOut,planeNormalWS,planeEqWS); + numVertsOut = clipFace(pVtxIn, numVertsIn, planeNormalWS,planeEqWS, pVtxOut); + + //btSwap(pVtxIn,pVtxOut); + float4* tmp = pVtxOut; + pVtxOut = pVtxIn; + pVtxIn = tmp; + numVertsIn = numVertsOut; + numVertsOut = 0; + } + + + // only keep points that are behind the witness face + { + float4 localPlaneNormal = make_float4(polyA.m_plane.x,polyA.m_plane.y,polyA.m_plane.z,0.f); + float localPlaneEq = polyA.m_plane.w; + float4 planeNormalWS = b3QuatRotate(ornA,localPlaneNormal); + float planeEqWS=localPlaneEq-dot3F4(planeNormalWS,posA); + for (int i=0;i& verticesA, const b3AlignedObjectArray& facesA, const b3AlignedObjectArray& indicesA, + const b3AlignedObjectArray& verticesB, const b3AlignedObjectArray& facesB, const b3AlignedObjectArray& indicesB, + + float4* contactsOut, + int contactCapacity) +{ + int numContactsOut = 0; + int numWorldVertsB1= 0; + + B3_PROFILE("clipHullAgainstHull"); + +// float curMaxDist=maxDist; + int closestFaceB=-1; + float dmax = -FLT_MAX; + + { + //B3_PROFILE("closestFaceB"); + if (hullB.m_numFaces!=1) + { + //printf("wtf\n"); + } + static bool once = true; + //printf("separatingNormal=%f,%f,%f\n",separatingNormal.x,separatingNormal.y,separatingNormal.z); + + for(int face=0;facem_numIndices;i++) + { + float4 vert = verticesB[hullB.m_vertexOffset+indicesB[faceB->m_indexOffset+i]]; + printf("vert[%d] = %f,%f,%f\n",i,vert.x,vert.y,vert.z); + } + } +#endif //BT_DEBUG_SAT_FACE + //if (facesB[hullB.m_faceOffset+face].m_numIndices>2) + { + const float4 Normal = b3MakeVector3(facesB[hullB.m_faceOffset+face].m_plane.x, + facesB[hullB.m_faceOffset+face].m_plane.y, facesB[hullB.m_faceOffset+face].m_plane.z,0.f); + const float4 WorldNormal = b3QuatRotate(ornB, Normal); +#ifdef BT_DEBUG_SAT_FACE + if (once) + printf("faceNormal = %f,%f,%f\n",Normal.x,Normal.y,Normal.z); +#endif + float d = dot3F4(WorldNormal,separatingNormal); + if (d > dmax) + { + dmax = d; + closestFaceB = face; + } + } + } + once = false; + } + + + b3Assert(closestFaceB>=0); + { + //B3_PROFILE("worldVertsB1"); + const b3GpuFace& polyB = facesB[hullB.m_faceOffset+closestFaceB]; + const int numVertices = polyB.m_numIndices; + for(int e0=0;e0=0) + { + //B3_PROFILE("clipFaceAgainstHull"); + numContactsOut = clipFaceAgainstHull((float4&)separatingNormal, &hullA, + posA,ornA, + worldVertsB1,numWorldVertsB1,worldVertsB2,capacityWorldVerts, minDist, maxDist, + verticesA, facesA, indicesA, + contactsOut,contactCapacity); + } + + return numContactsOut; +} + + + + + + +#define PARALLEL_SUM(v, n) for(int j=1; j v[i+offset].y)? v[i]: v[i+offset]; } +#define REDUCE_MIN(v, n) {int i=0;\ +for(int offset=0; offset64) + nPoints = 64; + + float4 center = make_float4(0,0,0,0); + { + + for (int i=0;i* bodyBuf, + b3AlignedObjectArray* globalContactOut, + int& nContacts, + + const b3AlignedObjectArray& hostConvexDataA, + const b3AlignedObjectArray& hostConvexDataB, + + const b3AlignedObjectArray& verticesA, + const b3AlignedObjectArray& uniqueEdgesA, + const b3AlignedObjectArray& facesA, + const b3AlignedObjectArray& indicesA, + + const b3AlignedObjectArray& verticesB, + const b3AlignedObjectArray& uniqueEdgesB, + const b3AlignedObjectArray& facesB, + const b3AlignedObjectArray& indicesB, + + const b3AlignedObjectArray& hostCollidablesA, + const b3AlignedObjectArray& hostCollidablesB, + const b3Vector3& sepNormalWorldSpace, + int maxContactCapacity ) +{ + int contactIndex = -1; + b3ConvexPolyhedronData hullA, hullB; + + b3Collidable colA = hostCollidablesA[collidableIndexA]; + hullA = hostConvexDataA[colA.m_shapeIndex]; + //printf("numvertsA = %d\n",hullA.m_numVertices); + + + b3Collidable colB = hostCollidablesB[collidableIndexB]; + hullB = hostConvexDataB[colB.m_shapeIndex]; + //printf("numvertsB = %d\n",hullB.m_numVertices); + + + float4 contactsOut[MAX_VERTS]; + int localContactCapacity = MAX_VERTS; + +#ifdef _WIN32 + b3Assert(_finite(bodyBuf->at(bodyIndexA).m_pos.x)); + b3Assert(_finite(bodyBuf->at(bodyIndexB).m_pos.x)); +#endif + + + { + + float4 worldVertsB1[MAX_VERTS]; + float4 worldVertsB2[MAX_VERTS]; + int capacityWorldVerts = MAX_VERTS; + + float4 hostNormal = make_float4(sepNormalWorldSpace.x,sepNormalWorldSpace.y,sepNormalWorldSpace.z,0.f); + int shapeA = hostCollidablesA[collidableIndexA].m_shapeIndex; + int shapeB = hostCollidablesB[collidableIndexB].m_shapeIndex; + + b3Scalar minDist = -1; + b3Scalar maxDist = 0.; + + + + b3Transform trA,trB; + { + //B3_PROFILE("transform computation"); + //trA.setIdentity(); + trA.setOrigin(b3MakeVector3(posA.x,posA.y,posA.z)); + trA.setRotation(b3Quaternion(ornA.x,ornA.y,ornA.z,ornA.w)); + + //trB.setIdentity(); + trB.setOrigin(b3MakeVector3(posB.x,posB.y,posB.z)); + trB.setRotation(b3Quaternion(ornB.x,ornB.y,ornB.z,ornB.w)); + } + + b3Quaternion trAorn = trA.getRotation(); + b3Quaternion trBorn = trB.getRotation(); + + int numContactsOut = clipHullAgainstHull(hostNormal, + hostConvexDataA.at(shapeA), + hostConvexDataB.at(shapeB), + (float4&)trA.getOrigin(), (b3Quaternion&)trAorn, + (float4&)trB.getOrigin(), (b3Quaternion&)trBorn, + worldVertsB1,worldVertsB2,capacityWorldVerts, + minDist, maxDist, + verticesA, facesA,indicesA, + verticesB, facesB,indicesB, + + contactsOut,localContactCapacity); + + if (numContactsOut>0) + { + B3_PROFILE("overlap"); + + float4 normalOnSurfaceB = (float4&)hostNormal; + + b3Int4 contactIdx; + contactIdx.x = 0; + contactIdx.y = 1; + contactIdx.z = 2; + contactIdx.w = 3; + + int numPoints = 0; + + { + // B3_PROFILE("extractManifold"); + numPoints = extractManifold(contactsOut, numContactsOut, normalOnSurfaceB, &contactIdx); + } + + b3Assert(numPoints); + + if (nContactsexpand(); + b3Contact4& contact = globalContactOut->at(nContacts); + contact.m_batchIdx = 0;//i; + contact.m_bodyAPtrAndSignBit = (bodyBuf->at(bodyIndexA).m_invMass==0)? -bodyIndexA:bodyIndexA; + contact.m_bodyBPtrAndSignBit = (bodyBuf->at(bodyIndexB).m_invMass==0)? -bodyIndexB:bodyIndexB; + + contact.m_frictionCoeffCmp = 45874; + contact.m_restituitionCoeffCmp = 0; + + // float distance = 0.f; + for (int p=0;pm_numVertices;i++) + { + b3Vector3 vtx = convexVertices[hullB->m_vertexOffset+i]; + float curDot = vtx.dot(planeNormalInConvex); + + + if (curDot>maxDot) + { + hitVertex=i; + maxDot=curDot; + hitVtx = vtx; + //make sure the deepest points is always included + if (numPoints==MAX_PLANE_CONVEX_POINTS) + numPoints--; + } + + if (numPoints4) + { + numReducedPoints = extractManifoldSequentialGlobal( contactPoints, numPoints, planeNormalInConvex, &contactIdx); + } + int dstIdx; +// dstIdx = nGlobalContactsOut++;//AppendInc( nGlobalContactsOut, dstIdx ); + + if (numReducedPoints>0) + { + if (nGlobalContactsOut < maxContactCapacity) + { + dstIdx=nGlobalContactsOut; + nGlobalContactsOut++; + + b3Contact4* c = &globalContactsOut[dstIdx]; + c->m_worldNormalOnB = -planeNormalWorld; + c->setFrictionCoeff(0.7); + c->setRestituitionCoeff(0.f); + + c->m_batchIdx = pairIndex; + c->m_bodyAPtrAndSignBit = rigidBodies[bodyIndexA].m_invMass==0?-bodyIndexA:bodyIndexA; + c->m_bodyBPtrAndSignBit = rigidBodies[bodyIndexB].m_invMass==0?-bodyIndexB:bodyIndexB; + for (int i=0;im_worldPosB[i] = pOnB1; + } + c->m_worldNormalOnB.w = (b3Scalar)numReducedPoints; + }//if (dstIdx < numPairs) + } + + + +// printf("computeContactPlaneConvex\n"); +} + + + +B3_FORCE_INLINE b3Vector3 MyUnQuantize(const unsigned short* vecIn, const b3Vector3& quantization, const b3Vector3& bvhAabbMin) + { + b3Vector3 vecOut; + vecOut.setValue( + (b3Scalar)(vecIn[0]) / (quantization.x), + (b3Scalar)(vecIn[1]) / (quantization.y), + (b3Scalar)(vecIn[2]) / (quantization.z)); + vecOut += bvhAabbMin; + return vecOut; + } + +void traverseTreeTree() +{ + +} + +#include "Bullet3Common/shared/b3Mat3x3.h" + +int numAabbChecks = 0; +int maxNumAabbChecks = 0; +int maxDepth = 0; + +// work-in-progress +__kernel void findCompoundPairsKernel( + int pairIndex, + int bodyIndexA, + int bodyIndexB, + int collidableIndexA, + int collidableIndexB, + __global const b3RigidBodyData* rigidBodies, + __global const b3Collidable* collidables, + __global const b3ConvexPolyhedronData* convexShapes, + __global const b3AlignedObjectArray& vertices, + __global const b3AlignedObjectArray& aabbsWorldSpace, + __global const b3AlignedObjectArray& aabbsLocalSpace, + __global const b3GpuChildShape* gpuChildShapes, + __global b3Int4* gpuCompoundPairsOut, + __global int* numCompoundPairsOut, + int maxNumCompoundPairsCapacity, + b3AlignedObjectArray& treeNodesCPU, + b3AlignedObjectArray& subTreesCPU, + b3AlignedObjectArray& bvhInfoCPU + ) +{ + numAabbChecks=0; + maxNumAabbChecks=0; +// int i = pairIndex; + { + + + int shapeIndexA = collidables[collidableIndexA].m_shapeIndex; + int shapeIndexB = collidables[collidableIndexB].m_shapeIndex; + + + //once the broadphase avoids static-static pairs, we can remove this test + if ((rigidBodies[bodyIndexA].m_invMass==0) &&(rigidBodies[bodyIndexB].m_invMass==0)) + { + return; + } + + if ((collidables[collidableIndexA].m_shapeType==SHAPE_COMPOUND_OF_CONVEX_HULLS) &&(collidables[collidableIndexB].m_shapeType==SHAPE_COMPOUND_OF_CONVEX_HULLS)) + { + int bvhA = collidables[collidableIndexA].m_compoundBvhIndex; + int bvhB = collidables[collidableIndexB].m_compoundBvhIndex; + int numSubTreesA = bvhInfoCPU[bvhA].m_numSubTrees; + int subTreesOffsetA = bvhInfoCPU[bvhA].m_subTreeOffset; + int subTreesOffsetB = bvhInfoCPU[bvhB].m_subTreeOffset; + + + int numSubTreesB = bvhInfoCPU[bvhB].m_numSubTrees; + + float4 posA = rigidBodies[bodyIndexA].m_pos; + b3Quat ornA = rigidBodies[bodyIndexA].m_quat; + + b3Transform transA; + transA.setIdentity(); + transA.setOrigin(posA); + transA.setRotation(ornA); + + b3Quat ornB = rigidBodies[bodyIndexB].m_quat; + float4 posB = rigidBodies[bodyIndexB].m_pos; + + b3Transform transB; + transB.setIdentity(); + transB.setOrigin(posB); + transB.setRotation(ornB); + + + + for (int p=0;p nodeStack; + b3Int2 node0; + node0.x = startNodeIndexA; + node0.y = startNodeIndexB; + + int maxStackDepth = 1024; + nodeStack.resize(maxStackDepth); + int depth=0; + nodeStack[depth++]=node0; + + do + { + if (depth > maxDepth) + { + maxDepth=depth; + printf("maxDepth=%d\n",maxDepth); + } + b3Int2 node = nodeStack[--depth]; + + b3Vector3 aMinLocal = MyUnQuantize(treeNodesCPU[node.x].m_quantizedAabbMin,bvhInfoCPU[bvhA].m_quantization,bvhInfoCPU[bvhA].m_aabbMin); + b3Vector3 aMaxLocal = MyUnQuantize(treeNodesCPU[node.x].m_quantizedAabbMax,bvhInfoCPU[bvhA].m_quantization,bvhInfoCPU[bvhA].m_aabbMin); + + b3Vector3 bMinLocal = MyUnQuantize(treeNodesCPU[node.y].m_quantizedAabbMin,bvhInfoCPU[bvhB].m_quantization,bvhInfoCPU[bvhB].m_aabbMin); + b3Vector3 bMaxLocal = MyUnQuantize(treeNodesCPU[node.y].m_quantizedAabbMax,bvhInfoCPU[bvhB].m_quantization,bvhInfoCPU[bvhB].m_aabbMin); + + float margin=0.f; + b3Vector3 aabbAMinOut,aabbAMaxOut; + b3TransformAabb2(aMinLocal,aMaxLocal, margin,transA.getOrigin(),transA.getRotation(),&aabbAMinOut,&aabbAMaxOut); + + b3Vector3 aabbBMinOut,aabbBMaxOut; + b3TransformAabb2(bMinLocal,bMaxLocal, margin,transB.getOrigin(),transB.getRotation(),&aabbBMinOut,&aabbBMaxOut); + + numAabbChecks++; + bool nodeOverlap = b3TestAabbAgainstAabb(aabbAMinOut,aabbAMaxOut,aabbBMinOut,aabbBMaxOut); + if (nodeOverlap) + { + bool isLeafA = treeNodesCPU[node.x].isLeafNode(); + bool isLeafB = treeNodesCPU[node.y].isLeafNode(); + bool isInternalA = !isLeafA; + bool isInternalB = !isLeafB; + + //fail, even though it might hit two leaf nodes + if (depth+4>maxStackDepth && !(isLeafA && isLeafB)) + { + b3Error("Error: traversal exceeded maxStackDepth\n"); + continue; + } + + if(isInternalA) + { + int nodeAleftChild = node.x+1; + bool isNodeALeftChildLeaf = treeNodesCPU[node.x+1].isLeafNode(); + int nodeArightChild = isNodeALeftChildLeaf? node.x+2 : node.x+1 + treeNodesCPU[node.x+1].getEscapeIndex(); + + if(isInternalB) + { + int nodeBleftChild = node.y+1; + bool isNodeBLeftChildLeaf = treeNodesCPU[node.y+1].isLeafNode(); + int nodeBrightChild = isNodeBLeftChildLeaf? node.y+2 : node.y+1 + treeNodesCPU[node.y+1].getEscapeIndex(); + + nodeStack[depth++] = b3MakeInt2(nodeAleftChild, nodeBleftChild); + nodeStack[depth++] = b3MakeInt2(nodeArightChild, nodeBleftChild); + nodeStack[depth++] = b3MakeInt2(nodeAleftChild, nodeBrightChild); + nodeStack[depth++] = b3MakeInt2(nodeArightChild, nodeBrightChild); + } + else + { + nodeStack[depth++] = b3MakeInt2(nodeAleftChild,node.y); + nodeStack[depth++] = b3MakeInt2(nodeArightChild,node.y); + } + } + else + { + if(isInternalB) + { + int nodeBleftChild = node.y+1; + bool isNodeBLeftChildLeaf = treeNodesCPU[node.y+1].isLeafNode(); + int nodeBrightChild = isNodeBLeftChildLeaf? node.y+2 : node.y+1 + treeNodesCPU[node.y+1].getEscapeIndex(); + nodeStack[depth++] = b3MakeInt2(node.x,nodeBleftChild); + nodeStack[depth++] = b3MakeInt2(node.x,nodeBrightChild); + } + else + { + int compoundPairIdx = b3AtomicInc(numCompoundPairsOut); + if (compoundPairIdx& vertices, + __global const b3AlignedObjectArray& uniqueEdges, + __global const b3AlignedObjectArray& faces, + __global const b3AlignedObjectArray& indices, + __global b3Aabb* aabbs, + __global const b3GpuChildShape* gpuChildShapes, + __global b3AlignedObjectArray& gpuCompoundSepNormalsOut, + __global b3AlignedObjectArray& gpuHasCompoundSepNormalsOut, + int numCompoundPairs, + int i + ) +{ + +// int i = get_global_id(0); + if (i= 0) + { + collidableIndexA = gpuChildShapes[childShapeIndexA].m_shapeIndex; + float4 childPosA = gpuChildShapes[childShapeIndexA].m_childPosition; + b3Quat childOrnA = gpuChildShapes[childShapeIndexA].m_childOrientation; + float4 newPosA = b3QuatRotate(ornA,childPosA)+posA; + b3Quat newOrnA = b3QuatMul(ornA,childOrnA); + posA = newPosA; + ornA = newOrnA; + } else + { + collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx; + } + + if (childShapeIndexB>=0) + { + collidableIndexB = gpuChildShapes[childShapeIndexB].m_shapeIndex; + float4 childPosB = gpuChildShapes[childShapeIndexB].m_childPosition; + b3Quat childOrnB = gpuChildShapes[childShapeIndexB].m_childOrientation; + float4 newPosB = b3QuatRotate(ornB,childPosB)+posB; + b3Quat newOrnB = b3QuatMul(ornB,childOrnB); + posB = newPosB; + ornB = newOrnB; + } else + { + collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx; + } + + gpuHasCompoundSepNormalsOut[i] = 0; + + int shapeIndexA = collidables[collidableIndexA].m_shapeIndex; + int shapeIndexB = collidables[collidableIndexB].m_shapeIndex; + + int shapeTypeA = collidables[collidableIndexA].m_shapeType; + int shapeTypeB = collidables[collidableIndexB].m_shapeType; + + + if ((shapeTypeA != SHAPE_CONVEX_HULL) || (shapeTypeB != SHAPE_CONVEX_HULL)) + { + return; + } + + int hasSeparatingAxis = 5; + + // int numFacesA = convexShapes[shapeIndexA].m_numFaces; + float dmin = FLT_MAX; + posA.w = 0.f; + posB.w = 0.f; + float4 c0local = convexShapes[shapeIndexA].m_localCenter; + float4 c0 = transform(&c0local, &posA, &ornA); + float4 c1local = convexShapes[shapeIndexB].m_localCenter; + float4 c1 = transform(&c1local,&posB,&ornB); + const float4 DeltaC2 = c0 - c1; + float4 sepNormal = make_float4(1,0,0,0); +// bool sepA = findSeparatingAxis( convexShapes[shapeIndexA], convexShapes[shapeIndexB],posA,ornA,posB,ornB,DeltaC2,vertices,uniqueEdges,faces,indices,&sepNormal,&dmin); + bool sepA = findSeparatingAxis( convexShapes[shapeIndexA], convexShapes[shapeIndexB],posA,ornA,posB,ornB,vertices,uniqueEdges,faces,indices,vertices,uniqueEdges,faces,indices,sepNormal);//,&dmin); + + hasSeparatingAxis = 4; + if (!sepA) + { + hasSeparatingAxis = 0; + } else + { + bool sepB = findSeparatingAxis( convexShapes[shapeIndexB],convexShapes[shapeIndexA],posB,ornB,posA,ornA,vertices,uniqueEdges,faces,indices,vertices,uniqueEdges,faces,indices,sepNormal);//,&dmin); + + if (!sepB) + { + hasSeparatingAxis = 0; + } else//(!sepB) + { + bool sepEE = findSeparatingAxisEdgeEdge( &convexShapes[shapeIndexA], &convexShapes[shapeIndexB],posA,ornA,posB,ornB,DeltaC2,vertices,uniqueEdges,faces,indices,&sepNormal,&dmin); + if (sepEE) + { + gpuCompoundSepNormalsOut[i] = sepNormal;//fastNormalize4(sepNormal); + gpuHasCompoundSepNormalsOut[i] = 1; + }//sepEE + }//(!sepB) + }//(!sepA) + + + } + +} + + +__kernel void clipCompoundsHullHullKernel( __global const b3Int4* gpuCompoundPairs, + __global const b3RigidBodyData* rigidBodies, + __global const b3Collidable* collidables, + __global const b3ConvexPolyhedronData* convexShapes, + __global const b3AlignedObjectArray& vertices, + __global const b3AlignedObjectArray& uniqueEdges, + __global const b3AlignedObjectArray& faces, + __global const b3AlignedObjectArray& indices, + __global const b3GpuChildShape* gpuChildShapes, + __global const b3AlignedObjectArray& gpuCompoundSepNormalsOut, + __global const b3AlignedObjectArray& gpuHasCompoundSepNormalsOut, + __global struct b3Contact4Data* globalContactsOut, + int* nGlobalContactsOut, + int numCompoundPairs, int maxContactCapacity, int i) +{ + +// int i = get_global_id(0); + int pairIndex = i; + + float4 worldVertsB1[64]; + float4 worldVertsB2[64]; + int capacityWorldVerts = 64; + + float4 localContactsOut[64]; + int localContactCapacity=64; + + float minDist = -1e30f; + float maxDist = 0.0f; + + if (i= 0) + { + collidableIndexA = gpuChildShapes[childShapeIndexA].m_shapeIndex; + float4 childPosA = gpuChildShapes[childShapeIndexA].m_childPosition; + b3Quat childOrnA = gpuChildShapes[childShapeIndexA].m_childOrientation; + float4 newPosA = b3QuatRotate(ornA,childPosA)+posA; + b3Quat newOrnA = b3QuatMul(ornA,childOrnA); + posA = newPosA; + ornA = newOrnA; + } else + { + collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx; + } + + if (childShapeIndexB>=0) + { + collidableIndexB = gpuChildShapes[childShapeIndexB].m_shapeIndex; + float4 childPosB = gpuChildShapes[childShapeIndexB].m_childPosition; + b3Quat childOrnB = gpuChildShapes[childShapeIndexB].m_childOrientation; + float4 newPosB = b3QuatRotate(ornB,childPosB)+posB; + b3Quat newOrnB = b3QuatMul(ornB,childOrnB); + posB = newPosB; + ornB = newOrnB; + } else + { + collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx; + } + + int shapeIndexA = collidables[collidableIndexA].m_shapeIndex; + int shapeIndexB = collidables[collidableIndexB].m_shapeIndex; + + int numLocalContactsOut = clipHullAgainstHull(gpuCompoundSepNormalsOut[i], + convexShapes[shapeIndexA], convexShapes[shapeIndexB], + posA,ornA, + posB,ornB, + worldVertsB1,worldVertsB2,capacityWorldVerts, + minDist, maxDist, + vertices,faces,indices, + vertices,faces,indices, + localContactsOut,localContactCapacity); + + if (numLocalContactsOut>0) + { + float4 normal = -gpuCompoundSepNormalsOut[i]; + int nPoints = numLocalContactsOut; + float4* pointsIn = localContactsOut; + b3Int4 contactIdx;// = {-1,-1,-1,-1}; + + contactIdx.s[0] = 0; + contactIdx.s[1] = 1; + contactIdx.s[2] = 2; + contactIdx.s[3] = 3; + + int nReducedContacts = extractManifoldSequentialGlobal(pointsIn, nPoints, normal, &contactIdx); + + int dstIdx; + dstIdx = b3AtomicInc( nGlobalContactsOut); + if ((dstIdx+nReducedContacts) < maxContactCapacity) + { + __global struct b3Contact4Data* c = globalContactsOut+ dstIdx; + c->m_worldNormalOnB = -normal; + c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff); + c->m_batchIdx = pairIndex; + int bodyA = gpuCompoundPairs[pairIndex].x; + int bodyB = gpuCompoundPairs[pairIndex].y; + c->m_bodyAPtrAndSignBit = rigidBodies[bodyA].m_invMass==0?-bodyA:bodyA; + c->m_bodyBPtrAndSignBit = rigidBodies[bodyB].m_invMass==0?-bodyB:bodyB; + c->m_childIndexA = childShapeIndexA; + c->m_childIndexB = childShapeIndexB; + for (int i=0;im_worldPosB[i] = pointsIn[contactIdx.s[i]]; + } + b3Contact4Data_setNumPoints(c,nReducedContacts); + } + + }// if (numContactsOut>0) + }// if (gpuHasCompoundSepNormalsOut[i]) + }// if (i& hostAabbsWorldSpace, + const b3AlignedObjectArray& hostAabbsLocalSpace, + + const b3AlignedObjectArray& convexVertices, + const b3AlignedObjectArray& hostUniqueEdges, + const b3AlignedObjectArray& convexIndices, + const b3AlignedObjectArray& faces, + + b3Contact4* globalContactsOut, + int& nGlobalContactsOut, + int maxContactCapacity, + b3AlignedObjectArray& treeNodesCPU, + b3AlignedObjectArray& subTreesCPU, + b3AlignedObjectArray& bvhInfoCPU + ) +{ + + int shapeTypeB = collidables[collidableIndexB].m_shapeType; + b3Assert(shapeTypeB == SHAPE_COMPOUND_OF_CONVEX_HULLS); + + b3AlignedObjectArray cpuCompoundPairsOut; + int numCompoundPairsOut=0; + int maxNumCompoundPairsCapacity = 8192;//1024; + cpuCompoundPairsOut.resize(maxNumCompoundPairsCapacity); + + // work-in-progress + findCompoundPairsKernel( + pairIndex, + bodyIndexA,bodyIndexB, + collidableIndexA,collidableIndexB, + rigidBodies, + collidables, + convexShapes, + convexVertices, + hostAabbsWorldSpace, + hostAabbsLocalSpace, + cpuChildShapes, + &cpuCompoundPairsOut[0], + &numCompoundPairsOut, + maxNumCompoundPairsCapacity , + treeNodesCPU, + subTreesCPU, + bvhInfoCPU + ); + + printf("maxNumAabbChecks=%d\n",maxNumAabbChecks); + if (numCompoundPairsOut>maxNumCompoundPairsCapacity) + { + b3Error("numCompoundPairsOut exceeded maxNumCompoundPairsCapacity (%d)\n",maxNumCompoundPairsCapacity); + numCompoundPairsOut=maxNumCompoundPairsCapacity; + } + b3AlignedObjectArray cpuCompoundSepNormalsOut; + b3AlignedObjectArray cpuHasCompoundSepNormalsOut; + cpuCompoundSepNormalsOut.resize(numCompoundPairsOut); + cpuHasCompoundSepNormalsOut.resize(numCompoundPairsOut); + + for (int i=0;im_numVertices;i++) + { + b3Vector3 vtx = convexVertices[hullB->m_vertexOffset+i]; + float curDot = vtx.dot(planeNormalInConvex); + + + if (curDot>maxDot) + { + hitVertex=i; + maxDot=curDot; + hitVtx = vtx; + //make sure the deepest points is always included + if (numPoints==MAX_PLANE_CONVEX_POINTS) + numPoints--; + } + + if (numPoints4) + { + numReducedPoints = extractManifoldSequentialGlobal( contactPoints, numPoints, planeNormalInConvex, &contactIdx); + } + int dstIdx; + // dstIdx = nGlobalContactsOut++;//AppendInc( nGlobalContactsOut, dstIdx ); + + if (numReducedPoints>0) + { + if (nGlobalContactsOut < maxContactCapacity) + { + dstIdx=nGlobalContactsOut; + nGlobalContactsOut++; + + b3Contact4* c = &globalContactsOut[dstIdx]; + c->m_worldNormalOnB = -planeNormalWorld; + c->setFrictionCoeff(0.7); + c->setRestituitionCoeff(0.f); + + c->m_batchIdx = pairIndex; + c->m_bodyAPtrAndSignBit = rigidBodies[bodyIndexA].m_invMass==0?-bodyIndexA:bodyIndexA; + c->m_bodyBPtrAndSignBit = rigidBodies[bodyIndexB].m_invMass==0?-bodyIndexB:bodyIndexB; + for (int i=0;im_worldPosB[i] = pOnB1; + } + c->m_worldNormalOnB.w = (b3Scalar)numReducedPoints; + }//if (dstIdx < numPairs) + } + + } + + +} + + + + + +void computeContactSphereConvex(int pairIndex, + int bodyIndexA, int bodyIndexB, + int collidableIndexA, int collidableIndexB, + const b3RigidBodyData* rigidBodies, + const b3Collidable* collidables, + const b3ConvexPolyhedronData* convexShapes, + const b3Vector3* convexVertices, + const int* convexIndices, + const b3GpuFace* faces, + b3Contact4* globalContactsOut, + int& nGlobalContactsOut, + int maxContactCapacity) +{ + + float radius = collidables[collidableIndexA].m_radius; + float4 spherePos1 = rigidBodies[bodyIndexA].m_pos; + b3Quaternion sphereOrn = rigidBodies[bodyIndexA].m_quat; + + + + float4 pos = rigidBodies[bodyIndexB].m_pos; + + + b3Quaternion quat = rigidBodies[bodyIndexB].m_quat; + + b3Transform tr; + tr.setIdentity(); + tr.setOrigin(pos); + tr.setRotation(quat); + b3Transform trInv = tr.inverse(); + + float4 spherePos = trInv(spherePos1); + + int collidableIndex = rigidBodies[bodyIndexB].m_collidableIdx; + int shapeIndex = collidables[collidableIndex].m_shapeIndex; + int numFaces = convexShapes[shapeIndex].m_numFaces; + float4 closestPnt = b3MakeVector3(0, 0, 0, 0); +// float4 hitNormalWorld = b3MakeVector3(0, 0, 0, 0); + float minDist = -1000000.f; // TODO: What is the largest/smallest float? + bool bCollide = true; + int region = -1; + float4 localHitNormal; + for ( int f = 0; f < numFaces; f++ ) + { + b3GpuFace face = faces[convexShapes[shapeIndex].m_faceOffset+f]; + float4 planeEqn; + float4 localPlaneNormal = b3MakeVector3(face.m_plane.x,face.m_plane.y,face.m_plane.z,0.f); + float4 n1 = localPlaneNormal;//quatRotate(quat,localPlaneNormal); + planeEqn = n1; + planeEqn[3] = face.m_plane.w; + + float4 pntReturn; + float dist = signedDistanceFromPointToPlane(spherePos, planeEqn, &pntReturn); + + if ( dist > radius) + { + bCollide = false; + break; + } + + if ( dist > 0 ) + { + //might hit an edge or vertex + b3Vector3 out; + + bool isInPoly = IsPointInPolygon(spherePos, + &face, + &convexVertices[convexShapes[shapeIndex].m_vertexOffset], + convexIndices, + &out); + if (isInPoly) + { + if (dist>minDist) + { + minDist = dist; + closestPnt = pntReturn; + localHitNormal = planeEqn; + region=1; + } + } else + { + b3Vector3 tmp = spherePos-out; + b3Scalar l2 = tmp.length2(); + if (l2minDist) + { + minDist = dist; + closestPnt = out; + localHitNormal = tmp/dist; + region=2; + } + + } else + { + bCollide = false; + break; + } + } + } + else + { + if ( dist > minDist ) + { + minDist = dist; + closestPnt = pntReturn; + localHitNormal = planeEqn; + region=3; + } + } + } + static int numChecks = 0; + numChecks++; + + if (bCollide && minDist > -10000) + { + + float4 normalOnSurfaceB1 = tr.getBasis()*localHitNormal;//-hitNormalWorld; + float4 pOnB1 = tr(closestPnt); + //printf("dist ,%f,",minDist); + float actualDepth = minDist-radius; + if (actualDepth<0) + { + //printf("actualDepth = ,%f,", actualDepth); + //printf("normalOnSurfaceB1 = ,%f,%f,%f,", normalOnSurfaceB1.x,normalOnSurfaceB1.y,normalOnSurfaceB1.z); + //printf("region=,%d,\n", region); + pOnB1[3] = actualDepth; + + int dstIdx; +// dstIdx = nGlobalContactsOut++;//AppendInc( nGlobalContactsOut, dstIdx ); + + if (nGlobalContactsOut < maxContactCapacity) + { + dstIdx=nGlobalContactsOut; + nGlobalContactsOut++; + + b3Contact4* c = &globalContactsOut[dstIdx]; + c->m_worldNormalOnB = normalOnSurfaceB1; + c->setFrictionCoeff(0.7); + c->setRestituitionCoeff(0.f); + + c->m_batchIdx = pairIndex; + c->m_bodyAPtrAndSignBit = rigidBodies[bodyIndexA].m_invMass==0?-bodyIndexA:bodyIndexA; + c->m_bodyBPtrAndSignBit = rigidBodies[bodyIndexB].m_invMass==0?-bodyIndexB:bodyIndexB; + c->m_worldPosB[0] = pOnB1; + int numPoints = 1; + c->m_worldNormalOnB.w = (b3Scalar)numPoints; + }//if (dstIdx < numPairs) + } + }//if (hasCollision) + +} + + + + +int computeContactConvexConvex2( + int pairIndex, + int bodyIndexA, int bodyIndexB, + int collidableIndexA, int collidableIndexB, + const b3AlignedObjectArray& rigidBodies, + const b3AlignedObjectArray& collidables, + const b3AlignedObjectArray& convexShapes, + const b3AlignedObjectArray& convexVertices, + const b3AlignedObjectArray& uniqueEdges, + const b3AlignedObjectArray& convexIndices, + const b3AlignedObjectArray& faces, + b3AlignedObjectArray& globalContactsOut, + int& nGlobalContactsOut, + int maxContactCapacity, + const b3AlignedObjectArray& oldContacts + ) +{ + int contactIndex = -1; + b3Vector3 posA = rigidBodies[bodyIndexA].m_pos; + b3Quaternion ornA = rigidBodies[bodyIndexA].m_quat; + b3Vector3 posB = rigidBodies[bodyIndexB].m_pos; + b3Quaternion ornB = rigidBodies[bodyIndexB].m_quat; + + + b3ConvexPolyhedronData hullA, hullB; + + b3Vector3 sepNormalWorldSpace; + + + + b3Collidable colA = collidables[collidableIndexA]; + hullA = convexShapes[colA.m_shapeIndex]; + //printf("numvertsA = %d\n",hullA.m_numVertices); + + + b3Collidable colB = collidables[collidableIndexB]; + hullB = convexShapes[colB.m_shapeIndex]; + //printf("numvertsB = %d\n",hullB.m_numVertices); + +// int contactCapacity = MAX_VERTS; + //int numContactsOut=0; + + +#ifdef _WIN32 + b3Assert(_finite(rigidBodies[bodyIndexA].m_pos.x)); + b3Assert(_finite(rigidBodies[bodyIndexB].m_pos.x)); +#endif + + bool foundSepAxis = findSeparatingAxis(hullA,hullB, + posA, + ornA, + posB, + ornB, + + convexVertices,uniqueEdges,faces,convexIndices, + convexVertices,uniqueEdges,faces,convexIndices, + + sepNormalWorldSpace + ); + + + if (foundSepAxis) + { + + + contactIndex = clipHullHullSingle( + bodyIndexA, bodyIndexB, + posA,ornA, + posB,ornB, + collidableIndexA, collidableIndexB, + &rigidBodies, + &globalContactsOut, + nGlobalContactsOut, + + convexShapes, + convexShapes, + + convexVertices, + uniqueEdges, + faces, + convexIndices, + + convexVertices, + uniqueEdges, + faces, + convexIndices, + + collidables, + collidables, + sepNormalWorldSpace, + maxContactCapacity); + + } + + return contactIndex; +} + + + + + + + +void GpuSatCollision::computeConvexConvexContactsGPUSAT( b3OpenCLArray* pairs, int nPairs, + const b3OpenCLArray* bodyBuf, + b3OpenCLArray* contactOut, int& nContacts, + const b3OpenCLArray* oldContacts, + int maxContactCapacity, + int compoundPairCapacity, + const b3OpenCLArray& convexData, + const b3OpenCLArray& gpuVertices, + const b3OpenCLArray& gpuUniqueEdges, + const b3OpenCLArray& gpuFaces, + const b3OpenCLArray& gpuIndices, + const b3OpenCLArray& gpuCollidables, + const b3OpenCLArray& gpuChildShapes, + + const b3OpenCLArray& clAabbsWorldSpace, + const b3OpenCLArray& clAabbsLocalSpace, + + b3OpenCLArray& worldVertsB1GPU, + b3OpenCLArray& clippingFacesOutGPU, + b3OpenCLArray& worldNormalsAGPU, + b3OpenCLArray& worldVertsA1GPU, + b3OpenCLArray& worldVertsB2GPU, + b3AlignedObjectArray& bvhDataUnused, + b3OpenCLArray* treeNodesGPU, + b3OpenCLArray* subTreesGPU, + b3OpenCLArray* bvhInfo, + + int numObjects, + int maxTriConvexPairCapacity, + b3OpenCLArray& triangleConvexPairsOut, + int& numTriConvexPairsOut + ) +{ + myframecount++; + + if (!nPairs) + return; + +#ifdef CHECK_ON_HOST + + + b3AlignedObjectArray treeNodesCPU; + treeNodesGPU->copyToHost(treeNodesCPU); + + b3AlignedObjectArray subTreesCPU; + subTreesGPU->copyToHost(subTreesCPU); + + b3AlignedObjectArray bvhInfoCPU; + bvhInfo->copyToHost(bvhInfoCPU); + + b3AlignedObjectArray hostAabbsWorldSpace; + clAabbsWorldSpace.copyToHost(hostAabbsWorldSpace); + + b3AlignedObjectArray hostAabbsLocalSpace; + clAabbsLocalSpace.copyToHost(hostAabbsLocalSpace); + + b3AlignedObjectArray hostPairs; + pairs->copyToHost(hostPairs); + + b3AlignedObjectArray hostBodyBuf; + bodyBuf->copyToHost(hostBodyBuf); + + + + b3AlignedObjectArray hostConvexData; + convexData.copyToHost(hostConvexData); + + b3AlignedObjectArray hostVertices; + gpuVertices.copyToHost(hostVertices); + + b3AlignedObjectArray hostUniqueEdges; + gpuUniqueEdges.copyToHost(hostUniqueEdges); + b3AlignedObjectArray hostFaces; + gpuFaces.copyToHost(hostFaces); + b3AlignedObjectArray hostIndices; + gpuIndices.copyToHost(hostIndices); + b3AlignedObjectArray hostCollidables; + gpuCollidables.copyToHost(hostCollidables); + + b3AlignedObjectArray cpuChildShapes; + gpuChildShapes.copyToHost(cpuChildShapes); + + + b3AlignedObjectArray hostTriangleConvexPairs; + + b3AlignedObjectArray hostContacts; + if (nContacts) + { + contactOut->copyToHost(hostContacts); + } + + b3AlignedObjectArray oldHostContacts; + + if (oldContacts->size()) + { + oldContacts->copyToHost(oldHostContacts); + } + + + hostContacts.resize(maxContactCapacity); + + for (int i=0;i=0) + { +// printf("convex convex contactIndex = %d\n",contactIndex); + hostPairs[i].z = contactIndex; + } +// printf("plane-convex\n"); + + } + + + } + + if (hostPairs.size()) + { + pairs->copyFromHost(hostPairs); + } + + hostContacts.resize(nContacts); + if (nContacts) + { + + contactOut->copyFromHost(hostContacts); + } else + { + contactOut->resize(0); + } + + m_totalContactsOut.copyFromHostPointer(&nContacts,1,0,true); + //printf("(HOST) nContacts = %d\n",nContacts); + +#else + + { + if (nPairs) + { + m_totalContactsOut.copyFromHostPointer(&nContacts,1,0,true); + + B3_PROFILE("primitiveContactsKernel"); + b3BufferInfoCL bInfo[] = { + b3BufferInfoCL( pairs->getBufferCL(), true ), + b3BufferInfoCL( bodyBuf->getBufferCL(),true), + b3BufferInfoCL( gpuCollidables.getBufferCL(),true), + b3BufferInfoCL( convexData.getBufferCL(),true), + b3BufferInfoCL( gpuVertices.getBufferCL(),true), + b3BufferInfoCL( gpuUniqueEdges.getBufferCL(),true), + b3BufferInfoCL( gpuFaces.getBufferCL(),true), + b3BufferInfoCL( gpuIndices.getBufferCL(),true), + b3BufferInfoCL( contactOut->getBufferCL()), + b3BufferInfoCL( m_totalContactsOut.getBufferCL()) + }; + + b3LauncherCL launcher(m_queue, m_primitiveContactsKernel,"m_primitiveContactsKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( nPairs ); + launcher.setConst(maxContactCapacity); + int num = nPairs; + launcher.launch1D( num); + clFinish(m_queue); + + nContacts = m_totalContactsOut.at(0); + contactOut->resize(nContacts); + } + } + + +#endif//CHECK_ON_HOST + + B3_PROFILE("computeConvexConvexContactsGPUSAT"); + // printf("nContacts = %d\n",nContacts); + + + m_sepNormals.resize(nPairs); + m_hasSeparatingNormals.resize(nPairs); + + int concaveCapacity=maxTriConvexPairCapacity; + m_concaveSepNormals.resize(concaveCapacity); + m_concaveHasSeparatingNormals.resize(concaveCapacity); + m_numConcavePairsOut.resize(0); + m_numConcavePairsOut.push_back(0); + + + m_gpuCompoundPairs.resize(compoundPairCapacity); + + m_gpuCompoundSepNormals.resize(compoundPairCapacity); + + + m_gpuHasCompoundSepNormals.resize(compoundPairCapacity); + + m_numCompoundPairsOut.resize(0); + m_numCompoundPairsOut.push_back(0); + + int numCompoundPairs = 0; + + int numConcavePairs =0; + + { + clFinish(m_queue); + if (findSeparatingAxisOnGpu) + { + m_dmins.resize(nPairs); + if (splitSearchSepAxisConvex) + { + + + if (useMprGpu) + { + nContacts = m_totalContactsOut.at(0); + { + B3_PROFILE("mprPenetrationKernel"); + b3BufferInfoCL bInfo[] = { + b3BufferInfoCL( pairs->getBufferCL(), true ), + b3BufferInfoCL( bodyBuf->getBufferCL(),true), + b3BufferInfoCL( gpuCollidables.getBufferCL(),true), + b3BufferInfoCL( convexData.getBufferCL(),true), + b3BufferInfoCL( gpuVertices.getBufferCL(),true), + b3BufferInfoCL( m_sepNormals.getBufferCL()), + b3BufferInfoCL( m_hasSeparatingNormals.getBufferCL()), + b3BufferInfoCL( contactOut->getBufferCL()), + b3BufferInfoCL( m_totalContactsOut.getBufferCL()) + }; + + b3LauncherCL launcher(m_queue, m_mprPenetrationKernel,"mprPenetrationKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + + launcher.setConst(maxContactCapacity); + launcher.setConst( nPairs ); + + int num = nPairs; + launcher.launch1D( num); + clFinish(m_queue); + /* + b3AlignedObjectArrayhostHasSepAxis; + m_hasSeparatingNormals.copyToHost(hostHasSepAxis); + b3AlignedObjectArrayhostSepAxis; + m_sepNormals.copyToHost(hostSepAxis); + */ + nContacts = m_totalContactsOut.at(0); + contactOut->resize(nContacts); + // printf("nContacts (after mprPenetrationKernel) = %d\n",nContacts); + if (nContacts>maxContactCapacity) + { + + b3Error("Error: contacts exceeds capacity (%d/%d)\n", nContacts, maxContactCapacity); + nContacts = maxContactCapacity; + } + + } + } + + if (1) + { + + if (1) + { + { + B3_PROFILE("findSeparatingAxisVertexFaceKernel"); + b3BufferInfoCL bInfo[] = { + b3BufferInfoCL( pairs->getBufferCL(), true ), + b3BufferInfoCL( bodyBuf->getBufferCL(),true), + b3BufferInfoCL( gpuCollidables.getBufferCL(),true), + b3BufferInfoCL( convexData.getBufferCL(),true), + b3BufferInfoCL( gpuVertices.getBufferCL(),true), + b3BufferInfoCL( gpuUniqueEdges.getBufferCL(),true), + b3BufferInfoCL( gpuFaces.getBufferCL(),true), + b3BufferInfoCL( gpuIndices.getBufferCL(),true), + b3BufferInfoCL( clAabbsWorldSpace.getBufferCL(),true), + b3BufferInfoCL( m_sepNormals.getBufferCL()), + b3BufferInfoCL( m_hasSeparatingNormals.getBufferCL()), + b3BufferInfoCL( m_dmins.getBufferCL()) + }; + + b3LauncherCL launcher(m_queue, m_findSeparatingAxisVertexFaceKernel,"findSeparatingAxisVertexFaceKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( nPairs ); + + int num = nPairs; + launcher.launch1D( num); + clFinish(m_queue); + } + + + int numDirections = sizeof(unitSphere162)/sizeof(b3Vector3); + + { + B3_PROFILE("findSeparatingAxisEdgeEdgeKernel"); + b3BufferInfoCL bInfo[] = { + b3BufferInfoCL( pairs->getBufferCL(), true ), + b3BufferInfoCL( bodyBuf->getBufferCL(),true), + b3BufferInfoCL( gpuCollidables.getBufferCL(),true), + b3BufferInfoCL( convexData.getBufferCL(),true), + b3BufferInfoCL( gpuVertices.getBufferCL(),true), + b3BufferInfoCL( gpuUniqueEdges.getBufferCL(),true), + b3BufferInfoCL( gpuFaces.getBufferCL(),true), + b3BufferInfoCL( gpuIndices.getBufferCL(),true), + b3BufferInfoCL( clAabbsWorldSpace.getBufferCL(),true), + b3BufferInfoCL( m_sepNormals.getBufferCL()), + b3BufferInfoCL( m_hasSeparatingNormals.getBufferCL()), + b3BufferInfoCL( m_dmins.getBufferCL()), + b3BufferInfoCL( m_unitSphereDirections.getBufferCL(),true) + + }; + + b3LauncherCL launcher(m_queue, m_findSeparatingAxisEdgeEdgeKernel,"findSeparatingAxisEdgeEdgeKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( numDirections); + launcher.setConst( nPairs ); + int num = nPairs; + launcher.launch1D( num); + clFinish(m_queue); + + } + } + if (useMprGpu) + { + B3_PROFILE("findSeparatingAxisUnitSphereKernel"); + b3BufferInfoCL bInfo[] = { + b3BufferInfoCL( pairs->getBufferCL(), true ), + b3BufferInfoCL( bodyBuf->getBufferCL(),true), + b3BufferInfoCL( gpuCollidables.getBufferCL(),true), + b3BufferInfoCL( convexData.getBufferCL(),true), + b3BufferInfoCL( gpuVertices.getBufferCL(),true), + b3BufferInfoCL( m_unitSphereDirections.getBufferCL(),true), + b3BufferInfoCL( m_sepNormals.getBufferCL()), + b3BufferInfoCL( m_hasSeparatingNormals.getBufferCL()), + b3BufferInfoCL( m_dmins.getBufferCL()) + }; + + b3LauncherCL launcher(m_queue, m_findSeparatingAxisUnitSphereKernel,"findSeparatingAxisUnitSphereKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + int numDirections = sizeof(unitSphere162)/sizeof(b3Vector3); + launcher.setConst( numDirections); + + launcher.setConst( nPairs ); + + int num = nPairs; + launcher.launch1D( num); + clFinish(m_queue); + } + } + + + } else + { + B3_PROFILE("findSeparatingAxisKernel"); + b3BufferInfoCL bInfo[] = { + b3BufferInfoCL( pairs->getBufferCL(), true ), + b3BufferInfoCL( bodyBuf->getBufferCL(),true), + b3BufferInfoCL( gpuCollidables.getBufferCL(),true), + b3BufferInfoCL( convexData.getBufferCL(),true), + b3BufferInfoCL( gpuVertices.getBufferCL(),true), + b3BufferInfoCL( gpuUniqueEdges.getBufferCL(),true), + b3BufferInfoCL( gpuFaces.getBufferCL(),true), + b3BufferInfoCL( gpuIndices.getBufferCL(),true), + b3BufferInfoCL( clAabbsWorldSpace.getBufferCL(),true), + b3BufferInfoCL( m_sepNormals.getBufferCL()), + b3BufferInfoCL( m_hasSeparatingNormals.getBufferCL()) + }; + + b3LauncherCL launcher(m_queue, m_findSeparatingAxisKernel,"m_findSeparatingAxisKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( nPairs ); + + int num = nPairs; + launcher.launch1D( num); + clFinish(m_queue); + } + + + } + else + { + + B3_PROFILE("findSeparatingAxisKernel CPU"); + + + b3AlignedObjectArray hostPairs; + pairs->copyToHost(hostPairs); + b3AlignedObjectArray hostBodyBuf; + bodyBuf->copyToHost(hostBodyBuf); + + b3AlignedObjectArray hostCollidables; + gpuCollidables.copyToHost(hostCollidables); + + b3AlignedObjectArray cpuChildShapes; + gpuChildShapes.copyToHost(cpuChildShapes); + + b3AlignedObjectArray hostConvexShapeData; + convexData.copyToHost(hostConvexShapeData); + + b3AlignedObjectArray hostVertices; + gpuVertices.copyToHost(hostVertices); + + b3AlignedObjectArray hostHasSepAxis; + hostHasSepAxis.resize(nPairs); + b3AlignedObjectArray hostSepAxis; + hostSepAxis.resize(nPairs); + + b3AlignedObjectArray hostUniqueEdges; + gpuUniqueEdges.copyToHost(hostUniqueEdges); + b3AlignedObjectArray hostFaces; + gpuFaces.copyToHost(hostFaces); + + b3AlignedObjectArray hostIndices; + gpuIndices.copyToHost(hostIndices); + + b3AlignedObjectArray hostContacts; + if (nContacts) + { + contactOut->copyToHost(hostContacts); + } + hostContacts.resize(maxContactCapacity); + int nGlobalContactsOut = nContacts; + + + for (int i=0;i dist) + { + float diff = depth - dist; + + static float maxdiff = 0.f; + if (maxdiff < diff) + { + maxdiff = diff; + printf("maxdiff = %20.10f\n",maxdiff); + } + } + } + if (depth > dmin) + { + b3Vector3 oldAxis = hostSepAxis[i]; + depth = dmin; + sepAxis2 = oldAxis; + } + + + + if(b3TestSepAxis( &hullA, &hullB, posA,ornA,posB,ornB,&sepAxis2, &hostVertices[0], &hostVertices[0],&dist)) + { + if (depth > dist) + { + float diff = depth - dist; + //printf("?diff = %f\n",diff ); + static float maxdiff = 0.f; + if (maxdiff < diff) + { + maxdiff = diff; + printf("maxdiff = %20.10f\n",maxdiff); + } + } + //this is used for SAT + //hostHasSepAxis[i] = 1; + //hostSepAxis[i] = sepAxis2; + + //add contact point + + //int contactIndex = nGlobalContactsOut; + b3Contact4& newContact = hostContacts.at(nGlobalContactsOut); + nGlobalContactsOut++; + newContact.m_batchIdx = 0;//i; + newContact.m_bodyAPtrAndSignBit = (hostBodyBuf.at(bodyIndexA).m_invMass==0)? -bodyIndexA:bodyIndexA; + newContact.m_bodyBPtrAndSignBit = (hostBodyBuf.at(bodyIndexB).m_invMass==0)? -bodyIndexB:bodyIndexB; + + newContact.m_frictionCoeffCmp = 45874; + newContact.m_restituitionCoeffCmp = 0; + + + static float maxDepth = 0.f; + + if (depth > maxDepth) + { + maxDepth = depth; + printf("MPR maxdepth = %f\n",maxDepth ); + + } + + + resultPointOnBWorld.w = -depth; + newContact.m_worldPosB[0] = resultPointOnBWorld; + //b3Vector3 resultPointOnAWorld = resultPointOnBWorld+depth*sepAxis2; + newContact.m_worldNormalOnB = sepAxis2; + newContact.m_worldNormalOnB.w = (b3Scalar)1; + } else + { + printf("rejected\n"); + } + + + } + } else + { + + + + //int contactIndex = computeContactConvexConvex2( i,bodyIndexA,bodyIndexB,collidableIndexA,collidableIndexB,hostBodyBuf, hostCollidables,hostConvexData,hostVertices,hostUniqueEdges,hostIndices,hostFaces,hostContacts,nContacts,maxContactCapacity,oldHostContacts); + b3AlignedObjectArray oldHostContacts; + int result; + result = computeContactConvexConvex2( //hostPairs, + pairIndex, + bodyIndexA, bodyIndexB, + collidableIndexA, collidableIndexB, + hostBodyBuf, + hostCollidables, + hostConvexShapeData, + hostVertices, + hostUniqueEdges, + hostIndices, + hostFaces, + hostContacts, + nGlobalContactsOut, + maxContactCapacity, + oldHostContacts + //hostHasSepAxis, + //hostSepAxis + + ); + }//mpr + }//hostHasSepAxis[i] = 1; + + } else + { + + b3Vector3 c0local = hostConvexShapeData[shapeIndexA].m_localCenter; + b3Vector3 c0 = b3TransformPoint(c0local, posA, ornA); + b3Vector3 c1local = hostConvexShapeData[shapeIndexB].m_localCenter; + b3Vector3 c1 = b3TransformPoint(c1local,posB,ornB); + b3Vector3 DeltaC2 = c0 - c1; + + b3Vector3 sepAxis; + + bool hasSepAxisA = b3FindSeparatingAxis(convexShapeA, convexShapeB, posA, ornA, posB, ornB, DeltaC2, + &hostVertices.at(0), &hostUniqueEdges.at(0), &hostFaces.at(0), &hostIndices.at(0), + &hostVertices.at(0), &hostUniqueEdges.at(0), &hostFaces.at(0), &hostIndices.at(0), + &sepAxis, &dmin); + + if (hasSepAxisA) + { + bool hasSepAxisB = b3FindSeparatingAxis(convexShapeB, convexShapeA, posB, ornB, posA, ornA, DeltaC2, + &hostVertices.at(0), &hostUniqueEdges.at(0), &hostFaces.at(0), &hostIndices.at(0), + &hostVertices.at(0), &hostUniqueEdges.at(0), &hostFaces.at(0), &hostIndices.at(0), + &sepAxis, &dmin); + if (hasSepAxisB) + { + bool hasEdgeEdge =b3FindSeparatingAxisEdgeEdge(convexShapeA, convexShapeB, posA, ornA, posB, ornB, DeltaC2, + &hostVertices.at(0), &hostUniqueEdges.at(0), &hostFaces.at(0), &hostIndices.at(0), + &hostVertices.at(0), &hostUniqueEdges.at(0), &hostFaces.at(0), &hostIndices.at(0), + &sepAxis, &dmin,true); + + if (hasEdgeEdge) + { + hostHasSepAxis[i] = 1; + hostSepAxis[i] = sepAxis; + } + } + } + } + } + + if (useGjkContacts)//nGlobalContactsOut>0) + { + //printf("nGlobalContactsOut=%d\n",nGlobalContactsOut); + nContacts = nGlobalContactsOut; + contactOut->copyFromHost(hostContacts); + + m_totalContactsOut.copyFromHostPointer(&nContacts,1,0,true); + } + + m_hasSeparatingNormals.copyFromHost(hostHasSepAxis); + m_sepNormals.copyFromHost(hostSepAxis); + + /* + //double-check results from GPU (comment-out the 'else' so both paths are executed + b3AlignedObjectArray checkHasSepAxis; + m_hasSeparatingNormals.copyToHost(checkHasSepAxis); + static int frameCount = 0; + frameCount++; + for (int i=0;igetBufferCL(), true ), + b3BufferInfoCL( bodyBuf->getBufferCL(),true), + b3BufferInfoCL( gpuCollidables.getBufferCL(),true), + b3BufferInfoCL( convexData.getBufferCL(),true), + b3BufferInfoCL( gpuVertices.getBufferCL(),true), + b3BufferInfoCL( gpuUniqueEdges.getBufferCL(),true), + b3BufferInfoCL( gpuFaces.getBufferCL(),true), + b3BufferInfoCL( gpuIndices.getBufferCL(),true), + b3BufferInfoCL( clAabbsLocalSpace.getBufferCL(),true), + b3BufferInfoCL( gpuChildShapes.getBufferCL(),true), + b3BufferInfoCL( m_gpuCompoundPairs.getBufferCL()), + b3BufferInfoCL( m_numCompoundPairsOut.getBufferCL()), + b3BufferInfoCL(subTreesGPU->getBufferCL()), + b3BufferInfoCL(treeNodesGPU->getBufferCL()), + b3BufferInfoCL(bvhInfo->getBufferCL()) + }; + + b3LauncherCL launcher(m_queue, m_findCompoundPairsKernel,"m_findCompoundPairsKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( nPairs ); + launcher.setConst( compoundPairCapacity); + + int num = nPairs; + launcher.launch1D( num); + clFinish(m_queue); + + numCompoundPairs = m_numCompoundPairsOut.at(0); + //printf("numCompoundPairs =%d\n",numCompoundPairs ); + if (numCompoundPairs) + { + //printf("numCompoundPairs=%d\n",numCompoundPairs); + } + + + } else + { + + + b3AlignedObjectArray treeNodesCPU; + treeNodesGPU->copyToHost(treeNodesCPU); + + b3AlignedObjectArray subTreesCPU; + subTreesGPU->copyToHost(subTreesCPU); + + b3AlignedObjectArray bvhInfoCPU; + bvhInfo->copyToHost(bvhInfoCPU); + + b3AlignedObjectArray hostAabbsWorldSpace; + clAabbsWorldSpace.copyToHost(hostAabbsWorldSpace); + + b3AlignedObjectArray hostAabbsLocalSpace; + clAabbsLocalSpace.copyToHost(hostAabbsLocalSpace); + + b3AlignedObjectArray hostPairs; + pairs->copyToHost(hostPairs); + + b3AlignedObjectArray hostBodyBuf; + bodyBuf->copyToHost(hostBodyBuf); + + + b3AlignedObjectArray cpuCompoundPairsOut; + cpuCompoundPairsOut.resize(compoundPairCapacity); + + b3AlignedObjectArray hostCollidables; + gpuCollidables.copyToHost(hostCollidables); + + b3AlignedObjectArray cpuChildShapes; + gpuChildShapes.copyToHost(cpuChildShapes); + + b3AlignedObjectArray hostConvexData; + convexData.copyToHost(hostConvexData); + + b3AlignedObjectArray hostVertices; + gpuVertices.copyToHost(hostVertices); + + + + + for (int pairIndex=0;pairIndex compoundPairCapacity) + { + b3Error("Exceeded compound pair capacity (%d/%d)\n", numCompoundPairs, compoundPairCapacity); + numCompoundPairs = compoundPairCapacity; + } + + + + m_gpuCompoundPairs.resize(numCompoundPairs); + m_gpuHasCompoundSepNormals.resize(numCompoundPairs); + m_gpuCompoundSepNormals.resize(numCompoundPairs); + + + if (numCompoundPairs) + { + B3_PROFILE("processCompoundPairsPrimitivesKernel"); + b3BufferInfoCL bInfo[] = + { + b3BufferInfoCL( m_gpuCompoundPairs.getBufferCL(), true ), + b3BufferInfoCL( bodyBuf->getBufferCL(),true), + b3BufferInfoCL( gpuCollidables.getBufferCL(),true), + b3BufferInfoCL( convexData.getBufferCL(),true), + b3BufferInfoCL( gpuVertices.getBufferCL(),true), + b3BufferInfoCL( gpuUniqueEdges.getBufferCL(),true), + b3BufferInfoCL( gpuFaces.getBufferCL(),true), + b3BufferInfoCL( gpuIndices.getBufferCL(),true), + b3BufferInfoCL( clAabbsWorldSpace.getBufferCL(),true), + b3BufferInfoCL( gpuChildShapes.getBufferCL(),true), + b3BufferInfoCL( contactOut->getBufferCL()), + b3BufferInfoCL( m_totalContactsOut.getBufferCL()) + }; + + b3LauncherCL launcher(m_queue, m_processCompoundPairsPrimitivesKernel,"m_processCompoundPairsPrimitivesKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( numCompoundPairs ); + launcher.setConst(maxContactCapacity); + + int num = numCompoundPairs; + launcher.launch1D( num); + clFinish(m_queue); + nContacts = m_totalContactsOut.at(0); + //printf("nContacts (after processCompoundPairsPrimitivesKernel) = %d\n",nContacts); + if (nContacts>maxContactCapacity) + { + + b3Error("Error: contacts exceeds capacity (%d/%d)\n", nContacts, maxContactCapacity); + nContacts = maxContactCapacity; + } + } + + + if (numCompoundPairs) + { + B3_PROFILE("processCompoundPairsKernel"); + b3BufferInfoCL bInfo[] = + { + b3BufferInfoCL( m_gpuCompoundPairs.getBufferCL(), true ), + b3BufferInfoCL( bodyBuf->getBufferCL(),true), + b3BufferInfoCL( gpuCollidables.getBufferCL(),true), + b3BufferInfoCL( convexData.getBufferCL(),true), + b3BufferInfoCL( gpuVertices.getBufferCL(),true), + b3BufferInfoCL( gpuUniqueEdges.getBufferCL(),true), + b3BufferInfoCL( gpuFaces.getBufferCL(),true), + b3BufferInfoCL( gpuIndices.getBufferCL(),true), + b3BufferInfoCL( clAabbsWorldSpace.getBufferCL(),true), + b3BufferInfoCL( gpuChildShapes.getBufferCL(),true), + b3BufferInfoCL( m_gpuCompoundSepNormals.getBufferCL()), + b3BufferInfoCL( m_gpuHasCompoundSepNormals.getBufferCL()) + }; + + b3LauncherCL launcher(m_queue, m_processCompoundPairsKernel,"m_processCompoundPairsKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( numCompoundPairs ); + + int num = numCompoundPairs; + launcher.launch1D( num); + clFinish(m_queue); + + } + + + //printf("numConcave = %d\n",numConcave); + + + +// printf("hostNormals.size()=%d\n",hostNormals.size()); + //int numPairs = pairCount.at(0); + + + + } + int vertexFaceCapacity = 64; + + + + { + //now perform the tree query on GPU + + + + + if (treeNodesGPU->size() && treeNodesGPU->size()) + { + if (bvhTraversalKernelGPU) + { + + B3_PROFILE("m_bvhTraversalKernel"); + + + numConcavePairs = m_numConcavePairsOut.at(0); + + b3LauncherCL launcher(m_queue, m_bvhTraversalKernel,"m_bvhTraversalKernel"); + launcher.setBuffer( pairs->getBufferCL()); + launcher.setBuffer( bodyBuf->getBufferCL()); + launcher.setBuffer( gpuCollidables.getBufferCL()); + launcher.setBuffer( clAabbsWorldSpace.getBufferCL()); + launcher.setBuffer( triangleConvexPairsOut.getBufferCL()); + launcher.setBuffer( m_numConcavePairsOut.getBufferCL()); + launcher.setBuffer( subTreesGPU->getBufferCL()); + launcher.setBuffer( treeNodesGPU->getBufferCL()); + launcher.setBuffer( bvhInfo->getBufferCL()); + + launcher.setConst( nPairs ); + launcher.setConst( maxTriConvexPairCapacity); + int num = nPairs; + launcher.launch1D( num); + clFinish(m_queue); + numConcavePairs = m_numConcavePairsOut.at(0); + } else + { + b3AlignedObjectArray hostPairs; + pairs->copyToHost(hostPairs); + b3AlignedObjectArray hostBodyBuf; + bodyBuf->copyToHost(hostBodyBuf); + b3AlignedObjectArray hostCollidables; + gpuCollidables.copyToHost(hostCollidables); + b3AlignedObjectArray hostAabbsWorldSpace; + clAabbsWorldSpace.copyToHost(hostAabbsWorldSpace); + + //int maxTriConvexPairCapacity, + b3AlignedObjectArray triangleConvexPairsOutHost; + triangleConvexPairsOutHost.resize(maxTriConvexPairCapacity); + + //int numTriConvexPairsOutHost=0; + numConcavePairs = 0; + //m_numConcavePairsOut + + b3AlignedObjectArray treeNodesCPU; + treeNodesGPU->copyToHost(treeNodesCPU); + b3AlignedObjectArray subTreesCPU; + subTreesGPU->copyToHost(subTreesCPU); + b3AlignedObjectArray bvhInfoCPU; + bvhInfo->copyToHost(bvhInfoCPU); + //compute it... + + volatile int hostNumConcavePairsOut=0; + + // + for (int i=0;i maxTriConvexPairCapacity) + { + static int exceeded_maxTriConvexPairCapacity_count = 0; + b3Error("Exceeded the maxTriConvexPairCapacity (found %d but max is %d, it happened %d times)\n", + numConcavePairs,maxTriConvexPairCapacity,exceeded_maxTriConvexPairCapacity_count++); + numConcavePairs = maxTriConvexPairCapacity; + } + triangleConvexPairsOut.resize(numConcavePairs); + + if (numConcavePairs) + { + + + + + clippingFacesOutGPU.resize(numConcavePairs); + worldNormalsAGPU.resize(numConcavePairs); + worldVertsA1GPU.resize(vertexFaceCapacity*(numConcavePairs)); + worldVertsB1GPU.resize(vertexFaceCapacity*(numConcavePairs)); + + + if (findConcaveSeparatingAxisKernelGPU) + { + + /* + m_concaveHasSeparatingNormals.copyFromHost(concaveHasSeparatingNormalsCPU); + clippingFacesOutGPU.copyFromHost(clippingFacesOutCPU); + worldVertsA1GPU.copyFromHost(worldVertsA1CPU); + worldNormalsAGPU.copyFromHost(worldNormalsACPU); + worldVertsB1GPU.copyFromHost(worldVertsB1CPU); + */ + + //now perform a SAT test for each triangle-convex element (stored in triangleConvexPairsOut) + if (splitSearchSepAxisConcave) + { + //printf("numConcavePairs = %d\n",numConcavePairs); + m_dmins.resize(numConcavePairs); + { + B3_PROFILE("findConcaveSeparatingAxisVertexFaceKernel"); + b3BufferInfoCL bInfo[] = { + b3BufferInfoCL( triangleConvexPairsOut.getBufferCL() ), + b3BufferInfoCL( bodyBuf->getBufferCL(),true), + b3BufferInfoCL( gpuCollidables.getBufferCL(),true), + b3BufferInfoCL( convexData.getBufferCL(),true), + b3BufferInfoCL( gpuVertices.getBufferCL(),true), + b3BufferInfoCL( gpuUniqueEdges.getBufferCL(),true), + b3BufferInfoCL( gpuFaces.getBufferCL(),true), + b3BufferInfoCL( gpuIndices.getBufferCL(),true), + b3BufferInfoCL( gpuChildShapes.getBufferCL(),true), + b3BufferInfoCL( clAabbsWorldSpace.getBufferCL(),true), + b3BufferInfoCL( m_concaveSepNormals.getBufferCL()), + b3BufferInfoCL( m_concaveHasSeparatingNormals.getBufferCL()), + b3BufferInfoCL( clippingFacesOutGPU.getBufferCL()), + b3BufferInfoCL( worldVertsA1GPU.getBufferCL()), + b3BufferInfoCL(worldNormalsAGPU.getBufferCL()), + b3BufferInfoCL(worldVertsB1GPU.getBufferCL()), + b3BufferInfoCL(m_dmins.getBufferCL()) + }; + + b3LauncherCL launcher(m_queue, m_findConcaveSeparatingAxisVertexFaceKernel,"m_findConcaveSeparatingAxisVertexFaceKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(vertexFaceCapacity); + launcher.setConst( numConcavePairs ); + + int num = numConcavePairs; + launcher.launch1D( num); + clFinish(m_queue); + + + } +// numConcavePairs = 0; + if (1) + { + B3_PROFILE("findConcaveSeparatingAxisEdgeEdgeKernel"); + b3BufferInfoCL bInfo[] = { + b3BufferInfoCL( triangleConvexPairsOut.getBufferCL() ), + b3BufferInfoCL( bodyBuf->getBufferCL(),true), + b3BufferInfoCL( gpuCollidables.getBufferCL(),true), + b3BufferInfoCL( convexData.getBufferCL(),true), + b3BufferInfoCL( gpuVertices.getBufferCL(),true), + b3BufferInfoCL( gpuUniqueEdges.getBufferCL(),true), + b3BufferInfoCL( gpuFaces.getBufferCL(),true), + b3BufferInfoCL( gpuIndices.getBufferCL(),true), + b3BufferInfoCL( gpuChildShapes.getBufferCL(),true), + b3BufferInfoCL( clAabbsWorldSpace.getBufferCL(),true), + b3BufferInfoCL( m_concaveSepNormals.getBufferCL()), + b3BufferInfoCL( m_concaveHasSeparatingNormals.getBufferCL()), + b3BufferInfoCL( clippingFacesOutGPU.getBufferCL()), + b3BufferInfoCL( worldVertsA1GPU.getBufferCL()), + b3BufferInfoCL(worldNormalsAGPU.getBufferCL()), + b3BufferInfoCL(worldVertsB1GPU.getBufferCL()), + b3BufferInfoCL(m_dmins.getBufferCL()) + }; + + b3LauncherCL launcher(m_queue, m_findConcaveSeparatingAxisEdgeEdgeKernel,"m_findConcaveSeparatingAxisEdgeEdgeKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(vertexFaceCapacity); + launcher.setConst( numConcavePairs ); + + int num = numConcavePairs; + launcher.launch1D( num); + clFinish(m_queue); + } + + + // numConcavePairs = 0; + + + + + + + } else + { + B3_PROFILE("findConcaveSeparatingAxisKernel"); + b3BufferInfoCL bInfo[] = { + b3BufferInfoCL( triangleConvexPairsOut.getBufferCL() ), + b3BufferInfoCL( bodyBuf->getBufferCL(),true), + b3BufferInfoCL( gpuCollidables.getBufferCL(),true), + b3BufferInfoCL( convexData.getBufferCL(),true), + b3BufferInfoCL( gpuVertices.getBufferCL(),true), + b3BufferInfoCL( gpuUniqueEdges.getBufferCL(),true), + b3BufferInfoCL( gpuFaces.getBufferCL(),true), + b3BufferInfoCL( gpuIndices.getBufferCL(),true), + b3BufferInfoCL( gpuChildShapes.getBufferCL(),true), + b3BufferInfoCL( clAabbsWorldSpace.getBufferCL(),true), + b3BufferInfoCL( m_concaveSepNormals.getBufferCL()), + b3BufferInfoCL( m_concaveHasSeparatingNormals.getBufferCL()), + b3BufferInfoCL( clippingFacesOutGPU.getBufferCL()), + b3BufferInfoCL( worldVertsA1GPU.getBufferCL()), + b3BufferInfoCL(worldNormalsAGPU.getBufferCL()), + b3BufferInfoCL(worldVertsB1GPU.getBufferCL()) + }; + + b3LauncherCL launcher(m_queue, m_findConcaveSeparatingAxisKernel,"m_findConcaveSeparatingAxisKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(vertexFaceCapacity); + launcher.setConst( numConcavePairs ); + + int num = numConcavePairs; + launcher.launch1D( num); + clFinish(m_queue); + } + + + } else + { + + b3AlignedObjectArray clippingFacesOutCPU; + b3AlignedObjectArray worldVertsA1CPU; + b3AlignedObjectArray worldNormalsACPU; + b3AlignedObjectArray worldVertsB1CPU; + b3AlignedObjectArrayconcaveHasSeparatingNormalsCPU; + + b3AlignedObjectArray triangleConvexPairsOutHost; + triangleConvexPairsOut.copyToHost(triangleConvexPairsOutHost); + //triangleConvexPairsOutHost.resize(maxTriConvexPairCapacity); + b3AlignedObjectArray hostBodyBuf; + bodyBuf->copyToHost(hostBodyBuf); + b3AlignedObjectArray hostCollidables; + gpuCollidables.copyToHost(hostCollidables); + b3AlignedObjectArray hostAabbsWorldSpace; + clAabbsWorldSpace.copyToHost(hostAabbsWorldSpace); + + b3AlignedObjectArray hostConvexData; + convexData.copyToHost(hostConvexData); + + b3AlignedObjectArray hostVertices; + gpuVertices.copyToHost(hostVertices); + + b3AlignedObjectArray hostUniqueEdges; + gpuUniqueEdges.copyToHost(hostUniqueEdges); + b3AlignedObjectArray hostFaces; + gpuFaces.copyToHost(hostFaces); + b3AlignedObjectArray hostIndices; + gpuIndices.copyToHost(hostIndices); + b3AlignedObjectArray cpuChildShapes; + gpuChildShapes.copyToHost(cpuChildShapes); + + + + b3AlignedObjectArray concaveSepNormalsHost; + m_concaveSepNormals.copyToHost(concaveSepNormalsHost); + concaveHasSeparatingNormalsCPU.resize(concaveSepNormalsHost.size()); + + b3GpuChildShape* childShapePointerCPU = 0; + if (cpuChildShapes.size()) + childShapePointerCPU = &cpuChildShapes.at(0); + + clippingFacesOutCPU.resize(clippingFacesOutGPU.size()); + worldVertsA1CPU.resize(worldVertsA1GPU.size()); + worldNormalsACPU.resize(worldNormalsAGPU.size()); + worldVertsB1CPU.resize(worldVertsB1GPU.size()); + + for (int i=0;i cpuCompoundSepNormals; +// m_concaveSepNormals.copyToHost(cpuCompoundSepNormals); +// b3AlignedObjectArray cpuConcavePairs; +// triangleConvexPairsOut.copyToHost(cpuConcavePairs); + + + } + } + + + } + + if (numConcavePairs) + { + if (numConcavePairs) + { + B3_PROFILE("findConcaveSphereContactsKernel"); + nContacts = m_totalContactsOut.at(0); +// printf("nContacts1 = %d\n",nContacts); + b3BufferInfoCL bInfo[] = { + b3BufferInfoCL( triangleConvexPairsOut.getBufferCL() ), + b3BufferInfoCL( bodyBuf->getBufferCL(),true), + b3BufferInfoCL( gpuCollidables.getBufferCL(),true), + b3BufferInfoCL( convexData.getBufferCL(),true), + b3BufferInfoCL( gpuVertices.getBufferCL(),true), + b3BufferInfoCL( gpuUniqueEdges.getBufferCL(),true), + b3BufferInfoCL( gpuFaces.getBufferCL(),true), + b3BufferInfoCL( gpuIndices.getBufferCL(),true), + b3BufferInfoCL( clAabbsWorldSpace.getBufferCL(),true), + b3BufferInfoCL( contactOut->getBufferCL()), + b3BufferInfoCL( m_totalContactsOut.getBufferCL()) + }; + + b3LauncherCL launcher(m_queue, m_findConcaveSphereContactsKernel,"m_findConcaveSphereContactsKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + + launcher.setConst( numConcavePairs ); + launcher.setConst(maxContactCapacity); + + int num = numConcavePairs; + launcher.launch1D( num); + clFinish(m_queue); + nContacts = m_totalContactsOut.at(0); + //printf("nContacts (after findConcaveSphereContactsKernel) = %d\n",nContacts); + + //printf("nContacts2 = %d\n",nContacts); + + if (nContacts >= maxContactCapacity) + { + b3Error("Error: contacts exceeds capacity (%d/%d)\n", nContacts, maxContactCapacity); + nContacts = maxContactCapacity; + } + } + + } + + + +#ifdef __APPLE__ + bool contactClippingOnGpu = true; +#else + bool contactClippingOnGpu = true; +#endif + + if (contactClippingOnGpu) + { + m_totalContactsOut.copyFromHostPointer(&nContacts,1,0,true); +// printf("nContacts3 = %d\n",nContacts); + + + //B3_PROFILE("clipHullHullKernel"); + + bool breakupConcaveConvexKernel = true; + +#ifdef __APPLE__ + //actually, some Apple OpenCL platform/device combinations work fine... + breakupConcaveConvexKernel = true; +#endif + //concave-convex contact clipping + if (numConcavePairs) + { + // printf("numConcavePairs = %d\n", numConcavePairs); + // nContacts = m_totalContactsOut.at(0); + // printf("nContacts before = %d\n", nContacts); + + if (breakupConcaveConvexKernel) + { + + worldVertsB2GPU.resize(vertexFaceCapacity*numConcavePairs); + + + //clipFacesAndFindContacts + + if (clipConcaveFacesAndFindContactsCPU) + { + + b3AlignedObjectArray clippingFacesOutCPU; + b3AlignedObjectArray worldVertsA1CPU; + b3AlignedObjectArray worldNormalsACPU; + b3AlignedObjectArray worldVertsB1CPU; + + clippingFacesOutGPU.copyToHost(clippingFacesOutCPU); + worldVertsA1GPU.copyToHost(worldVertsA1CPU); + worldNormalsAGPU.copyToHost(worldNormalsACPU); + worldVertsB1GPU.copyToHost(worldVertsB1CPU); + + + + b3AlignedObjectArrayconcaveHasSeparatingNormalsCPU; + m_concaveHasSeparatingNormals.copyToHost(concaveHasSeparatingNormalsCPU); + + b3AlignedObjectArray concaveSepNormalsHost; + m_concaveSepNormals.copyToHost(concaveSepNormalsHost); + + b3AlignedObjectArray worldVertsB2CPU; + worldVertsB2CPU.resize(worldVertsB2GPU.size()); + + + for (int i=0;ireserve(newContactCapacity); + if (reduceConcaveContactsOnGPU) + { +// printf("newReservation = %d\n",newReservation); + { + B3_PROFILE("newContactReductionKernel"); + b3BufferInfoCL bInfo[] = + { + b3BufferInfoCL( triangleConvexPairsOut.getBufferCL(), true ), + b3BufferInfoCL( bodyBuf->getBufferCL(),true), + b3BufferInfoCL( m_concaveSepNormals.getBufferCL()), + b3BufferInfoCL( m_concaveHasSeparatingNormals.getBufferCL()), + b3BufferInfoCL( contactOut->getBufferCL()), + b3BufferInfoCL( clippingFacesOutGPU.getBufferCL()), + b3BufferInfoCL( worldVertsB2GPU.getBufferCL()), + b3BufferInfoCL( m_totalContactsOut.getBufferCL()) + }; + + b3LauncherCL launcher(m_queue, m_newContactReductionKernel,"m_newContactReductionKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(vertexFaceCapacity); + launcher.setConst(newContactCapacity); + launcher.setConst( numConcavePairs ); + int num = numConcavePairs; + + launcher.launch1D( num); + } + nContacts = m_totalContactsOut.at(0); + contactOut->resize(nContacts); + + //printf("contactOut4 (after newContactReductionKernel) = %d\n",nContacts); + }else + { + + volatile int nGlobalContactsOut = nContacts; + b3AlignedObjectArray triangleConvexPairsOutHost; + triangleConvexPairsOut.copyToHost(triangleConvexPairsOutHost); + b3AlignedObjectArray hostBodyBuf; + bodyBuf->copyToHost(hostBodyBuf); + + b3AlignedObjectArrayconcaveHasSeparatingNormalsCPU; + m_concaveHasSeparatingNormals.copyToHost(concaveHasSeparatingNormalsCPU); + + b3AlignedObjectArray concaveSepNormalsHost; + m_concaveSepNormals.copyToHost(concaveSepNormalsHost); + + + b3AlignedObjectArray hostContacts; + if (nContacts) + { + contactOut->copyToHost(hostContacts); + } + hostContacts.resize(newContactCapacity); + + b3AlignedObjectArray clippingFacesOutCPU; + b3AlignedObjectArray worldVertsB2CPU; + + clippingFacesOutGPU.copyToHost(clippingFacesOutCPU); + worldVertsB2GPU.copyToHost(worldVertsB2CPU); + + + + for (int i=0;iresize(nContacts); + hostContacts.resize(nContacts); + //printf("contactOut4 (after newContactReductionKernel) = %d\n",nContacts); + contactOut->copyFromHost(hostContacts); + } + + } + //re-use? + + + } else + { + B3_PROFILE("clipHullHullConcaveConvexKernel"); + nContacts = m_totalContactsOut.at(0); + int newContactCapacity = contactOut->capacity(); + + //printf("contactOut5 = %d\n",nContacts); + b3BufferInfoCL bInfo[] = { + b3BufferInfoCL( triangleConvexPairsOut.getBufferCL(), true ), + b3BufferInfoCL( bodyBuf->getBufferCL(),true), + b3BufferInfoCL( gpuCollidables.getBufferCL(),true), + b3BufferInfoCL( convexData.getBufferCL(),true), + b3BufferInfoCL( gpuVertices.getBufferCL(),true), + b3BufferInfoCL( gpuUniqueEdges.getBufferCL(),true), + b3BufferInfoCL( gpuFaces.getBufferCL(),true), + b3BufferInfoCL( gpuIndices.getBufferCL(),true), + b3BufferInfoCL( gpuChildShapes.getBufferCL(),true), + b3BufferInfoCL( m_concaveSepNormals.getBufferCL()), + b3BufferInfoCL( contactOut->getBufferCL()), + b3BufferInfoCL( m_totalContactsOut.getBufferCL()) + }; + b3LauncherCL launcher(m_queue, m_clipHullHullConcaveConvexKernel,"m_clipHullHullConcaveConvexKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(newContactCapacity); + launcher.setConst( numConcavePairs ); + int num = numConcavePairs; + launcher.launch1D( num); + clFinish(m_queue); + nContacts = m_totalContactsOut.at(0); + contactOut->resize(nContacts); + //printf("contactOut6 = %d\n",nContacts); + b3AlignedObjectArray cpuContacts; + contactOut->copyToHost(cpuContacts); + } + // printf("nContacts after = %d\n", nContacts); + }//numConcavePairs + + + + //convex-convex contact clipping + + bool breakupKernel = false; + +#ifdef __APPLE__ + breakupKernel = true; +#endif + +#ifdef CHECK_ON_HOST + bool computeConvexConvex = false; +#else + bool computeConvexConvex = true; +#endif//CHECK_ON_HOST + if (computeConvexConvex) + { + B3_PROFILE("clipHullHullKernel"); + if (breakupKernel) + { + + + + + worldVertsB1GPU.resize(vertexFaceCapacity*nPairs); + clippingFacesOutGPU.resize(nPairs); + worldNormalsAGPU.resize(nPairs); + worldVertsA1GPU.resize(vertexFaceCapacity*nPairs); + worldVertsB2GPU.resize(vertexFaceCapacity*nPairs); + + if (findConvexClippingFacesGPU) + { + B3_PROFILE("findClippingFacesKernel"); + b3BufferInfoCL bInfo[] = { + b3BufferInfoCL( pairs->getBufferCL(), true ), + b3BufferInfoCL( bodyBuf->getBufferCL(),true), + b3BufferInfoCL( gpuCollidables.getBufferCL(),true), + b3BufferInfoCL( convexData.getBufferCL(),true), + b3BufferInfoCL( gpuVertices.getBufferCL(),true), + b3BufferInfoCL( gpuUniqueEdges.getBufferCL(),true), + b3BufferInfoCL( gpuFaces.getBufferCL(),true), + b3BufferInfoCL( gpuIndices.getBufferCL(),true), + b3BufferInfoCL( m_sepNormals.getBufferCL()), + b3BufferInfoCL( m_hasSeparatingNormals.getBufferCL()), + b3BufferInfoCL( clippingFacesOutGPU.getBufferCL()), + b3BufferInfoCL( worldVertsA1GPU.getBufferCL()), + b3BufferInfoCL( worldNormalsAGPU.getBufferCL()), + b3BufferInfoCL( worldVertsB1GPU.getBufferCL()) + }; + + b3LauncherCL launcher(m_queue, m_findClippingFacesKernel,"m_findClippingFacesKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( vertexFaceCapacity); + launcher.setConst( nPairs ); + int num = nPairs; + launcher.launch1D( num); + clFinish(m_queue); + + } else + { + + float minDist = -1e30f; + float maxDist = 0.02f; + + b3AlignedObjectArray hostConvexData; + convexData.copyToHost(hostConvexData); + b3AlignedObjectArray hostCollidables; + gpuCollidables.copyToHost(hostCollidables); + + b3AlignedObjectArray hostHasSepNormals; + m_hasSeparatingNormals.copyToHost(hostHasSepNormals); + b3AlignedObjectArray cpuSepNormals; + m_sepNormals.copyToHost(cpuSepNormals); + + b3AlignedObjectArray hostPairs; + pairs->copyToHost(hostPairs); + b3AlignedObjectArray hostBodyBuf; + bodyBuf->copyToHost(hostBodyBuf); + + + //worldVertsB1GPU.resize(vertexFaceCapacity*nPairs); + b3AlignedObjectArray worldVertsB1CPU; + worldVertsB1GPU.copyToHost(worldVertsB1CPU); + + b3AlignedObjectArray clippingFacesOutCPU; + clippingFacesOutGPU.copyToHost(clippingFacesOutCPU); + + b3AlignedObjectArray worldNormalsACPU; + worldNormalsACPU.resize(nPairs); + + b3AlignedObjectArray worldVertsA1CPU; + worldVertsA1CPU.resize(worldVertsA1GPU.size()); + + + b3AlignedObjectArray hostVertices; + gpuVertices.copyToHost(hostVertices); + b3AlignedObjectArray hostFaces; + gpuFaces.copyToHost(hostFaces); + b3AlignedObjectArray hostIndices; + gpuIndices.copyToHost(hostIndices); + + + for (int i=0;i hostPairs; + //pairs->copyToHost(hostPairs); + + b3AlignedObjectArray hostSepNormals; + m_sepNormals.copyToHost(hostSepNormals); + b3AlignedObjectArray hostHasSepAxis; + m_hasSeparatingNormals.copyToHost(hostHasSepAxis); + + b3AlignedObjectArray hostClippingFaces; + clippingFacesOutGPU.copyToHost(hostClippingFaces); + b3AlignedObjectArray worldVertsB2CPU; + worldVertsB2CPU.resize(vertexFaceCapacity*nPairs); + + b3AlignedObjectArrayworldVertsA1CPU; + worldVertsA1GPU.copyToHost(worldVertsA1CPU); + b3AlignedObjectArray worldNormalsACPU; + worldNormalsAGPU.copyToHost(worldNormalsACPU); + + b3AlignedObjectArray worldVertsB1CPU; + worldVertsB1GPU.copyToHost(worldVertsB1CPU); + + /* + __global const b3Float4* separatingNormals, + __global const int* hasSeparatingAxis, + __global b3Int4* clippingFacesOut, + __global b3Float4* worldVertsA1, + __global b3Float4* worldNormalsA1, + __global b3Float4* worldVertsB1, + __global b3Float4* worldVertsB2, + int vertexFaceCapacity, + int pairIndex + */ + for (int i=0;ireserve(newContactCapacity); + + if (reduceConvexContactsOnGPU) + { + { + B3_PROFILE("newContactReductionKernel"); + b3BufferInfoCL bInfo[] = + { + b3BufferInfoCL( pairs->getBufferCL(), true ), + b3BufferInfoCL( bodyBuf->getBufferCL(),true), + b3BufferInfoCL( m_sepNormals.getBufferCL()), + b3BufferInfoCL( m_hasSeparatingNormals.getBufferCL()), + b3BufferInfoCL( contactOut->getBufferCL()), + b3BufferInfoCL( clippingFacesOutGPU.getBufferCL()), + b3BufferInfoCL( worldVertsB2GPU.getBufferCL()), + b3BufferInfoCL( m_totalContactsOut.getBufferCL()) + }; + + b3LauncherCL launcher(m_queue, m_newContactReductionKernel,"m_newContactReductionKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(vertexFaceCapacity); + launcher.setConst(newContactCapacity); + launcher.setConst( nPairs ); + int num = nPairs; + + launcher.launch1D( num); + } + nContacts = m_totalContactsOut.at(0); + contactOut->resize(nContacts); + } else + { + + volatile int nGlobalContactsOut = nContacts; + b3AlignedObjectArray hostPairs; + pairs->copyToHost(hostPairs); + b3AlignedObjectArray hostBodyBuf; + bodyBuf->copyToHost(hostBodyBuf); + b3AlignedObjectArray hostSepNormals; + m_sepNormals.copyToHost(hostSepNormals); + b3AlignedObjectArray hostHasSepAxis; + m_hasSeparatingNormals.copyToHost(hostHasSepAxis); + b3AlignedObjectArray hostContactsOut; + contactOut->copyToHost(hostContactsOut); + hostContactsOut.resize(newContactCapacity); + + b3AlignedObjectArray hostClippingFaces; + clippingFacesOutGPU.copyToHost(hostClippingFaces); + b3AlignedObjectArray worldVertsB2CPU; + worldVertsB2GPU.copyToHost(worldVertsB2CPU); + + for (int i=0;icopyFromHost(hostContactsOut); + } + // b3Contact4 pt = contactOut->at(0); + // printf("nContacts = %d\n",nContacts); + } + } + } + else//breakupKernel + { + + if (nPairs) + { + b3BufferInfoCL bInfo[] = { + b3BufferInfoCL( pairs->getBufferCL(), true ), + b3BufferInfoCL( bodyBuf->getBufferCL(),true), + b3BufferInfoCL( gpuCollidables.getBufferCL(),true), + b3BufferInfoCL( convexData.getBufferCL(),true), + b3BufferInfoCL( gpuVertices.getBufferCL(),true), + b3BufferInfoCL( gpuUniqueEdges.getBufferCL(),true), + b3BufferInfoCL( gpuFaces.getBufferCL(),true), + b3BufferInfoCL( gpuIndices.getBufferCL(),true), + b3BufferInfoCL( m_sepNormals.getBufferCL()), + b3BufferInfoCL( m_hasSeparatingNormals.getBufferCL()), + b3BufferInfoCL( contactOut->getBufferCL()), + b3BufferInfoCL( m_totalContactsOut.getBufferCL()) + }; + b3LauncherCL launcher(m_queue, m_clipHullHullKernel,"m_clipHullHullKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( nPairs ); + launcher.setConst(maxContactCapacity); + + int num = nPairs; + launcher.launch1D( num); + clFinish(m_queue); + + nContacts = m_totalContactsOut.at(0); + if (nContacts >= maxContactCapacity) + { + b3Error("Exceeded contact capacity (%d/%d)\n",nContacts,maxContactCapacity); + nContacts = maxContactCapacity; + } + contactOut->resize(nContacts); + } + } + + + int nCompoundsPairs = m_gpuCompoundPairs.size(); + + if (nCompoundsPairs) + { + b3BufferInfoCL bInfo[] = { + b3BufferInfoCL( m_gpuCompoundPairs.getBufferCL(), true ), + b3BufferInfoCL( bodyBuf->getBufferCL(),true), + b3BufferInfoCL( gpuCollidables.getBufferCL(),true), + b3BufferInfoCL( convexData.getBufferCL(),true), + b3BufferInfoCL( gpuVertices.getBufferCL(),true), + b3BufferInfoCL( gpuUniqueEdges.getBufferCL(),true), + b3BufferInfoCL( gpuFaces.getBufferCL(),true), + b3BufferInfoCL( gpuIndices.getBufferCL(),true), + b3BufferInfoCL( gpuChildShapes.getBufferCL(),true), + b3BufferInfoCL( m_gpuCompoundSepNormals.getBufferCL(),true), + b3BufferInfoCL( m_gpuHasCompoundSepNormals.getBufferCL(),true), + b3BufferInfoCL( contactOut->getBufferCL()), + b3BufferInfoCL( m_totalContactsOut.getBufferCL()) + }; + b3LauncherCL launcher(m_queue, m_clipCompoundsHullHullKernel,"m_clipCompoundsHullHullKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( nCompoundsPairs ); + launcher.setConst(maxContactCapacity); + + int num = nCompoundsPairs; + launcher.launch1D( num); + clFinish(m_queue); + + nContacts = m_totalContactsOut.at(0); + if (nContacts>maxContactCapacity) + { + + b3Error("Error: contacts exceeds capacity (%d/%d)\n", nContacts, maxContactCapacity); + nContacts = maxContactCapacity; + } + contactOut->resize(nContacts); + }//if nCompoundsPairs + } + }//contactClippingOnGpu + + //printf("nContacts end = %d\n",nContacts); + + //printf("frameCount = %d\n",frameCount++); +} diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3ConvexHullContact.h b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3ConvexHullContact.h new file mode 100644 index 000000000000..e24c1579c6dc --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3ConvexHullContact.h @@ -0,0 +1,118 @@ + +#ifndef _CONVEX_HULL_CONTACT_H +#define _CONVEX_HULL_CONTACT_H + +#include "Bullet3OpenCL/ParallelPrimitives/b3OpenCLArray.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" +#include "Bullet3Common/b3AlignedObjectArray.h" + +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3ConvexPolyhedronData.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3Collidable.h" +#include "Bullet3Collision/NarrowPhaseCollision/b3Contact4.h" +#include "Bullet3Common/shared/b3Int2.h" +#include "Bullet3Common/shared/b3Int4.h" +#include "b3OptimizedBvh.h" +#include "b3BvhInfo.h" +#include "Bullet3Collision/BroadPhaseCollision/shared/b3Aabb.h" + +//#include "../../dynamics/basic_demo/Stubs/ChNarrowPhase.h" + + + + +struct GpuSatCollision +{ + cl_context m_context; + cl_device_id m_device; + cl_command_queue m_queue; + cl_kernel m_findSeparatingAxisKernel; + cl_kernel m_mprPenetrationKernel; + cl_kernel m_findSeparatingAxisUnitSphereKernel; + + + cl_kernel m_findSeparatingAxisVertexFaceKernel; + cl_kernel m_findSeparatingAxisEdgeEdgeKernel; + + cl_kernel m_findConcaveSeparatingAxisKernel; + cl_kernel m_findConcaveSeparatingAxisVertexFaceKernel; + cl_kernel m_findConcaveSeparatingAxisEdgeEdgeKernel; + + + + + cl_kernel m_findCompoundPairsKernel; + cl_kernel m_processCompoundPairsKernel; + + cl_kernel m_clipHullHullKernel; + cl_kernel m_clipCompoundsHullHullKernel; + + cl_kernel m_clipFacesAndFindContacts; + cl_kernel m_findClippingFacesKernel; + + cl_kernel m_clipHullHullConcaveConvexKernel; +// cl_kernel m_extractManifoldAndAddContactKernel; + cl_kernel m_newContactReductionKernel; + + cl_kernel m_bvhTraversalKernel; + cl_kernel m_primitiveContactsKernel; + cl_kernel m_findConcaveSphereContactsKernel; + + cl_kernel m_processCompoundPairsPrimitivesKernel; + + b3OpenCLArray m_unitSphereDirections; + + b3OpenCLArray m_totalContactsOut; + + b3OpenCLArray m_sepNormals; + b3OpenCLArray m_dmins; + + b3OpenCLArray m_hasSeparatingNormals; + b3OpenCLArray m_concaveSepNormals; + b3OpenCLArray m_concaveHasSeparatingNormals; + b3OpenCLArray m_numConcavePairsOut; + b3OpenCLArray m_gpuCompoundPairs; + b3OpenCLArray m_gpuCompoundSepNormals; + b3OpenCLArray m_gpuHasCompoundSepNormals; + b3OpenCLArray m_numCompoundPairsOut; + + + GpuSatCollision(cl_context ctx,cl_device_id device, cl_command_queue q ); + virtual ~GpuSatCollision(); + + + void computeConvexConvexContactsGPUSAT( b3OpenCLArray* pairs, int nPairs, + const b3OpenCLArray* bodyBuf, + b3OpenCLArray* contactOut, int& nContacts, + const b3OpenCLArray* oldContacts, + int maxContactCapacity, + int compoundPairCapacity, + const b3OpenCLArray& hostConvexData, + const b3OpenCLArray& vertices, + const b3OpenCLArray& uniqueEdges, + const b3OpenCLArray& faces, + const b3OpenCLArray& indices, + const b3OpenCLArray& gpuCollidables, + const b3OpenCLArray& gpuChildShapes, + + const b3OpenCLArray& clAabbsWorldSpace, + const b3OpenCLArray& clAabbsLocalSpace, + + b3OpenCLArray& worldVertsB1GPU, + b3OpenCLArray& clippingFacesOutGPU, + b3OpenCLArray& worldNormalsAGPU, + b3OpenCLArray& worldVertsA1GPU, + b3OpenCLArray& worldVertsB2GPU, + b3AlignedObjectArray& bvhData, + b3OpenCLArray* treeNodesGPU, + b3OpenCLArray* subTreesGPU, + b3OpenCLArray* bvhInfo, + int numObjects, + int maxTriConvexPairCapacity, + b3OpenCLArray& triangleConvexPairs, + int& numTriConvexPairsOut + ); + + +}; + +#endif //_CONVEX_HULL_CONTACT_H diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3ConvexPolyhedronCL.h b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3ConvexPolyhedronCL.h new file mode 100644 index 000000000000..337100fb1a6a --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3ConvexPolyhedronCL.h @@ -0,0 +1,9 @@ +#ifndef CONVEX_POLYHEDRON_CL +#define CONVEX_POLYHEDRON_CL + +#include "Bullet3Common/b3Transform.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3ConvexPolyhedronData.h" + + + +#endif //CONVEX_POLYHEDRON_CL diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3GjkEpa.cpp b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3GjkEpa.cpp new file mode 100644 index 000000000000..d636f983c69b --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3GjkEpa.cpp @@ -0,0 +1,1014 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2008 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, 2008 +*/ + +#include "b3GjkEpa.h" + +#include "b3SupportMappings.h" + +namespace gjkepa2_impl2 +{ + + // Config + + /* GJK */ +#define GJK_MAX_ITERATIONS 128 +#define GJK_ACCURACY ((b3Scalar)0.0001) +#define GJK_MIN_DISTANCE ((b3Scalar)0.0001) +#define GJK_DUPLICATED_EPS ((b3Scalar)0.0001) +#define GJK_SIMPLEX2_EPS ((b3Scalar)0.0) +#define GJK_SIMPLEX3_EPS ((b3Scalar)0.0) +#define GJK_SIMPLEX4_EPS ((b3Scalar)0.0) + + /* EPA */ +#define EPA_MAX_VERTICES 64 +#define EPA_MAX_FACES (EPA_MAX_VERTICES*2) +#define EPA_MAX_ITERATIONS 255 +#define EPA_ACCURACY ((b3Scalar)0.0001) +#define EPA_FALLBACK (10*EPA_ACCURACY) +#define EPA_PLANE_EPS ((b3Scalar)0.00001) +#define EPA_INSIDE_EPS ((b3Scalar)0.01) + + + // Shorthands + + + // MinkowskiDiff + struct b3MinkowskiDiff + { + + + const b3ConvexPolyhedronData* m_shapes[2]; + + + b3Matrix3x3 m_toshape1; + b3Transform m_toshape0; + + bool m_enableMargin; + + + void EnableMargin(bool enable) + { + m_enableMargin = enable; + } + inline b3Vector3 Support0(const b3Vector3& d, const b3AlignedObjectArray& verticesA) const + { + if (m_enableMargin) + { + return localGetSupportVertexWithMargin(d,m_shapes[0],verticesA,0.f); + } else + { + return localGetSupportVertexWithoutMargin(d,m_shapes[0],verticesA); + } + } + inline b3Vector3 Support1(const b3Vector3& d, const b3AlignedObjectArray& verticesB) const + { + if (m_enableMargin) + { + return m_toshape0*(localGetSupportVertexWithMargin(m_toshape1*d,m_shapes[1],verticesB,0.f)); + } else + { + return m_toshape0*(localGetSupportVertexWithoutMargin(m_toshape1*d,m_shapes[1],verticesB)); + } + } + + inline b3Vector3 Support(const b3Vector3& d, const b3AlignedObjectArray& verticesA, const b3AlignedObjectArray& verticesB) const + { + return(Support0(d,verticesA)-Support1(-d,verticesB)); + } + b3Vector3 Support(const b3Vector3& d,unsigned int index,const b3AlignedObjectArray& verticesA, const b3AlignedObjectArray& verticesB) const + { + if(index) + return(Support1(d,verticesA)); + else + return(Support0(d,verticesB)); + } + }; + + typedef b3MinkowskiDiff tShape; + + + // GJK + struct b3GJK + { + /* Types */ + struct sSV + { + b3Vector3 d,w; + }; + struct sSimplex + { + sSV* c[4]; + b3Scalar p[4]; + unsigned int rank; + }; + struct eStatus { enum _ { + Valid, + Inside, + Failed };}; + /* Fields */ + tShape m_shape; + const b3AlignedObjectArray& m_verticesA; + const b3AlignedObjectArray& m_verticesB; + b3Vector3 m_ray; + b3Scalar m_distance; + sSimplex m_simplices[2]; + sSV m_store[4]; + sSV* m_free[4]; + unsigned int m_nfree; + unsigned int m_current; + sSimplex* m_simplex; + eStatus::_ m_status; + /* Methods */ + b3GJK(const b3AlignedObjectArray& verticesA,const b3AlignedObjectArray& verticesB) + :m_verticesA(verticesA),m_verticesB(verticesB) + { + Initialize(); + } + void Initialize() + { + m_ray = b3MakeVector3(0,0,0); + m_nfree = 0; + m_status = eStatus::Failed; + m_current = 0; + m_distance = 0; + } + eStatus::_ Evaluate(const tShape& shapearg,const b3Vector3& guess) + { + unsigned int iterations=0; + b3Scalar sqdist=0; + b3Scalar alpha=0; + b3Vector3 lastw[4]; + unsigned int clastw=0; + /* Initialize solver */ + m_free[0] = &m_store[0]; + m_free[1] = &m_store[1]; + m_free[2] = &m_store[2]; + m_free[3] = &m_store[3]; + m_nfree = 4; + m_current = 0; + m_status = eStatus::Valid; + m_shape = shapearg; + m_distance = 0; + /* Initialize simplex */ + m_simplices[0].rank = 0; + m_ray = guess; + const b3Scalar sqrl= m_ray.length2(); + appendvertice(m_simplices[0],sqrl>0?-m_ray:b3MakeVector3(1,0,0)); + m_simplices[0].p[0] = 1; + m_ray = m_simplices[0].c[0]->w; + sqdist = sqrl; + lastw[0] = + lastw[1] = + lastw[2] = + lastw[3] = m_ray; + /* Loop */ + do { + const unsigned int next=1-m_current; + sSimplex& cs=m_simplices[m_current]; + sSimplex& ns=m_simplices[next]; + /* Check zero */ + const b3Scalar rl=m_ray.length(); + if(rlw; + bool found=false; + for(unsigned int i=0;i<4;++i) + { + if((w-lastw[i]).length2()w, + cs.c[1]->w, + weights,mask);break; + case 3: sqdist=projectorigin( cs.c[0]->w, + cs.c[1]->w, + cs.c[2]->w, + weights,mask);break; + case 4: sqdist=projectorigin( cs.c[0]->w, + cs.c[1]->w, + cs.c[2]->w, + cs.c[3]->w, + weights,mask);break; + } + if(sqdist>=0) + {/* Valid */ + ns.rank = 0; + m_ray = b3MakeVector3(0,0,0); + m_current = next; + for(unsigned int i=0,ni=cs.rank;iw*weights[i]; + } + else + { + m_free[m_nfree++] = cs.c[i]; + } + } + if(mask==15) m_status=eStatus::Inside; + } + else + {/* Return old simplex */ + removevertice(m_simplices[m_current]); + break; + } + m_status=((++iterations)rank) + { + case 1: + { + for(unsigned int i=0;i<3;++i) + { + b3Vector3 axis=b3MakeVector3(0,0,0); + axis[i]=1; + appendvertice(*m_simplex, axis); + if(EncloseOrigin()) return(true); + removevertice(*m_simplex); + appendvertice(*m_simplex,-axis); + if(EncloseOrigin()) return(true); + removevertice(*m_simplex); + } + } + break; + case 2: + { + const b3Vector3 d=m_simplex->c[1]->w-m_simplex->c[0]->w; + for(unsigned int i=0;i<3;++i) + { + b3Vector3 axis=b3MakeVector3(0,0,0); + axis[i]=1; + const b3Vector3 p=b3Cross(d,axis); + if(p.length2()>0) + { + appendvertice(*m_simplex, p); + if(EncloseOrigin()) return(true); + removevertice(*m_simplex); + appendvertice(*m_simplex,-p); + if(EncloseOrigin()) return(true); + removevertice(*m_simplex); + } + } + } + break; + case 3: + { + const b3Vector3 n=b3Cross(m_simplex->c[1]->w-m_simplex->c[0]->w, + m_simplex->c[2]->w-m_simplex->c[0]->w); + if(n.length2()>0) + { + appendvertice(*m_simplex,n); + if(EncloseOrigin()) return(true); + removevertice(*m_simplex); + appendvertice(*m_simplex,-n); + if(EncloseOrigin()) return(true); + removevertice(*m_simplex); + } + } + break; + case 4: + { + if(b3Fabs(det( m_simplex->c[0]->w-m_simplex->c[3]->w, + m_simplex->c[1]->w-m_simplex->c[3]->w, + m_simplex->c[2]->w-m_simplex->c[3]->w))>0) + return(true); + } + break; + } + return(false); + } + /* Internals */ + void getsupport(const b3Vector3& d,sSV& sv) const + { + sv.d = d/d.length(); + sv.w = m_shape.Support(sv.d,m_verticesA,m_verticesB); + } + void removevertice(sSimplex& simplex) + { + m_free[m_nfree++]=simplex.c[--simplex.rank]; + } + void appendvertice(sSimplex& simplex,const b3Vector3& v) + { + simplex.p[simplex.rank]=0; + simplex.c[simplex.rank]=m_free[--m_nfree]; + getsupport(v,*simplex.c[simplex.rank++]); + } + static b3Scalar det(const b3Vector3& a,const b3Vector3& b,const b3Vector3& c) + { + return( a.y*b.z*c.x+a.z*b.x*c.y- + a.x*b.z*c.y-a.y*b.x*c.z+ + a.x*b.y*c.z-a.z*b.y*c.x); + } + static b3Scalar projectorigin( const b3Vector3& a, + const b3Vector3& b, + b3Scalar* w,unsigned int& m) + { + const b3Vector3 d=b-a; + const b3Scalar l=d.length2(); + if(l>GJK_SIMPLEX2_EPS) + { + const b3Scalar t(l>0?-b3Dot(a,d)/l:0); + if(t>=1) { w[0]=0;w[1]=1;m=2;return(b.length2()); } + else if(t<=0) { w[0]=1;w[1]=0;m=1;return(a.length2()); } + else { w[0]=1-(w[1]=t);m=3;return((a+d*t).length2()); } + } + return(-1); + } + static b3Scalar projectorigin( const b3Vector3& a, + const b3Vector3& b, + const b3Vector3& c, + b3Scalar* w,unsigned int& m) + { + static const unsigned int imd3[]={1,2,0}; + const b3Vector3* vt[]={&a,&b,&c}; + const b3Vector3 dl[]={a-b,b-c,c-a}; + const b3Vector3 n=b3Cross(dl[0],dl[1]); + const b3Scalar l=n.length2(); + if(l>GJK_SIMPLEX3_EPS) + { + b3Scalar mindist=-1; + b3Scalar subw[2]={0.f,0.f}; + unsigned int subm(0); + for(unsigned int i=0;i<3;++i) + { + if(b3Dot(*vt[i],b3Cross(dl[i],n))>0) + { + const unsigned int j=imd3[i]; + const b3Scalar subd(projectorigin(*vt[i],*vt[j],subw,subm)); + if((mindist<0)||(subd(((subm&1)?1<GJK_SIMPLEX4_EPS)) + { + b3Scalar mindist=-1; + b3Scalar subw[3]={0.f,0.f,0.f}; + unsigned int subm(0); + for(unsigned int i=0;i<3;++i) + { + const unsigned int j=imd3[i]; + const b3Scalar s=vl*b3Dot(d,b3Cross(dl[i],dl[j])); + if(s>0) + { + const b3Scalar subd=projectorigin(*vt[i],*vt[j],d,subw,subm); + if((mindist<0)||(subd((subm&1?1<e[ea]=(unsigned char)eb;fa->f[ea]=fb; + fb->e[eb]=(unsigned char)ea;fb->f[eb]=fa; + } + static inline void append(sList& list,sFace* face) + { + face->l[0] = 0; + face->l[1] = list.root; + if(list.root) list.root->l[0]=face; + list.root = face; + ++list.count; + } + static inline void remove(sList& list,sFace* face) + { + if(face->l[1]) face->l[1]->l[0]=face->l[0]; + if(face->l[0]) face->l[0]->l[1]=face->l[1]; + if(face==list.root) list.root=face->l[1]; + --list.count; + } + + + void Initialize() + { + m_status = eStatus::Failed; + m_normal = b3MakeVector3(0,0,0); + m_depth = 0; + m_nextsv = 0; + for(unsigned int i=0;i1)&&gjk.EncloseOrigin()) + { + + /* Clean up */ + while(m_hull.root) + { + sFace* f = m_hull.root; + remove(m_hull,f); + append(m_stock,f); + } + m_status = eStatus::Valid; + m_nextsv = 0; + /* Orient simplex */ + if(gjk.det( simplex.c[0]->w-simplex.c[3]->w, + simplex.c[1]->w-simplex.c[3]->w, + simplex.c[2]->w-simplex.c[3]->w)<0) + { + b3Swap(simplex.c[0],simplex.c[1]); + b3Swap(simplex.p[0],simplex.p[1]); + } + /* Build initial hull */ + sFace* tetra[]={newface(simplex.c[0],simplex.c[1],simplex.c[2],true), + newface(simplex.c[1],simplex.c[0],simplex.c[3],true), + newface(simplex.c[2],simplex.c[1],simplex.c[3],true), + newface(simplex.c[0],simplex.c[2],simplex.c[3],true)}; + if(m_hull.count==4) + { + sFace* best=findbest(); + sFace outer=*best; + unsigned int pass=0; + unsigned int iterations=0; + bind(tetra[0],0,tetra[1],0); + bind(tetra[0],1,tetra[2],0); + bind(tetra[0],2,tetra[3],0); + bind(tetra[1],1,tetra[3],2); + bind(tetra[1],2,tetra[2],1); + bind(tetra[2],2,tetra[3],1); + m_status=eStatus::Valid; + for(;iterationspass = (unsigned char)(++pass); + gjk.getsupport(best->n,*w); + const b3Scalar wdist=b3Dot(best->n,w->w)-best->d; + if(wdist>EPA_ACCURACY) + { + for(unsigned int j=0;(j<3)&&valid;++j) + { + valid&=expand( pass,w, + best->f[j],best->e[j], + horizon); + } + if(valid&&(horizon.nf>=3)) + { + bind(horizon.cf,1,horizon.ff,2); + remove(m_hull,best); + append(m_stock,best); + best=findbest(); + outer=*best; + } else { + m_status=eStatus::Failed; + //m_status=eStatus::InvalidHull; + break; } + } else { m_status=eStatus::AccuraryReached;break; } + } else { m_status=eStatus::OutOfVertices;break; } + } + const b3Vector3 projection=outer.n*outer.d; + m_normal = outer.n; + m_depth = outer.d; + m_result.rank = 3; + m_result.c[0] = outer.c[0]; + m_result.c[1] = outer.c[1]; + m_result.c[2] = outer.c[2]; + m_result.p[0] = b3Cross( outer.c[1]->w-projection, + outer.c[2]->w-projection).length(); + m_result.p[1] = b3Cross( outer.c[2]->w-projection, + outer.c[0]->w-projection).length(); + m_result.p[2] = b3Cross( outer.c[0]->w-projection, + outer.c[1]->w-projection).length(); + const b3Scalar sum=m_result.p[0]+m_result.p[1]+m_result.p[2]; + m_result.p[0] /= sum; + m_result.p[1] /= sum; + m_result.p[2] /= sum; + return(m_status); + } + } + /* Fallback */ + m_status = eStatus::FallBack; + m_normal = -guess; + const b3Scalar nl=m_normal.length(); + if(nl>0) + m_normal = m_normal/nl; + else + m_normal = b3MakeVector3(1,0,0); + m_depth = 0; + m_result.rank=1; + m_result.c[0]=simplex.c[0]; + m_result.p[0]=1; + return(m_status); + } + bool getedgedist(sFace* face, sSV* a, sSV* b, b3Scalar& dist) + { + const b3Vector3 ba = b->w - a->w; + const b3Vector3 n_ab = b3Cross(ba, face->n); // Outward facing edge normal direction, on triangle plane + const b3Scalar a_dot_nab = b3Dot(a->w, n_ab); // Only care about the sign to determine inside/outside, so not normalization required + + if(a_dot_nab < 0) + { + // Outside of edge a->b + + const b3Scalar ba_l2 = ba.length2(); + const b3Scalar a_dot_ba = b3Dot(a->w, ba); + const b3Scalar b_dot_ba = b3Dot(b->w, ba); + + if(a_dot_ba > 0) + { + // Pick distance vertex a + dist = a->w.length(); + } + else if(b_dot_ba < 0) + { + // Pick distance vertex b + dist = b->w.length(); + } + else + { + // Pick distance to edge a->b + const b3Scalar a_dot_b = b3Dot(a->w, b->w); + dist = b3Sqrt(b3Max((a->w.length2() * b->w.length2() - a_dot_b * a_dot_b) / ba_l2, (b3Scalar)0)); + } + + return true; + } + + return false; + } + sFace* newface(sSV* a,sSV* b,sSV* c,bool forced) + { + if(m_stock.root) + { + sFace* face=m_stock.root; + remove(m_stock,face); + append(m_hull,face); + face->pass = 0; + face->c[0] = a; + face->c[1] = b; + face->c[2] = c; + face->n = b3Cross(b->w-a->w,c->w-a->w); + const b3Scalar l=face->n.length(); + const bool v=l>EPA_ACCURACY; + + if(v) + { + if(!(getedgedist(face, a, b, face->d) || + getedgedist(face, b, c, face->d) || + getedgedist(face, c, a, face->d))) + { + // Origin projects to the interior of the triangle + // Use distance to triangle plane + face->d = b3Dot(a->w, face->n) / l; + } + + face->n /= l; + if(forced || (face->d >= -EPA_PLANE_EPS)) + { + return face; + } + else + m_status=eStatus::NonConvex; + } + else + m_status=eStatus::Degenerated; + + remove(m_hull, face); + append(m_stock, face); + return 0; + + } + m_status = m_stock.root ? eStatus::OutOfVertices : eStatus::OutOfFaces; + return 0; + } + sFace* findbest() + { + sFace* minf=m_hull.root; + b3Scalar mind=minf->d*minf->d; + for(sFace* f=minf->l[1];f;f=f->l[1]) + { + const b3Scalar sqd=f->d*f->d; + if(sqdpass!=pass) + { + const unsigned int e1=i1m3[e]; + if((b3Dot(f->n,w->w)-f->d)<-EPA_PLANE_EPS) + { + sFace* nf=newface(f->c[e1],f->c[e],w,false); + if(nf) + { + bind(nf,0,f,e); + if(horizon.cf) bind(horizon.cf,1,nf,2); else horizon.ff=nf; + horizon.cf=nf; + ++horizon.nf; + return(true); + } + } + else + { + const unsigned int e2=i2m3[e]; + f->pass = (unsigned char)pass; + if( expand(pass,w,f->f[e1],f->e[e1],horizon)&& + expand(pass,w,f->f[e2],f->e[e2],horizon)) + { + remove(m_hull,f); + append(m_stock,f); + return(true); + } + } + } + return(false); + } + + }; + + // + static void Initialize(const b3Transform& transA, const b3Transform& transB, + const b3ConvexPolyhedronData* hullA, const b3ConvexPolyhedronData* hullB, + const b3AlignedObjectArray& verticesA, + const b3AlignedObjectArray& verticesB, + b3GjkEpaSolver2::sResults& results, + tShape& shape, + bool withmargins) + { + /* Results */ + results.witnesses[0] = + results.witnesses[1] = b3MakeVector3(0,0,0); + results.status = b3GjkEpaSolver2::sResults::Separated; + /* Shape */ + shape.m_shapes[0] = hullA; + shape.m_shapes[1] = hullB; + shape.m_toshape1 = transB.getBasis().transposeTimes(transA.getBasis()); + shape.m_toshape0 = transA.inverseTimes(transB); + shape.EnableMargin(withmargins); + } + +} + +// +// Api +// + +using namespace gjkepa2_impl2; + +// +int b3GjkEpaSolver2::StackSizeRequirement() +{ + return(sizeof(b3GJK)+sizeof(b3EPA)); +} + +// +bool b3GjkEpaSolver2::Distance( const b3Transform& transA, const b3Transform& transB, + const b3ConvexPolyhedronData* hullA, const b3ConvexPolyhedronData* hullB, + const b3AlignedObjectArray& verticesA, + const b3AlignedObjectArray& verticesB, + const b3Vector3& guess, + sResults& results) +{ + tShape shape; + Initialize(transA,transB,hullA,hullB,verticesA,verticesB,results,shape,false); + b3GJK gjk(verticesA,verticesB); + b3GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,guess); + if(gjk_status==b3GJK::eStatus::Valid) + { + b3Vector3 w0=b3MakeVector3(0,0,0); + b3Vector3 w1=b3MakeVector3(0,0,0); + for(unsigned int i=0;irank;++i) + { + const b3Scalar p=gjk.m_simplex->p[i]; + w0+=shape.Support( gjk.m_simplex->c[i]->d,0,verticesA,verticesB)*p; + w1+=shape.Support(-gjk.m_simplex->c[i]->d,1,verticesA,verticesB)*p; + } + results.witnesses[0] = transA*w0; + results.witnesses[1] = transA*w1; + results.normal = w0-w1; + results.distance = results.normal.length(); + results.normal /= results.distance>GJK_MIN_DISTANCE?results.distance:1; + return(true); + } + else + { + results.status = gjk_status==b3GJK::eStatus::Inside? + sResults::Penetrating : + sResults::GJK_Failed ; + return(false); + } +} + +// +bool b3GjkEpaSolver2::Penetration( const b3Transform& transA, const b3Transform& transB, + const b3ConvexPolyhedronData* hullA, const b3ConvexPolyhedronData* hullB, + const b3AlignedObjectArray& verticesA, + const b3AlignedObjectArray& verticesB, + const b3Vector3& guess, + sResults& results, + bool usemargins) +{ + + tShape shape; + Initialize(transA,transB,hullA,hullB,verticesA,verticesB,results,shape,usemargins); + b3GJK gjk(verticesA,verticesB); + b3GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,guess); + switch(gjk_status) + { + case b3GJK::eStatus::Inside: + { + b3EPA epa; + b3EPA::eStatus::_ epa_status=epa.Evaluate(gjk,-guess); + if(epa_status!=b3EPA::eStatus::Failed) + { + b3Vector3 w0=b3MakeVector3(0,0,0); + for(unsigned int i=0;id,0,verticesA,verticesB)*epa.m_result.p[i]; + } + results.status = sResults::Penetrating; + results.witnesses[0] = transA*w0; + results.witnesses[1] = transA*(w0-epa.m_normal*epa.m_depth); + results.normal = -epa.m_normal; + results.distance = -epa.m_depth; + return(true); + } else results.status=sResults::EPA_Failed; + } + break; + case b3GJK::eStatus::Failed: + results.status=sResults::GJK_Failed; + break; + default: + { + } + } + return(false); +} + + +#if 0 +// +b3Scalar b3GjkEpaSolver2::SignedDistance(const b3Vector3& position, + b3Scalar margin, + const b3Transform& transA, + const b3ConvexPolyhedronData& hullA, + const b3AlignedObjectArray& verticesA, + sResults& results) +{ + tShape shape; + btSphereShape shape1(margin); + b3Transform wtrs1(b3Quaternion(0,0,0,1),position); + Initialize(shape0,wtrs0,&shape1,wtrs1,results,shape,false); + GJK gjk; + GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,b3Vector3(1,1,1)); + if(gjk_status==GJK::eStatus::Valid) + { + b3Vector3 w0=b3Vector3(0,0,0); + b3Vector3 w1=b3Vector3(0,0,0); + for(unsigned int i=0;irank;++i) + { + const b3Scalar p=gjk.m_simplex->p[i]; + w0+=shape.Support( gjk.m_simplex->c[i]->d,0)*p; + w1+=shape.Support(-gjk.m_simplex->c[i]->d,1)*p; + } + results.witnesses[0] = wtrs0*w0; + results.witnesses[1] = wtrs0*w1; + const b3Vector3 delta= results.witnesses[1]- + results.witnesses[0]; + const b3Scalar margin= shape0->getMarginNonVirtual()+ + shape1.getMarginNonVirtual(); + const b3Scalar length= delta.length(); + results.normal = delta/length; + results.witnesses[0] += results.normal*margin; + return(length-margin); + } + else + { + if(gjk_status==GJK::eStatus::Inside) + { + if(Penetration(shape0,wtrs0,&shape1,wtrs1,gjk.m_ray,results)) + { + const b3Vector3 delta= results.witnesses[0]- + results.witnesses[1]; + const b3Scalar length= delta.length(); + if (length >= B3_EPSILON) + results.normal = delta/length; + return(-length); + } + } + } + return(B3_INFINITY); +} + +// +bool b3GjkEpaSolver2::SignedDistance(const btConvexShape* shape0, + const b3Transform& wtrs0, + const btConvexShape* shape1, + const b3Transform& wtrs1, + const b3Vector3& guess, + sResults& results) +{ + if(!Distance(shape0,wtrs0,shape1,wtrs1,guess,results)) + return(Penetration(shape0,wtrs0,shape1,wtrs1,guess,results,false)); + else + return(true); +} +#endif + + +/* Symbols cleanup */ + +#undef GJK_MAX_ITERATIONS +#undef GJK_ACCURACY +#undef GJK_MIN_DISTANCE +#undef GJK_DUPLICATED_EPS +#undef GJK_SIMPLEX2_EPS +#undef GJK_SIMPLEX3_EPS +#undef GJK_SIMPLEX4_EPS + +#undef EPA_MAX_VERTICES +#undef EPA_MAX_FACES +#undef EPA_MAX_ITERATIONS +#undef EPA_ACCURACY +#undef EPA_FALLBACK +#undef EPA_PLANE_EPS +#undef EPA_INSIDE_EPS diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3GjkEpa.h b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3GjkEpa.h new file mode 100644 index 000000000000..976238a04c84 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3GjkEpa.h @@ -0,0 +1,82 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2008 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, 2008 +*/ +#ifndef B3_GJK_EPA2_H +#define B3_GJK_EPA2_H + +#include "Bullet3Common/b3AlignedObjectArray.h" +#include "Bullet3Common/b3Transform.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3ConvexPolyhedronData.h" + + +///btGjkEpaSolver contributed under zlib by Nathanael Presson +struct b3GjkEpaSolver2 +{ +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; + b3Vector3 witnesses[2]; + b3Vector3 normal; + b3Scalar distance; + }; + +static int StackSizeRequirement(); + +static bool Distance( const b3Transform& transA, const b3Transform& transB, + const b3ConvexPolyhedronData* hullA, const b3ConvexPolyhedronData* hullB, + const b3AlignedObjectArray& verticesA, + const b3AlignedObjectArray& verticesB, + const b3Vector3& guess, + sResults& results); + +static bool Penetration( const b3Transform& transA, const b3Transform& transB, + const b3ConvexPolyhedronData* hullA, const b3ConvexPolyhedronData* hullB, + const b3AlignedObjectArray& verticesA, + const b3AlignedObjectArray& verticesB, + const b3Vector3& guess, + sResults& results, + bool usemargins=true); +#if 0 +static b3Scalar SignedDistance( const b3Vector3& position, + b3Scalar margin, + const btConvexShape* shape, + const btTransform& wtrs, + sResults& results); + +static bool SignedDistance( const btConvexShape* shape0,const btTransform& wtrs0, + const btConvexShape* shape1,const btTransform& wtrs1, + const b3Vector3& guess, + sResults& results); +#endif + +}; + +#endif //B3_GJK_EPA2_H + diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3OptimizedBvh.cpp b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3OptimizedBvh.cpp new file mode 100644 index 000000000000..e9e51d5a36ca --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3OptimizedBvh.cpp @@ -0,0 +1,390 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org + +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 "b3OptimizedBvh.h" +#include "b3StridingMeshInterface.h" +#include "Bullet3Geometry/b3AabbUtil.h" + + +b3OptimizedBvh::b3OptimizedBvh() +{ +} + +b3OptimizedBvh::~b3OptimizedBvh() +{ +} + + +void b3OptimizedBvh::build(b3StridingMeshInterface* triangles, bool useQuantizedAabbCompression, const b3Vector3& bvhAabbMin, const b3Vector3& bvhAabbMax) +{ + m_useQuantization = useQuantizedAabbCompression; + + + // NodeArray triangleNodes; + + struct NodeTriangleCallback : public b3InternalTriangleIndexCallback + { + + NodeArray& m_triangleNodes; + + NodeTriangleCallback& operator=(NodeTriangleCallback& other) + { + m_triangleNodes.copyFromArray(other.m_triangleNodes); + return *this; + } + + NodeTriangleCallback(NodeArray& triangleNodes) + :m_triangleNodes(triangleNodes) + { + } + + virtual void internalProcessTriangleIndex(b3Vector3* triangle,int partId,int triangleIndex) + { + b3OptimizedBvhNode node; + b3Vector3 aabbMin,aabbMax; + aabbMin.setValue(b3Scalar(B3_LARGE_FLOAT),b3Scalar(B3_LARGE_FLOAT),b3Scalar(B3_LARGE_FLOAT)); + aabbMax.setValue(b3Scalar(-B3_LARGE_FLOAT),b3Scalar(-B3_LARGE_FLOAT),b3Scalar(-B3_LARGE_FLOAT)); + 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 b3InternalTriangleIndexCallback + { + QuantizedNodeArray& m_triangleNodes; + const b3QuantizedBvh* m_optimizedTree; // for quantization + + QuantizedNodeTriangleCallback& operator=(QuantizedNodeTriangleCallback& other) + { + m_triangleNodes.copyFromArray(other.m_triangleNodes); + m_optimizedTree = other.m_optimizedTree; + return *this; + } + + QuantizedNodeTriangleCallback(QuantizedNodeArray& triangleNodes,const b3QuantizedBvh* tree) + :m_triangleNodes(triangleNodes),m_optimizedTree(tree) + { + } + + virtual void internalProcessTriangleIndex(b3Vector3* triangle,int partId,int triangleIndex) + { + // The partId and triangle index must fit in the same (positive) integer + b3Assert(partId < (1<=0); + + b3QuantizedBvhNode node; + b3Vector3 aabbMin,aabbMax; + aabbMin.setValue(b3Scalar(B3_LARGE_FLOAT),b3Scalar(B3_LARGE_FLOAT),b3Scalar(B3_LARGE_FLOAT)); + aabbMax.setValue(b3Scalar(-B3_LARGE_FLOAT),b3Scalar(-B3_LARGE_FLOAT),b3Scalar(-B3_LARGE_FLOAT)); + aabbMin.setMin(triangle[0]); + aabbMax.setMax(triangle[0]); + aabbMin.setMin(triangle[1]); + aabbMax.setMax(triangle[1]); + aabbMin.setMin(triangle[2]); + aabbMax.setMax(triangle[2]); + + //PCK: add these checks for zero dimensions of aabb + const b3Scalar MIN_AABB_DIMENSION = b3Scalar(0.002); + const b3Scalar MIN_AABB_HALF_DIMENSION = b3Scalar(0.001); + if (aabbMax.getX() - aabbMin.getX() < MIN_AABB_DIMENSION) + { + aabbMax.setX(aabbMax.getX() + MIN_AABB_HALF_DIMENSION); + aabbMin.setX(aabbMin.getX() - MIN_AABB_HALF_DIMENSION); + } + if (aabbMax.getY() - aabbMin.getY() < MIN_AABB_DIMENSION) + { + aabbMax.setY(aabbMax.getY() + MIN_AABB_HALF_DIMENSION); + aabbMin.setY(aabbMin.getY() - MIN_AABB_HALF_DIMENSION); + } + if (aabbMax.getZ() - aabbMin.getZ() < MIN_AABB_DIMENSION) + { + aabbMax.setZ(aabbMax.getZ() + MIN_AABB_HALF_DIMENSION); + aabbMin.setZ(aabbMin.getZ() - MIN_AABB_HALF_DIMENSION); + } + + m_optimizedTree->quantize(&node.m_quantizedAabbMin[0],aabbMin,0); + m_optimizedTree->quantize(&node.m_quantizedAabbMax[0],aabbMax,1); + + node.m_escapeIndexOrTriangleIndex = (partId<<(31-MAX_NUM_PARTS_IN_BITS)) | 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); + + b3Vector3 aabbMin=b3MakeVector3(b3Scalar(-B3_LARGE_FLOAT),b3Scalar(-B3_LARGE_FLOAT),b3Scalar(-B3_LARGE_FLOAT)); + b3Vector3 aabbMax=b3MakeVector3(b3Scalar(B3_LARGE_FLOAT),b3Scalar(B3_LARGE_FLOAT),b3Scalar(B3_LARGE_FLOAT)); + + 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()) + { + b3BvhSubtreeInfo& 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(); + } + + //PCK: update the copy of the size + m_subtreeHeaderCount = m_SubtreeHeaders.size(); + + //PCK: clear m_quantizedLeafNodes and m_leafNodes, they are temporary + m_quantizedLeafNodes.clear(); + m_leafNodes.clear(); +} + + + + +void b3OptimizedBvh::refit(b3StridingMeshInterface* meshInterface,const b3Vector3& aabbMin,const b3Vector3& aabbMax) +{ + if (m_useQuantization) + { + + setQuantizationValues(aabbMin,aabbMax); + + updateBvhNodes(meshInterface,0,m_curNodeIndex,0); + + ///now update all subtree headers + + int i; + for (i=0;i m_bvhAabbMin.getX()); + b3Assert(aabbMin.getY() > m_bvhAabbMin.getY()); + b3Assert(aabbMin.getZ() > m_bvhAabbMin.getZ()); + + b3Assert(aabbMax.getX() < m_bvhAabbMax.getX()); + b3Assert(aabbMax.getY() < m_bvhAabbMax.getY()); + b3Assert(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]; + + quantize(&quantizedQueryAabbMin[0],aabbMin,0); + quantize(&quantizedQueryAabbMax[0],aabbMax,1); + + int i; + for (i=0;im_SubtreeHeaders.size();i++) + { + b3BvhSubtreeInfo& subtree = m_SubtreeHeaders[i]; + + //PCK: unsigned instead of bool + unsigned overlap = b3TestQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,subtree.m_quantizedAabbMin,subtree.m_quantizedAabbMax); + if (overlap != 0) + { + updateBvhNodes(meshInterface,subtree.m_rootNodeIndex,subtree.m_rootNodeIndex+subtree.m_subtreeSize,i); + + subtree.setAabbFromQuantizeNode(m_quantizedContiguousNodes[subtree.m_rootNodeIndex]); + } + } + +} + +void b3OptimizedBvh::updateBvhNodes(b3StridingMeshInterface* meshInterface,int firstNode,int endNode,int index) +{ + (void)index; + + b3Assert(m_useQuantization); + + int curNodeSubPart=-1; + + //get access info to trianglemesh data + const unsigned char *vertexbase = 0; + int numverts = 0; + PHY_ScalarType type = PHY_INTEGER; + int stride = 0; + const unsigned char *indexbase = 0; + int indexstride = 0; + int numfaces = 0; + PHY_ScalarType indicestype = PHY_INTEGER; + + b3Vector3 triangleVerts[3]; + b3Vector3 aabbMin,aabbMax; + const b3Vector3& meshScaling = meshInterface->getScaling(); + + int i; + for (i=endNode-1;i>=firstNode;i--) + { + + + b3QuantizedBvhNode& curNode = m_quantizedContiguousNodes[i]; + if (curNode.isLeafNode()) + { + //recalc aabb from triangle data + int nodeSubPart = curNode.getPartId(); + int nodeTriangleIndex = curNode.getTriangleIndex(); + if (nodeSubPart != curNodeSubPart) + { + if (curNodeSubPart >= 0) + meshInterface->unLockReadOnlyVertexBase(curNodeSubPart); + meshInterface->getLockedReadOnlyVertexIndexBase(&vertexbase,numverts, type,stride,&indexbase,indexstride,numfaces,indicestype,nodeSubPart); + + curNodeSubPart = nodeSubPart; + b3Assert(indicestype==PHY_INTEGER||indicestype==PHY_SHORT); + } + //triangles->getLockedReadOnlyVertexIndexBase(vertexBase,numVerts, + + unsigned int* gfxbase = (unsigned int*)(indexbase+nodeTriangleIndex*indexstride); + + + for (int j=2;j>=0;j--) + { + + int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j]; + if (type == PHY_FLOAT) + { + float* graphicsbase = (float*)(vertexbase+graphicsindex*stride); + triangleVerts[j] = b3MakeVector3( + graphicsbase[0]*meshScaling.getX(), + graphicsbase[1]*meshScaling.getY(), + graphicsbase[2]*meshScaling.getZ()); + } + else + { + double* graphicsbase = (double*)(vertexbase+graphicsindex*stride); + triangleVerts[j] = b3MakeVector3( b3Scalar(graphicsbase[0]*meshScaling.getX()), b3Scalar(graphicsbase[1]*meshScaling.getY()), b3Scalar(graphicsbase[2]*meshScaling.getZ())); + } + } + + + + aabbMin.setValue(b3Scalar(B3_LARGE_FLOAT),b3Scalar(B3_LARGE_FLOAT),b3Scalar(B3_LARGE_FLOAT)); + aabbMax.setValue(b3Scalar(-B3_LARGE_FLOAT),b3Scalar(-B3_LARGE_FLOAT),b3Scalar(-B3_LARGE_FLOAT)); + aabbMin.setMin(triangleVerts[0]); + aabbMax.setMax(triangleVerts[0]); + aabbMin.setMin(triangleVerts[1]); + aabbMax.setMax(triangleVerts[1]); + aabbMin.setMin(triangleVerts[2]); + aabbMax.setMax(triangleVerts[2]); + + quantize(&curNode.m_quantizedAabbMin[0],aabbMin,0); + quantize(&curNode.m_quantizedAabbMax[0],aabbMax,1); + + } else + { + //combine aabb from both children + + b3QuantizedBvhNode* leftChildNode = &m_quantizedContiguousNodes[i+1]; + + b3QuantizedBvhNode* 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]; + } + } + } + + } + + if (curNodeSubPart >= 0) + meshInterface->unLockReadOnlyVertexBase(curNodeSubPart); + + +} + +///deSerializeInPlace loads and initializes a BVH from a buffer in memory 'in place' +b3OptimizedBvh* b3OptimizedBvh::deSerializeInPlace(void *i_alignedDataBuffer, unsigned int i_dataBufferSize, bool i_swapEndian) +{ + b3QuantizedBvh* bvh = b3QuantizedBvh::deSerializeInPlace(i_alignedDataBuffer,i_dataBufferSize,i_swapEndian); + + //we don't add additional data so just do a static upcast + return static_cast(bvh); +} diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3OptimizedBvh.h b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3OptimizedBvh.h new file mode 100644 index 000000000000..0272ef83bfc6 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3OptimizedBvh.h @@ -0,0 +1,65 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org + +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. +*/ + +///Contains contributions from Disney Studio's + +#ifndef B3_OPTIMIZED_BVH_H +#define B3_OPTIMIZED_BVH_H + +#include "b3QuantizedBvh.h" + +class b3StridingMeshInterface; + + +///The b3OptimizedBvh extends the b3QuantizedBvh to create AABB tree for triangle meshes, through the b3StridingMeshInterface. +B3_ATTRIBUTE_ALIGNED16(class) b3OptimizedBvh : public b3QuantizedBvh +{ + +public: + B3_DECLARE_ALIGNED_ALLOCATOR(); + +protected: + +public: + + b3OptimizedBvh(); + + virtual ~b3OptimizedBvh(); + + void build(b3StridingMeshInterface* triangles,bool useQuantizedAabbCompression, const b3Vector3& bvhAabbMin, const b3Vector3& bvhAabbMax); + + void refit(b3StridingMeshInterface* triangles,const b3Vector3& aabbMin,const b3Vector3& aabbMax); + + void refitPartial(b3StridingMeshInterface* triangles,const b3Vector3& aabbMin, const b3Vector3& aabbMax); + + void updateBvhNodes(b3StridingMeshInterface* meshInterface,int firstNode,int endNode,int index); + + /// Data buffer MUST be 16 byte aligned + virtual bool serializeInPlace(void *o_alignedDataBuffer, unsigned i_dataBufferSize, bool i_swapEndian) const + { + return b3QuantizedBvh::serialize(o_alignedDataBuffer,i_dataBufferSize,i_swapEndian); + + } + + ///deSerializeInPlace loads and initializes a BVH from a buffer in memory 'in place' + static b3OptimizedBvh *deSerializeInPlace(void *i_alignedDataBuffer, unsigned int i_dataBufferSize, bool i_swapEndian); + + +}; + + +#endif //B3_OPTIMIZED_BVH_H + + diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3QuantizedBvh.cpp b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3QuantizedBvh.cpp new file mode 100644 index 000000000000..52027e111845 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3QuantizedBvh.cpp @@ -0,0 +1,1301 @@ +/* +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 "b3QuantizedBvh.h" + +#include "Bullet3Geometry/b3AabbUtil.h" + + +#define RAYAABB2 + +b3QuantizedBvh::b3QuantizedBvh() : + m_bulletVersion(B3_BULLET_VERSION), + m_useQuantization(false), + m_traversalMode(TRAVERSAL_STACKLESS_CACHE_FRIENDLY) + //m_traversalMode(TRAVERSAL_STACKLESS) + //m_traversalMode(TRAVERSAL_RECURSIVE) + ,m_subtreeHeaderCount(0) //PCK: add this line +{ + m_bvhAabbMin.setValue(-B3_INFINITY,-B3_INFINITY,-B3_INFINITY); + m_bvhAabbMax.setValue(B3_INFINITY,B3_INFINITY,B3_INFINITY); +} + + + + + +void b3QuantizedBvh::buildInternal() +{ + ///assumes that caller filled in the m_quantizedLeafNodes + m_useQuantization = true; + int numLeafNodes = 0; + + if (m_useQuantization) + { + //now we have an array of leafnodes in m_leafNodes + numLeafNodes = m_quantizedLeafNodes.size(); + + m_quantizedContiguousNodes.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()) + { + b3BvhSubtreeInfo& 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(); + } + + //PCK: update the copy of the size + m_subtreeHeaderCount = m_SubtreeHeaders.size(); + + //PCK: clear m_quantizedLeafNodes and m_leafNodes, they are temporary + m_quantizedLeafNodes.clear(); + m_leafNodes.clear(); +} + + + +///just for debugging, to visualize the individual patches/subtrees +#ifdef DEBUG_PATCH_COLORS +b3Vector3 color[4]= +{ + b3Vector3(1,0,0), + b3Vector3(0,1,0), + b3Vector3(0,0,1), + b3Vector3(0,1,1) +}; +#endif //DEBUG_PATCH_COLORS + + + +void b3QuantizedBvh::setQuantizationValues(const b3Vector3& bvhAabbMin,const b3Vector3& bvhAabbMax,b3Scalar quantizationMargin) +{ + //enlarge the AABB to avoid division by zero when initializing the quantization values + b3Vector3 clampValue =b3MakeVector3(quantizationMargin,quantizationMargin,quantizationMargin); + m_bvhAabbMin = bvhAabbMin - clampValue; + m_bvhAabbMax = bvhAabbMax + clampValue; + b3Vector3 aabbSize = m_bvhAabbMax - m_bvhAabbMin; + m_bvhQuantization = b3MakeVector3(b3Scalar(65533.0),b3Scalar(65533.0),b3Scalar(65533.0)) / aabbSize; + m_useQuantization = true; +} + + + + +b3QuantizedBvh::~b3QuantizedBvh() +{ +} + +#ifdef DEBUG_TREE_BUILDING +int gStackDepth = 0; +int gMaxStackDepth = 0; +#endif //DEBUG_TREE_BUILDING + +void b3QuantizedBvh::buildTree (int startIndex,int endIndex) +{ +#ifdef DEBUG_TREE_BUILDING + gStackDepth++; + if (gStackDepth > gMaxStackDepth) + gMaxStackDepth = gStackDepth; +#endif //DEBUG_TREE_BUILDING + + + int splitAxis, splitIndex, i; + int numIndices =endIndex-startIndex; + int curIndex = m_curNodeIndex; + + b3Assert(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; + + //set the min aabb to 'inf' or a max value, and set the max aabb to a -inf/minimum value. + //the aabb will be expanded during buildTree/mergeInternalNodeAabb with actual node values + setInternalNodeAabbMin(m_curNodeIndex,m_bvhAabbMax);//can't use b3Vector3(B3_INFINITY,B3_INFINITY,B3_INFINITY)) because of quantization + setInternalNodeAabbMax(m_curNodeIndex,m_bvhAabbMin);//can't use b3Vector3(-B3_INFINITY,-B3_INFINITY,-B3_INFINITY)) because of quantization + + + 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(b3QuantizedBvhNode); + const int treeSizeInBytes = escapeIndex * sizeQuantizedNode; + if (treeSizeInBytes > MAX_SUBTREE_SIZE_IN_BYTES) + { + updateSubtreeHeaders(leftChildNodexIndex,rightChildNodexIndex); + } + } else + { + + } + + setInternalNodeEscapeIndex(internalNodeIndex,escapeIndex); + +} + +void b3QuantizedBvh::updateSubtreeHeaders(int leftChildNodexIndex,int rightChildNodexIndex) +{ + b3Assert(m_useQuantization); + + b3QuantizedBvhNode& leftChildNode = m_quantizedContiguousNodes[leftChildNodexIndex]; + int leftSubTreeSize = leftChildNode.isLeafNode() ? 1 : leftChildNode.getEscapeIndex(); + int leftSubTreeSizeInBytes = leftSubTreeSize * static_cast(sizeof(b3QuantizedBvhNode)); + + b3QuantizedBvhNode& rightChildNode = m_quantizedContiguousNodes[rightChildNodexIndex]; + int rightSubTreeSize = rightChildNode.isLeafNode() ? 1 : rightChildNode.getEscapeIndex(); + int rightSubTreeSizeInBytes = rightSubTreeSize * static_cast(sizeof(b3QuantizedBvhNode)); + + if(leftSubTreeSizeInBytes <= MAX_SUBTREE_SIZE_IN_BYTES) + { + b3BvhSubtreeInfo& subtree = m_SubtreeHeaders.expand(); + subtree.setAabbFromQuantizeNode(leftChildNode); + subtree.m_rootNodeIndex = leftChildNodexIndex; + subtree.m_subtreeSize = leftSubTreeSize; + } + + if(rightSubTreeSizeInBytes <= MAX_SUBTREE_SIZE_IN_BYTES) + { + b3BvhSubtreeInfo& subtree = m_SubtreeHeaders.expand(); + subtree.setAabbFromQuantizeNode(rightChildNode); + subtree.m_rootNodeIndex = rightChildNodexIndex; + subtree.m_subtreeSize = rightSubTreeSize; + } + + //PCK: update the copy of the size + m_subtreeHeaderCount = m_SubtreeHeaders.size(); +} + + +int b3QuantizedBvh::sortAndCalcSplittingIndex(int startIndex,int endIndex,int splitAxis) +{ + int i; + int splitIndex =startIndex; + int numIndices = endIndex - startIndex; + b3Scalar splitValue; + + b3Vector3 means=b3MakeVector3(b3Scalar(0.),b3Scalar(0.),b3Scalar(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)); + (void)unbal; + b3Assert(!unbal); + + return splitIndex; +} + + +int b3QuantizedBvh::calcSplittingAxis(int startIndex,int endIndex) +{ + int i; + + b3Vector3 means=b3MakeVector3(b3Scalar(0.),b3Scalar(0.),b3Scalar(0.)); + b3Vector3 variance=b3MakeVector3(b3Scalar(0.),b3Scalar(0.),b3Scalar(0.)); + int numIndices = endIndex-startIndex; + + for (i=startIndex;im_aabbMinOrg,rootNode->m_aabbMaxOrg); + isLeafNode = rootNode->m_escapeIndex == -1; + + //PCK: unsigned instead of bool + if (isLeafNode && (aabbOverlap != 0)) + { + nodeCallback->processNode(rootNode->m_subPart,rootNode->m_triangleIndex); + } + + //PCK: unsigned instead of bool + if ((aabbOverlap != 0) || isLeafNode) + { + rootNode++; + curIndex++; + } else + { + escapeIndex = rootNode->m_escapeIndex; + rootNode += escapeIndex; + curIndex += escapeIndex; + } + } + if (b3s_maxIterations < walkIterations) + b3s_maxIterations = walkIterations; + +} + +/* +///this was the original recursive traversal, before we optimized towards stackless traversal +void b3QuantizedBvh::walkTree(b3OptimizedBvhNode* rootNode,b3NodeOverlapCallback* nodeCallback,const b3Vector3& aabbMin,const b3Vector3& 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 b3QuantizedBvh::walkRecursiveQuantizedTreeAgainstQueryAabb(const b3QuantizedBvhNode* currentNode,b3NodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const +{ + b3Assert(m_useQuantization); + + bool isLeafNode; + //PCK: unsigned instead of bool + unsigned aabbOverlap; + + //PCK: unsigned instead of bool + aabbOverlap = b3TestQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,currentNode->m_quantizedAabbMin,currentNode->m_quantizedAabbMax); + isLeafNode = currentNode->isLeafNode(); + + //PCK: unsigned instead of bool + if (aabbOverlap != 0) + { + if (isLeafNode) + { + nodeCallback->processNode(currentNode->getPartId(),currentNode->getTriangleIndex()); + } else + { + //process left and right children + const b3QuantizedBvhNode* leftChildNode = currentNode+1; + walkRecursiveQuantizedTreeAgainstQueryAabb(leftChildNode,nodeCallback,quantizedQueryAabbMin,quantizedQueryAabbMax); + + const b3QuantizedBvhNode* rightChildNode = leftChildNode->isLeafNode() ? leftChildNode+1:leftChildNode+leftChildNode->getEscapeIndex(); + walkRecursiveQuantizedTreeAgainstQueryAabb(rightChildNode,nodeCallback,quantizedQueryAabbMin,quantizedQueryAabbMax); + } + } +} + + + +void b3QuantizedBvh::walkStacklessTreeAgainstRay(b3NodeOverlapCallback* nodeCallback, const b3Vector3& raySource, const b3Vector3& rayTarget, const b3Vector3& aabbMin, const b3Vector3& aabbMax, int startNodeIndex,int endNodeIndex) const +{ + b3Assert(!m_useQuantization); + + const b3OptimizedBvhNode* rootNode = &m_contiguousNodes[0]; + int escapeIndex, curIndex = 0; + int walkIterations = 0; + bool isLeafNode; + //PCK: unsigned instead of bool + unsigned aabbOverlap=0; + unsigned rayBoxOverlap=0; + b3Scalar lambda_max = 1.0; + + /* Quick pruning by quantized box */ + b3Vector3 rayAabbMin = raySource; + b3Vector3 rayAabbMax = raySource; + rayAabbMin.setMin(rayTarget); + rayAabbMax.setMax(rayTarget); + + /* Add box cast extents to bounding box */ + rayAabbMin += aabbMin; + rayAabbMax += aabbMax; + +#ifdef RAYAABB2 + b3Vector3 rayDir = (rayTarget-raySource); + rayDir.normalize (); + lambda_max = rayDir.dot(rayTarget-raySource); + ///what about division by zero? --> just set rayDirection[i] to 1.0 + b3Vector3 rayDirectionInverse; + rayDirectionInverse[0] = rayDir[0] == b3Scalar(0.0) ? b3Scalar(B3_LARGE_FLOAT) : b3Scalar(1.0) / rayDir[0]; + rayDirectionInverse[1] = rayDir[1] == b3Scalar(0.0) ? b3Scalar(B3_LARGE_FLOAT) : b3Scalar(1.0) / rayDir[1]; + rayDirectionInverse[2] = rayDir[2] == b3Scalar(0.0) ? b3Scalar(B3_LARGE_FLOAT) : b3Scalar(1.0) / rayDir[2]; + unsigned int sign[3] = { rayDirectionInverse[0] < 0.0, rayDirectionInverse[1] < 0.0, rayDirectionInverse[2] < 0.0}; +#endif + + b3Vector3 bounds[2]; + + while (curIndex < m_curNodeIndex) + { + b3Scalar param = 1.0; + //catch bugs in tree data + b3Assert (walkIterations < m_curNodeIndex); + + walkIterations++; + + bounds[0] = rootNode->m_aabbMinOrg; + bounds[1] = rootNode->m_aabbMaxOrg; + /* Add box cast extents */ + bounds[0] -= aabbMax; + bounds[1] -= aabbMin; + + aabbOverlap = b3TestAabbAgainstAabb2(rayAabbMin,rayAabbMax,rootNode->m_aabbMinOrg,rootNode->m_aabbMaxOrg); + //perhaps profile if it is worth doing the aabbOverlap test first + +#ifdef RAYAABB2 + ///careful with this check: need to check division by zero (above) and fix the unQuantize method + ///thanks Joerg/hiker for the reproduction case! + ///http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=9&t=1858 + rayBoxOverlap = aabbOverlap ? b3RayAabb2 (raySource, rayDirectionInverse, sign, bounds, param, 0.0f, lambda_max) : false; + +#else + b3Vector3 normal; + rayBoxOverlap = b3RayAabb(raySource, rayTarget,bounds[0],bounds[1],param, normal); +#endif + + isLeafNode = rootNode->m_escapeIndex == -1; + + //PCK: unsigned instead of bool + if (isLeafNode && (rayBoxOverlap != 0)) + { + nodeCallback->processNode(rootNode->m_subPart,rootNode->m_triangleIndex); + } + + //PCK: unsigned instead of bool + if ((rayBoxOverlap != 0) || isLeafNode) + { + rootNode++; + curIndex++; + } else + { + escapeIndex = rootNode->m_escapeIndex; + rootNode += escapeIndex; + curIndex += escapeIndex; + } + } + if (b3s_maxIterations < walkIterations) + b3s_maxIterations = walkIterations; + +} + + + +void b3QuantizedBvh::walkStacklessQuantizedTreeAgainstRay(b3NodeOverlapCallback* nodeCallback, const b3Vector3& raySource, const b3Vector3& rayTarget, const b3Vector3& aabbMin, const b3Vector3& aabbMax, int startNodeIndex,int endNodeIndex) const +{ + b3Assert(m_useQuantization); + + int curIndex = startNodeIndex; + int walkIterations = 0; + int subTreeSize = endNodeIndex - startNodeIndex; + (void)subTreeSize; + + const b3QuantizedBvhNode* rootNode = &m_quantizedContiguousNodes[startNodeIndex]; + int escapeIndex; + + bool isLeafNode; + //PCK: unsigned instead of bool + unsigned boxBoxOverlap = 0; + unsigned rayBoxOverlap = 0; + + b3Scalar lambda_max = 1.0; + +#ifdef RAYAABB2 + b3Vector3 rayDirection = (rayTarget-raySource); + rayDirection.normalize (); + lambda_max = rayDirection.dot(rayTarget-raySource); + ///what about division by zero? --> just set rayDirection[i] to 1.0 + rayDirection[0] = rayDirection[0] == b3Scalar(0.0) ? b3Scalar(B3_LARGE_FLOAT) : b3Scalar(1.0) / rayDirection[0]; + rayDirection[1] = rayDirection[1] == b3Scalar(0.0) ? b3Scalar(B3_LARGE_FLOAT) : b3Scalar(1.0) / rayDirection[1]; + rayDirection[2] = rayDirection[2] == b3Scalar(0.0) ? b3Scalar(B3_LARGE_FLOAT) : b3Scalar(1.0) / rayDirection[2]; + unsigned int sign[3] = { rayDirection[0] < 0.0, rayDirection[1] < 0.0, rayDirection[2] < 0.0}; +#endif + + /* Quick pruning by quantized box */ + b3Vector3 rayAabbMin = raySource; + b3Vector3 rayAabbMax = raySource; + rayAabbMin.setMin(rayTarget); + rayAabbMax.setMax(rayTarget); + + /* Add box cast extents to bounding box */ + rayAabbMin += aabbMin; + rayAabbMax += aabbMax; + + unsigned short int quantizedQueryAabbMin[3]; + unsigned short int quantizedQueryAabbMax[3]; + quantizeWithClamp(quantizedQueryAabbMin,rayAabbMin,0); + quantizeWithClamp(quantizedQueryAabbMax,rayAabbMax,1); + + 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 b3IDebugDraw* debugDrawerPtr; + if (curIndex==drawPatch) + { + b3Vector3 aabbMin,aabbMax; + aabbMin = unQuantize(rootNode->m_quantizedAabbMin); + aabbMax = unQuantize(rootNode->m_quantizedAabbMax); + b3Vector3 color(1,0,0); + debugDrawerPtr->drawAabb(aabbMin,aabbMax,color); + } +#endif//VISUALLY_ANALYZE_BVH + + //catch bugs in tree data + b3Assert (walkIterations < subTreeSize); + + walkIterations++; + //PCK: unsigned instead of bool + // only interested if this is closer than any previous hit + b3Scalar param = 1.0; + rayBoxOverlap = 0; + boxBoxOverlap = b3TestQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,rootNode->m_quantizedAabbMin,rootNode->m_quantizedAabbMax); + isLeafNode = rootNode->isLeafNode(); + if (boxBoxOverlap) + { + b3Vector3 bounds[2]; + bounds[0] = unQuantize(rootNode->m_quantizedAabbMin); + bounds[1] = unQuantize(rootNode->m_quantizedAabbMax); + /* Add box cast extents */ + bounds[0] -= aabbMax; + bounds[1] -= aabbMin; +#if 0 + b3Vector3 normal; + bool ra2 = b3RayAabb2 (raySource, rayDirection, sign, bounds, param, 0.0, lambda_max); + bool ra = b3RayAabb (raySource, rayTarget, bounds[0], bounds[1], param, normal); + if (ra2 != ra) + { + printf("functions don't match\n"); + } +#endif +#ifdef RAYAABB2 + ///careful with this check: need to check division by zero (above) and fix the unQuantize method + ///thanks Joerg/hiker for the reproduction case! + ///http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=9&t=1858 + + //B3_PROFILE("b3RayAabb2"); + rayBoxOverlap = b3RayAabb2 (raySource, rayDirection, sign, bounds, param, 0.0f, lambda_max); + +#else + rayBoxOverlap = true;//b3RayAabb(raySource, rayTarget, bounds[0], bounds[1], param, normal); +#endif + } + + if (isLeafNode && rayBoxOverlap) + { + nodeCallback->processNode(rootNode->getPartId(),rootNode->getTriangleIndex()); + } + + //PCK: unsigned instead of bool + if ((rayBoxOverlap != 0) || isLeafNode) + { + rootNode++; + curIndex++; + } else + { + escapeIndex = rootNode->getEscapeIndex(); + rootNode += escapeIndex; + curIndex += escapeIndex; + } + } + if (b3s_maxIterations < walkIterations) + b3s_maxIterations = walkIterations; + +} + +void b3QuantizedBvh::walkStacklessQuantizedTree(b3NodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax,int startNodeIndex,int endNodeIndex) const +{ + b3Assert(m_useQuantization); + + int curIndex = startNodeIndex; + int walkIterations = 0; + int subTreeSize = endNodeIndex - startNodeIndex; + (void)subTreeSize; + + const b3QuantizedBvhNode* rootNode = &m_quantizedContiguousNodes[startNodeIndex]; + int escapeIndex; + + bool isLeafNode; + //PCK: unsigned instead of bool + unsigned aabbOverlap; + + 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 b3IDebugDraw* debugDrawerPtr; + if (curIndex==drawPatch) + { + b3Vector3 aabbMin,aabbMax; + aabbMin = unQuantize(rootNode->m_quantizedAabbMin); + aabbMax = unQuantize(rootNode->m_quantizedAabbMax); + b3Vector3 color(1,0,0); + debugDrawerPtr->drawAabb(aabbMin,aabbMax,color); + } +#endif//VISUALLY_ANALYZE_BVH + + //catch bugs in tree data + b3Assert (walkIterations < subTreeSize); + + walkIterations++; + //PCK: unsigned instead of bool + aabbOverlap = b3TestQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,rootNode->m_quantizedAabbMin,rootNode->m_quantizedAabbMax); + isLeafNode = rootNode->isLeafNode(); + + if (isLeafNode && aabbOverlap) + { + nodeCallback->processNode(rootNode->getPartId(),rootNode->getTriangleIndex()); + } + + //PCK: unsigned instead of bool + if ((aabbOverlap != 0) || isLeafNode) + { + rootNode++; + curIndex++; + } else + { + escapeIndex = rootNode->getEscapeIndex(); + rootNode += escapeIndex; + curIndex += escapeIndex; + } + } + if (b3s_maxIterations < walkIterations) + b3s_maxIterations = walkIterations; + +} + +//This traversal can be called from Playstation 3 SPU +void b3QuantizedBvh::walkStacklessQuantizedTreeCacheFriendly(b3NodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const +{ + b3Assert(m_useQuantization); + + int i; + + + for (i=0;im_SubtreeHeaders.size();i++) + { + const b3BvhSubtreeInfo& subtree = m_SubtreeHeaders[i]; + + //PCK: unsigned instead of bool + unsigned overlap = b3TestQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,subtree.m_quantizedAabbMin,subtree.m_quantizedAabbMax); + if (overlap != 0) + { + walkStacklessQuantizedTree(nodeCallback,quantizedQueryAabbMin,quantizedQueryAabbMax, + subtree.m_rootNodeIndex, + subtree.m_rootNodeIndex+subtree.m_subtreeSize); + } + } +} + + +void b3QuantizedBvh::reportRayOverlappingNodex (b3NodeOverlapCallback* nodeCallback, const b3Vector3& raySource, const b3Vector3& rayTarget) const +{ + reportBoxCastOverlappingNodex(nodeCallback,raySource,rayTarget,b3MakeVector3(0,0,0),b3MakeVector3(0,0,0)); +} + + +void b3QuantizedBvh::reportBoxCastOverlappingNodex(b3NodeOverlapCallback* nodeCallback, const b3Vector3& raySource, const b3Vector3& rayTarget, const b3Vector3& aabbMin,const b3Vector3& aabbMax) const +{ + //always use stackless + + if (m_useQuantization) + { + walkStacklessQuantizedTreeAgainstRay(nodeCallback, raySource, rayTarget, aabbMin, aabbMax, 0, m_curNodeIndex); + } + else + { + walkStacklessTreeAgainstRay(nodeCallback, raySource, rayTarget, aabbMin, aabbMax, 0, m_curNodeIndex); + } + /* + { + //recursive traversal + b3Vector3 qaabbMin = raySource; + b3Vector3 qaabbMax = raySource; + qaabbMin.setMin(rayTarget); + qaabbMax.setMax(rayTarget); + qaabbMin += aabbMin; + qaabbMax += aabbMax; + reportAabbOverlappingNodex(nodeCallback,qaabbMin,qaabbMax); + } + */ + +} + + +void b3QuantizedBvh::swapLeafNodes(int i,int splitIndex) +{ + if (m_useQuantization) + { + b3QuantizedBvhNode tmp = m_quantizedLeafNodes[i]; + m_quantizedLeafNodes[i] = m_quantizedLeafNodes[splitIndex]; + m_quantizedLeafNodes[splitIndex] = tmp; + } else + { + b3OptimizedBvhNode tmp = m_leafNodes[i]; + m_leafNodes[i] = m_leafNodes[splitIndex]; + m_leafNodes[splitIndex] = tmp; + } +} + +void b3QuantizedBvh::assignInternalNodeFromLeafNode(int internalNode,int leafNodeIndex) +{ + if (m_useQuantization) + { + m_quantizedContiguousNodes[internalNode] = m_quantizedLeafNodes[leafNodeIndex]; + } else + { + m_contiguousNodes[internalNode] = m_leafNodes[leafNodeIndex]; + } +} + +//PCK: include +#include + +#if 0 +//PCK: consts +static const unsigned BVH_ALIGNMENT = 16; +static const unsigned BVH_ALIGNMENT_MASK = BVH_ALIGNMENT-1; + +static const unsigned BVH_ALIGNMENT_BLOCKS = 2; +#endif + + +unsigned int b3QuantizedBvh::getAlignmentSerializationPadding() +{ + // I changed this to 0 since the extra padding is not needed or used. + return 0;//BVH_ALIGNMENT_BLOCKS * BVH_ALIGNMENT; +} + +unsigned b3QuantizedBvh::calculateSerializeBufferSize() const +{ + unsigned baseSize = sizeof(b3QuantizedBvh) + getAlignmentSerializationPadding(); + baseSize += sizeof(b3BvhSubtreeInfo) * m_subtreeHeaderCount; + if (m_useQuantization) + { + return baseSize + m_curNodeIndex * sizeof(b3QuantizedBvhNode); + } + return baseSize + m_curNodeIndex * sizeof(b3OptimizedBvhNode); +} + +bool b3QuantizedBvh::serialize(void *o_alignedDataBuffer, unsigned /*i_dataBufferSize */, bool i_swapEndian) const +{ + b3Assert(m_subtreeHeaderCount == m_SubtreeHeaders.size()); + m_subtreeHeaderCount = m_SubtreeHeaders.size(); + +/* if (i_dataBufferSize < calculateSerializeBufferSize() || o_alignedDataBuffer == NULL || (((unsigned)o_alignedDataBuffer & BVH_ALIGNMENT_MASK) != 0)) + { + ///check alignedment for buffer? + b3Assert(0); + return false; + } +*/ + + b3QuantizedBvh *targetBvh = (b3QuantizedBvh *)o_alignedDataBuffer; + + // construct the class so the virtual function table, etc will be set up + // Also, m_leafNodes and m_quantizedLeafNodes will be initialized to default values by the constructor + new (targetBvh) b3QuantizedBvh; + + if (i_swapEndian) + { + targetBvh->m_curNodeIndex = static_cast(b3SwapEndian(m_curNodeIndex)); + + + b3SwapVector3Endian(m_bvhAabbMin,targetBvh->m_bvhAabbMin); + b3SwapVector3Endian(m_bvhAabbMax,targetBvh->m_bvhAabbMax); + b3SwapVector3Endian(m_bvhQuantization,targetBvh->m_bvhQuantization); + + targetBvh->m_traversalMode = (b3TraversalMode)b3SwapEndian(m_traversalMode); + targetBvh->m_subtreeHeaderCount = static_cast(b3SwapEndian(m_subtreeHeaderCount)); + } + else + { + targetBvh->m_curNodeIndex = m_curNodeIndex; + targetBvh->m_bvhAabbMin = m_bvhAabbMin; + targetBvh->m_bvhAabbMax = m_bvhAabbMax; + targetBvh->m_bvhQuantization = m_bvhQuantization; + targetBvh->m_traversalMode = m_traversalMode; + targetBvh->m_subtreeHeaderCount = m_subtreeHeaderCount; + } + + targetBvh->m_useQuantization = m_useQuantization; + + unsigned char *nodeData = (unsigned char *)targetBvh; + nodeData += sizeof(b3QuantizedBvh); + + unsigned sizeToAdd = 0;//(BVH_ALIGNMENT-((unsigned)nodeData & BVH_ALIGNMENT_MASK))&BVH_ALIGNMENT_MASK; + nodeData += sizeToAdd; + + int nodeCount = m_curNodeIndex; + + if (m_useQuantization) + { + targetBvh->m_quantizedContiguousNodes.initializeFromBuffer(nodeData, nodeCount, nodeCount); + + if (i_swapEndian) + { + for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++) + { + targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0] = b3SwapEndian(m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0]); + targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[1] = b3SwapEndian(m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[1]); + targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[2] = b3SwapEndian(m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[2]); + + targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0] = b3SwapEndian(m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0]); + targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[1] = b3SwapEndian(m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[1]); + targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[2] = b3SwapEndian(m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[2]); + + targetBvh->m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex = static_cast(b3SwapEndian(m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex)); + } + } + else + { + for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++) + { + + targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0] = m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0]; + targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[1] = m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[1]; + targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[2] = m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[2]; + + targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0] = m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0]; + targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[1] = m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[1]; + targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[2] = m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[2]; + + targetBvh->m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex = m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex; + + + } + } + nodeData += sizeof(b3QuantizedBvhNode) * nodeCount; + + // this clears the pointer in the member variable it doesn't really do anything to the data + // it does call the destructor on the contained objects, but they are all classes with no destructor defined + // so the memory (which is not freed) is left alone + targetBvh->m_quantizedContiguousNodes.initializeFromBuffer(NULL, 0, 0); + } + else + { + targetBvh->m_contiguousNodes.initializeFromBuffer(nodeData, nodeCount, nodeCount); + + if (i_swapEndian) + { + for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++) + { + b3SwapVector3Endian(m_contiguousNodes[nodeIndex].m_aabbMinOrg, targetBvh->m_contiguousNodes[nodeIndex].m_aabbMinOrg); + b3SwapVector3Endian(m_contiguousNodes[nodeIndex].m_aabbMaxOrg, targetBvh->m_contiguousNodes[nodeIndex].m_aabbMaxOrg); + + targetBvh->m_contiguousNodes[nodeIndex].m_escapeIndex = static_cast(b3SwapEndian(m_contiguousNodes[nodeIndex].m_escapeIndex)); + targetBvh->m_contiguousNodes[nodeIndex].m_subPart = static_cast(b3SwapEndian(m_contiguousNodes[nodeIndex].m_subPart)); + targetBvh->m_contiguousNodes[nodeIndex].m_triangleIndex = static_cast(b3SwapEndian(m_contiguousNodes[nodeIndex].m_triangleIndex)); + } + } + else + { + for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++) + { + targetBvh->m_contiguousNodes[nodeIndex].m_aabbMinOrg = m_contiguousNodes[nodeIndex].m_aabbMinOrg; + targetBvh->m_contiguousNodes[nodeIndex].m_aabbMaxOrg = m_contiguousNodes[nodeIndex].m_aabbMaxOrg; + + targetBvh->m_contiguousNodes[nodeIndex].m_escapeIndex = m_contiguousNodes[nodeIndex].m_escapeIndex; + targetBvh->m_contiguousNodes[nodeIndex].m_subPart = m_contiguousNodes[nodeIndex].m_subPart; + targetBvh->m_contiguousNodes[nodeIndex].m_triangleIndex = m_contiguousNodes[nodeIndex].m_triangleIndex; + } + } + nodeData += sizeof(b3OptimizedBvhNode) * nodeCount; + + // this clears the pointer in the member variable it doesn't really do anything to the data + // it does call the destructor on the contained objects, but they are all classes with no destructor defined + // so the memory (which is not freed) is left alone + targetBvh->m_contiguousNodes.initializeFromBuffer(NULL, 0, 0); + } + + sizeToAdd = 0;//(BVH_ALIGNMENT-((unsigned)nodeData & BVH_ALIGNMENT_MASK))&BVH_ALIGNMENT_MASK; + nodeData += sizeToAdd; + + // Now serialize the subtree headers + targetBvh->m_SubtreeHeaders.initializeFromBuffer(nodeData, m_subtreeHeaderCount, m_subtreeHeaderCount); + if (i_swapEndian) + { + for (int i = 0; i < m_subtreeHeaderCount; i++) + { + targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMin[0] = b3SwapEndian(m_SubtreeHeaders[i].m_quantizedAabbMin[0]); + targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMin[1] = b3SwapEndian(m_SubtreeHeaders[i].m_quantizedAabbMin[1]); + targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMin[2] = b3SwapEndian(m_SubtreeHeaders[i].m_quantizedAabbMin[2]); + + targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMax[0] = b3SwapEndian(m_SubtreeHeaders[i].m_quantizedAabbMax[0]); + targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMax[1] = b3SwapEndian(m_SubtreeHeaders[i].m_quantizedAabbMax[1]); + targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMax[2] = b3SwapEndian(m_SubtreeHeaders[i].m_quantizedAabbMax[2]); + + targetBvh->m_SubtreeHeaders[i].m_rootNodeIndex = static_cast(b3SwapEndian(m_SubtreeHeaders[i].m_rootNodeIndex)); + targetBvh->m_SubtreeHeaders[i].m_subtreeSize = static_cast(b3SwapEndian(m_SubtreeHeaders[i].m_subtreeSize)); + } + } + else + { + for (int i = 0; i < m_subtreeHeaderCount; i++) + { + targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMin[0] = (m_SubtreeHeaders[i].m_quantizedAabbMin[0]); + targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMin[1] = (m_SubtreeHeaders[i].m_quantizedAabbMin[1]); + targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMin[2] = (m_SubtreeHeaders[i].m_quantizedAabbMin[2]); + + targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMax[0] = (m_SubtreeHeaders[i].m_quantizedAabbMax[0]); + targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMax[1] = (m_SubtreeHeaders[i].m_quantizedAabbMax[1]); + targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMax[2] = (m_SubtreeHeaders[i].m_quantizedAabbMax[2]); + + targetBvh->m_SubtreeHeaders[i].m_rootNodeIndex = (m_SubtreeHeaders[i].m_rootNodeIndex); + targetBvh->m_SubtreeHeaders[i].m_subtreeSize = (m_SubtreeHeaders[i].m_subtreeSize); + + // need to clear padding in destination buffer + targetBvh->m_SubtreeHeaders[i].m_padding[0] = 0; + targetBvh->m_SubtreeHeaders[i].m_padding[1] = 0; + targetBvh->m_SubtreeHeaders[i].m_padding[2] = 0; + } + } + nodeData += sizeof(b3BvhSubtreeInfo) * m_subtreeHeaderCount; + + // this clears the pointer in the member variable it doesn't really do anything to the data + // it does call the destructor on the contained objects, but they are all classes with no destructor defined + // so the memory (which is not freed) is left alone + targetBvh->m_SubtreeHeaders.initializeFromBuffer(NULL, 0, 0); + + // this wipes the virtual function table pointer at the start of the buffer for the class + *((void**)o_alignedDataBuffer) = NULL; + + return true; +} + +b3QuantizedBvh *b3QuantizedBvh::deSerializeInPlace(void *i_alignedDataBuffer, unsigned int i_dataBufferSize, bool i_swapEndian) +{ + + if (i_alignedDataBuffer == NULL)// || (((unsigned)i_alignedDataBuffer & BVH_ALIGNMENT_MASK) != 0)) + { + return NULL; + } + b3QuantizedBvh *bvh = (b3QuantizedBvh *)i_alignedDataBuffer; + + if (i_swapEndian) + { + bvh->m_curNodeIndex = static_cast(b3SwapEndian(bvh->m_curNodeIndex)); + + b3UnSwapVector3Endian(bvh->m_bvhAabbMin); + b3UnSwapVector3Endian(bvh->m_bvhAabbMax); + b3UnSwapVector3Endian(bvh->m_bvhQuantization); + + bvh->m_traversalMode = (b3TraversalMode)b3SwapEndian(bvh->m_traversalMode); + bvh->m_subtreeHeaderCount = static_cast(b3SwapEndian(bvh->m_subtreeHeaderCount)); + } + + unsigned int calculatedBufSize = bvh->calculateSerializeBufferSize(); + b3Assert(calculatedBufSize <= i_dataBufferSize); + + if (calculatedBufSize > i_dataBufferSize) + { + return NULL; + } + + unsigned char *nodeData = (unsigned char *)bvh; + nodeData += sizeof(b3QuantizedBvh); + + unsigned sizeToAdd = 0;//(BVH_ALIGNMENT-((unsigned)nodeData & BVH_ALIGNMENT_MASK))&BVH_ALIGNMENT_MASK; + nodeData += sizeToAdd; + + int nodeCount = bvh->m_curNodeIndex; + + // Must call placement new to fill in virtual function table, etc, but we don't want to overwrite most data, so call a special version of the constructor + // Also, m_leafNodes and m_quantizedLeafNodes will be initialized to default values by the constructor + new (bvh) b3QuantizedBvh(*bvh, false); + + if (bvh->m_useQuantization) + { + bvh->m_quantizedContiguousNodes.initializeFromBuffer(nodeData, nodeCount, nodeCount); + + if (i_swapEndian) + { + for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++) + { + bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0] = b3SwapEndian(bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0]); + bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[1] = b3SwapEndian(bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[1]); + bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[2] = b3SwapEndian(bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[2]); + + bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0] = b3SwapEndian(bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0]); + bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[1] = b3SwapEndian(bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[1]); + bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[2] = b3SwapEndian(bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[2]); + + bvh->m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex = static_cast(b3SwapEndian(bvh->m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex)); + } + } + nodeData += sizeof(b3QuantizedBvhNode) * nodeCount; + } + else + { + bvh->m_contiguousNodes.initializeFromBuffer(nodeData, nodeCount, nodeCount); + + if (i_swapEndian) + { + for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++) + { + b3UnSwapVector3Endian(bvh->m_contiguousNodes[nodeIndex].m_aabbMinOrg); + b3UnSwapVector3Endian(bvh->m_contiguousNodes[nodeIndex].m_aabbMaxOrg); + + bvh->m_contiguousNodes[nodeIndex].m_escapeIndex = static_cast(b3SwapEndian(bvh->m_contiguousNodes[nodeIndex].m_escapeIndex)); + bvh->m_contiguousNodes[nodeIndex].m_subPart = static_cast(b3SwapEndian(bvh->m_contiguousNodes[nodeIndex].m_subPart)); + bvh->m_contiguousNodes[nodeIndex].m_triangleIndex = static_cast(b3SwapEndian(bvh->m_contiguousNodes[nodeIndex].m_triangleIndex)); + } + } + nodeData += sizeof(b3OptimizedBvhNode) * nodeCount; + } + + sizeToAdd = 0;//(BVH_ALIGNMENT-((unsigned)nodeData & BVH_ALIGNMENT_MASK))&BVH_ALIGNMENT_MASK; + nodeData += sizeToAdd; + + // Now serialize the subtree headers + bvh->m_SubtreeHeaders.initializeFromBuffer(nodeData, bvh->m_subtreeHeaderCount, bvh->m_subtreeHeaderCount); + if (i_swapEndian) + { + for (int i = 0; i < bvh->m_subtreeHeaderCount; i++) + { + bvh->m_SubtreeHeaders[i].m_quantizedAabbMin[0] = b3SwapEndian(bvh->m_SubtreeHeaders[i].m_quantizedAabbMin[0]); + bvh->m_SubtreeHeaders[i].m_quantizedAabbMin[1] = b3SwapEndian(bvh->m_SubtreeHeaders[i].m_quantizedAabbMin[1]); + bvh->m_SubtreeHeaders[i].m_quantizedAabbMin[2] = b3SwapEndian(bvh->m_SubtreeHeaders[i].m_quantizedAabbMin[2]); + + bvh->m_SubtreeHeaders[i].m_quantizedAabbMax[0] = b3SwapEndian(bvh->m_SubtreeHeaders[i].m_quantizedAabbMax[0]); + bvh->m_SubtreeHeaders[i].m_quantizedAabbMax[1] = b3SwapEndian(bvh->m_SubtreeHeaders[i].m_quantizedAabbMax[1]); + bvh->m_SubtreeHeaders[i].m_quantizedAabbMax[2] = b3SwapEndian(bvh->m_SubtreeHeaders[i].m_quantizedAabbMax[2]); + + bvh->m_SubtreeHeaders[i].m_rootNodeIndex = static_cast(b3SwapEndian(bvh->m_SubtreeHeaders[i].m_rootNodeIndex)); + bvh->m_SubtreeHeaders[i].m_subtreeSize = static_cast(b3SwapEndian(bvh->m_SubtreeHeaders[i].m_subtreeSize)); + } + } + + return bvh; +} + +// Constructor that prevents b3Vector3's default constructor from being called +b3QuantizedBvh::b3QuantizedBvh(b3QuantizedBvh &self, bool /* ownsMemory */) : +m_bvhAabbMin(self.m_bvhAabbMin), +m_bvhAabbMax(self.m_bvhAabbMax), +m_bvhQuantization(self.m_bvhQuantization), +m_bulletVersion(B3_BULLET_VERSION) +{ + +} + +void b3QuantizedBvh::deSerializeFloat(struct b3QuantizedBvhFloatData& quantizedBvhFloatData) +{ + m_bvhAabbMax.deSerializeFloat(quantizedBvhFloatData.m_bvhAabbMax); + m_bvhAabbMin.deSerializeFloat(quantizedBvhFloatData.m_bvhAabbMin); + m_bvhQuantization.deSerializeFloat(quantizedBvhFloatData.m_bvhQuantization); + + m_curNodeIndex = quantizedBvhFloatData.m_curNodeIndex; + m_useQuantization = quantizedBvhFloatData.m_useQuantization!=0; + + { + int numElem = quantizedBvhFloatData.m_numContiguousLeafNodes; + m_contiguousNodes.resize(numElem); + + if (numElem) + { + b3OptimizedBvhNodeFloatData* memPtr = quantizedBvhFloatData.m_contiguousNodesPtr; + + for (int i=0;im_aabbMaxOrg); + m_contiguousNodes[i].m_aabbMinOrg.deSerializeFloat(memPtr->m_aabbMinOrg); + m_contiguousNodes[i].m_escapeIndex = memPtr->m_escapeIndex; + m_contiguousNodes[i].m_subPart = memPtr->m_subPart; + m_contiguousNodes[i].m_triangleIndex = memPtr->m_triangleIndex; + } + } + } + + { + int numElem = quantizedBvhFloatData.m_numQuantizedContiguousNodes; + m_quantizedContiguousNodes.resize(numElem); + + if (numElem) + { + b3QuantizedBvhNodeData* memPtr = quantizedBvhFloatData.m_quantizedContiguousNodesPtr; + for (int i=0;im_escapeIndexOrTriangleIndex; + m_quantizedContiguousNodes[i].m_quantizedAabbMax[0] = memPtr->m_quantizedAabbMax[0]; + m_quantizedContiguousNodes[i].m_quantizedAabbMax[1] = memPtr->m_quantizedAabbMax[1]; + m_quantizedContiguousNodes[i].m_quantizedAabbMax[2] = memPtr->m_quantizedAabbMax[2]; + m_quantizedContiguousNodes[i].m_quantizedAabbMin[0] = memPtr->m_quantizedAabbMin[0]; + m_quantizedContiguousNodes[i].m_quantizedAabbMin[1] = memPtr->m_quantizedAabbMin[1]; + m_quantizedContiguousNodes[i].m_quantizedAabbMin[2] = memPtr->m_quantizedAabbMin[2]; + } + } + } + + m_traversalMode = b3TraversalMode(quantizedBvhFloatData.m_traversalMode); + + { + int numElem = quantizedBvhFloatData.m_numSubtreeHeaders; + m_SubtreeHeaders.resize(numElem); + if (numElem) + { + b3BvhSubtreeInfoData* memPtr = quantizedBvhFloatData.m_subTreeInfoPtr; + for (int i=0;im_quantizedAabbMax[0] ; + m_SubtreeHeaders[i].m_quantizedAabbMax[1] = memPtr->m_quantizedAabbMax[1]; + m_SubtreeHeaders[i].m_quantizedAabbMax[2] = memPtr->m_quantizedAabbMax[2]; + m_SubtreeHeaders[i].m_quantizedAabbMin[0] = memPtr->m_quantizedAabbMin[0]; + m_SubtreeHeaders[i].m_quantizedAabbMin[1] = memPtr->m_quantizedAabbMin[1]; + m_SubtreeHeaders[i].m_quantizedAabbMin[2] = memPtr->m_quantizedAabbMin[2]; + m_SubtreeHeaders[i].m_rootNodeIndex = memPtr->m_rootNodeIndex; + m_SubtreeHeaders[i].m_subtreeSize = memPtr->m_subtreeSize; + } + } + } +} + +void b3QuantizedBvh::deSerializeDouble(struct b3QuantizedBvhDoubleData& quantizedBvhDoubleData) +{ + m_bvhAabbMax.deSerializeDouble(quantizedBvhDoubleData.m_bvhAabbMax); + m_bvhAabbMin.deSerializeDouble(quantizedBvhDoubleData.m_bvhAabbMin); + m_bvhQuantization.deSerializeDouble(quantizedBvhDoubleData.m_bvhQuantization); + + m_curNodeIndex = quantizedBvhDoubleData.m_curNodeIndex; + m_useQuantization = quantizedBvhDoubleData.m_useQuantization!=0; + + { + int numElem = quantizedBvhDoubleData.m_numContiguousLeafNodes; + m_contiguousNodes.resize(numElem); + + if (numElem) + { + b3OptimizedBvhNodeDoubleData* memPtr = quantizedBvhDoubleData.m_contiguousNodesPtr; + + for (int i=0;im_aabbMaxOrg); + m_contiguousNodes[i].m_aabbMinOrg.deSerializeDouble(memPtr->m_aabbMinOrg); + m_contiguousNodes[i].m_escapeIndex = memPtr->m_escapeIndex; + m_contiguousNodes[i].m_subPart = memPtr->m_subPart; + m_contiguousNodes[i].m_triangleIndex = memPtr->m_triangleIndex; + } + } + } + + { + int numElem = quantizedBvhDoubleData.m_numQuantizedContiguousNodes; + m_quantizedContiguousNodes.resize(numElem); + + if (numElem) + { + b3QuantizedBvhNodeData* memPtr = quantizedBvhDoubleData.m_quantizedContiguousNodesPtr; + for (int i=0;im_escapeIndexOrTriangleIndex; + m_quantizedContiguousNodes[i].m_quantizedAabbMax[0] = memPtr->m_quantizedAabbMax[0]; + m_quantizedContiguousNodes[i].m_quantizedAabbMax[1] = memPtr->m_quantizedAabbMax[1]; + m_quantizedContiguousNodes[i].m_quantizedAabbMax[2] = memPtr->m_quantizedAabbMax[2]; + m_quantizedContiguousNodes[i].m_quantizedAabbMin[0] = memPtr->m_quantizedAabbMin[0]; + m_quantizedContiguousNodes[i].m_quantizedAabbMin[1] = memPtr->m_quantizedAabbMin[1]; + m_quantizedContiguousNodes[i].m_quantizedAabbMin[2] = memPtr->m_quantizedAabbMin[2]; + } + } + } + + m_traversalMode = b3TraversalMode(quantizedBvhDoubleData.m_traversalMode); + + { + int numElem = quantizedBvhDoubleData.m_numSubtreeHeaders; + m_SubtreeHeaders.resize(numElem); + if (numElem) + { + b3BvhSubtreeInfoData* memPtr = quantizedBvhDoubleData.m_subTreeInfoPtr; + for (int i=0;im_quantizedAabbMax[0] ; + m_SubtreeHeaders[i].m_quantizedAabbMax[1] = memPtr->m_quantizedAabbMax[1]; + m_SubtreeHeaders[i].m_quantizedAabbMax[2] = memPtr->m_quantizedAabbMax[2]; + m_SubtreeHeaders[i].m_quantizedAabbMin[0] = memPtr->m_quantizedAabbMin[0]; + m_SubtreeHeaders[i].m_quantizedAabbMin[1] = memPtr->m_quantizedAabbMin[1]; + m_SubtreeHeaders[i].m_quantizedAabbMin[2] = memPtr->m_quantizedAabbMin[2]; + m_SubtreeHeaders[i].m_rootNodeIndex = memPtr->m_rootNodeIndex; + m_SubtreeHeaders[i].m_subtreeSize = memPtr->m_subtreeSize; + } + } + } + +} + + + +///fills the dataBuffer and returns the struct name (and 0 on failure) +const char* b3QuantizedBvh::serialize(void* dataBuffer, b3Serializer* serializer) const +{ + b3Assert(0); + return 0; +} + + + + + diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3QuantizedBvh.h b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3QuantizedBvh.h new file mode 100644 index 000000000000..63c523c7584d --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3QuantizedBvh.h @@ -0,0 +1,556 @@ +/* +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 B3_QUANTIZED_BVH_H +#define B3_QUANTIZED_BVH_H + +class b3Serializer; + +//#define DEBUG_CHECK_DEQUANTIZATION 1 +#ifdef DEBUG_CHECK_DEQUANTIZATION +#ifdef __SPU__ +#define printf spu_printf +#endif //__SPU__ + +#include +#include +#endif //DEBUG_CHECK_DEQUANTIZATION + +#include "Bullet3Common/b3Vector3.h" +#include "Bullet3Common/b3AlignedAllocator.h" + +#ifdef B3_USE_DOUBLE_PRECISION +#define b3QuantizedBvhData b3QuantizedBvhDoubleData +#define b3OptimizedBvhNodeData b3OptimizedBvhNodeDoubleData +#define b3QuantizedBvhDataName "b3QuantizedBvhDoubleData" +#else +#define b3QuantizedBvhData b3QuantizedBvhFloatData +#define b3OptimizedBvhNodeData b3OptimizedBvhNodeFloatData +#define b3QuantizedBvhDataName "b3QuantizedBvhFloatData" +#endif + +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3QuantizedBvhNodeData.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3BvhSubtreeInfoData.h" + + + +//http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrf__m128.asp + + +//Note: currently we have 16 bytes per quantized node +#define MAX_SUBTREE_SIZE_IN_BYTES 2048 + +// 10 gives the potential for 1024 parts, with at most 2^21 (2097152) (minus one +// actually) triangles each (since the sign bit is reserved +#define MAX_NUM_PARTS_IN_BITS 10 + +///b3QuantizedBvhNode 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). +B3_ATTRIBUTE_ALIGNED16 (struct) b3QuantizedBvhNode : public b3QuantizedBvhNodeData +{ + B3_DECLARE_ALIGNED_ALLOCATOR(); + + bool isLeafNode() const + { + //skipindex is negative (internal node), triangleindex >=0 (leafnode) + return (m_escapeIndexOrTriangleIndex >= 0); + } + int getEscapeIndex() const + { + b3Assert(!isLeafNode()); + return -m_escapeIndexOrTriangleIndex; + } + int getTriangleIndex() const + { + b3Assert(isLeafNode()); + unsigned int x=0; + unsigned int y = (~(x&0))<<(31-MAX_NUM_PARTS_IN_BITS); + // Get only the lower bits where the triangle index is stored + return (m_escapeIndexOrTriangleIndex&~(y)); + } + int getPartId() const + { + b3Assert(isLeafNode()); + // Get only the highest bits where the part index is stored + return (m_escapeIndexOrTriangleIndex>>(31-MAX_NUM_PARTS_IN_BITS)); + } +} +; + +/// b3OptimizedBvhNode contains both internal and leaf node information. +/// Total node size is 44 bytes / node. You can use the compressed version of 16 bytes. +B3_ATTRIBUTE_ALIGNED16 (struct) b3OptimizedBvhNode +{ + B3_DECLARE_ALIGNED_ALLOCATOR(); + + //32 bytes + b3Vector3 m_aabbMinOrg; + b3Vector3 m_aabbMaxOrg; + + //4 + int m_escapeIndex; + + //8 + //for child nodes + int m_subPart; + int m_triangleIndex; + +//pad the size to 64 bytes + char m_padding[20]; +}; + + +///b3BvhSubtreeInfo provides info to gather a subtree of limited size +B3_ATTRIBUTE_ALIGNED16(class) b3BvhSubtreeInfo : public b3BvhSubtreeInfoData +{ +public: + B3_DECLARE_ALIGNED_ALLOCATOR(); + + b3BvhSubtreeInfo() + { + //memset(&m_padding[0], 0, sizeof(m_padding)); + } + + + void setAabbFromQuantizeNode(const b3QuantizedBvhNode& 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 b3NodeOverlapCallback +{ +public: + virtual ~b3NodeOverlapCallback() {}; + + virtual void processNode(int subPart, int triangleIndex) = 0; +}; + +#include "Bullet3Common/b3AlignedAllocator.h" +#include "Bullet3Common/b3AlignedObjectArray.h" + + + +///for code readability: +typedef b3AlignedObjectArray NodeArray; +typedef b3AlignedObjectArray QuantizedNodeArray; +typedef b3AlignedObjectArray BvhSubtreeInfoArray; + + +///The b3QuantizedBvh class stores an AABB tree that can be quickly traversed on CPU and Cell SPU. +///It is used by the b3BvhTriangleMeshShape as midphase +///It is recommended to use quantization for better performance and lower memory requirements. +B3_ATTRIBUTE_ALIGNED16(class) b3QuantizedBvh +{ +public: + enum b3TraversalMode + { + TRAVERSAL_STACKLESS = 0, + TRAVERSAL_STACKLESS_CACHE_FRIENDLY, + TRAVERSAL_RECURSIVE + }; + + + + + b3Vector3 m_bvhAabbMin; + b3Vector3 m_bvhAabbMax; + b3Vector3 m_bvhQuantization; + +protected: + int m_bulletVersion; //for serialization versioning. It could also be used to detect endianess. + + int m_curNodeIndex; + //quantization data + bool m_useQuantization; + + + + NodeArray m_leafNodes; + NodeArray m_contiguousNodes; + QuantizedNodeArray m_quantizedLeafNodes; + QuantizedNodeArray m_quantizedContiguousNodes; + + b3TraversalMode m_traversalMode; + BvhSubtreeInfoArray m_SubtreeHeaders; + + //This is only used for serialization so we don't have to add serialization directly to b3AlignedObjectArray + mutable int m_subtreeHeaderCount; + + + + + + ///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 b3Vector3& aabbMin) + { + if (m_useQuantization) + { + quantize(&m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0] ,aabbMin,0); + } else + { + m_contiguousNodes[nodeIndex].m_aabbMinOrg = aabbMin; + + } + } + void setInternalNodeAabbMax(int nodeIndex,const b3Vector3& aabbMax) + { + if (m_useQuantization) + { + quantize(&m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0],aabbMax,1); + } else + { + m_contiguousNodes[nodeIndex].m_aabbMaxOrg = aabbMax; + } + } + + b3Vector3 getAabbMin(int nodeIndex) const + { + if (m_useQuantization) + { + return unQuantize(&m_quantizedLeafNodes[nodeIndex].m_quantizedAabbMin[0]); + } + //non-quantized + return m_leafNodes[nodeIndex].m_aabbMinOrg; + + } + b3Vector3 getAabbMax(int nodeIndex) const + { + if (m_useQuantization) + { + return unQuantize(&m_quantizedLeafNodes[nodeIndex].m_quantizedAabbMax[0]); + } + //non-quantized + return m_leafNodes[nodeIndex].m_aabbMaxOrg; + + } + + + 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 b3Vector3& newAabbMin,const b3Vector3& newAabbMax) + { + if (m_useQuantization) + { + unsigned short int quantizedAabbMin[3]; + unsigned short int quantizedAabbMax[3]; + quantize(quantizedAabbMin,newAabbMin,0); + quantize(quantizedAabbMax,newAabbMax,1); + 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(b3NodeOverlapCallback* nodeCallback,const b3Vector3& aabbMin,const b3Vector3& aabbMax) const; + + void walkStacklessQuantizedTreeAgainstRay(b3NodeOverlapCallback* nodeCallback, const b3Vector3& raySource, const b3Vector3& rayTarget, const b3Vector3& aabbMin, const b3Vector3& aabbMax, int startNodeIndex,int endNodeIndex) const; + void walkStacklessQuantizedTree(b3NodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax,int startNodeIndex,int endNodeIndex) const; + void walkStacklessTreeAgainstRay(b3NodeOverlapCallback* nodeCallback, const b3Vector3& raySource, const b3Vector3& rayTarget, const b3Vector3& aabbMin, const b3Vector3& aabbMax, int startNodeIndex,int endNodeIndex) const; + + ///tree traversal designed for small-memory processors like PS3 SPU + void walkStacklessQuantizedTreeCacheFriendly(b3NodeOverlapCallback* 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 b3QuantizedBvhNode* currentNode,b3NodeOverlapCallback* 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 b3QuantizedBvhNode* treeNodeA,const b3QuantizedBvhNode* treeNodeB,b3NodeOverlapCallback* nodeCallback) const; + + + + + void updateSubtreeHeaders(int leftChildNodexIndex,int rightChildNodexIndex); + +public: + + B3_DECLARE_ALIGNED_ALLOCATOR(); + + b3QuantizedBvh(); + + virtual ~b3QuantizedBvh(); + + + ///***************************************** expert/internal use only ************************* + void setQuantizationValues(const b3Vector3& bvhAabbMin,const b3Vector3& bvhAabbMax,b3Scalar quantizationMargin=b3Scalar(1.0)); + QuantizedNodeArray& getLeafNodeArray() { return m_quantizedLeafNodes; } + ///buildInternal is expert use only: assumes that setQuantizationValues and LeafNodeArray are initialized + void buildInternal(); + ///***************************************** expert/internal use only ************************* + + void reportAabbOverlappingNodex(b3NodeOverlapCallback* nodeCallback,const b3Vector3& aabbMin,const b3Vector3& aabbMax) const; + void reportRayOverlappingNodex (b3NodeOverlapCallback* nodeCallback, const b3Vector3& raySource, const b3Vector3& rayTarget) const; + void reportBoxCastOverlappingNodex(b3NodeOverlapCallback* nodeCallback, const b3Vector3& raySource, const b3Vector3& rayTarget, const b3Vector3& aabbMin,const b3Vector3& aabbMax) const; + + B3_FORCE_INLINE void quantize(unsigned short* out, const b3Vector3& point,int isMax) const + { + + b3Assert(m_useQuantization); + + b3Assert(point.getX() <= m_bvhAabbMax.getX()); + b3Assert(point.getY() <= m_bvhAabbMax.getY()); + b3Assert(point.getZ() <= m_bvhAabbMax.getZ()); + + b3Assert(point.getX() >= m_bvhAabbMin.getX()); + b3Assert(point.getY() >= m_bvhAabbMin.getY()); + b3Assert(point.getZ() >= m_bvhAabbMin.getZ()); + + b3Vector3 v = (point - m_bvhAabbMin) * m_bvhQuantization; + ///Make sure rounding is done in a way that unQuantize(quantizeWithClamp(...)) is conservative + ///end-points always set the first bit, so that they are sorted properly (so that neighbouring AABBs overlap properly) + ///@todo: double-check this + if (isMax) + { + out[0] = (unsigned short) (((unsigned short)(v.getX()+b3Scalar(1.)) | 1)); + out[1] = (unsigned short) (((unsigned short)(v.getY()+b3Scalar(1.)) | 1)); + out[2] = (unsigned short) (((unsigned short)(v.getZ()+b3Scalar(1.)) | 1)); + } else + { + out[0] = (unsigned short) (((unsigned short)(v.getX()) & 0xfffe)); + out[1] = (unsigned short) (((unsigned short)(v.getY()) & 0xfffe)); + out[2] = (unsigned short) (((unsigned short)(v.getZ()) & 0xfffe)); + } + + +#ifdef DEBUG_CHECK_DEQUANTIZATION + b3Vector3 newPoint = unQuantize(out); + if (isMax) + { + if (newPoint.getX() < point.getX()) + { + printf("unconservative X, diffX = %f, oldX=%f,newX=%f\n",newPoint.getX()-point.getX(), newPoint.getX(),point.getX()); + } + if (newPoint.getY() < point.getY()) + { + printf("unconservative Y, diffY = %f, oldY=%f,newY=%f\n",newPoint.getY()-point.getY(), newPoint.getY(),point.getY()); + } + if (newPoint.getZ() < point.getZ()) + { + + printf("unconservative Z, diffZ = %f, oldZ=%f,newZ=%f\n",newPoint.getZ()-point.getZ(), newPoint.getZ(),point.getZ()); + } + } else + { + if (newPoint.getX() > point.getX()) + { + printf("unconservative X, diffX = %f, oldX=%f,newX=%f\n",newPoint.getX()-point.getX(), newPoint.getX(),point.getX()); + } + if (newPoint.getY() > point.getY()) + { + printf("unconservative Y, diffY = %f, oldY=%f,newY=%f\n",newPoint.getY()-point.getY(), newPoint.getY(),point.getY()); + } + if (newPoint.getZ() > point.getZ()) + { + printf("unconservative Z, diffZ = %f, oldZ=%f,newZ=%f\n",newPoint.getZ()-point.getZ(), newPoint.getZ(),point.getZ()); + } + } +#endif //DEBUG_CHECK_DEQUANTIZATION + + } + + + B3_FORCE_INLINE void quantizeWithClamp(unsigned short* out, const b3Vector3& point2,int isMax) const + { + + b3Assert(m_useQuantization); + + b3Vector3 clampedPoint(point2); + clampedPoint.setMax(m_bvhAabbMin); + clampedPoint.setMin(m_bvhAabbMax); + + quantize(out,clampedPoint,isMax); + + } + + B3_FORCE_INLINE b3Vector3 unQuantize(const unsigned short* vecIn) const + { + b3Vector3 vecOut; + vecOut.setValue( + (b3Scalar)(vecIn[0]) / (m_bvhQuantization.getX()), + (b3Scalar)(vecIn[1]) / (m_bvhQuantization.getY()), + (b3Scalar)(vecIn[2]) / (m_bvhQuantization.getZ())); + vecOut += m_bvhAabbMin; + return vecOut; + } + + ///setTraversalMode let's you choose between stackless, recursive or stackless cache friendly tree traversal. Note this is only implemented for quantized trees. + void setTraversalMode(b3TraversalMode traversalMode) + { + m_traversalMode = traversalMode; + } + + + B3_FORCE_INLINE QuantizedNodeArray& getQuantizedNodeArray() + { + return m_quantizedContiguousNodes; + } + + + B3_FORCE_INLINE BvhSubtreeInfoArray& getSubtreeInfoArray() + { + return m_SubtreeHeaders; + } + +//////////////////////////////////////////////////////////////////// + + /////Calculate space needed to store BVH for serialization + unsigned calculateSerializeBufferSize() const; + + /// Data buffer MUST be 16 byte aligned + virtual bool serialize(void *o_alignedDataBuffer, unsigned i_dataBufferSize, bool i_swapEndian) const; + + ///deSerializeInPlace loads and initializes a BVH from a buffer in memory 'in place' + static b3QuantizedBvh *deSerializeInPlace(void *i_alignedDataBuffer, unsigned int i_dataBufferSize, bool i_swapEndian); + + static unsigned int getAlignmentSerializationPadding(); +////////////////////////////////////////////////////////////////////// + + + virtual int calculateSerializeBufferSizeNew() const; + + ///fills the dataBuffer and returns the struct name (and 0 on failure) + virtual const char* serialize(void* dataBuffer, b3Serializer* serializer) const; + + virtual void deSerializeFloat(struct b3QuantizedBvhFloatData& quantizedBvhFloatData); + + virtual void deSerializeDouble(struct b3QuantizedBvhDoubleData& quantizedBvhDoubleData); + + +//////////////////////////////////////////////////////////////////// + + B3_FORCE_INLINE bool isQuantized() + { + return m_useQuantization; + } + +private: + // Special "copy" constructor that allows for in-place deserialization + // Prevents b3Vector3's default constructor from being called, but doesn't inialize much else + // ownsMemory should most likely be false if deserializing, and if you are not, don't call this (it also changes the function signature, which we need) + b3QuantizedBvh(b3QuantizedBvh &other, bool ownsMemory); + +} +; + + +struct b3OptimizedBvhNodeFloatData +{ + b3Vector3FloatData m_aabbMinOrg; + b3Vector3FloatData m_aabbMaxOrg; + int m_escapeIndex; + int m_subPart; + int m_triangleIndex; + char m_pad[4]; +}; + +struct b3OptimizedBvhNodeDoubleData +{ + b3Vector3DoubleData m_aabbMinOrg; + b3Vector3DoubleData m_aabbMaxOrg; + int m_escapeIndex; + int m_subPart; + int m_triangleIndex; + char m_pad[4]; +}; + + + +struct b3QuantizedBvhFloatData +{ + b3Vector3FloatData m_bvhAabbMin; + b3Vector3FloatData m_bvhAabbMax; + b3Vector3FloatData m_bvhQuantization; + int m_curNodeIndex; + int m_useQuantization; + int m_numContiguousLeafNodes; + int m_numQuantizedContiguousNodes; + b3OptimizedBvhNodeFloatData *m_contiguousNodesPtr; + b3QuantizedBvhNodeData *m_quantizedContiguousNodesPtr; + b3BvhSubtreeInfoData *m_subTreeInfoPtr; + int m_traversalMode; + int m_numSubtreeHeaders; + +}; + +struct b3QuantizedBvhDoubleData +{ + b3Vector3DoubleData m_bvhAabbMin; + b3Vector3DoubleData m_bvhAabbMax; + b3Vector3DoubleData m_bvhQuantization; + int m_curNodeIndex; + int m_useQuantization; + int m_numContiguousLeafNodes; + int m_numQuantizedContiguousNodes; + b3OptimizedBvhNodeDoubleData *m_contiguousNodesPtr; + b3QuantizedBvhNodeData *m_quantizedContiguousNodesPtr; + + int m_traversalMode; + int m_numSubtreeHeaders; + b3BvhSubtreeInfoData *m_subTreeInfoPtr; +}; + + +B3_FORCE_INLINE int b3QuantizedBvh::calculateSerializeBufferSizeNew() const +{ + return sizeof(b3QuantizedBvhData); +} + + + +#endif //B3_QUANTIZED_BVH_H diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3StridingMeshInterface.cpp b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3StridingMeshInterface.cpp new file mode 100644 index 000000000000..4d97f7f62b90 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3StridingMeshInterface.cpp @@ -0,0 +1,214 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org + +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 "b3StridingMeshInterface.h" + + +b3StridingMeshInterface::~b3StridingMeshInterface() +{ + +} + + +void b3StridingMeshInterface::InternalProcessAllTriangles(b3InternalTriangleIndexCallback* callback,const b3Vector3& aabbMin,const b3Vector3& 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; + b3Vector3 triangle[3]; + + b3Vector3 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; + } + case PHY_UCHAR: + { + for (gfxindex=0;gfxindexinternalProcessTriangleIndex(triangle,part,gfxindex); + } + break; + } + default: + b3Assert((gfxindextype == PHY_INTEGER) || (gfxindextype == PHY_SHORT)); + } + break; + } + + case PHY_DOUBLE: + { + double* graphicsbase; + + switch (gfxindextype) + { + case PHY_INTEGER: + { + for (gfxindex=0;gfxindexinternalProcessTriangleIndex(triangle,part,gfxindex); + } + break; + } + case PHY_SHORT: + { + for (gfxindex=0;gfxindexinternalProcessTriangleIndex(triangle,part,gfxindex); + } + break; + } + case PHY_UCHAR: + { + for (gfxindex=0;gfxindexinternalProcessTriangleIndex(triangle,part,gfxindex); + } + break; + } + default: + b3Assert((gfxindextype == PHY_INTEGER) || (gfxindextype == PHY_SHORT)); + } + break; + } + default: + b3Assert((type == PHY_FLOAT) || (type == PHY_DOUBLE)); + } + + unLockReadOnlyVertexBase(part); + } +} + +void b3StridingMeshInterface::calculateAabbBruteForce(b3Vector3& aabbMin,b3Vector3& aabbMax) +{ + + struct AabbCalculationCallback : public b3InternalTriangleIndexCallback + { + b3Vector3 m_aabbMin; + b3Vector3 m_aabbMax; + + AabbCalculationCallback() + { + m_aabbMin.setValue(b3Scalar(B3_LARGE_FLOAT),b3Scalar(B3_LARGE_FLOAT),b3Scalar(B3_LARGE_FLOAT)); + m_aabbMax.setValue(b3Scalar(-B3_LARGE_FLOAT),b3Scalar(-B3_LARGE_FLOAT),b3Scalar(-B3_LARGE_FLOAT)); + } + + virtual void internalProcessTriangleIndex(b3Vector3* 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(b3Scalar(-B3_LARGE_FLOAT),b3Scalar(-B3_LARGE_FLOAT),b3Scalar(-B3_LARGE_FLOAT)); + aabbMax.setValue(b3Scalar(B3_LARGE_FLOAT),b3Scalar(B3_LARGE_FLOAT),b3Scalar(B3_LARGE_FLOAT)); + InternalProcessAllTriangles(&aabbCallback,aabbMin,aabbMax); + + aabbMin = aabbCallback.m_aabbMin; + aabbMax = aabbCallback.m_aabbMax; +} + + diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3StridingMeshInterface.h b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3StridingMeshInterface.h new file mode 100644 index 000000000000..9513f68f77ea --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3StridingMeshInterface.h @@ -0,0 +1,167 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org + +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 B3_STRIDING_MESHINTERFACE_H +#define B3_STRIDING_MESHINTERFACE_H + +#include "Bullet3Common/b3Vector3.h" +#include "b3TriangleCallback.h" +//#include "b3ConcaveShape.h" + + +enum PHY_ScalarType { + PHY_FLOAT, PHY_DOUBLE, PHY_INTEGER, PHY_SHORT, + PHY_FIXEDPOINT88, PHY_UCHAR +}; + + +/// The b3StridingMeshInterface is the interface class for high performance generic access to triangle meshes, used in combination with b3BvhTriangleMeshShape and some other collision shapes. +/// Using index striding of 3*sizeof(integer) it can use triangle arrays, using index striding of 1*sizeof(integer) it can handle triangle strips. +/// It allows for sharing graphics and collision meshes. Also it provides locking/unlocking of graphics meshes that are in gpu memory. +B3_ATTRIBUTE_ALIGNED16(class ) b3StridingMeshInterface +{ + protected: + + b3Vector3 m_scaling; + + public: + B3_DECLARE_ALIGNED_ALLOCATOR(); + + b3StridingMeshInterface() :m_scaling(b3MakeVector3(b3Scalar(1.),b3Scalar(1.),b3Scalar(1.))) + { + + } + + virtual ~b3StridingMeshInterface(); + + + + virtual void InternalProcessAllTriangles(b3InternalTriangleIndexCallback* callback,const b3Vector3& aabbMin,const b3Vector3& aabbMax) const; + + ///brute force method to calculate aabb + void calculateAabbBruteForce(b3Vector3& aabbMin,b3Vector3& 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; + + virtual bool hasPremadeAabb() const { return false; } + virtual void setPremadeAabb(const b3Vector3& aabbMin, const b3Vector3& aabbMax ) const + { + (void) aabbMin; + (void) aabbMax; + } + virtual void getPremadeAabb(b3Vector3* aabbMin, b3Vector3* aabbMax ) const + { + (void) aabbMin; + (void) aabbMax; + } + + const b3Vector3& getScaling() const { + return m_scaling; + } + void setScaling(const b3Vector3& scaling) + { + m_scaling = scaling; + } + + virtual int calculateSerializeBufferSize() const; + + ///fills the dataBuffer and returns the struct name (and 0 on failure) + //virtual const char* serialize(void* dataBuffer, b3Serializer* serializer) const; + + +}; + +struct b3IntIndexData +{ + int m_value; +}; + +struct b3ShortIntIndexData +{ + short m_value; + char m_pad[2]; +}; + +struct b3ShortIntIndexTripletData +{ + short m_values[3]; + char m_pad[2]; +}; + +struct b3CharIndexTripletData +{ + unsigned char m_values[3]; + char m_pad; +}; + + +///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 +struct b3MeshPartData +{ + b3Vector3FloatData *m_vertices3f; + b3Vector3DoubleData *m_vertices3d; + + b3IntIndexData *m_indices32; + b3ShortIntIndexTripletData *m_3indices16; + b3CharIndexTripletData *m_3indices8; + + b3ShortIntIndexData *m_indices16;//backwards compatibility + + int m_numTriangles;//length of m_indices = m_numTriangles + int m_numVertices; +}; + + +///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 +struct b3StridingMeshInterfaceData +{ + b3MeshPartData *m_meshPartsPtr; + b3Vector3FloatData m_scaling; + int m_numMeshParts; + char m_padding[4]; +}; + + + + +B3_FORCE_INLINE int b3StridingMeshInterface::calculateSerializeBufferSize() const +{ + return sizeof(b3StridingMeshInterfaceData); +} + + + +#endif //B3_STRIDING_MESHINTERFACE_H diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3SupportMappings.h b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3SupportMappings.h new file mode 100644 index 000000000000..d073ee57c378 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3SupportMappings.h @@ -0,0 +1,38 @@ + +#ifndef B3_SUPPORT_MAPPINGS_H +#define B3_SUPPORT_MAPPINGS_H + +#include "Bullet3Common/b3Transform.h" +#include "Bullet3Common/b3AlignedObjectArray.h" +#include "b3VectorFloat4.h" + + +struct b3GjkPairDetector; + + + +inline b3Vector3 localGetSupportVertexWithMargin(const float4& supportVec,const struct b3ConvexPolyhedronData* hull, + const b3AlignedObjectArray& verticesA, b3Scalar margin) +{ + b3Vector3 supVec = b3MakeVector3(b3Scalar(0.),b3Scalar(0.),b3Scalar(0.)); + b3Scalar maxDot = b3Scalar(-B3_LARGE_FLOAT); + + // Here we take advantage of dot(a, b*c) = dot(a*b, c). Note: This is true mathematically, but not numerically. + if( 0 < hull->m_numVertices ) + { + const b3Vector3 scaled = supportVec; + int index = (int) scaled.maxDot( &verticesA[hull->m_vertexOffset], hull->m_numVertices, maxDot); + return verticesA[hull->m_vertexOffset+index]; + } + + return supVec; + +} + +inline b3Vector3 localGetSupportVertexWithoutMargin(const float4& supportVec,const struct b3ConvexPolyhedronData* hull, + const b3AlignedObjectArray& verticesA) +{ + return localGetSupportVertexWithMargin(supportVec,hull,verticesA,0.f); +} + +#endif //B3_SUPPORT_MAPPINGS_H diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3TriangleCallback.cpp b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3TriangleCallback.cpp new file mode 100644 index 000000000000..9066451884ef --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3TriangleCallback.cpp @@ -0,0 +1,28 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org + +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 "b3TriangleCallback.h" + +b3TriangleCallback::~b3TriangleCallback() +{ + +} + + +b3InternalTriangleIndexCallback::~b3InternalTriangleIndexCallback() +{ + +} + diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3TriangleCallback.h b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3TriangleCallback.h new file mode 100644 index 000000000000..3059fa4f2124 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3TriangleCallback.h @@ -0,0 +1,42 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org + +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 B3_TRIANGLE_CALLBACK_H +#define B3_TRIANGLE_CALLBACK_H + +#include "Bullet3Common/b3Vector3.h" + + +///The b3TriangleCallback provides a callback for each overlapping triangle when calling processAllTriangles. +///This callback is called by processAllTriangles for all b3ConcaveShape derived class, such as b3BvhTriangleMeshShape, b3StaticPlaneShape and b3HeightfieldTerrainShape. +class b3TriangleCallback +{ +public: + + virtual ~b3TriangleCallback(); + virtual void processTriangle(b3Vector3* triangle, int partId, int triangleIndex) = 0; +}; + +class b3InternalTriangleIndexCallback +{ +public: + + virtual ~b3InternalTriangleIndexCallback(); + virtual void internalProcessTriangleIndex(b3Vector3* triangle,int partId,int triangleIndex) = 0; +}; + + + +#endif //B3_TRIANGLE_CALLBACK_H diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3TriangleIndexVertexArray.cpp b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3TriangleIndexVertexArray.cpp new file mode 100644 index 000000000000..a0f59babbee1 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3TriangleIndexVertexArray.cpp @@ -0,0 +1,95 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org + +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 "b3TriangleIndexVertexArray.h" + +b3TriangleIndexVertexArray::b3TriangleIndexVertexArray(int numTriangles,int* triangleIndexBase,int triangleIndexStride,int numVertices,b3Scalar* vertexBase,int vertexStride) +: m_hasAabb(0) +{ + b3IndexedMesh 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); + +} + +b3TriangleIndexVertexArray::~b3TriangleIndexVertexArray() +{ + +} + +void b3TriangleIndexVertexArray::getLockedVertexIndexBase(unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& vertexStride,unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart) +{ + b3Assert(subpart< getNumSubParts() ); + + b3IndexedMesh& mesh = m_indexedMeshes[subpart]; + + numverts = mesh.m_numVertices; + (*vertexbase) = (unsigned char *) mesh.m_vertexBase; + + type = mesh.m_vertexType; + + vertexStride = mesh.m_vertexStride; + + numfaces = mesh.m_numTriangles; + + (*indexbase) = (unsigned char *)mesh.m_triangleIndexBase; + indexstride = mesh.m_triangleIndexStride; + indicestype = mesh.m_indexType; +} + +void b3TriangleIndexVertexArray::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 b3IndexedMesh& mesh = m_indexedMeshes[subpart]; + + numverts = mesh.m_numVertices; + (*vertexbase) = (const unsigned char *)mesh.m_vertexBase; + + type = mesh.m_vertexType; + + vertexStride = mesh.m_vertexStride; + + numfaces = mesh.m_numTriangles; + (*indexbase) = (const unsigned char *)mesh.m_triangleIndexBase; + indexstride = mesh.m_triangleIndexStride; + indicestype = mesh.m_indexType; +} + +bool b3TriangleIndexVertexArray::hasPremadeAabb() const +{ + return (m_hasAabb == 1); +} + + +void b3TriangleIndexVertexArray::setPremadeAabb(const b3Vector3& aabbMin, const b3Vector3& aabbMax ) const +{ + m_aabbMin = aabbMin; + m_aabbMax = aabbMax; + m_hasAabb = 1; // this is intentionally an int see notes in header +} + +void b3TriangleIndexVertexArray::getPremadeAabb(b3Vector3* aabbMin, b3Vector3* aabbMax ) const +{ + *aabbMin = m_aabbMin; + *aabbMax = m_aabbMax; +} + + diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3TriangleIndexVertexArray.h b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3TriangleIndexVertexArray.h new file mode 100644 index 000000000000..d26b2893bc57 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3TriangleIndexVertexArray.h @@ -0,0 +1,133 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org + +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 B3_TRIANGLE_INDEX_VERTEX_ARRAY_H +#define B3_TRIANGLE_INDEX_VERTEX_ARRAY_H + +#include "b3StridingMeshInterface.h" +#include "Bullet3Common/b3AlignedObjectArray.h" +#include "Bullet3Common/b3Scalar.h" + + +///The b3IndexedMesh indexes a single vertex and index array. Multiple b3IndexedMesh objects can be passed into a b3TriangleIndexVertexArray using addIndexedMesh. +///Instead of the number of indices, we pass the number of triangles. +B3_ATTRIBUTE_ALIGNED16( struct) b3IndexedMesh +{ + B3_DECLARE_ALIGNED_ALLOCATOR(); + + int m_numTriangles; + const unsigned char * m_triangleIndexBase; + // Size in byte of the indices for one triangle (3*sizeof(index_type) if the indices are tightly packed) + int m_triangleIndexStride; + int m_numVertices; + const unsigned char * m_vertexBase; + // Size of a vertex, in bytes + int m_vertexStride; + + // The index type is set when adding an indexed mesh to the + // b3TriangleIndexVertexArray, do not set it manually + PHY_ScalarType m_indexType; + + // The vertex type has a default type similar to Bullet's precision mode (float or double) + // but can be set manually if you for example run Bullet with double precision but have + // mesh data in single precision.. + PHY_ScalarType m_vertexType; + + + b3IndexedMesh() + :m_indexType(PHY_INTEGER), +#ifdef B3_USE_DOUBLE_PRECISION + m_vertexType(PHY_DOUBLE) +#else // B3_USE_DOUBLE_PRECISION + m_vertexType(PHY_FLOAT) +#endif // B3_USE_DOUBLE_PRECISION + { + } +} +; + + +typedef b3AlignedObjectArray IndexedMeshArray; + +///The b3TriangleIndexVertexArray allows to access multiple triangle 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 b3TriangleIndexVertexArray. +B3_ATTRIBUTE_ALIGNED16( class) b3TriangleIndexVertexArray : public b3StridingMeshInterface +{ +protected: + IndexedMeshArray m_indexedMeshes; + int m_pad[2]; + mutable int m_hasAabb; // using int instead of bool to maintain alignment + mutable b3Vector3 m_aabbMin; + mutable b3Vector3 m_aabbMax; + +public: + + B3_DECLARE_ALIGNED_ALLOCATOR(); + + b3TriangleIndexVertexArray() : m_hasAabb(0) + { + } + + virtual ~b3TriangleIndexVertexArray(); + + //just to be backwards compatible + b3TriangleIndexVertexArray(int numTriangles,int* triangleIndexBase,int triangleIndexStride,int numVertices,b3Scalar* vertexBase,int vertexStride); + + void addIndexedMesh(const b3IndexedMesh& mesh, PHY_ScalarType indexType = PHY_INTEGER) + { + m_indexedMeshes.push_back(mesh); + m_indexedMeshes[m_indexedMeshes.size()-1].m_indexType = indexType; + } + + + 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;} + + virtual bool hasPremadeAabb() const; + virtual void setPremadeAabb(const b3Vector3& aabbMin, const b3Vector3& aabbMax ) const; + virtual void getPremadeAabb(b3Vector3* aabbMin, b3Vector3* aabbMax ) const; + +} +; + +#endif //B3_TRIANGLE_INDEX_VERTEX_ARRAY_H diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3VectorFloat4.h b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3VectorFloat4.h new file mode 100644 index 000000000000..f6f65f7719d6 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3VectorFloat4.h @@ -0,0 +1,11 @@ +#ifndef B3_VECTOR_FLOAT4_H +#define B3_VECTOR_FLOAT4_H + +#include "Bullet3Common/b3Transform.h" + +//#define cross3(a,b) (a.cross(b)) +#define float4 b3Vector3 +//#define make_float4(x,y,z,w) b3Vector4(x,y,z,w) + + +#endif //B3_VECTOR_FLOAT4_H diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3VoronoiSimplexSolver.cpp b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3VoronoiSimplexSolver.cpp new file mode 100644 index 000000000000..cf3d5ef49d4a --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3VoronoiSimplexSolver.cpp @@ -0,0 +1,609 @@ + +/* +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 "b3VoronoiSimplexSolver.h" + +#define VERTA 0 +#define VERTB 1 +#define VERTC 2 +#define VERTD 3 + +#define B3_CATCH_DEGENERATE_TETRAHEDRON 1 +void b3VoronoiSimplexSolver::removeVertex(int index) +{ + + b3Assert(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 b3VoronoiSimplexSolver::reduceVertices (const b3UsageBitfield& 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 b3VoronoiSimplexSolver::reset() +{ + m_cachedValidClosest = false; + m_numVertices = 0; + m_needsUpdate = true; + m_lastW = b3MakeVector3(b3Scalar(B3_LARGE_FLOAT),b3Scalar(B3_LARGE_FLOAT),b3Scalar(B3_LARGE_FLOAT)); + m_cachedBC.reset(); +} + + + + //add a vertex +void b3VoronoiSimplexSolver::addVertex(const b3Vector3& w, const b3Vector3& p, const b3Vector3& 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 b3VoronoiSimplexSolver::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(b3Scalar(1.),b3Scalar(0.),b3Scalar(0.),b3Scalar(0.)); + m_cachedValidClosest = m_cachedBC.isValid(); + break; + }; + case 2: + { + //closest point origin from line segment + const b3Vector3& from = m_simplexVectorW[0]; + const b3Vector3& to = m_simplexVectorW[1]; + b3Vector3 nearest; + + b3Vector3 p =b3MakeVector3(b3Scalar(0.),b3Scalar(0.),b3Scalar(0.)); + b3Vector3 diff = p - from; + b3Vector3 v = to - from; + b3Scalar t = v.dot(diff); + + if (t > 0) { + b3Scalar 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 + b3Vector3 p =b3MakeVector3(b3Scalar(0.),b3Scalar(0.),b3Scalar(0.)); + + const b3Vector3& a = m_simplexVectorW[0]; + const b3Vector3& b = m_simplexVectorW[1]; + const b3Vector3& 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: + { + + + b3Vector3 p =b3MakeVector3(b3Scalar(0.),b3Scalar(0.),b3Scalar(0.)); + + const b3Vector3& a = m_simplexVectorW[0]; + const b3Vector3& b = m_simplexVectorW[1]; + const b3Vector3& c = m_simplexVectorW[2]; + const b3Vector3& 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(b3Scalar(0.),b3Scalar(0.),b3Scalar(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 b3VoronoiSimplexSolver::closest(b3Vector3& v) +{ + bool succes = updateClosestVectorAndPoints(); + v = m_cachedV; + return succes; +} + + + +b3Scalar b3VoronoiSimplexSolver::maxVertex() +{ + int i, numverts = numVertices(); + b3Scalar maxV = b3Scalar(0.); + for (i=0;i= b3Scalar(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 + b3Scalar vc = d1*d4 - d3*d2; + if (vc <= b3Scalar(0.0) && d1 >= b3Scalar(0.0) && d3 <= b3Scalar(0.0)) { + b3Scalar 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 + b3Vector3 cp = p - c; + b3Scalar d5 = ab.dot(cp); + b3Scalar d6 = ac.dot(cp); + if (d6 >= b3Scalar(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 + b3Scalar vb = d5*d2 - d1*d6; + if (vb <= b3Scalar(0.0) && d2 >= b3Scalar(0.0) && d6 <= b3Scalar(0.0)) { + b3Scalar 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 + b3Scalar va = d3*d6 - d5*d4; + if (va <= b3Scalar(0.0) && (d4 - d3) >= b3Scalar(0.0) && (d5 - d6) >= b3Scalar(0.0)) { + b3Scalar 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) + b3Scalar denom = b3Scalar(1.0) / (va + vb + vc); + b3Scalar v = vb * denom; + b3Scalar 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 = b3Scalar(1.0) - v - w + +} + + + + + +/// Test if point p and d lie on opposite sides of plane through abc +int b3VoronoiSimplexSolver::pointOutsideOfPlane(const b3Vector3& p, const b3Vector3& a, const b3Vector3& b, const b3Vector3& c, const b3Vector3& d) +{ + b3Vector3 normal = (b-a).cross(c-a); + + b3Scalar signp = (p - a).dot(normal); // [AP AB AC] + b3Scalar signd = (d - a).dot( normal); // [AD AB AC] + +#ifdef B3_CATCH_DEGENERATE_TETRAHEDRON +#ifdef BT_USE_DOUBLE_PRECISION +if (signd * signd < (b3Scalar(1e-8) * b3Scalar(1e-8))) + { + return -1; + } +#else + if (signd * signd < (b3Scalar(1e-4) * b3Scalar(1e-4))) + { +// printf("affine dependent/degenerate\n");// + return -1; + } +#endif + +#endif + // Points on opposite sides if expression signs are opposite + return signp * signd < b3Scalar(0.); +} + + +bool b3VoronoiSimplexSolver::closestPtPointTetrahedron(const b3Vector3& p, const b3Vector3& a, const b3Vector3& b, const b3Vector3& c, const b3Vector3& d, b3SubSimplexClosestResult& finalResult) +{ + b3SubSimplexClosestResult 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; + } + + + b3Scalar bestSqDist = FLT_MAX; + // If point outside face abc then compute closest point on abc + if (pointOutsideABC) + { + closestPtPointTriangle(p, a, b, c,tempResult); + b3Vector3 q = tempResult.m_closestPointOnSimplex; + + b3Scalar 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); + b3Vector3 q = tempResult.m_closestPointOnSimplex; + //convert result bitmask! + + b3Scalar 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); + b3Vector3 q = tempResult.m_closestPointOnSimplex; + //convert result bitmask! + + b3Scalar 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); + b3Vector3 q = tempResult.m_closestPointOnSimplex; + //convert result bitmask! + b3Scalar 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/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3VoronoiSimplexSolver.h b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3VoronoiSimplexSolver.h new file mode 100644 index 000000000000..a6e27667d89e --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/b3VoronoiSimplexSolver.h @@ -0,0 +1,177 @@ +/* +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 B3_VORONOI_SIMPLEX_SOLVER_H +#define B3_VORONOI_SIMPLEX_SOLVER_H + +#include "Bullet3Common/b3Vector3.h" + + +#define VORONOI_SIMPLEX_MAX_VERTS 5 + +///disable next define, or use defaultCollisionConfiguration->getSimplexSolver()->setEqualVertexThreshold(0.f) to disable/configure +//#define BT_USE_EQUAL_VERTEX_THRESHOLD +#define VORONOI_DEFAULT_EQUAL_VERTEX_THRESHOLD 0.0001f + + +struct b3UsageBitfield{ + b3UsageBitfield() + { + 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 b3SubSimplexClosestResult +{ + b3Vector3 m_closestPointOnSimplex; + //MASK for m_usedVertices + //stores the simplex vertex-usage, using the MASK, + // if m_usedVertices & MASK then the related vertex is used + b3UsageBitfield m_usedVertices; + b3Scalar m_barycentricCoords[4]; + bool m_degenerate; + + void reset() + { + m_degenerate = false; + setBarycentricCoordinates(); + m_usedVertices.reset(); + } + bool isValid() + { + bool valid = (m_barycentricCoords[0] >= b3Scalar(0.)) && + (m_barycentricCoords[1] >= b3Scalar(0.)) && + (m_barycentricCoords[2] >= b3Scalar(0.)) && + (m_barycentricCoords[3] >= b3Scalar(0.)); + + + return valid; + } + void setBarycentricCoordinates(b3Scalar a=b3Scalar(0.),b3Scalar b=b3Scalar(0.),b3Scalar c=b3Scalar(0.),b3Scalar d=b3Scalar(0.)) + { + m_barycentricCoords[0] = a; + m_barycentricCoords[1] = b; + m_barycentricCoords[2] = c; + m_barycentricCoords[3] = d; + } + +}; + +/// b3VoronoiSimplexSolver 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. + +B3_ATTRIBUTE_ALIGNED16(class) b3VoronoiSimplexSolver +{ +public: + + B3_DECLARE_ALIGNED_ALLOCATOR(); + + int m_numVertices; + + b3Vector3 m_simplexVectorW[VORONOI_SIMPLEX_MAX_VERTS]; + b3Vector3 m_simplexPointsP[VORONOI_SIMPLEX_MAX_VERTS]; + b3Vector3 m_simplexPointsQ[VORONOI_SIMPLEX_MAX_VERTS]; + + + + b3Vector3 m_cachedP1; + b3Vector3 m_cachedP2; + b3Vector3 m_cachedV; + b3Vector3 m_lastW; + + b3Scalar m_equalVertexThreshold; + bool m_cachedValidClosest; + + + b3SubSimplexClosestResult m_cachedBC; + + bool m_needsUpdate; + + void removeVertex(int index); + void reduceVertices (const b3UsageBitfield& usedVerts); + bool updateClosestVectorAndPoints(); + + bool closestPtPointTetrahedron(const b3Vector3& p, const b3Vector3& a, const b3Vector3& b, const b3Vector3& c, const b3Vector3& d, b3SubSimplexClosestResult& finalResult); + int pointOutsideOfPlane(const b3Vector3& p, const b3Vector3& a, const b3Vector3& b, const b3Vector3& c, const b3Vector3& d); + bool closestPtPointTriangle(const b3Vector3& p, const b3Vector3& a, const b3Vector3& b, const b3Vector3& c,b3SubSimplexClosestResult& result); + +public: + + b3VoronoiSimplexSolver() + : m_equalVertexThreshold(VORONOI_DEFAULT_EQUAL_VERTEX_THRESHOLD) + { + } + void reset(); + + void addVertex(const b3Vector3& w, const b3Vector3& p, const b3Vector3& q); + + void setEqualVertexThreshold(b3Scalar threshold) + { + m_equalVertexThreshold = threshold; + } + + b3Scalar getEqualVertexThreshold() const + { + return m_equalVertexThreshold; + } + + bool closest(b3Vector3& v); + + b3Scalar maxVertex(); + + bool fullSimplex() const + { + return (m_numVertices == 4); + } + + int getSimplex(b3Vector3 *pBuf, b3Vector3 *qBuf, b3Vector3 *yBuf) const; + + bool inSimplex(const b3Vector3& w); + + void backup_closest(b3Vector3& v) ; + + bool emptySimplex() const ; + + void compute_points(b3Vector3& p1, b3Vector3& p2) ; + + int numVertices() const + { + return m_numVertices; + } + + +}; + +#endif //B3_VORONOI_SIMPLEX_SOLVER_H + diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/kernels/bvhTraversal.cl b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/kernels/bvhTraversal.cl new file mode 100644 index 000000000000..faa413441c55 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/kernels/bvhTraversal.cl @@ -0,0 +1,283 @@ +//keep this enum in sync with the CPU version (in btCollidable.h) +//written by Erwin Coumans + +#define SHAPE_CONVEX_HULL 3 +#define SHAPE_CONCAVE_TRIMESH 5 +#define TRIANGLE_NUM_CONVEX_FACES 5 +#define SHAPE_COMPOUND_OF_CONVEX_HULLS 6 +#define SHAPE_SPHERE 7 + +typedef unsigned int u32; + +#define MAX_NUM_PARTS_IN_BITS 10 + +///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). +typedef struct +{ + //12 bytes + unsigned short int m_quantizedAabbMin[3]; + unsigned short int m_quantizedAabbMax[3]; + //4 bytes + int m_escapeIndexOrTriangleIndex; +} btQuantizedBvhNode; + +typedef struct +{ + float4 m_aabbMin; + float4 m_aabbMax; + float4 m_quantization; + int m_numNodes; + int m_numSubTrees; + int m_nodeOffset; + int m_subTreeOffset; + +} b3BvhInfo; + +int getTriangleIndex(const btQuantizedBvhNode* rootNode) +{ + unsigned int x=0; + unsigned int y = (~(x&0))<<(31-MAX_NUM_PARTS_IN_BITS); + // Get only the lower bits where the triangle index is stored + return (rootNode->m_escapeIndexOrTriangleIndex&~(y)); +} + +int isLeaf(const btQuantizedBvhNode* rootNode) +{ + //skipindex is negative (internal node), triangleindex >=0 (leafnode) + return (rootNode->m_escapeIndexOrTriangleIndex >= 0)? 1 : 0; +} + +int getEscapeIndex(const btQuantizedBvhNode* rootNode) +{ + return -rootNode->m_escapeIndexOrTriangleIndex; +} + +typedef struct +{ + //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]; +} btBvhSubtreeInfo; + +///keep this in sync with btCollidable.h +typedef struct +{ + int m_numChildShapes; + int blaat2; + int m_shapeType; + int m_shapeIndex; + +} btCollidableGpu; + +typedef struct +{ + float4 m_childPosition; + float4 m_childOrientation; + int m_shapeIndex; + int m_unused0; + int m_unused1; + int m_unused2; +} btGpuChildShape; + + +typedef struct +{ + float4 m_pos; + float4 m_quat; + float4 m_linVel; + float4 m_angVel; + + u32 m_collidableIdx; + float m_invMass; + float m_restituitionCoeff; + float m_frictionCoeff; +} BodyData; + +typedef struct +{ + union + { + float4 m_min; + float m_minElems[4]; + int m_minIndices[4]; + }; + union + { + float4 m_max; + float m_maxElems[4]; + int m_maxIndices[4]; + }; +} btAabbCL; + + +int testQuantizedAabbAgainstQuantizedAabb( + const unsigned short int* aabbMin1, + const unsigned short int* aabbMax1, + const unsigned short int* aabbMin2, + const unsigned short int* aabbMax2) +{ + //int overlap = 1; + if (aabbMin1[0] > aabbMax2[0]) + return 0; + if (aabbMax1[0] < aabbMin2[0]) + return 0; + if (aabbMin1[1] > aabbMax2[1]) + return 0; + if (aabbMax1[1] < aabbMin2[1]) + return 0; + if (aabbMin1[2] > aabbMax2[2]) + return 0; + if (aabbMax1[2] < aabbMin2[2]) + return 0; + return 1; + //overlap = ((aabbMin1[0] > aabbMax2[0]) || (aabbMax1[0] < aabbMin2[0])) ? 0 : overlap; + //overlap = ((aabbMin1[2] > aabbMax2[2]) || (aabbMax1[2] < aabbMin2[2])) ? 0 : overlap; + //overlap = ((aabbMin1[1] > aabbMax2[1]) || (aabbMax1[1] < aabbMin2[1])) ? 0 : overlap; + //return overlap; +} + + +void quantizeWithClamp(unsigned short* out, float4 point2,int isMax, float4 bvhAabbMin, float4 bvhAabbMax, float4 bvhQuantization) +{ + float4 clampedPoint = max(point2,bvhAabbMin); + clampedPoint = min (clampedPoint, bvhAabbMax); + + float4 v = (clampedPoint - bvhAabbMin) * bvhQuantization; + if (isMax) + { + out[0] = (unsigned short) (((unsigned short)(v.x+1.f) | 1)); + out[1] = (unsigned short) (((unsigned short)(v.y+1.f) | 1)); + out[2] = (unsigned short) (((unsigned short)(v.z+1.f) | 1)); + } else + { + out[0] = (unsigned short) (((unsigned short)(v.x) & 0xfffe)); + out[1] = (unsigned short) (((unsigned short)(v.y) & 0xfffe)); + out[2] = (unsigned short) (((unsigned short)(v.z) & 0xfffe)); + } + +} + + +// work-in-progress +__kernel void bvhTraversalKernel( __global const int4* pairs, + __global const BodyData* rigidBodies, + __global const btCollidableGpu* collidables, + __global btAabbCL* aabbs, + __global int4* concavePairsOut, + __global volatile int* numConcavePairsOut, + __global const btBvhSubtreeInfo* subtreeHeadersRoot, + __global const btQuantizedBvhNode* quantizedNodesRoot, + __global const b3BvhInfo* bvhInfos, + int numPairs, + int maxNumConcavePairsCapacity) +{ + int id = get_global_id(0); + if (id>=numPairs) + return; + + int bodyIndexA = pairs[id].x; + int bodyIndexB = pairs[id].y; + int collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx; + int collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx; + + //once the broadphase avoids static-static pairs, we can remove this test + if ((rigidBodies[bodyIndexA].m_invMass==0) &&(rigidBodies[bodyIndexB].m_invMass==0)) + { + return; + } + + if (collidables[collidableIndexA].m_shapeType!=SHAPE_CONCAVE_TRIMESH) + return; + + int shapeTypeB = collidables[collidableIndexB].m_shapeType; + + if (shapeTypeB!=SHAPE_CONVEX_HULL && + shapeTypeB!=SHAPE_SPHERE && + shapeTypeB!=SHAPE_COMPOUND_OF_CONVEX_HULLS + ) + return; + + b3BvhInfo bvhInfo = bvhInfos[collidables[collidableIndexA].m_numChildShapes]; + + float4 bvhAabbMin = bvhInfo.m_aabbMin; + float4 bvhAabbMax = bvhInfo.m_aabbMax; + float4 bvhQuantization = bvhInfo.m_quantization; + int numSubtreeHeaders = bvhInfo.m_numSubTrees; + __global const btBvhSubtreeInfo* subtreeHeaders = &subtreeHeadersRoot[bvhInfo.m_subTreeOffset]; + __global const btQuantizedBvhNode* quantizedNodes = &quantizedNodesRoot[bvhInfo.m_nodeOffset]; + + + unsigned short int quantizedQueryAabbMin[3]; + unsigned short int quantizedQueryAabbMax[3]; + quantizeWithClamp(quantizedQueryAabbMin,aabbs[bodyIndexB].m_min,false,bvhAabbMin, bvhAabbMax,bvhQuantization); + quantizeWithClamp(quantizedQueryAabbMax,aabbs[bodyIndexB].m_max,true ,bvhAabbMin, bvhAabbMax,bvhQuantization); + + for (int i=0;im_escapeIndexOrTriangleIndex&~(y));\n" +"}\n" +"int isLeaf(const btQuantizedBvhNode* rootNode)\n" +"{\n" +" //skipindex is negative (internal node), triangleindex >=0 (leafnode)\n" +" return (rootNode->m_escapeIndexOrTriangleIndex >= 0)? 1 : 0;\n" +"}\n" +" \n" +"int getEscapeIndex(const btQuantizedBvhNode* rootNode)\n" +"{\n" +" return -rootNode->m_escapeIndexOrTriangleIndex;\n" +"}\n" +"typedef struct\n" +"{\n" +" //12 bytes\n" +" unsigned short int m_quantizedAabbMin[3];\n" +" unsigned short int m_quantizedAabbMax[3];\n" +" //4 bytes, points to the root of the subtree\n" +" int m_rootNodeIndex;\n" +" //4 bytes\n" +" int m_subtreeSize;\n" +" int m_padding[3];\n" +"} btBvhSubtreeInfo;\n" +"///keep this in sync with btCollidable.h\n" +"typedef struct\n" +"{\n" +" int m_numChildShapes;\n" +" int blaat2;\n" +" int m_shapeType;\n" +" int m_shapeIndex;\n" +" \n" +"} btCollidableGpu;\n" +"typedef struct\n" +"{\n" +" float4 m_childPosition;\n" +" float4 m_childOrientation;\n" +" int m_shapeIndex;\n" +" int m_unused0;\n" +" int m_unused1;\n" +" int m_unused2;\n" +"} btGpuChildShape;\n" +"typedef struct\n" +"{\n" +" float4 m_pos;\n" +" float4 m_quat;\n" +" float4 m_linVel;\n" +" float4 m_angVel;\n" +" u32 m_collidableIdx;\n" +" float m_invMass;\n" +" float m_restituitionCoeff;\n" +" float m_frictionCoeff;\n" +"} BodyData;\n" +"typedef struct \n" +"{\n" +" union\n" +" {\n" +" float4 m_min;\n" +" float m_minElems[4];\n" +" int m_minIndices[4];\n" +" };\n" +" union\n" +" {\n" +" float4 m_max;\n" +" float m_maxElems[4];\n" +" int m_maxIndices[4];\n" +" };\n" +"} btAabbCL;\n" +"int testQuantizedAabbAgainstQuantizedAabb(\n" +" const unsigned short int* aabbMin1,\n" +" const unsigned short int* aabbMax1,\n" +" const unsigned short int* aabbMin2,\n" +" const unsigned short int* aabbMax2)\n" +"{\n" +" //int overlap = 1;\n" +" if (aabbMin1[0] > aabbMax2[0])\n" +" return 0;\n" +" if (aabbMax1[0] < aabbMin2[0])\n" +" return 0;\n" +" if (aabbMin1[1] > aabbMax2[1])\n" +" return 0;\n" +" if (aabbMax1[1] < aabbMin2[1])\n" +" return 0;\n" +" if (aabbMin1[2] > aabbMax2[2])\n" +" return 0;\n" +" if (aabbMax1[2] < aabbMin2[2])\n" +" return 0;\n" +" return 1;\n" +" //overlap = ((aabbMin1[0] > aabbMax2[0]) || (aabbMax1[0] < aabbMin2[0])) ? 0 : overlap;\n" +" //overlap = ((aabbMin1[2] > aabbMax2[2]) || (aabbMax1[2] < aabbMin2[2])) ? 0 : overlap;\n" +" //overlap = ((aabbMin1[1] > aabbMax2[1]) || (aabbMax1[1] < aabbMin2[1])) ? 0 : overlap;\n" +" //return overlap;\n" +"}\n" +"void quantizeWithClamp(unsigned short* out, float4 point2,int isMax, float4 bvhAabbMin, float4 bvhAabbMax, float4 bvhQuantization)\n" +"{\n" +" float4 clampedPoint = max(point2,bvhAabbMin);\n" +" clampedPoint = min (clampedPoint, bvhAabbMax);\n" +" float4 v = (clampedPoint - bvhAabbMin) * bvhQuantization;\n" +" if (isMax)\n" +" {\n" +" out[0] = (unsigned short) (((unsigned short)(v.x+1.f) | 1));\n" +" out[1] = (unsigned short) (((unsigned short)(v.y+1.f) | 1));\n" +" out[2] = (unsigned short) (((unsigned short)(v.z+1.f) | 1));\n" +" } else\n" +" {\n" +" out[0] = (unsigned short) (((unsigned short)(v.x) & 0xfffe));\n" +" out[1] = (unsigned short) (((unsigned short)(v.y) & 0xfffe));\n" +" out[2] = (unsigned short) (((unsigned short)(v.z) & 0xfffe));\n" +" }\n" +"}\n" +"// work-in-progress\n" +"__kernel void bvhTraversalKernel( __global const int4* pairs, \n" +" __global const BodyData* rigidBodies, \n" +" __global const btCollidableGpu* collidables,\n" +" __global btAabbCL* aabbs,\n" +" __global int4* concavePairsOut,\n" +" __global volatile int* numConcavePairsOut,\n" +" __global const btBvhSubtreeInfo* subtreeHeadersRoot,\n" +" __global const btQuantizedBvhNode* quantizedNodesRoot,\n" +" __global const b3BvhInfo* bvhInfos,\n" +" int numPairs,\n" +" int maxNumConcavePairsCapacity)\n" +"{\n" +" int id = get_global_id(0);\n" +" if (id>=numPairs)\n" +" return;\n" +" \n" +" int bodyIndexA = pairs[id].x;\n" +" int bodyIndexB = pairs[id].y;\n" +" int collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx;\n" +" int collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx;\n" +" \n" +" //once the broadphase avoids static-static pairs, we can remove this test\n" +" if ((rigidBodies[bodyIndexA].m_invMass==0) &&(rigidBodies[bodyIndexB].m_invMass==0))\n" +" {\n" +" return;\n" +" }\n" +" \n" +" if (collidables[collidableIndexA].m_shapeType!=SHAPE_CONCAVE_TRIMESH)\n" +" return;\n" +" int shapeTypeB = collidables[collidableIndexB].m_shapeType;\n" +" \n" +" if (shapeTypeB!=SHAPE_CONVEX_HULL &&\n" +" shapeTypeB!=SHAPE_SPHERE &&\n" +" shapeTypeB!=SHAPE_COMPOUND_OF_CONVEX_HULLS\n" +" )\n" +" return;\n" +" b3BvhInfo bvhInfo = bvhInfos[collidables[collidableIndexA].m_numChildShapes];\n" +" float4 bvhAabbMin = bvhInfo.m_aabbMin;\n" +" float4 bvhAabbMax = bvhInfo.m_aabbMax;\n" +" float4 bvhQuantization = bvhInfo.m_quantization;\n" +" int numSubtreeHeaders = bvhInfo.m_numSubTrees;\n" +" __global const btBvhSubtreeInfo* subtreeHeaders = &subtreeHeadersRoot[bvhInfo.m_subTreeOffset];\n" +" __global const btQuantizedBvhNode* quantizedNodes = &quantizedNodesRoot[bvhInfo.m_nodeOffset];\n" +" \n" +" unsigned short int quantizedQueryAabbMin[3];\n" +" unsigned short int quantizedQueryAabbMax[3];\n" +" quantizeWithClamp(quantizedQueryAabbMin,aabbs[bodyIndexB].m_min,false,bvhAabbMin, bvhAabbMax,bvhQuantization);\n" +" quantizeWithClamp(quantizedQueryAabbMax,aabbs[bodyIndexB].m_max,true ,bvhAabbMin, bvhAabbMax,bvhQuantization);\n" +" \n" +" for (int i=0;im_worldNormalOnB = -dirOut;//normal; + c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff); + c->m_batchIdx = pairIndex; + int bodyA = pairs[pairIndex].x; + int bodyB = pairs[pairIndex].y; + c->m_bodyAPtrAndSignBit = rigidBodies[bodyA].m_invMass==0 ? -bodyA:bodyA; + c->m_bodyBPtrAndSignBit = rigidBodies[bodyB].m_invMass==0 ? -bodyB:bodyB; + c->m_childIndexA = -1; + c->m_childIndexB = -1; + //for (int i=0;im_worldPosB[0] = posOut;//localPoints[contactIdx[i]]; + GET_NPOINTS(*c) = 1;//nContacts; + } + } + + } +} + +typedef float4 Quaternion; +#define make_float4 (float4) + +__inline +float dot3F4(float4 a, float4 b) +{ + float4 a1 = make_float4(a.xyz,0.f); + float4 b1 = make_float4(b.xyz,0.f); + return dot(a1, b1); +} + + + + +__inline +float4 cross3(float4 a, float4 b) +{ + return cross(a,b); +} +__inline +Quaternion qtMul(Quaternion a, Quaternion b) +{ + Quaternion ans; + ans = cross3( a, b ); + ans += a.w*b+b.w*a; +// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z); + ans.w = a.w*b.w - dot3F4(a, b); + return ans; +} + +__inline +Quaternion qtInvert(Quaternion q) +{ + return (Quaternion)(-q.xyz, q.w); +} + +__inline +float4 qtRotate(Quaternion q, float4 vec) +{ + Quaternion qInv = qtInvert( q ); + float4 vcpy = vec; + vcpy.w = 0.f; + float4 out = qtMul(qtMul(q,vcpy),qInv); + return out; +} + +__inline +float4 transform(const float4* p, const float4* translation, const Quaternion* orientation) +{ + return qtRotate( *orientation, *p ) + (*translation); +} + + +__inline +float4 qtInvRotate(const Quaternion q, float4 vec) +{ + return qtRotate( qtInvert( q ), vec ); +} + + +inline void project(__global const b3ConvexPolyhedronData_t* hull, const float4 pos, const float4 orn, +const float4* dir, __global const float4* vertices, float* min, float* max) +{ + min[0] = FLT_MAX; + max[0] = -FLT_MAX; + int numVerts = hull->m_numVertices; + + const float4 localDir = qtInvRotate(orn,*dir); + float offset = dot(pos,*dir); + for(int i=0;im_vertexOffset+i],localDir); + if(dp < min[0]) + min[0] = dp; + if(dp > max[0]) + max[0] = dp; + } + if(min[0]>max[0]) + { + float tmp = min[0]; + min[0] = max[0]; + max[0] = tmp; + } + min[0] += offset; + max[0] += offset; +} + + +bool findSeparatingAxisUnitSphere( __global const b3ConvexPolyhedronData_t* hullA, __global const b3ConvexPolyhedronData_t* hullB, + const float4 posA1, + const float4 ornA, + const float4 posB1, + const float4 ornB, + const float4 DeltaC2, + __global const float4* vertices, + __global const float4* unitSphereDirections, + int numUnitSphereDirections, + float4* sep, + float* dmin) +{ + + float4 posA = posA1; + posA.w = 0.f; + float4 posB = posB1; + posB.w = 0.f; + + int curPlaneTests=0; + + int curEdgeEdge = 0; + // Test unit sphere directions + for (int i=0;i0) + crossje *= -1.f; + { + float dist; + bool result = true; + float Min0,Max0; + float Min1,Max1; + project(hullA,posA,ornA,&crossje,vertices, &Min0, &Max0); + project(hullB,posB,ornB,&crossje,vertices, &Min1, &Max1); + + if(Max00.0f) + { + *sep = -(*sep); + } + return true; +} + + + +__kernel void findSeparatingAxisUnitSphereKernel( __global const int4* pairs, + __global const b3RigidBodyData_t* rigidBodies, + __global const b3Collidable_t* collidables, + __global const b3ConvexPolyhedronData_t* convexShapes, + __global const float4* vertices, + __global const float4* unitSphereDirections, + __global float4* separatingNormals, + __global int* hasSeparatingAxis, + __global float* dmins, + int numUnitSphereDirections, + int numPairs + ) +{ + + int i = get_global_id(0); + + if (inumUnitSphereDirections) + { + bool sepEE = findSeparatingAxisUnitSphere( &convexShapes[shapeIndexA], &convexShapes[shapeIndexB],posA,ornA, + posB,ornB, + DeltaC2, + vertices,unitSphereDirections,numUnitSphereDirections,&sepNormal,&dmin); + if (!sepEE) + { + hasSeparatingAxis[i] = 0; + } else + { + hasSeparatingAxis[i] = 1; + separatingNormals[i] = sepNormal; + } + } + } //if (hasSeparatingAxis[i]) + }//(i\n" +" *\n" +" * This file was ported from mpr.c file, part of libccd.\n" +" * The Minkoski Portal Refinement implementation was ported \n" +" * to OpenCL by Erwin Coumans for the Bullet 3 Physics library.\n" +" * at http://github.com/erwincoumans/bullet3\n" +" *\n" +" * Distributed under the OSI-approved BSD License (the \"License\");\n" +" * see .\n" +" * This software is distributed WITHOUT ANY WARRANTY; without even the\n" +" * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" +" * See the License for more information.\n" +" */\n" +"#ifndef B3_MPR_PENETRATION_H\n" +"#define B3_MPR_PENETRATION_H\n" +"#ifndef B3_PLATFORM_DEFINITIONS_H\n" +"#define B3_PLATFORM_DEFINITIONS_H\n" +"struct MyTest\n" +"{\n" +" int bla;\n" +"};\n" +"#ifdef __cplusplus\n" +"#else\n" +"//keep B3_LARGE_FLOAT*B3_LARGE_FLOAT < FLT_MAX\n" +"#define B3_LARGE_FLOAT 1e18f\n" +"#define B3_INFINITY 1e18f\n" +"#define b3Assert(a)\n" +"#define b3ConstArray(a) __global const a*\n" +"#define b3AtomicInc atomic_inc\n" +"#define b3AtomicAdd atomic_add\n" +"#define b3Fabs fabs\n" +"#define b3Sqrt native_sqrt\n" +"#define b3Sin native_sin\n" +"#define b3Cos native_cos\n" +"#define B3_STATIC\n" +"#endif\n" +"#endif\n" +"#ifndef B3_FLOAT4_H\n" +"#define B3_FLOAT4_H\n" +"#ifndef B3_PLATFORM_DEFINITIONS_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif\n" +"#endif\n" +"#ifdef __cplusplus\n" +"#else\n" +" typedef float4 b3Float4;\n" +" #define b3Float4ConstArg const b3Float4\n" +" #define b3MakeFloat4 (float4)\n" +" float b3Dot3F4(b3Float4ConstArg v0,b3Float4ConstArg v1)\n" +" {\n" +" float4 a1 = b3MakeFloat4(v0.xyz,0.f);\n" +" float4 b1 = b3MakeFloat4(v1.xyz,0.f);\n" +" return dot(a1, b1);\n" +" }\n" +" b3Float4 b3Cross3(b3Float4ConstArg v0,b3Float4ConstArg v1)\n" +" {\n" +" float4 a1 = b3MakeFloat4(v0.xyz,0.f);\n" +" float4 b1 = b3MakeFloat4(v1.xyz,0.f);\n" +" return cross(a1, b1);\n" +" }\n" +" #define b3MinFloat4 min\n" +" #define b3MaxFloat4 max\n" +" #define b3Normalized(a) normalize(a)\n" +"#endif \n" +" \n" +"inline bool b3IsAlmostZero(b3Float4ConstArg v)\n" +"{\n" +" if(b3Fabs(v.x)>1e-6 || b3Fabs(v.y)>1e-6 || b3Fabs(v.z)>1e-6) \n" +" return false;\n" +" return true;\n" +"}\n" +"inline int b3MaxDot( b3Float4ConstArg vec, __global const b3Float4* vecArray, int vecLen, float* dotOut )\n" +"{\n" +" float maxDot = -B3_INFINITY;\n" +" int i = 0;\n" +" int ptIndex = -1;\n" +" for( i = 0; i < vecLen; i++ )\n" +" {\n" +" float dot = b3Dot3F4(vecArray[i],vec);\n" +" \n" +" if( dot > maxDot )\n" +" {\n" +" maxDot = dot;\n" +" ptIndex = i;\n" +" }\n" +" }\n" +" b3Assert(ptIndex>=0);\n" +" if (ptIndex<0)\n" +" {\n" +" ptIndex = 0;\n" +" }\n" +" *dotOut = maxDot;\n" +" return ptIndex;\n" +"}\n" +"#endif //B3_FLOAT4_H\n" +"#ifndef B3_RIGIDBODY_DATA_H\n" +"#define B3_RIGIDBODY_DATA_H\n" +"#ifndef B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_FLOAT4_H\n" +"#ifndef B3_QUAT_H\n" +"#define B3_QUAT_H\n" +"#ifndef B3_PLATFORM_DEFINITIONS_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif\n" +"#endif\n" +"#ifndef B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +" typedef float4 b3Quat;\n" +" #define b3QuatConstArg const b3Quat\n" +" \n" +" \n" +"inline float4 b3FastNormalize4(float4 v)\n" +"{\n" +" v = (float4)(v.xyz,0.f);\n" +" return fast_normalize(v);\n" +"}\n" +" \n" +"inline b3Quat b3QuatMul(b3Quat a, b3Quat b);\n" +"inline b3Quat b3QuatNormalized(b3QuatConstArg in);\n" +"inline b3Quat b3QuatRotate(b3QuatConstArg q, b3QuatConstArg vec);\n" +"inline b3Quat b3QuatInvert(b3QuatConstArg q);\n" +"inline b3Quat b3QuatInverse(b3QuatConstArg q);\n" +"inline b3Quat b3QuatMul(b3QuatConstArg a, b3QuatConstArg b)\n" +"{\n" +" b3Quat ans;\n" +" ans = b3Cross3( a, b );\n" +" ans += a.w*b+b.w*a;\n" +"// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z);\n" +" ans.w = a.w*b.w - b3Dot3F4(a, b);\n" +" return ans;\n" +"}\n" +"inline b3Quat b3QuatNormalized(b3QuatConstArg in)\n" +"{\n" +" b3Quat q;\n" +" q=in;\n" +" //return b3FastNormalize4(in);\n" +" float len = native_sqrt(dot(q, q));\n" +" if(len > 0.f)\n" +" {\n" +" q *= 1.f / len;\n" +" }\n" +" else\n" +" {\n" +" q.x = q.y = q.z = 0.f;\n" +" q.w = 1.f;\n" +" }\n" +" return q;\n" +"}\n" +"inline float4 b3QuatRotate(b3QuatConstArg q, b3QuatConstArg vec)\n" +"{\n" +" b3Quat qInv = b3QuatInvert( q );\n" +" float4 vcpy = vec;\n" +" vcpy.w = 0.f;\n" +" float4 out = b3QuatMul(b3QuatMul(q,vcpy),qInv);\n" +" return out;\n" +"}\n" +"inline b3Quat b3QuatInverse(b3QuatConstArg q)\n" +"{\n" +" return (b3Quat)(-q.xyz, q.w);\n" +"}\n" +"inline b3Quat b3QuatInvert(b3QuatConstArg q)\n" +"{\n" +" return (b3Quat)(-q.xyz, q.w);\n" +"}\n" +"inline float4 b3QuatInvRotate(b3QuatConstArg q, b3QuatConstArg vec)\n" +"{\n" +" return b3QuatRotate( b3QuatInvert( q ), vec );\n" +"}\n" +"inline b3Float4 b3TransformPoint(b3Float4ConstArg point, b3Float4ConstArg translation, b3QuatConstArg orientation)\n" +"{\n" +" return b3QuatRotate( orientation, point ) + (translation);\n" +"}\n" +" \n" +"#endif \n" +"#endif //B3_QUAT_H\n" +"#ifndef B3_MAT3x3_H\n" +"#define B3_MAT3x3_H\n" +"#ifndef B3_QUAT_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_QUAT_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"typedef struct\n" +"{\n" +" b3Float4 m_row[3];\n" +"}b3Mat3x3;\n" +"#define b3Mat3x3ConstArg const b3Mat3x3\n" +"#define b3GetRow(m,row) (m.m_row[row])\n" +"inline b3Mat3x3 b3QuatGetRotationMatrix(b3Quat quat)\n" +"{\n" +" b3Float4 quat2 = (b3Float4)(quat.x*quat.x, quat.y*quat.y, quat.z*quat.z, 0.f);\n" +" b3Mat3x3 out;\n" +" out.m_row[0].x=1-2*quat2.y-2*quat2.z;\n" +" out.m_row[0].y=2*quat.x*quat.y-2*quat.w*quat.z;\n" +" out.m_row[0].z=2*quat.x*quat.z+2*quat.w*quat.y;\n" +" out.m_row[0].w = 0.f;\n" +" out.m_row[1].x=2*quat.x*quat.y+2*quat.w*quat.z;\n" +" out.m_row[1].y=1-2*quat2.x-2*quat2.z;\n" +" out.m_row[1].z=2*quat.y*quat.z-2*quat.w*quat.x;\n" +" out.m_row[1].w = 0.f;\n" +" out.m_row[2].x=2*quat.x*quat.z-2*quat.w*quat.y;\n" +" out.m_row[2].y=2*quat.y*quat.z+2*quat.w*quat.x;\n" +" out.m_row[2].z=1-2*quat2.x-2*quat2.y;\n" +" out.m_row[2].w = 0.f;\n" +" return out;\n" +"}\n" +"inline b3Mat3x3 b3AbsoluteMat3x3(b3Mat3x3ConstArg matIn)\n" +"{\n" +" b3Mat3x3 out;\n" +" out.m_row[0] = fabs(matIn.m_row[0]);\n" +" out.m_row[1] = fabs(matIn.m_row[1]);\n" +" out.m_row[2] = fabs(matIn.m_row[2]);\n" +" return out;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtZero();\n" +"__inline\n" +"b3Mat3x3 mtIdentity();\n" +"__inline\n" +"b3Mat3x3 mtTranspose(b3Mat3x3 m);\n" +"__inline\n" +"b3Mat3x3 mtMul(b3Mat3x3 a, b3Mat3x3 b);\n" +"__inline\n" +"b3Float4 mtMul1(b3Mat3x3 a, b3Float4 b);\n" +"__inline\n" +"b3Float4 mtMul3(b3Float4 a, b3Mat3x3 b);\n" +"__inline\n" +"b3Mat3x3 mtZero()\n" +"{\n" +" b3Mat3x3 m;\n" +" m.m_row[0] = (b3Float4)(0.f);\n" +" m.m_row[1] = (b3Float4)(0.f);\n" +" m.m_row[2] = (b3Float4)(0.f);\n" +" return m;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtIdentity()\n" +"{\n" +" b3Mat3x3 m;\n" +" m.m_row[0] = (b3Float4)(1,0,0,0);\n" +" m.m_row[1] = (b3Float4)(0,1,0,0);\n" +" m.m_row[2] = (b3Float4)(0,0,1,0);\n" +" return m;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtTranspose(b3Mat3x3 m)\n" +"{\n" +" b3Mat3x3 out;\n" +" out.m_row[0] = (b3Float4)(m.m_row[0].x, m.m_row[1].x, m.m_row[2].x, 0.f);\n" +" out.m_row[1] = (b3Float4)(m.m_row[0].y, m.m_row[1].y, m.m_row[2].y, 0.f);\n" +" out.m_row[2] = (b3Float4)(m.m_row[0].z, m.m_row[1].z, m.m_row[2].z, 0.f);\n" +" return out;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtMul(b3Mat3x3 a, b3Mat3x3 b)\n" +"{\n" +" b3Mat3x3 transB;\n" +" transB = mtTranspose( b );\n" +" b3Mat3x3 ans;\n" +" // why this doesn't run when 0ing in the for{}\n" +" a.m_row[0].w = 0.f;\n" +" a.m_row[1].w = 0.f;\n" +" a.m_row[2].w = 0.f;\n" +" for(int i=0; i<3; i++)\n" +" {\n" +"// a.m_row[i].w = 0.f;\n" +" ans.m_row[i].x = b3Dot3F4(a.m_row[i],transB.m_row[0]);\n" +" ans.m_row[i].y = b3Dot3F4(a.m_row[i],transB.m_row[1]);\n" +" ans.m_row[i].z = b3Dot3F4(a.m_row[i],transB.m_row[2]);\n" +" ans.m_row[i].w = 0.f;\n" +" }\n" +" return ans;\n" +"}\n" +"__inline\n" +"b3Float4 mtMul1(b3Mat3x3 a, b3Float4 b)\n" +"{\n" +" b3Float4 ans;\n" +" ans.x = b3Dot3F4( a.m_row[0], b );\n" +" ans.y = b3Dot3F4( a.m_row[1], b );\n" +" ans.z = b3Dot3F4( a.m_row[2], b );\n" +" ans.w = 0.f;\n" +" return ans;\n" +"}\n" +"__inline\n" +"b3Float4 mtMul3(b3Float4 a, b3Mat3x3 b)\n" +"{\n" +" b3Float4 colx = b3MakeFloat4(b.m_row[0].x, b.m_row[1].x, b.m_row[2].x, 0);\n" +" b3Float4 coly = b3MakeFloat4(b.m_row[0].y, b.m_row[1].y, b.m_row[2].y, 0);\n" +" b3Float4 colz = b3MakeFloat4(b.m_row[0].z, b.m_row[1].z, b.m_row[2].z, 0);\n" +" b3Float4 ans;\n" +" ans.x = b3Dot3F4( a, colx );\n" +" ans.y = b3Dot3F4( a, coly );\n" +" ans.z = b3Dot3F4( a, colz );\n" +" return ans;\n" +"}\n" +"#endif\n" +"#endif //B3_MAT3x3_H\n" +"typedef struct b3RigidBodyData b3RigidBodyData_t;\n" +"struct b3RigidBodyData\n" +"{\n" +" b3Float4 m_pos;\n" +" b3Quat m_quat;\n" +" b3Float4 m_linVel;\n" +" b3Float4 m_angVel;\n" +" int m_collidableIdx;\n" +" float m_invMass;\n" +" float m_restituitionCoeff;\n" +" float m_frictionCoeff;\n" +"};\n" +"typedef struct b3InertiaData b3InertiaData_t;\n" +"struct b3InertiaData\n" +"{\n" +" b3Mat3x3 m_invInertiaWorld;\n" +" b3Mat3x3 m_initInvInertia;\n" +"};\n" +"#endif //B3_RIGIDBODY_DATA_H\n" +" \n" +"#ifndef B3_CONVEX_POLYHEDRON_DATA_H\n" +"#define B3_CONVEX_POLYHEDRON_DATA_H\n" +"#ifndef B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_FLOAT4_H\n" +"#ifndef B3_QUAT_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_QUAT_H\n" +"typedef struct b3GpuFace b3GpuFace_t;\n" +"struct b3GpuFace\n" +"{\n" +" b3Float4 m_plane;\n" +" int m_indexOffset;\n" +" int m_numIndices;\n" +" int m_unusedPadding1;\n" +" int m_unusedPadding2;\n" +"};\n" +"typedef struct b3ConvexPolyhedronData b3ConvexPolyhedronData_t;\n" +"struct b3ConvexPolyhedronData\n" +"{\n" +" b3Float4 m_localCenter;\n" +" b3Float4 m_extents;\n" +" b3Float4 mC;\n" +" b3Float4 mE;\n" +" float m_radius;\n" +" int m_faceOffset;\n" +" int m_numFaces;\n" +" int m_numVertices;\n" +" int m_vertexOffset;\n" +" int m_uniqueEdgesOffset;\n" +" int m_numUniqueEdges;\n" +" int m_unused;\n" +"};\n" +"#endif //B3_CONVEX_POLYHEDRON_DATA_H\n" +"#ifndef B3_COLLIDABLE_H\n" +"#define B3_COLLIDABLE_H\n" +"#ifndef B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_FLOAT4_H\n" +"#ifndef B3_QUAT_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_QUAT_H\n" +"enum b3ShapeTypes\n" +"{\n" +" SHAPE_HEIGHT_FIELD=1,\n" +" SHAPE_CONVEX_HULL=3,\n" +" SHAPE_PLANE=4,\n" +" SHAPE_CONCAVE_TRIMESH=5,\n" +" SHAPE_COMPOUND_OF_CONVEX_HULLS=6,\n" +" SHAPE_SPHERE=7,\n" +" MAX_NUM_SHAPE_TYPES,\n" +"};\n" +"typedef struct b3Collidable b3Collidable_t;\n" +"struct b3Collidable\n" +"{\n" +" union {\n" +" int m_numChildShapes;\n" +" int m_bvhIndex;\n" +" };\n" +" union\n" +" {\n" +" float m_radius;\n" +" int m_compoundBvhIndex;\n" +" };\n" +" int m_shapeType;\n" +" int m_shapeIndex;\n" +"};\n" +"typedef struct b3GpuChildShape b3GpuChildShape_t;\n" +"struct b3GpuChildShape\n" +"{\n" +" b3Float4 m_childPosition;\n" +" b3Quat m_childOrientation;\n" +" int m_shapeIndex;\n" +" int m_unused0;\n" +" int m_unused1;\n" +" int m_unused2;\n" +"};\n" +"struct b3CompoundOverlappingPair\n" +"{\n" +" int m_bodyIndexA;\n" +" int m_bodyIndexB;\n" +"// int m_pairType;\n" +" int m_childShapeIndexA;\n" +" int m_childShapeIndexB;\n" +"};\n" +"#endif //B3_COLLIDABLE_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#define B3_MPR_SQRT sqrt\n" +"#endif\n" +"#define B3_MPR_FMIN(x, y) ((x) < (y) ? (x) : (y))\n" +"#define B3_MPR_FABS fabs\n" +"#define B3_MPR_TOLERANCE 1E-6f\n" +"#define B3_MPR_MAX_ITERATIONS 1000\n" +"struct _b3MprSupport_t \n" +"{\n" +" b3Float4 v; //!< Support point in minkowski sum\n" +" b3Float4 v1; //!< Support point in obj1\n" +" b3Float4 v2; //!< Support point in obj2\n" +"};\n" +"typedef struct _b3MprSupport_t b3MprSupport_t;\n" +"struct _b3MprSimplex_t \n" +"{\n" +" b3MprSupport_t ps[4];\n" +" int last; //!< index of last added point\n" +"};\n" +"typedef struct _b3MprSimplex_t b3MprSimplex_t;\n" +"inline b3MprSupport_t* b3MprSimplexPointW(b3MprSimplex_t *s, int idx)\n" +"{\n" +" return &s->ps[idx];\n" +"}\n" +"inline void b3MprSimplexSetSize(b3MprSimplex_t *s, int size)\n" +"{\n" +" s->last = size - 1;\n" +"}\n" +"inline int b3MprSimplexSize(const b3MprSimplex_t *s)\n" +"{\n" +" return s->last + 1;\n" +"}\n" +"inline const b3MprSupport_t* b3MprSimplexPoint(const b3MprSimplex_t* s, int idx)\n" +"{\n" +" // here is no check on boundaries\n" +" return &s->ps[idx];\n" +"}\n" +"inline void b3MprSupportCopy(b3MprSupport_t *d, const b3MprSupport_t *s)\n" +"{\n" +" *d = *s;\n" +"}\n" +"inline void b3MprSimplexSet(b3MprSimplex_t *s, size_t pos, const b3MprSupport_t *a)\n" +"{\n" +" b3MprSupportCopy(s->ps + pos, a);\n" +"}\n" +"inline void b3MprSimplexSwap(b3MprSimplex_t *s, size_t pos1, size_t pos2)\n" +"{\n" +" b3MprSupport_t supp;\n" +" b3MprSupportCopy(&supp, &s->ps[pos1]);\n" +" b3MprSupportCopy(&s->ps[pos1], &s->ps[pos2]);\n" +" b3MprSupportCopy(&s->ps[pos2], &supp);\n" +"}\n" +"inline int b3MprIsZero(float val)\n" +"{\n" +" return B3_MPR_FABS(val) < FLT_EPSILON;\n" +"}\n" +"inline int b3MprEq(float _a, float _b)\n" +"{\n" +" float ab;\n" +" float a, b;\n" +" ab = B3_MPR_FABS(_a - _b);\n" +" if (B3_MPR_FABS(ab) < FLT_EPSILON)\n" +" return 1;\n" +" a = B3_MPR_FABS(_a);\n" +" b = B3_MPR_FABS(_b);\n" +" if (b > a){\n" +" return ab < FLT_EPSILON * b;\n" +" }else{\n" +" return ab < FLT_EPSILON * a;\n" +" }\n" +"}\n" +"inline int b3MprVec3Eq(const b3Float4* a, const b3Float4 *b)\n" +"{\n" +" return b3MprEq((*a).x, (*b).x)\n" +" && b3MprEq((*a).y, (*b).y)\n" +" && b3MprEq((*a).z, (*b).z);\n" +"}\n" +"inline b3Float4 b3LocalGetSupportVertex(b3Float4ConstArg supportVec,__global const b3ConvexPolyhedronData_t* hull, b3ConstArray(b3Float4) verticesA)\n" +"{\n" +" b3Float4 supVec = b3MakeFloat4(0,0,0,0);\n" +" float maxDot = -B3_LARGE_FLOAT;\n" +" if( 0 < hull->m_numVertices )\n" +" {\n" +" const b3Float4 scaled = supportVec;\n" +" int index = b3MaxDot(scaled, &verticesA[hull->m_vertexOffset], hull->m_numVertices, &maxDot);\n" +" return verticesA[hull->m_vertexOffset+index];\n" +" }\n" +" return supVec;\n" +"}\n" +"B3_STATIC void b3MprConvexSupport(int pairIndex,int bodyIndex, b3ConstArray(b3RigidBodyData_t) cpuBodyBuf, \n" +" b3ConstArray(b3ConvexPolyhedronData_t) cpuConvexData, \n" +" b3ConstArray(b3Collidable_t) cpuCollidables,\n" +" b3ConstArray(b3Float4) cpuVertices,\n" +" __global b3Float4* sepAxis,\n" +" const b3Float4* _dir, b3Float4* outp, int logme)\n" +"{\n" +" //dir is in worldspace, move to local space\n" +" \n" +" b3Float4 pos = cpuBodyBuf[bodyIndex].m_pos;\n" +" b3Quat orn = cpuBodyBuf[bodyIndex].m_quat;\n" +" \n" +" b3Float4 dir = b3MakeFloat4((*_dir).x,(*_dir).y,(*_dir).z,0.f);\n" +" \n" +" const b3Float4 localDir = b3QuatRotate(b3QuatInverse(orn),dir);\n" +" \n" +" //find local support vertex\n" +" int colIndex = cpuBodyBuf[bodyIndex].m_collidableIdx;\n" +" \n" +" b3Assert(cpuCollidables[colIndex].m_shapeType==SHAPE_CONVEX_HULL);\n" +" __global const b3ConvexPolyhedronData_t* hull = &cpuConvexData[cpuCollidables[colIndex].m_shapeIndex];\n" +" \n" +" b3Float4 pInA;\n" +" if (logme)\n" +" {\n" +" b3Float4 supVec = b3MakeFloat4(0,0,0,0);\n" +" float maxDot = -B3_LARGE_FLOAT;\n" +" if( 0 < hull->m_numVertices )\n" +" {\n" +" const b3Float4 scaled = localDir;\n" +" int index = b3MaxDot(scaled, &cpuVertices[hull->m_vertexOffset], hull->m_numVertices, &maxDot);\n" +" pInA = cpuVertices[hull->m_vertexOffset+index];\n" +" \n" +" }\n" +" } else\n" +" {\n" +" pInA = b3LocalGetSupportVertex(localDir,hull,cpuVertices);\n" +" }\n" +" //move vertex to world space\n" +" *outp = b3TransformPoint(pInA,pos,orn);\n" +" \n" +"}\n" +"inline void b3MprSupport(int pairIndex,int bodyIndexA, int bodyIndexB, b3ConstArray(b3RigidBodyData_t) cpuBodyBuf, \n" +" b3ConstArray(b3ConvexPolyhedronData_t) cpuConvexData, \n" +" b3ConstArray(b3Collidable_t) cpuCollidables,\n" +" b3ConstArray(b3Float4) cpuVertices,\n" +" __global b3Float4* sepAxis,\n" +" const b3Float4* _dir, b3MprSupport_t *supp)\n" +"{\n" +" b3Float4 dir;\n" +" dir = *_dir;\n" +" b3MprConvexSupport(pairIndex,bodyIndexA,cpuBodyBuf,cpuConvexData,cpuCollidables,cpuVertices,sepAxis,&dir, &supp->v1,0);\n" +" dir = *_dir*-1.f;\n" +" b3MprConvexSupport(pairIndex,bodyIndexB,cpuBodyBuf,cpuConvexData,cpuCollidables,cpuVertices,sepAxis,&dir, &supp->v2,0);\n" +" supp->v = supp->v1 - supp->v2;\n" +"}\n" +"inline void b3FindOrigin(int bodyIndexA, int bodyIndexB, b3ConstArray(b3RigidBodyData_t) cpuBodyBuf, b3MprSupport_t *center)\n" +"{\n" +" center->v1 = cpuBodyBuf[bodyIndexA].m_pos;\n" +" center->v2 = cpuBodyBuf[bodyIndexB].m_pos;\n" +" center->v = center->v1 - center->v2;\n" +"}\n" +"inline void b3MprVec3Set(b3Float4 *v, float x, float y, float z)\n" +"{\n" +" (*v).x = x;\n" +" (*v).y = y;\n" +" (*v).z = z;\n" +" (*v).w = 0.f;\n" +"}\n" +"inline void b3MprVec3Add(b3Float4 *v, const b3Float4 *w)\n" +"{\n" +" (*v).x += (*w).x;\n" +" (*v).y += (*w).y;\n" +" (*v).z += (*w).z;\n" +"}\n" +"inline void b3MprVec3Copy(b3Float4 *v, const b3Float4 *w)\n" +"{\n" +" *v = *w;\n" +"}\n" +"inline void b3MprVec3Scale(b3Float4 *d, float k)\n" +"{\n" +" *d *= k;\n" +"}\n" +"inline float b3MprVec3Dot(const b3Float4 *a, const b3Float4 *b)\n" +"{\n" +" float dot;\n" +" dot = b3Dot3F4(*a,*b);\n" +" return dot;\n" +"}\n" +"inline float b3MprVec3Len2(const b3Float4 *v)\n" +"{\n" +" return b3MprVec3Dot(v, v);\n" +"}\n" +"inline void b3MprVec3Normalize(b3Float4 *d)\n" +"{\n" +" float k = 1.f / B3_MPR_SQRT(b3MprVec3Len2(d));\n" +" b3MprVec3Scale(d, k);\n" +"}\n" +"inline void b3MprVec3Cross(b3Float4 *d, const b3Float4 *a, const b3Float4 *b)\n" +"{\n" +" *d = b3Cross3(*a,*b);\n" +" \n" +"}\n" +"inline void b3MprVec3Sub2(b3Float4 *d, const b3Float4 *v, const b3Float4 *w)\n" +"{\n" +" *d = *v - *w;\n" +"}\n" +"inline void b3PortalDir(const b3MprSimplex_t *portal, b3Float4 *dir)\n" +"{\n" +" b3Float4 v2v1, v3v1;\n" +" b3MprVec3Sub2(&v2v1, &b3MprSimplexPoint(portal, 2)->v,\n" +" &b3MprSimplexPoint(portal, 1)->v);\n" +" b3MprVec3Sub2(&v3v1, &b3MprSimplexPoint(portal, 3)->v,\n" +" &b3MprSimplexPoint(portal, 1)->v);\n" +" b3MprVec3Cross(dir, &v2v1, &v3v1);\n" +" b3MprVec3Normalize(dir);\n" +"}\n" +"inline int portalEncapsulesOrigin(const b3MprSimplex_t *portal,\n" +" const b3Float4 *dir)\n" +"{\n" +" float dot;\n" +" dot = b3MprVec3Dot(dir, &b3MprSimplexPoint(portal, 1)->v);\n" +" return b3MprIsZero(dot) || dot > 0.f;\n" +"}\n" +"inline int portalReachTolerance(const b3MprSimplex_t *portal,\n" +" const b3MprSupport_t *v4,\n" +" const b3Float4 *dir)\n" +"{\n" +" float dv1, dv2, dv3, dv4;\n" +" float dot1, dot2, dot3;\n" +" // find the smallest dot product of dir and {v1-v4, v2-v4, v3-v4}\n" +" dv1 = b3MprVec3Dot(&b3MprSimplexPoint(portal, 1)->v, dir);\n" +" dv2 = b3MprVec3Dot(&b3MprSimplexPoint(portal, 2)->v, dir);\n" +" dv3 = b3MprVec3Dot(&b3MprSimplexPoint(portal, 3)->v, dir);\n" +" dv4 = b3MprVec3Dot(&v4->v, dir);\n" +" dot1 = dv4 - dv1;\n" +" dot2 = dv4 - dv2;\n" +" dot3 = dv4 - dv3;\n" +" dot1 = B3_MPR_FMIN(dot1, dot2);\n" +" dot1 = B3_MPR_FMIN(dot1, dot3);\n" +" return b3MprEq(dot1, B3_MPR_TOLERANCE) || dot1 < B3_MPR_TOLERANCE;\n" +"}\n" +"inline int portalCanEncapsuleOrigin(const b3MprSimplex_t *portal, \n" +" const b3MprSupport_t *v4,\n" +" const b3Float4 *dir)\n" +"{\n" +" float dot;\n" +" dot = b3MprVec3Dot(&v4->v, dir);\n" +" return b3MprIsZero(dot) || dot > 0.f;\n" +"}\n" +"inline void b3ExpandPortal(b3MprSimplex_t *portal,\n" +" const b3MprSupport_t *v4)\n" +"{\n" +" float dot;\n" +" b3Float4 v4v0;\n" +" b3MprVec3Cross(&v4v0, &v4->v, &b3MprSimplexPoint(portal, 0)->v);\n" +" dot = b3MprVec3Dot(&b3MprSimplexPoint(portal, 1)->v, &v4v0);\n" +" if (dot > 0.f){\n" +" dot = b3MprVec3Dot(&b3MprSimplexPoint(portal, 2)->v, &v4v0);\n" +" if (dot > 0.f){\n" +" b3MprSimplexSet(portal, 1, v4);\n" +" }else{\n" +" b3MprSimplexSet(portal, 3, v4);\n" +" }\n" +" }else{\n" +" dot = b3MprVec3Dot(&b3MprSimplexPoint(portal, 3)->v, &v4v0);\n" +" if (dot > 0.f){\n" +" b3MprSimplexSet(portal, 2, v4);\n" +" }else{\n" +" b3MprSimplexSet(portal, 1, v4);\n" +" }\n" +" }\n" +"}\n" +"B3_STATIC int b3DiscoverPortal(int pairIndex, int bodyIndexA, int bodyIndexB, b3ConstArray(b3RigidBodyData_t) cpuBodyBuf, \n" +" b3ConstArray(b3ConvexPolyhedronData_t) cpuConvexData, \n" +" b3ConstArray(b3Collidable_t) cpuCollidables,\n" +" b3ConstArray(b3Float4) cpuVertices,\n" +" __global b3Float4* sepAxis,\n" +" __global int* hasSepAxis,\n" +" b3MprSimplex_t *portal)\n" +"{\n" +" b3Float4 dir, va, vb;\n" +" float dot;\n" +" int cont;\n" +" \n" +" \n" +" // vertex 0 is center of portal\n" +" b3FindOrigin(bodyIndexA,bodyIndexB,cpuBodyBuf, b3MprSimplexPointW(portal, 0));\n" +" // vertex 0 is center of portal\n" +" b3MprSimplexSetSize(portal, 1);\n" +" \n" +" b3Float4 zero = b3MakeFloat4(0,0,0,0);\n" +" b3Float4* b3mpr_vec3_origin = &zero;\n" +" if (b3MprVec3Eq(&b3MprSimplexPoint(portal, 0)->v, b3mpr_vec3_origin)){\n" +" // Portal's center lies on origin (0,0,0) => we know that objects\n" +" // intersect but we would need to know penetration info.\n" +" // So move center little bit...\n" +" b3MprVec3Set(&va, FLT_EPSILON * 10.f, 0.f, 0.f);\n" +" b3MprVec3Add(&b3MprSimplexPointW(portal, 0)->v, &va);\n" +" }\n" +" // vertex 1 = support in direction of origin\n" +" b3MprVec3Copy(&dir, &b3MprSimplexPoint(portal, 0)->v);\n" +" b3MprVec3Scale(&dir, -1.f);\n" +" b3MprVec3Normalize(&dir);\n" +" b3MprSupport(pairIndex,bodyIndexA,bodyIndexB,cpuBodyBuf,cpuConvexData,cpuCollidables,cpuVertices, sepAxis,&dir, b3MprSimplexPointW(portal, 1));\n" +" b3MprSimplexSetSize(portal, 2);\n" +" // test if origin isn't outside of v1\n" +" dot = b3MprVec3Dot(&b3MprSimplexPoint(portal, 1)->v, &dir);\n" +" \n" +" if (b3MprIsZero(dot) || dot < 0.f)\n" +" return -1;\n" +" // vertex 2\n" +" b3MprVec3Cross(&dir, &b3MprSimplexPoint(portal, 0)->v,\n" +" &b3MprSimplexPoint(portal, 1)->v);\n" +" if (b3MprIsZero(b3MprVec3Len2(&dir))){\n" +" if (b3MprVec3Eq(&b3MprSimplexPoint(portal, 1)->v, b3mpr_vec3_origin)){\n" +" // origin lies on v1\n" +" return 1;\n" +" }else{\n" +" // origin lies on v0-v1 segment\n" +" return 2;\n" +" }\n" +" }\n" +" b3MprVec3Normalize(&dir);\n" +" b3MprSupport(pairIndex,bodyIndexA,bodyIndexB,cpuBodyBuf,cpuConvexData,cpuCollidables,cpuVertices, sepAxis,&dir, b3MprSimplexPointW(portal, 2));\n" +" \n" +" dot = b3MprVec3Dot(&b3MprSimplexPoint(portal, 2)->v, &dir);\n" +" if (b3MprIsZero(dot) || dot < 0.f)\n" +" return -1;\n" +" b3MprSimplexSetSize(portal, 3);\n" +" // vertex 3 direction\n" +" b3MprVec3Sub2(&va, &b3MprSimplexPoint(portal, 1)->v,\n" +" &b3MprSimplexPoint(portal, 0)->v);\n" +" b3MprVec3Sub2(&vb, &b3MprSimplexPoint(portal, 2)->v,\n" +" &b3MprSimplexPoint(portal, 0)->v);\n" +" b3MprVec3Cross(&dir, &va, &vb);\n" +" b3MprVec3Normalize(&dir);\n" +" // it is better to form portal faces to be oriented \"outside\" origin\n" +" dot = b3MprVec3Dot(&dir, &b3MprSimplexPoint(portal, 0)->v);\n" +" if (dot > 0.f){\n" +" b3MprSimplexSwap(portal, 1, 2);\n" +" b3MprVec3Scale(&dir, -1.f);\n" +" }\n" +" while (b3MprSimplexSize(portal) < 4){\n" +" b3MprSupport(pairIndex,bodyIndexA,bodyIndexB,cpuBodyBuf,cpuConvexData,cpuCollidables,cpuVertices, sepAxis,&dir, b3MprSimplexPointW(portal, 3));\n" +" \n" +" dot = b3MprVec3Dot(&b3MprSimplexPoint(portal, 3)->v, &dir);\n" +" if (b3MprIsZero(dot) || dot < 0.f)\n" +" return -1;\n" +" cont = 0;\n" +" // test if origin is outside (v1, v0, v3) - set v2 as v3 and\n" +" // continue\n" +" b3MprVec3Cross(&va, &b3MprSimplexPoint(portal, 1)->v,\n" +" &b3MprSimplexPoint(portal, 3)->v);\n" +" dot = b3MprVec3Dot(&va, &b3MprSimplexPoint(portal, 0)->v);\n" +" if (dot < 0.f && !b3MprIsZero(dot)){\n" +" b3MprSimplexSet(portal, 2, b3MprSimplexPoint(portal, 3));\n" +" cont = 1;\n" +" }\n" +" if (!cont){\n" +" // test if origin is outside (v3, v0, v2) - set v1 as v3 and\n" +" // continue\n" +" b3MprVec3Cross(&va, &b3MprSimplexPoint(portal, 3)->v,\n" +" &b3MprSimplexPoint(portal, 2)->v);\n" +" dot = b3MprVec3Dot(&va, &b3MprSimplexPoint(portal, 0)->v);\n" +" if (dot < 0.f && !b3MprIsZero(dot)){\n" +" b3MprSimplexSet(portal, 1, b3MprSimplexPoint(portal, 3));\n" +" cont = 1;\n" +" }\n" +" }\n" +" if (cont){\n" +" b3MprVec3Sub2(&va, &b3MprSimplexPoint(portal, 1)->v,\n" +" &b3MprSimplexPoint(portal, 0)->v);\n" +" b3MprVec3Sub2(&vb, &b3MprSimplexPoint(portal, 2)->v,\n" +" &b3MprSimplexPoint(portal, 0)->v);\n" +" b3MprVec3Cross(&dir, &va, &vb);\n" +" b3MprVec3Normalize(&dir);\n" +" }else{\n" +" b3MprSimplexSetSize(portal, 4);\n" +" }\n" +" }\n" +" return 0;\n" +"}\n" +"B3_STATIC int b3RefinePortal(int pairIndex,int bodyIndexA, int bodyIndexB, b3ConstArray(b3RigidBodyData_t) cpuBodyBuf, \n" +" b3ConstArray(b3ConvexPolyhedronData_t) cpuConvexData, \n" +" b3ConstArray(b3Collidable_t) cpuCollidables,\n" +" b3ConstArray(b3Float4) cpuVertices,\n" +" __global b3Float4* sepAxis,\n" +" b3MprSimplex_t *portal)\n" +"{\n" +" b3Float4 dir;\n" +" b3MprSupport_t v4;\n" +" for (int i=0;iv,\n" +" &b3MprSimplexPoint(portal, 2)->v);\n" +" b[0] = b3MprVec3Dot(&vec, &b3MprSimplexPoint(portal, 3)->v);\n" +" b3MprVec3Cross(&vec, &b3MprSimplexPoint(portal, 3)->v,\n" +" &b3MprSimplexPoint(portal, 2)->v);\n" +" b[1] = b3MprVec3Dot(&vec, &b3MprSimplexPoint(portal, 0)->v);\n" +" b3MprVec3Cross(&vec, &b3MprSimplexPoint(portal, 0)->v,\n" +" &b3MprSimplexPoint(portal, 1)->v);\n" +" b[2] = b3MprVec3Dot(&vec, &b3MprSimplexPoint(portal, 3)->v);\n" +" b3MprVec3Cross(&vec, &b3MprSimplexPoint(portal, 2)->v,\n" +" &b3MprSimplexPoint(portal, 1)->v);\n" +" b[3] = b3MprVec3Dot(&vec, &b3MprSimplexPoint(portal, 0)->v);\n" +" sum = b[0] + b[1] + b[2] + b[3];\n" +" if (b3MprIsZero(sum) || sum < 0.f){\n" +" b[0] = 0.f;\n" +" b3MprVec3Cross(&vec, &b3MprSimplexPoint(portal, 2)->v,\n" +" &b3MprSimplexPoint(portal, 3)->v);\n" +" b[1] = b3MprVec3Dot(&vec, &dir);\n" +" b3MprVec3Cross(&vec, &b3MprSimplexPoint(portal, 3)->v,\n" +" &b3MprSimplexPoint(portal, 1)->v);\n" +" b[2] = b3MprVec3Dot(&vec, &dir);\n" +" b3MprVec3Cross(&vec, &b3MprSimplexPoint(portal, 1)->v,\n" +" &b3MprSimplexPoint(portal, 2)->v);\n" +" b[3] = b3MprVec3Dot(&vec, &dir);\n" +" sum = b[1] + b[2] + b[3];\n" +" }\n" +" inv = 1.f / sum;\n" +" b3MprVec3Copy(&p1, b3mpr_vec3_origin);\n" +" b3MprVec3Copy(&p2, b3mpr_vec3_origin);\n" +" for (i = 0; i < 4; i++){\n" +" b3MprVec3Copy(&vec, &b3MprSimplexPoint(portal, i)->v1);\n" +" b3MprVec3Scale(&vec, b[i]);\n" +" b3MprVec3Add(&p1, &vec);\n" +" b3MprVec3Copy(&vec, &b3MprSimplexPoint(portal, i)->v2);\n" +" b3MprVec3Scale(&vec, b[i]);\n" +" b3MprVec3Add(&p2, &vec);\n" +" }\n" +" b3MprVec3Scale(&p1, inv);\n" +" b3MprVec3Scale(&p2, inv);\n" +" b3MprVec3Copy(pos, &p1);\n" +" b3MprVec3Add(pos, &p2);\n" +" b3MprVec3Scale(pos, 0.5);\n" +"}\n" +"inline float b3MprVec3Dist2(const b3Float4 *a, const b3Float4 *b)\n" +"{\n" +" b3Float4 ab;\n" +" b3MprVec3Sub2(&ab, a, b);\n" +" return b3MprVec3Len2(&ab);\n" +"}\n" +"inline float _b3MprVec3PointSegmentDist2(const b3Float4 *P,\n" +" const b3Float4 *x0,\n" +" const b3Float4 *b,\n" +" b3Float4 *witness)\n" +"{\n" +" // The computation comes from solving equation of segment:\n" +" // S(t) = x0 + t.d\n" +" // where - x0 is initial point of segment\n" +" // - d is direction of segment from x0 (|d| > 0)\n" +" // - t belongs to <0, 1> interval\n" +" // \n" +" // Than, distance from a segment to some point P can be expressed:\n" +" // D(t) = |x0 + t.d - P|^2\n" +" // which is distance from any point on segment. Minimization\n" +" // of this function brings distance from P to segment.\n" +" // Minimization of D(t) leads to simple quadratic equation that's\n" +" // solving is straightforward.\n" +" //\n" +" // Bonus of this method is witness point for free.\n" +" float dist, t;\n" +" b3Float4 d, a;\n" +" // direction of segment\n" +" b3MprVec3Sub2(&d, b, x0);\n" +" // precompute vector from P to x0\n" +" b3MprVec3Sub2(&a, x0, P);\n" +" t = -1.f * b3MprVec3Dot(&a, &d);\n" +" t /= b3MprVec3Len2(&d);\n" +" if (t < 0.f || b3MprIsZero(t)){\n" +" dist = b3MprVec3Dist2(x0, P);\n" +" if (witness)\n" +" b3MprVec3Copy(witness, x0);\n" +" }else if (t > 1.f || b3MprEq(t, 1.f)){\n" +" dist = b3MprVec3Dist2(b, P);\n" +" if (witness)\n" +" b3MprVec3Copy(witness, b);\n" +" }else{\n" +" if (witness){\n" +" b3MprVec3Copy(witness, &d);\n" +" b3MprVec3Scale(witness, t);\n" +" b3MprVec3Add(witness, x0);\n" +" dist = b3MprVec3Dist2(witness, P);\n" +" }else{\n" +" // recycling variables\n" +" b3MprVec3Scale(&d, t);\n" +" b3MprVec3Add(&d, &a);\n" +" dist = b3MprVec3Len2(&d);\n" +" }\n" +" }\n" +" return dist;\n" +"}\n" +"inline float b3MprVec3PointTriDist2(const b3Float4 *P,\n" +" const b3Float4 *x0, const b3Float4 *B,\n" +" const b3Float4 *C,\n" +" b3Float4 *witness)\n" +"{\n" +" // Computation comes from analytic expression for triangle (x0, B, C)\n" +" // T(s, t) = x0 + s.d1 + t.d2, where d1 = B - x0 and d2 = C - x0 and\n" +" // Then equation for distance is:\n" +" // D(s, t) = | T(s, t) - P |^2\n" +" // This leads to minimization of quadratic function of two variables.\n" +" // The solution from is taken only if s is between 0 and 1, t is\n" +" // between 0 and 1 and t + s < 1, otherwise distance from segment is\n" +" // computed.\n" +" b3Float4 d1, d2, a;\n" +" float u, v, w, p, q, r;\n" +" float s, t, dist, dist2;\n" +" b3Float4 witness2;\n" +" b3MprVec3Sub2(&d1, B, x0);\n" +" b3MprVec3Sub2(&d2, C, x0);\n" +" b3MprVec3Sub2(&a, x0, P);\n" +" u = b3MprVec3Dot(&a, &a);\n" +" v = b3MprVec3Dot(&d1, &d1);\n" +" w = b3MprVec3Dot(&d2, &d2);\n" +" p = b3MprVec3Dot(&a, &d1);\n" +" q = b3MprVec3Dot(&a, &d2);\n" +" r = b3MprVec3Dot(&d1, &d2);\n" +" s = (q * r - w * p) / (w * v - r * r);\n" +" t = (-s * r - q) / w;\n" +" if ((b3MprIsZero(s) || s > 0.f)\n" +" && (b3MprEq(s, 1.f) || s < 1.f)\n" +" && (b3MprIsZero(t) || t > 0.f)\n" +" && (b3MprEq(t, 1.f) || t < 1.f)\n" +" && (b3MprEq(t + s, 1.f) || t + s < 1.f)){\n" +" if (witness){\n" +" b3MprVec3Scale(&d1, s);\n" +" b3MprVec3Scale(&d2, t);\n" +" b3MprVec3Copy(witness, x0);\n" +" b3MprVec3Add(witness, &d1);\n" +" b3MprVec3Add(witness, &d2);\n" +" dist = b3MprVec3Dist2(witness, P);\n" +" }else{\n" +" dist = s * s * v;\n" +" dist += t * t * w;\n" +" dist += 2.f * s * t * r;\n" +" dist += 2.f * s * p;\n" +" dist += 2.f * t * q;\n" +" dist += u;\n" +" }\n" +" }else{\n" +" dist = _b3MprVec3PointSegmentDist2(P, x0, B, witness);\n" +" dist2 = _b3MprVec3PointSegmentDist2(P, x0, C, &witness2);\n" +" if (dist2 < dist){\n" +" dist = dist2;\n" +" if (witness)\n" +" b3MprVec3Copy(witness, &witness2);\n" +" }\n" +" dist2 = _b3MprVec3PointSegmentDist2(P, B, C, &witness2);\n" +" if (dist2 < dist){\n" +" dist = dist2;\n" +" if (witness)\n" +" b3MprVec3Copy(witness, &witness2);\n" +" }\n" +" }\n" +" return dist;\n" +"}\n" +"B3_STATIC void b3FindPenetr(int pairIndex,int bodyIndexA, int bodyIndexB, b3ConstArray(b3RigidBodyData_t) cpuBodyBuf, \n" +" b3ConstArray(b3ConvexPolyhedronData_t) cpuConvexData, \n" +" b3ConstArray(b3Collidable_t) cpuCollidables,\n" +" b3ConstArray(b3Float4) cpuVertices,\n" +" __global b3Float4* sepAxis,\n" +" b3MprSimplex_t *portal,\n" +" float *depth, b3Float4 *pdir, b3Float4 *pos)\n" +"{\n" +" b3Float4 dir;\n" +" b3MprSupport_t v4;\n" +" unsigned long iterations;\n" +" b3Float4 zero = b3MakeFloat4(0,0,0,0);\n" +" b3Float4* b3mpr_vec3_origin = &zero;\n" +" iterations = 1UL;\n" +" for (int i=0;i find penetration info\n" +" if (portalReachTolerance(portal, &v4, &dir)\n" +" || iterations ==B3_MPR_MAX_ITERATIONS)\n" +" {\n" +" *depth = b3MprVec3PointTriDist2(b3mpr_vec3_origin,&b3MprSimplexPoint(portal, 1)->v,&b3MprSimplexPoint(portal, 2)->v,&b3MprSimplexPoint(portal, 3)->v,pdir);\n" +" *depth = B3_MPR_SQRT(*depth);\n" +" \n" +" if (b3MprIsZero((*pdir).x) && b3MprIsZero((*pdir).y) && b3MprIsZero((*pdir).z))\n" +" {\n" +" \n" +" *pdir = dir;\n" +" } \n" +" b3MprVec3Normalize(pdir);\n" +" \n" +" // barycentric coordinates:\n" +" b3FindPos(portal, pos);\n" +" return;\n" +" }\n" +" b3ExpandPortal(portal, &v4);\n" +" iterations++;\n" +" }\n" +"}\n" +"B3_STATIC void b3FindPenetrTouch(b3MprSimplex_t *portal,float *depth, b3Float4 *dir, b3Float4 *pos)\n" +"{\n" +" // Touching contact on portal's v1 - so depth is zero and direction\n" +" // is unimportant and pos can be guessed\n" +" *depth = 0.f;\n" +" b3Float4 zero = b3MakeFloat4(0,0,0,0);\n" +" b3Float4* b3mpr_vec3_origin = &zero;\n" +" b3MprVec3Copy(dir, b3mpr_vec3_origin);\n" +" b3MprVec3Copy(pos, &b3MprSimplexPoint(portal, 1)->v1);\n" +" b3MprVec3Add(pos, &b3MprSimplexPoint(portal, 1)->v2);\n" +" b3MprVec3Scale(pos, 0.5);\n" +"}\n" +"B3_STATIC void b3FindPenetrSegment(b3MprSimplex_t *portal,\n" +" float *depth, b3Float4 *dir, b3Float4 *pos)\n" +"{\n" +" \n" +" // Origin lies on v0-v1 segment.\n" +" // Depth is distance to v1, direction also and position must be\n" +" // computed\n" +" b3MprVec3Copy(pos, &b3MprSimplexPoint(portal, 1)->v1);\n" +" b3MprVec3Add(pos, &b3MprSimplexPoint(portal, 1)->v2);\n" +" b3MprVec3Scale(pos, 0.5f);\n" +" \n" +" b3MprVec3Copy(dir, &b3MprSimplexPoint(portal, 1)->v);\n" +" *depth = B3_MPR_SQRT(b3MprVec3Len2(dir));\n" +" b3MprVec3Normalize(dir);\n" +"}\n" +"inline int b3MprPenetration(int pairIndex, int bodyIndexA, int bodyIndexB,\n" +" b3ConstArray(b3RigidBodyData_t) cpuBodyBuf,\n" +" b3ConstArray(b3ConvexPolyhedronData_t) cpuConvexData, \n" +" b3ConstArray(b3Collidable_t) cpuCollidables,\n" +" b3ConstArray(b3Float4) cpuVertices,\n" +" __global b3Float4* sepAxis,\n" +" __global int* hasSepAxis,\n" +" float *depthOut, b3Float4* dirOut, b3Float4* posOut)\n" +"{\n" +" \n" +" b3MprSimplex_t portal;\n" +" \n" +"// if (!hasSepAxis[pairIndex])\n" +" // return -1;\n" +" \n" +" hasSepAxis[pairIndex] = 0;\n" +" int res;\n" +" // Phase 1: Portal discovery\n" +" res = b3DiscoverPortal(pairIndex,bodyIndexA,bodyIndexB,cpuBodyBuf,cpuConvexData,cpuCollidables,cpuVertices,sepAxis,hasSepAxis, &portal);\n" +" \n" +" \n" +" //sepAxis[pairIndex] = *pdir;//or -dir?\n" +" switch (res)\n" +" {\n" +" case 0:\n" +" {\n" +" // Phase 2: Portal refinement\n" +" \n" +" res = b3RefinePortal(pairIndex,bodyIndexA,bodyIndexB,cpuBodyBuf,cpuConvexData,cpuCollidables,cpuVertices, sepAxis,&portal);\n" +" if (res < 0)\n" +" return -1;\n" +" // Phase 3. Penetration info\n" +" b3FindPenetr(pairIndex,bodyIndexA,bodyIndexB,cpuBodyBuf,cpuConvexData,cpuCollidables,cpuVertices, sepAxis,&portal, depthOut, dirOut, posOut);\n" +" hasSepAxis[pairIndex] = 1;\n" +" sepAxis[pairIndex] = -*dirOut;\n" +" break;\n" +" }\n" +" case 1:\n" +" {\n" +" // Touching contact on portal's v1.\n" +" b3FindPenetrTouch(&portal, depthOut, dirOut, posOut);\n" +" break;\n" +" }\n" +" case 2:\n" +" {\n" +" \n" +" b3FindPenetrSegment( &portal, depthOut, dirOut, posOut);\n" +" break;\n" +" }\n" +" default:\n" +" {\n" +" hasSepAxis[pairIndex]=0;\n" +" //if (res < 0)\n" +" //{\n" +" // Origin isn't inside portal - no collision.\n" +" return -1;\n" +" //}\n" +" }\n" +" };\n" +" \n" +" return 0;\n" +"};\n" +"#endif //B3_MPR_PENETRATION_H\n" +"#ifndef B3_CONTACT4DATA_H\n" +"#define B3_CONTACT4DATA_H\n" +"#ifndef B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_FLOAT4_H\n" +"typedef struct b3Contact4Data b3Contact4Data_t;\n" +"struct b3Contact4Data\n" +"{\n" +" b3Float4 m_worldPosB[4];\n" +"// b3Float4 m_localPosA[4];\n" +"// b3Float4 m_localPosB[4];\n" +" b3Float4 m_worldNormalOnB; // w: m_nPoints\n" +" unsigned short m_restituitionCoeffCmp;\n" +" unsigned short m_frictionCoeffCmp;\n" +" int m_batchIdx;\n" +" int m_bodyAPtrAndSignBit;//x:m_bodyAPtr, y:m_bodyBPtr\n" +" int m_bodyBPtrAndSignBit;\n" +" int m_childIndexA;\n" +" int m_childIndexB;\n" +" int m_unused1;\n" +" int m_unused2;\n" +"};\n" +"inline int b3Contact4Data_getNumPoints(const struct b3Contact4Data* contact)\n" +"{\n" +" return (int)contact->m_worldNormalOnB.w;\n" +"};\n" +"inline void b3Contact4Data_setNumPoints(struct b3Contact4Data* contact, int numPoints)\n" +"{\n" +" contact->m_worldNormalOnB.w = (float)numPoints;\n" +"};\n" +"#endif //B3_CONTACT4DATA_H\n" +"#define AppendInc(x, out) out = atomic_inc(x)\n" +"#define GET_NPOINTS(x) (x).m_worldNormalOnB.w\n" +"#ifdef cl_ext_atomic_counters_32\n" +" #pragma OPENCL EXTENSION cl_ext_atomic_counters_32 : enable\n" +"#else\n" +" #define counter32_t volatile __global int*\n" +"#endif\n" +"__kernel void mprPenetrationKernel( __global int4* pairs,\n" +" __global const b3RigidBodyData_t* rigidBodies, \n" +" __global const b3Collidable_t* collidables,\n" +" __global const b3ConvexPolyhedronData_t* convexShapes, \n" +" __global const float4* vertices,\n" +" __global float4* separatingNormals,\n" +" __global int* hasSeparatingAxis,\n" +" __global struct b3Contact4Data* restrict globalContactsOut,\n" +" counter32_t nGlobalContactsOut,\n" +" int contactCapacity,\n" +" int numPairs)\n" +"{\n" +" int i = get_global_id(0);\n" +" int pairIndex = i;\n" +" if (im_worldNormalOnB = -dirOut;//normal;\n" +" c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff);\n" +" c->m_batchIdx = pairIndex;\n" +" int bodyA = pairs[pairIndex].x;\n" +" int bodyB = pairs[pairIndex].y;\n" +" c->m_bodyAPtrAndSignBit = rigidBodies[bodyA].m_invMass==0 ? -bodyA:bodyA;\n" +" c->m_bodyBPtrAndSignBit = rigidBodies[bodyB].m_invMass==0 ? -bodyB:bodyB;\n" +" c->m_childIndexA = -1;\n" +" c->m_childIndexB = -1;\n" +" //for (int i=0;im_worldPosB[0] = posOut;//localPoints[contactIdx[i]];\n" +" GET_NPOINTS(*c) = 1;//nContacts;\n" +" }\n" +" }\n" +" }\n" +"}\n" +"typedef float4 Quaternion;\n" +"#define make_float4 (float4)\n" +"__inline\n" +"float dot3F4(float4 a, float4 b)\n" +"{\n" +" float4 a1 = make_float4(a.xyz,0.f);\n" +" float4 b1 = make_float4(b.xyz,0.f);\n" +" return dot(a1, b1);\n" +"}\n" +"__inline\n" +"float4 cross3(float4 a, float4 b)\n" +"{\n" +" return cross(a,b);\n" +"}\n" +"__inline\n" +"Quaternion qtMul(Quaternion a, Quaternion b)\n" +"{\n" +" Quaternion ans;\n" +" ans = cross3( a, b );\n" +" ans += a.w*b+b.w*a;\n" +"// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z);\n" +" ans.w = a.w*b.w - dot3F4(a, b);\n" +" return ans;\n" +"}\n" +"__inline\n" +"Quaternion qtInvert(Quaternion q)\n" +"{\n" +" return (Quaternion)(-q.xyz, q.w);\n" +"}\n" +"__inline\n" +"float4 qtRotate(Quaternion q, float4 vec)\n" +"{\n" +" Quaternion qInv = qtInvert( q );\n" +" float4 vcpy = vec;\n" +" vcpy.w = 0.f;\n" +" float4 out = qtMul(qtMul(q,vcpy),qInv);\n" +" return out;\n" +"}\n" +"__inline\n" +"float4 transform(const float4* p, const float4* translation, const Quaternion* orientation)\n" +"{\n" +" return qtRotate( *orientation, *p ) + (*translation);\n" +"}\n" +"__inline\n" +"float4 qtInvRotate(const Quaternion q, float4 vec)\n" +"{\n" +" return qtRotate( qtInvert( q ), vec );\n" +"}\n" +"inline void project(__global const b3ConvexPolyhedronData_t* hull, const float4 pos, const float4 orn, \n" +"const float4* dir, __global const float4* vertices, float* min, float* max)\n" +"{\n" +" min[0] = FLT_MAX;\n" +" max[0] = -FLT_MAX;\n" +" int numVerts = hull->m_numVertices;\n" +" const float4 localDir = qtInvRotate(orn,*dir);\n" +" float offset = dot(pos,*dir);\n" +" for(int i=0;im_vertexOffset+i],localDir);\n" +" if(dp < min[0]) \n" +" min[0] = dp;\n" +" if(dp > max[0]) \n" +" max[0] = dp;\n" +" }\n" +" if(min[0]>max[0])\n" +" {\n" +" float tmp = min[0];\n" +" min[0] = max[0];\n" +" max[0] = tmp;\n" +" }\n" +" min[0] += offset;\n" +" max[0] += offset;\n" +"}\n" +"bool findSeparatingAxisUnitSphere( __global const b3ConvexPolyhedronData_t* hullA, __global const b3ConvexPolyhedronData_t* hullB, \n" +" const float4 posA1,\n" +" const float4 ornA,\n" +" const float4 posB1,\n" +" const float4 ornB,\n" +" const float4 DeltaC2,\n" +" __global const float4* vertices,\n" +" __global const float4* unitSphereDirections,\n" +" int numUnitSphereDirections,\n" +" float4* sep,\n" +" float* dmin)\n" +"{\n" +" \n" +" float4 posA = posA1;\n" +" posA.w = 0.f;\n" +" float4 posB = posB1;\n" +" posB.w = 0.f;\n" +" int curPlaneTests=0;\n" +" int curEdgeEdge = 0;\n" +" // Test unit sphere directions\n" +" for (int i=0;i0)\n" +" crossje *= -1.f;\n" +" {\n" +" float dist;\n" +" bool result = true;\n" +" float Min0,Max0;\n" +" float Min1,Max1;\n" +" project(hullA,posA,ornA,&crossje,vertices, &Min0, &Max0);\n" +" project(hullB,posB,ornB,&crossje,vertices, &Min1, &Max1);\n" +" \n" +" if(Max00.0f)\n" +" {\n" +" *sep = -(*sep);\n" +" }\n" +" return true;\n" +"}\n" +"__kernel void findSeparatingAxisUnitSphereKernel( __global const int4* pairs, \n" +" __global const b3RigidBodyData_t* rigidBodies, \n" +" __global const b3Collidable_t* collidables,\n" +" __global const b3ConvexPolyhedronData_t* convexShapes, \n" +" __global const float4* vertices,\n" +" __global const float4* unitSphereDirections,\n" +" __global float4* separatingNormals,\n" +" __global int* hasSeparatingAxis,\n" +" __global float* dmins,\n" +" int numUnitSphereDirections,\n" +" int numPairs\n" +" )\n" +"{\n" +" int i = get_global_id(0);\n" +" \n" +" if (inumUnitSphereDirections)\n" +" {\n" +" bool sepEE = findSeparatingAxisUnitSphere( &convexShapes[shapeIndexA], &convexShapes[shapeIndexB],posA,ornA,\n" +" posB,ornB,\n" +" DeltaC2,\n" +" vertices,unitSphereDirections,numUnitSphereDirections,&sepNormal,&dmin);\n" +" if (!sepEE)\n" +" {\n" +" hasSeparatingAxis[i] = 0;\n" +" } else\n" +" {\n" +" hasSeparatingAxis[i] = 1;\n" +" separatingNormals[i] = sepNormal;\n" +" }\n" +" }\n" +" } //if (hasSeparatingAxis[i])\n" +" }//(im_plane.x,face->m_plane.y,face->m_plane.z,0.f); + + if (face->m_numIndices<2) + return false; + + + float4 v0 = baseVertex[convexIndices[face->m_indexOffset + face->m_numIndices-1]]; + + b = v0; + + for(unsigned i=0; i != face->m_numIndices; ++i) + { + a = b; + float4 vi = baseVertex[convexIndices[face->m_indexOffset + i]]; + b = vi; + ab = b-a; + ap = p-a; + v = cross3(ab,plane); + + if (dot(ap, v) > 0.f) + { + float ab_m2 = dot(ab, ab); + float rt = ab_m2 != 0.f ? dot(ab, ap) / ab_m2 : 0.f; + if (rt <= 0.f) + { + *out = a; + } + else if (rt >= 1.f) + { + *out = b; + } + else + { + float s = 1.f - rt; + out[0].x = s * a.x + rt * b.x; + out[0].y = s * a.y + rt * b.y; + out[0].z = s * a.z + rt * b.z; + } + return false; + } + } + return true; +} + + + + +void computeContactSphereConvex(int pairIndex, + int bodyIndexA, int bodyIndexB, + int collidableIndexA, int collidableIndexB, + __global const BodyData* rigidBodies, + __global const btCollidableGpu* collidables, + __global const ConvexPolyhedronCL* convexShapes, + __global const float4* convexVertices, + __global const int* convexIndices, + __global const btGpuFace* faces, + __global struct b3Contact4Data* restrict globalContactsOut, + counter32_t nGlobalContactsOut, + int maxContactCapacity, + float4 spherePos2, + float radius, + float4 pos, + float4 quat + ) +{ + + float4 invPos; + float4 invOrn; + + trInverse(pos,quat, &invPos,&invOrn); + + float4 spherePos = transform(&spherePos2,&invPos,&invOrn); + + int shapeIndex = collidables[collidableIndexB].m_shapeIndex; + int numFaces = convexShapes[shapeIndex].m_numFaces; + float4 closestPnt = (float4)(0, 0, 0, 0); + float4 hitNormalWorld = (float4)(0, 0, 0, 0); + float minDist = -1000000.f; + bool bCollide = true; + + for ( int f = 0; f < numFaces; f++ ) + { + btGpuFace face = faces[convexShapes[shapeIndex].m_faceOffset+f]; + + // set up a plane equation + float4 planeEqn; + float4 n1 = face.m_plane; + n1.w = 0.f; + planeEqn = n1; + planeEqn.w = face.m_plane.w; + + + // compute a signed distance from the vertex in cloth to the face of rigidbody. + float4 pntReturn; + float dist = signedDistanceFromPointToPlane(spherePos, planeEqn, &pntReturn); + + // If the distance is positive, the plane is a separating plane. + if ( dist > radius ) + { + bCollide = false; + break; + } + + + if (dist>0) + { + //might hit an edge or vertex + float4 out; + float4 zeroPos = make_float4(0,0,0,0); + + bool isInPoly = IsPointInPolygon(spherePos, + &face, + &convexVertices[convexShapes[shapeIndex].m_vertexOffset], + convexIndices, + &out); + if (isInPoly) + { + if (dist>minDist) + { + minDist = dist; + closestPnt = pntReturn; + hitNormalWorld = planeEqn; + + } + } else + { + float4 tmp = spherePos-out; + float l2 = dot(tmp,tmp); + if (l2minDist) + { + minDist = dist; + closestPnt = out; + hitNormalWorld = tmp/dist; + + } + + } else + { + bCollide = false; + break; + } + } + } else + { + if ( dist > minDist ) + { + minDist = dist; + closestPnt = pntReturn; + hitNormalWorld.xyz = planeEqn.xyz; + } + } + + } + + + + if (bCollide && minDist > -10000) + { + float4 normalOnSurfaceB1 = qtRotate(quat,-hitNormalWorld); + float4 pOnB1 = transform(&closestPnt,&pos,&quat); + + float actualDepth = minDist-radius; + if (actualDepth<=0.f) + { + + + pOnB1.w = actualDepth; + + int dstIdx; + AppendInc( nGlobalContactsOut, dstIdx ); + + + if (1)//dstIdx < maxContactCapacity) + { + __global struct b3Contact4Data* c = &globalContactsOut[dstIdx]; + c->m_worldNormalOnB = -normalOnSurfaceB1; + c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff); + c->m_batchIdx = pairIndex; + c->m_bodyAPtrAndSignBit = rigidBodies[bodyIndexA].m_invMass==0?-bodyIndexA:bodyIndexA; + c->m_bodyBPtrAndSignBit = rigidBodies[bodyIndexB].m_invMass==0?-bodyIndexB:bodyIndexB; + c->m_worldPosB[0] = pOnB1; + c->m_childIndexA = -1; + c->m_childIndexB = -1; + + GET_NPOINTS(*c) = 1; + } + + } + }//if (hasCollision) + +} + + + +int extractManifoldSequential(const float4* p, int nPoints, float4 nearNormal, int4* contactIdx) +{ + if( nPoints == 0 ) + return 0; + + if (nPoints <=4) + return nPoints; + + + if (nPoints >64) + nPoints = 64; + + float4 center = make_float4(0.f); + { + + for (int i=0;im_numVertices;i++) + { + float4 vtx = convexVertices[hullB->m_vertexOffset+i]; + float curDot = dot(vtx,planeNormalInConvex); + + + if (curDot>maxDot) + { + hitVertex=i; + maxDot=curDot; + hitVtx = vtx; + //make sure the deepest points is always included + if (numPoints==MAX_PLANE_CONVEX_POINTS) + numPoints--; + } + + if (numPoints4) + { + numReducedPoints = extractManifoldSequential( contactPoints, numPoints, planeNormalInConvex, &contactIdx); + } + + if (numReducedPoints>0) + { + int dstIdx; + AppendInc( nGlobalContactsOut, dstIdx ); + + if (dstIdx < maxContactCapacity) + { + resultIndex = dstIdx; + __global struct b3Contact4Data* c = &globalContactsOut[dstIdx]; + c->m_worldNormalOnB = -planeNormalWorld; + //c->setFrictionCoeff(0.7); + //c->setRestituitionCoeff(0.f); + c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff); + c->m_batchIdx = pairIndex; + c->m_bodyAPtrAndSignBit = rigidBodies[bodyIndexA].m_invMass==0?-bodyIndexA:bodyIndexA; + c->m_bodyBPtrAndSignBit = rigidBodies[bodyIndexB].m_invMass==0?-bodyIndexB:bodyIndexB; + c->m_childIndexA = -1; + c->m_childIndexB = -1; + + switch (numReducedPoints) + { + case 4: + c->m_worldPosB[3] = contactPoints[contactIdx.w]; + case 3: + c->m_worldPosB[2] = contactPoints[contactIdx.z]; + case 2: + c->m_worldPosB[1] = contactPoints[contactIdx.y]; + case 1: + c->m_worldPosB[0] = contactPoints[contactIdx.x]; + default: + { + } + }; + + GET_NPOINTS(*c) = numReducedPoints; + }//if (dstIdx < numPairs) + } + + return resultIndex; +} + + +void computeContactPlaneSphere(int pairIndex, + int bodyIndexA, int bodyIndexB, + int collidableIndexA, int collidableIndexB, + __global const BodyData* rigidBodies, + __global const btCollidableGpu* collidables, + __global const btGpuFace* faces, + __global struct b3Contact4Data* restrict globalContactsOut, + counter32_t nGlobalContactsOut, + int maxContactCapacity) +{ + float4 planeEq = faces[collidables[collidableIndexA].m_shapeIndex].m_plane; + float radius = collidables[collidableIndexB].m_radius; + float4 posA1 = rigidBodies[bodyIndexA].m_pos; + float4 ornA1 = rigidBodies[bodyIndexA].m_quat; + float4 posB1 = rigidBodies[bodyIndexB].m_pos; + float4 ornB1 = rigidBodies[bodyIndexB].m_quat; + + bool hasCollision = false; + float4 planeNormal1 = make_float4(planeEq.x,planeEq.y,planeEq.z,0.f); + float planeConstant = planeEq.w; + float4 convexInPlaneTransPos1; Quaternion convexInPlaneTransOrn1; + { + float4 invPosA;Quaternion invOrnA; + trInverse(posA1,ornA1,&invPosA,&invOrnA); + trMul(invPosA,invOrnA,posB1,ornB1,&convexInPlaneTransPos1,&convexInPlaneTransOrn1); + } + float4 planeInConvexPos1; Quaternion planeInConvexOrn1; + { + float4 invPosB;Quaternion invOrnB; + trInverse(posB1,ornB1,&invPosB,&invOrnB); + trMul(invPosB,invOrnB,posA1,ornA1,&planeInConvexPos1,&planeInConvexOrn1); + } + float4 vtx1 = qtRotate(planeInConvexOrn1,-planeNormal1)*radius; + float4 vtxInPlane1 = transform(&vtx1,&convexInPlaneTransPos1,&convexInPlaneTransOrn1); + float distance = dot3F4(planeNormal1,vtxInPlane1) - planeConstant; + hasCollision = distance < 0.f;//m_manifoldPtr->getContactBreakingThreshold(); + if (hasCollision) + { + float4 vtxInPlaneProjected1 = vtxInPlane1 - distance*planeNormal1; + float4 vtxInPlaneWorld1 = transform(&vtxInPlaneProjected1,&posA1,&ornA1); + float4 normalOnSurfaceB1 = qtRotate(ornA1,planeNormal1); + float4 pOnB1 = vtxInPlaneWorld1+normalOnSurfaceB1*distance; + pOnB1.w = distance; + + int dstIdx; + AppendInc( nGlobalContactsOut, dstIdx ); + + if (dstIdx < maxContactCapacity) + { + __global struct b3Contact4Data* c = &globalContactsOut[dstIdx]; + c->m_worldNormalOnB = -normalOnSurfaceB1; + c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff); + c->m_batchIdx = pairIndex; + c->m_bodyAPtrAndSignBit = rigidBodies[bodyIndexA].m_invMass==0?-bodyIndexA:bodyIndexA; + c->m_bodyBPtrAndSignBit = rigidBodies[bodyIndexB].m_invMass==0?-bodyIndexB:bodyIndexB; + c->m_worldPosB[0] = pOnB1; + c->m_childIndexA = -1; + c->m_childIndexB = -1; + GET_NPOINTS(*c) = 1; + }//if (dstIdx < numPairs) + }//if (hasCollision) +} + + +__kernel void primitiveContactsKernel( __global int4* pairs, + __global const BodyData* rigidBodies, + __global const btCollidableGpu* collidables, + __global const ConvexPolyhedronCL* convexShapes, + __global const float4* vertices, + __global const float4* uniqueEdges, + __global const btGpuFace* faces, + __global const int* indices, + __global struct b3Contact4Data* restrict globalContactsOut, + counter32_t nGlobalContactsOut, + int numPairs, int maxContactCapacity) +{ + + int i = get_global_id(0); + int pairIndex = i; + + float4 worldVertsB1[64]; + float4 worldVertsB2[64]; + int capacityWorldVerts = 64; + + float4 localContactsOut[64]; + int localContactCapacity=64; + + float minDist = -1e30f; + float maxDist = 0.02f; + + if (i=0) + pairs[pairIndex].z = contactIndex; + + return; + } + + + if (collidables[collidableIndexA].m_shapeType == SHAPE_CONVEX_HULL && + collidables[collidableIndexB].m_shapeType == SHAPE_PLANE) + { + + float4 posA; + posA = rigidBodies[bodyIndexA].m_pos; + Quaternion ornA; + ornA = rigidBodies[bodyIndexA].m_quat; + + + int contactIndex = computeContactPlaneConvex( pairIndex, bodyIndexB,bodyIndexA, collidableIndexB,collidableIndexA, + rigidBodies,collidables,convexShapes,vertices,indices, + faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity,posA,ornA); + + if (contactIndex>=0) + pairs[pairIndex].z = contactIndex; + + return; + } + + if (collidables[collidableIndexA].m_shapeType == SHAPE_PLANE && + collidables[collidableIndexB].m_shapeType == SHAPE_SPHERE) + { + computeContactPlaneSphere(pairIndex, bodyIndexA, bodyIndexB, collidableIndexA, collidableIndexB, + rigidBodies,collidables,faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity); + return; + } + + + if (collidables[collidableIndexA].m_shapeType == SHAPE_SPHERE && + collidables[collidableIndexB].m_shapeType == SHAPE_PLANE) + { + + + computeContactPlaneSphere( pairIndex, bodyIndexB,bodyIndexA, collidableIndexB,collidableIndexA, + rigidBodies,collidables, + faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity); + + return; + } + + + + + if (collidables[collidableIndexA].m_shapeType == SHAPE_SPHERE && + collidables[collidableIndexB].m_shapeType == SHAPE_CONVEX_HULL) + { + + float4 spherePos = rigidBodies[bodyIndexA].m_pos; + float sphereRadius = collidables[collidableIndexA].m_radius; + float4 convexPos = rigidBodies[bodyIndexB].m_pos; + float4 convexOrn = rigidBodies[bodyIndexB].m_quat; + + computeContactSphereConvex(pairIndex, bodyIndexA, bodyIndexB, collidableIndexA, collidableIndexB, + rigidBodies,collidables,convexShapes,vertices,indices,faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity, + spherePos,sphereRadius,convexPos,convexOrn); + + return; + } + + if (collidables[collidableIndexA].m_shapeType == SHAPE_CONVEX_HULL && + collidables[collidableIndexB].m_shapeType == SHAPE_SPHERE) + { + + float4 spherePos = rigidBodies[bodyIndexB].m_pos; + float sphereRadius = collidables[collidableIndexB].m_radius; + float4 convexPos = rigidBodies[bodyIndexA].m_pos; + float4 convexOrn = rigidBodies[bodyIndexA].m_quat; + + computeContactSphereConvex(pairIndex, bodyIndexB, bodyIndexA, collidableIndexB, collidableIndexA, + rigidBodies,collidables,convexShapes,vertices,indices,faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity, + spherePos,sphereRadius,convexPos,convexOrn); + return; + } + + + + + + + if (collidables[collidableIndexA].m_shapeType == SHAPE_SPHERE && + collidables[collidableIndexB].m_shapeType == SHAPE_SPHERE) + { + //sphere-sphere + float radiusA = collidables[collidableIndexA].m_radius; + float radiusB = collidables[collidableIndexB].m_radius; + float4 posA = rigidBodies[bodyIndexA].m_pos; + float4 posB = rigidBodies[bodyIndexB].m_pos; + + float4 diff = posA-posB; + float len = length(diff); + + ///iff distance positive, don't generate a new contact + if ( len <= (radiusA+radiusB)) + { + ///distance (negative means penetration) + float dist = len - (radiusA+radiusB); + float4 normalOnSurfaceB = make_float4(1.f,0.f,0.f,0.f); + if (len > 0.00001) + { + normalOnSurfaceB = diff / len; + } + float4 contactPosB = posB + normalOnSurfaceB*radiusB; + contactPosB.w = dist; + + int dstIdx; + AppendInc( nGlobalContactsOut, dstIdx ); + + if (dstIdx < maxContactCapacity) + { + __global struct b3Contact4Data* c = &globalContactsOut[dstIdx]; + c->m_worldNormalOnB = normalOnSurfaceB; + c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff); + c->m_batchIdx = pairIndex; + int bodyA = pairs[pairIndex].x; + int bodyB = pairs[pairIndex].y; + c->m_bodyAPtrAndSignBit = rigidBodies[bodyA].m_invMass==0?-bodyA:bodyA; + c->m_bodyBPtrAndSignBit = rigidBodies[bodyB].m_invMass==0?-bodyB:bodyB; + c->m_worldPosB[0] = contactPosB; + c->m_childIndexA = -1; + c->m_childIndexB = -1; + GET_NPOINTS(*c) = 1; + }//if (dstIdx < numPairs) + }//if ( len <= (radiusA+radiusB)) + + return; + }//SHAPE_SPHERE SHAPE_SPHERE + + }// if (i= 0) + { + collidableIndexA = gpuChildShapes[childShapeIndexA].m_shapeIndex; + float4 childPosA = gpuChildShapes[childShapeIndexA].m_childPosition; + float4 childOrnA = gpuChildShapes[childShapeIndexA].m_childOrientation; + float4 newPosA = qtRotate(ornA,childPosA)+posA; + float4 newOrnA = qtMul(ornA,childOrnA); + posA = newPosA; + ornA = newOrnA; + } else + { + collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx; + } + + if (childShapeIndexB>=0) + { + collidableIndexB = gpuChildShapes[childShapeIndexB].m_shapeIndex; + float4 childPosB = gpuChildShapes[childShapeIndexB].m_childPosition; + float4 childOrnB = gpuChildShapes[childShapeIndexB].m_childOrientation; + float4 newPosB = transform(&childPosB,&posB,&ornB); + float4 newOrnB = qtMul(ornB,childOrnB); + posB = newPosB; + ornB = newOrnB; + } else + { + collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx; + } + + int shapeIndexA = collidables[collidableIndexA].m_shapeIndex; + int shapeIndexB = collidables[collidableIndexB].m_shapeIndex; + + int shapeTypeA = collidables[collidableIndexA].m_shapeType; + int shapeTypeB = collidables[collidableIndexB].m_shapeType; + + int pairIndex = i; + if ((shapeTypeA == SHAPE_PLANE) && (shapeTypeB==SHAPE_CONVEX_HULL)) + { + + computeContactPlaneConvex( pairIndex, bodyIndexA,bodyIndexB, collidableIndexA,collidableIndexB, + rigidBodies,collidables,convexShapes,vertices,indices, + faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity,posB,ornB); + return; + } + + if ((shapeTypeA == SHAPE_CONVEX_HULL) && (shapeTypeB==SHAPE_PLANE)) + { + + computeContactPlaneConvex( pairIndex, bodyIndexB,bodyIndexA, collidableIndexB,collidableIndexA, + rigidBodies,collidables,convexShapes,vertices,indices, + faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity,posA,ornA); + return; + } + + if ((shapeTypeA == SHAPE_CONVEX_HULL) && (shapeTypeB == SHAPE_SPHERE)) + { + float4 spherePos = rigidBodies[bodyIndexB].m_pos; + float sphereRadius = collidables[collidableIndexB].m_radius; + float4 convexPos = posA; + float4 convexOrn = ornA; + + computeContactSphereConvex(pairIndex, bodyIndexB, bodyIndexA , collidableIndexB,collidableIndexA, + rigidBodies,collidables,convexShapes,vertices,indices,faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity, + spherePos,sphereRadius,convexPos,convexOrn); + + return; + } + + if ((shapeTypeA == SHAPE_SPHERE) && (shapeTypeB == SHAPE_CONVEX_HULL)) + { + + float4 spherePos = rigidBodies[bodyIndexA].m_pos; + float sphereRadius = collidables[collidableIndexA].m_radius; + float4 convexPos = posB; + float4 convexOrn = ornB; + + + computeContactSphereConvex(pairIndex, bodyIndexA, bodyIndexB, collidableIndexA, collidableIndexB, + rigidBodies,collidables,convexShapes,vertices,indices,faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity, + spherePos,sphereRadius,convexPos,convexOrn); + + return; + } + }// if (i 0 && r2 > 0 && r3 > 0 ) + return true; + if ( r1 <= 0 && r2 <= 0 && r3 <= 0 ) + return true; + return false; + +} + + +float segmentSqrDistance(float4 from, float4 to,float4 p, float4* nearest) +{ + float4 diff = p - from; + float4 v = to - from; + float t = dot(v,diff); + + if (t > 0) + { + float dotVV = dot(v,v); + if (t < dotVV) + { + t /= dotVV; + diff -= t*v; + } else + { + t = 1; + diff -= v; + } + } else + { + t = 0; + } + *nearest = from + t*v; + return dot(diff,diff); +} + + +void computeContactSphereTriangle(int pairIndex, + int bodyIndexA, int bodyIndexB, + int collidableIndexA, int collidableIndexB, + __global const BodyData* rigidBodies, + __global const btCollidableGpu* collidables, + const float4* triangleVertices, + __global struct b3Contact4Data* restrict globalContactsOut, + counter32_t nGlobalContactsOut, + int maxContactCapacity, + float4 spherePos2, + float radius, + float4 pos, + float4 quat, + int faceIndex + ) +{ + + float4 invPos; + float4 invOrn; + + trInverse(pos,quat, &invPos,&invOrn); + float4 spherePos = transform(&spherePos2,&invPos,&invOrn); + int numFaces = 3; + float4 closestPnt = (float4)(0, 0, 0, 0); + float4 hitNormalWorld = (float4)(0, 0, 0, 0); + float minDist = -1000000.f; + bool bCollide = false; + + + ////////////////////////////////////// + + float4 sphereCenter; + sphereCenter = spherePos; + + const float4* vertices = triangleVertices; + float contactBreakingThreshold = 0.f;//todo? + float radiusWithThreshold = radius + contactBreakingThreshold; + float4 edge10; + edge10 = vertices[1]-vertices[0]; + edge10.w = 0.f;//is this needed? + float4 edge20; + edge20 = vertices[2]-vertices[0]; + edge20.w = 0.f;//is this needed? + float4 normal = cross3(edge10,edge20); + normal = normalize(normal); + float4 p1ToCenter; + p1ToCenter = sphereCenter - vertices[0]; + + float distanceFromPlane = dot(p1ToCenter,normal); + + if (distanceFromPlane < 0.f) + { + //triangle facing the other way + distanceFromPlane *= -1.f; + normal *= -1.f; + } + hitNormalWorld = normal; + + bool isInsideContactPlane = distanceFromPlane < radiusWithThreshold; + + // Check for contact / intersection + bool hasContact = false; + float4 contactPoint; + if (isInsideContactPlane) + { + + if (pointInTriangle(vertices,&normal, &sphereCenter)) + { + // Inside the contact wedge - touches a point on the shell plane + hasContact = true; + contactPoint = sphereCenter - normal*distanceFromPlane; + + } else { + // Could be inside one of the contact capsules + float contactCapsuleRadiusSqr = radiusWithThreshold*radiusWithThreshold; + float4 nearestOnEdge; + int numEdges = 3; + for (int i = 0; i < numEdges; i++) + { + float4 pa =vertices[i]; + float4 pb = vertices[(i+1)%3]; + + float distanceSqr = segmentSqrDistance(pa,pb,sphereCenter, &nearestOnEdge); + if (distanceSqr < contactCapsuleRadiusSqr) + { + // Yep, we're inside a capsule + hasContact = true; + contactPoint = nearestOnEdge; + + } + + } + } + } + + if (hasContact) + { + + closestPnt = contactPoint; + float4 contactToCenter = sphereCenter - contactPoint; + minDist = length(contactToCenter); + if (minDist>FLT_EPSILON) + { + hitNormalWorld = normalize(contactToCenter);//*(1./minDist); + bCollide = true; + } + + } + + + ///////////////////////////////////// + + if (bCollide && minDist > -10000) + { + + float4 normalOnSurfaceB1 = qtRotate(quat,-hitNormalWorld); + float4 pOnB1 = transform(&closestPnt,&pos,&quat); + float actualDepth = minDist-radius; + + + if (actualDepth<=0.f) + { + pOnB1.w = actualDepth; + int dstIdx; + + + float lenSqr = dot3F4(normalOnSurfaceB1,normalOnSurfaceB1); + if (lenSqr>FLT_EPSILON) + { + AppendInc( nGlobalContactsOut, dstIdx ); + + if (dstIdx < maxContactCapacity) + { + __global struct b3Contact4Data* c = &globalContactsOut[dstIdx]; + c->m_worldNormalOnB = -normalOnSurfaceB1; + c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff); + c->m_batchIdx = pairIndex; + c->m_bodyAPtrAndSignBit = rigidBodies[bodyIndexA].m_invMass==0?-bodyIndexA:bodyIndexA; + c->m_bodyBPtrAndSignBit = rigidBodies[bodyIndexB].m_invMass==0?-bodyIndexB:bodyIndexB; + c->m_worldPosB[0] = pOnB1; + + c->m_childIndexA = -1; + c->m_childIndexB = faceIndex; + + GET_NPOINTS(*c) = 1; + } + } + + } + }//if (hasCollision) + +} + + + +// work-in-progress +__kernel void findConcaveSphereContactsKernel( __global int4* concavePairs, + __global const BodyData* rigidBodies, + __global const btCollidableGpu* collidables, + __global const ConvexPolyhedronCL* convexShapes, + __global const float4* vertices, + __global const float4* uniqueEdges, + __global const btGpuFace* faces, + __global const int* indices, + __global btAabbCL* aabbs, + __global struct b3Contact4Data* restrict globalContactsOut, + counter32_t nGlobalContactsOut, + int numConcavePairs, int maxContactCapacity + ) +{ + + int i = get_global_id(0); + if (i>=numConcavePairs) + return; + int pairIdx = i; + + int bodyIndexA = concavePairs[i].x; + int bodyIndexB = concavePairs[i].y; + + int collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx; + int collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx; + + int shapeIndexA = collidables[collidableIndexA].m_shapeIndex; + int shapeIndexB = collidables[collidableIndexB].m_shapeIndex; + + if (collidables[collidableIndexB].m_shapeType==SHAPE_SPHERE) + { + int f = concavePairs[i].z; + btGpuFace face = faces[convexShapes[shapeIndexA].m_faceOffset+f]; + + float4 verticesA[3]; + for (int i=0;i<3;i++) + { + int index = indices[face.m_indexOffset+i]; + float4 vert = vertices[convexShapes[shapeIndexA].m_vertexOffset+index]; + verticesA[i] = vert; + } + + float4 spherePos = rigidBodies[bodyIndexB].m_pos; + float sphereRadius = collidables[collidableIndexB].m_radius; + float4 convexPos = rigidBodies[bodyIndexA].m_pos; + float4 convexOrn = rigidBodies[bodyIndexA].m_quat; + + computeContactSphereTriangle(i, bodyIndexB, bodyIndexA, collidableIndexB, collidableIndexA, + rigidBodies,collidables, + verticesA, + globalContactsOut, nGlobalContactsOut,maxContactCapacity, + spherePos,sphereRadius,convexPos,convexOrn, f); + + return; + } +} \ No newline at end of file diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/kernels/primitiveContacts.h b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/kernels/primitiveContacts.h new file mode 100644 index 000000000000..b0103fe67488 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/kernels/primitiveContacts.h @@ -0,0 +1,1289 @@ +//this file is autogenerated using stringify.bat (premake --stringify) in the build folder of this project +static const char* primitiveContactsKernelsCL= \ +"#ifndef B3_CONTACT4DATA_H\n" +"#define B3_CONTACT4DATA_H\n" +"#ifndef B3_FLOAT4_H\n" +"#define B3_FLOAT4_H\n" +"#ifndef B3_PLATFORM_DEFINITIONS_H\n" +"#define B3_PLATFORM_DEFINITIONS_H\n" +"struct MyTest\n" +"{\n" +" int bla;\n" +"};\n" +"#ifdef __cplusplus\n" +"#else\n" +"//keep B3_LARGE_FLOAT*B3_LARGE_FLOAT < FLT_MAX\n" +"#define B3_LARGE_FLOAT 1e18f\n" +"#define B3_INFINITY 1e18f\n" +"#define b3Assert(a)\n" +"#define b3ConstArray(a) __global const a*\n" +"#define b3AtomicInc atomic_inc\n" +"#define b3AtomicAdd atomic_add\n" +"#define b3Fabs fabs\n" +"#define b3Sqrt native_sqrt\n" +"#define b3Sin native_sin\n" +"#define b3Cos native_cos\n" +"#define B3_STATIC\n" +"#endif\n" +"#endif\n" +"#ifdef __cplusplus\n" +"#else\n" +" typedef float4 b3Float4;\n" +" #define b3Float4ConstArg const b3Float4\n" +" #define b3MakeFloat4 (float4)\n" +" float b3Dot3F4(b3Float4ConstArg v0,b3Float4ConstArg v1)\n" +" {\n" +" float4 a1 = b3MakeFloat4(v0.xyz,0.f);\n" +" float4 b1 = b3MakeFloat4(v1.xyz,0.f);\n" +" return dot(a1, b1);\n" +" }\n" +" b3Float4 b3Cross3(b3Float4ConstArg v0,b3Float4ConstArg v1)\n" +" {\n" +" float4 a1 = b3MakeFloat4(v0.xyz,0.f);\n" +" float4 b1 = b3MakeFloat4(v1.xyz,0.f);\n" +" return cross(a1, b1);\n" +" }\n" +" #define b3MinFloat4 min\n" +" #define b3MaxFloat4 max\n" +" #define b3Normalized(a) normalize(a)\n" +"#endif \n" +" \n" +"inline bool b3IsAlmostZero(b3Float4ConstArg v)\n" +"{\n" +" if(b3Fabs(v.x)>1e-6 || b3Fabs(v.y)>1e-6 || b3Fabs(v.z)>1e-6) \n" +" return false;\n" +" return true;\n" +"}\n" +"inline int b3MaxDot( b3Float4ConstArg vec, __global const b3Float4* vecArray, int vecLen, float* dotOut )\n" +"{\n" +" float maxDot = -B3_INFINITY;\n" +" int i = 0;\n" +" int ptIndex = -1;\n" +" for( i = 0; i < vecLen; i++ )\n" +" {\n" +" float dot = b3Dot3F4(vecArray[i],vec);\n" +" \n" +" if( dot > maxDot )\n" +" {\n" +" maxDot = dot;\n" +" ptIndex = i;\n" +" }\n" +" }\n" +" b3Assert(ptIndex>=0);\n" +" if (ptIndex<0)\n" +" {\n" +" ptIndex = 0;\n" +" }\n" +" *dotOut = maxDot;\n" +" return ptIndex;\n" +"}\n" +"#endif //B3_FLOAT4_H\n" +"typedef struct b3Contact4Data b3Contact4Data_t;\n" +"struct b3Contact4Data\n" +"{\n" +" b3Float4 m_worldPosB[4];\n" +"// b3Float4 m_localPosA[4];\n" +"// b3Float4 m_localPosB[4];\n" +" b3Float4 m_worldNormalOnB; // w: m_nPoints\n" +" unsigned short m_restituitionCoeffCmp;\n" +" unsigned short m_frictionCoeffCmp;\n" +" int m_batchIdx;\n" +" int m_bodyAPtrAndSignBit;//x:m_bodyAPtr, y:m_bodyBPtr\n" +" int m_bodyBPtrAndSignBit;\n" +" int m_childIndexA;\n" +" int m_childIndexB;\n" +" int m_unused1;\n" +" int m_unused2;\n" +"};\n" +"inline int b3Contact4Data_getNumPoints(const struct b3Contact4Data* contact)\n" +"{\n" +" return (int)contact->m_worldNormalOnB.w;\n" +"};\n" +"inline void b3Contact4Data_setNumPoints(struct b3Contact4Data* contact, int numPoints)\n" +"{\n" +" contact->m_worldNormalOnB.w = (float)numPoints;\n" +"};\n" +"#endif //B3_CONTACT4DATA_H\n" +"#define SHAPE_CONVEX_HULL 3\n" +"#define SHAPE_PLANE 4\n" +"#define SHAPE_CONCAVE_TRIMESH 5\n" +"#define SHAPE_COMPOUND_OF_CONVEX_HULLS 6\n" +"#define SHAPE_SPHERE 7\n" +"#pragma OPENCL EXTENSION cl_amd_printf : enable\n" +"#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable\n" +"#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable\n" +"#pragma OPENCL EXTENSION cl_khr_local_int32_extended_atomics : enable\n" +"#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable\n" +"#ifdef cl_ext_atomic_counters_32\n" +"#pragma OPENCL EXTENSION cl_ext_atomic_counters_32 : enable\n" +"#else\n" +"#define counter32_t volatile __global int*\n" +"#endif\n" +"#define GET_GROUP_IDX get_group_id(0)\n" +"#define GET_LOCAL_IDX get_local_id(0)\n" +"#define GET_GLOBAL_IDX get_global_id(0)\n" +"#define GET_GROUP_SIZE get_local_size(0)\n" +"#define GET_NUM_GROUPS get_num_groups(0)\n" +"#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE)\n" +"#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE)\n" +"#define AtomInc(x) atom_inc(&(x))\n" +"#define AtomInc1(x, out) out = atom_inc(&(x))\n" +"#define AppendInc(x, out) out = atomic_inc(x)\n" +"#define AtomAdd(x, value) atom_add(&(x), value)\n" +"#define AtomCmpxhg(x, cmp, value) atom_cmpxchg( &(x), cmp, value )\n" +"#define AtomXhg(x, value) atom_xchg ( &(x), value )\n" +"#define max2 max\n" +"#define min2 min\n" +"typedef unsigned int u32;\n" +"typedef struct \n" +"{\n" +" union\n" +" {\n" +" float4 m_min;\n" +" float m_minElems[4];\n" +" int m_minIndices[4];\n" +" };\n" +" union\n" +" {\n" +" float4 m_max;\n" +" float m_maxElems[4];\n" +" int m_maxIndices[4];\n" +" };\n" +"} btAabbCL;\n" +"///keep this in sync with btCollidable.h\n" +"typedef struct\n" +"{\n" +" int m_numChildShapes;\n" +" float m_radius;\n" +" int m_shapeType;\n" +" int m_shapeIndex;\n" +" \n" +"} btCollidableGpu;\n" +"typedef struct\n" +"{\n" +" float4 m_childPosition;\n" +" float4 m_childOrientation;\n" +" int m_shapeIndex;\n" +" int m_unused0;\n" +" int m_unused1;\n" +" int m_unused2;\n" +"} btGpuChildShape;\n" +"#define GET_NPOINTS(x) (x).m_worldNormalOnB.w\n" +"typedef struct\n" +"{\n" +" float4 m_pos;\n" +" float4 m_quat;\n" +" float4 m_linVel;\n" +" float4 m_angVel;\n" +" u32 m_collidableIdx; \n" +" float m_invMass;\n" +" float m_restituitionCoeff;\n" +" float m_frictionCoeff;\n" +"} BodyData;\n" +"typedef struct \n" +"{\n" +" float4 m_localCenter;\n" +" float4 m_extents;\n" +" float4 mC;\n" +" float4 mE;\n" +" \n" +" float m_radius;\n" +" int m_faceOffset;\n" +" int m_numFaces;\n" +" int m_numVertices;\n" +" \n" +" int m_vertexOffset;\n" +" int m_uniqueEdgesOffset;\n" +" int m_numUniqueEdges;\n" +" int m_unused;\n" +"} ConvexPolyhedronCL;\n" +"typedef struct\n" +"{\n" +" float4 m_plane;\n" +" int m_indexOffset;\n" +" int m_numIndices;\n" +"} btGpuFace;\n" +"#define SELECT_UINT4( b, a, condition ) select( b,a,condition )\n" +"#define make_float4 (float4)\n" +"#define make_float2 (float2)\n" +"#define make_uint4 (uint4)\n" +"#define make_int4 (int4)\n" +"#define make_uint2 (uint2)\n" +"#define make_int2 (int2)\n" +"__inline\n" +"float fastDiv(float numerator, float denominator)\n" +"{\n" +" return native_divide(numerator, denominator); \n" +"// return numerator/denominator; \n" +"}\n" +"__inline\n" +"float4 fastDiv4(float4 numerator, float4 denominator)\n" +"{\n" +" return native_divide(numerator, denominator); \n" +"}\n" +"__inline\n" +"float4 cross3(float4 a, float4 b)\n" +"{\n" +" return cross(a,b);\n" +"}\n" +"//#define dot3F4 dot\n" +"__inline\n" +"float dot3F4(float4 a, float4 b)\n" +"{\n" +" float4 a1 = make_float4(a.xyz,0.f);\n" +" float4 b1 = make_float4(b.xyz,0.f);\n" +" return dot(a1, b1);\n" +"}\n" +"__inline\n" +"float4 fastNormalize4(float4 v)\n" +"{\n" +" return fast_normalize(v);\n" +"}\n" +"///////////////////////////////////////\n" +"// Quaternion\n" +"///////////////////////////////////////\n" +"typedef float4 Quaternion;\n" +"__inline\n" +"Quaternion qtMul(Quaternion a, Quaternion b);\n" +"__inline\n" +"Quaternion qtNormalize(Quaternion in);\n" +"__inline\n" +"float4 qtRotate(Quaternion q, float4 vec);\n" +"__inline\n" +"Quaternion qtInvert(Quaternion q);\n" +"__inline\n" +"Quaternion qtMul(Quaternion a, Quaternion b)\n" +"{\n" +" Quaternion ans;\n" +" ans = cross3( a, b );\n" +" ans += a.w*b+b.w*a;\n" +"// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z);\n" +" ans.w = a.w*b.w - dot3F4(a, b);\n" +" return ans;\n" +"}\n" +"__inline\n" +"Quaternion qtNormalize(Quaternion in)\n" +"{\n" +" return fastNormalize4(in);\n" +"// in /= length( in );\n" +"// return in;\n" +"}\n" +"__inline\n" +"float4 qtRotate(Quaternion q, float4 vec)\n" +"{\n" +" Quaternion qInv = qtInvert( q );\n" +" float4 vcpy = vec;\n" +" vcpy.w = 0.f;\n" +" float4 out = qtMul(qtMul(q,vcpy),qInv);\n" +" return out;\n" +"}\n" +"__inline\n" +"Quaternion qtInvert(Quaternion q)\n" +"{\n" +" return (Quaternion)(-q.xyz, q.w);\n" +"}\n" +"__inline\n" +"float4 qtInvRotate(const Quaternion q, float4 vec)\n" +"{\n" +" return qtRotate( qtInvert( q ), vec );\n" +"}\n" +"__inline\n" +"float4 transform(const float4* p, const float4* translation, const Quaternion* orientation)\n" +"{\n" +" return qtRotate( *orientation, *p ) + (*translation);\n" +"}\n" +"void trInverse(float4 translationIn, Quaternion orientationIn,\n" +" float4* translationOut, Quaternion* orientationOut)\n" +"{\n" +" *orientationOut = qtInvert(orientationIn);\n" +" *translationOut = qtRotate(*orientationOut, -translationIn);\n" +"}\n" +"void trMul(float4 translationA, Quaternion orientationA,\n" +" float4 translationB, Quaternion orientationB,\n" +" float4* translationOut, Quaternion* orientationOut)\n" +"{\n" +" *orientationOut = qtMul(orientationA,orientationB);\n" +" *translationOut = transform(&translationB,&translationA,&orientationA);\n" +"}\n" +"__inline\n" +"float4 normalize3(const float4 a)\n" +"{\n" +" float4 n = make_float4(a.x, a.y, a.z, 0.f);\n" +" return fastNormalize4( n );\n" +"}\n" +"__inline float4 lerp3(const float4 a,const float4 b, float t)\n" +"{\n" +" return make_float4( a.x + (b.x - a.x) * t,\n" +" a.y + (b.y - a.y) * t,\n" +" a.z + (b.z - a.z) * t,\n" +" 0.f);\n" +"}\n" +"float signedDistanceFromPointToPlane(float4 point, float4 planeEqn, float4* closestPointOnFace)\n" +"{\n" +" float4 n = (float4)(planeEqn.x, planeEqn.y, planeEqn.z, 0);\n" +" float dist = dot3F4(n, point) + planeEqn.w;\n" +" *closestPointOnFace = point - dist * n;\n" +" return dist;\n" +"}\n" +"inline bool IsPointInPolygon(float4 p, \n" +" const btGpuFace* face,\n" +" __global const float4* baseVertex,\n" +" __global const int* convexIndices,\n" +" float4* out)\n" +"{\n" +" float4 a;\n" +" float4 b;\n" +" float4 ab;\n" +" float4 ap;\n" +" float4 v;\n" +" float4 plane = make_float4(face->m_plane.x,face->m_plane.y,face->m_plane.z,0.f);\n" +" \n" +" if (face->m_numIndices<2)\n" +" return false;\n" +" \n" +" float4 v0 = baseVertex[convexIndices[face->m_indexOffset + face->m_numIndices-1]];\n" +" \n" +" b = v0;\n" +" for(unsigned i=0; i != face->m_numIndices; ++i)\n" +" {\n" +" a = b;\n" +" float4 vi = baseVertex[convexIndices[face->m_indexOffset + i]];\n" +" b = vi;\n" +" ab = b-a;\n" +" ap = p-a;\n" +" v = cross3(ab,plane);\n" +" if (dot(ap, v) > 0.f)\n" +" {\n" +" float ab_m2 = dot(ab, ab);\n" +" float rt = ab_m2 != 0.f ? dot(ab, ap) / ab_m2 : 0.f;\n" +" if (rt <= 0.f)\n" +" {\n" +" *out = a;\n" +" }\n" +" else if (rt >= 1.f) \n" +" {\n" +" *out = b;\n" +" }\n" +" else\n" +" {\n" +" float s = 1.f - rt;\n" +" out[0].x = s * a.x + rt * b.x;\n" +" out[0].y = s * a.y + rt * b.y;\n" +" out[0].z = s * a.z + rt * b.z;\n" +" }\n" +" return false;\n" +" }\n" +" }\n" +" return true;\n" +"}\n" +"void computeContactSphereConvex(int pairIndex,\n" +" int bodyIndexA, int bodyIndexB, \n" +" int collidableIndexA, int collidableIndexB, \n" +" __global const BodyData* rigidBodies, \n" +" __global const btCollidableGpu* collidables,\n" +" __global const ConvexPolyhedronCL* convexShapes,\n" +" __global const float4* convexVertices,\n" +" __global const int* convexIndices,\n" +" __global const btGpuFace* faces,\n" +" __global struct b3Contact4Data* restrict globalContactsOut,\n" +" counter32_t nGlobalContactsOut,\n" +" int maxContactCapacity,\n" +" float4 spherePos2,\n" +" float radius,\n" +" float4 pos,\n" +" float4 quat\n" +" )\n" +"{\n" +" float4 invPos;\n" +" float4 invOrn;\n" +" trInverse(pos,quat, &invPos,&invOrn);\n" +" float4 spherePos = transform(&spherePos2,&invPos,&invOrn);\n" +" int shapeIndex = collidables[collidableIndexB].m_shapeIndex;\n" +" int numFaces = convexShapes[shapeIndex].m_numFaces;\n" +" float4 closestPnt = (float4)(0, 0, 0, 0);\n" +" float4 hitNormalWorld = (float4)(0, 0, 0, 0);\n" +" float minDist = -1000000.f;\n" +" bool bCollide = true;\n" +" for ( int f = 0; f < numFaces; f++ )\n" +" {\n" +" btGpuFace face = faces[convexShapes[shapeIndex].m_faceOffset+f];\n" +" // set up a plane equation \n" +" float4 planeEqn;\n" +" float4 n1 = face.m_plane;\n" +" n1.w = 0.f;\n" +" planeEqn = n1;\n" +" planeEqn.w = face.m_plane.w;\n" +" \n" +" \n" +" // compute a signed distance from the vertex in cloth to the face of rigidbody.\n" +" float4 pntReturn;\n" +" float dist = signedDistanceFromPointToPlane(spherePos, planeEqn, &pntReturn);\n" +" // If the distance is positive, the plane is a separating plane. \n" +" if ( dist > radius )\n" +" {\n" +" bCollide = false;\n" +" break;\n" +" }\n" +" if (dist>0)\n" +" {\n" +" //might hit an edge or vertex\n" +" float4 out;\n" +" float4 zeroPos = make_float4(0,0,0,0);\n" +" bool isInPoly = IsPointInPolygon(spherePos,\n" +" &face,\n" +" &convexVertices[convexShapes[shapeIndex].m_vertexOffset],\n" +" convexIndices,\n" +" &out);\n" +" if (isInPoly)\n" +" {\n" +" if (dist>minDist)\n" +" {\n" +" minDist = dist;\n" +" closestPnt = pntReturn;\n" +" hitNormalWorld = planeEqn;\n" +" \n" +" }\n" +" } else\n" +" {\n" +" float4 tmp = spherePos-out;\n" +" float l2 = dot(tmp,tmp);\n" +" if (l2minDist)\n" +" {\n" +" minDist = dist;\n" +" closestPnt = out;\n" +" hitNormalWorld = tmp/dist;\n" +" \n" +" }\n" +" \n" +" } else\n" +" {\n" +" bCollide = false;\n" +" break;\n" +" }\n" +" }\n" +" } else\n" +" {\n" +" if ( dist > minDist )\n" +" {\n" +" minDist = dist;\n" +" closestPnt = pntReturn;\n" +" hitNormalWorld.xyz = planeEqn.xyz;\n" +" }\n" +" }\n" +" \n" +" }\n" +" \n" +" if (bCollide && minDist > -10000)\n" +" {\n" +" float4 normalOnSurfaceB1 = qtRotate(quat,-hitNormalWorld);\n" +" float4 pOnB1 = transform(&closestPnt,&pos,&quat);\n" +" \n" +" float actualDepth = minDist-radius;\n" +" if (actualDepth<=0.f)\n" +" {\n" +" \n" +" pOnB1.w = actualDepth;\n" +" int dstIdx;\n" +" AppendInc( nGlobalContactsOut, dstIdx );\n" +" \n" +" \n" +" if (1)//dstIdx < maxContactCapacity)\n" +" {\n" +" __global struct b3Contact4Data* c = &globalContactsOut[dstIdx];\n" +" c->m_worldNormalOnB = -normalOnSurfaceB1;\n" +" c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff);\n" +" c->m_batchIdx = pairIndex;\n" +" c->m_bodyAPtrAndSignBit = rigidBodies[bodyIndexA].m_invMass==0?-bodyIndexA:bodyIndexA;\n" +" c->m_bodyBPtrAndSignBit = rigidBodies[bodyIndexB].m_invMass==0?-bodyIndexB:bodyIndexB;\n" +" c->m_worldPosB[0] = pOnB1;\n" +" c->m_childIndexA = -1;\n" +" c->m_childIndexB = -1;\n" +" GET_NPOINTS(*c) = 1;\n" +" } \n" +" }\n" +" }//if (hasCollision)\n" +"}\n" +" \n" +"int extractManifoldSequential(const float4* p, int nPoints, float4 nearNormal, int4* contactIdx)\n" +"{\n" +" if( nPoints == 0 )\n" +" return 0;\n" +" \n" +" if (nPoints <=4)\n" +" return nPoints;\n" +" \n" +" \n" +" if (nPoints >64)\n" +" nPoints = 64;\n" +" \n" +" float4 center = make_float4(0.f);\n" +" {\n" +" \n" +" for (int i=0;im_numVertices;i++)\n" +" {\n" +" float4 vtx = convexVertices[hullB->m_vertexOffset+i];\n" +" float curDot = dot(vtx,planeNormalInConvex);\n" +" if (curDot>maxDot)\n" +" {\n" +" hitVertex=i;\n" +" maxDot=curDot;\n" +" hitVtx = vtx;\n" +" //make sure the deepest points is always included\n" +" if (numPoints==MAX_PLANE_CONVEX_POINTS)\n" +" numPoints--;\n" +" }\n" +" if (numPoints4)\n" +" {\n" +" numReducedPoints = extractManifoldSequential( contactPoints, numPoints, planeNormalInConvex, &contactIdx);\n" +" }\n" +" if (numReducedPoints>0)\n" +" {\n" +" int dstIdx;\n" +" AppendInc( nGlobalContactsOut, dstIdx );\n" +" if (dstIdx < maxContactCapacity)\n" +" {\n" +" resultIndex = dstIdx;\n" +" __global struct b3Contact4Data* c = &globalContactsOut[dstIdx];\n" +" c->m_worldNormalOnB = -planeNormalWorld;\n" +" //c->setFrictionCoeff(0.7);\n" +" //c->setRestituitionCoeff(0.f);\n" +" c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff);\n" +" c->m_batchIdx = pairIndex;\n" +" c->m_bodyAPtrAndSignBit = rigidBodies[bodyIndexA].m_invMass==0?-bodyIndexA:bodyIndexA;\n" +" c->m_bodyBPtrAndSignBit = rigidBodies[bodyIndexB].m_invMass==0?-bodyIndexB:bodyIndexB;\n" +" c->m_childIndexA = -1;\n" +" c->m_childIndexB = -1;\n" +" switch (numReducedPoints)\n" +" {\n" +" case 4:\n" +" c->m_worldPosB[3] = contactPoints[contactIdx.w];\n" +" case 3:\n" +" c->m_worldPosB[2] = contactPoints[contactIdx.z];\n" +" case 2:\n" +" c->m_worldPosB[1] = contactPoints[contactIdx.y];\n" +" case 1:\n" +" c->m_worldPosB[0] = contactPoints[contactIdx.x];\n" +" default:\n" +" {\n" +" }\n" +" };\n" +" \n" +" GET_NPOINTS(*c) = numReducedPoints;\n" +" }//if (dstIdx < numPairs)\n" +" } \n" +" return resultIndex;\n" +"}\n" +"void computeContactPlaneSphere(int pairIndex,\n" +" int bodyIndexA, int bodyIndexB, \n" +" int collidableIndexA, int collidableIndexB, \n" +" __global const BodyData* rigidBodies, \n" +" __global const btCollidableGpu* collidables,\n" +" __global const btGpuFace* faces,\n" +" __global struct b3Contact4Data* restrict globalContactsOut,\n" +" counter32_t nGlobalContactsOut,\n" +" int maxContactCapacity)\n" +"{\n" +" float4 planeEq = faces[collidables[collidableIndexA].m_shapeIndex].m_plane;\n" +" float radius = collidables[collidableIndexB].m_radius;\n" +" float4 posA1 = rigidBodies[bodyIndexA].m_pos;\n" +" float4 ornA1 = rigidBodies[bodyIndexA].m_quat;\n" +" float4 posB1 = rigidBodies[bodyIndexB].m_pos;\n" +" float4 ornB1 = rigidBodies[bodyIndexB].m_quat;\n" +" \n" +" bool hasCollision = false;\n" +" float4 planeNormal1 = make_float4(planeEq.x,planeEq.y,planeEq.z,0.f);\n" +" float planeConstant = planeEq.w;\n" +" float4 convexInPlaneTransPos1; Quaternion convexInPlaneTransOrn1;\n" +" {\n" +" float4 invPosA;Quaternion invOrnA;\n" +" trInverse(posA1,ornA1,&invPosA,&invOrnA);\n" +" trMul(invPosA,invOrnA,posB1,ornB1,&convexInPlaneTransPos1,&convexInPlaneTransOrn1);\n" +" }\n" +" float4 planeInConvexPos1; Quaternion planeInConvexOrn1;\n" +" {\n" +" float4 invPosB;Quaternion invOrnB;\n" +" trInverse(posB1,ornB1,&invPosB,&invOrnB);\n" +" trMul(invPosB,invOrnB,posA1,ornA1,&planeInConvexPos1,&planeInConvexOrn1); \n" +" }\n" +" float4 vtx1 = qtRotate(planeInConvexOrn1,-planeNormal1)*radius;\n" +" float4 vtxInPlane1 = transform(&vtx1,&convexInPlaneTransPos1,&convexInPlaneTransOrn1);\n" +" float distance = dot3F4(planeNormal1,vtxInPlane1) - planeConstant;\n" +" hasCollision = distance < 0.f;//m_manifoldPtr->getContactBreakingThreshold();\n" +" if (hasCollision)\n" +" {\n" +" float4 vtxInPlaneProjected1 = vtxInPlane1 - distance*planeNormal1;\n" +" float4 vtxInPlaneWorld1 = transform(&vtxInPlaneProjected1,&posA1,&ornA1);\n" +" float4 normalOnSurfaceB1 = qtRotate(ornA1,planeNormal1);\n" +" float4 pOnB1 = vtxInPlaneWorld1+normalOnSurfaceB1*distance;\n" +" pOnB1.w = distance;\n" +" int dstIdx;\n" +" AppendInc( nGlobalContactsOut, dstIdx );\n" +" \n" +" if (dstIdx < maxContactCapacity)\n" +" {\n" +" __global struct b3Contact4Data* c = &globalContactsOut[dstIdx];\n" +" c->m_worldNormalOnB = -normalOnSurfaceB1;\n" +" c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff);\n" +" c->m_batchIdx = pairIndex;\n" +" c->m_bodyAPtrAndSignBit = rigidBodies[bodyIndexA].m_invMass==0?-bodyIndexA:bodyIndexA;\n" +" c->m_bodyBPtrAndSignBit = rigidBodies[bodyIndexB].m_invMass==0?-bodyIndexB:bodyIndexB;\n" +" c->m_worldPosB[0] = pOnB1;\n" +" c->m_childIndexA = -1;\n" +" c->m_childIndexB = -1;\n" +" GET_NPOINTS(*c) = 1;\n" +" }//if (dstIdx < numPairs)\n" +" }//if (hasCollision)\n" +"}\n" +"__kernel void primitiveContactsKernel( __global int4* pairs, \n" +" __global const BodyData* rigidBodies, \n" +" __global const btCollidableGpu* collidables,\n" +" __global const ConvexPolyhedronCL* convexShapes, \n" +" __global const float4* vertices,\n" +" __global const float4* uniqueEdges,\n" +" __global const btGpuFace* faces,\n" +" __global const int* indices,\n" +" __global struct b3Contact4Data* restrict globalContactsOut,\n" +" counter32_t nGlobalContactsOut,\n" +" int numPairs, int maxContactCapacity)\n" +"{\n" +" int i = get_global_id(0);\n" +" int pairIndex = i;\n" +" \n" +" float4 worldVertsB1[64];\n" +" float4 worldVertsB2[64];\n" +" int capacityWorldVerts = 64; \n" +" float4 localContactsOut[64];\n" +" int localContactCapacity=64;\n" +" \n" +" float minDist = -1e30f;\n" +" float maxDist = 0.02f;\n" +" if (i=0)\n" +" pairs[pairIndex].z = contactIndex;\n" +" return;\n" +" }\n" +" if (collidables[collidableIndexA].m_shapeType == SHAPE_CONVEX_HULL &&\n" +" collidables[collidableIndexB].m_shapeType == SHAPE_PLANE)\n" +" {\n" +" float4 posA;\n" +" posA = rigidBodies[bodyIndexA].m_pos;\n" +" Quaternion ornA;\n" +" ornA = rigidBodies[bodyIndexA].m_quat;\n" +" int contactIndex = computeContactPlaneConvex( pairIndex, bodyIndexB,bodyIndexA, collidableIndexB,collidableIndexA, \n" +" rigidBodies,collidables,convexShapes,vertices,indices,\n" +" faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity,posA,ornA);\n" +" if (contactIndex>=0)\n" +" pairs[pairIndex].z = contactIndex;\n" +" return;\n" +" }\n" +" if (collidables[collidableIndexA].m_shapeType == SHAPE_PLANE &&\n" +" collidables[collidableIndexB].m_shapeType == SHAPE_SPHERE)\n" +" {\n" +" computeContactPlaneSphere(pairIndex, bodyIndexA, bodyIndexB, collidableIndexA, collidableIndexB, \n" +" rigidBodies,collidables,faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity);\n" +" return;\n" +" }\n" +" if (collidables[collidableIndexA].m_shapeType == SHAPE_SPHERE &&\n" +" collidables[collidableIndexB].m_shapeType == SHAPE_PLANE)\n" +" {\n" +" computeContactPlaneSphere( pairIndex, bodyIndexB,bodyIndexA, collidableIndexB,collidableIndexA, \n" +" rigidBodies,collidables,\n" +" faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity);\n" +" return;\n" +" }\n" +" \n" +" \n" +" if (collidables[collidableIndexA].m_shapeType == SHAPE_SPHERE &&\n" +" collidables[collidableIndexB].m_shapeType == SHAPE_CONVEX_HULL)\n" +" {\n" +" \n" +" float4 spherePos = rigidBodies[bodyIndexA].m_pos;\n" +" float sphereRadius = collidables[collidableIndexA].m_radius;\n" +" float4 convexPos = rigidBodies[bodyIndexB].m_pos;\n" +" float4 convexOrn = rigidBodies[bodyIndexB].m_quat;\n" +" computeContactSphereConvex(pairIndex, bodyIndexA, bodyIndexB, collidableIndexA, collidableIndexB, \n" +" rigidBodies,collidables,convexShapes,vertices,indices,faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity,\n" +" spherePos,sphereRadius,convexPos,convexOrn);\n" +" return;\n" +" }\n" +" if (collidables[collidableIndexA].m_shapeType == SHAPE_CONVEX_HULL &&\n" +" collidables[collidableIndexB].m_shapeType == SHAPE_SPHERE)\n" +" {\n" +" \n" +" float4 spherePos = rigidBodies[bodyIndexB].m_pos;\n" +" float sphereRadius = collidables[collidableIndexB].m_radius;\n" +" float4 convexPos = rigidBodies[bodyIndexA].m_pos;\n" +" float4 convexOrn = rigidBodies[bodyIndexA].m_quat;\n" +" computeContactSphereConvex(pairIndex, bodyIndexB, bodyIndexA, collidableIndexB, collidableIndexA, \n" +" rigidBodies,collidables,convexShapes,vertices,indices,faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity,\n" +" spherePos,sphereRadius,convexPos,convexOrn);\n" +" return;\n" +" }\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" if (collidables[collidableIndexA].m_shapeType == SHAPE_SPHERE &&\n" +" collidables[collidableIndexB].m_shapeType == SHAPE_SPHERE)\n" +" {\n" +" //sphere-sphere\n" +" float radiusA = collidables[collidableIndexA].m_radius;\n" +" float radiusB = collidables[collidableIndexB].m_radius;\n" +" float4 posA = rigidBodies[bodyIndexA].m_pos;\n" +" float4 posB = rigidBodies[bodyIndexB].m_pos;\n" +" float4 diff = posA-posB;\n" +" float len = length(diff);\n" +" \n" +" ///iff distance positive, don't generate a new contact\n" +" if ( len <= (radiusA+radiusB))\n" +" {\n" +" ///distance (negative means penetration)\n" +" float dist = len - (radiusA+radiusB);\n" +" float4 normalOnSurfaceB = make_float4(1.f,0.f,0.f,0.f);\n" +" if (len > 0.00001)\n" +" {\n" +" normalOnSurfaceB = diff / len;\n" +" }\n" +" float4 contactPosB = posB + normalOnSurfaceB*radiusB;\n" +" contactPosB.w = dist;\n" +" \n" +" int dstIdx;\n" +" AppendInc( nGlobalContactsOut, dstIdx );\n" +" \n" +" if (dstIdx < maxContactCapacity)\n" +" {\n" +" __global struct b3Contact4Data* c = &globalContactsOut[dstIdx];\n" +" c->m_worldNormalOnB = normalOnSurfaceB;\n" +" c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff);\n" +" c->m_batchIdx = pairIndex;\n" +" int bodyA = pairs[pairIndex].x;\n" +" int bodyB = pairs[pairIndex].y;\n" +" c->m_bodyAPtrAndSignBit = rigidBodies[bodyA].m_invMass==0?-bodyA:bodyA;\n" +" c->m_bodyBPtrAndSignBit = rigidBodies[bodyB].m_invMass==0?-bodyB:bodyB;\n" +" c->m_worldPosB[0] = contactPosB;\n" +" c->m_childIndexA = -1;\n" +" c->m_childIndexB = -1;\n" +" GET_NPOINTS(*c) = 1;\n" +" }//if (dstIdx < numPairs)\n" +" }//if ( len <= (radiusA+radiusB))\n" +" return;\n" +" }//SHAPE_SPHERE SHAPE_SPHERE\n" +" }// if (i= 0)\n" +" {\n" +" collidableIndexA = gpuChildShapes[childShapeIndexA].m_shapeIndex;\n" +" float4 childPosA = gpuChildShapes[childShapeIndexA].m_childPosition;\n" +" float4 childOrnA = gpuChildShapes[childShapeIndexA].m_childOrientation;\n" +" float4 newPosA = qtRotate(ornA,childPosA)+posA;\n" +" float4 newOrnA = qtMul(ornA,childOrnA);\n" +" posA = newPosA;\n" +" ornA = newOrnA;\n" +" } else\n" +" {\n" +" collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx;\n" +" }\n" +" \n" +" if (childShapeIndexB>=0)\n" +" {\n" +" collidableIndexB = gpuChildShapes[childShapeIndexB].m_shapeIndex;\n" +" float4 childPosB = gpuChildShapes[childShapeIndexB].m_childPosition;\n" +" float4 childOrnB = gpuChildShapes[childShapeIndexB].m_childOrientation;\n" +" float4 newPosB = transform(&childPosB,&posB,&ornB);\n" +" float4 newOrnB = qtMul(ornB,childOrnB);\n" +" posB = newPosB;\n" +" ornB = newOrnB;\n" +" } else\n" +" {\n" +" collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx; \n" +" }\n" +" \n" +" int shapeIndexA = collidables[collidableIndexA].m_shapeIndex;\n" +" int shapeIndexB = collidables[collidableIndexB].m_shapeIndex;\n" +" \n" +" int shapeTypeA = collidables[collidableIndexA].m_shapeType;\n" +" int shapeTypeB = collidables[collidableIndexB].m_shapeType;\n" +" int pairIndex = i;\n" +" if ((shapeTypeA == SHAPE_PLANE) && (shapeTypeB==SHAPE_CONVEX_HULL))\n" +" {\n" +" computeContactPlaneConvex( pairIndex, bodyIndexA,bodyIndexB, collidableIndexA,collidableIndexB, \n" +" rigidBodies,collidables,convexShapes,vertices,indices,\n" +" faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity,posB,ornB);\n" +" return;\n" +" }\n" +" if ((shapeTypeA == SHAPE_CONVEX_HULL) && (shapeTypeB==SHAPE_PLANE))\n" +" {\n" +" computeContactPlaneConvex( pairIndex, bodyIndexB,bodyIndexA, collidableIndexB,collidableIndexA, \n" +" rigidBodies,collidables,convexShapes,vertices,indices,\n" +" faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity,posA,ornA);\n" +" return;\n" +" }\n" +" if ((shapeTypeA == SHAPE_CONVEX_HULL) && (shapeTypeB == SHAPE_SPHERE))\n" +" {\n" +" float4 spherePos = rigidBodies[bodyIndexB].m_pos;\n" +" float sphereRadius = collidables[collidableIndexB].m_radius;\n" +" float4 convexPos = posA;\n" +" float4 convexOrn = ornA;\n" +" \n" +" computeContactSphereConvex(pairIndex, bodyIndexB, bodyIndexA , collidableIndexB,collidableIndexA, \n" +" rigidBodies,collidables,convexShapes,vertices,indices,faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity,\n" +" spherePos,sphereRadius,convexPos,convexOrn);\n" +" \n" +" return;\n" +" }\n" +" if ((shapeTypeA == SHAPE_SPHERE) && (shapeTypeB == SHAPE_CONVEX_HULL))\n" +" {\n" +" float4 spherePos = rigidBodies[bodyIndexA].m_pos;\n" +" float sphereRadius = collidables[collidableIndexA].m_radius;\n" +" float4 convexPos = posB;\n" +" float4 convexOrn = ornB;\n" +" \n" +" computeContactSphereConvex(pairIndex, bodyIndexA, bodyIndexB, collidableIndexA, collidableIndexB, \n" +" rigidBodies,collidables,convexShapes,vertices,indices,faces, globalContactsOut, nGlobalContactsOut,maxContactCapacity,\n" +" spherePos,sphereRadius,convexPos,convexOrn);\n" +" \n" +" return;\n" +" }\n" +" }// if (i 0 && r2 > 0 && r3 > 0 )\n" +" return true;\n" +" if ( r1 <= 0 && r2 <= 0 && r3 <= 0 ) \n" +" return true;\n" +" return false;\n" +"}\n" +"float segmentSqrDistance(float4 from, float4 to,float4 p, float4* nearest) \n" +"{\n" +" float4 diff = p - from;\n" +" float4 v = to - from;\n" +" float t = dot(v,diff);\n" +" \n" +" if (t > 0) \n" +" {\n" +" float dotVV = dot(v,v);\n" +" if (t < dotVV) \n" +" {\n" +" t /= dotVV;\n" +" diff -= t*v;\n" +" } else \n" +" {\n" +" t = 1;\n" +" diff -= v;\n" +" }\n" +" } else\n" +" {\n" +" t = 0;\n" +" }\n" +" *nearest = from + t*v;\n" +" return dot(diff,diff); \n" +"}\n" +"void computeContactSphereTriangle(int pairIndex,\n" +" int bodyIndexA, int bodyIndexB,\n" +" int collidableIndexA, int collidableIndexB, \n" +" __global const BodyData* rigidBodies, \n" +" __global const btCollidableGpu* collidables,\n" +" const float4* triangleVertices,\n" +" __global struct b3Contact4Data* restrict globalContactsOut,\n" +" counter32_t nGlobalContactsOut,\n" +" int maxContactCapacity,\n" +" float4 spherePos2,\n" +" float radius,\n" +" float4 pos,\n" +" float4 quat,\n" +" int faceIndex\n" +" )\n" +"{\n" +" float4 invPos;\n" +" float4 invOrn;\n" +" trInverse(pos,quat, &invPos,&invOrn);\n" +" float4 spherePos = transform(&spherePos2,&invPos,&invOrn);\n" +" int numFaces = 3;\n" +" float4 closestPnt = (float4)(0, 0, 0, 0);\n" +" float4 hitNormalWorld = (float4)(0, 0, 0, 0);\n" +" float minDist = -1000000.f;\n" +" bool bCollide = false;\n" +" \n" +" //////////////////////////////////////\n" +" float4 sphereCenter;\n" +" sphereCenter = spherePos;\n" +" const float4* vertices = triangleVertices;\n" +" float contactBreakingThreshold = 0.f;//todo?\n" +" float radiusWithThreshold = radius + contactBreakingThreshold;\n" +" float4 edge10;\n" +" edge10 = vertices[1]-vertices[0];\n" +" edge10.w = 0.f;//is this needed?\n" +" float4 edge20;\n" +" edge20 = vertices[2]-vertices[0];\n" +" edge20.w = 0.f;//is this needed?\n" +" float4 normal = cross3(edge10,edge20);\n" +" normal = normalize(normal);\n" +" float4 p1ToCenter;\n" +" p1ToCenter = sphereCenter - vertices[0];\n" +" \n" +" float distanceFromPlane = dot(p1ToCenter,normal);\n" +" if (distanceFromPlane < 0.f)\n" +" {\n" +" //triangle facing the other way\n" +" distanceFromPlane *= -1.f;\n" +" normal *= -1.f;\n" +" }\n" +" hitNormalWorld = normal;\n" +" bool isInsideContactPlane = distanceFromPlane < radiusWithThreshold;\n" +" \n" +" // Check for contact / intersection\n" +" bool hasContact = false;\n" +" float4 contactPoint;\n" +" if (isInsideContactPlane) \n" +" {\n" +" \n" +" if (pointInTriangle(vertices,&normal, &sphereCenter)) \n" +" {\n" +" // Inside the contact wedge - touches a point on the shell plane\n" +" hasContact = true;\n" +" contactPoint = sphereCenter - normal*distanceFromPlane;\n" +" \n" +" } else {\n" +" // Could be inside one of the contact capsules\n" +" float contactCapsuleRadiusSqr = radiusWithThreshold*radiusWithThreshold;\n" +" float4 nearestOnEdge;\n" +" int numEdges = 3;\n" +" for (int i = 0; i < numEdges; i++) \n" +" {\n" +" float4 pa =vertices[i];\n" +" float4 pb = vertices[(i+1)%3];\n" +" float distanceSqr = segmentSqrDistance(pa,pb,sphereCenter, &nearestOnEdge);\n" +" if (distanceSqr < contactCapsuleRadiusSqr) \n" +" {\n" +" // Yep, we're inside a capsule\n" +" hasContact = true;\n" +" contactPoint = nearestOnEdge;\n" +" \n" +" }\n" +" \n" +" }\n" +" }\n" +" }\n" +" if (hasContact) \n" +" {\n" +" closestPnt = contactPoint;\n" +" float4 contactToCenter = sphereCenter - contactPoint;\n" +" minDist = length(contactToCenter);\n" +" if (minDist>FLT_EPSILON)\n" +" {\n" +" hitNormalWorld = normalize(contactToCenter);//*(1./minDist);\n" +" bCollide = true;\n" +" }\n" +" \n" +" }\n" +" /////////////////////////////////////\n" +" if (bCollide && minDist > -10000)\n" +" {\n" +" \n" +" float4 normalOnSurfaceB1 = qtRotate(quat,-hitNormalWorld);\n" +" float4 pOnB1 = transform(&closestPnt,&pos,&quat);\n" +" float actualDepth = minDist-radius;\n" +" \n" +" if (actualDepth<=0.f)\n" +" {\n" +" pOnB1.w = actualDepth;\n" +" int dstIdx;\n" +" \n" +" float lenSqr = dot3F4(normalOnSurfaceB1,normalOnSurfaceB1);\n" +" if (lenSqr>FLT_EPSILON)\n" +" {\n" +" AppendInc( nGlobalContactsOut, dstIdx );\n" +" \n" +" if (dstIdx < maxContactCapacity)\n" +" {\n" +" __global struct b3Contact4Data* c = &globalContactsOut[dstIdx];\n" +" c->m_worldNormalOnB = -normalOnSurfaceB1;\n" +" c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff);\n" +" c->m_batchIdx = pairIndex;\n" +" c->m_bodyAPtrAndSignBit = rigidBodies[bodyIndexA].m_invMass==0?-bodyIndexA:bodyIndexA;\n" +" c->m_bodyBPtrAndSignBit = rigidBodies[bodyIndexB].m_invMass==0?-bodyIndexB:bodyIndexB;\n" +" c->m_worldPosB[0] = pOnB1;\n" +" c->m_childIndexA = -1;\n" +" c->m_childIndexB = faceIndex;\n" +" GET_NPOINTS(*c) = 1;\n" +" } \n" +" }\n" +" }\n" +" }//if (hasCollision)\n" +"}\n" +"// work-in-progress\n" +"__kernel void findConcaveSphereContactsKernel( __global int4* concavePairs,\n" +" __global const BodyData* rigidBodies,\n" +" __global const btCollidableGpu* collidables,\n" +" __global const ConvexPolyhedronCL* convexShapes, \n" +" __global const float4* vertices,\n" +" __global const float4* uniqueEdges,\n" +" __global const btGpuFace* faces,\n" +" __global const int* indices,\n" +" __global btAabbCL* aabbs,\n" +" __global struct b3Contact4Data* restrict globalContactsOut,\n" +" counter32_t nGlobalContactsOut,\n" +" int numConcavePairs, int maxContactCapacity\n" +" )\n" +"{\n" +" int i = get_global_id(0);\n" +" if (i>=numConcavePairs)\n" +" return;\n" +" int pairIdx = i;\n" +" int bodyIndexA = concavePairs[i].x;\n" +" int bodyIndexB = concavePairs[i].y;\n" +" int collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx;\n" +" int collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx;\n" +" int shapeIndexA = collidables[collidableIndexA].m_shapeIndex;\n" +" int shapeIndexB = collidables[collidableIndexB].m_shapeIndex;\n" +" if (collidables[collidableIndexB].m_shapeType==SHAPE_SPHERE)\n" +" {\n" +" int f = concavePairs[i].z;\n" +" btGpuFace face = faces[convexShapes[shapeIndexA].m_faceOffset+f];\n" +" \n" +" float4 verticesA[3];\n" +" for (int i=0;i<3;i++)\n" +" {\n" +" int index = indices[face.m_indexOffset+i];\n" +" float4 vert = vertices[convexShapes[shapeIndexA].m_vertexOffset+index];\n" +" verticesA[i] = vert;\n" +" }\n" +" float4 spherePos = rigidBodies[bodyIndexB].m_pos;\n" +" float sphereRadius = collidables[collidableIndexB].m_radius;\n" +" float4 convexPos = rigidBodies[bodyIndexA].m_pos;\n" +" float4 convexOrn = rigidBodies[bodyIndexA].m_quat;\n" +" computeContactSphereTriangle(i, bodyIndexB, bodyIndexA, collidableIndexB, collidableIndexA, \n" +" rigidBodies,collidables,\n" +" verticesA,\n" +" globalContactsOut, nGlobalContactsOut,maxContactCapacity,\n" +" spherePos,sphereRadius,convexPos,convexOrn, f);\n" +" return;\n" +" }\n" +"}\n" +; diff --git a/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/kernels/sat.cl b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/kernels/sat.cl new file mode 100644 index 000000000000..a6565fd6fac9 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/NarrowphaseCollision/kernels/sat.cl @@ -0,0 +1,2018 @@ +//keep this enum in sync with the CPU version (in btCollidable.h) +//written by Erwin Coumans + + +#define SHAPE_CONVEX_HULL 3 +#define SHAPE_CONCAVE_TRIMESH 5 +#define TRIANGLE_NUM_CONVEX_FACES 5 +#define SHAPE_COMPOUND_OF_CONVEX_HULLS 6 + +#define B3_MAX_STACK_DEPTH 256 + + +typedef unsigned int u32; + +///keep this in sync with btCollidable.h +typedef struct +{ + union { + int m_numChildShapes; + int m_bvhIndex; + }; + union + { + float m_radius; + int m_compoundBvhIndex; + }; + + int m_shapeType; + int m_shapeIndex; + +} btCollidableGpu; + +#define MAX_NUM_PARTS_IN_BITS 10 + +///b3QuantizedBvhNode 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). +typedef struct +{ + //12 bytes + unsigned short int m_quantizedAabbMin[3]; + unsigned short int m_quantizedAabbMax[3]; + //4 bytes + int m_escapeIndexOrTriangleIndex; +} b3QuantizedBvhNode; + +typedef struct +{ + float4 m_aabbMin; + float4 m_aabbMax; + float4 m_quantization; + int m_numNodes; + int m_numSubTrees; + int m_nodeOffset; + int m_subTreeOffset; + +} b3BvhInfo; + + +int getTriangleIndex(const b3QuantizedBvhNode* rootNode) +{ + unsigned int x=0; + unsigned int y = (~(x&0))<<(31-MAX_NUM_PARTS_IN_BITS); + // Get only the lower bits where the triangle index is stored + return (rootNode->m_escapeIndexOrTriangleIndex&~(y)); +} + +int getTriangleIndexGlobal(__global const b3QuantizedBvhNode* rootNode) +{ + unsigned int x=0; + unsigned int y = (~(x&0))<<(31-MAX_NUM_PARTS_IN_BITS); + // Get only the lower bits where the triangle index is stored + return (rootNode->m_escapeIndexOrTriangleIndex&~(y)); +} + +int isLeafNode(const b3QuantizedBvhNode* rootNode) +{ + //skipindex is negative (internal node), triangleindex >=0 (leafnode) + return (rootNode->m_escapeIndexOrTriangleIndex >= 0)? 1 : 0; +} + +int isLeafNodeGlobal(__global const b3QuantizedBvhNode* rootNode) +{ + //skipindex is negative (internal node), triangleindex >=0 (leafnode) + return (rootNode->m_escapeIndexOrTriangleIndex >= 0)? 1 : 0; +} + +int getEscapeIndex(const b3QuantizedBvhNode* rootNode) +{ + return -rootNode->m_escapeIndexOrTriangleIndex; +} + +int getEscapeIndexGlobal(__global const b3QuantizedBvhNode* rootNode) +{ + return -rootNode->m_escapeIndexOrTriangleIndex; +} + + +typedef struct +{ + //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]; +} b3BvhSubtreeInfo; + + + + + + + +typedef struct +{ + float4 m_childPosition; + float4 m_childOrientation; + int m_shapeIndex; + int m_unused0; + int m_unused1; + int m_unused2; +} btGpuChildShape; + + +typedef struct +{ + float4 m_pos; + float4 m_quat; + float4 m_linVel; + float4 m_angVel; + + u32 m_collidableIdx; + float m_invMass; + float m_restituitionCoeff; + float m_frictionCoeff; +} BodyData; + + +typedef struct +{ + float4 m_localCenter; + float4 m_extents; + float4 mC; + float4 mE; + + float m_radius; + int m_faceOffset; + int m_numFaces; + int m_numVertices; + + int m_vertexOffset; + int m_uniqueEdgesOffset; + int m_numUniqueEdges; + int m_unused; +} ConvexPolyhedronCL; + +typedef struct +{ + union + { + float4 m_min; + float m_minElems[4]; + int m_minIndices[4]; + }; + union + { + float4 m_max; + float m_maxElems[4]; + int m_maxIndices[4]; + }; +} btAabbCL; + +#include "Bullet3Collision/BroadPhaseCollision/shared/b3Aabb.h" +#include "Bullet3Common/shared/b3Int2.h" + + + +typedef struct +{ + float4 m_plane; + int m_indexOffset; + int m_numIndices; +} btGpuFace; + +#define make_float4 (float4) + + +__inline +float4 cross3(float4 a, float4 b) +{ + return cross(a,b); + + +// float4 a1 = make_float4(a.xyz,0.f); +// float4 b1 = make_float4(b.xyz,0.f); + +// return cross(a1,b1); + +//float4 c = make_float4(a.y*b.z - a.z*b.y,a.z*b.x - a.x*b.z,a.x*b.y - a.y*b.x,0.f); + + // float4 c = make_float4(a.y*b.z - a.z*b.y,1.f,a.x*b.y - a.y*b.x,0.f); + + //return c; +} + +__inline +float dot3F4(float4 a, float4 b) +{ + float4 a1 = make_float4(a.xyz,0.f); + float4 b1 = make_float4(b.xyz,0.f); + return dot(a1, b1); +} + +__inline +float4 fastNormalize4(float4 v) +{ + v = make_float4(v.xyz,0.f); + return fast_normalize(v); +} + + +/////////////////////////////////////// +// Quaternion +/////////////////////////////////////// + +typedef float4 Quaternion; + +__inline +Quaternion qtMul(Quaternion a, Quaternion b); + +__inline +Quaternion qtNormalize(Quaternion in); + +__inline +float4 qtRotate(Quaternion q, float4 vec); + +__inline +Quaternion qtInvert(Quaternion q); + + + + +__inline +Quaternion qtMul(Quaternion a, Quaternion b) +{ + Quaternion ans; + ans = cross3( a, b ); + ans += a.w*b+b.w*a; +// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z); + ans.w = a.w*b.w - dot3F4(a, b); + return ans; +} + +__inline +Quaternion qtNormalize(Quaternion in) +{ + return fastNormalize4(in); +// in /= length( in ); +// return in; +} +__inline +float4 qtRotate(Quaternion q, float4 vec) +{ + Quaternion qInv = qtInvert( q ); + float4 vcpy = vec; + vcpy.w = 0.f; + float4 out = qtMul(qtMul(q,vcpy),qInv); + return out; +} + +__inline +Quaternion qtInvert(Quaternion q) +{ + return (Quaternion)(-q.xyz, q.w); +} + +__inline +float4 qtInvRotate(const Quaternion q, float4 vec) +{ + return qtRotate( qtInvert( q ), vec ); +} + +__inline +float4 transform(const float4* p, const float4* translation, const Quaternion* orientation) +{ + return qtRotate( *orientation, *p ) + (*translation); +} + + + +__inline +float4 normalize3(const float4 a) +{ + float4 n = make_float4(a.x, a.y, a.z, 0.f); + return fastNormalize4( n ); +} + +inline void projectLocal(const ConvexPolyhedronCL* hull, const float4 pos, const float4 orn, +const float4* dir, const float4* vertices, float* min, float* max) +{ + min[0] = FLT_MAX; + max[0] = -FLT_MAX; + int numVerts = hull->m_numVertices; + + const float4 localDir = qtInvRotate(orn,*dir); + float offset = dot(pos,*dir); + for(int i=0;im_vertexOffset+i],localDir); + if(dp < min[0]) + min[0] = dp; + if(dp > max[0]) + max[0] = dp; + } + if(min[0]>max[0]) + { + float tmp = min[0]; + min[0] = max[0]; + max[0] = tmp; + } + min[0] += offset; + max[0] += offset; +} + +inline void project(__global const ConvexPolyhedronCL* hull, const float4 pos, const float4 orn, +const float4* dir, __global const float4* vertices, float* min, float* max) +{ + min[0] = FLT_MAX; + max[0] = -FLT_MAX; + int numVerts = hull->m_numVertices; + + const float4 localDir = qtInvRotate(orn,*dir); + float offset = dot(pos,*dir); + for(int i=0;im_vertexOffset+i],localDir); + if(dp < min[0]) + min[0] = dp; + if(dp > max[0]) + max[0] = dp; + } + if(min[0]>max[0]) + { + float tmp = min[0]; + min[0] = max[0]; + max[0] = tmp; + } + min[0] += offset; + max[0] += offset; +} + +inline bool TestSepAxisLocalA(const ConvexPolyhedronCL* hullA, __global const ConvexPolyhedronCL* hullB, + const float4 posA,const float4 ornA, + const float4 posB,const float4 ornB, + float4* sep_axis, const float4* verticesA, __global const float4* verticesB,float* depth) +{ + float Min0,Max0; + float Min1,Max1; + projectLocal(hullA,posA,ornA,sep_axis,verticesA, &Min0, &Max0); + project(hullB,posB,ornB, sep_axis,verticesB, &Min1, &Max1); + + if(Max01e-6f || fabs(v.y)>1e-6f || fabs(v.z)>1e-6f) + return false; + return true; +} + + + +bool findSeparatingAxisLocalA( const ConvexPolyhedronCL* hullA, __global const ConvexPolyhedronCL* hullB, + const float4 posA1, + const float4 ornA, + const float4 posB1, + const float4 ornB, + const float4 DeltaC2, + + const float4* verticesA, + const float4* uniqueEdgesA, + const btGpuFace* facesA, + const int* indicesA, + + __global const float4* verticesB, + __global const float4* uniqueEdgesB, + __global const btGpuFace* facesB, + __global const int* indicesB, + float4* sep, + float* dmin) +{ + + + float4 posA = posA1; + posA.w = 0.f; + float4 posB = posB1; + posB.w = 0.f; + int curPlaneTests=0; + { + int numFacesA = hullA->m_numFaces; + // Test normals from hullA + for(int i=0;im_faceOffset+i].m_plane; + float4 faceANormalWS = qtRotate(ornA,normal); + if (dot3F4(DeltaC2,faceANormalWS)<0) + faceANormalWS*=-1.f; + curPlaneTests++; + float d; + if(!TestSepAxisLocalA( hullA, hullB, posA,ornA,posB,ornB,&faceANormalWS, verticesA, verticesB,&d)) + return false; + if(d<*dmin) + { + *dmin = d; + *sep = faceANormalWS; + } + } + } + if((dot3F4(-DeltaC2,*sep))>0.0f) + { + *sep = -(*sep); + } + return true; +} + +bool findSeparatingAxisLocalB( __global const ConvexPolyhedronCL* hullA, const ConvexPolyhedronCL* hullB, + const float4 posA1, + const float4 ornA, + const float4 posB1, + const float4 ornB, + const float4 DeltaC2, + __global const float4* verticesA, + __global const float4* uniqueEdgesA, + __global const btGpuFace* facesA, + __global const int* indicesA, + const float4* verticesB, + const float4* uniqueEdgesB, + const btGpuFace* facesB, + const int* indicesB, + float4* sep, + float* dmin) +{ + + + float4 posA = posA1; + posA.w = 0.f; + float4 posB = posB1; + posB.w = 0.f; + int curPlaneTests=0; + { + int numFacesA = hullA->m_numFaces; + // Test normals from hullA + for(int i=0;im_faceOffset+i].m_plane; + float4 faceANormalWS = qtRotate(ornA,normal); + if (dot3F4(DeltaC2,faceANormalWS)<0) + faceANormalWS *= -1.f; + curPlaneTests++; + float d; + if(!TestSepAxisLocalA( hullB, hullA, posB,ornB,posA,ornA, &faceANormalWS, verticesB,verticesA, &d)) + return false; + if(d<*dmin) + { + *dmin = d; + *sep = faceANormalWS; + } + } + } + if((dot3F4(-DeltaC2,*sep))>0.0f) + { + *sep = -(*sep); + } + return true; +} + + + +bool findSeparatingAxisEdgeEdgeLocalA( const ConvexPolyhedronCL* hullA, __global const ConvexPolyhedronCL* hullB, + const float4 posA1, + const float4 ornA, + const float4 posB1, + const float4 ornB, + const float4 DeltaC2, + const float4* verticesA, + const float4* uniqueEdgesA, + const btGpuFace* facesA, + const int* indicesA, + __global const float4* verticesB, + __global const float4* uniqueEdgesB, + __global const btGpuFace* facesB, + __global const int* indicesB, + float4* sep, + float* dmin) +{ + + + float4 posA = posA1; + posA.w = 0.f; + float4 posB = posB1; + posB.w = 0.f; + + int curPlaneTests=0; + + int curEdgeEdge = 0; + // Test edges + for(int e0=0;e0m_numUniqueEdges;e0++) + { + const float4 edge0 = uniqueEdgesA[hullA->m_uniqueEdgesOffset+e0]; + float4 edge0World = qtRotate(ornA,edge0); + + for(int e1=0;e1m_numUniqueEdges;e1++) + { + const float4 edge1 = uniqueEdgesB[hullB->m_uniqueEdgesOffset+e1]; + float4 edge1World = qtRotate(ornB,edge1); + + + float4 crossje = cross3(edge0World,edge1World); + + curEdgeEdge++; + if(!IsAlmostZero(crossje)) + { + crossje = normalize3(crossje); + if (dot3F4(DeltaC2,crossje)<0) + crossje *= -1.f; + + float dist; + bool result = true; + { + float Min0,Max0; + float Min1,Max1; + projectLocal(hullA,posA,ornA,&crossje,verticesA, &Min0, &Max0); + project(hullB,posB,ornB,&crossje,verticesB, &Min1, &Max1); + + if(Max00.0f) + { + *sep = -(*sep); + } + return true; +} + + +inline bool TestSepAxis(__global const ConvexPolyhedronCL* hullA, __global const ConvexPolyhedronCL* hullB, + const float4 posA,const float4 ornA, + const float4 posB,const float4 ornB, + float4* sep_axis, __global const float4* vertices,float* depth) +{ + float Min0,Max0; + float Min1,Max1; + project(hullA,posA,ornA,sep_axis,vertices, &Min0, &Max0); + project(hullB,posB,ornB, sep_axis,vertices, &Min1, &Max1); + + if(Max0m_numFaces; + // Test normals from hullA + for(int i=0;im_faceOffset+i].m_plane; + float4 faceANormalWS = qtRotate(ornA,normal); + + if (dot3F4(DeltaC2,faceANormalWS)<0) + faceANormalWS*=-1.f; + + curPlaneTests++; + + float d; + if(!TestSepAxis( hullA, hullB, posA,ornA,posB,ornB,&faceANormalWS, vertices,&d)) + return false; + + if(d<*dmin) + { + *dmin = d; + *sep = faceANormalWS; + } + } + } + + + if((dot3F4(-DeltaC2,*sep))>0.0f) + { + *sep = -(*sep); + } + + return true; +} + + + + +bool findSeparatingAxisUnitSphere( __global const ConvexPolyhedronCL* hullA, __global const ConvexPolyhedronCL* hullB, + const float4 posA1, + const float4 ornA, + const float4 posB1, + const float4 ornB, + const float4 DeltaC2, + __global const float4* vertices, + __global const float4* unitSphereDirections, + int numUnitSphereDirections, + float4* sep, + float* dmin) +{ + + float4 posA = posA1; + posA.w = 0.f; + float4 posB = posB1; + posB.w = 0.f; + + int curPlaneTests=0; + + int curEdgeEdge = 0; + // Test unit sphere directions + for (int i=0;i0) + crossje *= -1.f; + { + float dist; + bool result = true; + float Min0,Max0; + float Min1,Max1; + project(hullA,posA,ornA,&crossje,vertices, &Min0, &Max0); + project(hullB,posB,ornB,&crossje,vertices, &Min1, &Max1); + + if(Max00.0f) + { + *sep = -(*sep); + } + return true; +} + + +bool findSeparatingAxisEdgeEdge( __global const ConvexPolyhedronCL* hullA, __global const ConvexPolyhedronCL* hullB, + const float4 posA1, + const float4 ornA, + const float4 posB1, + const float4 ornB, + const float4 DeltaC2, + __global const float4* vertices, + __global const float4* uniqueEdges, + __global const btGpuFace* faces, + __global const int* indices, + float4* sep, + float* dmin) +{ + + + float4 posA = posA1; + posA.w = 0.f; + float4 posB = posB1; + posB.w = 0.f; + + int curPlaneTests=0; + + int curEdgeEdge = 0; + // Test edges + for(int e0=0;e0m_numUniqueEdges;e0++) + { + const float4 edge0 = uniqueEdges[hullA->m_uniqueEdgesOffset+e0]; + float4 edge0World = qtRotate(ornA,edge0); + + for(int e1=0;e1m_numUniqueEdges;e1++) + { + const float4 edge1 = uniqueEdges[hullB->m_uniqueEdgesOffset+e1]; + float4 edge1World = qtRotate(ornB,edge1); + + + float4 crossje = cross3(edge0World,edge1World); + + curEdgeEdge++; + if(!IsAlmostZero(crossje)) + { + crossje = normalize3(crossje); + if (dot3F4(DeltaC2,crossje)<0) + crossje*=-1.f; + + float dist; + bool result = true; + { + float Min0,Max0; + float Min1,Max1; + project(hullA,posA,ornA,&crossje,vertices, &Min0, &Max0); + project(hullB,posB,ornB,&crossje,vertices, &Min1, &Max1); + + if(Max00.0f) + { + *sep = -(*sep); + } + return true; +} + + +// work-in-progress +__kernel void processCompoundPairsKernel( __global const int4* gpuCompoundPairs, + __global const BodyData* rigidBodies, + __global const btCollidableGpu* collidables, + __global const ConvexPolyhedronCL* convexShapes, + __global const float4* vertices, + __global const float4* uniqueEdges, + __global const btGpuFace* faces, + __global const int* indices, + __global btAabbCL* aabbs, + __global const btGpuChildShape* gpuChildShapes, + __global volatile float4* gpuCompoundSepNormalsOut, + __global volatile int* gpuHasCompoundSepNormalsOut, + int numCompoundPairs + ) +{ + + int i = get_global_id(0); + if (i= 0) + { + collidableIndexA = gpuChildShapes[childShapeIndexA].m_shapeIndex; + float4 childPosA = gpuChildShapes[childShapeIndexA].m_childPosition; + float4 childOrnA = gpuChildShapes[childShapeIndexA].m_childOrientation; + float4 newPosA = qtRotate(ornA,childPosA)+posA; + float4 newOrnA = qtMul(ornA,childOrnA); + posA = newPosA; + ornA = newOrnA; + } else + { + collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx; + } + + if (childShapeIndexB>=0) + { + collidableIndexB = gpuChildShapes[childShapeIndexB].m_shapeIndex; + float4 childPosB = gpuChildShapes[childShapeIndexB].m_childPosition; + float4 childOrnB = gpuChildShapes[childShapeIndexB].m_childOrientation; + float4 newPosB = transform(&childPosB,&posB,&ornB); + float4 newOrnB = qtMul(ornB,childOrnB); + posB = newPosB; + ornB = newOrnB; + } else + { + collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx; + } + + gpuHasCompoundSepNormalsOut[i] = 0; + + int shapeIndexA = collidables[collidableIndexA].m_shapeIndex; + int shapeIndexB = collidables[collidableIndexB].m_shapeIndex; + + int shapeTypeA = collidables[collidableIndexA].m_shapeType; + int shapeTypeB = collidables[collidableIndexB].m_shapeType; + + + if ((shapeTypeA != SHAPE_CONVEX_HULL) || (shapeTypeB != SHAPE_CONVEX_HULL)) + { + return; + } + + int hasSeparatingAxis = 5; + + int numFacesA = convexShapes[shapeIndexA].m_numFaces; + float dmin = FLT_MAX; + posA.w = 0.f; + posB.w = 0.f; + float4 c0local = convexShapes[shapeIndexA].m_localCenter; + float4 c0 = transform(&c0local, &posA, &ornA); + float4 c1local = convexShapes[shapeIndexB].m_localCenter; + float4 c1 = transform(&c1local,&posB,&ornB); + const float4 DeltaC2 = c0 - c1; + float4 sepNormal = make_float4(1,0,0,0); + bool sepA = findSeparatingAxis( &convexShapes[shapeIndexA], &convexShapes[shapeIndexB],posA,ornA,posB,ornB,DeltaC2,vertices,uniqueEdges,faces,indices,&sepNormal,&dmin); + hasSeparatingAxis = 4; + if (!sepA) + { + hasSeparatingAxis = 0; + } else + { + bool sepB = findSeparatingAxis( &convexShapes[shapeIndexB],&convexShapes[shapeIndexA],posB,ornB,posA,ornA,DeltaC2,vertices,uniqueEdges,faces,indices,&sepNormal,&dmin); + + if (!sepB) + { + hasSeparatingAxis = 0; + } else//(!sepB) + { + bool sepEE = findSeparatingAxisEdgeEdge( &convexShapes[shapeIndexA], &convexShapes[shapeIndexB],posA,ornA,posB,ornB,DeltaC2,vertices,uniqueEdges,faces,indices,&sepNormal,&dmin); + if (sepEE) + { + gpuCompoundSepNormalsOut[i] = sepNormal;//fastNormalize4(sepNormal); + gpuHasCompoundSepNormalsOut[i] = 1; + }//sepEE + }//(!sepB) + }//(!sepA) + + + } + +} + + +inline b3Float4 MyUnQuantize(const unsigned short* vecIn, b3Float4 quantization, b3Float4 bvhAabbMin) +{ + b3Float4 vecOut; + vecOut = b3MakeFloat4( + (float)(vecIn[0]) / (quantization.x), + (float)(vecIn[1]) / (quantization.y), + (float)(vecIn[2]) / (quantization.z), + 0.f); + + vecOut += bvhAabbMin; + return vecOut; +} + +inline b3Float4 MyUnQuantizeGlobal(__global const unsigned short* vecIn, b3Float4 quantization, b3Float4 bvhAabbMin) +{ + b3Float4 vecOut; + vecOut = b3MakeFloat4( + (float)(vecIn[0]) / (quantization.x), + (float)(vecIn[1]) / (quantization.y), + (float)(vecIn[2]) / (quantization.z), + 0.f); + + vecOut += bvhAabbMin; + return vecOut; +} + + +// work-in-progress +__kernel void findCompoundPairsKernel( __global const int4* pairs, + __global const BodyData* rigidBodies, + __global const btCollidableGpu* collidables, + __global const ConvexPolyhedronCL* convexShapes, + __global const float4* vertices, + __global const float4* uniqueEdges, + __global const btGpuFace* faces, + __global const int* indices, + __global b3Aabb_t* aabbLocalSpace, + __global const btGpuChildShape* gpuChildShapes, + __global volatile int4* gpuCompoundPairsOut, + __global volatile int* numCompoundPairsOut, + __global const b3BvhSubtreeInfo* subtrees, + __global const b3QuantizedBvhNode* quantizedNodes, + __global const b3BvhInfo* bvhInfos, + int numPairs, + int maxNumCompoundPairsCapacity + ) +{ + + int i = get_global_id(0); + + if (imaxStackDepth && !(isLeafA && isLeafB)) + { + //printf("Error: traversal exceeded maxStackDepth"); + continue; + } + + if(isInternalA) + { + int nodeAleftChild = node.x+1; + bool isNodeALeftChildLeaf = isLeafNodeGlobal(&quantizedNodes[node.x+1]); + int nodeArightChild = isNodeALeftChildLeaf? node.x+2 : node.x+1 + getEscapeIndexGlobal(&quantizedNodes[node.x+1]); + + if(isInternalB) + { + int nodeBleftChild = node.y+1; + bool isNodeBLeftChildLeaf = isLeafNodeGlobal(&quantizedNodes[node.y+1]); + int nodeBrightChild = isNodeBLeftChildLeaf? node.y+2 : node.y+1 + getEscapeIndexGlobal(&quantizedNodes[node.y+1]); + + nodeStack[depth++] = b3MakeInt2(nodeAleftChild, nodeBleftChild); + nodeStack[depth++] = b3MakeInt2(nodeArightChild, nodeBleftChild); + nodeStack[depth++] = b3MakeInt2(nodeAleftChild, nodeBrightChild); + nodeStack[depth++] = b3MakeInt2(nodeArightChild, nodeBrightChild); + } + else + { + nodeStack[depth++] = b3MakeInt2(nodeAleftChild,node.y); + nodeStack[depth++] = b3MakeInt2(nodeArightChild,node.y); + } + } + else + { + if(isInternalB) + { + int nodeBleftChild = node.y+1; + bool isNodeBLeftChildLeaf = isLeafNodeGlobal(&quantizedNodes[node.y+1]); + int nodeBrightChild = isNodeBLeftChildLeaf? node.y+2 : node.y+1 + getEscapeIndexGlobal(&quantizedNodes[node.y+1]); + nodeStack[depth++] = b3MakeInt2(node.x,nodeBleftChild); + nodeStack[depth++] = b3MakeInt2(node.x,nodeBrightChild); + } + else + { + int compoundPairIdx = atomic_inc(numCompoundPairsOut); + if (compoundPairIdxm_numFaces;face++) + { + const float4 Normal = make_float4(facesB[hullB->m_faceOffset+face].m_plane.x, + facesB[hullB->m_faceOffset+face].m_plane.y, facesB[hullB->m_faceOffset+face].m_plane.z,0.f); + const float4 WorldNormal = qtRotate(ornB, Normal); + float d = dot3F4(WorldNormal,separatingNormal); + if (d > dmax) + { + dmax = d; + closestFaceB = face; + } + } + } + + { + const btGpuFace polyB = facesB[hullB->m_faceOffset+closestFaceB]; + int numVertices = polyB.m_numIndices; + if (numVertices>capacityWorldVerts) + numVertices = capacityWorldVerts; + + for(int e0=0;e0m_vertexOffset+indicesB[polyB.m_indexOffset+e0]]; + worldVertsB1[pairIndex*capacityWorldVerts+numWorldVertsB1++] = transform(&b,&posB,&ornB); + } + } + } + + int closestFaceA=0; + { + float dmin = FLT_MAX; + for(int face=0;facem_numFaces;face++) + { + const float4 Normal = make_float4( + facesA[hullA->m_faceOffset+face].m_plane.x, + facesA[hullA->m_faceOffset+face].m_plane.y, + facesA[hullA->m_faceOffset+face].m_plane.z, + 0.f); + const float4 faceANormalWS = qtRotate(ornA,Normal); + + float d = dot3F4(faceANormalWS,separatingNormal); + if (d < dmin) + { + dmin = d; + closestFaceA = face; + worldNormalsA1[pairIndex] = faceANormalWS; + } + } + } + + int numVerticesA = facesA[hullA->m_faceOffset+closestFaceA].m_numIndices; + if (numVerticesA>capacityWorldVerts) + numVerticesA = capacityWorldVerts; + + for(int e0=0;e0m_vertexOffset+indicesA[facesA[hullA->m_faceOffset+closestFaceA].m_indexOffset+e0]]; + worldVertsA1[pairIndex*capacityWorldVerts+e0] = transform(&a, &posA,&ornA); + } + } + + clippingFaces[pairIndex].x = closestFaceA; + clippingFaces[pairIndex].y = closestFaceB; + clippingFaces[pairIndex].z = numVerticesA; + clippingFaces[pairIndex].w = numWorldVertsB1; + + + return numContactsOut; +} + + + + +// work-in-progress +__kernel void findConcaveSeparatingAxisKernel( __global int4* concavePairs, + __global const BodyData* rigidBodies, + __global const btCollidableGpu* collidables, + __global const ConvexPolyhedronCL* convexShapes, + __global const float4* vertices, + __global const float4* uniqueEdges, + __global const btGpuFace* faces, + __global const int* indices, + __global const btGpuChildShape* gpuChildShapes, + __global btAabbCL* aabbs, + __global float4* concaveSeparatingNormalsOut, + __global int* concaveHasSeparatingNormals, + __global int4* clippingFacesOut, + __global float4* worldVertsA1GPU, + __global float4* worldNormalsAGPU, + __global float4* worldVertsB1GPU, + int vertexFaceCapacity, + int numConcavePairs + ) +{ + + int i = get_global_id(0); + if (i>=numConcavePairs) + return; + + concaveHasSeparatingNormals[i] = 0; + + int pairIdx = i; + + int bodyIndexA = concavePairs[i].x; + int bodyIndexB = concavePairs[i].y; + + int collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx; + int collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx; + + int shapeIndexA = collidables[collidableIndexA].m_shapeIndex; + int shapeIndexB = collidables[collidableIndexB].m_shapeIndex; + + if (collidables[collidableIndexB].m_shapeType!=SHAPE_CONVEX_HULL&& + collidables[collidableIndexB].m_shapeType!=SHAPE_COMPOUND_OF_CONVEX_HULLS) + { + concavePairs[pairIdx].w = -1; + return; + } + + + + int numFacesA = convexShapes[shapeIndexA].m_numFaces; + int numActualConcaveConvexTests = 0; + + int f = concavePairs[i].z; + + bool overlap = false; + + ConvexPolyhedronCL convexPolyhedronA; + + //add 3 vertices of the triangle + convexPolyhedronA.m_numVertices = 3; + convexPolyhedronA.m_vertexOffset = 0; + float4 localCenter = make_float4(0.f,0.f,0.f,0.f); + + btGpuFace face = faces[convexShapes[shapeIndexA].m_faceOffset+f]; + float4 triMinAabb, triMaxAabb; + btAabbCL triAabb; + triAabb.m_min = make_float4(1e30f,1e30f,1e30f,0.f); + triAabb.m_max = make_float4(-1e30f,-1e30f,-1e30f,0.f); + + float4 verticesA[3]; + for (int i=0;i<3;i++) + { + int index = indices[face.m_indexOffset+i]; + float4 vert = vertices[convexShapes[shapeIndexA].m_vertexOffset+index]; + verticesA[i] = vert; + localCenter += vert; + + triAabb.m_min = min(triAabb.m_min,vert); + triAabb.m_max = max(triAabb.m_max,vert); + + } + + overlap = true; + overlap = (triAabb.m_min.x > aabbs[bodyIndexB].m_max.x || triAabb.m_max.x < aabbs[bodyIndexB].m_min.x) ? false : overlap; + overlap = (triAabb.m_min.z > aabbs[bodyIndexB].m_max.z || triAabb.m_max.z < aabbs[bodyIndexB].m_min.z) ? false : overlap; + overlap = (triAabb.m_min.y > aabbs[bodyIndexB].m_max.y || triAabb.m_max.y < aabbs[bodyIndexB].m_min.y) ? false : overlap; + + if (overlap) + { + float dmin = FLT_MAX; + int hasSeparatingAxis=5; + float4 sepAxis=make_float4(1,2,3,4); + + int localCC=0; + numActualConcaveConvexTests++; + + //a triangle has 3 unique edges + convexPolyhedronA.m_numUniqueEdges = 3; + convexPolyhedronA.m_uniqueEdgesOffset = 0; + float4 uniqueEdgesA[3]; + + uniqueEdgesA[0] = (verticesA[1]-verticesA[0]); + uniqueEdgesA[1] = (verticesA[2]-verticesA[1]); + uniqueEdgesA[2] = (verticesA[0]-verticesA[2]); + + + convexPolyhedronA.m_faceOffset = 0; + + float4 normal = make_float4(face.m_plane.x,face.m_plane.y,face.m_plane.z,0.f); + + btGpuFace facesA[TRIANGLE_NUM_CONVEX_FACES]; + int indicesA[3+3+2+2+2]; + int curUsedIndices=0; + int fidx=0; + + //front size of triangle + { + facesA[fidx].m_indexOffset=curUsedIndices; + indicesA[0] = 0; + indicesA[1] = 1; + indicesA[2] = 2; + curUsedIndices+=3; + float c = face.m_plane.w; + facesA[fidx].m_plane.x = normal.x; + facesA[fidx].m_plane.y = normal.y; + facesA[fidx].m_plane.z = normal.z; + facesA[fidx].m_plane.w = c; + facesA[fidx].m_numIndices=3; + } + fidx++; + //back size of triangle + { + facesA[fidx].m_indexOffset=curUsedIndices; + indicesA[3]=2; + indicesA[4]=1; + indicesA[5]=0; + curUsedIndices+=3; + float c = dot(normal,verticesA[0]); + float c1 = -face.m_plane.w; + facesA[fidx].m_plane.x = -normal.x; + facesA[fidx].m_plane.y = -normal.y; + facesA[fidx].m_plane.z = -normal.z; + facesA[fidx].m_plane.w = c; + facesA[fidx].m_numIndices=3; + } + fidx++; + + bool addEdgePlanes = true; + if (addEdgePlanes) + { + int numVertices=3; + int prevVertex = numVertices-1; + for (int i=0;i= 0, so output intersection + ppVtxOut[numVertsOut++] = lerp3(firstVertex, endVertex,(ds * 1.f/(ds - de)) ); + } + } + else + { + if (de<0) + { + // Start >= 0, end < 0 so output intersection and end + ppVtxOut[numVertsOut++] = lerp3(firstVertex, endVertex,(ds * 1.f/(ds - de)) ); + ppVtxOut[numVertsOut++] = endVertex; + } + } + firstVertex = endVertex; + ds = de; + } + return numVertsOut; +} + + + +// Clips a face to the back of a plane, return the number of vertices out, stored in ppVtxOut +int clipFace(const float4* pVtxIn, int numVertsIn, float4 planeNormalWS,float planeEqWS, float4* ppVtxOut) +{ + + int ve; + float ds, de; + int numVertsOut = 0; +//double-check next test + if (numVertsIn < 2) + return 0; + + float4 firstVertex=pVtxIn[numVertsIn-1]; + float4 endVertex = pVtxIn[0]; + + ds = dot3F4(planeNormalWS,firstVertex)+planeEqWS; + + for (ve = 0; ve < numVertsIn; ve++) + { + endVertex=pVtxIn[ve]; + + de = dot3F4(planeNormalWS,endVertex)+planeEqWS; + + if (ds<0) + { + if (de<0) + { + // Start < 0, end < 0, so output endVertex + ppVtxOut[numVertsOut++] = endVertex; + } + else + { + // Start < 0, end >= 0, so output intersection + ppVtxOut[numVertsOut++] = lerp3(firstVertex, endVertex,(ds * 1.f/(ds - de)) ); + } + } + else + { + if (de<0) + { + // Start >= 0, end < 0 so output intersection and end + ppVtxOut[numVertsOut++] = lerp3(firstVertex, endVertex,(ds * 1.f/(ds - de)) ); + ppVtxOut[numVertsOut++] = endVertex; + } + } + firstVertex = endVertex; + ds = de; + } + return numVertsOut; +} + + +int clipFaceAgainstHull(const float4 separatingNormal, __global const b3ConvexPolyhedronData_t* hullA, + const float4 posA, const Quaternion ornA, float4* worldVertsB1, int numWorldVertsB1, + float4* worldVertsB2, int capacityWorldVertsB2, + const float minDist, float maxDist, + __global const float4* vertices, + __global const b3GpuFace_t* faces, + __global const int* indices, + float4* contactsOut, + int contactCapacity) +{ + int numContactsOut = 0; + + float4* pVtxIn = worldVertsB1; + float4* pVtxOut = worldVertsB2; + + int numVertsIn = numWorldVertsB1; + int numVertsOut = 0; + + int closestFaceA=-1; + { + float dmin = FLT_MAX; + for(int face=0;facem_numFaces;face++) + { + const float4 Normal = make_float4( + faces[hullA->m_faceOffset+face].m_plane.x, + faces[hullA->m_faceOffset+face].m_plane.y, + faces[hullA->m_faceOffset+face].m_plane.z,0.f); + const float4 faceANormalWS = qtRotate(ornA,Normal); + + float d = dot3F4(faceANormalWS,separatingNormal); + if (d < dmin) + { + dmin = d; + closestFaceA = face; + } + } + } + if (closestFaceA<0) + return numContactsOut; + + b3GpuFace_t polyA = faces[hullA->m_faceOffset+closestFaceA]; + + // clip polygon to back of planes of all faces of hull A that are adjacent to witness face + int numVerticesA = polyA.m_numIndices; + for(int e0=0;e0m_vertexOffset+indices[polyA.m_indexOffset+e0]]; + const float4 b = vertices[hullA->m_vertexOffset+indices[polyA.m_indexOffset+((e0+1)%numVerticesA)]]; + const float4 edge0 = a - b; + const float4 WorldEdge0 = qtRotate(ornA,edge0); + float4 planeNormalA = make_float4(polyA.m_plane.x,polyA.m_plane.y,polyA.m_plane.z,0.f); + float4 worldPlaneAnormal1 = qtRotate(ornA,planeNormalA); + + float4 planeNormalWS1 = -cross3(WorldEdge0,worldPlaneAnormal1); + float4 worldA1 = transform(&a,&posA,&ornA); + float planeEqWS1 = -dot3F4(worldA1,planeNormalWS1); + + float4 planeNormalWS = planeNormalWS1; + float planeEqWS=planeEqWS1; + + //clip face + //clipFace(*pVtxIn, *pVtxOut,planeNormalWS,planeEqWS); + numVertsOut = clipFace(pVtxIn, numVertsIn, planeNormalWS,planeEqWS, pVtxOut); + + //btSwap(pVtxIn,pVtxOut); + float4* tmp = pVtxOut; + pVtxOut = pVtxIn; + pVtxIn = tmp; + numVertsIn = numVertsOut; + numVertsOut = 0; + } + + + // only keep points that are behind the witness face + { + float4 localPlaneNormal = make_float4(polyA.m_plane.x,polyA.m_plane.y,polyA.m_plane.z,0.f); + float localPlaneEq = polyA.m_plane.w; + float4 planeNormalWS = qtRotate(ornA,localPlaneNormal); + float planeEqWS=localPlaneEq-dot3F4(planeNormalWS,posA); + for (int i=0;im_numFaces;face++) + { + const float4 Normal = make_float4( + facesA[hullA->m_faceOffset+face].m_plane.x, + facesA[hullA->m_faceOffset+face].m_plane.y, + facesA[hullA->m_faceOffset+face].m_plane.z,0.f); + const float4 faceANormalWS = qtRotate(ornA,Normal); + + float d = dot3F4(faceANormalWS,separatingNormal); + if (d < dmin) + { + dmin = d; + closestFaceA = face; + } + } + } + if (closestFaceA<0) + return numContactsOut; + + b3GpuFace_t polyA = facesA[hullA->m_faceOffset+closestFaceA]; + + // clip polygon to back of planes of all faces of hull A that are adjacent to witness face + int numVerticesA = polyA.m_numIndices; + for(int e0=0;e0m_vertexOffset+indicesA[polyA.m_indexOffset+e0]]; + const float4 b = verticesA[hullA->m_vertexOffset+indicesA[polyA.m_indexOffset+((e0+1)%numVerticesA)]]; + const float4 edge0 = a - b; + const float4 WorldEdge0 = qtRotate(ornA,edge0); + float4 planeNormalA = make_float4(polyA.m_plane.x,polyA.m_plane.y,polyA.m_plane.z,0.f); + float4 worldPlaneAnormal1 = qtRotate(ornA,planeNormalA); + + float4 planeNormalWS1 = -cross3(WorldEdge0,worldPlaneAnormal1); + float4 worldA1 = transform(&a,&posA,&ornA); + float planeEqWS1 = -dot3F4(worldA1,planeNormalWS1); + + float4 planeNormalWS = planeNormalWS1; + float planeEqWS=planeEqWS1; + + //clip face + //clipFace(*pVtxIn, *pVtxOut,planeNormalWS,planeEqWS); + numVertsOut = clipFace(pVtxIn, numVertsIn, planeNormalWS,planeEqWS, pVtxOut); + + //btSwap(pVtxIn,pVtxOut); + float4* tmp = pVtxOut; + pVtxOut = pVtxIn; + pVtxIn = tmp; + numVertsIn = numVertsOut; + numVertsOut = 0; + } + + + // only keep points that are behind the witness face + { + float4 localPlaneNormal = make_float4(polyA.m_plane.x,polyA.m_plane.y,polyA.m_plane.z,0.f); + float localPlaneEq = polyA.m_plane.w; + float4 planeNormalWS = qtRotate(ornA,localPlaneNormal); + float planeEqWS=localPlaneEq-dot3F4(planeNormalWS,posA); + for (int i=0;im_numFaces;face++) + { + const float4 Normal = make_float4(faces[hullB->m_faceOffset+face].m_plane.x, + faces[hullB->m_faceOffset+face].m_plane.y, faces[hullB->m_faceOffset+face].m_plane.z,0.f); + const float4 WorldNormal = qtRotate(ornB, Normal); + float d = dot3F4(WorldNormal,separatingNormal); + if (d > dmax) + { + dmax = d; + closestFaceB = face; + } + } + } + + { + const b3GpuFace_t polyB = faces[hullB->m_faceOffset+closestFaceB]; + const int numVertices = polyB.m_numIndices; + for(int e0=0;e0m_vertexOffset+indices[polyB.m_indexOffset+e0]]; + worldVertsB1[numWorldVertsB1++] = transform(&b,&posB,&ornB); + } + } + + if (closestFaceB>=0) + { + numContactsOut = clipFaceAgainstHull(separatingNormal, hullA, + posA,ornA, + worldVertsB1,numWorldVertsB1,worldVertsB2,capacityWorldVerts, minDist, maxDist,vertices, + faces, + indices,localContactsOut,localContactCapacity); + } + + return numContactsOut; +} + + +int clipHullAgainstHullLocalA(const float4 separatingNormal, + const b3ConvexPolyhedronData_t* hullA, __global const b3ConvexPolyhedronData_t* hullB, + const float4 posA, const Quaternion ornA,const float4 posB, const Quaternion ornB, + float4* worldVertsB1, float4* worldVertsB2, int capacityWorldVerts, + const float minDist, float maxDist, + const float4* verticesA, + const b3GpuFace_t* facesA, + const int* indicesA, + __global const float4* verticesB, + __global const b3GpuFace_t* facesB, + __global const int* indicesB, + float4* localContactsOut, + int localContactCapacity) +{ + int numContactsOut = 0; + int numWorldVertsB1= 0; + + + int closestFaceB=-1; + float dmax = -FLT_MAX; + + { + for(int face=0;facem_numFaces;face++) + { + const float4 Normal = make_float4(facesB[hullB->m_faceOffset+face].m_plane.x, + facesB[hullB->m_faceOffset+face].m_plane.y, facesB[hullB->m_faceOffset+face].m_plane.z,0.f); + const float4 WorldNormal = qtRotate(ornB, Normal); + float d = dot3F4(WorldNormal,separatingNormal); + if (d > dmax) + { + dmax = d; + closestFaceB = face; + } + } + } + + { + const b3GpuFace_t polyB = facesB[hullB->m_faceOffset+closestFaceB]; + const int numVertices = polyB.m_numIndices; + for(int e0=0;e0m_vertexOffset+indicesB[polyB.m_indexOffset+e0]]; + worldVertsB1[numWorldVertsB1++] = transform(&b,&posB,&ornB); + } + } + + if (closestFaceB>=0) + { + numContactsOut = clipFaceAgainstHullLocalA(separatingNormal, hullA, + posA,ornA, + worldVertsB1,numWorldVertsB1,worldVertsB2,capacityWorldVerts, minDist, maxDist, + verticesA,facesA,indicesA, + verticesB,facesB,indicesB, + localContactsOut,localContactCapacity); + } + + return numContactsOut; +} + +#define PARALLEL_SUM(v, n) for(int j=1; j v[i+offset].y)? v[i]: v[i+offset]; } +#define REDUCE_MIN(v, n) {int i=0;\ +for(int offset=0; offset64) + nPoints = 64; + + float4 center = make_float4(0.f); + { + + for (int i=0;i a[ie].x )? a[0].x: a[ie].x; + a[0].y = (a[0].y > a[ie].y )? a[0].y: a[ie].y; + a[0].z = (a[0].z > a[ie].z )? a[0].z: a[ie].z; + a[0].w = (a[0].w > a[ie].w )? a[0].w: a[ie].w; + } + + idx[0] = (int)a[0].x & 0xff; + idx[1] = (int)a[0].y & 0xff; + idx[2] = (int)a[0].z & 0xff; + idx[3] = (int)a[0].w & 0xff; + } + } + + { + float2 h[64]; + PARALLEL_DO( h[ie] = make_float2((float)ie, p[ie].w), nPoints ); + REDUCE_MIN( h, nPoints ); + max00 = h[0]; + } + } + + contactIdx[0] = idx[0]; + contactIdx[1] = idx[1]; + contactIdx[2] = idx[2]; + contactIdx[3] = idx[3]; + + + return 4; + } +} + + + +__kernel void extractManifoldAndAddContactKernel(__global const int4* pairs, + __global const b3RigidBodyData_t* rigidBodies, + __global const float4* closestPointsWorld, + __global const float4* separatingNormalsWorld, + __global const int* contactCounts, + __global const int* contactOffsets, + __global struct b3Contact4Data* restrict contactsOut, + counter32_t nContactsOut, + int contactCapacity, + int numPairs, + int pairIndex + ) +{ + int idx = get_global_id(0); + + if (idxm_worldNormalOnB = -normal; + c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff); + c->m_batchIdx = idx; + int bodyA = pairs[pairIndex].x; + int bodyB = pairs[pairIndex].y; + c->m_bodyAPtrAndSignBit = rigidBodies[bodyA].m_invMass==0 ? -bodyA:bodyA; + c->m_bodyBPtrAndSignBit = rigidBodies[bodyB].m_invMass==0 ? -bodyB:bodyB; + c->m_childIndexA = -1; + c->m_childIndexB = -1; + for (int i=0;im_worldPosB[i] = localPoints[contactIdx[i]]; + } + GET_NPOINTS(*c) = nContacts; + } + } +} + + +void trInverse(float4 translationIn, Quaternion orientationIn, + float4* translationOut, Quaternion* orientationOut) +{ + *orientationOut = qtInvert(orientationIn); + *translationOut = qtRotate(*orientationOut, -translationIn); +} + +void trMul(float4 translationA, Quaternion orientationA, + float4 translationB, Quaternion orientationB, + float4* translationOut, Quaternion* orientationOut) +{ + *orientationOut = qtMul(orientationA,orientationB); + *translationOut = transform(&translationB,&translationA,&orientationA); +} + + + + +__kernel void clipHullHullKernel( __global int4* pairs, + __global const b3RigidBodyData_t* rigidBodies, + __global const b3Collidable_t* collidables, + __global const b3ConvexPolyhedronData_t* convexShapes, + __global const float4* vertices, + __global const float4* uniqueEdges, + __global const b3GpuFace_t* faces, + __global const int* indices, + __global const float4* separatingNormals, + __global const int* hasSeparatingAxis, + __global struct b3Contact4Data* restrict globalContactsOut, + counter32_t nGlobalContactsOut, + int numPairs, + int contactCapacity) +{ + + int i = get_global_id(0); + int pairIndex = i; + + float4 worldVertsB1[64]; + float4 worldVertsB2[64]; + int capacityWorldVerts = 64; + + float4 localContactsOut[64]; + int localContactCapacity=64; + + float minDist = -1e30f; + float maxDist = 0.02f; + + if (i0) + { + float4 normal = -separatingNormals[i]; + int nPoints = numLocalContactsOut; + float4* pointsIn = localContactsOut; + int contactIdx[4];// = {-1,-1,-1,-1}; + + contactIdx[0] = -1; + contactIdx[1] = -1; + contactIdx[2] = -1; + contactIdx[3] = -1; + + int nReducedContacts = extractManifoldSequential(pointsIn, nPoints, normal, contactIdx); + + + int mprContactIndex = pairs[pairIndex].z; + + int dstIdx = mprContactIndex; + if (dstIdx<0) + { + AppendInc( nGlobalContactsOut, dstIdx ); + } + + if (dstIdxm_worldNormalOnB = -normal; + c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff); + c->m_batchIdx = pairIndex; + int bodyA = pairs[pairIndex].x; + int bodyB = pairs[pairIndex].y; + c->m_bodyAPtrAndSignBit = rigidBodies[bodyA].m_invMass==0?-bodyA:bodyA; + c->m_bodyBPtrAndSignBit = rigidBodies[bodyB].m_invMass==0?-bodyB:bodyB; + c->m_childIndexA = -1; + c->m_childIndexB = -1; + + for (int i=0;i0||(mprContactIndex<0)) + { + c->m_worldPosB[i] = pointsIn[contactIdx[i]]; + } + } + GET_NPOINTS(*c) = nReducedContacts; + } + + }// if (numContactsOut>0) + }// if (hasSeparatingAxis[i]) + }// if (i= 0) + { + collidableIndexA = gpuChildShapes[childShapeIndexA].m_shapeIndex; + float4 childPosA = gpuChildShapes[childShapeIndexA].m_childPosition; + float4 childOrnA = gpuChildShapes[childShapeIndexA].m_childOrientation; + float4 newPosA = qtRotate(ornA,childPosA)+posA; + float4 newOrnA = qtMul(ornA,childOrnA); + posA = newPosA; + ornA = newOrnA; + } else + { + collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx; + } + + if (childShapeIndexB>=0) + { + collidableIndexB = gpuChildShapes[childShapeIndexB].m_shapeIndex; + float4 childPosB = gpuChildShapes[childShapeIndexB].m_childPosition; + float4 childOrnB = gpuChildShapes[childShapeIndexB].m_childOrientation; + float4 newPosB = transform(&childPosB,&posB,&ornB); + float4 newOrnB = qtMul(ornB,childOrnB); + posB = newPosB; + ornB = newOrnB; + } else + { + collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx; + } + + int shapeIndexA = collidables[collidableIndexA].m_shapeIndex; + int shapeIndexB = collidables[collidableIndexB].m_shapeIndex; + + int numLocalContactsOut = clipHullAgainstHull(gpuCompoundSepNormalsOut[i], + &convexShapes[shapeIndexA], &convexShapes[shapeIndexB], + posA,ornA, + posB,ornB, + worldVertsB1,worldVertsB2,capacityWorldVerts, + minDist, maxDist, + vertices,faces,indices, + localContactsOut,localContactCapacity); + + if (numLocalContactsOut>0) + { + float4 normal = -gpuCompoundSepNormalsOut[i]; + int nPoints = numLocalContactsOut; + float4* pointsIn = localContactsOut; + int contactIdx[4];// = {-1,-1,-1,-1}; + + contactIdx[0] = -1; + contactIdx[1] = -1; + contactIdx[2] = -1; + contactIdx[3] = -1; + + int nReducedContacts = extractManifoldSequential(pointsIn, nPoints, normal, contactIdx); + + int dstIdx; + AppendInc( nGlobalContactsOut, dstIdx ); + if ((dstIdx+nReducedContacts) < maxContactCapacity) + { + __global struct b3Contact4Data* c = globalContactsOut+ dstIdx; + c->m_worldNormalOnB = -normal; + c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff); + c->m_batchIdx = pairIndex; + int bodyA = gpuCompoundPairs[pairIndex].x; + int bodyB = gpuCompoundPairs[pairIndex].y; + c->m_bodyAPtrAndSignBit = rigidBodies[bodyA].m_invMass==0?-bodyA:bodyA; + c->m_bodyBPtrAndSignBit = rigidBodies[bodyB].m_invMass==0?-bodyB:bodyB; + c->m_childIndexA = childShapeIndexA; + c->m_childIndexB = childShapeIndexB; + for (int i=0;im_worldPosB[i] = pointsIn[contactIdx[i]]; + } + GET_NPOINTS(*c) = nReducedContacts; + } + + }// if (numContactsOut>0) + }// if (gpuHasCompoundSepNormalsOut[i]) + }// if (i 0.00001) + { + normalOnSurfaceB = diff / len; + } + float4 contactPosB = posB + normalOnSurfaceB*radiusB; + contactPosB.w = dist; + + int dstIdx; + AppendInc( nGlobalContactsOut, dstIdx ); + if (dstIdx < contactCapacity) + { + __global struct b3Contact4Data* c = &globalContactsOut[dstIdx]; + c->m_worldNormalOnB = -normalOnSurfaceB; + c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff); + c->m_batchIdx = pairIndex; + int bodyA = pairs[pairIndex].x; + int bodyB = pairs[pairIndex].y; + c->m_bodyAPtrAndSignBit = rigidBodies[bodyA].m_invMass==0?-bodyA:bodyA; + c->m_bodyBPtrAndSignBit = rigidBodies[bodyB].m_invMass==0?-bodyB:bodyB; + c->m_worldPosB[0] = contactPosB; + c->m_childIndexA = -1; + c->m_childIndexB = -1; + + GET_NPOINTS(*c) = 1; + }//if (dstIdx < numPairs) + }//if ( len <= (radiusA+radiusB)) + }//SHAPE_SPHERE SHAPE_SPHERE + }//if (i0) + { + float4 normal = -separatingNormals[i]; + int nPoints = numLocalContactsOut; + float4* pointsIn = localContactsOut; + int contactIdx[4];// = {-1,-1,-1,-1}; + + contactIdx[0] = -1; + contactIdx[1] = -1; + contactIdx[2] = -1; + contactIdx[3] = -1; + + int nReducedContacts = extractManifoldSequential(pointsIn, nPoints, normal, contactIdx); + + int dstIdx; + AppendInc( nGlobalContactsOut, dstIdx ); + if (dstIdxm_worldNormalOnB = -normal; + c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff); + c->m_batchIdx = pairIndex; + int bodyA = concavePairsIn[pairIndex].x; + int bodyB = concavePairsIn[pairIndex].y; + c->m_bodyAPtrAndSignBit = rigidBodies[bodyA].m_invMass==0?-bodyA:bodyA; + c->m_bodyBPtrAndSignBit = rigidBodies[bodyB].m_invMass==0?-bodyB:bodyB; + c->m_childIndexA = childShapeIndexA; + c->m_childIndexB = childShapeIndexB; + for (int i=0;im_worldPosB[i] = pointsIn[contactIdx[i]]; + } + GET_NPOINTS(*c) = nReducedContacts; + } + + }// if (numContactsOut>0) + }// if (im_numFaces;face++) + { + const float4 Normal = make_float4(faces[hullB->m_faceOffset+face].m_plane.x, + faces[hullB->m_faceOffset+face].m_plane.y, faces[hullB->m_faceOffset+face].m_plane.z,0.f); + const float4 WorldNormal = qtRotate(ornB, Normal); + float d = dot3F4(WorldNormal,separatingNormal); + if (d > dmax) + { + dmax = d; + closestFaceB = face; + } + } + } + + { + const b3GpuFace_t polyB = faces[hullB->m_faceOffset+closestFaceB]; + const int numVertices = polyB.m_numIndices; + for(int e0=0;e0m_vertexOffset+indices[polyB.m_indexOffset+e0]]; + worldVertsB1[pairIndex*capacityWorldVerts+numWorldVertsB1++] = transform(&b,&posB,&ornB); + } + } + + int closestFaceA=-1; + { + float dmin = FLT_MAX; + for(int face=0;facem_numFaces;face++) + { + const float4 Normal = make_float4( + faces[hullA->m_faceOffset+face].m_plane.x, + faces[hullA->m_faceOffset+face].m_plane.y, + faces[hullA->m_faceOffset+face].m_plane.z, + 0.f); + const float4 faceANormalWS = qtRotate(ornA,Normal); + + float d = dot3F4(faceANormalWS,separatingNormal); + if (d < dmin) + { + dmin = d; + closestFaceA = face; + worldNormalsA1[pairIndex] = faceANormalWS; + } + } + } + + int numVerticesA = faces[hullA->m_faceOffset+closestFaceA].m_numIndices; + for(int e0=0;e0m_vertexOffset+indices[faces[hullA->m_faceOffset+closestFaceA].m_indexOffset+e0]]; + worldVertsA1[pairIndex*capacityWorldVerts+e0] = transform(&a, &posA,&ornA); + } + + clippingFaces[pairIndex].x = closestFaceA; + clippingFaces[pairIndex].y = closestFaceB; + clippingFaces[pairIndex].z = numVerticesA; + clippingFaces[pairIndex].w = numWorldVertsB1; + + + return numContactsOut; +} + + + +int clipFaces(__global float4* worldVertsA1, + __global float4* worldNormalsA1, + __global float4* worldVertsB1, + __global float4* worldVertsB2, + int capacityWorldVertsB2, + const float minDist, float maxDist, + __global int4* clippingFaces, + int pairIndex) +{ + int numContactsOut = 0; + + int closestFaceA = clippingFaces[pairIndex].x; + int closestFaceB = clippingFaces[pairIndex].y; + int numVertsInA = clippingFaces[pairIndex].z; + int numVertsInB = clippingFaces[pairIndex].w; + + int numVertsOut = 0; + + if (closestFaceA<0) + return numContactsOut; + + __global float4* pVtxIn = &worldVertsB1[pairIndex*capacityWorldVertsB2]; + __global float4* pVtxOut = &worldVertsB2[pairIndex*capacityWorldVertsB2]; + + + + // clip polygon to back of planes of all faces of hull A that are adjacent to witness face + + for(int e0=0;e0=0) + { + + + + // clip polygon to back of planes of all faces of hull A that are adjacent to witness face + + for(int e0=0;e00) + { + + __global float4* pointsIn = &worldVertsB2[pairIndex*vertexFaceCapacity]; + float4 normal = -separatingNormals[i]; + + int nReducedContacts = extractManifoldSequentialGlobal(pointsIn, nPoints, normal, &contactIdx); + + int mprContactIndex = pairs[pairIndex].z; + + int dstIdx = mprContactIndex; + + if (dstIdx<0) + { + AppendInc( nGlobalContactsOut, dstIdx ); + } +//#if 0 + + if (dstIdx < contactCapacity) + { + + __global struct b3Contact4Data* c = &globalContactsOut[dstIdx]; + c->m_worldNormalOnB = -normal; + c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff); + c->m_batchIdx = pairIndex; + int bodyA = pairs[pairIndex].x; + int bodyB = pairs[pairIndex].y; + + pairs[pairIndex].w = dstIdx; + + c->m_bodyAPtrAndSignBit = rigidBodies[bodyA].m_invMass==0?-bodyA:bodyA; + c->m_bodyBPtrAndSignBit = rigidBodies[bodyB].m_invMass==0?-bodyB:bodyB; + c->m_childIndexA =-1; + c->m_childIndexB =-1; + + switch (nReducedContacts) + { + case 4: + c->m_worldPosB[3] = pointsIn[contactIdx.w]; + case 3: + c->m_worldPosB[2] = pointsIn[contactIdx.z]; + case 2: + c->m_worldPosB[1] = pointsIn[contactIdx.y]; + case 1: + if (mprContactIndex<0)//test + c->m_worldPosB[0] = pointsIn[contactIdx.x]; + default: + { + } + }; + + GET_NPOINTS(*c) = nReducedContacts; + + } + + +//#endif + + }// if (numContactsOut>0) + }// if (hasSeparatingAxis[i]) + }// if (i1e-6 || b3Fabs(v.y)>1e-6 || b3Fabs(v.z)>1e-6) \n" +" return false;\n" +" return true;\n" +"}\n" +"inline int b3MaxDot( b3Float4ConstArg vec, __global const b3Float4* vecArray, int vecLen, float* dotOut )\n" +"{\n" +" float maxDot = -B3_INFINITY;\n" +" int i = 0;\n" +" int ptIndex = -1;\n" +" for( i = 0; i < vecLen; i++ )\n" +" {\n" +" float dot = b3Dot3F4(vecArray[i],vec);\n" +" \n" +" if( dot > maxDot )\n" +" {\n" +" maxDot = dot;\n" +" ptIndex = i;\n" +" }\n" +" }\n" +" b3Assert(ptIndex>=0);\n" +" if (ptIndex<0)\n" +" {\n" +" ptIndex = 0;\n" +" }\n" +" *dotOut = maxDot;\n" +" return ptIndex;\n" +"}\n" +"#endif //B3_FLOAT4_H\n" +"typedef struct b3Contact4Data b3Contact4Data_t;\n" +"struct b3Contact4Data\n" +"{\n" +" b3Float4 m_worldPosB[4];\n" +"// b3Float4 m_localPosA[4];\n" +"// b3Float4 m_localPosB[4];\n" +" b3Float4 m_worldNormalOnB; // w: m_nPoints\n" +" unsigned short m_restituitionCoeffCmp;\n" +" unsigned short m_frictionCoeffCmp;\n" +" int m_batchIdx;\n" +" int m_bodyAPtrAndSignBit;//x:m_bodyAPtr, y:m_bodyBPtr\n" +" int m_bodyBPtrAndSignBit;\n" +" int m_childIndexA;\n" +" int m_childIndexB;\n" +" int m_unused1;\n" +" int m_unused2;\n" +"};\n" +"inline int b3Contact4Data_getNumPoints(const struct b3Contact4Data* contact)\n" +"{\n" +" return (int)contact->m_worldNormalOnB.w;\n" +"};\n" +"inline void b3Contact4Data_setNumPoints(struct b3Contact4Data* contact, int numPoints)\n" +"{\n" +" contact->m_worldNormalOnB.w = (float)numPoints;\n" +"};\n" +"#endif //B3_CONTACT4DATA_H\n" +"#ifndef B3_CONVEX_POLYHEDRON_DATA_H\n" +"#define B3_CONVEX_POLYHEDRON_DATA_H\n" +"#ifndef B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_FLOAT4_H\n" +"#ifndef B3_QUAT_H\n" +"#define B3_QUAT_H\n" +"#ifndef B3_PLATFORM_DEFINITIONS_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif\n" +"#endif\n" +"#ifndef B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +" typedef float4 b3Quat;\n" +" #define b3QuatConstArg const b3Quat\n" +" \n" +" \n" +"inline float4 b3FastNormalize4(float4 v)\n" +"{\n" +" v = (float4)(v.xyz,0.f);\n" +" return fast_normalize(v);\n" +"}\n" +" \n" +"inline b3Quat b3QuatMul(b3Quat a, b3Quat b);\n" +"inline b3Quat b3QuatNormalized(b3QuatConstArg in);\n" +"inline b3Quat b3QuatRotate(b3QuatConstArg q, b3QuatConstArg vec);\n" +"inline b3Quat b3QuatInvert(b3QuatConstArg q);\n" +"inline b3Quat b3QuatInverse(b3QuatConstArg q);\n" +"inline b3Quat b3QuatMul(b3QuatConstArg a, b3QuatConstArg b)\n" +"{\n" +" b3Quat ans;\n" +" ans = b3Cross3( a, b );\n" +" ans += a.w*b+b.w*a;\n" +"// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z);\n" +" ans.w = a.w*b.w - b3Dot3F4(a, b);\n" +" return ans;\n" +"}\n" +"inline b3Quat b3QuatNormalized(b3QuatConstArg in)\n" +"{\n" +" b3Quat q;\n" +" q=in;\n" +" //return b3FastNormalize4(in);\n" +" float len = native_sqrt(dot(q, q));\n" +" if(len > 0.f)\n" +" {\n" +" q *= 1.f / len;\n" +" }\n" +" else\n" +" {\n" +" q.x = q.y = q.z = 0.f;\n" +" q.w = 1.f;\n" +" }\n" +" return q;\n" +"}\n" +"inline float4 b3QuatRotate(b3QuatConstArg q, b3QuatConstArg vec)\n" +"{\n" +" b3Quat qInv = b3QuatInvert( q );\n" +" float4 vcpy = vec;\n" +" vcpy.w = 0.f;\n" +" float4 out = b3QuatMul(b3QuatMul(q,vcpy),qInv);\n" +" return out;\n" +"}\n" +"inline b3Quat b3QuatInverse(b3QuatConstArg q)\n" +"{\n" +" return (b3Quat)(-q.xyz, q.w);\n" +"}\n" +"inline b3Quat b3QuatInvert(b3QuatConstArg q)\n" +"{\n" +" return (b3Quat)(-q.xyz, q.w);\n" +"}\n" +"inline float4 b3QuatInvRotate(b3QuatConstArg q, b3QuatConstArg vec)\n" +"{\n" +" return b3QuatRotate( b3QuatInvert( q ), vec );\n" +"}\n" +"inline b3Float4 b3TransformPoint(b3Float4ConstArg point, b3Float4ConstArg translation, b3QuatConstArg orientation)\n" +"{\n" +" return b3QuatRotate( orientation, point ) + (translation);\n" +"}\n" +" \n" +"#endif \n" +"#endif //B3_QUAT_H\n" +"typedef struct b3GpuFace b3GpuFace_t;\n" +"struct b3GpuFace\n" +"{\n" +" b3Float4 m_plane;\n" +" int m_indexOffset;\n" +" int m_numIndices;\n" +" int m_unusedPadding1;\n" +" int m_unusedPadding2;\n" +"};\n" +"typedef struct b3ConvexPolyhedronData b3ConvexPolyhedronData_t;\n" +"struct b3ConvexPolyhedronData\n" +"{\n" +" b3Float4 m_localCenter;\n" +" b3Float4 m_extents;\n" +" b3Float4 mC;\n" +" b3Float4 mE;\n" +" float m_radius;\n" +" int m_faceOffset;\n" +" int m_numFaces;\n" +" int m_numVertices;\n" +" int m_vertexOffset;\n" +" int m_uniqueEdgesOffset;\n" +" int m_numUniqueEdges;\n" +" int m_unused;\n" +"};\n" +"#endif //B3_CONVEX_POLYHEDRON_DATA_H\n" +"#ifndef B3_COLLIDABLE_H\n" +"#define B3_COLLIDABLE_H\n" +"#ifndef B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_FLOAT4_H\n" +"#ifndef B3_QUAT_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_QUAT_H\n" +"enum b3ShapeTypes\n" +"{\n" +" SHAPE_HEIGHT_FIELD=1,\n" +" SHAPE_CONVEX_HULL=3,\n" +" SHAPE_PLANE=4,\n" +" SHAPE_CONCAVE_TRIMESH=5,\n" +" SHAPE_COMPOUND_OF_CONVEX_HULLS=6,\n" +" SHAPE_SPHERE=7,\n" +" MAX_NUM_SHAPE_TYPES,\n" +"};\n" +"typedef struct b3Collidable b3Collidable_t;\n" +"struct b3Collidable\n" +"{\n" +" union {\n" +" int m_numChildShapes;\n" +" int m_bvhIndex;\n" +" };\n" +" union\n" +" {\n" +" float m_radius;\n" +" int m_compoundBvhIndex;\n" +" };\n" +" int m_shapeType;\n" +" int m_shapeIndex;\n" +"};\n" +"typedef struct b3GpuChildShape b3GpuChildShape_t;\n" +"struct b3GpuChildShape\n" +"{\n" +" b3Float4 m_childPosition;\n" +" b3Quat m_childOrientation;\n" +" int m_shapeIndex;\n" +" int m_unused0;\n" +" int m_unused1;\n" +" int m_unused2;\n" +"};\n" +"struct b3CompoundOverlappingPair\n" +"{\n" +" int m_bodyIndexA;\n" +" int m_bodyIndexB;\n" +"// int m_pairType;\n" +" int m_childShapeIndexA;\n" +" int m_childShapeIndexB;\n" +"};\n" +"#endif //B3_COLLIDABLE_H\n" +"#ifndef B3_RIGIDBODY_DATA_H\n" +"#define B3_RIGIDBODY_DATA_H\n" +"#ifndef B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_FLOAT4_H\n" +"#ifndef B3_QUAT_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_QUAT_H\n" +"#ifndef B3_MAT3x3_H\n" +"#define B3_MAT3x3_H\n" +"#ifndef B3_QUAT_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_QUAT_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"typedef struct\n" +"{\n" +" b3Float4 m_row[3];\n" +"}b3Mat3x3;\n" +"#define b3Mat3x3ConstArg const b3Mat3x3\n" +"#define b3GetRow(m,row) (m.m_row[row])\n" +"inline b3Mat3x3 b3QuatGetRotationMatrix(b3Quat quat)\n" +"{\n" +" b3Float4 quat2 = (b3Float4)(quat.x*quat.x, quat.y*quat.y, quat.z*quat.z, 0.f);\n" +" b3Mat3x3 out;\n" +" out.m_row[0].x=1-2*quat2.y-2*quat2.z;\n" +" out.m_row[0].y=2*quat.x*quat.y-2*quat.w*quat.z;\n" +" out.m_row[0].z=2*quat.x*quat.z+2*quat.w*quat.y;\n" +" out.m_row[0].w = 0.f;\n" +" out.m_row[1].x=2*quat.x*quat.y+2*quat.w*quat.z;\n" +" out.m_row[1].y=1-2*quat2.x-2*quat2.z;\n" +" out.m_row[1].z=2*quat.y*quat.z-2*quat.w*quat.x;\n" +" out.m_row[1].w = 0.f;\n" +" out.m_row[2].x=2*quat.x*quat.z-2*quat.w*quat.y;\n" +" out.m_row[2].y=2*quat.y*quat.z+2*quat.w*quat.x;\n" +" out.m_row[2].z=1-2*quat2.x-2*quat2.y;\n" +" out.m_row[2].w = 0.f;\n" +" return out;\n" +"}\n" +"inline b3Mat3x3 b3AbsoluteMat3x3(b3Mat3x3ConstArg matIn)\n" +"{\n" +" b3Mat3x3 out;\n" +" out.m_row[0] = fabs(matIn.m_row[0]);\n" +" out.m_row[1] = fabs(matIn.m_row[1]);\n" +" out.m_row[2] = fabs(matIn.m_row[2]);\n" +" return out;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtZero();\n" +"__inline\n" +"b3Mat3x3 mtIdentity();\n" +"__inline\n" +"b3Mat3x3 mtTranspose(b3Mat3x3 m);\n" +"__inline\n" +"b3Mat3x3 mtMul(b3Mat3x3 a, b3Mat3x3 b);\n" +"__inline\n" +"b3Float4 mtMul1(b3Mat3x3 a, b3Float4 b);\n" +"__inline\n" +"b3Float4 mtMul3(b3Float4 a, b3Mat3x3 b);\n" +"__inline\n" +"b3Mat3x3 mtZero()\n" +"{\n" +" b3Mat3x3 m;\n" +" m.m_row[0] = (b3Float4)(0.f);\n" +" m.m_row[1] = (b3Float4)(0.f);\n" +" m.m_row[2] = (b3Float4)(0.f);\n" +" return m;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtIdentity()\n" +"{\n" +" b3Mat3x3 m;\n" +" m.m_row[0] = (b3Float4)(1,0,0,0);\n" +" m.m_row[1] = (b3Float4)(0,1,0,0);\n" +" m.m_row[2] = (b3Float4)(0,0,1,0);\n" +" return m;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtTranspose(b3Mat3x3 m)\n" +"{\n" +" b3Mat3x3 out;\n" +" out.m_row[0] = (b3Float4)(m.m_row[0].x, m.m_row[1].x, m.m_row[2].x, 0.f);\n" +" out.m_row[1] = (b3Float4)(m.m_row[0].y, m.m_row[1].y, m.m_row[2].y, 0.f);\n" +" out.m_row[2] = (b3Float4)(m.m_row[0].z, m.m_row[1].z, m.m_row[2].z, 0.f);\n" +" return out;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtMul(b3Mat3x3 a, b3Mat3x3 b)\n" +"{\n" +" b3Mat3x3 transB;\n" +" transB = mtTranspose( b );\n" +" b3Mat3x3 ans;\n" +" // why this doesn't run when 0ing in the for{}\n" +" a.m_row[0].w = 0.f;\n" +" a.m_row[1].w = 0.f;\n" +" a.m_row[2].w = 0.f;\n" +" for(int i=0; i<3; i++)\n" +" {\n" +"// a.m_row[i].w = 0.f;\n" +" ans.m_row[i].x = b3Dot3F4(a.m_row[i],transB.m_row[0]);\n" +" ans.m_row[i].y = b3Dot3F4(a.m_row[i],transB.m_row[1]);\n" +" ans.m_row[i].z = b3Dot3F4(a.m_row[i],transB.m_row[2]);\n" +" ans.m_row[i].w = 0.f;\n" +" }\n" +" return ans;\n" +"}\n" +"__inline\n" +"b3Float4 mtMul1(b3Mat3x3 a, b3Float4 b)\n" +"{\n" +" b3Float4 ans;\n" +" ans.x = b3Dot3F4( a.m_row[0], b );\n" +" ans.y = b3Dot3F4( a.m_row[1], b );\n" +" ans.z = b3Dot3F4( a.m_row[2], b );\n" +" ans.w = 0.f;\n" +" return ans;\n" +"}\n" +"__inline\n" +"b3Float4 mtMul3(b3Float4 a, b3Mat3x3 b)\n" +"{\n" +" b3Float4 colx = b3MakeFloat4(b.m_row[0].x, b.m_row[1].x, b.m_row[2].x, 0);\n" +" b3Float4 coly = b3MakeFloat4(b.m_row[0].y, b.m_row[1].y, b.m_row[2].y, 0);\n" +" b3Float4 colz = b3MakeFloat4(b.m_row[0].z, b.m_row[1].z, b.m_row[2].z, 0);\n" +" b3Float4 ans;\n" +" ans.x = b3Dot3F4( a, colx );\n" +" ans.y = b3Dot3F4( a, coly );\n" +" ans.z = b3Dot3F4( a, colz );\n" +" return ans;\n" +"}\n" +"#endif\n" +"#endif //B3_MAT3x3_H\n" +"typedef struct b3RigidBodyData b3RigidBodyData_t;\n" +"struct b3RigidBodyData\n" +"{\n" +" b3Float4 m_pos;\n" +" b3Quat m_quat;\n" +" b3Float4 m_linVel;\n" +" b3Float4 m_angVel;\n" +" int m_collidableIdx;\n" +" float m_invMass;\n" +" float m_restituitionCoeff;\n" +" float m_frictionCoeff;\n" +"};\n" +"typedef struct b3InertiaData b3InertiaData_t;\n" +"struct b3InertiaData\n" +"{\n" +" b3Mat3x3 m_invInertiaWorld;\n" +" b3Mat3x3 m_initInvInertia;\n" +"};\n" +"#endif //B3_RIGIDBODY_DATA_H\n" +" \n" +"#define GET_NPOINTS(x) (x).m_worldNormalOnB.w\n" +"#define SELECT_UINT4( b, a, condition ) select( b,a,condition )\n" +"#define make_float4 (float4)\n" +"#define make_float2 (float2)\n" +"#define make_uint4 (uint4)\n" +"#define make_int4 (int4)\n" +"#define make_uint2 (uint2)\n" +"#define make_int2 (int2)\n" +"__inline\n" +"float fastDiv(float numerator, float denominator)\n" +"{\n" +" return native_divide(numerator, denominator); \n" +"// return numerator/denominator; \n" +"}\n" +"__inline\n" +"float4 fastDiv4(float4 numerator, float4 denominator)\n" +"{\n" +" return native_divide(numerator, denominator); \n" +"}\n" +"__inline\n" +"float4 cross3(float4 a, float4 b)\n" +"{\n" +" return cross(a,b);\n" +"}\n" +"//#define dot3F4 dot\n" +"__inline\n" +"float dot3F4(float4 a, float4 b)\n" +"{\n" +" float4 a1 = make_float4(a.xyz,0.f);\n" +" float4 b1 = make_float4(b.xyz,0.f);\n" +" return dot(a1, b1);\n" +"}\n" +"__inline\n" +"float4 fastNormalize4(float4 v)\n" +"{\n" +" return fast_normalize(v);\n" +"}\n" +"///////////////////////////////////////\n" +"// Quaternion\n" +"///////////////////////////////////////\n" +"typedef float4 Quaternion;\n" +"__inline\n" +"Quaternion qtMul(Quaternion a, Quaternion b);\n" +"__inline\n" +"Quaternion qtNormalize(Quaternion in);\n" +"__inline\n" +"float4 qtRotate(Quaternion q, float4 vec);\n" +"__inline\n" +"Quaternion qtInvert(Quaternion q);\n" +"__inline\n" +"Quaternion qtMul(Quaternion a, Quaternion b)\n" +"{\n" +" Quaternion ans;\n" +" ans = cross3( a, b );\n" +" ans += a.w*b+b.w*a;\n" +"// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z);\n" +" ans.w = a.w*b.w - dot3F4(a, b);\n" +" return ans;\n" +"}\n" +"__inline\n" +"Quaternion qtNormalize(Quaternion in)\n" +"{\n" +" return fastNormalize4(in);\n" +"// in /= length( in );\n" +"// return in;\n" +"}\n" +"__inline\n" +"float4 qtRotate(Quaternion q, float4 vec)\n" +"{\n" +" Quaternion qInv = qtInvert( q );\n" +" float4 vcpy = vec;\n" +" vcpy.w = 0.f;\n" +" float4 out = qtMul(qtMul(q,vcpy),qInv);\n" +" return out;\n" +"}\n" +"__inline\n" +"Quaternion qtInvert(Quaternion q)\n" +"{\n" +" return (Quaternion)(-q.xyz, q.w);\n" +"}\n" +"__inline\n" +"float4 qtInvRotate(const Quaternion q, float4 vec)\n" +"{\n" +" return qtRotate( qtInvert( q ), vec );\n" +"}\n" +"__inline\n" +"float4 transform(const float4* p, const float4* translation, const Quaternion* orientation)\n" +"{\n" +" return qtRotate( *orientation, *p ) + (*translation);\n" +"}\n" +"__inline\n" +"float4 normalize3(const float4 a)\n" +"{\n" +" float4 n = make_float4(a.x, a.y, a.z, 0.f);\n" +" return fastNormalize4( n );\n" +"}\n" +"__inline float4 lerp3(const float4 a,const float4 b, float t)\n" +"{\n" +" return make_float4( a.x + (b.x - a.x) * t,\n" +" a.y + (b.y - a.y) * t,\n" +" a.z + (b.z - a.z) * t,\n" +" 0.f);\n" +"}\n" +"// Clips a face to the back of a plane, return the number of vertices out, stored in ppVtxOut\n" +"int clipFaceGlobal(__global const float4* pVtxIn, int numVertsIn, float4 planeNormalWS,float planeEqWS, __global float4* ppVtxOut)\n" +"{\n" +" \n" +" int ve;\n" +" float ds, de;\n" +" int numVertsOut = 0;\n" +" //double-check next test\n" +" if (numVertsIn < 2)\n" +" return 0;\n" +" \n" +" float4 firstVertex=pVtxIn[numVertsIn-1];\n" +" float4 endVertex = pVtxIn[0];\n" +" \n" +" ds = dot3F4(planeNormalWS,firstVertex)+planeEqWS;\n" +" \n" +" for (ve = 0; ve < numVertsIn; ve++)\n" +" {\n" +" endVertex=pVtxIn[ve];\n" +" de = dot3F4(planeNormalWS,endVertex)+planeEqWS;\n" +" if (ds<0)\n" +" {\n" +" if (de<0)\n" +" {\n" +" // Start < 0, end < 0, so output endVertex\n" +" ppVtxOut[numVertsOut++] = endVertex;\n" +" }\n" +" else\n" +" {\n" +" // Start < 0, end >= 0, so output intersection\n" +" ppVtxOut[numVertsOut++] = lerp3(firstVertex, endVertex,(ds * 1.f/(ds - de)) );\n" +" }\n" +" }\n" +" else\n" +" {\n" +" if (de<0)\n" +" {\n" +" // Start >= 0, end < 0 so output intersection and end\n" +" ppVtxOut[numVertsOut++] = lerp3(firstVertex, endVertex,(ds * 1.f/(ds - de)) );\n" +" ppVtxOut[numVertsOut++] = endVertex;\n" +" }\n" +" }\n" +" firstVertex = endVertex;\n" +" ds = de;\n" +" }\n" +" return numVertsOut;\n" +"}\n" +"// Clips a face to the back of a plane, return the number of vertices out, stored in ppVtxOut\n" +"int clipFace(const float4* pVtxIn, int numVertsIn, float4 planeNormalWS,float planeEqWS, float4* ppVtxOut)\n" +"{\n" +" \n" +" int ve;\n" +" float ds, de;\n" +" int numVertsOut = 0;\n" +"//double-check next test\n" +" if (numVertsIn < 2)\n" +" return 0;\n" +" float4 firstVertex=pVtxIn[numVertsIn-1];\n" +" float4 endVertex = pVtxIn[0];\n" +" \n" +" ds = dot3F4(planeNormalWS,firstVertex)+planeEqWS;\n" +" for (ve = 0; ve < numVertsIn; ve++)\n" +" {\n" +" endVertex=pVtxIn[ve];\n" +" de = dot3F4(planeNormalWS,endVertex)+planeEqWS;\n" +" if (ds<0)\n" +" {\n" +" if (de<0)\n" +" {\n" +" // Start < 0, end < 0, so output endVertex\n" +" ppVtxOut[numVertsOut++] = endVertex;\n" +" }\n" +" else\n" +" {\n" +" // Start < 0, end >= 0, so output intersection\n" +" ppVtxOut[numVertsOut++] = lerp3(firstVertex, endVertex,(ds * 1.f/(ds - de)) );\n" +" }\n" +" }\n" +" else\n" +" {\n" +" if (de<0)\n" +" {\n" +" // Start >= 0, end < 0 so output intersection and end\n" +" ppVtxOut[numVertsOut++] = lerp3(firstVertex, endVertex,(ds * 1.f/(ds - de)) );\n" +" ppVtxOut[numVertsOut++] = endVertex;\n" +" }\n" +" }\n" +" firstVertex = endVertex;\n" +" ds = de;\n" +" }\n" +" return numVertsOut;\n" +"}\n" +"int clipFaceAgainstHull(const float4 separatingNormal, __global const b3ConvexPolyhedronData_t* hullA, \n" +" const float4 posA, const Quaternion ornA, float4* worldVertsB1, int numWorldVertsB1,\n" +" float4* worldVertsB2, int capacityWorldVertsB2,\n" +" const float minDist, float maxDist,\n" +" __global const float4* vertices,\n" +" __global const b3GpuFace_t* faces,\n" +" __global const int* indices,\n" +" float4* contactsOut,\n" +" int contactCapacity)\n" +"{\n" +" int numContactsOut = 0;\n" +" float4* pVtxIn = worldVertsB1;\n" +" float4* pVtxOut = worldVertsB2;\n" +" \n" +" int numVertsIn = numWorldVertsB1;\n" +" int numVertsOut = 0;\n" +" int closestFaceA=-1;\n" +" {\n" +" float dmin = FLT_MAX;\n" +" for(int face=0;facem_numFaces;face++)\n" +" {\n" +" const float4 Normal = make_float4(\n" +" faces[hullA->m_faceOffset+face].m_plane.x, \n" +" faces[hullA->m_faceOffset+face].m_plane.y, \n" +" faces[hullA->m_faceOffset+face].m_plane.z,0.f);\n" +" const float4 faceANormalWS = qtRotate(ornA,Normal);\n" +" \n" +" float d = dot3F4(faceANormalWS,separatingNormal);\n" +" if (d < dmin)\n" +" {\n" +" dmin = d;\n" +" closestFaceA = face;\n" +" }\n" +" }\n" +" }\n" +" if (closestFaceA<0)\n" +" return numContactsOut;\n" +" b3GpuFace_t polyA = faces[hullA->m_faceOffset+closestFaceA];\n" +" // clip polygon to back of planes of all faces of hull A that are adjacent to witness face\n" +" int numVerticesA = polyA.m_numIndices;\n" +" for(int e0=0;e0m_vertexOffset+indices[polyA.m_indexOffset+e0]];\n" +" const float4 b = vertices[hullA->m_vertexOffset+indices[polyA.m_indexOffset+((e0+1)%numVerticesA)]];\n" +" const float4 edge0 = a - b;\n" +" const float4 WorldEdge0 = qtRotate(ornA,edge0);\n" +" float4 planeNormalA = make_float4(polyA.m_plane.x,polyA.m_plane.y,polyA.m_plane.z,0.f);\n" +" float4 worldPlaneAnormal1 = qtRotate(ornA,planeNormalA);\n" +" float4 planeNormalWS1 = -cross3(WorldEdge0,worldPlaneAnormal1);\n" +" float4 worldA1 = transform(&a,&posA,&ornA);\n" +" float planeEqWS1 = -dot3F4(worldA1,planeNormalWS1);\n" +" \n" +" float4 planeNormalWS = planeNormalWS1;\n" +" float planeEqWS=planeEqWS1;\n" +" \n" +" //clip face\n" +" //clipFace(*pVtxIn, *pVtxOut,planeNormalWS,planeEqWS);\n" +" numVertsOut = clipFace(pVtxIn, numVertsIn, planeNormalWS,planeEqWS, pVtxOut);\n" +" //btSwap(pVtxIn,pVtxOut);\n" +" float4* tmp = pVtxOut;\n" +" pVtxOut = pVtxIn;\n" +" pVtxIn = tmp;\n" +" numVertsIn = numVertsOut;\n" +" numVertsOut = 0;\n" +" }\n" +" \n" +" // only keep points that are behind the witness face\n" +" {\n" +" float4 localPlaneNormal = make_float4(polyA.m_plane.x,polyA.m_plane.y,polyA.m_plane.z,0.f);\n" +" float localPlaneEq = polyA.m_plane.w;\n" +" float4 planeNormalWS = qtRotate(ornA,localPlaneNormal);\n" +" float planeEqWS=localPlaneEq-dot3F4(planeNormalWS,posA);\n" +" for (int i=0;im_numFaces;face++)\n" +" {\n" +" const float4 Normal = make_float4(\n" +" facesA[hullA->m_faceOffset+face].m_plane.x, \n" +" facesA[hullA->m_faceOffset+face].m_plane.y, \n" +" facesA[hullA->m_faceOffset+face].m_plane.z,0.f);\n" +" const float4 faceANormalWS = qtRotate(ornA,Normal);\n" +" \n" +" float d = dot3F4(faceANormalWS,separatingNormal);\n" +" if (d < dmin)\n" +" {\n" +" dmin = d;\n" +" closestFaceA = face;\n" +" }\n" +" }\n" +" }\n" +" if (closestFaceA<0)\n" +" return numContactsOut;\n" +" b3GpuFace_t polyA = facesA[hullA->m_faceOffset+closestFaceA];\n" +" // clip polygon to back of planes of all faces of hull A that are adjacent to witness face\n" +" int numVerticesA = polyA.m_numIndices;\n" +" for(int e0=0;e0m_vertexOffset+indicesA[polyA.m_indexOffset+e0]];\n" +" const float4 b = verticesA[hullA->m_vertexOffset+indicesA[polyA.m_indexOffset+((e0+1)%numVerticesA)]];\n" +" const float4 edge0 = a - b;\n" +" const float4 WorldEdge0 = qtRotate(ornA,edge0);\n" +" float4 planeNormalA = make_float4(polyA.m_plane.x,polyA.m_plane.y,polyA.m_plane.z,0.f);\n" +" float4 worldPlaneAnormal1 = qtRotate(ornA,planeNormalA);\n" +" float4 planeNormalWS1 = -cross3(WorldEdge0,worldPlaneAnormal1);\n" +" float4 worldA1 = transform(&a,&posA,&ornA);\n" +" float planeEqWS1 = -dot3F4(worldA1,planeNormalWS1);\n" +" \n" +" float4 planeNormalWS = planeNormalWS1;\n" +" float planeEqWS=planeEqWS1;\n" +" \n" +" //clip face\n" +" //clipFace(*pVtxIn, *pVtxOut,planeNormalWS,planeEqWS);\n" +" numVertsOut = clipFace(pVtxIn, numVertsIn, planeNormalWS,planeEqWS, pVtxOut);\n" +" //btSwap(pVtxIn,pVtxOut);\n" +" float4* tmp = pVtxOut;\n" +" pVtxOut = pVtxIn;\n" +" pVtxIn = tmp;\n" +" numVertsIn = numVertsOut;\n" +" numVertsOut = 0;\n" +" }\n" +" \n" +" // only keep points that are behind the witness face\n" +" {\n" +" float4 localPlaneNormal = make_float4(polyA.m_plane.x,polyA.m_plane.y,polyA.m_plane.z,0.f);\n" +" float localPlaneEq = polyA.m_plane.w;\n" +" float4 planeNormalWS = qtRotate(ornA,localPlaneNormal);\n" +" float planeEqWS=localPlaneEq-dot3F4(planeNormalWS,posA);\n" +" for (int i=0;im_numFaces;face++)\n" +" {\n" +" const float4 Normal = make_float4(faces[hullB->m_faceOffset+face].m_plane.x, \n" +" faces[hullB->m_faceOffset+face].m_plane.y, faces[hullB->m_faceOffset+face].m_plane.z,0.f);\n" +" const float4 WorldNormal = qtRotate(ornB, Normal);\n" +" float d = dot3F4(WorldNormal,separatingNormal);\n" +" if (d > dmax)\n" +" {\n" +" dmax = d;\n" +" closestFaceB = face;\n" +" }\n" +" }\n" +" }\n" +" {\n" +" const b3GpuFace_t polyB = faces[hullB->m_faceOffset+closestFaceB];\n" +" const int numVertices = polyB.m_numIndices;\n" +" for(int e0=0;e0m_vertexOffset+indices[polyB.m_indexOffset+e0]];\n" +" worldVertsB1[numWorldVertsB1++] = transform(&b,&posB,&ornB);\n" +" }\n" +" }\n" +" if (closestFaceB>=0)\n" +" {\n" +" numContactsOut = clipFaceAgainstHull(separatingNormal, hullA, \n" +" posA,ornA,\n" +" worldVertsB1,numWorldVertsB1,worldVertsB2,capacityWorldVerts, minDist, maxDist,vertices,\n" +" faces,\n" +" indices,localContactsOut,localContactCapacity);\n" +" }\n" +" return numContactsOut;\n" +"}\n" +"int clipHullAgainstHullLocalA(const float4 separatingNormal,\n" +" const b3ConvexPolyhedronData_t* hullA, __global const b3ConvexPolyhedronData_t* hullB, \n" +" const float4 posA, const Quaternion ornA,const float4 posB, const Quaternion ornB, \n" +" float4* worldVertsB1, float4* worldVertsB2, int capacityWorldVerts,\n" +" const float minDist, float maxDist,\n" +" const float4* verticesA,\n" +" const b3GpuFace_t* facesA,\n" +" const int* indicesA,\n" +" __global const float4* verticesB,\n" +" __global const b3GpuFace_t* facesB,\n" +" __global const int* indicesB,\n" +" float4* localContactsOut,\n" +" int localContactCapacity)\n" +"{\n" +" int numContactsOut = 0;\n" +" int numWorldVertsB1= 0;\n" +" int closestFaceB=-1;\n" +" float dmax = -FLT_MAX;\n" +" {\n" +" for(int face=0;facem_numFaces;face++)\n" +" {\n" +" const float4 Normal = make_float4(facesB[hullB->m_faceOffset+face].m_plane.x, \n" +" facesB[hullB->m_faceOffset+face].m_plane.y, facesB[hullB->m_faceOffset+face].m_plane.z,0.f);\n" +" const float4 WorldNormal = qtRotate(ornB, Normal);\n" +" float d = dot3F4(WorldNormal,separatingNormal);\n" +" if (d > dmax)\n" +" {\n" +" dmax = d;\n" +" closestFaceB = face;\n" +" }\n" +" }\n" +" }\n" +" {\n" +" const b3GpuFace_t polyB = facesB[hullB->m_faceOffset+closestFaceB];\n" +" const int numVertices = polyB.m_numIndices;\n" +" for(int e0=0;e0m_vertexOffset+indicesB[polyB.m_indexOffset+e0]];\n" +" worldVertsB1[numWorldVertsB1++] = transform(&b,&posB,&ornB);\n" +" }\n" +" }\n" +" if (closestFaceB>=0)\n" +" {\n" +" numContactsOut = clipFaceAgainstHullLocalA(separatingNormal, hullA, \n" +" posA,ornA,\n" +" worldVertsB1,numWorldVertsB1,worldVertsB2,capacityWorldVerts, minDist, maxDist,\n" +" verticesA,facesA,indicesA,\n" +" verticesB,facesB,indicesB,\n" +" localContactsOut,localContactCapacity);\n" +" }\n" +" return numContactsOut;\n" +"}\n" +"#define PARALLEL_SUM(v, n) for(int j=1; j v[i+offset].y)? v[i]: v[i+offset]; }\n" +"#define REDUCE_MIN(v, n) {int i=0; for(int offset=0; offset64)\n" +" nPoints = 64;\n" +" \n" +" float4 center = make_float4(0.f);\n" +" {\n" +" \n" +" for (int i=0;i a[ie].x )? a[0].x: a[ie].x;\n" +" a[0].y = (a[0].y > a[ie].y )? a[0].y: a[ie].y;\n" +" a[0].z = (a[0].z > a[ie].z )? a[0].z: a[ie].z;\n" +" a[0].w = (a[0].w > a[ie].w )? a[0].w: a[ie].w;\n" +" }\n" +" idx[0] = (int)a[0].x & 0xff;\n" +" idx[1] = (int)a[0].y & 0xff;\n" +" idx[2] = (int)a[0].z & 0xff;\n" +" idx[3] = (int)a[0].w & 0xff;\n" +" }\n" +" }\n" +" {\n" +" float2 h[64];\n" +" PARALLEL_DO( h[ie] = make_float2((float)ie, p[ie].w), nPoints );\n" +" REDUCE_MIN( h, nPoints );\n" +" max00 = h[0];\n" +" }\n" +" }\n" +" contactIdx[0] = idx[0];\n" +" contactIdx[1] = idx[1];\n" +" contactIdx[2] = idx[2];\n" +" contactIdx[3] = idx[3];\n" +" return 4;\n" +" }\n" +"}\n" +"__kernel void extractManifoldAndAddContactKernel(__global const int4* pairs, \n" +" __global const b3RigidBodyData_t* rigidBodies, \n" +" __global const float4* closestPointsWorld,\n" +" __global const float4* separatingNormalsWorld,\n" +" __global const int* contactCounts,\n" +" __global const int* contactOffsets,\n" +" __global struct b3Contact4Data* restrict contactsOut,\n" +" counter32_t nContactsOut,\n" +" int contactCapacity,\n" +" int numPairs,\n" +" int pairIndex\n" +" )\n" +"{\n" +" int idx = get_global_id(0);\n" +" \n" +" if (idxm_worldNormalOnB = -normal;\n" +" c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff);\n" +" c->m_batchIdx = idx;\n" +" int bodyA = pairs[pairIndex].x;\n" +" int bodyB = pairs[pairIndex].y;\n" +" c->m_bodyAPtrAndSignBit = rigidBodies[bodyA].m_invMass==0 ? -bodyA:bodyA;\n" +" c->m_bodyBPtrAndSignBit = rigidBodies[bodyB].m_invMass==0 ? -bodyB:bodyB;\n" +" c->m_childIndexA = -1;\n" +" c->m_childIndexB = -1;\n" +" for (int i=0;im_worldPosB[i] = localPoints[contactIdx[i]];\n" +" }\n" +" GET_NPOINTS(*c) = nContacts;\n" +" }\n" +" }\n" +"}\n" +"void trInverse(float4 translationIn, Quaternion orientationIn,\n" +" float4* translationOut, Quaternion* orientationOut)\n" +"{\n" +" *orientationOut = qtInvert(orientationIn);\n" +" *translationOut = qtRotate(*orientationOut, -translationIn);\n" +"}\n" +"void trMul(float4 translationA, Quaternion orientationA,\n" +" float4 translationB, Quaternion orientationB,\n" +" float4* translationOut, Quaternion* orientationOut)\n" +"{\n" +" *orientationOut = qtMul(orientationA,orientationB);\n" +" *translationOut = transform(&translationB,&translationA,&orientationA);\n" +"}\n" +"__kernel void clipHullHullKernel( __global int4* pairs, \n" +" __global const b3RigidBodyData_t* rigidBodies, \n" +" __global const b3Collidable_t* collidables,\n" +" __global const b3ConvexPolyhedronData_t* convexShapes, \n" +" __global const float4* vertices,\n" +" __global const float4* uniqueEdges,\n" +" __global const b3GpuFace_t* faces,\n" +" __global const int* indices,\n" +" __global const float4* separatingNormals,\n" +" __global const int* hasSeparatingAxis,\n" +" __global struct b3Contact4Data* restrict globalContactsOut,\n" +" counter32_t nGlobalContactsOut,\n" +" int numPairs,\n" +" int contactCapacity)\n" +"{\n" +" int i = get_global_id(0);\n" +" int pairIndex = i;\n" +" \n" +" float4 worldVertsB1[64];\n" +" float4 worldVertsB2[64];\n" +" int capacityWorldVerts = 64; \n" +" float4 localContactsOut[64];\n" +" int localContactCapacity=64;\n" +" \n" +" float minDist = -1e30f;\n" +" float maxDist = 0.02f;\n" +" if (i0)\n" +" {\n" +" float4 normal = -separatingNormals[i];\n" +" int nPoints = numLocalContactsOut;\n" +" float4* pointsIn = localContactsOut;\n" +" int contactIdx[4];// = {-1,-1,-1,-1};\n" +" contactIdx[0] = -1;\n" +" contactIdx[1] = -1;\n" +" contactIdx[2] = -1;\n" +" contactIdx[3] = -1;\n" +" \n" +" int nReducedContacts = extractManifoldSequential(pointsIn, nPoints, normal, contactIdx);\n" +" \n" +" \n" +" int mprContactIndex = pairs[pairIndex].z;\n" +" int dstIdx = mprContactIndex;\n" +" if (dstIdx<0)\n" +" {\n" +" AppendInc( nGlobalContactsOut, dstIdx );\n" +" }\n" +" if (dstIdxm_worldNormalOnB = -normal;\n" +" c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff);\n" +" c->m_batchIdx = pairIndex;\n" +" int bodyA = pairs[pairIndex].x;\n" +" int bodyB = pairs[pairIndex].y;\n" +" c->m_bodyAPtrAndSignBit = rigidBodies[bodyA].m_invMass==0?-bodyA:bodyA;\n" +" c->m_bodyBPtrAndSignBit = rigidBodies[bodyB].m_invMass==0?-bodyB:bodyB;\n" +" c->m_childIndexA = -1;\n" +" c->m_childIndexB = -1;\n" +" for (int i=0;i0||(mprContactIndex<0))\n" +" {\n" +" c->m_worldPosB[i] = pointsIn[contactIdx[i]];\n" +" }\n" +" }\n" +" GET_NPOINTS(*c) = nReducedContacts;\n" +" }\n" +" \n" +" }// if (numContactsOut>0)\n" +" }// if (hasSeparatingAxis[i])\n" +" }// if (i= 0)\n" +" {\n" +" collidableIndexA = gpuChildShapes[childShapeIndexA].m_shapeIndex;\n" +" float4 childPosA = gpuChildShapes[childShapeIndexA].m_childPosition;\n" +" float4 childOrnA = gpuChildShapes[childShapeIndexA].m_childOrientation;\n" +" float4 newPosA = qtRotate(ornA,childPosA)+posA;\n" +" float4 newOrnA = qtMul(ornA,childOrnA);\n" +" posA = newPosA;\n" +" ornA = newOrnA;\n" +" } else\n" +" {\n" +" collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx;\n" +" }\n" +" \n" +" if (childShapeIndexB>=0)\n" +" {\n" +" collidableIndexB = gpuChildShapes[childShapeIndexB].m_shapeIndex;\n" +" float4 childPosB = gpuChildShapes[childShapeIndexB].m_childPosition;\n" +" float4 childOrnB = gpuChildShapes[childShapeIndexB].m_childOrientation;\n" +" float4 newPosB = transform(&childPosB,&posB,&ornB);\n" +" float4 newOrnB = qtMul(ornB,childOrnB);\n" +" posB = newPosB;\n" +" ornB = newOrnB;\n" +" } else\n" +" {\n" +" collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx; \n" +" }\n" +" \n" +" int shapeIndexA = collidables[collidableIndexA].m_shapeIndex;\n" +" int shapeIndexB = collidables[collidableIndexB].m_shapeIndex;\n" +" \n" +" int numLocalContactsOut = clipHullAgainstHull(gpuCompoundSepNormalsOut[i],\n" +" &convexShapes[shapeIndexA], &convexShapes[shapeIndexB],\n" +" posA,ornA,\n" +" posB,ornB,\n" +" worldVertsB1,worldVertsB2,capacityWorldVerts,\n" +" minDist, maxDist,\n" +" vertices,faces,indices,\n" +" localContactsOut,localContactCapacity);\n" +" \n" +" if (numLocalContactsOut>0)\n" +" {\n" +" float4 normal = -gpuCompoundSepNormalsOut[i];\n" +" int nPoints = numLocalContactsOut;\n" +" float4* pointsIn = localContactsOut;\n" +" int contactIdx[4];// = {-1,-1,-1,-1};\n" +" contactIdx[0] = -1;\n" +" contactIdx[1] = -1;\n" +" contactIdx[2] = -1;\n" +" contactIdx[3] = -1;\n" +" \n" +" int nReducedContacts = extractManifoldSequential(pointsIn, nPoints, normal, contactIdx);\n" +" \n" +" int dstIdx;\n" +" AppendInc( nGlobalContactsOut, dstIdx );\n" +" if ((dstIdx+nReducedContacts) < maxContactCapacity)\n" +" {\n" +" __global struct b3Contact4Data* c = globalContactsOut+ dstIdx;\n" +" c->m_worldNormalOnB = -normal;\n" +" c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff);\n" +" c->m_batchIdx = pairIndex;\n" +" int bodyA = gpuCompoundPairs[pairIndex].x;\n" +" int bodyB = gpuCompoundPairs[pairIndex].y;\n" +" c->m_bodyAPtrAndSignBit = rigidBodies[bodyA].m_invMass==0?-bodyA:bodyA;\n" +" c->m_bodyBPtrAndSignBit = rigidBodies[bodyB].m_invMass==0?-bodyB:bodyB;\n" +" c->m_childIndexA = childShapeIndexA;\n" +" c->m_childIndexB = childShapeIndexB;\n" +" for (int i=0;im_worldPosB[i] = pointsIn[contactIdx[i]];\n" +" }\n" +" GET_NPOINTS(*c) = nReducedContacts;\n" +" }\n" +" \n" +" }// if (numContactsOut>0)\n" +" }// if (gpuHasCompoundSepNormalsOut[i])\n" +" }// if (i 0.00001)\n" +" {\n" +" normalOnSurfaceB = diff / len;\n" +" }\n" +" float4 contactPosB = posB + normalOnSurfaceB*radiusB;\n" +" contactPosB.w = dist;\n" +" \n" +" int dstIdx;\n" +" AppendInc( nGlobalContactsOut, dstIdx );\n" +" if (dstIdx < contactCapacity)\n" +" {\n" +" __global struct b3Contact4Data* c = &globalContactsOut[dstIdx];\n" +" c->m_worldNormalOnB = -normalOnSurfaceB;\n" +" c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff);\n" +" c->m_batchIdx = pairIndex;\n" +" int bodyA = pairs[pairIndex].x;\n" +" int bodyB = pairs[pairIndex].y;\n" +" c->m_bodyAPtrAndSignBit = rigidBodies[bodyA].m_invMass==0?-bodyA:bodyA;\n" +" c->m_bodyBPtrAndSignBit = rigidBodies[bodyB].m_invMass==0?-bodyB:bodyB;\n" +" c->m_worldPosB[0] = contactPosB;\n" +" c->m_childIndexA = -1;\n" +" c->m_childIndexB = -1;\n" +" GET_NPOINTS(*c) = 1;\n" +" }//if (dstIdx < numPairs)\n" +" }//if ( len <= (radiusA+radiusB))\n" +" }//SHAPE_SPHERE SHAPE_SPHERE\n" +" }//if (i0)\n" +" {\n" +" float4 normal = -separatingNormals[i];\n" +" int nPoints = numLocalContactsOut;\n" +" float4* pointsIn = localContactsOut;\n" +" int contactIdx[4];// = {-1,-1,-1,-1};\n" +" contactIdx[0] = -1;\n" +" contactIdx[1] = -1;\n" +" contactIdx[2] = -1;\n" +" contactIdx[3] = -1;\n" +" \n" +" int nReducedContacts = extractManifoldSequential(pointsIn, nPoints, normal, contactIdx);\n" +" \n" +" int dstIdx;\n" +" AppendInc( nGlobalContactsOut, dstIdx );\n" +" if (dstIdxm_worldNormalOnB = -normal;\n" +" c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff);\n" +" c->m_batchIdx = pairIndex;\n" +" int bodyA = concavePairsIn[pairIndex].x;\n" +" int bodyB = concavePairsIn[pairIndex].y;\n" +" c->m_bodyAPtrAndSignBit = rigidBodies[bodyA].m_invMass==0?-bodyA:bodyA;\n" +" c->m_bodyBPtrAndSignBit = rigidBodies[bodyB].m_invMass==0?-bodyB:bodyB;\n" +" c->m_childIndexA = childShapeIndexA;\n" +" c->m_childIndexB = childShapeIndexB;\n" +" for (int i=0;im_worldPosB[i] = pointsIn[contactIdx[i]];\n" +" }\n" +" GET_NPOINTS(*c) = nReducedContacts;\n" +" }\n" +" \n" +" }// if (numContactsOut>0)\n" +" }// if (im_numFaces;face++)\n" +" {\n" +" const float4 Normal = make_float4(faces[hullB->m_faceOffset+face].m_plane.x,\n" +" faces[hullB->m_faceOffset+face].m_plane.y, faces[hullB->m_faceOffset+face].m_plane.z,0.f);\n" +" const float4 WorldNormal = qtRotate(ornB, Normal);\n" +" float d = dot3F4(WorldNormal,separatingNormal);\n" +" if (d > dmax)\n" +" {\n" +" dmax = d;\n" +" closestFaceB = face;\n" +" }\n" +" }\n" +" }\n" +" \n" +" {\n" +" const b3GpuFace_t polyB = faces[hullB->m_faceOffset+closestFaceB];\n" +" const int numVertices = polyB.m_numIndices;\n" +" for(int e0=0;e0m_vertexOffset+indices[polyB.m_indexOffset+e0]];\n" +" worldVertsB1[pairIndex*capacityWorldVerts+numWorldVertsB1++] = transform(&b,&posB,&ornB);\n" +" }\n" +" }\n" +" \n" +" int closestFaceA=-1;\n" +" {\n" +" float dmin = FLT_MAX;\n" +" for(int face=0;facem_numFaces;face++)\n" +" {\n" +" const float4 Normal = make_float4(\n" +" faces[hullA->m_faceOffset+face].m_plane.x,\n" +" faces[hullA->m_faceOffset+face].m_plane.y,\n" +" faces[hullA->m_faceOffset+face].m_plane.z,\n" +" 0.f);\n" +" const float4 faceANormalWS = qtRotate(ornA,Normal);\n" +" \n" +" float d = dot3F4(faceANormalWS,separatingNormal);\n" +" if (d < dmin)\n" +" {\n" +" dmin = d;\n" +" closestFaceA = face;\n" +" worldNormalsA1[pairIndex] = faceANormalWS;\n" +" }\n" +" }\n" +" }\n" +" \n" +" int numVerticesA = faces[hullA->m_faceOffset+closestFaceA].m_numIndices;\n" +" for(int e0=0;e0m_vertexOffset+indices[faces[hullA->m_faceOffset+closestFaceA].m_indexOffset+e0]];\n" +" worldVertsA1[pairIndex*capacityWorldVerts+e0] = transform(&a, &posA,&ornA);\n" +" }\n" +" \n" +" clippingFaces[pairIndex].x = closestFaceA;\n" +" clippingFaces[pairIndex].y = closestFaceB;\n" +" clippingFaces[pairIndex].z = numVerticesA;\n" +" clippingFaces[pairIndex].w = numWorldVertsB1;\n" +" \n" +" \n" +" return numContactsOut;\n" +"}\n" +"int clipFaces(__global float4* worldVertsA1,\n" +" __global float4* worldNormalsA1,\n" +" __global float4* worldVertsB1,\n" +" __global float4* worldVertsB2, \n" +" int capacityWorldVertsB2,\n" +" const float minDist, float maxDist,\n" +" __global int4* clippingFaces,\n" +" int pairIndex)\n" +"{\n" +" int numContactsOut = 0;\n" +" \n" +" int closestFaceA = clippingFaces[pairIndex].x;\n" +" int closestFaceB = clippingFaces[pairIndex].y;\n" +" int numVertsInA = clippingFaces[pairIndex].z;\n" +" int numVertsInB = clippingFaces[pairIndex].w;\n" +" \n" +" int numVertsOut = 0;\n" +" \n" +" if (closestFaceA<0)\n" +" return numContactsOut;\n" +" \n" +" __global float4* pVtxIn = &worldVertsB1[pairIndex*capacityWorldVertsB2];\n" +" __global float4* pVtxOut = &worldVertsB2[pairIndex*capacityWorldVertsB2];\n" +" \n" +" \n" +" \n" +" // clip polygon to back of planes of all faces of hull A that are adjacent to witness face\n" +" \n" +" for(int e0=0;e0=0)\n" +" {\n" +" \n" +" \n" +" \n" +" // clip polygon to back of planes of all faces of hull A that are adjacent to witness face\n" +" \n" +" for(int e0=0;e00)\n" +" {\n" +" __global float4* pointsIn = &worldVertsB2[pairIndex*vertexFaceCapacity];\n" +" float4 normal = -separatingNormals[i];\n" +" \n" +" int nReducedContacts = extractManifoldSequentialGlobal(pointsIn, nPoints, normal, &contactIdx);\n" +" \n" +" int mprContactIndex = pairs[pairIndex].z;\n" +" int dstIdx = mprContactIndex;\n" +" if (dstIdx<0)\n" +" {\n" +" AppendInc( nGlobalContactsOut, dstIdx );\n" +" }\n" +"//#if 0\n" +" \n" +" if (dstIdx < contactCapacity)\n" +" {\n" +" __global struct b3Contact4Data* c = &globalContactsOut[dstIdx];\n" +" c->m_worldNormalOnB = -normal;\n" +" c->m_restituitionCoeffCmp = (0.f*0xffff);c->m_frictionCoeffCmp = (0.7f*0xffff);\n" +" c->m_batchIdx = pairIndex;\n" +" int bodyA = pairs[pairIndex].x;\n" +" int bodyB = pairs[pairIndex].y;\n" +" pairs[pairIndex].w = dstIdx;\n" +" c->m_bodyAPtrAndSignBit = rigidBodies[bodyA].m_invMass==0?-bodyA:bodyA;\n" +" c->m_bodyBPtrAndSignBit = rigidBodies[bodyB].m_invMass==0?-bodyB:bodyB;\n" +" c->m_childIndexA =-1;\n" +" c->m_childIndexB =-1;\n" +" switch (nReducedContacts)\n" +" {\n" +" case 4:\n" +" c->m_worldPosB[3] = pointsIn[contactIdx.w];\n" +" case 3:\n" +" c->m_worldPosB[2] = pointsIn[contactIdx.z];\n" +" case 2:\n" +" c->m_worldPosB[1] = pointsIn[contactIdx.y];\n" +" case 1:\n" +" if (mprContactIndex<0)//test\n" +" c->m_worldPosB[0] = pointsIn[contactIdx.x];\n" +" default:\n" +" {\n" +" }\n" +" };\n" +" \n" +" GET_NPOINTS(*c) = nReducedContacts;\n" +" \n" +" }\n" +" \n" +" \n" +"//#endif\n" +" \n" +" }// if (numContactsOut>0)\n" +" }// if (hasSeparatingAxis[i])\n" +" }// if (im_escapeIndexOrTriangleIndex&~(y)); +} + +int getTriangleIndexGlobal(__global const b3QuantizedBvhNode* rootNode) +{ + unsigned int x=0; + unsigned int y = (~(x&0))<<(31-MAX_NUM_PARTS_IN_BITS); + // Get only the lower bits where the triangle index is stored + return (rootNode->m_escapeIndexOrTriangleIndex&~(y)); +} + +int isLeafNode(const b3QuantizedBvhNode* rootNode) +{ + //skipindex is negative (internal node), triangleindex >=0 (leafnode) + return (rootNode->m_escapeIndexOrTriangleIndex >= 0)? 1 : 0; +} + +int isLeafNodeGlobal(__global const b3QuantizedBvhNode* rootNode) +{ + //skipindex is negative (internal node), triangleindex >=0 (leafnode) + return (rootNode->m_escapeIndexOrTriangleIndex >= 0)? 1 : 0; +} + +int getEscapeIndex(const b3QuantizedBvhNode* rootNode) +{ + return -rootNode->m_escapeIndexOrTriangleIndex; +} + +int getEscapeIndexGlobal(__global const b3QuantizedBvhNode* rootNode) +{ + return -rootNode->m_escapeIndexOrTriangleIndex; +} + + +typedef struct +{ + //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]; +} b3BvhSubtreeInfo; + + + + + + + +typedef struct +{ + float4 m_childPosition; + float4 m_childOrientation; + int m_shapeIndex; + int m_unused0; + int m_unused1; + int m_unused2; +} btGpuChildShape; + + +typedef struct +{ + float4 m_pos; + float4 m_quat; + float4 m_linVel; + float4 m_angVel; + + u32 m_collidableIdx; + float m_invMass; + float m_restituitionCoeff; + float m_frictionCoeff; +} BodyData; + + +typedef struct +{ + float4 m_localCenter; + float4 m_extents; + float4 mC; + float4 mE; + + float m_radius; + int m_faceOffset; + int m_numFaces; + int m_numVertices; + + int m_vertexOffset; + int m_uniqueEdgesOffset; + int m_numUniqueEdges; + int m_unused; +} ConvexPolyhedronCL; + +typedef struct +{ + union + { + float4 m_min; + float m_minElems[4]; + int m_minIndices[4]; + }; + union + { + float4 m_max; + float m_maxElems[4]; + int m_maxIndices[4]; + }; +} btAabbCL; + +#include "Bullet3Collision/BroadPhaseCollision/shared/b3Aabb.h" +#include "Bullet3Common/shared/b3Int2.h" + + + +typedef struct +{ + float4 m_plane; + int m_indexOffset; + int m_numIndices; +} btGpuFace; + +#define make_float4 (float4) + + +__inline +float4 cross3(float4 a, float4 b) +{ + return cross(a,b); + + +// float4 a1 = make_float4(a.xyz,0.f); +// float4 b1 = make_float4(b.xyz,0.f); + +// return cross(a1,b1); + +//float4 c = make_float4(a.y*b.z - a.z*b.y,a.z*b.x - a.x*b.z,a.x*b.y - a.y*b.x,0.f); + + // float4 c = make_float4(a.y*b.z - a.z*b.y,1.f,a.x*b.y - a.y*b.x,0.f); + + //return c; +} + +__inline +float dot3F4(float4 a, float4 b) +{ + float4 a1 = make_float4(a.xyz,0.f); + float4 b1 = make_float4(b.xyz,0.f); + return dot(a1, b1); +} + +__inline +float4 fastNormalize4(float4 v) +{ + v = make_float4(v.xyz,0.f); + return fast_normalize(v); +} + + +/////////////////////////////////////// +// Quaternion +/////////////////////////////////////// + +typedef float4 Quaternion; + +__inline +Quaternion qtMul(Quaternion a, Quaternion b); + +__inline +Quaternion qtNormalize(Quaternion in); + +__inline +float4 qtRotate(Quaternion q, float4 vec); + +__inline +Quaternion qtInvert(Quaternion q); + + + + +__inline +Quaternion qtMul(Quaternion a, Quaternion b) +{ + Quaternion ans; + ans = cross3( a, b ); + ans += a.w*b+b.w*a; +// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z); + ans.w = a.w*b.w - dot3F4(a, b); + return ans; +} + +__inline +Quaternion qtNormalize(Quaternion in) +{ + return fastNormalize4(in); +// in /= length( in ); +// return in; +} +__inline +float4 qtRotate(Quaternion q, float4 vec) +{ + Quaternion qInv = qtInvert( q ); + float4 vcpy = vec; + vcpy.w = 0.f; + float4 out = qtMul(qtMul(q,vcpy),qInv); + return out; +} + +__inline +Quaternion qtInvert(Quaternion q) +{ + return (Quaternion)(-q.xyz, q.w); +} + +__inline +float4 qtInvRotate(const Quaternion q, float4 vec) +{ + return qtRotate( qtInvert( q ), vec ); +} + +__inline +float4 transform(const float4* p, const float4* translation, const Quaternion* orientation) +{ + return qtRotate( *orientation, *p ) + (*translation); +} + + + +__inline +float4 normalize3(const float4 a) +{ + float4 n = make_float4(a.x, a.y, a.z, 0.f); + return fastNormalize4( n ); +} + +inline void projectLocal(const ConvexPolyhedronCL* hull, const float4 pos, const float4 orn, +const float4* dir, const float4* vertices, float* min, float* max) +{ + min[0] = FLT_MAX; + max[0] = -FLT_MAX; + int numVerts = hull->m_numVertices; + + const float4 localDir = qtInvRotate(orn,*dir); + float offset = dot(pos,*dir); + for(int i=0;im_vertexOffset+i],localDir); + if(dp < min[0]) + min[0] = dp; + if(dp > max[0]) + max[0] = dp; + } + if(min[0]>max[0]) + { + float tmp = min[0]; + min[0] = max[0]; + max[0] = tmp; + } + min[0] += offset; + max[0] += offset; +} + +inline void project(__global const ConvexPolyhedronCL* hull, const float4 pos, const float4 orn, +const float4* dir, __global const float4* vertices, float* min, float* max) +{ + min[0] = FLT_MAX; + max[0] = -FLT_MAX; + int numVerts = hull->m_numVertices; + + const float4 localDir = qtInvRotate(orn,*dir); + float offset = dot(pos,*dir); + for(int i=0;im_vertexOffset+i],localDir); + if(dp < min[0]) + min[0] = dp; + if(dp > max[0]) + max[0] = dp; + } + if(min[0]>max[0]) + { + float tmp = min[0]; + min[0] = max[0]; + max[0] = tmp; + } + min[0] += offset; + max[0] += offset; +} + +inline bool TestSepAxisLocalA(const ConvexPolyhedronCL* hullA, __global const ConvexPolyhedronCL* hullB, + const float4 posA,const float4 ornA, + const float4 posB,const float4 ornB, + float4* sep_axis, const float4* verticesA, __global const float4* verticesB,float* depth) +{ + float Min0,Max0; + float Min1,Max1; + projectLocal(hullA,posA,ornA,sep_axis,verticesA, &Min0, &Max0); + project(hullB,posB,ornB, sep_axis,verticesB, &Min1, &Max1); + + if(Max01e-6f || fabs(v.y)>1e-6f || fabs(v.z)>1e-6f) + return false; + return true; +} + + + +bool findSeparatingAxisLocalA( const ConvexPolyhedronCL* hullA, __global const ConvexPolyhedronCL* hullB, + const float4 posA1, + const float4 ornA, + const float4 posB1, + const float4 ornB, + const float4 DeltaC2, + + const float4* verticesA, + const float4* uniqueEdgesA, + const btGpuFace* facesA, + const int* indicesA, + + __global const float4* verticesB, + __global const float4* uniqueEdgesB, + __global const btGpuFace* facesB, + __global const int* indicesB, + float4* sep, + float* dmin) +{ + + + float4 posA = posA1; + posA.w = 0.f; + float4 posB = posB1; + posB.w = 0.f; + int curPlaneTests=0; + { + int numFacesA = hullA->m_numFaces; + // Test normals from hullA + for(int i=0;im_faceOffset+i].m_plane; + float4 faceANormalWS = qtRotate(ornA,normal); + if (dot3F4(DeltaC2,faceANormalWS)<0) + faceANormalWS*=-1.f; + curPlaneTests++; + float d; + if(!TestSepAxisLocalA( hullA, hullB, posA,ornA,posB,ornB,&faceANormalWS, verticesA, verticesB,&d)) + return false; + if(d<*dmin) + { + *dmin = d; + *sep = faceANormalWS; + } + } + } + if((dot3F4(-DeltaC2,*sep))>0.0f) + { + *sep = -(*sep); + } + return true; +} + +bool findSeparatingAxisLocalB( __global const ConvexPolyhedronCL* hullA, const ConvexPolyhedronCL* hullB, + const float4 posA1, + const float4 ornA, + const float4 posB1, + const float4 ornB, + const float4 DeltaC2, + __global const float4* verticesA, + __global const float4* uniqueEdgesA, + __global const btGpuFace* facesA, + __global const int* indicesA, + const float4* verticesB, + const float4* uniqueEdgesB, + const btGpuFace* facesB, + const int* indicesB, + float4* sep, + float* dmin) +{ + + + float4 posA = posA1; + posA.w = 0.f; + float4 posB = posB1; + posB.w = 0.f; + int curPlaneTests=0; + { + int numFacesA = hullA->m_numFaces; + // Test normals from hullA + for(int i=0;im_faceOffset+i].m_plane; + float4 faceANormalWS = qtRotate(ornA,normal); + if (dot3F4(DeltaC2,faceANormalWS)<0) + faceANormalWS *= -1.f; + curPlaneTests++; + float d; + if(!TestSepAxisLocalA( hullB, hullA, posB,ornB,posA,ornA, &faceANormalWS, verticesB,verticesA, &d)) + return false; + if(d<*dmin) + { + *dmin = d; + *sep = faceANormalWS; + } + } + } + if((dot3F4(-DeltaC2,*sep))>0.0f) + { + *sep = -(*sep); + } + return true; +} + + + +bool findSeparatingAxisEdgeEdgeLocalA( const ConvexPolyhedronCL* hullA, __global const ConvexPolyhedronCL* hullB, + const float4 posA1, + const float4 ornA, + const float4 posB1, + const float4 ornB, + const float4 DeltaC2, + const float4* verticesA, + const float4* uniqueEdgesA, + const btGpuFace* facesA, + const int* indicesA, + __global const float4* verticesB, + __global const float4* uniqueEdgesB, + __global const btGpuFace* facesB, + __global const int* indicesB, + float4* sep, + float* dmin) +{ + + + float4 posA = posA1; + posA.w = 0.f; + float4 posB = posB1; + posB.w = 0.f; + + int curPlaneTests=0; + + int curEdgeEdge = 0; + // Test edges + for(int e0=0;e0m_numUniqueEdges;e0++) + { + const float4 edge0 = uniqueEdgesA[hullA->m_uniqueEdgesOffset+e0]; + float4 edge0World = qtRotate(ornA,edge0); + + for(int e1=0;e1m_numUniqueEdges;e1++) + { + const float4 edge1 = uniqueEdgesB[hullB->m_uniqueEdgesOffset+e1]; + float4 edge1World = qtRotate(ornB,edge1); + + + float4 crossje = cross3(edge0World,edge1World); + + curEdgeEdge++; + if(!IsAlmostZero(crossje)) + { + crossje = normalize3(crossje); + if (dot3F4(DeltaC2,crossje)<0) + crossje *= -1.f; + + float dist; + bool result = true; + { + float Min0,Max0; + float Min1,Max1; + projectLocal(hullA,posA,ornA,&crossje,verticesA, &Min0, &Max0); + project(hullB,posB,ornB,&crossje,verticesB, &Min1, &Max1); + + if(Max00.0f) + { + *sep = -(*sep); + } + return true; +} + + + +inline int findClippingFaces(const float4 separatingNormal, + const ConvexPolyhedronCL* hullA, + __global const ConvexPolyhedronCL* hullB, + const float4 posA, const Quaternion ornA,const float4 posB, const Quaternion ornB, + __global float4* worldVertsA1, + __global float4* worldNormalsA1, + __global float4* worldVertsB1, + int capacityWorldVerts, + const float minDist, float maxDist, + const float4* verticesA, + const btGpuFace* facesA, + const int* indicesA, + __global const float4* verticesB, + __global const btGpuFace* facesB, + __global const int* indicesB, + __global int4* clippingFaces, int pairIndex) +{ + int numContactsOut = 0; + int numWorldVertsB1= 0; + + + int closestFaceB=0; + float dmax = -FLT_MAX; + + { + for(int face=0;facem_numFaces;face++) + { + const float4 Normal = make_float4(facesB[hullB->m_faceOffset+face].m_plane.x, + facesB[hullB->m_faceOffset+face].m_plane.y, facesB[hullB->m_faceOffset+face].m_plane.z,0.f); + const float4 WorldNormal = qtRotate(ornB, Normal); + float d = dot3F4(WorldNormal,separatingNormal); + if (d > dmax) + { + dmax = d; + closestFaceB = face; + } + } + } + + { + const btGpuFace polyB = facesB[hullB->m_faceOffset+closestFaceB]; + int numVertices = polyB.m_numIndices; + if (numVertices>capacityWorldVerts) + numVertices = capacityWorldVerts; + if (numVertices<0) + numVertices = 0; + + for(int e0=0;e0m_vertexOffset+indicesB[polyB.m_indexOffset+e0]]; + worldVertsB1[pairIndex*capacityWorldVerts+numWorldVertsB1++] = transform(&b,&posB,&ornB); + } + } + } + + int closestFaceA=0; + { + float dmin = FLT_MAX; + for(int face=0;facem_numFaces;face++) + { + const float4 Normal = make_float4( + facesA[hullA->m_faceOffset+face].m_plane.x, + facesA[hullA->m_faceOffset+face].m_plane.y, + facesA[hullA->m_faceOffset+face].m_plane.z, + 0.f); + const float4 faceANormalWS = qtRotate(ornA,Normal); + + float d = dot3F4(faceANormalWS,separatingNormal); + if (d < dmin) + { + dmin = d; + closestFaceA = face; + worldNormalsA1[pairIndex] = faceANormalWS; + } + } + } + + int numVerticesA = facesA[hullA->m_faceOffset+closestFaceA].m_numIndices; + if (numVerticesA>capacityWorldVerts) + numVerticesA = capacityWorldVerts; + if (numVerticesA<0) + numVerticesA=0; + + for(int e0=0;e0m_vertexOffset+indicesA[facesA[hullA->m_faceOffset+closestFaceA].m_indexOffset+e0]]; + worldVertsA1[pairIndex*capacityWorldVerts+e0] = transform(&a, &posA,&ornA); + } + } + + clippingFaces[pairIndex].x = closestFaceA; + clippingFaces[pairIndex].y = closestFaceB; + clippingFaces[pairIndex].z = numVerticesA; + clippingFaces[pairIndex].w = numWorldVertsB1; + + + return numContactsOut; +} + + + + +// work-in-progress +__kernel void findConcaveSeparatingAxisVertexFaceKernel( __global int4* concavePairs, + __global const BodyData* rigidBodies, + __global const btCollidableGpu* collidables, + __global const ConvexPolyhedronCL* convexShapes, + __global const float4* vertices, + __global const float4* uniqueEdges, + __global const btGpuFace* faces, + __global const int* indices, + __global const btGpuChildShape* gpuChildShapes, + __global btAabbCL* aabbs, + __global float4* concaveSeparatingNormalsOut, + __global int* concaveHasSeparatingNormals, + __global int4* clippingFacesOut, + __global float4* worldVertsA1GPU, + __global float4* worldNormalsAGPU, + __global float4* worldVertsB1GPU, + __global float* dmins, + int vertexFaceCapacity, + int numConcavePairs + ) +{ + + int i = get_global_id(0); + if (i>=numConcavePairs) + return; + + concaveHasSeparatingNormals[i] = 0; + + int pairIdx = i; + + int bodyIndexA = concavePairs[i].x; + int bodyIndexB = concavePairs[i].y; + + int collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx; + int collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx; + + int shapeIndexA = collidables[collidableIndexA].m_shapeIndex; + int shapeIndexB = collidables[collidableIndexB].m_shapeIndex; + + if (collidables[collidableIndexB].m_shapeType!=SHAPE_CONVEX_HULL&& + collidables[collidableIndexB].m_shapeType!=SHAPE_COMPOUND_OF_CONVEX_HULLS) + { + concavePairs[pairIdx].w = -1; + return; + } + + + + int numFacesA = convexShapes[shapeIndexA].m_numFaces; + int numActualConcaveConvexTests = 0; + + int f = concavePairs[i].z; + + bool overlap = false; + + ConvexPolyhedronCL convexPolyhedronA; + + //add 3 vertices of the triangle + convexPolyhedronA.m_numVertices = 3; + convexPolyhedronA.m_vertexOffset = 0; + float4 localCenter = make_float4(0.f,0.f,0.f,0.f); + + btGpuFace face = faces[convexShapes[shapeIndexA].m_faceOffset+f]; + float4 triMinAabb, triMaxAabb; + btAabbCL triAabb; + triAabb.m_min = make_float4(1e30f,1e30f,1e30f,0.f); + triAabb.m_max = make_float4(-1e30f,-1e30f,-1e30f,0.f); + + float4 verticesA[3]; + for (int i=0;i<3;i++) + { + int index = indices[face.m_indexOffset+i]; + float4 vert = vertices[convexShapes[shapeIndexA].m_vertexOffset+index]; + verticesA[i] = vert; + localCenter += vert; + + triAabb.m_min = min(triAabb.m_min,vert); + triAabb.m_max = max(triAabb.m_max,vert); + + } + + overlap = true; + overlap = (triAabb.m_min.x > aabbs[bodyIndexB].m_max.x || triAabb.m_max.x < aabbs[bodyIndexB].m_min.x) ? false : overlap; + overlap = (triAabb.m_min.z > aabbs[bodyIndexB].m_max.z || triAabb.m_max.z < aabbs[bodyIndexB].m_min.z) ? false : overlap; + overlap = (triAabb.m_min.y > aabbs[bodyIndexB].m_max.y || triAabb.m_max.y < aabbs[bodyIndexB].m_min.y) ? false : overlap; + + if (overlap) + { + float dmin = FLT_MAX; + int hasSeparatingAxis=5; + float4 sepAxis=make_float4(1,2,3,4); + + int localCC=0; + numActualConcaveConvexTests++; + + //a triangle has 3 unique edges + convexPolyhedronA.m_numUniqueEdges = 3; + convexPolyhedronA.m_uniqueEdgesOffset = 0; + float4 uniqueEdgesA[3]; + + uniqueEdgesA[0] = (verticesA[1]-verticesA[0]); + uniqueEdgesA[1] = (verticesA[2]-verticesA[1]); + uniqueEdgesA[2] = (verticesA[0]-verticesA[2]); + + + convexPolyhedronA.m_faceOffset = 0; + + float4 normal = make_float4(face.m_plane.x,face.m_plane.y,face.m_plane.z,0.f); + + btGpuFace facesA[TRIANGLE_NUM_CONVEX_FACES]; + int indicesA[3+3+2+2+2]; + int curUsedIndices=0; + int fidx=0; + + //front size of triangle + { + facesA[fidx].m_indexOffset=curUsedIndices; + indicesA[0] = 0; + indicesA[1] = 1; + indicesA[2] = 2; + curUsedIndices+=3; + float c = face.m_plane.w; + facesA[fidx].m_plane.x = normal.x; + facesA[fidx].m_plane.y = normal.y; + facesA[fidx].m_plane.z = normal.z; + facesA[fidx].m_plane.w = c; + facesA[fidx].m_numIndices=3; + } + fidx++; + //back size of triangle + { + facesA[fidx].m_indexOffset=curUsedIndices; + indicesA[3]=2; + indicesA[4]=1; + indicesA[5]=0; + curUsedIndices+=3; + float c = dot(normal,verticesA[0]); + float c1 = -face.m_plane.w; + facesA[fidx].m_plane.x = -normal.x; + facesA[fidx].m_plane.y = -normal.y; + facesA[fidx].m_plane.z = -normal.z; + facesA[fidx].m_plane.w = c; + facesA[fidx].m_numIndices=3; + } + fidx++; + + bool addEdgePlanes = true; + if (addEdgePlanes) + { + int numVertices=3; + int prevVertex = numVertices-1; + for (int i=0;i=numConcavePairs) + return; + + if (!concaveHasSeparatingNormals[i]) + return; + + int pairIdx = i; + + int bodyIndexA = concavePairs[i].x; + int bodyIndexB = concavePairs[i].y; + + int collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx; + int collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx; + + int shapeIndexA = collidables[collidableIndexA].m_shapeIndex; + int shapeIndexB = collidables[collidableIndexB].m_shapeIndex; + + + int numFacesA = convexShapes[shapeIndexA].m_numFaces; + int numActualConcaveConvexTests = 0; + + int f = concavePairs[i].z; + + bool overlap = false; + + ConvexPolyhedronCL convexPolyhedronA; + + //add 3 vertices of the triangle + convexPolyhedronA.m_numVertices = 3; + convexPolyhedronA.m_vertexOffset = 0; + float4 localCenter = make_float4(0.f,0.f,0.f,0.f); + + btGpuFace face = faces[convexShapes[shapeIndexA].m_faceOffset+f]; + float4 triMinAabb, triMaxAabb; + btAabbCL triAabb; + triAabb.m_min = make_float4(1e30f,1e30f,1e30f,0.f); + triAabb.m_max = make_float4(-1e30f,-1e30f,-1e30f,0.f); + + float4 verticesA[3]; + for (int i=0;i<3;i++) + { + int index = indices[face.m_indexOffset+i]; + float4 vert = vertices[convexShapes[shapeIndexA].m_vertexOffset+index]; + verticesA[i] = vert; + localCenter += vert; + + triAabb.m_min = min(triAabb.m_min,vert); + triAabb.m_max = max(triAabb.m_max,vert); + + } + + overlap = true; + overlap = (triAabb.m_min.x > aabbs[bodyIndexB].m_max.x || triAabb.m_max.x < aabbs[bodyIndexB].m_min.x) ? false : overlap; + overlap = (triAabb.m_min.z > aabbs[bodyIndexB].m_max.z || triAabb.m_max.z < aabbs[bodyIndexB].m_min.z) ? false : overlap; + overlap = (triAabb.m_min.y > aabbs[bodyIndexB].m_max.y || triAabb.m_max.y < aabbs[bodyIndexB].m_min.y) ? false : overlap; + + if (overlap) + { + float dmin = dmins[i]; + int hasSeparatingAxis=5; + float4 sepAxis=make_float4(1,2,3,4); + sepAxis = concaveSeparatingNormalsOut[pairIdx]; + + int localCC=0; + numActualConcaveConvexTests++; + + //a triangle has 3 unique edges + convexPolyhedronA.m_numUniqueEdges = 3; + convexPolyhedronA.m_uniqueEdgesOffset = 0; + float4 uniqueEdgesA[3]; + + uniqueEdgesA[0] = (verticesA[1]-verticesA[0]); + uniqueEdgesA[1] = (verticesA[2]-verticesA[1]); + uniqueEdgesA[2] = (verticesA[0]-verticesA[2]); + + + convexPolyhedronA.m_faceOffset = 0; + + float4 normal = make_float4(face.m_plane.x,face.m_plane.y,face.m_plane.z,0.f); + + btGpuFace facesA[TRIANGLE_NUM_CONVEX_FACES]; + int indicesA[3+3+2+2+2]; + int curUsedIndices=0; + int fidx=0; + + //front size of triangle + { + facesA[fidx].m_indexOffset=curUsedIndices; + indicesA[0] = 0; + indicesA[1] = 1; + indicesA[2] = 2; + curUsedIndices+=3; + float c = face.m_plane.w; + facesA[fidx].m_plane.x = normal.x; + facesA[fidx].m_plane.y = normal.y; + facesA[fidx].m_plane.z = normal.z; + facesA[fidx].m_plane.w = c; + facesA[fidx].m_numIndices=3; + } + fidx++; + //back size of triangle + { + facesA[fidx].m_indexOffset=curUsedIndices; + indicesA[3]=2; + indicesA[4]=1; + indicesA[5]=0; + curUsedIndices+=3; + float c = dot(normal,verticesA[0]); + float c1 = -face.m_plane.w; + facesA[fidx].m_plane.x = -normal.x; + facesA[fidx].m_plane.y = -normal.y; + facesA[fidx].m_plane.z = -normal.z; + facesA[fidx].m_plane.w = c; + facesA[fidx].m_numIndices=3; + } + fidx++; + + bool addEdgePlanes = true; + if (addEdgePlanes) + { + int numVertices=3; + int prevVertex = numVertices-1; + for (int i=0;im_escapeIndexOrTriangleIndex&~(y));\n" +"}\n" +"int getTriangleIndexGlobal(__global const b3QuantizedBvhNode* rootNode)\n" +"{\n" +" unsigned int x=0;\n" +" unsigned int y = (~(x&0))<<(31-MAX_NUM_PARTS_IN_BITS);\n" +" // Get only the lower bits where the triangle index is stored\n" +" return (rootNode->m_escapeIndexOrTriangleIndex&~(y));\n" +"}\n" +"int isLeafNode(const b3QuantizedBvhNode* rootNode)\n" +"{\n" +" //skipindex is negative (internal node), triangleindex >=0 (leafnode)\n" +" return (rootNode->m_escapeIndexOrTriangleIndex >= 0)? 1 : 0;\n" +"}\n" +"int isLeafNodeGlobal(__global const b3QuantizedBvhNode* rootNode)\n" +"{\n" +" //skipindex is negative (internal node), triangleindex >=0 (leafnode)\n" +" return (rootNode->m_escapeIndexOrTriangleIndex >= 0)? 1 : 0;\n" +"}\n" +" \n" +"int getEscapeIndex(const b3QuantizedBvhNode* rootNode)\n" +"{\n" +" return -rootNode->m_escapeIndexOrTriangleIndex;\n" +"}\n" +"int getEscapeIndexGlobal(__global const b3QuantizedBvhNode* rootNode)\n" +"{\n" +" return -rootNode->m_escapeIndexOrTriangleIndex;\n" +"}\n" +"typedef struct\n" +"{\n" +" //12 bytes\n" +" unsigned short int m_quantizedAabbMin[3];\n" +" unsigned short int m_quantizedAabbMax[3];\n" +" //4 bytes, points to the root of the subtree\n" +" int m_rootNodeIndex;\n" +" //4 bytes\n" +" int m_subtreeSize;\n" +" int m_padding[3];\n" +"} b3BvhSubtreeInfo;\n" +"typedef struct\n" +"{\n" +" float4 m_childPosition;\n" +" float4 m_childOrientation;\n" +" int m_shapeIndex;\n" +" int m_unused0;\n" +" int m_unused1;\n" +" int m_unused2;\n" +"} btGpuChildShape;\n" +"typedef struct\n" +"{\n" +" float4 m_pos;\n" +" float4 m_quat;\n" +" float4 m_linVel;\n" +" float4 m_angVel;\n" +" u32 m_collidableIdx;\n" +" float m_invMass;\n" +" float m_restituitionCoeff;\n" +" float m_frictionCoeff;\n" +"} BodyData;\n" +"typedef struct \n" +"{\n" +" float4 m_localCenter;\n" +" float4 m_extents;\n" +" float4 mC;\n" +" float4 mE;\n" +" \n" +" float m_radius;\n" +" int m_faceOffset;\n" +" int m_numFaces;\n" +" int m_numVertices;\n" +" int m_vertexOffset;\n" +" int m_uniqueEdgesOffset;\n" +" int m_numUniqueEdges;\n" +" int m_unused;\n" +"} ConvexPolyhedronCL;\n" +"typedef struct \n" +"{\n" +" union\n" +" {\n" +" float4 m_min;\n" +" float m_minElems[4];\n" +" int m_minIndices[4];\n" +" };\n" +" union\n" +" {\n" +" float4 m_max;\n" +" float m_maxElems[4];\n" +" int m_maxIndices[4];\n" +" };\n" +"} btAabbCL;\n" +"#ifndef B3_AABB_H\n" +"#define B3_AABB_H\n" +"#ifndef B3_FLOAT4_H\n" +"#define B3_FLOAT4_H\n" +"#ifndef B3_PLATFORM_DEFINITIONS_H\n" +"#define B3_PLATFORM_DEFINITIONS_H\n" +"struct MyTest\n" +"{\n" +" int bla;\n" +"};\n" +"#ifdef __cplusplus\n" +"#else\n" +"//keep B3_LARGE_FLOAT*B3_LARGE_FLOAT < FLT_MAX\n" +"#define B3_LARGE_FLOAT 1e18f\n" +"#define B3_INFINITY 1e18f\n" +"#define b3Assert(a)\n" +"#define b3ConstArray(a) __global const a*\n" +"#define b3AtomicInc atomic_inc\n" +"#define b3AtomicAdd atomic_add\n" +"#define b3Fabs fabs\n" +"#define b3Sqrt native_sqrt\n" +"#define b3Sin native_sin\n" +"#define b3Cos native_cos\n" +"#define B3_STATIC\n" +"#endif\n" +"#endif\n" +"#ifdef __cplusplus\n" +"#else\n" +" typedef float4 b3Float4;\n" +" #define b3Float4ConstArg const b3Float4\n" +" #define b3MakeFloat4 (float4)\n" +" float b3Dot3F4(b3Float4ConstArg v0,b3Float4ConstArg v1)\n" +" {\n" +" float4 a1 = b3MakeFloat4(v0.xyz,0.f);\n" +" float4 b1 = b3MakeFloat4(v1.xyz,0.f);\n" +" return dot(a1, b1);\n" +" }\n" +" b3Float4 b3Cross3(b3Float4ConstArg v0,b3Float4ConstArg v1)\n" +" {\n" +" float4 a1 = b3MakeFloat4(v0.xyz,0.f);\n" +" float4 b1 = b3MakeFloat4(v1.xyz,0.f);\n" +" return cross(a1, b1);\n" +" }\n" +" #define b3MinFloat4 min\n" +" #define b3MaxFloat4 max\n" +" #define b3Normalized(a) normalize(a)\n" +"#endif \n" +" \n" +"inline bool b3IsAlmostZero(b3Float4ConstArg v)\n" +"{\n" +" if(b3Fabs(v.x)>1e-6 || b3Fabs(v.y)>1e-6 || b3Fabs(v.z)>1e-6) \n" +" return false;\n" +" return true;\n" +"}\n" +"inline int b3MaxDot( b3Float4ConstArg vec, __global const b3Float4* vecArray, int vecLen, float* dotOut )\n" +"{\n" +" float maxDot = -B3_INFINITY;\n" +" int i = 0;\n" +" int ptIndex = -1;\n" +" for( i = 0; i < vecLen; i++ )\n" +" {\n" +" float dot = b3Dot3F4(vecArray[i],vec);\n" +" \n" +" if( dot > maxDot )\n" +" {\n" +" maxDot = dot;\n" +" ptIndex = i;\n" +" }\n" +" }\n" +" b3Assert(ptIndex>=0);\n" +" if (ptIndex<0)\n" +" {\n" +" ptIndex = 0;\n" +" }\n" +" *dotOut = maxDot;\n" +" return ptIndex;\n" +"}\n" +"#endif //B3_FLOAT4_H\n" +"#ifndef B3_MAT3x3_H\n" +"#define B3_MAT3x3_H\n" +"#ifndef B3_QUAT_H\n" +"#define B3_QUAT_H\n" +"#ifndef B3_PLATFORM_DEFINITIONS_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif\n" +"#endif\n" +"#ifndef B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +" typedef float4 b3Quat;\n" +" #define b3QuatConstArg const b3Quat\n" +" \n" +" \n" +"inline float4 b3FastNormalize4(float4 v)\n" +"{\n" +" v = (float4)(v.xyz,0.f);\n" +" return fast_normalize(v);\n" +"}\n" +" \n" +"inline b3Quat b3QuatMul(b3Quat a, b3Quat b);\n" +"inline b3Quat b3QuatNormalized(b3QuatConstArg in);\n" +"inline b3Quat b3QuatRotate(b3QuatConstArg q, b3QuatConstArg vec);\n" +"inline b3Quat b3QuatInvert(b3QuatConstArg q);\n" +"inline b3Quat b3QuatInverse(b3QuatConstArg q);\n" +"inline b3Quat b3QuatMul(b3QuatConstArg a, b3QuatConstArg b)\n" +"{\n" +" b3Quat ans;\n" +" ans = b3Cross3( a, b );\n" +" ans += a.w*b+b.w*a;\n" +"// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z);\n" +" ans.w = a.w*b.w - b3Dot3F4(a, b);\n" +" return ans;\n" +"}\n" +"inline b3Quat b3QuatNormalized(b3QuatConstArg in)\n" +"{\n" +" b3Quat q;\n" +" q=in;\n" +" //return b3FastNormalize4(in);\n" +" float len = native_sqrt(dot(q, q));\n" +" if(len > 0.f)\n" +" {\n" +" q *= 1.f / len;\n" +" }\n" +" else\n" +" {\n" +" q.x = q.y = q.z = 0.f;\n" +" q.w = 1.f;\n" +" }\n" +" return q;\n" +"}\n" +"inline float4 b3QuatRotate(b3QuatConstArg q, b3QuatConstArg vec)\n" +"{\n" +" b3Quat qInv = b3QuatInvert( q );\n" +" float4 vcpy = vec;\n" +" vcpy.w = 0.f;\n" +" float4 out = b3QuatMul(b3QuatMul(q,vcpy),qInv);\n" +" return out;\n" +"}\n" +"inline b3Quat b3QuatInverse(b3QuatConstArg q)\n" +"{\n" +" return (b3Quat)(-q.xyz, q.w);\n" +"}\n" +"inline b3Quat b3QuatInvert(b3QuatConstArg q)\n" +"{\n" +" return (b3Quat)(-q.xyz, q.w);\n" +"}\n" +"inline float4 b3QuatInvRotate(b3QuatConstArg q, b3QuatConstArg vec)\n" +"{\n" +" return b3QuatRotate( b3QuatInvert( q ), vec );\n" +"}\n" +"inline b3Float4 b3TransformPoint(b3Float4ConstArg point, b3Float4ConstArg translation, b3QuatConstArg orientation)\n" +"{\n" +" return b3QuatRotate( orientation, point ) + (translation);\n" +"}\n" +" \n" +"#endif \n" +"#endif //B3_QUAT_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"typedef struct\n" +"{\n" +" b3Float4 m_row[3];\n" +"}b3Mat3x3;\n" +"#define b3Mat3x3ConstArg const b3Mat3x3\n" +"#define b3GetRow(m,row) (m.m_row[row])\n" +"inline b3Mat3x3 b3QuatGetRotationMatrix(b3Quat quat)\n" +"{\n" +" b3Float4 quat2 = (b3Float4)(quat.x*quat.x, quat.y*quat.y, quat.z*quat.z, 0.f);\n" +" b3Mat3x3 out;\n" +" out.m_row[0].x=1-2*quat2.y-2*quat2.z;\n" +" out.m_row[0].y=2*quat.x*quat.y-2*quat.w*quat.z;\n" +" out.m_row[0].z=2*quat.x*quat.z+2*quat.w*quat.y;\n" +" out.m_row[0].w = 0.f;\n" +" out.m_row[1].x=2*quat.x*quat.y+2*quat.w*quat.z;\n" +" out.m_row[1].y=1-2*quat2.x-2*quat2.z;\n" +" out.m_row[1].z=2*quat.y*quat.z-2*quat.w*quat.x;\n" +" out.m_row[1].w = 0.f;\n" +" out.m_row[2].x=2*quat.x*quat.z-2*quat.w*quat.y;\n" +" out.m_row[2].y=2*quat.y*quat.z+2*quat.w*quat.x;\n" +" out.m_row[2].z=1-2*quat2.x-2*quat2.y;\n" +" out.m_row[2].w = 0.f;\n" +" return out;\n" +"}\n" +"inline b3Mat3x3 b3AbsoluteMat3x3(b3Mat3x3ConstArg matIn)\n" +"{\n" +" b3Mat3x3 out;\n" +" out.m_row[0] = fabs(matIn.m_row[0]);\n" +" out.m_row[1] = fabs(matIn.m_row[1]);\n" +" out.m_row[2] = fabs(matIn.m_row[2]);\n" +" return out;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtZero();\n" +"__inline\n" +"b3Mat3x3 mtIdentity();\n" +"__inline\n" +"b3Mat3x3 mtTranspose(b3Mat3x3 m);\n" +"__inline\n" +"b3Mat3x3 mtMul(b3Mat3x3 a, b3Mat3x3 b);\n" +"__inline\n" +"b3Float4 mtMul1(b3Mat3x3 a, b3Float4 b);\n" +"__inline\n" +"b3Float4 mtMul3(b3Float4 a, b3Mat3x3 b);\n" +"__inline\n" +"b3Mat3x3 mtZero()\n" +"{\n" +" b3Mat3x3 m;\n" +" m.m_row[0] = (b3Float4)(0.f);\n" +" m.m_row[1] = (b3Float4)(0.f);\n" +" m.m_row[2] = (b3Float4)(0.f);\n" +" return m;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtIdentity()\n" +"{\n" +" b3Mat3x3 m;\n" +" m.m_row[0] = (b3Float4)(1,0,0,0);\n" +" m.m_row[1] = (b3Float4)(0,1,0,0);\n" +" m.m_row[2] = (b3Float4)(0,0,1,0);\n" +" return m;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtTranspose(b3Mat3x3 m)\n" +"{\n" +" b3Mat3x3 out;\n" +" out.m_row[0] = (b3Float4)(m.m_row[0].x, m.m_row[1].x, m.m_row[2].x, 0.f);\n" +" out.m_row[1] = (b3Float4)(m.m_row[0].y, m.m_row[1].y, m.m_row[2].y, 0.f);\n" +" out.m_row[2] = (b3Float4)(m.m_row[0].z, m.m_row[1].z, m.m_row[2].z, 0.f);\n" +" return out;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtMul(b3Mat3x3 a, b3Mat3x3 b)\n" +"{\n" +" b3Mat3x3 transB;\n" +" transB = mtTranspose( b );\n" +" b3Mat3x3 ans;\n" +" // why this doesn't run when 0ing in the for{}\n" +" a.m_row[0].w = 0.f;\n" +" a.m_row[1].w = 0.f;\n" +" a.m_row[2].w = 0.f;\n" +" for(int i=0; i<3; i++)\n" +" {\n" +"// a.m_row[i].w = 0.f;\n" +" ans.m_row[i].x = b3Dot3F4(a.m_row[i],transB.m_row[0]);\n" +" ans.m_row[i].y = b3Dot3F4(a.m_row[i],transB.m_row[1]);\n" +" ans.m_row[i].z = b3Dot3F4(a.m_row[i],transB.m_row[2]);\n" +" ans.m_row[i].w = 0.f;\n" +" }\n" +" return ans;\n" +"}\n" +"__inline\n" +"b3Float4 mtMul1(b3Mat3x3 a, b3Float4 b)\n" +"{\n" +" b3Float4 ans;\n" +" ans.x = b3Dot3F4( a.m_row[0], b );\n" +" ans.y = b3Dot3F4( a.m_row[1], b );\n" +" ans.z = b3Dot3F4( a.m_row[2], b );\n" +" ans.w = 0.f;\n" +" return ans;\n" +"}\n" +"__inline\n" +"b3Float4 mtMul3(b3Float4 a, b3Mat3x3 b)\n" +"{\n" +" b3Float4 colx = b3MakeFloat4(b.m_row[0].x, b.m_row[1].x, b.m_row[2].x, 0);\n" +" b3Float4 coly = b3MakeFloat4(b.m_row[0].y, b.m_row[1].y, b.m_row[2].y, 0);\n" +" b3Float4 colz = b3MakeFloat4(b.m_row[0].z, b.m_row[1].z, b.m_row[2].z, 0);\n" +" b3Float4 ans;\n" +" ans.x = b3Dot3F4( a, colx );\n" +" ans.y = b3Dot3F4( a, coly );\n" +" ans.z = b3Dot3F4( a, colz );\n" +" return ans;\n" +"}\n" +"#endif\n" +"#endif //B3_MAT3x3_H\n" +"typedef struct b3Aabb b3Aabb_t;\n" +"struct b3Aabb\n" +"{\n" +" union\n" +" {\n" +" float m_min[4];\n" +" b3Float4 m_minVec;\n" +" int m_minIndices[4];\n" +" };\n" +" union\n" +" {\n" +" float m_max[4];\n" +" b3Float4 m_maxVec;\n" +" int m_signedMaxIndices[4];\n" +" };\n" +"};\n" +"inline void b3TransformAabb2(b3Float4ConstArg localAabbMin,b3Float4ConstArg localAabbMax, float margin,\n" +" b3Float4ConstArg pos,\n" +" b3QuatConstArg orn,\n" +" b3Float4* aabbMinOut,b3Float4* aabbMaxOut)\n" +"{\n" +" b3Float4 localHalfExtents = 0.5f*(localAabbMax-localAabbMin);\n" +" localHalfExtents+=b3MakeFloat4(margin,margin,margin,0.f);\n" +" b3Float4 localCenter = 0.5f*(localAabbMax+localAabbMin);\n" +" b3Mat3x3 m;\n" +" m = b3QuatGetRotationMatrix(orn);\n" +" b3Mat3x3 abs_b = b3AbsoluteMat3x3(m);\n" +" b3Float4 center = b3TransformPoint(localCenter,pos,orn);\n" +" \n" +" b3Float4 extent = b3MakeFloat4(b3Dot3F4(localHalfExtents,b3GetRow(abs_b,0)),\n" +" b3Dot3F4(localHalfExtents,b3GetRow(abs_b,1)),\n" +" b3Dot3F4(localHalfExtents,b3GetRow(abs_b,2)),\n" +" 0.f);\n" +" *aabbMinOut = center-extent;\n" +" *aabbMaxOut = center+extent;\n" +"}\n" +"/// conservative test for overlap between two aabbs\n" +"inline bool b3TestAabbAgainstAabb(b3Float4ConstArg aabbMin1,b3Float4ConstArg aabbMax1,\n" +" b3Float4ConstArg aabbMin2, b3Float4ConstArg aabbMax2)\n" +"{\n" +" bool overlap = true;\n" +" overlap = (aabbMin1.x > aabbMax2.x || aabbMax1.x < aabbMin2.x) ? false : overlap;\n" +" overlap = (aabbMin1.z > aabbMax2.z || aabbMax1.z < aabbMin2.z) ? false : overlap;\n" +" overlap = (aabbMin1.y > aabbMax2.y || aabbMax1.y < aabbMin2.y) ? false : overlap;\n" +" return overlap;\n" +"}\n" +"#endif //B3_AABB_H\n" +"/*\n" +"Bullet Continuous Collision Detection and Physics Library\n" +"Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org\n" +"This software is provided 'as-is', without any express or implied warranty.\n" +"In no event will the authors be held liable for any damages arising from the use of this software.\n" +"Permission is granted to anyone to use this software for any purpose,\n" +"including commercial applications, and to alter it and redistribute it freely,\n" +"subject to the following restrictions:\n" +"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.\n" +"2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n" +"3. This notice may not be removed or altered from any source distribution.\n" +"*/\n" +"#ifndef B3_INT2_H\n" +"#define B3_INT2_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#define b3UnsignedInt2 uint2\n" +"#define b3Int2 int2\n" +"#define b3MakeInt2 (int2)\n" +"#endif //__cplusplus\n" +"#endif\n" +"typedef struct\n" +"{\n" +" float4 m_plane;\n" +" int m_indexOffset;\n" +" int m_numIndices;\n" +"} btGpuFace;\n" +"#define make_float4 (float4)\n" +"__inline\n" +"float4 cross3(float4 a, float4 b)\n" +"{\n" +" return cross(a,b);\n" +" \n" +"// float4 a1 = make_float4(a.xyz,0.f);\n" +"// float4 b1 = make_float4(b.xyz,0.f);\n" +"// return cross(a1,b1);\n" +"//float4 c = make_float4(a.y*b.z - a.z*b.y,a.z*b.x - a.x*b.z,a.x*b.y - a.y*b.x,0.f);\n" +" \n" +" // float4 c = make_float4(a.y*b.z - a.z*b.y,1.f,a.x*b.y - a.y*b.x,0.f);\n" +" \n" +" //return c;\n" +"}\n" +"__inline\n" +"float dot3F4(float4 a, float4 b)\n" +"{\n" +" float4 a1 = make_float4(a.xyz,0.f);\n" +" float4 b1 = make_float4(b.xyz,0.f);\n" +" return dot(a1, b1);\n" +"}\n" +"__inline\n" +"float4 fastNormalize4(float4 v)\n" +"{\n" +" v = make_float4(v.xyz,0.f);\n" +" return fast_normalize(v);\n" +"}\n" +"///////////////////////////////////////\n" +"// Quaternion\n" +"///////////////////////////////////////\n" +"typedef float4 Quaternion;\n" +"__inline\n" +"Quaternion qtMul(Quaternion a, Quaternion b);\n" +"__inline\n" +"Quaternion qtNormalize(Quaternion in);\n" +"__inline\n" +"float4 qtRotate(Quaternion q, float4 vec);\n" +"__inline\n" +"Quaternion qtInvert(Quaternion q);\n" +"__inline\n" +"Quaternion qtMul(Quaternion a, Quaternion b)\n" +"{\n" +" Quaternion ans;\n" +" ans = cross3( a, b );\n" +" ans += a.w*b+b.w*a;\n" +"// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z);\n" +" ans.w = a.w*b.w - dot3F4(a, b);\n" +" return ans;\n" +"}\n" +"__inline\n" +"Quaternion qtNormalize(Quaternion in)\n" +"{\n" +" return fastNormalize4(in);\n" +"// in /= length( in );\n" +"// return in;\n" +"}\n" +"__inline\n" +"float4 qtRotate(Quaternion q, float4 vec)\n" +"{\n" +" Quaternion qInv = qtInvert( q );\n" +" float4 vcpy = vec;\n" +" vcpy.w = 0.f;\n" +" float4 out = qtMul(qtMul(q,vcpy),qInv);\n" +" return out;\n" +"}\n" +"__inline\n" +"Quaternion qtInvert(Quaternion q)\n" +"{\n" +" return (Quaternion)(-q.xyz, q.w);\n" +"}\n" +"__inline\n" +"float4 qtInvRotate(const Quaternion q, float4 vec)\n" +"{\n" +" return qtRotate( qtInvert( q ), vec );\n" +"}\n" +"__inline\n" +"float4 transform(const float4* p, const float4* translation, const Quaternion* orientation)\n" +"{\n" +" return qtRotate( *orientation, *p ) + (*translation);\n" +"}\n" +"__inline\n" +"float4 normalize3(const float4 a)\n" +"{\n" +" float4 n = make_float4(a.x, a.y, a.z, 0.f);\n" +" return fastNormalize4( n );\n" +"}\n" +"inline void projectLocal(const ConvexPolyhedronCL* hull, const float4 pos, const float4 orn, \n" +"const float4* dir, const float4* vertices, float* min, float* max)\n" +"{\n" +" min[0] = FLT_MAX;\n" +" max[0] = -FLT_MAX;\n" +" int numVerts = hull->m_numVertices;\n" +" const float4 localDir = qtInvRotate(orn,*dir);\n" +" float offset = dot(pos,*dir);\n" +" for(int i=0;im_vertexOffset+i],localDir);\n" +" if(dp < min[0]) \n" +" min[0] = dp;\n" +" if(dp > max[0]) \n" +" max[0] = dp;\n" +" }\n" +" if(min[0]>max[0])\n" +" {\n" +" float tmp = min[0];\n" +" min[0] = max[0];\n" +" max[0] = tmp;\n" +" }\n" +" min[0] += offset;\n" +" max[0] += offset;\n" +"}\n" +"inline void project(__global const ConvexPolyhedronCL* hull, const float4 pos, const float4 orn, \n" +"const float4* dir, __global const float4* vertices, float* min, float* max)\n" +"{\n" +" min[0] = FLT_MAX;\n" +" max[0] = -FLT_MAX;\n" +" int numVerts = hull->m_numVertices;\n" +" const float4 localDir = qtInvRotate(orn,*dir);\n" +" float offset = dot(pos,*dir);\n" +" for(int i=0;im_vertexOffset+i],localDir);\n" +" if(dp < min[0]) \n" +" min[0] = dp;\n" +" if(dp > max[0]) \n" +" max[0] = dp;\n" +" }\n" +" if(min[0]>max[0])\n" +" {\n" +" float tmp = min[0];\n" +" min[0] = max[0];\n" +" max[0] = tmp;\n" +" }\n" +" min[0] += offset;\n" +" max[0] += offset;\n" +"}\n" +"inline bool TestSepAxisLocalA(const ConvexPolyhedronCL* hullA, __global const ConvexPolyhedronCL* hullB, \n" +" const float4 posA,const float4 ornA,\n" +" const float4 posB,const float4 ornB,\n" +" float4* sep_axis, const float4* verticesA, __global const float4* verticesB,float* depth)\n" +"{\n" +" float Min0,Max0;\n" +" float Min1,Max1;\n" +" projectLocal(hullA,posA,ornA,sep_axis,verticesA, &Min0, &Max0);\n" +" project(hullB,posB,ornB, sep_axis,verticesB, &Min1, &Max1);\n" +" if(Max01e-6f || fabs(v.y)>1e-6f || fabs(v.z)>1e-6f)\n" +" return false;\n" +" return true;\n" +"}\n" +"bool findSeparatingAxisLocalA( const ConvexPolyhedronCL* hullA, __global const ConvexPolyhedronCL* hullB, \n" +" const float4 posA1,\n" +" const float4 ornA,\n" +" const float4 posB1,\n" +" const float4 ornB,\n" +" const float4 DeltaC2,\n" +" \n" +" const float4* verticesA, \n" +" const float4* uniqueEdgesA, \n" +" const btGpuFace* facesA,\n" +" const int* indicesA,\n" +" __global const float4* verticesB, \n" +" __global const float4* uniqueEdgesB, \n" +" __global const btGpuFace* facesB,\n" +" __global const int* indicesB,\n" +" float4* sep,\n" +" float* dmin)\n" +"{\n" +" \n" +" float4 posA = posA1;\n" +" posA.w = 0.f;\n" +" float4 posB = posB1;\n" +" posB.w = 0.f;\n" +" int curPlaneTests=0;\n" +" {\n" +" int numFacesA = hullA->m_numFaces;\n" +" // Test normals from hullA\n" +" for(int i=0;im_faceOffset+i].m_plane;\n" +" float4 faceANormalWS = qtRotate(ornA,normal);\n" +" if (dot3F4(DeltaC2,faceANormalWS)<0)\n" +" faceANormalWS*=-1.f;\n" +" curPlaneTests++;\n" +" float d;\n" +" if(!TestSepAxisLocalA( hullA, hullB, posA,ornA,posB,ornB,&faceANormalWS, verticesA, verticesB,&d))\n" +" return false;\n" +" if(d<*dmin)\n" +" {\n" +" *dmin = d;\n" +" *sep = faceANormalWS;\n" +" }\n" +" }\n" +" }\n" +" if((dot3F4(-DeltaC2,*sep))>0.0f)\n" +" {\n" +" *sep = -(*sep);\n" +" }\n" +" return true;\n" +"}\n" +"bool findSeparatingAxisLocalB( __global const ConvexPolyhedronCL* hullA, const ConvexPolyhedronCL* hullB, \n" +" const float4 posA1,\n" +" const float4 ornA,\n" +" const float4 posB1,\n" +" const float4 ornB,\n" +" const float4 DeltaC2,\n" +" __global const float4* verticesA, \n" +" __global const float4* uniqueEdgesA, \n" +" __global const btGpuFace* facesA,\n" +" __global const int* indicesA,\n" +" const float4* verticesB,\n" +" const float4* uniqueEdgesB, \n" +" const btGpuFace* facesB,\n" +" const int* indicesB,\n" +" float4* sep,\n" +" float* dmin)\n" +"{\n" +" float4 posA = posA1;\n" +" posA.w = 0.f;\n" +" float4 posB = posB1;\n" +" posB.w = 0.f;\n" +" int curPlaneTests=0;\n" +" {\n" +" int numFacesA = hullA->m_numFaces;\n" +" // Test normals from hullA\n" +" for(int i=0;im_faceOffset+i].m_plane;\n" +" float4 faceANormalWS = qtRotate(ornA,normal);\n" +" if (dot3F4(DeltaC2,faceANormalWS)<0)\n" +" faceANormalWS *= -1.f;\n" +" curPlaneTests++;\n" +" float d;\n" +" if(!TestSepAxisLocalA( hullB, hullA, posB,ornB,posA,ornA, &faceANormalWS, verticesB,verticesA, &d))\n" +" return false;\n" +" if(d<*dmin)\n" +" {\n" +" *dmin = d;\n" +" *sep = faceANormalWS;\n" +" }\n" +" }\n" +" }\n" +" if((dot3F4(-DeltaC2,*sep))>0.0f)\n" +" {\n" +" *sep = -(*sep);\n" +" }\n" +" return true;\n" +"}\n" +"bool findSeparatingAxisEdgeEdgeLocalA( const ConvexPolyhedronCL* hullA, __global const ConvexPolyhedronCL* hullB, \n" +" const float4 posA1,\n" +" const float4 ornA,\n" +" const float4 posB1,\n" +" const float4 ornB,\n" +" const float4 DeltaC2,\n" +" const float4* verticesA, \n" +" const float4* uniqueEdgesA, \n" +" const btGpuFace* facesA,\n" +" const int* indicesA,\n" +" __global const float4* verticesB, \n" +" __global const float4* uniqueEdgesB, \n" +" __global const btGpuFace* facesB,\n" +" __global const int* indicesB,\n" +" float4* sep,\n" +" float* dmin)\n" +"{\n" +" float4 posA = posA1;\n" +" posA.w = 0.f;\n" +" float4 posB = posB1;\n" +" posB.w = 0.f;\n" +" int curPlaneTests=0;\n" +" int curEdgeEdge = 0;\n" +" // Test edges\n" +" for(int e0=0;e0m_numUniqueEdges;e0++)\n" +" {\n" +" const float4 edge0 = uniqueEdgesA[hullA->m_uniqueEdgesOffset+e0];\n" +" float4 edge0World = qtRotate(ornA,edge0);\n" +" for(int e1=0;e1m_numUniqueEdges;e1++)\n" +" {\n" +" const float4 edge1 = uniqueEdgesB[hullB->m_uniqueEdgesOffset+e1];\n" +" float4 edge1World = qtRotate(ornB,edge1);\n" +" float4 crossje = cross3(edge0World,edge1World);\n" +" curEdgeEdge++;\n" +" if(!IsAlmostZero(crossje))\n" +" {\n" +" crossje = normalize3(crossje);\n" +" if (dot3F4(DeltaC2,crossje)<0)\n" +" crossje *= -1.f;\n" +" float dist;\n" +" bool result = true;\n" +" {\n" +" float Min0,Max0;\n" +" float Min1,Max1;\n" +" projectLocal(hullA,posA,ornA,&crossje,verticesA, &Min0, &Max0);\n" +" project(hullB,posB,ornB,&crossje,verticesB, &Min1, &Max1);\n" +" \n" +" if(Max00.0f)\n" +" {\n" +" *sep = -(*sep);\n" +" }\n" +" return true;\n" +"}\n" +"inline int findClippingFaces(const float4 separatingNormal,\n" +" const ConvexPolyhedronCL* hullA, \n" +" __global const ConvexPolyhedronCL* hullB,\n" +" const float4 posA, const Quaternion ornA,const float4 posB, const Quaternion ornB,\n" +" __global float4* worldVertsA1,\n" +" __global float4* worldNormalsA1,\n" +" __global float4* worldVertsB1,\n" +" int capacityWorldVerts,\n" +" const float minDist, float maxDist,\n" +" const float4* verticesA,\n" +" const btGpuFace* facesA,\n" +" const int* indicesA,\n" +" __global const float4* verticesB,\n" +" __global const btGpuFace* facesB,\n" +" __global const int* indicesB,\n" +" __global int4* clippingFaces, int pairIndex)\n" +"{\n" +" int numContactsOut = 0;\n" +" int numWorldVertsB1= 0;\n" +" \n" +" \n" +" int closestFaceB=0;\n" +" float dmax = -FLT_MAX;\n" +" \n" +" {\n" +" for(int face=0;facem_numFaces;face++)\n" +" {\n" +" const float4 Normal = make_float4(facesB[hullB->m_faceOffset+face].m_plane.x,\n" +" facesB[hullB->m_faceOffset+face].m_plane.y, facesB[hullB->m_faceOffset+face].m_plane.z,0.f);\n" +" const float4 WorldNormal = qtRotate(ornB, Normal);\n" +" float d = dot3F4(WorldNormal,separatingNormal);\n" +" if (d > dmax)\n" +" {\n" +" dmax = d;\n" +" closestFaceB = face;\n" +" }\n" +" }\n" +" }\n" +" \n" +" {\n" +" const btGpuFace polyB = facesB[hullB->m_faceOffset+closestFaceB];\n" +" int numVertices = polyB.m_numIndices;\n" +" if (numVertices>capacityWorldVerts)\n" +" numVertices = capacityWorldVerts;\n" +" if (numVertices<0)\n" +" numVertices = 0;\n" +" \n" +" for(int e0=0;e0m_vertexOffset+indicesB[polyB.m_indexOffset+e0]];\n" +" worldVertsB1[pairIndex*capacityWorldVerts+numWorldVertsB1++] = transform(&b,&posB,&ornB);\n" +" }\n" +" }\n" +" }\n" +" \n" +" int closestFaceA=0;\n" +" {\n" +" float dmin = FLT_MAX;\n" +" for(int face=0;facem_numFaces;face++)\n" +" {\n" +" const float4 Normal = make_float4(\n" +" facesA[hullA->m_faceOffset+face].m_plane.x,\n" +" facesA[hullA->m_faceOffset+face].m_plane.y,\n" +" facesA[hullA->m_faceOffset+face].m_plane.z,\n" +" 0.f);\n" +" const float4 faceANormalWS = qtRotate(ornA,Normal);\n" +" \n" +" float d = dot3F4(faceANormalWS,separatingNormal);\n" +" if (d < dmin)\n" +" {\n" +" dmin = d;\n" +" closestFaceA = face;\n" +" worldNormalsA1[pairIndex] = faceANormalWS;\n" +" }\n" +" }\n" +" }\n" +" \n" +" int numVerticesA = facesA[hullA->m_faceOffset+closestFaceA].m_numIndices;\n" +" if (numVerticesA>capacityWorldVerts)\n" +" numVerticesA = capacityWorldVerts;\n" +" if (numVerticesA<0)\n" +" numVerticesA=0;\n" +" \n" +" for(int e0=0;e0m_vertexOffset+indicesA[facesA[hullA->m_faceOffset+closestFaceA].m_indexOffset+e0]];\n" +" worldVertsA1[pairIndex*capacityWorldVerts+e0] = transform(&a, &posA,&ornA);\n" +" }\n" +" }\n" +" \n" +" clippingFaces[pairIndex].x = closestFaceA;\n" +" clippingFaces[pairIndex].y = closestFaceB;\n" +" clippingFaces[pairIndex].z = numVerticesA;\n" +" clippingFaces[pairIndex].w = numWorldVertsB1;\n" +" \n" +" \n" +" return numContactsOut;\n" +"}\n" +"// work-in-progress\n" +"__kernel void findConcaveSeparatingAxisVertexFaceKernel( __global int4* concavePairs,\n" +" __global const BodyData* rigidBodies,\n" +" __global const btCollidableGpu* collidables,\n" +" __global const ConvexPolyhedronCL* convexShapes,\n" +" __global const float4* vertices,\n" +" __global const float4* uniqueEdges,\n" +" __global const btGpuFace* faces,\n" +" __global const int* indices,\n" +" __global const btGpuChildShape* gpuChildShapes,\n" +" __global btAabbCL* aabbs,\n" +" __global float4* concaveSeparatingNormalsOut,\n" +" __global int* concaveHasSeparatingNormals,\n" +" __global int4* clippingFacesOut,\n" +" __global float4* worldVertsA1GPU,\n" +" __global float4* worldNormalsAGPU,\n" +" __global float4* worldVertsB1GPU,\n" +" __global float* dmins,\n" +" int vertexFaceCapacity,\n" +" int numConcavePairs\n" +" )\n" +"{\n" +" \n" +" int i = get_global_id(0);\n" +" if (i>=numConcavePairs)\n" +" return;\n" +" \n" +" concaveHasSeparatingNormals[i] = 0;\n" +" \n" +" int pairIdx = i;\n" +" \n" +" int bodyIndexA = concavePairs[i].x;\n" +" int bodyIndexB = concavePairs[i].y;\n" +" \n" +" int collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx;\n" +" int collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx;\n" +" \n" +" int shapeIndexA = collidables[collidableIndexA].m_shapeIndex;\n" +" int shapeIndexB = collidables[collidableIndexB].m_shapeIndex;\n" +" \n" +" if (collidables[collidableIndexB].m_shapeType!=SHAPE_CONVEX_HULL&&\n" +" collidables[collidableIndexB].m_shapeType!=SHAPE_COMPOUND_OF_CONVEX_HULLS)\n" +" {\n" +" concavePairs[pairIdx].w = -1;\n" +" return;\n" +" }\n" +" \n" +" \n" +" \n" +" int numFacesA = convexShapes[shapeIndexA].m_numFaces;\n" +" int numActualConcaveConvexTests = 0;\n" +" \n" +" int f = concavePairs[i].z;\n" +" \n" +" bool overlap = false;\n" +" \n" +" ConvexPolyhedronCL convexPolyhedronA;\n" +" \n" +" //add 3 vertices of the triangle\n" +" convexPolyhedronA.m_numVertices = 3;\n" +" convexPolyhedronA.m_vertexOffset = 0;\n" +" float4 localCenter = make_float4(0.f,0.f,0.f,0.f);\n" +" \n" +" btGpuFace face = faces[convexShapes[shapeIndexA].m_faceOffset+f];\n" +" float4 triMinAabb, triMaxAabb;\n" +" btAabbCL triAabb;\n" +" triAabb.m_min = make_float4(1e30f,1e30f,1e30f,0.f);\n" +" triAabb.m_max = make_float4(-1e30f,-1e30f,-1e30f,0.f);\n" +" \n" +" float4 verticesA[3];\n" +" for (int i=0;i<3;i++)\n" +" {\n" +" int index = indices[face.m_indexOffset+i];\n" +" float4 vert = vertices[convexShapes[shapeIndexA].m_vertexOffset+index];\n" +" verticesA[i] = vert;\n" +" localCenter += vert;\n" +" \n" +" triAabb.m_min = min(triAabb.m_min,vert);\n" +" triAabb.m_max = max(triAabb.m_max,vert);\n" +" \n" +" }\n" +" \n" +" overlap = true;\n" +" overlap = (triAabb.m_min.x > aabbs[bodyIndexB].m_max.x || triAabb.m_max.x < aabbs[bodyIndexB].m_min.x) ? false : overlap;\n" +" overlap = (triAabb.m_min.z > aabbs[bodyIndexB].m_max.z || triAabb.m_max.z < aabbs[bodyIndexB].m_min.z) ? false : overlap;\n" +" overlap = (triAabb.m_min.y > aabbs[bodyIndexB].m_max.y || triAabb.m_max.y < aabbs[bodyIndexB].m_min.y) ? false : overlap;\n" +" \n" +" if (overlap)\n" +" {\n" +" float dmin = FLT_MAX;\n" +" int hasSeparatingAxis=5;\n" +" float4 sepAxis=make_float4(1,2,3,4);\n" +" \n" +" int localCC=0;\n" +" numActualConcaveConvexTests++;\n" +" \n" +" //a triangle has 3 unique edges\n" +" convexPolyhedronA.m_numUniqueEdges = 3;\n" +" convexPolyhedronA.m_uniqueEdgesOffset = 0;\n" +" float4 uniqueEdgesA[3];\n" +" \n" +" uniqueEdgesA[0] = (verticesA[1]-verticesA[0]);\n" +" uniqueEdgesA[1] = (verticesA[2]-verticesA[1]);\n" +" uniqueEdgesA[2] = (verticesA[0]-verticesA[2]);\n" +" \n" +" \n" +" convexPolyhedronA.m_faceOffset = 0;\n" +" \n" +" float4 normal = make_float4(face.m_plane.x,face.m_plane.y,face.m_plane.z,0.f);\n" +" \n" +" btGpuFace facesA[TRIANGLE_NUM_CONVEX_FACES];\n" +" int indicesA[3+3+2+2+2];\n" +" int curUsedIndices=0;\n" +" int fidx=0;\n" +" \n" +" //front size of triangle\n" +" {\n" +" facesA[fidx].m_indexOffset=curUsedIndices;\n" +" indicesA[0] = 0;\n" +" indicesA[1] = 1;\n" +" indicesA[2] = 2;\n" +" curUsedIndices+=3;\n" +" float c = face.m_plane.w;\n" +" facesA[fidx].m_plane.x = normal.x;\n" +" facesA[fidx].m_plane.y = normal.y;\n" +" facesA[fidx].m_plane.z = normal.z;\n" +" facesA[fidx].m_plane.w = c;\n" +" facesA[fidx].m_numIndices=3;\n" +" }\n" +" fidx++;\n" +" //back size of triangle\n" +" {\n" +" facesA[fidx].m_indexOffset=curUsedIndices;\n" +" indicesA[3]=2;\n" +" indicesA[4]=1;\n" +" indicesA[5]=0;\n" +" curUsedIndices+=3;\n" +" float c = dot(normal,verticesA[0]);\n" +" float c1 = -face.m_plane.w;\n" +" facesA[fidx].m_plane.x = -normal.x;\n" +" facesA[fidx].m_plane.y = -normal.y;\n" +" facesA[fidx].m_plane.z = -normal.z;\n" +" facesA[fidx].m_plane.w = c;\n" +" facesA[fidx].m_numIndices=3;\n" +" }\n" +" fidx++;\n" +" \n" +" bool addEdgePlanes = true;\n" +" if (addEdgePlanes)\n" +" {\n" +" int numVertices=3;\n" +" int prevVertex = numVertices-1;\n" +" for (int i=0;i=numConcavePairs)\n" +" return;\n" +" \n" +" if (!concaveHasSeparatingNormals[i])\n" +" return;\n" +" \n" +" int pairIdx = i;\n" +" \n" +" int bodyIndexA = concavePairs[i].x;\n" +" int bodyIndexB = concavePairs[i].y;\n" +" \n" +" int collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx;\n" +" int collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx;\n" +" \n" +" int shapeIndexA = collidables[collidableIndexA].m_shapeIndex;\n" +" int shapeIndexB = collidables[collidableIndexB].m_shapeIndex;\n" +" \n" +" \n" +" int numFacesA = convexShapes[shapeIndexA].m_numFaces;\n" +" int numActualConcaveConvexTests = 0;\n" +" \n" +" int f = concavePairs[i].z;\n" +" \n" +" bool overlap = false;\n" +" \n" +" ConvexPolyhedronCL convexPolyhedronA;\n" +" \n" +" //add 3 vertices of the triangle\n" +" convexPolyhedronA.m_numVertices = 3;\n" +" convexPolyhedronA.m_vertexOffset = 0;\n" +" float4 localCenter = make_float4(0.f,0.f,0.f,0.f);\n" +" \n" +" btGpuFace face = faces[convexShapes[shapeIndexA].m_faceOffset+f];\n" +" float4 triMinAabb, triMaxAabb;\n" +" btAabbCL triAabb;\n" +" triAabb.m_min = make_float4(1e30f,1e30f,1e30f,0.f);\n" +" triAabb.m_max = make_float4(-1e30f,-1e30f,-1e30f,0.f);\n" +" \n" +" float4 verticesA[3];\n" +" for (int i=0;i<3;i++)\n" +" {\n" +" int index = indices[face.m_indexOffset+i];\n" +" float4 vert = vertices[convexShapes[shapeIndexA].m_vertexOffset+index];\n" +" verticesA[i] = vert;\n" +" localCenter += vert;\n" +" \n" +" triAabb.m_min = min(triAabb.m_min,vert);\n" +" triAabb.m_max = max(triAabb.m_max,vert);\n" +" \n" +" }\n" +" \n" +" overlap = true;\n" +" overlap = (triAabb.m_min.x > aabbs[bodyIndexB].m_max.x || triAabb.m_max.x < aabbs[bodyIndexB].m_min.x) ? false : overlap;\n" +" overlap = (triAabb.m_min.z > aabbs[bodyIndexB].m_max.z || triAabb.m_max.z < aabbs[bodyIndexB].m_min.z) ? false : overlap;\n" +" overlap = (triAabb.m_min.y > aabbs[bodyIndexB].m_max.y || triAabb.m_max.y < aabbs[bodyIndexB].m_min.y) ? false : overlap;\n" +" \n" +" if (overlap)\n" +" {\n" +" float dmin = dmins[i];\n" +" int hasSeparatingAxis=5;\n" +" float4 sepAxis=make_float4(1,2,3,4);\n" +" sepAxis = concaveSeparatingNormalsOut[pairIdx];\n" +" \n" +" int localCC=0;\n" +" numActualConcaveConvexTests++;\n" +" \n" +" //a triangle has 3 unique edges\n" +" convexPolyhedronA.m_numUniqueEdges = 3;\n" +" convexPolyhedronA.m_uniqueEdgesOffset = 0;\n" +" float4 uniqueEdgesA[3];\n" +" \n" +" uniqueEdgesA[0] = (verticesA[1]-verticesA[0]);\n" +" uniqueEdgesA[1] = (verticesA[2]-verticesA[1]);\n" +" uniqueEdgesA[2] = (verticesA[0]-verticesA[2]);\n" +" \n" +" \n" +" convexPolyhedronA.m_faceOffset = 0;\n" +" \n" +" float4 normal = make_float4(face.m_plane.x,face.m_plane.y,face.m_plane.z,0.f);\n" +" \n" +" btGpuFace facesA[TRIANGLE_NUM_CONVEX_FACES];\n" +" int indicesA[3+3+2+2+2];\n" +" int curUsedIndices=0;\n" +" int fidx=0;\n" +" \n" +" //front size of triangle\n" +" {\n" +" facesA[fidx].m_indexOffset=curUsedIndices;\n" +" indicesA[0] = 0;\n" +" indicesA[1] = 1;\n" +" indicesA[2] = 2;\n" +" curUsedIndices+=3;\n" +" float c = face.m_plane.w;\n" +" facesA[fidx].m_plane.x = normal.x;\n" +" facesA[fidx].m_plane.y = normal.y;\n" +" facesA[fidx].m_plane.z = normal.z;\n" +" facesA[fidx].m_plane.w = c;\n" +" facesA[fidx].m_numIndices=3;\n" +" }\n" +" fidx++;\n" +" //back size of triangle\n" +" {\n" +" facesA[fidx].m_indexOffset=curUsedIndices;\n" +" indicesA[3]=2;\n" +" indicesA[4]=1;\n" +" indicesA[5]=0;\n" +" curUsedIndices+=3;\n" +" float c = dot(normal,verticesA[0]);\n" +" float c1 = -face.m_plane.w;\n" +" facesA[fidx].m_plane.x = -normal.x;\n" +" facesA[fidx].m_plane.y = -normal.y;\n" +" facesA[fidx].m_plane.z = -normal.z;\n" +" facesA[fidx].m_plane.w = c;\n" +" facesA[fidx].m_numIndices=3;\n" +" }\n" +" fidx++;\n" +" \n" +" bool addEdgePlanes = true;\n" +" if (addEdgePlanes)\n" +" {\n" +" int numVertices=3;\n" +" int prevVertex = numVertices-1;\n" +" for (int i=0;im_escapeIndexOrTriangleIndex&~(y));\n" +"}\n" +"int getTriangleIndexGlobal(__global const b3QuantizedBvhNode* rootNode)\n" +"{\n" +" unsigned int x=0;\n" +" unsigned int y = (~(x&0))<<(31-MAX_NUM_PARTS_IN_BITS);\n" +" // Get only the lower bits where the triangle index is stored\n" +" return (rootNode->m_escapeIndexOrTriangleIndex&~(y));\n" +"}\n" +"int isLeafNode(const b3QuantizedBvhNode* rootNode)\n" +"{\n" +" //skipindex is negative (internal node), triangleindex >=0 (leafnode)\n" +" return (rootNode->m_escapeIndexOrTriangleIndex >= 0)? 1 : 0;\n" +"}\n" +"int isLeafNodeGlobal(__global const b3QuantizedBvhNode* rootNode)\n" +"{\n" +" //skipindex is negative (internal node), triangleindex >=0 (leafnode)\n" +" return (rootNode->m_escapeIndexOrTriangleIndex >= 0)? 1 : 0;\n" +"}\n" +" \n" +"int getEscapeIndex(const b3QuantizedBvhNode* rootNode)\n" +"{\n" +" return -rootNode->m_escapeIndexOrTriangleIndex;\n" +"}\n" +"int getEscapeIndexGlobal(__global const b3QuantizedBvhNode* rootNode)\n" +"{\n" +" return -rootNode->m_escapeIndexOrTriangleIndex;\n" +"}\n" +"typedef struct\n" +"{\n" +" //12 bytes\n" +" unsigned short int m_quantizedAabbMin[3];\n" +" unsigned short int m_quantizedAabbMax[3];\n" +" //4 bytes, points to the root of the subtree\n" +" int m_rootNodeIndex;\n" +" //4 bytes\n" +" int m_subtreeSize;\n" +" int m_padding[3];\n" +"} b3BvhSubtreeInfo;\n" +"typedef struct\n" +"{\n" +" float4 m_childPosition;\n" +" float4 m_childOrientation;\n" +" int m_shapeIndex;\n" +" int m_unused0;\n" +" int m_unused1;\n" +" int m_unused2;\n" +"} btGpuChildShape;\n" +"typedef struct\n" +"{\n" +" float4 m_pos;\n" +" float4 m_quat;\n" +" float4 m_linVel;\n" +" float4 m_angVel;\n" +" u32 m_collidableIdx;\n" +" float m_invMass;\n" +" float m_restituitionCoeff;\n" +" float m_frictionCoeff;\n" +"} BodyData;\n" +"typedef struct \n" +"{\n" +" float4 m_localCenter;\n" +" float4 m_extents;\n" +" float4 mC;\n" +" float4 mE;\n" +" \n" +" float m_radius;\n" +" int m_faceOffset;\n" +" int m_numFaces;\n" +" int m_numVertices;\n" +" int m_vertexOffset;\n" +" int m_uniqueEdgesOffset;\n" +" int m_numUniqueEdges;\n" +" int m_unused;\n" +"} ConvexPolyhedronCL;\n" +"typedef struct \n" +"{\n" +" union\n" +" {\n" +" float4 m_min;\n" +" float m_minElems[4];\n" +" int m_minIndices[4];\n" +" };\n" +" union\n" +" {\n" +" float4 m_max;\n" +" float m_maxElems[4];\n" +" int m_maxIndices[4];\n" +" };\n" +"} btAabbCL;\n" +"#ifndef B3_AABB_H\n" +"#define B3_AABB_H\n" +"#ifndef B3_FLOAT4_H\n" +"#define B3_FLOAT4_H\n" +"#ifndef B3_PLATFORM_DEFINITIONS_H\n" +"#define B3_PLATFORM_DEFINITIONS_H\n" +"struct MyTest\n" +"{\n" +" int bla;\n" +"};\n" +"#ifdef __cplusplus\n" +"#else\n" +"//keep B3_LARGE_FLOAT*B3_LARGE_FLOAT < FLT_MAX\n" +"#define B3_LARGE_FLOAT 1e18f\n" +"#define B3_INFINITY 1e18f\n" +"#define b3Assert(a)\n" +"#define b3ConstArray(a) __global const a*\n" +"#define b3AtomicInc atomic_inc\n" +"#define b3AtomicAdd atomic_add\n" +"#define b3Fabs fabs\n" +"#define b3Sqrt native_sqrt\n" +"#define b3Sin native_sin\n" +"#define b3Cos native_cos\n" +"#define B3_STATIC\n" +"#endif\n" +"#endif\n" +"#ifdef __cplusplus\n" +"#else\n" +" typedef float4 b3Float4;\n" +" #define b3Float4ConstArg const b3Float4\n" +" #define b3MakeFloat4 (float4)\n" +" float b3Dot3F4(b3Float4ConstArg v0,b3Float4ConstArg v1)\n" +" {\n" +" float4 a1 = b3MakeFloat4(v0.xyz,0.f);\n" +" float4 b1 = b3MakeFloat4(v1.xyz,0.f);\n" +" return dot(a1, b1);\n" +" }\n" +" b3Float4 b3Cross3(b3Float4ConstArg v0,b3Float4ConstArg v1)\n" +" {\n" +" float4 a1 = b3MakeFloat4(v0.xyz,0.f);\n" +" float4 b1 = b3MakeFloat4(v1.xyz,0.f);\n" +" return cross(a1, b1);\n" +" }\n" +" #define b3MinFloat4 min\n" +" #define b3MaxFloat4 max\n" +" #define b3Normalized(a) normalize(a)\n" +"#endif \n" +" \n" +"inline bool b3IsAlmostZero(b3Float4ConstArg v)\n" +"{\n" +" if(b3Fabs(v.x)>1e-6 || b3Fabs(v.y)>1e-6 || b3Fabs(v.z)>1e-6) \n" +" return false;\n" +" return true;\n" +"}\n" +"inline int b3MaxDot( b3Float4ConstArg vec, __global const b3Float4* vecArray, int vecLen, float* dotOut )\n" +"{\n" +" float maxDot = -B3_INFINITY;\n" +" int i = 0;\n" +" int ptIndex = -1;\n" +" for( i = 0; i < vecLen; i++ )\n" +" {\n" +" float dot = b3Dot3F4(vecArray[i],vec);\n" +" \n" +" if( dot > maxDot )\n" +" {\n" +" maxDot = dot;\n" +" ptIndex = i;\n" +" }\n" +" }\n" +" b3Assert(ptIndex>=0);\n" +" if (ptIndex<0)\n" +" {\n" +" ptIndex = 0;\n" +" }\n" +" *dotOut = maxDot;\n" +" return ptIndex;\n" +"}\n" +"#endif //B3_FLOAT4_H\n" +"#ifndef B3_MAT3x3_H\n" +"#define B3_MAT3x3_H\n" +"#ifndef B3_QUAT_H\n" +"#define B3_QUAT_H\n" +"#ifndef B3_PLATFORM_DEFINITIONS_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif\n" +"#endif\n" +"#ifndef B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +" typedef float4 b3Quat;\n" +" #define b3QuatConstArg const b3Quat\n" +" \n" +" \n" +"inline float4 b3FastNormalize4(float4 v)\n" +"{\n" +" v = (float4)(v.xyz,0.f);\n" +" return fast_normalize(v);\n" +"}\n" +" \n" +"inline b3Quat b3QuatMul(b3Quat a, b3Quat b);\n" +"inline b3Quat b3QuatNormalized(b3QuatConstArg in);\n" +"inline b3Quat b3QuatRotate(b3QuatConstArg q, b3QuatConstArg vec);\n" +"inline b3Quat b3QuatInvert(b3QuatConstArg q);\n" +"inline b3Quat b3QuatInverse(b3QuatConstArg q);\n" +"inline b3Quat b3QuatMul(b3QuatConstArg a, b3QuatConstArg b)\n" +"{\n" +" b3Quat ans;\n" +" ans = b3Cross3( a, b );\n" +" ans += a.w*b+b.w*a;\n" +"// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z);\n" +" ans.w = a.w*b.w - b3Dot3F4(a, b);\n" +" return ans;\n" +"}\n" +"inline b3Quat b3QuatNormalized(b3QuatConstArg in)\n" +"{\n" +" b3Quat q;\n" +" q=in;\n" +" //return b3FastNormalize4(in);\n" +" float len = native_sqrt(dot(q, q));\n" +" if(len > 0.f)\n" +" {\n" +" q *= 1.f / len;\n" +" }\n" +" else\n" +" {\n" +" q.x = q.y = q.z = 0.f;\n" +" q.w = 1.f;\n" +" }\n" +" return q;\n" +"}\n" +"inline float4 b3QuatRotate(b3QuatConstArg q, b3QuatConstArg vec)\n" +"{\n" +" b3Quat qInv = b3QuatInvert( q );\n" +" float4 vcpy = vec;\n" +" vcpy.w = 0.f;\n" +" float4 out = b3QuatMul(b3QuatMul(q,vcpy),qInv);\n" +" return out;\n" +"}\n" +"inline b3Quat b3QuatInverse(b3QuatConstArg q)\n" +"{\n" +" return (b3Quat)(-q.xyz, q.w);\n" +"}\n" +"inline b3Quat b3QuatInvert(b3QuatConstArg q)\n" +"{\n" +" return (b3Quat)(-q.xyz, q.w);\n" +"}\n" +"inline float4 b3QuatInvRotate(b3QuatConstArg q, b3QuatConstArg vec)\n" +"{\n" +" return b3QuatRotate( b3QuatInvert( q ), vec );\n" +"}\n" +"inline b3Float4 b3TransformPoint(b3Float4ConstArg point, b3Float4ConstArg translation, b3QuatConstArg orientation)\n" +"{\n" +" return b3QuatRotate( orientation, point ) + (translation);\n" +"}\n" +" \n" +"#endif \n" +"#endif //B3_QUAT_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"typedef struct\n" +"{\n" +" b3Float4 m_row[3];\n" +"}b3Mat3x3;\n" +"#define b3Mat3x3ConstArg const b3Mat3x3\n" +"#define b3GetRow(m,row) (m.m_row[row])\n" +"inline b3Mat3x3 b3QuatGetRotationMatrix(b3Quat quat)\n" +"{\n" +" b3Float4 quat2 = (b3Float4)(quat.x*quat.x, quat.y*quat.y, quat.z*quat.z, 0.f);\n" +" b3Mat3x3 out;\n" +" out.m_row[0].x=1-2*quat2.y-2*quat2.z;\n" +" out.m_row[0].y=2*quat.x*quat.y-2*quat.w*quat.z;\n" +" out.m_row[0].z=2*quat.x*quat.z+2*quat.w*quat.y;\n" +" out.m_row[0].w = 0.f;\n" +" out.m_row[1].x=2*quat.x*quat.y+2*quat.w*quat.z;\n" +" out.m_row[1].y=1-2*quat2.x-2*quat2.z;\n" +" out.m_row[1].z=2*quat.y*quat.z-2*quat.w*quat.x;\n" +" out.m_row[1].w = 0.f;\n" +" out.m_row[2].x=2*quat.x*quat.z-2*quat.w*quat.y;\n" +" out.m_row[2].y=2*quat.y*quat.z+2*quat.w*quat.x;\n" +" out.m_row[2].z=1-2*quat2.x-2*quat2.y;\n" +" out.m_row[2].w = 0.f;\n" +" return out;\n" +"}\n" +"inline b3Mat3x3 b3AbsoluteMat3x3(b3Mat3x3ConstArg matIn)\n" +"{\n" +" b3Mat3x3 out;\n" +" out.m_row[0] = fabs(matIn.m_row[0]);\n" +" out.m_row[1] = fabs(matIn.m_row[1]);\n" +" out.m_row[2] = fabs(matIn.m_row[2]);\n" +" return out;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtZero();\n" +"__inline\n" +"b3Mat3x3 mtIdentity();\n" +"__inline\n" +"b3Mat3x3 mtTranspose(b3Mat3x3 m);\n" +"__inline\n" +"b3Mat3x3 mtMul(b3Mat3x3 a, b3Mat3x3 b);\n" +"__inline\n" +"b3Float4 mtMul1(b3Mat3x3 a, b3Float4 b);\n" +"__inline\n" +"b3Float4 mtMul3(b3Float4 a, b3Mat3x3 b);\n" +"__inline\n" +"b3Mat3x3 mtZero()\n" +"{\n" +" b3Mat3x3 m;\n" +" m.m_row[0] = (b3Float4)(0.f);\n" +" m.m_row[1] = (b3Float4)(0.f);\n" +" m.m_row[2] = (b3Float4)(0.f);\n" +" return m;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtIdentity()\n" +"{\n" +" b3Mat3x3 m;\n" +" m.m_row[0] = (b3Float4)(1,0,0,0);\n" +" m.m_row[1] = (b3Float4)(0,1,0,0);\n" +" m.m_row[2] = (b3Float4)(0,0,1,0);\n" +" return m;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtTranspose(b3Mat3x3 m)\n" +"{\n" +" b3Mat3x3 out;\n" +" out.m_row[0] = (b3Float4)(m.m_row[0].x, m.m_row[1].x, m.m_row[2].x, 0.f);\n" +" out.m_row[1] = (b3Float4)(m.m_row[0].y, m.m_row[1].y, m.m_row[2].y, 0.f);\n" +" out.m_row[2] = (b3Float4)(m.m_row[0].z, m.m_row[1].z, m.m_row[2].z, 0.f);\n" +" return out;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtMul(b3Mat3x3 a, b3Mat3x3 b)\n" +"{\n" +" b3Mat3x3 transB;\n" +" transB = mtTranspose( b );\n" +" b3Mat3x3 ans;\n" +" // why this doesn't run when 0ing in the for{}\n" +" a.m_row[0].w = 0.f;\n" +" a.m_row[1].w = 0.f;\n" +" a.m_row[2].w = 0.f;\n" +" for(int i=0; i<3; i++)\n" +" {\n" +"// a.m_row[i].w = 0.f;\n" +" ans.m_row[i].x = b3Dot3F4(a.m_row[i],transB.m_row[0]);\n" +" ans.m_row[i].y = b3Dot3F4(a.m_row[i],transB.m_row[1]);\n" +" ans.m_row[i].z = b3Dot3F4(a.m_row[i],transB.m_row[2]);\n" +" ans.m_row[i].w = 0.f;\n" +" }\n" +" return ans;\n" +"}\n" +"__inline\n" +"b3Float4 mtMul1(b3Mat3x3 a, b3Float4 b)\n" +"{\n" +" b3Float4 ans;\n" +" ans.x = b3Dot3F4( a.m_row[0], b );\n" +" ans.y = b3Dot3F4( a.m_row[1], b );\n" +" ans.z = b3Dot3F4( a.m_row[2], b );\n" +" ans.w = 0.f;\n" +" return ans;\n" +"}\n" +"__inline\n" +"b3Float4 mtMul3(b3Float4 a, b3Mat3x3 b)\n" +"{\n" +" b3Float4 colx = b3MakeFloat4(b.m_row[0].x, b.m_row[1].x, b.m_row[2].x, 0);\n" +" b3Float4 coly = b3MakeFloat4(b.m_row[0].y, b.m_row[1].y, b.m_row[2].y, 0);\n" +" b3Float4 colz = b3MakeFloat4(b.m_row[0].z, b.m_row[1].z, b.m_row[2].z, 0);\n" +" b3Float4 ans;\n" +" ans.x = b3Dot3F4( a, colx );\n" +" ans.y = b3Dot3F4( a, coly );\n" +" ans.z = b3Dot3F4( a, colz );\n" +" return ans;\n" +"}\n" +"#endif\n" +"#endif //B3_MAT3x3_H\n" +"typedef struct b3Aabb b3Aabb_t;\n" +"struct b3Aabb\n" +"{\n" +" union\n" +" {\n" +" float m_min[4];\n" +" b3Float4 m_minVec;\n" +" int m_minIndices[4];\n" +" };\n" +" union\n" +" {\n" +" float m_max[4];\n" +" b3Float4 m_maxVec;\n" +" int m_signedMaxIndices[4];\n" +" };\n" +"};\n" +"inline void b3TransformAabb2(b3Float4ConstArg localAabbMin,b3Float4ConstArg localAabbMax, float margin,\n" +" b3Float4ConstArg pos,\n" +" b3QuatConstArg orn,\n" +" b3Float4* aabbMinOut,b3Float4* aabbMaxOut)\n" +"{\n" +" b3Float4 localHalfExtents = 0.5f*(localAabbMax-localAabbMin);\n" +" localHalfExtents+=b3MakeFloat4(margin,margin,margin,0.f);\n" +" b3Float4 localCenter = 0.5f*(localAabbMax+localAabbMin);\n" +" b3Mat3x3 m;\n" +" m = b3QuatGetRotationMatrix(orn);\n" +" b3Mat3x3 abs_b = b3AbsoluteMat3x3(m);\n" +" b3Float4 center = b3TransformPoint(localCenter,pos,orn);\n" +" \n" +" b3Float4 extent = b3MakeFloat4(b3Dot3F4(localHalfExtents,b3GetRow(abs_b,0)),\n" +" b3Dot3F4(localHalfExtents,b3GetRow(abs_b,1)),\n" +" b3Dot3F4(localHalfExtents,b3GetRow(abs_b,2)),\n" +" 0.f);\n" +" *aabbMinOut = center-extent;\n" +" *aabbMaxOut = center+extent;\n" +"}\n" +"/// conservative test for overlap between two aabbs\n" +"inline bool b3TestAabbAgainstAabb(b3Float4ConstArg aabbMin1,b3Float4ConstArg aabbMax1,\n" +" b3Float4ConstArg aabbMin2, b3Float4ConstArg aabbMax2)\n" +"{\n" +" bool overlap = true;\n" +" overlap = (aabbMin1.x > aabbMax2.x || aabbMax1.x < aabbMin2.x) ? false : overlap;\n" +" overlap = (aabbMin1.z > aabbMax2.z || aabbMax1.z < aabbMin2.z) ? false : overlap;\n" +" overlap = (aabbMin1.y > aabbMax2.y || aabbMax1.y < aabbMin2.y) ? false : overlap;\n" +" return overlap;\n" +"}\n" +"#endif //B3_AABB_H\n" +"/*\n" +"Bullet Continuous Collision Detection and Physics Library\n" +"Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org\n" +"This software is provided 'as-is', without any express or implied warranty.\n" +"In no event will the authors be held liable for any damages arising from the use of this software.\n" +"Permission is granted to anyone to use this software for any purpose,\n" +"including commercial applications, and to alter it and redistribute it freely,\n" +"subject to the following restrictions:\n" +"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.\n" +"2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n" +"3. This notice may not be removed or altered from any source distribution.\n" +"*/\n" +"#ifndef B3_INT2_H\n" +"#define B3_INT2_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#define b3UnsignedInt2 uint2\n" +"#define b3Int2 int2\n" +"#define b3MakeInt2 (int2)\n" +"#endif //__cplusplus\n" +"#endif\n" +"typedef struct\n" +"{\n" +" float4 m_plane;\n" +" int m_indexOffset;\n" +" int m_numIndices;\n" +"} btGpuFace;\n" +"#define make_float4 (float4)\n" +"__inline\n" +"float4 cross3(float4 a, float4 b)\n" +"{\n" +" return cross(a,b);\n" +" \n" +"// float4 a1 = make_float4(a.xyz,0.f);\n" +"// float4 b1 = make_float4(b.xyz,0.f);\n" +"// return cross(a1,b1);\n" +"//float4 c = make_float4(a.y*b.z - a.z*b.y,a.z*b.x - a.x*b.z,a.x*b.y - a.y*b.x,0.f);\n" +" \n" +" // float4 c = make_float4(a.y*b.z - a.z*b.y,1.f,a.x*b.y - a.y*b.x,0.f);\n" +" \n" +" //return c;\n" +"}\n" +"__inline\n" +"float dot3F4(float4 a, float4 b)\n" +"{\n" +" float4 a1 = make_float4(a.xyz,0.f);\n" +" float4 b1 = make_float4(b.xyz,0.f);\n" +" return dot(a1, b1);\n" +"}\n" +"__inline\n" +"float4 fastNormalize4(float4 v)\n" +"{\n" +" v = make_float4(v.xyz,0.f);\n" +" return fast_normalize(v);\n" +"}\n" +"///////////////////////////////////////\n" +"// Quaternion\n" +"///////////////////////////////////////\n" +"typedef float4 Quaternion;\n" +"__inline\n" +"Quaternion qtMul(Quaternion a, Quaternion b);\n" +"__inline\n" +"Quaternion qtNormalize(Quaternion in);\n" +"__inline\n" +"float4 qtRotate(Quaternion q, float4 vec);\n" +"__inline\n" +"Quaternion qtInvert(Quaternion q);\n" +"__inline\n" +"Quaternion qtMul(Quaternion a, Quaternion b)\n" +"{\n" +" Quaternion ans;\n" +" ans = cross3( a, b );\n" +" ans += a.w*b+b.w*a;\n" +"// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z);\n" +" ans.w = a.w*b.w - dot3F4(a, b);\n" +" return ans;\n" +"}\n" +"__inline\n" +"Quaternion qtNormalize(Quaternion in)\n" +"{\n" +" return fastNormalize4(in);\n" +"// in /= length( in );\n" +"// return in;\n" +"}\n" +"__inline\n" +"float4 qtRotate(Quaternion q, float4 vec)\n" +"{\n" +" Quaternion qInv = qtInvert( q );\n" +" float4 vcpy = vec;\n" +" vcpy.w = 0.f;\n" +" float4 out = qtMul(qtMul(q,vcpy),qInv);\n" +" return out;\n" +"}\n" +"__inline\n" +"Quaternion qtInvert(Quaternion q)\n" +"{\n" +" return (Quaternion)(-q.xyz, q.w);\n" +"}\n" +"__inline\n" +"float4 qtInvRotate(const Quaternion q, float4 vec)\n" +"{\n" +" return qtRotate( qtInvert( q ), vec );\n" +"}\n" +"__inline\n" +"float4 transform(const float4* p, const float4* translation, const Quaternion* orientation)\n" +"{\n" +" return qtRotate( *orientation, *p ) + (*translation);\n" +"}\n" +"__inline\n" +"float4 normalize3(const float4 a)\n" +"{\n" +" float4 n = make_float4(a.x, a.y, a.z, 0.f);\n" +" return fastNormalize4( n );\n" +"}\n" +"inline void projectLocal(const ConvexPolyhedronCL* hull, const float4 pos, const float4 orn, \n" +"const float4* dir, const float4* vertices, float* min, float* max)\n" +"{\n" +" min[0] = FLT_MAX;\n" +" max[0] = -FLT_MAX;\n" +" int numVerts = hull->m_numVertices;\n" +" const float4 localDir = qtInvRotate(orn,*dir);\n" +" float offset = dot(pos,*dir);\n" +" for(int i=0;im_vertexOffset+i],localDir);\n" +" if(dp < min[0]) \n" +" min[0] = dp;\n" +" if(dp > max[0]) \n" +" max[0] = dp;\n" +" }\n" +" if(min[0]>max[0])\n" +" {\n" +" float tmp = min[0];\n" +" min[0] = max[0];\n" +" max[0] = tmp;\n" +" }\n" +" min[0] += offset;\n" +" max[0] += offset;\n" +"}\n" +"inline void project(__global const ConvexPolyhedronCL* hull, const float4 pos, const float4 orn, \n" +"const float4* dir, __global const float4* vertices, float* min, float* max)\n" +"{\n" +" min[0] = FLT_MAX;\n" +" max[0] = -FLT_MAX;\n" +" int numVerts = hull->m_numVertices;\n" +" const float4 localDir = qtInvRotate(orn,*dir);\n" +" float offset = dot(pos,*dir);\n" +" for(int i=0;im_vertexOffset+i],localDir);\n" +" if(dp < min[0]) \n" +" min[0] = dp;\n" +" if(dp > max[0]) \n" +" max[0] = dp;\n" +" }\n" +" if(min[0]>max[0])\n" +" {\n" +" float tmp = min[0];\n" +" min[0] = max[0];\n" +" max[0] = tmp;\n" +" }\n" +" min[0] += offset;\n" +" max[0] += offset;\n" +"}\n" +"inline bool TestSepAxisLocalA(const ConvexPolyhedronCL* hullA, __global const ConvexPolyhedronCL* hullB, \n" +" const float4 posA,const float4 ornA,\n" +" const float4 posB,const float4 ornB,\n" +" float4* sep_axis, const float4* verticesA, __global const float4* verticesB,float* depth)\n" +"{\n" +" float Min0,Max0;\n" +" float Min1,Max1;\n" +" projectLocal(hullA,posA,ornA,sep_axis,verticesA, &Min0, &Max0);\n" +" project(hullB,posB,ornB, sep_axis,verticesB, &Min1, &Max1);\n" +" if(Max01e-6f || fabs(v.y)>1e-6f || fabs(v.z)>1e-6f)\n" +" return false;\n" +" return true;\n" +"}\n" +"bool findSeparatingAxisLocalA( const ConvexPolyhedronCL* hullA, __global const ConvexPolyhedronCL* hullB, \n" +" const float4 posA1,\n" +" const float4 ornA,\n" +" const float4 posB1,\n" +" const float4 ornB,\n" +" const float4 DeltaC2,\n" +" \n" +" const float4* verticesA, \n" +" const float4* uniqueEdgesA, \n" +" const btGpuFace* facesA,\n" +" const int* indicesA,\n" +" __global const float4* verticesB, \n" +" __global const float4* uniqueEdgesB, \n" +" __global const btGpuFace* facesB,\n" +" __global const int* indicesB,\n" +" float4* sep,\n" +" float* dmin)\n" +"{\n" +" \n" +" float4 posA = posA1;\n" +" posA.w = 0.f;\n" +" float4 posB = posB1;\n" +" posB.w = 0.f;\n" +" int curPlaneTests=0;\n" +" {\n" +" int numFacesA = hullA->m_numFaces;\n" +" // Test normals from hullA\n" +" for(int i=0;im_faceOffset+i].m_plane;\n" +" float4 faceANormalWS = qtRotate(ornA,normal);\n" +" if (dot3F4(DeltaC2,faceANormalWS)<0)\n" +" faceANormalWS*=-1.f;\n" +" curPlaneTests++;\n" +" float d;\n" +" if(!TestSepAxisLocalA( hullA, hullB, posA,ornA,posB,ornB,&faceANormalWS, verticesA, verticesB,&d))\n" +" return false;\n" +" if(d<*dmin)\n" +" {\n" +" *dmin = d;\n" +" *sep = faceANormalWS;\n" +" }\n" +" }\n" +" }\n" +" if((dot3F4(-DeltaC2,*sep))>0.0f)\n" +" {\n" +" *sep = -(*sep);\n" +" }\n" +" return true;\n" +"}\n" +"bool findSeparatingAxisLocalB( __global const ConvexPolyhedronCL* hullA, const ConvexPolyhedronCL* hullB, \n" +" const float4 posA1,\n" +" const float4 ornA,\n" +" const float4 posB1,\n" +" const float4 ornB,\n" +" const float4 DeltaC2,\n" +" __global const float4* verticesA, \n" +" __global const float4* uniqueEdgesA, \n" +" __global const btGpuFace* facesA,\n" +" __global const int* indicesA,\n" +" const float4* verticesB,\n" +" const float4* uniqueEdgesB, \n" +" const btGpuFace* facesB,\n" +" const int* indicesB,\n" +" float4* sep,\n" +" float* dmin)\n" +"{\n" +" float4 posA = posA1;\n" +" posA.w = 0.f;\n" +" float4 posB = posB1;\n" +" posB.w = 0.f;\n" +" int curPlaneTests=0;\n" +" {\n" +" int numFacesA = hullA->m_numFaces;\n" +" // Test normals from hullA\n" +" for(int i=0;im_faceOffset+i].m_plane;\n" +" float4 faceANormalWS = qtRotate(ornA,normal);\n" +" if (dot3F4(DeltaC2,faceANormalWS)<0)\n" +" faceANormalWS *= -1.f;\n" +" curPlaneTests++;\n" +" float d;\n" +" if(!TestSepAxisLocalA( hullB, hullA, posB,ornB,posA,ornA, &faceANormalWS, verticesB,verticesA, &d))\n" +" return false;\n" +" if(d<*dmin)\n" +" {\n" +" *dmin = d;\n" +" *sep = faceANormalWS;\n" +" }\n" +" }\n" +" }\n" +" if((dot3F4(-DeltaC2,*sep))>0.0f)\n" +" {\n" +" *sep = -(*sep);\n" +" }\n" +" return true;\n" +"}\n" +"bool findSeparatingAxisEdgeEdgeLocalA( const ConvexPolyhedronCL* hullA, __global const ConvexPolyhedronCL* hullB, \n" +" const float4 posA1,\n" +" const float4 ornA,\n" +" const float4 posB1,\n" +" const float4 ornB,\n" +" const float4 DeltaC2,\n" +" const float4* verticesA, \n" +" const float4* uniqueEdgesA, \n" +" const btGpuFace* facesA,\n" +" const int* indicesA,\n" +" __global const float4* verticesB, \n" +" __global const float4* uniqueEdgesB, \n" +" __global const btGpuFace* facesB,\n" +" __global const int* indicesB,\n" +" float4* sep,\n" +" float* dmin)\n" +"{\n" +" float4 posA = posA1;\n" +" posA.w = 0.f;\n" +" float4 posB = posB1;\n" +" posB.w = 0.f;\n" +" int curPlaneTests=0;\n" +" int curEdgeEdge = 0;\n" +" // Test edges\n" +" for(int e0=0;e0m_numUniqueEdges;e0++)\n" +" {\n" +" const float4 edge0 = uniqueEdgesA[hullA->m_uniqueEdgesOffset+e0];\n" +" float4 edge0World = qtRotate(ornA,edge0);\n" +" for(int e1=0;e1m_numUniqueEdges;e1++)\n" +" {\n" +" const float4 edge1 = uniqueEdgesB[hullB->m_uniqueEdgesOffset+e1];\n" +" float4 edge1World = qtRotate(ornB,edge1);\n" +" float4 crossje = cross3(edge0World,edge1World);\n" +" curEdgeEdge++;\n" +" if(!IsAlmostZero(crossje))\n" +" {\n" +" crossje = normalize3(crossje);\n" +" if (dot3F4(DeltaC2,crossje)<0)\n" +" crossje *= -1.f;\n" +" float dist;\n" +" bool result = true;\n" +" {\n" +" float Min0,Max0;\n" +" float Min1,Max1;\n" +" projectLocal(hullA,posA,ornA,&crossje,verticesA, &Min0, &Max0);\n" +" project(hullB,posB,ornB,&crossje,verticesB, &Min1, &Max1);\n" +" \n" +" if(Max00.0f)\n" +" {\n" +" *sep = -(*sep);\n" +" }\n" +" return true;\n" +"}\n" +"inline bool TestSepAxis(__global const ConvexPolyhedronCL* hullA, __global const ConvexPolyhedronCL* hullB, \n" +" const float4 posA,const float4 ornA,\n" +" const float4 posB,const float4 ornB,\n" +" float4* sep_axis, __global const float4* vertices,float* depth)\n" +"{\n" +" float Min0,Max0;\n" +" float Min1,Max1;\n" +" project(hullA,posA,ornA,sep_axis,vertices, &Min0, &Max0);\n" +" project(hullB,posB,ornB, sep_axis,vertices, &Min1, &Max1);\n" +" if(Max0m_numFaces;\n" +" // Test normals from hullA\n" +" for(int i=0;im_faceOffset+i].m_plane;\n" +" float4 faceANormalWS = qtRotate(ornA,normal);\n" +" \n" +" if (dot3F4(DeltaC2,faceANormalWS)<0)\n" +" faceANormalWS*=-1.f;\n" +" \n" +" curPlaneTests++;\n" +" \n" +" float d;\n" +" if(!TestSepAxis( hullA, hullB, posA,ornA,posB,ornB,&faceANormalWS, vertices,&d))\n" +" return false;\n" +" \n" +" if(d<*dmin)\n" +" {\n" +" *dmin = d;\n" +" *sep = faceANormalWS;\n" +" }\n" +" }\n" +" }\n" +" if((dot3F4(-DeltaC2,*sep))>0.0f)\n" +" {\n" +" *sep = -(*sep);\n" +" }\n" +" \n" +" return true;\n" +"}\n" +"bool findSeparatingAxisUnitSphere( __global const ConvexPolyhedronCL* hullA, __global const ConvexPolyhedronCL* hullB, \n" +" const float4 posA1,\n" +" const float4 ornA,\n" +" const float4 posB1,\n" +" const float4 ornB,\n" +" const float4 DeltaC2,\n" +" __global const float4* vertices,\n" +" __global const float4* unitSphereDirections,\n" +" int numUnitSphereDirections,\n" +" float4* sep,\n" +" float* dmin)\n" +"{\n" +" \n" +" float4 posA = posA1;\n" +" posA.w = 0.f;\n" +" float4 posB = posB1;\n" +" posB.w = 0.f;\n" +" int curPlaneTests=0;\n" +" int curEdgeEdge = 0;\n" +" // Test unit sphere directions\n" +" for (int i=0;i0)\n" +" crossje *= -1.f;\n" +" {\n" +" float dist;\n" +" bool result = true;\n" +" float Min0,Max0;\n" +" float Min1,Max1;\n" +" project(hullA,posA,ornA,&crossje,vertices, &Min0, &Max0);\n" +" project(hullB,posB,ornB,&crossje,vertices, &Min1, &Max1);\n" +" \n" +" if(Max00.0f)\n" +" {\n" +" *sep = -(*sep);\n" +" }\n" +" return true;\n" +"}\n" +"bool findSeparatingAxisEdgeEdge( __global const ConvexPolyhedronCL* hullA, __global const ConvexPolyhedronCL* hullB, \n" +" const float4 posA1,\n" +" const float4 ornA,\n" +" const float4 posB1,\n" +" const float4 ornB,\n" +" const float4 DeltaC2,\n" +" __global const float4* vertices, \n" +" __global const float4* uniqueEdges, \n" +" __global const btGpuFace* faces,\n" +" __global const int* indices,\n" +" float4* sep,\n" +" float* dmin)\n" +"{\n" +" \n" +" float4 posA = posA1;\n" +" posA.w = 0.f;\n" +" float4 posB = posB1;\n" +" posB.w = 0.f;\n" +" int curPlaneTests=0;\n" +" int curEdgeEdge = 0;\n" +" // Test edges\n" +" for(int e0=0;e0m_numUniqueEdges;e0++)\n" +" {\n" +" const float4 edge0 = uniqueEdges[hullA->m_uniqueEdgesOffset+e0];\n" +" float4 edge0World = qtRotate(ornA,edge0);\n" +" for(int e1=0;e1m_numUniqueEdges;e1++)\n" +" {\n" +" const float4 edge1 = uniqueEdges[hullB->m_uniqueEdgesOffset+e1];\n" +" float4 edge1World = qtRotate(ornB,edge1);\n" +" float4 crossje = cross3(edge0World,edge1World);\n" +" curEdgeEdge++;\n" +" if(!IsAlmostZero(crossje))\n" +" {\n" +" crossje = normalize3(crossje);\n" +" if (dot3F4(DeltaC2,crossje)<0)\n" +" crossje*=-1.f;\n" +" \n" +" float dist;\n" +" bool result = true;\n" +" {\n" +" float Min0,Max0;\n" +" float Min1,Max1;\n" +" project(hullA,posA,ornA,&crossje,vertices, &Min0, &Max0);\n" +" project(hullB,posB,ornB,&crossje,vertices, &Min1, &Max1);\n" +" \n" +" if(Max00.0f)\n" +" {\n" +" *sep = -(*sep);\n" +" }\n" +" return true;\n" +"}\n" +"// work-in-progress\n" +"__kernel void processCompoundPairsKernel( __global const int4* gpuCompoundPairs,\n" +" __global const BodyData* rigidBodies, \n" +" __global const btCollidableGpu* collidables,\n" +" __global const ConvexPolyhedronCL* convexShapes, \n" +" __global const float4* vertices,\n" +" __global const float4* uniqueEdges,\n" +" __global const btGpuFace* faces,\n" +" __global const int* indices,\n" +" __global btAabbCL* aabbs,\n" +" __global const btGpuChildShape* gpuChildShapes,\n" +" __global volatile float4* gpuCompoundSepNormalsOut,\n" +" __global volatile int* gpuHasCompoundSepNormalsOut,\n" +" int numCompoundPairs\n" +" )\n" +"{\n" +" int i = get_global_id(0);\n" +" if (i= 0)\n" +" {\n" +" collidableIndexA = gpuChildShapes[childShapeIndexA].m_shapeIndex;\n" +" float4 childPosA = gpuChildShapes[childShapeIndexA].m_childPosition;\n" +" float4 childOrnA = gpuChildShapes[childShapeIndexA].m_childOrientation;\n" +" float4 newPosA = qtRotate(ornA,childPosA)+posA;\n" +" float4 newOrnA = qtMul(ornA,childOrnA);\n" +" posA = newPosA;\n" +" ornA = newOrnA;\n" +" } else\n" +" {\n" +" collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx;\n" +" }\n" +" \n" +" if (childShapeIndexB>=0)\n" +" {\n" +" collidableIndexB = gpuChildShapes[childShapeIndexB].m_shapeIndex;\n" +" float4 childPosB = gpuChildShapes[childShapeIndexB].m_childPosition;\n" +" float4 childOrnB = gpuChildShapes[childShapeIndexB].m_childOrientation;\n" +" float4 newPosB = transform(&childPosB,&posB,&ornB);\n" +" float4 newOrnB = qtMul(ornB,childOrnB);\n" +" posB = newPosB;\n" +" ornB = newOrnB;\n" +" } else\n" +" {\n" +" collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx; \n" +" }\n" +" \n" +" gpuHasCompoundSepNormalsOut[i] = 0;\n" +" \n" +" int shapeIndexA = collidables[collidableIndexA].m_shapeIndex;\n" +" int shapeIndexB = collidables[collidableIndexB].m_shapeIndex;\n" +" \n" +" int shapeTypeA = collidables[collidableIndexA].m_shapeType;\n" +" int shapeTypeB = collidables[collidableIndexB].m_shapeType;\n" +" \n" +" if ((shapeTypeA != SHAPE_CONVEX_HULL) || (shapeTypeB != SHAPE_CONVEX_HULL))\n" +" {\n" +" return;\n" +" }\n" +" int hasSeparatingAxis = 5;\n" +" \n" +" int numFacesA = convexShapes[shapeIndexA].m_numFaces;\n" +" float dmin = FLT_MAX;\n" +" posA.w = 0.f;\n" +" posB.w = 0.f;\n" +" float4 c0local = convexShapes[shapeIndexA].m_localCenter;\n" +" float4 c0 = transform(&c0local, &posA, &ornA);\n" +" float4 c1local = convexShapes[shapeIndexB].m_localCenter;\n" +" float4 c1 = transform(&c1local,&posB,&ornB);\n" +" const float4 DeltaC2 = c0 - c1;\n" +" float4 sepNormal = make_float4(1,0,0,0);\n" +" bool sepA = findSeparatingAxis( &convexShapes[shapeIndexA], &convexShapes[shapeIndexB],posA,ornA,posB,ornB,DeltaC2,vertices,uniqueEdges,faces,indices,&sepNormal,&dmin);\n" +" hasSeparatingAxis = 4;\n" +" if (!sepA)\n" +" {\n" +" hasSeparatingAxis = 0;\n" +" } else\n" +" {\n" +" bool sepB = findSeparatingAxis( &convexShapes[shapeIndexB],&convexShapes[shapeIndexA],posB,ornB,posA,ornA,DeltaC2,vertices,uniqueEdges,faces,indices,&sepNormal,&dmin);\n" +" if (!sepB)\n" +" {\n" +" hasSeparatingAxis = 0;\n" +" } else//(!sepB)\n" +" {\n" +" bool sepEE = findSeparatingAxisEdgeEdge( &convexShapes[shapeIndexA], &convexShapes[shapeIndexB],posA,ornA,posB,ornB,DeltaC2,vertices,uniqueEdges,faces,indices,&sepNormal,&dmin);\n" +" if (sepEE)\n" +" {\n" +" gpuCompoundSepNormalsOut[i] = sepNormal;//fastNormalize4(sepNormal);\n" +" gpuHasCompoundSepNormalsOut[i] = 1;\n" +" }//sepEE\n" +" }//(!sepB)\n" +" }//(!sepA)\n" +" \n" +" \n" +" }\n" +" \n" +"}\n" +"inline b3Float4 MyUnQuantize(const unsigned short* vecIn, b3Float4 quantization, b3Float4 bvhAabbMin)\n" +"{\n" +" b3Float4 vecOut;\n" +" vecOut = b3MakeFloat4(\n" +" (float)(vecIn[0]) / (quantization.x),\n" +" (float)(vecIn[1]) / (quantization.y),\n" +" (float)(vecIn[2]) / (quantization.z),\n" +" 0.f);\n" +" vecOut += bvhAabbMin;\n" +" return vecOut;\n" +"}\n" +"inline b3Float4 MyUnQuantizeGlobal(__global const unsigned short* vecIn, b3Float4 quantization, b3Float4 bvhAabbMin)\n" +"{\n" +" b3Float4 vecOut;\n" +" vecOut = b3MakeFloat4(\n" +" (float)(vecIn[0]) / (quantization.x),\n" +" (float)(vecIn[1]) / (quantization.y),\n" +" (float)(vecIn[2]) / (quantization.z),\n" +" 0.f);\n" +" vecOut += bvhAabbMin;\n" +" return vecOut;\n" +"}\n" +"// work-in-progress\n" +"__kernel void findCompoundPairsKernel( __global const int4* pairs, \n" +" __global const BodyData* rigidBodies, \n" +" __global const btCollidableGpu* collidables,\n" +" __global const ConvexPolyhedronCL* convexShapes, \n" +" __global const float4* vertices,\n" +" __global const float4* uniqueEdges,\n" +" __global const btGpuFace* faces,\n" +" __global const int* indices,\n" +" __global b3Aabb_t* aabbLocalSpace,\n" +" __global const btGpuChildShape* gpuChildShapes,\n" +" __global volatile int4* gpuCompoundPairsOut,\n" +" __global volatile int* numCompoundPairsOut,\n" +" __global const b3BvhSubtreeInfo* subtrees,\n" +" __global const b3QuantizedBvhNode* quantizedNodes,\n" +" __global const b3BvhInfo* bvhInfos,\n" +" int numPairs,\n" +" int maxNumCompoundPairsCapacity\n" +" )\n" +"{\n" +" int i = get_global_id(0);\n" +" if (imaxStackDepth && !(isLeafA && isLeafB))\n" +" {\n" +" //printf(\"Error: traversal exceeded maxStackDepth\");\n" +" continue;\n" +" }\n" +" if(isInternalA)\n" +" {\n" +" int nodeAleftChild = node.x+1;\n" +" bool isNodeALeftChildLeaf = isLeafNodeGlobal(&quantizedNodes[node.x+1]);\n" +" int nodeArightChild = isNodeALeftChildLeaf? node.x+2 : node.x+1 + getEscapeIndexGlobal(&quantizedNodes[node.x+1]);\n" +" if(isInternalB)\n" +" { \n" +" int nodeBleftChild = node.y+1;\n" +" bool isNodeBLeftChildLeaf = isLeafNodeGlobal(&quantizedNodes[node.y+1]);\n" +" int nodeBrightChild = isNodeBLeftChildLeaf? node.y+2 : node.y+1 + getEscapeIndexGlobal(&quantizedNodes[node.y+1]);\n" +" nodeStack[depth++] = b3MakeInt2(nodeAleftChild, nodeBleftChild);\n" +" nodeStack[depth++] = b3MakeInt2(nodeArightChild, nodeBleftChild);\n" +" nodeStack[depth++] = b3MakeInt2(nodeAleftChild, nodeBrightChild);\n" +" nodeStack[depth++] = b3MakeInt2(nodeArightChild, nodeBrightChild);\n" +" }\n" +" else\n" +" {\n" +" nodeStack[depth++] = b3MakeInt2(nodeAleftChild,node.y);\n" +" nodeStack[depth++] = b3MakeInt2(nodeArightChild,node.y);\n" +" }\n" +" }\n" +" else\n" +" {\n" +" if(isInternalB)\n" +" {\n" +" int nodeBleftChild = node.y+1;\n" +" bool isNodeBLeftChildLeaf = isLeafNodeGlobal(&quantizedNodes[node.y+1]);\n" +" int nodeBrightChild = isNodeBLeftChildLeaf? node.y+2 : node.y+1 + getEscapeIndexGlobal(&quantizedNodes[node.y+1]);\n" +" nodeStack[depth++] = b3MakeInt2(node.x,nodeBleftChild);\n" +" nodeStack[depth++] = b3MakeInt2(node.x,nodeBrightChild);\n" +" }\n" +" else\n" +" {\n" +" int compoundPairIdx = atomic_inc(numCompoundPairsOut);\n" +" if (compoundPairIdxm_numFaces;face++)\n" +" {\n" +" const float4 Normal = make_float4(facesB[hullB->m_faceOffset+face].m_plane.x,\n" +" facesB[hullB->m_faceOffset+face].m_plane.y, facesB[hullB->m_faceOffset+face].m_plane.z,0.f);\n" +" const float4 WorldNormal = qtRotate(ornB, Normal);\n" +" float d = dot3F4(WorldNormal,separatingNormal);\n" +" if (d > dmax)\n" +" {\n" +" dmax = d;\n" +" closestFaceB = face;\n" +" }\n" +" }\n" +" }\n" +" \n" +" {\n" +" const btGpuFace polyB = facesB[hullB->m_faceOffset+closestFaceB];\n" +" int numVertices = polyB.m_numIndices;\n" +" if (numVertices>capacityWorldVerts)\n" +" numVertices = capacityWorldVerts;\n" +" \n" +" for(int e0=0;e0m_vertexOffset+indicesB[polyB.m_indexOffset+e0]];\n" +" worldVertsB1[pairIndex*capacityWorldVerts+numWorldVertsB1++] = transform(&b,&posB,&ornB);\n" +" }\n" +" }\n" +" }\n" +" \n" +" int closestFaceA=0;\n" +" {\n" +" float dmin = FLT_MAX;\n" +" for(int face=0;facem_numFaces;face++)\n" +" {\n" +" const float4 Normal = make_float4(\n" +" facesA[hullA->m_faceOffset+face].m_plane.x,\n" +" facesA[hullA->m_faceOffset+face].m_plane.y,\n" +" facesA[hullA->m_faceOffset+face].m_plane.z,\n" +" 0.f);\n" +" const float4 faceANormalWS = qtRotate(ornA,Normal);\n" +" \n" +" float d = dot3F4(faceANormalWS,separatingNormal);\n" +" if (d < dmin)\n" +" {\n" +" dmin = d;\n" +" closestFaceA = face;\n" +" worldNormalsA1[pairIndex] = faceANormalWS;\n" +" }\n" +" }\n" +" }\n" +" \n" +" int numVerticesA = facesA[hullA->m_faceOffset+closestFaceA].m_numIndices;\n" +" if (numVerticesA>capacityWorldVerts)\n" +" numVerticesA = capacityWorldVerts;\n" +" \n" +" for(int e0=0;e0m_vertexOffset+indicesA[facesA[hullA->m_faceOffset+closestFaceA].m_indexOffset+e0]];\n" +" worldVertsA1[pairIndex*capacityWorldVerts+e0] = transform(&a, &posA,&ornA);\n" +" }\n" +" }\n" +" \n" +" clippingFaces[pairIndex].x = closestFaceA;\n" +" clippingFaces[pairIndex].y = closestFaceB;\n" +" clippingFaces[pairIndex].z = numVerticesA;\n" +" clippingFaces[pairIndex].w = numWorldVertsB1;\n" +" \n" +" \n" +" return numContactsOut;\n" +"}\n" +"// work-in-progress\n" +"__kernel void findConcaveSeparatingAxisKernel( __global int4* concavePairs,\n" +" __global const BodyData* rigidBodies,\n" +" __global const btCollidableGpu* collidables,\n" +" __global const ConvexPolyhedronCL* convexShapes, \n" +" __global const float4* vertices,\n" +" __global const float4* uniqueEdges,\n" +" __global const btGpuFace* faces,\n" +" __global const int* indices,\n" +" __global const btGpuChildShape* gpuChildShapes,\n" +" __global btAabbCL* aabbs,\n" +" __global float4* concaveSeparatingNormalsOut,\n" +" __global int* concaveHasSeparatingNormals,\n" +" __global int4* clippingFacesOut,\n" +" __global float4* worldVertsA1GPU,\n" +" __global float4* worldNormalsAGPU,\n" +" __global float4* worldVertsB1GPU,\n" +" int vertexFaceCapacity,\n" +" int numConcavePairs\n" +" )\n" +"{\n" +" int i = get_global_id(0);\n" +" if (i>=numConcavePairs)\n" +" return;\n" +" concaveHasSeparatingNormals[i] = 0;\n" +" int pairIdx = i;\n" +" int bodyIndexA = concavePairs[i].x;\n" +" int bodyIndexB = concavePairs[i].y;\n" +" int collidableIndexA = rigidBodies[bodyIndexA].m_collidableIdx;\n" +" int collidableIndexB = rigidBodies[bodyIndexB].m_collidableIdx;\n" +" int shapeIndexA = collidables[collidableIndexA].m_shapeIndex;\n" +" int shapeIndexB = collidables[collidableIndexB].m_shapeIndex;\n" +" if (collidables[collidableIndexB].m_shapeType!=SHAPE_CONVEX_HULL&&\n" +" collidables[collidableIndexB].m_shapeType!=SHAPE_COMPOUND_OF_CONVEX_HULLS)\n" +" {\n" +" concavePairs[pairIdx].w = -1;\n" +" return;\n" +" }\n" +" int numFacesA = convexShapes[shapeIndexA].m_numFaces;\n" +" int numActualConcaveConvexTests = 0;\n" +" \n" +" int f = concavePairs[i].z;\n" +" \n" +" bool overlap = false;\n" +" \n" +" ConvexPolyhedronCL convexPolyhedronA;\n" +" //add 3 vertices of the triangle\n" +" convexPolyhedronA.m_numVertices = 3;\n" +" convexPolyhedronA.m_vertexOffset = 0;\n" +" float4 localCenter = make_float4(0.f,0.f,0.f,0.f);\n" +" btGpuFace face = faces[convexShapes[shapeIndexA].m_faceOffset+f];\n" +" float4 triMinAabb, triMaxAabb;\n" +" btAabbCL triAabb;\n" +" triAabb.m_min = make_float4(1e30f,1e30f,1e30f,0.f);\n" +" triAabb.m_max = make_float4(-1e30f,-1e30f,-1e30f,0.f);\n" +" \n" +" float4 verticesA[3];\n" +" for (int i=0;i<3;i++)\n" +" {\n" +" int index = indices[face.m_indexOffset+i];\n" +" float4 vert = vertices[convexShapes[shapeIndexA].m_vertexOffset+index];\n" +" verticesA[i] = vert;\n" +" localCenter += vert;\n" +" \n" +" triAabb.m_min = min(triAabb.m_min,vert); \n" +" triAabb.m_max = max(triAabb.m_max,vert); \n" +" }\n" +" overlap = true;\n" +" overlap = (triAabb.m_min.x > aabbs[bodyIndexB].m_max.x || triAabb.m_max.x < aabbs[bodyIndexB].m_min.x) ? false : overlap;\n" +" overlap = (triAabb.m_min.z > aabbs[bodyIndexB].m_max.z || triAabb.m_max.z < aabbs[bodyIndexB].m_min.z) ? false : overlap;\n" +" overlap = (triAabb.m_min.y > aabbs[bodyIndexB].m_max.y || triAabb.m_max.y < aabbs[bodyIndexB].m_min.y) ? false : overlap;\n" +" \n" +" if (overlap)\n" +" {\n" +" float dmin = FLT_MAX;\n" +" int hasSeparatingAxis=5;\n" +" float4 sepAxis=make_float4(1,2,3,4);\n" +" int localCC=0;\n" +" numActualConcaveConvexTests++;\n" +" //a triangle has 3 unique edges\n" +" convexPolyhedronA.m_numUniqueEdges = 3;\n" +" convexPolyhedronA.m_uniqueEdgesOffset = 0;\n" +" float4 uniqueEdgesA[3];\n" +" \n" +" uniqueEdgesA[0] = (verticesA[1]-verticesA[0]);\n" +" uniqueEdgesA[1] = (verticesA[2]-verticesA[1]);\n" +" uniqueEdgesA[2] = (verticesA[0]-verticesA[2]);\n" +" convexPolyhedronA.m_faceOffset = 0;\n" +" \n" +" float4 normal = make_float4(face.m_plane.x,face.m_plane.y,face.m_plane.z,0.f);\n" +" \n" +" btGpuFace facesA[TRIANGLE_NUM_CONVEX_FACES];\n" +" int indicesA[3+3+2+2+2];\n" +" int curUsedIndices=0;\n" +" int fidx=0;\n" +" //front size of triangle\n" +" {\n" +" facesA[fidx].m_indexOffset=curUsedIndices;\n" +" indicesA[0] = 0;\n" +" indicesA[1] = 1;\n" +" indicesA[2] = 2;\n" +" curUsedIndices+=3;\n" +" float c = face.m_plane.w;\n" +" facesA[fidx].m_plane.x = normal.x;\n" +" facesA[fidx].m_plane.y = normal.y;\n" +" facesA[fidx].m_plane.z = normal.z;\n" +" facesA[fidx].m_plane.w = c;\n" +" facesA[fidx].m_numIndices=3;\n" +" }\n" +" fidx++;\n" +" //back size of triangle\n" +" {\n" +" facesA[fidx].m_indexOffset=curUsedIndices;\n" +" indicesA[3]=2;\n" +" indicesA[4]=1;\n" +" indicesA[5]=0;\n" +" curUsedIndices+=3;\n" +" float c = dot(normal,verticesA[0]);\n" +" float c1 = -face.m_plane.w;\n" +" facesA[fidx].m_plane.x = -normal.x;\n" +" facesA[fidx].m_plane.y = -normal.y;\n" +" facesA[fidx].m_plane.z = -normal.z;\n" +" facesA[fidx].m_plane.w = c;\n" +" facesA[fidx].m_numIndices=3;\n" +" }\n" +" fidx++;\n" +" bool addEdgePlanes = true;\n" +" if (addEdgePlanes)\n" +" {\n" +" int numVertices=3;\n" +" int prevVertex = numVertices-1;\n" +" for (int i=0;i( device, 1, BufferBase::BUFFER_CONST ); + + m_lower = (maxSize == 0)? 0: new b3OpenCLArray(ctx,queue,maxSize ); + m_upper = (maxSize == 0)? 0: new b3OpenCLArray(ctx,queue, maxSize ); + + m_filler = new b3FillCL(ctx,device,queue); +} + +b3BoundSearchCL::~b3BoundSearchCL() +{ + + delete m_lower; + delete m_upper; + delete m_filler; + + clReleaseKernel(m_lowerSortDataKernel); + clReleaseKernel(m_upperSortDataKernel); + clReleaseKernel(m_subtractKernel); + + +} + + +void b3BoundSearchCL::execute(b3OpenCLArray& src, int nSrc, b3OpenCLArray& dst, int nDst, Option option ) +{ + b3Int4 constBuffer; + constBuffer.x = nSrc; + constBuffer.y = nDst; + + if( option == BOUND_LOWER ) + { + b3BufferInfoCL bInfo[] = { b3BufferInfoCL( src.getBufferCL(), true ), b3BufferInfoCL( dst.getBufferCL()) }; + + b3LauncherCL launcher( m_queue, m_lowerSortDataKernel,"m_lowerSortDataKernel" ); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( nSrc ); + launcher.setConst( nDst ); + + launcher.launch1D( nSrc, 64 ); + } + else if( option == BOUND_UPPER ) + { + b3BufferInfoCL bInfo[] = { b3BufferInfoCL( src.getBufferCL(), true ), b3BufferInfoCL( dst.getBufferCL() ) }; + + b3LauncherCL launcher(m_queue, m_upperSortDataKernel,"m_upperSortDataKernel" ); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( nSrc ); + launcher.setConst( nDst ); + + launcher.launch1D( nSrc, 64 ); + } + else if( option == COUNT ) + { + b3Assert( m_lower ); + b3Assert( m_upper ); + b3Assert( m_lower->capacity() <= (int)nDst ); + b3Assert( m_upper->capacity() <= (int)nDst ); + + int zero = 0; + m_filler->execute( *m_lower, zero, nDst ); + m_filler->execute( *m_upper, zero, nDst ); + + execute( src, nSrc, *m_lower, nDst, BOUND_LOWER ); + execute( src, nSrc, *m_upper, nDst, BOUND_UPPER ); + + { + b3BufferInfoCL bInfo[] = { b3BufferInfoCL( m_upper->getBufferCL(), true ), b3BufferInfoCL( m_lower->getBufferCL(), true ), b3BufferInfoCL( dst.getBufferCL() ) }; + + b3LauncherCL launcher( m_queue, m_subtractKernel ,"m_subtractKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( nSrc ); + launcher.setConst( nDst ); + + launcher.launch1D( nDst, 64 ); + } + } + else + { + b3Assert( 0 ); + } + +} + + +void b3BoundSearchCL::executeHost( b3AlignedObjectArray& src, int nSrc, + b3AlignedObjectArray& dst, int nDst, Option option ) +{ + + + for(int i=0; i lower; + lower.resize(nDst ); + b3AlignedObjectArray upper; + upper.resize(nDst ); + + for(int i=0; i +#include +#include +#include +*/ + +#include "b3OpenCLArray.h" +#include "b3FillCL.h" +#include "b3RadixSort32CL.h" //for b3SortData (perhaps move it?) +class b3BoundSearchCL +{ + public: + + enum Option + { + BOUND_LOWER, + BOUND_UPPER, + COUNT, + }; + + cl_context m_context; + cl_device_id m_device; + cl_command_queue m_queue; + + + cl_kernel m_lowerSortDataKernel; + cl_kernel m_upperSortDataKernel; + cl_kernel m_subtractKernel; + + b3OpenCLArray* m_constbtOpenCLArray; + b3OpenCLArray* m_lower; + b3OpenCLArray* m_upper; + + b3FillCL* m_filler; + + b3BoundSearchCL(cl_context context, cl_device_id device, cl_command_queue queue, int size); + + virtual ~b3BoundSearchCL(); + + // src has to be src[i].m_key <= src[i+1].m_key + void execute( b3OpenCLArray& src, int nSrc, b3OpenCLArray& dst, int nDst, Option option = BOUND_LOWER ); + + void executeHost( b3AlignedObjectArray& src, int nSrc, b3AlignedObjectArray& dst, int nDst, Option option = BOUND_LOWER); +}; + + +#endif //B3_BOUNDSEARCH_H diff --git a/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3BufferInfoCL.h b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3BufferInfoCL.h new file mode 100644 index 000000000000..52f219ae3fc0 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3BufferInfoCL.h @@ -0,0 +1,19 @@ + +#ifndef B3_BUFFER_INFO_CL_H +#define B3_BUFFER_INFO_CL_H + +#include "b3OpenCLArray.h" + + +struct b3BufferInfoCL +{ + //b3BufferInfoCL(){} + +// template + b3BufferInfoCL(cl_mem buff, bool isReadOnly = false): m_clBuffer(buff), m_isReadOnly(isReadOnly){} + + cl_mem m_clBuffer; + bool m_isReadOnly; +}; + +#endif //B3_BUFFER_INFO_CL_H diff --git a/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3FillCL.cpp b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3FillCL.cpp new file mode 100644 index 000000000000..f05c2648f126 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3FillCL.cpp @@ -0,0 +1,126 @@ +#include "b3FillCL.h" +#include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h" +#include "b3BufferInfoCL.h" +#include "b3LauncherCL.h" + +#define FILL_CL_PROGRAM_PATH "src/Bullet3OpenCL/ParallelPrimitives/kernels/FillKernels.cl" + +#include "kernels/FillKernelsCL.h" + +b3FillCL::b3FillCL(cl_context ctx, cl_device_id device, cl_command_queue queue) +:m_commandQueue(queue) +{ + const char* kernelSource = fillKernelsCL; + cl_int pErrNum; + const char* additionalMacros = ""; + + cl_program fillProg = b3OpenCLUtils::compileCLProgramFromString( ctx, device, kernelSource, &pErrNum,additionalMacros, FILL_CL_PROGRAM_PATH); + b3Assert(fillProg); + + m_fillIntKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, kernelSource, "FillIntKernel", &pErrNum, fillProg,additionalMacros ); + b3Assert(m_fillIntKernel); + + m_fillUnsignedIntKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, kernelSource, "FillUnsignedIntKernel", &pErrNum, fillProg,additionalMacros ); + b3Assert(m_fillIntKernel); + + m_fillFloatKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, kernelSource, "FillFloatKernel", &pErrNum, fillProg,additionalMacros ); + b3Assert(m_fillFloatKernel); + + + + m_fillKernelInt2 = b3OpenCLUtils::compileCLKernelFromString( ctx, device, kernelSource, "FillInt2Kernel", &pErrNum, fillProg,additionalMacros ); + b3Assert(m_fillKernelInt2); + +} + +b3FillCL::~b3FillCL() +{ + clReleaseKernel(m_fillKernelInt2); + clReleaseKernel(m_fillIntKernel); + clReleaseKernel(m_fillUnsignedIntKernel); + clReleaseKernel(m_fillFloatKernel); + +} + +void b3FillCL::execute(b3OpenCLArray& src, const float value, int n, int offset) +{ + b3Assert( n>0 ); + + { + b3LauncherCL launcher( m_commandQueue, m_fillFloatKernel,"m_fillFloatKernel" ); + launcher.setBuffer( src.getBufferCL()); + launcher.setConst( n ); + launcher.setConst( value ); + launcher.setConst( offset); + + launcher.launch1D( n ); + } +} + +void b3FillCL::execute(b3OpenCLArray& src, const int value, int n, int offset) +{ + b3Assert( n>0 ); + + + { + b3LauncherCL launcher( m_commandQueue, m_fillIntKernel ,"m_fillIntKernel"); + launcher.setBuffer(src.getBufferCL()); + launcher.setConst( n); + launcher.setConst( value); + launcher.setConst( offset); + launcher.launch1D( n ); + } +} + + +void b3FillCL::execute(b3OpenCLArray& src, const unsigned int value, int n, int offset) +{ + b3Assert( n>0 ); + + { + b3BufferInfoCL bInfo[] = { b3BufferInfoCL( src.getBufferCL() ) }; + + b3LauncherCL launcher( m_commandQueue, m_fillUnsignedIntKernel,"m_fillUnsignedIntKernel" ); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( n ); + launcher.setConst(value); + launcher.setConst(offset); + + launcher.launch1D( n ); + } +} + +void b3FillCL::executeHost(b3AlignedObjectArray &src, const b3Int2 &value, int n, int offset) +{ + for (int i=0;i &src, const int value, int n, int offset) +{ + for (int i=0;i &src, const b3Int2 &value, int n, int offset) +{ + b3Assert( n>0 ); + + + { + b3BufferInfoCL bInfo[] = { b3BufferInfoCL( src.getBufferCL() ) }; + + b3LauncherCL launcher(m_commandQueue, m_fillKernelInt2,"m_fillKernelInt2"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(n); + launcher.setConst(value); + launcher.setConst(offset); + + //( constBuffer ); + launcher.launch1D( n ); + } +} diff --git a/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3FillCL.h b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3FillCL.h new file mode 100644 index 000000000000..1609676b9ddd --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3FillCL.h @@ -0,0 +1,63 @@ +#ifndef B3_FILL_CL_H +#define B3_FILL_CL_H + +#include "b3OpenCLArray.h" +#include "Bullet3Common/b3Scalar.h" + +#include "Bullet3Common/shared/b3Int2.h" +#include "Bullet3Common/shared/b3Int4.h" + + +class b3FillCL +{ + + cl_command_queue m_commandQueue; + + cl_kernel m_fillKernelInt2; + cl_kernel m_fillIntKernel; + cl_kernel m_fillUnsignedIntKernel; + cl_kernel m_fillFloatKernel; + + public: + + struct b3ConstData + { + union + { + b3Int4 m_data; + b3UnsignedInt4 m_UnsignedData; + }; + int m_offset; + int m_n; + int m_padding[2]; + }; + +protected: + +public: + + b3FillCL(cl_context ctx, cl_device_id device, cl_command_queue queue); + + virtual ~b3FillCL(); + + void execute(b3OpenCLArray& src, const unsigned int value, int n, int offset = 0); + + void execute(b3OpenCLArray& src, const int value, int n, int offset = 0); + + void execute(b3OpenCLArray& src, const float value, int n, int offset = 0); + + void execute(b3OpenCLArray& src, const b3Int2& value, int n, int offset = 0); + + void executeHost(b3AlignedObjectArray &src, const b3Int2 &value, int n, int offset); + + void executeHost(b3AlignedObjectArray &src, const int value, int n, int offset); + + // void execute(b3OpenCLArray& src, const b3Int4& value, int n, int offset = 0); + +}; + + + + + +#endif //B3_FILL_CL_H diff --git a/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.cpp b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.cpp new file mode 100644 index 000000000000..94590d11caf4 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.cpp @@ -0,0 +1,308 @@ +#include "b3LauncherCL.h" + +bool gDebugLauncherCL = false; + +b3LauncherCL::b3LauncherCL(cl_command_queue queue, cl_kernel kernel, const char* name) +:m_commandQueue(queue), +m_kernel(kernel), +m_idx(0), +m_enableSerialization(false), +m_name(name) +{ + if (gDebugLauncherCL) + { + static int counter = 0; + printf("[%d] Prepare to launch OpenCL kernel %s\n", counter++, name); + } + + m_serializationSizeInBytes = sizeof(int); +} + +b3LauncherCL::~b3LauncherCL() + { + for (int i=0;i + + + +int b3LauncherCL::deserializeArgs(unsigned char* buf, int bufSize, cl_context ctx) +{ + int index=0; + + int numArguments = *(int*) &buf[index]; + index+=sizeof(int); + + for (int i=0;im_isBuffer) + { + b3OpenCLArray* clData = new b3OpenCLArray(ctx,m_commandQueue, arg->m_argSizeInBytes); + clData->resize(arg->m_argSizeInBytes); + + clData->copyFromHostPointer(&buf[index], arg->m_argSizeInBytes); + + arg->m_clBuffer = clData->getBufferCL(); + + m_arrays.push_back(clData); + + cl_int status = clSetKernelArg( m_kernel, m_idx++, sizeof(cl_mem), &arg->m_clBuffer); + b3Assert( status == CL_SUCCESS ); + index+=arg->m_argSizeInBytes; + } else + { + cl_int status = clSetKernelArg( m_kernel, m_idx++, arg->m_argSizeInBytes, &arg->m_argData); + b3Assert( status == CL_SUCCESS ); + } + b3KernelArgData b; + memcpy(&b,arg,sizeof(b3KernelArgDataUnaligned)); + m_kernelArguments.push_back(b); + } +m_serializationSizeInBytes = index; + return index; +} + +int b3LauncherCL::validateResults(unsigned char* goldBuffer, int goldBufferCapacity, cl_context ctx) + { + int index=0; + + int numArguments = *(int*) &goldBuffer[index]; + index+=sizeof(int); + + if (numArguments != m_kernelArguments.size()) + { + printf("failed validation: expected %d arguments, found %d\n",numArguments, m_kernelArguments.size()); + return -1; + } + + for (int ii=0;iim_argSizeInBytes) + { + printf("failed validation: argument %d sizeInBytes expected: %d, found %d\n",ii, argGold->m_argSizeInBytes, m_kernelArguments[ii].m_argSizeInBytes); + return -2; + } + + { + int expected = argGold->m_isBuffer; + int found = m_kernelArguments[ii].m_isBuffer; + + if (expected != found) + { + printf("failed validation: argument %d isBuffer expected: %d, found %d\n",ii,expected, found); + return -3; + } + } + index+=sizeof(b3KernelArgData); + + if (argGold->m_isBuffer) + { + + unsigned char* memBuf= (unsigned char*) malloc(m_kernelArguments[ii].m_argSizeInBytes); + unsigned char* goldBuf = &goldBuffer[index]; + for (int j=0;jm_argSizeInBytes; + } else + { + + //compare content + for (int b=0;bm_argData[b]; + int found =m_kernelArguments[ii].m_argData[b]; + if (expected != found) + { + printf("failed validation: argument %d const data at byte position %d expected: %d, found %d\n", + ii, b, expected, found); + return -5; + } + } + + } + } + return index; + +} + +int b3LauncherCL::serializeArguments(unsigned char* destBuffer, int destBufferCapacity) +{ +//initialize to known values +for (int i=0;i=m_serializationSizeInBytes); + + //todo: use the b3Serializer for this to allow for 32/64bit, endianness etc + int numArguments = m_kernelArguments.size(); + int curBufferSize = 0; + int* dest = (int*)&destBuffer[curBufferSize]; + *dest = numArguments; + curBufferSize += sizeof(int); + + + + for (int i=0;im_kernelArguments.size();i++) + { + b3KernelArgData* arg = (b3KernelArgData*) &destBuffer[curBufferSize]; + *arg = m_kernelArguments[i]; + curBufferSize+=sizeof(b3KernelArgData); + if (arg->m_isBuffer==1) + { + //copy the OpenCL buffer content + cl_int status = 0; + status = clEnqueueReadBuffer( m_commandQueue, arg->m_clBuffer, 0, 0, arg->m_argSizeInBytes, + &destBuffer[curBufferSize], 0,0,0 ); + b3Assert( status==CL_SUCCESS ); + clFinish(m_commandQueue); + curBufferSize+=arg->m_argSizeInBytes; + } + + } + return curBufferSize; +} + +void b3LauncherCL::serializeToFile(const char* fileName, int numWorkItems) +{ + int num = numWorkItems; + int buffSize = getSerializationBufferSize(); + unsigned char* buf = new unsigned char[buffSize+sizeof(int)]; + for (int i=0;i + +#define B3_DEBUG_SERIALIZE_CL + + +#ifdef _WIN32 +#pragma warning(disable :4996) +#endif +#define B3_CL_MAX_ARG_SIZE 16 +B3_ATTRIBUTE_ALIGNED16(struct) b3KernelArgData +{ + int m_isBuffer; + int m_argIndex; + int m_argSizeInBytes; + int m_unusedPadding; + union + { + cl_mem m_clBuffer; + unsigned char m_argData[B3_CL_MAX_ARG_SIZE]; + }; + +}; + +class b3LauncherCL +{ + + cl_command_queue m_commandQueue; + cl_kernel m_kernel; + int m_idx; + + b3AlignedObjectArray m_kernelArguments; + int m_serializationSizeInBytes; + bool m_enableSerialization; + + const char* m_name; + public: + + b3AlignedObjectArray* > m_arrays; + + b3LauncherCL(cl_command_queue queue, cl_kernel kernel, const char* name); + + virtual ~b3LauncherCL(); + + void setBuffer( cl_mem clBuffer); + + void setBuffers( b3BufferInfoCL* buffInfo, int n ); + + int getSerializationBufferSize() const + { + return m_serializationSizeInBytes; + } + + int deserializeArgs(unsigned char* buf, int bufSize, cl_context ctx); + + inline int validateResults(unsigned char* goldBuffer, int goldBufferCapacity, cl_context ctx); + + int serializeArguments(unsigned char* destBuffer, int destBufferCapacity); + + int getNumArguments() const + { + return m_kernelArguments.size(); + } + + b3KernelArgData getArgument(int index) + { + return m_kernelArguments[index]; + } + + void serializeToFile(const char* fileName, int numWorkItems); + + template + inline void setConst( const T& consts ) + { + int sz=sizeof(T); + b3Assert(sz<=B3_CL_MAX_ARG_SIZE); + + if (m_enableSerialization) + { + b3KernelArgData kernelArg; + kernelArg.m_argIndex = m_idx; + kernelArg.m_isBuffer = 0; + T* destArg = (T*)kernelArg.m_argData; + *destArg = consts; + kernelArg.m_argSizeInBytes = sizeof(T); + m_kernelArguments.push_back(kernelArg); + m_serializationSizeInBytes+=sizeof(b3KernelArgData); + } + + cl_int status = clSetKernelArg( m_kernel, m_idx++, sz, &consts ); + b3Assert( status == CL_SUCCESS ); + } + + inline void launch1D( int numThreads, int localSize = 64) + { + launch2D( numThreads, 1, localSize, 1 ); + } + + inline void launch2D( int numThreadsX, int numThreadsY, int localSizeX, int localSizeY ) + { + size_t gRange[3] = {1,1,1}; + size_t lRange[3] = {1,1,1}; + lRange[0] = localSizeX; + lRange[1] = localSizeY; + gRange[0] = b3Max((size_t)1, (numThreadsX/lRange[0])+(!(numThreadsX%lRange[0])?0:1)); + gRange[0] *= lRange[0]; + gRange[1] = b3Max((size_t)1, (numThreadsY/lRange[1])+(!(numThreadsY%lRange[1])?0:1)); + gRange[1] *= lRange[1]; + + cl_int status = clEnqueueNDRangeKernel( m_commandQueue, + m_kernel, 2, NULL, gRange, lRange, 0,0,0 ); + if (status != CL_SUCCESS) + { + printf("Error: OpenCL status = %d\n",status); + } + b3Assert( status == CL_SUCCESS ); + + } + + void enableSerialization(bool serialize) + { + m_enableSerialization = serialize; + } + +}; + + + +#endif //B3_LAUNCHER_CL_H diff --git a/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3OpenCLArray.h b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3OpenCLArray.h new file mode 100644 index 000000000000..d70c30f53f4a --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3OpenCLArray.h @@ -0,0 +1,306 @@ +#ifndef B3_OPENCL_ARRAY_H +#define B3_OPENCL_ARRAY_H + +#include "Bullet3Common/b3AlignedObjectArray.h" +#include "Bullet3OpenCL/Initialize/b3OpenCLInclude.h" + +template +class b3OpenCLArray +{ + size_t m_size; + size_t m_capacity; + cl_mem m_clBuffer; + + cl_context m_clContext; + cl_command_queue m_commandQueue; + + bool m_ownsMemory; + + bool m_allowGrowingCapacity; + + void deallocate() + { + if (m_clBuffer && m_ownsMemory) + { + clReleaseMemObject(m_clBuffer); + } + m_clBuffer = 0; + m_capacity=0; + } + + b3OpenCLArray& operator=(const b3OpenCLArray& src); + + B3_FORCE_INLINE size_t allocSize(size_t size) + { + return (size ? size*2 : 1); + } + +public: + + b3OpenCLArray(cl_context ctx, cl_command_queue queue, size_t initialCapacity=0, bool allowGrowingCapacity=true) + :m_size(0), m_capacity(0),m_clBuffer(0), + m_clContext(ctx),m_commandQueue(queue), + m_ownsMemory(true),m_allowGrowingCapacity(true) + { + if (initialCapacity) + { + reserve(initialCapacity); + } + m_allowGrowingCapacity = allowGrowingCapacity; + } + + ///this is an error-prone method with no error checking, be careful! + void setFromOpenCLBuffer(cl_mem buffer, size_t sizeInElements) + { + deallocate(); + m_ownsMemory = false; + m_allowGrowingCapacity = false; + m_clBuffer = buffer; + m_size = sizeInElements; + m_capacity = sizeInElements; + } + +// we could enable this assignment, but need to make sure to avoid accidental deep copies +// b3OpenCLArray& operator=(const b3AlignedObjectArray& src) +// { +// copyFromArray(src); +// return *this; +// } + + + cl_mem getBufferCL() const + { + return m_clBuffer; + } + + + virtual ~b3OpenCLArray() + { + deallocate(); + m_size=0; + m_capacity=0; + } + + B3_FORCE_INLINE bool push_back(const T& _Val,bool waitForCompletion=true) + { + bool result = true; + size_t sz = size(); + if( sz == capacity() ) + { + result = reserve( allocSize(size()) ); + } + copyFromHostPointer(&_Val, 1, sz, waitForCompletion); + m_size++; + return result; + } + + B3_FORCE_INLINE T forcedAt(size_t n) const + { + b3Assert(n>=0); + b3Assert(n=0); + b3Assert(n size()) + { + result = reserve(newsize,copyOldContents); + } + + //leave new data uninitialized (init in debug mode?) + //for (size_t i=curSize;i0); + b3Assert(numElements<=m_size); + + size_t srcOffsetBytes = sizeof(T)*firstElem; + size_t dstOffsetInBytes = sizeof(T)*dstOffsetInElems; + + status = clEnqueueCopyBuffer( m_commandQueue, m_clBuffer, destination, + srcOffsetBytes, dstOffsetInBytes, sizeof(T)*numElements, 0, 0, 0 ); + + b3Assert( status == CL_SUCCESS ); + } + + void copyFromHost(const b3AlignedObjectArray& srcArray, bool waitForCompletion=true) + { + size_t newSize = srcArray.size(); + + bool copyOldContents = false; + resize (newSize,copyOldContents); + if (newSize) + copyFromHostPointer(&srcArray[0],newSize,0,waitForCompletion); + + } + + void copyFromHostPointer(const T* src, size_t numElems, size_t destFirstElem= 0, bool waitForCompletion=true) + { + b3Assert(numElems+destFirstElem <= capacity()); + + if (numElems+destFirstElem) + { + cl_int status = 0; + size_t sizeInBytes=sizeof(T)*numElems; + status = clEnqueueWriteBuffer( m_commandQueue, m_clBuffer, 0, sizeof(T)*destFirstElem, sizeInBytes, + src, 0,0,0 ); + b3Assert(status == CL_SUCCESS ); + if (waitForCompletion) + clFinish(m_commandQueue); + } else + { + b3Error("copyFromHostPointer invalid range\n"); + } + } + + + void copyToHost(b3AlignedObjectArray& destArray, bool waitForCompletion=true) const + { + destArray.resize(this->size()); + if (size()) + copyToHostPointer(&destArray[0], size(),0,waitForCompletion); + } + + void copyToHostPointer(T* destPtr, size_t numElem, size_t srcFirstElem=0, bool waitForCompletion=true) const + { + b3Assert(numElem+srcFirstElem <= capacity()); + + if(numElem+srcFirstElem <= capacity()) + { + cl_int status = 0; + status = clEnqueueReadBuffer( m_commandQueue, m_clBuffer, 0, sizeof(T)*srcFirstElem, sizeof(T)*numElem, + destPtr, 0,0,0 ); + b3Assert( status==CL_SUCCESS ); + + if (waitForCompletion) + clFinish(m_commandQueue); + } else + { + b3Error("copyToHostPointer invalid range\n"); + } + } + + void copyFromOpenCLArray(const b3OpenCLArray& src) + { + size_t newSize = src.size(); + resize(newSize); + if (size()) + { + src.copyToCL(m_clBuffer,size()); + } + } + +}; + + +#endif //B3_OPENCL_ARRAY_H diff --git a/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3PrefixScanCL.cpp b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3PrefixScanCL.cpp new file mode 100644 index 000000000000..42cd197740a4 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3PrefixScanCL.cpp @@ -0,0 +1,126 @@ +#include "b3PrefixScanCL.h" +#include "b3FillCL.h" +#define B3_PREFIXSCAN_PROG_PATH "src/Bullet3OpenCL/ParallelPrimitives/kernels/PrefixScanKernels.cl" + +#include "b3LauncherCL.h" +#include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h" +#include "kernels/PrefixScanKernelsCL.h" + +b3PrefixScanCL::b3PrefixScanCL(cl_context ctx, cl_device_id device, cl_command_queue queue, int size) +:m_commandQueue(queue) +{ + const char* scanKernelSource = prefixScanKernelsCL; + cl_int pErrNum; + char* additionalMacros=0; + + m_workBuffer = new b3OpenCLArray(ctx,queue,size); + cl_program scanProg = b3OpenCLUtils::compileCLProgramFromString( ctx, device, scanKernelSource, &pErrNum,additionalMacros, B3_PREFIXSCAN_PROG_PATH); + b3Assert(scanProg); + + m_localScanKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, scanKernelSource, "LocalScanKernel", &pErrNum, scanProg,additionalMacros ); + b3Assert(m_localScanKernel ); + m_blockSumKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, scanKernelSource, "TopLevelScanKernel", &pErrNum, scanProg,additionalMacros ); + b3Assert(m_blockSumKernel ); + m_propagationKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, scanKernelSource, "AddOffsetKernel", &pErrNum, scanProg,additionalMacros ); + b3Assert(m_propagationKernel ); +} + + +b3PrefixScanCL::~b3PrefixScanCL() +{ + delete m_workBuffer; + clReleaseKernel(m_localScanKernel); + clReleaseKernel(m_blockSumKernel); + clReleaseKernel(m_propagationKernel); +} + +template +T b3NextPowerOf2(T n) +{ + n -= 1; + for(int i=0; i>i); + return n+1; +} + +void b3PrefixScanCL::execute(b3OpenCLArray& src, b3OpenCLArray& dst, int n, unsigned int* sum) +{ + +// b3Assert( data->m_option == EXCLUSIVE ); + const unsigned int numBlocks = (const unsigned int)( (n+BLOCK_SIZE*2-1)/(BLOCK_SIZE*2) ); + + dst.resize(src.size()); + m_workBuffer->resize(src.size()); + + b3Int4 constBuffer; + constBuffer.x = n; + constBuffer.y = numBlocks; + constBuffer.z = (int)b3NextPowerOf2( numBlocks ); + + b3OpenCLArray* srcNative = &src; + b3OpenCLArray* dstNative = &dst; + + { + b3BufferInfoCL bInfo[] = { b3BufferInfoCL( dstNative->getBufferCL() ), b3BufferInfoCL( srcNative->getBufferCL() ), b3BufferInfoCL( m_workBuffer->getBufferCL() ) }; + + b3LauncherCL launcher( m_commandQueue, m_localScanKernel,"m_localScanKernel" ); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( constBuffer ); + launcher.launch1D( numBlocks*BLOCK_SIZE, BLOCK_SIZE ); + } + + { + b3BufferInfoCL bInfo[] = { b3BufferInfoCL( m_workBuffer->getBufferCL() ) }; + + b3LauncherCL launcher( m_commandQueue, m_blockSumKernel,"m_blockSumKernel" ); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( constBuffer ); + launcher.launch1D( BLOCK_SIZE, BLOCK_SIZE ); + } + + + if( numBlocks > 1 ) + { + b3BufferInfoCL bInfo[] = { b3BufferInfoCL( dstNative->getBufferCL() ), b3BufferInfoCL( m_workBuffer->getBufferCL() ) }; + b3LauncherCL launcher( m_commandQueue, m_propagationKernel,"m_propagationKernel" ); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( constBuffer ); + launcher.launch1D( (numBlocks-1)*BLOCK_SIZE, BLOCK_SIZE ); + } + + + if( sum ) + { + clFinish(m_commandQueue); + dstNative->copyToHostPointer(sum,1,n-1,true); + } + +} + + +void b3PrefixScanCL::executeHost(b3AlignedObjectArray& src, b3AlignedObjectArray& dst, int n, unsigned int* sum) +{ + unsigned int s = 0; + //if( data->m_option == EXCLUSIVE ) + { + for(int i=0; i* m_workBuffer; + + + public: + + b3PrefixScanCL(cl_context ctx, cl_device_id device, cl_command_queue queue,int size=0); + + virtual ~b3PrefixScanCL(); + + void execute(b3OpenCLArray& src, b3OpenCLArray& dst, int n, unsigned int* sum = 0); + void executeHost(b3AlignedObjectArray& src, b3AlignedObjectArray& dst, int n, unsigned int* sum=0); +}; + +#endif //B3_PREFIX_SCAN_CL_H diff --git a/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3PrefixScanFloat4CL.cpp b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3PrefixScanFloat4CL.cpp new file mode 100644 index 000000000000..80560d793de4 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3PrefixScanFloat4CL.cpp @@ -0,0 +1,126 @@ +#include "b3PrefixScanFloat4CL.h" +#include "b3FillCL.h" +#define B3_PREFIXSCAN_FLOAT4_PROG_PATH "src/Bullet3OpenCL/ParallelPrimitives/kernels/PrefixScanFloat4Kernels.cl" + +#include "b3LauncherCL.h" +#include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h" +#include "kernels/PrefixScanKernelsFloat4CL.h" + +b3PrefixScanFloat4CL::b3PrefixScanFloat4CL(cl_context ctx, cl_device_id device, cl_command_queue queue, int size) +:m_commandQueue(queue) +{ + const char* scanKernelSource = prefixScanKernelsFloat4CL; + cl_int pErrNum; + char* additionalMacros=0; + + m_workBuffer = new b3OpenCLArray(ctx,queue,size); + cl_program scanProg = b3OpenCLUtils::compileCLProgramFromString( ctx, device, scanKernelSource, &pErrNum,additionalMacros, B3_PREFIXSCAN_FLOAT4_PROG_PATH); + b3Assert(scanProg); + + m_localScanKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, scanKernelSource, "LocalScanKernel", &pErrNum, scanProg,additionalMacros ); + b3Assert(m_localScanKernel ); + m_blockSumKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, scanKernelSource, "TopLevelScanKernel", &pErrNum, scanProg,additionalMacros ); + b3Assert(m_blockSumKernel ); + m_propagationKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, scanKernelSource, "AddOffsetKernel", &pErrNum, scanProg,additionalMacros ); + b3Assert(m_propagationKernel ); +} + + +b3PrefixScanFloat4CL::~b3PrefixScanFloat4CL() +{ + delete m_workBuffer; + clReleaseKernel(m_localScanKernel); + clReleaseKernel(m_blockSumKernel); + clReleaseKernel(m_propagationKernel); +} + +template +T b3NextPowerOf2(T n) +{ + n -= 1; + for(int i=0; i>i); + return n+1; +} + +void b3PrefixScanFloat4CL::execute(b3OpenCLArray& src, b3OpenCLArray& dst, int n, b3Vector3* sum) +{ + +// b3Assert( data->m_option == EXCLUSIVE ); + const unsigned int numBlocks = (const unsigned int)( (n+BLOCK_SIZE*2-1)/(BLOCK_SIZE*2) ); + + dst.resize(src.size()); + m_workBuffer->resize(src.size()); + + b3Int4 constBuffer; + constBuffer.x = n; + constBuffer.y = numBlocks; + constBuffer.z = (int)b3NextPowerOf2( numBlocks ); + + b3OpenCLArray* srcNative = &src; + b3OpenCLArray* dstNative = &dst; + + { + b3BufferInfoCL bInfo[] = { b3BufferInfoCL( dstNative->getBufferCL() ), b3BufferInfoCL( srcNative->getBufferCL() ), b3BufferInfoCL( m_workBuffer->getBufferCL() ) }; + + b3LauncherCL launcher( m_commandQueue, m_localScanKernel ,"m_localScanKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( constBuffer ); + launcher.launch1D( numBlocks*BLOCK_SIZE, BLOCK_SIZE ); + } + + { + b3BufferInfoCL bInfo[] = { b3BufferInfoCL( m_workBuffer->getBufferCL() ) }; + + b3LauncherCL launcher( m_commandQueue, m_blockSumKernel ,"m_blockSumKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( constBuffer ); + launcher.launch1D( BLOCK_SIZE, BLOCK_SIZE ); + } + + + if( numBlocks > 1 ) + { + b3BufferInfoCL bInfo[] = { b3BufferInfoCL( dstNative->getBufferCL() ), b3BufferInfoCL( m_workBuffer->getBufferCL() ) }; + b3LauncherCL launcher( m_commandQueue, m_propagationKernel ,"m_propagationKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( constBuffer ); + launcher.launch1D( (numBlocks-1)*BLOCK_SIZE, BLOCK_SIZE ); + } + + + if( sum ) + { + clFinish(m_commandQueue); + dstNative->copyToHostPointer(sum,1,n-1,true); + } + +} + + +void b3PrefixScanFloat4CL::executeHost(b3AlignedObjectArray& src, b3AlignedObjectArray& dst, int n, b3Vector3* sum) +{ + b3Vector3 s=b3MakeVector3(0,0,0); + //if( data->m_option == EXCLUSIVE ) + { + for(int i=0; i* m_workBuffer; + + + public: + + b3PrefixScanFloat4CL(cl_context ctx, cl_device_id device, cl_command_queue queue,int size=0); + + virtual ~b3PrefixScanFloat4CL(); + + void execute(b3OpenCLArray& src, b3OpenCLArray& dst, int n, b3Vector3* sum = 0); + void executeHost(b3AlignedObjectArray& src, b3AlignedObjectArray& dst, int n, b3Vector3* sum); +}; + +#endif //B3_PREFIX_SCAN_CL_H diff --git a/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3RadixSort32CL.cpp b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3RadixSort32CL.cpp new file mode 100644 index 000000000000..f11ae4bcdb6e --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3RadixSort32CL.cpp @@ -0,0 +1,710 @@ + +#include "b3RadixSort32CL.h" +#include "b3LauncherCL.h" +#include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h" +#include "b3PrefixScanCL.h" +#include "b3FillCL.h" + +#define RADIXSORT32_PATH "src/Bullet3OpenCL/ParallelPrimitives/kernels/RadixSort32Kernels.cl" + +#include "kernels/RadixSort32KernelsCL.h" + +b3RadixSort32CL::b3RadixSort32CL(cl_context ctx, cl_device_id device, cl_command_queue queue, int initialCapacity) +:m_commandQueue(queue) +{ + b3OpenCLDeviceInfo info; + b3OpenCLUtils::getDeviceInfo(device,&info); + m_deviceCPU = (info.m_deviceType & CL_DEVICE_TYPE_CPU)!=0; + + m_workBuffer1 = new b3OpenCLArray(ctx,queue); + m_workBuffer2 = new b3OpenCLArray(ctx,queue); + m_workBuffer3 = new b3OpenCLArray(ctx,queue); + m_workBuffer3a = new b3OpenCLArray(ctx,queue); + m_workBuffer4 = new b3OpenCLArray(ctx,queue); + m_workBuffer4a = new b3OpenCLArray(ctx,queue); + + + if (initialCapacity>0) + { + m_workBuffer1->resize(initialCapacity); + m_workBuffer3->resize(initialCapacity); + m_workBuffer3a->resize(initialCapacity); + m_workBuffer4->resize(initialCapacity); + m_workBuffer4a->resize(initialCapacity); + } + + m_scan = new b3PrefixScanCL(ctx,device,queue); + m_fill = new b3FillCL(ctx,device,queue); + + const char* additionalMacros = ""; + + cl_int pErrNum; + const char* kernelSource = radixSort32KernelsCL; + + cl_program sortProg = b3OpenCLUtils::compileCLProgramFromString( ctx, device, kernelSource, &pErrNum,additionalMacros, RADIXSORT32_PATH); + b3Assert(sortProg); + + m_streamCountSortDataKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, kernelSource, "StreamCountSortDataKernel", &pErrNum, sortProg,additionalMacros ); + b3Assert(m_streamCountSortDataKernel ); + + + + m_streamCountKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, kernelSource, "StreamCountKernel", &pErrNum, sortProg,additionalMacros ); + b3Assert(m_streamCountKernel); + + + + if (m_deviceCPU) + { + + m_sortAndScatterSortDataKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, kernelSource, "SortAndScatterSortDataKernelSerial", &pErrNum, sortProg,additionalMacros ); + b3Assert(m_sortAndScatterSortDataKernel); + m_sortAndScatterKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, kernelSource, "SortAndScatterKernelSerial", &pErrNum, sortProg,additionalMacros ); + b3Assert(m_sortAndScatterKernel); + } else + { + m_sortAndScatterSortDataKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, kernelSource, "SortAndScatterSortDataKernel", &pErrNum, sortProg,additionalMacros ); + b3Assert(m_sortAndScatterSortDataKernel); + m_sortAndScatterKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, kernelSource, "SortAndScatterKernel", &pErrNum, sortProg,additionalMacros ); + b3Assert(m_sortAndScatterKernel); + } + + m_prefixScanKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, kernelSource, "PrefixScanKernel", &pErrNum, sortProg,additionalMacros ); + b3Assert(m_prefixScanKernel); + +} + +b3RadixSort32CL::~b3RadixSort32CL() +{ + delete m_scan; + delete m_fill; + delete m_workBuffer1; + delete m_workBuffer2; + delete m_workBuffer3; + delete m_workBuffer3a; + delete m_workBuffer4; + delete m_workBuffer4a; + + clReleaseKernel(m_streamCountSortDataKernel); + clReleaseKernel(m_streamCountKernel); + clReleaseKernel(m_sortAndScatterSortDataKernel); + clReleaseKernel(m_sortAndScatterKernel); + clReleaseKernel(m_prefixScanKernel); +} + +void b3RadixSort32CL::executeHost(b3AlignedObjectArray& inout, int sortBits /* = 32 */) +{ + int n = inout.size(); + const int BITS_PER_PASS = 8; + const int NUM_TABLES = (1< workbuffer; + workbuffer.resize(inout.size()); + b3SortData* dst = &workbuffer[0]; + + int count=0; + for(int startBit=0; startBit> startBit) & (NUM_TABLES-1); + tables[tableIdx]++; + } +//#define TEST +#ifdef TEST + printf("histogram size=%d\n",NUM_TABLES); + for (int i=0;i> startBit) & (NUM_TABLES-1); + + dst[tables[tableIdx] + counter[tableIdx]] = src[i]; + counter[tableIdx] ++; + } + + b3Swap( src, dst ); + count++; + } + + if (count&1) + { + b3Assert(0);//need to copy + + } +} + +void b3RadixSort32CL::executeHost(b3OpenCLArray& keyValuesInOut, int sortBits /* = 32 */) +{ + + b3AlignedObjectArray inout; + keyValuesInOut.copyToHost(inout); + + executeHost(inout,sortBits); + + keyValuesInOut.copyFromHost(inout); +} + +void b3RadixSort32CL::execute(b3OpenCLArray& keysIn, b3OpenCLArray& keysOut, b3OpenCLArray& valuesIn, + b3OpenCLArray& valuesOut, int n, int sortBits) +{ + +} + +//#define DEBUG_RADIXSORT +//#define DEBUG_RADIXSORT2 + + +void b3RadixSort32CL::execute(b3OpenCLArray& keyValuesInOut, int sortBits /* = 32 */) +{ + + int originalSize = keyValuesInOut.size(); + int workingSize = originalSize; + + + int dataAlignment = DATA_ALIGNMENT; + +#ifdef DEBUG_RADIXSORT2 + b3AlignedObjectArray test2; + keyValuesInOut.copyToHost(test2); + printf("numElem = %d\n",test2.size()); + for (int i=0;i* src = 0; + + if (workingSize%dataAlignment) + { + workingSize += dataAlignment-(workingSize%dataAlignment); + m_workBuffer4->copyFromOpenCLArray(keyValuesInOut); + m_workBuffer4->resize(workingSize); + b3SortData fillValue; + fillValue.m_key = 0xffffffff; + fillValue.m_value = 0xffffffff; + +#define USE_BTFILL +#ifdef USE_BTFILL + m_fill->execute((b3OpenCLArray&)*m_workBuffer4,(b3Int2&)fillValue,workingSize-originalSize,originalSize); +#else + //fill the remaining bits (very slow way, todo: fill on GPU/OpenCL side) + + for (int i=originalSize; icopyFromHostPointer(&fillValue,1,i); + } +#endif//USE_BTFILL + + src = m_workBuffer4; + } else + { + src = &keyValuesInOut; + m_workBuffer4->resize(0); + } + + b3Assert( workingSize%DATA_ALIGNMENT == 0 ); + int minCap = NUM_BUCKET*NUM_WGS; + + + int n = workingSize; + + m_workBuffer1->resize(minCap); + m_workBuffer3->resize(workingSize); + + +// ADLASSERT( ELEMENTS_PER_WORK_ITEM == 4 ); + b3Assert( BITS_PER_PASS == 4 ); + b3Assert( WG_SIZE == 64 ); + b3Assert( (sortBits&0x3) == 0 ); + + + + b3OpenCLArray* dst = m_workBuffer3; + + b3OpenCLArray* srcHisto = m_workBuffer1; + b3OpenCLArray* destHisto = m_workBuffer2; + + + int nWGs = NUM_WGS; + b3ConstData cdata; + + { + int blockSize = ELEMENTS_PER_WORK_ITEM*WG_SIZE;//set at 256 + int nBlocks = (n+blockSize-1)/(blockSize); + cdata.m_n = n; + cdata.m_nWGs = NUM_WGS; + cdata.m_startBit = 0; + cdata.m_nBlocksPerWG = (nBlocks + cdata.m_nWGs - 1)/cdata.m_nWGs; + if( nBlocks < NUM_WGS ) + { + cdata.m_nBlocksPerWG = 1; + nWGs = nBlocks; + } + } + + int count=0; + for(int ib=0; ibsize()) + { + b3BufferInfoCL bInfo[] = { b3BufferInfoCL( src->getBufferCL(), true ), b3BufferInfoCL( srcHisto->getBufferCL() ) }; + b3LauncherCL launcher(m_commandQueue, m_streamCountSortDataKernel,"m_streamCountSortDataKernel"); + + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( cdata ); + + int num = NUM_WGS*WG_SIZE; + launcher.launch1D( num, WG_SIZE ); + } + + + +#ifdef DEBUG_RADIXSORT + b3AlignedObjectArray testHist; + srcHisto->copyToHost(testHist); + printf("ib = %d, testHist size = %d, non zero elements:\n",ib, testHist.size()); + for (int i=0;igetBufferCL() ) }; + b3LauncherCL launcher( m_commandQueue, m_prefixScanKernel,"m_prefixScanKernel" ); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( cdata ); + launcher.launch1D( 128, 128 ); + destHisto = srcHisto; + }else + { + //unsigned int sum; //for debugging + m_scan->execute(*srcHisto,*destHisto,1920,0);//,&sum); + } + + +#ifdef DEBUG_RADIXSORT + destHisto->copyToHost(testHist); + printf("ib = %d, testHist size = %d, non zero elements:\n",ib, testHist.size()); + for (int i=0;isize()) + {// local sort and distribute + b3BufferInfoCL bInfo[] = { b3BufferInfoCL( src->getBufferCL(), true ), b3BufferInfoCL( destHisto->getBufferCL(), true ), b3BufferInfoCL( dst->getBufferCL() )}; + b3LauncherCL launcher( m_commandQueue, m_sortAndScatterSortDataKernel,"m_sortAndScatterSortDataKernel" ); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( cdata ); + launcher.launch1D( nWGs*WG_SIZE, WG_SIZE ); + + } +#else + { +#define NUM_TABLES 16 +//#define SEQUENTIAL +#ifdef SEQUENTIAL + int counter2[NUM_TABLES]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + int tables[NUM_TABLES]; + int startBit = ib; + + destHisto->copyToHost(testHist); + b3AlignedObjectArray srcHost; + b3AlignedObjectArray dstHost; + dstHost.resize(src->size()); + + src->copyToHost(srcHost); + + for (int i=0;i> startBit) & (NUM_TABLES-1); + + dstHost[tables[tableIdx] + counter2[tableIdx]] = srcHost[i]; + counter2[tableIdx] ++; + } + + +#else + + int counter2[NUM_TABLES]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + int tables[NUM_TABLES]; + b3AlignedObjectArray dstHostOK; + dstHostOK.resize(src->size()); + + destHisto->copyToHost(testHist); + b3AlignedObjectArray srcHost; + src->copyToHost(srcHost); + + int blockSize = 256; + int nBlocksPerWG = cdata.m_nBlocksPerWG; + int startBit = ib; + + { + for (int i=0;i> startBit) & (NUM_TABLES-1); + + dstHostOK[tables[tableIdx] + counter2[tableIdx]] = srcHost[i]; + counter2[tableIdx] ++; + } + + + } + + + b3AlignedObjectArray dstHost; + dstHost.resize(src->size()); + + + int counter[NUM_TABLES]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + + + for (int wgIdx=0;wgIdx> startBit) & (NUM_TABLES-1); + + int destIndex = testHist[tableIdx*NUM_WGS+wgIdx] + counter[tableIdx]; + + b3SortData ok = dstHostOK[destIndex]; + + if (ok.m_key != srcHost[i].m_key) + { + printf("ok.m_key = %d, srcHost[i].m_key = %d\n", ok.m_key,srcHost[i].m_key ); + printf("(ok.m_value = %d, srcHost[i].m_value = %d)\n", ok.m_value,srcHost[i].m_value ); + } + if (ok.m_value != srcHost[i].m_value) + { + + printf("ok.m_value = %d, srcHost[i].m_value = %d\n", ok.m_value,srcHost[i].m_value ); + printf("(ok.m_key = %d, srcHost[i].m_key = %d)\n", ok.m_key,srcHost[i].m_key ); + + } + + dstHost[destIndex] = srcHost[i]; + counter[tableIdx] ++; + + } + } + } + } + } + + +#endif //SEQUENTIAL + + dst->copyFromHost(dstHost); + } +#endif//USE_GPU + + + +#ifdef DEBUG_RADIXSORT + destHisto->copyToHost(testHist); + printf("ib = %d, testHist size = %d, non zero elements:\n",ib, testHist.size()); + for (int i=0;isize()) + { + m_workBuffer4->resize(originalSize); + keyValuesInOut.copyFromOpenCLArray(*m_workBuffer4); + } + + +#ifdef DEBUG_RADIXSORT + keyValuesInOut.copyToHost(test2); + + printf("numElem = %d\n",test2.size()); + for (int i=0;i& keysInOut, int sortBits /* = 32 */) +{ + int originalSize = keysInOut.size(); + int workingSize = originalSize; + + + int dataAlignment = DATA_ALIGNMENT; + + b3OpenCLArray* src = 0; + + if (workingSize%dataAlignment) + { + workingSize += dataAlignment-(workingSize%dataAlignment); + m_workBuffer4a->copyFromOpenCLArray(keysInOut); + m_workBuffer4a->resize(workingSize); + unsigned int fillValue = 0xffffffff; + + m_fill->execute(*m_workBuffer4a,fillValue,workingSize-originalSize,originalSize); + + src = m_workBuffer4a; + } else + { + src = &keysInOut; + m_workBuffer4a->resize(0); + } + + + + b3Assert( workingSize%DATA_ALIGNMENT == 0 ); + int minCap = NUM_BUCKET*NUM_WGS; + + + int n = workingSize; + + + m_workBuffer1->resize(minCap); + m_workBuffer3->resize(workingSize); + m_workBuffer3a->resize(workingSize); + +// ADLASSERT( ELEMENTS_PER_WORK_ITEM == 4 ); + b3Assert( BITS_PER_PASS == 4 ); + b3Assert( WG_SIZE == 64 ); + b3Assert( (sortBits&0x3) == 0 ); + + + + b3OpenCLArray* dst = m_workBuffer3a; + + b3OpenCLArray* srcHisto = m_workBuffer1; + b3OpenCLArray* destHisto = m_workBuffer2; + + + int nWGs = NUM_WGS; + b3ConstData cdata; + + { + int blockSize = ELEMENTS_PER_WORK_ITEM*WG_SIZE;//set at 256 + int nBlocks = (n+blockSize-1)/(blockSize); + cdata.m_n = n; + cdata.m_nWGs = NUM_WGS; + cdata.m_startBit = 0; + cdata.m_nBlocksPerWG = (nBlocks + cdata.m_nWGs - 1)/cdata.m_nWGs; + if( nBlocks < NUM_WGS ) + { + cdata.m_nBlocksPerWG = 1; + nWGs = nBlocks; + } + } + + int count=0; + for(int ib=0; ibsize()) + { + b3BufferInfoCL bInfo[] = { b3BufferInfoCL( src->getBufferCL(), true ), b3BufferInfoCL( srcHisto->getBufferCL() ) }; + b3LauncherCL launcher(m_commandQueue, m_streamCountKernel,"m_streamCountKernel"); + + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( cdata ); + + int num = NUM_WGS*WG_SIZE; + launcher.launch1D( num, WG_SIZE ); + } + + + +//fast prefix scan is not working properly on Mac OSX yet +#ifdef __APPLE__ + bool fastScan=false; +#else + bool fastScan=!m_deviceCPU; +#endif + + if (fastScan) + {// prefix scan group histogram + b3BufferInfoCL bInfo[] = { b3BufferInfoCL( srcHisto->getBufferCL() ) }; + b3LauncherCL launcher( m_commandQueue, m_prefixScanKernel,"m_prefixScanKernel" ); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( cdata ); + launcher.launch1D( 128, 128 ); + destHisto = srcHisto; + }else + { + //unsigned int sum; //for debugging + m_scan->execute(*srcHisto,*destHisto,1920,0);//,&sum); + } + + if (src->size()) + {// local sort and distribute + b3BufferInfoCL bInfo[] = { b3BufferInfoCL( src->getBufferCL(), true ), b3BufferInfoCL( destHisto->getBufferCL(), true ), b3BufferInfoCL( dst->getBufferCL() )}; + b3LauncherCL launcher( m_commandQueue, m_sortAndScatterKernel ,"m_sortAndScatterKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( cdata ); + launcher.launch1D( nWGs*WG_SIZE, WG_SIZE ); + + } + + b3Swap(src, dst ); + b3Swap(srcHisto,destHisto); + + count++; + } + + if (count&1) + { + b3Assert(0);//need to copy from workbuffer to keyValuesInOut + } + + if (m_workBuffer4a->size()) + { + m_workBuffer4a->resize(originalSize); + keysInOut.copyFromOpenCLArray(*m_workBuffer4a); + } + +} + + + + + + + diff --git a/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3RadixSort32CL.h b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3RadixSort32CL.h new file mode 100644 index 000000000000..975bd80e5307 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/b3RadixSort32CL.h @@ -0,0 +1,95 @@ + +#ifndef B3_RADIXSORT32_H +#define B3_RADIXSORT32_H + +#include "b3OpenCLArray.h" + +struct b3SortData +{ + union + { + unsigned int m_key; + unsigned int x; + }; + + union + { + unsigned int m_value; + unsigned int y; + + }; +}; +#include "b3BufferInfoCL.h" + +class b3RadixSort32CL +{ + + b3OpenCLArray* m_workBuffer1; + b3OpenCLArray* m_workBuffer2; + + b3OpenCLArray* m_workBuffer3; + b3OpenCLArray* m_workBuffer4; + + b3OpenCLArray* m_workBuffer3a; + b3OpenCLArray* m_workBuffer4a; + + cl_command_queue m_commandQueue; + + cl_kernel m_streamCountSortDataKernel; + cl_kernel m_streamCountKernel; + + cl_kernel m_prefixScanKernel; + cl_kernel m_sortAndScatterSortDataKernel; + cl_kernel m_sortAndScatterKernel; + + + bool m_deviceCPU; + + class b3PrefixScanCL* m_scan; + class b3FillCL* m_fill; + +public: + struct b3ConstData + { + int m_n; + int m_nWGs; + int m_startBit; + int m_nBlocksPerWG; + }; + enum + { + DATA_ALIGNMENT = 256, + WG_SIZE = 64, + BLOCK_SIZE = 256, + ELEMENTS_PER_WORK_ITEM = (BLOCK_SIZE/WG_SIZE), + BITS_PER_PASS = 4, + NUM_BUCKET=(1<& keysIn, b3OpenCLArray& keysOut, b3OpenCLArray& valuesIn, + b3OpenCLArray& valuesOut, int n, int sortBits = 32); + + ///keys only + void execute(b3OpenCLArray& keysInOut, int sortBits = 32 ); + + void execute(b3OpenCLArray& keyValuesInOut, int sortBits = 32 ); + void executeHost(b3OpenCLArray& keyValuesInOut, int sortBits = 32); + void executeHost(b3AlignedObjectArray& keyValuesInOut, int sortBits = 32); + +}; +#endif //B3_RADIXSORT32_H + diff --git a/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/BoundSearchKernels.cl b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/BoundSearchKernels.cl new file mode 100644 index 000000000000..f3b4a1e8a795 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/BoundSearchKernels.cl @@ -0,0 +1,106 @@ +/* +Copyright (c) 2012 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Takahiro Harada + + +typedef unsigned int u32; +#define GET_GROUP_IDX get_group_id(0) +#define GET_LOCAL_IDX get_local_id(0) +#define GET_GLOBAL_IDX get_global_id(0) +#define GET_GROUP_SIZE get_local_size(0) +#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE) + +typedef struct +{ + u32 m_key; + u32 m_value; +}SortData; + + + +typedef struct +{ + u32 m_nSrc; + u32 m_nDst; + u32 m_padding[2]; +} ConstBuffer; + + + +__attribute__((reqd_work_group_size(64,1,1))) +__kernel +void SearchSortDataLowerKernel(__global SortData* src, __global u32 *dst, + unsigned int nSrc, unsigned int nDst) +{ + int gIdx = GET_GLOBAL_IDX; + + if( gIdx < nSrc ) + { + SortData first; first.m_key = (u32)(-1); first.m_value = (u32)(-1); + SortData end; end.m_key = nDst; end.m_value = nDst; + + SortData iData = (gIdx==0)? first: src[gIdx-1]; + SortData jData = (gIdx==nSrc)? end: src[gIdx]; + + if( iData.m_key != jData.m_key ) + { +// for(u32 k=iData.m_key+1; k<=min(jData.m_key, nDst-1); k++) + u32 k = jData.m_key; + { + dst[k] = gIdx; + } + } + } +} + + +__attribute__((reqd_work_group_size(64,1,1))) +__kernel +void SearchSortDataUpperKernel(__global SortData* src, __global u32 *dst, + unsigned int nSrc, unsigned int nDst) +{ + int gIdx = GET_GLOBAL_IDX+1; + + if( gIdx < nSrc+1 ) + { + SortData first; first.m_key = 0; first.m_value = 0; + SortData end; end.m_key = nDst; end.m_value = nDst; + + SortData iData = src[gIdx-1]; + SortData jData = (gIdx==nSrc)? end: src[gIdx]; + + if( iData.m_key != jData.m_key ) + { + u32 k = iData.m_key; + { + dst[k] = gIdx; + } + } + } +} + +__attribute__((reqd_work_group_size(64,1,1))) +__kernel +void SubtractKernel(__global u32* A, __global u32 *B, __global u32 *C, + unsigned int nSrc, unsigned int nDst) +{ + int gIdx = GET_GLOBAL_IDX; + + + if( gIdx < nDst ) + { + C[gIdx] = A[gIdx] - B[gIdx]; + } +} + diff --git a/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/BoundSearchKernelsCL.h b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/BoundSearchKernelsCL.h new file mode 100644 index 000000000000..9c9e847138b6 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/BoundSearchKernelsCL.h @@ -0,0 +1,87 @@ +//this file is autogenerated using stringify.bat (premake --stringify) in the build folder of this project +static const char* boundSearchKernelsCL= \ +"/*\n" +"Copyright (c) 2012 Advanced Micro Devices, Inc. \n" +"This software is provided 'as-is', without any express or implied warranty.\n" +"In no event will the authors be held liable for any damages arising from the use of this software.\n" +"Permission is granted to anyone to use this software for any purpose, \n" +"including commercial applications, and to alter it and redistribute it freely, \n" +"subject to the following restrictions:\n" +"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.\n" +"2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n" +"3. This notice may not be removed or altered from any source distribution.\n" +"*/\n" +"//Originally written by Takahiro Harada\n" +"typedef unsigned int u32;\n" +"#define GET_GROUP_IDX get_group_id(0)\n" +"#define GET_LOCAL_IDX get_local_id(0)\n" +"#define GET_GLOBAL_IDX get_global_id(0)\n" +"#define GET_GROUP_SIZE get_local_size(0)\n" +"#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE)\n" +"typedef struct\n" +"{\n" +" u32 m_key; \n" +" u32 m_value;\n" +"}SortData;\n" +"typedef struct\n" +"{\n" +" u32 m_nSrc;\n" +" u32 m_nDst;\n" +" u32 m_padding[2];\n" +"} ConstBuffer;\n" +"__attribute__((reqd_work_group_size(64,1,1)))\n" +"__kernel\n" +"void SearchSortDataLowerKernel(__global SortData* src, __global u32 *dst, \n" +" unsigned int nSrc, unsigned int nDst)\n" +"{\n" +" int gIdx = GET_GLOBAL_IDX;\n" +" if( gIdx < nSrc )\n" +" {\n" +" SortData first; first.m_key = (u32)(-1); first.m_value = (u32)(-1);\n" +" SortData end; end.m_key = nDst; end.m_value = nDst;\n" +" SortData iData = (gIdx==0)? first: src[gIdx-1];\n" +" SortData jData = (gIdx==nSrc)? end: src[gIdx];\n" +" if( iData.m_key != jData.m_key )\n" +" {\n" +"// for(u32 k=iData.m_key+1; k<=min(jData.m_key, nDst-1); k++)\n" +" u32 k = jData.m_key;\n" +" {\n" +" dst[k] = gIdx;\n" +" }\n" +" }\n" +" }\n" +"}\n" +"__attribute__((reqd_work_group_size(64,1,1)))\n" +"__kernel\n" +"void SearchSortDataUpperKernel(__global SortData* src, __global u32 *dst, \n" +" unsigned int nSrc, unsigned int nDst)\n" +"{\n" +" int gIdx = GET_GLOBAL_IDX+1;\n" +" if( gIdx < nSrc+1 )\n" +" {\n" +" SortData first; first.m_key = 0; first.m_value = 0;\n" +" SortData end; end.m_key = nDst; end.m_value = nDst;\n" +" SortData iData = src[gIdx-1];\n" +" SortData jData = (gIdx==nSrc)? end: src[gIdx];\n" +" if( iData.m_key != jData.m_key )\n" +" {\n" +" u32 k = iData.m_key;\n" +" {\n" +" dst[k] = gIdx;\n" +" }\n" +" }\n" +" }\n" +"}\n" +"__attribute__((reqd_work_group_size(64,1,1)))\n" +"__kernel\n" +"void SubtractKernel(__global u32* A, __global u32 *B, __global u32 *C, \n" +" unsigned int nSrc, unsigned int nDst)\n" +"{\n" +" int gIdx = GET_GLOBAL_IDX;\n" +" \n" +" if( gIdx < nDst )\n" +" {\n" +" C[gIdx] = A[gIdx] - B[gIdx];\n" +" }\n" +"}\n" +; diff --git a/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/CopyKernels.cl b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/CopyKernels.cl new file mode 100644 index 000000000000..2eee5752ecfb --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/CopyKernels.cl @@ -0,0 +1,128 @@ +/* +Copyright (c) 2012 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Takahiro Harada + +#pragma OPENCL EXTENSION cl_amd_printf : enable +#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable + +typedef unsigned int u32; +#define GET_GROUP_IDX get_group_id(0) +#define GET_LOCAL_IDX get_local_id(0) +#define GET_GLOBAL_IDX get_global_id(0) +#define GET_GROUP_SIZE get_local_size(0) +#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE) +#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE) +#define AtomInc(x) atom_inc(&(x)) +#define AtomInc1(x, out) out = atom_inc(&(x)) + +#define make_uint4 (uint4) +#define make_uint2 (uint2) +#define make_int2 (int2) + +typedef struct +{ + int m_n; + int m_padding[3]; +} ConstBuffer; + + + +__kernel +__attribute__((reqd_work_group_size(64,1,1))) +void Copy1F4Kernel(__global float4* dst, __global float4* src, + ConstBuffer cb) +{ + int gIdx = GET_GLOBAL_IDX; + + if( gIdx < cb.m_n ) + { + float4 a0 = src[gIdx]; + + dst[ gIdx ] = a0; + } +} + +__kernel +__attribute__((reqd_work_group_size(64,1,1))) +void Copy2F4Kernel(__global float4* dst, __global float4* src, + ConstBuffer cb) +{ + int gIdx = GET_GLOBAL_IDX; + + if( 2*gIdx <= cb.m_n ) + { + float4 a0 = src[gIdx*2+0]; + float4 a1 = src[gIdx*2+1]; + + dst[ gIdx*2+0 ] = a0; + dst[ gIdx*2+1 ] = a1; + } +} + +__kernel +__attribute__((reqd_work_group_size(64,1,1))) +void Copy4F4Kernel(__global float4* dst, __global float4* src, + ConstBuffer cb) +{ + int gIdx = GET_GLOBAL_IDX; + + if( 4*gIdx <= cb.m_n ) + { + int idx0 = gIdx*4+0; + int idx1 = gIdx*4+1; + int idx2 = gIdx*4+2; + int idx3 = gIdx*4+3; + + float4 a0 = src[idx0]; + float4 a1 = src[idx1]; + float4 a2 = src[idx2]; + float4 a3 = src[idx3]; + + dst[ idx0 ] = a0; + dst[ idx1 ] = a1; + dst[ idx2 ] = a2; + dst[ idx3 ] = a3; + } +} + +__kernel +__attribute__((reqd_work_group_size(64,1,1))) +void CopyF1Kernel(__global float* dstF1, __global float* srcF1, + ConstBuffer cb) +{ + int gIdx = GET_GLOBAL_IDX; + + if( gIdx < cb.m_n ) + { + float a0 = srcF1[gIdx]; + + dstF1[ gIdx ] = a0; + } +} + +__kernel +__attribute__((reqd_work_group_size(64,1,1))) +void CopyF2Kernel(__global float2* dstF2, __global float2* srcF2, + ConstBuffer cb) +{ + int gIdx = GET_GLOBAL_IDX; + + if( gIdx < cb.m_n ) + { + float2 a0 = srcF2[gIdx]; + + dstF2[ gIdx ] = a0; + } +} + diff --git a/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/CopyKernelsCL.h b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/CopyKernelsCL.h new file mode 100644 index 000000000000..e5670e3cd3dd --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/CopyKernelsCL.h @@ -0,0 +1,132 @@ +//this file is autogenerated using stringify.bat (premake --stringify) in the build folder of this project +static const char* copyKernelsCL= \ +"/*\n" +"Copyright (c) 2012 Advanced Micro Devices, Inc. \n" +"\n" +"This software is provided 'as-is', without any express or implied warranty.\n" +"In no event will the authors be held liable for any damages arising from the use of this software.\n" +"Permission is granted to anyone to use this software for any purpose, \n" +"including commercial applications, and to alter it and redistribute it freely, \n" +"subject to the following restrictions:\n" +"\n" +"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.\n" +"2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n" +"3. This notice may not be removed or altered from any source distribution.\n" +"*/\n" +"//Originally written by Takahiro Harada\n" +"\n" +"#pragma OPENCL EXTENSION cl_amd_printf : enable\n" +"#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable\n" +"\n" +"typedef unsigned int u32;\n" +"#define GET_GROUP_IDX get_group_id(0)\n" +"#define GET_LOCAL_IDX get_local_id(0)\n" +"#define GET_GLOBAL_IDX get_global_id(0)\n" +"#define GET_GROUP_SIZE get_local_size(0)\n" +"#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE)\n" +"#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE)\n" +"#define AtomInc(x) atom_inc(&(x))\n" +"#define AtomInc1(x, out) out = atom_inc(&(x))\n" +"\n" +"#define make_uint4 (uint4)\n" +"#define make_uint2 (uint2)\n" +"#define make_int2 (int2)\n" +"\n" +"typedef struct\n" +"{\n" +" int m_n;\n" +" int m_padding[3];\n" +"} ConstBuffer;\n" +"\n" +"\n" +"\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(64,1,1)))\n" +"void Copy1F4Kernel(__global float4* dst, __global float4* src, \n" +" ConstBuffer cb)\n" +"{\n" +" int gIdx = GET_GLOBAL_IDX;\n" +"\n" +" if( gIdx < cb.m_n )\n" +" {\n" +" float4 a0 = src[gIdx];\n" +"\n" +" dst[ gIdx ] = a0;\n" +" }\n" +"}\n" +"\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(64,1,1)))\n" +"void Copy2F4Kernel(__global float4* dst, __global float4* src, \n" +" ConstBuffer cb)\n" +"{\n" +" int gIdx = GET_GLOBAL_IDX;\n" +"\n" +" if( 2*gIdx <= cb.m_n )\n" +" {\n" +" float4 a0 = src[gIdx*2+0];\n" +" float4 a1 = src[gIdx*2+1];\n" +"\n" +" dst[ gIdx*2+0 ] = a0;\n" +" dst[ gIdx*2+1 ] = a1;\n" +" }\n" +"}\n" +"\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(64,1,1)))\n" +"void Copy4F4Kernel(__global float4* dst, __global float4* src, \n" +" ConstBuffer cb)\n" +"{\n" +" int gIdx = GET_GLOBAL_IDX;\n" +"\n" +" if( 4*gIdx <= cb.m_n )\n" +" {\n" +" int idx0 = gIdx*4+0;\n" +" int idx1 = gIdx*4+1;\n" +" int idx2 = gIdx*4+2;\n" +" int idx3 = gIdx*4+3;\n" +"\n" +" float4 a0 = src[idx0];\n" +" float4 a1 = src[idx1];\n" +" float4 a2 = src[idx2];\n" +" float4 a3 = src[idx3];\n" +"\n" +" dst[ idx0 ] = a0;\n" +" dst[ idx1 ] = a1;\n" +" dst[ idx2 ] = a2;\n" +" dst[ idx3 ] = a3;\n" +" }\n" +"}\n" +"\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(64,1,1)))\n" +"void CopyF1Kernel(__global float* dstF1, __global float* srcF1, \n" +" ConstBuffer cb)\n" +"{\n" +" int gIdx = GET_GLOBAL_IDX;\n" +"\n" +" if( gIdx < cb.m_n )\n" +" {\n" +" float a0 = srcF1[gIdx];\n" +"\n" +" dstF1[ gIdx ] = a0;\n" +" }\n" +"}\n" +"\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(64,1,1)))\n" +"void CopyF2Kernel(__global float2* dstF2, __global float2* srcF2, \n" +" ConstBuffer cb)\n" +"{\n" +" int gIdx = GET_GLOBAL_IDX;\n" +"\n" +" if( gIdx < cb.m_n )\n" +" {\n" +" float2 a0 = srcF2[gIdx];\n" +"\n" +" dstF2[ gIdx ] = a0;\n" +" }\n" +"}\n" +"\n" +"\n" +; diff --git a/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/FillKernels.cl b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/FillKernels.cl new file mode 100644 index 000000000000..71c31075dd76 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/FillKernels.cl @@ -0,0 +1,107 @@ +/* +Copyright (c) 2012 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Takahiro Harada + + +#pragma OPENCL EXTENSION cl_amd_printf : enable +#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable + +typedef unsigned int u32; +#define GET_GROUP_IDX get_group_id(0) +#define GET_LOCAL_IDX get_local_id(0) +#define GET_GLOBAL_IDX get_global_id(0) +#define GET_GROUP_SIZE get_local_size(0) +#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE) +#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE) +#define AtomInc(x) atom_inc(&(x)) +#define AtomInc1(x, out) out = atom_inc(&(x)) + +#define make_uint4 (uint4) +#define make_uint2 (uint2) +#define make_int2 (int2) + +typedef struct +{ + union + { + int4 m_data; + uint4 m_unsignedData; + float m_floatData; + }; + int m_offset; + int m_n; + int m_padding[2]; +} ConstBuffer; + + +__kernel +__attribute__((reqd_work_group_size(64,1,1))) +void FillIntKernel(__global int* dstInt, int num_elements, int value, const int offset) +{ + int gIdx = GET_GLOBAL_IDX; + + if( gIdx < num_elements ) + { + dstInt[ offset+gIdx ] = value; + } +} + +__kernel +__attribute__((reqd_work_group_size(64,1,1))) +void FillFloatKernel(__global float* dstFloat, int num_elements, float value, const int offset) +{ + int gIdx = GET_GLOBAL_IDX; + + if( gIdx < num_elements ) + { + dstFloat[ offset+gIdx ] = value; + } +} + +__kernel +__attribute__((reqd_work_group_size(64,1,1))) +void FillUnsignedIntKernel(__global unsigned int* dstInt, const int num, const unsigned int value, const int offset) +{ + int gIdx = GET_GLOBAL_IDX; + + if( gIdx < num ) + { + dstInt[ offset+gIdx ] = value; + } +} + +__kernel +__attribute__((reqd_work_group_size(64,1,1))) +void FillInt2Kernel(__global int2* dstInt2, const int num, const int2 value, const int offset) +{ + int gIdx = GET_GLOBAL_IDX; + + if( gIdx < num ) + { + dstInt2[ gIdx + offset] = make_int2( value.x, value.y ); + } +} + +__kernel +__attribute__((reqd_work_group_size(64,1,1))) +void FillInt4Kernel(__global int4* dstInt4, const int num, const int4 value, const int offset) +{ + int gIdx = GET_GLOBAL_IDX; + + if( gIdx < num ) + { + dstInt4[ offset+gIdx ] = value; + } +} + diff --git a/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/FillKernelsCL.h b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/FillKernelsCL.h new file mode 100644 index 000000000000..4f8b96e48954 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/FillKernelsCL.h @@ -0,0 +1,91 @@ +//this file is autogenerated using stringify.bat (premake --stringify) in the build folder of this project +static const char* fillKernelsCL= \ +"/*\n" +"Copyright (c) 2012 Advanced Micro Devices, Inc. \n" +"This software is provided 'as-is', without any express or implied warranty.\n" +"In no event will the authors be held liable for any damages arising from the use of this software.\n" +"Permission is granted to anyone to use this software for any purpose, \n" +"including commercial applications, and to alter it and redistribute it freely, \n" +"subject to the following restrictions:\n" +"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.\n" +"2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n" +"3. This notice may not be removed or altered from any source distribution.\n" +"*/\n" +"//Originally written by Takahiro Harada\n" +"#pragma OPENCL EXTENSION cl_amd_printf : enable\n" +"#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable\n" +"typedef unsigned int u32;\n" +"#define GET_GROUP_IDX get_group_id(0)\n" +"#define GET_LOCAL_IDX get_local_id(0)\n" +"#define GET_GLOBAL_IDX get_global_id(0)\n" +"#define GET_GROUP_SIZE get_local_size(0)\n" +"#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE)\n" +"#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE)\n" +"#define AtomInc(x) atom_inc(&(x))\n" +"#define AtomInc1(x, out) out = atom_inc(&(x))\n" +"#define make_uint4 (uint4)\n" +"#define make_uint2 (uint2)\n" +"#define make_int2 (int2)\n" +"typedef struct\n" +"{\n" +" union\n" +" {\n" +" int4 m_data;\n" +" uint4 m_unsignedData;\n" +" float m_floatData;\n" +" };\n" +" int m_offset;\n" +" int m_n;\n" +" int m_padding[2];\n" +"} ConstBuffer;\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(64,1,1)))\n" +"void FillIntKernel(__global int* dstInt, int num_elements, int value, const int offset)\n" +"{\n" +" int gIdx = GET_GLOBAL_IDX;\n" +" if( gIdx < num_elements )\n" +" {\n" +" dstInt[ offset+gIdx ] = value;\n" +" }\n" +"}\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(64,1,1)))\n" +"void FillFloatKernel(__global float* dstFloat, int num_elements, float value, const int offset)\n" +"{\n" +" int gIdx = GET_GLOBAL_IDX;\n" +" if( gIdx < num_elements )\n" +" {\n" +" dstFloat[ offset+gIdx ] = value;\n" +" }\n" +"}\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(64,1,1)))\n" +"void FillUnsignedIntKernel(__global unsigned int* dstInt, const int num, const unsigned int value, const int offset)\n" +"{\n" +" int gIdx = GET_GLOBAL_IDX;\n" +" if( gIdx < num )\n" +" {\n" +" dstInt[ offset+gIdx ] = value;\n" +" }\n" +"}\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(64,1,1)))\n" +"void FillInt2Kernel(__global int2* dstInt2, const int num, const int2 value, const int offset)\n" +"{\n" +" int gIdx = GET_GLOBAL_IDX;\n" +" if( gIdx < num )\n" +" {\n" +" dstInt2[ gIdx + offset] = make_int2( value.x, value.y );\n" +" }\n" +"}\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(64,1,1)))\n" +"void FillInt4Kernel(__global int4* dstInt4, const int num, const int4 value, const int offset)\n" +"{\n" +" int gIdx = GET_GLOBAL_IDX;\n" +" if( gIdx < num )\n" +" {\n" +" dstInt4[ offset+gIdx ] = value;\n" +" }\n" +"}\n" +; diff --git a/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/PrefixScanFloat4Kernels.cl b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/PrefixScanFloat4Kernels.cl new file mode 100644 index 000000000000..c9da79854a2f --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/PrefixScanFloat4Kernels.cl @@ -0,0 +1,154 @@ +/* +Copyright (c) 2012 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Takahiro Harada + + +typedef unsigned int u32; +#define GET_GROUP_IDX get_group_id(0) +#define GET_LOCAL_IDX get_local_id(0) +#define GET_GLOBAL_IDX get_global_id(0) +#define GET_GROUP_SIZE get_local_size(0) +#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE) + +// takahiro end +#define WG_SIZE 128 +#define m_numElems x +#define m_numBlocks y +#define m_numScanBlocks z + +/*typedef struct +{ + uint m_numElems; + uint m_numBlocks; + uint m_numScanBlocks; + uint m_padding[1]; +} ConstBuffer; +*/ + +float4 ScanExclusiveFloat4(__local float4* data, u32 n, int lIdx, int lSize) +{ + float4 blocksum; + int offset = 1; + for(int nActive=n>>1; nActive>0; nActive>>=1, offset<<=1) + { + GROUP_LDS_BARRIER; + for(int iIdx=lIdx; iIdx>= 1; + for(int nActive=1; nActive>=1 ) + { + GROUP_LDS_BARRIER; + for( int iIdx = lIdx; iIdx>1; nActive>0; nActive>>=1, offset<<=1) + { + GROUP_LDS_BARRIER; + for(int iIdx=lIdx; iIdx>= 1; + for(int nActive=1; nActive>=1 ) + { + GROUP_LDS_BARRIER; + for( int iIdx = lIdx; iIdx>1; nActive>0; nActive>>=1, offset<<=1)\n" +" {\n" +" GROUP_LDS_BARRIER;\n" +" for(int iIdx=lIdx; iIdx>= 1;\n" +" for(int nActive=1; nActive>=1 )\n" +" {\n" +" GROUP_LDS_BARRIER;\n" +" for( int iIdx = lIdx; iIdx>1; nActive>0; nActive>>=1, offset<<=1)\n" +" {\n" +" GROUP_LDS_BARRIER;\n" +" for(int iIdx=lIdx; iIdx>= 1;\n" +" for(int nActive=1; nActive>=1 )\n" +" {\n" +" GROUP_LDS_BARRIER;\n" +" for( int iIdx = lIdx; iIdx 64 ) + { + sorterSharedMemory[idx] += sorterSharedMemory[idx-64]; + GROUP_MEM_FENCE; + } + + sorterSharedMemory[idx-1] += sorterSharedMemory[idx-2]; + GROUP_MEM_FENCE; + } +#else + if( lIdx < 64 ) + { + sorterSharedMemory[idx] += sorterSharedMemory[idx-1]; + GROUP_MEM_FENCE; + sorterSharedMemory[idx] += sorterSharedMemory[idx-2]; + GROUP_MEM_FENCE; + sorterSharedMemory[idx] += sorterSharedMemory[idx-4]; + GROUP_MEM_FENCE; + sorterSharedMemory[idx] += sorterSharedMemory[idx-8]; + GROUP_MEM_FENCE; + sorterSharedMemory[idx] += sorterSharedMemory[idx-16]; + GROUP_MEM_FENCE; + sorterSharedMemory[idx] += sorterSharedMemory[idx-32]; + GROUP_MEM_FENCE; + if( wgSize > 64 ) + { + sorterSharedMemory[idx] += sorterSharedMemory[idx-64]; + GROUP_MEM_FENCE; + } + + sorterSharedMemory[idx-1] += sorterSharedMemory[idx-2]; + GROUP_MEM_FENCE; + } +#endif + } + + GROUP_LDS_BARRIER; + + *totalSum = sorterSharedMemory[wgSize*2-1]; + u32 addValue = sorterSharedMemory[lIdx+wgSize-1]; + return addValue; +} + +//__attribute__((reqd_work_group_size(128,1,1))) +uint4 localPrefixSum128V( uint4 pData, uint lIdx, uint* totalSum, __local u32* sorterSharedMemory ) +{ + u32 s4 = prefixScanVectorEx( &pData ); + u32 rank = localPrefixSum( s4, lIdx, totalSum, sorterSharedMemory, 128 ); + return pData + make_uint4( rank, rank, rank, rank ); +} + + +//__attribute__((reqd_work_group_size(64,1,1))) +uint4 localPrefixSum64V( uint4 pData, uint lIdx, uint* totalSum, __local u32* sorterSharedMemory ) +{ + u32 s4 = prefixScanVectorEx( &pData ); + u32 rank = localPrefixSum( s4, lIdx, totalSum, sorterSharedMemory, 64 ); + return pData + make_uint4( rank, rank, rank, rank ); +} + +u32 unpack4Key( u32 key, int keyIdx ){ return (key>>(keyIdx*8)) & 0xff;} + +u32 bit8Scan(u32 v) +{ + return (v<<8) + (v<<16) + (v<<24); +} + +//=== + + + + +#define MY_HISTOGRAM(idx) localHistogramMat[(idx)*WG_SIZE+lIdx] + + +__kernel +__attribute__((reqd_work_group_size(WG_SIZE,1,1))) +void StreamCountKernel( __global u32* gSrc, __global u32* histogramOut, int4 cb ) +{ + __local u32 localHistogramMat[NUM_BUCKET*WG_SIZE]; + + u32 gIdx = GET_GLOBAL_IDX; + u32 lIdx = GET_LOCAL_IDX; + u32 wgIdx = GET_GROUP_IDX; + u32 wgSize = GET_GROUP_SIZE; + const int startBit = cb.m_startBit; + const int n = cb.m_n; + const int nWGs = cb.m_nWGs; + const int nBlocksPerWG = cb.m_nBlocksPerWG; + + for(int i=0; i>startBit) & 0xf; +#if defined(NV_GPU) + MY_HISTOGRAM( localKey )++; +#else + AtomInc( MY_HISTOGRAM( localKey ) ); +#endif + } + } + } + + GROUP_LDS_BARRIER; + + if( lIdx < NUM_BUCKET ) + { + u32 sum = 0; + for(int i=0; i>startBit) & 0xf; +#if defined(NV_GPU) + MY_HISTOGRAM( localKey )++; +#else + AtomInc( MY_HISTOGRAM( localKey ) ); +#endif + } + } + } + + GROUP_LDS_BARRIER; + + if( lIdx < NUM_BUCKET ) + { + u32 sum = 0; + for(int i=0; i>startBit) & mask, (sortData[1]>>startBit) & mask, (sortData[2]>>startBit) & mask, (sortData[3]>>startBit) & mask ); + uint4 prefixSum = SELECT_UINT4( make_uint4(1,1,1,1), make_uint4(0,0,0,0), cmpResult != make_uint4(0,0,0,0) ); + u32 total; + prefixSum = localPrefixSum64V( prefixSum, lIdx, &total, ldsSortData ); + { + uint4 localAddr = make_uint4(lIdx*4+0,lIdx*4+1,lIdx*4+2,lIdx*4+3); + uint4 dstAddr = localAddr - prefixSum + make_uint4( total, total, total, total ); + dstAddr = SELECT_UINT4( prefixSum, dstAddr, cmpResult != make_uint4(0, 0, 0, 0) ); + + GROUP_LDS_BARRIER; + + ldsSortData[dstAddr.x] = sortData[0]; + ldsSortData[dstAddr.y] = sortData[1]; + ldsSortData[dstAddr.z] = sortData[2]; + ldsSortData[dstAddr.w] = sortData[3]; + + GROUP_LDS_BARRIER; + + sortData[0] = ldsSortData[localAddr.x]; + sortData[1] = ldsSortData[localAddr.y]; + sortData[2] = ldsSortData[localAddr.z]; + sortData[3] = ldsSortData[localAddr.w]; + + GROUP_LDS_BARRIER; + } + } +} + +// 2 scan, 2 exchange +void sort4Bits1(u32 sortData[4], int startBit, int lIdx, __local u32* ldsSortData) +{ + for(uint ibit=0; ibit>(startBit+ibit)) & 0x3, + (sortData[1]>>(startBit+ibit)) & 0x3, + (sortData[2]>>(startBit+ibit)) & 0x3, + (sortData[3]>>(startBit+ibit)) & 0x3); + + u32 key4; + u32 sKeyPacked[4] = { 0, 0, 0, 0 }; + { + sKeyPacked[0] |= 1<<(8*b.x); + sKeyPacked[1] |= 1<<(8*b.y); + sKeyPacked[2] |= 1<<(8*b.z); + sKeyPacked[3] |= 1<<(8*b.w); + + key4 = sKeyPacked[0] + sKeyPacked[1] + sKeyPacked[2] + sKeyPacked[3]; + } + + u32 rankPacked; + u32 sumPacked; + { + rankPacked = localPrefixSum( key4, lIdx, &sumPacked, ldsSortData, WG_SIZE ); + } + + GROUP_LDS_BARRIER; + + u32 newOffset[4] = { 0,0,0,0 }; + { + u32 sumScanned = bit8Scan( sumPacked ); + + u32 scannedKeys[4]; + scannedKeys[0] = 1<<(8*b.x); + scannedKeys[1] = 1<<(8*b.y); + scannedKeys[2] = 1<<(8*b.z); + scannedKeys[3] = 1<<(8*b.w); + { // 4 scans at once + u32 sum4 = 0; + for(int ie=0; ie<4; ie++) + { + u32 tmp = scannedKeys[ie]; + scannedKeys[ie] = sum4; + sum4 += tmp; + } + } + + { + u32 sumPlusRank = sumScanned + rankPacked; + { u32 ie = b.x; + scannedKeys[0] += sumPlusRank; + newOffset[0] = unpack4Key( scannedKeys[0], ie ); + } + { u32 ie = b.y; + scannedKeys[1] += sumPlusRank; + newOffset[1] = unpack4Key( scannedKeys[1], ie ); + } + { u32 ie = b.z; + scannedKeys[2] += sumPlusRank; + newOffset[2] = unpack4Key( scannedKeys[2], ie ); + } + { u32 ie = b.w; + scannedKeys[3] += sumPlusRank; + newOffset[3] = unpack4Key( scannedKeys[3], ie ); + } + } + } + + + GROUP_LDS_BARRIER; + + { + ldsSortData[newOffset[0]] = sortData[0]; + ldsSortData[newOffset[1]] = sortData[1]; + ldsSortData[newOffset[2]] = sortData[2]; + ldsSortData[newOffset[3]] = sortData[3]; + + GROUP_LDS_BARRIER; + + u32 dstAddr = 4*lIdx; + sortData[0] = ldsSortData[dstAddr+0]; + sortData[1] = ldsSortData[dstAddr+1]; + sortData[2] = ldsSortData[dstAddr+2]; + sortData[3] = ldsSortData[dstAddr+3]; + + GROUP_LDS_BARRIER; + } + } +} + +#define SET_HISTOGRAM(setIdx, key) ldsSortData[(setIdx)*NUM_BUCKET+key] + +__kernel +__attribute__((reqd_work_group_size(WG_SIZE,1,1))) +void SortAndScatterKernel( __global const u32* restrict gSrc, __global const u32* rHistogram, __global u32* restrict gDst, int4 cb ) +{ + __local u32 ldsSortData[WG_SIZE*ELEMENTS_PER_WORK_ITEM+16]; + __local u32 localHistogramToCarry[NUM_BUCKET]; + __local u32 localHistogram[NUM_BUCKET*2]; + + u32 gIdx = GET_GLOBAL_IDX; + u32 lIdx = GET_LOCAL_IDX; + u32 wgIdx = GET_GROUP_IDX; + u32 wgSize = GET_GROUP_SIZE; + + const int n = cb.m_n; + const int nWGs = cb.m_nWGs; + const int startBit = cb.m_startBit; + const int nBlocksPerWG = cb.m_nBlocksPerWG; + + if( lIdx < (NUM_BUCKET) ) + { + localHistogramToCarry[lIdx] = rHistogram[lIdx*nWGs + wgIdx]; + } + + GROUP_LDS_BARRIER; + + const int blockSize = ELEMENTS_PER_WORK_ITEM*WG_SIZE; + + int nBlocks = n/blockSize - nBlocksPerWG*wgIdx; + + int addr = blockSize*nBlocksPerWG*wgIdx + ELEMENTS_PER_WORK_ITEM*lIdx; + + for(int iblock=0; iblock>startBit) & 0xf; + + { // create histogram + u32 setIdx = lIdx/16; + if( lIdx < NUM_BUCKET ) + { + localHistogram[lIdx] = 0; + } + ldsSortData[lIdx] = 0; + GROUP_LDS_BARRIER; + + for(int i=0; i>(startBit+ibit)) & 0x3, + (sortData[1]>>(startBit+ibit)) & 0x3, + (sortData[2]>>(startBit+ibit)) & 0x3, + (sortData[3]>>(startBit+ibit)) & 0x3); + + u32 key4; + u32 sKeyPacked[4] = { 0, 0, 0, 0 }; + { + sKeyPacked[0] |= 1<<(8*b.x); + sKeyPacked[1] |= 1<<(8*b.y); + sKeyPacked[2] |= 1<<(8*b.z); + sKeyPacked[3] |= 1<<(8*b.w); + + key4 = sKeyPacked[0] + sKeyPacked[1] + sKeyPacked[2] + sKeyPacked[3]; + } + + u32 rankPacked; + u32 sumPacked; + { + rankPacked = localPrefixSum( key4, lIdx, &sumPacked, ldsSortData, WG_SIZE ); + } + + GROUP_LDS_BARRIER; + + u32 newOffset[4] = { 0,0,0,0 }; + { + u32 sumScanned = bit8Scan( sumPacked ); + + u32 scannedKeys[4]; + scannedKeys[0] = 1<<(8*b.x); + scannedKeys[1] = 1<<(8*b.y); + scannedKeys[2] = 1<<(8*b.z); + scannedKeys[3] = 1<<(8*b.w); + { // 4 scans at once + u32 sum4 = 0; + for(int ie=0; ie<4; ie++) + { + u32 tmp = scannedKeys[ie]; + scannedKeys[ie] = sum4; + sum4 += tmp; + } + } + + { + u32 sumPlusRank = sumScanned + rankPacked; + { u32 ie = b.x; + scannedKeys[0] += sumPlusRank; + newOffset[0] = unpack4Key( scannedKeys[0], ie ); + } + { u32 ie = b.y; + scannedKeys[1] += sumPlusRank; + newOffset[1] = unpack4Key( scannedKeys[1], ie ); + } + { u32 ie = b.z; + scannedKeys[2] += sumPlusRank; + newOffset[2] = unpack4Key( scannedKeys[2], ie ); + } + { u32 ie = b.w; + scannedKeys[3] += sumPlusRank; + newOffset[3] = unpack4Key( scannedKeys[3], ie ); + } + } + } + + + GROUP_LDS_BARRIER; + + { + ldsSortData[newOffset[0]] = sortData[0]; + ldsSortData[newOffset[1]] = sortData[1]; + ldsSortData[newOffset[2]] = sortData[2]; + ldsSortData[newOffset[3]] = sortData[3]; + + ldsSortVal[newOffset[0]] = sortVal[0]; + ldsSortVal[newOffset[1]] = sortVal[1]; + ldsSortVal[newOffset[2]] = sortVal[2]; + ldsSortVal[newOffset[3]] = sortVal[3]; + + GROUP_LDS_BARRIER; + + u32 dstAddr = 4*lIdx; + sortData[0] = ldsSortData[dstAddr+0]; + sortData[1] = ldsSortData[dstAddr+1]; + sortData[2] = ldsSortData[dstAddr+2]; + sortData[3] = ldsSortData[dstAddr+3]; + + sortVal[0] = ldsSortVal[dstAddr+0]; + sortVal[1] = ldsSortVal[dstAddr+1]; + sortVal[2] = ldsSortVal[dstAddr+2]; + sortVal[3] = ldsSortVal[dstAddr+3]; + + GROUP_LDS_BARRIER; + } + } +} + + + + +__kernel +__attribute__((reqd_work_group_size(WG_SIZE,1,1))) +void SortAndScatterSortDataKernel( __global const SortDataCL* restrict gSrc, __global const u32* rHistogram, __global SortDataCL* restrict gDst, int4 cb) +{ + __local int ldsSortData[WG_SIZE*ELEMENTS_PER_WORK_ITEM+16]; + __local int ldsSortVal[WG_SIZE*ELEMENTS_PER_WORK_ITEM+16]; + __local u32 localHistogramToCarry[NUM_BUCKET]; + __local u32 localHistogram[NUM_BUCKET*2]; + + u32 gIdx = GET_GLOBAL_IDX; + u32 lIdx = GET_LOCAL_IDX; + u32 wgIdx = GET_GROUP_IDX; + u32 wgSize = GET_GROUP_SIZE; + + const int n = cb.m_n; + const int nWGs = cb.m_nWGs; + const int startBit = cb.m_startBit; + const int nBlocksPerWG = cb.m_nBlocksPerWG; + + if( lIdx < (NUM_BUCKET) ) + { + localHistogramToCarry[lIdx] = rHistogram[lIdx*nWGs + wgIdx]; + } + + GROUP_LDS_BARRIER; + + + const int blockSize = ELEMENTS_PER_WORK_ITEM*WG_SIZE; + + int nBlocks = n/blockSize - nBlocksPerWG*wgIdx; + + int addr = blockSize*nBlocksPerWG*wgIdx + ELEMENTS_PER_WORK_ITEM*lIdx; + + for(int iblock=0; iblock>startBit) & 0xf; + + { // create histogram + u32 setIdx = lIdx/16; + if( lIdx < NUM_BUCKET ) + { + localHistogram[lIdx] = 0; + } + ldsSortData[lIdx] = 0; + GROUP_LDS_BARRIER; + + for(int i=0; i0) + return; + + for (int c=0;c>startBit) & 0xf;//0xf = NUM_TABLES-1 + gDst[rHistogram[tableIdx*nWGs+wgIdx] + counter[tableIdx]] = gSrc[i]; + counter[tableIdx] ++; + } + } + } + } + +} + + +__kernel +__attribute__((reqd_work_group_size(WG_SIZE,1,1))) +void SortAndScatterKernelSerial( __global const u32* restrict gSrc, __global const u32* rHistogram, __global u32* restrict gDst, int4 cb ) +{ + + u32 gIdx = GET_GLOBAL_IDX; + u32 realLocalIdx = GET_LOCAL_IDX; + u32 wgIdx = GET_GROUP_IDX; + u32 wgSize = GET_GROUP_SIZE; + const int startBit = cb.m_startBit; + const int n = cb.m_n; + const int nWGs = cb.m_nWGs; + const int nBlocksPerWG = cb.m_nBlocksPerWG; + + int counter[NUM_BUCKET]; + + if (realLocalIdx>0) + return; + + for (int c=0;c>startBit) & 0xf;//0xf = NUM_TABLES-1 + gDst[rHistogram[tableIdx*nWGs+wgIdx] + counter[tableIdx]] = gSrc[i]; + counter[tableIdx] ++; + } + } + } + } + +} \ No newline at end of file diff --git a/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/RadixSort32KernelsCL.h b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/RadixSort32KernelsCL.h new file mode 100644 index 000000000000..8876c16aa641 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/ParallelPrimitives/kernels/RadixSort32KernelsCL.h @@ -0,0 +1,910 @@ +//this file is autogenerated using stringify.bat (premake --stringify) in the build folder of this project +static const char* radixSort32KernelsCL= \ +"/*\n" +"Bullet Continuous Collision Detection and Physics Library\n" +"Copyright (c) 2011 Advanced Micro Devices, Inc. http://bulletphysics.org\n" +"This software is provided 'as-is', without any express or implied warranty.\n" +"In no event will the authors be held liable for any damages arising from the use of this software.\n" +"Permission is granted to anyone to use this software for any purpose, \n" +"including commercial applications, and to alter it and redistribute it freely, \n" +"subject to the following restrictions:\n" +"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.\n" +"2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n" +"3. This notice may not be removed or altered from any source distribution.\n" +"*/\n" +"//Author Takahiro Harada\n" +"//#pragma OPENCL EXTENSION cl_amd_printf : enable\n" +"#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable\n" +"#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable\n" +"typedef unsigned int u32;\n" +"#define GET_GROUP_IDX get_group_id(0)\n" +"#define GET_LOCAL_IDX get_local_id(0)\n" +"#define GET_GLOBAL_IDX get_global_id(0)\n" +"#define GET_GROUP_SIZE get_local_size(0)\n" +"#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE)\n" +"#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE)\n" +"#define AtomInc(x) atom_inc(&(x))\n" +"#define AtomInc1(x, out) out = atom_inc(&(x))\n" +"#define AtomAdd(x, value) atom_add(&(x), value)\n" +"#define SELECT_UINT4( b, a, condition ) select( b,a,condition )\n" +"#define make_uint4 (uint4)\n" +"#define make_uint2 (uint2)\n" +"#define make_int2 (int2)\n" +"#define WG_SIZE 64\n" +"#define ELEMENTS_PER_WORK_ITEM (256/WG_SIZE)\n" +"#define BITS_PER_PASS 4\n" +"#define NUM_BUCKET (1< 64 )\n" +" {\n" +" sorterSharedMemory[idx] += sorterSharedMemory[idx-64];\n" +" GROUP_MEM_FENCE;\n" +" }\n" +" sorterSharedMemory[idx-1] += sorterSharedMemory[idx-2];\n" +" GROUP_MEM_FENCE;\n" +" }\n" +"#else\n" +" if( lIdx < 64 )\n" +" {\n" +" sorterSharedMemory[idx] += sorterSharedMemory[idx-1];\n" +" GROUP_MEM_FENCE;\n" +" sorterSharedMemory[idx] += sorterSharedMemory[idx-2]; \n" +" GROUP_MEM_FENCE;\n" +" sorterSharedMemory[idx] += sorterSharedMemory[idx-4];\n" +" GROUP_MEM_FENCE;\n" +" sorterSharedMemory[idx] += sorterSharedMemory[idx-8];\n" +" GROUP_MEM_FENCE;\n" +" sorterSharedMemory[idx] += sorterSharedMemory[idx-16];\n" +" GROUP_MEM_FENCE;\n" +" sorterSharedMemory[idx] += sorterSharedMemory[idx-32];\n" +" GROUP_MEM_FENCE;\n" +" if( wgSize > 64 )\n" +" {\n" +" sorterSharedMemory[idx] += sorterSharedMemory[idx-64];\n" +" GROUP_MEM_FENCE;\n" +" }\n" +" sorterSharedMemory[idx-1] += sorterSharedMemory[idx-2];\n" +" GROUP_MEM_FENCE;\n" +" }\n" +"#endif\n" +" }\n" +" GROUP_LDS_BARRIER;\n" +" *totalSum = sorterSharedMemory[wgSize*2-1];\n" +" u32 addValue = sorterSharedMemory[lIdx+wgSize-1];\n" +" return addValue;\n" +"}\n" +"//__attribute__((reqd_work_group_size(128,1,1)))\n" +"uint4 localPrefixSum128V( uint4 pData, uint lIdx, uint* totalSum, __local u32* sorterSharedMemory )\n" +"{\n" +" u32 s4 = prefixScanVectorEx( &pData );\n" +" u32 rank = localPrefixSum( s4, lIdx, totalSum, sorterSharedMemory, 128 );\n" +" return pData + make_uint4( rank, rank, rank, rank );\n" +"}\n" +"//__attribute__((reqd_work_group_size(64,1,1)))\n" +"uint4 localPrefixSum64V( uint4 pData, uint lIdx, uint* totalSum, __local u32* sorterSharedMemory )\n" +"{\n" +" u32 s4 = prefixScanVectorEx( &pData );\n" +" u32 rank = localPrefixSum( s4, lIdx, totalSum, sorterSharedMemory, 64 );\n" +" return pData + make_uint4( rank, rank, rank, rank );\n" +"}\n" +"u32 unpack4Key( u32 key, int keyIdx ){ return (key>>(keyIdx*8)) & 0xff;}\n" +"u32 bit8Scan(u32 v)\n" +"{\n" +" return (v<<8) + (v<<16) + (v<<24);\n" +"}\n" +"//===\n" +"#define MY_HISTOGRAM(idx) localHistogramMat[(idx)*WG_SIZE+lIdx]\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" +"void StreamCountKernel( __global u32* gSrc, __global u32* histogramOut, int4 cb )\n" +"{\n" +" __local u32 localHistogramMat[NUM_BUCKET*WG_SIZE];\n" +" u32 gIdx = GET_GLOBAL_IDX;\n" +" u32 lIdx = GET_LOCAL_IDX;\n" +" u32 wgIdx = GET_GROUP_IDX;\n" +" u32 wgSize = GET_GROUP_SIZE;\n" +" const int startBit = cb.m_startBit;\n" +" const int n = cb.m_n;\n" +" const int nWGs = cb.m_nWGs;\n" +" const int nBlocksPerWG = cb.m_nBlocksPerWG;\n" +" for(int i=0; i>startBit) & 0xf;\n" +"#if defined(NV_GPU)\n" +" MY_HISTOGRAM( localKey )++;\n" +"#else\n" +" AtomInc( MY_HISTOGRAM( localKey ) );\n" +"#endif\n" +" }\n" +" }\n" +" }\n" +" GROUP_LDS_BARRIER;\n" +" \n" +" if( lIdx < NUM_BUCKET )\n" +" {\n" +" u32 sum = 0;\n" +" for(int i=0; i>startBit) & 0xf;\n" +"#if defined(NV_GPU)\n" +" MY_HISTOGRAM( localKey )++;\n" +"#else\n" +" AtomInc( MY_HISTOGRAM( localKey ) );\n" +"#endif\n" +" }\n" +" }\n" +" }\n" +" GROUP_LDS_BARRIER;\n" +" \n" +" if( lIdx < NUM_BUCKET )\n" +" {\n" +" u32 sum = 0;\n" +" for(int i=0; i>startBit) & mask, (sortData[1]>>startBit) & mask, (sortData[2]>>startBit) & mask, (sortData[3]>>startBit) & mask );\n" +" uint4 prefixSum = SELECT_UINT4( make_uint4(1,1,1,1), make_uint4(0,0,0,0), cmpResult != make_uint4(0,0,0,0) );\n" +" u32 total;\n" +" prefixSum = localPrefixSum64V( prefixSum, lIdx, &total, ldsSortData );\n" +" {\n" +" uint4 localAddr = make_uint4(lIdx*4+0,lIdx*4+1,lIdx*4+2,lIdx*4+3);\n" +" uint4 dstAddr = localAddr - prefixSum + make_uint4( total, total, total, total );\n" +" dstAddr = SELECT_UINT4( prefixSum, dstAddr, cmpResult != make_uint4(0, 0, 0, 0) );\n" +" GROUP_LDS_BARRIER;\n" +" ldsSortData[dstAddr.x] = sortData[0];\n" +" ldsSortData[dstAddr.y] = sortData[1];\n" +" ldsSortData[dstAddr.z] = sortData[2];\n" +" ldsSortData[dstAddr.w] = sortData[3];\n" +" GROUP_LDS_BARRIER;\n" +" sortData[0] = ldsSortData[localAddr.x];\n" +" sortData[1] = ldsSortData[localAddr.y];\n" +" sortData[2] = ldsSortData[localAddr.z];\n" +" sortData[3] = ldsSortData[localAddr.w];\n" +" GROUP_LDS_BARRIER;\n" +" }\n" +" }\n" +"}\n" +"// 2 scan, 2 exchange\n" +"void sort4Bits1(u32 sortData[4], int startBit, int lIdx, __local u32* ldsSortData)\n" +"{\n" +" for(uint ibit=0; ibit>(startBit+ibit)) & 0x3, \n" +" (sortData[1]>>(startBit+ibit)) & 0x3, \n" +" (sortData[2]>>(startBit+ibit)) & 0x3, \n" +" (sortData[3]>>(startBit+ibit)) & 0x3);\n" +" u32 key4;\n" +" u32 sKeyPacked[4] = { 0, 0, 0, 0 };\n" +" {\n" +" sKeyPacked[0] |= 1<<(8*b.x);\n" +" sKeyPacked[1] |= 1<<(8*b.y);\n" +" sKeyPacked[2] |= 1<<(8*b.z);\n" +" sKeyPacked[3] |= 1<<(8*b.w);\n" +" key4 = sKeyPacked[0] + sKeyPacked[1] + sKeyPacked[2] + sKeyPacked[3];\n" +" }\n" +" u32 rankPacked;\n" +" u32 sumPacked;\n" +" {\n" +" rankPacked = localPrefixSum( key4, lIdx, &sumPacked, ldsSortData, WG_SIZE );\n" +" }\n" +" GROUP_LDS_BARRIER;\n" +" u32 newOffset[4] = { 0,0,0,0 };\n" +" {\n" +" u32 sumScanned = bit8Scan( sumPacked );\n" +" u32 scannedKeys[4];\n" +" scannedKeys[0] = 1<<(8*b.x);\n" +" scannedKeys[1] = 1<<(8*b.y);\n" +" scannedKeys[2] = 1<<(8*b.z);\n" +" scannedKeys[3] = 1<<(8*b.w);\n" +" { // 4 scans at once\n" +" u32 sum4 = 0;\n" +" for(int ie=0; ie<4; ie++)\n" +" {\n" +" u32 tmp = scannedKeys[ie];\n" +" scannedKeys[ie] = sum4;\n" +" sum4 += tmp;\n" +" }\n" +" }\n" +" {\n" +" u32 sumPlusRank = sumScanned + rankPacked;\n" +" { u32 ie = b.x;\n" +" scannedKeys[0] += sumPlusRank;\n" +" newOffset[0] = unpack4Key( scannedKeys[0], ie );\n" +" }\n" +" { u32 ie = b.y;\n" +" scannedKeys[1] += sumPlusRank;\n" +" newOffset[1] = unpack4Key( scannedKeys[1], ie );\n" +" }\n" +" { u32 ie = b.z;\n" +" scannedKeys[2] += sumPlusRank;\n" +" newOffset[2] = unpack4Key( scannedKeys[2], ie );\n" +" }\n" +" { u32 ie = b.w;\n" +" scannedKeys[3] += sumPlusRank;\n" +" newOffset[3] = unpack4Key( scannedKeys[3], ie );\n" +" }\n" +" }\n" +" }\n" +" GROUP_LDS_BARRIER;\n" +" {\n" +" ldsSortData[newOffset[0]] = sortData[0];\n" +" ldsSortData[newOffset[1]] = sortData[1];\n" +" ldsSortData[newOffset[2]] = sortData[2];\n" +" ldsSortData[newOffset[3]] = sortData[3];\n" +" GROUP_LDS_BARRIER;\n" +" u32 dstAddr = 4*lIdx;\n" +" sortData[0] = ldsSortData[dstAddr+0];\n" +" sortData[1] = ldsSortData[dstAddr+1];\n" +" sortData[2] = ldsSortData[dstAddr+2];\n" +" sortData[3] = ldsSortData[dstAddr+3];\n" +" GROUP_LDS_BARRIER;\n" +" }\n" +" }\n" +"}\n" +"#define SET_HISTOGRAM(setIdx, key) ldsSortData[(setIdx)*NUM_BUCKET+key]\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" +"void SortAndScatterKernel( __global const u32* restrict gSrc, __global const u32* rHistogram, __global u32* restrict gDst, int4 cb )\n" +"{\n" +" __local u32 ldsSortData[WG_SIZE*ELEMENTS_PER_WORK_ITEM+16];\n" +" __local u32 localHistogramToCarry[NUM_BUCKET];\n" +" __local u32 localHistogram[NUM_BUCKET*2];\n" +" u32 gIdx = GET_GLOBAL_IDX;\n" +" u32 lIdx = GET_LOCAL_IDX;\n" +" u32 wgIdx = GET_GROUP_IDX;\n" +" u32 wgSize = GET_GROUP_SIZE;\n" +" const int n = cb.m_n;\n" +" const int nWGs = cb.m_nWGs;\n" +" const int startBit = cb.m_startBit;\n" +" const int nBlocksPerWG = cb.m_nBlocksPerWG;\n" +" if( lIdx < (NUM_BUCKET) )\n" +" {\n" +" localHistogramToCarry[lIdx] = rHistogram[lIdx*nWGs + wgIdx];\n" +" }\n" +" GROUP_LDS_BARRIER;\n" +" const int blockSize = ELEMENTS_PER_WORK_ITEM*WG_SIZE;\n" +" int nBlocks = n/blockSize - nBlocksPerWG*wgIdx;\n" +" int addr = blockSize*nBlocksPerWG*wgIdx + ELEMENTS_PER_WORK_ITEM*lIdx;\n" +" for(int iblock=0; iblock>startBit) & 0xf;\n" +" { // create histogram\n" +" u32 setIdx = lIdx/16;\n" +" if( lIdx < NUM_BUCKET )\n" +" {\n" +" localHistogram[lIdx] = 0;\n" +" }\n" +" ldsSortData[lIdx] = 0;\n" +" GROUP_LDS_BARRIER;\n" +" for(int i=0; i>(startBit+ibit)) & 0x3, \n" +" (sortData[1]>>(startBit+ibit)) & 0x3, \n" +" (sortData[2]>>(startBit+ibit)) & 0x3, \n" +" (sortData[3]>>(startBit+ibit)) & 0x3);\n" +" u32 key4;\n" +" u32 sKeyPacked[4] = { 0, 0, 0, 0 };\n" +" {\n" +" sKeyPacked[0] |= 1<<(8*b.x);\n" +" sKeyPacked[1] |= 1<<(8*b.y);\n" +" sKeyPacked[2] |= 1<<(8*b.z);\n" +" sKeyPacked[3] |= 1<<(8*b.w);\n" +" key4 = sKeyPacked[0] + sKeyPacked[1] + sKeyPacked[2] + sKeyPacked[3];\n" +" }\n" +" u32 rankPacked;\n" +" u32 sumPacked;\n" +" {\n" +" rankPacked = localPrefixSum( key4, lIdx, &sumPacked, ldsSortData, WG_SIZE );\n" +" }\n" +" GROUP_LDS_BARRIER;\n" +" u32 newOffset[4] = { 0,0,0,0 };\n" +" {\n" +" u32 sumScanned = bit8Scan( sumPacked );\n" +" u32 scannedKeys[4];\n" +" scannedKeys[0] = 1<<(8*b.x);\n" +" scannedKeys[1] = 1<<(8*b.y);\n" +" scannedKeys[2] = 1<<(8*b.z);\n" +" scannedKeys[3] = 1<<(8*b.w);\n" +" { // 4 scans at once\n" +" u32 sum4 = 0;\n" +" for(int ie=0; ie<4; ie++)\n" +" {\n" +" u32 tmp = scannedKeys[ie];\n" +" scannedKeys[ie] = sum4;\n" +" sum4 += tmp;\n" +" }\n" +" }\n" +" {\n" +" u32 sumPlusRank = sumScanned + rankPacked;\n" +" { u32 ie = b.x;\n" +" scannedKeys[0] += sumPlusRank;\n" +" newOffset[0] = unpack4Key( scannedKeys[0], ie );\n" +" }\n" +" { u32 ie = b.y;\n" +" scannedKeys[1] += sumPlusRank;\n" +" newOffset[1] = unpack4Key( scannedKeys[1], ie );\n" +" }\n" +" { u32 ie = b.z;\n" +" scannedKeys[2] += sumPlusRank;\n" +" newOffset[2] = unpack4Key( scannedKeys[2], ie );\n" +" }\n" +" { u32 ie = b.w;\n" +" scannedKeys[3] += sumPlusRank;\n" +" newOffset[3] = unpack4Key( scannedKeys[3], ie );\n" +" }\n" +" }\n" +" }\n" +" GROUP_LDS_BARRIER;\n" +" {\n" +" ldsSortData[newOffset[0]] = sortData[0];\n" +" ldsSortData[newOffset[1]] = sortData[1];\n" +" ldsSortData[newOffset[2]] = sortData[2];\n" +" ldsSortData[newOffset[3]] = sortData[3];\n" +" ldsSortVal[newOffset[0]] = sortVal[0];\n" +" ldsSortVal[newOffset[1]] = sortVal[1];\n" +" ldsSortVal[newOffset[2]] = sortVal[2];\n" +" ldsSortVal[newOffset[3]] = sortVal[3];\n" +" GROUP_LDS_BARRIER;\n" +" u32 dstAddr = 4*lIdx;\n" +" sortData[0] = ldsSortData[dstAddr+0];\n" +" sortData[1] = ldsSortData[dstAddr+1];\n" +" sortData[2] = ldsSortData[dstAddr+2];\n" +" sortData[3] = ldsSortData[dstAddr+3];\n" +" sortVal[0] = ldsSortVal[dstAddr+0];\n" +" sortVal[1] = ldsSortVal[dstAddr+1];\n" +" sortVal[2] = ldsSortVal[dstAddr+2];\n" +" sortVal[3] = ldsSortVal[dstAddr+3];\n" +" GROUP_LDS_BARRIER;\n" +" }\n" +" }\n" +"}\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" +"void SortAndScatterSortDataKernel( __global const SortDataCL* restrict gSrc, __global const u32* rHistogram, __global SortDataCL* restrict gDst, int4 cb)\n" +"{\n" +" __local int ldsSortData[WG_SIZE*ELEMENTS_PER_WORK_ITEM+16];\n" +" __local int ldsSortVal[WG_SIZE*ELEMENTS_PER_WORK_ITEM+16];\n" +" __local u32 localHistogramToCarry[NUM_BUCKET];\n" +" __local u32 localHistogram[NUM_BUCKET*2];\n" +" u32 gIdx = GET_GLOBAL_IDX;\n" +" u32 lIdx = GET_LOCAL_IDX;\n" +" u32 wgIdx = GET_GROUP_IDX;\n" +" u32 wgSize = GET_GROUP_SIZE;\n" +" const int n = cb.m_n;\n" +" const int nWGs = cb.m_nWGs;\n" +" const int startBit = cb.m_startBit;\n" +" const int nBlocksPerWG = cb.m_nBlocksPerWG;\n" +" if( lIdx < (NUM_BUCKET) )\n" +" {\n" +" localHistogramToCarry[lIdx] = rHistogram[lIdx*nWGs + wgIdx];\n" +" }\n" +" GROUP_LDS_BARRIER;\n" +" \n" +" const int blockSize = ELEMENTS_PER_WORK_ITEM*WG_SIZE;\n" +" int nBlocks = n/blockSize - nBlocksPerWG*wgIdx;\n" +" int addr = blockSize*nBlocksPerWG*wgIdx + ELEMENTS_PER_WORK_ITEM*lIdx;\n" +" for(int iblock=0; iblock>startBit) & 0xf;\n" +" { // create histogram\n" +" u32 setIdx = lIdx/16;\n" +" if( lIdx < NUM_BUCKET )\n" +" {\n" +" localHistogram[lIdx] = 0;\n" +" }\n" +" ldsSortData[lIdx] = 0;\n" +" GROUP_LDS_BARRIER;\n" +" for(int i=0; i0)\n" +" return;\n" +" \n" +" for (int c=0;c>startBit) & 0xf;//0xf = NUM_TABLES-1\n" +" gDst[rHistogram[tableIdx*nWGs+wgIdx] + counter[tableIdx]] = gSrc[i];\n" +" counter[tableIdx] ++;\n" +" }\n" +" }\n" +" }\n" +" }\n" +" \n" +"}\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" +"void SortAndScatterKernelSerial( __global const u32* restrict gSrc, __global const u32* rHistogram, __global u32* restrict gDst, int4 cb )\n" +"{\n" +" \n" +" u32 gIdx = GET_GLOBAL_IDX;\n" +" u32 realLocalIdx = GET_LOCAL_IDX;\n" +" u32 wgIdx = GET_GROUP_IDX;\n" +" u32 wgSize = GET_GROUP_SIZE;\n" +" const int startBit = cb.m_startBit;\n" +" const int n = cb.m_n;\n" +" const int nWGs = cb.m_nWGs;\n" +" const int nBlocksPerWG = cb.m_nBlocksPerWG;\n" +" int counter[NUM_BUCKET];\n" +" \n" +" if (realLocalIdx>0)\n" +" return;\n" +" \n" +" for (int c=0;c>startBit) & 0xf;//0xf = NUM_TABLES-1\n" +" gDst[rHistogram[tableIdx*nWGs+wgIdx] + counter[tableIdx]] = gSrc[i];\n" +" counter[tableIdx] ++;\n" +" }\n" +" }\n" +" }\n" +" }\n" +" \n" +"}\n" +; diff --git a/extern/bullet/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp b/extern/bullet/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp new file mode 100644 index 000000000000..161e304f090e --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp @@ -0,0 +1,391 @@ + +#include "b3GpuRaycast.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3Collidable.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" +#include "Bullet3OpenCL/RigidBody/b3GpuNarrowPhaseInternalData.h" + + +#include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3OpenCLArray.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3FillCL.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3RadixSort32CL.h" +#include "Bullet3OpenCL/BroadphaseCollision/b3GpuBroadphaseInterface.h" +#include "Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h" + +#include "Bullet3OpenCL/Raycast/kernels/rayCastKernels.h" + + +#define B3_RAYCAST_PATH "src/Bullet3OpenCL/Raycast/kernels/rayCastKernels.cl" + + + +struct b3GpuRaycastInternalData +{ + cl_context m_context; + cl_device_id m_device; + cl_command_queue m_q; + cl_kernel m_raytraceKernel; + cl_kernel m_raytracePairsKernel; + cl_kernel m_findRayRigidPairIndexRanges; + + b3GpuParallelLinearBvh* m_plbvh; + b3RadixSort32CL* m_radixSorter; + b3FillCL* m_fill; + + //1 element per ray + b3OpenCLArray* m_gpuRays; + b3OpenCLArray* m_gpuHitResults; + b3OpenCLArray* m_firstRayRigidPairIndexPerRay; + b3OpenCLArray* m_numRayRigidPairsPerRay; + + //1 element per (ray index, rigid index) pair, where the ray intersects with the rigid's AABB + b3OpenCLArray* m_gpuNumRayRigidPairs; + b3OpenCLArray* m_gpuRayRigidPairs; //x == ray index, y == rigid index + + int m_test; +}; + +b3GpuRaycast::b3GpuRaycast(cl_context ctx,cl_device_id device, cl_command_queue q) +{ + m_data = new b3GpuRaycastInternalData; + m_data->m_context = ctx; + m_data->m_device = device; + m_data->m_q = q; + m_data->m_raytraceKernel = 0; + m_data->m_raytracePairsKernel = 0; + m_data->m_findRayRigidPairIndexRanges = 0; + + m_data->m_plbvh = new b3GpuParallelLinearBvh(ctx, device, q); + m_data->m_radixSorter = new b3RadixSort32CL(ctx, device, q); + m_data->m_fill = new b3FillCL(ctx, device, q); + + m_data->m_gpuRays = new b3OpenCLArray(ctx, q); + m_data->m_gpuHitResults = new b3OpenCLArray(ctx, q); + m_data->m_firstRayRigidPairIndexPerRay = new b3OpenCLArray(ctx, q); + m_data->m_numRayRigidPairsPerRay = new b3OpenCLArray(ctx, q); + m_data->m_gpuNumRayRigidPairs = new b3OpenCLArray(ctx, q); + m_data->m_gpuRayRigidPairs = new b3OpenCLArray(ctx, q); + + { + cl_int errNum=0; + cl_program prog = b3OpenCLUtils::compileCLProgramFromString(m_data->m_context,m_data->m_device,rayCastKernelCL,&errNum,"",B3_RAYCAST_PATH); + b3Assert(errNum==CL_SUCCESS); + m_data->m_raytraceKernel = b3OpenCLUtils::compileCLKernelFromString(m_data->m_context, m_data->m_device,rayCastKernelCL, "rayCastKernel",&errNum,prog); + b3Assert(errNum==CL_SUCCESS); + m_data->m_raytracePairsKernel = b3OpenCLUtils::compileCLKernelFromString(m_data->m_context, m_data->m_device,rayCastKernelCL, "rayCastPairsKernel",&errNum,prog); + b3Assert(errNum==CL_SUCCESS); + m_data->m_findRayRigidPairIndexRanges = b3OpenCLUtils::compileCLKernelFromString(m_data->m_context, m_data->m_device,rayCastKernelCL, "findRayRigidPairIndexRanges",&errNum,prog); + b3Assert(errNum==CL_SUCCESS); + clReleaseProgram(prog); + } + + +} + +b3GpuRaycast::~b3GpuRaycast() +{ + clReleaseKernel(m_data->m_raytraceKernel); + clReleaseKernel(m_data->m_raytracePairsKernel); + clReleaseKernel(m_data->m_findRayRigidPairIndexRanges); + + delete m_data->m_plbvh; + delete m_data->m_radixSorter; + delete m_data->m_fill; + + delete m_data->m_gpuRays; + delete m_data->m_gpuHitResults; + delete m_data->m_firstRayRigidPairIndexPerRay; + delete m_data->m_numRayRigidPairsPerRay; + delete m_data->m_gpuNumRayRigidPairs; + delete m_data->m_gpuRayRigidPairs; + + delete m_data; +} + +bool sphere_intersect(const b3Vector3& spherePos, b3Scalar radius, const b3Vector3& rayFrom, const b3Vector3& rayTo, float& hitFraction) +{ + b3Vector3 rs = rayFrom - spherePos; + b3Vector3 rayDir = rayTo-rayFrom; + + float A = b3Dot(rayDir,rayDir); + float B = b3Dot(rs, rayDir); + float C = b3Dot(rs, rs) - (radius * radius); + + float D = B * B - A*C; + + if (D > 0.0) + { + float t = (-B - sqrt(D))/A; + + if ( (t >= 0.0f) && (t < hitFraction) ) + { + hitFraction = t; + return true; + } + } + return false; +} + +bool rayConvex(const b3Vector3& rayFromLocal, const b3Vector3& rayToLocal, const b3ConvexPolyhedronData& poly, + const b3AlignedObjectArray& faces, float& hitFraction, b3Vector3& hitNormal) +{ + float exitFraction = hitFraction; + float enterFraction = -0.1f; + b3Vector3 curHitNormal=b3MakeVector3(0,0,0); + for (int i=0;i= 0.f) + { + float fraction = fromPlaneDist / (fromPlaneDist-toPlaneDist); + if (exitFraction>fraction) + { + exitFraction = fraction; + } + } + } else + { + if (toPlaneDist<0.f) + { + float fraction = fromPlaneDist / (fromPlaneDist-toPlaneDist); + if (enterFraction <= fraction) + { + enterFraction = fraction; + curHitNormal = face.m_plane; + curHitNormal.w = 0.f; + } + } else + { + return false; + } + } + if (exitFraction <= enterFraction) + return false; + } + + if (enterFraction < 0.f) + return false; + + hitFraction = enterFraction; + hitNormal = curHitNormal; + return true; +} + +void b3GpuRaycast::castRaysHost(const b3AlignedObjectArray& rays, b3AlignedObjectArray& hitResults, + int numBodies,const struct b3RigidBodyData* bodies, int numCollidables,const struct b3Collidable* collidables, const struct b3GpuNarrowPhaseInternalData* narrowphaseData) +{ + +// return castRays(rays,hitResults,numBodies,bodies,numCollidables,collidables); + + B3_PROFILE("castRaysHost"); + for (int r=0;rm_convexPolyhedra[shapeIndex]; + if (rayConvex(rayFromLocal, rayToLocal,poly,narrowphaseData->m_convexFaces, hitFraction, hitNormal)) + { + hitBodyIndex = b; + } + + + break; + } + default: + { + static bool once=true; + if (once) + { + once=false; + b3Warning("Raytest: unsupported shape type\n"); + } + } + } + } + if (hitBodyIndex>=0) + { + + hitResults[r].m_hitFraction = hitFraction; + hitResults[r].m_hitPoint.setInterpolate3(rays[r].m_from, rays[r].m_to,hitFraction); + hitResults[r].m_hitNormal = hitNormal; + hitResults[r].m_hitBody = hitBodyIndex; + } + + } +} +///todo: add some acceleration structure (AABBs, tree etc) +void b3GpuRaycast::castRays(const b3AlignedObjectArray& rays, b3AlignedObjectArray& hitResults, + int numBodies,const struct b3RigidBodyData* bodies, int numCollidables, const struct b3Collidable* collidables, + const struct b3GpuNarrowPhaseInternalData* narrowphaseData, class b3GpuBroadphaseInterface* broadphase) +{ + //castRaysHost(rays,hitResults,numBodies,bodies,numCollidables,collidables,narrowphaseData); + + B3_PROFILE("castRaysGPU"); + + { + B3_PROFILE("raycast copyFromHost"); + m_data->m_gpuRays->copyFromHost(rays); + m_data->m_gpuHitResults->copyFromHost(hitResults); + + } + + int numRays = hitResults.size(); + { + m_data->m_firstRayRigidPairIndexPerRay->resize(numRays); + m_data->m_numRayRigidPairsPerRay->resize(numRays); + + m_data->m_gpuNumRayRigidPairs->resize(1); + m_data->m_gpuRayRigidPairs->resize(numRays * 16); + } + + //run kernel + const bool USE_BRUTE_FORCE_RAYCAST = false; + if(USE_BRUTE_FORCE_RAYCAST) + { + B3_PROFILE("raycast launch1D"); + + b3LauncherCL launcher(m_data->m_q,m_data->m_raytraceKernel,"m_raytraceKernel"); + int numRays = rays.size(); + launcher.setConst(numRays); + + launcher.setBuffer(m_data->m_gpuRays->getBufferCL()); + launcher.setBuffer(m_data->m_gpuHitResults->getBufferCL()); + + launcher.setConst(numBodies); + launcher.setBuffer(narrowphaseData->m_bodyBufferGPU->getBufferCL()); + launcher.setBuffer(narrowphaseData->m_collidablesGPU->getBufferCL()); + launcher.setBuffer(narrowphaseData->m_convexFacesGPU->getBufferCL()); + launcher.setBuffer(narrowphaseData->m_convexPolyhedraGPU->getBufferCL()); + + launcher.launch1D(numRays); + clFinish(m_data->m_q); + } + else + { + m_data->m_plbvh->build( broadphase->getAllAabbsGPU(), broadphase->getSmallAabbIndicesGPU(), broadphase->getLargeAabbIndicesGPU() ); + + m_data->m_plbvh->testRaysAgainstBvhAabbs(*m_data->m_gpuRays, *m_data->m_gpuNumRayRigidPairs, *m_data->m_gpuRayRigidPairs); + + int numRayRigidPairs = -1; + m_data->m_gpuNumRayRigidPairs->copyToHostPointer(&numRayRigidPairs, 1); + if( numRayRigidPairs > m_data->m_gpuRayRigidPairs->size() ) + { + numRayRigidPairs = m_data->m_gpuRayRigidPairs->size(); + m_data->m_gpuNumRayRigidPairs->copyFromHostPointer(&numRayRigidPairs, 1); + } + + m_data->m_gpuRayRigidPairs->resize(numRayRigidPairs); //Radix sort needs b3OpenCLArray::size() to be correct + + //Sort ray-rigid pairs by ray index + { + B3_PROFILE("sort ray-rigid pairs"); + m_data->m_radixSorter->execute( *reinterpret_cast< b3OpenCLArray* >(m_data->m_gpuRayRigidPairs) ); + } + + //detect start,count of each ray pair + { + B3_PROFILE("detect ray-rigid pair index ranges"); + + { + B3_PROFILE("reset ray-rigid pair index ranges"); + + m_data->m_fill->execute(*m_data->m_firstRayRigidPairIndexPerRay, numRayRigidPairs, numRays); //atomic_min used to find first index + m_data->m_fill->execute(*m_data->m_numRayRigidPairsPerRay, 0, numRays); + clFinish(m_data->m_q); + } + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_data->m_gpuRayRigidPairs->getBufferCL() ), + + b3BufferInfoCL( m_data->m_firstRayRigidPairIndexPerRay->getBufferCL() ), + b3BufferInfoCL( m_data->m_numRayRigidPairsPerRay->getBufferCL() ) + }; + + b3LauncherCL launcher(m_data->m_q, m_data->m_findRayRigidPairIndexRanges, "m_findRayRigidPairIndexRanges"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numRayRigidPairs); + + launcher.launch1D(numRayRigidPairs); + clFinish(m_data->m_q); + } + + { + B3_PROFILE("ray-rigid intersection"); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_data->m_gpuRays->getBufferCL() ), + b3BufferInfoCL( m_data->m_gpuHitResults->getBufferCL() ), + b3BufferInfoCL( m_data->m_firstRayRigidPairIndexPerRay->getBufferCL() ), + b3BufferInfoCL( m_data->m_numRayRigidPairsPerRay->getBufferCL() ), + + b3BufferInfoCL( narrowphaseData->m_bodyBufferGPU->getBufferCL() ), + b3BufferInfoCL( narrowphaseData->m_collidablesGPU->getBufferCL() ), + b3BufferInfoCL( narrowphaseData->m_convexFacesGPU->getBufferCL() ), + b3BufferInfoCL( narrowphaseData->m_convexPolyhedraGPU->getBufferCL() ), + + b3BufferInfoCL( m_data->m_gpuRayRigidPairs->getBufferCL() ) + }; + + b3LauncherCL launcher(m_data->m_q, m_data->m_raytracePairsKernel, "m_raytracePairsKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numRays); + + launcher.launch1D(numRays); + clFinish(m_data->m_q); + } + } + + + + //copy results + { + B3_PROFILE("raycast copyToHost"); + m_data->m_gpuHitResults->copyToHost(hitResults); + } + +} \ No newline at end of file diff --git a/extern/bullet/src/Bullet3OpenCL/Raycast/b3GpuRaycast.h b/extern/bullet/src/Bullet3OpenCL/Raycast/b3GpuRaycast.h new file mode 100644 index 000000000000..3a5cf44b7956 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/Raycast/b3GpuRaycast.h @@ -0,0 +1,32 @@ +#ifndef B3_GPU_RAYCAST_H +#define B3_GPU_RAYCAST_H + +#include "Bullet3Common/b3Vector3.h" +#include "Bullet3OpenCL/Initialize/b3OpenCLInclude.h" + +#include "Bullet3Common/b3AlignedObjectArray.h" +#include "Bullet3Collision/NarrowPhaseCollision/b3RaycastInfo.h" + + + +class b3GpuRaycast +{ +protected: + struct b3GpuRaycastInternalData* m_data; +public: + b3GpuRaycast(cl_context ctx,cl_device_id device, cl_command_queue q); + virtual ~b3GpuRaycast(); + + void castRaysHost(const b3AlignedObjectArray& raysIn, b3AlignedObjectArray& hitResults, + int numBodies, const struct b3RigidBodyData* bodies, int numCollidables, const struct b3Collidable* collidables, + const struct b3GpuNarrowPhaseInternalData* narrowphaseData); + + void castRays(const b3AlignedObjectArray& rays, b3AlignedObjectArray& hitResults, + int numBodies,const struct b3RigidBodyData* bodies, int numCollidables, const struct b3Collidable* collidables, + const struct b3GpuNarrowPhaseInternalData* narrowphaseData, class b3GpuBroadphaseInterface* broadphase); + + + +}; + +#endif //B3_GPU_RAYCAST_H diff --git a/extern/bullet/src/Bullet3OpenCL/Raycast/kernels/rayCastKernels.cl b/extern/bullet/src/Bullet3OpenCL/Raycast/kernels/rayCastKernels.cl new file mode 100644 index 000000000000..e72d96876b10 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/Raycast/kernels/rayCastKernels.cl @@ -0,0 +1,439 @@ + +#define SHAPE_CONVEX_HULL 3 +#define SHAPE_PLANE 4 +#define SHAPE_CONCAVE_TRIMESH 5 +#define SHAPE_COMPOUND_OF_CONVEX_HULLS 6 +#define SHAPE_SPHERE 7 + + +typedef struct +{ + float4 m_from; + float4 m_to; +} b3RayInfo; + +typedef struct +{ + float m_hitFraction; + int m_hitResult0; + int m_hitResult1; + int m_hitResult2; + float4 m_hitPoint; + float4 m_hitNormal; +} b3RayHit; + +typedef struct +{ + float4 m_pos; + float4 m_quat; + float4 m_linVel; + float4 m_angVel; + + unsigned int m_collidableIdx; + float m_invMass; + float m_restituitionCoeff; + float m_frictionCoeff; +} Body; + +typedef struct Collidable +{ + union { + int m_numChildShapes; + int m_bvhIndex; + }; + float m_radius; + int m_shapeType; + int m_shapeIndex; +} Collidable; + + +typedef struct +{ + float4 m_localCenter; + float4 m_extents; + float4 mC; + float4 mE; + + float m_radius; + int m_faceOffset; + int m_numFaces; + int m_numVertices; + + int m_vertexOffset; + int m_uniqueEdgesOffset; + int m_numUniqueEdges; + int m_unused; + +} ConvexPolyhedronCL; + +typedef struct +{ + float4 m_plane; + int m_indexOffset; + int m_numIndices; +} b3GpuFace; + + + +/////////////////////////////////////// +// Quaternion +/////////////////////////////////////// + +typedef float4 Quaternion; + +__inline + Quaternion qtMul(Quaternion a, Quaternion b); + +__inline + Quaternion qtNormalize(Quaternion in); + + +__inline + Quaternion qtInvert(Quaternion q); + + +__inline + float dot3F4(float4 a, float4 b) +{ + float4 a1 = (float4)(a.xyz,0.f); + float4 b1 = (float4)(b.xyz,0.f); + return dot(a1, b1); +} + + +__inline + Quaternion qtMul(Quaternion a, Quaternion b) +{ + Quaternion ans; + ans = cross( a, b ); + ans += a.w*b+b.w*a; + // ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z); + ans.w = a.w*b.w - dot3F4(a, b); + return ans; +} + +__inline + Quaternion qtNormalize(Quaternion in) +{ + return fast_normalize(in); + // in /= length( in ); + // return in; +} +__inline + float4 qtRotate(Quaternion q, float4 vec) +{ + Quaternion qInv = qtInvert( q ); + float4 vcpy = vec; + vcpy.w = 0.f; + float4 out = qtMul(q,vcpy); + out = qtMul(out,qInv); + return out; +} + +__inline + Quaternion qtInvert(Quaternion q) +{ + return (Quaternion)(-q.xyz, q.w); +} + +__inline + float4 qtInvRotate(const Quaternion q, float4 vec) +{ + return qtRotate( qtInvert( q ), vec ); +} + + + +void trInverse(float4 translationIn, Quaternion orientationIn, + float4* translationOut, Quaternion* orientationOut) +{ + *orientationOut = qtInvert(orientationIn); + *translationOut = qtRotate(*orientationOut, -translationIn); +} + + + + + +bool rayConvex(float4 rayFromLocal, float4 rayToLocal, int numFaces, int faceOffset, + __global const b3GpuFace* faces, float* hitFraction, float4* hitNormal) +{ + rayFromLocal.w = 0.f; + rayToLocal.w = 0.f; + bool result = true; + + float exitFraction = hitFraction[0]; + float enterFraction = -0.3f; + float4 curHitNormal = (float4)(0,0,0,0); + for (int i=0;i= 0.f) + { + float fraction = fromPlaneDist / (fromPlaneDist-toPlaneDist); + if (exitFraction>fraction) + { + exitFraction = fraction; + } + } + } else + { + if (toPlaneDist<0.f) + { + float fraction = fromPlaneDist / (fromPlaneDist-toPlaneDist); + if (enterFraction <= fraction) + { + enterFraction = fraction; + curHitNormal = face.m_plane; + curHitNormal.w = 0.f; + } + } else + { + result = false; + } + } + if (exitFraction <= enterFraction) + result = false; + } + + if (enterFraction < 0.f) + { + result = false; + } + + if (result) + { + hitFraction[0] = enterFraction; + hitNormal[0] = curHitNormal; + } + return result; +} + + + + + + +bool sphere_intersect(float4 spherePos, float radius, float4 rayFrom, float4 rayTo, float* hitFraction) +{ + float4 rs = rayFrom - spherePos; + rs.w = 0.f; + float4 rayDir = rayTo-rayFrom; + rayDir.w = 0.f; + float A = dot(rayDir,rayDir); + float B = dot(rs, rayDir); + float C = dot(rs, rs) - (radius * radius); + + float D = B * B - A*C; + + if (D > 0.0f) + { + float t = (-B - sqrt(D))/A; + + if ( (t >= 0.0f) && (t < (*hitFraction)) ) + { + *hitFraction = t; + return true; + } + } + return false; +} + +float4 setInterpolate3(float4 from, float4 to, float t) +{ + float s = 1.0f - t; + float4 result; + result = s * from + t * to; + result.w = 0.f; + return result; +} + +__kernel void rayCastKernel( + int numRays, + const __global b3RayInfo* rays, + __global b3RayHit* hitResults, + const int numBodies, + __global Body* bodies, + __global Collidable* collidables, + __global const b3GpuFace* faces, + __global const ConvexPolyhedronCL* convexShapes ) +{ + + int i = get_global_id(0); + if (i>=numRays) + return; + + hitResults[i].m_hitFraction = 1.f; + + float4 rayFrom = rays[i].m_from; + float4 rayTo = rays[i].m_to; + float hitFraction = 1.f; + float4 hitPoint; + float4 hitNormal; + int hitBodyIndex= -1; + + int cachedCollidableIndex = -1; + Collidable cachedCollidable; + + for (int b=0;b=0) + { + hitPoint = setInterpolate3(rayFrom, rayTo,hitFraction); + hitResults[i].m_hitFraction = hitFraction; + hitResults[i].m_hitPoint = hitPoint; + hitResults[i].m_hitNormal = normalize(hitNormal); + hitResults[i].m_hitResult0 = hitBodyIndex; + } + +} + + +__kernel void findRayRigidPairIndexRanges(__global int2* rayRigidPairs, + __global int* out_firstRayRigidPairIndexPerRay, + __global int* out_numRayRigidPairsPerRay, + int numRayRigidPairs) +{ + int rayRigidPairIndex = get_global_id(0); + if (rayRigidPairIndex >= numRayRigidPairs) return; + + int rayIndex = rayRigidPairs[rayRigidPairIndex].x; + + atomic_min(&out_firstRayRigidPairIndexPerRay[rayIndex], rayRigidPairIndex); + atomic_inc(&out_numRayRigidPairsPerRay[rayIndex]); +} + +__kernel void rayCastPairsKernel(const __global b3RayInfo* rays, + __global b3RayHit* hitResults, + __global int* firstRayRigidPairIndexPerRay, + __global int* numRayRigidPairsPerRay, + + __global Body* bodies, + __global Collidable* collidables, + __global const b3GpuFace* faces, + __global const ConvexPolyhedronCL* convexShapes, + + __global int2* rayRigidPairs, + int numRays) +{ + int i = get_global_id(0); + if (i >= numRays) return; + + float4 rayFrom = rays[i].m_from; + float4 rayTo = rays[i].m_to; + + hitResults[i].m_hitFraction = 1.f; + + float hitFraction = 1.f; + float4 hitPoint; + float4 hitNormal; + int hitBodyIndex = -1; + + // + for(int pair = 0; pair < numRayRigidPairsPerRay[i]; ++pair) + { + int rayRigidPairIndex = pair + firstRayRigidPairIndexPerRay[i]; + int b = rayRigidPairs[rayRigidPairIndex].y; + + if (hitResults[i].m_hitResult2 == b) continue; + + Body body = bodies[b]; + Collidable rigidCollidable = collidables[body.m_collidableIdx]; + + float4 pos = body.m_pos; + float4 orn = body.m_quat; + + if (rigidCollidable.m_shapeType == SHAPE_CONVEX_HULL) + { + float4 invPos = (float4)(0,0,0,0); + float4 invOrn = (float4)(0,0,0,0); + float4 rayFromLocal = (float4)(0,0,0,0); + float4 rayToLocal = (float4)(0,0,0,0); + invOrn = qtInvert(orn); + invPos = qtRotate(invOrn, -pos); + rayFromLocal = qtRotate( invOrn, rayFrom ) + invPos; + rayToLocal = qtRotate( invOrn, rayTo) + invPos; + rayFromLocal.w = 0.f; + rayToLocal.w = 0.f; + int numFaces = convexShapes[rigidCollidable.m_shapeIndex].m_numFaces; + int faceOffset = convexShapes[rigidCollidable.m_shapeIndex].m_faceOffset; + + if (numFaces && rayConvex(rayFromLocal, rayToLocal, numFaces, faceOffset,faces, &hitFraction, &hitNormal)) + { + hitBodyIndex = b; + hitPoint = setInterpolate3(rayFrom, rayTo, hitFraction); + } + } + + if (rigidCollidable.m_shapeType == SHAPE_SPHERE) + { + float radius = rigidCollidable.m_radius; + + if (sphere_intersect(pos, radius, rayFrom, rayTo, &hitFraction)) + { + hitBodyIndex = b; + hitPoint = setInterpolate3(rayFrom, rayTo, hitFraction); + hitNormal = (float4) (hitPoint - bodies[b].m_pos); + } + } + } + + if (hitBodyIndex >= 0) + { + hitResults[i].m_hitFraction = hitFraction; + hitResults[i].m_hitPoint = hitPoint; + hitResults[i].m_hitNormal = normalize(hitNormal); + hitResults[i].m_hitResult0 = hitBodyIndex; + } + +} diff --git a/extern/bullet/src/Bullet3OpenCL/Raycast/kernels/rayCastKernels.h b/extern/bullet/src/Bullet3OpenCL/Raycast/kernels/rayCastKernels.h new file mode 100644 index 000000000000..6257909a4d6b --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/Raycast/kernels/rayCastKernels.h @@ -0,0 +1,381 @@ +//this file is autogenerated using stringify.bat (premake --stringify) in the build folder of this project +static const char* rayCastKernelCL= \ +"#define SHAPE_CONVEX_HULL 3\n" +"#define SHAPE_PLANE 4\n" +"#define SHAPE_CONCAVE_TRIMESH 5\n" +"#define SHAPE_COMPOUND_OF_CONVEX_HULLS 6\n" +"#define SHAPE_SPHERE 7\n" +"typedef struct\n" +"{\n" +" float4 m_from;\n" +" float4 m_to;\n" +"} b3RayInfo;\n" +"typedef struct\n" +"{\n" +" float m_hitFraction;\n" +" int m_hitResult0;\n" +" int m_hitResult1;\n" +" int m_hitResult2;\n" +" float4 m_hitPoint;\n" +" float4 m_hitNormal;\n" +"} b3RayHit;\n" +"typedef struct\n" +"{\n" +" float4 m_pos;\n" +" float4 m_quat;\n" +" float4 m_linVel;\n" +" float4 m_angVel;\n" +" unsigned int m_collidableIdx;\n" +" float m_invMass;\n" +" float m_restituitionCoeff;\n" +" float m_frictionCoeff;\n" +"} Body;\n" +"typedef struct Collidable\n" +"{\n" +" union {\n" +" int m_numChildShapes;\n" +" int m_bvhIndex;\n" +" };\n" +" float m_radius;\n" +" int m_shapeType;\n" +" int m_shapeIndex;\n" +"} Collidable;\n" +"typedef struct \n" +"{\n" +" float4 m_localCenter;\n" +" float4 m_extents;\n" +" float4 mC;\n" +" float4 mE;\n" +" float m_radius;\n" +" int m_faceOffset;\n" +" int m_numFaces;\n" +" int m_numVertices;\n" +" int m_vertexOffset;\n" +" int m_uniqueEdgesOffset;\n" +" int m_numUniqueEdges;\n" +" int m_unused;\n" +"} ConvexPolyhedronCL;\n" +"typedef struct\n" +"{\n" +" float4 m_plane;\n" +" int m_indexOffset;\n" +" int m_numIndices;\n" +"} b3GpuFace;\n" +"///////////////////////////////////////\n" +"// Quaternion\n" +"///////////////////////////////////////\n" +"typedef float4 Quaternion;\n" +"__inline\n" +" Quaternion qtMul(Quaternion a, Quaternion b);\n" +"__inline\n" +" Quaternion qtNormalize(Quaternion in);\n" +"__inline\n" +" Quaternion qtInvert(Quaternion q);\n" +"__inline\n" +" float dot3F4(float4 a, float4 b)\n" +"{\n" +" float4 a1 = (float4)(a.xyz,0.f);\n" +" float4 b1 = (float4)(b.xyz,0.f);\n" +" return dot(a1, b1);\n" +"}\n" +"__inline\n" +" Quaternion qtMul(Quaternion a, Quaternion b)\n" +"{\n" +" Quaternion ans;\n" +" ans = cross( a, b );\n" +" ans += a.w*b+b.w*a;\n" +" // ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z);\n" +" ans.w = a.w*b.w - dot3F4(a, b);\n" +" return ans;\n" +"}\n" +"__inline\n" +" Quaternion qtNormalize(Quaternion in)\n" +"{\n" +" return fast_normalize(in);\n" +" // in /= length( in );\n" +" // return in;\n" +"}\n" +"__inline\n" +" float4 qtRotate(Quaternion q, float4 vec)\n" +"{\n" +" Quaternion qInv = qtInvert( q );\n" +" float4 vcpy = vec;\n" +" vcpy.w = 0.f;\n" +" float4 out = qtMul(q,vcpy);\n" +" out = qtMul(out,qInv);\n" +" return out;\n" +"}\n" +"__inline\n" +" Quaternion qtInvert(Quaternion q)\n" +"{\n" +" return (Quaternion)(-q.xyz, q.w);\n" +"}\n" +"__inline\n" +" float4 qtInvRotate(const Quaternion q, float4 vec)\n" +"{\n" +" return qtRotate( qtInvert( q ), vec );\n" +"}\n" +"void trInverse(float4 translationIn, Quaternion orientationIn,\n" +" float4* translationOut, Quaternion* orientationOut)\n" +"{\n" +" *orientationOut = qtInvert(orientationIn);\n" +" *translationOut = qtRotate(*orientationOut, -translationIn);\n" +"}\n" +"bool rayConvex(float4 rayFromLocal, float4 rayToLocal, int numFaces, int faceOffset,\n" +" __global const b3GpuFace* faces, float* hitFraction, float4* hitNormal)\n" +"{\n" +" rayFromLocal.w = 0.f;\n" +" rayToLocal.w = 0.f;\n" +" bool result = true;\n" +" float exitFraction = hitFraction[0];\n" +" float enterFraction = -0.3f;\n" +" float4 curHitNormal = (float4)(0,0,0,0);\n" +" for (int i=0;i= 0.f)\n" +" {\n" +" float fraction = fromPlaneDist / (fromPlaneDist-toPlaneDist);\n" +" if (exitFraction>fraction)\n" +" {\n" +" exitFraction = fraction;\n" +" }\n" +" } \n" +" } else\n" +" {\n" +" if (toPlaneDist<0.f)\n" +" {\n" +" float fraction = fromPlaneDist / (fromPlaneDist-toPlaneDist);\n" +" if (enterFraction <= fraction)\n" +" {\n" +" enterFraction = fraction;\n" +" curHitNormal = face.m_plane;\n" +" curHitNormal.w = 0.f;\n" +" }\n" +" } else\n" +" {\n" +" result = false;\n" +" }\n" +" }\n" +" if (exitFraction <= enterFraction)\n" +" result = false;\n" +" }\n" +" if (enterFraction < 0.f)\n" +" {\n" +" result = false;\n" +" }\n" +" if (result)\n" +" { \n" +" hitFraction[0] = enterFraction;\n" +" hitNormal[0] = curHitNormal;\n" +" }\n" +" return result;\n" +"}\n" +"bool sphere_intersect(float4 spherePos, float radius, float4 rayFrom, float4 rayTo, float* hitFraction)\n" +"{\n" +" float4 rs = rayFrom - spherePos;\n" +" rs.w = 0.f;\n" +" float4 rayDir = rayTo-rayFrom;\n" +" rayDir.w = 0.f;\n" +" float A = dot(rayDir,rayDir);\n" +" float B = dot(rs, rayDir);\n" +" float C = dot(rs, rs) - (radius * radius);\n" +" float D = B * B - A*C;\n" +" if (D > 0.0f)\n" +" {\n" +" float t = (-B - sqrt(D))/A;\n" +" if ( (t >= 0.0f) && (t < (*hitFraction)) )\n" +" {\n" +" *hitFraction = t;\n" +" return true;\n" +" }\n" +" }\n" +" return false;\n" +"}\n" +"float4 setInterpolate3(float4 from, float4 to, float t)\n" +"{\n" +" float s = 1.0f - t;\n" +" float4 result;\n" +" result = s * from + t * to;\n" +" result.w = 0.f; \n" +" return result; \n" +"}\n" +"__kernel void rayCastKernel( \n" +" int numRays, \n" +" const __global b3RayInfo* rays, \n" +" __global b3RayHit* hitResults, \n" +" const int numBodies, \n" +" __global Body* bodies,\n" +" __global Collidable* collidables,\n" +" __global const b3GpuFace* faces,\n" +" __global const ConvexPolyhedronCL* convexShapes )\n" +"{\n" +" int i = get_global_id(0);\n" +" if (i>=numRays)\n" +" return;\n" +" hitResults[i].m_hitFraction = 1.f;\n" +" float4 rayFrom = rays[i].m_from;\n" +" float4 rayTo = rays[i].m_to;\n" +" float hitFraction = 1.f;\n" +" float4 hitPoint;\n" +" float4 hitNormal;\n" +" int hitBodyIndex= -1;\n" +" int cachedCollidableIndex = -1;\n" +" Collidable cachedCollidable;\n" +" for (int b=0;b=0)\n" +" {\n" +" hitPoint = setInterpolate3(rayFrom, rayTo,hitFraction);\n" +" hitResults[i].m_hitFraction = hitFraction;\n" +" hitResults[i].m_hitPoint = hitPoint;\n" +" hitResults[i].m_hitNormal = normalize(hitNormal);\n" +" hitResults[i].m_hitResult0 = hitBodyIndex;\n" +" }\n" +"}\n" +"__kernel void findRayRigidPairIndexRanges(__global int2* rayRigidPairs, \n" +" __global int* out_firstRayRigidPairIndexPerRay,\n" +" __global int* out_numRayRigidPairsPerRay,\n" +" int numRayRigidPairs)\n" +"{\n" +" int rayRigidPairIndex = get_global_id(0);\n" +" if (rayRigidPairIndex >= numRayRigidPairs) return;\n" +" \n" +" int rayIndex = rayRigidPairs[rayRigidPairIndex].x;\n" +" \n" +" atomic_min(&out_firstRayRigidPairIndexPerRay[rayIndex], rayRigidPairIndex);\n" +" atomic_inc(&out_numRayRigidPairsPerRay[rayIndex]);\n" +"}\n" +"__kernel void rayCastPairsKernel(const __global b3RayInfo* rays, \n" +" __global b3RayHit* hitResults, \n" +" __global int* firstRayRigidPairIndexPerRay,\n" +" __global int* numRayRigidPairsPerRay,\n" +" \n" +" __global Body* bodies,\n" +" __global Collidable* collidables,\n" +" __global const b3GpuFace* faces,\n" +" __global const ConvexPolyhedronCL* convexShapes,\n" +" \n" +" __global int2* rayRigidPairs,\n" +" int numRays)\n" +"{\n" +" int i = get_global_id(0);\n" +" if (i >= numRays) return;\n" +" \n" +" float4 rayFrom = rays[i].m_from;\n" +" float4 rayTo = rays[i].m_to;\n" +" \n" +" hitResults[i].m_hitFraction = 1.f;\n" +" \n" +" float hitFraction = 1.f;\n" +" float4 hitPoint;\n" +" float4 hitNormal;\n" +" int hitBodyIndex = -1;\n" +" \n" +" //\n" +" for(int pair = 0; pair < numRayRigidPairsPerRay[i]; ++pair)\n" +" {\n" +" int rayRigidPairIndex = pair + firstRayRigidPairIndexPerRay[i];\n" +" int b = rayRigidPairs[rayRigidPairIndex].y;\n" +" \n" +" if (hitResults[i].m_hitResult2 == b) continue;\n" +" \n" +" Body body = bodies[b];\n" +" Collidable rigidCollidable = collidables[body.m_collidableIdx];\n" +" \n" +" float4 pos = body.m_pos;\n" +" float4 orn = body.m_quat;\n" +" \n" +" if (rigidCollidable.m_shapeType == SHAPE_CONVEX_HULL)\n" +" {\n" +" float4 invPos = (float4)(0,0,0,0);\n" +" float4 invOrn = (float4)(0,0,0,0);\n" +" float4 rayFromLocal = (float4)(0,0,0,0);\n" +" float4 rayToLocal = (float4)(0,0,0,0);\n" +" invOrn = qtInvert(orn);\n" +" invPos = qtRotate(invOrn, -pos);\n" +" rayFromLocal = qtRotate( invOrn, rayFrom ) + invPos;\n" +" rayToLocal = qtRotate( invOrn, rayTo) + invPos;\n" +" rayFromLocal.w = 0.f;\n" +" rayToLocal.w = 0.f;\n" +" int numFaces = convexShapes[rigidCollidable.m_shapeIndex].m_numFaces;\n" +" int faceOffset = convexShapes[rigidCollidable.m_shapeIndex].m_faceOffset;\n" +" \n" +" if (numFaces && rayConvex(rayFromLocal, rayToLocal, numFaces, faceOffset,faces, &hitFraction, &hitNormal))\n" +" {\n" +" hitBodyIndex = b;\n" +" hitPoint = setInterpolate3(rayFrom, rayTo, hitFraction);\n" +" }\n" +" }\n" +" \n" +" if (rigidCollidable.m_shapeType == SHAPE_SPHERE)\n" +" {\n" +" float radius = rigidCollidable.m_radius;\n" +" \n" +" if (sphere_intersect(pos, radius, rayFrom, rayTo, &hitFraction))\n" +" {\n" +" hitBodyIndex = b;\n" +" hitPoint = setInterpolate3(rayFrom, rayTo, hitFraction);\n" +" hitNormal = (float4) (hitPoint - bodies[b].m_pos);\n" +" }\n" +" }\n" +" }\n" +" \n" +" if (hitBodyIndex >= 0)\n" +" {\n" +" hitResults[i].m_hitFraction = hitFraction;\n" +" hitResults[i].m_hitPoint = hitPoint;\n" +" hitResults[i].m_hitNormal = normalize(hitNormal);\n" +" hitResults[i].m_hitResult0 = hitBodyIndex;\n" +" }\n" +" \n" +"}\n" +; diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuConstraint4.h b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuConstraint4.h new file mode 100644 index 000000000000..c7478f54a1b6 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuConstraint4.h @@ -0,0 +1,18 @@ + +#ifndef B3_CONSTRAINT4_h +#define B3_CONSTRAINT4_h +#include "Bullet3Common/b3Vector3.h" + +#include "Bullet3Dynamics/shared/b3ContactConstraint4.h" + + +B3_ATTRIBUTE_ALIGNED16(struct) b3GpuConstraint4 : public b3ContactConstraint4 +{ + B3_DECLARE_ALIGNED_ALLOCATOR(); + + inline void setFrictionCoeff(float value) { m_linear[3] = value; } + inline float getFrictionCoeff() const { return m_linear[3]; } +}; + +#endif //B3_CONSTRAINT4_h + diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuGenericConstraint.cpp b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuGenericConstraint.cpp new file mode 100644 index 000000000000..af687b54e9b6 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuGenericConstraint.cpp @@ -0,0 +1,137 @@ +/* +Copyright (c) 2012 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Erwin Coumans + +#include "b3GpuGenericConstraint.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" + +#include +#include "Bullet3Common/b3Transform.h" + +void b3GpuGenericConstraint::getInfo1 (unsigned int* info,const b3RigidBodyData* bodies) +{ + switch (m_constraintType) + { + case B3_GPU_POINT2POINT_CONSTRAINT_TYPE: + { + *info = 3; + break; + }; + default: + { + b3Assert(0); + } + }; +} + +void getInfo2Point2Point(b3GpuGenericConstraint* constraint, b3GpuConstraintInfo2* info, const b3RigidBodyData* bodies) +{ + b3Transform trA; + trA.setIdentity(); + trA.setOrigin(bodies[constraint->m_rbA].m_pos); + trA.setRotation(bodies[constraint->m_rbA].m_quat); + + b3Transform trB; + trB.setIdentity(); + trB.setOrigin(bodies[constraint->m_rbB].m_pos); + trB.setRotation(bodies[constraint->m_rbB].m_quat); + + // anchor points in global coordinates with respect to body PORs. + + // set jacobian + info->m_J1linearAxis[0] = 1; + info->m_J1linearAxis[info->rowskip+1] = 1; + info->m_J1linearAxis[2*info->rowskip+2] = 1; + + b3Vector3 a1 = trA.getBasis()*constraint->getPivotInA(); + //b3Vector3 a1a = b3QuatRotate(trA.getRotation(),constraint->getPivotInA()); + + { + b3Vector3* angular0 = (b3Vector3*)(info->m_J1angularAxis); + b3Vector3* angular1 = (b3Vector3*)(info->m_J1angularAxis+info->rowskip); + b3Vector3* angular2 = (b3Vector3*)(info->m_J1angularAxis+2*info->rowskip); + b3Vector3 a1neg = -a1; + a1neg.getSkewSymmetricMatrix(angular0,angular1,angular2); + } + + if (info->m_J2linearAxis) + { + info->m_J2linearAxis[0] = -1; + info->m_J2linearAxis[info->rowskip+1] = -1; + info->m_J2linearAxis[2*info->rowskip+2] = -1; + } + + b3Vector3 a2 = trB.getBasis()*constraint->getPivotInB(); + + { + // b3Vector3 a2n = -a2; + b3Vector3* angular0 = (b3Vector3*)(info->m_J2angularAxis); + b3Vector3* angular1 = (b3Vector3*)(info->m_J2angularAxis+info->rowskip); + b3Vector3* angular2 = (b3Vector3*)(info->m_J2angularAxis+2*info->rowskip); + a2.getSkewSymmetricMatrix(angular0,angular1,angular2); + } + + + + // set right hand side +// b3Scalar currERP = (m_flags & B3_P2P_FLAGS_ERP) ? m_erp : info->erp; + b3Scalar currERP = info->erp; + + b3Scalar k = info->fps * currERP; + int j; + for (j=0; j<3; j++) + { + info->m_constraintError[j*info->rowskip] = k * (a2[j] + trB.getOrigin()[j] - a1[j] - trA.getOrigin()[j]); + //printf("info->m_constraintError[%d]=%f\n",j,info->m_constraintError[j]); + } +#if 0 + if(m_flags & B3_P2P_FLAGS_CFM) + { + for (j=0; j<3; j++) + { + info->cfm[j*info->rowskip] = m_cfm; + } + } +#endif + +#if 0 + b3Scalar impulseClamp = m_setting.m_impulseClamp;// + for (j=0; j<3; j++) + { + if (m_setting.m_impulseClamp > 0) + { + info->m_lowerLimit[j*info->rowskip] = -impulseClamp; + info->m_upperLimit[j*info->rowskip] = impulseClamp; + } + } + info->m_damping = m_setting.m_damping; +#endif + +} + +void b3GpuGenericConstraint::getInfo2 (b3GpuConstraintInfo2* info, const b3RigidBodyData* bodies) +{ + switch (m_constraintType) + { + case B3_GPU_POINT2POINT_CONSTRAINT_TYPE: + { + getInfo2Point2Point(this,info,bodies); + break; + }; + default: + { + b3Assert(0); + } + }; +} diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuGenericConstraint.h b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuGenericConstraint.h new file mode 100644 index 000000000000..14b3ba7fec70 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuGenericConstraint.h @@ -0,0 +1,132 @@ +/* +Copyright (c) 2013 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Erwin Coumans + +#ifndef B3_GPU_GENERIC_CONSTRAINT_H +#define B3_GPU_GENERIC_CONSTRAINT_H + +#include "Bullet3Common/b3Quaternion.h" +struct b3RigidBodyData; +enum B3_CONSTRAINT_FLAGS +{ + B3_CONSTRAINT_FLAG_ENABLED=1, +}; + +enum b3GpuGenericConstraintType +{ + B3_GPU_POINT2POINT_CONSTRAINT_TYPE=3, + B3_GPU_FIXED_CONSTRAINT_TYPE=4, +// B3_HINGE_CONSTRAINT_TYPE, +// B3_CONETWIST_CONSTRAINT_TYPE, +// B3_D6_CONSTRAINT_TYPE, +// B3_SLIDER_CONSTRAINT_TYPE, +// B3_CONTACT_CONSTRAINT_TYPE, +// B3_D6_SPRING_CONSTRAINT_TYPE, +// B3_GEAR_CONSTRAINT_TYPE, + + B3_GPU_MAX_CONSTRAINT_TYPE +}; + + + +struct b3GpuConstraintInfo2 +{ + // integrator parameters: frames per second (1/stepsize), default error + // reduction parameter (0..1). + b3Scalar 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. + b3Scalar *m_J1linearAxis,*m_J1angularAxis,*m_J2linearAxis,*m_J2angularAxis; + + // 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. + b3Scalar *m_constraintError,*cfm; + + // lo and hi limits for variables (set to -/+ infinity on entry). + b3Scalar *m_lowerLimit,*m_upperLimit; + + // 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; + // number of solver iterations + int m_numIterations; + + //damping of the velocity + b3Scalar m_damping; +}; + + +B3_ATTRIBUTE_ALIGNED16(struct) b3GpuGenericConstraint +{ + int m_constraintType; + int m_rbA; + int m_rbB; + float m_breakingImpulseThreshold; + + b3Vector3 m_pivotInA; + b3Vector3 m_pivotInB; + b3Quaternion m_relTargetAB; + + int m_flags; + int m_uid; + int m_padding[2]; + + int getRigidBodyA() const + { + return m_rbA; + } + int getRigidBodyB() const + { + return m_rbB; + } + + const b3Vector3& getPivotInA() const + { + return m_pivotInA; + } + + const b3Vector3& getPivotInB() const + { + return m_pivotInB; + } + + int isEnabled() const + { + return m_flags & B3_CONSTRAINT_FLAG_ENABLED; + } + + float getBreakingImpulseThreshold() const + { + return m_breakingImpulseThreshold; + } + + ///internal method used by the constraint solver, don't use them directly + void getInfo1 (unsigned int* info,const b3RigidBodyData* bodies); + + ///internal method used by the constraint solver, don't use them directly + void getInfo2 (b3GpuConstraintInfo2* info, const b3RigidBodyData* bodies); + + +}; + +#endif //B3_GPU_GENERIC_CONSTRAINT_H \ No newline at end of file diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuJacobiContactSolver.cpp b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuJacobiContactSolver.cpp new file mode 100644 index 000000000000..179dfc4f26e8 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuJacobiContactSolver.cpp @@ -0,0 +1,1382 @@ + +#include "b3GpuJacobiContactSolver.h" +#include "Bullet3Collision/NarrowPhaseCollision/b3Contact4.h" +#include "Bullet3Common/b3AlignedObjectArray.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3FillCL.h" //b3Int2 +class b3Vector3; +#include "Bullet3OpenCL/ParallelPrimitives/b3RadixSort32CL.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3PrefixScanCL.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.h" +#include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h" +#include "Bullet3OpenCL/RigidBody/kernels/solverUtils.h" +#include "Bullet3Common/b3Logging.h" +#include "b3GpuConstraint4.h" +#include "Bullet3Common/shared/b3Int2.h" +#include "Bullet3Common/shared/b3Int4.h" +#define SOLVER_UTILS_KERNEL_PATH "src/Bullet3OpenCL/RigidBody/kernels/solverUtils.cl" + + +struct b3GpuJacobiSolverInternalData +{ + //btRadixSort32CL* m_sort32; + //btBoundSearchCL* m_search; + b3PrefixScanCL* m_scan; + + b3OpenCLArray* m_bodyCount; + b3OpenCLArray* m_contactConstraintOffsets; + b3OpenCLArray* m_offsetSplitBodies; + + b3OpenCLArray* m_deltaLinearVelocities; + b3OpenCLArray* m_deltaAngularVelocities; + + b3AlignedObjectArray m_deltaLinearVelocitiesCPU; + b3AlignedObjectArray m_deltaAngularVelocitiesCPU; + + + + b3OpenCLArray* m_contactConstraints; + + b3FillCL* m_filler; + + + cl_kernel m_countBodiesKernel; + cl_kernel m_contactToConstraintSplitKernel; + cl_kernel m_clearVelocitiesKernel; + cl_kernel m_averageVelocitiesKernel; + cl_kernel m_updateBodyVelocitiesKernel; + cl_kernel m_solveContactKernel; + cl_kernel m_solveFrictionKernel; + + + +}; + + +b3GpuJacobiContactSolver::b3GpuJacobiContactSolver(cl_context ctx, cl_device_id device, cl_command_queue queue, int pairCapacity) + :m_context(ctx), + m_device(device), + m_queue(queue) +{ + m_data = new b3GpuJacobiSolverInternalData; + m_data->m_scan = new b3PrefixScanCL(m_context,m_device,m_queue); + m_data->m_bodyCount = new b3OpenCLArray(m_context,m_queue); + m_data->m_filler = new b3FillCL(m_context,m_device,m_queue); + m_data->m_contactConstraintOffsets = new b3OpenCLArray(m_context,m_queue); + m_data->m_offsetSplitBodies = new b3OpenCLArray(m_context,m_queue); + m_data->m_contactConstraints = new b3OpenCLArray(m_context,m_queue); + m_data->m_deltaLinearVelocities = new b3OpenCLArray(m_context,m_queue); + m_data->m_deltaAngularVelocities = new b3OpenCLArray(m_context,m_queue); + + cl_int pErrNum; + const char* additionalMacros=""; + const char* solverUtilsSource = solverUtilsCL; + { + cl_program solverUtilsProg= b3OpenCLUtils::compileCLProgramFromString( ctx, device, solverUtilsSource, &pErrNum,additionalMacros, SOLVER_UTILS_KERNEL_PATH); + b3Assert(solverUtilsProg); + m_data->m_countBodiesKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverUtilsSource, "CountBodiesKernel", &pErrNum, solverUtilsProg,additionalMacros ); + b3Assert(m_data->m_countBodiesKernel); + + m_data->m_contactToConstraintSplitKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverUtilsSource, "ContactToConstraintSplitKernel", &pErrNum, solverUtilsProg,additionalMacros ); + b3Assert(m_data->m_contactToConstraintSplitKernel); + m_data->m_clearVelocitiesKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverUtilsSource, "ClearVelocitiesKernel", &pErrNum, solverUtilsProg,additionalMacros ); + b3Assert(m_data->m_clearVelocitiesKernel); + + m_data->m_averageVelocitiesKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverUtilsSource, "AverageVelocitiesKernel", &pErrNum, solverUtilsProg,additionalMacros ); + b3Assert(m_data->m_averageVelocitiesKernel); + + m_data->m_updateBodyVelocitiesKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverUtilsSource, "UpdateBodyVelocitiesKernel", &pErrNum, solverUtilsProg,additionalMacros ); + b3Assert(m_data->m_updateBodyVelocitiesKernel); + + + m_data->m_solveContactKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverUtilsSource, "SolveContactJacobiKernel", &pErrNum, solverUtilsProg,additionalMacros ); + b3Assert(m_data->m_solveContactKernel ); + + m_data->m_solveFrictionKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverUtilsSource, "SolveFrictionJacobiKernel", &pErrNum, solverUtilsProg,additionalMacros ); + b3Assert(m_data->m_solveFrictionKernel); + } + +} + + +b3GpuJacobiContactSolver::~b3GpuJacobiContactSolver() +{ + clReleaseKernel(m_data->m_solveContactKernel); + clReleaseKernel(m_data->m_solveFrictionKernel); + clReleaseKernel(m_data->m_countBodiesKernel); + clReleaseKernel(m_data->m_contactToConstraintSplitKernel); + clReleaseKernel(m_data->m_averageVelocitiesKernel); + clReleaseKernel(m_data->m_updateBodyVelocitiesKernel); + clReleaseKernel(m_data->m_clearVelocitiesKernel ); + + delete m_data->m_deltaLinearVelocities; + delete m_data->m_deltaAngularVelocities; + delete m_data->m_contactConstraints; + delete m_data->m_offsetSplitBodies; + delete m_data->m_contactConstraintOffsets; + delete m_data->m_bodyCount; + delete m_data->m_filler; + delete m_data->m_scan; + delete m_data; +} + + + +b3Vector3 make_float4(float v) +{ + return b3MakeVector3 (v,v,v); +} + +b3Vector4 make_float4(float x,float y, float z, float w) +{ + return b3MakeVector4 (x,y,z,w); +} + + + static + inline + float calcRelVel(const b3Vector3& l0, const b3Vector3& l1, const b3Vector3& a0, const b3Vector3& a1, + const b3Vector3& linVel0, const b3Vector3& angVel0, const b3Vector3& linVel1, const b3Vector3& angVel1) + { + return b3Dot(l0, linVel0) + b3Dot(a0, angVel0) + b3Dot(l1, linVel1) + b3Dot(a1, angVel1); + } + + + static + inline + void setLinearAndAngular(const b3Vector3& n, const b3Vector3& r0, const b3Vector3& r1, + b3Vector3& linear, b3Vector3& angular0, b3Vector3& angular1) + { + linear = n; + angular0 = b3Cross(r0, n); + angular1 = -b3Cross(r1, n); + } + + +static __inline void solveContact(b3GpuConstraint4& cs, + const b3Vector3& posA, const b3Vector3& linVelARO, const b3Vector3& angVelARO, float invMassA, const b3Matrix3x3& invInertiaA, + const b3Vector3& posB, const b3Vector3& linVelBRO, const b3Vector3& angVelBRO, float invMassB, const b3Matrix3x3& invInertiaB, + float maxRambdaDt[4], float minRambdaDt[4], b3Vector3& dLinVelA, b3Vector3& dAngVelA, b3Vector3& dLinVelB, b3Vector3& dAngVelB) +{ + + + for(int ic=0; ic<4; ic++) + { + // dont necessary because this makes change to 0 + if( cs.m_jacCoeffInv[ic] == 0.f ) continue; + + { + b3Vector3 angular0, angular1, linear; + b3Vector3 r0 = cs.m_worldPos[ic] - (b3Vector3&)posA; + b3Vector3 r1 = cs.m_worldPos[ic] - (b3Vector3&)posB; + setLinearAndAngular( (const b3Vector3 &)cs.m_linear, (const b3Vector3 &)r0, (const b3Vector3 &)r1, linear, angular0, angular1 ); + + float rambdaDt = calcRelVel((const b3Vector3 &)cs.m_linear,(const b3Vector3 &) -cs.m_linear, angular0, angular1, + linVelARO+dLinVelA, angVelARO+dAngVelA, linVelBRO+dLinVelB, angVelBRO+dAngVelB ) + cs.m_b[ic]; + rambdaDt *= cs.m_jacCoeffInv[ic]; + + { + float prevSum = cs.m_appliedRambdaDt[ic]; + float updated = prevSum; + updated += rambdaDt; + updated = b3Max( updated, minRambdaDt[ic] ); + updated = b3Min( updated, maxRambdaDt[ic] ); + rambdaDt = updated - prevSum; + cs.m_appliedRambdaDt[ic] = updated; + } + + b3Vector3 linImp0 = invMassA*linear*rambdaDt; + b3Vector3 linImp1 = invMassB*(-linear)*rambdaDt; + b3Vector3 angImp0 = (invInertiaA* angular0)*rambdaDt; + b3Vector3 angImp1 = (invInertiaB* angular1)*rambdaDt; +#ifdef _WIN32 + b3Assert(_finite(linImp0.getX())); + b3Assert(_finite(linImp1.getX())); +#endif + + if (invMassA) + { + dLinVelA += linImp0; + dAngVelA += angImp0; + } + if (invMassB) + { + dLinVelB += linImp1; + dAngVelB += angImp1; + } + } + } +} + + + +void solveContact3(b3GpuConstraint4* cs, + b3Vector3* posAPtr, b3Vector3* linVelA, b3Vector3* angVelA, float invMassA, const b3Matrix3x3& invInertiaA, + b3Vector3* posBPtr, b3Vector3* linVelB, b3Vector3* angVelB, float invMassB, const b3Matrix3x3& invInertiaB, + b3Vector3* dLinVelA, b3Vector3* dAngVelA, b3Vector3* dLinVelB, b3Vector3* dAngVelB) +{ + float minRambdaDt = 0; + float maxRambdaDt = FLT_MAX; + + for(int ic=0; ic<4; ic++) + { + if( cs->m_jacCoeffInv[ic] == 0.f ) continue; + + b3Vector3 angular0, angular1, linear; + b3Vector3 r0 = cs->m_worldPos[ic] - *posAPtr; + b3Vector3 r1 = cs->m_worldPos[ic] - *posBPtr; + setLinearAndAngular( cs->m_linear, r0, r1, linear, angular0, angular1 ); + + float rambdaDt = calcRelVel( cs->m_linear, -cs->m_linear, angular0, angular1, + *linVelA+*dLinVelA, *angVelA+*dAngVelA, *linVelB+*dLinVelB, *angVelB+*dAngVelB ) + cs->m_b[ic]; + rambdaDt *= cs->m_jacCoeffInv[ic]; + + { + float prevSum = cs->m_appliedRambdaDt[ic]; + float updated = prevSum; + updated += rambdaDt; + updated = b3Max( updated, minRambdaDt ); + updated = b3Min( updated, maxRambdaDt ); + rambdaDt = updated - prevSum; + cs->m_appliedRambdaDt[ic] = updated; + } + + b3Vector3 linImp0 = invMassA*linear*rambdaDt; + b3Vector3 linImp1 = invMassB*(-linear)*rambdaDt; + b3Vector3 angImp0 = (invInertiaA* angular0)*rambdaDt; + b3Vector3 angImp1 = (invInertiaB* angular1)*rambdaDt; + + if (invMassA) + { + *dLinVelA += linImp0; + *dAngVelA += angImp0; + } + if (invMassB) + { + *dLinVelB += linImp1; + *dAngVelB += angImp1; + } + } +} + + +static inline void solveFriction(b3GpuConstraint4& cs, + const b3Vector3& posA, const b3Vector3& linVelARO, const b3Vector3& angVelARO, float invMassA, const b3Matrix3x3& invInertiaA, + const b3Vector3& posB, const b3Vector3& linVelBRO, const b3Vector3& angVelBRO, float invMassB, const b3Matrix3x3& invInertiaB, + float maxRambdaDt[4], float minRambdaDt[4], b3Vector3& dLinVelA, b3Vector3& dAngVelA, b3Vector3& dLinVelB, b3Vector3& dAngVelB) +{ + + b3Vector3 linVelA = linVelARO+dLinVelA; + b3Vector3 linVelB = linVelBRO+dLinVelB; + b3Vector3 angVelA = angVelARO+dAngVelA; + b3Vector3 angVelB = angVelBRO+dAngVelB; + + if( cs.m_fJacCoeffInv[0] == 0 && cs.m_fJacCoeffInv[0] == 0 ) return; + const b3Vector3& center = (const b3Vector3&)cs.m_center; + + b3Vector3 n = -(const b3Vector3&)cs.m_linear; + + b3Vector3 tangent[2]; +#if 1 + b3PlaneSpace1 (n, tangent[0],tangent[1]); +#else + b3Vector3 r = cs.m_worldPos[0]-center; + tangent[0] = cross3( n, r ); + tangent[1] = cross3( tangent[0], n ); + tangent[0] = normalize3( tangent[0] ); + tangent[1] = normalize3( tangent[1] ); +#endif + + b3Vector3 angular0, angular1, linear; + b3Vector3 r0 = center - posA; + b3Vector3 r1 = center - posB; + for(int i=0; i<2; i++) + { + setLinearAndAngular( tangent[i], r0, r1, linear, angular0, angular1 ); + float rambdaDt = calcRelVel(linear, -linear, angular0, angular1, + linVelA, angVelA, linVelB, angVelB ); + rambdaDt *= cs.m_fJacCoeffInv[i]; + + { + float prevSum = cs.m_fAppliedRambdaDt[i]; + float updated = prevSum; + updated += rambdaDt; + updated = b3Max( updated, minRambdaDt[i] ); + updated = b3Min( updated, maxRambdaDt[i] ); + rambdaDt = updated - prevSum; + cs.m_fAppliedRambdaDt[i] = updated; + } + + b3Vector3 linImp0 = invMassA*linear*rambdaDt; + b3Vector3 linImp1 = invMassB*(-linear)*rambdaDt; + b3Vector3 angImp0 = (invInertiaA* angular0)*rambdaDt; + b3Vector3 angImp1 = (invInertiaB* angular1)*rambdaDt; +#ifdef _WIN32 + b3Assert(_finite(linImp0.getX())); + b3Assert(_finite(linImp1.getX())); +#endif + if (invMassA) + { + dLinVelA += linImp0; + dAngVelA += angImp0; + } + if (invMassB) + { + dLinVelB += linImp1; + dAngVelB += angImp1; + } + } + + { // angular damping for point constraint + b3Vector3 ab = ( posB - posA ).normalized(); + b3Vector3 ac = ( center - posA ).normalized(); + if( b3Dot( ab, ac ) > 0.95f || (invMassA == 0.f || invMassB == 0.f)) + { + float angNA = b3Dot( n, angVelA ); + float angNB = b3Dot( n, angVelB ); + + if (invMassA) + dAngVelA -= (angNA*0.1f)*n; + if (invMassB) + dAngVelB -= (angNB*0.1f)*n; + } + } + +} + + + + +float calcJacCoeff(const b3Vector3& linear0, const b3Vector3& linear1, const b3Vector3& angular0, const b3Vector3& angular1, + float invMass0, const b3Matrix3x3* invInertia0, float invMass1, const b3Matrix3x3* invInertia1, float countA, float countB) +{ + // linear0,1 are normlized + float jmj0 = invMass0;//dot3F4(linear0, linear0)*invMass0; + + float jmj1 = b3Dot(mtMul3(angular0,*invInertia0), angular0); + float jmj2 = invMass1;//dot3F4(linear1, linear1)*invMass1; + float jmj3 = b3Dot(mtMul3(angular1,*invInertia1), angular1); + return -1.f/((jmj0+jmj1)*countA+(jmj2+jmj3)*countB); +// return -1.f/((jmj0+jmj1)+(jmj2+jmj3)); + +} + + +void setConstraint4( const b3Vector3& posA, const b3Vector3& linVelA, const b3Vector3& angVelA, float invMassA, const b3Matrix3x3& invInertiaA, + const b3Vector3& posB, const b3Vector3& linVelB, const b3Vector3& angVelB, float invMassB, const b3Matrix3x3& invInertiaB, + b3Contact4* src, float dt, float positionDrift, float positionConstraintCoeff, float countA, float countB, + b3GpuConstraint4* dstC ) +{ + dstC->m_bodyA = abs(src->m_bodyAPtrAndSignBit); + dstC->m_bodyB = abs(src->m_bodyBPtrAndSignBit); + + float dtInv = 1.f/dt; + for(int ic=0; ic<4; ic++) + { + dstC->m_appliedRambdaDt[ic] = 0.f; + } + dstC->m_fJacCoeffInv[0] = dstC->m_fJacCoeffInv[1] = 0.f; + + + dstC->m_linear = src->m_worldNormalOnB; + dstC->m_linear[3] = 0.7f ;//src->getFrictionCoeff() ); + for(int ic=0; ic<4; ic++) + { + b3Vector3 r0 = src->m_worldPosB[ic] - posA; + b3Vector3 r1 = src->m_worldPosB[ic] - posB; + + if( ic >= src->m_worldNormalOnB[3] )//npoints + { + dstC->m_jacCoeffInv[ic] = 0.f; + continue; + } + + float relVelN; + { + b3Vector3 linear, angular0, angular1; + setLinearAndAngular(src->m_worldNormalOnB, r0, r1, linear, angular0, angular1); + + dstC->m_jacCoeffInv[ic] = calcJacCoeff(linear, -linear, angular0, angular1, + invMassA, &invInertiaA, invMassB, &invInertiaB ,countA,countB); + + relVelN = calcRelVel(linear, -linear, angular0, angular1, + linVelA, angVelA, linVelB, angVelB); + + float e = 0.f;//src->getRestituitionCoeff(); + if( relVelN*relVelN < 0.004f ) + { + e = 0.f; + } + + dstC->m_b[ic] = e*relVelN; + //float penetration = src->m_worldPos[ic].w; + dstC->m_b[ic] += (src->m_worldPosB[ic][3] + positionDrift)*positionConstraintCoeff*dtInv; + dstC->m_appliedRambdaDt[ic] = 0.f; + } + } + + if( src->m_worldNormalOnB[3] > 0 )//npoints + { // prepare friction + b3Vector3 center = make_float4(0.f); + for(int i=0; im_worldNormalOnB[3]; i++) + center += src->m_worldPosB[i]; + center /= (float)src->m_worldNormalOnB[3]; + + b3Vector3 tangent[2]; + b3PlaneSpace1(src->m_worldNormalOnB,tangent[0],tangent[1]); + + b3Vector3 r[2]; + r[0] = center - posA; + r[1] = center - posB; + + for(int i=0; i<2; i++) + { + b3Vector3 linear, angular0, angular1; + setLinearAndAngular(tangent[i], r[0], r[1], linear, angular0, angular1); + + dstC->m_fJacCoeffInv[i] = calcJacCoeff(linear, -linear, angular0, angular1, + invMassA, &invInertiaA, invMassB, &invInertiaB ,countA,countB); + dstC->m_fAppliedRambdaDt[i] = 0.f; + } + dstC->m_center = center; + } + + for(int i=0; i<4; i++) + { + if( im_worldNormalOnB[3] ) + { + dstC->m_worldPos[i] = src->m_worldPosB[i]; + } + else + { + dstC->m_worldPos[i] = make_float4(0.f); + } + } +} + + + +void ContactToConstraintKernel(b3Contact4* gContact, b3RigidBodyData* gBodies, b3InertiaData* gShapes, b3GpuConstraint4* gConstraintOut, int nContacts, +float dt, +float positionDrift, +float positionConstraintCoeff, int gIdx, b3AlignedObjectArray& bodyCount +) +{ + //int gIdx = 0;//GET_GLOBAL_IDX; + + if( gIdx < nContacts ) + { + int aIdx = abs(gContact[gIdx].m_bodyAPtrAndSignBit); + int bIdx = abs(gContact[gIdx].m_bodyBPtrAndSignBit); + + b3Vector3 posA = gBodies[aIdx].m_pos; + b3Vector3 linVelA = gBodies[aIdx].m_linVel; + b3Vector3 angVelA = gBodies[aIdx].m_angVel; + float invMassA = gBodies[aIdx].m_invMass; + b3Matrix3x3 invInertiaA = gShapes[aIdx].m_invInertiaWorld;//.m_invInertia; + + b3Vector3 posB = gBodies[bIdx].m_pos; + b3Vector3 linVelB = gBodies[bIdx].m_linVel; + b3Vector3 angVelB = gBodies[bIdx].m_angVel; + float invMassB = gBodies[bIdx].m_invMass; + b3Matrix3x3 invInertiaB = gShapes[bIdx].m_invInertiaWorld;//m_invInertia; + + b3GpuConstraint4 cs; + float countA = invMassA ? (float)(bodyCount[aIdx]) : 1; + float countB = invMassB ? (float)(bodyCount[bIdx]) : 1; + setConstraint4( posA, linVelA, angVelA, invMassA, invInertiaA, posB, linVelB, angVelB, invMassB, invInertiaB, + &gContact[gIdx], dt, positionDrift, positionConstraintCoeff,countA,countB, + &cs ); + + + + cs.m_batchIdx = gContact[gIdx].m_batchIdx; + + gConstraintOut[gIdx] = cs; + } +} + + +void b3GpuJacobiContactSolver::solveGroupHost(b3RigidBodyData* bodies,b3InertiaData* inertias,int numBodies,b3Contact4* manifoldPtr, int numManifolds,const b3JacobiSolverInfo& solverInfo) +{ + B3_PROFILE("b3GpuJacobiContactSolver::solveGroup"); + + b3AlignedObjectArray bodyCount; + bodyCount.resize(numBodies); + for (int i=0;i contactConstraintOffsets; + contactConstraintOffsets.resize(numManifolds); + + + for (int i=0;i offsetSplitBodies; + offsetSplitBodies.resize(numBodies); + unsigned int totalNumSplitBodies; + m_data->m_scan->executeHost(bodyCount,offsetSplitBodies,numBodies,&totalNumSplitBodies); + int numlastBody = bodyCount[numBodies-1]; + totalNumSplitBodies += numlastBody; + printf("totalNumSplitBodies = %d\n",totalNumSplitBodies); + + + + + + b3AlignedObjectArray contactConstraints; + contactConstraints.resize(numManifolds); + + for (int i=0;i deltaLinearVelocities; + b3AlignedObjectArray deltaAngularVelocities; + deltaLinearVelocities.resize(totalNumSplitBodies); + deltaAngularVelocities.resize(totalNumSplitBodies); + for (unsigned int i=0;i* bodies,b3OpenCLArray* inertias,b3OpenCLArray* manifoldPtr,const btJacobiSolverInfo& solverInfo) +{ + b3JacobiSolverInfo solverInfo; + solverInfo.m_fixedBodyIndex = static0Index; + + + B3_PROFILE("b3GpuJacobiContactSolver::solveGroup"); + + //int numBodies = bodies->size(); + int numManifolds = numContacts;//manifoldPtr->size(); + + { + B3_PROFILE("resize"); + m_data->m_bodyCount->resize(numBodies); + } + + unsigned int val=0; + b3Int2 val2; + val2.x=0; + val2.y=0; + + { + B3_PROFILE("m_filler"); + m_data->m_contactConstraintOffsets->resize(numManifolds); + m_data->m_filler->execute(*m_data->m_bodyCount,val,numBodies); + + + m_data->m_filler->execute(*m_data->m_contactConstraintOffsets,val2,numManifolds); + } + + { + B3_PROFILE("m_countBodiesKernel"); + b3LauncherCL launcher(this->m_queue,m_data->m_countBodiesKernel,"m_countBodiesKernel"); + launcher.setBuffer(contactBuf);//manifoldPtr->getBufferCL()); + launcher.setBuffer(m_data->m_bodyCount->getBufferCL()); + launcher.setBuffer(m_data->m_contactConstraintOffsets->getBufferCL()); + launcher.setConst(numManifolds); + launcher.setConst(solverInfo.m_fixedBodyIndex); + launcher.launch1D(numManifolds); + } + unsigned int totalNumSplitBodies=0; + { + B3_PROFILE("m_scan->execute"); + + m_data->m_offsetSplitBodies->resize(numBodies); + m_data->m_scan->execute(*m_data->m_bodyCount,*m_data->m_offsetSplitBodies,numBodies,&totalNumSplitBodies); + totalNumSplitBodies+=m_data->m_bodyCount->at(numBodies-1); + } + + { + B3_PROFILE("m_data->m_contactConstraints->resize"); + //int numContacts = manifoldPtr->size(); + m_data->m_contactConstraints->resize(numContacts); + } + + { + B3_PROFILE("contactToConstraintSplitKernel"); + b3LauncherCL launcher( m_queue, m_data->m_contactToConstraintSplitKernel,"m_contactToConstraintSplitKernel"); + launcher.setBuffer(contactBuf); + launcher.setBuffer(bodyBuf); + launcher.setBuffer(inertiaBuf); + launcher.setBuffer(m_data->m_contactConstraints->getBufferCL()); + launcher.setBuffer(m_data->m_bodyCount->getBufferCL()); + launcher.setConst(numContacts); + launcher.setConst(solverInfo.m_deltaTime); + launcher.setConst(solverInfo.m_positionDrift); + launcher.setConst(solverInfo.m_positionConstraintCoeff); + launcher.launch1D( numContacts, 64 ); + + } + + + { + B3_PROFILE("m_data->m_deltaLinearVelocities->resize"); + m_data->m_deltaLinearVelocities->resize(totalNumSplitBodies); + m_data->m_deltaAngularVelocities->resize(totalNumSplitBodies); + } + + + + { + B3_PROFILE("m_clearVelocitiesKernel"); + b3LauncherCL launch(m_queue,m_data->m_clearVelocitiesKernel,"m_clearVelocitiesKernel"); + launch.setBuffer(m_data->m_deltaAngularVelocities->getBufferCL()); + launch.setBuffer(m_data->m_deltaLinearVelocities->getBufferCL()); + launch.setConst(totalNumSplitBodies); + launch.launch1D(totalNumSplitBodies); + clFinish(m_queue); + } + + + int maxIter = solverInfo.m_numIterations; + + for (int iter = 0;iterm_solveContactKernel,"m_solveContactKernel" ); + launcher.setBuffer(m_data->m_contactConstraints->getBufferCL()); + launcher.setBuffer(bodyBuf); + launcher.setBuffer(inertiaBuf); + launcher.setBuffer(m_data->m_contactConstraintOffsets->getBufferCL()); + launcher.setBuffer(m_data->m_offsetSplitBodies->getBufferCL()); + launcher.setBuffer(m_data->m_deltaLinearVelocities->getBufferCL()); + launcher.setBuffer(m_data->m_deltaAngularVelocities->getBufferCL()); + launcher.setConst(solverInfo.m_deltaTime); + launcher.setConst(solverInfo.m_positionDrift); + launcher.setConst(solverInfo.m_positionConstraintCoeff); + launcher.setConst(solverInfo.m_fixedBodyIndex); + launcher.setConst(numManifolds); + + launcher.launch1D(numManifolds); + clFinish(m_queue); + } + + + + { + B3_PROFILE("average velocities"); + b3LauncherCL launcher( m_queue, m_data->m_averageVelocitiesKernel,"m_averageVelocitiesKernel"); + launcher.setBuffer(bodyBuf); + launcher.setBuffer(m_data->m_offsetSplitBodies->getBufferCL()); + launcher.setBuffer(m_data->m_bodyCount->getBufferCL()); + launcher.setBuffer(m_data->m_deltaLinearVelocities->getBufferCL()); + launcher.setBuffer(m_data->m_deltaAngularVelocities->getBufferCL()); + launcher.setConst(numBodies); + launcher.launch1D(numBodies); + clFinish(m_queue); + } + + + { + B3_PROFILE("m_solveFrictionKernel"); + b3LauncherCL launcher( m_queue, m_data->m_solveFrictionKernel,"m_solveFrictionKernel"); + launcher.setBuffer(m_data->m_contactConstraints->getBufferCL()); + launcher.setBuffer(bodyBuf); + launcher.setBuffer(inertiaBuf); + launcher.setBuffer(m_data->m_contactConstraintOffsets->getBufferCL()); + launcher.setBuffer(m_data->m_offsetSplitBodies->getBufferCL()); + launcher.setBuffer(m_data->m_deltaLinearVelocities->getBufferCL()); + launcher.setBuffer(m_data->m_deltaAngularVelocities->getBufferCL()); + launcher.setConst(solverInfo.m_deltaTime); + launcher.setConst(solverInfo.m_positionDrift); + launcher.setConst(solverInfo.m_positionConstraintCoeff); + launcher.setConst(solverInfo.m_fixedBodyIndex); + launcher.setConst(numManifolds); + + launcher.launch1D(numManifolds); + clFinish(m_queue); + } + + + { + B3_PROFILE("average velocities"); + b3LauncherCL launcher( m_queue, m_data->m_averageVelocitiesKernel,"m_averageVelocitiesKernel"); + launcher.setBuffer(bodyBuf); + launcher.setBuffer(m_data->m_offsetSplitBodies->getBufferCL()); + launcher.setBuffer(m_data->m_bodyCount->getBufferCL()); + launcher.setBuffer(m_data->m_deltaLinearVelocities->getBufferCL()); + launcher.setBuffer(m_data->m_deltaAngularVelocities->getBufferCL()); + launcher.setConst(numBodies); + launcher.launch1D(numBodies); + clFinish(m_queue); + } + + + + } + + + { + B3_PROFILE("update body velocities"); + b3LauncherCL launcher( m_queue, m_data->m_updateBodyVelocitiesKernel,"m_updateBodyVelocitiesKernel"); + launcher.setBuffer(bodyBuf); + launcher.setBuffer(m_data->m_offsetSplitBodies->getBufferCL()); + launcher.setBuffer(m_data->m_bodyCount->getBufferCL()); + launcher.setBuffer(m_data->m_deltaLinearVelocities->getBufferCL()); + launcher.setBuffer(m_data->m_deltaAngularVelocities->getBufferCL()); + launcher.setConst(numBodies); + launcher.launch1D(numBodies); + clFinish(m_queue); + } + + + +} + +#if 0 + +void b3GpuJacobiContactSolver::solveGroupMixed(b3OpenCLArray* bodiesGPU,b3OpenCLArray* inertiasGPU,b3OpenCLArray* manifoldPtrGPU,const btJacobiSolverInfo& solverInfo) +{ + + b3AlignedObjectArray bodiesCPU; + bodiesGPU->copyToHost(bodiesCPU); + b3AlignedObjectArray inertiasCPU; + inertiasGPU->copyToHost(inertiasCPU); + b3AlignedObjectArray manifoldPtrCPU; + manifoldPtrGPU->copyToHost(manifoldPtrCPU); + + int numBodiesCPU = bodiesGPU->size(); + int numManifoldsCPU = manifoldPtrGPU->size(); + B3_PROFILE("b3GpuJacobiContactSolver::solveGroupMixed"); + + b3AlignedObjectArray bodyCount; + bodyCount.resize(numBodiesCPU); + for (int i=0;i contactConstraintOffsets; + contactConstraintOffsets.resize(numManifoldsCPU); + + + for (int i=0;i offsetSplitBodies; + offsetSplitBodies.resize(numBodiesCPU); + unsigned int totalNumSplitBodiesCPU; + m_data->m_scan->executeHost(bodyCount,offsetSplitBodies,numBodiesCPU,&totalNumSplitBodiesCPU); + int numlastBody = bodyCount[numBodiesCPU-1]; + totalNumSplitBodiesCPU += numlastBody; + + int numBodies = bodiesGPU->size(); + int numManifolds = manifoldPtrGPU->size(); + + m_data->m_bodyCount->resize(numBodies); + + unsigned int val=0; + b3Int2 val2; + val2.x=0; + val2.y=0; + + { + B3_PROFILE("m_filler"); + m_data->m_contactConstraintOffsets->resize(numManifolds); + m_data->m_filler->execute(*m_data->m_bodyCount,val,numBodies); + + + m_data->m_filler->execute(*m_data->m_contactConstraintOffsets,val2,numManifolds); + } + + { + B3_PROFILE("m_countBodiesKernel"); + b3LauncherCL launcher(this->m_queue,m_data->m_countBodiesKernel); + launcher.setBuffer(manifoldPtrGPU->getBufferCL()); + launcher.setBuffer(m_data->m_bodyCount->getBufferCL()); + launcher.setBuffer(m_data->m_contactConstraintOffsets->getBufferCL()); + launcher.setConst(numManifolds); + launcher.setConst(solverInfo.m_fixedBodyIndex); + launcher.launch1D(numManifolds); + } + + unsigned int totalNumSplitBodies=0; + m_data->m_offsetSplitBodies->resize(numBodies); + m_data->m_scan->execute(*m_data->m_bodyCount,*m_data->m_offsetSplitBodies,numBodies,&totalNumSplitBodies); + totalNumSplitBodies+=m_data->m_bodyCount->at(numBodies-1); + + if (totalNumSplitBodies != totalNumSplitBodiesCPU) + { + printf("error in totalNumSplitBodies!\n"); + } + + int numContacts = manifoldPtrGPU->size(); + m_data->m_contactConstraints->resize(numContacts); + + + { + B3_PROFILE("contactToConstraintSplitKernel"); + b3LauncherCL launcher( m_queue, m_data->m_contactToConstraintSplitKernel); + launcher.setBuffer(manifoldPtrGPU->getBufferCL()); + launcher.setBuffer(bodiesGPU->getBufferCL()); + launcher.setBuffer(inertiasGPU->getBufferCL()); + launcher.setBuffer(m_data->m_contactConstraints->getBufferCL()); + launcher.setBuffer(m_data->m_bodyCount->getBufferCL()); + launcher.setConst(numContacts); + launcher.setConst(solverInfo.m_deltaTime); + launcher.setConst(solverInfo.m_positionDrift); + launcher.setConst(solverInfo.m_positionConstraintCoeff); + launcher.launch1D( numContacts, 64 ); + clFinish(m_queue); + } + + + + b3AlignedObjectArray contactConstraints; + contactConstraints.resize(numManifoldsCPU); + + for (int i=0;i deltaLinearVelocities; + b3AlignedObjectArray deltaAngularVelocities; + deltaLinearVelocities.resize(totalNumSplitBodiesCPU); + deltaAngularVelocities.resize(totalNumSplitBodiesCPU); + for (int i=0;im_deltaLinearVelocities->resize(totalNumSplitBodies); + m_data->m_deltaAngularVelocities->resize(totalNumSplitBodies); + + + + { + B3_PROFILE("m_clearVelocitiesKernel"); + b3LauncherCL launch(m_queue,m_data->m_clearVelocitiesKernel); + launch.setBuffer(m_data->m_deltaAngularVelocities->getBufferCL()); + launch.setBuffer(m_data->m_deltaLinearVelocities->getBufferCL()); + launch.setConst(totalNumSplitBodies); + launch.launch1D(totalNumSplitBodies); + } + + + ///!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + + m_data->m_contactConstraints->copyToHost(contactConstraints); + m_data->m_offsetSplitBodies->copyToHost(offsetSplitBodies); + m_data->m_contactConstraintOffsets->copyToHost(contactConstraintOffsets); + m_data->m_deltaLinearVelocities->copyToHost(deltaLinearVelocities); + m_data->m_deltaAngularVelocities->copyToHost(deltaAngularVelocities); + + for (int iter = 0;iterm_solveContactKernel ); + launcher.setBuffer(m_data->m_contactConstraints->getBufferCL()); + launcher.setBuffer(bodiesGPU->getBufferCL()); + launcher.setBuffer(inertiasGPU->getBufferCL()); + launcher.setBuffer(m_data->m_contactConstraintOffsets->getBufferCL()); + launcher.setBuffer(m_data->m_offsetSplitBodies->getBufferCL()); + launcher.setBuffer(m_data->m_deltaLinearVelocities->getBufferCL()); + launcher.setBuffer(m_data->m_deltaAngularVelocities->getBufferCL()); + launcher.setConst(solverInfo.m_deltaTime); + launcher.setConst(solverInfo.m_positionDrift); + launcher.setConst(solverInfo.m_positionConstraintCoeff); + launcher.setConst(solverInfo.m_fixedBodyIndex); + launcher.setConst(numManifolds); + + launcher.launch1D(numManifolds); + clFinish(m_queue); + } + + + int i=0; + for( i=0; im_averageVelocitiesKernel); + launcher.setBuffer(bodiesGPU->getBufferCL()); + launcher.setBuffer(m_data->m_offsetSplitBodies->getBufferCL()); + launcher.setBuffer(m_data->m_bodyCount->getBufferCL()); + launcher.setBuffer(m_data->m_deltaLinearVelocities->getBufferCL()); + launcher.setBuffer(m_data->m_deltaAngularVelocities->getBufferCL()); + launcher.setConst(numBodies); + launcher.launch1D(numBodies); + clFinish(m_queue); + } + + //easy + for (int i=0;im_deltaAngularVelocities->copyFromHost(deltaAngularVelocities); + //m_data->m_deltaLinearVelocities->copyFromHost(deltaLinearVelocities); + m_data->m_deltaAngularVelocities->copyToHost(deltaAngularVelocities); + m_data->m_deltaLinearVelocities->copyToHost(deltaLinearVelocities); + +#if 0 + + { + B3_PROFILE("m_solveFrictionKernel"); + b3LauncherCL launcher( m_queue, m_data->m_solveFrictionKernel); + launcher.setBuffer(m_data->m_contactConstraints->getBufferCL()); + launcher.setBuffer(bodiesGPU->getBufferCL()); + launcher.setBuffer(inertiasGPU->getBufferCL()); + launcher.setBuffer(m_data->m_contactConstraintOffsets->getBufferCL()); + launcher.setBuffer(m_data->m_offsetSplitBodies->getBufferCL()); + launcher.setBuffer(m_data->m_deltaLinearVelocities->getBufferCL()); + launcher.setBuffer(m_data->m_deltaAngularVelocities->getBufferCL()); + launcher.setConst(solverInfo.m_deltaTime); + launcher.setConst(solverInfo.m_positionDrift); + launcher.setConst(solverInfo.m_positionConstraintCoeff); + launcher.setConst(solverInfo.m_fixedBodyIndex); + launcher.setConst(numManifolds); + + launcher.launch1D(numManifolds); + clFinish(m_queue); + } + + //solve friction + + for(int i=0; im_averageVelocitiesKernel); + launcher.setBuffer(bodiesGPU->getBufferCL()); + launcher.setBuffer(m_data->m_offsetSplitBodies->getBufferCL()); + launcher.setBuffer(m_data->m_bodyCount->getBufferCL()); + launcher.setBuffer(m_data->m_deltaLinearVelocities->getBufferCL()); + launcher.setBuffer(m_data->m_deltaAngularVelocities->getBufferCL()); + launcher.setConst(numBodies); + launcher.launch1D(numBodies); + clFinish(m_queue); + } + + //easy + for (int i=0;im_updateBodyVelocitiesKernel); + launcher.setBuffer(bodiesGPU->getBufferCL()); + launcher.setBuffer(m_data->m_offsetSplitBodies->getBufferCL()); + launcher.setBuffer(m_data->m_bodyCount->getBufferCL()); + launcher.setBuffer(m_data->m_deltaLinearVelocities->getBufferCL()); + launcher.setBuffer(m_data->m_deltaAngularVelocities->getBufferCL()); + launcher.setConst(numBodies); + launcher.launch1D(numBodies); + clFinish(m_queue); + } + + + //easy + for (int i=0;icopyFromHost(bodiesCPU); + + +} +#endif diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuJacobiContactSolver.h b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuJacobiContactSolver.h new file mode 100644 index 000000000000..b418f29ec437 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuJacobiContactSolver.h @@ -0,0 +1,62 @@ + +#ifndef B3_GPU_JACOBI_CONTACT_SOLVER_H +#define B3_GPU_JACOBI_CONTACT_SOLVER_H +#include "Bullet3OpenCL/Initialize/b3OpenCLInclude.h" +//#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" + +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3Contact4Data.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3OpenCLArray.h" + + +//struct b3InertiaData; +//b3InertiaData + +class b3TypedConstraint; + +struct b3JacobiSolverInfo +{ + int m_fixedBodyIndex; + + float m_deltaTime; + float m_positionDrift; + float m_positionConstraintCoeff; + int m_numIterations; + + b3JacobiSolverInfo() + :m_fixedBodyIndex(0), + m_deltaTime(1./60.f), + m_positionDrift( 0.005f ), + m_positionConstraintCoeff( 0.99f ), + m_numIterations(7) + { + } +}; +class b3GpuJacobiContactSolver +{ +protected: + + struct b3GpuJacobiSolverInternalData* m_data; + + cl_context m_context; + cl_device_id m_device; + cl_command_queue m_queue; + +public: + + b3GpuJacobiContactSolver(cl_context ctx, cl_device_id device, cl_command_queue queue, int pairCapacity); + virtual ~b3GpuJacobiContactSolver(); + + + void solveContacts(int numBodies, cl_mem bodyBuf, cl_mem inertiaBuf, int numContacts, cl_mem contactBuf, const struct b3Config& config, int static0Index); + void solveGroupHost(b3RigidBodyData* bodies,b3InertiaData* inertias,int numBodies,struct b3Contact4* manifoldPtr, int numManifolds,const b3JacobiSolverInfo& solverInfo); + //void solveGroupHost(btRigidBodyCL* bodies,b3InertiaData* inertias,int numBodies,btContact4* manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btJacobiSolverInfo& solverInfo); + + //b3Scalar solveGroup(b3OpenCLArray* gpuBodies,b3OpenCLArray* gpuInertias, int numBodies,b3OpenCLArray* gpuConstraints,int numConstraints,const b3ContactSolverInfo& infoGlobal); + + //void solveGroup(btOpenCLArray* bodies,btOpenCLArray* inertias,btOpenCLArray* manifoldPtr,const btJacobiSolverInfo& solverInfo); + //void solveGroupMixed(btOpenCLArray* bodies,btOpenCLArray* inertias,btOpenCLArray* manifoldPtr,const btJacobiSolverInfo& solverInfo); + +}; +#endif //B3_GPU_JACOBI_CONTACT_SOLVER_H + diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuNarrowPhase.cpp b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuNarrowPhase.cpp new file mode 100644 index 000000000000..698fa15f9611 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuNarrowPhase.cpp @@ -0,0 +1,1107 @@ +#include "b3GpuNarrowPhase.h" + + +#include "Bullet3OpenCL/ParallelPrimitives/b3OpenCLArray.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3ConvexPolyhedronData.h" +#include "Bullet3OpenCL/NarrowphaseCollision/b3ConvexHullContact.h" +#include "Bullet3OpenCL/BroadphaseCollision/b3SapAabb.h" +#include +#include "Bullet3Collision/NarrowPhaseCollision/b3Config.h" +#include "Bullet3OpenCL/NarrowphaseCollision/b3OptimizedBvh.h" +#include "Bullet3OpenCL/NarrowphaseCollision/b3TriangleIndexVertexArray.h" +#include "Bullet3Geometry/b3AabbUtil.h" +#include "Bullet3OpenCL/NarrowphaseCollision/b3BvhInfo.h" + +#include "b3GpuNarrowPhaseInternalData.h" +#include "Bullet3OpenCL/NarrowphaseCollision/b3QuantizedBvh.h" +#include "Bullet3Collision/NarrowPhaseCollision/b3ConvexUtility.h" + + + + +b3GpuNarrowPhase::b3GpuNarrowPhase(cl_context ctx, cl_device_id device, cl_command_queue queue, const b3Config& config) +:m_data(0) ,m_planeBodyIndex(-1),m_static0Index(-1), +m_context(ctx), +m_device(device), +m_queue(queue) +{ + + m_data = new b3GpuNarrowPhaseInternalData(); + m_data->m_currentContactBuffer = 0; + + memset(m_data,0,sizeof(b3GpuNarrowPhaseInternalData)); + + + m_data->m_config = config; + + m_data->m_gpuSatCollision = new GpuSatCollision(ctx,device,queue); + + + m_data->m_triangleConvexPairs = new b3OpenCLArray(m_context,m_queue, config.m_maxTriConvexPairCapacity); + + + //m_data->m_convexPairsOutGPU = new b3OpenCLArray(ctx,queue,config.m_maxBroadphasePairs,false); + //m_data->m_planePairs = new b3OpenCLArray(ctx,queue,config.m_maxBroadphasePairs,false); + + m_data->m_pBufContactOutCPU = new b3AlignedObjectArray(); + m_data->m_pBufContactOutCPU->resize(config.m_maxBroadphasePairs); + m_data->m_bodyBufferCPU = new b3AlignedObjectArray(); + m_data->m_bodyBufferCPU->resize(config.m_maxConvexBodies); + + m_data->m_inertiaBufferCPU = new b3AlignedObjectArray(); + m_data->m_inertiaBufferCPU->resize(config.m_maxConvexBodies); + + m_data->m_pBufContactBuffersGPU[0] = new b3OpenCLArray(ctx,queue, config.m_maxContactCapacity,true); + m_data->m_pBufContactBuffersGPU[1] = new b3OpenCLArray(ctx,queue, config.m_maxContactCapacity,true); + + m_data->m_inertiaBufferGPU = new b3OpenCLArray(ctx,queue,config.m_maxConvexBodies,false); + m_data->m_collidablesGPU = new b3OpenCLArray(ctx,queue,config.m_maxConvexShapes); + m_data->m_collidablesCPU.reserve(config.m_maxConvexShapes); + + m_data->m_localShapeAABBCPU = new b3AlignedObjectArray; + m_data->m_localShapeAABBGPU = new b3OpenCLArray(ctx,queue,config.m_maxConvexShapes); + + + //m_data->m_solverDataGPU = adl::Solver::allocate(ctx,queue, config.m_maxBroadphasePairs,false); + m_data->m_bodyBufferGPU = new b3OpenCLArray(ctx,queue, config.m_maxConvexBodies,false); + + m_data->m_convexFacesGPU = new b3OpenCLArray(ctx,queue,config.m_maxConvexShapes*config.m_maxFacesPerShape,false); + m_data->m_convexFaces.reserve(config.m_maxConvexShapes*config.m_maxFacesPerShape); + + m_data->m_gpuChildShapes = new b3OpenCLArray(ctx,queue,config.m_maxCompoundChildShapes,false); + + m_data->m_convexPolyhedraGPU = new b3OpenCLArray(ctx,queue,config.m_maxConvexShapes,false); + m_data->m_convexPolyhedra.reserve(config.m_maxConvexShapes); + + m_data->m_uniqueEdgesGPU = new b3OpenCLArray(ctx,queue,config.m_maxConvexUniqueEdges,true); + m_data->m_uniqueEdges.reserve(config.m_maxConvexUniqueEdges); + + + + m_data->m_convexVerticesGPU = new b3OpenCLArray(ctx,queue,config.m_maxConvexVertices,true); + m_data->m_convexVertices.reserve(config.m_maxConvexVertices); + + m_data->m_convexIndicesGPU = new b3OpenCLArray(ctx,queue,config.m_maxConvexIndices,true); + m_data->m_convexIndices.reserve(config.m_maxConvexIndices); + + m_data->m_worldVertsB1GPU = new b3OpenCLArray(ctx,queue,config.m_maxConvexBodies*config.m_maxVerticesPerFace); + m_data->m_clippingFacesOutGPU = new b3OpenCLArray(ctx,queue,config.m_maxConvexBodies); + m_data->m_worldNormalsAGPU = new b3OpenCLArray(ctx,queue,config.m_maxConvexBodies); + m_data->m_worldVertsA1GPU = new b3OpenCLArray(ctx,queue,config.m_maxConvexBodies*config.m_maxVerticesPerFace); + m_data->m_worldVertsB2GPU = new b3OpenCLArray(ctx,queue,config.m_maxConvexBodies*config.m_maxVerticesPerFace); + + + + m_data->m_convexData = new b3AlignedObjectArray(); + + m_data->m_convexData->resize(config.m_maxConvexShapes); + m_data->m_convexPolyhedra.resize(config.m_maxConvexShapes); + + m_data->m_numAcceleratedShapes = 0; + m_data->m_numAcceleratedRigidBodies = 0; + + + m_data->m_subTreesGPU = new b3OpenCLArray(this->m_context,this->m_queue); + m_data->m_treeNodesGPU = new b3OpenCLArray(this->m_context,this->m_queue); + m_data->m_bvhInfoGPU = new b3OpenCLArray(this->m_context,this->m_queue); + + //m_data->m_contactCGPU = new b3OpenCLArray(ctx,queue,config.m_maxBroadphasePairs,false); + //m_data->m_frictionCGPU = new b3OpenCLArray::allocateFrictionConstraint( m_data->m_deviceCL, config.m_maxBroadphasePairs); + + + +} + + +b3GpuNarrowPhase::~b3GpuNarrowPhase() +{ + delete m_data->m_gpuSatCollision; + + delete m_data->m_triangleConvexPairs; + //delete m_data->m_convexPairsOutGPU; + //delete m_data->m_planePairs; + delete m_data->m_pBufContactOutCPU; + delete m_data->m_bodyBufferCPU; + delete m_data->m_inertiaBufferCPU; + delete m_data->m_pBufContactBuffersGPU[0]; + delete m_data->m_pBufContactBuffersGPU[1]; + + + delete m_data->m_inertiaBufferGPU; + delete m_data->m_collidablesGPU; + delete m_data->m_localShapeAABBCPU; + delete m_data->m_localShapeAABBGPU; + delete m_data->m_bodyBufferGPU; + delete m_data->m_convexFacesGPU; + delete m_data->m_gpuChildShapes; + delete m_data->m_convexPolyhedraGPU; + delete m_data->m_uniqueEdgesGPU; + delete m_data->m_convexVerticesGPU; + delete m_data->m_convexIndicesGPU; + delete m_data->m_worldVertsB1GPU; + delete m_data->m_clippingFacesOutGPU; + delete m_data->m_worldNormalsAGPU; + delete m_data->m_worldVertsA1GPU; + delete m_data->m_worldVertsB2GPU; + + delete m_data->m_bvhInfoGPU; + + for (int i=0;im_bvhData.size();i++) + { + delete m_data->m_bvhData[i]; + } + for (int i=0;im_meshInterfaces.size();i++) + { + delete m_data->m_meshInterfaces[i]; + } + m_data->m_meshInterfaces.clear(); + m_data->m_bvhData.clear(); + delete m_data->m_treeNodesGPU; + delete m_data->m_subTreesGPU; + + + delete m_data->m_convexData; + delete m_data; +} + + +int b3GpuNarrowPhase::allocateCollidable() +{ + int curSize = m_data->m_collidablesCPU.size(); + if (curSizem_config.m_maxConvexShapes) + { + m_data->m_collidablesCPU.expand(); + return curSize; + } + else + { + b3Error("allocateCollidable out-of-range %d\n",m_data->m_config.m_maxConvexShapes); + } + return -1; + +} + + + + + +int b3GpuNarrowPhase::registerSphereShape(float radius) +{ + int collidableIndex = allocateCollidable(); + if (collidableIndex<0) + return collidableIndex; + + + b3Collidable& col = getCollidableCpu(collidableIndex); + col.m_shapeType = SHAPE_SPHERE; + col.m_shapeIndex = 0; + col.m_radius = radius; + + if (col.m_shapeIndex>=0) + { + b3SapAabb aabb; + b3Vector3 myAabbMin=b3MakeVector3(-radius,-radius,-radius); + b3Vector3 myAabbMax=b3MakeVector3(radius,radius,radius); + + aabb.m_min[0] = myAabbMin[0];//s_convexHeightField->m_aabb.m_min.x; + aabb.m_min[1] = myAabbMin[1];//s_convexHeightField->m_aabb.m_min.y; + aabb.m_min[2] = myAabbMin[2];//s_convexHeightField->m_aabb.m_min.z; + aabb.m_minIndices[3] = 0; + + aabb.m_max[0] = myAabbMax[0];//s_convexHeightField->m_aabb.m_max.x; + aabb.m_max[1] = myAabbMax[1];//s_convexHeightField->m_aabb.m_max.y; + aabb.m_max[2] = myAabbMax[2];//s_convexHeightField->m_aabb.m_max.z; + aabb.m_signedMaxIndices[3] = 0; + + m_data->m_localShapeAABBCPU->push_back(aabb); +// m_data->m_localShapeAABBGPU->push_back(aabb); + clFinish(m_queue); + } + + return collidableIndex; +} + + +int b3GpuNarrowPhase::registerFace(const b3Vector3& faceNormal, float faceConstant) +{ + int faceOffset = m_data->m_convexFaces.size(); + b3GpuFace& face = m_data->m_convexFaces.expand(); + face.m_plane = b3MakeVector3(faceNormal.x,faceNormal.y,faceNormal.z,faceConstant); + return faceOffset; +} + +int b3GpuNarrowPhase::registerPlaneShape(const b3Vector3& planeNormal, float planeConstant) +{ + int collidableIndex = allocateCollidable(); + if (collidableIndex<0) + return collidableIndex; + + + b3Collidable& col = getCollidableCpu(collidableIndex); + col.m_shapeType = SHAPE_PLANE; + col.m_shapeIndex = registerFace(planeNormal,planeConstant); + col.m_radius = planeConstant; + + if (col.m_shapeIndex>=0) + { + b3SapAabb aabb; + aabb.m_min[0] = -1e30f; + aabb.m_min[1] = -1e30f; + aabb.m_min[2] = -1e30f; + aabb.m_minIndices[3] = 0; + + aabb.m_max[0] = 1e30f; + aabb.m_max[1] = 1e30f; + aabb.m_max[2] = 1e30f; + aabb.m_signedMaxIndices[3] = 0; + + m_data->m_localShapeAABBCPU->push_back(aabb); +// m_data->m_localShapeAABBGPU->push_back(aabb); + clFinish(m_queue); + } + + return collidableIndex; +} + + +int b3GpuNarrowPhase::registerConvexHullShapeInternal(b3ConvexUtility* convexPtr,b3Collidable& col) +{ + + m_data->m_convexData->resize(m_data->m_numAcceleratedShapes+1); + m_data->m_convexPolyhedra.resize(m_data->m_numAcceleratedShapes+1); + + + b3ConvexPolyhedronData& convex = m_data->m_convexPolyhedra.at(m_data->m_convexPolyhedra.size()-1); + convex.mC = convexPtr->mC; + convex.mE = convexPtr->mE; + convex.m_extents= convexPtr->m_extents; + convex.m_localCenter = convexPtr->m_localCenter; + convex.m_radius = convexPtr->m_radius; + + convex.m_numUniqueEdges = convexPtr->m_uniqueEdges.size(); + int edgeOffset = m_data->m_uniqueEdges.size(); + convex.m_uniqueEdgesOffset = edgeOffset; + + m_data->m_uniqueEdges.resize(edgeOffset+convex.m_numUniqueEdges); + + //convex data here + int i; + for ( i=0;im_uniqueEdges.size();i++) + { + m_data->m_uniqueEdges[edgeOffset+i] = convexPtr->m_uniqueEdges[i]; + } + + int faceOffset = m_data->m_convexFaces.size(); + convex.m_faceOffset = faceOffset; + convex.m_numFaces = convexPtr->m_faces.size(); + + m_data->m_convexFaces.resize(faceOffset+convex.m_numFaces); + + + for (i=0;im_faces.size();i++) + { + m_data->m_convexFaces[convex.m_faceOffset+i].m_plane = b3MakeVector3(convexPtr->m_faces[i].m_plane[0], + convexPtr->m_faces[i].m_plane[1], + convexPtr->m_faces[i].m_plane[2], + convexPtr->m_faces[i].m_plane[3]); + + + int indexOffset = m_data->m_convexIndices.size(); + int numIndices = convexPtr->m_faces[i].m_indices.size(); + m_data->m_convexFaces[convex.m_faceOffset+i].m_numIndices = numIndices; + m_data->m_convexFaces[convex.m_faceOffset+i].m_indexOffset = indexOffset; + m_data->m_convexIndices.resize(indexOffset+numIndices); + for (int p=0;pm_convexIndices[indexOffset+p] = convexPtr->m_faces[i].m_indices[p]; + } + } + + convex.m_numVertices = convexPtr->m_vertices.size(); + int vertexOffset = m_data->m_convexVertices.size(); + convex.m_vertexOffset =vertexOffset; + + m_data->m_convexVertices.resize(vertexOffset+convex.m_numVertices); + for (int i=0;im_vertices.size();i++) + { + m_data->m_convexVertices[vertexOffset+i] = convexPtr->m_vertices[i]; + } + + (*m_data->m_convexData)[m_data->m_numAcceleratedShapes] = convexPtr; + + + + return m_data->m_numAcceleratedShapes++; +} + + +int b3GpuNarrowPhase::registerConvexHullShape(const float* vertices, int strideInBytes, int numVertices, const float* scaling) +{ + b3AlignedObjectArray verts; + + unsigned char* vts = (unsigned char*) vertices; + for (int i=0;iinitializePolyhedralFeatures(&verts[0],verts.size(),merge); + } + + int collidableIndex = registerConvexHullShape(utilPtr); + delete utilPtr; + return collidableIndex; +} + +int b3GpuNarrowPhase::registerConvexHullShape(b3ConvexUtility* utilPtr) +{ + int collidableIndex = allocateCollidable(); + if (collidableIndex<0) + return collidableIndex; + + b3Collidable& col = getCollidableCpu(collidableIndex); + col.m_shapeType = SHAPE_CONVEX_HULL; + col.m_shapeIndex = -1; + + + { + b3Vector3 localCenter=b3MakeVector3(0,0,0); + for (int i=0;im_vertices.size();i++) + localCenter+=utilPtr->m_vertices[i]; + localCenter*= (1.f/utilPtr->m_vertices.size()); + utilPtr->m_localCenter = localCenter; + + col.m_shapeIndex = registerConvexHullShapeInternal(utilPtr,col); + } + + if (col.m_shapeIndex>=0) + { + b3SapAabb aabb; + + b3Vector3 myAabbMin=b3MakeVector3(1e30f,1e30f,1e30f); + b3Vector3 myAabbMax=b3MakeVector3(-1e30f,-1e30f,-1e30f); + + for (int i=0;im_vertices.size();i++) + { + myAabbMin.setMin(utilPtr->m_vertices[i]); + myAabbMax.setMax(utilPtr->m_vertices[i]); + } + aabb.m_min[0] = myAabbMin[0]; + aabb.m_min[1] = myAabbMin[1]; + aabb.m_min[2] = myAabbMin[2]; + aabb.m_minIndices[3] = 0; + + aabb.m_max[0] = myAabbMax[0]; + aabb.m_max[1] = myAabbMax[1]; + aabb.m_max[2] = myAabbMax[2]; + aabb.m_signedMaxIndices[3] = 0; + + m_data->m_localShapeAABBCPU->push_back(aabb); +// m_data->m_localShapeAABBGPU->push_back(aabb); + } + + return collidableIndex; + +} + +int b3GpuNarrowPhase::registerCompoundShape(b3AlignedObjectArray* childShapes) +{ + + int collidableIndex = allocateCollidable(); + if (collidableIndex<0) + return collidableIndex; + + b3Collidable& col = getCollidableCpu(collidableIndex); + col.m_shapeType = SHAPE_COMPOUND_OF_CONVEX_HULLS; + col.m_shapeIndex = m_data->m_cpuChildShapes.size(); + col.m_compoundBvhIndex = m_data->m_bvhInfoCPU.size(); + + { + b3Assert(col.m_shapeIndex+childShapes->size()m_config.m_maxCompoundChildShapes); + for (int i=0;isize();i++) + { + m_data->m_cpuChildShapes.push_back(childShapes->at(i)); + } + } + + + + col.m_numChildShapes = childShapes->size(); + + + b3SapAabb aabbLocalSpace; + b3Vector3 myAabbMin=b3MakeVector3(1e30f,1e30f,1e30f); + b3Vector3 myAabbMax=b3MakeVector3(-1e30f,-1e30f,-1e30f); + + b3AlignedObjectArray childLocalAabbs; + childLocalAabbs.resize(childShapes->size()); + + //compute local AABB of the compound of all children + for (int i=0;isize();i++) + { + int childColIndex = childShapes->at(i).m_shapeIndex; + //b3Collidable& childCol = getCollidableCpu(childColIndex); + b3SapAabb aabbLoc =m_data->m_localShapeAABBCPU->at(childColIndex); + + b3Vector3 childLocalAabbMin=b3MakeVector3(aabbLoc.m_min[0],aabbLoc.m_min[1],aabbLoc.m_min[2]); + b3Vector3 childLocalAabbMax=b3MakeVector3(aabbLoc.m_max[0],aabbLoc.m_max[1],aabbLoc.m_max[2]); + b3Vector3 aMin,aMax; + b3Scalar margin(0.f); + b3Transform childTr; + childTr.setIdentity(); + + childTr.setOrigin(childShapes->at(i).m_childPosition); + childTr.setRotation(b3Quaternion(childShapes->at(i).m_childOrientation)); + b3TransformAabb(childLocalAabbMin,childLocalAabbMax,margin,childTr,aMin,aMax); + myAabbMin.setMin(aMin); + myAabbMax.setMax(aMax); + childLocalAabbs[i].m_min[0] = aMin[0]; + childLocalAabbs[i].m_min[1] = aMin[1]; + childLocalAabbs[i].m_min[2] = aMin[2]; + childLocalAabbs[i].m_min[3] = 0; + childLocalAabbs[i].m_max[0] = aMax[0]; + childLocalAabbs[i].m_max[1] = aMax[1]; + childLocalAabbs[i].m_max[2] = aMax[2]; + childLocalAabbs[i].m_max[3] = 0; + } + + aabbLocalSpace.m_min[0] = myAabbMin[0];//s_convexHeightField->m_aabb.m_min.x; + aabbLocalSpace.m_min[1]= myAabbMin[1];//s_convexHeightField->m_aabb.m_min.y; + aabbLocalSpace.m_min[2]= myAabbMin[2];//s_convexHeightField->m_aabb.m_min.z; + aabbLocalSpace.m_minIndices[3] = 0; + + aabbLocalSpace.m_max[0] = myAabbMax[0];//s_convexHeightField->m_aabb.m_max.x; + aabbLocalSpace.m_max[1]= myAabbMax[1];//s_convexHeightField->m_aabb.m_max.y; + aabbLocalSpace.m_max[2]= myAabbMax[2];//s_convexHeightField->m_aabb.m_max.z; + aabbLocalSpace.m_signedMaxIndices[3] = 0; + + m_data->m_localShapeAABBCPU->push_back(aabbLocalSpace); + + + b3QuantizedBvh* bvh = new b3QuantizedBvh; + bvh->setQuantizationValues(myAabbMin,myAabbMax); + QuantizedNodeArray& nodes = bvh->getLeafNodeArray(); + int numNodes = childShapes->size(); + + for (int i=0;iquantize(&node.m_quantizedAabbMin[0],aabbMin,0); + bvh->quantize(&node.m_quantizedAabbMax[0],aabbMax,1); + int partId = 0; + node.m_escapeIndexOrTriangleIndex = (partId<<(31-MAX_NUM_PARTS_IN_BITS)) | i; + nodes.push_back(node); + } + bvh->buildInternal(); + + int numSubTrees = bvh->getSubtreeInfoArray().size(); + + //void setQuantizationValues(const b3Vector3& bvhAabbMin,const b3Vector3& bvhAabbMax,b3Scalar quantizationMargin=b3Scalar(1.0)); + //QuantizedNodeArray& getLeafNodeArray() { return m_quantizedLeafNodes; } + ///buildInternal is expert use only: assumes that setQuantizationValues and LeafNodeArray are initialized + //void buildInternal(); + + b3BvhInfo bvhInfo; + + bvhInfo.m_aabbMin = bvh->m_bvhAabbMin; + bvhInfo.m_aabbMax = bvh->m_bvhAabbMax; + bvhInfo.m_quantization = bvh->m_bvhQuantization; + bvhInfo.m_numNodes = numNodes; + bvhInfo.m_numSubTrees = numSubTrees; + bvhInfo.m_nodeOffset = m_data->m_treeNodesCPU.size(); + bvhInfo.m_subTreeOffset = m_data->m_subTreesCPU.size(); + + int numNewNodes = bvh->getQuantizedNodeArray().size(); + + for (int i=0;igetQuantizedNodeArray()[i].isLeafNode()) + { + int orgIndex = bvh->getQuantizedNodeArray()[i].getTriangleIndex(); + + b3Vector3 nodeMinVec = bvh->unQuantize(bvh->getQuantizedNodeArray()[i].m_quantizedAabbMin); + b3Vector3 nodeMaxVec = bvh->unQuantize(bvh->getQuantizedNodeArray()[i].m_quantizedAabbMax); + + for (int c=0;c<3;c++) + { + if (childLocalAabbs[orgIndex].m_min[c] < nodeMinVec[c]) + { + printf("min org (%f) and new (%f) ? at i:%d,c:%d\n",childLocalAabbs[i].m_min[c],nodeMinVec[c],i,c); + } + if (childLocalAabbs[orgIndex].m_max[c] > nodeMaxVec[c]) + { + printf("max org (%f) and new (%f) ? at i:%d,c:%d\n",childLocalAabbs[i].m_max[c],nodeMaxVec[c],i,c); + } + + } + } + + } + + m_data->m_bvhInfoCPU.push_back(bvhInfo); + + int numNewSubtrees = bvh->getSubtreeInfoArray().size(); + m_data->m_subTreesCPU.reserve(m_data->m_subTreesCPU.size()+numNewSubtrees); + for (int i=0;im_subTreesCPU.push_back(bvh->getSubtreeInfoArray()[i]); + } + int numNewTreeNodes = bvh->getQuantizedNodeArray().size(); + + for (int i=0;im_treeNodesCPU.push_back(bvh->getQuantizedNodeArray()[i]); + } + +// m_data->m_localShapeAABBGPU->push_back(aabbWS); + clFinish(m_queue); + return collidableIndex; + +} + + +int b3GpuNarrowPhase::registerConcaveMesh(b3AlignedObjectArray* vertices, b3AlignedObjectArray* indices,const float* scaling1) +{ + + + b3Vector3 scaling=b3MakeVector3(scaling1[0],scaling1[1],scaling1[2]); + + int collidableIndex = allocateCollidable(); + if (collidableIndex<0) + return collidableIndex; + + b3Collidable& col = getCollidableCpu(collidableIndex); + + col.m_shapeType = SHAPE_CONCAVE_TRIMESH; + col.m_shapeIndex = registerConcaveMeshShape(vertices,indices,col,scaling); + col.m_bvhIndex = m_data->m_bvhInfoCPU.size(); + + + b3SapAabb aabb; + b3Vector3 myAabbMin=b3MakeVector3(1e30f,1e30f,1e30f); + b3Vector3 myAabbMax=b3MakeVector3(-1e30f,-1e30f,-1e30f); + + for (int i=0;isize();i++) + { + b3Vector3 vtx(vertices->at(i)*scaling); + myAabbMin.setMin(vtx); + myAabbMax.setMax(vtx); + } + aabb.m_min[0] = myAabbMin[0]; + aabb.m_min[1] = myAabbMin[1]; + aabb.m_min[2] = myAabbMin[2]; + aabb.m_minIndices[3] = 0; + + aabb.m_max[0] = myAabbMax[0]; + aabb.m_max[1]= myAabbMax[1]; + aabb.m_max[2]= myAabbMax[2]; + aabb.m_signedMaxIndices[3]= 0; + + m_data->m_localShapeAABBCPU->push_back(aabb); +// m_data->m_localShapeAABBGPU->push_back(aabb); + + b3OptimizedBvh* bvh = new b3OptimizedBvh(); + //void b3OptimizedBvh::build(b3StridingMeshInterface* triangles, bool useQuantizedAabbCompression, const b3Vector3& bvhAabbMin, const b3Vector3& bvhAabbMax) + + bool useQuantizedAabbCompression = true; + b3TriangleIndexVertexArray* meshInterface=new b3TriangleIndexVertexArray(); + m_data->m_meshInterfaces.push_back(meshInterface); + b3IndexedMesh mesh; + mesh.m_numTriangles = indices->size()/3; + mesh.m_numVertices = vertices->size(); + mesh.m_vertexBase = (const unsigned char *)&vertices->at(0).x; + mesh.m_vertexStride = sizeof(b3Vector3); + mesh.m_triangleIndexStride = 3 * sizeof(int);// or sizeof(int) + mesh.m_triangleIndexBase = (const unsigned char *)&indices->at(0); + + meshInterface->addIndexedMesh(mesh); + bvh->build(meshInterface, useQuantizedAabbCompression, (b3Vector3&)aabb.m_min, (b3Vector3&)aabb.m_max); + m_data->m_bvhData.push_back(bvh); + int numNodes = bvh->getQuantizedNodeArray().size(); + //b3OpenCLArray* treeNodesGPU = new b3OpenCLArray(this->m_context,this->m_queue,numNodes); + int numSubTrees = bvh->getSubtreeInfoArray().size(); + + b3BvhInfo bvhInfo; + + bvhInfo.m_aabbMin = bvh->m_bvhAabbMin; + bvhInfo.m_aabbMax = bvh->m_bvhAabbMax; + bvhInfo.m_quantization = bvh->m_bvhQuantization; + bvhInfo.m_numNodes = numNodes; + bvhInfo.m_numSubTrees = numSubTrees; + bvhInfo.m_nodeOffset = m_data->m_treeNodesCPU.size(); + bvhInfo.m_subTreeOffset = m_data->m_subTreesCPU.size(); + + m_data->m_bvhInfoCPU.push_back(bvhInfo); + + + int numNewSubtrees = bvh->getSubtreeInfoArray().size(); + m_data->m_subTreesCPU.reserve(m_data->m_subTreesCPU.size()+numNewSubtrees); + for (int i=0;im_subTreesCPU.push_back(bvh->getSubtreeInfoArray()[i]); + } + int numNewTreeNodes = bvh->getQuantizedNodeArray().size(); + + for (int i=0;im_treeNodesCPU.push_back(bvh->getQuantizedNodeArray()[i]); + } + + + + + return collidableIndex; +} + +int b3GpuNarrowPhase::registerConcaveMeshShape(b3AlignedObjectArray* vertices, b3AlignedObjectArray* indices,b3Collidable& col, const float* scaling1) +{ + + + b3Vector3 scaling=b3MakeVector3(scaling1[0],scaling1[1],scaling1[2]); + + m_data->m_convexData->resize(m_data->m_numAcceleratedShapes+1); + m_data->m_convexPolyhedra.resize(m_data->m_numAcceleratedShapes+1); + + + b3ConvexPolyhedronData& convex = m_data->m_convexPolyhedra.at(m_data->m_convexPolyhedra.size()-1); + convex.mC = b3MakeVector3(0,0,0); + convex.mE = b3MakeVector3(0,0,0); + convex.m_extents= b3MakeVector3(0,0,0); + convex.m_localCenter = b3MakeVector3(0,0,0); + convex.m_radius = 0.f; + + convex.m_numUniqueEdges = 0; + int edgeOffset = m_data->m_uniqueEdges.size(); + convex.m_uniqueEdgesOffset = edgeOffset; + + int faceOffset = m_data->m_convexFaces.size(); + convex.m_faceOffset = faceOffset; + + convex.m_numFaces = indices->size()/3; + m_data->m_convexFaces.resize(faceOffset+convex.m_numFaces); + m_data->m_convexIndices.reserve(convex.m_numFaces*3); + for (int i=0;iat(indices->at(i*3))*scaling); + b3Vector3 vert1(vertices->at(indices->at(i*3+1))*scaling); + b3Vector3 vert2(vertices->at(indices->at(i*3+2))*scaling); + + b3Vector3 normal = ((vert1-vert0).cross(vert2-vert0)).normalize(); + b3Scalar c = -(normal.dot(vert0)); + + m_data->m_convexFaces[convex.m_faceOffset+i].m_plane = b3MakeVector4(normal.x,normal.y,normal.z,c); + int indexOffset = m_data->m_convexIndices.size(); + int numIndices = 3; + m_data->m_convexFaces[convex.m_faceOffset+i].m_numIndices = numIndices; + m_data->m_convexFaces[convex.m_faceOffset+i].m_indexOffset = indexOffset; + m_data->m_convexIndices.resize(indexOffset+numIndices); + for (int p=0;pat(i*3+p); + m_data->m_convexIndices[indexOffset+p] = vi;//convexPtr->m_faces[i].m_indices[p]; + } + } + + convex.m_numVertices = vertices->size(); + int vertexOffset = m_data->m_convexVertices.size(); + convex.m_vertexOffset =vertexOffset; + m_data->m_convexVertices.resize(vertexOffset+convex.m_numVertices); + for (int i=0;isize();i++) + { + m_data->m_convexVertices[vertexOffset+i] = vertices->at(i)*scaling; + } + + (*m_data->m_convexData)[m_data->m_numAcceleratedShapes] = 0; + + + return m_data->m_numAcceleratedShapes++; +} + + + +cl_mem b3GpuNarrowPhase::getBodiesGpu() +{ + return (cl_mem)m_data->m_bodyBufferGPU->getBufferCL(); +} + +const struct b3RigidBodyData* b3GpuNarrowPhase::getBodiesCpu() const +{ + return &m_data->m_bodyBufferCPU->at(0); +}; + + + + +int b3GpuNarrowPhase::getNumBodiesGpu() const +{ + return m_data->m_bodyBufferGPU->size(); +} + +cl_mem b3GpuNarrowPhase::getBodyInertiasGpu() +{ + return (cl_mem)m_data->m_inertiaBufferGPU->getBufferCL(); +} + +int b3GpuNarrowPhase::getNumBodyInertiasGpu() const +{ + return m_data->m_inertiaBufferGPU->size(); +} + + +b3Collidable& b3GpuNarrowPhase::getCollidableCpu(int collidableIndex) +{ + return m_data->m_collidablesCPU[collidableIndex]; +} + +const b3Collidable& b3GpuNarrowPhase::getCollidableCpu(int collidableIndex) const +{ + return m_data->m_collidablesCPU[collidableIndex]; +} + +cl_mem b3GpuNarrowPhase::getCollidablesGpu() +{ + return m_data->m_collidablesGPU->getBufferCL(); +} + +const struct b3Collidable* b3GpuNarrowPhase::getCollidablesCpu() const +{ + if (m_data->m_collidablesCPU.size()) + return &m_data->m_collidablesCPU[0]; + return 0; +} + +const struct b3SapAabb* b3GpuNarrowPhase::getLocalSpaceAabbsCpu() const +{ + if (m_data->m_localShapeAABBCPU->size()) + { + return &m_data->m_localShapeAABBCPU->at(0); + } + return 0; +} + + +cl_mem b3GpuNarrowPhase::getAabbLocalSpaceBufferGpu() +{ + return m_data->m_localShapeAABBGPU->getBufferCL(); +} +int b3GpuNarrowPhase::getNumCollidablesGpu() const +{ + return m_data->m_collidablesGPU->size(); +} + + + + + +int b3GpuNarrowPhase::getNumContactsGpu() const +{ + return m_data->m_pBufContactBuffersGPU[m_data->m_currentContactBuffer]->size(); +} +cl_mem b3GpuNarrowPhase::getContactsGpu() +{ + return m_data->m_pBufContactBuffersGPU[m_data->m_currentContactBuffer]->getBufferCL(); +} + +const b3Contact4* b3GpuNarrowPhase::getContactsCPU() const +{ + m_data->m_pBufContactBuffersGPU[m_data->m_currentContactBuffer]->copyToHost(*m_data->m_pBufContactOutCPU); + return &m_data->m_pBufContactOutCPU->at(0); +} + +void b3GpuNarrowPhase::computeContacts(cl_mem broadphasePairs, int numBroadphasePairs, cl_mem aabbsWorldSpace, int numObjects) +{ + + cl_mem aabbsLocalSpace = m_data->m_localShapeAABBGPU->getBufferCL(); + + int nContactOut = 0; + + //swap buffer + m_data->m_currentContactBuffer=1-m_data->m_currentContactBuffer; + + //int curSize = m_data->m_pBufContactBuffersGPU[m_data->m_currentContactBuffer]->size(); + + int maxTriConvexPairCapacity = m_data->m_config.m_maxTriConvexPairCapacity; + int numTriConvexPairsOut=0; + + b3OpenCLArray broadphasePairsGPU(m_context,m_queue); + broadphasePairsGPU.setFromOpenCLBuffer(broadphasePairs,numBroadphasePairs); + + + + + b3OpenCLArray clAabbArrayWorldSpace(this->m_context,this->m_queue); + clAabbArrayWorldSpace.setFromOpenCLBuffer(aabbsWorldSpace,numObjects); + + b3OpenCLArray clAabbArrayLocalSpace(this->m_context,this->m_queue); + clAabbArrayLocalSpace.setFromOpenCLBuffer(aabbsLocalSpace,numObjects); + + m_data->m_gpuSatCollision->computeConvexConvexContactsGPUSAT( + &broadphasePairsGPU, numBroadphasePairs, + m_data->m_bodyBufferGPU, + m_data->m_pBufContactBuffersGPU[m_data->m_currentContactBuffer], + nContactOut, + m_data->m_pBufContactBuffersGPU[1-m_data->m_currentContactBuffer], + m_data->m_config.m_maxContactCapacity, + m_data->m_config.m_compoundPairCapacity, + *m_data->m_convexPolyhedraGPU, + *m_data->m_convexVerticesGPU, + *m_data->m_uniqueEdgesGPU, + *m_data->m_convexFacesGPU, + *m_data->m_convexIndicesGPU, + *m_data->m_collidablesGPU, + *m_data->m_gpuChildShapes, + clAabbArrayWorldSpace, + clAabbArrayLocalSpace, + *m_data->m_worldVertsB1GPU, + *m_data->m_clippingFacesOutGPU, + *m_data->m_worldNormalsAGPU, + *m_data->m_worldVertsA1GPU, + *m_data->m_worldVertsB2GPU, + m_data->m_bvhData, + m_data->m_treeNodesGPU, + m_data->m_subTreesGPU, + m_data->m_bvhInfoGPU, + numObjects, + maxTriConvexPairCapacity, + *m_data->m_triangleConvexPairs, + numTriConvexPairsOut + ); + + /*b3AlignedObjectArray broadphasePairsCPU; + broadphasePairsGPU.copyToHost(broadphasePairsCPU); + printf("checking pairs\n"); + */ +} + +const b3SapAabb& b3GpuNarrowPhase::getLocalSpaceAabb(int collidableIndex) const +{ + return m_data->m_localShapeAABBCPU->at(collidableIndex); +} + + + + + +int b3GpuNarrowPhase::registerRigidBody(int collidableIndex, float mass, const float* position, const float* orientation , const float* aabbMinPtr, const float* aabbMaxPtr,bool writeToGpu) +{ + b3Vector3 aabbMin=b3MakeVector3(aabbMinPtr[0],aabbMinPtr[1],aabbMinPtr[2]); + b3Vector3 aabbMax=b3MakeVector3(aabbMaxPtr[0],aabbMaxPtr[1],aabbMaxPtr[2]); + + + if (m_data->m_numAcceleratedRigidBodies >= (m_data->m_config.m_maxConvexBodies)) + { + b3Error("registerRigidBody: exceeding the number of rigid bodies, %d > %d \n",m_data->m_numAcceleratedRigidBodies,m_data->m_config.m_maxConvexBodies); + return -1; + } + + m_data->m_bodyBufferCPU->resize(m_data->m_numAcceleratedRigidBodies+1); + + b3RigidBodyData& body = m_data->m_bodyBufferCPU->at(m_data->m_numAcceleratedRigidBodies); + + float friction = 1.f; + float restitution = 0.f; + + body.m_frictionCoeff = friction; + body.m_restituitionCoeff = restitution; + body.m_angVel = b3MakeVector3(0,0,0); + body.m_linVel=b3MakeVector3(0,0,0);//.setZero(); + body.m_pos =b3MakeVector3(position[0],position[1],position[2]); + body.m_quat.setValue(orientation[0],orientation[1],orientation[2],orientation[3]); + body.m_collidableIdx = collidableIndex; + if (collidableIndex>=0) + { +// body.m_shapeType = m_data->m_collidablesCPU.at(collidableIndex).m_shapeType; + } else + { + // body.m_shapeType = CollisionShape::SHAPE_PLANE; + m_planeBodyIndex = m_data->m_numAcceleratedRigidBodies; + } + //body.m_shapeType = shapeType; + + + body.m_invMass = mass? 1.f/mass : 0.f; + + if (writeToGpu) + { + m_data->m_bodyBufferGPU->copyFromHostPointer(&body,1,m_data->m_numAcceleratedRigidBodies); + } + + b3InertiaData& shapeInfo = m_data->m_inertiaBufferCPU->at(m_data->m_numAcceleratedRigidBodies); + + if (mass==0.f) + { + if (m_data->m_numAcceleratedRigidBodies==0) + m_static0Index = 0; + + shapeInfo.m_initInvInertia.setValue(0,0,0,0,0,0,0,0,0); + shapeInfo.m_invInertiaWorld.setValue(0,0,0,0,0,0,0,0,0); + } else + { + + b3Assert(body.m_collidableIdx>=0); + + //approximate using the aabb of the shape + + //Aabb aabb = (*m_data->m_shapePointers)[shapeIndex]->m_aabb; + b3Vector3 halfExtents = (aabbMax-aabbMin);//*0.5f;//fake larger inertia makes demos more stable ;-) + + b3Vector3 localInertia; + + float lx=2.f*halfExtents[0]; + float ly=2.f*halfExtents[1]; + float lz=2.f*halfExtents[2]; + + localInertia.setValue( (mass/12.0f) * (ly*ly + lz*lz), + (mass/12.0f) * (lx*lx + lz*lz), + (mass/12.0f) * (lx*lx + ly*ly)); + + b3Vector3 invLocalInertia; + invLocalInertia[0] = 1.f/localInertia[0]; + invLocalInertia[1] = 1.f/localInertia[1]; + invLocalInertia[2] = 1.f/localInertia[2]; + invLocalInertia[3] = 0.f; + + shapeInfo.m_initInvInertia.setValue( + invLocalInertia[0], 0, 0, + 0, invLocalInertia[1], 0, + 0, 0, invLocalInertia[2]); + + b3Matrix3x3 m (body.m_quat); + + shapeInfo.m_invInertiaWorld = m.scaled(invLocalInertia) * m.transpose(); + + } + + if (writeToGpu) + m_data->m_inertiaBufferGPU->copyFromHostPointer(&shapeInfo,1,m_data->m_numAcceleratedRigidBodies); + + + + return m_data->m_numAcceleratedRigidBodies++; +} + +int b3GpuNarrowPhase::getNumRigidBodies() const +{ + return m_data->m_numAcceleratedRigidBodies; +} + +void b3GpuNarrowPhase::writeAllBodiesToGpu() +{ + + if (m_data->m_localShapeAABBCPU->size()) + { + m_data->m_localShapeAABBGPU->copyFromHost(*m_data->m_localShapeAABBCPU); + } + + + m_data->m_gpuChildShapes->copyFromHost(m_data->m_cpuChildShapes); + m_data->m_convexFacesGPU->copyFromHost(m_data->m_convexFaces); + m_data->m_convexPolyhedraGPU->copyFromHost(m_data->m_convexPolyhedra); + m_data->m_uniqueEdgesGPU->copyFromHost(m_data->m_uniqueEdges); + m_data->m_convexVerticesGPU->copyFromHost(m_data->m_convexVertices); + m_data->m_convexIndicesGPU->copyFromHost(m_data->m_convexIndices); + m_data->m_bvhInfoGPU->copyFromHost(m_data->m_bvhInfoCPU); + m_data->m_treeNodesGPU->copyFromHost(m_data->m_treeNodesCPU); + m_data->m_subTreesGPU->copyFromHost(m_data->m_subTreesCPU); + + + m_data->m_bodyBufferGPU->resize(m_data->m_numAcceleratedRigidBodies); + m_data->m_inertiaBufferGPU->resize(m_data->m_numAcceleratedRigidBodies); + + if (m_data->m_numAcceleratedRigidBodies) + { + m_data->m_bodyBufferGPU->copyFromHostPointer(&m_data->m_bodyBufferCPU->at(0),m_data->m_numAcceleratedRigidBodies); + m_data->m_inertiaBufferGPU->copyFromHostPointer(&m_data->m_inertiaBufferCPU->at(0),m_data->m_numAcceleratedRigidBodies); + } + if (m_data->m_collidablesCPU.size()) + { + m_data->m_collidablesGPU->copyFromHost(m_data->m_collidablesCPU); + } + + +} + + +void b3GpuNarrowPhase::reset() +{ + m_data->m_numAcceleratedShapes = 0; + m_data->m_numAcceleratedRigidBodies = 0; + this->m_static0Index = -1; + m_data->m_uniqueEdges.resize(0); + m_data->m_convexVertices.resize(0); + m_data->m_convexPolyhedra.resize(0); + m_data->m_convexIndices.resize(0); + m_data->m_cpuChildShapes.resize(0); + m_data->m_convexFaces.resize(0); + m_data->m_collidablesCPU.resize(0); + m_data->m_localShapeAABBCPU->resize(0); + m_data->m_bvhData.resize(0); + m_data->m_treeNodesCPU.resize(0); + m_data->m_subTreesCPU.resize(0); + m_data->m_bvhInfoCPU.resize(0); + +} + + +void b3GpuNarrowPhase::readbackAllBodiesToCpu() +{ + m_data->m_bodyBufferGPU->copyToHostPointer(&m_data->m_bodyBufferCPU->at(0),m_data->m_numAcceleratedRigidBodies); +} + +void b3GpuNarrowPhase::setObjectTransformCpu(float* position, float* orientation , int bodyIndex) +{ + if (bodyIndex>=0 && bodyIndexm_bodyBufferCPU->size()) + { + m_data->m_bodyBufferCPU->at(bodyIndex).m_pos=b3MakeVector3(position[0],position[1],position[2]); + m_data->m_bodyBufferCPU->at(bodyIndex).m_quat.setValue(orientation[0],orientation[1],orientation[2],orientation[3]); + } + else + { + b3Warning("setObjectVelocityCpu out of range.\n"); + } +} +void b3GpuNarrowPhase::setObjectVelocityCpu(float* linVel, float* angVel, int bodyIndex) +{ + if (bodyIndex>=0 && bodyIndexm_bodyBufferCPU->size()) + { + m_data->m_bodyBufferCPU->at(bodyIndex).m_linVel=b3MakeVector3(linVel[0],linVel[1],linVel[2]); + m_data->m_bodyBufferCPU->at(bodyIndex).m_angVel=b3MakeVector3(angVel[0],angVel[1],angVel[2]); + } else + { + b3Warning("setObjectVelocityCpu out of range.\n"); + } +} + +bool b3GpuNarrowPhase::getObjectTransformFromCpu(float* position, float* orientation , int bodyIndex) const +{ + if (bodyIndex>=0 && bodyIndexm_bodyBufferCPU->size()) + { + position[0] = m_data->m_bodyBufferCPU->at(bodyIndex).m_pos.x; + position[1] = m_data->m_bodyBufferCPU->at(bodyIndex).m_pos.y; + position[2] = m_data->m_bodyBufferCPU->at(bodyIndex).m_pos.z; + position[3] = 1.f;//or 1 + + orientation[0] = m_data->m_bodyBufferCPU->at(bodyIndex).m_quat.x; + orientation[1] = m_data->m_bodyBufferCPU->at(bodyIndex).m_quat.y; + orientation[2] = m_data->m_bodyBufferCPU->at(bodyIndex).m_quat.z; + orientation[3] = m_data->m_bodyBufferCPU->at(bodyIndex).m_quat.w; + return true; + } + + b3Warning("getObjectTransformFromCpu out of range.\n"); + return false; +} diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuNarrowPhase.h b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuNarrowPhase.h new file mode 100644 index 000000000000..05ff3fd09e59 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuNarrowPhase.h @@ -0,0 +1,109 @@ +#ifndef B3_GPU_NARROWPHASE_H +#define B3_GPU_NARROWPHASE_H + +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3Collidable.h" +#include "Bullet3OpenCL/Initialize/b3OpenCLInclude.h" +#include "Bullet3Common/b3AlignedObjectArray.h" +#include "Bullet3Common/b3Vector3.h" + +class b3GpuNarrowPhase +{ +protected: + + struct b3GpuNarrowPhaseInternalData* m_data; + int m_acceleratedCompanionShapeIndex; + int m_planeBodyIndex; + int m_static0Index; + + cl_context m_context; + cl_device_id m_device; + cl_command_queue m_queue; + + int registerConvexHullShapeInternal(class b3ConvexUtility* convexPtr, b3Collidable& col); + int registerConcaveMeshShape(b3AlignedObjectArray* vertices, b3AlignedObjectArray* indices, b3Collidable& col, const float* scaling); + +public: + + + + + b3GpuNarrowPhase(cl_context vtx, cl_device_id dev, cl_command_queue q, const struct b3Config& config); + + virtual ~b3GpuNarrowPhase(void); + + int registerSphereShape(float radius); + int registerPlaneShape(const b3Vector3& planeNormal, float planeConstant); + + int registerCompoundShape(b3AlignedObjectArray* childShapes); + int registerFace(const b3Vector3& faceNormal, float faceConstant); + + int registerConcaveMesh(b3AlignedObjectArray* vertices, b3AlignedObjectArray* indices,const float* scaling); + + //do they need to be merged? + + int registerConvexHullShape(b3ConvexUtility* utilPtr); + int registerConvexHullShape(const float* vertices, int strideInBytes, int numVertices, const float* scaling); + + int registerRigidBody(int collidableIndex, float mass, const float* position, const float* orientation, const float* aabbMin, const float* aabbMax,bool writeToGpu); + void setObjectTransform(const float* position, const float* orientation , int bodyIndex); + + void writeAllBodiesToGpu(); + void reset(); + void readbackAllBodiesToCpu(); + bool getObjectTransformFromCpu(float* position, float* orientation , int bodyIndex) const; + + void setObjectTransformCpu(float* position, float* orientation , int bodyIndex); + void setObjectVelocityCpu(float* linVel, float* angVel, int bodyIndex); + + + virtual void computeContacts(cl_mem broadphasePairs, int numBroadphasePairs, cl_mem aabbsWorldSpace, int numObjects); + + + cl_mem getBodiesGpu(); + const struct b3RigidBodyData* getBodiesCpu() const; + //struct b3RigidBodyData* getBodiesCpu(); + + int getNumBodiesGpu() const; + + cl_mem getBodyInertiasGpu(); + int getNumBodyInertiasGpu() const; + + cl_mem getCollidablesGpu(); + const struct b3Collidable* getCollidablesCpu() const; + int getNumCollidablesGpu() const; + + const struct b3SapAabb* getLocalSpaceAabbsCpu() const; + + const struct b3Contact4* getContactsCPU() const; + + cl_mem getContactsGpu(); + int getNumContactsGpu() const; + + cl_mem getAabbLocalSpaceBufferGpu(); + + int getNumRigidBodies() const; + + int allocateCollidable(); + + int getStatic0Index() const + { + return m_static0Index; + } + b3Collidable& getCollidableCpu(int collidableIndex); + const b3Collidable& getCollidableCpu(int collidableIndex) const; + + const b3GpuNarrowPhaseInternalData* getInternalData() const + { + return m_data; + } + + b3GpuNarrowPhaseInternalData* getInternalData() + { + return m_data; + } + + const struct b3SapAabb& getLocalSpaceAabb(int collidableIndex) const; +}; + +#endif //B3_GPU_NARROWPHASE_H + diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuNarrowPhaseInternalData.h b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuNarrowPhaseInternalData.h new file mode 100644 index 000000000000..8a7f1ea85906 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuNarrowPhaseInternalData.h @@ -0,0 +1,95 @@ + +#ifndef B3_GPU_NARROWPHASE_INTERNAL_DATA_H +#define B3_GPU_NARROWPHASE_INTERNAL_DATA_H + +#include "Bullet3OpenCL/ParallelPrimitives/b3OpenCLArray.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3ConvexPolyhedronData.h" +#include "Bullet3Collision/NarrowPhaseCollision/b3Config.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3Collidable.h" + +#include "Bullet3OpenCL/Initialize/b3OpenCLInclude.h" +#include "Bullet3Common/b3AlignedObjectArray.h" +#include "Bullet3Common/b3Vector3.h" + +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" +#include "Bullet3Collision/NarrowPhaseCollision/b3Contact4.h" +#include "Bullet3OpenCL/BroadphaseCollision/b3SapAabb.h" + +#include "Bullet3OpenCL/NarrowphaseCollision/b3QuantizedBvh.h" +#include "Bullet3OpenCL/NarrowphaseCollision/b3BvhInfo.h" +#include "Bullet3Common/shared/b3Int4.h" +#include "Bullet3Common/shared/b3Int2.h" + + +class b3ConvexUtility; + +struct b3GpuNarrowPhaseInternalData +{ + b3AlignedObjectArray* m_convexData; + + b3AlignedObjectArray m_convexPolyhedra; + b3AlignedObjectArray m_uniqueEdges; + b3AlignedObjectArray m_convexVertices; + b3AlignedObjectArray m_convexIndices; + + b3OpenCLArray* m_convexPolyhedraGPU; + b3OpenCLArray* m_uniqueEdgesGPU; + b3OpenCLArray* m_convexVerticesGPU; + b3OpenCLArray* m_convexIndicesGPU; + + b3OpenCLArray* m_worldVertsB1GPU; + b3OpenCLArray* m_clippingFacesOutGPU; + b3OpenCLArray* m_worldNormalsAGPU; + b3OpenCLArray* m_worldVertsA1GPU; + b3OpenCLArray* m_worldVertsB2GPU; + + b3AlignedObjectArray m_cpuChildShapes; + b3OpenCLArray* m_gpuChildShapes; + + b3AlignedObjectArray m_convexFaces; + b3OpenCLArray* m_convexFacesGPU; + + struct GpuSatCollision* m_gpuSatCollision; + + + b3OpenCLArray* m_triangleConvexPairs; + + + b3OpenCLArray* m_pBufContactBuffersGPU[2]; + int m_currentContactBuffer; + b3AlignedObjectArray* m_pBufContactOutCPU; + + + b3AlignedObjectArray* m_bodyBufferCPU; + b3OpenCLArray* m_bodyBufferGPU; + + b3AlignedObjectArray* m_inertiaBufferCPU; + b3OpenCLArray* m_inertiaBufferGPU; + + int m_numAcceleratedShapes; + int m_numAcceleratedRigidBodies; + + b3AlignedObjectArray m_collidablesCPU; + b3OpenCLArray* m_collidablesGPU; + + b3OpenCLArray* m_localShapeAABBGPU; + b3AlignedObjectArray* m_localShapeAABBCPU; + + b3AlignedObjectArray m_bvhData; + b3AlignedObjectArray m_meshInterfaces; + + b3AlignedObjectArray m_treeNodesCPU; + b3AlignedObjectArray m_subTreesCPU; + + b3AlignedObjectArray m_bvhInfoCPU; + b3OpenCLArray* m_bvhInfoGPU; + + b3OpenCLArray* m_treeNodesGPU; + b3OpenCLArray* m_subTreesGPU; + + + b3Config m_config; + +}; + +#endif //B3_GPU_NARROWPHASE_INTERNAL_DATA_H diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuPgsConstraintSolver.cpp b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuPgsConstraintSolver.cpp new file mode 100644 index 000000000000..0d3d50c54813 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuPgsConstraintSolver.cpp @@ -0,0 +1,1158 @@ + +/* +Copyright (c) 2013 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Erwin Coumans + + +bool useGpuInitSolverBodies = true; +bool useGpuInfo1 = true; +bool useGpuInfo2= true; +bool useGpuSolveJointConstraintRows=true; +bool useGpuWriteBackVelocities = true; +bool gpuBreakConstraints = true; + +#include "b3GpuPgsConstraintSolver.h" + +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" + +#include "Bullet3Dynamics/ConstraintSolver/b3TypedConstraint.h" +#include +#include "Bullet3Common/b3AlignedObjectArray.h" +#include //for memset +#include "Bullet3Collision/NarrowPhaseCollision/b3Contact4.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3OpenCLArray.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.h" + +#include "Bullet3OpenCL/ParallelPrimitives/b3PrefixScanCL.h" + +#include "Bullet3OpenCL/RigidBody/kernels/jointSolver.h" //solveConstraintRowsCL +#include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h" + +#define B3_JOINT_SOLVER_PATH "src/Bullet3OpenCL/RigidBody/kernels/jointSolver.cl" + + +struct b3GpuPgsJacobiSolverInternalData +{ + + cl_context m_context; + cl_device_id m_device; + cl_command_queue m_queue; + + b3PrefixScanCL* m_prefixScan; + + cl_kernel m_solveJointConstraintRowsKernels; + cl_kernel m_initSolverBodiesKernel; + cl_kernel m_getInfo1Kernel; + cl_kernel m_initBatchConstraintsKernel; + cl_kernel m_getInfo2Kernel; + cl_kernel m_writeBackVelocitiesKernel; + cl_kernel m_breakViolatedConstraintsKernel; + + b3OpenCLArray* m_gpuConstraintRowOffsets; + + b3OpenCLArray* m_gpuSolverBodies; + b3OpenCLArray* m_gpuBatchConstraints; + b3OpenCLArray* m_gpuConstraintRows; + b3OpenCLArray* m_gpuConstraintInfo1; + +// b3AlignedObjectArray m_cpuSolverBodies; + b3AlignedObjectArray m_cpuBatchConstraints; + b3AlignedObjectArray m_cpuConstraintRows; + b3AlignedObjectArray m_cpuConstraintInfo1; + b3AlignedObjectArray m_cpuConstraintRowOffsets; + + b3AlignedObjectArray m_cpuBodies; + b3AlignedObjectArray m_cpuInertias; + + + b3AlignedObjectArray m_cpuConstraints; + + b3AlignedObjectArray m_batchSizes; + + +}; + + +/* +static b3Transform getWorldTransform(b3RigidBodyData* rb) +{ + b3Transform newTrans; + newTrans.setOrigin(rb->m_pos); + newTrans.setRotation(rb->m_quat); + return newTrans; +} + +static const b3Matrix3x3& getInvInertiaTensorWorld(b3InertiaData* inertia) +{ + return inertia->m_invInertiaWorld; +} + +*/ + +static const b3Vector3& getLinearVelocity(b3RigidBodyData* rb) +{ + return rb->m_linVel; +} + +static const b3Vector3& getAngularVelocity(b3RigidBodyData* rb) +{ + return rb->m_angVel; +} + +b3Vector3 getVelocityInLocalPoint(b3RigidBodyData* rb, const b3Vector3& rel_pos) +{ + //we also calculate lin/ang velocity for kinematic objects + return getLinearVelocity(rb) + getAngularVelocity(rb).cross(rel_pos); + +} + + + +b3GpuPgsConstraintSolver::b3GpuPgsConstraintSolver (cl_context ctx, cl_device_id device, cl_command_queue queue,bool usePgs) +{ + m_usePgs = usePgs; + m_gpuData = new b3GpuPgsJacobiSolverInternalData(); + m_gpuData->m_context = ctx; + m_gpuData->m_device = device; + m_gpuData->m_queue = queue; + + m_gpuData->m_prefixScan = new b3PrefixScanCL(ctx,device,queue); + + m_gpuData->m_gpuConstraintRowOffsets = new b3OpenCLArray(m_gpuData->m_context,m_gpuData->m_queue); + + m_gpuData->m_gpuSolverBodies = new b3OpenCLArray(m_gpuData->m_context,m_gpuData->m_queue); + m_gpuData->m_gpuBatchConstraints = new b3OpenCLArray(m_gpuData->m_context,m_gpuData->m_queue); + m_gpuData->m_gpuConstraintRows = new b3OpenCLArray(m_gpuData->m_context,m_gpuData->m_queue); + m_gpuData->m_gpuConstraintInfo1 = new b3OpenCLArray(m_gpuData->m_context,m_gpuData->m_queue); + cl_int errNum=0; + + { + cl_program prog = b3OpenCLUtils::compileCLProgramFromString(m_gpuData->m_context,m_gpuData->m_device,solveConstraintRowsCL,&errNum,"",B3_JOINT_SOLVER_PATH); + //cl_program prog = b3OpenCLUtils::compileCLProgramFromString(m_gpuData->m_context,m_gpuData->m_device,0,&errNum,"",B3_JOINT_SOLVER_PATH,true); + b3Assert(errNum==CL_SUCCESS); + m_gpuData->m_solveJointConstraintRowsKernels = b3OpenCLUtils::compileCLKernelFromString(m_gpuData->m_context, m_gpuData->m_device,solveConstraintRowsCL, "solveJointConstraintRows",&errNum,prog); + b3Assert(errNum==CL_SUCCESS); + m_gpuData->m_initSolverBodiesKernel = b3OpenCLUtils::compileCLKernelFromString(m_gpuData->m_context,m_gpuData->m_device,solveConstraintRowsCL,"initSolverBodies",&errNum,prog); + b3Assert(errNum==CL_SUCCESS); + m_gpuData->m_getInfo1Kernel = b3OpenCLUtils::compileCLKernelFromString(m_gpuData->m_context,m_gpuData->m_device,solveConstraintRowsCL,"getInfo1Kernel",&errNum,prog); + b3Assert(errNum==CL_SUCCESS); + m_gpuData->m_initBatchConstraintsKernel = b3OpenCLUtils::compileCLKernelFromString(m_gpuData->m_context,m_gpuData->m_device,solveConstraintRowsCL,"initBatchConstraintsKernel",&errNum,prog); + b3Assert(errNum==CL_SUCCESS); + m_gpuData->m_getInfo2Kernel= b3OpenCLUtils::compileCLKernelFromString(m_gpuData->m_context,m_gpuData->m_device,solveConstraintRowsCL,"getInfo2Kernel",&errNum,prog); + b3Assert(errNum==CL_SUCCESS); + m_gpuData->m_writeBackVelocitiesKernel = b3OpenCLUtils::compileCLKernelFromString(m_gpuData->m_context,m_gpuData->m_device,solveConstraintRowsCL,"writeBackVelocitiesKernel",&errNum,prog); + b3Assert(errNum==CL_SUCCESS); + m_gpuData->m_breakViolatedConstraintsKernel = b3OpenCLUtils::compileCLKernelFromString(m_gpuData->m_context,m_gpuData->m_device,solveConstraintRowsCL,"breakViolatedConstraintsKernel",&errNum,prog); + b3Assert(errNum==CL_SUCCESS); + + + + + clReleaseProgram(prog); + } + + +} + +b3GpuPgsConstraintSolver::~b3GpuPgsConstraintSolver () +{ + clReleaseKernel(m_gpuData->m_solveJointConstraintRowsKernels); + clReleaseKernel(m_gpuData->m_initSolverBodiesKernel); + clReleaseKernel(m_gpuData->m_getInfo1Kernel); + clReleaseKernel(m_gpuData->m_initBatchConstraintsKernel); + clReleaseKernel(m_gpuData->m_getInfo2Kernel); + clReleaseKernel(m_gpuData->m_writeBackVelocitiesKernel); + clReleaseKernel(m_gpuData->m_breakViolatedConstraintsKernel); + + delete m_gpuData->m_prefixScan; + delete m_gpuData->m_gpuConstraintRowOffsets; + delete m_gpuData->m_gpuSolverBodies; + delete m_gpuData->m_gpuBatchConstraints; + delete m_gpuData->m_gpuConstraintRows; + delete m_gpuData->m_gpuConstraintInfo1; + + delete m_gpuData; +} + +struct b3BatchConstraint +{ + int m_bodyAPtrAndSignBit; + int m_bodyBPtrAndSignBit; + int m_originalConstraintIndex; + int m_batchId; +}; + +static b3AlignedObjectArray batchConstraints; + + +void b3GpuPgsConstraintSolver::recomputeBatches() +{ + m_gpuData->m_batchSizes.clear(); +} + + + + +b3Scalar b3GpuPgsConstraintSolver::solveGroupCacheFriendlySetup(b3OpenCLArray* gpuBodies, b3OpenCLArray* gpuInertias, int numBodies, b3OpenCLArray* gpuConstraints,int numConstraints,const b3ContactSolverInfo& infoGlobal) +{ + B3_PROFILE("GPU solveGroupCacheFriendlySetup"); + batchConstraints.resize(numConstraints); + m_gpuData->m_gpuBatchConstraints->resize(numConstraints); + m_staticIdx = -1; + m_maxOverrideNumSolverIterations = 0; + + + /* m_gpuData->m_gpuBodies->resize(numBodies); + m_gpuData->m_gpuBodies->copyFromHostPointer(bodies,numBodies); + + b3OpenCLArray gpuInertias(m_gpuData->m_context,m_gpuData->m_queue); + gpuInertias.resize(numBodies); + gpuInertias.copyFromHostPointer(inertias,numBodies); + */ + + m_gpuData->m_gpuSolverBodies->resize(numBodies); + + + m_tmpSolverBodyPool.resize(numBodies); + { + + if (useGpuInitSolverBodies) + { + B3_PROFILE("m_initSolverBodiesKernel"); + + b3LauncherCL launcher(m_gpuData->m_queue,m_gpuData->m_initSolverBodiesKernel,"m_initSolverBodiesKernel"); + launcher.setBuffer(m_gpuData->m_gpuSolverBodies->getBufferCL()); + launcher.setBuffer(gpuBodies->getBufferCL()); + launcher.setConst(numBodies); + launcher.launch1D(numBodies); + clFinish(m_gpuData->m_queue); + + // m_gpuData->m_gpuSolverBodies->copyToHost(m_tmpSolverBodyPool); + } else + { + gpuBodies->copyToHost(m_gpuData->m_cpuBodies); + for (int i=0;im_cpuBodies[i]; + b3GpuSolverBody& solverBody = m_tmpSolverBodyPool[i]; + initSolverBody(i,&solverBody,&body); + solverBody.m_originalBodyIndex = i; + } + m_gpuData->m_gpuSolverBodies->copyFromHost(m_tmpSolverBodyPool); + } + } + +// int totalBodies = 0; + int totalNumRows = 0; + //b3RigidBody* rb0=0,*rb1=0; + //if (1) + { + { + + + // int i; + + m_tmpConstraintSizesPool.resizeNoInitialize(numConstraints); + + // b3OpenCLArray gpuConstraints(m_gpuData->m_context,m_gpuData->m_queue); + + + if (useGpuInfo1) + { + B3_PROFILE("info1 and init batchConstraint"); + + m_gpuData->m_gpuConstraintInfo1->resize(numConstraints); + + + if (1) + { + B3_PROFILE("getInfo1Kernel"); + + b3LauncherCL launcher(m_gpuData->m_queue,m_gpuData->m_getInfo1Kernel,"m_getInfo1Kernel"); + launcher.setBuffer(m_gpuData->m_gpuConstraintInfo1->getBufferCL()); + launcher.setBuffer(gpuConstraints->getBufferCL()); + launcher.setConst(numConstraints); + launcher.launch1D(numConstraints); + clFinish(m_gpuData->m_queue); + } + + if (m_gpuData->m_batchSizes.size()==0) + { + B3_PROFILE("initBatchConstraintsKernel"); + + m_gpuData->m_gpuConstraintRowOffsets->resize(numConstraints); + unsigned int total=0; + m_gpuData->m_prefixScan->execute(*m_gpuData->m_gpuConstraintInfo1,*m_gpuData->m_gpuConstraintRowOffsets,numConstraints,&total); + unsigned int lastElem = m_gpuData->m_gpuConstraintInfo1->at(numConstraints-1); + totalNumRows = total+lastElem; + + { + B3_PROFILE("init batch constraints"); + b3LauncherCL launcher(m_gpuData->m_queue,m_gpuData->m_initBatchConstraintsKernel,"m_initBatchConstraintsKernel"); + launcher.setBuffer(m_gpuData->m_gpuConstraintInfo1->getBufferCL()); + launcher.setBuffer(m_gpuData->m_gpuConstraintRowOffsets->getBufferCL()); + launcher.setBuffer(m_gpuData->m_gpuBatchConstraints->getBufferCL()); + launcher.setBuffer(gpuConstraints->getBufferCL()); + launcher.setBuffer(gpuBodies->getBufferCL()); + launcher.setConst(numConstraints); + launcher.launch1D(numConstraints); + clFinish(m_gpuData->m_queue); + } + //assume the batching happens on CPU, so copy the data + m_gpuData->m_gpuBatchConstraints->copyToHost(batchConstraints); + } + } + else + { + totalNumRows = 0; + gpuConstraints->copyToHost(m_gpuData->m_cpuConstraints); + //calculate the total number of contraint rows + for (int i=0;im_cpuConstraints[i].isEnabled()) + { + + m_gpuData->m_cpuConstraints[i].getInfo1(&info1,&m_gpuData->m_cpuBodies[0]); + } else + { + info1 = 0; + } + + totalNumRows += info1; + } + + m_gpuData->m_gpuBatchConstraints->copyFromHost(batchConstraints); + m_gpuData->m_gpuConstraintInfo1->copyFromHost(m_tmpConstraintSizesPool); + + } + m_tmpSolverNonContactConstraintPool.resizeNoInitialize(totalNumRows); + m_gpuData->m_gpuConstraintRows->resize(totalNumRows); + + // b3GpuConstraintArray verify; + + if (useGpuInfo2) + { + { + B3_PROFILE("getInfo2Kernel"); + b3LauncherCL launcher(m_gpuData->m_queue,m_gpuData->m_getInfo2Kernel,"m_getInfo2Kernel"); + launcher.setBuffer(m_gpuData->m_gpuConstraintRows->getBufferCL()); + launcher.setBuffer(m_gpuData->m_gpuConstraintInfo1->getBufferCL()); + launcher.setBuffer(m_gpuData->m_gpuConstraintRowOffsets->getBufferCL()); + launcher.setBuffer(gpuConstraints->getBufferCL()); + launcher.setBuffer(m_gpuData->m_gpuBatchConstraints->getBufferCL()); + launcher.setBuffer(gpuBodies->getBufferCL()); + launcher.setBuffer(gpuInertias->getBufferCL()); + launcher.setBuffer(m_gpuData->m_gpuSolverBodies->getBufferCL()); + launcher.setConst(infoGlobal.m_timeStep); + launcher.setConst(infoGlobal.m_erp); + launcher.setConst(infoGlobal.m_globalCfm); + launcher.setConst(infoGlobal.m_damping); + launcher.setConst(infoGlobal.m_numIterations); + launcher.setConst(numConstraints); + launcher.launch1D(numConstraints); + clFinish(m_gpuData->m_queue); + + if (m_gpuData->m_batchSizes.size()==0) + m_gpuData->m_gpuBatchConstraints->copyToHost(batchConstraints); + //m_gpuData->m_gpuConstraintRows->copyToHost(verify); + //m_gpuData->m_gpuConstraintRows->copyToHost(m_tmpSolverNonContactConstraintPool); + + + + } + } + else + { + + gpuInertias->copyToHost(m_gpuData->m_cpuInertias); + + ///setup the b3SolverConstraints + + for (int i=0;im_cpuConstraintRowOffsets[constraintIndex]; + + b3GpuSolverConstraint* currentConstraintRow = &m_tmpSolverNonContactConstraintPool[constraintRowOffset]; + b3GpuGenericConstraint& constraint = m_gpuData->m_cpuConstraints[i]; + + b3RigidBodyData& rbA = m_gpuData->m_cpuBodies[ constraint.getRigidBodyA()]; + //b3RigidBody& rbA = constraint.getRigidBodyA(); + // b3RigidBody& rbB = constraint.getRigidBodyB(); + b3RigidBodyData& rbB = m_gpuData->m_cpuBodies[ constraint.getRigidBodyB()]; + + + + int solverBodyIdA = constraint.getRigidBodyA();//getOrInitSolverBody(constraint.getRigidBodyA(),bodies,inertias); + int solverBodyIdB = constraint.getRigidBodyB();//getOrInitSolverBody(constraint.getRigidBodyB(),bodies,inertias); + + b3GpuSolverBody* bodyAPtr = &m_tmpSolverBodyPool[solverBodyIdA]; + b3GpuSolverBody* bodyBPtr = &m_tmpSolverBodyPool[solverBodyIdB]; + + if (rbA.m_invMass) + { + batchConstraints[i].m_bodyAPtrAndSignBit = solverBodyIdA; + } else + { + if (!solverBodyIdA) + m_staticIdx = 0; + batchConstraints[i].m_bodyAPtrAndSignBit = -solverBodyIdA; + } + + if (rbB.m_invMass) + { + batchConstraints[i].m_bodyBPtrAndSignBit = solverBodyIdB; + } else + { + if (!solverBodyIdB) + m_staticIdx = 0; + batchConstraints[i].m_bodyBPtrAndSignBit = -solverBodyIdB; + } + + + int overrideNumSolverIterations = 0;//constraint->getOverrideNumSolverIterations() > 0 ? constraint->getOverrideNumSolverIterations() : infoGlobal.m_numIterations; + if (overrideNumSolverIterations>m_maxOverrideNumSolverIterations) + m_maxOverrideNumSolverIterations = overrideNumSolverIterations; + + + int j; + for ( j=0;jinternalGetDeltaLinearVelocity().setValue(0.f,0.f,0.f); + bodyAPtr->internalGetDeltaAngularVelocity().setValue(0.f,0.f,0.f); + bodyAPtr->internalGetPushVelocity().setValue(0.f,0.f,0.f); + bodyAPtr->internalGetTurnVelocity().setValue(0.f,0.f,0.f); + bodyBPtr->internalGetDeltaLinearVelocity().setValue(0.f,0.f,0.f); + bodyBPtr->internalGetDeltaAngularVelocity().setValue(0.f,0.f,0.f); + bodyBPtr->internalGetPushVelocity().setValue(0.f,0.f,0.f); + bodyBPtr->internalGetTurnVelocity().setValue(0.f,0.f,0.f); + + + b3GpuConstraintInfo2 info2; + info2.fps = 1.f/infoGlobal.m_timeStep; + info2.erp = infoGlobal.m_erp; + info2.m_J1linearAxis = currentConstraintRow->m_contactNormal; + info2.m_J1angularAxis = currentConstraintRow->m_relpos1CrossNormal; + info2.m_J2linearAxis = 0; + info2.m_J2angularAxis = currentConstraintRow->m_relpos2CrossNormal; + info2.rowskip = sizeof(b3GpuSolverConstraint)/sizeof(b3Scalar);//check this + ///the size of b3GpuSolverConstraint needs be a multiple of b3Scalar + b3Assert(info2.rowskip*sizeof(b3Scalar)== sizeof(b3GpuSolverConstraint)); + info2.m_constraintError = ¤tConstraintRow->m_rhs; + currentConstraintRow->m_cfm = infoGlobal.m_globalCfm; + info2.m_damping = infoGlobal.m_damping; + info2.cfm = ¤tConstraintRow->m_cfm; + info2.m_lowerLimit = ¤tConstraintRow->m_lowerLimit; + info2.m_upperLimit = ¤tConstraintRow->m_upperLimit; + info2.m_numIterations = infoGlobal.m_numIterations; + m_gpuData->m_cpuConstraints[i].getInfo2(&info2,&m_gpuData->m_cpuBodies[0]); + + ///finalize the constraint setup + for ( j=0;j=m_gpuData->m_cpuConstraints[i].getBreakingImpulseThreshold()) + { + solverConstraint.m_upperLimit = m_gpuData->m_cpuConstraints[i].getBreakingImpulseThreshold(); + } + + if (solverConstraint.m_lowerLimit<=-m_gpuData->m_cpuConstraints[i].getBreakingImpulseThreshold()) + { + solverConstraint.m_lowerLimit = -m_gpuData->m_cpuConstraints[i].getBreakingImpulseThreshold(); + } + + // solverConstraint.m_originalContactPoint = constraint; + + b3Matrix3x3& invInertiaWorldA= m_gpuData->m_cpuInertias[constraint.getRigidBodyA()].m_invInertiaWorld; + { + + //b3Vector3 angularFactorA(1,1,1); + const b3Vector3& ftorqueAxis1 = solverConstraint.m_relpos1CrossNormal; + solverConstraint.m_angularComponentA = invInertiaWorldA*ftorqueAxis1;//*angularFactorA; + } + + b3Matrix3x3& invInertiaWorldB= m_gpuData->m_cpuInertias[constraint.getRigidBodyB()].m_invInertiaWorld; + { + + const b3Vector3& ftorqueAxis2 = solverConstraint.m_relpos2CrossNormal; + solverConstraint.m_angularComponentB = invInertiaWorldB*ftorqueAxis2;//*constraint.getRigidBodyB().getAngularFactor(); + } + + { + //it is ok to use solverConstraint.m_contactNormal instead of -solverConstraint.m_contactNormal + //because it gets multiplied iMJlB + b3Vector3 iMJlA = solverConstraint.m_contactNormal*rbA.m_invMass; + b3Vector3 iMJaA = invInertiaWorldA*solverConstraint.m_relpos1CrossNormal; + b3Vector3 iMJlB = solverConstraint.m_contactNormal*rbB.m_invMass;//sign of normal? + b3Vector3 iMJaB = invInertiaWorldB*solverConstraint.m_relpos2CrossNormal; + + b3Scalar sum = iMJlA.dot(solverConstraint.m_contactNormal); + sum += iMJaA.dot(solverConstraint.m_relpos1CrossNormal); + sum += iMJlB.dot(solverConstraint.m_contactNormal); + sum += iMJaB.dot(solverConstraint.m_relpos2CrossNormal); + b3Scalar fsum = b3Fabs(sum); + b3Assert(fsum > B3_EPSILON); + solverConstraint.m_jacDiagABInv = fsum>B3_EPSILON?b3Scalar(1.)/sum : 0.f; + } + + + ///fix rhs + ///todo: add force/torque accelerators + { + b3Scalar rel_vel; + b3Scalar vel1Dotn = solverConstraint.m_contactNormal.dot(rbA.m_linVel) + solverConstraint.m_relpos1CrossNormal.dot(rbA.m_angVel); + b3Scalar vel2Dotn = -solverConstraint.m_contactNormal.dot(rbB.m_linVel) + solverConstraint.m_relpos2CrossNormal.dot(rbB.m_angVel); + + rel_vel = vel1Dotn+vel2Dotn; + + b3Scalar restitution = 0.f; + b3Scalar positionalError = solverConstraint.m_rhs;//already filled in by getConstraintInfo2 + b3Scalar velocityError = restitution - rel_vel * info2.m_damping; + b3Scalar penetrationImpulse = positionalError*solverConstraint.m_jacDiagABInv; + b3Scalar velocityImpulse = velocityError *solverConstraint.m_jacDiagABInv; + solverConstraint.m_rhs = penetrationImpulse+velocityImpulse; + solverConstraint.m_appliedImpulse = 0.f; + + } + } + + } + } + + + + m_gpuData->m_gpuConstraintRows->copyFromHost(m_tmpSolverNonContactConstraintPool); + m_gpuData->m_gpuConstraintInfo1->copyFromHost(m_tmpConstraintSizesPool); + + if (m_gpuData->m_batchSizes.size()==0) + m_gpuData->m_gpuBatchConstraints->copyFromHost(batchConstraints); + else + m_gpuData->m_gpuBatchConstraints->copyToHost(batchConstraints); + + m_gpuData->m_gpuSolverBodies->copyFromHost(m_tmpSolverBodyPool); + + + + }//end useGpuInfo2 + + + } + +#ifdef B3_SUPPORT_CONTACT_CONSTRAINTS + { + int i; + + for (i=0;im_deltaLinearVelocity += linearComponent*impulseMagnitude*body->m_linearFactor; + body->m_deltaAngularVelocity += angularComponent*(impulseMagnitude*body->m_angularFactor); +} + + +void resolveSingleConstraintRowGeneric2( b3GpuSolverBody* body1, b3GpuSolverBody* body2, b3GpuSolverConstraint* c) +{ + float deltaImpulse = c->m_rhs-b3Scalar(c->m_appliedImpulse)*c->m_cfm; + float deltaVel1Dotn = b3Dot(c->m_contactNormal,body1->m_deltaLinearVelocity) + b3Dot(c->m_relpos1CrossNormal,body1->m_deltaAngularVelocity); + float deltaVel2Dotn = -b3Dot(c->m_contactNormal,body2->m_deltaLinearVelocity) + b3Dot(c->m_relpos2CrossNormal,body2->m_deltaAngularVelocity); + + deltaImpulse -= deltaVel1Dotn*c->m_jacDiagABInv; + deltaImpulse -= deltaVel2Dotn*c->m_jacDiagABInv; + + float sum = b3Scalar(c->m_appliedImpulse) + deltaImpulse; + if (sum < c->m_lowerLimit) + { + deltaImpulse = c->m_lowerLimit-b3Scalar(c->m_appliedImpulse); + c->m_appliedImpulse = c->m_lowerLimit; + } + else if (sum > c->m_upperLimit) + { + deltaImpulse = c->m_upperLimit-b3Scalar(c->m_appliedImpulse); + c->m_appliedImpulse = c->m_upperLimit; + } + else + { + c->m_appliedImpulse = sum; + } + + internalApplyImpulse(body1,c->m_contactNormal*body1->m_invMass,c->m_angularComponentA,deltaImpulse); + internalApplyImpulse(body2,-c->m_contactNormal*body2->m_invMass,c->m_angularComponentB,deltaImpulse); + +} + + + +void b3GpuPgsConstraintSolver::initSolverBody(int bodyIndex, b3GpuSolverBody* solverBody, b3RigidBodyData* rb) +{ + + solverBody->m_deltaLinearVelocity.setValue(0.f,0.f,0.f); + solverBody->m_deltaAngularVelocity.setValue(0.f,0.f,0.f); + solverBody->internalGetPushVelocity().setValue(0.f,0.f,0.f); + solverBody->internalGetTurnVelocity().setValue(0.f,0.f,0.f); + + b3Assert(rb); +// solverBody->m_worldTransform = getWorldTransform(rb); + solverBody->internalSetInvMass(b3MakeVector3(rb->m_invMass,rb->m_invMass,rb->m_invMass)); + solverBody->m_originalBodyIndex = bodyIndex; + solverBody->m_angularFactor = b3MakeVector3(1,1,1); + solverBody->m_linearFactor = b3MakeVector3(1,1,1); + solverBody->m_linearVelocity = getLinearVelocity(rb); + solverBody->m_angularVelocity = getAngularVelocity(rb); +} + + +void b3GpuPgsConstraintSolver::averageVelocities() +{ +} + + +b3Scalar b3GpuPgsConstraintSolver::solveGroupCacheFriendlyIterations(b3OpenCLArray* gpuConstraints1,int numConstraints,const b3ContactSolverInfo& infoGlobal) +{ + //only create the batches once. + //@todo: incrementally update batches when constraints are added/activated and/or removed/deactivated + B3_PROFILE("GpuSolveGroupCacheFriendlyIterations"); + + bool createBatches = m_gpuData->m_batchSizes.size()==0; + { + + if (createBatches) + { + + m_gpuData->m_batchSizes.resize(0); + + { + m_gpuData->m_gpuBatchConstraints->copyToHost(batchConstraints); + + B3_PROFILE("batch joints"); + b3Assert(batchConstraints.size()==numConstraints); + int simdWidth =numConstraints+1; + int numBodies = m_tmpSolverBodyPool.size(); + sortConstraintByBatch3( &batchConstraints[0], numConstraints, simdWidth , m_staticIdx, numBodies); + + m_gpuData->m_gpuBatchConstraints->copyFromHost(batchConstraints); + + } + } else + { + /*b3AlignedObjectArray cpuCheckBatches; + m_gpuData->m_gpuBatchConstraints->copyToHost(cpuCheckBatches); + b3Assert(cpuCheckBatches.size()==batchConstraints.size()); + printf(".\n"); + */ + //>copyFromHost(batchConstraints); + } + int maxIterations = infoGlobal.m_numIterations; + + bool useBatching = true; + + if (useBatching ) + { + + if (!useGpuSolveJointConstraintRows) + { + B3_PROFILE("copy to host"); + m_gpuData->m_gpuSolverBodies->copyToHost(m_tmpSolverBodyPool); + m_gpuData->m_gpuBatchConstraints->copyToHost(batchConstraints); + m_gpuData->m_gpuConstraintRows->copyToHost(m_tmpSolverNonContactConstraintPool); + m_gpuData->m_gpuConstraintInfo1->copyToHost(m_gpuData->m_cpuConstraintInfo1); + m_gpuData->m_gpuConstraintRowOffsets->copyToHost(m_gpuData->m_cpuConstraintRowOffsets); + gpuConstraints1->copyToHost(m_gpuData->m_cpuConstraints); + + } + + for ( int iteration = 0 ; iteration< maxIterations ; iteration++) + { + + int batchOffset = 0; + int constraintOffset=0; + int numBatches = m_gpuData->m_batchSizes.size(); + for (int bb=0;bbm_batchSizes[bb]; + + + if (useGpuSolveJointConstraintRows) + { + B3_PROFILE("solveJointConstraintRowsKernels"); + + /* + __kernel void solveJointConstraintRows(__global b3GpuSolverBody* solverBodies, + __global b3BatchConstraint* batchConstraints, + __global b3SolverConstraint* rows, + __global unsigned int* numConstraintRowsInfo1, + __global unsigned int* rowOffsets, + __global b3GpuGenericConstraint* constraints, + int batchOffset, + int numConstraintsInBatch*/ + + + b3LauncherCL launcher(m_gpuData->m_queue,m_gpuData->m_solveJointConstraintRowsKernels,"m_solveJointConstraintRowsKernels"); + launcher.setBuffer(m_gpuData->m_gpuSolverBodies->getBufferCL()); + launcher.setBuffer(m_gpuData->m_gpuBatchConstraints->getBufferCL()); + launcher.setBuffer(m_gpuData->m_gpuConstraintRows->getBufferCL()); + launcher.setBuffer(m_gpuData->m_gpuConstraintInfo1->getBufferCL()); + launcher.setBuffer(m_gpuData->m_gpuConstraintRowOffsets->getBufferCL()); + launcher.setBuffer(gpuConstraints1->getBufferCL());//to detect disabled constraints + launcher.setConst(batchOffset); + launcher.setConst(numConstraintsInBatch); + + launcher.launch1D(numConstraintsInBatch); + + + } else//useGpu + { + + + + for (int b=0;bm_cpuConstraints[c.m_originalConstraintIndex]; + if (constraint->m_flags&B3_CONSTRAINT_FLAG_ENABLED) + { + int numConstraintRows = m_gpuData->m_cpuConstraintInfo1[c.m_originalConstraintIndex]; + int constraintOffset = m_gpuData->m_cpuConstraintRowOffsets[c.m_originalConstraintIndex]; + + for (int jj=0;jjm_gpuSolverBodies->copyFromHost(m_tmpSolverBodyPool); + m_gpuData->m_gpuBatchConstraints->copyFromHost(batchConstraints); + m_gpuData->m_gpuConstraintRows->copyFromHost(m_tmpSolverNonContactConstraintPool); + } + + //B3_PROFILE("copy to host"); + //m_gpuData->m_gpuSolverBodies->copyToHost(m_tmpSolverBodyPool); + } + //int sz = sizeof(b3GpuSolverBody); + //printf("cpu sizeof(b3GpuSolverBody)=%d\n",sz); + + + + + + } else + { + for ( int iteration = 0 ; iteration< maxIterations ; iteration++) + { + int numJoints = m_tmpSolverNonContactConstraintPool.size(); + for (int j=0;jm_queue); + return 0.f; +} + + + + +static b3AlignedObjectArray bodyUsed; +static b3AlignedObjectArray curUsed; + + + +inline int b3GpuPgsConstraintSolver::sortConstraintByBatch3( b3BatchConstraint* cs, int numConstraints, int simdWidth , int staticIdx, int numBodies) +{ + //int sz = sizeof(b3BatchConstraint); + + B3_PROFILE("sortConstraintByBatch3"); + + static int maxSwaps = 0; + int numSwaps = 0; + + curUsed.resize(2*simdWidth); + + static int maxNumConstraints = 0; + if (maxNumConstraintsm_batchSizes.push_back(nCurrentBatch); + batchIdx ++; + } + } + +#if defined(_DEBUG) + // debugPrintf( "nBatches: %d\n", batchIdx ); + for(int i=0; i* gpuBodies, b3OpenCLArray* gpuInertias, + int numBodies, b3OpenCLArray* gpuConstraints,int numConstraints, const b3ContactSolverInfo& infoGlobal) +{ + + B3_PROFILE("solveJoints"); + //you need to provide at least some bodies + + solveGroupCacheFriendlySetup( gpuBodies, gpuInertias,numBodies,gpuConstraints, numConstraints,infoGlobal); + + solveGroupCacheFriendlyIterations(gpuConstraints, numConstraints,infoGlobal); + + solveGroupCacheFriendlyFinish(gpuBodies, gpuInertias,numBodies, gpuConstraints, numConstraints, infoGlobal); + + return 0.f; +} + +void b3GpuPgsConstraintSolver::solveJoints(int numBodies, b3OpenCLArray* gpuBodies, b3OpenCLArray* gpuInertias, + int numConstraints, b3OpenCLArray* gpuConstraints) +{ + b3ContactSolverInfo infoGlobal; + infoGlobal.m_splitImpulse = false; + infoGlobal.m_timeStep = 1.f/60.f; + infoGlobal.m_numIterations = 4;//4; +// infoGlobal.m_solverMode|=B3_SOLVER_USE_2_FRICTION_DIRECTIONS|B3_SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS|B3_SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION; + //infoGlobal.m_solverMode|=B3_SOLVER_USE_2_FRICTION_DIRECTIONS|B3_SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS; + infoGlobal.m_solverMode|=B3_SOLVER_USE_2_FRICTION_DIRECTIONS; + + //if (infoGlobal.m_solverMode & B3_SOLVER_INTERLEAVE_CONTACT_AND_FRICTION_CONSTRAINTS) + //if ((infoGlobal.m_solverMode & B3_SOLVER_USE_2_FRICTION_DIRECTIONS) && (infoGlobal.m_solverMode & B3_SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION)) + + + solveGroup(gpuBodies,gpuInertias,numBodies,gpuConstraints,numConstraints,infoGlobal); + +} + +//b3AlignedObjectArray testBodies; + + +b3Scalar b3GpuPgsConstraintSolver::solveGroupCacheFriendlyFinish(b3OpenCLArray* gpuBodies,b3OpenCLArray* gpuInertias,int numBodies,b3OpenCLArray* gpuConstraints,int numConstraints,const b3ContactSolverInfo& infoGlobal) +{ + B3_PROFILE("solveGroupCacheFriendlyFinish"); +// int numPoolConstraints = m_tmpSolverContactConstraintPool.size(); +// int i,j; + + + { + if (gpuBreakConstraints) + { + B3_PROFILE("breakViolatedConstraintsKernel"); + b3LauncherCL launcher(m_gpuData->m_queue,m_gpuData->m_breakViolatedConstraintsKernel,"m_breakViolatedConstraintsKernel"); + launcher.setBuffer(gpuConstraints->getBufferCL()); + launcher.setBuffer(m_gpuData->m_gpuConstraintInfo1->getBufferCL()); + launcher.setBuffer(m_gpuData->m_gpuConstraintRowOffsets->getBufferCL()); + launcher.setBuffer(m_gpuData->m_gpuConstraintRows->getBufferCL()); + launcher.setConst(numConstraints); + launcher.launch1D(numConstraints); + } else + { + gpuConstraints->copyToHost(m_gpuData->m_cpuConstraints); + m_gpuData->m_gpuBatchConstraints->copyToHost(m_gpuData->m_cpuBatchConstraints); + m_gpuData->m_gpuConstraintRows->copyToHost(m_gpuData->m_cpuConstraintRows); + gpuConstraints->copyToHost(m_gpuData->m_cpuConstraints); + m_gpuData->m_gpuConstraintInfo1->copyToHost(m_gpuData->m_cpuConstraintInfo1); + m_gpuData->m_gpuConstraintRowOffsets->copyToHost(m_gpuData->m_cpuConstraintRowOffsets); + + for (int cid=0;cidm_cpuConstraintRowOffsets[originalConstraintIndex]; + int numRows = m_gpuData->m_cpuConstraintInfo1[originalConstraintIndex]; + if (numRows) + { + + // printf("cid=%d, breakingThreshold =%f\n",cid,breakingThreshold); + for (int i=0;im_cpuConstraintRows[rowIndex].m_originalConstraintIndex; + float breakingThreshold = m_gpuData->m_cpuConstraints[orgConstraintIndex].m_breakingImpulseThreshold; + // printf("rows[%d].m_appliedImpulse=%f\n",rowIndex,rows[rowIndex].m_appliedImpulse); + if (b3Fabs(m_gpuData->m_cpuConstraintRows[rowIndex].m_appliedImpulse) >= breakingThreshold) + { + + m_gpuData->m_cpuConstraints[orgConstraintIndex].m_flags =0;//&= ~B3_CONSTRAINT_FLAG_ENABLED; + } + } + } + } + + + gpuConstraints->copyFromHost(m_gpuData->m_cpuConstraints); + } + } + + { + if (useGpuWriteBackVelocities) + { + B3_PROFILE("GPU write back velocities and transforms"); + + b3LauncherCL launcher(m_gpuData->m_queue,m_gpuData->m_writeBackVelocitiesKernel,"m_writeBackVelocitiesKernel"); + launcher.setBuffer(gpuBodies->getBufferCL()); + launcher.setBuffer(m_gpuData->m_gpuSolverBodies->getBufferCL()); + launcher.setConst(numBodies); + launcher.launch1D(numBodies); + clFinish(m_gpuData->m_queue); +// m_gpuData->m_gpuSolverBodies->copyToHost(m_tmpSolverBodyPool); +// m_gpuData->m_gpuBodies->copyToHostPointer(bodies,numBodies); + //m_gpuData->m_gpuBodies->copyToHost(testBodies); + + } + else + { + B3_PROFILE("CPU write back velocities and transforms"); + + m_gpuData->m_gpuSolverBodies->copyToHost(m_tmpSolverBodyPool); + gpuBodies->copyToHost(m_gpuData->m_cpuBodies); + for ( int i=0;im_cpuBodies[bodyIndex]; + if (body->m_invMass) + { + if (infoGlobal.m_splitImpulse) + m_tmpSolverBodyPool[i].writebackVelocityAndTransform(infoGlobal.m_timeStep, infoGlobal.m_splitImpulseTurnErp); + else + m_tmpSolverBodyPool[i].writebackVelocity(); + + if (m_usePgs) + { + body->m_linVel = m_tmpSolverBodyPool[i].m_linearVelocity; + body->m_angVel = m_tmpSolverBodyPool[i].m_angularVelocity; + } else + { + b3Assert(0); + } + /* + if (infoGlobal.m_splitImpulse) + { + body->m_pos = m_tmpSolverBodyPool[i].m_worldTransform.getOrigin(); + b3Quaternion orn; + orn = m_tmpSolverBodyPool[i].m_worldTransform.getRotation(); + body->m_quat = orn; + } + */ + } + }//for + + gpuBodies->copyFromHost(m_gpuData->m_cpuBodies); + + } + } + + clFinish(m_gpuData->m_queue); + + m_tmpSolverContactConstraintPool.resizeNoInitialize(0); + m_tmpSolverNonContactConstraintPool.resizeNoInitialize(0); + m_tmpSolverContactFrictionConstraintPool.resizeNoInitialize(0); + m_tmpSolverContactRollingFrictionConstraintPool.resizeNoInitialize(0); + + m_tmpSolverBodyPool.resizeNoInitialize(0); + return 0.f; +} diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuPgsConstraintSolver.h b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuPgsConstraintSolver.h new file mode 100644 index 000000000000..ec0e3f73d634 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuPgsConstraintSolver.h @@ -0,0 +1,78 @@ +/* +Copyright (c) 2013 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Erwin Coumans + +#ifndef B3_GPU_PGS_CONSTRAINT_SOLVER_H +#define B3_GPU_PGS_CONSTRAINT_SOLVER_H + +struct b3Contact4; +struct b3ContactPoint; + + +class b3Dispatcher; + +#include "Bullet3Dynamics/ConstraintSolver/b3TypedConstraint.h" +#include "Bullet3Dynamics/ConstraintSolver/b3ContactSolverInfo.h" +#include "b3GpuSolverBody.h" +#include "b3GpuSolverConstraint.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3OpenCLArray.h" +struct b3RigidBodyData; +struct b3InertiaData; + +#include "Bullet3OpenCL/Initialize/b3OpenCLInclude.h" +#include "b3GpuGenericConstraint.h" + +class b3GpuPgsConstraintSolver +{ +protected: + int m_staticIdx; + struct b3GpuPgsJacobiSolverInternalData* m_gpuData; + protected: + b3AlignedObjectArray m_tmpSolverBodyPool; + b3GpuConstraintArray m_tmpSolverContactConstraintPool; + b3GpuConstraintArray m_tmpSolverNonContactConstraintPool; + b3GpuConstraintArray m_tmpSolverContactFrictionConstraintPool; + b3GpuConstraintArray m_tmpSolverContactRollingFrictionConstraintPool; + + b3AlignedObjectArray m_tmpConstraintSizesPool; + + + bool m_usePgs; + void averageVelocities(); + + int m_maxOverrideNumSolverIterations; + + int m_numSplitImpulseRecoveries; + +// int getOrInitSolverBody(int bodyIndex, b3RigidBodyData* bodies,b3InertiaData* inertias); + void initSolverBody(int bodyIndex, b3GpuSolverBody* solverBody, b3RigidBodyData* rb); + +public: + b3GpuPgsConstraintSolver (cl_context ctx, cl_device_id device, cl_command_queue queue,bool usePgs); + virtual~b3GpuPgsConstraintSolver (); + + virtual b3Scalar solveGroupCacheFriendlyIterations(b3OpenCLArray* gpuConstraints1,int numConstraints,const b3ContactSolverInfo& infoGlobal); + virtual b3Scalar solveGroupCacheFriendlySetup(b3OpenCLArray* gpuBodies, b3OpenCLArray* gpuInertias, int numBodies,b3OpenCLArray* gpuConstraints,int numConstraints,const b3ContactSolverInfo& infoGlobal); + b3Scalar solveGroupCacheFriendlyFinish(b3OpenCLArray* gpuBodies,b3OpenCLArray* gpuInertias,int numBodies,b3OpenCLArray* gpuConstraints,int numConstraints,const b3ContactSolverInfo& infoGlobal); + + + b3Scalar solveGroup(b3OpenCLArray* gpuBodies,b3OpenCLArray* gpuInertias, int numBodies,b3OpenCLArray* gpuConstraints,int numConstraints,const b3ContactSolverInfo& infoGlobal); + void solveJoints(int numBodies, b3OpenCLArray* gpuBodies, b3OpenCLArray* gpuInertias, + int numConstraints, b3OpenCLArray* gpuConstraints); + + int sortConstraintByBatch3( struct b3BatchConstraint* cs, int numConstraints, int simdWidth , int staticIdx, int numBodies); + void recomputeBatches(); +}; + +#endif //B3_GPU_PGS_CONSTRAINT_SOLVER_H diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuPgsContactSolver.cpp b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuPgsContactSolver.cpp new file mode 100644 index 000000000000..f0b0abd5e006 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuPgsContactSolver.cpp @@ -0,0 +1,1708 @@ + +bool gUseLargeBatches = false; +bool gCpuBatchContacts = false; +bool gCpuSolveConstraint = false; +bool gCpuRadixSort=false; +bool gCpuSetSortData = false; +bool gCpuSortContactsDeterminism = false; +bool gUseCpuCopyConstraints = false; +bool gUseScanHost = false; +bool gReorderContactsOnCpu = false; + +bool optionalSortContactsDeterminism = true; + + +#include "b3GpuPgsContactSolver.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3RadixSort32CL.h" + +#include "Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3BoundSearchCL.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3PrefixScanCL.h" +#include +#include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h" +#include "Bullet3Collision/NarrowPhaseCollision/b3Config.h" +#include "b3Solver.h" + + +#define B3_SOLVER_SETUP_KERNEL_PATH "src/Bullet3OpenCL/RigidBody/kernels/solverSetup.cl" +#define B3_SOLVER_SETUP2_KERNEL_PATH "src/Bullet3OpenCL/RigidBody/kernels/solverSetup2.cl" +#define B3_SOLVER_CONTACT_KERNEL_PATH "src/Bullet3OpenCL/RigidBody/kernels/solveContact.cl" +#define B3_SOLVER_FRICTION_KERNEL_PATH "src/Bullet3OpenCL/RigidBody/kernels/solveFriction.cl" +#define B3_BATCHING_PATH "src/Bullet3OpenCL/RigidBody/kernels/batchingKernels.cl" +#define B3_BATCHING_NEW_PATH "src/Bullet3OpenCL/RigidBody/kernels/batchingKernelsNew.cl" + +#include "kernels/solverSetup.h" +#include "kernels/solverSetup2.h" +#include "kernels/solveContact.h" +#include "kernels/solveFriction.h" +#include "kernels/batchingKernels.h" +#include "kernels/batchingKernelsNew.h" + + + + + +struct b3GpuBatchingPgsSolverInternalData +{ + cl_context m_context; + cl_device_id m_device; + cl_command_queue m_queue; + int m_pairCapacity; + int m_nIterations; + + b3OpenCLArray* m_contactCGPU; + b3OpenCLArray* m_numConstraints; + b3OpenCLArray* m_offsets; + + b3Solver* m_solverGPU; + + cl_kernel m_batchingKernel; + cl_kernel m_batchingKernelNew; + cl_kernel m_solveContactKernel; + cl_kernel m_solveSingleContactKernel; + cl_kernel m_solveSingleFrictionKernel; + cl_kernel m_solveFrictionKernel; + cl_kernel m_contactToConstraintKernel; + cl_kernel m_setSortDataKernel; + cl_kernel m_reorderContactKernel; + cl_kernel m_copyConstraintKernel; + + cl_kernel m_setDeterminismSortDataBodyAKernel; + cl_kernel m_setDeterminismSortDataBodyBKernel; + cl_kernel m_setDeterminismSortDataChildShapeAKernel; + cl_kernel m_setDeterminismSortDataChildShapeBKernel; + + + + + class b3RadixSort32CL* m_sort32; + class b3BoundSearchCL* m_search; + class b3PrefixScanCL* m_scan; + + b3OpenCLArray* m_sortDataBuffer; + b3OpenCLArray* m_contactBuffer; + + b3OpenCLArray* m_bodyBufferGPU; + b3OpenCLArray* m_inertiaBufferGPU; + b3OpenCLArray* m_pBufContactOutGPU; + + b3OpenCLArray* m_pBufContactOutGPUCopy; + b3OpenCLArray* m_contactKeyValues; + + + b3AlignedObjectArray m_idxBuffer; + b3AlignedObjectArray m_sortData; + b3AlignedObjectArray m_old; + + b3AlignedObjectArray m_batchSizes; + b3OpenCLArray* m_batchSizesGpu; + +}; + + + +b3GpuPgsContactSolver::b3GpuPgsContactSolver(cl_context ctx,cl_device_id device, cl_command_queue q,int pairCapacity) +{ + m_debugOutput=0; + m_data = new b3GpuBatchingPgsSolverInternalData; + m_data->m_context = ctx; + m_data->m_device = device; + m_data->m_queue = q; + m_data->m_pairCapacity = pairCapacity; + m_data->m_nIterations = 4; + m_data->m_batchSizesGpu = new b3OpenCLArray(ctx,q); + m_data->m_bodyBufferGPU = new b3OpenCLArray(ctx,q); + m_data->m_inertiaBufferGPU = new b3OpenCLArray(ctx,q); + m_data->m_pBufContactOutGPU = new b3OpenCLArray(ctx,q); + + m_data->m_pBufContactOutGPUCopy = new b3OpenCLArray(ctx,q); + m_data->m_contactKeyValues = new b3OpenCLArray(ctx,q); + + + m_data->m_solverGPU = new b3Solver(ctx,device,q,512*1024); + + m_data->m_sort32 = new b3RadixSort32CL(ctx,device,m_data->m_queue); + m_data->m_scan = new b3PrefixScanCL(ctx,device,m_data->m_queue,B3_SOLVER_N_CELLS); + m_data->m_search = new b3BoundSearchCL(ctx,device,m_data->m_queue,B3_SOLVER_N_CELLS); + + const int sortSize = B3NEXTMULTIPLEOF( pairCapacity, 512 ); + + m_data->m_sortDataBuffer = new b3OpenCLArray(ctx,m_data->m_queue,sortSize); + m_data->m_contactBuffer = new b3OpenCLArray(ctx,m_data->m_queue); + + m_data->m_numConstraints = new b3OpenCLArray(ctx,m_data->m_queue,B3_SOLVER_N_CELLS); + m_data->m_numConstraints->resize(B3_SOLVER_N_CELLS); + + m_data->m_contactCGPU = new b3OpenCLArray(ctx,q,pairCapacity); + + m_data->m_offsets = new b3OpenCLArray( ctx,m_data->m_queue,B3_SOLVER_N_CELLS); + m_data->m_offsets->resize(B3_SOLVER_N_CELLS); + const char* additionalMacros = ""; + //const char* srcFileNameForCaching=""; + + + + cl_int pErrNum; + const char* batchKernelSource = batchingKernelsCL; + const char* batchKernelNewSource = batchingKernelsNewCL; + const char* solverSetupSource = solverSetupCL; + const char* solverSetup2Source = solverSetup2CL; + const char* solveContactSource = solveContactCL; + const char* solveFrictionSource = solveFrictionCL; + + + { + + cl_program solveContactProg= b3OpenCLUtils::compileCLProgramFromString( ctx, device, solveContactSource, &pErrNum,additionalMacros, B3_SOLVER_CONTACT_KERNEL_PATH); + b3Assert(solveContactProg); + + cl_program solveFrictionProg= b3OpenCLUtils::compileCLProgramFromString( ctx, device, solveFrictionSource, &pErrNum,additionalMacros, B3_SOLVER_FRICTION_KERNEL_PATH); + b3Assert(solveFrictionProg); + + cl_program solverSetup2Prog= b3OpenCLUtils::compileCLProgramFromString( ctx, device, solverSetup2Source, &pErrNum,additionalMacros, B3_SOLVER_SETUP2_KERNEL_PATH); + + + b3Assert(solverSetup2Prog); + + + cl_program solverSetupProg= b3OpenCLUtils::compileCLProgramFromString( ctx, device, solverSetupSource, &pErrNum,additionalMacros, B3_SOLVER_SETUP_KERNEL_PATH); + b3Assert(solverSetupProg); + + + m_data->m_solveFrictionKernel= b3OpenCLUtils::compileCLKernelFromString( ctx, device, solveFrictionSource, "BatchSolveKernelFriction", &pErrNum, solveFrictionProg,additionalMacros ); + b3Assert(m_data->m_solveFrictionKernel); + + m_data->m_solveContactKernel= b3OpenCLUtils::compileCLKernelFromString( ctx, device, solveContactSource, "BatchSolveKernelContact", &pErrNum, solveContactProg,additionalMacros ); + b3Assert(m_data->m_solveContactKernel); + + m_data->m_solveSingleContactKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solveContactSource, "solveSingleContactKernel", &pErrNum, solveContactProg,additionalMacros ); + b3Assert(m_data->m_solveSingleContactKernel); + + m_data->m_solveSingleFrictionKernel =b3OpenCLUtils::compileCLKernelFromString( ctx, device, solveFrictionSource, "solveSingleFrictionKernel", &pErrNum, solveFrictionProg,additionalMacros ); + b3Assert(m_data->m_solveSingleFrictionKernel); + + m_data->m_contactToConstraintKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverSetupSource, "ContactToConstraintKernel", &pErrNum, solverSetupProg,additionalMacros ); + b3Assert(m_data->m_contactToConstraintKernel); + + m_data->m_setSortDataKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverSetup2Source, "SetSortDataKernel", &pErrNum, solverSetup2Prog,additionalMacros ); + b3Assert(m_data->m_setSortDataKernel); + + m_data->m_setDeterminismSortDataBodyAKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverSetup2Source, "SetDeterminismSortDataBodyA", &pErrNum, solverSetup2Prog,additionalMacros ); + b3Assert(m_data->m_setDeterminismSortDataBodyAKernel); + + m_data->m_setDeterminismSortDataBodyBKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverSetup2Source, "SetDeterminismSortDataBodyB", &pErrNum, solverSetup2Prog,additionalMacros ); + b3Assert(m_data->m_setDeterminismSortDataBodyBKernel); + + m_data->m_setDeterminismSortDataChildShapeAKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverSetup2Source, "SetDeterminismSortDataChildShapeA", &pErrNum, solverSetup2Prog,additionalMacros ); + b3Assert(m_data->m_setDeterminismSortDataChildShapeAKernel); + + m_data->m_setDeterminismSortDataChildShapeBKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverSetup2Source, "SetDeterminismSortDataChildShapeB", &pErrNum, solverSetup2Prog,additionalMacros ); + b3Assert(m_data->m_setDeterminismSortDataChildShapeBKernel); + + + m_data->m_reorderContactKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverSetup2Source, "ReorderContactKernel", &pErrNum, solverSetup2Prog,additionalMacros ); + b3Assert(m_data->m_reorderContactKernel); + + + m_data->m_copyConstraintKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverSetup2Source, "CopyConstraintKernel", &pErrNum, solverSetup2Prog,additionalMacros ); + b3Assert(m_data->m_copyConstraintKernel); + + } + + { + cl_program batchingProg = b3OpenCLUtils::compileCLProgramFromString( ctx, device, batchKernelSource, &pErrNum,additionalMacros, B3_BATCHING_PATH); + b3Assert(batchingProg); + + m_data->m_batchingKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, batchKernelSource, "CreateBatches", &pErrNum, batchingProg,additionalMacros ); + b3Assert(m_data->m_batchingKernel); + } + + { + cl_program batchingNewProg = b3OpenCLUtils::compileCLProgramFromString( ctx, device, batchKernelNewSource, &pErrNum,additionalMacros, B3_BATCHING_NEW_PATH); + b3Assert(batchingNewProg); + + m_data->m_batchingKernelNew = b3OpenCLUtils::compileCLKernelFromString( ctx, device, batchKernelNewSource, "CreateBatchesNew", &pErrNum, batchingNewProg,additionalMacros ); + b3Assert(m_data->m_batchingKernelNew); + } + + + + + + + +} + +b3GpuPgsContactSolver::~b3GpuPgsContactSolver() +{ + delete m_data->m_batchSizesGpu; + delete m_data->m_bodyBufferGPU; + delete m_data->m_inertiaBufferGPU; + delete m_data->m_pBufContactOutGPU; + delete m_data->m_pBufContactOutGPUCopy; + delete m_data->m_contactKeyValues; + + + + delete m_data->m_contactCGPU; + delete m_data->m_numConstraints; + delete m_data->m_offsets; + delete m_data->m_sortDataBuffer; + delete m_data->m_contactBuffer; + + delete m_data->m_sort32; + delete m_data->m_scan; + delete m_data->m_search; + delete m_data->m_solverGPU; + + clReleaseKernel(m_data->m_batchingKernel); + clReleaseKernel(m_data->m_batchingKernelNew); + clReleaseKernel(m_data->m_solveSingleContactKernel); + clReleaseKernel(m_data->m_solveSingleFrictionKernel); + clReleaseKernel( m_data->m_solveContactKernel); + clReleaseKernel( m_data->m_solveFrictionKernel); + + clReleaseKernel( m_data->m_contactToConstraintKernel); + clReleaseKernel( m_data->m_setSortDataKernel); + clReleaseKernel( m_data->m_reorderContactKernel); + clReleaseKernel( m_data->m_copyConstraintKernel); + + clReleaseKernel(m_data->m_setDeterminismSortDataBodyAKernel); + clReleaseKernel(m_data->m_setDeterminismSortDataBodyBKernel); + clReleaseKernel(m_data->m_setDeterminismSortDataChildShapeAKernel); + clReleaseKernel(m_data->m_setDeterminismSortDataChildShapeBKernel); + + + + delete m_data; +} + + + +struct b3ConstraintCfg +{ + b3ConstraintCfg( float dt = 0.f ): m_positionDrift( 0.005f ), m_positionConstraintCoeff( 0.2f ), m_dt(dt), m_staticIdx(0) {} + + float m_positionDrift; + float m_positionConstraintCoeff; + float m_dt; + bool m_enableParallelSolve; + float m_batchCellSize; + int m_staticIdx; +}; + + + +void b3GpuPgsContactSolver::solveContactConstraintBatchSizes( const b3OpenCLArray* bodyBuf, const b3OpenCLArray* shapeBuf, + b3OpenCLArray* constraint, void* additionalData, int n ,int maxNumBatches,int numIterations, const b3AlignedObjectArray* batchSizes)//const b3OpenCLArray* gpuBatchSizes) +{ + B3_PROFILE("solveContactConstraintBatchSizes"); + int numBatches = batchSizes->size()/B3_MAX_NUM_BATCHES; + for(int iter=0; iterat(cellId*B3_MAX_NUM_BATCHES+ii); + if (!numInBatch) + break; + + { + b3LauncherCL launcher( m_data->m_queue, m_data->m_solveSingleContactKernel,"m_solveSingleContactKernel" ); + launcher.setBuffer(bodyBuf->getBufferCL() ); + launcher.setBuffer(shapeBuf->getBufferCL() ); + launcher.setBuffer( constraint->getBufferCL() ); + launcher.setConst(cellId); + launcher.setConst(offset); + launcher.setConst(numInBatch); + launcher.launch1D(numInBatch); + offset+=numInBatch; + } + } + } + } + + + for(int iter=0; iterat(cellId*B3_MAX_NUM_BATCHES+ii); + if (!numInBatch) + break; + + { + b3LauncherCL launcher( m_data->m_queue, m_data->m_solveSingleFrictionKernel,"m_solveSingleFrictionKernel" ); + launcher.setBuffer(bodyBuf->getBufferCL() ); + launcher.setBuffer(shapeBuf->getBufferCL() ); + launcher.setBuffer( constraint->getBufferCL() ); + launcher.setConst(cellId); + launcher.setConst(offset); + launcher.setConst(numInBatch); + launcher.launch1D(numInBatch); + offset+=numInBatch; + } + } + } + } +} + +void b3GpuPgsContactSolver::solveContactConstraint( const b3OpenCLArray* bodyBuf, const b3OpenCLArray* shapeBuf, + b3OpenCLArray* constraint, void* additionalData, int n ,int maxNumBatches,int numIterations, const b3AlignedObjectArray* batchSizes)//,const b3OpenCLArray* gpuBatchSizes) +{ + + //sort the contacts + + + b3Int4 cdata = b3MakeInt4( n, 0, 0, 0 ); + { + + const int nn = B3_SOLVER_N_CELLS; + + cdata.x = 0; + cdata.y = maxNumBatches;//250; + + + int numWorkItems = 64*nn/B3_SOLVER_N_BATCHES; +#ifdef DEBUG_ME + SolverDebugInfo* debugInfo = new SolverDebugInfo[numWorkItems]; + adl::b3OpenCLArray gpuDebugInfo(data->m_device,numWorkItems); +#endif + + + + { + + B3_PROFILE("m_batchSolveKernel iterations"); + for(int iter=0; iterm_queue, m_data->m_solveContactKernel,"m_solveContactKernel" ); +#if 1 + + b3BufferInfoCL bInfo[] = { + + b3BufferInfoCL( bodyBuf->getBufferCL() ), + b3BufferInfoCL( shapeBuf->getBufferCL() ), + b3BufferInfoCL( constraint->getBufferCL() ), + b3BufferInfoCL( m_data->m_solverGPU->m_numConstraints->getBufferCL() ), + b3BufferInfoCL( m_data->m_solverGPU->m_offsets->getBufferCL() ) +#ifdef DEBUG_ME + , b3BufferInfoCL(&gpuDebugInfo) +#endif + }; + + + + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setBuffer( m_data->m_solverGPU->m_batchSizes.getBufferCL()); + //launcher.setConst( cdata.x ); + launcher.setConst( cdata.y ); + launcher.setConst( cdata.z ); + b3Int4 nSplit; + nSplit.x = B3_SOLVER_N_SPLIT_X; + nSplit.y = B3_SOLVER_N_SPLIT_Y; + nSplit.z = B3_SOLVER_N_SPLIT_Z; + + launcher.setConst( nSplit ); + launcher.launch1D( numWorkItems, 64 ); + + +#else + const char* fileName = "m_batchSolveKernel.bin"; + FILE* f = fopen(fileName,"rb"); + if (f) + { + int sizeInBytes=0; + if (fseek(f, 0, SEEK_END) || (sizeInBytes = ftell(f)) == EOF || fseek(f, 0, SEEK_SET)) + { + printf("error, cannot get file size\n"); + exit(0); + } + + unsigned char* buf = (unsigned char*) malloc(sizeInBytes); + fread(buf,sizeInBytes,1,f); + int serializedBytes = launcher.deserializeArgs(buf, sizeInBytes,m_context); + int num = *(int*)&buf[serializedBytes]; + + launcher.launch1D( num); + + //this clFinish is for testing on errors + clFinish(m_queue); + } + +#endif + + +#ifdef DEBUG_ME + clFinish(m_queue); + gpuDebugInfo.read(debugInfo,numWorkItems); + clFinish(m_queue); + for (int i=0;i0) + { + printf("debugInfo[i].m_valInt2 = %d\n",i,debugInfo[i].m_valInt2); + } + + if (debugInfo[i].m_valInt3>0) + { + printf("debugInfo[i].m_valInt3 = %d\n",i,debugInfo[i].m_valInt3); + } + } +#endif //DEBUG_ME + + + } + } + + clFinish(m_data->m_queue); + + + } + + cdata.x = 1; + bool applyFriction=true; + if (applyFriction) + { + B3_PROFILE("m_batchSolveKernel iterations2"); + for(int iter=0; itergetBufferCL() ), + b3BufferInfoCL( shapeBuf->getBufferCL() ), + b3BufferInfoCL( constraint->getBufferCL() ), + b3BufferInfoCL( m_data->m_solverGPU->m_numConstraints->getBufferCL() ), + b3BufferInfoCL( m_data->m_solverGPU->m_offsets->getBufferCL() ) +#ifdef DEBUG_ME + ,b3BufferInfoCL(&gpuDebugInfo) +#endif //DEBUG_ME + }; + b3LauncherCL launcher( m_data->m_queue, m_data->m_solveFrictionKernel,"m_solveFrictionKernel" ); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setBuffer( m_data->m_solverGPU->m_batchSizes.getBufferCL()); + //launcher.setConst( cdata.x ); + launcher.setConst( cdata.y ); + launcher.setConst( cdata.z ); + + b3Int4 nSplit; + nSplit.x = B3_SOLVER_N_SPLIT_X; + nSplit.y = B3_SOLVER_N_SPLIT_Y; + nSplit.z = B3_SOLVER_N_SPLIT_Z; + + launcher.setConst( nSplit ); + + launcher.launch1D( 64*nn/B3_SOLVER_N_BATCHES, 64 ); + } + } + clFinish(m_data->m_queue); + + } +#ifdef DEBUG_ME + delete[] debugInfo; +#endif //DEBUG_ME + } + + +} + + + + + + + + + + + +static bool sortfnc(const b3SortData& a,const b3SortData& b) +{ + return (a.m_keym_bodyBufferGPU->setFromOpenCLBuffer(bodyBuf,numBodies); + m_data->m_inertiaBufferGPU->setFromOpenCLBuffer(inertiaBuf,numBodies); + m_data->m_pBufContactOutGPU->setFromOpenCLBuffer(contactBuf,numContacts); + + if (optionalSortContactsDeterminism) + { + if (!gCpuSortContactsDeterminism) + { + B3_PROFILE("GPU Sort contact constraints (determinism)"); + + m_data->m_pBufContactOutGPUCopy->resize(numContacts); + m_data->m_contactKeyValues->resize(numContacts); + + m_data->m_pBufContactOutGPU->copyToCL(m_data->m_pBufContactOutGPUCopy->getBufferCL(),numContacts,0,0); + + { + b3LauncherCL launcher(m_data->m_queue, m_data->m_setDeterminismSortDataChildShapeBKernel,"m_setDeterminismSortDataChildShapeBKernel"); + launcher.setBuffer(m_data->m_pBufContactOutGPUCopy->getBufferCL()); + launcher.setBuffer(m_data->m_contactKeyValues->getBufferCL()); + launcher.setConst(numContacts); + launcher.launch1D( numContacts, 64 ); + } + m_data->m_solverGPU->m_sort32->execute(*m_data->m_contactKeyValues); + { + b3LauncherCL launcher(m_data->m_queue, m_data->m_setDeterminismSortDataChildShapeAKernel,"m_setDeterminismSortDataChildShapeAKernel"); + launcher.setBuffer(m_data->m_pBufContactOutGPUCopy->getBufferCL()); + launcher.setBuffer(m_data->m_contactKeyValues->getBufferCL()); + launcher.setConst(numContacts); + launcher.launch1D( numContacts, 64 ); + } + m_data->m_solverGPU->m_sort32->execute(*m_data->m_contactKeyValues); + { + b3LauncherCL launcher(m_data->m_queue, m_data->m_setDeterminismSortDataBodyBKernel,"m_setDeterminismSortDataBodyBKernel"); + launcher.setBuffer(m_data->m_pBufContactOutGPUCopy->getBufferCL()); + launcher.setBuffer(m_data->m_contactKeyValues->getBufferCL()); + launcher.setConst(numContacts); + launcher.launch1D( numContacts, 64 ); + } + + m_data->m_solverGPU->m_sort32->execute(*m_data->m_contactKeyValues); + + { + b3LauncherCL launcher(m_data->m_queue, m_data->m_setDeterminismSortDataBodyAKernel,"m_setDeterminismSortDataBodyAKernel"); + launcher.setBuffer(m_data->m_pBufContactOutGPUCopy->getBufferCL()); + launcher.setBuffer(m_data->m_contactKeyValues->getBufferCL()); + launcher.setConst(numContacts); + launcher.launch1D( numContacts, 64 ); + } + + m_data->m_solverGPU->m_sort32->execute(*m_data->m_contactKeyValues); + + { + B3_PROFILE("gpu reorderContactKernel (determinism)"); + + b3Int4 cdata; + cdata.x = numContacts; + + //b3BufferInfoCL bInfo[] = { b3BufferInfoCL( m_data->m_pBufContactOutGPU->getBufferCL() ), b3BufferInfoCL( m_data->m_solverGPU->m_contactBuffer2->getBufferCL()) + // , b3BufferInfoCL( m_data->m_solverGPU->m_sortDataBuffer->getBufferCL()) }; + b3LauncherCL launcher(m_data->m_queue,m_data->m_solverGPU->m_reorderContactKernel,"m_reorderContactKernel"); + launcher.setBuffer(m_data->m_pBufContactOutGPUCopy->getBufferCL()); + launcher.setBuffer(m_data->m_pBufContactOutGPU->getBufferCL()); + launcher.setBuffer(m_data->m_contactKeyValues->getBufferCL()); + launcher.setConst( cdata ); + launcher.launch1D( numContacts, 64 ); + } + + } else + { + B3_PROFILE("CPU Sort contact constraints (determinism)"); + b3AlignedObjectArray cpuConstraints; + m_data->m_pBufContactOutGPU->copyToHost(cpuConstraints); + bool sort = true; + if (sort) + { + cpuConstraints.quickSort(b3ContactCmp); + + for (int i=0;im_pBufContactOutGPU->copyFromHost(cpuConstraints); + if (m_debugOutput==100) + { + for (int i=0;im_pBufContactOutGPU->size(); + + bool useSolver = true; + + + if (useSolver) + { + float dt=1./60.; + b3ConstraintCfg csCfg( dt ); + csCfg.m_enableParallelSolve = true; + csCfg.m_batchCellSize = 6; + csCfg.m_staticIdx = static0Index; + + + b3OpenCLArray* bodyBuf = m_data->m_bodyBufferGPU; + + void* additionalData = 0;//m_data->m_frictionCGPU; + const b3OpenCLArray* shapeBuf = m_data->m_inertiaBufferGPU; + b3OpenCLArray* contactConstraintOut = m_data->m_contactCGPU; + int nContacts = nContactOut; + + + int maxNumBatches = 0; + + if (!gUseLargeBatches) + { + + if( m_data->m_solverGPU->m_contactBuffer2) + { + m_data->m_solverGPU->m_contactBuffer2->resize(nContacts); + } + + if( m_data->m_solverGPU->m_contactBuffer2 == 0 ) + { + m_data->m_solverGPU->m_contactBuffer2 = new b3OpenCLArray(m_data->m_context,m_data->m_queue, nContacts ); + m_data->m_solverGPU->m_contactBuffer2->resize(nContacts); + } + + //clFinish(m_data->m_queue); + + + + { + B3_PROFILE("batching"); + //@todo: just reserve it, without copy of original contact (unless we use warmstarting) + + + + //const b3OpenCLArray* bodyNative = bodyBuf; + + + { + + //b3OpenCLArray* bodyNative = b3OpenCLArrayUtils::map( data->m_device, bodyBuf ); + //b3OpenCLArray* contactNative = b3OpenCLArrayUtils::map( data->m_device, contactsIn ); + + const int sortAlignment = 512; // todo. get this out of sort + if( csCfg.m_enableParallelSolve ) + { + + + int sortSize = B3NEXTMULTIPLEOF( nContacts, sortAlignment ); + + b3OpenCLArray* countsNative = m_data->m_solverGPU->m_numConstraints; + b3OpenCLArray* offsetsNative = m_data->m_solverGPU->m_offsets; + + + if (!gCpuSetSortData) + { // 2. set cell idx + B3_PROFILE("GPU set cell idx"); + struct CB + { + int m_nContacts; + int m_staticIdx; + float m_scale; + b3Int4 m_nSplit; + }; + + b3Assert( sortSize%64 == 0 ); + CB cdata; + cdata.m_nContacts = nContacts; + cdata.m_staticIdx = csCfg.m_staticIdx; + cdata.m_scale = 1.f/csCfg.m_batchCellSize; + cdata.m_nSplit.x = B3_SOLVER_N_SPLIT_X; + cdata.m_nSplit.y = B3_SOLVER_N_SPLIT_Y; + cdata.m_nSplit.z = B3_SOLVER_N_SPLIT_Z; + + m_data->m_solverGPU->m_sortDataBuffer->resize(nContacts); + + + b3BufferInfoCL bInfo[] = { b3BufferInfoCL( m_data->m_pBufContactOutGPU->getBufferCL() ), b3BufferInfoCL( bodyBuf->getBufferCL()), b3BufferInfoCL( m_data->m_solverGPU->m_sortDataBuffer->getBufferCL()) }; + b3LauncherCL launcher(m_data->m_queue, m_data->m_solverGPU->m_setSortDataKernel,"m_setSortDataKernel" ); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( cdata.m_nContacts ); + launcher.setConst( cdata.m_scale ); + launcher.setConst(cdata.m_nSplit); + launcher.setConst(cdata.m_staticIdx); + + + launcher.launch1D( sortSize, 64 ); + } else + { + m_data->m_solverGPU->m_sortDataBuffer->resize(nContacts); + b3AlignedObjectArray sortDataCPU; + m_data->m_solverGPU->m_sortDataBuffer->copyToHost(sortDataCPU); + + b3AlignedObjectArray contactCPU; + m_data->m_pBufContactOutGPU->copyToHost(contactCPU); + b3AlignedObjectArray bodiesCPU; + bodyBuf->copyToHost(bodiesCPU); + float scale = 1.f/csCfg.m_batchCellSize; + b3Int4 nSplit; + nSplit.x = B3_SOLVER_N_SPLIT_X; + nSplit.y = B3_SOLVER_N_SPLIT_Y; + nSplit.z = B3_SOLVER_N_SPLIT_Z; + + SetSortDataCPU(&contactCPU[0], &bodiesCPU[0], &sortDataCPU[0], nContacts,scale,nSplit,csCfg.m_staticIdx); + + + m_data->m_solverGPU->m_sortDataBuffer->copyFromHost(sortDataCPU); + } + + + + if (!gCpuRadixSort) + { // 3. sort by cell idx + B3_PROFILE("gpuRadixSort"); + //int n = B3_SOLVER_N_SPLIT*B3_SOLVER_N_SPLIT; + //int sortBit = 32; + //if( n <= 0xffff ) sortBit = 16; + //if( n <= 0xff ) sortBit = 8; + //adl::RadixSort::execute( data->m_sort, *data->m_sortDataBuffer, sortSize ); + //adl::RadixSort32::execute( data->m_sort32, *data->m_sortDataBuffer, sortSize ); + b3OpenCLArray& keyValuesInOut = *(m_data->m_solverGPU->m_sortDataBuffer); + this->m_data->m_solverGPU->m_sort32->execute(keyValuesInOut); + + + + } else + { + b3OpenCLArray& keyValuesInOut = *(m_data->m_solverGPU->m_sortDataBuffer); + b3AlignedObjectArray hostValues; + keyValuesInOut.copyToHost(hostValues); + hostValues.quickSort(sortfnc); + keyValuesInOut.copyFromHost(hostValues); + } + + + if (gUseScanHost) + { + // 4. find entries + B3_PROFILE("cpuBoundSearch"); + b3AlignedObjectArray countsHost; + countsNative->copyToHost(countsHost); + + b3AlignedObjectArray sortDataHost; + m_data->m_solverGPU->m_sortDataBuffer->copyToHost(sortDataHost); + + + //m_data->m_solverGPU->m_search->executeHost(*m_data->m_solverGPU->m_sortDataBuffer,nContacts,*countsNative,B3_SOLVER_N_CELLS,b3BoundSearchCL::COUNT); + m_data->m_solverGPU->m_search->executeHost(sortDataHost,nContacts,countsHost,B3_SOLVER_N_CELLS,b3BoundSearchCL::COUNT); + + countsNative->copyFromHost(countsHost); + + + //adl::BoundSearch::execute( data->m_search, *data->m_sortDataBuffer, nContacts, *countsNative, + // B3_SOLVER_N_SPLIT*B3_SOLVER_N_SPLIT, adl::BoundSearchBase::COUNT ); + + //unsigned int sum; + //m_data->m_solverGPU->m_scan->execute(*countsNative,*offsetsNative, B3_SOLVER_N_CELLS);//,&sum ); + b3AlignedObjectArray offsetsHost; + offsetsHost.resize(offsetsNative->size()); + + + m_data->m_solverGPU->m_scan->executeHost(countsHost,offsetsHost, B3_SOLVER_N_CELLS);//,&sum ); + offsetsNative->copyFromHost(offsetsHost); + + //printf("sum = %d\n",sum); + } else + { + // 4. find entries + B3_PROFILE("gpuBoundSearch"); + m_data->m_solverGPU->m_search->execute(*m_data->m_solverGPU->m_sortDataBuffer,nContacts,*countsNative,B3_SOLVER_N_CELLS,b3BoundSearchCL::COUNT); + m_data->m_solverGPU->m_scan->execute(*countsNative,*offsetsNative, B3_SOLVER_N_CELLS);//,&sum ); + } + + + + + if (nContacts) + { // 5. sort constraints by cellIdx + if (gReorderContactsOnCpu) + { + B3_PROFILE("cpu m_reorderContactKernel"); + b3AlignedObjectArray sortDataHost; + m_data->m_solverGPU->m_sortDataBuffer->copyToHost(sortDataHost); + b3AlignedObjectArray inContacts; + b3AlignedObjectArray outContacts; + m_data->m_pBufContactOutGPU->copyToHost(inContacts); + outContacts.resize(inContacts.size()); + for (int i=0;im_solverGPU->m_contactBuffer2->copyFromHost(outContacts); + + /* "void ReorderContactKernel(__global struct b3Contact4Data* in, __global struct b3Contact4Data* out, __global int2* sortData, int4 cb )\n" + "{\n" + " int nContacts = cb.x;\n" + " int gIdx = GET_GLOBAL_IDX;\n" + " if( gIdx < nContacts )\n" + " {\n" + " int srcIdx = sortData[gIdx].y;\n" + " out[gIdx] = in[srcIdx];\n" + " }\n" + "}\n" + */ + } else + { + B3_PROFILE("gpu m_reorderContactKernel"); + + b3Int4 cdata; + cdata.x = nContacts; + + b3BufferInfoCL bInfo[] = { + b3BufferInfoCL( m_data->m_pBufContactOutGPU->getBufferCL() ), + b3BufferInfoCL( m_data->m_solverGPU->m_contactBuffer2->getBufferCL()) + , b3BufferInfoCL( m_data->m_solverGPU->m_sortDataBuffer->getBufferCL()) }; + + b3LauncherCL launcher(m_data->m_queue,m_data->m_solverGPU->m_reorderContactKernel,"m_reorderContactKernel"); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( cdata ); + launcher.launch1D( nContacts, 64 ); + } + } + + + + + } + + } + + //clFinish(m_data->m_queue); + + // { + // b3AlignedObjectArray histogram; + // m_data->m_solverGPU->m_numConstraints->copyToHost(histogram); + // printf(",,,\n"); + // } + + + if (nContacts) + { + + if (gUseCpuCopyConstraints) + { + for (int i=0;im_pBufContactOutGPU->copyFromOpenCLArray(*m_data->m_solverGPU->m_contactBuffer2); + // m_data->m_solverGPU->m_contactBuffer2->getBufferCL(); + // m_data->m_pBufContactOutGPU->getBufferCL() + } + + } else + { + B3_PROFILE("gpu m_copyConstraintKernel"); + b3Int4 cdata; cdata.x = nContacts; + b3BufferInfoCL bInfo[] = { + b3BufferInfoCL( m_data->m_solverGPU->m_contactBuffer2->getBufferCL() ), + b3BufferInfoCL( m_data->m_pBufContactOutGPU->getBufferCL() ) + }; + + b3LauncherCL launcher(m_data->m_queue, m_data->m_solverGPU->m_copyConstraintKernel,"m_copyConstraintKernel" ); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( cdata ); + launcher.launch1D( nContacts, 64 ); + //we use the clFinish for proper benchmark/profile + clFinish(m_data->m_queue); + } + } + + +// bool compareGPU = false; + if (nContacts) + { + if (!gCpuBatchContacts) + { + B3_PROFILE("gpu batchContacts"); + maxNumBatches = 250;//250; + m_data->m_solverGPU->batchContacts( m_data->m_pBufContactOutGPU, nContacts, m_data->m_solverGPU->m_numConstraints, m_data->m_solverGPU->m_offsets, csCfg.m_staticIdx ); + clFinish(m_data->m_queue); + } else + { + B3_PROFILE("cpu batchContacts"); + static b3AlignedObjectArray cpuContacts; + b3OpenCLArray* contactsIn = m_data->m_solverGPU->m_contactBuffer2; + { + B3_PROFILE("copyToHost"); + contactsIn->copyToHost(cpuContacts); + } + b3OpenCLArray* countsNative = m_data->m_solverGPU->m_numConstraints; + b3OpenCLArray* offsetsNative = m_data->m_solverGPU->m_offsets; + + b3AlignedObjectArray nNativeHost; + b3AlignedObjectArray offsetsNativeHost; + + { + B3_PROFILE("countsNative/offsetsNative copyToHost"); + countsNative->copyToHost(nNativeHost); + offsetsNative->copyToHost(offsetsNativeHost); + } + + + int numNonzeroGrid=0; + + if (gUseLargeBatches) + { + m_data->m_batchSizes.resize(B3_MAX_NUM_BATCHES); + int totalNumConstraints = cpuContacts.size(); + //int simdWidth =numBodies+1;//-1;//64;//-1;//32; + int numBatches = sortConstraintByBatch3( &cpuContacts[0], totalNumConstraints, totalNumConstraints+1,csCfg.m_staticIdx ,numBodies,&m_data->m_batchSizes[0]); // on GPU + maxNumBatches = b3Max(numBatches,maxNumBatches); + static int globalMaxBatch = 0; + if (maxNumBatches>globalMaxBatch ) + { + globalMaxBatch = maxNumBatches; + b3Printf("maxNumBatches = %d\n",maxNumBatches); + } + + } else + { + m_data->m_batchSizes.resize(B3_SOLVER_N_CELLS*B3_MAX_NUM_BATCHES); + B3_PROFILE("cpu batch grid"); + for(int i=0; im_batchSizes[i*B3_MAX_NUM_BATCHES]); // on GPU + maxNumBatches = b3Max(numBatches,maxNumBatches); + static int globalMaxBatch = 0; + if (maxNumBatches>globalMaxBatch ) + { + globalMaxBatch = maxNumBatches; + b3Printf("maxNumBatches = %d\n",maxNumBatches); + } + //we use the clFinish for proper benchmark/profile + + } + } + //clFinish(m_data->m_queue); + } + { + B3_PROFILE("m_contactBuffer->copyFromHost"); + m_data->m_solverGPU->m_contactBuffer2->copyFromHost((b3AlignedObjectArray&)cpuContacts); + } + + } + + } + + + + + + } + + + } + + + //printf("maxNumBatches = %d\n", maxNumBatches); + + if (gUseLargeBatches) + { + if (nContacts) + { + B3_PROFILE("cpu batchContacts"); + static b3AlignedObjectArray cpuContacts; +// b3OpenCLArray* contactsIn = m_data->m_solverGPU->m_contactBuffer2; + { + B3_PROFILE("copyToHost"); + m_data->m_pBufContactOutGPU->copyToHost(cpuContacts); + } +// b3OpenCLArray* countsNative = m_data->m_solverGPU->m_numConstraints; +// b3OpenCLArray* offsetsNative = m_data->m_solverGPU->m_offsets; + + + +// int numNonzeroGrid=0; + + { + m_data->m_batchSizes.resize(B3_MAX_NUM_BATCHES); + int totalNumConstraints = cpuContacts.size(); + // int simdWidth =numBodies+1;//-1;//64;//-1;//32; + int numBatches = sortConstraintByBatch3( &cpuContacts[0], totalNumConstraints, totalNumConstraints+1,csCfg.m_staticIdx ,numBodies,&m_data->m_batchSizes[0]); // on GPU + maxNumBatches = b3Max(numBatches,maxNumBatches); + static int globalMaxBatch = 0; + if (maxNumBatches>globalMaxBatch ) + { + globalMaxBatch = maxNumBatches; + b3Printf("maxNumBatches = %d\n",maxNumBatches); + } + + } + { + B3_PROFILE("m_contactBuffer->copyFromHost"); + m_data->m_solverGPU->m_contactBuffer2->copyFromHost((b3AlignedObjectArray&)cpuContacts); + } + + } + + } + + if (nContacts) + { + B3_PROFILE("gpu convertToConstraints"); + m_data->m_solverGPU->convertToConstraints( bodyBuf, + shapeBuf, m_data->m_solverGPU->m_contactBuffer2, + contactConstraintOut, + additionalData, nContacts, + (b3SolverBase::ConstraintCfg&) csCfg ); + clFinish(m_data->m_queue); + } + + + if (1) + { + int numIter = 4; + + m_data->m_solverGPU->m_nIterations = numIter;//10 + if (!gCpuSolveConstraint) + { + B3_PROFILE("GPU solveContactConstraint"); + + /*m_data->m_solverGPU->solveContactConstraint( + m_data->m_bodyBufferGPU, + m_data->m_inertiaBufferGPU, + m_data->m_contactCGPU,0, + nContactOut , + maxNumBatches); + */ + + //m_data->m_batchSizesGpu->copyFromHost(m_data->m_batchSizes); + + if (gUseLargeBatches) + { + solveContactConstraintBatchSizes(m_data->m_bodyBufferGPU, + m_data->m_inertiaBufferGPU, + m_data->m_contactCGPU,0, + nContactOut , + maxNumBatches,numIter,&m_data->m_batchSizes); + } else + { + solveContactConstraint( + m_data->m_bodyBufferGPU, + m_data->m_inertiaBufferGPU, + m_data->m_contactCGPU,0, + nContactOut , + maxNumBatches,numIter,&m_data->m_batchSizes);//m_data->m_batchSizesGpu); + } + } + else + { + B3_PROFILE("Host solveContactConstraint"); + + m_data->m_solverGPU->solveContactConstraintHost(m_data->m_bodyBufferGPU, m_data->m_inertiaBufferGPU, m_data->m_contactCGPU,0, nContactOut ,maxNumBatches,&m_data->m_batchSizes); + } + + + } + + +#if 0 + if (0) + { + B3_PROFILE("read body velocities back to CPU"); + //read body updated linear/angular velocities back to CPU + m_data->m_bodyBufferGPU->read( + m_data->m_bodyBufferCPU->m_ptr,numOfConvexRBodies); + adl::DeviceUtils::waitForCompletion( m_data->m_deviceCL ); + } +#endif + + } + +} + + +void b3GpuPgsContactSolver::batchContacts( b3OpenCLArray* contacts, int nContacts, b3OpenCLArray* n, b3OpenCLArray* offsets, int staticIdx ) +{ +} + + + + + + + + + + + +b3AlignedObjectArray idxBuffer; +b3AlignedObjectArray sortData; +b3AlignedObjectArray old; + + +inline int b3GpuPgsContactSolver::sortConstraintByBatch( b3Contact4* cs, int n, int simdWidth , int staticIdx, int numBodies) +{ + + B3_PROFILE("sortConstraintByBatch"); + int numIter = 0; + + sortData.resize(n); + idxBuffer.resize(n); + old.resize(n); + + unsigned int* idxSrc = &idxBuffer[0]; + unsigned int* idxDst = &idxBuffer[0]; + int nIdxSrc, nIdxDst; + + const int N_FLG = 256; + const int FLG_MASK = N_FLG-1; + unsigned int flg[N_FLG/32]; +#if defined(_DEBUG) + for(int i=0; i bodyUsed2; + +inline int b3GpuPgsContactSolver::sortConstraintByBatch2( b3Contact4* cs, int numConstraints, int simdWidth , int staticIdx, int numBodies) +{ + + B3_PROFILE("sortConstraintByBatch2"); + + + + bodyUsed2.resize(2*simdWidth); + + for (int q=0;q<2*simdWidth;q++) + bodyUsed2[q]=0; + + int curBodyUsed = 0; + + int numIter = 0; + + m_data->m_sortData.resize(numConstraints); + m_data->m_idxBuffer.resize(numConstraints); + m_data->m_old.resize(numConstraints); + + unsigned int* idxSrc = &m_data->m_idxBuffer[0]; + +#if defined(_DEBUG) + for(int i=0; im_sortData[idx].m_key = batchIdx; + m_data->m_sortData[idx].m_value = idx; + + if (i!=numValidConstraints) + { + b3Swap(idxSrc[i], idxSrc[numValidConstraints]); + } + + numValidConstraints++; + { + nCurrentBatch++; + if( nCurrentBatch == simdWidth ) + { + nCurrentBatch = 0; + for(int i=0; im_sortData.quickSort(sortfnc); + } + + { + B3_PROFILE("reorder"); + // reorder + + memcpy( &m_data->m_old[0], cs, sizeof(b3Contact4)*numConstraints); + + for(int i=0; im_sortData[idxSrc[i]].m_value == idxSrc[i]); + int idx = m_data->m_sortData[idxSrc[i]].m_value; + cs[i] = m_data->m_old[idx]; + } + } + +#if defined(_DEBUG) + // debugPrintf( "nBatches: %d\n", batchIdx ); + for(int i=0; i bodyUsed; +b3AlignedObjectArray curUsed; + + +inline int b3GpuPgsContactSolver::sortConstraintByBatch3( b3Contact4* cs, int numConstraints, int simdWidth , int staticIdx, int numBodies, int* batchSizes) +{ + + B3_PROFILE("sortConstraintByBatch3"); + + static int maxSwaps = 0; + int numSwaps = 0; + + curUsed.resize(2*simdWidth); + + static int maxNumConstraints = 0; + if (maxNumConstraintsm_sortData.resize(0); + m_data->m_idxBuffer.resize(0); + m_data->m_old.resize(0); + + +#if defined(_DEBUG) + for(int i=0; i=B3_MAX_NUM_BATCHES) + { + b3Error("batchIdx>=B3_MAX_NUM_BATCHES"); + b3Assert(0); + break; + } + + batchSizes[batchIdx] += nCurrentBatch; + + batchIdx ++; + + } + } + +#if defined(_DEBUG) + // debugPrintf( "nBatches: %d\n", batchIdx ); + for(int i=0; i* contacts, int nContacts, b3OpenCLArray* n, b3OpenCLArray* offsets, int staticIdx ); + + inline int sortConstraintByBatch( b3Contact4* cs, int n, int simdWidth , int staticIdx, int numBodies); + inline int sortConstraintByBatch2( b3Contact4* cs, int n, int simdWidth , int staticIdx, int numBodies); + inline int sortConstraintByBatch3( b3Contact4* cs, int n, int simdWidth , int staticIdx, int numBodies, int* batchSizes); + + + + void solveContactConstraintBatchSizes( const b3OpenCLArray* bodyBuf, const b3OpenCLArray* shapeBuf, + b3OpenCLArray* constraint, void* additionalData, int n ,int maxNumBatches, int numIterations, const b3AlignedObjectArray* batchSizes);//const b3OpenCLArray* gpuBatchSizes); + + void solveContactConstraint( const b3OpenCLArray* bodyBuf, const b3OpenCLArray* shapeBuf, + b3OpenCLArray* constraint, void* additionalData, int n ,int maxNumBatches, int numIterations, const b3AlignedObjectArray* batchSizes);//const b3OpenCLArray* gpuBatchSizes); + +public: + + b3GpuPgsContactSolver(cl_context ctx,cl_device_id device, cl_command_queue q,int pairCapacity); + virtual ~b3GpuPgsContactSolver(); + + void solveContacts(int numBodies, cl_mem bodyBuf, cl_mem inertiaBuf, int numContacts, cl_mem contactBuf, const struct b3Config& config, int static0Index); + +}; + +#endif //B3_GPU_BATCHING_PGS_SOLVER_H + diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.cpp b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.cpp new file mode 100644 index 000000000000..783e4430604f --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.cpp @@ -0,0 +1,708 @@ +/* +Copyright (c) 2013 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Erwin Coumans + +#include "b3GpuRigidBodyPipeline.h" +#include "b3GpuRigidBodyPipelineInternalData.h" +#include "kernels/integrateKernel.h" +#include "kernels/updateAabbsKernel.h" + +#include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h" +#include "b3GpuNarrowPhase.h" +#include "Bullet3Geometry/b3AabbUtil.h" +#include "Bullet3OpenCL/BroadphaseCollision/b3SapAabb.h" +#include "Bullet3OpenCL/BroadphaseCollision/b3GpuBroadphaseInterface.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.h" +#include "Bullet3Dynamics/ConstraintSolver/b3PgsJacobiSolver.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3UpdateAabbs.h" +#include "Bullet3Collision/BroadPhaseCollision/b3DynamicBvhBroadphase.h" + +//#define TEST_OTHER_GPU_SOLVER + +#define B3_RIGIDBODY_INTEGRATE_PATH "src/Bullet3OpenCL/RigidBody/kernels/integrateKernel.cl" +#define B3_RIGIDBODY_UPDATEAABB_PATH "src/Bullet3OpenCL/RigidBody/kernels/updateAabbsKernel.cl" + +bool useBullet2CpuSolver = true; + +//choice of contact solver +bool gUseJacobi = false; +bool gUseDbvt = false; +bool gDumpContactStats = false; +bool gCalcWorldSpaceAabbOnCpu = false; +bool gUseCalculateOverlappingPairsHost = false; +bool gIntegrateOnCpu = false; +bool gClearPairsOnGpu = true; + +#define TEST_OTHER_GPU_SOLVER 1 +#ifdef TEST_OTHER_GPU_SOLVER +#include "b3GpuJacobiContactSolver.h" +#endif //TEST_OTHER_GPU_SOLVER + +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" +#include "Bullet3Collision/NarrowPhaseCollision/b3Contact4.h" +#include "Bullet3OpenCL/RigidBody/b3GpuPgsConstraintSolver.h" + +#include "b3GpuPgsContactSolver.h" +#include "b3Solver.h" + +#include "Bullet3Collision/NarrowPhaseCollision/b3Config.h" +#include "Bullet3OpenCL/Raycast/b3GpuRaycast.h" + + +#include "Bullet3Dynamics/shared/b3IntegrateTransforms.h" +#include "Bullet3OpenCL/RigidBody/b3GpuNarrowPhaseInternalData.h" + +b3GpuRigidBodyPipeline::b3GpuRigidBodyPipeline(cl_context ctx,cl_device_id device, cl_command_queue q,class b3GpuNarrowPhase* narrowphase, class b3GpuBroadphaseInterface* broadphaseSap , struct b3DynamicBvhBroadphase* broadphaseDbvt, const b3Config& config) +{ + m_data = new b3GpuRigidBodyPipelineInternalData; + m_data->m_constraintUid=0; + m_data->m_config = config; + m_data->m_context = ctx; + m_data->m_device = device; + m_data->m_queue = q; + + m_data->m_solver = new b3PgsJacobiSolver(true);//new b3PgsJacobiSolver(true); + m_data->m_gpuSolver = new b3GpuPgsConstraintSolver(ctx,device,q,true);//new b3PgsJacobiSolver(true); + + m_data->m_allAabbsGPU = new b3OpenCLArray(ctx,q,config.m_maxConvexBodies); + m_data->m_overlappingPairsGPU = new b3OpenCLArray(ctx,q,config.m_maxBroadphasePairs); + + m_data->m_gpuConstraints = new b3OpenCLArray(ctx,q); +#ifdef TEST_OTHER_GPU_SOLVER + m_data->m_solver3 = new b3GpuJacobiContactSolver(ctx,device,q,config.m_maxBroadphasePairs); +#endif // TEST_OTHER_GPU_SOLVER + + m_data->m_solver2 = new b3GpuPgsContactSolver(ctx,device,q,config.m_maxBroadphasePairs); + + m_data->m_raycaster = new b3GpuRaycast(ctx,device,q); + + + m_data->m_broadphaseDbvt = broadphaseDbvt; + m_data->m_broadphaseSap = broadphaseSap; + m_data->m_narrowphase = narrowphase; + m_data->m_gravity.setValue(0.f,-9.8f,0.f); + + cl_int errNum=0; + + { + cl_program prog = b3OpenCLUtils::compileCLProgramFromString(m_data->m_context,m_data->m_device,integrateKernelCL,&errNum,"",B3_RIGIDBODY_INTEGRATE_PATH); + b3Assert(errNum==CL_SUCCESS); + m_data->m_integrateTransformsKernel = b3OpenCLUtils::compileCLKernelFromString(m_data->m_context, m_data->m_device,integrateKernelCL, "integrateTransformsKernel",&errNum,prog); + b3Assert(errNum==CL_SUCCESS); + clReleaseProgram(prog); + } + { + cl_program prog = b3OpenCLUtils::compileCLProgramFromString(m_data->m_context,m_data->m_device,updateAabbsKernelCL,&errNum,"",B3_RIGIDBODY_UPDATEAABB_PATH); + b3Assert(errNum==CL_SUCCESS); + m_data->m_updateAabbsKernel = b3OpenCLUtils::compileCLKernelFromString(m_data->m_context, m_data->m_device,updateAabbsKernelCL, "initializeGpuAabbsFull",&errNum,prog); + b3Assert(errNum==CL_SUCCESS); + + + m_data->m_clearOverlappingPairsKernel = b3OpenCLUtils::compileCLKernelFromString(m_data->m_context, m_data->m_device,updateAabbsKernelCL, "clearOverlappingPairsKernel",&errNum,prog); + b3Assert(errNum==CL_SUCCESS); + + clReleaseProgram(prog); + } + + +} + +b3GpuRigidBodyPipeline::~b3GpuRigidBodyPipeline() +{ + if (m_data->m_integrateTransformsKernel) + clReleaseKernel(m_data->m_integrateTransformsKernel); + + if (m_data->m_updateAabbsKernel) + clReleaseKernel(m_data->m_updateAabbsKernel); + + if (m_data->m_clearOverlappingPairsKernel) + clReleaseKernel(m_data->m_clearOverlappingPairsKernel); + delete m_data->m_raycaster; + delete m_data->m_solver; + delete m_data->m_allAabbsGPU; + delete m_data->m_gpuConstraints; + delete m_data->m_overlappingPairsGPU; + +#ifdef TEST_OTHER_GPU_SOLVER + delete m_data->m_solver3; +#endif //TEST_OTHER_GPU_SOLVER + + delete m_data->m_solver2; + + + delete m_data; +} + +void b3GpuRigidBodyPipeline::reset() +{ + m_data->m_gpuConstraints->resize(0); + m_data->m_cpuConstraints.resize(0); + m_data->m_allAabbsGPU->resize(0); + m_data->m_allAabbsCPU.resize(0); +} + +void b3GpuRigidBodyPipeline::addConstraint(b3TypedConstraint* constraint) +{ + m_data->m_joints.push_back(constraint); +} + +void b3GpuRigidBodyPipeline::removeConstraint(b3TypedConstraint* constraint) +{ + m_data->m_joints.remove(constraint); +} + + + +void b3GpuRigidBodyPipeline::removeConstraintByUid(int uid) +{ + m_data->m_gpuSolver->recomputeBatches(); + //slow linear search + m_data->m_gpuConstraints->copyToHost(m_data->m_cpuConstraints); + //remove + for (int i=0;im_cpuConstraints.size();i++) + { + if (m_data->m_cpuConstraints[i].m_uid == uid) + { + //m_data->m_cpuConstraints.remove(m_data->m_cpuConstraints[i]); + m_data->m_cpuConstraints.swap(i,m_data->m_cpuConstraints.size()-1); + m_data->m_cpuConstraints.pop_back(); + + break; + } + } + + if (m_data->m_cpuConstraints.size()) + { + m_data->m_gpuConstraints->copyFromHost(m_data->m_cpuConstraints); + } else + { + m_data->m_gpuConstraints->resize(0); + } + +} +int b3GpuRigidBodyPipeline::createPoint2PointConstraint(int bodyA, int bodyB, const float* pivotInA, const float* pivotInB,float breakingThreshold) +{ + m_data->m_gpuSolver->recomputeBatches(); + b3GpuGenericConstraint c; + c.m_uid = m_data->m_constraintUid; + m_data->m_constraintUid++; + c.m_flags = B3_CONSTRAINT_FLAG_ENABLED; + c.m_rbA = bodyA; + c.m_rbB = bodyB; + c.m_pivotInA.setValue(pivotInA[0],pivotInA[1],pivotInA[2]); + c.m_pivotInB.setValue(pivotInB[0],pivotInB[1],pivotInB[2]); + c.m_breakingImpulseThreshold = breakingThreshold; + c.m_constraintType = B3_GPU_POINT2POINT_CONSTRAINT_TYPE; + m_data->m_cpuConstraints.push_back(c); + return c.m_uid; +} +int b3GpuRigidBodyPipeline::createFixedConstraint(int bodyA, int bodyB, const float* pivotInA, const float* pivotInB, const float* relTargetAB,float breakingThreshold) +{ + m_data->m_gpuSolver->recomputeBatches(); + b3GpuGenericConstraint c; + c.m_uid = m_data->m_constraintUid; + m_data->m_constraintUid++; + c.m_flags = B3_CONSTRAINT_FLAG_ENABLED; + c.m_rbA = bodyA; + c.m_rbB = bodyB; + c.m_pivotInA.setValue(pivotInA[0],pivotInA[1],pivotInA[2]); + c.m_pivotInB.setValue(pivotInB[0],pivotInB[1],pivotInB[2]); + c.m_relTargetAB.setValue(relTargetAB[0],relTargetAB[1],relTargetAB[2],relTargetAB[3]); + c.m_breakingImpulseThreshold = breakingThreshold; + c.m_constraintType = B3_GPU_FIXED_CONSTRAINT_TYPE; + + m_data->m_cpuConstraints.push_back(c); + return c.m_uid; +} + + +void b3GpuRigidBodyPipeline::stepSimulation(float deltaTime) +{ + + //update worldspace AABBs from local AABB/worldtransform + { + B3_PROFILE("setupGpuAabbs"); + setupGpuAabbsFull(); + } + + int numPairs =0; + + //compute overlapping pairs + { + + if (gUseDbvt) + { + { + B3_PROFILE("setAabb"); + m_data->m_allAabbsGPU->copyToHost(m_data->m_allAabbsCPU); + for (int i=0;im_allAabbsCPU.size();i++) + { + b3Vector3 aabbMin=b3MakeVector3(m_data->m_allAabbsCPU[i].m_min[0],m_data->m_allAabbsCPU[i].m_min[1],m_data->m_allAabbsCPU[i].m_min[2]); + b3Vector3 aabbMax=b3MakeVector3(m_data->m_allAabbsCPU[i].m_max[0],m_data->m_allAabbsCPU[i].m_max[1],m_data->m_allAabbsCPU[i].m_max[2]); + m_data->m_broadphaseDbvt->setAabb(i,aabbMin,aabbMax,0); + } + } + + { + B3_PROFILE("calculateOverlappingPairs"); + m_data->m_broadphaseDbvt->calculateOverlappingPairs(); + } + numPairs = m_data->m_broadphaseDbvt->getOverlappingPairCache()->getNumOverlappingPairs(); + + } else + { + if (gUseCalculateOverlappingPairsHost) + { + m_data->m_broadphaseSap->calculateOverlappingPairsHost(m_data->m_config.m_maxBroadphasePairs); + } else + { + m_data->m_broadphaseSap->calculateOverlappingPairs(m_data->m_config.m_maxBroadphasePairs); + } + numPairs = m_data->m_broadphaseSap->getNumOverlap(); + } + } + + //compute contact points +// printf("numPairs=%d\n",numPairs); + + int numContacts = 0; + + + int numBodies = m_data->m_narrowphase->getNumRigidBodies(); + + if (numPairs) + { + cl_mem pairs =0; + cl_mem aabbsWS =0; + if (gUseDbvt) + { + B3_PROFILE("m_overlappingPairsGPU->copyFromHost"); + m_data->m_overlappingPairsGPU->copyFromHost(m_data->m_broadphaseDbvt->getOverlappingPairCache()->getOverlappingPairArray()); + pairs = m_data->m_overlappingPairsGPU->getBufferCL(); + aabbsWS = m_data->m_allAabbsGPU->getBufferCL(); + } else + { + pairs = m_data->m_broadphaseSap->getOverlappingPairBuffer(); + aabbsWS = m_data->m_broadphaseSap->getAabbBufferWS(); + } + + m_data->m_overlappingPairsGPU->resize(numPairs); + + //mark the contacts for each pair as 'unused' + if (numPairs) + { + b3OpenCLArray gpuPairs(this->m_data->m_context,m_data->m_queue); + gpuPairs.setFromOpenCLBuffer(pairs,numPairs); + + if (gClearPairsOnGpu) + { + + + //b3AlignedObjectArray hostPairs;//just for debugging + //gpuPairs.copyToHost(hostPairs); + + b3LauncherCL launcher(m_data->m_queue,m_data->m_clearOverlappingPairsKernel,"clearOverlappingPairsKernel"); + launcher.setBuffer(pairs); + launcher.setConst(numPairs); + launcher.launch1D(numPairs); + + + //gpuPairs.copyToHost(hostPairs); + + + } else + { + b3AlignedObjectArray hostPairs; + gpuPairs.copyToHost(hostPairs); + + for (int i=0;im_narrowphase->computeContacts(pairs,numPairs,aabbsWS,numBodies); + numContacts = m_data->m_narrowphase->getNumContactsGpu(); + + if (gUseDbvt) + { + ///store the cached information (contact locations in the 'z' component) + B3_PROFILE("m_overlappingPairsGPU->copyToHost"); + m_data->m_overlappingPairsGPU->copyToHost(m_data->m_broadphaseDbvt->getOverlappingPairCache()->getOverlappingPairArray()); + } + if (gDumpContactStats && numContacts) + { + m_data->m_narrowphase->getContactsGpu(); + + printf("numContacts = %d\n", numContacts); + + int totalPoints = 0; + const b3Contact4* contacts = m_data->m_narrowphase->getContactsCPU(); + + for (int i=0;igetNPoints(); + } + printf("totalPoints=%d\n",totalPoints); + + } + } + + + //convert contact points to contact constraints + + //solve constraints + + b3OpenCLArray gpuBodies(m_data->m_context,m_data->m_queue,0,true); + gpuBodies.setFromOpenCLBuffer(m_data->m_narrowphase->getBodiesGpu(),m_data->m_narrowphase->getNumRigidBodies()); + b3OpenCLArray gpuInertias(m_data->m_context,m_data->m_queue,0,true); + gpuInertias.setFromOpenCLBuffer(m_data->m_narrowphase->getBodyInertiasGpu(),m_data->m_narrowphase->getNumRigidBodies()); + b3OpenCLArray gpuContacts(m_data->m_context,m_data->m_queue,0,true); + gpuContacts.setFromOpenCLBuffer(m_data->m_narrowphase->getContactsGpu(),m_data->m_narrowphase->getNumContactsGpu()); + + int numJoints = m_data->m_joints.size() ? m_data->m_joints.size() : m_data->m_cpuConstraints.size(); + if (useBullet2CpuSolver && numJoints) + { + + // b3AlignedObjectArray hostContacts; + //gpuContacts.copyToHost(hostContacts); + { + bool useGpu = m_data->m_joints.size()==0; + +// b3Contact4* contacts = numContacts? &hostContacts[0]: 0; + //m_data->m_solver->solveContacts(m_data->m_narrowphase->getNumBodiesGpu(),&hostBodies[0],&hostInertias[0],numContacts,contacts,numJoints, joints); + if (useGpu) + { + m_data->m_gpuSolver->solveJoints(m_data->m_narrowphase->getNumRigidBodies(),&gpuBodies,&gpuInertias,numJoints, m_data->m_gpuConstraints); + } else + { + b3AlignedObjectArray hostBodies; + gpuBodies.copyToHost(hostBodies); + b3AlignedObjectArray hostInertias; + gpuInertias.copyToHost(hostInertias); + + b3TypedConstraint** joints = numJoints? &m_data->m_joints[0] : 0; + m_data->m_solver->solveContacts(m_data->m_narrowphase->getNumRigidBodies(),&hostBodies[0],&hostInertias[0],0,0,numJoints, joints); + gpuBodies.copyFromHost(hostBodies); + } + } + } + + if (numContacts) + { + +#ifdef TEST_OTHER_GPU_SOLVER + + if (gUseJacobi) + { + bool useGpu = true; + if (useGpu) + { + + bool forceHost = false; + if (forceHost) + { + b3AlignedObjectArray hostBodies; + b3AlignedObjectArray hostInertias; + b3AlignedObjectArray hostContacts; + + { + B3_PROFILE("copyToHost"); + gpuBodies.copyToHost(hostBodies); + gpuInertias.copyToHost(hostInertias); + gpuContacts.copyToHost(hostContacts); + } + + { + b3JacobiSolverInfo solverInfo; + m_data->m_solver3->solveGroupHost(&hostBodies[0], &hostInertias[0], hostBodies.size(),&hostContacts[0],hostContacts.size(),solverInfo); + + + } + { + B3_PROFILE("copyFromHost"); + gpuBodies.copyFromHost(hostBodies); + } + } else + + + { + int static0Index = m_data->m_narrowphase->getStatic0Index(); + b3JacobiSolverInfo solverInfo; + //m_data->m_solver3->solveContacts( >solveGroup(&gpuBodies, &gpuInertias, &gpuContacts,solverInfo); + //m_data->m_solver3->solveContacts(m_data->m_narrowphase->getNumBodiesGpu(),&hostBodies[0],&hostInertias[0],numContacts,&hostContacts[0]); + m_data->m_solver3->solveContacts(numBodies, gpuBodies.getBufferCL(),gpuInertias.getBufferCL(),numContacts, gpuContacts.getBufferCL(),m_data->m_config, static0Index); + } + } else + { + b3AlignedObjectArray hostBodies; + gpuBodies.copyToHost(hostBodies); + b3AlignedObjectArray hostInertias; + gpuInertias.copyToHost(hostInertias); + b3AlignedObjectArray hostContacts; + gpuContacts.copyToHost(hostContacts); + { + //m_data->m_solver->solveContacts(m_data->m_narrowphase->getNumBodiesGpu(),&hostBodies[0],&hostInertias[0],numContacts,&hostContacts[0]); + } + gpuBodies.copyFromHost(hostBodies); + } + + } else +#endif //TEST_OTHER_GPU_SOLVER + { + + int static0Index = m_data->m_narrowphase->getStatic0Index(); + m_data->m_solver2->solveContacts(numBodies, gpuBodies.getBufferCL(),gpuInertias.getBufferCL(),numContacts, gpuContacts.getBufferCL(),m_data->m_config, static0Index); + + //m_data->m_solver4->solveContacts(m_data->m_narrowphase->getNumBodiesGpu(), gpuBodies.getBufferCL(), gpuInertias.getBufferCL(), numContacts, gpuContacts.getBufferCL()); + + + /*m_data->m_solver3->solveContactConstraintHost( + (b3OpenCLArray*)&gpuBodies, + (b3OpenCLArray*)&gpuInertias, + (b3OpenCLArray*) &gpuContacts, + 0,numContacts,256); + */ + } + } + + integrate(deltaTime); + +} + + +void b3GpuRigidBodyPipeline::integrate(float timeStep) +{ + //integrate + int numBodies = m_data->m_narrowphase->getNumRigidBodies(); + float angularDamp = 0.99f; + + if (gIntegrateOnCpu) + { + if(numBodies) + { + b3GpuNarrowPhaseInternalData* npData = m_data->m_narrowphase->getInternalData(); + npData->m_bodyBufferGPU->copyToHost(*npData->m_bodyBufferCPU); + + b3RigidBodyData_t* bodies = &npData->m_bodyBufferCPU->at(0); + + for (int nodeID=0;nodeIDm_gravity); + } + npData->m_bodyBufferGPU->copyFromHost(*npData->m_bodyBufferCPU); + } + } else + { + b3LauncherCL launcher(m_data->m_queue,m_data->m_integrateTransformsKernel,"m_integrateTransformsKernel"); + launcher.setBuffer(m_data->m_narrowphase->getBodiesGpu()); + + launcher.setConst(numBodies); + launcher.setConst(timeStep); + launcher.setConst(angularDamp); + launcher.setConst(m_data->m_gravity); + launcher.launch1D(numBodies); + } +} + + + + +void b3GpuRigidBodyPipeline::setupGpuAabbsFull() +{ + cl_int ciErrNum=0; + + int numBodies = m_data->m_narrowphase->getNumRigidBodies(); + if (!numBodies) + return; + + if (gCalcWorldSpaceAabbOnCpu) + { + + if (numBodies) + { + if (gUseDbvt) + { + m_data->m_allAabbsCPU.resize(numBodies); + m_data->m_narrowphase->readbackAllBodiesToCpu(); + for (int i=0;im_narrowphase->getBodiesCpu(), m_data->m_narrowphase->getCollidablesCpu(), m_data->m_narrowphase->getLocalSpaceAabbsCpu(),&m_data->m_allAabbsCPU[0]); + } + m_data->m_allAabbsGPU->copyFromHost(m_data->m_allAabbsCPU); + } else + { + m_data->m_broadphaseSap->getAllAabbsCPU().resize(numBodies); + m_data->m_narrowphase->readbackAllBodiesToCpu(); + for (int i=0;im_narrowphase->getBodiesCpu(), m_data->m_narrowphase->getCollidablesCpu(), m_data->m_narrowphase->getLocalSpaceAabbsCpu(),&m_data->m_broadphaseSap->getAllAabbsCPU()[0]); + } + m_data->m_broadphaseSap->getAllAabbsGPU().copyFromHost(m_data->m_broadphaseSap->getAllAabbsCPU()); + //m_data->m_broadphaseSap->writeAabbsToGpu(); + } + } + } else + { + //__kernel void initializeGpuAabbsFull( const int numNodes, __global Body* gBodies,__global Collidable* collidables, __global b3AABBCL* plocalShapeAABB, __global b3AABBCL* pAABB) + b3LauncherCL launcher(m_data->m_queue,m_data->m_updateAabbsKernel,"m_updateAabbsKernel"); + launcher.setConst(numBodies); + cl_mem bodies = m_data->m_narrowphase->getBodiesGpu(); + launcher.setBuffer(bodies); + cl_mem collidables = m_data->m_narrowphase->getCollidablesGpu(); + launcher.setBuffer(collidables); + cl_mem localAabbs = m_data->m_narrowphase->getAabbLocalSpaceBufferGpu(); + launcher.setBuffer(localAabbs); + + cl_mem worldAabbs =0; + if (gUseDbvt) + { + worldAabbs = m_data->m_allAabbsGPU->getBufferCL(); + } else + { + worldAabbs = m_data->m_broadphaseSap->getAabbBufferWS(); + } + launcher.setBuffer(worldAabbs); + launcher.launch1D(numBodies); + + oclCHECKERROR(ciErrNum, CL_SUCCESS); + } + + /* + b3AlignedObjectArray aabbs; + m_data->m_broadphaseSap->m_allAabbsGPU.copyToHost(aabbs); + + printf("numAabbs = %d\n", aabbs.size()); + + for (int i=0;im_narrowphase->getBodiesGpu(); +} + +int b3GpuRigidBodyPipeline::getNumBodies() const +{ + return m_data->m_narrowphase->getNumRigidBodies(); +} + +void b3GpuRigidBodyPipeline::setGravity(const float* grav) +{ + m_data->m_gravity.setValue(grav[0],grav[1],grav[2]); +} + +void b3GpuRigidBodyPipeline::copyConstraintsToHost() +{ + m_data->m_gpuConstraints->copyToHost(m_data->m_cpuConstraints); +} + +void b3GpuRigidBodyPipeline::writeAllInstancesToGpu() +{ + m_data->m_allAabbsGPU->copyFromHost(m_data->m_allAabbsCPU); + m_data->m_gpuConstraints->copyFromHost(m_data->m_cpuConstraints); +} + + +int b3GpuRigidBodyPipeline::registerPhysicsInstance(float mass, const float* position, const float* orientation, int collidableIndex, int userIndex, bool writeInstanceToGpu) +{ + + b3Vector3 aabbMin=b3MakeVector3(0,0,0),aabbMax=b3MakeVector3(0,0,0); + + + if (collidableIndex>=0) + { + b3SapAabb localAabb = m_data->m_narrowphase->getLocalSpaceAabb(collidableIndex); + b3Vector3 localAabbMin=b3MakeVector3(localAabb.m_min[0],localAabb.m_min[1],localAabb.m_min[2]); + b3Vector3 localAabbMax=b3MakeVector3(localAabb.m_max[0],localAabb.m_max[1],localAabb.m_max[2]); + + b3Scalar margin = 0.01f; + b3Transform t; + t.setIdentity(); + t.setOrigin(b3MakeVector3(position[0],position[1],position[2])); + t.setRotation(b3Quaternion(orientation[0],orientation[1],orientation[2],orientation[3])); + b3TransformAabb(localAabbMin,localAabbMax, margin,t,aabbMin,aabbMax); + } else + { + b3Error("registerPhysicsInstance using invalid collidableIndex\n"); + return -1; + } + + + bool writeToGpu = false; + int bodyIndex = m_data->m_narrowphase->getNumRigidBodies(); + bodyIndex = m_data->m_narrowphase->registerRigidBody(collidableIndex,mass,position,orientation,&aabbMin.getX(),&aabbMax.getX(),writeToGpu); + + if (bodyIndex>=0) + { + if (gUseDbvt) + { + m_data->m_broadphaseDbvt->createProxy(aabbMin,aabbMax,bodyIndex,0,1,1); + b3SapAabb aabb; + for (int i=0;i<3;i++) + { + aabb.m_min[i] = aabbMin[i]; + aabb.m_max[i] = aabbMax[i]; + aabb.m_minIndices[3] = bodyIndex; + } + m_data->m_allAabbsCPU.push_back(aabb); + if (writeInstanceToGpu) + { + m_data->m_allAabbsGPU->copyFromHost(m_data->m_allAabbsCPU); + } + } else + { + if (mass) + { + m_data->m_broadphaseSap->createProxy(aabbMin,aabbMax,bodyIndex,1,1);//m_dispatcher); + } else + { + m_data->m_broadphaseSap->createLargeProxy(aabbMin,aabbMax,bodyIndex,1,1);//m_dispatcher); + } + } + } + + /* + if (mass>0.f) + m_numDynamicPhysicsInstances++; + + m_numPhysicsInstances++; + */ + + return bodyIndex; +} + +void b3GpuRigidBodyPipeline::castRays(const b3AlignedObjectArray& rays, b3AlignedObjectArray& hitResults) +{ + this->m_data->m_raycaster->castRays(rays,hitResults, + getNumBodies(),this->m_data->m_narrowphase->getBodiesCpu(), + m_data->m_narrowphase->getNumCollidablesGpu(), m_data->m_narrowphase->getCollidablesCpu(), + m_data->m_narrowphase->getInternalData(), m_data->m_broadphaseSap); +} diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.h b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.h new file mode 100644 index 000000000000..b4eac6841a11 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.h @@ -0,0 +1,74 @@ +/* +Copyright (c) 2013 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Erwin Coumans + +#ifndef B3_GPU_RIGIDBODY_PIPELINE_H +#define B3_GPU_RIGIDBODY_PIPELINE_H + +#include "Bullet3OpenCL/Initialize/b3OpenCLInclude.h" +#include "Bullet3Collision/NarrowPhaseCollision/b3Config.h" + +#include "Bullet3Common/b3AlignedObjectArray.h" +#include "Bullet3Collision/NarrowPhaseCollision/b3RaycastInfo.h" + +class b3GpuRigidBodyPipeline +{ +protected: + struct b3GpuRigidBodyPipelineInternalData* m_data; + + int allocateCollidable(); + +public: + + + b3GpuRigidBodyPipeline(cl_context ctx,cl_device_id device, cl_command_queue q , class b3GpuNarrowPhase* narrowphase, class b3GpuBroadphaseInterface* broadphaseSap, struct b3DynamicBvhBroadphase* broadphaseDbvt, const b3Config& config); + virtual ~b3GpuRigidBodyPipeline(); + + void stepSimulation(float deltaTime); + void integrate(float timeStep); + void setupGpuAabbsFull(); + + int registerConvexPolyhedron(class b3ConvexUtility* convex); + + //int registerConvexPolyhedron(const float* vertices, int strideInBytes, int numVertices, const float* scaling); + //int registerSphereShape(float radius); + //int registerPlaneShape(const b3Vector3& planeNormal, float planeConstant); + + //int registerConcaveMesh(b3AlignedObjectArray* vertices, b3AlignedObjectArray* indices, const float* scaling); + //int registerCompoundShape(b3AlignedObjectArray* childShapes); + + + int registerPhysicsInstance(float mass, const float* position, const float* orientation, int collisionShapeIndex, int userData, bool writeInstanceToGpu); + //if you passed "writeInstanceToGpu" false in the registerPhysicsInstance method (for performance) you need to call writeAllInstancesToGpu after all instances are registered + void writeAllInstancesToGpu(); + void copyConstraintsToHost(); + void setGravity(const float* grav); + void reset(); + + int createPoint2PointConstraint(int bodyA, int bodyB, const float* pivotInA, const float* pivotInB,float breakingThreshold); + int createFixedConstraint(int bodyA, int bodyB, const float* pivotInA, const float* pivotInB, const float* relTargetAB, float breakingThreshold); + void removeConstraintByUid(int uid); + + void addConstraint(class b3TypedConstraint* constraint); + void removeConstraint(b3TypedConstraint* constraint); + + void castRays(const b3AlignedObjectArray& rays, b3AlignedObjectArray& hitResults); + + cl_mem getBodyBuffer(); + + int getNumBodies() const; + +}; + +#endif //B3_GPU_RIGIDBODY_PIPELINE_H \ No newline at end of file diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipelineInternalData.h b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipelineInternalData.h new file mode 100644 index 000000000000..5ac92f97d612 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipelineInternalData.h @@ -0,0 +1,73 @@ +/* +Copyright (c) 2013 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Erwin Coumans + +#ifndef B3_GPU_RIGIDBODY_PIPELINE_INTERNAL_DATA_H +#define B3_GPU_RIGIDBODY_PIPELINE_INTERNAL_DATA_H + +#include "Bullet3OpenCL/Initialize/b3OpenCLInclude.h" +#include "Bullet3Common/b3AlignedObjectArray.h" + +#include "Bullet3OpenCL/ParallelPrimitives/b3OpenCLArray.h" +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3Collidable.h" + + +#include "Bullet3OpenCL/BroadphaseCollision/b3SapAabb.h" +#include "Bullet3Dynamics/ConstraintSolver/b3TypedConstraint.h" +#include "Bullet3Collision/NarrowPhaseCollision/b3Config.h" + + + +#include "Bullet3Collision/BroadPhaseCollision/b3OverlappingPair.h" +#include "Bullet3OpenCL/RigidBody/b3GpuGenericConstraint.h" + +struct b3GpuRigidBodyPipelineInternalData +{ + + cl_context m_context; + cl_device_id m_device; + cl_command_queue m_queue; + + cl_kernel m_integrateTransformsKernel; + cl_kernel m_updateAabbsKernel; + cl_kernel m_clearOverlappingPairsKernel; + + class b3PgsJacobiSolver* m_solver; + + class b3GpuPgsConstraintSolver* m_gpuSolver; + + class b3GpuPgsContactSolver* m_solver2; + class b3GpuJacobiContactSolver* m_solver3; + class b3GpuRaycast* m_raycaster; + + class b3GpuBroadphaseInterface* m_broadphaseSap; + + struct b3DynamicBvhBroadphase* m_broadphaseDbvt; + b3OpenCLArray* m_allAabbsGPU; + b3AlignedObjectArray m_allAabbsCPU; + b3OpenCLArray* m_overlappingPairsGPU; + + b3OpenCLArray* m_gpuConstraints; + b3AlignedObjectArray m_cpuConstraints; + + b3AlignedObjectArray m_joints; + int m_constraintUid; + class b3GpuNarrowPhase* m_narrowphase; + b3Vector3 m_gravity; + + b3Config m_config; +}; + +#endif //B3_GPU_RIGIDBODY_PIPELINE_INTERNAL_DATA_H + diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuSolverBody.h b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuSolverBody.h new file mode 100644 index 000000000000..f2a61801ac9a --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuSolverBody.h @@ -0,0 +1,228 @@ +/* +Copyright (c) 2013 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Erwin Coumans + + +#ifndef B3_GPU_SOLVER_BODY_H +#define B3_GPU_SOLVER_BODY_H + + +#include "Bullet3Common/b3Vector3.h" +#include "Bullet3Common/b3Matrix3x3.h" + +#include "Bullet3Common/b3AlignedAllocator.h" +#include "Bullet3Common/b3TransformUtil.h" + +///Until we get other contributions, only use SIMD on Windows, when using Visual Studio 2008 or later, and not double precision +#ifdef B3_USE_SSE +#define USE_SIMD 1 +#endif // + + + +///The b3SolverBody is an internal datastructure for the constraint solver. Only necessary data is packed to increase cache coherence/performance. +B3_ATTRIBUTE_ALIGNED16 (struct) b3GpuSolverBody +{ + B3_DECLARE_ALIGNED_ALLOCATOR(); +// b3Transform m_worldTransformUnused; + b3Vector3 m_deltaLinearVelocity; + b3Vector3 m_deltaAngularVelocity; + b3Vector3 m_angularFactor; + b3Vector3 m_linearFactor; + b3Vector3 m_invMass; + b3Vector3 m_pushVelocity; + b3Vector3 m_turnVelocity; + b3Vector3 m_linearVelocity; + b3Vector3 m_angularVelocity; + + union + { + void* m_originalBody; + int m_originalBodyIndex; + }; + + int padding[3]; + + /* + void setWorldTransform(const b3Transform& worldTransform) + { + m_worldTransform = worldTransform; + } + + const b3Transform& getWorldTransform() const + { + return m_worldTransform; + } + */ + B3_FORCE_INLINE void getVelocityInLocalPointObsolete(const b3Vector3& rel_pos, b3Vector3& velocity ) const + { + if (m_originalBody) + velocity = m_linearVelocity+m_deltaLinearVelocity + (m_angularVelocity+m_deltaAngularVelocity).cross(rel_pos); + else + velocity.setValue(0,0,0); + } + + B3_FORCE_INLINE void getAngularVelocity(b3Vector3& angVel) const + { + if (m_originalBody) + angVel =m_angularVelocity+m_deltaAngularVelocity; + else + angVel.setValue(0,0,0); + } + + + //Optimization for the iterative solver: avoid calculating constant terms involving inertia, normal, relative position + B3_FORCE_INLINE void applyImpulse(const b3Vector3& linearComponent, const b3Vector3& angularComponent,const b3Scalar impulseMagnitude) + { + if (m_originalBody) + { + m_deltaLinearVelocity += linearComponent*impulseMagnitude*m_linearFactor; + m_deltaAngularVelocity += angularComponent*(impulseMagnitude*m_angularFactor); + } + } + + B3_FORCE_INLINE void internalApplyPushImpulse(const b3Vector3& linearComponent, const b3Vector3& angularComponent,b3Scalar impulseMagnitude) + { + if (m_originalBody) + { + m_pushVelocity += linearComponent*impulseMagnitude*m_linearFactor; + m_turnVelocity += angularComponent*(impulseMagnitude*m_angularFactor); + } + } + + + + const b3Vector3& getDeltaLinearVelocity() const + { + return m_deltaLinearVelocity; + } + + const b3Vector3& getDeltaAngularVelocity() const + { + return m_deltaAngularVelocity; + } + + const b3Vector3& getPushVelocity() const + { + return m_pushVelocity; + } + + const b3Vector3& getTurnVelocity() const + { + return m_turnVelocity; + } + + + //////////////////////////////////////////////// + ///some internal methods, don't use them + + b3Vector3& internalGetDeltaLinearVelocity() + { + return m_deltaLinearVelocity; + } + + b3Vector3& internalGetDeltaAngularVelocity() + { + return m_deltaAngularVelocity; + } + + const b3Vector3& internalGetAngularFactor() const + { + return m_angularFactor; + } + + const b3Vector3& internalGetInvMass() const + { + return m_invMass; + } + + void internalSetInvMass(const b3Vector3& invMass) + { + m_invMass = invMass; + } + + b3Vector3& internalGetPushVelocity() + { + return m_pushVelocity; + } + + b3Vector3& internalGetTurnVelocity() + { + return m_turnVelocity; + } + + B3_FORCE_INLINE void internalGetVelocityInLocalPointObsolete(const b3Vector3& rel_pos, b3Vector3& velocity ) const + { + velocity = m_linearVelocity+m_deltaLinearVelocity + (m_angularVelocity+m_deltaAngularVelocity).cross(rel_pos); + } + + B3_FORCE_INLINE void internalGetAngularVelocity(b3Vector3& angVel) const + { + angVel = m_angularVelocity+m_deltaAngularVelocity; + } + + + //Optimization for the iterative solver: avoid calculating constant terms involving inertia, normal, relative position + B3_FORCE_INLINE void internalApplyImpulse(const b3Vector3& linearComponent, const b3Vector3& angularComponent,const b3Scalar impulseMagnitude) + { + //if (m_originalBody) + { + m_deltaLinearVelocity += linearComponent*impulseMagnitude*m_linearFactor; + m_deltaAngularVelocity += angularComponent*(impulseMagnitude*m_angularFactor); + } + } + + + + + void writebackVelocity() + { + //if (m_originalBody>=0) + { + m_linearVelocity +=m_deltaLinearVelocity; + m_angularVelocity += m_deltaAngularVelocity; + + //m_originalBody->setCompanionId(-1); + } + } + + + void writebackVelocityAndTransform(b3Scalar timeStep, b3Scalar splitImpulseTurnErp) + { + (void) timeStep; + if (m_originalBody) + { + m_linearVelocity += m_deltaLinearVelocity; + m_angularVelocity += m_deltaAngularVelocity; + + //correct the position/orientation based on push/turn recovery + b3Transform newTransform; + if (m_pushVelocity[0]!=0.f || m_pushVelocity[1]!=0 || m_pushVelocity[2]!=0 || m_turnVelocity[0]!=0.f || m_turnVelocity[1]!=0 || m_turnVelocity[2]!=0) + { + // b3Quaternion orn = m_worldTransform.getRotation(); +// b3TransformUtil::integrateTransform(m_worldTransform,m_pushVelocity,m_turnVelocity*splitImpulseTurnErp,timeStep,newTransform); +// m_worldTransform = newTransform; + } + //m_worldTransform.setRotation(orn); + //m_originalBody->setCompanionId(-1); + } + } + + + +}; + +#endif //B3_SOLVER_BODY_H + + diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuSolverConstraint.h b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuSolverConstraint.h new file mode 100644 index 000000000000..60d235baab04 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3GpuSolverConstraint.h @@ -0,0 +1,82 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2013 Erwin Coumans http://github.com/erwincoumans/bullet3 + +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 B3_GPU_SOLVER_CONSTRAINT_H +#define B3_GPU_SOLVER_CONSTRAINT_H + + +#include "Bullet3Common/b3Vector3.h" +#include "Bullet3Common/b3Matrix3x3.h" +//#include "b3JacobianEntry.h" +#include "Bullet3Common/b3AlignedObjectArray.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. +B3_ATTRIBUTE_ALIGNED16 (struct) b3GpuSolverConstraint +{ + B3_DECLARE_ALIGNED_ALLOCATOR(); + + b3Vector3 m_relpos1CrossNormal; + b3Vector3 m_contactNormal; + + b3Vector3 m_relpos2CrossNormal; + //b3Vector3 m_contactNormal2;//usually m_contactNormal2 == -m_contactNormal + + b3Vector3 m_angularComponentA; + b3Vector3 m_angularComponentB; + + mutable b3Scalar m_appliedPushImpulse; + mutable b3Scalar m_appliedImpulse; + int m_padding1; + int m_padding2; + b3Scalar m_friction; + b3Scalar m_jacDiagABInv; + b3Scalar m_rhs; + b3Scalar m_cfm; + + b3Scalar m_lowerLimit; + b3Scalar m_upperLimit; + b3Scalar m_rhsPenetration; + union + { + void* m_originalContactPoint; + int m_originalConstraintIndex; + b3Scalar m_unusedPadding4; + }; + + int m_overrideNumSolverIterations; + int m_frictionIndex; + int m_solverBodyIdA; + int m_solverBodyIdB; + + + enum b3SolverConstraintType + { + B3_SOLVER_CONTACT_1D = 0, + B3_SOLVER_FRICTION_1D + }; +}; + +typedef b3AlignedObjectArray b3GpuConstraintArray; + + +#endif //B3_GPU_SOLVER_CONSTRAINT_H + + + diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/b3Solver.cpp b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3Solver.cpp new file mode 100644 index 000000000000..20bf6d47c5ef --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3Solver.cpp @@ -0,0 +1,1225 @@ +/* +Copyright (c) 2012 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Takahiro Harada + + +#include "b3Solver.h" + +///useNewBatchingKernel is a rewritten kernel using just a single thread of the warp, for experiments +bool useNewBatchingKernel = true; +bool gConvertConstraintOnCpu = false; + +#define B3_SOLVER_SETUP_KERNEL_PATH "src/Bullet3OpenCL/RigidBody/kernels/solverSetup.cl" +#define B3_SOLVER_SETUP2_KERNEL_PATH "src/Bullet3OpenCL/RigidBody/kernels/solverSetup2.cl" +#define B3_SOLVER_CONTACT_KERNEL_PATH "src/Bullet3OpenCL/RigidBody/kernels/solveContact.cl" +#define B3_SOLVER_FRICTION_KERNEL_PATH "src/Bullet3OpenCL/RigidBody/kernels/solveFriction.cl" +#define B3_BATCHING_PATH "src/Bullet3OpenCL/RigidBody/kernels/batchingKernels.cl" +#define B3_BATCHING_NEW_PATH "src/Bullet3OpenCL/RigidBody/kernels/batchingKernelsNew.cl" + +#include "Bullet3Dynamics/shared/b3ConvertConstraint4.h" + +#include "kernels/solverSetup.h" +#include "kernels/solverSetup2.h" + +#include "kernels/solveContact.h" +#include "kernels/solveFriction.h" + +#include "kernels/batchingKernels.h" +#include "kernels/batchingKernelsNew.h" + + +#include "Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.h" +#include "Bullet3Common/b3Vector3.h" + +struct SolverDebugInfo +{ + int m_valInt0; + int m_valInt1; + int m_valInt2; + int m_valInt3; + + int m_valInt4; + int m_valInt5; + int m_valInt6; + int m_valInt7; + + int m_valInt8; + int m_valInt9; + int m_valInt10; + int m_valInt11; + + int m_valInt12; + int m_valInt13; + int m_valInt14; + int m_valInt15; + + + float m_val0; + float m_val1; + float m_val2; + float m_val3; +}; + + + + +class SolverDeviceInl +{ +public: + struct ParallelSolveData + { + b3OpenCLArray* m_numConstraints; + b3OpenCLArray* m_offsets; + }; +}; + + + +b3Solver::b3Solver(cl_context ctx, cl_device_id device, cl_command_queue queue, int pairCapacity) + : + m_context(ctx), + m_device(device), + m_queue(queue), + m_batchSizes(ctx,queue), + m_nIterations(4) +{ + m_sort32 = new b3RadixSort32CL(ctx,device,queue); + m_scan = new b3PrefixScanCL(ctx,device,queue,B3_SOLVER_N_CELLS); + m_search = new b3BoundSearchCL(ctx,device,queue,B3_SOLVER_N_CELLS); + + const int sortSize = B3NEXTMULTIPLEOF( pairCapacity, 512 ); + + m_sortDataBuffer = new b3OpenCLArray(ctx,queue,sortSize); + m_contactBuffer2 = new b3OpenCLArray(ctx,queue); + + m_numConstraints = new b3OpenCLArray(ctx,queue,B3_SOLVER_N_CELLS ); + m_numConstraints->resize(B3_SOLVER_N_CELLS); + + m_offsets = new b3OpenCLArray( ctx,queue,B3_SOLVER_N_CELLS); + m_offsets->resize(B3_SOLVER_N_CELLS); + const char* additionalMacros = ""; +// const char* srcFileNameForCaching=""; + + + + cl_int pErrNum; + const char* batchKernelSource = batchingKernelsCL; + const char* batchKernelNewSource = batchingKernelsNewCL; + + const char* solverSetupSource = solverSetupCL; + const char* solverSetup2Source = solverSetup2CL; + const char* solveContactSource = solveContactCL; + const char* solveFrictionSource = solveFrictionCL; + + + + { + + cl_program solveContactProg= b3OpenCLUtils::compileCLProgramFromString( ctx, device, solveContactSource, &pErrNum,additionalMacros, B3_SOLVER_CONTACT_KERNEL_PATH); + b3Assert(solveContactProg); + + cl_program solveFrictionProg= b3OpenCLUtils::compileCLProgramFromString( ctx, device, solveFrictionSource, &pErrNum,additionalMacros, B3_SOLVER_FRICTION_KERNEL_PATH); + b3Assert(solveFrictionProg); + + cl_program solverSetup2Prog= b3OpenCLUtils::compileCLProgramFromString( ctx, device, solverSetup2Source, &pErrNum,additionalMacros, B3_SOLVER_SETUP2_KERNEL_PATH); + b3Assert(solverSetup2Prog); + + + cl_program solverSetupProg= b3OpenCLUtils::compileCLProgramFromString( ctx, device, solverSetupSource, &pErrNum,additionalMacros, B3_SOLVER_SETUP_KERNEL_PATH); + b3Assert(solverSetupProg); + + + m_solveFrictionKernel= b3OpenCLUtils::compileCLKernelFromString( ctx, device, solveFrictionSource, "BatchSolveKernelFriction", &pErrNum, solveFrictionProg,additionalMacros ); + b3Assert(m_solveFrictionKernel); + + m_solveContactKernel= b3OpenCLUtils::compileCLKernelFromString( ctx, device, solveContactSource, "BatchSolveKernelContact", &pErrNum, solveContactProg,additionalMacros ); + b3Assert(m_solveContactKernel); + + m_contactToConstraintKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverSetupSource, "ContactToConstraintKernel", &pErrNum, solverSetupProg,additionalMacros ); + b3Assert(m_contactToConstraintKernel); + + m_setSortDataKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverSetup2Source, "SetSortDataKernel", &pErrNum, solverSetup2Prog,additionalMacros ); + b3Assert(m_setSortDataKernel); + + m_reorderContactKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverSetup2Source, "ReorderContactKernel", &pErrNum, solverSetup2Prog,additionalMacros ); + b3Assert(m_reorderContactKernel); + + + m_copyConstraintKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, solverSetup2Source, "CopyConstraintKernel", &pErrNum, solverSetup2Prog,additionalMacros ); + b3Assert(m_copyConstraintKernel); + + } + + { + cl_program batchingProg = b3OpenCLUtils::compileCLProgramFromString( ctx, device, batchKernelSource, &pErrNum,additionalMacros, B3_BATCHING_PATH); + //cl_program batchingProg = b3OpenCLUtils::compileCLProgramFromString( ctx, device, 0, &pErrNum,additionalMacros, B3_BATCHING_PATH,true); + b3Assert(batchingProg); + + m_batchingKernel = b3OpenCLUtils::compileCLKernelFromString( ctx, device, batchKernelSource, "CreateBatches", &pErrNum, batchingProg,additionalMacros ); + b3Assert(m_batchingKernel); + } + { + cl_program batchingNewProg = b3OpenCLUtils::compileCLProgramFromString( ctx, device, batchKernelNewSource, &pErrNum,additionalMacros, B3_BATCHING_NEW_PATH); + b3Assert(batchingNewProg); + + m_batchingKernelNew = b3OpenCLUtils::compileCLKernelFromString( ctx, device, batchKernelNewSource, "CreateBatchesNew", &pErrNum, batchingNewProg,additionalMacros ); + //m_batchingKernelNew = b3OpenCLUtils::compileCLKernelFromString( ctx, device, batchKernelNewSource, "CreateBatchesBruteForce", &pErrNum, batchingNewProg,additionalMacros ); + b3Assert(m_batchingKernelNew); + } +} + +b3Solver::~b3Solver() +{ + delete m_offsets; + delete m_numConstraints; + delete m_sortDataBuffer; + delete m_contactBuffer2; + + delete m_sort32; + delete m_scan; + delete m_search; + + + clReleaseKernel(m_batchingKernel); + clReleaseKernel(m_batchingKernelNew); + + clReleaseKernel( m_solveContactKernel); + clReleaseKernel( m_solveFrictionKernel); + + clReleaseKernel( m_contactToConstraintKernel); + clReleaseKernel( m_setSortDataKernel); + clReleaseKernel( m_reorderContactKernel); + clReleaseKernel( m_copyConstraintKernel); + +} + + + + +template +static +__inline +void solveContact(b3GpuConstraint4& cs, + const b3Vector3& posA, b3Vector3& linVelA, b3Vector3& angVelA, float invMassA, const b3Matrix3x3& invInertiaA, + const b3Vector3& posB, b3Vector3& linVelB, b3Vector3& angVelB, float invMassB, const b3Matrix3x3& invInertiaB, + float maxRambdaDt[4], float minRambdaDt[4]) +{ + + b3Vector3 dLinVelA; dLinVelA.setZero(); + b3Vector3 dAngVelA; dAngVelA.setZero(); + b3Vector3 dLinVelB; dLinVelB.setZero(); + b3Vector3 dAngVelB; dAngVelB.setZero(); + + for(int ic=0; ic<4; ic++) + { + // dont necessary because this makes change to 0 + if( cs.m_jacCoeffInv[ic] == 0.f ) continue; + + { + b3Vector3 angular0, angular1, linear; + b3Vector3 r0 = cs.m_worldPos[ic] - (b3Vector3&)posA; + b3Vector3 r1 = cs.m_worldPos[ic] - (b3Vector3&)posB; + setLinearAndAngular( (const b3Vector3 &)cs.m_linear, (const b3Vector3 &)r0, (const b3Vector3 &)r1, &linear, &angular0, &angular1 ); + + float rambdaDt = calcRelVel((const b3Vector3 &)cs.m_linear,(const b3Vector3 &) -cs.m_linear, angular0, angular1, + linVelA, angVelA, linVelB, angVelB ) + cs.m_b[ic]; + rambdaDt *= cs.m_jacCoeffInv[ic]; + + { + float prevSum = cs.m_appliedRambdaDt[ic]; + float updated = prevSum; + updated += rambdaDt; + updated = b3Max( updated, minRambdaDt[ic] ); + updated = b3Min( updated, maxRambdaDt[ic] ); + rambdaDt = updated - prevSum; + cs.m_appliedRambdaDt[ic] = updated; + } + + b3Vector3 linImp0 = invMassA*linear*rambdaDt; + b3Vector3 linImp1 = invMassB*(-linear)*rambdaDt; + b3Vector3 angImp0 = (invInertiaA* angular0)*rambdaDt; + b3Vector3 angImp1 = (invInertiaB* angular1)*rambdaDt; +#ifdef _WIN32 + b3Assert(_finite(linImp0.getX())); + b3Assert(_finite(linImp1.getX())); +#endif + if( JACOBI ) + { + dLinVelA += linImp0; + dAngVelA += angImp0; + dLinVelB += linImp1; + dAngVelB += angImp1; + } + else + { + linVelA += linImp0; + angVelA += angImp0; + linVelB += linImp1; + angVelB += angImp1; + } + } + } + + if( JACOBI ) + { + linVelA += dLinVelA; + angVelA += dAngVelA; + linVelB += dLinVelB; + angVelB += dAngVelB; + } + +} + + + + + + static + __inline + void solveFriction(b3GpuConstraint4& cs, + const b3Vector3& posA, b3Vector3& linVelA, b3Vector3& angVelA, float invMassA, const b3Matrix3x3& invInertiaA, + const b3Vector3& posB, b3Vector3& linVelB, b3Vector3& angVelB, float invMassB, const b3Matrix3x3& invInertiaB, + float maxRambdaDt[4], float minRambdaDt[4]) + { + + if( cs.m_fJacCoeffInv[0] == 0 && cs.m_fJacCoeffInv[0] == 0 ) return; + const b3Vector3& center = (const b3Vector3&)cs.m_center; + + b3Vector3 n = -(const b3Vector3&)cs.m_linear; + + b3Vector3 tangent[2]; +#if 1 + b3PlaneSpace1 (n, tangent[0],tangent[1]); +#else + b3Vector3 r = cs.m_worldPos[0]-center; + tangent[0] = cross3( n, r ); + tangent[1] = cross3( tangent[0], n ); + tangent[0] = normalize3( tangent[0] ); + tangent[1] = normalize3( tangent[1] ); +#endif + + b3Vector3 angular0, angular1, linear; + b3Vector3 r0 = center - posA; + b3Vector3 r1 = center - posB; + for(int i=0; i<2; i++) + { + setLinearAndAngular( tangent[i], r0, r1, &linear, &angular0, &angular1 ); + float rambdaDt = calcRelVel(linear, -linear, angular0, angular1, + linVelA, angVelA, linVelB, angVelB ); + rambdaDt *= cs.m_fJacCoeffInv[i]; + + { + float prevSum = cs.m_fAppliedRambdaDt[i]; + float updated = prevSum; + updated += rambdaDt; + updated = b3Max( updated, minRambdaDt[i] ); + updated = b3Min( updated, maxRambdaDt[i] ); + rambdaDt = updated - prevSum; + cs.m_fAppliedRambdaDt[i] = updated; + } + + b3Vector3 linImp0 = invMassA*linear*rambdaDt; + b3Vector3 linImp1 = invMassB*(-linear)*rambdaDt; + b3Vector3 angImp0 = (invInertiaA* angular0)*rambdaDt; + b3Vector3 angImp1 = (invInertiaB* angular1)*rambdaDt; +#ifdef _WIN32 + b3Assert(_finite(linImp0.getX())); + b3Assert(_finite(linImp1.getX())); +#endif + linVelA += linImp0; + angVelA += angImp0; + linVelB += linImp1; + angVelB += angImp1; + } + + { // angular damping for point constraint + b3Vector3 ab = ( posB - posA ).normalized(); + b3Vector3 ac = ( center - posA ).normalized(); + if( b3Dot( ab, ac ) > 0.95f || (invMassA == 0.f || invMassB == 0.f)) + { + float angNA = b3Dot( n, angVelA ); + float angNB = b3Dot( n, angVelB ); + + angVelA -= (angNA*0.1f)*n; + angVelB -= (angNB*0.1f)*n; + } + } + + } +/* + b3AlignedObjectArray& m_bodies; + b3AlignedObjectArray& m_shapes; + b3AlignedObjectArray& m_constraints; + b3AlignedObjectArray* m_batchSizes; + int m_cellIndex; + int m_curWgidx; + int m_start; + int m_nConstraints; + bool m_solveFriction; + int m_maxNumBatches; + */ + +struct SolveTask// : public ThreadPool::Task +{ + SolveTask(b3AlignedObjectArray& bodies, b3AlignedObjectArray& shapes, b3AlignedObjectArray& constraints, + int start, int nConstraints,int maxNumBatches,b3AlignedObjectArray* wgUsedBodies, int curWgidx, b3AlignedObjectArray* batchSizes, int cellIndex) + : m_bodies( bodies ), m_shapes( shapes ), + m_constraints( constraints ), + m_batchSizes(batchSizes), + m_cellIndex(cellIndex), + m_curWgidx(curWgidx), + m_start( start ), + m_nConstraints( nConstraints ), + m_solveFriction( true ), + m_maxNumBatches(maxNumBatches) + {} + + unsigned short int getType(){ return 0; } + + void run(int tIdx) + { + int offset = 0; + for (int ii=0;iiat(m_cellIndex*B3_MAX_NUM_BATCHES+ii); + if (!numInBatch) + break; + + for (int jj=0;jj( m_constraints[i], (b3Vector3&)bodyA.m_pos, (b3Vector3&)bodyA.m_linVel, (b3Vector3&)bodyA.m_angVel, bodyA.m_invMass, (const b3Matrix3x3 &)m_shapes[aIdx].m_invInertiaWorld, + (b3Vector3&)bodyB.m_pos, (b3Vector3&)bodyB.m_linVel, (b3Vector3&)bodyB.m_angVel, bodyB.m_invMass, (const b3Matrix3x3 &)m_shapes[bIdx].m_invInertiaWorld, + maxRambdaDt, minRambdaDt ); + } + else + { + float maxRambdaDt[4] = {FLT_MAX,FLT_MAX,FLT_MAX,FLT_MAX}; + float minRambdaDt[4] = {0.f,0.f,0.f,0.f}; + float sum = 0; + for(int j=0; j<4; j++) + { + sum +=m_constraints[i].m_appliedRambdaDt[j]; + } + frictionCoeff = 0.7f; + for(int j=0; j<4; j++) + { + maxRambdaDt[j] = frictionCoeff*sum; + minRambdaDt[j] = -maxRambdaDt[j]; + } + solveFriction( m_constraints[i], (b3Vector3&)bodyA.m_pos, (b3Vector3&)bodyA.m_linVel, (b3Vector3&)bodyA.m_angVel, bodyA.m_invMass,(const b3Matrix3x3 &) m_shapes[aIdx].m_invInertiaWorld, + (b3Vector3&)bodyB.m_pos, (b3Vector3&)bodyB.m_linVel, (b3Vector3&)bodyB.m_angVel, bodyB.m_invMass,(const b3Matrix3x3 &) m_shapes[bIdx].m_invInertiaWorld, + maxRambdaDt, minRambdaDt ); + + } + } + offset+=numInBatch; + + + } +/* for (int bb=0;bb=0; ic--) + for(int ic=0; ic( m_constraints[i], (b3Vector3&)bodyA.m_pos, (b3Vector3&)bodyA.m_linVel, (b3Vector3&)bodyA.m_angVel, bodyA.m_invMass, (const b3Matrix3x3 &)m_shapes[aIdx].m_invInertiaWorld, + (b3Vector3&)bodyB.m_pos, (b3Vector3&)bodyB.m_linVel, (b3Vector3&)bodyB.m_angVel, bodyB.m_invMass, (const b3Matrix3x3 &)m_shapes[bIdx].m_invInertiaWorld, + maxRambdaDt, minRambdaDt ); + } + else + { + float maxRambdaDt[4] = {FLT_MAX,FLT_MAX,FLT_MAX,FLT_MAX}; + float minRambdaDt[4] = {0.f,0.f,0.f,0.f}; + float sum = 0; + for(int j=0; j<4; j++) + { + sum +=m_constraints[i].m_appliedRambdaDt[j]; + } + frictionCoeff = 0.7f; + for(int j=0; j<4; j++) + { + maxRambdaDt[j] = frictionCoeff*sum; + minRambdaDt[j] = -maxRambdaDt[j]; + } + solveFriction( m_constraints[i], (b3Vector3&)bodyA.m_pos, (b3Vector3&)bodyA.m_linVel, (b3Vector3&)bodyA.m_angVel, bodyA.m_invMass,(const b3Matrix3x3 &) m_shapes[aIdx].m_invInertiaWorld, + (b3Vector3&)bodyB.m_pos, (b3Vector3&)bodyB.m_linVel, (b3Vector3&)bodyB.m_angVel, bodyB.m_invMass,(const b3Matrix3x3 &) m_shapes[bIdx].m_invInertiaWorld, + maxRambdaDt, minRambdaDt ); + + } + } + } + */ + + + + } + + b3AlignedObjectArray& m_bodies; + b3AlignedObjectArray& m_shapes; + b3AlignedObjectArray& m_constraints; + b3AlignedObjectArray* m_batchSizes; + int m_cellIndex; + int m_curWgidx; + int m_start; + int m_nConstraints; + bool m_solveFriction; + int m_maxNumBatches; +}; + + +void b3Solver::solveContactConstraintHost( b3OpenCLArray* bodyBuf, b3OpenCLArray* shapeBuf, + b3OpenCLArray* constraint, void* additionalData, int n ,int maxNumBatches,b3AlignedObjectArray* batchSizes) +{ + +#if 0 + { + int nSplitX = B3_SOLVER_N_SPLIT_X; + int nSplitY = B3_SOLVER_N_SPLIT_Y; + int numWorkgroups = B3_SOLVER_N_CELLS/B3_SOLVER_N_BATCHES; + for (int z=0;z<4;z++) + { + for (int y=0;y<4;y++) + { + for (int x=0;x<4;x++) + { + int newIndex = (x+y*nSplitX+z*nSplitX*nSplitY); + // printf("newIndex=%d\n",newIndex); + + int zIdx = newIndex/(nSplitX*nSplitY); + int remain = newIndex%(nSplitX*nSplitY); + int yIdx = remain/nSplitX; + int xIdx = remain%nSplitX; + // printf("newIndex=%d\n",newIndex); + } + } + } + + //for (int wgIdx=numWorkgroups-1;wgIdx>=0;wgIdx--) + for (int cellBatch=0;cellBatch>2); + int remain= (wgIdx%((nSplitX*nSplitY)/4)); + int yIdx = (remain/(nSplitX/2))*2 + ((cellBatch&2)>>1); + int xIdx = (remain%(nSplitX/2))*2 + (cellBatch&1); + + /*int zIdx = newIndex/(nSplitX*nSplitY); + int remain = newIndex%(nSplitX*nSplitY); + int yIdx = remain/nSplitX; + int xIdx = remain%nSplitX; + */ + int cellIdx = xIdx+yIdx*nSplitX+zIdx*(nSplitX*nSplitY); + // printf("wgIdx %d: xIdx=%d, yIdx=%d, zIdx=%d, cellIdx=%d, cell Batch %d\n",wgIdx,xIdx,yIdx,zIdx,cellIdx,cellBatch); + } + } + } +#endif + + b3AlignedObjectArray bodyNative; + bodyBuf->copyToHost(bodyNative); + b3AlignedObjectArray shapeNative; + shapeBuf->copyToHost(shapeNative); + b3AlignedObjectArray constraintNative; + constraint->copyToHost(constraintNative); + + b3AlignedObjectArray numConstraintsHost; + m_numConstraints->copyToHost(numConstraintsHost); + + //printf("------------------------\n"); + b3AlignedObjectArray offsetsHost; + m_offsets->copyToHost(offsetsHost); + static int frame=0; + bool useBatches=true; + if (useBatches) + { + for(int iter=0; iter usedBodies[B3_SOLVER_N_CELLS]; + for (int i=0;i=0;wgIdx--) + for (int wgIdx=0;wgIdx>2); + int remain= (wgIdx%((nSplitX*nSplitY)/4)); + int yIdx = (remain/(nSplitX/2))*2 + ((cellBatch&2)>>1); + int xIdx = (remain%(nSplitX/2))*2 + (cellBatch&1); + int cellIdx = xIdx+yIdx*nSplitX+zIdx*(nSplitX*nSplitY); + + + if( numConstraintsHost[cellIdx] == 0 ) + continue; + + //printf("wgIdx %d: xIdx=%d, yIdx=%d, zIdx=%d, cellIdx=%d, cell Batch %d\n",wgIdx,xIdx,yIdx,zIdx,cellIdx,cellBatch); + //printf("cell %d has %d constraints\n", cellIdx,numConstraintsHost[cellIdx]); + if (zIdx) + { + //printf("?\n"); + } + + if (iter==0) + { + //printf("frame=%d, Cell xIdx=%x, yIdx=%d ",frame, xIdx,yIdx); + //printf("cellBatch=%d, wgIdx=%d, #constraints in cell=%d\n",cellBatch,wgIdx,numConstraintsHost[cellIdx]); + } + const int start = offsetsHost[cellIdx]; + int numConstraintsInCell = numConstraintsHost[cellIdx]; + // const int end = start + numConstraintsInCell; + + SolveTask task( bodyNative, shapeNative, constraintNative, start, numConstraintsInCell ,maxNumBatches,usedBodies,wgIdx,batchSizes,cellIdx); + task.m_solveFriction = false; + task.run(0); + + } + } + } + + for(int iter=0; iter>2); + int remain= (wgIdx%((nSplitX*nSplitY)/4)); + int yIdx = (remain/(nSplitX/2))*2 + ((cellBatch&2)>>1); + int xIdx = (remain%(nSplitX/2))*2 + (cellBatch&1); + + int cellIdx = xIdx+yIdx*nSplitX+zIdx*(nSplitX*nSplitY); + + if( numConstraintsHost[cellIdx] == 0 ) + continue; + + //printf("yIdx=%d\n",yIdx); + + const int start = offsetsHost[cellIdx]; + int numConstraintsInCell = numConstraintsHost[cellIdx]; + // const int end = start + numConstraintsInCell; + + SolveTask task( bodyNative, shapeNative, constraintNative, start, numConstraintsInCell,maxNumBatches, 0,0,batchSizes,cellIdx); + task.m_solveFriction = true; + task.run(0); + + } + } + } + + + } else + { + for(int iter=0; itercopyFromHost(bodyNative); + shapeBuf->copyFromHost(shapeNative); + constraint->copyFromHost(constraintNative); + frame++; + +} + +void checkConstraintBatch(const b3OpenCLArray* bodyBuf, + const b3OpenCLArray* shapeBuf, + b3OpenCLArray* constraint, + b3OpenCLArray* m_numConstraints, + b3OpenCLArray* m_offsets, + int batchId + ) +{ +// b3BufferInfoCL( m_numConstraints->getBufferCL() ), +// b3BufferInfoCL( m_offsets->getBufferCL() ) + + int cellBatch = batchId; + const int nn = B3_SOLVER_N_CELLS; +// int numWorkItems = 64*nn/B3_SOLVER_N_BATCHES; + + b3AlignedObjectArray gN; + m_numConstraints->copyToHost(gN); + b3AlignedObjectArray gOffsets; + m_offsets->copyToHost(gOffsets); + int nSplitX = B3_SOLVER_N_SPLIT_X; + int nSplitY = B3_SOLVER_N_SPLIT_Y; + +// int bIdx = batchId; + + b3AlignedObjectArray cpuConstraints; + constraint->copyToHost(cpuConstraints); + + printf("batch = %d\n", batchId); + + int numWorkgroups = nn/B3_SOLVER_N_BATCHES; + b3AlignedObjectArray usedBodies; + + + for (int wgIdx=0;wgIdx>2); + int remain = wgIdx%((nSplitX*nSplitY)); + int yIdx = (remain%(nSplitX/2))*2 + ((cellBatch&2)>>1); + int xIdx = (remain/(nSplitX/2))*2 + (cellBatch&1); + + + int cellIdx = xIdx+yIdx*nSplitX+zIdx*(nSplitX*nSplitY); + printf("cellIdx=%d\n",cellIdx); + if( gN[cellIdx] == 0 ) + continue; + + const int start = gOffsets[cellIdx]; + const int end = start + gN[cellIdx]; + + for (int c=start;c* bodyBuf, const b3OpenCLArray* shapeBuf, + b3OpenCLArray* constraint, void* additionalData, int n ,int maxNumBatches) +{ + + + b3Int4 cdata = b3MakeInt4( n, 0, 0, 0 ); + { + + const int nn = B3_SOLVER_N_CELLS; + + cdata.x = 0; + cdata.y = maxNumBatches;//250; + + + int numWorkItems = 64*nn/B3_SOLVER_N_BATCHES; +#ifdef DEBUG_ME + SolverDebugInfo* debugInfo = new SolverDebugInfo[numWorkItems]; + adl::b3OpenCLArray gpuDebugInfo(data->m_device,numWorkItems); +#endif + + + + { + + B3_PROFILE("m_batchSolveKernel iterations"); + for(int iter=0; itergetBufferCL() ), + b3BufferInfoCL( shapeBuf->getBufferCL() ), + b3BufferInfoCL( constraint->getBufferCL() ), + b3BufferInfoCL( m_numConstraints->getBufferCL() ), + b3BufferInfoCL( m_offsets->getBufferCL() ) +#ifdef DEBUG_ME + , b3BufferInfoCL(&gpuDebugInfo) +#endif + }; + + + + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + //launcher.setConst( cdata.x ); + launcher.setConst( cdata.y ); + launcher.setConst( cdata.z ); + b3Int4 nSplit; + nSplit.x = B3_SOLVER_N_SPLIT_X; + nSplit.y = B3_SOLVER_N_SPLIT_Y; + nSplit.z = B3_SOLVER_N_SPLIT_Z; + + launcher.setConst( nSplit ); + launcher.launch1D( numWorkItems, 64 ); + + +#else + const char* fileName = "m_batchSolveKernel.bin"; + FILE* f = fopen(fileName,"rb"); + if (f) + { + int sizeInBytes=0; + if (fseek(f, 0, SEEK_END) || (sizeInBytes = ftell(f)) == EOF || fseek(f, 0, SEEK_SET)) + { + printf("error, cannot get file size\n"); + exit(0); + } + + unsigned char* buf = (unsigned char*) malloc(sizeInBytes); + fread(buf,sizeInBytes,1,f); + int serializedBytes = launcher.deserializeArgs(buf, sizeInBytes,m_context); + int num = *(int*)&buf[serializedBytes]; + + launcher.launch1D( num); + + //this clFinish is for testing on errors + clFinish(m_queue); + } + +#endif + + +#ifdef DEBUG_ME + clFinish(m_queue); + gpuDebugInfo.read(debugInfo,numWorkItems); + clFinish(m_queue); + for (int i=0;i0) + { + printf("debugInfo[i].m_valInt2 = %d\n",i,debugInfo[i].m_valInt2); + } + + if (debugInfo[i].m_valInt3>0) + { + printf("debugInfo[i].m_valInt3 = %d\n",i,debugInfo[i].m_valInt3); + } + } +#endif //DEBUG_ME + + + } + } + + clFinish(m_queue); + + + } + + cdata.x = 1; + bool applyFriction=true; + if (applyFriction) + { + B3_PROFILE("m_batchSolveKernel iterations2"); + for(int iter=0; itergetBufferCL() ), + b3BufferInfoCL( shapeBuf->getBufferCL() ), + b3BufferInfoCL( constraint->getBufferCL() ), + b3BufferInfoCL( m_numConstraints->getBufferCL() ), + b3BufferInfoCL( m_offsets->getBufferCL() ) +#ifdef DEBUG_ME + ,b3BufferInfoCL(&gpuDebugInfo) +#endif //DEBUG_ME + }; + b3LauncherCL launcher( m_queue, m_solveFrictionKernel,"m_solveFrictionKernel" ); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + //launcher.setConst( cdata.x ); + launcher.setConst( cdata.y ); + launcher.setConst( cdata.z ); + b3Int4 nSplit; + nSplit.x = B3_SOLVER_N_SPLIT_X; + nSplit.y = B3_SOLVER_N_SPLIT_Y; + nSplit.z = B3_SOLVER_N_SPLIT_Z; + + launcher.setConst( nSplit ); + + launcher.launch1D( 64*nn/B3_SOLVER_N_BATCHES, 64 ); + } + } + clFinish(m_queue); + + } +#ifdef DEBUG_ME + delete[] debugInfo; +#endif //DEBUG_ME + } + + +} + +void b3Solver::convertToConstraints( const b3OpenCLArray* bodyBuf, + const b3OpenCLArray* shapeBuf, + b3OpenCLArray* contactsIn, b3OpenCLArray* contactCOut, void* additionalData, + int nContacts, const ConstraintCfg& cfg ) +{ +// b3OpenCLArray* constraintNative =0; + contactCOut->resize(nContacts); + struct CB + { + int m_nContacts; + float m_dt; + float m_positionDrift; + float m_positionConstraintCoeff; + }; + + { + + CB cdata; + cdata.m_nContacts = nContacts; + cdata.m_dt = cfg.m_dt; + cdata.m_positionDrift = cfg.m_positionDrift; + cdata.m_positionConstraintCoeff = cfg.m_positionConstraintCoeff; + + + if (gConvertConstraintOnCpu) + { + b3AlignedObjectArray gBodies; + bodyBuf->copyToHost(gBodies); + + b3AlignedObjectArray gContact; + contactsIn->copyToHost(gContact); + + b3AlignedObjectArray gShapes; + shapeBuf->copyToHost(gShapes); + + b3AlignedObjectArray gConstraintOut; + gConstraintOut.resize(nContacts); + + B3_PROFILE("cpu contactToConstraintKernel"); + for (int gIdx=0;gIdxcopyFromHost(gConstraintOut); + + } else + { + B3_PROFILE("gpu m_contactToConstraintKernel"); + + + b3BufferInfoCL bInfo[] = { b3BufferInfoCL( contactsIn->getBufferCL() ), b3BufferInfoCL( bodyBuf->getBufferCL() ), b3BufferInfoCL( shapeBuf->getBufferCL()), + b3BufferInfoCL( contactCOut->getBufferCL() )}; + b3LauncherCL launcher( m_queue, m_contactToConstraintKernel,"m_contactToConstraintKernel" ); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + //launcher.setConst( cdata ); + + launcher.setConst(cdata.m_nContacts); + launcher.setConst(cdata.m_dt); + launcher.setConst(cdata.m_positionDrift); + launcher.setConst(cdata.m_positionConstraintCoeff); + + launcher.launch1D( nContacts, 64 ); + clFinish(m_queue); + + } + } + + +} + +/* +void b3Solver::sortContacts( const b3OpenCLArray* bodyBuf, + b3OpenCLArray* contactsIn, void* additionalData, + int nContacts, const b3Solver::ConstraintCfg& cfg ) +{ + + + + const int sortAlignment = 512; // todo. get this out of sort + if( cfg.m_enableParallelSolve ) + { + + + int sortSize = NEXTMULTIPLEOF( nContacts, sortAlignment ); + + b3OpenCLArray* countsNative = m_numConstraints;//BufferUtils::map( data->m_device, &countsHost ); + b3OpenCLArray* offsetsNative = m_offsets;//BufferUtils::map( data->m_device, &offsetsHost ); + + { // 2. set cell idx + struct CB + { + int m_nContacts; + int m_staticIdx; + float m_scale; + int m_nSplit; + }; + + b3Assert( sortSize%64 == 0 ); + CB cdata; + cdata.m_nContacts = nContacts; + cdata.m_staticIdx = cfg.m_staticIdx; + cdata.m_scale = 1.f/(N_OBJ_PER_SPLIT*cfg.m_averageExtent); + cdata.m_nSplit = B3_SOLVER_N_SPLIT; + + + b3BufferInfoCL bInfo[] = { b3BufferInfoCL( contactsIn->getBufferCL() ), b3BufferInfoCL( bodyBuf->getBufferCL() ), b3BufferInfoCL( m_sortDataBuffer->getBufferCL() ) }; + b3LauncherCL launcher( m_queue, m_setSortDataKernel ); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( cdata ); + launcher.launch1D( sortSize, 64 ); + } + + { // 3. sort by cell idx + int n = B3_SOLVER_N_SPLIT*B3_SOLVER_N_SPLIT; + int sortBit = 32; + //if( n <= 0xffff ) sortBit = 16; + //if( n <= 0xff ) sortBit = 8; + m_sort32->execute(*m_sortDataBuffer,sortSize); + } + { // 4. find entries + m_search->execute( *m_sortDataBuffer, nContacts, *countsNative, B3_SOLVER_N_SPLIT*B3_SOLVER_N_SPLIT, b3BoundSearchCL::COUNT); + + m_scan->execute( *countsNative, *offsetsNative, B3_SOLVER_N_SPLIT*B3_SOLVER_N_SPLIT ); + } + + { // 5. sort constraints by cellIdx + // todo. preallocate this +// b3Assert( contactsIn->getType() == TYPE_HOST ); +// b3OpenCLArray* out = BufferUtils::map( data->m_device, contactsIn ); // copying contacts to this buffer + + { + + + b3Int4 cdata; cdata.x = nContacts; + b3BufferInfoCL bInfo[] = { b3BufferInfoCL( contactsIn->getBufferCL() ), b3BufferInfoCL( m_contactBuffer->getBufferCL() ), b3BufferInfoCL( m_sortDataBuffer->getBufferCL() ) }; + b3LauncherCL launcher( m_queue, m_reorderContactKernel ); + launcher.setBuffers( bInfo, sizeof(bInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst( cdata ); + launcher.launch1D( nContacts, 64 ); + } +// BufferUtils::unmap( out, contactsIn, nContacts ); + } + } + + +} + +*/ +void b3Solver::batchContacts( b3OpenCLArray* contacts, int nContacts, b3OpenCLArray* nNative, b3OpenCLArray* offsetsNative, int staticIdx ) +{ + + int numWorkItems = 64*B3_SOLVER_N_CELLS; + { + B3_PROFILE("batch generation"); + + b3Int4 cdata; + cdata.x = nContacts; + cdata.y = 0; + cdata.z = staticIdx; + + +#ifdef BATCH_DEBUG + SolverDebugInfo* debugInfo = new SolverDebugInfo[numWorkItems]; + adl::b3OpenCLArray gpuDebugInfo(data->m_device,numWorkItems); + memset(debugInfo,0,sizeof(SolverDebugInfo)*numWorkItems); + gpuDebugInfo.write(debugInfo,numWorkItems); +#endif + + + +#if 0 + b3BufferInfoCL bInfo[] = { + b3BufferInfoCL( contacts->getBufferCL() ), + b3BufferInfoCL( m_contactBuffer2->getBufferCL()), + b3BufferInfoCL( nNative->getBufferCL() ), + b3BufferInfoCL( offsetsNative->getBufferCL() ), +#ifdef BATCH_DEBUG + , b3BufferInfoCL(&gpuDebugInfo) +#endif + }; +#endif + + + + { + m_batchSizes.resize(nNative->size()); + B3_PROFILE("batchingKernel"); + //b3LauncherCL launcher( m_queue, m_batchingKernel); + cl_kernel k = useNewBatchingKernel ? m_batchingKernelNew : m_batchingKernel; + + b3LauncherCL launcher( m_queue, k,"*batchingKernel"); + if (!useNewBatchingKernel ) + { + launcher.setBuffer( contacts->getBufferCL() ); + } + launcher.setBuffer( m_contactBuffer2->getBufferCL() ); + launcher.setBuffer( nNative->getBufferCL()); + launcher.setBuffer( offsetsNative->getBufferCL()); + + launcher.setBuffer(m_batchSizes.getBufferCL()); + + + //launcher.setConst( cdata ); + launcher.setConst(staticIdx); + + launcher.launch1D( numWorkItems, 64 ); + //clFinish(m_queue); + //b3AlignedObjectArray batchSizesCPU; + //m_batchSizes.copyToHost(batchSizesCPU); + //printf(".\n"); + } + +#ifdef BATCH_DEBUG + aaaa + b3Contact4* hostContacts = new b3Contact4[nContacts]; + m_contactBuffer->read(hostContacts,nContacts); + clFinish(m_queue); + + gpuDebugInfo.read(debugInfo,numWorkItems); + clFinish(m_queue); + + for (int i=0;i0) + { + printf("catch\n"); + } + if (debugInfo[i].m_valInt2>0) + { + printf("catch22\n"); + } + + if (debugInfo[i].m_valInt3>0) + { + printf("catch666\n"); + } + + if (debugInfo[i].m_valInt4>0) + { + printf("catch777\n"); + } + } + delete[] debugInfo; +#endif //BATCH_DEBUG + + } + +// copy buffer to buffer + //b3Assert(m_contactBuffer->size()==nContacts); + //contacts->copyFromOpenCLArray( *m_contactBuffer); + //clFinish(m_queue);//needed? + + + +} + diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/b3Solver.h b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3Solver.h new file mode 100644 index 000000000000..b37f2f1bece1 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/b3Solver.h @@ -0,0 +1,126 @@ +/* +Copyright (c) 2012 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Takahiro Harada + + +#ifndef __ADL_SOLVER_H +#define __ADL_SOLVER_H + +#include "Bullet3OpenCL/ParallelPrimitives/b3OpenCLArray.h" +#include "b3GpuConstraint4.h" + +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h" +#include "Bullet3Collision/NarrowPhaseCollision/b3Contact4.h" + +#include "Bullet3OpenCL/ParallelPrimitives/b3PrefixScanCL.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3RadixSort32CL.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3BoundSearchCL.h" + +#include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h" + + +#define B3NEXTMULTIPLEOF(num, alignment) (((num)/(alignment) + (((num)%(alignment)==0)?0:1))*(alignment)) + +enum +{ + B3_SOLVER_N_SPLIT_X = 8,//16,//4, + B3_SOLVER_N_SPLIT_Y = 4,//16,//4, + B3_SOLVER_N_SPLIT_Z = 8,//, + B3_SOLVER_N_CELLS = B3_SOLVER_N_SPLIT_X*B3_SOLVER_N_SPLIT_Y*B3_SOLVER_N_SPLIT_Z, + B3_SOLVER_N_BATCHES = 8,//4,//8,//4, + B3_MAX_NUM_BATCHES = 128, +}; + +class b3SolverBase +{ + public: + + + struct ConstraintCfg + { + ConstraintCfg( float dt = 0.f ): m_positionDrift( 0.005f ), m_positionConstraintCoeff( 0.2f ), m_dt(dt), m_staticIdx(-1) {} + + float m_positionDrift; + float m_positionConstraintCoeff; + float m_dt; + bool m_enableParallelSolve; + float m_batchCellSize; + int m_staticIdx; + }; + +}; + +class b3Solver : public b3SolverBase +{ + public: + + cl_context m_context; + cl_device_id m_device; + cl_command_queue m_queue; + + + b3OpenCLArray* m_numConstraints; + b3OpenCLArray* m_offsets; + b3OpenCLArray m_batchSizes; + + + int m_nIterations; + cl_kernel m_batchingKernel; + cl_kernel m_batchingKernelNew; + cl_kernel m_solveContactKernel; + cl_kernel m_solveFrictionKernel; + cl_kernel m_contactToConstraintKernel; + cl_kernel m_setSortDataKernel; + cl_kernel m_reorderContactKernel; + cl_kernel m_copyConstraintKernel; + + class b3RadixSort32CL* m_sort32; + class b3BoundSearchCL* m_search; + class b3PrefixScanCL* m_scan; + + b3OpenCLArray* m_sortDataBuffer; + b3OpenCLArray* m_contactBuffer2; + + enum + { + DYNAMIC_CONTACT_ALLOCATION_THRESHOLD = 2000000, + }; + + + + + b3Solver(cl_context ctx, cl_device_id device, cl_command_queue queue, int pairCapacity); + + virtual ~b3Solver(); + + void solveContactConstraint( const b3OpenCLArray* bodyBuf, const b3OpenCLArray* inertiaBuf, + b3OpenCLArray* constraint, void* additionalData, int n ,int maxNumBatches); + + void solveContactConstraintHost( b3OpenCLArray* bodyBuf, b3OpenCLArray* shapeBuf, + b3OpenCLArray* constraint, void* additionalData, int n ,int maxNumBatches, b3AlignedObjectArray* batchSizes); + + + void convertToConstraints( const b3OpenCLArray* bodyBuf, + const b3OpenCLArray* shapeBuf, + b3OpenCLArray* contactsIn, b3OpenCLArray* contactCOut, void* additionalData, + int nContacts, const ConstraintCfg& cfg ); + + void batchContacts( b3OpenCLArray* contacts, int nContacts, b3OpenCLArray* n, b3OpenCLArray* offsets, int staticIdx ); + +}; + + + + +#endif //__ADL_SOLVER_H diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/batchingKernels.cl b/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/batchingKernels.cl new file mode 100644 index 000000000000..3b891b863d4d --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/batchingKernels.cl @@ -0,0 +1,353 @@ +/* +Copyright (c) 2012 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Takahiro Harada + +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3Contact4Data.h" + +#pragma OPENCL EXTENSION cl_amd_printf : enable +#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable +#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable +#pragma OPENCL EXTENSION cl_khr_local_int32_extended_atomics : enable +#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable + +#ifdef cl_ext_atomic_counters_32 +#pragma OPENCL EXTENSION cl_ext_atomic_counters_32 : enable +#else +#define counter32_t volatile __global int* +#endif + + +typedef unsigned int u32; +typedef unsigned short u16; +typedef unsigned char u8; + +#define GET_GROUP_IDX get_group_id(0) +#define GET_LOCAL_IDX get_local_id(0) +#define GET_GLOBAL_IDX get_global_id(0) +#define GET_GROUP_SIZE get_local_size(0) +#define GET_NUM_GROUPS get_num_groups(0) +#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE) +#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE) +#define AtomInc(x) atom_inc(&(x)) +#define AtomInc1(x, out) out = atom_inc(&(x)) +#define AppendInc(x, out) out = atomic_inc(x) +#define AtomAdd(x, value) atom_add(&(x), value) +#define AtomCmpxhg(x, cmp, value) atom_cmpxchg( &(x), cmp, value ) +#define AtomXhg(x, value) atom_xchg ( &(x), value ) + + +#define SELECT_UINT4( b, a, condition ) select( b,a,condition ) + +#define make_float4 (float4) +#define make_float2 (float2) +#define make_uint4 (uint4) +#define make_int4 (int4) +#define make_uint2 (uint2) +#define make_int2 (int2) + + +#define max2 max +#define min2 min + + +#define WG_SIZE 64 + + + + + +typedef struct +{ + int m_n; + int m_start; + int m_staticIdx; + int m_paddings[1]; +} ConstBuffer; + +typedef struct +{ + int m_a; + int m_b; + u32 m_idx; +}Elem; + +#define STACK_SIZE (WG_SIZE*10) +//#define STACK_SIZE (WG_SIZE) +#define RING_SIZE 1024 +#define RING_SIZE_MASK (RING_SIZE-1) +#define CHECK_SIZE (WG_SIZE) + + +#define GET_RING_CAPACITY (RING_SIZE - ldsRingEnd) +#define RING_END ldsTmp + +u32 readBuf(__local u32* buff, int idx) +{ + idx = idx % (32*CHECK_SIZE); + int bitIdx = idx%32; + int bufIdx = idx/32; + return buff[bufIdx] & (1<> bitIdx)&1) == 0; +} + +// batching on the GPU +__kernel void CreateBatches( __global const struct b3Contact4Data* gConstraints, __global struct b3Contact4Data* gConstraintsOut, + __global const u32* gN, __global const u32* gStart, __global int* batchSizes, + int m_staticIdx ) +{ + __local u32 ldsStackIdx[STACK_SIZE]; + __local u32 ldsStackEnd; + __local Elem ldsRingElem[RING_SIZE]; + __local u32 ldsRingEnd; + __local u32 ldsTmp; + __local u32 ldsCheckBuffer[CHECK_SIZE]; + __local u32 ldsFixedBuffer[CHECK_SIZE]; + __local u32 ldsGEnd; + __local u32 ldsDstEnd; + + int wgIdx = GET_GROUP_IDX; + int lIdx = GET_LOCAL_IDX; + + const int m_n = gN[wgIdx]; + const int m_start = gStart[wgIdx]; + + if( lIdx == 0 ) + { + ldsRingEnd = 0; + ldsGEnd = 0; + ldsStackEnd = 0; + ldsDstEnd = m_start; + } + + + +// while(1) +//was 250 + int ie=0; + int maxBatch = 0; + for(ie=0; ie<50; ie++) + { + ldsFixedBuffer[lIdx] = 0; + + for(int giter=0; giter<4; giter++) + { + int ringCap = GET_RING_CAPACITY; + + // 1. fill ring + if( ldsGEnd < m_n ) + { + while( ringCap > WG_SIZE ) + { + if( ldsGEnd >= m_n ) break; + if( lIdx < ringCap - WG_SIZE ) + { + int srcIdx; + AtomInc1( ldsGEnd, srcIdx ); + if( srcIdx < m_n ) + { + int dstIdx; + AtomInc1( ldsRingEnd, dstIdx ); + + int a = gConstraints[m_start+srcIdx].m_bodyAPtrAndSignBit; + int b = gConstraints[m_start+srcIdx].m_bodyBPtrAndSignBit; + ldsRingElem[dstIdx].m_a = (a>b)? b:a; + ldsRingElem[dstIdx].m_b = (a>b)? a:b; + ldsRingElem[dstIdx].m_idx = srcIdx; + } + } + ringCap = GET_RING_CAPACITY; + } + } + + GROUP_LDS_BARRIER; + + // 2. fill stack + __local Elem* dst = ldsRingElem; + if( lIdx == 0 ) RING_END = 0; + + int srcIdx=lIdx; + int end = ldsRingEnd; + + { + for(int ii=0; ii1e-6 || b3Fabs(v.y)>1e-6 || b3Fabs(v.z)>1e-6) \n" +" return false;\n" +" return true;\n" +"}\n" +"inline int b3MaxDot( b3Float4ConstArg vec, __global const b3Float4* vecArray, int vecLen, float* dotOut )\n" +"{\n" +" float maxDot = -B3_INFINITY;\n" +" int i = 0;\n" +" int ptIndex = -1;\n" +" for( i = 0; i < vecLen; i++ )\n" +" {\n" +" float dot = b3Dot3F4(vecArray[i],vec);\n" +" \n" +" if( dot > maxDot )\n" +" {\n" +" maxDot = dot;\n" +" ptIndex = i;\n" +" }\n" +" }\n" +" b3Assert(ptIndex>=0);\n" +" if (ptIndex<0)\n" +" {\n" +" ptIndex = 0;\n" +" }\n" +" *dotOut = maxDot;\n" +" return ptIndex;\n" +"}\n" +"#endif //B3_FLOAT4_H\n" +"typedef struct b3Contact4Data b3Contact4Data_t;\n" +"struct b3Contact4Data\n" +"{\n" +" b3Float4 m_worldPosB[4];\n" +"// b3Float4 m_localPosA[4];\n" +"// b3Float4 m_localPosB[4];\n" +" b3Float4 m_worldNormalOnB; // w: m_nPoints\n" +" unsigned short m_restituitionCoeffCmp;\n" +" unsigned short m_frictionCoeffCmp;\n" +" int m_batchIdx;\n" +" int m_bodyAPtrAndSignBit;//x:m_bodyAPtr, y:m_bodyBPtr\n" +" int m_bodyBPtrAndSignBit;\n" +" int m_childIndexA;\n" +" int m_childIndexB;\n" +" int m_unused1;\n" +" int m_unused2;\n" +"};\n" +"inline int b3Contact4Data_getNumPoints(const struct b3Contact4Data* contact)\n" +"{\n" +" return (int)contact->m_worldNormalOnB.w;\n" +"};\n" +"inline void b3Contact4Data_setNumPoints(struct b3Contact4Data* contact, int numPoints)\n" +"{\n" +" contact->m_worldNormalOnB.w = (float)numPoints;\n" +"};\n" +"#endif //B3_CONTACT4DATA_H\n" +"#pragma OPENCL EXTENSION cl_amd_printf : enable\n" +"#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable\n" +"#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable\n" +"#pragma OPENCL EXTENSION cl_khr_local_int32_extended_atomics : enable\n" +"#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable\n" +"#ifdef cl_ext_atomic_counters_32\n" +"#pragma OPENCL EXTENSION cl_ext_atomic_counters_32 : enable\n" +"#else\n" +"#define counter32_t volatile __global int*\n" +"#endif\n" +"typedef unsigned int u32;\n" +"typedef unsigned short u16;\n" +"typedef unsigned char u8;\n" +"#define GET_GROUP_IDX get_group_id(0)\n" +"#define GET_LOCAL_IDX get_local_id(0)\n" +"#define GET_GLOBAL_IDX get_global_id(0)\n" +"#define GET_GROUP_SIZE get_local_size(0)\n" +"#define GET_NUM_GROUPS get_num_groups(0)\n" +"#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE)\n" +"#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE)\n" +"#define AtomInc(x) atom_inc(&(x))\n" +"#define AtomInc1(x, out) out = atom_inc(&(x))\n" +"#define AppendInc(x, out) out = atomic_inc(x)\n" +"#define AtomAdd(x, value) atom_add(&(x), value)\n" +"#define AtomCmpxhg(x, cmp, value) atom_cmpxchg( &(x), cmp, value )\n" +"#define AtomXhg(x, value) atom_xchg ( &(x), value )\n" +"#define SELECT_UINT4( b, a, condition ) select( b,a,condition )\n" +"#define make_float4 (float4)\n" +"#define make_float2 (float2)\n" +"#define make_uint4 (uint4)\n" +"#define make_int4 (int4)\n" +"#define make_uint2 (uint2)\n" +"#define make_int2 (int2)\n" +"#define max2 max\n" +"#define min2 min\n" +"#define WG_SIZE 64\n" +"typedef struct \n" +"{\n" +" int m_n;\n" +" int m_start;\n" +" int m_staticIdx;\n" +" int m_paddings[1];\n" +"} ConstBuffer;\n" +"typedef struct \n" +"{\n" +" int m_a;\n" +" int m_b;\n" +" u32 m_idx;\n" +"}Elem;\n" +"#define STACK_SIZE (WG_SIZE*10)\n" +"//#define STACK_SIZE (WG_SIZE)\n" +"#define RING_SIZE 1024\n" +"#define RING_SIZE_MASK (RING_SIZE-1)\n" +"#define CHECK_SIZE (WG_SIZE)\n" +"#define GET_RING_CAPACITY (RING_SIZE - ldsRingEnd)\n" +"#define RING_END ldsTmp\n" +"u32 readBuf(__local u32* buff, int idx)\n" +"{\n" +" idx = idx % (32*CHECK_SIZE);\n" +" int bitIdx = idx%32;\n" +" int bufIdx = idx/32;\n" +" return buff[bufIdx] & (1<> bitIdx)&1) == 0;\n" +"}\n" +"// batching on the GPU\n" +"__kernel void CreateBatches( __global const struct b3Contact4Data* gConstraints, __global struct b3Contact4Data* gConstraintsOut,\n" +" __global const u32* gN, __global const u32* gStart, __global int* batchSizes, \n" +" int m_staticIdx )\n" +"{\n" +" __local u32 ldsStackIdx[STACK_SIZE];\n" +" __local u32 ldsStackEnd;\n" +" __local Elem ldsRingElem[RING_SIZE];\n" +" __local u32 ldsRingEnd;\n" +" __local u32 ldsTmp;\n" +" __local u32 ldsCheckBuffer[CHECK_SIZE];\n" +" __local u32 ldsFixedBuffer[CHECK_SIZE];\n" +" __local u32 ldsGEnd;\n" +" __local u32 ldsDstEnd;\n" +" int wgIdx = GET_GROUP_IDX;\n" +" int lIdx = GET_LOCAL_IDX;\n" +" \n" +" const int m_n = gN[wgIdx];\n" +" const int m_start = gStart[wgIdx];\n" +" \n" +" if( lIdx == 0 )\n" +" {\n" +" ldsRingEnd = 0;\n" +" ldsGEnd = 0;\n" +" ldsStackEnd = 0;\n" +" ldsDstEnd = m_start;\n" +" }\n" +" \n" +" \n" +" \n" +"// while(1)\n" +"//was 250\n" +" int ie=0;\n" +" int maxBatch = 0;\n" +" for(ie=0; ie<50; ie++)\n" +" {\n" +" ldsFixedBuffer[lIdx] = 0;\n" +" for(int giter=0; giter<4; giter++)\n" +" {\n" +" int ringCap = GET_RING_CAPACITY;\n" +" \n" +" // 1. fill ring\n" +" if( ldsGEnd < m_n )\n" +" {\n" +" while( ringCap > WG_SIZE )\n" +" {\n" +" if( ldsGEnd >= m_n ) break;\n" +" if( lIdx < ringCap - WG_SIZE )\n" +" {\n" +" int srcIdx;\n" +" AtomInc1( ldsGEnd, srcIdx );\n" +" if( srcIdx < m_n )\n" +" {\n" +" int dstIdx;\n" +" AtomInc1( ldsRingEnd, dstIdx );\n" +" \n" +" int a = gConstraints[m_start+srcIdx].m_bodyAPtrAndSignBit;\n" +" int b = gConstraints[m_start+srcIdx].m_bodyBPtrAndSignBit;\n" +" ldsRingElem[dstIdx].m_a = (a>b)? b:a;\n" +" ldsRingElem[dstIdx].m_b = (a>b)? a:b;\n" +" ldsRingElem[dstIdx].m_idx = srcIdx;\n" +" }\n" +" }\n" +" ringCap = GET_RING_CAPACITY;\n" +" }\n" +" }\n" +" GROUP_LDS_BARRIER;\n" +" \n" +" // 2. fill stack\n" +" __local Elem* dst = ldsRingElem;\n" +" if( lIdx == 0 ) RING_END = 0;\n" +" int srcIdx=lIdx;\n" +" int end = ldsRingEnd;\n" +" {\n" +" for(int ii=0; ii> bitIdx)&1) == 0; +} + + +// batching on the GPU +__kernel void CreateBatchesNew( __global struct b3Contact4Data* gConstraints, __global const u32* gN, __global const u32* gStart, __global int* batchSizes, int staticIdx ) +{ + int wgIdx = GET_GROUP_IDX; + int lIdx = GET_LOCAL_IDX; + const int numConstraints = gN[wgIdx]; + const int m_start = gStart[wgIdx]; + b3Contact4Data_t tmp; + + __local u32 ldsFixedBuffer[CHECK_SIZE]; + + + + + + if( lIdx == 0 ) + { + + + __global struct b3Contact4Data* cs = &gConstraints[m_start]; + + + int numValidConstraints = 0; + int batchIdx = 0; + + while( numValidConstraints < numConstraints) + { + int nCurrentBatch = 0; + // clear flag + + for(int i=0; i1e-6 || b3Fabs(v.y)>1e-6 || b3Fabs(v.z)>1e-6) \n" +" return false;\n" +" return true;\n" +"}\n" +"inline int b3MaxDot( b3Float4ConstArg vec, __global const b3Float4* vecArray, int vecLen, float* dotOut )\n" +"{\n" +" float maxDot = -B3_INFINITY;\n" +" int i = 0;\n" +" int ptIndex = -1;\n" +" for( i = 0; i < vecLen; i++ )\n" +" {\n" +" float dot = b3Dot3F4(vecArray[i],vec);\n" +" \n" +" if( dot > maxDot )\n" +" {\n" +" maxDot = dot;\n" +" ptIndex = i;\n" +" }\n" +" }\n" +" b3Assert(ptIndex>=0);\n" +" if (ptIndex<0)\n" +" {\n" +" ptIndex = 0;\n" +" }\n" +" *dotOut = maxDot;\n" +" return ptIndex;\n" +"}\n" +"#endif //B3_FLOAT4_H\n" +"typedef struct b3Contact4Data b3Contact4Data_t;\n" +"struct b3Contact4Data\n" +"{\n" +" b3Float4 m_worldPosB[4];\n" +"// b3Float4 m_localPosA[4];\n" +"// b3Float4 m_localPosB[4];\n" +" b3Float4 m_worldNormalOnB; // w: m_nPoints\n" +" unsigned short m_restituitionCoeffCmp;\n" +" unsigned short m_frictionCoeffCmp;\n" +" int m_batchIdx;\n" +" int m_bodyAPtrAndSignBit;//x:m_bodyAPtr, y:m_bodyBPtr\n" +" int m_bodyBPtrAndSignBit;\n" +" int m_childIndexA;\n" +" int m_childIndexB;\n" +" int m_unused1;\n" +" int m_unused2;\n" +"};\n" +"inline int b3Contact4Data_getNumPoints(const struct b3Contact4Data* contact)\n" +"{\n" +" return (int)contact->m_worldNormalOnB.w;\n" +"};\n" +"inline void b3Contact4Data_setNumPoints(struct b3Contact4Data* contact, int numPoints)\n" +"{\n" +" contact->m_worldNormalOnB.w = (float)numPoints;\n" +"};\n" +"#endif //B3_CONTACT4DATA_H\n" +"#pragma OPENCL EXTENSION cl_amd_printf : enable\n" +"#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable\n" +"#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable\n" +"#pragma OPENCL EXTENSION cl_khr_local_int32_extended_atomics : enable\n" +"#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable\n" +"#ifdef cl_ext_atomic_counters_32\n" +"#pragma OPENCL EXTENSION cl_ext_atomic_counters_32 : enable\n" +"#else\n" +"#define counter32_t volatile __global int*\n" +"#endif\n" +"#define SIMD_WIDTH 64\n" +"typedef unsigned int u32;\n" +"typedef unsigned short u16;\n" +"typedef unsigned char u8;\n" +"#define GET_GROUP_IDX get_group_id(0)\n" +"#define GET_LOCAL_IDX get_local_id(0)\n" +"#define GET_GLOBAL_IDX get_global_id(0)\n" +"#define GET_GROUP_SIZE get_local_size(0)\n" +"#define GET_NUM_GROUPS get_num_groups(0)\n" +"#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE)\n" +"#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE)\n" +"#define AtomInc(x) atom_inc(&(x))\n" +"#define AtomInc1(x, out) out = atom_inc(&(x))\n" +"#define AppendInc(x, out) out = atomic_inc(x)\n" +"#define AtomAdd(x, value) atom_add(&(x), value)\n" +"#define AtomCmpxhg(x, cmp, value) atom_cmpxchg( &(x), cmp, value )\n" +"#define AtomXhg(x, value) atom_xchg ( &(x), value )\n" +"#define SELECT_UINT4( b, a, condition ) select( b,a,condition )\n" +"#define make_float4 (float4)\n" +"#define make_float2 (float2)\n" +"#define make_uint4 (uint4)\n" +"#define make_int4 (int4)\n" +"#define make_uint2 (uint2)\n" +"#define make_int2 (int2)\n" +"#define max2 max\n" +"#define min2 min\n" +"#define WG_SIZE 64\n" +"typedef struct \n" +"{\n" +" int m_n;\n" +" int m_start;\n" +" int m_staticIdx;\n" +" int m_paddings[1];\n" +"} ConstBuffer;\n" +"typedef struct \n" +"{\n" +" int m_a;\n" +" int m_b;\n" +" u32 m_idx;\n" +"}Elem;\n" +"// batching on the GPU\n" +"__kernel void CreateBatchesBruteForce( __global struct b3Contact4Data* gConstraints, __global const u32* gN, __global const u32* gStart, int m_staticIdx )\n" +"{\n" +" int wgIdx = GET_GROUP_IDX;\n" +" int lIdx = GET_LOCAL_IDX;\n" +" \n" +" const int m_n = gN[wgIdx];\n" +" const int m_start = gStart[wgIdx];\n" +" \n" +" if( lIdx == 0 )\n" +" {\n" +" for (int i=0;i> bitIdx)&1) == 0;\n" +"}\n" +"// batching on the GPU\n" +"__kernel void CreateBatchesNew( __global struct b3Contact4Data* gConstraints, __global const u32* gN, __global const u32* gStart, __global int* batchSizes, int staticIdx )\n" +"{\n" +" int wgIdx = GET_GROUP_IDX;\n" +" int lIdx = GET_LOCAL_IDX;\n" +" const int numConstraints = gN[wgIdx];\n" +" const int m_start = gStart[wgIdx];\n" +" b3Contact4Data_t tmp;\n" +" \n" +" __local u32 ldsFixedBuffer[CHECK_SIZE];\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" if( lIdx == 0 )\n" +" {\n" +" \n" +" \n" +" __global struct b3Contact4Data* cs = &gConstraints[m_start]; \n" +" \n" +" \n" +" int numValidConstraints = 0;\n" +" int batchIdx = 0;\n" +" while( numValidConstraints < numConstraints)\n" +" {\n" +" int nCurrentBatch = 0;\n" +" // clear flag\n" +" \n" +" for(int i=0; i1e-6 || b3Fabs(v.y)>1e-6 || b3Fabs(v.z)>1e-6) \n" +" return false;\n" +" return true;\n" +"}\n" +"inline int b3MaxDot( b3Float4ConstArg vec, __global const b3Float4* vecArray, int vecLen, float* dotOut )\n" +"{\n" +" float maxDot = -B3_INFINITY;\n" +" int i = 0;\n" +" int ptIndex = -1;\n" +" for( i = 0; i < vecLen; i++ )\n" +" {\n" +" float dot = b3Dot3F4(vecArray[i],vec);\n" +" \n" +" if( dot > maxDot )\n" +" {\n" +" maxDot = dot;\n" +" ptIndex = i;\n" +" }\n" +" }\n" +" b3Assert(ptIndex>=0);\n" +" if (ptIndex<0)\n" +" {\n" +" ptIndex = 0;\n" +" }\n" +" *dotOut = maxDot;\n" +" return ptIndex;\n" +"}\n" +"#endif //B3_FLOAT4_H\n" +"#ifndef B3_QUAT_H\n" +"#define B3_QUAT_H\n" +"#ifndef B3_PLATFORM_DEFINITIONS_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif\n" +"#endif\n" +"#ifndef B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +" typedef float4 b3Quat;\n" +" #define b3QuatConstArg const b3Quat\n" +" \n" +" \n" +"inline float4 b3FastNormalize4(float4 v)\n" +"{\n" +" v = (float4)(v.xyz,0.f);\n" +" return fast_normalize(v);\n" +"}\n" +" \n" +"inline b3Quat b3QuatMul(b3Quat a, b3Quat b);\n" +"inline b3Quat b3QuatNormalized(b3QuatConstArg in);\n" +"inline b3Quat b3QuatRotate(b3QuatConstArg q, b3QuatConstArg vec);\n" +"inline b3Quat b3QuatInvert(b3QuatConstArg q);\n" +"inline b3Quat b3QuatInverse(b3QuatConstArg q);\n" +"inline b3Quat b3QuatMul(b3QuatConstArg a, b3QuatConstArg b)\n" +"{\n" +" b3Quat ans;\n" +" ans = b3Cross3( a, b );\n" +" ans += a.w*b+b.w*a;\n" +"// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z);\n" +" ans.w = a.w*b.w - b3Dot3F4(a, b);\n" +" return ans;\n" +"}\n" +"inline b3Quat b3QuatNormalized(b3QuatConstArg in)\n" +"{\n" +" b3Quat q;\n" +" q=in;\n" +" //return b3FastNormalize4(in);\n" +" float len = native_sqrt(dot(q, q));\n" +" if(len > 0.f)\n" +" {\n" +" q *= 1.f / len;\n" +" }\n" +" else\n" +" {\n" +" q.x = q.y = q.z = 0.f;\n" +" q.w = 1.f;\n" +" }\n" +" return q;\n" +"}\n" +"inline float4 b3QuatRotate(b3QuatConstArg q, b3QuatConstArg vec)\n" +"{\n" +" b3Quat qInv = b3QuatInvert( q );\n" +" float4 vcpy = vec;\n" +" vcpy.w = 0.f;\n" +" float4 out = b3QuatMul(b3QuatMul(q,vcpy),qInv);\n" +" return out;\n" +"}\n" +"inline b3Quat b3QuatInverse(b3QuatConstArg q)\n" +"{\n" +" return (b3Quat)(-q.xyz, q.w);\n" +"}\n" +"inline b3Quat b3QuatInvert(b3QuatConstArg q)\n" +"{\n" +" return (b3Quat)(-q.xyz, q.w);\n" +"}\n" +"inline float4 b3QuatInvRotate(b3QuatConstArg q, b3QuatConstArg vec)\n" +"{\n" +" return b3QuatRotate( b3QuatInvert( q ), vec );\n" +"}\n" +"inline b3Float4 b3TransformPoint(b3Float4ConstArg point, b3Float4ConstArg translation, b3QuatConstArg orientation)\n" +"{\n" +" return b3QuatRotate( orientation, point ) + (translation);\n" +"}\n" +" \n" +"#endif \n" +"#endif //B3_QUAT_H\n" +"#ifndef B3_MAT3x3_H\n" +"#define B3_MAT3x3_H\n" +"#ifndef B3_QUAT_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_QUAT_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"typedef struct\n" +"{\n" +" b3Float4 m_row[3];\n" +"}b3Mat3x3;\n" +"#define b3Mat3x3ConstArg const b3Mat3x3\n" +"#define b3GetRow(m,row) (m.m_row[row])\n" +"inline b3Mat3x3 b3QuatGetRotationMatrix(b3Quat quat)\n" +"{\n" +" b3Float4 quat2 = (b3Float4)(quat.x*quat.x, quat.y*quat.y, quat.z*quat.z, 0.f);\n" +" b3Mat3x3 out;\n" +" out.m_row[0].x=1-2*quat2.y-2*quat2.z;\n" +" out.m_row[0].y=2*quat.x*quat.y-2*quat.w*quat.z;\n" +" out.m_row[0].z=2*quat.x*quat.z+2*quat.w*quat.y;\n" +" out.m_row[0].w = 0.f;\n" +" out.m_row[1].x=2*quat.x*quat.y+2*quat.w*quat.z;\n" +" out.m_row[1].y=1-2*quat2.x-2*quat2.z;\n" +" out.m_row[1].z=2*quat.y*quat.z-2*quat.w*quat.x;\n" +" out.m_row[1].w = 0.f;\n" +" out.m_row[2].x=2*quat.x*quat.z-2*quat.w*quat.y;\n" +" out.m_row[2].y=2*quat.y*quat.z+2*quat.w*quat.x;\n" +" out.m_row[2].z=1-2*quat2.x-2*quat2.y;\n" +" out.m_row[2].w = 0.f;\n" +" return out;\n" +"}\n" +"inline b3Mat3x3 b3AbsoluteMat3x3(b3Mat3x3ConstArg matIn)\n" +"{\n" +" b3Mat3x3 out;\n" +" out.m_row[0] = fabs(matIn.m_row[0]);\n" +" out.m_row[1] = fabs(matIn.m_row[1]);\n" +" out.m_row[2] = fabs(matIn.m_row[2]);\n" +" return out;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtZero();\n" +"__inline\n" +"b3Mat3x3 mtIdentity();\n" +"__inline\n" +"b3Mat3x3 mtTranspose(b3Mat3x3 m);\n" +"__inline\n" +"b3Mat3x3 mtMul(b3Mat3x3 a, b3Mat3x3 b);\n" +"__inline\n" +"b3Float4 mtMul1(b3Mat3x3 a, b3Float4 b);\n" +"__inline\n" +"b3Float4 mtMul3(b3Float4 a, b3Mat3x3 b);\n" +"__inline\n" +"b3Mat3x3 mtZero()\n" +"{\n" +" b3Mat3x3 m;\n" +" m.m_row[0] = (b3Float4)(0.f);\n" +" m.m_row[1] = (b3Float4)(0.f);\n" +" m.m_row[2] = (b3Float4)(0.f);\n" +" return m;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtIdentity()\n" +"{\n" +" b3Mat3x3 m;\n" +" m.m_row[0] = (b3Float4)(1,0,0,0);\n" +" m.m_row[1] = (b3Float4)(0,1,0,0);\n" +" m.m_row[2] = (b3Float4)(0,0,1,0);\n" +" return m;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtTranspose(b3Mat3x3 m)\n" +"{\n" +" b3Mat3x3 out;\n" +" out.m_row[0] = (b3Float4)(m.m_row[0].x, m.m_row[1].x, m.m_row[2].x, 0.f);\n" +" out.m_row[1] = (b3Float4)(m.m_row[0].y, m.m_row[1].y, m.m_row[2].y, 0.f);\n" +" out.m_row[2] = (b3Float4)(m.m_row[0].z, m.m_row[1].z, m.m_row[2].z, 0.f);\n" +" return out;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtMul(b3Mat3x3 a, b3Mat3x3 b)\n" +"{\n" +" b3Mat3x3 transB;\n" +" transB = mtTranspose( b );\n" +" b3Mat3x3 ans;\n" +" // why this doesn't run when 0ing in the for{}\n" +" a.m_row[0].w = 0.f;\n" +" a.m_row[1].w = 0.f;\n" +" a.m_row[2].w = 0.f;\n" +" for(int i=0; i<3; i++)\n" +" {\n" +"// a.m_row[i].w = 0.f;\n" +" ans.m_row[i].x = b3Dot3F4(a.m_row[i],transB.m_row[0]);\n" +" ans.m_row[i].y = b3Dot3F4(a.m_row[i],transB.m_row[1]);\n" +" ans.m_row[i].z = b3Dot3F4(a.m_row[i],transB.m_row[2]);\n" +" ans.m_row[i].w = 0.f;\n" +" }\n" +" return ans;\n" +"}\n" +"__inline\n" +"b3Float4 mtMul1(b3Mat3x3 a, b3Float4 b)\n" +"{\n" +" b3Float4 ans;\n" +" ans.x = b3Dot3F4( a.m_row[0], b );\n" +" ans.y = b3Dot3F4( a.m_row[1], b );\n" +" ans.z = b3Dot3F4( a.m_row[2], b );\n" +" ans.w = 0.f;\n" +" return ans;\n" +"}\n" +"__inline\n" +"b3Float4 mtMul3(b3Float4 a, b3Mat3x3 b)\n" +"{\n" +" b3Float4 colx = b3MakeFloat4(b.m_row[0].x, b.m_row[1].x, b.m_row[2].x, 0);\n" +" b3Float4 coly = b3MakeFloat4(b.m_row[0].y, b.m_row[1].y, b.m_row[2].y, 0);\n" +" b3Float4 colz = b3MakeFloat4(b.m_row[0].z, b.m_row[1].z, b.m_row[2].z, 0);\n" +" b3Float4 ans;\n" +" ans.x = b3Dot3F4( a, colx );\n" +" ans.y = b3Dot3F4( a, coly );\n" +" ans.z = b3Dot3F4( a, colz );\n" +" return ans;\n" +"}\n" +"#endif\n" +"#endif //B3_MAT3x3_H\n" +"typedef struct b3RigidBodyData b3RigidBodyData_t;\n" +"struct b3RigidBodyData\n" +"{\n" +" b3Float4 m_pos;\n" +" b3Quat m_quat;\n" +" b3Float4 m_linVel;\n" +" b3Float4 m_angVel;\n" +" int m_collidableIdx;\n" +" float m_invMass;\n" +" float m_restituitionCoeff;\n" +" float m_frictionCoeff;\n" +"};\n" +"typedef struct b3InertiaData b3InertiaData_t;\n" +"struct b3InertiaData\n" +"{\n" +" b3Mat3x3 m_invInertiaWorld;\n" +" b3Mat3x3 m_initInvInertia;\n" +"};\n" +"#endif //B3_RIGIDBODY_DATA_H\n" +" \n" +"#ifndef B3_RIGIDBODY_DATA_H\n" +"#endif //B3_RIGIDBODY_DATA_H\n" +" \n" +"inline void integrateSingleTransform( __global b3RigidBodyData_t* bodies,int nodeID, float timeStep, float angularDamping, b3Float4ConstArg gravityAcceleration)\n" +"{\n" +" \n" +" if (bodies[nodeID].m_invMass != 0.f)\n" +" {\n" +" float BT_GPU_ANGULAR_MOTION_THRESHOLD = (0.25f * 3.14159254f);\n" +" //angular velocity\n" +" {\n" +" b3Float4 axis;\n" +" //add some hardcoded angular damping\n" +" bodies[nodeID].m_angVel.x *= angularDamping;\n" +" bodies[nodeID].m_angVel.y *= angularDamping;\n" +" bodies[nodeID].m_angVel.z *= angularDamping;\n" +" \n" +" b3Float4 angvel = bodies[nodeID].m_angVel;\n" +" float fAngle = b3Sqrt(b3Dot3F4(angvel, angvel));\n" +" \n" +" //limit the angular motion\n" +" if(fAngle*timeStep > BT_GPU_ANGULAR_MOTION_THRESHOLD)\n" +" {\n" +" fAngle = BT_GPU_ANGULAR_MOTION_THRESHOLD / timeStep;\n" +" }\n" +" if(fAngle < 0.001f)\n" +" {\n" +" // use Taylor's expansions of sync function\n" +" axis = angvel * (0.5f*timeStep-(timeStep*timeStep*timeStep)*0.020833333333f * fAngle * fAngle);\n" +" }\n" +" else\n" +" {\n" +" // sync(fAngle) = sin(c*fAngle)/t\n" +" axis = angvel * ( b3Sin(0.5f * fAngle * timeStep) / fAngle);\n" +" }\n" +" \n" +" b3Quat dorn;\n" +" dorn.x = axis.x;\n" +" dorn.y = axis.y;\n" +" dorn.z = axis.z;\n" +" dorn.w = b3Cos(fAngle * timeStep * 0.5f);\n" +" b3Quat orn0 = bodies[nodeID].m_quat;\n" +" b3Quat predictedOrn = b3QuatMul(dorn, orn0);\n" +" predictedOrn = b3QuatNormalized(predictedOrn);\n" +" bodies[nodeID].m_quat=predictedOrn;\n" +" }\n" +" //linear velocity \n" +" bodies[nodeID].m_pos += bodies[nodeID].m_linVel * timeStep;\n" +" \n" +" //apply gravity\n" +" bodies[nodeID].m_linVel += gravityAcceleration * timeStep;\n" +" \n" +" }\n" +" \n" +"}\n" +"inline void b3IntegrateTransform( __global b3RigidBodyData_t* body, float timeStep, float angularDamping, b3Float4ConstArg gravityAcceleration)\n" +"{\n" +" float BT_GPU_ANGULAR_MOTION_THRESHOLD = (0.25f * 3.14159254f);\n" +" \n" +" if( (body->m_invMass != 0.f))\n" +" {\n" +" //angular velocity\n" +" {\n" +" b3Float4 axis;\n" +" //add some hardcoded angular damping\n" +" body->m_angVel.x *= angularDamping;\n" +" body->m_angVel.y *= angularDamping;\n" +" body->m_angVel.z *= angularDamping;\n" +" \n" +" b3Float4 angvel = body->m_angVel;\n" +" float fAngle = b3Sqrt(b3Dot3F4(angvel, angvel));\n" +" //limit the angular motion\n" +" if(fAngle*timeStep > BT_GPU_ANGULAR_MOTION_THRESHOLD)\n" +" {\n" +" fAngle = BT_GPU_ANGULAR_MOTION_THRESHOLD / timeStep;\n" +" }\n" +" if(fAngle < 0.001f)\n" +" {\n" +" // use Taylor's expansions of sync function\n" +" axis = angvel * (0.5f*timeStep-(timeStep*timeStep*timeStep)*0.020833333333f * fAngle * fAngle);\n" +" }\n" +" else\n" +" {\n" +" // sync(fAngle) = sin(c*fAngle)/t\n" +" axis = angvel * ( b3Sin(0.5f * fAngle * timeStep) / fAngle);\n" +" }\n" +" b3Quat dorn;\n" +" dorn.x = axis.x;\n" +" dorn.y = axis.y;\n" +" dorn.z = axis.z;\n" +" dorn.w = b3Cos(fAngle * timeStep * 0.5f);\n" +" b3Quat orn0 = body->m_quat;\n" +" b3Quat predictedOrn = b3QuatMul(dorn, orn0);\n" +" predictedOrn = b3QuatNormalized(predictedOrn);\n" +" body->m_quat=predictedOrn;\n" +" }\n" +" //apply gravity\n" +" body->m_linVel += gravityAcceleration * timeStep;\n" +" //linear velocity \n" +" body->m_pos += body->m_linVel * timeStep;\n" +" \n" +" }\n" +" \n" +"}\n" +"__kernel void \n" +" integrateTransformsKernel( __global b3RigidBodyData_t* bodies,const int numNodes, float timeStep, float angularDamping, float4 gravityAcceleration)\n" +"{\n" +" int nodeID = get_global_id(0);\n" +" \n" +" if( nodeID < numNodes)\n" +" {\n" +" integrateSingleTransform(bodies,nodeID, timeStep, angularDamping,gravityAcceleration);\n" +" }\n" +"}\n" +; diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/jointSolver.cl b/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/jointSolver.cl new file mode 100644 index 000000000000..7f5dabe274d5 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/jointSolver.cl @@ -0,0 +1,877 @@ +/* +Copyright (c) 2013 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Erwin Coumans + +#define B3_CONSTRAINT_FLAG_ENABLED 1 + +#define B3_GPU_POINT2POINT_CONSTRAINT_TYPE 3 +#define B3_GPU_FIXED_CONSTRAINT_TYPE 4 + +#define MOTIONCLAMP 100000 //unused, for debugging/safety in case constraint solver fails +#define B3_INFINITY 1e30f + +#define mymake_float4 (float4) + + +__inline float dot3F4(float4 a, float4 b) +{ + float4 a1 = mymake_float4(a.xyz,0.f); + float4 b1 = mymake_float4(b.xyz,0.f); + return dot(a1, b1); +} + + +typedef float4 Quaternion; + + +typedef struct +{ + float4 m_row[3]; +}Matrix3x3; + +__inline +float4 mtMul1(Matrix3x3 a, float4 b); + +__inline +float4 mtMul3(float4 a, Matrix3x3 b); + + + + + +__inline +float4 mtMul1(Matrix3x3 a, float4 b) +{ + float4 ans; + ans.x = dot3F4( a.m_row[0], b ); + ans.y = dot3F4( a.m_row[1], b ); + ans.z = dot3F4( a.m_row[2], b ); + ans.w = 0.f; + return ans; +} + +__inline +float4 mtMul3(float4 a, Matrix3x3 b) +{ + float4 colx = mymake_float4(b.m_row[0].x, b.m_row[1].x, b.m_row[2].x, 0); + float4 coly = mymake_float4(b.m_row[0].y, b.m_row[1].y, b.m_row[2].y, 0); + float4 colz = mymake_float4(b.m_row[0].z, b.m_row[1].z, b.m_row[2].z, 0); + + float4 ans; + ans.x = dot3F4( a, colx ); + ans.y = dot3F4( a, coly ); + ans.z = dot3F4( a, colz ); + return ans; +} + + + +typedef struct +{ + Matrix3x3 m_invInertiaWorld; + Matrix3x3 m_initInvInertia; +} BodyInertia; + + +typedef struct +{ + Matrix3x3 m_basis;//orientation + float4 m_origin;//transform +}b3Transform; + +typedef struct +{ +// b3Transform m_worldTransformUnused; + float4 m_deltaLinearVelocity; + float4 m_deltaAngularVelocity; + float4 m_angularFactor; + float4 m_linearFactor; + float4 m_invMass; + float4 m_pushVelocity; + float4 m_turnVelocity; + float4 m_linearVelocity; + float4 m_angularVelocity; + + union + { + void* m_originalBody; + int m_originalBodyIndex; + }; + int padding[3]; + +} b3GpuSolverBody; + +typedef struct +{ + float4 m_pos; + Quaternion m_quat; + float4 m_linVel; + float4 m_angVel; + + unsigned int m_shapeIdx; + float m_invMass; + float m_restituitionCoeff; + float m_frictionCoeff; +} b3RigidBodyCL; + +typedef struct +{ + + float4 m_relpos1CrossNormal; + float4 m_contactNormal; + + float4 m_relpos2CrossNormal; + //float4 m_contactNormal2;//usually m_contactNormal2 == -m_contactNormal + + float4 m_angularComponentA; + float4 m_angularComponentB; + + float m_appliedPushImpulse; + float m_appliedImpulse; + int m_padding1; + int m_padding2; + float m_friction; + float m_jacDiagABInv; + float m_rhs; + float m_cfm; + + float m_lowerLimit; + float m_upperLimit; + float m_rhsPenetration; + int m_originalConstraint; + + + int m_overrideNumSolverIterations; + int m_frictionIndex; + int m_solverBodyIdA; + int m_solverBodyIdB; + +} b3SolverConstraint; + +typedef struct +{ + int m_bodyAPtrAndSignBit; + int m_bodyBPtrAndSignBit; + int m_originalConstraintIndex; + int m_batchId; +} b3BatchConstraint; + + + + + + +typedef struct +{ + int m_constraintType; + int m_rbA; + int m_rbB; + float m_breakingImpulseThreshold; + + float4 m_pivotInA; + float4 m_pivotInB; + Quaternion m_relTargetAB; + + int m_flags; + int m_padding[3]; +} b3GpuGenericConstraint; + + +/*b3Transform getWorldTransform(b3RigidBodyCL* rb) +{ + b3Transform newTrans; + newTrans.setOrigin(rb->m_pos); + newTrans.setRotation(rb->m_quat); + return newTrans; +}*/ + + + + +__inline +float4 cross3(float4 a, float4 b) +{ + return cross(a,b); +} + +__inline +float4 fastNormalize4(float4 v) +{ + v = mymake_float4(v.xyz,0.f); + return fast_normalize(v); +} + + +__inline +Quaternion qtMul(Quaternion a, Quaternion b); + +__inline +Quaternion qtNormalize(Quaternion in); + +__inline +float4 qtRotate(Quaternion q, float4 vec); + +__inline +Quaternion qtInvert(Quaternion q); + + + + +__inline +Quaternion qtMul(Quaternion a, Quaternion b) +{ + Quaternion ans; + ans = cross3( a, b ); + ans += a.w*b+b.w*a; +// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z); + ans.w = a.w*b.w - dot3F4(a, b); + return ans; +} + +__inline +Quaternion qtNormalize(Quaternion in) +{ + return fastNormalize4(in); +// in /= length( in ); +// return in; +} +__inline +float4 qtRotate(Quaternion q, float4 vec) +{ + Quaternion qInv = qtInvert( q ); + float4 vcpy = vec; + vcpy.w = 0.f; + float4 out = qtMul(qtMul(q,vcpy),qInv); + return out; +} + +__inline +Quaternion qtInvert(Quaternion q) +{ + return (Quaternion)(-q.xyz, q.w); +} + + +__inline void internalApplyImpulse(__global b3GpuSolverBody* body, float4 linearComponent, float4 angularComponent,float impulseMagnitude) +{ + body->m_deltaLinearVelocity += linearComponent*impulseMagnitude*body->m_linearFactor; + body->m_deltaAngularVelocity += angularComponent*(impulseMagnitude*body->m_angularFactor); +} + + +void resolveSingleConstraintRowGeneric(__global b3GpuSolverBody* body1, __global b3GpuSolverBody* body2, __global b3SolverConstraint* c) +{ + float deltaImpulse = c->m_rhs-c->m_appliedImpulse*c->m_cfm; + float deltaVel1Dotn = dot3F4(c->m_contactNormal,body1->m_deltaLinearVelocity) + dot3F4(c->m_relpos1CrossNormal,body1->m_deltaAngularVelocity); + float deltaVel2Dotn = -dot3F4(c->m_contactNormal,body2->m_deltaLinearVelocity) + dot3F4(c->m_relpos2CrossNormal,body2->m_deltaAngularVelocity); + + deltaImpulse -= deltaVel1Dotn*c->m_jacDiagABInv; + deltaImpulse -= deltaVel2Dotn*c->m_jacDiagABInv; + + float sum = c->m_appliedImpulse + deltaImpulse; + if (sum < c->m_lowerLimit) + { + deltaImpulse = c->m_lowerLimit-c->m_appliedImpulse; + c->m_appliedImpulse = c->m_lowerLimit; + } + else if (sum > c->m_upperLimit) + { + deltaImpulse = c->m_upperLimit-c->m_appliedImpulse; + c->m_appliedImpulse = c->m_upperLimit; + } + else + { + c->m_appliedImpulse = sum; + } + + internalApplyImpulse(body1,c->m_contactNormal*body1->m_invMass,c->m_angularComponentA,deltaImpulse); + internalApplyImpulse(body2,-c->m_contactNormal*body2->m_invMass,c->m_angularComponentB,deltaImpulse); + +} + +__kernel void solveJointConstraintRows(__global b3GpuSolverBody* solverBodies, + __global b3BatchConstraint* batchConstraints, + __global b3SolverConstraint* rows, + __global unsigned int* numConstraintRowsInfo1, + __global unsigned int* rowOffsets, + __global b3GpuGenericConstraint* constraints, + int batchOffset, + int numConstraintsInBatch + ) +{ + int b = get_global_id(0); + if (b>=numConstraintsInBatch) + return; + + __global b3BatchConstraint* c = &batchConstraints[b+batchOffset]; + int originalConstraintIndex = c->m_originalConstraintIndex; + if (constraints[originalConstraintIndex].m_flags&B3_CONSTRAINT_FLAG_ENABLED) + { + int numConstraintRows = numConstraintRowsInfo1[originalConstraintIndex]; + int rowOffset = rowOffsets[originalConstraintIndex]; + for (int jj=0;jjm_solverBodyIdA],&solverBodies[constraint->m_solverBodyIdB],constraint); + } + } +}; + +__kernel void initSolverBodies(__global b3GpuSolverBody* solverBodies,__global b3RigidBodyCL* bodiesCL, int numBodies) +{ + int i = get_global_id(0); + if (i>=numBodies) + return; + + __global b3GpuSolverBody* solverBody = &solverBodies[i]; + __global b3RigidBodyCL* bodyCL = &bodiesCL[i]; + + solverBody->m_deltaLinearVelocity = (float4)(0.f,0.f,0.f,0.f); + solverBody->m_deltaAngularVelocity = (float4)(0.f,0.f,0.f,0.f); + solverBody->m_pushVelocity = (float4)(0.f,0.f,0.f,0.f); + solverBody->m_pushVelocity = (float4)(0.f,0.f,0.f,0.f); + solverBody->m_invMass = (float4)(bodyCL->m_invMass,bodyCL->m_invMass,bodyCL->m_invMass,0.f); + solverBody->m_originalBodyIndex = i; + solverBody->m_angularFactor = (float4)(1,1,1,0); + solverBody->m_linearFactor = (float4) (1,1,1,0); + solverBody->m_linearVelocity = bodyCL->m_linVel; + solverBody->m_angularVelocity = bodyCL->m_angVel; +} + +__kernel void breakViolatedConstraintsKernel(__global b3GpuGenericConstraint* constraints, __global unsigned int* numConstraintRows, __global unsigned int* rowOffsets, __global b3SolverConstraint* rows, int numConstraints) +{ + int cid = get_global_id(0); + if (cid>=numConstraints) + return; + int numRows = numConstraintRows[cid]; + if (numRows) + { + for (int i=0;i= breakingThreshold) + { + constraints[cid].m_flags =0;//&= ~B3_CONSTRAINT_FLAG_ENABLED; + } + } + } +} + + + +__kernel void getInfo1Kernel(__global unsigned int* infos, __global b3GpuGenericConstraint* constraints, int numConstraints) +{ + int i = get_global_id(0); + if (i>=numConstraints) + return; + + __global b3GpuGenericConstraint* constraint = &constraints[i]; + + switch (constraint->m_constraintType) + { + case B3_GPU_POINT2POINT_CONSTRAINT_TYPE: + { + infos[i] = 3; + break; + } + case B3_GPU_FIXED_CONSTRAINT_TYPE: + { + infos[i] = 6; + break; + } + default: + { + } + } +} + +__kernel void initBatchConstraintsKernel(__global unsigned int* numConstraintRows, __global unsigned int* rowOffsets, + __global b3BatchConstraint* batchConstraints, + __global b3GpuGenericConstraint* constraints, + __global b3RigidBodyCL* bodies, + int numConstraints) +{ + int i = get_global_id(0); + if (i>=numConstraints) + return; + + int rbA = constraints[i].m_rbA; + int rbB = constraints[i].m_rbB; + + batchConstraints[i].m_bodyAPtrAndSignBit = bodies[rbA].m_invMass != 0.f ? rbA : -rbA; + batchConstraints[i].m_bodyBPtrAndSignBit = bodies[rbB].m_invMass != 0.f ? rbB : -rbB; + batchConstraints[i].m_batchId = -1; + batchConstraints[i].m_originalConstraintIndex = i; + +} + + + + +typedef struct +{ + // integrator parameters: frames per second (1/stepsize), default error + // reduction parameter (0..1). + float 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. + union + { + __global float4* m_J1linearAxisFloat4; + __global float* m_J1linearAxis; + }; + union + { + __global float4* m_J1angularAxisFloat4; + __global float* m_J1angularAxis; + + }; + union + { + __global float4* m_J2linearAxisFloat4; + __global float* m_J2linearAxis; + }; + union + { + __global float4* m_J2angularAxisFloat4; + __global float* m_J2angularAxis; + }; + // 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. + __global float* m_constraintError; + __global float* cfm; + + // lo and hi limits for variables (set to -/+ infinity on entry). + __global float* m_lowerLimit; + __global float* m_upperLimit; + + // 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. + __global int *findex; + // number of solver iterations + int m_numIterations; + + //damping of the velocity + float m_damping; +} b3GpuConstraintInfo2; + + +void getSkewSymmetricMatrix(float4 vecIn, __global float4* v0,__global float4* v1,__global float4* v2) +{ + *v0 = (float4)(0. ,-vecIn.z ,vecIn.y,0.f); + *v1 = (float4)(vecIn.z ,0. ,-vecIn.x,0.f); + *v2 = (float4)(-vecIn.y ,vecIn.x ,0.f,0.f); +} + + +void getInfo2Point2Point(__global b3GpuGenericConstraint* constraint,b3GpuConstraintInfo2* info,__global b3RigidBodyCL* bodies) +{ + float4 posA = bodies[constraint->m_rbA].m_pos; + Quaternion rotA = bodies[constraint->m_rbA].m_quat; + + float4 posB = bodies[constraint->m_rbB].m_pos; + Quaternion rotB = bodies[constraint->m_rbB].m_quat; + + + + // anchor points in global coordinates with respect to body PORs. + + // set jacobian + info->m_J1linearAxis[0] = 1; + info->m_J1linearAxis[info->rowskip+1] = 1; + info->m_J1linearAxis[2*info->rowskip+2] = 1; + + float4 a1 = qtRotate(rotA,constraint->m_pivotInA); + + { + __global float4* angular0 = (__global float4*)(info->m_J1angularAxis); + __global float4* angular1 = (__global float4*)(info->m_J1angularAxis+info->rowskip); + __global float4* angular2 = (__global float4*)(info->m_J1angularAxis+2*info->rowskip); + float4 a1neg = -a1; + getSkewSymmetricMatrix(a1neg,angular0,angular1,angular2); + } + if (info->m_J2linearAxis) + { + info->m_J2linearAxis[0] = -1; + info->m_J2linearAxis[info->rowskip+1] = -1; + info->m_J2linearAxis[2*info->rowskip+2] = -1; + } + + float4 a2 = qtRotate(rotB,constraint->m_pivotInB); + + { + // float4 a2n = -a2; + __global float4* angular0 = (__global float4*)(info->m_J2angularAxis); + __global float4* angular1 = (__global float4*)(info->m_J2angularAxis+info->rowskip); + __global float4* angular2 = (__global float4*)(info->m_J2angularAxis+2*info->rowskip); + getSkewSymmetricMatrix(a2,angular0,angular1,angular2); + } + + // set right hand side +// float currERP = (m_flags & B3_P2P_FLAGS_ERP) ? m_erp : info->erp; + float currERP = info->erp; + + float k = info->fps * currERP; + int j; + float4 result = a2 + posB - a1 - posA; + float* resultPtr = &result; + + for (j=0; j<3; j++) + { + info->m_constraintError[j*info->rowskip] = k * (resultPtr[j]); + } +} + +Quaternion nearest( Quaternion first, Quaternion qd) +{ + Quaternion diff,sum; + diff = first- qd; + sum = first + qd; + + if( dot(diff,diff) < dot(sum,sum) ) + return qd; + return (-qd); +} + +float b3Acos(float x) +{ + if (x<-1) + x=-1; + if (x>1) + x=1; + return acos(x); +} + +float getAngle(Quaternion orn) +{ + if (orn.w>=1.f) + orn.w=1.f; + float s = 2.f * b3Acos(orn.w); + return s; +} + +void calculateDiffAxisAngleQuaternion( Quaternion orn0,Quaternion orn1a,float4* axis,float* angle) +{ + Quaternion orn1 = nearest(orn0,orn1a); + + Quaternion dorn = qtMul(orn1,qtInvert(orn0)); + *angle = getAngle(dorn); + *axis = (float4)(dorn.x,dorn.y,dorn.z,0.f); + + //check for axis length + float len = dot3F4(*axis,*axis); + if (len < FLT_EPSILON*FLT_EPSILON) + *axis = (float4)(1,0,0,0); + else + *axis /= sqrt(len); +} + + + +void getInfo2FixedOrientation(__global b3GpuGenericConstraint* constraint,b3GpuConstraintInfo2* info,__global b3RigidBodyCL* bodies, int start_row) +{ + Quaternion worldOrnA = bodies[constraint->m_rbA].m_quat; + Quaternion worldOrnB = bodies[constraint->m_rbB].m_quat; + + int s = info->rowskip; + int start_index = start_row * s; + + // 3 rows to make body rotations equal + info->m_J1angularAxis[start_index] = 1; + info->m_J1angularAxis[start_index + s + 1] = 1; + info->m_J1angularAxis[start_index + s*2+2] = 1; + if ( info->m_J2angularAxis) + { + info->m_J2angularAxis[start_index] = -1; + info->m_J2angularAxis[start_index + s+1] = -1; + info->m_J2angularAxis[start_index + s*2+2] = -1; + } + + float currERP = info->erp; + float k = info->fps * currERP; + float4 diff; + float angle; + float4 qrelCur = qtMul(worldOrnA,qtInvert(worldOrnB)); + + calculateDiffAxisAngleQuaternion(constraint->m_relTargetAB,qrelCur,&diff,&angle); + diff*=-angle; + + float* resultPtr = &diff; + + for (int j=0; j<3; j++) + { + info->m_constraintError[(3+j)*info->rowskip] = k * resultPtr[j]; + } + + +} + + +__kernel void writeBackVelocitiesKernel(__global b3RigidBodyCL* bodies,__global b3GpuSolverBody* solverBodies,int numBodies) +{ + int i = get_global_id(0); + if (i>=numBodies) + return; + + if (bodies[i].m_invMass) + { +// if (length(solverBodies[i].m_deltaLinearVelocity)=numConstraints) + return; + + //for now, always initialize the batch info + int info1 = infos[i]; + + __global b3SolverConstraint* currentConstraintRow = &solverConstraintRows[constraintRowOffsets[i]]; + __global b3GpuGenericConstraint* constraint = &constraints[i]; + + __global b3RigidBodyCL* rbA = &bodies[ constraint->m_rbA]; + __global b3RigidBodyCL* rbB = &bodies[ constraint->m_rbB]; + + int solverBodyIdA = constraint->m_rbA; + int solverBodyIdB = constraint->m_rbB; + + __global b3GpuSolverBody* bodyAPtr = &solverBodies[solverBodyIdA]; + __global b3GpuSolverBody* bodyBPtr = &solverBodies[solverBodyIdB]; + + + if (rbA->m_invMass) + { + batchConstraints[i].m_bodyAPtrAndSignBit = solverBodyIdA; + } else + { +// if (!solverBodyIdA) +// m_staticIdx = 0; + batchConstraints[i].m_bodyAPtrAndSignBit = -solverBodyIdA; + } + + if (rbB->m_invMass) + { + batchConstraints[i].m_bodyBPtrAndSignBit = solverBodyIdB; + } else + { +// if (!solverBodyIdB) +// m_staticIdx = 0; + batchConstraints[i].m_bodyBPtrAndSignBit = -solverBodyIdB; + } + + if (info1) + { + int overrideNumSolverIterations = 0;//constraint->getOverrideNumSolverIterations() > 0 ? constraint->getOverrideNumSolverIterations() : infoGlobal.m_numIterations; +// if (overrideNumSolverIterations>m_maxOverrideNumSolverIterations) + // m_maxOverrideNumSolverIterations = overrideNumSolverIterations; + + + int j; + for ( j=0;jm_deltaLinearVelocity = (float4)(0,0,0,0); + bodyAPtr->m_deltaAngularVelocity = (float4)(0,0,0,0); + bodyAPtr->m_pushVelocity = (float4)(0,0,0,0); + bodyAPtr->m_turnVelocity = (float4)(0,0,0,0); + bodyBPtr->m_deltaLinearVelocity = (float4)(0,0,0,0); + bodyBPtr->m_deltaAngularVelocity = (float4)(0,0,0,0); + bodyBPtr->m_pushVelocity = (float4)(0,0,0,0); + bodyBPtr->m_turnVelocity = (float4)(0,0,0,0); + + int rowskip = sizeof(b3SolverConstraint)/sizeof(float);//check this + + + + + b3GpuConstraintInfo2 info2; + info2.fps = 1.f/timeStep; + info2.erp = globalErp; + info2.m_J1linearAxisFloat4 = ¤tConstraintRow->m_contactNormal; + info2.m_J1angularAxisFloat4 = ¤tConstraintRow->m_relpos1CrossNormal; + info2.m_J2linearAxisFloat4 = 0; + info2.m_J2angularAxisFloat4 = ¤tConstraintRow->m_relpos2CrossNormal; + info2.rowskip = sizeof(b3SolverConstraint)/sizeof(float);//check this + + ///the size of b3SolverConstraint needs be a multiple of float +// b3Assert(info2.rowskip*sizeof(float)== sizeof(b3SolverConstraint)); + info2.m_constraintError = ¤tConstraintRow->m_rhs; + currentConstraintRow->m_cfm = globalCfm; + info2.m_damping = globalDamping; + info2.cfm = ¤tConstraintRow->m_cfm; + info2.m_lowerLimit = ¤tConstraintRow->m_lowerLimit; + info2.m_upperLimit = ¤tConstraintRow->m_upperLimit; + info2.m_numIterations = globalNumIterations; + + switch (constraint->m_constraintType) + { + case B3_GPU_POINT2POINT_CONSTRAINT_TYPE: + { + getInfo2Point2Point(constraint,&info2,bodies); + break; + } + case B3_GPU_FIXED_CONSTRAINT_TYPE: + { + getInfo2Point2Point(constraint,&info2,bodies); + + getInfo2FixedOrientation(constraint,&info2,bodies,3); + + break; + } + + default: + { + } + } + + ///finalize the constraint setup + for ( j=0;jm_upperLimit>=constraint->m_breakingImpulseThreshold) + { + solverConstraint->m_upperLimit = constraint->m_breakingImpulseThreshold; + } + + if (solverConstraint->m_lowerLimit<=-constraint->m_breakingImpulseThreshold) + { + solverConstraint->m_lowerLimit = -constraint->m_breakingImpulseThreshold; + } + +// solverConstraint->m_originalContactPoint = constraint; + + Matrix3x3 invInertiaWorldA= inertias[constraint->m_rbA].m_invInertiaWorld; + { + + //float4 angularFactorA(1,1,1); + float4 ftorqueAxis1 = solverConstraint->m_relpos1CrossNormal; + solverConstraint->m_angularComponentA = mtMul1(invInertiaWorldA,ftorqueAxis1);//*angularFactorA; + } + + Matrix3x3 invInertiaWorldB= inertias[constraint->m_rbB].m_invInertiaWorld; + { + + float4 ftorqueAxis2 = solverConstraint->m_relpos2CrossNormal; + solverConstraint->m_angularComponentB = mtMul1(invInertiaWorldB,ftorqueAxis2);//*constraint->m_rbB.getAngularFactor(); + } + + { + //it is ok to use solverConstraint->m_contactNormal instead of -solverConstraint->m_contactNormal + //because it gets multiplied iMJlB + float4 iMJlA = solverConstraint->m_contactNormal*rbA->m_invMass; + float4 iMJaA = mtMul3(solverConstraint->m_relpos1CrossNormal,invInertiaWorldA); + float4 iMJlB = solverConstraint->m_contactNormal*rbB->m_invMass;//sign of normal? + float4 iMJaB = mtMul3(solverConstraint->m_relpos2CrossNormal,invInertiaWorldB); + + float sum = dot3F4(iMJlA,solverConstraint->m_contactNormal); + sum += dot3F4(iMJaA,solverConstraint->m_relpos1CrossNormal); + sum += dot3F4(iMJlB,solverConstraint->m_contactNormal); + sum += dot3F4(iMJaB,solverConstraint->m_relpos2CrossNormal); + float fsum = fabs(sum); + if (fsum>FLT_EPSILON) + { + solverConstraint->m_jacDiagABInv = 1.f/sum; + } else + { + solverConstraint->m_jacDiagABInv = 0.f; + } + } + + + ///fix rhs + ///todo: add force/torque accelerators + { + float rel_vel; + float vel1Dotn = dot3F4(solverConstraint->m_contactNormal,rbA->m_linVel) + dot3F4(solverConstraint->m_relpos1CrossNormal,rbA->m_angVel); + float vel2Dotn = -dot3F4(solverConstraint->m_contactNormal,rbB->m_linVel) + dot3F4(solverConstraint->m_relpos2CrossNormal,rbB->m_angVel); + + rel_vel = vel1Dotn+vel2Dotn; + + float restitution = 0.f; + float positionalError = solverConstraint->m_rhs;//already filled in by getConstraintInfo2 + float velocityError = restitution - rel_vel * info2.m_damping; + float penetrationImpulse = positionalError*solverConstraint->m_jacDiagABInv; + float velocityImpulse = velocityError *solverConstraint->m_jacDiagABInv; + solverConstraint->m_rhs = penetrationImpulse+velocityImpulse; + solverConstraint->m_appliedImpulse = 0.f; + + } + } + } +} diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/jointSolver.h b/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/jointSolver.h new file mode 100644 index 000000000000..d48ecf6ea660 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/jointSolver.h @@ -0,0 +1,721 @@ +//this file is autogenerated using stringify.bat (premake --stringify) in the build folder of this project +static const char* solveConstraintRowsCL= \ +"/*\n" +"Copyright (c) 2013 Advanced Micro Devices, Inc. \n" +"This software is provided 'as-is', without any express or implied warranty.\n" +"In no event will the authors be held liable for any damages arising from the use of this software.\n" +"Permission is granted to anyone to use this software for any purpose, \n" +"including commercial applications, and to alter it and redistribute it freely, \n" +"subject to the following restrictions:\n" +"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.\n" +"2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n" +"3. This notice may not be removed or altered from any source distribution.\n" +"*/\n" +"//Originally written by Erwin Coumans\n" +"#define B3_CONSTRAINT_FLAG_ENABLED 1\n" +"#define B3_GPU_POINT2POINT_CONSTRAINT_TYPE 3\n" +"#define B3_GPU_FIXED_CONSTRAINT_TYPE 4\n" +"#define MOTIONCLAMP 100000 //unused, for debugging/safety in case constraint solver fails\n" +"#define B3_INFINITY 1e30f\n" +"#define mymake_float4 (float4)\n" +"__inline float dot3F4(float4 a, float4 b)\n" +"{\n" +" float4 a1 = mymake_float4(a.xyz,0.f);\n" +" float4 b1 = mymake_float4(b.xyz,0.f);\n" +" return dot(a1, b1);\n" +"}\n" +"typedef float4 Quaternion;\n" +"typedef struct\n" +"{\n" +" float4 m_row[3];\n" +"}Matrix3x3;\n" +"__inline\n" +"float4 mtMul1(Matrix3x3 a, float4 b);\n" +"__inline\n" +"float4 mtMul3(float4 a, Matrix3x3 b);\n" +"__inline\n" +"float4 mtMul1(Matrix3x3 a, float4 b)\n" +"{\n" +" float4 ans;\n" +" ans.x = dot3F4( a.m_row[0], b );\n" +" ans.y = dot3F4( a.m_row[1], b );\n" +" ans.z = dot3F4( a.m_row[2], b );\n" +" ans.w = 0.f;\n" +" return ans;\n" +"}\n" +"__inline\n" +"float4 mtMul3(float4 a, Matrix3x3 b)\n" +"{\n" +" float4 colx = mymake_float4(b.m_row[0].x, b.m_row[1].x, b.m_row[2].x, 0);\n" +" float4 coly = mymake_float4(b.m_row[0].y, b.m_row[1].y, b.m_row[2].y, 0);\n" +" float4 colz = mymake_float4(b.m_row[0].z, b.m_row[1].z, b.m_row[2].z, 0);\n" +" float4 ans;\n" +" ans.x = dot3F4( a, colx );\n" +" ans.y = dot3F4( a, coly );\n" +" ans.z = dot3F4( a, colz );\n" +" return ans;\n" +"}\n" +"typedef struct\n" +"{\n" +" Matrix3x3 m_invInertiaWorld;\n" +" Matrix3x3 m_initInvInertia;\n" +"} BodyInertia;\n" +"typedef struct\n" +"{\n" +" Matrix3x3 m_basis;//orientation\n" +" float4 m_origin;//transform\n" +"}b3Transform;\n" +"typedef struct\n" +"{\n" +"// b3Transform m_worldTransformUnused;\n" +" float4 m_deltaLinearVelocity;\n" +" float4 m_deltaAngularVelocity;\n" +" float4 m_angularFactor;\n" +" float4 m_linearFactor;\n" +" float4 m_invMass;\n" +" float4 m_pushVelocity;\n" +" float4 m_turnVelocity;\n" +" float4 m_linearVelocity;\n" +" float4 m_angularVelocity;\n" +" union \n" +" {\n" +" void* m_originalBody;\n" +" int m_originalBodyIndex;\n" +" };\n" +" int padding[3];\n" +"} b3GpuSolverBody;\n" +"typedef struct\n" +"{\n" +" float4 m_pos;\n" +" Quaternion m_quat;\n" +" float4 m_linVel;\n" +" float4 m_angVel;\n" +" unsigned int m_shapeIdx;\n" +" float m_invMass;\n" +" float m_restituitionCoeff;\n" +" float m_frictionCoeff;\n" +"} b3RigidBodyCL;\n" +"typedef struct\n" +"{\n" +" float4 m_relpos1CrossNormal;\n" +" float4 m_contactNormal;\n" +" float4 m_relpos2CrossNormal;\n" +" //float4 m_contactNormal2;//usually m_contactNormal2 == -m_contactNormal\n" +" float4 m_angularComponentA;\n" +" float4 m_angularComponentB;\n" +" \n" +" float m_appliedPushImpulse;\n" +" float m_appliedImpulse;\n" +" int m_padding1;\n" +" int m_padding2;\n" +" float m_friction;\n" +" float m_jacDiagABInv;\n" +" float m_rhs;\n" +" float m_cfm;\n" +" \n" +" float m_lowerLimit;\n" +" float m_upperLimit;\n" +" float m_rhsPenetration;\n" +" int m_originalConstraint;\n" +" int m_overrideNumSolverIterations;\n" +" int m_frictionIndex;\n" +" int m_solverBodyIdA;\n" +" int m_solverBodyIdB;\n" +"} b3SolverConstraint;\n" +"typedef struct \n" +"{\n" +" int m_bodyAPtrAndSignBit;\n" +" int m_bodyBPtrAndSignBit;\n" +" int m_originalConstraintIndex;\n" +" int m_batchId;\n" +"} b3BatchConstraint;\n" +"typedef struct \n" +"{\n" +" int m_constraintType;\n" +" int m_rbA;\n" +" int m_rbB;\n" +" float m_breakingImpulseThreshold;\n" +" float4 m_pivotInA;\n" +" float4 m_pivotInB;\n" +" Quaternion m_relTargetAB;\n" +" int m_flags;\n" +" int m_padding[3];\n" +"} b3GpuGenericConstraint;\n" +"/*b3Transform getWorldTransform(b3RigidBodyCL* rb)\n" +"{\n" +" b3Transform newTrans;\n" +" newTrans.setOrigin(rb->m_pos);\n" +" newTrans.setRotation(rb->m_quat);\n" +" return newTrans;\n" +"}*/\n" +"__inline\n" +"float4 cross3(float4 a, float4 b)\n" +"{\n" +" return cross(a,b);\n" +"}\n" +"__inline\n" +"float4 fastNormalize4(float4 v)\n" +"{\n" +" v = mymake_float4(v.xyz,0.f);\n" +" return fast_normalize(v);\n" +"}\n" +"__inline\n" +"Quaternion qtMul(Quaternion a, Quaternion b);\n" +"__inline\n" +"Quaternion qtNormalize(Quaternion in);\n" +"__inline\n" +"float4 qtRotate(Quaternion q, float4 vec);\n" +"__inline\n" +"Quaternion qtInvert(Quaternion q);\n" +"__inline\n" +"Quaternion qtMul(Quaternion a, Quaternion b)\n" +"{\n" +" Quaternion ans;\n" +" ans = cross3( a, b );\n" +" ans += a.w*b+b.w*a;\n" +"// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z);\n" +" ans.w = a.w*b.w - dot3F4(a, b);\n" +" return ans;\n" +"}\n" +"__inline\n" +"Quaternion qtNormalize(Quaternion in)\n" +"{\n" +" return fastNormalize4(in);\n" +"// in /= length( in );\n" +"// return in;\n" +"}\n" +"__inline\n" +"float4 qtRotate(Quaternion q, float4 vec)\n" +"{\n" +" Quaternion qInv = qtInvert( q );\n" +" float4 vcpy = vec;\n" +" vcpy.w = 0.f;\n" +" float4 out = qtMul(qtMul(q,vcpy),qInv);\n" +" return out;\n" +"}\n" +"__inline\n" +"Quaternion qtInvert(Quaternion q)\n" +"{\n" +" return (Quaternion)(-q.xyz, q.w);\n" +"}\n" +"__inline void internalApplyImpulse(__global b3GpuSolverBody* body, float4 linearComponent, float4 angularComponent,float impulseMagnitude)\n" +"{\n" +" body->m_deltaLinearVelocity += linearComponent*impulseMagnitude*body->m_linearFactor;\n" +" body->m_deltaAngularVelocity += angularComponent*(impulseMagnitude*body->m_angularFactor);\n" +"}\n" +"void resolveSingleConstraintRowGeneric(__global b3GpuSolverBody* body1, __global b3GpuSolverBody* body2, __global b3SolverConstraint* c)\n" +"{\n" +" float deltaImpulse = c->m_rhs-c->m_appliedImpulse*c->m_cfm;\n" +" float deltaVel1Dotn = dot3F4(c->m_contactNormal,body1->m_deltaLinearVelocity) + dot3F4(c->m_relpos1CrossNormal,body1->m_deltaAngularVelocity);\n" +" float deltaVel2Dotn = -dot3F4(c->m_contactNormal,body2->m_deltaLinearVelocity) + dot3F4(c->m_relpos2CrossNormal,body2->m_deltaAngularVelocity);\n" +" deltaImpulse -= deltaVel1Dotn*c->m_jacDiagABInv;\n" +" deltaImpulse -= deltaVel2Dotn*c->m_jacDiagABInv;\n" +" float sum = c->m_appliedImpulse + deltaImpulse;\n" +" if (sum < c->m_lowerLimit)\n" +" {\n" +" deltaImpulse = c->m_lowerLimit-c->m_appliedImpulse;\n" +" c->m_appliedImpulse = c->m_lowerLimit;\n" +" }\n" +" else if (sum > c->m_upperLimit) \n" +" {\n" +" deltaImpulse = c->m_upperLimit-c->m_appliedImpulse;\n" +" c->m_appliedImpulse = c->m_upperLimit;\n" +" }\n" +" else\n" +" {\n" +" c->m_appliedImpulse = sum;\n" +" }\n" +" internalApplyImpulse(body1,c->m_contactNormal*body1->m_invMass,c->m_angularComponentA,deltaImpulse);\n" +" internalApplyImpulse(body2,-c->m_contactNormal*body2->m_invMass,c->m_angularComponentB,deltaImpulse);\n" +"}\n" +"__kernel void solveJointConstraintRows(__global b3GpuSolverBody* solverBodies,\n" +" __global b3BatchConstraint* batchConstraints,\n" +" __global b3SolverConstraint* rows,\n" +" __global unsigned int* numConstraintRowsInfo1, \n" +" __global unsigned int* rowOffsets,\n" +" __global b3GpuGenericConstraint* constraints,\n" +" int batchOffset,\n" +" int numConstraintsInBatch\n" +" )\n" +"{\n" +" int b = get_global_id(0);\n" +" if (b>=numConstraintsInBatch)\n" +" return;\n" +" __global b3BatchConstraint* c = &batchConstraints[b+batchOffset];\n" +" int originalConstraintIndex = c->m_originalConstraintIndex;\n" +" if (constraints[originalConstraintIndex].m_flags&B3_CONSTRAINT_FLAG_ENABLED)\n" +" {\n" +" int numConstraintRows = numConstraintRowsInfo1[originalConstraintIndex];\n" +" int rowOffset = rowOffsets[originalConstraintIndex];\n" +" for (int jj=0;jjm_solverBodyIdA],&solverBodies[constraint->m_solverBodyIdB],constraint);\n" +" }\n" +" }\n" +"};\n" +"__kernel void initSolverBodies(__global b3GpuSolverBody* solverBodies,__global b3RigidBodyCL* bodiesCL, int numBodies)\n" +"{\n" +" int i = get_global_id(0);\n" +" if (i>=numBodies)\n" +" return;\n" +" __global b3GpuSolverBody* solverBody = &solverBodies[i];\n" +" __global b3RigidBodyCL* bodyCL = &bodiesCL[i];\n" +" solverBody->m_deltaLinearVelocity = (float4)(0.f,0.f,0.f,0.f);\n" +" solverBody->m_deltaAngularVelocity = (float4)(0.f,0.f,0.f,0.f);\n" +" solverBody->m_pushVelocity = (float4)(0.f,0.f,0.f,0.f);\n" +" solverBody->m_pushVelocity = (float4)(0.f,0.f,0.f,0.f);\n" +" solverBody->m_invMass = (float4)(bodyCL->m_invMass,bodyCL->m_invMass,bodyCL->m_invMass,0.f);\n" +" solverBody->m_originalBodyIndex = i;\n" +" solverBody->m_angularFactor = (float4)(1,1,1,0);\n" +" solverBody->m_linearFactor = (float4) (1,1,1,0);\n" +" solverBody->m_linearVelocity = bodyCL->m_linVel;\n" +" solverBody->m_angularVelocity = bodyCL->m_angVel;\n" +"}\n" +"__kernel void breakViolatedConstraintsKernel(__global b3GpuGenericConstraint* constraints, __global unsigned int* numConstraintRows, __global unsigned int* rowOffsets, __global b3SolverConstraint* rows, int numConstraints)\n" +"{\n" +" int cid = get_global_id(0);\n" +" if (cid>=numConstraints)\n" +" return;\n" +" int numRows = numConstraintRows[cid];\n" +" if (numRows)\n" +" {\n" +" for (int i=0;i= breakingThreshold)\n" +" {\n" +" constraints[cid].m_flags =0;//&= ~B3_CONSTRAINT_FLAG_ENABLED;\n" +" }\n" +" }\n" +" }\n" +"}\n" +"__kernel void getInfo1Kernel(__global unsigned int* infos, __global b3GpuGenericConstraint* constraints, int numConstraints)\n" +"{\n" +" int i = get_global_id(0);\n" +" if (i>=numConstraints)\n" +" return;\n" +" __global b3GpuGenericConstraint* constraint = &constraints[i];\n" +" switch (constraint->m_constraintType)\n" +" {\n" +" case B3_GPU_POINT2POINT_CONSTRAINT_TYPE:\n" +" {\n" +" infos[i] = 3;\n" +" break;\n" +" }\n" +" case B3_GPU_FIXED_CONSTRAINT_TYPE:\n" +" {\n" +" infos[i] = 6;\n" +" break;\n" +" }\n" +" default:\n" +" {\n" +" }\n" +" }\n" +"}\n" +"__kernel void initBatchConstraintsKernel(__global unsigned int* numConstraintRows, __global unsigned int* rowOffsets, \n" +" __global b3BatchConstraint* batchConstraints, \n" +" __global b3GpuGenericConstraint* constraints,\n" +" __global b3RigidBodyCL* bodies,\n" +" int numConstraints)\n" +"{\n" +" int i = get_global_id(0);\n" +" if (i>=numConstraints)\n" +" return;\n" +" int rbA = constraints[i].m_rbA;\n" +" int rbB = constraints[i].m_rbB;\n" +" batchConstraints[i].m_bodyAPtrAndSignBit = bodies[rbA].m_invMass != 0.f ? rbA : -rbA;\n" +" batchConstraints[i].m_bodyBPtrAndSignBit = bodies[rbB].m_invMass != 0.f ? rbB : -rbB;\n" +" batchConstraints[i].m_batchId = -1;\n" +" batchConstraints[i].m_originalConstraintIndex = i;\n" +"}\n" +"typedef struct\n" +"{\n" +" // integrator parameters: frames per second (1/stepsize), default error\n" +" // reduction parameter (0..1).\n" +" float fps,erp;\n" +" // for the first and second body, pointers to two (linear and angular)\n" +" // n*3 jacobian sub matrices, stored by rows. these matrices will have\n" +" // been initialized to 0 on entry. if the second body is zero then the\n" +" // J2xx pointers may be 0.\n" +" union \n" +" {\n" +" __global float4* m_J1linearAxisFloat4;\n" +" __global float* m_J1linearAxis;\n" +" };\n" +" union\n" +" {\n" +" __global float4* m_J1angularAxisFloat4;\n" +" __global float* m_J1angularAxis;\n" +" };\n" +" union\n" +" {\n" +" __global float4* m_J2linearAxisFloat4;\n" +" __global float* m_J2linearAxis;\n" +" };\n" +" union\n" +" {\n" +" __global float4* m_J2angularAxisFloat4;\n" +" __global float* m_J2angularAxis;\n" +" };\n" +" // elements to jump from one row to the next in J's\n" +" int rowskip;\n" +" // right hand sides of the equation J*v = c + cfm * lambda. cfm is the\n" +" // \"constraint force mixing\" vector. c is set to zero on entry, cfm is\n" +" // set to a constant value (typically very small or zero) value on entry.\n" +" __global float* m_constraintError;\n" +" __global float* cfm;\n" +" // lo and hi limits for variables (set to -/+ infinity on entry).\n" +" __global float* m_lowerLimit;\n" +" __global float* m_upperLimit;\n" +" // findex vector for variables. see the LCP solver interface for a\n" +" // description of what this does. this is set to -1 on entry.\n" +" // note that the returned indexes are relative to the first index of\n" +" // the constraint.\n" +" __global int *findex;\n" +" // number of solver iterations\n" +" int m_numIterations;\n" +" //damping of the velocity\n" +" float m_damping;\n" +"} b3GpuConstraintInfo2;\n" +"void getSkewSymmetricMatrix(float4 vecIn, __global float4* v0,__global float4* v1,__global float4* v2)\n" +"{\n" +" *v0 = (float4)(0. ,-vecIn.z ,vecIn.y,0.f);\n" +" *v1 = (float4)(vecIn.z ,0. ,-vecIn.x,0.f);\n" +" *v2 = (float4)(-vecIn.y ,vecIn.x ,0.f,0.f);\n" +"}\n" +"void getInfo2Point2Point(__global b3GpuGenericConstraint* constraint,b3GpuConstraintInfo2* info,__global b3RigidBodyCL* bodies)\n" +"{\n" +" float4 posA = bodies[constraint->m_rbA].m_pos;\n" +" Quaternion rotA = bodies[constraint->m_rbA].m_quat;\n" +" float4 posB = bodies[constraint->m_rbB].m_pos;\n" +" Quaternion rotB = bodies[constraint->m_rbB].m_quat;\n" +" // anchor points in global coordinates with respect to body PORs.\n" +" \n" +" // set jacobian\n" +" info->m_J1linearAxis[0] = 1;\n" +" info->m_J1linearAxis[info->rowskip+1] = 1;\n" +" info->m_J1linearAxis[2*info->rowskip+2] = 1;\n" +" float4 a1 = qtRotate(rotA,constraint->m_pivotInA);\n" +" {\n" +" __global float4* angular0 = (__global float4*)(info->m_J1angularAxis);\n" +" __global float4* angular1 = (__global float4*)(info->m_J1angularAxis+info->rowskip);\n" +" __global float4* angular2 = (__global float4*)(info->m_J1angularAxis+2*info->rowskip);\n" +" float4 a1neg = -a1;\n" +" getSkewSymmetricMatrix(a1neg,angular0,angular1,angular2);\n" +" }\n" +" if (info->m_J2linearAxis)\n" +" {\n" +" info->m_J2linearAxis[0] = -1;\n" +" info->m_J2linearAxis[info->rowskip+1] = -1;\n" +" info->m_J2linearAxis[2*info->rowskip+2] = -1;\n" +" }\n" +" \n" +" float4 a2 = qtRotate(rotB,constraint->m_pivotInB);\n" +" \n" +" {\n" +" // float4 a2n = -a2;\n" +" __global float4* angular0 = (__global float4*)(info->m_J2angularAxis);\n" +" __global float4* angular1 = (__global float4*)(info->m_J2angularAxis+info->rowskip);\n" +" __global float4* angular2 = (__global float4*)(info->m_J2angularAxis+2*info->rowskip);\n" +" getSkewSymmetricMatrix(a2,angular0,angular1,angular2);\n" +" }\n" +" \n" +" // set right hand side\n" +"// float currERP = (m_flags & B3_P2P_FLAGS_ERP) ? m_erp : info->erp;\n" +" float currERP = info->erp;\n" +" float k = info->fps * currERP;\n" +" int j;\n" +" float4 result = a2 + posB - a1 - posA;\n" +" float* resultPtr = &result;\n" +" for (j=0; j<3; j++)\n" +" {\n" +" info->m_constraintError[j*info->rowskip] = k * (resultPtr[j]);\n" +" }\n" +"}\n" +"Quaternion nearest( Quaternion first, Quaternion qd)\n" +"{\n" +" Quaternion diff,sum;\n" +" diff = first- qd;\n" +" sum = first + qd;\n" +" \n" +" if( dot(diff,diff) < dot(sum,sum) )\n" +" return qd;\n" +" return (-qd);\n" +"}\n" +"float b3Acos(float x) \n" +"{ \n" +" if (x<-1) \n" +" x=-1; \n" +" if (x>1) \n" +" x=1;\n" +" return acos(x); \n" +"}\n" +"float getAngle(Quaternion orn)\n" +"{\n" +" if (orn.w>=1.f)\n" +" orn.w=1.f;\n" +" float s = 2.f * b3Acos(orn.w);\n" +" return s;\n" +"}\n" +"void calculateDiffAxisAngleQuaternion( Quaternion orn0,Quaternion orn1a,float4* axis,float* angle)\n" +"{\n" +" Quaternion orn1 = nearest(orn0,orn1a);\n" +" \n" +" Quaternion dorn = qtMul(orn1,qtInvert(orn0));\n" +" *angle = getAngle(dorn);\n" +" *axis = (float4)(dorn.x,dorn.y,dorn.z,0.f);\n" +" \n" +" //check for axis length\n" +" float len = dot3F4(*axis,*axis);\n" +" if (len < FLT_EPSILON*FLT_EPSILON)\n" +" *axis = (float4)(1,0,0,0);\n" +" else\n" +" *axis /= sqrt(len);\n" +"}\n" +"void getInfo2FixedOrientation(__global b3GpuGenericConstraint* constraint,b3GpuConstraintInfo2* info,__global b3RigidBodyCL* bodies, int start_row)\n" +"{\n" +" Quaternion worldOrnA = bodies[constraint->m_rbA].m_quat;\n" +" Quaternion worldOrnB = bodies[constraint->m_rbB].m_quat;\n" +" int s = info->rowskip;\n" +" int start_index = start_row * s;\n" +" // 3 rows to make body rotations equal\n" +" info->m_J1angularAxis[start_index] = 1;\n" +" info->m_J1angularAxis[start_index + s + 1] = 1;\n" +" info->m_J1angularAxis[start_index + s*2+2] = 1;\n" +" if ( info->m_J2angularAxis)\n" +" {\n" +" info->m_J2angularAxis[start_index] = -1;\n" +" info->m_J2angularAxis[start_index + s+1] = -1;\n" +" info->m_J2angularAxis[start_index + s*2+2] = -1;\n" +" }\n" +" \n" +" float currERP = info->erp;\n" +" float k = info->fps * currERP;\n" +" float4 diff;\n" +" float angle;\n" +" float4 qrelCur = qtMul(worldOrnA,qtInvert(worldOrnB));\n" +" \n" +" calculateDiffAxisAngleQuaternion(constraint->m_relTargetAB,qrelCur,&diff,&angle);\n" +" diff*=-angle;\n" +" \n" +" float* resultPtr = &diff;\n" +" \n" +" for (int j=0; j<3; j++)\n" +" {\n" +" info->m_constraintError[(3+j)*info->rowskip] = k * resultPtr[j];\n" +" }\n" +" \n" +"}\n" +"__kernel void writeBackVelocitiesKernel(__global b3RigidBodyCL* bodies,__global b3GpuSolverBody* solverBodies,int numBodies)\n" +"{\n" +" int i = get_global_id(0);\n" +" if (i>=numBodies)\n" +" return;\n" +" if (bodies[i].m_invMass)\n" +" {\n" +"// if (length(solverBodies[i].m_deltaLinearVelocity)=numConstraints)\n" +" return;\n" +" \n" +" //for now, always initialize the batch info\n" +" int info1 = infos[i];\n" +" \n" +" __global b3SolverConstraint* currentConstraintRow = &solverConstraintRows[constraintRowOffsets[i]];\n" +" __global b3GpuGenericConstraint* constraint = &constraints[i];\n" +" __global b3RigidBodyCL* rbA = &bodies[ constraint->m_rbA];\n" +" __global b3RigidBodyCL* rbB = &bodies[ constraint->m_rbB];\n" +" int solverBodyIdA = constraint->m_rbA;\n" +" int solverBodyIdB = constraint->m_rbB;\n" +" __global b3GpuSolverBody* bodyAPtr = &solverBodies[solverBodyIdA];\n" +" __global b3GpuSolverBody* bodyBPtr = &solverBodies[solverBodyIdB];\n" +" if (rbA->m_invMass)\n" +" {\n" +" batchConstraints[i].m_bodyAPtrAndSignBit = solverBodyIdA;\n" +" } else\n" +" {\n" +"// if (!solverBodyIdA)\n" +"// m_staticIdx = 0;\n" +" batchConstraints[i].m_bodyAPtrAndSignBit = -solverBodyIdA;\n" +" }\n" +" if (rbB->m_invMass)\n" +" {\n" +" batchConstraints[i].m_bodyBPtrAndSignBit = solverBodyIdB;\n" +" } else\n" +" {\n" +"// if (!solverBodyIdB)\n" +"// m_staticIdx = 0;\n" +" batchConstraints[i].m_bodyBPtrAndSignBit = -solverBodyIdB;\n" +" }\n" +" if (info1)\n" +" {\n" +" int overrideNumSolverIterations = 0;//constraint->getOverrideNumSolverIterations() > 0 ? constraint->getOverrideNumSolverIterations() : infoGlobal.m_numIterations;\n" +"// if (overrideNumSolverIterations>m_maxOverrideNumSolverIterations)\n" +" // m_maxOverrideNumSolverIterations = overrideNumSolverIterations;\n" +" int j;\n" +" for ( j=0;jm_deltaLinearVelocity = (float4)(0,0,0,0);\n" +" bodyAPtr->m_deltaAngularVelocity = (float4)(0,0,0,0);\n" +" bodyAPtr->m_pushVelocity = (float4)(0,0,0,0);\n" +" bodyAPtr->m_turnVelocity = (float4)(0,0,0,0);\n" +" bodyBPtr->m_deltaLinearVelocity = (float4)(0,0,0,0);\n" +" bodyBPtr->m_deltaAngularVelocity = (float4)(0,0,0,0);\n" +" bodyBPtr->m_pushVelocity = (float4)(0,0,0,0);\n" +" bodyBPtr->m_turnVelocity = (float4)(0,0,0,0);\n" +" int rowskip = sizeof(b3SolverConstraint)/sizeof(float);//check this\n" +" \n" +" b3GpuConstraintInfo2 info2;\n" +" info2.fps = 1.f/timeStep;\n" +" info2.erp = globalErp;\n" +" info2.m_J1linearAxisFloat4 = ¤tConstraintRow->m_contactNormal;\n" +" info2.m_J1angularAxisFloat4 = ¤tConstraintRow->m_relpos1CrossNormal;\n" +" info2.m_J2linearAxisFloat4 = 0;\n" +" info2.m_J2angularAxisFloat4 = ¤tConstraintRow->m_relpos2CrossNormal;\n" +" info2.rowskip = sizeof(b3SolverConstraint)/sizeof(float);//check this\n" +" ///the size of b3SolverConstraint needs be a multiple of float\n" +"// b3Assert(info2.rowskip*sizeof(float)== sizeof(b3SolverConstraint));\n" +" info2.m_constraintError = ¤tConstraintRow->m_rhs;\n" +" currentConstraintRow->m_cfm = globalCfm;\n" +" info2.m_damping = globalDamping;\n" +" info2.cfm = ¤tConstraintRow->m_cfm;\n" +" info2.m_lowerLimit = ¤tConstraintRow->m_lowerLimit;\n" +" info2.m_upperLimit = ¤tConstraintRow->m_upperLimit;\n" +" info2.m_numIterations = globalNumIterations;\n" +" switch (constraint->m_constraintType)\n" +" {\n" +" case B3_GPU_POINT2POINT_CONSTRAINT_TYPE:\n" +" {\n" +" getInfo2Point2Point(constraint,&info2,bodies);\n" +" break;\n" +" }\n" +" case B3_GPU_FIXED_CONSTRAINT_TYPE:\n" +" {\n" +" getInfo2Point2Point(constraint,&info2,bodies);\n" +" getInfo2FixedOrientation(constraint,&info2,bodies,3);\n" +" break;\n" +" }\n" +" default:\n" +" {\n" +" }\n" +" }\n" +" ///finalize the constraint setup\n" +" for ( j=0;jm_upperLimit>=constraint->m_breakingImpulseThreshold)\n" +" {\n" +" solverConstraint->m_upperLimit = constraint->m_breakingImpulseThreshold;\n" +" }\n" +" if (solverConstraint->m_lowerLimit<=-constraint->m_breakingImpulseThreshold)\n" +" {\n" +" solverConstraint->m_lowerLimit = -constraint->m_breakingImpulseThreshold;\n" +" }\n" +"// solverConstraint->m_originalContactPoint = constraint;\n" +" \n" +" Matrix3x3 invInertiaWorldA= inertias[constraint->m_rbA].m_invInertiaWorld;\n" +" {\n" +" //float4 angularFactorA(1,1,1);\n" +" float4 ftorqueAxis1 = solverConstraint->m_relpos1CrossNormal;\n" +" solverConstraint->m_angularComponentA = mtMul1(invInertiaWorldA,ftorqueAxis1);//*angularFactorA;\n" +" }\n" +" \n" +" Matrix3x3 invInertiaWorldB= inertias[constraint->m_rbB].m_invInertiaWorld;\n" +" {\n" +" float4 ftorqueAxis2 = solverConstraint->m_relpos2CrossNormal;\n" +" solverConstraint->m_angularComponentB = mtMul1(invInertiaWorldB,ftorqueAxis2);//*constraint->m_rbB.getAngularFactor();\n" +" }\n" +" {\n" +" //it is ok to use solverConstraint->m_contactNormal instead of -solverConstraint->m_contactNormal\n" +" //because it gets multiplied iMJlB\n" +" float4 iMJlA = solverConstraint->m_contactNormal*rbA->m_invMass;\n" +" float4 iMJaA = mtMul3(solverConstraint->m_relpos1CrossNormal,invInertiaWorldA);\n" +" float4 iMJlB = solverConstraint->m_contactNormal*rbB->m_invMass;//sign of normal?\n" +" float4 iMJaB = mtMul3(solverConstraint->m_relpos2CrossNormal,invInertiaWorldB);\n" +" float sum = dot3F4(iMJlA,solverConstraint->m_contactNormal);\n" +" sum += dot3F4(iMJaA,solverConstraint->m_relpos1CrossNormal);\n" +" sum += dot3F4(iMJlB,solverConstraint->m_contactNormal);\n" +" sum += dot3F4(iMJaB,solverConstraint->m_relpos2CrossNormal);\n" +" float fsum = fabs(sum);\n" +" if (fsum>FLT_EPSILON)\n" +" {\n" +" solverConstraint->m_jacDiagABInv = 1.f/sum;\n" +" } else\n" +" {\n" +" solverConstraint->m_jacDiagABInv = 0.f;\n" +" }\n" +" }\n" +" ///fix rhs\n" +" ///todo: add force/torque accelerators\n" +" {\n" +" float rel_vel;\n" +" float vel1Dotn = dot3F4(solverConstraint->m_contactNormal,rbA->m_linVel) + dot3F4(solverConstraint->m_relpos1CrossNormal,rbA->m_angVel);\n" +" float vel2Dotn = -dot3F4(solverConstraint->m_contactNormal,rbB->m_linVel) + dot3F4(solverConstraint->m_relpos2CrossNormal,rbB->m_angVel);\n" +" rel_vel = vel1Dotn+vel2Dotn;\n" +" float restitution = 0.f;\n" +" float positionalError = solverConstraint->m_rhs;//already filled in by getConstraintInfo2\n" +" float velocityError = restitution - rel_vel * info2.m_damping;\n" +" float penetrationImpulse = positionalError*solverConstraint->m_jacDiagABInv;\n" +" float velocityImpulse = velocityError *solverConstraint->m_jacDiagABInv;\n" +" solverConstraint->m_rhs = penetrationImpulse+velocityImpulse;\n" +" solverConstraint->m_appliedImpulse = 0.f;\n" +" }\n" +" }\n" +" }\n" +"}\n" +; diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/solveContact.cl b/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/solveContact.cl new file mode 100644 index 000000000000..5c4d62e4ec93 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/solveContact.cl @@ -0,0 +1,501 @@ +/* +Copyright (c) 2012 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Takahiro Harada + + +//#pragma OPENCL EXTENSION cl_amd_printf : enable +#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable +#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable +#pragma OPENCL EXTENSION cl_khr_local_int32_extended_atomics : enable +#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable + + +#ifdef cl_ext_atomic_counters_32 +#pragma OPENCL EXTENSION cl_ext_atomic_counters_32 : enable +#else +#define counter32_t volatile global int* +#endif + +typedef unsigned int u32; +typedef unsigned short u16; +typedef unsigned char u8; + +#define GET_GROUP_IDX get_group_id(0) +#define GET_LOCAL_IDX get_local_id(0) +#define GET_GLOBAL_IDX get_global_id(0) +#define GET_GROUP_SIZE get_local_size(0) +#define GET_NUM_GROUPS get_num_groups(0) +#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE) +#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE) +#define AtomInc(x) atom_inc(&(x)) +#define AtomInc1(x, out) out = atom_inc(&(x)) +#define AppendInc(x, out) out = atomic_inc(x) +#define AtomAdd(x, value) atom_add(&(x), value) +#define AtomCmpxhg(x, cmp, value) atom_cmpxchg( &(x), cmp, value ) +#define AtomXhg(x, value) atom_xchg ( &(x), value ) + + +#define SELECT_UINT4( b, a, condition ) select( b,a,condition ) + +#define mymake_float4 (float4) +//#define make_float2 (float2) +//#define make_uint4 (uint4) +//#define make_int4 (int4) +//#define make_uint2 (uint2) +//#define make_int2 (int2) + + +#define max2 max +#define min2 min + + +/////////////////////////////////////// +// Vector +/////////////////////////////////////// + + + + +__inline +float4 fastNormalize4(float4 v) +{ + return fast_normalize(v); +} + + + +__inline +float4 cross3(float4 a, float4 b) +{ + return cross(a,b); +} + +__inline +float dot3F4(float4 a, float4 b) +{ + float4 a1 = mymake_float4(a.xyz,0.f); + float4 b1 = mymake_float4(b.xyz,0.f); + return dot(a1, b1); +} + + + + +__inline +float4 normalize3(const float4 a) +{ + float4 n = mymake_float4(a.x, a.y, a.z, 0.f); + return fastNormalize4( n ); +// float length = sqrtf(dot3F4(a, a)); +// return 1.f/length * a; +} + + + + +/////////////////////////////////////// +// Matrix3x3 +/////////////////////////////////////// + +typedef struct +{ + float4 m_row[3]; +}Matrix3x3; + + + + + + +__inline +float4 mtMul1(Matrix3x3 a, float4 b); + +__inline +float4 mtMul3(float4 a, Matrix3x3 b); + + + + +__inline +float4 mtMul1(Matrix3x3 a, float4 b) +{ + float4 ans; + ans.x = dot3F4( a.m_row[0], b ); + ans.y = dot3F4( a.m_row[1], b ); + ans.z = dot3F4( a.m_row[2], b ); + ans.w = 0.f; + return ans; +} + +__inline +float4 mtMul3(float4 a, Matrix3x3 b) +{ + float4 colx = mymake_float4(b.m_row[0].x, b.m_row[1].x, b.m_row[2].x, 0); + float4 coly = mymake_float4(b.m_row[0].y, b.m_row[1].y, b.m_row[2].y, 0); + float4 colz = mymake_float4(b.m_row[0].z, b.m_row[1].z, b.m_row[2].z, 0); + + float4 ans; + ans.x = dot3F4( a, colx ); + ans.y = dot3F4( a, coly ); + ans.z = dot3F4( a, colz ); + return ans; +} + +/////////////////////////////////////// +// Quaternion +/////////////////////////////////////// + +typedef float4 Quaternion; + + + + + + + +#define WG_SIZE 64 + +typedef struct +{ + float4 m_pos; + Quaternion m_quat; + float4 m_linVel; + float4 m_angVel; + + u32 m_shapeIdx; + float m_invMass; + float m_restituitionCoeff; + float m_frictionCoeff; +} Body; + +typedef struct +{ + Matrix3x3 m_invInertia; + Matrix3x3 m_initInvInertia; +} Shape; + +typedef struct +{ + float4 m_linear; + float4 m_worldPos[4]; + float4 m_center; + float m_jacCoeffInv[4]; + float m_b[4]; + float m_appliedRambdaDt[4]; + + float m_fJacCoeffInv[2]; + float m_fAppliedRambdaDt[2]; + + u32 m_bodyA; + u32 m_bodyB; + + int m_batchIdx; + u32 m_paddings[1]; +} Constraint4; + + + +typedef struct +{ + int m_nConstraints; + int m_start; + int m_batchIdx; + int m_nSplit; +// int m_paddings[1]; +} ConstBuffer; + +typedef struct +{ + int m_solveFriction; + int m_maxBatch; // long batch really kills the performance + int m_batchIdx; + int m_nSplit; +// int m_paddings[1]; +} ConstBufferBatchSolve; + +void setLinearAndAngular( float4 n, float4 r0, float4 r1, float4* linear, float4* angular0, float4* angular1); + +void setLinearAndAngular( float4 n, float4 r0, float4 r1, float4* linear, float4* angular0, float4* angular1) +{ + *linear = mymake_float4(-n.xyz,0.f); + *angular0 = -cross3(r0, n); + *angular1 = cross3(r1, n); +} + +float calcRelVel( float4 l0, float4 l1, float4 a0, float4 a1, float4 linVel0, float4 angVel0, float4 linVel1, float4 angVel1 ); + +float calcRelVel( float4 l0, float4 l1, float4 a0, float4 a1, float4 linVel0, float4 angVel0, float4 linVel1, float4 angVel1 ) +{ + return dot3F4(l0, linVel0) + dot3F4(a0, angVel0) + dot3F4(l1, linVel1) + dot3F4(a1, angVel1); +} + + +float calcJacCoeff(const float4 linear0, const float4 linear1, const float4 angular0, const float4 angular1, + float invMass0, const Matrix3x3* invInertia0, float invMass1, const Matrix3x3* invInertia1); + +float calcJacCoeff(const float4 linear0, const float4 linear1, const float4 angular0, const float4 angular1, + float invMass0, const Matrix3x3* invInertia0, float invMass1, const Matrix3x3* invInertia1) +{ + // linear0,1 are normlized + float jmj0 = invMass0;//dot3F4(linear0, linear0)*invMass0; + float jmj1 = dot3F4(mtMul3(angular0,*invInertia0), angular0); + float jmj2 = invMass1;//dot3F4(linear1, linear1)*invMass1; + float jmj3 = dot3F4(mtMul3(angular1,*invInertia1), angular1); + return -1.f/(jmj0+jmj1+jmj2+jmj3); +} + + +void solveContact(__global Constraint4* cs, + float4 posA, float4* linVelA, float4* angVelA, float invMassA, Matrix3x3 invInertiaA, + float4 posB, float4* linVelB, float4* angVelB, float invMassB, Matrix3x3 invInertiaB); + +void solveContact(__global Constraint4* cs, + float4 posA, float4* linVelA, float4* angVelA, float invMassA, Matrix3x3 invInertiaA, + float4 posB, float4* linVelB, float4* angVelB, float invMassB, Matrix3x3 invInertiaB) +{ + float minRambdaDt = 0; + float maxRambdaDt = FLT_MAX; + + for(int ic=0; ic<4; ic++) + { + if( cs->m_jacCoeffInv[ic] == 0.f ) continue; + + float4 angular0, angular1, linear; + float4 r0 = cs->m_worldPos[ic] - posA; + float4 r1 = cs->m_worldPos[ic] - posB; + setLinearAndAngular( -cs->m_linear, r0, r1, &linear, &angular0, &angular1 ); + + float rambdaDt = calcRelVel( cs->m_linear, -cs->m_linear, angular0, angular1, + *linVelA, *angVelA, *linVelB, *angVelB ) + cs->m_b[ic]; + rambdaDt *= cs->m_jacCoeffInv[ic]; + + { + float prevSum = cs->m_appliedRambdaDt[ic]; + float updated = prevSum; + updated += rambdaDt; + updated = max2( updated, minRambdaDt ); + updated = min2( updated, maxRambdaDt ); + rambdaDt = updated - prevSum; + cs->m_appliedRambdaDt[ic] = updated; + } + + float4 linImp0 = invMassA*linear*rambdaDt; + float4 linImp1 = invMassB*(-linear)*rambdaDt; + float4 angImp0 = mtMul1(invInertiaA, angular0)*rambdaDt; + float4 angImp1 = mtMul1(invInertiaB, angular1)*rambdaDt; + + *linVelA += linImp0; + *angVelA += angImp0; + *linVelB += linImp1; + *angVelB += angImp1; + } +} + +void btPlaneSpace1 (const float4* n, float4* p, float4* q); + void btPlaneSpace1 (const float4* n, float4* p, float4* q) +{ + if (fabs(n[0].z) > 0.70710678f) { + // choose p in y-z plane + float a = n[0].y*n[0].y + n[0].z*n[0].z; + float k = 1.f/sqrt(a); + p[0].x = 0; + p[0].y = -n[0].z*k; + p[0].z = n[0].y*k; + // set q = n x p + q[0].x = a*k; + q[0].y = -n[0].x*p[0].z; + q[0].z = n[0].x*p[0].y; + } + else { + // choose p in x-y plane + float a = n[0].x*n[0].x + n[0].y*n[0].y; + float k = 1.f/sqrt(a); + p[0].x = -n[0].y*k; + p[0].y = n[0].x*k; + p[0].z = 0; + // set q = n x p + q[0].x = -n[0].z*p[0].y; + q[0].y = n[0].z*p[0].x; + q[0].z = a*k; + } +} + +void solveContactConstraint(__global Body* gBodies, __global Shape* gShapes, __global Constraint4* ldsCs); +void solveContactConstraint(__global Body* gBodies, __global Shape* gShapes, __global Constraint4* ldsCs) +{ + //float frictionCoeff = ldsCs[0].m_linear.w; + int aIdx = ldsCs[0].m_bodyA; + int bIdx = ldsCs[0].m_bodyB; + + float4 posA = gBodies[aIdx].m_pos; + float4 linVelA = gBodies[aIdx].m_linVel; + float4 angVelA = gBodies[aIdx].m_angVel; + float invMassA = gBodies[aIdx].m_invMass; + Matrix3x3 invInertiaA = gShapes[aIdx].m_invInertia; + + float4 posB = gBodies[bIdx].m_pos; + float4 linVelB = gBodies[bIdx].m_linVel; + float4 angVelB = gBodies[bIdx].m_angVel; + float invMassB = gBodies[bIdx].m_invMass; + Matrix3x3 invInertiaB = gShapes[bIdx].m_invInertia; + + solveContact( ldsCs, posA, &linVelA, &angVelA, invMassA, invInertiaA, + posB, &linVelB, &angVelB, invMassB, invInertiaB ); + + if (gBodies[aIdx].m_invMass) + { + gBodies[aIdx].m_linVel = linVelA; + gBodies[aIdx].m_angVel = angVelA; + } else + { + gBodies[aIdx].m_linVel = mymake_float4(0,0,0,0); + gBodies[aIdx].m_angVel = mymake_float4(0,0,0,0); + + } + if (gBodies[bIdx].m_invMass) + { + gBodies[bIdx].m_linVel = linVelB; + gBodies[bIdx].m_angVel = angVelB; + } else + { + gBodies[bIdx].m_linVel = mymake_float4(0,0,0,0); + gBodies[bIdx].m_angVel = mymake_float4(0,0,0,0); + + } + +} + + + +typedef struct +{ + int m_valInt0; + int m_valInt1; + int m_valInt2; + int m_valInt3; + + float m_val0; + float m_val1; + float m_val2; + float m_val3; +} SolverDebugInfo; + + + + +__kernel +__attribute__((reqd_work_group_size(WG_SIZE,1,1))) +void BatchSolveKernelContact(__global Body* gBodies, + __global Shape* gShapes, + __global Constraint4* gConstraints, + __global int* gN, + __global int* gOffsets, + __global int* batchSizes, + int maxBatch1, + int cellBatch, + int4 nSplit + ) +{ + //__local int ldsBatchIdx[WG_SIZE+1]; + __local int ldsCurBatch; + __local int ldsNextBatch; + __local int ldsStart; + + int lIdx = GET_LOCAL_IDX; + int wgIdx = GET_GROUP_IDX; + +// int gIdx = GET_GLOBAL_IDX; +// debugInfo[gIdx].m_valInt0 = gIdx; + //debugInfo[gIdx].m_valInt1 = GET_GROUP_SIZE; + + + + + int zIdx = (wgIdx/((nSplit.x*nSplit.y)/4))*2+((cellBatch&4)>>2); + int remain= (wgIdx%((nSplit.x*nSplit.y)/4)); + int yIdx = (remain/(nSplit.x/2))*2 + ((cellBatch&2)>>1); + int xIdx = (remain%(nSplit.x/2))*2 + (cellBatch&1); + int cellIdx = xIdx+yIdx*nSplit.x+zIdx*(nSplit.x*nSplit.y); + + //int xIdx = (wgIdx/(nSplit/2))*2 + (bIdx&1); + //int yIdx = (wgIdx%(nSplit/2))*2 + (bIdx>>1); + //int cellIdx = xIdx+yIdx*nSplit; + + if( gN[cellIdx] == 0 ) + return; + + int maxBatch = batchSizes[cellIdx]; + + + const int start = gOffsets[cellIdx]; + const int end = start + gN[cellIdx]; + + + + + if( lIdx == 0 ) + { + ldsCurBatch = 0; + ldsNextBatch = 0; + ldsStart = start; + } + + + GROUP_LDS_BARRIER; + + int idx=ldsStart+lIdx; + while (ldsCurBatch < maxBatch) + { + for(; idxm_jacCoeffInv[ic] == 0.f ) continue;\n" +" float4 angular0, angular1, linear;\n" +" float4 r0 = cs->m_worldPos[ic] - posA;\n" +" float4 r1 = cs->m_worldPos[ic] - posB;\n" +" setLinearAndAngular( -cs->m_linear, r0, r1, &linear, &angular0, &angular1 );\n" +" float rambdaDt = calcRelVel( cs->m_linear, -cs->m_linear, angular0, angular1, \n" +" *linVelA, *angVelA, *linVelB, *angVelB ) + cs->m_b[ic];\n" +" rambdaDt *= cs->m_jacCoeffInv[ic];\n" +" {\n" +" float prevSum = cs->m_appliedRambdaDt[ic];\n" +" float updated = prevSum;\n" +" updated += rambdaDt;\n" +" updated = max2( updated, minRambdaDt );\n" +" updated = min2( updated, maxRambdaDt );\n" +" rambdaDt = updated - prevSum;\n" +" cs->m_appliedRambdaDt[ic] = updated;\n" +" }\n" +" float4 linImp0 = invMassA*linear*rambdaDt;\n" +" float4 linImp1 = invMassB*(-linear)*rambdaDt;\n" +" float4 angImp0 = mtMul1(invInertiaA, angular0)*rambdaDt;\n" +" float4 angImp1 = mtMul1(invInertiaB, angular1)*rambdaDt;\n" +" *linVelA += linImp0;\n" +" *angVelA += angImp0;\n" +" *linVelB += linImp1;\n" +" *angVelB += angImp1;\n" +" }\n" +"}\n" +"void btPlaneSpace1 (const float4* n, float4* p, float4* q);\n" +" void btPlaneSpace1 (const float4* n, float4* p, float4* q)\n" +"{\n" +" if (fabs(n[0].z) > 0.70710678f) {\n" +" // choose p in y-z plane\n" +" float a = n[0].y*n[0].y + n[0].z*n[0].z;\n" +" float k = 1.f/sqrt(a);\n" +" p[0].x = 0;\n" +" p[0].y = -n[0].z*k;\n" +" p[0].z = n[0].y*k;\n" +" // set q = n x p\n" +" q[0].x = a*k;\n" +" q[0].y = -n[0].x*p[0].z;\n" +" q[0].z = n[0].x*p[0].y;\n" +" }\n" +" else {\n" +" // choose p in x-y plane\n" +" float a = n[0].x*n[0].x + n[0].y*n[0].y;\n" +" float k = 1.f/sqrt(a);\n" +" p[0].x = -n[0].y*k;\n" +" p[0].y = n[0].x*k;\n" +" p[0].z = 0;\n" +" // set q = n x p\n" +" q[0].x = -n[0].z*p[0].y;\n" +" q[0].y = n[0].z*p[0].x;\n" +" q[0].z = a*k;\n" +" }\n" +"}\n" +"void solveContactConstraint(__global Body* gBodies, __global Shape* gShapes, __global Constraint4* ldsCs);\n" +"void solveContactConstraint(__global Body* gBodies, __global Shape* gShapes, __global Constraint4* ldsCs)\n" +"{\n" +" //float frictionCoeff = ldsCs[0].m_linear.w;\n" +" int aIdx = ldsCs[0].m_bodyA;\n" +" int bIdx = ldsCs[0].m_bodyB;\n" +" float4 posA = gBodies[aIdx].m_pos;\n" +" float4 linVelA = gBodies[aIdx].m_linVel;\n" +" float4 angVelA = gBodies[aIdx].m_angVel;\n" +" float invMassA = gBodies[aIdx].m_invMass;\n" +" Matrix3x3 invInertiaA = gShapes[aIdx].m_invInertia;\n" +" float4 posB = gBodies[bIdx].m_pos;\n" +" float4 linVelB = gBodies[bIdx].m_linVel;\n" +" float4 angVelB = gBodies[bIdx].m_angVel;\n" +" float invMassB = gBodies[bIdx].m_invMass;\n" +" Matrix3x3 invInertiaB = gShapes[bIdx].m_invInertia;\n" +" solveContact( ldsCs, posA, &linVelA, &angVelA, invMassA, invInertiaA,\n" +" posB, &linVelB, &angVelB, invMassB, invInertiaB );\n" +" if (gBodies[aIdx].m_invMass)\n" +" {\n" +" gBodies[aIdx].m_linVel = linVelA;\n" +" gBodies[aIdx].m_angVel = angVelA;\n" +" } else\n" +" {\n" +" gBodies[aIdx].m_linVel = mymake_float4(0,0,0,0);\n" +" gBodies[aIdx].m_angVel = mymake_float4(0,0,0,0);\n" +" \n" +" }\n" +" if (gBodies[bIdx].m_invMass)\n" +" {\n" +" gBodies[bIdx].m_linVel = linVelB;\n" +" gBodies[bIdx].m_angVel = angVelB;\n" +" } else\n" +" {\n" +" gBodies[bIdx].m_linVel = mymake_float4(0,0,0,0);\n" +" gBodies[bIdx].m_angVel = mymake_float4(0,0,0,0);\n" +" \n" +" }\n" +"}\n" +"typedef struct \n" +"{\n" +" int m_valInt0;\n" +" int m_valInt1;\n" +" int m_valInt2;\n" +" int m_valInt3;\n" +" float m_val0;\n" +" float m_val1;\n" +" float m_val2;\n" +" float m_val3;\n" +"} SolverDebugInfo;\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" +"void BatchSolveKernelContact(__global Body* gBodies,\n" +" __global Shape* gShapes,\n" +" __global Constraint4* gConstraints,\n" +" __global int* gN,\n" +" __global int* gOffsets,\n" +" __global int* batchSizes,\n" +" int maxBatch1,\n" +" int cellBatch,\n" +" int4 nSplit\n" +" )\n" +"{\n" +" //__local int ldsBatchIdx[WG_SIZE+1];\n" +" __local int ldsCurBatch;\n" +" __local int ldsNextBatch;\n" +" __local int ldsStart;\n" +" int lIdx = GET_LOCAL_IDX;\n" +" int wgIdx = GET_GROUP_IDX;\n" +"// int gIdx = GET_GLOBAL_IDX;\n" +"// debugInfo[gIdx].m_valInt0 = gIdx;\n" +" //debugInfo[gIdx].m_valInt1 = GET_GROUP_SIZE;\n" +" \n" +" \n" +" int zIdx = (wgIdx/((nSplit.x*nSplit.y)/4))*2+((cellBatch&4)>>2);\n" +" int remain= (wgIdx%((nSplit.x*nSplit.y)/4));\n" +" int yIdx = (remain/(nSplit.x/2))*2 + ((cellBatch&2)>>1);\n" +" int xIdx = (remain%(nSplit.x/2))*2 + (cellBatch&1);\n" +" int cellIdx = xIdx+yIdx*nSplit.x+zIdx*(nSplit.x*nSplit.y);\n" +" //int xIdx = (wgIdx/(nSplit/2))*2 + (bIdx&1);\n" +" //int yIdx = (wgIdx%(nSplit/2))*2 + (bIdx>>1);\n" +" //int cellIdx = xIdx+yIdx*nSplit;\n" +" \n" +" if( gN[cellIdx] == 0 ) \n" +" return;\n" +" int maxBatch = batchSizes[cellIdx];\n" +" \n" +" \n" +" const int start = gOffsets[cellIdx];\n" +" const int end = start + gN[cellIdx];\n" +" \n" +" \n" +" \n" +" if( lIdx == 0 )\n" +" {\n" +" ldsCurBatch = 0;\n" +" ldsNextBatch = 0;\n" +" ldsStart = start;\n" +" }\n" +" GROUP_LDS_BARRIER;\n" +" int idx=ldsStart+lIdx;\n" +" while (ldsCurBatch < maxBatch)\n" +" {\n" +" for(; idx 0.70710678f) { + // choose p in y-z plane + float a = n[0].y*n[0].y + n[0].z*n[0].z; + float k = 1.f/sqrt(a); + p[0].x = 0; + p[0].y = -n[0].z*k; + p[0].z = n[0].y*k; + // set q = n x p + q[0].x = a*k; + q[0].y = -n[0].x*p[0].z; + q[0].z = n[0].x*p[0].y; + } + else { + // choose p in x-y plane + float a = n[0].x*n[0].x + n[0].y*n[0].y; + float k = 1.f/sqrt(a); + p[0].x = -n[0].y*k; + p[0].y = n[0].x*k; + p[0].z = 0; + // set q = n x p + q[0].x = -n[0].z*p[0].y; + q[0].y = n[0].z*p[0].x; + q[0].z = a*k; + } +} + + +void solveFrictionConstraint(__global Body* gBodies, __global Shape* gShapes, __global Constraint4* ldsCs); +void solveFrictionConstraint(__global Body* gBodies, __global Shape* gShapes, __global Constraint4* ldsCs) +{ + float frictionCoeff = ldsCs[0].m_linear.w; + int aIdx = ldsCs[0].m_bodyA; + int bIdx = ldsCs[0].m_bodyB; + + + float4 posA = gBodies[aIdx].m_pos; + float4 linVelA = gBodies[aIdx].m_linVel; + float4 angVelA = gBodies[aIdx].m_angVel; + float invMassA = gBodies[aIdx].m_invMass; + Matrix3x3 invInertiaA = gShapes[aIdx].m_invInertia; + + float4 posB = gBodies[bIdx].m_pos; + float4 linVelB = gBodies[bIdx].m_linVel; + float4 angVelB = gBodies[bIdx].m_angVel; + float invMassB = gBodies[bIdx].m_invMass; + Matrix3x3 invInertiaB = gShapes[bIdx].m_invInertia; + + + { + float maxRambdaDt[4] = {FLT_MAX,FLT_MAX,FLT_MAX,FLT_MAX}; + float minRambdaDt[4] = {0.f,0.f,0.f,0.f}; + + float sum = 0; + for(int j=0; j<4; j++) + { + sum +=ldsCs[0].m_appliedRambdaDt[j]; + } + frictionCoeff = 0.7f; + for(int j=0; j<4; j++) + { + maxRambdaDt[j] = frictionCoeff*sum; + minRambdaDt[j] = -maxRambdaDt[j]; + } + + +// solveFriction( ldsCs, posA, &linVelA, &angVelA, invMassA, invInertiaA, +// posB, &linVelB, &angVelB, invMassB, invInertiaB, maxRambdaDt, minRambdaDt ); + + + { + + __global Constraint4* cs = ldsCs; + + if( cs->m_fJacCoeffInv[0] == 0 && cs->m_fJacCoeffInv[0] == 0 ) return; + const float4 center = cs->m_center; + + float4 n = -cs->m_linear; + + float4 tangent[2]; + btPlaneSpace1(&n,&tangent[0],&tangent[1]); + float4 angular0, angular1, linear; + float4 r0 = center - posA; + float4 r1 = center - posB; + for(int i=0; i<2; i++) + { + setLinearAndAngular( tangent[i], r0, r1, &linear, &angular0, &angular1 ); + float rambdaDt = calcRelVel(linear, -linear, angular0, angular1, + linVelA, angVelA, linVelB, angVelB ); + rambdaDt *= cs->m_fJacCoeffInv[i]; + + { + float prevSum = cs->m_fAppliedRambdaDt[i]; + float updated = prevSum; + updated += rambdaDt; + updated = max2( updated, minRambdaDt[i] ); + updated = min2( updated, maxRambdaDt[i] ); + rambdaDt = updated - prevSum; + cs->m_fAppliedRambdaDt[i] = updated; + } + + float4 linImp0 = invMassA*linear*rambdaDt; + float4 linImp1 = invMassB*(-linear)*rambdaDt; + float4 angImp0 = mtMul1(invInertiaA, angular0)*rambdaDt; + float4 angImp1 = mtMul1(invInertiaB, angular1)*rambdaDt; + + linVelA += linImp0; + angVelA += angImp0; + linVelB += linImp1; + angVelB += angImp1; + } + { // angular damping for point constraint + float4 ab = normalize3( posB - posA ); + float4 ac = normalize3( center - posA ); + if( dot3F4( ab, ac ) > 0.95f || (invMassA == 0.f || invMassB == 0.f)) + { + float angNA = dot3F4( n, angVelA ); + float angNB = dot3F4( n, angVelB ); + + angVelA -= (angNA*0.1f)*n; + angVelB -= (angNB*0.1f)*n; + } + } + } + + + + } + + if (gBodies[aIdx].m_invMass) + { + gBodies[aIdx].m_linVel = linVelA; + gBodies[aIdx].m_angVel = angVelA; + } else + { + gBodies[aIdx].m_linVel = mymake_float4(0,0,0,0); + gBodies[aIdx].m_angVel = mymake_float4(0,0,0,0); + } + if (gBodies[bIdx].m_invMass) + { + gBodies[bIdx].m_linVel = linVelB; + gBodies[bIdx].m_angVel = angVelB; + } else + { + gBodies[bIdx].m_linVel = mymake_float4(0,0,0,0); + gBodies[bIdx].m_angVel = mymake_float4(0,0,0,0); + } + + +} + +typedef struct +{ + int m_valInt0; + int m_valInt1; + int m_valInt2; + int m_valInt3; + + float m_val0; + float m_val1; + float m_val2; + float m_val3; +} SolverDebugInfo; + + + + +__kernel +__attribute__((reqd_work_group_size(WG_SIZE,1,1))) +void BatchSolveKernelFriction(__global Body* gBodies, + __global Shape* gShapes, + __global Constraint4* gConstraints, + __global int* gN, + __global int* gOffsets, + __global int* batchSizes, + int maxBatch1, + int cellBatch, + int4 nSplit + ) +{ + //__local int ldsBatchIdx[WG_SIZE+1]; + __local int ldsCurBatch; + __local int ldsNextBatch; + __local int ldsStart; + + int lIdx = GET_LOCAL_IDX; + int wgIdx = GET_GROUP_IDX; + +// int gIdx = GET_GLOBAL_IDX; +// debugInfo[gIdx].m_valInt0 = gIdx; + //debugInfo[gIdx].m_valInt1 = GET_GROUP_SIZE; + + + int zIdx = (wgIdx/((nSplit.x*nSplit.y)/4))*2+((cellBatch&4)>>2); + int remain= (wgIdx%((nSplit.x*nSplit.y)/4)); + int yIdx = (remain/(nSplit.x/2))*2 + ((cellBatch&2)>>1); + int xIdx = (remain%(nSplit.x/2))*2 + (cellBatch&1); + int cellIdx = xIdx+yIdx*nSplit.x+zIdx*(nSplit.x*nSplit.y); + + + if( gN[cellIdx] == 0 ) + return; + + int maxBatch = batchSizes[cellIdx]; + + const int start = gOffsets[cellIdx]; + const int end = start + gN[cellIdx]; + + + if( lIdx == 0 ) + { + ldsCurBatch = 0; + ldsNextBatch = 0; + ldsStart = start; + } + + + GROUP_LDS_BARRIER; + + int idx=ldsStart+lIdx; + while (ldsCurBatch < maxBatch) + { + for(; idx 0.70710678f) {\n" +" // choose p in y-z plane\n" +" float a = n[0].y*n[0].y + n[0].z*n[0].z;\n" +" float k = 1.f/sqrt(a);\n" +" p[0].x = 0;\n" +" p[0].y = -n[0].z*k;\n" +" p[0].z = n[0].y*k;\n" +" // set q = n x p\n" +" q[0].x = a*k;\n" +" q[0].y = -n[0].x*p[0].z;\n" +" q[0].z = n[0].x*p[0].y;\n" +" }\n" +" else {\n" +" // choose p in x-y plane\n" +" float a = n[0].x*n[0].x + n[0].y*n[0].y;\n" +" float k = 1.f/sqrt(a);\n" +" p[0].x = -n[0].y*k;\n" +" p[0].y = n[0].x*k;\n" +" p[0].z = 0;\n" +" // set q = n x p\n" +" q[0].x = -n[0].z*p[0].y;\n" +" q[0].y = n[0].z*p[0].x;\n" +" q[0].z = a*k;\n" +" }\n" +"}\n" +"void solveFrictionConstraint(__global Body* gBodies, __global Shape* gShapes, __global Constraint4* ldsCs);\n" +"void solveFrictionConstraint(__global Body* gBodies, __global Shape* gShapes, __global Constraint4* ldsCs)\n" +"{\n" +" float frictionCoeff = ldsCs[0].m_linear.w;\n" +" int aIdx = ldsCs[0].m_bodyA;\n" +" int bIdx = ldsCs[0].m_bodyB;\n" +" float4 posA = gBodies[aIdx].m_pos;\n" +" float4 linVelA = gBodies[aIdx].m_linVel;\n" +" float4 angVelA = gBodies[aIdx].m_angVel;\n" +" float invMassA = gBodies[aIdx].m_invMass;\n" +" Matrix3x3 invInertiaA = gShapes[aIdx].m_invInertia;\n" +" float4 posB = gBodies[bIdx].m_pos;\n" +" float4 linVelB = gBodies[bIdx].m_linVel;\n" +" float4 angVelB = gBodies[bIdx].m_angVel;\n" +" float invMassB = gBodies[bIdx].m_invMass;\n" +" Matrix3x3 invInertiaB = gShapes[bIdx].m_invInertia;\n" +" \n" +" {\n" +" float maxRambdaDt[4] = {FLT_MAX,FLT_MAX,FLT_MAX,FLT_MAX};\n" +" float minRambdaDt[4] = {0.f,0.f,0.f,0.f};\n" +" float sum = 0;\n" +" for(int j=0; j<4; j++)\n" +" {\n" +" sum +=ldsCs[0].m_appliedRambdaDt[j];\n" +" }\n" +" frictionCoeff = 0.7f;\n" +" for(int j=0; j<4; j++)\n" +" {\n" +" maxRambdaDt[j] = frictionCoeff*sum;\n" +" minRambdaDt[j] = -maxRambdaDt[j];\n" +" }\n" +" \n" +"// solveFriction( ldsCs, posA, &linVelA, &angVelA, invMassA, invInertiaA,\n" +"// posB, &linVelB, &angVelB, invMassB, invInertiaB, maxRambdaDt, minRambdaDt );\n" +" \n" +" \n" +" {\n" +" \n" +" __global Constraint4* cs = ldsCs;\n" +" \n" +" if( cs->m_fJacCoeffInv[0] == 0 && cs->m_fJacCoeffInv[0] == 0 ) return;\n" +" const float4 center = cs->m_center;\n" +" \n" +" float4 n = -cs->m_linear;\n" +" \n" +" float4 tangent[2];\n" +" btPlaneSpace1(&n,&tangent[0],&tangent[1]);\n" +" float4 angular0, angular1, linear;\n" +" float4 r0 = center - posA;\n" +" float4 r1 = center - posB;\n" +" for(int i=0; i<2; i++)\n" +" {\n" +" setLinearAndAngular( tangent[i], r0, r1, &linear, &angular0, &angular1 );\n" +" float rambdaDt = calcRelVel(linear, -linear, angular0, angular1,\n" +" linVelA, angVelA, linVelB, angVelB );\n" +" rambdaDt *= cs->m_fJacCoeffInv[i];\n" +" \n" +" {\n" +" float prevSum = cs->m_fAppliedRambdaDt[i];\n" +" float updated = prevSum;\n" +" updated += rambdaDt;\n" +" updated = max2( updated, minRambdaDt[i] );\n" +" updated = min2( updated, maxRambdaDt[i] );\n" +" rambdaDt = updated - prevSum;\n" +" cs->m_fAppliedRambdaDt[i] = updated;\n" +" }\n" +" \n" +" float4 linImp0 = invMassA*linear*rambdaDt;\n" +" float4 linImp1 = invMassB*(-linear)*rambdaDt;\n" +" float4 angImp0 = mtMul1(invInertiaA, angular0)*rambdaDt;\n" +" float4 angImp1 = mtMul1(invInertiaB, angular1)*rambdaDt;\n" +" \n" +" linVelA += linImp0;\n" +" angVelA += angImp0;\n" +" linVelB += linImp1;\n" +" angVelB += angImp1;\n" +" }\n" +" { // angular damping for point constraint\n" +" float4 ab = normalize3( posB - posA );\n" +" float4 ac = normalize3( center - posA );\n" +" if( dot3F4( ab, ac ) > 0.95f || (invMassA == 0.f || invMassB == 0.f))\n" +" {\n" +" float angNA = dot3F4( n, angVelA );\n" +" float angNB = dot3F4( n, angVelB );\n" +" \n" +" angVelA -= (angNA*0.1f)*n;\n" +" angVelB -= (angNB*0.1f)*n;\n" +" }\n" +" }\n" +" }\n" +" \n" +" \n" +" }\n" +" if (gBodies[aIdx].m_invMass)\n" +" {\n" +" gBodies[aIdx].m_linVel = linVelA;\n" +" gBodies[aIdx].m_angVel = angVelA;\n" +" } else\n" +" {\n" +" gBodies[aIdx].m_linVel = mymake_float4(0,0,0,0);\n" +" gBodies[aIdx].m_angVel = mymake_float4(0,0,0,0);\n" +" }\n" +" if (gBodies[bIdx].m_invMass)\n" +" {\n" +" gBodies[bIdx].m_linVel = linVelB;\n" +" gBodies[bIdx].m_angVel = angVelB;\n" +" } else\n" +" {\n" +" gBodies[bIdx].m_linVel = mymake_float4(0,0,0,0);\n" +" gBodies[bIdx].m_angVel = mymake_float4(0,0,0,0);\n" +" }\n" +" \n" +"}\n" +"typedef struct \n" +"{\n" +" int m_valInt0;\n" +" int m_valInt1;\n" +" int m_valInt2;\n" +" int m_valInt3;\n" +" float m_val0;\n" +" float m_val1;\n" +" float m_val2;\n" +" float m_val3;\n" +"} SolverDebugInfo;\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" +"void BatchSolveKernelFriction(__global Body* gBodies,\n" +" __global Shape* gShapes,\n" +" __global Constraint4* gConstraints,\n" +" __global int* gN,\n" +" __global int* gOffsets,\n" +" __global int* batchSizes,\n" +" int maxBatch1,\n" +" int cellBatch,\n" +" int4 nSplit\n" +" )\n" +"{\n" +" //__local int ldsBatchIdx[WG_SIZE+1];\n" +" __local int ldsCurBatch;\n" +" __local int ldsNextBatch;\n" +" __local int ldsStart;\n" +" int lIdx = GET_LOCAL_IDX;\n" +" int wgIdx = GET_GROUP_IDX;\n" +"// int gIdx = GET_GLOBAL_IDX;\n" +"// debugInfo[gIdx].m_valInt0 = gIdx;\n" +" //debugInfo[gIdx].m_valInt1 = GET_GROUP_SIZE;\n" +" int zIdx = (wgIdx/((nSplit.x*nSplit.y)/4))*2+((cellBatch&4)>>2);\n" +" int remain= (wgIdx%((nSplit.x*nSplit.y)/4));\n" +" int yIdx = (remain/(nSplit.x/2))*2 + ((cellBatch&2)>>1);\n" +" int xIdx = (remain%(nSplit.x/2))*2 + (cellBatch&1);\n" +" int cellIdx = xIdx+yIdx*nSplit.x+zIdx*(nSplit.x*nSplit.y);\n" +" \n" +" if( gN[cellIdx] == 0 ) \n" +" return;\n" +" int maxBatch = batchSizes[cellIdx];\n" +" const int start = gOffsets[cellIdx];\n" +" const int end = start + gN[cellIdx];\n" +" \n" +" if( lIdx == 0 )\n" +" {\n" +" ldsCurBatch = 0;\n" +" ldsNextBatch = 0;\n" +" ldsStart = start;\n" +" }\n" +" GROUP_LDS_BARRIER;\n" +" int idx=ldsStart+lIdx;\n" +" while (ldsCurBatch < maxBatch)\n" +" {\n" +" for(; idx1e-6 || b3Fabs(v.y)>1e-6 || b3Fabs(v.z)>1e-6) \n" +" return false;\n" +" return true;\n" +"}\n" +"inline int b3MaxDot( b3Float4ConstArg vec, __global const b3Float4* vecArray, int vecLen, float* dotOut )\n" +"{\n" +" float maxDot = -B3_INFINITY;\n" +" int i = 0;\n" +" int ptIndex = -1;\n" +" for( i = 0; i < vecLen; i++ )\n" +" {\n" +" float dot = b3Dot3F4(vecArray[i],vec);\n" +" \n" +" if( dot > maxDot )\n" +" {\n" +" maxDot = dot;\n" +" ptIndex = i;\n" +" }\n" +" }\n" +" b3Assert(ptIndex>=0);\n" +" if (ptIndex<0)\n" +" {\n" +" ptIndex = 0;\n" +" }\n" +" *dotOut = maxDot;\n" +" return ptIndex;\n" +"}\n" +"#endif //B3_FLOAT4_H\n" +"typedef struct b3Contact4Data b3Contact4Data_t;\n" +"struct b3Contact4Data\n" +"{\n" +" b3Float4 m_worldPosB[4];\n" +"// b3Float4 m_localPosA[4];\n" +"// b3Float4 m_localPosB[4];\n" +" b3Float4 m_worldNormalOnB; // w: m_nPoints\n" +" unsigned short m_restituitionCoeffCmp;\n" +" unsigned short m_frictionCoeffCmp;\n" +" int m_batchIdx;\n" +" int m_bodyAPtrAndSignBit;//x:m_bodyAPtr, y:m_bodyBPtr\n" +" int m_bodyBPtrAndSignBit;\n" +" int m_childIndexA;\n" +" int m_childIndexB;\n" +" int m_unused1;\n" +" int m_unused2;\n" +"};\n" +"inline int b3Contact4Data_getNumPoints(const struct b3Contact4Data* contact)\n" +"{\n" +" return (int)contact->m_worldNormalOnB.w;\n" +"};\n" +"inline void b3Contact4Data_setNumPoints(struct b3Contact4Data* contact, int numPoints)\n" +"{\n" +" contact->m_worldNormalOnB.w = (float)numPoints;\n" +"};\n" +"#endif //B3_CONTACT4DATA_H\n" +"#ifndef B3_CONTACT_CONSTRAINT5_H\n" +"#define B3_CONTACT_CONSTRAINT5_H\n" +"#ifndef B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_FLOAT4_H\n" +"typedef struct b3ContactConstraint4 b3ContactConstraint4_t;\n" +"struct b3ContactConstraint4\n" +"{\n" +" b3Float4 m_linear;//normal?\n" +" b3Float4 m_worldPos[4];\n" +" b3Float4 m_center; // friction\n" +" float m_jacCoeffInv[4];\n" +" float m_b[4];\n" +" float m_appliedRambdaDt[4];\n" +" float m_fJacCoeffInv[2]; // friction\n" +" float m_fAppliedRambdaDt[2]; // friction\n" +" unsigned int m_bodyA;\n" +" unsigned int m_bodyB;\n" +" int m_batchIdx;\n" +" unsigned int m_paddings;\n" +"};\n" +"//inline void setFrictionCoeff(float value) { m_linear[3] = value; }\n" +"inline float b3GetFrictionCoeff(b3ContactConstraint4_t* constraint) \n" +"{\n" +" return constraint->m_linear.w; \n" +"}\n" +"#endif //B3_CONTACT_CONSTRAINT5_H\n" +"#ifndef B3_RIGIDBODY_DATA_H\n" +"#define B3_RIGIDBODY_DATA_H\n" +"#ifndef B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_FLOAT4_H\n" +"#ifndef B3_QUAT_H\n" +"#define B3_QUAT_H\n" +"#ifndef B3_PLATFORM_DEFINITIONS_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif\n" +"#endif\n" +"#ifndef B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +" typedef float4 b3Quat;\n" +" #define b3QuatConstArg const b3Quat\n" +" \n" +" \n" +"inline float4 b3FastNormalize4(float4 v)\n" +"{\n" +" v = (float4)(v.xyz,0.f);\n" +" return fast_normalize(v);\n" +"}\n" +" \n" +"inline b3Quat b3QuatMul(b3Quat a, b3Quat b);\n" +"inline b3Quat b3QuatNormalized(b3QuatConstArg in);\n" +"inline b3Quat b3QuatRotate(b3QuatConstArg q, b3QuatConstArg vec);\n" +"inline b3Quat b3QuatInvert(b3QuatConstArg q);\n" +"inline b3Quat b3QuatInverse(b3QuatConstArg q);\n" +"inline b3Quat b3QuatMul(b3QuatConstArg a, b3QuatConstArg b)\n" +"{\n" +" b3Quat ans;\n" +" ans = b3Cross3( a, b );\n" +" ans += a.w*b+b.w*a;\n" +"// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z);\n" +" ans.w = a.w*b.w - b3Dot3F4(a, b);\n" +" return ans;\n" +"}\n" +"inline b3Quat b3QuatNormalized(b3QuatConstArg in)\n" +"{\n" +" b3Quat q;\n" +" q=in;\n" +" //return b3FastNormalize4(in);\n" +" float len = native_sqrt(dot(q, q));\n" +" if(len > 0.f)\n" +" {\n" +" q *= 1.f / len;\n" +" }\n" +" else\n" +" {\n" +" q.x = q.y = q.z = 0.f;\n" +" q.w = 1.f;\n" +" }\n" +" return q;\n" +"}\n" +"inline float4 b3QuatRotate(b3QuatConstArg q, b3QuatConstArg vec)\n" +"{\n" +" b3Quat qInv = b3QuatInvert( q );\n" +" float4 vcpy = vec;\n" +" vcpy.w = 0.f;\n" +" float4 out = b3QuatMul(b3QuatMul(q,vcpy),qInv);\n" +" return out;\n" +"}\n" +"inline b3Quat b3QuatInverse(b3QuatConstArg q)\n" +"{\n" +" return (b3Quat)(-q.xyz, q.w);\n" +"}\n" +"inline b3Quat b3QuatInvert(b3QuatConstArg q)\n" +"{\n" +" return (b3Quat)(-q.xyz, q.w);\n" +"}\n" +"inline float4 b3QuatInvRotate(b3QuatConstArg q, b3QuatConstArg vec)\n" +"{\n" +" return b3QuatRotate( b3QuatInvert( q ), vec );\n" +"}\n" +"inline b3Float4 b3TransformPoint(b3Float4ConstArg point, b3Float4ConstArg translation, b3QuatConstArg orientation)\n" +"{\n" +" return b3QuatRotate( orientation, point ) + (translation);\n" +"}\n" +" \n" +"#endif \n" +"#endif //B3_QUAT_H\n" +"#ifndef B3_MAT3x3_H\n" +"#define B3_MAT3x3_H\n" +"#ifndef B3_QUAT_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_QUAT_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"typedef struct\n" +"{\n" +" b3Float4 m_row[3];\n" +"}b3Mat3x3;\n" +"#define b3Mat3x3ConstArg const b3Mat3x3\n" +"#define b3GetRow(m,row) (m.m_row[row])\n" +"inline b3Mat3x3 b3QuatGetRotationMatrix(b3Quat quat)\n" +"{\n" +" b3Float4 quat2 = (b3Float4)(quat.x*quat.x, quat.y*quat.y, quat.z*quat.z, 0.f);\n" +" b3Mat3x3 out;\n" +" out.m_row[0].x=1-2*quat2.y-2*quat2.z;\n" +" out.m_row[0].y=2*quat.x*quat.y-2*quat.w*quat.z;\n" +" out.m_row[0].z=2*quat.x*quat.z+2*quat.w*quat.y;\n" +" out.m_row[0].w = 0.f;\n" +" out.m_row[1].x=2*quat.x*quat.y+2*quat.w*quat.z;\n" +" out.m_row[1].y=1-2*quat2.x-2*quat2.z;\n" +" out.m_row[1].z=2*quat.y*quat.z-2*quat.w*quat.x;\n" +" out.m_row[1].w = 0.f;\n" +" out.m_row[2].x=2*quat.x*quat.z-2*quat.w*quat.y;\n" +" out.m_row[2].y=2*quat.y*quat.z+2*quat.w*quat.x;\n" +" out.m_row[2].z=1-2*quat2.x-2*quat2.y;\n" +" out.m_row[2].w = 0.f;\n" +" return out;\n" +"}\n" +"inline b3Mat3x3 b3AbsoluteMat3x3(b3Mat3x3ConstArg matIn)\n" +"{\n" +" b3Mat3x3 out;\n" +" out.m_row[0] = fabs(matIn.m_row[0]);\n" +" out.m_row[1] = fabs(matIn.m_row[1]);\n" +" out.m_row[2] = fabs(matIn.m_row[2]);\n" +" return out;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtZero();\n" +"__inline\n" +"b3Mat3x3 mtIdentity();\n" +"__inline\n" +"b3Mat3x3 mtTranspose(b3Mat3x3 m);\n" +"__inline\n" +"b3Mat3x3 mtMul(b3Mat3x3 a, b3Mat3x3 b);\n" +"__inline\n" +"b3Float4 mtMul1(b3Mat3x3 a, b3Float4 b);\n" +"__inline\n" +"b3Float4 mtMul3(b3Float4 a, b3Mat3x3 b);\n" +"__inline\n" +"b3Mat3x3 mtZero()\n" +"{\n" +" b3Mat3x3 m;\n" +" m.m_row[0] = (b3Float4)(0.f);\n" +" m.m_row[1] = (b3Float4)(0.f);\n" +" m.m_row[2] = (b3Float4)(0.f);\n" +" return m;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtIdentity()\n" +"{\n" +" b3Mat3x3 m;\n" +" m.m_row[0] = (b3Float4)(1,0,0,0);\n" +" m.m_row[1] = (b3Float4)(0,1,0,0);\n" +" m.m_row[2] = (b3Float4)(0,0,1,0);\n" +" return m;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtTranspose(b3Mat3x3 m)\n" +"{\n" +" b3Mat3x3 out;\n" +" out.m_row[0] = (b3Float4)(m.m_row[0].x, m.m_row[1].x, m.m_row[2].x, 0.f);\n" +" out.m_row[1] = (b3Float4)(m.m_row[0].y, m.m_row[1].y, m.m_row[2].y, 0.f);\n" +" out.m_row[2] = (b3Float4)(m.m_row[0].z, m.m_row[1].z, m.m_row[2].z, 0.f);\n" +" return out;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtMul(b3Mat3x3 a, b3Mat3x3 b)\n" +"{\n" +" b3Mat3x3 transB;\n" +" transB = mtTranspose( b );\n" +" b3Mat3x3 ans;\n" +" // why this doesn't run when 0ing in the for{}\n" +" a.m_row[0].w = 0.f;\n" +" a.m_row[1].w = 0.f;\n" +" a.m_row[2].w = 0.f;\n" +" for(int i=0; i<3; i++)\n" +" {\n" +"// a.m_row[i].w = 0.f;\n" +" ans.m_row[i].x = b3Dot3F4(a.m_row[i],transB.m_row[0]);\n" +" ans.m_row[i].y = b3Dot3F4(a.m_row[i],transB.m_row[1]);\n" +" ans.m_row[i].z = b3Dot3F4(a.m_row[i],transB.m_row[2]);\n" +" ans.m_row[i].w = 0.f;\n" +" }\n" +" return ans;\n" +"}\n" +"__inline\n" +"b3Float4 mtMul1(b3Mat3x3 a, b3Float4 b)\n" +"{\n" +" b3Float4 ans;\n" +" ans.x = b3Dot3F4( a.m_row[0], b );\n" +" ans.y = b3Dot3F4( a.m_row[1], b );\n" +" ans.z = b3Dot3F4( a.m_row[2], b );\n" +" ans.w = 0.f;\n" +" return ans;\n" +"}\n" +"__inline\n" +"b3Float4 mtMul3(b3Float4 a, b3Mat3x3 b)\n" +"{\n" +" b3Float4 colx = b3MakeFloat4(b.m_row[0].x, b.m_row[1].x, b.m_row[2].x, 0);\n" +" b3Float4 coly = b3MakeFloat4(b.m_row[0].y, b.m_row[1].y, b.m_row[2].y, 0);\n" +" b3Float4 colz = b3MakeFloat4(b.m_row[0].z, b.m_row[1].z, b.m_row[2].z, 0);\n" +" b3Float4 ans;\n" +" ans.x = b3Dot3F4( a, colx );\n" +" ans.y = b3Dot3F4( a, coly );\n" +" ans.z = b3Dot3F4( a, colz );\n" +" return ans;\n" +"}\n" +"#endif\n" +"#endif //B3_MAT3x3_H\n" +"typedef struct b3RigidBodyData b3RigidBodyData_t;\n" +"struct b3RigidBodyData\n" +"{\n" +" b3Float4 m_pos;\n" +" b3Quat m_quat;\n" +" b3Float4 m_linVel;\n" +" b3Float4 m_angVel;\n" +" int m_collidableIdx;\n" +" float m_invMass;\n" +" float m_restituitionCoeff;\n" +" float m_frictionCoeff;\n" +"};\n" +"typedef struct b3InertiaData b3InertiaData_t;\n" +"struct b3InertiaData\n" +"{\n" +" b3Mat3x3 m_invInertiaWorld;\n" +" b3Mat3x3 m_initInvInertia;\n" +"};\n" +"#endif //B3_RIGIDBODY_DATA_H\n" +" \n" +"void b3PlaneSpace1 (b3Float4ConstArg n, b3Float4* p, b3Float4* q);\n" +" void b3PlaneSpace1 (b3Float4ConstArg n, b3Float4* p, b3Float4* q)\n" +"{\n" +" if (b3Fabs(n.z) > 0.70710678f) {\n" +" // choose p in y-z plane\n" +" float a = n.y*n.y + n.z*n.z;\n" +" float k = 1.f/sqrt(a);\n" +" p[0].x = 0;\n" +" p[0].y = -n.z*k;\n" +" p[0].z = n.y*k;\n" +" // set q = n x p\n" +" q[0].x = a*k;\n" +" q[0].y = -n.x*p[0].z;\n" +" q[0].z = n.x*p[0].y;\n" +" }\n" +" else {\n" +" // choose p in x-y plane\n" +" float a = n.x*n.x + n.y*n.y;\n" +" float k = 1.f/sqrt(a);\n" +" p[0].x = -n.y*k;\n" +" p[0].y = n.x*k;\n" +" p[0].z = 0;\n" +" // set q = n x p\n" +" q[0].x = -n.z*p[0].y;\n" +" q[0].y = n.z*p[0].x;\n" +" q[0].z = a*k;\n" +" }\n" +"}\n" +" \n" +"void setLinearAndAngular( b3Float4ConstArg n, b3Float4ConstArg r0, b3Float4ConstArg r1, b3Float4* linear, b3Float4* angular0, b3Float4* angular1)\n" +"{\n" +" *linear = b3MakeFloat4(n.x,n.y,n.z,0.f);\n" +" *angular0 = b3Cross3(r0, n);\n" +" *angular1 = -b3Cross3(r1, n);\n" +"}\n" +"float calcRelVel( b3Float4ConstArg l0, b3Float4ConstArg l1, b3Float4ConstArg a0, b3Float4ConstArg a1, b3Float4ConstArg linVel0,\n" +" b3Float4ConstArg angVel0, b3Float4ConstArg linVel1, b3Float4ConstArg angVel1 )\n" +"{\n" +" return b3Dot3F4(l0, linVel0) + b3Dot3F4(a0, angVel0) + b3Dot3F4(l1, linVel1) + b3Dot3F4(a1, angVel1);\n" +"}\n" +"float calcJacCoeff(b3Float4ConstArg linear0, b3Float4ConstArg linear1, b3Float4ConstArg angular0, b3Float4ConstArg angular1,\n" +" float invMass0, const b3Mat3x3* invInertia0, float invMass1, const b3Mat3x3* invInertia1)\n" +"{\n" +" // linear0,1 are normlized\n" +" float jmj0 = invMass0;//b3Dot3F4(linear0, linear0)*invMass0;\n" +" float jmj1 = b3Dot3F4(mtMul3(angular0,*invInertia0), angular0);\n" +" float jmj2 = invMass1;//b3Dot3F4(linear1, linear1)*invMass1;\n" +" float jmj3 = b3Dot3F4(mtMul3(angular1,*invInertia1), angular1);\n" +" return -1.f/(jmj0+jmj1+jmj2+jmj3);\n" +"}\n" +"void setConstraint4( b3Float4ConstArg posA, b3Float4ConstArg linVelA, b3Float4ConstArg angVelA, float invMassA, b3Mat3x3ConstArg invInertiaA,\n" +" b3Float4ConstArg posB, b3Float4ConstArg linVelB, b3Float4ConstArg angVelB, float invMassB, b3Mat3x3ConstArg invInertiaB, \n" +" __global struct b3Contact4Data* src, float dt, float positionDrift, float positionConstraintCoeff,\n" +" b3ContactConstraint4_t* dstC )\n" +"{\n" +" dstC->m_bodyA = abs(src->m_bodyAPtrAndSignBit);\n" +" dstC->m_bodyB = abs(src->m_bodyBPtrAndSignBit);\n" +" float dtInv = 1.f/dt;\n" +" for(int ic=0; ic<4; ic++)\n" +" {\n" +" dstC->m_appliedRambdaDt[ic] = 0.f;\n" +" }\n" +" dstC->m_fJacCoeffInv[0] = dstC->m_fJacCoeffInv[1] = 0.f;\n" +" dstC->m_linear = src->m_worldNormalOnB;\n" +" dstC->m_linear.w = 0.7f ;//src->getFrictionCoeff() );\n" +" for(int ic=0; ic<4; ic++)\n" +" {\n" +" b3Float4 r0 = src->m_worldPosB[ic] - posA;\n" +" b3Float4 r1 = src->m_worldPosB[ic] - posB;\n" +" if( ic >= src->m_worldNormalOnB.w )//npoints\n" +" {\n" +" dstC->m_jacCoeffInv[ic] = 0.f;\n" +" continue;\n" +" }\n" +" float relVelN;\n" +" {\n" +" b3Float4 linear, angular0, angular1;\n" +" setLinearAndAngular(src->m_worldNormalOnB, r0, r1, &linear, &angular0, &angular1);\n" +" dstC->m_jacCoeffInv[ic] = calcJacCoeff(linear, -linear, angular0, angular1,\n" +" invMassA, &invInertiaA, invMassB, &invInertiaB );\n" +" relVelN = calcRelVel(linear, -linear, angular0, angular1,\n" +" linVelA, angVelA, linVelB, angVelB);\n" +" float e = 0.f;//src->getRestituitionCoeff();\n" +" if( relVelN*relVelN < 0.004f ) e = 0.f;\n" +" dstC->m_b[ic] = e*relVelN;\n" +" //float penetration = src->m_worldPosB[ic].w;\n" +" dstC->m_b[ic] += (src->m_worldPosB[ic].w + positionDrift)*positionConstraintCoeff*dtInv;\n" +" dstC->m_appliedRambdaDt[ic] = 0.f;\n" +" }\n" +" }\n" +" if( src->m_worldNormalOnB.w > 0 )//npoints\n" +" { // prepare friction\n" +" b3Float4 center = b3MakeFloat4(0.f,0.f,0.f,0.f);\n" +" for(int i=0; im_worldNormalOnB.w; i++) \n" +" center += src->m_worldPosB[i];\n" +" center /= (float)src->m_worldNormalOnB.w;\n" +" b3Float4 tangent[2];\n" +" b3PlaneSpace1(src->m_worldNormalOnB,&tangent[0],&tangent[1]);\n" +" \n" +" b3Float4 r[2];\n" +" r[0] = center - posA;\n" +" r[1] = center - posB;\n" +" for(int i=0; i<2; i++)\n" +" {\n" +" b3Float4 linear, angular0, angular1;\n" +" setLinearAndAngular(tangent[i], r[0], r[1], &linear, &angular0, &angular1);\n" +" dstC->m_fJacCoeffInv[i] = calcJacCoeff(linear, -linear, angular0, angular1,\n" +" invMassA, &invInertiaA, invMassB, &invInertiaB );\n" +" dstC->m_fAppliedRambdaDt[i] = 0.f;\n" +" }\n" +" dstC->m_center = center;\n" +" }\n" +" for(int i=0; i<4; i++)\n" +" {\n" +" if( im_worldNormalOnB.w )\n" +" {\n" +" dstC->m_worldPos[i] = src->m_worldPosB[i];\n" +" }\n" +" else\n" +" {\n" +" dstC->m_worldPos[i] = b3MakeFloat4(0.f,0.f,0.f,0.f);\n" +" }\n" +" }\n" +"}\n" +"#pragma OPENCL EXTENSION cl_amd_printf : enable\n" +"#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable\n" +"#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable\n" +"#pragma OPENCL EXTENSION cl_khr_local_int32_extended_atomics : enable\n" +"#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable\n" +"#ifdef cl_ext_atomic_counters_32\n" +"#pragma OPENCL EXTENSION cl_ext_atomic_counters_32 : enable\n" +"#else\n" +"#define counter32_t volatile global int*\n" +"#endif\n" +"typedef unsigned int u32;\n" +"typedef unsigned short u16;\n" +"typedef unsigned char u8;\n" +"#define GET_GROUP_IDX get_group_id(0)\n" +"#define GET_LOCAL_IDX get_local_id(0)\n" +"#define GET_GLOBAL_IDX get_global_id(0)\n" +"#define GET_GROUP_SIZE get_local_size(0)\n" +"#define GET_NUM_GROUPS get_num_groups(0)\n" +"#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE)\n" +"#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE)\n" +"#define AtomInc(x) atom_inc(&(x))\n" +"#define AtomInc1(x, out) out = atom_inc(&(x))\n" +"#define AppendInc(x, out) out = atomic_inc(x)\n" +"#define AtomAdd(x, value) atom_add(&(x), value)\n" +"#define AtomCmpxhg(x, cmp, value) atom_cmpxchg( &(x), cmp, value )\n" +"#define AtomXhg(x, value) atom_xchg ( &(x), value )\n" +"#define SELECT_UINT4( b, a, condition ) select( b,a,condition )\n" +"#define make_float4 (float4)\n" +"#define make_float2 (float2)\n" +"#define make_uint4 (uint4)\n" +"#define make_int4 (int4)\n" +"#define make_uint2 (uint2)\n" +"#define make_int2 (int2)\n" +"#define max2 max\n" +"#define min2 min\n" +"///////////////////////////////////////\n" +"// Vector\n" +"///////////////////////////////////////\n" +"__inline\n" +"float fastDiv(float numerator, float denominator)\n" +"{\n" +" return native_divide(numerator, denominator); \n" +"// return numerator/denominator; \n" +"}\n" +"__inline\n" +"float4 fastDiv4(float4 numerator, float4 denominator)\n" +"{\n" +" return native_divide(numerator, denominator); \n" +"}\n" +"__inline\n" +"float fastSqrtf(float f2)\n" +"{\n" +" return native_sqrt(f2);\n" +"// return sqrt(f2);\n" +"}\n" +"__inline\n" +"float fastRSqrt(float f2)\n" +"{\n" +" return native_rsqrt(f2);\n" +"}\n" +"__inline\n" +"float fastLength4(float4 v)\n" +"{\n" +" return fast_length(v);\n" +"}\n" +"__inline\n" +"float4 fastNormalize4(float4 v)\n" +"{\n" +" return fast_normalize(v);\n" +"}\n" +"__inline\n" +"float sqrtf(float a)\n" +"{\n" +"// return sqrt(a);\n" +" return native_sqrt(a);\n" +"}\n" +"__inline\n" +"float4 cross3(float4 a, float4 b)\n" +"{\n" +" return cross(a,b);\n" +"}\n" +"__inline\n" +"float dot3F4(float4 a, float4 b)\n" +"{\n" +" float4 a1 = make_float4(a.xyz,0.f);\n" +" float4 b1 = make_float4(b.xyz,0.f);\n" +" return dot(a1, b1);\n" +"}\n" +"__inline\n" +"float length3(const float4 a)\n" +"{\n" +" return sqrtf(dot3F4(a,a));\n" +"}\n" +"__inline\n" +"float dot4(const float4 a, const float4 b)\n" +"{\n" +" return dot( a, b );\n" +"}\n" +"// for height\n" +"__inline\n" +"float dot3w1(const float4 point, const float4 eqn)\n" +"{\n" +" return dot3F4(point,eqn) + eqn.w;\n" +"}\n" +"__inline\n" +"float4 normalize3(const float4 a)\n" +"{\n" +" float4 n = make_float4(a.x, a.y, a.z, 0.f);\n" +" return fastNormalize4( n );\n" +"// float length = sqrtf(dot3F4(a, a));\n" +"// return 1.f/length * a;\n" +"}\n" +"__inline\n" +"float4 normalize4(const float4 a)\n" +"{\n" +" float length = sqrtf(dot4(a, a));\n" +" return 1.f/length * a;\n" +"}\n" +"__inline\n" +"float4 createEquation(const float4 a, const float4 b, const float4 c)\n" +"{\n" +" float4 eqn;\n" +" float4 ab = b-a;\n" +" float4 ac = c-a;\n" +" eqn = normalize3( cross3(ab, ac) );\n" +" eqn.w = -dot3F4(eqn,a);\n" +" return eqn;\n" +"}\n" +"#define WG_SIZE 64\n" +"typedef struct\n" +"{\n" +" int m_nConstraints;\n" +" int m_start;\n" +" int m_batchIdx;\n" +" int m_nSplit;\n" +"// int m_paddings[1];\n" +"} ConstBuffer;\n" +"typedef struct\n" +"{\n" +" int m_solveFriction;\n" +" int m_maxBatch; // long batch really kills the performance\n" +" int m_batchIdx;\n" +" int m_nSplit;\n" +"// int m_paddings[1];\n" +"} ConstBufferBatchSolve;\n" +" \n" +"typedef struct \n" +"{\n" +" int m_valInt0;\n" +" int m_valInt1;\n" +" int m_valInt2;\n" +" int m_valInt3;\n" +" float m_val0;\n" +" float m_val1;\n" +" float m_val2;\n" +" float m_val3;\n" +"} SolverDebugInfo;\n" +"typedef struct\n" +"{\n" +" int m_nContacts;\n" +" float m_dt;\n" +" float m_positionDrift;\n" +" float m_positionConstraintCoeff;\n" +"} ConstBufferCTC;\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" +"void ContactToConstraintKernel(__global struct b3Contact4Data* gContact, __global b3RigidBodyData_t* gBodies, __global b3InertiaData_t* gShapes, __global b3ContactConstraint4_t* gConstraintOut, \n" +"int nContacts,\n" +"float dt,\n" +"float positionDrift,\n" +"float positionConstraintCoeff\n" +")\n" +"{\n" +" int gIdx = GET_GLOBAL_IDX;\n" +" \n" +" if( gIdx < nContacts )\n" +" {\n" +" int aIdx = abs(gContact[gIdx].m_bodyAPtrAndSignBit);\n" +" int bIdx = abs(gContact[gIdx].m_bodyBPtrAndSignBit);\n" +" float4 posA = gBodies[aIdx].m_pos;\n" +" float4 linVelA = gBodies[aIdx].m_linVel;\n" +" float4 angVelA = gBodies[aIdx].m_angVel;\n" +" float invMassA = gBodies[aIdx].m_invMass;\n" +" b3Mat3x3 invInertiaA = gShapes[aIdx].m_initInvInertia;\n" +" float4 posB = gBodies[bIdx].m_pos;\n" +" float4 linVelB = gBodies[bIdx].m_linVel;\n" +" float4 angVelB = gBodies[bIdx].m_angVel;\n" +" float invMassB = gBodies[bIdx].m_invMass;\n" +" b3Mat3x3 invInertiaB = gShapes[bIdx].m_initInvInertia;\n" +" b3ContactConstraint4_t cs;\n" +" setConstraint4( posA, linVelA, angVelA, invMassA, invInertiaA, posB, linVelB, angVelB, invMassB, invInertiaB,\n" +" &gContact[gIdx], dt, positionDrift, positionConstraintCoeff,\n" +" &cs );\n" +" \n" +" cs.m_batchIdx = gContact[gIdx].m_batchIdx;\n" +" gConstraintOut[gIdx] = cs;\n" +" }\n" +"}\n" +; diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/solverSetup2.cl b/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/solverSetup2.cl new file mode 100644 index 000000000000..3dc48d435021 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/solverSetup2.cl @@ -0,0 +1,613 @@ +/* +Copyright (c) 2012 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Takahiro Harada + + +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3Contact4Data.h" + +#pragma OPENCL EXTENSION cl_amd_printf : enable +#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable +#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable +#pragma OPENCL EXTENSION cl_khr_local_int32_extended_atomics : enable +#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable + + +#ifdef cl_ext_atomic_counters_32 +#pragma OPENCL EXTENSION cl_ext_atomic_counters_32 : enable +#else +#define counter32_t volatile global int* +#endif + +typedef unsigned int u32; +typedef unsigned short u16; +typedef unsigned char u8; + +#define GET_GROUP_IDX get_group_id(0) +#define GET_LOCAL_IDX get_local_id(0) +#define GET_GLOBAL_IDX get_global_id(0) +#define GET_GROUP_SIZE get_local_size(0) +#define GET_NUM_GROUPS get_num_groups(0) +#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE) +#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE) +#define AtomInc(x) atom_inc(&(x)) +#define AtomInc1(x, out) out = atom_inc(&(x)) +#define AppendInc(x, out) out = atomic_inc(x) +#define AtomAdd(x, value) atom_add(&(x), value) +#define AtomCmpxhg(x, cmp, value) atom_cmpxchg( &(x), cmp, value ) +#define AtomXhg(x, value) atom_xchg ( &(x), value ) + + +#define SELECT_UINT4( b, a, condition ) select( b,a,condition ) + +#define make_float4 (float4) +#define make_float2 (float2) +#define make_uint4 (uint4) +#define make_int4 (int4) +#define make_uint2 (uint2) +#define make_int2 (int2) + + +#define max2 max +#define min2 min + + +/////////////////////////////////////// +// Vector +/////////////////////////////////////// +__inline +float fastDiv(float numerator, float denominator) +{ + return native_divide(numerator, denominator); +// return numerator/denominator; +} + +__inline +float4 fastDiv4(float4 numerator, float4 denominator) +{ + return native_divide(numerator, denominator); +} + +__inline +float fastSqrtf(float f2) +{ + return native_sqrt(f2); +// return sqrt(f2); +} + +__inline +float fastRSqrt(float f2) +{ + return native_rsqrt(f2); +} + +__inline +float fastLength4(float4 v) +{ + return fast_length(v); +} + +__inline +float4 fastNormalize4(float4 v) +{ + return fast_normalize(v); +} + + +__inline +float sqrtf(float a) +{ +// return sqrt(a); + return native_sqrt(a); +} + +__inline +float4 cross3(float4 a, float4 b) +{ + return cross(a,b); +} + +__inline +float dot3F4(float4 a, float4 b) +{ + float4 a1 = make_float4(a.xyz,0.f); + float4 b1 = make_float4(b.xyz,0.f); + return dot(a1, b1); +} + +__inline +float length3(const float4 a) +{ + return sqrtf(dot3F4(a,a)); +} + +__inline +float dot4(const float4 a, const float4 b) +{ + return dot( a, b ); +} + +// for height +__inline +float dot3w1(const float4 point, const float4 eqn) +{ + return dot3F4(point,eqn) + eqn.w; +} + +__inline +float4 normalize3(const float4 a) +{ + float4 n = make_float4(a.x, a.y, a.z, 0.f); + return fastNormalize4( n ); +// float length = sqrtf(dot3F4(a, a)); +// return 1.f/length * a; +} + +__inline +float4 normalize4(const float4 a) +{ + float length = sqrtf(dot4(a, a)); + return 1.f/length * a; +} + +__inline +float4 createEquation(const float4 a, const float4 b, const float4 c) +{ + float4 eqn; + float4 ab = b-a; + float4 ac = c-a; + eqn = normalize3( cross3(ab, ac) ); + eqn.w = -dot3F4(eqn,a); + return eqn; +} + +/////////////////////////////////////// +// Matrix3x3 +/////////////////////////////////////// + +typedef struct +{ + float4 m_row[3]; +}Matrix3x3; + +__inline +Matrix3x3 mtZero(); + +__inline +Matrix3x3 mtIdentity(); + +__inline +Matrix3x3 mtTranspose(Matrix3x3 m); + +__inline +Matrix3x3 mtMul(Matrix3x3 a, Matrix3x3 b); + +__inline +float4 mtMul1(Matrix3x3 a, float4 b); + +__inline +float4 mtMul3(float4 a, Matrix3x3 b); + +__inline +Matrix3x3 mtZero() +{ + Matrix3x3 m; + m.m_row[0] = (float4)(0.f); + m.m_row[1] = (float4)(0.f); + m.m_row[2] = (float4)(0.f); + return m; +} + +__inline +Matrix3x3 mtIdentity() +{ + Matrix3x3 m; + m.m_row[0] = (float4)(1,0,0,0); + m.m_row[1] = (float4)(0,1,0,0); + m.m_row[2] = (float4)(0,0,1,0); + return m; +} + +__inline +Matrix3x3 mtTranspose(Matrix3x3 m) +{ + Matrix3x3 out; + out.m_row[0] = (float4)(m.m_row[0].x, m.m_row[1].x, m.m_row[2].x, 0.f); + out.m_row[1] = (float4)(m.m_row[0].y, m.m_row[1].y, m.m_row[2].y, 0.f); + out.m_row[2] = (float4)(m.m_row[0].z, m.m_row[1].z, m.m_row[2].z, 0.f); + return out; +} + +__inline +Matrix3x3 mtMul(Matrix3x3 a, Matrix3x3 b) +{ + Matrix3x3 transB; + transB = mtTranspose( b ); + Matrix3x3 ans; + // why this doesn't run when 0ing in the for{} + a.m_row[0].w = 0.f; + a.m_row[1].w = 0.f; + a.m_row[2].w = 0.f; + for(int i=0; i<3; i++) + { +// a.m_row[i].w = 0.f; + ans.m_row[i].x = dot3F4(a.m_row[i],transB.m_row[0]); + ans.m_row[i].y = dot3F4(a.m_row[i],transB.m_row[1]); + ans.m_row[i].z = dot3F4(a.m_row[i],transB.m_row[2]); + ans.m_row[i].w = 0.f; + } + return ans; +} + +__inline +float4 mtMul1(Matrix3x3 a, float4 b) +{ + float4 ans; + ans.x = dot3F4( a.m_row[0], b ); + ans.y = dot3F4( a.m_row[1], b ); + ans.z = dot3F4( a.m_row[2], b ); + ans.w = 0.f; + return ans; +} + +__inline +float4 mtMul3(float4 a, Matrix3x3 b) +{ + float4 colx = make_float4(b.m_row[0].x, b.m_row[1].x, b.m_row[2].x, 0); + float4 coly = make_float4(b.m_row[0].y, b.m_row[1].y, b.m_row[2].y, 0); + float4 colz = make_float4(b.m_row[0].z, b.m_row[1].z, b.m_row[2].z, 0); + + float4 ans; + ans.x = dot3F4( a, colx ); + ans.y = dot3F4( a, coly ); + ans.z = dot3F4( a, colz ); + return ans; +} + +/////////////////////////////////////// +// Quaternion +/////////////////////////////////////// + +typedef float4 Quaternion; + +__inline +Quaternion qtMul(Quaternion a, Quaternion b); + +__inline +Quaternion qtNormalize(Quaternion in); + +__inline +float4 qtRotate(Quaternion q, float4 vec); + +__inline +Quaternion qtInvert(Quaternion q); + + + + + +__inline +Quaternion qtMul(Quaternion a, Quaternion b) +{ + Quaternion ans; + ans = cross3( a, b ); + ans += a.w*b+b.w*a; +// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z); + ans.w = a.w*b.w - dot3F4(a, b); + return ans; +} + +__inline +Quaternion qtNormalize(Quaternion in) +{ + return fastNormalize4(in); +// in /= length( in ); +// return in; +} +__inline +float4 qtRotate(Quaternion q, float4 vec) +{ + Quaternion qInv = qtInvert( q ); + float4 vcpy = vec; + vcpy.w = 0.f; + float4 out = qtMul(qtMul(q,vcpy),qInv); + return out; +} + +__inline +Quaternion qtInvert(Quaternion q) +{ + return (Quaternion)(-q.xyz, q.w); +} + +__inline +float4 qtInvRotate(const Quaternion q, float4 vec) +{ + return qtRotate( qtInvert( q ), vec ); +} + + + + +#define WG_SIZE 64 + +typedef struct +{ + float4 m_pos; + Quaternion m_quat; + float4 m_linVel; + float4 m_angVel; + + u32 m_shapeIdx; + float m_invMass; + float m_restituitionCoeff; + float m_frictionCoeff; +} Body; + +typedef struct +{ + Matrix3x3 m_invInertia; + Matrix3x3 m_initInvInertia; +} Shape; + +typedef struct +{ + float4 m_linear; + float4 m_worldPos[4]; + float4 m_center; + float m_jacCoeffInv[4]; + float m_b[4]; + float m_appliedRambdaDt[4]; + + float m_fJacCoeffInv[2]; + float m_fAppliedRambdaDt[2]; + + u32 m_bodyA; + u32 m_bodyB; + + int m_batchIdx; + u32 m_paddings[1]; +} Constraint4; + + + +typedef struct +{ + int m_nConstraints; + int m_start; + int m_batchIdx; + int m_nSplit; +// int m_paddings[1]; +} ConstBuffer; + +typedef struct +{ + int m_solveFriction; + int m_maxBatch; // long batch really kills the performance + int m_batchIdx; + int m_nSplit; +// int m_paddings[1]; +} ConstBufferBatchSolve; + + + + + +typedef struct +{ + int m_valInt0; + int m_valInt1; + int m_valInt2; + int m_valInt3; + + float m_val0; + float m_val1; + float m_val2; + float m_val3; +} SolverDebugInfo; + + + + +// others +__kernel +__attribute__((reqd_work_group_size(WG_SIZE,1,1))) +void ReorderContactKernel(__global struct b3Contact4Data* in, __global struct b3Contact4Data* out, __global int2* sortData, int4 cb ) +{ + int nContacts = cb.x; + int gIdx = GET_GLOBAL_IDX; + + if( gIdx < nContacts ) + { + int srcIdx = sortData[gIdx].y; + out[gIdx] = in[srcIdx]; + } +} + +__kernel __attribute__((reqd_work_group_size(WG_SIZE,1,1))) +void SetDeterminismSortDataChildShapeB(__global struct b3Contact4Data* contactsIn, __global int2* sortDataOut, int nContacts) +{ + int gIdx = GET_GLOBAL_IDX; + + if( gIdx < nContacts ) + { + int2 sd; + sd.x = contactsIn[gIdx].m_childIndexB; + sd.y = gIdx; + sortDataOut[gIdx] = sd; + } +} + +__kernel __attribute__((reqd_work_group_size(WG_SIZE,1,1))) +void SetDeterminismSortDataChildShapeA(__global struct b3Contact4Data* contactsIn, __global int2* sortDataInOut, int nContacts) +{ + int gIdx = GET_GLOBAL_IDX; + + if( gIdx < nContacts ) + { + int2 sdIn; + sdIn = sortDataInOut[gIdx]; + int2 sdOut; + sdOut.x = contactsIn[sdIn.y].m_childIndexA; + sdOut.y = sdIn.y; + sortDataInOut[gIdx] = sdOut; + } +} + +__kernel __attribute__((reqd_work_group_size(WG_SIZE,1,1))) +void SetDeterminismSortDataBodyA(__global struct b3Contact4Data* contactsIn, __global int2* sortDataInOut, int nContacts) +{ + int gIdx = GET_GLOBAL_IDX; + + if( gIdx < nContacts ) + { + int2 sdIn; + sdIn = sortDataInOut[gIdx]; + int2 sdOut; + sdOut.x = contactsIn[sdIn.y].m_bodyAPtrAndSignBit; + sdOut.y = sdIn.y; + sortDataInOut[gIdx] = sdOut; + } +} + + +__kernel +__attribute__((reqd_work_group_size(WG_SIZE,1,1))) +void SetDeterminismSortDataBodyB(__global struct b3Contact4Data* contactsIn, __global int2* sortDataInOut, int nContacts) +{ + int gIdx = GET_GLOBAL_IDX; + + if( gIdx < nContacts ) + { + int2 sdIn; + sdIn = sortDataInOut[gIdx]; + int2 sdOut; + sdOut.x = contactsIn[sdIn.y].m_bodyBPtrAndSignBit; + sdOut.y = sdIn.y; + sortDataInOut[gIdx] = sdOut; + } +} + + + + +typedef struct +{ + int m_nContacts; + int m_staticIdx; + float m_scale; + int m_nSplit; +} ConstBufferSSD; + + +__constant const int gridTable4x4[] = +{ + 0,1,17,16, + 1,2,18,19, + 17,18,32,3, + 16,19,3,34 +}; + +__constant const int gridTable8x8[] = +{ + 0, 2, 3, 16, 17, 18, 19, 1, + 66, 64, 80, 67, 82, 81, 65, 83, + 131,144,128,130,147,129,145,146, + 208,195,194,192,193,211,210,209, + 21, 22, 23, 5, 4, 6, 7, 20, + 86, 85, 69, 87, 70, 68, 84, 71, + 151,133,149,150,135,148,132,134, + 197,27,214,213,212,199,198,196 + +}; + + + + +#define USE_SPATIAL_BATCHING 1 +#define USE_4x4_GRID 1 + +__kernel +__attribute__((reqd_work_group_size(WG_SIZE,1,1))) +void SetSortDataKernel(__global struct b3Contact4Data* gContact, __global Body* gBodies, __global int2* gSortDataOut, +int nContacts,float scale,int4 nSplit,int staticIdx) + +{ + int gIdx = GET_GLOBAL_IDX; + + if( gIdx < nContacts ) + { + int aPtrAndSignBit = gContact[gIdx].m_bodyAPtrAndSignBit; + int bPtrAndSignBit = gContact[gIdx].m_bodyBPtrAndSignBit; + + int aIdx = abs(aPtrAndSignBit ); + int bIdx = abs(bPtrAndSignBit); + + bool aStatic = (aPtrAndSignBit<0) ||(aPtrAndSignBit==staticIdx); + bool bStatic = (bPtrAndSignBit<0) ||(bPtrAndSignBit==staticIdx); + +#if USE_SPATIAL_BATCHING + int idx = (aStatic)? bIdx: aIdx; + float4 p = gBodies[idx].m_pos; + int xIdx = (int)((p.x-((p.x<0.f)?1.f:0.f))*scale) & (nSplit.x-1); + int yIdx = (int)((p.y-((p.y<0.f)?1.f:0.f))*scale) & (nSplit.y-1); + int zIdx = (int)((p.z-((p.z<0.f)?1.f:0.f))*scale) & (nSplit.z-1); + int newIndex = (xIdx+yIdx*nSplit.x+zIdx*nSplit.x*nSplit.y); + +#else//USE_SPATIAL_BATCHING + #if USE_4x4_GRID + int aa = aIdx&3; + int bb = bIdx&3; + if (aStatic) + aa = bb; + if (bStatic) + bb = aa; + + int gridIndex = aa + bb*4; + int newIndex = gridTable4x4[gridIndex]; + #else//USE_4x4_GRID + int aa = aIdx&7; + int bb = bIdx&7; + if (aStatic) + aa = bb; + if (bStatic) + bb = aa; + + int gridIndex = aa + bb*8; + int newIndex = gridTable8x8[gridIndex]; + #endif//USE_4x4_GRID +#endif//USE_SPATIAL_BATCHING + + + gSortDataOut[gIdx].x = newIndex; + gSortDataOut[gIdx].y = gIdx; + } + else + { + gSortDataOut[gIdx].x = 0xffffffff; + } +} + +__kernel +__attribute__((reqd_work_group_size(WG_SIZE,1,1))) +void CopyConstraintKernel(__global struct b3Contact4Data* gIn, __global struct b3Contact4Data* gOut, int4 cb ) +{ + int gIdx = GET_GLOBAL_IDX; + if( gIdx < cb.x ) + { + gOut[gIdx] = gIn[gIdx]; + } +} + + + diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/solverSetup2.h b/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/solverSetup2.h new file mode 100644 index 000000000000..1b5819f6cf32 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/solverSetup2.h @@ -0,0 +1,601 @@ +//this file is autogenerated using stringify.bat (premake --stringify) in the build folder of this project +static const char* solverSetup2CL= \ +"/*\n" +"Copyright (c) 2012 Advanced Micro Devices, Inc. \n" +"This software is provided 'as-is', without any express or implied warranty.\n" +"In no event will the authors be held liable for any damages arising from the use of this software.\n" +"Permission is granted to anyone to use this software for any purpose, \n" +"including commercial applications, and to alter it and redistribute it freely, \n" +"subject to the following restrictions:\n" +"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.\n" +"2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n" +"3. This notice may not be removed or altered from any source distribution.\n" +"*/\n" +"//Originally written by Takahiro Harada\n" +"#ifndef B3_CONTACT4DATA_H\n" +"#define B3_CONTACT4DATA_H\n" +"#ifndef B3_FLOAT4_H\n" +"#define B3_FLOAT4_H\n" +"#ifndef B3_PLATFORM_DEFINITIONS_H\n" +"#define B3_PLATFORM_DEFINITIONS_H\n" +"struct MyTest\n" +"{\n" +" int bla;\n" +"};\n" +"#ifdef __cplusplus\n" +"#else\n" +"//keep B3_LARGE_FLOAT*B3_LARGE_FLOAT < FLT_MAX\n" +"#define B3_LARGE_FLOAT 1e18f\n" +"#define B3_INFINITY 1e18f\n" +"#define b3Assert(a)\n" +"#define b3ConstArray(a) __global const a*\n" +"#define b3AtomicInc atomic_inc\n" +"#define b3AtomicAdd atomic_add\n" +"#define b3Fabs fabs\n" +"#define b3Sqrt native_sqrt\n" +"#define b3Sin native_sin\n" +"#define b3Cos native_cos\n" +"#define B3_STATIC\n" +"#endif\n" +"#endif\n" +"#ifdef __cplusplus\n" +"#else\n" +" typedef float4 b3Float4;\n" +" #define b3Float4ConstArg const b3Float4\n" +" #define b3MakeFloat4 (float4)\n" +" float b3Dot3F4(b3Float4ConstArg v0,b3Float4ConstArg v1)\n" +" {\n" +" float4 a1 = b3MakeFloat4(v0.xyz,0.f);\n" +" float4 b1 = b3MakeFloat4(v1.xyz,0.f);\n" +" return dot(a1, b1);\n" +" }\n" +" b3Float4 b3Cross3(b3Float4ConstArg v0,b3Float4ConstArg v1)\n" +" {\n" +" float4 a1 = b3MakeFloat4(v0.xyz,0.f);\n" +" float4 b1 = b3MakeFloat4(v1.xyz,0.f);\n" +" return cross(a1, b1);\n" +" }\n" +" #define b3MinFloat4 min\n" +" #define b3MaxFloat4 max\n" +" #define b3Normalized(a) normalize(a)\n" +"#endif \n" +" \n" +"inline bool b3IsAlmostZero(b3Float4ConstArg v)\n" +"{\n" +" if(b3Fabs(v.x)>1e-6 || b3Fabs(v.y)>1e-6 || b3Fabs(v.z)>1e-6) \n" +" return false;\n" +" return true;\n" +"}\n" +"inline int b3MaxDot( b3Float4ConstArg vec, __global const b3Float4* vecArray, int vecLen, float* dotOut )\n" +"{\n" +" float maxDot = -B3_INFINITY;\n" +" int i = 0;\n" +" int ptIndex = -1;\n" +" for( i = 0; i < vecLen; i++ )\n" +" {\n" +" float dot = b3Dot3F4(vecArray[i],vec);\n" +" \n" +" if( dot > maxDot )\n" +" {\n" +" maxDot = dot;\n" +" ptIndex = i;\n" +" }\n" +" }\n" +" b3Assert(ptIndex>=0);\n" +" if (ptIndex<0)\n" +" {\n" +" ptIndex = 0;\n" +" }\n" +" *dotOut = maxDot;\n" +" return ptIndex;\n" +"}\n" +"#endif //B3_FLOAT4_H\n" +"typedef struct b3Contact4Data b3Contact4Data_t;\n" +"struct b3Contact4Data\n" +"{\n" +" b3Float4 m_worldPosB[4];\n" +"// b3Float4 m_localPosA[4];\n" +"// b3Float4 m_localPosB[4];\n" +" b3Float4 m_worldNormalOnB; // w: m_nPoints\n" +" unsigned short m_restituitionCoeffCmp;\n" +" unsigned short m_frictionCoeffCmp;\n" +" int m_batchIdx;\n" +" int m_bodyAPtrAndSignBit;//x:m_bodyAPtr, y:m_bodyBPtr\n" +" int m_bodyBPtrAndSignBit;\n" +" int m_childIndexA;\n" +" int m_childIndexB;\n" +" int m_unused1;\n" +" int m_unused2;\n" +"};\n" +"inline int b3Contact4Data_getNumPoints(const struct b3Contact4Data* contact)\n" +"{\n" +" return (int)contact->m_worldNormalOnB.w;\n" +"};\n" +"inline void b3Contact4Data_setNumPoints(struct b3Contact4Data* contact, int numPoints)\n" +"{\n" +" contact->m_worldNormalOnB.w = (float)numPoints;\n" +"};\n" +"#endif //B3_CONTACT4DATA_H\n" +"#pragma OPENCL EXTENSION cl_amd_printf : enable\n" +"#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable\n" +"#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable\n" +"#pragma OPENCL EXTENSION cl_khr_local_int32_extended_atomics : enable\n" +"#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable\n" +"#ifdef cl_ext_atomic_counters_32\n" +"#pragma OPENCL EXTENSION cl_ext_atomic_counters_32 : enable\n" +"#else\n" +"#define counter32_t volatile global int*\n" +"#endif\n" +"typedef unsigned int u32;\n" +"typedef unsigned short u16;\n" +"typedef unsigned char u8;\n" +"#define GET_GROUP_IDX get_group_id(0)\n" +"#define GET_LOCAL_IDX get_local_id(0)\n" +"#define GET_GLOBAL_IDX get_global_id(0)\n" +"#define GET_GROUP_SIZE get_local_size(0)\n" +"#define GET_NUM_GROUPS get_num_groups(0)\n" +"#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE)\n" +"#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE)\n" +"#define AtomInc(x) atom_inc(&(x))\n" +"#define AtomInc1(x, out) out = atom_inc(&(x))\n" +"#define AppendInc(x, out) out = atomic_inc(x)\n" +"#define AtomAdd(x, value) atom_add(&(x), value)\n" +"#define AtomCmpxhg(x, cmp, value) atom_cmpxchg( &(x), cmp, value )\n" +"#define AtomXhg(x, value) atom_xchg ( &(x), value )\n" +"#define SELECT_UINT4( b, a, condition ) select( b,a,condition )\n" +"#define make_float4 (float4)\n" +"#define make_float2 (float2)\n" +"#define make_uint4 (uint4)\n" +"#define make_int4 (int4)\n" +"#define make_uint2 (uint2)\n" +"#define make_int2 (int2)\n" +"#define max2 max\n" +"#define min2 min\n" +"///////////////////////////////////////\n" +"// Vector\n" +"///////////////////////////////////////\n" +"__inline\n" +"float fastDiv(float numerator, float denominator)\n" +"{\n" +" return native_divide(numerator, denominator); \n" +"// return numerator/denominator; \n" +"}\n" +"__inline\n" +"float4 fastDiv4(float4 numerator, float4 denominator)\n" +"{\n" +" return native_divide(numerator, denominator); \n" +"}\n" +"__inline\n" +"float fastSqrtf(float f2)\n" +"{\n" +" return native_sqrt(f2);\n" +"// return sqrt(f2);\n" +"}\n" +"__inline\n" +"float fastRSqrt(float f2)\n" +"{\n" +" return native_rsqrt(f2);\n" +"}\n" +"__inline\n" +"float fastLength4(float4 v)\n" +"{\n" +" return fast_length(v);\n" +"}\n" +"__inline\n" +"float4 fastNormalize4(float4 v)\n" +"{\n" +" return fast_normalize(v);\n" +"}\n" +"__inline\n" +"float sqrtf(float a)\n" +"{\n" +"// return sqrt(a);\n" +" return native_sqrt(a);\n" +"}\n" +"__inline\n" +"float4 cross3(float4 a, float4 b)\n" +"{\n" +" return cross(a,b);\n" +"}\n" +"__inline\n" +"float dot3F4(float4 a, float4 b)\n" +"{\n" +" float4 a1 = make_float4(a.xyz,0.f);\n" +" float4 b1 = make_float4(b.xyz,0.f);\n" +" return dot(a1, b1);\n" +"}\n" +"__inline\n" +"float length3(const float4 a)\n" +"{\n" +" return sqrtf(dot3F4(a,a));\n" +"}\n" +"__inline\n" +"float dot4(const float4 a, const float4 b)\n" +"{\n" +" return dot( a, b );\n" +"}\n" +"// for height\n" +"__inline\n" +"float dot3w1(const float4 point, const float4 eqn)\n" +"{\n" +" return dot3F4(point,eqn) + eqn.w;\n" +"}\n" +"__inline\n" +"float4 normalize3(const float4 a)\n" +"{\n" +" float4 n = make_float4(a.x, a.y, a.z, 0.f);\n" +" return fastNormalize4( n );\n" +"// float length = sqrtf(dot3F4(a, a));\n" +"// return 1.f/length * a;\n" +"}\n" +"__inline\n" +"float4 normalize4(const float4 a)\n" +"{\n" +" float length = sqrtf(dot4(a, a));\n" +" return 1.f/length * a;\n" +"}\n" +"__inline\n" +"float4 createEquation(const float4 a, const float4 b, const float4 c)\n" +"{\n" +" float4 eqn;\n" +" float4 ab = b-a;\n" +" float4 ac = c-a;\n" +" eqn = normalize3( cross3(ab, ac) );\n" +" eqn.w = -dot3F4(eqn,a);\n" +" return eqn;\n" +"}\n" +"///////////////////////////////////////\n" +"// Matrix3x3\n" +"///////////////////////////////////////\n" +"typedef struct\n" +"{\n" +" float4 m_row[3];\n" +"}Matrix3x3;\n" +"__inline\n" +"Matrix3x3 mtZero();\n" +"__inline\n" +"Matrix3x3 mtIdentity();\n" +"__inline\n" +"Matrix3x3 mtTranspose(Matrix3x3 m);\n" +"__inline\n" +"Matrix3x3 mtMul(Matrix3x3 a, Matrix3x3 b);\n" +"__inline\n" +"float4 mtMul1(Matrix3x3 a, float4 b);\n" +"__inline\n" +"float4 mtMul3(float4 a, Matrix3x3 b);\n" +"__inline\n" +"Matrix3x3 mtZero()\n" +"{\n" +" Matrix3x3 m;\n" +" m.m_row[0] = (float4)(0.f);\n" +" m.m_row[1] = (float4)(0.f);\n" +" m.m_row[2] = (float4)(0.f);\n" +" return m;\n" +"}\n" +"__inline\n" +"Matrix3x3 mtIdentity()\n" +"{\n" +" Matrix3x3 m;\n" +" m.m_row[0] = (float4)(1,0,0,0);\n" +" m.m_row[1] = (float4)(0,1,0,0);\n" +" m.m_row[2] = (float4)(0,0,1,0);\n" +" return m;\n" +"}\n" +"__inline\n" +"Matrix3x3 mtTranspose(Matrix3x3 m)\n" +"{\n" +" Matrix3x3 out;\n" +" out.m_row[0] = (float4)(m.m_row[0].x, m.m_row[1].x, m.m_row[2].x, 0.f);\n" +" out.m_row[1] = (float4)(m.m_row[0].y, m.m_row[1].y, m.m_row[2].y, 0.f);\n" +" out.m_row[2] = (float4)(m.m_row[0].z, m.m_row[1].z, m.m_row[2].z, 0.f);\n" +" return out;\n" +"}\n" +"__inline\n" +"Matrix3x3 mtMul(Matrix3x3 a, Matrix3x3 b)\n" +"{\n" +" Matrix3x3 transB;\n" +" transB = mtTranspose( b );\n" +" Matrix3x3 ans;\n" +" // why this doesn't run when 0ing in the for{}\n" +" a.m_row[0].w = 0.f;\n" +" a.m_row[1].w = 0.f;\n" +" a.m_row[2].w = 0.f;\n" +" for(int i=0; i<3; i++)\n" +" {\n" +"// a.m_row[i].w = 0.f;\n" +" ans.m_row[i].x = dot3F4(a.m_row[i],transB.m_row[0]);\n" +" ans.m_row[i].y = dot3F4(a.m_row[i],transB.m_row[1]);\n" +" ans.m_row[i].z = dot3F4(a.m_row[i],transB.m_row[2]);\n" +" ans.m_row[i].w = 0.f;\n" +" }\n" +" return ans;\n" +"}\n" +"__inline\n" +"float4 mtMul1(Matrix3x3 a, float4 b)\n" +"{\n" +" float4 ans;\n" +" ans.x = dot3F4( a.m_row[0], b );\n" +" ans.y = dot3F4( a.m_row[1], b );\n" +" ans.z = dot3F4( a.m_row[2], b );\n" +" ans.w = 0.f;\n" +" return ans;\n" +"}\n" +"__inline\n" +"float4 mtMul3(float4 a, Matrix3x3 b)\n" +"{\n" +" float4 colx = make_float4(b.m_row[0].x, b.m_row[1].x, b.m_row[2].x, 0);\n" +" float4 coly = make_float4(b.m_row[0].y, b.m_row[1].y, b.m_row[2].y, 0);\n" +" float4 colz = make_float4(b.m_row[0].z, b.m_row[1].z, b.m_row[2].z, 0);\n" +" float4 ans;\n" +" ans.x = dot3F4( a, colx );\n" +" ans.y = dot3F4( a, coly );\n" +" ans.z = dot3F4( a, colz );\n" +" return ans;\n" +"}\n" +"///////////////////////////////////////\n" +"// Quaternion\n" +"///////////////////////////////////////\n" +"typedef float4 Quaternion;\n" +"__inline\n" +"Quaternion qtMul(Quaternion a, Quaternion b);\n" +"__inline\n" +"Quaternion qtNormalize(Quaternion in);\n" +"__inline\n" +"float4 qtRotate(Quaternion q, float4 vec);\n" +"__inline\n" +"Quaternion qtInvert(Quaternion q);\n" +"__inline\n" +"Quaternion qtMul(Quaternion a, Quaternion b)\n" +"{\n" +" Quaternion ans;\n" +" ans = cross3( a, b );\n" +" ans += a.w*b+b.w*a;\n" +"// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z);\n" +" ans.w = a.w*b.w - dot3F4(a, b);\n" +" return ans;\n" +"}\n" +"__inline\n" +"Quaternion qtNormalize(Quaternion in)\n" +"{\n" +" return fastNormalize4(in);\n" +"// in /= length( in );\n" +"// return in;\n" +"}\n" +"__inline\n" +"float4 qtRotate(Quaternion q, float4 vec)\n" +"{\n" +" Quaternion qInv = qtInvert( q );\n" +" float4 vcpy = vec;\n" +" vcpy.w = 0.f;\n" +" float4 out = qtMul(qtMul(q,vcpy),qInv);\n" +" return out;\n" +"}\n" +"__inline\n" +"Quaternion qtInvert(Quaternion q)\n" +"{\n" +" return (Quaternion)(-q.xyz, q.w);\n" +"}\n" +"__inline\n" +"float4 qtInvRotate(const Quaternion q, float4 vec)\n" +"{\n" +" return qtRotate( qtInvert( q ), vec );\n" +"}\n" +"#define WG_SIZE 64\n" +"typedef struct\n" +"{\n" +" float4 m_pos;\n" +" Quaternion m_quat;\n" +" float4 m_linVel;\n" +" float4 m_angVel;\n" +" u32 m_shapeIdx;\n" +" float m_invMass;\n" +" float m_restituitionCoeff;\n" +" float m_frictionCoeff;\n" +"} Body;\n" +"typedef struct\n" +"{\n" +" Matrix3x3 m_invInertia;\n" +" Matrix3x3 m_initInvInertia;\n" +"} Shape;\n" +"typedef struct\n" +"{\n" +" float4 m_linear;\n" +" float4 m_worldPos[4];\n" +" float4 m_center; \n" +" float m_jacCoeffInv[4];\n" +" float m_b[4];\n" +" float m_appliedRambdaDt[4];\n" +" float m_fJacCoeffInv[2]; \n" +" float m_fAppliedRambdaDt[2]; \n" +" u32 m_bodyA;\n" +" u32 m_bodyB;\n" +" int m_batchIdx;\n" +" u32 m_paddings[1];\n" +"} Constraint4;\n" +"typedef struct\n" +"{\n" +" int m_nConstraints;\n" +" int m_start;\n" +" int m_batchIdx;\n" +" int m_nSplit;\n" +"// int m_paddings[1];\n" +"} ConstBuffer;\n" +"typedef struct\n" +"{\n" +" int m_solveFriction;\n" +" int m_maxBatch; // long batch really kills the performance\n" +" int m_batchIdx;\n" +" int m_nSplit;\n" +"// int m_paddings[1];\n" +"} ConstBufferBatchSolve;\n" +" \n" +"typedef struct \n" +"{\n" +" int m_valInt0;\n" +" int m_valInt1;\n" +" int m_valInt2;\n" +" int m_valInt3;\n" +" float m_val0;\n" +" float m_val1;\n" +" float m_val2;\n" +" float m_val3;\n" +"} SolverDebugInfo;\n" +"// others\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" +"void ReorderContactKernel(__global struct b3Contact4Data* in, __global struct b3Contact4Data* out, __global int2* sortData, int4 cb )\n" +"{\n" +" int nContacts = cb.x;\n" +" int gIdx = GET_GLOBAL_IDX;\n" +" if( gIdx < nContacts )\n" +" {\n" +" int srcIdx = sortData[gIdx].y;\n" +" out[gIdx] = in[srcIdx];\n" +" }\n" +"}\n" +"__kernel __attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" +"void SetDeterminismSortDataChildShapeB(__global struct b3Contact4Data* contactsIn, __global int2* sortDataOut, int nContacts)\n" +"{\n" +" int gIdx = GET_GLOBAL_IDX;\n" +" if( gIdx < nContacts )\n" +" {\n" +" int2 sd;\n" +" sd.x = contactsIn[gIdx].m_childIndexB;\n" +" sd.y = gIdx;\n" +" sortDataOut[gIdx] = sd;\n" +" }\n" +"}\n" +"__kernel __attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" +"void SetDeterminismSortDataChildShapeA(__global struct b3Contact4Data* contactsIn, __global int2* sortDataInOut, int nContacts)\n" +"{\n" +" int gIdx = GET_GLOBAL_IDX;\n" +" if( gIdx < nContacts )\n" +" {\n" +" int2 sdIn;\n" +" sdIn = sortDataInOut[gIdx];\n" +" int2 sdOut;\n" +" sdOut.x = contactsIn[sdIn.y].m_childIndexA;\n" +" sdOut.y = sdIn.y;\n" +" sortDataInOut[gIdx] = sdOut;\n" +" }\n" +"}\n" +"__kernel __attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" +"void SetDeterminismSortDataBodyA(__global struct b3Contact4Data* contactsIn, __global int2* sortDataInOut, int nContacts)\n" +"{\n" +" int gIdx = GET_GLOBAL_IDX;\n" +" if( gIdx < nContacts )\n" +" {\n" +" int2 sdIn;\n" +" sdIn = sortDataInOut[gIdx];\n" +" int2 sdOut;\n" +" sdOut.x = contactsIn[sdIn.y].m_bodyAPtrAndSignBit;\n" +" sdOut.y = sdIn.y;\n" +" sortDataInOut[gIdx] = sdOut;\n" +" }\n" +"}\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" +"void SetDeterminismSortDataBodyB(__global struct b3Contact4Data* contactsIn, __global int2* sortDataInOut, int nContacts)\n" +"{\n" +" int gIdx = GET_GLOBAL_IDX;\n" +" if( gIdx < nContacts )\n" +" {\n" +" int2 sdIn;\n" +" sdIn = sortDataInOut[gIdx];\n" +" int2 sdOut;\n" +" sdOut.x = contactsIn[sdIn.y].m_bodyBPtrAndSignBit;\n" +" sdOut.y = sdIn.y;\n" +" sortDataInOut[gIdx] = sdOut;\n" +" }\n" +"}\n" +"typedef struct\n" +"{\n" +" int m_nContacts;\n" +" int m_staticIdx;\n" +" float m_scale;\n" +" int m_nSplit;\n" +"} ConstBufferSSD;\n" +"__constant const int gridTable4x4[] = \n" +"{\n" +" 0,1,17,16,\n" +" 1,2,18,19,\n" +" 17,18,32,3,\n" +" 16,19,3,34\n" +"};\n" +"__constant const int gridTable8x8[] = \n" +"{\n" +" 0, 2, 3, 16, 17, 18, 19, 1,\n" +" 66, 64, 80, 67, 82, 81, 65, 83,\n" +" 131,144,128,130,147,129,145,146,\n" +" 208,195,194,192,193,211,210,209,\n" +" 21, 22, 23, 5, 4, 6, 7, 20,\n" +" 86, 85, 69, 87, 70, 68, 84, 71,\n" +" 151,133,149,150,135,148,132,134,\n" +" 197,27,214,213,212,199,198,196\n" +" \n" +"};\n" +"#define USE_SPATIAL_BATCHING 1\n" +"#define USE_4x4_GRID 1\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" +"void SetSortDataKernel(__global struct b3Contact4Data* gContact, __global Body* gBodies, __global int2* gSortDataOut, \n" +"int nContacts,float scale,int4 nSplit,int staticIdx)\n" +"{\n" +" int gIdx = GET_GLOBAL_IDX;\n" +" \n" +" if( gIdx < nContacts )\n" +" {\n" +" int aPtrAndSignBit = gContact[gIdx].m_bodyAPtrAndSignBit;\n" +" int bPtrAndSignBit = gContact[gIdx].m_bodyBPtrAndSignBit;\n" +" int aIdx = abs(aPtrAndSignBit );\n" +" int bIdx = abs(bPtrAndSignBit);\n" +" bool aStatic = (aPtrAndSignBit<0) ||(aPtrAndSignBit==staticIdx);\n" +" bool bStatic = (bPtrAndSignBit<0) ||(bPtrAndSignBit==staticIdx);\n" +"#if USE_SPATIAL_BATCHING \n" +" int idx = (aStatic)? bIdx: aIdx;\n" +" float4 p = gBodies[idx].m_pos;\n" +" int xIdx = (int)((p.x-((p.x<0.f)?1.f:0.f))*scale) & (nSplit.x-1);\n" +" int yIdx = (int)((p.y-((p.y<0.f)?1.f:0.f))*scale) & (nSplit.y-1);\n" +" int zIdx = (int)((p.z-((p.z<0.f)?1.f:0.f))*scale) & (nSplit.z-1);\n" +" int newIndex = (xIdx+yIdx*nSplit.x+zIdx*nSplit.x*nSplit.y);\n" +" \n" +"#else//USE_SPATIAL_BATCHING\n" +" #if USE_4x4_GRID\n" +" int aa = aIdx&3;\n" +" int bb = bIdx&3;\n" +" if (aStatic)\n" +" aa = bb;\n" +" if (bStatic)\n" +" bb = aa;\n" +" int gridIndex = aa + bb*4;\n" +" int newIndex = gridTable4x4[gridIndex];\n" +" #else//USE_4x4_GRID\n" +" int aa = aIdx&7;\n" +" int bb = bIdx&7;\n" +" if (aStatic)\n" +" aa = bb;\n" +" if (bStatic)\n" +" bb = aa;\n" +" int gridIndex = aa + bb*8;\n" +" int newIndex = gridTable8x8[gridIndex];\n" +" #endif//USE_4x4_GRID\n" +"#endif//USE_SPATIAL_BATCHING\n" +" gSortDataOut[gIdx].x = newIndex;\n" +" gSortDataOut[gIdx].y = gIdx;\n" +" }\n" +" else\n" +" {\n" +" gSortDataOut[gIdx].x = 0xffffffff;\n" +" }\n" +"}\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" +"void CopyConstraintKernel(__global struct b3Contact4Data* gIn, __global struct b3Contact4Data* gOut, int4 cb )\n" +"{\n" +" int gIdx = GET_GLOBAL_IDX;\n" +" if( gIdx < cb.x )\n" +" {\n" +" gOut[gIdx] = gIn[gIdx];\n" +" }\n" +"}\n" +; diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/solverUtils.cl b/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/solverUtils.cl new file mode 100644 index 000000000000..a21a08c3b4ef --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/solverUtils.cl @@ -0,0 +1,968 @@ +/* +Copyright (c) 2013 Advanced Micro Devices, Inc. + +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. +*/ +//Originally written by Erwin Coumans + +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3Contact4Data.h" + +#pragma OPENCL EXTENSION cl_amd_printf : enable +#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable +#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable +#pragma OPENCL EXTENSION cl_khr_local_int32_extended_atomics : enable +#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable + + +#ifdef cl_ext_atomic_counters_32 +#pragma OPENCL EXTENSION cl_ext_atomic_counters_32 : enable +#else +#define counter32_t volatile global int* +#endif + +typedef unsigned int u32; +typedef unsigned short u16; +typedef unsigned char u8; + +#define GET_GROUP_IDX get_group_id(0) +#define GET_LOCAL_IDX get_local_id(0) +#define GET_GLOBAL_IDX get_global_id(0) +#define GET_GROUP_SIZE get_local_size(0) +#define GET_NUM_GROUPS get_num_groups(0) +#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE) +#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE) +#define AtomInc(x) atom_inc(&(x)) +#define AtomInc1(x, out) out = atom_inc(&(x)) +#define AppendInc(x, out) out = atomic_inc(x) +#define AtomAdd(x, value) atom_add(&(x), value) +#define AtomCmpxhg(x, cmp, value) atom_cmpxchg( &(x), cmp, value ) +#define AtomXhg(x, value) atom_xchg ( &(x), value ) + + +#define SELECT_UINT4( b, a, condition ) select( b,a,condition ) + +#define make_float4 (float4) +#define make_float2 (float2) +#define make_uint4 (uint4) +#define make_int4 (int4) +#define make_uint2 (uint2) +#define make_int2 (int2) + + +#define max2 max +#define min2 min + + +/////////////////////////////////////// +// Vector +/////////////////////////////////////// +__inline +float fastDiv(float numerator, float denominator) +{ + return native_divide(numerator, denominator); +// return numerator/denominator; +} + +__inline +float4 fastDiv4(float4 numerator, float4 denominator) +{ + return native_divide(numerator, denominator); +} + +__inline +float fastSqrtf(float f2) +{ + return native_sqrt(f2); +// return sqrt(f2); +} + +__inline +float fastRSqrt(float f2) +{ + return native_rsqrt(f2); +} + +__inline +float fastLength4(float4 v) +{ + return fast_length(v); +} + +__inline +float4 fastNormalize4(float4 v) +{ + return fast_normalize(v); +} + + +__inline +float sqrtf(float a) +{ +// return sqrt(a); + return native_sqrt(a); +} + +__inline +float4 cross3(float4 a1, float4 b1) +{ + + float4 a=make_float4(a1.xyz,0.f); + float4 b=make_float4(b1.xyz,0.f); + //float4 a=a1; + //float4 b=b1; + return cross(a,b); +} + +__inline +float dot3F4(float4 a, float4 b) +{ + float4 a1 = make_float4(a.xyz,0.f); + float4 b1 = make_float4(b.xyz,0.f); + return dot(a1, b1); +} + +__inline +float length3(const float4 a) +{ + return sqrtf(dot3F4(a,a)); +} + +__inline +float dot4(const float4 a, const float4 b) +{ + return dot( a, b ); +} + +// for height +__inline +float dot3w1(const float4 point, const float4 eqn) +{ + return dot3F4(point,eqn) + eqn.w; +} + +__inline +float4 normalize3(const float4 a) +{ + float4 n = make_float4(a.x, a.y, a.z, 0.f); + return fastNormalize4( n ); +// float length = sqrtf(dot3F4(a, a)); +// return 1.f/length * a; +} + +__inline +float4 normalize4(const float4 a) +{ + float length = sqrtf(dot4(a, a)); + return 1.f/length * a; +} + +__inline +float4 createEquation(const float4 a, const float4 b, const float4 c) +{ + float4 eqn; + float4 ab = b-a; + float4 ac = c-a; + eqn = normalize3( cross3(ab, ac) ); + eqn.w = -dot3F4(eqn,a); + return eqn; +} + +/////////////////////////////////////// +// Matrix3x3 +/////////////////////////////////////// + +typedef struct +{ + float4 m_row[3]; +}Matrix3x3; + +__inline +Matrix3x3 mtZero(); + +__inline +Matrix3x3 mtIdentity(); + +__inline +Matrix3x3 mtTranspose(Matrix3x3 m); + +__inline +Matrix3x3 mtMul(Matrix3x3 a, Matrix3x3 b); + +__inline +float4 mtMul1(Matrix3x3 a, float4 b); + +__inline +float4 mtMul3(float4 a, Matrix3x3 b); + +__inline +Matrix3x3 mtZero() +{ + Matrix3x3 m; + m.m_row[0] = (float4)(0.f); + m.m_row[1] = (float4)(0.f); + m.m_row[2] = (float4)(0.f); + return m; +} + +__inline +Matrix3x3 mtIdentity() +{ + Matrix3x3 m; + m.m_row[0] = (float4)(1,0,0,0); + m.m_row[1] = (float4)(0,1,0,0); + m.m_row[2] = (float4)(0,0,1,0); + return m; +} + +__inline +Matrix3x3 mtTranspose(Matrix3x3 m) +{ + Matrix3x3 out; + out.m_row[0] = (float4)(m.m_row[0].x, m.m_row[1].x, m.m_row[2].x, 0.f); + out.m_row[1] = (float4)(m.m_row[0].y, m.m_row[1].y, m.m_row[2].y, 0.f); + out.m_row[2] = (float4)(m.m_row[0].z, m.m_row[1].z, m.m_row[2].z, 0.f); + return out; +} + +__inline +Matrix3x3 mtMul(Matrix3x3 a, Matrix3x3 b) +{ + Matrix3x3 transB; + transB = mtTranspose( b ); + Matrix3x3 ans; + // why this doesn't run when 0ing in the for{} + a.m_row[0].w = 0.f; + a.m_row[1].w = 0.f; + a.m_row[2].w = 0.f; + for(int i=0; i<3; i++) + { +// a.m_row[i].w = 0.f; + ans.m_row[i].x = dot3F4(a.m_row[i],transB.m_row[0]); + ans.m_row[i].y = dot3F4(a.m_row[i],transB.m_row[1]); + ans.m_row[i].z = dot3F4(a.m_row[i],transB.m_row[2]); + ans.m_row[i].w = 0.f; + } + return ans; +} + +__inline +float4 mtMul1(Matrix3x3 a, float4 b) +{ + float4 ans; + ans.x = dot3F4( a.m_row[0], b ); + ans.y = dot3F4( a.m_row[1], b ); + ans.z = dot3F4( a.m_row[2], b ); + ans.w = 0.f; + return ans; +} + +__inline +float4 mtMul3(float4 a, Matrix3x3 b) +{ + float4 colx = make_float4(b.m_row[0].x, b.m_row[1].x, b.m_row[2].x, 0); + float4 coly = make_float4(b.m_row[0].y, b.m_row[1].y, b.m_row[2].y, 0); + float4 colz = make_float4(b.m_row[0].z, b.m_row[1].z, b.m_row[2].z, 0); + + float4 ans; + ans.x = dot3F4( a, colx ); + ans.y = dot3F4( a, coly ); + ans.z = dot3F4( a, colz ); + return ans; +} + +/////////////////////////////////////// +// Quaternion +/////////////////////////////////////// + +typedef float4 Quaternion; + +__inline +Quaternion qtMul(Quaternion a, Quaternion b); + +__inline +Quaternion qtNormalize(Quaternion in); + +__inline +float4 qtRotate(Quaternion q, float4 vec); + +__inline +Quaternion qtInvert(Quaternion q); + + + + + +__inline +Quaternion qtMul(Quaternion a, Quaternion b) +{ + Quaternion ans; + ans = cross3( a, b ); + ans += a.w*b+b.w*a; +// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z); + ans.w = a.w*b.w - dot3F4(a, b); + return ans; +} + +__inline +Quaternion qtNormalize(Quaternion in) +{ + return fastNormalize4(in); +// in /= length( in ); +// return in; +} +__inline +float4 qtRotate(Quaternion q, float4 vec) +{ + Quaternion qInv = qtInvert( q ); + float4 vcpy = vec; + vcpy.w = 0.f; + float4 out = qtMul(qtMul(q,vcpy),qInv); + return out; +} + +__inline +Quaternion qtInvert(Quaternion q) +{ + return (Quaternion)(-q.xyz, q.w); +} + +__inline +float4 qtInvRotate(const Quaternion q, float4 vec) +{ + return qtRotate( qtInvert( q ), vec ); +} + + + + +#define WG_SIZE 64 + +typedef struct +{ + float4 m_pos; + Quaternion m_quat; + float4 m_linVel; + float4 m_angVel; + + u32 m_shapeIdx; + float m_invMass; + float m_restituitionCoeff; + float m_frictionCoeff; +} Body; + + + +typedef struct +{ + Matrix3x3 m_invInertia; + Matrix3x3 m_initInvInertia; +} Shape; + +typedef struct +{ + float4 m_linear; + float4 m_worldPos[4]; + float4 m_center; + float m_jacCoeffInv[4]; + float m_b[4]; + float m_appliedRambdaDt[4]; + + float m_fJacCoeffInv[2]; + float m_fAppliedRambdaDt[2]; + + u32 m_bodyA; + u32 m_bodyB; + int m_batchIdx; + u32 m_paddings; +} Constraint4; + + + + + + +__kernel void CountBodiesKernel(__global struct b3Contact4Data* manifoldPtr, __global unsigned int* bodyCount, __global int2* contactConstraintOffsets, int numContactManifolds, int fixedBodyIndex) +{ + int i = GET_GLOBAL_IDX; + + if( i < numContactManifolds) + { + int pa = manifoldPtr[i].m_bodyAPtrAndSignBit; + bool isFixedA = (pa <0) || (pa == fixedBodyIndex); + int bodyIndexA = abs(pa); + if (!isFixedA) + { + AtomInc1(bodyCount[bodyIndexA],contactConstraintOffsets[i].x); + } + barrier(CLK_GLOBAL_MEM_FENCE); + int pb = manifoldPtr[i].m_bodyBPtrAndSignBit; + bool isFixedB = (pb <0) || (pb == fixedBodyIndex); + int bodyIndexB = abs(pb); + if (!isFixedB) + { + AtomInc1(bodyCount[bodyIndexB],contactConstraintOffsets[i].y); + } + } +} + +__kernel void ClearVelocitiesKernel(__global float4* linearVelocities,__global float4* angularVelocities, int numSplitBodies) +{ + int i = GET_GLOBAL_IDX; + + if( i < numSplitBodies) + { + linearVelocities[i] = make_float4(0); + angularVelocities[i] = make_float4(0); + } +} + + +__kernel void AverageVelocitiesKernel(__global Body* gBodies,__global int* offsetSplitBodies,__global const unsigned int* bodyCount, +__global float4* deltaLinearVelocities, __global float4* deltaAngularVelocities, int numBodies) +{ + int i = GET_GLOBAL_IDX; + if (i 0.70710678f) { + // choose p in y-z plane + float a = n.y*n.y + n.z*n.z; + float k = 1.f/sqrt(a); + p[0].x = 0; + p[0].y = -n.z*k; + p[0].z = n.y*k; + // set q = n x p + q[0].x = a*k; + q[0].y = -n.x*p[0].z; + q[0].z = n.x*p[0].y; + } + else { + // choose p in x-y plane + float a = n.x*n.x + n.y*n.y; + float k = 1.f/sqrt(a); + p[0].x = -n.y*k; + p[0].y = n.x*k; + p[0].z = 0; + // set q = n x p + q[0].x = -n.z*p[0].y; + q[0].y = n.z*p[0].x; + q[0].z = a*k; + } +} + + + + + +void solveContact(__global Constraint4* cs, + float4 posA, float4* linVelA, float4* angVelA, float invMassA, Matrix3x3 invInertiaA, + float4 posB, float4* linVelB, float4* angVelB, float invMassB, Matrix3x3 invInertiaB, + float4* dLinVelA, float4* dAngVelA, float4* dLinVelB, float4* dAngVelB) +{ + float minRambdaDt = 0; + float maxRambdaDt = FLT_MAX; + + for(int ic=0; ic<4; ic++) + { + if( cs->m_jacCoeffInv[ic] == 0.f ) continue; + + float4 angular0, angular1, linear; + float4 r0 = cs->m_worldPos[ic] - posA; + float4 r1 = cs->m_worldPos[ic] - posB; + setLinearAndAngular( cs->m_linear, r0, r1, &linear, &angular0, &angular1 ); + + + + float rambdaDt = calcRelVel( cs->m_linear, -cs->m_linear, angular0, angular1, + *linVelA+*dLinVelA, *angVelA+*dAngVelA, *linVelB+*dLinVelB, *angVelB+*dAngVelB ) + cs->m_b[ic]; + rambdaDt *= cs->m_jacCoeffInv[ic]; + + + { + float prevSum = cs->m_appliedRambdaDt[ic]; + float updated = prevSum; + updated += rambdaDt; + updated = max2( updated, minRambdaDt ); + updated = min2( updated, maxRambdaDt ); + rambdaDt = updated - prevSum; + cs->m_appliedRambdaDt[ic] = updated; + } + + + float4 linImp0 = invMassA*linear*rambdaDt; + float4 linImp1 = invMassB*(-linear)*rambdaDt; + float4 angImp0 = mtMul1(invInertiaA, angular0)*rambdaDt; + float4 angImp1 = mtMul1(invInertiaB, angular1)*rambdaDt; + + + if (invMassA) + { + *dLinVelA += linImp0; + *dAngVelA += angImp0; + } + if (invMassB) + { + *dLinVelB += linImp1; + *dAngVelB += angImp1; + } + } +} + + +// solveContactConstraint( gBodies, gShapes, &gConstraints[i] ,contactConstraintOffsets,offsetSplitBodies, deltaLinearVelocities, deltaAngularVelocities); + + +void solveContactConstraint(__global Body* gBodies, __global Shape* gShapes, __global Constraint4* ldsCs, +__global int2* contactConstraintOffsets,__global unsigned int* offsetSplitBodies, +__global float4* deltaLinearVelocities, __global float4* deltaAngularVelocities) +{ + + //float frictionCoeff = ldsCs[0].m_linear.w; + int aIdx = ldsCs[0].m_bodyA; + int bIdx = ldsCs[0].m_bodyB; + + float4 posA = gBodies[aIdx].m_pos; + float4 linVelA = gBodies[aIdx].m_linVel; + float4 angVelA = gBodies[aIdx].m_angVel; + float invMassA = gBodies[aIdx].m_invMass; + Matrix3x3 invInertiaA = gShapes[aIdx].m_invInertia; + + float4 posB = gBodies[bIdx].m_pos; + float4 linVelB = gBodies[bIdx].m_linVel; + float4 angVelB = gBodies[bIdx].m_angVel; + float invMassB = gBodies[bIdx].m_invMass; + Matrix3x3 invInertiaB = gShapes[bIdx].m_invInertia; + + + float4 dLinVelA = make_float4(0,0,0,0); + float4 dAngVelA = make_float4(0,0,0,0); + float4 dLinVelB = make_float4(0,0,0,0); + float4 dAngVelB = make_float4(0,0,0,0); + + int bodyOffsetA = offsetSplitBodies[aIdx]; + int constraintOffsetA = contactConstraintOffsets[0].x; + int splitIndexA = bodyOffsetA+constraintOffsetA; + + if (invMassA) + { + dLinVelA = deltaLinearVelocities[splitIndexA]; + dAngVelA = deltaAngularVelocities[splitIndexA]; + } + + int bodyOffsetB = offsetSplitBodies[bIdx]; + int constraintOffsetB = contactConstraintOffsets[0].y; + int splitIndexB= bodyOffsetB+constraintOffsetB; + + if (invMassB) + { + dLinVelB = deltaLinearVelocities[splitIndexB]; + dAngVelB = deltaAngularVelocities[splitIndexB]; + } + + solveContact( ldsCs, posA, &linVelA, &angVelA, invMassA, invInertiaA, + posB, &linVelB, &angVelB, invMassB, invInertiaB ,&dLinVelA, &dAngVelA, &dLinVelB, &dAngVelB); + + if (invMassA) + { + deltaLinearVelocities[splitIndexA] = dLinVelA; + deltaAngularVelocities[splitIndexA] = dAngVelA; + } + if (invMassB) + { + deltaLinearVelocities[splitIndexB] = dLinVelB; + deltaAngularVelocities[splitIndexB] = dAngVelB; + } + +} + + +__kernel void SolveContactJacobiKernel(__global Constraint4* gConstraints, __global Body* gBodies, __global Shape* gShapes , +__global int2* contactConstraintOffsets,__global unsigned int* offsetSplitBodies,__global float4* deltaLinearVelocities, __global float4* deltaAngularVelocities, +float deltaTime, float positionDrift, float positionConstraintCoeff, int fixedBodyIndex, int numManifolds +) +{ + int i = GET_GLOBAL_IDX; + if (im_fJacCoeffInv[0] == 0 && cs->m_fJacCoeffInv[0] == 0 ) return; + const float4 center = cs->m_center; + + float4 n = -cs->m_linear; + + float4 tangent[2]; + btPlaneSpace1(n,&tangent[0],&tangent[1]); + float4 angular0, angular1, linear; + float4 r0 = center - posA; + float4 r1 = center - posB; + for(int i=0; i<2; i++) + { + setLinearAndAngular( tangent[i], r0, r1, &linear, &angular0, &angular1 ); + float rambdaDt = calcRelVel(linear, -linear, angular0, angular1, + linVelA+dLinVelA, angVelA+dAngVelA, linVelB+dLinVelB, angVelB+dAngVelB ); + rambdaDt *= cs->m_fJacCoeffInv[i]; + + { + float prevSum = cs->m_fAppliedRambdaDt[i]; + float updated = prevSum; + updated += rambdaDt; + updated = max2( updated, minRambdaDt[i] ); + updated = min2( updated, maxRambdaDt[i] ); + rambdaDt = updated - prevSum; + cs->m_fAppliedRambdaDt[i] = updated; + } + + float4 linImp0 = invMassA*linear*rambdaDt; + float4 linImp1 = invMassB*(-linear)*rambdaDt; + float4 angImp0 = mtMul1(invInertiaA, angular0)*rambdaDt; + float4 angImp1 = mtMul1(invInertiaB, angular1)*rambdaDt; + + dLinVelA += linImp0; + dAngVelA += angImp0; + dLinVelB += linImp1; + dAngVelB += angImp1; + } + { // angular damping for point constraint + float4 ab = normalize3( posB - posA ); + float4 ac = normalize3( center - posA ); + if( dot3F4( ab, ac ) > 0.95f || (invMassA == 0.f || invMassB == 0.f)) + { + float angNA = dot3F4( n, angVelA ); + float angNB = dot3F4( n, angVelB ); + + dAngVelA -= (angNA*0.1f)*n; + dAngVelB -= (angNB*0.1f)*n; + } + } + } + + + + } + + if (invMassA) + { + deltaLinearVelocities[splitIndexA] = dLinVelA; + deltaAngularVelocities[splitIndexA] = dAngVelA; + } + if (invMassB) + { + deltaLinearVelocities[splitIndexB] = dLinVelB; + deltaAngularVelocities[splitIndexB] = dAngVelB; + } + + +} + + +__kernel void SolveFrictionJacobiKernel(__global Constraint4* gConstraints, __global Body* gBodies, __global Shape* gShapes , + __global int2* contactConstraintOffsets,__global unsigned int* offsetSplitBodies, + __global float4* deltaLinearVelocities, __global float4* deltaAngularVelocities, + float deltaTime, float positionDrift, float positionConstraintCoeff, int fixedBodyIndex, int numManifolds +) +{ + int i = GET_GLOBAL_IDX; + if (im_bodyA = abs(src->m_bodyAPtrAndSignBit); + dstC->m_bodyB = abs(src->m_bodyBPtrAndSignBit); + + float dtInv = 1.f/dt; + for(int ic=0; ic<4; ic++) + { + dstC->m_appliedRambdaDt[ic] = 0.f; + } + dstC->m_fJacCoeffInv[0] = dstC->m_fJacCoeffInv[1] = 0.f; + + + dstC->m_linear = src->m_worldNormalOnB; + dstC->m_linear.w = 0.7f ;//src->getFrictionCoeff() ); + for(int ic=0; ic<4; ic++) + { + float4 r0 = src->m_worldPosB[ic] - posA; + float4 r1 = src->m_worldPosB[ic] - posB; + + if( ic >= src->m_worldNormalOnB.w )//npoints + { + dstC->m_jacCoeffInv[ic] = 0.f; + continue; + } + + float relVelN; + { + float4 linear, angular0, angular1; + setLinearAndAngular(src->m_worldNormalOnB, r0, r1, &linear, &angular0, &angular1); + + dstC->m_jacCoeffInv[ic] = calcJacCoeff(linear, -linear, angular0, angular1, + invMassA, &invInertiaA, invMassB, &invInertiaB , countA, countB); + + relVelN = calcRelVel(linear, -linear, angular0, angular1, + linVelA, angVelA, linVelB, angVelB); + + float e = 0.f;//src->getRestituitionCoeff(); + if( relVelN*relVelN < 0.004f ) e = 0.f; + + dstC->m_b[ic] = e*relVelN; + //float penetration = src->m_worldPosB[ic].w; + dstC->m_b[ic] += (src->m_worldPosB[ic].w + positionDrift)*positionConstraintCoeff*dtInv; + dstC->m_appliedRambdaDt[ic] = 0.f; + } + } + + if( src->m_worldNormalOnB.w > 0 )//npoints + { // prepare friction + float4 center = make_float4(0.f); + for(int i=0; im_worldNormalOnB.w; i++) + center += src->m_worldPosB[i]; + center /= (float)src->m_worldNormalOnB.w; + + float4 tangent[2]; + btPlaneSpace1(-src->m_worldNormalOnB,&tangent[0],&tangent[1]); + + float4 r[2]; + r[0] = center - posA; + r[1] = center - posB; + + for(int i=0; i<2; i++) + { + float4 linear, angular0, angular1; + setLinearAndAngular(tangent[i], r[0], r[1], &linear, &angular0, &angular1); + + dstC->m_fJacCoeffInv[i] = calcJacCoeff(linear, -linear, angular0, angular1, + invMassA, &invInertiaA, invMassB, &invInertiaB ,countA, countB); + dstC->m_fAppliedRambdaDt[i] = 0.f; + } + dstC->m_center = center; + } + + for(int i=0; i<4; i++) + { + if( im_worldNormalOnB.w ) + { + dstC->m_worldPos[i] = src->m_worldPosB[i]; + } + else + { + dstC->m_worldPos[i] = make_float4(0.f); + } + } +} + + +__kernel +__attribute__((reqd_work_group_size(WG_SIZE,1,1))) +void ContactToConstraintSplitKernel(__global const struct b3Contact4Data* gContact, __global const Body* gBodies, __global const Shape* gShapes, __global Constraint4* gConstraintOut, +__global const unsigned int* bodyCount, +int nContacts, +float dt, +float positionDrift, +float positionConstraintCoeff +) +{ + int gIdx = GET_GLOBAL_IDX; + + if( gIdx < nContacts ) + { + int aIdx = abs(gContact[gIdx].m_bodyAPtrAndSignBit); + int bIdx = abs(gContact[gIdx].m_bodyBPtrAndSignBit); + + float4 posA = gBodies[aIdx].m_pos; + float4 linVelA = gBodies[aIdx].m_linVel; + float4 angVelA = gBodies[aIdx].m_angVel; + float invMassA = gBodies[aIdx].m_invMass; + Matrix3x3 invInertiaA = gShapes[aIdx].m_invInertia; + + float4 posB = gBodies[bIdx].m_pos; + float4 linVelB = gBodies[bIdx].m_linVel; + float4 angVelB = gBodies[bIdx].m_angVel; + float invMassB = gBodies[bIdx].m_invMass; + Matrix3x3 invInertiaB = gShapes[bIdx].m_invInertia; + + Constraint4 cs; + + float countA = invMassA != 0.f ? (float)bodyCount[aIdx] : 1; + float countB = invMassB != 0.f ? (float)bodyCount[bIdx] : 1; + + setConstraint4( posA, linVelA, angVelA, invMassA, invInertiaA, posB, linVelB, angVelB, invMassB, invInertiaB, + &gContact[gIdx], dt, positionDrift, positionConstraintCoeff,countA,countB, + &cs ); + + cs.m_batchIdx = gContact[gIdx].m_batchIdx; + + gConstraintOut[gIdx] = cs; + } +} \ No newline at end of file diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/solverUtils.h b/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/solverUtils.h new file mode 100644 index 000000000000..c0173ad9f42a --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/solverUtils.h @@ -0,0 +1,909 @@ +//this file is autogenerated using stringify.bat (premake --stringify) in the build folder of this project +static const char* solverUtilsCL= \ +"/*\n" +"Copyright (c) 2013 Advanced Micro Devices, Inc. \n" +"This software is provided 'as-is', without any express or implied warranty.\n" +"In no event will the authors be held liable for any damages arising from the use of this software.\n" +"Permission is granted to anyone to use this software for any purpose, \n" +"including commercial applications, and to alter it and redistribute it freely, \n" +"subject to the following restrictions:\n" +"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.\n" +"2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n" +"3. This notice may not be removed or altered from any source distribution.\n" +"*/\n" +"//Originally written by Erwin Coumans\n" +"#ifndef B3_CONTACT4DATA_H\n" +"#define B3_CONTACT4DATA_H\n" +"#ifndef B3_FLOAT4_H\n" +"#define B3_FLOAT4_H\n" +"#ifndef B3_PLATFORM_DEFINITIONS_H\n" +"#define B3_PLATFORM_DEFINITIONS_H\n" +"struct MyTest\n" +"{\n" +" int bla;\n" +"};\n" +"#ifdef __cplusplus\n" +"#else\n" +"//keep B3_LARGE_FLOAT*B3_LARGE_FLOAT < FLT_MAX\n" +"#define B3_LARGE_FLOAT 1e18f\n" +"#define B3_INFINITY 1e18f\n" +"#define b3Assert(a)\n" +"#define b3ConstArray(a) __global const a*\n" +"#define b3AtomicInc atomic_inc\n" +"#define b3AtomicAdd atomic_add\n" +"#define b3Fabs fabs\n" +"#define b3Sqrt native_sqrt\n" +"#define b3Sin native_sin\n" +"#define b3Cos native_cos\n" +"#define B3_STATIC\n" +"#endif\n" +"#endif\n" +"#ifdef __cplusplus\n" +"#else\n" +" typedef float4 b3Float4;\n" +" #define b3Float4ConstArg const b3Float4\n" +" #define b3MakeFloat4 (float4)\n" +" float b3Dot3F4(b3Float4ConstArg v0,b3Float4ConstArg v1)\n" +" {\n" +" float4 a1 = b3MakeFloat4(v0.xyz,0.f);\n" +" float4 b1 = b3MakeFloat4(v1.xyz,0.f);\n" +" return dot(a1, b1);\n" +" }\n" +" b3Float4 b3Cross3(b3Float4ConstArg v0,b3Float4ConstArg v1)\n" +" {\n" +" float4 a1 = b3MakeFloat4(v0.xyz,0.f);\n" +" float4 b1 = b3MakeFloat4(v1.xyz,0.f);\n" +" return cross(a1, b1);\n" +" }\n" +" #define b3MinFloat4 min\n" +" #define b3MaxFloat4 max\n" +" #define b3Normalized(a) normalize(a)\n" +"#endif \n" +" \n" +"inline bool b3IsAlmostZero(b3Float4ConstArg v)\n" +"{\n" +" if(b3Fabs(v.x)>1e-6 || b3Fabs(v.y)>1e-6 || b3Fabs(v.z)>1e-6) \n" +" return false;\n" +" return true;\n" +"}\n" +"inline int b3MaxDot( b3Float4ConstArg vec, __global const b3Float4* vecArray, int vecLen, float* dotOut )\n" +"{\n" +" float maxDot = -B3_INFINITY;\n" +" int i = 0;\n" +" int ptIndex = -1;\n" +" for( i = 0; i < vecLen; i++ )\n" +" {\n" +" float dot = b3Dot3F4(vecArray[i],vec);\n" +" \n" +" if( dot > maxDot )\n" +" {\n" +" maxDot = dot;\n" +" ptIndex = i;\n" +" }\n" +" }\n" +" b3Assert(ptIndex>=0);\n" +" if (ptIndex<0)\n" +" {\n" +" ptIndex = 0;\n" +" }\n" +" *dotOut = maxDot;\n" +" return ptIndex;\n" +"}\n" +"#endif //B3_FLOAT4_H\n" +"typedef struct b3Contact4Data b3Contact4Data_t;\n" +"struct b3Contact4Data\n" +"{\n" +" b3Float4 m_worldPosB[4];\n" +"// b3Float4 m_localPosA[4];\n" +"// b3Float4 m_localPosB[4];\n" +" b3Float4 m_worldNormalOnB; // w: m_nPoints\n" +" unsigned short m_restituitionCoeffCmp;\n" +" unsigned short m_frictionCoeffCmp;\n" +" int m_batchIdx;\n" +" int m_bodyAPtrAndSignBit;//x:m_bodyAPtr, y:m_bodyBPtr\n" +" int m_bodyBPtrAndSignBit;\n" +" int m_childIndexA;\n" +" int m_childIndexB;\n" +" int m_unused1;\n" +" int m_unused2;\n" +"};\n" +"inline int b3Contact4Data_getNumPoints(const struct b3Contact4Data* contact)\n" +"{\n" +" return (int)contact->m_worldNormalOnB.w;\n" +"};\n" +"inline void b3Contact4Data_setNumPoints(struct b3Contact4Data* contact, int numPoints)\n" +"{\n" +" contact->m_worldNormalOnB.w = (float)numPoints;\n" +"};\n" +"#endif //B3_CONTACT4DATA_H\n" +"#pragma OPENCL EXTENSION cl_amd_printf : enable\n" +"#pragma OPENCL EXTENSION cl_khr_local_int32_base_atomics : enable\n" +"#pragma OPENCL EXTENSION cl_khr_global_int32_base_atomics : enable\n" +"#pragma OPENCL EXTENSION cl_khr_local_int32_extended_atomics : enable\n" +"#pragma OPENCL EXTENSION cl_khr_global_int32_extended_atomics : enable\n" +"#ifdef cl_ext_atomic_counters_32\n" +"#pragma OPENCL EXTENSION cl_ext_atomic_counters_32 : enable\n" +"#else\n" +"#define counter32_t volatile global int*\n" +"#endif\n" +"typedef unsigned int u32;\n" +"typedef unsigned short u16;\n" +"typedef unsigned char u8;\n" +"#define GET_GROUP_IDX get_group_id(0)\n" +"#define GET_LOCAL_IDX get_local_id(0)\n" +"#define GET_GLOBAL_IDX get_global_id(0)\n" +"#define GET_GROUP_SIZE get_local_size(0)\n" +"#define GET_NUM_GROUPS get_num_groups(0)\n" +"#define GROUP_LDS_BARRIER barrier(CLK_LOCAL_MEM_FENCE)\n" +"#define GROUP_MEM_FENCE mem_fence(CLK_LOCAL_MEM_FENCE)\n" +"#define AtomInc(x) atom_inc(&(x))\n" +"#define AtomInc1(x, out) out = atom_inc(&(x))\n" +"#define AppendInc(x, out) out = atomic_inc(x)\n" +"#define AtomAdd(x, value) atom_add(&(x), value)\n" +"#define AtomCmpxhg(x, cmp, value) atom_cmpxchg( &(x), cmp, value )\n" +"#define AtomXhg(x, value) atom_xchg ( &(x), value )\n" +"#define SELECT_UINT4( b, a, condition ) select( b,a,condition )\n" +"#define make_float4 (float4)\n" +"#define make_float2 (float2)\n" +"#define make_uint4 (uint4)\n" +"#define make_int4 (int4)\n" +"#define make_uint2 (uint2)\n" +"#define make_int2 (int2)\n" +"#define max2 max\n" +"#define min2 min\n" +"///////////////////////////////////////\n" +"// Vector\n" +"///////////////////////////////////////\n" +"__inline\n" +"float fastDiv(float numerator, float denominator)\n" +"{\n" +" return native_divide(numerator, denominator); \n" +"// return numerator/denominator; \n" +"}\n" +"__inline\n" +"float4 fastDiv4(float4 numerator, float4 denominator)\n" +"{\n" +" return native_divide(numerator, denominator); \n" +"}\n" +"__inline\n" +"float fastSqrtf(float f2)\n" +"{\n" +" return native_sqrt(f2);\n" +"// return sqrt(f2);\n" +"}\n" +"__inline\n" +"float fastRSqrt(float f2)\n" +"{\n" +" return native_rsqrt(f2);\n" +"}\n" +"__inline\n" +"float fastLength4(float4 v)\n" +"{\n" +" return fast_length(v);\n" +"}\n" +"__inline\n" +"float4 fastNormalize4(float4 v)\n" +"{\n" +" return fast_normalize(v);\n" +"}\n" +"__inline\n" +"float sqrtf(float a)\n" +"{\n" +"// return sqrt(a);\n" +" return native_sqrt(a);\n" +"}\n" +"__inline\n" +"float4 cross3(float4 a1, float4 b1)\n" +"{\n" +" float4 a=make_float4(a1.xyz,0.f);\n" +" float4 b=make_float4(b1.xyz,0.f);\n" +" //float4 a=a1;\n" +" //float4 b=b1;\n" +" return cross(a,b);\n" +"}\n" +"__inline\n" +"float dot3F4(float4 a, float4 b)\n" +"{\n" +" float4 a1 = make_float4(a.xyz,0.f);\n" +" float4 b1 = make_float4(b.xyz,0.f);\n" +" return dot(a1, b1);\n" +"}\n" +"__inline\n" +"float length3(const float4 a)\n" +"{\n" +" return sqrtf(dot3F4(a,a));\n" +"}\n" +"__inline\n" +"float dot4(const float4 a, const float4 b)\n" +"{\n" +" return dot( a, b );\n" +"}\n" +"// for height\n" +"__inline\n" +"float dot3w1(const float4 point, const float4 eqn)\n" +"{\n" +" return dot3F4(point,eqn) + eqn.w;\n" +"}\n" +"__inline\n" +"float4 normalize3(const float4 a)\n" +"{\n" +" float4 n = make_float4(a.x, a.y, a.z, 0.f);\n" +" return fastNormalize4( n );\n" +"// float length = sqrtf(dot3F4(a, a));\n" +"// return 1.f/length * a;\n" +"}\n" +"__inline\n" +"float4 normalize4(const float4 a)\n" +"{\n" +" float length = sqrtf(dot4(a, a));\n" +" return 1.f/length * a;\n" +"}\n" +"__inline\n" +"float4 createEquation(const float4 a, const float4 b, const float4 c)\n" +"{\n" +" float4 eqn;\n" +" float4 ab = b-a;\n" +" float4 ac = c-a;\n" +" eqn = normalize3( cross3(ab, ac) );\n" +" eqn.w = -dot3F4(eqn,a);\n" +" return eqn;\n" +"}\n" +"///////////////////////////////////////\n" +"// Matrix3x3\n" +"///////////////////////////////////////\n" +"typedef struct\n" +"{\n" +" float4 m_row[3];\n" +"}Matrix3x3;\n" +"__inline\n" +"Matrix3x3 mtZero();\n" +"__inline\n" +"Matrix3x3 mtIdentity();\n" +"__inline\n" +"Matrix3x3 mtTranspose(Matrix3x3 m);\n" +"__inline\n" +"Matrix3x3 mtMul(Matrix3x3 a, Matrix3x3 b);\n" +"__inline\n" +"float4 mtMul1(Matrix3x3 a, float4 b);\n" +"__inline\n" +"float4 mtMul3(float4 a, Matrix3x3 b);\n" +"__inline\n" +"Matrix3x3 mtZero()\n" +"{\n" +" Matrix3x3 m;\n" +" m.m_row[0] = (float4)(0.f);\n" +" m.m_row[1] = (float4)(0.f);\n" +" m.m_row[2] = (float4)(0.f);\n" +" return m;\n" +"}\n" +"__inline\n" +"Matrix3x3 mtIdentity()\n" +"{\n" +" Matrix3x3 m;\n" +" m.m_row[0] = (float4)(1,0,0,0);\n" +" m.m_row[1] = (float4)(0,1,0,0);\n" +" m.m_row[2] = (float4)(0,0,1,0);\n" +" return m;\n" +"}\n" +"__inline\n" +"Matrix3x3 mtTranspose(Matrix3x3 m)\n" +"{\n" +" Matrix3x3 out;\n" +" out.m_row[0] = (float4)(m.m_row[0].x, m.m_row[1].x, m.m_row[2].x, 0.f);\n" +" out.m_row[1] = (float4)(m.m_row[0].y, m.m_row[1].y, m.m_row[2].y, 0.f);\n" +" out.m_row[2] = (float4)(m.m_row[0].z, m.m_row[1].z, m.m_row[2].z, 0.f);\n" +" return out;\n" +"}\n" +"__inline\n" +"Matrix3x3 mtMul(Matrix3x3 a, Matrix3x3 b)\n" +"{\n" +" Matrix3x3 transB;\n" +" transB = mtTranspose( b );\n" +" Matrix3x3 ans;\n" +" // why this doesn't run when 0ing in the for{}\n" +" a.m_row[0].w = 0.f;\n" +" a.m_row[1].w = 0.f;\n" +" a.m_row[2].w = 0.f;\n" +" for(int i=0; i<3; i++)\n" +" {\n" +"// a.m_row[i].w = 0.f;\n" +" ans.m_row[i].x = dot3F4(a.m_row[i],transB.m_row[0]);\n" +" ans.m_row[i].y = dot3F4(a.m_row[i],transB.m_row[1]);\n" +" ans.m_row[i].z = dot3F4(a.m_row[i],transB.m_row[2]);\n" +" ans.m_row[i].w = 0.f;\n" +" }\n" +" return ans;\n" +"}\n" +"__inline\n" +"float4 mtMul1(Matrix3x3 a, float4 b)\n" +"{\n" +" float4 ans;\n" +" ans.x = dot3F4( a.m_row[0], b );\n" +" ans.y = dot3F4( a.m_row[1], b );\n" +" ans.z = dot3F4( a.m_row[2], b );\n" +" ans.w = 0.f;\n" +" return ans;\n" +"}\n" +"__inline\n" +"float4 mtMul3(float4 a, Matrix3x3 b)\n" +"{\n" +" float4 colx = make_float4(b.m_row[0].x, b.m_row[1].x, b.m_row[2].x, 0);\n" +" float4 coly = make_float4(b.m_row[0].y, b.m_row[1].y, b.m_row[2].y, 0);\n" +" float4 colz = make_float4(b.m_row[0].z, b.m_row[1].z, b.m_row[2].z, 0);\n" +" float4 ans;\n" +" ans.x = dot3F4( a, colx );\n" +" ans.y = dot3F4( a, coly );\n" +" ans.z = dot3F4( a, colz );\n" +" return ans;\n" +"}\n" +"///////////////////////////////////////\n" +"// Quaternion\n" +"///////////////////////////////////////\n" +"typedef float4 Quaternion;\n" +"__inline\n" +"Quaternion qtMul(Quaternion a, Quaternion b);\n" +"__inline\n" +"Quaternion qtNormalize(Quaternion in);\n" +"__inline\n" +"float4 qtRotate(Quaternion q, float4 vec);\n" +"__inline\n" +"Quaternion qtInvert(Quaternion q);\n" +"__inline\n" +"Quaternion qtMul(Quaternion a, Quaternion b)\n" +"{\n" +" Quaternion ans;\n" +" ans = cross3( a, b );\n" +" ans += a.w*b+b.w*a;\n" +"// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z);\n" +" ans.w = a.w*b.w - dot3F4(a, b);\n" +" return ans;\n" +"}\n" +"__inline\n" +"Quaternion qtNormalize(Quaternion in)\n" +"{\n" +" return fastNormalize4(in);\n" +"// in /= length( in );\n" +"// return in;\n" +"}\n" +"__inline\n" +"float4 qtRotate(Quaternion q, float4 vec)\n" +"{\n" +" Quaternion qInv = qtInvert( q );\n" +" float4 vcpy = vec;\n" +" vcpy.w = 0.f;\n" +" float4 out = qtMul(qtMul(q,vcpy),qInv);\n" +" return out;\n" +"}\n" +"__inline\n" +"Quaternion qtInvert(Quaternion q)\n" +"{\n" +" return (Quaternion)(-q.xyz, q.w);\n" +"}\n" +"__inline\n" +"float4 qtInvRotate(const Quaternion q, float4 vec)\n" +"{\n" +" return qtRotate( qtInvert( q ), vec );\n" +"}\n" +"#define WG_SIZE 64\n" +"typedef struct\n" +"{\n" +" float4 m_pos;\n" +" Quaternion m_quat;\n" +" float4 m_linVel;\n" +" float4 m_angVel;\n" +" u32 m_shapeIdx;\n" +" float m_invMass;\n" +" float m_restituitionCoeff;\n" +" float m_frictionCoeff;\n" +"} Body;\n" +"typedef struct\n" +"{\n" +" Matrix3x3 m_invInertia;\n" +" Matrix3x3 m_initInvInertia;\n" +"} Shape;\n" +"typedef struct\n" +"{\n" +" float4 m_linear;\n" +" float4 m_worldPos[4];\n" +" float4 m_center; \n" +" float m_jacCoeffInv[4];\n" +" float m_b[4];\n" +" float m_appliedRambdaDt[4];\n" +" float m_fJacCoeffInv[2]; \n" +" float m_fAppliedRambdaDt[2]; \n" +" u32 m_bodyA;\n" +" u32 m_bodyB;\n" +" int m_batchIdx;\n" +" u32 m_paddings;\n" +"} Constraint4;\n" +"__kernel void CountBodiesKernel(__global struct b3Contact4Data* manifoldPtr, __global unsigned int* bodyCount, __global int2* contactConstraintOffsets, int numContactManifolds, int fixedBodyIndex)\n" +"{\n" +" int i = GET_GLOBAL_IDX;\n" +" \n" +" if( i < numContactManifolds)\n" +" {\n" +" int pa = manifoldPtr[i].m_bodyAPtrAndSignBit;\n" +" bool isFixedA = (pa <0) || (pa == fixedBodyIndex);\n" +" int bodyIndexA = abs(pa);\n" +" if (!isFixedA)\n" +" {\n" +" AtomInc1(bodyCount[bodyIndexA],contactConstraintOffsets[i].x);\n" +" }\n" +" barrier(CLK_GLOBAL_MEM_FENCE);\n" +" int pb = manifoldPtr[i].m_bodyBPtrAndSignBit;\n" +" bool isFixedB = (pb <0) || (pb == fixedBodyIndex);\n" +" int bodyIndexB = abs(pb);\n" +" if (!isFixedB)\n" +" {\n" +" AtomInc1(bodyCount[bodyIndexB],contactConstraintOffsets[i].y);\n" +" } \n" +" }\n" +"}\n" +"__kernel void ClearVelocitiesKernel(__global float4* linearVelocities,__global float4* angularVelocities, int numSplitBodies)\n" +"{\n" +" int i = GET_GLOBAL_IDX;\n" +" \n" +" if( i < numSplitBodies)\n" +" {\n" +" linearVelocities[i] = make_float4(0);\n" +" angularVelocities[i] = make_float4(0);\n" +" }\n" +"}\n" +"__kernel void AverageVelocitiesKernel(__global Body* gBodies,__global int* offsetSplitBodies,__global const unsigned int* bodyCount,\n" +"__global float4* deltaLinearVelocities, __global float4* deltaAngularVelocities, int numBodies)\n" +"{\n" +" int i = GET_GLOBAL_IDX;\n" +" if (i 0.70710678f) {\n" +" // choose p in y-z plane\n" +" float a = n.y*n.y + n.z*n.z;\n" +" float k = 1.f/sqrt(a);\n" +" p[0].x = 0;\n" +" p[0].y = -n.z*k;\n" +" p[0].z = n.y*k;\n" +" // set q = n x p\n" +" q[0].x = a*k;\n" +" q[0].y = -n.x*p[0].z;\n" +" q[0].z = n.x*p[0].y;\n" +" }\n" +" else {\n" +" // choose p in x-y plane\n" +" float a = n.x*n.x + n.y*n.y;\n" +" float k = 1.f/sqrt(a);\n" +" p[0].x = -n.y*k;\n" +" p[0].y = n.x*k;\n" +" p[0].z = 0;\n" +" // set q = n x p\n" +" q[0].x = -n.z*p[0].y;\n" +" q[0].y = n.z*p[0].x;\n" +" q[0].z = a*k;\n" +" }\n" +"}\n" +"void solveContact(__global Constraint4* cs,\n" +" float4 posA, float4* linVelA, float4* angVelA, float invMassA, Matrix3x3 invInertiaA,\n" +" float4 posB, float4* linVelB, float4* angVelB, float invMassB, Matrix3x3 invInertiaB,\n" +" float4* dLinVelA, float4* dAngVelA, float4* dLinVelB, float4* dAngVelB)\n" +"{\n" +" float minRambdaDt = 0;\n" +" float maxRambdaDt = FLT_MAX;\n" +" for(int ic=0; ic<4; ic++)\n" +" {\n" +" if( cs->m_jacCoeffInv[ic] == 0.f ) continue;\n" +" float4 angular0, angular1, linear;\n" +" float4 r0 = cs->m_worldPos[ic] - posA;\n" +" float4 r1 = cs->m_worldPos[ic] - posB;\n" +" setLinearAndAngular( cs->m_linear, r0, r1, &linear, &angular0, &angular1 );\n" +" \n" +" float rambdaDt = calcRelVel( cs->m_linear, -cs->m_linear, angular0, angular1, \n" +" *linVelA+*dLinVelA, *angVelA+*dAngVelA, *linVelB+*dLinVelB, *angVelB+*dAngVelB ) + cs->m_b[ic];\n" +" rambdaDt *= cs->m_jacCoeffInv[ic];\n" +" \n" +" {\n" +" float prevSum = cs->m_appliedRambdaDt[ic];\n" +" float updated = prevSum;\n" +" updated += rambdaDt;\n" +" updated = max2( updated, minRambdaDt );\n" +" updated = min2( updated, maxRambdaDt );\n" +" rambdaDt = updated - prevSum;\n" +" cs->m_appliedRambdaDt[ic] = updated;\n" +" }\n" +" \n" +" float4 linImp0 = invMassA*linear*rambdaDt;\n" +" float4 linImp1 = invMassB*(-linear)*rambdaDt;\n" +" float4 angImp0 = mtMul1(invInertiaA, angular0)*rambdaDt;\n" +" float4 angImp1 = mtMul1(invInertiaB, angular1)*rambdaDt;\n" +" \n" +" if (invMassA)\n" +" {\n" +" *dLinVelA += linImp0;\n" +" *dAngVelA += angImp0;\n" +" }\n" +" if (invMassB)\n" +" {\n" +" *dLinVelB += linImp1;\n" +" *dAngVelB += angImp1;\n" +" }\n" +" }\n" +"}\n" +"// solveContactConstraint( gBodies, gShapes, &gConstraints[i] ,contactConstraintOffsets,offsetSplitBodies, deltaLinearVelocities, deltaAngularVelocities);\n" +"void solveContactConstraint(__global Body* gBodies, __global Shape* gShapes, __global Constraint4* ldsCs, \n" +"__global int2* contactConstraintOffsets,__global unsigned int* offsetSplitBodies,\n" +"__global float4* deltaLinearVelocities, __global float4* deltaAngularVelocities)\n" +"{\n" +" //float frictionCoeff = ldsCs[0].m_linear.w;\n" +" int aIdx = ldsCs[0].m_bodyA;\n" +" int bIdx = ldsCs[0].m_bodyB;\n" +" float4 posA = gBodies[aIdx].m_pos;\n" +" float4 linVelA = gBodies[aIdx].m_linVel;\n" +" float4 angVelA = gBodies[aIdx].m_angVel;\n" +" float invMassA = gBodies[aIdx].m_invMass;\n" +" Matrix3x3 invInertiaA = gShapes[aIdx].m_invInertia;\n" +" float4 posB = gBodies[bIdx].m_pos;\n" +" float4 linVelB = gBodies[bIdx].m_linVel;\n" +" float4 angVelB = gBodies[bIdx].m_angVel;\n" +" float invMassB = gBodies[bIdx].m_invMass;\n" +" Matrix3x3 invInertiaB = gShapes[bIdx].m_invInertia;\n" +" \n" +" float4 dLinVelA = make_float4(0,0,0,0);\n" +" float4 dAngVelA = make_float4(0,0,0,0);\n" +" float4 dLinVelB = make_float4(0,0,0,0);\n" +" float4 dAngVelB = make_float4(0,0,0,0);\n" +" \n" +" int bodyOffsetA = offsetSplitBodies[aIdx];\n" +" int constraintOffsetA = contactConstraintOffsets[0].x;\n" +" int splitIndexA = bodyOffsetA+constraintOffsetA;\n" +" \n" +" if (invMassA)\n" +" {\n" +" dLinVelA = deltaLinearVelocities[splitIndexA];\n" +" dAngVelA = deltaAngularVelocities[splitIndexA];\n" +" }\n" +" int bodyOffsetB = offsetSplitBodies[bIdx];\n" +" int constraintOffsetB = contactConstraintOffsets[0].y;\n" +" int splitIndexB= bodyOffsetB+constraintOffsetB;\n" +" if (invMassB)\n" +" {\n" +" dLinVelB = deltaLinearVelocities[splitIndexB];\n" +" dAngVelB = deltaAngularVelocities[splitIndexB];\n" +" }\n" +" solveContact( ldsCs, posA, &linVelA, &angVelA, invMassA, invInertiaA,\n" +" posB, &linVelB, &angVelB, invMassB, invInertiaB ,&dLinVelA, &dAngVelA, &dLinVelB, &dAngVelB);\n" +" if (invMassA)\n" +" {\n" +" deltaLinearVelocities[splitIndexA] = dLinVelA;\n" +" deltaAngularVelocities[splitIndexA] = dAngVelA;\n" +" } \n" +" if (invMassB)\n" +" {\n" +" deltaLinearVelocities[splitIndexB] = dLinVelB;\n" +" deltaAngularVelocities[splitIndexB] = dAngVelB;\n" +" }\n" +"}\n" +"__kernel void SolveContactJacobiKernel(__global Constraint4* gConstraints, __global Body* gBodies, __global Shape* gShapes ,\n" +"__global int2* contactConstraintOffsets,__global unsigned int* offsetSplitBodies,__global float4* deltaLinearVelocities, __global float4* deltaAngularVelocities,\n" +"float deltaTime, float positionDrift, float positionConstraintCoeff, int fixedBodyIndex, int numManifolds\n" +")\n" +"{\n" +" int i = GET_GLOBAL_IDX;\n" +" if (im_fJacCoeffInv[0] == 0 && cs->m_fJacCoeffInv[0] == 0 ) return;\n" +" const float4 center = cs->m_center;\n" +" \n" +" float4 n = -cs->m_linear;\n" +" \n" +" float4 tangent[2];\n" +" btPlaneSpace1(n,&tangent[0],&tangent[1]);\n" +" float4 angular0, angular1, linear;\n" +" float4 r0 = center - posA;\n" +" float4 r1 = center - posB;\n" +" for(int i=0; i<2; i++)\n" +" {\n" +" setLinearAndAngular( tangent[i], r0, r1, &linear, &angular0, &angular1 );\n" +" float rambdaDt = calcRelVel(linear, -linear, angular0, angular1,\n" +" linVelA+dLinVelA, angVelA+dAngVelA, linVelB+dLinVelB, angVelB+dAngVelB );\n" +" rambdaDt *= cs->m_fJacCoeffInv[i];\n" +" \n" +" {\n" +" float prevSum = cs->m_fAppliedRambdaDt[i];\n" +" float updated = prevSum;\n" +" updated += rambdaDt;\n" +" updated = max2( updated, minRambdaDt[i] );\n" +" updated = min2( updated, maxRambdaDt[i] );\n" +" rambdaDt = updated - prevSum;\n" +" cs->m_fAppliedRambdaDt[i] = updated;\n" +" }\n" +" \n" +" float4 linImp0 = invMassA*linear*rambdaDt;\n" +" float4 linImp1 = invMassB*(-linear)*rambdaDt;\n" +" float4 angImp0 = mtMul1(invInertiaA, angular0)*rambdaDt;\n" +" float4 angImp1 = mtMul1(invInertiaB, angular1)*rambdaDt;\n" +" \n" +" dLinVelA += linImp0;\n" +" dAngVelA += angImp0;\n" +" dLinVelB += linImp1;\n" +" dAngVelB += angImp1;\n" +" }\n" +" { // angular damping for point constraint\n" +" float4 ab = normalize3( posB - posA );\n" +" float4 ac = normalize3( center - posA );\n" +" if( dot3F4( ab, ac ) > 0.95f || (invMassA == 0.f || invMassB == 0.f))\n" +" {\n" +" float angNA = dot3F4( n, angVelA );\n" +" float angNB = dot3F4( n, angVelB );\n" +" \n" +" dAngVelA -= (angNA*0.1f)*n;\n" +" dAngVelB -= (angNB*0.1f)*n;\n" +" }\n" +" }\n" +" }\n" +" \n" +" \n" +" }\n" +" if (invMassA)\n" +" {\n" +" deltaLinearVelocities[splitIndexA] = dLinVelA;\n" +" deltaAngularVelocities[splitIndexA] = dAngVelA;\n" +" } \n" +" if (invMassB)\n" +" {\n" +" deltaLinearVelocities[splitIndexB] = dLinVelB;\n" +" deltaAngularVelocities[splitIndexB] = dAngVelB;\n" +" }\n" +" \n" +"}\n" +"__kernel void SolveFrictionJacobiKernel(__global Constraint4* gConstraints, __global Body* gBodies, __global Shape* gShapes ,\n" +" __global int2* contactConstraintOffsets,__global unsigned int* offsetSplitBodies,\n" +" __global float4* deltaLinearVelocities, __global float4* deltaAngularVelocities,\n" +" float deltaTime, float positionDrift, float positionConstraintCoeff, int fixedBodyIndex, int numManifolds\n" +")\n" +"{\n" +" int i = GET_GLOBAL_IDX;\n" +" if (im_bodyA = abs(src->m_bodyAPtrAndSignBit);\n" +" dstC->m_bodyB = abs(src->m_bodyBPtrAndSignBit);\n" +" float dtInv = 1.f/dt;\n" +" for(int ic=0; ic<4; ic++)\n" +" {\n" +" dstC->m_appliedRambdaDt[ic] = 0.f;\n" +" }\n" +" dstC->m_fJacCoeffInv[0] = dstC->m_fJacCoeffInv[1] = 0.f;\n" +" dstC->m_linear = src->m_worldNormalOnB;\n" +" dstC->m_linear.w = 0.7f ;//src->getFrictionCoeff() );\n" +" for(int ic=0; ic<4; ic++)\n" +" {\n" +" float4 r0 = src->m_worldPosB[ic] - posA;\n" +" float4 r1 = src->m_worldPosB[ic] - posB;\n" +" if( ic >= src->m_worldNormalOnB.w )//npoints\n" +" {\n" +" dstC->m_jacCoeffInv[ic] = 0.f;\n" +" continue;\n" +" }\n" +" float relVelN;\n" +" {\n" +" float4 linear, angular0, angular1;\n" +" setLinearAndAngular(src->m_worldNormalOnB, r0, r1, &linear, &angular0, &angular1);\n" +" dstC->m_jacCoeffInv[ic] = calcJacCoeff(linear, -linear, angular0, angular1,\n" +" invMassA, &invInertiaA, invMassB, &invInertiaB , countA, countB);\n" +" relVelN = calcRelVel(linear, -linear, angular0, angular1,\n" +" linVelA, angVelA, linVelB, angVelB);\n" +" float e = 0.f;//src->getRestituitionCoeff();\n" +" if( relVelN*relVelN < 0.004f ) e = 0.f;\n" +" dstC->m_b[ic] = e*relVelN;\n" +" //float penetration = src->m_worldPosB[ic].w;\n" +" dstC->m_b[ic] += (src->m_worldPosB[ic].w + positionDrift)*positionConstraintCoeff*dtInv;\n" +" dstC->m_appliedRambdaDt[ic] = 0.f;\n" +" }\n" +" }\n" +" if( src->m_worldNormalOnB.w > 0 )//npoints\n" +" { // prepare friction\n" +" float4 center = make_float4(0.f);\n" +" for(int i=0; im_worldNormalOnB.w; i++) \n" +" center += src->m_worldPosB[i];\n" +" center /= (float)src->m_worldNormalOnB.w;\n" +" float4 tangent[2];\n" +" btPlaneSpace1(-src->m_worldNormalOnB,&tangent[0],&tangent[1]);\n" +" \n" +" float4 r[2];\n" +" r[0] = center - posA;\n" +" r[1] = center - posB;\n" +" for(int i=0; i<2; i++)\n" +" {\n" +" float4 linear, angular0, angular1;\n" +" setLinearAndAngular(tangent[i], r[0], r[1], &linear, &angular0, &angular1);\n" +" dstC->m_fJacCoeffInv[i] = calcJacCoeff(linear, -linear, angular0, angular1,\n" +" invMassA, &invInertiaA, invMassB, &invInertiaB ,countA, countB);\n" +" dstC->m_fAppliedRambdaDt[i] = 0.f;\n" +" }\n" +" dstC->m_center = center;\n" +" }\n" +" for(int i=0; i<4; i++)\n" +" {\n" +" if( im_worldNormalOnB.w )\n" +" {\n" +" dstC->m_worldPos[i] = src->m_worldPosB[i];\n" +" }\n" +" else\n" +" {\n" +" dstC->m_worldPos[i] = make_float4(0.f);\n" +" }\n" +" }\n" +"}\n" +"__kernel\n" +"__attribute__((reqd_work_group_size(WG_SIZE,1,1)))\n" +"void ContactToConstraintSplitKernel(__global const struct b3Contact4Data* gContact, __global const Body* gBodies, __global const Shape* gShapes, __global Constraint4* gConstraintOut, \n" +"__global const unsigned int* bodyCount,\n" +"int nContacts,\n" +"float dt,\n" +"float positionDrift,\n" +"float positionConstraintCoeff\n" +")\n" +"{\n" +" int gIdx = GET_GLOBAL_IDX;\n" +" \n" +" if( gIdx < nContacts )\n" +" {\n" +" int aIdx = abs(gContact[gIdx].m_bodyAPtrAndSignBit);\n" +" int bIdx = abs(gContact[gIdx].m_bodyBPtrAndSignBit);\n" +" float4 posA = gBodies[aIdx].m_pos;\n" +" float4 linVelA = gBodies[aIdx].m_linVel;\n" +" float4 angVelA = gBodies[aIdx].m_angVel;\n" +" float invMassA = gBodies[aIdx].m_invMass;\n" +" Matrix3x3 invInertiaA = gShapes[aIdx].m_invInertia;\n" +" float4 posB = gBodies[bIdx].m_pos;\n" +" float4 linVelB = gBodies[bIdx].m_linVel;\n" +" float4 angVelB = gBodies[bIdx].m_angVel;\n" +" float invMassB = gBodies[bIdx].m_invMass;\n" +" Matrix3x3 invInertiaB = gShapes[bIdx].m_invInertia;\n" +" Constraint4 cs;\n" +" float countA = invMassA != 0.f ? (float)bodyCount[aIdx] : 1;\n" +" float countB = invMassB != 0.f ? (float)bodyCount[bIdx] : 1;\n" +" setConstraint4( posA, linVelA, angVelA, invMassA, invInertiaA, posB, linVelB, angVelB, invMassB, invInertiaB,\n" +" &gContact[gIdx], dt, positionDrift, positionConstraintCoeff,countA,countB,\n" +" &cs );\n" +" \n" +" cs.m_batchIdx = gContact[gIdx].m_batchIdx;\n" +" gConstraintOut[gIdx] = cs;\n" +" }\n" +"}\n" +; diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/updateAabbsKernel.cl b/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/updateAabbsKernel.cl new file mode 100644 index 000000000000..ba8ba735d05b --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/updateAabbsKernel.cl @@ -0,0 +1,22 @@ + + +#include "Bullet3Collision/NarrowPhaseCollision/shared/b3UpdateAabbs.h" + + +__kernel void initializeGpuAabbsFull( const int numNodes, __global b3RigidBodyData_t* gBodies,__global b3Collidable_t* collidables, __global b3Aabb_t* plocalShapeAABB, __global b3Aabb_t* pAABB) +{ + int nodeID = get_global_id(0); + if( nodeID < numNodes ) + { + b3ComputeWorldAabb(nodeID, gBodies, collidables, plocalShapeAABB,pAABB); + } +} + +__kernel void clearOverlappingPairsKernel( __global int4* pairs, int numPairs) +{ + int pairId = get_global_id(0); + if( pairId< numPairs ) + { + pairs[pairId].z = 0xffffffff; + } +} \ No newline at end of file diff --git a/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/updateAabbsKernel.h b/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/updateAabbsKernel.h new file mode 100644 index 000000000000..d70e74017aa2 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/RigidBody/kernels/updateAabbsKernel.h @@ -0,0 +1,483 @@ +//this file is autogenerated using stringify.bat (premake --stringify) in the build folder of this project +static const char* updateAabbsKernelCL= \ +"#ifndef B3_UPDATE_AABBS_H\n" +"#define B3_UPDATE_AABBS_H\n" +"#ifndef B3_AABB_H\n" +"#define B3_AABB_H\n" +"#ifndef B3_FLOAT4_H\n" +"#define B3_FLOAT4_H\n" +"#ifndef B3_PLATFORM_DEFINITIONS_H\n" +"#define B3_PLATFORM_DEFINITIONS_H\n" +"struct MyTest\n" +"{\n" +" int bla;\n" +"};\n" +"#ifdef __cplusplus\n" +"#else\n" +"//keep B3_LARGE_FLOAT*B3_LARGE_FLOAT < FLT_MAX\n" +"#define B3_LARGE_FLOAT 1e18f\n" +"#define B3_INFINITY 1e18f\n" +"#define b3Assert(a)\n" +"#define b3ConstArray(a) __global const a*\n" +"#define b3AtomicInc atomic_inc\n" +"#define b3AtomicAdd atomic_add\n" +"#define b3Fabs fabs\n" +"#define b3Sqrt native_sqrt\n" +"#define b3Sin native_sin\n" +"#define b3Cos native_cos\n" +"#define B3_STATIC\n" +"#endif\n" +"#endif\n" +"#ifdef __cplusplus\n" +"#else\n" +" typedef float4 b3Float4;\n" +" #define b3Float4ConstArg const b3Float4\n" +" #define b3MakeFloat4 (float4)\n" +" float b3Dot3F4(b3Float4ConstArg v0,b3Float4ConstArg v1)\n" +" {\n" +" float4 a1 = b3MakeFloat4(v0.xyz,0.f);\n" +" float4 b1 = b3MakeFloat4(v1.xyz,0.f);\n" +" return dot(a1, b1);\n" +" }\n" +" b3Float4 b3Cross3(b3Float4ConstArg v0,b3Float4ConstArg v1)\n" +" {\n" +" float4 a1 = b3MakeFloat4(v0.xyz,0.f);\n" +" float4 b1 = b3MakeFloat4(v1.xyz,0.f);\n" +" return cross(a1, b1);\n" +" }\n" +" #define b3MinFloat4 min\n" +" #define b3MaxFloat4 max\n" +" #define b3Normalized(a) normalize(a)\n" +"#endif \n" +" \n" +"inline bool b3IsAlmostZero(b3Float4ConstArg v)\n" +"{\n" +" if(b3Fabs(v.x)>1e-6 || b3Fabs(v.y)>1e-6 || b3Fabs(v.z)>1e-6) \n" +" return false;\n" +" return true;\n" +"}\n" +"inline int b3MaxDot( b3Float4ConstArg vec, __global const b3Float4* vecArray, int vecLen, float* dotOut )\n" +"{\n" +" float maxDot = -B3_INFINITY;\n" +" int i = 0;\n" +" int ptIndex = -1;\n" +" for( i = 0; i < vecLen; i++ )\n" +" {\n" +" float dot = b3Dot3F4(vecArray[i],vec);\n" +" \n" +" if( dot > maxDot )\n" +" {\n" +" maxDot = dot;\n" +" ptIndex = i;\n" +" }\n" +" }\n" +" b3Assert(ptIndex>=0);\n" +" if (ptIndex<0)\n" +" {\n" +" ptIndex = 0;\n" +" }\n" +" *dotOut = maxDot;\n" +" return ptIndex;\n" +"}\n" +"#endif //B3_FLOAT4_H\n" +"#ifndef B3_MAT3x3_H\n" +"#define B3_MAT3x3_H\n" +"#ifndef B3_QUAT_H\n" +"#define B3_QUAT_H\n" +"#ifndef B3_PLATFORM_DEFINITIONS_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif\n" +"#endif\n" +"#ifndef B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +" typedef float4 b3Quat;\n" +" #define b3QuatConstArg const b3Quat\n" +" \n" +" \n" +"inline float4 b3FastNormalize4(float4 v)\n" +"{\n" +" v = (float4)(v.xyz,0.f);\n" +" return fast_normalize(v);\n" +"}\n" +" \n" +"inline b3Quat b3QuatMul(b3Quat a, b3Quat b);\n" +"inline b3Quat b3QuatNormalized(b3QuatConstArg in);\n" +"inline b3Quat b3QuatRotate(b3QuatConstArg q, b3QuatConstArg vec);\n" +"inline b3Quat b3QuatInvert(b3QuatConstArg q);\n" +"inline b3Quat b3QuatInverse(b3QuatConstArg q);\n" +"inline b3Quat b3QuatMul(b3QuatConstArg a, b3QuatConstArg b)\n" +"{\n" +" b3Quat ans;\n" +" ans = b3Cross3( a, b );\n" +" ans += a.w*b+b.w*a;\n" +"// ans.w = a.w*b.w - (a.x*b.x+a.y*b.y+a.z*b.z);\n" +" ans.w = a.w*b.w - b3Dot3F4(a, b);\n" +" return ans;\n" +"}\n" +"inline b3Quat b3QuatNormalized(b3QuatConstArg in)\n" +"{\n" +" b3Quat q;\n" +" q=in;\n" +" //return b3FastNormalize4(in);\n" +" float len = native_sqrt(dot(q, q));\n" +" if(len > 0.f)\n" +" {\n" +" q *= 1.f / len;\n" +" }\n" +" else\n" +" {\n" +" q.x = q.y = q.z = 0.f;\n" +" q.w = 1.f;\n" +" }\n" +" return q;\n" +"}\n" +"inline float4 b3QuatRotate(b3QuatConstArg q, b3QuatConstArg vec)\n" +"{\n" +" b3Quat qInv = b3QuatInvert( q );\n" +" float4 vcpy = vec;\n" +" vcpy.w = 0.f;\n" +" float4 out = b3QuatMul(b3QuatMul(q,vcpy),qInv);\n" +" return out;\n" +"}\n" +"inline b3Quat b3QuatInverse(b3QuatConstArg q)\n" +"{\n" +" return (b3Quat)(-q.xyz, q.w);\n" +"}\n" +"inline b3Quat b3QuatInvert(b3QuatConstArg q)\n" +"{\n" +" return (b3Quat)(-q.xyz, q.w);\n" +"}\n" +"inline float4 b3QuatInvRotate(b3QuatConstArg q, b3QuatConstArg vec)\n" +"{\n" +" return b3QuatRotate( b3QuatInvert( q ), vec );\n" +"}\n" +"inline b3Float4 b3TransformPoint(b3Float4ConstArg point, b3Float4ConstArg translation, b3QuatConstArg orientation)\n" +"{\n" +" return b3QuatRotate( orientation, point ) + (translation);\n" +"}\n" +" \n" +"#endif \n" +"#endif //B3_QUAT_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"typedef struct\n" +"{\n" +" b3Float4 m_row[3];\n" +"}b3Mat3x3;\n" +"#define b3Mat3x3ConstArg const b3Mat3x3\n" +"#define b3GetRow(m,row) (m.m_row[row])\n" +"inline b3Mat3x3 b3QuatGetRotationMatrix(b3Quat quat)\n" +"{\n" +" b3Float4 quat2 = (b3Float4)(quat.x*quat.x, quat.y*quat.y, quat.z*quat.z, 0.f);\n" +" b3Mat3x3 out;\n" +" out.m_row[0].x=1-2*quat2.y-2*quat2.z;\n" +" out.m_row[0].y=2*quat.x*quat.y-2*quat.w*quat.z;\n" +" out.m_row[0].z=2*quat.x*quat.z+2*quat.w*quat.y;\n" +" out.m_row[0].w = 0.f;\n" +" out.m_row[1].x=2*quat.x*quat.y+2*quat.w*quat.z;\n" +" out.m_row[1].y=1-2*quat2.x-2*quat2.z;\n" +" out.m_row[1].z=2*quat.y*quat.z-2*quat.w*quat.x;\n" +" out.m_row[1].w = 0.f;\n" +" out.m_row[2].x=2*quat.x*quat.z-2*quat.w*quat.y;\n" +" out.m_row[2].y=2*quat.y*quat.z+2*quat.w*quat.x;\n" +" out.m_row[2].z=1-2*quat2.x-2*quat2.y;\n" +" out.m_row[2].w = 0.f;\n" +" return out;\n" +"}\n" +"inline b3Mat3x3 b3AbsoluteMat3x3(b3Mat3x3ConstArg matIn)\n" +"{\n" +" b3Mat3x3 out;\n" +" out.m_row[0] = fabs(matIn.m_row[0]);\n" +" out.m_row[1] = fabs(matIn.m_row[1]);\n" +" out.m_row[2] = fabs(matIn.m_row[2]);\n" +" return out;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtZero();\n" +"__inline\n" +"b3Mat3x3 mtIdentity();\n" +"__inline\n" +"b3Mat3x3 mtTranspose(b3Mat3x3 m);\n" +"__inline\n" +"b3Mat3x3 mtMul(b3Mat3x3 a, b3Mat3x3 b);\n" +"__inline\n" +"b3Float4 mtMul1(b3Mat3x3 a, b3Float4 b);\n" +"__inline\n" +"b3Float4 mtMul3(b3Float4 a, b3Mat3x3 b);\n" +"__inline\n" +"b3Mat3x3 mtZero()\n" +"{\n" +" b3Mat3x3 m;\n" +" m.m_row[0] = (b3Float4)(0.f);\n" +" m.m_row[1] = (b3Float4)(0.f);\n" +" m.m_row[2] = (b3Float4)(0.f);\n" +" return m;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtIdentity()\n" +"{\n" +" b3Mat3x3 m;\n" +" m.m_row[0] = (b3Float4)(1,0,0,0);\n" +" m.m_row[1] = (b3Float4)(0,1,0,0);\n" +" m.m_row[2] = (b3Float4)(0,0,1,0);\n" +" return m;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtTranspose(b3Mat3x3 m)\n" +"{\n" +" b3Mat3x3 out;\n" +" out.m_row[0] = (b3Float4)(m.m_row[0].x, m.m_row[1].x, m.m_row[2].x, 0.f);\n" +" out.m_row[1] = (b3Float4)(m.m_row[0].y, m.m_row[1].y, m.m_row[2].y, 0.f);\n" +" out.m_row[2] = (b3Float4)(m.m_row[0].z, m.m_row[1].z, m.m_row[2].z, 0.f);\n" +" return out;\n" +"}\n" +"__inline\n" +"b3Mat3x3 mtMul(b3Mat3x3 a, b3Mat3x3 b)\n" +"{\n" +" b3Mat3x3 transB;\n" +" transB = mtTranspose( b );\n" +" b3Mat3x3 ans;\n" +" // why this doesn't run when 0ing in the for{}\n" +" a.m_row[0].w = 0.f;\n" +" a.m_row[1].w = 0.f;\n" +" a.m_row[2].w = 0.f;\n" +" for(int i=0; i<3; i++)\n" +" {\n" +"// a.m_row[i].w = 0.f;\n" +" ans.m_row[i].x = b3Dot3F4(a.m_row[i],transB.m_row[0]);\n" +" ans.m_row[i].y = b3Dot3F4(a.m_row[i],transB.m_row[1]);\n" +" ans.m_row[i].z = b3Dot3F4(a.m_row[i],transB.m_row[2]);\n" +" ans.m_row[i].w = 0.f;\n" +" }\n" +" return ans;\n" +"}\n" +"__inline\n" +"b3Float4 mtMul1(b3Mat3x3 a, b3Float4 b)\n" +"{\n" +" b3Float4 ans;\n" +" ans.x = b3Dot3F4( a.m_row[0], b );\n" +" ans.y = b3Dot3F4( a.m_row[1], b );\n" +" ans.z = b3Dot3F4( a.m_row[2], b );\n" +" ans.w = 0.f;\n" +" return ans;\n" +"}\n" +"__inline\n" +"b3Float4 mtMul3(b3Float4 a, b3Mat3x3 b)\n" +"{\n" +" b3Float4 colx = b3MakeFloat4(b.m_row[0].x, b.m_row[1].x, b.m_row[2].x, 0);\n" +" b3Float4 coly = b3MakeFloat4(b.m_row[0].y, b.m_row[1].y, b.m_row[2].y, 0);\n" +" b3Float4 colz = b3MakeFloat4(b.m_row[0].z, b.m_row[1].z, b.m_row[2].z, 0);\n" +" b3Float4 ans;\n" +" ans.x = b3Dot3F4( a, colx );\n" +" ans.y = b3Dot3F4( a, coly );\n" +" ans.z = b3Dot3F4( a, colz );\n" +" return ans;\n" +"}\n" +"#endif\n" +"#endif //B3_MAT3x3_H\n" +"typedef struct b3Aabb b3Aabb_t;\n" +"struct b3Aabb\n" +"{\n" +" union\n" +" {\n" +" float m_min[4];\n" +" b3Float4 m_minVec;\n" +" int m_minIndices[4];\n" +" };\n" +" union\n" +" {\n" +" float m_max[4];\n" +" b3Float4 m_maxVec;\n" +" int m_signedMaxIndices[4];\n" +" };\n" +"};\n" +"inline void b3TransformAabb2(b3Float4ConstArg localAabbMin,b3Float4ConstArg localAabbMax, float margin,\n" +" b3Float4ConstArg pos,\n" +" b3QuatConstArg orn,\n" +" b3Float4* aabbMinOut,b3Float4* aabbMaxOut)\n" +"{\n" +" b3Float4 localHalfExtents = 0.5f*(localAabbMax-localAabbMin);\n" +" localHalfExtents+=b3MakeFloat4(margin,margin,margin,0.f);\n" +" b3Float4 localCenter = 0.5f*(localAabbMax+localAabbMin);\n" +" b3Mat3x3 m;\n" +" m = b3QuatGetRotationMatrix(orn);\n" +" b3Mat3x3 abs_b = b3AbsoluteMat3x3(m);\n" +" b3Float4 center = b3TransformPoint(localCenter,pos,orn);\n" +" \n" +" b3Float4 extent = b3MakeFloat4(b3Dot3F4(localHalfExtents,b3GetRow(abs_b,0)),\n" +" b3Dot3F4(localHalfExtents,b3GetRow(abs_b,1)),\n" +" b3Dot3F4(localHalfExtents,b3GetRow(abs_b,2)),\n" +" 0.f);\n" +" *aabbMinOut = center-extent;\n" +" *aabbMaxOut = center+extent;\n" +"}\n" +"/// conservative test for overlap between two aabbs\n" +"inline bool b3TestAabbAgainstAabb(b3Float4ConstArg aabbMin1,b3Float4ConstArg aabbMax1,\n" +" b3Float4ConstArg aabbMin2, b3Float4ConstArg aabbMax2)\n" +"{\n" +" bool overlap = true;\n" +" overlap = (aabbMin1.x > aabbMax2.x || aabbMax1.x < aabbMin2.x) ? false : overlap;\n" +" overlap = (aabbMin1.z > aabbMax2.z || aabbMax1.z < aabbMin2.z) ? false : overlap;\n" +" overlap = (aabbMin1.y > aabbMax2.y || aabbMax1.y < aabbMin2.y) ? false : overlap;\n" +" return overlap;\n" +"}\n" +"#endif //B3_AABB_H\n" +"#ifndef B3_COLLIDABLE_H\n" +"#define B3_COLLIDABLE_H\n" +"#ifndef B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_FLOAT4_H\n" +"#ifndef B3_QUAT_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_QUAT_H\n" +"enum b3ShapeTypes\n" +"{\n" +" SHAPE_HEIGHT_FIELD=1,\n" +" SHAPE_CONVEX_HULL=3,\n" +" SHAPE_PLANE=4,\n" +" SHAPE_CONCAVE_TRIMESH=5,\n" +" SHAPE_COMPOUND_OF_CONVEX_HULLS=6,\n" +" SHAPE_SPHERE=7,\n" +" MAX_NUM_SHAPE_TYPES,\n" +"};\n" +"typedef struct b3Collidable b3Collidable_t;\n" +"struct b3Collidable\n" +"{\n" +" union {\n" +" int m_numChildShapes;\n" +" int m_bvhIndex;\n" +" };\n" +" union\n" +" {\n" +" float m_radius;\n" +" int m_compoundBvhIndex;\n" +" };\n" +" int m_shapeType;\n" +" union\n" +" {\n" +" int m_shapeIndex;\n" +" float m_height;\n" +" };\n" +"};\n" +"typedef struct b3GpuChildShape b3GpuChildShape_t;\n" +"struct b3GpuChildShape\n" +"{\n" +" b3Float4 m_childPosition;\n" +" b3Quat m_childOrientation;\n" +" union\n" +" {\n" +" int m_shapeIndex;//used for SHAPE_COMPOUND_OF_CONVEX_HULLS\n" +" int m_capsuleAxis;\n" +" };\n" +" union \n" +" {\n" +" float m_radius;//used for childshape of SHAPE_COMPOUND_OF_SPHERES or SHAPE_COMPOUND_OF_CAPSULES\n" +" int m_numChildShapes;//used for compound shape\n" +" };\n" +" union \n" +" {\n" +" float m_height;//used for childshape of SHAPE_COMPOUND_OF_CAPSULES\n" +" int m_collidableShapeIndex;\n" +" };\n" +" int m_shapeType;\n" +"};\n" +"struct b3CompoundOverlappingPair\n" +"{\n" +" int m_bodyIndexA;\n" +" int m_bodyIndexB;\n" +"// int m_pairType;\n" +" int m_childShapeIndexA;\n" +" int m_childShapeIndexB;\n" +"};\n" +"#endif //B3_COLLIDABLE_H\n" +"#ifndef B3_RIGIDBODY_DATA_H\n" +"#define B3_RIGIDBODY_DATA_H\n" +"#ifndef B3_FLOAT4_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_FLOAT4_H\n" +"#ifndef B3_QUAT_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif \n" +"#endif //B3_QUAT_H\n" +"#ifndef B3_MAT3x3_H\n" +"#ifdef __cplusplus\n" +"#else\n" +"#endif\n" +"#endif //B3_MAT3x3_H\n" +"typedef struct b3RigidBodyData b3RigidBodyData_t;\n" +"struct b3RigidBodyData\n" +"{\n" +" b3Float4 m_pos;\n" +" b3Quat m_quat;\n" +" b3Float4 m_linVel;\n" +" b3Float4 m_angVel;\n" +" int m_collidableIdx;\n" +" float m_invMass;\n" +" float m_restituitionCoeff;\n" +" float m_frictionCoeff;\n" +"};\n" +"typedef struct b3InertiaData b3InertiaData_t;\n" +"struct b3InertiaData\n" +"{\n" +" b3Mat3x3 m_invInertiaWorld;\n" +" b3Mat3x3 m_initInvInertia;\n" +"};\n" +"#endif //B3_RIGIDBODY_DATA_H\n" +" \n" +"void b3ComputeWorldAabb( int bodyId, __global const b3RigidBodyData_t* bodies, __global const b3Collidable_t* collidables, __global const b3Aabb_t* localShapeAABB, __global b3Aabb_t* worldAabbs)\n" +"{\n" +" __global const b3RigidBodyData_t* body = &bodies[bodyId];\n" +" b3Float4 position = body->m_pos;\n" +" b3Quat orientation = body->m_quat;\n" +" \n" +" int collidableIndex = body->m_collidableIdx;\n" +" int shapeIndex = collidables[collidableIndex].m_shapeIndex;\n" +" \n" +" if (shapeIndex>=0)\n" +" {\n" +" \n" +" b3Aabb_t localAabb = localShapeAABB[collidableIndex];\n" +" b3Aabb_t worldAabb;\n" +" \n" +" b3Float4 aabbAMinOut,aabbAMaxOut; \n" +" float margin = 0.f;\n" +" b3TransformAabb2(localAabb.m_minVec,localAabb.m_maxVec,margin,position,orientation,&aabbAMinOut,&aabbAMaxOut);\n" +" \n" +" worldAabb.m_minVec =aabbAMinOut;\n" +" worldAabb.m_minIndices[3] = bodyId;\n" +" worldAabb.m_maxVec = aabbAMaxOut;\n" +" worldAabb.m_signedMaxIndices[3] = body[bodyId].m_invMass==0.f? 0 : 1;\n" +" worldAabbs[bodyId] = worldAabb;\n" +" }\n" +"}\n" +"#endif //B3_UPDATE_AABBS_H\n" +"__kernel void initializeGpuAabbsFull( const int numNodes, __global b3RigidBodyData_t* gBodies,__global b3Collidable_t* collidables, __global b3Aabb_t* plocalShapeAABB, __global b3Aabb_t* pAABB)\n" +"{\n" +" int nodeID = get_global_id(0);\n" +" if( nodeID < numNodes )\n" +" {\n" +" b3ComputeWorldAabb(nodeID, gBodies, collidables, plocalShapeAABB,pAABB);\n" +" }\n" +"}\n" +"__kernel void clearOverlappingPairsKernel( __global int4* pairs, int numPairs)\n" +"{\n" +" int pairId = get_global_id(0);\n" +" if( pairId< numPairs )\n" +" {\n" +" pairs[pairId].z = 0xffffffff;\n" +" }\n" +"}\n" +; diff --git a/extern/bullet/src/Bullet3OpenCL/premake4.lua b/extern/bullet/src/Bullet3OpenCL/premake4.lua new file mode 100644 index 000000000000..55a861363485 --- /dev/null +++ b/extern/bullet/src/Bullet3OpenCL/premake4.lua @@ -0,0 +1,29 @@ +function createProject(vendor) + hasCL = findOpenCL(vendor) + + if (hasCL) then + + project ("Bullet3OpenCL_" .. vendor) + + initOpenCL(vendor) + + kind "StaticLib" + + + includedirs { + ".",".." + } + + files { + "**.cpp", + "**.h" + } + + end +end + +createProject("clew") +createProject("AMD") +createProject("Intel") +createProject("NVIDIA") +createProject("Apple") diff --git a/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/CMakeLists.txt b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/CMakeLists.txt new file mode 100644 index 000000000000..125576634f09 --- /dev/null +++ b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/CMakeLists.txt @@ -0,0 +1,55 @@ + +INCLUDE_DIRECTORIES( + ${BULLET_PHYSICS_SOURCE_DIR}/src +) + +SET(Bullet2FileLoader_SRCS + b3BulletFile.cpp + b3Chunk.cpp + b3DNA.cpp + b3File.cpp + b3Serializer.cpp +) + + +SET(Bullet2FileLoader_HDRS + b3BulletFile.h + b3Chunk.h + b3Common.h + b3Defines.h + b3DNA.h + b3File.h + b3Serializer.h + autogenerated/bullet2.h +) + +ADD_LIBRARY(Bullet2FileLoader ${Bullet2FileLoader_SRCS} ${Bullet2FileLoader_HDRS}) +if (BUILD_SHARED_LIBS) + target_link_libraries(Bullet2FileLoader Bullet3Common) +endif () +SET_TARGET_PROPERTIES(Bullet2FileLoader PROPERTIES VERSION ${BULLET_VERSION}) +SET_TARGET_PROPERTIES(Bullet2FileLoader PROPERTIES SOVERSION ${BULLET_VERSION}) + +IF (INSTALL_LIBS) + IF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) + #FILES_MATCHING requires CMake 2.6 + IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS Bullet2FileLoader DESTINATION .) + ELSE (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS Bullet2FileLoader + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib${LIB_SUFFIX} + ARCHIVE DESTINATION lib${LIB_SUFFIX}) + INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.h" PATTERN +".svn" EXCLUDE PATTERN "CMakeFiles" EXCLUDE) + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + SET_TARGET_PROPERTIES(Bullet2FileLoader PROPERTIES FRAMEWORK true) + SET_TARGET_PROPERTIES(Bullet2FileLoader PROPERTIES PUBLIC_HEADER "${Bullet2FileLoader_HDRS}") + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) +ENDIF (INSTALL_LIBS) diff --git a/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/autogenerated/bullet2.h b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/autogenerated/bullet2.h new file mode 100644 index 000000000000..a6b57b1a1280 --- /dev/null +++ b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/autogenerated/bullet2.h @@ -0,0 +1,1053 @@ +/* Copyright (C) 2011 Erwin Coumans & Charlie C +* +* 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. +*/ +// Auto generated from Bullet/Extras/HeaderGenerator/bulletGenerate.py +#ifndef __BULLET2_H__ +#define __BULLET2_H__ +namespace Bullet3SerializeBullet2 { + +// put an empty struct in the case +typedef struct bInvalidHandle { + int unused; +}bInvalidHandle; + + class PointerArray; + class b3PhysicsSystem; + class ListBase; + class b3Vector3FloatData; + class b3Vector3DoubleData; + class b3Matrix3x3FloatData; + class b3Matrix3x3DoubleData; + class b3TransformFloatData; + class b3TransformDoubleData; + class b3BvhSubtreeInfoData; + class b3OptimizedBvhNodeFloatData; + class b3OptimizedBvhNodeDoubleData; + class b3QuantizedBvhNodeData; + class b3QuantizedBvhFloatData; + class b3QuantizedBvhDoubleData; + class b3CollisionShapeData; + class b3StaticPlaneShapeData; + class b3ConvexInternalShapeData; + class b3PositionAndRadius; + class b3MultiSphereShapeData; + class b3IntIndexData; + class b3ShortIntIndexData; + class b3ShortIntIndexTripletData; + class b3CharIndexTripletData; + class b3MeshPartData; + class b3StridingMeshInterfaceData; + class b3TriangleMeshShapeData; + class b3ScaledTriangleMeshShapeData; + class b3CompoundShapeChildData; + class b3CompoundShapeData; + class b3CylinderShapeData; + class b3CapsuleShapeData; + class b3TriangleInfoData; + class b3TriangleInfoMapData; + class b3GImpactMeshShapeData; + class b3ConvexHullShapeData; + class b3CollisionObjectDoubleData; + class b3CollisionObjectFloatData; + class b3DynamicsWorldDoubleData; + class b3DynamicsWorldFloatData; + class b3RigidBodyFloatData; + class b3RigidBodyDoubleData; + class b3ConstraintInfo1; + class b3TypedConstraintData; + class b3Point2PointConstraintFloatData; + class b3Point2PointConstraintDoubleData; + class b3HingeConstraintDoubleData; + class b3HingeConstraintFloatData; + class b3ConeTwistConstraintData; + class b3Generic6DofConstraintData; + class b3Generic6DofSpringConstraintData; + class b3SliderConstraintData; + class b3ContactSolverInfoDoubleData; + class b3ContactSolverInfoFloatData; + class SoftBodyMaterialData; + class SoftBodyNodeData; + class SoftBodyLinkData; + class SoftBodyFaceData; + class SoftBodyTetraData; + class SoftRigidAnchorData; + class SoftBodyConfigData; + class SoftBodyPoseData; + class SoftBodyClusterData; + class b3SoftBodyJointData; + class b3SoftBodyFloatData; +// -------------------------------------------------- // + class PointerArray + { + public: + int m_size; + int m_capacity; + void *m_data; + }; + + +// -------------------------------------------------- // + class b3PhysicsSystem + { + public: + PointerArray m_collisionShapes; + PointerArray m_collisionObjects; + PointerArray m_constraints; + }; + + +// -------------------------------------------------- // + class ListBase + { + public: + void *first; + void *last; + }; + + +// -------------------------------------------------- // + class b3Vector3FloatData + { + public: + float m_floats[4]; + }; + + +// -------------------------------------------------- // + class b3Vector3DoubleData + { + public: + double m_floats[4]; + }; + + +// -------------------------------------------------- // + class b3Matrix3x3FloatData + { + public: + b3Vector3FloatData m_el[3]; + }; + + +// -------------------------------------------------- // + class b3Matrix3x3DoubleData + { + public: + b3Vector3DoubleData m_el[3]; + }; + + +// -------------------------------------------------- // + class b3TransformFloatData + { + public: + b3Matrix3x3FloatData m_basis; + b3Vector3FloatData m_origin; + }; + + +// -------------------------------------------------- // + class b3TransformDoubleData + { + public: + b3Matrix3x3DoubleData m_basis; + b3Vector3DoubleData m_origin; + }; + + +// -------------------------------------------------- // + class b3BvhSubtreeInfoData + { + public: + int m_rootNodeIndex; + int m_subtreeSize; + short m_quantizedAabbMin[3]; + short m_quantizedAabbMax[3]; + }; + + +// -------------------------------------------------- // + class b3OptimizedBvhNodeFloatData + { + public: + b3Vector3FloatData m_aabbMinOrg; + b3Vector3FloatData m_aabbMaxOrg; + int m_escapeIndex; + int m_subPart; + int m_triangleIndex; + char m_pad[4]; + }; + + +// -------------------------------------------------- // + class b3OptimizedBvhNodeDoubleData + { + public: + b3Vector3DoubleData m_aabbMinOrg; + b3Vector3DoubleData m_aabbMaxOrg; + int m_escapeIndex; + int m_subPart; + int m_triangleIndex; + char m_pad[4]; + }; + + +// -------------------------------------------------- // + class b3QuantizedBvhNodeData + { + public: + short m_quantizedAabbMin[3]; + short m_quantizedAabbMax[3]; + int m_escapeIndexOrTriangleIndex; + }; + + +// -------------------------------------------------- // + class b3QuantizedBvhFloatData + { + public: + b3Vector3FloatData m_bvhAabbMin; + b3Vector3FloatData m_bvhAabbMax; + b3Vector3FloatData m_bvhQuantization; + int m_curNodeIndex; + int m_useQuantization; + int m_numContiguousLeafNodes; + int m_numQuantizedContiguousNodes; + b3OptimizedBvhNodeFloatData *m_contiguousNodesPtr; + b3QuantizedBvhNodeData *m_quantizedContiguousNodesPtr; + b3BvhSubtreeInfoData *m_subTreeInfoPtr; + int m_traversalMode; + int m_numSubtreeHeaders; + }; + + +// -------------------------------------------------- // + class b3QuantizedBvhDoubleData + { + public: + b3Vector3DoubleData m_bvhAabbMin; + b3Vector3DoubleData m_bvhAabbMax; + b3Vector3DoubleData m_bvhQuantization; + int m_curNodeIndex; + int m_useQuantization; + int m_numContiguousLeafNodes; + int m_numQuantizedContiguousNodes; + b3OptimizedBvhNodeDoubleData *m_contiguousNodesPtr; + b3QuantizedBvhNodeData *m_quantizedContiguousNodesPtr; + int m_traversalMode; + int m_numSubtreeHeaders; + b3BvhSubtreeInfoData *m_subTreeInfoPtr; + }; + + +// -------------------------------------------------- // + class b3CollisionShapeData + { + public: + char *m_name; + int m_shapeType; + char m_padding[4]; + }; + + +// -------------------------------------------------- // + class b3StaticPlaneShapeData + { + public: + b3CollisionShapeData m_collisionShapeData; + b3Vector3FloatData m_localScaling; + b3Vector3FloatData m_planeNormal; + float m_planeConstant; + char m_pad[4]; + }; + + +// -------------------------------------------------- // + class b3ConvexInternalShapeData + { + public: + b3CollisionShapeData m_collisionShapeData; + b3Vector3FloatData m_localScaling; + b3Vector3FloatData m_implicitShapeDimensions; + float m_collisionMargin; + int m_padding; + }; + + +// -------------------------------------------------- // + class b3PositionAndRadius + { + public: + b3Vector3FloatData m_pos; + float m_radius; + }; + + +// -------------------------------------------------- // + class b3MultiSphereShapeData + { + public: + b3ConvexInternalShapeData m_convexInternalShapeData; + b3PositionAndRadius *m_localPositionArrayPtr; + int m_localPositionArraySize; + char m_padding[4]; + }; + + +// -------------------------------------------------- // + class b3IntIndexData + { + public: + int m_value; + }; + + +// -------------------------------------------------- // + class b3ShortIntIndexData + { + public: + short m_value; + char m_pad[2]; + }; + + +// -------------------------------------------------- // + class b3ShortIntIndexTripletData + { + public: + short m_values[3]; + char m_pad[2]; + }; + + +// -------------------------------------------------- // + class b3CharIndexTripletData + { + public: + char m_values[3]; + char m_pad; + }; + + +// -------------------------------------------------- // + class b3MeshPartData + { + public: + b3Vector3FloatData *m_vertices3f; + b3Vector3DoubleData *m_vertices3d; + b3IntIndexData *m_indices32; + b3ShortIntIndexTripletData *m_3indices16; + b3CharIndexTripletData *m_3indices8; + b3ShortIntIndexData *m_indices16; + int m_numTriangles; + int m_numVertices; + }; + + +// -------------------------------------------------- // + class b3StridingMeshInterfaceData + { + public: + b3MeshPartData *m_meshPartsPtr; + b3Vector3FloatData m_scaling; + int m_numMeshParts; + char m_padding[4]; + }; + + +// -------------------------------------------------- // + class b3TriangleMeshShapeData + { + public: + b3CollisionShapeData m_collisionShapeData; + b3StridingMeshInterfaceData m_meshInterface; + b3QuantizedBvhFloatData *m_quantizedFloatBvh; + b3QuantizedBvhDoubleData *m_quantizedDoubleBvh; + b3TriangleInfoMapData *m_triangleInfoMap; + float m_collisionMargin; + char m_pad3[4]; + }; + + +// -------------------------------------------------- // + class b3ScaledTriangleMeshShapeData + { + public: + b3TriangleMeshShapeData m_trimeshShapeData; + b3Vector3FloatData m_localScaling; + }; + + +// -------------------------------------------------- // + class b3CompoundShapeChildData + { + public: + b3TransformFloatData m_transform; + b3CollisionShapeData *m_childShape; + int m_childShapeType; + float m_childMargin; + }; + + +// -------------------------------------------------- // + class b3CompoundShapeData + { + public: + b3CollisionShapeData m_collisionShapeData; + b3CompoundShapeChildData *m_childShapePtr; + int m_numChildShapes; + float m_collisionMargin; + }; + + +// -------------------------------------------------- // + class b3CylinderShapeData + { + public: + b3ConvexInternalShapeData m_convexInternalShapeData; + int m_upAxis; + char m_padding[4]; + }; + + +// -------------------------------------------------- // + class b3CapsuleShapeData + { + public: + b3ConvexInternalShapeData m_convexInternalShapeData; + int m_upAxis; + char m_padding[4]; + }; + + +// -------------------------------------------------- // + class b3TriangleInfoData + { + public: + int m_flags; + float m_edgeV0V1Angle; + float m_edgeV1V2Angle; + float m_edgeV2V0Angle; + }; + + +// -------------------------------------------------- // + class b3TriangleInfoMapData + { + public: + int *m_hashTablePtr; + int *m_nextPtr; + b3TriangleInfoData *m_valueArrayPtr; + int *m_keyArrayPtr; + float m_convexEpsilon; + float m_planarEpsilon; + float m_equalVertexThreshold; + float m_edgeDistanceThreshold; + float m_zeroAreaThreshold; + int m_nextSize; + int m_hashTableSize; + int m_numValues; + int m_numKeys; + char m_padding[4]; + }; + + +// -------------------------------------------------- // + class b3GImpactMeshShapeData + { + public: + b3CollisionShapeData m_collisionShapeData; + b3StridingMeshInterfaceData m_meshInterface; + b3Vector3FloatData m_localScaling; + float m_collisionMargin; + int m_gimpactSubType; + }; + + +// -------------------------------------------------- // + class b3ConvexHullShapeData + { + public: + b3ConvexInternalShapeData m_convexInternalShapeData; + b3Vector3FloatData *m_unscaledPointsFloatPtr; + b3Vector3DoubleData *m_unscaledPointsDoublePtr; + int m_numUnscaledPoints; + char m_padding3[4]; + }; + + +// -------------------------------------------------- // + class b3CollisionObjectDoubleData + { + public: + void *m_broadphaseHandle; + void *m_collisionShape; + b3CollisionShapeData *m_rootCollisionShape; + char *m_name; + b3TransformDoubleData m_worldTransform; + b3TransformDoubleData m_interpolationWorldTransform; + b3Vector3DoubleData m_interpolationLinearVelocity; + b3Vector3DoubleData m_interpolationAngularVelocity; + b3Vector3DoubleData m_anisotropicFriction; + double m_contactProcessingThreshold; + double m_deactivationTime; + double m_friction; + double m_rollingFriction; + double m_restitution; + double m_hitFraction; + double m_ccdSweptSphereRadius; + double m_ccdMotionThreshold; + int m_hasAnisotropicFriction; + int m_collisionFlags; + int m_islandTag1; + int m_companionId; + int m_activationState1; + int m_internalType; + int m_checkCollideWith; + char m_padding[4]; + }; + + +// -------------------------------------------------- // + class b3CollisionObjectFloatData + { + public: + void *m_broadphaseHandle; + void *m_collisionShape; + b3CollisionShapeData *m_rootCollisionShape; + char *m_name; + b3TransformFloatData m_worldTransform; + b3TransformFloatData m_interpolationWorldTransform; + b3Vector3FloatData m_interpolationLinearVelocity; + b3Vector3FloatData m_interpolationAngularVelocity; + b3Vector3FloatData m_anisotropicFriction; + float m_contactProcessingThreshold; + float m_deactivationTime; + float m_friction; + float m_rollingFriction; + float m_restitution; + float m_hitFraction; + float m_ccdSweptSphereRadius; + float m_ccdMotionThreshold; + int m_hasAnisotropicFriction; + int m_collisionFlags; + int m_islandTag1; + int m_companionId; + int m_activationState1; + int m_internalType; + int m_checkCollideWith; + char m_padding[4]; + }; + + + +// -------------------------------------------------- // + class b3RigidBodyFloatData + { + public: + b3CollisionObjectFloatData m_collisionObjectData; + b3Matrix3x3FloatData m_invInertiaTensorWorld; + b3Vector3FloatData m_linearVelocity; + b3Vector3FloatData m_angularVelocity; + b3Vector3FloatData m_angularFactor; + b3Vector3FloatData m_linearFactor; + b3Vector3FloatData m_gravity; + b3Vector3FloatData m_gravity_acceleration; + b3Vector3FloatData m_invInertiaLocal; + b3Vector3FloatData m_totalForce; + b3Vector3FloatData m_totalTorque; + float m_inverseMass; + float m_linearDamping; + float m_angularDamping; + float m_additionalDampingFactor; + float m_additionalLinearDampingThresholdSqr; + float m_additionalAngularDampingThresholdSqr; + float m_additionalAngularDampingFactor; + float m_linearSleepingThreshold; + float m_angularSleepingThreshold; + int m_additionalDamping; + }; + + +// -------------------------------------------------- // + class b3RigidBodyDoubleData + { + public: + b3CollisionObjectDoubleData m_collisionObjectData; + b3Matrix3x3DoubleData m_invInertiaTensorWorld; + b3Vector3DoubleData m_linearVelocity; + b3Vector3DoubleData m_angularVelocity; + b3Vector3DoubleData m_angularFactor; + b3Vector3DoubleData m_linearFactor; + b3Vector3DoubleData m_gravity; + b3Vector3DoubleData m_gravity_acceleration; + b3Vector3DoubleData m_invInertiaLocal; + b3Vector3DoubleData m_totalForce; + b3Vector3DoubleData m_totalTorque; + double m_inverseMass; + double m_linearDamping; + double m_angularDamping; + double m_additionalDampingFactor; + double m_additionalLinearDampingThresholdSqr; + double m_additionalAngularDampingThresholdSqr; + double m_additionalAngularDampingFactor; + double m_linearSleepingThreshold; + double m_angularSleepingThreshold; + int m_additionalDamping; + char m_padding[4]; + }; + + +// -------------------------------------------------- // + class b3ConstraintInfo1 + { + public: + int m_numConstraintRows; + int nub; + }; + + +// -------------------------------------------------- // + class b3TypedConstraintData + { + public: + bInvalidHandle *m_rbA; + bInvalidHandle *m_rbB; + char *m_name; + int m_objectType; + int m_userConstraintType; + int m_userConstraintId; + int m_needsFeedback; + float m_appliedImpulse; + float m_dbgDrawSize; + int m_disableCollisionsBetweenLinkedBodies; + int m_overrideNumSolverIterations; + float m_breakingImpulseThreshold; + int m_isEnabled; + }; + + +// -------------------------------------------------- // + class b3Point2PointConstraintFloatData + { + public: + b3TypedConstraintData m_typeConstraintData; + b3Vector3FloatData m_pivotInA; + b3Vector3FloatData m_pivotInB; + }; + + +// -------------------------------------------------- // + class b3Point2PointConstraintDoubleData + { + public: + b3TypedConstraintData m_typeConstraintData; + b3Vector3DoubleData m_pivotInA; + b3Vector3DoubleData m_pivotInB; + }; + + +// -------------------------------------------------- // + class b3HingeConstraintDoubleData + { + public: + b3TypedConstraintData m_typeConstraintData; + b3TransformDoubleData m_rbAFrame; + b3TransformDoubleData m_rbBFrame; + int m_useReferenceFrameA; + int m_angularOnly; + int m_enableAngularMotor; + float m_motorTargetVelocity; + float m_maxMotorImpulse; + float m_lowerLimit; + float m_upperLimit; + float m_limitSoftness; + float m_biasFactor; + float m_relaxationFactor; + }; + + +// -------------------------------------------------- // + class b3HingeConstraintFloatData + { + public: + b3TypedConstraintData m_typeConstraintData; + b3TransformFloatData m_rbAFrame; + b3TransformFloatData m_rbBFrame; + int m_useReferenceFrameA; + int m_angularOnly; + int m_enableAngularMotor; + float m_motorTargetVelocity; + float m_maxMotorImpulse; + float m_lowerLimit; + float m_upperLimit; + float m_limitSoftness; + float m_biasFactor; + float m_relaxationFactor; + }; + + +// -------------------------------------------------- // + class b3ConeTwistConstraintData + { + public: + b3TypedConstraintData m_typeConstraintData; + b3TransformFloatData m_rbAFrame; + b3TransformFloatData m_rbBFrame; + float m_swingSpan1; + float m_swingSpan2; + float m_twistSpan; + float m_limitSoftness; + float m_biasFactor; + float m_relaxationFactor; + float m_damping; + char m_pad[4]; + }; + + +// -------------------------------------------------- // + class b3Generic6DofConstraintData + { + public: + b3TypedConstraintData m_typeConstraintData; + b3TransformFloatData m_rbAFrame; + b3TransformFloatData m_rbBFrame; + b3Vector3FloatData m_linearUpperLimit; + b3Vector3FloatData m_linearLowerLimit; + b3Vector3FloatData m_angularUpperLimit; + b3Vector3FloatData m_angularLowerLimit; + int m_useLinearReferenceFrameA; + int m_useOffsetForConstraintFrame; + }; + + +// -------------------------------------------------- // + class b3Generic6DofSpringConstraintData + { + public: + b3Generic6DofConstraintData m_6dofData; + int m_springEnabled[6]; + float m_equilibriumPoint[6]; + float m_springStiffness[6]; + float m_springDamping[6]; + }; + + +// -------------------------------------------------- // + class b3SliderConstraintData + { + public: + b3TypedConstraintData m_typeConstraintData; + b3TransformFloatData m_rbAFrame; + b3TransformFloatData m_rbBFrame; + float m_linearUpperLimit; + float m_linearLowerLimit; + float m_angularUpperLimit; + float m_angularLowerLimit; + int m_useLinearReferenceFrameA; + int m_useOffsetForConstraintFrame; + }; + + +// -------------------------------------------------- // + class b3ContactSolverInfoDoubleData + { + public: + double m_tau; + double m_damping; + double m_friction; + double m_timeStep; + double m_restitution; + double m_maxErrorReduction; + double m_sor; + double m_erp; + double m_erp2; + double m_globalCfm; + double m_splitImpulsePenetrationThreshold; + double m_splitImpulseTurnErp; + double m_linearSlop; + double m_warmstartingFactor; + double m_maxGyroscopicForce; + double m_singleAxisRollingFrictionThreshold; + int m_numIterations; + int m_solverMode; + int m_restingContactRestitutionThreshold; + int m_minimumSolverBatchSize; + int m_splitImpulse; + char m_padding[4]; + }; + + +// -------------------------------------------------- // + class b3ContactSolverInfoFloatData + { + public: + float m_tau; + float m_damping; + float m_friction; + float m_timeStep; + float m_restitution; + float m_maxErrorReduction; + float m_sor; + float m_erp; + float m_erp2; + float m_globalCfm; + float m_splitImpulsePenetrationThreshold; + float m_splitImpulseTurnErp; + float m_linearSlop; + float m_warmstartingFactor; + float m_maxGyroscopicForce; + float m_singleAxisRollingFrictionThreshold; + int m_numIterations; + int m_solverMode; + int m_restingContactRestitutionThreshold; + int m_minimumSolverBatchSize; + int m_splitImpulse; + char m_padding[4]; + }; + + + // -------------------------------------------------- // + class b3DynamicsWorldDoubleData + { + public: + b3ContactSolverInfoDoubleData m_solverInfo; + b3Vector3DoubleData m_gravity; + }; + + +// -------------------------------------------------- // + class b3DynamicsWorldFloatData + { + public: + b3ContactSolverInfoFloatData m_solverInfo; + b3Vector3FloatData m_gravity; + }; + + + +// -------------------------------------------------- // + class SoftBodyMaterialData + { + public: + float m_linearStiffness; + float m_angularStiffness; + float m_volumeStiffness; + int m_flags; + }; + + +// -------------------------------------------------- // + class SoftBodyNodeData + { + public: + SoftBodyMaterialData *m_material; + b3Vector3FloatData m_position; + b3Vector3FloatData m_previousPosition; + b3Vector3FloatData m_velocity; + b3Vector3FloatData m_accumulatedForce; + b3Vector3FloatData m_normal; + float m_inverseMass; + float m_area; + int m_attach; + int m_pad; + }; + + +// -------------------------------------------------- // + class SoftBodyLinkData + { + public: + SoftBodyMaterialData *m_material; + int m_nodeIndices[2]; + float m_restLength; + int m_bbending; + }; + + +// -------------------------------------------------- // + class SoftBodyFaceData + { + public: + b3Vector3FloatData m_normal; + SoftBodyMaterialData *m_material; + int m_nodeIndices[3]; + float m_restArea; + }; + + +// -------------------------------------------------- // + class SoftBodyTetraData + { + public: + b3Vector3FloatData m_c0[4]; + SoftBodyMaterialData *m_material; + int m_nodeIndices[4]; + float m_restVolume; + float m_c1; + float m_c2; + int m_pad; + }; + + +// -------------------------------------------------- // + class SoftRigidAnchorData + { + public: + b3Matrix3x3FloatData m_c0; + b3Vector3FloatData m_c1; + b3Vector3FloatData m_localFrame; + bInvalidHandle *m_rigidBody; + int m_nodeIndex; + float m_c2; + }; + + +// -------------------------------------------------- // + class SoftBodyConfigData + { + public: + int m_aeroModel; + float m_baumgarte; + float m_damping; + float m_drag; + float m_lift; + float m_pressure; + float m_volume; + float m_dynamicFriction; + float m_poseMatch; + float m_rigidContactHardness; + float m_kineticContactHardness; + float m_softContactHardness; + float m_anchorHardness; + float m_softRigidClusterHardness; + float m_softKineticClusterHardness; + float m_softSoftClusterHardness; + float m_softRigidClusterImpulseSplit; + float m_softKineticClusterImpulseSplit; + float m_softSoftClusterImpulseSplit; + float m_maxVolume; + float m_timeScale; + int m_velocityIterations; + int m_positionIterations; + int m_driftIterations; + int m_clusterIterations; + int m_collisionFlags; + }; + + +// -------------------------------------------------- // + class SoftBodyPoseData + { + public: + b3Matrix3x3FloatData m_rot; + b3Matrix3x3FloatData m_scale; + b3Matrix3x3FloatData m_aqq; + b3Vector3FloatData m_com; + b3Vector3FloatData *m_positions; + float *m_weights; + int m_numPositions; + int m_numWeigts; + int m_bvolume; + int m_bframe; + float m_restVolume; + int m_pad; + }; + + +// -------------------------------------------------- // + class SoftBodyClusterData + { + public: + b3TransformFloatData m_framexform; + b3Matrix3x3FloatData m_locii; + b3Matrix3x3FloatData m_invwi; + b3Vector3FloatData m_com; + b3Vector3FloatData m_vimpulses[2]; + b3Vector3FloatData m_dimpulses[2]; + b3Vector3FloatData m_lv; + b3Vector3FloatData m_av; + b3Vector3FloatData *m_framerefs; + int *m_nodeIndices; + float *m_masses; + int m_numFrameRefs; + int m_numNodes; + int m_numMasses; + float m_idmass; + float m_imass; + int m_nvimpulses; + int m_ndimpulses; + float m_ndamping; + float m_ldamping; + float m_adamping; + float m_matching; + float m_maxSelfCollisionImpulse; + float m_selfCollisionImpulseFactor; + int m_containsAnchor; + int m_collide; + int m_clusterIndex; + }; + + +// -------------------------------------------------- // + class b3SoftBodyJointData + { + public: + void *m_bodyA; + void *m_bodyB; + b3Vector3FloatData m_refs[2]; + float m_cfm; + float m_erp; + float m_split; + int m_delete; + b3Vector3FloatData m_relPosition[2]; + int m_bodyAtype; + int m_bodyBtype; + int m_jointType; + int m_pad; + }; + + +// -------------------------------------------------- // + class b3SoftBodyFloatData + { + public: + b3CollisionObjectFloatData m_collisionObjectData; + SoftBodyPoseData *m_pose; + SoftBodyMaterialData **m_materials; + SoftBodyNodeData *m_nodes; + SoftBodyLinkData *m_links; + SoftBodyFaceData *m_faces; + SoftBodyTetraData *m_tetrahedra; + SoftRigidAnchorData *m_anchors; + SoftBodyClusterData *m_clusters; + b3SoftBodyJointData *m_joints; + int m_numMaterials; + int m_numNodes; + int m_numLinks; + int m_numFaces; + int m_numTetrahedra; + int m_numAnchors; + int m_numClusters; + int m_numJoints; + SoftBodyConfigData m_config; + }; + + +} +#endif//__BULLET2_H__ \ No newline at end of file diff --git a/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3BulletFile.cpp b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3BulletFile.cpp new file mode 100644 index 000000000000..c3ceb8388ca3 --- /dev/null +++ b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3BulletFile.cpp @@ -0,0 +1,423 @@ +/* +bParse +Copyright (c) 2006-2010 Erwin Coumans http://gamekit.googlecode.com + +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 "b3BulletFile.h" +#include "b3Defines.h" +#include "b3DNA.h" + +#if !defined( __CELLOS_LV2__) && !defined(__MWERKS__) +#include +#endif +#include + + +// 32 && 64 bit versions +#ifdef B3_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES +#ifdef _WIN64 +extern char b3s_bulletDNAstr64[]; +extern int b3s_bulletDNAlen64; +#else +extern char b3s_bulletDNAstr[]; +extern int b3s_bulletDNAlen; +#endif //_WIN64 +#else//B3_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES + +extern char b3s_bulletDNAstr64[]; +extern int b3s_bulletDNAlen64; +extern char b3s_bulletDNAstr[]; +extern int b3s_bulletDNAlen; + +#endif //B3_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES + +using namespace bParse; + +b3BulletFile::b3BulletFile() +:bFile("", "BULLET ") +{ + mMemoryDNA = new bDNA(); //this memory gets released in the bFile::~bFile destructor,@todo not consistent with the rule 'who allocates it, has to deallocate it" + + m_DnaCopy = 0; + + +#ifdef B3_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES +#ifdef _WIN64 + m_DnaCopy = (char*)b3AlignedAlloc(b3s_bulletDNAlen64,16); + memcpy(m_DnaCopy,b3s_bulletDNAstr64,b3s_bulletDNAlen64); + mMemoryDNA->init(m_DnaCopy,b3s_bulletDNAlen64); +#else//_WIN64 + m_DnaCopy = (char*)b3AlignedAlloc(b3s_bulletDNAlen,16); + memcpy(m_DnaCopy,b3s_bulletDNAstr,b3s_bulletDNAlen); + mMemoryDNA->init(m_DnaCopy,b3s_bulletDNAlen); +#endif//_WIN64 +#else//B3_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES + if (VOID_IS_8) + { + m_DnaCopy = (char*) b3AlignedAlloc(b3s_bulletDNAlen64,16); + memcpy(m_DnaCopy,b3s_bulletDNAstr64,b3s_bulletDNAlen64); + mMemoryDNA->init(m_DnaCopy,b3s_bulletDNAlen64); + } + else + { + m_DnaCopy =(char*) b3AlignedAlloc(b3s_bulletDNAlen,16); + memcpy(m_DnaCopy,b3s_bulletDNAstr,b3s_bulletDNAlen); + mMemoryDNA->init(m_DnaCopy,b3s_bulletDNAlen); + } +#endif//B3_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES +} + + + +b3BulletFile::b3BulletFile(const char* fileName) +:bFile(fileName, "BULLET ") +{ + m_DnaCopy = 0; +} + + + +b3BulletFile::b3BulletFile(char *memoryBuffer, int len) +:bFile(memoryBuffer,len, "BULLET ") +{ + m_DnaCopy = 0; +} + + +b3BulletFile::~b3BulletFile() +{ + if (m_DnaCopy) + b3AlignedFree(m_DnaCopy); + + + while (m_dataBlocks.size()) + { + char* dataBlock = m_dataBlocks[m_dataBlocks.size()-1]; + delete[] dataBlock; + m_dataBlocks.pop_back(); + } + +} + + + +// ----------------------------------------------------- // +void b3BulletFile::parseData() +{ +// printf ("Building datablocks"); +// printf ("Chunk size = %d",CHUNK_HEADER_LEN); +// printf ("File chunk size = %d",ChunkUtils::getOffset(mFlags)); + + const bool brokenDNA = (mFlags&FD_BROKEN_DNA)!=0; + + //const bool swap = (mFlags&FD_ENDIAN_SWAP)!=0; + + + mDataStart = 12; + + char *dataPtr = mFileBuffer+mDataStart; + + bChunkInd dataChunk; + dataChunk.code = 0; + + + //dataPtr += ChunkUtils::getNextBlock(&dataChunk, dataPtr, mFlags); + int seek = getNextBlock(&dataChunk, dataPtr, mFlags); + + + if (mFlags &FD_ENDIAN_SWAP) + swapLen(dataPtr); + + //dataPtr += ChunkUtils::getOffset(mFlags); + char *dataPtrHead = 0; + + while (dataChunk.code != B3_DNA1) + { + if (!brokenDNA || (dataChunk.code != B3_QUANTIZED_BVH_CODE) ) + { + + // one behind + if (dataChunk.code == B3_SDNA) break; + //if (dataChunk.code == DNA1) break; + + // same as (BHEAD+DATA dependency) + dataPtrHead = dataPtr+ChunkUtils::getOffset(mFlags); + if (dataChunk.dna_nr>=0) + { + char *id = readStruct(dataPtrHead, dataChunk); + + // lookup maps + if (id) + { + m_chunkPtrPtrMap.insert(dataChunk.oldPtr, dataChunk); + mLibPointers.insert(dataChunk.oldPtr, (bStructHandle*)id); + + m_chunks.push_back(dataChunk); + // block it + //bListBasePtr *listID = mMain->getListBasePtr(dataChunk.code); + //if (listID) + // listID->push_back((bStructHandle*)id); + } + + if (dataChunk.code == B3_SOFTBODY_CODE) + { + m_softBodies.push_back((bStructHandle*) id); + } + + if (dataChunk.code == B3_RIGIDBODY_CODE) + { + m_rigidBodies.push_back((bStructHandle*) id); + } + + if (dataChunk.code == B3_DYNAMICSWORLD_CODE) + { + m_dynamicsWorldInfo.push_back((bStructHandle*) id); + } + + if (dataChunk.code == B3_CONSTRAINT_CODE) + { + m_constraints.push_back((bStructHandle*) id); + } + + if (dataChunk.code == B3_QUANTIZED_BVH_CODE) + { + m_bvhs.push_back((bStructHandle*) id); + } + + if (dataChunk.code == B3_TRIANLGE_INFO_MAP) + { + m_triangleInfoMaps.push_back((bStructHandle*) id); + } + + if (dataChunk.code == B3_COLLISIONOBJECT_CODE) + { + m_collisionObjects.push_back((bStructHandle*) id); + } + + if (dataChunk.code == B3_SHAPE_CODE) + { + m_collisionShapes.push_back((bStructHandle*) id); + } + + // if (dataChunk.code == GLOB) + // { + // m_glob = (bStructHandle*) id; + // } + } else + { + //printf("unknown chunk\n"); + + mLibPointers.insert(dataChunk.oldPtr, (bStructHandle*)dataPtrHead); + } + } else + { + printf("skipping B3_QUANTIZED_BVH_CODE due to broken DNA\n"); + } + + + dataPtr += seek; + + seek = getNextBlock(&dataChunk, dataPtr, mFlags); + if (mFlags &FD_ENDIAN_SWAP) + swapLen(dataPtr); + + if (seek < 0) + break; + } + +} + +void b3BulletFile::addDataBlock(char* dataBlock) +{ + m_dataBlocks.push_back(dataBlock); + +} + + + + +void b3BulletFile::writeDNA(FILE* fp) +{ + + bChunkInd dataChunk; + dataChunk.code = B3_DNA1; + dataChunk.dna_nr = 0; + dataChunk.nr = 1; +#ifdef B3_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES + if (VOID_IS_8) + { +#ifdef _WIN64 + dataChunk.len = b3s_bulletDNAlen64; + dataChunk.oldPtr = b3s_bulletDNAstr64; + fwrite(&dataChunk,sizeof(bChunkInd),1,fp); + fwrite(b3s_bulletDNAstr64, b3s_bulletDNAlen64,1,fp); +#else + b3Assert(0); +#endif + } + else + { +#ifndef _WIN64 + dataChunk.len = b3s_bulletDNAlen; + dataChunk.oldPtr = b3s_bulletDNAstr; + fwrite(&dataChunk,sizeof(bChunkInd),1,fp); + fwrite(b3s_bulletDNAstr, b3s_bulletDNAlen,1,fp); +#else//_WIN64 + b3Assert(0); +#endif//_WIN64 + } +#else//B3_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES + if (VOID_IS_8) + { + dataChunk.len = b3s_bulletDNAlen64; + dataChunk.oldPtr = b3s_bulletDNAstr64; + fwrite(&dataChunk,sizeof(bChunkInd),1,fp); + fwrite(b3s_bulletDNAstr64, b3s_bulletDNAlen64,1,fp); + } + else + { + dataChunk.len = b3s_bulletDNAlen; + dataChunk.oldPtr = b3s_bulletDNAstr; + fwrite(&dataChunk,sizeof(bChunkInd),1,fp); + fwrite(b3s_bulletDNAstr, b3s_bulletDNAlen,1,fp); + } +#endif//B3_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES +} + + +void b3BulletFile::parse(int verboseMode) +{ +#ifdef B3_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES + if (VOID_IS_8) + { +#ifdef _WIN64 + + if (m_DnaCopy) + delete m_DnaCopy; + m_DnaCopy = (char*)b3AlignedAlloc(b3s_bulletDNAlen64,16); + memcpy(m_DnaCopy,b3s_bulletDNAstr64,b3s_bulletDNAlen64); + parseInternal(verboseMode,(char*)b3s_bulletDNAstr64,b3s_bulletDNAlen64); +#else + b3Assert(0); +#endif + } + else + { +#ifndef _WIN64 + + if (m_DnaCopy) + delete m_DnaCopy; + m_DnaCopy = (char*)b3AlignedAlloc(b3s_bulletDNAlen,16); + memcpy(m_DnaCopy,b3s_bulletDNAstr,b3s_bulletDNAlen); + parseInternal(verboseMode,m_DnaCopy,b3s_bulletDNAlen); +#else + b3Assert(0); +#endif + } +#else//B3_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES + if (VOID_IS_8) + { + if (m_DnaCopy) + delete m_DnaCopy; + m_DnaCopy = (char*)b3AlignedAlloc(b3s_bulletDNAlen64,16); + memcpy(m_DnaCopy,b3s_bulletDNAstr64,b3s_bulletDNAlen64); + parseInternal(verboseMode,m_DnaCopy,b3s_bulletDNAlen64); + } + else + { + if (m_DnaCopy) + delete m_DnaCopy; + m_DnaCopy = (char*)b3AlignedAlloc(b3s_bulletDNAlen,16); + memcpy(m_DnaCopy,b3s_bulletDNAstr,b3s_bulletDNAlen); + parseInternal(verboseMode,m_DnaCopy,b3s_bulletDNAlen); + } +#endif//B3_INTERNAL_UPDATE_SERIALIZATION_STRUCTURES + + //the parsing will convert to cpu endian + mFlags &=~FD_ENDIAN_SWAP; + + int littleEndian= 1; + littleEndian= ((char*)&littleEndian)[0]; + + mFileBuffer[8] = littleEndian?'v':'V'; + +} + +// experimental +int b3BulletFile::write(const char* fileName, bool fixupPointers) +{ + FILE *fp = fopen(fileName, "wb"); + if (fp) + { + char header[B3_SIZEOFBLENDERHEADER] ; + memcpy(header, m_headerString, 7); + int endian= 1; + endian= ((char*)&endian)[0]; + + if (endian) + { + header[7] = '_'; + } else + { + header[7] = '-'; + } + if (VOID_IS_8) + { + header[8]='V'; + } else + { + header[8]='v'; + } + + header[9] = '2'; + header[10] = '7'; + header[11] = '5'; + + fwrite(header,B3_SIZEOFBLENDERHEADER,1,fp); + + writeChunks(fp, fixupPointers); + + writeDNA(fp); + + fclose(fp); + + } else + { + printf("Error: cannot open file %s for writing\n",fileName); + return 0; + } + return 1; +} + + + +void b3BulletFile::addStruct(const char* structType,void* data, int len, void* oldPtr, int code) +{ + + bParse::bChunkInd dataChunk; + dataChunk.code = code; + dataChunk.nr = 1; + dataChunk.len = len; + dataChunk.dna_nr = mMemoryDNA->getReverseType(structType); + dataChunk.oldPtr = oldPtr; + + ///Perform structure size validation + short* structInfo= mMemoryDNA->getStruct(dataChunk.dna_nr); + int elemBytes; + elemBytes= mMemoryDNA->getLength(structInfo[0]); +// int elemBytes = mMemoryDNA->getElementSize(structInfo[0],structInfo[1]); + assert(len==elemBytes); + + mLibPointers.insert(dataChunk.oldPtr, (bStructHandle*)data); + m_chunks.push_back(dataChunk); +} diff --git a/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3BulletFile.h b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3BulletFile.h new file mode 100644 index 000000000000..fb1b9b0dde4c --- /dev/null +++ b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3BulletFile.h @@ -0,0 +1,83 @@ +/* +bParse +Copyright (c) 2006-2010 Charlie C & Erwin Coumans http://gamekit.googlecode.com + +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 B3_BULLET_FILE_H +#define B3_BULLET_FILE_H + + +#include "b3File.h" +#include "Bullet3Common/b3AlignedObjectArray.h" +#include "b3Defines.h" + +#include "Bullet3Serialize/Bullet2FileLoader/b3Serializer.h" + + + +namespace bParse { + + // ----------------------------------------------------- // + class b3BulletFile : public bFile + { + + + protected: + + char* m_DnaCopy; + + public: + + b3AlignedObjectArray m_softBodies; + + b3AlignedObjectArray m_rigidBodies; + + b3AlignedObjectArray m_collisionObjects; + + b3AlignedObjectArray m_collisionShapes; + + b3AlignedObjectArray m_constraints; + + b3AlignedObjectArray m_bvhs; + + b3AlignedObjectArray m_triangleInfoMaps; + + b3AlignedObjectArray m_dynamicsWorldInfo; + + b3AlignedObjectArray m_dataBlocks; + b3BulletFile(); + + b3BulletFile(const char* fileName); + + b3BulletFile(char *memoryBuffer, int len); + + virtual ~b3BulletFile(); + + virtual void addDataBlock(char* dataBlock); + + + // experimental + virtual int write(const char* fileName, bool fixupPointers=false); + + virtual void parse(int verboseMode); + + virtual void parseData(); + + virtual void writeDNA(FILE* fp); + + void addStruct(const char* structType,void* data, int len, void* oldPtr, int code); + + }; +}; + +#endif //B3_BULLET_FILE_H diff --git a/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3Chunk.cpp b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3Chunk.cpp new file mode 100644 index 000000000000..c0e1bb708cea --- /dev/null +++ b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3Chunk.cpp @@ -0,0 +1,75 @@ +/* +bParse +Copyright (c) 2006-2009 Charlie C & Erwin Coumans http://gamekit.googlecode.com + +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 "b3Chunk.h" +#include "b3Defines.h" +#include "b3File.h" + +#if !defined( __CELLOS_LV2__) && !defined(__MWERKS__) +#include +#endif +#include + + +using namespace bParse; + + +// ----------------------------------------------------- // +short ChunkUtils::swapShort(short sht) +{ + B3_SWITCH_SHORT(sht); + return sht; +} + +// ----------------------------------------------------- // +int ChunkUtils::swapInt(int inte) +{ + B3_SWITCH_INT(inte); + return inte; +} + +// ----------------------------------------------------- // +b3Long64 ChunkUtils::swapLong64(b3Long64 lng) +{ + B3_SWITCH_LONGINT(lng); + return lng; +} + +// ----------------------------------------------------- // +int ChunkUtils::getOffset(int flags) +{ + // if the file is saved in a + // different format, get the + // file's chunk size + int res = CHUNK_HEADER_LEN; + + if (VOID_IS_8) + { + if (flags &FD_BITS_VARIES) + res = sizeof(bChunkPtr4); + } + else + { + if (flags &FD_BITS_VARIES) + res = sizeof(bChunkPtr8); + } + return res; +} + + + + + +//eof diff --git a/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3Chunk.h b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3Chunk.h new file mode 100644 index 000000000000..03ecb6b4faf8 --- /dev/null +++ b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3Chunk.h @@ -0,0 +1,92 @@ +/* +bParse +Copyright (c) 2006-2009 Charlie C & Erwin Coumans http://gamekit.googlecode.com + +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 __BCHUNK_H__ +#define __BCHUNK_H__ + +#if defined (_WIN32) && ! defined (__MINGW32__) + #define b3Long64 __int64 +#elif defined (__MINGW32__) + #include + #define b3Long64 int64_t +#else + #define b3Long64 long long +#endif + + +namespace bParse { + + + // ----------------------------------------------------- // + class bChunkPtr4 + { + public: + bChunkPtr4(){} + int code; + int len; + union + { + int m_uniqueInt; + }; + int dna_nr; + int nr; + }; + + // ----------------------------------------------------- // + class bChunkPtr8 + { + public: + bChunkPtr8(){} + int code, len; + union + { + b3Long64 oldPrev; + int m_uniqueInts[2]; + }; + int dna_nr, nr; + }; + + // ----------------------------------------------------- // + class bChunkInd + { + public: + bChunkInd(){} + int code, len; + void *oldPtr; + int dna_nr, nr; + }; + + + // ----------------------------------------------------- // + class ChunkUtils + { + public: + + // file chunk offset + static int getOffset(int flags); + + // endian utils + static short swapShort(short sht); + static int swapInt(int inte); + static b3Long64 swapLong64(b3Long64 lng); + + }; + + + const int CHUNK_HEADER_LEN = ((sizeof(bChunkInd))); + const bool VOID_IS_8 = ((sizeof(void*)==8)); +} + +#endif//__BCHUNK_H__ diff --git a/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3Common.h b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3Common.h new file mode 100644 index 000000000000..2792d84033f1 --- /dev/null +++ b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3Common.h @@ -0,0 +1,39 @@ +/* +bParse +Copyright (c) 2006-2009 Charlie C & Erwin Coumans http://gamekit.googlecode.com + +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 __BCOMMON_H__ +#define __BCOMMON_H__ + + +#include +//#include "bLog.h" +#include "Bullet3Common/b3AlignedObjectArray.h" +#include "Bullet3Common/b3HashMap.h" + +namespace bParse { + + class bMain; + class bFileData; + class bFile; + class bDNA; + + // delete void* undefined + typedef struct bStructHandle {int unused;}bStructHandle; + typedef b3AlignedObjectArray bListBasePtr; + typedef b3HashMap bPtrMap; +} + + +#endif//__BCOMMON_H__ diff --git a/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3DNA.cpp b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3DNA.cpp new file mode 100644 index 000000000000..0fe50569221d --- /dev/null +++ b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3DNA.cpp @@ -0,0 +1,629 @@ +/* +bParse +Copyright (c) 2006-2009 Charlie C & Erwin Coumans http://gamekit.googlecode.com + +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 + +#include "b3DNA.h" +#include "b3Chunk.h" +#include +#include +#include + +//this define will force traversal of structures, to check backward (and forward) compatibility +//#define TEST_BACKWARD_FORWARD_COMPATIBILITY + + +using namespace bParse; + + +// ----------------------------------------------------- // +bDNA::bDNA() + : mPtrLen(0) +{ + // -- +} + +// ----------------------------------------------------- // +bDNA::~bDNA() +{ + // -- +} + +// ----------------------------------------------------- // +bool bDNA::lessThan(bDNA *file) +{ + return ( m_Names.size() < file->m_Names.size()); +} + +// ----------------------------------------------------- // +char *bDNA::getName(int ind) +{ + assert(ind <= (int)m_Names.size()); + return m_Names[ind].m_name; +} + + +// ----------------------------------------------------- // +char *bDNA::getType(int ind) +{ + assert(ind<= (int)mTypes.size()); + return mTypes[ind]; +} + + +// ----------------------------------------------------- // +short *bDNA::getStruct(int ind) +{ + assert(ind <= (int)mStructs.size()); + return mStructs[ind]; +} + + +// ----------------------------------------------------- // +short bDNA::getLength(int ind) +{ + assert(ind <= (int)mTlens.size()); + return mTlens[ind]; +} + + +// ----------------------------------------------------- // +int bDNA::getReverseType(short type) +{ + + int* intPtr = mStructReverse.find(type); + if (intPtr) + return *intPtr; + + return -1; +} + +// ----------------------------------------------------- // +int bDNA::getReverseType(const char *type) +{ + + b3HashString key(type); + int* valuePtr = mTypeLookup.find(key); + if (valuePtr) + return *valuePtr; + + return -1; +} + +// ----------------------------------------------------- // +int bDNA::getNumStructs() +{ + return (int)mStructs.size(); +} + +// ----------------------------------------------------- // +bool bDNA::flagNotEqual(int dna_nr) +{ + assert(dna_nr <= (int)mCMPFlags.size()); + return mCMPFlags[dna_nr] == FDF_STRUCT_NEQU; +} + +// ----------------------------------------------------- // +bool bDNA::flagEqual(int dna_nr) +{ + assert(dna_nr <= (int)mCMPFlags.size()); + int flag = mCMPFlags[dna_nr]; + return flag == FDF_STRUCT_EQU; +} + +// ----------------------------------------------------- // +bool bDNA::flagNone(int dna_nr) +{ + assert(dna_nr <= (int)mCMPFlags.size()); + return mCMPFlags[dna_nr] == FDF_NONE; +} + +// ----------------------------------------------------- // +int bDNA::getPointerSize() +{ + return mPtrLen; +} + +// ----------------------------------------------------- // +void bDNA::initRecurseCmpFlags(int iter) +{ + // iter is FDF_STRUCT_NEQU + + short *oldStrc = mStructs[iter]; + short type = oldStrc[0]; + + for (int i=0; i<(int)mStructs.size(); i++) + { + if (i != iter && mCMPFlags[i] == FDF_STRUCT_EQU ) + { + short *curStruct = mStructs[i]; + int eleLen = curStruct[1]; + curStruct+=2; + + for (int j=0; jgetReverseType(typeName); + if (newLookup == -1) + { + mCMPFlags[i] = FDF_NONE; + continue; + } + short *curStruct = memDNA->mStructs[newLookup]; +#else + // memory for file + + if (oldLookup < memDNA->mStructs.size()) + { + short *curStruct = memDNA->mStructs[oldLookup]; +#endif + + + + // rebuild... + mCMPFlags[i] = FDF_STRUCT_NEQU; + +#ifndef TEST_BACKWARD_FORWARD_COMPATIBILITY + + if (curStruct[1] == oldStruct[1]) + { + // type len same ... + if (mTlens[oldStruct[0]] == memDNA->mTlens[curStruct[0]]) + { + bool isSame = true; + int elementLength = oldStruct[1]; + + + curStruct+=2; + oldStruct+=2; + + + for (int j=0; jmTypes[curStruct[0]])!=0) + { + isSame=false; + break; + } + + // name the same + if (strcmp(m_Names[oldStruct[1]].m_name, memDNA->m_Names[curStruct[1]].m_name)!=0) + { + isSame=false; + break; + } + } + // flag valid == + if (isSame) + mCMPFlags[i] = FDF_STRUCT_EQU; + } + } +#endif + } + } + + + + + + // recurse in + for ( i=0; i<(int)mStructs.size(); i++) + { + if (mCMPFlags[i] == FDF_STRUCT_NEQU) + initRecurseCmpFlags(i); + } +} + + + + +static int name_is_array(char* name, int* dim1, int* dim2) { + int len = strlen(name); + /*fprintf(stderr,"[%s]",name);*/ + /*if (len >= 1) { + if (name[len-1] != ']') + return 1; + } + return 0;*/ + char *bp; + int num; + if (dim1) { + *dim1 = 1; + } + if (dim2) { + *dim2 = 1; + } + bp = strchr(name, '['); + if (!bp) { + return 0; + } + num = 0; + while (++bp < name+len-1) { + const char c = *bp; + if (c == ']') { + break; + } + if (c <= '9' && c >= '0') { + num *= 10; + num += (c - '0'); + } else { + printf("array parse error.\n"); + return 0; + } + } + if (dim2) { + *dim2 = num; + } + + /* find second dim, if any. */ + bp = strchr(bp, '['); + if (!bp) { + return 1; /* at least we got the first dim. */ + } + num = 0; + while (++bp < name+len-1) { + const char c = *bp; + if (c == ']') { + break; + } + if (c <= '9' && c >= '0') { + num *= 10; + num += (c - '0'); + } else { + printf("array2 parse error.\n"); + return 1; + } + } + if (dim1) { + if (dim2) { + *dim1 = *dim2; + *dim2 = num; + } else { + *dim1 = num; + } + } + + return 1; +} + + +// ----------------------------------------------------- // +void bDNA::init(char *data, int len, bool swap) +{ + int *intPtr=0;short *shtPtr=0; + char *cp = 0;int dataLen =0; + //long nr=0; + intPtr = (int*)data; + + /* + SDNA (4 bytes) (magic number) + NAME (4 bytes) + (4 bytes) amount of names (int) + + + */ + + if (strncmp(data, "SDNA", 4)==0) + { + // skip ++ NAME + intPtr++; intPtr++; + } + + + + // Parse names + if (swap) + { + *intPtr = ChunkUtils::swapInt(*intPtr); + } + dataLen = *intPtr; + intPtr++; + + cp = (char*)intPtr; + int i; + for ( i=0; i amount of types (int) + + + */ + + intPtr = (int*)cp; + assert(strncmp(cp, "TYPE", 4)==0); intPtr++; + + if (swap) + { + *intPtr = ChunkUtils::swapInt(*intPtr); + } + dataLen = *intPtr; + intPtr++; + + cp = (char*)intPtr; + for ( i=0; i (short) the lengths of types + + */ + + // Parse type lens + intPtr = (int*)cp; + assert(strncmp(cp, "TLEN", 4)==0); intPtr++; + + dataLen = (int)mTypes.size(); + + shtPtr = (short*)intPtr; + for ( i=0; i amount of structs (int) + + + + + + + */ + + intPtr = (int*)shtPtr; + cp = (char*)intPtr; + assert(strncmp(cp, "STRC", 4)==0); intPtr++; + + if (swap) + { + *intPtr = ChunkUtils::swapInt(*intPtr); + } + dataLen = *intPtr; + intPtr++; + + + shtPtr = (short*)intPtr; + for ( i=0; itypes_count; ++i) { + /* if (!bf->types[i].is_struct)*/ + { + printf("%3d: sizeof(%s%s)=%d", + i, + bf->types[i].is_struct ? "struct " : "atomic ", + bf->types[i].name, bf->types[i].size); + if (bf->types[i].is_struct) { + int j; + printf(", %d fields: { ", bf->types[i].fieldtypes_count); + for (j=0; jtypes[i].fieldtypes_count; ++j) { + printf("%s %s", + bf->types[bf->types[i].fieldtypes[j]].name, + bf->names[bf->types[i].fieldnames[j]]); + if (j == bf->types[i].fieldtypes_count-1) { + printf(";}"); + } else { + printf("; "); + } + } + } + printf("\n\n"); + + } + } +#endif + +} + + + + +//eof + + diff --git a/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3DNA.h b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3DNA.h new file mode 100644 index 000000000000..6e60087cce3d --- /dev/null +++ b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3DNA.h @@ -0,0 +1,110 @@ +/* +bParse +Copyright (c) 2006-2009 Charlie C & Erwin Coumans http://gamekit.googlecode.com + +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 __BDNA_H__ +#define __BDNA_H__ + + +#include "b3Common.h" + +namespace bParse { + + struct bNameInfo + { + char* m_name; + bool m_isPointer; + int m_dim0; + int m_dim1; + }; + + class bDNA + { + public: + bDNA(); + ~bDNA(); + + void init(char *data, int len, bool swap=false); + + int getArraySize(char* str); + int getArraySizeNew(short name) + { + const bNameInfo& nameInfo = m_Names[name]; + return nameInfo.m_dim0*nameInfo.m_dim1; + } + int getElementSize(short type, short name) + { + const bNameInfo& nameInfo = m_Names[name]; + int size = nameInfo.m_isPointer ? mPtrLen*nameInfo.m_dim0*nameInfo.m_dim1 : mTlens[type]*nameInfo.m_dim0*nameInfo.m_dim1; + return size; + } + + int getNumNames() const + { + return m_Names.size(); + } + + char *getName(int ind); + char *getType(int ind); + short *getStruct(int ind); + short getLength(int ind); + int getReverseType(short type); + int getReverseType(const char *type); + + + int getNumStructs(); + + // + bool lessThan(bDNA* other); + + void initCmpFlags(bDNA *memDNA); + bool flagNotEqual(int dna_nr); + bool flagEqual(int dna_nr); + bool flagNone(int dna_nr); + + + int getPointerSize(); + + void dumpTypeDefinitions(); + + + private: + enum FileDNAFlags + { + FDF_NONE=0, + FDF_STRUCT_NEQU, + FDF_STRUCT_EQU + }; + + void initRecurseCmpFlags(int i); + + b3AlignedObjectArray mCMPFlags; + + b3AlignedObjectArray m_Names; + b3AlignedObjectArray mTypes; + b3AlignedObjectArray mStructs; + b3AlignedObjectArray mTlens; + b3HashMap mStructReverse; + b3HashMap mTypeLookup; + + int mPtrLen; + + + + + }; +} + + +#endif//__BDNA_H__ diff --git a/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3Defines.h b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3Defines.h new file mode 100644 index 000000000000..8f28d3c44179 --- /dev/null +++ b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3Defines.h @@ -0,0 +1,136 @@ +/* Copyright (C) 2006-2009 Charlie C & Erwin Coumans http://gamekit.googlecode.com +* +* 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 __B_DEFINES_H__ +#define __B_DEFINES_H__ + + +// MISC defines, see BKE_global.h, BKE_utildefines.h +#define B3_SIZEOFBLENDERHEADER 12 + + +// ------------------------------------------------------------ +#if defined(__sgi) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__) +# define B3_MAKE_ID(a,b,c,d) ( (int)(a)<<24 | (int)(b)<<16 | (c)<<8 | (d) ) +#else +# define B3_MAKE_ID(a,b,c,d) ( (int)(d)<<24 | (int)(c)<<16 | (b)<<8 | (a) ) +#endif + + +// ------------------------------------------------------------ +#if defined(__sgi) || defined(__sparc) || defined(__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__) +# define B3_MAKE_ID2(c, d) ( (c)<<8 | (d) ) +#else +# define B3_MAKE_ID2(c, d) ( (d)<<8 | (c) ) +#endif + +// ------------------------------------------------------------ +#define B3_ID_SCE B3_MAKE_ID2('S', 'C') +#define B3_ID_LI B3_MAKE_ID2('L', 'I') +#define B3_ID_OB B3_MAKE_ID2('O', 'B') +#define B3_ID_ME B3_MAKE_ID2('M', 'E') +#define B3_ID_CU B3_MAKE_ID2('C', 'U') +#define B3_ID_MB B3_MAKE_ID2('M', 'B') +#define B3_ID_MA B3_MAKE_ID2('M', 'A') +#define B3_ID_TE B3_MAKE_ID2('T', 'E') +#define B3_ID_IM B3_MAKE_ID2('I', 'M') +#define B3_ID_IK B3_MAKE_ID2('I', 'K') +#define B3_ID_WV B3_MAKE_ID2('W', 'V') +#define B3_ID_LT B3_MAKE_ID2('L', 'T') +#define B3_ID_SE B3_MAKE_ID2('S', 'E') +#define B3_ID_LF B3_MAKE_ID2('L', 'F') +#define B3_ID_LA B3_MAKE_ID2('L', 'A') +#define B3_ID_CA B3_MAKE_ID2('C', 'A') +#define B3_ID_IP B3_MAKE_ID2('I', 'P') +#define B3_ID_KE B3_MAKE_ID2('K', 'E') +#define B3_ID_WO B3_MAKE_ID2('W', 'O') +#define B3_ID_SCR B3_MAKE_ID2('S', 'R') +#define B3_ID_VF B3_MAKE_ID2('V', 'F') +#define B3_ID_TXT B3_MAKE_ID2('T', 'X') +#define B3_ID_SO B3_MAKE_ID2('S', 'O') +#define B3_ID_SAMPLE B3_MAKE_ID2('S', 'A') +#define B3_ID_GR B3_MAKE_ID2('G', 'R') +#define B3_ID_ID B3_MAKE_ID2('I', 'D') +#define B3_ID_AR B3_MAKE_ID2('A', 'R') +#define B3_ID_AC B3_MAKE_ID2('A', 'C') +#define B3_ID_SCRIPT B3_MAKE_ID2('P', 'Y') +#define B3_ID_FLUIDSIM B3_MAKE_ID2('F', 'S') +#define B3_ID_NT B3_MAKE_ID2('N', 'T') +#define B3_ID_BR B3_MAKE_ID2('B', 'R') + + +#define B3_ID_SEQ B3_MAKE_ID2('S', 'Q') +#define B3_ID_CO B3_MAKE_ID2('C', 'O') +#define B3_ID_PO B3_MAKE_ID2('A', 'C') +#define B3_ID_NLA B3_MAKE_ID2('N', 'L') + +#define B3_ID_VS B3_MAKE_ID2('V', 'S') +#define B3_ID_VN B3_MAKE_ID2('V', 'N') + + +// ------------------------------------------------------------ +#define B3_FORM B3_MAKE_ID('F','O','R','M') +#define B3_DDG1 B3_MAKE_ID('3','D','G','1') +#define B3_DDG2 B3_MAKE_ID('3','D','G','2') +#define B3_DDG3 B3_MAKE_ID('3','D','G','3') +#define B3_DDG4 B3_MAKE_ID('3','D','G','4') +#define B3_GOUR B3_MAKE_ID('G','O','U','R') +#define B3_BLEN B3_MAKE_ID('B','L','E','N') +#define B3_DER_ B3_MAKE_ID('D','E','R','_') +#define B3_V100 B3_MAKE_ID('V','1','0','0') +#define B3_DATA B3_MAKE_ID('D','A','T','A') +#define B3_GLOB B3_MAKE_ID('G','L','O','B') +#define B3_IMAG B3_MAKE_ID('I','M','A','G') +#define B3_TEST B3_MAKE_ID('T','E','S','T') +#define B3_USER B3_MAKE_ID('U','S','E','R') + + +// ------------------------------------------------------------ +#define B3_DNA1 B3_MAKE_ID('D','N','A','1') +#define B3_REND B3_MAKE_ID('R','E','N','D') +#define B3_ENDB B3_MAKE_ID('E','N','D','B') +#define B3_NAME B3_MAKE_ID('N','A','M','E') +#define B3_SDNA B3_MAKE_ID('S','D','N','A') +#define B3_TYPE B3_MAKE_ID('T','Y','P','E') +#define B3_TLEN B3_MAKE_ID('T','L','E','N') +#define B3_STRC B3_MAKE_ID('S','T','R','C') + + +// ------------------------------------------------------------ +#define B3_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; } + +// ------------------------------------------------------------ +#define B3_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; } + +// ------------------------------------------------------------ +#define B3_SWITCH_LONGINT(a) { \ + char s_i, *p_i; \ + p_i= (char *)&(a); \ + s_i=p_i[0]; p_i[0]=p_i[7]; p_i[7]=s_i; \ + s_i=p_i[1]; p_i[1]=p_i[6]; p_i[6]=s_i; \ + s_i=p_i[2]; p_i[2]=p_i[5]; p_i[5]=s_i; \ + s_i=p_i[3]; p_i[3]=p_i[4]; p_i[4]=s_i; } + +#endif//__B_DEFINES_H__ diff --git a/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3File.cpp b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3File.cpp new file mode 100644 index 000000000000..432f7fc2b4bc --- /dev/null +++ b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3File.cpp @@ -0,0 +1,1739 @@ +/* +bParse +Copyright (c) 2006-2009 Charlie C & Erwin Coumans http://gamekit.googlecode.com + +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 "b3File.h" +#include "b3Common.h" +#include "b3Chunk.h" +#include "b3DNA.h" +#include +#include +#include +#include "b3Defines.h" +#include "Bullet3Serialize/Bullet2FileLoader/b3Serializer.h" +#include "Bullet3Common/b3AlignedAllocator.h" +#include "Bullet3Common/b3MinMax.h" + +#define B3_SIZEOFBLENDERHEADER 12 +#define MAX_ARRAY_LENGTH 512 +using namespace bParse; +#define MAX_STRLEN 1024 + +const char* getCleanName(const char* memName, char* buffer) +{ + int slen = strlen(memName); + assert(slen 0) + { + if (strncmp((tempBuffer + ChunkUtils::getOffset(mFlags)), "SDNANAME", 8) ==0) + dna.oldPtr = (tempBuffer + ChunkUtils::getOffset(mFlags)); + else dna.oldPtr = 0; + } + else dna.oldPtr = 0; + } + // Some Bullet files are missing the DNA1 block + // In Blender it's DNA1 + ChunkUtils::getOffset() + SDNA + NAME + // In Bullet tests its SDNA + NAME + else if (strncmp(tempBuffer, "SDNANAME", 8) ==0) + { + dna.oldPtr = blenderData + i; + dna.len = mFileLen-i; + + // Also no REND block, so exit now. + if (mVersion==276) break; + } + + if (mDataStart && dna.oldPtr) break; + tempBuffer++; + } + if (!dna.oldPtr || !dna.len) + { + //printf("Failed to find DNA1+SDNA pair\n"); + mFlags &= ~FD_OK; + return; + } + + + mFileDNA = new bDNA(); + + + ///mFileDNA->init will convert part of DNA file endianness to current CPU endianness if necessary + mFileDNA->init((char*)dna.oldPtr, dna.len, (mFlags & FD_ENDIAN_SWAP)!=0); + + + if (mVersion==276) + { + int i; + for (i=0;igetNumNames();i++) + { + if (strcmp(mFileDNA->getName(i),"int")==0) + { + mFlags |= FD_BROKEN_DNA; + } + } + if ((mFlags&FD_BROKEN_DNA)!=0) + { + //printf("warning: fixing some broken DNA version\n"); + } + } + + + + if (verboseMode & FD_VERBOSE_DUMP_DNA_TYPE_DEFINITIONS) + mFileDNA->dumpTypeDefinitions(); + + mMemoryDNA = new bDNA(); + int littleEndian= 1; + littleEndian= ((char*)&littleEndian)[0]; + + mMemoryDNA->init(memDna,memDnaLength,littleEndian==0); + + + + + ///@todo we need a better version check, add version/sub version info from FileGlobal into memory DNA/header files + if (mMemoryDNA->getNumNames() != mFileDNA->getNumNames()) + { + mFlags |= FD_VERSION_VARIES; + //printf ("Warning, file DNA is different than built in, performance is reduced. Best to re-export file with a matching version/platform"); + } + + // as long as it kept up to date it will be ok!! + if (mMemoryDNA->lessThan(mFileDNA)) + { + //printf ("Warning, file DNA is newer than built in."); + } + + + mFileDNA->initCmpFlags(mMemoryDNA); + + parseData(); + + resolvePointers(verboseMode); + + updateOldPointers(); + + +} + + + +// ----------------------------------------------------- // +void bFile::swap(char *head, bChunkInd& dataChunk, bool ignoreEndianFlag) +{ + char *data = head; + short *strc = mFileDNA->getStruct(dataChunk.dna_nr); + + + + const char s[] = "SoftBodyMaterialData"; + int szs = sizeof(s); + if (strncmp((char*)&dataChunk.code,"ARAY",4)==0) + { + short *oldStruct = mFileDNA->getStruct(dataChunk.dna_nr); + char *oldType = mFileDNA->getType(oldStruct[0]); + if (strncmp(oldType,s,szs)==0) + { + return; + } + } + + + int len = mFileDNA->getLength(strc[0]); + + for (int i=0; icode & 0xFFFF)==0) + c->code >>=16; + B3_SWITCH_INT(c->len); + B3_SWITCH_INT(c->dna_nr); + B3_SWITCH_INT(c->nr); + } else + { + bChunkPtr8* c = (bChunkPtr8*) dataPtr; + if ((c->code & 0xFFFF)==0) + c->code >>=16; + B3_SWITCH_INT(c->len); + B3_SWITCH_INT(c->dna_nr); + B3_SWITCH_INT(c->nr); + + } + } else + { + if (mFlags &FD_BITS_VARIES) + { + bChunkPtr8*c = (bChunkPtr8*) dataPtr; + if ((c->code & 0xFFFF)==0) + c->code >>=16; + B3_SWITCH_INT(c->len); + B3_SWITCH_INT(c->dna_nr); + B3_SWITCH_INT(c->nr); + + } else + { + bChunkPtr4* c = (bChunkPtr4*) dataPtr; + if ((c->code & 0xFFFF)==0) + c->code >>=16; + B3_SWITCH_INT(c->len); + + B3_SWITCH_INT(c->dna_nr); + B3_SWITCH_INT(c->nr); + + } + } + +} + + +void bFile::swapDNA(char* ptr) +{ + bool swap = ((mFlags & FD_ENDIAN_SWAP)!=0); + + char* data = &ptr[20]; +// void bDNA::init(char *data, int len, bool swap) + int *intPtr=0;short *shtPtr=0; + char *cp = 0;int dataLen =0; + //long nr=0; + intPtr = (int*)data; + + /* + SDNA (4 bytes) (magic number) + NAME (4 bytes) + (4 bytes) amount of names (int) + + + */ + + if (strncmp(data, "SDNA", 4)==0) + { + // skip ++ NAME + intPtr++; intPtr++; + } + + + + // Parse names + if (swap) + dataLen = ChunkUtils::swapInt(*intPtr); + else + dataLen = *intPtr; + + *intPtr = ChunkUtils::swapInt(*intPtr); + intPtr++; + + cp = (char*)intPtr; + int i; + for ( i=0; i amount of types (int) + + + */ + + intPtr = (int*)cp; + assert(strncmp(cp, "TYPE", 4)==0); intPtr++; + + if (swap) + dataLen = ChunkUtils::swapInt(*intPtr); + else + dataLen = *intPtr; + + *intPtr = ChunkUtils::swapInt(*intPtr); + + intPtr++; + + cp = (char*)intPtr; + for ( i=0; i (short) the lengths of types + + */ + + // Parse type lens + intPtr = (int*)cp; + assert(strncmp(cp, "TLEN", 4)==0); intPtr++; + + + shtPtr = (short*)intPtr; + for ( i=0; i amount of structs (int) + + + + + + + */ + + intPtr = (int*)shtPtr; + cp = (char*)intPtr; + assert(strncmp(cp, "STRC", 4)==0); + intPtr++; + + if (swap) + dataLen = ChunkUtils::swapInt(*intPtr); + else + dataLen = *intPtr; + + *intPtr = ChunkUtils::swapInt(*intPtr); + + intPtr++; + + + shtPtr = (short*)intPtr; + for ( i=0; i=0) + { + swap(dataPtrHead, dataChunk,ignoreEndianFlag); + } else + { + //printf("unknown chunk\n"); + } + } + + // next please! + dataPtr += seek; + + seek = getNextBlock(&dataChunk, dataPtr, mFlags); + if (seek < 0) + break; + } + + if (mFlags & FD_ENDIAN_SWAP) + { + mFlags &= ~FD_ENDIAN_SWAP; + } else + { + mFlags |= FD_ENDIAN_SWAP; + } + + + +} + + +// ----------------------------------------------------- // +char* bFile::readStruct(char *head, bChunkInd& dataChunk) +{ + bool ignoreEndianFlag = false; + + if (mFlags & FD_ENDIAN_SWAP) + swap(head, dataChunk, ignoreEndianFlag); + + + + if (!mFileDNA->flagEqual(dataChunk.dna_nr)) + { + // Ouch! need to rebuild the struct + short *oldStruct,*curStruct; + char *oldType, *newType; + int oldLen, curLen, reverseOld; + + + oldStruct = mFileDNA->getStruct(dataChunk.dna_nr); + oldType = mFileDNA->getType(oldStruct[0]); + + oldLen = mFileDNA->getLength(oldStruct[0]); + + if ((mFlags&FD_BROKEN_DNA)!=0) + { + if ((strcmp(oldType,"b3QuantizedBvhNodeData")==0)&&oldLen==20) + { + return 0; + } + if ((strcmp(oldType,"b3ShortIntIndexData")==0)) + { + int allocLen = 2; + char *dataAlloc = new char[(dataChunk.nr*allocLen)+1]; + memset(dataAlloc, 0, (dataChunk.nr*allocLen)+1); + short* dest = (short*) dataAlloc; + const short* src = (short*) head; + for (int i=0;igetReverseType(oldType); + + if ((reverseOld!=-1)) + { + // make sure it's here + //assert(reverseOld!= -1 && "getReverseType() returned -1, struct required!"); + + // + curStruct = mMemoryDNA->getStruct(reverseOld); + newType = mMemoryDNA->getType(curStruct[0]); + curLen = mMemoryDNA->getLength(curStruct[0]); + + + + // make sure it's the same + assert((strcmp(oldType, newType)==0) && "internal error, struct mismatch!"); + + + // numBlocks * length + + int allocLen = (curLen); + char *dataAlloc = new char[(dataChunk.nr*allocLen)+1]; + memset(dataAlloc, 0, (dataChunk.nr*allocLen)); + + // track allocated + addDataBlock(dataAlloc); + + char *cur = dataAlloc; + char *old = head; + for (int block=0; blockgetStruct(dataChunk.dna_nr); + oldType = mFileDNA->getType(oldStruct[0]); + printf("%s equal structure, just memcpy\n",oldType); +#endif // + } + + + char *dataAlloc = new char[(dataChunk.len)+1]; + memset(dataAlloc, 0, dataChunk.len+1); + + + // track allocated + addDataBlock(dataAlloc); + + memcpy(dataAlloc, head, dataChunk.len); + return dataAlloc; + +} + + +// ----------------------------------------------------- // +void bFile::parseStruct(char *strcPtr, char *dtPtr, int old_dna, int new_dna, bool fixupPointers) +{ + if (old_dna == -1) return; + if (new_dna == -1) return; + + //disable this, because we need to fixup pointers/ListBase + if (0)//mFileDNA->flagEqual(old_dna)) + { + short *strc = mFileDNA->getStruct(old_dna); + int len = mFileDNA->getLength(strc[0]); + + memcpy(strcPtr, dtPtr, len); + return; + } + + // Ok, now build the struct + char *memType, *memName, *cpc, *cpo; + short *fileStruct, *filePtrOld, *memoryStruct, *firstStruct; + int elementLength, size, revType, old_nr, new_nr, fpLen; + short firstStructType; + + + // File to memory lookup + memoryStruct = mMemoryDNA->getStruct(new_dna); + fileStruct = mFileDNA->getStruct(old_dna); + firstStruct = fileStruct; + + + filePtrOld = fileStruct; + firstStructType = mMemoryDNA->getStruct(0)[0]; + + // Get number of elements + elementLength = memoryStruct[1]; + memoryStruct+=2; + + cpc = strcPtr; cpo = 0; + for (int ele=0; elegetType(memoryStruct[0]); + memName = mMemoryDNA->getName(memoryStruct[1]); + + + size = mMemoryDNA->getElementSize(memoryStruct[0], memoryStruct[1]); + revType = mMemoryDNA->getReverseType(memoryStruct[0]); + + if (revType != -1 && memoryStruct[0]>=firstStructType && memName[0] != '*') + { + cpo = getFileElement(firstStruct, memName, memType, dtPtr, &filePtrOld); + if (cpo) + { + int arrayLen = mFileDNA->getArraySizeNew(filePtrOld[1]); + old_nr = mFileDNA->getReverseType(memType); + new_nr = revType; + fpLen = mFileDNA->getElementSize(filePtrOld[0], filePtrOld[1]); + if (arrayLen==1) + { + parseStruct(cpc, cpo, old_nr, new_nr,fixupPointers); + } else + { + char* tmpCpc = cpc; + char* tmpCpo = cpo; + + for (int i=0;i3 && type <8) + { + char c; + char *cp = data; + for (int i=0; igetPointerSize(); + int ptrMem = mMemoryDNA->getPointerSize(); + + if (!src && !dst) + return; + + + if (ptrFile == ptrMem) + { + memcpy(dst, src, ptrMem); + } + else if (ptrMem==4 && ptrFile==8) + { + b3PointerUid* oldPtr = (b3PointerUid*)src; + b3PointerUid* newPtr = (b3PointerUid*)dst; + + if (oldPtr->m_uniqueIds[0] == oldPtr->m_uniqueIds[1]) + { + //Bullet stores the 32bit unique ID in both upper and lower part of 64bit pointers + //so it can be used to distinguish between .blend and .bullet + newPtr->m_uniqueIds[0] = oldPtr->m_uniqueIds[0]; + } else + { + //deal with pointers the Blender .blend style way, see + //readfile.c in the Blender source tree + b3Long64 longValue = *((b3Long64*)src); + //endian swap for 64bit pointer otherwise truncation will fail due to trailing zeros + if (mFlags & FD_ENDIAN_SWAP) + B3_SWITCH_LONGINT(longValue); + *((int*)dst) = (int)(longValue>>3); + } + + } + else if (ptrMem==8 && ptrFile==4) + { + b3PointerUid* oldPtr = (b3PointerUid*)src; + b3PointerUid* newPtr = (b3PointerUid*)dst; + if (oldPtr->m_uniqueIds[0] == oldPtr->m_uniqueIds[1]) + { + newPtr->m_uniqueIds[0] = oldPtr->m_uniqueIds[0]; + newPtr->m_uniqueIds[1] = 0; + } else + { + *((b3Long64*)dst)= *((int*)src); + } + } + else + { + printf ("%d %d\n", ptrFile,ptrMem); + assert(0 && "Invalid pointer len"); + } + + +} + + +// ----------------------------------------------------- // +void bFile::getMatchingFileDNA(short* dna_addr, const char* lookupName, const char* lookupType, char *strcData, char *data, bool fixupPointers) +{ + // find the matching memory dna data + // to the file being loaded. Fill the + // memory with the file data... + + int len = dna_addr[1]; + dna_addr+=2; + + for (int i=0; igetType(dna_addr[0]); + const char* name = mFileDNA->getName(dna_addr[1]); + + + + int eleLen = mFileDNA->getElementSize(dna_addr[0], dna_addr[1]); + + if ((mFlags&FD_BROKEN_DNA)!=0) + { + if ((strcmp(type,"short")==0)&&(strcmp(name,"int")==0)) + { + eleLen = 0; + } + } + + if (strcmp(lookupName, name)==0) + { + //int arrayLenold = mFileDNA->getArraySize((char*)name.c_str()); + int arrayLen = mFileDNA->getArraySizeNew(dna_addr[1]); + //assert(arrayLenold == arrayLen); + + if (name[0] == '*') + { + // cast pointers + int ptrFile = mFileDNA->getPointerSize(); + int ptrMem = mMemoryDNA->getPointerSize(); + safeSwapPtr(strcData,data); + + if (fixupPointers) + { + if (arrayLen > 1) + { + //void **sarray = (void**)strcData; + //void **darray = (void**)data; + + char *cpc, *cpo; + cpc = (char*)strcData; + cpo = (char*)data; + + for (int a=0; agetStruct(old_nr); + int elementLength = old[1]; + old+=2; + + for (int i=0; igetType(old[0]); + char* name = mFileDNA->getName(old[1]); + int len = mFileDNA->getElementSize(old[0], old[1]); + + if (strcmp(lookupName, name)==0) + { + if (strcmp(type, lookupType)==0) + { + if (foundPos) + *foundPos = old; + return data; + } + return 0; + } + data+=len; + } + return 0; +} + + +// ----------------------------------------------------- // +void bFile::swapStruct(int dna_nr, char *data,bool ignoreEndianFlag) +{ + if (dna_nr == -1) return; + + short *strc = mFileDNA->getStruct(dna_nr); + //short *firstStrc = strc; + + int elementLen= strc[1]; + strc+=2; + + short first = mFileDNA->getStruct(0)[0]; + + char *buf = data; + for (int i=0; igetType(strc[0]); + char *name = mFileDNA->getName(strc[1]); + + int size = mFileDNA->getElementSize(strc[0], strc[1]); + if (strc[0] >= first && name[0]!='*') + { + int old_nr = mFileDNA->getReverseType(type); + int arrayLen = mFileDNA->getArraySizeNew(strc[1]); + if (arrayLen==1) + { + swapStruct(old_nr,buf,ignoreEndianFlag); + } else + { + char* tmpBuf = buf; + for (int i=0;igetArraySize(name); + int arrayLen = mFileDNA->getArraySizeNew(strc[1]); + //assert(arrayLenOld == arrayLen); + swapData(buf, strc[0], arrayLen,ignoreEndianFlag); + } + buf+=size; + } +} + +void bFile::resolvePointersMismatch() +{ +// printf("resolvePointersStructMismatch\n"); + + int i; + + for (i=0;i< m_pointerFixupArray.size();i++) + { + char* cur = m_pointerFixupArray.at(i); + void** ptrptr = (void**) cur; + void* ptr = *ptrptr; + ptr = findLibPointer(ptr); + if (ptr) + { + //printf("Fixup pointer!\n"); + *(ptrptr) = ptr; + } else + { +// printf("pointer not found: %x\n",cur); + } + } + + + for (i=0; igetPointerSize(); + int ptrFile = mFileDNA->getPointerSize(); + + + int blockLen = block->len / ptrFile; + + void *onptr = findLibPointer(*ptrptr); + if (onptr) + { + char *newPtr = new char[blockLen * ptrMem]; + addDataBlock(newPtr); + memset(newPtr, 0, blockLen * ptrMem); + + void **onarray = (void**)onptr; + char *oldPtr = (char*)onarray; + + int p = 0; + while (blockLen-- > 0) + { + b3PointerUid dp = {{0}}; + safeSwapPtr((char*)dp.m_uniqueIds, oldPtr); + + void **tptr = (void**)(newPtr + p * ptrMem); + *tptr = findLibPointer(dp.m_ptr); + + oldPtr += ptrFile; + ++p; + } + + *ptrptr = newPtr; + } + } + } +} + + +///this loop only works fine if the Blender DNA structure of the file matches the headerfiles +void bFile::resolvePointersChunk(const bChunkInd& dataChunk, int verboseMode) +{ + bParse::bDNA* fileDna = mFileDNA ? mFileDNA : mMemoryDNA; + + short int* oldStruct = fileDna->getStruct(dataChunk.dna_nr); + short oldLen = fileDna->getLength(oldStruct[0]); + //char* structType = fileDna->getType(oldStruct[0]); + + char* cur = (char*)findLibPointer(dataChunk.oldPtr); + for (int block=0; blockgetStruct(0)[0]; + + + char* elemPtr= strcPtr; + + short int* oldStruct = fileDna->getStruct(dna_nr); + + int elementLength = oldStruct[1]; + oldStruct+=2; + + int totalSize = 0; + + for (int ele=0; elegetType(oldStruct[0]); + memName = fileDna->getName(oldStruct[1]); + + + + int arrayLen = fileDna->getArraySizeNew(oldStruct[1]); + if (memName[0] == '*') + { + if (arrayLen > 1) + { + void **array= (void**)elemPtr; + for (int a=0; a ",&memName[1]); + printf("%p ", array[a]); + printf("\n",&memName[1]); + } + + array[a] = findLibPointer(array[a]); + } + } + else + { + void** ptrptr = (void**) elemPtr; + void* ptr = *ptrptr; + if (verboseMode & FD_VERBOSE_EXPORT_XML) + { + for (int i=0;i ",&memName[1]); + printf("%p ", ptr); + printf("\n",&memName[1]); + } + ptr = findLibPointer(ptr); + + if (ptr) + { + // printf("Fixup pointer at 0x%x from 0x%x to 0x%x!\n",ptrptr,*ptrptr,ptr); + *(ptrptr) = ptr; + if (memName[1] == '*' && ptrptr && *ptrptr) + { + // This will only work if the given **array is continuous + void **array= (void**)*(ptrptr); + void *np= array[0]; + int n=0; + while (np) + { + np= findLibPointer(array[n]); + if (np) array[n]= np; + n++; + } + } + } else + { + // printf("Cannot fixup pointer at 0x%x from 0x%x to 0x%x!\n",ptrptr,*ptrptr,ptr); + } + } + } else + { + int revType = fileDna->getReverseType(oldStruct[0]); + if (oldStruct[0]>=firstStructType) //revType != -1 && + { + char cleanName[MAX_STRLEN]; + getCleanName(memName,cleanName); + + int arrayLen = fileDna->getArraySizeNew(oldStruct[1]); + int byteOffset = 0; + + if (verboseMode & FD_VERBOSE_EXPORT_XML) + { + for (int i=0;i1) + { + printf("<%s type=\"%s\" count=%d>\n",cleanName,memType, arrayLen); + } else + { + printf("<%s type=\"%s\">\n",cleanName,memType); + } + } + + for (int i=0;i\n",cleanName); + } + } else + { + //export a simple type + if (verboseMode & FD_VERBOSE_EXPORT_XML) + { + + if (arrayLen>MAX_ARRAY_LENGTH) + { + printf("too long\n"); + } else + { + //printf("%s %s\n",memType,memName); + + bool isIntegerType = (strcmp(memType,"char")==0) || (strcmp(memType,"int")==0) || (strcmp(memType,"short")==0); + + if (isIntegerType) + { + const char* newtype="int"; + int dbarray[MAX_ARRAY_LENGTH]; + int* dbPtr = 0; + char* tmp = elemPtr; + dbPtr = &dbarray[0]; + if (dbPtr) + { + char cleanName[MAX_STRLEN]; + getCleanName(memName,cleanName); + + int i; + getElement(arrayLen, newtype,memType, tmp, (char*)dbPtr); + for (i=0;i",cleanName,memType); + else + printf("<%s type=\"%s\" count=%d>",cleanName,memType,arrayLen); + for (i=0;i\n",cleanName); + } + } else + { + const char* newtype="double"; + double dbarray[MAX_ARRAY_LENGTH]; + double* dbPtr = 0; + char* tmp = elemPtr; + dbPtr = &dbarray[0]; + if (dbPtr) + { + int i; + getElement(arrayLen, newtype,memType, tmp, (char*)dbPtr); + for (i=0;i",memName,memType); + } + else + { + printf("<%s type=\"%s\" count=%d>",cleanName,memType,arrayLen); + } + for (i=0;i\n",cleanName); + } + } + } + + } + } + } + + int size = fileDna->getElementSize(oldStruct[0], oldStruct[1]); + totalSize += size; + elemPtr+=size; + + } + + return totalSize; +} + + +///Resolve pointers replaces the original pointers in structures, and linked lists by the new in-memory structures +void bFile::resolvePointers(int verboseMode) +{ + bParse::bDNA* fileDna = mFileDNA ? mFileDNA : mMemoryDNA; + + //char *dataPtr = mFileBuffer+mDataStart; + + if (1) //mFlags & (FD_BITS_VARIES | FD_VERSION_VARIES)) + { + resolvePointersMismatch(); + } + + { + + if (verboseMode & FD_VERBOSE_EXPORT_XML) + { + printf("\n"); + int numitems = m_chunks.size(); + printf("\n", b3GetVersion(), numitems); + } + for (int i=0;iflagEqual(dataChunk.dna_nr)) + { + //dataChunk.len + short int* oldStruct = fileDna->getStruct(dataChunk.dna_nr); + char* oldType = fileDna->getType(oldStruct[0]); + + if (verboseMode & FD_VERBOSE_EXPORT_XML) + printf(" <%s pointer=%p>\n",oldType,dataChunk.oldPtr); + + resolvePointersChunk(dataChunk, verboseMode); + + if (verboseMode & FD_VERBOSE_EXPORT_XML) + printf(" \n",oldType); + } else + { + //printf("skipping mStruct\n"); + } + } + if (verboseMode & FD_VERBOSE_EXPORT_XML) + { + printf("\n"); + } + } + + +} + + +// ----------------------------------------------------- // +void* bFile::findLibPointer(void *ptr) +{ + + bStructHandle** ptrptr = getLibPointers().find(ptr); + if (ptrptr) + return *ptrptr; + return 0; +} + + +void bFile::updateOldPointers() +{ + int i; + + for (i=0;igetStruct(dataChunk.dna_nr); + char* typeName = dna->getType(newStruct[0]); + printf("%3d: %s ",i,typeName); + + printf("code=%s ",codestr); + + printf("ptr=%p ",dataChunk.oldPtr); + printf("len=%d ",dataChunk.len); + printf("nr=%d ",dataChunk.nr); + if (dataChunk.nr!=1) + { + printf("not 1\n"); + } + printf("\n"); + + + + + } + +#if 0 + IDFinderData ifd; + ifd.success = 0; + ifd.IDname = NULL; + ifd.just_print_it = 1; + for (i=0; im_blocks.size(); ++i) + { + BlendBlock* bb = bf->m_blocks[i]; + printf("tag='%s'\tptr=%p\ttype=%s\t[%4d]", bb->tag, bb,bf->types[bb->type_index].name,bb->m_array_entries_.size()); + block_ID_finder(bb, bf, &ifd); + printf("\n"); + } +#endif + +} + + +void bFile::writeChunks(FILE* fp, bool fixupPointers) +{ + bParse::bDNA* fileDna = mFileDNA ? mFileDNA : mMemoryDNA; + + for (int i=0;igetStruct(dataChunk.dna_nr); + oldType = fileDna->getType(oldStruct[0]); + oldLen = fileDna->getLength(oldStruct[0]); + ///don't try to convert Link block data, just memcpy it. Other data can be converted. + reverseOld = mMemoryDNA->getReverseType(oldType); + + + if ((reverseOld!=-1)) + { + // make sure it's here + //assert(reverseOld!= -1 && "getReverseType() returned -1, struct required!"); + // + curStruct = mMemoryDNA->getStruct(reverseOld); + newType = mMemoryDNA->getType(curStruct[0]); + // make sure it's the same + assert((strcmp(oldType, newType)==0) && "internal error, struct mismatch!"); + + + curLen = mMemoryDNA->getLength(curStruct[0]); + dataChunk.dna_nr = reverseOld; + if (strcmp("Link",oldType)!=0) + { + dataChunk.len = curLen * dataChunk.nr; + } else + { +// printf("keep length of link = %d\n",dataChunk.len); + } + + //write the structure header + fwrite(&dataChunk,sizeof(bChunkInd),1,fp); + + + + short int* curStruct1; + curStruct1 = mMemoryDNA->getStruct(dataChunk.dna_nr); + assert(curStruct1 == curStruct); + + char* cur = fixupPointers ? (char*)findLibPointer(dataChunk.oldPtr) : (char*)dataChunk.oldPtr; + + //write the actual contents of the structure(s) + fwrite(cur,dataChunk.len,1,fp); + } else + { + printf("serious error, struct mismatch: don't write\n"); + } + } + +} + + +// ----------------------------------------------------- // +int bFile::getNextBlock(bChunkInd *dataChunk, const char *dataPtr, const int flags) +{ + bool swap = false; + bool varies = false; + + if (flags &FD_ENDIAN_SWAP) + swap = true; + if (flags &FD_BITS_VARIES) + varies = true; + + if (VOID_IS_8) + { + if (varies) + { + bChunkPtr4 head; + memcpy(&head, dataPtr, sizeof(bChunkPtr4)); + + + bChunkPtr8 chunk; + + chunk.code = head.code; + chunk.len = head.len; + chunk.m_uniqueInts[0] = head.m_uniqueInt; + chunk.m_uniqueInts[1] = 0; + chunk.dna_nr = head.dna_nr; + chunk.nr = head.nr; + + if (swap) + { + if ((chunk.code & 0xFFFF)==0) + chunk.code >>=16; + + B3_SWITCH_INT(chunk.len); + B3_SWITCH_INT(chunk.dna_nr); + B3_SWITCH_INT(chunk.nr); + } + + + memcpy(dataChunk, &chunk, sizeof(bChunkInd)); + } + else + { + bChunkPtr8 c; + memcpy(&c, dataPtr, sizeof(bChunkPtr8)); + + if (swap) + { + if ((c.code & 0xFFFF)==0) + c.code >>=16; + + B3_SWITCH_INT(c.len); + B3_SWITCH_INT(c.dna_nr); + B3_SWITCH_INT(c.nr); + } + + memcpy(dataChunk, &c, sizeof(bChunkInd)); + } + } + else + { + if (varies) + { + bChunkPtr8 head; + memcpy(&head, dataPtr, sizeof(bChunkPtr8)); + + + bChunkPtr4 chunk; + chunk.code = head.code; + chunk.len = head.len; + + if (head.m_uniqueInts[0]==head.m_uniqueInts[1]) + { + chunk.m_uniqueInt = head.m_uniqueInts[0]; + } else + { + b3Long64 oldPtr =0; + memcpy(&oldPtr, &head.m_uniqueInts[0], 8); + if (swap) + B3_SWITCH_LONGINT(oldPtr); + chunk.m_uniqueInt = (int)(oldPtr >> 3); + } + + + chunk.dna_nr = head.dna_nr; + chunk.nr = head.nr; + + if (swap) + { + if ((chunk.code & 0xFFFF)==0) + chunk.code >>=16; + + B3_SWITCH_INT(chunk.len); + B3_SWITCH_INT(chunk.dna_nr); + B3_SWITCH_INT(chunk.nr); + } + + memcpy(dataChunk, &chunk, sizeof(bChunkInd)); + } + else + { + bChunkPtr4 c; + memcpy(&c, dataPtr, sizeof(bChunkPtr4)); + + if (swap) + { + if ((c.code & 0xFFFF)==0) + c.code >>=16; + + B3_SWITCH_INT(c.len); + B3_SWITCH_INT(c.dna_nr); + B3_SWITCH_INT(c.nr); + } + memcpy(dataChunk, &c, sizeof(bChunkInd)); + } + } + + if (dataChunk->len < 0) + return -1; + +#if 0 + print ("----------"); + print (dataChunk->code); + print (dataChunk->len); + print (dataChunk->old); + print (dataChunk->dna_nr); + print (dataChunk->nr); +#endif + return (dataChunk->len+ChunkUtils::getOffset(flags)); +} + + + +//eof diff --git a/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3File.h b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3File.h new file mode 100644 index 000000000000..861056806d78 --- /dev/null +++ b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3File.h @@ -0,0 +1,165 @@ +/* +bParse +Copyright (c) 2006-2009 Charlie C & Erwin Coumans http://gamekit.googlecode.com + +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 __BFILE_H__ +#define __BFILE_H__ + +#include "b3Common.h" +#include "b3Chunk.h" +#include + +namespace bParse { + + // ----------------------------------------------------- // + enum bFileFlags + { + FD_INVALID =0, + FD_OK =1, + FD_VOID_IS_8 =2, + FD_ENDIAN_SWAP =4, + FD_FILE_64 =8, + FD_BITS_VARIES =16, + FD_VERSION_VARIES = 32, + FD_DOUBLE_PRECISION =64, + FD_BROKEN_DNA = 128 + }; + + enum bFileVerboseMode + { + FD_VERBOSE_EXPORT_XML = 1, + FD_VERBOSE_DUMP_DNA_TYPE_DEFINITIONS = 2, + FD_VERBOSE_DUMP_CHUNKS = 4, + FD_VERBOSE_DUMP_FILE_INFO=8, + }; + // ----------------------------------------------------- // + class bFile + { + protected: + + char m_headerString[7]; + + bool mOwnsBuffer; + char* mFileBuffer; + int mFileLen; + int mVersion; + + + bPtrMap mLibPointers; + + int mDataStart; + bDNA* mFileDNA; + bDNA* mMemoryDNA; + + b3AlignedObjectArray m_pointerFixupArray; + b3AlignedObjectArray m_pointerPtrFixupArray; + + b3AlignedObjectArray m_chunks; + b3HashMap m_chunkPtrPtrMap; + + // + + bPtrMap mDataPointers; + + + int mFlags; + + // //////////////////////////////////////////////////////////////////////////// + + // buffer offset util + int getNextBlock(bChunkInd *dataChunk, const char *dataPtr, const int flags); + void safeSwapPtr(char *dst, const char *src); + + virtual void parseHeader(); + + virtual void parseData() = 0; + + void resolvePointersMismatch(); + void resolvePointersChunk(const bChunkInd& dataChunk, int verboseMode); + + int resolvePointersStructRecursive(char *strcPtr, int old_dna, int verboseMode, int recursion); + //void swapPtr(char *dst, char *src); + + void parseStruct(char *strcPtr, char *dtPtr, int old_dna, int new_dna, bool fixupPointers); + void getMatchingFileDNA(short* old, const char* lookupName, const char* lookupType, char *strcData, char *data, bool fixupPointers); + char* getFileElement(short *firstStruct, char *lookupName, char *lookupType, char *data, short **foundPos); + + + void swap(char *head, class bChunkInd& ch, bool ignoreEndianFlag); + void swapData(char *data, short type, int arraySize, bool ignoreEndianFlag); + void swapStruct(int dna_nr, char *data, bool ignoreEndianFlag); + void swapLen(char *dataPtr); + void swapDNA(char* ptr); + + + char* readStruct(char *head, class bChunkInd& chunk); + char *getAsString(int code); + + void parseInternal(int verboseMode, char* memDna,int memDnaLength); + + public: + bFile(const char *filename, const char headerString[7]); + + //todo: make memoryBuffer const char + //bFile( const char *memoryBuffer, int len); + bFile( char *memoryBuffer, int len, const char headerString[7]); + virtual ~bFile(); + + bDNA* getFileDNA() + { + return mFileDNA; + } + + virtual void addDataBlock(char* dataBlock) = 0; + + int getFlags() const + { + return mFlags; + } + + bPtrMap& getLibPointers() + { + return mLibPointers; + } + + void* findLibPointer(void *ptr); + + bool ok(); + + virtual void parse(int verboseMode) = 0; + + virtual int write(const char* fileName, bool fixupPointers=false) = 0; + + virtual void writeChunks(FILE* fp, bool fixupPointers ); + + virtual void writeDNA(FILE* fp) = 0; + + void updateOldPointers(); + void resolvePointers(int verboseMode); + + void dumpChunks(bDNA* dna); + + int getVersion() const + { + return mVersion; + } + //pre-swap the endianness, so that data loaded on a target with different endianness doesn't need to be swapped + void preSwap(); + void writeFile(const char* fileName); + + }; +} + + +#endif//__BFILE_H__ diff --git a/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3Serializer.cpp b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3Serializer.cpp new file mode 100644 index 000000000000..c6a2a832ad96 --- /dev/null +++ b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3Serializer.cpp @@ -0,0 +1,908 @@ +char b3s_bulletDNAstr[]= { +char(83),char(68),char(78),char(65),char(78),char(65),char(77),char(69),char(63),char(1),char(0),char(0),char(109),char(95),char(115),char(105),char(122),char(101),char(0),char(109), +char(95),char(99),char(97),char(112),char(97),char(99),char(105),char(116),char(121),char(0),char(42),char(109),char(95),char(100),char(97),char(116),char(97),char(0),char(109),char(95), +char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(115),char(0),char(109),char(95),char(99),char(111), +char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(115),char(0),char(109),char(95),char(99),char(111),char(110), +char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(115),char(0),char(42),char(102),char(105),char(114),char(115),char(116),char(0),char(42),char(108),char(97),char(115), +char(116),char(0),char(109),char(95),char(102),char(108),char(111),char(97),char(116),char(115),char(91),char(52),char(93),char(0),char(109),char(95),char(101),char(108),char(91),char(51), +char(93),char(0),char(109),char(95),char(98),char(97),char(115),char(105),char(115),char(0),char(109),char(95),char(111),char(114),char(105),char(103),char(105),char(110),char(0),char(109), +char(95),char(114),char(111),char(111),char(116),char(78),char(111),char(100),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(115),char(117),char(98), +char(116),char(114),char(101),char(101),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100), +char(65),char(97),char(98),char(98),char(77),char(105),char(110),char(91),char(51),char(93),char(0),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122), +char(101),char(100),char(65),char(97),char(98),char(98),char(77),char(97),char(120),char(91),char(51),char(93),char(0),char(109),char(95),char(97),char(97),char(98),char(98),char(77), +char(105),char(110),char(79),char(114),char(103),char(0),char(109),char(95),char(97),char(97),char(98),char(98),char(77),char(97),char(120),char(79),char(114),char(103),char(0),char(109), +char(95),char(101),char(115),char(99),char(97),char(112),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(115),char(117),char(98),char(80),char(97), +char(114),char(116),char(0),char(109),char(95),char(116),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109), +char(95),char(112),char(97),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(101),char(115),char(99),char(97),char(112),char(101),char(73),char(110),char(100),char(101), +char(120),char(79),char(114),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(98), +char(118),char(104),char(65),char(97),char(98),char(98),char(77),char(105),char(110),char(0),char(109),char(95),char(98),char(118),char(104),char(65),char(97),char(98),char(98),char(77), +char(97),char(120),char(0),char(109),char(95),char(98),char(118),char(104),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(97),char(116),char(105),char(111),char(110), +char(0),char(109),char(95),char(99),char(117),char(114),char(78),char(111),char(100),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(117),char(115), +char(101),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(97),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(110),char(117),char(109),char(67), +char(111),char(110),char(116),char(105),char(103),char(117),char(111),char(117),char(115),char(76),char(101),char(97),char(102),char(78),char(111),char(100),char(101),char(115),char(0),char(109), +char(95),char(110),char(117),char(109),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(67),char(111),char(110),char(116),char(105),char(103),char(117), +char(111),char(117),char(115),char(78),char(111),char(100),char(101),char(115),char(0),char(42),char(109),char(95),char(99),char(111),char(110),char(116),char(105),char(103),char(117),char(111), +char(117),char(115),char(78),char(111),char(100),char(101),char(115),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105), +char(122),char(101),char(100),char(67),char(111),char(110),char(116),char(105),char(103),char(117),char(111),char(117),char(115),char(78),char(111),char(100),char(101),char(115),char(80),char(116), +char(114),char(0),char(42),char(109),char(95),char(115),char(117),char(98),char(84),char(114),char(101),char(101),char(73),char(110),char(102),char(111),char(80),char(116),char(114),char(0), +char(109),char(95),char(116),char(114),char(97),char(118),char(101),char(114),char(115),char(97),char(108),char(77),char(111),char(100),char(101),char(0),char(109),char(95),char(110),char(117), +char(109),char(83),char(117),char(98),char(116),char(114),char(101),char(101),char(72),char(101),char(97),char(100),char(101),char(114),char(115),char(0),char(42),char(109),char(95),char(110), +char(97),char(109),char(101),char(0),char(109),char(95),char(115),char(104),char(97),char(112),char(101),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(112),char(97), +char(100),char(100),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110), +char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(83),char(99),char(97), +char(108),char(105),char(110),char(103),char(0),char(109),char(95),char(112),char(108),char(97),char(110),char(101),char(78),char(111),char(114),char(109),char(97),char(108),char(0),char(109), +char(95),char(112),char(108),char(97),char(110),char(101),char(67),char(111),char(110),char(115),char(116),char(97),char(110),char(116),char(0),char(109),char(95),char(105),char(109),char(112), +char(108),char(105),char(99),char(105),char(116),char(83),char(104),char(97),char(112),char(101),char(68),char(105),char(109),char(101),char(110),char(115),char(105),char(111),char(110),char(115), +char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(77),char(97),char(114),char(103),char(105),char(110),char(0),char(109), +char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(0),char(109),char(95),char(112),char(111),char(115),char(0),char(109),char(95),char(114),char(97),char(100), +char(105),char(117),char(115),char(0),char(109),char(95),char(99),char(111),char(110),char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114),char(110),char(97),char(108), +char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(42),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(80),char(111), +char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(114),char(114),char(97),char(121),char(80),char(116),char(114),char(0),char(109),char(95),char(108),char(111),char(99), +char(97),char(108),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(114),char(114),char(97),char(121),char(83),char(105),char(122),char(101),char(0), +char(109),char(95),char(118),char(97),char(108),char(117),char(101),char(0),char(109),char(95),char(112),char(97),char(100),char(91),char(50),char(93),char(0),char(109),char(95),char(118), +char(97),char(108),char(117),char(101),char(115),char(91),char(51),char(93),char(0),char(109),char(95),char(112),char(97),char(100),char(0),char(42),char(109),char(95),char(118),char(101), +char(114),char(116),char(105),char(99),char(101),char(115),char(51),char(102),char(0),char(42),char(109),char(95),char(118),char(101),char(114),char(116),char(105),char(99),char(101),char(115), +char(51),char(100),char(0),char(42),char(109),char(95),char(105),char(110),char(100),char(105),char(99),char(101),char(115),char(51),char(50),char(0),char(42),char(109),char(95),char(51), +char(105),char(110),char(100),char(105),char(99),char(101),char(115),char(49),char(54),char(0),char(42),char(109),char(95),char(51),char(105),char(110),char(100),char(105),char(99),char(101), +char(115),char(56),char(0),char(42),char(109),char(95),char(105),char(110),char(100),char(105),char(99),char(101),char(115),char(49),char(54),char(0),char(109),char(95),char(110),char(117), +char(109),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(86),char(101),char(114),char(116), +char(105),char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(109),char(101),char(115),char(104),char(80),char(97),char(114),char(116),char(115),char(80),char(116),char(114), +char(0),char(109),char(95),char(115),char(99),char(97),char(108),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(101),char(115),char(104), +char(80),char(97),char(114),char(116),char(115),char(0),char(109),char(95),char(109),char(101),char(115),char(104),char(73),char(110),char(116),char(101),char(114),char(102),char(97),char(99), +char(101),char(0),char(42),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(70),char(108),char(111),char(97),char(116),char(66), +char(118),char(104),char(0),char(42),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(68),char(111),char(117),char(98),char(108), +char(101),char(66),char(118),char(104),char(0),char(42),char(109),char(95),char(116),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111), +char(77),char(97),char(112),char(0),char(109),char(95),char(112),char(97),char(100),char(51),char(91),char(52),char(93),char(0),char(109),char(95),char(116),char(114),char(105),char(109), +char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(116),char(114),char(97),char(110),char(115), +char(102),char(111),char(114),char(109),char(0),char(42),char(109),char(95),char(99),char(104),char(105),char(108),char(100),char(83),char(104),char(97),char(112),char(101),char(0),char(109), +char(95),char(99),char(104),char(105),char(108),char(100),char(83),char(104),char(97),char(112),char(101),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(99),char(104), +char(105),char(108),char(100),char(77),char(97),char(114),char(103),char(105),char(110),char(0),char(42),char(109),char(95),char(99),char(104),char(105),char(108),char(100),char(83),char(104), +char(97),char(112),char(101),char(80),char(116),char(114),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(104),char(105),char(108),char(100),char(83),char(104),char(97), +char(112),char(101),char(115),char(0),char(109),char(95),char(117),char(112),char(65),char(120),char(105),char(115),char(0),char(109),char(95),char(102),char(108),char(97),char(103),char(115), +char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(86),char(48),char(86),char(49),char(65),char(110),char(103),char(108),char(101),char(0),char(109),char(95),char(101), +char(100),char(103),char(101),char(86),char(49),char(86),char(50),char(65),char(110),char(103),char(108),char(101),char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(86), +char(50),char(86),char(48),char(65),char(110),char(103),char(108),char(101),char(0),char(42),char(109),char(95),char(104),char(97),char(115),char(104),char(84),char(97),char(98),char(108), +char(101),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(110),char(101),char(120),char(116),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(118), +char(97),char(108),char(117),char(101),char(65),char(114),char(114),char(97),char(121),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(107),char(101),char(121),char(65), +char(114),char(114),char(97),char(121),char(80),char(116),char(114),char(0),char(109),char(95),char(99),char(111),char(110),char(118),char(101),char(120),char(69),char(112),char(115),char(105), +char(108),char(111),char(110),char(0),char(109),char(95),char(112),char(108),char(97),char(110),char(97),char(114),char(69),char(112),char(115),char(105),char(108),char(111),char(110),char(0), +char(109),char(95),char(101),char(113),char(117),char(97),char(108),char(86),char(101),char(114),char(116),char(101),char(120),char(84),char(104),char(114),char(101),char(115),char(104),char(111), +char(108),char(100),char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(68),char(105),char(115),char(116),char(97),char(110),char(99),char(101),char(84),char(104),char(114), +char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(122),char(101),char(114),char(111),char(65),char(114),char(101),char(97),char(84),char(104),char(114), +char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(110),char(101),char(120),char(116),char(83),char(105),char(122),char(101),char(0),char(109),char(95), +char(104),char(97),char(115),char(104),char(84),char(97),char(98),char(108),char(101),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(110),char(117),char(109),char(86), +char(97),char(108),char(117),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(75),char(101),char(121),char(115),char(0),char(109),char(95),char(103),char(105), +char(109),char(112),char(97),char(99),char(116),char(83),char(117),char(98),char(84),char(121),char(112),char(101),char(0),char(42),char(109),char(95),char(117),char(110),char(115),char(99), +char(97),char(108),char(101),char(100),char(80),char(111),char(105),char(110),char(116),char(115),char(70),char(108),char(111),char(97),char(116),char(80),char(116),char(114),char(0),char(42), +char(109),char(95),char(117),char(110),char(115),char(99),char(97),char(108),char(101),char(100),char(80),char(111),char(105),char(110),char(116),char(115),char(68),char(111),char(117),char(98), +char(108),char(101),char(80),char(116),char(114),char(0),char(109),char(95),char(110),char(117),char(109),char(85),char(110),char(115),char(99),char(97),char(108),char(101),char(100),char(80), +char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(51),char(91),char(52),char(93),char(0), +char(42),char(109),char(95),char(98),char(114),char(111),char(97),char(100),char(112),char(104),char(97),char(115),char(101),char(72),char(97),char(110),char(100),char(108),char(101),char(0), +char(42),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(0),char(42),char(109), +char(95),char(114),char(111),char(111),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(0), +char(109),char(95),char(119),char(111),char(114),char(108),char(100),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(105), +char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105),char(111),char(110),char(87),char(111),char(114),char(108),char(100),char(84),char(114),char(97), +char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105), +char(111),char(110),char(76),char(105),char(110),char(101),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(105), +char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105),char(111),char(110),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(86), +char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(105),char(115),char(111),char(116),char(114),char(111),char(112),char(105), +char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(99),char(116),char(80), +char(114),char(111),char(99),char(101),char(115),char(115),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109), +char(95),char(100),char(101),char(97),char(99),char(116),char(105),char(118),char(97),char(116),char(105),char(111),char(110),char(84),char(105),char(109),char(101),char(0),char(109),char(95), +char(102),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(114),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114), +char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(105),char(116),char(117),char(116),char(105),char(111),char(110), +char(0),char(109),char(95),char(104),char(105),char(116),char(70),char(114),char(97),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(99),char(100), +char(83),char(119),char(101),char(112),char(116),char(83),char(112),char(104),char(101),char(114),char(101),char(82),char(97),char(100),char(105),char(117),char(115),char(0),char(109),char(95), +char(99),char(99),char(100),char(77),char(111),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109), +char(95),char(104),char(97),char(115),char(65),char(110),char(105),char(115),char(111),char(116),char(114),char(111),char(112),char(105),char(99),char(70),char(114),char(105),char(99),char(116), +char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(70),char(108),char(97),char(103),char(115), +char(0),char(109),char(95),char(105),char(115),char(108),char(97),char(110),char(100),char(84),char(97),char(103),char(49),char(0),char(109),char(95),char(99),char(111),char(109),char(112), +char(97),char(110),char(105),char(111),char(110),char(73),char(100),char(0),char(109),char(95),char(97),char(99),char(116),char(105),char(118),char(97),char(116),char(105),char(111),char(110), +char(83),char(116),char(97),char(116),char(101),char(49),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(84),char(121),char(112), +char(101),char(0),char(109),char(95),char(99),char(104),char(101),char(99),char(107),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(87),char(105),char(116),char(104), +char(0),char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(0),char(109),char(95),char(103),char(114),char(97),char(118), +char(105),char(116),char(121),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99), +char(116),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(84),char(101), +char(110),char(115),char(111),char(114),char(87),char(111),char(114),char(108),char(100),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(86),char(101), +char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111), +char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114), +char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(103),char(114), +char(97),char(118),char(105),char(116),char(121),char(95),char(97),char(99),char(99),char(101),char(108),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(0),char(109), +char(95),char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(76),char(111),char(99),char(97),char(108),char(0),char(109),char(95),char(116), +char(111),char(116),char(97),char(108),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(116),char(111),char(116),char(97),char(108),char(84),char(111),char(114), +char(113),char(117),char(101),char(0),char(109),char(95),char(105),char(110),char(118),char(101),char(114),char(115),char(101),char(77),char(97),char(115),char(115),char(0),char(109),char(95), +char(108),char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117), +char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111), +char(110),char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(97), +char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(76),char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105), +char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100), +char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110), +char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105), +char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103), +char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(101),char(101),char(112), +char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108), +char(97),char(114),char(83),char(108),char(101),char(101),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0), +char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0), +char(109),char(95),char(110),char(117),char(109),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(82),char(111),char(119),char(115),char(0), +char(110),char(117),char(98),char(0),char(42),char(109),char(95),char(114),char(98),char(65),char(0),char(42),char(109),char(95),char(114),char(98),char(66),char(0),char(109),char(95), +char(111),char(98),char(106),char(101),char(99),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110), +char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111), +char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(100),char(0),char(109),char(95),char(110),char(101),char(101),char(100),char(115),char(70),char(101), +char(101),char(100),char(98),char(97),char(99),char(107),char(0),char(109),char(95),char(97),char(112),char(112),char(108),char(105),char(101),char(100),char(73),char(109),char(112),char(117), +char(108),char(115),char(101),char(0),char(109),char(95),char(100),char(98),char(103),char(68),char(114),char(97),char(119),char(83),char(105),char(122),char(101),char(0),char(109),char(95), +char(100),char(105),char(115),char(97),char(98),char(108),char(101),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(115),char(66),char(101),char(116), +char(119),char(101),char(101),char(110),char(76),char(105),char(110),char(107),char(101),char(100),char(66),char(111),char(100),char(105),char(101),char(115),char(0),char(109),char(95),char(111), +char(118),char(101),char(114),char(114),char(105),char(100),char(101),char(78),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(116),char(101),char(114), +char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(98),char(114),char(101),char(97),char(107),char(105),char(110),char(103),char(73),char(109),char(112), +char(117),char(108),char(115),char(101),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(105),char(115),char(69),char(110), +char(97),char(98),char(108),char(101),char(100),char(0),char(109),char(95),char(116),char(121),char(112),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), +char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(112),char(105),char(118),char(111),char(116),char(73),char(110),char(65),char(0),char(109),char(95), +char(112),char(105),char(118),char(111),char(116),char(73),char(110),char(66),char(0),char(109),char(95),char(114),char(98),char(65),char(70),char(114),char(97),char(109),char(101),char(0), +char(109),char(95),char(114),char(98),char(66),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(82),char(101),char(102),char(101), +char(114),char(101),char(110),char(99),char(101),char(70),char(114),char(97),char(109),char(101),char(65),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97), +char(114),char(79),char(110),char(108),char(121),char(0),char(109),char(95),char(101),char(110),char(97),char(98),char(108),char(101),char(65),char(110),char(103),char(117),char(108),char(97), +char(114),char(77),char(111),char(116),char(111),char(114),char(0),char(109),char(95),char(109),char(111),char(116),char(111),char(114),char(84),char(97),char(114),char(103),char(101),char(116), +char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(109),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(73), +char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(108),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0), +char(109),char(95),char(117),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(108),char(105),char(109),char(105),char(116), +char(83),char(111),char(102),char(116),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(98),char(105),char(97),char(115),char(70),char(97),char(99),char(116),char(111), +char(114),char(0),char(109),char(95),char(114),char(101),char(108),char(97),char(120),char(97),char(116),char(105),char(111),char(110),char(70),char(97),char(99),char(116),char(111),char(114), +char(0),char(109),char(95),char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(49),char(0),char(109),char(95),char(115),char(119),char(105),char(110), +char(103),char(83),char(112),char(97),char(110),char(50),char(0),char(109),char(95),char(116),char(119),char(105),char(115),char(116),char(83),char(112),char(97),char(110),char(0),char(109), +char(95),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(85),char(112),char(112), +char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(76),char(111),char(119),char(101), +char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(85),char(112),char(112),char(101), +char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(76),char(111),char(119),char(101), +char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(117),char(115),char(101),char(76),char(105),char(110),char(101),char(97),char(114),char(82),char(101), +char(102),char(101),char(114),char(101),char(110),char(99),char(101),char(70),char(114),char(97),char(109),char(101),char(65),char(0),char(109),char(95),char(117),char(115),char(101),char(79), +char(102),char(102),char(115),char(101),char(116),char(70),char(111),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(114), +char(97),char(109),char(101),char(0),char(109),char(95),char(54),char(100),char(111),char(102),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(115),char(112),char(114), +char(105),char(110),char(103),char(69),char(110),char(97),char(98),char(108),char(101),char(100),char(91),char(54),char(93),char(0),char(109),char(95),char(101),char(113),char(117),char(105), +char(108),char(105),char(98),char(114),char(105),char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112), +char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(91),char(54),char(93),char(0),char(109),char(95),char(115), +char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(91),char(54),char(93),char(0),char(109),char(95),char(116),char(97), +char(117),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(116),char(101),char(112),char(0),char(109),char(95),char(109),char(97),char(120),char(69),char(114), +char(114),char(111),char(114),char(82),char(101),char(100),char(117),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(115),char(111),char(114),char(0),char(109), +char(95),char(101),char(114),char(112),char(0),char(109),char(95),char(101),char(114),char(112),char(50),char(0),char(109),char(95),char(103),char(108),char(111),char(98),char(97),char(108), +char(67),char(102),char(109),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(80),char(101), +char(110),char(101),char(116),char(114),char(97),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109), +char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(84),char(117),char(114),char(110),char(69),char(114),char(112), +char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(111),char(112),char(0),char(109),char(95),char(119),char(97),char(114),char(109), +char(115),char(116),char(97),char(114),char(116),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(109),char(97),char(120), +char(71),char(121),char(114),char(111),char(115),char(99),char(111),char(112),char(105),char(99),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(115),char(105), +char(110),char(103),char(108),char(101),char(65),char(120),char(105),char(115),char(82),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99),char(116), +char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(110),char(117),char(109),char(73),char(116), +char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(77),char(111),char(100), +char(101),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(105),char(110),char(103),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(82),char(101), +char(115),char(116),char(105),char(116),char(117),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109), +char(95),char(109),char(105),char(110),char(105),char(109),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(66),char(97),char(116),char(99),char(104),char(83), +char(105),char(122),char(101),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109), +char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97), +char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(118),char(111), +char(108),char(117),char(109),char(101),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(116), +char(101),char(114),char(105),char(97),char(108),char(0),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(112), +char(114),char(101),char(118),char(105),char(111),char(117),char(115),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(118),char(101), +char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(99),char(99),char(117),char(109),char(117),char(108),char(97),char(116),char(101),char(100), +char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(110),char(111),char(114),char(109),char(97),char(108),char(0),char(109),char(95),char(97),char(114),char(101), +char(97),char(0),char(109),char(95),char(97),char(116),char(116),char(97),char(99),char(104),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100), +char(105),char(99),char(101),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(76),char(101),char(110),char(103),char(116),char(104), +char(0),char(109),char(95),char(98),char(98),char(101),char(110),char(100),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110), +char(100),char(105),char(99),char(101),char(115),char(91),char(51),char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(65),char(114),char(101),char(97),char(0), +char(109),char(95),char(99),char(48),char(91),char(52),char(93),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101), +char(115),char(91),char(52),char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95), +char(99),char(49),char(0),char(109),char(95),char(99),char(50),char(0),char(109),char(95),char(99),char(48),char(0),char(109),char(95),char(108),char(111),char(99),char(97),char(108), +char(70),char(114),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(114),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(0),char(109), +char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(97),char(101),char(114),char(111),char(77),char(111),char(100), +char(101),char(108),char(0),char(109),char(95),char(98),char(97),char(117),char(109),char(103),char(97),char(114),char(116),char(101),char(0),char(109),char(95),char(100),char(114),char(97), +char(103),char(0),char(109),char(95),char(108),char(105),char(102),char(116),char(0),char(109),char(95),char(112),char(114),char(101),char(115),char(115),char(117),char(114),char(101),char(0), +char(109),char(95),char(118),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(100),char(121),char(110),char(97),char(109),char(105),char(99),char(70),char(114), +char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(112),char(111),char(115),char(101),char(77),char(97),char(116),char(99),char(104),char(0),char(109), +char(95),char(114),char(105),char(103),char(105),char(100),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115), +char(115),char(0),char(109),char(95),char(107),char(105),char(110),char(101),char(116),char(105),char(99),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97), +char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116), +char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114),char(72),char(97),char(114), +char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117), +char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75), +char(105),char(110),char(101),char(116),char(105),char(99),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115), +char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72), +char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67), +char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109), +char(95),char(115),char(111),char(102),char(116),char(75),char(105),char(110),char(101),char(116),char(105),char(99),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73), +char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(83),char(111), +char(102),char(116),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105), +char(116),char(0),char(109),char(95),char(109),char(97),char(120),char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(116),char(105),char(109),char(101), +char(83),char(99),char(97),char(108),char(101),char(0),char(109),char(95),char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(73),char(116),char(101),char(114), +char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(73),char(116),char(101), +char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(100),char(114),char(105),char(102),char(116),char(73),char(116),char(101),char(114),char(97), +char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(116),char(101),char(114),char(97), +char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(114),char(111),char(116),char(0),char(109),char(95),char(115),char(99),char(97),char(108),char(101),char(0), +char(109),char(95),char(97),char(113),char(113),char(0),char(109),char(95),char(99),char(111),char(109),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(105),char(116), +char(105),char(111),char(110),char(115),char(0),char(42),char(109),char(95),char(119),char(101),char(105),char(103),char(104),char(116),char(115),char(0),char(109),char(95),char(110),char(117), +char(109),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(87),char(101),char(105),char(103), +char(116),char(115),char(0),char(109),char(95),char(98),char(118),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(98),char(102),char(114),char(97),char(109), +char(101),char(0),char(109),char(95),char(102),char(114),char(97),char(109),char(101),char(120),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(108),char(111),char(99), +char(105),char(105),char(0),char(109),char(95),char(105),char(110),char(118),char(119),char(105),char(0),char(109),char(95),char(118),char(105),char(109),char(112),char(117),char(108),char(115), +char(101),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(100),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93), +char(0),char(109),char(95),char(108),char(118),char(0),char(109),char(95),char(97),char(118),char(0),char(42),char(109),char(95),char(102),char(114),char(97),char(109),char(101),char(114), +char(101),char(102),char(115),char(0),char(42),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(0),char(42), +char(109),char(95),char(109),char(97),char(115),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(114),char(97),char(109),char(101),char(82), +char(101),char(102),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(78),char(111),char(100),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109), +char(77),char(97),char(115),char(115),char(101),char(115),char(0),char(109),char(95),char(105),char(100),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(105),char(109), +char(97),char(115),char(115),char(0),char(109),char(95),char(110),char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(0),char(109),char(95),char(110), +char(100),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(97),char(109),char(112),char(105),char(110),char(103), +char(0),char(109),char(95),char(108),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(97),char(109),char(112),char(105), +char(110),char(103),char(0),char(109),char(95),char(109),char(97),char(116),char(99),char(104),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97),char(120),char(83), +char(101),char(108),char(102),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0), +char(109),char(95),char(115),char(101),char(108),char(102),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108), +char(115),char(101),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(105),char(110),char(115),char(65), +char(110),char(99),char(104),char(111),char(114),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(100),char(101),char(0),char(109),char(95),char(99),char(108), +char(117),char(115),char(116),char(101),char(114),char(73),char(110),char(100),char(101),char(120),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(0), +char(42),char(109),char(95),char(98),char(111),char(100),char(121),char(66),char(0),char(109),char(95),char(114),char(101),char(102),char(115),char(91),char(50),char(93),char(0),char(109), +char(95),char(99),char(102),char(109),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(100),char(101),char(108),char(101),char(116), +char(101),char(0),char(109),char(95),char(114),char(101),char(108),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(91),char(50),char(93),char(0),char(109), +char(95),char(98),char(111),char(100),char(121),char(65),char(116),char(121),char(112),char(101),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(66),char(116),char(121), +char(112),char(101),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(42),char(109),char(95),char(112),char(111), +char(115),char(101),char(0),char(42),char(42),char(109),char(95),char(109),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(42),char(109),char(95), +char(110),char(111),char(100),char(101),char(115),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(115),char(0),char(42),char(109),char(95),char(102),char(97), +char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(116),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(42),char(109), +char(95),char(97),char(110),char(99),char(104),char(111),char(114),char(115),char(0),char(42),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(115), +char(0),char(42),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(116),char(101), +char(114),char(105),char(97),char(108),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(76),char(105),char(110),char(107),char(115),char(0),char(109),char(95),char(110), +char(117),char(109),char(70),char(97),char(99),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(84),char(101),char(116),char(114),char(97),char(104),char(101), +char(100),char(114),char(97),char(0),char(109),char(95),char(110),char(117),char(109),char(65),char(110),char(99),char(104),char(111),char(114),char(115),char(0),char(109),char(95),char(110), +char(117),char(109),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(74),char(111),char(105),char(110), +char(116),char(115),char(0),char(109),char(95),char(99),char(111),char(110),char(102),char(105),char(103),char(0),char(84),char(89),char(80),char(69),char(76),char(0),char(0),char(0), +char(99),char(104),char(97),char(114),char(0),char(117),char(99),char(104),char(97),char(114),char(0),char(115),char(104),char(111),char(114),char(116),char(0),char(117),char(115),char(104), +char(111),char(114),char(116),char(0),char(105),char(110),char(116),char(0),char(108),char(111),char(110),char(103),char(0),char(117),char(108),char(111),char(110),char(103),char(0),char(102), +char(108),char(111),char(97),char(116),char(0),char(100),char(111),char(117),char(98),char(108),char(101),char(0),char(118),char(111),char(105),char(100),char(0),char(80),char(111),char(105), +char(110),char(116),char(101),char(114),char(65),char(114),char(114),char(97),char(121),char(0),char(98),char(116),char(80),char(104),char(121),char(115),char(105),char(99),char(115),char(83), +char(121),char(115),char(116),char(101),char(109),char(0),char(76),char(105),char(115),char(116),char(66),char(97),char(115),char(101),char(0),char(98),char(116),char(86),char(101),char(99), +char(116),char(111),char(114),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(86),char(101),char(99),char(116), +char(111),char(114),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116),char(114), +char(105),char(120),char(51),char(120),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116), +char(114),char(105),char(120),char(51),char(120),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84), +char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116), +char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0), +char(98),char(116),char(66),char(118),char(104),char(83),char(117),char(98),char(116),char(114),char(101),char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),char(97), +char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(70), +char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),char(100), +char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116), +char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(97),char(116),char(97), +char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(70),char(108),char(111),char(97),char(116), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(68), +char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111), +char(110),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(97),char(116),char(105),char(99),char(80), +char(108),char(97),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118), +char(101),char(120),char(73),char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0), +char(98),char(116),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(110),char(100),char(82),char(97),char(100),char(105),char(117),char(115),char(0), +char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(83),char(112),char(104),char(101),char(114),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),char(116), +char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),char(116), +char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),char(112),char(108),char(101),char(116), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(104),char(97),char(114),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),char(112), +char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(101),char(115),char(104),char(80),char(97),char(114),char(116),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(114),char(105),char(100),char(105),char(110),char(103),char(77),char(101),char(115),char(104),char(73),char(110),char(116), +char(101),char(114),char(102),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108), +char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105), +char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111),char(77),char(97),char(112),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83), +char(99),char(97),char(108),char(101),char(100),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97), +char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),char(97), +char(112),char(101),char(67),char(104),char(105),char(108),char(100),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117), +char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(121),char(108),char(105),char(110),char(100), +char(101),char(114),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(97),char(112),char(115),char(117),char(108), +char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108), +char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(73),char(109),char(112),char(97),char(99),char(116),char(77), +char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118),char(101), +char(120),char(72),char(117),char(108),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108), +char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116), +char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115), +char(87),char(111),char(114),char(108),char(100),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111), +char(110),char(116),char(97),char(99),char(116),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(68),char(111),char(117),char(98),char(108), +char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115),char(87),char(111),char(114),char(108), +char(100),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116), +char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0), +char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97), +char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(110),char(102),char(111),char(49), +char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(68),char(97),char(116),char(97),char(0),char(98), +char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), +char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50), +char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108), +char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97), +char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103), +char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97), +char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), +char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102), +char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110), +char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(67),char(111),char(110),char(115),char(116),char(114), +char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(108),char(105),char(100),char(101),char(114),char(67),char(111),char(110), +char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121), +char(77),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100), +char(121),char(78),char(111),char(100),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(76),char(105), +char(110),char(107),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(70),char(97),char(99),char(101),char(68), +char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(84),char(101),char(116),char(114),char(97),char(68),char(97),char(116), +char(97),char(0),char(83),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(65),char(110),char(99),char(104),char(111),char(114),char(68),char(97),char(116), +char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(67),char(111),char(110),char(102),char(105),char(103),char(68),char(97),char(116),char(97), +char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(80),char(111),char(115),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111), +char(102),char(116),char(66),char(111),char(100),char(121),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(68),char(97),char(116),char(97),char(0),char(98),char(116), +char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(74),char(111),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116), +char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(0),char(0), +char(84),char(76),char(69),char(78),char(1),char(0),char(1),char(0),char(2),char(0),char(2),char(0),char(4),char(0),char(4),char(0),char(4),char(0),char(4),char(0), +char(8),char(0),char(0),char(0),char(12),char(0),char(36),char(0),char(8),char(0),char(16),char(0),char(32),char(0),char(48),char(0),char(96),char(0),char(64),char(0), +char(-128),char(0),char(20),char(0),char(48),char(0),char(80),char(0),char(16),char(0),char(84),char(0),char(-124),char(0),char(12),char(0),char(52),char(0),char(52),char(0), +char(20),char(0),char(64),char(0),char(4),char(0),char(4),char(0),char(8),char(0),char(4),char(0),char(32),char(0),char(28),char(0),char(60),char(0),char(56),char(0), +char(76),char(0),char(76),char(0),char(24),char(0),char(60),char(0),char(60),char(0),char(16),char(0),char(64),char(0),char(68),char(0),char(-48),char(1),char(0),char(1), +char(-72),char(0),char(-104),char(0),char(104),char(0),char(88),char(0),char(-24),char(1),char(-96),char(3),char(8),char(0),char(52),char(0),char(0),char(0),char(84),char(0), +char(116),char(0),char(92),char(1),char(-36),char(0),char(-44),char(0),char(-4),char(0),char(92),char(1),char(-52),char(0),char(16),char(0),char(100),char(0),char(20),char(0), +char(36),char(0),char(100),char(0),char(92),char(0),char(104),char(0),char(-64),char(0),char(92),char(1),char(104),char(0),char(-84),char(1),char(83),char(84),char(82),char(67), +char(65),char(0),char(0),char(0),char(10),char(0),char(3),char(0),char(4),char(0),char(0),char(0),char(4),char(0),char(1),char(0),char(9),char(0),char(2),char(0), +char(11),char(0),char(3),char(0),char(10),char(0),char(3),char(0),char(10),char(0),char(4),char(0),char(10),char(0),char(5),char(0),char(12),char(0),char(2),char(0), +char(9),char(0),char(6),char(0),char(9),char(0),char(7),char(0),char(13),char(0),char(1),char(0),char(7),char(0),char(8),char(0),char(14),char(0),char(1),char(0), +char(8),char(0),char(8),char(0),char(15),char(0),char(1),char(0),char(13),char(0),char(9),char(0),char(16),char(0),char(1),char(0),char(14),char(0),char(9),char(0), +char(17),char(0),char(2),char(0),char(15),char(0),char(10),char(0),char(13),char(0),char(11),char(0),char(18),char(0),char(2),char(0),char(16),char(0),char(10),char(0), +char(14),char(0),char(11),char(0),char(19),char(0),char(4),char(0),char(4),char(0),char(12),char(0),char(4),char(0),char(13),char(0),char(2),char(0),char(14),char(0), +char(2),char(0),char(15),char(0),char(20),char(0),char(6),char(0),char(13),char(0),char(16),char(0),char(13),char(0),char(17),char(0),char(4),char(0),char(18),char(0), +char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0),char(21),char(0),char(6),char(0),char(14),char(0),char(16),char(0), +char(14),char(0),char(17),char(0),char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0), +char(22),char(0),char(3),char(0),char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0),char(4),char(0),char(22),char(0),char(23),char(0),char(12),char(0), +char(13),char(0),char(23),char(0),char(13),char(0),char(24),char(0),char(13),char(0),char(25),char(0),char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0), +char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0),char(20),char(0),char(30),char(0),char(22),char(0),char(31),char(0),char(19),char(0),char(32),char(0), +char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),char(24),char(0),char(12),char(0),char(14),char(0),char(23),char(0),char(14),char(0),char(24),char(0), +char(14),char(0),char(25),char(0),char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0), +char(21),char(0),char(30),char(0),char(22),char(0),char(31),char(0),char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),char(19),char(0),char(32),char(0), +char(25),char(0),char(3),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(36),char(0),char(0),char(0),char(37),char(0),char(26),char(0),char(5),char(0), +char(25),char(0),char(38),char(0),char(13),char(0),char(39),char(0),char(13),char(0),char(40),char(0),char(7),char(0),char(41),char(0),char(0),char(0),char(21),char(0), +char(27),char(0),char(5),char(0),char(25),char(0),char(38),char(0),char(13),char(0),char(39),char(0),char(13),char(0),char(42),char(0),char(7),char(0),char(43),char(0), +char(4),char(0),char(44),char(0),char(28),char(0),char(2),char(0),char(13),char(0),char(45),char(0),char(7),char(0),char(46),char(0),char(29),char(0),char(4),char(0), +char(27),char(0),char(47),char(0),char(28),char(0),char(48),char(0),char(4),char(0),char(49),char(0),char(0),char(0),char(37),char(0),char(30),char(0),char(1),char(0), +char(4),char(0),char(50),char(0),char(31),char(0),char(2),char(0),char(2),char(0),char(50),char(0),char(0),char(0),char(51),char(0),char(32),char(0),char(2),char(0), +char(2),char(0),char(52),char(0),char(0),char(0),char(51),char(0),char(33),char(0),char(2),char(0),char(0),char(0),char(52),char(0),char(0),char(0),char(53),char(0), +char(34),char(0),char(8),char(0),char(13),char(0),char(54),char(0),char(14),char(0),char(55),char(0),char(30),char(0),char(56),char(0),char(32),char(0),char(57),char(0), +char(33),char(0),char(58),char(0),char(31),char(0),char(59),char(0),char(4),char(0),char(60),char(0),char(4),char(0),char(61),char(0),char(35),char(0),char(4),char(0), +char(34),char(0),char(62),char(0),char(13),char(0),char(63),char(0),char(4),char(0),char(64),char(0),char(0),char(0),char(37),char(0),char(36),char(0),char(7),char(0), +char(25),char(0),char(38),char(0),char(35),char(0),char(65),char(0),char(23),char(0),char(66),char(0),char(24),char(0),char(67),char(0),char(37),char(0),char(68),char(0), +char(7),char(0),char(43),char(0),char(0),char(0),char(69),char(0),char(38),char(0),char(2),char(0),char(36),char(0),char(70),char(0),char(13),char(0),char(39),char(0), +char(39),char(0),char(4),char(0),char(17),char(0),char(71),char(0),char(25),char(0),char(72),char(0),char(4),char(0),char(73),char(0),char(7),char(0),char(74),char(0), +char(40),char(0),char(4),char(0),char(25),char(0),char(38),char(0),char(39),char(0),char(75),char(0),char(4),char(0),char(76),char(0),char(7),char(0),char(43),char(0), +char(41),char(0),char(3),char(0),char(27),char(0),char(47),char(0),char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),char(42),char(0),char(3),char(0), +char(27),char(0),char(47),char(0),char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),char(43),char(0),char(4),char(0),char(4),char(0),char(78),char(0), +char(7),char(0),char(79),char(0),char(7),char(0),char(80),char(0),char(7),char(0),char(81),char(0),char(37),char(0),char(14),char(0),char(4),char(0),char(82),char(0), +char(4),char(0),char(83),char(0),char(43),char(0),char(84),char(0),char(4),char(0),char(85),char(0),char(7),char(0),char(86),char(0),char(7),char(0),char(87),char(0), +char(7),char(0),char(88),char(0),char(7),char(0),char(89),char(0),char(7),char(0),char(90),char(0),char(4),char(0),char(91),char(0),char(4),char(0),char(92),char(0), +char(4),char(0),char(93),char(0),char(4),char(0),char(94),char(0),char(0),char(0),char(37),char(0),char(44),char(0),char(5),char(0),char(25),char(0),char(38),char(0), +char(35),char(0),char(65),char(0),char(13),char(0),char(39),char(0),char(7),char(0),char(43),char(0),char(4),char(0),char(95),char(0),char(45),char(0),char(5),char(0), +char(27),char(0),char(47),char(0),char(13),char(0),char(96),char(0),char(14),char(0),char(97),char(0),char(4),char(0),char(98),char(0),char(0),char(0),char(99),char(0), +char(46),char(0),char(25),char(0),char(9),char(0),char(100),char(0),char(9),char(0),char(101),char(0),char(25),char(0),char(102),char(0),char(0),char(0),char(35),char(0), +char(18),char(0),char(103),char(0),char(18),char(0),char(104),char(0),char(14),char(0),char(105),char(0),char(14),char(0),char(106),char(0),char(14),char(0),char(107),char(0), +char(8),char(0),char(108),char(0),char(8),char(0),char(109),char(0),char(8),char(0),char(110),char(0),char(8),char(0),char(111),char(0),char(8),char(0),char(112),char(0), +char(8),char(0),char(113),char(0),char(8),char(0),char(114),char(0),char(8),char(0),char(115),char(0),char(4),char(0),char(116),char(0),char(4),char(0),char(117),char(0), +char(4),char(0),char(118),char(0),char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0),char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0), +char(0),char(0),char(37),char(0),char(47),char(0),char(25),char(0),char(9),char(0),char(100),char(0),char(9),char(0),char(101),char(0),char(25),char(0),char(102),char(0), +char(0),char(0),char(35),char(0),char(17),char(0),char(103),char(0),char(17),char(0),char(104),char(0),char(13),char(0),char(105),char(0),char(13),char(0),char(106),char(0), +char(13),char(0),char(107),char(0),char(7),char(0),char(108),char(0),char(7),char(0),char(109),char(0),char(7),char(0),char(110),char(0),char(7),char(0),char(111),char(0), +char(7),char(0),char(112),char(0),char(7),char(0),char(113),char(0),char(7),char(0),char(114),char(0),char(7),char(0),char(115),char(0),char(4),char(0),char(116),char(0), +char(4),char(0),char(117),char(0),char(4),char(0),char(118),char(0),char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0),char(4),char(0),char(121),char(0), +char(4),char(0),char(122),char(0),char(0),char(0),char(37),char(0),char(48),char(0),char(2),char(0),char(49),char(0),char(123),char(0),char(14),char(0),char(124),char(0), +char(50),char(0),char(2),char(0),char(51),char(0),char(123),char(0),char(13),char(0),char(124),char(0),char(52),char(0),char(21),char(0),char(47),char(0),char(125),char(0), +char(15),char(0),char(126),char(0),char(13),char(0),char(127),char(0),char(13),char(0),char(-128),char(0),char(13),char(0),char(-127),char(0),char(13),char(0),char(-126),char(0), +char(13),char(0),char(124),char(0),char(13),char(0),char(-125),char(0),char(13),char(0),char(-124),char(0),char(13),char(0),char(-123),char(0),char(13),char(0),char(-122),char(0), +char(7),char(0),char(-121),char(0),char(7),char(0),char(-120),char(0),char(7),char(0),char(-119),char(0),char(7),char(0),char(-118),char(0),char(7),char(0),char(-117),char(0), +char(7),char(0),char(-116),char(0),char(7),char(0),char(-115),char(0),char(7),char(0),char(-114),char(0),char(7),char(0),char(-113),char(0),char(4),char(0),char(-112),char(0), +char(53),char(0),char(22),char(0),char(46),char(0),char(125),char(0),char(16),char(0),char(126),char(0),char(14),char(0),char(127),char(0),char(14),char(0),char(-128),char(0), +char(14),char(0),char(-127),char(0),char(14),char(0),char(-126),char(0),char(14),char(0),char(124),char(0),char(14),char(0),char(-125),char(0),char(14),char(0),char(-124),char(0), +char(14),char(0),char(-123),char(0),char(14),char(0),char(-122),char(0),char(8),char(0),char(-121),char(0),char(8),char(0),char(-120),char(0),char(8),char(0),char(-119),char(0), +char(8),char(0),char(-118),char(0),char(8),char(0),char(-117),char(0),char(8),char(0),char(-116),char(0),char(8),char(0),char(-115),char(0),char(8),char(0),char(-114),char(0), +char(8),char(0),char(-113),char(0),char(4),char(0),char(-112),char(0),char(0),char(0),char(37),char(0),char(54),char(0),char(2),char(0),char(4),char(0),char(-111),char(0), +char(4),char(0),char(-110),char(0),char(55),char(0),char(13),char(0),char(56),char(0),char(-109),char(0),char(56),char(0),char(-108),char(0),char(0),char(0),char(35),char(0), +char(4),char(0),char(-107),char(0),char(4),char(0),char(-106),char(0),char(4),char(0),char(-105),char(0),char(4),char(0),char(-104),char(0),char(7),char(0),char(-103),char(0), +char(7),char(0),char(-102),char(0),char(4),char(0),char(-101),char(0),char(4),char(0),char(-100),char(0),char(7),char(0),char(-99),char(0),char(4),char(0),char(-98),char(0), +char(57),char(0),char(3),char(0),char(55),char(0),char(-97),char(0),char(13),char(0),char(-96),char(0),char(13),char(0),char(-95),char(0),char(58),char(0),char(3),char(0), +char(55),char(0),char(-97),char(0),char(14),char(0),char(-96),char(0),char(14),char(0),char(-95),char(0),char(59),char(0),char(13),char(0),char(55),char(0),char(-97),char(0), +char(18),char(0),char(-94),char(0),char(18),char(0),char(-93),char(0),char(4),char(0),char(-92),char(0),char(4),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0), +char(7),char(0),char(-89),char(0),char(7),char(0),char(-88),char(0),char(7),char(0),char(-87),char(0),char(7),char(0),char(-86),char(0),char(7),char(0),char(-85),char(0), +char(7),char(0),char(-84),char(0),char(7),char(0),char(-83),char(0),char(60),char(0),char(13),char(0),char(55),char(0),char(-97),char(0),char(17),char(0),char(-94),char(0), +char(17),char(0),char(-93),char(0),char(4),char(0),char(-92),char(0),char(4),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),char(7),char(0),char(-89),char(0), +char(7),char(0),char(-88),char(0),char(7),char(0),char(-87),char(0),char(7),char(0),char(-86),char(0),char(7),char(0),char(-85),char(0),char(7),char(0),char(-84),char(0), +char(7),char(0),char(-83),char(0),char(61),char(0),char(11),char(0),char(55),char(0),char(-97),char(0),char(17),char(0),char(-94),char(0),char(17),char(0),char(-93),char(0), +char(7),char(0),char(-82),char(0),char(7),char(0),char(-81),char(0),char(7),char(0),char(-80),char(0),char(7),char(0),char(-85),char(0),char(7),char(0),char(-84),char(0), +char(7),char(0),char(-83),char(0),char(7),char(0),char(-79),char(0),char(0),char(0),char(21),char(0),char(62),char(0),char(9),char(0),char(55),char(0),char(-97),char(0), +char(17),char(0),char(-94),char(0),char(17),char(0),char(-93),char(0),char(13),char(0),char(-78),char(0),char(13),char(0),char(-77),char(0),char(13),char(0),char(-76),char(0), +char(13),char(0),char(-75),char(0),char(4),char(0),char(-74),char(0),char(4),char(0),char(-73),char(0),char(63),char(0),char(5),char(0),char(62),char(0),char(-72),char(0), +char(4),char(0),char(-71),char(0),char(7),char(0),char(-70),char(0),char(7),char(0),char(-69),char(0),char(7),char(0),char(-68),char(0),char(64),char(0),char(9),char(0), +char(55),char(0),char(-97),char(0),char(17),char(0),char(-94),char(0),char(17),char(0),char(-93),char(0),char(7),char(0),char(-78),char(0),char(7),char(0),char(-77),char(0), +char(7),char(0),char(-76),char(0),char(7),char(0),char(-75),char(0),char(4),char(0),char(-74),char(0),char(4),char(0),char(-73),char(0),char(49),char(0),char(22),char(0), +char(8),char(0),char(-67),char(0),char(8),char(0),char(-79),char(0),char(8),char(0),char(110),char(0),char(8),char(0),char(-66),char(0),char(8),char(0),char(112),char(0), +char(8),char(0),char(-65),char(0),char(8),char(0),char(-64),char(0),char(8),char(0),char(-63),char(0),char(8),char(0),char(-62),char(0),char(8),char(0),char(-61),char(0), +char(8),char(0),char(-60),char(0),char(8),char(0),char(-59),char(0),char(8),char(0),char(-58),char(0),char(8),char(0),char(-57),char(0),char(8),char(0),char(-56),char(0), +char(8),char(0),char(-55),char(0),char(4),char(0),char(-54),char(0),char(4),char(0),char(-53),char(0),char(4),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0), +char(4),char(0),char(-50),char(0),char(0),char(0),char(37),char(0),char(51),char(0),char(22),char(0),char(7),char(0),char(-67),char(0),char(7),char(0),char(-79),char(0), +char(7),char(0),char(110),char(0),char(7),char(0),char(-66),char(0),char(7),char(0),char(112),char(0),char(7),char(0),char(-65),char(0),char(7),char(0),char(-64),char(0), +char(7),char(0),char(-63),char(0),char(7),char(0),char(-62),char(0),char(7),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0),char(7),char(0),char(-59),char(0), +char(7),char(0),char(-58),char(0),char(7),char(0),char(-57),char(0),char(7),char(0),char(-56),char(0),char(7),char(0),char(-55),char(0),char(4),char(0),char(-54),char(0), +char(4),char(0),char(-53),char(0),char(4),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0),char(0),char(0),char(37),char(0), +char(65),char(0),char(4),char(0),char(7),char(0),char(-49),char(0),char(7),char(0),char(-48),char(0),char(7),char(0),char(-47),char(0),char(4),char(0),char(78),char(0), +char(66),char(0),char(10),char(0),char(65),char(0),char(-46),char(0),char(13),char(0),char(-45),char(0),char(13),char(0),char(-44),char(0),char(13),char(0),char(-43),char(0), +char(13),char(0),char(-42),char(0),char(13),char(0),char(-41),char(0),char(7),char(0),char(-121),char(0),char(7),char(0),char(-40),char(0),char(4),char(0),char(-39),char(0), +char(4),char(0),char(53),char(0),char(67),char(0),char(4),char(0),char(65),char(0),char(-46),char(0),char(4),char(0),char(-38),char(0),char(7),char(0),char(-37),char(0), +char(4),char(0),char(-36),char(0),char(68),char(0),char(4),char(0),char(13),char(0),char(-41),char(0),char(65),char(0),char(-46),char(0),char(4),char(0),char(-35),char(0), +char(7),char(0),char(-34),char(0),char(69),char(0),char(7),char(0),char(13),char(0),char(-33),char(0),char(65),char(0),char(-46),char(0),char(4),char(0),char(-32),char(0), +char(7),char(0),char(-31),char(0),char(7),char(0),char(-30),char(0),char(7),char(0),char(-29),char(0),char(4),char(0),char(53),char(0),char(70),char(0),char(6),char(0), +char(15),char(0),char(-28),char(0),char(13),char(0),char(-30),char(0),char(13),char(0),char(-27),char(0),char(56),char(0),char(-26),char(0),char(4),char(0),char(-25),char(0), +char(7),char(0),char(-29),char(0),char(71),char(0),char(26),char(0),char(4),char(0),char(-24),char(0),char(7),char(0),char(-23),char(0),char(7),char(0),char(-79),char(0), +char(7),char(0),char(-22),char(0),char(7),char(0),char(-21),char(0),char(7),char(0),char(-20),char(0),char(7),char(0),char(-19),char(0),char(7),char(0),char(-18),char(0), +char(7),char(0),char(-17),char(0),char(7),char(0),char(-16),char(0),char(7),char(0),char(-15),char(0),char(7),char(0),char(-14),char(0),char(7),char(0),char(-13),char(0), +char(7),char(0),char(-12),char(0),char(7),char(0),char(-11),char(0),char(7),char(0),char(-10),char(0),char(7),char(0),char(-9),char(0),char(7),char(0),char(-8),char(0), +char(7),char(0),char(-7),char(0),char(7),char(0),char(-6),char(0),char(7),char(0),char(-5),char(0),char(4),char(0),char(-4),char(0),char(4),char(0),char(-3),char(0), +char(4),char(0),char(-2),char(0),char(4),char(0),char(-1),char(0),char(4),char(0),char(117),char(0),char(72),char(0),char(12),char(0),char(15),char(0),char(0),char(1), +char(15),char(0),char(1),char(1),char(15),char(0),char(2),char(1),char(13),char(0),char(3),char(1),char(13),char(0),char(4),char(1),char(7),char(0),char(5),char(1), +char(4),char(0),char(6),char(1),char(4),char(0),char(7),char(1),char(4),char(0),char(8),char(1),char(4),char(0),char(9),char(1),char(7),char(0),char(-31),char(0), +char(4),char(0),char(53),char(0),char(73),char(0),char(27),char(0),char(17),char(0),char(10),char(1),char(15),char(0),char(11),char(1),char(15),char(0),char(12),char(1), +char(13),char(0),char(3),char(1),char(13),char(0),char(13),char(1),char(13),char(0),char(14),char(1),char(13),char(0),char(15),char(1),char(13),char(0),char(16),char(1), +char(13),char(0),char(17),char(1),char(4),char(0),char(18),char(1),char(7),char(0),char(19),char(1),char(4),char(0),char(20),char(1),char(4),char(0),char(21),char(1), +char(4),char(0),char(22),char(1),char(7),char(0),char(23),char(1),char(7),char(0),char(24),char(1),char(4),char(0),char(25),char(1),char(4),char(0),char(26),char(1), +char(7),char(0),char(27),char(1),char(7),char(0),char(28),char(1),char(7),char(0),char(29),char(1),char(7),char(0),char(30),char(1),char(7),char(0),char(31),char(1), +char(7),char(0),char(32),char(1),char(4),char(0),char(33),char(1),char(4),char(0),char(34),char(1),char(4),char(0),char(35),char(1),char(74),char(0),char(12),char(0), +char(9),char(0),char(36),char(1),char(9),char(0),char(37),char(1),char(13),char(0),char(38),char(1),char(7),char(0),char(39),char(1),char(7),char(0),char(-63),char(0), +char(7),char(0),char(40),char(1),char(4),char(0),char(41),char(1),char(13),char(0),char(42),char(1),char(4),char(0),char(43),char(1),char(4),char(0),char(44),char(1), +char(4),char(0),char(45),char(1),char(4),char(0),char(53),char(0),char(75),char(0),char(19),char(0),char(47),char(0),char(125),char(0),char(72),char(0),char(46),char(1), +char(65),char(0),char(47),char(1),char(66),char(0),char(48),char(1),char(67),char(0),char(49),char(1),char(68),char(0),char(50),char(1),char(69),char(0),char(51),char(1), +char(70),char(0),char(52),char(1),char(73),char(0),char(53),char(1),char(74),char(0),char(54),char(1),char(4),char(0),char(55),char(1),char(4),char(0),char(21),char(1), +char(4),char(0),char(56),char(1),char(4),char(0),char(57),char(1),char(4),char(0),char(58),char(1),char(4),char(0),char(59),char(1),char(4),char(0),char(60),char(1), +char(4),char(0),char(61),char(1),char(71),char(0),char(62),char(1),}; +int b3s_bulletDNAlen= sizeof(b3s_bulletDNAstr); +char b3s_bulletDNAstr64[]= { +char(83),char(68),char(78),char(65),char(78),char(65),char(77),char(69),char(63),char(1),char(0),char(0),char(109),char(95),char(115),char(105),char(122),char(101),char(0),char(109), +char(95),char(99),char(97),char(112),char(97),char(99),char(105),char(116),char(121),char(0),char(42),char(109),char(95),char(100),char(97),char(116),char(97),char(0),char(109),char(95), +char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(115),char(0),char(109),char(95),char(99),char(111), +char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(115),char(0),char(109),char(95),char(99),char(111),char(110), +char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(115),char(0),char(42),char(102),char(105),char(114),char(115),char(116),char(0),char(42),char(108),char(97),char(115), +char(116),char(0),char(109),char(95),char(102),char(108),char(111),char(97),char(116),char(115),char(91),char(52),char(93),char(0),char(109),char(95),char(101),char(108),char(91),char(51), +char(93),char(0),char(109),char(95),char(98),char(97),char(115),char(105),char(115),char(0),char(109),char(95),char(111),char(114),char(105),char(103),char(105),char(110),char(0),char(109), +char(95),char(114),char(111),char(111),char(116),char(78),char(111),char(100),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(115),char(117),char(98), +char(116),char(114),char(101),char(101),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100), +char(65),char(97),char(98),char(98),char(77),char(105),char(110),char(91),char(51),char(93),char(0),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122), +char(101),char(100),char(65),char(97),char(98),char(98),char(77),char(97),char(120),char(91),char(51),char(93),char(0),char(109),char(95),char(97),char(97),char(98),char(98),char(77), +char(105),char(110),char(79),char(114),char(103),char(0),char(109),char(95),char(97),char(97),char(98),char(98),char(77),char(97),char(120),char(79),char(114),char(103),char(0),char(109), +char(95),char(101),char(115),char(99),char(97),char(112),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(115),char(117),char(98),char(80),char(97), +char(114),char(116),char(0),char(109),char(95),char(116),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109), +char(95),char(112),char(97),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(101),char(115),char(99),char(97),char(112),char(101),char(73),char(110),char(100),char(101), +char(120),char(79),char(114),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(98), +char(118),char(104),char(65),char(97),char(98),char(98),char(77),char(105),char(110),char(0),char(109),char(95),char(98),char(118),char(104),char(65),char(97),char(98),char(98),char(77), +char(97),char(120),char(0),char(109),char(95),char(98),char(118),char(104),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(97),char(116),char(105),char(111),char(110), +char(0),char(109),char(95),char(99),char(117),char(114),char(78),char(111),char(100),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(117),char(115), +char(101),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(97),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(110),char(117),char(109),char(67), +char(111),char(110),char(116),char(105),char(103),char(117),char(111),char(117),char(115),char(76),char(101),char(97),char(102),char(78),char(111),char(100),char(101),char(115),char(0),char(109), +char(95),char(110),char(117),char(109),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(67),char(111),char(110),char(116),char(105),char(103),char(117), +char(111),char(117),char(115),char(78),char(111),char(100),char(101),char(115),char(0),char(42),char(109),char(95),char(99),char(111),char(110),char(116),char(105),char(103),char(117),char(111), +char(117),char(115),char(78),char(111),char(100),char(101),char(115),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105), +char(122),char(101),char(100),char(67),char(111),char(110),char(116),char(105),char(103),char(117),char(111),char(117),char(115),char(78),char(111),char(100),char(101),char(115),char(80),char(116), +char(114),char(0),char(42),char(109),char(95),char(115),char(117),char(98),char(84),char(114),char(101),char(101),char(73),char(110),char(102),char(111),char(80),char(116),char(114),char(0), +char(109),char(95),char(116),char(114),char(97),char(118),char(101),char(114),char(115),char(97),char(108),char(77),char(111),char(100),char(101),char(0),char(109),char(95),char(110),char(117), +char(109),char(83),char(117),char(98),char(116),char(114),char(101),char(101),char(72),char(101),char(97),char(100),char(101),char(114),char(115),char(0),char(42),char(109),char(95),char(110), +char(97),char(109),char(101),char(0),char(109),char(95),char(115),char(104),char(97),char(112),char(101),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(112),char(97), +char(100),char(100),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110), +char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(83),char(99),char(97), +char(108),char(105),char(110),char(103),char(0),char(109),char(95),char(112),char(108),char(97),char(110),char(101),char(78),char(111),char(114),char(109),char(97),char(108),char(0),char(109), +char(95),char(112),char(108),char(97),char(110),char(101),char(67),char(111),char(110),char(115),char(116),char(97),char(110),char(116),char(0),char(109),char(95),char(105),char(109),char(112), +char(108),char(105),char(99),char(105),char(116),char(83),char(104),char(97),char(112),char(101),char(68),char(105),char(109),char(101),char(110),char(115),char(105),char(111),char(110),char(115), +char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(77),char(97),char(114),char(103),char(105),char(110),char(0),char(109), +char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(0),char(109),char(95),char(112),char(111),char(115),char(0),char(109),char(95),char(114),char(97),char(100), +char(105),char(117),char(115),char(0),char(109),char(95),char(99),char(111),char(110),char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114),char(110),char(97),char(108), +char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(42),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(80),char(111), +char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(114),char(114),char(97),char(121),char(80),char(116),char(114),char(0),char(109),char(95),char(108),char(111),char(99), +char(97),char(108),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(114),char(114),char(97),char(121),char(83),char(105),char(122),char(101),char(0), +char(109),char(95),char(118),char(97),char(108),char(117),char(101),char(0),char(109),char(95),char(112),char(97),char(100),char(91),char(50),char(93),char(0),char(109),char(95),char(118), +char(97),char(108),char(117),char(101),char(115),char(91),char(51),char(93),char(0),char(109),char(95),char(112),char(97),char(100),char(0),char(42),char(109),char(95),char(118),char(101), +char(114),char(116),char(105),char(99),char(101),char(115),char(51),char(102),char(0),char(42),char(109),char(95),char(118),char(101),char(114),char(116),char(105),char(99),char(101),char(115), +char(51),char(100),char(0),char(42),char(109),char(95),char(105),char(110),char(100),char(105),char(99),char(101),char(115),char(51),char(50),char(0),char(42),char(109),char(95),char(51), +char(105),char(110),char(100),char(105),char(99),char(101),char(115),char(49),char(54),char(0),char(42),char(109),char(95),char(51),char(105),char(110),char(100),char(105),char(99),char(101), +char(115),char(56),char(0),char(42),char(109),char(95),char(105),char(110),char(100),char(105),char(99),char(101),char(115),char(49),char(54),char(0),char(109),char(95),char(110),char(117), +char(109),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(86),char(101),char(114),char(116), +char(105),char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(109),char(101),char(115),char(104),char(80),char(97),char(114),char(116),char(115),char(80),char(116),char(114), +char(0),char(109),char(95),char(115),char(99),char(97),char(108),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(101),char(115),char(104), +char(80),char(97),char(114),char(116),char(115),char(0),char(109),char(95),char(109),char(101),char(115),char(104),char(73),char(110),char(116),char(101),char(114),char(102),char(97),char(99), +char(101),char(0),char(42),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(70),char(108),char(111),char(97),char(116),char(66), +char(118),char(104),char(0),char(42),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(68),char(111),char(117),char(98),char(108), +char(101),char(66),char(118),char(104),char(0),char(42),char(109),char(95),char(116),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111), +char(77),char(97),char(112),char(0),char(109),char(95),char(112),char(97),char(100),char(51),char(91),char(52),char(93),char(0),char(109),char(95),char(116),char(114),char(105),char(109), +char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(116),char(114),char(97),char(110),char(115), +char(102),char(111),char(114),char(109),char(0),char(42),char(109),char(95),char(99),char(104),char(105),char(108),char(100),char(83),char(104),char(97),char(112),char(101),char(0),char(109), +char(95),char(99),char(104),char(105),char(108),char(100),char(83),char(104),char(97),char(112),char(101),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(99),char(104), +char(105),char(108),char(100),char(77),char(97),char(114),char(103),char(105),char(110),char(0),char(42),char(109),char(95),char(99),char(104),char(105),char(108),char(100),char(83),char(104), +char(97),char(112),char(101),char(80),char(116),char(114),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(104),char(105),char(108),char(100),char(83),char(104),char(97), +char(112),char(101),char(115),char(0),char(109),char(95),char(117),char(112),char(65),char(120),char(105),char(115),char(0),char(109),char(95),char(102),char(108),char(97),char(103),char(115), +char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(86),char(48),char(86),char(49),char(65),char(110),char(103),char(108),char(101),char(0),char(109),char(95),char(101), +char(100),char(103),char(101),char(86),char(49),char(86),char(50),char(65),char(110),char(103),char(108),char(101),char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(86), +char(50),char(86),char(48),char(65),char(110),char(103),char(108),char(101),char(0),char(42),char(109),char(95),char(104),char(97),char(115),char(104),char(84),char(97),char(98),char(108), +char(101),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(110),char(101),char(120),char(116),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(118), +char(97),char(108),char(117),char(101),char(65),char(114),char(114),char(97),char(121),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(107),char(101),char(121),char(65), +char(114),char(114),char(97),char(121),char(80),char(116),char(114),char(0),char(109),char(95),char(99),char(111),char(110),char(118),char(101),char(120),char(69),char(112),char(115),char(105), +char(108),char(111),char(110),char(0),char(109),char(95),char(112),char(108),char(97),char(110),char(97),char(114),char(69),char(112),char(115),char(105),char(108),char(111),char(110),char(0), +char(109),char(95),char(101),char(113),char(117),char(97),char(108),char(86),char(101),char(114),char(116),char(101),char(120),char(84),char(104),char(114),char(101),char(115),char(104),char(111), +char(108),char(100),char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(68),char(105),char(115),char(116),char(97),char(110),char(99),char(101),char(84),char(104),char(114), +char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(122),char(101),char(114),char(111),char(65),char(114),char(101),char(97),char(84),char(104),char(114), +char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(110),char(101),char(120),char(116),char(83),char(105),char(122),char(101),char(0),char(109),char(95), +char(104),char(97),char(115),char(104),char(84),char(97),char(98),char(108),char(101),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(110),char(117),char(109),char(86), +char(97),char(108),char(117),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(75),char(101),char(121),char(115),char(0),char(109),char(95),char(103),char(105), +char(109),char(112),char(97),char(99),char(116),char(83),char(117),char(98),char(84),char(121),char(112),char(101),char(0),char(42),char(109),char(95),char(117),char(110),char(115),char(99), +char(97),char(108),char(101),char(100),char(80),char(111),char(105),char(110),char(116),char(115),char(70),char(108),char(111),char(97),char(116),char(80),char(116),char(114),char(0),char(42), +char(109),char(95),char(117),char(110),char(115),char(99),char(97),char(108),char(101),char(100),char(80),char(111),char(105),char(110),char(116),char(115),char(68),char(111),char(117),char(98), +char(108),char(101),char(80),char(116),char(114),char(0),char(109),char(95),char(110),char(117),char(109),char(85),char(110),char(115),char(99),char(97),char(108),char(101),char(100),char(80), +char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(51),char(91),char(52),char(93),char(0), +char(42),char(109),char(95),char(98),char(114),char(111),char(97),char(100),char(112),char(104),char(97),char(115),char(101),char(72),char(97),char(110),char(100),char(108),char(101),char(0), +char(42),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(0),char(42),char(109), +char(95),char(114),char(111),char(111),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(0), +char(109),char(95),char(119),char(111),char(114),char(108),char(100),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(105), +char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105),char(111),char(110),char(87),char(111),char(114),char(108),char(100),char(84),char(114),char(97), +char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105), +char(111),char(110),char(76),char(105),char(110),char(101),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(105), +char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105),char(111),char(110),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(86), +char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(105),char(115),char(111),char(116),char(114),char(111),char(112),char(105), +char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(99),char(116),char(80), +char(114),char(111),char(99),char(101),char(115),char(115),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109), +char(95),char(100),char(101),char(97),char(99),char(116),char(105),char(118),char(97),char(116),char(105),char(111),char(110),char(84),char(105),char(109),char(101),char(0),char(109),char(95), +char(102),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(114),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114), +char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(105),char(116),char(117),char(116),char(105),char(111),char(110), +char(0),char(109),char(95),char(104),char(105),char(116),char(70),char(114),char(97),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(99),char(100), +char(83),char(119),char(101),char(112),char(116),char(83),char(112),char(104),char(101),char(114),char(101),char(82),char(97),char(100),char(105),char(117),char(115),char(0),char(109),char(95), +char(99),char(99),char(100),char(77),char(111),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109), +char(95),char(104),char(97),char(115),char(65),char(110),char(105),char(115),char(111),char(116),char(114),char(111),char(112),char(105),char(99),char(70),char(114),char(105),char(99),char(116), +char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(70),char(108),char(97),char(103),char(115), +char(0),char(109),char(95),char(105),char(115),char(108),char(97),char(110),char(100),char(84),char(97),char(103),char(49),char(0),char(109),char(95),char(99),char(111),char(109),char(112), +char(97),char(110),char(105),char(111),char(110),char(73),char(100),char(0),char(109),char(95),char(97),char(99),char(116),char(105),char(118),char(97),char(116),char(105),char(111),char(110), +char(83),char(116),char(97),char(116),char(101),char(49),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(84),char(121),char(112), +char(101),char(0),char(109),char(95),char(99),char(104),char(101),char(99),char(107),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(87),char(105),char(116),char(104), +char(0),char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(0),char(109),char(95),char(103),char(114),char(97),char(118), +char(105),char(116),char(121),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99), +char(116),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(84),char(101), +char(110),char(115),char(111),char(114),char(87),char(111),char(114),char(108),char(100),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(86),char(101), +char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111), +char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114), +char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(103),char(114), +char(97),char(118),char(105),char(116),char(121),char(95),char(97),char(99),char(99),char(101),char(108),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(0),char(109), +char(95),char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(76),char(111),char(99),char(97),char(108),char(0),char(109),char(95),char(116), +char(111),char(116),char(97),char(108),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(116),char(111),char(116),char(97),char(108),char(84),char(111),char(114), +char(113),char(117),char(101),char(0),char(109),char(95),char(105),char(110),char(118),char(101),char(114),char(115),char(101),char(77),char(97),char(115),char(115),char(0),char(109),char(95), +char(108),char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117), +char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111), +char(110),char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(97), +char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(76),char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105), +char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100), +char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110), +char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105), +char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103), +char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(101),char(101),char(112), +char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108), +char(97),char(114),char(83),char(108),char(101),char(101),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0), +char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0), +char(109),char(95),char(110),char(117),char(109),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(82),char(111),char(119),char(115),char(0), +char(110),char(117),char(98),char(0),char(42),char(109),char(95),char(114),char(98),char(65),char(0),char(42),char(109),char(95),char(114),char(98),char(66),char(0),char(109),char(95), +char(111),char(98),char(106),char(101),char(99),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110), +char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111), +char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(100),char(0),char(109),char(95),char(110),char(101),char(101),char(100),char(115),char(70),char(101), +char(101),char(100),char(98),char(97),char(99),char(107),char(0),char(109),char(95),char(97),char(112),char(112),char(108),char(105),char(101),char(100),char(73),char(109),char(112),char(117), +char(108),char(115),char(101),char(0),char(109),char(95),char(100),char(98),char(103),char(68),char(114),char(97),char(119),char(83),char(105),char(122),char(101),char(0),char(109),char(95), +char(100),char(105),char(115),char(97),char(98),char(108),char(101),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(115),char(66),char(101),char(116), +char(119),char(101),char(101),char(110),char(76),char(105),char(110),char(107),char(101),char(100),char(66),char(111),char(100),char(105),char(101),char(115),char(0),char(109),char(95),char(111), +char(118),char(101),char(114),char(114),char(105),char(100),char(101),char(78),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(116),char(101),char(114), +char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(98),char(114),char(101),char(97),char(107),char(105),char(110),char(103),char(73),char(109),char(112), +char(117),char(108),char(115),char(101),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(105),char(115),char(69),char(110), +char(97),char(98),char(108),char(101),char(100),char(0),char(109),char(95),char(116),char(121),char(112),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), +char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(112),char(105),char(118),char(111),char(116),char(73),char(110),char(65),char(0),char(109),char(95), +char(112),char(105),char(118),char(111),char(116),char(73),char(110),char(66),char(0),char(109),char(95),char(114),char(98),char(65),char(70),char(114),char(97),char(109),char(101),char(0), +char(109),char(95),char(114),char(98),char(66),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(82),char(101),char(102),char(101), +char(114),char(101),char(110),char(99),char(101),char(70),char(114),char(97),char(109),char(101),char(65),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97), +char(114),char(79),char(110),char(108),char(121),char(0),char(109),char(95),char(101),char(110),char(97),char(98),char(108),char(101),char(65),char(110),char(103),char(117),char(108),char(97), +char(114),char(77),char(111),char(116),char(111),char(114),char(0),char(109),char(95),char(109),char(111),char(116),char(111),char(114),char(84),char(97),char(114),char(103),char(101),char(116), +char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(109),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(73), +char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(108),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0), +char(109),char(95),char(117),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(108),char(105),char(109),char(105),char(116), +char(83),char(111),char(102),char(116),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(98),char(105),char(97),char(115),char(70),char(97),char(99),char(116),char(111), +char(114),char(0),char(109),char(95),char(114),char(101),char(108),char(97),char(120),char(97),char(116),char(105),char(111),char(110),char(70),char(97),char(99),char(116),char(111),char(114), +char(0),char(109),char(95),char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(49),char(0),char(109),char(95),char(115),char(119),char(105),char(110), +char(103),char(83),char(112),char(97),char(110),char(50),char(0),char(109),char(95),char(116),char(119),char(105),char(115),char(116),char(83),char(112),char(97),char(110),char(0),char(109), +char(95),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(85),char(112),char(112), +char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(76),char(111),char(119),char(101), +char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(85),char(112),char(112),char(101), +char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(76),char(111),char(119),char(101), +char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(117),char(115),char(101),char(76),char(105),char(110),char(101),char(97),char(114),char(82),char(101), +char(102),char(101),char(114),char(101),char(110),char(99),char(101),char(70),char(114),char(97),char(109),char(101),char(65),char(0),char(109),char(95),char(117),char(115),char(101),char(79), +char(102),char(102),char(115),char(101),char(116),char(70),char(111),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(114), +char(97),char(109),char(101),char(0),char(109),char(95),char(54),char(100),char(111),char(102),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(115),char(112),char(114), +char(105),char(110),char(103),char(69),char(110),char(97),char(98),char(108),char(101),char(100),char(91),char(54),char(93),char(0),char(109),char(95),char(101),char(113),char(117),char(105), +char(108),char(105),char(98),char(114),char(105),char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112), +char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(91),char(54),char(93),char(0),char(109),char(95),char(115), +char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(91),char(54),char(93),char(0),char(109),char(95),char(116),char(97), +char(117),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(116),char(101),char(112),char(0),char(109),char(95),char(109),char(97),char(120),char(69),char(114), +char(114),char(111),char(114),char(82),char(101),char(100),char(117),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(115),char(111),char(114),char(0),char(109), +char(95),char(101),char(114),char(112),char(0),char(109),char(95),char(101),char(114),char(112),char(50),char(0),char(109),char(95),char(103),char(108),char(111),char(98),char(97),char(108), +char(67),char(102),char(109),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(80),char(101), +char(110),char(101),char(116),char(114),char(97),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109), +char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(84),char(117),char(114),char(110),char(69),char(114),char(112), +char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(111),char(112),char(0),char(109),char(95),char(119),char(97),char(114),char(109), +char(115),char(116),char(97),char(114),char(116),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(109),char(97),char(120), +char(71),char(121),char(114),char(111),char(115),char(99),char(111),char(112),char(105),char(99),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(115),char(105), +char(110),char(103),char(108),char(101),char(65),char(120),char(105),char(115),char(82),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99),char(116), +char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(110),char(117),char(109),char(73),char(116), +char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(77),char(111),char(100), +char(101),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(105),char(110),char(103),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(82),char(101), +char(115),char(116),char(105),char(116),char(117),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109), +char(95),char(109),char(105),char(110),char(105),char(109),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(66),char(97),char(116),char(99),char(104),char(83), +char(105),char(122),char(101),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109), +char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97), +char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(118),char(111), +char(108),char(117),char(109),char(101),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(116), +char(101),char(114),char(105),char(97),char(108),char(0),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(112), +char(114),char(101),char(118),char(105),char(111),char(117),char(115),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(118),char(101), +char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(99),char(99),char(117),char(109),char(117),char(108),char(97),char(116),char(101),char(100), +char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(110),char(111),char(114),char(109),char(97),char(108),char(0),char(109),char(95),char(97),char(114),char(101), +char(97),char(0),char(109),char(95),char(97),char(116),char(116),char(97),char(99),char(104),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100), +char(105),char(99),char(101),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(76),char(101),char(110),char(103),char(116),char(104), +char(0),char(109),char(95),char(98),char(98),char(101),char(110),char(100),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110), +char(100),char(105),char(99),char(101),char(115),char(91),char(51),char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(65),char(114),char(101),char(97),char(0), +char(109),char(95),char(99),char(48),char(91),char(52),char(93),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101), +char(115),char(91),char(52),char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95), +char(99),char(49),char(0),char(109),char(95),char(99),char(50),char(0),char(109),char(95),char(99),char(48),char(0),char(109),char(95),char(108),char(111),char(99),char(97),char(108), +char(70),char(114),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(114),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(0),char(109), +char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(97),char(101),char(114),char(111),char(77),char(111),char(100), +char(101),char(108),char(0),char(109),char(95),char(98),char(97),char(117),char(109),char(103),char(97),char(114),char(116),char(101),char(0),char(109),char(95),char(100),char(114),char(97), +char(103),char(0),char(109),char(95),char(108),char(105),char(102),char(116),char(0),char(109),char(95),char(112),char(114),char(101),char(115),char(115),char(117),char(114),char(101),char(0), +char(109),char(95),char(118),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(100),char(121),char(110),char(97),char(109),char(105),char(99),char(70),char(114), +char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(112),char(111),char(115),char(101),char(77),char(97),char(116),char(99),char(104),char(0),char(109), +char(95),char(114),char(105),char(103),char(105),char(100),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115), +char(115),char(0),char(109),char(95),char(107),char(105),char(110),char(101),char(116),char(105),char(99),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97), +char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116), +char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114),char(72),char(97),char(114), +char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117), +char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75), +char(105),char(110),char(101),char(116),char(105),char(99),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115), +char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72), +char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67), +char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109), +char(95),char(115),char(111),char(102),char(116),char(75),char(105),char(110),char(101),char(116),char(105),char(99),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73), +char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(83),char(111), +char(102),char(116),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105), +char(116),char(0),char(109),char(95),char(109),char(97),char(120),char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(116),char(105),char(109),char(101), +char(83),char(99),char(97),char(108),char(101),char(0),char(109),char(95),char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(73),char(116),char(101),char(114), +char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(73),char(116),char(101), +char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(100),char(114),char(105),char(102),char(116),char(73),char(116),char(101),char(114),char(97), +char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(116),char(101),char(114),char(97), +char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(114),char(111),char(116),char(0),char(109),char(95),char(115),char(99),char(97),char(108),char(101),char(0), +char(109),char(95),char(97),char(113),char(113),char(0),char(109),char(95),char(99),char(111),char(109),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(105),char(116), +char(105),char(111),char(110),char(115),char(0),char(42),char(109),char(95),char(119),char(101),char(105),char(103),char(104),char(116),char(115),char(0),char(109),char(95),char(110),char(117), +char(109),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(87),char(101),char(105),char(103), +char(116),char(115),char(0),char(109),char(95),char(98),char(118),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(98),char(102),char(114),char(97),char(109), +char(101),char(0),char(109),char(95),char(102),char(114),char(97),char(109),char(101),char(120),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(108),char(111),char(99), +char(105),char(105),char(0),char(109),char(95),char(105),char(110),char(118),char(119),char(105),char(0),char(109),char(95),char(118),char(105),char(109),char(112),char(117),char(108),char(115), +char(101),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(100),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93), +char(0),char(109),char(95),char(108),char(118),char(0),char(109),char(95),char(97),char(118),char(0),char(42),char(109),char(95),char(102),char(114),char(97),char(109),char(101),char(114), +char(101),char(102),char(115),char(0),char(42),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(0),char(42), +char(109),char(95),char(109),char(97),char(115),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(114),char(97),char(109),char(101),char(82), +char(101),char(102),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(78),char(111),char(100),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109), +char(77),char(97),char(115),char(115),char(101),char(115),char(0),char(109),char(95),char(105),char(100),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(105),char(109), +char(97),char(115),char(115),char(0),char(109),char(95),char(110),char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(0),char(109),char(95),char(110), +char(100),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(97),char(109),char(112),char(105),char(110),char(103), +char(0),char(109),char(95),char(108),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(97),char(109),char(112),char(105), +char(110),char(103),char(0),char(109),char(95),char(109),char(97),char(116),char(99),char(104),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97),char(120),char(83), +char(101),char(108),char(102),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0), +char(109),char(95),char(115),char(101),char(108),char(102),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108), +char(115),char(101),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(105),char(110),char(115),char(65), +char(110),char(99),char(104),char(111),char(114),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(100),char(101),char(0),char(109),char(95),char(99),char(108), +char(117),char(115),char(116),char(101),char(114),char(73),char(110),char(100),char(101),char(120),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(0), +char(42),char(109),char(95),char(98),char(111),char(100),char(121),char(66),char(0),char(109),char(95),char(114),char(101),char(102),char(115),char(91),char(50),char(93),char(0),char(109), +char(95),char(99),char(102),char(109),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(100),char(101),char(108),char(101),char(116), +char(101),char(0),char(109),char(95),char(114),char(101),char(108),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(91),char(50),char(93),char(0),char(109), +char(95),char(98),char(111),char(100),char(121),char(65),char(116),char(121),char(112),char(101),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(66),char(116),char(121), +char(112),char(101),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(42),char(109),char(95),char(112),char(111), +char(115),char(101),char(0),char(42),char(42),char(109),char(95),char(109),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(42),char(109),char(95), +char(110),char(111),char(100),char(101),char(115),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(115),char(0),char(42),char(109),char(95),char(102),char(97), +char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(116),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(42),char(109), +char(95),char(97),char(110),char(99),char(104),char(111),char(114),char(115),char(0),char(42),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(115), +char(0),char(42),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(116),char(101), +char(114),char(105),char(97),char(108),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(76),char(105),char(110),char(107),char(115),char(0),char(109),char(95),char(110), +char(117),char(109),char(70),char(97),char(99),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(84),char(101),char(116),char(114),char(97),char(104),char(101), +char(100),char(114),char(97),char(0),char(109),char(95),char(110),char(117),char(109),char(65),char(110),char(99),char(104),char(111),char(114),char(115),char(0),char(109),char(95),char(110), +char(117),char(109),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(74),char(111),char(105),char(110), +char(116),char(115),char(0),char(109),char(95),char(99),char(111),char(110),char(102),char(105),char(103),char(0),char(84),char(89),char(80),char(69),char(76),char(0),char(0),char(0), +char(99),char(104),char(97),char(114),char(0),char(117),char(99),char(104),char(97),char(114),char(0),char(115),char(104),char(111),char(114),char(116),char(0),char(117),char(115),char(104), +char(111),char(114),char(116),char(0),char(105),char(110),char(116),char(0),char(108),char(111),char(110),char(103),char(0),char(117),char(108),char(111),char(110),char(103),char(0),char(102), +char(108),char(111),char(97),char(116),char(0),char(100),char(111),char(117),char(98),char(108),char(101),char(0),char(118),char(111),char(105),char(100),char(0),char(80),char(111),char(105), +char(110),char(116),char(101),char(114),char(65),char(114),char(114),char(97),char(121),char(0),char(98),char(116),char(80),char(104),char(121),char(115),char(105),char(99),char(115),char(83), +char(121),char(115),char(116),char(101),char(109),char(0),char(76),char(105),char(115),char(116),char(66),char(97),char(115),char(101),char(0),char(98),char(116),char(86),char(101),char(99), +char(116),char(111),char(114),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(86),char(101),char(99),char(116), +char(111),char(114),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116),char(114), +char(105),char(120),char(51),char(120),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116), +char(114),char(105),char(120),char(51),char(120),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84), +char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116), +char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0), +char(98),char(116),char(66),char(118),char(104),char(83),char(117),char(98),char(116),char(114),char(101),char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),char(97), +char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(70), +char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),char(100), +char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116), +char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(97),char(116),char(97), +char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(70),char(108),char(111),char(97),char(116), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(68), +char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111), +char(110),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(97),char(116),char(105),char(99),char(80), +char(108),char(97),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118), +char(101),char(120),char(73),char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0), +char(98),char(116),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(110),char(100),char(82),char(97),char(100),char(105),char(117),char(115),char(0), +char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(83),char(112),char(104),char(101),char(114),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),char(116), +char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),char(116), +char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),char(112),char(108),char(101),char(116), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(104),char(97),char(114),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),char(112), +char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(101),char(115),char(104),char(80),char(97),char(114),char(116),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(114),char(105),char(100),char(105),char(110),char(103),char(77),char(101),char(115),char(104),char(73),char(110),char(116), +char(101),char(114),char(102),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108), +char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105), +char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111),char(77),char(97),char(112),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83), +char(99),char(97),char(108),char(101),char(100),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97), +char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),char(97), +char(112),char(101),char(67),char(104),char(105),char(108),char(100),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117), +char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(121),char(108),char(105),char(110),char(100), +char(101),char(114),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(97),char(112),char(115),char(117),char(108), +char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108), +char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(73),char(109),char(112),char(97),char(99),char(116),char(77), +char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118),char(101), +char(120),char(72),char(117),char(108),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108), +char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116), +char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115), +char(87),char(111),char(114),char(108),char(100),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111), +char(110),char(116),char(97),char(99),char(116),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(68),char(111),char(117),char(98),char(108), +char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115),char(87),char(111),char(114),char(108), +char(100),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116), +char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0), +char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97), +char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(110),char(102),char(111),char(49), +char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(68),char(97),char(116),char(97),char(0),char(98), +char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), +char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50), +char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108), +char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97), +char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103), +char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97), +char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), +char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102), +char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110), +char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(67),char(111),char(110),char(115),char(116),char(114), +char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(108),char(105),char(100),char(101),char(114),char(67),char(111),char(110), +char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121), +char(77),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100), +char(121),char(78),char(111),char(100),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(76),char(105), +char(110),char(107),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(70),char(97),char(99),char(101),char(68), +char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(84),char(101),char(116),char(114),char(97),char(68),char(97),char(116), +char(97),char(0),char(83),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(65),char(110),char(99),char(104),char(111),char(114),char(68),char(97),char(116), +char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(67),char(111),char(110),char(102),char(105),char(103),char(68),char(97),char(116),char(97), +char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(80),char(111),char(115),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111), +char(102),char(116),char(66),char(111),char(100),char(121),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(68),char(97),char(116),char(97),char(0),char(98),char(116), +char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(74),char(111),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116), +char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(0),char(0), +char(84),char(76),char(69),char(78),char(1),char(0),char(1),char(0),char(2),char(0),char(2),char(0),char(4),char(0),char(4),char(0),char(4),char(0),char(4),char(0), +char(8),char(0),char(0),char(0),char(16),char(0),char(48),char(0),char(16),char(0),char(16),char(0),char(32),char(0),char(48),char(0),char(96),char(0),char(64),char(0), +char(-128),char(0),char(20),char(0),char(48),char(0),char(80),char(0),char(16),char(0),char(96),char(0),char(-112),char(0),char(16),char(0),char(56),char(0),char(56),char(0), +char(20),char(0),char(72),char(0),char(4),char(0),char(4),char(0),char(8),char(0),char(4),char(0),char(56),char(0),char(32),char(0),char(80),char(0),char(72),char(0), +char(96),char(0),char(80),char(0),char(32),char(0),char(64),char(0),char(64),char(0),char(16),char(0),char(72),char(0),char(80),char(0),char(-32),char(1),char(16),char(1), +char(-72),char(0),char(-104),char(0),char(104),char(0),char(88),char(0),char(-8),char(1),char(-80),char(3),char(8),char(0),char(64),char(0),char(0),char(0),char(96),char(0), +char(-128),char(0),char(104),char(1),char(-24),char(0),char(-32),char(0),char(8),char(1),char(104),char(1),char(-40),char(0),char(16),char(0),char(104),char(0),char(24),char(0), +char(40),char(0),char(104),char(0),char(96),char(0),char(104),char(0),char(-56),char(0),char(104),char(1),char(112),char(0),char(-32),char(1),char(83),char(84),char(82),char(67), +char(65),char(0),char(0),char(0),char(10),char(0),char(3),char(0),char(4),char(0),char(0),char(0),char(4),char(0),char(1),char(0),char(9),char(0),char(2),char(0), +char(11),char(0),char(3),char(0),char(10),char(0),char(3),char(0),char(10),char(0),char(4),char(0),char(10),char(0),char(5),char(0),char(12),char(0),char(2),char(0), +char(9),char(0),char(6),char(0),char(9),char(0),char(7),char(0),char(13),char(0),char(1),char(0),char(7),char(0),char(8),char(0),char(14),char(0),char(1),char(0), +char(8),char(0),char(8),char(0),char(15),char(0),char(1),char(0),char(13),char(0),char(9),char(0),char(16),char(0),char(1),char(0),char(14),char(0),char(9),char(0), +char(17),char(0),char(2),char(0),char(15),char(0),char(10),char(0),char(13),char(0),char(11),char(0),char(18),char(0),char(2),char(0),char(16),char(0),char(10),char(0), +char(14),char(0),char(11),char(0),char(19),char(0),char(4),char(0),char(4),char(0),char(12),char(0),char(4),char(0),char(13),char(0),char(2),char(0),char(14),char(0), +char(2),char(0),char(15),char(0),char(20),char(0),char(6),char(0),char(13),char(0),char(16),char(0),char(13),char(0),char(17),char(0),char(4),char(0),char(18),char(0), +char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0),char(21),char(0),char(6),char(0),char(14),char(0),char(16),char(0), +char(14),char(0),char(17),char(0),char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0), +char(22),char(0),char(3),char(0),char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0),char(4),char(0),char(22),char(0),char(23),char(0),char(12),char(0), +char(13),char(0),char(23),char(0),char(13),char(0),char(24),char(0),char(13),char(0),char(25),char(0),char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0), +char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0),char(20),char(0),char(30),char(0),char(22),char(0),char(31),char(0),char(19),char(0),char(32),char(0), +char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),char(24),char(0),char(12),char(0),char(14),char(0),char(23),char(0),char(14),char(0),char(24),char(0), +char(14),char(0),char(25),char(0),char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0), +char(21),char(0),char(30),char(0),char(22),char(0),char(31),char(0),char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),char(19),char(0),char(32),char(0), +char(25),char(0),char(3),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(36),char(0),char(0),char(0),char(37),char(0),char(26),char(0),char(5),char(0), +char(25),char(0),char(38),char(0),char(13),char(0),char(39),char(0),char(13),char(0),char(40),char(0),char(7),char(0),char(41),char(0),char(0),char(0),char(21),char(0), +char(27),char(0),char(5),char(0),char(25),char(0),char(38),char(0),char(13),char(0),char(39),char(0),char(13),char(0),char(42),char(0),char(7),char(0),char(43),char(0), +char(4),char(0),char(44),char(0),char(28),char(0),char(2),char(0),char(13),char(0),char(45),char(0),char(7),char(0),char(46),char(0),char(29),char(0),char(4),char(0), +char(27),char(0),char(47),char(0),char(28),char(0),char(48),char(0),char(4),char(0),char(49),char(0),char(0),char(0),char(37),char(0),char(30),char(0),char(1),char(0), +char(4),char(0),char(50),char(0),char(31),char(0),char(2),char(0),char(2),char(0),char(50),char(0),char(0),char(0),char(51),char(0),char(32),char(0),char(2),char(0), +char(2),char(0),char(52),char(0),char(0),char(0),char(51),char(0),char(33),char(0),char(2),char(0),char(0),char(0),char(52),char(0),char(0),char(0),char(53),char(0), +char(34),char(0),char(8),char(0),char(13),char(0),char(54),char(0),char(14),char(0),char(55),char(0),char(30),char(0),char(56),char(0),char(32),char(0),char(57),char(0), +char(33),char(0),char(58),char(0),char(31),char(0),char(59),char(0),char(4),char(0),char(60),char(0),char(4),char(0),char(61),char(0),char(35),char(0),char(4),char(0), +char(34),char(0),char(62),char(0),char(13),char(0),char(63),char(0),char(4),char(0),char(64),char(0),char(0),char(0),char(37),char(0),char(36),char(0),char(7),char(0), +char(25),char(0),char(38),char(0),char(35),char(0),char(65),char(0),char(23),char(0),char(66),char(0),char(24),char(0),char(67),char(0),char(37),char(0),char(68),char(0), +char(7),char(0),char(43),char(0),char(0),char(0),char(69),char(0),char(38),char(0),char(2),char(0),char(36),char(0),char(70),char(0),char(13),char(0),char(39),char(0), +char(39),char(0),char(4),char(0),char(17),char(0),char(71),char(0),char(25),char(0),char(72),char(0),char(4),char(0),char(73),char(0),char(7),char(0),char(74),char(0), +char(40),char(0),char(4),char(0),char(25),char(0),char(38),char(0),char(39),char(0),char(75),char(0),char(4),char(0),char(76),char(0),char(7),char(0),char(43),char(0), +char(41),char(0),char(3),char(0),char(27),char(0),char(47),char(0),char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),char(42),char(0),char(3),char(0), +char(27),char(0),char(47),char(0),char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),char(43),char(0),char(4),char(0),char(4),char(0),char(78),char(0), +char(7),char(0),char(79),char(0),char(7),char(0),char(80),char(0),char(7),char(0),char(81),char(0),char(37),char(0),char(14),char(0),char(4),char(0),char(82),char(0), +char(4),char(0),char(83),char(0),char(43),char(0),char(84),char(0),char(4),char(0),char(85),char(0),char(7),char(0),char(86),char(0),char(7),char(0),char(87),char(0), +char(7),char(0),char(88),char(0),char(7),char(0),char(89),char(0),char(7),char(0),char(90),char(0),char(4),char(0),char(91),char(0),char(4),char(0),char(92),char(0), +char(4),char(0),char(93),char(0),char(4),char(0),char(94),char(0),char(0),char(0),char(37),char(0),char(44),char(0),char(5),char(0),char(25),char(0),char(38),char(0), +char(35),char(0),char(65),char(0),char(13),char(0),char(39),char(0),char(7),char(0),char(43),char(0),char(4),char(0),char(95),char(0),char(45),char(0),char(5),char(0), +char(27),char(0),char(47),char(0),char(13),char(0),char(96),char(0),char(14),char(0),char(97),char(0),char(4),char(0),char(98),char(0),char(0),char(0),char(99),char(0), +char(46),char(0),char(25),char(0),char(9),char(0),char(100),char(0),char(9),char(0),char(101),char(0),char(25),char(0),char(102),char(0),char(0),char(0),char(35),char(0), +char(18),char(0),char(103),char(0),char(18),char(0),char(104),char(0),char(14),char(0),char(105),char(0),char(14),char(0),char(106),char(0),char(14),char(0),char(107),char(0), +char(8),char(0),char(108),char(0),char(8),char(0),char(109),char(0),char(8),char(0),char(110),char(0),char(8),char(0),char(111),char(0),char(8),char(0),char(112),char(0), +char(8),char(0),char(113),char(0),char(8),char(0),char(114),char(0),char(8),char(0),char(115),char(0),char(4),char(0),char(116),char(0),char(4),char(0),char(117),char(0), +char(4),char(0),char(118),char(0),char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0),char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0), +char(0),char(0),char(37),char(0),char(47),char(0),char(25),char(0),char(9),char(0),char(100),char(0),char(9),char(0),char(101),char(0),char(25),char(0),char(102),char(0), +char(0),char(0),char(35),char(0),char(17),char(0),char(103),char(0),char(17),char(0),char(104),char(0),char(13),char(0),char(105),char(0),char(13),char(0),char(106),char(0), +char(13),char(0),char(107),char(0),char(7),char(0),char(108),char(0),char(7),char(0),char(109),char(0),char(7),char(0),char(110),char(0),char(7),char(0),char(111),char(0), +char(7),char(0),char(112),char(0),char(7),char(0),char(113),char(0),char(7),char(0),char(114),char(0),char(7),char(0),char(115),char(0),char(4),char(0),char(116),char(0), +char(4),char(0),char(117),char(0),char(4),char(0),char(118),char(0),char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0),char(4),char(0),char(121),char(0), +char(4),char(0),char(122),char(0),char(0),char(0),char(37),char(0),char(48),char(0),char(2),char(0),char(49),char(0),char(123),char(0),char(14),char(0),char(124),char(0), +char(50),char(0),char(2),char(0),char(51),char(0),char(123),char(0),char(13),char(0),char(124),char(0),char(52),char(0),char(21),char(0),char(47),char(0),char(125),char(0), +char(15),char(0),char(126),char(0),char(13),char(0),char(127),char(0),char(13),char(0),char(-128),char(0),char(13),char(0),char(-127),char(0),char(13),char(0),char(-126),char(0), +char(13),char(0),char(124),char(0),char(13),char(0),char(-125),char(0),char(13),char(0),char(-124),char(0),char(13),char(0),char(-123),char(0),char(13),char(0),char(-122),char(0), +char(7),char(0),char(-121),char(0),char(7),char(0),char(-120),char(0),char(7),char(0),char(-119),char(0),char(7),char(0),char(-118),char(0),char(7),char(0),char(-117),char(0), +char(7),char(0),char(-116),char(0),char(7),char(0),char(-115),char(0),char(7),char(0),char(-114),char(0),char(7),char(0),char(-113),char(0),char(4),char(0),char(-112),char(0), +char(53),char(0),char(22),char(0),char(46),char(0),char(125),char(0),char(16),char(0),char(126),char(0),char(14),char(0),char(127),char(0),char(14),char(0),char(-128),char(0), +char(14),char(0),char(-127),char(0),char(14),char(0),char(-126),char(0),char(14),char(0),char(124),char(0),char(14),char(0),char(-125),char(0),char(14),char(0),char(-124),char(0), +char(14),char(0),char(-123),char(0),char(14),char(0),char(-122),char(0),char(8),char(0),char(-121),char(0),char(8),char(0),char(-120),char(0),char(8),char(0),char(-119),char(0), +char(8),char(0),char(-118),char(0),char(8),char(0),char(-117),char(0),char(8),char(0),char(-116),char(0),char(8),char(0),char(-115),char(0),char(8),char(0),char(-114),char(0), +char(8),char(0),char(-113),char(0),char(4),char(0),char(-112),char(0),char(0),char(0),char(37),char(0),char(54),char(0),char(2),char(0),char(4),char(0),char(-111),char(0), +char(4),char(0),char(-110),char(0),char(55),char(0),char(13),char(0),char(56),char(0),char(-109),char(0),char(56),char(0),char(-108),char(0),char(0),char(0),char(35),char(0), +char(4),char(0),char(-107),char(0),char(4),char(0),char(-106),char(0),char(4),char(0),char(-105),char(0),char(4),char(0),char(-104),char(0),char(7),char(0),char(-103),char(0), +char(7),char(0),char(-102),char(0),char(4),char(0),char(-101),char(0),char(4),char(0),char(-100),char(0),char(7),char(0),char(-99),char(0),char(4),char(0),char(-98),char(0), +char(57),char(0),char(3),char(0),char(55),char(0),char(-97),char(0),char(13),char(0),char(-96),char(0),char(13),char(0),char(-95),char(0),char(58),char(0),char(3),char(0), +char(55),char(0),char(-97),char(0),char(14),char(0),char(-96),char(0),char(14),char(0),char(-95),char(0),char(59),char(0),char(13),char(0),char(55),char(0),char(-97),char(0), +char(18),char(0),char(-94),char(0),char(18),char(0),char(-93),char(0),char(4),char(0),char(-92),char(0),char(4),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0), +char(7),char(0),char(-89),char(0),char(7),char(0),char(-88),char(0),char(7),char(0),char(-87),char(0),char(7),char(0),char(-86),char(0),char(7),char(0),char(-85),char(0), +char(7),char(0),char(-84),char(0),char(7),char(0),char(-83),char(0),char(60),char(0),char(13),char(0),char(55),char(0),char(-97),char(0),char(17),char(0),char(-94),char(0), +char(17),char(0),char(-93),char(0),char(4),char(0),char(-92),char(0),char(4),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),char(7),char(0),char(-89),char(0), +char(7),char(0),char(-88),char(0),char(7),char(0),char(-87),char(0),char(7),char(0),char(-86),char(0),char(7),char(0),char(-85),char(0),char(7),char(0),char(-84),char(0), +char(7),char(0),char(-83),char(0),char(61),char(0),char(11),char(0),char(55),char(0),char(-97),char(0),char(17),char(0),char(-94),char(0),char(17),char(0),char(-93),char(0), +char(7),char(0),char(-82),char(0),char(7),char(0),char(-81),char(0),char(7),char(0),char(-80),char(0),char(7),char(0),char(-85),char(0),char(7),char(0),char(-84),char(0), +char(7),char(0),char(-83),char(0),char(7),char(0),char(-79),char(0),char(0),char(0),char(21),char(0),char(62),char(0),char(9),char(0),char(55),char(0),char(-97),char(0), +char(17),char(0),char(-94),char(0),char(17),char(0),char(-93),char(0),char(13),char(0),char(-78),char(0),char(13),char(0),char(-77),char(0),char(13),char(0),char(-76),char(0), +char(13),char(0),char(-75),char(0),char(4),char(0),char(-74),char(0),char(4),char(0),char(-73),char(0),char(63),char(0),char(5),char(0),char(62),char(0),char(-72),char(0), +char(4),char(0),char(-71),char(0),char(7),char(0),char(-70),char(0),char(7),char(0),char(-69),char(0),char(7),char(0),char(-68),char(0),char(64),char(0),char(9),char(0), +char(55),char(0),char(-97),char(0),char(17),char(0),char(-94),char(0),char(17),char(0),char(-93),char(0),char(7),char(0),char(-78),char(0),char(7),char(0),char(-77),char(0), +char(7),char(0),char(-76),char(0),char(7),char(0),char(-75),char(0),char(4),char(0),char(-74),char(0),char(4),char(0),char(-73),char(0),char(49),char(0),char(22),char(0), +char(8),char(0),char(-67),char(0),char(8),char(0),char(-79),char(0),char(8),char(0),char(110),char(0),char(8),char(0),char(-66),char(0),char(8),char(0),char(112),char(0), +char(8),char(0),char(-65),char(0),char(8),char(0),char(-64),char(0),char(8),char(0),char(-63),char(0),char(8),char(0),char(-62),char(0),char(8),char(0),char(-61),char(0), +char(8),char(0),char(-60),char(0),char(8),char(0),char(-59),char(0),char(8),char(0),char(-58),char(0),char(8),char(0),char(-57),char(0),char(8),char(0),char(-56),char(0), +char(8),char(0),char(-55),char(0),char(4),char(0),char(-54),char(0),char(4),char(0),char(-53),char(0),char(4),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0), +char(4),char(0),char(-50),char(0),char(0),char(0),char(37),char(0),char(51),char(0),char(22),char(0),char(7),char(0),char(-67),char(0),char(7),char(0),char(-79),char(0), +char(7),char(0),char(110),char(0),char(7),char(0),char(-66),char(0),char(7),char(0),char(112),char(0),char(7),char(0),char(-65),char(0),char(7),char(0),char(-64),char(0), +char(7),char(0),char(-63),char(0),char(7),char(0),char(-62),char(0),char(7),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0),char(7),char(0),char(-59),char(0), +char(7),char(0),char(-58),char(0),char(7),char(0),char(-57),char(0),char(7),char(0),char(-56),char(0),char(7),char(0),char(-55),char(0),char(4),char(0),char(-54),char(0), +char(4),char(0),char(-53),char(0),char(4),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0),char(0),char(0),char(37),char(0), +char(65),char(0),char(4),char(0),char(7),char(0),char(-49),char(0),char(7),char(0),char(-48),char(0),char(7),char(0),char(-47),char(0),char(4),char(0),char(78),char(0), +char(66),char(0),char(10),char(0),char(65),char(0),char(-46),char(0),char(13),char(0),char(-45),char(0),char(13),char(0),char(-44),char(0),char(13),char(0),char(-43),char(0), +char(13),char(0),char(-42),char(0),char(13),char(0),char(-41),char(0),char(7),char(0),char(-121),char(0),char(7),char(0),char(-40),char(0),char(4),char(0),char(-39),char(0), +char(4),char(0),char(53),char(0),char(67),char(0),char(4),char(0),char(65),char(0),char(-46),char(0),char(4),char(0),char(-38),char(0),char(7),char(0),char(-37),char(0), +char(4),char(0),char(-36),char(0),char(68),char(0),char(4),char(0),char(13),char(0),char(-41),char(0),char(65),char(0),char(-46),char(0),char(4),char(0),char(-35),char(0), +char(7),char(0),char(-34),char(0),char(69),char(0),char(7),char(0),char(13),char(0),char(-33),char(0),char(65),char(0),char(-46),char(0),char(4),char(0),char(-32),char(0), +char(7),char(0),char(-31),char(0),char(7),char(0),char(-30),char(0),char(7),char(0),char(-29),char(0),char(4),char(0),char(53),char(0),char(70),char(0),char(6),char(0), +char(15),char(0),char(-28),char(0),char(13),char(0),char(-30),char(0),char(13),char(0),char(-27),char(0),char(56),char(0),char(-26),char(0),char(4),char(0),char(-25),char(0), +char(7),char(0),char(-29),char(0),char(71),char(0),char(26),char(0),char(4),char(0),char(-24),char(0),char(7),char(0),char(-23),char(0),char(7),char(0),char(-79),char(0), +char(7),char(0),char(-22),char(0),char(7),char(0),char(-21),char(0),char(7),char(0),char(-20),char(0),char(7),char(0),char(-19),char(0),char(7),char(0),char(-18),char(0), +char(7),char(0),char(-17),char(0),char(7),char(0),char(-16),char(0),char(7),char(0),char(-15),char(0),char(7),char(0),char(-14),char(0),char(7),char(0),char(-13),char(0), +char(7),char(0),char(-12),char(0),char(7),char(0),char(-11),char(0),char(7),char(0),char(-10),char(0),char(7),char(0),char(-9),char(0),char(7),char(0),char(-8),char(0), +char(7),char(0),char(-7),char(0),char(7),char(0),char(-6),char(0),char(7),char(0),char(-5),char(0),char(4),char(0),char(-4),char(0),char(4),char(0),char(-3),char(0), +char(4),char(0),char(-2),char(0),char(4),char(0),char(-1),char(0),char(4),char(0),char(117),char(0),char(72),char(0),char(12),char(0),char(15),char(0),char(0),char(1), +char(15),char(0),char(1),char(1),char(15),char(0),char(2),char(1),char(13),char(0),char(3),char(1),char(13),char(0),char(4),char(1),char(7),char(0),char(5),char(1), +char(4),char(0),char(6),char(1),char(4),char(0),char(7),char(1),char(4),char(0),char(8),char(1),char(4),char(0),char(9),char(1),char(7),char(0),char(-31),char(0), +char(4),char(0),char(53),char(0),char(73),char(0),char(27),char(0),char(17),char(0),char(10),char(1),char(15),char(0),char(11),char(1),char(15),char(0),char(12),char(1), +char(13),char(0),char(3),char(1),char(13),char(0),char(13),char(1),char(13),char(0),char(14),char(1),char(13),char(0),char(15),char(1),char(13),char(0),char(16),char(1), +char(13),char(0),char(17),char(1),char(4),char(0),char(18),char(1),char(7),char(0),char(19),char(1),char(4),char(0),char(20),char(1),char(4),char(0),char(21),char(1), +char(4),char(0),char(22),char(1),char(7),char(0),char(23),char(1),char(7),char(0),char(24),char(1),char(4),char(0),char(25),char(1),char(4),char(0),char(26),char(1), +char(7),char(0),char(27),char(1),char(7),char(0),char(28),char(1),char(7),char(0),char(29),char(1),char(7),char(0),char(30),char(1),char(7),char(0),char(31),char(1), +char(7),char(0),char(32),char(1),char(4),char(0),char(33),char(1),char(4),char(0),char(34),char(1),char(4),char(0),char(35),char(1),char(74),char(0),char(12),char(0), +char(9),char(0),char(36),char(1),char(9),char(0),char(37),char(1),char(13),char(0),char(38),char(1),char(7),char(0),char(39),char(1),char(7),char(0),char(-63),char(0), +char(7),char(0),char(40),char(1),char(4),char(0),char(41),char(1),char(13),char(0),char(42),char(1),char(4),char(0),char(43),char(1),char(4),char(0),char(44),char(1), +char(4),char(0),char(45),char(1),char(4),char(0),char(53),char(0),char(75),char(0),char(19),char(0),char(47),char(0),char(125),char(0),char(72),char(0),char(46),char(1), +char(65),char(0),char(47),char(1),char(66),char(0),char(48),char(1),char(67),char(0),char(49),char(1),char(68),char(0),char(50),char(1),char(69),char(0),char(51),char(1), +char(70),char(0),char(52),char(1),char(73),char(0),char(53),char(1),char(74),char(0),char(54),char(1),char(4),char(0),char(55),char(1),char(4),char(0),char(21),char(1), +char(4),char(0),char(56),char(1),char(4),char(0),char(57),char(1),char(4),char(0),char(58),char(1),char(4),char(0),char(59),char(1),char(4),char(0),char(60),char(1), +char(4),char(0),char(61),char(1),char(71),char(0),char(62),char(1),}; +int b3s_bulletDNAlen64= sizeof(b3s_bulletDNAstr64); diff --git a/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3Serializer.h b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3Serializer.h new file mode 100644 index 000000000000..1c1ce4376473 --- /dev/null +++ b/extern/bullet/src/Bullet3Serialize/Bullet2FileLoader/b3Serializer.h @@ -0,0 +1,639 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org + +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 B3_SERIALIZER_H +#define B3_SERIALIZER_H + +#include "Bullet3Common/b3Scalar.h" // has definitions like B3_FORCE_INLINE +#include "Bullet3Common/b3StackAlloc.h" +#include "Bullet3Common/b3HashMap.h" + +#if !defined( __CELLOS_LV2__) && !defined(__MWERKS__) +#include +#endif +#include + + + +extern char b3s_bulletDNAstr[]; +extern int b3s_bulletDNAlen; +extern char b3s_bulletDNAstr64[]; +extern int b3s_bulletDNAlen64; + +B3_FORCE_INLINE int b3StrLen(const char* str) +{ + if (!str) + return(0); + int len = 0; + + while (*str != 0) + { + str++; + len++; + } + + return len; +} + + +class b3Chunk +{ +public: + int m_chunkCode; + int m_length; + void *m_oldPtr; + int m_dna_nr; + int m_number; +}; + +enum b3SerializationFlags +{ + B3_SERIALIZE_NO_BVH = 1, + B3_SERIALIZE_NO_TRIANGLEINFOMAP = 2, + B3_SERIALIZE_NO_DUPLICATE_ASSERT = 4 +}; + +class b3Serializer +{ + +public: + + virtual ~b3Serializer() {} + + virtual const unsigned char* getBufferPointer() const = 0; + + virtual int getCurrentBufferSize() const = 0; + + virtual b3Chunk* allocate(size_t size, int numElements) = 0; + + virtual void finalizeChunk(b3Chunk* chunk, const char* structType, int chunkCode,void* oldPtr)= 0; + + virtual void* findPointer(void* oldPtr) = 0; + + virtual void* getUniquePointer(void*oldPtr) = 0; + + virtual void startSerialization() = 0; + + virtual void finishSerialization() = 0; + + virtual const char* findNameForPointer(const void* ptr) const = 0; + + virtual void registerNameForPointer(const void* ptr, const char* name) = 0; + + virtual void serializeName(const char* ptr) = 0; + + virtual int getSerializationFlags() const = 0; + + virtual void setSerializationFlags(int flags) = 0; + + +}; + + + +#define B3_HEADER_LENGTH 12 +#if defined(__sgi) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__) +# define B3_MAKE_ID(a,b,c,d) ( (int)(a)<<24 | (int)(b)<<16 | (c)<<8 | (d) ) +#else +# define B3_MAKE_ID(a,b,c,d) ( (int)(d)<<24 | (int)(c)<<16 | (b)<<8 | (a) ) +#endif + +#define B3_SOFTBODY_CODE B3_MAKE_ID('S','B','D','Y') +#define B3_COLLISIONOBJECT_CODE B3_MAKE_ID('C','O','B','J') +#define B3_RIGIDBODY_CODE B3_MAKE_ID('R','B','D','Y') +#define B3_CONSTRAINT_CODE B3_MAKE_ID('C','O','N','S') +#define B3_BOXSHAPE_CODE B3_MAKE_ID('B','O','X','S') +#define B3_QUANTIZED_BVH_CODE B3_MAKE_ID('Q','B','V','H') +#define B3_TRIANLGE_INFO_MAP B3_MAKE_ID('T','M','A','P') +#define B3_SHAPE_CODE B3_MAKE_ID('S','H','A','P') +#define B3_ARRAY_CODE B3_MAKE_ID('A','R','A','Y') +#define B3_SBMATERIAL_CODE B3_MAKE_ID('S','B','M','T') +#define B3_SBNODE_CODE B3_MAKE_ID('S','B','N','D') +#define B3_DYNAMICSWORLD_CODE B3_MAKE_ID('D','W','L','D') +#define B3_DNA_CODE B3_MAKE_ID('D','N','A','1') + + +struct b3PointerUid +{ + union + { + void* m_ptr; + int m_uniqueIds[2]; + }; +}; + +///The b3DefaultSerializer is the main Bullet serialization class. +///The constructor takes an optional argument for backwards compatibility, it is recommended to leave this empty/zero. +class b3DefaultSerializer : public b3Serializer +{ + + + b3AlignedObjectArray mTypes; + b3AlignedObjectArray mStructs; + b3AlignedObjectArray mTlens; + b3HashMap mStructReverse; + b3HashMap mTypeLookup; + + + b3HashMap m_chunkP; + + b3HashMap m_nameMap; + + b3HashMap m_uniquePointers; + int m_uniqueIdGenerator; + + int m_totalSize; + unsigned char* m_buffer; + int m_currentSize; + void* m_dna; + int m_dnaLength; + + int m_serializationFlags; + + + b3AlignedObjectArray m_chunkPtrs; + +protected: + + virtual void* findPointer(void* oldPtr) + { + void** ptr = m_chunkP.find(oldPtr); + if (ptr && *ptr) + return *ptr; + return 0; + } + + + + + + void writeDNA() + { + b3Chunk* dnaChunk = allocate(m_dnaLength,1); + memcpy(dnaChunk->m_oldPtr,m_dna,m_dnaLength); + finalizeChunk(dnaChunk,"DNA1",B3_DNA_CODE, m_dna); + } + + int getReverseType(const char *type) const + { + + b3HashString key(type); + const int* valuePtr = mTypeLookup.find(key); + if (valuePtr) + return *valuePtr; + + return -1; + } + + void initDNA(const char* bdnaOrg,int dnalen) + { + ///was already initialized + if (m_dna) + return; + + int littleEndian= 1; + littleEndian= ((char*)&littleEndian)[0]; + + + m_dna = b3AlignedAlloc(dnalen,16); + memcpy(m_dna,bdnaOrg,dnalen); + m_dnaLength = dnalen; + + int *intPtr=0; + short *shtPtr=0; + char *cp = 0;int dataLen =0; + intPtr = (int*)m_dna; + + /* + SDNA (4 bytes) (magic number) + NAME (4 bytes) + (4 bytes) amount of names (int) + + + */ + + if (strncmp((const char*)m_dna, "SDNA", 4)==0) + { + // skip ++ NAME + intPtr++; intPtr++; + } + + // Parse names + if (!littleEndian) + *intPtr = b3SwapEndian(*intPtr); + + dataLen = *intPtr; + + intPtr++; + + cp = (char*)intPtr; + int i; + for ( i=0; i amount of types (int) + + + */ + + intPtr = (int*)cp; + b3Assert(strncmp(cp, "TYPE", 4)==0); intPtr++; + + if (!littleEndian) + *intPtr = b3SwapEndian(*intPtr); + + dataLen = *intPtr; + intPtr++; + + + cp = (char*)intPtr; + for (i=0; i (short) the lengths of types + + */ + + // Parse type lens + intPtr = (int*)cp; + b3Assert(strncmp(cp, "TLEN", 4)==0); intPtr++; + + dataLen = (int)mTypes.size(); + + shtPtr = (short*)intPtr; + for (i=0; i amount of structs (int) + + + + + + + */ + + intPtr = (int*)shtPtr; + cp = (char*)intPtr; + b3Assert(strncmp(cp, "STRC", 4)==0); intPtr++; + + if (!littleEndian) + *intPtr = b3SwapEndian(*intPtr); + dataLen = *intPtr ; + intPtr++; + + + shtPtr = (short*)intPtr; + for (i=0; im_length; + memcpy(currentPtr,m_chunkPtrs[i], curLength); + b3AlignedFree(m_chunkPtrs[i]); + currentPtr+=curLength; + mysize+=curLength; + } + } + + mTypes.clear(); + mStructs.clear(); + mTlens.clear(); + mStructReverse.clear(); + mTypeLookup.clear(); + m_chunkP.clear(); + m_nameMap.clear(); + m_uniquePointers.clear(); + m_chunkPtrs.clear(); + } + + virtual void* getUniquePointer(void*oldPtr) + { + if (!oldPtr) + return 0; + + b3PointerUid* uptr = (b3PointerUid*)m_uniquePointers.find(oldPtr); + if (uptr) + { + return uptr->m_ptr; + } + m_uniqueIdGenerator++; + + b3PointerUid uid; + uid.m_uniqueIds[0] = m_uniqueIdGenerator; + uid.m_uniqueIds[1] = m_uniqueIdGenerator; + m_uniquePointers.insert(oldPtr,uid); + return uid.m_ptr; + + } + + virtual const unsigned char* getBufferPointer() const + { + return m_buffer; + } + + virtual int getCurrentBufferSize() const + { + return m_currentSize; + } + + virtual void finalizeChunk(b3Chunk* chunk, const char* structType, int chunkCode,void* oldPtr) + { + if (!(m_serializationFlags&B3_SERIALIZE_NO_DUPLICATE_ASSERT)) + { + b3Assert(!findPointer(oldPtr)); + } + + chunk->m_dna_nr = getReverseType(structType); + + chunk->m_chunkCode = chunkCode; + + void* uniquePtr = getUniquePointer(oldPtr); + + m_chunkP.insert(oldPtr,uniquePtr);//chunk->m_oldPtr); + chunk->m_oldPtr = uniquePtr;//oldPtr; + + } + + + virtual unsigned char* internalAlloc(size_t size) + { + unsigned char* ptr = 0; + + if (m_totalSize) + { + ptr = m_buffer+m_currentSize; + m_currentSize += int(size); + b3Assert(m_currentSizem_chunkCode = 0; + chunk->m_oldPtr = data; + chunk->m_length = int(size)*numElements; + chunk->m_number = numElements; + + m_chunkPtrs.push_back(chunk); + + + return chunk; + } + + virtual const char* findNameForPointer(const void* ptr) const + { + const char*const * namePtr = m_nameMap.find(ptr); + if (namePtr && *namePtr) + return *namePtr; + return 0; + + } + + virtual void registerNameForPointer(const void* ptr, const char* name) + { + m_nameMap.insert(ptr,name); + } + + virtual void serializeName(const char* name) + { + if (name) + { + //don't serialize name twice + if (findPointer((void*)name)) + return; + + int len = b3StrLen(name); + if (len) + { + + int newLen = len+1; + int padding = ((newLen+3)&~3)-newLen; + newLen += padding; + + //serialize name string now + b3Chunk* chunk = allocate(sizeof(char),newLen); + char* destinationName = (char*)chunk->m_oldPtr; + for (int i=0;i +{ +public: + + btAxisSweep3(const btVector3& worldAabbMin,const btVector3& worldAabbMax, unsigned short int maxHandles = 16384, btOverlappingPairCache* pairCache = 0, bool disableRaycastAccelerator = false); + +}; + +/// The bt32BitAxisSweep3 allows higher precision quantization and more objects compared to the btAxisSweep3 sweep and prune. +/// This comes at the cost of more memory per handle, and a bit slower performance. +/// It uses arrays rather then lists for storage of the 3 axis. +class bt32BitAxisSweep3 : public btAxisSweep3Internal +{ +public: + + bt32BitAxisSweep3(const btVector3& worldAabbMin,const btVector3& worldAabbMax, unsigned int maxHandles = 1500000, btOverlappingPairCache* pairCache = 0, bool disableRaycastAccelerator = false); + +}; + +#endif diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btAxisSweep3.h b/extern/bullet/src/BulletCollision/BroadphaseCollision/btAxisSweep3Internal.h similarity index 93% rename from extern/bullet2/src/BulletCollision/BroadphaseCollision/btAxisSweep3.h rename to extern/bullet/src/BulletCollision/BroadphaseCollision/btAxisSweep3Internal.h index cd6e1a8929e0..2c4d41bc041b 100644 --- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btAxisSweep3.h +++ b/extern/bullet/src/BulletCollision/BroadphaseCollision/btAxisSweep3Internal.h @@ -16,8 +16,8 @@ // // 3. This notice may not be removed or altered from any source distribution. -#ifndef BT_AXIS_SWEEP_3_H -#define BT_AXIS_SWEEP_3_H +#ifndef BT_AXIS_SWEEP_3_INTERNAL_H +#define BT_AXIS_SWEEP_3_INTERNAL_H #include "LinearMath/btVector3.h" #include "btOverlappingPairCache.h" @@ -134,7 +134,7 @@ class btAxisSweep3Internal : public btBroadphaseInterface virtual void calculateOverlappingPairs(btDispatcher* dispatcher); - BP_FP_INT_TYPE addHandle(const btVector3& aabbMin,const btVector3& aabbMax, void* pOwner,short int collisionFilterGroup,short int collisionFilterMask,btDispatcher* dispatcher,void* multiSapProxy); + BP_FP_INT_TYPE addHandle(const btVector3& aabbMin,const btVector3& aabbMax, void* pOwner, int collisionFilterGroup, int collisionFilterMask,btDispatcher* dispatcher); void removeHandle(BP_FP_INT_TYPE handle,btDispatcher* dispatcher); void updateHandle(BP_FP_INT_TYPE handle, const btVector3& aabbMin,const btVector3& aabbMax,btDispatcher* dispatcher); SIMD_FORCE_INLINE Handle* getHandle(BP_FP_INT_TYPE index) const {return m_pHandles + index;} @@ -144,7 +144,7 @@ class btAxisSweep3Internal : public btBroadphaseInterface void processAllOverlappingPairs(btOverlapCallback* callback); //Broadphase Interface - virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask,btDispatcher* dispatcher,void* multiSapProxy); + virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr , int collisionFilterGroup, int collisionFilterMask,btDispatcher* dispatcher); virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher); virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax,btDispatcher* dispatcher); virtual void getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const; @@ -228,16 +228,16 @@ void btAxisSweep3::debugPrintAxis(int axis, bool checkCardinalit #endif //DEBUG_BROADPHASE template -btBroadphaseProxy* btAxisSweep3Internal::createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr,short int collisionFilterGroup,short int collisionFilterMask,btDispatcher* dispatcher,void* multiSapProxy) +btBroadphaseProxy* btAxisSweep3Internal::createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, int collisionFilterGroup, int collisionFilterMask,btDispatcher* dispatcher) { (void)shapeType; - BP_FP_INT_TYPE handleId = addHandle(aabbMin,aabbMax, userPtr,collisionFilterGroup,collisionFilterMask,dispatcher,multiSapProxy); + BP_FP_INT_TYPE handleId = addHandle(aabbMin,aabbMax, userPtr,collisionFilterGroup,collisionFilterMask,dispatcher); Handle* handle = getHandle(handleId); if (m_raycastAccelerator) { - btBroadphaseProxy* rayProxy = m_raycastAccelerator->createProxy(aabbMin,aabbMax,shapeType,userPtr,collisionFilterGroup,collisionFilterMask,dispatcher,0); + btBroadphaseProxy* rayProxy = m_raycastAccelerator->createProxy(aabbMin,aabbMax,shapeType,userPtr,collisionFilterGroup,collisionFilterMask,dispatcher); handle->m_dbvtProxy = rayProxy; } return handle; @@ -502,7 +502,7 @@ void btAxisSweep3Internal::freeHandle(BP_FP_INT_TYPE handle) template -BP_FP_INT_TYPE btAxisSweep3Internal::addHandle(const btVector3& aabbMin,const btVector3& aabbMax, void* pOwner,short int collisionFilterGroup,short int collisionFilterMask,btDispatcher* dispatcher,void* multiSapProxy) +BP_FP_INT_TYPE btAxisSweep3Internal::addHandle(const btVector3& aabbMin,const btVector3& aabbMax, void* pOwner, int collisionFilterGroup, int collisionFilterMask,btDispatcher* dispatcher) { // quantize the bounds BP_FP_INT_TYPE min[3], max[3]; @@ -520,7 +520,6 @@ BP_FP_INT_TYPE btAxisSweep3Internal::addHandle(const btVector3& pHandle->m_clientObject = pOwner; pHandle->m_collisionFilterGroup = collisionFilterGroup; pHandle->m_collisionFilterMask = collisionFilterMask; - pHandle->m_multiSapParentProxy = multiSapProxy; // compute current limit of edge arrays BP_FP_INT_TYPE limit = static_cast(m_numHandles * 2); @@ -1020,32 +1019,4 @@ void btAxisSweep3Internal::sortMaxUp(int axis, BP_FP_INT_TYPE ed } - - -//////////////////////////////////////////////////////////////////// - - -/// The 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 16 bit integer coordinates instead of floats. -/// For large worlds and many objects, use bt32BitAxisSweep3 or btDbvtBroadphase instead. bt32BitAxisSweep3 has higher precision and allows more then 16384 objects at the cost of more memory and bit of performance. -class btAxisSweep3 : public btAxisSweep3Internal -{ -public: - - btAxisSweep3(const btVector3& worldAabbMin,const btVector3& worldAabbMax, unsigned short int maxHandles = 16384, btOverlappingPairCache* pairCache = 0, bool disableRaycastAccelerator = false); - -}; - -/// The bt32BitAxisSweep3 allows higher precision quantization and more objects compared to the btAxisSweep3 sweep and prune. -/// This comes at the cost of more memory per handle, and a bit slower performance. -/// It uses arrays rather then lists for storage of the 3 axis. -class bt32BitAxisSweep3 : public btAxisSweep3Internal -{ -public: - - bt32BitAxisSweep3(const btVector3& worldAabbMin,const btVector3& worldAabbMax, unsigned int maxHandles = 1500000, btOverlappingPairCache* pairCache = 0, bool disableRaycastAccelerator = false); - -}; - #endif - diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h b/extern/bullet/src/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h similarity index 94% rename from extern/bullet2/src/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h rename to extern/bullet/src/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h index f1bf00594d3b..fb68e0024e02 100644 --- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h +++ b/extern/bullet/src/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h @@ -41,6 +41,10 @@ struct btBroadphaseRayCallback : public btBroadphaseAabbCallback btScalar m_lambda_max; virtual ~btBroadphaseRayCallback() {} + +protected: + + btBroadphaseRayCallback() {} }; #include "LinearMath/btVector3.h" @@ -53,7 +57,7 @@ class btBroadphaseInterface public: virtual ~btBroadphaseInterface() {} - virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy) =0; + virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, int collisionFilterGroup, int collisionFilterMask, btDispatcher* dispatcher) =0; virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher)=0; virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher)=0; virtual void getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const =0; diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp b/extern/bullet/src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp similarity index 83% rename from extern/bullet2/src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp rename to extern/bullet/src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp index f4d7341f8ddf..0fd4ef46be5b 100644 --- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp +++ b/extern/bullet/src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp @@ -15,3 +15,4 @@ subject to the following restrictions: #include "btBroadphaseProxy.h" +BT_NOT_EMPTY_FILE // fix warning LNK4221: This object file does not define any previously undefined public symbols, so it will not be used by any link operation that consumes this library diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h b/extern/bullet/src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h similarity index 94% rename from extern/bullet2/src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h rename to extern/bullet/src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h index bb58b8289361..adaf083a21dc 100644 --- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h +++ b/extern/bullet/src/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h @@ -101,10 +101,10 @@ BT_DECLARE_ALIGNED_ALLOCATOR(); //Usually the client btCollisionObject or Rigidbody class void* m_clientObject; - short int m_collisionFilterGroup; - short int m_collisionFilterMask; - void* m_multiSapParentProxy; - int m_uniqueId;//m_uniqueId is introduced for paircache. could get rid of this, by calculating the address offset etc. + int m_collisionFilterGroup; + int m_collisionFilterMask; + + int m_uniqueId;//m_uniqueId is introduced for paircache. could get rid of this, by calculating the address offset etc. btVector3 m_aabbMin; btVector3 m_aabbMax; @@ -115,18 +115,17 @@ BT_DECLARE_ALIGNED_ALLOCATOR(); } //used for memory pools - btBroadphaseProxy() :m_clientObject(0),m_multiSapParentProxy(0) + btBroadphaseProxy() :m_clientObject(0) { } - btBroadphaseProxy(const btVector3& aabbMin,const btVector3& aabbMax,void* userPtr,short int collisionFilterGroup, short int collisionFilterMask,void* multiSapParentProxy=0) + btBroadphaseProxy(const btVector3& aabbMin,const btVector3& aabbMax,void* userPtr, int collisionFilterGroup, int collisionFilterMask) :m_clientObject(userPtr), m_collisionFilterGroup(collisionFilterGroup), m_collisionFilterMask(collisionFilterMask), m_aabbMin(aabbMin), m_aabbMax(aabbMax) { - m_multiSapParentProxy = multiSapParentProxy; } diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.cpp b/extern/bullet/src/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.cpp rename to extern/bullet/src/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.cpp diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h b/extern/bullet/src/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h similarity index 100% rename from extern/bullet2/src/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h rename to extern/bullet/src/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvt.cpp b/extern/bullet/src/BulletCollision/BroadphaseCollision/btDbvt.cpp similarity index 95% rename from extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvt.cpp rename to extern/bullet/src/BulletCollision/BroadphaseCollision/btDbvt.cpp index 2ca20cdd8b8b..d791d0741821 100644 --- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvt.cpp +++ b/extern/bullet/src/BulletCollision/BroadphaseCollision/btDbvt.cpp @@ -229,25 +229,60 @@ static void fetchleaves(btDbvt* pdbvt, } // -static void split( const tNodeArray& leaves, - tNodeArray& left, - tNodeArray& right, +static bool leftOfAxis( const btDbvtNode* node, + const btVector3& org, + const btVector3& axis) +{ + return btDot(axis, node->volume.Center() - org) <= 0; +} + + +// Partitions leaves such that leaves[0, n) are on the +// left of axis, and leaves[n, count) are on the right +// of axis. returns N. +static int split( btDbvtNode** leaves, + int count, const btVector3& org, const btVector3& axis) { - left.resize(0); - right.resize(0); - for(int i=0,ni=leaves.size();ivolume.Center()-org)<0) - left.push_back(leaves[i]); - else - right.push_back(leaves[i]); + while(begin!=end && leftOfAxis(leaves[begin],org,axis)) + { + ++begin; + } + + if(begin==end) + { + break; + } + + while(begin!=end && !leftOfAxis(leaves[end-1],org,axis)) + { + --end; + } + + if(begin==end) + { + break; + } + + // swap out of place nodes + --end; + btDbvtNode* temp=leaves[begin]; + leaves[begin]=leaves[end]; + leaves[end]=temp; + ++begin; } + + return begin; } // -static btDbvtVolume bounds( const tNodeArray& leaves) +static btDbvtVolume bounds( btDbvtNode** leaves, + int count) { #if DBVT_MERGE_IMPL==DBVT_IMPL_SSE ATTRIBUTE_ALIGNED16(char locals[sizeof(btDbvtVolume)]); @@ -257,7 +292,7 @@ static btDbvtVolume bounds( const tNodeArray& leaves) #else btDbvtVolume volume=leaves[0]->volume; #endif - for(int i=1,ni=leaves.size();ivolume,volume); } @@ -266,15 +301,16 @@ static btDbvtVolume bounds( const tNodeArray& leaves) // static void bottomup( btDbvt* pdbvt, - tNodeArray& leaves) + btDbvtNode** leaves, + int count) { - while(leaves.size()>1) + while(count>1) { btScalar minsize=SIMD_INFINITY; int minidx[2]={-1,-1}; - for(int i=0;ivolume,leaves[j]->volume)); if(szparent = p; n[1]->parent = p; leaves[minidx[0]] = p; - leaves.swap(minidx[1],leaves.size()-1); - leaves.pop_back(); + leaves[minidx[1]] = leaves[count-1]; + --count; } } // static btDbvtNode* topdown(btDbvt* pdbvt, - tNodeArray& leaves, + btDbvtNode** leaves, + int count, int bu_treshold) { static const btVector3 axis[]={btVector3(1,0,0), btVector3(0,1,0), btVector3(0,0,1)}; - if(leaves.size()>1) + btAssert(bu_treshold>2); + if(count>1) { - if(leaves.size()>bu_treshold) + if(count>bu_treshold) { - const btDbvtVolume vol=bounds(leaves); + const btDbvtVolume vol=bounds(leaves,count); const btVector3 org=vol.Center(); - tNodeArray sets[2]; + int partition; int bestaxis=-1; - int bestmidp=leaves.size(); + int bestmidp=count; int splitcount[3][2]={{0,0},{0,0},{0,0}}; int i; - for( i=0;ivolume.Center()-org; for(int j=0;j<3;++j) @@ -338,29 +376,23 @@ static btDbvtNode* topdown(btDbvt* pdbvt, } if(bestaxis>=0) { - sets[0].reserve(splitcount[bestaxis][0]); - sets[1].reserve(splitcount[bestaxis][1]); - split(leaves,sets[0],sets[1],org,axis[bestaxis]); + partition=split(leaves,count,org,axis[bestaxis]); + btAssert(partition!=0 && partition!=count); } else { - sets[0].reserve(leaves.size()/2+1); - sets[1].reserve(leaves.size()/2); - for(int i=0,ni=leaves.size();ichilds[0]=topdown(pdbvt,sets[0],bu_treshold); - node->childs[1]=topdown(pdbvt,sets[1],bu_treshold); + node->childs[0]=topdown(pdbvt,&leaves[0],partition,bu_treshold); + node->childs[1]=topdown(pdbvt,&leaves[partition],count-partition,bu_treshold); node->childs[0]->parent=node; node->childs[1]->parent=node; return(node); } else { - bottomup(pdbvt,leaves); + bottomup(pdbvt,leaves,count); return(leaves[0]); } } @@ -444,7 +476,7 @@ void btDbvt::optimizeBottomUp() tNodeArray leaves; leaves.reserve(m_leaves); fetchleaves(this,m_root,leaves); - bottomup(this,leaves); + bottomup(this,&leaves[0],leaves.size()); m_root=leaves[0]; } } @@ -457,7 +489,7 @@ void btDbvt::optimizeTopDown(int bu_treshold) tNodeArray leaves; leaves.reserve(m_leaves); fetchleaves(this,m_root,leaves); - m_root=topdown(this,leaves,bu_treshold); + m_root=topdown(this,&leaves[0],leaves.size(),bu_treshold); } } diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvt.h b/extern/bullet/src/BulletCollision/BroadphaseCollision/btDbvt.h similarity index 94% rename from extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvt.h rename to extern/bullet/src/BulletCollision/BroadphaseCollision/btDbvt.h index db4e482f2926..b5a0014580df 100644 --- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvt.h +++ b/extern/bullet/src/BulletCollision/BroadphaseCollision/btDbvt.h @@ -122,6 +122,7 @@ subject to the following restrictions: #error "DBVT_INT0_IMPL undefined" #endif + // // Defaults volumes // @@ -188,6 +189,9 @@ struct btDbvtNode }; }; +typedef btAlignedObjectArray btNodeStack; + + ///The btDbvt class implements a fast dynamic bounding volume tree based on axis aligned bounding boxes (aabb tree). ///This btDbvt is used for soft body collision detection and for the btDbvtBroadphase. It has a fast insert, remove and update of nodes. ///Unlike the btQuantizedBvh, nodes can be dynamically moved around, which allows for change in topology of the underlying data structure. @@ -263,7 +267,6 @@ struct btDbvt btAlignedObjectArray m_stkStack; - mutable btAlignedObjectArray m_rayTestStack; // Methods @@ -325,6 +328,16 @@ struct btDbvt void collideTV( const btDbvtNode* root, const btDbvtVolume& volume, DBVT_IPOLICY) const; + + DBVT_PREFIX + void collideTVNoStackAlloc( const btDbvtNode* root, + const btDbvtVolume& volume, + btNodeStack& stack, + DBVT_IPOLICY) const; + + + + ///rayTest is a re-entrant ray test, and can be called in parallel as long as the btAlignedAlloc is thread-safe (uses locking etc) ///rayTest is slower than rayTestInternal, because it builds a local stack, using memory allocations, and it recomputes signs/rayDirectionInverses each time DBVT_PREFIX @@ -343,6 +356,7 @@ struct btDbvt btScalar lambda_max, const btVector3& aabbMin, const btVector3& aabbMax, + btAlignedObjectArray& stack, DBVT_IPOLICY) const; DBVT_PREFIX @@ -917,39 +931,78 @@ inline void btDbvt::collideTT( const btDbvtNode* root0, } #endif -// DBVT_PREFIX inline void btDbvt::collideTV( const btDbvtNode* root, const btDbvtVolume& vol, DBVT_IPOLICY) const { DBVT_CHECKTYPE - if(root) - { - ATTRIBUTE_ALIGNED16(btDbvtVolume) volume(vol); - btAlignedObjectArray stack; - stack.resize(0); - stack.reserve(SIMPLE_STACKSIZE); - stack.push_back(root); - do { - const btDbvtNode* n=stack[stack.size()-1]; - stack.pop_back(); - if(Intersect(n->volume,volume)) + if(root) + { + ATTRIBUTE_ALIGNED16(btDbvtVolume) volume(vol); + btAlignedObjectArray stack; + stack.resize(0); +#ifndef BT_DISABLE_STACK_TEMP_MEMORY + char tempmemory[SIMPLE_STACKSIZE*sizeof(const btDbvtNode*)]; + stack.initializeFromBuffer(tempmemory, 0, SIMPLE_STACKSIZE); +#else + stack.reserve(SIMPLE_STACKSIZE); +#endif //BT_DISABLE_STACK_TEMP_MEMORY + + stack.push_back(root); + do { + const btDbvtNode* n=stack[stack.size()-1]; + stack.pop_back(); + if(Intersect(n->volume,volume)) + { + if(n->isinternal()) { - if(n->isinternal()) - { - stack.push_back(n->childs[0]); - stack.push_back(n->childs[1]); - } - else - { - policy.Process(n); - } + stack.push_back(n->childs[0]); + stack.push_back(n->childs[1]); } - } while(stack.size()>0); - } + else + { + policy.Process(n); + } + } + } while(stack.size()>0); + } +} + +// +DBVT_PREFIX +inline void btDbvt::collideTVNoStackAlloc( const btDbvtNode* root, + const btDbvtVolume& vol, + btNodeStack& stack, + DBVT_IPOLICY) const +{ + DBVT_CHECKTYPE + if(root) + { + ATTRIBUTE_ALIGNED16(btDbvtVolume) volume(vol); + stack.resize(0); + stack.reserve(SIMPLE_STACKSIZE); + stack.push_back(root); + do { + const btDbvtNode* n=stack[stack.size()-1]; + stack.pop_back(); + if(Intersect(n->volume,volume)) + { + if(n->isinternal()) + { + stack.push_back(n->childs[0]); + stack.push_back(n->childs[1]); + } + else + { + policy.Process(n); + } + } + } while(stack.size()>0); + } } + DBVT_PREFIX inline void btDbvt::rayTestInternal( const btDbvtNode* root, const btVector3& rayFrom, @@ -959,7 +1012,8 @@ inline void btDbvt::rayTestInternal( const btDbvtNode* root, btScalar lambda_max, const btVector3& aabbMin, const btVector3& aabbMax, - DBVT_IPOLICY) const + btAlignedObjectArray& stack, + DBVT_IPOLICY ) const { (void) rayTo; DBVT_CHECKTYPE @@ -969,7 +1023,6 @@ inline void btDbvt::rayTestInternal( const btDbvtNode* root, int depth=1; int treshold=DOUBLE_STACKSIZE-2; - btAlignedObjectArray& stack = m_rayTestStack; stack.resize(DOUBLE_STACKSIZE); stack[0]=root; btVector3 bounds[2]; @@ -1031,7 +1084,12 @@ inline void btDbvt::rayTest( const btDbvtNode* root, int depth=1; int treshold=DOUBLE_STACKSIZE-2; + char tempmemory[DOUBLE_STACKSIZE * sizeof(const btDbvtNode*)]; +#ifndef BT_DISABLE_STACK_TEMP_MEMORY + stack.initializeFromBuffer(tempmemory, DOUBLE_STACKSIZE, DOUBLE_STACKSIZE); +#else//BT_DISABLE_STACK_TEMP_MEMORY stack.resize(DOUBLE_STACKSIZE); +#endif //BT_DISABLE_STACK_TEMP_MEMORY stack[0]=root; btVector3 bounds[2]; do { diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp b/extern/bullet/src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp similarity index 95% rename from extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp rename to extern/bullet/src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp index 75cfac64368d..4d12b1c9c79b 100644 --- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp +++ b/extern/bullet/src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp @@ -16,6 +16,7 @@ subject to the following restrictions: ///btDbvtBroadphase implementation by Nathanael Presson #include "btDbvtBroadphase.h" +#include "LinearMath/btThreads.h" // // Profiling @@ -142,6 +143,11 @@ btDbvtBroadphase::btDbvtBroadphase(btOverlappingPairCache* paircache) { m_stageRoots[i]=0; } +#if BT_THREADSAFE + m_rayTestStacks.resize(BT_MAX_THREAD_COUNT); +#else + m_rayTestStacks.resize(1); +#endif #if DBVT_BP_PROFILE clear(m_profiling); #endif @@ -162,10 +168,9 @@ btBroadphaseProxy* btDbvtBroadphase::createProxy( const btVector3& aabbMin, const btVector3& aabbMax, int /*shapeType*/, void* userPtr, - short int collisionFilterGroup, - short int collisionFilterMask, - btDispatcher* /*dispatcher*/, - void* /*multiSapProxy*/) + int collisionFilterGroup, + int collisionFilterMask, + btDispatcher* /*dispatcher*/) { btDbvtProxy* proxy=new(btAlignedAlloc(sizeof(btDbvtProxy),16)) btDbvtProxy( aabbMin,aabbMax,userPtr, collisionFilterGroup, @@ -227,6 +232,23 @@ struct BroadphaseRayTester : btDbvt::ICollide void btDbvtBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback,const btVector3& aabbMin,const btVector3& aabbMax) { BroadphaseRayTester callback(rayCallback); + btAlignedObjectArray* stack = &m_rayTestStacks[0]; +#if BT_THREADSAFE + // for this function to be threadsafe, each thread must have a separate copy + // of this stack. This could be thread-local static to avoid dynamic allocations, + // instead of just a local. + int threadIndex = btGetCurrentThreadIndex(); + btAlignedObjectArray localStack; + if (threadIndex < m_rayTestStacks.size()) + { + // use per-thread preallocated stack if possible to avoid dynamic allocations + stack = &m_rayTestStacks[threadIndex]; + } + else + { + stack = &localStack; + } +#endif m_sets[0].rayTestInternal( m_sets[0].m_root, rayFrom, @@ -236,6 +258,7 @@ void btDbvtBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, rayCallback.m_lambda_max, aabbMin, aabbMax, + *stack, callback); m_sets[1].rayTestInternal( m_sets[1].m_root, @@ -246,6 +269,7 @@ void btDbvtBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, rayCallback.m_lambda_max, aabbMin, aabbMax, + *stack, callback); } @@ -520,7 +544,9 @@ void btDbvtBroadphase::collide(btDispatcher* dispatcher) btDbvtProxy* current=m_stageRoots[m_stageCurrent]; if(current) { +#if DBVT_BP_ACCURATESLEEPING btDbvtTreeCollider collider(this); +#endif do { btDbvtProxy* next=current->links[1]; listremove(current,m_stageRoots[current->stage]); diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h b/extern/bullet/src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h similarity index 95% rename from extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h rename to extern/bullet/src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h index 18b64ad0e57f..8feb95d51fec 100644 --- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h +++ b/extern/bullet/src/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h @@ -47,7 +47,7 @@ struct btDbvtProxy : btBroadphaseProxy btDbvtProxy* links[2]; int stage; /* ctor */ - btDbvtProxy(const btVector3& aabbMin,const btVector3& aabbMax,void* userPtr,short int collisionFilterGroup, short int collisionFilterMask) : + btDbvtProxy(const btVector3& aabbMin,const btVector3& aabbMax,void* userPtr, int collisionFilterGroup, int collisionFilterMask) : btBroadphaseProxy(aabbMin,aabbMax,userPtr,collisionFilterGroup,collisionFilterMask) { links[0]=links[1]=0; @@ -87,6 +87,7 @@ struct btDbvtBroadphase : btBroadphaseInterface bool m_releasepaircache; // Release pair cache on delete bool m_deferedcollide; // Defere dynamic/static collision to collide call bool m_needcleanup; // Need to run cleanup? + btAlignedObjectArray< btAlignedObjectArray > m_rayTestStacks; #if DBVT_BP_PROFILE btClock m_clock; struct { @@ -104,7 +105,7 @@ struct btDbvtBroadphase : btBroadphaseInterface void optimize(); /* btBroadphaseInterface Implementation */ - btBroadphaseProxy* createProxy(const btVector3& aabbMin,const btVector3& aabbMax,int shapeType,void* userPtr,short int collisionFilterGroup,short int collisionFilterMask,btDispatcher* dispatcher,void* multiSapProxy); + btBroadphaseProxy* createProxy(const btVector3& aabbMin,const btVector3& aabbMax,int shapeType,void* userPtr, int collisionFilterGroup, int collisionFilterMask,btDispatcher* dispatcher); virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher); virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax,btDispatcher* dispatcher); virtual void rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin=btVector3(0,0,0), const btVector3& aabbMax = btVector3(0,0,0)); diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDispatcher.cpp b/extern/bullet/src/BulletCollision/BroadphaseCollision/btDispatcher.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/BroadphaseCollision/btDispatcher.cpp rename to extern/bullet/src/BulletCollision/BroadphaseCollision/btDispatcher.cpp diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDispatcher.h b/extern/bullet/src/BulletCollision/BroadphaseCollision/btDispatcher.h similarity index 95% rename from extern/bullet2/src/BulletCollision/BroadphaseCollision/btDispatcher.h rename to extern/bullet/src/BulletCollision/BroadphaseCollision/btDispatcher.h index 89c307d14ca5..7b0f9489afd5 100644 --- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btDispatcher.h +++ b/extern/bullet/src/BulletCollision/BroadphaseCollision/btDispatcher.h @@ -64,6 +64,12 @@ struct btDispatcherInfo btScalar m_convexConservativeDistanceThreshold; }; +enum ebtDispatcherQueryType +{ + BT_CONTACT_POINT_ALGORITHMS = 1, + BT_CLOSEST_POINT_ALGORITHMS = 2 +}; + ///The btDispatcher interface class can be used in combination with broadphase to dispatch calculations for overlapping pairs. ///For example for pairwise collision detection, calculating contact points stored in btPersistentManifold or user callbacks (game logic). class btDispatcher @@ -73,7 +79,7 @@ class btDispatcher public: virtual ~btDispatcher() ; - virtual btCollisionAlgorithm* findAlgorithm(const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btPersistentManifold* sharedManifold=0) = 0; + virtual btCollisionAlgorithm* findAlgorithm(const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btPersistentManifold* sharedManifold, ebtDispatcherQueryType queryType) = 0; virtual btPersistentManifold* getNewManifold(const btCollisionObject* b0,const btCollisionObject* b1)=0; diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp b/extern/bullet/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp similarity index 99% rename from extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp rename to extern/bullet/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp index ad69fcbd712b..55ebf06f1e5f 100644 --- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp +++ b/extern/bullet/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp @@ -372,10 +372,10 @@ void* btHashedOverlappingPairCache::removeOverlappingPair(btBroadphaseProxy* pro return userData; } //#include - +#include "LinearMath/btQuickprof.h" void btHashedOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback* callback,btDispatcher* dispatcher) { - + BT_PROFILE("btHashedOverlappingPairCache::processAllOverlappingPairs"); int i; // printf("m_overlappingPairArray.size()=%d\n",m_overlappingPairArray.size()); diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h b/extern/bullet/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h similarity index 97% rename from extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h rename to extern/bullet/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h index 146142704761..f7be7d45b3e5 100644 --- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h +++ b/extern/bullet/src/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h @@ -90,7 +90,8 @@ class btOverlappingPairCache : public btOverlappingPairCallback }; /// Hash-space based Pair Cache, thanks to Erin Catto, Box2D, http://www.box2d.org, and Pierre Terdiman, Codercorner, http://codercorner.com -class btHashedOverlappingPairCache : public btOverlappingPairCache + +ATTRIBUTE_ALIGNED16(class) btHashedOverlappingPairCache : public btOverlappingPairCache { btBroadphasePairArray m_overlappingPairArray; btOverlapFilterCallback* m_overlapFilterCallback; @@ -103,6 +104,8 @@ class btHashedOverlappingPairCache : public btOverlappingPairCache public: + BT_DECLARE_ALIGNED_ALLOCATOR(); + btHashedOverlappingPairCache(); virtual ~btHashedOverlappingPairCache(); @@ -212,10 +215,9 @@ class btHashedOverlappingPairCache : public btOverlappingPairCache */ - - SIMD_FORCE_INLINE unsigned int getHash(unsigned int proxyId1, unsigned int proxyId2) + SIMD_FORCE_INLINE unsigned int getHash(unsigned int proxyId1, unsigned int proxyId2) { - int key = static_cast(((unsigned int)proxyId1) | (((unsigned int)proxyId2) <<16)); + unsigned int key = proxyId1 | (proxyId2 << 16); // Thomas Wang's hash key += ~(key << 15); @@ -224,13 +226,11 @@ class btHashedOverlappingPairCache : public btOverlappingPairCache key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); - return static_cast(key); + return key; } - - SIMD_FORCE_INLINE btBroadphasePair* internalFindPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1, int hash) { int proxyId1 = proxy0->getUid(); diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h b/extern/bullet/src/BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h similarity index 97% rename from extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h rename to extern/bullet/src/BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h index 9c7b6f81367d..3e069fa5e283 100644 --- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h +++ b/extern/bullet/src/BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h @@ -23,6 +23,9 @@ struct btBroadphasePair; ///The btOverlappingPairCallback class is an additional optional broadphase user callback for adding/removing overlapping pairs, similar interface to btOverlappingPairCache. class btOverlappingPairCallback { +protected: + btOverlappingPairCallback() {} + public: virtual ~btOverlappingPairCallback() { diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp b/extern/bullet/src/BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp similarity index 99% rename from extern/bullet2/src/BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp rename to extern/bullet/src/BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp index 889216df5092..875d89c53ec9 100644 --- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp +++ b/extern/bullet/src/BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp @@ -107,6 +107,8 @@ void btQuantizedBvh::setQuantizationValues(const btVector3& bvhAabbMin,const btV v = unQuantize(vecIn); m_bvhAabbMin.setMin(v-clampValue); } + aabbSize = m_bvhAabbMax - m_bvhAabbMin; + m_bvhQuantization = btVector3(btScalar(65533.0),btScalar(65533.0),btScalar(65533.0)) / aabbSize; { quantize(vecIn,m_bvhAabbMax,true); v = unQuantize(vecIn); @@ -1334,6 +1336,8 @@ const char* btQuantizedBvh::serialize(void* dataBuffer, btSerializer* serializer memPtr->m_escapeIndex = m_contiguousNodes[i].m_escapeIndex; memPtr->m_subPart = m_contiguousNodes[i].m_subPart; memPtr->m_triangleIndex = m_contiguousNodes[i].m_triangleIndex; + // Fill padding with zeros to appease msan. + memset(memPtr->m_pad, 0, sizeof(memPtr->m_pad)); } serializer->finalizeChunk(chunk,"btOptimizedBvhNodeData",BT_ARRAY_CODE,(void*)&m_contiguousNodes[0]); } diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btQuantizedBvh.h b/extern/bullet/src/BulletCollision/BroadphaseCollision/btQuantizedBvh.h similarity index 99% rename from extern/bullet2/src/BulletCollision/BroadphaseCollision/btQuantizedBvh.h rename to extern/bullet/src/BulletCollision/BroadphaseCollision/btQuantizedBvh.h index 78382da79f0a..3dd5ac9bb65c 100644 --- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btQuantizedBvh.h +++ b/extern/bullet/src/BulletCollision/BroadphaseCollision/btQuantizedBvh.h @@ -169,7 +169,7 @@ typedef btAlignedObjectArray BvhSubtreeInfoArray; ///The btQuantizedBvh class stores an AABB tree that can be quickly traversed on CPU and Cell SPU. -///It is used by the btBvhTriangleMeshShape as midphase, and by the btMultiSapBroadphase. +///It is used by the btBvhTriangleMeshShape as midphase. ///It is recommended to use quantization for better performance and lower memory requirements. ATTRIBUTE_ALIGNED16(class) btQuantizedBvh { diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp b/extern/bullet/src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp similarity index 98% rename from extern/bullet2/src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp rename to extern/bullet/src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp index 752fcd0fef27..f1d5f5476ecf 100644 --- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp +++ b/extern/bullet/src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp @@ -84,7 +84,7 @@ btSimpleBroadphase::~btSimpleBroadphase() } -btBroadphaseProxy* btSimpleBroadphase::createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* /*dispatcher*/,void* multiSapProxy) +btBroadphaseProxy* btSimpleBroadphase::createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr , int collisionFilterGroup, int collisionFilterMask, btDispatcher* /*dispatcher*/) { if (m_numHandles >= m_maxHandles) { @@ -94,7 +94,7 @@ btBroadphaseProxy* btSimpleBroadphase::createProxy( const btVector3& aabbMin, btAssert(aabbMin[0]<= aabbMax[0] && aabbMin[1]<= aabbMax[1] && aabbMin[2]<= aabbMax[2]); int newHandleIndex = allocHandle(); - btSimpleBroadphaseProxy* proxy = new (&m_pHandles[newHandleIndex])btSimpleBroadphaseProxy(aabbMin,aabbMax,shapeType,userPtr,collisionFilterGroup,collisionFilterMask,multiSapProxy); + btSimpleBroadphaseProxy* proxy = new (&m_pHandles[newHandleIndex])btSimpleBroadphaseProxy(aabbMin,aabbMax,shapeType,userPtr,collisionFilterGroup,collisionFilterMask); return proxy; } diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.h b/extern/bullet/src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.h similarity index 94% rename from extern/bullet2/src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.h rename to extern/bullet/src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.h index 7cb3c40a0438..d7a18e400a45 100644 --- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.h +++ b/extern/bullet/src/BulletCollision/BroadphaseCollision/btSimpleBroadphase.h @@ -29,8 +29,8 @@ struct btSimpleBroadphaseProxy : public btBroadphaseProxy btSimpleBroadphaseProxy() {}; - btSimpleBroadphaseProxy(const btVector3& minpt,const btVector3& maxpt,int shapeType,void* userPtr,short int collisionFilterGroup,short int collisionFilterMask,void* multiSapProxy) - :btBroadphaseProxy(minpt,maxpt,userPtr,collisionFilterGroup,collisionFilterMask,multiSapProxy) + btSimpleBroadphaseProxy(const btVector3& minpt,const btVector3& maxpt,int shapeType,void* userPtr, int collisionFilterGroup, int collisionFilterMask) + :btBroadphaseProxy(minpt,maxpt,userPtr,collisionFilterGroup,collisionFilterMask) { (void)shapeType; } @@ -127,7 +127,7 @@ class btSimpleBroadphase : public btBroadphaseInterface static bool aabbOverlap(btSimpleBroadphaseProxy* proxy0,btSimpleBroadphaseProxy* proxy1); - virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy); + virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr , int collisionFilterGroup, int collisionFilterMask, btDispatcher* dispatcher); virtual void calculateOverlappingPairs(btDispatcher* dispatcher); diff --git a/extern/bullet/src/BulletCollision/CMakeLists.txt b/extern/bullet/src/BulletCollision/CMakeLists.txt new file mode 100644 index 000000000000..85c5fc8b647b --- /dev/null +++ b/extern/bullet/src/BulletCollision/CMakeLists.txt @@ -0,0 +1,292 @@ +INCLUDE_DIRECTORIES( ${BULLET_PHYSICS_SOURCE_DIR}/src ) + +SET(BulletCollision_SRCS + BroadphaseCollision/btAxisSweep3.cpp + BroadphaseCollision/btBroadphaseProxy.cpp + BroadphaseCollision/btCollisionAlgorithm.cpp + BroadphaseCollision/btDbvt.cpp + BroadphaseCollision/btDbvtBroadphase.cpp + BroadphaseCollision/btDispatcher.cpp + BroadphaseCollision/btOverlappingPairCache.cpp + BroadphaseCollision/btQuantizedBvh.cpp + BroadphaseCollision/btSimpleBroadphase.cpp + CollisionDispatch/btActivatingCollisionAlgorithm.cpp + CollisionDispatch/btBoxBoxCollisionAlgorithm.cpp + CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp + CollisionDispatch/btBoxBoxDetector.cpp + CollisionDispatch/btCollisionDispatcher.cpp + CollisionDispatch/btCollisionDispatcherMt.cpp + CollisionDispatch/btCollisionObject.cpp + CollisionDispatch/btCollisionWorld.cpp + CollisionDispatch/btCollisionWorldImporter.cpp + CollisionDispatch/btCompoundCollisionAlgorithm.cpp + CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp + CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp + CollisionDispatch/btConvexConvexAlgorithm.cpp + CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp + CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp + CollisionDispatch/btDefaultCollisionConfiguration.cpp + CollisionDispatch/btEmptyCollisionAlgorithm.cpp + CollisionDispatch/btGhostObject.cpp + CollisionDispatch/btHashedSimplePairCache.cpp + CollisionDispatch/btInternalEdgeUtility.cpp + CollisionDispatch/btInternalEdgeUtility.h + CollisionDispatch/btManifoldResult.cpp + CollisionDispatch/btSimulationIslandManager.cpp + CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp + CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp + CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp + CollisionDispatch/btUnionFind.cpp + CollisionDispatch/SphereTriangleDetector.cpp + CollisionShapes/btBoxShape.cpp + CollisionShapes/btBox2dShape.cpp + CollisionShapes/btBvhTriangleMeshShape.cpp + CollisionShapes/btCapsuleShape.cpp + CollisionShapes/btCollisionShape.cpp + CollisionShapes/btCompoundShape.cpp + CollisionShapes/btConcaveShape.cpp + CollisionShapes/btConeShape.cpp + CollisionShapes/btConvexHullShape.cpp + CollisionShapes/btConvexInternalShape.cpp + CollisionShapes/btConvexPointCloudShape.cpp + CollisionShapes/btConvexPolyhedron.cpp + CollisionShapes/btConvexShape.cpp + CollisionShapes/btConvex2dShape.cpp + CollisionShapes/btConvexTriangleMeshShape.cpp + CollisionShapes/btCylinderShape.cpp + CollisionShapes/btEmptyShape.cpp + CollisionShapes/btHeightfieldTerrainShape.cpp + CollisionShapes/btMinkowskiSumShape.cpp + CollisionShapes/btMultimaterialTriangleMeshShape.cpp + CollisionShapes/btMultiSphereShape.cpp + CollisionShapes/btOptimizedBvh.cpp + CollisionShapes/btPolyhedralConvexShape.cpp + CollisionShapes/btScaledBvhTriangleMeshShape.cpp + CollisionShapes/btShapeHull.cpp + CollisionShapes/btSphereShape.cpp + CollisionShapes/btStaticPlaneShape.cpp + CollisionShapes/btStridingMeshInterface.cpp + CollisionShapes/btTetrahedronShape.cpp + CollisionShapes/btTriangleBuffer.cpp + CollisionShapes/btTriangleCallback.cpp + CollisionShapes/btTriangleIndexVertexArray.cpp + CollisionShapes/btTriangleIndexVertexMaterialArray.cpp + CollisionShapes/btTriangleMesh.cpp + CollisionShapes/btTriangleMeshShape.cpp + CollisionShapes/btUniformScalingShape.cpp + Gimpact/btContactProcessing.cpp + Gimpact/btGenericPoolAllocator.cpp + Gimpact/btGImpactBvh.cpp + Gimpact/btGImpactCollisionAlgorithm.cpp + Gimpact/btGImpactQuantizedBvh.cpp + Gimpact/btGImpactShape.cpp + Gimpact/btTriangleShapeEx.cpp + Gimpact/gim_box_set.cpp + Gimpact/gim_contact.cpp + Gimpact/gim_memory.cpp + Gimpact/gim_tri_collision.cpp + NarrowPhaseCollision/btContinuousConvexCollision.cpp + NarrowPhaseCollision/btConvexCast.cpp + NarrowPhaseCollision/btGjkConvexCast.cpp + NarrowPhaseCollision/btGjkEpa2.cpp + NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp + NarrowPhaseCollision/btGjkPairDetector.cpp + NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp + NarrowPhaseCollision/btPersistentManifold.cpp + NarrowPhaseCollision/btRaycastCallback.cpp + NarrowPhaseCollision/btSubSimplexConvexCast.cpp + NarrowPhaseCollision/btVoronoiSimplexSolver.cpp + NarrowPhaseCollision/btPolyhedralContactClipping.cpp +) + +SET(Root_HDRS + ../btBulletCollisionCommon.h +) +SET(BroadphaseCollision_HDRS + BroadphaseCollision/btAxisSweep3Internal.h + BroadphaseCollision/btAxisSweep3.h + BroadphaseCollision/btBroadphaseInterface.h + BroadphaseCollision/btBroadphaseProxy.h + BroadphaseCollision/btCollisionAlgorithm.h + BroadphaseCollision/btDbvt.h + BroadphaseCollision/btDbvtBroadphase.h + BroadphaseCollision/btDispatcher.h + BroadphaseCollision/btOverlappingPairCache.h + BroadphaseCollision/btOverlappingPairCallback.h + BroadphaseCollision/btQuantizedBvh.h + BroadphaseCollision/btSimpleBroadphase.h +) +SET(CollisionDispatch_HDRS + CollisionDispatch/btActivatingCollisionAlgorithm.h + CollisionDispatch/btBoxBoxCollisionAlgorithm.h + CollisionDispatch/btBox2dBox2dCollisionAlgorithm.h + CollisionDispatch/btBoxBoxDetector.h + CollisionDispatch/btCollisionConfiguration.h + CollisionDispatch/btCollisionCreateFunc.h + CollisionDispatch/btCollisionDispatcher.h + CollisionDispatch/btCollisionDispatcherMt.h + CollisionDispatch/btCollisionObject.h + CollisionDispatch/btCollisionObjectWrapper.h + CollisionDispatch/btCollisionWorld.h + CollisionDispatch/btCollisionWorldImporter.h + CollisionDispatch/btCompoundCollisionAlgorithm.h + CollisionDispatch/btCompoundCompoundCollisionAlgorithm.h + CollisionDispatch/btConvexConcaveCollisionAlgorithm.h + CollisionDispatch/btConvexConvexAlgorithm.h + CollisionDispatch/btConvex2dConvex2dAlgorithm.h + CollisionDispatch/btConvexPlaneCollisionAlgorithm.h + CollisionDispatch/btDefaultCollisionConfiguration.h + CollisionDispatch/btEmptyCollisionAlgorithm.h + CollisionDispatch/btGhostObject.h + CollisionDispatch/btHashedSimplePairCache.h + CollisionDispatch/btManifoldResult.h + CollisionDispatch/btSimulationIslandManager.h + CollisionDispatch/btSphereBoxCollisionAlgorithm.h + CollisionDispatch/btSphereSphereCollisionAlgorithm.h + CollisionDispatch/btSphereTriangleCollisionAlgorithm.h + CollisionDispatch/btUnionFind.h + CollisionDispatch/SphereTriangleDetector.h +) +SET(CollisionShapes_HDRS + CollisionShapes/btBoxShape.h + CollisionShapes/btBox2dShape.h + CollisionShapes/btBvhTriangleMeshShape.h + CollisionShapes/btCapsuleShape.h + CollisionShapes/btCollisionMargin.h + CollisionShapes/btCollisionShape.h + CollisionShapes/btCompoundShape.h + CollisionShapes/btConcaveShape.h + CollisionShapes/btConeShape.h + CollisionShapes/btConvexHullShape.h + CollisionShapes/btConvexInternalShape.h + CollisionShapes/btConvexPointCloudShape.h + CollisionShapes/btConvexPolyhedron.h + CollisionShapes/btConvexShape.h + CollisionShapes/btConvex2dShape.h + CollisionShapes/btConvexTriangleMeshShape.h + CollisionShapes/btCylinderShape.h + CollisionShapes/btEmptyShape.h + CollisionShapes/btHeightfieldTerrainShape.h + CollisionShapes/btMaterial.h + CollisionShapes/btMinkowskiSumShape.h + CollisionShapes/btMultimaterialTriangleMeshShape.h + CollisionShapes/btMultiSphereShape.h + CollisionShapes/btOptimizedBvh.h + CollisionShapes/btPolyhedralConvexShape.h + CollisionShapes/btScaledBvhTriangleMeshShape.h + CollisionShapes/btShapeHull.h + CollisionShapes/btSphereShape.h + CollisionShapes/btStaticPlaneShape.h + CollisionShapes/btStridingMeshInterface.h + CollisionShapes/btTetrahedronShape.h + CollisionShapes/btTriangleBuffer.h + CollisionShapes/btTriangleCallback.h + CollisionShapes/btTriangleIndexVertexArray.h + CollisionShapes/btTriangleIndexVertexMaterialArray.h + CollisionShapes/btTriangleInfoMap.h + CollisionShapes/btTriangleMesh.h + CollisionShapes/btTriangleMeshShape.h + CollisionShapes/btTriangleShape.h + CollisionShapes/btUniformScalingShape.h +) +SET(Gimpact_HDRS + Gimpact/btBoxCollision.h + Gimpact/btClipPolygon.h + Gimpact/btContactProcessingStructs.h + Gimpact/btContactProcessing.h + Gimpact/btGenericPoolAllocator.h + Gimpact/btGeometryOperations.h + Gimpact/btGImpactBvhStructs.h + Gimpact/btGImpactBvh.h + Gimpact/btGImpactCollisionAlgorithm.h + Gimpact/btGImpactMassUtil.h + Gimpact/btGImpactQuantizedBvhStructs.h + Gimpact/btGImpactQuantizedBvh.h + Gimpact/btGImpactShape.h + Gimpact/btQuantization.h + Gimpact/btTriangleShapeEx.h + Gimpact/gim_array.h + Gimpact/gim_basic_geometry_operations.h + Gimpact/gim_bitset.h + Gimpact/gim_box_collision.h + Gimpact/gim_box_set.h + Gimpact/gim_clip_polygon.h + Gimpact/gim_contact.h + Gimpact/gim_geom_types.h + Gimpact/gim_geometry.h + Gimpact/gim_hash_table.h + Gimpact/gim_linear_math.h + Gimpact/gim_math.h + Gimpact/gim_memory.h + Gimpact/gim_radixsort.h + Gimpact/gim_tri_collision.h +) +SET(NarrowPhaseCollision_HDRS + NarrowPhaseCollision/btContinuousConvexCollision.h + NarrowPhaseCollision/btConvexCast.h + NarrowPhaseCollision/btConvexPenetrationDepthSolver.h + NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h + NarrowPhaseCollision/btGjkConvexCast.h + NarrowPhaseCollision/btGjkEpa2.h + NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h + NarrowPhaseCollision/btGjkPairDetector.h + NarrowPhaseCollision/btManifoldPoint.h + NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h + NarrowPhaseCollision/btPersistentManifold.h + NarrowPhaseCollision/btPointCollector.h + NarrowPhaseCollision/btRaycastCallback.h + NarrowPhaseCollision/btSimplexSolverInterface.h + NarrowPhaseCollision/btSubSimplexConvexCast.h + NarrowPhaseCollision/btVoronoiSimplexSolver.h + NarrowPhaseCollision/btPolyhedralContactClipping.h +) + +SET(BulletCollision_HDRS + ${Root_HDRS} + ${BroadphaseCollision_HDRS} + ${CollisionDispatch_HDRS} + ${CollisionShapes_HDRS} + ${Gimpact_HDRS} + ${NarrowPhaseCollision_HDRS} +) + + +ADD_LIBRARY(BulletCollision ${BulletCollision_SRCS} ${BulletCollision_HDRS}) +SET_TARGET_PROPERTIES(BulletCollision PROPERTIES VERSION ${BULLET_VERSION}) +SET_TARGET_PROPERTIES(BulletCollision PROPERTIES SOVERSION ${BULLET_VERSION}) +IF (BUILD_SHARED_LIBS) + TARGET_LINK_LIBRARIES(BulletCollision LinearMath) +ENDIF (BUILD_SHARED_LIBS) + + +IF (INSTALL_LIBS) + IF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) + #INSTALL of other files requires CMake 2.6 + IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS BulletCollision DESTINATION .) + ELSE (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS BulletCollision RUNTIME DESTINATION bin + LIBRARY DESTINATION lib${LIB_SUFFIX} + ARCHIVE DESTINATION lib${LIB_SUFFIX}) + INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.h" PATTERN ".svn" EXCLUDE PATTERN "CMakeFiles" EXCLUDE) + INSTALL(FILES ../btBulletCollisionCommon.h +DESTINATION ${INCLUDE_INSTALL_DIR}/BulletCollision) + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + SET_TARGET_PROPERTIES(BulletCollision PROPERTIES FRAMEWORK true) + + SET_TARGET_PROPERTIES(BulletCollision PROPERTIES PUBLIC_HEADER "${Root_HDRS}") + # Have to list out sub-directories manually: + SET_PROPERTY(SOURCE ${BroadphaseCollision_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/BroadphaseCollision) + SET_PROPERTY(SOURCE ${CollisionDispatch_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/CollisionDispatch) + SET_PROPERTY(SOURCE ${CollisionShapes_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/CollisionShapes) + SET_PROPERTY(SOURCE ${Gimpact_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/Gimpact) + SET_PROPERTY(SOURCE ${NarrowPhaseCollision_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/NarrowPhaseCollision) + + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) +ENDIF (INSTALL_LIBS) diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp similarity index 79% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp index 63401780970f..c81af95672a3 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp @@ -100,45 +100,54 @@ bool SphereTriangleDetector::collide(const btVector3& sphereCenter,btVector3 &po btScalar radiusWithThreshold = radius + contactBreakingThreshold; btVector3 normal = (vertices[1]-vertices[0]).cross(vertices[2]-vertices[0]); - normal.normalize(); - btVector3 p1ToCentre = sphereCenter - vertices[0]; - btScalar distanceFromPlane = p1ToCentre.dot(normal); - if (distanceFromPlane < btScalar(0.)) + btScalar l2 = normal.length2(); + bool hasContact = false; + btVector3 contactPoint; + + if (l2 >= SIMD_EPSILON*SIMD_EPSILON) { - //triangle facing the other way - distanceFromPlane *= btScalar(-1.); - normal *= btScalar(-1.); - } + normal /= btSqrt(l2); + + btVector3 p1ToCentre = sphereCenter - vertices[0]; + btScalar distanceFromPlane = p1ToCentre.dot(normal); - bool isInsideContactPlane = distanceFromPlane < radiusWithThreshold; + if (distanceFromPlane < btScalar(0.)) + { + //triangle facing the other way + distanceFromPlane *= btScalar(-1.); + normal *= btScalar(-1.); + } + + bool isInsideContactPlane = distanceFromPlane < radiusWithThreshold; - // Check for contact / intersection - bool hasContact = false; - btVector3 contactPoint; - if (isInsideContactPlane) { - if (facecontains(sphereCenter,vertices,normal)) { - // Inside the contact wedge - touches a point on the shell plane - hasContact = true; - contactPoint = sphereCenter - normal*distanceFromPlane; - } else { - // Could be inside one of the contact capsules - btScalar contactCapsuleRadiusSqr = radiusWithThreshold*radiusWithThreshold; - btVector3 nearestOnEdge; - for (int i = 0; i < m_triangle->getNumEdges(); i++) { - - btVector3 pa; - btVector3 pb; - - m_triangle->getEdge(i,pa,pb); - - btScalar distanceSqr = SegmentSqrDistance(pa,pb,sphereCenter, nearestOnEdge); - if (distanceSqr < contactCapsuleRadiusSqr) { - // Yep, we're inside a capsule - hasContact = true; - contactPoint = nearestOnEdge; + // Check for contact / intersection + + if (isInsideContactPlane) { + if (facecontains(sphereCenter, vertices, normal)) { + // Inside the contact wedge - touches a point on the shell plane + hasContact = true; + contactPoint = sphereCenter - normal*distanceFromPlane; + } + else { + // Could be inside one of the contact capsules + btScalar contactCapsuleRadiusSqr = radiusWithThreshold*radiusWithThreshold; + btVector3 nearestOnEdge; + for (int i = 0; i < m_triangle->getNumEdges(); i++) { + + btVector3 pa; + btVector3 pb; + + m_triangle->getEdge(i, pa, pb); + + btScalar distanceSqr = SegmentSqrDistance(pa, pb, sphereCenter, nearestOnEdge); + if (distanceSqr < contactCapsuleRadiusSqr) { + // Yep, we're inside a capsule + hasContact = true; + contactPoint = nearestOnEdge; + } + } - } } } diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.h b/extern/bullet/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/SphereTriangleDetector.h diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h similarity index 99% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h index 489812b96631..0e19f1ea356c 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h @@ -24,12 +24,13 @@ class btActivatingCollisionAlgorithm : public btCollisionAlgorithm // btCollisionObject* m_colObj0; // btCollisionObject* m_colObj1; -public: +protected: btActivatingCollisionAlgorithm (const btCollisionAlgorithmConstructionInfo& ci); btActivatingCollisionAlgorithm (const btCollisionAlgorithmConstructionInfo& ci, const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap); +public: virtual ~btActivatingCollisionAlgorithm(); }; diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp similarity index 98% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp index c1da9f36cfb8..2c3627782109 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp @@ -151,8 +151,8 @@ static btScalar EdgeSeparation(const btBox2dShape* poly1, const btTransform& xf1 int index = 0; btScalar minDot = BT_LARGE_FLOAT; - if( count2 > 0 ) - index = (int) normal1.minDot( vertices2, count2, minDot); + if( count2 > 0 ) + index = (int) normal1.minDot( vertices2, count2, minDot); btVector3 v1 = b2Mul(xf1, vertices1[edge1]); btVector3 v2 = b2Mul(xf2, vertices2[index]); @@ -174,9 +174,9 @@ static btScalar FindMaxSeparation(int* edgeIndex, // Find edge normal on poly1 that has the largest projection onto d. int edge = 0; - btScalar maxDot; - if( count1 > 0 ) - edge = (int) dLocal1.maxDot( normals1, count1, maxDot); + btScalar maxDot; + if( count1 > 0 ) + edge = (int) dLocal1.maxDot( normals1, count1, maxDot); // Get the separation for the edge normal. btScalar s = EdgeSeparation(poly1, xf1, edge, poly2, xf2); diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.h diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.h diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btBoxBoxDetector.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btBoxBoxDetector.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btBoxBoxDetector.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btBoxBoxDetector.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btBoxBoxDetector.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btBoxBoxDetector.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btBoxBoxDetector.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btBoxBoxDetector.h diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionConfiguration.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionConfiguration.h similarity index 93% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionConfiguration.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionConfiguration.h index 66949849448e..35f77d4e6543 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionConfiguration.h +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionConfiguration.h @@ -40,6 +40,9 @@ class btCollisionConfiguration virtual btCollisionAlgorithmCreateFunc* getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1) =0; + virtual btCollisionAlgorithmCreateFunc* getClosestPointsAlgorithmCreateFunc(int proxyType0, int proxyType1) = 0; + + }; #endif //BT_COLLISION_CONFIGURATION diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionCreateFunc.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionCreateFunc.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionCreateFunc.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionCreateFunc.h diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp similarity index 84% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp index 3b6913c0e1ec..5739a1ef01e1 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp @@ -16,7 +16,7 @@ subject to the following restrictions: #include "btCollisionDispatcher.h" - +#include "LinearMath/btQuickprof.h" #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" @@ -50,8 +50,10 @@ m_dispatcherFlags(btCollisionDispatcher::CD_USE_RELATIVE_CONTACT_BREAKING_THRESH { for (int j=0;jgetCollisionAlgorithmCreateFunc(i,j); - btAssert(m_doubleDispatch[i][j]); + m_doubleDispatchContactPoints[i][j] = m_collisionConfiguration->getCollisionAlgorithmCreateFunc(i,j); + btAssert(m_doubleDispatchContactPoints[i][j]); + m_doubleDispatchClosestPoints[i][j] = m_collisionConfiguration->getClosestPointsAlgorithmCreateFunc(i, j); + } } @@ -61,7 +63,12 @@ m_dispatcherFlags(btCollisionDispatcher::CD_USE_RELATIVE_CONTACT_BREAKING_THRESH void btCollisionDispatcher::registerCollisionCreateFunc(int proxyType0, int proxyType1, btCollisionAlgorithmCreateFunc *createFunc) { - m_doubleDispatch[proxyType0][proxyType1] = createFunc; + m_doubleDispatchContactPoints[proxyType0][proxyType1] = createFunc; +} + +void btCollisionDispatcher::registerClosestPointsCreateFunc(int proxyType0, int proxyType1, btCollisionAlgorithmCreateFunc *createFunc) +{ + m_doubleDispatchClosestPoints[proxyType0][proxyType1] = createFunc; } btCollisionDispatcher::~btCollisionDispatcher() @@ -84,14 +91,10 @@ btPersistentManifold* btCollisionDispatcher::getNewManifold(const btCollisionObj btScalar contactProcessingThreshold = btMin(body0->getContactProcessingThreshold(),body1->getContactProcessingThreshold()); - void* mem = 0; - - if (m_persistentManifoldPoolAllocator->getFreeCount()) - { - mem = m_persistentManifoldPoolAllocator->allocate(sizeof(btPersistentManifold)); - } else + void* mem = m_persistentManifoldPoolAllocator->allocate( sizeof( btPersistentManifold ) ); + if (NULL == mem) { - //we got a pool memory overflow, by default we fallback to dynamically allocate memory. If we require a contiguous contact pool then assert. + //we got a pool memory overflow, by default we fallback to dynamically allocate memory. If we require a contiguous contact pool then assert. if ((m_dispatcherFlags&CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION)==0) { mem = btAlignedAlloc(sizeof(btPersistentManifold),16); @@ -142,14 +145,23 @@ void btCollisionDispatcher::releaseManifold(btPersistentManifold* manifold) -btCollisionAlgorithm* btCollisionDispatcher::findAlgorithm(const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btPersistentManifold* sharedManifold) + +btCollisionAlgorithm* btCollisionDispatcher::findAlgorithm(const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btPersistentManifold* sharedManifold, ebtDispatcherQueryType algoType) { btCollisionAlgorithmConstructionInfo ci; ci.m_dispatcher1 = this; ci.m_manifold = sharedManifold; - btCollisionAlgorithm* algo = m_doubleDispatch[body0Wrap->getCollisionShape()->getShapeType()][body1Wrap->getCollisionShape()->getShapeType()]->CreateCollisionAlgorithm(ci,body0Wrap,body1Wrap); + btCollisionAlgorithm* algo = 0; + if (algoType == BT_CONTACT_POINT_ALGORITHMS) + { + algo = m_doubleDispatchContactPoints[body0Wrap->getCollisionShape()->getShapeType()][body1Wrap->getCollisionShape()->getShapeType()]->CreateCollisionAlgorithm(ci, body0Wrap, body1Wrap); + } + else + { + algo = m_doubleDispatchClosestPoints[body0Wrap->getCollisionShape()->getShapeType()][body1Wrap->getCollisionShape()->getShapeType()]->CreateCollisionAlgorithm(ci, body0Wrap, body1Wrap); + } return algo; } @@ -228,7 +240,6 @@ class btCollisionPairCallback : public btOverlapCallback virtual bool processOverlap(btBroadphasePair& pair) { (*m_dispatcher->getNearCallback())(pair,*m_dispatcher,m_dispatchInfo); - return false; } }; @@ -249,7 +260,6 @@ void btCollisionDispatcher::dispatchAllCollisionPairs(btOverlappingPairCache* pa - //by default, Bullet will use this near callback void btCollisionDispatcher::defaultNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo) { @@ -265,7 +275,7 @@ void btCollisionDispatcher::defaultNearCallback(btBroadphasePair& collisionPair, //dispatcher will keep algorithms persistent in the collision pair if (!collisionPair.m_algorithm) { - collisionPair.m_algorithm = dispatcher.findAlgorithm(&obj0Wrap,&obj1Wrap); + collisionPair.m_algorithm = dispatcher.findAlgorithm(&obj0Wrap,&obj1Wrap,0, BT_CONTACT_POINT_ALGORITHMS); } if (collisionPair.m_algorithm) @@ -293,13 +303,13 @@ void btCollisionDispatcher::defaultNearCallback(btBroadphasePair& collisionPair, void* btCollisionDispatcher::allocateCollisionAlgorithm(int size) { - if (m_collisionAlgorithmPoolAllocator->getFreeCount()) - { - return m_collisionAlgorithmPoolAllocator->allocate(size); - } - - //warn user for overflow? - return btAlignedAlloc(static_cast(size), 16); + void* mem = m_collisionAlgorithmPoolAllocator->allocate( size ); + if (NULL == mem) + { + //warn user for overflow? + return btAlignedAlloc(static_cast(size), 16); + } + return mem; } void btCollisionDispatcher::freeCollisionAlgorithm(void* ptr) diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.h similarity index 92% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.h index 92696ee54290..b97ee3c1ba6a 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.h +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.h @@ -57,7 +57,9 @@ class btCollisionDispatcher : public btDispatcher btPoolAllocator* m_persistentManifoldPoolAllocator; - btCollisionAlgorithmCreateFunc* m_doubleDispatch[MAX_BROADPHASE_COLLISION_TYPES][MAX_BROADPHASE_COLLISION_TYPES]; + btCollisionAlgorithmCreateFunc* m_doubleDispatchContactPoints[MAX_BROADPHASE_COLLISION_TYPES][MAX_BROADPHASE_COLLISION_TYPES]; + + btCollisionAlgorithmCreateFunc* m_doubleDispatchClosestPoints[MAX_BROADPHASE_COLLISION_TYPES][MAX_BROADPHASE_COLLISION_TYPES]; btCollisionConfiguration* m_collisionConfiguration; @@ -84,6 +86,8 @@ class btCollisionDispatcher : public btDispatcher ///registerCollisionCreateFunc allows registration of custom/alternative collision create functions void registerCollisionCreateFunc(int proxyType0,int proxyType1, btCollisionAlgorithmCreateFunc* createFunc); + void registerClosestPointsCreateFunc(int proxyType0, int proxyType1, btCollisionAlgorithmCreateFunc *createFunc); + int getNumManifolds() const { return int( m_manifoldsPtr.size()); @@ -115,7 +119,7 @@ class btCollisionDispatcher : public btDispatcher virtual void clearManifold(btPersistentManifold* manifold); - btCollisionAlgorithm* findAlgorithm(const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btPersistentManifold* sharedManifold = 0); + btCollisionAlgorithm* findAlgorithm(const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btPersistentManifold* sharedManifold, ebtDispatcherQueryType queryType); virtual bool needsCollision(const btCollisionObject* body0,const btCollisionObject* body1); diff --git a/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionDispatcherMt.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionDispatcherMt.cpp new file mode 100644 index 000000000000..075860c503d4 --- /dev/null +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionDispatcherMt.cpp @@ -0,0 +1,164 @@ +/* +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 "btCollisionDispatcherMt.h" +#include "LinearMath/btQuickprof.h" + +#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" + +#include "BulletCollision/CollisionShapes/btCollisionShape.h" +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" +#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" +#include "LinearMath/btPoolAllocator.h" +#include "BulletCollision/CollisionDispatch/btCollisionConfiguration.h" +#include "BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h" + + +btCollisionDispatcherMt::btCollisionDispatcherMt( btCollisionConfiguration* config, int grainSize ) + : btCollisionDispatcher( config ) +{ + m_batchUpdating = false; + m_grainSize = grainSize; // iterations per task +} + + +btPersistentManifold* btCollisionDispatcherMt::getNewManifold( const btCollisionObject* body0, const btCollisionObject* body1 ) +{ + //optional relative contact breaking threshold, turned on by default (use setDispatcherFlags to switch off feature for improved performance) + + btScalar contactBreakingThreshold = ( m_dispatcherFlags & btCollisionDispatcher::CD_USE_RELATIVE_CONTACT_BREAKING_THRESHOLD ) ? + btMin( body0->getCollisionShape()->getContactBreakingThreshold( gContactBreakingThreshold ), body1->getCollisionShape()->getContactBreakingThreshold( gContactBreakingThreshold ) ) + : gContactBreakingThreshold; + + btScalar contactProcessingThreshold = btMin( body0->getContactProcessingThreshold(), body1->getContactProcessingThreshold() ); + + void* mem = m_persistentManifoldPoolAllocator->allocate( sizeof( btPersistentManifold ) ); + if ( NULL == mem ) + { + //we got a pool memory overflow, by default we fallback to dynamically allocate memory. If we require a contiguous contact pool then assert. + if ( ( m_dispatcherFlags&CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION ) == 0 ) + { + mem = btAlignedAlloc( sizeof( btPersistentManifold ), 16 ); + } + else + { + btAssert( 0 ); + //make sure to increase the m_defaultMaxPersistentManifoldPoolSize in the btDefaultCollisionConstructionInfo/btDefaultCollisionConfiguration + return 0; + } + } + btPersistentManifold* manifold = new( mem ) btPersistentManifold( body0, body1, 0, contactBreakingThreshold, contactProcessingThreshold ); + if ( !m_batchUpdating ) + { + // batch updater will update manifold pointers array after finishing, so + // only need to update array when not batch-updating + //btAssert( !btThreadsAreRunning() ); + manifold->m_index1a = m_manifoldsPtr.size(); + m_manifoldsPtr.push_back( manifold ); + } + + return manifold; +} + +void btCollisionDispatcherMt::releaseManifold( btPersistentManifold* manifold ) +{ + clearManifold( manifold ); + //btAssert( !btThreadsAreRunning() ); + if ( !m_batchUpdating ) + { + // batch updater will update manifold pointers array after finishing, so + // only need to update array when not batch-updating + int findIndex = manifold->m_index1a; + btAssert( findIndex < m_manifoldsPtr.size() ); + m_manifoldsPtr.swap( findIndex, m_manifoldsPtr.size() - 1 ); + m_manifoldsPtr[ findIndex ]->m_index1a = findIndex; + m_manifoldsPtr.pop_back(); + } + + manifold->~btPersistentManifold(); + if ( m_persistentManifoldPoolAllocator->validPtr( manifold ) ) + { + m_persistentManifoldPoolAllocator->freeMemory( manifold ); + } + else + { + btAlignedFree( manifold ); + } +} + +struct CollisionDispatcherUpdater : public btIParallelForBody +{ + btBroadphasePair* mPairArray; + btNearCallback mCallback; + btCollisionDispatcher* mDispatcher; + const btDispatcherInfo* mInfo; + + CollisionDispatcherUpdater() + { + mPairArray = NULL; + mCallback = NULL; + mDispatcher = NULL; + mInfo = NULL; + } + void forLoop( int iBegin, int iEnd ) const + { + for ( int i = iBegin; i < iEnd; ++i ) + { + btBroadphasePair* pair = &mPairArray[ i ]; + mCallback( *pair, *mDispatcher, *mInfo ); + } + } +}; + + +void btCollisionDispatcherMt::dispatchAllCollisionPairs( btOverlappingPairCache* pairCache, const btDispatcherInfo& info, btDispatcher* dispatcher ) +{ + int pairCount = pairCache->getNumOverlappingPairs(); + if ( pairCount == 0 ) + { + return; + } + CollisionDispatcherUpdater updater; + updater.mCallback = getNearCallback(); + updater.mPairArray = pairCache->getOverlappingPairArrayPtr(); + updater.mDispatcher = this; + updater.mInfo = &info; + + m_batchUpdating = true; + btParallelFor( 0, pairCount, m_grainSize, updater ); + m_batchUpdating = false; + + // reconstruct the manifolds array to ensure determinism + m_manifoldsPtr.resizeNoInitialize( 0 ); + + btBroadphasePair* pairs = pairCache->getOverlappingPairArrayPtr(); + for ( int i = 0; i < pairCount; ++i ) + { + if (btCollisionAlgorithm* algo = pairs[ i ].m_algorithm) + { + algo->getAllContactManifolds( m_manifoldsPtr ); + } + } + + // update the indices (used when releasing manifolds) + for ( int i = 0; i < m_manifoldsPtr.size(); ++i ) + { + m_manifoldsPtr[ i ]->m_index1a = i; + } +} + + diff --git a/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionDispatcherMt.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionDispatcherMt.h new file mode 100644 index 000000000000..f1d7eafdc963 --- /dev/null +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionDispatcherMt.h @@ -0,0 +1,39 @@ +/* +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_COLLISION_DISPATCHER_MT_H +#define BT_COLLISION_DISPATCHER_MT_H + +#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" +#include "LinearMath/btThreads.h" + + +class btCollisionDispatcherMt : public btCollisionDispatcher +{ +public: + btCollisionDispatcherMt( btCollisionConfiguration* config, int grainSize = 40 ); + + virtual btPersistentManifold* getNewManifold( const btCollisionObject* body0, const btCollisionObject* body1 ) BT_OVERRIDE; + virtual void releaseManifold( btPersistentManifold* manifold ) BT_OVERRIDE; + + virtual void dispatchAllCollisionPairs( btOverlappingPairCache* pairCache, const btDispatcherInfo& info, btDispatcher* dispatcher ) BT_OVERRIDE; + +protected: + bool m_batchUpdating; + int m_grainSize; +}; + +#endif //BT_COLLISION_DISPATCHER_MT_H + diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionObject.cpp similarity index 87% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionObject.cpp index 395df3a550f1..b595c56bc56e 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.cpp +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionObject.cpp @@ -18,9 +18,11 @@ subject to the following restrictions: #include "LinearMath/btSerializer.h" btCollisionObject::btCollisionObject() - : m_anisotropicFriction(1.f,1.f,1.f), - m_hasAnisotropicFriction(false), - m_contactProcessingThreshold(BT_LARGE_FLOAT), + : m_interpolationLinearVelocity(0.f, 0.f, 0.f), + m_interpolationAngularVelocity(0.f, 0.f, 0.f), + m_anisotropicFriction(1.f,1.f,1.f), + m_hasAnisotropicFriction(false), + m_contactProcessingThreshold(BT_LARGE_FLOAT), m_broadphaseHandle(0), m_collisionShape(0), m_extensionPointer(0), @@ -28,13 +30,18 @@ btCollisionObject::btCollisionObject() m_collisionFlags(btCollisionObject::CF_STATIC_OBJECT), m_islandTag1(-1), m_companionId(-1), + m_worldArrayIndex(-1), m_activationState1(1), m_deactivationTime(btScalar(0.)), m_friction(btScalar(0.5)), m_restitution(btScalar(0.)), m_rollingFriction(0.0f), + m_spinningFriction(0.f), + m_contactDamping(.1), + m_contactStiffness(1e4), m_internalType(CO_COLLISION_OBJECT), m_userObjectPointer(0), + m_userIndex2(-1), m_userIndex(-1), m_hitFraction(btScalar(1.)), m_ccdSweptSphereRadius(btScalar(0.)), @@ -43,6 +50,7 @@ btCollisionObject::btCollisionObject() m_updateRevision(0) { m_worldTransform.setIdentity(); + m_interpolationWorldTransform.setIdentity(); } btCollisionObject::~btCollisionObject() @@ -91,6 +99,8 @@ const char* btCollisionObject::serialize(void* dataBuffer, btSerializer* seriali dataOut->m_deactivationTime = m_deactivationTime; dataOut->m_friction = m_friction; dataOut->m_rollingFriction = m_rollingFriction; + dataOut->m_contactDamping = m_contactDamping; + dataOut->m_contactStiffness = m_contactStiffness; dataOut->m_restitution = m_restitution; dataOut->m_internalType = m_internalType; @@ -105,6 +115,9 @@ const char* btCollisionObject::serialize(void* dataBuffer, btSerializer* seriali dataOut->m_ccdMotionThreshold = m_ccdMotionThreshold; dataOut->m_checkCollideWith = m_checkCollideWith; + // Fill padding with zeros to appease msan. + memset(dataOut->m_padding, 0, sizeof(dataOut->m_padding)); + return btCollisionObjectDataName; } diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionObject.h similarity index 86% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionObject.h index c68402418f72..fec831bffcd2 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.h +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionObject.h @@ -79,13 +79,19 @@ ATTRIBUTE_ALIGNED16(class) btCollisionObject int m_islandTag1; int m_companionId; + int m_worldArrayIndex; // index of object in world's collisionObjects array mutable int m_activationState1; mutable btScalar m_deactivationTime; btScalar m_friction; btScalar m_restitution; - btScalar m_rollingFriction; + btScalar m_rollingFriction;//torsional friction orthogonal to contact normal (useful to stop spheres rolling forever) + btScalar m_spinningFriction; // torsional friction around the contact normal (useful for grasping) + btScalar m_contactDamping; + btScalar m_contactStiffness; + + ///m_internalType is reserved to distinguish Bullet's btCollisionObject, btRigidBody, btSoftBody, btGhostObject etc. ///do not assign your own m_internalType unless you write a new dynamics object class. @@ -93,8 +99,10 @@ ATTRIBUTE_ALIGNED16(class) btCollisionObject ///users can point to their objects, m_userPointer is not used by Bullet, see setUserPointer/getUserPointer - void* m_userObjectPointer; - + void* m_userObjectPointer; + + int m_userIndex2; + int m_userIndex; ///time of impact calculation @@ -114,6 +122,7 @@ ATTRIBUTE_ALIGNED16(class) btCollisionObject ///internal update revision number. It will be increased when the object changes. This allows some subsystems to perform lazy evaluation. int m_updateRevision; + btVector3 m_customDebugColorRGB; public: @@ -127,7 +136,11 @@ ATTRIBUTE_ALIGNED16(class) btCollisionObject CF_CUSTOM_MATERIAL_CALLBACK = 8,//this allows per-triangle material (friction/restitution) CF_CHARACTER_OBJECT = 16, CF_DISABLE_VISUALIZE_OBJECT = 32, //disable debug drawing - CF_DISABLE_SPU_COLLISION_PROCESSING = 64//disable parallel/SPU processing + CF_DISABLE_SPU_COLLISION_PROCESSING = 64,//disable parallel/SPU processing + CF_HAS_CONTACT_STIFFNESS_DAMPING = 128, + CF_HAS_CUSTOM_DEBUG_RENDERING_COLOR = 256, + CF_HAS_FRICTION_ANCHOR = 512, + CF_HAS_COLLISION_SOUND_TRIGGER = 1024 }; enum CollisionObjectTypes @@ -316,8 +329,40 @@ ATTRIBUTE_ALIGNED16(class) btCollisionObject { return m_rollingFriction; } - - + void setSpinningFriction(btScalar frict) + { + m_updateRevision++; + m_spinningFriction = frict; + } + btScalar getSpinningFriction() const + { + return m_spinningFriction; + } + void setContactStiffnessAndDamping(btScalar stiffness, btScalar damping) + { + m_updateRevision++; + m_contactStiffness = stiffness; + m_contactDamping = damping; + + m_collisionFlags |=CF_HAS_CONTACT_STIFFNESS_DAMPING; + + //avoid divisions by zero... + if (m_contactStiffness< SIMD_EPSILON) + { + m_contactStiffness = SIMD_EPSILON; + } + } + + btScalar getContactStiffness() const + { + return m_contactStiffness; + } + + btScalar getContactDamping() const + { + return m_contactDamping; + } + ///reserved for Bullet internal usage int getInternalType() const { @@ -415,7 +460,18 @@ ATTRIBUTE_ALIGNED16(class) btCollisionObject m_companionId = id; } - SIMD_FORCE_INLINE btScalar getHitFraction() const + SIMD_FORCE_INLINE int getWorldArrayIndex() const + { + return m_worldArrayIndex; + } + + // only should be called by CollisionWorld + void setWorldArrayIndex(int ix) + { + m_worldArrayIndex = ix; + } + + SIMD_FORCE_INLINE btScalar getHitFraction() const { return m_hitFraction; } @@ -476,6 +532,12 @@ ATTRIBUTE_ALIGNED16(class) btCollisionObject { return m_userIndex; } + + int getUserIndex2() const + { + return m_userIndex2; + } + ///users can point to their objects, userPointer is not used by Bullet void setUserPointer(void* userPointer) { @@ -487,12 +549,37 @@ ATTRIBUTE_ALIGNED16(class) btCollisionObject { m_userIndex = index; } + + void setUserIndex2(int index) + { + m_userIndex2 = index; + } int getUpdateRevisionInternal() const { return m_updateRevision; } + void setCustomDebugColor(const btVector3& colorRGB) + { + m_customDebugColorRGB = colorRGB; + m_collisionFlags |= CF_HAS_CUSTOM_DEBUG_RENDERING_COLOR; + } + + void removeCustomDebugColor() + { + m_collisionFlags &= ~CF_HAS_CUSTOM_DEBUG_RENDERING_COLOR; + } + + bool getCustomDebugColor(btVector3& colorRGB) const + { + bool hasCustomColor = (0!=(m_collisionFlags&CF_HAS_CUSTOM_DEBUG_RENDERING_COLOR)); + if (hasCustomColor) + { + colorRGB = m_customDebugColorRGB; + } + return hasCustomColor; + } inline bool checkCollideWith(const btCollisionObject* co) const { @@ -528,6 +615,8 @@ struct btCollisionObjectDoubleData double m_deactivationTime; double m_friction; double m_rollingFriction; + double m_contactDamping; + double m_contactStiffness; double m_restitution; double m_hitFraction; double m_ccdSweptSphereRadius; @@ -561,7 +650,8 @@ struct btCollisionObjectFloatData float m_deactivationTime; float m_friction; float m_rollingFriction; - + float m_contactDamping; + float m_contactStiffness; float m_restitution; float m_hitFraction; float m_ccdSweptSphereRadius; diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp similarity index 91% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp index c505ed5d5080..c893b60d39a8 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp @@ -108,14 +108,16 @@ btCollisionWorld::~btCollisionWorld() -void btCollisionWorld::addCollisionObject(btCollisionObject* collisionObject,short int collisionFilterGroup,short int collisionFilterMask) +void btCollisionWorld::addCollisionObject(btCollisionObject* collisionObject, int collisionFilterGroup, int collisionFilterMask) { btAssert(collisionObject); //check that the object isn't already added btAssert( m_collisionObjects.findLinearSearch(collisionObject) == m_collisionObjects.size()); + btAssert(collisionObject->getWorldArrayIndex() == -1); // do not add the same object to more than one collision world + collisionObject->setWorldArrayIndex(m_collisionObjects.size()); m_collisionObjects.push_back(collisionObject); //calculate new AABB @@ -133,8 +135,7 @@ void btCollisionWorld::addCollisionObject(btCollisionObject* collisionObject,sho collisionObject, collisionFilterGroup, collisionFilterMask, - m_dispatcher1,0 - )) ; + m_dispatcher1)) ; @@ -195,6 +196,7 @@ void btCollisionWorld::updateAabbs() for ( int i=0;igetWorldArrayIndex() == i); //only update aabb of active objects if (m_forceUpdateAllAabbs || colObj->isActive()) @@ -253,9 +255,25 @@ void btCollisionWorld::removeCollisionObject(btCollisionObject* collisionObject) } - //swapremove - m_collisionObjects.remove(collisionObject); - + int iObj = collisionObject->getWorldArrayIndex(); +// btAssert(iObj >= 0 && iObj < m_collisionObjects.size()); // trying to remove an object that was never added or already removed previously? + if (iObj >= 0 && iObj < m_collisionObjects.size()) + { + btAssert(collisionObject == m_collisionObjects[iObj]); + m_collisionObjects.swap(iObj, m_collisionObjects.size()-1); + m_collisionObjects.pop_back(); + if (iObj < m_collisionObjects.size()) + { + m_collisionObjects[iObj]->setWorldArrayIndex(iObj); + } + } + else + { + // slow linear search + //swapremove + m_collisionObjects.remove(collisionObject); + } + collisionObject->setWorldArrayIndex(-1); } @@ -790,23 +808,50 @@ void btCollisionWorld::objectQuerySingleInternal(const btConvexShape* castShape, } } } else { - ///@todo : use AABB tree or other BVH acceleration structure! if (collisionShape->isCompound()) { - BT_PROFILE("convexSweepCompound"); - const btCompoundShape* compoundShape = static_cast(collisionShape); - int i=0; - for (i=0;igetNumChildShapes();i++) + struct btCompoundLeafCallback : btDbvt::ICollide { - btTransform childTrans = compoundShape->getChildTransform(i); - const btCollisionShape* childCollisionShape = compoundShape->getChildShape(i); - btTransform childWorldTrans = colObjWorldTransform * childTrans; - - struct LocalInfoAdder : public ConvexResultCallback { - ConvexResultCallback* m_userCallback; + btCompoundLeafCallback( + const btCollisionObjectWrapper* colObjWrap, + const btConvexShape* castShape, + const btTransform& convexFromTrans, + const btTransform& convexToTrans, + btScalar allowedPenetration, + const btCompoundShape* compoundShape, + const btTransform& colObjWorldTransform, + ConvexResultCallback& resultCallback) + : + m_colObjWrap(colObjWrap), + m_castShape(castShape), + m_convexFromTrans(convexFromTrans), + m_convexToTrans(convexToTrans), + m_allowedPenetration(allowedPenetration), + m_compoundShape(compoundShape), + m_colObjWorldTransform(colObjWorldTransform), + m_resultCallback(resultCallback) { + } + + const btCollisionObjectWrapper* m_colObjWrap; + const btConvexShape* m_castShape; + const btTransform& m_convexFromTrans; + const btTransform& m_convexToTrans; + btScalar m_allowedPenetration; + const btCompoundShape* m_compoundShape; + const btTransform& m_colObjWorldTransform; + ConvexResultCallback& m_resultCallback; + + public: + + void ProcessChild(int index, const btTransform& childTrans, const btCollisionShape* childCollisionShape) + { + btTransform childWorldTrans = m_colObjWorldTransform * childTrans; + + struct LocalInfoAdder : public ConvexResultCallback { + ConvexResultCallback* m_userCallback; int m_i; - LocalInfoAdder (int i, ConvexResultCallback *user) + LocalInfoAdder(int i, ConvexResultCallback *user) : m_userCallback(user), m_i(i) { m_closestHitFraction = m_userCallback->m_closestHitFraction; @@ -815,27 +860,66 @@ void btCollisionWorld::objectQuerySingleInternal(const btConvexShape* castShape, { return m_userCallback->needsCollision(p); } - virtual btScalar addSingleResult (btCollisionWorld::LocalConvexResult& r, bool b) - { - btCollisionWorld::LocalShapeInfo shapeInfo; - shapeInfo.m_shapePart = -1; - shapeInfo.m_triangleIndex = m_i; - if (r.m_localShapeInfo == NULL) - r.m_localShapeInfo = &shapeInfo; - const btScalar result = m_userCallback->addSingleResult(r, b); - m_closestHitFraction = m_userCallback->m_closestHitFraction; - return result; - - } - }; + virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& r, bool b) + { + btCollisionWorld::LocalShapeInfo shapeInfo; + shapeInfo.m_shapePart = -1; + shapeInfo.m_triangleIndex = m_i; + if (r.m_localShapeInfo == NULL) + r.m_localShapeInfo = &shapeInfo; + const btScalar result = m_userCallback->addSingleResult(r, b); + m_closestHitFraction = m_userCallback->m_closestHitFraction; + return result; - LocalInfoAdder my_cb(i, &resultCallback); - - btCollisionObjectWrapper tmpObj(colObjWrap,childCollisionShape,colObjWrap->getCollisionObject(),childWorldTrans,-1,i); + } + }; - objectQuerySingleInternal(castShape, convexFromTrans,convexToTrans, - &tmpObj,my_cb, allowedPenetration); - + LocalInfoAdder my_cb(index, &m_resultCallback); + + btCollisionObjectWrapper tmpObj(m_colObjWrap, childCollisionShape, m_colObjWrap->getCollisionObject(), childWorldTrans, -1, index); + + objectQuerySingleInternal(m_castShape, m_convexFromTrans, m_convexToTrans, &tmpObj, my_cb, m_allowedPenetration); + } + + void Process(const btDbvtNode* leaf) + { + // Processing leaf node + int index = leaf->dataAsInt; + + btTransform childTrans = m_compoundShape->getChildTransform(index); + const btCollisionShape* childCollisionShape = m_compoundShape->getChildShape(index); + + ProcessChild(index, childTrans, childCollisionShape); + } + }; + + BT_PROFILE("convexSweepCompound"); + const btCompoundShape* compoundShape = static_cast(collisionShape); + + btVector3 fromLocalAabbMin, fromLocalAabbMax; + btVector3 toLocalAabbMin, toLocalAabbMax; + + castShape->getAabb(colObjWorldTransform.inverse() * convexFromTrans, fromLocalAabbMin, fromLocalAabbMax); + castShape->getAabb(colObjWorldTransform.inverse() * convexToTrans, toLocalAabbMin, toLocalAabbMax); + + fromLocalAabbMin.setMin(toLocalAabbMin); + fromLocalAabbMax.setMax(toLocalAabbMax); + + btCompoundLeafCallback callback(colObjWrap, castShape, convexFromTrans, convexToTrans, + allowedPenetration, compoundShape, colObjWorldTransform, resultCallback); + + const btDbvt* tree = compoundShape->getDynamicAabbTree(); + if (tree) { + const ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds = btDbvtVolume::FromMM(fromLocalAabbMin, fromLocalAabbMax); + tree->collideTV(tree->m_root, bounds, callback); + } else { + int i; + for (i=0;igetNumChildShapes();i++) + { + const btCollisionShape* childCollisionShape = compoundShape->getChildShape(i); + btTransform childTrans = compoundShape->getChildTransform(i); + callback.ProcessChild(i, childTrans, childCollisionShape); + } } } } @@ -1146,7 +1230,7 @@ struct btSingleContactCallback : public btBroadphaseAabbCallback btCollisionObjectWrapper ob0(0,m_collisionObject->getCollisionShape(),m_collisionObject,m_collisionObject->getWorldTransform(),-1,-1); btCollisionObjectWrapper ob1(0,collisionObject->getCollisionShape(),collisionObject,collisionObject->getWorldTransform(),-1,-1); - btCollisionAlgorithm* algorithm = m_world->getDispatcher()->findAlgorithm(&ob0,&ob1); + btCollisionAlgorithm* algorithm = m_world->getDispatcher()->findAlgorithm(&ob0,&ob1,0, BT_CLOSEST_POINT_ALGORITHMS); if (algorithm) { btBridgedManifoldResult contactPointResult(&ob0,&ob1, m_resultCallback); @@ -1182,10 +1266,11 @@ void btCollisionWorld::contactPairTest(btCollisionObject* colObjA, btCollisionOb btCollisionObjectWrapper obA(0,colObjA->getCollisionShape(),colObjA,colObjA->getWorldTransform(),-1,-1); btCollisionObjectWrapper obB(0,colObjB->getCollisionShape(),colObjB,colObjB->getWorldTransform(),-1,-1); - btCollisionAlgorithm* algorithm = getDispatcher()->findAlgorithm(&obA,&obB); + btCollisionAlgorithm* algorithm = getDispatcher()->findAlgorithm(&obA,&obB, 0, BT_CLOSEST_POINT_ALGORITHMS); if (algorithm) { btBridgedManifoldResult contactPointResult(&obA,&obB, resultCallback); + contactPointResult.m_closestPointDistanceThreshold = resultCallback.m_closestDistanceThreshold; //discrete collision detection query algorithm->processCollision(&obA,&obB, getDispatchInfo(),&contactPointResult); @@ -1248,7 +1333,7 @@ void btCollisionWorld::debugDrawObject(const btTransform& worldTransform, const // Draw a small simplex at the center of the object if (getDebugDrawer() && getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawFrames) { - getDebugDrawer()->drawTransform(worldTransform,1); + getDebugDrawer()->drawTransform(worldTransform,.1); } if (shape->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) @@ -1429,6 +1514,8 @@ void btCollisionWorld::debugDrawWorld() { if (getDebugDrawer()) { + getDebugDrawer()->clearLines(); + btIDebugDraw::DefaultColors defaultColors = getDebugDrawer()->getDefaultColors(); if ( getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawContactPoints) @@ -1486,6 +1573,8 @@ void btCollisionWorld::debugDrawWorld() } }; + colObj->getCustomDebugColor(color); + debugDrawObject(colObj->getWorldTransform(),colObj->getCollisionShape(),color); } if (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawAabb)) diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorld.h similarity index 97% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorld.h index ec40c969f51c..4a3bf0f7e1ea 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorld.h @@ -205,8 +205,8 @@ class btCollisionWorld { btScalar m_closestHitFraction; const btCollisionObject* m_collisionObject; - short int m_collisionFilterGroup; - short int m_collisionFilterMask; + int m_collisionFilterGroup; + int m_collisionFilterMask; //@BP Mod - Custom flags, currently used to enable backface culling on tri-meshes, see btRaycastCallback.h. Apply any of the EFlags defined there on m_flags here to invoke. unsigned int m_flags; @@ -340,8 +340,8 @@ class btCollisionWorld struct ConvexResultCallback { btScalar m_closestHitFraction; - short int m_collisionFilterGroup; - short int m_collisionFilterMask; + int m_collisionFilterGroup; + int m_collisionFilterMask; ConvexResultCallback() :m_closestHitFraction(btScalar(1.)), @@ -410,12 +410,14 @@ class btCollisionWorld ///ContactResultCallback is used to report contact points struct ContactResultCallback { - short int m_collisionFilterGroup; - short int m_collisionFilterMask; - + int m_collisionFilterGroup; + int m_collisionFilterMask; + btScalar m_closestDistanceThreshold; + ContactResultCallback() :m_collisionFilterGroup(btBroadphaseProxy::DefaultFilter), - m_collisionFilterMask(btBroadphaseProxy::AllFilter) + m_collisionFilterMask(btBroadphaseProxy::AllFilter), + m_closestDistanceThreshold(0) { } @@ -481,7 +483,7 @@ class btCollisionWorld const btCollisionObjectWrapper* colObjWrap, ConvexResultCallback& resultCallback, btScalar allowedPenetration); - virtual void addCollisionObject(btCollisionObject* collisionObject,short int collisionFilterGroup=btBroadphaseProxy::DefaultFilter,short int collisionFilterMask=btBroadphaseProxy::AllFilter); + virtual void addCollisionObject(btCollisionObject* collisionObject, int collisionFilterGroup=btBroadphaseProxy::DefaultFilter, int collisionFilterMask=btBroadphaseProxy::AllFilter); btCollisionObjectArray& getCollisionObjectArray() { diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp similarity index 99% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp index 57eb81703e76..f2b083780864 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp @@ -579,10 +579,14 @@ btCollisionShape* btCollisionWorldImporter::convertCollisionShape( btCollisionS btCompoundShapeData* compoundData = (btCompoundShapeData*)shapeData; btCompoundShape* compoundShape = createCompoundShape(); + //btCompoundShapeChildData* childShapeDataArray = &compoundData->m_childShapePtr[0]; + btAlignedObjectArray childShapes; for (int i=0;im_numChildShapes;i++) { + //btCompoundShapeChildData* ptr = &compoundData->m_childShapePtr[i]; + btCollisionShapeData* cd = compoundData->m_childShapePtr[i].m_childShape; btCollisionShape* childShape = convertCollisionShape(cd); diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.h similarity index 99% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.h index 9a6d16fbea7c..81c61427267f 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.h +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.h @@ -124,7 +124,6 @@ class btCollisionWorldImporter btCollisionShape* getCollisionShapeByIndex(int index); int getNumRigidBodies() const; btCollisionObject* getRigidBodyByIndex(int index) const; - int getNumConstraints() const; int getNumBvhs() const; btOptimizedBvh* getBvhByIndex(int index) const; diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp similarity index 89% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp index 589a7f55f2b8..7f4dea1c6ddb 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp @@ -65,7 +65,13 @@ void btCompoundCollisionAlgorithm::preallocateChildAlgorithms(const btCollisionO const btCollisionShape* childShape = compoundShape->getChildShape(i); btCollisionObjectWrapper childWrap(colObjWrap,childShape,colObjWrap->getCollisionObject(),colObjWrap->getWorldTransform(),-1,i);//wrong child trans, but unused (hopefully) - m_childCollisionAlgorithms[i] = m_dispatcher->findAlgorithm(&childWrap,otherObjWrap,m_sharedManifold); + m_childCollisionAlgorithms[i] = m_dispatcher->findAlgorithm(&childWrap,otherObjWrap,m_sharedManifold, BT_CONTACT_POINT_ALGORITHMS); + + + btAlignedObjectArray m_childCollisionAlgorithmsContact; + btAlignedObjectArray m_childCollisionAlgorithmsClosestPoints; + + } } } @@ -128,8 +134,14 @@ struct btCompoundLeafCallback : btDbvt::ICollide btTransform newChildWorldTrans = orgTrans*childTrans ; //perform an AABB check first - btVector3 aabbMin0,aabbMax0,aabbMin1,aabbMax1; + btVector3 aabbMin0,aabbMax0; childShape->getAabb(newChildWorldTrans,aabbMin0,aabbMax0); + + btVector3 extendAabb(m_resultOut->m_closestPointDistanceThreshold, m_resultOut->m_closestPointDistanceThreshold, m_resultOut->m_closestPointDistanceThreshold); + aabbMin0 -= extendAabb; + aabbMax0 += extendAabb; + + btVector3 aabbMin1, aabbMax1; m_otherObjWrap->getCollisionShape()->getAabb(m_otherObjWrap->getWorldTransform(),aabbMin1,aabbMax1); if (gCompoundChildShapePairCallback) @@ -142,12 +154,22 @@ struct btCompoundLeafCallback : btDbvt::ICollide { btCollisionObjectWrapper compoundWrap(this->m_compoundColObjWrap,childShape,m_compoundColObjWrap->getCollisionObject(),newChildWorldTrans,-1,index); + + btCollisionAlgorithm* algo = 0; - - //the contactpoint is still projected back using the original inverted worldtrans - if (!m_childCollisionAlgorithms[index]) - m_childCollisionAlgorithms[index] = m_dispatcher->findAlgorithm(&compoundWrap,m_otherObjWrap,m_sharedManifold); - + if (m_resultOut->m_closestPointDistanceThreshold > 0) + { + algo = m_dispatcher->findAlgorithm(&compoundWrap, m_otherObjWrap, 0, BT_CLOSEST_POINT_ALGORITHMS); + } + else + { + //the contactpoint is still projected back using the original inverted worldtrans + if (!m_childCollisionAlgorithms[index]) + { + m_childCollisionAlgorithms[index] = m_dispatcher->findAlgorithm(&compoundWrap, m_otherObjWrap, m_sharedManifold, BT_CONTACT_POINT_ALGORITHMS); + } + algo = m_childCollisionAlgorithms[index]; + } const btCollisionObjectWrapper* tmpWrap = 0; @@ -164,8 +186,7 @@ struct btCompoundLeafCallback : btDbvt::ICollide m_resultOut->setShapeIdentifiersB(-1,index); } - - m_childCollisionAlgorithms[index]->processCollision(&compoundWrap,m_otherObjWrap,m_dispatchInfo,m_resultOut); + algo->processCollision(&compoundWrap,m_otherObjWrap,m_dispatchInfo,m_resultOut); #if 0 if (m_dispatchInfo.m_debugDraw && (m_dispatchInfo.m_debugDraw->getDebugMode() & btIDebugDraw::DBG_DrawAabb)) @@ -232,8 +253,8 @@ void btCompoundCollisionAlgorithm::processCollision (const btCollisionObjectWrap m_compoundShapeRevision = compoundShape->getUpdateRevision(); } - if (m_childCollisionAlgorithms.size()==0) - return; + if (m_childCollisionAlgorithms.size()==0) + return; const btDbvt* tree = compoundShape->getDynamicAabbTree(); //use a dynamic aabb tree to cull potential child-overlaps @@ -244,7 +265,7 @@ void btCompoundCollisionAlgorithm::processCollision (const btCollisionObjectWrap ///so we should add a 'refreshManifolds' in the btCollisionAlgorithm { int i; - btManifoldArray manifoldArray; + manifoldArray.resize(0); for (i=0;igetWorldTransform().inverse() * otherObjWrap->getWorldTransform(); otherObjWrap->getCollisionShape()->getAabb(otherInCompoundSpace,localAabbMin,localAabbMax); + btVector3 extraExtends(resultOut->m_closestPointDistanceThreshold, resultOut->m_closestPointDistanceThreshold, resultOut->m_closestPointDistanceThreshold); + localAabbMin -= extraExtends; + localAabbMax += extraExtends; const ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds=btDbvtVolume::FromMM(localAabbMin,localAabbMax); //process all children, that overlap with the given AABB bounds - tree->collideTV(tree->m_root,bounds,callback); + tree->collideTVNoStackAlloc(tree->m_root,bounds,stack2,callback); } else { @@ -291,7 +315,7 @@ void btCompoundCollisionAlgorithm::processCollision (const btCollisionObjectWrap //iterate over all children, perform an AABB check inside ProcessChildShape int numChildren = m_childCollisionAlgorithms.size(); int i; - btManifoldArray manifoldArray; + manifoldArray.resize(0); const btCollisionShape* childShape = 0; btTransform orgTrans; diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h similarity index 97% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h index 7d792c18d348..d2086fbc0260 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h @@ -26,6 +26,7 @@ class btDispatcher; #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "btCollisionCreateFunc.h" #include "LinearMath/btAlignedObjectArray.h" +#include "BulletCollision/BroadphaseCollision/btDbvt.h" class btDispatcher; class btCollisionObject; @@ -36,6 +37,9 @@ extern btShapePairCallback gCompoundChildShapePairCallback; /// btCompoundCollisionAlgorithm supports collision between CompoundCollisionShapes and other collision shapes class btCompoundCollisionAlgorithm : public btActivatingCollisionAlgorithm { + btNodeStack stack2; + btManifoldArray manifoldArray; + protected: btAlignedObjectArray m_childCollisionAlgorithms; bool m_isSwapped; diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp similarity index 86% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp index 1d64d84b87b7..d4a1aa78e4ee 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.cpp @@ -15,6 +15,7 @@ subject to the following restrictions: */ #include "btCompoundCompoundCollisionAlgorithm.h" +#include "LinearMath/btQuickprof.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/CollisionShapes/btCompoundShape.h" #include "BulletCollision/BroadphaseCollision/btDbvt.h" @@ -23,6 +24,8 @@ subject to the following restrictions: #include "BulletCollision/CollisionDispatch/btManifoldResult.h" #include "BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h" +//USE_LOCAL_STACK will avoid most (often all) dynamic memory allocations due to resizing in processCollision and MycollideTT +#define USE_LOCAL_STACK 1 btShapePairCallback gCompoundCompoundChildShapePairCallback = 0; @@ -124,6 +127,7 @@ struct btCompoundCompoundLeafCallback : btDbvt::ICollide void Process(const btDbvtNode* leaf0,const btDbvtNode* leaf1) { + BT_PROFILE("btCompoundCompoundLeafCallback::Process"); m_numOverlapPairs++; @@ -159,6 +163,11 @@ struct btCompoundCompoundLeafCallback : btDbvt::ICollide childShape0->getAabb(newChildWorldTrans0,aabbMin0,aabbMax0); childShape1->getAabb(newChildWorldTrans1,aabbMin1,aabbMax1); + btVector3 thresholdVec(m_resultOut->m_closestPointDistanceThreshold, m_resultOut->m_closestPointDistanceThreshold, m_resultOut->m_closestPointDistanceThreshold); + + aabbMin0 -= thresholdVec; + aabbMax0 += thresholdVec; + if (gCompoundCompoundChildShapePairCallback) { if (!gCompoundCompoundChildShapePairCallback(childShape0,childShape1)) @@ -174,17 +183,24 @@ struct btCompoundCompoundLeafCallback : btDbvt::ICollide btSimplePair* pair = m_childCollisionAlgorithmCache->findPair(childIndex0,childIndex1); btCollisionAlgorithm* colAlgo = 0; - - if (pair) + if (m_resultOut->m_closestPointDistanceThreshold > 0) { - colAlgo = (btCollisionAlgorithm*)pair->m_userPointer; - - } else + colAlgo = m_dispatcher->findAlgorithm(&compoundWrap0, &compoundWrap1, 0, BT_CLOSEST_POINT_ALGORITHMS); + } + else { - colAlgo = m_dispatcher->findAlgorithm(&compoundWrap0,&compoundWrap1,m_sharedManifold); - pair = m_childCollisionAlgorithmCache->addOverlappingPair(childIndex0,childIndex1); - btAssert(pair); - pair->m_userPointer = colAlgo; + if (pair) + { + colAlgo = (btCollisionAlgorithm*)pair->m_userPointer; + + } + else + { + colAlgo = m_dispatcher->findAlgorithm(&compoundWrap0, &compoundWrap1, m_sharedManifold, BT_CONTACT_POINT_ALGORITHMS); + pair = m_childCollisionAlgorithmCache->addOverlappingPair(childIndex0, childIndex1); + btAssert(pair); + pair->m_userPointer = colAlgo; + } } btAssert(colAlgo); @@ -215,10 +231,12 @@ struct btCompoundCompoundLeafCallback : btDbvt::ICollide static DBVT_INLINE bool MyIntersect( const btDbvtAabbMm& a, - const btDbvtAabbMm& b, const btTransform& xform) + const btDbvtAabbMm& b, const btTransform& xform, btScalar distanceThreshold) { btVector3 newmin,newmax; btTransformAabb(b.Mins(),b.Maxs(),0.f,xform,newmin,newmax); + newmin -= btVector3(distanceThreshold, distanceThreshold, distanceThreshold); + newmax += btVector3(distanceThreshold, distanceThreshold, distanceThreshold); btDbvtAabbMm newb = btDbvtAabbMm::FromMM(newmin,newmax); return Intersect(a,newb); } @@ -227,7 +245,7 @@ static DBVT_INLINE bool MyIntersect( const btDbvtAabbMm& a, static inline void MycollideTT( const btDbvtNode* root0, const btDbvtNode* root1, const btTransform& xform, - btCompoundCompoundLeafCallback* callback) + btCompoundCompoundLeafCallback* callback, btScalar distanceThreshold) { if(root0&&root1) @@ -235,11 +253,16 @@ static inline void MycollideTT( const btDbvtNode* root0, int depth=1; int treshold=btDbvt::DOUBLE_STACKSIZE-4; btAlignedObjectArray stkStack; +#ifdef USE_LOCAL_STACK + ATTRIBUTE_ALIGNED16(btDbvt::sStkNN localStack[btDbvt::DOUBLE_STACKSIZE]); + stkStack.initializeFromBuffer(&localStack,btDbvt::DOUBLE_STACKSIZE,btDbvt::DOUBLE_STACKSIZE); +#else stkStack.resize(btDbvt::DOUBLE_STACKSIZE); +#endif stkStack[0]=btDbvt::sStkNN(root0,root1); do { btDbvt::sStkNN p=stkStack[--depth]; - if(MyIntersect(p.a->volume,p.b->volume,xform)) + if(MyIntersect(p.a->volume,p.b->volume,xform, distanceThreshold)) { if(depth>treshold) { @@ -313,6 +336,10 @@ void btCompoundCompoundCollisionAlgorithm::processCollision (const btCollisionOb { int i; btManifoldArray manifoldArray; +#ifdef USE_LOCAL_STACK + btPersistentManifold localManifolds[4]; + manifoldArray.initializeFromBuffer(&localManifolds,0,4); +#endif btSimplePairArray& pairs = m_childCollisionAlgorithmCache->getOverlappingPairArray(); for (i=0;igetWorldTransform().inverse()*col1ObjWrap->getWorldTransform(); - MycollideTT(tree0->m_root,tree1->m_root,xform,&callback); + MycollideTT(tree0->m_root,tree1->m_root,xform,&callback, resultOut->m_closestPointDistanceThreshold); //printf("#compound-compound child/leaf overlap =%d \r",callback.m_numOverlapPairs); @@ -381,7 +408,9 @@ void btCompoundCompoundCollisionAlgorithm::processCollision (const btCollisionOb newChildWorldTrans0 = orgTrans0*childTrans0 ; childShape0->getAabb(newChildWorldTrans0,aabbMin0,aabbMax0); } - + btVector3 thresholdVec(resultOut->m_closestPointDistanceThreshold, resultOut->m_closestPointDistanceThreshold, resultOut->m_closestPointDistanceThreshold); + aabbMin0 -= thresholdVec; + aabbMax0 += thresholdVec; { btTransform orgInterpolationTrans1; const btCollisionShape* childShape1 = 0; @@ -396,7 +425,8 @@ void btCompoundCompoundCollisionAlgorithm::processCollision (const btCollisionOb childShape1->getAabb(newChildWorldTrans1,aabbMin1,aabbMax1); } - + aabbMin1 -= thresholdVec; + aabbMax1 += thresholdVec; if (!TestAabbAgainstAabb2(aabbMin0,aabbMax0,aabbMin1,aabbMax1)) { diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.h similarity index 95% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.h index 06a762f209d3..f29f7a709a49 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.h +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btCompoundCompoundCollisionAlgorithm.h @@ -33,8 +33,6 @@ class btDispatcher; class btCollisionObject; class btCollisionShape; -typedef bool (*btShapePairCallback)(const btCollisionShape* pShape0, const btCollisionShape* pShape1); -extern btShapePairCallback gCompoundCompoundChildShapePairCallback; /// btCompoundCompoundCollisionAlgorithm supports collision between two btCompoundCollisionShape shapes class btCompoundCompoundCollisionAlgorithm : public btCompoundCollisionAlgorithm diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.h diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp similarity index 94% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp index 912a52855682..39ff7934d988 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp @@ -15,6 +15,7 @@ subject to the following restrictions: #include "btConvexConcaveCollisionAlgorithm.h" +#include "LinearMath/btQuickprof.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/CollisionShapes/btMultiSphereShape.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" @@ -29,8 +30,8 @@ subject to the following restrictions: btConvexConcaveCollisionAlgorithm::btConvexConcaveCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci, const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,bool isSwapped) : btActivatingCollisionAlgorithm(ci,body0Wrap,body1Wrap), -m_isSwapped(isSwapped), -m_btConvexTriangleCallback(ci.m_dispatcher1,body0Wrap,body1Wrap,isSwapped) +m_btConvexTriangleCallback(ci.m_dispatcher1,body0Wrap,body1Wrap,isSwapped), +m_isSwapped(isSwapped) { } @@ -79,6 +80,7 @@ void btConvexTriangleCallback::clearCache() void btConvexTriangleCallback::processTriangle(btVector3* triangle,int partId, int triangleIndex) { + BT_PROFILE("btConvexTriangleCallback::processTriangle"); if (!TestTriangleAgainstAabb2(triangle, m_aabbMin, m_aabbMax)) { @@ -116,8 +118,16 @@ partId, int triangleIndex) btCollisionObjectWrapper triObWrap(m_triBodyWrap,&tm,m_triBodyWrap->getCollisionObject(),m_triBodyWrap->getWorldTransform(),partId,triangleIndex);//correct transform? - btCollisionAlgorithm* colAlgo = ci.m_dispatcher1->findAlgorithm(m_convexBodyWrap,&triObWrap,m_manifoldPtr); - + btCollisionAlgorithm* colAlgo = 0; + + if (m_resultOut->m_closestPointDistanceThreshold > 0) + { + colAlgo = ci.m_dispatcher1->findAlgorithm(m_convexBodyWrap, &triObWrap, 0, BT_CLOSEST_POINT_ALGORITHMS); + } + else + { + colAlgo = ci.m_dispatcher1->findAlgorithm(m_convexBodyWrap, &triObWrap, m_manifoldPtr, BT_CONTACT_POINT_ALGORITHMS); + } const btCollisionObjectWrapper* tmpWrap = 0; if (m_resultOut->getBody0Internal() == m_triBodyWrap->getCollisionObject()) @@ -168,7 +178,8 @@ void btConvexTriangleCallback::setTimeStepAndCounters(btScalar collisionMarginTr const btCollisionShape* convexShape = static_cast(m_convexBodyWrap->getCollisionShape()); //CollisionShape* triangleShape = static_cast(triBody->m_collisionShape); convexShape->getAabb(convexInTriangleSpace,m_aabbMin,m_aabbMax); - btScalar extraMargin = collisionMarginTriangle; + btScalar extraMargin = collisionMarginTriangle+ resultOut->m_closestPointDistanceThreshold; + btVector3 extra(extraMargin,extraMargin,extraMargin); m_aabbMax += extra; @@ -184,7 +195,7 @@ void btConvexConcaveCollisionAlgorithm::clearCache() void btConvexConcaveCollisionAlgorithm::processCollision (const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { - + BT_PROFILE("btConvexConcaveCollisionAlgorithm::processCollision"); const btCollisionObjectWrapper* convexBodyWrap = m_isSwapped ? body1Wrap : body0Wrap; const btCollisionObjectWrapper* triBodyWrap = m_isSwapped ? body0Wrap : body1Wrap; @@ -265,6 +276,7 @@ btScalar btConvexConcaveCollisionAlgorithm::calculateTimeOfImpact(btCollisionObj virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex) { + BT_PROFILE("processTriangle"); (void)partId; (void)triangleIndex; //do a swept sphere for now diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h similarity index 94% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h index e90d06eb191b..93d842ef5014 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h @@ -26,14 +26,16 @@ class btDispatcher; #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 +ATTRIBUTE_ALIGNED16(class) btConvexTriangleCallback : public btTriangleCallback { - const btCollisionObjectWrapper* m_convexBodyWrap; - const btCollisionObjectWrapper* m_triBodyWrap; btVector3 m_aabbMin; btVector3 m_aabbMax ; + const btCollisionObjectWrapper* m_convexBodyWrap; + const btCollisionObjectWrapper* m_triBodyWrap; + + btManifoldResult* m_resultOut; btDispatcher* m_dispatcher; @@ -41,6 +43,8 @@ class btConvexTriangleCallback : public btTriangleCallback btScalar m_collisionMarginTriangle; public: + BT_DECLARE_ALIGNED_ALLOCATOR(); + int m_triangleCount; btPersistentManifold* m_manifoldPtr; @@ -75,17 +79,19 @@ int m_triangleCount; /// btConvexConcaveCollisionAlgorithm supports collision between convex shapes and (concave) trianges meshes. -class btConvexConcaveCollisionAlgorithm : public btActivatingCollisionAlgorithm +ATTRIBUTE_ALIGNED16(class) btConvexConcaveCollisionAlgorithm : public btActivatingCollisionAlgorithm { - bool m_isSwapped; - btConvexTriangleCallback m_btConvexTriangleCallback; + bool m_isSwapped; + public: + BT_DECLARE_ALIGNED_ALLOCATOR(); + btConvexConcaveCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,bool isSwapped); virtual ~btConvexConcaveCollisionAlgorithm(); diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp similarity index 91% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp index 7f2722aa463c..b54bd48932ed 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp @@ -16,7 +16,7 @@ subject to the following restrictions: ///Specialized capsule-capsule collision algorithm has been added for Bullet 2.75 release to increase ragdoll performance ///If you experience problems with capsule-capsule collision, try to define BT_DISABLE_CAPSULE_CAPSULE_COLLIDER and report it in the Bullet forums ///with reproduction case -//define BT_DISABLE_CAPSULE_CAPSULE_COLLIDER 1 +//#define BT_DISABLE_CAPSULE_CAPSULE_COLLIDER 1 //#define ZERO_MARGIN #include "btConvexConvexAlgorithm.h" @@ -179,11 +179,10 @@ static SIMD_FORCE_INLINE btScalar capsuleCapsuleDistance( -btConvexConvexAlgorithm::CreateFunc::CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver) +btConvexConvexAlgorithm::CreateFunc::CreateFunc(btConvexPenetrationDepthSolver* pdSolver) { m_numPerturbationIterations = 0; m_minimumPointsPerturbationThreshold = 3; - m_simplexSolver = simplexSolver; m_pdSolver = pdSolver; } @@ -191,9 +190,8 @@ btConvexConvexAlgorithm::CreateFunc::~CreateFunc() { } -btConvexConvexAlgorithm::btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver,int numPerturbationIterations, int minimumPointsPerturbationThreshold) +btConvexConvexAlgorithm::btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,btConvexPenetrationDepthSolver* pdSolver,int numPerturbationIterations, int minimumPointsPerturbationThreshold) : btActivatingCollisionAlgorithm(ci,body0Wrap,body1Wrap), -m_simplexSolver(simplexSolver), m_pdSolver(pdSolver), m_ownManifold (false), m_manifoldPtr(mf), @@ -312,10 +310,10 @@ void btConvexConvexAlgorithm ::processCollision (const btCollisionObjectWrapper* #ifndef BT_DISABLE_CAPSULE_CAPSULE_COLLIDER if ((min0->getShapeType() == CAPSULE_SHAPE_PROXYTYPE) && (min1->getShapeType() == CAPSULE_SHAPE_PROXYTYPE)) { + //m_manifoldPtr->clearManifold(); + btCapsuleShape* capsuleA = (btCapsuleShape*) min0; btCapsuleShape* capsuleB = (btCapsuleShape*) min1; - // btVector3 localScalingA = capsuleA->getLocalScaling(); - // btVector3 localScalingB = capsuleB->getLocalScaling(); btScalar threshold = m_manifoldPtr->getContactBreakingThreshold(); @@ -331,6 +329,50 @@ void btConvexConvexAlgorithm ::processCollision (const btCollisionObjectWrapper* resultOut->refreshContactPoints(); return; } + + if ((min0->getShapeType() == CAPSULE_SHAPE_PROXYTYPE) && (min1->getShapeType() == SPHERE_SHAPE_PROXYTYPE)) + { + //m_manifoldPtr->clearManifold(); + + btCapsuleShape* capsuleA = (btCapsuleShape*) min0; + btSphereShape* capsuleB = (btSphereShape*) min1; + + btScalar threshold = m_manifoldPtr->getContactBreakingThreshold(); + + btScalar dist = capsuleCapsuleDistance(normalOnB, pointOnBWorld,capsuleA->getHalfHeight(),capsuleA->getRadius(), + 0.,capsuleB->getRadius(),capsuleA->getUpAxis(),1, + body0Wrap->getWorldTransform(),body1Wrap->getWorldTransform(),threshold); + + if (dist=(SIMD_EPSILON*SIMD_EPSILON)); + resultOut->addContactPoint(normalOnB,pointOnBWorld,dist); + } + resultOut->refreshContactPoints(); + return; + } + + if ((min0->getShapeType() == SPHERE_SHAPE_PROXYTYPE) && (min1->getShapeType() == CAPSULE_SHAPE_PROXYTYPE)) + { + //m_manifoldPtr->clearManifold(); + + btSphereShape* capsuleA = (btSphereShape*) min0; + btCapsuleShape* capsuleB = (btCapsuleShape*) min1; + + btScalar threshold = m_manifoldPtr->getContactBreakingThreshold(); + + btScalar dist = capsuleCapsuleDistance(normalOnB, pointOnBWorld,0.,capsuleA->getRadius(), + capsuleB->getHalfHeight(),capsuleB->getRadius(),1,capsuleB->getUpAxis(), + body0Wrap->getWorldTransform(),body1Wrap->getWorldTransform(),threshold); + + if (dist=(SIMD_EPSILON*SIMD_EPSILON)); + resultOut->addContactPoint(normalOnB,pointOnBWorld,dist); + } + resultOut->refreshContactPoints(); + return; + } #endif //BT_DISABLE_CAPSULE_CAPSULE_COLLIDER @@ -349,8 +391,8 @@ void btConvexConvexAlgorithm ::processCollision (const btCollisionObjectWrapper* btGjkPairDetector::ClosestPointInput input; - - btGjkPairDetector gjkPairDetector(min0,min1,m_simplexSolver,m_pdSolver); + btVoronoiSimplexSolver simplexSolver; + btGjkPairDetector gjkPairDetector( min0, min1, &simplexSolver, m_pdSolver ); //TODO: if (dispatchInfo.m_useContinuous) gjkPairDetector.setMinkowskiA(min0); gjkPairDetector.setMinkowskiB(min1); @@ -367,7 +409,7 @@ void btConvexConvexAlgorithm ::processCollision (const btCollisionObjectWrapper* // input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactProcessingThreshold(); //} else //{ - input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactBreakingThreshold(); + input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactBreakingThreshold()+resultOut->m_closestPointDistanceThreshold; // } input.m_maximumDistanceSquared*= input.m_maximumDistanceSquared; @@ -503,9 +545,11 @@ void btConvexConvexAlgorithm ::processCollision (const btCollisionObjectWrapper* // printf("sepNormalWorldSpace=%f,%f,%f\n",sepNormalWorldSpace.getX(),sepNormalWorldSpace.getY(),sepNormalWorldSpace.getZ()); + worldVertsB1.resize(0); btPolyhedralContactClipping::clipHullAgainstHull(sepNormalWorldSpace, *polyhedronA->getConvexPolyhedron(), *polyhedronB->getConvexPolyhedron(), body0Wrap->getWorldTransform(), - body1Wrap->getWorldTransform(), minDist-threshold, threshold, *resultOut); + body1Wrap->getWorldTransform(), minDist-threshold, threshold, worldVertsB1,worldVertsB2, + *resultOut); } if (m_ownManifold) @@ -568,8 +612,9 @@ void btConvexConvexAlgorithm ::processCollision (const btCollisionObjectWrapper* if (foundSepAxis) { + worldVertsB2.resize(0); btPolyhedralContactClipping::clipFaceAgainstHull(sepNormalWorldSpace, *polyhedronA->getConvexPolyhedron(), - body0Wrap->getWorldTransform(), vertices, minDist-threshold, maxDist, *resultOut); + body0Wrap->getWorldTransform(), vertices, worldVertsB2,minDist-threshold, maxDist, *resultOut); } diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h similarity index 89% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h index 51db0c6548dc..cd75ba12d7f9 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h @@ -24,6 +24,7 @@ subject to the following restrictions: #include "btCollisionCreateFunc.h" #include "btCollisionDispatcher.h" #include "LinearMath/btTransformUtil.h" //for btConvexSeparatingDistanceUtil +#include "BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.h" class btConvexPenetrationDepthSolver; @@ -42,9 +43,10 @@ class btConvexConvexAlgorithm : public btActivatingCollisionAlgorithm #ifdef USE_SEPDISTANCE_UTIL2 btConvexSeparatingDistanceUtil m_sepDistance; #endif - btSimplexSolverInterface* m_simplexSolver; btConvexPenetrationDepthSolver* m_pdSolver; + btVertexArray worldVertsB1; + btVertexArray worldVertsB2; bool m_ownManifold; btPersistentManifold* m_manifoldPtr; @@ -59,7 +61,7 @@ class btConvexConvexAlgorithm : public btActivatingCollisionAlgorithm public: - btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap, btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver, int numPerturbationIterations, int minimumPointsPerturbationThreshold); + btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap, btConvexPenetrationDepthSolver* pdSolver, int numPerturbationIterations, int minimumPointsPerturbationThreshold); virtual ~btConvexConvexAlgorithm(); @@ -87,18 +89,17 @@ class btConvexConvexAlgorithm : public btActivatingCollisionAlgorithm { btConvexPenetrationDepthSolver* m_pdSolver; - btSimplexSolverInterface* m_simplexSolver; int m_numPerturbationIterations; int m_minimumPointsPerturbationThreshold; - CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver); + CreateFunc(btConvexPenetrationDepthSolver* pdSolver); virtual ~CreateFunc(); virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap) { void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexConvexAlgorithm)); - return new(mem) btConvexConvexAlgorithm(ci.m_manifold,ci,body0Wrap,body1Wrap,m_simplexSolver,m_pdSolver,m_numPerturbationIterations,m_minimumPointsPerturbationThreshold); + return new(mem) btConvexConvexAlgorithm(ci.m_manifold,ci,body0Wrap,body1Wrap,m_pdSolver,m_numPerturbationIterations,m_minimumPointsPerturbationThreshold); } }; diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.h diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp similarity index 85% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp index d42f00a637ff..f6e4e57b0a33 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp @@ -44,9 +44,7 @@ btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(const btDefault //btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(btStackAlloc* stackAlloc,btPoolAllocator* persistentManifoldPool,btPoolAllocator* collisionAlgorithmPool) { - void* mem = btAlignedAlloc(sizeof(btVoronoiSimplexSolver),16); - m_simplexSolver = new (mem)btVoronoiSimplexSolver(); - + void* mem = NULL; if (constructionInfo.m_useEpaPenetrationAlgorithm) { mem = btAlignedAlloc(sizeof(btGjkEpaPenetrationDepthSolver),16); @@ -59,7 +57,7 @@ btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(const btDefault //default CreationFunctions, filling the m_doubleDispatch table mem = btAlignedAlloc(sizeof(btConvexConvexAlgorithm::CreateFunc),16); - m_convexConvexCreateFunc = new(mem) btConvexConvexAlgorithm::CreateFunc(m_simplexSolver,m_pdSolver); + m_convexConvexCreateFunc = new(mem) btConvexConvexAlgorithm::CreateFunc(m_pdSolver); mem = btAlignedAlloc(sizeof(btConvexConcaveCollisionAlgorithm::CreateFunc),16); m_convexConcaveCreateFunc = new (mem)btConvexConcaveCollisionAlgorithm::CreateFunc; mem = btAlignedAlloc(sizeof(btConvexConcaveCollisionAlgorithm::CreateFunc),16); @@ -123,6 +121,7 @@ btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(const btDefault m_persistentManifoldPool = new (mem) btPoolAllocator(sizeof(btPersistentManifold),constructionInfo.m_defaultMaxPersistentManifoldPoolSize); } + collisionAlgorithmMaxElementSize = (collisionAlgorithmMaxElementSize+16)&0xffffffffffff0; if (constructionInfo.m_collisionAlgorithmPool) { m_ownsCollisionAlgorithmPool = false; @@ -192,9 +191,6 @@ btDefaultCollisionConfiguration::~btDefaultCollisionConfiguration() m_planeConvexCF->~btCollisionAlgorithmCreateFunc(); btAlignedFree( m_planeConvexCF); - m_simplexSolver->~btVoronoiSimplexSolver(); - btAlignedFree(m_simplexSolver); - m_pdSolver->~btConvexPenetrationDepthSolver(); btAlignedFree(m_pdSolver); @@ -202,6 +198,86 @@ btDefaultCollisionConfiguration::~btDefaultCollisionConfiguration() } +btCollisionAlgorithmCreateFunc* btDefaultCollisionConfiguration::getClosestPointsAlgorithmCreateFunc(int proxyType0, int proxyType1) +{ + + + if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE) && (proxyType1 == SPHERE_SHAPE_PROXYTYPE)) + { + return m_sphereSphereCF; + } +#ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM + if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE) && (proxyType1 == BOX_SHAPE_PROXYTYPE)) + { + return m_sphereBoxCF; + } + + if ((proxyType0 == BOX_SHAPE_PROXYTYPE) && (proxyType1 == SPHERE_SHAPE_PROXYTYPE)) + { + return m_boxSphereCF; + } +#endif //USE_BUGGY_SPHERE_BOX_ALGORITHM + + + if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE) && (proxyType1 == TRIANGLE_SHAPE_PROXYTYPE)) + { + return m_sphereTriangleCF; + } + + if ((proxyType0 == TRIANGLE_SHAPE_PROXYTYPE) && (proxyType1 == SPHERE_SHAPE_PROXYTYPE)) + { + return m_triangleSphereCF; + } + + if (btBroadphaseProxy::isConvex(proxyType0) && (proxyType1 == STATIC_PLANE_PROXYTYPE)) + { + return m_convexPlaneCF; + } + + if (btBroadphaseProxy::isConvex(proxyType1) && (proxyType0 == STATIC_PLANE_PROXYTYPE)) + { + return m_planeConvexCF; + } + + + + 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) && btBroadphaseProxy::isCompound(proxyType1)) + { + return m_compoundCompoundCreateFunc; + } + + if (btBroadphaseProxy::isCompound(proxyType0)) + { + return m_compoundCreateFunc; + } + else + { + if (btBroadphaseProxy::isCompound(proxyType1)) + { + return m_swappedCompoundCreateFunc; + } + } + + //failed to find an algorithm + return m_emptyCreateFunc; + +} btCollisionAlgorithmCreateFunc* btDefaultCollisionConfiguration::getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1) { diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h similarity index 96% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h index 2078420e1989..17c7596cffb4 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h @@ -60,8 +60,7 @@ class btDefaultCollisionConfiguration : public btCollisionConfiguration btPoolAllocator* m_collisionAlgorithmPool; bool m_ownsCollisionAlgorithmPool; - //default simplex/penetration depth solvers - btVoronoiSimplexSolver* m_simplexSolver; + //default penetration depth solver btConvexPenetrationDepthSolver* m_pdSolver; //default CreationFunctions, filling the m_doubleDispatch table @@ -102,14 +101,10 @@ class btDefaultCollisionConfiguration : public btCollisionConfiguration } - virtual btVoronoiSimplexSolver* getSimplexSolver() - { - return m_simplexSolver; - } - - virtual btCollisionAlgorithmCreateFunc* getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1); + virtual btCollisionAlgorithmCreateFunc* getClosestPointsAlgorithmCreateFunc(int proxyType0, int proxyType1); + ///Use this method to allow to generate multiple contact points between at once, between two objects using the generic convex-convex algorithm. ///By default, this feature is disabled for best performance. ///@param numPerturbationIterations controls the number of collision queries. Set it to zero to disable the feature. diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btGhostObject.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btGhostObject.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btGhostObject.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btGhostObject.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btGhostObject.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btGhostObject.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btGhostObject.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btGhostObject.h diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.h similarity index 95% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.h index 186964d723e2..2aaf6201f30d 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.h +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btHashedSimplePairCache.h @@ -123,9 +123,9 @@ class btHashedSimplePairCache - SIMD_FORCE_INLINE unsigned int getHash(unsigned int indexA, unsigned int indexB) + SIMD_FORCE_INLINE unsigned int getHash(unsigned int indexA, unsigned int indexB) { - int key = static_cast(((unsigned int)indexA) | (((unsigned int)indexB) <<16)); + unsigned int key = indexA | (indexB << 16); // Thomas Wang's hash key += ~(key << 15); @@ -134,7 +134,7 @@ class btHashedSimplePairCache key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); - return static_cast(key); + return key; } diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.h diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btManifoldResult.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btManifoldResult.cpp similarity index 67% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btManifoldResult.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btManifoldResult.cpp index 4b2986a00873..aa3d159f889b 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btManifoldResult.cpp +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btManifoldResult.cpp @@ -24,10 +24,9 @@ ContactAddedCallback gContactAddedCallback=0; -///User can override this material combiner by implementing gContactAddedCallback and setting body0->m_collisionFlags |= btCollisionObject::customMaterialCallback; -inline btScalar calculateCombinedRollingFriction(const btCollisionObject* body0,const btCollisionObject* body1) +btScalar btManifoldResult::calculateCombinedRollingFriction(const btCollisionObject* body0,const btCollisionObject* body1) { - btScalar friction = body0->getRollingFriction() * body1->getRollingFriction(); + btScalar friction = body0->getRollingFriction() * body1->getFriction() + body1->getRollingFriction() * body0->getFriction(); const btScalar MAX_FRICTION = btScalar(10.); if (friction < -MAX_FRICTION) @@ -38,6 +37,17 @@ inline btScalar calculateCombinedRollingFriction(const btCollisionObject* body0, } +btScalar btManifoldResult::calculateCombinedSpinningFriction(const btCollisionObject* body0,const btCollisionObject* body1) +{ + btScalar friction = body0->getSpinningFriction() * body1->getFriction() + body1->getSpinningFriction() * body0->getFriction(); + + const btScalar MAX_FRICTION = btScalar(10.); + if (friction < -MAX_FRICTION) + friction = -MAX_FRICTION; + if (friction > MAX_FRICTION) + friction = MAX_FRICTION; + return friction; +} ///User can override this material combiner by implementing gContactAddedCallback and setting body0->m_collisionFlags |= btCollisionObject::customMaterialCallback; btScalar btManifoldResult::calculateCombinedFriction(const btCollisionObject* body0,const btCollisionObject* body1) @@ -58,6 +68,22 @@ btScalar btManifoldResult::calculateCombinedRestitution(const btCollisionObject* return body0->getRestitution() * body1->getRestitution(); } +btScalar btManifoldResult::calculateCombinedContactDamping(const btCollisionObject* body0,const btCollisionObject* body1) +{ + return body0->getContactDamping() + body1->getContactDamping(); +} + +btScalar btManifoldResult::calculateCombinedContactStiffness(const btCollisionObject* body0,const btCollisionObject* body1) +{ + + btScalar s0 = body0->getContactStiffness(); + btScalar s1 = body1->getContactStiffness(); + + btScalar tmp0 = btScalar(1)/s0; + btScalar tmp1 = btScalar(1)/s1; + btScalar combinedStiffness = btScalar(1) / (tmp0+tmp1); + return combinedStiffness; +} btManifoldResult::btManifoldResult(const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap) @@ -70,6 +96,7 @@ btManifoldResult::btManifoldResult(const btCollisionObjectWrapper* body0Wrap,con m_index0(-1), m_index1(-1) #endif //DEBUG_PART_INDEX + , m_closestPointDistanceThreshold(0) { } @@ -84,6 +111,7 @@ void btManifoldResult::addContactPoint(const btVector3& normalOnBInWorld,const b return; bool isSwapped = m_manifoldPtr->getBody0() != m_body0Wrap->getCollisionObject(); + bool isNewCollision = m_manifoldPtr->getNumContacts() == 0; btVector3 pointA = pointInWorld + normalOnBInWorld * depth; @@ -109,6 +137,22 @@ void btManifoldResult::addContactPoint(const btVector3& normalOnBInWorld,const b newPt.m_combinedFriction = calculateCombinedFriction(m_body0Wrap->getCollisionObject(),m_body1Wrap->getCollisionObject()); newPt.m_combinedRestitution = calculateCombinedRestitution(m_body0Wrap->getCollisionObject(),m_body1Wrap->getCollisionObject()); newPt.m_combinedRollingFriction = calculateCombinedRollingFriction(m_body0Wrap->getCollisionObject(),m_body1Wrap->getCollisionObject()); + newPt.m_combinedSpinningFriction = calculateCombinedSpinningFriction(m_body0Wrap->getCollisionObject(),m_body1Wrap->getCollisionObject()); + + if ( (m_body0Wrap->getCollisionObject()->getCollisionFlags()& btCollisionObject::CF_HAS_CONTACT_STIFFNESS_DAMPING) || + (m_body1Wrap->getCollisionObject()->getCollisionFlags()& btCollisionObject::CF_HAS_CONTACT_STIFFNESS_DAMPING)) + { + newPt.m_combinedContactDamping1 = calculateCombinedContactDamping(m_body0Wrap->getCollisionObject(),m_body1Wrap->getCollisionObject()); + newPt.m_combinedContactStiffness1 = calculateCombinedContactStiffness(m_body0Wrap->getCollisionObject(),m_body1Wrap->getCollisionObject()); + newPt.m_contactPointFlags |= BT_CONTACT_FLAG_CONTACT_STIFFNESS_DAMPING; + } + + if ( (m_body0Wrap->getCollisionObject()->getCollisionFlags()& btCollisionObject::CF_HAS_FRICTION_ANCHOR) || + (m_body1Wrap->getCollisionObject()->getCollisionFlags()& btCollisionObject::CF_HAS_FRICTION_ANCHOR)) + { + newPt.m_contactPointFlags |= BT_CONTACT_FLAG_FRICTION_ANCHOR; + } + btPlaneSpace1(newPt.m_normalWorldOnB,newPt.m_lateralFrictionDir1,newPt.m_lateralFrictionDir2); @@ -150,5 +194,9 @@ void btManifoldResult::addContactPoint(const btVector3& normalOnBInWorld,const b (*gContactAddedCallback)(m_manifoldPtr->getContactPoint(insertIndex),obj0Wrap,newPt.m_partId0,newPt.m_index0,obj1Wrap,newPt.m_partId1,newPt.m_index1); } + if (gContactStartedCallback && isNewCollision) + { + gContactStartedCallback(m_manifoldPtr); + } } diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btManifoldResult.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btManifoldResult.h similarity index 88% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btManifoldResult.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btManifoldResult.h index 977b9a02fc55..86bbc3f7295d 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btManifoldResult.h +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btManifoldResult.h @@ -49,17 +49,19 @@ class btManifoldResult : public btDiscreteCollisionDetectorInterface::Result int m_index0; int m_index1; - + public: btManifoldResult() -#ifdef DEBUG_PART_INDEX : +#ifdef DEBUG_PART_INDEX + m_partId0(-1), m_partId1(-1), m_index0(-1), m_index1(-1) #endif //DEBUG_PART_INDEX + m_closestPointDistanceThreshold(0) { } @@ -142,9 +144,15 @@ class btManifoldResult : public btDiscreteCollisionDetectorInterface::Result return m_body1Wrap->getCollisionObject(); } + btScalar m_closestPointDistanceThreshold; + /// in the future we can let the user override the methods to combine restitution and friction static btScalar calculateCombinedRestitution(const btCollisionObject* body0,const btCollisionObject* body1); static btScalar calculateCombinedFriction(const btCollisionObject* body0,const btCollisionObject* body1); + static btScalar calculateCombinedRollingFriction(const btCollisionObject* body0,const btCollisionObject* body1); + static btScalar calculateCombinedSpinningFriction(const btCollisionObject* body0,const btCollisionObject* body1); + static btScalar calculateCombinedContactDamping(const btCollisionObject* body0,const btCollisionObject* body1); + static btScalar calculateCombinedContactStiffness(const btCollisionObject* body0,const btCollisionObject* body1); }; #endif //BT_MANIFOLD_RESULT_H diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btSimulationIslandManager.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btSimulationIslandManager.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btSimulationIslandManager.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btSimulationIslandManager.h diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp similarity index 97% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp index 36ba21f5bb0c..27eaec3059fb 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp @@ -12,6 +12,7 @@ subject to the following restrictions: 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 CLEAR_MANIFOLD 1 #include "btSphereSphereCollisionAlgorithm.h" #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" @@ -62,7 +63,7 @@ void btSphereSphereCollisionAlgorithm::processCollision (const btCollisionObject #endif ///iff distance positive, don't generate a new contact - if ( len > (radius0+radius1)) + if ( len > (radius0+radius1+resultOut->m_closestPointDistanceThreshold)) { #ifndef CLEAR_MANIFOLD resultOut->refreshContactPoints(); diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp similarity index 97% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp index 280a4d355fdf..86d4e7440094 100644 --- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp +++ b/extern/bullet/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp @@ -56,7 +56,7 @@ void btSphereTriangleCollisionAlgorithm::processCollision (const btCollisionObje /// report a contact. internally this will be kept persistent, and contact reduction is done resultOut->setPersistentManifold(m_manifoldPtr); - SphereTriangleDetector detector(sphere,triangle, m_manifoldPtr->getContactBreakingThreshold()); + SphereTriangleDetector detector(sphere,triangle, m_manifoldPtr->getContactBreakingThreshold()+ resultOut->m_closestPointDistanceThreshold); btDiscreteCollisionDetectorInterface::ClosestPointInput input; input.m_maximumDistanceSquared = btScalar(BT_LARGE_FLOAT);///@todo: tighter bounds diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.h diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btUnionFind.cpp b/extern/bullet/src/BulletCollision/CollisionDispatch/btUnionFind.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btUnionFind.cpp rename to extern/bullet/src/BulletCollision/CollisionDispatch/btUnionFind.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btUnionFind.h b/extern/bullet/src/BulletCollision/CollisionDispatch/btUnionFind.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionDispatch/btUnionFind.h rename to extern/bullet/src/BulletCollision/CollisionDispatch/btUnionFind.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btBox2dShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btBox2dShape.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btBox2dShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btBox2dShape.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btBox2dShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btBox2dShape.h similarity index 99% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btBox2dShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btBox2dShape.h index ce333783e44d..22bee4f2c839 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btBox2dShape.h +++ b/extern/bullet/src/BulletCollision/CollisionShapes/btBox2dShape.h @@ -103,11 +103,12 @@ ATTRIBUTE_ALIGNED16(class) btBox2dShape: public btPolyhedralConvexShape btScalar minDimension = boxHalfExtents.getX(); if (minDimension>boxHalfExtents.getY()) minDimension = boxHalfExtents.getY(); - setSafeMargin(minDimension); m_shapeType = BOX_2D_SHAPE_PROXYTYPE; btVector3 margin(getMargin(),getMargin(),getMargin()); m_implicitShapeDimensions = (boxHalfExtents * m_localScaling) - margin; + + setSafeMargin(minDimension); }; virtual void setMargin(btScalar collisionMargin) diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btBoxShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btBoxShape.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btBoxShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btBoxShape.cpp index 3859138f18af..72eeb38911f2 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btBoxShape.cpp +++ b/extern/bullet/src/BulletCollision/CollisionShapes/btBoxShape.cpp @@ -19,10 +19,10 @@ btBoxShape::btBoxShape( const btVector3& boxHalfExtents) { m_shapeType = BOX_SHAPE_PROXYTYPE; - setSafeMargin(boxHalfExtents); - btVector3 margin(getMargin(),getMargin(),getMargin()); m_implicitShapeDimensions = (boxHalfExtents * m_localScaling) - margin; + + setSafeMargin(boxHalfExtents); }; diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btBoxShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btBoxShape.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btBoxShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btBoxShape.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp similarity index 98% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp index ace4cfa26465..61f465cb729e 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp +++ b/extern/bullet/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp @@ -245,16 +245,18 @@ void btBvhTriangleMeshShape::processAllTriangles(btTriangleCallback* callback,co btStridingMeshInterface* m_meshInterface; btTriangleCallback* m_callback; btVector3 m_triangle[3]; - + int m_numOverlap; MyNodeOverlapCallback(btTriangleCallback* callback,btStridingMeshInterface* meshInterface) :m_meshInterface(meshInterface), - m_callback(callback) + m_callback(callback), + m_numOverlap(0) { } virtual void processNode(int nodeSubPart, int nodeTriangleIndex) { + m_numOverlap++; const unsigned char *vertexbase; int numverts; PHY_ScalarType type; @@ -321,8 +323,7 @@ void btBvhTriangleMeshShape::processAllTriangles(btTriangleCallback* callback,co MyNodeOverlapCallback myNodeCallback(callback,m_meshInterface); m_bvh->reportAabbOverlappingNodex(&myNodeCallback,aabbMin,aabbMax); - - + #endif//DISABLE_BVH @@ -436,6 +437,9 @@ const char* btBvhTriangleMeshShape::serialize(void* dataBuffer, btSerializer* se trimeshData->m_triangleInfoMap = 0; } + // Fill padding with zeros to appease msan. + memset(trimeshData->m_pad3, 0, sizeof(trimeshData->m_pad3)); + return "btTriangleMeshShapeData"; } diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCapsuleShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btCapsuleShape.cpp similarity index 87% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btCapsuleShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btCapsuleShape.cpp index 864df26e9314..0345501ce24f 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btCapsuleShape.cpp +++ b/extern/bullet/src/BulletCollision/CollisionShapes/btCapsuleShape.cpp @@ -16,11 +16,11 @@ subject to the following restrictions: #include "btCapsuleShape.h" -#include "BulletCollision/CollisionShapes/btCollisionMargin.h" #include "LinearMath/btQuaternion.h" btCapsuleShape::btCapsuleShape(btScalar radius, btScalar height) : btConvexInternalShape () { + m_collisionMargin = radius; m_shapeType = CAPSULE_SHAPE_PROXYTYPE; m_upAxis = 1; m_implicitShapeDimensions.setValue(radius,0.5f*height,radius); @@ -48,14 +48,13 @@ btCapsuleShape::btCapsuleShape(btScalar radius, btScalar height) : btConvexInter btVector3 vtx; btScalar newDot; - btScalar radius = getRadius(); - + { btVector3 pos(0,0,0); pos[getUpAxis()] = getHalfHeight(); - vtx = pos +vec*(radius) - vec * getMargin(); + vtx = pos; newDot = vec.dot(vtx); if (newDot > maxDot) { @@ -67,7 +66,7 @@ btCapsuleShape::btCapsuleShape(btScalar radius, btScalar height) : btConvexInter btVector3 pos(0,0,0); pos[getUpAxis()] = -getHalfHeight(); - vtx = pos +vec*(radius) - vec * getMargin(); + vtx = pos; newDot = vec.dot(vtx); if (newDot > maxDot) { @@ -84,8 +83,7 @@ btCapsuleShape::btCapsuleShape(btScalar radius, btScalar height) : btConvexInter { - btScalar radius = getRadius(); - + for (int j=0;j maxDot) { @@ -107,7 +105,7 @@ btCapsuleShape::btCapsuleShape(btScalar radius, btScalar height) : btConvexInter { btVector3 pos(0,0,0); pos[getUpAxis()] = -getHalfHeight(); - vtx = pos +vec*(radius) - vec * getMargin(); + vtx = pos; newDot = vec.dot(vtx); if (newDot > maxDot) { @@ -133,11 +131,9 @@ void btCapsuleShape::calculateLocalInertia(btScalar mass,btVector3& inertia) con btVector3 halfExtents(radius,radius,radius); halfExtents[getUpAxis()]+=getHalfHeight(); - 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); + btScalar lx=btScalar(2.)*(halfExtents[0]); + btScalar ly=btScalar(2.)*(halfExtents[1]); + btScalar lz=btScalar(2.)*(halfExtents[2]); const btScalar x2 = lx*lx; const btScalar y2 = ly*ly; const btScalar z2 = lz*lz; @@ -151,6 +147,7 @@ void btCapsuleShape::calculateLocalInertia(btScalar mass,btVector3& inertia) con btCapsuleShapeX::btCapsuleShapeX(btScalar radius,btScalar height) { + m_collisionMargin = radius; m_upAxis = 0; m_implicitShapeDimensions.setValue(0.5f*height, radius,radius); } @@ -162,6 +159,7 @@ btCapsuleShapeX::btCapsuleShapeX(btScalar radius,btScalar height) btCapsuleShapeZ::btCapsuleShapeZ(btScalar radius,btScalar height) { + m_collisionMargin = radius; m_upAxis = 2; m_implicitShapeDimensions.setValue(radius,radius,0.5f*height); } diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCapsuleShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btCapsuleShape.h similarity index 86% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btCapsuleShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btCapsuleShape.h index f8c55ace4eb9..7d64b46abf89 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btCapsuleShape.h +++ b/extern/bullet/src/BulletCollision/CollisionShapes/btCapsuleShape.h @@ -48,21 +48,13 @@ ATTRIBUTE_ALIGNED16(class) btCapsuleShape : public btConvexInternalShape virtual void setMargin(btScalar collisionMargin) { - //correct the m_implicitShapeDimensions for the margin - btVector3 oldMargin(getMargin(),getMargin(),getMargin()); - btVector3 implicitShapeDimensionsWithMargin = m_implicitShapeDimensions+oldMargin; - - btConvexInternalShape::setMargin(collisionMargin); - btVector3 newMargin(getMargin(),getMargin(),getMargin()); - m_implicitShapeDimensions = implicitShapeDimensionsWithMargin - newMargin; - + //don't override the margin for capsules, their entire radius == margin } virtual void getAabb (const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const { btVector3 halfExtents(getRadius(),getRadius(),getRadius()); halfExtents[m_upAxis] = getRadius() + getHalfHeight(); - halfExtents += btVector3(getMargin(),getMargin(),getMargin()); btMatrix3x3 abs_b = t.getBasis().absolute(); btVector3 center = t.getOrigin(); btVector3 extent = halfExtents.dot3(abs_b[0], abs_b[1], abs_b[2]); @@ -94,14 +86,12 @@ ATTRIBUTE_ALIGNED16(class) btCapsuleShape : public btConvexInternalShape virtual void setLocalScaling(const btVector3& scaling) { - btVector3 oldMargin(getMargin(),getMargin(),getMargin()); - btVector3 implicitShapeDimensionsWithMargin = m_implicitShapeDimensions+oldMargin; - btVector3 unScaledImplicitShapeDimensionsWithMargin = implicitShapeDimensionsWithMargin / m_localScaling; - - btConvexInternalShape::setLocalScaling(scaling); - - m_implicitShapeDimensions = (unScaledImplicitShapeDimensionsWithMargin * m_localScaling) - oldMargin; - + btVector3 unScaledImplicitShapeDimensions = m_implicitShapeDimensions / m_localScaling; + btConvexInternalShape::setLocalScaling(scaling); + m_implicitShapeDimensions = (unScaledImplicitShapeDimensions * scaling); + //update m_collisionMargin, since entire radius==margin + int radiusAxis = (m_upAxis+2)%3; + m_collisionMargin = m_implicitShapeDimensions[radiusAxis]; } virtual btVector3 getAnisotropicRollingFrictionDirection() const @@ -174,11 +164,17 @@ SIMD_FORCE_INLINE int btCapsuleShape::calculateSerializeBufferSize() const SIMD_FORCE_INLINE const char* btCapsuleShape::serialize(void* dataBuffer, btSerializer* serializer) const { btCapsuleShapeData* shapeData = (btCapsuleShapeData*) dataBuffer; - + btConvexInternalShape::serialize(&shapeData->m_convexInternalShapeData,serializer); shapeData->m_upAxis = m_upAxis; - + + // Fill padding with zeros to appease msan. + shapeData->m_padding[0] = 0; + shapeData->m_padding[1] = 0; + shapeData->m_padding[2] = 0; + shapeData->m_padding[3] = 0; + return "btCapsuleShapeData"; } diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionMargin.h b/extern/bullet/src/BulletCollision/CollisionShapes/btCollisionMargin.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionMargin.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btCollisionMargin.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btCollisionShape.cpp similarity index 97% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btCollisionShape.cpp index 39ee21cad73c..823e2788f2e7 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionShape.cpp +++ b/extern/bullet/src/BulletCollision/CollisionShapes/btCollisionShape.cpp @@ -106,7 +106,10 @@ const char* btCollisionShape::serialize(void* dataBuffer, btSerializer* serializ serializer->serializeName(name); } shapeData->m_shapeType = m_shapeType; - //shapeData->m_padding//?? + + // Fill padding with zeros to appease msan. + memset(shapeData->m_padding, 0, sizeof(shapeData->m_padding)); + return "btCollisionShapeData"; } diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btCollisionShape.h similarity index 98% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btCollisionShape.h index 5e86568005ec..6c4916fbd4bd 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btCollisionShape.h +++ b/extern/bullet/src/BulletCollision/CollisionShapes/btCollisionShape.h @@ -48,7 +48,7 @@ ATTRIBUTE_ALIGNED16(class) btCollisionShape virtual void getBoundingSphere(btVector3& center,btScalar& radius) const; - ///getAngularMotionDisc returns the maximus radius needed for Conservative Advancement to handle time-of-impact with rotations. + ///getAngularMotionDisc returns the maximum radius needed for Conservative Advancement to handle time-of-impact with rotations. virtual btScalar getAngularMotionDisc() const; virtual btScalar getContactBreakingThreshold(btScalar defaultContactThresholdFactor) const; diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btCompoundShape.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btCompoundShape.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btCompoundShape.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btCompoundShape.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConcaveShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btConcaveShape.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btConcaveShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btConcaveShape.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConcaveShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btConcaveShape.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btConcaveShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btConcaveShape.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConeShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btConeShape.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btConeShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btConeShape.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConeShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btConeShape.h similarity index 94% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btConeShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btConeShape.h index 4a0df0d558bb..3b44e3f272c4 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btConeShape.h +++ b/extern/bullet/src/BulletCollision/CollisionShapes/btConeShape.h @@ -43,6 +43,15 @@ ATTRIBUTE_ALIGNED16(class) btConeShape : public btConvexInternalShape btScalar getRadius() const { return m_radius;} btScalar getHeight() const { return m_height;} + void setRadius(const btScalar radius) + { + m_radius = radius; + } + void setHeight(const btScalar height) + { + m_height = height; + } + virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const { @@ -159,11 +168,17 @@ SIMD_FORCE_INLINE int btConeShape::calculateSerializeBufferSize() const SIMD_FORCE_INLINE const char* btConeShape::serialize(void* dataBuffer, btSerializer* serializer) const { btConeShapeData* shapeData = (btConeShapeData*) dataBuffer; - + btConvexInternalShape::serialize(&shapeData->m_convexInternalShapeData,serializer); - + shapeData->m_upIndex = m_coneIndices[1]; - + + // Fill padding with zeros to appease msan. + shapeData->m_padding[0] = 0; + shapeData->m_padding[1] = 0; + shapeData->m_padding[2] = 0; + shapeData->m_padding[3] = 0; + return "btConeShapeData"; } diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvex2dShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btConvex2dShape.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btConvex2dShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btConvex2dShape.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvex2dShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btConvex2dShape.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btConvex2dShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btConvex2dShape.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexHullShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btConvexHullShape.cpp similarity index 93% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btConvexHullShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btConvexHullShape.cpp index 02ea5033b156..eec2b8d769ea 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexHullShape.cpp +++ b/extern/bullet/src/BulletCollision/CollisionShapes/btConvexHullShape.cpp @@ -22,6 +22,8 @@ subject to the following restrictions: #include "LinearMath/btQuaternion.h" #include "LinearMath/btSerializer.h" +#include "btConvexPolyhedron.h" +#include "LinearMath/btConvexHullComputer.h" btConvexHullShape ::btConvexHullShape (const btScalar* points,int numPoints,int stride) : btPolyhedralConvexAabbCachingShape () { @@ -121,10 +123,17 @@ btVector3 btConvexHullShape::localGetSupportingVertex(const btVector3& vec)const } - - - - +void btConvexHullShape::optimizeConvexHull() +{ + btConvexHullComputer conv; + conv.compute(&m_unscaledPoints[0].getX(), sizeof(btVector3),m_unscaledPoints.size(),0.f,0.f); + int numVerts = conv.vertices.size(); + m_unscaledPoints.resize(0); + for (int i=0;ifinalizeChunk(chunk,btVector3DataName,BT_ARRAY_CODE,(void*)&m_unscaledPoints[0]); } - + + // Fill padding with zeros to appease msan. + memset(shapeData->m_padding3, 0, sizeof(shapeData->m_padding3)); + return "btConvexHullShapeData"; } diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexHullShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btConvexHullShape.h similarity index 99% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btConvexHullShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btConvexHullShape.h index 3bd598ec4e9d..0c12aeef156d 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexHullShape.h +++ b/extern/bullet/src/BulletCollision/CollisionShapes/btConvexHullShape.h @@ -55,9 +55,8 @@ ATTRIBUTE_ALIGNED16(class) btConvexHullShape : public btPolyhedralConvexAabbCach return getUnscaledPoints(); } - - - + void optimizeConvexHull(); + SIMD_FORCE_INLINE btVector3 getScaledPoint(int i) const { return m_unscaledPoints[i] * m_localScaling; diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexInternalShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btConvexInternalShape.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btConvexInternalShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btConvexInternalShape.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexInternalShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btConvexInternalShape.h similarity index 98% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btConvexInternalShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btConvexInternalShape.h index 37e04f5fc81b..1213b82fbe31 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexInternalShape.h +++ b/extern/bullet/src/BulletCollision/CollisionShapes/btConvexInternalShape.h @@ -172,6 +172,9 @@ SIMD_FORCE_INLINE const char* btConvexInternalShape::serialize(void* dataBuffer, m_localScaling.serializeFloat(shapeData->m_localScaling); shapeData->m_collisionMargin = float(m_collisionMargin); + // Fill padding with zeros to appease msan. + shapeData->m_padding = 0; + return "btConvexInternalShapeData"; } diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexPointCloudShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btConvexPointCloudShape.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btConvexPointCloudShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btConvexPointCloudShape.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexPointCloudShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btConvexPointCloudShape.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btConvexPointCloudShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btConvexPointCloudShape.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexPolyhedron.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btConvexPolyhedron.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btConvexPolyhedron.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btConvexPolyhedron.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexPolyhedron.h b/extern/bullet/src/BulletCollision/CollisionShapes/btConvexPolyhedron.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btConvexPolyhedron.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btConvexPolyhedron.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btConvexShape.cpp similarity index 97% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btConvexShape.cpp index 88018b4c6248..b31fbdcf237d 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.cpp +++ b/extern/bullet/src/BulletCollision/CollisionShapes/btConvexShape.cpp @@ -230,14 +230,13 @@ btVector3 btConvexShape::localGetSupportVertexWithoutMarginNonVirtual (const btV btScalar halfHeight = capsuleShape->getHalfHeight(); int capsuleUpAxis = capsuleShape->getUpAxis(); - btScalar radius = capsuleShape->getRadius(); btVector3 supVec(0,0,0); btScalar maxDot(btScalar(-BT_LARGE_FLOAT)); btVector3 vec = vec0; btScalar lenSqr = vec.length2(); - if (lenSqr < btScalar(0.0001)) + if (lenSqr < SIMD_EPSILON*SIMD_EPSILON) { vec.setValue(1,0,0); } else @@ -251,8 +250,7 @@ btVector3 btConvexShape::localGetSupportVertexWithoutMarginNonVirtual (const btV btVector3 pos(0,0,0); pos[capsuleUpAxis] = halfHeight; - //vtx = pos +vec*(radius); - vtx = pos +vec*(radius) - vec * capsuleShape->getMarginNV(); + vtx = pos; newDot = vec.dot(vtx); @@ -266,8 +264,7 @@ btVector3 btConvexShape::localGetSupportVertexWithoutMarginNonVirtual (const btV btVector3 pos(0,0,0); pos[capsuleUpAxis] = -halfHeight; - //vtx = pos +vec*(radius); - vtx = pos +vec*(radius) - vec * capsuleShape->getMarginNV(); + vtx = pos; newDot = vec.dot(vtx); if (newDot > maxDot) { @@ -427,7 +424,6 @@ void btConvexShape::getAabbNonVirtual (const btTransform& t, btVector3& aabbMin, btVector3 halfExtents(capsuleShape->getRadius(),capsuleShape->getRadius(),capsuleShape->getRadius()); int m_upAxis = capsuleShape->getUpAxis(); halfExtents[m_upAxis] = capsuleShape->getRadius() + capsuleShape->getHalfHeight(); - halfExtents += btVector3(capsuleShape->getMarginNonVirtual(),capsuleShape->getMarginNonVirtual(),capsuleShape->getMarginNonVirtual()); btMatrix3x3 abs_b = t.getBasis().absolute(); btVector3 center = t.getOrigin(); btVector3 extent = halfExtents.dot3(abs_b[0], abs_b[1], abs_b[2]); diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btConvexShape.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btConvexShape.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCylinderShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btCylinderShape.cpp similarity index 99% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btCylinderShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btCylinderShape.cpp index 6cfe43be4da7..604b3fc77085 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btCylinderShape.cpp +++ b/extern/bullet/src/BulletCollision/CollisionShapes/btCylinderShape.cpp @@ -19,10 +19,11 @@ btCylinderShape::btCylinderShape (const btVector3& halfExtents) :btConvexInternalShape(), m_upAxis(1) { - setSafeMargin(halfExtents); - btVector3 margin(getMargin(),getMargin(),getMargin()); m_implicitShapeDimensions = (halfExtents * m_localScaling) - margin; + + setSafeMargin(halfExtents); + m_shapeType = CYLINDER_SHAPE_PROXYTYPE; } diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCylinderShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btCylinderShape.h similarity index 97% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btCylinderShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btCylinderShape.h index 6f796950e1dd..a214a827c9d0 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btCylinderShape.h +++ b/extern/bullet/src/BulletCollision/CollisionShapes/btCylinderShape.h @@ -199,11 +199,17 @@ SIMD_FORCE_INLINE int btCylinderShape::calculateSerializeBufferSize() const SIMD_FORCE_INLINE const char* btCylinderShape::serialize(void* dataBuffer, btSerializer* serializer) const { btCylinderShapeData* shapeData = (btCylinderShapeData*) dataBuffer; - + btConvexInternalShape::serialize(&shapeData->m_convexInternalShapeData,serializer); shapeData->m_upAxis = m_upAxis; - + + // Fill padding with zeros to appease msan. + shapeData->m_padding[0] = 0; + shapeData->m_padding[1] = 0; + shapeData->m_padding[2] = 0; + shapeData->m_padding[3] = 0; + return "btCylinderShapeData"; } diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btEmptyShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btEmptyShape.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btEmptyShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btEmptyShape.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btEmptyShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btEmptyShape.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btEmptyShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btEmptyShape.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btMaterial.h b/extern/bullet/src/BulletCollision/CollisionShapes/btMaterial.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btMaterial.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btMaterial.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp similarity index 78% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp index 06707e24e552..899ef5005647 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp +++ b/extern/bullet/src/BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp @@ -55,6 +55,23 @@ btScalar btMinkowskiSumShape::getMargin() const void btMinkowskiSumShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const { (void)mass; - btAssert(0); - inertia.setValue(0,0,0); + //inertia of the AABB of the Minkowski sum + btTransform identity; + identity.setIdentity(); + btVector3 aabbMin,aabbMax; + getAabb(identity,aabbMin,aabbMax); + + btVector3 halfExtents = (aabbMax-aabbMin)*btScalar(0.5); + + btScalar margin = getMargin(); + + 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)); } diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btMinkowskiSumShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btMinkowskiSumShape.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btMinkowskiSumShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btMinkowskiSumShape.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp similarity index 94% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp index 6abfdffa6775..d5bf6d60fe3f 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp +++ b/extern/bullet/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp @@ -75,7 +75,7 @@ btMultiSphereShape::btMultiSphereShape (const btVector3* positions,const btScala int inner_count = MIN( numSpheres - k, 128 ); for( long i = 0; i < inner_count; i++ ) { - temp[i] = (*pos) +vec*m_localScaling*(*rad) - vec * getMargin(); + temp[i] = (*pos)*m_localScaling +vec*m_localScaling*(*rad) - vec * getMargin(); pos++; rad++; } @@ -113,7 +113,7 @@ btMultiSphereShape::btMultiSphereShape (const btVector3* positions,const btScala int inner_count = MIN( numSpheres - k, 128 ); for( long i = 0; i < inner_count; i++ ) { - temp[i] = (*pos) +vec*m_localScaling*(*rad) - vec * getMargin(); + temp[i] = (*pos)*m_localScaling +vec*m_localScaling*(*rad) - vec * getMargin(); pos++; rad++; } @@ -175,7 +175,10 @@ const char* btMultiSphereShape::serialize(void* dataBuffer, btSerializer* serial } serializer->finalizeChunk(chunk,"btPositionAndRadius",BT_ARRAY_CODE,(void*)&m_localPositionArray[0]); } - + + // Fill padding with zeros to appease msan. + memset(shapeData->m_padding, 0, sizeof(shapeData->m_padding)); + return "btMultiSphereShapeData"; } diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btMultiSphereShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btMultiSphereShape.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btMultiSphereShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btMultiSphereShape.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btOptimizedBvh.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btOptimizedBvh.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btOptimizedBvh.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btOptimizedBvh.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btOptimizedBvh.h b/extern/bullet/src/BulletCollision/CollisionShapes/btOptimizedBvh.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btOptimizedBvh.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btOptimizedBvh.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h similarity index 99% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h index 961d001a9dd2..7bf8e01c1fcb 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h +++ b/extern/bullet/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h @@ -93,10 +93,12 @@ class btPolyhedralConvexAabbCachingShape : public btPolyhedralConvexShape aabbMax = m_localAabbMax; } -public: +protected: btPolyhedralConvexAabbCachingShape(); +public: + inline void getNonvirtualAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax, btScalar margin) const { diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btShapeHull.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btShapeHull.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btShapeHull.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btShapeHull.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btShapeHull.h b/extern/bullet/src/BulletCollision/CollisionShapes/btShapeHull.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btShapeHull.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btShapeHull.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btSphereShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btSphereShape.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btSphereShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btSphereShape.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btSphereShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btSphereShape.h similarity index 96% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btSphereShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btSphereShape.h index b192efeeb8df..50561f7f54fd 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btSphereShape.h +++ b/extern/bullet/src/BulletCollision/CollisionShapes/btSphereShape.h @@ -29,8 +29,11 @@ ATTRIBUTE_ALIGNED16(class) btSphereShape : public btConvexInternalShape btSphereShape (btScalar radius) : btConvexInternalShape () { m_shapeType = SPHERE_SHAPE_PROXYTYPE; + m_localScaling.setValue(1.0, 1.0, 1.0); + m_implicitShapeDimensions.setZero(); m_implicitShapeDimensions.setX(radius); m_collisionMargin = radius; + m_padding = 0; } virtual btVector3 localGetSupportingVertex(const btVector3& vec)const; diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btStaticPlaneShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btStaticPlaneShape.h similarity index 95% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btStaticPlaneShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btStaticPlaneShape.h index e6e328839590..5e9eccc77d9e 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btStaticPlaneShape.h +++ b/extern/bullet/src/BulletCollision/CollisionShapes/btStaticPlaneShape.h @@ -94,7 +94,13 @@ SIMD_FORCE_INLINE const char* btStaticPlaneShape::serialize(void* dataBuffer, bt m_localScaling.serializeFloat(planeData->m_localScaling); m_planeNormal.serializeFloat(planeData->m_planeNormal); planeData->m_planeConstant = float(m_planeConstant); - + + // Fill padding with zeros to appease msan. + planeData->m_pad[0] = 0; + planeData->m_pad[1] = 0; + planeData->m_pad[2] = 0; + planeData->m_pad[3] = 0; + return "btStaticPlaneShapeData"; } diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btStridingMeshInterface.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btStridingMeshInterface.cpp similarity index 97% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btStridingMeshInterface.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btStridingMeshInterface.cpp index b3d449676b9a..78ddeb37047c 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btStridingMeshInterface.cpp +++ b/extern/bullet/src/BulletCollision/CollisionShapes/btStridingMeshInterface.cpp @@ -293,6 +293,9 @@ const char* btStridingMeshInterface::serialize(void* dataBuffer, btSerializer* s tmpIndices[gfxindex].m_values[0] = tri_indices[0]; tmpIndices[gfxindex].m_values[1] = tri_indices[1]; tmpIndices[gfxindex].m_values[2] = tri_indices[2]; + // Fill padding with zeros to appease msan. + tmpIndices[gfxindex].m_pad[0] = 0; + tmpIndices[gfxindex].m_pad[1] = 0; } serializer->finalizeChunk(chunk,"btShortIntIndexTripletData",BT_ARRAY_CODE,(void*)chunk->m_oldPtr); } @@ -311,6 +314,8 @@ const char* btStridingMeshInterface::serialize(void* dataBuffer, btSerializer* s tmpIndices[gfxindex].m_values[0] = tri_indices[0]; tmpIndices[gfxindex].m_values[1] = tri_indices[1]; tmpIndices[gfxindex].m_values[2] = tri_indices[2]; + // Fill padding with zeros to appease msan. + tmpIndices[gfxindex].m_pad = 0; } serializer->finalizeChunk(chunk,"btCharIndexTripletData",BT_ARRAY_CODE,(void*)chunk->m_oldPtr); } @@ -375,6 +380,8 @@ const char* btStridingMeshInterface::serialize(void* dataBuffer, btSerializer* s serializer->finalizeChunk(chunk,"btMeshPartData",BT_ARRAY_CODE,chunk->m_oldPtr); } + // Fill padding with zeros to appease msan. + memset(trimeshData->m_padding, 0, sizeof(trimeshData->m_padding)); m_scaling.serializeFloat(trimeshData->m_scaling); return "btStridingMeshInterfaceData"; diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btStridingMeshInterface.h b/extern/bullet/src/BulletCollision/CollisionShapes/btStridingMeshInterface.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btStridingMeshInterface.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btStridingMeshInterface.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTetrahedronShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btTetrahedronShape.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btTetrahedronShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btTetrahedronShape.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTetrahedronShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btTetrahedronShape.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btTetrahedronShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btTetrahedronShape.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleBuffer.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btTriangleBuffer.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleBuffer.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btTriangleBuffer.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleBuffer.h b/extern/bullet/src/BulletCollision/CollisionShapes/btTriangleBuffer.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleBuffer.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btTriangleBuffer.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleCallback.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btTriangleCallback.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleCallback.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btTriangleCallback.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleCallback.h b/extern/bullet/src/BulletCollision/CollisionShapes/btTriangleCallback.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleCallback.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btTriangleCallback.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h b/extern/bullet/src/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.h b/extern/bullet/src/BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleInfoMap.h b/extern/bullet/src/BulletCollision/CollisionShapes/btTriangleInfoMap.h similarity index 98% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleInfoMap.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btTriangleInfoMap.h index 17deef89d377..642758959011 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleInfoMap.h +++ b/extern/bullet/src/BulletCollision/CollisionShapes/btTriangleInfoMap.h @@ -195,6 +195,13 @@ SIMD_FORCE_INLINE const char* btTriangleInfoMap::serialize(void* dataBuffer, btS serializer->finalizeChunk(chunk,"int",BT_ARRAY_CODE,(void*) &m_keyArray[0]); } + + // Fill padding with zeros to appease msan. + tmapData->m_padding[0] = 0; + tmapData->m_padding[1] = 0; + tmapData->m_padding[2] = 0; + tmapData->m_padding[3] = 0; + return "btTriangleInfoMapData"; } diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btTriangleMesh.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btTriangleMesh.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.h b/extern/bullet/src/BulletCollision/CollisionShapes/btTriangleMesh.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMesh.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btTriangleMesh.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMeshShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btTriangleMeshShape.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleMeshShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btTriangleMeshShape.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btTriangleShape.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btTriangleShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btTriangleShape.h diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btUniformScalingShape.cpp b/extern/bullet/src/BulletCollision/CollisionShapes/btUniformScalingShape.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btUniformScalingShape.cpp rename to extern/bullet/src/BulletCollision/CollisionShapes/btUniformScalingShape.cpp diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btUniformScalingShape.h b/extern/bullet/src/BulletCollision/CollisionShapes/btUniformScalingShape.h similarity index 100% rename from extern/bullet2/src/BulletCollision/CollisionShapes/btUniformScalingShape.h rename to extern/bullet/src/BulletCollision/CollisionShapes/btUniformScalingShape.h diff --git a/extern/bullet2/src/BulletCollision/Gimpact/btBoxCollision.h b/extern/bullet/src/BulletCollision/Gimpact/btBoxCollision.h similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/btBoxCollision.h rename to extern/bullet/src/BulletCollision/Gimpact/btBoxCollision.h diff --git a/extern/bullet2/src/BulletCollision/Gimpact/btClipPolygon.h b/extern/bullet/src/BulletCollision/Gimpact/btClipPolygon.h similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/btClipPolygon.h rename to extern/bullet/src/BulletCollision/Gimpact/btClipPolygon.h diff --git a/extern/bullet2/src/BulletCollision/Gimpact/btCompoundFromGimpact.h b/extern/bullet/src/BulletCollision/Gimpact/btCompoundFromGimpact.h similarity index 86% rename from extern/bullet2/src/BulletCollision/Gimpact/btCompoundFromGimpact.h rename to extern/bullet/src/BulletCollision/Gimpact/btCompoundFromGimpact.h index 02f8b678a45d..19f7ecddd0e7 100644 --- a/extern/bullet2/src/BulletCollision/Gimpact/btCompoundFromGimpact.h +++ b/extern/bullet/src/BulletCollision/Gimpact/btCompoundFromGimpact.h @@ -5,6 +5,22 @@ #include "btGImpactShape.h" #include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h" +ATTRIBUTE_ALIGNED16(class) btCompoundFromGimpactShape : public btCompoundShape +{ +public: + BT_DECLARE_ALIGNED_ALLOCATOR(); + + virtual ~btCompoundFromGimpactShape() + { + /*delete all the btBU_Simplex1to4 ChildShapes*/ + for (int i = 0; i < m_children.size(); i++) + { + delete m_children[i].m_childShape; + } + } + +}; + struct MyCallback : public btTriangleRaycastCallback { int m_ignorePart; @@ -77,7 +93,7 @@ struct MyCallback : public btTriangleRaycastCallback btCompoundShape* btCreateCompoundFromGimpactShape(const btGImpactMeshShape* gimpactMesh, btScalar depth) { - btCompoundShape* colShape = new btCompoundShape(); + btCompoundShape* colShape = new btCompoundFromGimpactShape(); btTransform tr; tr.setIdentity(); @@ -90,4 +106,4 @@ btCompoundShape* btCreateCompoundFromGimpactShape(const btGImpactMeshShape* gimp return colShape; } -#endif //BT_COMPOUND_FROM_GIMPACT \ No newline at end of file +#endif //BT_COMPOUND_FROM_GIMPACT diff --git a/extern/bullet2/src/BulletCollision/Gimpact/btContactProcessing.cpp b/extern/bullet/src/BulletCollision/Gimpact/btContactProcessing.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/btContactProcessing.cpp rename to extern/bullet/src/BulletCollision/Gimpact/btContactProcessing.cpp diff --git a/extern/bullet/src/BulletCollision/Gimpact/btContactProcessing.h b/extern/bullet/src/BulletCollision/Gimpact/btContactProcessing.h new file mode 100644 index 000000000000..d1027dbe67e4 --- /dev/null +++ b/extern/bullet/src/BulletCollision/Gimpact/btContactProcessing.h @@ -0,0 +1,65 @@ +#ifndef BT_CONTACT_H_INCLUDED +#define BT_CONTACT_H_INCLUDED + +/*! \file gim_contact.h +\author Francisco Leon Najera +*/ +/* +This source file is part of GIMPACT Library. + +For the latest info, see http://gimpact.sourceforge.net/ + +Copyright (c) 2007 Francisco Leon Najera. C.C. 80087371. +email: projectileman@yahoo.com + + +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/btTransform.h" +#include "LinearMath/btAlignedObjectArray.h" +#include "btTriangleShapeEx.h" +#include "btContactProcessingStructs.h" + +class btContactArray:public btAlignedObjectArray +{ +public: + btContactArray() + { + reserve(64); + } + + SIMD_FORCE_INLINE void push_contact( + const btVector3 &point,const btVector3 & normal, + btScalar depth, int feature1, int feature2) + { + push_back( GIM_CONTACT(point,normal,depth,feature1,feature2) ); + } + + SIMD_FORCE_INLINE void push_triangle_contacts( + const GIM_TRIANGLE_CONTACT & tricontact, + int feature1,int feature2) + { + for(int i = 0;i -{ -public: - btContactArray() - { - reserve(64); - } - - SIMD_FORCE_INLINE void push_contact( - const btVector3 &point,const btVector3 & normal, - btScalar depth, int feature1, int feature2) - { - push_back( GIM_CONTACT(point,normal,depth,feature1,feature2) ); - } - - SIMD_FORCE_INLINE void push_triangle_contacts( - const GIM_TRIANGLE_CONTACT & tricontact, - int feature1,int feature2) - { - for(int i = 0;i @@ -74,59 +50,6 @@ class btPairSet: public btAlignedObjectArray } }; - -///GIM_BVH_DATA is an internal GIMPACT collision structure to contain axis aligned bounding box -struct GIM_BVH_DATA -{ - btAABB m_bound; - int m_data; -}; - -//! Node Structure for trees -class GIM_BVH_TREE_NODE -{ -public: - btAABB m_bound; -protected: - int m_escapeIndexOrDataIndex; -public: - GIM_BVH_TREE_NODE() - { - m_escapeIndexOrDataIndex = 0; - } - - SIMD_FORCE_INLINE bool isLeafNode() const - { - //skipindex is negative (internal node), triangleindex >=0 (leafnode) - return (m_escapeIndexOrDataIndex>=0); - } - - SIMD_FORCE_INLINE int getEscapeIndex() const - { - //btAssert(m_escapeIndexOrDataIndex < 0); - return -m_escapeIndexOrDataIndex; - } - - SIMD_FORCE_INLINE void setEscapeIndex(int index) - { - m_escapeIndexOrDataIndex = -index; - } - - SIMD_FORCE_INLINE int getDataIndex() const - { - //btAssert(m_escapeIndexOrDataIndex >= 0); - - return m_escapeIndexOrDataIndex; - } - - SIMD_FORCE_INLINE void setDataIndex(int index) - { - m_escapeIndexOrDataIndex = index; - } - -}; - - class GIM_BVH_DATA_ARRAY:public btAlignedObjectArray { }; @@ -392,5 +315,4 @@ class btGImpactBvh btPairSet & collision_pairs); }; - #endif // GIM_BOXPRUNING_H_INCLUDED diff --git a/extern/bullet/src/BulletCollision/Gimpact/btGImpactBvhStructs.h b/extern/bullet/src/BulletCollision/Gimpact/btGImpactBvhStructs.h new file mode 100644 index 000000000000..9342a572d09c --- /dev/null +++ b/extern/bullet/src/BulletCollision/Gimpact/btGImpactBvhStructs.h @@ -0,0 +1,105 @@ +#ifndef GIM_BOX_SET_STRUCT_H_INCLUDED +#define GIM_BOX_SET_STRUCT_H_INCLUDED + +/*! \file gim_box_set.h +\author Francisco Leon Najera +*/ +/* +This source file is part of GIMPACT Library. + +For the latest info, see http://gimpact.sourceforge.net/ + +Copyright (c) 2007 Francisco Leon Najera. C.C. 80087371. +email: projectileman@yahoo.com + + +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/btAlignedObjectArray.h" + +#include "btBoxCollision.h" +#include "btTriangleShapeEx.h" + +//! Overlapping pair +struct GIM_PAIR +{ + int m_index1; + int m_index2; + GIM_PAIR() + {} + + GIM_PAIR(const GIM_PAIR & p) + { + m_index1 = p.m_index1; + m_index2 = p.m_index2; + } + + GIM_PAIR(int index1, int index2) + { + m_index1 = index1; + m_index2 = index2; + } +}; + +///GIM_BVH_DATA is an internal GIMPACT collision structure to contain axis aligned bounding box +struct GIM_BVH_DATA +{ + btAABB m_bound; + int m_data; +}; + +//! Node Structure for trees +class GIM_BVH_TREE_NODE +{ +public: + btAABB m_bound; +protected: + int m_escapeIndexOrDataIndex; +public: + GIM_BVH_TREE_NODE() + { + m_escapeIndexOrDataIndex = 0; + } + + SIMD_FORCE_INLINE bool isLeafNode() const + { + //skipindex is negative (internal node), triangleindex >=0 (leafnode) + return (m_escapeIndexOrDataIndex>=0); + } + + SIMD_FORCE_INLINE int getEscapeIndex() const + { + //btAssert(m_escapeIndexOrDataIndex < 0); + return -m_escapeIndexOrDataIndex; + } + + SIMD_FORCE_INLINE void setEscapeIndex(int index) + { + m_escapeIndexOrDataIndex = -index; + } + + SIMD_FORCE_INLINE int getDataIndex() const + { + //btAssert(m_escapeIndexOrDataIndex >= 0); + + return m_escapeIndexOrDataIndex; + } + + SIMD_FORCE_INLINE void setDataIndex(int index) + { + m_escapeIndexOrDataIndex = index; + } + +}; + +#endif // GIM_BOXPRUNING_H_INCLUDED diff --git a/extern/bullet2/src/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.cpp b/extern/bullet/src/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.cpp rename to extern/bullet/src/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.cpp diff --git a/extern/bullet2/src/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h b/extern/bullet/src/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h similarity index 99% rename from extern/bullet2/src/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h rename to extern/bullet/src/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h index f85a94cb4c7d..3e5675f729d4 100644 --- a/extern/bullet2/src/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h +++ b/extern/bullet/src/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h @@ -122,7 +122,7 @@ class btGImpactCollisionAlgorithm : public btActivatingCollisionAlgorithm checkManifold(body0Wrap,body1Wrap); btCollisionAlgorithm * convex_algorithm = m_dispatcher->findAlgorithm( - body0Wrap,body1Wrap,getLastManifold()); + body0Wrap,body1Wrap,getLastManifold(), BT_CONTACT_POINT_ALGORITHMS); return convex_algorithm ; } diff --git a/extern/bullet2/src/BulletCollision/Gimpact/btGImpactMassUtil.h b/extern/bullet/src/BulletCollision/Gimpact/btGImpactMassUtil.h similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/btGImpactMassUtil.h rename to extern/bullet/src/BulletCollision/Gimpact/btGImpactMassUtil.h diff --git a/extern/bullet2/src/BulletCollision/Gimpact/btGImpactQuantizedBvh.cpp b/extern/bullet/src/BulletCollision/Gimpact/btGImpactQuantizedBvh.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/btGImpactQuantizedBvh.cpp rename to extern/bullet/src/BulletCollision/Gimpact/btGImpactQuantizedBvh.cpp diff --git a/extern/bullet2/src/BulletCollision/Gimpact/btGImpactQuantizedBvh.h b/extern/bullet/src/BulletCollision/Gimpact/btGImpactQuantizedBvh.h similarity index 84% rename from extern/bullet2/src/BulletCollision/Gimpact/btGImpactQuantizedBvh.h rename to extern/bullet/src/BulletCollision/Gimpact/btGImpactQuantizedBvh.h index e6e52fff4c07..42e5520fc03a 100644 --- a/extern/bullet2/src/BulletCollision/Gimpact/btGImpactQuantizedBvh.h +++ b/extern/bullet/src/BulletCollision/Gimpact/btGImpactQuantizedBvh.h @@ -26,73 +26,7 @@ subject to the following restrictions: #include "btGImpactBvh.h" #include "btQuantization.h" - - - - - -///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) BT_QUANTIZED_BVH_NODE -{ - //12 bytes - unsigned short int m_quantizedAabbMin[3]; - unsigned short int m_quantizedAabbMax[3]; - //4 bytes - int m_escapeIndexOrDataIndex; - - BT_QUANTIZED_BVH_NODE() - { - m_escapeIndexOrDataIndex = 0; - } - - SIMD_FORCE_INLINE bool isLeafNode() const - { - //skipindex is negative (internal node), triangleindex >=0 (leafnode) - return (m_escapeIndexOrDataIndex>=0); - } - - SIMD_FORCE_INLINE int getEscapeIndex() const - { - //btAssert(m_escapeIndexOrDataIndex < 0); - return -m_escapeIndexOrDataIndex; - } - - SIMD_FORCE_INLINE void setEscapeIndex(int index) - { - m_escapeIndexOrDataIndex = -index; - } - - SIMD_FORCE_INLINE int getDataIndex() const - { - //btAssert(m_escapeIndexOrDataIndex >= 0); - - return m_escapeIndexOrDataIndex; - } - - SIMD_FORCE_INLINE void setDataIndex(int index) - { - m_escapeIndexOrDataIndex = index; - } - - SIMD_FORCE_INLINE bool testQuantizedBoxOverlapp( - unsigned short * quantizedMin,unsigned short * quantizedMax) const - { - if(m_quantizedAabbMin[0] > quantizedMax[0] || - m_quantizedAabbMax[0] < quantizedMin[0] || - m_quantizedAabbMin[1] > quantizedMax[1] || - m_quantizedAabbMax[1] < quantizedMin[1] || - m_quantizedAabbMin[2] > quantizedMax[2] || - m_quantizedAabbMax[2] < quantizedMin[2]) - { - return false; - } - return true; - } - -}; - - +#include "btGImpactQuantizedBvhStructs.h" class GIM_QUANTIZED_BVH_NODE_ARRAY:public btAlignedObjectArray { @@ -368,5 +302,4 @@ class btGImpactQuantizedBvh btPairSet & collision_pairs); }; - #endif // GIM_BOXPRUNING_H_INCLUDED diff --git a/extern/bullet/src/BulletCollision/Gimpact/btGImpactQuantizedBvhStructs.h b/extern/bullet/src/BulletCollision/Gimpact/btGImpactQuantizedBvhStructs.h new file mode 100644 index 000000000000..7dd5a1b9d01e --- /dev/null +++ b/extern/bullet/src/BulletCollision/Gimpact/btGImpactQuantizedBvhStructs.h @@ -0,0 +1,91 @@ +#ifndef GIM_QUANTIZED_SET_STRUCTS_H_INCLUDED +#define GIM_QUANTIZED_SET_STRUCTS_H_INCLUDED + +/*! \file btGImpactQuantizedBvh.h +\author Francisco Leon Najera +*/ +/* +This source file is part of GIMPACT Library. + +For the latest info, see http://gimpact.sourceforge.net/ + +Copyright (c) 2007 Francisco Leon Najera. C.C. 80087371. +email: projectileman@yahoo.com + + +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 "btGImpactBvh.h" +#include "btQuantization.h" + +///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) BT_QUANTIZED_BVH_NODE +{ + //12 bytes + unsigned short int m_quantizedAabbMin[3]; + unsigned short int m_quantizedAabbMax[3]; + //4 bytes + int m_escapeIndexOrDataIndex; + + BT_QUANTIZED_BVH_NODE() + { + m_escapeIndexOrDataIndex = 0; + } + + SIMD_FORCE_INLINE bool isLeafNode() const + { + //skipindex is negative (internal node), triangleindex >=0 (leafnode) + return (m_escapeIndexOrDataIndex>=0); + } + + SIMD_FORCE_INLINE int getEscapeIndex() const + { + //btAssert(m_escapeIndexOrDataIndex < 0); + return -m_escapeIndexOrDataIndex; + } + + SIMD_FORCE_INLINE void setEscapeIndex(int index) + { + m_escapeIndexOrDataIndex = -index; + } + + SIMD_FORCE_INLINE int getDataIndex() const + { + //btAssert(m_escapeIndexOrDataIndex >= 0); + + return m_escapeIndexOrDataIndex; + } + + SIMD_FORCE_INLINE void setDataIndex(int index) + { + m_escapeIndexOrDataIndex = index; + } + + SIMD_FORCE_INLINE bool testQuantizedBoxOverlapp( + unsigned short * quantizedMin,unsigned short * quantizedMax) const + { + if(m_quantizedAabbMin[0] > quantizedMax[0] || + m_quantizedAabbMax[0] < quantizedMin[0] || + m_quantizedAabbMin[1] > quantizedMax[1] || + m_quantizedAabbMax[1] < quantizedMin[1] || + m_quantizedAabbMin[2] > quantizedMax[2] || + m_quantizedAabbMax[2] < quantizedMin[2]) + { + return false; + } + return true; + } + +}; + +#endif // GIM_QUANTIZED_SET_STRUCTS_H_INCLUDED diff --git a/extern/bullet2/src/BulletCollision/Gimpact/btGImpactShape.cpp b/extern/bullet/src/BulletCollision/Gimpact/btGImpactShape.cpp similarity index 73% rename from extern/bullet2/src/BulletCollision/Gimpact/btGImpactShape.cpp rename to extern/bullet/src/BulletCollision/Gimpact/btGImpactShape.cpp index ac8efdf3833d..30c85e3fffd1 100644 --- a/extern/bullet2/src/BulletCollision/Gimpact/btGImpactShape.cpp +++ b/extern/bullet/src/BulletCollision/Gimpact/btGImpactShape.cpp @@ -23,6 +23,59 @@ subject to the following restrictions: #include "btGImpactMassUtil.h" +btGImpactMeshShapePart::btGImpactMeshShapePart( btStridingMeshInterface * meshInterface, int part ) +{ + // moved from .h to .cpp because of conditional compilation + // (The setting of BT_THREADSAFE may differ between various cpp files, so it is best to + // avoid using it in h files) + m_primitive_manager.m_meshInterface = meshInterface; + m_primitive_manager.m_part = part; + m_box_set.setPrimitiveManager( &m_primitive_manager ); +#if BT_THREADSAFE + // If threadsafe is requested, this object uses a different lock/unlock + // model with the btStridingMeshInterface -- lock once when the object is constructed + // and unlock once in the destructor. + // The other way of locking and unlocking for each collision check in the narrowphase + // is not threadsafe. Note these are not thread-locks, they are calls to the meshInterface's + // getLockedReadOnlyVertexIndexBase virtual function, which by default just returns a couple of + // pointers. In theory a client could override the lock function to do all sorts of + // things like reading data from GPU memory, or decompressing data on the fly, but such things + // do not seem all that likely or useful, given the performance cost. + m_primitive_manager.lock(); +#endif +} + +btGImpactMeshShapePart::~btGImpactMeshShapePart() +{ + // moved from .h to .cpp because of conditional compilation +#if BT_THREADSAFE + m_primitive_manager.unlock(); +#endif +} + +void btGImpactMeshShapePart::lockChildShapes() const +{ + // moved from .h to .cpp because of conditional compilation +#if ! BT_THREADSAFE + // called in the narrowphase -- not threadsafe! + void * dummy = (void*) ( m_box_set.getPrimitiveManager() ); + TrimeshPrimitiveManager * dummymanager = static_cast( dummy ); + dummymanager->lock(); +#endif +} + +void btGImpactMeshShapePart::unlockChildShapes() const +{ + // moved from .h to .cpp because of conditional compilation +#if ! BT_THREADSAFE + // called in the narrowphase -- not threadsafe! + void * dummy = (void*) ( m_box_set.getPrimitiveManager() ); + TrimeshPrimitiveManager * dummymanager = static_cast( dummy ); + dummymanager->unlock(); +#endif +} + + #define CALC_EXACT_INERTIA 1 diff --git a/extern/bullet2/src/BulletCollision/Gimpact/btGImpactShape.h b/extern/bullet/src/BulletCollision/Gimpact/btGImpactShape.h similarity index 97% rename from extern/bullet2/src/BulletCollision/Gimpact/btGImpactShape.h rename to extern/bullet/src/BulletCollision/Gimpact/btGImpactShape.h index 3d1f48d47767..9d7e40562c6a 100644 --- a/extern/bullet2/src/BulletCollision/Gimpact/btGImpactShape.h +++ b/extern/bullet/src/BulletCollision/Gimpact/btGImpactShape.h @@ -722,17 +722,8 @@ class btGImpactMeshShapePart : public btGImpactShapeInterface m_box_set.setPrimitiveManager(&m_primitive_manager); } - - btGImpactMeshShapePart(btStridingMeshInterface * meshInterface, int part) - { - m_primitive_manager.m_meshInterface = meshInterface; - m_primitive_manager.m_part = part; - m_box_set.setPrimitiveManager(&m_primitive_manager); - } - - virtual ~btGImpactMeshShapePart() - { - } + btGImpactMeshShapePart( btStridingMeshInterface * meshInterface, int part ); + virtual ~btGImpactMeshShapePart(); //! if true, then its children must get transforms. virtual bool childrenHasTransform() const @@ -742,19 +733,8 @@ class btGImpactMeshShapePart : public btGImpactShapeInterface //! call when reading child shapes - virtual void lockChildShapes() const - { - void * dummy = (void*)(m_box_set.getPrimitiveManager()); - TrimeshPrimitiveManager * dummymanager = static_cast(dummy); - dummymanager->lock(); - } - - virtual void unlockChildShapes() const - { - void * dummy = (void*)(m_box_set.getPrimitiveManager()); - TrimeshPrimitiveManager * dummymanager = static_cast(dummy); - dummymanager->unlock(); - } + virtual void lockChildShapes() const; + virtual void unlockChildShapes() const; //! Gets the number of children virtual int getNumChildShapes() const diff --git a/extern/bullet2/src/BulletCollision/Gimpact/btGenericPoolAllocator.cpp b/extern/bullet/src/BulletCollision/Gimpact/btGenericPoolAllocator.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/btGenericPoolAllocator.cpp rename to extern/bullet/src/BulletCollision/Gimpact/btGenericPoolAllocator.cpp diff --git a/extern/bullet2/src/BulletCollision/Gimpact/btGenericPoolAllocator.h b/extern/bullet/src/BulletCollision/Gimpact/btGenericPoolAllocator.h similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/btGenericPoolAllocator.h rename to extern/bullet/src/BulletCollision/Gimpact/btGenericPoolAllocator.h diff --git a/extern/bullet2/src/BulletCollision/Gimpact/btGeometryOperations.h b/extern/bullet/src/BulletCollision/Gimpact/btGeometryOperations.h similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/btGeometryOperations.h rename to extern/bullet/src/BulletCollision/Gimpact/btGeometryOperations.h diff --git a/extern/bullet2/src/BulletCollision/Gimpact/btQuantization.h b/extern/bullet/src/BulletCollision/Gimpact/btQuantization.h similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/btQuantization.h rename to extern/bullet/src/BulletCollision/Gimpact/btQuantization.h diff --git a/extern/bullet2/src/BulletCollision/Gimpact/btTriangleShapeEx.cpp b/extern/bullet/src/BulletCollision/Gimpact/btTriangleShapeEx.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/btTriangleShapeEx.cpp rename to extern/bullet/src/BulletCollision/Gimpact/btTriangleShapeEx.cpp diff --git a/extern/bullet2/src/BulletCollision/Gimpact/btTriangleShapeEx.h b/extern/bullet/src/BulletCollision/Gimpact/btTriangleShapeEx.h similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/btTriangleShapeEx.h rename to extern/bullet/src/BulletCollision/Gimpact/btTriangleShapeEx.h diff --git a/extern/bullet2/src/BulletCollision/Gimpact/gim_array.h b/extern/bullet/src/BulletCollision/Gimpact/gim_array.h similarity index 99% rename from extern/bullet2/src/BulletCollision/Gimpact/gim_array.h rename to extern/bullet/src/BulletCollision/Gimpact/gim_array.h index 27e6f32fc8b3..cda51a5fcecf 100644 --- a/extern/bullet2/src/BulletCollision/Gimpact/gim_array.h +++ b/extern/bullet/src/BulletCollision/Gimpact/gim_array.h @@ -228,7 +228,7 @@ class gim_array inline void push_back_memcpy(const T & obj) { this->growingCheck(); - irr_simd_memcpy(&m_data[m_size],&obj,sizeof(T)); + gim_simd_memcpy(&m_data[m_size],&obj,sizeof(T)); m_size++; } diff --git a/extern/bullet2/src/BulletCollision/Gimpact/gim_basic_geometry_operations.h b/extern/bullet/src/BulletCollision/Gimpact/gim_basic_geometry_operations.h similarity index 99% rename from extern/bullet2/src/BulletCollision/Gimpact/gim_basic_geometry_operations.h rename to extern/bullet/src/BulletCollision/Gimpact/gim_basic_geometry_operations.h index d98051da3d60..0c48cb60fc50 100644 --- a/extern/bullet2/src/BulletCollision/Gimpact/gim_basic_geometry_operations.h +++ b/extern/bullet/src/BulletCollision/Gimpact/gim_basic_geometry_operations.h @@ -41,10 +41,13 @@ email: projectileman@yahoo.com - +#ifndef PLANEDIREPSILON #define PLANEDIREPSILON 0.0000001f -#define PARALELENORMALS 0.000001f +#endif +#ifndef PARALELENORMALS +#define PARALELENORMALS 0.000001f +#endif #define TRIANGLE_NORMAL(v1,v2,v3,n)\ {\ diff --git a/extern/bullet2/src/BulletCollision/Gimpact/gim_bitset.h b/extern/bullet/src/BulletCollision/Gimpact/gim_bitset.h similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/gim_bitset.h rename to extern/bullet/src/BulletCollision/Gimpact/gim_bitset.h diff --git a/extern/bullet2/src/BulletCollision/Gimpact/gim_box_collision.h b/extern/bullet/src/BulletCollision/Gimpact/gim_box_collision.h similarity index 99% rename from extern/bullet2/src/BulletCollision/Gimpact/gim_box_collision.h rename to extern/bullet/src/BulletCollision/Gimpact/gim_box_collision.h index 9c572638acd4..a051b4fdbf2a 100644 --- a/extern/bullet2/src/BulletCollision/Gimpact/gim_box_collision.h +++ b/extern/bullet/src/BulletCollision/Gimpact/gim_box_collision.h @@ -97,6 +97,8 @@ email: projectileman@yahoo.com // return test_cross_edge_box(edge,absolute_edge,pointa,pointb,extend,1,0,0,1); //} +#ifndef TEST_CROSS_EDGE_BOX_MCR + #define TEST_CROSS_EDGE_BOX_MCR(edge,absolute_edge,pointa,pointb,_extend,i_dir_0,i_dir_1,i_comp_0,i_comp_1)\ {\ const btScalar dir0 = -edge[i_dir_0];\ @@ -113,6 +115,7 @@ email: projectileman@yahoo.com if(pmin>rad || -rad>pmax) return false;\ }\ +#endif #define TEST_CROSS_EDGE_BOX_X_AXIS_MCR(edge,absolute_edge,pointa,pointb,_extend)\ {\ @@ -190,8 +193,9 @@ class GIM_BOX_BOX_TRANSFORM_CACHE } }; - +#ifndef BOX_PLANE_EPSILON #define BOX_PLANE_EPSILON 0.000001f +#endif //! Axis aligned box class GIM_AABB @@ -571,7 +575,7 @@ class GIM_AABB } }; - +#ifndef BT_BOX_COLLISION_H_INCLUDED //! Compairison of transformation objects SIMD_FORCE_INLINE bool btCompareTransformsEqual(const btTransform & t1,const btTransform & t2) { @@ -582,6 +586,7 @@ SIMD_FORCE_INLINE bool btCompareTransformsEqual(const btTransform & t1,const btT if(!(t1.getBasis().getRow(2) == t2.getBasis().getRow(2)) ) return false; return true; } +#endif diff --git a/extern/bullet2/src/BulletCollision/Gimpact/gim_box_set.cpp b/extern/bullet/src/BulletCollision/Gimpact/gim_box_set.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/gim_box_set.cpp rename to extern/bullet/src/BulletCollision/Gimpact/gim_box_set.cpp diff --git a/extern/bullet2/src/BulletCollision/Gimpact/gim_box_set.h b/extern/bullet/src/BulletCollision/Gimpact/gim_box_set.h similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/gim_box_set.h rename to extern/bullet/src/BulletCollision/Gimpact/gim_box_set.h diff --git a/extern/bullet2/src/BulletCollision/Gimpact/gim_clip_polygon.h b/extern/bullet/src/BulletCollision/Gimpact/gim_clip_polygon.h similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/gim_clip_polygon.h rename to extern/bullet/src/BulletCollision/Gimpact/gim_clip_polygon.h diff --git a/extern/bullet2/src/BulletCollision/Gimpact/gim_contact.cpp b/extern/bullet/src/BulletCollision/Gimpact/gim_contact.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/gim_contact.cpp rename to extern/bullet/src/BulletCollision/Gimpact/gim_contact.cpp diff --git a/extern/bullet2/src/BulletCollision/Gimpact/gim_contact.h b/extern/bullet/src/BulletCollision/Gimpact/gim_contact.h similarity index 97% rename from extern/bullet2/src/BulletCollision/Gimpact/gim_contact.h rename to extern/bullet/src/BulletCollision/Gimpact/gim_contact.h index 5d9f8ef81807..b41c714b5f72 100644 --- a/extern/bullet2/src/BulletCollision/Gimpact/gim_contact.h +++ b/extern/bullet/src/BulletCollision/Gimpact/gim_contact.h @@ -40,8 +40,15 @@ email: projectileman@yahoo.com /** Configuration var for applying interpolation of contact normals */ +#ifndef NORMAL_CONTACT_AVERAGE #define NORMAL_CONTACT_AVERAGE 1 +#endif + +#ifndef CONTACT_DIFF_EPSILON #define CONTACT_DIFF_EPSILON 0.00001f +#endif + +#ifndef BT_CONTACT_H_STRUCTS_INCLUDED /// Structure for collision results ///Functions for managing and sorting contacts resulting from a collision query. @@ -121,6 +128,7 @@ class GIM_CONTACT }; +#endif class gim_contact_array:public gim_array { diff --git a/extern/bullet2/src/BulletCollision/Gimpact/gim_geom_types.h b/extern/bullet/src/BulletCollision/Gimpact/gim_geom_types.h similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/gim_geom_types.h rename to extern/bullet/src/BulletCollision/Gimpact/gim_geom_types.h diff --git a/extern/bullet2/src/BulletCollision/Gimpact/gim_geometry.h b/extern/bullet/src/BulletCollision/Gimpact/gim_geometry.h similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/gim_geometry.h rename to extern/bullet/src/BulletCollision/Gimpact/gim_geometry.h diff --git a/extern/bullet2/src/BulletCollision/Gimpact/gim_hash_table.h b/extern/bullet/src/BulletCollision/Gimpact/gim_hash_table.h similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/gim_hash_table.h rename to extern/bullet/src/BulletCollision/Gimpact/gim_hash_table.h diff --git a/extern/bullet2/src/BulletCollision/Gimpact/gim_linear_math.h b/extern/bullet/src/BulletCollision/Gimpact/gim_linear_math.h similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/gim_linear_math.h rename to extern/bullet/src/BulletCollision/Gimpact/gim_linear_math.h diff --git a/extern/bullet2/src/BulletCollision/Gimpact/gim_math.h b/extern/bullet/src/BulletCollision/Gimpact/gim_math.h similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/gim_math.h rename to extern/bullet/src/BulletCollision/Gimpact/gim_math.h diff --git a/extern/bullet2/src/BulletCollision/Gimpact/gim_memory.cpp b/extern/bullet/src/BulletCollision/Gimpact/gim_memory.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/gim_memory.cpp rename to extern/bullet/src/BulletCollision/Gimpact/gim_memory.cpp diff --git a/extern/bullet2/src/BulletCollision/Gimpact/gim_memory.h b/extern/bullet/src/BulletCollision/Gimpact/gim_memory.h similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/gim_memory.h rename to extern/bullet/src/BulletCollision/Gimpact/gim_memory.h diff --git a/extern/bullet2/src/BulletCollision/Gimpact/gim_radixsort.h b/extern/bullet/src/BulletCollision/Gimpact/gim_radixsort.h similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/gim_radixsort.h rename to extern/bullet/src/BulletCollision/Gimpact/gim_radixsort.h diff --git a/extern/bullet2/src/BulletCollision/Gimpact/gim_tri_collision.cpp b/extern/bullet/src/BulletCollision/Gimpact/gim_tri_collision.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/Gimpact/gim_tri_collision.cpp rename to extern/bullet/src/BulletCollision/Gimpact/gim_tri_collision.cpp diff --git a/extern/bullet2/src/BulletCollision/Gimpact/gim_tri_collision.h b/extern/bullet/src/BulletCollision/Gimpact/gim_tri_collision.h similarity index 99% rename from extern/bullet2/src/BulletCollision/Gimpact/gim_tri_collision.h rename to extern/bullet/src/BulletCollision/Gimpact/gim_tri_collision.h index 5b552a1ed517..267f806e7e53 100644 --- a/extern/bullet2/src/BulletCollision/Gimpact/gim_tri_collision.h +++ b/extern/bullet/src/BulletCollision/Gimpact/gim_tri_collision.h @@ -38,8 +38,9 @@ email: projectileman@yahoo.com - +#ifndef MAX_TRI_CLIPPING #define MAX_TRI_CLIPPING 16 +#endif //! Structure for collision struct GIM_TRIANGLE_CONTACT_DATA diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btComputeGjkEpaPenetration.h b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btComputeGjkEpaPenetration.h similarity index 97% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btComputeGjkEpaPenetration.h rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btComputeGjkEpaPenetration.h index 9eb880b8dfca..bb8d8b872d15 100644 --- a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btComputeGjkEpaPenetration.h +++ b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btComputeGjkEpaPenetration.h @@ -1,369 +1,369 @@ -/* -Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2014 Erwin Coumans http://bulletphysics.org - -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_GJK_EPA_PENETATION_CONVEX_COLLISION_H -#define BT_GJK_EPA_PENETATION_CONVEX_COLLISION_H - -#include "LinearMath/btTransform.h" // Note that btVector3 might be double precision... -#include "btGjkEpa3.h" -#include "btGjkCollisionDescription.h" -#include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" - - - - - - -template -bool btGjkEpaCalcPenDepth(const btConvexTemplate& a, const btConvexTemplate& b, - const btGjkCollisionDescription& colDesc, - btVector3& v, btVector3& wWitnessOnA, btVector3& wWitnessOnB) -{ - (void)v; - - // const btScalar radialmargin(btScalar(0.)); - - btVector3 guessVector(b.getWorldTransform().getOrigin()-a.getWorldTransform().getOrigin());//?? why not use the GJK input? - - btGjkEpaSolver3::sResults results; - - - if(btGjkEpaSolver3_Penetration(a,b,guessVector,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]; - v = results.normal; - return true; - } else - { - if(btGjkEpaSolver3_Distance(a,b,guessVector,results)) - { - wWitnessOnA = results.witnesses[0]; - wWitnessOnB = results.witnesses[1]; - v = results.normal; - return false; - } - } - return false; -} - -template -int btComputeGjkEpaPenetration(const btConvexTemplate& a, const btConvexTemplate& b, const btGjkCollisionDescription& colDesc, btVoronoiSimplexSolver& simplexSolver, btGjkDistanceTemplate* distInfo) -{ - - bool m_catchDegeneracies = true; - btScalar m_cachedSeparatingDistance = 0.f; - - btScalar distance=btScalar(0.); - btVector3 normalInB(btScalar(0.),btScalar(0.),btScalar(0.)); - - btVector3 pointOnA,pointOnB; - btTransform localTransA = a.getWorldTransform(); - btTransform localTransB = b.getWorldTransform(); - - btScalar marginA = a.getMargin(); - btScalar marginB = b.getMargin(); - - int m_curIter = 0; - int gGjkMaxIter = colDesc.m_maxGjkIterations;//this is to catch invalid input, perhaps check for #NaN? - btVector3 m_cachedSeparatingAxis = colDesc.m_firstDir; - - bool isValid = false; - bool checkSimplex = false; - bool checkPenetration = true; - int m_degenerateSimplex = 0; - - int m_lastUsedMethod = -1; - - { - btScalar squaredDistance = BT_LARGE_FLOAT; - btScalar delta = btScalar(0.); - - btScalar margin = marginA + marginB; - - - - simplexSolver.reset(); - - for ( ; ; ) - //while (true) - { - - btVector3 seperatingAxisInA = (-m_cachedSeparatingAxis)* localTransA.getBasis(); - btVector3 seperatingAxisInB = m_cachedSeparatingAxis* localTransB.getBasis(); - - btVector3 pInA = a.getLocalSupportWithoutMargin(seperatingAxisInA); - btVector3 qInB = b.getLocalSupportWithoutMargin(seperatingAxisInB); - - btVector3 pWorld = localTransA(pInA); - btVector3 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 * colDesc.m_maximumDistanceSquared)) - { - m_degenerateSimplex = 10; - checkSimplex=true; - //checkPenetration = false; - break; - } - - //exit 0: the new point is already in the simplex, or we didn't come any closer - if (simplexSolver.inSimplex(w)) - { - m_degenerateSimplex = 1; - checkSimplex = true; - break; - } - // are we getting any closer ? - btScalar f0 = squaredDistance - delta; - btScalar f1 = squaredDistance * colDesc.m_gjkRelError2; - - if (f0 <= f1) - { - if (f0 <= btScalar(0.)) - { - m_degenerateSimplex = 2; - } else - { - m_degenerateSimplex = 11; - } - checkSimplex = true; - break; - } - - //add current vertex to simplex - simplexSolver.addVertex(w, pWorld, qWorld); - btVector3 newCachedSeparatingAxis; - - //calculate the closest point to the origin (update vector v) - if (!simplexSolver.closest(newCachedSeparatingAxis)) - { - m_degenerateSimplex = 3; - checkSimplex = true; - break; - } - - if(newCachedSeparatingAxis.length2()previousSquaredDistance) - { - m_degenerateSimplex = 7; - squaredDistance = previousSquaredDistance; - checkSimplex = false; - break; - } -#endif // - - - //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; - m_degenerateSimplex = 12; - - break; - } - - m_cachedSeparatingAxis = newCachedSeparatingAxis; - - //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\n", - m_cachedSeparatingAxis.getX(), - m_cachedSeparatingAxis.getY(), - m_cachedSeparatingAxis.getZ(), - squaredDistance); -#endif - - break; - - } - - - bool check = (!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); - m_degenerateSimplex = 13; - break; - } - } - - if (checkSimplex) - { - simplexSolver.compute_points(pointOnA, pointOnB); - normalInB = m_cachedSeparatingAxis; - - 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_degenerateSimplex && ((distance+margin) < 0.01)); - - //if (checkPenetration && !isValid) - if (checkPenetration && (!isValid || catchDegeneratePenetrationCase )) - { - //penetration case - - //if there is no way to handle penetrations, bail out - - // Penetration depth case. - btVector3 tmpPointOnA,tmpPointOnB; - - m_cachedSeparatingAxis.setZero(); - - bool isValid2 = btGjkEpaCalcPenDepth(a,b, - colDesc, - m_cachedSeparatingAxis, tmpPointOnA, tmpPointOnB); - - if (isValid2) - { - btVector3 tmpNormalInB = tmpPointOnB-tmpPointOnA; - btScalar lenSqr = tmpNormalInB.length2(); - if (lenSqr <= (SIMD_EPSILON*SIMD_EPSILON)) - { - tmpNormalInB = m_cachedSeparatingAxis; - lenSqr = m_cachedSeparatingAxis.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 - { - m_lastUsedMethod = 8; - } - } else - { - m_lastUsedMethod = 9; - } - } else - - { - ///this is another degenerate case, where the initial GJK calculation reports a degenerate case - ///EPA reports no penetration, and the second GJK (using the supporting vector without margin) - ///reports a valid positive distance. Use the results of the second GJK instead of failing. - ///thanks to Jacob.Langford for the reproduction case - ///http://code.google.com/p/bullet/issues/detail?id=250 - - - if (m_cachedSeparatingAxis.length2() > btScalar(0.)) - { - btScalar distance2 = (tmpPointOnA-tmpPointOnB).length()-margin; - //only replace valid distances when the distance is less - if (!isValid || (distance2 < distance)) - { - distance = distance2; - pointOnA = tmpPointOnA; - pointOnB = tmpPointOnB; - pointOnA -= m_cachedSeparatingAxis * marginA ; - pointOnB += m_cachedSeparatingAxis * marginB ; - normalInB = m_cachedSeparatingAxis; - normalInB.normalize(); - - isValid = true; - m_lastUsedMethod = 6; - } else - { - m_lastUsedMethod = 5; - } - } - } - } - } - - - - if (isValid && ((distance < 0) || (distance*distance < colDesc.m_maximumDistanceSquared))) - { - - m_cachedSeparatingAxis = normalInB; - m_cachedSeparatingDistance = distance; - distInfo->m_distance = distance; - distInfo->m_normalBtoA = normalInB; - distInfo->m_pointOnB = pointOnB; - distInfo->m_pointOnA = pointOnB+normalInB*distance; - return 0; - } - return -m_lastUsedMethod; -} - - - - -#endif //BT_GJK_EPA_PENETATION_CONVEX_COLLISION_H +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2014 Erwin Coumans http://bulletphysics.org + +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_GJK_EPA_PENETATION_CONVEX_COLLISION_H +#define BT_GJK_EPA_PENETATION_CONVEX_COLLISION_H + +#include "LinearMath/btTransform.h" // Note that btVector3 might be double precision... +#include "btGjkEpa3.h" +#include "btGjkCollisionDescription.h" +#include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" + + + + + + +template +bool btGjkEpaCalcPenDepth(const btConvexTemplate& a, const btConvexTemplate& b, + const btGjkCollisionDescription& colDesc, + btVector3& v, btVector3& wWitnessOnA, btVector3& wWitnessOnB) +{ + (void)v; + + // const btScalar radialmargin(btScalar(0.)); + + btVector3 guessVector(b.getWorldTransform().getOrigin()-a.getWorldTransform().getOrigin());//?? why not use the GJK input? + + btGjkEpaSolver3::sResults results; + + + if(btGjkEpaSolver3_Penetration(a,b,guessVector,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]; + v = results.normal; + return true; + } else + { + if(btGjkEpaSolver3_Distance(a,b,guessVector,results)) + { + wWitnessOnA = results.witnesses[0]; + wWitnessOnB = results.witnesses[1]; + v = results.normal; + return false; + } + } + return false; +} + +template +int btComputeGjkEpaPenetration(const btConvexTemplate& a, const btConvexTemplate& b, const btGjkCollisionDescription& colDesc, btVoronoiSimplexSolver& simplexSolver, btGjkDistanceTemplate* distInfo) +{ + + bool m_catchDegeneracies = true; + btScalar m_cachedSeparatingDistance = 0.f; + + btScalar distance=btScalar(0.); + btVector3 normalInB(btScalar(0.),btScalar(0.),btScalar(0.)); + + btVector3 pointOnA,pointOnB; + btTransform localTransA = a.getWorldTransform(); + btTransform localTransB = b.getWorldTransform(); + + btScalar marginA = a.getMargin(); + btScalar marginB = b.getMargin(); + + int m_curIter = 0; + int gGjkMaxIter = colDesc.m_maxGjkIterations;//this is to catch invalid input, perhaps check for #NaN? + btVector3 m_cachedSeparatingAxis = colDesc.m_firstDir; + + bool isValid = false; + bool checkSimplex = false; + bool checkPenetration = true; + int m_degenerateSimplex = 0; + + int m_lastUsedMethod = -1; + + { + btScalar squaredDistance = BT_LARGE_FLOAT; + btScalar delta = btScalar(0.); + + btScalar margin = marginA + marginB; + + + + simplexSolver.reset(); + + for ( ; ; ) + //while (true) + { + + btVector3 seperatingAxisInA = (-m_cachedSeparatingAxis)* localTransA.getBasis(); + btVector3 seperatingAxisInB = m_cachedSeparatingAxis* localTransB.getBasis(); + + btVector3 pInA = a.getLocalSupportWithoutMargin(seperatingAxisInA); + btVector3 qInB = b.getLocalSupportWithoutMargin(seperatingAxisInB); + + btVector3 pWorld = localTransA(pInA); + btVector3 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 * colDesc.m_maximumDistanceSquared)) + { + m_degenerateSimplex = 10; + checkSimplex=true; + //checkPenetration = false; + break; + } + + //exit 0: the new point is already in the simplex, or we didn't come any closer + if (simplexSolver.inSimplex(w)) + { + m_degenerateSimplex = 1; + checkSimplex = true; + break; + } + // are we getting any closer ? + btScalar f0 = squaredDistance - delta; + btScalar f1 = squaredDistance * colDesc.m_gjkRelError2; + + if (f0 <= f1) + { + if (f0 <= btScalar(0.)) + { + m_degenerateSimplex = 2; + } else + { + m_degenerateSimplex = 11; + } + checkSimplex = true; + break; + } + + //add current vertex to simplex + simplexSolver.addVertex(w, pWorld, qWorld); + btVector3 newCachedSeparatingAxis; + + //calculate the closest point to the origin (update vector v) + if (!simplexSolver.closest(newCachedSeparatingAxis)) + { + m_degenerateSimplex = 3; + checkSimplex = true; + break; + } + + if(newCachedSeparatingAxis.length2()previousSquaredDistance) + { + m_degenerateSimplex = 7; + squaredDistance = previousSquaredDistance; + checkSimplex = false; + break; + } +#endif // + + + //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; + m_degenerateSimplex = 12; + + break; + } + + m_cachedSeparatingAxis = newCachedSeparatingAxis; + + //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\n", + m_cachedSeparatingAxis.getX(), + m_cachedSeparatingAxis.getY(), + m_cachedSeparatingAxis.getZ(), + squaredDistance); +#endif + + break; + + } + + + bool check = (!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); + m_degenerateSimplex = 13; + break; + } + } + + if (checkSimplex) + { + simplexSolver.compute_points(pointOnA, pointOnB); + normalInB = m_cachedSeparatingAxis; + + 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_degenerateSimplex && ((distance+margin) < 0.01)); + + //if (checkPenetration && !isValid) + if (checkPenetration && (!isValid || catchDegeneratePenetrationCase )) + { + //penetration case + + //if there is no way to handle penetrations, bail out + + // Penetration depth case. + btVector3 tmpPointOnA,tmpPointOnB; + + m_cachedSeparatingAxis.setZero(); + + bool isValid2 = btGjkEpaCalcPenDepth(a,b, + colDesc, + m_cachedSeparatingAxis, tmpPointOnA, tmpPointOnB); + + if (isValid2) + { + btVector3 tmpNormalInB = tmpPointOnB-tmpPointOnA; + btScalar lenSqr = tmpNormalInB.length2(); + if (lenSqr <= (SIMD_EPSILON*SIMD_EPSILON)) + { + tmpNormalInB = m_cachedSeparatingAxis; + lenSqr = m_cachedSeparatingAxis.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 + { + m_lastUsedMethod = 8; + } + } else + { + m_lastUsedMethod = 9; + } + } else + + { + ///this is another degenerate case, where the initial GJK calculation reports a degenerate case + ///EPA reports no penetration, and the second GJK (using the supporting vector without margin) + ///reports a valid positive distance. Use the results of the second GJK instead of failing. + ///thanks to Jacob.Langford for the reproduction case + ///http://code.google.com/p/bullet/issues/detail?id=250 + + + if (m_cachedSeparatingAxis.length2() > btScalar(0.)) + { + btScalar distance2 = (tmpPointOnA-tmpPointOnB).length()-margin; + //only replace valid distances when the distance is less + if (!isValid || (distance2 < distance)) + { + distance = distance2; + pointOnA = tmpPointOnA; + pointOnB = tmpPointOnB; + pointOnA -= m_cachedSeparatingAxis * marginA ; + pointOnB += m_cachedSeparatingAxis * marginB ; + normalInB = m_cachedSeparatingAxis; + normalInB.normalize(); + + isValid = true; + m_lastUsedMethod = 6; + } else + { + m_lastUsedMethod = 5; + } + } + } + } + } + + + + if (isValid && ((distance < 0) || (distance*distance < colDesc.m_maximumDistanceSquared))) + { + + m_cachedSeparatingAxis = normalInB; + m_cachedSeparatingDistance = distance; + distInfo->m_distance = distance; + distInfo->m_normalBtoA = normalInB; + distInfo->m_pointOnB = pointOnB; + distInfo->m_pointOnA = pointOnB+normalInB*distance; + return 0; + } + return -m_lastUsedMethod; +} + + + + +#endif //BT_GJK_EPA_PENETATION_CONVEX_COLLISION_H diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h similarity index 100% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btConvexCast.cpp b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btConvexCast.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btConvexCast.cpp rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btConvexCast.cpp diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btConvexCast.h b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btConvexCast.h similarity index 100% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btConvexCast.h rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btConvexCast.h diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h similarity index 100% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h similarity index 99% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h index 46ce1ab75e75..0ea7b483cfba 100644 --- a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h +++ b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h @@ -67,10 +67,12 @@ struct btStorageResult : public btDiscreteCollisionDetectorInterface::Result btVector3 m_closestPointInB; btScalar m_distance; //negative means penetration ! + protected: btStorageResult() : m_distance(btScalar(BT_LARGE_FLOAT)) { - } + + public: virtual ~btStorageResult() {}; virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth) diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkCollisionDescription.h b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkCollisionDescription.h similarity index 100% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkCollisionDescription.h rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkCollisionDescription.h diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.cpp b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.cpp rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.cpp diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h similarity index 100% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpa2.cpp b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkEpa2.cpp similarity index 96% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpa2.cpp rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkEpa2.cpp index 3268f06c2f92..eefb974bbd2c 100644 --- a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpa2.cpp +++ b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkEpa2.cpp @@ -41,21 +41,38 @@ namespace gjkepa2_impl /* GJK */ #define GJK_MAX_ITERATIONS 128 -#define GJK_ACCURARY ((btScalar)0.0001) -#define GJK_MIN_DISTANCE ((btScalar)0.0001) -#define GJK_DUPLICATED_EPS ((btScalar)0.0001) + +#ifdef BT_USE_DOUBLE_PRECISION + #define GJK_ACCURACY ((btScalar)1e-12) + #define GJK_MIN_DISTANCE ((btScalar)1e-12) + #define GJK_DUPLICATED_EPS ((btScalar)1e-12) +#else + #define GJK_ACCURACY ((btScalar)0.0001) + #define GJK_MIN_DISTANCE ((btScalar)0.0001) + #define GJK_DUPLICATED_EPS ((btScalar)0.0001) +#endif //BT_USE_DOUBLE_PRECISION + + #define GJK_SIMPLEX2_EPS ((btScalar)0.0) #define GJK_SIMPLEX3_EPS ((btScalar)0.0) #define GJK_SIMPLEX4_EPS ((btScalar)0.0) /* EPA */ -#define EPA_MAX_VERTICES 64 -#define EPA_MAX_FACES (EPA_MAX_VERTICES*2) +#define EPA_MAX_VERTICES 128 #define EPA_MAX_ITERATIONS 255 -#define EPA_ACCURACY ((btScalar)0.0001) -#define EPA_FALLBACK (10*EPA_ACCURACY) -#define EPA_PLANE_EPS ((btScalar)0.00001) -#define EPA_INSIDE_EPS ((btScalar)0.01) + +#ifdef BT_USE_DOUBLE_PRECISION + #define EPA_ACCURACY ((btScalar)1e-12) + #define EPA_PLANE_EPS ((btScalar)1e-14) + #define EPA_INSIDE_EPS ((btScalar)1e-9) +#else + #define EPA_ACCURACY ((btScalar)0.0001) + #define EPA_PLANE_EPS ((btScalar)0.00001) + #define EPA_INSIDE_EPS ((btScalar)0.01) +#endif + +#define EPA_FALLBACK (10*EPA_ACCURACY) +#define EPA_MAX_FACES (EPA_MAX_VERTICES*2) // Shorthands @@ -242,7 +259,7 @@ namespace gjkepa2_impl /* Check for termination */ const btScalar omega=btDot(m_ray,w)/rl; alpha=btMax(omega,alpha); - if(((rl-alpha)-(GJK_ACCURARY*rl))<=0) + if(((rl-alpha)-(GJK_ACCURACY*rl))<=0) {/* Return old simplex */ removevertice(m_simplices[m_current]); break; @@ -1015,7 +1032,7 @@ bool btGjkEpaSolver2::SignedDistance(const btConvexShape* shape0, /* Symbols cleanup */ #undef GJK_MAX_ITERATIONS -#undef GJK_ACCURARY +#undef GJK_ACCURACY #undef GJK_MIN_DISTANCE #undef GJK_DUPLICATED_EPS #undef GJK_SIMPLEX2_EPS diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpa2.h b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkEpa2.h similarity index 100% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpa2.h rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkEpa2.h diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpa3.h b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkEpa3.h similarity index 97% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpa3.h rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkEpa3.h index ce1f24bc50db..878949af940b 100644 --- a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpa3.h +++ b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkEpa3.h @@ -1,1035 +1,1035 @@ -/* -Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2014 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. -*/ - -/* -Initial GJK-EPA collision solver by Nathanael Presson, 2008 -Improvements and refactoring by Erwin Coumans, 2008-2014 -*/ -#ifndef BT_GJK_EPA3_H -#define BT_GJK_EPA3_H - -#include "LinearMath/btTransform.h" -#include "btGjkCollisionDescription.h" - - - -struct btGjkEpaSolver3 -{ -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 distance; - }; - - -}; - - - -#if defined(DEBUG) || defined (_DEBUG) -#include //for debug printf -#ifdef __SPU__ -#include -#define printf spu_printf -#endif //__SPU__ -#endif - - - - // Config - - /* GJK */ -#define GJK_MAX_ITERATIONS 128 -#define GJK_ACCURARY ((btScalar)0.0001) -#define GJK_MIN_DISTANCE ((btScalar)0.0001) -#define GJK_DUPLICATED_EPS ((btScalar)0.0001) -#define GJK_SIMPLEX2_EPS ((btScalar)0.0) -#define GJK_SIMPLEX3_EPS ((btScalar)0.0) -#define GJK_SIMPLEX4_EPS ((btScalar)0.0) - - /* EPA */ -#define EPA_MAX_VERTICES 64 -#define EPA_MAX_FACES (EPA_MAX_VERTICES*2) -#define EPA_MAX_ITERATIONS 255 -#define EPA_ACCURACY ((btScalar)0.0001) -#define EPA_FALLBACK (10*EPA_ACCURACY) -#define EPA_PLANE_EPS ((btScalar)0.00001) -#define EPA_INSIDE_EPS ((btScalar)0.01) - - - // Shorthands - typedef unsigned int U; - typedef unsigned char U1; - - // MinkowskiDiff - template - struct MinkowskiDiff - { - const btConvexTemplate* m_convexAPtr; - const btConvexTemplate* m_convexBPtr; - - btMatrix3x3 m_toshape1; - btTransform m_toshape0; - - bool m_enableMargin; - - - MinkowskiDiff(const btConvexTemplate& a, const btConvexTemplate& b) - :m_convexAPtr(&a), - m_convexBPtr(&b) - { - } - - void EnableMargin(bool enable) - { - m_enableMargin = enable; - } - inline btVector3 Support0(const btVector3& d) const - { - return m_convexAPtr->getLocalSupportWithMargin(d); - } - inline btVector3 Support1(const btVector3& d) const - { - return m_toshape0*m_convexBPtr->getLocalSupportWithMargin(m_toshape1*d); - } - - - inline btVector3 Support(const btVector3& d) const - { - return(Support0(d)-Support1(-d)); - } - btVector3 Support(const btVector3& d,U index) const - { - if(index) - return(Support1(d)); - else - return(Support0(d)); - } - }; - -enum eGjkStatus -{ - eGjkValid, - eGjkInside, - eGjkFailed -}; - - // GJK - template - struct GJK - { - /* Types */ - struct sSV - { - btVector3 d,w; - }; - struct sSimplex - { - sSV* c[4]; - btScalar p[4]; - U rank; - }; - - /* Fields */ - - MinkowskiDiff m_shape; - btVector3 m_ray; - btScalar m_distance; - sSimplex m_simplices[2]; - sSV m_store[4]; - sSV* m_free[4]; - U m_nfree; - U m_current; - sSimplex* m_simplex; - eGjkStatus m_status; - /* Methods */ - - GJK(const btConvexTemplate& a, const btConvexTemplate& b) - :m_shape(a,b) - { - Initialize(); - } - void Initialize() - { - m_ray = btVector3(0,0,0); - m_nfree = 0; - m_status = eGjkFailed; - m_current = 0; - m_distance = 0; - } - eGjkStatus Evaluate(const MinkowskiDiff& shapearg,const btVector3& guess) - { - U iterations=0; - btScalar sqdist=0; - btScalar alpha=0; - btVector3 lastw[4]; - U clastw=0; - /* Initialize solver */ - m_free[0] = &m_store[0]; - m_free[1] = &m_store[1]; - m_free[2] = &m_store[2]; - m_free[3] = &m_store[3]; - m_nfree = 4; - m_current = 0; - m_status = eGjkValid; - m_shape = shapearg; - m_distance = 0; - /* Initialize simplex */ - m_simplices[0].rank = 0; - m_ray = guess; - const btScalar sqrl= m_ray.length2(); - appendvertice(m_simplices[0],sqrl>0?-m_ray:btVector3(1,0,0)); - m_simplices[0].p[0] = 1; - m_ray = m_simplices[0].c[0]->w; - sqdist = sqrl; - lastw[0] = - lastw[1] = - lastw[2] = - lastw[3] = m_ray; - /* Loop */ - do { - const U next=1-m_current; - sSimplex& cs=m_simplices[m_current]; - sSimplex& ns=m_simplices[next]; - /* Check zero */ - const btScalar rl=m_ray.length(); - if(rlw; - bool found=false; - for(U i=0;i<4;++i) - { - if((w-lastw[i]).length2()w, - cs.c[1]->w, - weights,mask);break; - case 3: sqdist=projectorigin( cs.c[0]->w, - cs.c[1]->w, - cs.c[2]->w, - weights,mask);break; - case 4: sqdist=projectorigin( cs.c[0]->w, - cs.c[1]->w, - cs.c[2]->w, - cs.c[3]->w, - weights,mask);break; - } - if(sqdist>=0) - {/* Valid */ - ns.rank = 0; - m_ray = btVector3(0,0,0); - m_current = next; - for(U i=0,ni=cs.rank;iw*weights[i]; - } - else - { - m_free[m_nfree++] = cs.c[i]; - } - } - if(mask==15) m_status=eGjkInside; - } - else - {/* Return old simplex */ - removevertice(m_simplices[m_current]); - break; - } - m_status=((++iterations)rank) - { - case 1: - { - for(U i=0;i<3;++i) - { - btVector3 axis=btVector3(0,0,0); - axis[i]=1; - appendvertice(*m_simplex, axis); - if(EncloseOrigin()) return(true); - removevertice(*m_simplex); - appendvertice(*m_simplex,-axis); - if(EncloseOrigin()) return(true); - removevertice(*m_simplex); - } - } - break; - case 2: - { - const btVector3 d=m_simplex->c[1]->w-m_simplex->c[0]->w; - for(U i=0;i<3;++i) - { - btVector3 axis=btVector3(0,0,0); - axis[i]=1; - const btVector3 p=btCross(d,axis); - if(p.length2()>0) - { - appendvertice(*m_simplex, p); - if(EncloseOrigin()) return(true); - removevertice(*m_simplex); - appendvertice(*m_simplex,-p); - if(EncloseOrigin()) return(true); - removevertice(*m_simplex); - } - } - } - break; - case 3: - { - const btVector3 n=btCross(m_simplex->c[1]->w-m_simplex->c[0]->w, - m_simplex->c[2]->w-m_simplex->c[0]->w); - if(n.length2()>0) - { - appendvertice(*m_simplex,n); - if(EncloseOrigin()) return(true); - removevertice(*m_simplex); - appendvertice(*m_simplex,-n); - if(EncloseOrigin()) return(true); - removevertice(*m_simplex); - } - } - break; - case 4: - { - if(btFabs(det( m_simplex->c[0]->w-m_simplex->c[3]->w, - m_simplex->c[1]->w-m_simplex->c[3]->w, - m_simplex->c[2]->w-m_simplex->c[3]->w))>0) - return(true); - } - break; - } - return(false); - } - /* Internals */ - void getsupport(const btVector3& d,sSV& sv) const - { - sv.d = d/d.length(); - sv.w = m_shape.Support(sv.d); - } - void removevertice(sSimplex& simplex) - { - m_free[m_nfree++]=simplex.c[--simplex.rank]; - } - void appendvertice(sSimplex& simplex,const btVector3& v) - { - simplex.p[simplex.rank]=0; - simplex.c[simplex.rank]=m_free[--m_nfree]; - getsupport(v,*simplex.c[simplex.rank++]); - } - static btScalar det(const btVector3& a,const btVector3& b,const btVector3& c) - { - return( a.y()*b.z()*c.x()+a.z()*b.x()*c.y()- - a.x()*b.z()*c.y()-a.y()*b.x()*c.z()+ - a.x()*b.y()*c.z()-a.z()*b.y()*c.x()); - } - static btScalar projectorigin( const btVector3& a, - const btVector3& b, - btScalar* w,U& m) - { - const btVector3 d=b-a; - const btScalar l=d.length2(); - if(l>GJK_SIMPLEX2_EPS) - { - const btScalar t(l>0?-btDot(a,d)/l:0); - if(t>=1) { w[0]=0;w[1]=1;m=2;return(b.length2()); } - else if(t<=0) { w[0]=1;w[1]=0;m=1;return(a.length2()); } - else { w[0]=1-(w[1]=t);m=3;return((a+d*t).length2()); } - } - return(-1); - } - static btScalar projectorigin( const btVector3& a, - const btVector3& b, - const btVector3& c, - btScalar* w,U& m) - { - static const U imd3[]={1,2,0}; - const btVector3* vt[]={&a,&b,&c}; - const btVector3 dl[]={a-b,b-c,c-a}; - const btVector3 n=btCross(dl[0],dl[1]); - const btScalar l=n.length2(); - if(l>GJK_SIMPLEX3_EPS) - { - btScalar mindist=-1; - btScalar subw[2]={0.f,0.f}; - U subm(0); - for(U i=0;i<3;++i) - { - if(btDot(*vt[i],btCross(dl[i],n))>0) - { - const U j=imd3[i]; - const btScalar subd(projectorigin(*vt[i],*vt[j],subw,subm)); - if((mindist<0)||(subd(((subm&1)?1<GJK_SIMPLEX4_EPS)) - { - btScalar mindist=-1; - btScalar subw[3]={0.f,0.f,0.f}; - U subm(0); - for(U i=0;i<3;++i) - { - const U j=imd3[i]; - const btScalar s=vl*btDot(d,btCross(dl[i],dl[j])); - if(s>0) - { - const btScalar subd=projectorigin(*vt[i],*vt[j],d,subw,subm); - if((mindist<0)||(subd((subm&1?1< - struct EPA - { - /* Types */ - - struct sFace - { - btVector3 n; - btScalar d; - typename GJK::sSV* c[3]; - sFace* f[3]; - sFace* l[2]; - U1 e[3]; - U1 pass; - }; - struct sList - { - sFace* root; - U count; - sList() : root(0),count(0) {} - }; - struct sHorizon - { - sFace* cf; - sFace* ff; - U nf; - sHorizon() : cf(0),ff(0),nf(0) {} - }; - - /* Fields */ - eEpaStatus m_status; - typename GJK::sSimplex m_result; - btVector3 m_normal; - btScalar m_depth; - typename GJK::sSV m_sv_store[EPA_MAX_VERTICES]; - sFace m_fc_store[EPA_MAX_FACES]; - U m_nextsv; - sList m_hull; - sList m_stock; - /* Methods */ - EPA() - { - Initialize(); - } - - - static inline void bind(sFace* fa,U ea,sFace* fb,U eb) - { - fa->e[ea]=(U1)eb;fa->f[ea]=fb; - fb->e[eb]=(U1)ea;fb->f[eb]=fa; - } - static inline void append(sList& list,sFace* face) - { - face->l[0] = 0; - face->l[1] = list.root; - if(list.root) list.root->l[0]=face; - list.root = face; - ++list.count; - } - static inline void remove(sList& list,sFace* face) - { - if(face->l[1]) face->l[1]->l[0]=face->l[0]; - if(face->l[0]) face->l[0]->l[1]=face->l[1]; - if(face==list.root) list.root=face->l[1]; - --list.count; - } - - - void Initialize() - { - m_status = eEpaFailed; - m_normal = btVector3(0,0,0); - m_depth = 0; - m_nextsv = 0; - for(U i=0;i& gjk,const btVector3& guess) - { - typename GJK::sSimplex& simplex=*gjk.m_simplex; - if((simplex.rank>1)&&gjk.EncloseOrigin()) - { - - /* Clean up */ - while(m_hull.root) - { - sFace* f = m_hull.root; - remove(m_hull,f); - append(m_stock,f); - } - m_status = eEpaValid; - m_nextsv = 0; - /* Orient simplex */ - if(gjk.det( simplex.c[0]->w-simplex.c[3]->w, - simplex.c[1]->w-simplex.c[3]->w, - simplex.c[2]->w-simplex.c[3]->w)<0) - { - btSwap(simplex.c[0],simplex.c[1]); - btSwap(simplex.p[0],simplex.p[1]); - } - /* Build initial hull */ - sFace* tetra[]={newface(simplex.c[0],simplex.c[1],simplex.c[2],true), - newface(simplex.c[1],simplex.c[0],simplex.c[3],true), - newface(simplex.c[2],simplex.c[1],simplex.c[3],true), - newface(simplex.c[0],simplex.c[2],simplex.c[3],true)}; - if(m_hull.count==4) - { - sFace* best=findbest(); - sFace outer=*best; - U pass=0; - U iterations=0; - bind(tetra[0],0,tetra[1],0); - bind(tetra[0],1,tetra[2],0); - bind(tetra[0],2,tetra[3],0); - bind(tetra[1],1,tetra[3],2); - bind(tetra[1],2,tetra[2],1); - bind(tetra[2],2,tetra[3],1); - m_status=eEpaValid; - for(;iterations::sSV* w=&m_sv_store[m_nextsv++]; - bool valid=true; - best->pass = (U1)(++pass); - gjk.getsupport(best->n,*w); - const btScalar wdist=btDot(best->n,w->w)-best->d; - if(wdist>EPA_ACCURACY) - { - for(U j=0;(j<3)&&valid;++j) - { - valid&=expand( pass,w, - best->f[j],best->e[j], - horizon); - } - if(valid&&(horizon.nf>=3)) - { - bind(horizon.cf,1,horizon.ff,2); - remove(m_hull,best); - append(m_stock,best); - best=findbest(); - outer=*best; - } else { m_status=eEpaInvalidHull;break; } - } else { m_status=eEpaAccuraryReached;break; } - } else { m_status=eEpaOutOfVertices;break; } - } - const btVector3 projection=outer.n*outer.d; - m_normal = outer.n; - m_depth = outer.d; - m_result.rank = 3; - m_result.c[0] = outer.c[0]; - m_result.c[1] = outer.c[1]; - m_result.c[2] = outer.c[2]; - m_result.p[0] = btCross( outer.c[1]->w-projection, - outer.c[2]->w-projection).length(); - m_result.p[1] = btCross( outer.c[2]->w-projection, - outer.c[0]->w-projection).length(); - m_result.p[2] = btCross( outer.c[0]->w-projection, - outer.c[1]->w-projection).length(); - const btScalar sum=m_result.p[0]+m_result.p[1]+m_result.p[2]; - m_result.p[0] /= sum; - m_result.p[1] /= sum; - m_result.p[2] /= sum; - return(m_status); - } - } - /* Fallback */ - m_status = eEpaFallBack; - m_normal = -guess; - const btScalar nl=m_normal.length(); - if(nl>0) - m_normal = m_normal/nl; - else - m_normal = btVector3(1,0,0); - m_depth = 0; - m_result.rank=1; - m_result.c[0]=simplex.c[0]; - m_result.p[0]=1; - return(m_status); - } - bool getedgedist(sFace* face, typename GJK::sSV* a, typename GJK::sSV* b, btScalar& dist) - { - const btVector3 ba = b->w - a->w; - const btVector3 n_ab = btCross(ba, face->n); // Outward facing edge normal direction, on triangle plane - const btScalar a_dot_nab = btDot(a->w, n_ab); // Only care about the sign to determine inside/outside, so not normalization required - - if(a_dot_nab < 0) - { - // Outside of edge a->b - - const btScalar ba_l2 = ba.length2(); - const btScalar a_dot_ba = btDot(a->w, ba); - const btScalar b_dot_ba = btDot(b->w, ba); - - if(a_dot_ba > 0) - { - // Pick distance vertex a - dist = a->w.length(); - } - else if(b_dot_ba < 0) - { - // Pick distance vertex b - dist = b->w.length(); - } - else - { - // Pick distance to edge a->b - const btScalar a_dot_b = btDot(a->w, b->w); - dist = btSqrt(btMax((a->w.length2() * b->w.length2() - a_dot_b * a_dot_b) / ba_l2, (btScalar)0)); - } - - return true; - } - - return false; - } - sFace* newface(typename GJK::sSV* a,typename GJK::sSV* b,typename GJK::sSV* c,bool forced) - { - if(m_stock.root) - { - sFace* face=m_stock.root; - remove(m_stock,face); - append(m_hull,face); - face->pass = 0; - face->c[0] = a; - face->c[1] = b; - face->c[2] = c; - face->n = btCross(b->w-a->w,c->w-a->w); - const btScalar l=face->n.length(); - const bool v=l>EPA_ACCURACY; - - if(v) - { - if(!(getedgedist(face, a, b, face->d) || - getedgedist(face, b, c, face->d) || - getedgedist(face, c, a, face->d))) - { - // Origin projects to the interior of the triangle - // Use distance to triangle plane - face->d = btDot(a->w, face->n) / l; - } - - face->n /= l; - if(forced || (face->d >= -EPA_PLANE_EPS)) - { - return face; - } - else - m_status=eEpaNonConvex; - } - else - m_status=eEpaDegenerated; - - remove(m_hull, face); - append(m_stock, face); - return 0; - - } - m_status = m_stock.root ? eEpaOutOfVertices : eEpaOutOfFaces; - return 0; - } - sFace* findbest() - { - sFace* minf=m_hull.root; - btScalar mind=minf->d*minf->d; - for(sFace* f=minf->l[1];f;f=f->l[1]) - { - const btScalar sqd=f->d*f->d; - if(sqd::sSV* w,sFace* f,U e,sHorizon& horizon) - { - static const U i1m3[]={1,2,0}; - static const U i2m3[]={2,0,1}; - if(f->pass!=pass) - { - const U e1=i1m3[e]; - if((btDot(f->n,w->w)-f->d)<-EPA_PLANE_EPS) - { - sFace* nf=newface(f->c[e1],f->c[e],w,false); - if(nf) - { - bind(nf,0,f,e); - if(horizon.cf) bind(horizon.cf,1,nf,2); else horizon.ff=nf; - horizon.cf=nf; - ++horizon.nf; - return(true); - } - } - else - { - const U e2=i2m3[e]; - f->pass = (U1)pass; - if( expand(pass,w,f->f[e1],f->e[e1],horizon)&& - expand(pass,w,f->f[e2],f->e[e2],horizon)) - { - remove(m_hull,f); - append(m_stock,f); - return(true); - } - } - } - return(false); - } - - }; - - template - static void Initialize( const btConvexTemplate& a, const btConvexTemplate& b, - btGjkEpaSolver3::sResults& results, - MinkowskiDiff& shape) - { - /* Results */ - results.witnesses[0] = - results.witnesses[1] = btVector3(0,0,0); - results.status = btGjkEpaSolver3::sResults::Separated; - /* Shape */ - - shape.m_toshape1 = b.getWorldTransform().getBasis().transposeTimes(a.getWorldTransform().getBasis()); - shape.m_toshape0 = a.getWorldTransform().inverseTimes(b.getWorldTransform()); - - } - - -// -// Api -// - - - -// -template -bool btGjkEpaSolver3_Distance(const btConvexTemplate& a, const btConvexTemplate& b, - const btVector3& guess, - btGjkEpaSolver3::sResults& results) -{ - MinkowskiDiff shape(a,b); - Initialize(a,b,results,shape); - GJK gjk(a,b); - eGjkStatus gjk_status=gjk.Evaluate(shape,guess); - if(gjk_status==eGjkValid) - { - btVector3 w0=btVector3(0,0,0); - btVector3 w1=btVector3(0,0,0); - for(U i=0;irank;++i) - { - const btScalar p=gjk.m_simplex->p[i]; - w0+=shape.Support( gjk.m_simplex->c[i]->d,0)*p; - w1+=shape.Support(-gjk.m_simplex->c[i]->d,1)*p; - } - results.witnesses[0] = a.getWorldTransform()*w0; - results.witnesses[1] = a.getWorldTransform()*w1; - results.normal = w0-w1; - results.distance = results.normal.length(); - results.normal /= results.distance>GJK_MIN_DISTANCE?results.distance:1; - return(true); - } - else - { - results.status = gjk_status==eGjkInside? - btGjkEpaSolver3::sResults::Penetrating : - btGjkEpaSolver3::sResults::GJK_Failed ; - return(false); - } -} - - -template -bool btGjkEpaSolver3_Penetration(const btConvexTemplate& a, - const btConvexTemplate& b, - const btVector3& guess, - btGjkEpaSolver3::sResults& results) -{ - MinkowskiDiff shape(a,b); - Initialize(a,b,results,shape); - GJK gjk(a,b); - eGjkStatus gjk_status=gjk.Evaluate(shape,-guess); - switch(gjk_status) - { - case eGjkInside: - { - EPA epa; - eEpaStatus epa_status=epa.Evaluate(gjk,-guess); - if(epa_status!=eEpaFailed) - { - btVector3 w0=btVector3(0,0,0); - for(U i=0;id,0)*epa.m_result.p[i]; - } - results.status = btGjkEpaSolver3::sResults::Penetrating; - results.witnesses[0] = a.getWorldTransform()*w0; - results.witnesses[1] = a.getWorldTransform()*(w0-epa.m_normal*epa.m_depth); - results.normal = -epa.m_normal; - results.distance = -epa.m_depth; - return(true); - } else results.status=btGjkEpaSolver3::sResults::EPA_Failed; - } - break; - case eGjkFailed: - results.status=btGjkEpaSolver3::sResults::GJK_Failed; - break; - default: - { - } - } - return(false); -} - -#if 0 -int btComputeGjkEpaPenetration2(const btCollisionDescription& colDesc, btDistanceInfo* distInfo) -{ - btGjkEpaSolver3::sResults results; - btVector3 guess = colDesc.m_firstDir; - - bool res = btGjkEpaSolver3::Penetration(colDesc.m_objA,colDesc.m_objB, - colDesc.m_transformA,colDesc.m_transformB, - colDesc.m_localSupportFuncA,colDesc.m_localSupportFuncB, - guess, - results); - if (res) - { - if ((results.status==btGjkEpaSolver3::sResults::Penetrating) || results.status==GJK::eStatus::Inside) - { - //normal could be 'swapped' - - distInfo->m_distance = results.distance; - distInfo->m_normalBtoA = results.normal; - btVector3 tmpNormalInB = results.witnesses[1]-results.witnesses[0]; - btScalar lenSqr = tmpNormalInB.length2(); - if (lenSqr <= (SIMD_EPSILON*SIMD_EPSILON)) - { - tmpNormalInB = results.normal; - lenSqr = results.normal.length2(); - } - - if (lenSqr > (SIMD_EPSILON*SIMD_EPSILON)) - { - tmpNormalInB /= btSqrt(lenSqr); - btScalar distance2 = -(results.witnesses[0]-results.witnesses[1]).length(); - //only replace valid penetrations when the result is deeper (check) - //if ((distance2 < results.distance)) - { - distInfo->m_distance = distance2; - distInfo->m_pointOnA= results.witnesses[0]; - distInfo->m_pointOnB= results.witnesses[1]; - distInfo->m_normalBtoA= tmpNormalInB; - return 0; - } - } - } - - } - - return -1; -} -#endif - -template -int btComputeGjkDistance(const btConvexTemplate& a, const btConvexTemplate& b, - const btGjkCollisionDescription& colDesc, btDistanceInfoTemplate* distInfo) -{ - btGjkEpaSolver3::sResults results; - btVector3 guess = colDesc.m_firstDir; - - bool isSeparated = btGjkEpaSolver3_Distance( a,b, - guess, - results); - if (isSeparated) - { - distInfo->m_distance = results.distance; - distInfo->m_pointOnA= results.witnesses[0]; - distInfo->m_pointOnB= results.witnesses[1]; - distInfo->m_normalBtoA= results.normal; - return 0; - } - - return -1; -} - -/* Symbols cleanup */ - -#undef GJK_MAX_ITERATIONS -#undef GJK_ACCURARY -#undef GJK_MIN_DISTANCE -#undef GJK_DUPLICATED_EPS -#undef GJK_SIMPLEX2_EPS -#undef GJK_SIMPLEX3_EPS -#undef GJK_SIMPLEX4_EPS - -#undef EPA_MAX_VERTICES -#undef EPA_MAX_FACES -#undef EPA_MAX_ITERATIONS -#undef EPA_ACCURACY -#undef EPA_FALLBACK -#undef EPA_PLANE_EPS -#undef EPA_INSIDE_EPS - - - -#endif //BT_GJK_EPA3_H - +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2014 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. +*/ + +/* +Initial GJK-EPA collision solver by Nathanael Presson, 2008 +Improvements and refactoring by Erwin Coumans, 2008-2014 +*/ +#ifndef BT_GJK_EPA3_H +#define BT_GJK_EPA3_H + +#include "LinearMath/btTransform.h" +#include "btGjkCollisionDescription.h" + + + +struct btGjkEpaSolver3 +{ +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 distance; + }; + + +}; + + + +#if defined(DEBUG) || defined (_DEBUG) +#include //for debug printf +#ifdef __SPU__ +#include +#define printf spu_printf +#endif //__SPU__ +#endif + + + + // Config + + /* GJK */ +#define GJK_MAX_ITERATIONS 128 +#define GJK_ACCURARY ((btScalar)0.0001) +#define GJK_MIN_DISTANCE ((btScalar)0.0001) +#define GJK_DUPLICATED_EPS ((btScalar)0.0001) +#define GJK_SIMPLEX2_EPS ((btScalar)0.0) +#define GJK_SIMPLEX3_EPS ((btScalar)0.0) +#define GJK_SIMPLEX4_EPS ((btScalar)0.0) + + /* EPA */ +#define EPA_MAX_VERTICES 64 +#define EPA_MAX_FACES (EPA_MAX_VERTICES*2) +#define EPA_MAX_ITERATIONS 255 +#define EPA_ACCURACY ((btScalar)0.0001) +#define EPA_FALLBACK (10*EPA_ACCURACY) +#define EPA_PLANE_EPS ((btScalar)0.00001) +#define EPA_INSIDE_EPS ((btScalar)0.01) + + + // Shorthands + typedef unsigned int U; + typedef unsigned char U1; + + // MinkowskiDiff + template + struct MinkowskiDiff + { + const btConvexTemplate* m_convexAPtr; + const btConvexTemplate* m_convexBPtr; + + btMatrix3x3 m_toshape1; + btTransform m_toshape0; + + bool m_enableMargin; + + + MinkowskiDiff(const btConvexTemplate& a, const btConvexTemplate& b) + :m_convexAPtr(&a), + m_convexBPtr(&b) + { + } + + void EnableMargin(bool enable) + { + m_enableMargin = enable; + } + inline btVector3 Support0(const btVector3& d) const + { + return m_convexAPtr->getLocalSupportWithMargin(d); + } + inline btVector3 Support1(const btVector3& d) const + { + return m_toshape0*m_convexBPtr->getLocalSupportWithMargin(m_toshape1*d); + } + + + inline btVector3 Support(const btVector3& d) const + { + return(Support0(d)-Support1(-d)); + } + btVector3 Support(const btVector3& d,U index) const + { + if(index) + return(Support1(d)); + else + return(Support0(d)); + } + }; + +enum eGjkStatus +{ + eGjkValid, + eGjkInside, + eGjkFailed +}; + + // GJK + template + struct GJK + { + /* Types */ + struct sSV + { + btVector3 d,w; + }; + struct sSimplex + { + sSV* c[4]; + btScalar p[4]; + U rank; + }; + + /* Fields */ + + MinkowskiDiff m_shape; + btVector3 m_ray; + btScalar m_distance; + sSimplex m_simplices[2]; + sSV m_store[4]; + sSV* m_free[4]; + U m_nfree; + U m_current; + sSimplex* m_simplex; + eGjkStatus m_status; + /* Methods */ + + GJK(const btConvexTemplate& a, const btConvexTemplate& b) + :m_shape(a,b) + { + Initialize(); + } + void Initialize() + { + m_ray = btVector3(0,0,0); + m_nfree = 0; + m_status = eGjkFailed; + m_current = 0; + m_distance = 0; + } + eGjkStatus Evaluate(const MinkowskiDiff& shapearg,const btVector3& guess) + { + U iterations=0; + btScalar sqdist=0; + btScalar alpha=0; + btVector3 lastw[4]; + U clastw=0; + /* Initialize solver */ + m_free[0] = &m_store[0]; + m_free[1] = &m_store[1]; + m_free[2] = &m_store[2]; + m_free[3] = &m_store[3]; + m_nfree = 4; + m_current = 0; + m_status = eGjkValid; + m_shape = shapearg; + m_distance = 0; + /* Initialize simplex */ + m_simplices[0].rank = 0; + m_ray = guess; + const btScalar sqrl= m_ray.length2(); + appendvertice(m_simplices[0],sqrl>0?-m_ray:btVector3(1,0,0)); + m_simplices[0].p[0] = 1; + m_ray = m_simplices[0].c[0]->w; + sqdist = sqrl; + lastw[0] = + lastw[1] = + lastw[2] = + lastw[3] = m_ray; + /* Loop */ + do { + const U next=1-m_current; + sSimplex& cs=m_simplices[m_current]; + sSimplex& ns=m_simplices[next]; + /* Check zero */ + const btScalar rl=m_ray.length(); + if(rlw; + bool found=false; + for(U i=0;i<4;++i) + { + if((w-lastw[i]).length2()w, + cs.c[1]->w, + weights,mask);break; + case 3: sqdist=projectorigin( cs.c[0]->w, + cs.c[1]->w, + cs.c[2]->w, + weights,mask);break; + case 4: sqdist=projectorigin( cs.c[0]->w, + cs.c[1]->w, + cs.c[2]->w, + cs.c[3]->w, + weights,mask);break; + } + if(sqdist>=0) + {/* Valid */ + ns.rank = 0; + m_ray = btVector3(0,0,0); + m_current = next; + for(U i=0,ni=cs.rank;iw*weights[i]; + } + else + { + m_free[m_nfree++] = cs.c[i]; + } + } + if(mask==15) m_status=eGjkInside; + } + else + {/* Return old simplex */ + removevertice(m_simplices[m_current]); + break; + } + m_status=((++iterations)rank) + { + case 1: + { + for(U i=0;i<3;++i) + { + btVector3 axis=btVector3(0,0,0); + axis[i]=1; + appendvertice(*m_simplex, axis); + if(EncloseOrigin()) return(true); + removevertice(*m_simplex); + appendvertice(*m_simplex,-axis); + if(EncloseOrigin()) return(true); + removevertice(*m_simplex); + } + } + break; + case 2: + { + const btVector3 d=m_simplex->c[1]->w-m_simplex->c[0]->w; + for(U i=0;i<3;++i) + { + btVector3 axis=btVector3(0,0,0); + axis[i]=1; + const btVector3 p=btCross(d,axis); + if(p.length2()>0) + { + appendvertice(*m_simplex, p); + if(EncloseOrigin()) return(true); + removevertice(*m_simplex); + appendvertice(*m_simplex,-p); + if(EncloseOrigin()) return(true); + removevertice(*m_simplex); + } + } + } + break; + case 3: + { + const btVector3 n=btCross(m_simplex->c[1]->w-m_simplex->c[0]->w, + m_simplex->c[2]->w-m_simplex->c[0]->w); + if(n.length2()>0) + { + appendvertice(*m_simplex,n); + if(EncloseOrigin()) return(true); + removevertice(*m_simplex); + appendvertice(*m_simplex,-n); + if(EncloseOrigin()) return(true); + removevertice(*m_simplex); + } + } + break; + case 4: + { + if(btFabs(det( m_simplex->c[0]->w-m_simplex->c[3]->w, + m_simplex->c[1]->w-m_simplex->c[3]->w, + m_simplex->c[2]->w-m_simplex->c[3]->w))>0) + return(true); + } + break; + } + return(false); + } + /* Internals */ + void getsupport(const btVector3& d,sSV& sv) const + { + sv.d = d/d.length(); + sv.w = m_shape.Support(sv.d); + } + void removevertice(sSimplex& simplex) + { + m_free[m_nfree++]=simplex.c[--simplex.rank]; + } + void appendvertice(sSimplex& simplex,const btVector3& v) + { + simplex.p[simplex.rank]=0; + simplex.c[simplex.rank]=m_free[--m_nfree]; + getsupport(v,*simplex.c[simplex.rank++]); + } + static btScalar det(const btVector3& a,const btVector3& b,const btVector3& c) + { + return( a.y()*b.z()*c.x()+a.z()*b.x()*c.y()- + a.x()*b.z()*c.y()-a.y()*b.x()*c.z()+ + a.x()*b.y()*c.z()-a.z()*b.y()*c.x()); + } + static btScalar projectorigin( const btVector3& a, + const btVector3& b, + btScalar* w,U& m) + { + const btVector3 d=b-a; + const btScalar l=d.length2(); + if(l>GJK_SIMPLEX2_EPS) + { + const btScalar t(l>0?-btDot(a,d)/l:0); + if(t>=1) { w[0]=0;w[1]=1;m=2;return(b.length2()); } + else if(t<=0) { w[0]=1;w[1]=0;m=1;return(a.length2()); } + else { w[0]=1-(w[1]=t);m=3;return((a+d*t).length2()); } + } + return(-1); + } + static btScalar projectorigin( const btVector3& a, + const btVector3& b, + const btVector3& c, + btScalar* w,U& m) + { + static const U imd3[]={1,2,0}; + const btVector3* vt[]={&a,&b,&c}; + const btVector3 dl[]={a-b,b-c,c-a}; + const btVector3 n=btCross(dl[0],dl[1]); + const btScalar l=n.length2(); + if(l>GJK_SIMPLEX3_EPS) + { + btScalar mindist=-1; + btScalar subw[2]={0.f,0.f}; + U subm(0); + for(U i=0;i<3;++i) + { + if(btDot(*vt[i],btCross(dl[i],n))>0) + { + const U j=imd3[i]; + const btScalar subd(projectorigin(*vt[i],*vt[j],subw,subm)); + if((mindist<0)||(subd(((subm&1)?1<GJK_SIMPLEX4_EPS)) + { + btScalar mindist=-1; + btScalar subw[3]={0.f,0.f,0.f}; + U subm(0); + for(U i=0;i<3;++i) + { + const U j=imd3[i]; + const btScalar s=vl*btDot(d,btCross(dl[i],dl[j])); + if(s>0) + { + const btScalar subd=projectorigin(*vt[i],*vt[j],d,subw,subm); + if((mindist<0)||(subd((subm&1?1< + struct EPA + { + /* Types */ + + struct sFace + { + btVector3 n; + btScalar d; + typename GJK::sSV* c[3]; + sFace* f[3]; + sFace* l[2]; + U1 e[3]; + U1 pass; + }; + struct sList + { + sFace* root; + U count; + sList() : root(0),count(0) {} + }; + struct sHorizon + { + sFace* cf; + sFace* ff; + U nf; + sHorizon() : cf(0),ff(0),nf(0) {} + }; + + /* Fields */ + eEpaStatus m_status; + typename GJK::sSimplex m_result; + btVector3 m_normal; + btScalar m_depth; + typename GJK::sSV m_sv_store[EPA_MAX_VERTICES]; + sFace m_fc_store[EPA_MAX_FACES]; + U m_nextsv; + sList m_hull; + sList m_stock; + /* Methods */ + EPA() + { + Initialize(); + } + + + static inline void bind(sFace* fa,U ea,sFace* fb,U eb) + { + fa->e[ea]=(U1)eb;fa->f[ea]=fb; + fb->e[eb]=(U1)ea;fb->f[eb]=fa; + } + static inline void append(sList& list,sFace* face) + { + face->l[0] = 0; + face->l[1] = list.root; + if(list.root) list.root->l[0]=face; + list.root = face; + ++list.count; + } + static inline void remove(sList& list,sFace* face) + { + if(face->l[1]) face->l[1]->l[0]=face->l[0]; + if(face->l[0]) face->l[0]->l[1]=face->l[1]; + if(face==list.root) list.root=face->l[1]; + --list.count; + } + + + void Initialize() + { + m_status = eEpaFailed; + m_normal = btVector3(0,0,0); + m_depth = 0; + m_nextsv = 0; + for(U i=0;i& gjk,const btVector3& guess) + { + typename GJK::sSimplex& simplex=*gjk.m_simplex; + if((simplex.rank>1)&&gjk.EncloseOrigin()) + { + + /* Clean up */ + while(m_hull.root) + { + sFace* f = m_hull.root; + remove(m_hull,f); + append(m_stock,f); + } + m_status = eEpaValid; + m_nextsv = 0; + /* Orient simplex */ + if(gjk.det( simplex.c[0]->w-simplex.c[3]->w, + simplex.c[1]->w-simplex.c[3]->w, + simplex.c[2]->w-simplex.c[3]->w)<0) + { + btSwap(simplex.c[0],simplex.c[1]); + btSwap(simplex.p[0],simplex.p[1]); + } + /* Build initial hull */ + sFace* tetra[]={newface(simplex.c[0],simplex.c[1],simplex.c[2],true), + newface(simplex.c[1],simplex.c[0],simplex.c[3],true), + newface(simplex.c[2],simplex.c[1],simplex.c[3],true), + newface(simplex.c[0],simplex.c[2],simplex.c[3],true)}; + if(m_hull.count==4) + { + sFace* best=findbest(); + sFace outer=*best; + U pass=0; + U iterations=0; + bind(tetra[0],0,tetra[1],0); + bind(tetra[0],1,tetra[2],0); + bind(tetra[0],2,tetra[3],0); + bind(tetra[1],1,tetra[3],2); + bind(tetra[1],2,tetra[2],1); + bind(tetra[2],2,tetra[3],1); + m_status=eEpaValid; + for(;iterations::sSV* w=&m_sv_store[m_nextsv++]; + bool valid=true; + best->pass = (U1)(++pass); + gjk.getsupport(best->n,*w); + const btScalar wdist=btDot(best->n,w->w)-best->d; + if(wdist>EPA_ACCURACY) + { + for(U j=0;(j<3)&&valid;++j) + { + valid&=expand( pass,w, + best->f[j],best->e[j], + horizon); + } + if(valid&&(horizon.nf>=3)) + { + bind(horizon.cf,1,horizon.ff,2); + remove(m_hull,best); + append(m_stock,best); + best=findbest(); + outer=*best; + } else { m_status=eEpaInvalidHull;break; } + } else { m_status=eEpaAccuraryReached;break; } + } else { m_status=eEpaOutOfVertices;break; } + } + const btVector3 projection=outer.n*outer.d; + m_normal = outer.n; + m_depth = outer.d; + m_result.rank = 3; + m_result.c[0] = outer.c[0]; + m_result.c[1] = outer.c[1]; + m_result.c[2] = outer.c[2]; + m_result.p[0] = btCross( outer.c[1]->w-projection, + outer.c[2]->w-projection).length(); + m_result.p[1] = btCross( outer.c[2]->w-projection, + outer.c[0]->w-projection).length(); + m_result.p[2] = btCross( outer.c[0]->w-projection, + outer.c[1]->w-projection).length(); + const btScalar sum=m_result.p[0]+m_result.p[1]+m_result.p[2]; + m_result.p[0] /= sum; + m_result.p[1] /= sum; + m_result.p[2] /= sum; + return(m_status); + } + } + /* Fallback */ + m_status = eEpaFallBack; + m_normal = -guess; + const btScalar nl=m_normal.length(); + if(nl>0) + m_normal = m_normal/nl; + else + m_normal = btVector3(1,0,0); + m_depth = 0; + m_result.rank=1; + m_result.c[0]=simplex.c[0]; + m_result.p[0]=1; + return(m_status); + } + bool getedgedist(sFace* face, typename GJK::sSV* a, typename GJK::sSV* b, btScalar& dist) + { + const btVector3 ba = b->w - a->w; + const btVector3 n_ab = btCross(ba, face->n); // Outward facing edge normal direction, on triangle plane + const btScalar a_dot_nab = btDot(a->w, n_ab); // Only care about the sign to determine inside/outside, so not normalization required + + if(a_dot_nab < 0) + { + // Outside of edge a->b + + const btScalar ba_l2 = ba.length2(); + const btScalar a_dot_ba = btDot(a->w, ba); + const btScalar b_dot_ba = btDot(b->w, ba); + + if(a_dot_ba > 0) + { + // Pick distance vertex a + dist = a->w.length(); + } + else if(b_dot_ba < 0) + { + // Pick distance vertex b + dist = b->w.length(); + } + else + { + // Pick distance to edge a->b + const btScalar a_dot_b = btDot(a->w, b->w); + dist = btSqrt(btMax((a->w.length2() * b->w.length2() - a_dot_b * a_dot_b) / ba_l2, (btScalar)0)); + } + + return true; + } + + return false; + } + sFace* newface(typename GJK::sSV* a,typename GJK::sSV* b,typename GJK::sSV* c,bool forced) + { + if(m_stock.root) + { + sFace* face=m_stock.root; + remove(m_stock,face); + append(m_hull,face); + face->pass = 0; + face->c[0] = a; + face->c[1] = b; + face->c[2] = c; + face->n = btCross(b->w-a->w,c->w-a->w); + const btScalar l=face->n.length(); + const bool v=l>EPA_ACCURACY; + + if(v) + { + if(!(getedgedist(face, a, b, face->d) || + getedgedist(face, b, c, face->d) || + getedgedist(face, c, a, face->d))) + { + // Origin projects to the interior of the triangle + // Use distance to triangle plane + face->d = btDot(a->w, face->n) / l; + } + + face->n /= l; + if(forced || (face->d >= -EPA_PLANE_EPS)) + { + return face; + } + else + m_status=eEpaNonConvex; + } + else + m_status=eEpaDegenerated; + + remove(m_hull, face); + append(m_stock, face); + return 0; + + } + m_status = m_stock.root ? eEpaOutOfVertices : eEpaOutOfFaces; + return 0; + } + sFace* findbest() + { + sFace* minf=m_hull.root; + btScalar mind=minf->d*minf->d; + for(sFace* f=minf->l[1];f;f=f->l[1]) + { + const btScalar sqd=f->d*f->d; + if(sqd::sSV* w,sFace* f,U e,sHorizon& horizon) + { + static const U i1m3[]={1,2,0}; + static const U i2m3[]={2,0,1}; + if(f->pass!=pass) + { + const U e1=i1m3[e]; + if((btDot(f->n,w->w)-f->d)<-EPA_PLANE_EPS) + { + sFace* nf=newface(f->c[e1],f->c[e],w,false); + if(nf) + { + bind(nf,0,f,e); + if(horizon.cf) bind(horizon.cf,1,nf,2); else horizon.ff=nf; + horizon.cf=nf; + ++horizon.nf; + return(true); + } + } + else + { + const U e2=i2m3[e]; + f->pass = (U1)pass; + if( expand(pass,w,f->f[e1],f->e[e1],horizon)&& + expand(pass,w,f->f[e2],f->e[e2],horizon)) + { + remove(m_hull,f); + append(m_stock,f); + return(true); + } + } + } + return(false); + } + + }; + + template + static void Initialize( const btConvexTemplate& a, const btConvexTemplate& b, + btGjkEpaSolver3::sResults& results, + MinkowskiDiff& shape) + { + /* Results */ + results.witnesses[0] = + results.witnesses[1] = btVector3(0,0,0); + results.status = btGjkEpaSolver3::sResults::Separated; + /* Shape */ + + shape.m_toshape1 = b.getWorldTransform().getBasis().transposeTimes(a.getWorldTransform().getBasis()); + shape.m_toshape0 = a.getWorldTransform().inverseTimes(b.getWorldTransform()); + + } + + +// +// Api +// + + + +// +template +bool btGjkEpaSolver3_Distance(const btConvexTemplate& a, const btConvexTemplate& b, + const btVector3& guess, + btGjkEpaSolver3::sResults& results) +{ + MinkowskiDiff shape(a,b); + Initialize(a,b,results,shape); + GJK gjk(a,b); + eGjkStatus gjk_status=gjk.Evaluate(shape,guess); + if(gjk_status==eGjkValid) + { + btVector3 w0=btVector3(0,0,0); + btVector3 w1=btVector3(0,0,0); + for(U i=0;irank;++i) + { + const btScalar p=gjk.m_simplex->p[i]; + w0+=shape.Support( gjk.m_simplex->c[i]->d,0)*p; + w1+=shape.Support(-gjk.m_simplex->c[i]->d,1)*p; + } + results.witnesses[0] = a.getWorldTransform()*w0; + results.witnesses[1] = a.getWorldTransform()*w1; + results.normal = w0-w1; + results.distance = results.normal.length(); + results.normal /= results.distance>GJK_MIN_DISTANCE?results.distance:1; + return(true); + } + else + { + results.status = gjk_status==eGjkInside? + btGjkEpaSolver3::sResults::Penetrating : + btGjkEpaSolver3::sResults::GJK_Failed ; + return(false); + } +} + + +template +bool btGjkEpaSolver3_Penetration(const btConvexTemplate& a, + const btConvexTemplate& b, + const btVector3& guess, + btGjkEpaSolver3::sResults& results) +{ + MinkowskiDiff shape(a,b); + Initialize(a,b,results,shape); + GJK gjk(a,b); + eGjkStatus gjk_status=gjk.Evaluate(shape,-guess); + switch(gjk_status) + { + case eGjkInside: + { + EPA epa; + eEpaStatus epa_status=epa.Evaluate(gjk,-guess); + if(epa_status!=eEpaFailed) + { + btVector3 w0=btVector3(0,0,0); + for(U i=0;id,0)*epa.m_result.p[i]; + } + results.status = btGjkEpaSolver3::sResults::Penetrating; + results.witnesses[0] = a.getWorldTransform()*w0; + results.witnesses[1] = a.getWorldTransform()*(w0-epa.m_normal*epa.m_depth); + results.normal = -epa.m_normal; + results.distance = -epa.m_depth; + return(true); + } else results.status=btGjkEpaSolver3::sResults::EPA_Failed; + } + break; + case eGjkFailed: + results.status=btGjkEpaSolver3::sResults::GJK_Failed; + break; + default: + { + } + } + return(false); +} + +#if 0 +int btComputeGjkEpaPenetration2(const btCollisionDescription& colDesc, btDistanceInfo* distInfo) +{ + btGjkEpaSolver3::sResults results; + btVector3 guess = colDesc.m_firstDir; + + bool res = btGjkEpaSolver3::Penetration(colDesc.m_objA,colDesc.m_objB, + colDesc.m_transformA,colDesc.m_transformB, + colDesc.m_localSupportFuncA,colDesc.m_localSupportFuncB, + guess, + results); + if (res) + { + if ((results.status==btGjkEpaSolver3::sResults::Penetrating) || results.status==GJK::eStatus::Inside) + { + //normal could be 'swapped' + + distInfo->m_distance = results.distance; + distInfo->m_normalBtoA = results.normal; + btVector3 tmpNormalInB = results.witnesses[1]-results.witnesses[0]; + btScalar lenSqr = tmpNormalInB.length2(); + if (lenSqr <= (SIMD_EPSILON*SIMD_EPSILON)) + { + tmpNormalInB = results.normal; + lenSqr = results.normal.length2(); + } + + if (lenSqr > (SIMD_EPSILON*SIMD_EPSILON)) + { + tmpNormalInB /= btSqrt(lenSqr); + btScalar distance2 = -(results.witnesses[0]-results.witnesses[1]).length(); + //only replace valid penetrations when the result is deeper (check) + //if ((distance2 < results.distance)) + { + distInfo->m_distance = distance2; + distInfo->m_pointOnA= results.witnesses[0]; + distInfo->m_pointOnB= results.witnesses[1]; + distInfo->m_normalBtoA= tmpNormalInB; + return 0; + } + } + } + + } + + return -1; +} +#endif + +template +int btComputeGjkDistance(const btConvexTemplate& a, const btConvexTemplate& b, + const btGjkCollisionDescription& colDesc, btDistanceInfoTemplate* distInfo) +{ + btGjkEpaSolver3::sResults results; + btVector3 guess = colDesc.m_firstDir; + + bool isSeparated = btGjkEpaSolver3_Distance( a,b, + guess, + results); + if (isSeparated) + { + distInfo->m_distance = results.distance; + distInfo->m_pointOnA= results.witnesses[0]; + distInfo->m_pointOnB= results.witnesses[1]; + distInfo->m_normalBtoA= results.normal; + return 0; + } + + return -1; +} + +/* Symbols cleanup */ + +#undef GJK_MAX_ITERATIONS +#undef GJK_ACCURARY +#undef GJK_MIN_DISTANCE +#undef GJK_DUPLICATED_EPS +#undef GJK_SIMPLEX2_EPS +#undef GJK_SIMPLEX3_EPS +#undef GJK_SIMPLEX4_EPS + +#undef EPA_MAX_VERTICES +#undef EPA_MAX_FACES +#undef EPA_MAX_ITERATIONS +#undef EPA_ACCURACY +#undef EPA_FALLBACK +#undef EPA_PLANE_EPS +#undef EPA_INSIDE_EPS + + + +#endif //BT_GJK_EPA3_H + diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h similarity index 100% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp similarity index 87% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp index 759443a9613f..257b026d9bbd 100644 --- a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp +++ b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp @@ -30,7 +30,13 @@ subject to the following restrictions: #endif //must be above the machine epsilon -#define REL_ERROR2 btScalar(1.0e-6) +#ifdef BT_USE_DOUBLE_PRECISION + #define REL_ERROR2 btScalar(1.0e-12) + btScalar gGjkEpaPenetrationTolerance = 1e-7; +#else + #define REL_ERROR2 btScalar(1.0e-6) + btScalar gGjkEpaPenetrationTolerance = 0.001; +#endif //temp globals, to improve GJK/EPA/penetration calculations int gNumDeepPenetrationChecks = 0; @@ -275,7 +281,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu btScalar lenSqr =m_cachedSeparatingAxis.length2(); //valid normal - if (lenSqr < 0.0001) + if (lenSqr < REL_ERROR2) { m_degenerateSimplex = 5; } @@ -300,7 +306,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu } bool catchDegeneratePenetrationCase = - (m_catchDegeneracies && m_penetrationDepthSolver && m_degenerateSimplex && ((distance+margin) < 0.01)); + (m_catchDegeneracies && m_penetrationDepthSolver && m_degenerateSimplex && ((distance+margin) < gGjkEpaPenetrationTolerance)); //if (checkPenetration && !isValid) if (checkPenetration && (!isValid || catchDegeneratePenetrationCase )) @@ -347,46 +353,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu pointOnA = tmpPointOnA; pointOnB = tmpPointOnB; normalInB = tmpNormalInB; - ///todo: need to track down this EPA penetration solver degeneracy - ///the penetration solver reports penetration but the contact normal - ///connecting the contact points is pointing in the opposite direction - ///until then, detect the issue and revert the normal - { - btScalar d1=0; - { - btVector3 seperatingAxisInA = (normalInB)* input.m_transformA.getBasis(); - btVector3 seperatingAxisInB = -normalInB* input.m_transformB.getBasis(); - - - btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA); - btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB); - - btVector3 pWorld = localTransA(pInA); - btVector3 qWorld = localTransB(qInB); - btVector3 w = pWorld - qWorld; - d1 = (-normalInB).dot(w); - } - btScalar d0 = 0.f; - { - btVector3 seperatingAxisInA = (-normalInB)* input.m_transformA.getBasis(); - btVector3 seperatingAxisInB = normalInB* input.m_transformB.getBasis(); - - - btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA); - btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB); - - btVector3 pWorld = localTransA(pInA); - btVector3 qWorld = localTransB(qInB); - btVector3 w = pWorld - qWorld; - d0 = normalInB.dot(w); - } - if (d1>d0) - { - m_lastUsedMethod = 10; - normalInB*=-1; - } - - } + isValid = true; } else @@ -443,6 +410,47 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu m_cachedSeparatingAxis = normalInB; m_cachedSeparatingDistance = distance; + { + ///todo: need to track down this EPA penetration solver degeneracy + ///the penetration solver reports penetration but the contact normal + ///connecting the contact points is pointing in the opposite direction + ///until then, detect the issue and revert the normal + + btScalar d1=0; + { + btVector3 seperatingAxisInA = (normalInB)* input.m_transformA.getBasis(); + btVector3 seperatingAxisInB = -normalInB* input.m_transformB.getBasis(); + + + btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA); + btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB); + + btVector3 pWorld = localTransA(pInA); + btVector3 qWorld = localTransB(qInB); + btVector3 w = pWorld - qWorld; + d1 = (-normalInB).dot(w); + } + btScalar d0 = 0.f; + { + btVector3 seperatingAxisInA = (-normalInB)* input.m_transformA.getBasis(); + btVector3 seperatingAxisInB = normalInB* input.m_transformB.getBasis(); + + + btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA); + btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB); + + btVector3 pWorld = localTransA(pInA); + btVector3 qWorld = localTransB(qInB); + btVector3 w = pWorld - qWorld; + d0 = normalInB.dot(w); + } + if (d1>d0) + { + m_lastUsedMethod = 10; + normalInB*=-1; + } + + } output.addContactPoint( normalInB, pointOnB+positionOffset, diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h similarity index 100% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h similarity index 76% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h index e40fb1d3db60..571ad2c5f72e 100644 --- a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h +++ b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h @@ -35,7 +35,14 @@ typedef sce::PhysicsEffects::PfxConstraintRow btConstraintRow; typedef btConstraintRow PfxConstraintRow; #endif //PFX_USE_FREE_VECTORMATH - +enum btContactPointFlags +{ + BT_CONTACT_FLAG_LATERAL_FRICTION_INITIALIZED=1, + BT_CONTACT_FLAG_HAS_CONTACT_CFM=2, + BT_CONTACT_FLAG_HAS_CONTACT_ERP=4, + BT_CONTACT_FLAG_CONTACT_STIFFNESS_DAMPING = 8, + BT_CONTACT_FLAG_FRICTION_ANCHOR = 16, +}; /// ManifoldContactPoint collects and maintains persistent contactpoints. /// used to improve stability and performance of rigidbody dynamics response. @@ -44,14 +51,15 @@ class btManifoldPoint public: btManifoldPoint() :m_userPersistentData(0), - m_lateralFrictionInitialized(false), - m_appliedImpulse(0.f), + m_contactPointFlags(0), + m_appliedImpulse(0.f), m_appliedImpulseLateral1(0.f), m_appliedImpulseLateral2(0.f), m_contactMotion1(0.f), m_contactMotion2(0.f), - m_contactCFM1(0.f), - m_contactCFM2(0.f), + m_contactCFM(0.f), + m_contactERP(0.f), + m_frictionCFM(0.f), m_lifeTime(0) { } @@ -65,16 +73,18 @@ class btManifoldPoint m_distance1( distance ), m_combinedFriction(btScalar(0.)), m_combinedRollingFriction(btScalar(0.)), - m_combinedRestitution(btScalar(0.)), + m_combinedSpinningFriction(btScalar(0.)), + m_combinedRestitution(btScalar(0.)), m_userPersistentData(0), - m_lateralFrictionInitialized(false), - m_appliedImpulse(0.f), + m_contactPointFlags(0), + m_appliedImpulse(0.f), m_appliedImpulseLateral1(0.f), m_appliedImpulseLateral2(0.f), m_contactMotion1(0.f), m_contactMotion2(0.f), - m_contactCFM1(0.f), - m_contactCFM2(0.f), + m_contactCFM(0.f), + m_contactERP(0.f), + m_frictionCFM(0.f), m_lifeTime(0) { @@ -91,8 +101,9 @@ class btManifoldPoint btScalar m_distance1; btScalar m_combinedFriction; - btScalar m_combinedRollingFriction; - btScalar m_combinedRestitution; + btScalar m_combinedRollingFriction;//torsional friction orthogonal to contact normal, useful to make spheres stop rolling forever + btScalar m_combinedSpinningFriction;//torsional friction around contact normal, useful for grasping objects + btScalar m_combinedRestitution; //BP mod, store contact triangles. int m_partId0; @@ -101,15 +112,28 @@ class btManifoldPoint int m_index1; mutable void* m_userPersistentData; - bool m_lateralFrictionInitialized; - + //bool m_lateralFrictionInitialized; + int m_contactPointFlags; + btScalar m_appliedImpulse; btScalar m_appliedImpulseLateral1; btScalar m_appliedImpulseLateral2; btScalar m_contactMotion1; btScalar m_contactMotion2; - btScalar m_contactCFM1; - btScalar m_contactCFM2; + + union + { + btScalar m_contactCFM; + btScalar m_combinedContactStiffness1; + }; + + union + { + btScalar m_contactERP; + btScalar m_combinedContactDamping1; + }; + + btScalar m_frictionCFM; int m_lifeTime;//lifetime of the contactpoint in frames diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h similarity index 100% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btMprPenetration.h b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btMprPenetration.h similarity index 96% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btMprPenetration.h rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btMprPenetration.h index a22a0bae66be..052f48b8c574 100644 --- a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btMprPenetration.h +++ b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btMprPenetration.h @@ -1,908 +1,908 @@ - -/*** - * --------------------------------- - * Copyright (c)2012 Daniel Fiser - * - * This file was ported from mpr.c file, part of libccd. - * The Minkoski Portal Refinement implementation was ported - * to OpenCL by Erwin Coumans for the Bullet 3 Physics library. - * The original MPR idea and implementation is by Gary Snethen - * in XenoCollide, see http://github.com/erwincoumans/xenocollide - * - * Distributed under the OSI-approved BSD License (the "License"); - * see . - * This software is distributed WITHOUT ANY WARRANTY; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the License for more information. - */ - -///2014 Oct, Erwin Coumans, Use templates to avoid void* casts - -#ifndef BT_MPR_PENETRATION_H -#define BT_MPR_PENETRATION_H - -#define BT_DEBUG_MPR1 - -#include "LinearMath/btTransform.h" -#include "LinearMath/btAlignedObjectArray.h" - -//#define MPR_AVERAGE_CONTACT_POSITIONS - - -struct btMprCollisionDescription -{ - btVector3 m_firstDir; - int m_maxGjkIterations; - btScalar m_maximumDistanceSquared; - btScalar m_gjkRelError2; - - btMprCollisionDescription() - : m_firstDir(0,1,0), - m_maxGjkIterations(1000), - m_maximumDistanceSquared(1e30f), - m_gjkRelError2(1.0e-6) - { - } - virtual ~btMprCollisionDescription() - { - } -}; - -struct btMprDistanceInfo -{ - btVector3 m_pointOnA; - btVector3 m_pointOnB; - btVector3 m_normalBtoA; - btScalar m_distance; -}; - -#ifdef __cplusplus -#define BT_MPR_SQRT sqrtf -#else -#define BT_MPR_SQRT sqrt -#endif -#define BT_MPR_FMIN(x, y) ((x) < (y) ? (x) : (y)) -#define BT_MPR_FABS fabs - -#define BT_MPR_TOLERANCE 1E-6f -#define BT_MPR_MAX_ITERATIONS 1000 - -struct _btMprSupport_t -{ - btVector3 v; //!< Support point in minkowski sum - btVector3 v1; //!< Support point in obj1 - btVector3 v2; //!< Support point in obj2 -}; -typedef struct _btMprSupport_t btMprSupport_t; - -struct _btMprSimplex_t -{ - btMprSupport_t ps[4]; - int last; //!< index of last added point -}; -typedef struct _btMprSimplex_t btMprSimplex_t; - -inline btMprSupport_t* btMprSimplexPointW(btMprSimplex_t *s, int idx) -{ - return &s->ps[idx]; -} - -inline void btMprSimplexSetSize(btMprSimplex_t *s, int size) -{ - s->last = size - 1; -} - -#ifdef DEBUG_MPR -inline void btPrintPortalVertex(_btMprSimplex_t* portal, int index) -{ - printf("portal[%d].v = %f,%f,%f, v1=%f,%f,%f, v2=%f,%f,%f\n", index, portal->ps[index].v.x(),portal->ps[index].v.y(),portal->ps[index].v.z(), - portal->ps[index].v1.x(),portal->ps[index].v1.y(),portal->ps[index].v1.z(), - portal->ps[index].v2.x(),portal->ps[index].v2.y(),portal->ps[index].v2.z()); -} -#endif //DEBUG_MPR - - - - -inline int btMprSimplexSize(const btMprSimplex_t *s) -{ - return s->last + 1; -} - - -inline const btMprSupport_t* btMprSimplexPoint(const btMprSimplex_t* s, int idx) -{ - // here is no check on boundaries - return &s->ps[idx]; -} - -inline void btMprSupportCopy(btMprSupport_t *d, const btMprSupport_t *s) -{ - *d = *s; -} - -inline void btMprSimplexSet(btMprSimplex_t *s, size_t pos, const btMprSupport_t *a) -{ - btMprSupportCopy(s->ps + pos, a); -} - - -inline void btMprSimplexSwap(btMprSimplex_t *s, size_t pos1, size_t pos2) -{ - btMprSupport_t supp; - - btMprSupportCopy(&supp, &s->ps[pos1]); - btMprSupportCopy(&s->ps[pos1], &s->ps[pos2]); - btMprSupportCopy(&s->ps[pos2], &supp); -} - - -inline int btMprIsZero(float val) -{ - return BT_MPR_FABS(val) < FLT_EPSILON; -} - - - -inline int btMprEq(float _a, float _b) -{ - float ab; - float a, b; - - ab = BT_MPR_FABS(_a - _b); - if (BT_MPR_FABS(ab) < FLT_EPSILON) - return 1; - - a = BT_MPR_FABS(_a); - b = BT_MPR_FABS(_b); - if (b > a){ - return ab < FLT_EPSILON * b; - }else{ - return ab < FLT_EPSILON * a; - } -} - - -inline int btMprVec3Eq(const btVector3* a, const btVector3 *b) -{ - return btMprEq((*a).x(), (*b).x()) - && btMprEq((*a).y(), (*b).y()) - && btMprEq((*a).z(), (*b).z()); -} - - - - - - - - - - - -template -inline void btFindOrigin(const btConvexTemplate& a, const btConvexTemplate& b, const btMprCollisionDescription& colDesc,btMprSupport_t *center) -{ - - center->v1 = a.getObjectCenterInWorld(); - center->v2 = b.getObjectCenterInWorld(); - center->v = center->v1 - center->v2; -} - -inline void btMprVec3Set(btVector3 *v, float x, float y, float z) -{ - v->setValue(x,y,z); -} - -inline void btMprVec3Add(btVector3 *v, const btVector3 *w) -{ - *v += *w; -} - -inline void btMprVec3Copy(btVector3 *v, const btVector3 *w) -{ - *v = *w; -} - -inline void btMprVec3Scale(btVector3 *d, float k) -{ - *d *= k; -} - -inline float btMprVec3Dot(const btVector3 *a, const btVector3 *b) -{ - float dot; - - dot = btDot(*a,*b); - return dot; -} - - -inline float btMprVec3Len2(const btVector3 *v) -{ - return btMprVec3Dot(v, v); -} - -inline void btMprVec3Normalize(btVector3 *d) -{ - float k = 1.f / BT_MPR_SQRT(btMprVec3Len2(d)); - btMprVec3Scale(d, k); -} - -inline void btMprVec3Cross(btVector3 *d, const btVector3 *a, const btVector3 *b) -{ - *d = btCross(*a,*b); - -} - - -inline void btMprVec3Sub2(btVector3 *d, const btVector3 *v, const btVector3 *w) -{ - *d = *v - *w; -} - -inline void btPortalDir(const btMprSimplex_t *portal, btVector3 *dir) -{ - btVector3 v2v1, v3v1; - - btMprVec3Sub2(&v2v1, &btMprSimplexPoint(portal, 2)->v, - &btMprSimplexPoint(portal, 1)->v); - btMprVec3Sub2(&v3v1, &btMprSimplexPoint(portal, 3)->v, - &btMprSimplexPoint(portal, 1)->v); - btMprVec3Cross(dir, &v2v1, &v3v1); - btMprVec3Normalize(dir); -} - - -inline int portalEncapsulesOrigin(const btMprSimplex_t *portal, - const btVector3 *dir) -{ - float dot; - dot = btMprVec3Dot(dir, &btMprSimplexPoint(portal, 1)->v); - return btMprIsZero(dot) || dot > 0.f; -} - -inline int portalReachTolerance(const btMprSimplex_t *portal, - const btMprSupport_t *v4, - const btVector3 *dir) -{ - float dv1, dv2, dv3, dv4; - float dot1, dot2, dot3; - - // find the smallest dot product of dir and {v1-v4, v2-v4, v3-v4} - - dv1 = btMprVec3Dot(&btMprSimplexPoint(portal, 1)->v, dir); - dv2 = btMprVec3Dot(&btMprSimplexPoint(portal, 2)->v, dir); - dv3 = btMprVec3Dot(&btMprSimplexPoint(portal, 3)->v, dir); - dv4 = btMprVec3Dot(&v4->v, dir); - - dot1 = dv4 - dv1; - dot2 = dv4 - dv2; - dot3 = dv4 - dv3; - - dot1 = BT_MPR_FMIN(dot1, dot2); - dot1 = BT_MPR_FMIN(dot1, dot3); - - return btMprEq(dot1, BT_MPR_TOLERANCE) || dot1 < BT_MPR_TOLERANCE; -} - -inline int portalCanEncapsuleOrigin(const btMprSimplex_t *portal, - const btMprSupport_t *v4, - const btVector3 *dir) -{ - float dot; - dot = btMprVec3Dot(&v4->v, dir); - return btMprIsZero(dot) || dot > 0.f; -} - -inline void btExpandPortal(btMprSimplex_t *portal, - const btMprSupport_t *v4) -{ - float dot; - btVector3 v4v0; - - btMprVec3Cross(&v4v0, &v4->v, &btMprSimplexPoint(portal, 0)->v); - dot = btMprVec3Dot(&btMprSimplexPoint(portal, 1)->v, &v4v0); - if (dot > 0.f){ - dot = btMprVec3Dot(&btMprSimplexPoint(portal, 2)->v, &v4v0); - if (dot > 0.f){ - btMprSimplexSet(portal, 1, v4); - }else{ - btMprSimplexSet(portal, 3, v4); - } - }else{ - dot = btMprVec3Dot(&btMprSimplexPoint(portal, 3)->v, &v4v0); - if (dot > 0.f){ - btMprSimplexSet(portal, 2, v4); - }else{ - btMprSimplexSet(portal, 1, v4); - } - } -} -template -inline void btMprSupport(const btConvexTemplate& a, const btConvexTemplate& b, - const btMprCollisionDescription& colDesc, - const btVector3& dir, btMprSupport_t *supp) -{ - btVector3 seperatingAxisInA = dir* a.getWorldTransform().getBasis(); - btVector3 seperatingAxisInB = -dir* b.getWorldTransform().getBasis(); - - btVector3 pInA = a.getLocalSupportWithMargin(seperatingAxisInA); - btVector3 qInB = b.getLocalSupportWithMargin(seperatingAxisInB); - - supp->v1 = a.getWorldTransform()(pInA); - supp->v2 = b.getWorldTransform()(qInB); - supp->v = supp->v1 - supp->v2; -} - - -template -static int btDiscoverPortal(const btConvexTemplate& a, const btConvexTemplate& b, - const btMprCollisionDescription& colDesc, - btMprSimplex_t *portal) -{ - btVector3 dir, va, vb; - float dot; - int cont; - - - - // vertex 0 is center of portal - btFindOrigin(a,b,colDesc, btMprSimplexPointW(portal, 0)); - - - // vertex 0 is center of portal - btMprSimplexSetSize(portal, 1); - - - - btVector3 zero = btVector3(0,0,0); - btVector3* org = &zero; - - if (btMprVec3Eq(&btMprSimplexPoint(portal, 0)->v, org)){ - // Portal's center lies on origin (0,0,0) => we know that objects - // intersect but we would need to know penetration info. - // So move center little bit... - btMprVec3Set(&va, FLT_EPSILON * 10.f, 0.f, 0.f); - btMprVec3Add(&btMprSimplexPointW(portal, 0)->v, &va); - } - - - // vertex 1 = support in direction of origin - btMprVec3Copy(&dir, &btMprSimplexPoint(portal, 0)->v); - btMprVec3Scale(&dir, -1.f); - btMprVec3Normalize(&dir); - - - btMprSupport(a,b,colDesc, dir, btMprSimplexPointW(portal, 1)); - - btMprSimplexSetSize(portal, 2); - - // test if origin isn't outside of v1 - dot = btMprVec3Dot(&btMprSimplexPoint(portal, 1)->v, &dir); - - - if (btMprIsZero(dot) || dot < 0.f) - return -1; - - - // vertex 2 - btMprVec3Cross(&dir, &btMprSimplexPoint(portal, 0)->v, - &btMprSimplexPoint(portal, 1)->v); - if (btMprIsZero(btMprVec3Len2(&dir))){ - if (btMprVec3Eq(&btMprSimplexPoint(portal, 1)->v, org)){ - // origin lies on v1 - return 1; - }else{ - // origin lies on v0-v1 segment - return 2; - } - } - - btMprVec3Normalize(&dir); - btMprSupport(a,b,colDesc, dir, btMprSimplexPointW(portal, 2)); - - - - dot = btMprVec3Dot(&btMprSimplexPoint(portal, 2)->v, &dir); - if (btMprIsZero(dot) || dot < 0.f) - return -1; - - btMprSimplexSetSize(portal, 3); - - // vertex 3 direction - btMprVec3Sub2(&va, &btMprSimplexPoint(portal, 1)->v, - &btMprSimplexPoint(portal, 0)->v); - btMprVec3Sub2(&vb, &btMprSimplexPoint(portal, 2)->v, - &btMprSimplexPoint(portal, 0)->v); - btMprVec3Cross(&dir, &va, &vb); - btMprVec3Normalize(&dir); - - // it is better to form portal faces to be oriented "outside" origin - dot = btMprVec3Dot(&dir, &btMprSimplexPoint(portal, 0)->v); - if (dot > 0.f){ - btMprSimplexSwap(portal, 1, 2); - btMprVec3Scale(&dir, -1.f); - } - - while (btMprSimplexSize(portal) < 4){ - btMprSupport(a,b,colDesc, dir, btMprSimplexPointW(portal, 3)); - - dot = btMprVec3Dot(&btMprSimplexPoint(portal, 3)->v, &dir); - if (btMprIsZero(dot) || dot < 0.f) - return -1; - - cont = 0; - - // test if origin is outside (v1, v0, v3) - set v2 as v3 and - // continue - btMprVec3Cross(&va, &btMprSimplexPoint(portal, 1)->v, - &btMprSimplexPoint(portal, 3)->v); - dot = btMprVec3Dot(&va, &btMprSimplexPoint(portal, 0)->v); - if (dot < 0.f && !btMprIsZero(dot)){ - btMprSimplexSet(portal, 2, btMprSimplexPoint(portal, 3)); - cont = 1; - } - - if (!cont){ - // test if origin is outside (v3, v0, v2) - set v1 as v3 and - // continue - btMprVec3Cross(&va, &btMprSimplexPoint(portal, 3)->v, - &btMprSimplexPoint(portal, 2)->v); - dot = btMprVec3Dot(&va, &btMprSimplexPoint(portal, 0)->v); - if (dot < 0.f && !btMprIsZero(dot)){ - btMprSimplexSet(portal, 1, btMprSimplexPoint(portal, 3)); - cont = 1; - } - } - - if (cont){ - btMprVec3Sub2(&va, &btMprSimplexPoint(portal, 1)->v, - &btMprSimplexPoint(portal, 0)->v); - btMprVec3Sub2(&vb, &btMprSimplexPoint(portal, 2)->v, - &btMprSimplexPoint(portal, 0)->v); - btMprVec3Cross(&dir, &va, &vb); - btMprVec3Normalize(&dir); - }else{ - btMprSimplexSetSize(portal, 4); - } - } - - return 0; -} - -template -static int btRefinePortal(const btConvexTemplate& a, const btConvexTemplate& b,const btMprCollisionDescription& colDesc, - btMprSimplex_t *portal) -{ - btVector3 dir; - btMprSupport_t v4; - - for (int i=0;iv, - &btMprSimplexPoint(portal, 2)->v); - b[0] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 3)->v); - - btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 3)->v, - &btMprSimplexPoint(portal, 2)->v); - b[1] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 0)->v); - - btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 0)->v, - &btMprSimplexPoint(portal, 1)->v); - b[2] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 3)->v); - - btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 2)->v, - &btMprSimplexPoint(portal, 1)->v); - b[3] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 0)->v); - - sum = b[0] + b[1] + b[2] + b[3]; - - if (btMprIsZero(sum) || sum < 0.f){ - b[0] = 0.f; - - btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 2)->v, - &btMprSimplexPoint(portal, 3)->v); - b[1] = btMprVec3Dot(&vec, &dir); - btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 3)->v, - &btMprSimplexPoint(portal, 1)->v); - b[2] = btMprVec3Dot(&vec, &dir); - btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 1)->v, - &btMprSimplexPoint(portal, 2)->v); - b[3] = btMprVec3Dot(&vec, &dir); - - sum = b[1] + b[2] + b[3]; - } - - inv = 1.f / sum; - - btMprVec3Copy(&p1, origin); - btMprVec3Copy(&p2, origin); - for (i = 0; i < 4; i++){ - btMprVec3Copy(&vec, &btMprSimplexPoint(portal, i)->v1); - btMprVec3Scale(&vec, b[i]); - btMprVec3Add(&p1, &vec); - - btMprVec3Copy(&vec, &btMprSimplexPoint(portal, i)->v2); - btMprVec3Scale(&vec, b[i]); - btMprVec3Add(&p2, &vec); - } - btMprVec3Scale(&p1, inv); - btMprVec3Scale(&p2, inv); -#ifdef MPR_AVERAGE_CONTACT_POSITIONS - btMprVec3Copy(pos, &p1); - btMprVec3Add(pos, &p2); - btMprVec3Scale(pos, 0.5); -#else - btMprVec3Copy(pos, &p2); -#endif//MPR_AVERAGE_CONTACT_POSITIONS -} - -inline float btMprVec3Dist2(const btVector3 *a, const btVector3 *b) -{ - btVector3 ab; - btMprVec3Sub2(&ab, a, b); - return btMprVec3Len2(&ab); -} - -inline float _btMprVec3PointSegmentDist2(const btVector3 *P, - const btVector3 *x0, - const btVector3 *b, - btVector3 *witness) -{ - // The computation comes from solving equation of segment: - // S(t) = x0 + t.d - // where - x0 is initial point of segment - // - d is direction of segment from x0 (|d| > 0) - // - t belongs to <0, 1> interval - // - // Than, distance from a segment to some point P can be expressed: - // D(t) = |x0 + t.d - P|^2 - // which is distance from any point on segment. Minimization - // of this function brings distance from P to segment. - // Minimization of D(t) leads to simple quadratic equation that's - // solving is straightforward. - // - // Bonus of this method is witness point for free. - - float dist, t; - btVector3 d, a; - - // direction of segment - btMprVec3Sub2(&d, b, x0); - - // precompute vector from P to x0 - btMprVec3Sub2(&a, x0, P); - - t = -1.f * btMprVec3Dot(&a, &d); - t /= btMprVec3Len2(&d); - - if (t < 0.f || btMprIsZero(t)){ - dist = btMprVec3Dist2(x0, P); - if (witness) - btMprVec3Copy(witness, x0); - }else if (t > 1.f || btMprEq(t, 1.f)){ - dist = btMprVec3Dist2(b, P); - if (witness) - btMprVec3Copy(witness, b); - }else{ - if (witness){ - btMprVec3Copy(witness, &d); - btMprVec3Scale(witness, t); - btMprVec3Add(witness, x0); - dist = btMprVec3Dist2(witness, P); - }else{ - // recycling variables - btMprVec3Scale(&d, t); - btMprVec3Add(&d, &a); - dist = btMprVec3Len2(&d); - } - } - - return dist; -} - - - -inline float btMprVec3PointTriDist2(const btVector3 *P, - const btVector3 *x0, const btVector3 *B, - const btVector3 *C, - btVector3 *witness) -{ - // Computation comes from analytic expression for triangle (x0, B, C) - // T(s, t) = x0 + s.d1 + t.d2, where d1 = B - x0 and d2 = C - x0 and - // Then equation for distance is: - // D(s, t) = | T(s, t) - P |^2 - // This leads to minimization of quadratic function of two variables. - // The solution from is taken only if s is between 0 and 1, t is - // between 0 and 1 and t + s < 1, otherwise distance from segment is - // computed. - - btVector3 d1, d2, a; - float u, v, w, p, q, r; - float s, t, dist, dist2; - btVector3 witness2; - - btMprVec3Sub2(&d1, B, x0); - btMprVec3Sub2(&d2, C, x0); - btMprVec3Sub2(&a, x0, P); - - u = btMprVec3Dot(&a, &a); - v = btMprVec3Dot(&d1, &d1); - w = btMprVec3Dot(&d2, &d2); - p = btMprVec3Dot(&a, &d1); - q = btMprVec3Dot(&a, &d2); - r = btMprVec3Dot(&d1, &d2); - - btScalar div = (w * v - r * r); - if (btMprIsZero(div)) - { - s=-1; - } else - { - s = (q * r - w * p) / div; - t = (-s * r - q) / w; - } - - if ((btMprIsZero(s) || s > 0.f) - && (btMprEq(s, 1.f) || s < 1.f) - && (btMprIsZero(t) || t > 0.f) - && (btMprEq(t, 1.f) || t < 1.f) - && (btMprEq(t + s, 1.f) || t + s < 1.f)){ - - if (witness){ - btMprVec3Scale(&d1, s); - btMprVec3Scale(&d2, t); - btMprVec3Copy(witness, x0); - btMprVec3Add(witness, &d1); - btMprVec3Add(witness, &d2); - - dist = btMprVec3Dist2(witness, P); - }else{ - dist = s * s * v; - dist += t * t * w; - dist += 2.f * s * t * r; - dist += 2.f * s * p; - dist += 2.f * t * q; - dist += u; - } - }else{ - dist = _btMprVec3PointSegmentDist2(P, x0, B, witness); - - dist2 = _btMprVec3PointSegmentDist2(P, x0, C, &witness2); - if (dist2 < dist){ - dist = dist2; - if (witness) - btMprVec3Copy(witness, &witness2); - } - - dist2 = _btMprVec3PointSegmentDist2(P, B, C, &witness2); - if (dist2 < dist){ - dist = dist2; - if (witness) - btMprVec3Copy(witness, &witness2); - } - } - - return dist; -} - -template -static void btFindPenetr(const btConvexTemplate& a, const btConvexTemplate& b, - const btMprCollisionDescription& colDesc, - btMprSimplex_t *portal, - float *depth, btVector3 *pdir, btVector3 *pos) -{ - btVector3 dir; - btMprSupport_t v4; - unsigned long iterations; - - btVector3 zero = btVector3(0,0,0); - btVector3* origin = &zero; - - - iterations = 1UL; - for (int i=0;i find penetration info - if (portalReachTolerance(portal, &v4, &dir) - || iterations ==BT_MPR_MAX_ITERATIONS) - { - *depth = btMprVec3PointTriDist2(origin,&btMprSimplexPoint(portal, 1)->v,&btMprSimplexPoint(portal, 2)->v,&btMprSimplexPoint(portal, 3)->v,pdir); - *depth = BT_MPR_SQRT(*depth); - - if (btMprIsZero((*pdir).x()) && btMprIsZero((*pdir).y()) && btMprIsZero((*pdir).z())) - { - - *pdir = dir; - } - btMprVec3Normalize(pdir); - - // barycentric coordinates: - btFindPos(portal, pos); - - - return; - } - - btExpandPortal(portal, &v4); - - iterations++; - } -} - -static void btFindPenetrTouch(btMprSimplex_t *portal,float *depth, btVector3 *dir, btVector3 *pos) -{ - // Touching contact on portal's v1 - so depth is zero and direction - // is unimportant and pos can be guessed - *depth = 0.f; - btVector3 zero = btVector3(0,0,0); - btVector3* origin = &zero; - - - btMprVec3Copy(dir, origin); -#ifdef MPR_AVERAGE_CONTACT_POSITIONS - btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v1); - btMprVec3Add(pos, &btMprSimplexPoint(portal, 1)->v2); - btMprVec3Scale(pos, 0.5); -#else - btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v2); -#endif -} - -static void btFindPenetrSegment(btMprSimplex_t *portal, - float *depth, btVector3 *dir, btVector3 *pos) -{ - - // Origin lies on v0-v1 segment. - // Depth is distance to v1, direction also and position must be - // computed -#ifdef MPR_AVERAGE_CONTACT_POSITIONS - btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v1); - btMprVec3Add(pos, &btMprSimplexPoint(portal, 1)->v2); - btMprVec3Scale(pos, 0.5f); -#else - btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v2); -#endif//MPR_AVERAGE_CONTACT_POSITIONS - - btMprVec3Copy(dir, &btMprSimplexPoint(portal, 1)->v); - *depth = BT_MPR_SQRT(btMprVec3Len2(dir)); - btMprVec3Normalize(dir); - - -} - - -template -inline int btMprPenetration( const btConvexTemplate& a, const btConvexTemplate& b, - const btMprCollisionDescription& colDesc, - float *depthOut, btVector3* dirOut, btVector3* posOut) -{ - - btMprSimplex_t portal; - - - // Phase 1: Portal discovery - int result = btDiscoverPortal(a,b,colDesc, &portal); - - - //sepAxis[pairIndex] = *pdir;//or -dir? - - switch (result) - { - case 0: - { - // Phase 2: Portal refinement - - result = btRefinePortal(a,b,colDesc, &portal); - if (result < 0) - return -1; - - // Phase 3. Penetration info - btFindPenetr(a,b,colDesc, &portal, depthOut, dirOut, posOut); - - - break; - } - case 1: - { - // Touching contact on portal's v1. - btFindPenetrTouch(&portal, depthOut, dirOut, posOut); - result=0; - break; - } - case 2: - { - - btFindPenetrSegment( &portal, depthOut, dirOut, posOut); - result=0; - break; - } - default: - { - //if (res < 0) - //{ - // Origin isn't inside portal - no collision. - result = -1; - //} - } - }; - - return result; -}; - - -template -inline int btComputeMprPenetration( const btConvexTemplate& a, const btConvexTemplate& b, const - btMprCollisionDescription& colDesc, btMprDistanceTemplate* distInfo) -{ - btVector3 dir,pos; - float depth; - - int res = btMprPenetration(a,b,colDesc,&depth, &dir, &pos); - if (res==0) - { - distInfo->m_distance = -depth; - distInfo->m_pointOnB = pos; - distInfo->m_normalBtoA = -dir; - distInfo->m_pointOnA = pos-distInfo->m_distance*dir; - return 0; - } - - return -1; -} - - - -#endif //BT_MPR_PENETRATION_H + +/*** + * --------------------------------- + * Copyright (c)2012 Daniel Fiser + * + * This file was ported from mpr.c file, part of libccd. + * The Minkoski Portal Refinement implementation was ported + * to OpenCL by Erwin Coumans for the Bullet 3 Physics library. + * The original MPR idea and implementation is by Gary Snethen + * in XenoCollide, see http://github.com/erwincoumans/xenocollide + * + * Distributed under the OSI-approved BSD License (the "License"); + * see . + * This software is distributed WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the License for more information. + */ + +///2014 Oct, Erwin Coumans, Use templates to avoid void* casts + +#ifndef BT_MPR_PENETRATION_H +#define BT_MPR_PENETRATION_H + +#define BT_DEBUG_MPR1 + +#include "LinearMath/btTransform.h" +#include "LinearMath/btAlignedObjectArray.h" + +//#define MPR_AVERAGE_CONTACT_POSITIONS + + +struct btMprCollisionDescription +{ + btVector3 m_firstDir; + int m_maxGjkIterations; + btScalar m_maximumDistanceSquared; + btScalar m_gjkRelError2; + + btMprCollisionDescription() + : m_firstDir(0,1,0), + m_maxGjkIterations(1000), + m_maximumDistanceSquared(1e30f), + m_gjkRelError2(1.0e-6) + { + } + virtual ~btMprCollisionDescription() + { + } +}; + +struct btMprDistanceInfo +{ + btVector3 m_pointOnA; + btVector3 m_pointOnB; + btVector3 m_normalBtoA; + btScalar m_distance; +}; + +#ifdef __cplusplus +#define BT_MPR_SQRT sqrtf +#else +#define BT_MPR_SQRT sqrt +#endif +#define BT_MPR_FMIN(x, y) ((x) < (y) ? (x) : (y)) +#define BT_MPR_FABS fabs + +#define BT_MPR_TOLERANCE 1E-6f +#define BT_MPR_MAX_ITERATIONS 1000 + +struct _btMprSupport_t +{ + btVector3 v; //!< Support point in minkowski sum + btVector3 v1; //!< Support point in obj1 + btVector3 v2; //!< Support point in obj2 +}; +typedef struct _btMprSupport_t btMprSupport_t; + +struct _btMprSimplex_t +{ + btMprSupport_t ps[4]; + int last; //!< index of last added point +}; +typedef struct _btMprSimplex_t btMprSimplex_t; + +inline btMprSupport_t* btMprSimplexPointW(btMprSimplex_t *s, int idx) +{ + return &s->ps[idx]; +} + +inline void btMprSimplexSetSize(btMprSimplex_t *s, int size) +{ + s->last = size - 1; +} + +#ifdef DEBUG_MPR +inline void btPrintPortalVertex(_btMprSimplex_t* portal, int index) +{ + printf("portal[%d].v = %f,%f,%f, v1=%f,%f,%f, v2=%f,%f,%f\n", index, portal->ps[index].v.x(),portal->ps[index].v.y(),portal->ps[index].v.z(), + portal->ps[index].v1.x(),portal->ps[index].v1.y(),portal->ps[index].v1.z(), + portal->ps[index].v2.x(),portal->ps[index].v2.y(),portal->ps[index].v2.z()); +} +#endif //DEBUG_MPR + + + + +inline int btMprSimplexSize(const btMprSimplex_t *s) +{ + return s->last + 1; +} + + +inline const btMprSupport_t* btMprSimplexPoint(const btMprSimplex_t* s, int idx) +{ + // here is no check on boundaries + return &s->ps[idx]; +} + +inline void btMprSupportCopy(btMprSupport_t *d, const btMprSupport_t *s) +{ + *d = *s; +} + +inline void btMprSimplexSet(btMprSimplex_t *s, size_t pos, const btMprSupport_t *a) +{ + btMprSupportCopy(s->ps + pos, a); +} + + +inline void btMprSimplexSwap(btMprSimplex_t *s, size_t pos1, size_t pos2) +{ + btMprSupport_t supp; + + btMprSupportCopy(&supp, &s->ps[pos1]); + btMprSupportCopy(&s->ps[pos1], &s->ps[pos2]); + btMprSupportCopy(&s->ps[pos2], &supp); +} + + +inline int btMprIsZero(float val) +{ + return BT_MPR_FABS(val) < FLT_EPSILON; +} + + + +inline int btMprEq(float _a, float _b) +{ + float ab; + float a, b; + + ab = BT_MPR_FABS(_a - _b); + if (BT_MPR_FABS(ab) < FLT_EPSILON) + return 1; + + a = BT_MPR_FABS(_a); + b = BT_MPR_FABS(_b); + if (b > a){ + return ab < FLT_EPSILON * b; + }else{ + return ab < FLT_EPSILON * a; + } +} + + +inline int btMprVec3Eq(const btVector3* a, const btVector3 *b) +{ + return btMprEq((*a).x(), (*b).x()) + && btMprEq((*a).y(), (*b).y()) + && btMprEq((*a).z(), (*b).z()); +} + + + + + + + + + + + +template +inline void btFindOrigin(const btConvexTemplate& a, const btConvexTemplate& b, const btMprCollisionDescription& colDesc,btMprSupport_t *center) +{ + + center->v1 = a.getObjectCenterInWorld(); + center->v2 = b.getObjectCenterInWorld(); + center->v = center->v1 - center->v2; +} + +inline void btMprVec3Set(btVector3 *v, float x, float y, float z) +{ + v->setValue(x,y,z); +} + +inline void btMprVec3Add(btVector3 *v, const btVector3 *w) +{ + *v += *w; +} + +inline void btMprVec3Copy(btVector3 *v, const btVector3 *w) +{ + *v = *w; +} + +inline void btMprVec3Scale(btVector3 *d, float k) +{ + *d *= k; +} + +inline float btMprVec3Dot(const btVector3 *a, const btVector3 *b) +{ + float dot; + + dot = btDot(*a,*b); + return dot; +} + + +inline float btMprVec3Len2(const btVector3 *v) +{ + return btMprVec3Dot(v, v); +} + +inline void btMprVec3Normalize(btVector3 *d) +{ + float k = 1.f / BT_MPR_SQRT(btMprVec3Len2(d)); + btMprVec3Scale(d, k); +} + +inline void btMprVec3Cross(btVector3 *d, const btVector3 *a, const btVector3 *b) +{ + *d = btCross(*a,*b); + +} + + +inline void btMprVec3Sub2(btVector3 *d, const btVector3 *v, const btVector3 *w) +{ + *d = *v - *w; +} + +inline void btPortalDir(const btMprSimplex_t *portal, btVector3 *dir) +{ + btVector3 v2v1, v3v1; + + btMprVec3Sub2(&v2v1, &btMprSimplexPoint(portal, 2)->v, + &btMprSimplexPoint(portal, 1)->v); + btMprVec3Sub2(&v3v1, &btMprSimplexPoint(portal, 3)->v, + &btMprSimplexPoint(portal, 1)->v); + btMprVec3Cross(dir, &v2v1, &v3v1); + btMprVec3Normalize(dir); +} + + +inline int portalEncapsulesOrigin(const btMprSimplex_t *portal, + const btVector3 *dir) +{ + float dot; + dot = btMprVec3Dot(dir, &btMprSimplexPoint(portal, 1)->v); + return btMprIsZero(dot) || dot > 0.f; +} + +inline int portalReachTolerance(const btMprSimplex_t *portal, + const btMprSupport_t *v4, + const btVector3 *dir) +{ + float dv1, dv2, dv3, dv4; + float dot1, dot2, dot3; + + // find the smallest dot product of dir and {v1-v4, v2-v4, v3-v4} + + dv1 = btMprVec3Dot(&btMprSimplexPoint(portal, 1)->v, dir); + dv2 = btMprVec3Dot(&btMprSimplexPoint(portal, 2)->v, dir); + dv3 = btMprVec3Dot(&btMprSimplexPoint(portal, 3)->v, dir); + dv4 = btMprVec3Dot(&v4->v, dir); + + dot1 = dv4 - dv1; + dot2 = dv4 - dv2; + dot3 = dv4 - dv3; + + dot1 = BT_MPR_FMIN(dot1, dot2); + dot1 = BT_MPR_FMIN(dot1, dot3); + + return btMprEq(dot1, BT_MPR_TOLERANCE) || dot1 < BT_MPR_TOLERANCE; +} + +inline int portalCanEncapsuleOrigin(const btMprSimplex_t *portal, + const btMprSupport_t *v4, + const btVector3 *dir) +{ + float dot; + dot = btMprVec3Dot(&v4->v, dir); + return btMprIsZero(dot) || dot > 0.f; +} + +inline void btExpandPortal(btMprSimplex_t *portal, + const btMprSupport_t *v4) +{ + float dot; + btVector3 v4v0; + + btMprVec3Cross(&v4v0, &v4->v, &btMprSimplexPoint(portal, 0)->v); + dot = btMprVec3Dot(&btMprSimplexPoint(portal, 1)->v, &v4v0); + if (dot > 0.f){ + dot = btMprVec3Dot(&btMprSimplexPoint(portal, 2)->v, &v4v0); + if (dot > 0.f){ + btMprSimplexSet(portal, 1, v4); + }else{ + btMprSimplexSet(portal, 3, v4); + } + }else{ + dot = btMprVec3Dot(&btMprSimplexPoint(portal, 3)->v, &v4v0); + if (dot > 0.f){ + btMprSimplexSet(portal, 2, v4); + }else{ + btMprSimplexSet(portal, 1, v4); + } + } +} +template +inline void btMprSupport(const btConvexTemplate& a, const btConvexTemplate& b, + const btMprCollisionDescription& colDesc, + const btVector3& dir, btMprSupport_t *supp) +{ + btVector3 seperatingAxisInA = dir* a.getWorldTransform().getBasis(); + btVector3 seperatingAxisInB = -dir* b.getWorldTransform().getBasis(); + + btVector3 pInA = a.getLocalSupportWithMargin(seperatingAxisInA); + btVector3 qInB = b.getLocalSupportWithMargin(seperatingAxisInB); + + supp->v1 = a.getWorldTransform()(pInA); + supp->v2 = b.getWorldTransform()(qInB); + supp->v = supp->v1 - supp->v2; +} + + +template +static int btDiscoverPortal(const btConvexTemplate& a, const btConvexTemplate& b, + const btMprCollisionDescription& colDesc, + btMprSimplex_t *portal) +{ + btVector3 dir, va, vb; + float dot; + int cont; + + + + // vertex 0 is center of portal + btFindOrigin(a,b,colDesc, btMprSimplexPointW(portal, 0)); + + + // vertex 0 is center of portal + btMprSimplexSetSize(portal, 1); + + + + btVector3 zero = btVector3(0,0,0); + btVector3* org = &zero; + + if (btMprVec3Eq(&btMprSimplexPoint(portal, 0)->v, org)){ + // Portal's center lies on origin (0,0,0) => we know that objects + // intersect but we would need to know penetration info. + // So move center little bit... + btMprVec3Set(&va, FLT_EPSILON * 10.f, 0.f, 0.f); + btMprVec3Add(&btMprSimplexPointW(portal, 0)->v, &va); + } + + + // vertex 1 = support in direction of origin + btMprVec3Copy(&dir, &btMprSimplexPoint(portal, 0)->v); + btMprVec3Scale(&dir, -1.f); + btMprVec3Normalize(&dir); + + + btMprSupport(a,b,colDesc, dir, btMprSimplexPointW(portal, 1)); + + btMprSimplexSetSize(portal, 2); + + // test if origin isn't outside of v1 + dot = btMprVec3Dot(&btMprSimplexPoint(portal, 1)->v, &dir); + + + if (btMprIsZero(dot) || dot < 0.f) + return -1; + + + // vertex 2 + btMprVec3Cross(&dir, &btMprSimplexPoint(portal, 0)->v, + &btMprSimplexPoint(portal, 1)->v); + if (btMprIsZero(btMprVec3Len2(&dir))){ + if (btMprVec3Eq(&btMprSimplexPoint(portal, 1)->v, org)){ + // origin lies on v1 + return 1; + }else{ + // origin lies on v0-v1 segment + return 2; + } + } + + btMprVec3Normalize(&dir); + btMprSupport(a,b,colDesc, dir, btMprSimplexPointW(portal, 2)); + + + + dot = btMprVec3Dot(&btMprSimplexPoint(portal, 2)->v, &dir); + if (btMprIsZero(dot) || dot < 0.f) + return -1; + + btMprSimplexSetSize(portal, 3); + + // vertex 3 direction + btMprVec3Sub2(&va, &btMprSimplexPoint(portal, 1)->v, + &btMprSimplexPoint(portal, 0)->v); + btMprVec3Sub2(&vb, &btMprSimplexPoint(portal, 2)->v, + &btMprSimplexPoint(portal, 0)->v); + btMprVec3Cross(&dir, &va, &vb); + btMprVec3Normalize(&dir); + + // it is better to form portal faces to be oriented "outside" origin + dot = btMprVec3Dot(&dir, &btMprSimplexPoint(portal, 0)->v); + if (dot > 0.f){ + btMprSimplexSwap(portal, 1, 2); + btMprVec3Scale(&dir, -1.f); + } + + while (btMprSimplexSize(portal) < 4){ + btMprSupport(a,b,colDesc, dir, btMprSimplexPointW(portal, 3)); + + dot = btMprVec3Dot(&btMprSimplexPoint(portal, 3)->v, &dir); + if (btMprIsZero(dot) || dot < 0.f) + return -1; + + cont = 0; + + // test if origin is outside (v1, v0, v3) - set v2 as v3 and + // continue + btMprVec3Cross(&va, &btMprSimplexPoint(portal, 1)->v, + &btMprSimplexPoint(portal, 3)->v); + dot = btMprVec3Dot(&va, &btMprSimplexPoint(portal, 0)->v); + if (dot < 0.f && !btMprIsZero(dot)){ + btMprSimplexSet(portal, 2, btMprSimplexPoint(portal, 3)); + cont = 1; + } + + if (!cont){ + // test if origin is outside (v3, v0, v2) - set v1 as v3 and + // continue + btMprVec3Cross(&va, &btMprSimplexPoint(portal, 3)->v, + &btMprSimplexPoint(portal, 2)->v); + dot = btMprVec3Dot(&va, &btMprSimplexPoint(portal, 0)->v); + if (dot < 0.f && !btMprIsZero(dot)){ + btMprSimplexSet(portal, 1, btMprSimplexPoint(portal, 3)); + cont = 1; + } + } + + if (cont){ + btMprVec3Sub2(&va, &btMprSimplexPoint(portal, 1)->v, + &btMprSimplexPoint(portal, 0)->v); + btMprVec3Sub2(&vb, &btMprSimplexPoint(portal, 2)->v, + &btMprSimplexPoint(portal, 0)->v); + btMprVec3Cross(&dir, &va, &vb); + btMprVec3Normalize(&dir); + }else{ + btMprSimplexSetSize(portal, 4); + } + } + + return 0; +} + +template +static int btRefinePortal(const btConvexTemplate& a, const btConvexTemplate& b,const btMprCollisionDescription& colDesc, + btMprSimplex_t *portal) +{ + btVector3 dir; + btMprSupport_t v4; + + for (int i=0;iv, + &btMprSimplexPoint(portal, 2)->v); + b[0] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 3)->v); + + btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 3)->v, + &btMprSimplexPoint(portal, 2)->v); + b[1] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 0)->v); + + btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 0)->v, + &btMprSimplexPoint(portal, 1)->v); + b[2] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 3)->v); + + btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 2)->v, + &btMprSimplexPoint(portal, 1)->v); + b[3] = btMprVec3Dot(&vec, &btMprSimplexPoint(portal, 0)->v); + + sum = b[0] + b[1] + b[2] + b[3]; + + if (btMprIsZero(sum) || sum < 0.f){ + b[0] = 0.f; + + btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 2)->v, + &btMprSimplexPoint(portal, 3)->v); + b[1] = btMprVec3Dot(&vec, &dir); + btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 3)->v, + &btMprSimplexPoint(portal, 1)->v); + b[2] = btMprVec3Dot(&vec, &dir); + btMprVec3Cross(&vec, &btMprSimplexPoint(portal, 1)->v, + &btMprSimplexPoint(portal, 2)->v); + b[3] = btMprVec3Dot(&vec, &dir); + + sum = b[1] + b[2] + b[3]; + } + + inv = 1.f / sum; + + btMprVec3Copy(&p1, origin); + btMprVec3Copy(&p2, origin); + for (i = 0; i < 4; i++){ + btMprVec3Copy(&vec, &btMprSimplexPoint(portal, i)->v1); + btMprVec3Scale(&vec, b[i]); + btMprVec3Add(&p1, &vec); + + btMprVec3Copy(&vec, &btMprSimplexPoint(portal, i)->v2); + btMprVec3Scale(&vec, b[i]); + btMprVec3Add(&p2, &vec); + } + btMprVec3Scale(&p1, inv); + btMprVec3Scale(&p2, inv); +#ifdef MPR_AVERAGE_CONTACT_POSITIONS + btMprVec3Copy(pos, &p1); + btMprVec3Add(pos, &p2); + btMprVec3Scale(pos, 0.5); +#else + btMprVec3Copy(pos, &p2); +#endif//MPR_AVERAGE_CONTACT_POSITIONS +} + +inline float btMprVec3Dist2(const btVector3 *a, const btVector3 *b) +{ + btVector3 ab; + btMprVec3Sub2(&ab, a, b); + return btMprVec3Len2(&ab); +} + +inline float _btMprVec3PointSegmentDist2(const btVector3 *P, + const btVector3 *x0, + const btVector3 *b, + btVector3 *witness) +{ + // The computation comes from solving equation of segment: + // S(t) = x0 + t.d + // where - x0 is initial point of segment + // - d is direction of segment from x0 (|d| > 0) + // - t belongs to <0, 1> interval + // + // Than, distance from a segment to some point P can be expressed: + // D(t) = |x0 + t.d - P|^2 + // which is distance from any point on segment. Minimization + // of this function brings distance from P to segment. + // Minimization of D(t) leads to simple quadratic equation that's + // solving is straightforward. + // + // Bonus of this method is witness point for free. + + float dist, t; + btVector3 d, a; + + // direction of segment + btMprVec3Sub2(&d, b, x0); + + // precompute vector from P to x0 + btMprVec3Sub2(&a, x0, P); + + t = -1.f * btMprVec3Dot(&a, &d); + t /= btMprVec3Len2(&d); + + if (t < 0.f || btMprIsZero(t)){ + dist = btMprVec3Dist2(x0, P); + if (witness) + btMprVec3Copy(witness, x0); + }else if (t > 1.f || btMprEq(t, 1.f)){ + dist = btMprVec3Dist2(b, P); + if (witness) + btMprVec3Copy(witness, b); + }else{ + if (witness){ + btMprVec3Copy(witness, &d); + btMprVec3Scale(witness, t); + btMprVec3Add(witness, x0); + dist = btMprVec3Dist2(witness, P); + }else{ + // recycling variables + btMprVec3Scale(&d, t); + btMprVec3Add(&d, &a); + dist = btMprVec3Len2(&d); + } + } + + return dist; +} + + + +inline float btMprVec3PointTriDist2(const btVector3 *P, + const btVector3 *x0, const btVector3 *B, + const btVector3 *C, + btVector3 *witness) +{ + // Computation comes from analytic expression for triangle (x0, B, C) + // T(s, t) = x0 + s.d1 + t.d2, where d1 = B - x0 and d2 = C - x0 and + // Then equation for distance is: + // D(s, t) = | T(s, t) - P |^2 + // This leads to minimization of quadratic function of two variables. + // The solution from is taken only if s is between 0 and 1, t is + // between 0 and 1 and t + s < 1, otherwise distance from segment is + // computed. + + btVector3 d1, d2, a; + float u, v, w, p, q, r; + float s, t, dist, dist2; + btVector3 witness2; + + btMprVec3Sub2(&d1, B, x0); + btMprVec3Sub2(&d2, C, x0); + btMprVec3Sub2(&a, x0, P); + + u = btMprVec3Dot(&a, &a); + v = btMprVec3Dot(&d1, &d1); + w = btMprVec3Dot(&d2, &d2); + p = btMprVec3Dot(&a, &d1); + q = btMprVec3Dot(&a, &d2); + r = btMprVec3Dot(&d1, &d2); + + btScalar div = (w * v - r * r); + if (btMprIsZero(div)) + { + s=-1; + } else + { + s = (q * r - w * p) / div; + t = (-s * r - q) / w; + } + + if ((btMprIsZero(s) || s > 0.f) + && (btMprEq(s, 1.f) || s < 1.f) + && (btMprIsZero(t) || t > 0.f) + && (btMprEq(t, 1.f) || t < 1.f) + && (btMprEq(t + s, 1.f) || t + s < 1.f)){ + + if (witness){ + btMprVec3Scale(&d1, s); + btMprVec3Scale(&d2, t); + btMprVec3Copy(witness, x0); + btMprVec3Add(witness, &d1); + btMprVec3Add(witness, &d2); + + dist = btMprVec3Dist2(witness, P); + }else{ + dist = s * s * v; + dist += t * t * w; + dist += 2.f * s * t * r; + dist += 2.f * s * p; + dist += 2.f * t * q; + dist += u; + } + }else{ + dist = _btMprVec3PointSegmentDist2(P, x0, B, witness); + + dist2 = _btMprVec3PointSegmentDist2(P, x0, C, &witness2); + if (dist2 < dist){ + dist = dist2; + if (witness) + btMprVec3Copy(witness, &witness2); + } + + dist2 = _btMprVec3PointSegmentDist2(P, B, C, &witness2); + if (dist2 < dist){ + dist = dist2; + if (witness) + btMprVec3Copy(witness, &witness2); + } + } + + return dist; +} + +template +static void btFindPenetr(const btConvexTemplate& a, const btConvexTemplate& b, + const btMprCollisionDescription& colDesc, + btMprSimplex_t *portal, + float *depth, btVector3 *pdir, btVector3 *pos) +{ + btVector3 dir; + btMprSupport_t v4; + unsigned long iterations; + + btVector3 zero = btVector3(0,0,0); + btVector3* origin = &zero; + + + iterations = 1UL; + for (int i=0;i find penetration info + if (portalReachTolerance(portal, &v4, &dir) + || iterations ==BT_MPR_MAX_ITERATIONS) + { + *depth = btMprVec3PointTriDist2(origin,&btMprSimplexPoint(portal, 1)->v,&btMprSimplexPoint(portal, 2)->v,&btMprSimplexPoint(portal, 3)->v,pdir); + *depth = BT_MPR_SQRT(*depth); + + if (btMprIsZero((*pdir).x()) && btMprIsZero((*pdir).y()) && btMprIsZero((*pdir).z())) + { + + *pdir = dir; + } + btMprVec3Normalize(pdir); + + // barycentric coordinates: + btFindPos(portal, pos); + + + return; + } + + btExpandPortal(portal, &v4); + + iterations++; + } +} + +static void btFindPenetrTouch(btMprSimplex_t *portal,float *depth, btVector3 *dir, btVector3 *pos) +{ + // Touching contact on portal's v1 - so depth is zero and direction + // is unimportant and pos can be guessed + *depth = 0.f; + btVector3 zero = btVector3(0,0,0); + btVector3* origin = &zero; + + + btMprVec3Copy(dir, origin); +#ifdef MPR_AVERAGE_CONTACT_POSITIONS + btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v1); + btMprVec3Add(pos, &btMprSimplexPoint(portal, 1)->v2); + btMprVec3Scale(pos, 0.5); +#else + btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v2); +#endif +} + +static void btFindPenetrSegment(btMprSimplex_t *portal, + float *depth, btVector3 *dir, btVector3 *pos) +{ + + // Origin lies on v0-v1 segment. + // Depth is distance to v1, direction also and position must be + // computed +#ifdef MPR_AVERAGE_CONTACT_POSITIONS + btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v1); + btMprVec3Add(pos, &btMprSimplexPoint(portal, 1)->v2); + btMprVec3Scale(pos, 0.5f); +#else + btMprVec3Copy(pos, &btMprSimplexPoint(portal, 1)->v2); +#endif//MPR_AVERAGE_CONTACT_POSITIONS + + btMprVec3Copy(dir, &btMprSimplexPoint(portal, 1)->v); + *depth = BT_MPR_SQRT(btMprVec3Len2(dir)); + btMprVec3Normalize(dir); + + +} + + +template +inline int btMprPenetration( const btConvexTemplate& a, const btConvexTemplate& b, + const btMprCollisionDescription& colDesc, + float *depthOut, btVector3* dirOut, btVector3* posOut) +{ + + btMprSimplex_t portal; + + + // Phase 1: Portal discovery + int result = btDiscoverPortal(a,b,colDesc, &portal); + + + //sepAxis[pairIndex] = *pdir;//or -dir? + + switch (result) + { + case 0: + { + // Phase 2: Portal refinement + + result = btRefinePortal(a,b,colDesc, &portal); + if (result < 0) + return -1; + + // Phase 3. Penetration info + btFindPenetr(a,b,colDesc, &portal, depthOut, dirOut, posOut); + + + break; + } + case 1: + { + // Touching contact on portal's v1. + btFindPenetrTouch(&portal, depthOut, dirOut, posOut); + result=0; + break; + } + case 2: + { + + btFindPenetrSegment( &portal, depthOut, dirOut, posOut); + result=0; + break; + } + default: + { + //if (res < 0) + //{ + // Origin isn't inside portal - no collision. + result = -1; + //} + } + }; + + return result; +}; + + +template +inline int btComputeMprPenetration( const btConvexTemplate& a, const btConvexTemplate& b, const + btMprCollisionDescription& colDesc, btMprDistanceTemplate* distInfo) +{ + btVector3 dir,pos; + float depth; + + int res = btMprPenetration(a,b,colDesc,&depth, &dir, &pos); + if (res==0) + { + distInfo->m_distance = -depth; + distInfo->m_pointOnB = pos; + distInfo->m_normalBtoA = -dir; + distInfo->m_pointOnA = pos-distInfo->m_distance*dir; + return 0; + } + + return -1; +} + + + +#endif //BT_MPR_PENETRATION_H diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp similarity index 97% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp index 4d92e853d3fa..23aaece22b30 100644 --- a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp +++ b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp @@ -21,6 +21,8 @@ subject to the following restrictions: btScalar gContactBreakingThreshold = btScalar(0.02); ContactDestroyedCallback gContactDestroyedCallback = 0; ContactProcessedCallback gContactProcessedCallback = 0; +ContactStartedCallback gContactStartedCallback = 0; +ContactEndedCallback gContactEndedCallback = 0; ///gContactCalcArea3Points will approximate the convex hull area using 3 points ///when setting it to false, it will use 4 points to compute the area: it is more accurate but slower bool gContactCalcArea3Points = true; @@ -279,6 +281,7 @@ void btPersistentManifold::refreshContactPoints(const btTransform& trA,const btT removeContactPoint(i); } else { + //todo: friction anchor may require the contact to be around a bit longer //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; diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h similarity index 73% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h index 5026397f67fd..f872c8e1c9f3 100644 --- a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h +++ b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h @@ -28,10 +28,18 @@ struct btCollisionResult; ///maximum contact breaking and merging threshold extern btScalar gContactBreakingThreshold; +#ifndef SWIG +class btPersistentManifold; + typedef bool (*ContactDestroyedCallback)(void* userPersistentData); typedef bool (*ContactProcessedCallback)(btManifoldPoint& cp,void* body0,void* body1); +typedef void (*ContactStartedCallback)(btPersistentManifold* const &manifold); +typedef void (*ContactEndedCallback)(btPersistentManifold* const &manifold); extern ContactDestroyedCallback gContactDestroyedCallback; extern ContactProcessedCallback gContactProcessedCallback; +extern ContactStartedCallback gContactStartedCallback; +extern ContactEndedCallback gContactEndedCallback; +#endif //SWIG //the enum starts at 1024 to avoid type conflicts with btTypedConstraint enum btContactManifoldTypes @@ -51,8 +59,8 @@ enum btContactManifoldTypes ///note that some pairs of objects might have more then one contact manifold. -ATTRIBUTE_ALIGNED128( class) btPersistentManifold : public btTypedObject -//ATTRIBUTE_ALIGNED16( class) btPersistentManifold : public btTypedObject +//ATTRIBUTE_ALIGNED128( class) btPersistentManifold : public btTypedObject +ATTRIBUTE_ALIGNED16( class) btPersistentManifold : public btTypedObject { btManifoldPoint m_pointCache[MANIFOLD_CACHE_SIZE]; @@ -163,7 +171,7 @@ ATTRIBUTE_ALIGNED128( class) btPersistentManifold : public btTypedObject //get rid of duplicated userPersistentData pointer m_pointCache[lastUsedIndex].m_userPersistentData = 0; m_pointCache[lastUsedIndex].m_appliedImpulse = 0.f; - m_pointCache[lastUsedIndex].m_lateralFrictionInitialized = false; + m_pointCache[lastUsedIndex].m_contactPointFlags = 0; m_pointCache[lastUsedIndex].m_appliedImpulseLateral1 = 0.f; m_pointCache[lastUsedIndex].m_appliedImpulseLateral2 = 0.f; m_pointCache[lastUsedIndex].m_lifeTime = 0; @@ -171,41 +179,60 @@ ATTRIBUTE_ALIGNED128( class) btPersistentManifold : public btTypedObject btAssert(m_pointCache[lastUsedIndex].m_userPersistentData==0); m_cachedPoints--; + + if (gContactEndedCallback && m_cachedPoints == 0) + { + gContactEndedCallback(this); + } } - void replaceContactPoint(const btManifoldPoint& newPoint,int insertIndex) + void replaceContactPoint(const btManifoldPoint& newPoint, int insertIndex) { btAssert(validContactDistance(newPoint)); #define MAINTAIN_PERSISTENCY 1 #ifdef MAINTAIN_PERSISTENCY - int lifeTime = m_pointCache[insertIndex].getLifeTime(); - btScalar appliedImpulse = m_pointCache[insertIndex].m_appliedImpulse; - btScalar appliedLateralImpulse1 = m_pointCache[insertIndex].m_appliedImpulseLateral1; - btScalar appliedLateralImpulse2 = m_pointCache[insertIndex].m_appliedImpulseLateral2; -// bool isLateralFrictionInitialized = m_pointCache[insertIndex].m_lateralFrictionInitialized; - - - - btAssert(lifeTime>=0); - void* cache = m_pointCache[insertIndex].m_userPersistentData; - - m_pointCache[insertIndex] = newPoint; + int lifeTime = m_pointCache[insertIndex].getLifeTime(); + btScalar appliedImpulse = m_pointCache[insertIndex].m_appliedImpulse; + btScalar appliedLateralImpulse1 = m_pointCache[insertIndex].m_appliedImpulseLateral1; + btScalar appliedLateralImpulse2 = m_pointCache[insertIndex].m_appliedImpulseLateral2; + + bool replacePoint = true; + ///we keep existing contact points for friction anchors + ///if the friction force is within the Coulomb friction cone + if (newPoint.m_contactPointFlags & BT_CONTACT_FLAG_FRICTION_ANCHOR) + { + // printf("appliedImpulse=%f\n", appliedImpulse); + // printf("appliedLateralImpulse1=%f\n", appliedLateralImpulse1); + // printf("appliedLateralImpulse2=%f\n", appliedLateralImpulse2); + // printf("mu = %f\n", m_pointCache[insertIndex].m_combinedFriction); + btScalar mu = m_pointCache[insertIndex].m_combinedFriction; + btScalar eps = 0; //we could allow to enlarge or shrink the tolerance to check against the friction cone a bit, say 1e-7 + btScalar a = appliedLateralImpulse1 * appliedLateralImpulse1 + appliedLateralImpulse2 * appliedLateralImpulse2; + btScalar b = eps + mu * appliedImpulse; + b = b * b; + replacePoint = (a) > (b); + } - m_pointCache[insertIndex].m_userPersistentData = cache; - m_pointCache[insertIndex].m_appliedImpulse = appliedImpulse; - m_pointCache[insertIndex].m_appliedImpulseLateral1 = appliedLateralImpulse1; - m_pointCache[insertIndex].m_appliedImpulseLateral2 = appliedLateralImpulse2; - + if (replacePoint) + { + btAssert(lifeTime >= 0); + void* cache = m_pointCache[insertIndex].m_userPersistentData; + + m_pointCache[insertIndex] = newPoint; + m_pointCache[insertIndex].m_userPersistentData = cache; + m_pointCache[insertIndex].m_appliedImpulse = appliedImpulse; + m_pointCache[insertIndex].m_appliedImpulseLateral1 = appliedLateralImpulse1; + m_pointCache[insertIndex].m_appliedImpulseLateral2 = appliedLateralImpulse2; + } 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(); @@ -221,6 +248,11 @@ ATTRIBUTE_ALIGNED128( class) btPersistentManifold : public btTypedObject { clearUserCache(m_pointCache[i]); } + + if (gContactEndedCallback && m_cachedPoints) + { + gContactEndedCallback(this); + } m_cachedPoints = 0; } diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPointCollector.h b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btPointCollector.h similarity index 100% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPointCollector.h rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btPointCollector.h diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp similarity index 97% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp index d5f4a964bf36..ea380bc5f1b1 100644 --- a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp +++ b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.cpp @@ -411,9 +411,9 @@ bool btPolyhedralContactClipping::findSeparatingAxis( const btConvexPolyhedron& return true; } -void btPolyhedralContactClipping::clipFaceAgainstHull(const btVector3& separatingNormal, const btConvexPolyhedron& hullA, const btTransform& transA, btVertexArray& worldVertsB1, const btScalar minDist, btScalar maxDist,btDiscreteCollisionDetectorInterface::Result& resultOut) +void btPolyhedralContactClipping::clipFaceAgainstHull(const btVector3& separatingNormal, const btConvexPolyhedron& hullA, const btTransform& transA, btVertexArray& worldVertsB1,btVertexArray& worldVertsB2, const btScalar minDist, btScalar maxDist,btDiscreteCollisionDetectorInterface::Result& resultOut) { - btVertexArray worldVertsB2; + worldVertsB2.resize(0); btVertexArray* pVtxIn = &worldVertsB1; btVertexArray* pVtxOut = &worldVertsB2; pVtxOut->reserve(pVtxIn->size()); @@ -527,7 +527,7 @@ void btPolyhedralContactClipping::clipFaceAgainstHull(const btVector3& separatin -void btPolyhedralContactClipping::clipHullAgainstHull(const btVector3& separatingNormal1, const btConvexPolyhedron& hullA, const btConvexPolyhedron& hullB, const btTransform& transA,const btTransform& transB, const btScalar minDist, btScalar maxDist,btDiscreteCollisionDetectorInterface::Result& resultOut) +void btPolyhedralContactClipping::clipHullAgainstHull(const btVector3& separatingNormal1, const btConvexPolyhedron& hullA, const btConvexPolyhedron& hullB, const btTransform& transA,const btTransform& transB, const btScalar minDist, btScalar maxDist,btVertexArray& worldVertsB1,btVertexArray& worldVertsB2,btDiscreteCollisionDetectorInterface::Result& resultOut) { btVector3 separatingNormal = separatingNormal1.normalized(); @@ -552,7 +552,7 @@ void btPolyhedralContactClipping::clipHullAgainstHull(const btVector3& separatin } } } - btVertexArray worldVertsB1; + worldVertsB1.resize(0); { const btFace& polyB = hullB.m_faces[closestFaceB]; const int numVertices = polyB.m_indices.size(); @@ -565,6 +565,6 @@ void btPolyhedralContactClipping::clipHullAgainstHull(const btVector3& separatin if (closestFaceB>=0) - clipFaceAgainstHull(separatingNormal, hullA, transA,worldVertsB1, minDist, maxDist,resultOut); + clipFaceAgainstHull(separatingNormal, hullA, transA,worldVertsB1, worldVertsB2,minDist, maxDist,resultOut); } diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.h b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.h similarity index 79% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.h rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.h index b87bd4f3245a..30e3db687b48 100644 --- a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.h +++ b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.h @@ -32,8 +32,11 @@ typedef btAlignedObjectArray btVertexArray; // Clips a face to the back of a plane struct btPolyhedralContactClipping { - static void clipHullAgainstHull(const btVector3& separatingNormal, const btConvexPolyhedron& hullA, const btConvexPolyhedron& hullB, const btTransform& transA,const btTransform& transB, const btScalar minDist, btScalar maxDist, btDiscreteCollisionDetectorInterface::Result& resultOut); - static void clipFaceAgainstHull(const btVector3& separatingNormal, const btConvexPolyhedron& hullA, const btTransform& transA, btVertexArray& worldVertsB1, const btScalar minDist, btScalar maxDist,btDiscreteCollisionDetectorInterface::Result& resultOut); + + static void clipHullAgainstHull(const btVector3& separatingNormal1, const btConvexPolyhedron& hullA, const btConvexPolyhedron& hullB, const btTransform& transA,const btTransform& transB, const btScalar minDist, btScalar maxDist,btVertexArray& worldVertsB1,btVertexArray& worldVertsB2,btDiscreteCollisionDetectorInterface::Result& resultOut); + + static void clipFaceAgainstHull(const btVector3& separatingNormal, const btConvexPolyhedron& hullA, const btTransform& transA, btVertexArray& worldVertsB1,btVertexArray& worldVertsB2, const btScalar minDist, btScalar maxDist,btDiscreteCollisionDetectorInterface::Result& resultOut); + static bool findSeparatingAxis( const btConvexPolyhedron& hullA, const btConvexPolyhedron& hullB, const btTransform& transA,const btTransform& transB, btVector3& sep, btDiscreteCollisionDetectorInterface::Result& resultOut); diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h similarity index 100% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h similarity index 100% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h similarity index 100% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp similarity index 100% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp diff --git a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h similarity index 97% rename from extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h rename to extern/bullet/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h index 2f389e27e3fd..80fd490f4e15 100644 --- a/extern/bullet2/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h +++ b/extern/bullet/src/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h @@ -26,8 +26,12 @@ subject to the following restrictions: ///disable next define, or use defaultCollisionConfiguration->getSimplexSolver()->setEqualVertexThreshold(0.f) to disable/configure #define BT_USE_EQUAL_VERTEX_THRESHOLD -#define VORONOI_DEFAULT_EQUAL_VERTEX_THRESHOLD 0.0001f +#ifdef BT_USE_DOUBLE_PRECISION +#define VORONOI_DEFAULT_EQUAL_VERTEX_THRESHOLD 1e-12f +#else +#define VORONOI_DEFAULT_EQUAL_VERTEX_THRESHOLD 0.0001f +#endif//BT_USE_DOUBLE_PRECISION struct btUsageBitfield{ btUsageBitfield() diff --git a/extern/bullet/src/BulletCollision/premake4.lua b/extern/bullet/src/BulletCollision/premake4.lua new file mode 100644 index 000000000000..70407771d8e7 --- /dev/null +++ b/extern/bullet/src/BulletCollision/premake4.lua @@ -0,0 +1,20 @@ + project "BulletCollision" + + kind "StaticLib" + includedirs { + "..", + } + files { + "*.cpp", + "*.h", + "BroadphaseCollision/*.cpp", + "BroadphaseCollision/*.h", + "CollisionDispatch/*.cpp", + "CollisionDispatch/*.h", + "CollisionShapes/*.cpp", + "CollisionShapes/*.h", + "Gimpact/*.cpp", + "Gimpact/*.h", + "NarrowPhaseCollision/*.cpp", + "NarrowPhaseCollision/*.h", + } diff --git a/extern/bullet/src/BulletDynamics/CMakeLists.txt b/extern/bullet/src/BulletDynamics/CMakeLists.txt new file mode 100644 index 000000000000..f8a6f34baf9a --- /dev/null +++ b/extern/bullet/src/BulletDynamics/CMakeLists.txt @@ -0,0 +1,170 @@ +INCLUDE_DIRECTORIES( ${BULLET_PHYSICS_SOURCE_DIR}/src ) + + + +SET(BulletDynamics_SRCS + Character/btKinematicCharacterController.cpp + ConstraintSolver/btConeTwistConstraint.cpp + ConstraintSolver/btContactConstraint.cpp + ConstraintSolver/btFixedConstraint.cpp + ConstraintSolver/btGearConstraint.cpp + ConstraintSolver/btGeneric6DofConstraint.cpp + ConstraintSolver/btGeneric6DofSpringConstraint.cpp + ConstraintSolver/btGeneric6DofSpring2Constraint.cpp + ConstraintSolver/btHinge2Constraint.cpp + ConstraintSolver/btHingeConstraint.cpp + ConstraintSolver/btPoint2PointConstraint.cpp + ConstraintSolver/btSequentialImpulseConstraintSolver.cpp + ConstraintSolver/btNNCGConstraintSolver.cpp + ConstraintSolver/btSliderConstraint.cpp + ConstraintSolver/btSolve2LinearConstraint.cpp + ConstraintSolver/btTypedConstraint.cpp + ConstraintSolver/btUniversalConstraint.cpp + Dynamics/btDiscreteDynamicsWorld.cpp + Dynamics/btDiscreteDynamicsWorldMt.cpp + Dynamics/btSimulationIslandManagerMt.cpp + Dynamics/btRigidBody.cpp + Dynamics/btSimpleDynamicsWorld.cpp +# Dynamics/Bullet-C-API.cpp + Vehicle/btRaycastVehicle.cpp + Vehicle/btWheelInfo.cpp + Featherstone/btMultiBody.cpp + Featherstone/btMultiBodyConstraintSolver.cpp + Featherstone/btMultiBodyDynamicsWorld.cpp + Featherstone/btMultiBodyJointLimitConstraint.cpp + Featherstone/btMultiBodyConstraint.cpp + Featherstone/btMultiBodyPoint2Point.cpp + Featherstone/btMultiBodyFixedConstraint.cpp + Featherstone/btMultiBodySliderConstraint.cpp + Featherstone/btMultiBodyJointMotor.cpp + Featherstone/btMultiBodyGearConstraint.cpp + MLCPSolvers/btDantzigLCP.cpp + MLCPSolvers/btMLCPSolver.cpp + MLCPSolvers/btLemkeAlgorithm.cpp +) + +SET(Root_HDRS + ../btBulletDynamicsCommon.h + ../btBulletCollisionCommon.h +) +SET(ConstraintSolver_HDRS + ConstraintSolver/btConeTwistConstraint.h + ConstraintSolver/btConstraintSolver.h + ConstraintSolver/btContactConstraint.h + ConstraintSolver/btContactSolverInfo.h + ConstraintSolver/btFixedConstraint.h + ConstraintSolver/btGearConstraint.h + ConstraintSolver/btGeneric6DofConstraint.h + ConstraintSolver/btGeneric6DofSpringConstraint.h + ConstraintSolver/btGeneric6DofSpring2Constraint.h + ConstraintSolver/btHinge2Constraint.h + ConstraintSolver/btHingeConstraint.h + ConstraintSolver/btJacobianEntry.h + ConstraintSolver/btPoint2PointConstraint.h + ConstraintSolver/btSequentialImpulseConstraintSolver.h + ConstraintSolver/btNNCGConstraintSolver.h + ConstraintSolver/btSliderConstraint.h + ConstraintSolver/btSolve2LinearConstraint.h + ConstraintSolver/btSolverBody.h + ConstraintSolver/btSolverConstraint.h + ConstraintSolver/btTypedConstraint.h + ConstraintSolver/btUniversalConstraint.h +) +SET(Dynamics_HDRS + Dynamics/btActionInterface.h + Dynamics/btDiscreteDynamicsWorld.h + Dynamics/btDiscreteDynamicsWorldMt.h + Dynamics/btSimulationIslandManagerMt.h + Dynamics/btDynamicsWorld.h + Dynamics/btSimpleDynamicsWorld.h + Dynamics/btRigidBody.h +) +SET(Vehicle_HDRS + Vehicle/btRaycastVehicle.h + Vehicle/btVehicleRaycaster.h + Vehicle/btWheelInfo.h +) + +SET(Featherstone_HDRS + Featherstone/btMultiBody.h + Featherstone/btMultiBodyConstraintSolver.h + Featherstone/btMultiBodyDynamicsWorld.h + Featherstone/btMultiBodyLink.h + Featherstone/btMultiBodyLinkCollider.h + Featherstone/btMultiBodySolverConstraint.h + Featherstone/btMultiBodyConstraint.h + Featherstone/btMultiBodyJointLimitConstraint.h + Featherstone/btMultiBodyConstraint.h + Featherstone/btMultiBodyPoint2Point.h + Featherstone/btMultiBodyFixedConstraint.h + Featherstone/btMultiBodySliderConstraint.h + Featherstone/btMultiBodyJointMotor.h + Featherstone/btMultiBodyGearConstraint.h +) + +SET(MLCPSolvers_HDRS + MLCPSolvers/btDantzigLCP.h + MLCPSolvers/btDantzigSolver.h + MLCPSolvers/btMLCPSolver.h + MLCPSolvers/btMLCPSolverInterface.h + MLCPSolvers/btPATHSolver.h + MLCPSolvers/btSolveProjectedGaussSeidel.h + MLCPSolvers/btLemkeSolver.h + MLCPSolvers/btLemkeAlgorithm.h +) + +SET(Character_HDRS + Character/btCharacterControllerInterface.h + Character/btKinematicCharacterController.h +) + + + +SET(BulletDynamics_HDRS + ${Root_HDRS} + ${ConstraintSolver_HDRS} + ${Dynamics_HDRS} + ${Vehicle_HDRS} + ${Character_HDRS} + ${Featherstone_HDRS} + ${MLCPSolvers_HDRS} +) + + +ADD_LIBRARY(BulletDynamics ${BulletDynamics_SRCS} ${BulletDynamics_HDRS}) +SET_TARGET_PROPERTIES(BulletDynamics PROPERTIES VERSION ${BULLET_VERSION}) +SET_TARGET_PROPERTIES(BulletDynamics PROPERTIES SOVERSION ${BULLET_VERSION}) +IF (BUILD_SHARED_LIBS) + TARGET_LINK_LIBRARIES(BulletDynamics BulletCollision LinearMath) +ENDIF (BUILD_SHARED_LIBS) + +IF (INSTALL_LIBS) + IF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) + IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS BulletDynamics DESTINATION .) + ELSE (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS BulletDynamics RUNTIME DESTINATION bin + LIBRARY DESTINATION lib${LIB_SUFFIX} + ARCHIVE DESTINATION lib${LIB_SUFFIX}) + INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.h" PATTERN +".svn" EXCLUDE PATTERN "CMakeFiles" EXCLUDE) + INSTALL(FILES ../btBulletDynamicsCommon.h +DESTINATION ${INCLUDE_INSTALL_DIR}/BulletDynamics) + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + SET_TARGET_PROPERTIES(BulletDynamics PROPERTIES FRAMEWORK true) + SET_TARGET_PROPERTIES(BulletDynamics PROPERTIES PUBLIC_HEADER "${Root_HDRS}") + # Have to list out sub-directories manually: + SET_PROPERTY(SOURCE ${ConstraintSolver_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/ConstraintSolver) + SET_PROPERTY(SOURCE ${Dynamics_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/Dynamics) + SET_PROPERTY(SOURCE ${Vehicle_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/Vehicle) + SET_PROPERTY(SOURCE ${Character_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/Character) + SET_PROPERTY(SOURCE ${Featherstone_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/Featherstone) + SET_PROPERTY(SOURCE ${MLCPSolvers_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/MLCPSolvers) + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) +ENDIF (INSTALL_LIBS) diff --git a/extern/bullet2/src/BulletDynamics/Character/btCharacterControllerInterface.h b/extern/bullet/src/BulletDynamics/Character/btCharacterControllerInterface.h similarity index 96% rename from extern/bullet2/src/BulletDynamics/Character/btCharacterControllerInterface.h rename to extern/bullet/src/BulletDynamics/Character/btCharacterControllerInterface.h index dffb06dfe94d..c3a3ac6c8ddf 100644 --- a/extern/bullet2/src/BulletDynamics/Character/btCharacterControllerInterface.h +++ b/extern/bullet/src/BulletDynamics/Character/btCharacterControllerInterface.h @@ -37,7 +37,7 @@ class btCharacterControllerInterface : public btActionInterface virtual void preStep ( btCollisionWorld* collisionWorld) = 0; virtual void playerStep (btCollisionWorld* collisionWorld, btScalar dt) = 0; virtual bool canJump () const = 0; - virtual void jump () = 0; + virtual void jump(const btVector3& dir = btVector3()) = 0; virtual bool onGround () const = 0; virtual void setUpInterpolate (bool value) = 0; diff --git a/extern/bullet2/src/BulletDynamics/Character/btKinematicCharacterController.cpp b/extern/bullet/src/BulletDynamics/Character/btKinematicCharacterController.cpp similarity index 62% rename from extern/bullet2/src/BulletDynamics/Character/btKinematicCharacterController.cpp rename to extern/bullet/src/BulletDynamics/Character/btKinematicCharacterController.cpp index 31faf1df5e3b..4a6ce16a4e2b 100644 --- a/extern/bullet2/src/BulletDynamics/Character/btKinematicCharacterController.cpp +++ b/extern/bullet/src/BulletDynamics/Character/btKinematicCharacterController.cpp @@ -132,37 +132,45 @@ btVector3 btKinematicCharacterController::perpindicularComponent (const btVector return direction - parallelComponent(direction, normal); } -btKinematicCharacterController::btKinematicCharacterController (btPairCachingGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, int upAxis) +btKinematicCharacterController::btKinematicCharacterController (btGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, const btVector3& up) { - m_upAxis = upAxis; - m_addedMargin = 0.02; - m_walkDirection.setValue(0,0,0); - m_useGhostObjectSweepTest = true; m_ghostObject = ghostObject; - m_stepHeight = stepHeight; + m_up.setValue(0.0f, 0.0f, 1.0f); + m_jumpAxis.setValue(0.0f, 0.0f, 1.0f); + m_addedMargin = 0.02; + m_walkDirection.setValue(0.0,0.0,0.0); + m_AngVel.setValue(0.0, 0.0, 0.0); + m_useGhostObjectSweepTest = true; m_turnAngle = btScalar(0.0); m_convexShape=convexShape; m_useWalkDirection = true; // use walk direction by default, legacy behavior m_velocityTimeInterval = 0.0; m_verticalVelocity = 0.0; m_verticalOffset = 0.0; - m_gravity = 9.8 * 3 ; // 3G acceleration. + m_gravity = 9.8 * 3.0 ; // 3G acceleration. m_fallSpeed = 55.0; // Terminal velocity of a sky diver in m/s. m_jumpSpeed = 10.0; // ? + m_SetjumpSpeed = m_jumpSpeed; m_wasOnGround = false; m_wasJumping = false; m_interpolateUp = true; - setMaxSlope(btRadians(45.0)); - m_currentStepOffset = 0; + m_currentStepOffset = 0.0; + m_maxPenetrationDepth = 0.2; full_drop = false; bounce_fix = false; + m_linearDamping = btScalar(0.0); + m_angularDamping = btScalar(0.0); + + setUp(up); + setStepHeight(stepHeight); + setMaxSlope(btRadians(45.0)); } btKinematicCharacterController::~btKinematicCharacterController () { } -btPairCachingGhostObject* btKinematicCharacterController::getGhostObject() +btGhostObject* btKinematicCharacterController::getGhostObject() { return m_ghostObject; } @@ -186,23 +194,32 @@ bool btKinematicCharacterController::recoverFromPenetration ( btCollisionWorld* bool penetration = false; - collisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_ghostObject->getOverlappingPairCache(), collisionWorld->getDispatchInfo(), collisionWorld->getDispatcher()); - m_currentPosition = m_ghostObject->getWorldTransform().getOrigin(); - - btScalar maxPen = btScalar(0.0); - for (int i = 0; i < m_ghostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++) + + btOverlappingPairCache *pairCache = collisionWorld->getPairCache(); + const unsigned int numPairs = m_ghostObject->getNumOverlappingObjects(); + +// btScalar maxPen = btScalar(0.0); + for (int i = 0; i < numPairs; i++) { - m_manifoldArray.resize(0); + btCollisionObject *obj0 = m_ghostObject; + btCollisionObject *obj1 = m_ghostObject->getOverlappingObject(i); + + btBroadphaseProxy *proxy0 = obj0->getBroadphaseHandle(); + btBroadphaseProxy *proxy1 = obj1->getBroadphaseHandle(); - btBroadphasePair* collisionPair = &m_ghostObject->getOverlappingPairCache()->getOverlappingPairArray()[i]; + btBroadphasePair* collisionPair = pairCache->findPair(proxy0, proxy1); - btCollisionObject* obj0 = static_cast(collisionPair->m_pProxy0->m_clientObject); - btCollisionObject* obj1 = static_cast(collisionPair->m_pProxy1->m_clientObject); + btAssert(collisionPair); if ((obj0 && !obj0->hasContactResponse()) || (obj1 && !obj1->hasContactResponse())) continue; - + + if (!needsCollision(obj0, obj1)) + continue; + + m_manifoldArray.resize(0); + if (collisionPair->m_algorithm) collisionPair->m_algorithm->getAllContactManifolds(m_manifoldArray); @@ -217,14 +234,15 @@ bool btKinematicCharacterController::recoverFromPenetration ( btCollisionWorld* btScalar dist = pt.getDistance(); - if (dist < 0.0) + if (dist < -m_maxPenetrationDepth) { - if (dist < maxPen) - { - maxPen = dist; - m_touchingNormal = pt.m_normalWorldOnB * directionSign;//?? + // TODO: cause problems on slopes, not sure if it is needed + //if (dist < maxPen) + //{ + // maxPen = dist; + // m_touchingNormal = pt.m_normalWorldOnB * directionSign;//?? - } + //} m_currentPosition += pt.m_normalWorldOnB * directionSign * dist * btScalar(0.2); penetration = true; } else { @@ -244,18 +262,28 @@ bool btKinematicCharacterController::recoverFromPenetration ( btCollisionWorld* void btKinematicCharacterController::stepUp ( btCollisionWorld* world) { + btScalar stepHeight = 0.0f; + if (m_verticalVelocity < 0.0) + stepHeight = m_stepHeight; + // phase 1: up btTransform start, end; - m_targetPosition = m_currentPosition + getUpAxisDirections()[m_upAxis] * (m_stepHeight + (m_verticalOffset > 0.f?m_verticalOffset:0.f)); start.setIdentity (); end.setIdentity (); /* FIXME: Handle penetration properly */ - start.setOrigin (m_currentPosition + getUpAxisDirections()[m_upAxis] * (m_convexShape->getMargin() + m_addedMargin)); + start.setOrigin(m_currentPosition); + + m_targetPosition = m_currentPosition + m_up * (stepHeight) + m_jumpAxis * ((m_verticalOffset > 0.f ? m_verticalOffset : 0.f)); + m_currentPosition = m_targetPosition; + end.setOrigin (m_targetPosition); - btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, -getUpAxisDirections()[m_upAxis], btScalar(0.7071)); + start.setRotation(m_currentOrientation); + end.setRotation(m_targetOrientation); + + btKinematicClosestNotMeConvexResultCallback callback(m_ghostObject, -m_up, m_maxSlopeCosine); callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; @@ -265,29 +293,61 @@ void btKinematicCharacterController::stepUp ( btCollisionWorld* world) } else { - world->convexSweepTest (m_convexShape, start, end, callback); + world->convexSweepTest(m_convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration); } - - if (callback.hasHit()) + + if (callback.hasHit() && m_ghostObject->hasContactResponse() && needsCollision(m_ghostObject, callback.m_hitCollisionObject)) { // Only modify the position if the hit was a slope and not a wall or ceiling. - if(callback.m_hitNormalWorld.dot(getUpAxisDirections()[m_upAxis]) > 0.0) + if (callback.m_hitNormalWorld.dot(m_up) > 0.0) { // we moved up only a fraction of the step height - m_currentStepOffset = m_stepHeight * callback.m_closestHitFraction; + m_currentStepOffset = stepHeight * callback.m_closestHitFraction; if (m_interpolateUp == true) m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction); else m_currentPosition = m_targetPosition; } - m_verticalVelocity = 0.0; - m_verticalOffset = 0.0; + + btTransform& xform = m_ghostObject->getWorldTransform(); + xform.setOrigin(m_currentPosition); + m_ghostObject->setWorldTransform(xform); + + // fix penetration if we hit a ceiling for example + int numPenetrationLoops = 0; + m_touchingContact = false; + while (recoverFromPenetration(world)) + { + numPenetrationLoops++; + m_touchingContact = true; + if (numPenetrationLoops > 4) + { + //printf("character could not recover from penetration = %d\n", numPenetrationLoops); + break; + } + } + m_targetPosition = m_ghostObject->getWorldTransform().getOrigin(); + m_currentPosition = m_targetPosition; + + if (m_verticalOffset > 0) + { + m_verticalOffset = 0.0; + m_verticalVelocity = 0.0; + m_currentStepOffset = m_stepHeight; + } } else { - m_currentStepOffset = m_stepHeight; + m_currentStepOffset = stepHeight; m_currentPosition = m_targetPosition; } } +bool btKinematicCharacterController::needsCollision(const btCollisionObject* body0, const btCollisionObject* body1) +{ + bool collides = (body0->getBroadphaseHandle()->m_collisionFilterGroup & body1->getBroadphaseHandle()->m_collisionFilterMask) != 0; + collides = collides && (body1->getBroadphaseHandle()->m_collisionFilterGroup & body0->getBroadphaseHandle()->m_collisionFilterMask); + return collides; +} + void btKinematicCharacterController::updateTargetPositionBasedOnCollision (const btVector3& hitNormal, btScalar tangentMag, btScalar normalMag) { btVector3 movementDirection = m_targetPosition - m_currentPosition; @@ -330,6 +390,7 @@ void btKinematicCharacterController::stepForwardAndStrafe ( btCollisionWorld* co // m_normalizedDirection[0],m_normalizedDirection[1],m_normalizedDirection[2]); // phase 2: forward and strafe btTransform start, end; + m_targetPosition = m_currentPosition + walkMove; start.setIdentity (); @@ -339,15 +400,6 @@ void btKinematicCharacterController::stepForwardAndStrafe ( btCollisionWorld* co btScalar distance2 = (m_currentPosition-m_targetPosition).length2(); // printf("distance2=%f\n",distance2); - if (m_touchingContact) - { - if (m_normalizedDirection.dot(m_touchingNormal) > btScalar(0.0)) - { - //interferes with step movement - //updateTargetPositionBasedOnCollision (m_touchingNormal); - } - } - int maxIter = 10; while (fraction > btScalar(0.01) && maxIter-- > 0) @@ -356,6 +408,9 @@ void btKinematicCharacterController::stepForwardAndStrafe ( btCollisionWorld* co end.setOrigin (m_targetPosition); btVector3 sweepDirNegative(m_currentPosition - m_targetPosition); + start.setRotation(m_currentOrientation); + end.setRotation(m_targetOrientation); + btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, sweepDirNegative, btScalar(0.0)); callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; @@ -364,21 +419,23 @@ void btKinematicCharacterController::stepForwardAndStrafe ( btCollisionWorld* co btScalar margin = m_convexShape->getMargin(); m_convexShape->setMargin(margin + m_addedMargin); - - if (m_useGhostObjectSweepTest) - { - m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); - } else + if (!(start == end)) { - collisionWorld->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); + if (m_useGhostObjectSweepTest) + { + m_ghostObject->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); + } + else + { + collisionWorld->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); + } } - m_convexShape->setMargin(margin); fraction -= callback.m_closestHitFraction; - if (callback.hasHit()) + if (callback.hasHit() && m_ghostObject->hasContactResponse() && needsCollision(m_ghostObject, callback.m_hitCollisionObject)) { // we moved only a fraction //btScalar hitDistance; @@ -403,14 +460,11 @@ void btKinematicCharacterController::stepForwardAndStrafe ( btCollisionWorld* co break; } - } else { - // we moved whole way - m_currentPosition = m_targetPosition; } - - // if (callback.m_closestHitFraction == 0.f) - // break; - + else + { + m_currentPosition = m_targetPosition; + } } } @@ -421,27 +475,30 @@ void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld // phase 3: down /*btScalar additionalDownStep = (m_wasOnGround && !onGround()) ? m_stepHeight : 0.0; - btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + additionalDownStep); + btVector3 step_drop = m_up * (m_currentStepOffset + additionalDownStep); btScalar downVelocity = (additionalDownStep == 0.0 && m_verticalVelocity<0.0?-m_verticalVelocity:0.0) * dt; - btVector3 gravity_drop = getUpAxisDirections()[m_upAxis] * downVelocity; + btVector3 gravity_drop = m_up * downVelocity; m_targetPosition -= (step_drop + gravity_drop);*/ btVector3 orig_position = m_targetPosition; btScalar downVelocity = (m_verticalVelocity<0.f?-m_verticalVelocity:0.f) * dt; + if (m_verticalVelocity > 0.0) + return; + if(downVelocity > 0.0 && downVelocity > m_fallSpeed && (m_wasOnGround || !m_wasJumping)) downVelocity = m_fallSpeed; - btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + downVelocity); + btVector3 step_drop = m_up * (m_currentStepOffset + downVelocity); m_targetPosition -= step_drop; - btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject, getUpAxisDirections()[m_upAxis], m_maxSlopeCosine); + btKinematicClosestNotMeConvexResultCallback callback(m_ghostObject, m_up, m_maxSlopeCosine); callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; - btKinematicClosestNotMeConvexResultCallback callback2 (m_ghostObject, getUpAxisDirections()[m_upAxis], m_maxSlopeCosine); + btKinematicClosestNotMeConvexResultCallback callback2(m_ghostObject, m_up, m_maxSlopeCosine); callback2.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; callback2.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; @@ -455,6 +512,9 @@ void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld start.setOrigin (m_currentPosition); end.setOrigin (m_targetPosition); + start.setRotation(m_currentOrientation); + end.setRotation(m_targetOrientation); + //set double test for 2x the step drop, to check for a large drop vs small drop end_double.setOrigin (m_targetPosition - step_drop); @@ -462,7 +522,7 @@ void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld { m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); - if (!callback.hasHit()) + if (!callback.hasHit() && m_ghostObject->hasContactResponse()) { //test a double fall height, to see if the character should interpolate it's fall (full) or not (partial) m_ghostObject->convexSweepTest (m_convexShape, start, end_double, callback2, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); @@ -471,30 +531,34 @@ void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld { collisionWorld->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); - if (!callback.hasHit()) - { - //test a double fall height, to see if the character should interpolate it's fall (large) or not (small) - collisionWorld->convexSweepTest (m_convexShape, start, end_double, callback2, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); - } + if (!callback.hasHit() && m_ghostObject->hasContactResponse()) + { + //test a double fall height, to see if the character should interpolate it's fall (large) or not (small) + collisionWorld->convexSweepTest (m_convexShape, start, end_double, callback2, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); + } } btScalar downVelocity2 = (m_verticalVelocity<0.f?-m_verticalVelocity:0.f) * dt; - bool has_hit = false; + bool has_hit; if (bounce_fix == true) - has_hit = callback.hasHit() || callback2.hasHit(); + has_hit = (callback.hasHit() || callback2.hasHit()) && m_ghostObject->hasContactResponse() && needsCollision(m_ghostObject, callback.m_hitCollisionObject); else - has_hit = callback2.hasHit(); + has_hit = callback2.hasHit() && m_ghostObject->hasContactResponse() && needsCollision(m_ghostObject, callback2.m_hitCollisionObject); - if(downVelocity2 > 0.0 && downVelocity2 < m_stepHeight && has_hit == true && runonce == false + btScalar stepHeight = 0.0f; + if (m_verticalVelocity < 0.0) + stepHeight = m_stepHeight; + + if (downVelocity2 > 0.0 && downVelocity2 < stepHeight && has_hit == true && runonce == false && (m_wasOnGround || !m_wasJumping)) { //redo the velocity calculation when falling a small amount, for fast stairs motion //for larger falls, use the smoother/slower interpolated movement by not touching the target position m_targetPosition = orig_position; - downVelocity = m_stepHeight; + downVelocity = stepHeight; - btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + downVelocity); + step_drop = m_up * (m_currentStepOffset + downVelocity); m_targetPosition -= step_drop; runonce = true; continue; //re-run previous tests @@ -502,10 +566,9 @@ void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld break; } - if (callback.hasHit() || runonce == true) + if ((m_ghostObject->hasContactResponse() && (callback.hasHit() && needsCollision(m_ghostObject, callback.m_hitCollisionObject))) || runonce == true) { // we dropped a fraction of the height -> hit floor - btScalar fraction = (m_currentPosition.getY() - callback.m_hitPointWorld.getY()) / 2; //printf("hitpoint: %g - pos %g\n", callback.m_hitPointWorld.getY(), m_currentPosition.getY()); @@ -513,10 +576,10 @@ void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld if (bounce_fix == true) { if (full_drop == true) - m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction); - else - //due to errors in the closestHitFraction variable when used with large polygons, calculate the hit fraction manually - m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, fraction); + m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction); + else + //due to errors in the closestHitFraction variable when used with large polygons, calculate the hit fraction manually + m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, fraction); } else m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction); @@ -528,7 +591,7 @@ void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld m_wasJumping = false; } else { // we dropped the full height - + full_drop = true; if (bounce_fix == true) @@ -538,7 +601,7 @@ void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld { m_targetPosition += step_drop; //undo previous target change downVelocity = m_fallSpeed; - step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + downVelocity); + step_drop = m_up * (m_currentStepOffset + downVelocity); m_targetPosition -= step_drop; } } @@ -579,21 +642,63 @@ btScalar timeInterval m_velocityTimeInterval += timeInterval; } -void btKinematicCharacterController::reset ( btCollisionWorld* collisionWorld ) +void btKinematicCharacterController::setAngularVelocity(const btVector3& velocity) { - m_verticalVelocity = 0.0; - m_verticalOffset = 0.0; - m_wasOnGround = false; - m_wasJumping = false; - m_walkDirection.setValue(0,0,0); - m_velocityTimeInterval = 0.0; + m_AngVel = velocity; +} - //clear pair cache - btHashedOverlappingPairCache *cache = m_ghostObject->getOverlappingPairCache(); - while (cache->getOverlappingPairArray().size() > 0) - { - cache->removeOverlappingPair(cache->getOverlappingPairArray()[0].m_pProxy0, cache->getOverlappingPairArray()[0].m_pProxy1, collisionWorld->getDispatcher()); - } +const btVector3& btKinematicCharacterController::getAngularVelocity() const +{ + return m_AngVel; +} + +void btKinematicCharacterController::setLinearVelocity(const btVector3& velocity) +{ + m_walkDirection = velocity; + + // HACK: if we are moving in the direction of the up, treat it as a jump :( + if (m_walkDirection.length2() > 0) + { + btVector3 w = velocity.normalized(); + btScalar c = w.dot(m_up); + if (c != 0) + { + //there is a component in walkdirection for vertical velocity + btVector3 upComponent = m_up * (btSin(SIMD_HALF_PI - btAcos(c)) * m_walkDirection.length()); + m_walkDirection -= upComponent; + m_verticalVelocity = (c < 0.0f ? -1 : 1) * upComponent.length(); + + if (c > 0.0f) + { + m_wasJumping = true; + m_jumpPosition = m_ghostObject->getWorldTransform().getOrigin(); + } + } + } + else + m_verticalVelocity = 0.0f; +} + +btVector3 btKinematicCharacterController::getLinearVelocity() const +{ + return m_walkDirection + (m_verticalVelocity * m_up); +} + +void btKinematicCharacterController::reset ( btCollisionWorld* collisionWorld ) +{ + m_verticalVelocity = 0.0; + m_verticalOffset = 0.0; + m_wasOnGround = false; + m_wasJumping = false; + m_walkDirection.setValue(0,0,0); + m_velocityTimeInterval = 0.0; + + //clear pair cache + /*btHashedOverlappingPairCache *cache = m_ghostObject->getOverlappingPairCache(); + while (cache->getOverlappingPairArray().size() > 0) + { + cache->removeOverlappingPair(cache->getOverlappingPairArray()[0].m_pProxy0, cache->getOverlappingPairArray()[0].m_pProxy1, collisionWorld->getDispatcher()); + }*/ } void btKinematicCharacterController::warp (const btVector3& origin) @@ -607,62 +712,99 @@ void btKinematicCharacterController::warp (const btVector3& origin) void btKinematicCharacterController::preStep ( btCollisionWorld* collisionWorld) { - - int numPenetrationLoops = 0; - m_touchingContact = false; - while (recoverFromPenetration (collisionWorld)) - { - numPenetrationLoops++; - m_touchingContact = true; - if (numPenetrationLoops > 4) - { - //printf("character could not recover from penetration = %d\n", numPenetrationLoops); - break; - } - } - m_currentPosition = m_ghostObject->getWorldTransform().getOrigin(); m_targetPosition = m_currentPosition; -// printf("m_targetPosition=%f,%f,%f\n",m_targetPosition[0],m_targetPosition[1],m_targetPosition[2]); - + m_currentOrientation = m_ghostObject->getWorldTransform().getRotation(); + m_targetOrientation = m_currentOrientation; +// printf("m_targetPosition=%f,%f,%f\n",m_targetPosition[0],m_targetPosition[1],m_targetPosition[2]); } -#include - void btKinematicCharacterController::playerStep ( btCollisionWorld* collisionWorld, btScalar dt) { // printf("playerStep(): "); // printf(" dt = %f", dt); + if (m_AngVel.length2() > 0.0f) + { + m_AngVel *= btPow(btScalar(1) - m_angularDamping, dt); + } + + // integrate for angular velocity + if (m_AngVel.length2() > 0.0f) + { + btTransform xform; + xform = m_ghostObject->getWorldTransform(); + + btQuaternion rot(m_AngVel.normalized(), m_AngVel.length() * dt); + + btQuaternion orn = rot * xform.getRotation(); + + xform.setRotation(orn); + m_ghostObject->setWorldTransform(xform); + + m_currentPosition = m_ghostObject->getWorldTransform().getOrigin(); + m_targetPosition = m_currentPosition; + m_currentOrientation = m_ghostObject->getWorldTransform().getRotation(); + m_targetOrientation = m_currentOrientation; + } + // quick check... - if (!m_useWalkDirection && (m_velocityTimeInterval <= 0.0 || m_walkDirection.fuzzyZero())) { + if (!m_useWalkDirection && (m_velocityTimeInterval <= 0.0)) { // printf("\n"); return; // no motion } m_wasOnGround = onGround(); + //btVector3 lvel = m_walkDirection; + //btScalar c = 0.0f; + + if (m_walkDirection.length2() > 0) + { + // apply damping + m_walkDirection *= btPow(btScalar(1) - m_linearDamping, dt); + } + + m_verticalVelocity *= btPow(btScalar(1) - m_linearDamping, dt); + // Update fall velocity. m_verticalVelocity -= m_gravity * dt; - if(m_verticalVelocity > 0.0 && m_verticalVelocity > m_jumpSpeed) + if (m_verticalVelocity > 0.0 && m_verticalVelocity > m_jumpSpeed) { m_verticalVelocity = m_jumpSpeed; } - if(m_verticalVelocity < 0.0 && btFabs(m_verticalVelocity) > btFabs(m_fallSpeed)) + if (m_verticalVelocity < 0.0 && btFabs(m_verticalVelocity) > btFabs(m_fallSpeed)) { m_verticalVelocity = -btFabs(m_fallSpeed); } m_verticalOffset = m_verticalVelocity * dt; - btTransform xform; - xform = m_ghostObject->getWorldTransform (); + xform = m_ghostObject->getWorldTransform(); // printf("walkDirection(%f,%f,%f)\n",walkDirection[0],walkDirection[1],walkDirection[2]); // printf("walkSpeed=%f\n",walkSpeed); - stepUp (collisionWorld); + stepUp(collisionWorld); + //todo: Experimenting with behavior of controller when it hits a ceiling.. + //bool hitUp = stepUp (collisionWorld); + //if (hitUp) + //{ + // m_verticalVelocity -= m_gravity * dt; + // if (m_verticalVelocity > 0.0 && m_verticalVelocity > m_jumpSpeed) + // { + // m_verticalVelocity = m_jumpSpeed; + // } + // if (m_verticalVelocity < 0.0 && btFabs(m_verticalVelocity) > btFabs(m_fallSpeed)) + // { + // m_verticalVelocity = -btFabs(m_fallSpeed); + // } + // m_verticalOffset = m_verticalVelocity * dt; + + // xform = m_ghostObject->getWorldTransform(); + //} + if (m_useWalkDirection) { stepForwardAndStrafe (collisionWorld, m_walkDirection); } else { @@ -682,10 +824,38 @@ void btKinematicCharacterController::playerStep ( btCollisionWorld* collisionWo } stepDown (collisionWorld, dt); + //todo: Experimenting with max jump height + //if (m_wasJumping) + //{ + // btScalar ds = m_currentPosition[m_upAxis] - m_jumpPosition[m_upAxis]; + // if (ds > m_maxJumpHeight) + // { + // // substract the overshoot + // m_currentPosition[m_upAxis] -= ds - m_maxJumpHeight; + + // // max height was reached, so potential energy is at max + // // and kinematic energy is 0, thus velocity is 0. + // if (m_verticalVelocity > 0.0) + // m_verticalVelocity = 0.0; + // } + //} // printf("\n"); xform.setOrigin (m_currentPosition); m_ghostObject->setWorldTransform (xform); + + int numPenetrationLoops = 0; + m_touchingContact = false; + while (recoverFromPenetration(collisionWorld)) + { + numPenetrationLoops++; + m_touchingContact = true; + if (numPenetrationLoops > 4) + { + //printf("character could not recover from penetration = %d\n", numPenetrationLoops); + break; + } + } } void btKinematicCharacterController::setFallSpeed (btScalar fallSpeed) @@ -696,6 +866,7 @@ void btKinematicCharacterController::setFallSpeed (btScalar fallSpeed) void btKinematicCharacterController::setJumpSpeed (btScalar jumpSpeed) { m_jumpSpeed = jumpSpeed; + m_SetjumpSpeed = m_jumpSpeed; } void btKinematicCharacterController::setMaxJumpHeight (btScalar maxJumpHeight) @@ -708,14 +879,16 @@ bool btKinematicCharacterController::canJump () const return onGround(); } -void btKinematicCharacterController::jump () +void btKinematicCharacterController::jump(const btVector3& v) { - if (!canJump()) - return; - + m_jumpSpeed = v.length2() == 0 ? m_SetjumpSpeed : v.length(); m_verticalVelocity = m_jumpSpeed; m_wasJumping = true; + m_jumpAxis = v.length2() == 0 ? m_up : v.normalized(); + + m_jumpPosition = m_ghostObject->getWorldTransform().getOrigin(); + #if 0 currently no jumping. btTransform xform; @@ -727,14 +900,16 @@ void btKinematicCharacterController::jump () #endif } -void btKinematicCharacterController::setGravity(btScalar gravity) +void btKinematicCharacterController::setGravity(const btVector3& gravity) { - m_gravity = gravity; + if (gravity.length2() > 0) setUpVector(-gravity); + + m_gravity = gravity.length(); } -btScalar btKinematicCharacterController::getGravity() const +btVector3 btKinematicCharacterController::getGravity() const { - return m_gravity; + return -m_gravity * m_up; } void btKinematicCharacterController::setMaxSlope(btScalar slopeRadians) @@ -748,11 +923,25 @@ btScalar btKinematicCharacterController::getMaxSlope() const return m_maxSlopeRadians; } +void btKinematicCharacterController::setMaxPenetrationDepth(btScalar d) +{ + m_maxPenetrationDepth = d; +} + +btScalar btKinematicCharacterController::getMaxPenetrationDepth() const +{ + return m_maxPenetrationDepth; +} + bool btKinematicCharacterController::onGround () const { - return m_verticalVelocity == 0.0 && m_verticalOffset == 0.0; + return (fabs(m_verticalVelocity) < SIMD_EPSILON) && (fabs(m_verticalOffset) < SIMD_EPSILON); } +void btKinematicCharacterController::setStepHeight(btScalar h) +{ + m_stepHeight = h; +} btVector3* btKinematicCharacterController::getUpAxisDirections() { @@ -769,3 +958,49 @@ void btKinematicCharacterController::setUpInterpolate(bool value) { m_interpolateUp = value; } + +void btKinematicCharacterController::setUp(const btVector3& up) +{ + if (up.length2() > 0 && m_gravity > 0.0f) + { + setGravity(-m_gravity * up.normalized()); + return; + } + + setUpVector(up); +} + +void btKinematicCharacterController::setUpVector(const btVector3& up) +{ + if (m_up == up) + return; + + btVector3 u = m_up; + + if (up.length2() > 0) + m_up = up.normalized(); + else + m_up = btVector3(0.0, 0.0, 0.0); + + if (!m_ghostObject) return; + btQuaternion rot = getRotation(m_up, u); + + //set orientation with new up + btTransform xform; + xform = m_ghostObject->getWorldTransform(); + btQuaternion orn = rot.inverse() * xform.getRotation(); + xform.setRotation(orn); + m_ghostObject->setWorldTransform(xform); +} + +btQuaternion btKinematicCharacterController::getRotation(btVector3& v0, btVector3& v1) const +{ + if (v0.length2() == 0.0f || v1.length2() == 0.0f) + { + btQuaternion q; + return q; + } + + return shortestArcQuatNormalize2(v0, v1); +} + diff --git a/extern/bullet2/src/BulletDynamics/Character/btKinematicCharacterController.h b/extern/bullet/src/BulletDynamics/Character/btKinematicCharacterController.h similarity index 75% rename from extern/bullet2/src/BulletDynamics/Character/btKinematicCharacterController.h rename to extern/bullet/src/BulletDynamics/Character/btKinematicCharacterController.h index add6f30a6872..2dd12eaa5f10 100644 --- a/extern/bullet2/src/BulletDynamics/Character/btKinematicCharacterController.h +++ b/extern/bullet/src/BulletDynamics/Character/btKinematicCharacterController.h @@ -29,7 +29,7 @@ class btConvexShape; class btRigidBody; class btCollisionWorld; class btCollisionDispatcher; -class btPairCachingGhostObject; +class btGhostObject; ///btKinematicCharacterController is an object that supports a sliding motion in a world. ///It uses a ghost object and convex sweep test to test for upcoming collisions. This is combined with discrete collision detection to recover from penetrations. @@ -40,13 +40,15 @@ ATTRIBUTE_ALIGNED16(class) btKinematicCharacterController : public btCharacterCo btScalar m_halfHeight; - btPairCachingGhostObject* m_ghostObject; + btGhostObject* m_ghostObject; btConvexShape* m_convexShape;//is also in m_ghostObject, but it needs to be convex, so we store it here to avoid upcast + btScalar m_maxPenetrationDepth; btScalar m_verticalVelocity; btScalar m_verticalOffset; btScalar m_fallSpeed; btScalar m_jumpSpeed; + btScalar m_SetjumpSpeed; btScalar m_maxJumpHeight; btScalar m_maxSlopeRadians; // Slope angle that is set (used for returning the exact value) btScalar m_maxSlopeCosine; // Cosine equivalent of m_maxSlopeRadians (calculated once when set, for optimization) @@ -61,24 +63,34 @@ ATTRIBUTE_ALIGNED16(class) btKinematicCharacterController : public btCharacterCo ///this is the desired walk direction, set by the user btVector3 m_walkDirection; btVector3 m_normalizedDirection; + btVector3 m_AngVel; + + btVector3 m_jumpPosition; //some internal variables btVector3 m_currentPosition; btScalar m_currentStepOffset; btVector3 m_targetPosition; + btQuaternion m_currentOrientation; + btQuaternion m_targetOrientation; + ///keep track of the contact manifolds btManifoldArray m_manifoldArray; bool m_touchingContact; btVector3 m_touchingNormal; + btScalar m_linearDamping; + btScalar m_angularDamping; + bool m_wasOnGround; bool m_wasJumping; bool m_useGhostObjectSweepTest; bool m_useWalkDirection; btScalar m_velocityTimeInterval; - int m_upAxis; + btVector3 m_up; + btVector3 m_jumpAxis; static btVector3* getUpAxisDirections(); bool m_interpolateUp; @@ -94,11 +106,18 @@ ATTRIBUTE_ALIGNED16(class) btKinematicCharacterController : public btCharacterCo void updateTargetPositionBasedOnCollision (const btVector3& hit_normal, btScalar tangentMag = btScalar(0.0), btScalar normalMag = btScalar(1.0)); void stepForwardAndStrafe (btCollisionWorld* collisionWorld, const btVector3& walkMove); void stepDown (btCollisionWorld* collisionWorld, btScalar dt); + + virtual bool needsCollision(const btCollisionObject* body0, const btCollisionObject* body1); + + void setUpVector(const btVector3& up); + + btQuaternion getRotation(btVector3& v0, btVector3& v1) const; + public: BT_DECLARE_ALIGNED_ALLOCATOR(); - btKinematicCharacterController (btPairCachingGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, int upAxis = 1); + btKinematicCharacterController (btGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, const btVector3& up = btVector3(1.0,0.0,0.0)); ~btKinematicCharacterController (); @@ -112,14 +131,9 @@ ATTRIBUTE_ALIGNED16(class) btKinematicCharacterController : public btCharacterCo ///btActionInterface interface void debugDraw(btIDebugDraw* debugDrawer); - void setUpAxis (int axis) - { - if (axis < 0) - axis = 0; - if (axis > 2) - axis = 2; - m_upAxis = axis; - } + void setUp(const btVector3& up); + + const btVector3& getUp() { return m_up; } /// This should probably be called setPositionIncrementPerSimulatorStep. /// This is neither a direction nor a velocity, but the amount to @@ -136,28 +150,48 @@ ATTRIBUTE_ALIGNED16(class) btKinematicCharacterController : public btCharacterCo virtual void setVelocityForTimeInterval(const btVector3& velocity, btScalar timeInterval); + virtual void setAngularVelocity(const btVector3& velocity); + virtual const btVector3& getAngularVelocity() const; + + virtual void setLinearVelocity(const btVector3& velocity); + virtual btVector3 getLinearVelocity() const; + + void setLinearDamping(btScalar d) { m_linearDamping = btClamped(d, (btScalar)btScalar(0.0), (btScalar)btScalar(1.0)); } + btScalar getLinearDamping() const { return m_linearDamping; } + void setAngularDamping(btScalar d) { m_angularDamping = btClamped(d, (btScalar)btScalar(0.0), (btScalar)btScalar(1.0)); } + btScalar getAngularDamping() const { return m_angularDamping; } + void reset ( btCollisionWorld* collisionWorld ); void warp (const btVector3& origin); void preStep ( btCollisionWorld* collisionWorld); void playerStep ( btCollisionWorld* collisionWorld, btScalar dt); + void setStepHeight(btScalar h); + btScalar getStepHeight() const { return m_stepHeight; } void setFallSpeed (btScalar fallSpeed); + btScalar getFallSpeed() const { return m_fallSpeed; } void setJumpSpeed (btScalar jumpSpeed); + btScalar getJumpSpeed() const { return m_jumpSpeed; } void setMaxJumpHeight (btScalar maxJumpHeight); bool canJump () const; - void jump (); + void jump(const btVector3& v = btVector3()); + + void applyImpulse(const btVector3& v) { jump(v); } - void setGravity(btScalar gravity); - btScalar getGravity() const; + void setGravity(const btVector3& gravity); + btVector3 getGravity() const; /// The max slope determines the maximum angle that the controller can walk up. /// The slope angle is measured in radians. void setMaxSlope(btScalar slopeRadians); btScalar getMaxSlope() const; - btPairCachingGhostObject* getGhostObject(); + void setMaxPenetrationDepth(btScalar d); + btScalar getMaxPenetrationDepth() const; + + btGhostObject* getGhostObject(); void setUseGhostSweepTest(bool useGhostObjectSweepTest) { m_useGhostObjectSweepTest = useGhostObjectSweepTest; diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp b/extern/bullet/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp similarity index 99% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp index 09b7388b63e0..0572256f74b0 100644 --- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp +++ b/extern/bullet/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp @@ -642,7 +642,7 @@ void btConeTwistConstraint::calcAngleInfo2(const btTransform& transA, const btTr btTransform trDeltaAB = trB * trPose * trA.inverse(); btQuaternion qDeltaAB = trDeltaAB.getRotation(); btVector3 swingAxis = btVector3(qDeltaAB.x(), qDeltaAB.y(), qDeltaAB.z()); - float swingAxisLen2 = swingAxis.length2(); + btScalar swingAxisLen2 = swingAxis.length2(); if(btFuzzyZero(swingAxisLen2)) { return; @@ -903,7 +903,7 @@ btVector3 btConeTwistConstraint::GetPointForAngle(btScalar fAngleInRadians, btSc // a^2 b^2 // Do the math and it should be clear. - float swingLimit = m_swingSpan1; // if xEllipse == 0, just use axis b (1) + btScalar swingLimit = m_swingSpan1; // if xEllipse == 0, just use axis b (1) if (fabs(xEllipse) > SIMD_EPSILON) { btScalar surfaceSlope2 = (yEllipse*yEllipse)/(xEllipse*xEllipse); diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h b/extern/bullet/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h similarity index 99% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h index b7636180c345..7a33d01d1eb2 100644 --- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h +++ b/extern/bullet/src/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h @@ -260,7 +260,7 @@ ATTRIBUTE_ALIGNED16(class) btConeTwistConstraint : public btTypedConstraint inline int getSolveSwingLimit() { - return m_solveTwistLimit; + return m_solveSwingLimit; } inline btScalar getTwistLimitSign() diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btConstraintSolver.h b/extern/bullet/src/BulletDynamics/ConstraintSolver/btConstraintSolver.h similarity index 100% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btConstraintSolver.h rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btConstraintSolver.h diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp b/extern/bullet/src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp similarity index 100% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btContactConstraint.cpp diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactConstraint.h b/extern/bullet/src/BulletDynamics/ConstraintSolver/btContactConstraint.h similarity index 99% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactConstraint.h rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btContactConstraint.h index 477c79d17565..adb2268353e0 100644 --- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactConstraint.h +++ b/extern/bullet/src/BulletDynamics/ConstraintSolver/btContactConstraint.h @@ -28,11 +28,13 @@ ATTRIBUTE_ALIGNED16(class) btContactConstraint : public btTypedConstraint btPersistentManifold m_contactManifold; -public: +protected: btContactConstraint(btPersistentManifold* contactManifold,btRigidBody& rbA,btRigidBody& rbB); +public: + void setContactManifold(btPersistentManifold* contactManifold); btPersistentManifold* getContactManifold() diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h b/extern/bullet/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h similarity index 87% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h index a3a0fa6729fe..28d0c1dd4836 100644 --- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h +++ b/extern/bullet/src/BulletDynamics/ConstraintSolver/btContactSolverInfo.h @@ -43,10 +43,13 @@ struct btContactSolverInfoData btScalar m_restitution; int m_numIterations; btScalar m_maxErrorReduction; - btScalar m_sor; - btScalar m_erp;//used as Baumgarte factor - btScalar m_erp2;//used in Split Impulse - btScalar m_globalCfm;//constraint force mixing + btScalar m_sor;//successive over-relaxation term + btScalar m_erp;//error reduction for non-contact constraints + btScalar m_erp2;//error reduction for contact constraints + btScalar m_globalCfm;//constraint force mixing for contacts and non-contacts + btScalar m_frictionERP;//error reduction for friction constraints + btScalar m_frictionCFM;//constraint force mixing for friction constraints + int m_splitImpulse; btScalar m_splitImpulsePenetrationThreshold; btScalar m_splitImpulseTurnErp; @@ -58,7 +61,8 @@ struct btContactSolverInfoData int m_minimumSolverBatchSize; btScalar m_maxGyroscopicForce; btScalar m_singleAxisRollingFrictionThreshold; - + btScalar m_leastSquaresResidualThreshold; + btScalar m_restitutionVelocityThreshold; }; @@ -77,8 +81,10 @@ struct btContactSolverInfo : public btContactSolverInfoData m_maxErrorReduction = btScalar(20.); m_numIterations = 10; m_erp = btScalar(0.2); - m_erp2 = btScalar(0.8); + m_erp2 = btScalar(0.2); m_globalCfm = btScalar(0.); + m_frictionERP = btScalar(0.2);//positional friction 'anchors' are disabled by default + m_frictionCFM = btScalar(0.); m_sor = btScalar(1.); m_splitImpulse = true; m_splitImpulsePenetrationThreshold = -.04f; @@ -91,6 +97,8 @@ struct btContactSolverInfo : public btContactSolverInfoData m_minimumSolverBatchSize = 128; //try to combine islands until the amount of constraints reaches this limit m_maxGyroscopicForce = 100.f; ///it is only used for 'explicit' version of gyroscopic force m_singleAxisRollingFrictionThreshold = 1e30f;///if the velocity is above this threshold, it will use a single constraint row (axis), otherwise 3 rows. + m_leastSquaresResidualThreshold = 0.f; + m_restitutionVelocityThreshold = 0.2f;//if the relative velocity is below this threshold, there is zero restitution } }; diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btFixedConstraint.cpp b/extern/bullet/src/BulletDynamics/ConstraintSolver/btFixedConstraint.cpp similarity index 100% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btFixedConstraint.cpp rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btFixedConstraint.cpp diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btFixedConstraint.h b/extern/bullet/src/BulletDynamics/ConstraintSolver/btFixedConstraint.h similarity index 100% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btFixedConstraint.h rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btFixedConstraint.h diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGearConstraint.cpp b/extern/bullet/src/BulletDynamics/ConstraintSolver/btGearConstraint.cpp similarity index 100% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btGearConstraint.cpp rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btGearConstraint.cpp diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGearConstraint.h b/extern/bullet/src/BulletDynamics/ConstraintSolver/btGearConstraint.h similarity index 95% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btGearConstraint.h rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btGearConstraint.h index f9afcb91211f..e4613455a2b8 100644 --- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGearConstraint.h +++ b/extern/bullet/src/BulletDynamics/ConstraintSolver/btGearConstraint.h @@ -141,6 +141,14 @@ SIMD_FORCE_INLINE const char* btGearConstraint::serialize(void* dataBuffer, btSe gear->m_ratio = m_ratio; + // Fill padding with zeros to appease msan. +#ifndef BT_USE_DOUBLE_PRECISION + gear->m_padding[0] = 0; + gear->m_padding[1] = 0; + gear->m_padding[2] = 0; + gear->m_padding[3] = 0; +#endif + return btGearConstraintDataName; } diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp b/extern/bullet/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp similarity index 99% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp index bc2b5a85df95..fa17254ec3f2 100644 --- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp +++ b/extern/bullet/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp @@ -776,7 +776,7 @@ int btGeneric6DofConstraint::get_limit_motor_info2( btConstraintInfo2 *info, int row, btVector3& ax1, int rotational,int rotAllowed) { int srow = row * info->rowskip; - int powered = limot->m_enableMotor; + bool powered = limot->m_enableMotor; int limit = limot->m_currentLimit; if (powered || limit) { // if the joint is powered, or has joint limits, add in the extra row @@ -840,7 +840,7 @@ int btGeneric6DofConstraint::get_limit_motor_info2( } // if we're limited low and high simultaneously, the joint motor is // ineffective - if (limit && (limot->m_loLimit == limot->m_hiLimit)) powered = 0; + if (limit && (limot->m_loLimit == limot->m_hiLimit)) powered = false; info->m_constraintError[srow] = btScalar(0.f); if (powered) { diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h b/extern/bullet/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h similarity index 100% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp b/extern/bullet/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp similarity index 94% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp index 313719448645..e2d3a69839bb 100644 --- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp +++ b/extern/bullet/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.cpp @@ -1,1138 +1,1172 @@ -/* -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. -*/ - -/* -2014 May: btGeneric6DofSpring2Constraint is created from the original (2.82.2712) btGeneric6DofConstraint by Gabor Puhr and Tamas Umenhoffer -Pros: -- Much more accurate and stable in a lot of situation. (Especially when a sleeping chain of RBs connected with 6dof2 is pulled) -- Stable and accurate spring with minimal energy loss that works with all of the solvers. (latter is not true for the original 6dof spring) -- Servo motor functionality -- Much more accurate bouncing. 0 really means zero bouncing (not true for the original 6odf) and there is only a minimal energy loss when the value is 1 (because of the solvers' precision) -- Rotation order for the Euler system can be set. (One axis' freedom is still limited to pi/2) - -Cons: -- It is slower than the original 6dof. There is no exact ratio, but half speed is a good estimation. (with PGS) -- At bouncing the correct velocity is calculated, but not the correct position. (it is because of the solver can correct position or velocity, but not both.) -*/ - -/// 2009 March: btGeneric6DofConstraint refactored by Roman Ponomarev -/// Added support for generic constraint solver through getInfo1/getInfo2 methods - -/* -2007-09-09 -btGeneric6DofConstraint Refactored by Francisco Le?n -email: projectileman@yahoo.com -http://gimpact.sf.net -*/ - - - -#include "btGeneric6DofSpring2Constraint.h" -#include "BulletDynamics/Dynamics/btRigidBody.h" -#include "LinearMath/btTransformUtil.h" -#include - - - -btGeneric6DofSpring2Constraint::btGeneric6DofSpring2Constraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, RotateOrder rotOrder) - : btTypedConstraint(D6_SPRING_2_CONSTRAINT_TYPE, rbA, rbB) - , m_frameInA(frameInA) - , m_frameInB(frameInB) - , m_rotateOrder(rotOrder) - , m_flags(0) -{ - calculateTransforms(); -} - - -btGeneric6DofSpring2Constraint::btGeneric6DofSpring2Constraint(btRigidBody& rbB, const btTransform& frameInB, RotateOrder rotOrder) - : btTypedConstraint(D6_SPRING_2_CONSTRAINT_TYPE, getFixedBody(), rbB) - , m_frameInB(frameInB) - , m_rotateOrder(rotOrder) - , m_flags(0) -{ - ///not providing rigidbody A means implicitly using worldspace for body A - m_frameInA = rbB.getCenterOfMassTransform() * m_frameInB; - calculateTransforms(); -} - - -btScalar btGeneric6DofSpring2Constraint::btGetMatrixElem(const btMatrix3x3& mat, int index) -{ - int i = index%3; - int j = index/3; - return mat[i][j]; -} - -// MatrixToEulerXYZ from http://www.geometrictools.com/LibFoundation/Mathematics/Wm4Matrix3.inl.html - -bool btGeneric6DofSpring2Constraint::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 - - btScalar fi = btGetMatrixElem(mat,2); - if (fi < btScalar(1.0f)) - { - if (fi > btScalar(-1.0f)) - { - xyz[0] = btAtan2(-btGetMatrixElem(mat,5),btGetMatrixElem(mat,8)); - xyz[1] = btAsin(btGetMatrixElem(mat,2)); - xyz[2] = btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0)); - return true; - } - else - { - // WARNING. Not unique. XA - ZA = -atan2(r10,r11) - xyz[0] = -btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(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(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4)); - xyz[1] = SIMD_HALF_PI; - xyz[2] = 0.0; - } - return false; -} - -bool btGeneric6DofSpring2Constraint::matrixToEulerXZY(const btMatrix3x3& mat,btVector3& xyz) -{ - // rot = cy*cz -sz sy*cz - // cy*cx*sz+sx*sy cx*cz sy*cx*sz-cy*sx - // cy*sx*sz-cx*sy sx*cz sy*sx*sz+cx*cy - - btScalar fi = btGetMatrixElem(mat,1); - if (fi < btScalar(1.0f)) - { - if (fi > btScalar(-1.0f)) - { - xyz[0] = btAtan2(btGetMatrixElem(mat,7),btGetMatrixElem(mat,4)); - xyz[1] = btAtan2(btGetMatrixElem(mat,2),btGetMatrixElem(mat,0)); - xyz[2] = btAsin(-btGetMatrixElem(mat,1)); - return true; - } - else - { - xyz[0] = -btAtan2(-btGetMatrixElem(mat,6),btGetMatrixElem(mat,8)); - xyz[1] = btScalar(0.0); - xyz[2] = SIMD_HALF_PI; - return false; - } - } - else - { - xyz[0] = btAtan2(-btGetMatrixElem(mat,6),btGetMatrixElem(mat,8)); - xyz[1] = 0.0; - xyz[2] = -SIMD_HALF_PI; - } - return false; -} - -bool btGeneric6DofSpring2Constraint::matrixToEulerYXZ(const btMatrix3x3& mat,btVector3& xyz) -{ - // rot = cy*cz+sy*sx*sz cz*sy*sx-cy*sz cx*sy - // cx*sz cx*cz -sx - // cy*sx*sz-cz*sy sy*sz+cy*cz*sx cy*cx - - btScalar fi = btGetMatrixElem(mat,5); - if (fi < btScalar(1.0f)) - { - if (fi > btScalar(-1.0f)) - { - xyz[0] = btAsin(-btGetMatrixElem(mat,5)); - xyz[1] = btAtan2(btGetMatrixElem(mat,2),btGetMatrixElem(mat,8)); - xyz[2] = btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4)); - return true; - } - else - { - xyz[0] = SIMD_HALF_PI; - xyz[1] = -btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0)); - xyz[2] = btScalar(0.0); - return false; - } - } - else - { - xyz[0] = -SIMD_HALF_PI; - xyz[1] = btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0)); - xyz[2] = 0.0; - } - return false; -} - -bool btGeneric6DofSpring2Constraint::matrixToEulerYZX(const btMatrix3x3& mat,btVector3& xyz) -{ - // rot = cy*cz sy*sx-cy*cx*sz cx*sy+cy*sz*sx - // sz cz*cx -cz*sx - // -cz*sy cy*sx+cx*sy*sz cy*cx-sy*sz*sx - - btScalar fi = btGetMatrixElem(mat,3); - if (fi < btScalar(1.0f)) - { - if (fi > btScalar(-1.0f)) - { - xyz[0] = btAtan2(-btGetMatrixElem(mat,5),btGetMatrixElem(mat,4)); - xyz[1] = btAtan2(-btGetMatrixElem(mat,6),btGetMatrixElem(mat,0)); - xyz[2] = btAsin(btGetMatrixElem(mat,3)); - return true; - } - else - { - xyz[0] = btScalar(0.0); - xyz[1] = -btAtan2(btGetMatrixElem(mat,7),btGetMatrixElem(mat,8)); - xyz[2] = -SIMD_HALF_PI; - return false; - } - } - else - { - xyz[0] = btScalar(0.0); - xyz[1] = btAtan2(btGetMatrixElem(mat,7),btGetMatrixElem(mat,8)); - xyz[2] = SIMD_HALF_PI; - } - return false; -} - -bool btGeneric6DofSpring2Constraint::matrixToEulerZXY(const btMatrix3x3& mat,btVector3& xyz) -{ - // rot = cz*cy-sz*sx*sy -cx*sz cz*sy+cy*sz*sx - // cy*sz+cz*sx*sy cz*cx sz*sy-cz*xy*sx - // -cx*sy sx cx*cy - - btScalar fi = btGetMatrixElem(mat,7); - if (fi < btScalar(1.0f)) - { - if (fi > btScalar(-1.0f)) - { - xyz[0] = btAsin(btGetMatrixElem(mat,7)); - xyz[1] = btAtan2(-btGetMatrixElem(mat,6),btGetMatrixElem(mat,8)); - xyz[2] = btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,4)); - return true; - } - else - { - xyz[0] = -SIMD_HALF_PI; - xyz[1] = btScalar(0.0); - xyz[2] = -btAtan2(btGetMatrixElem(mat,2),btGetMatrixElem(mat,0)); - return false; - } - } - else - { - xyz[0] = SIMD_HALF_PI; - xyz[1] = btScalar(0.0); - xyz[2] = btAtan2(btGetMatrixElem(mat,2),btGetMatrixElem(mat,0)); - } - return false; -} - -bool btGeneric6DofSpring2Constraint::matrixToEulerZYX(const btMatrix3x3& mat,btVector3& xyz) -{ - // rot = cz*cy cz*sy*sx-cx*sz sz*sx+cz*cx*sy - // cy*sz cz*cx+sz*sy*sx cx*sz*sy-cz*sx - // -sy cy*sx cy*cx - - btScalar fi = btGetMatrixElem(mat,6); - if (fi < btScalar(1.0f)) - { - if (fi > btScalar(-1.0f)) - { - xyz[0] = btAtan2(btGetMatrixElem(mat,7), btGetMatrixElem(mat,8)); - xyz[1] = btAsin(-btGetMatrixElem(mat,6)); - xyz[2] = btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,0)); - return true; - } - else - { - xyz[0] = btScalar(0.0); - xyz[1] = SIMD_HALF_PI; - xyz[2] = -btAtan2(btGetMatrixElem(mat,1),btGetMatrixElem(mat,2)); - return false; - } - } - else - { - xyz[0] = btScalar(0.0); - xyz[1] = -SIMD_HALF_PI; - xyz[2] = btAtan2(-btGetMatrixElem(mat,1),-btGetMatrixElem(mat,2)); - } - return false; -} - -void btGeneric6DofSpring2Constraint::calculateAngleInfo() -{ - btMatrix3x3 relative_frame = m_calculatedTransformA.getBasis().inverse()*m_calculatedTransformB.getBasis(); - switch (m_rotateOrder) - { - case RO_XYZ : matrixToEulerXYZ(relative_frame,m_calculatedAxisAngleDiff); break; - case RO_XZY : matrixToEulerXZY(relative_frame,m_calculatedAxisAngleDiff); break; - case RO_YXZ : matrixToEulerYXZ(relative_frame,m_calculatedAxisAngleDiff); break; - case RO_YZX : matrixToEulerYZX(relative_frame,m_calculatedAxisAngleDiff); break; - case RO_ZXY : matrixToEulerZXY(relative_frame,m_calculatedAxisAngleDiff); break; - case RO_ZYX : matrixToEulerZYX(relative_frame,m_calculatedAxisAngleDiff); break; - default : btAssert(false); - } - // 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. - switch (m_rotateOrder) - { - case RO_XYZ : - { - //Is this the "line of nodes" calculation choosing planes YZ (B coordinate system) and xy (A coordinate system)? (http://en.wikipedia.org/wiki/Euler_angles) - //The two planes are non-homologous, so this is a Tait–Bryan angle formalism and not a proper Euler - //Extrinsic rotations are equal to the reversed order intrinsic rotations so the above xyz extrinsic rotations (axes are fixed) are the same as the zy'x" intrinsic rotations (axes are refreshed after each rotation) - //that is why xy and YZ planes are chosen (this will describe a zy'x" intrinsic rotation) (see the figure on the left at http://en.wikipedia.org/wiki/Euler_angles under Tait–Bryan angles) - // x' = Nperp = N.cross(axis2) - // y' = N = axis2.cross(axis0) - // z' = z - // - // x" = X - // y" = y' - // z" = ?? - //in other words: - //first rotate around z - //second rotate around y'= z.cross(X) - //third rotate around x" = X - //Original XYZ extrinsic rotation order. - //Planes: xy and YZ normals: z, X. Plane intersection (N) is z.cross(X) - btVector3 axis0 = m_calculatedTransformB.getBasis().getColumn(0); - btVector3 axis2 = m_calculatedTransformA.getBasis().getColumn(2); - m_calculatedAxis[1] = axis2.cross(axis0); - m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2); - m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]); - break; - } - case RO_XZY : - { - //planes: xz,ZY normals: y, X - //first rotate around y - //second rotate around z'= y.cross(X) - //third rotate around x" = X - btVector3 axis0 = m_calculatedTransformB.getBasis().getColumn(0); - btVector3 axis1 = m_calculatedTransformA.getBasis().getColumn(1); - m_calculatedAxis[2] = axis0.cross(axis1); - m_calculatedAxis[0] = axis1.cross(m_calculatedAxis[2]); - m_calculatedAxis[1] = m_calculatedAxis[2].cross(axis0); - break; - } - case RO_YXZ : - { - //planes: yx,XZ normals: z, Y - //first rotate around z - //second rotate around x'= z.cross(Y) - //third rotate around y" = Y - btVector3 axis1 = m_calculatedTransformB.getBasis().getColumn(1); - btVector3 axis2 = m_calculatedTransformA.getBasis().getColumn(2); - m_calculatedAxis[0] = axis1.cross(axis2); - m_calculatedAxis[1] = axis2.cross(m_calculatedAxis[0]); - m_calculatedAxis[2] = m_calculatedAxis[0].cross(axis1); - break; - } - case RO_YZX : - { - //planes: yz,ZX normals: x, Y - //first rotate around x - //second rotate around z'= x.cross(Y) - //third rotate around y" = Y - btVector3 axis0 = m_calculatedTransformA.getBasis().getColumn(0); - btVector3 axis1 = m_calculatedTransformB.getBasis().getColumn(1); - m_calculatedAxis[2] = axis0.cross(axis1); - m_calculatedAxis[0] = axis1.cross(m_calculatedAxis[2]); - m_calculatedAxis[1] = m_calculatedAxis[2].cross(axis0); - break; - } - case RO_ZXY : - { - //planes: zx,XY normals: y, Z - //first rotate around y - //second rotate around x'= y.cross(Z) - //third rotate around z" = Z - btVector3 axis1 = m_calculatedTransformA.getBasis().getColumn(1); - btVector3 axis2 = m_calculatedTransformB.getBasis().getColumn(2); - m_calculatedAxis[0] = axis1.cross(axis2); - m_calculatedAxis[1] = axis2.cross(m_calculatedAxis[0]); - m_calculatedAxis[2] = m_calculatedAxis[0].cross(axis1); - break; - } - case RO_ZYX : - { - //planes: zy,YX normals: x, Z - //first rotate around x - //second rotate around y' = x.cross(Z) - //third rotate around z" = Z - btVector3 axis0 = m_calculatedTransformA.getBasis().getColumn(0); - btVector3 axis2 = m_calculatedTransformB.getBasis().getColumn(2); - m_calculatedAxis[1] = axis2.cross(axis0); - m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2); - m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]); - break; - } - default: - btAssert(false); - } - - m_calculatedAxis[0].normalize(); - m_calculatedAxis[1].normalize(); - m_calculatedAxis[2].normalize(); - -} - -void btGeneric6DofSpring2Constraint::calculateTransforms() -{ - calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); -} - -void btGeneric6DofSpring2Constraint::calculateTransforms(const btTransform& transA,const btTransform& transB) -{ - m_calculatedTransformA = transA * m_frameInA; - m_calculatedTransformB = transB * m_frameInB; - calculateLinearInfo(); - calculateAngleInfo(); - - btScalar miA = getRigidBodyA().getInvMass(); - btScalar miB = getRigidBodyB().getInvMass(); - m_hasStaticBody = (miA < SIMD_EPSILON) || (miB < SIMD_EPSILON); - btScalar miS = miA + miB; - if(miS > btScalar(0.f)) - { - m_factA = miB / miS; - } - else - { - m_factA = btScalar(0.5f); - } - m_factB = btScalar(1.0f) - m_factA; -} - - -void btGeneric6DofSpring2Constraint::testAngularLimitMotor(int axis_index) -{ - btScalar angle = m_calculatedAxisAngleDiff[axis_index]; - angle = btAdjustAngleToLimits(angle, m_angularLimits[axis_index].m_loLimit, m_angularLimits[axis_index].m_hiLimit); - m_angularLimits[axis_index].m_currentPosition = angle; - m_angularLimits[axis_index].testLimitValue(angle); -} - - -void btGeneric6DofSpring2Constraint::getInfo1 (btConstraintInfo1* info) -{ - //prepare constraint - calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); - info->m_numConstraintRows = 0; - info->nub = 0; - int i; - //test linear limits - for(i = 0; i < 3; i++) - { - if (m_linearLimits.m_currentLimit[i]==4) info->m_numConstraintRows += 2; - else if (m_linearLimits.m_currentLimit[i]!=0) info->m_numConstraintRows += 1; - if (m_linearLimits.m_enableMotor[i] ) info->m_numConstraintRows += 1; - if (m_linearLimits.m_enableSpring[i]) info->m_numConstraintRows += 1; - } - //test angular limits - for (i=0;i<3 ;i++ ) - { - testAngularLimitMotor(i); - if (m_angularLimits[i].m_currentLimit==4) info->m_numConstraintRows += 2; - else if (m_angularLimits[i].m_currentLimit!=0) info->m_numConstraintRows += 1; - if (m_angularLimits[i].m_enableMotor ) info->m_numConstraintRows += 1; - if (m_angularLimits[i].m_enableSpring) info->m_numConstraintRows += 1; - } -} - - -void btGeneric6DofSpring2Constraint::getInfo2 (btConstraintInfo2* info) -{ - const btTransform& transA = m_rbA.getCenterOfMassTransform(); - const btTransform& transB = m_rbB.getCenterOfMassTransform(); - const btVector3& linVelA = m_rbA.getLinearVelocity(); - const btVector3& linVelB = m_rbB.getLinearVelocity(); - const btVector3& angVelA = m_rbA.getAngularVelocity(); - const btVector3& angVelB = m_rbB.getAngularVelocity(); - - // for stability better to solve angular limits first - int row = setAngularLimits(info, 0,transA,transB,linVelA,linVelB,angVelA,angVelB); - setLinearLimits(info, row, transA,transB,linVelA,linVelB,angVelA,angVelB); -} - - -int btGeneric6DofSpring2Constraint::setLinearLimits(btConstraintInfo2* info, int row, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB) -{ - //solve linear limits - btRotationalLimitMotor2 limot; - for (int i=0;i<3 ;i++ ) - { - if(m_linearLimits.m_currentLimit[i] || m_linearLimits.m_enableMotor[i] || m_linearLimits.m_enableSpring[i]) - { // re-use rotational motor code - limot.m_bounce = m_linearLimits.m_bounce[i]; - limot.m_currentLimit = m_linearLimits.m_currentLimit[i]; - limot.m_currentPosition = m_linearLimits.m_currentLinearDiff[i]; - limot.m_currentLimitError = m_linearLimits.m_currentLimitError[i]; - limot.m_currentLimitErrorHi = m_linearLimits.m_currentLimitErrorHi[i]; - limot.m_enableMotor = m_linearLimits.m_enableMotor[i]; - limot.m_servoMotor = m_linearLimits.m_servoMotor[i]; - limot.m_servoTarget = m_linearLimits.m_servoTarget[i]; - limot.m_enableSpring = m_linearLimits.m_enableSpring[i]; - limot.m_springStiffness = m_linearLimits.m_springStiffness[i]; - limot.m_springStiffnessLimited = m_linearLimits.m_springStiffnessLimited[i]; - limot.m_springDamping = m_linearLimits.m_springDamping[i]; - limot.m_springDampingLimited = m_linearLimits.m_springDampingLimited[i]; - limot.m_equilibriumPoint = m_linearLimits.m_equilibriumPoint[i]; - limot.m_hiLimit = m_linearLimits.m_upperLimit[i]; - limot.m_loLimit = m_linearLimits.m_lowerLimit[i]; - limot.m_maxMotorForce = m_linearLimits.m_maxMotorForce[i]; - limot.m_targetVelocity = m_linearLimits.m_targetVelocity[i]; - btVector3 axis = m_calculatedTransformA.getBasis().getColumn(i); - int flags = m_flags >> (i * BT_6DOF_FLAGS_AXIS_SHIFT2); - limot.m_stopCFM = (flags & BT_6DOF_FLAGS_CFM_STOP2) ? m_linearLimits.m_stopCFM[i] : info->cfm[0]; - limot.m_stopERP = (flags & BT_6DOF_FLAGS_ERP_STOP2) ? m_linearLimits.m_stopERP[i] : info->erp; - limot.m_motorCFM = (flags & BT_6DOF_FLAGS_CFM_MOTO2) ? m_linearLimits.m_motorCFM[i] : info->cfm[0]; - limot.m_motorERP = (flags & BT_6DOF_FLAGS_ERP_MOTO2) ? m_linearLimits.m_motorERP[i] : info->erp; - - //rotAllowed is a bit of a magic from the original 6dof. The calculation of it here is something that imitates the original behavior as much as possible. - int indx1 = (i + 1) % 3; - int indx2 = (i + 2) % 3; - int rotAllowed = 1; // rotations around orthos to current axis (it is used only when one of the body is static) - #define D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION 1.0e-3 - bool indx1Violated = m_angularLimits[indx1].m_currentLimit == 1 || - m_angularLimits[indx1].m_currentLimit == 2 || - ( m_angularLimits[indx1].m_currentLimit == 3 && ( m_angularLimits[indx1].m_currentLimitError < -D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION || m_angularLimits[indx1].m_currentLimitError > D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION ) ) || - ( m_angularLimits[indx1].m_currentLimit == 4 && ( m_angularLimits[indx1].m_currentLimitError < -D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION || m_angularLimits[indx1].m_currentLimitErrorHi > D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION ) ); - bool indx2Violated = m_angularLimits[indx2].m_currentLimit == 1 || - m_angularLimits[indx2].m_currentLimit == 2 || - ( m_angularLimits[indx2].m_currentLimit == 3 && ( m_angularLimits[indx2].m_currentLimitError < -D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION || m_angularLimits[indx2].m_currentLimitError > D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION ) ) || - ( m_angularLimits[indx2].m_currentLimit == 4 && ( m_angularLimits[indx2].m_currentLimitError < -D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION || m_angularLimits[indx2].m_currentLimitErrorHi > D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION ) ); - if( indx1Violated && indx2Violated ) - { - rotAllowed = 0; - } - row += get_limit_motor_info2(&limot, transA,transB,linVelA,linVelB,angVelA,angVelB, info, row, axis, 0, rotAllowed); - - } - } - return row; -} - - - -int btGeneric6DofSpring2Constraint::setAngularLimits(btConstraintInfo2 *info, int row_offset, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB) -{ - int row = row_offset; - - //order of rotational constraint rows - int cIdx[] = {0, 1, 2}; - switch(m_rotateOrder) - { - case RO_XYZ : cIdx[0] = 0; cIdx[1] = 1; cIdx[2] = 2; break; - case RO_XZY : cIdx[0] = 0; cIdx[1] = 2; cIdx[2] = 1; break; - case RO_YXZ : cIdx[0] = 1; cIdx[1] = 0; cIdx[2] = 2; break; - case RO_YZX : cIdx[0] = 1; cIdx[1] = 2; cIdx[2] = 0; break; - case RO_ZXY : cIdx[0] = 2; cIdx[1] = 0; cIdx[2] = 1; break; - case RO_ZYX : cIdx[0] = 2; cIdx[1] = 1; cIdx[2] = 0; break; - default : btAssert(false); - } - - for (int ii = 0; ii < 3 ; ii++ ) - { - int i = cIdx[ii]; - if(m_angularLimits[i].m_currentLimit || m_angularLimits[i].m_enableMotor || m_angularLimits[i].m_enableSpring) - { - btVector3 axis = getAxis(i); - int flags = m_flags >> ((i + 3) * BT_6DOF_FLAGS_AXIS_SHIFT2); - if(!(flags & BT_6DOF_FLAGS_CFM_STOP2)) - { - m_angularLimits[i].m_stopCFM = info->cfm[0]; - } - if(!(flags & BT_6DOF_FLAGS_ERP_STOP2)) - { - m_angularLimits[i].m_stopERP = info->erp; - } - if(!(flags & BT_6DOF_FLAGS_CFM_MOTO2)) - { - m_angularLimits[i].m_motorCFM = info->cfm[0]; - } - if(!(flags & BT_6DOF_FLAGS_ERP_MOTO2)) - { - m_angularLimits[i].m_motorERP = info->erp; - } - row += get_limit_motor_info2(&m_angularLimits[i],transA,transB,linVelA,linVelB,angVelA,angVelB, info,row,axis,1); - } - } - - return row; -} - - -void btGeneric6DofSpring2Constraint::setFrames(const btTransform& frameA, const btTransform& frameB) -{ - m_frameInA = frameA; - m_frameInB = frameB; - buildJacobian(); - calculateTransforms(); -} - - -void btGeneric6DofSpring2Constraint::calculateLinearInfo() -{ - m_calculatedLinearDiff = m_calculatedTransformB.getOrigin() - m_calculatedTransformA.getOrigin(); - m_calculatedLinearDiff = m_calculatedTransformA.getBasis().inverse() * m_calculatedLinearDiff; - for(int i = 0; i < 3; i++) - { - m_linearLimits.m_currentLinearDiff[i] = m_calculatedLinearDiff[i]; - m_linearLimits.testLimitValue(i, m_calculatedLinearDiff[i]); - } -} - -void btGeneric6DofSpring2Constraint::calculateJacobi(btRotationalLimitMotor2 * limot, const btTransform& transA,const btTransform& transB, btConstraintInfo2 *info, int srow, btVector3& ax1, int rotational, int rotAllowed) -{ - btScalar *J1 = rotational ? info->m_J1angularAxis : info->m_J1linearAxis; - btScalar *J2 = rotational ? info->m_J2angularAxis : info->m_J2linearAxis; - - J1[srow+0] = ax1[0]; - J1[srow+1] = ax1[1]; - J1[srow+2] = ax1[2]; - - J2[srow+0] = -ax1[0]; - J2[srow+1] = -ax1[1]; - J2[srow+2] = -ax1[2]; - - if(!rotational) - { - btVector3 tmpA, tmpB, relA, relB; - // get vector from bodyB to frameB in WCS - relB = m_calculatedTransformB.getOrigin() - transB.getOrigin(); - // same for bodyA - relA = m_calculatedTransformA.getOrigin() - transA.getOrigin(); - tmpA = relA.cross(ax1); - tmpB = relB.cross(ax1); - if(m_hasStaticBody && (!rotAllowed)) - { - tmpA *= m_factA; - tmpB *= m_factB; - } - int i; - for (i=0; i<3; i++) info->m_J1angularAxis[srow+i] = tmpA[i]; - for (i=0; i<3; i++) info->m_J2angularAxis[srow+i] = -tmpB[i]; - } -} - - -int btGeneric6DofSpring2Constraint::get_limit_motor_info2( - btRotationalLimitMotor2 * limot, - const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB, - btConstraintInfo2 *info, int row, btVector3& ax1, int rotational,int rotAllowed) -{ - int count = 0; - int srow = row * info->rowskip; - - if (limot->m_currentLimit==4) - { - btScalar vel = rotational ? angVelA.dot(ax1) - angVelB.dot(ax1) : linVelA.dot(ax1) - linVelB.dot(ax1); - - calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed); - info->m_constraintError[srow] = info->fps * limot->m_stopERP * limot->m_currentLimitError * (rotational ? -1 : 1); - if (rotational) { - if (info->m_constraintError[srow]-vel*limot->m_stopERP > 0) { - btScalar bounceerror = -limot->m_bounce* vel; - if (bounceerror > info->m_constraintError[srow]) info->m_constraintError[srow] = bounceerror; - } - } else { - if (info->m_constraintError[srow]-vel*limot->m_stopERP < 0) { - btScalar bounceerror = -limot->m_bounce* vel; - if (bounceerror < info->m_constraintError[srow]) info->m_constraintError[srow] = bounceerror; - } - } - info->m_lowerLimit[srow] = rotational ? 0 : -SIMD_INFINITY; - info->m_upperLimit[srow] = rotational ? SIMD_INFINITY : 0; - info->cfm[srow] = limot->m_stopCFM; - srow += info->rowskip; - ++count; - - calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed); - info->m_constraintError[srow] = info->fps * limot->m_stopERP * limot->m_currentLimitErrorHi * (rotational ? -1 : 1); - if (rotational) { - if (info->m_constraintError[srow]-vel*limot->m_stopERP < 0) { - btScalar bounceerror = -limot->m_bounce* vel; - if (bounceerror < info->m_constraintError[srow]) info->m_constraintError[srow] = bounceerror; - } - } else { - if (info->m_constraintError[srow]-vel*limot->m_stopERP > 0) { - btScalar bounceerror = -limot->m_bounce* vel; - if (bounceerror > info->m_constraintError[srow]) info->m_constraintError[srow] = bounceerror; - } - } - info->m_lowerLimit[srow] = rotational ? -SIMD_INFINITY : 0; - info->m_upperLimit[srow] = rotational ? 0 : SIMD_INFINITY; - info->cfm[srow] = limot->m_stopCFM; - srow += info->rowskip; - ++count; - } else - if (limot->m_currentLimit==3) - { - calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed); - info->m_constraintError[srow] = info->fps * limot->m_stopERP * limot->m_currentLimitError * (rotational ? -1 : 1); - info->m_lowerLimit[srow] = -SIMD_INFINITY; - info->m_upperLimit[srow] = SIMD_INFINITY; - info->cfm[srow] = limot->m_stopCFM; - srow += info->rowskip; - ++count; - } - - if (limot->m_enableMotor && !limot->m_servoMotor) - { - calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed); - btScalar tag_vel = rotational ? limot->m_targetVelocity : -limot->m_targetVelocity; - btScalar mot_fact = getMotorFactor(limot->m_currentPosition, - limot->m_loLimit, - limot->m_hiLimit, - tag_vel, - info->fps * limot->m_motorERP); - info->m_constraintError[srow] = mot_fact * limot->m_targetVelocity; - info->m_lowerLimit[srow] = -limot->m_maxMotorForce; - info->m_upperLimit[srow] = limot->m_maxMotorForce; - info->cfm[srow] = limot->m_motorCFM; - srow += info->rowskip; - ++count; - } - - if (limot->m_enableMotor && limot->m_servoMotor) - { - btScalar error = limot->m_currentPosition - limot->m_servoTarget; - calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed); - btScalar targetvelocity = error<0 ? -limot->m_targetVelocity : limot->m_targetVelocity; - btScalar tag_vel = -targetvelocity; - btScalar mot_fact; - if(error != 0) - { - btScalar lowLimit; - btScalar hiLimit; - if(limot->m_loLimit > limot->m_hiLimit) - { - lowLimit = error > 0 ? limot->m_servoTarget : -SIMD_INFINITY; - hiLimit = error < 0 ? limot->m_servoTarget : SIMD_INFINITY; - } - else - { - lowLimit = error > 0 && limot->m_servoTarget>limot->m_loLimit ? limot->m_servoTarget : limot->m_loLimit; - hiLimit = error < 0 && limot->m_servoTargetm_hiLimit ? limot->m_servoTarget : limot->m_hiLimit; - } - mot_fact = getMotorFactor(limot->m_currentPosition, lowLimit, hiLimit, tag_vel, info->fps * limot->m_motorERP); - } - else - { - mot_fact = 0; - } - info->m_constraintError[srow] = mot_fact * targetvelocity * (rotational ? -1 : 1); - info->m_lowerLimit[srow] = -limot->m_maxMotorForce; - info->m_upperLimit[srow] = limot->m_maxMotorForce; - info->cfm[srow] = limot->m_motorCFM; - srow += info->rowskip; - ++count; - } - - if (limot->m_enableSpring) - { - btScalar error = limot->m_currentPosition - limot->m_equilibriumPoint; - calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed); - - //btScalar cfm = 1.0 / ((1.0/info->fps)*limot->m_springStiffness+ limot->m_springDamping); - //if(cfm > 0.99999) - // cfm = 0.99999; - //btScalar erp = (1.0/info->fps)*limot->m_springStiffness / ((1.0/info->fps)*limot->m_springStiffness + limot->m_springDamping); - //info->m_constraintError[srow] = info->fps * erp * error * (rotational ? -1.0 : 1.0); - //info->m_lowerLimit[srow] = -SIMD_INFINITY; - //info->m_upperLimit[srow] = SIMD_INFINITY; - - btScalar dt = BT_ONE / info->fps; - btScalar kd = limot->m_springDamping; - btScalar ks = limot->m_springStiffness; - btScalar vel = rotational ? angVelA.dot(ax1) - angVelB.dot(ax1) : linVelA.dot(ax1) - linVelB.dot(ax1); -// btScalar erp = 0.1; - btScalar cfm = BT_ZERO; - btScalar mA = BT_ONE / m_rbA.getInvMass(); - btScalar mB = BT_ONE / m_rbB.getInvMass(); - if (rotational) { - btScalar rrA = (m_calculatedTransformA.getOrigin() - transA.getOrigin()).length2(); - btScalar rrB = (m_calculatedTransformB.getOrigin() - transB.getOrigin()).length2(); - if (m_rbA.getInvMass()) mA = mA * rrA + 1 / (m_rbA.getInvInertiaTensorWorld() * ax1).length(); - if (m_rbB.getInvMass()) mB = mB * rrB + 1 / (m_rbB.getInvInertiaTensorWorld() * ax1).length(); - } - btScalar m = mA > mB ? mB : mA; - btScalar angularfreq = sqrt(ks / m); - - - //limit stiffness (the spring should not be sampled faster that the quarter of its angular frequency) - if(limot->m_springStiffnessLimited && 0.25 < angularfreq * dt) - { - ks = BT_ONE / dt / dt / btScalar(16.0) * m; - } - //avoid damping that would blow up the spring - if(limot->m_springDampingLimited && kd * dt > m) - { - kd = m / dt; - } - btScalar fs = ks * error * dt; - btScalar fd = -kd * (vel) * (rotational ? -1 : 1) * dt; - btScalar f = (fs+fd); - - // after the spring force affecting the body(es) the new velocity will be - // vel + f / m * (rotational ? -1 : 1) - // so in theory this should be set here for m_constraintError - // (with m_constraintError we set a desired velocity for the affected body(es)) - // however in practice any value is fine as long as it is greater then the "proper" velocity, - // because the m_lowerLimit and the m_upperLimit will determinate the strength of the final pulling force - // so it is much simpler (and more robust) just to simply use inf (with the proper sign) - // you may also wonder what if the current velocity (vel) so high that the pulling force will not change its direction (in this iteration) - // will we not request a velocity with the wrong direction ? - // and the answare is not, because in practice during the solving the current velocity is subtracted from the m_constraintError - // so the sign of the force that is really matters - info->m_constraintError[srow] = (rotational ? -1 : 1) * (f < 0 ? -SIMD_INFINITY : SIMD_INFINITY); - - btScalar minf = f < fd ? f : fd; - btScalar maxf = f < fd ? fd : f; - if(!rotational) - { - info->m_lowerLimit[srow] = minf > 0 ? 0 : minf; - info->m_upperLimit[srow] = maxf < 0 ? 0 : maxf; - } - else - { - info->m_lowerLimit[srow] = -maxf > 0 ? 0 : -maxf; - info->m_upperLimit[srow] = -minf < 0 ? 0 : -minf; - } - - info->cfm[srow] = cfm; - srow += info->rowskip; - ++count; - } - - return count; -} - - -//override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). -//If no axis is provided, it uses the default axis for this constraint. -void btGeneric6DofSpring2Constraint::setParam(int num, btScalar value, int axis) -{ - if((axis >= 0) && (axis < 3)) - { - switch(num) - { - case BT_CONSTRAINT_STOP_ERP : - m_linearLimits.m_stopERP[axis] = value; - m_flags |= BT_6DOF_FLAGS_ERP_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2); - break; - case BT_CONSTRAINT_STOP_CFM : - m_linearLimits.m_stopCFM[axis] = value; - m_flags |= BT_6DOF_FLAGS_CFM_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2); - break; - case BT_CONSTRAINT_ERP : - m_linearLimits.m_motorERP[axis] = value; - m_flags |= BT_6DOF_FLAGS_ERP_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2); - break; - case BT_CONSTRAINT_CFM : - m_linearLimits.m_motorCFM[axis] = value; - m_flags |= BT_6DOF_FLAGS_CFM_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2); - break; - default : - btAssertConstrParams(0); - } - } - else if((axis >=3) && (axis < 6)) - { - switch(num) - { - case BT_CONSTRAINT_STOP_ERP : - m_angularLimits[axis - 3].m_stopERP = value; - m_flags |= BT_6DOF_FLAGS_ERP_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2); - break; - case BT_CONSTRAINT_STOP_CFM : - m_angularLimits[axis - 3].m_stopCFM = value; - m_flags |= BT_6DOF_FLAGS_CFM_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2); - break; - case BT_CONSTRAINT_ERP : - m_angularLimits[axis - 3].m_motorERP = value; - m_flags |= BT_6DOF_FLAGS_ERP_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2); - break; - case BT_CONSTRAINT_CFM : - m_angularLimits[axis - 3].m_motorCFM = value; - m_flags |= BT_6DOF_FLAGS_CFM_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2); - break; - default : - btAssertConstrParams(0); - } - } - else - { - btAssertConstrParams(0); - } -} - -//return the local value of parameter -btScalar btGeneric6DofSpring2Constraint::getParam(int num, int axis) const -{ - btScalar retVal = 0; - if((axis >= 0) && (axis < 3)) - { - switch(num) - { - case BT_CONSTRAINT_STOP_ERP : - btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2))); - retVal = m_linearLimits.m_stopERP[axis]; - break; - case BT_CONSTRAINT_STOP_CFM : - btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2))); - retVal = m_linearLimits.m_stopCFM[axis]; - break; - case BT_CONSTRAINT_ERP : - btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2))); - retVal = m_linearLimits.m_motorERP[axis]; - break; - case BT_CONSTRAINT_CFM : - btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2))); - retVal = m_linearLimits.m_motorCFM[axis]; - break; - default : - btAssertConstrParams(0); - } - } - else if((axis >=3) && (axis < 6)) - { - switch(num) - { - case BT_CONSTRAINT_STOP_ERP : - btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2))); - retVal = m_angularLimits[axis - 3].m_stopERP; - break; - case BT_CONSTRAINT_STOP_CFM : - btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2))); - retVal = m_angularLimits[axis - 3].m_stopCFM; - break; - case BT_CONSTRAINT_ERP : - btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2))); - retVal = m_angularLimits[axis - 3].m_motorERP; - break; - case BT_CONSTRAINT_CFM : - btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2))); - retVal = m_angularLimits[axis - 3].m_motorCFM; - break; - default : - btAssertConstrParams(0); - } - } - else - { - btAssertConstrParams(0); - } - return retVal; -} - - - -void btGeneric6DofSpring2Constraint::setAxis(const btVector3& axis1,const btVector3& axis2) -{ - btVector3 zAxis = axis1.normalized(); - btVector3 yAxis = axis2.normalized(); - btVector3 xAxis = yAxis.cross(zAxis); // we want right coordinate system - - btTransform frameInW; - frameInW.setIdentity(); - frameInW.getBasis().setValue( xAxis[0], yAxis[0], zAxis[0], - xAxis[1], yAxis[1], zAxis[1], - xAxis[2], yAxis[2], zAxis[2]); - - // now get constraint frame in local coordinate systems - m_frameInA = m_rbA.getCenterOfMassTransform().inverse() * frameInW; - m_frameInB = m_rbB.getCenterOfMassTransform().inverse() * frameInW; - - calculateTransforms(); -} - -void btGeneric6DofSpring2Constraint::setBounce(int index, btScalar bounce) -{ - btAssert((index >= 0) && (index < 6)); - if (index<3) - m_linearLimits.m_bounce[index] = bounce; - else - m_angularLimits[index - 3].m_bounce = bounce; -} - -void btGeneric6DofSpring2Constraint::enableMotor(int index, bool onOff) -{ - btAssert((index >= 0) && (index < 6)); - if (index<3) - m_linearLimits.m_enableMotor[index] = onOff; - else - m_angularLimits[index - 3].m_enableMotor = onOff; -} - -void btGeneric6DofSpring2Constraint::setServo(int index, bool onOff) -{ - btAssert((index >= 0) && (index < 6)); - if (index<3) - m_linearLimits.m_servoMotor[index] = onOff; - else - m_angularLimits[index - 3].m_servoMotor = onOff; -} - -void btGeneric6DofSpring2Constraint::setTargetVelocity(int index, btScalar velocity) -{ - btAssert((index >= 0) && (index < 6)); - if (index<3) - m_linearLimits.m_targetVelocity[index] = velocity; - else - m_angularLimits[index - 3].m_targetVelocity = velocity; -} - -void btGeneric6DofSpring2Constraint::setServoTarget(int index, btScalar target) -{ - btAssert((index >= 0) && (index < 6)); - if (index<3) - m_linearLimits.m_servoTarget[index] = target; - else - m_angularLimits[index - 3].m_servoTarget = target; -} - -void btGeneric6DofSpring2Constraint::setMaxMotorForce(int index, btScalar force) -{ - btAssert((index >= 0) && (index < 6)); - if (index<3) - m_linearLimits.m_maxMotorForce[index] = force; - else - m_angularLimits[index - 3].m_maxMotorForce = force; -} - -void btGeneric6DofSpring2Constraint::enableSpring(int index, bool onOff) -{ - btAssert((index >= 0) && (index < 6)); - if (index<3) - m_linearLimits.m_enableSpring[index] = onOff; - else - m_angularLimits[index - 3] .m_enableSpring = onOff; -} - -void btGeneric6DofSpring2Constraint::setStiffness(int index, btScalar stiffness, bool limitIfNeeded) -{ - btAssert((index >= 0) && (index < 6)); - if (index<3) { - m_linearLimits.m_springStiffness[index] = stiffness; - m_linearLimits.m_springStiffnessLimited[index] = limitIfNeeded; - } else { - m_angularLimits[index - 3].m_springStiffness = stiffness; - m_angularLimits[index - 3].m_springStiffnessLimited = limitIfNeeded; - } -} - -void btGeneric6DofSpring2Constraint::setDamping(int index, btScalar damping, bool limitIfNeeded) -{ - btAssert((index >= 0) && (index < 6)); - if (index<3) { - m_linearLimits.m_springDamping[index] = damping; - m_linearLimits.m_springDampingLimited[index] = limitIfNeeded; - } else { - m_angularLimits[index - 3].m_springDamping = damping; - m_angularLimits[index - 3].m_springDampingLimited = limitIfNeeded; - } -} - -void btGeneric6DofSpring2Constraint::setEquilibriumPoint() -{ - calculateTransforms(); - int i; - for( i = 0; i < 3; i++) - m_linearLimits.m_equilibriumPoint[i] = m_calculatedLinearDiff[i]; - for(i = 0; i < 3; i++) - m_angularLimits[i].m_equilibriumPoint = m_calculatedAxisAngleDiff[i]; -} - -void btGeneric6DofSpring2Constraint::setEquilibriumPoint(int index) -{ - btAssert((index >= 0) && (index < 6)); - calculateTransforms(); - if (index<3) - m_linearLimits.m_equilibriumPoint[index] = m_calculatedLinearDiff[index]; - else - m_angularLimits[index - 3] .m_equilibriumPoint = m_calculatedAxisAngleDiff[index - 3]; -} - -void btGeneric6DofSpring2Constraint::setEquilibriumPoint(int index, btScalar val) -{ - btAssert((index >= 0) && (index < 6)); - if (index<3) - m_linearLimits.m_equilibriumPoint[index] = val; - else - m_angularLimits[index - 3] .m_equilibriumPoint = val; -} - - -//////////////////////////// btRotationalLimitMotor2 //////////////////////////////////// - -void btRotationalLimitMotor2::testLimitValue(btScalar test_value) -{ - //we can't normalize the angles here because we would lost the sign that we use later, but it doesn't seem to be a problem - if(m_loLimit > m_hiLimit) { - m_currentLimit = 0; - m_currentLimitError = btScalar(0.f); - } - else if(m_loLimit == m_hiLimit) { - m_currentLimitError = test_value - m_loLimit; - m_currentLimit = 3; - } else { - m_currentLimitError = test_value - m_loLimit; - m_currentLimitErrorHi = test_value - m_hiLimit; - m_currentLimit = 4; - } -} - -//////////////////////////// btTranslationalLimitMotor2 //////////////////////////////////// - -void btTranslationalLimitMotor2::testLimitValue(int limitIndex, btScalar test_value) -{ - btScalar loLimit = m_lowerLimit[limitIndex]; - btScalar hiLimit = m_upperLimit[limitIndex]; - if(loLimit > hiLimit) { - m_currentLimitError[limitIndex] = 0; - m_currentLimit[limitIndex] = 0; - } - else if(loLimit == hiLimit) { - m_currentLimitError[limitIndex] = test_value - loLimit; - m_currentLimit[limitIndex] = 3; - } else { - m_currentLimitError[limitIndex] = test_value - loLimit; - m_currentLimitErrorHi[limitIndex] = test_value - hiLimit; - m_currentLimit[limitIndex] = 4; - } -} - - +/* +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. +*/ + +/* +2014 May: btGeneric6DofSpring2Constraint is created from the original (2.82.2712) btGeneric6DofConstraint by Gabor Puhr and Tamas Umenhoffer +Pros: +- Much more accurate and stable in a lot of situation. (Especially when a sleeping chain of RBs connected with 6dof2 is pulled) +- Stable and accurate spring with minimal energy loss that works with all of the solvers. (latter is not true for the original 6dof spring) +- Servo motor functionality +- Much more accurate bouncing. 0 really means zero bouncing (not true for the original 6odf) and there is only a minimal energy loss when the value is 1 (because of the solvers' precision) +- Rotation order for the Euler system can be set. (One axis' freedom is still limited to pi/2) + +Cons: +- It is slower than the original 6dof. There is no exact ratio, but half speed is a good estimation. (with PGS) +- At bouncing the correct velocity is calculated, but not the correct position. (it is because of the solver can correct position or velocity, but not both.) +*/ + +/// 2009 March: btGeneric6DofConstraint refactored by Roman Ponomarev +/// Added support for generic constraint solver through getInfo1/getInfo2 methods + +/* +2007-09-09 +btGeneric6DofConstraint Refactored by Francisco Le?n +email: projectileman@yahoo.com +http://gimpact.sf.net +*/ + + + +#include "btGeneric6DofSpring2Constraint.h" +#include "BulletDynamics/Dynamics/btRigidBody.h" +#include "LinearMath/btTransformUtil.h" +#include + + + +btGeneric6DofSpring2Constraint::btGeneric6DofSpring2Constraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, RotateOrder rotOrder) + : btTypedConstraint(D6_SPRING_2_CONSTRAINT_TYPE, rbA, rbB) + , m_frameInA(frameInA) + , m_frameInB(frameInB) + , m_rotateOrder(rotOrder) + , m_flags(0) +{ + calculateTransforms(); +} + + +btGeneric6DofSpring2Constraint::btGeneric6DofSpring2Constraint(btRigidBody& rbB, const btTransform& frameInB, RotateOrder rotOrder) + : btTypedConstraint(D6_SPRING_2_CONSTRAINT_TYPE, getFixedBody(), rbB) + , m_frameInB(frameInB) + , m_rotateOrder(rotOrder) + , m_flags(0) +{ + ///not providing rigidbody A means implicitly using worldspace for body A + m_frameInA = rbB.getCenterOfMassTransform() * m_frameInB; + calculateTransforms(); +} + + +btScalar btGeneric6DofSpring2Constraint::btGetMatrixElem(const btMatrix3x3& mat, int index) +{ + int i = index%3; + int j = index/3; + return mat[i][j]; +} + +// MatrixToEulerXYZ from http://www.geometrictools.com/LibFoundation/Mathematics/Wm4Matrix3.inl.html + +bool btGeneric6DofSpring2Constraint::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 + + btScalar fi = btGetMatrixElem(mat,2); + if (fi < btScalar(1.0f)) + { + if (fi > btScalar(-1.0f)) + { + xyz[0] = btAtan2(-btGetMatrixElem(mat,5),btGetMatrixElem(mat,8)); + xyz[1] = btAsin(btGetMatrixElem(mat,2)); + xyz[2] = btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0)); + return true; + } + else + { + // WARNING. Not unique. XA - ZA = -atan2(r10,r11) + xyz[0] = -btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(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(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4)); + xyz[1] = SIMD_HALF_PI; + xyz[2] = 0.0; + } + return false; +} + +bool btGeneric6DofSpring2Constraint::matrixToEulerXZY(const btMatrix3x3& mat,btVector3& xyz) +{ + // rot = cy*cz -sz sy*cz + // cy*cx*sz+sx*sy cx*cz sy*cx*sz-cy*sx + // cy*sx*sz-cx*sy sx*cz sy*sx*sz+cx*cy + + btScalar fi = btGetMatrixElem(mat,1); + if (fi < btScalar(1.0f)) + { + if (fi > btScalar(-1.0f)) + { + xyz[0] = btAtan2(btGetMatrixElem(mat,7),btGetMatrixElem(mat,4)); + xyz[1] = btAtan2(btGetMatrixElem(mat,2),btGetMatrixElem(mat,0)); + xyz[2] = btAsin(-btGetMatrixElem(mat,1)); + return true; + } + else + { + xyz[0] = -btAtan2(-btGetMatrixElem(mat,6),btGetMatrixElem(mat,8)); + xyz[1] = btScalar(0.0); + xyz[2] = SIMD_HALF_PI; + return false; + } + } + else + { + xyz[0] = btAtan2(-btGetMatrixElem(mat,6),btGetMatrixElem(mat,8)); + xyz[1] = 0.0; + xyz[2] = -SIMD_HALF_PI; + } + return false; +} + +bool btGeneric6DofSpring2Constraint::matrixToEulerYXZ(const btMatrix3x3& mat,btVector3& xyz) +{ + // rot = cy*cz+sy*sx*sz cz*sy*sx-cy*sz cx*sy + // cx*sz cx*cz -sx + // cy*sx*sz-cz*sy sy*sz+cy*cz*sx cy*cx + + btScalar fi = btGetMatrixElem(mat,5); + if (fi < btScalar(1.0f)) + { + if (fi > btScalar(-1.0f)) + { + xyz[0] = btAsin(-btGetMatrixElem(mat,5)); + xyz[1] = btAtan2(btGetMatrixElem(mat,2),btGetMatrixElem(mat,8)); + xyz[2] = btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4)); + return true; + } + else + { + xyz[0] = SIMD_HALF_PI; + xyz[1] = -btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0)); + xyz[2] = btScalar(0.0); + return false; + } + } + else + { + xyz[0] = -SIMD_HALF_PI; + xyz[1] = btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0)); + xyz[2] = 0.0; + } + return false; +} + +bool btGeneric6DofSpring2Constraint::matrixToEulerYZX(const btMatrix3x3& mat,btVector3& xyz) +{ + // rot = cy*cz sy*sx-cy*cx*sz cx*sy+cy*sz*sx + // sz cz*cx -cz*sx + // -cz*sy cy*sx+cx*sy*sz cy*cx-sy*sz*sx + + btScalar fi = btGetMatrixElem(mat,3); + if (fi < btScalar(1.0f)) + { + if (fi > btScalar(-1.0f)) + { + xyz[0] = btAtan2(-btGetMatrixElem(mat,5),btGetMatrixElem(mat,4)); + xyz[1] = btAtan2(-btGetMatrixElem(mat,6),btGetMatrixElem(mat,0)); + xyz[2] = btAsin(btGetMatrixElem(mat,3)); + return true; + } + else + { + xyz[0] = btScalar(0.0); + xyz[1] = -btAtan2(btGetMatrixElem(mat,7),btGetMatrixElem(mat,8)); + xyz[2] = -SIMD_HALF_PI; + return false; + } + } + else + { + xyz[0] = btScalar(0.0); + xyz[1] = btAtan2(btGetMatrixElem(mat,7),btGetMatrixElem(mat,8)); + xyz[2] = SIMD_HALF_PI; + } + return false; +} + +bool btGeneric6DofSpring2Constraint::matrixToEulerZXY(const btMatrix3x3& mat,btVector3& xyz) +{ + // rot = cz*cy-sz*sx*sy -cx*sz cz*sy+cy*sz*sx + // cy*sz+cz*sx*sy cz*cx sz*sy-cz*xy*sx + // -cx*sy sx cx*cy + + btScalar fi = btGetMatrixElem(mat,7); + if (fi < btScalar(1.0f)) + { + if (fi > btScalar(-1.0f)) + { + xyz[0] = btAsin(btGetMatrixElem(mat,7)); + xyz[1] = btAtan2(-btGetMatrixElem(mat,6),btGetMatrixElem(mat,8)); + xyz[2] = btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,4)); + return true; + } + else + { + xyz[0] = -SIMD_HALF_PI; + xyz[1] = btScalar(0.0); + xyz[2] = -btAtan2(btGetMatrixElem(mat,2),btGetMatrixElem(mat,0)); + return false; + } + } + else + { + xyz[0] = SIMD_HALF_PI; + xyz[1] = btScalar(0.0); + xyz[2] = btAtan2(btGetMatrixElem(mat,2),btGetMatrixElem(mat,0)); + } + return false; +} + +bool btGeneric6DofSpring2Constraint::matrixToEulerZYX(const btMatrix3x3& mat,btVector3& xyz) +{ + // rot = cz*cy cz*sy*sx-cx*sz sz*sx+cz*cx*sy + // cy*sz cz*cx+sz*sy*sx cx*sz*sy-cz*sx + // -sy cy*sx cy*cx + + btScalar fi = btGetMatrixElem(mat,6); + if (fi < btScalar(1.0f)) + { + if (fi > btScalar(-1.0f)) + { + xyz[0] = btAtan2(btGetMatrixElem(mat,7), btGetMatrixElem(mat,8)); + xyz[1] = btAsin(-btGetMatrixElem(mat,6)); + xyz[2] = btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,0)); + return true; + } + else + { + xyz[0] = btScalar(0.0); + xyz[1] = SIMD_HALF_PI; + xyz[2] = -btAtan2(btGetMatrixElem(mat,1),btGetMatrixElem(mat,2)); + return false; + } + } + else + { + xyz[0] = btScalar(0.0); + xyz[1] = -SIMD_HALF_PI; + xyz[2] = btAtan2(-btGetMatrixElem(mat,1),-btGetMatrixElem(mat,2)); + } + return false; +} + +void btGeneric6DofSpring2Constraint::calculateAngleInfo() +{ + btMatrix3x3 relative_frame = m_calculatedTransformA.getBasis().inverse()*m_calculatedTransformB.getBasis(); + switch (m_rotateOrder) + { + case RO_XYZ : matrixToEulerXYZ(relative_frame,m_calculatedAxisAngleDiff); break; + case RO_XZY : matrixToEulerXZY(relative_frame,m_calculatedAxisAngleDiff); break; + case RO_YXZ : matrixToEulerYXZ(relative_frame,m_calculatedAxisAngleDiff); break; + case RO_YZX : matrixToEulerYZX(relative_frame,m_calculatedAxisAngleDiff); break; + case RO_ZXY : matrixToEulerZXY(relative_frame,m_calculatedAxisAngleDiff); break; + case RO_ZYX : matrixToEulerZYX(relative_frame,m_calculatedAxisAngleDiff); break; + default : btAssert(false); + } + // 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. + switch (m_rotateOrder) + { + case RO_XYZ : + { + //Is this the "line of nodes" calculation choosing planes YZ (B coordinate system) and xy (A coordinate system)? (http://en.wikipedia.org/wiki/Euler_angles) + //The two planes are non-homologous, so this is a Tait–Bryan angle formalism and not a proper Euler + //Extrinsic rotations are equal to the reversed order intrinsic rotations so the above xyz extrinsic rotations (axes are fixed) are the same as the zy'x" intrinsic rotations (axes are refreshed after each rotation) + //that is why xy and YZ planes are chosen (this will describe a zy'x" intrinsic rotation) (see the figure on the left at http://en.wikipedia.org/wiki/Euler_angles under Tait–Bryan angles) + // x' = Nperp = N.cross(axis2) + // y' = N = axis2.cross(axis0) + // z' = z + // + // x" = X + // y" = y' + // z" = ?? + //in other words: + //first rotate around z + //second rotate around y'= z.cross(X) + //third rotate around x" = X + //Original XYZ extrinsic rotation order. + //Planes: xy and YZ normals: z, X. Plane intersection (N) is z.cross(X) + btVector3 axis0 = m_calculatedTransformB.getBasis().getColumn(0); + btVector3 axis2 = m_calculatedTransformA.getBasis().getColumn(2); + m_calculatedAxis[1] = axis2.cross(axis0); + m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2); + m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]); + break; + } + case RO_XZY : + { + //planes: xz,ZY normals: y, X + //first rotate around y + //second rotate around z'= y.cross(X) + //third rotate around x" = X + btVector3 axis0 = m_calculatedTransformB.getBasis().getColumn(0); + btVector3 axis1 = m_calculatedTransformA.getBasis().getColumn(1); + m_calculatedAxis[2] = axis0.cross(axis1); + m_calculatedAxis[0] = axis1.cross(m_calculatedAxis[2]); + m_calculatedAxis[1] = m_calculatedAxis[2].cross(axis0); + break; + } + case RO_YXZ : + { + //planes: yx,XZ normals: z, Y + //first rotate around z + //second rotate around x'= z.cross(Y) + //third rotate around y" = Y + btVector3 axis1 = m_calculatedTransformB.getBasis().getColumn(1); + btVector3 axis2 = m_calculatedTransformA.getBasis().getColumn(2); + m_calculatedAxis[0] = axis1.cross(axis2); + m_calculatedAxis[1] = axis2.cross(m_calculatedAxis[0]); + m_calculatedAxis[2] = m_calculatedAxis[0].cross(axis1); + break; + } + case RO_YZX : + { + //planes: yz,ZX normals: x, Y + //first rotate around x + //second rotate around z'= x.cross(Y) + //third rotate around y" = Y + btVector3 axis0 = m_calculatedTransformA.getBasis().getColumn(0); + btVector3 axis1 = m_calculatedTransformB.getBasis().getColumn(1); + m_calculatedAxis[2] = axis0.cross(axis1); + m_calculatedAxis[0] = axis1.cross(m_calculatedAxis[2]); + m_calculatedAxis[1] = m_calculatedAxis[2].cross(axis0); + break; + } + case RO_ZXY : + { + //planes: zx,XY normals: y, Z + //first rotate around y + //second rotate around x'= y.cross(Z) + //third rotate around z" = Z + btVector3 axis1 = m_calculatedTransformA.getBasis().getColumn(1); + btVector3 axis2 = m_calculatedTransformB.getBasis().getColumn(2); + m_calculatedAxis[0] = axis1.cross(axis2); + m_calculatedAxis[1] = axis2.cross(m_calculatedAxis[0]); + m_calculatedAxis[2] = m_calculatedAxis[0].cross(axis1); + break; + } + case RO_ZYX : + { + //planes: zy,YX normals: x, Z + //first rotate around x + //second rotate around y' = x.cross(Z) + //third rotate around z" = Z + btVector3 axis0 = m_calculatedTransformA.getBasis().getColumn(0); + btVector3 axis2 = m_calculatedTransformB.getBasis().getColumn(2); + m_calculatedAxis[1] = axis2.cross(axis0); + m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2); + m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]); + break; + } + default: + btAssert(false); + } + + m_calculatedAxis[0].normalize(); + m_calculatedAxis[1].normalize(); + m_calculatedAxis[2].normalize(); + +} + +void btGeneric6DofSpring2Constraint::calculateTransforms() +{ + calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); +} + +void btGeneric6DofSpring2Constraint::calculateTransforms(const btTransform& transA,const btTransform& transB) +{ + m_calculatedTransformA = transA * m_frameInA; + m_calculatedTransformB = transB * m_frameInB; + calculateLinearInfo(); + calculateAngleInfo(); + + btScalar miA = getRigidBodyA().getInvMass(); + btScalar miB = getRigidBodyB().getInvMass(); + m_hasStaticBody = (miA < SIMD_EPSILON) || (miB < SIMD_EPSILON); + btScalar miS = miA + miB; + if(miS > btScalar(0.f)) + { + m_factA = miB / miS; + } + else + { + m_factA = btScalar(0.5f); + } + m_factB = btScalar(1.0f) - m_factA; +} + + +void btGeneric6DofSpring2Constraint::testAngularLimitMotor(int axis_index) +{ + btScalar angle = m_calculatedAxisAngleDiff[axis_index]; + angle = btAdjustAngleToLimits(angle, m_angularLimits[axis_index].m_loLimit, m_angularLimits[axis_index].m_hiLimit); + m_angularLimits[axis_index].m_currentPosition = angle; + m_angularLimits[axis_index].testLimitValue(angle); +} + + +void btGeneric6DofSpring2Constraint::getInfo1 (btConstraintInfo1* info) +{ + //prepare constraint + calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); + info->m_numConstraintRows = 0; + info->nub = 0; + int i; + //test linear limits + for(i = 0; i < 3; i++) + { + if (m_linearLimits.m_currentLimit[i]==4) info->m_numConstraintRows += 2; + else if (m_linearLimits.m_currentLimit[i]!=0) info->m_numConstraintRows += 1; + if (m_linearLimits.m_enableMotor[i] ) info->m_numConstraintRows += 1; + if (m_linearLimits.m_enableSpring[i]) info->m_numConstraintRows += 1; + } + //test angular limits + for (i=0;i<3 ;i++ ) + { + testAngularLimitMotor(i); + if (m_angularLimits[i].m_currentLimit==4) info->m_numConstraintRows += 2; + else if (m_angularLimits[i].m_currentLimit!=0) info->m_numConstraintRows += 1; + if (m_angularLimits[i].m_enableMotor ) info->m_numConstraintRows += 1; + if (m_angularLimits[i].m_enableSpring) info->m_numConstraintRows += 1; + } +} + + +void btGeneric6DofSpring2Constraint::getInfo2 (btConstraintInfo2* info) +{ + const btTransform& transA = m_rbA.getCenterOfMassTransform(); + const btTransform& transB = m_rbB.getCenterOfMassTransform(); + const btVector3& linVelA = m_rbA.getLinearVelocity(); + const btVector3& linVelB = m_rbB.getLinearVelocity(); + const btVector3& angVelA = m_rbA.getAngularVelocity(); + const btVector3& angVelB = m_rbB.getAngularVelocity(); + + // for stability better to solve angular limits first + int row = setAngularLimits(info, 0,transA,transB,linVelA,linVelB,angVelA,angVelB); + setLinearLimits(info, row, transA,transB,linVelA,linVelB,angVelA,angVelB); +} + + +int btGeneric6DofSpring2Constraint::setLinearLimits(btConstraintInfo2* info, int row, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB) +{ + //solve linear limits + btRotationalLimitMotor2 limot; + for (int i=0;i<3 ;i++ ) + { + if(m_linearLimits.m_currentLimit[i] || m_linearLimits.m_enableMotor[i] || m_linearLimits.m_enableSpring[i]) + { // re-use rotational motor code + limot.m_bounce = m_linearLimits.m_bounce[i]; + limot.m_currentLimit = m_linearLimits.m_currentLimit[i]; + limot.m_currentPosition = m_linearLimits.m_currentLinearDiff[i]; + limot.m_currentLimitError = m_linearLimits.m_currentLimitError[i]; + limot.m_currentLimitErrorHi = m_linearLimits.m_currentLimitErrorHi[i]; + limot.m_enableMotor = m_linearLimits.m_enableMotor[i]; + limot.m_servoMotor = m_linearLimits.m_servoMotor[i]; + limot.m_servoTarget = m_linearLimits.m_servoTarget[i]; + limot.m_enableSpring = m_linearLimits.m_enableSpring[i]; + limot.m_springStiffness = m_linearLimits.m_springStiffness[i]; + limot.m_springStiffnessLimited = m_linearLimits.m_springStiffnessLimited[i]; + limot.m_springDamping = m_linearLimits.m_springDamping[i]; + limot.m_springDampingLimited = m_linearLimits.m_springDampingLimited[i]; + limot.m_equilibriumPoint = m_linearLimits.m_equilibriumPoint[i]; + limot.m_hiLimit = m_linearLimits.m_upperLimit[i]; + limot.m_loLimit = m_linearLimits.m_lowerLimit[i]; + limot.m_maxMotorForce = m_linearLimits.m_maxMotorForce[i]; + limot.m_targetVelocity = m_linearLimits.m_targetVelocity[i]; + btVector3 axis = m_calculatedTransformA.getBasis().getColumn(i); + int flags = m_flags >> (i * BT_6DOF_FLAGS_AXIS_SHIFT2); + limot.m_stopCFM = (flags & BT_6DOF_FLAGS_CFM_STOP2) ? m_linearLimits.m_stopCFM[i] : info->cfm[0]; + limot.m_stopERP = (flags & BT_6DOF_FLAGS_ERP_STOP2) ? m_linearLimits.m_stopERP[i] : info->erp; + limot.m_motorCFM = (flags & BT_6DOF_FLAGS_CFM_MOTO2) ? m_linearLimits.m_motorCFM[i] : info->cfm[0]; + limot.m_motorERP = (flags & BT_6DOF_FLAGS_ERP_MOTO2) ? m_linearLimits.m_motorERP[i] : info->erp; + + //rotAllowed is a bit of a magic from the original 6dof. The calculation of it here is something that imitates the original behavior as much as possible. + int indx1 = (i + 1) % 3; + int indx2 = (i + 2) % 3; + int rotAllowed = 1; // rotations around orthos to current axis (it is used only when one of the body is static) + #define D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION 1.0e-3 + bool indx1Violated = m_angularLimits[indx1].m_currentLimit == 1 || + m_angularLimits[indx1].m_currentLimit == 2 || + ( m_angularLimits[indx1].m_currentLimit == 3 && ( m_angularLimits[indx1].m_currentLimitError < -D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION || m_angularLimits[indx1].m_currentLimitError > D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION ) ) || + ( m_angularLimits[indx1].m_currentLimit == 4 && ( m_angularLimits[indx1].m_currentLimitError < -D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION || m_angularLimits[indx1].m_currentLimitErrorHi > D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION ) ); + bool indx2Violated = m_angularLimits[indx2].m_currentLimit == 1 || + m_angularLimits[indx2].m_currentLimit == 2 || + ( m_angularLimits[indx2].m_currentLimit == 3 && ( m_angularLimits[indx2].m_currentLimitError < -D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION || m_angularLimits[indx2].m_currentLimitError > D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION ) ) || + ( m_angularLimits[indx2].m_currentLimit == 4 && ( m_angularLimits[indx2].m_currentLimitError < -D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION || m_angularLimits[indx2].m_currentLimitErrorHi > D6_LIMIT_ERROR_THRESHOLD_FOR_ROTATION ) ); + if( indx1Violated && indx2Violated ) + { + rotAllowed = 0; + } + row += get_limit_motor_info2(&limot, transA,transB,linVelA,linVelB,angVelA,angVelB, info, row, axis, 0, rotAllowed); + + } + } + return row; +} + + + +int btGeneric6DofSpring2Constraint::setAngularLimits(btConstraintInfo2 *info, int row_offset, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB) +{ + int row = row_offset; + + //order of rotational constraint rows + int cIdx[] = {0, 1, 2}; + switch(m_rotateOrder) + { + case RO_XYZ : cIdx[0] = 0; cIdx[1] = 1; cIdx[2] = 2; break; + case RO_XZY : cIdx[0] = 0; cIdx[1] = 2; cIdx[2] = 1; break; + case RO_YXZ : cIdx[0] = 1; cIdx[1] = 0; cIdx[2] = 2; break; + case RO_YZX : cIdx[0] = 1; cIdx[1] = 2; cIdx[2] = 0; break; + case RO_ZXY : cIdx[0] = 2; cIdx[1] = 0; cIdx[2] = 1; break; + case RO_ZYX : cIdx[0] = 2; cIdx[1] = 1; cIdx[2] = 0; break; + default : btAssert(false); + } + + for (int ii = 0; ii < 3 ; ii++ ) + { + int i = cIdx[ii]; + if(m_angularLimits[i].m_currentLimit || m_angularLimits[i].m_enableMotor || m_angularLimits[i].m_enableSpring) + { + btVector3 axis = getAxis(i); + int flags = m_flags >> ((i + 3) * BT_6DOF_FLAGS_AXIS_SHIFT2); + if(!(flags & BT_6DOF_FLAGS_CFM_STOP2)) + { + m_angularLimits[i].m_stopCFM = info->cfm[0]; + } + if(!(flags & BT_6DOF_FLAGS_ERP_STOP2)) + { + m_angularLimits[i].m_stopERP = info->erp; + } + if(!(flags & BT_6DOF_FLAGS_CFM_MOTO2)) + { + m_angularLimits[i].m_motorCFM = info->cfm[0]; + } + if(!(flags & BT_6DOF_FLAGS_ERP_MOTO2)) + { + m_angularLimits[i].m_motorERP = info->erp; + } + row += get_limit_motor_info2(&m_angularLimits[i],transA,transB,linVelA,linVelB,angVelA,angVelB, info,row,axis,1); + } + } + + return row; +} + + +void btGeneric6DofSpring2Constraint::setFrames(const btTransform& frameA, const btTransform& frameB) +{ + m_frameInA = frameA; + m_frameInB = frameB; + buildJacobian(); + calculateTransforms(); +} + + +void btGeneric6DofSpring2Constraint::calculateLinearInfo() +{ + m_calculatedLinearDiff = m_calculatedTransformB.getOrigin() - m_calculatedTransformA.getOrigin(); + m_calculatedLinearDiff = m_calculatedTransformA.getBasis().inverse() * m_calculatedLinearDiff; + for(int i = 0; i < 3; i++) + { + m_linearLimits.m_currentLinearDiff[i] = m_calculatedLinearDiff[i]; + m_linearLimits.testLimitValue(i, m_calculatedLinearDiff[i]); + } +} + +void btGeneric6DofSpring2Constraint::calculateJacobi(btRotationalLimitMotor2 * limot, const btTransform& transA,const btTransform& transB, btConstraintInfo2 *info, int srow, btVector3& ax1, int rotational, int rotAllowed) +{ + btScalar *J1 = rotational ? info->m_J1angularAxis : info->m_J1linearAxis; + btScalar *J2 = rotational ? info->m_J2angularAxis : info->m_J2linearAxis; + + J1[srow+0] = ax1[0]; + J1[srow+1] = ax1[1]; + J1[srow+2] = ax1[2]; + + J2[srow+0] = -ax1[0]; + J2[srow+1] = -ax1[1]; + J2[srow+2] = -ax1[2]; + + if(!rotational) + { + btVector3 tmpA, tmpB, relA, relB; + // get vector from bodyB to frameB in WCS + relB = m_calculatedTransformB.getOrigin() - transB.getOrigin(); + // same for bodyA + relA = m_calculatedTransformA.getOrigin() - transA.getOrigin(); + tmpA = relA.cross(ax1); + tmpB = relB.cross(ax1); + if(m_hasStaticBody && (!rotAllowed)) + { + tmpA *= m_factA; + tmpB *= m_factB; + } + int i; + for (i=0; i<3; i++) info->m_J1angularAxis[srow+i] = tmpA[i]; + for (i=0; i<3; i++) info->m_J2angularAxis[srow+i] = -tmpB[i]; + } +} + + +int btGeneric6DofSpring2Constraint::get_limit_motor_info2( + btRotationalLimitMotor2 * limot, + const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB, + btConstraintInfo2 *info, int row, btVector3& ax1, int rotational,int rotAllowed) +{ + int count = 0; + int srow = row * info->rowskip; + + if (limot->m_currentLimit==4) + { + btScalar vel = rotational ? angVelA.dot(ax1) - angVelB.dot(ax1) : linVelA.dot(ax1) - linVelB.dot(ax1); + + calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed); + info->m_constraintError[srow] = info->fps * limot->m_stopERP * limot->m_currentLimitError * (rotational ? -1 : 1); + if (rotational) { + if (info->m_constraintError[srow]-vel*limot->m_stopERP > 0) { + btScalar bounceerror = -limot->m_bounce* vel; + if (bounceerror > info->m_constraintError[srow]) info->m_constraintError[srow] = bounceerror; + } + } else { + if (info->m_constraintError[srow]-vel*limot->m_stopERP < 0) { + btScalar bounceerror = -limot->m_bounce* vel; + if (bounceerror < info->m_constraintError[srow]) info->m_constraintError[srow] = bounceerror; + } + } + info->m_lowerLimit[srow] = rotational ? 0 : -SIMD_INFINITY; + info->m_upperLimit[srow] = rotational ? SIMD_INFINITY : 0; + info->cfm[srow] = limot->m_stopCFM; + srow += info->rowskip; + ++count; + + calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed); + info->m_constraintError[srow] = info->fps * limot->m_stopERP * limot->m_currentLimitErrorHi * (rotational ? -1 : 1); + if (rotational) { + if (info->m_constraintError[srow]-vel*limot->m_stopERP < 0) { + btScalar bounceerror = -limot->m_bounce* vel; + if (bounceerror < info->m_constraintError[srow]) info->m_constraintError[srow] = bounceerror; + } + } else { + if (info->m_constraintError[srow]-vel*limot->m_stopERP > 0) { + btScalar bounceerror = -limot->m_bounce* vel; + if (bounceerror > info->m_constraintError[srow]) info->m_constraintError[srow] = bounceerror; + } + } + info->m_lowerLimit[srow] = rotational ? -SIMD_INFINITY : 0; + info->m_upperLimit[srow] = rotational ? 0 : SIMD_INFINITY; + info->cfm[srow] = limot->m_stopCFM; + srow += info->rowskip; + ++count; + } else + if (limot->m_currentLimit==3) + { + calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed); + info->m_constraintError[srow] = info->fps * limot->m_stopERP * limot->m_currentLimitError * (rotational ? -1 : 1); + info->m_lowerLimit[srow] = -SIMD_INFINITY; + info->m_upperLimit[srow] = SIMD_INFINITY; + info->cfm[srow] = limot->m_stopCFM; + srow += info->rowskip; + ++count; + } + + if (limot->m_enableMotor && !limot->m_servoMotor) + { + calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed); + btScalar tag_vel = rotational ? limot->m_targetVelocity : -limot->m_targetVelocity; + btScalar mot_fact = getMotorFactor(limot->m_currentPosition, + limot->m_loLimit, + limot->m_hiLimit, + tag_vel, + info->fps * limot->m_motorERP); + info->m_constraintError[srow] = mot_fact * limot->m_targetVelocity; + info->m_lowerLimit[srow] = -limot->m_maxMotorForce; + info->m_upperLimit[srow] = limot->m_maxMotorForce; + info->cfm[srow] = limot->m_motorCFM; + srow += info->rowskip; + ++count; + } + + if (limot->m_enableMotor && limot->m_servoMotor) + { + btScalar error = limot->m_currentPosition - limot->m_servoTarget; + btScalar curServoTarget = limot->m_servoTarget; + if (rotational) + { + if (error > SIMD_PI) + { + error -= SIMD_2_PI; + curServoTarget +=SIMD_2_PI; + } + if (error < -SIMD_PI) + { + error += SIMD_2_PI; + curServoTarget -=SIMD_2_PI; + } + } + + calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed); + btScalar targetvelocity = error<0 ? -limot->m_targetVelocity : limot->m_targetVelocity; + btScalar tag_vel = -targetvelocity; + btScalar mot_fact; + if(error != 0) + { + btScalar lowLimit; + btScalar hiLimit; + if(limot->m_loLimit > limot->m_hiLimit) + { + lowLimit = error > 0 ? curServoTarget : -SIMD_INFINITY; + hiLimit = error < 0 ? curServoTarget : SIMD_INFINITY; + } + else + { + lowLimit = error > 0 && curServoTarget>limot->m_loLimit ? curServoTarget : limot->m_loLimit; + hiLimit = error < 0 && curServoTargetm_hiLimit ? curServoTarget : limot->m_hiLimit; + } + mot_fact = getMotorFactor(limot->m_currentPosition, lowLimit, hiLimit, tag_vel, info->fps * limot->m_motorERP); + } + else + { + mot_fact = 0; + } + info->m_constraintError[srow] = mot_fact * targetvelocity * (rotational ? -1 : 1); + info->m_lowerLimit[srow] = -limot->m_maxMotorForce; + info->m_upperLimit[srow] = limot->m_maxMotorForce; + info->cfm[srow] = limot->m_motorCFM; + srow += info->rowskip; + ++count; + } + + if (limot->m_enableSpring) + { + btScalar error = limot->m_currentPosition - limot->m_equilibriumPoint; + calculateJacobi(limot,transA,transB,info,srow,ax1,rotational,rotAllowed); + + //btScalar cfm = 1.0 / ((1.0/info->fps)*limot->m_springStiffness+ limot->m_springDamping); + //if(cfm > 0.99999) + // cfm = 0.99999; + //btScalar erp = (1.0/info->fps)*limot->m_springStiffness / ((1.0/info->fps)*limot->m_springStiffness + limot->m_springDamping); + //info->m_constraintError[srow] = info->fps * erp * error * (rotational ? -1.0 : 1.0); + //info->m_lowerLimit[srow] = -SIMD_INFINITY; + //info->m_upperLimit[srow] = SIMD_INFINITY; + + btScalar dt = BT_ONE / info->fps; + btScalar kd = limot->m_springDamping; + btScalar ks = limot->m_springStiffness; + btScalar vel = rotational ? angVelA.dot(ax1) - angVelB.dot(ax1) : linVelA.dot(ax1) - linVelB.dot(ax1); +// btScalar erp = 0.1; + btScalar cfm = BT_ZERO; + btScalar mA = BT_ONE / m_rbA.getInvMass(); + btScalar mB = BT_ONE / m_rbB.getInvMass(); + btScalar m = mA > mB ? mB : mA; + btScalar angularfreq = sqrt(ks / m); + + + //limit stiffness (the spring should not be sampled faster that the quarter of its angular frequency) + if(limot->m_springStiffnessLimited && 0.25 < angularfreq * dt) + { + ks = BT_ONE / dt / dt / btScalar(16.0) * m; + } + //avoid damping that would blow up the spring + if(limot->m_springDampingLimited && kd * dt > m) + { + kd = m / dt; + } + btScalar fs = ks * error * dt; + btScalar fd = -kd * (vel) * (rotational ? -1 : 1) * dt; + btScalar f = (fs+fd); + + info->m_constraintError[srow] = (vel + f * (rotational ? -1 : 1)) ; + + btScalar minf = f < fd ? f : fd; + btScalar maxf = f < fd ? fd : f; + if(!rotational) + { + info->m_lowerLimit[srow] = minf > 0 ? 0 : minf; + info->m_upperLimit[srow] = maxf < 0 ? 0 : maxf; + } + else + { + info->m_lowerLimit[srow] = -maxf > 0 ? 0 : -maxf; + info->m_upperLimit[srow] = -minf < 0 ? 0 : -minf; + } + + info->cfm[srow] = cfm; + srow += info->rowskip; + ++count; + } + + return count; +} + + +//override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). +//If no axis is provided, it uses the default axis for this constraint. +void btGeneric6DofSpring2Constraint::setParam(int num, btScalar value, int axis) +{ + if((axis >= 0) && (axis < 3)) + { + switch(num) + { + case BT_CONSTRAINT_STOP_ERP : + m_linearLimits.m_stopERP[axis] = value; + m_flags |= BT_6DOF_FLAGS_ERP_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2); + break; + case BT_CONSTRAINT_STOP_CFM : + m_linearLimits.m_stopCFM[axis] = value; + m_flags |= BT_6DOF_FLAGS_CFM_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2); + break; + case BT_CONSTRAINT_ERP : + m_linearLimits.m_motorERP[axis] = value; + m_flags |= BT_6DOF_FLAGS_ERP_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2); + break; + case BT_CONSTRAINT_CFM : + m_linearLimits.m_motorCFM[axis] = value; + m_flags |= BT_6DOF_FLAGS_CFM_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2); + break; + default : + btAssertConstrParams(0); + } + } + else if((axis >=3) && (axis < 6)) + { + switch(num) + { + case BT_CONSTRAINT_STOP_ERP : + m_angularLimits[axis - 3].m_stopERP = value; + m_flags |= BT_6DOF_FLAGS_ERP_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2); + break; + case BT_CONSTRAINT_STOP_CFM : + m_angularLimits[axis - 3].m_stopCFM = value; + m_flags |= BT_6DOF_FLAGS_CFM_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2); + break; + case BT_CONSTRAINT_ERP : + m_angularLimits[axis - 3].m_motorERP = value; + m_flags |= BT_6DOF_FLAGS_ERP_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2); + break; + case BT_CONSTRAINT_CFM : + m_angularLimits[axis - 3].m_motorCFM = value; + m_flags |= BT_6DOF_FLAGS_CFM_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2); + break; + default : + btAssertConstrParams(0); + } + } + else + { + btAssertConstrParams(0); + } +} + +//return the local value of parameter +btScalar btGeneric6DofSpring2Constraint::getParam(int num, int axis) const +{ + btScalar retVal = 0; + if((axis >= 0) && (axis < 3)) + { + switch(num) + { + case BT_CONSTRAINT_STOP_ERP : + btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2))); + retVal = m_linearLimits.m_stopERP[axis]; + break; + case BT_CONSTRAINT_STOP_CFM : + btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2))); + retVal = m_linearLimits.m_stopCFM[axis]; + break; + case BT_CONSTRAINT_ERP : + btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2))); + retVal = m_linearLimits.m_motorERP[axis]; + break; + case BT_CONSTRAINT_CFM : + btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2))); + retVal = m_linearLimits.m_motorCFM[axis]; + break; + default : + btAssertConstrParams(0); + } + } + else if((axis >=3) && (axis < 6)) + { + switch(num) + { + case BT_CONSTRAINT_STOP_ERP : + btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2))); + retVal = m_angularLimits[axis - 3].m_stopERP; + break; + case BT_CONSTRAINT_STOP_CFM : + btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_STOP2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2))); + retVal = m_angularLimits[axis - 3].m_stopCFM; + break; + case BT_CONSTRAINT_ERP : + btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2))); + retVal = m_angularLimits[axis - 3].m_motorERP; + break; + case BT_CONSTRAINT_CFM : + btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_MOTO2 << (axis * BT_6DOF_FLAGS_AXIS_SHIFT2))); + retVal = m_angularLimits[axis - 3].m_motorCFM; + break; + default : + btAssertConstrParams(0); + } + } + else + { + btAssertConstrParams(0); + } + return retVal; +} + + + +void btGeneric6DofSpring2Constraint::setAxis(const btVector3& axis1,const btVector3& axis2) +{ + btVector3 zAxis = axis1.normalized(); + btVector3 yAxis = axis2.normalized(); + btVector3 xAxis = yAxis.cross(zAxis); // we want right coordinate system + + btTransform frameInW; + frameInW.setIdentity(); + frameInW.getBasis().setValue( xAxis[0], yAxis[0], zAxis[0], + xAxis[1], yAxis[1], zAxis[1], + xAxis[2], yAxis[2], zAxis[2]); + + // now get constraint frame in local coordinate systems + m_frameInA = m_rbA.getCenterOfMassTransform().inverse() * frameInW; + m_frameInB = m_rbB.getCenterOfMassTransform().inverse() * frameInW; + + calculateTransforms(); +} + +void btGeneric6DofSpring2Constraint::setBounce(int index, btScalar bounce) +{ + btAssert((index >= 0) && (index < 6)); + if (index<3) + m_linearLimits.m_bounce[index] = bounce; + else + m_angularLimits[index - 3].m_bounce = bounce; +} + +void btGeneric6DofSpring2Constraint::enableMotor(int index, bool onOff) +{ + btAssert((index >= 0) && (index < 6)); + if (index<3) + m_linearLimits.m_enableMotor[index] = onOff; + else + m_angularLimits[index - 3].m_enableMotor = onOff; +} + +void btGeneric6DofSpring2Constraint::setServo(int index, bool onOff) +{ + btAssert((index >= 0) && (index < 6)); + if (index<3) + m_linearLimits.m_servoMotor[index] = onOff; + else + m_angularLimits[index - 3].m_servoMotor = onOff; +} + +void btGeneric6DofSpring2Constraint::setTargetVelocity(int index, btScalar velocity) +{ + btAssert((index >= 0) && (index < 6)); + if (index<3) + m_linearLimits.m_targetVelocity[index] = velocity; + else + m_angularLimits[index - 3].m_targetVelocity = velocity; +} + + + +void btGeneric6DofSpring2Constraint::setServoTarget(int index, btScalar targetOrg) +{ + btAssert((index >= 0) && (index < 6)); + if (index<3) + { + m_linearLimits.m_servoTarget[index] = targetOrg; + } + else + { + //wrap between -PI and PI, see also + //https://stackoverflow.com/questions/4633177/c-how-to-wrap-a-float-to-the-interval-pi-pi + + btScalar target = targetOrg+SIMD_PI; + if (1) + { + btScalar m = target - SIMD_2_PI * floor(target/SIMD_2_PI); + // handle boundary cases resulted from floating-point cut off: + { + if (m>=SIMD_2_PI) + { + target = 0; + } else + { + if (m<0 ) + { + if (SIMD_2_PI+m == SIMD_2_PI) + target = 0; + else + target = SIMD_2_PI+m; + } + else + { + target = m; + } + } + } + target -= SIMD_PI; + } + + m_angularLimits[index - 3].m_servoTarget = target; + } +} + +void btGeneric6DofSpring2Constraint::setMaxMotorForce(int index, btScalar force) +{ + btAssert((index >= 0) && (index < 6)); + if (index<3) + m_linearLimits.m_maxMotorForce[index] = force; + else + m_angularLimits[index - 3].m_maxMotorForce = force; +} + +void btGeneric6DofSpring2Constraint::enableSpring(int index, bool onOff) +{ + btAssert((index >= 0) && (index < 6)); + if (index<3) + m_linearLimits.m_enableSpring[index] = onOff; + else + m_angularLimits[index - 3] .m_enableSpring = onOff; +} + +void btGeneric6DofSpring2Constraint::setStiffness(int index, btScalar stiffness, bool limitIfNeeded) +{ + btAssert((index >= 0) && (index < 6)); + if (index<3) { + m_linearLimits.m_springStiffness[index] = stiffness; + m_linearLimits.m_springStiffnessLimited[index] = limitIfNeeded; + } else { + m_angularLimits[index - 3].m_springStiffness = stiffness; + m_angularLimits[index - 3].m_springStiffnessLimited = limitIfNeeded; + } +} + +void btGeneric6DofSpring2Constraint::setDamping(int index, btScalar damping, bool limitIfNeeded) +{ + btAssert((index >= 0) && (index < 6)); + if (index<3) { + m_linearLimits.m_springDamping[index] = damping; + m_linearLimits.m_springDampingLimited[index] = limitIfNeeded; + } else { + m_angularLimits[index - 3].m_springDamping = damping; + m_angularLimits[index - 3].m_springDampingLimited = limitIfNeeded; + } +} + +void btGeneric6DofSpring2Constraint::setEquilibriumPoint() +{ + calculateTransforms(); + int i; + for( i = 0; i < 3; i++) + m_linearLimits.m_equilibriumPoint[i] = m_calculatedLinearDiff[i]; + for(i = 0; i < 3; i++) + m_angularLimits[i].m_equilibriumPoint = m_calculatedAxisAngleDiff[i]; +} + +void btGeneric6DofSpring2Constraint::setEquilibriumPoint(int index) +{ + btAssert((index >= 0) && (index < 6)); + calculateTransforms(); + if (index<3) + m_linearLimits.m_equilibriumPoint[index] = m_calculatedLinearDiff[index]; + else + m_angularLimits[index - 3] .m_equilibriumPoint = m_calculatedAxisAngleDiff[index - 3]; +} + +void btGeneric6DofSpring2Constraint::setEquilibriumPoint(int index, btScalar val) +{ + btAssert((index >= 0) && (index < 6)); + if (index<3) + m_linearLimits.m_equilibriumPoint[index] = val; + else + m_angularLimits[index - 3] .m_equilibriumPoint = val; +} + + +//////////////////////////// btRotationalLimitMotor2 //////////////////////////////////// + +void btRotationalLimitMotor2::testLimitValue(btScalar test_value) +{ + //we can't normalize the angles here because we would lost the sign that we use later, but it doesn't seem to be a problem + if(m_loLimit > m_hiLimit) { + m_currentLimit = 0; + m_currentLimitError = btScalar(0.f); + } + else if(m_loLimit == m_hiLimit) { + m_currentLimitError = test_value - m_loLimit; + m_currentLimit = 3; + } else { + m_currentLimitError = test_value - m_loLimit; + m_currentLimitErrorHi = test_value - m_hiLimit; + m_currentLimit = 4; + } +} + +//////////////////////////// btTranslationalLimitMotor2 //////////////////////////////////// + +void btTranslationalLimitMotor2::testLimitValue(int limitIndex, btScalar test_value) +{ + btScalar loLimit = m_lowerLimit[limitIndex]; + btScalar hiLimit = m_upperLimit[limitIndex]; + if(loLimit > hiLimit) { + m_currentLimitError[limitIndex] = 0; + m_currentLimit[limitIndex] = 0; + } + else if(loLimit == hiLimit) { + m_currentLimitError[limitIndex] = test_value - loLimit; + m_currentLimit[limitIndex] = 3; + } else { + m_currentLimitError[limitIndex] = test_value - loLimit; + m_currentLimitErrorHi[limitIndex] = test_value - hiLimit; + m_currentLimit[limitIndex] = 4; + } +} + + diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h b/extern/bullet/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h similarity index 95% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h index ace4b3c29bf2..536e5af1b9c4 100644 --- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h +++ b/extern/bullet/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h @@ -1,674 +1,679 @@ -/* -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. -*/ - -/* -2014 May: btGeneric6DofSpring2Constraint is created from the original (2.82.2712) btGeneric6DofConstraint by Gabor Puhr and Tamas Umenhoffer -Pros: -- Much more accurate and stable in a lot of situation. (Especially when a sleeping chain of RBs connected with 6dof2 is pulled) -- Stable and accurate spring with minimal energy loss that works with all of the solvers. (latter is not true for the original 6dof spring) -- Servo motor functionality -- Much more accurate bouncing. 0 really means zero bouncing (not true for the original 6odf) and there is only a minimal energy loss when the value is 1 (because of the solvers' precision) -- Rotation order for the Euler system can be set. (One axis' freedom is still limited to pi/2) - -Cons: -- It is slower than the original 6dof. There is no exact ratio, but half speed is a good estimation. -- At bouncing the correct velocity is calculated, but not the correct position. (it is because of the solver can correct position or velocity, but not both.) -*/ - -/// 2009 March: btGeneric6DofConstraint refactored by Roman Ponomarev -/// Added support for generic constraint solver through getInfo1/getInfo2 methods - -/* -2007-09-09 -btGeneric6DofConstraint Refactored by Francisco Le?n -email: projectileman@yahoo.com -http://gimpact.sf.net -*/ - - -#ifndef BT_GENERIC_6DOF_CONSTRAINT2_H -#define BT_GENERIC_6DOF_CONSTRAINT2_H - -#include "LinearMath/btVector3.h" -#include "btJacobianEntry.h" -#include "btTypedConstraint.h" - -class btRigidBody; - - -#ifdef BT_USE_DOUBLE_PRECISION -#define btGeneric6DofSpring2ConstraintData2 btGeneric6DofSpring2ConstraintDoubleData2 -#define btGeneric6DofSpring2ConstraintDataName "btGeneric6DofSpring2ConstraintDoubleData2" -#else -#define btGeneric6DofSpring2ConstraintData2 btGeneric6DofSpring2ConstraintData -#define btGeneric6DofSpring2ConstraintDataName "btGeneric6DofSpring2ConstraintData" -#endif //BT_USE_DOUBLE_PRECISION - -enum RotateOrder -{ - RO_XYZ=0, - RO_XZY, - RO_YXZ, - RO_YZX, - RO_ZXY, - RO_ZYX -}; - -class btRotationalLimitMotor2 -{ -public: -// upper < lower means free -// upper == lower means locked -// upper > lower means limited - btScalar m_loLimit; - btScalar m_hiLimit; - btScalar m_bounce; - btScalar m_stopERP; - btScalar m_stopCFM; - btScalar m_motorERP; - btScalar m_motorCFM; - bool m_enableMotor; - btScalar m_targetVelocity; - btScalar m_maxMotorForce; - bool m_servoMotor; - btScalar m_servoTarget; - bool m_enableSpring; - btScalar m_springStiffness; - bool m_springStiffnessLimited; - btScalar m_springDamping; - bool m_springDampingLimited; - btScalar m_equilibriumPoint; - - btScalar m_currentLimitError; - btScalar m_currentLimitErrorHi; - btScalar m_currentPosition; - int m_currentLimit; - - btRotationalLimitMotor2() - { - m_loLimit = 1.0f; - m_hiLimit = -1.0f; - m_bounce = 0.0f; - m_stopERP = 0.2f; - m_stopCFM = 0.f; - m_motorERP = 0.9f; - m_motorCFM = 0.f; - m_enableMotor = false; - m_targetVelocity = 0; - m_maxMotorForce = 0.1f; - m_servoMotor = false; - m_servoTarget = 0; - m_enableSpring = false; - m_springStiffness = 0; - m_springStiffnessLimited = false; - m_springDamping = 0; - m_springDampingLimited = false; - m_equilibriumPoint = 0; - - m_currentLimitError = 0; - m_currentLimitErrorHi = 0; - m_currentPosition = 0; - m_currentLimit = 0; - } - - btRotationalLimitMotor2(const btRotationalLimitMotor2 & limot) - { - m_loLimit = limot.m_loLimit; - m_hiLimit = limot.m_hiLimit; - m_bounce = limot.m_bounce; - m_stopERP = limot.m_stopERP; - m_stopCFM = limot.m_stopCFM; - m_motorERP = limot.m_motorERP; - m_motorCFM = limot.m_motorCFM; - m_enableMotor = limot.m_enableMotor; - m_targetVelocity = limot.m_targetVelocity; - m_maxMotorForce = limot.m_maxMotorForce; - m_servoMotor = limot.m_servoMotor; - m_servoTarget = limot.m_servoTarget; - m_enableSpring = limot.m_enableSpring; - m_springStiffness = limot.m_springStiffness; - m_springStiffnessLimited = limot.m_springStiffnessLimited; - m_springDamping = limot.m_springDamping; - m_springDampingLimited = limot.m_springDampingLimited; - m_equilibriumPoint = limot.m_equilibriumPoint; - - m_currentLimitError = limot.m_currentLimitError; - m_currentLimitErrorHi = limot.m_currentLimitErrorHi; - m_currentPosition = limot.m_currentPosition; - m_currentLimit = limot.m_currentLimit; - } - - - bool isLimited() - { - if(m_loLimit > m_hiLimit) return false; - return true; - } - - void testLimitValue(btScalar test_value); -}; - - - -class btTranslationalLimitMotor2 -{ -public: -// upper < lower means free -// upper == lower means locked -// upper > lower means limited - btVector3 m_lowerLimit; - btVector3 m_upperLimit; - btVector3 m_bounce; - btVector3 m_stopERP; - btVector3 m_stopCFM; - btVector3 m_motorERP; - btVector3 m_motorCFM; - bool m_enableMotor[3]; - bool m_servoMotor[3]; - bool m_enableSpring[3]; - btVector3 m_servoTarget; - btVector3 m_springStiffness; - bool m_springStiffnessLimited[3]; - btVector3 m_springDamping; - bool m_springDampingLimited[3]; - btVector3 m_equilibriumPoint; - btVector3 m_targetVelocity; - btVector3 m_maxMotorForce; - - btVector3 m_currentLimitError; - btVector3 m_currentLimitErrorHi; - btVector3 m_currentLinearDiff; - int m_currentLimit[3]; - - btTranslationalLimitMotor2() - { - m_lowerLimit .setValue(0.f , 0.f , 0.f ); - m_upperLimit .setValue(0.f , 0.f , 0.f ); - m_bounce .setValue(0.f , 0.f , 0.f ); - m_stopERP .setValue(0.2f, 0.2f, 0.2f); - m_stopCFM .setValue(0.f , 0.f , 0.f ); - m_motorERP .setValue(0.9f, 0.9f, 0.9f); - m_motorCFM .setValue(0.f , 0.f , 0.f ); - - m_currentLimitError .setValue(0.f , 0.f , 0.f ); - m_currentLimitErrorHi.setValue(0.f , 0.f , 0.f ); - m_currentLinearDiff .setValue(0.f , 0.f , 0.f ); - - for(int i=0; i < 3; i++) - { - m_enableMotor[i] = false; - m_servoMotor[i] = false; - m_enableSpring[i] = false; - m_servoTarget[i] = btScalar(0.f); - m_springStiffness[i] = btScalar(0.f); - m_springStiffnessLimited[i] = false; - m_springDamping[i] = btScalar(0.f); - m_springDampingLimited[i] = false; - m_equilibriumPoint[i] = btScalar(0.f); - m_targetVelocity[i] = btScalar(0.f); - m_maxMotorForce[i] = btScalar(0.f); - - m_currentLimit[i] = 0; - } - } - - btTranslationalLimitMotor2(const btTranslationalLimitMotor2 & other ) - { - m_lowerLimit = other.m_lowerLimit; - m_upperLimit = other.m_upperLimit; - m_bounce = other.m_bounce; - m_stopERP = other.m_stopERP; - m_stopCFM = other.m_stopCFM; - m_motorERP = other.m_motorERP; - m_motorCFM = other.m_motorCFM; - - m_currentLimitError = other.m_currentLimitError; - m_currentLimitErrorHi = other.m_currentLimitErrorHi; - m_currentLinearDiff = other.m_currentLinearDiff; - - for(int i=0; i < 3; i++) - { - m_enableMotor[i] = other.m_enableMotor[i]; - m_servoMotor[i] = other.m_servoMotor[i]; - m_enableSpring[i] = other.m_enableSpring[i]; - m_servoTarget[i] = other.m_servoTarget[i]; - m_springStiffness[i] = other.m_springStiffness[i]; - m_springStiffnessLimited[i] = other.m_springStiffnessLimited[i]; - m_springDamping[i] = other.m_springDamping[i]; - m_springDampingLimited[i] = other.m_springDampingLimited[i]; - m_equilibriumPoint[i] = other.m_equilibriumPoint[i]; - m_targetVelocity[i] = other.m_targetVelocity[i]; - m_maxMotorForce[i] = other.m_maxMotorForce[i]; - - m_currentLimit[i] = other.m_currentLimit[i]; - } - } - - inline bool isLimited(int limitIndex) - { - return (m_upperLimit[limitIndex] >= m_lowerLimit[limitIndex]); - } - - void testLimitValue(int limitIndex, btScalar test_value); -}; - -enum bt6DofFlags2 -{ - BT_6DOF_FLAGS_CFM_STOP2 = 1, - BT_6DOF_FLAGS_ERP_STOP2 = 2, - BT_6DOF_FLAGS_CFM_MOTO2 = 4, - BT_6DOF_FLAGS_ERP_MOTO2 = 8 -}; -#define BT_6DOF_FLAGS_AXIS_SHIFT2 4 // bits per axis - - -ATTRIBUTE_ALIGNED16(class) btGeneric6DofSpring2Constraint : public btTypedConstraint -{ -protected: - - btTransform m_frameInA; - btTransform m_frameInB; - - btJacobianEntry m_jacLinear[3]; - btJacobianEntry m_jacAng[3]; - - btTranslationalLimitMotor2 m_linearLimits; - btRotationalLimitMotor2 m_angularLimits[3]; - - RotateOrder m_rotateOrder; - -protected: - - btTransform m_calculatedTransformA; - btTransform m_calculatedTransformB; - btVector3 m_calculatedAxisAngleDiff; - btVector3 m_calculatedAxis[3]; - btVector3 m_calculatedLinearDiff; - btScalar m_factA; - btScalar m_factB; - bool m_hasStaticBody; - int m_flags; - - btGeneric6DofSpring2Constraint& operator=(btGeneric6DofSpring2Constraint&) - { - btAssert(0); - return *this; - } - - int setAngularLimits(btConstraintInfo2 *info, int row_offset,const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB); - int setLinearLimits(btConstraintInfo2 *info, int row, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB); - - void calculateLinearInfo(); - void calculateAngleInfo(); - void testAngularLimitMotor(int axis_index); - - void calculateJacobi(btRotationalLimitMotor2* limot, const btTransform& transA,const btTransform& transB, btConstraintInfo2* info, int srow, btVector3& ax1, int rotational, int rotAllowed); - int get_limit_motor_info2(btRotationalLimitMotor2* limot, - const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB, - btConstraintInfo2* info, int row, btVector3& ax1, int rotational, int rotAllowed = false); - - static btScalar btGetMatrixElem(const btMatrix3x3& mat, int index); - static bool matrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz); - static bool matrixToEulerXZY(const btMatrix3x3& mat,btVector3& xyz); - static bool matrixToEulerYXZ(const btMatrix3x3& mat,btVector3& xyz); - static bool matrixToEulerYZX(const btMatrix3x3& mat,btVector3& xyz); - static bool matrixToEulerZXY(const btMatrix3x3& mat,btVector3& xyz); - static bool matrixToEulerZYX(const btMatrix3x3& mat,btVector3& xyz); - -public: - - BT_DECLARE_ALIGNED_ALLOCATOR(); - - btGeneric6DofSpring2Constraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, RotateOrder rotOrder = RO_XYZ); - btGeneric6DofSpring2Constraint(btRigidBody& rbB, const btTransform& frameInB, RotateOrder rotOrder = RO_XYZ); - - virtual void buildJacobian() {} - virtual void getInfo1 (btConstraintInfo1* info); - virtual void getInfo2 (btConstraintInfo2* info); - virtual int calculateSerializeBufferSize() const; - virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; - - btRotationalLimitMotor2* getRotationalLimitMotor(int index) { return &m_angularLimits[index]; } - btTranslationalLimitMotor2* getTranslationalLimitMotor() { return &m_linearLimits; } - - // Calculates the global transform for the joint offset for body A an B, and also calculates the angle differences between the bodies. - void calculateTransforms(const btTransform& transA,const btTransform& transB); - void calculateTransforms(); - - // Gets the global transform of the offset for body A - const btTransform & getCalculatedTransformA() const { return m_calculatedTransformA; } - // Gets the global transform of the offset for body B - const btTransform & getCalculatedTransformB() const { return m_calculatedTransformB; } - - const btTransform & getFrameOffsetA() const { return m_frameInA; } - const btTransform & getFrameOffsetB() const { return m_frameInB; } - - btTransform & getFrameOffsetA() { return m_frameInA; } - btTransform & getFrameOffsetB() { return m_frameInB; } - - // Get the rotation axis in global coordinates ( btGeneric6DofSpring2Constraint::calculateTransforms() must be called previously ) - btVector3 getAxis(int axis_index) const { return m_calculatedAxis[axis_index]; } - - // Get the relative Euler angle ( btGeneric6DofSpring2Constraint::calculateTransforms() must be called previously ) - btScalar getAngle(int axis_index) const { return m_calculatedAxisAngleDiff[axis_index]; } - - // Get the relative position of the constraint pivot ( btGeneric6DofSpring2Constraint::calculateTransforms() must be called previously ) - btScalar getRelativePivotPosition(int axis_index) const { return m_calculatedLinearDiff[axis_index]; } - - void setFrames(const btTransform & frameA, const btTransform & frameB); - - void setLinearLowerLimit(const btVector3& linearLower) { m_linearLimits.m_lowerLimit = linearLower; } - void getLinearLowerLimit(btVector3& linearLower) { linearLower = m_linearLimits.m_lowerLimit; } - void setLinearUpperLimit(const btVector3& linearUpper) { m_linearLimits.m_upperLimit = linearUpper; } - void getLinearUpperLimit(btVector3& linearUpper) { linearUpper = m_linearLimits.m_upperLimit; } - - void setAngularLowerLimit(const btVector3& angularLower) - { - for(int i = 0; i < 3; i++) - m_angularLimits[i].m_loLimit = btNormalizeAngle(angularLower[i]); - } - - void setAngularLowerLimitReversed(const btVector3& angularLower) - { - for(int i = 0; i < 3; i++) - m_angularLimits[i].m_hiLimit = btNormalizeAngle(-angularLower[i]); - } - - void getAngularLowerLimit(btVector3& angularLower) - { - for(int i = 0; i < 3; i++) - angularLower[i] = m_angularLimits[i].m_loLimit; - } - - void getAngularLowerLimitReversed(btVector3& angularLower) - { - for(int i = 0; i < 3; i++) - angularLower[i] = -m_angularLimits[i].m_hiLimit; - } - - void setAngularUpperLimit(const btVector3& angularUpper) - { - for(int i = 0; i < 3; i++) - m_angularLimits[i].m_hiLimit = btNormalizeAngle(angularUpper[i]); - } - - void setAngularUpperLimitReversed(const btVector3& angularUpper) - { - for(int i = 0; i < 3; i++) - m_angularLimits[i].m_loLimit = btNormalizeAngle(-angularUpper[i]); - } - - void getAngularUpperLimit(btVector3& angularUpper) - { - for(int i = 0; i < 3; i++) - angularUpper[i] = m_angularLimits[i].m_hiLimit; - } - - void getAngularUpperLimitReversed(btVector3& angularUpper) - { - for(int i = 0; i < 3; i++) - angularUpper[i] = -m_angularLimits[i].m_loLimit; - } - - //first 3 are linear, next 3 are angular - - void setLimit(int axis, btScalar lo, btScalar hi) - { - if(axis<3) - { - m_linearLimits.m_lowerLimit[axis] = lo; - m_linearLimits.m_upperLimit[axis] = hi; - } - else - { - lo = btNormalizeAngle(lo); - hi = btNormalizeAngle(hi); - m_angularLimits[axis-3].m_loLimit = lo; - m_angularLimits[axis-3].m_hiLimit = hi; - } - } - - void setLimitReversed(int axis, btScalar lo, btScalar hi) - { - if(axis<3) - { - m_linearLimits.m_lowerLimit[axis] = lo; - m_linearLimits.m_upperLimit[axis] = hi; - } - else - { - lo = btNormalizeAngle(lo); - hi = btNormalizeAngle(hi); - m_angularLimits[axis-3].m_hiLimit = -lo; - m_angularLimits[axis-3].m_loLimit = -hi; - } - } - - bool isLimited(int limitIndex) - { - if(limitIndex<3) - { - return m_linearLimits.isLimited(limitIndex); - } - return m_angularLimits[limitIndex-3].isLimited(); - } - - void setRotationOrder(RotateOrder order) { m_rotateOrder = order; } - RotateOrder getRotationOrder() { return m_rotateOrder; } - - void setAxis( const btVector3& axis1, const btVector3& axis2); - - void setBounce(int index, btScalar bounce); - - void enableMotor(int index, bool onOff); - void setServo(int index, bool onOff); // set the type of the motor (servo or not) (the motor has to be turned on for servo also) - void setTargetVelocity(int index, btScalar velocity); - void setServoTarget(int index, btScalar target); - void setMaxMotorForce(int index, btScalar force); - - void enableSpring(int index, bool onOff); - void setStiffness(int index, btScalar stiffness, bool limitIfNeeded = true); // if limitIfNeeded is true the system will automatically limit the stiffness in necessary situations where otherwise the spring would move unrealistically too widely - void setDamping(int index, btScalar damping, bool limitIfNeeded = true); // if limitIfNeeded is true the system will automatically limit the damping in necessary situations where otherwise the spring would blow up - void setEquilibriumPoint(); // set the current constraint position/orientation as an equilibrium point for all DOF - void setEquilibriumPoint(int index); // set the current constraint position/orientation as an equilibrium point for given DOF - void setEquilibriumPoint(int index, btScalar val); - - //override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). - //If no axis is provided, it uses the default axis for this constraint. - virtual void setParam(int num, btScalar value, int axis = -1); - virtual btScalar getParam(int num, int axis = -1) const; -}; - - -struct btGeneric6DofSpring2ConstraintData -{ - btTypedConstraintData m_typeConstraintData; - btTransformFloatData m_rbAFrame; - btTransformFloatData m_rbBFrame; - - btVector3FloatData m_linearUpperLimit; - btVector3FloatData m_linearLowerLimit; - btVector3FloatData m_linearBounce; - btVector3FloatData m_linearStopERP; - btVector3FloatData m_linearStopCFM; - btVector3FloatData m_linearMotorERP; - btVector3FloatData m_linearMotorCFM; - btVector3FloatData m_linearTargetVelocity; - btVector3FloatData m_linearMaxMotorForce; - btVector3FloatData m_linearServoTarget; - btVector3FloatData m_linearSpringStiffness; - btVector3FloatData m_linearSpringDamping; - btVector3FloatData m_linearEquilibriumPoint; - char m_linearEnableMotor[4]; - char m_linearServoMotor[4]; - char m_linearEnableSpring[4]; - char m_linearSpringStiffnessLimited[4]; - char m_linearSpringDampingLimited[4]; - char m_padding1[4]; - - btVector3FloatData m_angularUpperLimit; - btVector3FloatData m_angularLowerLimit; - btVector3FloatData m_angularBounce; - btVector3FloatData m_angularStopERP; - btVector3FloatData m_angularStopCFM; - btVector3FloatData m_angularMotorERP; - btVector3FloatData m_angularMotorCFM; - btVector3FloatData m_angularTargetVelocity; - btVector3FloatData m_angularMaxMotorForce; - btVector3FloatData m_angularServoTarget; - btVector3FloatData m_angularSpringStiffness; - btVector3FloatData m_angularSpringDamping; - btVector3FloatData m_angularEquilibriumPoint; - char m_angularEnableMotor[4]; - char m_angularServoMotor[4]; - char m_angularEnableSpring[4]; - char m_angularSpringStiffnessLimited[4]; - char m_angularSpringDampingLimited[4]; - - int m_rotateOrder; -}; - -struct btGeneric6DofSpring2ConstraintDoubleData2 -{ - btTypedConstraintDoubleData m_typeConstraintData; - btTransformDoubleData m_rbAFrame; - btTransformDoubleData m_rbBFrame; - - btVector3DoubleData m_linearUpperLimit; - btVector3DoubleData m_linearLowerLimit; - btVector3DoubleData m_linearBounce; - btVector3DoubleData m_linearStopERP; - btVector3DoubleData m_linearStopCFM; - btVector3DoubleData m_linearMotorERP; - btVector3DoubleData m_linearMotorCFM; - btVector3DoubleData m_linearTargetVelocity; - btVector3DoubleData m_linearMaxMotorForce; - btVector3DoubleData m_linearServoTarget; - btVector3DoubleData m_linearSpringStiffness; - btVector3DoubleData m_linearSpringDamping; - btVector3DoubleData m_linearEquilibriumPoint; - char m_linearEnableMotor[4]; - char m_linearServoMotor[4]; - char m_linearEnableSpring[4]; - char m_linearSpringStiffnessLimited[4]; - char m_linearSpringDampingLimited[4]; - char m_padding1[4]; - - btVector3DoubleData m_angularUpperLimit; - btVector3DoubleData m_angularLowerLimit; - btVector3DoubleData m_angularBounce; - btVector3DoubleData m_angularStopERP; - btVector3DoubleData m_angularStopCFM; - btVector3DoubleData m_angularMotorERP; - btVector3DoubleData m_angularMotorCFM; - btVector3DoubleData m_angularTargetVelocity; - btVector3DoubleData m_angularMaxMotorForce; - btVector3DoubleData m_angularServoTarget; - btVector3DoubleData m_angularSpringStiffness; - btVector3DoubleData m_angularSpringDamping; - btVector3DoubleData m_angularEquilibriumPoint; - char m_angularEnableMotor[4]; - char m_angularServoMotor[4]; - char m_angularEnableSpring[4]; - char m_angularSpringStiffnessLimited[4]; - char m_angularSpringDampingLimited[4]; - - int m_rotateOrder; -}; - -SIMD_FORCE_INLINE int btGeneric6DofSpring2Constraint::calculateSerializeBufferSize() const -{ - return sizeof(btGeneric6DofSpring2ConstraintData2); -} - -SIMD_FORCE_INLINE const char* btGeneric6DofSpring2Constraint::serialize(void* dataBuffer, btSerializer* serializer) const -{ - btGeneric6DofSpring2ConstraintData2* dof = (btGeneric6DofSpring2ConstraintData2*)dataBuffer; - btTypedConstraint::serialize(&dof->m_typeConstraintData,serializer); - - m_frameInA.serialize(dof->m_rbAFrame); - m_frameInB.serialize(dof->m_rbBFrame); - - int i; - for (i=0;i<3;i++) - { - dof->m_angularLowerLimit.m_floats[i] = m_angularLimits[i].m_loLimit; - dof->m_angularUpperLimit.m_floats[i] = m_angularLimits[i].m_hiLimit; - dof->m_angularBounce.m_floats[i] = m_angularLimits[i].m_bounce; - dof->m_angularStopERP.m_floats[i] = m_angularLimits[i].m_stopERP; - dof->m_angularStopCFM.m_floats[i] = m_angularLimits[i].m_stopCFM; - dof->m_angularMotorERP.m_floats[i] = m_angularLimits[i].m_motorERP; - dof->m_angularMotorCFM.m_floats[i] = m_angularLimits[i].m_motorCFM; - dof->m_angularTargetVelocity.m_floats[i] = m_angularLimits[i].m_targetVelocity; - dof->m_angularMaxMotorForce.m_floats[i] = m_angularLimits[i].m_maxMotorForce; - dof->m_angularServoTarget.m_floats[i] = m_angularLimits[i].m_servoTarget; - dof->m_angularSpringStiffness.m_floats[i] = m_angularLimits[i].m_springStiffness; - dof->m_angularSpringDamping.m_floats[i] = m_angularLimits[i].m_springDamping; - dof->m_angularEquilibriumPoint.m_floats[i] = m_angularLimits[i].m_equilibriumPoint; - } - dof->m_angularLowerLimit.m_floats[3] = 0; - dof->m_angularUpperLimit.m_floats[3] = 0; - dof->m_angularBounce.m_floats[3] = 0; - dof->m_angularStopERP.m_floats[3] = 0; - dof->m_angularStopCFM.m_floats[3] = 0; - dof->m_angularMotorERP.m_floats[3] = 0; - dof->m_angularMotorCFM.m_floats[3] = 0; - dof->m_angularTargetVelocity.m_floats[3] = 0; - dof->m_angularMaxMotorForce.m_floats[3] = 0; - dof->m_angularServoTarget.m_floats[3] = 0; - dof->m_angularSpringStiffness.m_floats[3] = 0; - dof->m_angularSpringDamping.m_floats[3] = 0; - dof->m_angularEquilibriumPoint.m_floats[3] = 0; - for (i=0;i<4;i++) - { - dof->m_angularEnableMotor[i] = i < 3 ? ( m_angularLimits[i].m_enableMotor ? 1 : 0 ) : 0; - dof->m_angularServoMotor[i] = i < 3 ? ( m_angularLimits[i].m_servoMotor ? 1 : 0 ) : 0; - dof->m_angularEnableSpring[i] = i < 3 ? ( m_angularLimits[i].m_enableSpring ? 1 : 0 ) : 0; - dof->m_angularSpringStiffnessLimited[i] = i < 3 ? ( m_angularLimits[i].m_springStiffnessLimited ? 1 : 0 ) : 0; - dof->m_angularSpringDampingLimited[i] = i < 3 ? ( m_angularLimits[i].m_springDampingLimited ? 1 : 0 ) : 0; - } - - m_linearLimits.m_lowerLimit.serialize( dof->m_linearLowerLimit ); - m_linearLimits.m_upperLimit.serialize( dof->m_linearUpperLimit ); - m_linearLimits.m_bounce.serialize( dof->m_linearBounce ); - m_linearLimits.m_stopERP.serialize( dof->m_linearStopERP ); - m_linearLimits.m_stopCFM.serialize( dof->m_linearStopCFM ); - m_linearLimits.m_motorERP.serialize( dof->m_linearMotorERP ); - m_linearLimits.m_motorCFM.serialize( dof->m_linearMotorCFM ); - m_linearLimits.m_targetVelocity.serialize( dof->m_linearTargetVelocity ); - m_linearLimits.m_maxMotorForce.serialize( dof->m_linearMaxMotorForce ); - m_linearLimits.m_servoTarget.serialize( dof->m_linearServoTarget ); - m_linearLimits.m_springStiffness.serialize( dof->m_linearSpringStiffness ); - m_linearLimits.m_springDamping.serialize( dof->m_linearSpringDamping ); - m_linearLimits.m_equilibriumPoint.serialize( dof->m_linearEquilibriumPoint ); - for (i=0;i<4;i++) - { - dof->m_linearEnableMotor[i] = i < 3 ? ( m_linearLimits.m_enableMotor[i] ? 1 : 0 ) : 0; - dof->m_linearServoMotor[i] = i < 3 ? ( m_linearLimits.m_servoMotor[i] ? 1 : 0 ) : 0; - dof->m_linearEnableSpring[i] = i < 3 ? ( m_linearLimits.m_enableSpring[i] ? 1 : 0 ) : 0; - dof->m_linearSpringStiffnessLimited[i] = i < 3 ? ( m_linearLimits.m_springStiffnessLimited[i] ? 1 : 0 ) : 0; - dof->m_linearSpringDampingLimited[i] = i < 3 ? ( m_linearLimits.m_springDampingLimited[i] ? 1 : 0 ) : 0; - } - - dof->m_rotateOrder = m_rotateOrder; - - return btGeneric6DofSpring2ConstraintDataName; -} - - - - - -#endif //BT_GENERIC_6DOF_CONSTRAINT_H +/* +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. +*/ + +/* +2014 May: btGeneric6DofSpring2Constraint is created from the original (2.82.2712) btGeneric6DofConstraint by Gabor Puhr and Tamas Umenhoffer +Pros: +- Much more accurate and stable in a lot of situation. (Especially when a sleeping chain of RBs connected with 6dof2 is pulled) +- Stable and accurate spring with minimal energy loss that works with all of the solvers. (latter is not true for the original 6dof spring) +- Servo motor functionality +- Much more accurate bouncing. 0 really means zero bouncing (not true for the original 6odf) and there is only a minimal energy loss when the value is 1 (because of the solvers' precision) +- Rotation order for the Euler system can be set. (One axis' freedom is still limited to pi/2) + +Cons: +- It is slower than the original 6dof. There is no exact ratio, but half speed is a good estimation. +- At bouncing the correct velocity is calculated, but not the correct position. (it is because of the solver can correct position or velocity, but not both.) +*/ + +/// 2009 March: btGeneric6DofConstraint refactored by Roman Ponomarev +/// Added support for generic constraint solver through getInfo1/getInfo2 methods + +/* +2007-09-09 +btGeneric6DofConstraint Refactored by Francisco Le?n +email: projectileman@yahoo.com +http://gimpact.sf.net +*/ + + +#ifndef BT_GENERIC_6DOF_CONSTRAINT2_H +#define BT_GENERIC_6DOF_CONSTRAINT2_H + +#include "LinearMath/btVector3.h" +#include "btJacobianEntry.h" +#include "btTypedConstraint.h" + +class btRigidBody; + + +#ifdef BT_USE_DOUBLE_PRECISION +#define btGeneric6DofSpring2ConstraintData2 btGeneric6DofSpring2ConstraintDoubleData2 +#define btGeneric6DofSpring2ConstraintDataName "btGeneric6DofSpring2ConstraintDoubleData2" +#else +#define btGeneric6DofSpring2ConstraintData2 btGeneric6DofSpring2ConstraintData +#define btGeneric6DofSpring2ConstraintDataName "btGeneric6DofSpring2ConstraintData" +#endif //BT_USE_DOUBLE_PRECISION + +enum RotateOrder +{ + RO_XYZ=0, + RO_XZY, + RO_YXZ, + RO_YZX, + RO_ZXY, + RO_ZYX +}; + +class btRotationalLimitMotor2 +{ +public: +// upper < lower means free +// upper == lower means locked +// upper > lower means limited + btScalar m_loLimit; + btScalar m_hiLimit; + btScalar m_bounce; + btScalar m_stopERP; + btScalar m_stopCFM; + btScalar m_motorERP; + btScalar m_motorCFM; + bool m_enableMotor; + btScalar m_targetVelocity; + btScalar m_maxMotorForce; + bool m_servoMotor; + btScalar m_servoTarget; + bool m_enableSpring; + btScalar m_springStiffness; + bool m_springStiffnessLimited; + btScalar m_springDamping; + bool m_springDampingLimited; + btScalar m_equilibriumPoint; + + btScalar m_currentLimitError; + btScalar m_currentLimitErrorHi; + btScalar m_currentPosition; + int m_currentLimit; + + btRotationalLimitMotor2() + { + m_loLimit = 1.0f; + m_hiLimit = -1.0f; + m_bounce = 0.0f; + m_stopERP = 0.2f; + m_stopCFM = 0.f; + m_motorERP = 0.9f; + m_motorCFM = 0.f; + m_enableMotor = false; + m_targetVelocity = 0; + m_maxMotorForce = 0.1f; + m_servoMotor = false; + m_servoTarget = 0; + m_enableSpring = false; + m_springStiffness = 0; + m_springStiffnessLimited = false; + m_springDamping = 0; + m_springDampingLimited = false; + m_equilibriumPoint = 0; + + m_currentLimitError = 0; + m_currentLimitErrorHi = 0; + m_currentPosition = 0; + m_currentLimit = 0; + } + + btRotationalLimitMotor2(const btRotationalLimitMotor2 & limot) + { + m_loLimit = limot.m_loLimit; + m_hiLimit = limot.m_hiLimit; + m_bounce = limot.m_bounce; + m_stopERP = limot.m_stopERP; + m_stopCFM = limot.m_stopCFM; + m_motorERP = limot.m_motorERP; + m_motorCFM = limot.m_motorCFM; + m_enableMotor = limot.m_enableMotor; + m_targetVelocity = limot.m_targetVelocity; + m_maxMotorForce = limot.m_maxMotorForce; + m_servoMotor = limot.m_servoMotor; + m_servoTarget = limot.m_servoTarget; + m_enableSpring = limot.m_enableSpring; + m_springStiffness = limot.m_springStiffness; + m_springStiffnessLimited = limot.m_springStiffnessLimited; + m_springDamping = limot.m_springDamping; + m_springDampingLimited = limot.m_springDampingLimited; + m_equilibriumPoint = limot.m_equilibriumPoint; + + m_currentLimitError = limot.m_currentLimitError; + m_currentLimitErrorHi = limot.m_currentLimitErrorHi; + m_currentPosition = limot.m_currentPosition; + m_currentLimit = limot.m_currentLimit; + } + + + bool isLimited() + { + if(m_loLimit > m_hiLimit) return false; + return true; + } + + void testLimitValue(btScalar test_value); +}; + + + +class btTranslationalLimitMotor2 +{ +public: +// upper < lower means free +// upper == lower means locked +// upper > lower means limited + btVector3 m_lowerLimit; + btVector3 m_upperLimit; + btVector3 m_bounce; + btVector3 m_stopERP; + btVector3 m_stopCFM; + btVector3 m_motorERP; + btVector3 m_motorCFM; + bool m_enableMotor[3]; + bool m_servoMotor[3]; + bool m_enableSpring[3]; + btVector3 m_servoTarget; + btVector3 m_springStiffness; + bool m_springStiffnessLimited[3]; + btVector3 m_springDamping; + bool m_springDampingLimited[3]; + btVector3 m_equilibriumPoint; + btVector3 m_targetVelocity; + btVector3 m_maxMotorForce; + + btVector3 m_currentLimitError; + btVector3 m_currentLimitErrorHi; + btVector3 m_currentLinearDiff; + int m_currentLimit[3]; + + btTranslationalLimitMotor2() + { + m_lowerLimit .setValue(0.f , 0.f , 0.f ); + m_upperLimit .setValue(0.f , 0.f , 0.f ); + m_bounce .setValue(0.f , 0.f , 0.f ); + m_stopERP .setValue(0.2f, 0.2f, 0.2f); + m_stopCFM .setValue(0.f , 0.f , 0.f ); + m_motorERP .setValue(0.9f, 0.9f, 0.9f); + m_motorCFM .setValue(0.f , 0.f , 0.f ); + + m_currentLimitError .setValue(0.f , 0.f , 0.f ); + m_currentLimitErrorHi.setValue(0.f , 0.f , 0.f ); + m_currentLinearDiff .setValue(0.f , 0.f , 0.f ); + + for(int i=0; i < 3; i++) + { + m_enableMotor[i] = false; + m_servoMotor[i] = false; + m_enableSpring[i] = false; + m_servoTarget[i] = btScalar(0.f); + m_springStiffness[i] = btScalar(0.f); + m_springStiffnessLimited[i] = false; + m_springDamping[i] = btScalar(0.f); + m_springDampingLimited[i] = false; + m_equilibriumPoint[i] = btScalar(0.f); + m_targetVelocity[i] = btScalar(0.f); + m_maxMotorForce[i] = btScalar(0.f); + + m_currentLimit[i] = 0; + } + } + + btTranslationalLimitMotor2(const btTranslationalLimitMotor2 & other ) + { + m_lowerLimit = other.m_lowerLimit; + m_upperLimit = other.m_upperLimit; + m_bounce = other.m_bounce; + m_stopERP = other.m_stopERP; + m_stopCFM = other.m_stopCFM; + m_motorERP = other.m_motorERP; + m_motorCFM = other.m_motorCFM; + + m_currentLimitError = other.m_currentLimitError; + m_currentLimitErrorHi = other.m_currentLimitErrorHi; + m_currentLinearDiff = other.m_currentLinearDiff; + + for(int i=0; i < 3; i++) + { + m_enableMotor[i] = other.m_enableMotor[i]; + m_servoMotor[i] = other.m_servoMotor[i]; + m_enableSpring[i] = other.m_enableSpring[i]; + m_servoTarget[i] = other.m_servoTarget[i]; + m_springStiffness[i] = other.m_springStiffness[i]; + m_springStiffnessLimited[i] = other.m_springStiffnessLimited[i]; + m_springDamping[i] = other.m_springDamping[i]; + m_springDampingLimited[i] = other.m_springDampingLimited[i]; + m_equilibriumPoint[i] = other.m_equilibriumPoint[i]; + m_targetVelocity[i] = other.m_targetVelocity[i]; + m_maxMotorForce[i] = other.m_maxMotorForce[i]; + + m_currentLimit[i] = other.m_currentLimit[i]; + } + } + + inline bool isLimited(int limitIndex) + { + return (m_upperLimit[limitIndex] >= m_lowerLimit[limitIndex]); + } + + void testLimitValue(int limitIndex, btScalar test_value); +}; + +enum bt6DofFlags2 +{ + BT_6DOF_FLAGS_CFM_STOP2 = 1, + BT_6DOF_FLAGS_ERP_STOP2 = 2, + BT_6DOF_FLAGS_CFM_MOTO2 = 4, + BT_6DOF_FLAGS_ERP_MOTO2 = 8 +}; +#define BT_6DOF_FLAGS_AXIS_SHIFT2 4 // bits per axis + + +ATTRIBUTE_ALIGNED16(class) btGeneric6DofSpring2Constraint : public btTypedConstraint +{ +protected: + + btTransform m_frameInA; + btTransform m_frameInB; + + btJacobianEntry m_jacLinear[3]; + btJacobianEntry m_jacAng[3]; + + btTranslationalLimitMotor2 m_linearLimits; + btRotationalLimitMotor2 m_angularLimits[3]; + + RotateOrder m_rotateOrder; + +protected: + + btTransform m_calculatedTransformA; + btTransform m_calculatedTransformB; + btVector3 m_calculatedAxisAngleDiff; + btVector3 m_calculatedAxis[3]; + btVector3 m_calculatedLinearDiff; + btScalar m_factA; + btScalar m_factB; + bool m_hasStaticBody; + int m_flags; + + btGeneric6DofSpring2Constraint& operator=(btGeneric6DofSpring2Constraint&) + { + btAssert(0); + return *this; + } + + int setAngularLimits(btConstraintInfo2 *info, int row_offset,const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB); + int setLinearLimits(btConstraintInfo2 *info, int row, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB); + + void calculateLinearInfo(); + void calculateAngleInfo(); + void testAngularLimitMotor(int axis_index); + + void calculateJacobi(btRotationalLimitMotor2* limot, const btTransform& transA,const btTransform& transB, btConstraintInfo2* info, int srow, btVector3& ax1, int rotational, int rotAllowed); + int get_limit_motor_info2(btRotationalLimitMotor2* limot, + const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB, + btConstraintInfo2* info, int row, btVector3& ax1, int rotational, int rotAllowed = false); + +public: + + BT_DECLARE_ALIGNED_ALLOCATOR(); + + btGeneric6DofSpring2Constraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, RotateOrder rotOrder = RO_XYZ); + btGeneric6DofSpring2Constraint(btRigidBody& rbB, const btTransform& frameInB, RotateOrder rotOrder = RO_XYZ); + + virtual void buildJacobian() {} + virtual void getInfo1 (btConstraintInfo1* info); + virtual void getInfo2 (btConstraintInfo2* info); + virtual int calculateSerializeBufferSize() const; + virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; + + btRotationalLimitMotor2* getRotationalLimitMotor(int index) { return &m_angularLimits[index]; } + btTranslationalLimitMotor2* getTranslationalLimitMotor() { return &m_linearLimits; } + + // Calculates the global transform for the joint offset for body A an B, and also calculates the angle differences between the bodies. + void calculateTransforms(const btTransform& transA,const btTransform& transB); + void calculateTransforms(); + + // Gets the global transform of the offset for body A + const btTransform & getCalculatedTransformA() const { return m_calculatedTransformA; } + // Gets the global transform of the offset for body B + const btTransform & getCalculatedTransformB() const { return m_calculatedTransformB; } + + const btTransform & getFrameOffsetA() const { return m_frameInA; } + const btTransform & getFrameOffsetB() const { return m_frameInB; } + + btTransform & getFrameOffsetA() { return m_frameInA; } + btTransform & getFrameOffsetB() { return m_frameInB; } + + // Get the rotation axis in global coordinates ( btGeneric6DofSpring2Constraint::calculateTransforms() must be called previously ) + btVector3 getAxis(int axis_index) const { return m_calculatedAxis[axis_index]; } + + // Get the relative Euler angle ( btGeneric6DofSpring2Constraint::calculateTransforms() must be called previously ) + btScalar getAngle(int axis_index) const { return m_calculatedAxisAngleDiff[axis_index]; } + + // Get the relative position of the constraint pivot ( btGeneric6DofSpring2Constraint::calculateTransforms() must be called previously ) + btScalar getRelativePivotPosition(int axis_index) const { return m_calculatedLinearDiff[axis_index]; } + + void setFrames(const btTransform & frameA, const btTransform & frameB); + + void setLinearLowerLimit(const btVector3& linearLower) { m_linearLimits.m_lowerLimit = linearLower; } + void getLinearLowerLimit(btVector3& linearLower) { linearLower = m_linearLimits.m_lowerLimit; } + void setLinearUpperLimit(const btVector3& linearUpper) { m_linearLimits.m_upperLimit = linearUpper; } + void getLinearUpperLimit(btVector3& linearUpper) { linearUpper = m_linearLimits.m_upperLimit; } + + void setAngularLowerLimit(const btVector3& angularLower) + { + for(int i = 0; i < 3; i++) + m_angularLimits[i].m_loLimit = btNormalizeAngle(angularLower[i]); + } + + void setAngularLowerLimitReversed(const btVector3& angularLower) + { + for(int i = 0; i < 3; i++) + m_angularLimits[i].m_hiLimit = btNormalizeAngle(-angularLower[i]); + } + + void getAngularLowerLimit(btVector3& angularLower) + { + for(int i = 0; i < 3; i++) + angularLower[i] = m_angularLimits[i].m_loLimit; + } + + void getAngularLowerLimitReversed(btVector3& angularLower) + { + for(int i = 0; i < 3; i++) + angularLower[i] = -m_angularLimits[i].m_hiLimit; + } + + void setAngularUpperLimit(const btVector3& angularUpper) + { + for(int i = 0; i < 3; i++) + m_angularLimits[i].m_hiLimit = btNormalizeAngle(angularUpper[i]); + } + + void setAngularUpperLimitReversed(const btVector3& angularUpper) + { + for(int i = 0; i < 3; i++) + m_angularLimits[i].m_loLimit = btNormalizeAngle(-angularUpper[i]); + } + + void getAngularUpperLimit(btVector3& angularUpper) + { + for(int i = 0; i < 3; i++) + angularUpper[i] = m_angularLimits[i].m_hiLimit; + } + + void getAngularUpperLimitReversed(btVector3& angularUpper) + { + for(int i = 0; i < 3; i++) + angularUpper[i] = -m_angularLimits[i].m_loLimit; + } + + //first 3 are linear, next 3 are angular + + void setLimit(int axis, btScalar lo, btScalar hi) + { + if(axis<3) + { + m_linearLimits.m_lowerLimit[axis] = lo; + m_linearLimits.m_upperLimit[axis] = hi; + } + else + { + lo = btNormalizeAngle(lo); + hi = btNormalizeAngle(hi); + m_angularLimits[axis-3].m_loLimit = lo; + m_angularLimits[axis-3].m_hiLimit = hi; + } + } + + void setLimitReversed(int axis, btScalar lo, btScalar hi) + { + if(axis<3) + { + m_linearLimits.m_lowerLimit[axis] = lo; + m_linearLimits.m_upperLimit[axis] = hi; + } + else + { + lo = btNormalizeAngle(lo); + hi = btNormalizeAngle(hi); + m_angularLimits[axis-3].m_hiLimit = -lo; + m_angularLimits[axis-3].m_loLimit = -hi; + } + } + + bool isLimited(int limitIndex) + { + if(limitIndex<3) + { + return m_linearLimits.isLimited(limitIndex); + } + return m_angularLimits[limitIndex-3].isLimited(); + } + + void setRotationOrder(RotateOrder order) { m_rotateOrder = order; } + RotateOrder getRotationOrder() { return m_rotateOrder; } + + void setAxis( const btVector3& axis1, const btVector3& axis2); + + void setBounce(int index, btScalar bounce); + + void enableMotor(int index, bool onOff); + void setServo(int index, bool onOff); // set the type of the motor (servo or not) (the motor has to be turned on for servo also) + void setTargetVelocity(int index, btScalar velocity); + void setServoTarget(int index, btScalar target); + void setMaxMotorForce(int index, btScalar force); + + void enableSpring(int index, bool onOff); + void setStiffness(int index, btScalar stiffness, bool limitIfNeeded = true); // if limitIfNeeded is true the system will automatically limit the stiffness in necessary situations where otherwise the spring would move unrealistically too widely + void setDamping(int index, btScalar damping, bool limitIfNeeded = true); // if limitIfNeeded is true the system will automatically limit the damping in necessary situations where otherwise the spring would blow up + void setEquilibriumPoint(); // set the current constraint position/orientation as an equilibrium point for all DOF + void setEquilibriumPoint(int index); // set the current constraint position/orientation as an equilibrium point for given DOF + void setEquilibriumPoint(int index, btScalar val); + + //override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). + //If no axis is provided, it uses the default axis for this constraint. + virtual void setParam(int num, btScalar value, int axis = -1); + virtual btScalar getParam(int num, int axis = -1) const; + + static btScalar btGetMatrixElem(const btMatrix3x3& mat, int index); + static bool matrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz); + static bool matrixToEulerXZY(const btMatrix3x3& mat,btVector3& xyz); + static bool matrixToEulerYXZ(const btMatrix3x3& mat,btVector3& xyz); + static bool matrixToEulerYZX(const btMatrix3x3& mat,btVector3& xyz); + static bool matrixToEulerZXY(const btMatrix3x3& mat,btVector3& xyz); + static bool matrixToEulerZYX(const btMatrix3x3& mat,btVector3& xyz); +}; + + +struct btGeneric6DofSpring2ConstraintData +{ + btTypedConstraintData m_typeConstraintData; + btTransformFloatData m_rbAFrame; + btTransformFloatData m_rbBFrame; + + btVector3FloatData m_linearUpperLimit; + btVector3FloatData m_linearLowerLimit; + btVector3FloatData m_linearBounce; + btVector3FloatData m_linearStopERP; + btVector3FloatData m_linearStopCFM; + btVector3FloatData m_linearMotorERP; + btVector3FloatData m_linearMotorCFM; + btVector3FloatData m_linearTargetVelocity; + btVector3FloatData m_linearMaxMotorForce; + btVector3FloatData m_linearServoTarget; + btVector3FloatData m_linearSpringStiffness; + btVector3FloatData m_linearSpringDamping; + btVector3FloatData m_linearEquilibriumPoint; + char m_linearEnableMotor[4]; + char m_linearServoMotor[4]; + char m_linearEnableSpring[4]; + char m_linearSpringStiffnessLimited[4]; + char m_linearSpringDampingLimited[4]; + char m_padding1[4]; + + btVector3FloatData m_angularUpperLimit; + btVector3FloatData m_angularLowerLimit; + btVector3FloatData m_angularBounce; + btVector3FloatData m_angularStopERP; + btVector3FloatData m_angularStopCFM; + btVector3FloatData m_angularMotorERP; + btVector3FloatData m_angularMotorCFM; + btVector3FloatData m_angularTargetVelocity; + btVector3FloatData m_angularMaxMotorForce; + btVector3FloatData m_angularServoTarget; + btVector3FloatData m_angularSpringStiffness; + btVector3FloatData m_angularSpringDamping; + btVector3FloatData m_angularEquilibriumPoint; + char m_angularEnableMotor[4]; + char m_angularServoMotor[4]; + char m_angularEnableSpring[4]; + char m_angularSpringStiffnessLimited[4]; + char m_angularSpringDampingLimited[4]; + + int m_rotateOrder; +}; + +struct btGeneric6DofSpring2ConstraintDoubleData2 +{ + btTypedConstraintDoubleData m_typeConstraintData; + btTransformDoubleData m_rbAFrame; + btTransformDoubleData m_rbBFrame; + + btVector3DoubleData m_linearUpperLimit; + btVector3DoubleData m_linearLowerLimit; + btVector3DoubleData m_linearBounce; + btVector3DoubleData m_linearStopERP; + btVector3DoubleData m_linearStopCFM; + btVector3DoubleData m_linearMotorERP; + btVector3DoubleData m_linearMotorCFM; + btVector3DoubleData m_linearTargetVelocity; + btVector3DoubleData m_linearMaxMotorForce; + btVector3DoubleData m_linearServoTarget; + btVector3DoubleData m_linearSpringStiffness; + btVector3DoubleData m_linearSpringDamping; + btVector3DoubleData m_linearEquilibriumPoint; + char m_linearEnableMotor[4]; + char m_linearServoMotor[4]; + char m_linearEnableSpring[4]; + char m_linearSpringStiffnessLimited[4]; + char m_linearSpringDampingLimited[4]; + char m_padding1[4]; + + btVector3DoubleData m_angularUpperLimit; + btVector3DoubleData m_angularLowerLimit; + btVector3DoubleData m_angularBounce; + btVector3DoubleData m_angularStopERP; + btVector3DoubleData m_angularStopCFM; + btVector3DoubleData m_angularMotorERP; + btVector3DoubleData m_angularMotorCFM; + btVector3DoubleData m_angularTargetVelocity; + btVector3DoubleData m_angularMaxMotorForce; + btVector3DoubleData m_angularServoTarget; + btVector3DoubleData m_angularSpringStiffness; + btVector3DoubleData m_angularSpringDamping; + btVector3DoubleData m_angularEquilibriumPoint; + char m_angularEnableMotor[4]; + char m_angularServoMotor[4]; + char m_angularEnableSpring[4]; + char m_angularSpringStiffnessLimited[4]; + char m_angularSpringDampingLimited[4]; + + int m_rotateOrder; +}; + +SIMD_FORCE_INLINE int btGeneric6DofSpring2Constraint::calculateSerializeBufferSize() const +{ + return sizeof(btGeneric6DofSpring2ConstraintData2); +} + +SIMD_FORCE_INLINE const char* btGeneric6DofSpring2Constraint::serialize(void* dataBuffer, btSerializer* serializer) const +{ + btGeneric6DofSpring2ConstraintData2* dof = (btGeneric6DofSpring2ConstraintData2*)dataBuffer; + btTypedConstraint::serialize(&dof->m_typeConstraintData,serializer); + + m_frameInA.serialize(dof->m_rbAFrame); + m_frameInB.serialize(dof->m_rbBFrame); + + int i; + for (i=0;i<3;i++) + { + dof->m_angularLowerLimit.m_floats[i] = m_angularLimits[i].m_loLimit; + dof->m_angularUpperLimit.m_floats[i] = m_angularLimits[i].m_hiLimit; + dof->m_angularBounce.m_floats[i] = m_angularLimits[i].m_bounce; + dof->m_angularStopERP.m_floats[i] = m_angularLimits[i].m_stopERP; + dof->m_angularStopCFM.m_floats[i] = m_angularLimits[i].m_stopCFM; + dof->m_angularMotorERP.m_floats[i] = m_angularLimits[i].m_motorERP; + dof->m_angularMotorCFM.m_floats[i] = m_angularLimits[i].m_motorCFM; + dof->m_angularTargetVelocity.m_floats[i] = m_angularLimits[i].m_targetVelocity; + dof->m_angularMaxMotorForce.m_floats[i] = m_angularLimits[i].m_maxMotorForce; + dof->m_angularServoTarget.m_floats[i] = m_angularLimits[i].m_servoTarget; + dof->m_angularSpringStiffness.m_floats[i] = m_angularLimits[i].m_springStiffness; + dof->m_angularSpringDamping.m_floats[i] = m_angularLimits[i].m_springDamping; + dof->m_angularEquilibriumPoint.m_floats[i] = m_angularLimits[i].m_equilibriumPoint; + } + dof->m_angularLowerLimit.m_floats[3] = 0; + dof->m_angularUpperLimit.m_floats[3] = 0; + dof->m_angularBounce.m_floats[3] = 0; + dof->m_angularStopERP.m_floats[3] = 0; + dof->m_angularStopCFM.m_floats[3] = 0; + dof->m_angularMotorERP.m_floats[3] = 0; + dof->m_angularMotorCFM.m_floats[3] = 0; + dof->m_angularTargetVelocity.m_floats[3] = 0; + dof->m_angularMaxMotorForce.m_floats[3] = 0; + dof->m_angularServoTarget.m_floats[3] = 0; + dof->m_angularSpringStiffness.m_floats[3] = 0; + dof->m_angularSpringDamping.m_floats[3] = 0; + dof->m_angularEquilibriumPoint.m_floats[3] = 0; + for (i=0;i<4;i++) + { + dof->m_angularEnableMotor[i] = i < 3 ? ( m_angularLimits[i].m_enableMotor ? 1 : 0 ) : 0; + dof->m_angularServoMotor[i] = i < 3 ? ( m_angularLimits[i].m_servoMotor ? 1 : 0 ) : 0; + dof->m_angularEnableSpring[i] = i < 3 ? ( m_angularLimits[i].m_enableSpring ? 1 : 0 ) : 0; + dof->m_angularSpringStiffnessLimited[i] = i < 3 ? ( m_angularLimits[i].m_springStiffnessLimited ? 1 : 0 ) : 0; + dof->m_angularSpringDampingLimited[i] = i < 3 ? ( m_angularLimits[i].m_springDampingLimited ? 1 : 0 ) : 0; + } + + m_linearLimits.m_lowerLimit.serialize( dof->m_linearLowerLimit ); + m_linearLimits.m_upperLimit.serialize( dof->m_linearUpperLimit ); + m_linearLimits.m_bounce.serialize( dof->m_linearBounce ); + m_linearLimits.m_stopERP.serialize( dof->m_linearStopERP ); + m_linearLimits.m_stopCFM.serialize( dof->m_linearStopCFM ); + m_linearLimits.m_motorERP.serialize( dof->m_linearMotorERP ); + m_linearLimits.m_motorCFM.serialize( dof->m_linearMotorCFM ); + m_linearLimits.m_targetVelocity.serialize( dof->m_linearTargetVelocity ); + m_linearLimits.m_maxMotorForce.serialize( dof->m_linearMaxMotorForce ); + m_linearLimits.m_servoTarget.serialize( dof->m_linearServoTarget ); + m_linearLimits.m_springStiffness.serialize( dof->m_linearSpringStiffness ); + m_linearLimits.m_springDamping.serialize( dof->m_linearSpringDamping ); + m_linearLimits.m_equilibriumPoint.serialize( dof->m_linearEquilibriumPoint ); + for (i=0;i<4;i++) + { + dof->m_linearEnableMotor[i] = i < 3 ? ( m_linearLimits.m_enableMotor[i] ? 1 : 0 ) : 0; + dof->m_linearServoMotor[i] = i < 3 ? ( m_linearLimits.m_servoMotor[i] ? 1 : 0 ) : 0; + dof->m_linearEnableSpring[i] = i < 3 ? ( m_linearLimits.m_enableSpring[i] ? 1 : 0 ) : 0; + dof->m_linearSpringStiffnessLimited[i] = i < 3 ? ( m_linearLimits.m_springStiffnessLimited[i] ? 1 : 0 ) : 0; + dof->m_linearSpringDampingLimited[i] = i < 3 ? ( m_linearLimits.m_springDampingLimited[i] ? 1 : 0 ) : 0; + } + + dof->m_rotateOrder = m_rotateOrder; + + dof->m_padding1[0] = 0; + dof->m_padding1[1] = 0; + dof->m_padding1[2] = 0; + dof->m_padding1[3] = 0; + + return btGeneric6DofSpring2ConstraintDataName; +} + + + + + +#endif //BT_GENERIC_6DOF_CONSTRAINT_H diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.cpp b/extern/bullet/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.cpp similarity index 100% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.cpp rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.cpp diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.h b/extern/bullet/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.h similarity index 100% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.h rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.h diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp b/extern/bullet/src/BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp similarity index 100% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHinge2Constraint.h b/extern/bullet/src/BulletDynamics/ConstraintSolver/btHinge2Constraint.h similarity index 100% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btHinge2Constraint.h rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btHinge2Constraint.h diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp b/extern/bullet/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp similarity index 99% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp index 76a1509471e8..7e5e6f9e54cd 100644 --- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp +++ b/extern/bullet/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp @@ -556,12 +556,8 @@ void btHingeConstraint::getInfo2Internal(btConstraintInfo2* info, const btTransf } // if the hinge has joint limits or motor, add in the extra row - int powered = 0; - if(getEnableAngularMotor()) - { - powered = 1; - } - if(limit || powered) + bool powered = getEnableAngularMotor(); + if(limit || powered) { nrow++; srow = nrow * info->rowskip; @@ -577,7 +573,7 @@ void btHingeConstraint::getInfo2Internal(btConstraintInfo2* info, const btTransf btScalar histop = getUpperLimit(); if(limit && (lostop == histop)) { // the joint motor is ineffective - powered = 0; + powered = false; } info->m_constraintError[srow] = btScalar(0.0f); btScalar currERP = (m_flags & BT_HINGE_FLAGS_ERP_STOP) ? m_stopERP : normalErp; @@ -951,12 +947,8 @@ void btHingeConstraint::getInfo2InternalUsingFrameOffset(btConstraintInfo2* info } // if the hinge has joint limits or motor, add in the extra row - int powered = 0; - if(getEnableAngularMotor()) - { - powered = 1; - } - if(limit || powered) + bool powered = getEnableAngularMotor(); + if(limit || powered) { nrow++; srow = nrow * info->rowskip; @@ -972,7 +964,7 @@ void btHingeConstraint::getInfo2InternalUsingFrameOffset(btConstraintInfo2* info btScalar histop = getUpperLimit(); if(limit && (lostop == histop)) { // the joint motor is ineffective - powered = 0; + powered = false; } info->m_constraintError[srow] = btScalar(0.0f); btScalar currERP = (m_flags & BT_HINGE_FLAGS_ERP_STOP) ? m_stopERP : normalErp; diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h b/extern/bullet/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h similarity index 98% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h index f26e72105ba7..3c3df24dba27 100644 --- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h +++ b/extern/bullet/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h @@ -314,7 +314,7 @@ ATTRIBUTE_ALIGNED16(class) btHingeConstraint : public btTypedConstraint { return m_enableAngularMotor; } - inline btScalar getMotorTargetVelosity() + inline btScalar getMotorTargetVelocity() { return m_motorTargetVelocity; } @@ -489,6 +489,14 @@ SIMD_FORCE_INLINE const char* btHingeConstraint::serialize(void* dataBuffer, btS hingeData->m_relaxationFactor = float(m_relaxationFactor); #endif + // Fill padding with zeros to appease msan. +#ifdef BT_USE_DOUBLE_PRECISION + hingeData->m_padding1[0] = 0; + hingeData->m_padding1[1] = 0; + hingeData->m_padding1[2] = 0; + hingeData->m_padding1[3] = 0; +#endif + return btHingeConstraintDataName; } diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btJacobianEntry.h b/extern/bullet/src/BulletDynamics/ConstraintSolver/btJacobianEntry.h similarity index 100% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btJacobianEntry.h rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btJacobianEntry.h diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.cpp b/extern/bullet/src/BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.cpp similarity index 74% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.cpp rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.cpp index f110cd480812..f3979be358a5 100644 --- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.cpp +++ b/extern/bullet/src/BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.cpp @@ -78,20 +78,6 @@ btScalar btNNCGConstraintSolver::solveSingleIteration(int iteration, btCollision btScalar deltaflengthsqr = 0; - - if (infoGlobal.m_solverMode & SOLVER_SIMD) - { - for (int j=0;jisEnabled()) - { - int bodyAid = getOrInitSolverBody(constraints[j]->getRigidBodyA(),infoGlobal.m_timeStep); - int bodyBid = getOrInitSolverBody(constraints[j]->getRigidBodyB(),infoGlobal.m_timeStep); - btSolverBody& bodyA = m_tmpSolverBodyPool[bodyAid]; - btSolverBody& bodyB = m_tmpSolverBodyPool[bodyBid]; - constraints[j]->solveConstraintObsolete(bodyA,bodyB,infoGlobal.m_timeStep); - } - } - ///solve all contact constraints - int numPoolConstraints = m_tmpSolverContactConstraintPool.size(); - for (int j=0;jbtScalar(0)) - { - solveManifold.m_lowerLimit = -(solveManifold.m_friction*totalImpulse); - solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse; - - btScalar deltaf = resolveSingleConstraintRowGeneric(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold); - m_deltafCF[j] = deltaf; - deltaflengthsqr += deltaf*deltaf; - } else { - m_deltafCF[j] = 0; - } - } - - int numRollingFrictionPoolConstraints = m_tmpSolverContactRollingFrictionConstraintPool.size(); - for (int j=0;jbtScalar(0)) - { - btScalar rollingFrictionMagnitude = rollingFrictionConstraint.m_friction*totalImpulse; - if (rollingFrictionMagnitude>rollingFrictionConstraint.m_friction) - rollingFrictionMagnitude = rollingFrictionConstraint.m_friction; - - rollingFrictionConstraint.m_lowerLimit = -rollingFrictionMagnitude; - rollingFrictionConstraint.m_upperLimit = rollingFrictionMagnitude; - - btScalar deltaf = resolveSingleConstraintRowGeneric(m_tmpSolverBodyPool[rollingFrictionConstraint.m_solverBodyIdA],m_tmpSolverBodyPool[rollingFrictionConstraint.m_solverBodyIdB],rollingFrictionConstraint); - m_deltafCRF[j] = deltaf; - deltaflengthsqr += deltaf*deltaf; - } else { - m_deltafCRF[j] = 0; - } - } - } } @@ -362,10 +278,7 @@ btScalar btNNCGConstraintSolver::solveSingleIteration(int iteration, btCollision for (int j=0;j= m_kinematicBodyUniqueIdToSolverBodyTable.size()) + { + m_kinematicBodyUniqueIdToSolverBodyTable.resize(uniqueId + 1, INVALID_SOLVER_BODY_ID); + } + solverBodyId = m_kinematicBodyUniqueIdToSolverBodyTable[uniqueId]; + // if no table entry yet, + if (solverBodyId == INVALID_SOLVER_BODY_ID) + { + // create a table entry for this body + solverBodyId = m_tmpSolverBodyPool.size(); + btSolverBody& solverBody = m_tmpSolverBodyPool.expand(); + initSolverBody(&solverBody, &body, timeStep); + m_kinematicBodyUniqueIdToSolverBodyTable[uniqueId] = solverBodyId; + } + } + else + { + bool isMultiBodyType = (body.getInternalType() & btCollisionObject::CO_FEATHERSTONE_LINK); + bool isGhostType = (body.getInternalType() & btCollisionObject::CO_GHOST_OBJECT); + // Incorrectly set collision object flags can degrade performance in various ways. + if (!isMultiBodyType && !isGhostType) + { + btAssert(body.isStaticOrKinematicObject()); + } + //it could be a multibody link collider + // all fixed bodies (inf mass) get mapped to a single solver id + if (m_fixedBodyId < 0) + { + m_fixedBodyId = m_tmpSolverBodyPool.size(); + btSolverBody& fixedBody = m_tmpSolverBodyPool.expand(); + initSolverBody(&fixedBody, 0, timeStep); + } + solverBodyId = m_fixedBodyId; + } + btAssert(solverBodyId >= 0 && solverBodyId < m_tmpSolverBodyPool.size()); + return solverBodyId; +#else // BT_THREADSAFE - int solverBodyIdA = -1; + int solverBodyIdA = -1; if (body.getCompanionId() >= 0) { @@ -749,6 +833,7 @@ int btSequentialImpulseConstraintSolver::getOrInitSolverBody(btCollisionObject& } return solverBodyIdA; +#endif // BT_THREADSAFE } #include @@ -775,7 +860,37 @@ void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstra //rel_pos1 = pos1 - bodyA->getWorldTransform().getOrigin(); //rel_pos2 = pos2 - bodyB->getWorldTransform().getOrigin(); - relaxation = 1.f; + relaxation = infoGlobal.m_sor; + btScalar invTimeStep = btScalar(1)/infoGlobal.m_timeStep; + + //cfm = 1 / ( dt * kp + kd ) + //erp = dt * kp / ( dt * kp + kd ) + + btScalar cfm = infoGlobal.m_globalCfm; + btScalar erp = infoGlobal.m_erp2; + + if ((cp.m_contactPointFlags&BT_CONTACT_FLAG_HAS_CONTACT_CFM) || (cp.m_contactPointFlags&BT_CONTACT_FLAG_HAS_CONTACT_ERP)) + { + if (cp.m_contactPointFlags&BT_CONTACT_FLAG_HAS_CONTACT_CFM) + cfm = cp.m_contactCFM; + if (cp.m_contactPointFlags&BT_CONTACT_FLAG_HAS_CONTACT_ERP) + erp = cp.m_contactERP; + } else + { + if (cp.m_contactPointFlags & BT_CONTACT_FLAG_CONTACT_STIFFNESS_DAMPING) + { + btScalar denom = ( infoGlobal.m_timeStep * cp.m_combinedContactStiffness1 + cp.m_combinedContactDamping1 ); + if (denom < SIMD_EPSILON) + { + denom = SIMD_EPSILON; + } + cfm = btScalar(1) / denom; + erp = (infoGlobal.m_timeStep * cp.m_combinedContactStiffness1) / denom; + } + } + + cfm *= invTimeStep; + btVector3 torqueAxis0 = rel_pos1.cross(cp.m_normalWorldOnB); solverConstraint.m_angularComponentA = rb0 ? rb0->getInvInertiaTensorWorld()*torqueAxis0*rb0->getAngularFactor() : btVector3(0,0,0); @@ -802,7 +917,7 @@ void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstra } #endif //COMPUTE_IMPULSE_DENOM - btScalar denom = relaxation/(denom0+denom1); + btScalar denom = relaxation/(denom0+denom1+cfm); solverConstraint.m_jacDiagABInv = denom; } @@ -843,7 +958,7 @@ void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstra solverConstraint.m_friction = cp.m_combinedFriction; - restitution = restitutionCurve(rel_vel, cp.m_combinedRestitution); + restitution = restitutionCurve(rel_vel, cp.m_combinedRestitution, infoGlobal.m_restitutionVelocityThreshold); if (restitution <= btScalar(0.)) { restitution = 0.f; @@ -884,20 +999,16 @@ void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstra btScalar velocityError = restitution - rel_vel;// * damping; - btScalar erp = infoGlobal.m_erp2; - if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold)) - { - erp = infoGlobal.m_erp; - } - + if (penetration>0) { positionalError = 0; - velocityError -= penetration / infoGlobal.m_timeStep; + velocityError -= penetration *invTimeStep; } else { - positionalError = -penetration * erp/infoGlobal.m_timeStep; + positionalError = -penetration * erp*invTimeStep; + } btScalar penetrationImpulse = positionalError*solverConstraint.m_jacDiagABInv; @@ -915,7 +1026,7 @@ void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstra solverConstraint.m_rhs = velocityImpulse; solverConstraint.m_rhsPenetration = penetrationImpulse; } - solverConstraint.m_cfm = 0.f; + solverConstraint.m_cfm = cfm*solverConstraint.m_jacDiagABInv; solverConstraint.m_lowerLimit = 0; solverConstraint.m_upperLimit = 1e10f; } @@ -1010,8 +1121,6 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m int frictionIndex = m_tmpSolverContactConstraintPool.size(); btSolverConstraint& solverConstraint = m_tmpSolverContactConstraintPool.expandNonInitializing(); - btRigidBody* rb0 = btRigidBody::upcast(colObj0); - btRigidBody* rb1 = btRigidBody::upcast(colObj1); solverConstraint.m_solverBodyIdA = solverBodyIdA; solverConstraint.m_solverBodyIdB = solverBodyIdB; @@ -1023,9 +1132,9 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m rel_pos1 = pos1 - colObj0->getWorldTransform().getOrigin(); rel_pos2 = pos2 - colObj1->getWorldTransform().getOrigin(); - btVector3 vel1;// = rb0 ? rb0->getVelocityInLocalPoint(rel_pos1) : btVector3(0,0,0); - btVector3 vel2;// = rb1 ? rb1->getVelocityInLocalPoint(rel_pos2) : btVector3(0,0,0); - + btVector3 vel1; + btVector3 vel2; + solverBodyA->getVelocityInLocalPointNoDelta(rel_pos1,vel1); solverBodyB->getVelocityInLocalPointNoDelta(rel_pos2,vel2 ); @@ -1036,45 +1145,31 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m -// const btVector3& pos1 = cp.getPositionWorldOnA(); -// const btVector3& pos2 = cp.getPositionWorldOnB(); /////setup the friction constraints solverConstraint.m_frictionIndex = m_tmpSolverContactFrictionConstraintPool.size(); - btVector3 angVelA(0,0,0),angVelB(0,0,0); - if (rb0) - angVelA = rb0->getAngularVelocity(); - if (rb1) - angVelB = rb1->getAngularVelocity(); - btVector3 relAngVel = angVelB-angVelA; - if ((cp.m_combinedRollingFriction>0.f) && (rollingFriction>0)) { - //only a single rollingFriction per manifold - rollingFriction--; - if (relAngVel.length()>infoGlobal.m_singleAxisRollingFrictionThreshold) - { - relAngVel.normalize(); - applyAnisotropicFriction(colObj0,relAngVel,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); - applyAnisotropicFriction(colObj1,relAngVel,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); - if (relAngVel.length()>0.001) - addRollingFrictionConstraint(relAngVel,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); - - } else + { - addRollingFrictionConstraint(cp.m_normalWorldOnB,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); + addTorsionalFrictionConstraint(cp.m_normalWorldOnB,solverBodyIdA,solverBodyIdB,frictionIndex,cp,cp.m_combinedSpinningFriction, rel_pos1,rel_pos2,colObj0,colObj1, relaxation); btVector3 axis0,axis1; btPlaneSpace1(cp.m_normalWorldOnB,axis0,axis1); + axis0.normalize(); + axis1.normalize(); + applyAnisotropicFriction(colObj0,axis0,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); applyAnisotropicFriction(colObj1,axis0,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); applyAnisotropicFriction(colObj0,axis1,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); applyAnisotropicFriction(colObj1,axis1,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); if (axis0.length()>0.001) - addRollingFrictionConstraint(axis0,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); + addTorsionalFrictionConstraint(axis0,solverBodyIdA,solverBodyIdB,frictionIndex,cp, + cp.m_combinedRollingFriction, rel_pos1,rel_pos2,colObj0,colObj1, relaxation); if (axis1.length()>0.001) - addRollingFrictionConstraint(axis1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); + addTorsionalFrictionConstraint(axis1,solverBodyIdA,solverBodyIdB,frictionIndex,cp, + cp.m_combinedRollingFriction, rel_pos1,rel_pos2,colObj0,colObj1, relaxation); } } @@ -1094,7 +1189,8 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m ///In that case, you can set the target relative motion in each friction direction (cp.m_contactMotion1 and cp.m_contactMotion2) ///this will give a conveyor belt effect /// - if (!(infoGlobal.m_solverMode & SOLVER_ENABLE_FRICTION_DIRECTION_CACHING) || !cp.m_lateralFrictionInitialized) + + if (!(infoGlobal.m_solverMode & SOLVER_ENABLE_FRICTION_DIRECTION_CACHING) || !(cp.m_contactPointFlags&BT_CONTACT_FLAG_LATERAL_FRICTION_INITIALIZED)) { cp.m_lateralFrictionDir1 = vel - cp.m_normalWorldOnB * rel_vel; btScalar lat_rel_vel = cp.m_lateralFrictionDir1.length2(); @@ -1103,7 +1199,7 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m cp.m_lateralFrictionDir1 *= 1.f/btSqrt(lat_rel_vel); applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir1,btCollisionObject::CF_ANISOTROPIC_FRICTION); applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir1,btCollisionObject::CF_ANISOTROPIC_FRICTION); - addFrictionConstraint(cp.m_lateralFrictionDir1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); + addFrictionConstraint(cp.m_lateralFrictionDir1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation,infoGlobal); if((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS)) { @@ -1111,7 +1207,7 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m cp.m_lateralFrictionDir2.normalize();//?? applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir2,btCollisionObject::CF_ANISOTROPIC_FRICTION); applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir2,btCollisionObject::CF_ANISOTROPIC_FRICTION); - addFrictionConstraint(cp.m_lateralFrictionDir2,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); + addFrictionConstraint(cp.m_lateralFrictionDir2,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation, infoGlobal); } } else @@ -1120,28 +1216,28 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir1,btCollisionObject::CF_ANISOTROPIC_FRICTION); applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir1,btCollisionObject::CF_ANISOTROPIC_FRICTION); - addFrictionConstraint(cp.m_lateralFrictionDir1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); + addFrictionConstraint(cp.m_lateralFrictionDir1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation, infoGlobal); if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS)) { applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir2,btCollisionObject::CF_ANISOTROPIC_FRICTION); applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir2,btCollisionObject::CF_ANISOTROPIC_FRICTION); - addFrictionConstraint(cp.m_lateralFrictionDir2,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); + addFrictionConstraint(cp.m_lateralFrictionDir2,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation, infoGlobal); } if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS) && (infoGlobal.m_solverMode & SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION)) { - cp.m_lateralFrictionInitialized = true; + cp.m_contactPointFlags|=BT_CONTACT_FLAG_LATERAL_FRICTION_INITIALIZED; } } } else { - addFrictionConstraint(cp.m_lateralFrictionDir1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation,cp.m_contactMotion1, cp.m_contactCFM1); + addFrictionConstraint(cp.m_lateralFrictionDir1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation, infoGlobal, cp.m_contactMotion1, cp.m_frictionCFM); if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS)) - addFrictionConstraint(cp.m_lateralFrictionDir2,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation, cp.m_contactMotion2, cp.m_contactCFM2); + addFrictionConstraint(cp.m_lateralFrictionDir2,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation, infoGlobal, cp.m_contactMotion2, cp.m_frictionCFM); } setFrictionConstraintImpulse( solverConstraint, solverBodyIdA, solverBodyIdB, cp, infoGlobal); @@ -1173,6 +1269,14 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol BT_PROFILE("solveGroupCacheFriendlySetup"); (void)debugDrawer; + // if solver mode has changed, + if ( infoGlobal.m_solverMode != m_cachedSolverMode ) + { + // update solver functions to use SIMD or non-SIMD + bool useSimd = !!( infoGlobal.m_solverMode & SOLVER_SIMD ); + setupSolverFunctions( useSimd ); + m_cachedSolverMode = infoGlobal.m_solverMode; + } m_maxOverrideNumSolverIterations = 0; #ifdef BT_ADDITIONAL_DEBUG @@ -1249,7 +1353,9 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol { bodies[i]->setCompanionId(-1); } - +#if BT_THREADSAFE + m_kinematicBodyUniqueIdToSolverBodyTable.resize( 0 ); +#endif // BT_THREADSAFE m_tmpSolverBodyPool.reserve(numBodies+1); m_tmpSolverBodyPool.resize(0); @@ -1450,7 +1556,8 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol sum += iMJaB.dot(solverConstraint.m_relpos2CrossNormal); btScalar fsum = btFabs(sum); btAssert(fsum > SIMD_EPSILON); - solverConstraint.m_jacDiagABInv = fsum>SIMD_EPSILON?btScalar(1.)/sum : 0.f; + btScalar sorRelaxation = 1.f;//todo: get from globalInfo? + solverConstraint.m_jacDiagABInv = fsum>SIMD_EPSILON?sorRelaxation/sum : 0.f; } @@ -1528,6 +1635,7 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration, btCollisionObject** /*bodies */,int /*numBodies*/,btPersistentManifold** /*manifoldPtr*/, int /*numManifolds*/,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* /*debugDrawer*/) { + btScalar leastSquaresResidual = 0.f; int numNonContactPool = m_tmpSolverNonContactConstraintPool.size(); int numConstraintPool = m_tmpSolverContactConstraintPool.size(); @@ -1565,14 +1673,15 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration } } - if (infoGlobal.m_solverMode & SOLVER_SIMD) - { - ///solve all joint constraints, using SIMD, if available + ///solve all joint constraints for (int j=0;jisEnabled()) - { - int bodyAid = getOrInitSolverBody(constraints[j]->getRigidBodyA(),infoGlobal.m_timeStep); - int bodyBid = getOrInitSolverBody(constraints[j]->getRigidBodyB(),infoGlobal.m_timeStep); - btSolverBody& bodyA = m_tmpSolverBodyPool[bodyAid]; - btSolverBody& bodyB = m_tmpSolverBodyPool[bodyBid]; - constraints[j]->solveConstraintObsolete(bodyA,bodyB,infoGlobal.m_timeStep); - } - } - ///solve all contact constraints - int numPoolConstraints = m_tmpSolverContactConstraintPool.size(); - for (int j=0;jbtScalar(0)) - { - solveManifold.m_lowerLimit = -(solveManifold.m_friction*totalImpulse); - solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse; - - resolveSingleConstraintRowGeneric(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold); - } - } - - int numRollingFrictionPoolConstraints = m_tmpSolverContactRollingFrictionConstraintPool.size(); - for (int j=0;jbtScalar(0)) - { - btScalar rollingFrictionMagnitude = rollingFrictionConstraint.m_friction*totalImpulse; - if (rollingFrictionMagnitude>rollingFrictionConstraint.m_friction) - rollingFrictionMagnitude = rollingFrictionConstraint.m_friction; - - rollingFrictionConstraint.m_lowerLimit = -rollingFrictionMagnitude; - rollingFrictionConstraint.m_upperLimit = rollingFrictionMagnitude; - - resolveSingleConstraintRowGeneric(m_tmpSolverBodyPool[rollingFrictionConstraint.m_solverBodyIdA],m_tmpSolverBodyPool[rollingFrictionConstraint.m_solverBodyIdB],rollingFrictionConstraint); - } - } - } - } - return 0.f; + return leastSquaresResidual; } @@ -1767,10 +1816,10 @@ void btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySplitImpulseIte int iteration; if (infoGlobal.m_splitImpulse) { - if (infoGlobal.m_solverMode & SOLVER_SIMD) { for ( iteration = 0;iteration=(infoGlobal.m_numIterations-1)) { - int numPoolConstraints = m_tmpSolverContactConstraintPool.size(); - int j; - for (j=0;j= 0;iteration--) { - solveSingleIteration(iteration, bodies ,numBodies,manifoldPtr, numManifolds,constraints,numConstraints,infoGlobal,debugDrawer); + m_leastSquaresResidual = solveSingleIteration(iteration, bodies ,numBodies,manifoldPtr, numManifolds,constraints,numConstraints,infoGlobal,debugDrawer); + + if (m_leastSquaresResidual <= infoGlobal.m_leastSquaresResidualThreshold || (iteration>= (maxIterations-1))) + { +#ifdef VERBOSE_RESIDUAL_PRINTF + printf("residual = %f at iteration #%d\n",m_leastSquaresResidual,iteration); +#endif + break; + } } } diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h b/extern/bullet/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h similarity index 76% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h index a60291809837..16c7eb74c1de 100644 --- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h +++ b/extern/bullet/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h @@ -45,22 +45,36 @@ ATTRIBUTE_ALIGNED16(class) btSequentialImpulseConstraintSolver : public btConstr btAlignedObjectArray m_tmpConstraintSizesPool; int m_maxOverrideNumSolverIterations; int m_fixedBodyId; + // When running solvers on multiple threads, a race condition exists for Kinematic objects that + // participate in more than one solver. + // The getOrInitSolverBody() function writes the companionId of each body (storing the index of the solver body + // for the current solver). For normal dynamic bodies it isn't an issue because they can only be in one island + // (and therefore one thread) at a time. But kinematic bodies can be in multiple islands at once. + // To avoid this race condition, this solver does not write the companionId, instead it stores the solver body + // index in this solver-local table, indexed by the uniqueId of the body. + btAlignedObjectArray m_kinematicBodyUniqueIdToSolverBodyTable; // only used for multithreading btSingleConstraintRowSolver m_resolveSingleConstraintRowGeneric; btSingleConstraintRowSolver m_resolveSingleConstraintRowLowerLimit; + btSingleConstraintRowSolver m_resolveSplitPenetrationImpulse; + int m_cachedSolverMode; // used to check if SOLVER_SIMD flag has been changed + void setupSolverFunctions( bool useSimd ); + + btScalar m_leastSquaresResidual; void setupFrictionConstraint( btSolverConstraint& solverConstraint, const btVector3& normalAxis,int solverBodyIdA,int solverBodyIdB, btManifoldPoint& cp,const btVector3& rel_pos1,const btVector3& rel_pos2, btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, + const btContactSolverInfo& infoGlobal, btScalar desiredVelocity=0., btScalar cfmSlip=0.); - void setupRollingFrictionConstraint( btSolverConstraint& solverConstraint, const btVector3& normalAxis,int solverBodyIdA,int solverBodyIdB, - btManifoldPoint& cp,const btVector3& rel_pos1,const btVector3& rel_pos2, + void setupTorsionalFrictionConstraint( btSolverConstraint& solverConstraint, const btVector3& normalAxis,int solverBodyIdA,int solverBodyIdB, + btManifoldPoint& cp,btScalar combinedTorsionalFriction, const btVector3& rel_pos1,const btVector3& rel_pos2, btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, btScalar desiredVelocity=0., btScalar cfmSlip=0.); - btSolverConstraint& addFrictionConstraint(const btVector3& normalAxis,int solverBodyIdA,int solverBodyIdB,int frictionIndex,btManifoldPoint& cp,const btVector3& rel_pos1,const btVector3& rel_pos2,btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, btScalar desiredVelocity=0., btScalar cfmSlip=0.); - btSolverConstraint& addRollingFrictionConstraint(const btVector3& normalAxis,int solverBodyIdA,int solverBodyIdB,int frictionIndex,btManifoldPoint& cp,const btVector3& rel_pos1,const btVector3& rel_pos2,btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, btScalar desiredVelocity=0, btScalar cfmSlip=0.f); + btSolverConstraint& addFrictionConstraint(const btVector3& normalAxis,int solverBodyIdA,int solverBodyIdB,int frictionIndex,btManifoldPoint& cp,const btVector3& rel_pos1,const btVector3& rel_pos2,btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, const btContactSolverInfo& infoGlobal, btScalar desiredVelocity=0., btScalar cfmSlip=0.); + btSolverConstraint& addTorsionalFrictionConstraint(const btVector3& normalAxis,int solverBodyIdA,int solverBodyIdB,int frictionIndex,btManifoldPoint& cp,btScalar torsionalFriction, const btVector3& rel_pos1,const btVector3& rel_pos2,btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, btScalar desiredVelocity=0, btScalar cfmSlip=0.f); void setupContactConstraint(btSolverConstraint& solverConstraint, int solverBodyIdA, int solverBodyIdB, btManifoldPoint& cp, @@ -75,20 +89,22 @@ ATTRIBUTE_ALIGNED16(class) btSequentialImpulseConstraintSolver : public btConstr unsigned long m_btSeed2; - btScalar restitutionCurve(btScalar rel_vel, btScalar restitution); + btScalar restitutionCurve(btScalar rel_vel, btScalar restitution, btScalar velocityThreshold); virtual void convertContacts(btPersistentManifold** manifoldPtr, int numManifolds, const btContactSolverInfo& infoGlobal); void convertContact(btPersistentManifold* manifold,const btContactSolverInfo& infoGlobal); - void resolveSplitPenetrationSIMD( - btSolverBody& bodyA,btSolverBody& bodyB, - const btSolverConstraint& contactConstraint); + btSimdScalar resolveSplitPenetrationSIMD(btSolverBody& bodyA,btSolverBody& bodyB, const btSolverConstraint& contactConstraint) + { + return m_resolveSplitPenetrationImpulse( bodyA, bodyB, contactConstraint ); + } - void resolveSplitPenetrationImpulseCacheFriendly( - btSolverBody& bodyA,btSolverBody& bodyB, - const btSolverConstraint& contactConstraint); + btSimdScalar resolveSplitPenetrationImpulseCacheFriendly(btSolverBody& bodyA,btSolverBody& bodyB, const btSolverConstraint& contactConstraint) + { + return m_resolveSplitPenetrationImpulse( bodyA, bodyB, contactConstraint ); + } //internal method int getOrInitSolverBody(btCollisionObject& body,btScalar timeStep); @@ -98,6 +114,10 @@ ATTRIBUTE_ALIGNED16(class) btSequentialImpulseConstraintSolver : public btConstr btSimdScalar resolveSingleConstraintRowGenericSIMD(btSolverBody& bodyA,btSolverBody& bodyB,const btSolverConstraint& contactConstraint); btSimdScalar resolveSingleConstraintRowLowerLimit(btSolverBody& bodyA,btSolverBody& bodyB,const btSolverConstraint& contactConstraint); btSimdScalar resolveSingleConstraintRowLowerLimitSIMD(btSolverBody& bodyA,btSolverBody& bodyB,const btSolverConstraint& contactConstraint); + btSimdScalar resolveSplitPenetrationImpulse(btSolverBody& bodyA,btSolverBody& bodyB, const btSolverConstraint& contactConstraint) + { + return m_resolveSplitPenetrationImpulse( bodyA, bodyB, contactConstraint ); + } protected: diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp b/extern/bullet/src/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp old mode 100644 new mode 100755 similarity index 99% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp index f8f81bfe6fa5..d63cef031626 --- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp +++ b/extern/bullet/src/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp @@ -364,7 +364,6 @@ void btSliderConstraint::getInfo2NonVirtual(btConstraintInfo2* info, const btTra int srow; btScalar limit_err; int limit; - int powered; // next two rows. // we want: velA + wA x relA == velB + wB x relB ... but this would @@ -470,13 +469,9 @@ void btSliderConstraint::getInfo2NonVirtual(btConstraintInfo2* info, const btTra limit_err = getLinDepth() * signFact; limit = (limit_err > btScalar(0.0)) ? 2 : 1; } - powered = 0; - if(getPoweredLinMotor()) - { - powered = 1; - } + bool powered = getPoweredLinMotor(); // if the slider has joint limits or motor, add in the extra row - if (limit || powered) + if (limit || powered) { nrow++; srow = nrow * info->rowskip; @@ -524,7 +519,7 @@ void btSliderConstraint::getInfo2NonVirtual(btConstraintInfo2* info, const btTra btScalar histop = getUpperLinLimit(); if(limit && (lostop == histop)) { // the joint motor is ineffective - powered = 0; + powered = false; } info->m_constraintError[srow] = 0.; info->m_lowerLimit[srow] = 0.; @@ -609,12 +604,8 @@ void btSliderConstraint::getInfo2NonVirtual(btConstraintInfo2* info, const btTra limit = (limit_err > btScalar(0.0)) ? 1 : 2; } // if the slider has joint limits, add in the extra row - powered = 0; - if(getPoweredAngMotor()) - { - powered = 1; - } - if(limit || powered) + powered = getPoweredAngMotor(); + if(limit || powered) { nrow++; srow = nrow * info->rowskip; @@ -630,7 +621,7 @@ void btSliderConstraint::getInfo2NonVirtual(btConstraintInfo2* info, const btTra btScalar histop = getUpperAngLimit(); if(limit && (lostop == histop)) { // the joint motor is ineffective - powered = 0; + powered = false; } currERP = (m_flags & BT_SLIDER_FLAGS_ERP_LIMANG) ? m_softnessLimAng : info->erp; if(powered) diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSliderConstraint.h b/extern/bullet/src/BulletDynamics/ConstraintSolver/btSliderConstraint.h old mode 100644 new mode 100755 similarity index 99% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btSliderConstraint.h rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btSliderConstraint.h index 628ada4cfb11..1957f08a96c8 --- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSliderConstraint.h +++ b/extern/bullet/src/BulletDynamics/ConstraintSolver/btSliderConstraint.h @@ -25,6 +25,8 @@ April 04, 2008 #ifndef BT_SLIDER_CONSTRAINT_H #define BT_SLIDER_CONSTRAINT_H +#include "LinearMath/btScalar.h"//for BT_USE_DOUBLE_PRECISION + #ifdef BT_USE_DOUBLE_PRECISION #define btSliderConstraintData2 btSliderConstraintDoubleData #define btSliderConstraintDataName "btSliderConstraintDoubleData" diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.cpp b/extern/bullet/src/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.cpp similarity index 100% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.cpp rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.cpp diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.h b/extern/bullet/src/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.h similarity index 100% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.h rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.h diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolverBody.h b/extern/bullet/src/BulletDynamics/ConstraintSolver/btSolverBody.h similarity index 100% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolverBody.h rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btSolverBody.h diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolverConstraint.h b/extern/bullet/src/BulletDynamics/ConstraintSolver/btSolverConstraint.h similarity index 100% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolverConstraint.h rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btSolverConstraint.h diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.cpp b/extern/bullet/src/BulletDynamics/ConstraintSolver/btTypedConstraint.cpp similarity index 99% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.cpp rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btTypedConstraint.cpp index 736a64a1c943..9f04f2805395 100644 --- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.cpp +++ b/extern/bullet/src/BulletDynamics/ConstraintSolver/btTypedConstraint.cpp @@ -19,7 +19,7 @@ subject to the following restrictions: #include "LinearMath/btSerializer.h" -#define DEFAULT_DEBUGDRAW_SIZE btScalar(0.3f) +#define DEFAULT_DEBUGDRAW_SIZE btScalar(0.05f) btTypedConstraint::btTypedConstraint(btTypedConstraintType type, btRigidBody& rbA) :btTypedObject(type), diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h b/extern/bullet/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h similarity index 98% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h index b55db0c1bfb4..8a2a2d1ae7e7 100644 --- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h +++ b/extern/bullet/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h @@ -145,11 +145,6 @@ ATTRIBUTE_ALIGNED16(class) btTypedConstraint : public btTypedObject // lo and hi limits for variables (set to -/+ infinity on entry). btScalar *m_lowerLimit,*m_upperLimit; - // 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; // number of solver iterations int m_numIterations; diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btUniversalConstraint.cpp b/extern/bullet/src/BulletDynamics/ConstraintSolver/btUniversalConstraint.cpp similarity index 100% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btUniversalConstraint.cpp rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btUniversalConstraint.cpp diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btUniversalConstraint.h b/extern/bullet/src/BulletDynamics/ConstraintSolver/btUniversalConstraint.h similarity index 100% rename from extern/bullet2/src/BulletDynamics/ConstraintSolver/btUniversalConstraint.h rename to extern/bullet/src/BulletDynamics/ConstraintSolver/btUniversalConstraint.h diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp b/extern/bullet/src/BulletDynamics/Dynamics/Bullet-C-API.cpp similarity index 100% rename from extern/bullet2/src/BulletDynamics/Dynamics/Bullet-C-API.cpp rename to extern/bullet/src/BulletDynamics/Dynamics/Bullet-C-API.cpp diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btActionInterface.h b/extern/bullet/src/BulletDynamics/Dynamics/btActionInterface.h similarity index 100% rename from extern/bullet2/src/BulletDynamics/Dynamics/btActionInterface.h rename to extern/bullet/src/BulletDynamics/Dynamics/btActionInterface.h diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp b/extern/bullet/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp similarity index 95% rename from extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp rename to extern/bullet/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp index 361a054ec69c..fc85b4f8626f 100644 --- a/extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp +++ b/extern/bullet/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp @@ -374,7 +374,7 @@ void btDiscreteDynamicsWorld::synchronizeSingleMotionState(btRigidBody* body) void btDiscreteDynamicsWorld::synchronizeMotionStates() { - BT_PROFILE("synchronizeMotionStates"); +// BT_PROFILE("synchronizeMotionStates"); if (m_synchronizeAllMotionStates) { //iterate over all collision objects @@ -402,7 +402,6 @@ int btDiscreteDynamicsWorld::stepSimulation( btScalar timeStep,int maxSubSteps, { startProfiling(timeStep); - BT_PROFILE("stepSimulation"); int numSimulationSubSteps = 0; @@ -539,7 +538,7 @@ btVector3 btDiscreteDynamicsWorld::getGravity () const return m_gravity; } -void btDiscreteDynamicsWorld::addCollisionObject(btCollisionObject* collisionObject,short int collisionFilterGroup,short int collisionFilterMask) +void btDiscreteDynamicsWorld::addCollisionObject(btCollisionObject* collisionObject, int collisionFilterGroup, int collisionFilterMask) { btCollisionWorld::addCollisionObject(collisionObject,collisionFilterGroup,collisionFilterMask); } @@ -578,14 +577,14 @@ void btDiscreteDynamicsWorld::addRigidBody(btRigidBody* body) } 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); + int collisionFilterGroup = isDynamic? int(btBroadphaseProxy::DefaultFilter) : int(btBroadphaseProxy::StaticFilter); + int collisionFilterMask = isDynamic? int(btBroadphaseProxy::AllFilter) : int(btBroadphaseProxy::AllFilter ^ btBroadphaseProxy::StaticFilter); addCollisionObject(body,collisionFilterGroup,collisionFilterMask); } } -void btDiscreteDynamicsWorld::addRigidBody(btRigidBody* body, short group, short mask) +void btDiscreteDynamicsWorld::addRigidBody(btRigidBody* body, int group, int mask) { if (!body->isStaticOrKinematicObject() && !(body->getFlags() &BT_DISABLE_WORLD_GRAVITY)) { @@ -878,25 +877,12 @@ class btClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConve int gNumClampedCcdMotions=0; -void btDiscreteDynamicsWorld::createPredictiveContacts(btScalar timeStep) +void btDiscreteDynamicsWorld::createPredictiveContactsInternal( btRigidBody** bodies, int numBodies, btScalar timeStep) { - BT_PROFILE("createPredictiveContacts"); - - { - BT_PROFILE("release predictive contact manifolds"); - - for (int i=0;im_dispatcher1->releaseManifold(manifold); - } - m_predictiveManifolds.clear(); - } - btTransform predictedTrans; - for ( int i=0;isetHitFraction(1.f); if (body->isActive() && (!body->isStaticOrKinematicObject())) @@ -953,7 +939,9 @@ void btDiscreteDynamicsWorld::createPredictiveContacts(btScalar timeStep) btPersistentManifold* manifold = m_dispatcher1->getNewManifold(body,sweepResults.m_hitCollisionObject); + btMutexLock( &m_predictiveManifoldsMutex ); m_predictiveManifolds.push_back(manifold); + btMutexUnlock( &m_predictiveManifoldsMutex ); btVector3 worldPointB = body->getWorldTransform().getOrigin()+distVec; btVector3 localPointB = sweepResults.m_hitCollisionObject->getWorldTransform().inverse()*worldPointB; @@ -974,13 +962,35 @@ void btDiscreteDynamicsWorld::createPredictiveContacts(btScalar timeStep) } } } -void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep) + +void btDiscreteDynamicsWorld::releasePredictiveContacts() +{ + BT_PROFILE( "release predictive contact manifolds" ); + + for ( int i = 0; i < m_predictiveManifolds.size(); i++ ) + { + btPersistentManifold* manifold = m_predictiveManifolds[ i ]; + this->m_dispatcher1->releaseManifold( manifold ); + } + m_predictiveManifolds.clear(); +} + +void btDiscreteDynamicsWorld::createPredictiveContacts(btScalar timeStep) +{ + BT_PROFILE("createPredictiveContacts"); + releasePredictiveContacts(); + if (m_nonStaticRigidBodies.size() > 0) + { + createPredictiveContactsInternal( &m_nonStaticRigidBodies[ 0 ], m_nonStaticRigidBodies.size(), timeStep ); + } +} + +void btDiscreteDynamicsWorld::integrateTransformsInternal( btRigidBody** bodies, int numBodies, btScalar timeStep ) { - BT_PROFILE("integrateTransforms"); btTransform predictedTrans; - for ( int i=0;isetHitFraction(1.f); if (body->isActive() && (!body->isStaticOrKinematicObject())) @@ -1080,7 +1090,17 @@ void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep) } - ///this should probably be switched on by default, but it is not well tested yet +} + +void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep) +{ + BT_PROFILE("integrateTransforms"); + if (m_nonStaticRigidBodies.size() > 0) + { + integrateTransformsInternal(&m_nonStaticRigidBodies[0], m_nonStaticRigidBodies.size(), timeStep); + } + + ///this should probably be switched on by default, but it is not well tested yet if (m_applySpeculativeContactRestitution) { BT_PROFILE("apply speculative contact restitution"); @@ -1114,14 +1134,12 @@ void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep) } } } - } - void btDiscreteDynamicsWorld::predictUnconstraintMotion(btScalar timeStep) { BT_PROFILE("predictUnconstraintMotion"); @@ -1493,6 +1511,9 @@ void btDiscreteDynamicsWorld::serializeDynamicsWorldInfo(btSerializer* serialize worldInfo->m_solverInfo.m_splitImpulse = getSolverInfo().m_splitImpulse; + // Fill padding with zeros to appease msan. + memset(worldInfo->m_solverInfo.m_padding, 0, sizeof(worldInfo->m_solverInfo.m_padding)); + #ifdef BT_USE_DOUBLE_PRECISION const char* structType = "btDynamicsWorldDoubleData"; #else//BT_USE_DOUBLE_PRECISION diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h b/extern/bullet/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h similarity index 90% rename from extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h rename to extern/bullet/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h index dd3d1c3660ca..b0d19f48a371 100644 --- a/extern/bullet2/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h +++ b/extern/bullet/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h @@ -30,6 +30,7 @@ class btIDebugDraw; struct InplaceSolverIslandCallback; #include "LinearMath/btAlignedObjectArray.h" +#include "LinearMath/btThreads.h" ///btDiscreteDynamicsWorld provides discrete rigid body simulation @@ -68,9 +69,11 @@ ATTRIBUTE_ALIGNED16(class) btDiscreteDynamicsWorld : public btDynamicsWorld bool m_latencyMotionStateInterpolation; btAlignedObjectArray m_predictiveManifolds; + btSpinMutex m_predictiveManifoldsMutex; // used to synchronize threads creating predictive contacts virtual void predictUnconstraintMotion(btScalar timeStep); + void integrateTransformsInternal( btRigidBody** bodies, int numBodies, btScalar timeStep ); // can be called in parallel virtual void integrateTransforms(btScalar timeStep); virtual void calculateSimulationIslands(); @@ -85,7 +88,9 @@ ATTRIBUTE_ALIGNED16(class) btDiscreteDynamicsWorld : public btDynamicsWorld virtual void internalSingleStepSimulation( btScalar timeStep); - void createPredictiveContacts(btScalar timeStep); + void releasePredictiveContacts(); + void createPredictiveContactsInternal( btRigidBody** bodies, int numBodies, btScalar timeStep ); // can be called in parallel + virtual void createPredictiveContacts(btScalar timeStep); virtual void saveKinematicState(btScalar timeStep); @@ -139,11 +144,11 @@ ATTRIBUTE_ALIGNED16(class) btDiscreteDynamicsWorld : public btDynamicsWorld virtual btVector3 getGravity () const; - virtual void addCollisionObject(btCollisionObject* collisionObject,short int collisionFilterGroup=btBroadphaseProxy::StaticFilter,short int collisionFilterMask=btBroadphaseProxy::AllFilter ^ btBroadphaseProxy::StaticFilter); + virtual void addCollisionObject(btCollisionObject* collisionObject, int collisionFilterGroup=btBroadphaseProxy::StaticFilter, int collisionFilterMask=btBroadphaseProxy::AllFilter ^ btBroadphaseProxy::StaticFilter); virtual void addRigidBody(btRigidBody* body); - virtual void addRigidBody(btRigidBody* body, short group, short mask); + virtual void addRigidBody(btRigidBody* body, int group, int mask); virtual void removeRigidBody(btRigidBody* body); diff --git a/extern/bullet/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.cpp b/extern/bullet/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.cpp new file mode 100644 index 000000000000..1d10bad9221d --- /dev/null +++ b/extern/bullet/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.cpp @@ -0,0 +1,327 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org + +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 "btDiscreteDynamicsWorldMt.h" + +//collision detection +#include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" +#include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h" +#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" +#include "BulletCollision/CollisionShapes/btCollisionShape.h" +#include "btSimulationIslandManagerMt.h" +#include "LinearMath/btTransformUtil.h" +#include "LinearMath/btQuickprof.h" + +//rigidbody & constraints +#include "BulletDynamics/Dynamics/btRigidBody.h" +#include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h" +#include "BulletDynamics/ConstraintSolver/btContactSolverInfo.h" +#include "BulletDynamics/ConstraintSolver/btTypedConstraint.h" +#include "BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h" +#include "BulletDynamics/ConstraintSolver/btHingeConstraint.h" +#include "BulletDynamics/ConstraintSolver/btConeTwistConstraint.h" +#include "BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h" +#include "BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h" +#include "BulletDynamics/ConstraintSolver/btSliderConstraint.h" +#include "BulletDynamics/ConstraintSolver/btContactConstraint.h" + + +#include "LinearMath/btIDebugDraw.h" +#include "BulletCollision/CollisionShapes/btSphereShape.h" + + +#include "BulletDynamics/Dynamics/btActionInterface.h" +#include "LinearMath/btQuickprof.h" +#include "LinearMath/btMotionState.h" + +#include "LinearMath/btSerializer.h" + + +struct InplaceSolverIslandCallbackMt : public btSimulationIslandManagerMt::IslandCallback +{ + btContactSolverInfo* m_solverInfo; + btConstraintSolver* m_solver; + btIDebugDraw* m_debugDrawer; + btDispatcher* m_dispatcher; + + InplaceSolverIslandCallbackMt( + btConstraintSolver* solver, + btStackAlloc* stackAlloc, + btDispatcher* dispatcher) + :m_solverInfo(NULL), + m_solver(solver), + m_debugDrawer(NULL), + m_dispatcher(dispatcher) + { + + } + + InplaceSolverIslandCallbackMt& operator=(InplaceSolverIslandCallbackMt& other) + { + btAssert(0); + (void)other; + return *this; + } + + SIMD_FORCE_INLINE void setup ( btContactSolverInfo* solverInfo, btIDebugDraw* debugDrawer) + { + btAssert(solverInfo); + m_solverInfo = solverInfo; + m_debugDrawer = debugDrawer; + } + + + virtual void processIsland( btCollisionObject** bodies, + int numBodies, + btPersistentManifold** manifolds, + int numManifolds, + btTypedConstraint** constraints, + int numConstraints, + int islandId + ) + { + m_solver->solveGroup( bodies, + numBodies, + manifolds, + numManifolds, + constraints, + numConstraints, + *m_solverInfo, + m_debugDrawer, + m_dispatcher + ); + } + +}; + + +/// +/// btConstraintSolverPoolMt +/// + +btConstraintSolverPoolMt::ThreadSolver* btConstraintSolverPoolMt::getAndLockThreadSolver() +{ + int i = 0; +#if BT_THREADSAFE + i = btGetCurrentThreadIndex() % m_solvers.size(); +#endif // #if BT_THREADSAFE + while ( true ) + { + ThreadSolver& solver = m_solvers[ i ]; + if ( solver.mutex.tryLock() ) + { + return &solver; + } + // failed, try the next one + i = ( i + 1 ) % m_solvers.size(); + } + return NULL; +} + +void btConstraintSolverPoolMt::init( btConstraintSolver** solvers, int numSolvers ) +{ + m_solverType = BT_SEQUENTIAL_IMPULSE_SOLVER; + m_solvers.resize( numSolvers ); + for ( int i = 0; i < numSolvers; ++i ) + { + m_solvers[ i ].solver = solvers[ i ]; + } + if ( numSolvers > 0 ) + { + m_solverType = solvers[ 0 ]->getSolverType(); + } +} + +// create the solvers for me +btConstraintSolverPoolMt::btConstraintSolverPoolMt( int numSolvers ) +{ + btAlignedObjectArray solvers; + solvers.reserve( numSolvers ); + for ( int i = 0; i < numSolvers; ++i ) + { + btConstraintSolver* solver = new btSequentialImpulseConstraintSolver(); + solvers.push_back( solver ); + } + init( &solvers[ 0 ], numSolvers ); +} + +// pass in fully constructed solvers (destructor will delete them) +btConstraintSolverPoolMt::btConstraintSolverPoolMt( btConstraintSolver** solvers, int numSolvers ) +{ + init( solvers, numSolvers ); +} + +btConstraintSolverPoolMt::~btConstraintSolverPoolMt() +{ + // delete all solvers + for ( int i = 0; i < m_solvers.size(); ++i ) + { + ThreadSolver& solver = m_solvers[ i ]; + delete solver.solver; + solver.solver = NULL; + } +} + +///solve a group of constraints +btScalar btConstraintSolverPoolMt::solveGroup( btCollisionObject** bodies, + int numBodies, + btPersistentManifold** manifolds, + int numManifolds, + btTypedConstraint** constraints, + int numConstraints, + const btContactSolverInfo& info, + btIDebugDraw* debugDrawer, + btDispatcher* dispatcher +) +{ + ThreadSolver* ts = getAndLockThreadSolver(); + ts->solver->solveGroup( bodies, numBodies, manifolds, numManifolds, constraints, numConstraints, info, debugDrawer, dispatcher ); + ts->mutex.unlock(); + return 0.0f; +} + +void btConstraintSolverPoolMt::reset() +{ + for ( int i = 0; i < m_solvers.size(); ++i ) + { + ThreadSolver& solver = m_solvers[ i ]; + solver.mutex.lock(); + solver.solver->reset(); + solver.mutex.unlock(); + } +} + + +/// +/// btDiscreteDynamicsWorldMt +/// + +btDiscreteDynamicsWorldMt::btDiscreteDynamicsWorldMt(btDispatcher* dispatcher, btBroadphaseInterface* pairCache, btConstraintSolverPoolMt* constraintSolver, btCollisionConfiguration* collisionConfiguration) +: btDiscreteDynamicsWorld(dispatcher,pairCache,constraintSolver,collisionConfiguration) +{ + if (m_ownsIslandManager) + { + m_islandManager->~btSimulationIslandManager(); + btAlignedFree( m_islandManager); + } + { + void* mem = btAlignedAlloc(sizeof(InplaceSolverIslandCallbackMt),16); + m_solverIslandCallbackMt = new (mem) InplaceSolverIslandCallbackMt (m_constraintSolver, 0, dispatcher); + } + { + void* mem = btAlignedAlloc(sizeof(btSimulationIslandManagerMt),16); + btSimulationIslandManagerMt* im = new (mem) btSimulationIslandManagerMt(); + im->setMinimumSolverBatchSize( m_solverInfo.m_minimumSolverBatchSize ); + m_islandManager = im; + } +} + + +btDiscreteDynamicsWorldMt::~btDiscreteDynamicsWorldMt() +{ + if (m_solverIslandCallbackMt) + { + m_solverIslandCallbackMt->~InplaceSolverIslandCallbackMt(); + btAlignedFree(m_solverIslandCallbackMt); + } + if (m_ownsConstraintSolver) + { + m_constraintSolver->~btConstraintSolver(); + btAlignedFree(m_constraintSolver); + } +} + + +void btDiscreteDynamicsWorldMt::solveConstraints(btContactSolverInfo& solverInfo) +{ + BT_PROFILE("solveConstraints"); + + m_solverIslandCallbackMt->setup(&solverInfo, getDebugDrawer()); + m_constraintSolver->prepareSolve(getCollisionWorld()->getNumCollisionObjects(), getCollisionWorld()->getDispatcher()->getNumManifolds()); + + /// solve all the constraints for this island + btSimulationIslandManagerMt* im = static_cast(m_islandManager); + im->buildAndProcessIslands( getCollisionWorld()->getDispatcher(), getCollisionWorld(), m_constraints, m_solverIslandCallbackMt ); + + m_constraintSolver->allSolved(solverInfo, m_debugDrawer); +} + + +struct UpdaterUnconstrainedMotion : public btIParallelForBody +{ + btScalar timeStep; + btRigidBody** rigidBodies; + + void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE + { + for ( int i = iBegin; i < iEnd; ++i ) + { + btRigidBody* body = rigidBodies[ i ]; + if ( !body->isStaticOrKinematicObject() ) + { + //don't integrate/update velocities here, it happens in the constraint solver + body->applyDamping( timeStep ); + body->predictIntegratedTransform( timeStep, body->getInterpolationWorldTransform() ); + } + } + } +}; + + +void btDiscreteDynamicsWorldMt::predictUnconstraintMotion( btScalar timeStep ) +{ + BT_PROFILE( "predictUnconstraintMotion" ); + if ( m_nonStaticRigidBodies.size() > 0 ) + { + UpdaterUnconstrainedMotion update; + update.timeStep = timeStep; + update.rigidBodies = &m_nonStaticRigidBodies[ 0 ]; + int grainSize = 50; // num of iterations per task for task scheduler + btParallelFor( 0, m_nonStaticRigidBodies.size(), grainSize, update ); + } +} + + +void btDiscreteDynamicsWorldMt::createPredictiveContacts( btScalar timeStep ) +{ + BT_PROFILE( "createPredictiveContacts" ); + releasePredictiveContacts(); + if ( m_nonStaticRigidBodies.size() > 0 ) + { + UpdaterCreatePredictiveContacts update; + update.world = this; + update.timeStep = timeStep; + update.rigidBodies = &m_nonStaticRigidBodies[ 0 ]; + int grainSize = 50; // num of iterations per task for task scheduler + btParallelFor( 0, m_nonStaticRigidBodies.size(), grainSize, update ); + } +} + + +void btDiscreteDynamicsWorldMt::integrateTransforms( btScalar timeStep ) +{ + BT_PROFILE( "integrateTransforms" ); + if ( m_nonStaticRigidBodies.size() > 0 ) + { + UpdaterIntegrateTransforms update; + update.world = this; + update.timeStep = timeStep; + update.rigidBodies = &m_nonStaticRigidBodies[ 0 ]; + int grainSize = 50; // num of iterations per task for task scheduler + btParallelFor( 0, m_nonStaticRigidBodies.size(), grainSize, update ); + } +} + diff --git a/extern/bullet/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h b/extern/bullet/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h new file mode 100644 index 000000000000..2f144cdda4c9 --- /dev/null +++ b/extern/bullet/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h @@ -0,0 +1,134 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org + +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_MT_H +#define BT_DISCRETE_DYNAMICS_WORLD_MT_H + +#include "btDiscreteDynamicsWorld.h" +#include "btSimulationIslandManagerMt.h" +#include "BulletDynamics/ConstraintSolver/btConstraintSolver.h" + +struct InplaceSolverIslandCallbackMt; + +/// +/// btConstraintSolverPoolMt - masquerades as a constraint solver, but really it is a threadsafe pool of them. +/// +/// Each solver in the pool is protected by a mutex. When solveGroup is called from a thread, +/// the pool looks for a solver that isn't being used by another thread, locks it, and dispatches the +/// call to the solver. +/// So long as there are at least as many solvers as there are hardware threads, it should never need to +/// spin wait. +/// +class btConstraintSolverPoolMt : public btConstraintSolver +{ +public: + // create the solvers for me + explicit btConstraintSolverPoolMt( int numSolvers ); + + // pass in fully constructed solvers (destructor will delete them) + btConstraintSolverPoolMt( btConstraintSolver** solvers, int numSolvers ); + + virtual ~btConstraintSolverPoolMt(); + + ///solve a group of constraints + virtual btScalar solveGroup( btCollisionObject** bodies, + int numBodies, + btPersistentManifold** manifolds, + int numManifolds, + btTypedConstraint** constraints, + int numConstraints, + const btContactSolverInfo& info, + btIDebugDraw* debugDrawer, + btDispatcher* dispatcher + ) BT_OVERRIDE; + + virtual void reset() BT_OVERRIDE; + virtual btConstraintSolverType getSolverType() const BT_OVERRIDE { return m_solverType; } + +private: + const static size_t kCacheLineSize = 128; + struct ThreadSolver + { + btConstraintSolver* solver; + btSpinMutex mutex; + char _cachelinePadding[ kCacheLineSize - sizeof( btSpinMutex ) - sizeof( void* ) ]; // keep mutexes from sharing a cache line + }; + btAlignedObjectArray m_solvers; + btConstraintSolverType m_solverType; + + ThreadSolver* getAndLockThreadSolver(); + void init( btConstraintSolver** solvers, int numSolvers ); +}; + + + +/// +/// btDiscreteDynamicsWorldMt -- a version of DiscreteDynamicsWorld with some minor changes to support +/// solving simulation islands on multiple threads. +/// +/// Should function exactly like btDiscreteDynamicsWorld. +/// Also 3 methods that iterate over all of the rigidbodies can run in parallel: +/// - predictUnconstraintMotion +/// - integrateTransforms +/// - createPredictiveContacts +/// +ATTRIBUTE_ALIGNED16(class) btDiscreteDynamicsWorldMt : public btDiscreteDynamicsWorld +{ +protected: + InplaceSolverIslandCallbackMt* m_solverIslandCallbackMt; + + virtual void solveConstraints(btContactSolverInfo& solverInfo) BT_OVERRIDE; + + virtual void predictUnconstraintMotion( btScalar timeStep ) BT_OVERRIDE; + + struct UpdaterCreatePredictiveContacts : public btIParallelForBody + { + btScalar timeStep; + btRigidBody** rigidBodies; + btDiscreteDynamicsWorldMt* world; + + void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE + { + world->createPredictiveContactsInternal( &rigidBodies[ iBegin ], iEnd - iBegin, timeStep ); + } + }; + virtual void createPredictiveContacts( btScalar timeStep ) BT_OVERRIDE; + + struct UpdaterIntegrateTransforms : public btIParallelForBody + { + btScalar timeStep; + btRigidBody** rigidBodies; + btDiscreteDynamicsWorldMt* world; + + void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE + { + world->integrateTransformsInternal( &rigidBodies[ iBegin ], iEnd - iBegin, timeStep ); + } + }; + virtual void integrateTransforms( btScalar timeStep ) BT_OVERRIDE; + +public: + BT_DECLARE_ALIGNED_ALLOCATOR(); + + btDiscreteDynamicsWorldMt(btDispatcher* dispatcher, + btBroadphaseInterface* pairCache, + btConstraintSolverPoolMt* constraintSolver, // Note this should be a solver-pool for multi-threading + btCollisionConfiguration* collisionConfiguration + ); + virtual ~btDiscreteDynamicsWorldMt(); +}; + +#endif //BT_DISCRETE_DYNAMICS_WORLD_H diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btDynamicsWorld.h b/extern/bullet/src/BulletDynamics/Dynamics/btDynamicsWorld.h similarity index 96% rename from extern/bullet2/src/BulletDynamics/Dynamics/btDynamicsWorld.h rename to extern/bullet/src/BulletDynamics/Dynamics/btDynamicsWorld.h index 35dd1400fe7e..42d8fc0de3f6 100644 --- a/extern/bullet2/src/BulletDynamics/Dynamics/btDynamicsWorld.h +++ b/extern/bullet/src/BulletDynamics/Dynamics/btDynamicsWorld.h @@ -34,7 +34,8 @@ enum btDynamicsWorldType BT_DISCRETE_DYNAMICS_WORLD=2, BT_CONTINUOUS_DYNAMICS_WORLD=3, BT_SOFT_RIGID_DYNAMICS_WORLD=4, - BT_GPU_DYNAMICS_WORLD=5 + BT_GPU_DYNAMICS_WORLD=5, + BT_SOFT_MULTIBODY_DYNAMICS_WORLD=6 }; ///The btDynamicsWorld is the interface class for several dynamics implementation, basic, discrete, parallel, and continuous etc. @@ -88,7 +89,7 @@ class btDynamicsWorld : public btCollisionWorld virtual void addRigidBody(btRigidBody* body) = 0; - virtual void addRigidBody(btRigidBody* body, short group, short mask) = 0; + virtual void addRigidBody(btRigidBody* body, int group, int mask) = 0; virtual void removeRigidBody(btRigidBody* body) = 0; @@ -134,6 +135,11 @@ class btDynamicsWorld : public btCollisionWorld return m_solverInfo; } + const btContactSolverInfo& getSolverInfo() const + { + return m_solverInfo; + } + ///obsolete, use addAction instead. virtual void addVehicle(btActionInterface* vehicle) {(void)vehicle;} diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.cpp b/extern/bullet/src/BulletDynamics/Dynamics/btRigidBody.cpp similarity index 98% rename from extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.cpp rename to extern/bullet/src/BulletDynamics/Dynamics/btRigidBody.cpp index a7882684bf1a..a9f274962120 100644 --- a/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.cpp +++ b/extern/bullet/src/BulletDynamics/Dynamics/btRigidBody.cpp @@ -79,6 +79,8 @@ void btRigidBody::setupRigidBody(const btRigidBody::btRigidBodyConstructionInfo& //moved to btCollisionObject m_friction = constructionInfo.m_friction; m_rollingFriction = constructionInfo.m_rollingFriction; + m_spinningFriction = constructionInfo.m_spinningFriction; + m_restitution = constructionInfo.m_restitution; setCollisionShape( constructionInfo.m_collisionShape ); @@ -493,6 +495,11 @@ const char* btRigidBody::serialize(void* dataBuffer, class btSerializer* seriali rbd->m_linearSleepingThreshold=m_linearSleepingThreshold; rbd->m_angularSleepingThreshold = m_angularSleepingThreshold; + // Fill padding with zeros to appease msan. +#ifdef BT_USE_DOUBLE_PRECISION + memset(rbd->m_padding, 0, sizeof(rbd->m_padding)); +#endif + return btRigidBodyDataName; } diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.h b/extern/bullet/src/BulletDynamics/Dynamics/btRigidBody.h similarity index 99% rename from extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.h rename to extern/bullet/src/BulletDynamics/Dynamics/btRigidBody.h index c2f8c5d64ae0..dbbf9958618c 100644 --- a/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.h +++ b/extern/bullet/src/BulletDynamics/Dynamics/btRigidBody.h @@ -135,6 +135,8 @@ class btRigidBody : public btCollisionObject ///the m_rollingFriction prevents rounded shapes, such as spheres, cylinders and capsules from rolling forever. ///See Bullet/Demos/RollingFrictionDemo for usage btScalar m_rollingFriction; + btScalar m_spinningFriction;//torsional friction around contact normal + ///best simulation results using zero restitution. btScalar m_restitution; @@ -158,6 +160,7 @@ class btRigidBody : public btCollisionObject m_angularDamping(btScalar(0.)), m_friction(btScalar(0.5)), m_rollingFriction(btScalar(0)), + m_spinningFriction(btScalar(0)), m_restitution(btScalar(0.)), m_linearSleepingThreshold(btScalar(0.8)), m_angularSleepingThreshold(btScalar(1.f)), diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp b/extern/bullet/src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp similarity index 98% rename from extern/bullet2/src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp rename to extern/bullet/src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp index 35dd38840f60..6f63b87c80ae 100644 --- a/extern/bullet2/src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp +++ b/extern/bullet/src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp @@ -155,7 +155,7 @@ void btSimpleDynamicsWorld::addRigidBody(btRigidBody* body) } } -void btSimpleDynamicsWorld::addRigidBody(btRigidBody* body, short group, short mask) +void btSimpleDynamicsWorld::addRigidBody(btRigidBody* body, int group, int mask) { body->setGravity(m_gravity); diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.h b/extern/bullet/src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.h similarity index 97% rename from extern/bullet2/src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.h rename to extern/bullet/src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.h index d48d2e39c4d1..44b7e7fb34b2 100644 --- a/extern/bullet2/src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.h +++ b/extern/bullet/src/BulletDynamics/Dynamics/btSimpleDynamicsWorld.h @@ -56,7 +56,7 @@ class btSimpleDynamicsWorld : public btDynamicsWorld virtual void addRigidBody(btRigidBody* body); - virtual void addRigidBody(btRigidBody* body, short group, short mask); + virtual void addRigidBody(btRigidBody* body, int group, int mask); virtual void removeRigidBody(btRigidBody* body); diff --git a/extern/bullet/src/BulletDynamics/Dynamics/btSimulationIslandManagerMt.cpp b/extern/bullet/src/BulletDynamics/Dynamics/btSimulationIslandManagerMt.cpp new file mode 100644 index 000000000000..99b34353c781 --- /dev/null +++ b/extern/bullet/src/BulletDynamics/Dynamics/btSimulationIslandManagerMt.cpp @@ -0,0 +1,678 @@ +/* +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 "LinearMath/btThreads.h" +#include "btSimulationIslandManagerMt.h" +#include "BulletCollision/BroadphaseCollision/btDispatcher.h" +#include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" +#include "BulletCollision/CollisionDispatch/btCollisionWorld.h" +#include "BulletDynamics/ConstraintSolver/btTypedConstraint.h" + +//#include +#include "LinearMath/btQuickprof.h" + + +SIMD_FORCE_INLINE int calcBatchCost( int bodies, int manifolds, int constraints ) +{ + // rough estimate of the cost of a batch, used for merging + int batchCost = bodies + 8 * manifolds + 4 * constraints; + return batchCost; +} + + +SIMD_FORCE_INLINE int calcBatchCost( const btSimulationIslandManagerMt::Island* island ) +{ + return calcBatchCost( island->bodyArray.size(), island->manifoldArray.size(), island->constraintArray.size() ); +} + + +btSimulationIslandManagerMt::btSimulationIslandManagerMt() +{ + m_minimumSolverBatchSize = calcBatchCost(0, 128, 0); + m_batchIslandMinBodyCount = 32; + m_islandDispatch = parallelIslandDispatch; + m_batchIsland = NULL; +} + + +btSimulationIslandManagerMt::~btSimulationIslandManagerMt() +{ + for ( int i = 0; i < m_allocatedIslands.size(); ++i ) + { + delete m_allocatedIslands[ i ]; + } + m_allocatedIslands.resize( 0 ); + m_activeIslands.resize( 0 ); + m_freeIslands.resize( 0 ); +} + + +inline int getIslandId(const btPersistentManifold* lhs) +{ + const btCollisionObject* rcolObj0 = static_cast(lhs->getBody0()); + const btCollisionObject* rcolObj1 = static_cast(lhs->getBody1()); + int islandId = rcolObj0->getIslandTag() >= 0 ? rcolObj0->getIslandTag() : rcolObj1->getIslandTag(); + return islandId; +} + + +SIMD_FORCE_INLINE int btGetConstraintIslandId( const btTypedConstraint* lhs ) +{ + const btCollisionObject& rcolObj0 = lhs->getRigidBodyA(); + const btCollisionObject& rcolObj1 = lhs->getRigidBodyB(); + int islandId = rcolObj0.getIslandTag() >= 0 ? rcolObj0.getIslandTag() : rcolObj1.getIslandTag(); + return islandId; +} + +/// function object that routes calls to operator< +class IslandBatchSizeSortPredicate +{ +public: + bool operator() ( const btSimulationIslandManagerMt::Island* lhs, const btSimulationIslandManagerMt::Island* rhs ) const + { + int lCost = calcBatchCost( lhs ); + int rCost = calcBatchCost( rhs ); + return lCost > rCost; + } +}; + + +class IslandBodyCapacitySortPredicate +{ +public: + bool operator() ( const btSimulationIslandManagerMt::Island* lhs, const btSimulationIslandManagerMt::Island* rhs ) const + { + return lhs->bodyArray.capacity() > rhs->bodyArray.capacity(); + } +}; + + +void btSimulationIslandManagerMt::Island::append( const Island& other ) +{ + // append bodies + for ( int i = 0; i < other.bodyArray.size(); ++i ) + { + bodyArray.push_back( other.bodyArray[ i ] ); + } + // append manifolds + for ( int i = 0; i < other.manifoldArray.size(); ++i ) + { + manifoldArray.push_back( other.manifoldArray[ i ] ); + } + // append constraints + for ( int i = 0; i < other.constraintArray.size(); ++i ) + { + constraintArray.push_back( other.constraintArray[ i ] ); + } +} + + +bool btIsBodyInIsland( const btSimulationIslandManagerMt::Island& island, const btCollisionObject* obj ) +{ + for ( int i = 0; i < island.bodyArray.size(); ++i ) + { + if ( island.bodyArray[ i ] == obj ) + { + return true; + } + } + return false; +} + + +void btSimulationIslandManagerMt::initIslandPools() +{ + // reset island pools + int numElem = getUnionFind().getNumElements(); + m_lookupIslandFromId.resize( numElem ); + for ( int i = 0; i < m_lookupIslandFromId.size(); ++i ) + { + m_lookupIslandFromId[ i ] = NULL; + } + m_activeIslands.resize( 0 ); + m_freeIslands.resize( 0 ); + // check whether allocated islands are sorted by body capacity (largest to smallest) + int lastCapacity = 0; + bool isSorted = true; + for ( int i = 0; i < m_allocatedIslands.size(); ++i ) + { + Island* island = m_allocatedIslands[ i ]; + int cap = island->bodyArray.capacity(); + if ( cap > lastCapacity ) + { + isSorted = false; + break; + } + lastCapacity = cap; + } + if ( !isSorted ) + { + m_allocatedIslands.quickSort( IslandBodyCapacitySortPredicate() ); + } + + m_batchIsland = NULL; + // mark all islands free (but avoid deallocation) + for ( int i = 0; i < m_allocatedIslands.size(); ++i ) + { + Island* island = m_allocatedIslands[ i ]; + island->bodyArray.resize( 0 ); + island->manifoldArray.resize( 0 ); + island->constraintArray.resize( 0 ); + island->id = -1; + island->isSleeping = true; + m_freeIslands.push_back( island ); + } +} + + +btSimulationIslandManagerMt::Island* btSimulationIslandManagerMt::getIsland( int id ) +{ + Island* island = m_lookupIslandFromId[ id ]; + if ( island == NULL ) + { + // search for existing island + for ( int i = 0; i < m_activeIslands.size(); ++i ) + { + if ( m_activeIslands[ i ]->id == id ) + { + island = m_activeIslands[ i ]; + break; + } + } + m_lookupIslandFromId[ id ] = island; + } + return island; +} + + +btSimulationIslandManagerMt::Island* btSimulationIslandManagerMt::allocateIsland( int id, int numBodies ) +{ + Island* island = NULL; + int allocSize = numBodies; + if ( numBodies < m_batchIslandMinBodyCount ) + { + if ( m_batchIsland ) + { + island = m_batchIsland; + m_lookupIslandFromId[ id ] = island; + // if we've made a large enough batch, + if ( island->bodyArray.size() + numBodies >= m_batchIslandMinBodyCount ) + { + // next time start a new batch + m_batchIsland = NULL; + } + return island; + } + else + { + // need to allocate a batch island + allocSize = m_batchIslandMinBodyCount * 2; + } + } + btAlignedObjectArray& freeIslands = m_freeIslands; + + // search for free island + if ( freeIslands.size() > 0 ) + { + // try to reuse a previously allocated island + int iFound = freeIslands.size(); + // linear search for smallest island that can hold our bodies + for ( int i = freeIslands.size() - 1; i >= 0; --i ) + { + if ( freeIslands[ i ]->bodyArray.capacity() >= allocSize ) + { + iFound = i; + island = freeIslands[ i ]; + island->id = id; + break; + } + } + // if found, shrink array while maintaining ordering + if ( island ) + { + int iDest = iFound; + int iSrc = iDest + 1; + while ( iSrc < freeIslands.size() ) + { + freeIslands[ iDest++ ] = freeIslands[ iSrc++ ]; + } + freeIslands.pop_back(); + } + } + if ( island == NULL ) + { + // no free island found, allocate + island = new Island(); // TODO: change this to use the pool allocator + island->id = id; + island->bodyArray.reserve( allocSize ); + m_allocatedIslands.push_back( island ); + } + m_lookupIslandFromId[ id ] = island; + if ( numBodies < m_batchIslandMinBodyCount ) + { + m_batchIsland = island; + } + m_activeIslands.push_back( island ); + return island; +} + + +void btSimulationIslandManagerMt::buildIslands( btDispatcher* dispatcher, btCollisionWorld* collisionWorld ) +{ + + BT_PROFILE("islandUnionFindAndQuickSort"); + + btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray(); + + //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"); + } + + btAssert((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"); + } + + btAssert((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"); + } + + btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1)); + + if (colObj0->getIslandTag() == islandId) + { + if ( colObj0->getActivationState() == ISLAND_SLEEPING) + { + colObj0->setActivationState( WANTS_DEACTIVATION); + colObj0->setDeactivationTime(0.f); + } + } + } + } + } +} + + +void btSimulationIslandManagerMt::addBodiesToIslands( btCollisionWorld* collisionWorld ) +{ + btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray(); + int endIslandIndex = 1; + int startIslandIndex; + int numElem = getUnionFind().getNumElements(); + + // create explicit islands and add bodies to each + for ( startIslandIndex = 0; startIslandIndex < numElem; startIslandIndex = endIslandIndex ) + { + int islandId = getUnionFind().getElement( startIslandIndex ).m_id; + + // find end index + for ( endIslandIndex = startIslandIndex; ( endIslandIndex < numElem ) && ( getUnionFind().getElement( endIslandIndex ).m_id == islandId ); endIslandIndex++ ) + { + } + // check if island is sleeping + bool islandSleeping = true; + for ( int iElem = startIslandIndex; iElem < endIslandIndex; iElem++ ) + { + int i = getUnionFind().getElement( iElem ).m_sz; + btCollisionObject* colObj = collisionObjects[ i ]; + if ( colObj->isActive() ) + { + islandSleeping = false; + } + } + if ( !islandSleeping ) + { + // want to count the number of bodies before allocating the island to optimize memory usage of the Island structures + int numBodies = endIslandIndex - startIslandIndex; + Island* island = allocateIsland( islandId, numBodies ); + island->isSleeping = false; + + // add bodies to island + for ( int iElem = startIslandIndex; iElem < endIslandIndex; iElem++ ) + { + int i = getUnionFind().getElement( iElem ).m_sz; + btCollisionObject* colObj = collisionObjects[ i ]; + island->bodyArray.push_back( colObj ); + } + } + } + +} + + +void btSimulationIslandManagerMt::addManifoldsToIslands( btDispatcher* dispatcher ) +{ + // walk all the manifolds, activating bodies touched by kinematic objects, and add each manifold to its Island + int maxNumManifolds = dispatcher->getNumManifolds(); + for ( int i = 0; i < maxNumManifolds; i++ ) + { + btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal( i ); + + const btCollisionObject* colObj0 = static_cast( manifold->getBody0() ); + const 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->isKinematicObject() && colObj0->getActivationState() != ISLAND_SLEEPING ) + { + if ( colObj0->hasContactResponse() ) + colObj1->activate(); + } + if ( colObj1->isKinematicObject() && colObj1->getActivationState() != ISLAND_SLEEPING ) + { + if ( colObj1->hasContactResponse() ) + colObj0->activate(); + } + //filtering for response + if ( dispatcher->needsResponse( colObj0, colObj1 ) ) + { + // scatter manifolds into various islands + int islandId = getIslandId( manifold ); + // if island not sleeping, + if ( Island* island = getIsland( islandId ) ) + { + island->manifoldArray.push_back( manifold ); + } + } + } + } +} + + +void btSimulationIslandManagerMt::addConstraintsToIslands( btAlignedObjectArray& constraints ) +{ + // walk constraints + for ( int i = 0; i < constraints.size(); i++ ) + { + // scatter constraints into various islands + btTypedConstraint* constraint = constraints[ i ]; + if ( constraint->isEnabled() ) + { + int islandId = btGetConstraintIslandId( constraint ); + // if island is not sleeping, + if ( Island* island = getIsland( islandId ) ) + { + island->constraintArray.push_back( constraint ); + } + } + } +} + + +void btSimulationIslandManagerMt::mergeIslands() +{ + // sort islands in order of decreasing batch size + m_activeIslands.quickSort( IslandBatchSizeSortPredicate() ); + + // merge small islands to satisfy minimum batch size + // find first small batch island + int destIslandIndex = m_activeIslands.size(); + for ( int i = 0; i < m_activeIslands.size(); ++i ) + { + Island* island = m_activeIslands[ i ]; + int batchSize = calcBatchCost( island ); + if ( batchSize < m_minimumSolverBatchSize ) + { + destIslandIndex = i; + break; + } + } + int lastIndex = m_activeIslands.size() - 1; + while ( destIslandIndex < lastIndex ) + { + // merge islands from the back of the list + Island* island = m_activeIslands[ destIslandIndex ]; + int numBodies = island->bodyArray.size(); + int numManifolds = island->manifoldArray.size(); + int numConstraints = island->constraintArray.size(); + int firstIndex = lastIndex; + // figure out how many islands we want to merge and find out how many bodies, manifolds and constraints we will have + while ( true ) + { + Island* src = m_activeIslands[ firstIndex ]; + numBodies += src->bodyArray.size(); + numManifolds += src->manifoldArray.size(); + numConstraints += src->constraintArray.size(); + int batchCost = calcBatchCost( numBodies, numManifolds, numConstraints ); + if ( batchCost >= m_minimumSolverBatchSize ) + { + break; + } + if ( firstIndex - 1 == destIslandIndex ) + { + break; + } + firstIndex--; + } + // reserve space for these pointers to minimize reallocation + island->bodyArray.reserve( numBodies ); + island->manifoldArray.reserve( numManifolds ); + island->constraintArray.reserve( numConstraints ); + // merge islands + for ( int i = firstIndex; i <= lastIndex; ++i ) + { + island->append( *m_activeIslands[ i ] ); + } + // shrink array to exclude the islands that were merged from + m_activeIslands.resize( firstIndex ); + lastIndex = firstIndex - 1; + destIslandIndex++; + } +} + + +void btSimulationIslandManagerMt::serialIslandDispatch( btAlignedObjectArray* islandsPtr, IslandCallback* callback ) +{ + BT_PROFILE( "serialIslandDispatch" ); + // serial dispatch + btAlignedObjectArray& islands = *islandsPtr; + for ( int i = 0; i < islands.size(); ++i ) + { + Island* island = islands[ i ]; + btPersistentManifold** manifolds = island->manifoldArray.size() ? &island->manifoldArray[ 0 ] : NULL; + btTypedConstraint** constraintsPtr = island->constraintArray.size() ? &island->constraintArray[ 0 ] : NULL; + callback->processIsland( &island->bodyArray[ 0 ], + island->bodyArray.size(), + manifolds, + island->manifoldArray.size(), + constraintsPtr, + island->constraintArray.size(), + island->id + ); + } +} + +struct UpdateIslandDispatcher : public btIParallelForBody +{ + btAlignedObjectArray* islandsPtr; + btSimulationIslandManagerMt::IslandCallback* callback; + + void forLoop( int iBegin, int iEnd ) const BT_OVERRIDE + { + for ( int i = iBegin; i < iEnd; ++i ) + { + btSimulationIslandManagerMt::Island* island = ( *islandsPtr )[ i ]; + btPersistentManifold** manifolds = island->manifoldArray.size() ? &island->manifoldArray[ 0 ] : NULL; + btTypedConstraint** constraintsPtr = island->constraintArray.size() ? &island->constraintArray[ 0 ] : NULL; + callback->processIsland( &island->bodyArray[ 0 ], + island->bodyArray.size(), + manifolds, + island->manifoldArray.size(), + constraintsPtr, + island->constraintArray.size(), + island->id + ); + } + } +}; + +void btSimulationIslandManagerMt::parallelIslandDispatch( btAlignedObjectArray* islandsPtr, IslandCallback* callback ) +{ + BT_PROFILE( "parallelIslandDispatch" ); + int grainSize = 1; // iterations per task + UpdateIslandDispatcher dispatcher; + dispatcher.islandsPtr = islandsPtr; + dispatcher.callback = callback; + btParallelFor( 0, islandsPtr->size(), grainSize, dispatcher ); +} + + +///@todo: this is random access, it can be walked 'cache friendly'! +void btSimulationIslandManagerMt::buildAndProcessIslands( btDispatcher* dispatcher, + btCollisionWorld* collisionWorld, + btAlignedObjectArray& constraints, + IslandCallback* callback + ) +{ + btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray(); + + buildIslands(dispatcher,collisionWorld); + + BT_PROFILE("processIslands"); + + if(!getSplitIslands()) + { + btPersistentManifold** manifolds = dispatcher->getInternalManifoldPointer(); + int maxNumManifolds = dispatcher->getNumManifolds(); + + for ( int i = 0; i < maxNumManifolds; i++ ) + { + btPersistentManifold* manifold = manifolds[ i ]; + + const btCollisionObject* colObj0 = static_cast( manifold->getBody0() ); + const 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->isKinematicObject() && colObj0->getActivationState() != ISLAND_SLEEPING ) + { + if ( colObj0->hasContactResponse() ) + colObj1->activate(); + } + if ( colObj1->isKinematicObject() && colObj1->getActivationState() != ISLAND_SLEEPING ) + { + if ( colObj1->hasContactResponse() ) + colObj0->activate(); + } + } + } + btTypedConstraint** constraintsPtr = constraints.size() ? &constraints[ 0 ] : NULL; + callback->processIsland(&collisionObjects[0], + collisionObjects.size(), + manifolds, + maxNumManifolds, + constraintsPtr, + constraints.size(), + -1 + ); + } + else + { + initIslandPools(); + + //traverse the simulation islands, and call the solver, unless all objects are sleeping/deactivated + addBodiesToIslands( collisionWorld ); + addManifoldsToIslands( dispatcher ); + addConstraintsToIslands( constraints ); + + // m_activeIslands array should now contain all non-sleeping Islands, and each Island should + // have all the necessary bodies, manifolds and constraints. + + // if we want to merge islands with small batch counts, + if ( m_minimumSolverBatchSize > 1 ) + { + mergeIslands(); + } + // dispatch islands to solver + m_islandDispatch( &m_activeIslands, callback ); + } +} diff --git a/extern/bullet/src/BulletDynamics/Dynamics/btSimulationIslandManagerMt.h b/extern/bullet/src/BulletDynamics/Dynamics/btSimulationIslandManagerMt.h new file mode 100644 index 000000000000..9a781aaef16e --- /dev/null +++ b/extern/bullet/src/BulletDynamics/Dynamics/btSimulationIslandManagerMt.h @@ -0,0 +1,110 @@ +/* +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_SIMULATION_ISLAND_MANAGER_MT_H +#define BT_SIMULATION_ISLAND_MANAGER_MT_H + +#include "BulletCollision/CollisionDispatch/btSimulationIslandManager.h" + +class btTypedConstraint; + + +/// +/// SimulationIslandManagerMt -- Multithread capable version of SimulationIslandManager +/// Splits the world up into islands which can be solved in parallel. +/// In order to solve islands in parallel, an IslandDispatch function +/// must be provided which will dispatch calls to multiple threads. +/// The amount of parallelism that can be achieved depends on the number +/// of islands. If only a single island exists, then no parallelism is +/// possible. +/// +class btSimulationIslandManagerMt : public btSimulationIslandManager +{ +public: + struct Island + { + // a simulation island consisting of bodies, manifolds and constraints, + // to be passed into a constraint solver. + btAlignedObjectArray bodyArray; + btAlignedObjectArray manifoldArray; + btAlignedObjectArray constraintArray; + int id; // island id + bool isSleeping; + + void append( const Island& other ); // add bodies, manifolds, constraints to my own + }; + struct IslandCallback + { + virtual ~IslandCallback() {}; + + virtual void processIsland( btCollisionObject** bodies, + int numBodies, + btPersistentManifold** manifolds, + int numManifolds, + btTypedConstraint** constraints, + int numConstraints, + int islandId + ) = 0; + }; + typedef void( *IslandDispatchFunc ) ( btAlignedObjectArray* islands, IslandCallback* callback ); + static void serialIslandDispatch( btAlignedObjectArray* islandsPtr, IslandCallback* callback ); + static void parallelIslandDispatch( btAlignedObjectArray* islandsPtr, IslandCallback* callback ); +protected: + btAlignedObjectArray m_allocatedIslands; // owner of all Islands + btAlignedObjectArray m_activeIslands; // islands actively in use + btAlignedObjectArray m_freeIslands; // islands ready to be reused + btAlignedObjectArray m_lookupIslandFromId; // big lookup table to map islandId to Island pointer + Island* m_batchIsland; + int m_minimumSolverBatchSize; + int m_batchIslandMinBodyCount; + IslandDispatchFunc m_islandDispatch; + + Island* getIsland( int id ); + virtual Island* allocateIsland( int id, int numBodies ); + virtual void initIslandPools(); + virtual void addBodiesToIslands( btCollisionWorld* collisionWorld ); + virtual void addManifoldsToIslands( btDispatcher* dispatcher ); + virtual void addConstraintsToIslands( btAlignedObjectArray& constraints ); + virtual void mergeIslands(); + +public: + btSimulationIslandManagerMt(); + virtual ~btSimulationIslandManagerMt(); + + virtual void buildAndProcessIslands( btDispatcher* dispatcher, btCollisionWorld* collisionWorld, btAlignedObjectArray& constraints, IslandCallback* callback ); + + virtual void buildIslands(btDispatcher* dispatcher,btCollisionWorld* colWorld); + + int getMinimumSolverBatchSize() const + { + return m_minimumSolverBatchSize; + } + void setMinimumSolverBatchSize( int sz ) + { + m_minimumSolverBatchSize = sz; + } + IslandDispatchFunc getIslandDispatchFunction() const + { + return m_islandDispatch; + } + // allow users to set their own dispatch function for multithreaded dispatch + void setIslandDispatchFunction( IslandDispatchFunc func ) + { + m_islandDispatch = func; + } +}; + +#endif //BT_SIMULATION_ISLAND_MANAGER_H + diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.cpp b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBody.cpp similarity index 89% rename from extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.cpp rename to extern/bullet/src/BulletDynamics/Featherstone/btMultiBody.cpp index aea8c6837326..036b226e8dbc 100644 --- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.cpp +++ b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBody.cpp @@ -1,1946 +1,2040 @@ -/* - * PURPOSE: - * Class representing an articulated rigid body. Stores the body's - * current state, allows forces and torques to be set, handles - * timestepping and implements Featherstone's algorithm. - * - * COPYRIGHT: - * Copyright (C) Stephen Thompson, , 2011-2013 - * Portions written By Erwin Coumans: connection to LCP solver, various multibody constraints, replacing Eigen math library by Bullet LinearMath and a dedicated 6x6 matrix inverse (solveImatrix) - * Portions written By Jakub Stepien: support for multi-DOF constraints, introduction of spatial algebra and several other improvements - - 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 "btMultiBody.h" -#include "btMultiBodyLink.h" -#include "btMultiBodyLinkCollider.h" -#include "btMultiBodyJointFeedback.h" -#include "LinearMath/btTransformUtil.h" -#include "LinearMath/btSerializer.h" -// #define INCLUDE_GYRO_TERM - -///todo: determine if we need these options. If so, make a proper API, otherwise delete those globals -bool gJointFeedbackInWorldSpace = false; -bool gJointFeedbackInJointFrame = false; - -namespace { - const btScalar SLEEP_EPSILON = btScalar(0.05); // this is a squared velocity (m^2 s^-2) - const btScalar SLEEP_TIMEOUT = btScalar(2); // in seconds -} - -namespace { - void SpatialTransform(const btMatrix3x3 &rotation_matrix, // rotates vectors in 'from' frame to vectors in 'to' frame - const btVector3 &displacement, // vector from origin of 'from' frame to origin of 'to' frame, in 'to' coordinates - const btVector3 &top_in, // top part of input vector - const btVector3 &bottom_in, // bottom part of input vector - btVector3 &top_out, // top part of output vector - btVector3 &bottom_out) // bottom part of output vector - { - top_out = rotation_matrix * top_in; - bottom_out = -displacement.cross(top_out) + rotation_matrix * bottom_in; - } - -/* - void InverseSpatialTransform(const btMatrix3x3 &rotation_matrix, - const btVector3 &displacement, - const btVector3 &top_in, - const btVector3 &bottom_in, - btVector3 &top_out, - btVector3 &bottom_out) - { - top_out = rotation_matrix.transpose() * top_in; - bottom_out = rotation_matrix.transpose() * (bottom_in + displacement.cross(top_in)); - } - - btScalar SpatialDotProduct(const btVector3 &a_top, - const btVector3 &a_bottom, - const btVector3 &b_top, - const btVector3 &b_bottom) - { - return a_bottom.dot(b_top) + a_top.dot(b_bottom); - } - - void SpatialCrossProduct(const btVector3 &a_top, - const btVector3 &a_bottom, - const btVector3 &b_top, - const btVector3 &b_bottom, - btVector3 &top_out, - btVector3 &bottom_out) - { - top_out = a_top.cross(b_top); - bottom_out = a_bottom.cross(b_top) + a_top.cross(b_bottom); - } -*/ -} - - -// -// Implementation of class btMultiBody -// - -btMultiBody::btMultiBody(int n_links, - btScalar mass, - const btVector3 &inertia, - bool fixedBase, - bool canSleep, - bool /*deprecatedUseMultiDof*/) - : - m_baseCollider(0), - m_baseName(0), - m_basePos(0,0,0), - m_baseQuat(0, 0, 0, 1), - m_baseMass(mass), - m_baseInertia(inertia), - - m_fixedBase(fixedBase), - m_awake(true), - m_canSleep(canSleep), - m_sleepTimer(0), - - m_linearDamping(0.04f), - m_angularDamping(0.04f), - m_useGyroTerm(true), - m_maxAppliedImpulse(1000.f), - m_maxCoordinateVelocity(100.f), - m_hasSelfCollision(true), - __posUpdated(false), - m_dofCount(0), - m_posVarCnt(0), - m_useRK4(false), - m_useGlobalVelocities(false), - m_internalNeedsJointFeedback(false) -{ - m_links.resize(n_links); - m_matrixBuf.resize(n_links + 1); - - - m_baseForce.setValue(0, 0, 0); - m_baseTorque.setValue(0, 0, 0); -} - -btMultiBody::~btMultiBody() -{ -} - -void btMultiBody::setupFixed(int i, - btScalar mass, - const btVector3 &inertia, - int parent, - const btQuaternion &rotParentToThis, - const btVector3 &parentComToThisPivotOffset, - const btVector3 &thisPivotToThisComOffset, bool /*deprecatedDisableParentCollision*/) -{ - - m_links[i].m_mass = mass; - m_links[i].m_inertiaLocal = inertia; - m_links[i].m_parent = parent; - m_links[i].m_zeroRotParentToThis = rotParentToThis; - m_links[i].m_dVector = thisPivotToThisComOffset; - m_links[i].m_eVector = parentComToThisPivotOffset; - - m_links[i].m_jointType = btMultibodyLink::eFixed; - m_links[i].m_dofCount = 0; - m_links[i].m_posVarCount = 0; - - m_links[i].m_flags |=BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION; - - m_links[i].updateCacheMultiDof(); - - updateLinksDofOffsets(); - -} - - -void btMultiBody::setupPrismatic(int i, - btScalar mass, - const btVector3 &inertia, - int parent, - const btQuaternion &rotParentToThis, - const btVector3 &jointAxis, - const btVector3 &parentComToThisPivotOffset, - const btVector3 &thisPivotToThisComOffset, - bool disableParentCollision) -{ - m_dofCount += 1; - m_posVarCnt += 1; - - m_links[i].m_mass = mass; - m_links[i].m_inertiaLocal = inertia; - m_links[i].m_parent = parent; - m_links[i].m_zeroRotParentToThis = rotParentToThis; - m_links[i].setAxisTop(0, 0., 0., 0.); - m_links[i].setAxisBottom(0, jointAxis); - m_links[i].m_eVector = parentComToThisPivotOffset; - m_links[i].m_dVector = thisPivotToThisComOffset; - m_links[i].m_cachedRotParentToThis = rotParentToThis; - - m_links[i].m_jointType = btMultibodyLink::ePrismatic; - m_links[i].m_dofCount = 1; - m_links[i].m_posVarCount = 1; - m_links[i].m_jointPos[0] = 0.f; - m_links[i].m_jointTorque[0] = 0.f; - - if (disableParentCollision) - m_links[i].m_flags |=BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION; - // - - m_links[i].updateCacheMultiDof(); - - updateLinksDofOffsets(); -} - -void btMultiBody::setupRevolute(int i, - btScalar mass, - const btVector3 &inertia, - int parent, - const btQuaternion &rotParentToThis, - const btVector3 &jointAxis, - const btVector3 &parentComToThisPivotOffset, - const btVector3 &thisPivotToThisComOffset, - bool disableParentCollision) -{ - m_dofCount += 1; - m_posVarCnt += 1; - - m_links[i].m_mass = mass; - m_links[i].m_inertiaLocal = inertia; - m_links[i].m_parent = parent; - m_links[i].m_zeroRotParentToThis = rotParentToThis; - m_links[i].setAxisTop(0, jointAxis); - m_links[i].setAxisBottom(0, jointAxis.cross(thisPivotToThisComOffset)); - m_links[i].m_dVector = thisPivotToThisComOffset; - m_links[i].m_eVector = parentComToThisPivotOffset; - - m_links[i].m_jointType = btMultibodyLink::eRevolute; - m_links[i].m_dofCount = 1; - m_links[i].m_posVarCount = 1; - m_links[i].m_jointPos[0] = 0.f; - m_links[i].m_jointTorque[0] = 0.f; - - if (disableParentCollision) - m_links[i].m_flags |=BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION; - // - m_links[i].updateCacheMultiDof(); - // - updateLinksDofOffsets(); -} - - - -void btMultiBody::setupSpherical(int i, - btScalar mass, - const btVector3 &inertia, - int parent, - const btQuaternion &rotParentToThis, - const btVector3 &parentComToThisPivotOffset, - const btVector3 &thisPivotToThisComOffset, - bool disableParentCollision) -{ - - m_dofCount += 3; - m_posVarCnt += 4; - - m_links[i].m_mass = mass; - m_links[i].m_inertiaLocal = inertia; - m_links[i].m_parent = parent; - m_links[i].m_zeroRotParentToThis = rotParentToThis; - m_links[i].m_dVector = thisPivotToThisComOffset; - m_links[i].m_eVector = parentComToThisPivotOffset; - - m_links[i].m_jointType = btMultibodyLink::eSpherical; - m_links[i].m_dofCount = 3; - m_links[i].m_posVarCount = 4; - m_links[i].setAxisTop(0, 1.f, 0.f, 0.f); - m_links[i].setAxisTop(1, 0.f, 1.f, 0.f); - m_links[i].setAxisTop(2, 0.f, 0.f, 1.f); - m_links[i].setAxisBottom(0, m_links[i].getAxisTop(0).cross(thisPivotToThisComOffset)); - m_links[i].setAxisBottom(1, m_links[i].getAxisTop(1).cross(thisPivotToThisComOffset)); - m_links[i].setAxisBottom(2, m_links[i].getAxisTop(2).cross(thisPivotToThisComOffset)); - m_links[i].m_jointPos[0] = m_links[i].m_jointPos[1] = m_links[i].m_jointPos[2] = 0.f; m_links[i].m_jointPos[3] = 1.f; - m_links[i].m_jointTorque[0] = m_links[i].m_jointTorque[1] = m_links[i].m_jointTorque[2] = 0.f; - - - if (disableParentCollision) - m_links[i].m_flags |=BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION; - // - m_links[i].updateCacheMultiDof(); - // - updateLinksDofOffsets(); -} - -void btMultiBody::setupPlanar(int i, - btScalar mass, - const btVector3 &inertia, - int parent, - const btQuaternion &rotParentToThis, - const btVector3 &rotationAxis, - const btVector3 &parentComToThisComOffset, - bool disableParentCollision) -{ - - m_dofCount += 3; - m_posVarCnt += 3; - - m_links[i].m_mass = mass; - m_links[i].m_inertiaLocal = inertia; - m_links[i].m_parent = parent; - m_links[i].m_zeroRotParentToThis = rotParentToThis; - m_links[i].m_dVector.setZero(); - m_links[i].m_eVector = parentComToThisComOffset; - - // - static btVector3 vecNonParallelToRotAxis(1, 0, 0); - if(rotationAxis.normalized().dot(vecNonParallelToRotAxis) > 0.999) - vecNonParallelToRotAxis.setValue(0, 1, 0); - // - - m_links[i].m_jointType = btMultibodyLink::ePlanar; - m_links[i].m_dofCount = 3; - m_links[i].m_posVarCount = 3; - btVector3 n=rotationAxis.normalized(); - m_links[i].setAxisTop(0, n[0],n[1],n[2]); - m_links[i].setAxisTop(1,0,0,0); - m_links[i].setAxisTop(2,0,0,0); - m_links[i].setAxisBottom(0,0,0,0); - btVector3 cr = m_links[i].getAxisTop(0).cross(vecNonParallelToRotAxis); - m_links[i].setAxisBottom(1,cr[0],cr[1],cr[2]); - cr = m_links[i].getAxisBottom(1).cross(m_links[i].getAxisTop(0)); - m_links[i].setAxisBottom(2,cr[0],cr[1],cr[2]); - m_links[i].m_jointPos[0] = m_links[i].m_jointPos[1] = m_links[i].m_jointPos[2] = 0.f; - m_links[i].m_jointTorque[0] = m_links[i].m_jointTorque[1] = m_links[i].m_jointTorque[2] = 0.f; - - if (disableParentCollision) - m_links[i].m_flags |=BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION; - // - m_links[i].updateCacheMultiDof(); - // - updateLinksDofOffsets(); -} - -void btMultiBody::finalizeMultiDof() -{ - m_deltaV.resize(0); - m_deltaV.resize(6 + m_dofCount); - m_realBuf.resize(6 + m_dofCount + m_dofCount*m_dofCount + 6 + m_dofCount); //m_dofCount for joint-space vels + m_dofCount^2 for "D" matrices + delta-pos vector (6 base "vels" + joint "vels") - m_vectorBuf.resize(2 * m_dofCount); //two 3-vectors (i.e. one six-vector) for each system dof ("h" matrices) - - updateLinksDofOffsets(); -} - -int btMultiBody::getParent(int i) const -{ - return m_links[i].m_parent; -} - -btScalar btMultiBody::getLinkMass(int i) const -{ - return m_links[i].m_mass; -} - -const btVector3 & btMultiBody::getLinkInertia(int i) const -{ - return m_links[i].m_inertiaLocal; -} - -btScalar btMultiBody::getJointPos(int i) const -{ - return m_links[i].m_jointPos[0]; -} - -btScalar btMultiBody::getJointVel(int i) const -{ - return m_realBuf[6 + m_links[i].m_dofOffset]; -} - -btScalar * btMultiBody::getJointPosMultiDof(int i) -{ - return &m_links[i].m_jointPos[0]; -} - -btScalar * btMultiBody::getJointVelMultiDof(int i) -{ - return &m_realBuf[6 + m_links[i].m_dofOffset]; -} - -const btScalar * btMultiBody::getJointPosMultiDof(int i) const -{ - return &m_links[i].m_jointPos[0]; -} - -const btScalar * btMultiBody::getJointVelMultiDof(int i) const -{ - return &m_realBuf[6 + m_links[i].m_dofOffset]; -} - - -void btMultiBody::setJointPos(int i, btScalar q) -{ - m_links[i].m_jointPos[0] = q; - m_links[i].updateCacheMultiDof(); -} - -void btMultiBody::setJointPosMultiDof(int i, btScalar *q) -{ - for(int pos = 0; pos < m_links[i].m_posVarCount; ++pos) - m_links[i].m_jointPos[pos] = q[pos]; - - m_links[i].updateCacheMultiDof(); -} - -void btMultiBody::setJointVel(int i, btScalar qdot) -{ - m_realBuf[6 + m_links[i].m_dofOffset] = qdot; -} - -void btMultiBody::setJointVelMultiDof(int i, btScalar *qdot) -{ - for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) - m_realBuf[6 + m_links[i].m_dofOffset + dof] = qdot[dof]; -} - -const btVector3 & btMultiBody::getRVector(int i) const -{ - return m_links[i].m_cachedRVector; -} - -const btQuaternion & btMultiBody::getParentToLocalRot(int i) const -{ - return m_links[i].m_cachedRotParentToThis; -} - -btVector3 btMultiBody::localPosToWorld(int i, const btVector3 &local_pos) const -{ - btVector3 result = local_pos; - while (i != -1) { - // 'result' is in frame i. transform it to frame parent(i) - result += getRVector(i); - result = quatRotate(getParentToLocalRot(i).inverse(),result); - i = getParent(i); - } - - // 'result' is now in the base frame. transform it to world frame - result = quatRotate(getWorldToBaseRot().inverse() ,result); - result += getBasePos(); - - return result; -} - -btVector3 btMultiBody::worldPosToLocal(int i, const btVector3 &world_pos) const -{ - if (i == -1) { - // world to base - return quatRotate(getWorldToBaseRot(),(world_pos - getBasePos())); - } else { - // find position in parent frame, then transform to current frame - return quatRotate(getParentToLocalRot(i),worldPosToLocal(getParent(i), world_pos)) - getRVector(i); - } -} - -btVector3 btMultiBody::localDirToWorld(int i, const btVector3 &local_dir) const -{ - btVector3 result = local_dir; - while (i != -1) { - result = quatRotate(getParentToLocalRot(i).inverse() , result); - i = getParent(i); - } - result = quatRotate(getWorldToBaseRot().inverse() , result); - return result; -} - -btVector3 btMultiBody::worldDirToLocal(int i, const btVector3 &world_dir) const -{ - if (i == -1) { - return quatRotate(getWorldToBaseRot(), world_dir); - } else { - return quatRotate(getParentToLocalRot(i) ,worldDirToLocal(getParent(i), world_dir)); - } -} - -void btMultiBody::compTreeLinkVelocities(btVector3 *omega, btVector3 *vel) const -{ - int num_links = getNumLinks(); - // Calculates the velocities of each link (and the base) in its local frame - omega[0] = quatRotate(m_baseQuat ,getBaseOmega()); - vel[0] = quatRotate(m_baseQuat ,getBaseVel()); - - for (int i = 0; i < num_links; ++i) { - const int parent = m_links[i].m_parent; - - // transform parent vel into this frame, store in omega[i+1], vel[i+1] - SpatialTransform(btMatrix3x3(m_links[i].m_cachedRotParentToThis), m_links[i].m_cachedRVector, - omega[parent+1], vel[parent+1], - omega[i+1], vel[i+1]); - - // now add qidot * shat_i - omega[i+1] += getJointVel(i) * m_links[i].getAxisTop(0); - vel[i+1] += getJointVel(i) * m_links[i].getAxisBottom(0); - } -} - -btScalar btMultiBody::getKineticEnergy() const -{ - int num_links = getNumLinks(); - // TODO: would be better not to allocate memory here - btAlignedObjectArray omega;omega.resize(num_links+1); - btAlignedObjectArray vel;vel.resize(num_links+1); - compTreeLinkVelocities(&omega[0], &vel[0]); - - // we will do the factor of 0.5 at the end - btScalar result = m_baseMass * vel[0].dot(vel[0]); - result += omega[0].dot(m_baseInertia * omega[0]); - - for (int i = 0; i < num_links; ++i) { - result += m_links[i].m_mass * vel[i+1].dot(vel[i+1]); - result += omega[i+1].dot(m_links[i].m_inertiaLocal * omega[i+1]); - } - - return 0.5f * result; -} - -btVector3 btMultiBody::getAngularMomentum() const -{ - int num_links = getNumLinks(); - // TODO: would be better not to allocate memory here - btAlignedObjectArray omega;omega.resize(num_links+1); - btAlignedObjectArray vel;vel.resize(num_links+1); - btAlignedObjectArray rot_from_world;rot_from_world.resize(num_links+1); - compTreeLinkVelocities(&omega[0], &vel[0]); - - rot_from_world[0] = m_baseQuat; - btVector3 result = quatRotate(rot_from_world[0].inverse() , (m_baseInertia * omega[0])); - - for (int i = 0; i < num_links; ++i) { - rot_from_world[i+1] = m_links[i].m_cachedRotParentToThis * rot_from_world[m_links[i].m_parent+1]; - result += (quatRotate(rot_from_world[i+1].inverse() , (m_links[i].m_inertiaLocal * omega[i+1]))); - } - - return result; -} - -void btMultiBody::clearConstraintForces() -{ - m_baseConstraintForce.setValue(0, 0, 0); - m_baseConstraintTorque.setValue(0, 0, 0); - - - for (int i = 0; i < getNumLinks(); ++i) { - m_links[i].m_appliedConstraintForce.setValue(0, 0, 0); - m_links[i].m_appliedConstraintTorque.setValue(0, 0, 0); - } -} -void btMultiBody::clearForcesAndTorques() -{ - m_baseForce.setValue(0, 0, 0); - m_baseTorque.setValue(0, 0, 0); - - - for (int i = 0; i < getNumLinks(); ++i) { - m_links[i].m_appliedForce.setValue(0, 0, 0); - m_links[i].m_appliedTorque.setValue(0, 0, 0); - m_links[i].m_jointTorque[0] = m_links[i].m_jointTorque[1] = m_links[i].m_jointTorque[2] = m_links[i].m_jointTorque[3] = m_links[i].m_jointTorque[4] = m_links[i].m_jointTorque[5] = 0.f; - } -} - -void btMultiBody::clearVelocities() -{ - for (int i = 0; i < 6 + getNumLinks(); ++i) - { - m_realBuf[i] = 0.f; - } -} -void btMultiBody::addLinkForce(int i, const btVector3 &f) -{ - m_links[i].m_appliedForce += f; -} - -void btMultiBody::addLinkTorque(int i, const btVector3 &t) -{ - m_links[i].m_appliedTorque += t; -} - -void btMultiBody::addLinkConstraintForce(int i, const btVector3 &f) -{ - m_links[i].m_appliedConstraintForce += f; -} - -void btMultiBody::addLinkConstraintTorque(int i, const btVector3 &t) -{ - m_links[i].m_appliedConstraintTorque += t; -} - - - -void btMultiBody::addJointTorque(int i, btScalar Q) -{ - m_links[i].m_jointTorque[0] += Q; -} - -void btMultiBody::addJointTorqueMultiDof(int i, int dof, btScalar Q) -{ - m_links[i].m_jointTorque[dof] += Q; -} - -void btMultiBody::addJointTorqueMultiDof(int i, const btScalar *Q) -{ - for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) - m_links[i].m_jointTorque[dof] = Q[dof]; -} - -const btVector3 & btMultiBody::getLinkForce(int i) const -{ - return m_links[i].m_appliedForce; -} - -const btVector3 & btMultiBody::getLinkTorque(int i) const -{ - return m_links[i].m_appliedTorque; -} - -btScalar btMultiBody::getJointTorque(int i) const -{ - return m_links[i].m_jointTorque[0]; -} - -btScalar * btMultiBody::getJointTorqueMultiDof(int i) -{ - return &m_links[i].m_jointTorque[0]; -} - -inline btMatrix3x3 outerProduct(const btVector3& v0, const btVector3& v1) //renamed it from vecMulVecTranspose (http://en.wikipedia.org/wiki/Outer_product); maybe it should be moved to btVector3 like dot and cross? -{ - btVector3 row0 = btVector3( - v0.x() * v1.x(), - v0.x() * v1.y(), - v0.x() * v1.z()); - btVector3 row1 = btVector3( - v0.y() * v1.x(), - v0.y() * v1.y(), - v0.y() * v1.z()); - btVector3 row2 = btVector3( - v0.z() * v1.x(), - v0.z() * v1.y(), - v0.z() * v1.z()); - - btMatrix3x3 m(row0[0],row0[1],row0[2], - row1[0],row1[1],row1[2], - row2[0],row2[1],row2[2]); - return m; -} - -#define vecMulVecTranspose(v0, v1Transposed) outerProduct(v0, v1Transposed) -// - -void btMultiBody::computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar dt, - btAlignedObjectArray &scratch_r, - btAlignedObjectArray &scratch_v, - btAlignedObjectArray &scratch_m, - bool isConstraintPass) -{ - // Implement Featherstone's algorithm to calculate joint accelerations (q_double_dot) - // and the base linear & angular accelerations. - - // We apply damping forces in this routine as well as any external forces specified by the - // caller (via addBaseForce etc). - - // output should point to an array of 6 + num_links reals. - // Format is: 3 angular accelerations (in world frame), 3 linear accelerations (in world frame), - // num_links joint acceleration values. - - // We added support for multi degree of freedom (multi dof) joints. - // In addition we also can compute the joint reaction forces. This is performed in a second pass, - // so that we can include the effect of the constraint solver forces (computed in the PGS LCP solver) - - m_internalNeedsJointFeedback = false; - - int num_links = getNumLinks(); - - const btScalar DAMPING_K1_LINEAR = m_linearDamping; - const btScalar DAMPING_K2_LINEAR = m_linearDamping; - - const btScalar DAMPING_K1_ANGULAR = m_angularDamping; - const btScalar DAMPING_K2_ANGULAR= m_angularDamping; - - btVector3 base_vel = getBaseVel(); - btVector3 base_omega = getBaseOmega(); - - // Temporary matrices/vectors -- use scratch space from caller - // so that we don't have to keep reallocating every frame - - scratch_r.resize(2*m_dofCount + 6); //multidof? ("Y"s use it and it is used to store qdd) => 2 x m_dofCount - scratch_v.resize(8*num_links + 6); - scratch_m.resize(4*num_links + 4); - - //btScalar * r_ptr = &scratch_r[0]; - btScalar * output = &scratch_r[m_dofCount]; // "output" holds the q_double_dot results - btVector3 * v_ptr = &scratch_v[0]; - - // vhat_i (top = angular, bottom = linear part) - btSpatialMotionVector *spatVel = (btSpatialMotionVector *)v_ptr; - v_ptr += num_links * 2 + 2; - // - // zhat_i^A - btSpatialForceVector * zeroAccSpatFrc = (btSpatialForceVector *)v_ptr; - v_ptr += num_links * 2 + 2; - // - // chat_i (note NOT defined for the base) - btSpatialMotionVector * spatCoriolisAcc = (btSpatialMotionVector *)v_ptr; - v_ptr += num_links * 2; - // - // Ihat_i^A. - btSymmetricSpatialDyad * spatInertia = (btSymmetricSpatialDyad *)&scratch_m[num_links + 1]; - - // Cached 3x3 rotation matrices from parent frame to this frame. - btMatrix3x3 * rot_from_parent = &m_matrixBuf[0]; - btMatrix3x3 * rot_from_world = &scratch_m[0]; - - // hhat_i, ahat_i - // hhat is NOT stored for the base (but ahat is) - btSpatialForceVector * h = (btSpatialForceVector *)(m_dofCount > 0 ? &m_vectorBuf[0] : 0); - btSpatialMotionVector * spatAcc = (btSpatialMotionVector *)v_ptr; - v_ptr += num_links * 2 + 2; - // - // Y_i, invD_i - btScalar * invD = m_dofCount > 0 ? &m_realBuf[6 + m_dofCount] : 0; - btScalar * Y = &scratch_r[0]; - // - //aux variables - static btSpatialMotionVector spatJointVel; //spatial velocity due to the joint motion (i.e. without predecessors' influence) - static btScalar D[36]; //"D" matrix; it's dofxdof for each body so asingle 6x6 D matrix will do - static btScalar invD_times_Y[6]; //D^{-1} * Y [dofxdof x dofx1 = dofx1] <=> D^{-1} * u; better moved to buffers since it is recalced in calcAccelerationDeltasMultiDof; num_dof of btScalar would cover all bodies - static btSpatialMotionVector result; //holds results of the SolveImatrix op; it is a spatial motion vector (accel) - static btScalar Y_minus_hT_a[6]; //Y - h^{T} * a; it's dofx1 for each body so a single 6x1 temp is enough - static btSpatialForceVector spatForceVecTemps[6]; //6 temporary spatial force vectors - static btSpatialTransformationMatrix fromParent; //spatial transform from parent to child - static btSymmetricSpatialDyad dyadTemp; //inertia matrix temp - static btSpatialTransformationMatrix fromWorld; - fromWorld.m_trnVec.setZero(); - ///////////////// - - // ptr to the joint accel part of the output - btScalar * joint_accel = output + 6; - - // Start of the algorithm proper. - - // First 'upward' loop. - // Combines CompTreeLinkVelocities and InitTreeLinks from Mirtich. - - rot_from_parent[0] = btMatrix3x3(m_baseQuat); //m_baseQuat assumed to be alias!? - - //create the vector of spatial velocity of the base by transforming global-coor linear and angular velocities into base-local coordinates - spatVel[0].setVector(rot_from_parent[0] * base_omega, rot_from_parent[0] * base_vel); - - if (m_fixedBase) - { - zeroAccSpatFrc[0].setZero(); - } - else - { - btVector3 baseForce = isConstraintPass? m_baseConstraintForce : m_baseForce; - btVector3 baseTorque = isConstraintPass? m_baseConstraintTorque : m_baseTorque; - //external forces - zeroAccSpatFrc[0].setVector(-(rot_from_parent[0] * baseTorque), -(rot_from_parent[0] * baseForce)); - - //adding damping terms (only) - btScalar linDampMult = 1., angDampMult = 1.; - zeroAccSpatFrc[0].addVector(angDampMult * m_baseInertia * spatVel[0].getAngular() * (DAMPING_K1_ANGULAR + DAMPING_K2_ANGULAR * spatVel[0].getAngular().norm()), - linDampMult * m_baseMass * spatVel[0].getLinear() * (DAMPING_K1_LINEAR + DAMPING_K2_LINEAR * spatVel[0].getLinear().norm())); - - // - //p += vhat x Ihat vhat - done in a simpler way - if (m_useGyroTerm) - zeroAccSpatFrc[0].addAngular(spatVel[0].getAngular().cross(m_baseInertia * spatVel[0].getAngular())); - // - zeroAccSpatFrc[0].addLinear(m_baseMass * spatVel[0].getAngular().cross(spatVel[0].getLinear())); - } - - - //init the spatial AB inertia (it has the simple form thanks to choosing local body frames origins at their COMs) - spatInertia[0].setMatrix( btMatrix3x3(0,0,0,0,0,0,0,0,0), - // - btMatrix3x3(m_baseMass, 0, 0, - 0, m_baseMass, 0, - 0, 0, m_baseMass), - // - btMatrix3x3(m_baseInertia[0], 0, 0, - 0, m_baseInertia[1], 0, - 0, 0, m_baseInertia[2]) - ); - - rot_from_world[0] = rot_from_parent[0]; - - // - for (int i = 0; i < num_links; ++i) { - const int parent = m_links[i].m_parent; - rot_from_parent[i+1] = btMatrix3x3(m_links[i].m_cachedRotParentToThis); - rot_from_world[i+1] = rot_from_parent[i+1] * rot_from_world[parent+1]; - - fromParent.m_rotMat = rot_from_parent[i+1]; fromParent.m_trnVec = m_links[i].m_cachedRVector; - fromWorld.m_rotMat = rot_from_world[i+1]; - fromParent.transform(spatVel[parent+1], spatVel[i+1]); - - // now set vhat_i to its true value by doing - // vhat_i += qidot * shat_i - if(!m_useGlobalVelocities) - { - spatJointVel.setZero(); - - for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) - spatJointVel += m_links[i].m_axes[dof] * getJointVelMultiDof(i)[dof]; - - // remember vhat_i is really vhat_p(i) (but in current frame) at this point => we need to add velocity across the inboard joint - spatVel[i+1] += spatJointVel; - - // - // vhat_i is vhat_p(i) transformed to local coors + the velocity across the i-th inboard joint - //spatVel[i+1] = fromParent * spatVel[parent+1] + spatJointVel; - - } - else - { - fromWorld.transformRotationOnly(m_links[i].m_absFrameTotVelocity, spatVel[i+1]); - fromWorld.transformRotationOnly(m_links[i].m_absFrameLocVelocity, spatJointVel); - } - - // we can now calculate chat_i - spatVel[i+1].cross(spatJointVel, spatCoriolisAcc[i]); - - // calculate zhat_i^A - // - //external forces - btVector3 linkAppliedForce = isConstraintPass? m_links[i].m_appliedConstraintForce : m_links[i].m_appliedForce; - btVector3 linkAppliedTorque =isConstraintPass ? m_links[i].m_appliedConstraintTorque : m_links[i].m_appliedTorque; - - zeroAccSpatFrc[i+1].setVector(-(rot_from_world[i+1] * linkAppliedTorque), -(rot_from_world[i+1] * linkAppliedForce )); - -#if 0 - { - - b3Printf("stepVelocitiesMultiDof zeroAccSpatFrc[%d] linear:%f,%f,%f, angular:%f,%f,%f", - i+1, - zeroAccSpatFrc[i+1].m_topVec[0], - zeroAccSpatFrc[i+1].m_topVec[1], - zeroAccSpatFrc[i+1].m_topVec[2], - - zeroAccSpatFrc[i+1].m_bottomVec[0], - zeroAccSpatFrc[i+1].m_bottomVec[1], - zeroAccSpatFrc[i+1].m_bottomVec[2]); - } -#endif - // - //adding damping terms (only) - btScalar linDampMult = 1., angDampMult = 1.; - zeroAccSpatFrc[i+1].addVector(angDampMult * m_links[i].m_inertiaLocal * spatVel[i+1].getAngular() * (DAMPING_K1_ANGULAR + DAMPING_K2_ANGULAR * spatVel[i+1].getAngular().norm()), - linDampMult * m_links[i].m_mass * spatVel[i+1].getLinear() * (DAMPING_K1_LINEAR + DAMPING_K2_LINEAR * spatVel[i+1].getLinear().norm())); - - // calculate Ihat_i^A - //init the spatial AB inertia (it has the simple form thanks to choosing local body frames origins at their COMs) - spatInertia[i+1].setMatrix( btMatrix3x3(0,0,0,0,0,0,0,0,0), - // - btMatrix3x3(m_links[i].m_mass, 0, 0, - 0, m_links[i].m_mass, 0, - 0, 0, m_links[i].m_mass), - // - btMatrix3x3(m_links[i].m_inertiaLocal[0], 0, 0, - 0, m_links[i].m_inertiaLocal[1], 0, - 0, 0, m_links[i].m_inertiaLocal[2]) - ); - // - //p += vhat x Ihat vhat - done in a simpler way - if(m_useGyroTerm) - zeroAccSpatFrc[i+1].addAngular(spatVel[i+1].getAngular().cross(m_links[i].m_inertiaLocal * spatVel[i+1].getAngular())); - // - zeroAccSpatFrc[i+1].addLinear(m_links[i].m_mass * spatVel[i+1].getAngular().cross(spatVel[i+1].getLinear())); - //btVector3 temp = m_links[i].m_mass * spatVel[i+1].getAngular().cross(spatVel[i+1].getLinear()); - ////clamp parent's omega - //btScalar parOmegaMod = temp.length(); - //btScalar parOmegaModMax = 1000; - //if(parOmegaMod > parOmegaModMax) - // temp *= parOmegaModMax / parOmegaMod; - //zeroAccSpatFrc[i+1].addLinear(temp); - //printf("|zeroAccSpatFrc[%d]| = %.4f\n", i+1, temp.length()); - //temp = spatCoriolisAcc[i].getLinear(); - //printf("|spatCoriolisAcc[%d]| = %.4f\n", i+1, temp.length()); - - - - //printf("w[%d] = [%.4f %.4f %.4f]\n", i, vel_top_angular[i+1].x(), vel_top_angular[i+1].y(), vel_top_angular[i+1].z()); - //printf("v[%d] = [%.4f %.4f %.4f]\n", i, vel_bottom_linear[i+1].x(), vel_bottom_linear[i+1].y(), vel_bottom_linear[i+1].z()); - //printf("c[%d] = [%.4f %.4f %.4f]\n", i, coriolis_bottom_linear[i].x(), coriolis_bottom_linear[i].y(), coriolis_bottom_linear[i].z()); - } - - // 'Downward' loop. - // (part of TreeForwardDynamics in Mirtich.) - for (int i = num_links - 1; i >= 0; --i) - { - const int parent = m_links[i].m_parent; - fromParent.m_rotMat = rot_from_parent[i+1]; fromParent.m_trnVec = m_links[i].m_cachedRVector; - - for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) - { - btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof]; - // - hDof = spatInertia[i+1] * m_links[i].m_axes[dof]; - // - Y[m_links[i].m_dofOffset + dof] = m_links[i].m_jointTorque[dof] - - m_links[i].m_axes[dof].dot(zeroAccSpatFrc[i+1]) - - spatCoriolisAcc[i].dot(hDof) - ; - } - - for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) - { - btScalar *D_row = &D[dof * m_links[i].m_dofCount]; - for(int dof2 = 0; dof2 < m_links[i].m_dofCount; ++dof2) - { - btSpatialForceVector &hDof2 = h[m_links[i].m_dofOffset + dof2]; - D_row[dof2] = m_links[i].m_axes[dof].dot(hDof2); - } - } - - btScalar *invDi = &invD[m_links[i].m_dofOffset*m_links[i].m_dofOffset]; - switch(m_links[i].m_jointType) - { - case btMultibodyLink::ePrismatic: - case btMultibodyLink::eRevolute: - { - invDi[0] = 1.0f / D[0]; - break; - } - case btMultibodyLink::eSpherical: - case btMultibodyLink::ePlanar: - { - static btMatrix3x3 D3x3; D3x3.setValue(D[0], D[1], D[2], D[3], D[4], D[5], D[6], D[7], D[8]); - static btMatrix3x3 invD3x3; invD3x3 = D3x3.inverse(); - - //unroll the loop? - for(int row = 0; row < 3; ++row) - { - for(int col = 0; col < 3; ++col) - { - invDi[row * 3 + col] = invD3x3[row][col]; - } - } - - break; - } - default: - { - - } - } - - //determine h*D^{-1} - for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) - { - spatForceVecTemps[dof].setZero(); - - for(int dof2 = 0; dof2 < m_links[i].m_dofCount; ++dof2) - { - btSpatialForceVector &hDof2 = h[m_links[i].m_dofOffset + dof2]; - // - spatForceVecTemps[dof] += hDof2 * invDi[dof2 * m_links[i].m_dofCount + dof]; - } - } - - dyadTemp = spatInertia[i+1]; - - //determine (h*D^{-1}) * h^{T} - for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) - { - btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof]; - // - dyadTemp -= symmetricSpatialOuterProduct(hDof, spatForceVecTemps[dof]); - } - - fromParent.transformInverse(dyadTemp, spatInertia[parent+1], btSpatialTransformationMatrix::Add); - - for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) - { - invD_times_Y[dof] = 0.f; - - for(int dof2 = 0; dof2 < m_links[i].m_dofCount; ++dof2) - { - invD_times_Y[dof] += invDi[dof * m_links[i].m_dofCount + dof2] * Y[m_links[i].m_dofOffset + dof2]; - } - } - - spatForceVecTemps[0] = zeroAccSpatFrc[i+1] + spatInertia[i+1] * spatCoriolisAcc[i]; - - for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) - { - btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof]; - // - spatForceVecTemps[0] += hDof * invD_times_Y[dof]; - } - - fromParent.transformInverse(spatForceVecTemps[0], spatForceVecTemps[1]); - - zeroAccSpatFrc[parent+1] += spatForceVecTemps[1]; - } - - - // Second 'upward' loop - // (part of TreeForwardDynamics in Mirtich) - - if (m_fixedBase) - { - spatAcc[0].setZero(); - } - else - { - if (num_links > 0) - { - m_cachedInertiaTopLeft = spatInertia[0].m_topLeftMat; - m_cachedInertiaTopRight = spatInertia[0].m_topRightMat; - m_cachedInertiaLowerLeft = spatInertia[0].m_bottomLeftMat; - m_cachedInertiaLowerRight= spatInertia[0].m_topLeftMat.transpose(); - - } - - solveImatrix(zeroAccSpatFrc[0], result); - spatAcc[0] = -result; - } - - - // now do the loop over the m_links - for (int i = 0; i < num_links; ++i) - { - // qdd = D^{-1} * (Y - h^{T}*apar) = (S^{T}*I*S)^{-1} * (tau - S^{T}*I*cor - S^{T}*zeroAccFrc - S^{T}*I*apar) - // a = apar + cor + Sqdd - //or - // qdd = D^{-1} * (Y - h^{T}*(apar+cor)) - // a = apar + Sqdd - - const int parent = m_links[i].m_parent; - fromParent.m_rotMat = rot_from_parent[i+1]; fromParent.m_trnVec = m_links[i].m_cachedRVector; - - fromParent.transform(spatAcc[parent+1], spatAcc[i+1]); - - for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) - { - btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof]; - // - Y_minus_hT_a[dof] = Y[m_links[i].m_dofOffset + dof] - spatAcc[i+1].dot(hDof); - } - - btScalar *invDi = &invD[m_links[i].m_dofOffset*m_links[i].m_dofOffset]; - //D^{-1} * (Y - h^{T}*apar) - mulMatrix(invDi, Y_minus_hT_a, m_links[i].m_dofCount, m_links[i].m_dofCount, m_links[i].m_dofCount, 1, &joint_accel[m_links[i].m_dofOffset]); - - spatAcc[i+1] += spatCoriolisAcc[i]; - - for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) - spatAcc[i+1] += m_links[i].m_axes[dof] * joint_accel[m_links[i].m_dofOffset + dof]; - - if (m_links[i].m_jointFeedback) - { - m_internalNeedsJointFeedback = true; - - btVector3 angularBotVec = (spatInertia[i+1]*spatAcc[i+1]+zeroAccSpatFrc[i+1]).m_bottomVec; - btVector3 linearTopVec = (spatInertia[i+1]*spatAcc[i+1]+zeroAccSpatFrc[i+1]).m_topVec; - - if (gJointFeedbackInJointFrame) - { - //shift the reaction forces to the joint frame - //linear (force) component is the same - //shift the angular (torque, moment) component using the relative position, m_links[i].m_dVector - angularBotVec = angularBotVec - linearTopVec.cross(m_links[i].m_dVector); - } - - - if (gJointFeedbackInWorldSpace) - { - if (isConstraintPass) - { - m_links[i].m_jointFeedback->m_reactionForces.m_bottomVec += m_links[i].m_cachedWorldTransform.getBasis()*angularBotVec; - m_links[i].m_jointFeedback->m_reactionForces.m_topVec += m_links[i].m_cachedWorldTransform.getBasis()*linearTopVec; - } else - { - m_links[i].m_jointFeedback->m_reactionForces.m_bottomVec = m_links[i].m_cachedWorldTransform.getBasis()*angularBotVec; - m_links[i].m_jointFeedback->m_reactionForces.m_topVec = m_links[i].m_cachedWorldTransform.getBasis()*linearTopVec; - } - } else - { - if (isConstraintPass) - { - m_links[i].m_jointFeedback->m_reactionForces.m_bottomVec += angularBotVec; - m_links[i].m_jointFeedback->m_reactionForces.m_topVec += linearTopVec; - - } - else - { - m_links[i].m_jointFeedback->m_reactionForces.m_bottomVec = angularBotVec; - m_links[i].m_jointFeedback->m_reactionForces.m_topVec = linearTopVec; - } - } - } - - } - - // transform base accelerations back to the world frame. - btVector3 omegadot_out = rot_from_parent[0].transpose() * spatAcc[0].getAngular(); - output[0] = omegadot_out[0]; - output[1] = omegadot_out[1]; - output[2] = omegadot_out[2]; - - btVector3 vdot_out = rot_from_parent[0].transpose() * (spatAcc[0].getLinear() + spatVel[0].getAngular().cross(spatVel[0].getLinear())); - output[3] = vdot_out[0]; - output[4] = vdot_out[1]; - output[5] = vdot_out[2]; - - ///////////////// - //printf("q = ["); - //printf("%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f ", m_baseQuat.x(), m_baseQuat.y(), m_baseQuat.z(), m_baseQuat.w(), m_basePos.x(), m_basePos.y(), m_basePos.z()); - //for(int link = 0; link < getNumLinks(); ++link) - // for(int dof = 0; dof < m_links[link].m_dofCount; ++dof) - // printf("%.6f ", m_links[link].m_jointPos[dof]); - //printf("]\n"); - //// - //printf("qd = ["); - //for(int dof = 0; dof < getNumDofs() + 6; ++dof) - // printf("%.6f ", m_realBuf[dof]); - //printf("]\n"); - //printf("qdd = ["); - //for(int dof = 0; dof < getNumDofs() + 6; ++dof) - // printf("%.6f ", output[dof]); - //printf("]\n"); - ///////////////// - - // Final step: add the accelerations (times dt) to the velocities. - - if (!isConstraintPass) - { - if(dt > 0.) - applyDeltaVeeMultiDof(output, dt); - - } - ///// - //btScalar angularThres = 1; - //btScalar maxAngVel = 0.; - //bool scaleDown = 1.; - //for(int link = 0; link < m_links.size(); ++link) - //{ - // if(spatVel[link+1].getAngular().length() > maxAngVel) - // { - // maxAngVel = spatVel[link+1].getAngular().length(); - // scaleDown = angularThres / spatVel[link+1].getAngular().length(); - // break; - // } - //} - - //if(scaleDown != 1.) - //{ - // for(int link = 0; link < m_links.size(); ++link) - // { - // if(m_links[link].m_jointType == btMultibodyLink::eRevolute || m_links[link].m_jointType == btMultibodyLink::eSpherical) - // { - // for(int dof = 0; dof < m_links[link].m_dofCount; ++dof) - // getJointVelMultiDof(link)[dof] *= scaleDown; - // } - // } - //} - ///// - - ///////////////////// - if(m_useGlobalVelocities) - { - for (int i = 0; i < num_links; ++i) - { - const int parent = m_links[i].m_parent; - //rot_from_parent[i+1] = btMatrix3x3(m_links[i].m_cachedRotParentToThis); /// <- done - //rot_from_world[i+1] = rot_from_parent[i+1] * rot_from_world[parent+1]; /// <- done - - fromParent.m_rotMat = rot_from_parent[i+1]; fromParent.m_trnVec = m_links[i].m_cachedRVector; - fromWorld.m_rotMat = rot_from_world[i+1]; - - // vhat_i = i_xhat_p(i) * vhat_p(i) - fromParent.transform(spatVel[parent+1], spatVel[i+1]); - //nice alternative below (using operator *) but it generates temps - ///////////////////////////////////////////////////////////// - - // now set vhat_i to its true value by doing - // vhat_i += qidot * shat_i - spatJointVel.setZero(); - - for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) - spatJointVel += m_links[i].m_axes[dof] * getJointVelMultiDof(i)[dof]; - - // remember vhat_i is really vhat_p(i) (but in current frame) at this point => we need to add velocity across the inboard joint - spatVel[i+1] += spatJointVel; - - - fromWorld.transformInverseRotationOnly(spatVel[i+1], m_links[i].m_absFrameTotVelocity); - fromWorld.transformInverseRotationOnly(spatJointVel, m_links[i].m_absFrameLocVelocity); - } - } - -} - - - -void btMultiBody::solveImatrix(const btVector3& rhs_top, const btVector3& rhs_bot, float result[6]) const -{ - int num_links = getNumLinks(); - ///solve I * x = rhs, so the result = invI * rhs - if (num_links == 0) - { - // in the case of 0 m_links (i.e. a plain rigid body, not a multibody) rhs * invI is easier - result[0] = rhs_bot[0] / m_baseInertia[0]; - result[1] = rhs_bot[1] / m_baseInertia[1]; - result[2] = rhs_bot[2] / m_baseInertia[2]; - result[3] = rhs_top[0] / m_baseMass; - result[4] = rhs_top[1] / m_baseMass; - result[5] = rhs_top[2] / m_baseMass; - } else - { - /// Special routine for calculating the inverse of a spatial inertia matrix - ///the 6x6 matrix is stored as 4 blocks of 3x3 matrices - btMatrix3x3 Binv = m_cachedInertiaTopRight.inverse()*-1.f; - btMatrix3x3 tmp = m_cachedInertiaLowerRight * Binv; - btMatrix3x3 invIupper_right = (tmp * m_cachedInertiaTopLeft + m_cachedInertiaLowerLeft).inverse(); - tmp = invIupper_right * m_cachedInertiaLowerRight; - btMatrix3x3 invI_upper_left = (tmp * Binv); - btMatrix3x3 invI_lower_right = (invI_upper_left).transpose(); - tmp = m_cachedInertiaTopLeft * invI_upper_left; - tmp[0][0]-= 1.0; - tmp[1][1]-= 1.0; - tmp[2][2]-= 1.0; - btMatrix3x3 invI_lower_left = (Binv * tmp); - - //multiply result = invI * rhs - { - btVector3 vtop = invI_upper_left*rhs_top; - btVector3 tmp; - tmp = invIupper_right * rhs_bot; - vtop += tmp; - btVector3 vbot = invI_lower_left*rhs_top; - tmp = invI_lower_right * rhs_bot; - vbot += tmp; - result[0] = vtop[0]; - result[1] = vtop[1]; - result[2] = vtop[2]; - result[3] = vbot[0]; - result[4] = vbot[1]; - result[5] = vbot[2]; - } - - } -} -void btMultiBody::solveImatrix(const btSpatialForceVector &rhs, btSpatialMotionVector &result) const -{ - int num_links = getNumLinks(); - ///solve I * x = rhs, so the result = invI * rhs - if (num_links == 0) - { - // in the case of 0 m_links (i.e. a plain rigid body, not a multibody) rhs * invI is easier - result.setAngular(rhs.getAngular() / m_baseInertia); - result.setLinear(rhs.getLinear() / m_baseMass); - } else - { - /// Special routine for calculating the inverse of a spatial inertia matrix - ///the 6x6 matrix is stored as 4 blocks of 3x3 matrices - btMatrix3x3 Binv = m_cachedInertiaTopRight.inverse()*-1.f; - btMatrix3x3 tmp = m_cachedInertiaLowerRight * Binv; - btMatrix3x3 invIupper_right = (tmp * m_cachedInertiaTopLeft + m_cachedInertiaLowerLeft).inverse(); - tmp = invIupper_right * m_cachedInertiaLowerRight; - btMatrix3x3 invI_upper_left = (tmp * Binv); - btMatrix3x3 invI_lower_right = (invI_upper_left).transpose(); - tmp = m_cachedInertiaTopLeft * invI_upper_left; - tmp[0][0]-= 1.0; - tmp[1][1]-= 1.0; - tmp[2][2]-= 1.0; - btMatrix3x3 invI_lower_left = (Binv * tmp); - - //multiply result = invI * rhs - { - btVector3 vtop = invI_upper_left*rhs.getLinear(); - btVector3 tmp; - tmp = invIupper_right * rhs.getAngular(); - vtop += tmp; - btVector3 vbot = invI_lower_left*rhs.getLinear(); - tmp = invI_lower_right * rhs.getAngular(); - vbot += tmp; - result.setVector(vtop, vbot); - } - - } -} - -void btMultiBody::mulMatrix(btScalar *pA, btScalar *pB, int rowsA, int colsA, int rowsB, int colsB, btScalar *pC) const -{ - for (int row = 0; row < rowsA; row++) - { - for (int col = 0; col < colsB; col++) - { - pC[row * colsB + col] = 0.f; - for (int inner = 0; inner < rowsB; inner++) - { - pC[row * colsB + col] += pA[row * colsA + inner] * pB[col + inner * colsB]; - } - } - } -} - -void btMultiBody::calcAccelerationDeltasMultiDof(const btScalar *force, btScalar *output, - btAlignedObjectArray &scratch_r, btAlignedObjectArray &scratch_v) const -{ - // Temporary matrices/vectors -- use scratch space from caller - // so that we don't have to keep reallocating every frame - - - int num_links = getNumLinks(); - scratch_r.resize(m_dofCount); - scratch_v.resize(4*num_links + 4); - - btScalar * r_ptr = m_dofCount ? &scratch_r[0] : 0; - btVector3 * v_ptr = &scratch_v[0]; - - // zhat_i^A (scratch space) - btSpatialForceVector * zeroAccSpatFrc = (btSpatialForceVector *)v_ptr; - v_ptr += num_links * 2 + 2; - - // rot_from_parent (cached from calcAccelerations) - const btMatrix3x3 * rot_from_parent = &m_matrixBuf[0]; - - // hhat (cached), accel (scratch) - // hhat is NOT stored for the base (but ahat is) - const btSpatialForceVector * h = (btSpatialForceVector *)(m_dofCount > 0 ? &m_vectorBuf[0] : 0); - btSpatialMotionVector * spatAcc = (btSpatialMotionVector *)v_ptr; - v_ptr += num_links * 2 + 2; - - // Y_i (scratch), invD_i (cached) - const btScalar * invD = m_dofCount > 0 ? &m_realBuf[6 + m_dofCount] : 0; - btScalar * Y = r_ptr; - //////////////// - //aux variables - static btScalar invD_times_Y[6]; //D^{-1} * Y [dofxdof x dofx1 = dofx1] <=> D^{-1} * u; better moved to buffers since it is recalced in calcAccelerationDeltasMultiDof; num_dof of btScalar would cover all bodies - static btSpatialMotionVector result; //holds results of the SolveImatrix op; it is a spatial motion vector (accel) - static btScalar Y_minus_hT_a[6]; //Y - h^{T} * a; it's dofx1 for each body so a single 6x1 temp is enough - static btSpatialForceVector spatForceVecTemps[6]; //6 temporary spatial force vectors - static btSpatialTransformationMatrix fromParent; - ///////////////// - - // First 'upward' loop. - // Combines CompTreeLinkVelocities and InitTreeLinks from Mirtich. - - // Fill in zero_acc - // -- set to force/torque on the base, zero otherwise - if (m_fixedBase) - { - zeroAccSpatFrc[0].setZero(); - } else - { - //test forces - fromParent.m_rotMat = rot_from_parent[0]; - fromParent.transformRotationOnly(btSpatialForceVector(-force[0],-force[1],-force[2], -force[3],-force[4],-force[5]), zeroAccSpatFrc[0]); - } - for (int i = 0; i < num_links; ++i) - { - zeroAccSpatFrc[i+1].setZero(); - } - - // 'Downward' loop. - // (part of TreeForwardDynamics in Mirtich.) - for (int i = num_links - 1; i >= 0; --i) - { - const int parent = m_links[i].m_parent; - fromParent.m_rotMat = rot_from_parent[i+1]; fromParent.m_trnVec = m_links[i].m_cachedRVector; - - for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) - { - Y[m_links[i].m_dofOffset + dof] = force[6 + m_links[i].m_dofOffset + dof] - - m_links[i].m_axes[dof].dot(zeroAccSpatFrc[i+1]) - ; - } - - btVector3 in_top, in_bottom, out_top, out_bottom; - const btScalar *invDi = &invD[m_links[i].m_dofOffset*m_links[i].m_dofOffset]; - - for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) - { - invD_times_Y[dof] = 0.f; - - for(int dof2 = 0; dof2 < m_links[i].m_dofCount; ++dof2) - { - invD_times_Y[dof] += invDi[dof * m_links[i].m_dofCount + dof2] * Y[m_links[i].m_dofOffset + dof2]; - } - } - - // Zp += pXi * (Zi + hi*Yi/Di) - spatForceVecTemps[0] = zeroAccSpatFrc[i+1]; - - for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) - { - const btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof]; - // - spatForceVecTemps[0] += hDof * invD_times_Y[dof]; - } - - - fromParent.transformInverse(spatForceVecTemps[0], spatForceVecTemps[1]); - - zeroAccSpatFrc[parent+1] += spatForceVecTemps[1]; - } - - // ptr to the joint accel part of the output - btScalar * joint_accel = output + 6; - - - // Second 'upward' loop - // (part of TreeForwardDynamics in Mirtich) - - if (m_fixedBase) - { - spatAcc[0].setZero(); - } - else - { - solveImatrix(zeroAccSpatFrc[0], result); - spatAcc[0] = -result; - - } - - // now do the loop over the m_links - for (int i = 0; i < num_links; ++i) - { - const int parent = m_links[i].m_parent; - fromParent.m_rotMat = rot_from_parent[i+1]; fromParent.m_trnVec = m_links[i].m_cachedRVector; - - fromParent.transform(spatAcc[parent+1], spatAcc[i+1]); - - for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) - { - const btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof]; - // - Y_minus_hT_a[dof] = Y[m_links[i].m_dofOffset + dof] - spatAcc[i+1].dot(hDof); - } - - const btScalar *invDi = &invD[m_links[i].m_dofOffset*m_links[i].m_dofOffset]; - mulMatrix(const_cast(invDi), Y_minus_hT_a, m_links[i].m_dofCount, m_links[i].m_dofCount, m_links[i].m_dofCount, 1, &joint_accel[m_links[i].m_dofOffset]); - - for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) - spatAcc[i+1] += m_links[i].m_axes[dof] * joint_accel[m_links[i].m_dofOffset + dof]; - } - - // transform base accelerations back to the world frame. - btVector3 omegadot_out; - omegadot_out = rot_from_parent[0].transpose() * spatAcc[0].getAngular(); - output[0] = omegadot_out[0]; - output[1] = omegadot_out[1]; - output[2] = omegadot_out[2]; - - btVector3 vdot_out; - vdot_out = rot_from_parent[0].transpose() * spatAcc[0].getLinear(); - output[3] = vdot_out[0]; - output[4] = vdot_out[1]; - output[5] = vdot_out[2]; - - ///////////////// - //printf("delta = ["); - //for(int dof = 0; dof < getNumDofs() + 6; ++dof) - // printf("%.2f ", output[dof]); - //printf("]\n"); - ///////////////// -} - - - - -void btMultiBody::stepPositionsMultiDof(btScalar dt, btScalar *pq, btScalar *pqd) -{ - int num_links = getNumLinks(); - // step position by adding dt * velocity - //btVector3 v = getBaseVel(); - //m_basePos += dt * v; - // - btScalar *pBasePos = (pq ? &pq[4] : m_basePos); - btScalar *pBaseVel = (pqd ? &pqd[3] : &m_realBuf[3]); //note: the !pqd case assumes m_realBuf holds with base velocity at 3,4,5 (should be wrapped for safety) - // - pBasePos[0] += dt * pBaseVel[0]; - pBasePos[1] += dt * pBaseVel[1]; - pBasePos[2] += dt * pBaseVel[2]; - - /////////////////////////////// - //local functor for quaternion integration (to avoid error prone redundancy) - struct - { - //"exponential map" based on btTransformUtil::integrateTransform(..) - void operator() (const btVector3 &omega, btQuaternion &quat, bool baseBody, btScalar dt) - { - //baseBody => quat is alias and omega is global coor - //!baseBody => quat is alibi and omega is local coor - - btVector3 axis; - btVector3 angvel; - - if(!baseBody) - angvel = quatRotate(quat, omega); //if quat is not m_baseQuat, it is alibi => ok - else - angvel = omega; - - btScalar fAngle = angvel.length(); - //limit the angular motion - if (fAngle * dt > ANGULAR_MOTION_THRESHOLD) - { - fAngle = btScalar(0.5)*SIMD_HALF_PI / dt; - } - - if ( fAngle < btScalar(0.001) ) - { - // use Taylor's expansions of sync function - axis = angvel*( btScalar(0.5)*dt-(dt*dt*dt)*(btScalar(0.020833333333))*fAngle*fAngle ); - } - else - { - // sync(fAngle) = sin(c*fAngle)/t - axis = angvel*( btSin(btScalar(0.5)*fAngle*dt)/fAngle ); - } - - if(!baseBody) - quat = btQuaternion(axis.x(),axis.y(),axis.z(),btCos( fAngle*dt*btScalar(0.5) )) * quat; - else - quat = quat * btQuaternion(-axis.x(),-axis.y(),-axis.z(),btCos( fAngle*dt*btScalar(0.5) )); - //equivalent to: quat = (btQuaternion(axis.x(),axis.y(),axis.z(),btCos( fAngle*dt*btScalar(0.5) )) * quat.inverse()).inverse(); - - quat.normalize(); - } - } pQuatUpdateFun; - /////////////////////////////// - - //pQuatUpdateFun(getBaseOmega(), m_baseQuat, true, dt); - // - btScalar *pBaseQuat = pq ? pq : m_baseQuat; - btScalar *pBaseOmega = pqd ? pqd : &m_realBuf[0]; //note: the !pqd case assumes m_realBuf starts with base omega (should be wrapped for safety) - // - static btQuaternion baseQuat; baseQuat.setValue(pBaseQuat[0], pBaseQuat[1], pBaseQuat[2], pBaseQuat[3]); - static btVector3 baseOmega; baseOmega.setValue(pBaseOmega[0], pBaseOmega[1], pBaseOmega[2]); - pQuatUpdateFun(baseOmega, baseQuat, true, dt); - pBaseQuat[0] = baseQuat.x(); - pBaseQuat[1] = baseQuat.y(); - pBaseQuat[2] = baseQuat.z(); - pBaseQuat[3] = baseQuat.w(); - - - //printf("pBaseOmega = %.4f %.4f %.4f\n", pBaseOmega->x(), pBaseOmega->y(), pBaseOmega->z()); - //printf("pBaseVel = %.4f %.4f %.4f\n", pBaseVel->x(), pBaseVel->y(), pBaseVel->z()); - //printf("baseQuat = %.4f %.4f %.4f %.4f\n", pBaseQuat->x(), pBaseQuat->y(), pBaseQuat->z(), pBaseQuat->w()); - - if(pq) - pq += 7; - if(pqd) - pqd += 6; - - // Finally we can update m_jointPos for each of the m_links - for (int i = 0; i < num_links; ++i) - { - btScalar *pJointPos = (pq ? pq : &m_links[i].m_jointPos[0]); - btScalar *pJointVel = (pqd ? pqd : getJointVelMultiDof(i)); - - switch(m_links[i].m_jointType) - { - case btMultibodyLink::ePrismatic: - case btMultibodyLink::eRevolute: - { - btScalar jointVel = pJointVel[0]; - pJointPos[0] += dt * jointVel; - break; - } - case btMultibodyLink::eSpherical: - { - static btVector3 jointVel; jointVel.setValue(pJointVel[0], pJointVel[1], pJointVel[2]); - static btQuaternion jointOri; jointOri.setValue(pJointPos[0], pJointPos[1], pJointPos[2], pJointPos[3]); - pQuatUpdateFun(jointVel, jointOri, false, dt); - pJointPos[0] = jointOri.x(); pJointPos[1] = jointOri.y(); pJointPos[2] = jointOri.z(); pJointPos[3] = jointOri.w(); - break; - } - case btMultibodyLink::ePlanar: - { - pJointPos[0] += dt * getJointVelMultiDof(i)[0]; - - btVector3 q0_coors_qd1qd2 = getJointVelMultiDof(i)[1] * m_links[i].getAxisBottom(1) + getJointVelMultiDof(i)[2] * m_links[i].getAxisBottom(2); - btVector3 no_q0_coors_qd1qd2 = quatRotate(btQuaternion(m_links[i].getAxisTop(0), pJointPos[0]), q0_coors_qd1qd2); - pJointPos[1] += m_links[i].getAxisBottom(1).dot(no_q0_coors_qd1qd2) * dt; - pJointPos[2] += m_links[i].getAxisBottom(2).dot(no_q0_coors_qd1qd2) * dt; - - break; - } - default: - { - } - - } - - m_links[i].updateCacheMultiDof(pq); - - if(pq) - pq += m_links[i].m_posVarCount; - if(pqd) - pqd += m_links[i].m_dofCount; - } -} - -void btMultiBody::fillConstraintJacobianMultiDof(int link, - const btVector3 &contact_point, - const btVector3 &normal_ang, - const btVector3 &normal_lin, - btScalar *jac, - btAlignedObjectArray &scratch_r, - btAlignedObjectArray &scratch_v, - btAlignedObjectArray &scratch_m) const -{ - // temporary space - int num_links = getNumLinks(); - int m_dofCount = getNumDofs(); - scratch_v.resize(3*num_links + 3); //(num_links + base) offsets + (num_links + base) normals_lin + (num_links + base) normals_ang - scratch_m.resize(num_links + 1); - - btVector3 * v_ptr = &scratch_v[0]; - btVector3 * p_minus_com_local = v_ptr; v_ptr += num_links + 1; - btVector3 * n_local_lin = v_ptr; v_ptr += num_links + 1; - btVector3 * n_local_ang = v_ptr; v_ptr += num_links + 1; - btAssert(v_ptr - &scratch_v[0] == scratch_v.size()); - - scratch_r.resize(m_dofCount); - btScalar * results = m_dofCount > 0 ? &scratch_r[0] : 0; - - btMatrix3x3 * rot_from_world = &scratch_m[0]; - - const btVector3 p_minus_com_world = contact_point - m_basePos; - const btVector3 &normal_lin_world = normal_lin; //convenience - const btVector3 &normal_ang_world = normal_ang; - - rot_from_world[0] = btMatrix3x3(m_baseQuat); - - // omega coeffients first. - btVector3 omega_coeffs_world; - omega_coeffs_world = p_minus_com_world.cross(normal_lin_world); - jac[0] = omega_coeffs_world[0] + normal_ang_world[0]; - jac[1] = omega_coeffs_world[1] + normal_ang_world[1]; - jac[2] = omega_coeffs_world[2] + normal_ang_world[2]; - // then v coefficients - jac[3] = normal_lin_world[0]; - jac[4] = normal_lin_world[1]; - jac[5] = normal_lin_world[2]; - - //create link-local versions of p_minus_com and normal - p_minus_com_local[0] = rot_from_world[0] * p_minus_com_world; - n_local_lin[0] = rot_from_world[0] * normal_lin_world; - n_local_ang[0] = rot_from_world[0] * normal_ang_world; - - // Set remaining jac values to zero for now. - for (int i = 6; i < 6 + m_dofCount; ++i) - { - jac[i] = 0; - } - - // Qdot coefficients, if necessary. - if (num_links > 0 && link > -1) { - - // TODO: speed this up -- don't calculate for m_links we don't need. - // (Also, we are making 3 separate calls to this function, for the normal & the 2 friction directions, - // which is resulting in repeated work being done...) - - // calculate required normals & positions in the local frames. - for (int i = 0; i < num_links; ++i) { - - // transform to local frame - const int parent = m_links[i].m_parent; - const btMatrix3x3 mtx(m_links[i].m_cachedRotParentToThis); - rot_from_world[i+1] = mtx * rot_from_world[parent+1]; - - n_local_lin[i+1] = mtx * n_local_lin[parent+1]; - n_local_ang[i+1] = mtx * n_local_ang[parent+1]; - p_minus_com_local[i+1] = mtx * p_minus_com_local[parent+1] - m_links[i].m_cachedRVector; - - // calculate the jacobian entry - switch(m_links[i].m_jointType) - { - case btMultibodyLink::eRevolute: - { - results[m_links[i].m_dofOffset] = n_local_lin[i+1].dot(m_links[i].getAxisTop(0).cross(p_minus_com_local[i+1]) + m_links[i].getAxisBottom(0)); - results[m_links[i].m_dofOffset] += n_local_ang[i+1].dot(m_links[i].getAxisTop(0)); - break; - } - case btMultibodyLink::ePrismatic: - { - results[m_links[i].m_dofOffset] = n_local_lin[i+1].dot(m_links[i].getAxisBottom(0)); - break; - } - case btMultibodyLink::eSpherical: - { - results[m_links[i].m_dofOffset + 0] = n_local_lin[i+1].dot(m_links[i].getAxisTop(0).cross(p_minus_com_local[i+1]) + m_links[i].getAxisBottom(0)); - results[m_links[i].m_dofOffset + 1] = n_local_lin[i+1].dot(m_links[i].getAxisTop(1).cross(p_minus_com_local[i+1]) + m_links[i].getAxisBottom(1)); - results[m_links[i].m_dofOffset + 2] = n_local_lin[i+1].dot(m_links[i].getAxisTop(2).cross(p_minus_com_local[i+1]) + m_links[i].getAxisBottom(2)); - - results[m_links[i].m_dofOffset + 0] += n_local_ang[i+1].dot(m_links[i].getAxisTop(0)); - results[m_links[i].m_dofOffset + 1] += n_local_ang[i+1].dot(m_links[i].getAxisTop(1)); - results[m_links[i].m_dofOffset + 2] += n_local_ang[i+1].dot(m_links[i].getAxisTop(2)); - - break; - } - case btMultibodyLink::ePlanar: - { - results[m_links[i].m_dofOffset + 0] = n_local_lin[i+1].dot(m_links[i].getAxisTop(0).cross(p_minus_com_local[i+1]));// + m_links[i].getAxisBottom(0)); - results[m_links[i].m_dofOffset + 1] = n_local_lin[i+1].dot(m_links[i].getAxisBottom(1)); - results[m_links[i].m_dofOffset + 2] = n_local_lin[i+1].dot(m_links[i].getAxisBottom(2)); - - break; - } - default: - { - } - } - - } - - // Now copy through to output. - //printf("jac[%d] = ", link); - while (link != -1) - { - for(int dof = 0; dof < m_links[link].m_dofCount; ++dof) - { - jac[6 + m_links[link].m_dofOffset + dof] = results[m_links[link].m_dofOffset + dof]; - //printf("%.2f\t", jac[6 + m_links[link].m_dofOffset + dof]); - } - - link = m_links[link].m_parent; - } - //printf("]\n"); - } -} - - -void btMultiBody::wakeUp() -{ - m_awake = true; -} - -void btMultiBody::goToSleep() -{ - m_awake = false; -} - -void btMultiBody::checkMotionAndSleepIfRequired(btScalar timestep) -{ - extern bool gDisableDeactivation; - if (!m_canSleep || gDisableDeactivation) - { - m_awake = true; - m_sleepTimer = 0; - return; - } - - // motion is computed as omega^2 + v^2 + (sum of squares of joint velocities) - btScalar motion = 0; - { - for (int i = 0; i < 6 + m_dofCount; ++i) - motion += m_realBuf[i] * m_realBuf[i]; - } - - - if (motion < SLEEP_EPSILON) { - m_sleepTimer += timestep; - if (m_sleepTimer > SLEEP_TIMEOUT) { - goToSleep(); - } - } else { - m_sleepTimer = 0; - if (!m_awake) - wakeUp(); - } -} - - -void btMultiBody::forwardKinematics(btAlignedObjectArray& world_to_local,btAlignedObjectArray& local_origin) -{ - - int num_links = getNumLinks(); - - // Cached 3x3 rotation matrices from parent frame to this frame. - btMatrix3x3* rot_from_parent =(btMatrix3x3 *) &m_matrixBuf[0]; - - rot_from_parent[0] = btMatrix3x3(m_baseQuat); //m_baseQuat assumed to be alias!? - - for (int i = 0; i < num_links; ++i) - { - rot_from_parent[i+1] = btMatrix3x3(m_links[i].m_cachedRotParentToThis); - } - - int nLinks = getNumLinks(); - ///base + num m_links - world_to_local.resize(nLinks+1); - local_origin.resize(nLinks+1); - - world_to_local[0] = getWorldToBaseRot(); - local_origin[0] = getBasePos(); - - for (int k=0;k& world_to_local,btAlignedObjectArray& local_origin) -{ - world_to_local.resize(getNumLinks()+1); - local_origin.resize(getNumLinks()+1); - - world_to_local[0] = getWorldToBaseRot(); - local_origin[0] = getBasePos(); - - if (getBaseCollider()) - { - btVector3 posr = local_origin[0]; - // float pos[4]={posr.x(),posr.y(),posr.z(),1}; - btScalar quat[4]={-world_to_local[0].x(),-world_to_local[0].y(),-world_to_local[0].z(),world_to_local[0].w()}; - btTransform tr; - tr.setIdentity(); - tr.setOrigin(posr); - tr.setRotation(btQuaternion(quat[0],quat[1],quat[2],quat[3])); - - getBaseCollider()->setWorldTransform(tr); - - } - - for (int k=0;km_link; - btAssert(link == m); - - int index = link+1; - - btVector3 posr = local_origin[index]; - // float pos[4]={posr.x(),posr.y(),posr.z(),1}; - btScalar quat[4]={-world_to_local[index].x(),-world_to_local[index].y(),-world_to_local[index].z(),world_to_local[index].w()}; - btTransform tr; - tr.setIdentity(); - tr.setOrigin(posr); - tr.setRotation(btQuaternion(quat[0],quat[1],quat[2],quat[3])); - - col->setWorldTransform(tr); - } - } -} - -int btMultiBody::calculateSerializeBufferSize() const -{ - int sz = sizeof(btMultiBodyData); - return sz; -} - - ///fills the dataBuffer and returns the struct name (and 0 on failure) -const char* btMultiBody::serialize(void* dataBuffer, class btSerializer* serializer) const -{ - btMultiBodyData* mbd = (btMultiBodyData*) dataBuffer; - getBaseWorldTransform().serialize(mbd->m_baseWorldTransform); - mbd->m_baseMass = this->getBaseMass(); - getBaseInertia().serialize(mbd->m_baseInertia); - { - char* name = (char*) serializer->findNameForPointer(m_baseName); - mbd->m_baseName = (char*)serializer->getUniquePointer(name); - if (mbd->m_baseName) - { - serializer->serializeName(name); - } - } - mbd->m_numLinks = this->getNumLinks(); - if (mbd->m_numLinks) - { - int sz = sizeof(btMultiBodyLinkData); - int numElem = mbd->m_numLinks; - btChunk* chunk = serializer->allocate(sz,numElem); - btMultiBodyLinkData* memPtr = (btMultiBodyLinkData*)chunk->m_oldPtr; - for (int i=0;im_jointType = getLink(i).m_jointType; - memPtr->m_dofCount = getLink(i).m_dofCount; - memPtr->m_posVarCount = getLink(i).m_posVarCount; - - getLink(i).m_inertiaLocal.serialize(memPtr->m_linkInertia); - memPtr->m_linkMass = getLink(i).m_mass; - memPtr->m_parentIndex = getLink(i).m_parent; - getLink(i).m_eVector.serialize(memPtr->m_parentComToThisComOffset); - getLink(i).m_dVector.serialize(memPtr->m_thisPivotToThisComOffset); - getLink(i).m_zeroRotParentToThis.serialize(memPtr->m_zeroRotParentToThis); - btAssert(memPtr->m_dofCount<=3); - for (int dof = 0;dofm_jointAxisBottom[dof]); - getLink(i).getAxisTop(dof).serialize(memPtr->m_jointAxisTop[dof]); - - memPtr->m_jointTorque[dof] = getLink(i).m_jointTorque[dof]; - memPtr->m_jointVel[dof] = getJointVelMultiDof(i)[dof]; - - } - int numPosVar = getLink(i).m_posVarCount; - for (int posvar = 0; posvar < numPosVar;posvar++) - { - memPtr->m_jointPos[posvar] = getLink(i).m_jointPos[posvar]; - } - - - { - char* name = (char*) serializer->findNameForPointer(m_links[i].m_linkName); - memPtr->m_linkName = (char*)serializer->getUniquePointer(name); - if (memPtr->m_linkName) - { - serializer->serializeName(name); - } - } - { - char* name = (char*) serializer->findNameForPointer(m_links[i].m_jointName); - memPtr->m_jointName = (char*)serializer->getUniquePointer(name); - if (memPtr->m_jointName) - { - serializer->serializeName(name); - } - } - memPtr->m_linkCollider = (btCollisionObjectData*)serializer->getUniquePointer(getLink(i).m_collider); - - } - serializer->finalizeChunk(chunk,btMultiBodyLinkDataName,BT_ARRAY_CODE,(void*) &m_links[0]); - } - mbd->m_links = mbd->m_numLinks? (btMultiBodyLinkData*) serializer->getUniquePointer((void*)&m_links[0]):0; - - return btMultiBodyDataName; -} +/* + * PURPOSE: + * Class representing an articulated rigid body. Stores the body's + * current state, allows forces and torques to be set, handles + * timestepping and implements Featherstone's algorithm. + * + * COPYRIGHT: + * Copyright (C) Stephen Thompson, , 2011-2013 + * Portions written By Erwin Coumans: connection to LCP solver, various multibody constraints, replacing Eigen math library by Bullet LinearMath and a dedicated 6x6 matrix inverse (solveImatrix) + * Portions written By Jakub Stepien: support for multi-DOF constraints, introduction of spatial algebra and several other improvements + + 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 "btMultiBody.h" +#include "btMultiBodyLink.h" +#include "btMultiBodyLinkCollider.h" +#include "btMultiBodyJointFeedback.h" +#include "LinearMath/btTransformUtil.h" +#include "LinearMath/btSerializer.h" +//#include "Bullet3Common/b3Logging.h" +// #define INCLUDE_GYRO_TERM + +///todo: determine if we need these options. If so, make a proper API, otherwise delete those globals +bool gJointFeedbackInWorldSpace = false; +bool gJointFeedbackInJointFrame = false; + +namespace { + const btScalar SLEEP_EPSILON = btScalar(0.05); // this is a squared velocity (m^2 s^-2) + const btScalar SLEEP_TIMEOUT = btScalar(2); // in seconds +} + +namespace { + void SpatialTransform(const btMatrix3x3 &rotation_matrix, // rotates vectors in 'from' frame to vectors in 'to' frame + const btVector3 &displacement, // vector from origin of 'from' frame to origin of 'to' frame, in 'to' coordinates + const btVector3 &top_in, // top part of input vector + const btVector3 &bottom_in, // bottom part of input vector + btVector3 &top_out, // top part of output vector + btVector3 &bottom_out) // bottom part of output vector + { + top_out = rotation_matrix * top_in; + bottom_out = -displacement.cross(top_out) + rotation_matrix * bottom_in; + } + +#if 0 + void InverseSpatialTransform(const btMatrix3x3 &rotation_matrix, + const btVector3 &displacement, + const btVector3 &top_in, + const btVector3 &bottom_in, + btVector3 &top_out, + btVector3 &bottom_out) + { + top_out = rotation_matrix.transpose() * top_in; + bottom_out = rotation_matrix.transpose() * (bottom_in + displacement.cross(top_in)); + } + + btScalar SpatialDotProduct(const btVector3 &a_top, + const btVector3 &a_bottom, + const btVector3 &b_top, + const btVector3 &b_bottom) + { + return a_bottom.dot(b_top) + a_top.dot(b_bottom); + } + + void SpatialCrossProduct(const btVector3 &a_top, + const btVector3 &a_bottom, + const btVector3 &b_top, + const btVector3 &b_bottom, + btVector3 &top_out, + btVector3 &bottom_out) + { + top_out = a_top.cross(b_top); + bottom_out = a_bottom.cross(b_top) + a_top.cross(b_bottom); + } +#endif + +} + + +// +// Implementation of class btMultiBody +// + +btMultiBody::btMultiBody(int n_links, + btScalar mass, + const btVector3 &inertia, + bool fixedBase, + bool canSleep, + bool /*deprecatedUseMultiDof*/) + : + m_baseCollider(0), + m_baseName(0), + m_basePos(0,0,0), + m_baseQuat(0, 0, 0, 1), + m_baseMass(mass), + m_baseInertia(inertia), + + m_fixedBase(fixedBase), + m_awake(true), + m_canSleep(canSleep), + m_sleepTimer(0), + m_userObjectPointer(0), + m_userIndex2(-1), + m_userIndex(-1), + m_linearDamping(0.04f), + m_angularDamping(0.04f), + m_useGyroTerm(true), + m_maxAppliedImpulse(1000.f), + m_maxCoordinateVelocity(100.f), + m_hasSelfCollision(true), + __posUpdated(false), + m_dofCount(0), + m_posVarCnt(0), + m_useRK4(false), + m_useGlobalVelocities(false), + m_internalNeedsJointFeedback(false) +{ + m_cachedInertiaTopLeft.setValue(0,0,0,0,0,0,0,0,0); + m_cachedInertiaTopRight.setValue(0,0,0,0,0,0,0,0,0); + m_cachedInertiaLowerLeft.setValue(0,0,0,0,0,0,0,0,0); + m_cachedInertiaLowerRight.setValue(0,0,0,0,0,0,0,0,0); + m_cachedInertiaValid=false; + + m_links.resize(n_links); + m_matrixBuf.resize(n_links + 1); + + m_baseForce.setValue(0, 0, 0); + m_baseTorque.setValue(0, 0, 0); +} + +btMultiBody::~btMultiBody() +{ +} + +void btMultiBody::setupFixed(int i, + btScalar mass, + const btVector3 &inertia, + int parent, + const btQuaternion &rotParentToThis, + const btVector3 &parentComToThisPivotOffset, + const btVector3 &thisPivotToThisComOffset, bool /*deprecatedDisableParentCollision*/) +{ + + m_links[i].m_mass = mass; + m_links[i].m_inertiaLocal = inertia; + m_links[i].m_parent = parent; + m_links[i].setAxisTop(0, 0., 0., 0.); + m_links[i].setAxisBottom(0, btVector3(0,0,0)); + m_links[i].m_zeroRotParentToThis = rotParentToThis; + m_links[i].m_dVector = thisPivotToThisComOffset; + m_links[i].m_eVector = parentComToThisPivotOffset; + + m_links[i].m_jointType = btMultibodyLink::eFixed; + m_links[i].m_dofCount = 0; + m_links[i].m_posVarCount = 0; + + m_links[i].m_flags |=BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION; + + m_links[i].updateCacheMultiDof(); + + updateLinksDofOffsets(); + +} + + +void btMultiBody::setupPrismatic(int i, + btScalar mass, + const btVector3 &inertia, + int parent, + const btQuaternion &rotParentToThis, + const btVector3 &jointAxis, + const btVector3 &parentComToThisPivotOffset, + const btVector3 &thisPivotToThisComOffset, + bool disableParentCollision) +{ + m_dofCount += 1; + m_posVarCnt += 1; + + m_links[i].m_mass = mass; + m_links[i].m_inertiaLocal = inertia; + m_links[i].m_parent = parent; + m_links[i].m_zeroRotParentToThis = rotParentToThis; + m_links[i].setAxisTop(0, 0., 0., 0.); + m_links[i].setAxisBottom(0, jointAxis); + m_links[i].m_eVector = parentComToThisPivotOffset; + m_links[i].m_dVector = thisPivotToThisComOffset; + m_links[i].m_cachedRotParentToThis = rotParentToThis; + + m_links[i].m_jointType = btMultibodyLink::ePrismatic; + m_links[i].m_dofCount = 1; + m_links[i].m_posVarCount = 1; + m_links[i].m_jointPos[0] = 0.f; + m_links[i].m_jointTorque[0] = 0.f; + + if (disableParentCollision) + m_links[i].m_flags |=BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION; + // + + m_links[i].updateCacheMultiDof(); + + updateLinksDofOffsets(); +} + +void btMultiBody::setupRevolute(int i, + btScalar mass, + const btVector3 &inertia, + int parent, + const btQuaternion &rotParentToThis, + const btVector3 &jointAxis, + const btVector3 &parentComToThisPivotOffset, + const btVector3 &thisPivotToThisComOffset, + bool disableParentCollision) +{ + m_dofCount += 1; + m_posVarCnt += 1; + + m_links[i].m_mass = mass; + m_links[i].m_inertiaLocal = inertia; + m_links[i].m_parent = parent; + m_links[i].m_zeroRotParentToThis = rotParentToThis; + m_links[i].setAxisTop(0, jointAxis); + m_links[i].setAxisBottom(0, jointAxis.cross(thisPivotToThisComOffset)); + m_links[i].m_dVector = thisPivotToThisComOffset; + m_links[i].m_eVector = parentComToThisPivotOffset; + + m_links[i].m_jointType = btMultibodyLink::eRevolute; + m_links[i].m_dofCount = 1; + m_links[i].m_posVarCount = 1; + m_links[i].m_jointPos[0] = 0.f; + m_links[i].m_jointTorque[0] = 0.f; + + if (disableParentCollision) + m_links[i].m_flags |=BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION; + // + m_links[i].updateCacheMultiDof(); + // + updateLinksDofOffsets(); +} + + + +void btMultiBody::setupSpherical(int i, + btScalar mass, + const btVector3 &inertia, + int parent, + const btQuaternion &rotParentToThis, + const btVector3 &parentComToThisPivotOffset, + const btVector3 &thisPivotToThisComOffset, + bool disableParentCollision) +{ + + m_dofCount += 3; + m_posVarCnt += 4; + + m_links[i].m_mass = mass; + m_links[i].m_inertiaLocal = inertia; + m_links[i].m_parent = parent; + m_links[i].m_zeroRotParentToThis = rotParentToThis; + m_links[i].m_dVector = thisPivotToThisComOffset; + m_links[i].m_eVector = parentComToThisPivotOffset; + + m_links[i].m_jointType = btMultibodyLink::eSpherical; + m_links[i].m_dofCount = 3; + m_links[i].m_posVarCount = 4; + m_links[i].setAxisTop(0, 1.f, 0.f, 0.f); + m_links[i].setAxisTop(1, 0.f, 1.f, 0.f); + m_links[i].setAxisTop(2, 0.f, 0.f, 1.f); + m_links[i].setAxisBottom(0, m_links[i].getAxisTop(0).cross(thisPivotToThisComOffset)); + m_links[i].setAxisBottom(1, m_links[i].getAxisTop(1).cross(thisPivotToThisComOffset)); + m_links[i].setAxisBottom(2, m_links[i].getAxisTop(2).cross(thisPivotToThisComOffset)); + m_links[i].m_jointPos[0] = m_links[i].m_jointPos[1] = m_links[i].m_jointPos[2] = 0.f; m_links[i].m_jointPos[3] = 1.f; + m_links[i].m_jointTorque[0] = m_links[i].m_jointTorque[1] = m_links[i].m_jointTorque[2] = 0.f; + + + if (disableParentCollision) + m_links[i].m_flags |=BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION; + // + m_links[i].updateCacheMultiDof(); + // + updateLinksDofOffsets(); +} + +void btMultiBody::setupPlanar(int i, + btScalar mass, + const btVector3 &inertia, + int parent, + const btQuaternion &rotParentToThis, + const btVector3 &rotationAxis, + const btVector3 &parentComToThisComOffset, + bool disableParentCollision) +{ + + m_dofCount += 3; + m_posVarCnt += 3; + + m_links[i].m_mass = mass; + m_links[i].m_inertiaLocal = inertia; + m_links[i].m_parent = parent; + m_links[i].m_zeroRotParentToThis = rotParentToThis; + m_links[i].m_dVector.setZero(); + m_links[i].m_eVector = parentComToThisComOffset; + + // + btVector3 vecNonParallelToRotAxis(1, 0, 0); + if(rotationAxis.normalized().dot(vecNonParallelToRotAxis) > 0.999) + vecNonParallelToRotAxis.setValue(0, 1, 0); + // + + m_links[i].m_jointType = btMultibodyLink::ePlanar; + m_links[i].m_dofCount = 3; + m_links[i].m_posVarCount = 3; + btVector3 n=rotationAxis.normalized(); + m_links[i].setAxisTop(0, n[0],n[1],n[2]); + m_links[i].setAxisTop(1,0,0,0); + m_links[i].setAxisTop(2,0,0,0); + m_links[i].setAxisBottom(0,0,0,0); + btVector3 cr = m_links[i].getAxisTop(0).cross(vecNonParallelToRotAxis); + m_links[i].setAxisBottom(1,cr[0],cr[1],cr[2]); + cr = m_links[i].getAxisBottom(1).cross(m_links[i].getAxisTop(0)); + m_links[i].setAxisBottom(2,cr[0],cr[1],cr[2]); + m_links[i].m_jointPos[0] = m_links[i].m_jointPos[1] = m_links[i].m_jointPos[2] = 0.f; + m_links[i].m_jointTorque[0] = m_links[i].m_jointTorque[1] = m_links[i].m_jointTorque[2] = 0.f; + + if (disableParentCollision) + m_links[i].m_flags |=BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION; + // + m_links[i].updateCacheMultiDof(); + // + updateLinksDofOffsets(); +} + +void btMultiBody::finalizeMultiDof() +{ + m_deltaV.resize(0); + m_deltaV.resize(6 + m_dofCount); + m_realBuf.resize(6 + m_dofCount + m_dofCount*m_dofCount + 6 + m_dofCount); //m_dofCount for joint-space vels + m_dofCount^2 for "D" matrices + delta-pos vector (6 base "vels" + joint "vels") + m_vectorBuf.resize(2 * m_dofCount); //two 3-vectors (i.e. one six-vector) for each system dof ("h" matrices) + + updateLinksDofOffsets(); +} + +int btMultiBody::getParent(int i) const +{ + return m_links[i].m_parent; +} + +btScalar btMultiBody::getLinkMass(int i) const +{ + return m_links[i].m_mass; +} + +const btVector3 & btMultiBody::getLinkInertia(int i) const +{ + return m_links[i].m_inertiaLocal; +} + +btScalar btMultiBody::getJointPos(int i) const +{ + return m_links[i].m_jointPos[0]; +} + +btScalar btMultiBody::getJointVel(int i) const +{ + return m_realBuf[6 + m_links[i].m_dofOffset]; +} + +btScalar * btMultiBody::getJointPosMultiDof(int i) +{ + return &m_links[i].m_jointPos[0]; +} + +btScalar * btMultiBody::getJointVelMultiDof(int i) +{ + return &m_realBuf[6 + m_links[i].m_dofOffset]; +} + +const btScalar * btMultiBody::getJointPosMultiDof(int i) const +{ + return &m_links[i].m_jointPos[0]; +} + +const btScalar * btMultiBody::getJointVelMultiDof(int i) const +{ + return &m_realBuf[6 + m_links[i].m_dofOffset]; +} + + +void btMultiBody::setJointPos(int i, btScalar q) +{ + m_links[i].m_jointPos[0] = q; + m_links[i].updateCacheMultiDof(); +} + +void btMultiBody::setJointPosMultiDof(int i, btScalar *q) +{ + for(int pos = 0; pos < m_links[i].m_posVarCount; ++pos) + m_links[i].m_jointPos[pos] = q[pos]; + + m_links[i].updateCacheMultiDof(); +} + +void btMultiBody::setJointVel(int i, btScalar qdot) +{ + m_realBuf[6 + m_links[i].m_dofOffset] = qdot; +} + +void btMultiBody::setJointVelMultiDof(int i, btScalar *qdot) +{ + for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) + m_realBuf[6 + m_links[i].m_dofOffset + dof] = qdot[dof]; +} + +const btVector3 & btMultiBody::getRVector(int i) const +{ + return m_links[i].m_cachedRVector; +} + +const btQuaternion & btMultiBody::getParentToLocalRot(int i) const +{ + return m_links[i].m_cachedRotParentToThis; +} + +btVector3 btMultiBody::localPosToWorld(int i, const btVector3 &local_pos) const +{ + btAssert(i>=-1); + btAssert(i=m_links.size())) + { + return btVector3(SIMD_INFINITY,SIMD_INFINITY,SIMD_INFINITY); + } + + btVector3 result = local_pos; + while (i != -1) { + // 'result' is in frame i. transform it to frame parent(i) + result += getRVector(i); + result = quatRotate(getParentToLocalRot(i).inverse(),result); + i = getParent(i); + } + + // 'result' is now in the base frame. transform it to world frame + result = quatRotate(getWorldToBaseRot().inverse() ,result); + result += getBasePos(); + + return result; +} + +btVector3 btMultiBody::worldPosToLocal(int i, const btVector3 &world_pos) const +{ + btAssert(i>=-1); + btAssert(i=m_links.size())) + { + return btVector3(SIMD_INFINITY,SIMD_INFINITY,SIMD_INFINITY); + } + + if (i == -1) { + // world to base + return quatRotate(getWorldToBaseRot(),(world_pos - getBasePos())); + } else { + // find position in parent frame, then transform to current frame + return quatRotate(getParentToLocalRot(i),worldPosToLocal(getParent(i), world_pos)) - getRVector(i); + } +} + +btVector3 btMultiBody::localDirToWorld(int i, const btVector3 &local_dir) const +{ + btAssert(i>=-1); + btAssert(i=m_links.size())) + { + return btVector3(SIMD_INFINITY,SIMD_INFINITY,SIMD_INFINITY); + } + + + btVector3 result = local_dir; + while (i != -1) { + result = quatRotate(getParentToLocalRot(i).inverse() , result); + i = getParent(i); + } + result = quatRotate(getWorldToBaseRot().inverse() , result); + return result; +} + +btVector3 btMultiBody::worldDirToLocal(int i, const btVector3 &world_dir) const +{ + btAssert(i>=-1); + btAssert(i=m_links.size())) + { + return btVector3(SIMD_INFINITY,SIMD_INFINITY,SIMD_INFINITY); + } + + if (i == -1) { + return quatRotate(getWorldToBaseRot(), world_dir); + } else { + return quatRotate(getParentToLocalRot(i) ,worldDirToLocal(getParent(i), world_dir)); + } +} + +btMatrix3x3 btMultiBody::localFrameToWorld(int i, const btMatrix3x3 &local_frame) const +{ + btMatrix3x3 result = local_frame; + btVector3 frameInWorld0 = localDirToWorld(i, local_frame.getColumn(0)); + btVector3 frameInWorld1 = localDirToWorld(i, local_frame.getColumn(1)); + btVector3 frameInWorld2 = localDirToWorld(i, local_frame.getColumn(2)); + result.setValue(frameInWorld0[0], frameInWorld1[0], frameInWorld2[0], frameInWorld0[1], frameInWorld1[1], frameInWorld2[1], frameInWorld0[2], frameInWorld1[2], frameInWorld2[2]); + return result; +} + +void btMultiBody::compTreeLinkVelocities(btVector3 *omega, btVector3 *vel) const +{ + int num_links = getNumLinks(); + // Calculates the velocities of each link (and the base) in its local frame + omega[0] = quatRotate(m_baseQuat ,getBaseOmega()); + vel[0] = quatRotate(m_baseQuat ,getBaseVel()); + + for (int i = 0; i < num_links; ++i) + { + const int parent = m_links[i].m_parent; + + // transform parent vel into this frame, store in omega[i+1], vel[i+1] + SpatialTransform(btMatrix3x3(m_links[i].m_cachedRotParentToThis), m_links[i].m_cachedRVector, + omega[parent+1], vel[parent+1], + omega[i+1], vel[i+1]); + + // now add qidot * shat_i + //only supported for revolute/prismatic joints, todo: spherical and planar joints + switch(m_links[i].m_jointType) + { + case btMultibodyLink::ePrismatic: + case btMultibodyLink::eRevolute: + { + btVector3 axisTop = m_links[i].getAxisTop(0); + btVector3 axisBottom = m_links[i].getAxisBottom(0); + btScalar jointVel = getJointVel(i); + omega[i+1] += jointVel * axisTop; + vel[i+1] += jointVel * axisBottom; + break; + } + default: + { + } + } + } +} + +btScalar btMultiBody::getKineticEnergy() const +{ + int num_links = getNumLinks(); + // TODO: would be better not to allocate memory here + btAlignedObjectArray omega;omega.resize(num_links+1); + btAlignedObjectArray vel;vel.resize(num_links+1); + compTreeLinkVelocities(&omega[0], &vel[0]); + + // we will do the factor of 0.5 at the end + btScalar result = m_baseMass * vel[0].dot(vel[0]); + result += omega[0].dot(m_baseInertia * omega[0]); + + for (int i = 0; i < num_links; ++i) { + result += m_links[i].m_mass * vel[i+1].dot(vel[i+1]); + result += omega[i+1].dot(m_links[i].m_inertiaLocal * omega[i+1]); + } + + return 0.5f * result; +} + +btVector3 btMultiBody::getAngularMomentum() const +{ + int num_links = getNumLinks(); + // TODO: would be better not to allocate memory here + btAlignedObjectArray omega;omega.resize(num_links+1); + btAlignedObjectArray vel;vel.resize(num_links+1); + btAlignedObjectArray rot_from_world;rot_from_world.resize(num_links+1); + compTreeLinkVelocities(&omega[0], &vel[0]); + + rot_from_world[0] = m_baseQuat; + btVector3 result = quatRotate(rot_from_world[0].inverse() , (m_baseInertia * omega[0])); + + for (int i = 0; i < num_links; ++i) { + rot_from_world[i+1] = m_links[i].m_cachedRotParentToThis * rot_from_world[m_links[i].m_parent+1]; + result += (quatRotate(rot_from_world[i+1].inverse() , (m_links[i].m_inertiaLocal * omega[i+1]))); + } + + return result; +} + +void btMultiBody::clearConstraintForces() +{ + m_baseConstraintForce.setValue(0, 0, 0); + m_baseConstraintTorque.setValue(0, 0, 0); + + + for (int i = 0; i < getNumLinks(); ++i) { + m_links[i].m_appliedConstraintForce.setValue(0, 0, 0); + m_links[i].m_appliedConstraintTorque.setValue(0, 0, 0); + } +} +void btMultiBody::clearForcesAndTorques() +{ + m_baseForce.setValue(0, 0, 0); + m_baseTorque.setValue(0, 0, 0); + + + for (int i = 0; i < getNumLinks(); ++i) { + m_links[i].m_appliedForce.setValue(0, 0, 0); + m_links[i].m_appliedTorque.setValue(0, 0, 0); + m_links[i].m_jointTorque[0] = m_links[i].m_jointTorque[1] = m_links[i].m_jointTorque[2] = m_links[i].m_jointTorque[3] = m_links[i].m_jointTorque[4] = m_links[i].m_jointTorque[5] = 0.f; + } +} + +void btMultiBody::clearVelocities() +{ + for (int i = 0; i < 6 + getNumDofs(); ++i) + { + m_realBuf[i] = 0.f; + } +} +void btMultiBody::addLinkForce(int i, const btVector3 &f) +{ + m_links[i].m_appliedForce += f; +} + +void btMultiBody::addLinkTorque(int i, const btVector3 &t) +{ + m_links[i].m_appliedTorque += t; +} + +void btMultiBody::addLinkConstraintForce(int i, const btVector3 &f) +{ + m_links[i].m_appliedConstraintForce += f; +} + +void btMultiBody::addLinkConstraintTorque(int i, const btVector3 &t) +{ + m_links[i].m_appliedConstraintTorque += t; +} + + + +void btMultiBody::addJointTorque(int i, btScalar Q) +{ + m_links[i].m_jointTorque[0] += Q; +} + +void btMultiBody::addJointTorqueMultiDof(int i, int dof, btScalar Q) +{ + m_links[i].m_jointTorque[dof] += Q; +} + +void btMultiBody::addJointTorqueMultiDof(int i, const btScalar *Q) +{ + for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) + m_links[i].m_jointTorque[dof] = Q[dof]; +} + +const btVector3 & btMultiBody::getLinkForce(int i) const +{ + return m_links[i].m_appliedForce; +} + +const btVector3 & btMultiBody::getLinkTorque(int i) const +{ + return m_links[i].m_appliedTorque; +} + +btScalar btMultiBody::getJointTorque(int i) const +{ + return m_links[i].m_jointTorque[0]; +} + +btScalar * btMultiBody::getJointTorqueMultiDof(int i) +{ + return &m_links[i].m_jointTorque[0]; +} + +inline btMatrix3x3 outerProduct(const btVector3& v0, const btVector3& v1) //renamed it from vecMulVecTranspose (http://en.wikipedia.org/wiki/Outer_product); maybe it should be moved to btVector3 like dot and cross? +{ + btVector3 row0 = btVector3( + v0.x() * v1.x(), + v0.x() * v1.y(), + v0.x() * v1.z()); + btVector3 row1 = btVector3( + v0.y() * v1.x(), + v0.y() * v1.y(), + v0.y() * v1.z()); + btVector3 row2 = btVector3( + v0.z() * v1.x(), + v0.z() * v1.y(), + v0.z() * v1.z()); + + btMatrix3x3 m(row0[0],row0[1],row0[2], + row1[0],row1[1],row1[2], + row2[0],row2[1],row2[2]); + return m; +} + +#define vecMulVecTranspose(v0, v1Transposed) outerProduct(v0, v1Transposed) +// + +void btMultiBody::computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar dt, + btAlignedObjectArray &scratch_r, + btAlignedObjectArray &scratch_v, + btAlignedObjectArray &scratch_m, + bool isConstraintPass) +{ + // Implement Featherstone's algorithm to calculate joint accelerations (q_double_dot) + // and the base linear & angular accelerations. + + // We apply damping forces in this routine as well as any external forces specified by the + // caller (via addBaseForce etc). + + // output should point to an array of 6 + num_links reals. + // Format is: 3 angular accelerations (in world frame), 3 linear accelerations (in world frame), + // num_links joint acceleration values. + + // We added support for multi degree of freedom (multi dof) joints. + // In addition we also can compute the joint reaction forces. This is performed in a second pass, + // so that we can include the effect of the constraint solver forces (computed in the PGS LCP solver) + + m_internalNeedsJointFeedback = false; + + int num_links = getNumLinks(); + + const btScalar DAMPING_K1_LINEAR = m_linearDamping; + const btScalar DAMPING_K2_LINEAR = m_linearDamping; + + const btScalar DAMPING_K1_ANGULAR = m_angularDamping; + const btScalar DAMPING_K2_ANGULAR= m_angularDamping; + + btVector3 base_vel = getBaseVel(); + btVector3 base_omega = getBaseOmega(); + + // Temporary matrices/vectors -- use scratch space from caller + // so that we don't have to keep reallocating every frame + + scratch_r.resize(2*m_dofCount + 6); //multidof? ("Y"s use it and it is used to store qdd) => 2 x m_dofCount + scratch_v.resize(8*num_links + 6); + scratch_m.resize(4*num_links + 4); + + //btScalar * r_ptr = &scratch_r[0]; + btScalar * output = &scratch_r[m_dofCount]; // "output" holds the q_double_dot results + btVector3 * v_ptr = &scratch_v[0]; + + // vhat_i (top = angular, bottom = linear part) + btSpatialMotionVector *spatVel = (btSpatialMotionVector *)v_ptr; + v_ptr += num_links * 2 + 2; + // + // zhat_i^A + btSpatialForceVector * zeroAccSpatFrc = (btSpatialForceVector *)v_ptr; + v_ptr += num_links * 2 + 2; + // + // chat_i (note NOT defined for the base) + btSpatialMotionVector * spatCoriolisAcc = (btSpatialMotionVector *)v_ptr; + v_ptr += num_links * 2; + // + // Ihat_i^A. + btSymmetricSpatialDyad * spatInertia = (btSymmetricSpatialDyad *)&scratch_m[num_links + 1]; + + // Cached 3x3 rotation matrices from parent frame to this frame. + btMatrix3x3 * rot_from_parent = &m_matrixBuf[0]; + btMatrix3x3 * rot_from_world = &scratch_m[0]; + + // hhat_i, ahat_i + // hhat is NOT stored for the base (but ahat is) + btSpatialForceVector * h = (btSpatialForceVector *)(m_dofCount > 0 ? &m_vectorBuf[0] : 0); + btSpatialMotionVector * spatAcc = (btSpatialMotionVector *)v_ptr; + v_ptr += num_links * 2 + 2; + // + // Y_i, invD_i + btScalar * invD = m_dofCount > 0 ? &m_realBuf[6 + m_dofCount] : 0; + btScalar * Y = &scratch_r[0]; + // + //aux variables + btSpatialMotionVector spatJointVel; //spatial velocity due to the joint motion (i.e. without predecessors' influence) + btScalar D[36]; //"D" matrix; it's dofxdof for each body so asingle 6x6 D matrix will do + btScalar invD_times_Y[6]; //D^{-1} * Y [dofxdof x dofx1 = dofx1] <=> D^{-1} * u; better moved to buffers since it is recalced in calcAccelerationDeltasMultiDof; num_dof of btScalar would cover all bodies + btSpatialMotionVector result; //holds results of the SolveImatrix op; it is a spatial motion vector (accel) + btScalar Y_minus_hT_a[6]; //Y - h^{T} * a; it's dofx1 for each body so a single 6x1 temp is enough + btSpatialForceVector spatForceVecTemps[6]; //6 temporary spatial force vectors + btSpatialTransformationMatrix fromParent; //spatial transform from parent to child + btSymmetricSpatialDyad dyadTemp; //inertia matrix temp + btSpatialTransformationMatrix fromWorld; + fromWorld.m_trnVec.setZero(); + ///////////////// + + // ptr to the joint accel part of the output + btScalar * joint_accel = output + 6; + + // Start of the algorithm proper. + + // First 'upward' loop. + // Combines CompTreeLinkVelocities and InitTreeLinks from Mirtich. + + rot_from_parent[0] = btMatrix3x3(m_baseQuat); //m_baseQuat assumed to be alias!? + + //create the vector of spatial velocity of the base by transforming global-coor linear and angular velocities into base-local coordinates + spatVel[0].setVector(rot_from_parent[0] * base_omega, rot_from_parent[0] * base_vel); + + if (m_fixedBase) + { + zeroAccSpatFrc[0].setZero(); + } + else + { + btVector3 baseForce = isConstraintPass? m_baseConstraintForce : m_baseForce; + btVector3 baseTorque = isConstraintPass? m_baseConstraintTorque : m_baseTorque; + //external forces + zeroAccSpatFrc[0].setVector(-(rot_from_parent[0] * baseTorque), -(rot_from_parent[0] * baseForce)); + + //adding damping terms (only) + btScalar linDampMult = 1., angDampMult = 1.; + zeroAccSpatFrc[0].addVector(angDampMult * m_baseInertia * spatVel[0].getAngular() * (DAMPING_K1_ANGULAR + DAMPING_K2_ANGULAR * spatVel[0].getAngular().safeNorm()), + linDampMult * m_baseMass * spatVel[0].getLinear() * (DAMPING_K1_LINEAR + DAMPING_K2_LINEAR * spatVel[0].getLinear().safeNorm())); + + // + //p += vhat x Ihat vhat - done in a simpler way + if (m_useGyroTerm) + zeroAccSpatFrc[0].addAngular(spatVel[0].getAngular().cross(m_baseInertia * spatVel[0].getAngular())); + // + zeroAccSpatFrc[0].addLinear(m_baseMass * spatVel[0].getAngular().cross(spatVel[0].getLinear())); + } + + + //init the spatial AB inertia (it has the simple form thanks to choosing local body frames origins at their COMs) + spatInertia[0].setMatrix( btMatrix3x3(0,0,0,0,0,0,0,0,0), + // + btMatrix3x3(m_baseMass, 0, 0, + 0, m_baseMass, 0, + 0, 0, m_baseMass), + // + btMatrix3x3(m_baseInertia[0], 0, 0, + 0, m_baseInertia[1], 0, + 0, 0, m_baseInertia[2]) + ); + + rot_from_world[0] = rot_from_parent[0]; + + // + for (int i = 0; i < num_links; ++i) { + const int parent = m_links[i].m_parent; + rot_from_parent[i+1] = btMatrix3x3(m_links[i].m_cachedRotParentToThis); + rot_from_world[i+1] = rot_from_parent[i+1] * rot_from_world[parent+1]; + + fromParent.m_rotMat = rot_from_parent[i+1]; fromParent.m_trnVec = m_links[i].m_cachedRVector; + fromWorld.m_rotMat = rot_from_world[i+1]; + fromParent.transform(spatVel[parent+1], spatVel[i+1]); + + // now set vhat_i to its true value by doing + // vhat_i += qidot * shat_i + if(!m_useGlobalVelocities) + { + spatJointVel.setZero(); + + for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) + spatJointVel += m_links[i].m_axes[dof] * getJointVelMultiDof(i)[dof]; + + // remember vhat_i is really vhat_p(i) (but in current frame) at this point => we need to add velocity across the inboard joint + spatVel[i+1] += spatJointVel; + + // + // vhat_i is vhat_p(i) transformed to local coors + the velocity across the i-th inboard joint + //spatVel[i+1] = fromParent * spatVel[parent+1] + spatJointVel; + + } + else + { + fromWorld.transformRotationOnly(m_links[i].m_absFrameTotVelocity, spatVel[i+1]); + fromWorld.transformRotationOnly(m_links[i].m_absFrameLocVelocity, spatJointVel); + } + + // we can now calculate chat_i + spatVel[i+1].cross(spatJointVel, spatCoriolisAcc[i]); + + // calculate zhat_i^A + // + //external forces + btVector3 linkAppliedForce = isConstraintPass? m_links[i].m_appliedConstraintForce : m_links[i].m_appliedForce; + btVector3 linkAppliedTorque =isConstraintPass ? m_links[i].m_appliedConstraintTorque : m_links[i].m_appliedTorque; + + zeroAccSpatFrc[i+1].setVector(-(rot_from_world[i+1] * linkAppliedTorque), -(rot_from_world[i+1] * linkAppliedForce )); + +#if 0 + { + + b3Printf("stepVelocitiesMultiDof zeroAccSpatFrc[%d] linear:%f,%f,%f, angular:%f,%f,%f", + i+1, + zeroAccSpatFrc[i+1].m_topVec[0], + zeroAccSpatFrc[i+1].m_topVec[1], + zeroAccSpatFrc[i+1].m_topVec[2], + + zeroAccSpatFrc[i+1].m_bottomVec[0], + zeroAccSpatFrc[i+1].m_bottomVec[1], + zeroAccSpatFrc[i+1].m_bottomVec[2]); + } +#endif + // + //adding damping terms (only) + btScalar linDampMult = 1., angDampMult = 1.; + zeroAccSpatFrc[i+1].addVector(angDampMult * m_links[i].m_inertiaLocal * spatVel[i+1].getAngular() * (DAMPING_K1_ANGULAR + DAMPING_K2_ANGULAR * spatVel[i+1].getAngular().safeNorm()), + linDampMult * m_links[i].m_mass * spatVel[i+1].getLinear() * (DAMPING_K1_LINEAR + DAMPING_K2_LINEAR * spatVel[i+1].getLinear().safeNorm())); + + // calculate Ihat_i^A + //init the spatial AB inertia (it has the simple form thanks to choosing local body frames origins at their COMs) + spatInertia[i+1].setMatrix( btMatrix3x3(0,0,0,0,0,0,0,0,0), + // + btMatrix3x3(m_links[i].m_mass, 0, 0, + 0, m_links[i].m_mass, 0, + 0, 0, m_links[i].m_mass), + // + btMatrix3x3(m_links[i].m_inertiaLocal[0], 0, 0, + 0, m_links[i].m_inertiaLocal[1], 0, + 0, 0, m_links[i].m_inertiaLocal[2]) + ); + // + //p += vhat x Ihat vhat - done in a simpler way + if(m_useGyroTerm) + zeroAccSpatFrc[i+1].addAngular(spatVel[i+1].getAngular().cross(m_links[i].m_inertiaLocal * spatVel[i+1].getAngular())); + // + zeroAccSpatFrc[i+1].addLinear(m_links[i].m_mass * spatVel[i+1].getAngular().cross(spatVel[i+1].getLinear())); + //btVector3 temp = m_links[i].m_mass * spatVel[i+1].getAngular().cross(spatVel[i+1].getLinear()); + ////clamp parent's omega + //btScalar parOmegaMod = temp.length(); + //btScalar parOmegaModMax = 1000; + //if(parOmegaMod > parOmegaModMax) + // temp *= parOmegaModMax / parOmegaMod; + //zeroAccSpatFrc[i+1].addLinear(temp); + //printf("|zeroAccSpatFrc[%d]| = %.4f\n", i+1, temp.length()); + //temp = spatCoriolisAcc[i].getLinear(); + //printf("|spatCoriolisAcc[%d]| = %.4f\n", i+1, temp.length()); + + + + //printf("w[%d] = [%.4f %.4f %.4f]\n", i, vel_top_angular[i+1].x(), vel_top_angular[i+1].y(), vel_top_angular[i+1].z()); + //printf("v[%d] = [%.4f %.4f %.4f]\n", i, vel_bottom_linear[i+1].x(), vel_bottom_linear[i+1].y(), vel_bottom_linear[i+1].z()); + //printf("c[%d] = [%.4f %.4f %.4f]\n", i, coriolis_bottom_linear[i].x(), coriolis_bottom_linear[i].y(), coriolis_bottom_linear[i].z()); + } + + // 'Downward' loop. + // (part of TreeForwardDynamics in Mirtich.) + for (int i = num_links - 1; i >= 0; --i) + { + const int parent = m_links[i].m_parent; + fromParent.m_rotMat = rot_from_parent[i+1]; fromParent.m_trnVec = m_links[i].m_cachedRVector; + + for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) + { + btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof]; + // + hDof = spatInertia[i+1] * m_links[i].m_axes[dof]; + // + Y[m_links[i].m_dofOffset + dof] = m_links[i].m_jointTorque[dof] + - m_links[i].m_axes[dof].dot(zeroAccSpatFrc[i+1]) + - spatCoriolisAcc[i].dot(hDof) + ; + } + + for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) + { + btScalar *D_row = &D[dof * m_links[i].m_dofCount]; + for(int dof2 = 0; dof2 < m_links[i].m_dofCount; ++dof2) + { + btSpatialForceVector &hDof2 = h[m_links[i].m_dofOffset + dof2]; + D_row[dof2] = m_links[i].m_axes[dof].dot(hDof2); + } + } + + btScalar *invDi = &invD[m_links[i].m_dofOffset*m_links[i].m_dofOffset]; + switch(m_links[i].m_jointType) + { + case btMultibodyLink::ePrismatic: + case btMultibodyLink::eRevolute: + { + invDi[0] = 1.0f / D[0]; + break; + } + case btMultibodyLink::eSpherical: + case btMultibodyLink::ePlanar: + { + btMatrix3x3 D3x3; D3x3.setValue(D[0], D[1], D[2], D[3], D[4], D[5], D[6], D[7], D[8]); + btMatrix3x3 invD3x3; invD3x3 = D3x3.inverse(); + + //unroll the loop? + for(int row = 0; row < 3; ++row) + { + for(int col = 0; col < 3; ++col) + { + invDi[row * 3 + col] = invD3x3[row][col]; + } + } + + break; + } + default: + { + + } + } + + //determine h*D^{-1} + for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) + { + spatForceVecTemps[dof].setZero(); + + for(int dof2 = 0; dof2 < m_links[i].m_dofCount; ++dof2) + { + btSpatialForceVector &hDof2 = h[m_links[i].m_dofOffset + dof2]; + // + spatForceVecTemps[dof] += hDof2 * invDi[dof2 * m_links[i].m_dofCount + dof]; + } + } + + dyadTemp = spatInertia[i+1]; + + //determine (h*D^{-1}) * h^{T} + for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) + { + btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof]; + // + dyadTemp -= symmetricSpatialOuterProduct(hDof, spatForceVecTemps[dof]); + } + + fromParent.transformInverse(dyadTemp, spatInertia[parent+1], btSpatialTransformationMatrix::Add); + + for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) + { + invD_times_Y[dof] = 0.f; + + for(int dof2 = 0; dof2 < m_links[i].m_dofCount; ++dof2) + { + invD_times_Y[dof] += invDi[dof * m_links[i].m_dofCount + dof2] * Y[m_links[i].m_dofOffset + dof2]; + } + } + + spatForceVecTemps[0] = zeroAccSpatFrc[i+1] + spatInertia[i+1] * spatCoriolisAcc[i]; + + for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) + { + btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof]; + // + spatForceVecTemps[0] += hDof * invD_times_Y[dof]; + } + + fromParent.transformInverse(spatForceVecTemps[0], spatForceVecTemps[1]); + + zeroAccSpatFrc[parent+1] += spatForceVecTemps[1]; + } + + + // Second 'upward' loop + // (part of TreeForwardDynamics in Mirtich) + + if (m_fixedBase) + { + spatAcc[0].setZero(); + } + else + { + if (num_links > 0) + { + m_cachedInertiaValid = true; + m_cachedInertiaTopLeft = spatInertia[0].m_topLeftMat; + m_cachedInertiaTopRight = spatInertia[0].m_topRightMat; + m_cachedInertiaLowerLeft = spatInertia[0].m_bottomLeftMat; + m_cachedInertiaLowerRight= spatInertia[0].m_topLeftMat.transpose(); + + } + + solveImatrix(zeroAccSpatFrc[0], result); + spatAcc[0] = -result; + } + + + // now do the loop over the m_links + for (int i = 0; i < num_links; ++i) + { + // qdd = D^{-1} * (Y - h^{T}*apar) = (S^{T}*I*S)^{-1} * (tau - S^{T}*I*cor - S^{T}*zeroAccFrc - S^{T}*I*apar) + // a = apar + cor + Sqdd + //or + // qdd = D^{-1} * (Y - h^{T}*(apar+cor)) + // a = apar + Sqdd + + const int parent = m_links[i].m_parent; + fromParent.m_rotMat = rot_from_parent[i+1]; fromParent.m_trnVec = m_links[i].m_cachedRVector; + + fromParent.transform(spatAcc[parent+1], spatAcc[i+1]); + + for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) + { + btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof]; + // + Y_minus_hT_a[dof] = Y[m_links[i].m_dofOffset + dof] - spatAcc[i+1].dot(hDof); + } + + btScalar *invDi = &invD[m_links[i].m_dofOffset*m_links[i].m_dofOffset]; + //D^{-1} * (Y - h^{T}*apar) + mulMatrix(invDi, Y_minus_hT_a, m_links[i].m_dofCount, m_links[i].m_dofCount, m_links[i].m_dofCount, 1, &joint_accel[m_links[i].m_dofOffset]); + + spatAcc[i+1] += spatCoriolisAcc[i]; + + for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) + spatAcc[i+1] += m_links[i].m_axes[dof] * joint_accel[m_links[i].m_dofOffset + dof]; + + if (m_links[i].m_jointFeedback) + { + m_internalNeedsJointFeedback = true; + + btVector3 angularBotVec = (spatInertia[i+1]*spatAcc[i+1]+zeroAccSpatFrc[i+1]).m_bottomVec; + btVector3 linearTopVec = (spatInertia[i+1]*spatAcc[i+1]+zeroAccSpatFrc[i+1]).m_topVec; + + if (gJointFeedbackInJointFrame) + { + //shift the reaction forces to the joint frame + //linear (force) component is the same + //shift the angular (torque, moment) component using the relative position, m_links[i].m_dVector + angularBotVec = angularBotVec - linearTopVec.cross(m_links[i].m_dVector); + } + + + if (gJointFeedbackInWorldSpace) + { + if (isConstraintPass) + { + m_links[i].m_jointFeedback->m_reactionForces.m_bottomVec += m_links[i].m_cachedWorldTransform.getBasis()*angularBotVec; + m_links[i].m_jointFeedback->m_reactionForces.m_topVec += m_links[i].m_cachedWorldTransform.getBasis()*linearTopVec; + } else + { + m_links[i].m_jointFeedback->m_reactionForces.m_bottomVec = m_links[i].m_cachedWorldTransform.getBasis()*angularBotVec; + m_links[i].m_jointFeedback->m_reactionForces.m_topVec = m_links[i].m_cachedWorldTransform.getBasis()*linearTopVec; + } + } else + { + if (isConstraintPass) + { + m_links[i].m_jointFeedback->m_reactionForces.m_bottomVec += angularBotVec; + m_links[i].m_jointFeedback->m_reactionForces.m_topVec += linearTopVec; + + } + else + { + m_links[i].m_jointFeedback->m_reactionForces.m_bottomVec = angularBotVec; + m_links[i].m_jointFeedback->m_reactionForces.m_topVec = linearTopVec; + } + } + } + + } + + // transform base accelerations back to the world frame. + btVector3 omegadot_out = rot_from_parent[0].transpose() * spatAcc[0].getAngular(); + output[0] = omegadot_out[0]; + output[1] = omegadot_out[1]; + output[2] = omegadot_out[2]; + + btVector3 vdot_out = rot_from_parent[0].transpose() * (spatAcc[0].getLinear() + spatVel[0].getAngular().cross(spatVel[0].getLinear())); + output[3] = vdot_out[0]; + output[4] = vdot_out[1]; + output[5] = vdot_out[2]; + + ///////////////// + //printf("q = ["); + //printf("%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f ", m_baseQuat.x(), m_baseQuat.y(), m_baseQuat.z(), m_baseQuat.w(), m_basePos.x(), m_basePos.y(), m_basePos.z()); + //for(int link = 0; link < getNumLinks(); ++link) + // for(int dof = 0; dof < m_links[link].m_dofCount; ++dof) + // printf("%.6f ", m_links[link].m_jointPos[dof]); + //printf("]\n"); + //// + //printf("qd = ["); + //for(int dof = 0; dof < getNumDofs() + 6; ++dof) + // printf("%.6f ", m_realBuf[dof]); + //printf("]\n"); + //printf("qdd = ["); + //for(int dof = 0; dof < getNumDofs() + 6; ++dof) + // printf("%.6f ", output[dof]); + //printf("]\n"); + ///////////////// + + // Final step: add the accelerations (times dt) to the velocities. + + if (!isConstraintPass) + { + if(dt > 0.) + applyDeltaVeeMultiDof(output, dt); + + } + ///// + //btScalar angularThres = 1; + //btScalar maxAngVel = 0.; + //bool scaleDown = 1.; + //for(int link = 0; link < m_links.size(); ++link) + //{ + // if(spatVel[link+1].getAngular().length() > maxAngVel) + // { + // maxAngVel = spatVel[link+1].getAngular().length(); + // scaleDown = angularThres / spatVel[link+1].getAngular().length(); + // break; + // } + //} + + //if(scaleDown != 1.) + //{ + // for(int link = 0; link < m_links.size(); ++link) + // { + // if(m_links[link].m_jointType == btMultibodyLink::eRevolute || m_links[link].m_jointType == btMultibodyLink::eSpherical) + // { + // for(int dof = 0; dof < m_links[link].m_dofCount; ++dof) + // getJointVelMultiDof(link)[dof] *= scaleDown; + // } + // } + //} + ///// + + ///////////////////// + if(m_useGlobalVelocities) + { + for (int i = 0; i < num_links; ++i) + { + const int parent = m_links[i].m_parent; + //rot_from_parent[i+1] = btMatrix3x3(m_links[i].m_cachedRotParentToThis); /// <- done + //rot_from_world[i+1] = rot_from_parent[i+1] * rot_from_world[parent+1]; /// <- done + + fromParent.m_rotMat = rot_from_parent[i+1]; fromParent.m_trnVec = m_links[i].m_cachedRVector; + fromWorld.m_rotMat = rot_from_world[i+1]; + + // vhat_i = i_xhat_p(i) * vhat_p(i) + fromParent.transform(spatVel[parent+1], spatVel[i+1]); + //nice alternative below (using operator *) but it generates temps + ///////////////////////////////////////////////////////////// + + // now set vhat_i to its true value by doing + // vhat_i += qidot * shat_i + spatJointVel.setZero(); + + for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) + spatJointVel += m_links[i].m_axes[dof] * getJointVelMultiDof(i)[dof]; + + // remember vhat_i is really vhat_p(i) (but in current frame) at this point => we need to add velocity across the inboard joint + spatVel[i+1] += spatJointVel; + + + fromWorld.transformInverseRotationOnly(spatVel[i+1], m_links[i].m_absFrameTotVelocity); + fromWorld.transformInverseRotationOnly(spatJointVel, m_links[i].m_absFrameLocVelocity); + } + } + +} + + + +void btMultiBody::solveImatrix(const btVector3& rhs_top, const btVector3& rhs_bot, btScalar result[6]) const +{ + int num_links = getNumLinks(); + ///solve I * x = rhs, so the result = invI * rhs + if (num_links == 0) + { + // in the case of 0 m_links (i.e. a plain rigid body, not a multibody) rhs * invI is easier + result[0] = rhs_bot[0] / m_baseInertia[0]; + result[1] = rhs_bot[1] / m_baseInertia[1]; + result[2] = rhs_bot[2] / m_baseInertia[2]; + result[3] = rhs_top[0] / m_baseMass; + result[4] = rhs_top[1] / m_baseMass; + result[5] = rhs_top[2] / m_baseMass; + } else + { + if (!m_cachedInertiaValid) + { + for (int i=0;i<6;i++) + { + result[i] = 0.f; + } + return; + } + /// Special routine for calculating the inverse of a spatial inertia matrix + ///the 6x6 matrix is stored as 4 blocks of 3x3 matrices + btMatrix3x3 Binv = m_cachedInertiaTopRight.inverse()*-1.f; + btMatrix3x3 tmp = m_cachedInertiaLowerRight * Binv; + btMatrix3x3 invIupper_right = (tmp * m_cachedInertiaTopLeft + m_cachedInertiaLowerLeft).inverse(); + tmp = invIupper_right * m_cachedInertiaLowerRight; + btMatrix3x3 invI_upper_left = (tmp * Binv); + btMatrix3x3 invI_lower_right = (invI_upper_left).transpose(); + tmp = m_cachedInertiaTopLeft * invI_upper_left; + tmp[0][0]-= 1.0; + tmp[1][1]-= 1.0; + tmp[2][2]-= 1.0; + btMatrix3x3 invI_lower_left = (Binv * tmp); + + //multiply result = invI * rhs + { + btVector3 vtop = invI_upper_left*rhs_top; + btVector3 tmp; + tmp = invIupper_right * rhs_bot; + vtop += tmp; + btVector3 vbot = invI_lower_left*rhs_top; + tmp = invI_lower_right * rhs_bot; + vbot += tmp; + result[0] = vtop[0]; + result[1] = vtop[1]; + result[2] = vtop[2]; + result[3] = vbot[0]; + result[4] = vbot[1]; + result[5] = vbot[2]; + } + + } +} +void btMultiBody::solveImatrix(const btSpatialForceVector &rhs, btSpatialMotionVector &result) const +{ + int num_links = getNumLinks(); + ///solve I * x = rhs, so the result = invI * rhs + if (num_links == 0) + { + // in the case of 0 m_links (i.e. a plain rigid body, not a multibody) rhs * invI is easier + result.setAngular(rhs.getAngular() / m_baseInertia); + result.setLinear(rhs.getLinear() / m_baseMass); + } else + { + /// Special routine for calculating the inverse of a spatial inertia matrix + ///the 6x6 matrix is stored as 4 blocks of 3x3 matrices + if (!m_cachedInertiaValid) + { + result.setLinear(btVector3(0,0,0)); + result.setAngular(btVector3(0,0,0)); + result.setVector(btVector3(0,0,0),btVector3(0,0,0)); + return; + } + btMatrix3x3 Binv = m_cachedInertiaTopRight.inverse()*-1.f; + btMatrix3x3 tmp = m_cachedInertiaLowerRight * Binv; + btMatrix3x3 invIupper_right = (tmp * m_cachedInertiaTopLeft + m_cachedInertiaLowerLeft).inverse(); + tmp = invIupper_right * m_cachedInertiaLowerRight; + btMatrix3x3 invI_upper_left = (tmp * Binv); + btMatrix3x3 invI_lower_right = (invI_upper_left).transpose(); + tmp = m_cachedInertiaTopLeft * invI_upper_left; + tmp[0][0]-= 1.0; + tmp[1][1]-= 1.0; + tmp[2][2]-= 1.0; + btMatrix3x3 invI_lower_left = (Binv * tmp); + + //multiply result = invI * rhs + { + btVector3 vtop = invI_upper_left*rhs.getLinear(); + btVector3 tmp; + tmp = invIupper_right * rhs.getAngular(); + vtop += tmp; + btVector3 vbot = invI_lower_left*rhs.getLinear(); + tmp = invI_lower_right * rhs.getAngular(); + vbot += tmp; + result.setVector(vtop, vbot); + } + + } +} + +void btMultiBody::mulMatrix(btScalar *pA, btScalar *pB, int rowsA, int colsA, int rowsB, int colsB, btScalar *pC) const +{ + for (int row = 0; row < rowsA; row++) + { + for (int col = 0; col < colsB; col++) + { + pC[row * colsB + col] = 0.f; + for (int inner = 0; inner < rowsB; inner++) + { + pC[row * colsB + col] += pA[row * colsA + inner] * pB[col + inner * colsB]; + } + } + } +} + +void btMultiBody::calcAccelerationDeltasMultiDof(const btScalar *force, btScalar *output, + btAlignedObjectArray &scratch_r, btAlignedObjectArray &scratch_v) const +{ + // Temporary matrices/vectors -- use scratch space from caller + // so that we don't have to keep reallocating every frame + + + int num_links = getNumLinks(); + scratch_r.resize(m_dofCount); + scratch_v.resize(4*num_links + 4); + + btScalar * r_ptr = m_dofCount ? &scratch_r[0] : 0; + btVector3 * v_ptr = &scratch_v[0]; + + // zhat_i^A (scratch space) + btSpatialForceVector * zeroAccSpatFrc = (btSpatialForceVector *)v_ptr; + v_ptr += num_links * 2 + 2; + + // rot_from_parent (cached from calcAccelerations) + const btMatrix3x3 * rot_from_parent = &m_matrixBuf[0]; + + // hhat (cached), accel (scratch) + // hhat is NOT stored for the base (but ahat is) + const btSpatialForceVector * h = (btSpatialForceVector *)(m_dofCount > 0 ? &m_vectorBuf[0] : 0); + btSpatialMotionVector * spatAcc = (btSpatialMotionVector *)v_ptr; + v_ptr += num_links * 2 + 2; + + // Y_i (scratch), invD_i (cached) + const btScalar * invD = m_dofCount > 0 ? &m_realBuf[6 + m_dofCount] : 0; + btScalar * Y = r_ptr; + //////////////// + //aux variables + btScalar invD_times_Y[6]; //D^{-1} * Y [dofxdof x dofx1 = dofx1] <=> D^{-1} * u; better moved to buffers since it is recalced in calcAccelerationDeltasMultiDof; num_dof of btScalar would cover all bodies + btSpatialMotionVector result; //holds results of the SolveImatrix op; it is a spatial motion vector (accel) + btScalar Y_minus_hT_a[6]; //Y - h^{T} * a; it's dofx1 for each body so a single 6x1 temp is enough + btSpatialForceVector spatForceVecTemps[6]; //6 temporary spatial force vectors + btSpatialTransformationMatrix fromParent; + ///////////////// + + // First 'upward' loop. + // Combines CompTreeLinkVelocities and InitTreeLinks from Mirtich. + + // Fill in zero_acc + // -- set to force/torque on the base, zero otherwise + if (m_fixedBase) + { + zeroAccSpatFrc[0].setZero(); + } else + { + //test forces + fromParent.m_rotMat = rot_from_parent[0]; + fromParent.transformRotationOnly(btSpatialForceVector(-force[0],-force[1],-force[2], -force[3],-force[4],-force[5]), zeroAccSpatFrc[0]); + } + for (int i = 0; i < num_links; ++i) + { + zeroAccSpatFrc[i+1].setZero(); + } + + // 'Downward' loop. + // (part of TreeForwardDynamics in Mirtich.) + for (int i = num_links - 1; i >= 0; --i) + { + const int parent = m_links[i].m_parent; + fromParent.m_rotMat = rot_from_parent[i+1]; fromParent.m_trnVec = m_links[i].m_cachedRVector; + + for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) + { + Y[m_links[i].m_dofOffset + dof] = force[6 + m_links[i].m_dofOffset + dof] + - m_links[i].m_axes[dof].dot(zeroAccSpatFrc[i+1]) + ; + } + + btVector3 in_top, in_bottom, out_top, out_bottom; + const btScalar *invDi = &invD[m_links[i].m_dofOffset*m_links[i].m_dofOffset]; + + for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) + { + invD_times_Y[dof] = 0.f; + + for(int dof2 = 0; dof2 < m_links[i].m_dofCount; ++dof2) + { + invD_times_Y[dof] += invDi[dof * m_links[i].m_dofCount + dof2] * Y[m_links[i].m_dofOffset + dof2]; + } + } + + // Zp += pXi * (Zi + hi*Yi/Di) + spatForceVecTemps[0] = zeroAccSpatFrc[i+1]; + + for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) + { + const btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof]; + // + spatForceVecTemps[0] += hDof * invD_times_Y[dof]; + } + + + fromParent.transformInverse(spatForceVecTemps[0], spatForceVecTemps[1]); + + zeroAccSpatFrc[parent+1] += spatForceVecTemps[1]; + } + + // ptr to the joint accel part of the output + btScalar * joint_accel = output + 6; + + + // Second 'upward' loop + // (part of TreeForwardDynamics in Mirtich) + + if (m_fixedBase) + { + spatAcc[0].setZero(); + } + else + { + solveImatrix(zeroAccSpatFrc[0], result); + spatAcc[0] = -result; + + } + + // now do the loop over the m_links + for (int i = 0; i < num_links; ++i) + { + const int parent = m_links[i].m_parent; + fromParent.m_rotMat = rot_from_parent[i+1]; fromParent.m_trnVec = m_links[i].m_cachedRVector; + + fromParent.transform(spatAcc[parent+1], spatAcc[i+1]); + + for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) + { + const btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof]; + // + Y_minus_hT_a[dof] = Y[m_links[i].m_dofOffset + dof] - spatAcc[i+1].dot(hDof); + } + + const btScalar *invDi = &invD[m_links[i].m_dofOffset*m_links[i].m_dofOffset]; + mulMatrix(const_cast(invDi), Y_minus_hT_a, m_links[i].m_dofCount, m_links[i].m_dofCount, m_links[i].m_dofCount, 1, &joint_accel[m_links[i].m_dofOffset]); + + for(int dof = 0; dof < m_links[i].m_dofCount; ++dof) + spatAcc[i+1] += m_links[i].m_axes[dof] * joint_accel[m_links[i].m_dofOffset + dof]; + } + + // transform base accelerations back to the world frame. + btVector3 omegadot_out; + omegadot_out = rot_from_parent[0].transpose() * spatAcc[0].getAngular(); + output[0] = omegadot_out[0]; + output[1] = omegadot_out[1]; + output[2] = omegadot_out[2]; + + btVector3 vdot_out; + vdot_out = rot_from_parent[0].transpose() * spatAcc[0].getLinear(); + output[3] = vdot_out[0]; + output[4] = vdot_out[1]; + output[5] = vdot_out[2]; + + ///////////////// + //printf("delta = ["); + //for(int dof = 0; dof < getNumDofs() + 6; ++dof) + // printf("%.2f ", output[dof]); + //printf("]\n"); + ///////////////// +} + + + + +void btMultiBody::stepPositionsMultiDof(btScalar dt, btScalar *pq, btScalar *pqd) +{ + int num_links = getNumLinks(); + // step position by adding dt * velocity + //btVector3 v = getBaseVel(); + //m_basePos += dt * v; + // + btScalar *pBasePos = (pq ? &pq[4] : m_basePos); + btScalar *pBaseVel = (pqd ? &pqd[3] : &m_realBuf[3]); //note: the !pqd case assumes m_realBuf holds with base velocity at 3,4,5 (should be wrapped for safety) + // + pBasePos[0] += dt * pBaseVel[0]; + pBasePos[1] += dt * pBaseVel[1]; + pBasePos[2] += dt * pBaseVel[2]; + + /////////////////////////////// + //local functor for quaternion integration (to avoid error prone redundancy) + struct + { + //"exponential map" based on btTransformUtil::integrateTransform(..) + void operator() (const btVector3 &omega, btQuaternion &quat, bool baseBody, btScalar dt) + { + //baseBody => quat is alias and omega is global coor + //!baseBody => quat is alibi and omega is local coor + + btVector3 axis; + btVector3 angvel; + + if(!baseBody) + angvel = quatRotate(quat, omega); //if quat is not m_baseQuat, it is alibi => ok + else + angvel = omega; + + btScalar fAngle = angvel.length(); + //limit the angular motion + if (fAngle * dt > ANGULAR_MOTION_THRESHOLD) + { + fAngle = btScalar(0.5)*SIMD_HALF_PI / dt; + } + + if ( fAngle < btScalar(0.001) ) + { + // use Taylor's expansions of sync function + axis = angvel*( btScalar(0.5)*dt-(dt*dt*dt)*(btScalar(0.020833333333))*fAngle*fAngle ); + } + else + { + // sync(fAngle) = sin(c*fAngle)/t + axis = angvel*( btSin(btScalar(0.5)*fAngle*dt)/fAngle ); + } + + if(!baseBody) + quat = btQuaternion(axis.x(),axis.y(),axis.z(),btCos( fAngle*dt*btScalar(0.5) )) * quat; + else + quat = quat * btQuaternion(-axis.x(),-axis.y(),-axis.z(),btCos( fAngle*dt*btScalar(0.5) )); + //equivalent to: quat = (btQuaternion(axis.x(),axis.y(),axis.z(),btCos( fAngle*dt*btScalar(0.5) )) * quat.inverse()).inverse(); + + quat.normalize(); + } + } pQuatUpdateFun; + /////////////////////////////// + + //pQuatUpdateFun(getBaseOmega(), m_baseQuat, true, dt); + // + btScalar *pBaseQuat = pq ? pq : m_baseQuat; + btScalar *pBaseOmega = pqd ? pqd : &m_realBuf[0]; //note: the !pqd case assumes m_realBuf starts with base omega (should be wrapped for safety) + // + btQuaternion baseQuat; baseQuat.setValue(pBaseQuat[0], pBaseQuat[1], pBaseQuat[2], pBaseQuat[3]); + btVector3 baseOmega; baseOmega.setValue(pBaseOmega[0], pBaseOmega[1], pBaseOmega[2]); + pQuatUpdateFun(baseOmega, baseQuat, true, dt); + pBaseQuat[0] = baseQuat.x(); + pBaseQuat[1] = baseQuat.y(); + pBaseQuat[2] = baseQuat.z(); + pBaseQuat[3] = baseQuat.w(); + + + //printf("pBaseOmega = %.4f %.4f %.4f\n", pBaseOmega->x(), pBaseOmega->y(), pBaseOmega->z()); + //printf("pBaseVel = %.4f %.4f %.4f\n", pBaseVel->x(), pBaseVel->y(), pBaseVel->z()); + //printf("baseQuat = %.4f %.4f %.4f %.4f\n", pBaseQuat->x(), pBaseQuat->y(), pBaseQuat->z(), pBaseQuat->w()); + + if(pq) + pq += 7; + if(pqd) + pqd += 6; + + // Finally we can update m_jointPos for each of the m_links + for (int i = 0; i < num_links; ++i) + { + btScalar *pJointPos = (pq ? pq : &m_links[i].m_jointPos[0]); + btScalar *pJointVel = (pqd ? pqd : getJointVelMultiDof(i)); + + switch(m_links[i].m_jointType) + { + case btMultibodyLink::ePrismatic: + case btMultibodyLink::eRevolute: + { + btScalar jointVel = pJointVel[0]; + pJointPos[0] += dt * jointVel; + break; + } + case btMultibodyLink::eSpherical: + { + btVector3 jointVel; jointVel.setValue(pJointVel[0], pJointVel[1], pJointVel[2]); + btQuaternion jointOri; jointOri.setValue(pJointPos[0], pJointPos[1], pJointPos[2], pJointPos[3]); + pQuatUpdateFun(jointVel, jointOri, false, dt); + pJointPos[0] = jointOri.x(); pJointPos[1] = jointOri.y(); pJointPos[2] = jointOri.z(); pJointPos[3] = jointOri.w(); + break; + } + case btMultibodyLink::ePlanar: + { + pJointPos[0] += dt * getJointVelMultiDof(i)[0]; + + btVector3 q0_coors_qd1qd2 = getJointVelMultiDof(i)[1] * m_links[i].getAxisBottom(1) + getJointVelMultiDof(i)[2] * m_links[i].getAxisBottom(2); + btVector3 no_q0_coors_qd1qd2 = quatRotate(btQuaternion(m_links[i].getAxisTop(0), pJointPos[0]), q0_coors_qd1qd2); + pJointPos[1] += m_links[i].getAxisBottom(1).dot(no_q0_coors_qd1qd2) * dt; + pJointPos[2] += m_links[i].getAxisBottom(2).dot(no_q0_coors_qd1qd2) * dt; + + break; + } + default: + { + } + + } + + m_links[i].updateCacheMultiDof(pq); + + if(pq) + pq += m_links[i].m_posVarCount; + if(pqd) + pqd += m_links[i].m_dofCount; + } +} + +void btMultiBody::fillConstraintJacobianMultiDof(int link, + const btVector3 &contact_point, + const btVector3 &normal_ang, + const btVector3 &normal_lin, + btScalar *jac, + btAlignedObjectArray &scratch_r, + btAlignedObjectArray &scratch_v, + btAlignedObjectArray &scratch_m) const +{ + // temporary space + int num_links = getNumLinks(); + int m_dofCount = getNumDofs(); + scratch_v.resize(3*num_links + 3); //(num_links + base) offsets + (num_links + base) normals_lin + (num_links + base) normals_ang + scratch_m.resize(num_links + 1); + + btVector3 * v_ptr = &scratch_v[0]; + btVector3 * p_minus_com_local = v_ptr; v_ptr += num_links + 1; + btVector3 * n_local_lin = v_ptr; v_ptr += num_links + 1; + btVector3 * n_local_ang = v_ptr; v_ptr += num_links + 1; + btAssert(v_ptr - &scratch_v[0] == scratch_v.size()); + + scratch_r.resize(m_dofCount); + btScalar * results = m_dofCount > 0 ? &scratch_r[0] : 0; + + btMatrix3x3 * rot_from_world = &scratch_m[0]; + + const btVector3 p_minus_com_world = contact_point - m_basePos; + const btVector3 &normal_lin_world = normal_lin; //convenience + const btVector3 &normal_ang_world = normal_ang; + + rot_from_world[0] = btMatrix3x3(m_baseQuat); + + // omega coeffients first. + btVector3 omega_coeffs_world; + omega_coeffs_world = p_minus_com_world.cross(normal_lin_world); + jac[0] = omega_coeffs_world[0] + normal_ang_world[0]; + jac[1] = omega_coeffs_world[1] + normal_ang_world[1]; + jac[2] = omega_coeffs_world[2] + normal_ang_world[2]; + // then v coefficients + jac[3] = normal_lin_world[0]; + jac[4] = normal_lin_world[1]; + jac[5] = normal_lin_world[2]; + + //create link-local versions of p_minus_com and normal + p_minus_com_local[0] = rot_from_world[0] * p_minus_com_world; + n_local_lin[0] = rot_from_world[0] * normal_lin_world; + n_local_ang[0] = rot_from_world[0] * normal_ang_world; + + // Set remaining jac values to zero for now. + for (int i = 6; i < 6 + m_dofCount; ++i) + { + jac[i] = 0; + } + + // Qdot coefficients, if necessary. + if (num_links > 0 && link > -1) { + + // TODO: speed this up -- don't calculate for m_links we don't need. + // (Also, we are making 3 separate calls to this function, for the normal & the 2 friction directions, + // which is resulting in repeated work being done...) + + // calculate required normals & positions in the local frames. + for (int i = 0; i < num_links; ++i) { + + // transform to local frame + const int parent = m_links[i].m_parent; + const btMatrix3x3 mtx(m_links[i].m_cachedRotParentToThis); + rot_from_world[i+1] = mtx * rot_from_world[parent+1]; + + n_local_lin[i+1] = mtx * n_local_lin[parent+1]; + n_local_ang[i+1] = mtx * n_local_ang[parent+1]; + p_minus_com_local[i+1] = mtx * p_minus_com_local[parent+1] - m_links[i].m_cachedRVector; + + // calculate the jacobian entry + switch(m_links[i].m_jointType) + { + case btMultibodyLink::eRevolute: + { + results[m_links[i].m_dofOffset] = n_local_lin[i+1].dot(m_links[i].getAxisTop(0).cross(p_minus_com_local[i+1]) + m_links[i].getAxisBottom(0)); + results[m_links[i].m_dofOffset] += n_local_ang[i+1].dot(m_links[i].getAxisTop(0)); + break; + } + case btMultibodyLink::ePrismatic: + { + results[m_links[i].m_dofOffset] = n_local_lin[i+1].dot(m_links[i].getAxisBottom(0)); + break; + } + case btMultibodyLink::eSpherical: + { + results[m_links[i].m_dofOffset + 0] = n_local_lin[i+1].dot(m_links[i].getAxisTop(0).cross(p_minus_com_local[i+1]) + m_links[i].getAxisBottom(0)); + results[m_links[i].m_dofOffset + 1] = n_local_lin[i+1].dot(m_links[i].getAxisTop(1).cross(p_minus_com_local[i+1]) + m_links[i].getAxisBottom(1)); + results[m_links[i].m_dofOffset + 2] = n_local_lin[i+1].dot(m_links[i].getAxisTop(2).cross(p_minus_com_local[i+1]) + m_links[i].getAxisBottom(2)); + + results[m_links[i].m_dofOffset + 0] += n_local_ang[i+1].dot(m_links[i].getAxisTop(0)); + results[m_links[i].m_dofOffset + 1] += n_local_ang[i+1].dot(m_links[i].getAxisTop(1)); + results[m_links[i].m_dofOffset + 2] += n_local_ang[i+1].dot(m_links[i].getAxisTop(2)); + + break; + } + case btMultibodyLink::ePlanar: + { + results[m_links[i].m_dofOffset + 0] = n_local_lin[i+1].dot(m_links[i].getAxisTop(0).cross(p_minus_com_local[i+1]));// + m_links[i].getAxisBottom(0)); + results[m_links[i].m_dofOffset + 1] = n_local_lin[i+1].dot(m_links[i].getAxisBottom(1)); + results[m_links[i].m_dofOffset + 2] = n_local_lin[i+1].dot(m_links[i].getAxisBottom(2)); + + break; + } + default: + { + } + } + + } + + // Now copy through to output. + //printf("jac[%d] = ", link); + while (link != -1) + { + for(int dof = 0; dof < m_links[link].m_dofCount; ++dof) + { + jac[6 + m_links[link].m_dofOffset + dof] = results[m_links[link].m_dofOffset + dof]; + //printf("%.2f\t", jac[6 + m_links[link].m_dofOffset + dof]); + } + + link = m_links[link].m_parent; + } + //printf("]\n"); + } +} + + +void btMultiBody::wakeUp() +{ + m_awake = true; +} + +void btMultiBody::goToSleep() +{ + m_awake = false; +} + +void btMultiBody::checkMotionAndSleepIfRequired(btScalar timestep) +{ + extern bool gDisableDeactivation; + if (!m_canSleep || gDisableDeactivation) + { + m_awake = true; + m_sleepTimer = 0; + return; + } + + // motion is computed as omega^2 + v^2 + (sum of squares of joint velocities) + btScalar motion = 0; + { + for (int i = 0; i < 6 + m_dofCount; ++i) + motion += m_realBuf[i] * m_realBuf[i]; + } + + + if (motion < SLEEP_EPSILON) { + m_sleepTimer += timestep; + if (m_sleepTimer > SLEEP_TIMEOUT) { + goToSleep(); + } + } else { + m_sleepTimer = 0; + if (!m_awake) + wakeUp(); + } +} + + +void btMultiBody::forwardKinematics(btAlignedObjectArray& world_to_local,btAlignedObjectArray& local_origin) +{ + + int num_links = getNumLinks(); + + // Cached 3x3 rotation matrices from parent frame to this frame. + btMatrix3x3* rot_from_parent =(btMatrix3x3 *) &m_matrixBuf[0]; + + rot_from_parent[0] = btMatrix3x3(m_baseQuat); //m_baseQuat assumed to be alias!? + + for (int i = 0; i < num_links; ++i) + { + rot_from_parent[i+1] = btMatrix3x3(m_links[i].m_cachedRotParentToThis); + } + + int nLinks = getNumLinks(); + ///base + num m_links + world_to_local.resize(nLinks+1); + local_origin.resize(nLinks+1); + + world_to_local[0] = getWorldToBaseRot(); + local_origin[0] = getBasePos(); + + for (int k=0;k& world_to_local,btAlignedObjectArray& local_origin) +{ + world_to_local.resize(getNumLinks()+1); + local_origin.resize(getNumLinks()+1); + + world_to_local[0] = getWorldToBaseRot(); + local_origin[0] = getBasePos(); + + if (getBaseCollider()) + { + btVector3 posr = local_origin[0]; + // float pos[4]={posr.x(),posr.y(),posr.z(),1}; + btScalar quat[4]={-world_to_local[0].x(),-world_to_local[0].y(),-world_to_local[0].z(),world_to_local[0].w()}; + btTransform tr; + tr.setIdentity(); + tr.setOrigin(posr); + tr.setRotation(btQuaternion(quat[0],quat[1],quat[2],quat[3])); + + getBaseCollider()->setWorldTransform(tr); + + } + + for (int k=0;km_link; + btAssert(link == m); + + int index = link+1; + + btVector3 posr = local_origin[index]; + // float pos[4]={posr.x(),posr.y(),posr.z(),1}; + btScalar quat[4]={-world_to_local[index].x(),-world_to_local[index].y(),-world_to_local[index].z(),world_to_local[index].w()}; + btTransform tr; + tr.setIdentity(); + tr.setOrigin(posr); + tr.setRotation(btQuaternion(quat[0],quat[1],quat[2],quat[3])); + + col->setWorldTransform(tr); + } + } +} + +int btMultiBody::calculateSerializeBufferSize() const +{ + int sz = sizeof(btMultiBodyData); + return sz; +} + + ///fills the dataBuffer and returns the struct name (and 0 on failure) +const char* btMultiBody::serialize(void* dataBuffer, class btSerializer* serializer) const +{ + btMultiBodyData* mbd = (btMultiBodyData*) dataBuffer; + getBaseWorldTransform().serialize(mbd->m_baseWorldTransform); + mbd->m_baseMass = this->getBaseMass(); + getBaseInertia().serialize(mbd->m_baseInertia); + { + char* name = (char*) serializer->findNameForPointer(m_baseName); + mbd->m_baseName = (char*)serializer->getUniquePointer(name); + if (mbd->m_baseName) + { + serializer->serializeName(name); + } + } + mbd->m_numLinks = this->getNumLinks(); + if (mbd->m_numLinks) + { + int sz = sizeof(btMultiBodyLinkData); + int numElem = mbd->m_numLinks; + btChunk* chunk = serializer->allocate(sz,numElem); + btMultiBodyLinkData* memPtr = (btMultiBodyLinkData*)chunk->m_oldPtr; + for (int i=0;im_jointType = getLink(i).m_jointType; + memPtr->m_dofCount = getLink(i).m_dofCount; + memPtr->m_posVarCount = getLink(i).m_posVarCount; + + getLink(i).m_inertiaLocal.serialize(memPtr->m_linkInertia); + memPtr->m_linkMass = getLink(i).m_mass; + memPtr->m_parentIndex = getLink(i).m_parent; + memPtr->m_jointDamping = getLink(i).m_jointDamping; + memPtr->m_jointFriction = getLink(i).m_jointFriction; + memPtr->m_jointLowerLimit = getLink(i).m_jointLowerLimit; + memPtr->m_jointUpperLimit = getLink(i).m_jointUpperLimit; + memPtr->m_jointMaxForce = getLink(i).m_jointMaxForce; + memPtr->m_jointMaxVelocity = getLink(i).m_jointMaxVelocity; + + getLink(i).m_eVector.serialize(memPtr->m_parentComToThisComOffset); + getLink(i).m_dVector.serialize(memPtr->m_thisPivotToThisComOffset); + getLink(i).m_zeroRotParentToThis.serialize(memPtr->m_zeroRotParentToThis); + btAssert(memPtr->m_dofCount<=3); + for (int dof = 0;dofm_jointAxisBottom[dof]); + getLink(i).getAxisTop(dof).serialize(memPtr->m_jointAxisTop[dof]); + + memPtr->m_jointTorque[dof] = getLink(i).m_jointTorque[dof]; + memPtr->m_jointVel[dof] = getJointVelMultiDof(i)[dof]; + + } + int numPosVar = getLink(i).m_posVarCount; + for (int posvar = 0; posvar < numPosVar;posvar++) + { + memPtr->m_jointPos[posvar] = getLink(i).m_jointPos[posvar]; + } + + + { + char* name = (char*) serializer->findNameForPointer(m_links[i].m_linkName); + memPtr->m_linkName = (char*)serializer->getUniquePointer(name); + if (memPtr->m_linkName) + { + serializer->serializeName(name); + } + } + { + char* name = (char*) serializer->findNameForPointer(m_links[i].m_jointName); + memPtr->m_jointName = (char*)serializer->getUniquePointer(name); + if (memPtr->m_jointName) + { + serializer->serializeName(name); + } + } + memPtr->m_linkCollider = (btCollisionObjectData*)serializer->getUniquePointer(getLink(i).m_collider); + + } + serializer->finalizeChunk(chunk,btMultiBodyLinkDataName,BT_ARRAY_CODE,(void*) &m_links[0]); + } + mbd->m_links = mbd->m_numLinks? (btMultiBodyLinkData*) serializer->getUniquePointer((void*)&m_links[0]):0; + + // Fill padding with zeros to appease msan. +#ifdef BT_USE_DOUBLE_PRECISION + memset(mbd->m_padding, 0, sizeof(mbd->m_padding)); +#endif + + return btMultiBodyDataName; +} diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.h b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBody.h similarity index 91% rename from extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.h rename to extern/bullet/src/BulletDynamics/Featherstone/btMultiBody.h index 8fbe6cda827a..ac5f0993e9cb 100644 --- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.h +++ b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBody.h @@ -1,760 +1,814 @@ -/* - * PURPOSE: - * Class representing an articulated rigid body. Stores the body's - * current state, allows forces and torques to be set, handles - * timestepping and implements Featherstone's algorithm. - * - * COPYRIGHT: - * Copyright (C) Stephen Thompson, , 2011-2013 - * Portions written By Erwin Coumans: connection to LCP solver, various multibody constraints, replacing Eigen math library by Bullet LinearMath and a dedicated 6x6 matrix inverse (solveImatrix) - * Portions written By Jakub Stepien: support for multi-DOF constraints, introduction of spatial algebra and several other improvements - - 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_MULTIBODY_H -#define BT_MULTIBODY_H - -#include "LinearMath/btScalar.h" -#include "LinearMath/btVector3.h" -#include "LinearMath/btQuaternion.h" -#include "LinearMath/btMatrix3x3.h" -#include "LinearMath/btAlignedObjectArray.h" - - -///serialization data, don't change them if you are not familiar with the details of the serialization mechanisms -#ifdef BT_USE_DOUBLE_PRECISION - #define btMultiBodyData btMultiBodyDoubleData - #define btMultiBodyDataName "btMultiBodyDoubleData" - #define btMultiBodyLinkData btMultiBodyLinkDoubleData - #define btMultiBodyLinkDataName "btMultiBodyLinkDoubleData" -#else - #define btMultiBodyData btMultiBodyFloatData - #define btMultiBodyDataName "btMultiBodyFloatData" - #define btMultiBodyLinkData btMultiBodyLinkFloatData - #define btMultiBodyLinkDataName "btMultiBodyLinkFloatData" -#endif //BT_USE_DOUBLE_PRECISION - -#include "btMultiBodyLink.h" -class btMultiBodyLinkCollider; - -ATTRIBUTE_ALIGNED16(class) btMultiBody -{ -public: - - - BT_DECLARE_ALIGNED_ALLOCATOR(); - - // - // initialization - // - - btMultiBody(int n_links, // NOT including the base - btScalar mass, // mass of base - const btVector3 &inertia, // inertia of base, in base frame; assumed diagonal - bool fixedBase, // whether the base is fixed (true) or can move (false) - bool canSleep, bool deprecatedMultiDof=true); - - - virtual ~btMultiBody(); - - //note: fixed link collision with parent is always disabled - void setupFixed(int linkIndex, - btScalar mass, - const btVector3 &inertia, - int parent, - const btQuaternion &rotParentToThis, - const btVector3 &parentComToThisPivotOffset, - const btVector3 &thisPivotToThisComOffset, bool deprecatedDisableParentCollision=true); - - - void setupPrismatic(int i, - btScalar mass, - const btVector3 &inertia, - int parent, - const btQuaternion &rotParentToThis, - const btVector3 &jointAxis, - const btVector3 &parentComToThisPivotOffset, - const btVector3 &thisPivotToThisComOffset, - bool disableParentCollision); - - void setupRevolute(int linkIndex, // 0 to num_links-1 - btScalar mass, - const btVector3 &inertia, - int parentIndex, - const btQuaternion &rotParentToThis, // rotate points in parent frame to this frame, when q = 0 - const btVector3 &jointAxis, // in my frame - const btVector3 &parentComToThisPivotOffset, // vector from parent COM to joint axis, in PARENT frame - const btVector3 &thisPivotToThisComOffset, // vector from joint axis to my COM, in MY frame - bool disableParentCollision=false); - - void setupSpherical(int linkIndex, // 0 to num_links-1 - btScalar mass, - const btVector3 &inertia, - int parent, - const btQuaternion &rotParentToThis, // rotate points in parent frame to this frame, when q = 0 - const btVector3 &parentComToThisPivotOffset, // vector from parent COM to joint axis, in PARENT frame - const btVector3 &thisPivotToThisComOffset, // vector from joint axis to my COM, in MY frame - bool disableParentCollision=false); - - void setupPlanar(int i, // 0 to num_links-1 - btScalar mass, - const btVector3 &inertia, - int parent, - const btQuaternion &rotParentToThis, // rotate points in parent frame to this frame, when q = 0 - const btVector3 &rotationAxis, - const btVector3 &parentComToThisComOffset, // vector from parent COM to this COM, in PARENT frame - bool disableParentCollision=false); - - const btMultibodyLink& getLink(int index) const - { - return m_links[index]; - } - - btMultibodyLink& getLink(int index) - { - return m_links[index]; - } - - - void setBaseCollider(btMultiBodyLinkCollider* collider)//collider can be NULL to disable collision for the base - { - m_baseCollider = collider; - } - const btMultiBodyLinkCollider* getBaseCollider() const - { - return m_baseCollider; - } - btMultiBodyLinkCollider* getBaseCollider() - { - return m_baseCollider; - } - - // - // get parent - // input: link num from 0 to num_links-1 - // output: link num from 0 to num_links-1, OR -1 to mean the base. - // - int getParent(int link_num) const; - - - // - // get number of m_links, masses, moments of inertia - // - - int getNumLinks() const { return m_links.size(); } - int getNumDofs() const { return m_dofCount; } - int getNumPosVars() const { return m_posVarCnt; } - btScalar getBaseMass() const { return m_baseMass; } - const btVector3 & getBaseInertia() const { return m_baseInertia; } - btScalar getLinkMass(int i) const; - const btVector3 & getLinkInertia(int i) const; - - - - // - // change mass (incomplete: can only change base mass and inertia at present) - // - - void setBaseMass(btScalar mass) { m_baseMass = mass; } - void setBaseInertia(const btVector3 &inertia) { m_baseInertia = inertia; } - - - // - // get/set pos/vel/rot/omega for the base link - // - - const btVector3 & getBasePos() const { return m_basePos; } // in world frame - const btVector3 getBaseVel() const - { - return btVector3(m_realBuf[3],m_realBuf[4],m_realBuf[5]); - } // in world frame - const btQuaternion & getWorldToBaseRot() const - { - return m_baseQuat; - } // rotates world vectors into base frame - btVector3 getBaseOmega() const { return btVector3(m_realBuf[0],m_realBuf[1],m_realBuf[2]); } // in world frame - - void setBasePos(const btVector3 &pos) - { - m_basePos = pos; - } - - void setBaseWorldTransform(const btTransform& tr) - { - setBasePos(tr.getOrigin()); - setWorldToBaseRot(tr.getRotation().inverse()); - - } - - btTransform getBaseWorldTransform() const - { - btTransform tr; - tr.setOrigin(getBasePos()); - tr.setRotation(getWorldToBaseRot().inverse()); - return tr; - } - - void setBaseVel(const btVector3 &vel) - { - - m_realBuf[3]=vel[0]; m_realBuf[4]=vel[1]; m_realBuf[5]=vel[2]; - } - void setWorldToBaseRot(const btQuaternion &rot) - { - m_baseQuat = rot; //m_baseQuat asumed to ba alias!? - } - void setBaseOmega(const btVector3 &omega) - { - m_realBuf[0]=omega[0]; - m_realBuf[1]=omega[1]; - m_realBuf[2]=omega[2]; - } - - - // - // get/set pos/vel for child m_links (i = 0 to num_links-1) - // - - btScalar getJointPos(int i) const; - btScalar getJointVel(int i) const; - - btScalar * getJointVelMultiDof(int i); - btScalar * getJointPosMultiDof(int i); - - const btScalar * getJointVelMultiDof(int i) const ; - const btScalar * getJointPosMultiDof(int i) const ; - - void setJointPos(int i, btScalar q); - void setJointVel(int i, btScalar qdot); - void setJointPosMultiDof(int i, btScalar *q); - void setJointVelMultiDof(int i, btScalar *qdot); - - - - // - // direct access to velocities as a vector of 6 + num_links elements. - // (omega first, then v, then joint velocities.) - // - const btScalar * getVelocityVector() const - { - return &m_realBuf[0]; - } -/* btScalar * getVelocityVector() - { - return &real_buf[0]; - } - */ - - // - // get the frames of reference (positions and orientations) of the child m_links - // (i = 0 to num_links-1) - // - - const btVector3 & getRVector(int i) const; // vector from COM(parent(i)) to COM(i), in frame i's coords - const btQuaternion & getParentToLocalRot(int i) const; // rotates vectors in frame parent(i) to vectors in frame i. - - - // - // transform vectors in local frame of link i to world frame (or vice versa) - // - btVector3 localPosToWorld(int i, const btVector3 &vec) const; - btVector3 localDirToWorld(int i, const btVector3 &vec) const; - btVector3 worldPosToLocal(int i, const btVector3 &vec) const; - btVector3 worldDirToLocal(int i, const btVector3 &vec) const; - - - // - // calculate kinetic energy and angular momentum - // useful for debugging. - // - - btScalar getKineticEnergy() const; - btVector3 getAngularMomentum() const; - - - // - // set external forces and torques. Note all external forces/torques are given in the WORLD frame. - // - - void clearForcesAndTorques(); - void clearConstraintForces(); - - void clearVelocities(); - - void addBaseForce(const btVector3 &f) - { - m_baseForce += f; - } - void addBaseTorque(const btVector3 &t) { m_baseTorque += t; } - void addLinkForce(int i, const btVector3 &f); - void addLinkTorque(int i, const btVector3 &t); - - void addBaseConstraintForce(const btVector3 &f) - { - m_baseConstraintForce += f; - } - void addBaseConstraintTorque(const btVector3 &t) { m_baseConstraintTorque += t; } - void addLinkConstraintForce(int i, const btVector3 &f); - void addLinkConstraintTorque(int i, const btVector3 &t); - - -void addJointTorque(int i, btScalar Q); - void addJointTorqueMultiDof(int i, int dof, btScalar Q); - void addJointTorqueMultiDof(int i, const btScalar *Q); - - const btVector3 & getBaseForce() const { return m_baseForce; } - const btVector3 & getBaseTorque() const { return m_baseTorque; } - const btVector3 & getLinkForce(int i) const; - const btVector3 & getLinkTorque(int i) const; - btScalar getJointTorque(int i) const; - btScalar * getJointTorqueMultiDof(int i); - - - // - // dynamics routines. - // - - // timestep the velocities (given the external forces/torques set using addBaseForce etc). - // also sets up caches for calcAccelerationDeltas. - // - // Note: the caller must provide three vectors which are used as - // temporary scratch space. The idea here is to reduce dynamic - // memory allocation: the same scratch vectors can be re-used - // again and again for different Multibodies, instead of each - // btMultiBody allocating (and then deallocating) their own - // individual scratch buffers. This gives a considerable speed - // improvement, at least on Windows (where dynamic memory - // allocation appears to be fairly slow). - // - - - void computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar dt, - btAlignedObjectArray &scratch_r, - btAlignedObjectArray &scratch_v, - btAlignedObjectArray &scratch_m, - bool isConstraintPass=false - ); - -///stepVelocitiesMultiDof is deprecated, use computeAccelerationsArticulatedBodyAlgorithmMultiDof instead - void stepVelocitiesMultiDof(btScalar dt, - btAlignedObjectArray &scratch_r, - btAlignedObjectArray &scratch_v, - btAlignedObjectArray &scratch_m, - bool isConstraintPass=false) - { - computeAccelerationsArticulatedBodyAlgorithmMultiDof(dt,scratch_r,scratch_v,scratch_m,isConstraintPass); - } - - // calcAccelerationDeltasMultiDof - // input: force vector (in same format as jacobian, i.e.: - // 3 torque values, 3 force values, num_links joint torque values) - // output: 3 omegadot values, 3 vdot values, num_links q_double_dot values - // (existing contents of output array are replaced) - // calcAccelerationDeltasMultiDof must have been called first. - void calcAccelerationDeltasMultiDof(const btScalar *force, btScalar *output, - btAlignedObjectArray &scratch_r, - btAlignedObjectArray &scratch_v) const; - - - void applyDeltaVeeMultiDof2(const btScalar * delta_vee, btScalar multiplier) - { - for (int dof = 0; dof < 6 + getNumDofs(); ++dof) - { - m_deltaV[dof] += delta_vee[dof] * multiplier; - } - } - void processDeltaVeeMultiDof2() - { - applyDeltaVeeMultiDof(&m_deltaV[0],1); - - for (int dof = 0; dof < 6 + getNumDofs(); ++dof) - { - m_deltaV[dof] = 0.f; - } - } - - void applyDeltaVeeMultiDof(const btScalar * delta_vee, btScalar multiplier) - { - //for (int dof = 0; dof < 6 + getNumDofs(); ++dof) - // printf("%.4f ", delta_vee[dof]*multiplier); - //printf("\n"); - - //btScalar sum = 0; - //for (int dof = 0; dof < 6 + getNumDofs(); ++dof) - //{ - // sum += delta_vee[dof]*multiplier*delta_vee[dof]*multiplier; - //} - //btScalar l = btSqrt(sum); - - //if (l>m_maxAppliedImpulse) - //{ - // multiplier *= m_maxAppliedImpulse/l; - //} - - for (int dof = 0; dof < 6 + getNumDofs(); ++dof) - { - m_realBuf[dof] += delta_vee[dof] * multiplier; - btClamp(m_realBuf[dof],-m_maxCoordinateVelocity,m_maxCoordinateVelocity); - } - } - - - - // timestep the positions (given current velocities). - void stepPositionsMultiDof(btScalar dt, btScalar *pq = 0, btScalar *pqd = 0); - - - // - // contacts - // - - // This routine fills out a contact constraint jacobian for this body. - // the 'normal' supplied must be -n for body1 or +n for body2 of the contact. - // 'normal' & 'contact_point' are both given in world coordinates. - - void fillContactJacobianMultiDof(int link, - const btVector3 &contact_point, - const btVector3 &normal, - btScalar *jac, - btAlignedObjectArray &scratch_r, - btAlignedObjectArray &scratch_v, - btAlignedObjectArray &scratch_m) const { fillConstraintJacobianMultiDof(link, contact_point, btVector3(0, 0, 0), normal, jac, scratch_r, scratch_v, scratch_m); } - - //a more general version of fillContactJacobianMultiDof which does not assume.. - //.. that the constraint in question is contact or, to be more precise, constrains linear velocity only - void fillConstraintJacobianMultiDof(int link, - const btVector3 &contact_point, - const btVector3 &normal_ang, - const btVector3 &normal_lin, - btScalar *jac, - btAlignedObjectArray &scratch_r, - btAlignedObjectArray &scratch_v, - btAlignedObjectArray &scratch_m) const; - - - // - // sleeping - // - void setCanSleep(bool canSleep) - { - m_canSleep = canSleep; - } - - bool getCanSleep()const - { - return m_canSleep; - } - - bool isAwake() const { return m_awake; } - void wakeUp(); - void goToSleep(); - void checkMotionAndSleepIfRequired(btScalar timestep); - - bool hasFixedBase() const - { - return m_fixedBase; - } - - int getCompanionId() const - { - return m_companionId; - } - void setCompanionId(int id) - { - //printf("for %p setCompanionId(%d)\n",this, id); - m_companionId = id; - } - - void setNumLinks(int numLinks)//careful: when changing the number of m_links, make sure to re-initialize or update existing m_links - { - m_links.resize(numLinks); - } - - btScalar getLinearDamping() const - { - return m_linearDamping; - } - void setLinearDamping( btScalar damp) - { - m_linearDamping = damp; - } - btScalar getAngularDamping() const - { - return m_angularDamping; - } - void setAngularDamping( btScalar damp) - { - m_angularDamping = damp; - } - - bool getUseGyroTerm() const - { - return m_useGyroTerm; - } - void setUseGyroTerm(bool useGyro) - { - m_useGyroTerm = useGyro; - } - btScalar getMaxCoordinateVelocity() const - { - return m_maxCoordinateVelocity ; - } - void setMaxCoordinateVelocity(btScalar maxVel) - { - m_maxCoordinateVelocity = maxVel; - } - - btScalar getMaxAppliedImpulse() const - { - return m_maxAppliedImpulse; - } - void setMaxAppliedImpulse(btScalar maxImp) - { - m_maxAppliedImpulse = maxImp; - } - void setHasSelfCollision(bool hasSelfCollision) - { - m_hasSelfCollision = hasSelfCollision; - } - bool hasSelfCollision() const - { - return m_hasSelfCollision; - } - - - void finalizeMultiDof(); - - void useRK4Integration(bool use) { m_useRK4 = use; } - bool isUsingRK4Integration() const { return m_useRK4; } - void useGlobalVelocities(bool use) { m_useGlobalVelocities = use; } - bool isUsingGlobalVelocities() const { return m_useGlobalVelocities; } - - bool isPosUpdated() const - { - return __posUpdated; - } - void setPosUpdated(bool updated) - { - __posUpdated = updated; - } - - //internalNeedsJointFeedback is for internal use only - bool internalNeedsJointFeedback() const - { - return m_internalNeedsJointFeedback; - } - void forwardKinematics(btAlignedObjectArray& scratch_q,btAlignedObjectArray& scratch_m); - - void updateCollisionObjectWorldTransforms(btAlignedObjectArray& scratch_q,btAlignedObjectArray& scratch_m); - - virtual int calculateSerializeBufferSize() const; - - ///fills the dataBuffer and returns the struct name (and 0 on failure) - virtual const char* serialize(void* dataBuffer, class btSerializer* serializer) const; - - const char* getBaseName() const - { - return m_baseName; - } - ///memory of setBaseName needs to be manager by user - void setBaseName(const char* name) - { - m_baseName = name; - } - -private: - btMultiBody(const btMultiBody &); // not implemented - void operator=(const btMultiBody &); // not implemented - - void compTreeLinkVelocities(btVector3 *omega, btVector3 *vel) const; - - void solveImatrix(const btVector3& rhs_top, const btVector3& rhs_bot, float result[6]) const; - void solveImatrix(const btSpatialForceVector &rhs, btSpatialMotionVector &result) const; - - void updateLinksDofOffsets() - { - int dofOffset = 0, cfgOffset = 0; - for(int bidx = 0; bidx < m_links.size(); ++bidx) - { - m_links[bidx].m_dofOffset = dofOffset; m_links[bidx].m_cfgOffset = cfgOffset; - dofOffset += m_links[bidx].m_dofCount; cfgOffset += m_links[bidx].m_posVarCount; - } - } - - void mulMatrix(btScalar *pA, btScalar *pB, int rowsA, int colsA, int rowsB, int colsB, btScalar *pC) const; - - -private: - - btMultiBodyLinkCollider* m_baseCollider;//can be NULL - const char* m_baseName;//memory needs to be manager by user! - - btVector3 m_basePos; // position of COM of base (world frame) - btQuaternion m_baseQuat; // rotates world points into base frame - - btScalar m_baseMass; // mass of the base - btVector3 m_baseInertia; // inertia of the base (in local frame; diagonal) - - btVector3 m_baseForce; // external force applied to base. World frame. - btVector3 m_baseTorque; // external torque applied to base. World frame. - - btVector3 m_baseConstraintForce; // external force applied to base. World frame. - btVector3 m_baseConstraintTorque; // external torque applied to base. World frame. - - btAlignedObjectArray m_links; // array of m_links, excluding the base. index from 0 to num_links-1. - btAlignedObjectArray m_colliders; - - - // - // realBuf: - // offset size array - // 0 6 + num_links v (base_omega; base_vel; joint_vels) MULTIDOF [sysdof x sysdof for D matrices (TOO MUCH!) + pos_delta which is sys-cfg sized] - // 6+num_links num_links D - // - // vectorBuf: - // offset size array - // 0 num_links h_top - // num_links num_links h_bottom - // - // matrixBuf: - // offset size array - // 0 num_links+1 rot_from_parent - // - btAlignedObjectArray m_deltaV; - btAlignedObjectArray m_realBuf; - btAlignedObjectArray m_vectorBuf; - btAlignedObjectArray m_matrixBuf; - - - btMatrix3x3 m_cachedInertiaTopLeft; - btMatrix3x3 m_cachedInertiaTopRight; - btMatrix3x3 m_cachedInertiaLowerLeft; - btMatrix3x3 m_cachedInertiaLowerRight; - - bool m_fixedBase; - - // Sleep parameters. - bool m_awake; - bool m_canSleep; - btScalar m_sleepTimer; - - int m_companionId; - btScalar m_linearDamping; - btScalar m_angularDamping; - bool m_useGyroTerm; - btScalar m_maxAppliedImpulse; - btScalar m_maxCoordinateVelocity; - bool m_hasSelfCollision; - - bool __posUpdated; - int m_dofCount, m_posVarCnt; - bool m_useRK4, m_useGlobalVelocities; - - ///the m_needsJointFeedback gets updated/computed during the stepVelocitiesMultiDof and it for internal usage only - bool m_internalNeedsJointFeedback; -}; - -struct btMultiBodyLinkDoubleData -{ - btQuaternionDoubleData m_zeroRotParentToThis; - btVector3DoubleData m_parentComToThisComOffset; - btVector3DoubleData m_thisPivotToThisComOffset; - btVector3DoubleData m_jointAxisTop[6]; - btVector3DoubleData m_jointAxisBottom[6]; - - - char *m_linkName; - char *m_jointName; - btCollisionObjectDoubleData *m_linkCollider; - - btVector3DoubleData m_linkInertia; // inertia of the base (in local frame; diagonal) - double m_linkMass; - int m_parentIndex; - int m_jointType; - - - - - int m_dofCount; - int m_posVarCount; - double m_jointPos[7]; - double m_jointVel[6]; - double m_jointTorque[6]; - - - -}; - -struct btMultiBodyLinkFloatData -{ - btQuaternionFloatData m_zeroRotParentToThis; - btVector3FloatData m_parentComToThisComOffset; - btVector3FloatData m_thisPivotToThisComOffset; - btVector3FloatData m_jointAxisTop[6]; - btVector3FloatData m_jointAxisBottom[6]; - - - char *m_linkName; - char *m_jointName; - btCollisionObjectFloatData *m_linkCollider; - - btVector3FloatData m_linkInertia; // inertia of the base (in local frame; diagonal) - int m_dofCount; - float m_linkMass; - int m_parentIndex; - int m_jointType; - - - - float m_jointPos[7]; - float m_jointVel[6]; - float m_jointTorque[6]; - int m_posVarCount; - - -}; - -///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 -struct btMultiBodyDoubleData -{ - char *m_baseName; - btMultiBodyLinkDoubleData *m_links; - btCollisionObjectDoubleData *m_baseCollider; - - btTransformDoubleData m_baseWorldTransform; - btVector3DoubleData m_baseInertia; // inertia of the base (in local frame; diagonal) - - int m_numLinks; - double m_baseMass; - - char m_padding[4]; - -}; - -///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 -struct btMultiBodyFloatData -{ - char *m_baseName; - btMultiBodyLinkFloatData *m_links; - btCollisionObjectFloatData *m_baseCollider; - btTransformFloatData m_baseWorldTransform; - btVector3FloatData m_baseInertia; // inertia of the base (in local frame; diagonal) - - float m_baseMass; - int m_numLinks; -}; - - - -#endif +/* + * PURPOSE: + * Class representing an articulated rigid body. Stores the body's + * current state, allows forces and torques to be set, handles + * timestepping and implements Featherstone's algorithm. + * + * COPYRIGHT: + * Copyright (C) Stephen Thompson, , 2011-2013 + * Portions written By Erwin Coumans: connection to LCP solver, various multibody constraints, replacing Eigen math library by Bullet LinearMath and a dedicated 6x6 matrix inverse (solveImatrix) + * Portions written By Jakub Stepien: support for multi-DOF constraints, introduction of spatial algebra and several other improvements + + 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_MULTIBODY_H +#define BT_MULTIBODY_H + +#include "LinearMath/btScalar.h" +#include "LinearMath/btVector3.h" +#include "LinearMath/btQuaternion.h" +#include "LinearMath/btMatrix3x3.h" +#include "LinearMath/btAlignedObjectArray.h" + + +///serialization data, don't change them if you are not familiar with the details of the serialization mechanisms +#ifdef BT_USE_DOUBLE_PRECISION + #define btMultiBodyData btMultiBodyDoubleData + #define btMultiBodyDataName "btMultiBodyDoubleData" + #define btMultiBodyLinkData btMultiBodyLinkDoubleData + #define btMultiBodyLinkDataName "btMultiBodyLinkDoubleData" +#else + #define btMultiBodyData btMultiBodyFloatData + #define btMultiBodyDataName "btMultiBodyFloatData" + #define btMultiBodyLinkData btMultiBodyLinkFloatData + #define btMultiBodyLinkDataName "btMultiBodyLinkFloatData" +#endif //BT_USE_DOUBLE_PRECISION + +#include "btMultiBodyLink.h" +class btMultiBodyLinkCollider; + +ATTRIBUTE_ALIGNED16(class) btMultiBody +{ +public: + + + BT_DECLARE_ALIGNED_ALLOCATOR(); + + // + // initialization + // + + btMultiBody(int n_links, // NOT including the base + btScalar mass, // mass of base + const btVector3 &inertia, // inertia of base, in base frame; assumed diagonal + bool fixedBase, // whether the base is fixed (true) or can move (false) + bool canSleep, bool deprecatedMultiDof=true); + + + virtual ~btMultiBody(); + + //note: fixed link collision with parent is always disabled + void setupFixed(int linkIndex, + btScalar mass, + const btVector3 &inertia, + int parent, + const btQuaternion &rotParentToThis, + const btVector3 &parentComToThisPivotOffset, + const btVector3 &thisPivotToThisComOffset, bool deprecatedDisableParentCollision=true); + + + void setupPrismatic(int i, + btScalar mass, + const btVector3 &inertia, + int parent, + const btQuaternion &rotParentToThis, + const btVector3 &jointAxis, + const btVector3 &parentComToThisPivotOffset, + const btVector3 &thisPivotToThisComOffset, + bool disableParentCollision); + + void setupRevolute(int linkIndex, // 0 to num_links-1 + btScalar mass, + const btVector3 &inertia, + int parentIndex, + const btQuaternion &rotParentToThis, // rotate points in parent frame to this frame, when q = 0 + const btVector3 &jointAxis, // in my frame + const btVector3 &parentComToThisPivotOffset, // vector from parent COM to joint axis, in PARENT frame + const btVector3 &thisPivotToThisComOffset, // vector from joint axis to my COM, in MY frame + bool disableParentCollision=false); + + void setupSpherical(int linkIndex, // 0 to num_links-1 + btScalar mass, + const btVector3 &inertia, + int parent, + const btQuaternion &rotParentToThis, // rotate points in parent frame to this frame, when q = 0 + const btVector3 &parentComToThisPivotOffset, // vector from parent COM to joint axis, in PARENT frame + const btVector3 &thisPivotToThisComOffset, // vector from joint axis to my COM, in MY frame + bool disableParentCollision=false); + + void setupPlanar(int i, // 0 to num_links-1 + btScalar mass, + const btVector3 &inertia, + int parent, + const btQuaternion &rotParentToThis, // rotate points in parent frame to this frame, when q = 0 + const btVector3 &rotationAxis, + const btVector3 &parentComToThisComOffset, // vector from parent COM to this COM, in PARENT frame + bool disableParentCollision=false); + + const btMultibodyLink& getLink(int index) const + { + return m_links[index]; + } + + btMultibodyLink& getLink(int index) + { + return m_links[index]; + } + + + void setBaseCollider(btMultiBodyLinkCollider* collider)//collider can be NULL to disable collision for the base + { + m_baseCollider = collider; + } + const btMultiBodyLinkCollider* getBaseCollider() const + { + return m_baseCollider; + } + btMultiBodyLinkCollider* getBaseCollider() + { + return m_baseCollider; + } + + btMultiBodyLinkCollider* getLinkCollider(int index) + { + if (index >= 0 && index < getNumLinks()) + { + return getLink(index).m_collider; + } + return 0; + } + + // + // get parent + // input: link num from 0 to num_links-1 + // output: link num from 0 to num_links-1, OR -1 to mean the base. + // + int getParent(int link_num) const; + + + // + // get number of m_links, masses, moments of inertia + // + + int getNumLinks() const { return m_links.size(); } + int getNumDofs() const { return m_dofCount; } + int getNumPosVars() const { return m_posVarCnt; } + btScalar getBaseMass() const { return m_baseMass; } + const btVector3 & getBaseInertia() const { return m_baseInertia; } + btScalar getLinkMass(int i) const; + const btVector3 & getLinkInertia(int i) const; + + + + // + // change mass (incomplete: can only change base mass and inertia at present) + // + + void setBaseMass(btScalar mass) { m_baseMass = mass; } + void setBaseInertia(const btVector3 &inertia) { m_baseInertia = inertia; } + + + // + // get/set pos/vel/rot/omega for the base link + // + + const btVector3 & getBasePos() const { return m_basePos; } // in world frame + const btVector3 getBaseVel() const + { + return btVector3(m_realBuf[3],m_realBuf[4],m_realBuf[5]); + } // in world frame + const btQuaternion & getWorldToBaseRot() const + { + return m_baseQuat; + } // rotates world vectors into base frame + btVector3 getBaseOmega() const { return btVector3(m_realBuf[0],m_realBuf[1],m_realBuf[2]); } // in world frame + + void setBasePos(const btVector3 &pos) + { + m_basePos = pos; + } + + void setBaseWorldTransform(const btTransform& tr) + { + setBasePos(tr.getOrigin()); + setWorldToBaseRot(tr.getRotation().inverse()); + + } + + btTransform getBaseWorldTransform() const + { + btTransform tr; + tr.setOrigin(getBasePos()); + tr.setRotation(getWorldToBaseRot().inverse()); + return tr; + } + + void setBaseVel(const btVector3 &vel) + { + + m_realBuf[3]=vel[0]; m_realBuf[4]=vel[1]; m_realBuf[5]=vel[2]; + } + void setWorldToBaseRot(const btQuaternion &rot) + { + m_baseQuat = rot; //m_baseQuat asumed to ba alias!? + } + void setBaseOmega(const btVector3 &omega) + { + m_realBuf[0]=omega[0]; + m_realBuf[1]=omega[1]; + m_realBuf[2]=omega[2]; + } + + + // + // get/set pos/vel for child m_links (i = 0 to num_links-1) + // + + btScalar getJointPos(int i) const; + btScalar getJointVel(int i) const; + + btScalar * getJointVelMultiDof(int i); + btScalar * getJointPosMultiDof(int i); + + const btScalar * getJointVelMultiDof(int i) const ; + const btScalar * getJointPosMultiDof(int i) const ; + + void setJointPos(int i, btScalar q); + void setJointVel(int i, btScalar qdot); + void setJointPosMultiDof(int i, btScalar *q); + void setJointVelMultiDof(int i, btScalar *qdot); + + + + // + // direct access to velocities as a vector of 6 + num_links elements. + // (omega first, then v, then joint velocities.) + // + const btScalar * getVelocityVector() const + { + return &m_realBuf[0]; + } +/* btScalar * getVelocityVector() + { + return &real_buf[0]; + } + */ + + // + // get the frames of reference (positions and orientations) of the child m_links + // (i = 0 to num_links-1) + // + + const btVector3 & getRVector(int i) const; // vector from COM(parent(i)) to COM(i), in frame i's coords + const btQuaternion & getParentToLocalRot(int i) const; // rotates vectors in frame parent(i) to vectors in frame i. + + + // + // transform vectors in local frame of link i to world frame (or vice versa) + // + btVector3 localPosToWorld(int i, const btVector3 &vec) const; + btVector3 localDirToWorld(int i, const btVector3 &vec) const; + btVector3 worldPosToLocal(int i, const btVector3 &vec) const; + btVector3 worldDirToLocal(int i, const btVector3 &vec) const; + + // + // transform a frame in local coordinate to a frame in world coordinate + // + btMatrix3x3 localFrameToWorld(int i, const btMatrix3x3 &mat) const; + + // + // calculate kinetic energy and angular momentum + // useful for debugging. + // + + btScalar getKineticEnergy() const; + btVector3 getAngularMomentum() const; + + + // + // set external forces and torques. Note all external forces/torques are given in the WORLD frame. + // + + void clearForcesAndTorques(); + void clearConstraintForces(); + + void clearVelocities(); + + void addBaseForce(const btVector3 &f) + { + m_baseForce += f; + } + void addBaseTorque(const btVector3 &t) { m_baseTorque += t; } + void addLinkForce(int i, const btVector3 &f); + void addLinkTorque(int i, const btVector3 &t); + + void addBaseConstraintForce(const btVector3 &f) + { + m_baseConstraintForce += f; + } + void addBaseConstraintTorque(const btVector3 &t) { m_baseConstraintTorque += t; } + void addLinkConstraintForce(int i, const btVector3 &f); + void addLinkConstraintTorque(int i, const btVector3 &t); + + +void addJointTorque(int i, btScalar Q); + void addJointTorqueMultiDof(int i, int dof, btScalar Q); + void addJointTorqueMultiDof(int i, const btScalar *Q); + + const btVector3 & getBaseForce() const { return m_baseForce; } + const btVector3 & getBaseTorque() const { return m_baseTorque; } + const btVector3 & getLinkForce(int i) const; + const btVector3 & getLinkTorque(int i) const; + btScalar getJointTorque(int i) const; + btScalar * getJointTorqueMultiDof(int i); + + + // + // dynamics routines. + // + + // timestep the velocities (given the external forces/torques set using addBaseForce etc). + // also sets up caches for calcAccelerationDeltas. + // + // Note: the caller must provide three vectors which are used as + // temporary scratch space. The idea here is to reduce dynamic + // memory allocation: the same scratch vectors can be re-used + // again and again for different Multibodies, instead of each + // btMultiBody allocating (and then deallocating) their own + // individual scratch buffers. This gives a considerable speed + // improvement, at least on Windows (where dynamic memory + // allocation appears to be fairly slow). + // + + + void computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar dt, + btAlignedObjectArray &scratch_r, + btAlignedObjectArray &scratch_v, + btAlignedObjectArray &scratch_m, + bool isConstraintPass=false + ); + +///stepVelocitiesMultiDof is deprecated, use computeAccelerationsArticulatedBodyAlgorithmMultiDof instead + void stepVelocitiesMultiDof(btScalar dt, + btAlignedObjectArray &scratch_r, + btAlignedObjectArray &scratch_v, + btAlignedObjectArray &scratch_m, + bool isConstraintPass=false) + { + computeAccelerationsArticulatedBodyAlgorithmMultiDof(dt,scratch_r,scratch_v,scratch_m,isConstraintPass); + } + + // calcAccelerationDeltasMultiDof + // input: force vector (in same format as jacobian, i.e.: + // 3 torque values, 3 force values, num_links joint torque values) + // output: 3 omegadot values, 3 vdot values, num_links q_double_dot values + // (existing contents of output array are replaced) + // calcAccelerationDeltasMultiDof must have been called first. + void calcAccelerationDeltasMultiDof(const btScalar *force, btScalar *output, + btAlignedObjectArray &scratch_r, + btAlignedObjectArray &scratch_v) const; + + + void applyDeltaVeeMultiDof2(const btScalar * delta_vee, btScalar multiplier) + { + for (int dof = 0; dof < 6 + getNumDofs(); ++dof) + { + m_deltaV[dof] += delta_vee[dof] * multiplier; + } + } + void processDeltaVeeMultiDof2() + { + applyDeltaVeeMultiDof(&m_deltaV[0],1); + + for (int dof = 0; dof < 6 + getNumDofs(); ++dof) + { + m_deltaV[dof] = 0.f; + } + } + + void applyDeltaVeeMultiDof(const btScalar * delta_vee, btScalar multiplier) + { + //for (int dof = 0; dof < 6 + getNumDofs(); ++dof) + // printf("%.4f ", delta_vee[dof]*multiplier); + //printf("\n"); + + //btScalar sum = 0; + //for (int dof = 0; dof < 6 + getNumDofs(); ++dof) + //{ + // sum += delta_vee[dof]*multiplier*delta_vee[dof]*multiplier; + //} + //btScalar l = btSqrt(sum); + + //if (l>m_maxAppliedImpulse) + //{ + // multiplier *= m_maxAppliedImpulse/l; + //} + + for (int dof = 0; dof < 6 + getNumDofs(); ++dof) + { + m_realBuf[dof] += delta_vee[dof] * multiplier; + btClamp(m_realBuf[dof],-m_maxCoordinateVelocity,m_maxCoordinateVelocity); + } + } + + + + // timestep the positions (given current velocities). + void stepPositionsMultiDof(btScalar dt, btScalar *pq = 0, btScalar *pqd = 0); + + + // + // contacts + // + + // This routine fills out a contact constraint jacobian for this body. + // the 'normal' supplied must be -n for body1 or +n for body2 of the contact. + // 'normal' & 'contact_point' are both given in world coordinates. + + void fillContactJacobianMultiDof(int link, + const btVector3 &contact_point, + const btVector3 &normal, + btScalar *jac, + btAlignedObjectArray &scratch_r, + btAlignedObjectArray &scratch_v, + btAlignedObjectArray &scratch_m) const { fillConstraintJacobianMultiDof(link, contact_point, btVector3(0, 0, 0), normal, jac, scratch_r, scratch_v, scratch_m); } + + //a more general version of fillContactJacobianMultiDof which does not assume.. + //.. that the constraint in question is contact or, to be more precise, constrains linear velocity only + void fillConstraintJacobianMultiDof(int link, + const btVector3 &contact_point, + const btVector3 &normal_ang, + const btVector3 &normal_lin, + btScalar *jac, + btAlignedObjectArray &scratch_r, + btAlignedObjectArray &scratch_v, + btAlignedObjectArray &scratch_m) const; + + + // + // sleeping + // + void setCanSleep(bool canSleep) + { + m_canSleep = canSleep; + } + + bool getCanSleep()const + { + return m_canSleep; + } + + bool isAwake() const { return m_awake; } + void wakeUp(); + void goToSleep(); + void checkMotionAndSleepIfRequired(btScalar timestep); + + bool hasFixedBase() const + { + return m_fixedBase; + } + + int getCompanionId() const + { + return m_companionId; + } + void setCompanionId(int id) + { + //printf("for %p setCompanionId(%d)\n",this, id); + m_companionId = id; + } + + void setNumLinks(int numLinks)//careful: when changing the number of m_links, make sure to re-initialize or update existing m_links + { + m_links.resize(numLinks); + } + + btScalar getLinearDamping() const + { + return m_linearDamping; + } + void setLinearDamping( btScalar damp) + { + m_linearDamping = damp; + } + btScalar getAngularDamping() const + { + return m_angularDamping; + } + void setAngularDamping( btScalar damp) + { + m_angularDamping = damp; + } + + bool getUseGyroTerm() const + { + return m_useGyroTerm; + } + void setUseGyroTerm(bool useGyro) + { + m_useGyroTerm = useGyro; + } + btScalar getMaxCoordinateVelocity() const + { + return m_maxCoordinateVelocity ; + } + void setMaxCoordinateVelocity(btScalar maxVel) + { + m_maxCoordinateVelocity = maxVel; + } + + btScalar getMaxAppliedImpulse() const + { + return m_maxAppliedImpulse; + } + void setMaxAppliedImpulse(btScalar maxImp) + { + m_maxAppliedImpulse = maxImp; + } + void setHasSelfCollision(bool hasSelfCollision) + { + m_hasSelfCollision = hasSelfCollision; + } + bool hasSelfCollision() const + { + return m_hasSelfCollision; + } + + + void finalizeMultiDof(); + + void useRK4Integration(bool use) { m_useRK4 = use; } + bool isUsingRK4Integration() const { return m_useRK4; } + void useGlobalVelocities(bool use) { m_useGlobalVelocities = use; } + bool isUsingGlobalVelocities() const { return m_useGlobalVelocities; } + + bool isPosUpdated() const + { + return __posUpdated; + } + void setPosUpdated(bool updated) + { + __posUpdated = updated; + } + + //internalNeedsJointFeedback is for internal use only + bool internalNeedsJointFeedback() const + { + return m_internalNeedsJointFeedback; + } + void forwardKinematics(btAlignedObjectArray& scratch_q,btAlignedObjectArray& scratch_m); + + void compTreeLinkVelocities(btVector3 *omega, btVector3 *vel) const; + + void updateCollisionObjectWorldTransforms(btAlignedObjectArray& scratch_q,btAlignedObjectArray& scratch_m); + + virtual int calculateSerializeBufferSize() const; + + ///fills the dataBuffer and returns the struct name (and 0 on failure) + virtual const char* serialize(void* dataBuffer, class btSerializer* serializer) const; + + const char* getBaseName() const + { + return m_baseName; + } + ///memory of setBaseName needs to be manager by user + void setBaseName(const char* name) + { + m_baseName = name; + } + + ///users can point to their objects, userPointer is not used by Bullet + void* getUserPointer() const + { + return m_userObjectPointer; + } + + int getUserIndex() const + { + return m_userIndex; + } + + int getUserIndex2() const + { + return m_userIndex2; + } + ///users can point to their objects, userPointer is not used by Bullet + void setUserPointer(void* userPointer) + { + m_userObjectPointer = userPointer; + } + + ///users can point to their objects, userPointer is not used by Bullet + void setUserIndex(int index) + { + m_userIndex = index; + } + + void setUserIndex2(int index) + { + m_userIndex2 = index; + } + +private: + btMultiBody(const btMultiBody &); // not implemented + void operator=(const btMultiBody &); // not implemented + + + void solveImatrix(const btVector3& rhs_top, const btVector3& rhs_bot, btScalar result[6]) const; + void solveImatrix(const btSpatialForceVector &rhs, btSpatialMotionVector &result) const; + + void updateLinksDofOffsets() + { + int dofOffset = 0, cfgOffset = 0; + for(int bidx = 0; bidx < m_links.size(); ++bidx) + { + m_links[bidx].m_dofOffset = dofOffset; m_links[bidx].m_cfgOffset = cfgOffset; + dofOffset += m_links[bidx].m_dofCount; cfgOffset += m_links[bidx].m_posVarCount; + } + } + + void mulMatrix(btScalar *pA, btScalar *pB, int rowsA, int colsA, int rowsB, int colsB, btScalar *pC) const; + + +private: + + btMultiBodyLinkCollider* m_baseCollider;//can be NULL + const char* m_baseName;//memory needs to be manager by user! + + btVector3 m_basePos; // position of COM of base (world frame) + btQuaternion m_baseQuat; // rotates world points into base frame + + btScalar m_baseMass; // mass of the base + btVector3 m_baseInertia; // inertia of the base (in local frame; diagonal) + + btVector3 m_baseForce; // external force applied to base. World frame. + btVector3 m_baseTorque; // external torque applied to base. World frame. + + btVector3 m_baseConstraintForce; // external force applied to base. World frame. + btVector3 m_baseConstraintTorque; // external torque applied to base. World frame. + + btAlignedObjectArray m_links; // array of m_links, excluding the base. index from 0 to num_links-1. + + + // + // realBuf: + // offset size array + // 0 6 + num_links v (base_omega; base_vel; joint_vels) MULTIDOF [sysdof x sysdof for D matrices (TOO MUCH!) + pos_delta which is sys-cfg sized] + // 6+num_links num_links D + // + // vectorBuf: + // offset size array + // 0 num_links h_top + // num_links num_links h_bottom + // + // matrixBuf: + // offset size array + // 0 num_links+1 rot_from_parent + // + btAlignedObjectArray m_deltaV; + btAlignedObjectArray m_realBuf; + btAlignedObjectArray m_vectorBuf; + btAlignedObjectArray m_matrixBuf; + + + btMatrix3x3 m_cachedInertiaTopLeft; + btMatrix3x3 m_cachedInertiaTopRight; + btMatrix3x3 m_cachedInertiaLowerLeft; + btMatrix3x3 m_cachedInertiaLowerRight; + bool m_cachedInertiaValid; + + bool m_fixedBase; + + // Sleep parameters. + bool m_awake; + bool m_canSleep; + btScalar m_sleepTimer; + + void* m_userObjectPointer; + int m_userIndex2; + int m_userIndex; + + int m_companionId; + btScalar m_linearDamping; + btScalar m_angularDamping; + bool m_useGyroTerm; + btScalar m_maxAppliedImpulse; + btScalar m_maxCoordinateVelocity; + bool m_hasSelfCollision; + + bool __posUpdated; + int m_dofCount, m_posVarCnt; + bool m_useRK4, m_useGlobalVelocities; + + ///the m_needsJointFeedback gets updated/computed during the stepVelocitiesMultiDof and it for internal usage only + bool m_internalNeedsJointFeedback; +}; + +struct btMultiBodyLinkDoubleData +{ + btQuaternionDoubleData m_zeroRotParentToThis; + btVector3DoubleData m_parentComToThisComOffset; + btVector3DoubleData m_thisPivotToThisComOffset; + btVector3DoubleData m_jointAxisTop[6]; + btVector3DoubleData m_jointAxisBottom[6]; + + btVector3DoubleData m_linkInertia; // inertia of the base (in local frame; diagonal) + double m_linkMass; + int m_parentIndex; + int m_jointType; + + int m_dofCount; + int m_posVarCount; + double m_jointPos[7]; + double m_jointVel[6]; + double m_jointTorque[6]; + + double m_jointDamping; + double m_jointFriction; + double m_jointLowerLimit; + double m_jointUpperLimit; + double m_jointMaxForce; + double m_jointMaxVelocity; + + char *m_linkName; + char *m_jointName; + btCollisionObjectDoubleData *m_linkCollider; + char *m_paddingPtr; + +}; + +struct btMultiBodyLinkFloatData +{ + btQuaternionFloatData m_zeroRotParentToThis; + btVector3FloatData m_parentComToThisComOffset; + btVector3FloatData m_thisPivotToThisComOffset; + btVector3FloatData m_jointAxisTop[6]; + btVector3FloatData m_jointAxisBottom[6]; + btVector3FloatData m_linkInertia; // inertia of the base (in local frame; diagonal) + int m_dofCount; + float m_linkMass; + int m_parentIndex; + int m_jointType; + + + + float m_jointPos[7]; + float m_jointVel[6]; + float m_jointTorque[6]; + int m_posVarCount; + float m_jointDamping; + float m_jointFriction; + float m_jointLowerLimit; + float m_jointUpperLimit; + float m_jointMaxForce; + float m_jointMaxVelocity; + + char *m_linkName; + char *m_jointName; + btCollisionObjectFloatData *m_linkCollider; + char *m_paddingPtr; + +}; + +///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 +struct btMultiBodyDoubleData +{ + btTransformDoubleData m_baseWorldTransform; + btVector3DoubleData m_baseInertia; // inertia of the base (in local frame; diagonal) + double m_baseMass; + + char *m_baseName; + btMultiBodyLinkDoubleData *m_links; + btCollisionObjectDoubleData *m_baseCollider; + char *m_paddingPtr; + int m_numLinks; + char m_padding[4]; +}; + +///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 +struct btMultiBodyFloatData +{ + char *m_baseName; + btMultiBodyLinkFloatData *m_links; + btCollisionObjectFloatData *m_baseCollider; + btTransformFloatData m_baseWorldTransform; + btVector3FloatData m_baseInertia; // inertia of the base (in local frame; diagonal) + + float m_baseMass; + int m_numLinks; +}; + + + +#endif diff --git a/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp new file mode 100644 index 000000000000..d52852dd8e9a --- /dev/null +++ b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp @@ -0,0 +1,417 @@ +#include "btMultiBodyConstraint.h" +#include "BulletDynamics/Dynamics/btRigidBody.h" +#include "btMultiBodyPoint2Point.h" //for testing (BTMBP2PCONSTRAINT_BLOCK_ANGULAR_MOTION_TEST macro) + + + +btMultiBodyConstraint::btMultiBodyConstraint(btMultiBody* bodyA,btMultiBody* bodyB,int linkA, int linkB, int numRows, bool isUnilateral) + :m_bodyA(bodyA), + m_bodyB(bodyB), + m_linkA(linkA), + m_linkB(linkB), + m_numRows(numRows), + m_jacSizeA(0), + m_jacSizeBoth(0), + m_isUnilateral(isUnilateral), + m_numDofsFinalized(-1), + m_maxAppliedImpulse(100) +{ + +} + +void btMultiBodyConstraint::updateJacobianSizes() +{ + if(m_bodyA) + { + m_jacSizeA = (6 + m_bodyA->getNumDofs()); + } + + if(m_bodyB) + { + m_jacSizeBoth = m_jacSizeA + 6 + m_bodyB->getNumDofs(); + } + else + m_jacSizeBoth = m_jacSizeA; +} + +void btMultiBodyConstraint::allocateJacobiansMultiDof() +{ + updateJacobianSizes(); + + m_posOffset = ((1 + m_jacSizeBoth)*m_numRows); + m_data.resize((2 + m_jacSizeBoth) * m_numRows); +} + +btMultiBodyConstraint::~btMultiBodyConstraint() +{ +} + +void btMultiBodyConstraint::applyDeltaVee(btMultiBodyJacobianData& data, btScalar* delta_vee, btScalar impulse, int velocityIndex, int ndof) +{ + for (int i = 0; i < ndof; ++i) + data.m_deltaVelocities[velocityIndex+i] += delta_vee[i] * impulse; +} + +btScalar btMultiBodyConstraint::fillMultiBodyConstraint( btMultiBodySolverConstraint& solverConstraint, + btMultiBodyJacobianData& data, + btScalar* jacOrgA, btScalar* jacOrgB, + const btVector3& constraintNormalAng, + const btVector3& constraintNormalLin, + const btVector3& posAworld, const btVector3& posBworld, + btScalar posError, + const btContactSolverInfo& infoGlobal, + btScalar lowerLimit, btScalar upperLimit, + bool angConstraint, + btScalar relaxation, + bool isFriction, btScalar desiredVelocity, btScalar cfmSlip) +{ + solverConstraint.m_multiBodyA = m_bodyA; + solverConstraint.m_multiBodyB = m_bodyB; + solverConstraint.m_linkA = m_linkA; + solverConstraint.m_linkB = m_linkB; + + btMultiBody* multiBodyA = solverConstraint.m_multiBodyA; + btMultiBody* multiBodyB = solverConstraint.m_multiBodyB; + + btSolverBody* bodyA = multiBodyA ? 0 : &data.m_solverBodyPool->at(solverConstraint.m_solverBodyIdA); + btSolverBody* bodyB = multiBodyB ? 0 : &data.m_solverBodyPool->at(solverConstraint.m_solverBodyIdB); + + btRigidBody* rb0 = multiBodyA ? 0 : bodyA->m_originalBody; + btRigidBody* rb1 = multiBodyB ? 0 : bodyB->m_originalBody; + + btVector3 rel_pos1, rel_pos2; //these two used to be inited to posAworld and posBworld (respectively) but it does not seem necessary + if (bodyA) + rel_pos1 = posAworld - bodyA->getWorldTransform().getOrigin(); + if (bodyB) + rel_pos2 = posBworld - bodyB->getWorldTransform().getOrigin(); + + if (multiBodyA) + { + if (solverConstraint.m_linkA<0) + { + rel_pos1 = posAworld - multiBodyA->getBasePos(); + } else + { + rel_pos1 = posAworld - multiBodyA->getLink(solverConstraint.m_linkA).m_cachedWorldTransform.getOrigin(); + } + + const int ndofA = multiBodyA->getNumDofs() + 6; + + solverConstraint.m_deltaVelAindex = multiBodyA->getCompanionId(); + + if (solverConstraint.m_deltaVelAindex <0) + { + solverConstraint.m_deltaVelAindex = data.m_deltaVelocities.size(); + multiBodyA->setCompanionId(solverConstraint.m_deltaVelAindex); + data.m_deltaVelocities.resize(data.m_deltaVelocities.size()+ndofA); + } else + { + btAssert(data.m_deltaVelocities.size() >= solverConstraint.m_deltaVelAindex+ndofA); + } + + //determine jacobian of this 1D constraint in terms of multibodyA's degrees of freedom + //resize.. + solverConstraint.m_jacAindex = data.m_jacobians.size(); + data.m_jacobians.resize(data.m_jacobians.size()+ndofA); + //copy/determine + if(jacOrgA) + { + for (int i=0;ifillContactJacobianMultiDof(solverConstraint.m_linkA, posAworld, constraintNormalLin, jac1, data.scratch_r, data.scratch_v, data.scratch_m); + multiBodyA->fillConstraintJacobianMultiDof(solverConstraint.m_linkA, posAworld, constraintNormalAng, constraintNormalLin, jac1, data.scratch_r, data.scratch_v, data.scratch_m); + } + + //determine the velocity response of multibodyA to reaction impulses of this constraint (i.e. A[i,i] for i=1,...n_con: multibody's inverse inertia with respect to this 1D constraint) + //resize.. + data.m_deltaVelocitiesUnitImpulse.resize(data.m_deltaVelocitiesUnitImpulse.size()+ndofA); //=> each constraint row has the constrained tree dofs allocated in m_deltaVelocitiesUnitImpulse + btAssert(data.m_jacobians.size() == data.m_deltaVelocitiesUnitImpulse.size()); + btScalar* delta = &data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex]; + //determine.. + multiBodyA->calcAccelerationDeltasMultiDof(&data.m_jacobians[solverConstraint.m_jacAindex],delta,data.scratch_r, data.scratch_v); + + btVector3 torqueAxis0; + if (angConstraint) { + torqueAxis0 = constraintNormalAng; + } + else { + torqueAxis0 = rel_pos1.cross(constraintNormalLin); + + } + solverConstraint.m_relpos1CrossNormal = torqueAxis0; + solverConstraint.m_contactNormal1 = constraintNormalLin; + } + else //if(rb0) + { + btVector3 torqueAxis0; + if (angConstraint) { + torqueAxis0 = constraintNormalAng; + } + else { + torqueAxis0 = rel_pos1.cross(constraintNormalLin); + } + solverConstraint.m_angularComponentA = rb0 ? rb0->getInvInertiaTensorWorld()*torqueAxis0*rb0->getAngularFactor() : btVector3(0,0,0); + solverConstraint.m_relpos1CrossNormal = torqueAxis0; + solverConstraint.m_contactNormal1 = constraintNormalLin; + } + + if (multiBodyB) + { + if (solverConstraint.m_linkB<0) + { + rel_pos2 = posBworld - multiBodyB->getBasePos(); + } else + { + rel_pos2 = posBworld - multiBodyB->getLink(solverConstraint.m_linkB).m_cachedWorldTransform.getOrigin(); + } + + const int ndofB = multiBodyB->getNumDofs() + 6; + + solverConstraint.m_deltaVelBindex = multiBodyB->getCompanionId(); + if (solverConstraint.m_deltaVelBindex <0) + { + solverConstraint.m_deltaVelBindex = data.m_deltaVelocities.size(); + multiBodyB->setCompanionId(solverConstraint.m_deltaVelBindex); + data.m_deltaVelocities.resize(data.m_deltaVelocities.size()+ndofB); + } + + //determine jacobian of this 1D constraint in terms of multibodyB's degrees of freedom + //resize.. + solverConstraint.m_jacBindex = data.m_jacobians.size(); + data.m_jacobians.resize(data.m_jacobians.size()+ndofB); + //copy/determine.. + if(jacOrgB) + { + for (int i=0;ifillContactJacobianMultiDof(solverConstraint.m_linkB, posBworld, -constraintNormalLin, &data.m_jacobians[solverConstraint.m_jacBindex], data.scratch_r, data.scratch_v, data.scratch_m); + multiBodyB->fillConstraintJacobianMultiDof(solverConstraint.m_linkB, posBworld, -constraintNormalAng, -constraintNormalLin, &data.m_jacobians[solverConstraint.m_jacBindex], data.scratch_r, data.scratch_v, data.scratch_m); + } + + //determine velocity response of multibodyB to reaction impulses of this constraint (i.e. A[i,i] for i=1,...n_con: multibody's inverse inertia with respect to this 1D constraint) + //resize.. + data.m_deltaVelocitiesUnitImpulse.resize(data.m_deltaVelocitiesUnitImpulse.size()+ndofB); + btAssert(data.m_jacobians.size() == data.m_deltaVelocitiesUnitImpulse.size()); + btScalar* delta = &data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex]; + //determine.. + multiBodyB->calcAccelerationDeltasMultiDof(&data.m_jacobians[solverConstraint.m_jacBindex],delta,data.scratch_r, data.scratch_v); + + btVector3 torqueAxis1; + if (angConstraint) { + torqueAxis1 = constraintNormalAng; + } + else { + torqueAxis1 = rel_pos2.cross(constraintNormalLin); + } + solverConstraint.m_relpos2CrossNormal = -torqueAxis1; + solverConstraint.m_contactNormal2 = -constraintNormalLin; + } + else //if(rb1) + { + btVector3 torqueAxis1; + if (angConstraint) { + torqueAxis1 = constraintNormalAng; + } + else { + torqueAxis1 = rel_pos2.cross(constraintNormalLin); + } + solverConstraint.m_angularComponentB = rb1 ? rb1->getInvInertiaTensorWorld()*-torqueAxis1*rb1->getAngularFactor() : btVector3(0,0,0); + solverConstraint.m_relpos2CrossNormal = -torqueAxis1; + solverConstraint.m_contactNormal2 = -constraintNormalLin; + } + { + + btVector3 vec; + btScalar denom0 = 0.f; + btScalar denom1 = 0.f; + btScalar* jacB = 0; + btScalar* jacA = 0; + btScalar* deltaVelA = 0; + btScalar* deltaVelB = 0; + int ndofA = 0; + //determine the "effective mass" of the constrained multibodyA with respect to this 1D constraint (i.e. 1/A[i,i]) + if (multiBodyA) + { + ndofA = multiBodyA->getNumDofs() + 6; + jacA = &data.m_jacobians[solverConstraint.m_jacAindex]; + deltaVelA = &data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex]; + for (int i = 0; i < ndofA; ++i) + { + btScalar j = jacA[i] ; + btScalar l = deltaVelA[i]; + denom0 += j*l; + } + } + else if(rb0) + { + vec = ( solverConstraint.m_angularComponentA).cross(rel_pos1); + if (angConstraint) { + denom0 = rb0->getInvMass() + constraintNormalAng.dot(vec); + } + else { + denom0 = rb0->getInvMass() + constraintNormalLin.dot(vec); + } + } + // + if (multiBodyB) + { + const int ndofB = multiBodyB->getNumDofs() + 6; + jacB = &data.m_jacobians[solverConstraint.m_jacBindex]; + deltaVelB = &data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex]; + for (int i = 0; i < ndofB; ++i) + { + btScalar j = jacB[i] ; + btScalar l = deltaVelB[i]; + denom1 += j*l; + } + + } + else if(rb1) + { + vec = ( -solverConstraint.m_angularComponentB).cross(rel_pos2); + if (angConstraint) { + denom1 = rb1->getInvMass() + constraintNormalAng.dot(vec); + } + else { + denom1 = rb1->getInvMass() + constraintNormalLin.dot(vec); + } + } + + // + btScalar d = denom0+denom1; + if (d>SIMD_EPSILON) + { + solverConstraint.m_jacDiagABInv = relaxation/(d); + } + else + { + //disable the constraint row to handle singularity/redundant constraint + solverConstraint.m_jacDiagABInv = 0.f; + } + } + + + //compute rhs and remaining solverConstraint fields + btScalar penetration = isFriction? 0 : posError; + + btScalar rel_vel = 0.f; + int ndofA = 0; + int ndofB = 0; + { + btVector3 vel1,vel2; + if (multiBodyA) + { + ndofA = multiBodyA->getNumDofs() + 6; + btScalar* jacA = &data.m_jacobians[solverConstraint.m_jacAindex]; + for (int i = 0; i < ndofA ; ++i) + rel_vel += multiBodyA->getVelocityVector()[i] * jacA[i]; + } + else if(rb0) + { + rel_vel += rb0->getVelocityInLocalPoint(rel_pos1).dot(solverConstraint.m_contactNormal1); + } + if (multiBodyB) + { + ndofB = multiBodyB->getNumDofs() + 6; + btScalar* jacB = &data.m_jacobians[solverConstraint.m_jacBindex]; + for (int i = 0; i < ndofB ; ++i) + rel_vel += multiBodyB->getVelocityVector()[i] * jacB[i]; + + } + else if(rb1) + { + rel_vel += rb1->getVelocityInLocalPoint(rel_pos2).dot(solverConstraint.m_contactNormal2); + } + + solverConstraint.m_friction = 0.f;//cp.m_combinedFriction; + } + + + ///warm starting (or zero if disabled) + /* + if (infoGlobal.m_solverMode & SOLVER_USE_WARMSTARTING) + { + solverConstraint.m_appliedImpulse = isFriction ? 0 : cp.m_appliedImpulse * infoGlobal.m_warmstartingFactor; + + if (solverConstraint.m_appliedImpulse) + { + if (multiBodyA) + { + btScalar impulse = solverConstraint.m_appliedImpulse; + btScalar* deltaV = &data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex]; + multiBodyA->applyDeltaVee(deltaV,impulse); + applyDeltaVee(data,deltaV,impulse,solverConstraint.m_deltaVelAindex,ndofA); + } else + { + if (rb0) + bodyA->internalApplyImpulse(solverConstraint.m_contactNormal1*bodyA->internalGetInvMass()*rb0->getLinearFactor(),solverConstraint.m_angularComponentA,solverConstraint.m_appliedImpulse); + } + if (multiBodyB) + { + btScalar impulse = solverConstraint.m_appliedImpulse; + btScalar* deltaV = &data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex]; + multiBodyB->applyDeltaVee(deltaV,impulse); + applyDeltaVee(data,deltaV,impulse,solverConstraint.m_deltaVelBindex,ndofB); + } else + { + if (rb1) + bodyB->internalApplyImpulse(-solverConstraint.m_contactNormal2*bodyB->internalGetInvMass()*rb1->getLinearFactor(),-solverConstraint.m_angularComponentB,-(btScalar)solverConstraint.m_appliedImpulse); + } + } + } else + */ + + solverConstraint.m_appliedImpulse = 0.f; + solverConstraint.m_appliedPushImpulse = 0.f; + + { + + btScalar positionalError = 0.f; + btScalar velocityError = desiredVelocity - rel_vel;// * damping; + + + btScalar erp = infoGlobal.m_erp2; + + //split impulse is not implemented yet for btMultiBody* + //if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold)) + { + erp = infoGlobal.m_erp; + } + + positionalError = -penetration * erp/infoGlobal.m_timeStep; + + btScalar penetrationImpulse = positionalError*solverConstraint.m_jacDiagABInv; + btScalar velocityImpulse = velocityError *solverConstraint.m_jacDiagABInv; + + //split impulse is not implemented yet for btMultiBody* + + // if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold)) + { + //combine position and velocity into rhs + solverConstraint.m_rhs = penetrationImpulse+velocityImpulse; + solverConstraint.m_rhsPenetration = 0.f; + + } + /*else + { + //split position and velocity into rhs and m_rhsPenetration + solverConstraint.m_rhs = velocityImpulse; + solverConstraint.m_rhsPenetration = penetrationImpulse; + } + */ + + solverConstraint.m_cfm = 0.f; + solverConstraint.m_lowerLimit = lowerLimit; + solverConstraint.m_upperLimit = upperLimit; + } + + return rel_vel; + +} diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraint.h b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyConstraint.h similarity index 84% rename from extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraint.h rename to extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyConstraint.h index 3b32b46e911f..83521b9501b5 100644 --- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraint.h +++ b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyConstraint.h @@ -39,7 +39,7 @@ struct btMultiBodyJacobianData }; -class btMultiBodyConstraint +ATTRIBUTE_ALIGNED16(class) btMultiBodyConstraint { protected: @@ -66,26 +66,36 @@ class btMultiBodyConstraint btAlignedObjectArray m_data; void applyDeltaVee(btMultiBodyJacobianData& data, btScalar* delta_vee, btScalar impulse, int velocityIndex, int ndof); - + btScalar fillMultiBodyConstraint(btMultiBodySolverConstraint& solverConstraint, btMultiBodyJacobianData& data, - btScalar* jacOrgA, btScalar* jacOrgB, - const btVector3& contactNormalOnB, + btScalar* jacOrgA, btScalar* jacOrgB, + const btVector3& constraintNormalAng, + + const btVector3& constraintNormalLin, const btVector3& posAworld, const btVector3& posBworld, btScalar posError, const btContactSolverInfo& infoGlobal, - btScalar lowerLimit, btScalar upperLimit, + btScalar lowerLimit, btScalar upperLimit, + bool angConstraint = false, + btScalar relaxation = 1.f, bool isFriction = false, btScalar desiredVelocity=0, btScalar cfmSlip=0); public: + BT_DECLARE_ALIGNED_ALLOCATOR(); + btMultiBodyConstraint(btMultiBody* bodyA,btMultiBody* bodyB,int linkA, int linkB, int numRows, bool isUnilateral); virtual ~btMultiBodyConstraint(); void updateJacobianSizes(); void allocateJacobiansMultiDof(); + //many constraints have setFrameInB/setPivotInB. Will use 'getConstraintType' later. + virtual void setFrameInB(const btMatrix3x3& frameInB) {} + virtual void setPivotInB(const btVector3& pivotInB){} + virtual void finalizeMultiDof()=0; virtual int getIslandIdA() const =0; @@ -114,6 +124,7 @@ class btMultiBodyConstraint btAssert(dof>=0); btAssert(dof < getNumRows()); m_data[dof] = appliedImpulse; + } btScalar getAppliedImpulse(int dof) @@ -172,6 +183,12 @@ class btMultiBodyConstraint virtual void debugDraw(class btIDebugDraw* drawer)=0; + virtual void setGearRatio(btScalar ratio) {} + virtual void setGearAuxLink(int gearAuxLink) {} + virtual void setRelativePositionTarget(btScalar relPosTarget){} + virtual void setErp(btScalar erp){} + + }; #endif //BT_MULTIBODY_CONSTRAINT_H diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp similarity index 67% rename from extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp rename to extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp index 4f66b20b2c1b..1e2d07409609 100644 --- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp +++ b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp @@ -26,16 +26,21 @@ subject to the following restrictions: btScalar btMultiBodyConstraintSolver::solveSingleIteration(int iteration, btCollisionObject** bodies ,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer) { - btScalar val = btSequentialImpulseConstraintSolver::solveSingleIteration(iteration, bodies ,numBodies,manifoldPtr, numManifolds,constraints,numConstraints,infoGlobal,debugDrawer); + btScalar leastSquaredResidual = btSequentialImpulseConstraintSolver::solveSingleIteration(iteration, bodies ,numBodies,manifoldPtr, numManifolds,constraints,numConstraints,infoGlobal,debugDrawer); //solve featherstone non-contact constraints //printf("m_multiBodyNonContactConstraints = %d\n",m_multiBodyNonContactConstraints.size()); + for (int j=0;jsetPosUpdated(false); if(constraint.m_multiBodyB) @@ -43,12 +48,20 @@ btScalar btMultiBodyConstraintSolver::solveSingleIteration(int iteration, btColl } //solve featherstone normal contact - for (int j=0;jsetPosUpdated(false); if(constraint.m_multiBodyB) @@ -57,18 +70,21 @@ btScalar btMultiBodyConstraintSolver::solveSingleIteration(int iteration, btColl //solve featherstone frictional contact - for (int j=0;jm_multiBodyFrictionContactConstraints.size();j++) + for (int j1=0;j1m_multiBodyFrictionContactConstraints.size();j1++) { if (iteration < infoGlobal.m_numIterations) { - btMultiBodySolverConstraint& frictionConstraint = m_multiBodyFrictionContactConstraints[j]; + int index = j1;//iteration&1? j1 : m_multiBodyFrictionContactConstraints.size()-1-j1; + + btMultiBodySolverConstraint& frictionConstraint = m_multiBodyFrictionContactConstraints[index]; btScalar totalImpulse = m_multiBodyNormalContactConstraints[frictionConstraint.m_frictionIndex].m_appliedImpulse; //adjust friction limits here if (totalImpulse>btScalar(0)) { frictionConstraint.m_lowerLimit = -(frictionConstraint.m_friction*totalImpulse); frictionConstraint.m_upperLimit = frictionConstraint.m_friction*totalImpulse; - resolveSingleConstraintRowGeneric(frictionConstraint); + btScalar residual = resolveSingleConstraintRowGeneric(frictionConstraint); + leastSquaredResidual += residual*residual; if(frictionConstraint.m_multiBodyA) frictionConstraint.m_multiBodyA->setPosUpdated(false); @@ -77,7 +93,7 @@ btScalar btMultiBodyConstraintSolver::solveSingleIteration(int iteration, btColl } } } - return val; + return leastSquaredResidual; } btScalar btMultiBodyConstraintSolver::solveGroupCacheFriendlySetup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer) @@ -109,7 +125,7 @@ void btMultiBodyConstraintSolver::applyDeltaVee(btScalar* delta_vee, btScalar im m_data.m_deltaVelocities[velocityIndex+i] += delta_vee[i] * impulse; } -void btMultiBodyConstraintSolver::resolveSingleConstraintRowGeneric(const btMultiBodySolverConstraint& c) +btScalar btMultiBodyConstraintSolver::resolveSingleConstraintRowGeneric(const btMultiBodySolverConstraint& c) { btScalar deltaImpulse = c.m_rhs-btScalar(c.m_appliedImpulse)*c.m_cfm; @@ -187,7 +203,7 @@ void btMultiBodyConstraintSolver::resolveSingleConstraintRowGeneric(const btMult { bodyB->internalApplyImpulse(c.m_contactNormal2*bodyB->internalGetInvMass(),c.m_angularComponentB,deltaImpulse); } - + return deltaImpulse; } @@ -221,10 +237,46 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol if (bodyB) rel_pos2 = pos2 - bodyB->getWorldTransform().getOrigin(); - relaxation = 1.f; - + relaxation = infoGlobal.m_sor; + + btScalar invTimeStep = btScalar(1)/infoGlobal.m_timeStep; + //cfm = 1 / ( dt * kp + kd ) + //erp = dt * kp / ( dt * kp + kd ) + + btScalar cfm; + btScalar erp; + if (isFriction) + { + cfm = infoGlobal.m_frictionCFM; + erp = infoGlobal.m_frictionERP; + } else + { + cfm = infoGlobal.m_globalCfm; + erp = infoGlobal.m_erp2; + + if ((cp.m_contactPointFlags&BT_CONTACT_FLAG_HAS_CONTACT_CFM) || (cp.m_contactPointFlags&BT_CONTACT_FLAG_HAS_CONTACT_ERP)) + { + if (cp.m_contactPointFlags&BT_CONTACT_FLAG_HAS_CONTACT_CFM) + cfm = cp.m_contactCFM; + if (cp.m_contactPointFlags&BT_CONTACT_FLAG_HAS_CONTACT_ERP) + erp = cp.m_contactERP; + } else + { + if (cp.m_contactPointFlags & BT_CONTACT_FLAG_CONTACT_STIFFNESS_DAMPING) + { + btScalar denom = ( infoGlobal.m_timeStep * cp.m_combinedContactStiffness1 + cp.m_combinedContactDamping1 ); + if (denom < SIMD_EPSILON) + { + denom = SIMD_EPSILON; + } + cfm = btScalar(1) / denom; + erp = (infoGlobal.m_timeStep * cp.m_combinedContactStiffness1) / denom; + } + } + } + cfm *= invTimeStep; if (multiBodyA) { @@ -366,7 +418,7 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol - btScalar d = denom0+denom1; + btScalar d = denom0+denom1+cfm; if (d>SIMD_EPSILON) { solverConstraint.m_jacDiagABInv = relaxation/(d); @@ -384,8 +436,19 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol btScalar restitution = 0.f; - btScalar penetration = isFriction? 0 : cp.getDistance()+infoGlobal.m_linearSlop; - + btScalar distance = 0; + if (!isFriction) + { + distance = cp.getDistance()+infoGlobal.m_linearSlop; + } else + { + if (cp.m_contactPointFlags & BT_CONTACT_FLAG_FRICTION_ANCHOR) + { + distance = (cp.getPositionWorldOnA() - cp.getPositionWorldOnB()).dot(contactNormal); + } + } + + btScalar rel_vel = 0.f; int ndofA = 0; int ndofB = 0; @@ -402,7 +465,9 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol { if (rb0) { - rel_vel += rb0->getVelocityInLocalPoint(rel_pos1).dot(solverConstraint.m_contactNormal1); + rel_vel += (rb0->getVelocityInLocalPoint(rel_pos1) + + (rb0->getTotalTorque()*rb0->getInvInertiaTensorWorld()*infoGlobal.m_timeStep).cross(rel_pos1)+ + rb0->getTotalForce()*rb0->getInvMass()*infoGlobal.m_timeStep).dot(solverConstraint.m_contactNormal1); } } if (multiBodyB) @@ -416,7 +481,9 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol { if (rb1) { - rel_vel += rb1->getVelocityInLocalPoint(rel_pos2).dot(solverConstraint.m_contactNormal2); + rel_vel += (rb1->getVelocityInLocalPoint(rel_pos2)+ + (rb1->getTotalTorque()*rb1->getInvInertiaTensorWorld()*infoGlobal.m_timeStep).cross(rel_pos2) + + rb1->getTotalForce()*rb1->getInvMass()*infoGlobal.m_timeStep).dot(solverConstraint.m_contactNormal2); } } @@ -424,7 +491,7 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol if(!isFriction) { - restitution = restitutionCurve(rel_vel, cp.m_combinedRestitution); + restitution = restitutionCurve(rel_vel, cp.m_combinedRestitution, infoGlobal.m_restitutionVelocityThreshold); if (restitution <= btScalar(0.)) { restitution = 0.f; @@ -476,21 +543,20 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol btScalar positionalError = 0.f; btScalar velocityError = restitution - rel_vel;// * damping; //note for friction restitution is always set to 0 (check above) so it is acutally velocityError = -rel_vel for friction - - btScalar erp = infoGlobal.m_erp2; - if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold)) + if (isFriction) { - erp = infoGlobal.m_erp; - } - - if (penetration>0) - { - positionalError = 0; - velocityError -= penetration / infoGlobal.m_timeStep; - + positionalError = -distance * erp/infoGlobal.m_timeStep; } else { - positionalError = -penetration * erp/infoGlobal.m_timeStep; + if (distance>0) + { + positionalError = 0; + velocityError -= distance / infoGlobal.m_timeStep; + + } else + { + positionalError = -distance * erp/infoGlobal.m_timeStep; + } } btScalar penetrationImpulse = positionalError*solverConstraint.m_jacDiagABInv; @@ -498,37 +564,309 @@ void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySol if(!isFriction) { - if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold)) + // if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold)) { //combine position and velocity into rhs solverConstraint.m_rhs = penetrationImpulse+velocityImpulse; solverConstraint.m_rhsPenetration = 0.f; - } else + } + /*else { //split position and velocity into rhs and m_rhsPenetration solverConstraint.m_rhs = velocityImpulse; solverConstraint.m_rhsPenetration = penetrationImpulse; } - + */ solverConstraint.m_lowerLimit = 0; solverConstraint.m_upperLimit = 1e10f; } else { - solverConstraint.m_rhs = velocityImpulse; + solverConstraint.m_rhs = penetrationImpulse+velocityImpulse; solverConstraint.m_rhsPenetration = 0.f; solverConstraint.m_lowerLimit = -solverConstraint.m_friction; solverConstraint.m_upperLimit = solverConstraint.m_friction; } - solverConstraint.m_cfm = 0.f; //why not use cfmSlip? - } + solverConstraint.m_cfm = cfm*solverConstraint.m_jacDiagABInv; + -} + } +} +void btMultiBodyConstraintSolver::setupMultiBodyTorsionalFrictionConstraint(btMultiBodySolverConstraint& solverConstraint, + const btVector3& constraintNormal, + btManifoldPoint& cp, + btScalar combinedTorsionalFriction, + const btContactSolverInfo& infoGlobal, + btScalar& relaxation, + bool isFriction, btScalar desiredVelocity, btScalar cfmSlip) +{ + + BT_PROFILE("setupMultiBodyRollingFrictionConstraint"); + btVector3 rel_pos1; + btVector3 rel_pos2; + + btMultiBody* multiBodyA = solverConstraint.m_multiBodyA; + btMultiBody* multiBodyB = solverConstraint.m_multiBodyB; + + const btVector3& pos1 = cp.getPositionWorldOnA(); + const btVector3& pos2 = cp.getPositionWorldOnB(); + + btSolverBody* bodyA = multiBodyA ? 0 : &m_tmpSolverBodyPool[solverConstraint.m_solverBodyIdA]; + btSolverBody* bodyB = multiBodyB ? 0 : &m_tmpSolverBodyPool[solverConstraint.m_solverBodyIdB]; + + btRigidBody* rb0 = multiBodyA ? 0 : bodyA->m_originalBody; + btRigidBody* rb1 = multiBodyB ? 0 : bodyB->m_originalBody; + + if (bodyA) + rel_pos1 = pos1 - bodyA->getWorldTransform().getOrigin(); + if (bodyB) + rel_pos2 = pos2 - bodyB->getWorldTransform().getOrigin(); + + relaxation = infoGlobal.m_sor; + + // btScalar invTimeStep = btScalar(1)/infoGlobal.m_timeStep; + + + if (multiBodyA) + { + if (solverConstraint.m_linkA<0) + { + rel_pos1 = pos1 - multiBodyA->getBasePos(); + } else + { + rel_pos1 = pos1 - multiBodyA->getLink(solverConstraint.m_linkA).m_cachedWorldTransform.getOrigin(); + } + const int ndofA = multiBodyA->getNumDofs() + 6; + + solverConstraint.m_deltaVelAindex = multiBodyA->getCompanionId(); + + if (solverConstraint.m_deltaVelAindex <0) + { + solverConstraint.m_deltaVelAindex = m_data.m_deltaVelocities.size(); + multiBodyA->setCompanionId(solverConstraint.m_deltaVelAindex); + m_data.m_deltaVelocities.resize(m_data.m_deltaVelocities.size()+ndofA); + } else + { + btAssert(m_data.m_deltaVelocities.size() >= solverConstraint.m_deltaVelAindex+ndofA); + } + + solverConstraint.m_jacAindex = m_data.m_jacobians.size(); + m_data.m_jacobians.resize(m_data.m_jacobians.size()+ndofA); + m_data.m_deltaVelocitiesUnitImpulse.resize(m_data.m_deltaVelocitiesUnitImpulse.size()+ndofA); + btAssert(m_data.m_jacobians.size() == m_data.m_deltaVelocitiesUnitImpulse.size()); + + btScalar* jac1=&m_data.m_jacobians[solverConstraint.m_jacAindex]; + multiBodyA->fillConstraintJacobianMultiDof(solverConstraint.m_linkA, cp.getPositionWorldOnA(), constraintNormal, btVector3(0,0,0), jac1, m_data.scratch_r, m_data.scratch_v, m_data.scratch_m); + btScalar* delta = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex]; + multiBodyA->calcAccelerationDeltasMultiDof(&m_data.m_jacobians[solverConstraint.m_jacAindex],delta,m_data.scratch_r, m_data.scratch_v); + + btVector3 torqueAxis0 = -constraintNormal; + solverConstraint.m_relpos1CrossNormal = torqueAxis0; + solverConstraint.m_contactNormal1 = btVector3(0,0,0); + } else + { + btVector3 torqueAxis0 = -constraintNormal; + solverConstraint.m_relpos1CrossNormal = torqueAxis0; + solverConstraint.m_contactNormal1 = btVector3(0,0,0); + solverConstraint.m_angularComponentA = rb0 ? rb0->getInvInertiaTensorWorld()*torqueAxis0*rb0->getAngularFactor() : btVector3(0,0,0); + } + + + + if (multiBodyB) + { + if (solverConstraint.m_linkB<0) + { + rel_pos2 = pos2 - multiBodyB->getBasePos(); + } else + { + rel_pos2 = pos2 - multiBodyB->getLink(solverConstraint.m_linkB).m_cachedWorldTransform.getOrigin(); + } + + const int ndofB = multiBodyB->getNumDofs() + 6; + + solverConstraint.m_deltaVelBindex = multiBodyB->getCompanionId(); + if (solverConstraint.m_deltaVelBindex <0) + { + solverConstraint.m_deltaVelBindex = m_data.m_deltaVelocities.size(); + multiBodyB->setCompanionId(solverConstraint.m_deltaVelBindex); + m_data.m_deltaVelocities.resize(m_data.m_deltaVelocities.size()+ndofB); + } + + solverConstraint.m_jacBindex = m_data.m_jacobians.size(); + + m_data.m_jacobians.resize(m_data.m_jacobians.size()+ndofB); + m_data.m_deltaVelocitiesUnitImpulse.resize(m_data.m_deltaVelocitiesUnitImpulse.size()+ndofB); + btAssert(m_data.m_jacobians.size() == m_data.m_deltaVelocitiesUnitImpulse.size()); + + multiBodyB->fillConstraintJacobianMultiDof(solverConstraint.m_linkB, cp.getPositionWorldOnB(), -constraintNormal, btVector3(0,0,0), &m_data.m_jacobians[solverConstraint.m_jacBindex], m_data.scratch_r, m_data.scratch_v, m_data.scratch_m); + multiBodyB->calcAccelerationDeltasMultiDof(&m_data.m_jacobians[solverConstraint.m_jacBindex],&m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex],m_data.scratch_r, m_data.scratch_v); + + btVector3 torqueAxis1 = constraintNormal; + solverConstraint.m_relpos2CrossNormal = torqueAxis1; + solverConstraint.m_contactNormal2 = -btVector3(0,0,0); + + } else + { + btVector3 torqueAxis1 = constraintNormal; + solverConstraint.m_relpos2CrossNormal = torqueAxis1; + solverConstraint.m_contactNormal2 = -btVector3(0,0,0); + + solverConstraint.m_angularComponentB = rb1 ? rb1->getInvInertiaTensorWorld()*torqueAxis1*rb1->getAngularFactor() : btVector3(0,0,0); + } + + { + + btScalar denom0 = 0.f; + btScalar denom1 = 0.f; + btScalar* jacB = 0; + btScalar* jacA = 0; + btScalar* lambdaA =0; + btScalar* lambdaB =0; + int ndofA = 0; + if (multiBodyA) + { + ndofA = multiBodyA->getNumDofs() + 6; + jacA = &m_data.m_jacobians[solverConstraint.m_jacAindex]; + lambdaA = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex]; + for (int i = 0; i < ndofA; ++i) + { + btScalar j = jacA[i] ; + btScalar l =lambdaA[i]; + denom0 += j*l; + } + } else + { + if (rb0) + { + btVector3 iMJaA = rb0?rb0->getInvInertiaTensorWorld()*solverConstraint.m_relpos1CrossNormal:btVector3(0,0,0); + denom0 = iMJaA.dot(solverConstraint.m_relpos1CrossNormal); + } + } + if (multiBodyB) + { + const int ndofB = multiBodyB->getNumDofs() + 6; + jacB = &m_data.m_jacobians[solverConstraint.m_jacBindex]; + lambdaB = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex]; + for (int i = 0; i < ndofB; ++i) + { + btScalar j = jacB[i] ; + btScalar l =lambdaB[i]; + denom1 += j*l; + } + + } else + { + if (rb1) + { + btVector3 iMJaB = rb1?rb1->getInvInertiaTensorWorld()*solverConstraint.m_relpos2CrossNormal:btVector3(0,0,0); + denom1 = iMJaB.dot(solverConstraint.m_relpos2CrossNormal); + } + } + + + + btScalar d = denom0+denom1+infoGlobal.m_globalCfm; + if (d>SIMD_EPSILON) + { + solverConstraint.m_jacDiagABInv = relaxation/(d); + } else + { + //disable the constraint row to handle singularity/redundant constraint + solverConstraint.m_jacDiagABInv = 0.f; + } + + } + + + //compute rhs and remaining solverConstraint fields + + + + btScalar restitution = 0.f; + btScalar penetration = isFriction? 0 : cp.getDistance(); + + btScalar rel_vel = 0.f; + int ndofA = 0; + int ndofB = 0; + { + + btVector3 vel1,vel2; + if (multiBodyA) + { + ndofA = multiBodyA->getNumDofs() + 6; + btScalar* jacA = &m_data.m_jacobians[solverConstraint.m_jacAindex]; + for (int i = 0; i < ndofA ; ++i) + rel_vel += multiBodyA->getVelocityVector()[i] * jacA[i]; + } else + { + if (rb0) + { + btSolverBody* solverBodyA = &m_tmpSolverBodyPool[solverConstraint.m_solverBodyIdA]; + rel_vel += solverConstraint.m_contactNormal1.dot(rb0?solverBodyA->m_linearVelocity+solverBodyA->m_externalForceImpulse:btVector3(0,0,0)) + + solverConstraint.m_relpos1CrossNormal.dot(rb0?solverBodyA->m_angularVelocity:btVector3(0,0,0)); + + } + } + if (multiBodyB) + { + ndofB = multiBodyB->getNumDofs() + 6; + btScalar* jacB = &m_data.m_jacobians[solverConstraint.m_jacBindex]; + for (int i = 0; i < ndofB ; ++i) + rel_vel += multiBodyB->getVelocityVector()[i] * jacB[i]; + + } else + { + if (rb1) + { + btSolverBody* solverBodyB = &m_tmpSolverBodyPool[solverConstraint.m_solverBodyIdB]; + rel_vel += solverConstraint.m_contactNormal2.dot(rb1?solverBodyB->m_linearVelocity+solverBodyB->m_externalForceImpulse:btVector3(0,0,0)) + + solverConstraint.m_relpos2CrossNormal.dot(rb1?solverBodyB->m_angularVelocity:btVector3(0,0,0)); + + } + } + + solverConstraint.m_friction =combinedTorsionalFriction; + + if(!isFriction) + { + restitution = restitutionCurve(rel_vel, cp.m_combinedRestitution, infoGlobal.m_restitutionVelocityThreshold); + if (restitution <= btScalar(0.)) + { + restitution = 0.f; + } + } + } + + + solverConstraint.m_appliedImpulse = 0.f; + solverConstraint.m_appliedPushImpulse = 0.f; + + { + + btScalar velocityError = 0 - rel_vel;// * damping; //note for friction restitution is always set to 0 (check above) so it is acutally velocityError = -rel_vel for friction + + + + btScalar velocityImpulse = velocityError*solverConstraint.m_jacDiagABInv; + + solverConstraint.m_rhs = velocityImpulse; + solverConstraint.m_rhsPenetration = 0.f; + solverConstraint.m_lowerLimit = -solverConstraint.m_friction; + solverConstraint.m_upperLimit = solverConstraint.m_friction; + + solverConstraint.m_cfm = infoGlobal.m_globalCfm*solverConstraint.m_jacDiagABInv; + + + + } + +} btMultiBodySolverConstraint& btMultiBodyConstraintSolver::addMultiBodyFrictionConstraint(const btVector3& normalAxis,btPersistentManifold* manifold,int frictionIndex,btManifoldPoint& cp,btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, const btContactSolverInfo& infoGlobal, btScalar desiredVelocity, btScalar cfmSlip) { @@ -565,6 +903,43 @@ btMultiBodySolverConstraint& btMultiBodyConstraintSolver::addMultiBodyFrictionCo return solverConstraint; } +btMultiBodySolverConstraint& btMultiBodyConstraintSolver::addMultiBodyTorsionalFrictionConstraint(const btVector3& normalAxis,btPersistentManifold* manifold,int frictionIndex,btManifoldPoint& cp, + btScalar combinedTorsionalFriction, + btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, const btContactSolverInfo& infoGlobal, btScalar desiredVelocity, btScalar cfmSlip) +{ + BT_PROFILE("addMultiBodyRollingFrictionConstraint"); + btMultiBodySolverConstraint& solverConstraint = m_multiBodyFrictionContactConstraints.expandNonInitializing(); + solverConstraint.m_orgConstraint = 0; + solverConstraint.m_orgDofIndex = -1; + + solverConstraint.m_frictionIndex = frictionIndex; + bool isFriction = true; + + const btMultiBodyLinkCollider* fcA = btMultiBodyLinkCollider::upcast(manifold->getBody0()); + const btMultiBodyLinkCollider* fcB = btMultiBodyLinkCollider::upcast(manifold->getBody1()); + + btMultiBody* mbA = fcA? fcA->m_multiBody : 0; + btMultiBody* mbB = fcB? fcB->m_multiBody : 0; + + int solverBodyIdA = mbA? -1 : getOrInitSolverBody(*colObj0,infoGlobal.m_timeStep); + int solverBodyIdB = mbB ? -1 : getOrInitSolverBody(*colObj1,infoGlobal.m_timeStep); + + solverConstraint.m_solverBodyIdA = solverBodyIdA; + solverConstraint.m_solverBodyIdB = solverBodyIdB; + solverConstraint.m_multiBodyA = mbA; + if (mbA) + solverConstraint.m_linkA = fcA->m_link; + + solverConstraint.m_multiBodyB = mbB; + if (mbB) + solverConstraint.m_linkB = fcB->m_link; + + solverConstraint.m_originalContactPoint = &cp; + + setupMultiBodyTorsionalFrictionConstraint(solverConstraint, normalAxis, cp, combinedTorsionalFriction,infoGlobal,relaxation,isFriction, desiredVelocity, cfmSlip); + return solverConstraint; +} + void btMultiBodyConstraintSolver::convertMultiBodyContact(btPersistentManifold* manifold,const btContactSolverInfo& infoGlobal) { const btMultiBodyLinkCollider* fcA = btMultiBodyLinkCollider::upcast(manifold->getBody0()); @@ -589,8 +964,9 @@ void btMultiBodyConstraintSolver::convertMultiBodyContact(btPersistentManifold* // if (!solverBodyA || (solverBodyA->m_invMass.isZero() && (!solverBodyB || solverBodyB->m_invMass.isZero()))) // return; - - + //only a single rollingFriction per manifold + int rollingFriction=1; + for (int j=0;jgetNumContacts();j++) { @@ -631,49 +1007,11 @@ void btMultiBodyConstraintSolver::convertMultiBodyContact(btPersistentManifold* #define ENABLE_FRICTION #ifdef ENABLE_FRICTION solverConstraint.m_frictionIndex = frictionIndex; -#if ROLLING_FRICTION - int rollingFriction=1; - btVector3 angVelA(0,0,0),angVelB(0,0,0); - if (rb0) - angVelA = rb0->getAngularVelocity(); - if (rb1) - angVelB = rb1->getAngularVelocity(); - btVector3 relAngVel = angVelB-angVelA; - - if ((cp.m_combinedRollingFriction>0.f) && (rollingFriction>0)) - { - //only a single rollingFriction per manifold - rollingFriction--; - if (relAngVel.length()>infoGlobal.m_singleAxisRollingFrictionThreshold) - { - relAngVel.normalize(); - applyAnisotropicFriction(colObj0,relAngVel,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); - applyAnisotropicFriction(colObj1,relAngVel,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); - if (relAngVel.length()>0.001) - addRollingFrictionConstraint(relAngVel,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); - - } else - { - addRollingFrictionConstraint(cp.m_normalWorldOnB,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); - btVector3 axis0,axis1; - btPlaneSpace1(cp.m_normalWorldOnB,axis0,axis1); - applyAnisotropicFriction(colObj0,axis0,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); - applyAnisotropicFriction(colObj1,axis0,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); - applyAnisotropicFriction(colObj0,axis1,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); - applyAnisotropicFriction(colObj1,axis1,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); - if (axis0.length()>0.001) - addRollingFrictionConstraint(axis0,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); - if (axis1.length()>0.001) - addRollingFrictionConstraint(axis1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); - - } - } -#endif //ROLLING_FRICTION ///Bullet has several options to set the friction directions - ///By default, each contact has only a single friction direction that is recomputed automatically very frame + ///By default, each contact has only a single friction direction that is recomputed automatically every frame ///based on the relative linear velocity. - ///If the relative velocity it zero, it will automatically compute a friction direction. + ///If the relative velocity is zero, it will automatically compute a friction direction. ///You can also enable two friction directions, using the SOLVER_USE_2_FRICTION_DIRECTIONS. ///In that case, the second friction direction will be orthogonal to both contact normal and first friction direction. @@ -685,7 +1023,34 @@ void btMultiBodyConstraintSolver::convertMultiBodyContact(btPersistentManifold* ///In that case, you can set the target relative motion in each friction direction (cp.m_contactMotion1 and cp.m_contactMotion2) ///this will give a conveyor belt effect /// - if (!(infoGlobal.m_solverMode & SOLVER_ENABLE_FRICTION_DIRECTION_CACHING) || !cp.m_lateralFrictionInitialized) + + btPlaneSpace1(cp.m_normalWorldOnB,cp.m_lateralFrictionDir1,cp.m_lateralFrictionDir2); + cp.m_lateralFrictionDir1.normalize(); + cp.m_lateralFrictionDir2.normalize(); + + if (rollingFriction > 0 ) + { + if (cp.m_combinedSpinningFriction>0) + { + addMultiBodyTorsionalFrictionConstraint(cp.m_normalWorldOnB,manifold,frictionIndex,cp,cp.m_combinedSpinningFriction, colObj0,colObj1, relaxation,infoGlobal); + } + if (cp.m_combinedRollingFriction>0) + { + + applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir1,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); + applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir1,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); + applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir2,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); + applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir2,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); + + if (cp.m_lateralFrictionDir1.length()>0.001) + addMultiBodyTorsionalFrictionConstraint(cp.m_lateralFrictionDir1,manifold,frictionIndex,cp,cp.m_combinedRollingFriction, colObj0,colObj1, relaxation,infoGlobal); + + if (cp.m_lateralFrictionDir2.length()>0.001) + addMultiBodyTorsionalFrictionConstraint(cp.m_lateralFrictionDir2,manifold,frictionIndex,cp,cp.m_combinedRollingFriction, colObj0,colObj1, relaxation,infoGlobal); + } + rollingFriction--; + } + if (!(infoGlobal.m_solverMode & SOLVER_ENABLE_FRICTION_DIRECTION_CACHING) || !(cp.m_contactPointFlags&BT_CONTACT_FLAG_LATERAL_FRICTION_INITIALIZED)) {/* cp.m_lateralFrictionDir1 = vel - cp.m_normalWorldOnB * rel_vel; btScalar lat_rel_vel = cp.m_lateralFrictionDir1.length2(); @@ -709,11 +1074,12 @@ void btMultiBodyConstraintSolver::convertMultiBodyContact(btPersistentManifold* } else */ { - btPlaneSpace1(cp.m_normalWorldOnB,cp.m_lateralFrictionDir1,cp.m_lateralFrictionDir2); + applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir1,btCollisionObject::CF_ANISOTROPIC_FRICTION); applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir1,btCollisionObject::CF_ANISOTROPIC_FRICTION); addMultiBodyFrictionConstraint(cp.m_lateralFrictionDir1,manifold,frictionIndex,cp,colObj0,colObj1, relaxation,infoGlobal); + if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS)) { @@ -724,16 +1090,16 @@ void btMultiBodyConstraintSolver::convertMultiBodyContact(btPersistentManifold* if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS) && (infoGlobal.m_solverMode & SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION)) { - cp.m_lateralFrictionInitialized = true; + cp.m_contactPointFlags|=BT_CONTACT_FLAG_LATERAL_FRICTION_INITIALIZED; } } } else { - addMultiBodyFrictionConstraint(cp.m_lateralFrictionDir1,manifold,frictionIndex,cp,colObj0,colObj1, relaxation,infoGlobal,cp.m_contactMotion1, cp.m_contactCFM1); + addMultiBodyFrictionConstraint(cp.m_lateralFrictionDir1,manifold,frictionIndex,cp,colObj0,colObj1, relaxation,infoGlobal,cp.m_contactMotion1, cp.m_frictionCFM); if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS)) - addMultiBodyFrictionConstraint(cp.m_lateralFrictionDir2,manifold,frictionIndex,cp,colObj0,colObj1, relaxation, infoGlobal,cp.m_contactMotion2, cp.m_contactCFM2); + addMultiBodyFrictionConstraint(cp.m_lateralFrictionDir2,manifold,frictionIndex,cp,colObj0,colObj1, relaxation, infoGlobal,cp.m_contactMotion2, cp.m_frictionCFM); //setMultiBodyFrictionConstraintImpulse( solverConstraint, solverBodyIdA, solverBodyIdB, cp, infoGlobal); //todo: @@ -809,6 +1175,7 @@ static void applyJointFeedback(btMultiBodyJacobianData& data, const btMultiBodyS } #endif + void btMultiBodyConstraintSolver::writeBackSolverBodyToMultiBody(btMultiBodySolverConstraint& c, btScalar deltaTime) { #if 1 diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h similarity index 75% rename from extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h rename to extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h index 321ee4231a34..489347d874fa 100644 --- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h +++ b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h @@ -43,12 +43,16 @@ ATTRIBUTE_ALIGNED16(class) btMultiBodyConstraintSolver : public btSequentialImpu btMultiBodyConstraint** m_tmpMultiBodyConstraints; int m_tmpNumMultiBodyConstraints; - void resolveSingleConstraintRowGeneric(const btMultiBodySolverConstraint& c); + btScalar resolveSingleConstraintRowGeneric(const btMultiBodySolverConstraint& c); void convertContacts(btPersistentManifold** manifoldPtr,int numManifolds, const btContactSolverInfo& infoGlobal); - btMultiBodySolverConstraint& addMultiBodyFrictionConstraint(const btVector3& normalAxis,btPersistentManifold* manifold,int frictionIndex,btManifoldPoint& cp,btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, const btContactSolverInfo& infoGlobal, btScalar desiredVelocity=0, btScalar cfmSlip=0); + + btMultiBodySolverConstraint& addMultiBodyFrictionConstraint(const btVector3& normalAxis,btPersistentManifold* manifold,int frictionIndex,btManifoldPoint& cp,btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, const btContactSolverInfo& infoGlobal, btScalar desiredVelocity=0, btScalar cfmSlip=0); + btMultiBodySolverConstraint& addMultiBodyTorsionalFrictionConstraint(const btVector3& normalAxis,btPersistentManifold* manifold,int frictionIndex,btManifoldPoint& cp, + btScalar combinedTorsionalFriction, + btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, const btContactSolverInfo& infoGlobal, btScalar desiredVelocity=0, btScalar cfmSlip=0); void setupMultiBodyJointLimitConstraint(btMultiBodySolverConstraint& constraintRow, btScalar* jacA,btScalar* jacB, @@ -60,6 +64,15 @@ ATTRIBUTE_ALIGNED16(class) btMultiBodyConstraintSolver : public btSequentialImpu btManifoldPoint& cp, const btContactSolverInfo& infoGlobal, btScalar& relaxation, bool isFriction, btScalar desiredVelocity=0, btScalar cfmSlip=0); + + //either rolling or spinning friction + void setupMultiBodyTorsionalFrictionConstraint(btMultiBodySolverConstraint& solverConstraint, + const btVector3& contactNormal, + btManifoldPoint& cp, + btScalar combinedTorsionalFriction, + const btContactSolverInfo& infoGlobal, + btScalar& relaxation, + bool isFriction, btScalar desiredVelocity=0, btScalar cfmSlip=0); void convertMultiBodyContact(btPersistentManifold* manifold,const btContactSolverInfo& infoGlobal); virtual btScalar solveGroupCacheFriendlySetup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer); diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp similarity index 93% rename from extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp rename to extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp index a9c0b33b3a3c..9eacc2264703 100644 --- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp +++ b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.cpp @@ -24,7 +24,7 @@ subject to the following restrictions: #include "LinearMath/btSerializer.h" -void btMultiBodyDynamicsWorld::addMultiBody(btMultiBody* body, short group, short mask) +void btMultiBodyDynamicsWorld::addMultiBody(btMultiBody* body, int group, int mask) { m_multiBodies.push_back(body); @@ -332,10 +332,10 @@ struct MultiBodyInplaceSolverIslandCallback : public btSimulationIslandManager:: } } - if (m_solverInfo->m_minimumSolverBatchSize<=1) - { - m_solver->solveGroup( bodies,numBodies,manifolds, numManifolds,startConstraint,numCurConstraints,*m_solverInfo,m_debugDrawer,m_dispatcher); - } else + //if (m_solverInfo->m_minimumSolverBatchSize<=1) + //{ + // m_solver->solveGroup( bodies,numBodies,manifolds, numManifolds,startConstraint,numCurConstraints,*m_solverInfo,m_debugDrawer,m_dispatcher); + //} else { for (i=0;i world_to_local; - btAlignedObjectArray local_origin; for (int b=0;bforwardKinematics(world_to_local,local_origin); + bod->forwardKinematics(m_scratch_world_to_local,m_scratch_local_origin); } } void btMultiBodyDynamicsWorld::solveConstraints(btContactSolverInfo& solverInfo) { forwardKinematics(); - btAlignedObjectArray scratch_r; - btAlignedObjectArray scratch_v; - btAlignedObjectArray scratch_m; BT_PROFILE("solveConstraints"); @@ -463,9 +458,9 @@ void btMultiBodyDynamicsWorld::solveConstraints(btContactSolverInfo& solverInfo) if (!isSleeping) { //useless? they get resized in stepVelocities once again (AND DIFFERENTLY) - scratch_r.resize(bod->getNumLinks()+1); //multidof? ("Y"s use it and it is used to store qdd) - scratch_v.resize(bod->getNumLinks()+1); - scratch_m.resize(bod->getNumLinks()+1); + m_scratch_r.resize(bod->getNumLinks()+1); //multidof? ("Y"s use it and it is used to store qdd) + m_scratch_v.resize(bod->getNumLinks()+1); + m_scratch_m.resize(bod->getNumLinks()+1); bod->addBaseForce(m_gravity * bod->getBaseMass()); @@ -500,15 +495,15 @@ void btMultiBodyDynamicsWorld::solveConstraints(btContactSolverInfo& solverInfo) if (!isSleeping) { //useless? they get resized in stepVelocities once again (AND DIFFERENTLY) - scratch_r.resize(bod->getNumLinks()+1); //multidof? ("Y"s use it and it is used to store qdd) - scratch_v.resize(bod->getNumLinks()+1); - scratch_m.resize(bod->getNumLinks()+1); + m_scratch_r.resize(bod->getNumLinks()+1); //multidof? ("Y"s use it and it is used to store qdd) + m_scratch_v.resize(bod->getNumLinks()+1); + m_scratch_m.resize(bod->getNumLinks()+1); bool doNotUpdatePos = false; { if(!bod->isUsingRK4Integration()) { - bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(solverInfo.m_timeStep, scratch_r, scratch_v, scratch_m); + bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(solverInfo.m_timeStep, m_scratch_r, m_scratch_v, m_scratch_m); } else { @@ -594,9 +589,9 @@ void btMultiBodyDynamicsWorld::solveConstraints(btContactSolverInfo& solverInfo) // btScalar h = solverInfo.m_timeStep; - #define output &scratch_r[bod->getNumDofs()] + #define output &m_scratch_r[bod->getNumDofs()] //calc qdd0 from: q0 & qd0 - bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(0., scratch_r, scratch_v, scratch_m); + bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(0., m_scratch_r, m_scratch_v, m_scratch_m); pCopy(output, scratch_qdd0, 0, numDofs); //calc q1 = q0 + h/2 * qd0 pResetQx(); @@ -606,7 +601,7 @@ void btMultiBodyDynamicsWorld::solveConstraints(btContactSolverInfo& solverInfo) // //calc qdd1 from: q1 & qd1 pCopyToVelocityVector(bod, scratch_qd1); - bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(0., scratch_r, scratch_v, scratch_m); + bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(0., m_scratch_r, m_scratch_v, m_scratch_m); pCopy(output, scratch_qdd1, 0, numDofs); //calc q2 = q0 + h/2 * qd1 pResetQx(); @@ -616,7 +611,7 @@ void btMultiBodyDynamicsWorld::solveConstraints(btContactSolverInfo& solverInfo) // //calc qdd2 from: q2 & qd2 pCopyToVelocityVector(bod, scratch_qd2); - bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(0., scratch_r, scratch_v, scratch_m); + bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(0., m_scratch_r, m_scratch_v, m_scratch_m); pCopy(output, scratch_qdd2, 0, numDofs); //calc q3 = q0 + h * qd2 pResetQx(); @@ -626,7 +621,7 @@ void btMultiBodyDynamicsWorld::solveConstraints(btContactSolverInfo& solverInfo) // //calc qdd3 from: q3 & qd3 pCopyToVelocityVector(bod, scratch_qd3); - bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(0., scratch_r, scratch_v, scratch_m); + bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(0., m_scratch_r, m_scratch_v, m_scratch_m); pCopy(output, scratch_qdd3, 0, numDofs); // @@ -661,7 +656,7 @@ void btMultiBodyDynamicsWorld::solveConstraints(btContactSolverInfo& solverInfo) { for(int link = 0; link < bod->getNumLinks(); ++link) bod->getLink(link).updateCacheMultiDof(); - bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(0, scratch_r, scratch_v, scratch_m); + bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(0, m_scratch_r, m_scratch_v, m_scratch_m); } } @@ -701,16 +696,16 @@ void btMultiBodyDynamicsWorld::solveConstraints(btContactSolverInfo& solverInfo) if (!isSleeping) { //useless? they get resized in stepVelocities once again (AND DIFFERENTLY) - scratch_r.resize(bod->getNumLinks()+1); //multidof? ("Y"s use it and it is used to store qdd) - scratch_v.resize(bod->getNumLinks()+1); - scratch_m.resize(bod->getNumLinks()+1); + m_scratch_r.resize(bod->getNumLinks()+1); //multidof? ("Y"s use it and it is used to store qdd) + m_scratch_v.resize(bod->getNumLinks()+1); + m_scratch_m.resize(bod->getNumLinks()+1); { if(!bod->isUsingRK4Integration()) { bool isConstraintPass = true; - bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(solverInfo.m_timeStep, scratch_r, scratch_v, scratch_m, isConstraintPass); + bod->computeAccelerationsArticulatedBodyAlgorithmMultiDof(solverInfo.m_timeStep, m_scratch_r, m_scratch_v, m_scratch_m, isConstraintPass); } } } @@ -732,9 +727,7 @@ void btMultiBodyDynamicsWorld::integrateTransforms(btScalar timeStep) { BT_PROFILE("btMultiBody stepPositions"); //integrate and update the Featherstone hierarchies - btAlignedObjectArray world_to_local; - btAlignedObjectArray local_origin; - + for (int b=0;bupdateCollisionObjectWorldTransforms(world_to_local,local_origin); + bod->updateCollisionObjectWorldTransforms(m_scratch_world_to_local,m_scratch_local_origin); } else { @@ -805,6 +798,8 @@ void btMultiBodyDynamicsWorld::debugDrawWorld() { BT_PROFILE("btMultiBodyDynamicsWorld debugDrawWorld"); + btDiscreteDynamicsWorld::debugDrawWorld(); + bool drawConstraints = false; if (getDebugDrawer()) { @@ -818,8 +813,6 @@ void btMultiBodyDynamicsWorld::debugDrawWorld() { BT_PROFILE("btMultiBody debugDrawWorld"); - btAlignedObjectArray world_to_local1; - btAlignedObjectArray local_origin1; for (int c=0;cforwardKinematics(world_to_local1,local_origin1); + bod->forwardKinematics(m_scratch_world_to_local1,m_scratch_local_origin1); getDebugDrawer()->drawTransform(bod->getBaseWorldTransform(), 0.1); @@ -876,7 +869,7 @@ void btMultiBodyDynamicsWorld::debugDrawWorld() } } - btDiscreteDynamicsWorld::debugDrawWorld(); + } @@ -926,7 +919,7 @@ void btMultiBodyDynamicsWorld::clearMultiBodyConstraintForces() void btMultiBodyDynamicsWorld::clearMultiBodyForces() { { - BT_PROFILE("clearMultiBodyForces"); + // BT_PROFILE("clearMultiBodyForces"); for (int i=0;im_multiBodies.size();i++) { btMultiBody* bod = m_multiBodies[i]; diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h similarity index 84% rename from extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h rename to extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h index 03ef3335c22c..c0c132bbbab8 100644 --- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h +++ b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h @@ -36,6 +36,16 @@ class btMultiBodyDynamicsWorld : public btDiscreteDynamicsWorld btMultiBodyConstraintSolver* m_multiBodyConstraintSolver; MultiBodyInplaceSolverIslandCallback* m_solverMultiBodyIslandCallback; + //cached data to avoid memory allocations + btAlignedObjectArray m_scratch_world_to_local; + btAlignedObjectArray m_scratch_local_origin; + btAlignedObjectArray m_scratch_world_to_local1; + btAlignedObjectArray m_scratch_local_origin1; + btAlignedObjectArray m_scratch_r; + btAlignedObjectArray m_scratch_v; + btAlignedObjectArray m_scratch_m; + + virtual void calculateSimulationIslands(); virtual void updateActivationState(btScalar timeStep); virtual void solveConstraints(btContactSolverInfo& solverInfo); @@ -48,7 +58,7 @@ class btMultiBodyDynamicsWorld : public btDiscreteDynamicsWorld virtual ~btMultiBodyDynamicsWorld (); - virtual void addMultiBody(btMultiBody* body, short group= btBroadphaseProxy::DefaultFilter, short mask=btBroadphaseProxy::AllFilter); + virtual void addMultiBody(btMultiBody* body, int group= btBroadphaseProxy::DefaultFilter, int mask=btBroadphaseProxy::AllFilter); virtual void removeMultiBody(btMultiBody* body); @@ -62,6 +72,11 @@ class btMultiBodyDynamicsWorld : public btDiscreteDynamicsWorld return m_multiBodies[mbIndex]; } + const btMultiBody* getMultiBody(int mbIndex) const + { + return m_multiBodies[mbIndex]; + } + virtual void addMultiBodyConstraint( btMultiBodyConstraint* constraint); virtual int getNumMultiBodyConstraints() const diff --git a/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyFixedConstraint.cpp b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyFixedConstraint.cpp new file mode 100644 index 000000000000..0f0d9f67b8f8 --- /dev/null +++ b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyFixedConstraint.cpp @@ -0,0 +1,211 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2013 Erwin Coumans http://bulletphysics.org + +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. +*/ + +///This file was written by Erwin Coumans + +#include "btMultiBodyFixedConstraint.h" +#include "btMultiBodyLinkCollider.h" +#include "BulletDynamics/Dynamics/btRigidBody.h" +#include "BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h" +#include "LinearMath/btIDebugDraw.h" + +#define BTMBFIXEDCONSTRAINT_DIM 6 + +btMultiBodyFixedConstraint::btMultiBodyFixedConstraint(btMultiBody* body, int link, btRigidBody* bodyB, const btVector3& pivotInA, const btVector3& pivotInB, const btMatrix3x3& frameInA, const btMatrix3x3& frameInB) + :btMultiBodyConstraint(body,0,link,-1,BTMBFIXEDCONSTRAINT_DIM,false), + m_rigidBodyA(0), + m_rigidBodyB(bodyB), + m_pivotInA(pivotInA), + m_pivotInB(pivotInB), + m_frameInA(frameInA), + m_frameInB(frameInB) +{ + m_data.resize(BTMBFIXEDCONSTRAINT_DIM);//at least store the applied impulses +} + +btMultiBodyFixedConstraint::btMultiBodyFixedConstraint(btMultiBody* bodyA, int linkA, btMultiBody* bodyB, int linkB, const btVector3& pivotInA, const btVector3& pivotInB, const btMatrix3x3& frameInA, const btMatrix3x3& frameInB) + :btMultiBodyConstraint(bodyA,bodyB,linkA,linkB,BTMBFIXEDCONSTRAINT_DIM,false), + m_rigidBodyA(0), + m_rigidBodyB(0), + m_pivotInA(pivotInA), + m_pivotInB(pivotInB), + m_frameInA(frameInA), + m_frameInB(frameInB) +{ + m_data.resize(BTMBFIXEDCONSTRAINT_DIM);//at least store the applied impulses +} + +void btMultiBodyFixedConstraint::finalizeMultiDof() +{ + //not implemented yet + btAssert(0); +} + +btMultiBodyFixedConstraint::~btMultiBodyFixedConstraint() +{ +} + + +int btMultiBodyFixedConstraint::getIslandIdA() const +{ + if (m_rigidBodyA) + return m_rigidBodyA->getIslandTag(); + + if (m_bodyA) + { + btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider(); + if (col) + return col->getIslandTag(); + for (int i=0;igetNumLinks();i++) + { + if (m_bodyA->getLink(i).m_collider) + return m_bodyA->getLink(i).m_collider->getIslandTag(); + } + } + return -1; +} + +int btMultiBodyFixedConstraint::getIslandIdB() const +{ + if (m_rigidBodyB) + return m_rigidBodyB->getIslandTag(); + if (m_bodyB) + { + btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider(); + if (col) + return col->getIslandTag(); + + for (int i=0;igetNumLinks();i++) + { + col = m_bodyB->getLink(i).m_collider; + if (col) + return col->getIslandTag(); + } + } + return -1; +} + +void btMultiBodyFixedConstraint::createConstraintRows(btMultiBodyConstraintArray& constraintRows, btMultiBodyJacobianData& data, const btContactSolverInfo& infoGlobal) +{ + int numDim = BTMBFIXEDCONSTRAINT_DIM; + for (int i=0;igetCompanionId(); + pivotAworld = m_rigidBodyA->getCenterOfMassTransform()*m_pivotInA; + frameAworld = frameAworld.transpose()*btMatrix3x3(m_rigidBodyA->getOrientation()); + + } else + { + if (m_bodyA) { + pivotAworld = m_bodyA->localPosToWorld(m_linkA, m_pivotInA); + frameAworld = m_bodyA->localFrameToWorld(m_linkA, frameAworld); + } + } + btVector3 pivotBworld = m_pivotInB; + btMatrix3x3 frameBworld = m_frameInB; + if (m_rigidBodyB) + { + constraintRow.m_solverBodyIdB = m_rigidBodyB->getCompanionId(); + pivotBworld = m_rigidBodyB->getCenterOfMassTransform()*m_pivotInB; + frameBworld = frameBworld.transpose()*btMatrix3x3(m_rigidBodyB->getOrientation()); + + } else + { + if (m_bodyB) { + pivotBworld = m_bodyB->localPosToWorld(m_linkB, m_pivotInB); + frameBworld = m_bodyB->localFrameToWorld(m_linkB, frameBworld); + } + } + + btMatrix3x3 relRot = frameAworld.inverse()*frameBworld; + btVector3 angleDiff; + btGeneric6DofSpring2Constraint::matrixToEulerXYZ(relRot,angleDiff); + + btVector3 constraintNormalLin(0,0,0); + btVector3 constraintNormalAng(0,0,0); + btScalar posError = 0.0; + if (i < 3) { + constraintNormalLin[i] = -1; + posError = (pivotAworld-pivotBworld).dot(constraintNormalLin); + fillMultiBodyConstraint(constraintRow, data, 0, 0, constraintNormalAng, + constraintNormalLin, pivotAworld, pivotBworld, + posError, + infoGlobal, + -m_maxAppliedImpulse, m_maxAppliedImpulse + ); + } + else { //i>=3 + constraintNormalAng = frameAworld.getColumn(i%3); + posError = angleDiff[i%3]; + fillMultiBodyConstraint(constraintRow, data, 0, 0, constraintNormalAng, + constraintNormalLin, pivotAworld, pivotBworld, + posError, + infoGlobal, + -m_maxAppliedImpulse, m_maxAppliedImpulse, true + ); + } + } +} + +void btMultiBodyFixedConstraint::debugDraw(class btIDebugDraw* drawer) +{ + btTransform tr; + tr.setIdentity(); + + if (m_rigidBodyA) + { + btVector3 pivot = m_rigidBodyA->getCenterOfMassTransform() * m_pivotInA; + tr.setOrigin(pivot); + drawer->drawTransform(tr, 0.1); + } + if (m_bodyA) + { + btVector3 pivotAworld = m_bodyA->localPosToWorld(m_linkA, m_pivotInA); + tr.setOrigin(pivotAworld); + drawer->drawTransform(tr, 0.1); + } + if (m_rigidBodyB) + { + // that ideally should draw the same frame + btVector3 pivot = m_rigidBodyB->getCenterOfMassTransform() * m_pivotInB; + tr.setOrigin(pivot); + drawer->drawTransform(tr, 0.1); + } + if (m_bodyB) + { + btVector3 pivotBworld = m_bodyB->localPosToWorld(m_linkB, m_pivotInB); + tr.setOrigin(pivotBworld); + drawer->drawTransform(tr, 0.1); + } +} diff --git a/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyFixedConstraint.h b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyFixedConstraint.h new file mode 100644 index 000000000000..036025136ed8 --- /dev/null +++ b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyFixedConstraint.h @@ -0,0 +1,94 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2013 Erwin Coumans http://bulletphysics.org + +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. +*/ + +///This file was written by Erwin Coumans + +#ifndef BT_MULTIBODY_FIXED_CONSTRAINT_H +#define BT_MULTIBODY_FIXED_CONSTRAINT_H + +#include "btMultiBodyConstraint.h" + +class btMultiBodyFixedConstraint : public btMultiBodyConstraint +{ +protected: + + btRigidBody* m_rigidBodyA; + btRigidBody* m_rigidBodyB; + btVector3 m_pivotInA; + btVector3 m_pivotInB; + btMatrix3x3 m_frameInA; + btMatrix3x3 m_frameInB; + +public: + + btMultiBodyFixedConstraint(btMultiBody* body, int link, btRigidBody* bodyB, const btVector3& pivotInA, const btVector3& pivotInB, const btMatrix3x3& frameInA, const btMatrix3x3& frameInB); + btMultiBodyFixedConstraint(btMultiBody* bodyA, int linkA, btMultiBody* bodyB, int linkB, const btVector3& pivotInA, const btVector3& pivotInB, const btMatrix3x3& frameInA, const btMatrix3x3& frameInB); + + virtual ~btMultiBodyFixedConstraint(); + + virtual void finalizeMultiDof(); + + virtual int getIslandIdA() const; + virtual int getIslandIdB() const; + + virtual void createConstraintRows(btMultiBodyConstraintArray& constraintRows, + btMultiBodyJacobianData& data, + const btContactSolverInfo& infoGlobal); + + const btVector3& getPivotInA() const + { + return m_pivotInA; + } + + void setPivotInA(const btVector3& pivotInA) + { + m_pivotInA = pivotInA; + } + + const btVector3& getPivotInB() const + { + return m_pivotInB; + } + + virtual void setPivotInB(const btVector3& pivotInB) + { + m_pivotInB = pivotInB; + } + + const btMatrix3x3& getFrameInA() const + { + return m_frameInA; + } + + void setFrameInA(const btMatrix3x3& frameInA) + { + m_frameInA = frameInA; + } + + const btMatrix3x3& getFrameInB() const + { + return m_frameInB; + } + + virtual void setFrameInB(const btMatrix3x3& frameInB) + { + m_frameInB = frameInB; + } + + virtual void debugDraw(class btIDebugDraw* drawer); + +}; + +#endif //BT_MULTIBODY_FIXED_CONSTRAINT_H diff --git a/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyGearConstraint.cpp b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyGearConstraint.cpp new file mode 100644 index 000000000000..5fdb7007d81d --- /dev/null +++ b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyGearConstraint.cpp @@ -0,0 +1,184 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2013 Erwin Coumans http://bulletphysics.org + +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. +*/ + +///This file was written by Erwin Coumans + +#include "btMultiBodyGearConstraint.h" +#include "btMultiBody.h" +#include "btMultiBodyLinkCollider.h" +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" + +btMultiBodyGearConstraint::btMultiBodyGearConstraint(btMultiBody* bodyA, int linkA, btMultiBody* bodyB, int linkB, const btVector3& pivotInA, const btVector3& pivotInB, const btMatrix3x3& frameInA, const btMatrix3x3& frameInB) + :btMultiBodyConstraint(bodyA,bodyB,linkA,linkB,1,false), + m_gearRatio(1), + m_gearAuxLink(-1), + m_erp(0), + m_relativePositionTarget(0) +{ + +} + +void btMultiBodyGearConstraint::finalizeMultiDof() +{ + + allocateJacobiansMultiDof(); + + m_numDofsFinalized = m_jacSizeBoth; +} + +btMultiBodyGearConstraint::~btMultiBodyGearConstraint() +{ +} + + +int btMultiBodyGearConstraint::getIslandIdA() const +{ + + if (m_bodyA) + { + btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider(); + if (col) + return col->getIslandTag(); + for (int i=0;igetNumLinks();i++) + { + if (m_bodyA->getLink(i).m_collider) + return m_bodyA->getLink(i).m_collider->getIslandTag(); + } + } + return -1; +} + +int btMultiBodyGearConstraint::getIslandIdB() const +{ + if (m_bodyB) + { + btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider(); + if (col) + return col->getIslandTag(); + + for (int i=0;igetNumLinks();i++) + { + col = m_bodyB->getLink(i).m_collider; + if (col) + return col->getIslandTag(); + } + } + return -1; +} + + +void btMultiBodyGearConstraint::createConstraintRows(btMultiBodyConstraintArray& constraintRows, + btMultiBodyJacobianData& data, + const btContactSolverInfo& infoGlobal) +{ + // only positions need to be updated -- data.m_jacobians and force + // directions were set in the ctor and never change. + + if (m_numDofsFinalized != m_jacSizeBoth) + { + finalizeMultiDof(); + } + + //don't crash + if (m_numDofsFinalized != m_jacSizeBoth) + return; + + + if (m_maxAppliedImpulse==0.f) + return; + + // note: we rely on the fact that data.m_jacobians are + // always initialized to zero by the Constraint ctor + int linkDoF = 0; + unsigned int offsetA = 6 + (m_bodyA->getLink(m_linkA).m_dofOffset + linkDoF); + unsigned int offsetB = 6 + (m_bodyB->getLink(m_linkB).m_dofOffset + linkDoF); + + // row 0: the lower bound + jacobianA(0)[offsetA] = 1; + jacobianB(0)[offsetB] = m_gearRatio; + + btScalar posError = 0; + const btVector3 dummy(0, 0, 0); + + btScalar kp = 1; + btScalar kd = 1; + int numRows = getNumRows(); + + for (int row=0;rowgetJointPosMultiDof(m_linkA)[dof]; + btScalar currentVelocity = m_bodyA->getJointVelMultiDof(m_linkA)[dof]; + btScalar auxVel = 0; + + if (m_gearAuxLink>=0) + { + auxVel = m_bodyA->getJointVelMultiDof(m_gearAuxLink)[dof]; + } + currentVelocity += auxVel; + if (m_erp!=0) + { + btScalar currentPositionA = m_bodyA->getJointPosMultiDof(m_linkA)[dof]; + btScalar currentPositionB = m_gearRatio*m_bodyA->getJointPosMultiDof(m_linkB)[dof]; + btScalar diff = currentPositionB+currentPositionA; + btScalar desiredPositionDiff = this->m_relativePositionTarget; + posError = -m_erp*(desiredPositionDiff - diff); + } + + btScalar desiredRelativeVelocity = auxVel; + + fillMultiBodyConstraint(constraintRow,data,jacobianA(row),jacobianB(row),dummy,dummy,dummy,dummy,posError,infoGlobal,-m_maxAppliedImpulse,m_maxAppliedImpulse,false,1,false,desiredRelativeVelocity); + + constraintRow.m_orgConstraint = this; + constraintRow.m_orgDofIndex = row; + { + //expect either prismatic or revolute joint type for now + btAssert((m_bodyA->getLink(m_linkA).m_jointType == btMultibodyLink::eRevolute)||(m_bodyA->getLink(m_linkA).m_jointType == btMultibodyLink::ePrismatic)); + switch (m_bodyA->getLink(m_linkA).m_jointType) + { + case btMultibodyLink::eRevolute: + { + constraintRow.m_contactNormal1.setZero(); + constraintRow.m_contactNormal2.setZero(); + btVector3 revoluteAxisInWorld = quatRotate(m_bodyA->getLink(m_linkA).m_cachedWorldTransform.getRotation(),m_bodyA->getLink(m_linkA).m_axes[0].m_topVec); + constraintRow.m_relpos1CrossNormal=revoluteAxisInWorld; + constraintRow.m_relpos2CrossNormal=-revoluteAxisInWorld; + + break; + } + case btMultibodyLink::ePrismatic: + { + btVector3 prismaticAxisInWorld = quatRotate(m_bodyA->getLink(m_linkA).m_cachedWorldTransform.getRotation(),m_bodyA->getLink(m_linkA).m_axes[0].m_bottomVec); + constraintRow.m_contactNormal1=prismaticAxisInWorld; + constraintRow.m_contactNormal2=-prismaticAxisInWorld; + constraintRow.m_relpos1CrossNormal.setZero(); + constraintRow.m_relpos2CrossNormal.setZero(); + break; + } + default: + { + btAssert(0); + } + }; + + } + + } + +} + diff --git a/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyGearConstraint.h b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyGearConstraint.h new file mode 100644 index 000000000000..0115de6241c3 --- /dev/null +++ b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyGearConstraint.h @@ -0,0 +1,117 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2013 Erwin Coumans http://bulletphysics.org + +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. +*/ + +///This file was written by Erwin Coumans + +#ifndef BT_MULTIBODY_GEAR_CONSTRAINT_H +#define BT_MULTIBODY_GEAR_CONSTRAINT_H + +#include "btMultiBodyConstraint.h" + +class btMultiBodyGearConstraint : public btMultiBodyConstraint +{ +protected: + + btRigidBody* m_rigidBodyA; + btRigidBody* m_rigidBodyB; + btVector3 m_pivotInA; + btVector3 m_pivotInB; + btMatrix3x3 m_frameInA; + btMatrix3x3 m_frameInB; + btScalar m_gearRatio; + int m_gearAuxLink; + btScalar m_erp; + btScalar m_relativePositionTarget; + +public: + + //btMultiBodyGearConstraint(btMultiBody* body, int link, btRigidBody* bodyB, const btVector3& pivotInA, const btVector3& pivotInB, const btMatrix3x3& frameInA, const btMatrix3x3& frameInB); + btMultiBodyGearConstraint(btMultiBody* bodyA, int linkA, btMultiBody* bodyB, int linkB, const btVector3& pivotInA, const btVector3& pivotInB, const btMatrix3x3& frameInA, const btMatrix3x3& frameInB); + + virtual ~btMultiBodyGearConstraint(); + + virtual void finalizeMultiDof(); + + virtual int getIslandIdA() const; + virtual int getIslandIdB() const; + + virtual void createConstraintRows(btMultiBodyConstraintArray& constraintRows, + btMultiBodyJacobianData& data, + const btContactSolverInfo& infoGlobal); + + const btVector3& getPivotInA() const + { + return m_pivotInA; + } + + void setPivotInA(const btVector3& pivotInA) + { + m_pivotInA = pivotInA; + } + + const btVector3& getPivotInB() const + { + return m_pivotInB; + } + + virtual void setPivotInB(const btVector3& pivotInB) + { + m_pivotInB = pivotInB; + } + + const btMatrix3x3& getFrameInA() const + { + return m_frameInA; + } + + void setFrameInA(const btMatrix3x3& frameInA) + { + m_frameInA = frameInA; + } + + const btMatrix3x3& getFrameInB() const + { + return m_frameInB; + } + + virtual void setFrameInB(const btMatrix3x3& frameInB) + { + m_frameInB = frameInB; + } + + virtual void debugDraw(class btIDebugDraw* drawer) + { + //todo(erwincoumans) + } + + virtual void setGearRatio(btScalar gearRatio) + { + m_gearRatio = gearRatio; + } + virtual void setGearAuxLink(int gearAuxLink) + { + m_gearAuxLink = gearAuxLink; + } + virtual void setRelativePositionTarget(btScalar relPosTarget) + { + m_relativePositionTarget = relPosTarget; + } + virtual void setErp(btScalar erp) + { + m_erp = erp; + } +}; + +#endif //BT_MULTIBODY_GEAR_CONSTRAINT_H diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointFeedback.h b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyJointFeedback.h similarity index 100% rename from extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointFeedback.h rename to extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyJointFeedback.h diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp similarity index 96% rename from extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp rename to extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp index 3f05aa4d5fac..6d173b66a1de 100644 --- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp +++ b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.cpp @@ -110,7 +110,13 @@ void btMultiBodyJointLimitConstraint::createConstraintRows(btMultiBodyConstraint for (int row=0;row0) + { + continue; + } btScalar direction = row? -1 : 1; btMultiBodySolverConstraint& constraintRow = constraintRows.expandNonInitializing(); @@ -122,7 +128,7 @@ void btMultiBodyJointLimitConstraint::createConstraintRows(btMultiBodyConstraint const btScalar posError = 0; //why assume it's zero? const btVector3 dummy(0, 0, 0); - btScalar rel_vel = fillMultiBodyConstraint(constraintRow,data,jacobianA(row),jacobianB(row),dummy,dummy,dummy,posError,infoGlobal,0,m_maxAppliedImpulse); + btScalar rel_vel = fillMultiBodyConstraint(constraintRow,data,jacobianA(row),jacobianB(row),dummy,dummy,dummy,dummy,posError,infoGlobal,0,m_maxAppliedImpulse); { //expect either prismatic or revolute joint type for now @@ -158,7 +164,7 @@ void btMultiBodyJointLimitConstraint::createConstraintRows(btMultiBodyConstraint } { - btScalar penetration = getPosition(row); + btScalar positionalError = 0.f; btScalar velocityError = - rel_vel;// * damping; btScalar erp = infoGlobal.m_erp2; diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.h b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.h similarity index 100% rename from extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.h rename to extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.h diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp similarity index 80% rename from extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp rename to extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp index 062d19accaa6..5ec9f43f0371 100644 --- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp +++ b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp @@ -1,157 +1,186 @@ -/* -Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2013 Erwin Coumans http://bulletphysics.org - -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. -*/ - -///This file was written by Erwin Coumans - -#include "btMultiBodyJointMotor.h" -#include "btMultiBody.h" -#include "btMultiBodyLinkCollider.h" -#include "BulletCollision/CollisionDispatch/btCollisionObject.h" - - -btMultiBodyJointMotor::btMultiBodyJointMotor(btMultiBody* body, int link, btScalar desiredVelocity, btScalar maxMotorImpulse) - :btMultiBodyConstraint(body,body,link,body->getLink(link).m_parent,1,true), - m_desiredVelocity(desiredVelocity) -{ - - m_maxAppliedImpulse = maxMotorImpulse; - // the data.m_jacobians never change, so may as well - // initialize them here - - -} - -void btMultiBodyJointMotor::finalizeMultiDof() -{ - allocateJacobiansMultiDof(); - // note: we rely on the fact that data.m_jacobians are - // always initialized to zero by the Constraint ctor - int linkDoF = 0; - unsigned int offset = 6 + (m_bodyA->getLink(m_linkA).m_dofOffset + linkDoF); - - // row 0: the lower bound - // row 0: the lower bound - jacobianA(0)[offset] = 1; - - m_numDofsFinalized = m_jacSizeBoth; -} - -btMultiBodyJointMotor::btMultiBodyJointMotor(btMultiBody* body, int link, int linkDoF, btScalar desiredVelocity, btScalar maxMotorImpulse) - //:btMultiBodyConstraint(body,0,link,-1,1,true), - :btMultiBodyConstraint(body,body,link,body->getLink(link).m_parent,1,true), - m_desiredVelocity(desiredVelocity) -{ - btAssert(linkDoF < body->getLink(link).m_dofCount); - - m_maxAppliedImpulse = maxMotorImpulse; - -} -btMultiBodyJointMotor::~btMultiBodyJointMotor() -{ -} - -int btMultiBodyJointMotor::getIslandIdA() const -{ - btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider(); - if (col) - return col->getIslandTag(); - for (int i=0;igetNumLinks();i++) - { - if (m_bodyA->getLink(i).m_collider) - return m_bodyA->getLink(i).m_collider->getIslandTag(); - } - return -1; -} - -int btMultiBodyJointMotor::getIslandIdB() const -{ - btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider(); - if (col) - return col->getIslandTag(); - - for (int i=0;igetNumLinks();i++) - { - col = m_bodyB->getLink(i).m_collider; - if (col) - return col->getIslandTag(); - } - return -1; -} - - -void btMultiBodyJointMotor::createConstraintRows(btMultiBodyConstraintArray& constraintRows, - btMultiBodyJacobianData& data, - const btContactSolverInfo& infoGlobal) -{ - // only positions need to be updated -- data.m_jacobians and force - // directions were set in the ctor and never change. - - if (m_numDofsFinalized != m_jacSizeBoth) - { - finalizeMultiDof(); - } - - //don't crash - if (m_numDofsFinalized != m_jacSizeBoth) - return; - - const btScalar posError = 0; - const btVector3 dummy(0, 0, 0); - - for (int row=0;rowgetLink(m_linkA).m_jointType == btMultibodyLink::eRevolute)||(m_bodyA->getLink(m_linkA).m_jointType == btMultibodyLink::ePrismatic)); - switch (m_bodyA->getLink(m_linkA).m_jointType) - { - case btMultibodyLink::eRevolute: - { - constraintRow.m_contactNormal1.setZero(); - constraintRow.m_contactNormal2.setZero(); - btVector3 revoluteAxisInWorld = quatRotate(m_bodyA->getLink(m_linkA).m_cachedWorldTransform.getRotation(),m_bodyA->getLink(m_linkA).m_axes[0].m_topVec); - constraintRow.m_relpos1CrossNormal=revoluteAxisInWorld; - constraintRow.m_relpos2CrossNormal=-revoluteAxisInWorld; - - break; - } - case btMultibodyLink::ePrismatic: - { - btVector3 prismaticAxisInWorld = quatRotate(m_bodyA->getLink(m_linkA).m_cachedWorldTransform.getRotation(),m_bodyA->getLink(m_linkA).m_axes[0].m_bottomVec); - constraintRow.m_contactNormal1=prismaticAxisInWorld; - constraintRow.m_contactNormal2=-prismaticAxisInWorld; - constraintRow.m_relpos1CrossNormal.setZero(); - constraintRow.m_relpos2CrossNormal.setZero(); - - break; - } - default: - { - btAssert(0); - } - }; - - } - - } - -} - +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2013 Erwin Coumans http://bulletphysics.org + +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. +*/ + +///This file was written by Erwin Coumans + +#include "btMultiBodyJointMotor.h" +#include "btMultiBody.h" +#include "btMultiBodyLinkCollider.h" +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" + + +btMultiBodyJointMotor::btMultiBodyJointMotor(btMultiBody* body, int link, btScalar desiredVelocity, btScalar maxMotorImpulse) + :btMultiBodyConstraint(body,body,link,body->getLink(link).m_parent,1,true), + m_desiredVelocity(desiredVelocity), + m_desiredPosition(0), + m_kd(1.), + m_kp(0), + m_erp(1), + m_rhsClamp(SIMD_INFINITY) +{ + + m_maxAppliedImpulse = maxMotorImpulse; + // the data.m_jacobians never change, so may as well + // initialize them here + + +} + +void btMultiBodyJointMotor::finalizeMultiDof() +{ + allocateJacobiansMultiDof(); + // note: we rely on the fact that data.m_jacobians are + // always initialized to zero by the Constraint ctor + int linkDoF = 0; + unsigned int offset = 6 + (m_bodyA->getLink(m_linkA).m_dofOffset + linkDoF); + + // row 0: the lower bound + // row 0: the lower bound + jacobianA(0)[offset] = 1; + + m_numDofsFinalized = m_jacSizeBoth; +} + +btMultiBodyJointMotor::btMultiBodyJointMotor(btMultiBody* body, int link, int linkDoF, btScalar desiredVelocity, btScalar maxMotorImpulse) + //:btMultiBodyConstraint(body,0,link,-1,1,true), + :btMultiBodyConstraint(body,body,link,body->getLink(link).m_parent,1,true), + m_desiredVelocity(desiredVelocity), + m_desiredPosition(0), + m_kd(1.), + m_kp(0), + m_erp(1), + m_rhsClamp(SIMD_INFINITY) +{ + btAssert(linkDoF < body->getLink(link).m_dofCount); + + m_maxAppliedImpulse = maxMotorImpulse; + +} +btMultiBodyJointMotor::~btMultiBodyJointMotor() +{ +} + +int btMultiBodyJointMotor::getIslandIdA() const +{ + btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider(); + if (col) + return col->getIslandTag(); + for (int i=0;igetNumLinks();i++) + { + if (m_bodyA->getLink(i).m_collider) + return m_bodyA->getLink(i).m_collider->getIslandTag(); + } + return -1; +} + +int btMultiBodyJointMotor::getIslandIdB() const +{ + btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider(); + if (col) + return col->getIslandTag(); + + for (int i=0;igetNumLinks();i++) + { + col = m_bodyB->getLink(i).m_collider; + if (col) + return col->getIslandTag(); + } + return -1; +} + + +void btMultiBodyJointMotor::createConstraintRows(btMultiBodyConstraintArray& constraintRows, + btMultiBodyJacobianData& data, + const btContactSolverInfo& infoGlobal) +{ + // only positions need to be updated -- data.m_jacobians and force + // directions were set in the ctor and never change. + + if (m_numDofsFinalized != m_jacSizeBoth) + { + finalizeMultiDof(); + } + + //don't crash + if (m_numDofsFinalized != m_jacSizeBoth) + return; + + if (m_maxAppliedImpulse==0.f) + return; + + const btScalar posError = 0; + const btVector3 dummy(0, 0, 0); + + for (int row=0;rowgetJointPosMultiDof(m_linkA)[dof]; + btScalar currentVelocity = m_bodyA->getJointVelMultiDof(m_linkA)[dof]; + btScalar positionStabiliationTerm = m_erp*(m_desiredPosition-currentPosition)/infoGlobal.m_timeStep; + + btScalar velocityError = (m_desiredVelocity - currentVelocity); + btScalar rhs = m_kp * positionStabiliationTerm + currentVelocity+m_kd * velocityError; + if (rhs>m_rhsClamp) + { + rhs=m_rhsClamp; + } + if (rhs<-m_rhsClamp) + { + rhs=-m_rhsClamp; + } + + + fillMultiBodyConstraint(constraintRow,data,jacobianA(row),jacobianB(row),dummy,dummy,dummy,dummy,posError,infoGlobal,-m_maxAppliedImpulse,m_maxAppliedImpulse,false,1,false,rhs); + constraintRow.m_orgConstraint = this; + constraintRow.m_orgDofIndex = row; + { + //expect either prismatic or revolute joint type for now + btAssert((m_bodyA->getLink(m_linkA).m_jointType == btMultibodyLink::eRevolute)||(m_bodyA->getLink(m_linkA).m_jointType == btMultibodyLink::ePrismatic)); + switch (m_bodyA->getLink(m_linkA).m_jointType) + { + case btMultibodyLink::eRevolute: + { + constraintRow.m_contactNormal1.setZero(); + constraintRow.m_contactNormal2.setZero(); + btVector3 revoluteAxisInWorld = quatRotate(m_bodyA->getLink(m_linkA).m_cachedWorldTransform.getRotation(),m_bodyA->getLink(m_linkA).m_axes[0].m_topVec); + constraintRow.m_relpos1CrossNormal=revoluteAxisInWorld; + constraintRow.m_relpos2CrossNormal=-revoluteAxisInWorld; + + break; + } + case btMultibodyLink::ePrismatic: + { + btVector3 prismaticAxisInWorld = quatRotate(m_bodyA->getLink(m_linkA).m_cachedWorldTransform.getRotation(),m_bodyA->getLink(m_linkA).m_axes[0].m_bottomVec); + constraintRow.m_contactNormal1=prismaticAxisInWorld; + constraintRow.m_contactNormal2=-prismaticAxisInWorld; + constraintRow.m_relpos1CrossNormal.setZero(); + constraintRow.m_relpos2CrossNormal.setZero(); + + break; + } + default: + { + btAssert(0); + } + }; + + } + + } + +} + diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.h b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.h similarity index 75% rename from extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.h rename to extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.h index 011aadcfa4b7..7cf57311afb6 100644 --- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.h +++ b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.h @@ -1,57 +1,81 @@ -/* -Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2013 Erwin Coumans http://bulletphysics.org - -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. -*/ - -///This file was written by Erwin Coumans - -#ifndef BT_MULTIBODY_JOINT_MOTOR_H -#define BT_MULTIBODY_JOINT_MOTOR_H - -#include "btMultiBodyConstraint.h" -struct btSolverInfo; - -class btMultiBodyJointMotor : public btMultiBodyConstraint -{ -protected: - - - btScalar m_desiredVelocity; - -public: - - btMultiBodyJointMotor(btMultiBody* body, int link, btScalar desiredVelocity, btScalar maxMotorImpulse); - btMultiBodyJointMotor(btMultiBody* body, int link, int linkDoF, btScalar desiredVelocity, btScalar maxMotorImpulse); - virtual ~btMultiBodyJointMotor(); - virtual void finalizeMultiDof(); - - virtual int getIslandIdA() const; - virtual int getIslandIdB() const; - - virtual void createConstraintRows(btMultiBodyConstraintArray& constraintRows, - btMultiBodyJacobianData& data, - const btContactSolverInfo& infoGlobal); - - virtual void setVelocityTarget(btScalar velTarget) - { - m_desiredVelocity = velTarget; - } - - virtual void debugDraw(class btIDebugDraw* drawer) - { - //todo(erwincoumans) - } -}; - -#endif //BT_MULTIBODY_JOINT_MOTOR_H - +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2013 Erwin Coumans http://bulletphysics.org + +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. +*/ + +///This file was written by Erwin Coumans + +#ifndef BT_MULTIBODY_JOINT_MOTOR_H +#define BT_MULTIBODY_JOINT_MOTOR_H + +#include "btMultiBodyConstraint.h" +struct btSolverInfo; + +class btMultiBodyJointMotor : public btMultiBodyConstraint +{ +protected: + + btScalar m_desiredVelocity; + btScalar m_desiredPosition; + btScalar m_kd; + btScalar m_kp; + btScalar m_erp; + btScalar m_rhsClamp;//maximum error + + +public: + + btMultiBodyJointMotor(btMultiBody* body, int link, btScalar desiredVelocity, btScalar maxMotorImpulse); + btMultiBodyJointMotor(btMultiBody* body, int link, int linkDoF, btScalar desiredVelocity, btScalar maxMotorImpulse); + virtual ~btMultiBodyJointMotor(); + virtual void finalizeMultiDof(); + + virtual int getIslandIdA() const; + virtual int getIslandIdB() const; + + virtual void createConstraintRows(btMultiBodyConstraintArray& constraintRows, + btMultiBodyJacobianData& data, + const btContactSolverInfo& infoGlobal); + + virtual void setVelocityTarget(btScalar velTarget, btScalar kd = 1.f) + { + m_desiredVelocity = velTarget; + m_kd = kd; + } + + virtual void setPositionTarget(btScalar posTarget, btScalar kp = 1.f) + { + m_desiredPosition = posTarget; + m_kp = kp; + } + + virtual void setErp(btScalar erp) + { + m_erp = erp; + } + virtual btScalar getErp() const + { + return m_erp; + } + virtual void setRhsClamp(btScalar rhsClamp) + { + m_rhsClamp = rhsClamp; + } + virtual void debugDraw(class btIDebugDraw* drawer) + { + //todo(erwincoumans) + } +}; + +#endif //BT_MULTIBODY_JOINT_MOTOR_H + diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyLink.h b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyLink.h similarity index 81% rename from extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyLink.h rename to extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyLink.h index 668e44439045..8129ae9013d3 100644 --- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyLink.h +++ b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyLink.h @@ -1,219 +1,244 @@ -/* -Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2013 Erwin Coumans http://bulletphysics.org - -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_MULTIBODY_LINK_H -#define BT_MULTIBODY_LINK_H - -#include "LinearMath/btQuaternion.h" -#include "LinearMath/btVector3.h" -#include "BulletCollision/CollisionDispatch/btCollisionObject.h" - -enum btMultiBodyLinkFlags -{ - BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION = 1 -}; - -//both defines are now permanently enabled -#define BT_MULTIBODYLINK_INCLUDE_PLANAR_JOINTS -#define TEST_SPATIAL_ALGEBRA_LAYER - -// -// Various spatial helper functions -// - -//namespace { - - -#include "LinearMath/btSpatialAlgebra.h" - -//} - -// -// Link struct -// - -struct btMultibodyLink -{ - - BT_DECLARE_ALIGNED_ALLOCATOR(); - - btScalar m_mass; // mass of link - btVector3 m_inertiaLocal; // inertia of link (local frame; diagonal) - - int m_parent; // index of the parent link (assumed to be < index of this link), or -1 if parent is the base link. - - btQuaternion m_zeroRotParentToThis; // rotates vectors in parent-frame to vectors in local-frame (when q=0). constant. - - btVector3 m_dVector; // vector from the inboard joint pos to this link's COM. (local frame.) constant. - //this is set to zero for planar joint (see also m_eVector comment) - - // m_eVector is constant, but depends on the joint type: - // revolute, fixed, prismatic, spherical: vector from parent's COM to the pivot point, in PARENT's frame. - // planar: vector from COM of parent to COM of this link, WHEN Q = 0. (local frame.) - // todo: fix the planar so it is consistent with the other joints - - btVector3 m_eVector; - - btSpatialMotionVector m_absFrameTotVelocity, m_absFrameLocVelocity; - - enum eFeatherstoneJointType - { - eRevolute = 0, - ePrismatic = 1, - eSpherical = 2, - ePlanar = 3, - eFixed = 4, - eInvalid - }; - - - - // "axis" = spatial joint axis (Mirtich Defn 9 p104). (expressed in local frame.) constant. - // for prismatic: m_axesTop[0] = zero; - // m_axesBottom[0] = unit vector along the joint axis. - // for revolute: m_axesTop[0] = unit vector along the rotation axis (u); - // m_axesBottom[0] = u cross m_dVector (i.e. COM linear motion due to the rotation at the joint) - // - // for spherical: m_axesTop[0][1][2] (u1,u2,u3) form a 3x3 identity matrix (3 rotation axes) - // m_axesBottom[0][1][2] cross u1,u2,u3 (i.e. COM linear motion due to the rotation at the joint) - // - // for planar: m_axesTop[0] = unit vector along the rotation axis (u); defines the plane of motion - // m_axesTop[1][2] = zero - // m_axesBottom[0] = zero - // m_axesBottom[1][2] = unit vectors along the translational axes on that plane - btSpatialMotionVector m_axes[6]; - void setAxisTop(int dof, const btVector3 &axis) { m_axes[dof].m_topVec = axis; } - void setAxisBottom(int dof, const btVector3 &axis) { m_axes[dof].m_bottomVec = axis; } - void setAxisTop(int dof, const btScalar &x, const btScalar &y, const btScalar &z) { m_axes[dof].m_topVec.setValue(x, y, z); } - void setAxisBottom(int dof, const btScalar &x, const btScalar &y, const btScalar &z) { m_axes[dof].m_bottomVec.setValue(x, y, z); } - const btVector3 & getAxisTop(int dof) const { return m_axes[dof].m_topVec; } - const btVector3 & getAxisBottom(int dof) const { return m_axes[dof].m_bottomVec; } - - int m_dofOffset, m_cfgOffset; - - btQuaternion m_cachedRotParentToThis; // rotates vectors in parent frame to vectors in local frame - btVector3 m_cachedRVector; // vector from COM of parent to COM of this link, in local frame. - - btVector3 m_appliedForce; // In WORLD frame - btVector3 m_appliedTorque; // In WORLD frame - -btVector3 m_appliedConstraintForce; // In WORLD frame - btVector3 m_appliedConstraintTorque; // In WORLD frame - - btScalar m_jointPos[7]; - - //m_jointTorque is the joint torque applied by the user using 'addJointTorque'. - //It gets set to zero after each internal stepSimulation call - btScalar m_jointTorque[6]; - - class btMultiBodyLinkCollider* m_collider; - int m_flags; - - - int m_dofCount, m_posVarCount; //redundant but handy - - eFeatherstoneJointType m_jointType; - - struct btMultiBodyJointFeedback* m_jointFeedback; - - btTransform m_cachedWorldTransform;//this cache is updated when calling btMultiBody::forwardKinematics - - const char* m_linkName;//m_linkName memory needs to be managed by the developer/user! - const char* m_jointName;//m_jointName memory needs to be managed by the developer/user! - - // ctor: set some sensible defaults - btMultibodyLink() - : m_mass(1), - m_parent(-1), - m_zeroRotParentToThis(0, 0, 0, 1), - m_cachedRotParentToThis(0, 0, 0, 1), - m_collider(0), - m_flags(0), - m_dofCount(0), - m_posVarCount(0), - m_jointType(btMultibodyLink::eInvalid), - m_jointFeedback(0), - m_linkName(0), - m_jointName(0) - { - - m_inertiaLocal.setValue(1, 1, 1); - setAxisTop(0, 0., 0., 0.); - setAxisBottom(0, 1., 0., 0.); - m_dVector.setValue(0, 0, 0); - m_eVector.setValue(0, 0, 0); - m_cachedRVector.setValue(0, 0, 0); - m_appliedForce.setValue( 0, 0, 0); - m_appliedTorque.setValue(0, 0, 0); - // - m_jointPos[0] = m_jointPos[1] = m_jointPos[2] = m_jointPos[4] = m_jointPos[5] = m_jointPos[6] = 0.f; - m_jointPos[3] = 1.f; //"quat.w" - m_jointTorque[0] = m_jointTorque[1] = m_jointTorque[2] = m_jointTorque[3] = m_jointTorque[4] = m_jointTorque[5] = 0.f; - m_cachedWorldTransform.setIdentity(); - } - - // routine to update m_cachedRotParentToThis and m_cachedRVector - void updateCacheMultiDof(btScalar *pq = 0) - { - btScalar *pJointPos = (pq ? pq : &m_jointPos[0]); - - switch(m_jointType) - { - case eRevolute: - { - m_cachedRotParentToThis = btQuaternion(getAxisTop(0),-pJointPos[0]) * m_zeroRotParentToThis; - m_cachedRVector = m_dVector + quatRotate(m_cachedRotParentToThis,m_eVector); - - break; - } - case ePrismatic: - { - // m_cachedRotParentToThis never changes, so no need to update - m_cachedRVector = m_dVector + quatRotate(m_cachedRotParentToThis,m_eVector) + pJointPos[0] * getAxisBottom(0); - - break; - } - case eSpherical: - { - m_cachedRotParentToThis = btQuaternion(pJointPos[0], pJointPos[1], pJointPos[2], -pJointPos[3]) * m_zeroRotParentToThis; - m_cachedRVector = m_dVector + quatRotate(m_cachedRotParentToThis,m_eVector); - - break; - } - case ePlanar: - { - m_cachedRotParentToThis = btQuaternion(getAxisTop(0),-pJointPos[0]) * m_zeroRotParentToThis; - m_cachedRVector = quatRotate(btQuaternion(getAxisTop(0),-pJointPos[0]), pJointPos[1] * getAxisBottom(1) + pJointPos[2] * getAxisBottom(2)) + quatRotate(m_cachedRotParentToThis,m_eVector); - - break; - } - case eFixed: - { - m_cachedRotParentToThis = m_zeroRotParentToThis; - m_cachedRVector = m_dVector + quatRotate(m_cachedRotParentToThis,m_eVector); - - break; - } - default: - { - //invalid type - btAssert(0); - } - } - } -}; - - -#endif //BT_MULTIBODY_LINK_H +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2013 Erwin Coumans http://bulletphysics.org + +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_MULTIBODY_LINK_H +#define BT_MULTIBODY_LINK_H + +#include "LinearMath/btQuaternion.h" +#include "LinearMath/btVector3.h" +#include "BulletCollision/CollisionDispatch/btCollisionObject.h" + +enum btMultiBodyLinkFlags +{ + BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION = 1, + BT_MULTIBODYLINKFLAGS_DISABLE_ALL_PARENT_COLLISION = 2, +}; + +//both defines are now permanently enabled +#define BT_MULTIBODYLINK_INCLUDE_PLANAR_JOINTS +#define TEST_SPATIAL_ALGEBRA_LAYER + +// +// Various spatial helper functions +// + +//namespace { + + +#include "LinearMath/btSpatialAlgebra.h" + +//} + +// +// Link struct +// + +struct btMultibodyLink +{ + + BT_DECLARE_ALIGNED_ALLOCATOR(); + + btScalar m_mass; // mass of link + btVector3 m_inertiaLocal; // inertia of link (local frame; diagonal) + + int m_parent; // index of the parent link (assumed to be < index of this link), or -1 if parent is the base link. + + btQuaternion m_zeroRotParentToThis; // rotates vectors in parent-frame to vectors in local-frame (when q=0). constant. + + btVector3 m_dVector; // vector from the inboard joint pos to this link's COM. (local frame.) constant. + //this is set to zero for planar joint (see also m_eVector comment) + + // m_eVector is constant, but depends on the joint type: + // revolute, fixed, prismatic, spherical: vector from parent's COM to the pivot point, in PARENT's frame. + // planar: vector from COM of parent to COM of this link, WHEN Q = 0. (local frame.) + // todo: fix the planar so it is consistent with the other joints + + btVector3 m_eVector; + + btSpatialMotionVector m_absFrameTotVelocity, m_absFrameLocVelocity; + + enum eFeatherstoneJointType + { + eRevolute = 0, + ePrismatic = 1, + eSpherical = 2, + ePlanar = 3, + eFixed = 4, + eInvalid + }; + + + + // "axis" = spatial joint axis (Mirtich Defn 9 p104). (expressed in local frame.) constant. + // for prismatic: m_axesTop[0] = zero; + // m_axesBottom[0] = unit vector along the joint axis. + // for revolute: m_axesTop[0] = unit vector along the rotation axis (u); + // m_axesBottom[0] = u cross m_dVector (i.e. COM linear motion due to the rotation at the joint) + // + // for spherical: m_axesTop[0][1][2] (u1,u2,u3) form a 3x3 identity matrix (3 rotation axes) + // m_axesBottom[0][1][2] cross u1,u2,u3 (i.e. COM linear motion due to the rotation at the joint) + // + // for planar: m_axesTop[0] = unit vector along the rotation axis (u); defines the plane of motion + // m_axesTop[1][2] = zero + // m_axesBottom[0] = zero + // m_axesBottom[1][2] = unit vectors along the translational axes on that plane + btSpatialMotionVector m_axes[6]; + void setAxisTop(int dof, const btVector3 &axis) { m_axes[dof].m_topVec = axis; } + void setAxisBottom(int dof, const btVector3 &axis) + { + m_axes[dof].m_bottomVec = axis; + } + void setAxisTop(int dof, const btScalar &x, const btScalar &y, const btScalar &z) + { + m_axes[dof].m_topVec.setValue(x, y, z); + } + void setAxisBottom(int dof, const btScalar &x, const btScalar &y, const btScalar &z) + { + m_axes[dof].m_bottomVec.setValue(x, y, z); + } + const btVector3 & getAxisTop(int dof) const { return m_axes[dof].m_topVec; } + const btVector3 & getAxisBottom(int dof) const { return m_axes[dof].m_bottomVec; } + + int m_dofOffset, m_cfgOffset; + + btQuaternion m_cachedRotParentToThis; // rotates vectors in parent frame to vectors in local frame + btVector3 m_cachedRVector; // vector from COM of parent to COM of this link, in local frame. + + btVector3 m_appliedForce; // In WORLD frame + btVector3 m_appliedTorque; // In WORLD frame + +btVector3 m_appliedConstraintForce; // In WORLD frame + btVector3 m_appliedConstraintTorque; // In WORLD frame + + btScalar m_jointPos[7]; + + //m_jointTorque is the joint torque applied by the user using 'addJointTorque'. + //It gets set to zero after each internal stepSimulation call + btScalar m_jointTorque[6]; + + class btMultiBodyLinkCollider* m_collider; + int m_flags; + + + int m_dofCount, m_posVarCount; //redundant but handy + + eFeatherstoneJointType m_jointType; + + struct btMultiBodyJointFeedback* m_jointFeedback; + + btTransform m_cachedWorldTransform;//this cache is updated when calling btMultiBody::forwardKinematics + + const char* m_linkName;//m_linkName memory needs to be managed by the developer/user! + const char* m_jointName;//m_jointName memory needs to be managed by the developer/user! + const void* m_userPtr;//m_userPtr ptr needs to be managed by the developer/user! + + btScalar m_jointDamping; //todo: implement this internally. It is unused for now, it is set by a URDF loader. User can apply manual damping. + btScalar m_jointFriction; //todo: implement this internally. It is unused for now, it is set by a URDF loader. User can apply manual friction using a velocity motor. + btScalar m_jointLowerLimit; //todo: implement this internally. It is unused for now, it is set by a URDF loader. + btScalar m_jointUpperLimit; //todo: implement this internally. It is unused for now, it is set by a URDF loader. + btScalar m_jointMaxForce; //todo: implement this internally. It is unused for now, it is set by a URDF loader. + btScalar m_jointMaxVelocity;//todo: implement this internally. It is unused for now, it is set by a URDF loader. + + // ctor: set some sensible defaults + btMultibodyLink() + : m_mass(1), + m_parent(-1), + m_zeroRotParentToThis(0, 0, 0, 1), + m_cachedRotParentToThis(0, 0, 0, 1), + m_collider(0), + m_flags(0), + m_dofCount(0), + m_posVarCount(0), + m_jointType(btMultibodyLink::eInvalid), + m_jointFeedback(0), + m_linkName(0), + m_jointName(0), + m_userPtr(0), + m_jointDamping(0), + m_jointFriction(0), + m_jointLowerLimit(0), + m_jointUpperLimit(0), + m_jointMaxForce(0), + m_jointMaxVelocity(0) + { + + m_inertiaLocal.setValue(1, 1, 1); + setAxisTop(0, 0., 0., 0.); + setAxisBottom(0, 1., 0., 0.); + m_dVector.setValue(0, 0, 0); + m_eVector.setValue(0, 0, 0); + m_cachedRVector.setValue(0, 0, 0); + m_appliedForce.setValue( 0, 0, 0); + m_appliedTorque.setValue(0, 0, 0); + // + m_jointPos[0] = m_jointPos[1] = m_jointPos[2] = m_jointPos[4] = m_jointPos[5] = m_jointPos[6] = 0.f; + m_jointPos[3] = 1.f; //"quat.w" + m_jointTorque[0] = m_jointTorque[1] = m_jointTorque[2] = m_jointTorque[3] = m_jointTorque[4] = m_jointTorque[5] = 0.f; + m_cachedWorldTransform.setIdentity(); + } + + // routine to update m_cachedRotParentToThis and m_cachedRVector + void updateCacheMultiDof(btScalar *pq = 0) + { + btScalar *pJointPos = (pq ? pq : &m_jointPos[0]); + + switch(m_jointType) + { + case eRevolute: + { + m_cachedRotParentToThis = btQuaternion(getAxisTop(0),-pJointPos[0]) * m_zeroRotParentToThis; + m_cachedRVector = m_dVector + quatRotate(m_cachedRotParentToThis,m_eVector); + + break; + } + case ePrismatic: + { + // m_cachedRotParentToThis never changes, so no need to update + m_cachedRVector = m_dVector + quatRotate(m_cachedRotParentToThis,m_eVector) + pJointPos[0] * getAxisBottom(0); + + break; + } + case eSpherical: + { + m_cachedRotParentToThis = btQuaternion(pJointPos[0], pJointPos[1], pJointPos[2], -pJointPos[3]) * m_zeroRotParentToThis; + m_cachedRVector = m_dVector + quatRotate(m_cachedRotParentToThis,m_eVector); + + break; + } + case ePlanar: + { + m_cachedRotParentToThis = btQuaternion(getAxisTop(0),-pJointPos[0]) * m_zeroRotParentToThis; + m_cachedRVector = quatRotate(btQuaternion(getAxisTop(0),-pJointPos[0]), pJointPos[1] * getAxisBottom(1) + pJointPos[2] * getAxisBottom(2)) + quatRotate(m_cachedRotParentToThis,m_eVector); + + break; + } + case eFixed: + { + m_cachedRotParentToThis = m_zeroRotParentToThis; + m_cachedRVector = m_dVector + quatRotate(m_cachedRotParentToThis,m_eVector); + + break; + } + default: + { + //invalid type + btAssert(0); + } + } + } +}; + + +#endif //BT_MULTIBODY_LINK_H diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h similarity index 74% rename from extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h rename to extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h index 5080ea874541..671e15d314d4 100644 --- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h +++ b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyLinkCollider.h @@ -4,8 +4,8 @@ Copyright (c) 2013 Erwin Coumans http://bulletphysics.org 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, +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. @@ -74,15 +74,48 @@ class btMultiBodyLinkCollider : public btCollisionObject if (m_link>=0) { const btMultibodyLink& link = m_multiBody->getLink(this->m_link); - if ((link.m_flags&BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION) && link.m_parent == other->m_link) - return false; + if (link.m_flags&BT_MULTIBODYLINKFLAGS_DISABLE_ALL_PARENT_COLLISION) + { + int parent_of_this = m_link; + while (1) + { + if (parent_of_this==-1) + break; + parent_of_this = m_multiBody->getLink(parent_of_this).m_parent; + if (parent_of_this==other->m_link) + { + return false; + } + } + } + else if (link.m_flags&BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION) + { + if ( link.m_parent == other->m_link) + return false; + } + } - + if (other->m_link>=0) { const btMultibodyLink& otherLink = other->m_multiBody->getLink(other->m_link); - if ((otherLink.m_flags& BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION) && otherLink.m_parent == this->m_link) - return false; + if (otherLink.m_flags& BT_MULTIBODYLINKFLAGS_DISABLE_ALL_PARENT_COLLISION) + { + int parent_of_other = other->m_link; + while (1) + { + if (parent_of_other==-1) + break; + parent_of_other = m_multiBody->getLink(parent_of_other).m_parent; + if (parent_of_other==this->m_link) + return false; + } + } + else if (otherLink.m_flags& BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION) + { + if (otherLink.m_parent == this->m_link) + return false; + } } return true; } diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp similarity index 95% rename from extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp rename to extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp index 12b21f74603a..3e28f80dfa4e 100644 --- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp +++ b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp @@ -1,221 +1,221 @@ -/* -Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2013 Erwin Coumans http://bulletphysics.org - -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. -*/ - -///This file was written by Erwin Coumans - -#include "btMultiBodyPoint2Point.h" -#include "btMultiBodyLinkCollider.h" -#include "BulletDynamics/Dynamics/btRigidBody.h" -#include "LinearMath/btIDebugDraw.h" - -#ifndef BTMBP2PCONSTRAINT_BLOCK_ANGULAR_MOTION_TEST - #define BTMBP2PCONSTRAINT_DIM 3 -#else - #define BTMBP2PCONSTRAINT_DIM 6 -#endif - -btMultiBodyPoint2Point::btMultiBodyPoint2Point(btMultiBody* body, int link, btRigidBody* bodyB, const btVector3& pivotInA, const btVector3& pivotInB) - :btMultiBodyConstraint(body,0,link,-1,BTMBP2PCONSTRAINT_DIM,false), - m_rigidBodyA(0), - m_rigidBodyB(bodyB), - m_pivotInA(pivotInA), - m_pivotInB(pivotInB) -{ - m_data.resize(BTMBP2PCONSTRAINT_DIM);//at least store the applied impulses -} - -btMultiBodyPoint2Point::btMultiBodyPoint2Point(btMultiBody* bodyA, int linkA, btMultiBody* bodyB, int linkB, const btVector3& pivotInA, const btVector3& pivotInB) - :btMultiBodyConstraint(bodyA,bodyB,linkA,linkB,BTMBP2PCONSTRAINT_DIM,false), - m_rigidBodyA(0), - m_rigidBodyB(0), - m_pivotInA(pivotInA), - m_pivotInB(pivotInB) -{ - m_data.resize(BTMBP2PCONSTRAINT_DIM);//at least store the applied impulses -} - -void btMultiBodyPoint2Point::finalizeMultiDof() -{ - //not implemented yet - btAssert(0); -} - -btMultiBodyPoint2Point::~btMultiBodyPoint2Point() -{ -} - - -int btMultiBodyPoint2Point::getIslandIdA() const -{ - if (m_rigidBodyA) - return m_rigidBodyA->getIslandTag(); - - if (m_bodyA) - { - btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider(); - if (col) - return col->getIslandTag(); - for (int i=0;igetNumLinks();i++) - { - if (m_bodyA->getLink(i).m_collider) - return m_bodyA->getLink(i).m_collider->getIslandTag(); - } - } - return -1; -} - -int btMultiBodyPoint2Point::getIslandIdB() const -{ - if (m_rigidBodyB) - return m_rigidBodyB->getIslandTag(); - if (m_bodyB) - { - btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider(); - if (col) - return col->getIslandTag(); - - for (int i=0;igetNumLinks();i++) - { - col = m_bodyB->getLink(i).m_collider; - if (col) - return col->getIslandTag(); - } - } - return -1; -} - - - -void btMultiBodyPoint2Point::createConstraintRows(btMultiBodyConstraintArray& constraintRows, - btMultiBodyJacobianData& data, - const btContactSolverInfo& infoGlobal) -{ - -// int i=1; -int numDim = BTMBP2PCONSTRAINT_DIM; - for (int i=0;igetCompanionId(); - pivotAworld = m_rigidBodyA->getCenterOfMassTransform()*m_pivotInA; - } else - { - if (m_bodyA) - pivotAworld = m_bodyA->localPosToWorld(m_linkA, m_pivotInA); - } - btVector3 pivotBworld = m_pivotInB; - if (m_rigidBodyB) - { - constraintRow.m_solverBodyIdB = m_rigidBodyB->getCompanionId(); - pivotBworld = m_rigidBodyB->getCenterOfMassTransform()*m_pivotInB; - } else - { - if (m_bodyB) - pivotBworld = m_bodyB->localPosToWorld(m_linkB, m_pivotInB); - - } - - btScalar posError = i < 3 ? (pivotAworld-pivotBworld).dot(contactNormalOnB) : 0; - -#ifndef BTMBP2PCONSTRAINT_BLOCK_ANGULAR_MOTION_TEST - - - fillMultiBodyConstraint(constraintRow, data, 0, 0, - contactNormalOnB, pivotAworld, pivotBworld, //sucks but let it be this way "for the time being" - posError, - infoGlobal, - -m_maxAppliedImpulse, m_maxAppliedImpulse - ); - //@todo: support the case of btMultiBody versus btRigidBody, - //see btPoint2PointConstraint::getInfo2NonVirtual -#else - const btVector3 dummy(0, 0, 0); - - btAssert(m_bodyA->isMultiDof()); - - btScalar* jac1 = jacobianA(i); - const btVector3 &normalAng = i >= 3 ? contactNormalOnB : dummy; - const btVector3 &normalLin = i < 3 ? contactNormalOnB : dummy; - - m_bodyA->filConstraintJacobianMultiDof(m_linkA, pivotAworld, normalAng, normalLin, jac1, data.scratch_r, data.scratch_v, data.scratch_m); - - fillMultiBodyConstraint(constraintRow, data, jac1, 0, - dummy, dummy, dummy, //sucks but let it be this way "for the time being" - posError, - infoGlobal, - -m_maxAppliedImpulse, m_maxAppliedImpulse - ); -#endif - } -} - -void btMultiBodyPoint2Point::debugDraw(class btIDebugDraw* drawer) -{ - btTransform tr; - tr.setIdentity(); - - if (m_rigidBodyA) - { - btVector3 pivot = m_rigidBodyA->getCenterOfMassTransform() * m_pivotInA; - tr.setOrigin(pivot); - drawer->drawTransform(tr, 0.1); - } - if (m_bodyA) - { - btVector3 pivotAworld = m_bodyA->localPosToWorld(m_linkA, m_pivotInA); - tr.setOrigin(pivotAworld); - drawer->drawTransform(tr, 0.1); - } - if (m_rigidBodyB) - { - // that ideally should draw the same frame - btVector3 pivot = m_rigidBodyB->getCenterOfMassTransform() * m_pivotInB; - tr.setOrigin(pivot); - drawer->drawTransform(tr, 0.1); - } - if (m_bodyB) - { - btVector3 pivotBworld = m_bodyB->localPosToWorld(m_linkB, m_pivotInB); - tr.setOrigin(pivotBworld); - drawer->drawTransform(tr, 0.1); - } -} +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2013 Erwin Coumans http://bulletphysics.org + +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. +*/ + +///This file was written by Erwin Coumans + +#include "btMultiBodyPoint2Point.h" +#include "btMultiBodyLinkCollider.h" +#include "BulletDynamics/Dynamics/btRigidBody.h" +#include "LinearMath/btIDebugDraw.h" + +#ifndef BTMBP2PCONSTRAINT_BLOCK_ANGULAR_MOTION_TEST + #define BTMBP2PCONSTRAINT_DIM 3 +#else + #define BTMBP2PCONSTRAINT_DIM 6 +#endif + +btMultiBodyPoint2Point::btMultiBodyPoint2Point(btMultiBody* body, int link, btRigidBody* bodyB, const btVector3& pivotInA, const btVector3& pivotInB) + :btMultiBodyConstraint(body,0,link,-1,BTMBP2PCONSTRAINT_DIM,false), + m_rigidBodyA(0), + m_rigidBodyB(bodyB), + m_pivotInA(pivotInA), + m_pivotInB(pivotInB) +{ + m_data.resize(BTMBP2PCONSTRAINT_DIM);//at least store the applied impulses +} + +btMultiBodyPoint2Point::btMultiBodyPoint2Point(btMultiBody* bodyA, int linkA, btMultiBody* bodyB, int linkB, const btVector3& pivotInA, const btVector3& pivotInB) + :btMultiBodyConstraint(bodyA,bodyB,linkA,linkB,BTMBP2PCONSTRAINT_DIM,false), + m_rigidBodyA(0), + m_rigidBodyB(0), + m_pivotInA(pivotInA), + m_pivotInB(pivotInB) +{ + m_data.resize(BTMBP2PCONSTRAINT_DIM);//at least store the applied impulses +} + +void btMultiBodyPoint2Point::finalizeMultiDof() +{ + //not implemented yet + btAssert(0); +} + +btMultiBodyPoint2Point::~btMultiBodyPoint2Point() +{ +} + + +int btMultiBodyPoint2Point::getIslandIdA() const +{ + if (m_rigidBodyA) + return m_rigidBodyA->getIslandTag(); + + if (m_bodyA) + { + btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider(); + if (col) + return col->getIslandTag(); + for (int i=0;igetNumLinks();i++) + { + if (m_bodyA->getLink(i).m_collider) + return m_bodyA->getLink(i).m_collider->getIslandTag(); + } + } + return -1; +} + +int btMultiBodyPoint2Point::getIslandIdB() const +{ + if (m_rigidBodyB) + return m_rigidBodyB->getIslandTag(); + if (m_bodyB) + { + btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider(); + if (col) + return col->getIslandTag(); + + for (int i=0;igetNumLinks();i++) + { + col = m_bodyB->getLink(i).m_collider; + if (col) + return col->getIslandTag(); + } + } + return -1; +} + + + +void btMultiBodyPoint2Point::createConstraintRows(btMultiBodyConstraintArray& constraintRows, + btMultiBodyJacobianData& data, + const btContactSolverInfo& infoGlobal) +{ + +// int i=1; +int numDim = BTMBP2PCONSTRAINT_DIM; + for (int i=0;igetCompanionId(); + pivotAworld = m_rigidBodyA->getCenterOfMassTransform()*m_pivotInA; + } else + { + if (m_bodyA) + pivotAworld = m_bodyA->localPosToWorld(m_linkA, m_pivotInA); + } + btVector3 pivotBworld = m_pivotInB; + if (m_rigidBodyB) + { + constraintRow.m_solverBodyIdB = m_rigidBodyB->getCompanionId(); + pivotBworld = m_rigidBodyB->getCenterOfMassTransform()*m_pivotInB; + } else + { + if (m_bodyB) + pivotBworld = m_bodyB->localPosToWorld(m_linkB, m_pivotInB); + + } + + btScalar posError = i < 3 ? (pivotAworld-pivotBworld).dot(contactNormalOnB) : 0; + +#ifndef BTMBP2PCONSTRAINT_BLOCK_ANGULAR_MOTION_TEST + + + fillMultiBodyConstraint(constraintRow, data, 0, 0, btVector3(0,0,0), + contactNormalOnB, pivotAworld, pivotBworld, //sucks but let it be this way "for the time being" + posError, + infoGlobal, + -m_maxAppliedImpulse, m_maxAppliedImpulse + ); + //@todo: support the case of btMultiBody versus btRigidBody, + //see btPoint2PointConstraint::getInfo2NonVirtual +#else + const btVector3 dummy(0, 0, 0); + + btAssert(m_bodyA->isMultiDof()); + + btScalar* jac1 = jacobianA(i); + const btVector3 &normalAng = i >= 3 ? contactNormalOnB : dummy; + const btVector3 &normalLin = i < 3 ? contactNormalOnB : dummy; + + m_bodyA->filConstraintJacobianMultiDof(m_linkA, pivotAworld, normalAng, normalLin, jac1, data.scratch_r, data.scratch_v, data.scratch_m); + + fillMultiBodyConstraint(constraintRow, data, jac1, 0, + dummy, dummy, dummy, //sucks but let it be this way "for the time being" + posError, + infoGlobal, + -m_maxAppliedImpulse, m_maxAppliedImpulse + ); +#endif + } +} + +void btMultiBodyPoint2Point::debugDraw(class btIDebugDraw* drawer) +{ + btTransform tr; + tr.setIdentity(); + + if (m_rigidBodyA) + { + btVector3 pivot = m_rigidBodyA->getCenterOfMassTransform() * m_pivotInA; + tr.setOrigin(pivot); + drawer->drawTransform(tr, 0.1); + } + if (m_bodyA) + { + btVector3 pivotAworld = m_bodyA->localPosToWorld(m_linkA, m_pivotInA); + tr.setOrigin(pivotAworld); + drawer->drawTransform(tr, 0.1); + } + if (m_rigidBodyB) + { + // that ideally should draw the same frame + btVector3 pivot = m_rigidBodyB->getCenterOfMassTransform() * m_pivotInB; + tr.setOrigin(pivot); + drawer->drawTransform(tr, 0.1); + } + if (m_bodyB) + { + btVector3 pivotBworld = m_bodyB->localPosToWorld(m_linkB, m_pivotInB); + tr.setOrigin(pivotBworld); + drawer->drawTransform(tr, 0.1); + } +} diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.h b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.h similarity index 92% rename from extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.h rename to extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.h index b2e219ac1590..bf39acc5b95f 100644 --- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.h +++ b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.h @@ -22,7 +22,7 @@ subject to the following restrictions: //#define BTMBP2PCONSTRAINT_BLOCK_ANGULAR_MOTION_TEST -class btMultiBodyPoint2Point : public btMultiBodyConstraint +ATTRIBUTE_ALIGNED16(class) btMultiBodyPoint2Point : public btMultiBodyConstraint { protected: @@ -34,6 +34,8 @@ class btMultiBodyPoint2Point : public btMultiBodyConstraint public: + BT_DECLARE_ALIGNED_ALLOCATOR(); + btMultiBodyPoint2Point(btMultiBody* body, int link, btRigidBody* bodyB, const btVector3& pivotInA, const btVector3& pivotInB); btMultiBodyPoint2Point(btMultiBody* bodyA, int linkA, btMultiBody* bodyB, int linkB, const btVector3& pivotInA, const btVector3& pivotInB); @@ -53,11 +55,12 @@ class btMultiBodyPoint2Point : public btMultiBodyConstraint return m_pivotInB; } - void setPivotInB(const btVector3& pivotInB) + virtual void setPivotInB(const btVector3& pivotInB) { m_pivotInB = pivotInB; } + virtual void debugDraw(class btIDebugDraw* drawer); }; diff --git a/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp new file mode 100644 index 000000000000..67b106f28f80 --- /dev/null +++ b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodySliderConstraint.cpp @@ -0,0 +1,230 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2013 Erwin Coumans http://bulletphysics.org + +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. +*/ + +///This file was written by Erwin Coumans + +#include "btMultiBodySliderConstraint.h" +#include "btMultiBodyLinkCollider.h" +#include "BulletDynamics/Dynamics/btRigidBody.h" +#include "BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h" +#include "LinearMath/btIDebugDraw.h" + +#define BTMBSLIDERCONSTRAINT_DIM 5 +#define EPSILON 0.000001 + +btMultiBodySliderConstraint::btMultiBodySliderConstraint(btMultiBody* body, int link, btRigidBody* bodyB, const btVector3& pivotInA, const btVector3& pivotInB, const btMatrix3x3& frameInA, const btMatrix3x3& frameInB, const btVector3& jointAxis) + :btMultiBodyConstraint(body,0,link,-1,BTMBSLIDERCONSTRAINT_DIM,false), + m_rigidBodyA(0), + m_rigidBodyB(bodyB), + m_pivotInA(pivotInA), + m_pivotInB(pivotInB), + m_frameInA(frameInA), + m_frameInB(frameInB), + m_jointAxis(jointAxis) +{ + m_data.resize(BTMBSLIDERCONSTRAINT_DIM);//at least store the applied impulses +} + +btMultiBodySliderConstraint::btMultiBodySliderConstraint(btMultiBody* bodyA, int linkA, btMultiBody* bodyB, int linkB, const btVector3& pivotInA, const btVector3& pivotInB, const btMatrix3x3& frameInA, const btMatrix3x3& frameInB, const btVector3& jointAxis) + :btMultiBodyConstraint(bodyA,bodyB,linkA,linkB,BTMBSLIDERCONSTRAINT_DIM,false), + m_rigidBodyA(0), + m_rigidBodyB(0), + m_pivotInA(pivotInA), + m_pivotInB(pivotInB), + m_frameInA(frameInA), + m_frameInB(frameInB), + m_jointAxis(jointAxis) +{ + m_data.resize(BTMBSLIDERCONSTRAINT_DIM);//at least store the applied impulses +} + +void btMultiBodySliderConstraint::finalizeMultiDof() +{ + //not implemented yet + btAssert(0); +} + +btMultiBodySliderConstraint::~btMultiBodySliderConstraint() +{ +} + + +int btMultiBodySliderConstraint::getIslandIdA() const +{ + if (m_rigidBodyA) + return m_rigidBodyA->getIslandTag(); + + if (m_bodyA) + { + btMultiBodyLinkCollider* col = m_bodyA->getBaseCollider(); + if (col) + return col->getIslandTag(); + for (int i=0;igetNumLinks();i++) + { + if (m_bodyA->getLink(i).m_collider) + return m_bodyA->getLink(i).m_collider->getIslandTag(); + } + } + return -1; +} + +int btMultiBodySliderConstraint::getIslandIdB() const +{ + if (m_rigidBodyB) + return m_rigidBodyB->getIslandTag(); + if (m_bodyB) + { + btMultiBodyLinkCollider* col = m_bodyB->getBaseCollider(); + if (col) + return col->getIslandTag(); + + for (int i=0;igetNumLinks();i++) + { + col = m_bodyB->getLink(i).m_collider; + if (col) + return col->getIslandTag(); + } + } + return -1; +} + +void btMultiBodySliderConstraint::createConstraintRows(btMultiBodyConstraintArray& constraintRows, btMultiBodyJacobianData& data, const btContactSolverInfo& infoGlobal) +{ + // Convert local points back to world + btVector3 pivotAworld = m_pivotInA; + btMatrix3x3 frameAworld = m_frameInA; + btVector3 jointAxis = m_jointAxis; + if (m_rigidBodyA) + { + pivotAworld = m_rigidBodyA->getCenterOfMassTransform()*m_pivotInA; + frameAworld = m_frameInA.transpose()*btMatrix3x3(m_rigidBodyA->getOrientation()); + jointAxis = quatRotate(m_rigidBodyA->getOrientation(),m_jointAxis); + + } else if (m_bodyA) { + pivotAworld = m_bodyA->localPosToWorld(m_linkA, m_pivotInA); + frameAworld = m_bodyA->localFrameToWorld(m_linkA, m_frameInA); + jointAxis = m_bodyA->localDirToWorld(m_linkA, m_jointAxis); + } + btVector3 pivotBworld = m_pivotInB; + btMatrix3x3 frameBworld = m_frameInB; + if (m_rigidBodyB) + { + pivotBworld = m_rigidBodyB->getCenterOfMassTransform()*m_pivotInB; + frameBworld = m_frameInB.transpose()*btMatrix3x3(m_rigidBodyB->getOrientation()); + + } else if (m_bodyB) { + pivotBworld = m_bodyB->localPosToWorld(m_linkB, m_pivotInB); + frameBworld = m_bodyB->localFrameToWorld(m_linkB, m_frameInB); + } + + btVector3 constraintAxis[2]; + for (int i = 0; i < 3; ++i) + { + constraintAxis[0] = frameAworld.getColumn(i).cross(jointAxis); + if (constraintAxis[0].safeNorm() > EPSILON) + { + constraintAxis[0] = constraintAxis[0].normalized(); + constraintAxis[1] = jointAxis.cross(constraintAxis[0]); + constraintAxis[1] = constraintAxis[1].normalized(); + break; + } + } + + btMatrix3x3 relRot = frameAworld.inverse()*frameBworld; + btVector3 angleDiff; + btGeneric6DofSpring2Constraint::matrixToEulerXYZ(relRot,angleDiff); + + int numDim = BTMBSLIDERCONSTRAINT_DIM; + for (int i=0;igetCompanionId(); + } + if (m_rigidBodyB) + { + constraintRow.m_solverBodyIdB = m_rigidBodyB->getCompanionId(); + } + + btVector3 constraintNormalLin(0,0,0); + btVector3 constraintNormalAng(0,0,0); + btScalar posError = 0.0; + if (i < 2) { + constraintNormalLin = constraintAxis[i]; + posError = (pivotAworld-pivotBworld).dot(constraintNormalLin); + fillMultiBodyConstraint(constraintRow, data, 0, 0, constraintNormalAng, + constraintNormalLin, pivotAworld, pivotBworld, + posError, + infoGlobal, + -m_maxAppliedImpulse, m_maxAppliedImpulse + ); + } + else { //i>=2 + constraintNormalAng = frameAworld.getColumn(i%3); + posError = angleDiff[i%3]; + fillMultiBodyConstraint(constraintRow, data, 0, 0, constraintNormalAng, + constraintNormalLin, pivotAworld, pivotBworld, + posError, + infoGlobal, + -m_maxAppliedImpulse, m_maxAppliedImpulse, true + ); + } + } +} + +void btMultiBodySliderConstraint::debugDraw(class btIDebugDraw* drawer) +{ + btTransform tr; + tr.setIdentity(); + + if (m_rigidBodyA) + { + btVector3 pivot = m_rigidBodyA->getCenterOfMassTransform() * m_pivotInA; + tr.setOrigin(pivot); + drawer->drawTransform(tr, 0.1); + } + if (m_bodyA) + { + btVector3 pivotAworld = m_bodyA->localPosToWorld(m_linkA, m_pivotInA); + tr.setOrigin(pivotAworld); + drawer->drawTransform(tr, 0.1); + } + if (m_rigidBodyB) + { + // that ideally should draw the same frame + btVector3 pivot = m_rigidBodyB->getCenterOfMassTransform() * m_pivotInB; + tr.setOrigin(pivot); + drawer->drawTransform(tr, 0.1); + } + if (m_bodyB) + { + btVector3 pivotBworld = m_bodyB->localPosToWorld(m_linkB, m_pivotInB); + tr.setOrigin(pivotBworld); + drawer->drawTransform(tr, 0.1); + } +} diff --git a/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodySliderConstraint.h b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodySliderConstraint.h new file mode 100644 index 000000000000..0a6cf3df12b5 --- /dev/null +++ b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodySliderConstraint.h @@ -0,0 +1,105 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2013 Erwin Coumans http://bulletphysics.org + +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. +*/ + +///This file was written by Erwin Coumans + +#ifndef BT_MULTIBODY_SLIDER_CONSTRAINT_H +#define BT_MULTIBODY_SLIDER_CONSTRAINT_H + +#include "btMultiBodyConstraint.h" + +class btMultiBodySliderConstraint : public btMultiBodyConstraint +{ +protected: + + btRigidBody* m_rigidBodyA; + btRigidBody* m_rigidBodyB; + btVector3 m_pivotInA; + btVector3 m_pivotInB; + btMatrix3x3 m_frameInA; + btMatrix3x3 m_frameInB; + btVector3 m_jointAxis; + +public: + + btMultiBodySliderConstraint(btMultiBody* body, int link, btRigidBody* bodyB, const btVector3& pivotInA, const btVector3& pivotInB, const btMatrix3x3& frameInA, const btMatrix3x3& frameInB, const btVector3& jointAxis); + btMultiBodySliderConstraint(btMultiBody* bodyA, int linkA, btMultiBody* bodyB, int linkB, const btVector3& pivotInA, const btVector3& pivotInB, const btMatrix3x3& frameInA, const btMatrix3x3& frameInB, const btVector3& jointAxis); + + virtual ~btMultiBodySliderConstraint(); + + virtual void finalizeMultiDof(); + + virtual int getIslandIdA() const; + virtual int getIslandIdB() const; + + virtual void createConstraintRows(btMultiBodyConstraintArray& constraintRows, + btMultiBodyJacobianData& data, + const btContactSolverInfo& infoGlobal); + + const btVector3& getPivotInA() const + { + return m_pivotInA; + } + + void setPivotInA(const btVector3& pivotInA) + { + m_pivotInA = pivotInA; + } + + const btVector3& getPivotInB() const + { + return m_pivotInB; + } + + virtual void setPivotInB(const btVector3& pivotInB) + { + m_pivotInB = pivotInB; + } + + const btMatrix3x3& getFrameInA() const + { + return m_frameInA; + } + + void setFrameInA(const btMatrix3x3& frameInA) + { + m_frameInA = frameInA; + } + + const btMatrix3x3& getFrameInB() const + { + return m_frameInB; + } + + virtual void setFrameInB(const btMatrix3x3& frameInB) + { + m_frameInB = frameInB; + } + + const btVector3& getJointAxis() const + { + return m_jointAxis; + } + + void setJointAxis(const btVector3& jointAxis) + { + m_jointAxis = jointAxis; + } + + virtual void debugDraw(class btIDebugDraw* drawer); + +}; + +#endif //BT_MULTIBODY_SLIDER_CONSTRAINT_H diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodySolverConstraint.h b/extern/bullet/src/BulletDynamics/Featherstone/btMultiBodySolverConstraint.h similarity index 100% rename from extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodySolverConstraint.h rename to extern/bullet/src/BulletDynamics/Featherstone/btMultiBodySolverConstraint.h diff --git a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btDantzigLCP.cpp b/extern/bullet/src/BulletDynamics/MLCPSolvers/btDantzigLCP.cpp similarity index 100% rename from extern/bullet2/src/BulletDynamics/MLCPSolvers/btDantzigLCP.cpp rename to extern/bullet/src/BulletDynamics/MLCPSolvers/btDantzigLCP.cpp diff --git a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btDantzigLCP.h b/extern/bullet/src/BulletDynamics/MLCPSolvers/btDantzigLCP.h similarity index 100% rename from extern/bullet2/src/BulletDynamics/MLCPSolvers/btDantzigLCP.h rename to extern/bullet/src/BulletDynamics/MLCPSolvers/btDantzigLCP.h diff --git a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btDantzigSolver.h b/extern/bullet/src/BulletDynamics/MLCPSolvers/btDantzigSolver.h similarity index 100% rename from extern/bullet2/src/BulletDynamics/MLCPSolvers/btDantzigSolver.h rename to extern/bullet/src/BulletDynamics/MLCPSolvers/btDantzigSolver.h diff --git a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btLemkeAlgorithm.cpp b/extern/bullet/src/BulletDynamics/MLCPSolvers/btLemkeAlgorithm.cpp similarity index 100% rename from extern/bullet2/src/BulletDynamics/MLCPSolvers/btLemkeAlgorithm.cpp rename to extern/bullet/src/BulletDynamics/MLCPSolvers/btLemkeAlgorithm.cpp diff --git a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btLemkeAlgorithm.h b/extern/bullet/src/BulletDynamics/MLCPSolvers/btLemkeAlgorithm.h similarity index 100% rename from extern/bullet2/src/BulletDynamics/MLCPSolvers/btLemkeAlgorithm.h rename to extern/bullet/src/BulletDynamics/MLCPSolvers/btLemkeAlgorithm.h diff --git a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btLemkeSolver.h b/extern/bullet/src/BulletDynamics/MLCPSolvers/btLemkeSolver.h similarity index 100% rename from extern/bullet2/src/BulletDynamics/MLCPSolvers/btLemkeSolver.h rename to extern/bullet/src/BulletDynamics/MLCPSolvers/btLemkeSolver.h diff --git a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btMLCPSolver.cpp b/extern/bullet/src/BulletDynamics/MLCPSolvers/btMLCPSolver.cpp similarity index 97% rename from extern/bullet2/src/BulletDynamics/MLCPSolvers/btMLCPSolver.cpp rename to extern/bullet/src/BulletDynamics/MLCPSolvers/btMLCPSolver.cpp index 6688694a9282..8f54c5262697 100644 --- a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btMLCPSolver.cpp +++ b/extern/bullet/src/BulletDynamics/MLCPSolvers/btMLCPSolver.cpp @@ -22,8 +22,7 @@ subject to the following restrictions: btMLCPSolver::btMLCPSolver( btMLCPSolverInterface* solver) :m_solver(solver), -m_fallback(0), -m_cfm(0.000001)//0.0000001 +m_fallback(0) { } @@ -216,12 +215,12 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal) jointNodeArray.reserve(2*m_allConstraintPtrArray.size()); } - static btMatrixXu J3; + btMatrixXu& J3 = m_scratchJ3; { BT_PROFILE("J3.resize"); J3.resize(2*m,8); } - static btMatrixXu JinvM3; + btMatrixXu& JinvM3 = m_scratchJInvM3; { BT_PROFILE("JinvM3.resize/setZero"); @@ -231,7 +230,7 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal) } int cur=0; int rowOffset = 0; - static btAlignedObjectArray ofs; + btAlignedObjectArray& ofs = m_scratchOfs; { BT_PROFILE("ofs resize"); ofs.resize(0); @@ -436,7 +435,7 @@ void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal) // add cfm to the diagonal of m_A for ( int i=0; igetInvInertiaTensorWorld()[r][c] : 0); } - static btMatrixXu J; + btMatrixXu& J = m_scratchJ; J.resize(numConstraintRows,6*numBodies); J.setZero(); @@ -542,10 +541,10 @@ void btMLCPSolver::createMLCP(const btContactSolverInfo& infoGlobal) } } - static btMatrixXu J_transpose; + btMatrixXu& J_transpose = m_scratchJTranspose; J_transpose= J.transpose(); - static btMatrixXu tmp; + btMatrixXu& tmp = m_scratchTmp; { { @@ -564,7 +563,7 @@ void btMLCPSolver::createMLCP(const btContactSolverInfo& infoGlobal) // add cfm to the diagonal of m_A for ( int i=0; i m_allConstraintPtrArray; btMLCPSolverInterface* m_solver; int m_fallback; - btScalar m_cfm; + + /// The following scratch variables are not stateful -- contents are cleared prior to each use. + /// They are only cached here to avoid extra memory allocations and deallocations and to ensure + /// that multiple instances of the solver can be run in parallel. + btMatrixXu m_scratchJ3; + btMatrixXu m_scratchJInvM3; + btAlignedObjectArray m_scratchOfs; + btMatrixXu m_scratchMInv; + btMatrixXu m_scratchJ; + btMatrixXu m_scratchJTranspose; + btMatrixXu m_scratchTmp; virtual btScalar solveGroupCacheFriendlySetup(btCollisionObject** bodies, int numBodies, btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer); virtual btScalar solveGroupCacheFriendlyIterations(btCollisionObject** bodies ,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer); @@ -73,15 +83,6 @@ class btMLCPSolver : public btSequentialImpulseConstraintSolver m_fallback = num; } - btScalar getCfm() const - { - return m_cfm; - } - void setCfm(btScalar cfm) - { - m_cfm = cfm; - } - virtual btConstraintSolverType getSolverType() const { return BT_MLCP_SOLVER; diff --git a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btMLCPSolverInterface.h b/extern/bullet/src/BulletDynamics/MLCPSolvers/btMLCPSolverInterface.h similarity index 100% rename from extern/bullet2/src/BulletDynamics/MLCPSolvers/btMLCPSolverInterface.h rename to extern/bullet/src/BulletDynamics/MLCPSolvers/btMLCPSolverInterface.h diff --git a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btPATHSolver.h b/extern/bullet/src/BulletDynamics/MLCPSolvers/btPATHSolver.h similarity index 100% rename from extern/bullet2/src/BulletDynamics/MLCPSolvers/btPATHSolver.h rename to extern/bullet/src/BulletDynamics/MLCPSolvers/btPATHSolver.h diff --git a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h b/extern/bullet/src/BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h similarity index 80% rename from extern/bullet2/src/BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h rename to extern/bullet/src/BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h index 77cc57c6e0ee..c0b40ffd9f80 100644 --- a/extern/bullet2/src/BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h +++ b/extern/bullet/src/BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h @@ -23,7 +23,18 @@ subject to the following restrictions: ///This solver is mainly for debug/learning purposes: it is functionally equivalent to the btSequentialImpulseConstraintSolver solver, but much slower (it builds the full LCP matrix) class btSolveProjectedGaussSeidel : public btMLCPSolverInterface { + public: + + btScalar m_leastSquaresResidualThreshold; + btScalar m_leastSquaresResidual; + + btSolveProjectedGaussSeidel() + :m_leastSquaresResidualThreshold(0), + m_leastSquaresResidual(0) + { + } + virtual bool solveMLCP(const btMatrixXu & A, const btVectorXu & b, btVectorXu& x, const btVectorXu & lo,const btVectorXu & hi,const btAlignedObjectArray& limitDependency, int numIterations, bool useSparsity = true) { if (!A.rows()) @@ -36,10 +47,11 @@ class btSolveProjectedGaussSeidel : public btMLCPSolverInterface int i, j, numRows = A.rows(); - float delta; + btScalar delta; for (int k = 0; k =0) { @@ -76,6 +89,17 @@ class btSolveProjectedGaussSeidel : public btMLCPSolverInterface x[i]=lo[i]*s; if (x[i]>hi[i]*s) x[i]=hi[i]*s; + btScalar diff = x[i] - xOld; + m_leastSquaresResidual += diff*diff; + } + + btScalar eps = m_leastSquaresResidualThreshold; + if ((m_leastSquaresResidual < eps) || (k >=(numIterations-1))) + { +#ifdef VERBOSE_PRINTF_RESIDUAL + printf("totalLenSqr = %f at iteration #%d\n", m_leastSquaresResidual,k); +#endif + break; } } return true; diff --git a/extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.cpp b/extern/bullet/src/BulletDynamics/Vehicle/btRaycastVehicle.cpp similarity index 100% rename from extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.cpp rename to extern/bullet/src/BulletDynamics/Vehicle/btRaycastVehicle.cpp diff --git a/extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.h b/extern/bullet/src/BulletDynamics/Vehicle/btRaycastVehicle.h similarity index 99% rename from extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.h rename to extern/bullet/src/BulletDynamics/Vehicle/btRaycastVehicle.h index 82d44c73e054..04656b912c7b 100644 --- a/extern/bullet2/src/BulletDynamics/Vehicle/btRaycastVehicle.h +++ b/extern/bullet/src/BulletDynamics/Vehicle/btRaycastVehicle.h @@ -19,7 +19,7 @@ class btDynamicsWorld; #include "btWheelInfo.h" #include "BulletDynamics/Dynamics/btActionInterface.h" -class btVehicleTuning; +//class btVehicleTuning; ///rayCast vehicle, very special constraint that turn a rigidbody into a vehicle. class btRaycastVehicle : public btActionInterface diff --git a/extern/bullet2/src/BulletDynamics/Vehicle/btVehicleRaycaster.h b/extern/bullet/src/BulletDynamics/Vehicle/btVehicleRaycaster.h similarity index 100% rename from extern/bullet2/src/BulletDynamics/Vehicle/btVehicleRaycaster.h rename to extern/bullet/src/BulletDynamics/Vehicle/btVehicleRaycaster.h diff --git a/extern/bullet2/src/BulletDynamics/Vehicle/btWheelInfo.cpp b/extern/bullet/src/BulletDynamics/Vehicle/btWheelInfo.cpp similarity index 100% rename from extern/bullet2/src/BulletDynamics/Vehicle/btWheelInfo.cpp rename to extern/bullet/src/BulletDynamics/Vehicle/btWheelInfo.cpp diff --git a/extern/bullet2/src/BulletDynamics/Vehicle/btWheelInfo.h b/extern/bullet/src/BulletDynamics/Vehicle/btWheelInfo.h similarity index 99% rename from extern/bullet2/src/BulletDynamics/Vehicle/btWheelInfo.h rename to extern/bullet/src/BulletDynamics/Vehicle/btWheelInfo.h index f916053ecac1..f991a57b69e3 100644 --- a/extern/bullet2/src/BulletDynamics/Vehicle/btWheelInfo.h +++ b/extern/bullet/src/BulletDynamics/Vehicle/btWheelInfo.h @@ -79,6 +79,8 @@ struct btWheelInfo void* m_clientInfo;//can be used to store pointer to sync transforms... + btWheelInfo() {} + btWheelInfo(btWheelInfoConstructionInfo& ci) { diff --git a/extern/bullet/src/BulletDynamics/premake4.lua b/extern/bullet/src/BulletDynamics/premake4.lua new file mode 100644 index 000000000000..32414dce3eab --- /dev/null +++ b/extern/bullet/src/BulletDynamics/premake4.lua @@ -0,0 +1,21 @@ + project "BulletDynamics" + kind "StaticLib" + includedirs { + "..", + } + files { + "Dynamics/*.cpp", + "Dynamics/*.h", + "ConstraintSolver/*.cpp", + "ConstraintSolver/*.h", + "Featherstone/*.cpp", + "Featherstone/*.h", + "MLCPSolvers/*.cpp", + "MLCPSolvers/*.h", + "Vehicle/*.cpp", + "Vehicle/*.h", + "Character/*.cpp", + "Character/*.h" + + } + diff --git a/extern/bullet/src/BulletInverseDynamics/CMakeLists.txt b/extern/bullet/src/BulletInverseDynamics/CMakeLists.txt new file mode 100644 index 000000000000..3331c27eac0e --- /dev/null +++ b/extern/bullet/src/BulletInverseDynamics/CMakeLists.txt @@ -0,0 +1,66 @@ +INCLUDE_DIRECTORIES( ${BULLET_PHYSICS_SOURCE_DIR}/src ) + +SET(BulletInverseDynamics_SRCS + IDMath.cpp + MultiBodyTree.cpp + details/MultiBodyTreeInitCache.cpp + details/MultiBodyTreeImpl.cpp +) + +SET(BulletInverseDynamicsRoot_HDRS + IDConfig.hpp + IDConfigEigen.hpp + IDMath.hpp + IDConfigBuiltin.hpp + IDErrorMessages.hpp + MultiBodyTree.hpp +) +SET(BulletInverseDynamicsDetails_HDRS + details/IDEigenInterface.hpp + details/IDMatVec.hpp + details/IDLinearMathInterface.hpp + details/MultiBodyTreeImpl.hpp + details/MultiBodyTreeInitCache.hpp +) + +SET(BulletInverseDynamics_HDRS + ${BulletInverseDynamicsRoot_HDRS} + ${BulletInverseDynamicsDetails_HDRS} +) + + +ADD_LIBRARY(BulletInverseDynamics ${BulletInverseDynamics_SRCS} ${BulletInverseDynamics_HDRS}) +SET_TARGET_PROPERTIES(BulletInverseDynamics PROPERTIES VERSION ${BULLET_VERSION}) +SET_TARGET_PROPERTIES(BulletInverseDynamics PROPERTIES SOVERSION ${BULLET_VERSION}) +IF (BUILD_SHARED_LIBS) + TARGET_LINK_LIBRARIES(BulletInverseDynamics Bullet3Common LinearMath) +ENDIF (BUILD_SHARED_LIBS) + + +IF (INSTALL_LIBS) + IF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) + #INSTALL of other files requires CMake 2.6 + IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS BulletInverseDynamics DESTINATION .) + ELSE (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS BulletInverseDynamics RUNTIME DESTINATION bin + LIBRARY DESTINATION lib${LIB_SUFFIX} + ARCHIVE DESTINATION lib${LIB_SUFFIX}) + INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.h" PATTERN ".svn" EXCLUDE PATTERN "CMakeFiles" EXCLUDE) + INSTALL(FILES ../btBulletCollisionCommon.h +DESTINATION ${INCLUDE_INSTALL_DIR}/BulletInverseDynamics) + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + SET_TARGET_PROPERTIES(BulletInverseDynamics PROPERTIES FRAMEWORK true) + + SET_TARGET_PROPERTIES(BulletInverseDynamics PROPERTIES PUBLIC_HEADER "${BulletInverseDynamicsRoot_HDRS}") + # Have to list out sub-directories manually: + SET_PROPERTY(SOURCE ${BulletInverseDynamicsDetails_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/details) + + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) +ENDIF (INSTALL_LIBS) diff --git a/extern/bullet/src/BulletInverseDynamics/IDConfig.hpp b/extern/bullet/src/BulletInverseDynamics/IDConfig.hpp new file mode 100644 index 000000000000..ebb10e7a16ef --- /dev/null +++ b/extern/bullet/src/BulletInverseDynamics/IDConfig.hpp @@ -0,0 +1,107 @@ +///@file Configuration for Inverse Dynamics Library, +/// such as choice of linear algebra library and underlying scalar type +#ifndef IDCONFIG_HPP_ +#define IDCONFIG_HPP_ + +// If true, enable jacobian calculations. +// This adds a 3xN matrix to every body, + 2 3-Vectors. +// so it is not advised for large systems if it is not absolutely necessary. +// Also, this is not required for standard inverse dynamics calculations. +// Will only work with vector math libraries that support 3xN matrices. +#define BT_ID_WITH_JACOBIANS + +// If we have a custom configuration, compile without using other parts of bullet. +#ifdef BT_CUSTOM_INVERSE_DYNAMICS_CONFIG_H +#include +#define BT_ID_WO_BULLET +#define BT_ID_SQRT(x) std::sqrt(x) +#define BT_ID_FABS(x) std::fabs(x) +#define BT_ID_COS(x) std::cos(x) +#define BT_ID_SIN(x) std::sin(x) +#define BT_ID_ATAN2(x, y) std::atan2(x, y) +#define BT_ID_POW(x, y) std::pow(x, y) +#define BT_ID_SNPRINTF snprintf +#define BT_ID_PI M_PI +#define BT_ID_USE_DOUBLE_PRECISION +#else +#define BT_ID_SQRT(x) btSqrt(x) +#define BT_ID_FABS(x) btFabs(x) +#define BT_ID_COS(x) btCos(x) +#define BT_ID_SIN(x) btSin(x) +#define BT_ID_ATAN2(x, y) btAtan2(x, y) +#define BT_ID_POW(x, y) btPow(x, y) +#define BT_ID_PI SIMD_PI +#ifdef _WIN32 + #define BT_ID_SNPRINTF _snprintf +#else + #define BT_ID_SNPRINTF snprintf +#endif // +#endif +// error messages +#include "IDErrorMessages.hpp" + +#ifdef BT_CUSTOM_INVERSE_DYNAMICS_CONFIG_H +/* +#include "IDConfigEigen.hpp" +#include "IDConfigBuiltin.hpp" +*/ +#define INVDYN_INCLUDE_HELPER_2(x) #x +#define INVDYN_INCLUDE_HELPER(x) INVDYN_INCLUDE_HELPER_2(x) +#include INVDYN_INCLUDE_HELPER(BT_CUSTOM_INVERSE_DYNAMICS_CONFIG_H) +#ifndef btInverseDynamics +#error "custom inverse dynamics config, but no custom namespace defined" +#endif + +#define BT_ID_MAX(a,b) std::max(a,b) +#define BT_ID_MIN(a,b) std::min(a,b) + +#else +#define btInverseDynamics btInverseDynamicsBullet3 +// Use default configuration with bullet's types +// Use the same scalar type as rest of bullet library +#include "LinearMath/btScalar.h" +typedef btScalar idScalar; +#include "LinearMath/btMinMax.h" +#define BT_ID_MAX(a,b) btMax(a,b) +#define BT_ID_MIN(a,b) btMin(a,b) + +#ifdef BT_USE_DOUBLE_PRECISION +#define BT_ID_USE_DOUBLE_PRECISION +#endif + +#ifndef BT_USE_INVERSE_DYNAMICS_WITH_BULLET2 + + +// use bullet types for arrays and array indices +#include "Bullet3Common/b3AlignedObjectArray.h" +// this is to make it work with C++2003, otherwise we could do this: +// template +// using idArray = b3AlignedObjectArray; +template +struct idArray { + typedef b3AlignedObjectArray type; +}; +typedef int idArrayIdx; +#define ID_DECLARE_ALIGNED_ALLOCATOR() B3_DECLARE_ALIGNED_ALLOCATOR() + +#else // BT_USE_INVERSE_DYNAMICS_WITH_BULLET2 + +#include "LinearMath/btAlignedObjectArray.h" +template +struct idArray { + typedef btAlignedObjectArray type; +}; +typedef int idArrayIdx; +#define ID_DECLARE_ALIGNED_ALLOCATOR() BT_DECLARE_ALIGNED_ALLOCATOR() + +#endif // BT_USE_INVERSE_DYNAMICS_WITH_BULLET2 + + +// use bullet's allocator functions +#define idMalloc btAllocFunc +#define idFree btFreeFunc + +#define ID_LINEAR_MATH_USE_BULLET +#include "details/IDLinearMathInterface.hpp" +#endif +#endif diff --git a/extern/bullet/src/BulletInverseDynamics/IDConfigBuiltin.hpp b/extern/bullet/src/BulletInverseDynamics/IDConfigBuiltin.hpp new file mode 100644 index 000000000000..130c19c6d6ff --- /dev/null +++ b/extern/bullet/src/BulletInverseDynamics/IDConfigBuiltin.hpp @@ -0,0 +1,37 @@ +///@file Configuration for Inverse Dynamics Library without external dependencies +#ifndef INVDYNCONFIG_BUILTIN_HPP_ +#define INVDYNCONFIG_BUILTIN_HPP_ +#define btInverseDynamics btInverseDynamicsBuiltin +#ifdef BT_USE_DOUBLE_PRECISION +// choose double/single precision version +typedef double idScalar; +#else +typedef float idScalar; +#endif +// use std::vector for arrays +#include +// this is to make it work with C++2003, otherwise we could do this +// template +// using idArray = std::vector; +template +struct idArray { + typedef std::vector type; +}; +typedef std::vector::size_type idArrayIdx; +// default to standard malloc/free +#include +#define idMalloc ::malloc +#define idFree ::free +// currently not aligned at all... +#define ID_DECLARE_ALIGNED_ALLOCATOR() \ + inline void* operator new(std::size_t sizeInBytes) { return idMalloc(sizeInBytes); } \ + inline void operator delete(void* ptr) { idFree(ptr); } \ + inline void* operator new(std::size_t, void* ptr) { return ptr; } \ + inline void operator delete(void*, void*) {} \ + inline void* operator new[](std::size_t sizeInBytes) { return idMalloc(sizeInBytes); } \ + inline void operator delete[](void* ptr) { idFree(ptr); } \ + inline void* operator new[](std::size_t, void* ptr) { return ptr; } \ + inline void operator delete[](void*, void*) {} + +#include "details/IDMatVec.hpp" +#endif diff --git a/extern/bullet/src/BulletInverseDynamics/IDConfigEigen.hpp b/extern/bullet/src/BulletInverseDynamics/IDConfigEigen.hpp new file mode 100644 index 000000000000..cbd7e8a9c4e2 --- /dev/null +++ b/extern/bullet/src/BulletInverseDynamics/IDConfigEigen.hpp @@ -0,0 +1,31 @@ +///@file Configuration for Inverse Dynamics Library with Eigen +#ifndef INVDYNCONFIG_EIGEN_HPP_ +#define INVDYNCONFIG_EIGEN_HPP_ +#define btInverseDynamics btInverseDynamicsEigen +#ifdef BT_USE_DOUBLE_PRECISION +// choose double/single precision version +typedef double idScalar; +#else +typedef float idScalar; +#endif + +// use std::vector for arrays +#include +// this is to make it work with C++2003, otherwise we could do this +// template +// using idArray = std::vector; +template +struct idArray { + typedef std::vector type; +}; +typedef std::vector::size_type idArrayIdx; +// default to standard malloc/free +#include +#define ID_DECLARE_ALIGNED_ALLOCATOR() EIGEN_MAKE_ALIGNED_OPERATOR_NEW +// Note on interfaces: +// Eigen::Matrix has data(), to get c-array storage +// HOWEVER: default storage is column-major! +#define ID_LINEAR_MATH_USE_EIGEN +#include "Eigen/Eigen" +#include "details/IDEigenInterface.hpp" +#endif diff --git a/extern/bullet/src/BulletInverseDynamics/IDErrorMessages.hpp b/extern/bullet/src/BulletInverseDynamics/IDErrorMessages.hpp new file mode 100644 index 000000000000..1dc22f860ab6 --- /dev/null +++ b/extern/bullet/src/BulletInverseDynamics/IDErrorMessages.hpp @@ -0,0 +1,29 @@ +///@file error message utility functions +#ifndef IDUTILS_HPP_ +#define IDUTILS_HPP_ +#include +/// name of file being compiled, without leading path components +#define __INVDYN_FILE_WO_DIR__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) + +#if !defined(BT_ID_WO_BULLET) && !defined(BT_USE_INVERSE_DYNAMICS_WITH_BULLET2) +#include "Bullet3Common/b3Logging.h" +#define error_message(...) b3Error(__VA_ARGS__) +#define warning_message(...) b3Warning(__VA_ARGS__) +#define id_printf(...) b3Printf(__VA_ARGS__) +#else // BT_ID_WO_BULLET +#include +/// print error message with file/line information +#define error_message(...) \ + do { \ + fprintf(stderr, "[Error:%s:%d] ", __INVDYN_FILE_WO_DIR__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); \ + } while (0) +/// print warning message with file/line information +#define warning_message(...) \ + do { \ + fprintf(stderr, "[Warning:%s:%d] ", __INVDYN_FILE_WO_DIR__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); \ + } while (0) +#define id_printf(...) printf(__VA_ARGS__) +#endif // BT_ID_WO_BULLET +#endif diff --git a/extern/bullet/src/BulletInverseDynamics/IDMath.cpp b/extern/bullet/src/BulletInverseDynamics/IDMath.cpp new file mode 100644 index 000000000000..99fe20e49287 --- /dev/null +++ b/extern/bullet/src/BulletInverseDynamics/IDMath.cpp @@ -0,0 +1,437 @@ +#include "IDMath.hpp" + +#include +#include + +namespace btInverseDynamics { +static const idScalar kIsZero = 5 * std::numeric_limits::epsilon(); +// requirements for axis length deviation from 1.0 +// experimentally set from random euler angle rotation matrices +static const idScalar kAxisLengthEpsilon = 10 * kIsZero; + +void setZero(vec3 &v) { + v(0) = 0; + v(1) = 0; + v(2) = 0; +} + +void setZero(vecx &v) { + for (int i = 0; i < v.size(); i++) { + v(i) = 0; + } +} + +void setZero(mat33 &m) { + m(0, 0) = 0; + m(0, 1) = 0; + m(0, 2) = 0; + m(1, 0) = 0; + m(1, 1) = 0; + m(1, 2) = 0; + m(2, 0) = 0; + m(2, 1) = 0; + m(2, 2) = 0; +} + +void skew(vec3& v, mat33* result) { + (*result)(0, 0) = 0.0; + (*result)(0, 1) = -v(2); + (*result)(0, 2) = v(1); + (*result)(1, 0) = v(2); + (*result)(1, 1) = 0.0; + (*result)(1, 2) = -v(0); + (*result)(2, 0) = -v(1); + (*result)(2, 1) = v(0); + (*result)(2, 2) = 0.0; +} + +idScalar maxAbs(const vecx &v) { + idScalar result = 0.0; + for (int i = 0; i < v.size(); i++) { + const idScalar tmp = BT_ID_FABS(v(i)); + if (tmp > result) { + result = tmp; + } + } + return result; +} + +idScalar maxAbs(const vec3 &v) { + idScalar result = 0.0; + for (int i = 0; i < 3; i++) { + const idScalar tmp = BT_ID_FABS(v(i)); + if (tmp > result) { + result = tmp; + } + } + return result; +} + +#if (defined BT_ID_HAVE_MAT3X) +idScalar maxAbsMat3x(const mat3x &m) { + // only used for tests -- so just loop here for portability + idScalar result = 0.0; + for (idArrayIdx col = 0; col < m.cols(); col++) { + for (idArrayIdx row = 0; row < 3; row++) { + result = BT_ID_MAX(result, std::fabs(m(row, col))); + } + } + return result; +} + +void mul(const mat33 &a, const mat3x &b, mat3x *result) { + if (b.cols() != result->cols()) { + error_message("size missmatch. b.cols()= %d, result->cols()= %d\n", + static_cast(b.cols()), static_cast(result->cols())); + abort(); + } + + for (idArrayIdx col = 0; col < b.cols(); col++) { + const idScalar x = a(0,0)*b(0,col)+a(0,1)*b(1,col)+a(0,2)*b(2,col); + const idScalar y = a(1,0)*b(0,col)+a(1,1)*b(1,col)+a(1,2)*b(2,col); + const idScalar z = a(2,0)*b(0,col)+a(2,1)*b(1,col)+a(2,2)*b(2,col); + setMat3xElem(0, col, x, result); + setMat3xElem(1, col, y, result); + setMat3xElem(2, col, z, result); + } +} +void add(const mat3x &a, const mat3x &b, mat3x *result) { + if (a.cols() != b.cols()) { + error_message("size missmatch. a.cols()= %d, b.cols()= %d\n", + static_cast(a.cols()), static_cast(b.cols())); + abort(); + } + for (idArrayIdx col = 0; col < b.cols(); col++) { + for (idArrayIdx row = 0; row < 3; row++) { + setMat3xElem(row, col, a(row, col) + b(row, col), result); + } + } +} +void sub(const mat3x &a, const mat3x &b, mat3x *result) { + if (a.cols() != b.cols()) { + error_message("size missmatch. a.cols()= %d, b.cols()= %d\n", + static_cast(a.cols()), static_cast(b.cols())); + abort(); + } + for (idArrayIdx col = 0; col < b.cols(); col++) { + for (idArrayIdx row = 0; row < 3; row++) { + setMat3xElem(row, col, a(row, col) - b(row, col), result); + } + } +} +#endif + +mat33 transformX(const idScalar &alpha) { + mat33 T; + const idScalar cos_alpha = BT_ID_COS(alpha); + const idScalar sin_alpha = BT_ID_SIN(alpha); + // [1 0 0] + // [0 c s] + // [0 -s c] + T(0, 0) = 1.0; + T(0, 1) = 0.0; + T(0, 2) = 0.0; + + T(1, 0) = 0.0; + T(1, 1) = cos_alpha; + T(1, 2) = sin_alpha; + + T(2, 0) = 0.0; + T(2, 1) = -sin_alpha; + T(2, 2) = cos_alpha; + + return T; +} + +mat33 transformY(const idScalar &beta) { + mat33 T; + const idScalar cos_beta = BT_ID_COS(beta); + const idScalar sin_beta = BT_ID_SIN(beta); + // [c 0 -s] + // [0 1 0] + // [s 0 c] + T(0, 0) = cos_beta; + T(0, 1) = 0.0; + T(0, 2) = -sin_beta; + + T(1, 0) = 0.0; + T(1, 1) = 1.0; + T(1, 2) = 0.0; + + T(2, 0) = sin_beta; + T(2, 1) = 0.0; + T(2, 2) = cos_beta; + + return T; +} + +mat33 transformZ(const idScalar &gamma) { + mat33 T; + const idScalar cos_gamma = BT_ID_COS(gamma); + const idScalar sin_gamma = BT_ID_SIN(gamma); + // [ c s 0] + // [-s c 0] + // [ 0 0 1] + T(0, 0) = cos_gamma; + T(0, 1) = sin_gamma; + T(0, 2) = 0.0; + + T(1, 0) = -sin_gamma; + T(1, 1) = cos_gamma; + T(1, 2) = 0.0; + + T(2, 0) = 0.0; + T(2, 1) = 0.0; + T(2, 2) = 1.0; + + return T; +} + +mat33 tildeOperator(const vec3 &v) { + mat33 m; + m(0, 0) = 0.0; + m(0, 1) = -v(2); + m(0, 2) = v(1); + m(1, 0) = v(2); + m(1, 1) = 0.0; + m(1, 2) = -v(0); + m(2, 0) = -v(1); + m(2, 1) = v(0); + m(2, 2) = 0.0; + return m; +} + +void getVecMatFromDH(idScalar theta, idScalar d, idScalar a, idScalar alpha, vec3 *r, mat33 *T) { + const idScalar sa = BT_ID_SIN(alpha); + const idScalar ca = BT_ID_COS(alpha); + const idScalar st = BT_ID_SIN(theta); + const idScalar ct = BT_ID_COS(theta); + + (*r)(0) = a; + (*r)(1) = -sa * d; + (*r)(2) = ca * d; + + (*T)(0, 0) = ct; + (*T)(0, 1) = -st; + (*T)(0, 2) = 0.0; + + (*T)(1, 0) = st * ca; + (*T)(1, 1) = ct * ca; + (*T)(1, 2) = -sa; + + (*T)(2, 0) = st * sa; + (*T)(2, 1) = ct * sa; + (*T)(2, 2) = ca; +} + +void bodyTParentFromAxisAngle(const vec3 &axis, const idScalar &angle, mat33 *T) { + const idScalar c = BT_ID_COS(angle); + const idScalar s = -BT_ID_SIN(angle); + const idScalar one_m_c = 1.0 - c; + + const idScalar &x = axis(0); + const idScalar &y = axis(1); + const idScalar &z = axis(2); + + (*T)(0, 0) = x * x * one_m_c + c; + (*T)(0, 1) = x * y * one_m_c - z * s; + (*T)(0, 2) = x * z * one_m_c + y * s; + + (*T)(1, 0) = x * y * one_m_c + z * s; + (*T)(1, 1) = y * y * one_m_c + c; + (*T)(1, 2) = y * z * one_m_c - x * s; + + (*T)(2, 0) = x * z * one_m_c - y * s; + (*T)(2, 1) = y * z * one_m_c + x * s; + (*T)(2, 2) = z * z * one_m_c + c; +} + +bool isPositiveDefinite(const mat33 &m) { + // test if all upper left determinants are positive + if (m(0, 0) <= 0) { // upper 1x1 + return false; + } + if (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0) <= 0) { // upper 2x2 + return false; + } + if ((m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) - + m(0, 1) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) + + m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0))) < 0) { + return false; + } + return true; +} + +bool isPositiveSemiDefinite(const mat33 &m) { + // test if all upper left determinants are positive + if (m(0, 0) < 0) { // upper 1x1 + return false; + } + if (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0) < 0) { // upper 2x2 + return false; + } + if ((m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) - + m(0, 1) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) + + m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0))) < 0) { + return false; + } + return true; +} + +bool isPositiveSemiDefiniteFuzzy(const mat33 &m) { + // test if all upper left determinants are positive + if (m(0, 0) < -kIsZero) { // upper 1x1 + return false; + } + if (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0) < -kIsZero) { // upper 2x2 + return false; + } + if ((m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) - + m(0, 1) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) + + m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0))) < -kIsZero) { + return false; + } + return true; +} + +idScalar determinant(const mat33 &m) { + return m(0, 0) * m(1, 1) * m(2, 2) + m(0, 1) * m(1, 2) * m(2, 0) + m(0, 2) * m(1, 0) * m(2, 1) - + m(0, 2) * m(1, 1) * m(2, 0) - m(0, 0) * m(1, 2) * m(2, 1) - m(0, 1) * m(1, 0) * m(2, 2); +} + +bool isValidInertiaMatrix(const mat33 &I, const int index, bool has_fixed_joint) { + // TODO(Thomas) do we really want this? + // in cases where the inertia tensor about the center of mass is zero, + // the determinant of the inertia tensor about the joint axis is almost + // zero and can have a very small negative value. + if (!isPositiveSemiDefiniteFuzzy(I)) { + error_message("invalid inertia matrix for body %d, not positive definite " + "(fixed joint)\n", + index); + error_message("matrix is:\n" + "[%.20e %.20e %.20e;\n" + "%.20e %.20e %.20e;\n" + "%.20e %.20e %.20e]\n", + I(0, 0), I(0, 1), I(0, 2), I(1, 0), I(1, 1), I(1, 2), I(2, 0), I(2, 1), + I(2, 2)); + + return false; + } + + // check triangle inequality, must have I(i,i)+I(j,j)>=I(k,k) + if (!has_fixed_joint) { + if (I(0, 0) + I(1, 1) < I(2, 2)) { + error_message("invalid inertia tensor for body %d, I(0,0) + I(1,1) < I(2,2)\n", index); + error_message("matrix is:\n" + "[%.20e %.20e %.20e;\n" + "%.20e %.20e %.20e;\n" + "%.20e %.20e %.20e]\n", + I(0, 0), I(0, 1), I(0, 2), I(1, 0), I(1, 1), I(1, 2), I(2, 0), I(2, 1), + I(2, 2)); + return false; + } + if (I(0, 0) + I(1, 1) < I(2, 2)) { + error_message("invalid inertia tensor for body %d, I(0,0) + I(1,1) < I(2,2)\n", index); + error_message("matrix is:\n" + "[%.20e %.20e %.20e;\n" + "%.20e %.20e %.20e;\n" + "%.20e %.20e %.20e]\n", + I(0, 0), I(0, 1), I(0, 2), I(1, 0), I(1, 1), I(1, 2), I(2, 0), I(2, 1), + I(2, 2)); + return false; + } + if (I(1, 1) + I(2, 2) < I(0, 0)) { + error_message("invalid inertia tensor for body %d, I(1,1) + I(2,2) < I(0,0)\n", index); + error_message("matrix is:\n" + "[%.20e %.20e %.20e;\n" + "%.20e %.20e %.20e;\n" + "%.20e %.20e %.20e]\n", + I(0, 0), I(0, 1), I(0, 2), I(1, 0), I(1, 1), I(1, 2), I(2, 0), I(2, 1), + I(2, 2)); + return false; + } + } + // check positive/zero diagonal elements + for (int i = 0; i < 3; i++) { + if (I(i, i) < 0) { // accept zero + error_message("invalid inertia tensor, I(%d,%d)= %e <0\n", i, i, I(i, i)); + return false; + } + } + // check symmetry + if (BT_ID_FABS(I(1, 0) - I(0, 1)) > kIsZero) { + error_message("invalid inertia tensor for body %d I(1,0)!=I(0,1). I(1,0)-I(0,1)= " + "%e\n", + index, I(1, 0) - I(0, 1)); + return false; + } + if (BT_ID_FABS(I(2, 0) - I(0, 2)) > kIsZero) { + error_message("invalid inertia tensor for body %d I(2,0)!=I(0,2). I(2,0)-I(0,2)= " + "%e\n", + index, I(2, 0) - I(0, 2)); + return false; + } + if (BT_ID_FABS(I(1, 2) - I(2, 1)) > kIsZero) { + error_message("invalid inertia tensor body %d I(1,2)!=I(2,1). I(1,2)-I(2,1)= %e\n", index, + I(1, 2) - I(2, 1)); + return false; + } + return true; +} + +bool isValidTransformMatrix(const mat33 &m) { +#define print_mat(x) \ + error_message("matrix is [%e, %e, %e; %e, %e, %e; %e, %e, %e]\n", x(0, 0), x(0, 1), x(0, 2), \ + x(1, 0), x(1, 1), x(1, 2), x(2, 0), x(2, 1), x(2, 2)) + + // check for unit length column vectors + for (int i = 0; i < 3; i++) { + const idScalar length_minus_1 = + BT_ID_FABS(m(0, i) * m(0, i) + m(1, i) * m(1, i) + m(2, i) * m(2, i) - 1.0); + if (length_minus_1 > kAxisLengthEpsilon) { + error_message("Not a valid rotation matrix (column %d not unit length)\n" + "column = [%.18e %.18e %.18e]\n" + "length-1.0= %.18e\n", + i, m(0, i), m(1, i), m(2, i), length_minus_1); + print_mat(m); + return false; + } + } + // check for orthogonal column vectors + if (BT_ID_FABS(m(0, 0) * m(0, 1) + m(1, 0) * m(1, 1) + m(2, 0) * m(2, 1)) > kAxisLengthEpsilon) { + error_message("Not a valid rotation matrix (columns 0 and 1 not orthogonal)\n"); + print_mat(m); + return false; + } + if (BT_ID_FABS(m(0, 0) * m(0, 2) + m(1, 0) * m(1, 2) + m(2, 0) * m(2, 2)) > kAxisLengthEpsilon) { + error_message("Not a valid rotation matrix (columns 0 and 2 not orthogonal)\n"); + print_mat(m); + return false; + } + if (BT_ID_FABS(m(0, 1) * m(0, 2) + m(1, 1) * m(1, 2) + m(2, 1) * m(2, 2)) > kAxisLengthEpsilon) { + error_message("Not a valid rotation matrix (columns 0 and 2 not orthogonal)\n"); + print_mat(m); + return false; + } + // check determinant (rotation not reflection) + if (determinant(m) <= 0) { + error_message("Not a valid rotation matrix (determinant <=0)\n"); + print_mat(m); + return false; + } + return true; +} + +bool isUnitVector(const vec3 &vector) { + return BT_ID_FABS(vector(0) * vector(0) + vector(1) * vector(1) + vector(2) * vector(2) - 1.0) < + kIsZero; +} + +vec3 rpyFromMatrix(const mat33 &rot) { + vec3 rpy; + rpy(2) = BT_ID_ATAN2(-rot(1, 0), rot(0, 0)); + rpy(1) = BT_ID_ATAN2(rot(2, 0), BT_ID_COS(rpy(2)) * rot(0, 0) - BT_ID_SIN(rpy(0)) * rot(1, 0)); + rpy(0) = BT_ID_ATAN2(-rot(2, 0), rot(2, 2)); + return rpy; +} +} diff --git a/extern/bullet/src/BulletInverseDynamics/IDMath.hpp b/extern/bullet/src/BulletInverseDynamics/IDMath.hpp new file mode 100644 index 000000000000..b355474d44e2 --- /dev/null +++ b/extern/bullet/src/BulletInverseDynamics/IDMath.hpp @@ -0,0 +1,99 @@ +/// @file Math utility functions used in inverse dynamics library. +/// Defined here as they may not be provided by the math library. + +#ifndef IDMATH_HPP_ +#define IDMATH_HPP_ +#include "IDConfig.hpp" + +namespace btInverseDynamics { +/// set all elements to zero +void setZero(vec3& v); +/// set all elements to zero +void setZero(vecx& v); +/// set all elements to zero +void setZero(mat33& m); +/// create a skew symmetric matrix from a vector (useful for cross product abstraction, e.g. v x a = V * a) +void skew(vec3& v, mat33* result); +/// return maximum absolute value +idScalar maxAbs(const vecx& v); +#ifndef ID_LINEAR_MATH_USE_EIGEN +/// return maximum absolute value +idScalar maxAbs(const vec3& v); +#endif //ID_LINEAR_MATH_USE_EIGEN + +#if (defined BT_ID_HAVE_MAT3X) +idScalar maxAbsMat3x(const mat3x& m); +void setZero(mat3x&m); +// define math functions on mat3x here to avoid allocations in operators. +void mul(const mat33&a, const mat3x&b, mat3x* result); +void add(const mat3x&a, const mat3x&b, mat3x* result); +void sub(const mat3x&a, const mat3x&b, mat3x* result); +#endif + +/// get offset vector & transform matrix from DH parameters +/// TODO: add documentation +void getVecMatFromDH(idScalar theta, idScalar d, idScalar a, idScalar alpha, vec3* r, mat33* T); + +/// Check if a 3x3 matrix is positive definite +/// @param m a 3x3 matrix +/// @return true if m>0, false otherwise +bool isPositiveDefinite(const mat33& m); + +/// Check if a 3x3 matrix is positive semi definite +/// @param m a 3x3 matrix +/// @return true if m>=0, false otherwise +bool isPositiveSemiDefinite(const mat33& m); +/// Check if a 3x3 matrix is positive semi definite within numeric limits +/// @param m a 3x3 matrix +/// @return true if m>=-eps, false otherwise +bool isPositiveSemiDefiniteFuzzy(const mat33& m); + +/// Determinant of 3x3 matrix +/// NOTE: implemented here for portability, as determinant operation +/// will be implemented differently for various matrix/vector libraries +/// @param m a 3x3 matrix +/// @return det(m) +idScalar determinant(const mat33& m); + +/// Test if a 3x3 matrix satisfies some properties of inertia matrices +/// @param I a 3x3 matrix +/// @param index body index (for error messages) +/// @param has_fixed_joint: if true, positive semi-definite matrices are accepted +/// @return true if I satisfies inertia matrix properties, false otherwise. +bool isValidInertiaMatrix(const mat33& I, int index, bool has_fixed_joint); + +/// Check if a 3x3 matrix is a valid transform (rotation) matrix +/// @param m a 3x3 matrix +/// @return true if m is a rotation matrix, false otherwise +bool isValidTransformMatrix(const mat33& m); +/// Transform matrix from parent to child frame, +/// when the child frame is rotated about @param axis by @angle +/// (mathematically positive) +/// @param axis the axis of rotation +/// @param angle rotation angle +/// @param T pointer to transform matrix +void bodyTParentFromAxisAngle(const vec3& axis, const idScalar& angle, mat33* T); + +/// Check if this is a unit vector +/// @param vector +/// @return true if |vector|=1 within numeric limits +bool isUnitVector(const vec3& vector); + +/// @input a vector in R^3 +/// @returns corresponding spin tensor +mat33 tildeOperator(const vec3& v); +/// @param alpha angle in radians +/// @returns transform matrix for ratation with @param alpha about x-axis +mat33 transformX(const idScalar& alpha); +/// @param beta angle in radians +/// @returns transform matrix for ratation with @param beta about y-axis +mat33 transformY(const idScalar& beta); +/// @param gamma angle in radians +/// @returns transform matrix for ratation with @param gamma about z-axis +mat33 transformZ(const idScalar& gamma); +///calculate rpy angles (x-y-z Euler angles) from a given rotation matrix +/// @param rot rotation matrix +/// @returns x-y-z Euler angles +vec3 rpyFromMatrix(const mat33&rot); +} +#endif // IDMATH_HPP_ diff --git a/extern/bullet/src/BulletInverseDynamics/MultiBodyTree.cpp b/extern/bullet/src/BulletInverseDynamics/MultiBodyTree.cpp new file mode 100644 index 000000000000..c67588d49fd5 --- /dev/null +++ b/extern/bullet/src/BulletInverseDynamics/MultiBodyTree.cpp @@ -0,0 +1,445 @@ +#include "MultiBodyTree.hpp" + +#include +#include +#include + +#include "IDMath.hpp" +#include "details/MultiBodyTreeImpl.hpp" +#include "details/MultiBodyTreeInitCache.hpp" + +namespace btInverseDynamics { + +MultiBodyTree::MultiBodyTree() + : m_is_finalized(false), + m_mass_parameters_are_valid(true), + m_accept_invalid_mass_parameters(false), + m_impl(0x0), + m_init_cache(0x0) { + m_init_cache = new InitCache(); +} + +MultiBodyTree::~MultiBodyTree() { + delete m_impl; + delete m_init_cache; +} + +void MultiBodyTree::setAcceptInvalidMassParameters(bool flag) { + m_accept_invalid_mass_parameters = flag; +} + +bool MultiBodyTree::getAcceptInvalidMassProperties() const { + return m_accept_invalid_mass_parameters; +} + +int MultiBodyTree::getBodyOrigin(const int body_index, vec3 *world_origin) const { + return m_impl->getBodyOrigin(body_index, world_origin); +} + +int MultiBodyTree::getBodyCoM(const int body_index, vec3 *world_com) const { + return m_impl->getBodyCoM(body_index, world_com); +} + +int MultiBodyTree::getBodyTransform(const int body_index, mat33 *world_T_body) const { + return m_impl->getBodyTransform(body_index, world_T_body); +} +int MultiBodyTree::getBodyAngularVelocity(const int body_index, vec3 *world_omega) const { + return m_impl->getBodyAngularVelocity(body_index, world_omega); +} +int MultiBodyTree::getBodyLinearVelocity(const int body_index, vec3 *world_velocity) const { + return m_impl->getBodyLinearVelocity(body_index, world_velocity); +} + +int MultiBodyTree::getBodyLinearVelocityCoM(const int body_index, vec3 *world_velocity) const { + return m_impl->getBodyLinearVelocityCoM(body_index, world_velocity); +} + +int MultiBodyTree::getBodyAngularAcceleration(const int body_index, vec3 *world_dot_omega) const { + return m_impl->getBodyAngularAcceleration(body_index, world_dot_omega); +} +int MultiBodyTree::getBodyLinearAcceleration(const int body_index, vec3 *world_acceleration) const { + return m_impl->getBodyLinearAcceleration(body_index, world_acceleration); +} + +int MultiBodyTree::getParentRParentBodyRef(const int body_index, vec3* r) const { + return m_impl->getParentRParentBodyRef(body_index, r); +} + +int MultiBodyTree::getBodyTParentRef(const int body_index, mat33* T) const { + return m_impl->getBodyTParentRef(body_index, T); +} + +int MultiBodyTree::getBodyAxisOfMotion(const int body_index, vec3* axis) const { + return m_impl->getBodyAxisOfMotion(body_index, axis); +} + +void MultiBodyTree::printTree() { m_impl->printTree(); } +void MultiBodyTree::printTreeData() { m_impl->printTreeData(); } + +int MultiBodyTree::numBodies() const { return m_impl->m_num_bodies; } + +int MultiBodyTree::numDoFs() const { return m_impl->m_num_dofs; } + +int MultiBodyTree::calculateInverseDynamics(const vecx &q, const vecx &u, const vecx &dot_u, + vecx *joint_forces) { + if (false == m_is_finalized) { + error_message("system has not been initialized\n"); + return -1; + } + if (-1 == m_impl->calculateInverseDynamics(q, u, dot_u, joint_forces)) { + error_message("error in inverse dynamics calculation\n"); + return -1; + } + return 0; +} + +int MultiBodyTree::calculateMassMatrix(const vecx &q, const bool update_kinematics, + const bool initialize_matrix, + const bool set_lower_triangular_matrix, matxx *mass_matrix) { + if (false == m_is_finalized) { + error_message("system has not been initialized\n"); + return -1; + } + if (-1 == + m_impl->calculateMassMatrix(q, update_kinematics, initialize_matrix, + set_lower_triangular_matrix, mass_matrix)) { + error_message("error in mass matrix calculation\n"); + return -1; + } + return 0; +} + +int MultiBodyTree::calculateMassMatrix(const vecx &q, matxx *mass_matrix) { + return calculateMassMatrix(q, true, true, true, mass_matrix); +} + + + +int MultiBodyTree::calculateKinematics(const vecx& q, const vecx& u, const vecx& dot_u) { + vec3 world_gravity(m_impl->m_world_gravity); + // temporarily set gravity to zero, to ensure we get the actual accelerations + setZero(m_impl->m_world_gravity); + + if (false == m_is_finalized) { + error_message("system has not been initialized\n"); + return -1; + } + if (-1 == m_impl->calculateKinematics(q, u, dot_u, + MultiBodyTree::MultiBodyImpl::POSITION_VELOCITY_ACCELERATION)) { + error_message("error in kinematics calculation\n"); + return -1; + } + + m_impl->m_world_gravity=world_gravity; + return 0; +} + + +int MultiBodyTree::calculatePositionKinematics(const vecx& q) { + if (false == m_is_finalized) { + error_message("system has not been initialized\n"); + return -1; + } + if (-1 == m_impl->calculateKinematics(q, q, q, + MultiBodyTree::MultiBodyImpl::POSITION_VELOCITY)) { + error_message("error in kinematics calculation\n"); + return -1; + } + return 0; +} + +int MultiBodyTree::calculatePositionAndVelocityKinematics(const vecx& q, const vecx& u) { + if (false == m_is_finalized) { + error_message("system has not been initialized\n"); + return -1; + } + if (-1 == m_impl->calculateKinematics(q, u, u, + MultiBodyTree::MultiBodyImpl::POSITION_VELOCITY)) { + error_message("error in kinematics calculation\n"); + return -1; + } + return 0; +} + + +#if (defined BT_ID_HAVE_MAT3X) && (defined BT_ID_WITH_JACOBIANS) +int MultiBodyTree::calculateJacobians(const vecx& q, const vecx& u) { + if (false == m_is_finalized) { + error_message("system has not been initialized\n"); + return -1; + } + if (-1 == m_impl->calculateJacobians(q, u, + MultiBodyTree::MultiBodyImpl::POSITION_VELOCITY)) { + error_message("error in jacobian calculation\n"); + return -1; + } + return 0; +} + +int MultiBodyTree::calculateJacobians(const vecx& q){ + if (false == m_is_finalized) { + error_message("system has not been initialized\n"); + return -1; + } + if (-1 == m_impl->calculateJacobians(q, q, + MultiBodyTree::MultiBodyImpl::POSITION_ONLY)) { + error_message("error in jacobian calculation\n"); + return -1; + } + return 0; +} + +int MultiBodyTree::getBodyDotJacobianTransU(const int body_index, vec3* world_dot_jac_trans_u) const { + return m_impl->getBodyDotJacobianTransU(body_index,world_dot_jac_trans_u); +} + +int MultiBodyTree::getBodyDotJacobianRotU(const int body_index, vec3* world_dot_jac_rot_u) const { + return m_impl->getBodyDotJacobianRotU(body_index,world_dot_jac_rot_u); +} + +int MultiBodyTree::getBodyJacobianTrans(const int body_index, mat3x* world_jac_trans) const { + return m_impl->getBodyJacobianTrans(body_index,world_jac_trans); +} + +int MultiBodyTree::getBodyJacobianRot(const int body_index, mat3x* world_jac_rot) const { + return m_impl->getBodyJacobianRot(body_index,world_jac_rot); +} + + +#endif + +int MultiBodyTree::addBody(int body_index, int parent_index, JointType joint_type, + const vec3 &parent_r_parent_body_ref, const mat33 &body_T_parent_ref, + const vec3 &body_axis_of_motion_, idScalar mass, + const vec3 &body_r_body_com, const mat33 &body_I_body, + const int user_int, void *user_ptr) { + if (body_index < 0) { + error_message("body index must be positive (got %d)\n", body_index); + return -1; + } + vec3 body_axis_of_motion(body_axis_of_motion_); + switch (joint_type) { + case REVOLUTE: + case PRISMATIC: + // check if axis is unit vector + if (!isUnitVector(body_axis_of_motion)) { + warning_message( + "axis of motion not a unit axis ([%f %f %f]), will use normalized vector\n", + body_axis_of_motion(0), body_axis_of_motion(1), body_axis_of_motion(2)); + idScalar length = BT_ID_SQRT(BT_ID_POW(body_axis_of_motion(0), 2) + + BT_ID_POW(body_axis_of_motion(1), 2) + + BT_ID_POW(body_axis_of_motion(2), 2)); + if (length < BT_ID_SQRT(std::numeric_limits::min())) { + error_message("axis of motion vector too short (%e)\n", length); + return -1; + } + body_axis_of_motion = (1.0 / length) * body_axis_of_motion; + } + break; + case FIXED: + break; + case FLOATING: + break; + default: + error_message("unknown joint type %d\n", joint_type); + return -1; + } + + // sanity check for mass properties. Zero mass is OK. + if (mass < 0) { + m_mass_parameters_are_valid = false; + error_message("Body %d has invalid mass %e\n", body_index, mass); + if (!m_accept_invalid_mass_parameters) { + return -1; + } + } + + if (!isValidInertiaMatrix(body_I_body, body_index, FIXED == joint_type)) { + m_mass_parameters_are_valid = false; + // error message printed in function call + if (!m_accept_invalid_mass_parameters) { + return -1; + } + } + + if (!isValidTransformMatrix(body_T_parent_ref)) { + return -1; + } + + return m_init_cache->addBody(body_index, parent_index, joint_type, parent_r_parent_body_ref, + body_T_parent_ref, body_axis_of_motion, mass, body_r_body_com, + body_I_body, user_int, user_ptr); +} + +int MultiBodyTree::getParentIndex(const int body_index, int *parent_index) const { + return m_impl->getParentIndex(body_index, parent_index); +} + +int MultiBodyTree::getUserInt(const int body_index, int *user_int) const { + return m_impl->getUserInt(body_index, user_int); +} + +int MultiBodyTree::getUserPtr(const int body_index, void **user_ptr) const { + return m_impl->getUserPtr(body_index, user_ptr); +} + +int MultiBodyTree::setUserInt(const int body_index, const int user_int) { + return m_impl->setUserInt(body_index, user_int); +} + +int MultiBodyTree::setUserPtr(const int body_index, void *const user_ptr) { + return m_impl->setUserPtr(body_index, user_ptr); +} + +int MultiBodyTree::finalize() { + const int &num_bodies = m_init_cache->numBodies(); + const int &num_dofs = m_init_cache->numDoFs(); + + if(num_dofs<=0) { + error_message("Need num_dofs>=1, but num_dofs= %d\n", num_dofs); + //return -1; + } + + // 1 allocate internal MultiBody structure + m_impl = new MultiBodyImpl(num_bodies, num_dofs); + + // 2 build new index set assuring index(parent) < index(child) + if (-1 == m_init_cache->buildIndexSets()) { + return -1; + } + m_init_cache->getParentIndexArray(&m_impl->m_parent_index); + + // 3 setup internal kinematic and dynamic data + for (int index = 0; index < num_bodies; index++) { + InertiaData inertia; + JointData joint; + if (-1 == m_init_cache->getInertiaData(index, &inertia)) { + return -1; + } + if (-1 == m_init_cache->getJointData(index, &joint)) { + return -1; + } + + RigidBody &rigid_body = m_impl->m_body_list[index]; + + rigid_body.m_mass = inertia.m_mass; + rigid_body.m_body_mass_com = inertia.m_mass * inertia.m_body_pos_body_com; + rigid_body.m_body_I_body = inertia.m_body_I_body; + rigid_body.m_joint_type = joint.m_type; + rigid_body.m_parent_pos_parent_body_ref = joint.m_parent_pos_parent_child_ref; + rigid_body.m_body_T_parent_ref = joint.m_child_T_parent_ref; + rigid_body.m_parent_pos_parent_body_ref = joint.m_parent_pos_parent_child_ref; + rigid_body.m_joint_type = joint.m_type; + + // Set joint Jacobians. Note that the dimension is always 3x1 here to avoid variable sized + // matrices. + switch (rigid_body.m_joint_type) { + case REVOLUTE: + rigid_body.m_Jac_JR(0) = joint.m_child_axis_of_motion(0); + rigid_body.m_Jac_JR(1) = joint.m_child_axis_of_motion(1); + rigid_body.m_Jac_JR(2) = joint.m_child_axis_of_motion(2); + rigid_body.m_Jac_JT(0) = 0.0; + rigid_body.m_Jac_JT(1) = 0.0; + rigid_body.m_Jac_JT(2) = 0.0; + break; + case PRISMATIC: + rigid_body.m_Jac_JR(0) = 0.0; + rigid_body.m_Jac_JR(1) = 0.0; + rigid_body.m_Jac_JR(2) = 0.0; + rigid_body.m_Jac_JT(0) = joint.m_child_axis_of_motion(0); + rigid_body.m_Jac_JT(1) = joint.m_child_axis_of_motion(1); + rigid_body.m_Jac_JT(2) = joint.m_child_axis_of_motion(2); + break; + case FIXED: + // NOTE/TODO: dimension really should be zero .. + rigid_body.m_Jac_JR(0) = 0.0; + rigid_body.m_Jac_JR(1) = 0.0; + rigid_body.m_Jac_JR(2) = 0.0; + rigid_body.m_Jac_JT(0) = 0.0; + rigid_body.m_Jac_JT(1) = 0.0; + rigid_body.m_Jac_JT(2) = 0.0; + break; + case FLOATING: + // NOTE/TODO: this is not really correct. + // the Jacobians should be 3x3 matrices here ! + rigid_body.m_Jac_JR(0) = 0.0; + rigid_body.m_Jac_JR(1) = 0.0; + rigid_body.m_Jac_JR(2) = 0.0; + rigid_body.m_Jac_JT(0) = 0.0; + rigid_body.m_Jac_JT(1) = 0.0; + rigid_body.m_Jac_JT(2) = 0.0; + break; + default: + error_message("unsupported joint type %d\n", rigid_body.m_joint_type); + return -1; + } + } + + // 4 assign degree of freedom indices & build per-joint-type index arrays + if (-1 == m_impl->generateIndexSets()) { + error_message("generating index sets\n"); + return -1; + } + + // 5 do some pre-computations .. + m_impl->calculateStaticData(); + + // 6. make sure all user forces are set to zero, as this might not happen + // in the vector ctors. + m_impl->clearAllUserForcesAndMoments(); + + m_is_finalized = true; + return 0; +} + +int MultiBodyTree::setGravityInWorldFrame(const vec3 &gravity) { + return m_impl->setGravityInWorldFrame(gravity); +} + +int MultiBodyTree::getJointType(const int body_index, JointType *joint_type) const { + return m_impl->getJointType(body_index, joint_type); +} + +int MultiBodyTree::getJointTypeStr(const int body_index, const char **joint_type) const { + return m_impl->getJointTypeStr(body_index, joint_type); +} + +int MultiBodyTree::getDoFOffset(const int body_index, int *q_offset) const { + return m_impl->getDoFOffset(body_index, q_offset); +} + +int MultiBodyTree::setBodyMass(const int body_index, idScalar mass) { + return m_impl->setBodyMass(body_index, mass); +} + +int MultiBodyTree::setBodyFirstMassMoment(const int body_index, const vec3& first_mass_moment) { + return m_impl->setBodyFirstMassMoment(body_index, first_mass_moment); +} + +int MultiBodyTree::setBodySecondMassMoment(const int body_index, const mat33& second_mass_moment) { + return m_impl->setBodySecondMassMoment(body_index, second_mass_moment); +} + +int MultiBodyTree::getBodyMass(const int body_index, idScalar *mass) const { + return m_impl->getBodyMass(body_index, mass); +} + +int MultiBodyTree::getBodyFirstMassMoment(const int body_index, vec3 *first_mass_moment) const { + return m_impl->getBodyFirstMassMoment(body_index, first_mass_moment); +} + +int MultiBodyTree::getBodySecondMassMoment(const int body_index, mat33 *second_mass_moment) const { + return m_impl->getBodySecondMassMoment(body_index, second_mass_moment); +} + +void MultiBodyTree::clearAllUserForcesAndMoments() { m_impl->clearAllUserForcesAndMoments(); } + +int MultiBodyTree::addUserForce(const int body_index, const vec3 &body_force) { + return m_impl->addUserForce(body_index, body_force); +} + +int MultiBodyTree::addUserMoment(const int body_index, const vec3 &body_moment) { + return m_impl->addUserMoment(body_index, body_moment); +} + +} diff --git a/extern/bullet/src/BulletInverseDynamics/MultiBodyTree.hpp b/extern/bullet/src/BulletInverseDynamics/MultiBodyTree.hpp new file mode 100644 index 000000000000..d235aa6e7613 --- /dev/null +++ b/extern/bullet/src/BulletInverseDynamics/MultiBodyTree.hpp @@ -0,0 +1,363 @@ +#ifndef MULTIBODYTREE_HPP_ +#define MULTIBODYTREE_HPP_ + +#include "IDConfig.hpp" +#include "IDMath.hpp" + +namespace btInverseDynamics { + +/// Enumeration of supported joint types +enum JointType { + /// no degree of freedom, moves with parent + FIXED = 0, + /// one rotational degree of freedom relative to parent + REVOLUTE, + /// one translational degree of freedom relative to parent + PRISMATIC, + /// six degrees of freedom relative to parent + FLOATING +}; + +/// Interface class for calculating inverse dynamics for tree structured +/// multibody systems +/// +/// Note on degrees of freedom +/// The q vector contains the generalized coordinate set defining the tree's configuration. +/// Every joint adds elements that define the corresponding link's frame pose relative to +/// its parent. For the joint types that is: +/// - FIXED: none +/// - REVOLUTE: angle of rotation [rad] +/// - PRISMATIC: displacement [m] +/// - FLOATING: Euler x-y-z angles [rad] and displacement in body-fixed frame of parent [m] +/// (in that order) +/// The u vector contains the generalized speeds, which are +/// - FIXED: none +/// - REVOLUTE: time derivative of angle of rotation [rad/s] +/// - PRISMATIC: time derivative of displacement [m/s] +/// - FLOATING: angular velocity [rad/s] (*not* time derivative of rpy angles) +/// and time derivative of displacement in parent frame [m/s] +/// +/// The q and u vectors are obtained by stacking contributions of all bodies in one +/// vector in the order of body indices. +/// +/// Note on generalized forces: analogous to u, i.e., +/// - FIXED: none +/// - REVOLUTE: moment [Nm], about joint axis +/// - PRISMATIC: force [N], along joint axis +/// - FLOATING: moment vector [Nm] and force vector [N], both in body-fixed frame +/// (in that order) +/// +/// TODO - force element interface (friction, springs, dampers, etc) +/// - gears and motor inertia +class MultiBodyTree { +public: + ID_DECLARE_ALIGNED_ALLOCATOR(); + /// The contructor. + /// Initialization & allocation is via addBody and buildSystem calls. + MultiBodyTree(); + /// the destructor. This also deallocates all memory + ~MultiBodyTree(); + + /// Add body to the system. this allocates memory and not real-time safe. + /// This only adds the data to an initial cache. After all bodies have been + /// added, + /// the system is setup using the buildSystem call + /// @param body_index index of the body to be added. Must >=0, =dim(u) + /// @param dot_u time derivative of u + /// @param joint_forces this is where the resulting joint forces will be + /// stored. dim(joint_forces) = dim(u) + /// @return 0 on success, -1 on error + int calculateInverseDynamics(const vecx& q, const vecx& u, const vecx& dot_u, + vecx* joint_forces); + /// Calculate joint space mass matrix + /// @param q generalized coordinates + /// @param initialize_matrix if true, initialize mass matrix with zero. + /// If mass_matrix is initialized to zero externally and only used + /// for mass matrix computations for the same system, it is safe to + /// set this to false. + /// @param set_lower_triangular_matrix if true, the lower triangular section of mass_matrix + /// is also populated, otherwise not. + /// @param mass_matrix matrix for storing the output (should be dim(q)xdim(q)) + /// @return -1 on error, 0 on success + int calculateMassMatrix(const vecx& q, const bool update_kinematics, + const bool initialize_matrix, const bool set_lower_triangular_matrix, + matxx* mass_matrix); + + /// Calculate joint space mass matrix. + /// This version will update kinematics, initialize all mass_matrix elements to zero and + /// populate all mass matrix entries. + /// @param q generalized coordinates + /// @param mass_matrix matrix for storing the output (should be dim(q)xdim(q)) + /// @return -1 on error, 0 on success + int calculateMassMatrix(const vecx& q, matxx* mass_matrix); + + + /// Calculates kinematics also calculated in calculateInverseDynamics, + /// but not dynamics. + /// This function ensures that correct accelerations are computed that do not + /// contain gravitational acceleration terms. + /// Does not calculate Jacobians, but only vector quantities (positions, velocities & accelerations) + int calculateKinematics(const vecx& q, const vecx& u, const vecx& dot_u); + /// Calculate position kinematics + int calculatePositionKinematics(const vecx& q); + /// Calculate position and velocity kinematics + int calculatePositionAndVelocityKinematics(const vecx& q, const vecx& u); + +#if (defined BT_ID_HAVE_MAT3X) && (defined BT_ID_WITH_JACOBIANS) + /// Calculate Jacobians (dvel/du), as well as velocity-dependent accelearation components + /// d(Jacobian)/dt*u + /// This function assumes that calculateInverseDynamics was called, or calculateKinematics, + /// or calculatePositionAndVelocityKinematics + int calculateJacobians(const vecx& q, const vecx& u); + /// Calculate Jacobians (dvel/du) + /// This function assumes that calculateInverseDynamics was called, or + /// one of the calculateKineamtics functions + int calculateJacobians(const vecx& q); +#endif // BT_ID_HAVE_MAT3X + + + /// set gravitational acceleration + /// the default is [0;0;-9.8] in the world frame + /// @param gravity the gravitational acceleration in world frame + /// @return 0 on success, -1 on error + int setGravityInWorldFrame(const vec3& gravity); + /// returns number of bodies in tree + int numBodies() const; + /// returns number of mechanical degrees of freedom (dimension of q-vector) + int numDoFs() const; + /// get origin of a body-fixed frame, represented in world frame + /// @param body_index index for frame/body + /// @param world_origin pointer for return data + /// @return 0 on success, -1 on error + int getBodyOrigin(const int body_index, vec3* world_origin) const; + /// get center of mass of a body, represented in world frame + /// @param body_index index for frame/body + /// @param world_com pointer for return data + /// @return 0 on success, -1 on error + int getBodyCoM(const int body_index, vec3* world_com) const; + /// get transform from of a body-fixed frame to the world frame + /// @param body_index index for frame/body + /// @param world_T_body pointer for return data + /// @return 0 on success, -1 on error + int getBodyTransform(const int body_index, mat33* world_T_body) const; + /// get absolute angular velocity for a body, represented in the world frame + /// @param body_index index for frame/body + /// @param world_omega pointer for return data + /// @return 0 on success, -1 on error + int getBodyAngularVelocity(const int body_index, vec3* world_omega) const; + /// get linear velocity of a body, represented in world frame + /// @param body_index index for frame/body + /// @param world_velocity pointer for return data + /// @return 0 on success, -1 on error + int getBodyLinearVelocity(const int body_index, vec3* world_velocity) const; + /// get linear velocity of a body's CoM, represented in world frame + /// (not required for inverse dynamics, provided for convenience) + /// @param body_index index for frame/body + /// @param world_vel_com pointer for return data + /// @return 0 on success, -1 on error + int getBodyLinearVelocityCoM(const int body_index, vec3* world_velocity) const; + /// get origin of a body-fixed frame, represented in world frame + /// @param body_index index for frame/body + /// @param world_origin pointer for return data + /// @return 0 on success, -1 on error + int getBodyAngularAcceleration(const int body_index, vec3* world_dot_omega) const; + /// get origin of a body-fixed frame, represented in world frame + /// NOTE: this will include the gravitational acceleration, so the actual acceleration is + /// obtainened by setting gravitational acceleration to zero, or subtracting it. + /// @param body_index index for frame/body + /// @param world_origin pointer for return data + /// @return 0 on success, -1 on error + int getBodyLinearAcceleration(const int body_index, vec3* world_acceleration) const; + +#if (defined BT_ID_HAVE_MAT3X) && (defined BT_ID_WITH_JACOBIANS) + // get translational jacobian, in world frame (dworld_velocity/du) + int getBodyJacobianTrans(const int body_index, mat3x* world_jac_trans) const; + // get rotational jacobian, in world frame (dworld_omega/du) + int getBodyJacobianRot(const int body_index, mat3x* world_jac_rot) const; + // get product of translational jacobian derivative * generatlized velocities + int getBodyDotJacobianTransU(const int body_index, vec3* world_dot_jac_trans_u) const; + // get product of rotational jacobian derivative * generatlized velocities + int getBodyDotJacobianRotU(const int body_index, vec3* world_dot_jac_rot_u) const; +#endif // BT_ID_HAVE_MAT3X + + /// returns the (internal) index of body + /// @param body_index is the index of a body + /// @param parent_index pointer to where parent index will be stored + /// @return 0 on success, -1 on error + int getParentIndex(const int body_index, int* parent_index) const; + /// get joint type + /// @param body_index index of the body + /// @param joint_type the corresponding joint type + /// @return 0 on success, -1 on failure + int getJointType(const int body_index, JointType* joint_type) const; + /// get joint type as string + /// @param body_index index of the body + /// @param joint_type string naming the corresponding joint type + /// @return 0 on success, -1 on failure + int getJointTypeStr(const int body_index, const char** joint_type) const; + /// get offset translation to parent body (see addBody) + /// @param body_index index of the body + /// @param r the offset translation (see above) + /// @return 0 on success, -1 on failure + int getParentRParentBodyRef(const int body_index, vec3* r) const; + /// get offset rotation to parent body (see addBody) + /// @param body_index index of the body + /// @param T the transform (see above) + /// @return 0 on success, -1 on failure + int getBodyTParentRef(const int body_index, mat33* T) const; + /// get axis of motion (see addBody) + /// @param body_index index of the body + /// @param axis the axis (see above) + /// @return 0 on success, -1 on failure + int getBodyAxisOfMotion(const int body_index, vec3* axis) const; + /// get offset for degrees of freedom of this body into the q-vector + /// @param body_index index of the body + /// @param q_offset offset the q vector + /// @return -1 on error, 0 on success + int getDoFOffset(const int body_index, int* q_offset) const; + /// get user integer. not used by the library. + /// @param body_index index of the body + /// @param user_int the user integer + /// @return 0 on success, -1 on error + int getUserInt(const int body_index, int* user_int) const; + /// get user pointer. not used by the library. + /// @param body_index index of the body + /// @param user_ptr the user pointer + /// @return 0 on success, -1 on error + int getUserPtr(const int body_index, void** user_ptr) const; + /// set user integer. not used by the library. + /// @param body_index index of the body + /// @param user_int the user integer + /// @return 0 on success, -1 on error + int setUserInt(const int body_index, const int user_int); + /// set user pointer. not used by the library. + /// @param body_index index of the body + /// @param user_ptr the user pointer + /// @return 0 on success, -1 on error + int setUserPtr(const int body_index, void* const user_ptr); + /// set mass for a body + /// @param body_index index of the body + /// @param mass the mass to set + /// @return 0 on success, -1 on failure + int setBodyMass(const int body_index, const idScalar mass); + /// set first moment of mass for a body + /// (mass * center of mass, in body fixed frame, relative to joint) + /// @param body_index index of the body + /// @param first_mass_moment the vector to set + /// @return 0 on success, -1 on failure + int setBodyFirstMassMoment(const int body_index, const vec3& first_mass_moment); + /// set second moment of mass for a body + /// (moment of inertia, in body fixed frame, relative to joint) + /// @param body_index index of the body + /// @param second_mass_moment the inertia matrix + /// @return 0 on success, -1 on failure + int setBodySecondMassMoment(const int body_index, const mat33& second_mass_moment); + /// get mass for a body + /// @param body_index index of the body + /// @param mass the mass + /// @return 0 on success, -1 on failure + int getBodyMass(const int body_index, idScalar* mass) const; + /// get first moment of mass for a body + /// (mass * center of mass, in body fixed frame, relative to joint) + /// @param body_index index of the body + /// @param first_moment the vector + /// @return 0 on success, -1 on failure + int getBodyFirstMassMoment(const int body_index, vec3* first_mass_moment) const; + /// get second moment of mass for a body + /// (moment of inertia, in body fixed frame, relative to joint) + /// @param body_index index of the body + /// @param second_mass_moment the inertia matrix + /// @return 0 on success, -1 on failure + int getBodySecondMassMoment(const int body_index, mat33* second_mass_moment) const; + /// set all user forces and moments to zero + void clearAllUserForcesAndMoments(); + /// Add an external force to a body, acting at the origin of the body-fixed frame. + /// Calls to addUserForce are cumulative. Set the user force and moment to zero + /// via clearAllUserForcesAndMoments() + /// @param body_force the force represented in the body-fixed frame of reference + /// @return 0 on success, -1 on error + int addUserForce(const int body_index, const vec3& body_force); + /// Add an external moment to a body. + /// Calls to addUserMoment are cumulative. Set the user force and moment to zero + /// via clearAllUserForcesAndMoments() + /// @param body_moment the moment represented in the body-fixed frame of reference + /// @return 0 on success, -1 on error + int addUserMoment(const int body_index, const vec3& body_moment); + +private: + // flag indicating if system has been initialized + bool m_is_finalized; + // flag indicating if mass properties are physically valid + bool m_mass_parameters_are_valid; + // flag defining if unphysical mass parameters are accepted + bool m_accept_invalid_mass_parameters; + // This struct implements the inverse dynamics calculations + class MultiBodyImpl; + MultiBodyImpl* m_impl; + // cache data structure for initialization + class InitCache; + InitCache* m_init_cache; +}; +} // namespace btInverseDynamics +#endif // MULTIBODYTREE_HPP_ diff --git a/extern/bullet/src/BulletInverseDynamics/details/IDEigenInterface.hpp b/extern/bullet/src/BulletInverseDynamics/details/IDEigenInterface.hpp new file mode 100644 index 000000000000..836395cea22e --- /dev/null +++ b/extern/bullet/src/BulletInverseDynamics/details/IDEigenInterface.hpp @@ -0,0 +1,36 @@ +#ifndef INVDYNEIGENINTERFACE_HPP_ +#define INVDYNEIGENINTERFACE_HPP_ +#include "../IDConfig.hpp" +namespace btInverseDynamics { + +#define BT_ID_HAVE_MAT3X + +#ifdef BT_USE_DOUBLE_PRECISION +typedef Eigen::Matrix vecx; +typedef Eigen::Matrix vec3; +typedef Eigen::Matrix mat33; +typedef Eigen::Matrix matxx; +typedef Eigen::Matrix mat3x; +#else +typedef Eigen::Matrix vecx; +typedef Eigen::Matrix vec3; +typedef Eigen::Matrix mat33; +typedef Eigen::Matrix matxx; +typedef Eigen::Matrix mat3x; +#endif + +inline void resize(mat3x &m, Eigen::Index size) { + m.resize(3, size); + m.setZero(); +} + +inline void setMatxxElem(const idArrayIdx row, const idArrayIdx col, const idScalar val, matxx*m){ + (*m)(row, col) = val; +} + +inline void setMat3xElem(const idArrayIdx row, const idArrayIdx col, const idScalar val, mat3x*m){ + (*m)(row, col) = val; +} + +} +#endif // INVDYNEIGENINTERFACE_HPP_ diff --git a/extern/bullet/src/BulletInverseDynamics/details/IDLinearMathInterface.hpp b/extern/bullet/src/BulletInverseDynamics/details/IDLinearMathInterface.hpp new file mode 100644 index 000000000000..5bb4a33bdd46 --- /dev/null +++ b/extern/bullet/src/BulletInverseDynamics/details/IDLinearMathInterface.hpp @@ -0,0 +1,172 @@ +#ifndef IDLINEARMATHINTERFACE_HPP_ +#define IDLINEARMATHINTERFACE_HPP_ + +#include + +#include "../IDConfig.hpp" + +#include "../../LinearMath/btMatrix3x3.h" +#include "../../LinearMath/btVector3.h" +#include "../../LinearMath/btMatrixX.h" +#define BT_ID_HAVE_MAT3X + +namespace btInverseDynamics { +class vec3; +class vecx; +class mat33; +typedef btMatrixX matxx; + +class vec3 : public btVector3 { +public: + vec3() : btVector3() {} + vec3(const btVector3& btv) { *this = btv; } + idScalar& operator()(int i) { return (*this)[i]; } + const idScalar& operator()(int i) const { return (*this)[i]; } + int size() const { return 3; } + const vec3& operator=(const btVector3& rhs) { + *static_cast(this) = rhs; + return *this; + } +}; + +class mat33 : public btMatrix3x3 { +public: + mat33() : btMatrix3x3() {} + mat33(const btMatrix3x3& btm) { *this = btm; } + idScalar& operator()(int i, int j) { return (*this)[i][j]; } + const idScalar& operator()(int i, int j) const { return (*this)[i][j]; } + const mat33& operator=(const btMatrix3x3& rhs) { + *static_cast(this) = rhs; + return *this; + } + friend mat33 operator*(const idScalar& s, const mat33& a); + friend mat33 operator/(const mat33& a, const idScalar& s); +}; + +inline mat33 operator/(const mat33& a, const idScalar& s) { return a * (1.0 / s); } + +inline mat33 operator*(const idScalar& s, const mat33& a) { return a * s; } + +class vecx : public btVectorX { +public: + vecx(int size) : btVectorX(size) {} + const vecx& operator=(const btVectorX& rhs) { + *static_cast(this) = rhs; + return *this; + } + + idScalar& operator()(int i) { return (*this)[i]; } + const idScalar& operator()(int i) const { return (*this)[i]; } + + friend vecx operator*(const vecx& a, const idScalar& s); + friend vecx operator*(const idScalar& s, const vecx& a); + + friend vecx operator+(const vecx& a, const vecx& b); + friend vecx operator-(const vecx& a, const vecx& b); + friend vecx operator/(const vecx& a, const idScalar& s); +}; + +inline vecx operator*(const vecx& a, const idScalar& s) { + vecx result(a.size()); + for (int i = 0; i < result.size(); i++) { + result(i) = a(i) * s; + } + return result; +} +inline vecx operator*(const idScalar& s, const vecx& a) { return a * s; } +inline vecx operator+(const vecx& a, const vecx& b) { + vecx result(a.size()); + // TODO: error handling for a.size() != b.size()?? + if (a.size() != b.size()) { + error_message("size missmatch. a.size()= %d, b.size()= %d\n", a.size(), b.size()); + abort(); + } + for (int i = 0; i < a.size(); i++) { + result(i) = a(i) + b(i); + } + + return result; +} + +inline vecx operator-(const vecx& a, const vecx& b) { + vecx result(a.size()); + // TODO: error handling for a.size() != b.size()?? + if (a.size() != b.size()) { + error_message("size missmatch. a.size()= %d, b.size()= %d\n", a.size(), b.size()); + abort(); + } + for (int i = 0; i < a.size(); i++) { + result(i) = a(i) - b(i); + } + return result; +} +inline vecx operator/(const vecx& a, const idScalar& s) { + vecx result(a.size()); + for (int i = 0; i < result.size(); i++) { + result(i) = a(i) / s; + } + + return result; +} + +// use btMatrixX to implement 3xX matrix +class mat3x : public matxx { +public: + mat3x(){} + mat3x(const mat3x&rhs) { + matxx::resize(rhs.rows(), rhs.cols()); + *this = rhs; + } + mat3x(int rows, int cols): matxx(3,cols) { + } + void operator=(const mat3x& rhs) { + if (m_cols != rhs.m_cols) { + error_message("size missmatch, cols= %d but rhs.cols= %d\n", cols(), rhs.cols()); + abort(); + } + for(int i=0;isetElem(row, col, val); +} + +inline void setMat3xElem(const idArrayIdx row, const idArrayIdx col, const idScalar val, mat3x*m){ + m->setElem(row, col, val); +} + +} + +#endif // IDLINEARMATHINTERFACE_HPP_ diff --git a/extern/bullet/src/BulletInverseDynamics/details/IDMatVec.hpp b/extern/bullet/src/BulletInverseDynamics/details/IDMatVec.hpp new file mode 100644 index 000000000000..4d3f6c87e9e1 --- /dev/null +++ b/extern/bullet/src/BulletInverseDynamics/details/IDMatVec.hpp @@ -0,0 +1,415 @@ +/// @file Built-In Matrix-Vector functions +#ifndef IDMATVEC_HPP_ +#define IDMATVEC_HPP_ + +#include + +#include "../IDConfig.hpp" +#define BT_ID_HAVE_MAT3X + +namespace btInverseDynamics { +class vec3; +class vecx; +class mat33; +class matxx; +class mat3x; + +/// This is a very basic implementation to enable stand-alone use of the library. +/// The implementation is not really optimized and misses many features that you would +/// want from a "fully featured" linear math library. +class vec3 { +public: + idScalar& operator()(int i) { return m_data[i]; } + const idScalar& operator()(int i) const { return m_data[i]; } + const int size() const { return 3; } + const vec3& operator=(const vec3& rhs); + const vec3& operator+=(const vec3& b); + const vec3& operator-=(const vec3& b); + vec3 cross(const vec3& b) const; + idScalar dot(const vec3& b) const; + + friend vec3 operator*(const mat33& a, const vec3& b); + friend vec3 operator*(const vec3& a, const idScalar& s); + friend vec3 operator*(const idScalar& s, const vec3& a); + + friend vec3 operator+(const vec3& a, const vec3& b); + friend vec3 operator-(const vec3& a, const vec3& b); + friend vec3 operator/(const vec3& a, const idScalar& s); + +private: + idScalar m_data[3]; +}; + +class mat33 { +public: + idScalar& operator()(int i, int j) { return m_data[3 * i + j]; } + const idScalar& operator()(int i, int j) const { return m_data[3 * i + j]; } + const mat33& operator=(const mat33& rhs); + mat33 transpose() const; + const mat33& operator+=(const mat33& b); + const mat33& operator-=(const mat33& b); + + friend mat33 operator*(const mat33& a, const mat33& b); + friend vec3 operator*(const mat33& a, const vec3& b); + friend mat33 operator*(const mat33& a, const idScalar& s); + friend mat33 operator*(const idScalar& s, const mat33& a); + friend mat33 operator+(const mat33& a, const mat33& b); + friend mat33 operator-(const mat33& a, const mat33& b); + friend mat33 operator/(const mat33& a, const idScalar& s); + +private: + // layout is [0,1,2;3,4,5;6,7,8] + idScalar m_data[9]; +}; + +class vecx { +public: + vecx(int size) : m_size(size) { + m_data = static_cast(idMalloc(sizeof(idScalar) * size)); + } + ~vecx() { idFree(m_data); } + const vecx& operator=(const vecx& rhs); + idScalar& operator()(int i) { return m_data[i]; } + const idScalar& operator()(int i) const { return m_data[i]; } + const int& size() const { return m_size; } + + friend vecx operator*(const vecx& a, const idScalar& s); + friend vecx operator*(const idScalar& s, const vecx& a); + + friend vecx operator+(const vecx& a, const vecx& b); + friend vecx operator-(const vecx& a, const vecx& b); + friend vecx operator/(const vecx& a, const idScalar& s); + +private: + int m_size; + idScalar* m_data; +}; + +class matxx { +public: + matxx() { + m_data = 0x0; + m_cols=0; + m_rows=0; + } + matxx(int rows, int cols) : m_rows(rows), m_cols(cols) { + m_data = static_cast(idMalloc(sizeof(idScalar) * rows * cols)); + } + ~matxx() { idFree(m_data); } + idScalar& operator()(int row, int col) { return m_data[row * m_cols + col]; } + const idScalar& operator()(int row, int col) const { return m_data[row * m_cols + col]; } + const int& rows() const { return m_rows; } + const int& cols() const { return m_cols; } + +private: + int m_rows; + int m_cols; + idScalar* m_data; +}; + +class mat3x { +public: + mat3x() { + m_data = 0x0; + m_cols=0; + } + mat3x(const mat3x&rhs) { + m_cols=rhs.m_cols; + allocate(); + *this = rhs; + } + mat3x(int rows, int cols): m_cols(cols) { + allocate(); + }; + void operator=(const mat3x& rhs) { + if (m_cols != rhs.m_cols) { + error_message("size missmatch, cols= %d but rhs.cols= %d\n", cols(), rhs.cols()); + abort(); + } + for(int i=0;i<3*m_cols;i++) { + m_data[i] = rhs.m_data[i]; + } + } + + ~mat3x() { + free(); + } + idScalar& operator()(int row, int col) { return m_data[row * m_cols + col]; } + const idScalar& operator()(int row, int col) const { return m_data[row * m_cols + col]; } + int rows() const { return m_rows; } + const int& cols() const { return m_cols; } + void resize(int rows, int cols) { + m_cols=cols; + free(); + allocate(); + } + void setZero() { + memset(m_data,0x0,sizeof(idScalar)*m_rows*m_cols); + } + // avoid operators that would allocate -- use functions sub/add/mul in IDMath.hpp instead +private: + void allocate(){m_data = static_cast(idMalloc(sizeof(idScalar) * m_rows * m_cols));} + void free() { idFree(m_data);} + enum {m_rows=3}; + int m_cols; + idScalar* m_data; +}; + +inline void resize(mat3x &m, idArrayIdx size) { + m.resize(3, size); + m.setZero(); +} + +////////////////////////////////////////////////// +// Implementations +inline const vec3& vec3::operator=(const vec3& rhs) { + if (&rhs != this) { + memcpy(m_data, rhs.m_data, 3 * sizeof(idScalar)); + } + return *this; +} + +inline vec3 vec3::cross(const vec3& b) const { + vec3 result; + result.m_data[0] = m_data[1] * b.m_data[2] - m_data[2] * b.m_data[1]; + result.m_data[1] = m_data[2] * b.m_data[0] - m_data[0] * b.m_data[2]; + result.m_data[2] = m_data[0] * b.m_data[1] - m_data[1] * b.m_data[0]; + + return result; +} + +inline idScalar vec3::dot(const vec3& b) const { + return m_data[0] * b.m_data[0] + m_data[1] * b.m_data[1] + m_data[2] * b.m_data[2]; +} + +inline const mat33& mat33::operator=(const mat33& rhs) { + if (&rhs != this) { + memcpy(m_data, rhs.m_data, 9 * sizeof(idScalar)); + } + return *this; +} +inline mat33 mat33::transpose() const { + mat33 result; + result.m_data[0] = m_data[0]; + result.m_data[1] = m_data[3]; + result.m_data[2] = m_data[6]; + result.m_data[3] = m_data[1]; + result.m_data[4] = m_data[4]; + result.m_data[5] = m_data[7]; + result.m_data[6] = m_data[2]; + result.m_data[7] = m_data[5]; + result.m_data[8] = m_data[8]; + + return result; +} + +inline mat33 operator*(const mat33& a, const mat33& b) { + mat33 result; + result.m_data[0] = + a.m_data[0] * b.m_data[0] + a.m_data[1] * b.m_data[3] + a.m_data[2] * b.m_data[6]; + result.m_data[1] = + a.m_data[0] * b.m_data[1] + a.m_data[1] * b.m_data[4] + a.m_data[2] * b.m_data[7]; + result.m_data[2] = + a.m_data[0] * b.m_data[2] + a.m_data[1] * b.m_data[5] + a.m_data[2] * b.m_data[8]; + result.m_data[3] = + a.m_data[3] * b.m_data[0] + a.m_data[4] * b.m_data[3] + a.m_data[5] * b.m_data[6]; + result.m_data[4] = + a.m_data[3] * b.m_data[1] + a.m_data[4] * b.m_data[4] + a.m_data[5] * b.m_data[7]; + result.m_data[5] = + a.m_data[3] * b.m_data[2] + a.m_data[4] * b.m_data[5] + a.m_data[5] * b.m_data[8]; + result.m_data[6] = + a.m_data[6] * b.m_data[0] + a.m_data[7] * b.m_data[3] + a.m_data[8] * b.m_data[6]; + result.m_data[7] = + a.m_data[6] * b.m_data[1] + a.m_data[7] * b.m_data[4] + a.m_data[8] * b.m_data[7]; + result.m_data[8] = + a.m_data[6] * b.m_data[2] + a.m_data[7] * b.m_data[5] + a.m_data[8] * b.m_data[8]; + + return result; +} + +inline const mat33& mat33::operator+=(const mat33& b) { + for (int i = 0; i < 9; i++) { + m_data[i] += b.m_data[i]; + } + + return *this; +} + +inline const mat33& mat33::operator-=(const mat33& b) { + for (int i = 0; i < 9; i++) { + m_data[i] -= b.m_data[i]; + } + return *this; +} + +inline vec3 operator*(const mat33& a, const vec3& b) { + vec3 result; + + result.m_data[0] = + a.m_data[0] * b.m_data[0] + a.m_data[1] * b.m_data[1] + a.m_data[2] * b.m_data[2]; + result.m_data[1] = + a.m_data[3] * b.m_data[0] + a.m_data[4] * b.m_data[1] + a.m_data[5] * b.m_data[2]; + result.m_data[2] = + a.m_data[6] * b.m_data[0] + a.m_data[7] * b.m_data[1] + a.m_data[8] * b.m_data[2]; + + return result; +} + +inline const vec3& vec3::operator+=(const vec3& b) { + for (int i = 0; i < 3; i++) { + m_data[i] += b.m_data[i]; + } + return *this; +} + +inline const vec3& vec3::operator-=(const vec3& b) { + for (int i = 0; i < 3; i++) { + m_data[i] -= b.m_data[i]; + } + return *this; +} + +inline mat33 operator*(const mat33& a, const idScalar& s) { + mat33 result; + for (int i = 0; i < 9; i++) { + result.m_data[i] = a.m_data[i] * s; + } + return result; +} + +inline mat33 operator*(const idScalar& s, const mat33& a) { return a * s; } + +inline vec3 operator*(const vec3& a, const idScalar& s) { + vec3 result; + for (int i = 0; i < 3; i++) { + result.m_data[i] = a.m_data[i] * s; + } + return result; +} +inline vec3 operator*(const idScalar& s, const vec3& a) { return a * s; } + +inline mat33 operator+(const mat33& a, const mat33& b) { + mat33 result; + for (int i = 0; i < 9; i++) { + result.m_data[i] = a.m_data[i] + b.m_data[i]; + } + return result; +} +inline vec3 operator+(const vec3& a, const vec3& b) { + vec3 result; + for (int i = 0; i < 3; i++) { + result.m_data[i] = a.m_data[i] + b.m_data[i]; + } + return result; +} + +inline mat33 operator-(const mat33& a, const mat33& b) { + mat33 result; + for (int i = 0; i < 9; i++) { + result.m_data[i] = a.m_data[i] - b.m_data[i]; + } + return result; +} +inline vec3 operator-(const vec3& a, const vec3& b) { + vec3 result; + for (int i = 0; i < 3; i++) { + result.m_data[i] = a.m_data[i] - b.m_data[i]; + } + return result; +} + +inline mat33 operator/(const mat33& a, const idScalar& s) { + mat33 result; + for (int i = 0; i < 9; i++) { + result.m_data[i] = a.m_data[i] / s; + } + return result; +} + +inline vec3 operator/(const vec3& a, const idScalar& s) { + vec3 result; + for (int i = 0; i < 3; i++) { + result.m_data[i] = a.m_data[i] / s; + } + return result; +} + +inline const vecx& vecx::operator=(const vecx& rhs) { + if (size() != rhs.size()) { + error_message("size missmatch, size()= %d but rhs.size()= %d\n", size(), rhs.size()); + abort(); + } + if (&rhs != this) { + memcpy(m_data, rhs.m_data, rhs.size() * sizeof(idScalar)); + } + return *this; +} +inline vecx operator*(const vecx& a, const idScalar& s) { + vecx result(a.size()); + for (int i = 0; i < result.size(); i++) { + result.m_data[i] = a.m_data[i] * s; + } + return result; +} +inline vecx operator*(const idScalar& s, const vecx& a) { return a * s; } +inline vecx operator+(const vecx& a, const vecx& b) { + vecx result(a.size()); + // TODO: error handling for a.size() != b.size()?? + if (a.size() != b.size()) { + error_message("size missmatch. a.size()= %d, b.size()= %d\n", a.size(), b.size()); + abort(); + } + for (int i = 0; i < a.size(); i++) { + result.m_data[i] = a.m_data[i] + b.m_data[i]; + } + + return result; +} +inline vecx operator-(const vecx& a, const vecx& b) { + vecx result(a.size()); + // TODO: error handling for a.size() != b.size()?? + if (a.size() != b.size()) { + error_message("size missmatch. a.size()= %d, b.size()= %d\n", a.size(), b.size()); + abort(); + } + for (int i = 0; i < a.size(); i++) { + result.m_data[i] = a.m_data[i] - b.m_data[i]; + } + return result; +} +inline vecx operator/(const vecx& a, const idScalar& s) { + vecx result(a.size()); + for (int i = 0; i < result.size(); i++) { + result.m_data[i] = a.m_data[i] / s; + } + + return result; +} + +inline vec3 operator*(const mat3x& a, const vecx& b) { + vec3 result; + if (a.cols() != b.size()) { + error_message("size missmatch. a.cols()= %d, b.size()= %d\n", a.cols(), b.size()); + abort(); + } + result(0)=0.0; + result(1)=0.0; + result(2)=0.0; + for(int i=0;i(i)); + id_printf("type: %s\n", jointTypeToString(body.m_joint_type)); + id_printf("q_index= %d\n", body.m_q_index); + id_printf("Jac_JR= [%f;%f;%f]\n", body.m_Jac_JR(0), body.m_Jac_JR(1), body.m_Jac_JR(2)); + id_printf("Jac_JT= [%f;%f;%f]\n", body.m_Jac_JT(0), body.m_Jac_JT(1), body.m_Jac_JT(2)); + + id_printf("mass = %f\n", body.m_mass); + id_printf("mass * com = [%f %f %f]\n", body.m_body_mass_com(0), body.m_body_mass_com(1), + body.m_body_mass_com(2)); + id_printf("I_o= [%f %f %f;\n" + " %f %f %f;\n" + " %f %f %f]\n", + body.m_body_I_body(0, 0), body.m_body_I_body(0, 1), body.m_body_I_body(0, 2), + body.m_body_I_body(1, 0), body.m_body_I_body(1, 1), body.m_body_I_body(1, 2), + body.m_body_I_body(2, 0), body.m_body_I_body(2, 1), body.m_body_I_body(2, 2)); + + id_printf("parent_pos_parent_body_ref= [%f %f %f]\n", body.m_parent_pos_parent_body_ref(0), + body.m_parent_pos_parent_body_ref(1), body.m_parent_pos_parent_body_ref(2)); + } +} +int MultiBodyTree::MultiBodyImpl::bodyNumDoFs(const JointType &type) const { + switch (type) { + case FIXED: + return 0; + case REVOLUTE: + case PRISMATIC: + return 1; + case FLOATING: + return 6; + } + error_message("unknown joint type %d\n", type); + return 0; +} + +void MultiBodyTree::MultiBodyImpl::printTree(int index, int indentation) { + // this is adapted from URDF2Bullet. + // TODO: fix this and print proper graph (similar to git --log --graph) + int num_children = m_child_indices[index].size(); + + indentation += 2; + int count = 0; + + for (int i = 0; i < num_children; i++) { + int child_index = m_child_indices[index][i]; + indent(indentation); + id_printf("body %.2d[%s]: %.2d is child no. %d (qi= %d .. %d) \n", index, + jointTypeToString(m_body_list[index].m_joint_type), child_index, (count++) + 1, + m_body_list[index].m_q_index, + m_body_list[index].m_q_index + bodyNumDoFs(m_body_list[index].m_joint_type)); + // first grandchild + printTree(child_index, indentation); + } +} + +int MultiBodyTree::MultiBodyImpl::setGravityInWorldFrame(const vec3 &gravity) { + m_world_gravity = gravity; + return 0; +} + +int MultiBodyTree::MultiBodyImpl::generateIndexSets() { + m_body_revolute_list.resize(0); + m_body_prismatic_list.resize(0); + int q_index = 0; + for (idArrayIdx i = 0; i < m_body_list.size(); i++) { + RigidBody &body = m_body_list[i]; + body.m_q_index = -1; + switch (body.m_joint_type) { + case REVOLUTE: + m_body_revolute_list.push_back(i); + body.m_q_index = q_index; + q_index++; + break; + case PRISMATIC: + m_body_prismatic_list.push_back(i); + body.m_q_index = q_index; + q_index++; + break; + case FIXED: + // do nothing + break; + case FLOATING: + m_body_floating_list.push_back(i); + body.m_q_index = q_index; + q_index += 6; + break; + default: + error_message("unsupported joint type %d\n", body.m_joint_type); + return -1; + } + } + // sanity check + if (q_index != m_num_dofs) { + error_message("internal error, q_index= %d but num_dofs %d\n", q_index, m_num_dofs); + return -1; + } + + m_child_indices.resize(m_body_list.size()); + + for (idArrayIdx child = 1; child < m_parent_index.size(); child++) { + const int &parent = m_parent_index[child]; + if (parent >= 0 && parent < (static_cast(m_parent_index.size()) - 1)) { + m_child_indices[parent].push_back(child); + } else { + if (-1 == parent) { + // multiple bodies are directly linked to the environment, ie, not a single root + error_message("building index sets parent(%zu)= -1 (multiple roots)\n", child); + } else { + // should never happen + error_message( + "building index sets. parent_index[%zu]= %d, but m_parent_index.size()= %d\n", + child, parent, static_cast(m_parent_index.size())); + } + return -1; + } + } + + return 0; +} + +void MultiBodyTree::MultiBodyImpl::calculateStaticData() { + // relative kinematics that are not a function of q, u, dot_u + for (idArrayIdx i = 0; i < m_body_list.size(); i++) { + RigidBody &body = m_body_list[i]; + switch (body.m_joint_type) { + case REVOLUTE: + body.m_parent_vel_rel(0) = 0; + body.m_parent_vel_rel(1) = 0; + body.m_parent_vel_rel(2) = 0; + body.m_parent_acc_rel(0) = 0; + body.m_parent_acc_rel(1) = 0; + body.m_parent_acc_rel(2) = 0; + body.m_parent_pos_parent_body = body.m_parent_pos_parent_body_ref; + break; + case PRISMATIC: + body.m_body_T_parent = body.m_body_T_parent_ref; + body.m_parent_Jac_JT = body.m_body_T_parent_ref.transpose() * body.m_Jac_JT; + body.m_body_ang_vel_rel(0) = 0; + body.m_body_ang_vel_rel(1) = 0; + body.m_body_ang_vel_rel(2) = 0; + body.m_body_ang_acc_rel(0) = 0; + body.m_body_ang_acc_rel(1) = 0; + body.m_body_ang_acc_rel(2) = 0; + break; + case FIXED: + body.m_parent_pos_parent_body = body.m_parent_pos_parent_body_ref; + body.m_body_T_parent = body.m_body_T_parent_ref; + body.m_body_ang_vel_rel(0) = 0; + body.m_body_ang_vel_rel(1) = 0; + body.m_body_ang_vel_rel(2) = 0; + body.m_parent_vel_rel(0) = 0; + body.m_parent_vel_rel(1) = 0; + body.m_parent_vel_rel(2) = 0; + body.m_body_ang_acc_rel(0) = 0; + body.m_body_ang_acc_rel(1) = 0; + body.m_body_ang_acc_rel(2) = 0; + body.m_parent_acc_rel(0) = 0; + body.m_parent_acc_rel(1) = 0; + body.m_parent_acc_rel(2) = 0; + break; + case FLOATING: + // no static data + break; + } + + // resize & initialize jacobians to zero. +#if (defined BT_ID_HAVE_MAT3X) && (defined BT_ID_WITH_JACOBIANS) + body.m_body_dot_Jac_T_u(0) = 0.0; + body.m_body_dot_Jac_T_u(1) = 0.0; + body.m_body_dot_Jac_T_u(2) = 0.0; + body.m_body_dot_Jac_R_u(0) = 0.0; + body.m_body_dot_Jac_R_u(1) = 0.0; + body.m_body_dot_Jac_R_u(2) = 0.0; + resize(body.m_body_Jac_T,m_num_dofs); + resize(body.m_body_Jac_R,m_num_dofs); + body.m_body_Jac_T.setZero(); + body.m_body_Jac_R.setZero(); +#endif // + } +} + +int MultiBodyTree::MultiBodyImpl::calculateInverseDynamics(const vecx &q, const vecx &u, + const vecx &dot_u, vecx *joint_forces) { + if (q.size() != m_num_dofs || u.size() != m_num_dofs || dot_u.size() != m_num_dofs || + joint_forces->size() != m_num_dofs) { + error_message("wrong vector dimension. system has %d DOFs,\n" + "but dim(q)= %d, dim(u)= %d, dim(dot_u)= %d, dim(joint_forces)= %d\n", + m_num_dofs, static_cast(q.size()), static_cast(u.size()), + static_cast(dot_u.size()), static_cast(joint_forces->size())); + return -1; + } + // 1. relative kinematics + if(-1 == calculateKinematics(q,u,dot_u, POSITION_VELOCITY_ACCELERATION)) { + error_message("error in calculateKinematics\n"); + return -1; + } + // 2. update contributions to equations of motion for every body. + for (idArrayIdx i = 0; i < m_body_list.size(); i++) { + RigidBody &body = m_body_list[i]; + // 3.4 update dynamic terms (rate of change of angular & linear momentum) + body.m_eom_lhs_rotational = + body.m_body_I_body * body.m_body_ang_acc + body.m_body_mass_com.cross(body.m_body_acc) + + body.m_body_ang_vel.cross(body.m_body_I_body * body.m_body_ang_vel) - + body.m_body_moment_user; + body.m_eom_lhs_translational = + body.m_body_ang_acc.cross(body.m_body_mass_com) + body.m_mass * body.m_body_acc + + body.m_body_ang_vel.cross(body.m_body_ang_vel.cross(body.m_body_mass_com)) - + body.m_body_force_user; + } + + // 3. calculate full set of forces at parent joint + // (not directly calculating the joint force along the free direction + // simplifies inclusion of fixed joints. + // An alternative would be to fuse bodies in a pre-processing step, + // but that would make changing masses online harder (eg, payload masses + // added with fixed joints to a gripper) + // Also, this enables adding zero weight bodies as a way to calculate frame poses + // for force elements, etc. + + for (int body_idx = m_body_list.size() - 1; body_idx >= 0; body_idx--) { + // sum of forces and moments acting on this body from its children + vec3 sum_f_children; + vec3 sum_m_children; + setZero(sum_f_children); + setZero(sum_m_children); + for (idArrayIdx child_list_idx = 0; child_list_idx < m_child_indices[body_idx].size(); + child_list_idx++) { + const RigidBody &child = m_body_list[m_child_indices[body_idx][child_list_idx]]; + vec3 child_joint_force_in_this_frame = + child.m_body_T_parent.transpose() * child.m_force_at_joint; + sum_f_children -= child_joint_force_in_this_frame; + sum_m_children -= child.m_body_T_parent.transpose() * child.m_moment_at_joint + + child.m_parent_pos_parent_body.cross(child_joint_force_in_this_frame); + } + RigidBody &body = m_body_list[body_idx]; + + body.m_force_at_joint = body.m_eom_lhs_translational - sum_f_children; + body.m_moment_at_joint = body.m_eom_lhs_rotational - sum_m_children; + } + + // 4. Calculate Joint forces. + // These are the components of force_at_joint/moment_at_joint + // in the free directions given by Jac_JT/Jac_JR + // 4.1 revolute joints + for (idArrayIdx i = 0; i < m_body_revolute_list.size(); i++) { + RigidBody &body = m_body_list[m_body_revolute_list[i]]; + // (*joint_forces)(body.m_q_index) = body.m_Jac_JR.transpose() * body.m_moment_at_joint; + (*joint_forces)(body.m_q_index) = body.m_Jac_JR.dot(body.m_moment_at_joint); + } + // 4.2 for prismatic joints + for (idArrayIdx i = 0; i < m_body_prismatic_list.size(); i++) { + RigidBody &body = m_body_list[m_body_prismatic_list[i]]; + // (*joint_forces)(body.m_q_index) = body.m_Jac_JT.transpose() * body.m_force_at_joint; + (*joint_forces)(body.m_q_index) = body.m_Jac_JT.dot(body.m_force_at_joint); + } + // 4.3 floating bodies (6-DoF joints) + for (idArrayIdx i = 0; i < m_body_floating_list.size(); i++) { + RigidBody &body = m_body_list[m_body_floating_list[i]]; + (*joint_forces)(body.m_q_index + 0) = body.m_moment_at_joint(0); + (*joint_forces)(body.m_q_index + 1) = body.m_moment_at_joint(1); + (*joint_forces)(body.m_q_index + 2) = body.m_moment_at_joint(2); + + (*joint_forces)(body.m_q_index + 3) = body.m_force_at_joint(0); + (*joint_forces)(body.m_q_index + 4) = body.m_force_at_joint(1); + (*joint_forces)(body.m_q_index + 5) = body.m_force_at_joint(2); + } + + return 0; +} + +int MultiBodyTree::MultiBodyImpl::calculateKinematics(const vecx &q, const vecx &u, const vecx& dot_u, + const KinUpdateType type) { + if (q.size() != m_num_dofs || u.size() != m_num_dofs || dot_u.size() != m_num_dofs ) { + error_message("wrong vector dimension. system has %d DOFs,\n" + "but dim(q)= %d, dim(u)= %d, dim(dot_u)= %d\n", + m_num_dofs, static_cast(q.size()), static_cast(u.size()), + static_cast(dot_u.size())); + return -1; + } + if(type != POSITION_ONLY && type != POSITION_VELOCITY && type != POSITION_VELOCITY_ACCELERATION) { + error_message("invalid type %d\n", type); + return -1; + } + + // 1. update relative kinematics + // 1.1 for revolute + for (idArrayIdx i = 0; i < m_body_revolute_list.size(); i++) { + RigidBody &body = m_body_list[m_body_revolute_list[i]]; + mat33 T; + bodyTParentFromAxisAngle(body.m_Jac_JR, q(body.m_q_index), &T); + body.m_body_T_parent = T * body.m_body_T_parent_ref; + if(type >= POSITION_VELOCITY) { + body.m_body_ang_vel_rel = body.m_Jac_JR * u(body.m_q_index); + } + if(type >= POSITION_VELOCITY_ACCELERATION) { + body.m_body_ang_acc_rel = body.m_Jac_JR * dot_u(body.m_q_index); + } + } + // 1.2 for prismatic + for (idArrayIdx i = 0; i < m_body_prismatic_list.size(); i++) { + RigidBody &body = m_body_list[m_body_prismatic_list[i]]; + body.m_parent_pos_parent_body = + body.m_parent_pos_parent_body_ref + body.m_parent_Jac_JT * q(body.m_q_index); + if(type >= POSITION_VELOCITY) { + body.m_parent_vel_rel = + body.m_body_T_parent_ref.transpose() * body.m_Jac_JT * u(body.m_q_index); + } + if(type >= POSITION_VELOCITY_ACCELERATION) { + body.m_parent_acc_rel = body.m_parent_Jac_JT * dot_u(body.m_q_index); + } + } + // 1.3 fixed joints: nothing to do + // 1.4 6dof joints: + for (idArrayIdx i = 0; i < m_body_floating_list.size(); i++) { + RigidBody &body = m_body_list[m_body_floating_list[i]]; + + body.m_body_T_parent = transformZ(q(body.m_q_index + 2)) * + transformY(q(body.m_q_index + 1)) * transformX(q(body.m_q_index)); + body.m_parent_pos_parent_body(0) = q(body.m_q_index + 3); + body.m_parent_pos_parent_body(1) = q(body.m_q_index + 4); + body.m_parent_pos_parent_body(2) = q(body.m_q_index + 5); + body.m_parent_pos_parent_body = body.m_body_T_parent * body.m_parent_pos_parent_body; + + if(type >= POSITION_VELOCITY) { + body.m_body_ang_vel_rel(0) = u(body.m_q_index + 0); + body.m_body_ang_vel_rel(1) = u(body.m_q_index + 1); + body.m_body_ang_vel_rel(2) = u(body.m_q_index + 2); + + body.m_parent_vel_rel(0) = u(body.m_q_index + 3); + body.m_parent_vel_rel(1) = u(body.m_q_index + 4); + body.m_parent_vel_rel(2) = u(body.m_q_index + 5); + + body.m_parent_vel_rel = body.m_body_T_parent.transpose() * body.m_parent_vel_rel; + } + if(type >= POSITION_VELOCITY_ACCELERATION) { + body.m_body_ang_acc_rel(0) = dot_u(body.m_q_index + 0); + body.m_body_ang_acc_rel(1) = dot_u(body.m_q_index + 1); + body.m_body_ang_acc_rel(2) = dot_u(body.m_q_index + 2); + + body.m_parent_acc_rel(0) = dot_u(body.m_q_index + 3); + body.m_parent_acc_rel(1) = dot_u(body.m_q_index + 4); + body.m_parent_acc_rel(2) = dot_u(body.m_q_index + 5); + + body.m_parent_acc_rel = body.m_body_T_parent.transpose() * body.m_parent_acc_rel; + } + } + + // 2. absolute kinematic quantities (vector valued) + // NOTE: this should be optimized by specializing for different body types + // (e.g., relative rotation is always zero for prismatic joints, etc.) + + // calculations for root body + { + RigidBody &body = m_body_list[0]; + // 3.1 update absolute positions and orientations: + // will be required if we add force elements (eg springs between bodies, + // or contacts) + // not required right now, added here for debugging purposes + body.m_body_pos = body.m_body_T_parent * body.m_parent_pos_parent_body; + body.m_body_T_world = body.m_body_T_parent; + + if(type >= POSITION_VELOCITY) { + // 3.2 update absolute velocities + body.m_body_ang_vel = body.m_body_ang_vel_rel; + body.m_body_vel = body.m_parent_vel_rel; + } + if(type >= POSITION_VELOCITY_ACCELERATION) { + // 3.3 update absolute accelerations + // NOTE: assumption: dot(J_JR) = 0; true here, but not for general joints + body.m_body_ang_acc = body.m_body_ang_acc_rel; + body.m_body_acc = body.m_body_T_parent * body.m_parent_acc_rel; + // add gravitational acceleration to root body + // this is an efficient way to add gravitational terms, + // but it does mean that the kinematics are no longer + // correct at the acceleration level + // NOTE: To get correct acceleration kinematics, just set world_gravity to zero + body.m_body_acc = body.m_body_acc - body.m_body_T_parent * m_world_gravity; + } + } + + for (idArrayIdx i = 1; i < m_body_list.size(); i++) { + RigidBody &body = m_body_list[i]; + RigidBody &parent = m_body_list[m_parent_index[i]]; + // 2.1 update absolute positions and orientations: + // will be required if we add force elements (eg springs between bodies, + // or contacts) not required right now added here for debugging purposes + body.m_body_pos = + body.m_body_T_parent * (parent.m_body_pos + body.m_parent_pos_parent_body); + body.m_body_T_world = body.m_body_T_parent * parent.m_body_T_world; + + if(type >= POSITION_VELOCITY) { + // 2.2 update absolute velocities + body.m_body_ang_vel = + body.m_body_T_parent * parent.m_body_ang_vel + body.m_body_ang_vel_rel; + + body.m_body_vel = + body.m_body_T_parent * + (parent.m_body_vel + parent.m_body_ang_vel.cross(body.m_parent_pos_parent_body) + + body.m_parent_vel_rel); + } + if(type >= POSITION_VELOCITY_ACCELERATION) { + // 2.3 update absolute accelerations + // NOTE: assumption: dot(J_JR) = 0; true here, but not for general joints + body.m_body_ang_acc = + body.m_body_T_parent * parent.m_body_ang_acc - + body.m_body_ang_vel_rel.cross(body.m_body_T_parent * parent.m_body_ang_vel) + + body.m_body_ang_acc_rel; + body.m_body_acc = + body.m_body_T_parent * + (parent.m_body_acc + parent.m_body_ang_acc.cross(body.m_parent_pos_parent_body) + + parent.m_body_ang_vel.cross(parent.m_body_ang_vel.cross(body.m_parent_pos_parent_body)) + + 2.0 * parent.m_body_ang_vel.cross(body.m_parent_vel_rel) + body.m_parent_acc_rel); + } + } + + return 0; +} + +#if (defined BT_ID_HAVE_MAT3X) && (defined BT_ID_WITH_JACOBIANS) + +void MultiBodyTree::MultiBodyImpl::addRelativeJacobianComponent(RigidBody&body) { + const int& idx=body.m_q_index; + switch(body.m_joint_type) { + case FIXED: + break; + case REVOLUTE: + setMat3xElem(0,idx, body.m_Jac_JR(0), &body.m_body_Jac_R); + setMat3xElem(1,idx, body.m_Jac_JR(1), &body.m_body_Jac_R); + setMat3xElem(2,idx, body.m_Jac_JR(2), &body.m_body_Jac_R); + break; + case PRISMATIC: + setMat3xElem(0,idx, body.m_body_T_parent_ref(0,0)*body.m_Jac_JT(0) + +body.m_body_T_parent_ref(1,0)*body.m_Jac_JT(1) + +body.m_body_T_parent_ref(2,0)*body.m_Jac_JT(2), + &body.m_body_Jac_T); + setMat3xElem(1,idx,body.m_body_T_parent_ref(0,1)*body.m_Jac_JT(0) + +body.m_body_T_parent_ref(1,1)*body.m_Jac_JT(1) + +body.m_body_T_parent_ref(2,1)*body.m_Jac_JT(2), + &body.m_body_Jac_T); + setMat3xElem(2,idx, body.m_body_T_parent_ref(0,2)*body.m_Jac_JT(0) + +body.m_body_T_parent_ref(1,2)*body.m_Jac_JT(1) + +body.m_body_T_parent_ref(2,2)*body.m_Jac_JT(2), + &body.m_body_Jac_T); + break; + case FLOATING: + setMat3xElem(0,idx+0, 1.0, &body.m_body_Jac_R); + setMat3xElem(1,idx+1, 1.0, &body.m_body_Jac_R); + setMat3xElem(2,idx+2, 1.0, &body.m_body_Jac_R); + // body_Jac_T = body_T_parent.transpose(); + setMat3xElem(0,idx+3, body.m_body_T_parent(0,0), &body.m_body_Jac_T); + setMat3xElem(0,idx+4, body.m_body_T_parent(1,0), &body.m_body_Jac_T); + setMat3xElem(0,idx+5, body.m_body_T_parent(2,0), &body.m_body_Jac_T); + + setMat3xElem(1,idx+3, body.m_body_T_parent(0,1), &body.m_body_Jac_T); + setMat3xElem(1,idx+4, body.m_body_T_parent(1,1), &body.m_body_Jac_T); + setMat3xElem(1,idx+5, body.m_body_T_parent(2,1), &body.m_body_Jac_T); + + setMat3xElem(2,idx+3, body.m_body_T_parent(0,2), &body.m_body_Jac_T); + setMat3xElem(2,idx+4, body.m_body_T_parent(1,2), &body.m_body_Jac_T); + setMat3xElem(2,idx+5, body.m_body_T_parent(2,2), &body.m_body_Jac_T); + + break; + } +} + +int MultiBodyTree::MultiBodyImpl::calculateJacobians(const vecx& q, const vecx& u, const KinUpdateType type) { + if (q.size() != m_num_dofs || u.size() != m_num_dofs) { + error_message("wrong vector dimension. system has %d DOFs,\n" + "but dim(q)= %d, dim(u)= %d\n", + m_num_dofs, static_cast(q.size()), static_cast(u.size())); + return -1; + } + if(type != POSITION_ONLY && type != POSITION_VELOCITY) { + error_message("invalid type %d\n", type); + return -1; + } + + addRelativeJacobianComponent(m_body_list[0]); + for (idArrayIdx i = 1; i < m_body_list.size(); i++) { + RigidBody &body = m_body_list[i]; + RigidBody &parent = m_body_list[m_parent_index[i]]; + + mul(body.m_body_T_parent, parent.m_body_Jac_R,& body.m_body_Jac_R); + body.m_body_Jac_T = parent.m_body_Jac_T; + mul(tildeOperator(body.m_parent_pos_parent_body),parent.m_body_Jac_R,&m_m3x); + sub(body.m_body_Jac_T,m_m3x, &body.m_body_Jac_T); + + addRelativeJacobianComponent(body); + mul(body.m_body_T_parent, body.m_body_Jac_T,&body.m_body_Jac_T); + + if(type >= POSITION_VELOCITY) { + body.m_body_dot_Jac_R_u = body.m_body_T_parent * parent.m_body_dot_Jac_R_u - + body.m_body_ang_vel_rel.cross(body.m_body_T_parent * parent.m_body_ang_vel); + body.m_body_dot_Jac_T_u = body.m_body_T_parent * + (parent.m_body_dot_Jac_T_u + parent.m_body_dot_Jac_R_u.cross(body.m_parent_pos_parent_body) + + parent.m_body_ang_vel.cross(parent.m_body_ang_vel.cross(body.m_parent_pos_parent_body)) + + 2.0 * parent.m_body_ang_vel.cross(body.m_parent_vel_rel)); + } + } + return 0; +} +#endif + +static inline void setSixDoFJacobians(const int dof, vec3 &Jac_JR, vec3 &Jac_JT) { + switch (dof) { + // rotational part + case 0: + Jac_JR(0) = 1; + Jac_JR(1) = 0; + Jac_JR(2) = 0; + setZero(Jac_JT); + break; + case 1: + Jac_JR(0) = 0; + Jac_JR(1) = 1; + Jac_JR(2) = 0; + setZero(Jac_JT); + break; + case 2: + Jac_JR(0) = 0; + Jac_JR(1) = 0; + Jac_JR(2) = 1; + setZero(Jac_JT); + break; + // translational part + case 3: + setZero(Jac_JR); + Jac_JT(0) = 1; + Jac_JT(1) = 0; + Jac_JT(2) = 0; + break; + case 4: + setZero(Jac_JR); + Jac_JT(0) = 0; + Jac_JT(1) = 1; + Jac_JT(2) = 0; + break; + case 5: + setZero(Jac_JR); + Jac_JT(0) = 0; + Jac_JT(1) = 0; + Jac_JT(2) = 1; + break; + } +} + +static inline int jointNumDoFs(const JointType &type) { + switch (type) { + case FIXED: + return 0; + case REVOLUTE: + case PRISMATIC: + return 1; + case FLOATING: + return 6; + } + // this should never happen + error_message("invalid joint type\n"); + // TODO add configurable abort/crash function + abort(); + return 0; +} + +int MultiBodyTree::MultiBodyImpl::calculateMassMatrix(const vecx &q, const bool update_kinematics, + const bool initialize_matrix, + const bool set_lower_triangular_matrix, + matxx *mass_matrix) { +// This calculates the joint space mass matrix for the multibody system. +// The algorithm is essentially an implementation of "method 3" +// in "Efficient Dynamic Simulation of Robotic Mechanisms" (Walker and Orin, 1982) +// (Later named "Composite Rigid Body Algorithm" by Featherstone). +// +// This implementation, however, handles branched systems and uses a formulation centered +// on the origin of the body-fixed frame to avoid re-computing various quantities at the com. + + if (q.size() != m_num_dofs || mass_matrix->rows() != m_num_dofs || + mass_matrix->cols() != m_num_dofs) { + error_message("Dimension error. System has %d DOFs,\n" + "but dim(q)= %d, dim(mass_matrix)= %d x %d\n", + m_num_dofs, static_cast(q.size()), static_cast(mass_matrix->rows()), + static_cast(mass_matrix->cols())); + return -1; + } + + // TODO add optimized zeroing function? + if (initialize_matrix) { + for (int i = 0; i < m_num_dofs; i++) { + for (int j = 0; j < m_num_dofs; j++) { + setMatxxElem(i, j, 0.0, mass_matrix); + } + } + } + + if (update_kinematics) { + // 1. update relative kinematics + // 1.1 for revolute joints + for (idArrayIdx i = 0; i < m_body_revolute_list.size(); i++) { + RigidBody &body = m_body_list[m_body_revolute_list[i]]; + // from reference orientation (q=0) of body-fixed frame to current orientation + mat33 body_T_body_ref; + bodyTParentFromAxisAngle(body.m_Jac_JR, q(body.m_q_index), &body_T_body_ref); + body.m_body_T_parent = body_T_body_ref * body.m_body_T_parent_ref; + } + // 1.2 for prismatic joints + for (idArrayIdx i = 0; i < m_body_prismatic_list.size(); i++) { + RigidBody &body = m_body_list[m_body_prismatic_list[i]]; + // body.m_body_T_parent= fixed + body.m_parent_pos_parent_body = + body.m_parent_pos_parent_body_ref + body.m_parent_Jac_JT * q(body.m_q_index); + } + // 1.3 fixed joints: nothing to do + // 1.4 6dof joints: + for (idArrayIdx i = 0; i < m_body_floating_list.size(); i++) { + RigidBody &body = m_body_list[m_body_floating_list[i]]; + + body.m_body_T_parent = transformZ(q(body.m_q_index + 2)) * + transformY(q(body.m_q_index + 1)) * + transformX(q(body.m_q_index)); + body.m_parent_pos_parent_body(0) = q(body.m_q_index + 3); + body.m_parent_pos_parent_body(1) = q(body.m_q_index + 4); + body.m_parent_pos_parent_body(2) = q(body.m_q_index + 5); + + body.m_parent_pos_parent_body = body.m_body_T_parent * body.m_parent_pos_parent_body; + } + } + for (int i = m_body_list.size() - 1; i >= 0; i--) { + RigidBody &body = m_body_list[i]; + // calculate mass, center of mass and inertia of "composite rigid body", + // ie, sub-tree starting at current body + body.m_subtree_mass = body.m_mass; + body.m_body_subtree_mass_com = body.m_body_mass_com; + body.m_body_subtree_I_body = body.m_body_I_body; + + for (idArrayIdx c = 0; c < m_child_indices[i].size(); c++) { + RigidBody &child = m_body_list[m_child_indices[i][c]]; + mat33 body_T_child = child.m_body_T_parent.transpose(); + + body.m_subtree_mass += child.m_subtree_mass; + body.m_body_subtree_mass_com += body_T_child * child.m_body_subtree_mass_com + + child.m_parent_pos_parent_body * child.m_subtree_mass; + body.m_body_subtree_I_body += + body_T_child * child.m_body_subtree_I_body * child.m_body_T_parent; + + if (child.m_subtree_mass > 0) { + // Shift the reference point for the child subtree inertia using the + // Huygens-Steiner ("parallel axis") theorem. + // (First shift from child origin to child com, then from there to this body's + // origin) + vec3 r_com = body_T_child * child.m_body_subtree_mass_com / child.m_subtree_mass; + mat33 tilde_r_child_com = tildeOperator(r_com); + mat33 tilde_r_body_com = tildeOperator(child.m_parent_pos_parent_body + r_com); + body.m_body_subtree_I_body += + child.m_subtree_mass * + (tilde_r_child_com * tilde_r_child_com - tilde_r_body_com * tilde_r_body_com); + } + } + } + + for (int i = m_body_list.size() - 1; i >= 0; i--) { + const RigidBody &body = m_body_list[i]; + + // determine DoF-range for body + const int q_index_min = body.m_q_index; + const int q_index_max = q_index_min + jointNumDoFs(body.m_joint_type) - 1; + // loop over the DoFs used by this body + // local joint jacobians (ok as is for 1-DoF joints) + vec3 Jac_JR = body.m_Jac_JR; + vec3 Jac_JT = body.m_Jac_JT; + for (int col = q_index_max; col >= q_index_min; col--) { + // set jacobians for 6-DoF joints + if (FLOATING == body.m_joint_type) { + setSixDoFJacobians(col - q_index_min, Jac_JR, Jac_JT); + } + + vec3 body_eom_rot = + body.m_body_subtree_I_body * Jac_JR + body.m_body_subtree_mass_com.cross(Jac_JT); + vec3 body_eom_trans = + body.m_subtree_mass * Jac_JT - body.m_body_subtree_mass_com.cross(Jac_JR); + setMatxxElem(col, col, Jac_JR.dot(body_eom_rot) + Jac_JT.dot(body_eom_trans), mass_matrix); + + // rest of the mass matrix column upwards + { + // 1. for multi-dof joints, rest of the dofs of this body + for (int row = col - 1; row >= q_index_min; row--) { + if (FLOATING != body.m_joint_type) { + error_message("??\n"); + return -1; + } + setSixDoFJacobians(row - q_index_min, Jac_JR, Jac_JT); + const double Mrc = Jac_JR.dot(body_eom_rot) + Jac_JT.dot(body_eom_trans); + setMatxxElem(col, row, Mrc, mass_matrix); + } + // 2. ancestor dofs + int child_idx = i; + int parent_idx = m_parent_index[i]; + while (parent_idx >= 0) { + const RigidBody &child_body = m_body_list[child_idx]; + const RigidBody &parent_body = m_body_list[parent_idx]; + + const mat33 parent_T_child = child_body.m_body_T_parent.transpose(); + body_eom_rot = parent_T_child * body_eom_rot; + body_eom_trans = parent_T_child * body_eom_trans; + body_eom_rot += child_body.m_parent_pos_parent_body.cross(body_eom_trans); + + const int parent_body_q_index_min = parent_body.m_q_index; + const int parent_body_q_index_max = + parent_body_q_index_min + jointNumDoFs(parent_body.m_joint_type) - 1; + vec3 Jac_JR = parent_body.m_Jac_JR; + vec3 Jac_JT = parent_body.m_Jac_JT; + for (int row = parent_body_q_index_max; row >= parent_body_q_index_min; row--) { + // set jacobians for 6-DoF joints + if (FLOATING == parent_body.m_joint_type) { + setSixDoFJacobians(row - parent_body_q_index_min, Jac_JR, Jac_JT); + } + const double Mrc = Jac_JR.dot(body_eom_rot) + Jac_JT.dot(body_eom_trans); + setMatxxElem(col, row, Mrc, mass_matrix); + } + + child_idx = parent_idx; + parent_idx = m_parent_index[child_idx]; + } + } + } + } + + if (set_lower_triangular_matrix) { + for (int col = 0; col < m_num_dofs; col++) { + for (int row = 0; row < col; row++) { + setMatxxElem(row, col, (*mass_matrix)(col, row), mass_matrix); + } + } + } + return 0; +} + +// utility macro +#define CHECK_IF_BODY_INDEX_IS_VALID(index) \ + do { \ + if (index < 0 || index >= m_num_bodies) { \ + error_message("invalid index %d (num_bodies= %d)\n", index, m_num_bodies); \ + return -1; \ + } \ + } while (0) + +int MultiBodyTree::MultiBodyImpl::getParentIndex(const int body_index, int *p) { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + *p = m_parent_index[body_index]; + return 0; +} + +int MultiBodyTree::MultiBodyImpl::getUserInt(const int body_index, int *user_int) const { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + *user_int = m_user_int[body_index]; + return 0; +} +int MultiBodyTree::MultiBodyImpl::getUserPtr(const int body_index, void **user_ptr) const { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + *user_ptr = m_user_ptr[body_index]; + return 0; +} + +int MultiBodyTree::MultiBodyImpl::setUserInt(const int body_index, const int user_int) { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + m_user_int[body_index] = user_int; + return 0; +} + +int MultiBodyTree::MultiBodyImpl::setUserPtr(const int body_index, void *const user_ptr) { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + m_user_ptr[body_index] = user_ptr; + return 0; +} + +int MultiBodyTree::MultiBodyImpl::getBodyOrigin(int body_index, vec3 *world_origin) const { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + const RigidBody &body = m_body_list[body_index]; + *world_origin = body.m_body_T_world.transpose() * body.m_body_pos; + return 0; +} + +int MultiBodyTree::MultiBodyImpl::getBodyCoM(int body_index, vec3 *world_com) const { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + const RigidBody &body = m_body_list[body_index]; + if (body.m_mass > 0) { + *world_com = body.m_body_T_world.transpose() * + (body.m_body_pos + body.m_body_mass_com / body.m_mass); + } else { + *world_com = body.m_body_T_world.transpose() * (body.m_body_pos); + } + return 0; +} + +int MultiBodyTree::MultiBodyImpl::getBodyTransform(int body_index, mat33 *world_T_body) const { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + const RigidBody &body = m_body_list[body_index]; + *world_T_body = body.m_body_T_world.transpose(); + return 0; +} +int MultiBodyTree::MultiBodyImpl::getBodyAngularVelocity(int body_index, vec3 *world_omega) const { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + const RigidBody &body = m_body_list[body_index]; + *world_omega = body.m_body_T_world.transpose() * body.m_body_ang_vel; + return 0; +} +int MultiBodyTree::MultiBodyImpl::getBodyLinearVelocity(int body_index, + vec3 *world_velocity) const { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + const RigidBody &body = m_body_list[body_index]; + *world_velocity = body.m_body_T_world.transpose() * body.m_body_vel; + return 0; +} + +int MultiBodyTree::MultiBodyImpl::getBodyLinearVelocityCoM(int body_index, + vec3 *world_velocity) const { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + const RigidBody &body = m_body_list[body_index]; + vec3 com; + if (body.m_mass > 0) { + com = body.m_body_mass_com / body.m_mass; + } else { + com(0) = 0; + com(1) = 0; + com(2) = 0; + } + + *world_velocity = + body.m_body_T_world.transpose() * (body.m_body_vel + body.m_body_ang_vel.cross(com)); + return 0; +} + +int MultiBodyTree::MultiBodyImpl::getBodyAngularAcceleration(int body_index, + vec3 *world_dot_omega) const { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + const RigidBody &body = m_body_list[body_index]; + *world_dot_omega = body.m_body_T_world.transpose() * body.m_body_ang_acc; + return 0; +} +int MultiBodyTree::MultiBodyImpl::getBodyLinearAcceleration(int body_index, + vec3 *world_acceleration) const { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + const RigidBody &body = m_body_list[body_index]; + *world_acceleration = body.m_body_T_world.transpose() * body.m_body_acc; + return 0; +} + +int MultiBodyTree::MultiBodyImpl::getJointType(const int body_index, JointType *joint_type) const { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + *joint_type = m_body_list[body_index].m_joint_type; + return 0; +} + +int MultiBodyTree::MultiBodyImpl::getJointTypeStr(const int body_index, + const char **joint_type) const { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + *joint_type = jointTypeToString(m_body_list[body_index].m_joint_type); + return 0; +} + +int MultiBodyTree::MultiBodyImpl::getParentRParentBodyRef(const int body_index, vec3* r) const{ + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + *r=m_body_list[body_index].m_parent_pos_parent_body_ref; + return 0; +} + +int MultiBodyTree::MultiBodyImpl::getBodyTParentRef(const int body_index, mat33* T) const{ + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + *T=m_body_list[body_index].m_body_T_parent_ref; + return 0; +} + +int MultiBodyTree::MultiBodyImpl::getBodyAxisOfMotion(const int body_index, vec3* axis) const{ + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + if(m_body_list[body_index].m_joint_type == REVOLUTE) { + *axis = m_body_list[body_index].m_Jac_JR; + return 0; + } + if(m_body_list[body_index].m_joint_type == PRISMATIC) { + *axis = m_body_list[body_index].m_Jac_JT; + return 0; + } + setZero(*axis); + return 0; +} + +int MultiBodyTree::MultiBodyImpl::getDoFOffset(const int body_index, int *q_index) const { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + *q_index = m_body_list[body_index].m_q_index; + return 0; +} + +int MultiBodyTree::MultiBodyImpl::setBodyMass(const int body_index, const idScalar mass) { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + m_body_list[body_index].m_mass = mass; + return 0; +} + +int MultiBodyTree::MultiBodyImpl::setBodyFirstMassMoment(const int body_index, + const vec3& first_mass_moment) { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + m_body_list[body_index].m_body_mass_com = first_mass_moment; + return 0; +} +int MultiBodyTree::MultiBodyImpl::setBodySecondMassMoment(const int body_index, + const mat33& second_mass_moment) { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + m_body_list[body_index].m_body_I_body = second_mass_moment; + return 0; +} +int MultiBodyTree::MultiBodyImpl::getBodyMass(const int body_index, idScalar *mass) const { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + *mass = m_body_list[body_index].m_mass; + return 0; +} +int MultiBodyTree::MultiBodyImpl::getBodyFirstMassMoment(const int body_index, + vec3 *first_mass_moment) const { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + *first_mass_moment = m_body_list[body_index].m_body_mass_com; + return 0; +} +int MultiBodyTree::MultiBodyImpl::getBodySecondMassMoment(const int body_index, + mat33 *second_mass_moment) const { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + *second_mass_moment = m_body_list[body_index].m_body_I_body; + return 0; +} + +void MultiBodyTree::MultiBodyImpl::clearAllUserForcesAndMoments() { + for (int index = 0; index < m_num_bodies; index++) { + RigidBody &body = m_body_list[index]; + setZero(body.m_body_force_user); + setZero(body.m_body_moment_user); + } +} + +int MultiBodyTree::MultiBodyImpl::addUserForce(const int body_index, const vec3 &body_force) { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + m_body_list[body_index].m_body_force_user += body_force; + return 0; +} + +int MultiBodyTree::MultiBodyImpl::addUserMoment(const int body_index, const vec3 &body_moment) { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + m_body_list[body_index].m_body_moment_user += body_moment; + return 0; +} + +#if (defined BT_ID_HAVE_MAT3X) && (defined BT_ID_WITH_JACOBIANS) +int MultiBodyTree::MultiBodyImpl::getBodyDotJacobianTransU(const int body_index, vec3* world_dot_jac_trans_u) const { + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + const RigidBody &body = m_body_list[body_index]; + *world_dot_jac_trans_u = body.m_body_T_world.transpose() * body.m_body_dot_Jac_T_u; + return 0; +} + +int MultiBodyTree::MultiBodyImpl::getBodyDotJacobianRotU(const int body_index, vec3* world_dot_jac_rot_u) const{ + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + const RigidBody &body = m_body_list[body_index]; + *world_dot_jac_rot_u = body.m_body_T_world.transpose() * body.m_body_dot_Jac_R_u; + return 0; +} + +int MultiBodyTree::MultiBodyImpl::getBodyJacobianTrans(const int body_index, mat3x* world_jac_trans) const{ + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + const RigidBody &body = m_body_list[body_index]; + mul(body.m_body_T_world.transpose(), body.m_body_Jac_T, world_jac_trans); + return 0; +} + +int MultiBodyTree::MultiBodyImpl::getBodyJacobianRot(const int body_index, mat3x* world_jac_rot) const{ + CHECK_IF_BODY_INDEX_IS_VALID(body_index); + const RigidBody &body = m_body_list[body_index]; + mul(body.m_body_T_world.transpose(), body.m_body_Jac_R,world_jac_rot); + return 0; +} + +#endif +} diff --git a/extern/bullet/src/BulletInverseDynamics/details/MultiBodyTreeImpl.hpp b/extern/bullet/src/BulletInverseDynamics/details/MultiBodyTreeImpl.hpp new file mode 100644 index 000000000000..3efe9d049269 --- /dev/null +++ b/extern/bullet/src/BulletInverseDynamics/details/MultiBodyTreeImpl.hpp @@ -0,0 +1,283 @@ +// The structs and classes defined here provide a basic inverse fynamics implementation used +// by MultiBodyTree +// User interaction should be through MultiBodyTree + +#ifndef MULTI_BODY_REFERENCE_IMPL_HPP_ +#define MULTI_BODY_REFERENCE_IMPL_HPP_ + +#include "../IDConfig.hpp" +#include "../MultiBodyTree.hpp" + +namespace btInverseDynamics { + +/// Structure for for rigid body mass properties, connectivity and kinematic state +/// all vectors and matrices are in body-fixed frame, if not indicated otherwise. +/// The body-fixed frame is located in the joint connecting the body to its parent. +struct RigidBody { + ID_DECLARE_ALIGNED_ALLOCATOR(); + // 1 Inertial properties + /// Mass + idScalar m_mass; + /// Mass times center of gravity in body-fixed frame + vec3 m_body_mass_com; + /// Moment of inertia w.r.t. body-fixed frame + mat33 m_body_I_body; + + // 2 dynamic properties + /// Left-hand side of the body equation of motion, translational part + vec3 m_eom_lhs_translational; + /// Left-hand side of the body equation of motion, rotational part + vec3 m_eom_lhs_rotational; + /// Force acting at the joint when the body is cut from its parent; + /// includes impressed joint force in J_JT direction, + /// as well as constraint force, + /// in body-fixed frame + vec3 m_force_at_joint; + /// Moment acting at the joint when the body is cut from its parent; + /// includes impressed joint moment in J_JR direction, and constraint moment + /// in body-fixed frame + vec3 m_moment_at_joint; + /// external (user provided) force acting at the body-fixed frame's origin, written in that + /// frame + vec3 m_body_force_user; + /// external (user provided) moment acting at the body-fixed frame's origin, written in that + /// frame + vec3 m_body_moment_user; + // 3 absolute kinematic properties + /// Position of body-fixed frame relative to world frame + /// this is currently only for debugging purposes + vec3 m_body_pos; + /// Absolute velocity of body-fixed frame + vec3 m_body_vel; + /// Absolute acceleration of body-fixed frame + /// NOTE: if gravitational acceleration is not zero, this is the accelation PLUS gravitational + /// acceleration! + vec3 m_body_acc; + /// Absolute angular velocity + vec3 m_body_ang_vel; + /// Absolute angular acceleration + /// NOTE: if gravitational acceleration is not zero, this is the accelation PLUS gravitational + /// acceleration! + vec3 m_body_ang_acc; + + // 4 relative kinematic properties. + // these are in the parent body frame + /// Transform from world to body-fixed frame; + /// this is currently only for debugging purposes + mat33 m_body_T_world; + /// Transform from parent to body-fixed frame + mat33 m_body_T_parent; + /// Vector from parent to child frame in parent frame + vec3 m_parent_pos_parent_body; + /// Relative angular velocity + vec3 m_body_ang_vel_rel; + /// Relative linear velocity + vec3 m_parent_vel_rel; + /// Relative angular acceleration + vec3 m_body_ang_acc_rel; + /// Relative linear acceleration + vec3 m_parent_acc_rel; + + // 5 Data describing the joint type and geometry + /// Type of joint + JointType m_joint_type; + /// Position of joint frame (body-fixed frame at q=0) relative to the parent frame + /// Components are in body-fixed frame of the parent + vec3 m_parent_pos_parent_body_ref; + /// Orientation of joint frame (body-fixed frame at q=0) relative to the parent frame + mat33 m_body_T_parent_ref; + /// Joint rotational Jacobian, ie, the partial derivative of the body-fixed frames absolute + /// angular velocity w.r.t. the generalized velocity of this body's relative degree of freedom. + /// For revolute joints this is the joint axis, for prismatic joints it is a null matrix. + /// (NOTE: dimensions will have to be dynamic for additional joint types!) + vec3 m_Jac_JR; + /// Joint translational Jacobian, ie, the partial derivative of the body-fixed frames absolute + /// linear velocity w.r.t. the generalized velocity of this body's relative degree of freedom. + /// For prismatic joints this is the joint axis, for revolute joints it is a null matrix. + /// (NOTE: dimensions might have to be dynamic for additional joint types!) + vec3 m_Jac_JT; + /// m_Jac_JT in the parent frame, it, m_body_T_parent_ref.transpose()*m_Jac_JT + vec3 m_parent_Jac_JT; + /// Start of index range for the position degree(s) of freedom describing this body's motion + /// relative to + /// its parent. The indices are wrt the multibody system's q-vector of generalized coordinates. + int m_q_index; + + // 6 Scratch data for mass matrix computation using "composite rigid body algorithm" + /// mass of the subtree rooted in this body + idScalar m_subtree_mass; + /// center of mass * mass for subtree rooted in this body, in body-fixed frame + vec3 m_body_subtree_mass_com; + /// moment of inertia of subtree rooted in this body, w.r.t. body origin, in body-fixed frame + mat33 m_body_subtree_I_body; + +#if (defined BT_ID_HAVE_MAT3X) && (defined BT_ID_WITH_JACOBIANS) + /// translational jacobian in body-fixed frame d(m_body_vel)/du + mat3x m_body_Jac_T; + /// rotationsl jacobian in body-fixed frame d(m_body_ang_vel)/du + mat3x m_body_Jac_R; + /// components of linear acceleration depending on u + /// (same as is d(m_Jac_T)/dt*u) + vec3 m_body_dot_Jac_T_u; + /// components of angular acceleration depending on u + /// (same as is d(m_Jac_T)/dt*u) + vec3 m_body_dot_Jac_R_u; +#endif +}; + +/// The MBS implements a tree structured multibody system +class MultiBodyTree::MultiBodyImpl { + friend class MultiBodyTree; + +public: + ID_DECLARE_ALIGNED_ALLOCATOR(); + + enum KinUpdateType { + POSITION_ONLY, + POSITION_VELOCITY, + POSITION_VELOCITY_ACCELERATION + }; + + /// constructor + /// @param num_bodies the number of bodies in the system + /// @param num_dofs number of degrees of freedom in the system + MultiBodyImpl(int num_bodies_, int num_dofs_); + + /// \copydoc MultiBodyTree::calculateInverseDynamics + int calculateInverseDynamics(const vecx& q, const vecx& u, const vecx& dot_u, + vecx* joint_forces); + ///\copydoc MultiBodyTree::calculateMassMatrix + int calculateMassMatrix(const vecx& q, const bool update_kinematics, + const bool initialize_matrix, const bool set_lower_triangular_matrix, + matxx* mass_matrix); + /// calculate kinematics (vector quantities) + /// Depending on type, update positions only, positions & velocities, or positions, velocities + /// and accelerations. + int calculateKinematics(const vecx& q, const vecx& u, const vecx& dot_u, const KinUpdateType type); +#if (defined BT_ID_HAVE_MAT3X) && (defined BT_ID_WITH_JACOBIANS) + /// calculate jacobians and (if type == POSITION_VELOCITY), also velocity-dependent accelration terms. + int calculateJacobians(const vecx& q, const vecx& u, const KinUpdateType type); + /// \copydoc MultiBodyTree::getBodyDotJacobianTransU + int getBodyDotJacobianTransU(const int body_index, vec3* world_dot_jac_trans_u) const ; + /// \copydoc MultiBodyTree::getBodyDotJacobianRotU + int getBodyDotJacobianRotU(const int body_index, vec3* world_dot_jac_rot_u) const; + /// \copydoc MultiBodyTree::getBodyJacobianTrans + int getBodyJacobianTrans(const int body_index, mat3x* world_jac_trans) const ; + /// \copydoc MultiBodyTree::getBodyJacobianRot + int getBodyJacobianRot(const int body_index, mat3x* world_jac_rot) const; + /// Add relative Jacobian component from motion relative to parent body + /// @param body the body to add the Jacobian component for + void addRelativeJacobianComponent(RigidBody&body); +#endif + /// generate additional index sets from the parent_index array + /// @return -1 on error, 0 on success + int generateIndexSets(); + /// set gravity acceleration in world frame + /// @param gravity gravity vector in the world frame + /// @return 0 on success, -1 on error + int setGravityInWorldFrame(const vec3& gravity); + /// pretty print tree + void printTree(); + /// print tree data + void printTreeData(); + /// initialize fixed data + void calculateStaticData(); + /// \copydoc MultiBodyTree::getBodyFrame + int getBodyFrame(const int index, vec3* world_origin, mat33* body_T_world) const; + /// \copydoc MultiBodyTree::getParentIndex + int getParentIndex(const int body_index, int* m_parent_index); + /// \copydoc MultiBodyTree::getJointType + int getJointType(const int body_index, JointType* joint_type) const; + /// \copydoc MultiBodyTree::getJointTypeStr + int getJointTypeStr(const int body_index, const char** joint_type) const; + /// \copydoc MultiBodyTree::getParentRParentBodyRef + int getParentRParentBodyRef(const int body_index, vec3* r) const; + /// \copydoc MultiBodyTree::getBodyTParentRef + int getBodyTParentRef(const int body_index, mat33* T) const; + /// \copydoc MultiBodyTree::getBodyAxisOfMotion + int getBodyAxisOfMotion(const int body_index, vec3* axis) const; + /// \copydoc MultiBodyTree:getDoFOffset + int getDoFOffset(const int body_index, int* q_index) const; + /// \copydoc MultiBodyTree::getBodyOrigin + int getBodyOrigin(const int body_index, vec3* world_origin) const; + /// \copydoc MultiBodyTree::getBodyCoM + int getBodyCoM(const int body_index, vec3* world_com) const; + /// \copydoc MultiBodyTree::getBodyTransform + int getBodyTransform(const int body_index, mat33* world_T_body) const; + /// \copydoc MultiBodyTree::getBodyAngularVelocity + int getBodyAngularVelocity(const int body_index, vec3* world_omega) const; + /// \copydoc MultiBodyTree::getBodyLinearVelocity + int getBodyLinearVelocity(const int body_index, vec3* world_velocity) const; + /// \copydoc MultiBodyTree::getBodyLinearVelocityCoM + int getBodyLinearVelocityCoM(const int body_index, vec3* world_velocity) const; + /// \copydoc MultiBodyTree::getBodyAngularAcceleration + int getBodyAngularAcceleration(const int body_index, vec3* world_dot_omega) const; + /// \copydoc MultiBodyTree::getBodyLinearAcceleration + int getBodyLinearAcceleration(const int body_index, vec3* world_acceleration) const; + /// \copydoc MultiBodyTree::getUserInt + int getUserInt(const int body_index, int* user_int) const; + /// \copydoc MultiBodyTree::getUserPtr + int getUserPtr(const int body_index, void** user_ptr) const; + /// \copydoc MultiBodyTree::setUserInt + int setUserInt(const int body_index, const int user_int); + /// \copydoc MultiBodyTree::setUserPtr + int setUserPtr(const int body_index, void* const user_ptr); + ///\copydoc MultiBodytTree::setBodyMass + int setBodyMass(const int body_index, const idScalar mass); + ///\copydoc MultiBodytTree::setBodyFirstMassMoment + int setBodyFirstMassMoment(const int body_index, const vec3& first_mass_moment); + ///\copydoc MultiBodytTree::setBodySecondMassMoment + int setBodySecondMassMoment(const int body_index, const mat33& second_mass_moment); + ///\copydoc MultiBodytTree::getBodyMass + int getBodyMass(const int body_index, idScalar* mass) const; + ///\copydoc MultiBodytTree::getBodyFirstMassMoment + int getBodyFirstMassMoment(const int body_index, vec3* first_mass_moment) const; + ///\copydoc MultiBodytTree::getBodySecondMassMoment + int getBodySecondMassMoment(const int body_index, mat33* second_mass_moment) const; + /// \copydoc MultiBodyTree::clearAllUserForcesAndMoments + void clearAllUserForcesAndMoments(); + /// \copydoc MultiBodyTree::addUserForce + int addUserForce(const int body_index, const vec3& body_force); + /// \copydoc MultiBodyTree::addUserMoment + int addUserMoment(const int body_index, const vec3& body_moment); + +private: + // debug function. print tree structure to stdout + void printTree(int index, int indentation); + // get string representation of JointType (for debugging) + const char* jointTypeToString(const JointType& type) const; + // get number of degrees of freedom from joint type + int bodyNumDoFs(const JointType& type) const; + // number of bodies in the system + int m_num_bodies; + // number of degrees of freedom + int m_num_dofs; + // Gravitational acceleration (in world frame) + vec3 m_world_gravity; + // vector of bodies in the system + // body 0 is used as an environment body and is allways fixed. + // The bodies are ordered such that a parent body always has an index + // smaller than its child. + idArray::type m_body_list; + // Parent_index[i] is the index for i's parent body in body_list. + // This fully describes the tree. + idArray::type m_parent_index; + // child_indices[i] contains a vector of indices of + // all children of the i-th body + idArray::type>::type m_child_indices; + // Indices of rotary joints + idArray::type m_body_revolute_list; + // Indices of prismatic joints + idArray::type m_body_prismatic_list; + // Indices of floating joints + idArray::type m_body_floating_list; + // a user-provided integer + idArray::type m_user_int; + // a user-provided pointer + idArray::type m_user_ptr; +#if (defined BT_ID_HAVE_MAT3X) && (defined BT_ID_WITH_JACOBIANS) + mat3x m_m3x; +#endif +}; +} +#endif diff --git a/extern/bullet/src/BulletInverseDynamics/details/MultiBodyTreeInitCache.cpp b/extern/bullet/src/BulletInverseDynamics/details/MultiBodyTreeInitCache.cpp new file mode 100644 index 000000000000..47b4ab38908e --- /dev/null +++ b/extern/bullet/src/BulletInverseDynamics/details/MultiBodyTreeInitCache.cpp @@ -0,0 +1,113 @@ +#include "MultiBodyTreeInitCache.hpp" + +namespace btInverseDynamics { + +MultiBodyTree::InitCache::InitCache() { + m_inertias.resize(0); + m_joints.resize(0); + m_num_dofs = 0; + m_root_index=-1; +} + +int MultiBodyTree::InitCache::addBody(const int body_index, const int parent_index, + const JointType joint_type, + const vec3& parent_r_parent_body_ref, + const mat33& body_T_parent_ref, + const vec3& body_axis_of_motion, const idScalar mass, + const vec3& body_r_body_com, const mat33& body_I_body, + const int user_int, void* user_ptr) { + switch (joint_type) { + case REVOLUTE: + case PRISMATIC: + m_num_dofs += 1; + break; + case FIXED: + // does not add a degree of freedom + // m_num_dofs+=0; + break; + case FLOATING: + m_num_dofs += 6; + break; + default: + error_message("unknown joint type %d\n", joint_type); + return -1; + } + + if(-1 == parent_index) { + if(m_root_index>=0) { + error_message("trying to add body %d as root, but already added %d as root body\n", + body_index, m_root_index); + return -1; + } + m_root_index=body_index; + } + + JointData joint; + joint.m_child = body_index; + joint.m_parent = parent_index; + joint.m_type = joint_type; + joint.m_parent_pos_parent_child_ref = parent_r_parent_body_ref; + joint.m_child_T_parent_ref = body_T_parent_ref; + joint.m_child_axis_of_motion = body_axis_of_motion; + + InertiaData body; + body.m_mass = mass; + body.m_body_pos_body_com = body_r_body_com; + body.m_body_I_body = body_I_body; + + m_inertias.push_back(body); + m_joints.push_back(joint); + m_user_int.push_back(user_int); + m_user_ptr.push_back(user_ptr); + return 0; +} +int MultiBodyTree::InitCache::getInertiaData(const int index, InertiaData* inertia) const { + if (index < 0 || index > static_cast(m_inertias.size())) { + error_message("index out of range\n"); + return -1; + } + + *inertia = m_inertias[index]; + return 0; +} + +int MultiBodyTree::InitCache::getUserInt(const int index, int* user_int) const { + if (index < 0 || index > static_cast(m_user_int.size())) { + error_message("index out of range\n"); + return -1; + } + *user_int = m_user_int[index]; + return 0; +} + +int MultiBodyTree::InitCache::getUserPtr(const int index, void** user_ptr) const { + if (index < 0 || index > static_cast(m_user_ptr.size())) { + error_message("index out of range\n"); + return -1; + } + *user_ptr = m_user_ptr[index]; + return 0; +} + +int MultiBodyTree::InitCache::getJointData(const int index, JointData* joint) const { + if (index < 0 || index > static_cast(m_joints.size())) { + error_message("index out of range\n"); + return -1; + } + *joint = m_joints[index]; + return 0; +} + +int MultiBodyTree::InitCache::buildIndexSets() { + // NOTE: This function assumes that proper indices were provided + // User2InternalIndex from utils can be used to facilitate this. + + m_parent_index.resize(numBodies()); + for (idArrayIdx j = 0; j < m_joints.size(); j++) { + const JointData& joint = m_joints[j]; + m_parent_index[joint.m_child] = joint.m_parent; + } + + return 0; +} +} diff --git a/extern/bullet/src/BulletInverseDynamics/details/MultiBodyTreeInitCache.hpp b/extern/bullet/src/BulletInverseDynamics/details/MultiBodyTreeInitCache.hpp new file mode 100644 index 000000000000..0d2aa4a07184 --- /dev/null +++ b/extern/bullet/src/BulletInverseDynamics/details/MultiBodyTreeInitCache.hpp @@ -0,0 +1,109 @@ +#ifndef MULTIBODYTREEINITCACHE_HPP_ +#define MULTIBODYTREEINITCACHE_HPP_ + +#include "../IDConfig.hpp" +#include "../IDMath.hpp" +#include "../MultiBodyTree.hpp" + +namespace btInverseDynamics { +/// Mass properties of a rigid body +struct InertiaData { + ID_DECLARE_ALIGNED_ALLOCATOR(); + + /// mass + idScalar m_mass; + /// vector from body-fixed frame to center of mass, + /// in body-fixed frame, multiplied by the mass + vec3 m_body_pos_body_com; + /// moment of inertia w.r.t. the origin of the body-fixed + /// frame, represented in that frame + mat33 m_body_I_body; +}; + +/// Joint properties +struct JointData { + ID_DECLARE_ALIGNED_ALLOCATOR(); + + /// type of joint + JointType m_type; + /// index of parent body + int m_parent; + /// index of child body + int m_child; + /// vector from parent's body-fixed frame to child's body-fixed + /// frame for q=0, written in the parent's body fixed frame + vec3 m_parent_pos_parent_child_ref; + /// Transform matrix converting vectors written in the parent's frame + /// into vectors written in the child's frame for q=0 + /// ie, child_vector = child_T_parent_ref * parent_vector; + mat33 m_child_T_parent_ref; + /// Axis of motion for 1 degree-of-freedom joints, + /// written in the child's frame + /// For revolute joints, the q-value is positive for a positive + /// rotation about this axis. + /// For prismatic joints, the q-value is positive for a positive + /// translation is this direction. + vec3 m_child_axis_of_motion; +}; + +/// Data structure to store data passed by the user. +/// This is used in MultiBodyTree::finalize to build internal data structures. +class MultiBodyTree::InitCache { +public: + ID_DECLARE_ALIGNED_ALLOCATOR(); + /// constructor + InitCache(); + ///\copydoc MultiBodyTree::addBody + int addBody(const int body_index, const int parent_index, const JointType joint_type, + const vec3 &parent_r_parent_body_ref, const mat33 &body_T_parent_ref, + const vec3 &body_axis_of_motion, idScalar mass, const vec3 &body_r_body_com, + const mat33 &body_I_body, const int user_int, void *user_ptr); + /// build index arrays + /// @return 0 on success, -1 on failure + int buildIndexSets(); + /// @return number of degrees of freedom + int numDoFs() const { return m_num_dofs; } + /// @return number of bodies + int numBodies() const { return m_inertias.size(); } + /// get inertia data for index + /// @param index of the body + /// @param inertia pointer for return data + /// @return 0 on success, -1 on failure + int getInertiaData(const int index, InertiaData *inertia) const; + /// get joint data for index + /// @param index of the body + /// @param joint pointer for return data + /// @return 0 on success, -1 on failure + int getJointData(const int index, JointData *joint) const; + /// get parent index array (paren_index[i] is the index of the parent of i) + /// @param parent_index pointer for return data + void getParentIndexArray(idArray::type *parent_index) { *parent_index = m_parent_index; } + /// get user integer + /// @param index body index + /// @param user_int user integer + /// @return 0 on success, -1 on failure + int getUserInt(const int index, int *user_int) const; + /// get user pointer + /// @param index body index + /// @param user_int user pointer + /// @return 0 on success, -1 on failure + int getUserPtr(const int index, void **user_ptr) const; + +private: + // vector of bodies + idArray::type m_inertias; + // vector of joints + idArray::type m_joints; + // number of mechanical degrees of freedom + int m_num_dofs; + // parent index array + idArray::type m_parent_index; + // user integers + idArray::type m_user_int; + // user pointers + idArray::type m_user_ptr; + // index of root body (or -1 if not set) + int m_root_index; +}; +} +#endif // MULTIBODYTREEINITCACHE_HPP_ diff --git a/extern/bullet/src/BulletInverseDynamics/premake4.lua b/extern/bullet/src/BulletInverseDynamics/premake4.lua new file mode 100644 index 000000000000..774e037b3f44 --- /dev/null +++ b/extern/bullet/src/BulletInverseDynamics/premake4.lua @@ -0,0 +1,12 @@ + project "BulletInverseDynamics" + + kind "StaticLib" + includedirs { + "..", + } + files { + "IDMath.cpp", + "MultiBodyTree.cpp", + "details/MultiBodyTreeInitCache.cpp", + "details/MultiBodyTreeImpl.cpp", + } diff --git a/extern/bullet/src/BulletSoftBody/CMakeLists.txt b/extern/bullet/src/BulletSoftBody/CMakeLists.txt new file mode 100644 index 000000000000..d43df1c67b31 --- /dev/null +++ b/extern/bullet/src/BulletSoftBody/CMakeLists.txt @@ -0,0 +1,69 @@ + +INCLUDE_DIRECTORIES( +${BULLET_PHYSICS_SOURCE_DIR}/src + +) + +#SUBDIRS( Solvers ) + +SET(BulletSoftBody_SRCS + btSoftBody.cpp + btSoftBodyConcaveCollisionAlgorithm.cpp + btSoftBodyHelpers.cpp + btSoftBodyRigidBodyCollisionConfiguration.cpp + btSoftRigidCollisionAlgorithm.cpp + btSoftRigidDynamicsWorld.cpp + btSoftMultiBodyDynamicsWorld.cpp + btSoftSoftCollisionAlgorithm.cpp + btDefaultSoftBodySolver.cpp + +) + +SET(BulletSoftBody_HDRS + btSoftBody.h + btSoftBodyData.h + btSoftBodyConcaveCollisionAlgorithm.h + btSoftBodyHelpers.h + btSoftBodyRigidBodyCollisionConfiguration.h + btSoftRigidCollisionAlgorithm.h + btSoftRigidDynamicsWorld.h + btSoftMultiBodyDynamicsWorld.h + btSoftSoftCollisionAlgorithm.h + btSparseSDF.h + + btSoftBodySolvers.h + btDefaultSoftBodySolver.h + + btSoftBodySolverVertexBuffer.h +) + + + +ADD_LIBRARY(BulletSoftBody ${BulletSoftBody_SRCS} ${BulletSoftBody_HDRS}) +SET_TARGET_PROPERTIES(BulletSoftBody PROPERTIES VERSION ${BULLET_VERSION}) +SET_TARGET_PROPERTIES(BulletSoftBody PROPERTIES SOVERSION ${BULLET_VERSION}) +IF (BUILD_SHARED_LIBS) + TARGET_LINK_LIBRARIES(BulletSoftBody BulletDynamics) +ENDIF (BUILD_SHARED_LIBS) + +IF (INSTALL_LIBS) + IF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) + IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS BulletSoftBody DESTINATION .) + ELSE (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS BulletSoftBody RUNTIME DESTINATION bin + LIBRARY DESTINATION lib${LIB_SUFFIX} + ARCHIVE DESTINATION lib${LIB_SUFFIX}) + INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.h" PATTERN +".svn" EXCLUDE PATTERN "CMakeFiles" EXCLUDE) + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + SET_TARGET_PROPERTIES(BulletSoftBody PROPERTIES FRAMEWORK true) + SET_TARGET_PROPERTIES(BulletSoftBody PROPERTIES PUBLIC_HEADER "${BulletSoftBody_HDRS}") + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) +ENDIF (INSTALL_LIBS) diff --git a/extern/bullet2/src/BulletSoftBody/btDefaultSoftBodySolver.cpp b/extern/bullet/src/BulletSoftBody/btDefaultSoftBodySolver.cpp similarity index 94% rename from extern/bullet2/src/BulletSoftBody/btDefaultSoftBodySolver.cpp rename to extern/bullet/src/BulletSoftBody/btDefaultSoftBodySolver.cpp index e90d24e6edfb..9c2040307437 100644 --- a/extern/bullet2/src/BulletSoftBody/btDefaultSoftBodySolver.cpp +++ b/extern/bullet/src/BulletSoftBody/btDefaultSoftBodySolver.cpp @@ -100,9 +100,9 @@ void btDefaultSoftBodySolver::copySoftBodyToVertexBuffer( const btSoftBody *cons for( int vertexIndex = 0; vertexIndex < numVertices; ++vertexIndex ) { btVector3 position = clothVertices[vertexIndex].m_x; - *(vertexPointer + 0) = position.getX(); - *(vertexPointer + 1) = position.getY(); - *(vertexPointer + 2) = position.getZ(); + *(vertexPointer + 0) = (float)position.getX(); + *(vertexPointer + 1) = (float)position.getY(); + *(vertexPointer + 2) = (float)position.getZ(); vertexPointer += vertexStride; } } @@ -115,9 +115,9 @@ void btDefaultSoftBodySolver::copySoftBodyToVertexBuffer( const btSoftBody *cons for( int vertexIndex = 0; vertexIndex < numVertices; ++vertexIndex ) { btVector3 normal = clothVertices[vertexIndex].m_n; - *(normalPointer + 0) = normal.getX(); - *(normalPointer + 1) = normal.getY(); - *(normalPointer + 2) = normal.getZ(); + *(normalPointer + 0) = (float)normal.getX(); + *(normalPointer + 1) = (float)normal.getY(); + *(normalPointer + 2) = (float)normal.getZ(); normalPointer += normalStride; } } diff --git a/extern/bullet2/src/BulletSoftBody/btDefaultSoftBodySolver.h b/extern/bullet/src/BulletSoftBody/btDefaultSoftBodySolver.h similarity index 100% rename from extern/bullet2/src/BulletSoftBody/btDefaultSoftBodySolver.h rename to extern/bullet/src/BulletSoftBody/btDefaultSoftBodySolver.h diff --git a/extern/bullet2/src/BulletSoftBody/btSoftBody.cpp b/extern/bullet/src/BulletSoftBody/btSoftBody.cpp similarity index 96% rename from extern/bullet2/src/BulletSoftBody/btSoftBody.cpp rename to extern/bullet/src/BulletSoftBody/btSoftBody.cpp index 51f4b33d034d..48efb0d8d48b 100644 --- a/extern/bullet2/src/BulletSoftBody/btSoftBody.cpp +++ b/extern/bullet/src/BulletSoftBody/btSoftBody.cpp @@ -18,6 +18,8 @@ subject to the following restrictions: #include "BulletSoftBody/btSoftBodySolvers.h" #include "btSoftBodyData.h" #include "LinearMath/btSerializer.h" +#include "BulletDynamics/Featherstone/btMultiBodyLinkCollider.h" +#include "BulletDynamics/Featherstone/btMultiBodyConstraint.h" // @@ -522,7 +524,7 @@ void btSoftBody::addAeroForceToNode(const btVector3& windVelocity,int nodeInde } else if (m_cfg.aeromodel == btSoftBody::eAeroModel::V_Point || m_cfg.aeromodel == btSoftBody::eAeroModel::V_OneSided || m_cfg.aeromodel == btSoftBody::eAeroModel::V_TwoSided) { - if (btSoftBody::eAeroModel::V_TwoSided) + if (m_cfg.aeromodel == btSoftBody::eAeroModel::V_TwoSided) nrm *= (btScalar)( (btDot(nrm,rel_v) < 0) ? -1 : +1); const btScalar dvn = btDot(rel_v,nrm); @@ -617,7 +619,7 @@ void btSoftBody::addAeroForceToFace(const btVector3& windVelocity,int faceInde } else if (m_cfg.aeromodel == btSoftBody::eAeroModel::F_OneSided || m_cfg.aeromodel == btSoftBody::eAeroModel::F_TwoSided) { - if (btSoftBody::eAeroModel::F_TwoSided) + if (m_cfg.aeromodel == btSoftBody::eAeroModel::F_TwoSided) nrm *= (btScalar)( (btDot(nrm,rel_v) < 0) ? -1 : +1); const btScalar dvn=btDot(rel_v,nrm); @@ -3001,6 +3003,7 @@ void btSoftBody::applyForces() // void btSoftBody::PSolve_Anchors(btSoftBody* psb,btScalar kst,btScalar ti) { + BT_PROFILE("PSolve_Anchors"); const btScalar kAHR=psb->m_cfg.kAHR*kst; const btScalar dt=psb->m_sst.sdt; for(int i=0,ni=psb->m_anchors.size();im_sst.sdt; const btScalar mrg = psb->getCollisionShape()->getMargin(); + btMultiBodyJacobianData jacobianData; for(int i=0,ni=psb->m_rcontacts.size();im_rcontacts[i]; const sCti& cti = c.m_cti; if (cti.m_colObj->hasContactResponse()) { - btRigidBody* tmpRigid = (btRigidBody*)btRigidBody::upcast(cti.m_colObj); - const btVector3 va = tmpRigid ? tmpRigid->getVelocityInLocalPoint(c.m_c1)*dt : btVector3(0,0,0); - const btVector3 vb = c.m_node->m_x-c.m_node->m_q; + btVector3 va(0,0,0); + btRigidBody* rigidCol=0; + btMultiBodyLinkCollider* multibodyLinkCol=0; + btScalar* deltaV; + + if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY) + { + rigidCol = (btRigidBody*)btRigidBody::upcast(cti.m_colObj); + va = rigidCol ? rigidCol->getVelocityInLocalPoint(c.m_c1)*dt : btVector3(0,0,0); + } + else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK) + { + multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(cti.m_colObj); + if (multibodyLinkCol) + { + const int ndof = multibodyLinkCol->m_multiBody->getNumDofs() + 6; + jacobianData.m_jacobians.resize(ndof); + jacobianData.m_deltaVelocitiesUnitImpulse.resize(ndof); + btScalar* jac=&jacobianData.m_jacobians[0]; + + multibodyLinkCol->m_multiBody->fillContactJacobianMultiDof(multibodyLinkCol->m_link, c.m_node->m_x, cti.m_normal, jac, jacobianData.scratch_r, jacobianData.scratch_v, jacobianData.scratch_m); + deltaV = &jacobianData.m_deltaVelocitiesUnitImpulse[0]; + multibodyLinkCol->m_multiBody->calcAccelerationDeltasMultiDof(&jacobianData.m_jacobians[0],deltaV,jacobianData.scratch_r, jacobianData.scratch_v); + + btScalar vel = 0.0; + for (int j = 0; j < ndof ; ++j) { + vel += multibodyLinkCol->m_multiBody->getVelocityVector()[j] * jac[j]; + } + va = cti.m_normal*vel*dt; + } + } + + const btVector3 vb = c.m_node->m_x-c.m_node->m_q; const btVector3 vr = vb-va; const btScalar dn = btDot(vr, cti.m_normal); if(dn<=SIMD_EPSILON) @@ -3041,8 +3077,20 @@ void btSoftBody::PSolve_RContacts(btSoftBody* psb, btScalar kst, btScalar ti) // c0 is the impulse matrix, c3 is 1 - the friction coefficient or 0, c4 is the contact hardness coefficient const btVector3 impulse = c.m_c0 * ( (vr - (fv * c.m_c3) + (cti.m_normal * (dp * c.m_c4))) * kst ); c.m_node->m_x -= impulse * c.m_c2; - if (tmpRigid) - tmpRigid->applyImpulse(impulse,c.m_c1); + + if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY) + { + if (rigidCol) + rigidCol->applyImpulse(impulse,c.m_c1); + } + else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK) + { + if (multibodyLinkCol) + { + double multiplier = 0.5; + multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof(deltaV,-impulse.length()*multiplier); + } + } } } } @@ -3051,6 +3099,8 @@ void btSoftBody::PSolve_RContacts(btSoftBody* psb, btScalar kst, btScalar ti) // void btSoftBody::PSolve_SContacts(btSoftBody* psb,btScalar,btScalar ti) { + BT_PROFILE("PSolve_SContacts"); + for(int i=0,ni=psb->m_scontacts.size();im_scontacts[i]; @@ -3084,6 +3134,7 @@ void btSoftBody::PSolve_SContacts(btSoftBody* psb,btScalar,btScalar ti) // void btSoftBody::PSolve_Links(btSoftBody* psb,btScalar kst,btScalar ti) { +BT_PROFILE("PSolve_Links"); for(int i=0,ni=psb->m_links.size();im_links[i]; @@ -3106,6 +3157,7 @@ void btSoftBody::PSolve_Links(btSoftBody* psb,btScalar kst,btScalar ti) // void btSoftBody::VSolve_Links(btSoftBody* psb,btScalar kst) { + BT_PROFILE("VSolve_Links"); for(int i=0,ni=psb->m_links.size();im_links[i]; diff --git a/extern/bullet2/src/BulletSoftBody/btSoftBody.h b/extern/bullet/src/BulletSoftBody/btSoftBody.h similarity index 99% rename from extern/bullet2/src/BulletSoftBody/btSoftBody.h rename to extern/bullet/src/BulletSoftBody/btSoftBody.h index bd5846bfb67b..ada0dfd1a5cd 100644 --- a/extern/bullet2/src/BulletSoftBody/btSoftBody.h +++ b/extern/bullet/src/BulletSoftBody/btSoftBody.h @@ -232,15 +232,18 @@ class btSoftBody : public btCollisionObject int m_battach:1; // Attached }; /* Link */ - struct Link : Feature + ATTRIBUTE_ALIGNED16(struct) Link : Feature { + btVector3 m_c3; // gradient Node* m_n[2]; // Node pointers btScalar m_rl; // Rest length int m_bbending:1; // Bending link btScalar m_c0; // (ima+imb)*kLST btScalar m_c1; // rl^2 btScalar m_c2; // |gradient|^2/c0 - btVector3 m_c3; // gradient + + BT_DECLARE_ALIGNED_ALLOCATOR(); + }; /* Face */ struct Face : Feature @@ -614,7 +617,7 @@ class btSoftBody : public btCollisionObject RayFromToCaster(const btVector3& rayFrom,const btVector3& rayTo,btScalar mxt); void Process(const btDbvtNode* leaf); - static inline btScalar rayFromToTriangle(const btVector3& rayFrom, + static /*inline*/ btScalar rayFromToTriangle(const btVector3& rayFrom, const btVector3& rayTo, const btVector3& rayNormalizedDirection, const btVector3& a, diff --git a/extern/bullet2/src/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.cpp b/extern/bullet/src/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.cpp similarity index 96% rename from extern/bullet2/src/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.cpp rename to extern/bullet/src/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.cpp index 9f0d44526bf4..ab84bddf2a68 100644 --- a/extern/bullet2/src/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.cpp +++ b/extern/bullet/src/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.cpp @@ -120,8 +120,8 @@ void btSoftBodyTriangleCallback::processTriangle(btVector3* triangle,int partId, btCollisionObjectWrapper softBody(0,m_softBody->getCollisionShape(),m_softBody,m_softBody->getWorldTransform(),-1,-1); //btCollisionObjectWrapper triBody(0,tm, ob, btTransform::getIdentity());//ob->getWorldTransform());//?? btCollisionObjectWrapper triBody(0,tm, m_triBody, m_triBody->getWorldTransform(),partId, triangleIndex); - - btCollisionAlgorithm* colAlgo = ci.m_dispatcher1->findAlgorithm(&softBody,&triBody,0);//m_manifoldPtr); + ebtDispatcherQueryType algoType = m_resultOut->m_closestPointDistanceThreshold > 0 ? BT_CLOSEST_POINT_ALGORITHMS : BT_CONTACT_POINT_ALGORITHMS; + btCollisionAlgorithm* colAlgo = ci.m_dispatcher1->findAlgorithm(&softBody,&triBody,0, algoType);//m_manifoldPtr); colAlgo->processCollision(&softBody,&triBody,*m_dispatchInfoPtr,m_resultOut); colAlgo->~btCollisionAlgorithm(); @@ -164,7 +164,8 @@ void btSoftBodyTriangleCallback::processTriangle(btVector3* triangle,int partId, btCollisionObjectWrapper softBody(0,m_softBody->getCollisionShape(),m_softBody,m_softBody->getWorldTransform(),-1,-1); btCollisionObjectWrapper triBody(0,tm, m_triBody, m_triBody->getWorldTransform(),partId, triangleIndex);//btTransform::getIdentity());//?? - btCollisionAlgorithm* colAlgo = ci.m_dispatcher1->findAlgorithm(&softBody,&triBody,0);//m_manifoldPtr); + ebtDispatcherQueryType algoType = m_resultOut->m_closestPointDistanceThreshold > 0 ? BT_CLOSEST_POINT_ALGORITHMS : BT_CONTACT_POINT_ALGORITHMS; + btCollisionAlgorithm* colAlgo = ci.m_dispatcher1->findAlgorithm(&softBody,&triBody,0, algoType);//m_manifoldPtr); colAlgo->processCollision(&softBody,&triBody,*m_dispatchInfoPtr,m_resultOut); colAlgo->~btCollisionAlgorithm(); diff --git a/extern/bullet2/src/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.h b/extern/bullet/src/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.h similarity index 100% rename from extern/bullet2/src/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.h rename to extern/bullet/src/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.h diff --git a/extern/bullet2/src/BulletSoftBody/btSoftBodyData.h b/extern/bullet/src/BulletSoftBody/btSoftBodyData.h similarity index 100% rename from extern/bullet2/src/BulletSoftBody/btSoftBodyData.h rename to extern/bullet/src/BulletSoftBody/btSoftBodyData.h diff --git a/extern/bullet2/src/BulletSoftBody/btSoftBodyHelpers.cpp b/extern/bullet/src/BulletSoftBody/btSoftBodyHelpers.cpp similarity index 99% rename from extern/bullet2/src/BulletSoftBody/btSoftBodyHelpers.cpp rename to extern/bullet/src/BulletSoftBody/btSoftBodyHelpers.cpp index d96f85ec6308..51fcd16da407 100644 --- a/extern/bullet2/src/BulletSoftBody/btSoftBodyHelpers.cpp +++ b/extern/bullet/src/BulletSoftBody/btSoftBodyHelpers.cpp @@ -123,8 +123,9 @@ static inline T average(const btAlignedObjectArray& items) return(sum(items)/n); } +#if 0 // -static inline btScalar tetravolume(const btVector3& x0, + inline static btScalar tetravolume(const btVector3& x0, const btVector3& x1, const btVector3& x2, const btVector3& x3) @@ -134,6 +135,7 @@ static inline btScalar tetravolume(const btVector3& x0, const btVector3 c=x3-x0; return(btDot(a,btCross(b,c))); } +#endif // #if 0 @@ -1127,7 +1129,6 @@ int nattrb=0; int hasbounds=0; int result = sscanf(node,"%d %d %d %d",&nnode,&ndims,&nattrb,&hasbounds); result = sscanf(node,"%d %d %d %d",&nnode,&ndims,&nattrb,&hasbounds); -(void)result; node += nextLine(node); pos.resize(nnode); @@ -1209,10 +1210,10 @@ if(ele&&ele[0]) } } } -printf("Nodes: %d\r\n",psb->m_nodes.size()); -printf("Links: %d\r\n",psb->m_links.size()); -printf("Faces: %d\r\n",psb->m_faces.size()); -printf("Tetras: %d\r\n",psb->m_tetras.size()); +printf("Nodes: %u\r\n",psb->m_nodes.size()); +printf("Links: %u\r\n",psb->m_links.size()); +printf("Faces: %u\r\n",psb->m_faces.size()); +printf("Tetras: %u\r\n",psb->m_tetras.size()); return(psb); } diff --git a/extern/bullet2/src/BulletSoftBody/btSoftBodyHelpers.h b/extern/bullet/src/BulletSoftBody/btSoftBodyHelpers.h similarity index 100% rename from extern/bullet2/src/BulletSoftBody/btSoftBodyHelpers.h rename to extern/bullet/src/BulletSoftBody/btSoftBodyHelpers.h diff --git a/extern/bullet2/src/BulletSoftBody/btSoftBodyInternals.h b/extern/bullet/src/BulletSoftBody/btSoftBodyInternals.h similarity index 99% rename from extern/bullet2/src/BulletSoftBody/btSoftBodyInternals.h rename to extern/bullet/src/BulletSoftBody/btSoftBodyInternals.h index 1b9d02d79f93..1ad82616ea0b 100644 --- a/extern/bullet2/src/BulletSoftBody/btSoftBodyInternals.h +++ b/extern/bullet/src/BulletSoftBody/btSoftBodyInternals.h @@ -422,7 +422,7 @@ static inline btVector3 BaryCoord( const btVector3& a, } // -static inline btScalar ImplicitSolve( btSoftBody::ImplicitFn* fn, +inline static btScalar ImplicitSolve( btSoftBody::ImplicitFn* fn, const btVector3& a, const btVector3& b, const btScalar accuracy, @@ -451,6 +451,25 @@ static inline btScalar ImplicitSolve( btSoftBody::ImplicitFn* fn, return(-1); } +inline static void EvaluateMedium( const btSoftBodyWorldInfo* wfi, + const btVector3& x, + btSoftBody::sMedium& medium) +{ + medium.m_velocity = btVector3(0,0,0); + medium.m_pressure = 0; + medium.m_density = wfi->air_density; + if(wfi->water_density>0) + { + const btScalar depth=-(btDot(x,wfi->water_normal)+wfi->water_offset); + if(depth>0) + { + medium.m_density = wfi->water_density; + medium.m_pressure = depth*wfi->water_density*wfi->m_gravity.length(); + } + } +} + + // static inline btVector3 NormalizeAny(const btVector3& v) { @@ -504,23 +523,7 @@ static inline btScalar VolumeOf( const btVector3& x0, } // -static inline void EvaluateMedium( const btSoftBodyWorldInfo* wfi, - const btVector3& x, - btSoftBody::sMedium& medium) -{ - medium.m_velocity = btVector3(0,0,0); - medium.m_pressure = 0; - medium.m_density = wfi->air_density; - if(wfi->water_density>0) - { - const btScalar depth=-(btDot(x,wfi->water_normal)+wfi->water_offset); - if(depth>0) - { - medium.m_density = wfi->water_density; - medium.m_pressure = depth*wfi->water_density*wfi->m_gravity.length(); - } - } -} + // static inline void ApplyClampedForce( btSoftBody::Node& n, diff --git a/extern/bullet2/src/BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.cpp b/extern/bullet/src/BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.cpp similarity index 100% rename from extern/bullet2/src/BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.cpp rename to extern/bullet/src/BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.cpp diff --git a/extern/bullet2/src/BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h b/extern/bullet/src/BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h similarity index 100% rename from extern/bullet2/src/BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h rename to extern/bullet/src/BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h diff --git a/extern/bullet2/src/BulletSoftBody/btSoftBodySolverVertexBuffer.h b/extern/bullet/src/BulletSoftBody/btSoftBodySolverVertexBuffer.h similarity index 100% rename from extern/bullet2/src/BulletSoftBody/btSoftBodySolverVertexBuffer.h rename to extern/bullet/src/BulletSoftBody/btSoftBodySolverVertexBuffer.h diff --git a/extern/bullet2/src/BulletSoftBody/btSoftBodySolvers.h b/extern/bullet/src/BulletSoftBody/btSoftBodySolvers.h similarity index 100% rename from extern/bullet2/src/BulletSoftBody/btSoftBodySolvers.h rename to extern/bullet/src/BulletSoftBody/btSoftBodySolvers.h diff --git a/extern/bullet/src/BulletSoftBody/btSoftMultiBodyDynamicsWorld.cpp b/extern/bullet/src/BulletSoftBody/btSoftMultiBodyDynamicsWorld.cpp new file mode 100644 index 000000000000..4e76dca9db10 --- /dev/null +++ b/extern/bullet/src/BulletSoftBody/btSoftMultiBodyDynamicsWorld.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 "btSoftMultiBodyDynamicsWorld.h" +#include "LinearMath/btQuickprof.h" + +//softbody & helpers +#include "BulletSoftBody/btSoftBody.h" +#include "BulletSoftBody/btSoftBodyHelpers.h" +#include "BulletSoftBody/btSoftBodySolvers.h" +#include "BulletSoftBody/btDefaultSoftBodySolver.h" +#include "LinearMath/btSerializer.h" + + +btSoftMultiBodyDynamicsWorld::btSoftMultiBodyDynamicsWorld( + btDispatcher* dispatcher, + btBroadphaseInterface* pairCache, + btMultiBodyConstraintSolver* constraintSolver, + btCollisionConfiguration* collisionConfiguration, + btSoftBodySolver *softBodySolver ) : + btMultiBodyDynamicsWorld(dispatcher,pairCache,constraintSolver,collisionConfiguration), + m_softBodySolver( softBodySolver ), + m_ownsSolver(false) +{ + if( !m_softBodySolver ) + { + void* ptr = btAlignedAlloc(sizeof(btDefaultSoftBodySolver),16); + m_softBodySolver = new(ptr) btDefaultSoftBodySolver(); + m_ownsSolver = true; + } + + m_drawFlags = fDrawFlags::Std; + m_drawNodeTree = true; + m_drawFaceTree = false; + m_drawClusterTree = false; + m_sbi.m_broadphase = pairCache; + m_sbi.m_dispatcher = dispatcher; + m_sbi.m_sparsesdf.Initialize(); + m_sbi.m_sparsesdf.Reset(); + + m_sbi.air_density = (btScalar)1.2; + m_sbi.water_density = 0; + m_sbi.water_offset = 0; + m_sbi.water_normal = btVector3(0,0,0); + m_sbi.m_gravity.setValue(0,-10,0); + + m_sbi.m_sparsesdf.Initialize(); + + +} + +btSoftMultiBodyDynamicsWorld::~btSoftMultiBodyDynamicsWorld() +{ + if (m_ownsSolver) + { + m_softBodySolver->~btSoftBodySolver(); + btAlignedFree(m_softBodySolver); + } +} + +void btSoftMultiBodyDynamicsWorld::predictUnconstraintMotion(btScalar timeStep) +{ + btDiscreteDynamicsWorld::predictUnconstraintMotion( timeStep ); + { + BT_PROFILE("predictUnconstraintMotionSoftBody"); + m_softBodySolver->predictMotion( float(timeStep) ); + } +} + +void btSoftMultiBodyDynamicsWorld::internalSingleStepSimulation( btScalar timeStep ) +{ + + // Let the solver grab the soft bodies and if necessary optimize for it + m_softBodySolver->optimize( getSoftBodyArray() ); + + if( !m_softBodySolver->checkInitialized() ) + { + btAssert( "Solver initialization failed\n" ); + } + + btDiscreteDynamicsWorld::internalSingleStepSimulation( timeStep ); + + ///solve soft bodies constraints + solveSoftBodiesConstraints( timeStep ); + + //self collisions + for ( int i=0;idefaultCollisionHandler(psb); + } + + ///update soft bodies + m_softBodySolver->updateSoftBodies( ); + + // End solver-wise simulation step + // /////////////////////////////// + +} + +void btSoftMultiBodyDynamicsWorld::solveSoftBodiesConstraints( btScalar timeStep ) +{ + BT_PROFILE("solveSoftConstraints"); + + if(m_softBodies.size()) + { + btSoftBody::solveClusters(m_softBodies); + } + + // Solve constraints solver-wise + m_softBodySolver->solveConstraints( timeStep * m_softBodySolver->getTimeScale() ); + +} + +void btSoftMultiBodyDynamicsWorld::addSoftBody(btSoftBody* body, int collisionFilterGroup, int collisionFilterMask) +{ + m_softBodies.push_back(body); + + // Set the soft body solver that will deal with this body + // to be the world's solver + body->setSoftBodySolver( m_softBodySolver ); + + btCollisionWorld::addCollisionObject(body, + collisionFilterGroup, + collisionFilterMask); + +} + +void btSoftMultiBodyDynamicsWorld::removeSoftBody(btSoftBody* body) +{ + m_softBodies.remove(body); + + btCollisionWorld::removeCollisionObject(body); +} + +void btSoftMultiBodyDynamicsWorld::removeCollisionObject(btCollisionObject* collisionObject) +{ + btSoftBody* body = btSoftBody::upcast(collisionObject); + if (body) + removeSoftBody(body); + else + btDiscreteDynamicsWorld::removeCollisionObject(collisionObject); +} + +void btSoftMultiBodyDynamicsWorld::debugDrawWorld() +{ + btDiscreteDynamicsWorld::debugDrawWorld(); + + if (getDebugDrawer()) + { + int i; + for ( i=0;im_softBodies.size();i++) + { + btSoftBody* psb=(btSoftBody*)this->m_softBodies[i]; + if (getDebugDrawer() && (getDebugDrawer()->getDebugMode() & (btIDebugDraw::DBG_DrawWireframe))) + { + btSoftBodyHelpers::DrawFrame(psb,m_debugDrawer); + btSoftBodyHelpers::Draw(psb,m_debugDrawer,m_drawFlags); + } + + if (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawAabb)) + { + if(m_drawNodeTree) btSoftBodyHelpers::DrawNodeTree(psb,m_debugDrawer); + if(m_drawFaceTree) btSoftBodyHelpers::DrawFaceTree(psb,m_debugDrawer); + if(m_drawClusterTree) btSoftBodyHelpers::DrawClusterTree(psb,m_debugDrawer); + } + } + } +} + + + + +struct btSoftSingleRayCallback : public btBroadphaseRayCallback +{ + btVector3 m_rayFromWorld; + btVector3 m_rayToWorld; + btTransform m_rayFromTrans; + btTransform m_rayToTrans; + btVector3 m_hitNormal; + + const btSoftMultiBodyDynamicsWorld* m_world; + btCollisionWorld::RayResultCallback& m_resultCallback; + + btSoftSingleRayCallback(const btVector3& rayFromWorld,const btVector3& rayToWorld,const btSoftMultiBodyDynamicsWorld* world,btCollisionWorld::RayResultCallback& resultCallback) + :m_rayFromWorld(rayFromWorld), + m_rayToWorld(rayToWorld), + m_world(world), + m_resultCallback(resultCallback) + { + m_rayFromTrans.setIdentity(); + m_rayFromTrans.setOrigin(m_rayFromWorld); + m_rayToTrans.setIdentity(); + m_rayToTrans.setOrigin(m_rayToWorld); + + btVector3 rayDir = (rayToWorld-rayFromWorld); + + rayDir.normalize (); + ///what about division by zero? --> just set rayDirection[i] to INF/1e30 + m_rayDirectionInverse[0] = rayDir[0] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[0]; + m_rayDirectionInverse[1] = rayDir[1] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[1]; + m_rayDirectionInverse[2] = rayDir[2] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[2]; + m_signs[0] = m_rayDirectionInverse[0] < 0.0; + m_signs[1] = m_rayDirectionInverse[1] < 0.0; + m_signs[2] = m_rayDirectionInverse[2] < 0.0; + + m_lambda_max = rayDir.dot(m_rayToWorld-m_rayFromWorld); + + } + + + + virtual bool process(const btBroadphaseProxy* proxy) + { + ///terminate further ray tests, once the closestHitFraction reached zero + if (m_resultCallback.m_closestHitFraction == btScalar(0.f)) + return false; + + btCollisionObject* collisionObject = (btCollisionObject*)proxy->m_clientObject; + + //only perform raycast if filterMask matches + if(m_resultCallback.needsCollision(collisionObject->getBroadphaseHandle())) + { + //RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject(); + //btVector3 collisionObjectAabbMin,collisionObjectAabbMax; +#if 0 +#ifdef RECALCULATE_AABB + btVector3 collisionObjectAabbMin,collisionObjectAabbMax; + collisionObject->getCollisionShape()->getAabb(collisionObject->getWorldTransform(),collisionObjectAabbMin,collisionObjectAabbMax); +#else + //getBroadphase()->getAabb(collisionObject->getBroadphaseHandle(),collisionObjectAabbMin,collisionObjectAabbMax); + const btVector3& collisionObjectAabbMin = collisionObject->getBroadphaseHandle()->m_aabbMin; + const btVector3& collisionObjectAabbMax = collisionObject->getBroadphaseHandle()->m_aabbMax; +#endif +#endif + //btScalar hitLambda = m_resultCallback.m_closestHitFraction; + //culling already done by broadphase + //if (btRayAabb(m_rayFromWorld,m_rayToWorld,collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,m_hitNormal)) + { + m_world->rayTestSingle(m_rayFromTrans,m_rayToTrans, + collisionObject, + collisionObject->getCollisionShape(), + collisionObject->getWorldTransform(), + m_resultCallback); + } + } + return true; + } +}; + +void btSoftMultiBodyDynamicsWorld::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) const +{ + BT_PROFILE("rayTest"); + /// use the broadphase to accelerate the search for objects, based on their aabb + /// and for each object with ray-aabb overlap, perform an exact ray test + btSoftSingleRayCallback rayCB(rayFromWorld,rayToWorld,this,resultCallback); + +#ifndef USE_BRUTEFORCE_RAYBROADPHASE + m_broadphasePairCache->rayTest(rayFromWorld,rayToWorld,rayCB); +#else + for (int i=0;igetNumCollisionObjects();i++) + { + rayCB.process(m_collisionObjects[i]->getBroadphaseHandle()); + } +#endif //USE_BRUTEFORCE_RAYBROADPHASE + +} + + +void btSoftMultiBodyDynamicsWorld::rayTestSingle(const btTransform& rayFromTrans,const btTransform& rayToTrans, + btCollisionObject* collisionObject, + const btCollisionShape* collisionShape, + const btTransform& colObjWorldTransform, + RayResultCallback& resultCallback) +{ + if (collisionShape->isSoftBody()) { + btSoftBody* softBody = btSoftBody::upcast(collisionObject); + if (softBody) { + btSoftBody::sRayCast softResult; + if (softBody->rayTest(rayFromTrans.getOrigin(), rayToTrans.getOrigin(), softResult)) + { + + if (softResult.fraction<= resultCallback.m_closestHitFraction) + { + + btCollisionWorld::LocalShapeInfo shapeInfo; + shapeInfo.m_shapePart = 0; + shapeInfo.m_triangleIndex = softResult.index; + // get the normal + btVector3 rayDir = rayToTrans.getOrigin() - rayFromTrans.getOrigin(); + btVector3 normal=-rayDir; + normal.normalize(); + + if (softResult.feature == btSoftBody::eFeature::Face) + { + normal = softBody->m_faces[softResult.index].m_normal; + if (normal.dot(rayDir) > 0) { + // normal always point toward origin of the ray + normal = -normal; + } + } + + btCollisionWorld::LocalRayResult rayResult + (collisionObject, + &shapeInfo, + normal, + softResult.fraction); + bool normalInWorldSpace = true; + resultCallback.addSingleResult(rayResult,normalInWorldSpace); + } + } + } + } + else { + btCollisionWorld::rayTestSingle(rayFromTrans,rayToTrans,collisionObject,collisionShape,colObjWorldTransform,resultCallback); + } +} + + +void btSoftMultiBodyDynamicsWorld::serializeSoftBodies(btSerializer* serializer) +{ + int i; + //serialize all collision objects + for (i=0;igetInternalType() & btCollisionObject::CO_SOFT_BODY) + { + int len = colObj->calculateSerializeBufferSize(); + btChunk* chunk = serializer->allocate(len,1); + const char* structType = colObj->serialize(chunk->m_oldPtr, serializer); + serializer->finalizeChunk(chunk,structType,BT_SOFTBODY_CODE,colObj); + } + } + +} + +void btSoftMultiBodyDynamicsWorld::serialize(btSerializer* serializer) +{ + + serializer->startSerialization(); + + serializeDynamicsWorldInfo( serializer); + + serializeSoftBodies(serializer); + + serializeRigidBodies(serializer); + + serializeCollisionObjects(serializer); + + serializer->finishSerialization(); +} + + diff --git a/extern/bullet/src/BulletSoftBody/btSoftMultiBodyDynamicsWorld.h b/extern/bullet/src/BulletSoftBody/btSoftMultiBodyDynamicsWorld.h new file mode 100644 index 000000000000..6d46a21db5c0 --- /dev/null +++ b/extern/bullet/src/BulletSoftBody/btSoftMultiBodyDynamicsWorld.h @@ -0,0 +1,110 @@ +/* +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_SOFT_MULTIBODY_DYNAMICS_WORLD_H +#define BT_SOFT_MULTIBODY_DYNAMICS_WORLD_H + +#include "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h" +#include "BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h" +#include "BulletSoftBody/btSoftBody.h" + +#ifndef BT_SOFT_RIGID_DYNAMICS_WORLD_H +typedef btAlignedObjectArray btSoftBodyArray; +#endif + +class btSoftBodySolver; + +class btSoftMultiBodyDynamicsWorld : public btMultiBodyDynamicsWorld +{ + + btSoftBodyArray m_softBodies; + int m_drawFlags; + bool m_drawNodeTree; + bool m_drawFaceTree; + bool m_drawClusterTree; + btSoftBodyWorldInfo m_sbi; + ///Solver classes that encapsulate multiple soft bodies for solving + btSoftBodySolver *m_softBodySolver; + bool m_ownsSolver; + +protected: + + virtual void predictUnconstraintMotion(btScalar timeStep); + + virtual void internalSingleStepSimulation( btScalar timeStep); + + void solveSoftBodiesConstraints( btScalar timeStep ); + + void serializeSoftBodies(btSerializer* serializer); + +public: + + btSoftMultiBodyDynamicsWorld(btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btMultiBodyConstraintSolver* constraintSolver, btCollisionConfiguration* collisionConfiguration, btSoftBodySolver *softBodySolver = 0 ); + + virtual ~btSoftMultiBodyDynamicsWorld(); + + virtual void debugDrawWorld(); + + void addSoftBody(btSoftBody* body, int collisionFilterGroup=btBroadphaseProxy::DefaultFilter, int collisionFilterMask=btBroadphaseProxy::AllFilter); + + void removeSoftBody(btSoftBody* body); + + ///removeCollisionObject will first check if it is a rigid body, if so call removeRigidBody otherwise call btDiscreteDynamicsWorld::removeCollisionObject + virtual void removeCollisionObject(btCollisionObject* collisionObject); + + int getDrawFlags() const { return(m_drawFlags); } + void setDrawFlags(int f) { m_drawFlags=f; } + + btSoftBodyWorldInfo& getWorldInfo() + { + return m_sbi; + } + const btSoftBodyWorldInfo& getWorldInfo() const + { + return m_sbi; + } + + virtual btDynamicsWorldType getWorldType() const + { + return BT_SOFT_MULTIBODY_DYNAMICS_WORLD; + } + + btSoftBodyArray& getSoftBodyArray() + { + return m_softBodies; + } + + const btSoftBodyArray& getSoftBodyArray() const + { + return m_softBodies; + } + + + virtual void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) const; + + /// 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); + + virtual void serialize(btSerializer* serializer); + +}; + +#endif //BT_SOFT_MULTIBODY_DYNAMICS_WORLD_H diff --git a/extern/bullet2/src/BulletSoftBody/btSoftRigidCollisionAlgorithm.cpp b/extern/bullet/src/BulletSoftBody/btSoftRigidCollisionAlgorithm.cpp similarity index 100% rename from extern/bullet2/src/BulletSoftBody/btSoftRigidCollisionAlgorithm.cpp rename to extern/bullet/src/BulletSoftBody/btSoftRigidCollisionAlgorithm.cpp diff --git a/extern/bullet2/src/BulletSoftBody/btSoftRigidCollisionAlgorithm.h b/extern/bullet/src/BulletSoftBody/btSoftRigidCollisionAlgorithm.h similarity index 97% rename from extern/bullet2/src/BulletSoftBody/btSoftRigidCollisionAlgorithm.h rename to extern/bullet/src/BulletSoftBody/btSoftRigidCollisionAlgorithm.h index a9b513e36397..93fcc6065b5e 100644 --- a/extern/bullet2/src/BulletSoftBody/btSoftRigidCollisionAlgorithm.h +++ b/extern/bullet/src/BulletSoftBody/btSoftRigidCollisionAlgorithm.h @@ -31,8 +31,8 @@ class btSoftRigidCollisionAlgorithm : public btCollisionAlgorithm // bool m_ownManifold; // btPersistentManifold* m_manifoldPtr; - btSoftBody* m_softBody; - btCollisionObject* m_rigidCollisionObject; + //btSoftBody* m_softBody; + //btCollisionObject* m_rigidCollisionObject; ///for rigid versus soft (instead of soft versus rigid), we use this swapped boolean bool m_isSwapped; diff --git a/extern/bullet2/src/BulletSoftBody/btSoftRigidDynamicsWorld.cpp b/extern/bullet/src/BulletSoftBody/btSoftRigidDynamicsWorld.cpp similarity index 98% rename from extern/bullet2/src/BulletSoftBody/btSoftRigidDynamicsWorld.cpp rename to extern/bullet/src/BulletSoftBody/btSoftRigidDynamicsWorld.cpp index 653d5a06b496..204b4f576d57 100644 --- a/extern/bullet2/src/BulletSoftBody/btSoftRigidDynamicsWorld.cpp +++ b/extern/bullet/src/BulletSoftBody/btSoftRigidDynamicsWorld.cpp @@ -125,7 +125,7 @@ void btSoftRigidDynamicsWorld::solveSoftBodiesConstraints( btScalar timeStep ) } -void btSoftRigidDynamicsWorld::addSoftBody(btSoftBody* body,short int collisionFilterGroup,short int collisionFilterMask) +void btSoftRigidDynamicsWorld::addSoftBody(btSoftBody* body, int collisionFilterGroup, int collisionFilterMask) { m_softBodies.push_back(body); diff --git a/extern/bullet2/src/BulletSoftBody/btSoftRigidDynamicsWorld.h b/extern/bullet/src/BulletSoftBody/btSoftRigidDynamicsWorld.h similarity index 95% rename from extern/bullet2/src/BulletSoftBody/btSoftRigidDynamicsWorld.h rename to extern/bullet/src/BulletSoftBody/btSoftRigidDynamicsWorld.h index 3e0efafd6c76..d921a6488d33 100644 --- a/extern/bullet2/src/BulletSoftBody/btSoftRigidDynamicsWorld.h +++ b/extern/bullet/src/BulletSoftBody/btSoftRigidDynamicsWorld.h @@ -54,7 +54,7 @@ class btSoftRigidDynamicsWorld : public btDiscreteDynamicsWorld virtual void debugDrawWorld(); - void addSoftBody(btSoftBody* body,short int collisionFilterGroup=btBroadphaseProxy::DefaultFilter,short int collisionFilterMask=btBroadphaseProxy::AllFilter); + void addSoftBody(btSoftBody* body, int collisionFilterGroup=btBroadphaseProxy::DefaultFilter, int collisionFilterMask=btBroadphaseProxy::AllFilter); void removeSoftBody(btSoftBody* body); diff --git a/extern/bullet/src/BulletSoftBody/btSoftRigidDynamicsWorldMt.cpp b/extern/bullet/src/BulletSoftBody/btSoftRigidDynamicsWorldMt.cpp new file mode 100644 index 000000000000..bd3625a751cf --- /dev/null +++ b/extern/bullet/src/BulletSoftBody/btSoftRigidDynamicsWorldMt.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 "btSoftRigidDynamicsWorldMt.h" +#include "LinearMath/btQuickprof.h" + +//softbody & helpers +#include "btSoftBody.h" +#include "btSoftBodyHelpers.h" +#include "btSoftBodySolvers.h" +#include "btDefaultSoftBodySolver.h" +#include "LinearMath/btSerializer.h" + + +btSoftRigidDynamicsWorldMt::btSoftRigidDynamicsWorldMt( + btDispatcher* dispatcher, + btBroadphaseInterface* pairCache, + btConstraintSolverPoolMt* constraintSolver, + btCollisionConfiguration* collisionConfiguration, + btSoftBodySolver *softBodySolver ) : + btDiscreteDynamicsWorldMt(dispatcher,pairCache,constraintSolver,collisionConfiguration), + m_softBodySolver( softBodySolver ), + m_ownsSolver(false) +{ + if( !m_softBodySolver ) + { + void* ptr = btAlignedAlloc(sizeof(btDefaultSoftBodySolver),16); + m_softBodySolver = new(ptr) btDefaultSoftBodySolver(); + m_ownsSolver = true; + } + + m_drawFlags = fDrawFlags::Std; + m_drawNodeTree = true; + m_drawFaceTree = false; + m_drawClusterTree = false; + m_sbi.m_broadphase = pairCache; + m_sbi.m_dispatcher = dispatcher; + m_sbi.m_sparsesdf.Initialize(); + m_sbi.m_sparsesdf.Reset(); + + m_sbi.air_density = (btScalar)1.2; + m_sbi.water_density = 0; + m_sbi.water_offset = 0; + m_sbi.water_normal = btVector3(0,0,0); + m_sbi.m_gravity.setValue(0,-10,0); + + m_sbi.m_sparsesdf.Initialize(); + + +} + +btSoftRigidDynamicsWorldMt::~btSoftRigidDynamicsWorldMt() +{ + if (m_ownsSolver) + { + m_softBodySolver->~btSoftBodySolver(); + btAlignedFree(m_softBodySolver); + } +} + +void btSoftRigidDynamicsWorldMt::predictUnconstraintMotion(btScalar timeStep) +{ + btDiscreteDynamicsWorldMt::predictUnconstraintMotion( timeStep ); + { + BT_PROFILE("predictUnconstraintMotionSoftBody"); + m_softBodySolver->predictMotion( float(timeStep) ); + } +} + +void btSoftRigidDynamicsWorldMt::internalSingleStepSimulation( btScalar timeStep ) +{ + + // Let the solver grab the soft bodies and if necessary optimize for it + m_softBodySolver->optimize( getSoftBodyArray() ); + + if( !m_softBodySolver->checkInitialized() ) + { + btAssert( "Solver initialization failed\n" ); + } + + btDiscreteDynamicsWorldMt::internalSingleStepSimulation( timeStep ); + + ///solve soft bodies constraints + solveSoftBodiesConstraints( timeStep ); + + //self collisions + for ( int i=0;idefaultCollisionHandler(psb); + } + + ///update soft bodies + m_softBodySolver->updateSoftBodies( ); + + // End solver-wise simulation step + // /////////////////////////////// + +} + +void btSoftRigidDynamicsWorldMt::solveSoftBodiesConstraints( btScalar timeStep ) +{ + BT_PROFILE("solveSoftConstraints"); + + if(m_softBodies.size()) + { + btSoftBody::solveClusters(m_softBodies); + } + + // Solve constraints solver-wise + m_softBodySolver->solveConstraints( timeStep * m_softBodySolver->getTimeScale() ); + +} + +void btSoftRigidDynamicsWorldMt::addSoftBody(btSoftBody* body, int collisionFilterGroup, int collisionFilterMask) +{ + m_softBodies.push_back(body); + + // Set the soft body solver that will deal with this body + // to be the world's solver + body->setSoftBodySolver( m_softBodySolver ); + + btCollisionWorld::addCollisionObject(body, + collisionFilterGroup, + collisionFilterMask); + +} + +void btSoftRigidDynamicsWorldMt::removeSoftBody(btSoftBody* body) +{ + m_softBodies.remove(body); + + btCollisionWorld::removeCollisionObject(body); +} + +void btSoftRigidDynamicsWorldMt::removeCollisionObject(btCollisionObject* collisionObject) +{ + btSoftBody* body = btSoftBody::upcast(collisionObject); + if (body) + removeSoftBody(body); + else + btDiscreteDynamicsWorldMt::removeCollisionObject(collisionObject); +} + +void btSoftRigidDynamicsWorldMt::debugDrawWorld() +{ + btDiscreteDynamicsWorldMt::debugDrawWorld(); + + if (getDebugDrawer()) + { + int i; + for ( i=0;im_softBodies.size();i++) + { + btSoftBody* psb=(btSoftBody*)this->m_softBodies[i]; + if (getDebugDrawer() && (getDebugDrawer()->getDebugMode() & (btIDebugDraw::DBG_DrawWireframe))) + { + btSoftBodyHelpers::DrawFrame(psb,m_debugDrawer); + btSoftBodyHelpers::Draw(psb,m_debugDrawer,m_drawFlags); + } + + if (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawAabb)) + { + if(m_drawNodeTree) btSoftBodyHelpers::DrawNodeTree(psb,m_debugDrawer); + if(m_drawFaceTree) btSoftBodyHelpers::DrawFaceTree(psb,m_debugDrawer); + if(m_drawClusterTree) btSoftBodyHelpers::DrawClusterTree(psb,m_debugDrawer); + } + } + } +} + + + + +struct btSoftSingleRayCallback : public btBroadphaseRayCallback +{ + btVector3 m_rayFromWorld; + btVector3 m_rayToWorld; + btTransform m_rayFromTrans; + btTransform m_rayToTrans; + btVector3 m_hitNormal; + + const btSoftRigidDynamicsWorldMt* m_world; + btCollisionWorld::RayResultCallback& m_resultCallback; + + btSoftSingleRayCallback(const btVector3& rayFromWorld,const btVector3& rayToWorld,const btSoftRigidDynamicsWorldMt* world,btCollisionWorld::RayResultCallback& resultCallback) + :m_rayFromWorld(rayFromWorld), + m_rayToWorld(rayToWorld), + m_world(world), + m_resultCallback(resultCallback) + { + m_rayFromTrans.setIdentity(); + m_rayFromTrans.setOrigin(m_rayFromWorld); + m_rayToTrans.setIdentity(); + m_rayToTrans.setOrigin(m_rayToWorld); + + btVector3 rayDir = (rayToWorld-rayFromWorld); + + rayDir.normalize (); + ///what about division by zero? --> just set rayDirection[i] to INF/1e30 + m_rayDirectionInverse[0] = rayDir[0] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[0]; + m_rayDirectionInverse[1] = rayDir[1] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[1]; + m_rayDirectionInverse[2] = rayDir[2] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[2]; + m_signs[0] = m_rayDirectionInverse[0] < 0.0; + m_signs[1] = m_rayDirectionInverse[1] < 0.0; + m_signs[2] = m_rayDirectionInverse[2] < 0.0; + + m_lambda_max = rayDir.dot(m_rayToWorld-m_rayFromWorld); + + } + + + + virtual bool process(const btBroadphaseProxy* proxy) + { + ///terminate further ray tests, once the closestHitFraction reached zero + if (m_resultCallback.m_closestHitFraction == btScalar(0.f)) + return false; + + btCollisionObject* collisionObject = (btCollisionObject*)proxy->m_clientObject; + + //only perform raycast if filterMask matches + if(m_resultCallback.needsCollision(collisionObject->getBroadphaseHandle())) + { + //RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject(); + //btVector3 collisionObjectAabbMin,collisionObjectAabbMax; +#if 0 +#ifdef RECALCULATE_AABB + btVector3 collisionObjectAabbMin,collisionObjectAabbMax; + collisionObject->getCollisionShape()->getAabb(collisionObject->getWorldTransform(),collisionObjectAabbMin,collisionObjectAabbMax); +#else + //getBroadphase()->getAabb(collisionObject->getBroadphaseHandle(),collisionObjectAabbMin,collisionObjectAabbMax); + const btVector3& collisionObjectAabbMin = collisionObject->getBroadphaseHandle()->m_aabbMin; + const btVector3& collisionObjectAabbMax = collisionObject->getBroadphaseHandle()->m_aabbMax; +#endif +#endif + //btScalar hitLambda = m_resultCallback.m_closestHitFraction; + //culling already done by broadphase + //if (btRayAabb(m_rayFromWorld,m_rayToWorld,collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,m_hitNormal)) + { + m_world->rayTestSingle(m_rayFromTrans,m_rayToTrans, + collisionObject, + collisionObject->getCollisionShape(), + collisionObject->getWorldTransform(), + m_resultCallback); + } + } + return true; + } +}; + +void btSoftRigidDynamicsWorldMt::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) const +{ + BT_PROFILE("rayTest"); + /// use the broadphase to accelerate the search for objects, based on their aabb + /// and for each object with ray-aabb overlap, perform an exact ray test + btSoftSingleRayCallback rayCB(rayFromWorld,rayToWorld,this,resultCallback); + +#ifndef USE_BRUTEFORCE_RAYBROADPHASE + m_broadphasePairCache->rayTest(rayFromWorld,rayToWorld,rayCB); +#else + for (int i=0;igetNumCollisionObjects();i++) + { + rayCB.process(m_collisionObjects[i]->getBroadphaseHandle()); + } +#endif //USE_BRUTEFORCE_RAYBROADPHASE + +} + + +void btSoftRigidDynamicsWorldMt::rayTestSingle(const btTransform& rayFromTrans,const btTransform& rayToTrans, + btCollisionObject* collisionObject, + const btCollisionShape* collisionShape, + const btTransform& colObjWorldTransform, + RayResultCallback& resultCallback) +{ + if (collisionShape->isSoftBody()) { + btSoftBody* softBody = btSoftBody::upcast(collisionObject); + if (softBody) { + btSoftBody::sRayCast softResult; + if (softBody->rayTest(rayFromTrans.getOrigin(), rayToTrans.getOrigin(), softResult)) + { + + if (softResult.fraction<= resultCallback.m_closestHitFraction) + { + + btCollisionWorld::LocalShapeInfo shapeInfo; + shapeInfo.m_shapePart = 0; + shapeInfo.m_triangleIndex = softResult.index; + // get the normal + btVector3 rayDir = rayToTrans.getOrigin() - rayFromTrans.getOrigin(); + btVector3 normal=-rayDir; + normal.normalize(); + + if (softResult.feature == btSoftBody::eFeature::Face) + { + normal = softBody->m_faces[softResult.index].m_normal; + if (normal.dot(rayDir) > 0) { + // normal always point toward origin of the ray + normal = -normal; + } + } + + btCollisionWorld::LocalRayResult rayResult + (collisionObject, + &shapeInfo, + normal, + softResult.fraction); + bool normalInWorldSpace = true; + resultCallback.addSingleResult(rayResult,normalInWorldSpace); + } + } + } + } + else { + btCollisionWorld::rayTestSingle(rayFromTrans,rayToTrans,collisionObject,collisionShape,colObjWorldTransform,resultCallback); + } +} + + +void btSoftRigidDynamicsWorldMt::serializeSoftBodies(btSerializer* serializer) +{ + int i; + //serialize all collision objects + for (i=0;igetInternalType() & btCollisionObject::CO_SOFT_BODY) + { + int len = colObj->calculateSerializeBufferSize(); + btChunk* chunk = serializer->allocate(len,1); + const char* structType = colObj->serialize(chunk->m_oldPtr, serializer); + serializer->finalizeChunk(chunk,structType,BT_SOFTBODY_CODE,colObj); + } + } + +} + +void btSoftRigidDynamicsWorldMt::serialize(btSerializer* serializer) +{ + + serializer->startSerialization(); + + serializeDynamicsWorldInfo( serializer); + + serializeSoftBodies(serializer); + + serializeRigidBodies(serializer); + + serializeCollisionObjects(serializer); + + serializer->finishSerialization(); +} + + diff --git a/extern/bullet/src/BulletSoftBody/btSoftRigidDynamicsWorldMt.h b/extern/bullet/src/BulletSoftBody/btSoftRigidDynamicsWorldMt.h new file mode 100644 index 000000000000..be3b98c33615 --- /dev/null +++ b/extern/bullet/src/BulletSoftBody/btSoftRigidDynamicsWorldMt.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 BT_SOFT_RIGID_DYNAMICS_WORLD_H +#define BT_SOFT_RIGID_DYNAMICS_WORLD_H + +#include "BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h" +#include "btSoftBody.h" + +typedef btAlignedObjectArray btSoftBodyArray; + +class btSoftBodySolver; + +class btSoftRigidDynamicsWorldMt : public btDiscreteDynamicsWorldMt +{ + + btSoftBodyArray m_softBodies; + int m_drawFlags; + bool m_drawNodeTree; + bool m_drawFaceTree; + bool m_drawClusterTree; + btSoftBodyWorldInfo m_sbi; + ///Solver classes that encapsulate multiple soft bodies for solving + btSoftBodySolver *m_softBodySolver; + bool m_ownsSolver; + +protected: + + virtual void predictUnconstraintMotion(btScalar timeStep); + + virtual void internalSingleStepSimulation( btScalar timeStep); + + void solveSoftBodiesConstraints( btScalar timeStep ); + + void serializeSoftBodies(btSerializer* serializer); + +public: + + btSoftRigidDynamicsWorldMt(btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btConstraintSolverPoolMt* constraintSolver, btCollisionConfiguration* collisionConfiguration, btSoftBodySolver *softBodySolver = 0 ); + + virtual ~btSoftRigidDynamicsWorldMt(); + + virtual void debugDrawWorld(); + + void addSoftBody(btSoftBody* body, int collisionFilterGroup=btBroadphaseProxy::DefaultFilter, int collisionFilterMask=btBroadphaseProxy::AllFilter); + + void removeSoftBody(btSoftBody* body); + + ///removeCollisionObject will first check if it is a rigid body, if so call removeRigidBody otherwise call btDiscreteDynamicsWorld::removeCollisionObject + virtual void removeCollisionObject(btCollisionObject* collisionObject); + + int getDrawFlags() const { return(m_drawFlags); } + void setDrawFlags(int f) { m_drawFlags=f; } + + btSoftBodyWorldInfo& getWorldInfo() + { + return m_sbi; + } + const btSoftBodyWorldInfo& getWorldInfo() const + { + return m_sbi; + } + + virtual btDynamicsWorldType getWorldType() const + { + return BT_SOFT_RIGID_DYNAMICS_WORLD; + } + + btSoftBodyArray& getSoftBodyArray() + { + return m_softBodies; + } + + const btSoftBodyArray& getSoftBodyArray() const + { + return m_softBodies; + } + + + virtual void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) const; + + /// 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); + + virtual void serialize(btSerializer* serializer); + +}; + +#endif //BT_SOFT_RIGID_DYNAMICS_WORLD_H diff --git a/extern/bullet2/src/BulletSoftBody/btSoftSoftCollisionAlgorithm.cpp b/extern/bullet/src/BulletSoftBody/btSoftSoftCollisionAlgorithm.cpp similarity index 100% rename from extern/bullet2/src/BulletSoftBody/btSoftSoftCollisionAlgorithm.cpp rename to extern/bullet/src/BulletSoftBody/btSoftSoftCollisionAlgorithm.cpp diff --git a/extern/bullet2/src/BulletSoftBody/btSoftSoftCollisionAlgorithm.h b/extern/bullet/src/BulletSoftBody/btSoftSoftCollisionAlgorithm.h similarity index 98% rename from extern/bullet2/src/BulletSoftBody/btSoftSoftCollisionAlgorithm.h rename to extern/bullet/src/BulletSoftBody/btSoftSoftCollisionAlgorithm.h index 43b1439cc536..4eab7aea2fef 100644 --- a/extern/bullet2/src/BulletSoftBody/btSoftSoftCollisionAlgorithm.h +++ b/extern/bullet/src/BulletSoftBody/btSoftSoftCollisionAlgorithm.h @@ -30,8 +30,8 @@ class btSoftSoftCollisionAlgorithm : public btCollisionAlgorithm bool m_ownManifold; btPersistentManifold* m_manifoldPtr; - btSoftBody* m_softBody0; - btSoftBody* m_softBody1; +// btSoftBody* m_softBody0; +// btSoftBody* m_softBody1; public: diff --git a/extern/bullet2/src/BulletSoftBody/btSparseSDF.h b/extern/bullet/src/BulletSoftBody/btSparseSDF.h similarity index 99% rename from extern/bullet2/src/BulletSoftBody/btSparseSDF.h rename to extern/bullet/src/BulletSoftBody/btSparseSDF.h index 8992ddbb68d1..ba437c28efc2 100644 --- a/extern/bullet2/src/BulletSoftBody/btSparseSDF.h +++ b/extern/bullet/src/BulletSoftBody/btSparseSDF.h @@ -185,6 +185,7 @@ struct btSparseSdf { ++nprobes; ++ncells; + //int sz = sizeof(Cell); if (ncells>m_clampCells) { static int numResets=0; diff --git a/extern/bullet/src/BulletSoftBody/premake4.lua b/extern/bullet/src/BulletSoftBody/premake4.lua new file mode 100644 index 000000000000..57a575fb1831 --- /dev/null +++ b/extern/bullet/src/BulletSoftBody/premake4.lua @@ -0,0 +1,11 @@ + project "BulletSoftBody" + + kind "StaticLib" + + includedirs { + "..", + } + files { + "**.cpp", + "**.h" + } \ No newline at end of file diff --git a/extern/bullet/src/LinearMath/CMakeLists.txt b/extern/bullet/src/LinearMath/CMakeLists.txt new file mode 100644 index 000000000000..ede21d9a70c9 --- /dev/null +++ b/extern/bullet/src/LinearMath/CMakeLists.txt @@ -0,0 +1,75 @@ + +INCLUDE_DIRECTORIES( + ${BULLET_PHYSICS_SOURCE_DIR}/src +) + +SET(LinearMath_SRCS + btAlignedAllocator.cpp + btConvexHull.cpp + btConvexHullComputer.cpp + btGeometryUtil.cpp + btPolarDecomposition.cpp + btQuickprof.cpp + btSerializer.cpp + btSerializer64.cpp + btThreads.cpp + btVector3.cpp +) + +SET(LinearMath_HDRS + btAabbUtil2.h + btAlignedAllocator.h + btAlignedObjectArray.h + btConvexHull.h + btConvexHullComputer.h + btDefaultMotionState.h + btGeometryUtil.h + btGrahamScan2dConvexHull.h + btHashMap.h + btIDebugDraw.h + btList.h + btMatrix3x3.h + btMinMax.h + btMotionState.h + btPolarDecomposition.h + btPoolAllocator.h + btQuadWord.h + btQuaternion.h + btQuickprof.h + btRandom.h + btScalar.h + btSerializer.h + btStackAlloc.h + btThreads.h + btTransform.h + btTransformUtil.h + btVector3.h +) + +ADD_LIBRARY(LinearMath ${LinearMath_SRCS} ${LinearMath_HDRS}) +SET_TARGET_PROPERTIES(LinearMath PROPERTIES VERSION ${BULLET_VERSION}) +SET_TARGET_PROPERTIES(LinearMath PROPERTIES SOVERSION ${BULLET_VERSION}) + +IF (INSTALL_LIBS) + IF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) + #FILES_MATCHING requires CMake 2.6 + IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS LinearMath DESTINATION .) + ELSE (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + INSTALL(TARGETS LinearMath + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib${LIB_SUFFIX} + ARCHIVE DESTINATION lib${LIB_SUFFIX}) + INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.h" PATTERN +".svn" EXCLUDE PATTERN "CMakeFiles" EXCLUDE) + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + + IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + SET_TARGET_PROPERTIES(LinearMath PROPERTIES FRAMEWORK true) + SET_TARGET_PROPERTIES(LinearMath PROPERTIES PUBLIC_HEADER "${LinearMath_HDRS}") + ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) + ENDIF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) +ENDIF (INSTALL_LIBS) diff --git a/extern/bullet2/src/LinearMath/btAabbUtil2.h b/extern/bullet/src/LinearMath/btAabbUtil2.h similarity index 100% rename from extern/bullet2/src/LinearMath/btAabbUtil2.h rename to extern/bullet/src/LinearMath/btAabbUtil2.h diff --git a/extern/bullet2/src/LinearMath/btAlignedAllocator.cpp b/extern/bullet/src/LinearMath/btAlignedAllocator.cpp similarity index 62% rename from extern/bullet2/src/LinearMath/btAlignedAllocator.cpp rename to extern/bullet/src/LinearMath/btAlignedAllocator.cpp index a65296c6abe1..e5f6040c4382 100644 --- a/extern/bullet2/src/LinearMath/btAlignedAllocator.cpp +++ b/extern/bullet/src/LinearMath/btAlignedAllocator.cpp @@ -105,30 +105,94 @@ void btAlignedAllocSetCustom(btAllocFunc *allocFunc, btFreeFunc *freeFunc) } #ifdef BT_DEBUG_MEMORY_ALLOCATIONS + +static int allocations_id[10241024]; +static int allocations_bytes[10241024]; +static int mynumallocs = 0; +#include + +int btDumpMemoryLeaks() +{ + int totalLeak = 0; + + for (int i=0;i +struct btDebugPtrMagic +{ + union + { + void** vptrptr; + void* vptr; + int* iptr; + char* cptr; + }; +}; + + void* btAlignedAllocInternal (size_t size, int alignment,int line,char* filename) { + if (size==0) + { + printf("Whaat? size==0"); + return 0; + } + static int allocId = 0; + void *ret; char *real; +// to find some particular memory leak, you could do something like this: +// if (allocId==172) +// { +// printf("catch me!\n"); +// } +// if (size>1024*1024) +// { +// printf("big alloc!%d\n", size); +// } + gTotalBytesAlignedAllocs += size; gNumAlignedAllocs++; - real = (char *)sAllocFunc(size + 2*sizeof(void *) + (alignment-1)); +int sz4prt = 4*sizeof(void *); + + real = (char *)sAllocFunc(size + sz4prt + (alignment-1)); if (real) { - ret = (void*) btAlignPointer(real + 2*sizeof(void *), alignment); - *((void **)(ret)-1) = (void *)(real); - *((int*)(ret)-2) = size; + + ret = (void*) btAlignPointer(real + sz4prt, alignment); + btDebugPtrMagic p; + p.vptr = ret; + p.cptr-=sizeof(void*); + *p.vptrptr = (void*)real; + p.cptr-=sizeof(void*); + *p.iptr = size; + p.cptr-=sizeof(void*); + *p.iptr = allocId; + + allocations_id[mynumallocs] = allocId; + allocations_bytes[mynumallocs] = size; + mynumallocs++; } else { ret = (void *)(real);//?? } - printf("allocation#%d at address %x, from %s,line %d, size %d\n",gNumAlignedAllocs,real, filename,line,size); - + printf("allocation %d at address %x, from %s,line %d, size %d (total allocated = %d)\n",allocId,real, filename,line,size,gTotalBytesAlignedAllocs); + allocId++; + int* ptr = (int*)ret; *ptr = 12; return (ret); @@ -138,19 +202,43 @@ void btAlignedFreeInternal (void* ptr,int line,char* filename) { void* real; - gNumAlignedFree++; if (ptr) { - real = *((void **)(ptr)-1); - int size = *((int*)(ptr)-2); - gTotalBytesAlignedAllocs -= size; - - printf("free #%d at address %x, from %s,line %d, size %d\n",gNumAlignedFree,real, filename,line,size); + gNumAlignedFree++; + + btDebugPtrMagic p; + p.vptr = ptr; + p.cptr-=sizeof(void*); + real = *p.vptrptr; + p.cptr-=sizeof(void*); + int size = *p.iptr; + p.cptr-=sizeof(void*); + int allocId = *p.iptr; + + bool found = false; + + for (int i=0;iedges = NULL; + v->next = v; + v->prev = v; + + result.minXy = v; + result.maxXy = v; + result.minYx = v; + result.maxYx = v; + } + + return; } - // lint -fallthrough + case 1: { Vertex* v = originalVertices[start]; diff --git a/extern/bullet2/src/LinearMath/btConvexHullComputer.h b/extern/bullet/src/LinearMath/btConvexHullComputer.h similarity index 100% rename from extern/bullet2/src/LinearMath/btConvexHullComputer.h rename to extern/bullet/src/LinearMath/btConvexHullComputer.h diff --git a/extern/bullet2/src/LinearMath/btCpuFeatureUtility.h b/extern/bullet/src/LinearMath/btCpuFeatureUtility.h similarity index 100% rename from extern/bullet2/src/LinearMath/btCpuFeatureUtility.h rename to extern/bullet/src/LinearMath/btCpuFeatureUtility.h diff --git a/extern/bullet2/src/LinearMath/btDefaultMotionState.h b/extern/bullet/src/LinearMath/btDefaultMotionState.h similarity index 100% rename from extern/bullet2/src/LinearMath/btDefaultMotionState.h rename to extern/bullet/src/LinearMath/btDefaultMotionState.h diff --git a/extern/bullet2/src/LinearMath/btGeometryUtil.cpp b/extern/bullet/src/LinearMath/btGeometryUtil.cpp similarity index 100% rename from extern/bullet2/src/LinearMath/btGeometryUtil.cpp rename to extern/bullet/src/LinearMath/btGeometryUtil.cpp diff --git a/extern/bullet2/src/LinearMath/btGeometryUtil.h b/extern/bullet/src/LinearMath/btGeometryUtil.h similarity index 100% rename from extern/bullet2/src/LinearMath/btGeometryUtil.h rename to extern/bullet/src/LinearMath/btGeometryUtil.h diff --git a/extern/bullet2/src/LinearMath/btGrahamScan2dConvexHull.h b/extern/bullet/src/LinearMath/btGrahamScan2dConvexHull.h similarity index 100% rename from extern/bullet2/src/LinearMath/btGrahamScan2dConvexHull.h rename to extern/bullet/src/LinearMath/btGrahamScan2dConvexHull.h diff --git a/extern/bullet2/src/LinearMath/btHashMap.h b/extern/bullet/src/LinearMath/btHashMap.h similarity index 91% rename from extern/bullet2/src/LinearMath/btHashMap.h rename to extern/bullet/src/LinearMath/btHashMap.h index af9727b7adaf..5e9cdb605481 100644 --- a/extern/bullet2/src/LinearMath/btHashMap.h +++ b/extern/bullet/src/LinearMath/btHashMap.h @@ -52,7 +52,7 @@ struct btHashString { int ret = 0 ; - while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst) + while( ! (ret = *(const unsigned char *)src - *(const unsigned char *)dst) && *dst) ++src, ++dst; if ( ret < 0 ) @@ -79,6 +79,11 @@ class btHashInt { int m_uid; public: + + btHashInt() + { + } + btHashInt(int uid) :m_uid(uid) { } @@ -100,9 +105,10 @@ class btHashInt //to our success SIMD_FORCE_INLINE unsigned int getHash()const { - int key = m_uid; + unsigned int key = m_uid; // Thomas Wang's hash key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); + return key; } }; @@ -115,7 +121,7 @@ class btHashPtr union { const void* m_pointer; - int m_hashValues[2]; + unsigned int m_hashValues[2]; }; public: @@ -140,8 +146,7 @@ class btHashPtr { const bool VOID_IS_8 = ((sizeof(void*)==8)); - int key = VOID_IS_8? m_hashValues[0]+m_hashValues[1] : m_hashValues[0]; - + unsigned int key = VOID_IS_8? m_hashValues[0]+m_hashValues[1] : m_hashValues[0]; // Thomas Wang's hash key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); return key; @@ -174,7 +179,7 @@ class btHashKeyPtr //to our success SIMD_FORCE_INLINE unsigned int getHash()const { - int key = m_uid; + unsigned int key = m_uid; // Thomas Wang's hash key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); return key; @@ -206,7 +211,7 @@ class btHashKey //to our success SIMD_FORCE_INLINE unsigned int getHash()const { - int key = m_uid; + unsigned int key = m_uid; // Thomas Wang's hash key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); return key; @@ -384,17 +389,40 @@ class btHashMap const Value* getAtIndex(int index) const { btAssert(index < m_valueArray.size()); - - return &m_valueArray[index]; + btAssert(index>=0); + if (index>=0 && index < m_valueArray.size()) + { + return &m_valueArray[index]; + } + return 0; } Value* getAtIndex(int index) { btAssert(index < m_valueArray.size()); - - return &m_valueArray[index]; + btAssert(index>=0); + if (index>=0 && index < m_valueArray.size()) + { + return &m_valueArray[index]; + } + return 0; } + Key getKeyAtIndex(int index) + { + btAssert(index < m_keyArray.size()); + btAssert(index>=0); + return m_keyArray[index]; + } + + const Key getKeyAtIndex(int index) const + { + btAssert(index < m_keyArray.size()); + btAssert(index>=0); + return m_keyArray[index]; + } + + Value* operator[](const Key& key) { return find(key); } diff --git a/extern/bullet2/src/LinearMath/btIDebugDraw.h b/extern/bullet/src/LinearMath/btIDebugDraw.h similarity index 99% rename from extern/bullet2/src/LinearMath/btIDebugDraw.h rename to extern/bullet/src/LinearMath/btIDebugDraw.h index 58c9838c4903..936aaa896b07 100644 --- a/extern/bullet2/src/LinearMath/btIDebugDraw.h +++ b/extern/bullet/src/LinearMath/btIDebugDraw.h @@ -166,9 +166,9 @@ class btIDebugDraw virtual void drawTransform(const btTransform& transform, btScalar orthoLen) { btVector3 start = transform.getOrigin(); - drawLine(start, start+transform.getBasis() * btVector3(orthoLen, 0, 0), btVector3(0.7f,0,0)); - drawLine(start, start+transform.getBasis() * btVector3(0, orthoLen, 0), btVector3(0,0.7f,0)); - drawLine(start, start+transform.getBasis() * btVector3(0, 0, orthoLen), btVector3(0,0,0.7f)); + drawLine(start, start+transform.getBasis() * btVector3(orthoLen, 0, 0), btVector3(1.f,0.3,0.3)); + drawLine(start, start+transform.getBasis() * btVector3(0, orthoLen, 0), btVector3(0.3,1.f, 0.3)); + drawLine(start, start+transform.getBasis() * btVector3(0, 0, orthoLen), btVector3(0.3, 0.3,1.f)); } virtual void drawArc(const btVector3& center, const btVector3& normal, const btVector3& axis, btScalar radiusA, btScalar radiusB, btScalar minAngle, btScalar maxAngle, @@ -469,6 +469,10 @@ class btIDebugDraw drawLine(transform*pt2,transform*pt3,color); } + virtual void clearLines() + { + } + virtual void flushLines() { } diff --git a/extern/bullet2/src/LinearMath/btList.h b/extern/bullet/src/LinearMath/btList.h similarity index 100% rename from extern/bullet2/src/LinearMath/btList.h rename to extern/bullet/src/LinearMath/btList.h diff --git a/extern/bullet2/src/LinearMath/btMatrix3x3.h b/extern/bullet/src/LinearMath/btMatrix3x3.h similarity index 95% rename from extern/bullet2/src/LinearMath/btMatrix3x3.h rename to extern/bullet/src/LinearMath/btMatrix3x3.h index 41dea6948352..9f642a1779ae 100644 --- a/extern/bullet2/src/LinearMath/btMatrix3x3.h +++ b/extern/bullet/src/LinearMath/btMatrix3x3.h @@ -647,92 +647,49 @@ ATTRIBUTE_ALIGNED16(class) btMatrix3x3 { return m_el[0].z() * v.x() + m_el[1].z() * v.y() + m_el[2].z() * v.z(); } + ///extractRotation is from "A robust method to extract the rotational part of deformations" + ///See http://dl.acm.org/citation.cfm?doid=2994258.2994269 + SIMD_FORCE_INLINE void extractRotation(btQuaternion &q,btScalar tolerance = 1.0e-9, int maxIter=100) + { + int iter =0; + btScalar w; + const btMatrix3x3& A=*this; + for(iter = 0; iter < maxIter; iter++) + { + btMatrix3x3 R(q); + btVector3 omega = (R.getColumn(0).cross(A.getColumn(0)) + R.getColumn(1).cross(A.getColumn(1)) + + R.getColumn(2).cross(A.getColumn(2)) + ) * (btScalar(1.0) / btFabs(R.getColumn(0).dot(A.getColumn(0)) + R.getColumn + (1).dot(A.getColumn(1)) + R.getColumn(2).dot(A.getColumn(2))) + + tolerance); + w = omega.norm(); + if(w < tolerance) + break; + q = btQuaternion(btVector3((btScalar(1.0) / w) * omega),w) * + q; + q.normalize(); + } + } - /**@brief diagonalizes this matrix by the Jacobi method. + + + /**@brief diagonalizes this matrix * @param rot stores the rotation from the coordinate system in which the matrix is diagonal to the original * coordinate system, i.e., old_this = rot * new_this * rot^T. * @param threshold See iteration - * @param iteration The iteration stops when all off-diagonal elements are less than the threshold multiplied - * by the sum of the absolute values of the diagonal, or when maxSteps have been executed. - * - * Note that this matrix is assumed to be symmetric. + * @param maxIter The iteration stops when we hit the given tolerance or when maxIter have been executed. */ - void diagonalize(btMatrix3x3& rot, btScalar threshold, int maxSteps) + void diagonalize(btMatrix3x3& rot, btScalar tolerance = 1.0e-9, int maxIter=100) { - rot.setIdentity(); - for (int step = maxSteps; step > 0; step--) - { - // find off-diagonal element [p][q] with largest magnitude - int p = 0; - int q = 1; - int r = 2; - btScalar max = btFabs(m_el[0][1]); - btScalar v = btFabs(m_el[0][2]); - if (v > max) - { - q = 2; - r = 1; - max = v; - } - v = btFabs(m_el[1][2]); - if (v > max) - { - p = 1; - q = 2; - r = 0; - max = v; - } - - btScalar t = threshold * (btFabs(m_el[0][0]) + btFabs(m_el[1][1]) + btFabs(m_el[2][2])); - if (max <= t) - { - if (max <= SIMD_EPSILON * t) - { - return; - } - step = 1; - } - - // compute Jacobi rotation J which leads to a zero for element [p][q] - btScalar mpq = m_el[p][q]; - btScalar theta = (m_el[q][q] - m_el[p][p]) / (2 * mpq); - btScalar theta2 = theta * theta; - btScalar cos; - btScalar sin; - if (theta2 * theta2 < btScalar(10 / SIMD_EPSILON)) - { - t = (theta >= 0) ? 1 / (theta + btSqrt(1 + theta2)) - : 1 / (theta - btSqrt(1 + theta2)); - cos = 1 / btSqrt(1 + t * t); - sin = cos * t; - } - else - { - // approximation for large theta-value, i.e., a nearly diagonal matrix - t = 1 / (theta * (2 + btScalar(0.5) / theta2)); - cos = 1 - btScalar(0.5) * t * t; - sin = cos * t; - } - - // apply rotation to matrix (this = J^T * this * J) - m_el[p][q] = m_el[q][p] = 0; - m_el[p][p] -= t * mpq; - m_el[q][q] += t * mpq; - btScalar mrp = m_el[r][p]; - btScalar mrq = m_el[r][q]; - m_el[r][p] = m_el[p][r] = cos * mrp - sin * mrq; - m_el[r][q] = m_el[q][r] = cos * mrq + sin * mrp; - - // apply rotation to rot (rot = rot * J) - for (int i = 0; i < 3; i++) - { - btVector3& row = rot[i]; - mrp = row[p]; - mrq = row[q]; - row[p] = cos * mrp - sin * mrq; - row[q] = cos * mrq + sin * mrp; - } - } + btQuaternion r; + r = btQuaternion::getIdentity(); + extractRotation(r,tolerance,maxIter); + rot.setRotation(r); + btMatrix3x3 rotInv = btMatrix3x3(r.inverse()); + btMatrix3x3 old = *this; + setValue(old.tdotx( rotInv[0]), old.tdoty( rotInv[0]), old.tdotz( rotInv[0]), + old.tdotx( rotInv[1]), old.tdoty( rotInv[1]), old.tdotz( rotInv[1]), + old.tdotx( rotInv[2]), old.tdoty( rotInv[2]), old.tdotz( rotInv[2])); } @@ -1047,7 +1004,8 @@ 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)); + //btFullAssert(det != btScalar(0.0)); + btAssert(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, @@ -1329,7 +1287,9 @@ SIMD_FORCE_INLINE bool operator==(const btMatrix3x3& m1, const btMatrix3x3& m2) c0 = _mm_and_ps(c0, c1); c0 = _mm_and_ps(c0, c2); - return (0x7 == _mm_movemask_ps((__m128)c0)); + int m = _mm_movemask_ps((__m128)c0); + return (0x7 == (m & 0x7)); + #else return ( m1[0][0] == m2[0][0] && m1[1][0] == m2[1][0] && m1[2][0] == m2[2][0] && diff --git a/extern/bullet2/src/LinearMath/btMatrixX.h b/extern/bullet/src/LinearMath/btMatrixX.h similarity index 100% rename from extern/bullet2/src/LinearMath/btMatrixX.h rename to extern/bullet/src/LinearMath/btMatrixX.h diff --git a/extern/bullet2/src/LinearMath/btMinMax.h b/extern/bullet/src/LinearMath/btMinMax.h similarity index 100% rename from extern/bullet2/src/LinearMath/btMinMax.h rename to extern/bullet/src/LinearMath/btMinMax.h diff --git a/extern/bullet2/src/LinearMath/btMotionState.h b/extern/bullet/src/LinearMath/btMotionState.h similarity index 100% rename from extern/bullet2/src/LinearMath/btMotionState.h rename to extern/bullet/src/LinearMath/btMotionState.h diff --git a/extern/bullet2/src/LinearMath/btPolarDecomposition.cpp b/extern/bullet/src/LinearMath/btPolarDecomposition.cpp similarity index 94% rename from extern/bullet2/src/LinearMath/btPolarDecomposition.cpp rename to extern/bullet/src/LinearMath/btPolarDecomposition.cpp index a4dca7fdd401..b3664faa4ea1 100644 --- a/extern/bullet2/src/LinearMath/btPolarDecomposition.cpp +++ b/extern/bullet/src/LinearMath/btPolarDecomposition.cpp @@ -30,8 +30,7 @@ namespace } } -const btScalar btPolarDecomposition::DEFAULT_TOLERANCE = btScalar(0.0001); -const unsigned int btPolarDecomposition::DEFAULT_MAX_ITERATIONS = 16; + btPolarDecomposition::btPolarDecomposition(btScalar tolerance, unsigned int maxIterations) : m_tolerance(tolerance) diff --git a/extern/bullet2/src/LinearMath/btPolarDecomposition.h b/extern/bullet/src/LinearMath/btPolarDecomposition.h similarity index 91% rename from extern/bullet2/src/LinearMath/btPolarDecomposition.h rename to extern/bullet/src/LinearMath/btPolarDecomposition.h index 561566764153..1feea0f78e85 100644 --- a/extern/bullet2/src/LinearMath/btPolarDecomposition.h +++ b/extern/bullet/src/LinearMath/btPolarDecomposition.h @@ -14,8 +14,7 @@ class btPolarDecomposition { public: - static const btScalar DEFAULT_TOLERANCE; - static const unsigned int DEFAULT_MAX_ITERATIONS; + /** * Creates an instance with optional parameters. @@ -25,8 +24,8 @@ class btPolarDecomposition * @param maxIterations - the maximum number of iterations used to achieve * convergence */ - btPolarDecomposition(btScalar tolerance = DEFAULT_TOLERANCE, - unsigned int maxIterations = DEFAULT_MAX_ITERATIONS); + btPolarDecomposition(btScalar tolerance = btScalar(0.0001), + unsigned int maxIterations = 16); /** * Decomposes a matrix into orthogonal and symmetric, positive-definite diff --git a/extern/bullet2/src/LinearMath/btPoolAllocator.h b/extern/bullet/src/LinearMath/btPoolAllocator.h similarity index 87% rename from extern/bullet2/src/LinearMath/btPoolAllocator.h rename to extern/bullet/src/LinearMath/btPoolAllocator.h index ef2084537a2f..efdeda8ffc4a 100644 --- a/extern/bullet2/src/LinearMath/btPoolAllocator.h +++ b/extern/bullet/src/LinearMath/btPoolAllocator.h @@ -18,6 +18,7 @@ subject to the following restrictions: #include "btScalar.h" #include "btAlignedAllocator.h" +#include "btThreads.h" ///The btPoolAllocator class allows to efficiently allocate a large pool of objects, instead of dynamically allocating them separately. class btPoolAllocator @@ -27,6 +28,7 @@ class btPoolAllocator int m_freeCount; void* m_firstFree; unsigned char* m_pool; + btSpinMutex m_mutex; // only used if BT_THREADSAFE public: @@ -71,11 +73,16 @@ class btPoolAllocator { // release mode fix (void)size; + btMutexLock(&m_mutex); btAssert(!size || size<=m_elemSize); - btAssert(m_freeCount>0); + //btAssert(m_freeCount>0); // should return null if all full void* result = m_firstFree; - m_firstFree = *(void**)m_firstFree; - --m_freeCount; + if (NULL != m_firstFree) + { + m_firstFree = *(void**)m_firstFree; + --m_freeCount; + } + btMutexUnlock(&m_mutex); return result; } @@ -95,9 +102,11 @@ class btPoolAllocator if (ptr) { btAssert((unsigned char*)ptr >= m_pool && (unsigned char*)ptr < m_pool + m_maxElements * m_elemSize); + btMutexLock(&m_mutex); *(void**)ptr = m_firstFree; m_firstFree = ptr; ++m_freeCount; + btMutexUnlock(&m_mutex); } } diff --git a/extern/bullet2/src/LinearMath/btQuadWord.h b/extern/bullet/src/LinearMath/btQuadWord.h similarity index 100% rename from extern/bullet2/src/LinearMath/btQuadWord.h rename to extern/bullet/src/LinearMath/btQuadWord.h diff --git a/extern/bullet2/src/LinearMath/btQuaternion.h b/extern/bullet/src/LinearMath/btQuaternion.h similarity index 92% rename from extern/bullet2/src/LinearMath/btQuaternion.h rename to extern/bullet/src/LinearMath/btQuaternion.h index ede76938404f..7bd39e6a3316 100644 --- a/extern/bullet2/src/LinearMath/btQuaternion.h +++ b/extern/bullet/src/LinearMath/btQuaternion.h @@ -141,11 +141,11 @@ class btQuaternion : public btQuadWord { * @param yaw Angle around Z * @param pitch Angle around Y * @param roll Angle around X */ - void setEulerZYX(const btScalar& yaw, const btScalar& pitch, const btScalar& roll) + void setEulerZYX(const btScalar& yawZ, const btScalar& pitchY, const btScalar& rollX) { - btScalar halfYaw = btScalar(yaw) * btScalar(0.5); - btScalar halfPitch = btScalar(pitch) * btScalar(0.5); - btScalar halfRoll = btScalar(roll) * btScalar(0.5); + btScalar halfYaw = btScalar(yawZ) * btScalar(0.5); + btScalar halfPitch = btScalar(pitchY) * btScalar(0.5); + btScalar halfRoll = btScalar(rollX) * btScalar(0.5); btScalar cosYaw = btCos(halfYaw); btScalar sinYaw = btSin(halfYaw); btScalar cosPitch = btCos(halfPitch); @@ -157,6 +157,28 @@ class btQuaternion : public btQuadWord { cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw, //z cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw); //formerly yzx } + + /**@brief Get the euler angles from this quaternion + * @param yaw Angle around Z + * @param pitch Angle around Y + * @param roll Angle around X */ + void getEulerZYX(btScalar& yawZ, btScalar& pitchY, btScalar& rollX) const + { + btScalar squ; + btScalar sqx; + btScalar sqy; + btScalar sqz; + btScalar sarg; + sqx = m_floats[0] * m_floats[0]; + sqy = m_floats[1] * m_floats[1]; + sqz = m_floats[2] * m_floats[2]; + squ = m_floats[3] * m_floats[3]; + rollX = btAtan2(2 * (m_floats[1] * m_floats[2] + m_floats[3] * m_floats[0]), squ - sqx - sqy + sqz); + sarg = btScalar(-2.) * (m_floats[0] * m_floats[2] - m_floats[3] * m_floats[1]); + pitchY = sarg <= btScalar(-1.0) ? btScalar(-0.5) * SIMD_PI: (sarg >= btScalar(1.0) ? btScalar(0.5) * SIMD_PI : btAsin(sarg)); + yawZ = btAtan2(2 * (m_floats[0] * m_floats[1] + m_floats[3] * m_floats[2]), squ + sqx - sqy - sqz); + } + /**@brief Add two quaternions * @param q The quaternion to add to this one */ SIMD_FORCE_INLINE btQuaternion& operator+=(const btQuaternion& q) @@ -333,7 +355,15 @@ class btQuaternion : public btQuadWord { { return btSqrt(length2()); } - + btQuaternion& safeNormalize() + { + btScalar l2 = length2(); + if (l2>SIMD_EPSILON) + { + normalize(); + } + return *this; + } /**@brief Normalize the quaternion * Such that x^2 + y^2 + z^2 +w^2 = 1 */ btQuaternion& normalize() @@ -418,22 +448,21 @@ class btQuaternion : public btQuadWord { return btAcos(dot(q) / s) * btScalar(2.0); } - /**@brief Return the angle of rotation represented by this quaternion */ + /**@brief Return the angle [0, 2Pi] of rotation represented by this quaternion */ btScalar getAngle() const { btScalar s = btScalar(2.) * btAcos(m_floats[3]); return s; } - /**@brief Return the angle of rotation represented by this quaternion along the shortest path*/ + /**@brief Return the angle [0, Pi] of rotation represented by this quaternion along the shortest path */ btScalar getAngleShortestPath() const { btScalar s; - if (dot(*this) < 0) + if (m_floats[3] >= 0) s = btScalar(2.) * btAcos(m_floats[3]); else s = btScalar(2.) * btAcos(-m_floats[3]); - return s; } @@ -533,25 +562,29 @@ class btQuaternion : public btQuadWord { * Slerp interpolates assuming constant velocity. */ btQuaternion slerp(const btQuaternion& q, const btScalar& t) const { - btScalar magnitude = btSqrt(length2() * q.length2()); - btAssert(magnitude > btScalar(0)); - btScalar product = dot(q) / magnitude; - if (btFabs(product) < btScalar(1)) + const btScalar magnitude = btSqrt(length2() * q.length2()); + btAssert(magnitude > btScalar(0)); + + const btScalar product = dot(q) / magnitude; + const btScalar absproduct = btFabs(product); + + if(absproduct < btScalar(1.0 - SIMD_EPSILON)) { - // Take care of long angle case see http://en.wikipedia.org/wiki/Slerp - const btScalar sign = (product < 0) ? btScalar(-1) : btScalar(1); - - const btScalar theta = btAcos(sign * product); - const btScalar s1 = btSin(sign * t * theta); - const btScalar d = btScalar(1.0) / btSin(theta); - const btScalar s0 = btSin((btScalar(1.0) - t) * theta); - - return btQuaternion( - (m_floats[0] * s0 + q.x() * s1) * d, - (m_floats[1] * s0 + q.y() * s1) * d, - (m_floats[2] * s0 + q.z() * s1) * d, - (m_floats[3] * s0 + q.m_floats[3] * s1) * d); + // Take care of long angle case see http://en.wikipedia.org/wiki/Slerp + const btScalar theta = btAcos(absproduct); + const btScalar d = btSin(theta); + btAssert(d > btScalar(0)); + + const btScalar sign = (product < 0) ? btScalar(-1) : btScalar(1); + const btScalar s0 = btSin((btScalar(1.0) - t) * theta) / d; + const btScalar s1 = btSin(sign * t * theta) / d; + + return btQuaternion( + (m_floats[0] * s0 + q.x() * s1), + (m_floats[1] * s0 + q.y() * s1), + (m_floats[2] * s0 + q.z() * s1), + (m_floats[3] * s0 + q.w() * s1)); } else { diff --git a/extern/bullet2/src/LinearMath/btQuickprof.cpp b/extern/bullet/src/LinearMath/btQuickprof.cpp similarity index 63% rename from extern/bullet2/src/LinearMath/btQuickprof.cpp rename to extern/bullet/src/LinearMath/btQuickprof.cpp index d88d965a4cc4..aed3104a6e25 100644 --- a/extern/bullet2/src/LinearMath/btQuickprof.cpp +++ b/extern/bullet/src/LinearMath/btQuickprof.cpp @@ -14,11 +14,9 @@ // Ogre (www.ogre3d.org). #include "btQuickprof.h" - -#ifndef BT_NO_PROFILE +#include "btThreads.h" -static btClock gProfileClock; #ifdef __CELLOS_LV2__ @@ -30,6 +28,10 @@ static btClock gProfileClock; #if defined (SUNOS) || defined (__SUNOS__) #include #endif +#ifdef __APPLE__ +#include +#include +#endif #if defined(WIN32) || defined(_WIN32) @@ -55,6 +57,12 @@ static btClock gProfileClock; #else //_WIN32 #include + +#ifdef BT_LINUX_REALTIME +//required linking against rt (librt) +#include +#endif //BT_LINUX_REALTIME + #endif //_WIN32 #define mymin(a,b) (a > b ? a : b) @@ -65,12 +73,14 @@ struct btClockData #ifdef BT_USE_WINDOWS_TIMERS LARGE_INTEGER mClockFrequency; LONGLONG mStartTick; - LONGLONG mPrevElapsedTime; LARGE_INTEGER mStartTime; #else #ifdef __CELLOS_LV2__ uint64_t mStartTime; #else +#ifdef __APPLE__ + uint64_t mStartTimeNano; +#endif struct timeval mStartTime; #endif #endif //__CELLOS_LV2__ @@ -111,7 +121,6 @@ void btClock::reset() #ifdef BT_USE_WINDOWS_TIMERS QueryPerformanceCounter(&m_data->mStartTime); m_data->mStartTick = GetTickCount64(); - m_data->mPrevElapsedTime = 0; #else #ifdef __CELLOS_LV2__ @@ -121,6 +130,9 @@ void btClock::reset() SYS_TIMEBASE_GET( newTime ); m_data->mStartTime = newTime; #else +#ifdef __APPLE__ + m_data->mStartTimeNano = mach_absolute_time(); +#endif gettimeofday(&m_data->mStartTime, 0); #endif #endif @@ -128,7 +140,7 @@ void btClock::reset() /// Returns the time in ms since the last call to reset or since /// the btClock was created. -unsigned long int btClock::getTimeMilliseconds() +unsigned long long int btClock::getTimeMilliseconds() { #ifdef BT_USE_WINDOWS_TIMERS LARGE_INTEGER currentTime; @@ -138,27 +150,6 @@ unsigned long int btClock::getTimeMilliseconds() // Compute the number of millisecond ticks elapsed. unsigned long msecTicks = (unsigned long)(1000 * elapsedTime / m_data->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 = (unsigned long)(GetTickCount64() - m_data->mStartTick); - signed long msecOff = (signed long)(msecTicks - elapsedTicks); - if (msecOff < -100 || msecOff > 100) - { - // Adjust the starting time forwards. - LONGLONG msecAdjustment = mymin(msecOff * - m_data->mClockFrequency.QuadPart / 1000, elapsedTime - - m_data->mPrevElapsedTime); - m_data->mStartTime.QuadPart += msecAdjustment; - elapsedTime -= msecAdjustment; - - // Recompute the number of millisecond ticks elapsed. - msecTicks = (unsigned long)(1000 * elapsedTime / - m_data->mClockFrequency.QuadPart); - } - - // Store the current elapsed time for adjustments next time. - m_data->mPrevElapsedTime = elapsedTime; return msecTicks; #else @@ -184,41 +175,19 @@ unsigned long int btClock::getTimeMilliseconds() /// Returns the time in us since the last call to reset or since /// the Clock was created. -unsigned long int btClock::getTimeMicroseconds() +unsigned long long int btClock::getTimeMicroseconds() { #ifdef BT_USE_WINDOWS_TIMERS - LARGE_INTEGER currentTime; + //see https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx + LARGE_INTEGER currentTime, elapsedTime; + QueryPerformanceCounter(¤tTime); - LONGLONG elapsedTime = currentTime.QuadPart - + elapsedTime.QuadPart = currentTime.QuadPart - m_data->mStartTime.QuadPart; + elapsedTime.QuadPart *= 1000000; + elapsedTime.QuadPart /= m_data->mClockFrequency.QuadPart; - // Compute the number of millisecond ticks elapsed. - unsigned long msecTicks = (unsigned long)(1000 * elapsedTime / - m_data->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 = (unsigned long)(GetTickCount64() - m_data->mStartTick); - signed long msecOff = (signed long)(msecTicks - elapsedTicks); - if (msecOff < -100 || msecOff > 100) - { - // Adjust the starting time forwards. - LONGLONG msecAdjustment = mymin(msecOff * - m_data->mClockFrequency.QuadPart / 1000, elapsedTime - - m_data->mPrevElapsedTime); - m_data->mStartTime.QuadPart += msecAdjustment; - elapsedTime -= msecAdjustment; - } - - // Store the current elapsed time for adjustments next time. - m_data->mPrevElapsedTime = elapsedTime; - - // Convert to microseconds. - unsigned long usecTicks = (unsigned long)(1000000 * elapsedTime / - m_data->mClockFrequency.QuadPart); - - return usecTicks; + return (unsigned long long) elapsedTime.QuadPart; #else #ifdef __CELLOS_LV2__ @@ -240,6 +209,66 @@ unsigned long int btClock::getTimeMicroseconds() #endif } +unsigned long long int btClock::getTimeNanoseconds() +{ +#ifdef BT_USE_WINDOWS_TIMERS + //see https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx + LARGE_INTEGER currentTime, elapsedTime; + + QueryPerformanceCounter(¤tTime); + elapsedTime.QuadPart = currentTime.QuadPart - + m_data->mStartTime.QuadPart; + elapsedTime.QuadPart *= 1000000000; + elapsedTime.QuadPart /= m_data->mClockFrequency.QuadPart; + + return (unsigned long long) elapsedTime.QuadPart; +#else + +#ifdef __CELLOS_LV2__ + uint64_t freq=sys_time_get_timebase_frequency(); + double dFreq=((double) freq)/ 1e9; + typedef uint64_t ClockSize; + ClockSize newTime; + //__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory"); + SYS_TIMEBASE_GET( newTime ); + + return (unsigned long int)((double(newTime-m_data->mStartTime)) / dFreq); +#else +#ifdef __APPLE__ + uint64_t ticks = mach_absolute_time() - m_data->mStartTimeNano; + static long double conversion = 0.0L; + if( 0.0L == conversion ) + { + // attempt to get conversion to nanoseconds + mach_timebase_info_data_t info; + int err = mach_timebase_info( &info ); + if( err ) + { + btAssert(0); + conversion = 1.; + } + conversion = info.numer / info.denom; + } + return (ticks * conversion); + + +#else//__APPLE__ + +#ifdef BT_LINUX_REALTIME + timespec ts; + clock_gettime(CLOCK_REALTIME,&ts); + return 1000000000*ts.tv_sec + ts.tv_nsec; +#else + struct timeval currentTime; + gettimeofday(¤tTime, 0); + return (currentTime.tv_sec - m_data->mStartTime.tv_sec) * 1e9 + + (currentTime.tv_usec - m_data->mStartTime.tv_usec)*1000; +#endif //BT_LINUX_REALTIME + +#endif//__APPLE__ +#endif//__CELLOS_LV2__ +#endif +} /// Returns the time in s since the last call to reset or since @@ -250,11 +279,15 @@ btScalar btClock::getTimeSeconds() return btScalar(getTimeMicroseconds()) * microseconds_to_seconds; } +#ifndef BT_NO_PROFILE + + +static btClock gProfileClock; inline void Profile_Get_Ticks(unsigned long int * ticks) { - *ticks = gProfileClock.getTimeMicroseconds(); + *ticks = (unsigned long int)gProfileClock.getTimeMicroseconds(); } inline float Profile_Get_Tick_Rate(void) @@ -265,7 +298,6 @@ inline float Profile_Get_Tick_Rate(void) } - /*************************************************************************************************** ** ** CProfileNode @@ -367,6 +399,7 @@ bool CProfileNode::Return( void ) if ( --RecursionCounter == 0 && TotalCalls != 0 ) { unsigned long int time; Profile_Get_Ticks(&time); + time-=StartTime; TotalTime += (float)time / Profile_Get_Tick_Rate(); } @@ -434,11 +467,71 @@ void CProfileIterator::Enter_Parent( void ) ** ***************************************************************************************************/ -CProfileNode CProfileManager::Root( "Root", NULL ); -CProfileNode * CProfileManager::CurrentNode = &CProfileManager::Root; + + + +CProfileNode gRoots[BT_QUICKPROF_MAX_THREAD_COUNT]={ + CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), + CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), + CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), + CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), + CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), + CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), + CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), + CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), + CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), + CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), + CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), + CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), + CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), + CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), + CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL), + CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL),CProfileNode("Root",NULL) +}; + + +CProfileNode* gCurrentNodes[BT_QUICKPROF_MAX_THREAD_COUNT]= +{ + &gRoots[ 0], &gRoots[ 1], &gRoots[ 2], &gRoots[ 3], + &gRoots[ 4], &gRoots[ 5], &gRoots[ 6], &gRoots[ 7], + &gRoots[ 8], &gRoots[ 9], &gRoots[10], &gRoots[11], + &gRoots[12], &gRoots[13], &gRoots[14], &gRoots[15], + &gRoots[16], &gRoots[17], &gRoots[18], &gRoots[19], + &gRoots[20], &gRoots[21], &gRoots[22], &gRoots[23], + &gRoots[24], &gRoots[25], &gRoots[26], &gRoots[27], + &gRoots[28], &gRoots[29], &gRoots[30], &gRoots[31], + &gRoots[32], &gRoots[33], &gRoots[34], &gRoots[35], + &gRoots[36], &gRoots[37], &gRoots[38], &gRoots[39], + &gRoots[40], &gRoots[41], &gRoots[42], &gRoots[43], + &gRoots[44], &gRoots[45], &gRoots[46], &gRoots[47], + &gRoots[48], &gRoots[49], &gRoots[50], &gRoots[51], + &gRoots[52], &gRoots[53], &gRoots[54], &gRoots[55], + &gRoots[56], &gRoots[57], &gRoots[58], &gRoots[59], + &gRoots[60], &gRoots[61], &gRoots[62], &gRoots[63], +}; + + int CProfileManager::FrameCounter = 0; unsigned long int CProfileManager::ResetTime = 0; +CProfileIterator * CProfileManager::Get_Iterator( void ) +{ + + int threadIndex = btQuickprofGetCurrentThreadIndex2(); + if ((threadIndex<0) || threadIndex >= BT_QUICKPROF_MAX_THREAD_COUNT) + return 0; + + return new CProfileIterator( &gRoots[threadIndex]); +} + +void CProfileManager::CleanupMemory(void) +{ + for (int i=0;iGet_Name()) { - CurrentNode = CurrentNode->Get_Sub_Node( name ); + int threadIndex = btQuickprofGetCurrentThreadIndex2(); + if ((threadIndex<0) || threadIndex >= BT_QUICKPROF_MAX_THREAD_COUNT) + return; + + if (name != gCurrentNodes[threadIndex]->Get_Name()) { + gCurrentNodes[threadIndex] = gCurrentNodes[threadIndex]->Get_Sub_Node( name ); } - CurrentNode->Call(); + gCurrentNodes[threadIndex]->Call(); } @@ -468,14 +565,22 @@ void CProfileManager::Start_Profile( const char * name ) *=============================================================================================*/ void CProfileManager::Stop_Profile( void ) { + int threadIndex = btQuickprofGetCurrentThreadIndex2(); + if ((threadIndex<0) || threadIndex >= BT_QUICKPROF_MAX_THREAD_COUNT) + return; + // Return will indicate whether we should back up to our parent (we may // be profiling a recursive function) - if (CurrentNode->Return()) { - CurrentNode = CurrentNode->Get_Parent(); + if (gCurrentNodes[threadIndex]->Return()) { + gCurrentNodes[threadIndex] = gCurrentNodes[threadIndex]->Get_Parent(); } } + + + + /*********************************************************************************************** * CProfileManager::Reset -- Reset the contents of the profiling system * * * @@ -484,8 +589,11 @@ void CProfileManager::Stop_Profile( void ) void CProfileManager::Reset( void ) { gProfileClock.reset(); - Root.Reset(); - Root.Call(); + int threadIndex = btQuickprofGetCurrentThreadIndex2(); + if ((threadIndex<0) || threadIndex >= BT_QUICKPROF_MAX_THREAD_COUNT) + return; + gRoots[threadIndex].Reset(); + gRoots[threadIndex].Call(); FrameCounter = 0; Profile_Get_Ticks(&ResetTime); } @@ -575,4 +683,107 @@ void CProfileManager::dumpAll() +unsigned int btQuickprofGetCurrentThreadIndex2() +{ +#if BT_THREADSAFE + return btGetCurrentThreadIndex(); +#else // #if BT_THREADSAFE + const unsigned int kNullIndex = ~0U; +#ifdef _WIN32 + #if defined(__MINGW32__) || defined(__MINGW64__) + static __thread unsigned int sThreadIndex = kNullIndex; + #else + __declspec( thread ) static unsigned int sThreadIndex = kNullIndex; + #endif +#else +#ifdef __APPLE__ + #if TARGET_OS_IPHONE + unsigned int sThreadIndex = 0; + return -1; + #else + static __thread unsigned int sThreadIndex = kNullIndex; + #endif +#else//__APPLE__ +#if __linux__ + static __thread unsigned int sThreadIndex = kNullIndex; +#else + unsigned int sThreadIndex = 0; + return -1; +#endif +#endif//__APPLE__ + +#endif + static int gThreadCounter=0; + + if ( sThreadIndex == kNullIndex ) + { + sThreadIndex = gThreadCounter++; + } + return sThreadIndex; +#endif // #else // #if BT_THREADSAFE +} + +void btEnterProfileZoneDefault(const char* name) +{ + CProfileManager::Start_Profile( name ); +} +void btLeaveProfileZoneDefault() +{ + CProfileManager::Stop_Profile(); +} + + +#else +void btEnterProfileZoneDefault(const char* name) +{ +} +void btLeaveProfileZoneDefault() +{ +} #endif //BT_NO_PROFILE + + + + + +static btEnterProfileZoneFunc* bts_enterFunc = btEnterProfileZoneDefault; +static btLeaveProfileZoneFunc* bts_leaveFunc = btLeaveProfileZoneDefault; + +void btEnterProfileZone(const char* name) +{ + (bts_enterFunc)(name); +} +void btLeaveProfileZone() +{ + (bts_leaveFunc)(); +} + +btEnterProfileZoneFunc* btGetCurrentEnterProfileZoneFunc() +{ + return bts_enterFunc ; +} +btLeaveProfileZoneFunc* btGetCurrentLeaveProfileZoneFunc() +{ + return bts_leaveFunc; +} + + +void btSetCustomEnterProfileZoneFunc(btEnterProfileZoneFunc* enterFunc) +{ + bts_enterFunc = enterFunc; +} +void btSetCustomLeaveProfileZoneFunc(btLeaveProfileZoneFunc* leaveFunc) +{ + bts_leaveFunc = leaveFunc; +} + +CProfileSample::CProfileSample( const char * name ) +{ + btEnterProfileZone(name); +} + +CProfileSample::~CProfileSample( void ) +{ + btLeaveProfileZone(); +} + diff --git a/extern/bullet2/src/LinearMath/btQuickprof.h b/extern/bullet/src/LinearMath/btQuickprof.h similarity index 81% rename from extern/bullet2/src/LinearMath/btQuickprof.h rename to extern/bullet/src/LinearMath/btQuickprof.h index 362f62d6d400..7b38d71b90db 100644 --- a/extern/bullet2/src/LinearMath/btQuickprof.h +++ b/extern/bullet/src/LinearMath/btQuickprof.h @@ -15,18 +15,7 @@ #ifndef BT_QUICK_PROF_H #define BT_QUICK_PROF_H -//To disable built-in profiling, please comment out next line -//#define BT_NO_PROFILE 1 -#ifndef BT_NO_PROFILE -#include //@todo remove this, backwards compatibility #include "btScalar.h" -#include "btAlignedAllocator.h" -#include - - - - - #define USE_BT_CLOCK 1 #ifdef USE_BT_CLOCK @@ -47,12 +36,14 @@ class btClock /// Returns the time in ms since the last call to reset or since /// the btClock was created. - unsigned long int getTimeMilliseconds(); + unsigned long long int getTimeMilliseconds(); /// Returns the time in us since the last call to reset or since /// the Clock was created. - unsigned long int getTimeMicroseconds(); + unsigned long long int getTimeMicroseconds(); + unsigned long long int getTimeNanoseconds(); + /// Returns the time in s since the last call to reset or since /// the Clock was created. btScalar getTimeSeconds(); @@ -63,6 +54,38 @@ class btClock #endif //USE_BT_CLOCK +typedef void (btEnterProfileZoneFunc)(const char* msg); +typedef void (btLeaveProfileZoneFunc)(); + +btEnterProfileZoneFunc* btGetCurrentEnterProfileZoneFunc(); +btLeaveProfileZoneFunc* btGetCurrentLeaveProfileZoneFunc(); + + + +void btSetCustomEnterProfileZoneFunc(btEnterProfileZoneFunc* enterFunc); +void btSetCustomLeaveProfileZoneFunc(btLeaveProfileZoneFunc* leaveFunc); + +#ifndef BT_NO_PROFILE // FIX redefinition +//To disable built-in profiling, please comment out next line +//#define BT_NO_PROFILE 1 +#endif //BT_NO_PROFILE + +#ifndef BT_NO_PROFILE +//btQuickprofGetCurrentThreadIndex will return -1 if thread index cannot be determined, +//otherwise returns thread index in range [0..maxThreads] +unsigned int btQuickprofGetCurrentThreadIndex2(); +const unsigned int BT_QUICKPROF_MAX_THREAD_COUNT = 64; + +#include //@todo remove this, backwards compatibility + +#include "btAlignedAllocator.h" +#include + + + + + + @@ -148,21 +171,21 @@ class CProfileManager { static void Start_Profile( const char * name ); static void Stop_Profile( void ); - static void CleanupMemory(void) - { - Root.CleanupMemory(); - } + static void CleanupMemory(void); +// { +// Root.CleanupMemory(); +// } static void Reset( void ); static void Increment_Frame_Counter( void ); static int Get_Frame_Count_Since_Reset( void ) { return FrameCounter; } static float Get_Time_Since_Reset( void ); - static CProfileIterator * Get_Iterator( void ) - { - - return new CProfileIterator( &Root ); - } + static CProfileIterator * Get_Iterator( void ); +// { +// +// return new CProfileIterator( &Root ); +// } static void Release_Iterator( CProfileIterator * iterator ) { delete ( iterator); } static void dumpRecursive(CProfileIterator* profileIterator, int spacing); @@ -170,37 +193,27 @@ class CProfileManager { static void dumpAll(); private: - static CProfileNode Root; - static CProfileNode * CurrentNode; + static int FrameCounter; static unsigned long int ResetTime; }; + + +#endif //#ifndef BT_NO_PROFILE + ///ProfileSampleClass is a simple way to profile a function's scope ///Use the BT_PROFILE macro at the start of scope to time class CProfileSample { public: - CProfileSample( const char * name ) - { - CProfileManager::Start_Profile( name ); - } - - ~CProfileSample( void ) - { - CProfileManager::Stop_Profile(); - } -}; + CProfileSample( const char * name ); + ~CProfileSample( void ); +}; #define BT_PROFILE( name ) CProfileSample __profile( name ) -#else - -#define BT_PROFILE( name ) - -#endif //#ifndef BT_NO_PROFILE - #endif //BT_QUICK_PROF_H diff --git a/extern/bullet2/src/LinearMath/btRandom.h b/extern/bullet/src/LinearMath/btRandom.h similarity index 100% rename from extern/bullet2/src/LinearMath/btRandom.h rename to extern/bullet/src/LinearMath/btRandom.h diff --git a/extern/bullet/src/LinearMath/btScalar.h b/extern/bullet/src/LinearMath/btScalar.h new file mode 100644 index 000000000000..47b00385057b --- /dev/null +++ b/extern/bullet/src/LinearMath/btScalar.h @@ -0,0 +1,813 @@ +/* +Copyright (c) 2003-2009 Erwin Coumans http://bullet.googlecode.com + +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_SCALAR_H +#define BT_SCALAR_H +#if defined(_MSC_VER) && defined(__clang__) /* clang supplies it's own overloads already */ +#define BT_NO_SIMD_OPERATOR_OVERLOADS +#endif + +#ifdef BT_MANAGED_CODE +//Aligned data types not supported in managed code +#pragma unmanaged +#endif + +#include +#include //size_t for MSVC 6.0 +#include + +/* SVN $Revision$ on $Date$ from http://bullet.googlecode.com*/ +#define BT_BULLET_VERSION 287 + +inline int btGetVersion() +{ + return BT_BULLET_VERSION; +} + + +// The following macro "BT_NOT_EMPTY_FILE" can be put into a file +// in order suppress the MS Visual C++ Linker warning 4221 +// +// warning LNK4221: no public symbols found; archive member will be inaccessible +// +// This warning occurs on PC and XBOX when a file compiles out completely +// has no externally visible symbols which may be dependant on configuration +// #defines and options. +// +// see more https://stackoverflow.com/questions/1822887/what-is-the-best-way-to-eliminate-ms-visual-c-linker-warning-warning-lnk422 + +#if defined (_MSC_VER) + #define BT_NOT_EMPTY_FILE_CAT_II(p, res) res + #define BT_NOT_EMPTY_FILE_CAT_I(a, b) BT_NOT_EMPTY_FILE_CAT_II(~, a ## b) + #define BT_NOT_EMPTY_FILE_CAT(a, b) BT_NOT_EMPTY_FILE_CAT_I(a, b) + #define BT_NOT_EMPTY_FILE namespace { char BT_NOT_EMPTY_FILE_CAT(NoEmptyFileDummy, __COUNTER__); } +#else + #define BT_NOT_EMPTY_FILE +#endif + + +// clang and most formatting tools don't support indentation of preprocessor guards, so turn it off +// clang-format off +#if defined(DEBUG) || defined (_DEBUG) + #define BT_DEBUG +#endif + +#ifdef _WIN32 + #if defined(__MINGW32__) || defined(__CYGWIN__) || (defined (_MSC_VER) && _MSC_VER < 1300) + #define SIMD_FORCE_INLINE inline + #define ATTRIBUTE_ALIGNED16(a) a + #define ATTRIBUTE_ALIGNED64(a) a + #define ATTRIBUTE_ALIGNED128(a) a + #elif defined(_M_ARM) + #define SIMD_FORCE_INLINE __forceinline + #define ATTRIBUTE_ALIGNED16(a) __declspec() a + #define ATTRIBUTE_ALIGNED64(a) __declspec() a + #define ATTRIBUTE_ALIGNED128(a) __declspec () a + #else//__MINGW32__ + //#define BT_HAS_ALIGNED_ALLOCATOR + #pragma warning(disable : 4324) // disable padding warning +// #pragma warning(disable:4530) // Disable the exception disable but used in MSCV Stl warning. + #pragma warning(disable:4996) //Turn off warnings about deprecated C routines +// #pragma warning(disable:4786) // Disable the "debug name too long" warning + + #define SIMD_FORCE_INLINE __forceinline + #define ATTRIBUTE_ALIGNED16(a) __declspec(align(16)) a + #define ATTRIBUTE_ALIGNED64(a) __declspec(align(64)) a + #define ATTRIBUTE_ALIGNED128(a) __declspec (align(128)) a + #ifdef _XBOX + #define BT_USE_VMX128 + + #include + #define BT_HAVE_NATIVE_FSEL + #define btFsel(a,b,c) __fsel((a),(b),(c)) + #else + +#if defined (_M_ARM) + //Do not turn SSE on for ARM (may want to turn on BT_USE_NEON however) +#elif (defined (_WIN32) && (_MSC_VER) && _MSC_VER >= 1400) && (!defined (BT_USE_DOUBLE_PRECISION)) + #if _MSC_VER>1400 + #define BT_USE_SIMD_VECTOR3 + #endif + + #define BT_USE_SSE + #ifdef BT_USE_SSE + +#if (_MSC_FULL_VER >= 170050727)//Visual Studio 2012 can compile SSE4/FMA3 (but SSE4/FMA3 is not enabled by default) + //#define BT_ALLOW_SSE4 //disable this cause blender targets sse2 +#endif //(_MSC_FULL_VER >= 160040219) + + //BT_USE_SSE_IN_API is disabled under Windows by default, because + //it makes it harder to integrate Bullet into your application under Windows + //(structured embedding Bullet structs/classes need to be 16-byte aligned) + //with relatively little performance gain + //If you are not embedded Bullet data in your classes, or make sure that you align those classes on 16-byte boundaries + //you can manually enable this line or set it in the build system for a bit of performance gain (a few percent, dependent on usage) + //#define BT_USE_SSE_IN_API + #endif //BT_USE_SSE + #include +#endif + + #endif//_XBOX + + #endif //__MINGW32__ + + #ifdef BT_DEBUG + #ifdef _MSC_VER + #include + #define btAssert(x) { if(!(x)){printf("Assert "__FILE__ ":%u (%s)\n", __LINE__, #x);__debugbreak(); }} + #else//_MSC_VER + #include + #define btAssert assert + #endif//_MSC_VER + #else + #define btAssert(x) + #endif + //btFullAssert is optional, slows down a lot + #define btFullAssert(x) + + #define btLikely(_c) _c + #define btUnlikely(_c) _c + +#else//_WIN32 + + #if defined (__CELLOS_LV2__) + #define SIMD_FORCE_INLINE inline __attribute__((always_inline)) + #define ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16))) + #define ATTRIBUTE_ALIGNED64(a) a __attribute__ ((aligned (64))) + #define ATTRIBUTE_ALIGNED128(a) a __attribute__ ((aligned (128))) + #ifndef assert + #include + #endif + #ifdef BT_DEBUG + #ifdef __SPU__ + #include + #define printf spu_printf + #define btAssert(x) {if(!(x)){printf("Assert "__FILE__ ":%u ("#x")\n", __LINE__);spu_hcmpeq(0,0);}} + #else + #define btAssert assert + #endif + + #else//BT_DEBUG + #define btAssert(x) + #endif//BT_DEBUG + //btFullAssert is optional, slows down a lot + #define btFullAssert(x) + + #define btLikely(_c) _c + #define btUnlikely(_c) _c + + #else//defined (__CELLOS_LV2__) + + #ifdef USE_LIBSPE2 + + #define SIMD_FORCE_INLINE __inline + #define ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16))) + #define ATTRIBUTE_ALIGNED64(a) a __attribute__ ((aligned (64))) + #define ATTRIBUTE_ALIGNED128(a) a __attribute__ ((aligned (128))) + #ifndef assert + #include + #endif + #ifdef BT_DEBUG + #define btAssert assert + #else + #define btAssert(x) + #endif + //btFullAssert is optional, slows down a lot + #define btFullAssert(x) + + + #define btLikely(_c) __builtin_expect((_c), 1) + #define btUnlikely(_c) __builtin_expect((_c), 0) + + + #else//USE_LIBSPE2 + //non-windows systems + + #if (defined (__APPLE__) && (!defined (BT_USE_DOUBLE_PRECISION))) + #if defined (__i386__) || defined (__x86_64__) + #define BT_USE_SIMD_VECTOR3 + #define BT_USE_SSE + //BT_USE_SSE_IN_API is enabled on Mac OSX by default, because memory is automatically aligned on 16-byte boundaries + //if apps run into issues, we will disable the next line + #define BT_USE_SSE_IN_API + #ifdef BT_USE_SSE + // include appropriate SSE level + #if defined (__SSE4_1__) + #include + #elif defined (__SSSE3__) + #include + #elif defined (__SSE3__) + #include + #else + #include + #endif + #endif //BT_USE_SSE + #elif defined( __ARM_NEON__ ) + #ifdef __clang__ + #define BT_USE_NEON 1 + #define BT_USE_SIMD_VECTOR3 + + #if defined BT_USE_NEON && defined (__clang__) + #include + #endif//BT_USE_NEON + #endif //__clang__ + #endif//__arm__ + + #define SIMD_FORCE_INLINE inline __attribute__ ((always_inline)) + ///@todo: check out alignment methods for other platforms/compilers + #define ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16))) + #define ATTRIBUTE_ALIGNED64(a) a __attribute__ ((aligned (64))) + #define ATTRIBUTE_ALIGNED128(a) a __attribute__ ((aligned (128))) + #ifndef assert + #include + #endif + + #if defined(DEBUG) || defined (_DEBUG) + #if defined (__i386__) || defined (__x86_64__) + #include + #define btAssert(x)\ + {\ + if(!(x))\ + {\ + printf("Assert %s in line %d, file %s\n",#x, __LINE__, __FILE__);\ + asm volatile ("int3");\ + }\ + } + #else//defined (__i386__) || defined (__x86_64__) + #define btAssert assert + #endif//defined (__i386__) || defined (__x86_64__) + #else//defined(DEBUG) || defined (_DEBUG) + #define btAssert(x) + #endif//defined(DEBUG) || defined (_DEBUG) + + //btFullAssert is optional, slows down a lot + #define btFullAssert(x) + #define btLikely(_c) _c + #define btUnlikely(_c) _c + + #else//__APPLE__ + + #define SIMD_FORCE_INLINE inline + ///@todo: check out alignment methods for other platforms/compilers + ///#define ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16))) + ///#define ATTRIBUTE_ALIGNED64(a) a __attribute__ ((aligned (64))) + ///#define ATTRIBUTE_ALIGNED128(a) a __attribute__ ((aligned (128))) + #define ATTRIBUTE_ALIGNED16(a) a + #define ATTRIBUTE_ALIGNED64(a) a + #define ATTRIBUTE_ALIGNED128(a) a + #ifndef assert + #include + #endif + + #if defined(DEBUG) || defined (_DEBUG) + #define btAssert assert + #else + #define btAssert(x) + #endif + + //btFullAssert is optional, slows down a lot + #define btFullAssert(x) + #define btLikely(_c) _c + #define btUnlikely(_c) _c + #endif //__APPLE__ + #endif // LIBSPE2 + #endif //__CELLOS_LV2__ +#endif//_WIN32 + + +///The btScalar type abstracts floating point numbers, to easily switch between double and single floating point precision. +#if defined(BT_USE_DOUBLE_PRECISION) + typedef double btScalar; + //this number could be bigger in double precision + #define BT_LARGE_FLOAT 1e30 +#else + typedef float btScalar; + //keep BT_LARGE_FLOAT*BT_LARGE_FLOAT < FLT_MAX + #define BT_LARGE_FLOAT 1e18f +#endif + +#ifdef BT_USE_SSE + typedef __m128 btSimdFloat4; +#endif //BT_USE_SSE + +#if defined(BT_USE_SSE) + //#if defined BT_USE_SSE_IN_API && defined (BT_USE_SSE) + #ifdef _WIN32 + + #ifndef BT_NAN + static int btNanMask = 0x7F800001; + #define BT_NAN (*(float *)&btNanMask) + #endif + + #ifndef BT_INFINITY + static int btInfinityMask = 0x7F800000; + #define BT_INFINITY (*(float *)&btInfinityMask) + inline int btGetInfinityMask() //suppress stupid compiler warning + { + return btInfinityMask; + } + #endif + + + + //use this, in case there are clashes (such as xnamath.h) + #ifndef BT_NO_SIMD_OPERATOR_OVERLOADS + inline __m128 operator+(const __m128 A, const __m128 B) + { + return _mm_add_ps(A, B); + } + + inline __m128 operator-(const __m128 A, const __m128 B) + { + return _mm_sub_ps(A, B); + } + + inline __m128 operator*(const __m128 A, const __m128 B) + { + return _mm_mul_ps(A, B); + } + #endif //BT_NO_SIMD_OPERATOR_OVERLOADS + + #define btCastfTo128i(a) (_mm_castps_si128(a)) + #define btCastfTo128d(a) (_mm_castps_pd(a)) + #define btCastiTo128f(a) (_mm_castsi128_ps(a)) + #define btCastdTo128f(a) (_mm_castpd_ps(a)) + #define btCastdTo128i(a) (_mm_castpd_si128(a)) + #define btAssign128(r0, r1, r2, r3) _mm_setr_ps(r0, r1, r2, r3) + + #else //_WIN32 + + #define btCastfTo128i(a) ((__m128i)(a)) + #define btCastfTo128d(a) ((__m128d)(a)) + #define btCastiTo128f(a) ((__m128)(a)) + #define btCastdTo128f(a) ((__m128)(a)) + #define btCastdTo128i(a) ((__m128i)(a)) + #define btAssign128(r0, r1, r2, r3) \ + (__m128) { r0, r1, r2, r3 } + #define BT_INFINITY INFINITY + #define BT_NAN NAN + #endif //_WIN32 +#else//BT_USE_SSE + + #ifdef BT_USE_NEON + #include + + typedef float32x4_t btSimdFloat4; + #define BT_INFINITY INFINITY + #define BT_NAN NAN + #define btAssign128(r0, r1, r2, r3) \ + (float32x4_t) { r0, r1, r2, r3 } + #else //BT_USE_NEON + + #ifndef BT_INFINITY + struct btInfMaskConverter + { + union { + float mask; + int intmask; + }; + btInfMaskConverter(int _mask = 0x7F800000) + : intmask(_mask) + { + } + }; + static btInfMaskConverter btInfinityMask = 0x7F800000; + #define BT_INFINITY (btInfinityMask.mask) + inline int btGetInfinityMask() //suppress stupid compiler warning + { + return btInfinityMask.intmask; + } + #endif + #endif //BT_USE_NEON + +#endif //BT_USE_SSE + +#ifdef BT_USE_NEON + #include + + typedef float32x4_t btSimdFloat4; + #define BT_INFINITY INFINITY + #define BT_NAN NAN + #define btAssign128(r0, r1, r2, r3) \ + (float32x4_t) { r0, r1, r2, r3 } +#endif//BT_USE_NEON + +#define BT_DECLARE_ALIGNED_ALLOCATOR() \ + SIMD_FORCE_INLINE void *operator new(size_t sizeInBytes) { return btAlignedAlloc(sizeInBytes, 16); } \ + SIMD_FORCE_INLINE void operator delete(void *ptr) { btAlignedFree(ptr); } \ + SIMD_FORCE_INLINE void *operator new(size_t, void *ptr) { return ptr; } \ + SIMD_FORCE_INLINE void operator delete(void *, void *) {} \ + SIMD_FORCE_INLINE void *operator new[](size_t sizeInBytes) { return btAlignedAlloc(sizeInBytes, 16); } \ + SIMD_FORCE_INLINE void operator delete[](void *ptr) { btAlignedFree(ptr); } \ + SIMD_FORCE_INLINE void *operator new[](size_t, void *ptr) { return ptr; } \ + SIMD_FORCE_INLINE void operator delete[](void *, void *) {} + +#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) + { + if (x < btScalar(-1)) x = btScalar(-1); + if (x > btScalar(1)) x = btScalar(1); + return acos(x); + } + SIMD_FORCE_INLINE btScalar btAsin(btScalar x) + { + if (x < btScalar(-1)) x = btScalar(-1); + if (x > btScalar(1)) x = btScalar(1); + 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); } + SIMD_FORCE_INLINE btScalar btFmod(btScalar x, btScalar y) { return fmod(x, y); } + +#else//BT_USE_DOUBLE_PRECISION + + SIMD_FORCE_INLINE btScalar btSqrt(btScalar y) + { + #ifdef USE_APPROXIMATION + #ifdef __LP64__ + float xhalf = 0.5f * y; + int i = *(int *)&y; + i = 0x5f375a86 - (i >> 1); + y = *(float *)&i; + y = y * (1.5f - xhalf * y * y); + y = y * (1.5f - xhalf * y * y); + y = y * (1.5f - xhalf * y * y); + y = 1 / y; + return y; + #else + double x, z, tempf; + unsigned long *tfptr = ((unsigned long *)&tempf) + 1; + tempf = y; + *tfptr = (0xbfcdd90a - *tfptr) >> 1; /* estimate of 1/sqrt(y) */ + x = tempf; + z = y * btScalar(0.5); + x = (btScalar(1.5) * x) - (x * x) * (x * z); /* iteration formula */ + x = (btScalar(1.5) * x) - (x * x) * (x * z); + x = (btScalar(1.5) * x) - (x * x) * (x * z); + x = (btScalar(1.5) * x) - (x * x) * (x * z); + x = (btScalar(1.5) * x) - (x * x) * (x * z); + return x * y; + #endif + #else + return sqrtf(y); + #endif + } + 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) + { + if (x < btScalar(-1)) + x = btScalar(-1); + if (x > btScalar(1)) + x = btScalar(1); + return acosf(x); + } + SIMD_FORCE_INLINE btScalar btAsin(btScalar x) + { + if (x < btScalar(-1)) + x = btScalar(-1); + if (x > btScalar(1)) + x = btScalar(1); + 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); } + SIMD_FORCE_INLINE btScalar btFmod(btScalar x, btScalar y) { return fmodf(x, y); } + +#endif//BT_USE_DOUBLE_PRECISION + +#define SIMD_PI btScalar(3.1415926535897932384626433832795029) +#define SIMD_2_PI (btScalar(2.0) * SIMD_PI) +#define SIMD_HALF_PI (SIMD_PI * btScalar(0.5)) +#define SIMD_RADS_PER_DEG (SIMD_2_PI / btScalar(360.0)) +#define SIMD_DEGS_PER_RAD (btScalar(360.0) / SIMD_2_PI) +#define SIMDSQRT12 btScalar(0.7071067811865475244008443621048490) +#define btRecipSqrt(x) ((btScalar)(btScalar(1.0) / btSqrt(btScalar(x)))) /* reciprocal square root */ +#define btRecip(x) (btScalar(1.0) / btScalar(x)) + +#ifdef BT_USE_DOUBLE_PRECISION + #define SIMD_EPSILON DBL_EPSILON + #define SIMD_INFINITY DBL_MAX + #define BT_ONE 1.0 + #define BT_ZERO 0.0 + #define BT_TWO 2.0 + #define BT_HALF 0.5 +#else + #define SIMD_EPSILON FLT_EPSILON + #define SIMD_INFINITY FLT_MAX + #define BT_ONE 1.0f + #define BT_ZERO 0.0f + #define BT_TWO 2.0f + #define BT_HALF 0.5f +#endif + +// clang-format on + +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 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 + +#ifndef btFsel +SIMD_FORCE_INLINE btScalar btFsel(btScalar a, btScalar b, btScalar c) +{ + return a >= 0 ? b : c; +} +#endif +#define btFsels(a, b, c) (btScalar) btFsel(a, b, c) + +SIMD_FORCE_INLINE bool btMachineIsLittleEndian() +{ + long int i = 1; + const char *p = (const char *)&i; + if (p[0] == 1) // Lowest address contains the least significant byte + return true; + else + return false; +} + +///btSelect avoids branches, which makes performance much better for consoles like Playstation 3 and XBox 360 +///Thanks Phil Knight. See also http://www.cellperformance.com/articles/2006/04/more_techniques_for_eliminatin_1.html +SIMD_FORCE_INLINE unsigned btSelect(unsigned condition, unsigned valueIfConditionNonZero, unsigned valueIfConditionZero) +{ + // Set testNz to 0xFFFFFFFF if condition is nonzero, 0x00000000 if condition is zero + // Rely on positive value or'ed with its negative having sign bit on + // and zero value or'ed with its negative (which is still zero) having sign bit off + // Use arithmetic shift right, shifting the sign bit through all 32 bits + unsigned testNz = (unsigned)(((int)condition | -(int)condition) >> 31); + unsigned testEqz = ~testNz; + return ((valueIfConditionNonZero & testNz) | (valueIfConditionZero & testEqz)); +} +SIMD_FORCE_INLINE int btSelect(unsigned condition, int valueIfConditionNonZero, int valueIfConditionZero) +{ + unsigned testNz = (unsigned)(((int)condition | -(int)condition) >> 31); + unsigned testEqz = ~testNz; + return static_cast((valueIfConditionNonZero & testNz) | (valueIfConditionZero & testEqz)); +} +SIMD_FORCE_INLINE float btSelect(unsigned condition, float valueIfConditionNonZero, float valueIfConditionZero) +{ +#ifdef BT_HAVE_NATIVE_FSEL + return (float)btFsel((btScalar)condition - btScalar(1.0f), valueIfConditionNonZero, valueIfConditionZero); +#else + return (condition != 0) ? valueIfConditionNonZero : valueIfConditionZero; +#endif +} + +template +SIMD_FORCE_INLINE void btSwap(T &a, T &b) +{ + T tmp = a; + a = b; + b = tmp; +} + +//PCK: endian swapping functions +SIMD_FORCE_INLINE unsigned btSwapEndian(unsigned val) +{ + return (((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); +} + +SIMD_FORCE_INLINE unsigned short btSwapEndian(unsigned short val) +{ + return static_cast(((val & 0xff00) >> 8) | ((val & 0x00ff) << 8)); +} + +SIMD_FORCE_INLINE unsigned btSwapEndian(int val) +{ + return btSwapEndian((unsigned)val); +} + +SIMD_FORCE_INLINE unsigned short btSwapEndian(short val) +{ + return btSwapEndian((unsigned short)val); +} + +///btSwapFloat uses using char pointers to swap the endianness +////btSwapFloat/btSwapDouble will NOT return a float, because the machine might 'correct' invalid floating point values +///Not all values of sign/exponent/mantissa are valid floating point numbers according to IEEE 754. +///When a floating point unit is faced with an invalid value, it may actually change the value, or worse, throw an exception. +///In most systems, running user mode code, you wouldn't get an exception, but instead the hardware/os/runtime will 'fix' the number for you. +///so instead of returning a float/double, we return integer/long long integer +SIMD_FORCE_INLINE unsigned int btSwapEndianFloat(float d) +{ + unsigned int a = 0; + unsigned char *dst = (unsigned char *)&a; + unsigned char *src = (unsigned char *)&d; + + dst[0] = src[3]; + dst[1] = src[2]; + dst[2] = src[1]; + dst[3] = src[0]; + return a; +} + +// unswap using char pointers +SIMD_FORCE_INLINE float btUnswapEndianFloat(unsigned int a) +{ + float d = 0.0f; + unsigned char *src = (unsigned char *)&a; + unsigned char *dst = (unsigned char *)&d; + + dst[0] = src[3]; + dst[1] = src[2]; + dst[2] = src[1]; + dst[3] = src[0]; + + return d; +} + +// swap using char pointers +SIMD_FORCE_INLINE void btSwapEndianDouble(double d, unsigned char *dst) +{ + unsigned char *src = (unsigned char *)&d; + + dst[0] = src[7]; + dst[1] = src[6]; + dst[2] = src[5]; + dst[3] = src[4]; + dst[4] = src[3]; + dst[5] = src[2]; + dst[6] = src[1]; + dst[7] = src[0]; +} + +// unswap using char pointers +SIMD_FORCE_INLINE double btUnswapEndianDouble(const unsigned char *src) +{ + double d = 0.0; + unsigned char *dst = (unsigned char *)&d; + + dst[0] = src[7]; + dst[1] = src[6]; + dst[2] = src[5]; + dst[3] = src[4]; + dst[4] = src[3]; + dst[5] = src[2]; + dst[6] = src[1]; + dst[7] = src[0]; + + return d; +} + +template +SIMD_FORCE_INLINE void btSetZero(T *a, int n) +{ + T *acurr = a; + size_t ncurr = n; + while (ncurr > 0) + { + *(acurr++) = 0; + --ncurr; + } +} + +SIMD_FORCE_INLINE btScalar btLargeDot(const btScalar *a, const btScalar *b, int n) +{ + btScalar 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; +} + +// returns normalized value in range [-SIMD_PI, SIMD_PI] +SIMD_FORCE_INLINE btScalar btNormalizeAngle(btScalar angleInRadians) +{ + angleInRadians = btFmod(angleInRadians, SIMD_2_PI); + if (angleInRadians < -SIMD_PI) + { + return angleInRadians + SIMD_2_PI; + } + else if (angleInRadians > SIMD_PI) + { + return angleInRadians - SIMD_2_PI; + } + else + { + return angleInRadians; + } +} + +///rudimentary class to provide type info +struct btTypedObject +{ + btTypedObject(int objectType) + : m_objectType(objectType) + { + } + int m_objectType; + inline int getObjectType() const + { + return m_objectType; + } +}; + +///align a pointer to the provided alignment, upwards +template +T *btAlignPointer(T *unalignedPtr, size_t alignment) +{ + struct btConvertPointerSizeT + { + union { + T *ptr; + size_t integer; + }; + }; + btConvertPointerSizeT converter; + + const size_t bit_mask = ~(alignment - 1); + converter.ptr = unalignedPtr; + converter.integer += alignment - 1; + converter.integer &= bit_mask; + return converter.ptr; +} + +#endif //BT_SCALAR_H diff --git a/extern/bullet/src/LinearMath/btSerializer.cpp b/extern/bullet/src/LinearMath/btSerializer.cpp new file mode 100644 index 000000000000..fcd2255ad566 --- /dev/null +++ b/extern/bullet/src/LinearMath/btSerializer.cpp @@ -0,0 +1,599 @@ +char sBulletDNAstr[]= { +char(83),char(68),char(78),char(65),char(78),char(65),char(77),char(69),char(-124),char(1),char(0),char(0),char(109),char(95),char(115),char(105),char(122),char(101),char(0),char(109), +char(95),char(99),char(97),char(112),char(97),char(99),char(105),char(116),char(121),char(0),char(42),char(109),char(95),char(100),char(97),char(116),char(97),char(0),char(109),char(95), +char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(115),char(0),char(109),char(95),char(99),char(111), +char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(115),char(0),char(109),char(95),char(99),char(111),char(110), +char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(115),char(0),char(42),char(102),char(105),char(114),char(115),char(116),char(0),char(42),char(108),char(97),char(115), +char(116),char(0),char(109),char(95),char(102),char(108),char(111),char(97),char(116),char(115),char(91),char(52),char(93),char(0),char(109),char(95),char(101),char(108),char(91),char(51), +char(93),char(0),char(109),char(95),char(98),char(97),char(115),char(105),char(115),char(0),char(109),char(95),char(111),char(114),char(105),char(103),char(105),char(110),char(0),char(109), +char(95),char(114),char(111),char(111),char(116),char(78),char(111),char(100),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(115),char(117),char(98), +char(116),char(114),char(101),char(101),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100), +char(65),char(97),char(98),char(98),char(77),char(105),char(110),char(91),char(51),char(93),char(0),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122), +char(101),char(100),char(65),char(97),char(98),char(98),char(77),char(97),char(120),char(91),char(51),char(93),char(0),char(109),char(95),char(97),char(97),char(98),char(98),char(77), +char(105),char(110),char(79),char(114),char(103),char(0),char(109),char(95),char(97),char(97),char(98),char(98),char(77),char(97),char(120),char(79),char(114),char(103),char(0),char(109), +char(95),char(101),char(115),char(99),char(97),char(112),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(115),char(117),char(98),char(80),char(97), +char(114),char(116),char(0),char(109),char(95),char(116),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109), +char(95),char(112),char(97),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(101),char(115),char(99),char(97),char(112),char(101),char(73),char(110),char(100),char(101), +char(120),char(79),char(114),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(98), +char(118),char(104),char(65),char(97),char(98),char(98),char(77),char(105),char(110),char(0),char(109),char(95),char(98),char(118),char(104),char(65),char(97),char(98),char(98),char(77), +char(97),char(120),char(0),char(109),char(95),char(98),char(118),char(104),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(97),char(116),char(105),char(111),char(110), +char(0),char(109),char(95),char(99),char(117),char(114),char(78),char(111),char(100),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(117),char(115), +char(101),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(97),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(110),char(117),char(109),char(67), +char(111),char(110),char(116),char(105),char(103),char(117),char(111),char(117),char(115),char(76),char(101),char(97),char(102),char(78),char(111),char(100),char(101),char(115),char(0),char(109), +char(95),char(110),char(117),char(109),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(67),char(111),char(110),char(116),char(105),char(103),char(117), +char(111),char(117),char(115),char(78),char(111),char(100),char(101),char(115),char(0),char(42),char(109),char(95),char(99),char(111),char(110),char(116),char(105),char(103),char(117),char(111), +char(117),char(115),char(78),char(111),char(100),char(101),char(115),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105), +char(122),char(101),char(100),char(67),char(111),char(110),char(116),char(105),char(103),char(117),char(111),char(117),char(115),char(78),char(111),char(100),char(101),char(115),char(80),char(116), +char(114),char(0),char(42),char(109),char(95),char(115),char(117),char(98),char(84),char(114),char(101),char(101),char(73),char(110),char(102),char(111),char(80),char(116),char(114),char(0), +char(109),char(95),char(116),char(114),char(97),char(118),char(101),char(114),char(115),char(97),char(108),char(77),char(111),char(100),char(101),char(0),char(109),char(95),char(110),char(117), +char(109),char(83),char(117),char(98),char(116),char(114),char(101),char(101),char(72),char(101),char(97),char(100),char(101),char(114),char(115),char(0),char(42),char(109),char(95),char(110), +char(97),char(109),char(101),char(0),char(109),char(95),char(115),char(104),char(97),char(112),char(101),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(112),char(97), +char(100),char(100),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110), +char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(83),char(99),char(97), +char(108),char(105),char(110),char(103),char(0),char(109),char(95),char(112),char(108),char(97),char(110),char(101),char(78),char(111),char(114),char(109),char(97),char(108),char(0),char(109), +char(95),char(112),char(108),char(97),char(110),char(101),char(67),char(111),char(110),char(115),char(116),char(97),char(110),char(116),char(0),char(109),char(95),char(105),char(109),char(112), +char(108),char(105),char(99),char(105),char(116),char(83),char(104),char(97),char(112),char(101),char(68),char(105),char(109),char(101),char(110),char(115),char(105),char(111),char(110),char(115), +char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(77),char(97),char(114),char(103),char(105),char(110),char(0),char(109), +char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(0),char(109),char(95),char(112),char(111),char(115),char(0),char(109),char(95),char(114),char(97),char(100), +char(105),char(117),char(115),char(0),char(109),char(95),char(99),char(111),char(110),char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114),char(110),char(97),char(108), +char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(42),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(80),char(111), +char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(114),char(114),char(97),char(121),char(80),char(116),char(114),char(0),char(109),char(95),char(108),char(111),char(99), +char(97),char(108),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(114),char(114),char(97),char(121),char(83),char(105),char(122),char(101),char(0), +char(109),char(95),char(118),char(97),char(108),char(117),char(101),char(0),char(109),char(95),char(112),char(97),char(100),char(91),char(50),char(93),char(0),char(109),char(95),char(118), +char(97),char(108),char(117),char(101),char(115),char(91),char(51),char(93),char(0),char(109),char(95),char(112),char(97),char(100),char(0),char(42),char(109),char(95),char(118),char(101), +char(114),char(116),char(105),char(99),char(101),char(115),char(51),char(102),char(0),char(42),char(109),char(95),char(118),char(101),char(114),char(116),char(105),char(99),char(101),char(115), +char(51),char(100),char(0),char(42),char(109),char(95),char(105),char(110),char(100),char(105),char(99),char(101),char(115),char(51),char(50),char(0),char(42),char(109),char(95),char(51), +char(105),char(110),char(100),char(105),char(99),char(101),char(115),char(49),char(54),char(0),char(42),char(109),char(95),char(51),char(105),char(110),char(100),char(105),char(99),char(101), +char(115),char(56),char(0),char(42),char(109),char(95),char(105),char(110),char(100),char(105),char(99),char(101),char(115),char(49),char(54),char(0),char(109),char(95),char(110),char(117), +char(109),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(86),char(101),char(114),char(116), +char(105),char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(109),char(101),char(115),char(104),char(80),char(97),char(114),char(116),char(115),char(80),char(116),char(114), +char(0),char(109),char(95),char(115),char(99),char(97),char(108),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(101),char(115),char(104), +char(80),char(97),char(114),char(116),char(115),char(0),char(109),char(95),char(109),char(101),char(115),char(104),char(73),char(110),char(116),char(101),char(114),char(102),char(97),char(99), +char(101),char(0),char(42),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(70),char(108),char(111),char(97),char(116),char(66), +char(118),char(104),char(0),char(42),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(68),char(111),char(117),char(98),char(108), +char(101),char(66),char(118),char(104),char(0),char(42),char(109),char(95),char(116),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111), +char(77),char(97),char(112),char(0),char(109),char(95),char(112),char(97),char(100),char(51),char(91),char(52),char(93),char(0),char(109),char(95),char(116),char(114),char(105),char(109), +char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(116),char(114),char(97),char(110),char(115), +char(102),char(111),char(114),char(109),char(0),char(42),char(109),char(95),char(99),char(104),char(105),char(108),char(100),char(83),char(104),char(97),char(112),char(101),char(0),char(109), +char(95),char(99),char(104),char(105),char(108),char(100),char(83),char(104),char(97),char(112),char(101),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(99),char(104), +char(105),char(108),char(100),char(77),char(97),char(114),char(103),char(105),char(110),char(0),char(42),char(109),char(95),char(99),char(104),char(105),char(108),char(100),char(83),char(104), +char(97),char(112),char(101),char(80),char(116),char(114),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(104),char(105),char(108),char(100),char(83),char(104),char(97), +char(112),char(101),char(115),char(0),char(109),char(95),char(117),char(112),char(65),char(120),char(105),char(115),char(0),char(109),char(95),char(117),char(112),char(73),char(110),char(100), +char(101),char(120),char(0),char(109),char(95),char(102),char(108),char(97),char(103),char(115),char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(86),char(48),char(86), +char(49),char(65),char(110),char(103),char(108),char(101),char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(86),char(49),char(86),char(50),char(65),char(110),char(103), +char(108),char(101),char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(86),char(50),char(86),char(48),char(65),char(110),char(103),char(108),char(101),char(0),char(42), +char(109),char(95),char(104),char(97),char(115),char(104),char(84),char(97),char(98),char(108),char(101),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(110),char(101), +char(120),char(116),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(118),char(97),char(108),char(117),char(101),char(65),char(114),char(114),char(97),char(121),char(80), +char(116),char(114),char(0),char(42),char(109),char(95),char(107),char(101),char(121),char(65),char(114),char(114),char(97),char(121),char(80),char(116),char(114),char(0),char(109),char(95), +char(99),char(111),char(110),char(118),char(101),char(120),char(69),char(112),char(115),char(105),char(108),char(111),char(110),char(0),char(109),char(95),char(112),char(108),char(97),char(110), +char(97),char(114),char(69),char(112),char(115),char(105),char(108),char(111),char(110),char(0),char(109),char(95),char(101),char(113),char(117),char(97),char(108),char(86),char(101),char(114), +char(116),char(101),char(120),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(68), +char(105),char(115),char(116),char(97),char(110),char(99),char(101),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(122), +char(101),char(114),char(111),char(65),char(114),char(101),char(97),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(110), +char(101),char(120),char(116),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(104),char(97),char(115),char(104),char(84),char(97),char(98),char(108),char(101),char(83), +char(105),char(122),char(101),char(0),char(109),char(95),char(110),char(117),char(109),char(86),char(97),char(108),char(117),char(101),char(115),char(0),char(109),char(95),char(110),char(117), +char(109),char(75),char(101),char(121),char(115),char(0),char(109),char(95),char(103),char(105),char(109),char(112),char(97),char(99),char(116),char(83),char(117),char(98),char(84),char(121), +char(112),char(101),char(0),char(42),char(109),char(95),char(117),char(110),char(115),char(99),char(97),char(108),char(101),char(100),char(80),char(111),char(105),char(110),char(116),char(115), +char(70),char(108),char(111),char(97),char(116),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(117),char(110),char(115),char(99),char(97),char(108),char(101),char(100), +char(80),char(111),char(105),char(110),char(116),char(115),char(68),char(111),char(117),char(98),char(108),char(101),char(80),char(116),char(114),char(0),char(109),char(95),char(110),char(117), +char(109),char(85),char(110),char(115),char(99),char(97),char(108),char(101),char(100),char(80),char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(112),char(97), +char(100),char(100),char(105),char(110),char(103),char(51),char(91),char(52),char(93),char(0),char(42),char(109),char(95),char(98),char(114),char(111),char(97),char(100),char(112),char(104), +char(97),char(115),char(101),char(72),char(97),char(110),char(100),char(108),char(101),char(0),char(42),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105), +char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(0),char(42),char(109),char(95),char(114),char(111),char(111),char(116),char(67),char(111),char(108),char(108),char(105), +char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(0),char(109),char(95),char(119),char(111),char(114),char(108),char(100),char(84),char(114),char(97), +char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105), +char(111),char(110),char(87),char(111),char(114),char(108),char(100),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(105), +char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105),char(111),char(110),char(76),char(105),char(110),char(101),char(97),char(114),char(86),char(101), +char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105), +char(111),char(110),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95), +char(97),char(110),char(105),char(115),char(111),char(116),char(114),char(111),char(112),char(105),char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0), +char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(99),char(116),char(80),char(114),char(111),char(99),char(101),char(115),char(115),char(105),char(110),char(103),char(84), +char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(100),char(101),char(97),char(99),char(116),char(105),char(118),char(97),char(116), +char(105),char(111),char(110),char(84),char(105),char(109),char(101),char(0),char(109),char(95),char(102),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109), +char(95),char(114),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99), +char(111),char(110),char(116),char(97),char(99),char(116),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(99),char(111),char(110),char(116), +char(97),char(99),char(116),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(105), +char(116),char(117),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(104),char(105),char(116),char(70),char(114),char(97),char(99),char(116),char(105),char(111),char(110), +char(0),char(109),char(95),char(99),char(99),char(100),char(83),char(119),char(101),char(112),char(116),char(83),char(112),char(104),char(101),char(114),char(101),char(82),char(97),char(100), +char(105),char(117),char(115),char(0),char(109),char(95),char(99),char(99),char(100),char(77),char(111),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115), +char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(104),char(97),char(115),char(65),char(110),char(105),char(115),char(111),char(116),char(114),char(111),char(112),char(105), +char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111), +char(110),char(70),char(108),char(97),char(103),char(115),char(0),char(109),char(95),char(105),char(115),char(108),char(97),char(110),char(100),char(84),char(97),char(103),char(49),char(0), +char(109),char(95),char(99),char(111),char(109),char(112),char(97),char(110),char(105),char(111),char(110),char(73),char(100),char(0),char(109),char(95),char(97),char(99),char(116),char(105), +char(118),char(97),char(116),char(105),char(111),char(110),char(83),char(116),char(97),char(116),char(101),char(49),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114), +char(110),char(97),char(108),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(99),char(104),char(101),char(99),char(107),char(67),char(111),char(108),char(108),char(105), +char(100),char(101),char(87),char(105),char(116),char(104),char(0),char(109),char(95),char(116),char(97),char(117),char(0),char(109),char(95),char(100),char(97),char(109),char(112),char(105), +char(110),char(103),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(116),char(101),char(112),char(0),char(109),char(95),char(109),char(97),char(120),char(69), +char(114),char(114),char(111),char(114),char(82),char(101),char(100),char(117),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(115),char(111),char(114),char(0), +char(109),char(95),char(101),char(114),char(112),char(0),char(109),char(95),char(101),char(114),char(112),char(50),char(0),char(109),char(95),char(103),char(108),char(111),char(98),char(97), +char(108),char(67),char(102),char(109),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(80), +char(101),char(110),char(101),char(116),char(114),char(97),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0), +char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(84),char(117),char(114),char(110),char(69),char(114), +char(112),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(111),char(112),char(0),char(109),char(95),char(119),char(97),char(114), +char(109),char(115),char(116),char(97),char(114),char(116),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(109),char(97), +char(120),char(71),char(121),char(114),char(111),char(115),char(99),char(111),char(112),char(105),char(99),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(115), +char(105),char(110),char(103),char(108),char(101),char(65),char(120),char(105),char(115),char(82),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99), +char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(110),char(117),char(109),char(73), +char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(77),char(111), +char(100),char(101),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(105),char(110),char(103),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(82), +char(101),char(115),char(116),char(105),char(116),char(117),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0), +char(109),char(95),char(109),char(105),char(110),char(105),char(109),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(66),char(97),char(116),char(99),char(104), +char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0), +char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(0),char(109),char(95),char(103),char(114),char(97),char(118),char(105), +char(116),char(121),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116), +char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(84),char(101),char(110), +char(115),char(111),char(114),char(87),char(111),char(114),char(108),char(100),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(86),char(101),char(108), +char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111),char(99), +char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114),char(0), +char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(103),char(114),char(97), +char(118),char(105),char(116),char(121),char(95),char(97),char(99),char(99),char(101),char(108),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(0),char(109),char(95), +char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(76),char(111),char(99),char(97),char(108),char(0),char(109),char(95),char(116),char(111), +char(116),char(97),char(108),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(116),char(111),char(116),char(97),char(108),char(84),char(111),char(114),char(113), +char(117),char(101),char(0),char(109),char(95),char(105),char(110),char(118),char(101),char(114),char(115),char(101),char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(108), +char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108), +char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110), +char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(97),char(100), +char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(76),char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110), +char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105), +char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103), +char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116), +char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(70), +char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(101),char(101),char(112),char(105), +char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97), +char(114),char(83),char(108),char(101),char(101),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109), +char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109), +char(95),char(110),char(117),char(109),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(82),char(111),char(119),char(115),char(0),char(110), +char(117),char(98),char(0),char(42),char(109),char(95),char(114),char(98),char(65),char(0),char(42),char(109),char(95),char(114),char(98),char(66),char(0),char(109),char(95),char(111), +char(98),char(106),char(101),char(99),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110),char(115), +char(116),char(114),char(97),char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110), +char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(100),char(0),char(109),char(95),char(110),char(101),char(101),char(100),char(115),char(70),char(101),char(101), +char(100),char(98),char(97),char(99),char(107),char(0),char(109),char(95),char(97),char(112),char(112),char(108),char(105),char(101),char(100),char(73),char(109),char(112),char(117),char(108), +char(115),char(101),char(0),char(109),char(95),char(100),char(98),char(103),char(68),char(114),char(97),char(119),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(100), +char(105),char(115),char(97),char(98),char(108),char(101),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(115),char(66),char(101),char(116),char(119), +char(101),char(101),char(110),char(76),char(105),char(110),char(107),char(101),char(100),char(66),char(111),char(100),char(105),char(101),char(115),char(0),char(109),char(95),char(111),char(118), +char(101),char(114),char(114),char(105),char(100),char(101),char(78),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(116),char(101),char(114),char(97), +char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(98),char(114),char(101),char(97),char(107),char(105),char(110),char(103),char(73),char(109),char(112),char(117), +char(108),char(115),char(101),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(105),char(115),char(69),char(110),char(97), +char(98),char(108),char(101),char(100),char(0),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(116),char(121), +char(112),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(112), +char(105),char(118),char(111),char(116),char(73),char(110),char(65),char(0),char(109),char(95),char(112),char(105),char(118),char(111),char(116),char(73),char(110),char(66),char(0),char(109), +char(95),char(114),char(98),char(65),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(114),char(98),char(66),char(70),char(114),char(97),char(109),char(101), +char(0),char(109),char(95),char(117),char(115),char(101),char(82),char(101),char(102),char(101),char(114),char(101),char(110),char(99),char(101),char(70),char(114),char(97),char(109),char(101), +char(65),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(79),char(110),char(108),char(121),char(0),char(109),char(95),char(101),char(110), +char(97),char(98),char(108),char(101),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(0),char(109),char(95),char(109), +char(111),char(116),char(111),char(114),char(84),char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109), +char(95),char(109),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(108), +char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(117),char(112),char(112),char(101),char(114),char(76),char(105),char(109), +char(105),char(116),char(0),char(109),char(95),char(108),char(105),char(109),char(105),char(116),char(83),char(111),char(102),char(116),char(110),char(101),char(115),char(115),char(0),char(109), +char(95),char(98),char(105),char(97),char(115),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(114),char(101),char(108),char(97),char(120),char(97), +char(116),char(105),char(111),char(110),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103), +char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(49),char(0),char(109),char(95), +char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(50),char(0),char(109),char(95),char(116),char(119),char(105),char(115),char(116),char(83),char(112), +char(97),char(110),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105), +char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116), +char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),char(116), +char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116), +char(0),char(109),char(95),char(117),char(115),char(101),char(76),char(105),char(110),char(101),char(97),char(114),char(82),char(101),char(102),char(101),char(114),char(101),char(110),char(99), +char(101),char(70),char(114),char(97),char(109),char(101),char(65),char(0),char(109),char(95),char(117),char(115),char(101),char(79),char(102),char(102),char(115),char(101),char(116),char(70), +char(111),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95), +char(54),char(100),char(111),char(102),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(69),char(110),char(97), +char(98),char(108),char(101),char(100),char(91),char(54),char(93),char(0),char(109),char(95),char(101),char(113),char(117),char(105),char(108),char(105),char(98),char(114),char(105),char(117), +char(109),char(80),char(111),char(105),char(110),char(116),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(83),char(116), +char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(68), +char(97),char(109),char(112),char(105),char(110),char(103),char(91),char(54),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(66),char(111), +char(117),char(110),char(99),char(101),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82),char(80), +char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95),char(108), +char(105),char(110),char(101),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(108),char(105),char(110),char(101), +char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(84), +char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(108),char(105),char(110),char(101), +char(97),char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(108),char(105), +char(110),char(101),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0),char(109),char(95),char(108),char(105), +char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0), +char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110), +char(103),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105),char(98),char(114),char(105),char(117), +char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(110),char(97),char(98),char(108), +char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(101), +char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114), +char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105), +char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(76), +char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112), +char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52), +char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(66),char(111),char(117),char(110),char(99),char(101),char(0),char(109),char(95), +char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110),char(103), +char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97), +char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(77), +char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(84),char(97),char(114), +char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97), +char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(97),char(110),char(103), +char(117),char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0),char(109),char(95),char(97),char(110), +char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115), +char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112), +char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105),char(98), +char(114),char(105),char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69), +char(110),char(97),char(98),char(108),char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117), +char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(97), +char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91),char(52), +char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105), +char(102),char(102),char(110),char(101),char(115),char(115),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(97), +char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(76), +char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(114),char(111),char(116),char(97),char(116),char(101),char(79),char(114), +char(100),char(101),char(114),char(0),char(109),char(95),char(97),char(120),char(105),char(115),char(73),char(110),char(65),char(0),char(109),char(95),char(97),char(120),char(105),char(115), +char(73),char(110),char(66),char(0),char(109),char(95),char(114),char(97),char(116),char(105),char(111),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114), +char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83), +char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(118),char(111),char(108),char(117),char(109),char(101),char(83),char(116),char(105), +char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(0),char(109), +char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(112),char(114),char(101),char(118),char(105),char(111),char(117),char(115), +char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0), +char(109),char(95),char(97),char(99),char(99),char(117),char(109),char(117),char(108),char(97),char(116),char(101),char(100),char(70),char(111),char(114),char(99),char(101),char(0),char(109), +char(95),char(110),char(111),char(114),char(109),char(97),char(108),char(0),char(109),char(95),char(97),char(114),char(101),char(97),char(0),char(109),char(95),char(97),char(116),char(116), +char(97),char(99),char(104),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(50),char(93), +char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(76),char(101),char(110),char(103),char(116),char(104),char(0),char(109),char(95),char(98),char(98),char(101),char(110), +char(100),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(51), +char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(65),char(114),char(101),char(97),char(0),char(109),char(95),char(99),char(48),char(91),char(52),char(93), +char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(52),char(93),char(0),char(109),char(95), +char(114),char(101),char(115),char(116),char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(99),char(49),char(0),char(109),char(95),char(99),char(50), +char(0),char(109),char(95),char(99),char(48),char(0),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(70),char(114),char(97),char(109),char(101),char(0),char(42), +char(109),char(95),char(114),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110), +char(100),char(101),char(120),char(0),char(109),char(95),char(97),char(101),char(114),char(111),char(77),char(111),char(100),char(101),char(108),char(0),char(109),char(95),char(98),char(97), +char(117),char(109),char(103),char(97),char(114),char(116),char(101),char(0),char(109),char(95),char(100),char(114),char(97),char(103),char(0),char(109),char(95),char(108),char(105),char(102), +char(116),char(0),char(109),char(95),char(112),char(114),char(101),char(115),char(115),char(117),char(114),char(101),char(0),char(109),char(95),char(118),char(111),char(108),char(117),char(109), +char(101),char(0),char(109),char(95),char(100),char(121),char(110),char(97),char(109),char(105),char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0), +char(109),char(95),char(112),char(111),char(115),char(101),char(77),char(97),char(116),char(99),char(104),char(0),char(109),char(95),char(114),char(105),char(103),char(105),char(100),char(67), +char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(107),char(105),char(110), +char(101),char(116),char(105),char(99),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0), +char(109),char(95),char(115),char(111),char(102),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115), +char(115),char(0),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109), +char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114), +char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75),char(105),char(110),char(101),char(116),char(105),char(99),char(67), +char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102), +char(116),char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115), +char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73), +char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75),char(105), +char(110),char(101),char(116),char(105),char(99),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83), +char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116), +char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(109),char(97),char(120), +char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(99),char(97),char(108),char(101),char(0),char(109), +char(95),char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0), +char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115), +char(0),char(109),char(95),char(100),char(114),char(105),char(102),char(116),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109), +char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109), +char(95),char(114),char(111),char(116),char(0),char(109),char(95),char(115),char(99),char(97),char(108),char(101),char(0),char(109),char(95),char(97),char(113),char(113),char(0),char(109), +char(95),char(99),char(111),char(109),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(115),char(0),char(42),char(109), +char(95),char(119),char(101),char(105),char(103),char(104),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(80),char(111),char(115),char(105),char(116),char(105), +char(111),char(110),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(87),char(101),char(105),char(103),char(116),char(115),char(0),char(109),char(95),char(98),char(118), +char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(98),char(102),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(102),char(114),char(97), +char(109),char(101),char(120),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(108),char(111),char(99),char(105),char(105),char(0),char(109),char(95),char(105),char(110), +char(118),char(119),char(105),char(0),char(109),char(95),char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93),char(0),char(109), +char(95),char(100),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(108),char(118),char(0),char(109), +char(95),char(97),char(118),char(0),char(42),char(109),char(95),char(102),char(114),char(97),char(109),char(101),char(114),char(101),char(102),char(115),char(0),char(42),char(109),char(95), +char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(115),char(115),char(101), +char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(114),char(97),char(109),char(101),char(82),char(101),char(102),char(115),char(0),char(109),char(95),char(110), +char(117),char(109),char(78),char(111),char(100),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(115),char(115),char(101),char(115),char(0), +char(109),char(95),char(105),char(100),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(105),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(110), +char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(105),char(109),char(112),char(117),char(108),char(115), +char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(108),char(100),char(97),char(109), +char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97), +char(116),char(99),char(104),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97),char(120),char(83),char(101),char(108),char(102),char(67),char(111),char(108),char(108), +char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(115),char(101),char(108),char(102),char(67), +char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(70),char(97),char(99),char(116),char(111), +char(114),char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(105),char(110),char(115),char(65),char(110),char(99),char(104),char(111),char(114),char(0),char(109), +char(95),char(99),char(111),char(108),char(108),char(105),char(100),char(101),char(0),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(110), +char(100),char(101),char(120),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121), +char(66),char(0),char(109),char(95),char(114),char(101),char(102),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(99),char(102),char(109),char(0),char(109),char(95), +char(115),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(100),char(101),char(108),char(101),char(116),char(101),char(0),char(109),char(95),char(114),char(101),char(108), +char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(91),char(50),char(93),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(116), +char(121),char(112),char(101),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(66),char(116),char(121),char(112),char(101),char(0),char(109),char(95),char(106),char(111), +char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(101),char(0),char(42),char(42),char(109),char(95), +char(109),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(42),char(109),char(95),char(110),char(111),char(100),char(101),char(115),char(0),char(42), +char(109),char(95),char(108),char(105),char(110),char(107),char(115),char(0),char(42),char(109),char(95),char(102),char(97),char(99),char(101),char(115),char(0),char(42),char(109),char(95), +char(116),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(42),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114), +char(115),char(0),char(42),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(115),char(0),char(42),char(109),char(95),char(106),char(111),char(105), +char(110),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(109), +char(95),char(110),char(117),char(109),char(76),char(105),char(110),char(107),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(97),char(99),char(101),char(115), +char(0),char(109),char(95),char(110),char(117),char(109),char(84),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(109),char(95),char(110), +char(117),char(109),char(65),char(110),char(99),char(104),char(111),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(108),char(117),char(115),char(116), +char(101),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(74),char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(99),char(111), +char(110),char(102),char(105),char(103),char(0),char(109),char(95),char(122),char(101),char(114),char(111),char(82),char(111),char(116),char(80),char(97),char(114),char(101),char(110),char(116), +char(84),char(111),char(84),char(104),char(105),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(67),char(111),char(109),char(84),char(111), +char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102),char(102),char(115),char(101),char(116),char(0),char(109),char(95),char(116),char(104),char(105),char(115), +char(80),char(105),char(118),char(111),char(116),char(84),char(111),char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102),char(102),char(115),char(101),char(116), +char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(84),char(111),char(112),char(91),char(54),char(93),char(0),char(109), +char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(66),char(111),char(116),char(116),char(111),char(109),char(91),char(54),char(93),char(0), +char(109),char(95),char(108),char(105),char(110),char(107),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(0),char(109),char(95),char(108),char(105),char(110),char(107), +char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(0),char(109), +char(95),char(100),char(111),char(102),char(67),char(111),char(117),char(110),char(116),char(0),char(109),char(95),char(112),char(111),char(115),char(86),char(97),char(114),char(67),char(111), +char(117),char(110),char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(80),char(111),char(115),char(91),char(55),char(93),char(0),char(109),char(95), +char(106),char(111),char(105),char(110),char(116),char(86),char(101),char(108),char(91),char(54),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(84), +char(111),char(114),char(113),char(117),char(101),char(91),char(54),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(68),char(97),char(109),char(112), +char(105),char(110),char(103),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0), +char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95), +char(106),char(111),char(105),char(110),char(116),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(106),char(111), +char(105),char(110),char(116),char(77),char(97),char(120),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(77), +char(97),char(120),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(78),char(97), +char(109),char(101),char(0),char(42),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(108), +char(105),char(110),char(107),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114),char(0),char(42),char(109),char(95),char(112),char(97),char(100),char(100),char(105), +char(110),char(103),char(80),char(116),char(114),char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(87),char(111),char(114),char(108),char(100),char(84),char(114),char(97), +char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(73),char(110),char(101),char(114),char(116),char(105),char(97), +char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(77),char(97),char(115),char(115),char(0),char(42),char(109),char(95),char(98),char(97),char(115),char(101),char(78), +char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(98),char(97),char(115),char(101),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114),char(0), +char(84),char(89),char(80),char(69),char(95),char(0),char(0),char(0),char(99),char(104),char(97),char(114),char(0),char(117),char(99),char(104),char(97),char(114),char(0),char(115), +char(104),char(111),char(114),char(116),char(0),char(117),char(115),char(104),char(111),char(114),char(116),char(0),char(105),char(110),char(116),char(0),char(108),char(111),char(110),char(103), +char(0),char(117),char(108),char(111),char(110),char(103),char(0),char(102),char(108),char(111),char(97),char(116),char(0),char(100),char(111),char(117),char(98),char(108),char(101),char(0), +char(118),char(111),char(105),char(100),char(0),char(80),char(111),char(105),char(110),char(116),char(101),char(114),char(65),char(114),char(114),char(97),char(121),char(0),char(98),char(116), +char(80),char(104),char(121),char(115),char(105),char(99),char(115),char(83),char(121),char(115),char(116),char(101),char(109),char(0),char(76),char(105),char(115),char(116),char(66),char(97), +char(115),char(101),char(0),char(98),char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116), +char(97),char(0),char(98),char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116), +char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114),char(110),char(105),char(111),char(110),char(70),char(108),char(111),char(97),char(116),char(68), +char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114),char(110),char(105),char(111),char(110),char(68),char(111),char(117),char(98), +char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(70),char(108), +char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(68), +char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114), +char(109),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111), +char(114),char(109),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(66),char(118),char(104),char(83),char(117), +char(98),char(116),char(114),char(101),char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105), +char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116), +char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101), +char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122), +char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110), +char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116), +char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(68), +char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(97),char(116),char(105),char(99),char(80),char(108),char(97),char(110),char(101),char(83),char(104),char(97), +char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114), +char(110),char(97),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(115),char(105),char(116), +char(105),char(111),char(110),char(65),char(110),char(100),char(82),char(97),char(100),char(105),char(117),char(115),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105), +char(83),char(112),char(104),char(101),char(114),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(73),char(110), +char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110), +char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110), +char(116),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116), +char(67),char(104),char(97),char(114),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97), +char(0),char(98),char(116),char(77),char(101),char(115),char(104),char(80),char(97),char(114),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116), +char(114),char(105),char(100),char(105),char(110),char(103),char(77),char(101),char(115),char(104),char(73),char(110),char(116),char(101),char(114),char(102),char(97),char(99),char(101),char(68), +char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104), +char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110), +char(102),char(111),char(77),char(97),char(112),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(99),char(97),char(108),char(101),char(100),char(84),char(114), +char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0), +char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(67),char(104),char(105),char(108),char(100), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(121),char(108),char(105),char(110),char(100),char(101),char(114),char(83),char(104),char(97),char(112),char(101), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97), +char(0),char(98),char(116),char(67),char(97),char(112),char(115),char(117),char(108),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0), +char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98), +char(116),char(71),char(73),char(109),char(112),char(97),char(99),char(116),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116), +char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118),char(101),char(120),char(72),char(117),char(108),char(108),char(83),char(104),char(97),char(112),char(101),char(68), +char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99), +char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115), +char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98), +char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(68),char(111), +char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(83),char(111), +char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116), +char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115),char(87),char(111),char(114),char(108),char(100),char(68),char(111),char(117),char(98),char(108),char(101),char(68), +char(97),char(116),char(97),char(0),char(98),char(116),char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115),char(87),char(111),char(114),char(108),char(100),char(70), +char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121), +char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100), +char(121),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(115),char(116),char(114), +char(97),char(105),char(110),char(116),char(73),char(110),char(102),char(111),char(49),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110), +char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84), +char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98), +char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(121),char(112), +char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115), +char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111), +char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68), +char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80), +char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), +char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101), +char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0), +char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117), +char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116), +char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97), +char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), +char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102), +char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110), +char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111), +char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54), +char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68), +char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114), +char(105),char(110),char(103),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68), +char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112), +char(114),char(105),char(110),char(103),char(50),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0), +char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(50), +char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97), +char(50),char(0),char(98),char(116),char(83),char(108),char(105),char(100),char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(108),char(105),char(100),char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97), +char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(97),char(114), +char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0), +char(98),char(116),char(71),char(101),char(97),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98), +char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(77),char(97),char(116),char(101),char(114), +char(105),char(97),char(108),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(78),char(111),char(100),char(101), +char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(68),char(97),char(116), +char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(70),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(83), +char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(84),char(101),char(116),char(114),char(97),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102), +char(116),char(82),char(105),char(103),char(105),char(100),char(65),char(110),char(99),char(104),char(111),char(114),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102), +char(116),char(66),char(111),char(100),char(121),char(67),char(111),char(110),char(102),char(105),char(103),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116), +char(66),char(111),char(100),char(121),char(80),char(111),char(115),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100), +char(121),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66), +char(111),char(100),char(121),char(74),char(111),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66), +char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105), +char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98), +char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(70),char(108),char(111),char(97),char(116),char(68), +char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(68),char(111),char(117),char(98),char(108), +char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(70),char(108),char(111), +char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(0),char(84),char(76),char(69),char(78),char(1),char(0),char(1),char(0),char(2),char(0),char(2),char(0), +char(4),char(0),char(4),char(0),char(4),char(0),char(4),char(0),char(8),char(0),char(0),char(0),char(12),char(0),char(36),char(0),char(8),char(0),char(16),char(0), +char(32),char(0),char(16),char(0),char(32),char(0),char(48),char(0),char(96),char(0),char(64),char(0),char(-128),char(0),char(20),char(0),char(48),char(0),char(80),char(0), +char(16),char(0),char(84),char(0),char(-124),char(0),char(12),char(0),char(52),char(0),char(52),char(0),char(20),char(0),char(64),char(0),char(4),char(0),char(4),char(0), +char(8),char(0),char(4),char(0),char(32),char(0),char(28),char(0),char(60),char(0),char(56),char(0),char(76),char(0),char(76),char(0),char(24),char(0),char(60),char(0), +char(60),char(0),char(60),char(0),char(16),char(0),char(64),char(0),char(68),char(0),char(-32),char(1),char(8),char(1),char(-104),char(0),char(88),char(0),char(-72),char(0), +char(104),char(0),char(-16),char(1),char(-80),char(3),char(8),char(0),char(52),char(0),char(52),char(0),char(0),char(0),char(68),char(0),char(84),char(0),char(-124),char(0), +char(116),char(0),char(92),char(1),char(-36),char(0),char(-116),char(1),char(124),char(1),char(-44),char(0),char(-4),char(0),char(-52),char(1),char(92),char(1),char(116),char(2), +char(-124),char(2),char(-76),char(4),char(-52),char(0),char(108),char(1),char(92),char(0),char(-116),char(0),char(16),char(0),char(100),char(0),char(20),char(0),char(36),char(0), +char(100),char(0),char(92),char(0),char(104),char(0),char(-64),char(0),char(92),char(1),char(104),char(0),char(-76),char(1),char(-16),char(2),char(-120),char(1),char(-64),char(0), +char(100),char(0),char(0),char(0),char(83),char(84),char(82),char(67),char(84),char(0),char(0),char(0),char(10),char(0),char(3),char(0),char(4),char(0),char(0),char(0), +char(4),char(0),char(1),char(0),char(9),char(0),char(2),char(0),char(11),char(0),char(3),char(0),char(10),char(0),char(3),char(0),char(10),char(0),char(4),char(0), +char(10),char(0),char(5),char(0),char(12),char(0),char(2),char(0),char(9),char(0),char(6),char(0),char(9),char(0),char(7),char(0),char(13),char(0),char(1),char(0), +char(7),char(0),char(8),char(0),char(14),char(0),char(1),char(0),char(8),char(0),char(8),char(0),char(15),char(0),char(1),char(0),char(7),char(0),char(8),char(0), +char(16),char(0),char(1),char(0),char(8),char(0),char(8),char(0),char(17),char(0),char(1),char(0),char(13),char(0),char(9),char(0),char(18),char(0),char(1),char(0), +char(14),char(0),char(9),char(0),char(19),char(0),char(2),char(0),char(17),char(0),char(10),char(0),char(13),char(0),char(11),char(0),char(20),char(0),char(2),char(0), +char(18),char(0),char(10),char(0),char(14),char(0),char(11),char(0),char(21),char(0),char(4),char(0),char(4),char(0),char(12),char(0),char(4),char(0),char(13),char(0), +char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0),char(22),char(0),char(6),char(0),char(13),char(0),char(16),char(0),char(13),char(0),char(17),char(0), +char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0),char(23),char(0),char(6),char(0), +char(14),char(0),char(16),char(0),char(14),char(0),char(17),char(0),char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0), +char(0),char(0),char(21),char(0),char(24),char(0),char(3),char(0),char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0),char(4),char(0),char(22),char(0), +char(25),char(0),char(12),char(0),char(13),char(0),char(23),char(0),char(13),char(0),char(24),char(0),char(13),char(0),char(25),char(0),char(4),char(0),char(26),char(0), +char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0),char(22),char(0),char(30),char(0),char(24),char(0),char(31),char(0), +char(21),char(0),char(32),char(0),char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),char(26),char(0),char(12),char(0),char(14),char(0),char(23),char(0), +char(14),char(0),char(24),char(0),char(14),char(0),char(25),char(0),char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0), +char(4),char(0),char(29),char(0),char(23),char(0),char(30),char(0),char(24),char(0),char(31),char(0),char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0), +char(21),char(0),char(32),char(0),char(27),char(0),char(3),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(36),char(0),char(0),char(0),char(37),char(0), +char(28),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(13),char(0),char(39),char(0),char(13),char(0),char(40),char(0),char(7),char(0),char(41),char(0), +char(0),char(0),char(21),char(0),char(29),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(13),char(0),char(39),char(0),char(13),char(0),char(42),char(0), +char(7),char(0),char(43),char(0),char(4),char(0),char(44),char(0),char(30),char(0),char(2),char(0),char(13),char(0),char(45),char(0),char(7),char(0),char(46),char(0), +char(31),char(0),char(4),char(0),char(29),char(0),char(47),char(0),char(30),char(0),char(48),char(0),char(4),char(0),char(49),char(0),char(0),char(0),char(37),char(0), +char(32),char(0),char(1),char(0),char(4),char(0),char(50),char(0),char(33),char(0),char(2),char(0),char(2),char(0),char(50),char(0),char(0),char(0),char(51),char(0), +char(34),char(0),char(2),char(0),char(2),char(0),char(52),char(0),char(0),char(0),char(51),char(0),char(35),char(0),char(2),char(0),char(0),char(0),char(52),char(0), +char(0),char(0),char(53),char(0),char(36),char(0),char(8),char(0),char(13),char(0),char(54),char(0),char(14),char(0),char(55),char(0),char(32),char(0),char(56),char(0), +char(34),char(0),char(57),char(0),char(35),char(0),char(58),char(0),char(33),char(0),char(59),char(0),char(4),char(0),char(60),char(0),char(4),char(0),char(61),char(0), +char(37),char(0),char(4),char(0),char(36),char(0),char(62),char(0),char(13),char(0),char(63),char(0),char(4),char(0),char(64),char(0),char(0),char(0),char(37),char(0), +char(38),char(0),char(7),char(0),char(27),char(0),char(38),char(0),char(37),char(0),char(65),char(0),char(25),char(0),char(66),char(0),char(26),char(0),char(67),char(0), +char(39),char(0),char(68),char(0),char(7),char(0),char(43),char(0),char(0),char(0),char(69),char(0),char(40),char(0),char(2),char(0),char(38),char(0),char(70),char(0), +char(13),char(0),char(39),char(0),char(41),char(0),char(4),char(0),char(19),char(0),char(71),char(0),char(27),char(0),char(72),char(0),char(4),char(0),char(73),char(0), +char(7),char(0),char(74),char(0),char(42),char(0),char(4),char(0),char(27),char(0),char(38),char(0),char(41),char(0),char(75),char(0),char(4),char(0),char(76),char(0), +char(7),char(0),char(43),char(0),char(43),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0), +char(44),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(78),char(0),char(0),char(0),char(37),char(0),char(45),char(0),char(3),char(0), +char(29),char(0),char(47),char(0),char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),char(46),char(0),char(4),char(0),char(4),char(0),char(79),char(0), +char(7),char(0),char(80),char(0),char(7),char(0),char(81),char(0),char(7),char(0),char(82),char(0),char(39),char(0),char(14),char(0),char(4),char(0),char(83),char(0), +char(4),char(0),char(84),char(0),char(46),char(0),char(85),char(0),char(4),char(0),char(86),char(0),char(7),char(0),char(87),char(0),char(7),char(0),char(88),char(0), +char(7),char(0),char(89),char(0),char(7),char(0),char(90),char(0),char(7),char(0),char(91),char(0),char(4),char(0),char(92),char(0),char(4),char(0),char(93),char(0), +char(4),char(0),char(94),char(0),char(4),char(0),char(95),char(0),char(0),char(0),char(37),char(0),char(47),char(0),char(5),char(0),char(27),char(0),char(38),char(0), +char(37),char(0),char(65),char(0),char(13),char(0),char(39),char(0),char(7),char(0),char(43),char(0),char(4),char(0),char(96),char(0),char(48),char(0),char(5),char(0), +char(29),char(0),char(47),char(0),char(13),char(0),char(97),char(0),char(14),char(0),char(98),char(0),char(4),char(0),char(99),char(0),char(0),char(0),char(100),char(0), +char(49),char(0),char(27),char(0),char(9),char(0),char(101),char(0),char(9),char(0),char(102),char(0),char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0), +char(20),char(0),char(104),char(0),char(20),char(0),char(105),char(0),char(14),char(0),char(106),char(0),char(14),char(0),char(107),char(0),char(14),char(0),char(108),char(0), +char(8),char(0),char(109),char(0),char(8),char(0),char(110),char(0),char(8),char(0),char(111),char(0),char(8),char(0),char(112),char(0),char(8),char(0),char(113),char(0), +char(8),char(0),char(114),char(0),char(8),char(0),char(115),char(0),char(8),char(0),char(116),char(0),char(8),char(0),char(117),char(0),char(8),char(0),char(118),char(0), +char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0),char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0), +char(4),char(0),char(124),char(0),char(4),char(0),char(125),char(0),char(0),char(0),char(37),char(0),char(50),char(0),char(27),char(0),char(9),char(0),char(101),char(0), +char(9),char(0),char(102),char(0),char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0),char(19),char(0),char(104),char(0),char(19),char(0),char(105),char(0), +char(13),char(0),char(106),char(0),char(13),char(0),char(107),char(0),char(13),char(0),char(108),char(0),char(7),char(0),char(109),char(0),char(7),char(0),char(110),char(0), +char(7),char(0),char(111),char(0),char(7),char(0),char(112),char(0),char(7),char(0),char(113),char(0),char(7),char(0),char(114),char(0),char(7),char(0),char(115),char(0), +char(7),char(0),char(116),char(0),char(7),char(0),char(117),char(0),char(7),char(0),char(118),char(0),char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0), +char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(4),char(0),char(124),char(0),char(4),char(0),char(125),char(0), +char(0),char(0),char(37),char(0),char(51),char(0),char(22),char(0),char(8),char(0),char(126),char(0),char(8),char(0),char(127),char(0),char(8),char(0),char(111),char(0), +char(8),char(0),char(-128),char(0),char(8),char(0),char(115),char(0),char(8),char(0),char(-127),char(0),char(8),char(0),char(-126),char(0),char(8),char(0),char(-125),char(0), +char(8),char(0),char(-124),char(0),char(8),char(0),char(-123),char(0),char(8),char(0),char(-122),char(0),char(8),char(0),char(-121),char(0),char(8),char(0),char(-120),char(0), +char(8),char(0),char(-119),char(0),char(8),char(0),char(-118),char(0),char(8),char(0),char(-117),char(0),char(4),char(0),char(-116),char(0),char(4),char(0),char(-115),char(0), +char(4),char(0),char(-114),char(0),char(4),char(0),char(-113),char(0),char(4),char(0),char(-112),char(0),char(0),char(0),char(37),char(0),char(52),char(0),char(22),char(0), +char(7),char(0),char(126),char(0),char(7),char(0),char(127),char(0),char(7),char(0),char(111),char(0),char(7),char(0),char(-128),char(0),char(7),char(0),char(115),char(0), +char(7),char(0),char(-127),char(0),char(7),char(0),char(-126),char(0),char(7),char(0),char(-125),char(0),char(7),char(0),char(-124),char(0),char(7),char(0),char(-123),char(0), +char(7),char(0),char(-122),char(0),char(7),char(0),char(-121),char(0),char(7),char(0),char(-120),char(0),char(7),char(0),char(-119),char(0),char(7),char(0),char(-118),char(0), +char(7),char(0),char(-117),char(0),char(4),char(0),char(-116),char(0),char(4),char(0),char(-115),char(0),char(4),char(0),char(-114),char(0),char(4),char(0),char(-113),char(0), +char(4),char(0),char(-112),char(0),char(0),char(0),char(37),char(0),char(53),char(0),char(2),char(0),char(51),char(0),char(-111),char(0),char(14),char(0),char(-110),char(0), +char(54),char(0),char(2),char(0),char(52),char(0),char(-111),char(0),char(13),char(0),char(-110),char(0),char(55),char(0),char(21),char(0),char(50),char(0),char(-109),char(0), +char(17),char(0),char(-108),char(0),char(13),char(0),char(-107),char(0),char(13),char(0),char(-106),char(0),char(13),char(0),char(-105),char(0),char(13),char(0),char(-104),char(0), +char(13),char(0),char(-110),char(0),char(13),char(0),char(-103),char(0),char(13),char(0),char(-102),char(0),char(13),char(0),char(-101),char(0),char(13),char(0),char(-100),char(0), +char(7),char(0),char(-99),char(0),char(7),char(0),char(-98),char(0),char(7),char(0),char(-97),char(0),char(7),char(0),char(-96),char(0),char(7),char(0),char(-95),char(0), +char(7),char(0),char(-94),char(0),char(7),char(0),char(-93),char(0),char(7),char(0),char(-92),char(0),char(7),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0), +char(56),char(0),char(22),char(0),char(49),char(0),char(-109),char(0),char(18),char(0),char(-108),char(0),char(14),char(0),char(-107),char(0),char(14),char(0),char(-106),char(0), +char(14),char(0),char(-105),char(0),char(14),char(0),char(-104),char(0),char(14),char(0),char(-110),char(0),char(14),char(0),char(-103),char(0),char(14),char(0),char(-102),char(0), +char(14),char(0),char(-101),char(0),char(14),char(0),char(-100),char(0),char(8),char(0),char(-99),char(0),char(8),char(0),char(-98),char(0),char(8),char(0),char(-97),char(0), +char(8),char(0),char(-96),char(0),char(8),char(0),char(-95),char(0),char(8),char(0),char(-94),char(0),char(8),char(0),char(-93),char(0),char(8),char(0),char(-92),char(0), +char(8),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),char(0),char(0),char(37),char(0),char(57),char(0),char(2),char(0),char(4),char(0),char(-89),char(0), +char(4),char(0),char(-88),char(0),char(58),char(0),char(13),char(0),char(55),char(0),char(-87),char(0),char(55),char(0),char(-86),char(0),char(0),char(0),char(35),char(0), +char(4),char(0),char(-85),char(0),char(4),char(0),char(-84),char(0),char(4),char(0),char(-83),char(0),char(4),char(0),char(-82),char(0),char(7),char(0),char(-81),char(0), +char(7),char(0),char(-80),char(0),char(4),char(0),char(-79),char(0),char(4),char(0),char(-78),char(0),char(7),char(0),char(-77),char(0),char(4),char(0),char(-76),char(0), +char(59),char(0),char(13),char(0),char(60),char(0),char(-87),char(0),char(60),char(0),char(-86),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-85),char(0), +char(4),char(0),char(-84),char(0),char(4),char(0),char(-83),char(0),char(4),char(0),char(-82),char(0),char(7),char(0),char(-81),char(0),char(7),char(0),char(-80),char(0), +char(4),char(0),char(-79),char(0),char(4),char(0),char(-78),char(0),char(7),char(0),char(-77),char(0),char(4),char(0),char(-76),char(0),char(61),char(0),char(14),char(0), +char(56),char(0),char(-87),char(0),char(56),char(0),char(-86),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-85),char(0),char(4),char(0),char(-84),char(0), +char(4),char(0),char(-83),char(0),char(4),char(0),char(-82),char(0),char(8),char(0),char(-81),char(0),char(8),char(0),char(-80),char(0),char(4),char(0),char(-79),char(0), +char(4),char(0),char(-78),char(0),char(8),char(0),char(-77),char(0),char(4),char(0),char(-76),char(0),char(0),char(0),char(-75),char(0),char(62),char(0),char(3),char(0), +char(59),char(0),char(-74),char(0),char(13),char(0),char(-73),char(0),char(13),char(0),char(-72),char(0),char(63),char(0),char(3),char(0),char(61),char(0),char(-74),char(0), +char(14),char(0),char(-73),char(0),char(14),char(0),char(-72),char(0),char(64),char(0),char(3),char(0),char(59),char(0),char(-74),char(0),char(14),char(0),char(-73),char(0), +char(14),char(0),char(-72),char(0),char(65),char(0),char(13),char(0),char(59),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0), +char(4),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),char(4),char(0),char(-67),char(0),char(7),char(0),char(-66),char(0),char(7),char(0),char(-65),char(0), +char(7),char(0),char(-64),char(0),char(7),char(0),char(-63),char(0),char(7),char(0),char(-62),char(0),char(7),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0), +char(66),char(0),char(13),char(0),char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(4),char(0),char(-69),char(0), +char(4),char(0),char(-68),char(0),char(4),char(0),char(-67),char(0),char(7),char(0),char(-66),char(0),char(7),char(0),char(-65),char(0),char(7),char(0),char(-64),char(0), +char(7),char(0),char(-63),char(0),char(7),char(0),char(-62),char(0),char(7),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0),char(67),char(0),char(14),char(0), +char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),char(4),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0), +char(4),char(0),char(-67),char(0),char(8),char(0),char(-66),char(0),char(8),char(0),char(-65),char(0),char(8),char(0),char(-64),char(0),char(8),char(0),char(-63),char(0), +char(8),char(0),char(-62),char(0),char(8),char(0),char(-61),char(0),char(8),char(0),char(-60),char(0),char(0),char(0),char(-59),char(0),char(68),char(0),char(10),char(0), +char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),char(8),char(0),char(-58),char(0),char(8),char(0),char(-57),char(0), +char(8),char(0),char(-56),char(0),char(8),char(0),char(-62),char(0),char(8),char(0),char(-61),char(0),char(8),char(0),char(-60),char(0),char(8),char(0),char(127),char(0), +char(69),char(0),char(11),char(0),char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(7),char(0),char(-58),char(0), +char(7),char(0),char(-57),char(0),char(7),char(0),char(-56),char(0),char(7),char(0),char(-62),char(0),char(7),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0), +char(7),char(0),char(127),char(0),char(0),char(0),char(21),char(0),char(70),char(0),char(9),char(0),char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0), +char(19),char(0),char(-70),char(0),char(13),char(0),char(-55),char(0),char(13),char(0),char(-54),char(0),char(13),char(0),char(-53),char(0),char(13),char(0),char(-52),char(0), +char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0),char(71),char(0),char(9),char(0),char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0), +char(20),char(0),char(-70),char(0),char(14),char(0),char(-55),char(0),char(14),char(0),char(-54),char(0),char(14),char(0),char(-53),char(0),char(14),char(0),char(-52),char(0), +char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0),char(72),char(0),char(5),char(0),char(70),char(0),char(-49),char(0),char(4),char(0),char(-48),char(0), +char(7),char(0),char(-47),char(0),char(7),char(0),char(-46),char(0),char(7),char(0),char(-45),char(0),char(73),char(0),char(5),char(0),char(71),char(0),char(-49),char(0), +char(4),char(0),char(-48),char(0),char(8),char(0),char(-47),char(0),char(8),char(0),char(-46),char(0),char(8),char(0),char(-45),char(0),char(74),char(0),char(41),char(0), +char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(13),char(0),char(-55),char(0),char(13),char(0),char(-54),char(0), +char(13),char(0),char(-44),char(0),char(13),char(0),char(-43),char(0),char(13),char(0),char(-42),char(0),char(13),char(0),char(-41),char(0),char(13),char(0),char(-40),char(0), +char(13),char(0),char(-39),char(0),char(13),char(0),char(-38),char(0),char(13),char(0),char(-37),char(0),char(13),char(0),char(-36),char(0),char(13),char(0),char(-35),char(0), +char(13),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0),char(0),char(0),char(-32),char(0),char(0),char(0),char(-31),char(0),char(0),char(0),char(-30),char(0), +char(0),char(0),char(-29),char(0),char(0),char(0),char(-59),char(0),char(13),char(0),char(-53),char(0),char(13),char(0),char(-52),char(0),char(13),char(0),char(-28),char(0), +char(13),char(0),char(-27),char(0),char(13),char(0),char(-26),char(0),char(13),char(0),char(-25),char(0),char(13),char(0),char(-24),char(0),char(13),char(0),char(-23),char(0), +char(13),char(0),char(-22),char(0),char(13),char(0),char(-21),char(0),char(13),char(0),char(-20),char(0),char(13),char(0),char(-19),char(0),char(13),char(0),char(-18),char(0), +char(0),char(0),char(-17),char(0),char(0),char(0),char(-16),char(0),char(0),char(0),char(-15),char(0),char(0),char(0),char(-14),char(0),char(0),char(0),char(-13),char(0), +char(4),char(0),char(-12),char(0),char(75),char(0),char(41),char(0),char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0), +char(14),char(0),char(-55),char(0),char(14),char(0),char(-54),char(0),char(14),char(0),char(-44),char(0),char(14),char(0),char(-43),char(0),char(14),char(0),char(-42),char(0), +char(14),char(0),char(-41),char(0),char(14),char(0),char(-40),char(0),char(14),char(0),char(-39),char(0),char(14),char(0),char(-38),char(0),char(14),char(0),char(-37),char(0), +char(14),char(0),char(-36),char(0),char(14),char(0),char(-35),char(0),char(14),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0),char(0),char(0),char(-32),char(0), +char(0),char(0),char(-31),char(0),char(0),char(0),char(-30),char(0),char(0),char(0),char(-29),char(0),char(0),char(0),char(-59),char(0),char(14),char(0),char(-53),char(0), +char(14),char(0),char(-52),char(0),char(14),char(0),char(-28),char(0),char(14),char(0),char(-27),char(0),char(14),char(0),char(-26),char(0),char(14),char(0),char(-25),char(0), +char(14),char(0),char(-24),char(0),char(14),char(0),char(-23),char(0),char(14),char(0),char(-22),char(0),char(14),char(0),char(-21),char(0),char(14),char(0),char(-20),char(0), +char(14),char(0),char(-19),char(0),char(14),char(0),char(-18),char(0),char(0),char(0),char(-17),char(0),char(0),char(0),char(-16),char(0),char(0),char(0),char(-15),char(0), +char(0),char(0),char(-14),char(0),char(0),char(0),char(-13),char(0),char(4),char(0),char(-12),char(0),char(76),char(0),char(9),char(0),char(59),char(0),char(-74),char(0), +char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(7),char(0),char(-55),char(0),char(7),char(0),char(-54),char(0),char(7),char(0),char(-53),char(0), +char(7),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0),char(77),char(0),char(9),char(0),char(61),char(0),char(-74),char(0), +char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),char(8),char(0),char(-55),char(0),char(8),char(0),char(-54),char(0),char(8),char(0),char(-53),char(0), +char(8),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0),char(78),char(0),char(5),char(0),char(58),char(0),char(-74),char(0), +char(13),char(0),char(-11),char(0),char(13),char(0),char(-10),char(0),char(7),char(0),char(-9),char(0),char(0),char(0),char(37),char(0),char(79),char(0),char(4),char(0), +char(61),char(0),char(-74),char(0),char(14),char(0),char(-11),char(0),char(14),char(0),char(-10),char(0),char(8),char(0),char(-9),char(0),char(80),char(0),char(4),char(0), +char(7),char(0),char(-8),char(0),char(7),char(0),char(-7),char(0),char(7),char(0),char(-6),char(0),char(4),char(0),char(79),char(0),char(81),char(0),char(10),char(0), +char(80),char(0),char(-5),char(0),char(13),char(0),char(-4),char(0),char(13),char(0),char(-3),char(0),char(13),char(0),char(-2),char(0),char(13),char(0),char(-1),char(0), +char(13),char(0),char(0),char(1),char(7),char(0),char(-99),char(0),char(7),char(0),char(1),char(1),char(4),char(0),char(2),char(1),char(4),char(0),char(53),char(0), +char(82),char(0),char(4),char(0),char(80),char(0),char(-5),char(0),char(4),char(0),char(3),char(1),char(7),char(0),char(4),char(1),char(4),char(0),char(5),char(1), +char(83),char(0),char(4),char(0),char(13),char(0),char(0),char(1),char(80),char(0),char(-5),char(0),char(4),char(0),char(6),char(1),char(7),char(0),char(7),char(1), +char(84),char(0),char(7),char(0),char(13),char(0),char(8),char(1),char(80),char(0),char(-5),char(0),char(4),char(0),char(9),char(1),char(7),char(0),char(10),char(1), +char(7),char(0),char(11),char(1),char(7),char(0),char(12),char(1),char(4),char(0),char(53),char(0),char(85),char(0),char(6),char(0),char(17),char(0),char(13),char(1), +char(13),char(0),char(11),char(1),char(13),char(0),char(14),char(1),char(60),char(0),char(15),char(1),char(4),char(0),char(16),char(1),char(7),char(0),char(12),char(1), +char(86),char(0),char(26),char(0),char(4),char(0),char(17),char(1),char(7),char(0),char(18),char(1),char(7),char(0),char(127),char(0),char(7),char(0),char(19),char(1), +char(7),char(0),char(20),char(1),char(7),char(0),char(21),char(1),char(7),char(0),char(22),char(1),char(7),char(0),char(23),char(1),char(7),char(0),char(24),char(1), +char(7),char(0),char(25),char(1),char(7),char(0),char(26),char(1),char(7),char(0),char(27),char(1),char(7),char(0),char(28),char(1),char(7),char(0),char(29),char(1), +char(7),char(0),char(30),char(1),char(7),char(0),char(31),char(1),char(7),char(0),char(32),char(1),char(7),char(0),char(33),char(1),char(7),char(0),char(34),char(1), +char(7),char(0),char(35),char(1),char(7),char(0),char(36),char(1),char(4),char(0),char(37),char(1),char(4),char(0),char(38),char(1),char(4),char(0),char(39),char(1), +char(4),char(0),char(40),char(1),char(4),char(0),char(120),char(0),char(87),char(0),char(12),char(0),char(17),char(0),char(41),char(1),char(17),char(0),char(42),char(1), +char(17),char(0),char(43),char(1),char(13),char(0),char(44),char(1),char(13),char(0),char(45),char(1),char(7),char(0),char(46),char(1),char(4),char(0),char(47),char(1), +char(4),char(0),char(48),char(1),char(4),char(0),char(49),char(1),char(4),char(0),char(50),char(1),char(7),char(0),char(10),char(1),char(4),char(0),char(53),char(0), +char(88),char(0),char(27),char(0),char(19),char(0),char(51),char(1),char(17),char(0),char(52),char(1),char(17),char(0),char(53),char(1),char(13),char(0),char(44),char(1), +char(13),char(0),char(54),char(1),char(13),char(0),char(55),char(1),char(13),char(0),char(56),char(1),char(13),char(0),char(57),char(1),char(13),char(0),char(58),char(1), +char(4),char(0),char(59),char(1),char(7),char(0),char(60),char(1),char(4),char(0),char(61),char(1),char(4),char(0),char(62),char(1),char(4),char(0),char(63),char(1), +char(7),char(0),char(64),char(1),char(7),char(0),char(65),char(1),char(4),char(0),char(66),char(1),char(4),char(0),char(67),char(1),char(7),char(0),char(68),char(1), +char(7),char(0),char(69),char(1),char(7),char(0),char(70),char(1),char(7),char(0),char(71),char(1),char(7),char(0),char(72),char(1),char(7),char(0),char(73),char(1), +char(4),char(0),char(74),char(1),char(4),char(0),char(75),char(1),char(4),char(0),char(76),char(1),char(89),char(0),char(12),char(0),char(9),char(0),char(77),char(1), +char(9),char(0),char(78),char(1),char(13),char(0),char(79),char(1),char(7),char(0),char(80),char(1),char(7),char(0),char(-125),char(0),char(7),char(0),char(81),char(1), +char(4),char(0),char(82),char(1),char(13),char(0),char(83),char(1),char(4),char(0),char(84),char(1),char(4),char(0),char(85),char(1),char(4),char(0),char(86),char(1), +char(4),char(0),char(53),char(0),char(90),char(0),char(19),char(0),char(50),char(0),char(-109),char(0),char(87),char(0),char(87),char(1),char(80),char(0),char(88),char(1), +char(81),char(0),char(89),char(1),char(82),char(0),char(90),char(1),char(83),char(0),char(91),char(1),char(84),char(0),char(92),char(1),char(85),char(0),char(93),char(1), +char(88),char(0),char(94),char(1),char(89),char(0),char(95),char(1),char(4),char(0),char(96),char(1),char(4),char(0),char(62),char(1),char(4),char(0),char(97),char(1), +char(4),char(0),char(98),char(1),char(4),char(0),char(99),char(1),char(4),char(0),char(100),char(1),char(4),char(0),char(101),char(1),char(4),char(0),char(102),char(1), +char(86),char(0),char(103),char(1),char(91),char(0),char(24),char(0),char(16),char(0),char(104),char(1),char(14),char(0),char(105),char(1),char(14),char(0),char(106),char(1), +char(14),char(0),char(107),char(1),char(14),char(0),char(108),char(1),char(14),char(0),char(109),char(1),char(8),char(0),char(110),char(1),char(4),char(0),char(111),char(1), +char(4),char(0),char(86),char(1),char(4),char(0),char(112),char(1),char(4),char(0),char(113),char(1),char(8),char(0),char(114),char(1),char(8),char(0),char(115),char(1), +char(8),char(0),char(116),char(1),char(8),char(0),char(117),char(1),char(8),char(0),char(118),char(1),char(8),char(0),char(119),char(1),char(8),char(0),char(120),char(1), +char(8),char(0),char(121),char(1),char(8),char(0),char(122),char(1),char(0),char(0),char(123),char(1),char(0),char(0),char(124),char(1),char(49),char(0),char(125),char(1), +char(0),char(0),char(126),char(1),char(92),char(0),char(24),char(0),char(15),char(0),char(104),char(1),char(13),char(0),char(105),char(1),char(13),char(0),char(106),char(1), +char(13),char(0),char(107),char(1),char(13),char(0),char(108),char(1),char(13),char(0),char(109),char(1),char(4),char(0),char(112),char(1),char(7),char(0),char(110),char(1), +char(4),char(0),char(111),char(1),char(4),char(0),char(86),char(1),char(7),char(0),char(114),char(1),char(7),char(0),char(115),char(1),char(7),char(0),char(116),char(1), +char(4),char(0),char(113),char(1),char(7),char(0),char(117),char(1),char(7),char(0),char(118),char(1),char(7),char(0),char(119),char(1),char(7),char(0),char(120),char(1), +char(7),char(0),char(121),char(1),char(7),char(0),char(122),char(1),char(0),char(0),char(123),char(1),char(0),char(0),char(124),char(1),char(50),char(0),char(125),char(1), +char(0),char(0),char(126),char(1),char(93),char(0),char(9),char(0),char(20),char(0),char(127),char(1),char(14),char(0),char(-128),char(1),char(8),char(0),char(-127),char(1), +char(0),char(0),char(-126),char(1),char(91),char(0),char(90),char(1),char(49),char(0),char(-125),char(1),char(0),char(0),char(126),char(1),char(4),char(0),char(97),char(1), +char(0),char(0),char(37),char(0),char(94),char(0),char(7),char(0),char(0),char(0),char(-126),char(1),char(92),char(0),char(90),char(1),char(50),char(0),char(-125),char(1), +char(19),char(0),char(127),char(1),char(13),char(0),char(-128),char(1),char(7),char(0),char(-127),char(1),char(4),char(0),char(97),char(1),}; +int sBulletDNAlen= sizeof(sBulletDNAstr); diff --git a/extern/bullet2/src/LinearMath/btSerializer.h b/extern/bullet/src/LinearMath/btSerializer.h similarity index 97% rename from extern/bullet2/src/LinearMath/btSerializer.h rename to extern/bullet/src/LinearMath/btSerializer.h index 033895b1e5ec..89b4d7468386 100644 --- a/extern/bullet2/src/LinearMath/btSerializer.h +++ b/extern/bullet/src/LinearMath/btSerializer.h @@ -26,7 +26,7 @@ subject to the following restrictions: -///only the 32bit versions for now + extern char sBulletDNAstr[]; extern int sBulletDNAlen; extern char sBulletDNAstr64[]; @@ -391,7 +391,8 @@ class btDefaultSerializer : public btSerializer btDefaultSerializer(int totalSize=0, unsigned char* buffer=0) - :m_totalSize(totalSize), + :m_uniqueIdGenerator(0), + m_totalSize(totalSize), m_currentSize(0), m_dna(0), m_dnaLength(0), @@ -446,6 +447,26 @@ class btDefaultSerializer : public btSerializer btAlignedFree(m_dna); } + static int getMemoryDnaSizeInBytes() + { + const bool VOID_IS_8 = ((sizeof(void*) == 8)); + + if (VOID_IS_8) + { + return sBulletDNAlen64; + } + return sBulletDNAlen; + } + static const char* getMemoryDna() + { + const bool VOID_IS_8 = ((sizeof(void*) == 8)); + if (VOID_IS_8) + { + return (const char*)sBulletDNAstr64; + } + return (const char*)sBulletDNAstr; + } + void insertHeader() { writeHeader(m_buffer); @@ -484,7 +505,7 @@ class btDefaultSerializer : public btSerializer buffer[9] = '2'; buffer[10] = '8'; - buffer[11] = '4'; + buffer[11] = '7'; } @@ -541,6 +562,7 @@ class btDefaultSerializer : public btSerializer virtual void* getUniquePointer(void*oldPtr) { + btAssert(m_uniqueIdGenerator >= 0); if (!oldPtr) return 0; diff --git a/extern/bullet/src/LinearMath/btSerializer64.cpp b/extern/bullet/src/LinearMath/btSerializer64.cpp new file mode 100644 index 000000000000..05f59202d725 --- /dev/null +++ b/extern/bullet/src/LinearMath/btSerializer64.cpp @@ -0,0 +1,599 @@ +char sBulletDNAstr64[]= { +char(83),char(68),char(78),char(65),char(78),char(65),char(77),char(69),char(-124),char(1),char(0),char(0),char(109),char(95),char(115),char(105),char(122),char(101),char(0),char(109), +char(95),char(99),char(97),char(112),char(97),char(99),char(105),char(116),char(121),char(0),char(42),char(109),char(95),char(100),char(97),char(116),char(97),char(0),char(109),char(95), +char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(115),char(0),char(109),char(95),char(99),char(111), +char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(115),char(0),char(109),char(95),char(99),char(111),char(110), +char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(115),char(0),char(42),char(102),char(105),char(114),char(115),char(116),char(0),char(42),char(108),char(97),char(115), +char(116),char(0),char(109),char(95),char(102),char(108),char(111),char(97),char(116),char(115),char(91),char(52),char(93),char(0),char(109),char(95),char(101),char(108),char(91),char(51), +char(93),char(0),char(109),char(95),char(98),char(97),char(115),char(105),char(115),char(0),char(109),char(95),char(111),char(114),char(105),char(103),char(105),char(110),char(0),char(109), +char(95),char(114),char(111),char(111),char(116),char(78),char(111),char(100),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(115),char(117),char(98), +char(116),char(114),char(101),char(101),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100), +char(65),char(97),char(98),char(98),char(77),char(105),char(110),char(91),char(51),char(93),char(0),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122), +char(101),char(100),char(65),char(97),char(98),char(98),char(77),char(97),char(120),char(91),char(51),char(93),char(0),char(109),char(95),char(97),char(97),char(98),char(98),char(77), +char(105),char(110),char(79),char(114),char(103),char(0),char(109),char(95),char(97),char(97),char(98),char(98),char(77),char(97),char(120),char(79),char(114),char(103),char(0),char(109), +char(95),char(101),char(115),char(99),char(97),char(112),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(115),char(117),char(98),char(80),char(97), +char(114),char(116),char(0),char(109),char(95),char(116),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109), +char(95),char(112),char(97),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(101),char(115),char(99),char(97),char(112),char(101),char(73),char(110),char(100),char(101), +char(120),char(79),char(114),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(98), +char(118),char(104),char(65),char(97),char(98),char(98),char(77),char(105),char(110),char(0),char(109),char(95),char(98),char(118),char(104),char(65),char(97),char(98),char(98),char(77), +char(97),char(120),char(0),char(109),char(95),char(98),char(118),char(104),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(97),char(116),char(105),char(111),char(110), +char(0),char(109),char(95),char(99),char(117),char(114),char(78),char(111),char(100),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(117),char(115), +char(101),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(97),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(110),char(117),char(109),char(67), +char(111),char(110),char(116),char(105),char(103),char(117),char(111),char(117),char(115),char(76),char(101),char(97),char(102),char(78),char(111),char(100),char(101),char(115),char(0),char(109), +char(95),char(110),char(117),char(109),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(67),char(111),char(110),char(116),char(105),char(103),char(117), +char(111),char(117),char(115),char(78),char(111),char(100),char(101),char(115),char(0),char(42),char(109),char(95),char(99),char(111),char(110),char(116),char(105),char(103),char(117),char(111), +char(117),char(115),char(78),char(111),char(100),char(101),char(115),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105), +char(122),char(101),char(100),char(67),char(111),char(110),char(116),char(105),char(103),char(117),char(111),char(117),char(115),char(78),char(111),char(100),char(101),char(115),char(80),char(116), +char(114),char(0),char(42),char(109),char(95),char(115),char(117),char(98),char(84),char(114),char(101),char(101),char(73),char(110),char(102),char(111),char(80),char(116),char(114),char(0), +char(109),char(95),char(116),char(114),char(97),char(118),char(101),char(114),char(115),char(97),char(108),char(77),char(111),char(100),char(101),char(0),char(109),char(95),char(110),char(117), +char(109),char(83),char(117),char(98),char(116),char(114),char(101),char(101),char(72),char(101),char(97),char(100),char(101),char(114),char(115),char(0),char(42),char(109),char(95),char(110), +char(97),char(109),char(101),char(0),char(109),char(95),char(115),char(104),char(97),char(112),char(101),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(112),char(97), +char(100),char(100),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110), +char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(83),char(99),char(97), +char(108),char(105),char(110),char(103),char(0),char(109),char(95),char(112),char(108),char(97),char(110),char(101),char(78),char(111),char(114),char(109),char(97),char(108),char(0),char(109), +char(95),char(112),char(108),char(97),char(110),char(101),char(67),char(111),char(110),char(115),char(116),char(97),char(110),char(116),char(0),char(109),char(95),char(105),char(109),char(112), +char(108),char(105),char(99),char(105),char(116),char(83),char(104),char(97),char(112),char(101),char(68),char(105),char(109),char(101),char(110),char(115),char(105),char(111),char(110),char(115), +char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(77),char(97),char(114),char(103),char(105),char(110),char(0),char(109), +char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(0),char(109),char(95),char(112),char(111),char(115),char(0),char(109),char(95),char(114),char(97),char(100), +char(105),char(117),char(115),char(0),char(109),char(95),char(99),char(111),char(110),char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114),char(110),char(97),char(108), +char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(42),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(80),char(111), +char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(114),char(114),char(97),char(121),char(80),char(116),char(114),char(0),char(109),char(95),char(108),char(111),char(99), +char(97),char(108),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(114),char(114),char(97),char(121),char(83),char(105),char(122),char(101),char(0), +char(109),char(95),char(118),char(97),char(108),char(117),char(101),char(0),char(109),char(95),char(112),char(97),char(100),char(91),char(50),char(93),char(0),char(109),char(95),char(118), +char(97),char(108),char(117),char(101),char(115),char(91),char(51),char(93),char(0),char(109),char(95),char(112),char(97),char(100),char(0),char(42),char(109),char(95),char(118),char(101), +char(114),char(116),char(105),char(99),char(101),char(115),char(51),char(102),char(0),char(42),char(109),char(95),char(118),char(101),char(114),char(116),char(105),char(99),char(101),char(115), +char(51),char(100),char(0),char(42),char(109),char(95),char(105),char(110),char(100),char(105),char(99),char(101),char(115),char(51),char(50),char(0),char(42),char(109),char(95),char(51), +char(105),char(110),char(100),char(105),char(99),char(101),char(115),char(49),char(54),char(0),char(42),char(109),char(95),char(51),char(105),char(110),char(100),char(105),char(99),char(101), +char(115),char(56),char(0),char(42),char(109),char(95),char(105),char(110),char(100),char(105),char(99),char(101),char(115),char(49),char(54),char(0),char(109),char(95),char(110),char(117), +char(109),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(86),char(101),char(114),char(116), +char(105),char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(109),char(101),char(115),char(104),char(80),char(97),char(114),char(116),char(115),char(80),char(116),char(114), +char(0),char(109),char(95),char(115),char(99),char(97),char(108),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(101),char(115),char(104), +char(80),char(97),char(114),char(116),char(115),char(0),char(109),char(95),char(109),char(101),char(115),char(104),char(73),char(110),char(116),char(101),char(114),char(102),char(97),char(99), +char(101),char(0),char(42),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(70),char(108),char(111),char(97),char(116),char(66), +char(118),char(104),char(0),char(42),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(68),char(111),char(117),char(98),char(108), +char(101),char(66),char(118),char(104),char(0),char(42),char(109),char(95),char(116),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111), +char(77),char(97),char(112),char(0),char(109),char(95),char(112),char(97),char(100),char(51),char(91),char(52),char(93),char(0),char(109),char(95),char(116),char(114),char(105),char(109), +char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(116),char(114),char(97),char(110),char(115), +char(102),char(111),char(114),char(109),char(0),char(42),char(109),char(95),char(99),char(104),char(105),char(108),char(100),char(83),char(104),char(97),char(112),char(101),char(0),char(109), +char(95),char(99),char(104),char(105),char(108),char(100),char(83),char(104),char(97),char(112),char(101),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(99),char(104), +char(105),char(108),char(100),char(77),char(97),char(114),char(103),char(105),char(110),char(0),char(42),char(109),char(95),char(99),char(104),char(105),char(108),char(100),char(83),char(104), +char(97),char(112),char(101),char(80),char(116),char(114),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(104),char(105),char(108),char(100),char(83),char(104),char(97), +char(112),char(101),char(115),char(0),char(109),char(95),char(117),char(112),char(65),char(120),char(105),char(115),char(0),char(109),char(95),char(117),char(112),char(73),char(110),char(100), +char(101),char(120),char(0),char(109),char(95),char(102),char(108),char(97),char(103),char(115),char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(86),char(48),char(86), +char(49),char(65),char(110),char(103),char(108),char(101),char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(86),char(49),char(86),char(50),char(65),char(110),char(103), +char(108),char(101),char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(86),char(50),char(86),char(48),char(65),char(110),char(103),char(108),char(101),char(0),char(42), +char(109),char(95),char(104),char(97),char(115),char(104),char(84),char(97),char(98),char(108),char(101),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(110),char(101), +char(120),char(116),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(118),char(97),char(108),char(117),char(101),char(65),char(114),char(114),char(97),char(121),char(80), +char(116),char(114),char(0),char(42),char(109),char(95),char(107),char(101),char(121),char(65),char(114),char(114),char(97),char(121),char(80),char(116),char(114),char(0),char(109),char(95), +char(99),char(111),char(110),char(118),char(101),char(120),char(69),char(112),char(115),char(105),char(108),char(111),char(110),char(0),char(109),char(95),char(112),char(108),char(97),char(110), +char(97),char(114),char(69),char(112),char(115),char(105),char(108),char(111),char(110),char(0),char(109),char(95),char(101),char(113),char(117),char(97),char(108),char(86),char(101),char(114), +char(116),char(101),char(120),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(68), +char(105),char(115),char(116),char(97),char(110),char(99),char(101),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(122), +char(101),char(114),char(111),char(65),char(114),char(101),char(97),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(110), +char(101),char(120),char(116),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(104),char(97),char(115),char(104),char(84),char(97),char(98),char(108),char(101),char(83), +char(105),char(122),char(101),char(0),char(109),char(95),char(110),char(117),char(109),char(86),char(97),char(108),char(117),char(101),char(115),char(0),char(109),char(95),char(110),char(117), +char(109),char(75),char(101),char(121),char(115),char(0),char(109),char(95),char(103),char(105),char(109),char(112),char(97),char(99),char(116),char(83),char(117),char(98),char(84),char(121), +char(112),char(101),char(0),char(42),char(109),char(95),char(117),char(110),char(115),char(99),char(97),char(108),char(101),char(100),char(80),char(111),char(105),char(110),char(116),char(115), +char(70),char(108),char(111),char(97),char(116),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(117),char(110),char(115),char(99),char(97),char(108),char(101),char(100), +char(80),char(111),char(105),char(110),char(116),char(115),char(68),char(111),char(117),char(98),char(108),char(101),char(80),char(116),char(114),char(0),char(109),char(95),char(110),char(117), +char(109),char(85),char(110),char(115),char(99),char(97),char(108),char(101),char(100),char(80),char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(112),char(97), +char(100),char(100),char(105),char(110),char(103),char(51),char(91),char(52),char(93),char(0),char(42),char(109),char(95),char(98),char(114),char(111),char(97),char(100),char(112),char(104), +char(97),char(115),char(101),char(72),char(97),char(110),char(100),char(108),char(101),char(0),char(42),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105), +char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(0),char(42),char(109),char(95),char(114),char(111),char(111),char(116),char(67),char(111),char(108),char(108),char(105), +char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(0),char(109),char(95),char(119),char(111),char(114),char(108),char(100),char(84),char(114),char(97), +char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105), +char(111),char(110),char(87),char(111),char(114),char(108),char(100),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(105), +char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105),char(111),char(110),char(76),char(105),char(110),char(101),char(97),char(114),char(86),char(101), +char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105), +char(111),char(110),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95), +char(97),char(110),char(105),char(115),char(111),char(116),char(114),char(111),char(112),char(105),char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0), +char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(99),char(116),char(80),char(114),char(111),char(99),char(101),char(115),char(115),char(105),char(110),char(103),char(84), +char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(100),char(101),char(97),char(99),char(116),char(105),char(118),char(97),char(116), +char(105),char(111),char(110),char(84),char(105),char(109),char(101),char(0),char(109),char(95),char(102),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109), +char(95),char(114),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99), +char(111),char(110),char(116),char(97),char(99),char(116),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(99),char(111),char(110),char(116), +char(97),char(99),char(116),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(105), +char(116),char(117),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(104),char(105),char(116),char(70),char(114),char(97),char(99),char(116),char(105),char(111),char(110), +char(0),char(109),char(95),char(99),char(99),char(100),char(83),char(119),char(101),char(112),char(116),char(83),char(112),char(104),char(101),char(114),char(101),char(82),char(97),char(100), +char(105),char(117),char(115),char(0),char(109),char(95),char(99),char(99),char(100),char(77),char(111),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115), +char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(104),char(97),char(115),char(65),char(110),char(105),char(115),char(111),char(116),char(114),char(111),char(112),char(105), +char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111), +char(110),char(70),char(108),char(97),char(103),char(115),char(0),char(109),char(95),char(105),char(115),char(108),char(97),char(110),char(100),char(84),char(97),char(103),char(49),char(0), +char(109),char(95),char(99),char(111),char(109),char(112),char(97),char(110),char(105),char(111),char(110),char(73),char(100),char(0),char(109),char(95),char(97),char(99),char(116),char(105), +char(118),char(97),char(116),char(105),char(111),char(110),char(83),char(116),char(97),char(116),char(101),char(49),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114), +char(110),char(97),char(108),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(99),char(104),char(101),char(99),char(107),char(67),char(111),char(108),char(108),char(105), +char(100),char(101),char(87),char(105),char(116),char(104),char(0),char(109),char(95),char(116),char(97),char(117),char(0),char(109),char(95),char(100),char(97),char(109),char(112),char(105), +char(110),char(103),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(116),char(101),char(112),char(0),char(109),char(95),char(109),char(97),char(120),char(69), +char(114),char(114),char(111),char(114),char(82),char(101),char(100),char(117),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(115),char(111),char(114),char(0), +char(109),char(95),char(101),char(114),char(112),char(0),char(109),char(95),char(101),char(114),char(112),char(50),char(0),char(109),char(95),char(103),char(108),char(111),char(98),char(97), +char(108),char(67),char(102),char(109),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(80), +char(101),char(110),char(101),char(116),char(114),char(97),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0), +char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(84),char(117),char(114),char(110),char(69),char(114), +char(112),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(111),char(112),char(0),char(109),char(95),char(119),char(97),char(114), +char(109),char(115),char(116),char(97),char(114),char(116),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(109),char(97), +char(120),char(71),char(121),char(114),char(111),char(115),char(99),char(111),char(112),char(105),char(99),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(115), +char(105),char(110),char(103),char(108),char(101),char(65),char(120),char(105),char(115),char(82),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99), +char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(110),char(117),char(109),char(73), +char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(77),char(111), +char(100),char(101),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(105),char(110),char(103),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(82), +char(101),char(115),char(116),char(105),char(116),char(117),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0), +char(109),char(95),char(109),char(105),char(110),char(105),char(109),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(66),char(97),char(116),char(99),char(104), +char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0), +char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(0),char(109),char(95),char(103),char(114),char(97),char(118),char(105), +char(116),char(121),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116), +char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(84),char(101),char(110), +char(115),char(111),char(114),char(87),char(111),char(114),char(108),char(100),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(86),char(101),char(108), +char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111),char(99), +char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114),char(0), +char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(103),char(114),char(97), +char(118),char(105),char(116),char(121),char(95),char(97),char(99),char(99),char(101),char(108),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(0),char(109),char(95), +char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(76),char(111),char(99),char(97),char(108),char(0),char(109),char(95),char(116),char(111), +char(116),char(97),char(108),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(116),char(111),char(116),char(97),char(108),char(84),char(111),char(114),char(113), +char(117),char(101),char(0),char(109),char(95),char(105),char(110),char(118),char(101),char(114),char(115),char(101),char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(108), +char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108), +char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110), +char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(97),char(100), +char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(76),char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110), +char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105), +char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103), +char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116), +char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(70), +char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(101),char(101),char(112),char(105), +char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97), +char(114),char(83),char(108),char(101),char(101),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109), +char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109), +char(95),char(110),char(117),char(109),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(82),char(111),char(119),char(115),char(0),char(110), +char(117),char(98),char(0),char(42),char(109),char(95),char(114),char(98),char(65),char(0),char(42),char(109),char(95),char(114),char(98),char(66),char(0),char(109),char(95),char(111), +char(98),char(106),char(101),char(99),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110),char(115), +char(116),char(114),char(97),char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110), +char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(100),char(0),char(109),char(95),char(110),char(101),char(101),char(100),char(115),char(70),char(101),char(101), +char(100),char(98),char(97),char(99),char(107),char(0),char(109),char(95),char(97),char(112),char(112),char(108),char(105),char(101),char(100),char(73),char(109),char(112),char(117),char(108), +char(115),char(101),char(0),char(109),char(95),char(100),char(98),char(103),char(68),char(114),char(97),char(119),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(100), +char(105),char(115),char(97),char(98),char(108),char(101),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(115),char(66),char(101),char(116),char(119), +char(101),char(101),char(110),char(76),char(105),char(110),char(107),char(101),char(100),char(66),char(111),char(100),char(105),char(101),char(115),char(0),char(109),char(95),char(111),char(118), +char(101),char(114),char(114),char(105),char(100),char(101),char(78),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(116),char(101),char(114),char(97), +char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(98),char(114),char(101),char(97),char(107),char(105),char(110),char(103),char(73),char(109),char(112),char(117), +char(108),char(115),char(101),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(105),char(115),char(69),char(110),char(97), +char(98),char(108),char(101),char(100),char(0),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(116),char(121), +char(112),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(112), +char(105),char(118),char(111),char(116),char(73),char(110),char(65),char(0),char(109),char(95),char(112),char(105),char(118),char(111),char(116),char(73),char(110),char(66),char(0),char(109), +char(95),char(114),char(98),char(65),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(114),char(98),char(66),char(70),char(114),char(97),char(109),char(101), +char(0),char(109),char(95),char(117),char(115),char(101),char(82),char(101),char(102),char(101),char(114),char(101),char(110),char(99),char(101),char(70),char(114),char(97),char(109),char(101), +char(65),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(79),char(110),char(108),char(121),char(0),char(109),char(95),char(101),char(110), +char(97),char(98),char(108),char(101),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(0),char(109),char(95),char(109), +char(111),char(116),char(111),char(114),char(84),char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109), +char(95),char(109),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(108), +char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(117),char(112),char(112),char(101),char(114),char(76),char(105),char(109), +char(105),char(116),char(0),char(109),char(95),char(108),char(105),char(109),char(105),char(116),char(83),char(111),char(102),char(116),char(110),char(101),char(115),char(115),char(0),char(109), +char(95),char(98),char(105),char(97),char(115),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(114),char(101),char(108),char(97),char(120),char(97), +char(116),char(105),char(111),char(110),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103), +char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(49),char(0),char(109),char(95), +char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(50),char(0),char(109),char(95),char(116),char(119),char(105),char(115),char(116),char(83),char(112), +char(97),char(110),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105), +char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116), +char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),char(116), +char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116), +char(0),char(109),char(95),char(117),char(115),char(101),char(76),char(105),char(110),char(101),char(97),char(114),char(82),char(101),char(102),char(101),char(114),char(101),char(110),char(99), +char(101),char(70),char(114),char(97),char(109),char(101),char(65),char(0),char(109),char(95),char(117),char(115),char(101),char(79),char(102),char(102),char(115),char(101),char(116),char(70), +char(111),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95), +char(54),char(100),char(111),char(102),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(69),char(110),char(97), +char(98),char(108),char(101),char(100),char(91),char(54),char(93),char(0),char(109),char(95),char(101),char(113),char(117),char(105),char(108),char(105),char(98),char(114),char(105),char(117), +char(109),char(80),char(111),char(105),char(110),char(116),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(83),char(116), +char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(68), +char(97),char(109),char(112),char(105),char(110),char(103),char(91),char(54),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(66),char(111), +char(117),char(110),char(99),char(101),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82),char(80), +char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95),char(108), +char(105),char(110),char(101),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(108),char(105),char(110),char(101), +char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(84), +char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(108),char(105),char(110),char(101), +char(97),char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(108),char(105), +char(110),char(101),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0),char(109),char(95),char(108),char(105), +char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0), +char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110), +char(103),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105),char(98),char(114),char(105),char(117), +char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(110),char(97),char(98),char(108), +char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(101), +char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114), +char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105), +char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(76), +char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112), +char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52), +char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(66),char(111),char(117),char(110),char(99),char(101),char(0),char(109),char(95), +char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110),char(103), +char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97), +char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(77), +char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(84),char(97),char(114), +char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97), +char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(97),char(110),char(103), +char(117),char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0),char(109),char(95),char(97),char(110), +char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115), +char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112), +char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105),char(98), +char(114),char(105),char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69), +char(110),char(97),char(98),char(108),char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117), +char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(97), +char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91),char(52), +char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105), +char(102),char(102),char(110),char(101),char(115),char(115),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(97), +char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(76), +char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(114),char(111),char(116),char(97),char(116),char(101),char(79),char(114), +char(100),char(101),char(114),char(0),char(109),char(95),char(97),char(120),char(105),char(115),char(73),char(110),char(65),char(0),char(109),char(95),char(97),char(120),char(105),char(115), +char(73),char(110),char(66),char(0),char(109),char(95),char(114),char(97),char(116),char(105),char(111),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114), +char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83), +char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(118),char(111),char(108),char(117),char(109),char(101),char(83),char(116),char(105), +char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(0),char(109), +char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(112),char(114),char(101),char(118),char(105),char(111),char(117),char(115), +char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0), +char(109),char(95),char(97),char(99),char(99),char(117),char(109),char(117),char(108),char(97),char(116),char(101),char(100),char(70),char(111),char(114),char(99),char(101),char(0),char(109), +char(95),char(110),char(111),char(114),char(109),char(97),char(108),char(0),char(109),char(95),char(97),char(114),char(101),char(97),char(0),char(109),char(95),char(97),char(116),char(116), +char(97),char(99),char(104),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(50),char(93), +char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(76),char(101),char(110),char(103),char(116),char(104),char(0),char(109),char(95),char(98),char(98),char(101),char(110), +char(100),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(51), +char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(65),char(114),char(101),char(97),char(0),char(109),char(95),char(99),char(48),char(91),char(52),char(93), +char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(52),char(93),char(0),char(109),char(95), +char(114),char(101),char(115),char(116),char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(99),char(49),char(0),char(109),char(95),char(99),char(50), +char(0),char(109),char(95),char(99),char(48),char(0),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(70),char(114),char(97),char(109),char(101),char(0),char(42), +char(109),char(95),char(114),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110), +char(100),char(101),char(120),char(0),char(109),char(95),char(97),char(101),char(114),char(111),char(77),char(111),char(100),char(101),char(108),char(0),char(109),char(95),char(98),char(97), +char(117),char(109),char(103),char(97),char(114),char(116),char(101),char(0),char(109),char(95),char(100),char(114),char(97),char(103),char(0),char(109),char(95),char(108),char(105),char(102), +char(116),char(0),char(109),char(95),char(112),char(114),char(101),char(115),char(115),char(117),char(114),char(101),char(0),char(109),char(95),char(118),char(111),char(108),char(117),char(109), +char(101),char(0),char(109),char(95),char(100),char(121),char(110),char(97),char(109),char(105),char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0), +char(109),char(95),char(112),char(111),char(115),char(101),char(77),char(97),char(116),char(99),char(104),char(0),char(109),char(95),char(114),char(105),char(103),char(105),char(100),char(67), +char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(107),char(105),char(110), +char(101),char(116),char(105),char(99),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0), +char(109),char(95),char(115),char(111),char(102),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115), +char(115),char(0),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109), +char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114), +char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75),char(105),char(110),char(101),char(116),char(105),char(99),char(67), +char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102), +char(116),char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115), +char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73), +char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75),char(105), +char(110),char(101),char(116),char(105),char(99),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83), +char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116), +char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(109),char(97),char(120), +char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(99),char(97),char(108),char(101),char(0),char(109), +char(95),char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0), +char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115), +char(0),char(109),char(95),char(100),char(114),char(105),char(102),char(116),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109), +char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109), +char(95),char(114),char(111),char(116),char(0),char(109),char(95),char(115),char(99),char(97),char(108),char(101),char(0),char(109),char(95),char(97),char(113),char(113),char(0),char(109), +char(95),char(99),char(111),char(109),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(115),char(0),char(42),char(109), +char(95),char(119),char(101),char(105),char(103),char(104),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(80),char(111),char(115),char(105),char(116),char(105), +char(111),char(110),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(87),char(101),char(105),char(103),char(116),char(115),char(0),char(109),char(95),char(98),char(118), +char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(98),char(102),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(102),char(114),char(97), +char(109),char(101),char(120),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(108),char(111),char(99),char(105),char(105),char(0),char(109),char(95),char(105),char(110), +char(118),char(119),char(105),char(0),char(109),char(95),char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93),char(0),char(109), +char(95),char(100),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(108),char(118),char(0),char(109), +char(95),char(97),char(118),char(0),char(42),char(109),char(95),char(102),char(114),char(97),char(109),char(101),char(114),char(101),char(102),char(115),char(0),char(42),char(109),char(95), +char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(115),char(115),char(101), +char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(114),char(97),char(109),char(101),char(82),char(101),char(102),char(115),char(0),char(109),char(95),char(110), +char(117),char(109),char(78),char(111),char(100),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(115),char(115),char(101),char(115),char(0), +char(109),char(95),char(105),char(100),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(105),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(110), +char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(105),char(109),char(112),char(117),char(108),char(115), +char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(108),char(100),char(97),char(109), +char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97), +char(116),char(99),char(104),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97),char(120),char(83),char(101),char(108),char(102),char(67),char(111),char(108),char(108), +char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(115),char(101),char(108),char(102),char(67), +char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(70),char(97),char(99),char(116),char(111), +char(114),char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(105),char(110),char(115),char(65),char(110),char(99),char(104),char(111),char(114),char(0),char(109), +char(95),char(99),char(111),char(108),char(108),char(105),char(100),char(101),char(0),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(110), +char(100),char(101),char(120),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121), +char(66),char(0),char(109),char(95),char(114),char(101),char(102),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(99),char(102),char(109),char(0),char(109),char(95), +char(115),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(100),char(101),char(108),char(101),char(116),char(101),char(0),char(109),char(95),char(114),char(101),char(108), +char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(91),char(50),char(93),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(116), +char(121),char(112),char(101),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(66),char(116),char(121),char(112),char(101),char(0),char(109),char(95),char(106),char(111), +char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(101),char(0),char(42),char(42),char(109),char(95), +char(109),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(42),char(109),char(95),char(110),char(111),char(100),char(101),char(115),char(0),char(42), +char(109),char(95),char(108),char(105),char(110),char(107),char(115),char(0),char(42),char(109),char(95),char(102),char(97),char(99),char(101),char(115),char(0),char(42),char(109),char(95), +char(116),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(42),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114), +char(115),char(0),char(42),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(115),char(0),char(42),char(109),char(95),char(106),char(111),char(105), +char(110),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(109), +char(95),char(110),char(117),char(109),char(76),char(105),char(110),char(107),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(97),char(99),char(101),char(115), +char(0),char(109),char(95),char(110),char(117),char(109),char(84),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(109),char(95),char(110), +char(117),char(109),char(65),char(110),char(99),char(104),char(111),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(108),char(117),char(115),char(116), +char(101),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(74),char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(99),char(111), +char(110),char(102),char(105),char(103),char(0),char(109),char(95),char(122),char(101),char(114),char(111),char(82),char(111),char(116),char(80),char(97),char(114),char(101),char(110),char(116), +char(84),char(111),char(84),char(104),char(105),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(67),char(111),char(109),char(84),char(111), +char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102),char(102),char(115),char(101),char(116),char(0),char(109),char(95),char(116),char(104),char(105),char(115), +char(80),char(105),char(118),char(111),char(116),char(84),char(111),char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102),char(102),char(115),char(101),char(116), +char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(84),char(111),char(112),char(91),char(54),char(93),char(0),char(109), +char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(66),char(111),char(116),char(116),char(111),char(109),char(91),char(54),char(93),char(0), +char(109),char(95),char(108),char(105),char(110),char(107),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(0),char(109),char(95),char(108),char(105),char(110),char(107), +char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(0),char(109), +char(95),char(100),char(111),char(102),char(67),char(111),char(117),char(110),char(116),char(0),char(109),char(95),char(112),char(111),char(115),char(86),char(97),char(114),char(67),char(111), +char(117),char(110),char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(80),char(111),char(115),char(91),char(55),char(93),char(0),char(109),char(95), +char(106),char(111),char(105),char(110),char(116),char(86),char(101),char(108),char(91),char(54),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(84), +char(111),char(114),char(113),char(117),char(101),char(91),char(54),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(68),char(97),char(109),char(112), +char(105),char(110),char(103),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0), +char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95), +char(106),char(111),char(105),char(110),char(116),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(106),char(111), +char(105),char(110),char(116),char(77),char(97),char(120),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(77), +char(97),char(120),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(78),char(97), +char(109),char(101),char(0),char(42),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(108), +char(105),char(110),char(107),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114),char(0),char(42),char(109),char(95),char(112),char(97),char(100),char(100),char(105), +char(110),char(103),char(80),char(116),char(114),char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(87),char(111),char(114),char(108),char(100),char(84),char(114),char(97), +char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(73),char(110),char(101),char(114),char(116),char(105),char(97), +char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(77),char(97),char(115),char(115),char(0),char(42),char(109),char(95),char(98),char(97),char(115),char(101),char(78), +char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(98),char(97),char(115),char(101),char(67),char(111),char(108),char(108),char(105),char(100),char(101),char(114),char(0), +char(84),char(89),char(80),char(69),char(95),char(0),char(0),char(0),char(99),char(104),char(97),char(114),char(0),char(117),char(99),char(104),char(97),char(114),char(0),char(115), +char(104),char(111),char(114),char(116),char(0),char(117),char(115),char(104),char(111),char(114),char(116),char(0),char(105),char(110),char(116),char(0),char(108),char(111),char(110),char(103), +char(0),char(117),char(108),char(111),char(110),char(103),char(0),char(102),char(108),char(111),char(97),char(116),char(0),char(100),char(111),char(117),char(98),char(108),char(101),char(0), +char(118),char(111),char(105),char(100),char(0),char(80),char(111),char(105),char(110),char(116),char(101),char(114),char(65),char(114),char(114),char(97),char(121),char(0),char(98),char(116), +char(80),char(104),char(121),char(115),char(105),char(99),char(115),char(83),char(121),char(115),char(116),char(101),char(109),char(0),char(76),char(105),char(115),char(116),char(66),char(97), +char(115),char(101),char(0),char(98),char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116), +char(97),char(0),char(98),char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116), +char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114),char(110),char(105),char(111),char(110),char(70),char(108),char(111),char(97),char(116),char(68), +char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114),char(110),char(105),char(111),char(110),char(68),char(111),char(117),char(98), +char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(70),char(108), +char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(68), +char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114), +char(109),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111), +char(114),char(109),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(66),char(118),char(104),char(83),char(117), +char(98),char(116),char(114),char(101),char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105), +char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116), +char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101), +char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122), +char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110), +char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116), +char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(68), +char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(97),char(116),char(105),char(99),char(80),char(108),char(97),char(110),char(101),char(83),char(104),char(97), +char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114), +char(110),char(97),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(115),char(105),char(116), +char(105),char(111),char(110),char(65),char(110),char(100),char(82),char(97),char(100),char(105),char(117),char(115),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105), +char(83),char(112),char(104),char(101),char(114),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(73),char(110), +char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110), +char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110), +char(116),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116), +char(67),char(104),char(97),char(114),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97), +char(0),char(98),char(116),char(77),char(101),char(115),char(104),char(80),char(97),char(114),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116), +char(114),char(105),char(100),char(105),char(110),char(103),char(77),char(101),char(115),char(104),char(73),char(110),char(116),char(101),char(114),char(102),char(97),char(99),char(101),char(68), +char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104), +char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110), +char(102),char(111),char(77),char(97),char(112),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(99),char(97),char(108),char(101),char(100),char(84),char(114), +char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0), +char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(67),char(104),char(105),char(108),char(100), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(121),char(108),char(105),char(110),char(100),char(101),char(114),char(83),char(104),char(97),char(112),char(101), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97), +char(0),char(98),char(116),char(67),char(97),char(112),char(115),char(117),char(108),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0), +char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98), +char(116),char(71),char(73),char(109),char(112),char(97),char(99),char(116),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116), +char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118),char(101),char(120),char(72),char(117),char(108),char(108),char(83),char(104),char(97),char(112),char(101),char(68), +char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99), +char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115), +char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98), +char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(68),char(111), +char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(83),char(111), +char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116), +char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115),char(87),char(111),char(114),char(108),char(100),char(68),char(111),char(117),char(98),char(108),char(101),char(68), +char(97),char(116),char(97),char(0),char(98),char(116),char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115),char(87),char(111),char(114),char(108),char(100),char(70), +char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121), +char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100), +char(121),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(115),char(116),char(114), +char(97),char(105),char(110),char(116),char(73),char(110),char(102),char(111),char(49),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110), +char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84), +char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98), +char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(121),char(112), +char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97), +char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115), +char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111), +char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68), +char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80), +char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), +char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101), +char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0), +char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117), +char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116), +char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97), +char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), +char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102), +char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110), +char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111), +char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54), +char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68), +char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114), +char(105),char(110),char(103),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68), +char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112), +char(114),char(105),char(110),char(103),char(50),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0), +char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(50), +char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97), +char(50),char(0),char(98),char(116),char(83),char(108),char(105),char(100),char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116), +char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(108),char(105),char(100),char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97), +char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(97),char(114), +char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0), +char(98),char(116),char(71),char(101),char(97),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98), +char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(77),char(97),char(116),char(101),char(114), +char(105),char(97),char(108),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(78),char(111),char(100),char(101), +char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(68),char(97),char(116), +char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(70),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(83), +char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(84),char(101),char(116),char(114),char(97),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102), +char(116),char(82),char(105),char(103),char(105),char(100),char(65),char(110),char(99),char(104),char(111),char(114),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102), +char(116),char(66),char(111),char(100),char(121),char(67),char(111),char(110),char(102),char(105),char(103),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116), +char(66),char(111),char(100),char(121),char(80),char(111),char(115),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100), +char(121),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66), +char(111),char(100),char(121),char(74),char(111),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66), +char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105), +char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98), +char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(70),char(108),char(111),char(97),char(116),char(68), +char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(68),char(111),char(117),char(98),char(108), +char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(70),char(108),char(111), +char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(0),char(84),char(76),char(69),char(78),char(1),char(0),char(1),char(0),char(2),char(0),char(2),char(0), +char(4),char(0),char(4),char(0),char(4),char(0),char(4),char(0),char(8),char(0),char(0),char(0),char(16),char(0),char(48),char(0),char(16),char(0),char(16),char(0), +char(32),char(0),char(16),char(0),char(32),char(0),char(48),char(0),char(96),char(0),char(64),char(0),char(-128),char(0),char(20),char(0),char(48),char(0),char(80),char(0), +char(16),char(0),char(96),char(0),char(-112),char(0),char(16),char(0),char(56),char(0),char(56),char(0),char(20),char(0),char(72),char(0),char(4),char(0),char(4),char(0), +char(8),char(0),char(4),char(0),char(56),char(0),char(32),char(0),char(80),char(0),char(72),char(0),char(96),char(0),char(80),char(0),char(32),char(0),char(64),char(0), +char(64),char(0),char(64),char(0),char(16),char(0),char(72),char(0),char(80),char(0),char(-16),char(1),char(24),char(1),char(-104),char(0),char(88),char(0),char(-72),char(0), +char(104),char(0),char(0),char(2),char(-64),char(3),char(8),char(0),char(64),char(0),char(64),char(0),char(0),char(0),char(80),char(0),char(96),char(0),char(-112),char(0), +char(-128),char(0),char(104),char(1),char(-24),char(0),char(-104),char(1),char(-120),char(1),char(-32),char(0),char(8),char(1),char(-40),char(1),char(104),char(1),char(-128),char(2), +char(-112),char(2),char(-64),char(4),char(-40),char(0),char(120),char(1),char(104),char(0),char(-104),char(0),char(16),char(0),char(104),char(0),char(24),char(0),char(40),char(0), +char(104),char(0),char(96),char(0),char(104),char(0),char(-56),char(0),char(104),char(1),char(112),char(0),char(-24),char(1),char(0),char(3),char(-104),char(1),char(-48),char(0), +char(112),char(0),char(0),char(0),char(83),char(84),char(82),char(67),char(84),char(0),char(0),char(0),char(10),char(0),char(3),char(0),char(4),char(0),char(0),char(0), +char(4),char(0),char(1),char(0),char(9),char(0),char(2),char(0),char(11),char(0),char(3),char(0),char(10),char(0),char(3),char(0),char(10),char(0),char(4),char(0), +char(10),char(0),char(5),char(0),char(12),char(0),char(2),char(0),char(9),char(0),char(6),char(0),char(9),char(0),char(7),char(0),char(13),char(0),char(1),char(0), +char(7),char(0),char(8),char(0),char(14),char(0),char(1),char(0),char(8),char(0),char(8),char(0),char(15),char(0),char(1),char(0),char(7),char(0),char(8),char(0), +char(16),char(0),char(1),char(0),char(8),char(0),char(8),char(0),char(17),char(0),char(1),char(0),char(13),char(0),char(9),char(0),char(18),char(0),char(1),char(0), +char(14),char(0),char(9),char(0),char(19),char(0),char(2),char(0),char(17),char(0),char(10),char(0),char(13),char(0),char(11),char(0),char(20),char(0),char(2),char(0), +char(18),char(0),char(10),char(0),char(14),char(0),char(11),char(0),char(21),char(0),char(4),char(0),char(4),char(0),char(12),char(0),char(4),char(0),char(13),char(0), +char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0),char(22),char(0),char(6),char(0),char(13),char(0),char(16),char(0),char(13),char(0),char(17),char(0), +char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0),char(23),char(0),char(6),char(0), +char(14),char(0),char(16),char(0),char(14),char(0),char(17),char(0),char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0), +char(0),char(0),char(21),char(0),char(24),char(0),char(3),char(0),char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0),char(4),char(0),char(22),char(0), +char(25),char(0),char(12),char(0),char(13),char(0),char(23),char(0),char(13),char(0),char(24),char(0),char(13),char(0),char(25),char(0),char(4),char(0),char(26),char(0), +char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0),char(22),char(0),char(30),char(0),char(24),char(0),char(31),char(0), +char(21),char(0),char(32),char(0),char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),char(26),char(0),char(12),char(0),char(14),char(0),char(23),char(0), +char(14),char(0),char(24),char(0),char(14),char(0),char(25),char(0),char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0), +char(4),char(0),char(29),char(0),char(23),char(0),char(30),char(0),char(24),char(0),char(31),char(0),char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0), +char(21),char(0),char(32),char(0),char(27),char(0),char(3),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(36),char(0),char(0),char(0),char(37),char(0), +char(28),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(13),char(0),char(39),char(0),char(13),char(0),char(40),char(0),char(7),char(0),char(41),char(0), +char(0),char(0),char(21),char(0),char(29),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(13),char(0),char(39),char(0),char(13),char(0),char(42),char(0), +char(7),char(0),char(43),char(0),char(4),char(0),char(44),char(0),char(30),char(0),char(2),char(0),char(13),char(0),char(45),char(0),char(7),char(0),char(46),char(0), +char(31),char(0),char(4),char(0),char(29),char(0),char(47),char(0),char(30),char(0),char(48),char(0),char(4),char(0),char(49),char(0),char(0),char(0),char(37),char(0), +char(32),char(0),char(1),char(0),char(4),char(0),char(50),char(0),char(33),char(0),char(2),char(0),char(2),char(0),char(50),char(0),char(0),char(0),char(51),char(0), +char(34),char(0),char(2),char(0),char(2),char(0),char(52),char(0),char(0),char(0),char(51),char(0),char(35),char(0),char(2),char(0),char(0),char(0),char(52),char(0), +char(0),char(0),char(53),char(0),char(36),char(0),char(8),char(0),char(13),char(0),char(54),char(0),char(14),char(0),char(55),char(0),char(32),char(0),char(56),char(0), +char(34),char(0),char(57),char(0),char(35),char(0),char(58),char(0),char(33),char(0),char(59),char(0),char(4),char(0),char(60),char(0),char(4),char(0),char(61),char(0), +char(37),char(0),char(4),char(0),char(36),char(0),char(62),char(0),char(13),char(0),char(63),char(0),char(4),char(0),char(64),char(0),char(0),char(0),char(37),char(0), +char(38),char(0),char(7),char(0),char(27),char(0),char(38),char(0),char(37),char(0),char(65),char(0),char(25),char(0),char(66),char(0),char(26),char(0),char(67),char(0), +char(39),char(0),char(68),char(0),char(7),char(0),char(43),char(0),char(0),char(0),char(69),char(0),char(40),char(0),char(2),char(0),char(38),char(0),char(70),char(0), +char(13),char(0),char(39),char(0),char(41),char(0),char(4),char(0),char(19),char(0),char(71),char(0),char(27),char(0),char(72),char(0),char(4),char(0),char(73),char(0), +char(7),char(0),char(74),char(0),char(42),char(0),char(4),char(0),char(27),char(0),char(38),char(0),char(41),char(0),char(75),char(0),char(4),char(0),char(76),char(0), +char(7),char(0),char(43),char(0),char(43),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0), +char(44),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(78),char(0),char(0),char(0),char(37),char(0),char(45),char(0),char(3),char(0), +char(29),char(0),char(47),char(0),char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),char(46),char(0),char(4),char(0),char(4),char(0),char(79),char(0), +char(7),char(0),char(80),char(0),char(7),char(0),char(81),char(0),char(7),char(0),char(82),char(0),char(39),char(0),char(14),char(0),char(4),char(0),char(83),char(0), +char(4),char(0),char(84),char(0),char(46),char(0),char(85),char(0),char(4),char(0),char(86),char(0),char(7),char(0),char(87),char(0),char(7),char(0),char(88),char(0), +char(7),char(0),char(89),char(0),char(7),char(0),char(90),char(0),char(7),char(0),char(91),char(0),char(4),char(0),char(92),char(0),char(4),char(0),char(93),char(0), +char(4),char(0),char(94),char(0),char(4),char(0),char(95),char(0),char(0),char(0),char(37),char(0),char(47),char(0),char(5),char(0),char(27),char(0),char(38),char(0), +char(37),char(0),char(65),char(0),char(13),char(0),char(39),char(0),char(7),char(0),char(43),char(0),char(4),char(0),char(96),char(0),char(48),char(0),char(5),char(0), +char(29),char(0),char(47),char(0),char(13),char(0),char(97),char(0),char(14),char(0),char(98),char(0),char(4),char(0),char(99),char(0),char(0),char(0),char(100),char(0), +char(49),char(0),char(27),char(0),char(9),char(0),char(101),char(0),char(9),char(0),char(102),char(0),char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0), +char(20),char(0),char(104),char(0),char(20),char(0),char(105),char(0),char(14),char(0),char(106),char(0),char(14),char(0),char(107),char(0),char(14),char(0),char(108),char(0), +char(8),char(0),char(109),char(0),char(8),char(0),char(110),char(0),char(8),char(0),char(111),char(0),char(8),char(0),char(112),char(0),char(8),char(0),char(113),char(0), +char(8),char(0),char(114),char(0),char(8),char(0),char(115),char(0),char(8),char(0),char(116),char(0),char(8),char(0),char(117),char(0),char(8),char(0),char(118),char(0), +char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0),char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0), +char(4),char(0),char(124),char(0),char(4),char(0),char(125),char(0),char(0),char(0),char(37),char(0),char(50),char(0),char(27),char(0),char(9),char(0),char(101),char(0), +char(9),char(0),char(102),char(0),char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0),char(19),char(0),char(104),char(0),char(19),char(0),char(105),char(0), +char(13),char(0),char(106),char(0),char(13),char(0),char(107),char(0),char(13),char(0),char(108),char(0),char(7),char(0),char(109),char(0),char(7),char(0),char(110),char(0), +char(7),char(0),char(111),char(0),char(7),char(0),char(112),char(0),char(7),char(0),char(113),char(0),char(7),char(0),char(114),char(0),char(7),char(0),char(115),char(0), +char(7),char(0),char(116),char(0),char(7),char(0),char(117),char(0),char(7),char(0),char(118),char(0),char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0), +char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(4),char(0),char(124),char(0),char(4),char(0),char(125),char(0), +char(0),char(0),char(37),char(0),char(51),char(0),char(22),char(0),char(8),char(0),char(126),char(0),char(8),char(0),char(127),char(0),char(8),char(0),char(111),char(0), +char(8),char(0),char(-128),char(0),char(8),char(0),char(115),char(0),char(8),char(0),char(-127),char(0),char(8),char(0),char(-126),char(0),char(8),char(0),char(-125),char(0), +char(8),char(0),char(-124),char(0),char(8),char(0),char(-123),char(0),char(8),char(0),char(-122),char(0),char(8),char(0),char(-121),char(0),char(8),char(0),char(-120),char(0), +char(8),char(0),char(-119),char(0),char(8),char(0),char(-118),char(0),char(8),char(0),char(-117),char(0),char(4),char(0),char(-116),char(0),char(4),char(0),char(-115),char(0), +char(4),char(0),char(-114),char(0),char(4),char(0),char(-113),char(0),char(4),char(0),char(-112),char(0),char(0),char(0),char(37),char(0),char(52),char(0),char(22),char(0), +char(7),char(0),char(126),char(0),char(7),char(0),char(127),char(0),char(7),char(0),char(111),char(0),char(7),char(0),char(-128),char(0),char(7),char(0),char(115),char(0), +char(7),char(0),char(-127),char(0),char(7),char(0),char(-126),char(0),char(7),char(0),char(-125),char(0),char(7),char(0),char(-124),char(0),char(7),char(0),char(-123),char(0), +char(7),char(0),char(-122),char(0),char(7),char(0),char(-121),char(0),char(7),char(0),char(-120),char(0),char(7),char(0),char(-119),char(0),char(7),char(0),char(-118),char(0), +char(7),char(0),char(-117),char(0),char(4),char(0),char(-116),char(0),char(4),char(0),char(-115),char(0),char(4),char(0),char(-114),char(0),char(4),char(0),char(-113),char(0), +char(4),char(0),char(-112),char(0),char(0),char(0),char(37),char(0),char(53),char(0),char(2),char(0),char(51),char(0),char(-111),char(0),char(14),char(0),char(-110),char(0), +char(54),char(0),char(2),char(0),char(52),char(0),char(-111),char(0),char(13),char(0),char(-110),char(0),char(55),char(0),char(21),char(0),char(50),char(0),char(-109),char(0), +char(17),char(0),char(-108),char(0),char(13),char(0),char(-107),char(0),char(13),char(0),char(-106),char(0),char(13),char(0),char(-105),char(0),char(13),char(0),char(-104),char(0), +char(13),char(0),char(-110),char(0),char(13),char(0),char(-103),char(0),char(13),char(0),char(-102),char(0),char(13),char(0),char(-101),char(0),char(13),char(0),char(-100),char(0), +char(7),char(0),char(-99),char(0),char(7),char(0),char(-98),char(0),char(7),char(0),char(-97),char(0),char(7),char(0),char(-96),char(0),char(7),char(0),char(-95),char(0), +char(7),char(0),char(-94),char(0),char(7),char(0),char(-93),char(0),char(7),char(0),char(-92),char(0),char(7),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0), +char(56),char(0),char(22),char(0),char(49),char(0),char(-109),char(0),char(18),char(0),char(-108),char(0),char(14),char(0),char(-107),char(0),char(14),char(0),char(-106),char(0), +char(14),char(0),char(-105),char(0),char(14),char(0),char(-104),char(0),char(14),char(0),char(-110),char(0),char(14),char(0),char(-103),char(0),char(14),char(0),char(-102),char(0), +char(14),char(0),char(-101),char(0),char(14),char(0),char(-100),char(0),char(8),char(0),char(-99),char(0),char(8),char(0),char(-98),char(0),char(8),char(0),char(-97),char(0), +char(8),char(0),char(-96),char(0),char(8),char(0),char(-95),char(0),char(8),char(0),char(-94),char(0),char(8),char(0),char(-93),char(0),char(8),char(0),char(-92),char(0), +char(8),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),char(0),char(0),char(37),char(0),char(57),char(0),char(2),char(0),char(4),char(0),char(-89),char(0), +char(4),char(0),char(-88),char(0),char(58),char(0),char(13),char(0),char(55),char(0),char(-87),char(0),char(55),char(0),char(-86),char(0),char(0),char(0),char(35),char(0), +char(4),char(0),char(-85),char(0),char(4),char(0),char(-84),char(0),char(4),char(0),char(-83),char(0),char(4),char(0),char(-82),char(0),char(7),char(0),char(-81),char(0), +char(7),char(0),char(-80),char(0),char(4),char(0),char(-79),char(0),char(4),char(0),char(-78),char(0),char(7),char(0),char(-77),char(0),char(4),char(0),char(-76),char(0), +char(59),char(0),char(13),char(0),char(60),char(0),char(-87),char(0),char(60),char(0),char(-86),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-85),char(0), +char(4),char(0),char(-84),char(0),char(4),char(0),char(-83),char(0),char(4),char(0),char(-82),char(0),char(7),char(0),char(-81),char(0),char(7),char(0),char(-80),char(0), +char(4),char(0),char(-79),char(0),char(4),char(0),char(-78),char(0),char(7),char(0),char(-77),char(0),char(4),char(0),char(-76),char(0),char(61),char(0),char(14),char(0), +char(56),char(0),char(-87),char(0),char(56),char(0),char(-86),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-85),char(0),char(4),char(0),char(-84),char(0), +char(4),char(0),char(-83),char(0),char(4),char(0),char(-82),char(0),char(8),char(0),char(-81),char(0),char(8),char(0),char(-80),char(0),char(4),char(0),char(-79),char(0), +char(4),char(0),char(-78),char(0),char(8),char(0),char(-77),char(0),char(4),char(0),char(-76),char(0),char(0),char(0),char(-75),char(0),char(62),char(0),char(3),char(0), +char(59),char(0),char(-74),char(0),char(13),char(0),char(-73),char(0),char(13),char(0),char(-72),char(0),char(63),char(0),char(3),char(0),char(61),char(0),char(-74),char(0), +char(14),char(0),char(-73),char(0),char(14),char(0),char(-72),char(0),char(64),char(0),char(3),char(0),char(59),char(0),char(-74),char(0),char(14),char(0),char(-73),char(0), +char(14),char(0),char(-72),char(0),char(65),char(0),char(13),char(0),char(59),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0), +char(4),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),char(4),char(0),char(-67),char(0),char(7),char(0),char(-66),char(0),char(7),char(0),char(-65),char(0), +char(7),char(0),char(-64),char(0),char(7),char(0),char(-63),char(0),char(7),char(0),char(-62),char(0),char(7),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0), +char(66),char(0),char(13),char(0),char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(4),char(0),char(-69),char(0), +char(4),char(0),char(-68),char(0),char(4),char(0),char(-67),char(0),char(7),char(0),char(-66),char(0),char(7),char(0),char(-65),char(0),char(7),char(0),char(-64),char(0), +char(7),char(0),char(-63),char(0),char(7),char(0),char(-62),char(0),char(7),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0),char(67),char(0),char(14),char(0), +char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),char(4),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0), +char(4),char(0),char(-67),char(0),char(8),char(0),char(-66),char(0),char(8),char(0),char(-65),char(0),char(8),char(0),char(-64),char(0),char(8),char(0),char(-63),char(0), +char(8),char(0),char(-62),char(0),char(8),char(0),char(-61),char(0),char(8),char(0),char(-60),char(0),char(0),char(0),char(-59),char(0),char(68),char(0),char(10),char(0), +char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),char(8),char(0),char(-58),char(0),char(8),char(0),char(-57),char(0), +char(8),char(0),char(-56),char(0),char(8),char(0),char(-62),char(0),char(8),char(0),char(-61),char(0),char(8),char(0),char(-60),char(0),char(8),char(0),char(127),char(0), +char(69),char(0),char(11),char(0),char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(7),char(0),char(-58),char(0), +char(7),char(0),char(-57),char(0),char(7),char(0),char(-56),char(0),char(7),char(0),char(-62),char(0),char(7),char(0),char(-61),char(0),char(7),char(0),char(-60),char(0), +char(7),char(0),char(127),char(0),char(0),char(0),char(21),char(0),char(70),char(0),char(9),char(0),char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0), +char(19),char(0),char(-70),char(0),char(13),char(0),char(-55),char(0),char(13),char(0),char(-54),char(0),char(13),char(0),char(-53),char(0),char(13),char(0),char(-52),char(0), +char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0),char(71),char(0),char(9),char(0),char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0), +char(20),char(0),char(-70),char(0),char(14),char(0),char(-55),char(0),char(14),char(0),char(-54),char(0),char(14),char(0),char(-53),char(0),char(14),char(0),char(-52),char(0), +char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0),char(72),char(0),char(5),char(0),char(70),char(0),char(-49),char(0),char(4),char(0),char(-48),char(0), +char(7),char(0),char(-47),char(0),char(7),char(0),char(-46),char(0),char(7),char(0),char(-45),char(0),char(73),char(0),char(5),char(0),char(71),char(0),char(-49),char(0), +char(4),char(0),char(-48),char(0),char(8),char(0),char(-47),char(0),char(8),char(0),char(-46),char(0),char(8),char(0),char(-45),char(0),char(74),char(0),char(41),char(0), +char(59),char(0),char(-74),char(0),char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(13),char(0),char(-55),char(0),char(13),char(0),char(-54),char(0), +char(13),char(0),char(-44),char(0),char(13),char(0),char(-43),char(0),char(13),char(0),char(-42),char(0),char(13),char(0),char(-41),char(0),char(13),char(0),char(-40),char(0), +char(13),char(0),char(-39),char(0),char(13),char(0),char(-38),char(0),char(13),char(0),char(-37),char(0),char(13),char(0),char(-36),char(0),char(13),char(0),char(-35),char(0), +char(13),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0),char(0),char(0),char(-32),char(0),char(0),char(0),char(-31),char(0),char(0),char(0),char(-30),char(0), +char(0),char(0),char(-29),char(0),char(0),char(0),char(-59),char(0),char(13),char(0),char(-53),char(0),char(13),char(0),char(-52),char(0),char(13),char(0),char(-28),char(0), +char(13),char(0),char(-27),char(0),char(13),char(0),char(-26),char(0),char(13),char(0),char(-25),char(0),char(13),char(0),char(-24),char(0),char(13),char(0),char(-23),char(0), +char(13),char(0),char(-22),char(0),char(13),char(0),char(-21),char(0),char(13),char(0),char(-20),char(0),char(13),char(0),char(-19),char(0),char(13),char(0),char(-18),char(0), +char(0),char(0),char(-17),char(0),char(0),char(0),char(-16),char(0),char(0),char(0),char(-15),char(0),char(0),char(0),char(-14),char(0),char(0),char(0),char(-13),char(0), +char(4),char(0),char(-12),char(0),char(75),char(0),char(41),char(0),char(61),char(0),char(-74),char(0),char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0), +char(14),char(0),char(-55),char(0),char(14),char(0),char(-54),char(0),char(14),char(0),char(-44),char(0),char(14),char(0),char(-43),char(0),char(14),char(0),char(-42),char(0), +char(14),char(0),char(-41),char(0),char(14),char(0),char(-40),char(0),char(14),char(0),char(-39),char(0),char(14),char(0),char(-38),char(0),char(14),char(0),char(-37),char(0), +char(14),char(0),char(-36),char(0),char(14),char(0),char(-35),char(0),char(14),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0),char(0),char(0),char(-32),char(0), +char(0),char(0),char(-31),char(0),char(0),char(0),char(-30),char(0),char(0),char(0),char(-29),char(0),char(0),char(0),char(-59),char(0),char(14),char(0),char(-53),char(0), +char(14),char(0),char(-52),char(0),char(14),char(0),char(-28),char(0),char(14),char(0),char(-27),char(0),char(14),char(0),char(-26),char(0),char(14),char(0),char(-25),char(0), +char(14),char(0),char(-24),char(0),char(14),char(0),char(-23),char(0),char(14),char(0),char(-22),char(0),char(14),char(0),char(-21),char(0),char(14),char(0),char(-20),char(0), +char(14),char(0),char(-19),char(0),char(14),char(0),char(-18),char(0),char(0),char(0),char(-17),char(0),char(0),char(0),char(-16),char(0),char(0),char(0),char(-15),char(0), +char(0),char(0),char(-14),char(0),char(0),char(0),char(-13),char(0),char(4),char(0),char(-12),char(0),char(76),char(0),char(9),char(0),char(59),char(0),char(-74),char(0), +char(19),char(0),char(-71),char(0),char(19),char(0),char(-70),char(0),char(7),char(0),char(-55),char(0),char(7),char(0),char(-54),char(0),char(7),char(0),char(-53),char(0), +char(7),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0),char(77),char(0),char(9),char(0),char(61),char(0),char(-74),char(0), +char(20),char(0),char(-71),char(0),char(20),char(0),char(-70),char(0),char(8),char(0),char(-55),char(0),char(8),char(0),char(-54),char(0),char(8),char(0),char(-53),char(0), +char(8),char(0),char(-52),char(0),char(4),char(0),char(-51),char(0),char(4),char(0),char(-50),char(0),char(78),char(0),char(5),char(0),char(58),char(0),char(-74),char(0), +char(13),char(0),char(-11),char(0),char(13),char(0),char(-10),char(0),char(7),char(0),char(-9),char(0),char(0),char(0),char(37),char(0),char(79),char(0),char(4),char(0), +char(61),char(0),char(-74),char(0),char(14),char(0),char(-11),char(0),char(14),char(0),char(-10),char(0),char(8),char(0),char(-9),char(0),char(80),char(0),char(4),char(0), +char(7),char(0),char(-8),char(0),char(7),char(0),char(-7),char(0),char(7),char(0),char(-6),char(0),char(4),char(0),char(79),char(0),char(81),char(0),char(10),char(0), +char(80),char(0),char(-5),char(0),char(13),char(0),char(-4),char(0),char(13),char(0),char(-3),char(0),char(13),char(0),char(-2),char(0),char(13),char(0),char(-1),char(0), +char(13),char(0),char(0),char(1),char(7),char(0),char(-99),char(0),char(7),char(0),char(1),char(1),char(4),char(0),char(2),char(1),char(4),char(0),char(53),char(0), +char(82),char(0),char(4),char(0),char(80),char(0),char(-5),char(0),char(4),char(0),char(3),char(1),char(7),char(0),char(4),char(1),char(4),char(0),char(5),char(1), +char(83),char(0),char(4),char(0),char(13),char(0),char(0),char(1),char(80),char(0),char(-5),char(0),char(4),char(0),char(6),char(1),char(7),char(0),char(7),char(1), +char(84),char(0),char(7),char(0),char(13),char(0),char(8),char(1),char(80),char(0),char(-5),char(0),char(4),char(0),char(9),char(1),char(7),char(0),char(10),char(1), +char(7),char(0),char(11),char(1),char(7),char(0),char(12),char(1),char(4),char(0),char(53),char(0),char(85),char(0),char(6),char(0),char(17),char(0),char(13),char(1), +char(13),char(0),char(11),char(1),char(13),char(0),char(14),char(1),char(60),char(0),char(15),char(1),char(4),char(0),char(16),char(1),char(7),char(0),char(12),char(1), +char(86),char(0),char(26),char(0),char(4),char(0),char(17),char(1),char(7),char(0),char(18),char(1),char(7),char(0),char(127),char(0),char(7),char(0),char(19),char(1), +char(7),char(0),char(20),char(1),char(7),char(0),char(21),char(1),char(7),char(0),char(22),char(1),char(7),char(0),char(23),char(1),char(7),char(0),char(24),char(1), +char(7),char(0),char(25),char(1),char(7),char(0),char(26),char(1),char(7),char(0),char(27),char(1),char(7),char(0),char(28),char(1),char(7),char(0),char(29),char(1), +char(7),char(0),char(30),char(1),char(7),char(0),char(31),char(1),char(7),char(0),char(32),char(1),char(7),char(0),char(33),char(1),char(7),char(0),char(34),char(1), +char(7),char(0),char(35),char(1),char(7),char(0),char(36),char(1),char(4),char(0),char(37),char(1),char(4),char(0),char(38),char(1),char(4),char(0),char(39),char(1), +char(4),char(0),char(40),char(1),char(4),char(0),char(120),char(0),char(87),char(0),char(12),char(0),char(17),char(0),char(41),char(1),char(17),char(0),char(42),char(1), +char(17),char(0),char(43),char(1),char(13),char(0),char(44),char(1),char(13),char(0),char(45),char(1),char(7),char(0),char(46),char(1),char(4),char(0),char(47),char(1), +char(4),char(0),char(48),char(1),char(4),char(0),char(49),char(1),char(4),char(0),char(50),char(1),char(7),char(0),char(10),char(1),char(4),char(0),char(53),char(0), +char(88),char(0),char(27),char(0),char(19),char(0),char(51),char(1),char(17),char(0),char(52),char(1),char(17),char(0),char(53),char(1),char(13),char(0),char(44),char(1), +char(13),char(0),char(54),char(1),char(13),char(0),char(55),char(1),char(13),char(0),char(56),char(1),char(13),char(0),char(57),char(1),char(13),char(0),char(58),char(1), +char(4),char(0),char(59),char(1),char(7),char(0),char(60),char(1),char(4),char(0),char(61),char(1),char(4),char(0),char(62),char(1),char(4),char(0),char(63),char(1), +char(7),char(0),char(64),char(1),char(7),char(0),char(65),char(1),char(4),char(0),char(66),char(1),char(4),char(0),char(67),char(1),char(7),char(0),char(68),char(1), +char(7),char(0),char(69),char(1),char(7),char(0),char(70),char(1),char(7),char(0),char(71),char(1),char(7),char(0),char(72),char(1),char(7),char(0),char(73),char(1), +char(4),char(0),char(74),char(1),char(4),char(0),char(75),char(1),char(4),char(0),char(76),char(1),char(89),char(0),char(12),char(0),char(9),char(0),char(77),char(1), +char(9),char(0),char(78),char(1),char(13),char(0),char(79),char(1),char(7),char(0),char(80),char(1),char(7),char(0),char(-125),char(0),char(7),char(0),char(81),char(1), +char(4),char(0),char(82),char(1),char(13),char(0),char(83),char(1),char(4),char(0),char(84),char(1),char(4),char(0),char(85),char(1),char(4),char(0),char(86),char(1), +char(4),char(0),char(53),char(0),char(90),char(0),char(19),char(0),char(50),char(0),char(-109),char(0),char(87),char(0),char(87),char(1),char(80),char(0),char(88),char(1), +char(81),char(0),char(89),char(1),char(82),char(0),char(90),char(1),char(83),char(0),char(91),char(1),char(84),char(0),char(92),char(1),char(85),char(0),char(93),char(1), +char(88),char(0),char(94),char(1),char(89),char(0),char(95),char(1),char(4),char(0),char(96),char(1),char(4),char(0),char(62),char(1),char(4),char(0),char(97),char(1), +char(4),char(0),char(98),char(1),char(4),char(0),char(99),char(1),char(4),char(0),char(100),char(1),char(4),char(0),char(101),char(1),char(4),char(0),char(102),char(1), +char(86),char(0),char(103),char(1),char(91),char(0),char(24),char(0),char(16),char(0),char(104),char(1),char(14),char(0),char(105),char(1),char(14),char(0),char(106),char(1), +char(14),char(0),char(107),char(1),char(14),char(0),char(108),char(1),char(14),char(0),char(109),char(1),char(8),char(0),char(110),char(1),char(4),char(0),char(111),char(1), +char(4),char(0),char(86),char(1),char(4),char(0),char(112),char(1),char(4),char(0),char(113),char(1),char(8),char(0),char(114),char(1),char(8),char(0),char(115),char(1), +char(8),char(0),char(116),char(1),char(8),char(0),char(117),char(1),char(8),char(0),char(118),char(1),char(8),char(0),char(119),char(1),char(8),char(0),char(120),char(1), +char(8),char(0),char(121),char(1),char(8),char(0),char(122),char(1),char(0),char(0),char(123),char(1),char(0),char(0),char(124),char(1),char(49),char(0),char(125),char(1), +char(0),char(0),char(126),char(1),char(92),char(0),char(24),char(0),char(15),char(0),char(104),char(1),char(13),char(0),char(105),char(1),char(13),char(0),char(106),char(1), +char(13),char(0),char(107),char(1),char(13),char(0),char(108),char(1),char(13),char(0),char(109),char(1),char(4),char(0),char(112),char(1),char(7),char(0),char(110),char(1), +char(4),char(0),char(111),char(1),char(4),char(0),char(86),char(1),char(7),char(0),char(114),char(1),char(7),char(0),char(115),char(1),char(7),char(0),char(116),char(1), +char(4),char(0),char(113),char(1),char(7),char(0),char(117),char(1),char(7),char(0),char(118),char(1),char(7),char(0),char(119),char(1),char(7),char(0),char(120),char(1), +char(7),char(0),char(121),char(1),char(7),char(0),char(122),char(1),char(0),char(0),char(123),char(1),char(0),char(0),char(124),char(1),char(50),char(0),char(125),char(1), +char(0),char(0),char(126),char(1),char(93),char(0),char(9),char(0),char(20),char(0),char(127),char(1),char(14),char(0),char(-128),char(1),char(8),char(0),char(-127),char(1), +char(0),char(0),char(-126),char(1),char(91),char(0),char(90),char(1),char(49),char(0),char(-125),char(1),char(0),char(0),char(126),char(1),char(4),char(0),char(97),char(1), +char(0),char(0),char(37),char(0),char(94),char(0),char(7),char(0),char(0),char(0),char(-126),char(1),char(92),char(0),char(90),char(1),char(50),char(0),char(-125),char(1), +char(19),char(0),char(127),char(1),char(13),char(0),char(-128),char(1),char(7),char(0),char(-127),char(1),char(4),char(0),char(97),char(1),}; +int sBulletDNAlen64= sizeof(sBulletDNAstr64); diff --git a/extern/bullet2/src/LinearMath/btSpatialAlgebra.h b/extern/bullet/src/LinearMath/btSpatialAlgebra.h similarity index 100% rename from extern/bullet2/src/LinearMath/btSpatialAlgebra.h rename to extern/bullet/src/LinearMath/btSpatialAlgebra.h diff --git a/extern/bullet2/src/LinearMath/btStackAlloc.h b/extern/bullet/src/LinearMath/btStackAlloc.h similarity index 100% rename from extern/bullet2/src/LinearMath/btStackAlloc.h rename to extern/bullet/src/LinearMath/btStackAlloc.h diff --git a/extern/bullet/src/LinearMath/btThreads.cpp b/extern/bullet/src/LinearMath/btThreads.cpp new file mode 100644 index 000000000000..59a7ea36e9ac --- /dev/null +++ b/extern/bullet/src/LinearMath/btThreads.cpp @@ -0,0 +1,722 @@ +/* +Copyright (c) 2003-2014 Erwin Coumans http://bullet.googlecode.com + +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 "btThreads.h" +#include "btQuickprof.h" +#include // for min and max + + +#if BT_USE_OPENMP && BT_THREADSAFE + +#include + +#endif // #if BT_USE_OPENMP && BT_THREADSAFE + + +#if BT_USE_PPL && BT_THREADSAFE + +// use Microsoft Parallel Patterns Library (installed with Visual Studio 2010 and later) +#include // if you get a compile error here, check whether your version of Visual Studio includes PPL +// Visual Studio 2010 and later should come with it +#include // for GetProcessorCount() + +#endif // #if BT_USE_PPL && BT_THREADSAFE + + +#if BT_USE_TBB && BT_THREADSAFE + +// use Intel Threading Building Blocks for thread management +#define __TBB_NO_IMPLICIT_LINKAGE 1 +#include +#include +#include +#include + +#endif // #if BT_USE_TBB && BT_THREADSAFE + + +#if BT_THREADSAFE +// +// Lightweight spin-mutex based on atomics +// Using ordinary system-provided mutexes like Windows critical sections was noticeably slower +// presumably because when it fails to lock at first it would sleep the thread and trigger costly +// context switching. +// + +#if __cplusplus >= 201103L + +// for anything claiming full C++11 compliance, use C++11 atomics +// on GCC or Clang you need to compile with -std=c++11 +#define USE_CPP11_ATOMICS 1 + +#elif defined( _MSC_VER ) + +// on MSVC, use intrinsics instead +#define USE_MSVC_INTRINSICS 1 + +#elif defined( __GNUC__ ) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) + +// available since GCC 4.7 and some versions of clang +// todo: check for clang +#define USE_GCC_BUILTIN_ATOMICS 1 + +#elif defined( __GNUC__ ) && (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) + +// available since GCC 4.1 +#define USE_GCC_BUILTIN_ATOMICS_OLD 1 + +#endif + + +#if USE_CPP11_ATOMICS + +#include +#include + +#define THREAD_LOCAL_STATIC thread_local static + +bool btSpinMutex::tryLock() +{ + std::atomic* aDest = reinterpret_cast*>(&mLock); + int expected = 0; + return std::atomic_compare_exchange_weak_explicit( aDest, &expected, int(1), std::memory_order_acq_rel, std::memory_order_acquire ); +} + +void btSpinMutex::lock() +{ + // note: this lock does not sleep the thread. + while (! tryLock()) + { + // spin + } +} + +void btSpinMutex::unlock() +{ + std::atomic* aDest = reinterpret_cast*>(&mLock); + std::atomic_store_explicit( aDest, int(0), std::memory_order_release ); +} + + +#elif USE_MSVC_INTRINSICS + +#define WIN32_LEAN_AND_MEAN + +#include +#include + +#define THREAD_LOCAL_STATIC __declspec( thread ) static + + +bool btSpinMutex::tryLock() +{ + volatile long* aDest = reinterpret_cast(&mLock); + return ( 0 == _InterlockedCompareExchange( aDest, 1, 0) ); +} + +void btSpinMutex::lock() +{ + // note: this lock does not sleep the thread + while (! tryLock()) + { + // spin + } +} + +void btSpinMutex::unlock() +{ + volatile long* aDest = reinterpret_cast( &mLock ); + _InterlockedExchange( aDest, 0 ); +} + +#elif USE_GCC_BUILTIN_ATOMICS + +#define THREAD_LOCAL_STATIC static __thread + + +bool btSpinMutex::tryLock() +{ + int expected = 0; + bool weak = false; + const int memOrderSuccess = __ATOMIC_ACQ_REL; + const int memOrderFail = __ATOMIC_ACQUIRE; + return __atomic_compare_exchange_n(&mLock, &expected, int(1), weak, memOrderSuccess, memOrderFail); +} + +void btSpinMutex::lock() +{ + // note: this lock does not sleep the thread + while (! tryLock()) + { + // spin + } +} + +void btSpinMutex::unlock() +{ + __atomic_store_n(&mLock, int(0), __ATOMIC_RELEASE); +} + +#elif USE_GCC_BUILTIN_ATOMICS_OLD + + +#define THREAD_LOCAL_STATIC static __thread + +bool btSpinMutex::tryLock() +{ + return __sync_bool_compare_and_swap(&mLock, int(0), int(1)); +} + +void btSpinMutex::lock() +{ + // note: this lock does not sleep the thread + while (! tryLock()) + { + // spin + } +} + +void btSpinMutex::unlock() +{ + // write 0 + __sync_fetch_and_and(&mLock, int(0)); +} + +#else //#elif USE_MSVC_INTRINSICS + +#error "no threading primitives defined -- unknown platform" + +#endif //#else //#elif USE_MSVC_INTRINSICS + +#else //#if BT_THREADSAFE + +// These should not be called ever +void btSpinMutex::lock() +{ + btAssert( !"unimplemented btSpinMutex::lock() called" ); +} + +void btSpinMutex::unlock() +{ + btAssert( !"unimplemented btSpinMutex::unlock() called" ); +} + +bool btSpinMutex::tryLock() +{ + btAssert( !"unimplemented btSpinMutex::tryLock() called" ); + return true; +} + +#define THREAD_LOCAL_STATIC static + +#endif // #else //#if BT_THREADSAFE + + +struct ThreadsafeCounter +{ + unsigned int mCounter; + btSpinMutex mMutex; + + ThreadsafeCounter() + { + mCounter = 0; + --mCounter; // first count should come back 0 + } + + unsigned int getNext() + { + // no need to optimize this with atomics, it is only called ONCE per thread! + mMutex.lock(); + mCounter++; + if ( mCounter >= BT_MAX_THREAD_COUNT ) + { + btAssert( !"thread counter exceeded" ); + // wrap back to the first worker index + mCounter = 1; + } + unsigned int val = mCounter; + mMutex.unlock(); + return val; + } +}; + + +static btITaskScheduler* gBtTaskScheduler; +static int gThreadsRunningCounter = 0; // useful for detecting if we are trying to do nested parallel-for calls +static btSpinMutex gThreadsRunningCounterMutex; +static ThreadsafeCounter gThreadCounter; + + +// +// BT_DETECT_BAD_THREAD_INDEX tries to detect when there are multiple threads assigned the same thread index. +// +// BT_DETECT_BAD_THREAD_INDEX is a developer option to test if +// certain assumptions about how the task scheduler manages its threads +// holds true. +// The main assumption is: +// - when the threadpool is resized, the task scheduler either +// 1. destroys all worker threads and creates all new ones in the correct number, OR +// 2. never destroys a worker thread +// +// We make that assumption because we can't easily enumerate the worker threads of a task scheduler +// to assign nice sequential thread-indexes. We also do not get notified if a worker thread is destroyed, +// so we can't tell when a thread-index is no longer being used. +// We allocate thread-indexes as needed with a sequential global thread counter. +// +// Our simple thread-counting scheme falls apart if the task scheduler destroys some threads but +// continues to re-use other threads and the application repeatedly resizes the thread pool of the +// task scheduler. +// In order to prevent the thread-counter from exceeding the global max (BT_MAX_THREAD_COUNT), we +// wrap the thread counter back to 1. This should only happen if the worker threads have all been +// destroyed and re-created. +// +// BT_DETECT_BAD_THREAD_INDEX only works for Win32 right now, +// but could be adapted to work with pthreads +#define BT_DETECT_BAD_THREAD_INDEX 0 + +#if BT_DETECT_BAD_THREAD_INDEX + +typedef DWORD ThreadId_t; +const static ThreadId_t kInvalidThreadId = 0; +ThreadId_t gDebugThreadIds[ BT_MAX_THREAD_COUNT ]; + +static ThreadId_t getDebugThreadId() +{ + return GetCurrentThreadId(); +} + +#endif // #if BT_DETECT_BAD_THREAD_INDEX + + +// return a unique index per thread, main thread is 0, worker threads are in [1, BT_MAX_THREAD_COUNT) +unsigned int btGetCurrentThreadIndex() +{ + const unsigned int kNullIndex = ~0U; + THREAD_LOCAL_STATIC unsigned int sThreadIndex = kNullIndex; + if ( sThreadIndex == kNullIndex ) + { + sThreadIndex = gThreadCounter.getNext(); + btAssert( sThreadIndex < BT_MAX_THREAD_COUNT ); + } +#if BT_DETECT_BAD_THREAD_INDEX + if ( gBtTaskScheduler && sThreadIndex > 0 ) + { + ThreadId_t tid = getDebugThreadId(); + // if not set + if ( gDebugThreadIds[ sThreadIndex ] == kInvalidThreadId ) + { + // set it + gDebugThreadIds[ sThreadIndex ] = tid; + } + else + { + if ( gDebugThreadIds[ sThreadIndex ] != tid ) + { + // this could indicate the task scheduler is breaking our assumptions about + // how threads are managed when threadpool is resized + btAssert( !"there are 2 or more threads with the same thread-index!" ); + __debugbreak(); + } + } + } +#endif // #if BT_DETECT_BAD_THREAD_INDEX + return sThreadIndex; +} + +bool btIsMainThread() +{ + return btGetCurrentThreadIndex() == 0; +} + +void btResetThreadIndexCounter() +{ + // for when all current worker threads are destroyed + btAssert( btIsMainThread() ); + gThreadCounter.mCounter = 0; +} + +btITaskScheduler::btITaskScheduler( const char* name ) +{ + m_name = name; + m_savedThreadCounter = 0; + m_isActive = false; +} + +void btITaskScheduler::activate() +{ + // gThreadCounter is used to assign a thread-index to each worker thread in a task scheduler. + // The main thread is always thread-index 0, and worker threads are numbered from 1 to 63 (BT_MAX_THREAD_COUNT-1) + // The thread-indexes need to be unique amongst the threads that can be running simultaneously. + // Since only one task scheduler can be used at a time, it is OK for a pair of threads that belong to different + // task schedulers to share the same thread index because they can't be running at the same time. + // So each task scheduler needs to keep its own thread counter value + if ( !m_isActive ) + { + gThreadCounter.mCounter = m_savedThreadCounter; // restore saved thread counter + m_isActive = true; + } +} + +void btITaskScheduler::deactivate() +{ + if ( m_isActive ) + { + m_savedThreadCounter = gThreadCounter.mCounter; // save thread counter + m_isActive = false; + } +} + +void btPushThreadsAreRunning() +{ + gThreadsRunningCounterMutex.lock(); + gThreadsRunningCounter++; + gThreadsRunningCounterMutex.unlock(); +} + +void btPopThreadsAreRunning() +{ + gThreadsRunningCounterMutex.lock(); + gThreadsRunningCounter--; + gThreadsRunningCounterMutex.unlock(); +} + +bool btThreadsAreRunning() +{ + return gThreadsRunningCounter != 0; +} + + +void btSetTaskScheduler( btITaskScheduler* ts ) +{ + int threadId = btGetCurrentThreadIndex(); // make sure we call this on main thread at least once before any workers run + if ( threadId != 0 ) + { + btAssert( !"btSetTaskScheduler must be called from the main thread!" ); + return; + } + if ( gBtTaskScheduler ) + { + // deactivate old task scheduler + gBtTaskScheduler->deactivate(); + } + gBtTaskScheduler = ts; + if ( ts ) + { + // activate new task scheduler + ts->activate(); + } +} + + +btITaskScheduler* btGetTaskScheduler() +{ + return gBtTaskScheduler; +} + + +void btParallelFor( int iBegin, int iEnd, int grainSize, const btIParallelForBody& body ) +{ +#if BT_THREADSAFE + +#if BT_DETECT_BAD_THREAD_INDEX + if ( !btThreadsAreRunning() ) + { + // clear out thread ids + for ( int i = 0; i < BT_MAX_THREAD_COUNT; ++i ) + { + gDebugThreadIds[ i ] = kInvalidThreadId; + } + } +#endif // #if BT_DETECT_BAD_THREAD_INDEX + + btAssert( gBtTaskScheduler != NULL ); // call btSetTaskScheduler() with a valid task scheduler first! + gBtTaskScheduler->parallelFor( iBegin, iEnd, grainSize, body ); + +#else // #if BT_THREADSAFE + + // non-parallel version of btParallelFor + btAssert( !"called btParallelFor in non-threadsafe build. enable BT_THREADSAFE" ); + body.forLoop( iBegin, iEnd ); + +#endif// #if BT_THREADSAFE +} + + +/// +/// btTaskSchedulerSequential -- non-threaded implementation of task scheduler +/// (really just useful for testing performance of single threaded vs multi) +/// +class btTaskSchedulerSequential : public btITaskScheduler +{ +public: + btTaskSchedulerSequential() : btITaskScheduler( "Sequential" ) {} + virtual int getMaxNumThreads() const BT_OVERRIDE { return 1; } + virtual int getNumThreads() const BT_OVERRIDE { return 1; } + virtual void setNumThreads( int numThreads ) BT_OVERRIDE {} + virtual void parallelFor( int iBegin, int iEnd, int grainSize, const btIParallelForBody& body ) BT_OVERRIDE + { + BT_PROFILE( "parallelFor_sequential" ); + body.forLoop( iBegin, iEnd ); + } +}; + + +#if BT_USE_OPENMP && BT_THREADSAFE +/// +/// btTaskSchedulerOpenMP -- wrapper around OpenMP task scheduler +/// +class btTaskSchedulerOpenMP : public btITaskScheduler +{ + int m_numThreads; +public: + btTaskSchedulerOpenMP() : btITaskScheduler( "OpenMP" ) + { + m_numThreads = 0; + } + virtual int getMaxNumThreads() const BT_OVERRIDE + { + return omp_get_max_threads(); + } + virtual int getNumThreads() const BT_OVERRIDE + { + return m_numThreads; + } + virtual void setNumThreads( int numThreads ) BT_OVERRIDE + { + // With OpenMP, because it is a standard with various implementations, we can't + // know for sure if every implementation has the same behavior of destroying all + // previous threads when resizing the threadpool + m_numThreads = ( std::max )( 1, ( std::min )( int( BT_MAX_THREAD_COUNT ), numThreads ) ); + omp_set_num_threads( 1 ); // hopefully, all previous threads get destroyed here + omp_set_num_threads( m_numThreads ); + m_savedThreadCounter = 0; + if ( m_isActive ) + { + btResetThreadIndexCounter(); + } + } + virtual void parallelFor( int iBegin, int iEnd, int grainSize, const btIParallelForBody& body ) BT_OVERRIDE + { + BT_PROFILE( "parallelFor_OpenMP" ); + btPushThreadsAreRunning(); +#pragma omp parallel for schedule( static, 1 ) + for ( int i = iBegin; i < iEnd; i += grainSize ) + { + BT_PROFILE( "OpenMP_job" ); + body.forLoop( i, ( std::min )( i + grainSize, iEnd ) ); + } + btPopThreadsAreRunning(); + } +}; +#endif // #if BT_USE_OPENMP && BT_THREADSAFE + + +#if BT_USE_TBB && BT_THREADSAFE +/// +/// btTaskSchedulerTBB -- wrapper around Intel Threaded Building Blocks task scheduler +/// +class btTaskSchedulerTBB : public btITaskScheduler +{ + int m_numThreads; + tbb::task_scheduler_init* m_tbbSchedulerInit; + +public: + btTaskSchedulerTBB() : btITaskScheduler( "IntelTBB" ) + { + m_numThreads = 0; + m_tbbSchedulerInit = NULL; + } + ~btTaskSchedulerTBB() + { + if ( m_tbbSchedulerInit ) + { + delete m_tbbSchedulerInit; + m_tbbSchedulerInit = NULL; + } + } + + virtual int getMaxNumThreads() const BT_OVERRIDE + { + return tbb::task_scheduler_init::default_num_threads(); + } + virtual int getNumThreads() const BT_OVERRIDE + { + return m_numThreads; + } + virtual void setNumThreads( int numThreads ) BT_OVERRIDE + { + m_numThreads = ( std::max )( 1, ( std::min )( int(BT_MAX_THREAD_COUNT), numThreads ) ); + if ( m_tbbSchedulerInit ) + { + // destroys all previous threads + delete m_tbbSchedulerInit; + m_tbbSchedulerInit = NULL; + } + m_tbbSchedulerInit = new tbb::task_scheduler_init( m_numThreads ); + m_savedThreadCounter = 0; + if ( m_isActive ) + { + btResetThreadIndexCounter(); + } + } + struct BodyAdapter + { + const btIParallelForBody* mBody; + + void operator()( const tbb::blocked_range& range ) const + { + BT_PROFILE( "TBB_job" ); + mBody->forLoop( range.begin(), range.end() ); + } + }; + virtual void parallelFor( int iBegin, int iEnd, int grainSize, const btIParallelForBody& body ) BT_OVERRIDE + { + BT_PROFILE( "parallelFor_TBB" ); + // TBB dispatch + BodyAdapter tbbBody; + tbbBody.mBody = &body; + btPushThreadsAreRunning(); + tbb::parallel_for( tbb::blocked_range( iBegin, iEnd, grainSize ), + tbbBody, + tbb::simple_partitioner() + ); + btPopThreadsAreRunning(); + } +}; +#endif // #if BT_USE_TBB && BT_THREADSAFE + + +#if BT_USE_PPL && BT_THREADSAFE +/// +/// btTaskSchedulerPPL -- wrapper around Microsoft Parallel Patterns Lib task scheduler +/// +class btTaskSchedulerPPL : public btITaskScheduler +{ + int m_numThreads; +public: + btTaskSchedulerPPL() : btITaskScheduler( "PPL" ) + { + m_numThreads = 0; + } + virtual int getMaxNumThreads() const BT_OVERRIDE + { + return concurrency::GetProcessorCount(); + } + virtual int getNumThreads() const BT_OVERRIDE + { + return m_numThreads; + } + virtual void setNumThreads( int numThreads ) BT_OVERRIDE + { + // capping the thread count for PPL due to a thread-index issue + const int maxThreadCount = (std::min)(int(BT_MAX_THREAD_COUNT), 31); + m_numThreads = ( std::max )( 1, ( std::min )( maxThreadCount, numThreads ) ); + using namespace concurrency; + if ( CurrentScheduler::Id() != -1 ) + { + CurrentScheduler::Detach(); + } + SchedulerPolicy policy; + { + // PPL seems to destroy threads when threadpool is shrunk, but keeps reusing old threads + // force it to destroy old threads + policy.SetConcurrencyLimits( 1, 1 ); + CurrentScheduler::Create( policy ); + CurrentScheduler::Detach(); + } + policy.SetConcurrencyLimits( m_numThreads, m_numThreads ); + CurrentScheduler::Create( policy ); + m_savedThreadCounter = 0; + if ( m_isActive ) + { + btResetThreadIndexCounter(); + } + } + struct BodyAdapter + { + const btIParallelForBody* mBody; + int mGrainSize; + int mIndexEnd; + + void operator()( int i ) const + { + BT_PROFILE( "PPL_job" ); + mBody->forLoop( i, ( std::min )( i + mGrainSize, mIndexEnd ) ); + } + }; + virtual void parallelFor( int iBegin, int iEnd, int grainSize, const btIParallelForBody& body ) BT_OVERRIDE + { + BT_PROFILE( "parallelFor_PPL" ); + // PPL dispatch + BodyAdapter pplBody; + pplBody.mBody = &body; + pplBody.mGrainSize = grainSize; + pplBody.mIndexEnd = iEnd; + btPushThreadsAreRunning(); + // note: MSVC 2010 doesn't support partitioner args, so avoid them + concurrency::parallel_for( iBegin, + iEnd, + grainSize, + pplBody + ); + btPopThreadsAreRunning(); + } +}; +#endif // #if BT_USE_PPL && BT_THREADSAFE + + +// create a non-threaded task scheduler (always available) +btITaskScheduler* btGetSequentialTaskScheduler() +{ + static btTaskSchedulerSequential sTaskScheduler; + return &sTaskScheduler; +} + + +// create an OpenMP task scheduler (if available, otherwise returns null) +btITaskScheduler* btGetOpenMPTaskScheduler() +{ +#if BT_USE_OPENMP && BT_THREADSAFE + static btTaskSchedulerOpenMP sTaskScheduler; + return &sTaskScheduler; +#else + return NULL; +#endif +} + + +// create an Intel TBB task scheduler (if available, otherwise returns null) +btITaskScheduler* btGetTBBTaskScheduler() +{ +#if BT_USE_TBB && BT_THREADSAFE + static btTaskSchedulerTBB sTaskScheduler; + return &sTaskScheduler; +#else + return NULL; +#endif +} + + +// create a PPL task scheduler (if available, otherwise returns null) +btITaskScheduler* btGetPPLTaskScheduler() +{ +#if BT_USE_PPL && BT_THREADSAFE + static btTaskSchedulerPPL sTaskScheduler; + return &sTaskScheduler; +#else + return NULL; +#endif +} + diff --git a/extern/bullet/src/LinearMath/btThreads.h b/extern/bullet/src/LinearMath/btThreads.h new file mode 100644 index 000000000000..05fd15ec82ef --- /dev/null +++ b/extern/bullet/src/LinearMath/btThreads.h @@ -0,0 +1,155 @@ +/* +Copyright (c) 2003-2014 Erwin Coumans http://bullet.googlecode.com + +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_THREADS_H +#define BT_THREADS_H + +#include "btScalar.h" // has definitions like SIMD_FORCE_INLINE + +#if defined (_MSC_VER) && _MSC_VER >= 1600 +// give us a compile error if any signatures of overriden methods is changed +#define BT_OVERRIDE override +#endif + +#ifndef BT_OVERRIDE +#define BT_OVERRIDE +#endif + +const unsigned int BT_MAX_THREAD_COUNT = 64; // only if BT_THREADSAFE is 1 + +// for internal use only +bool btIsMainThread(); +bool btThreadsAreRunning(); +unsigned int btGetCurrentThreadIndex(); +void btResetThreadIndexCounter(); // notify that all worker threads have been destroyed + +/// +/// btSpinMutex -- lightweight spin-mutex implemented with atomic ops, never puts +/// a thread to sleep because it is designed to be used with a task scheduler +/// which has one thread per core and the threads don't sleep until they +/// run out of tasks. Not good for general purpose use. +/// +class btSpinMutex +{ + int mLock; + +public: + btSpinMutex() + { + mLock = 0; + } + void lock(); + void unlock(); + bool tryLock(); +}; + + +// +// NOTE: btMutex* is for internal Bullet use only +// +// If BT_THREADSAFE is undefined or 0, should optimize away to nothing. +// This is good because for the single-threaded build of Bullet, any calls +// to these functions will be optimized out. +// +// However, for users of the multi-threaded build of Bullet this is kind +// of bad because if you call any of these functions from external code +// (where BT_THREADSAFE is undefined) you will get unexpected race conditions. +// +SIMD_FORCE_INLINE void btMutexLock( btSpinMutex* mutex ) +{ +#if BT_THREADSAFE + mutex->lock(); +#endif // #if BT_THREADSAFE +} + +SIMD_FORCE_INLINE void btMutexUnlock( btSpinMutex* mutex ) +{ +#if BT_THREADSAFE + mutex->unlock(); +#endif // #if BT_THREADSAFE +} + +SIMD_FORCE_INLINE bool btMutexTryLock( btSpinMutex* mutex ) +{ +#if BT_THREADSAFE + return mutex->tryLock(); +#else + return true; +#endif // #if BT_THREADSAFE +} + + +// +// btIParallelForBody -- subclass this to express work that can be done in parallel +// +class btIParallelForBody +{ +public: + virtual ~btIParallelForBody() {} + virtual void forLoop( int iBegin, int iEnd ) const = 0; +}; + +// +// btITaskScheduler -- subclass this to implement a task scheduler that can dispatch work to +// worker threads +// +class btITaskScheduler +{ +public: + btITaskScheduler( const char* name ); + virtual ~btITaskScheduler() {} + const char* getName() const { return m_name; } + + virtual int getMaxNumThreads() const = 0; + virtual int getNumThreads() const = 0; + virtual void setNumThreads( int numThreads ) = 0; + virtual void parallelFor( int iBegin, int iEnd, int grainSize, const btIParallelForBody& body ) = 0; + + // internal use only + virtual void activate(); + virtual void deactivate(); + +protected: + const char* m_name; + unsigned int m_savedThreadCounter; + bool m_isActive; +}; + +// set the task scheduler to use for all calls to btParallelFor() +// NOTE: you must set this prior to using any of the multi-threaded "Mt" classes +void btSetTaskScheduler( btITaskScheduler* ts ); + +// get the current task scheduler +btITaskScheduler* btGetTaskScheduler(); + +// get non-threaded task scheduler (always available) +btITaskScheduler* btGetSequentialTaskScheduler(); + +// get OpenMP task scheduler (if available, otherwise returns null) +btITaskScheduler* btGetOpenMPTaskScheduler(); + +// get Intel TBB task scheduler (if available, otherwise returns null) +btITaskScheduler* btGetTBBTaskScheduler(); + +// get PPL task scheduler (if available, otherwise returns null) +btITaskScheduler* btGetPPLTaskScheduler(); + +// btParallelFor -- call this to dispatch work like a for-loop +// (iterations may be done out of order, so no dependencies are allowed) +void btParallelFor( int iBegin, int iEnd, int grainSize, const btIParallelForBody& body ); + + +#endif diff --git a/extern/bullet2/src/LinearMath/btTransform.h b/extern/bullet/src/LinearMath/btTransform.h similarity index 100% rename from extern/bullet2/src/LinearMath/btTransform.h rename to extern/bullet/src/LinearMath/btTransform.h diff --git a/extern/bullet2/src/LinearMath/btTransformUtil.h b/extern/bullet/src/LinearMath/btTransformUtil.h similarity index 94% rename from extern/bullet2/src/LinearMath/btTransformUtil.h rename to extern/bullet/src/LinearMath/btTransformUtil.h index 2303c2742753..182cc43fab90 100644 --- a/extern/bullet2/src/LinearMath/btTransformUtil.h +++ b/extern/bullet/src/LinearMath/btTransformUtil.h @@ -47,13 +47,19 @@ class btTransformUtil #ifdef QUATERNION_DERIVATIVE btQuaternion predictedOrn = curTrans.getRotation(); predictedOrn += (angvel * predictedOrn) * (timeStep * btScalar(0.5)); - predictedOrn.normalize(); + predictedOrn.safeNormalize(); #else //Exponential map //google for "Practical Parameterization of Rotations Using the Exponential Map", F. Sebastian Grassia btVector3 axis; - btScalar fAngle = angvel.length(); + btScalar fAngle2 = angvel.length2(); + btScalar fAngle = 0; + if (fAngle2>SIMD_EPSILON) + { + fAngle = btSqrt(fAngle2); + } + //limit the angular motion if (fAngle*timeStep > ANGULAR_MOTION_THRESHOLD) { @@ -74,9 +80,16 @@ class btTransformUtil btQuaternion orn0 = curTrans.getRotation(); btQuaternion predictedOrn = dorn * orn0; - predictedOrn.normalize(); + predictedOrn.safeNormalize(); #endif - predictedTransform.setRotation(predictedOrn); + if (predictedOrn.length2()>SIMD_EPSILON) + { + predictedTransform.setRotation(predictedOrn); + } + else + { + predictedTransform.setBasis(curTrans.getBasis()); + } } static void calculateVelocityQuaternion(const btVector3& pos0,const btVector3& pos1,const btQuaternion& orn0,const btQuaternion& orn1,btScalar timeStep,btVector3& linVel,btVector3& angVel) diff --git a/extern/bullet2/src/LinearMath/btVector3.cpp b/extern/bullet/src/LinearMath/btVector3.cpp similarity index 100% rename from extern/bullet2/src/LinearMath/btVector3.cpp rename to extern/bullet/src/LinearMath/btVector3.cpp diff --git a/extern/bullet2/src/LinearMath/btVector3.h b/extern/bullet/src/LinearMath/btVector3.h similarity index 98% rename from extern/bullet2/src/LinearMath/btVector3.h rename to extern/bullet/src/LinearMath/btVector3.h index 839b19c1449d..fdf3fd796fc3 100644 --- a/extern/bullet2/src/LinearMath/btVector3.h +++ b/extern/bullet/src/LinearMath/btVector3.h @@ -267,10 +267,20 @@ ATTRIBUTE_ALIGNED16(class) btVector3 /**@brief Return the norm (length) of the vector */ SIMD_FORCE_INLINE btScalar norm() const - { + { return length(); } + /**@brief Return the norm (length) of the vector */ + SIMD_FORCE_INLINE btScalar safeNorm() const + { + btScalar d = length2(); + //workaround for some clang/gcc issue of sqrtf(tiny number) = -INF + if (d>SIMD_EPSILON) + return btSqrt(d); + return btScalar(0); + } + /**@brief Return the distance squared between the ends of this and another vector * This is symantically treating the vector like a point */ SIMD_FORCE_INLINE btScalar distance2(const btVector3& v) const; @@ -281,14 +291,16 @@ ATTRIBUTE_ALIGNED16(class) btVector3 SIMD_FORCE_INLINE btVector3& safeNormalize() { - btVector3 absVec = this->absolute(); - int maxIndex = absVec.maxAxis(); - if (absVec[maxIndex]>0) + btScalar l2 = length2(); + //triNormal.normalize(); + if (l2 >= SIMD_EPSILON*SIMD_EPSILON) + { + (*this) /= btSqrt(l2); + } + else { - *this /= absVec[maxIndex]; - return *this /= length(); + setValue(1, 0, 0); } - setValue(1,0,0); return *this; } @@ -1147,7 +1159,6 @@ class btVector4 : public btVector3 if (m_floats[3] > maxVal) { maxIndex = 3; - maxVal = m_floats[3]; } return maxIndex; diff --git a/extern/bullet/src/LinearMath/premake4.lua b/extern/bullet/src/LinearMath/premake4.lua new file mode 100644 index 000000000000..524e2c316160 --- /dev/null +++ b/extern/bullet/src/LinearMath/premake4.lua @@ -0,0 +1,10 @@ + project "LinearMath" + + kind "StaticLib" + includedirs { + "..", + } + files { + "*.cpp", + "*.h" + } diff --git a/extern/bullet2/src/btBulletCollisionCommon.h b/extern/bullet/src/btBulletCollisionCommon.h similarity index 97% rename from extern/bullet2/src/btBulletCollisionCommon.h rename to extern/bullet/src/btBulletCollisionCommon.h index af981b5d36dc..948e02eb4cd6 100644 --- a/extern/bullet2/src/btBulletCollisionCommon.h +++ b/extern/bullet/src/btBulletCollisionCommon.h @@ -52,7 +52,6 @@ subject to the following restrictions: #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h" #include "BulletCollision/BroadphaseCollision/btAxisSweep3.h" -#include "BulletCollision/BroadphaseCollision/btMultiSapBroadphase.h" #include "BulletCollision/BroadphaseCollision/btDbvtBroadphase.h" ///Math library & Utils diff --git a/extern/bullet2/src/btBulletDynamicsCommon.h b/extern/bullet/src/btBulletDynamicsCommon.h similarity index 100% rename from extern/bullet2/src/btBulletDynamicsCommon.h rename to extern/bullet/src/btBulletDynamicsCommon.h diff --git a/extern/bullet/src/clew/clew.c b/extern/bullet/src/clew/clew.c new file mode 100644 index 000000000000..a07b0aad754f --- /dev/null +++ b/extern/bullet/src/clew/clew.c @@ -0,0 +1,312 @@ +////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009 Organic Vectory B.V. +// Written by George van Venrooij +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file license.txt) +////////////////////////////////////////////////////////////////////////// + +#include "clew.h" + +#ifdef _WIN32 + #define WIN32_LEAN_AND_MEAN + #define VC_EXTRALEAN + #include + + typedef HMODULE CLEW_DYNLIB_HANDLE; + + #define CLEW_DYNLIB_OPEN LoadLibrary + #define CLEW_DYNLIB_CLOSE FreeLibrary + #define CLEW_DYNLIB_IMPORT GetProcAddress +#else + #include + + typedef void* CLEW_DYNLIB_HANDLE; + + #define CLEW_DYNLIB_OPEN(path) dlopen(path, RTLD_NOW | RTLD_GLOBAL) + #define CLEW_DYNLIB_CLOSE dlclose + #define CLEW_DYNLIB_IMPORT dlsym +#endif + +#include + +//! \brief module handle +static CLEW_DYNLIB_HANDLE module = NULL; + +// Variables holding function entry points +PFNCLGETPLATFORMIDS __clewGetPlatformIDs = NULL; +PFNCLGETPLATFORMINFO __clewGetPlatformInfo = NULL; +PFNCLGETDEVICEIDS __clewGetDeviceIDs = NULL; +PFNCLGETDEVICEINFO __clewGetDeviceInfo = NULL; +PFNCLCREATECONTEXT __clewCreateContext = NULL; +PFNCLCREATECONTEXTFROMTYPE __clewCreateContextFromType = NULL; +PFNCLRETAINCONTEXT __clewRetainContext = NULL; +PFNCLRELEASECONTEXT __clewReleaseContext = NULL; +PFNCLGETCONTEXTINFO __clewGetContextInfo = NULL; +PFNCLCREATECOMMANDQUEUE __clewCreateCommandQueue = NULL; +PFNCLRETAINCOMMANDQUEUE __clewRetainCommandQueue = NULL; +PFNCLRELEASECOMMANDQUEUE __clewReleaseCommandQueue = NULL; +PFNCLGETCOMMANDQUEUEINFO __clewGetCommandQueueInfo = NULL; +#ifdef CL_USE_DEPRECATED_OPENCL_1_0_APIS +PFNCLSETCOMMANDQUEUEPROPERTY __clewSetCommandQueueProperty = NULL; +#endif +PFNCLCREATEBUFFER __clewCreateBuffer = NULL; +PFNCLCREATESUBBUFFER __clewCreateSubBuffer = NULL; +PFNCLCREATEIMAGE2D __clewCreateImage2D = NULL; +PFNCLCREATEIMAGE3D __clewCreateImage3D = NULL; +PFNCLRETAINMEMOBJECT __clewRetainMemObject = NULL; +PFNCLRELEASEMEMOBJECT __clewReleaseMemObject = NULL; +PFNCLGETSUPPORTEDIMAGEFORMATS __clewGetSupportedImageFormats = NULL; +PFNCLGETMEMOBJECTINFO __clewGetMemObjectInfo = NULL; +PFNCLGETIMAGEINFO __clewGetImageInfo = NULL; +PFNCLSETMEMOBJECTDESTRUCTORCALLBACK __clewSetMemObjectDestructorCallback = NULL; +PFNCLCREATESAMPLER __clewCreateSampler = NULL; +PFNCLRETAINSAMPLER __clewRetainSampler = NULL; +PFNCLRELEASESAMPLER __clewReleaseSampler = NULL; +PFNCLGETSAMPLERINFO __clewGetSamplerInfo = NULL; +PFNCLCREATEPROGRAMWITHSOURCE __clewCreateProgramWithSource = NULL; +PFNCLCREATEPROGRAMWITHBINARY __clewCreateProgramWithBinary = NULL; +PFNCLRETAINPROGRAM __clewRetainProgram = NULL; +PFNCLRELEASEPROGRAM __clewReleaseProgram = NULL; +PFNCLBUILDPROGRAM __clewBuildProgram = NULL; +PFNCLUNLOADCOMPILER __clewUnloadCompiler = NULL; +PFNCLGETPROGRAMINFO __clewGetProgramInfo = NULL; +PFNCLGETPROGRAMBUILDINFO __clewGetProgramBuildInfo = NULL; +PFNCLCREATEKERNEL __clewCreateKernel = NULL; +PFNCLCREATEKERNELSINPROGRAM __clewCreateKernelsInProgram = NULL; +PFNCLRETAINKERNEL __clewRetainKernel = NULL; +PFNCLRELEASEKERNEL __clewReleaseKernel = NULL; +PFNCLSETKERNELARG __clewSetKernelArg = NULL; +PFNCLGETKERNELINFO __clewGetKernelInfo = NULL; +PFNCLGETKERNELWORKGROUPINFO __clewGetKernelWorkGroupInfo = NULL; +PFNCLWAITFOREVENTS __clewWaitForEvents = NULL; +PFNCLGETEVENTINFO __clewGetEventInfo = NULL; +PFNCLCREATEUSEREVENT __clewCreateUserEvent = NULL; +PFNCLRETAINEVENT __clewRetainEvent = NULL; +PFNCLRELEASEEVENT __clewReleaseEvent = NULL; +PFNCLSETUSEREVENTSTATUS __clewSetUserEventStatus = NULL; +PFNCLSETEVENTCALLBACK __clewSetEventCallback = NULL; +PFNCLGETEVENTPROFILINGINFO __clewGetEventProfilingInfo = NULL; +PFNCLFLUSH __clewFlush = NULL; +PFNCLFINISH __clewFinish = NULL; +PFNCLENQUEUEREADBUFFER __clewEnqueueReadBuffer = NULL; +PFNCLENQUEUEREADBUFFERRECT __clewEnqueueReadBufferRect = NULL; +PFNCLENQUEUEWRITEBUFFER __clewEnqueueWriteBuffer = NULL; +PFNCLENQUEUEWRITEBUFFERRECT __clewEnqueueWriteBufferRect = NULL; +PFNCLENQUEUECOPYBUFFER __clewEnqueueCopyBuffer = NULL; +PFNCLENQUEUEREADIMAGE __clewEnqueueReadImage = NULL; +PFNCLENQUEUEWRITEIMAGE __clewEnqueueWriteImage = NULL; +PFNCLENQUEUECOPYIMAGE __clewEnqueueCopyImage = NULL; +PFNCLENQUEUECOPYBUFFERRECT __clewEnqueueCopyBufferRect = NULL; +PFNCLENQUEUECOPYIMAGETOBUFFER __clewEnqueueCopyImageToBuffer = NULL; +PFNCLENQUEUECOPYBUFFERTOIMAGE __clewEnqueueCopyBufferToImage = NULL; +PFNCLENQUEUEMAPBUFFER __clewEnqueueMapBuffer = NULL; +PFNCLENQUEUEMAPIMAGE __clewEnqueueMapImage = NULL; +PFNCLENQUEUEUNMAPMEMOBJECT __clewEnqueueUnmapMemObject = NULL; +PFNCLENQUEUENDRANGEKERNEL __clewEnqueueNDRangeKernel = NULL; +PFNCLENQUEUETASK __clewEnqueueTask = NULL; +PFNCLENQUEUENATIVEKERNEL __clewEnqueueNativeKernel = NULL; +PFNCLENQUEUEMARKER __clewEnqueueMarker = NULL; +PFNCLENQUEUEWAITFOREVENTS __clewEnqueueWaitForEvents = NULL; +PFNCLENQUEUEBARRIER __clewEnqueueBarrier = NULL; +PFNCLGETEXTENSIONFUNCTIONADDRESS __clewGetExtensionFunctionAddress = NULL; + + +void clewExit(void) +{ + if (module != NULL) + { + // Ignore errors + CLEW_DYNLIB_CLOSE(module); + module = NULL; + } +} + +int clewInit(const char* path) +{ + int error = 0; + + // Check if already initialized + if (module != NULL) + { + return CLEW_SUCCESS; + } + + // Load library + module = CLEW_DYNLIB_OPEN(path); + + // Check for errors + if (module == NULL) + { + return CLEW_ERROR_OPEN_FAILED; + } + + // Set unloading + error = atexit(clewExit); + + if (error) + { + // Failure queuing atexit, shutdown with error + CLEW_DYNLIB_CLOSE(module); + module = NULL; + + return CLEW_ERROR_ATEXIT_FAILED; + } + + // Determine function entry-points + __clewGetPlatformIDs = (PFNCLGETPLATFORMIDS )CLEW_DYNLIB_IMPORT(module, "clGetPlatformIDs"); + __clewGetPlatformInfo = (PFNCLGETPLATFORMINFO )CLEW_DYNLIB_IMPORT(module, "clGetPlatformInfo"); + __clewGetDeviceIDs = (PFNCLGETDEVICEIDS )CLEW_DYNLIB_IMPORT(module, "clGetDeviceIDs"); + __clewGetDeviceInfo = (PFNCLGETDEVICEINFO )CLEW_DYNLIB_IMPORT(module, "clGetDeviceInfo"); + __clewCreateContext = (PFNCLCREATECONTEXT )CLEW_DYNLIB_IMPORT(module, "clCreateContext"); + __clewCreateContextFromType = (PFNCLCREATECONTEXTFROMTYPE )CLEW_DYNLIB_IMPORT(module, "clCreateContextFromType"); + __clewRetainContext = (PFNCLRETAINCONTEXT )CLEW_DYNLIB_IMPORT(module, "clRetainContext"); + __clewReleaseContext = (PFNCLRELEASECONTEXT )CLEW_DYNLIB_IMPORT(module, "clReleaseContext"); + __clewGetContextInfo = (PFNCLGETCONTEXTINFO )CLEW_DYNLIB_IMPORT(module, "clGetContextInfo"); + __clewCreateCommandQueue = (PFNCLCREATECOMMANDQUEUE )CLEW_DYNLIB_IMPORT(module, "clCreateCommandQueue"); + __clewRetainCommandQueue = (PFNCLRETAINCOMMANDQUEUE )CLEW_DYNLIB_IMPORT(module, "clRetainCommandQueue"); + __clewReleaseCommandQueue = (PFNCLRELEASECOMMANDQUEUE )CLEW_DYNLIB_IMPORT(module, "clReleaseCommandQueue"); + __clewGetCommandQueueInfo = (PFNCLGETCOMMANDQUEUEINFO )CLEW_DYNLIB_IMPORT(module, "clGetCommandQueueInfo"); +#ifdef CL_USE_DEPRECATED_OPENCL_1_0_APIS + __clewSetCommandQueueProperty = (PFNCLSETCOMMANDQUEUEPROPERTY )CLEW_DYNLIB_IMPORT(module, "clSetCommandQueueProperty"); +#endif + __clewCreateBuffer = (PFNCLCREATEBUFFER )CLEW_DYNLIB_IMPORT(module, "clCreateBuffer"); + __clewCreateSubBuffer = (PFNCLCREATESUBBUFFER )CLEW_DYNLIB_IMPORT(module, "clCreateBuffer"); + __clewCreateImage2D = (PFNCLCREATEIMAGE2D )CLEW_DYNLIB_IMPORT(module, "clCreateImage2D"); + __clewCreateImage3D = (PFNCLCREATEIMAGE3D )CLEW_DYNLIB_IMPORT(module, "clCreateImage3D"); + __clewRetainMemObject = (PFNCLRETAINMEMOBJECT )CLEW_DYNLIB_IMPORT(module, "clRetainMemObject"); + __clewReleaseMemObject = (PFNCLRELEASEMEMOBJECT )CLEW_DYNLIB_IMPORT(module, "clReleaseMemObject"); + __clewGetSupportedImageFormats = (PFNCLGETSUPPORTEDIMAGEFORMATS )CLEW_DYNLIB_IMPORT(module, "clGetSupportedImageFormats"); + __clewGetMemObjectInfo = (PFNCLGETMEMOBJECTINFO )CLEW_DYNLIB_IMPORT(module, "clGetMemObjectInfo"); + __clewGetImageInfo = (PFNCLGETIMAGEINFO )CLEW_DYNLIB_IMPORT(module, "clGetImageInfo"); + __clewSetMemObjectDestructorCallback = (PFNCLSETMEMOBJECTDESTRUCTORCALLBACK)CLEW_DYNLIB_IMPORT(module, "clSetMemObjectDestructorCallback"); + __clewCreateSampler = (PFNCLCREATESAMPLER )CLEW_DYNLIB_IMPORT(module, "clCreateSampler"); + __clewRetainSampler = (PFNCLRETAINSAMPLER )CLEW_DYNLIB_IMPORT(module, "clRetainSampler"); + __clewReleaseSampler = (PFNCLRELEASESAMPLER )CLEW_DYNLIB_IMPORT(module, "clReleaseSampler"); + __clewGetSamplerInfo = (PFNCLGETSAMPLERINFO )CLEW_DYNLIB_IMPORT(module, "clGetSamplerInfo"); + __clewCreateProgramWithSource = (PFNCLCREATEPROGRAMWITHSOURCE )CLEW_DYNLIB_IMPORT(module, "clCreateProgramWithSource"); + __clewCreateProgramWithBinary = (PFNCLCREATEPROGRAMWITHBINARY )CLEW_DYNLIB_IMPORT(module, "clCreateProgramWithBinary"); + __clewRetainProgram = (PFNCLRETAINPROGRAM )CLEW_DYNLIB_IMPORT(module, "clRetainProgram"); + __clewReleaseProgram = (PFNCLRELEASEPROGRAM )CLEW_DYNLIB_IMPORT(module, "clReleaseProgram"); + __clewBuildProgram = (PFNCLBUILDPROGRAM )CLEW_DYNLIB_IMPORT(module, "clBuildProgram"); + __clewUnloadCompiler = (PFNCLUNLOADCOMPILER )CLEW_DYNLIB_IMPORT(module, "clUnloadCompiler"); + __clewGetProgramInfo = (PFNCLGETPROGRAMINFO )CLEW_DYNLIB_IMPORT(module, "clGetProgramInfo"); + __clewGetProgramBuildInfo = (PFNCLGETPROGRAMBUILDINFO )CLEW_DYNLIB_IMPORT(module, "clGetProgramBuildInfo"); + __clewCreateKernel = (PFNCLCREATEKERNEL )CLEW_DYNLIB_IMPORT(module, "clCreateKernel"); + __clewCreateKernelsInProgram = (PFNCLCREATEKERNELSINPROGRAM )CLEW_DYNLIB_IMPORT(module, "clCreateKernelsInProgram"); + __clewRetainKernel = (PFNCLRETAINKERNEL )CLEW_DYNLIB_IMPORT(module, "clRetainKernel"); + __clewReleaseKernel = (PFNCLRELEASEKERNEL )CLEW_DYNLIB_IMPORT(module, "clReleaseKernel"); + __clewSetKernelArg = (PFNCLSETKERNELARG )CLEW_DYNLIB_IMPORT(module, "clSetKernelArg"); + __clewGetKernelInfo = (PFNCLGETKERNELINFO )CLEW_DYNLIB_IMPORT(module, "clGetKernelInfo"); + __clewGetKernelWorkGroupInfo = (PFNCLGETKERNELWORKGROUPINFO )CLEW_DYNLIB_IMPORT(module, "clGetKernelWorkGroupInfo"); + __clewWaitForEvents = (PFNCLWAITFOREVENTS )CLEW_DYNLIB_IMPORT(module, "clWaitForEvents"); + __clewGetEventInfo = (PFNCLGETEVENTINFO )CLEW_DYNLIB_IMPORT(module, "clGetEventInfo"); + __clewCreateUserEvent = (PFNCLCREATEUSEREVENT )CLEW_DYNLIB_IMPORT(module, "clCreateUserEvent"); + __clewRetainEvent = (PFNCLRETAINEVENT )CLEW_DYNLIB_IMPORT(module, "clRetainEvent"); + __clewReleaseEvent = (PFNCLRELEASEEVENT )CLEW_DYNLIB_IMPORT(module, "clReleaseEvent"); + __clewSetUserEventStatus = (PFNCLSETUSEREVENTSTATUS )CLEW_DYNLIB_IMPORT(module, "clSetUserEventStatus"); + __clewSetEventCallback = (PFNCLSETEVENTCALLBACK )CLEW_DYNLIB_IMPORT(module, "clSetEventCallback"); + __clewGetEventProfilingInfo = (PFNCLGETEVENTPROFILINGINFO )CLEW_DYNLIB_IMPORT(module, "clGetEventProfilingInfo"); + __clewFlush = (PFNCLFLUSH )CLEW_DYNLIB_IMPORT(module, "clFlush"); + __clewFinish = (PFNCLFINISH )CLEW_DYNLIB_IMPORT(module, "clFinish"); + __clewEnqueueReadBuffer = (PFNCLENQUEUEREADBUFFER )CLEW_DYNLIB_IMPORT(module, "clEnqueueReadBuffer"); + __clewEnqueueReadBufferRect = (PFNCLENQUEUEREADBUFFERRECT )CLEW_DYNLIB_IMPORT(module, "clEnqueueReadBufferRect"); + __clewEnqueueWriteBuffer = (PFNCLENQUEUEWRITEBUFFER )CLEW_DYNLIB_IMPORT(module, "clEnqueueWriteBuffer"); + __clewEnqueueWriteBufferRect = (PFNCLENQUEUEWRITEBUFFERRECT )CLEW_DYNLIB_IMPORT(module, "clEnqueueWriteBufferRect"); + __clewEnqueueCopyBuffer = (PFNCLENQUEUECOPYBUFFER )CLEW_DYNLIB_IMPORT(module, "clEnqueueCopyBuffer"); + __clewEnqueueCopyBufferRect = (PFNCLENQUEUECOPYBUFFERRECT )CLEW_DYNLIB_IMPORT(module, "clEnqueueCopyBufferRect"); + __clewEnqueueReadImage = (PFNCLENQUEUEREADIMAGE )CLEW_DYNLIB_IMPORT(module, "clEnqueueReadImage"); + __clewEnqueueWriteImage = (PFNCLENQUEUEWRITEIMAGE )CLEW_DYNLIB_IMPORT(module, "clEnqueueWriteImage"); + __clewEnqueueCopyImage = (PFNCLENQUEUECOPYIMAGE )CLEW_DYNLIB_IMPORT(module, "clEnqueueCopyImage"); + __clewEnqueueCopyImageToBuffer = (PFNCLENQUEUECOPYIMAGETOBUFFER )CLEW_DYNLIB_IMPORT(module, "clEnqueueCopyImageToBuffer"); + __clewEnqueueCopyBufferToImage = (PFNCLENQUEUECOPYBUFFERTOIMAGE )CLEW_DYNLIB_IMPORT(module, "clEnqueueCopyBufferToImage"); + __clewEnqueueMapBuffer = (PFNCLENQUEUEMAPBUFFER )CLEW_DYNLIB_IMPORT(module, "clEnqueueMapBuffer"); + __clewEnqueueMapImage = (PFNCLENQUEUEMAPIMAGE )CLEW_DYNLIB_IMPORT(module, "clEnqueueMapImage"); + __clewEnqueueUnmapMemObject = (PFNCLENQUEUEUNMAPMEMOBJECT )CLEW_DYNLIB_IMPORT(module, "clEnqueueUnmapMemObject"); + __clewEnqueueNDRangeKernel = (PFNCLENQUEUENDRANGEKERNEL )CLEW_DYNLIB_IMPORT(module, "clEnqueueNDRangeKernel"); + __clewEnqueueTask = (PFNCLENQUEUETASK )CLEW_DYNLIB_IMPORT(module, "clEnqueueTask"); + __clewEnqueueNativeKernel = (PFNCLENQUEUENATIVEKERNEL )CLEW_DYNLIB_IMPORT(module, "clEnqueueNativeKernel"); + __clewEnqueueMarker = (PFNCLENQUEUEMARKER )CLEW_DYNLIB_IMPORT(module, "clEnqueueMarker"); + __clewEnqueueWaitForEvents = (PFNCLENQUEUEWAITFOREVENTS )CLEW_DYNLIB_IMPORT(module, "clEnqueueWaitForEvents"); + __clewEnqueueBarrier = (PFNCLENQUEUEBARRIER )CLEW_DYNLIB_IMPORT(module, "clEnqueueBarrier"); + __clewGetExtensionFunctionAddress = (PFNCLGETEXTENSIONFUNCTIONADDRESS )CLEW_DYNLIB_IMPORT(module, "clGetExtensionFunctionAddress"); + + return CLEW_SUCCESS; +} + +const char* clewErrorString(cl_int error) +{ + static const char* strings[] = + { + // Error Codes + "CL_SUCCESS" // 0 + , "CL_DEVICE_NOT_FOUND" // -1 + , "CL_DEVICE_NOT_AVAILABLE" // -2 + , "CL_COMPILER_NOT_AVAILABLE" // -3 + , "CL_MEM_OBJECT_ALLOCATION_FAILURE" // -4 + , "CL_OUT_OF_RESOURCES" // -5 + , "CL_OUT_OF_HOST_MEMORY" // -6 + , "CL_PROFILING_INFO_NOT_AVAILABLE" // -7 + , "CL_MEM_COPY_OVERLAP" // -8 + , "CL_IMAGE_FORMAT_MISMATCH" // -9 + , "CL_IMAGE_FORMAT_NOT_SUPPORTED" // -10 + , "CL_BUILD_PROGRAM_FAILURE" // -11 + , "CL_MAP_FAILURE" // -12 + + , "" // -13 + , "" // -14 + , "" // -15 + , "" // -16 + , "" // -17 + , "" // -18 + , "" // -19 + + , "" // -20 + , "" // -21 + , "" // -22 + , "" // -23 + , "" // -24 + , "" // -25 + , "" // -26 + , "" // -27 + , "" // -28 + , "" // -29 + + , "CL_INVALID_VALUE" // -30 + , "CL_INVALID_DEVICE_TYPE" // -31 + , "CL_INVALID_PLATFORM" // -32 + , "CL_INVALID_DEVICE" // -33 + , "CL_INVALID_CONTEXT" // -34 + , "CL_INVALID_QUEUE_PROPERTIES" // -35 + , "CL_INVALID_COMMAND_QUEUE" // -36 + , "CL_INVALID_HOST_PTR" // -37 + , "CL_INVALID_MEM_OBJECT" // -38 + , "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR" // -39 + , "CL_INVALID_IMAGE_SIZE" // -40 + , "CL_INVALID_SAMPLER" // -41 + , "CL_INVALID_BINARY" // -42 + , "CL_INVALID_BUILD_OPTIONS" // -43 + , "CL_INVALID_PROGRAM" // -44 + , "CL_INVALID_PROGRAM_EXECUTABLE" // -45 + , "CL_INVALID_KERNEL_NAME" // -46 + , "CL_INVALID_KERNEL_DEFINITION" // -47 + , "CL_INVALID_KERNEL" // -48 + , "CL_INVALID_ARG_INDEX" // -49 + , "CL_INVALID_ARG_VALUE" // -50 + , "CL_INVALID_ARG_SIZE" // -51 + , "CL_INVALID_KERNEL_ARGS" // -52 + , "CL_INVALID_WORK_DIMENSION" // -53 + , "CL_INVALID_WORK_GROUP_SIZE" // -54 + , "CL_INVALID_WORK_ITEM_SIZE" // -55 + , "CL_INVALID_GLOBAL_OFFSET" // -56 + , "CL_INVALID_EVENT_WAIT_LIST" // -57 + , "CL_INVALID_EVENT" // -58 + , "CL_INVALID_OPERATION" // -59 + , "CL_INVALID_GL_OBJECT" // -60 + , "CL_INVALID_BUFFER_SIZE" // -61 + , "CL_INVALID_MIP_LEVEL" // -62 + , "CL_INVALID_GLOBAL_WORK_SIZE" // -63 + }; + + return strings[-error]; +} diff --git a/extern/bullet/src/clew/clew.h b/extern/bullet/src/clew/clew.h new file mode 100644 index 000000000000..ee0fef18b414 --- /dev/null +++ b/extern/bullet/src/clew/clew.h @@ -0,0 +1,2397 @@ +#ifndef CLEW_HPP_INCLUDED +#define CLEW_HPP_INCLUDED + +////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2009-2011 Organic Vectory B.V., KindDragon +// Written by George van Venrooij +// +// Distributed under the MIT License. +////////////////////////////////////////////////////////////////////////// + +//! \file clew.h +//! \brief OpenCL run-time loader header +//! +//! This file contains a copy of the contents of CL.H and CL_PLATFORM.H from the +//! official OpenCL spec. The purpose of this code is to load the OpenCL dynamic +//! library at run-time and thus allow the executable to function on many +//! platforms regardless of the vendor of the OpenCL driver actually installed. +//! Some of the techniques used here were inspired by work done in the GLEW +//! library (http://glew.sourceforge.net/) + +// Run-time dynamic linking functionality based on concepts used in GLEW +#ifdef __OPENCL_CL_H +#error cl.h included before clew.h +#endif + +#ifdef __OPENCL_CL_PLATFORM_H +#error cl_platform.h included before clew.h +#endif + +// Prevent cl.h inclusion +#define __OPENCL_CL_H +// Prevent cl_platform.h inclusion +#define __CL_PLATFORM_H + +/******************************************************************************* +* Copyright (c) 2008-2010 The Khronos Group Inc. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and/or associated documentation files (the +* "Materials"), to deal in the Materials without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Materials, and to +* permit persons to whom the Materials are 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 Materials. +* +* THE MATERIALS ARE 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 +* MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +******************************************************************************/ +#ifdef __APPLE__ + /* Contains #defines for AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER below */ + #include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_WIN32) + #define CL_API_ENTRY + #define CL_API_CALL __stdcall + #define CL_CALLBACK __stdcall +#else + #define CL_API_ENTRY + #define CL_API_CALL + #define CL_CALLBACK +#endif +//disabled the APPLE thing, don't know why it is there, is just causes tons of warnings + +#ifdef __APPLE1__ + #define CL_EXTENSION_WEAK_LINK __attribute__((weak_import)) + #define CL_API_SUFFIX__VERSION_1_0 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + #define CL_EXT_SUFFIX__VERSION_1_0 CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + #define CL_API_SUFFIX__VERSION_1_1 CL_EXTENSION_WEAK_LINK + #define CL_EXT_SUFFIX__VERSION_1_1 CL_EXTENSION_WEAK_LINK + #define CL_EXT_SUFFIX__VERSION_1_0_DEPRECATED CL_EXTENSION_WEAK_LINK AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER +#else + #define CL_EXTENSION_WEAK_LINK + #define CL_API_SUFFIX__VERSION_1_0 + #define CL_EXT_SUFFIX__VERSION_1_0 + #define CL_API_SUFFIX__VERSION_1_1 + #define CL_EXT_SUFFIX__VERSION_1_1 + #define CL_EXT_SUFFIX__VERSION_1_0_DEPRECATED +#endif + +#if (defined (_WIN32) && defined(_MSC_VER)) + +/* scalar types */ +typedef signed __int8 cl_char; +typedef unsigned __int8 cl_uchar; +typedef signed __int16 cl_short; +typedef unsigned __int16 cl_ushort; +typedef signed __int32 cl_int; +typedef unsigned __int32 cl_uint; +typedef signed __int64 cl_long; +typedef unsigned __int64 cl_ulong; + +typedef unsigned __int16 cl_half; +typedef float cl_float; +typedef double cl_double; + +/* Macro names and corresponding values defined by OpenCL */ +#define CL_CHAR_BIT 8 +#define CL_SCHAR_MAX 127 +#define CL_SCHAR_MIN (-127-1) +#define CL_CHAR_MAX CL_SCHAR_MAX +#define CL_CHAR_MIN CL_SCHAR_MIN +#define CL_UCHAR_MAX 255 +#define CL_SHRT_MAX 32767 +#define CL_SHRT_MIN (-32767-1) +#define CL_USHRT_MAX 65535 +#define CL_INT_MAX 2147483647 +#define CL_INT_MIN (-2147483647-1) +#define CL_UINT_MAX 0xffffffffU +#define CL_LONG_MAX ((cl_long) 0x7FFFFFFFFFFFFFFFLL) +#define CL_LONG_MIN ((cl_long) -0x7FFFFFFFFFFFFFFFLL - 1LL) +#define CL_ULONG_MAX ((cl_ulong) 0xFFFFFFFFFFFFFFFFULL) + +#define CL_FLT_DIG 6 +#define CL_FLT_MANT_DIG 24 +#define CL_FLT_MAX_10_EXP +38 +#define CL_FLT_MAX_EXP +128 +#define CL_FLT_MIN_10_EXP -37 +#define CL_FLT_MIN_EXP -125 +#define CL_FLT_RADIX 2 +#define CL_FLT_MAX 340282346638528859811704183484516925440.0f +#define CL_FLT_MIN 1.175494350822287507969e-38f +#define CL_FLT_EPSILON 0x1.0p-23f + +#define CL_DBL_DIG 15 +#define CL_DBL_MANT_DIG 53 +#define CL_DBL_MAX_10_EXP +308 +#define CL_DBL_MAX_EXP +1024 +#define CL_DBL_MIN_10_EXP -307 +#define CL_DBL_MIN_EXP -1021 +#define CL_DBL_RADIX 2 +#define CL_DBL_MAX 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0 +#define CL_DBL_MIN 2.225073858507201383090e-308 +#define CL_DBL_EPSILON 2.220446049250313080847e-16 + +#define CL_M_E 2.718281828459045090796 +#define CL_M_LOG2E 1.442695040888963387005 +#define CL_M_LOG10E 0.434294481903251816668 +#define CL_M_LN2 0.693147180559945286227 +#define CL_M_LN10 2.302585092994045901094 +#define CL_M_PI 3.141592653589793115998 +#define CL_M_PI_2 1.570796326794896557999 +#define CL_M_PI_4 0.785398163397448278999 +#define CL_M_1_PI 0.318309886183790691216 +#define CL_M_2_PI 0.636619772367581382433 +#define CL_M_2_SQRTPI 1.128379167095512558561 +#define CL_M_SQRT2 1.414213562373095145475 +#define CL_M_SQRT1_2 0.707106781186547572737 + +#define CL_M_E_F 2.71828174591064f +#define CL_M_LOG2E_F 1.44269502162933f +#define CL_M_LOG10E_F 0.43429449200630f +#define CL_M_LN2_F 0.69314718246460f +#define CL_M_LN10_F 2.30258512496948f +#define CL_M_PI_F 3.14159274101257f +#define CL_M_PI_2_F 1.57079637050629f +#define CL_M_PI_4_F 0.78539818525314f +#define CL_M_1_PI_F 0.31830987334251f +#define CL_M_2_PI_F 0.63661974668503f +#define CL_M_2_SQRTPI_F 1.12837922573090f +#define CL_M_SQRT2_F 1.41421353816986f +#define CL_M_SQRT1_2_F 0.70710676908493f + +#define CL_NAN (CL_INFINITY - CL_INFINITY) +#define CL_HUGE_VALF ((cl_float) 1e50) +#define CL_HUGE_VAL ((cl_double) 1e500) +#define CL_MAXFLOAT CL_FLT_MAX +#define CL_INFINITY CL_HUGE_VALF + +#else + +#include + +/* scalar types */ +typedef int8_t cl_char; +typedef uint8_t cl_uchar; +typedef int16_t cl_short __attribute__((aligned(2))); +typedef uint16_t cl_ushort __attribute__((aligned(2))); +typedef int32_t cl_int __attribute__((aligned(4))); +typedef uint32_t cl_uint __attribute__((aligned(4))); +typedef int64_t cl_long __attribute__((aligned(8))); +typedef uint64_t cl_ulong __attribute__((aligned(8))); + +typedef uint16_t cl_half __attribute__((aligned(2))); +typedef float cl_float __attribute__((aligned(4))); +typedef double cl_double __attribute__((aligned(8))); + +/* Macro names and corresponding values defined by OpenCL */ +#define CL_CHAR_BIT 8 +#define CL_SCHAR_MAX 127 +#define CL_SCHAR_MIN (-127-1) +#define CL_CHAR_MAX CL_SCHAR_MAX +#define CL_CHAR_MIN CL_SCHAR_MIN +#define CL_UCHAR_MAX 255 +#define CL_SHRT_MAX 32767 +#define CL_SHRT_MIN (-32767-1) +#define CL_USHRT_MAX 65535 +#define CL_INT_MAX 2147483647 +#define CL_INT_MIN (-2147483647-1) +#define CL_UINT_MAX 0xffffffffU +#define CL_LONG_MAX ((cl_long) 0x7FFFFFFFFFFFFFFFLL) +#define CL_LONG_MIN ((cl_long) -0x7FFFFFFFFFFFFFFFLL - 1LL) +#define CL_ULONG_MAX ((cl_ulong) 0xFFFFFFFFFFFFFFFFULL) + +#define CL_FLT_DIG 6 +#define CL_FLT_MANT_DIG 24 +#define CL_FLT_MAX_10_EXP +38 +#define CL_FLT_MAX_EXP +128 +#define CL_FLT_MIN_10_EXP -37 +#define CL_FLT_MIN_EXP -125 +#define CL_FLT_RADIX 2 +#define CL_FLT_MAX 0x1.fffffep127f +#define CL_FLT_MIN 0x1.0p-126f +#define CL_FLT_EPSILON 0x1.0p-23f + +#define CL_DBL_DIG 15 +#define CL_DBL_MANT_DIG 53 +#define CL_DBL_MAX_10_EXP +308 +#define CL_DBL_MAX_EXP +1024 +#define CL_DBL_MIN_10_EXP -307 +#define CL_DBL_MIN_EXP -1021 +#define CL_DBL_RADIX 2 +#define CL_DBL_MAX 0x1.fffffffffffffp1023 +#define CL_DBL_MIN 0x1.0p-1022 +#define CL_DBL_EPSILON 0x1.0p-52 + +#define CL_M_E 2.718281828459045090796 +#define CL_M_LOG2E 1.442695040888963387005 +#define CL_M_LOG10E 0.434294481903251816668 +#define CL_M_LN2 0.693147180559945286227 +#define CL_M_LN10 2.302585092994045901094 +#define CL_M_PI 3.141592653589793115998 +#define CL_M_PI_2 1.570796326794896557999 +#define CL_M_PI_4 0.785398163397448278999 +#define CL_M_1_PI 0.318309886183790691216 +#define CL_M_2_PI 0.636619772367581382433 +#define CL_M_2_SQRTPI 1.128379167095512558561 +#define CL_M_SQRT2 1.414213562373095145475 +#define CL_M_SQRT1_2 0.707106781186547572737 + +#define CL_M_E_F 2.71828174591064f +#define CL_M_LOG2E_F 1.44269502162933f +#define CL_M_LOG10E_F 0.43429449200630f +#define CL_M_LN2_F 0.69314718246460f +#define CL_M_LN10_F 2.30258512496948f +#define CL_M_PI_F 3.14159274101257f +#define CL_M_PI_2_F 1.57079637050629f +#define CL_M_PI_4_F 0.78539818525314f +#define CL_M_1_PI_F 0.31830987334251f +#define CL_M_2_PI_F 0.63661974668503f +#define CL_M_2_SQRTPI_F 1.12837922573090f +#define CL_M_SQRT2_F 1.41421353816986f +#define CL_M_SQRT1_2_F 0.70710676908493f + +#if defined( __GNUC__ ) + #define CL_HUGE_VALF __builtin_huge_valf() + #define CL_HUGE_VAL __builtin_huge_val() + #define CL_NAN __builtin_nanf( "" ) +#else + #define CL_HUGE_VALF ((cl_float) 1e50) + #define CL_HUGE_VAL ((cl_double) 1e500) + float nanf( const char * ); + #define CL_NAN nanf( "" ) +#endif +#define CL_MAXFLOAT CL_FLT_MAX +#define CL_INFINITY CL_HUGE_VALF + +#endif + +#include + +/* Mirror types to GL types. Mirror types allow us to avoid deciding which headers to load based on whether we are using GL or GLES here. */ +typedef unsigned int cl_GLuint; +typedef int cl_GLint; +typedef unsigned int cl_GLenum; + +/* + * Vector types + * + * Note: OpenCL requires that all types be naturally aligned. + * This means that vector types must be naturally aligned. + * For example, a vector of four floats must be aligned to + * a 16 byte boundary (calculated as 4 * the natural 4-byte + * alignment of the float). The alignment qualifiers here + * will only function properly if your compiler supports them + * and if you don't actively work to defeat them. For example, + * in order for a cl_float4 to be 16 byte aligned in a struct, + * the start of the struct must itself be 16-byte aligned. + * + * Maintaining proper alignment is the user's responsibility. + */ + + +#ifdef _MSC_VER +#if defined(_M_IX86) +#if _M_IX86_FP >= 0 +#define __SSE__ +#endif +#if _M_IX86_FP >= 1 +#define __SSE2__ +#endif +#elif defined(_M_X64) +#define __SSE__ +#define __SSE2__ +#endif +#endif + +/* Define basic vector types */ +#if defined( __VEC__ ) + #include /* may be omitted depending on compiler. AltiVec spec provides no way to detect whether the header is required. */ + typedef vector unsigned char __cl_uchar16; + typedef vector signed char __cl_char16; + typedef vector unsigned short __cl_ushort8; + typedef vector signed short __cl_short8; + typedef vector unsigned int __cl_uint4; + typedef vector signed int __cl_int4; + typedef vector float __cl_float4; + #define __CL_UCHAR16__ 1 + #define __CL_CHAR16__ 1 + #define __CL_USHORT8__ 1 + #define __CL_SHORT8__ 1 + #define __CL_UINT4__ 1 + #define __CL_INT4__ 1 + #define __CL_FLOAT4__ 1 +#endif + +#if defined( __SSE__ ) + #if defined( __MINGW64__ ) + #include + #else + #include + #endif + #if defined( __GNUC__ ) && !defined( __ICC ) + typedef float __cl_float4 __attribute__((vector_size(16))); + #else + typedef __m128 __cl_float4; + #endif + #define __CL_FLOAT4__ 1 +#endif + +#if defined( __SSE2__ ) + #if defined( __MINGW64__ ) + #include + #else + #include + #endif + #if defined( __GNUC__ ) && !defined( __ICC ) + typedef cl_uchar __cl_uchar16 __attribute__((vector_size(16))); + typedef cl_char __cl_char16 __attribute__((vector_size(16))); + typedef cl_ushort __cl_ushort8 __attribute__((vector_size(16))); + typedef cl_short __cl_short8 __attribute__((vector_size(16))); + typedef cl_uint __cl_uint4 __attribute__((vector_size(16))); + typedef cl_int __cl_int4 __attribute__((vector_size(16))); + typedef cl_ulong __cl_ulong2 __attribute__((vector_size(16))); + typedef cl_long __cl_long2 __attribute__((vector_size(16))); + typedef cl_double __cl_double2 __attribute__((vector_size(16))); + #else + typedef __m128i __cl_uchar16; + typedef __m128i __cl_char16; + typedef __m128i __cl_ushort8; + typedef __m128i __cl_short8; + typedef __m128i __cl_uint4; + typedef __m128i __cl_int4; + typedef __m128i __cl_ulong2; + typedef __m128i __cl_long2; + typedef __m128d __cl_double2; + #endif + #define __CL_UCHAR16__ 1 + #define __CL_CHAR16__ 1 + #define __CL_USHORT8__ 1 + #define __CL_SHORT8__ 1 + #define __CL_INT4__ 1 + #define __CL_UINT4__ 1 + #define __CL_ULONG2__ 1 + #define __CL_LONG2__ 1 + #define __CL_DOUBLE2__ 1 +#endif + +#if defined( __MMX__ ) + #include + #if defined( __GNUC__ ) && !defined( __ICC ) + typedef cl_uchar __cl_uchar8 __attribute__((vector_size(8))); + typedef cl_char __cl_char8 __attribute__((vector_size(8))); + typedef cl_ushort __cl_ushort4 __attribute__((vector_size(8))); + typedef cl_short __cl_short4 __attribute__((vector_size(8))); + typedef cl_uint __cl_uint2 __attribute__((vector_size(8))); + typedef cl_int __cl_int2 __attribute__((vector_size(8))); + typedef cl_ulong __cl_ulong1 __attribute__((vector_size(8))); + typedef cl_long __cl_long1 __attribute__((vector_size(8))); + typedef cl_float __cl_float2 __attribute__((vector_size(8))); + #else + typedef __m64 __cl_uchar8; + typedef __m64 __cl_char8; + typedef __m64 __cl_ushort4; + typedef __m64 __cl_short4; + typedef __m64 __cl_uint2; + typedef __m64 __cl_int2; + typedef __m64 __cl_ulong1; + typedef __m64 __cl_long1; + typedef __m64 __cl_float2; + #endif + #define __CL_UCHAR8__ 1 + #define __CL_CHAR8__ 1 + #define __CL_USHORT4__ 1 + #define __CL_SHORT4__ 1 + #define __CL_INT2__ 1 + #define __CL_UINT2__ 1 + #define __CL_ULONG1__ 1 + #define __CL_LONG1__ 1 + #define __CL_FLOAT2__ 1 +#endif + +#if defined( __AVX__ ) + #if defined( __MINGW64__ ) + #include + #else + #include + #endif + #if defined( __GNUC__ ) && !defined( __ICC ) + typedef cl_float __cl_float8 __attribute__((vector_size(32))); + typedef cl_double __cl_double4 __attribute__((vector_size(32))); + #else + typedef __m256 __cl_float8; + typedef __m256d __cl_double4; + #endif + #define __CL_FLOAT8__ 1 + #define __CL_DOUBLE4__ 1 +#endif + +/* Define alignment keys */ +#if defined( __GNUC__ ) + #define CL_ALIGNED(_x) __attribute__ ((aligned(_x))) +#elif defined( _WIN32) && (_MSC_VER) + /* Alignment keys neutered on windows because MSVC can't swallow function arguments with alignment requirements */ + /* http://msdn.microsoft.com/en-us/library/373ak2y1%28VS.71%29.aspx */ + /* #include */ + /* #define CL_ALIGNED(_x) _CRT_ALIGN(_x) */ + #define CL_ALIGNED(_x) +#else + #warning Need to implement some method to align data here + #define CL_ALIGNED(_x) +#endif + +/* Indicate whether .xyzw, .s0123 and .hi.lo are supported */ +#if (defined( __GNUC__) && ! defined( __STRICT_ANSI__ )) || (defined( _MSC_VER ) && ! defined( __STDC__ )) + /* .xyzw and .s0123...{f|F} are supported */ + #define CL_HAS_NAMED_VECTOR_FIELDS 1 + /* .hi and .lo are supported */ + #define CL_HAS_HI_LO_VECTOR_FIELDS 1 + + #define CL_NAMED_STRUCT_SUPPORTED +#endif + +#if defined( CL_NAMED_STRUCT_SUPPORTED) && defined( _MSC_VER ) +#define __extension__ __pragma(warning(suppress:4201)) +#endif + +/* Define cl_vector types */ + +/* ---- cl_charn ---- */ +typedef union +{ + cl_char CL_ALIGNED(2) s[2]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_char x, y; }; + __extension__ struct{ cl_char s0, s1; }; + __extension__ struct{ cl_char lo, hi; }; +#endif +#if defined( __CL_CHAR2__) + __cl_char2 v2; +#endif +}cl_char2; + +typedef union +{ + cl_char CL_ALIGNED(4) s[4]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_char x, y, z, w; }; + __extension__ struct{ cl_char s0, s1, s2, s3; }; + __extension__ struct{ cl_char2 lo, hi; }; +#endif +#if defined( __CL_CHAR2__) + __cl_char2 v2[2]; +#endif +#if defined( __CL_CHAR4__) + __cl_char4 v4; +#endif +}cl_char4; + +/* cl_char3 is identical in size, alignment and behavior to cl_char4. See section 6.1.5. */ +typedef cl_char4 cl_char3; + +typedef union +{ + cl_char CL_ALIGNED(8) s[8]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_char x, y, z, w; }; + __extension__ struct{ cl_char s0, s1, s2, s3, s4, s5, s6, s7; }; + __extension__ struct{ cl_char4 lo, hi; }; +#endif +#if defined( __CL_CHAR2__) + __cl_char2 v2[4]; +#endif +#if defined( __CL_CHAR4__) + __cl_char4 v4[2]; +#endif +#if defined( __CL_CHAR8__ ) + __cl_char8 v8; +#endif +}cl_char8; + +typedef union +{ + cl_char CL_ALIGNED(16) s[16]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_char x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __extension__ struct{ cl_char s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __extension__ struct{ cl_char8 lo, hi; }; +#endif +#if defined( __CL_CHAR2__) + __cl_char2 v2[8]; +#endif +#if defined( __CL_CHAR4__) + __cl_char4 v4[4]; +#endif +#if defined( __CL_CHAR8__ ) + __cl_char8 v8[2]; +#endif +#if defined( __CL_CHAR16__ ) + __cl_char16 v16; +#endif +}cl_char16; + + +/* ---- cl_ucharn ---- */ +typedef union +{ + cl_uchar CL_ALIGNED(2) s[2]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_uchar x, y; }; + __extension__ struct{ cl_uchar s0, s1; }; + __extension__ struct{ cl_uchar lo, hi; }; +#endif +#if defined( __cl_uchar2__) + __cl_uchar2 v2; +#endif +}cl_uchar2; + +typedef union +{ + cl_uchar CL_ALIGNED(4) s[4]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_uchar x, y, z, w; }; + __extension__ struct{ cl_uchar s0, s1, s2, s3; }; + __extension__ struct{ cl_uchar2 lo, hi; }; +#endif +#if defined( __CL_UCHAR2__) + __cl_uchar2 v2[2]; +#endif +#if defined( __CL_UCHAR4__) + __cl_uchar4 v4; +#endif +}cl_uchar4; + +/* cl_uchar3 is identical in size, alignment and behavior to cl_uchar4. See section 6.1.5. */ +typedef cl_uchar4 cl_uchar3; + +typedef union +{ + cl_uchar CL_ALIGNED(8) s[8]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_uchar x, y, z, w; }; + __extension__ struct{ cl_uchar s0, s1, s2, s3, s4, s5, s6, s7; }; + __extension__ struct{ cl_uchar4 lo, hi; }; +#endif +#if defined( __CL_UCHAR2__) + __cl_uchar2 v2[4]; +#endif +#if defined( __CL_UCHAR4__) + __cl_uchar4 v4[2]; +#endif +#if defined( __CL_UCHAR8__ ) + __cl_uchar8 v8; +#endif +}cl_uchar8; + +typedef union +{ + cl_uchar CL_ALIGNED(16) s[16]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_uchar x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __extension__ struct{ cl_uchar s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __extension__ struct{ cl_uchar8 lo, hi; }; +#endif +#if defined( __CL_UCHAR2__) + __cl_uchar2 v2[8]; +#endif +#if defined( __CL_UCHAR4__) + __cl_uchar4 v4[4]; +#endif +#if defined( __CL_UCHAR8__ ) + __cl_uchar8 v8[2]; +#endif +#if defined( __CL_UCHAR16__ ) + __cl_uchar16 v16; +#endif +}cl_uchar16; + + +/* ---- cl_shortn ---- */ +typedef union +{ + cl_short CL_ALIGNED(4) s[2]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_short x, y; }; + __extension__ struct{ cl_short s0, s1; }; + __extension__ struct{ cl_short lo, hi; }; +#endif +#if defined( __CL_SHORT2__) + __cl_short2 v2; +#endif +}cl_short2; + +typedef union +{ + cl_short CL_ALIGNED(8) s[4]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_short x, y, z, w; }; + __extension__ struct{ cl_short s0, s1, s2, s3; }; + __extension__ struct{ cl_short2 lo, hi; }; +#endif +#if defined( __CL_SHORT2__) + __cl_short2 v2[2]; +#endif +#if defined( __CL_SHORT4__) + __cl_short4 v4; +#endif +}cl_short4; + +/* cl_short3 is identical in size, alignment and behavior to cl_short4. See section 6.1.5. */ +typedef cl_short4 cl_short3; + +typedef union +{ + cl_short CL_ALIGNED(16) s[8]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_short x, y, z, w; }; + __extension__ struct{ cl_short s0, s1, s2, s3, s4, s5, s6, s7; }; + __extension__ struct{ cl_short4 lo, hi; }; +#endif +#if defined( __CL_SHORT2__) + __cl_short2 v2[4]; +#endif +#if defined( __CL_SHORT4__) + __cl_short4 v4[2]; +#endif +#if defined( __CL_SHORT8__ ) + __cl_short8 v8; +#endif +}cl_short8; + +typedef union +{ + cl_short CL_ALIGNED(32) s[16]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_short x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __extension__ struct{ cl_short s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __extension__ struct{ cl_short8 lo, hi; }; +#endif +#if defined( __CL_SHORT2__) + __cl_short2 v2[8]; +#endif +#if defined( __CL_SHORT4__) + __cl_short4 v4[4]; +#endif +#if defined( __CL_SHORT8__ ) + __cl_short8 v8[2]; +#endif +#if defined( __CL_SHORT16__ ) + __cl_short16 v16; +#endif +}cl_short16; + + +/* ---- cl_ushortn ---- */ +typedef union +{ + cl_ushort CL_ALIGNED(4) s[2]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_ushort x, y; }; + __extension__ struct{ cl_ushort s0, s1; }; + __extension__ struct{ cl_ushort lo, hi; }; +#endif +#if defined( __CL_USHORT2__) + __cl_ushort2 v2; +#endif +}cl_ushort2; + +typedef union +{ + cl_ushort CL_ALIGNED(8) s[4]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_ushort x, y, z, w; }; + __extension__ struct{ cl_ushort s0, s1, s2, s3; }; + __extension__ struct{ cl_ushort2 lo, hi; }; +#endif +#if defined( __CL_USHORT2__) + __cl_ushort2 v2[2]; +#endif +#if defined( __CL_USHORT4__) + __cl_ushort4 v4; +#endif +}cl_ushort4; + +/* cl_ushort3 is identical in size, alignment and behavior to cl_ushort4. See section 6.1.5. */ +typedef cl_ushort4 cl_ushort3; + +typedef union +{ + cl_ushort CL_ALIGNED(16) s[8]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_ushort x, y, z, w; }; + __extension__ struct{ cl_ushort s0, s1, s2, s3, s4, s5, s6, s7; }; + __extension__ struct{ cl_ushort4 lo, hi; }; +#endif +#if defined( __CL_USHORT2__) + __cl_ushort2 v2[4]; +#endif +#if defined( __CL_USHORT4__) + __cl_ushort4 v4[2]; +#endif +#if defined( __CL_USHORT8__ ) + __cl_ushort8 v8; +#endif +}cl_ushort8; + +typedef union +{ + cl_ushort CL_ALIGNED(32) s[16]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_ushort x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __extension__ struct{ cl_ushort s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __extension__ struct{ cl_ushort8 lo, hi; }; +#endif +#if defined( __CL_USHORT2__) + __cl_ushort2 v2[8]; +#endif +#if defined( __CL_USHORT4__) + __cl_ushort4 v4[4]; +#endif +#if defined( __CL_USHORT8__ ) + __cl_ushort8 v8[2]; +#endif +#if defined( __CL_USHORT16__ ) + __cl_ushort16 v16; +#endif +}cl_ushort16; + +/* ---- cl_intn ---- */ +typedef union +{ + cl_int CL_ALIGNED(8) s[2]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_int x, y; }; + __extension__ struct{ cl_int s0, s1; }; + __extension__ struct{ cl_int lo, hi; }; +#endif +#if defined( __CL_INT2__) + __cl_int2 v2; +#endif +}cl_int2; + +typedef union +{ + cl_int CL_ALIGNED(16) s[4]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_int x, y, z, w; }; + __extension__ struct{ cl_int s0, s1, s2, s3; }; + __extension__ struct{ cl_int2 lo, hi; }; +#endif +#if defined( __CL_INT2__) + __cl_int2 v2[2]; +#endif +#if defined( __CL_INT4__) + __cl_int4 v4; +#endif +}cl_int4; + +/* cl_int3 is identical in size, alignment and behavior to cl_int4. See section 6.1.5. */ +typedef cl_int4 cl_int3; + +typedef union +{ + cl_int CL_ALIGNED(32) s[8]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_int x, y, z, w; }; + __extension__ struct{ cl_int s0, s1, s2, s3, s4, s5, s6, s7; }; + __extension__ struct{ cl_int4 lo, hi; }; +#endif +#if defined( __CL_INT2__) + __cl_int2 v2[4]; +#endif +#if defined( __CL_INT4__) + __cl_int4 v4[2]; +#endif +#if defined( __CL_INT8__ ) + __cl_int8 v8; +#endif +}cl_int8; + +typedef union +{ + cl_int CL_ALIGNED(64) s[16]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_int x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __extension__ struct{ cl_int s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __extension__ struct{ cl_int8 lo, hi; }; +#endif +#if defined( __CL_INT2__) + __cl_int2 v2[8]; +#endif +#if defined( __CL_INT4__) + __cl_int4 v4[4]; +#endif +#if defined( __CL_INT8__ ) + __cl_int8 v8[2]; +#endif +#if defined( __CL_INT16__ ) + __cl_int16 v16; +#endif +}cl_int16; + + +/* ---- cl_uintn ---- */ +typedef union +{ + cl_uint CL_ALIGNED(8) s[2]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_uint x, y; }; + __extension__ struct{ cl_uint s0, s1; }; + __extension__ struct{ cl_uint lo, hi; }; +#endif +#if defined( __CL_UINT2__) + __cl_uint2 v2; +#endif +}cl_uint2; + +typedef union +{ + cl_uint CL_ALIGNED(16) s[4]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_uint x, y, z, w; }; + __extension__ struct{ cl_uint s0, s1, s2, s3; }; + __extension__ struct{ cl_uint2 lo, hi; }; +#endif +#if defined( __CL_UINT2__) + __cl_uint2 v2[2]; +#endif +#if defined( __CL_UINT4__) + __cl_uint4 v4; +#endif +}cl_uint4; + +/* cl_uint3 is identical in size, alignment and behavior to cl_uint4. See section 6.1.5. */ +typedef cl_uint4 cl_uint3; + +typedef union +{ + cl_uint CL_ALIGNED(32) s[8]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_uint x, y, z, w; }; + __extension__ struct{ cl_uint s0, s1, s2, s3, s4, s5, s6, s7; }; + __extension__ struct{ cl_uint4 lo, hi; }; +#endif +#if defined( __CL_UINT2__) + __cl_uint2 v2[4]; +#endif +#if defined( __CL_UINT4__) + __cl_uint4 v4[2]; +#endif +#if defined( __CL_UINT8__ ) + __cl_uint8 v8; +#endif +}cl_uint8; + +typedef union +{ + cl_uint CL_ALIGNED(64) s[16]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_uint x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __extension__ struct{ cl_uint s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __extension__ struct{ cl_uint8 lo, hi; }; +#endif +#if defined( __CL_UINT2__) + __cl_uint2 v2[8]; +#endif +#if defined( __CL_UINT4__) + __cl_uint4 v4[4]; +#endif +#if defined( __CL_UINT8__ ) + __cl_uint8 v8[2]; +#endif +#if defined( __CL_UINT16__ ) + __cl_uint16 v16; +#endif +}cl_uint16; + +/* ---- cl_longn ---- */ +typedef union +{ + cl_long CL_ALIGNED(16) s[2]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_long x, y; }; + __extension__ struct{ cl_long s0, s1; }; + __extension__ struct{ cl_long lo, hi; }; +#endif +#if defined( __CL_LONG2__) + __cl_long2 v2; +#endif +}cl_long2; + +typedef union +{ + cl_long CL_ALIGNED(32) s[4]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_long x, y, z, w; }; + __extension__ struct{ cl_long s0, s1, s2, s3; }; + __extension__ struct{ cl_long2 lo, hi; }; +#endif +#if defined( __CL_LONG2__) + __cl_long2 v2[2]; +#endif +#if defined( __CL_LONG4__) + __cl_long4 v4; +#endif +}cl_long4; + +/* cl_long3 is identical in size, alignment and behavior to cl_long4. See section 6.1.5. */ +typedef cl_long4 cl_long3; + +typedef union +{ + cl_long CL_ALIGNED(64) s[8]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_long x, y, z, w; }; + __extension__ struct{ cl_long s0, s1, s2, s3, s4, s5, s6, s7; }; + __extension__ struct{ cl_long4 lo, hi; }; +#endif +#if defined( __CL_LONG2__) + __cl_long2 v2[4]; +#endif +#if defined( __CL_LONG4__) + __cl_long4 v4[2]; +#endif +#if defined( __CL_LONG8__ ) + __cl_long8 v8; +#endif +}cl_long8; + +typedef union +{ + cl_long CL_ALIGNED(128) s[16]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_long x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __extension__ struct{ cl_long s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __extension__ struct{ cl_long8 lo, hi; }; +#endif +#if defined( __CL_LONG2__) + __cl_long2 v2[8]; +#endif +#if defined( __CL_LONG4__) + __cl_long4 v4[4]; +#endif +#if defined( __CL_LONG8__ ) + __cl_long8 v8[2]; +#endif +#if defined( __CL_LONG16__ ) + __cl_long16 v16; +#endif +}cl_long16; + + +/* ---- cl_ulongn ---- */ +typedef union +{ + cl_ulong CL_ALIGNED(16) s[2]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_ulong x, y; }; + __extension__ struct{ cl_ulong s0, s1; }; + __extension__ struct{ cl_ulong lo, hi; }; +#endif +#if defined( __CL_ULONG2__) + __cl_ulong2 v2; +#endif +}cl_ulong2; + +typedef union +{ + cl_ulong CL_ALIGNED(32) s[4]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_ulong x, y, z, w; }; + __extension__ struct{ cl_ulong s0, s1, s2, s3; }; + __extension__ struct{ cl_ulong2 lo, hi; }; +#endif +#if defined( __CL_ULONG2__) + __cl_ulong2 v2[2]; +#endif +#if defined( __CL_ULONG4__) + __cl_ulong4 v4; +#endif +}cl_ulong4; + +/* cl_ulong3 is identical in size, alignment and behavior to cl_ulong4. See section 6.1.5. */ +typedef cl_ulong4 cl_ulong3; + +typedef union +{ + cl_ulong CL_ALIGNED(64) s[8]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_ulong x, y, z, w; }; + __extension__ struct{ cl_ulong s0, s1, s2, s3, s4, s5, s6, s7; }; + __extension__ struct{ cl_ulong4 lo, hi; }; +#endif +#if defined( __CL_ULONG2__) + __cl_ulong2 v2[4]; +#endif +#if defined( __CL_ULONG4__) + __cl_ulong4 v4[2]; +#endif +#if defined( __CL_ULONG8__ ) + __cl_ulong8 v8; +#endif +}cl_ulong8; + +typedef union +{ + cl_ulong CL_ALIGNED(128) s[16]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_ulong x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __extension__ struct{ cl_ulong s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __extension__ struct{ cl_ulong8 lo, hi; }; +#endif +#if defined( __CL_ULONG2__) + __cl_ulong2 v2[8]; +#endif +#if defined( __CL_ULONG4__) + __cl_ulong4 v4[4]; +#endif +#if defined( __CL_ULONG8__ ) + __cl_ulong8 v8[2]; +#endif +#if defined( __CL_ULONG16__ ) + __cl_ulong16 v16; +#endif +}cl_ulong16; + + +/* --- cl_floatn ---- */ + +typedef union +{ + cl_float CL_ALIGNED(8) s[2]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_float x, y; }; + __extension__ struct{ cl_float s0, s1; }; + __extension__ struct{ cl_float lo, hi; }; +#endif +#if defined( __CL_FLOAT2__) + __cl_float2 v2; +#endif +}cl_float2; + +typedef union +{ + cl_float CL_ALIGNED(16) s[4]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_float x, y, z, w; }; + __extension__ struct{ cl_float s0, s1, s2, s3; }; + __extension__ struct{ cl_float2 lo, hi; }; +#endif +#if defined( __CL_FLOAT2__) + __cl_float2 v2[2]; +#endif +#if defined( __CL_FLOAT4__) + __cl_float4 v4; +#endif +}cl_float4; + +/* cl_float3 is identical in size, alignment and behavior to cl_float4. See section 6.1.5. */ +typedef cl_float4 cl_float3; + +typedef union +{ + cl_float CL_ALIGNED(32) s[8]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_float x, y, z, w; }; + __extension__ struct{ cl_float s0, s1, s2, s3, s4, s5, s6, s7; }; + __extension__ struct{ cl_float4 lo, hi; }; +#endif +#if defined( __CL_FLOAT2__) + __cl_float2 v2[4]; +#endif +#if defined( __CL_FLOAT4__) + __cl_float4 v4[2]; +#endif +#if defined( __CL_FLOAT8__ ) + __cl_float8 v8; +#endif +}cl_float8; + +typedef union +{ + cl_float CL_ALIGNED(64) s[16]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_float x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __extension__ struct{ cl_float s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __extension__ struct{ cl_float8 lo, hi; }; +#endif +#if defined( __CL_FLOAT2__) + __cl_float2 v2[8]; +#endif +#if defined( __CL_FLOAT4__) + __cl_float4 v4[4]; +#endif +#if defined( __CL_FLOAT8__ ) + __cl_float8 v8[2]; +#endif +#if defined( __CL_FLOAT16__ ) + __cl_float16 v16; +#endif +}cl_float16; + +/* --- cl_doublen ---- */ + +typedef union +{ + cl_double CL_ALIGNED(16) s[2]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_double x, y; }; + __extension__ struct{ cl_double s0, s1; }; + __extension__ struct{ cl_double lo, hi; }; +#endif +#if defined( __CL_DOUBLE2__) + __cl_double2 v2; +#endif +}cl_double2; + +typedef union +{ + cl_double CL_ALIGNED(32) s[4]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_double x, y, z, w; }; + __extension__ struct{ cl_double s0, s1, s2, s3; }; + __extension__ struct{ cl_double2 lo, hi; }; +#endif +#if defined( __CL_DOUBLE2__) + __cl_double2 v2[2]; +#endif +#if defined( __CL_DOUBLE4__) + __cl_double4 v4; +#endif +}cl_double4; + +/* cl_double3 is identical in size, alignment and behavior to cl_double4. See section 6.1.5. */ +typedef cl_double4 cl_double3; + +typedef union +{ + cl_double CL_ALIGNED(64) s[8]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_double x, y, z, w; }; + __extension__ struct{ cl_double s0, s1, s2, s3, s4, s5, s6, s7; }; + __extension__ struct{ cl_double4 lo, hi; }; +#endif +#if defined( __CL_DOUBLE2__) + __cl_double2 v2[4]; +#endif +#if defined( __CL_DOUBLE4__) + __cl_double4 v4[2]; +#endif +#if defined( __CL_DOUBLE8__ ) + __cl_double8 v8; +#endif +}cl_double8; + +typedef union +{ + cl_double CL_ALIGNED(128) s[16]; +#if defined( CL_NAMED_STRUCT_SUPPORTED ) + __extension__ struct{ cl_double x, y, z, w, __spacer4, __spacer5, __spacer6, __spacer7, __spacer8, __spacer9, sa, sb, sc, sd, se, sf; }; + __extension__ struct{ cl_double s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, sA, sB, sC, sD, sE, sF; }; + __extension__ struct{ cl_double8 lo, hi; }; +#endif +#if defined( __CL_DOUBLE2__) + __cl_double2 v2[8]; +#endif +#if defined( __CL_DOUBLE4__) + __cl_double4 v4[4]; +#endif +#if defined( __CL_DOUBLE8__ ) + __cl_double8 v8[2]; +#endif +#if defined( __CL_DOUBLE16__ ) + __cl_double16 v16; +#endif +}cl_double16; + +/* Macro to facilitate debugging + * Usage: + * Place CL_PROGRAM_STRING_DEBUG_INFO on the line before the first line of your source. + * The first line ends with: CL_PROGRAM_STRING_BEGIN \" + * Each line thereafter of OpenCL C source must end with: \n\ + * The last line ends in "; + * + * Example: + * + * const char *my_program = CL_PROGRAM_STRING_BEGIN "\ + * kernel void foo( int a, float * b ) \n\ + * { \n\ + * // my comment \n\ + * *b[ get_global_id(0)] = a; \n\ + * } \n\ + * "; + * + * This should correctly set up the line, (column) and file information for your source + * string so you can do source level debugging. + */ +#define __CL_STRINGIFY( _x ) # _x +#define _CL_STRINGIFY( _x ) __CL_STRINGIFY( _x ) +#define CL_PROGRAM_STRING_DEBUG_INFO "#line " _CL_STRINGIFY(__LINE__) " \"" __FILE__ "\" \n\n" + +// CL.h contents +/******************************************************************************/ + +typedef struct _cl_platform_id * cl_platform_id; +typedef struct _cl_device_id * cl_device_id; +typedef struct _cl_context * cl_context; +typedef struct _cl_command_queue * cl_command_queue; +typedef struct _cl_mem * cl_mem; +typedef struct _cl_program * cl_program; +typedef struct _cl_kernel * cl_kernel; +typedef struct _cl_event * cl_event; +typedef struct _cl_sampler * cl_sampler; + +typedef cl_uint cl_bool; /* WARNING! Unlike cl_ types in cl_platform.h, cl_bool is not guaranteed to be the same size as the bool in kernels. */ +typedef cl_ulong cl_bitfield; +typedef cl_bitfield cl_device_type; +typedef cl_uint cl_platform_info; +typedef cl_uint cl_device_info; +typedef cl_bitfield cl_device_fp_config; +typedef cl_uint cl_device_mem_cache_type; +typedef cl_uint cl_device_local_mem_type; +typedef cl_bitfield cl_device_exec_capabilities; +typedef cl_bitfield cl_command_queue_properties; + +typedef intptr_t cl_context_properties; +typedef cl_uint cl_context_info; +typedef cl_uint cl_command_queue_info; +typedef cl_uint cl_channel_order; +typedef cl_uint cl_channel_type; +typedef cl_bitfield cl_mem_flags; +typedef cl_uint cl_mem_object_type; +typedef cl_uint cl_mem_info; +typedef cl_uint cl_image_info; +typedef cl_uint cl_buffer_create_type; +typedef cl_uint cl_addressing_mode; +typedef cl_uint cl_filter_mode; +typedef cl_uint cl_sampler_info; +typedef cl_bitfield cl_map_flags; +typedef cl_uint cl_program_info; +typedef cl_uint cl_program_build_info; +typedef cl_int cl_build_status; +typedef cl_uint cl_kernel_info; +typedef cl_uint cl_kernel_work_group_info; +typedef cl_uint cl_event_info; +typedef cl_uint cl_command_type; +typedef cl_uint cl_profiling_info; + +typedef struct _cl_image_format { + cl_channel_order image_channel_order; + cl_channel_type image_channel_data_type; +} cl_image_format; + + +typedef struct _cl_buffer_region { + size_t origin; + size_t size; +} cl_buffer_region; + +/******************************************************************************/ + +/* Error Codes */ +#define CL_SUCCESS 0 +#define CL_DEVICE_NOT_FOUND -1 +#define CL_DEVICE_NOT_AVAILABLE -2 +#define CL_COMPILER_NOT_AVAILABLE -3 +#define CL_MEM_OBJECT_ALLOCATION_FAILURE -4 +#define CL_OUT_OF_RESOURCES -5 +#define CL_OUT_OF_HOST_MEMORY -6 +#define CL_PROFILING_INFO_NOT_AVAILABLE -7 +#define CL_MEM_COPY_OVERLAP -8 +#define CL_IMAGE_FORMAT_MISMATCH -9 +#define CL_IMAGE_FORMAT_NOT_SUPPORTED -10 +#define CL_BUILD_PROGRAM_FAILURE -11 +#define CL_MAP_FAILURE -12 +#define CL_MISALIGNED_SUB_BUFFER_OFFSET -13 +#define CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST -14 + +#define CL_INVALID_VALUE -30 +#define CL_INVALID_DEVICE_TYPE -31 +#define CL_INVALID_PLATFORM -32 +#define CL_INVALID_DEVICE -33 +#define CL_INVALID_CONTEXT -34 +#define CL_INVALID_QUEUE_PROPERTIES -35 +#define CL_INVALID_COMMAND_QUEUE -36 +#define CL_INVALID_HOST_PTR -37 +#define CL_INVALID_MEM_OBJECT -38 +#define CL_INVALID_IMAGE_FORMAT_DESCRIPTOR -39 +#define CL_INVALID_IMAGE_SIZE -40 +#define CL_INVALID_SAMPLER -41 +#define CL_INVALID_BINARY -42 +#define CL_INVALID_BUILD_OPTIONS -43 +#define CL_INVALID_PROGRAM -44 +#define CL_INVALID_PROGRAM_EXECUTABLE -45 +#define CL_INVALID_KERNEL_NAME -46 +#define CL_INVALID_KERNEL_DEFINITION -47 +#define CL_INVALID_KERNEL -48 +#define CL_INVALID_ARG_INDEX -49 +#define CL_INVALID_ARG_VALUE -50 +#define CL_INVALID_ARG_SIZE -51 +#define CL_INVALID_KERNEL_ARGS -52 +#define CL_INVALID_WORK_DIMENSION -53 +#define CL_INVALID_WORK_GROUP_SIZE -54 +#define CL_INVALID_WORK_ITEM_SIZE -55 +#define CL_INVALID_GLOBAL_OFFSET -56 +#define CL_INVALID_EVENT_WAIT_LIST -57 +#define CL_INVALID_EVENT -58 +#define CL_INVALID_OPERATION -59 +#define CL_INVALID_GL_OBJECT -60 +#define CL_INVALID_BUFFER_SIZE -61 +#define CL_INVALID_MIP_LEVEL -62 +#define CL_INVALID_GLOBAL_WORK_SIZE -63 +#define CL_INVALID_PROPERTY -64 + +/* OpenCL Version */ +#define CL_VERSION_1_0 1 +#define CL_VERSION_1_1 1 + +/* cl_bool */ +#define CL_FALSE 0 +#define CL_TRUE 1 + +/* cl_platform_info */ +#define CL_PLATFORM_PROFILE 0x0900 +#define CL_PLATFORM_VERSION 0x0901 +#define CL_PLATFORM_NAME 0x0902 +#define CL_PLATFORM_VENDOR 0x0903 +#define CL_PLATFORM_EXTENSIONS 0x0904 + +/* cl_device_type - bitfield */ +#define CL_DEVICE_TYPE_DEFAULT (1 << 0) +#define CL_DEVICE_TYPE_CPU (1 << 1) +#define CL_DEVICE_TYPE_GPU (1 << 2) +#define CL_DEVICE_TYPE_ACCELERATOR (1 << 3) +#define CL_DEVICE_TYPE_ALL 0xFFFFFFFF + +/* cl_device_info */ +#define CL_DEVICE_TYPE 0x1000 +#define CL_DEVICE_VENDOR_ID 0x1001 +#define CL_DEVICE_MAX_COMPUTE_UNITS 0x1002 +#define CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS 0x1003 +#define CL_DEVICE_MAX_WORK_GROUP_SIZE 0x1004 +#define CL_DEVICE_MAX_WORK_ITEM_SIZES 0x1005 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR 0x1006 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT 0x1007 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT 0x1008 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG 0x1009 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT 0x100A +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE 0x100B +#define CL_DEVICE_MAX_CLOCK_FREQUENCY 0x100C +#define CL_DEVICE_ADDRESS_BITS 0x100D +#define CL_DEVICE_MAX_READ_IMAGE_ARGS 0x100E +#define CL_DEVICE_MAX_WRITE_IMAGE_ARGS 0x100F +#define CL_DEVICE_MAX_MEM_ALLOC_SIZE 0x1010 +#define CL_DEVICE_IMAGE2D_MAX_WIDTH 0x1011 +#define CL_DEVICE_IMAGE2D_MAX_HEIGHT 0x1012 +#define CL_DEVICE_IMAGE3D_MAX_WIDTH 0x1013 +#define CL_DEVICE_IMAGE3D_MAX_HEIGHT 0x1014 +#define CL_DEVICE_IMAGE3D_MAX_DEPTH 0x1015 +#define CL_DEVICE_IMAGE_SUPPORT 0x1016 +#define CL_DEVICE_MAX_PARAMETER_SIZE 0x1017 +#define CL_DEVICE_MAX_SAMPLERS 0x1018 +#define CL_DEVICE_MEM_BASE_ADDR_ALIGN 0x1019 +#define CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE 0x101A +#define CL_DEVICE_SINGLE_FP_CONFIG 0x101B +#define CL_DEVICE_GLOBAL_MEM_CACHE_TYPE 0x101C +#define CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE 0x101D +#define CL_DEVICE_GLOBAL_MEM_CACHE_SIZE 0x101E +#define CL_DEVICE_GLOBAL_MEM_SIZE 0x101F +#define CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE 0x1020 +#define CL_DEVICE_MAX_CONSTANT_ARGS 0x1021 +#define CL_DEVICE_LOCAL_MEM_TYPE 0x1022 +#define CL_DEVICE_LOCAL_MEM_SIZE 0x1023 +#define CL_DEVICE_ERROR_CORRECTION_SUPPORT 0x1024 +#define CL_DEVICE_PROFILING_TIMER_RESOLUTION 0x1025 +#define CL_DEVICE_ENDIAN_LITTLE 0x1026 +#define CL_DEVICE_AVAILABLE 0x1027 +#define CL_DEVICE_COMPILER_AVAILABLE 0x1028 +#define CL_DEVICE_EXECUTION_CAPABILITIES 0x1029 +#define CL_DEVICE_QUEUE_PROPERTIES 0x102A +#define CL_DEVICE_NAME 0x102B +#define CL_DEVICE_VENDOR 0x102C +#define CL_DRIVER_VERSION 0x102D +#define CL_DEVICE_PROFILE 0x102E +#define CL_DEVICE_VERSION 0x102F +#define CL_DEVICE_EXTENSIONS 0x1030 +#define CL_DEVICE_PLATFORM 0x1031 +/* 0x1032 reserved for CL_DEVICE_DOUBLE_FP_CONFIG */ +/* 0x1033 reserved for CL_DEVICE_HALF_FP_CONFIG */ +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF 0x1034 +#define CL_DEVICE_HOST_UNIFIED_MEMORY 0x1035 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR 0x1036 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT 0x1037 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_INT 0x1038 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG 0x1039 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT 0x103A +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE 0x103B +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF 0x103C +#define CL_DEVICE_OPENCL_C_VERSION 0x103D + +/* cl_device_fp_config - bitfield */ +#define CL_FP_DENORM (1 << 0) +#define CL_FP_INF_NAN (1 << 1) +#define CL_FP_ROUND_TO_NEAREST (1 << 2) +#define CL_FP_ROUND_TO_ZERO (1 << 3) +#define CL_FP_ROUND_TO_INF (1 << 4) +#define CL_FP_FMA (1 << 5) +#define CL_FP_SOFT_FLOAT (1 << 6) + +/* cl_device_mem_cache_type */ +#define CL_NONE 0x0 +#define CL_READ_ONLY_CACHE 0x1 +#define CL_READ_WRITE_CACHE 0x2 + +/* cl_device_local_mem_type */ +#define CL_LOCAL 0x1 +#define CL_GLOBAL 0x2 + +/* cl_device_exec_capabilities - bitfield */ +#define CL_EXEC_KERNEL (1 << 0) +#define CL_EXEC_NATIVE_KERNEL (1 << 1) + +/* cl_command_queue_properties - bitfield */ +#define CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE (1 << 0) +#define CL_QUEUE_PROFILING_ENABLE (1 << 1) + +/* cl_context_info */ +#define CL_CONTEXT_REFERENCE_COUNT 0x1080 +#define CL_CONTEXT_DEVICES 0x1081 +#define CL_CONTEXT_PROPERTIES 0x1082 +#define CL_CONTEXT_NUM_DEVICES 0x1083 + +/* cl_context_info + cl_context_properties */ +#define CL_CONTEXT_PLATFORM 0x1084 + +/* cl_command_queue_info */ +#define CL_QUEUE_CONTEXT 0x1090 +#define CL_QUEUE_DEVICE 0x1091 +#define CL_QUEUE_REFERENCE_COUNT 0x1092 +#define CL_QUEUE_PROPERTIES 0x1093 + +/* cl_mem_flags - bitfield */ +#define CL_MEM_READ_WRITE (1 << 0) +#define CL_MEM_WRITE_ONLY (1 << 1) +#define CL_MEM_READ_ONLY (1 << 2) +#define CL_MEM_USE_HOST_PTR (1 << 3) +#define CL_MEM_ALLOC_HOST_PTR (1 << 4) +#define CL_MEM_COPY_HOST_PTR (1 << 5) + +/* cl_channel_order */ +#define CL_R 0x10B0 +#define CL_A 0x10B1 +#define CL_RG 0x10B2 +#define CL_RA 0x10B3 +#define CL_RGB 0x10B4 +#define CL_RGBA 0x10B5 +#define CL_BGRA 0x10B6 +#define CL_ARGB 0x10B7 +#define CL_INTENSITY 0x10B8 +#define CL_LUMINANCE 0x10B9 +#define CL_Rx 0x10BA +#define CL_RGx 0x10BB +#define CL_RGBx 0x10BC + +/* cl_channel_type */ +#define CL_SNORM_INT8 0x10D0 +#define CL_SNORM_INT16 0x10D1 +#define CL_UNORM_INT8 0x10D2 +#define CL_UNORM_INT16 0x10D3 +#define CL_UNORM_SHORT_565 0x10D4 +#define CL_UNORM_SHORT_555 0x10D5 +#define CL_UNORM_INT_101010 0x10D6 +#define CL_SIGNED_INT8 0x10D7 +#define CL_SIGNED_INT16 0x10D8 +#define CL_SIGNED_INT32 0x10D9 +#define CL_UNSIGNED_INT8 0x10DA +#define CL_UNSIGNED_INT16 0x10DB +#define CL_UNSIGNED_INT32 0x10DC +#define CL_HALF_FLOAT 0x10DD +#define CL_FLOAT 0x10DE + +/* cl_mem_object_type */ +#define CL_MEM_OBJECT_BUFFER 0x10F0 +#define CL_MEM_OBJECT_IMAGE2D 0x10F1 +#define CL_MEM_OBJECT_IMAGE3D 0x10F2 + +/* cl_mem_info */ +#define CL_MEM_TYPE 0x1100 +#define CL_MEM_FLAGS 0x1101 +#define CL_MEM_SIZE 0x1102 +#define CL_MEM_HOST_PTR 0x1103 +#define CL_MEM_MAP_COUNT 0x1104 +#define CL_MEM_REFERENCE_COUNT 0x1105 +#define CL_MEM_CONTEXT 0x1106 +#define CL_MEM_ASSOCIATED_MEMOBJECT 0x1107 +#define CL_MEM_OFFSET 0x1108 + +/* cl_image_info */ +#define CL_IMAGE_FORMAT 0x1110 +#define CL_IMAGE_ELEMENT_SIZE 0x1111 +#define CL_IMAGE_ROW_PITCH 0x1112 +#define CL_IMAGE_SLICE_PITCH 0x1113 +#define CL_IMAGE_WIDTH 0x1114 +#define CL_IMAGE_HEIGHT 0x1115 +#define CL_IMAGE_DEPTH 0x1116 + +/* cl_addressing_mode */ +#define CL_ADDRESS_NONE 0x1130 +#define CL_ADDRESS_CLAMP_TO_EDGE 0x1131 +#define CL_ADDRESS_CLAMP 0x1132 +#define CL_ADDRESS_REPEAT 0x1133 +#define CL_ADDRESS_MIRRORED_REPEAT 0x1134 + +/* cl_filter_mode */ +#define CL_FILTER_NEAREST 0x1140 +#define CL_FILTER_LINEAR 0x1141 + +/* cl_sampler_info */ +#define CL_SAMPLER_REFERENCE_COUNT 0x1150 +#define CL_SAMPLER_CONTEXT 0x1151 +#define CL_SAMPLER_NORMALIZED_COORDS 0x1152 +#define CL_SAMPLER_ADDRESSING_MODE 0x1153 +#define CL_SAMPLER_FILTER_MODE 0x1154 + +/* cl_map_flags - bitfield */ +#define CL_MAP_READ (1 << 0) +#define CL_MAP_WRITE (1 << 1) + +/* cl_program_info */ +#define CL_PROGRAM_REFERENCE_COUNT 0x1160 +#define CL_PROGRAM_CONTEXT 0x1161 +#define CL_PROGRAM_NUM_DEVICES 0x1162 +#define CL_PROGRAM_DEVICES 0x1163 +#define CL_PROGRAM_SOURCE 0x1164 +#define CL_PROGRAM_BINARY_SIZES 0x1165 +#define CL_PROGRAM_BINARIES 0x1166 + +/* cl_program_build_info */ +#define CL_PROGRAM_BUILD_STATUS 0x1181 +#define CL_PROGRAM_BUILD_OPTIONS 0x1182 +#define CL_PROGRAM_BUILD_LOG 0x1183 + +/* cl_build_status */ +#define CL_BUILD_SUCCESS 0 +#define CL_BUILD_NONE -1 +#define CL_BUILD_ERROR -2 +#define CL_BUILD_IN_PROGRESS -3 + +/* cl_kernel_info */ +#define CL_KERNEL_FUNCTION_NAME 0x1190 +#define CL_KERNEL_NUM_ARGS 0x1191 +#define CL_KERNEL_REFERENCE_COUNT 0x1192 +#define CL_KERNEL_CONTEXT 0x1193 +#define CL_KERNEL_PROGRAM 0x1194 + +/* cl_kernel_work_group_info */ +#define CL_KERNEL_WORK_GROUP_SIZE 0x11B0 +#define CL_KERNEL_COMPILE_WORK_GROUP_SIZE 0x11B1 +#define CL_KERNEL_LOCAL_MEM_SIZE 0x11B2 +#define CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE 0x11B3 +#define CL_KERNEL_PRIVATE_MEM_SIZE 0x11B4 + +/* cl_event_info */ +#define CL_EVENT_COMMAND_QUEUE 0x11D0 +#define CL_EVENT_COMMAND_TYPE 0x11D1 +#define CL_EVENT_REFERENCE_COUNT 0x11D2 +#define CL_EVENT_COMMAND_EXECUTION_STATUS 0x11D3 +#define CL_EVENT_CONTEXT 0x11D4 + +/* cl_command_type */ +#define CL_COMMAND_NDRANGE_KERNEL 0x11F0 +#define CL_COMMAND_TASK 0x11F1 +#define CL_COMMAND_NATIVE_KERNEL 0x11F2 +#define CL_COMMAND_READ_BUFFER 0x11F3 +#define CL_COMMAND_WRITE_BUFFER 0x11F4 +#define CL_COMMAND_COPY_BUFFER 0x11F5 +#define CL_COMMAND_READ_IMAGE 0x11F6 +#define CL_COMMAND_WRITE_IMAGE 0x11F7 +#define CL_COMMAND_COPY_IMAGE 0x11F8 +#define CL_COMMAND_COPY_IMAGE_TO_BUFFER 0x11F9 +#define CL_COMMAND_COPY_BUFFER_TO_IMAGE 0x11FA +#define CL_COMMAND_MAP_BUFFER 0x11FB +#define CL_COMMAND_MAP_IMAGE 0x11FC +#define CL_COMMAND_UNMAP_MEM_OBJECT 0x11FD +#define CL_COMMAND_MARKER 0x11FE +#define CL_COMMAND_ACQUIRE_GL_OBJECTS 0x11FF +#define CL_COMMAND_RELEASE_GL_OBJECTS 0x1200 +#define CL_COMMAND_READ_BUFFER_RECT 0x1201 +#define CL_COMMAND_WRITE_BUFFER_RECT 0x1202 +#define CL_COMMAND_COPY_BUFFER_RECT 0x1203 +#define CL_COMMAND_USER 0x1204 + +/* command execution status */ +#define CL_COMPLETE 0x0 +#define CL_RUNNING 0x1 +#define CL_SUBMITTED 0x2 +#define CL_QUEUED 0x3 + +/* cl_buffer_create_type */ +#define CL_BUFFER_CREATE_TYPE_REGION 0x1220 + +/* cl_profiling_info */ +#define CL_PROFILING_COMMAND_QUEUED 0x1280 +#define CL_PROFILING_COMMAND_SUBMIT 0x1281 +#define CL_PROFILING_COMMAND_START 0x1282 +#define CL_PROFILING_COMMAND_END 0x1283 + +/********************************************************************************************************/ + +/********************************************************************************************************/ + +/* Function signature typedef's */ + +/* Platform API */ +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLGETPLATFORMIDS)(cl_uint /* num_entries */, + cl_platform_id * /* platforms */, + cl_uint * /* num_platforms */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLGETPLATFORMINFO)(cl_platform_id /* platform */, + cl_platform_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +/* Device APIs */ +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLGETDEVICEIDS)(cl_platform_id /* platform */, + cl_device_type /* device_type */, + cl_uint /* num_entries */, + cl_device_id * /* devices */, + cl_uint * /* num_devices */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLGETDEVICEINFO)(cl_device_id /* device */, + cl_device_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +// Context APIs +typedef CL_API_ENTRY cl_context (CL_API_CALL * +PFNCLCREATECONTEXT)(const cl_context_properties * /* properties */, + cl_uint /* num_devices */, + const cl_device_id * /* devices */, + void (CL_CALLBACK * /* pfn_notify */)(const char *, const void *, size_t, void *), + void * /* user_data */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_context (CL_API_CALL * +PFNCLCREATECONTEXTFROMTYPE)(const cl_context_properties * /* properties */, + cl_device_type /* device_type */, + void (CL_CALLBACK * /* pfn_notify*/ )(const char *, const void *, size_t, void *), + void * /* user_data */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLRETAINCONTEXT)(cl_context /* context */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLRELEASECONTEXT)(cl_context /* context */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLGETCONTEXTINFO)(cl_context /* context */, + cl_context_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +/* Command Queue APIs */ +typedef CL_API_ENTRY cl_command_queue (CL_API_CALL * +PFNCLCREATECOMMANDQUEUE)(cl_context /* context */, + cl_device_id /* device */, + cl_command_queue_properties /* properties */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLRETAINCOMMANDQUEUE)(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLRELEASECOMMANDQUEUE)(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLGETCOMMANDQUEUEINFO)(cl_command_queue /* command_queue */, + cl_command_queue_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLSETCOMMANDQUEUEPROPERTY)(cl_command_queue /* command_queue */, + cl_command_queue_properties /* properties */, + cl_bool /* enable */, + cl_command_queue_properties * /* old_properties */) CL_API_SUFFIX__VERSION_1_0; + +/* Memory Object APIs */ +typedef CL_API_ENTRY cl_mem (CL_API_CALL * +PFNCLCREATEBUFFER)(cl_context /* context */, + cl_mem_flags /* flags */, + size_t /* size */, + void * /* host_ptr */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_mem (CL_API_CALL * +PFNCLCREATESUBBUFFER)(cl_mem /* buffer */, + cl_mem_flags /* flags */, + cl_buffer_create_type /* buffer_create_type */, + const void * /* buffer_create_info */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_1; + +typedef CL_API_ENTRY cl_mem (CL_API_CALL * +PFNCLCREATEIMAGE2D)(cl_context /* context */, + cl_mem_flags /* flags */, + const cl_image_format * /* image_format */, + size_t /* image_width */, + size_t /* image_height */, + size_t /* image_row_pitch */, + void * /* host_ptr */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_mem (CL_API_CALL * +PFNCLCREATEIMAGE3D)(cl_context /* context */, + cl_mem_flags /* flags */, + const cl_image_format * /* image_format */, + size_t /* image_width */, + size_t /* image_height */, + size_t /* image_depth */, + size_t /* image_row_pitch */, + size_t /* image_slice_pitch */, + void * /* host_ptr */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLRETAINMEMOBJECT)(cl_mem /* memobj */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLRELEASEMEMOBJECT)(cl_mem /* memobj */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLGETSUPPORTEDIMAGEFORMATS)(cl_context /* context */, + cl_mem_flags /* flags */, + cl_mem_object_type /* image_type */, + cl_uint /* num_entries */, + cl_image_format * /* image_formats */, + cl_uint * /* num_image_formats */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLGETMEMOBJECTINFO)(cl_mem /* memobj */, + cl_mem_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLGETIMAGEINFO)(cl_mem /* image */, + cl_image_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLSETMEMOBJECTDESTRUCTORCALLBACK)( cl_mem /* memobj */, + void (CL_CALLBACK * /*pfn_notify*/)( cl_mem /* memobj */, void* /*user_data*/), + void * /*user_data */ ) CL_API_SUFFIX__VERSION_1_1; + +/* Sampler APIs */ +typedef CL_API_ENTRY cl_sampler (CL_API_CALL * +PFNCLCREATESAMPLER)(cl_context /* context */, + cl_bool /* normalized_coords */, + cl_addressing_mode /* addressing_mode */, + cl_filter_mode /* filter_mode */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLRETAINSAMPLER)(cl_sampler /* sampler */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLRELEASESAMPLER)(cl_sampler /* sampler */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLGETSAMPLERINFO)(cl_sampler /* sampler */, + cl_sampler_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +/* Program Object APIs */ +typedef CL_API_ENTRY cl_program (CL_API_CALL * +PFNCLCREATEPROGRAMWITHSOURCE)(cl_context /* context */, + cl_uint /* count */, + const char ** /* strings */, + const size_t * /* lengths */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_program (CL_API_CALL * +PFNCLCREATEPROGRAMWITHBINARY)(cl_context /* context */, + cl_uint /* num_devices */, + const cl_device_id * /* device_list */, + const size_t * /* lengths */, + const unsigned char ** /* binaries */, + cl_int * /* binary_status */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLRETAINPROGRAM)(cl_program /* program */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLRELEASEPROGRAM)(cl_program /* program */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLBUILDPROGRAM)(cl_program /* program */, + cl_uint /* num_devices */, + const cl_device_id * /* device_list */, + const char * /* options */, + void (CL_CALLBACK * /* pfn_notify */)(cl_program /* program */, void * /* user_data */), + void * /* user_data */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLUNLOADCOMPILER)(void) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLGETPROGRAMINFO)(cl_program /* program */, + cl_program_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLGETPROGRAMBUILDINFO)(cl_program /* program */, + cl_device_id /* device */, + cl_program_build_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +/* Kernel Object APIs */ +typedef CL_API_ENTRY cl_kernel (CL_API_CALL * +PFNCLCREATEKERNEL)(cl_program /* program */, + const char * /* kernel_name */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLCREATEKERNELSINPROGRAM)(cl_program /* program */, + cl_uint /* num_kernels */, + cl_kernel * /* kernels */, + cl_uint * /* num_kernels_ret */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLRETAINKERNEL)(cl_kernel /* kernel */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLRELEASEKERNEL)(cl_kernel /* kernel */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLSETKERNELARG)(cl_kernel /* kernel */, + cl_uint /* arg_index */, + size_t /* arg_size */, + const void * /* arg_value */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLGETKERNELINFO)(cl_kernel /* kernel */, + cl_kernel_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLGETKERNELWORKGROUPINFO)(cl_kernel /* kernel */, + cl_device_id /* device */, + cl_kernel_work_group_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +// Event Object APIs +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLWAITFOREVENTS)(cl_uint /* num_events */, + const cl_event * /* event_list */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLGETEVENTINFO)(cl_event /* event */, + cl_event_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_event (CL_API_CALL * +PFNCLCREATEUSEREVENT)(cl_context /* context */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_1; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLRETAINEVENT)(cl_event /* event */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLRELEASEEVENT)(cl_event /* event */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLSETUSEREVENTSTATUS)(cl_event /* event */, + cl_int /* execution_status */) CL_API_SUFFIX__VERSION_1_1; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLSETEVENTCALLBACK)( cl_event /* event */, + cl_int /* command_exec_callback_type */, + void (CL_CALLBACK * /* pfn_notify */)(cl_event, cl_int, void *), + void * /* user_data */) CL_API_SUFFIX__VERSION_1_1; + +/* Profiling APIs */ +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLGETEVENTPROFILINGINFO)(cl_event /* event */, + cl_profiling_info /* param_name */, + size_t /* param_value_size */, + void * /* param_value */, + size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; + +// Flush and Finish APIs +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLFLUSH)(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLFINISH)(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; + +/* Enqueued Commands APIs */ +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLENQUEUEREADBUFFER)(cl_command_queue /* command_queue */, + cl_mem /* buffer */, + cl_bool /* blocking_read */, + size_t /* offset */, + size_t /* cb */, + void * /* ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLENQUEUEREADBUFFERRECT)(cl_command_queue /* command_queue */, + cl_mem /* buffer */, + cl_bool /* blocking_read */, + const size_t * /* buffer_origin */, + const size_t * /* host_origin */, + const size_t * /* region */, + size_t /* buffer_row_pitch */, + size_t /* buffer_slice_pitch */, + size_t /* host_row_pitch */, + size_t /* host_slice_pitch */, + void * /* ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_1; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLENQUEUEWRITEBUFFER)(cl_command_queue /* command_queue */, + cl_mem /* buffer */, + cl_bool /* blocking_write */, + size_t /* offset */, + size_t /* cb */, + const void * /* ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLENQUEUEWRITEBUFFERRECT)(cl_command_queue /* command_queue */, + cl_mem /* buffer */, + cl_bool /* blocking_write */, + const size_t * /* buffer_origin */, + const size_t * /* host_origin */, + const size_t * /* region */, + size_t /* buffer_row_pitch */, + size_t /* buffer_slice_pitch */, + size_t /* host_row_pitch */, + size_t /* host_slice_pitch */, + const void * /* ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_1; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLENQUEUECOPYBUFFER)(cl_command_queue /* command_queue */, + cl_mem /* src_buffer */, + cl_mem /* dst_buffer */, + size_t /* src_offset */, + size_t /* dst_offset */, + size_t /* cb */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLENQUEUECOPYBUFFERRECT)(cl_command_queue /* command_queue */, + cl_mem /* src_buffer */, + cl_mem /* dst_buffer */, + const size_t * /* src_origin */, + const size_t * /* dst_origin */, + const size_t * /* region */, + size_t /* src_row_pitch */, + size_t /* src_slice_pitch */, + size_t /* dst_row_pitch */, + size_t /* dst_slice_pitch */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_1; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLENQUEUEREADIMAGE)(cl_command_queue /* command_queue */, + cl_mem /* image */, + cl_bool /* blocking_read */, + const size_t * /* origin[3] */, + const size_t * /* region[3] */, + size_t /* row_pitch */, + size_t /* slice_pitch */, + void * /* ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLENQUEUEWRITEIMAGE)(cl_command_queue /* command_queue */, + cl_mem /* image */, + cl_bool /* blocking_write */, + const size_t * /* origin[3] */, + const size_t * /* region[3] */, + size_t /* input_row_pitch */, + size_t /* input_slice_pitch */, + const void * /* ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLENQUEUECOPYIMAGE)(cl_command_queue /* command_queue */, + cl_mem /* src_image */, + cl_mem /* dst_image */, + const size_t * /* src_origin[3] */, + const size_t * /* dst_origin[3] */, + const size_t * /* region[3] */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLENQUEUECOPYIMAGETOBUFFER)(cl_command_queue /* command_queue */, + cl_mem /* src_image */, + cl_mem /* dst_buffer */, + const size_t * /* src_origin[3] */, + const size_t * /* region[3] */, + size_t /* dst_offset */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLENQUEUECOPYBUFFERTOIMAGE)(cl_command_queue /* command_queue */, + cl_mem /* src_buffer */, + cl_mem /* dst_image */, + size_t /* src_offset */, + const size_t * /* dst_origin[3] */, + const size_t * /* region[3] */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY void * (CL_API_CALL * +PFNCLENQUEUEMAPBUFFER)(cl_command_queue /* command_queue */, + cl_mem /* buffer */, + cl_bool /* blocking_map */, + cl_map_flags /* map_flags */, + size_t /* offset */, + size_t /* cb */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY void * (CL_API_CALL * +PFNCLENQUEUEMAPIMAGE)(cl_command_queue /* command_queue */, + cl_mem /* image */, + cl_bool /* blocking_map */, + cl_map_flags /* map_flags */, + const size_t * /* origin[3] */, + const size_t * /* region[3] */, + size_t * /* image_row_pitch */, + size_t * /* image_slice_pitch */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */, + cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLENQUEUEUNMAPMEMOBJECT)(cl_command_queue /* command_queue */, + cl_mem /* memobj */, + void * /* mapped_ptr */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLENQUEUENDRANGEKERNEL)(cl_command_queue /* command_queue */, + cl_kernel /* kernel */, + cl_uint /* work_dim */, + const size_t * /* global_work_offset */, + const size_t * /* global_work_size */, + const size_t * /* local_work_size */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLENQUEUETASK)(cl_command_queue /* command_queue */, + cl_kernel /* kernel */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLENQUEUENATIVEKERNEL)(cl_command_queue /* command_queue */, + void (*user_func)(void *), + void * /* args */, + size_t /* cb_args */, + cl_uint /* num_mem_objects */, + const cl_mem * /* mem_list */, + const void ** /* args_mem_loc */, + cl_uint /* num_events_in_wait_list */, + const cl_event * /* event_wait_list */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLENQUEUEMARKER)(cl_command_queue /* command_queue */, + cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLENQUEUEWAITFOREVENTS)(cl_command_queue /* command_queue */, + cl_uint /* num_events */, + const cl_event * /* event_list */) CL_API_SUFFIX__VERSION_1_0; + +typedef CL_API_ENTRY cl_int (CL_API_CALL * +PFNCLENQUEUEBARRIER)(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; + +// Extension function access +// +// Returns the extension function address for the given function name, +// or NULL if a valid function can not be found. The client must +// check to make sure the address is not NULL, before using or +// calling the returned function address. +// +typedef CL_API_ENTRY void * (CL_API_CALL * PFNCLGETEXTENSIONFUNCTIONADDRESS)(const char * /* func_name */) CL_API_SUFFIX__VERSION_1_0; + + +#define CLEW_STATIC + +#ifdef CLEW_STATIC +# define CLEWAPI extern +#else +# ifdef CLEW_BUILD +# define CLEWAPI extern __declspec(dllexport) +# else +# define CLEWAPI extern __declspec(dllimport) +# endif +#endif + +#if defined(_WIN32) +#define CLEW_FUN_EXPORT extern +#else +#define CLEW_FUN_EXPORT CLEWAPI +#endif + +#define CLEW_GET_FUN(x) x + + +// Variables holding function entry points +CLEW_FUN_EXPORT PFNCLGETPLATFORMIDS __clewGetPlatformIDs ; +CLEW_FUN_EXPORT PFNCLGETPLATFORMINFO __clewGetPlatformInfo ; +CLEW_FUN_EXPORT PFNCLGETDEVICEIDS __clewGetDeviceIDs ; +CLEW_FUN_EXPORT PFNCLGETDEVICEINFO __clewGetDeviceInfo ; +CLEW_FUN_EXPORT PFNCLCREATECONTEXT __clewCreateContext ; +CLEW_FUN_EXPORT PFNCLCREATECONTEXTFROMTYPE __clewCreateContextFromType ; +CLEW_FUN_EXPORT PFNCLRETAINCONTEXT __clewRetainContext ; +CLEW_FUN_EXPORT PFNCLRELEASECONTEXT __clewReleaseContext ; +CLEW_FUN_EXPORT PFNCLGETCONTEXTINFO __clewGetContextInfo ; +CLEW_FUN_EXPORT PFNCLCREATECOMMANDQUEUE __clewCreateCommandQueue ; +CLEW_FUN_EXPORT PFNCLRETAINCOMMANDQUEUE __clewRetainCommandQueue ; +CLEW_FUN_EXPORT PFNCLRELEASECOMMANDQUEUE __clewReleaseCommandQueue ; +CLEW_FUN_EXPORT PFNCLGETCOMMANDQUEUEINFO __clewGetCommandQueueInfo ; +#ifdef CL_USE_DEPRECATED_OPENCL_1_0_APIS +CLEW_FUN_EXPORT PFNCLSETCOMMANDQUEUEPROPERTY __clewSetCommandQueueProperty ; +#endif +CLEW_FUN_EXPORT PFNCLCREATEBUFFER __clewCreateBuffer ; +CLEW_FUN_EXPORT PFNCLCREATESUBBUFFER __clewCreateSubBuffer ; +CLEW_FUN_EXPORT PFNCLCREATEIMAGE2D __clewCreateImage2D ; +CLEW_FUN_EXPORT PFNCLCREATEIMAGE3D __clewCreateImage3D ; +CLEW_FUN_EXPORT PFNCLRETAINMEMOBJECT __clewRetainMemObject ; +CLEW_FUN_EXPORT PFNCLRELEASEMEMOBJECT __clewReleaseMemObject ; +CLEW_FUN_EXPORT PFNCLGETSUPPORTEDIMAGEFORMATS __clewGetSupportedImageFormats ; +CLEW_FUN_EXPORT PFNCLGETMEMOBJECTINFO __clewGetMemObjectInfo ; +CLEW_FUN_EXPORT PFNCLGETIMAGEINFO __clewGetImageInfo ; +CLEW_FUN_EXPORT PFNCLSETMEMOBJECTDESTRUCTORCALLBACK __clewSetMemObjectDestructorCallback; +CLEW_FUN_EXPORT PFNCLCREATESAMPLER __clewCreateSampler ; +CLEW_FUN_EXPORT PFNCLRETAINSAMPLER __clewRetainSampler ; +CLEW_FUN_EXPORT PFNCLRELEASESAMPLER __clewReleaseSampler ; +CLEW_FUN_EXPORT PFNCLGETSAMPLERINFO __clewGetSamplerInfo ; +CLEW_FUN_EXPORT PFNCLCREATEPROGRAMWITHSOURCE __clewCreateProgramWithSource ; +CLEW_FUN_EXPORT PFNCLCREATEPROGRAMWITHBINARY __clewCreateProgramWithBinary ; +CLEW_FUN_EXPORT PFNCLRETAINPROGRAM __clewRetainProgram ; +CLEW_FUN_EXPORT PFNCLRELEASEPROGRAM __clewReleaseProgram ; +CLEW_FUN_EXPORT PFNCLBUILDPROGRAM __clewBuildProgram ; +CLEW_FUN_EXPORT PFNCLUNLOADCOMPILER __clewUnloadCompiler ; +CLEW_FUN_EXPORT PFNCLGETPROGRAMINFO __clewGetProgramInfo ; +CLEW_FUN_EXPORT PFNCLGETPROGRAMBUILDINFO __clewGetProgramBuildInfo ; +CLEW_FUN_EXPORT PFNCLCREATEKERNEL __clewCreateKernel ; +CLEW_FUN_EXPORT PFNCLCREATEKERNELSINPROGRAM __clewCreateKernelsInProgram ; +CLEW_FUN_EXPORT PFNCLRETAINKERNEL __clewRetainKernel ; +CLEW_FUN_EXPORT PFNCLRELEASEKERNEL __clewReleaseKernel ; +CLEW_FUN_EXPORT PFNCLSETKERNELARG __clewSetKernelArg ; +CLEW_FUN_EXPORT PFNCLGETKERNELINFO __clewGetKernelInfo ; +CLEW_FUN_EXPORT PFNCLGETKERNELWORKGROUPINFO __clewGetKernelWorkGroupInfo ; +CLEW_FUN_EXPORT PFNCLWAITFOREVENTS __clewWaitForEvents ; +CLEW_FUN_EXPORT PFNCLGETEVENTINFO __clewGetEventInfo ; +CLEW_FUN_EXPORT PFNCLCREATEUSEREVENT __clewCreateUserEvent ; +CLEW_FUN_EXPORT PFNCLRETAINEVENT __clewRetainEvent ; +CLEW_FUN_EXPORT PFNCLRELEASEEVENT __clewReleaseEvent ; +CLEW_FUN_EXPORT PFNCLSETUSEREVENTSTATUS __clewSetUserEventStatus ; +CLEW_FUN_EXPORT PFNCLSETEVENTCALLBACK __clewSetEventCallback ; +CLEW_FUN_EXPORT PFNCLGETEVENTPROFILINGINFO __clewGetEventProfilingInfo ; +CLEW_FUN_EXPORT PFNCLFLUSH __clewFlush ; +CLEW_FUN_EXPORT PFNCLFINISH __clewFinish ; +CLEW_FUN_EXPORT PFNCLENQUEUEREADBUFFER __clewEnqueueReadBuffer ; +CLEW_FUN_EXPORT PFNCLENQUEUEREADBUFFERRECT __clewEnqueueReadBufferRect ; +CLEW_FUN_EXPORT PFNCLENQUEUEWRITEBUFFER __clewEnqueueWriteBuffer ; +CLEW_FUN_EXPORT PFNCLENQUEUEWRITEBUFFERRECT __clewEnqueueWriteBufferRect ; +CLEW_FUN_EXPORT PFNCLENQUEUECOPYBUFFER __clewEnqueueCopyBuffer ; +CLEW_FUN_EXPORT PFNCLENQUEUECOPYBUFFERRECT __clewEnqueueCopyBufferRect ; +CLEW_FUN_EXPORT PFNCLENQUEUEREADIMAGE __clewEnqueueReadImage ; +CLEW_FUN_EXPORT PFNCLENQUEUEWRITEIMAGE __clewEnqueueWriteImage ; +CLEW_FUN_EXPORT PFNCLENQUEUECOPYIMAGE __clewEnqueueCopyImage ; +CLEW_FUN_EXPORT PFNCLENQUEUECOPYIMAGETOBUFFER __clewEnqueueCopyImageToBuffer ; +CLEW_FUN_EXPORT PFNCLENQUEUECOPYBUFFERTOIMAGE __clewEnqueueCopyBufferToImage ; +CLEW_FUN_EXPORT PFNCLENQUEUEMAPBUFFER __clewEnqueueMapBuffer ; +CLEW_FUN_EXPORT PFNCLENQUEUEMAPIMAGE __clewEnqueueMapImage ; +CLEW_FUN_EXPORT PFNCLENQUEUEUNMAPMEMOBJECT __clewEnqueueUnmapMemObject ; +CLEW_FUN_EXPORT PFNCLENQUEUENDRANGEKERNEL __clewEnqueueNDRangeKernel ; +CLEW_FUN_EXPORT PFNCLENQUEUETASK __clewEnqueueTask ; +CLEW_FUN_EXPORT PFNCLENQUEUENATIVEKERNEL __clewEnqueueNativeKernel ; +CLEW_FUN_EXPORT PFNCLENQUEUEMARKER __clewEnqueueMarker ; +CLEW_FUN_EXPORT PFNCLENQUEUEWAITFOREVENTS __clewEnqueueWaitForEvents ; +CLEW_FUN_EXPORT PFNCLENQUEUEBARRIER __clewEnqueueBarrier ; +CLEW_FUN_EXPORT PFNCLGETEXTENSIONFUNCTIONADDRESS __clewGetExtensionFunctionAddress ; + + +#define clGetPlatformIDs CLEW_GET_FUN(__clewGetPlatformIDs ) +#define clGetPlatformInfo CLEW_GET_FUN(__clewGetPlatformInfo ) +#define clGetDeviceIDs CLEW_GET_FUN(__clewGetDeviceIDs ) +#define clGetDeviceInfo CLEW_GET_FUN(__clewGetDeviceInfo ) +#define clCreateContext CLEW_GET_FUN(__clewCreateContext ) +#define clCreateContextFromType CLEW_GET_FUN(__clewCreateContextFromType ) +#define clRetainContext CLEW_GET_FUN(__clewRetainContext ) +#define clReleaseContext CLEW_GET_FUN(__clewReleaseContext ) +#define clGetContextInfo CLEW_GET_FUN(__clewGetContextInfo ) +#define clCreateCommandQueue CLEW_GET_FUN(__clewCreateCommandQueue ) +#define clRetainCommandQueue CLEW_GET_FUN(__clewRetainCommandQueue ) +#define clReleaseCommandQueue CLEW_GET_FUN(__clewReleaseCommandQueue ) +#define clGetCommandQueueInfo CLEW_GET_FUN(__clewGetCommandQueueInfo ) +#ifdef CL_USE_DEPRECATED_OPENCL_1_0_APIS +#warning CL_USE_DEPRECATED_OPENCL_1_0_APIS is defined. These APIs are unsupported and untested in OpenCL 1.1! +/* + * WARNING: + * This API introduces mutable state into the OpenCL implementation. It has been REMOVED + * to better facilitate thread safety. The 1.0 API is not thread safe. It is not tested by the + * OpenCL 1.1 conformance test, and consequently may not work or may not work dependably. + * It is likely to be non-performant. Use of this API is not advised. Use at your own risk. + * + * Software developers previously relying on this API are instructed to set the command queue + * properties when creating the queue, instead. + */ +#define clSetCommandQueueProperty CLEW_GET_FUN(__clewSetCommandQueueProperty ) +#endif /* CL_USE_DEPRECATED_OPENCL_1_0_APIS */ +#define clCreateBuffer CLEW_GET_FUN(__clewCreateBuffer ) +#define clCreateSubBuffer CLEW_GET_FUN(__clewCreateSubBuffer ) +#define clCreateImage2D CLEW_GET_FUN(__clewCreateImage2D ) +#define clCreateImage3D CLEW_GET_FUN(__clewCreateImage3D ) +#define clRetainMemObject CLEW_GET_FUN(__clewRetainMemObject ) +#define clReleaseMemObject CLEW_GET_FUN(__clewReleaseMemObject ) +#define clGetSupportedImageFormats CLEW_GET_FUN(__clewGetSupportedImageFormats ) +#define clGetMemObjectInfo CLEW_GET_FUN(__clewGetMemObjectInfo ) +#define clGetImageInfo CLEW_GET_FUN(__clewGetImageInfo ) +#define clSetMemObjectDestructorCallback CLEW_GET_FUN(__clewSetMemObjectDestructorCallback) +#define clCreateSampler CLEW_GET_FUN(__clewCreateSampler ) +#define clRetainSampler CLEW_GET_FUN(__clewRetainSampler ) +#define clReleaseSampler CLEW_GET_FUN(__clewReleaseSampler ) +#define clGetSamplerInfo CLEW_GET_FUN(__clewGetSamplerInfo ) +#define clCreateProgramWithSource CLEW_GET_FUN(__clewCreateProgramWithSource ) +#define clCreateProgramWithBinary CLEW_GET_FUN(__clewCreateProgramWithBinary ) +#define clRetainProgram CLEW_GET_FUN(__clewRetainProgram ) +#define clReleaseProgram CLEW_GET_FUN(__clewReleaseProgram ) +#define clBuildProgram CLEW_GET_FUN(__clewBuildProgram ) +#define clUnloadCompiler CLEW_GET_FUN(__clewUnloadCompiler ) +#define clGetProgramInfo CLEW_GET_FUN(__clewGetProgramInfo ) +#define clGetProgramBuildInfo CLEW_GET_FUN(__clewGetProgramBuildInfo ) +#define clCreateKernel CLEW_GET_FUN(__clewCreateKernel ) +#define clCreateKernelsInProgram CLEW_GET_FUN(__clewCreateKernelsInProgram ) +#define clRetainKernel CLEW_GET_FUN(__clewRetainKernel ) +#define clReleaseKernel CLEW_GET_FUN(__clewReleaseKernel ) +#define clSetKernelArg CLEW_GET_FUN(__clewSetKernelArg ) +#define clGetKernelInfo CLEW_GET_FUN(__clewGetKernelInfo ) +#define clGetKernelWorkGroupInfo CLEW_GET_FUN(__clewGetKernelWorkGroupInfo ) +#define clWaitForEvents CLEW_GET_FUN(__clewWaitForEvents ) +#define clGetEventInfo CLEW_GET_FUN(__clewGetEventInfo ) +#define clCreateUserEvent CLEW_GET_FUN(__clewCreateUserEvent ) +#define clRetainEvent CLEW_GET_FUN(__clewRetainEvent ) +#define clReleaseEvent CLEW_GET_FUN(__clewReleaseEvent ) +#define clSetUserEventStatus CLEW_GET_FUN(__clewSetUserEventStatus ) +#define clSetEventCallback CLEW_GET_FUN(__clewSetEventCallback ) +#define clGetEventProfilingInfo CLEW_GET_FUN(__clewGetEventProfilingInfo ) +#define clFlush CLEW_GET_FUN(__clewFlush ) +#define clFinish CLEW_GET_FUN(__clewFinish ) +#define clEnqueueReadBuffer CLEW_GET_FUN(__clewEnqueueReadBuffer ) +#define clEnqueueReadBufferRect CLEW_GET_FUN(__clewEnqueueReadBufferRect ) +#define clEnqueueWriteBuffer CLEW_GET_FUN(__clewEnqueueWriteBuffer ) +#define clEnqueueWriteBufferRect CLEW_GET_FUN(__clewEnqueueWriteBufferRect ) +#define clEnqueueCopyBuffer CLEW_GET_FUN(__clewEnqueueCopyBuffer ) +#define clEnqueueCopyBufferRect CLEW_GET_FUN(__clewEnqueueCopyBufferRect ) +#define clEnqueueReadImage CLEW_GET_FUN(__clewEnqueueReadImage ) +#define clEnqueueWriteImage CLEW_GET_FUN(__clewEnqueueWriteImage ) +#define clEnqueueCopyImage CLEW_GET_FUN(__clewEnqueueCopyImage ) +#define clEnqueueCopyImageToBuffer CLEW_GET_FUN(__clewEnqueueCopyImageToBuffer ) +#define clEnqueueCopyBufferToImage CLEW_GET_FUN(__clewEnqueueCopyBufferToImage ) +#define clEnqueueMapBuffer CLEW_GET_FUN(__clewEnqueueMapBuffer ) +#define clEnqueueMapImage CLEW_GET_FUN(__clewEnqueueMapImage ) +#define clEnqueueUnmapMemObject CLEW_GET_FUN(__clewEnqueueUnmapMemObject ) +#define clEnqueueNDRangeKernel CLEW_GET_FUN(__clewEnqueueNDRangeKernel ) +#define clEnqueueTask CLEW_GET_FUN(__clewEnqueueTask ) +#define clEnqueueNativeKernel CLEW_GET_FUN(__clewEnqueueNativeKernel ) +#define clEnqueueMarker CLEW_GET_FUN(__clewEnqueueMarker ) +#define clEnqueueWaitForEvents CLEW_GET_FUN(__clewEnqueueWaitForEvents ) +#define clEnqueueBarrier CLEW_GET_FUN(__clewEnqueueBarrier ) +#define clGetExtensionFunctionAddress CLEW_GET_FUN(__clewGetExtensionFunctionAddress ) + + +#define CLEW_SUCCESS 0 //!< Success error code +#define CLEW_ERROR_OPEN_FAILED -1 //!< Error code for failing to open the dynamic library +#define CLEW_ERROR_ATEXIT_FAILED -2 //!< Error code for failing to queue the closing of the dynamic library to atexit() + +//! \brief Load OpenCL dynamic library and set function entry points +int clewInit (const char*); + +//! \brief Exit clew and unload OpenCL dynamic library +void clewExit(); + +//! \brief Convert an OpenCL error code to its string equivalent +const char* clewErrorString (cl_int error); + +#ifdef __cplusplus +} +#endif + +#endif // CLEW_HPP_INCLUDED diff --git a/extern/bullet2/patches/blender.patch b/extern/bullet2/patches/blender.patch deleted file mode 100644 index cb3bf2ba38a0..000000000000 --- a/extern/bullet2/patches/blender.patch +++ /dev/null @@ -1,355 +0,0 @@ -diff --git a/extern/bullet2/src/LinearMath/btScalar.h b/extern/bullet2/src/LinearMath/btScalar.h ---- a/extern/bullet2/src/LinearMath/btScalar.h -+++ b/extern/bullet2/src/LinearMath/btScalar.h -@@ -16,6 +16,9 @@ - - #ifndef BT_SCALAR_H - #define BT_SCALAR_H -+#if defined(_MSC_VER) && defined(__clang__) /* clang supplies it's own overloads already */ -+#define BT_NO_SIMD_OPERATOR_OVERLOADS -+#endif - - #ifdef BT_MANAGED_CODE - //Aligned data types not supported in managed code -@@ -83,7 +86,7 @@ - #ifdef BT_USE_SSE - - #if (_MSC_FULL_VER >= 170050727)//Visual Studio 2012 can compile SSE4/FMA3 (but SSE4/FMA3 is not enabled by default) -- #define BT_ALLOW_SSE4 -+ //#define BT_ALLOW_SSE4 //disable this cause blender targets sse2 - #endif //(_MSC_FULL_VER >= 160040219) - - //BT_USE_SSE_IN_API is disabled under Windows by default, because -@@ -102,7 +105,7 @@ - #endif //__MINGW32__ - - #ifdef BT_DEBUG -- #ifdef _MSC_VER -+ #if defined(_MSC_VER) && !defined(__clang__) - #include - #define btAssert(x) { if(!(x)){printf("Assert "__FILE__ ":%u ("#x")\n", __LINE__);__debugbreak(); }} - #else//_MSC_VER -diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h -index be9eca6..ec40c96 100644 ---- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h -+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorld.h -@@ -15,7 +15,7 @@ subject to the following restrictions: - - - /** -- * @mainpage Bullet Documentation -+ * @page Bullet Documentation - * - * @section intro_sec Introduction - * 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 ). -diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp -index 36dd043..57eb817 100644 ---- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp -+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionWorldImporter.cpp -@@ -579,14 +579,10 @@ btCollisionShape* btCollisionWorldImporter::convertCollisionShape( btCollisionS - btCompoundShapeData* compoundData = (btCompoundShapeData*)shapeData; - btCompoundShape* compoundShape = createCompoundShape(); - -- btCompoundShapeChildData* childShapeDataArray = &compoundData->m_childShapePtr[0]; -- - - btAlignedObjectArray childShapes; - for (int i=0;im_numChildShapes;i++) - { -- btCompoundShapeChildData* ptr = &compoundData->m_childShapePtr[i]; -- - btCollisionShapeData* cd = compoundData->m_childShapePtr[i].m_childShape; - - btCollisionShape* childShape = convertCollisionShape(cd); -diff --git a/extern/bullet2/src/BulletDynamics/Character/btKinematicCharacterController.cpp b/extern/bullet2/src/BulletDynamics/Character/btKinematicCharacterController.cpp -index 57fc119..31faf1d 100644 ---- a/extern/bullet2/src/BulletDynamics/Character/btKinematicCharacterController.cpp -+++ b/extern/bullet2/src/BulletDynamics/Character/btKinematicCharacterController.cpp -@@ -29,14 +29,11 @@ subject to the following restrictions: - static btVector3 - getNormalizedVector(const btVector3& v) - { -- btScalar l = v.length(); -- btVector3 n = v; -- if (l < SIMD_EPSILON) { -- n.setValue(0,0,0); -- } else { -- n /= l; -- } -+ btVector3 n(0, 0, 0); - -+ if (v.length() > SIMD_EPSILON) { -+ n = v.normalized(); -+ } - return n; - } - -diff --git a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolverBody.h b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolverBody.h -index 27ccefe..8e4456e 100644 ---- a/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolverBody.h -+++ b/extern/bullet2/src/BulletDynamics/ConstraintSolver/btSolverBody.h -@@ -37,8 +37,13 @@ struct btSimdScalar - { - - } -- -+/* workaround for clang 3.4 ( == apple clang 5.1 ) issue, friction would fail with forced inlining */ -+#if (defined(__clang__) && defined(__apple_build_version__) && (__clang_major__ == 5) && (__clang_minor__ == 1)) \ -+|| (defined(__clang__) && !defined(__apple_build_version__) && (__clang_major__ == 3) && (__clang_minor__ == 4)) -+ inline __attribute__ ((noinline)) btSimdScalar(float fl) -+#else - SIMD_FORCE_INLINE btSimdScalar(float fl) -+#endif - :m_vec128 (_mm_set1_ps(fl)) - { - } -diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.cpp b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.cpp -index 5d62da7..fcd312e 100644 ---- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.cpp -+++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBody.cpp -@@ -28,7 +28,6 @@ - #include "btMultiBodyJointFeedback.h" - #include "LinearMath/btTransformUtil.h" - #include "LinearMath/btSerializer.h" --#include "Bullet3Common/b3Logging.h" - // #define INCLUDE_GYRO_TERM - - ///todo: determine if we need these options. If so, make a proper API, otherwise delete those globals -@@ -1732,7 +1731,6 @@ void btMultiBody::goToSleep() - - void btMultiBody::checkMotionAndSleepIfRequired(btScalar timestep) - { -- int num_links = getNumLinks(); - extern bool gDisableDeactivation; - if (!m_canSleep || gDisableDeactivation) - { -diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp -index 8a034b3..4f66b20 100644 ---- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp -+++ b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraintSolver.cpp -@@ -809,7 +809,6 @@ static void applyJointFeedback(btMultiBodyJacobianData& data, const btMultiBodyS - } - #endif - --#include "Bullet3Common/b3Logging.h" - void btMultiBodyConstraintSolver::writeBackSolverBodyToMultiBody(btMultiBodySolverConstraint& c, btScalar deltaTime) - { - #if 1 -diff --git a/extern/bullet2/src/BulletSoftBody/btSparseSDF.h b/extern/bullet2/src/BulletSoftBody/btSparseSDF.h -index bcf0c79..8992ddb 100644 ---- a/extern/bullet2/src/BulletSoftBody/btSparseSDF.h -+++ b/extern/bullet2/src/BulletSoftBody/btSparseSDF.h -@@ -185,7 +185,6 @@ struct btSparseSdf - { - ++nprobes; - ++ncells; -- int sz = sizeof(Cell); - if (ncells>m_clampCells) - { - static int numResets=0; -diff --git a/extern/bullet2/src/LinearMath/btConvexHullComputer.cpp b/extern/bullet2/src/LinearMath/btConvexHullComputer.cpp -index d58ac95..3fd77df 100644 ---- a/extern/bullet2/src/LinearMath/btConvexHullComputer.cpp -+++ b/extern/bullet2/src/LinearMath/btConvexHullComputer.cpp -@@ -2665,6 +2665,7 @@ btScalar btConvexHullComputer::compute(const void* coords, bool doubleCoords, in - } - - vertices.resize(0); -+ original_vertex_index.resize(0); - edges.resize(0); - faces.resize(0); - -@@ -2675,6 +2676,7 @@ btScalar btConvexHullComputer::compute(const void* coords, bool doubleCoords, in - { - btConvexHullInternal::Vertex* v = oldVertices[copied]; - vertices.push_back(hull.getCoordinates(v)); -+ original_vertex_index.push_back(v->point.index); - btConvexHullInternal::Edge* firstEdge = v->edges; - if (firstEdge) - { -diff --git a/extern/bullet2/src/LinearMath/btConvexHullComputer.h b/extern/bullet2/src/LinearMath/btConvexHullComputer.h -index 7240ac4..6871ce8 100644 ---- a/extern/bullet2/src/LinearMath/btConvexHullComputer.h -+++ b/extern/bullet2/src/LinearMath/btConvexHullComputer.h -@@ -67,6 +67,7 @@ class btConvexHullComputer - - // Vertices of the output hull - btAlignedObjectArray vertices; -+ btAlignedObjectArray original_vertex_index; - - // Edges of the output hull - btAlignedObjectArray edges; -diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexHullShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexHullShape.cpp -index 0623e35..02ea503 100644 ---- a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexHullShape.cpp -+++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexHullShape.cpp -@@ -13,9 +13,9 @@ subject to the following restrictions: - 3. This notice may not be removed or altered from any source distribution. - */ - --#if defined (_WIN32) || defined (__i386__) --#define BT_USE_SSE_IN_API --#endif -+//#if defined (_WIN32) || defined (__i386__) -+//#define BT_USE_SSE_IN_API -+//#endif - - #include "btConvexHullShape.h" - #include "BulletCollision/CollisionShapes/btCollisionMargin.h" -diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.cpp -index b56d729..88018b4 100644 ---- a/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.cpp -+++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btConvexShape.cpp -@@ -13,9 +13,9 @@ subject to the following restrictions: - 3. This notice may not be removed or altered from any source distribution. - */ - --#if defined (_WIN32) || defined (__i386__) --#define BT_USE_SSE_IN_API --#endif -+//#if defined (_WIN32) || defined (__i386__) -+//#define BT_USE_SSE_IN_API -+//#endif - - #include "btConvexShape.h" - #include "btTriangleShape.h" -diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp -index a7362ea..6abfdff 100644 ---- a/extern/bullet2/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp -+++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btMultiSphereShape.cpp -@@ -13,9 +13,9 @@ subject to the following restrictions: - 3. This notice may not be removed or altered from any source distribution. - */ - --#if defined (_WIN32) || defined (__i386__) --#define BT_USE_SSE_IN_API --#endif -+//#if defined (_WIN32) || defined (__i386__) -+//#define BT_USE_SSE_IN_API -+//#endif - - #include "btMultiSphereShape.h" - #include "BulletCollision/CollisionShapes/btCollisionMargin.h" -diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp -index 4854f37..9095c59 100644 ---- a/extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp -+++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp -@@ -12,9 +12,9 @@ subject to the following restrictions: - 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. - */ --#if defined (_WIN32) || defined (__i386__) --#define BT_USE_SSE_IN_API --#endif -+//#if defined (_WIN32) || defined (__i386__) -+//#define BT_USE_SSE_IN_API -+//#endif - - #include "BulletCollision/CollisionShapes/btPolyhedralConvexShape.h" - #include "btConvexPolyhedron.h" -diff --git a/extern/bullet2/src/LinearMath/btVector3.cpp b/extern/bullet2/src/LinearMath/btVector3.cpp -index e05bdcc..dbcf2b6 100644 ---- a/extern/bullet2/src/LinearMath/btVector3.cpp -+++ b/extern/bullet2/src/LinearMath/btVector3.cpp -@@ -15,9 +15,9 @@ - This source version has been altered. - */ - --#if defined (_WIN32) || defined (__i386__) --#define BT_USE_SSE_IN_API --#endif -+//#if defined (_WIN32) || defined (__i386__) -+//#define BT_USE_SSE_IN_API -+//#endif - - - #include "btVector3.h" -diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.cpp b/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.cpp -index e0e8bc7..a788268 100644 ---- a/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.cpp -+++ b/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.cpp -@@ -425,50 +425,38 @@ void btRigidBody::setCenterOfMassTransform(const btTransform& xform) - } - - -+bool btRigidBody::checkCollideWithOverride(const btCollisionObject* co) const -+{ -+ const btRigidBody* otherRb = btRigidBody::upcast(co); -+ if (!otherRb) -+ return true; -+ -+ for (int i = 0; i < m_constraintRefs.size(); ++i) -+ { -+ const btTypedConstraint* c = m_constraintRefs[i]; -+ if (c->isEnabled()) -+ if (&c->getRigidBodyA() == otherRb || &c->getRigidBodyB() == otherRb) -+ return false; -+ } -+ -+ return true; -+} - - - - void btRigidBody::addConstraintRef(btTypedConstraint* c) - { -- ///disable collision with the 'other' body -- - int index = m_constraintRefs.findLinearSearch(c); -- //don't add constraints that are already referenced -- //btAssert(index == m_constraintRefs.size()); - if (index == m_constraintRefs.size()) -- { -- m_constraintRefs.push_back(c); -- btCollisionObject* colObjA = &c->getRigidBodyA(); -- btCollisionObject* colObjB = &c->getRigidBodyB(); -- if (colObjA == this) -- { -- colObjA->setIgnoreCollisionCheck(colObjB, true); -- } -- else -- { -- colObjB->setIgnoreCollisionCheck(colObjA, true); -- } -- } -+ m_constraintRefs.push_back(c); -+ -+ m_checkCollideWith = true; - } - - void btRigidBody::removeConstraintRef(btTypedConstraint* c) - { -- int index = m_constraintRefs.findLinearSearch(c); -- //don't remove constraints that are not referenced -- if(index < m_constraintRefs.size()) -- { -- m_constraintRefs.remove(c); -- btCollisionObject* colObjA = &c->getRigidBodyA(); -- btCollisionObject* colObjB = &c->getRigidBodyB(); -- if (colObjA == this) -- { -- colObjA->setIgnoreCollisionCheck(colObjB, false); -- } -- else -- { -- colObjB->setIgnoreCollisionCheck(colObjA, false); -- } -- } -+ m_constraintRefs.remove(c); -+ m_checkCollideWith = m_constraintRefs.size() > 0; - } - - int btRigidBody::calculateSerializeBufferSize() const -diff --git a/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.h b/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.h -index 1d177db..c2f8c5d 100644 ---- a/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.h -+++ b/extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.h -@@ -509,6 +509,8 @@ public: - return (getBroadphaseProxy() != 0); - } - -+ virtual bool checkCollideWithOverride(const btCollisionObject* co) const; -+ - void addConstraintRef(btTypedConstraint* c); - void removeConstraintRef(btTypedConstraint* c); - diff --git a/extern/bullet2/readme.txt b/extern/bullet2/readme.txt deleted file mode 100644 index ec99abf71cfd..000000000000 --- a/extern/bullet2/readme.txt +++ /dev/null @@ -1,13 +0,0 @@ -This is the new refactored version of Bullet physics library version 2.x - -Questions? mail blender at erwincoumans.com, or check the bf-blender mailing list. -Thanks, -Erwin - -Apply patches/blender.patch to fix a few build errors and warnings and dd original -vertex access for BMesh convex hull operator. - -Documentation is available at: -http://code.google.com/p/bullet/source/browse/trunk/Bullet_User_Manual.pdf -and: -https://github.com/bulletphysics/bullet3/tree/master/docs diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.cpp b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.cpp deleted file mode 100644 index 81369fe9b50a..000000000000 --- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.cpp +++ /dev/null @@ -1,489 +0,0 @@ -/* -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 "btMultiSapBroadphase.h" - -#include "btSimpleBroadphase.h" -#include "LinearMath/btAabbUtil2.h" -#include "btQuantizedBvh.h" - -/// btSapBroadphaseArray m_sapBroadphases; - -/// btOverlappingPairCache* m_overlappingPairs; -extern int gOverlappingPairs; - -/* -class btMultiSapSortedOverlappingPairCache : public btSortedOverlappingPairCache -{ -public: - - virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) - { - return btSortedOverlappingPairCache::addOverlappingPair((btBroadphaseProxy*)proxy0->m_multiSapParentProxy,(btBroadphaseProxy*)proxy1->m_multiSapParentProxy); - } -}; - -*/ - -btMultiSapBroadphase::btMultiSapBroadphase(int /*maxProxies*/,btOverlappingPairCache* pairCache) -:m_overlappingPairs(pairCache), -m_optimizedAabbTree(0), -m_ownsPairCache(false), -m_invalidPair(0) -{ - if (!m_overlappingPairs) - { - m_ownsPairCache = true; - void* mem = btAlignedAlloc(sizeof(btSortedOverlappingPairCache),16); - m_overlappingPairs = new (mem)btSortedOverlappingPairCache(); - } - - struct btMultiSapOverlapFilterCallback : public btOverlapFilterCallback - { - virtual ~btMultiSapOverlapFilterCallback() - {} - // return true when pairs need collision - virtual bool needBroadphaseCollision(btBroadphaseProxy* childProxy0,btBroadphaseProxy* childProxy1) const - { - btBroadphaseProxy* multiProxy0 = (btBroadphaseProxy*)childProxy0->m_multiSapParentProxy; - btBroadphaseProxy* multiProxy1 = (btBroadphaseProxy*)childProxy1->m_multiSapParentProxy; - - bool collides = (multiProxy0->m_collisionFilterGroup & multiProxy1->m_collisionFilterMask) != 0; - collides = collides && (multiProxy1->m_collisionFilterGroup & multiProxy0->m_collisionFilterMask); - - return collides; - } - }; - - void* mem = btAlignedAlloc(sizeof(btMultiSapOverlapFilterCallback),16); - m_filterCallback = new (mem)btMultiSapOverlapFilterCallback(); - - m_overlappingPairs->setOverlapFilterCallback(m_filterCallback); -// mem = btAlignedAlloc(sizeof(btSimpleBroadphase),16); -// m_simpleBroadphase = new (mem) btSimpleBroadphase(maxProxies,m_overlappingPairs); -} - -btMultiSapBroadphase::~btMultiSapBroadphase() -{ - if (m_ownsPairCache) - { - m_overlappingPairs->~btOverlappingPairCache(); - btAlignedFree(m_overlappingPairs); - } -} - - -void btMultiSapBroadphase::buildTree(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax) -{ - m_optimizedAabbTree = new btQuantizedBvh(); - m_optimizedAabbTree->setQuantizationValues(bvhAabbMin,bvhAabbMax); - QuantizedNodeArray& nodes = m_optimizedAabbTree->getLeafNodeArray(); - for (int i=0;igetBroadphaseAabb(aabbMin,aabbMax); - m_optimizedAabbTree->quantize(&node.m_quantizedAabbMin[0],aabbMin,0); - m_optimizedAabbTree->quantize(&node.m_quantizedAabbMax[0],aabbMax,1); - int partId = 0; - node.m_escapeIndexOrTriangleIndex = (partId<<(31-MAX_NUM_PARTS_IN_BITS)) | i; - nodes.push_back(node); - } - m_optimizedAabbTree->buildInternal(); -} - -btBroadphaseProxy* btMultiSapBroadphase::createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* /*ignoreMe*/) -{ - //void* ignoreMe -> we could think of recursive multi-sap, if someone is interested - - void* mem = btAlignedAlloc(sizeof(btMultiSapProxy),16); - btMultiSapProxy* proxy = new (mem)btMultiSapProxy(aabbMin, aabbMax,shapeType,userPtr, collisionFilterGroup,collisionFilterMask); - m_multiSapProxies.push_back(proxy); - - ///this should deal with inserting/removal into child broadphases - setAabb(proxy,aabbMin,aabbMax,dispatcher); - return proxy; -} - -void btMultiSapBroadphase::destroyProxy(btBroadphaseProxy* /*proxy*/,btDispatcher* /*dispatcher*/) -{ - ///not yet - btAssert(0); - -} - - -void btMultiSapBroadphase::addToChildBroadphase(btMultiSapProxy* parentMultiSapProxy, btBroadphaseProxy* childProxy, btBroadphaseInterface* childBroadphase) -{ - void* mem = btAlignedAlloc(sizeof(btBridgeProxy),16); - btBridgeProxy* bridgeProxyRef = new(mem) btBridgeProxy; - bridgeProxyRef->m_childProxy = childProxy; - bridgeProxyRef->m_childBroadphase = childBroadphase; - parentMultiSapProxy->m_bridgeProxies.push_back(bridgeProxyRef); -} - - -bool boxIsContainedWithinBox(const btVector3& amin,const btVector3& amax,const btVector3& bmin,const btVector3& bmax); -bool boxIsContainedWithinBox(const btVector3& amin,const btVector3& amax,const btVector3& bmin,const btVector3& bmax) -{ -return -amin.getX() >= bmin.getX() && amax.getX() <= bmax.getX() && -amin.getY() >= bmin.getY() && amax.getY() <= bmax.getY() && -amin.getZ() >= bmin.getZ() && amax.getZ() <= bmax.getZ(); -} - - - - - - -void btMultiSapBroadphase::getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const -{ - btMultiSapProxy* multiProxy = static_cast(proxy); - aabbMin = multiProxy->m_aabbMin; - aabbMax = multiProxy->m_aabbMax; -} - -void btMultiSapBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin,const btVector3& aabbMax) -{ - for (int i=0;i - -void btMultiSapBroadphase::setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher) -{ - btMultiSapProxy* multiProxy = static_cast(proxy); - multiProxy->m_aabbMin = aabbMin; - multiProxy->m_aabbMax = aabbMax; - - -// bool fullyContained = false; -// bool alreadyInSimple = false; - - - - - struct MyNodeOverlapCallback : public btNodeOverlapCallback - { - btMultiSapBroadphase* m_multiSap; - btMultiSapProxy* m_multiProxy; - btDispatcher* m_dispatcher; - - MyNodeOverlapCallback(btMultiSapBroadphase* multiSap,btMultiSapProxy* multiProxy,btDispatcher* dispatcher) - :m_multiSap(multiSap), - m_multiProxy(multiProxy), - m_dispatcher(dispatcher) - { - - } - - virtual void processNode(int /*nodeSubPart*/, int broadphaseIndex) - { - btBroadphaseInterface* childBroadphase = m_multiSap->getBroadphaseArray()[broadphaseIndex]; - - int containingBroadphaseIndex = -1; - //already found? - for (int i=0;im_bridgeProxies.size();i++) - { - - if (m_multiProxy->m_bridgeProxies[i]->m_childBroadphase == childBroadphase) - { - containingBroadphaseIndex = i; - break; - } - } - if (containingBroadphaseIndex<0) - { - //add it - btBroadphaseProxy* childProxy = childBroadphase->createProxy(m_multiProxy->m_aabbMin,m_multiProxy->m_aabbMax,m_multiProxy->m_shapeType,m_multiProxy->m_clientObject,m_multiProxy->m_collisionFilterGroup,m_multiProxy->m_collisionFilterMask, m_dispatcher,m_multiProxy); - m_multiSap->addToChildBroadphase(m_multiProxy,childProxy,childBroadphase); - - } - } - }; - - MyNodeOverlapCallback myNodeCallback(this,multiProxy,dispatcher); - - - - - if (m_optimizedAabbTree) - m_optimizedAabbTree->reportAabbOverlappingNodex(&myNodeCallback,aabbMin,aabbMax); - - int i; - - for ( i=0;im_bridgeProxies.size();i++) - { - btVector3 worldAabbMin,worldAabbMax; - multiProxy->m_bridgeProxies[i]->m_childBroadphase->getBroadphaseAabb(worldAabbMin,worldAabbMax); - bool overlapsBroadphase = TestAabbAgainstAabb2(worldAabbMin,worldAabbMax,multiProxy->m_aabbMin,multiProxy->m_aabbMax); - if (!overlapsBroadphase) - { - //remove it now - btBridgeProxy* bridgeProxy = multiProxy->m_bridgeProxies[i]; - - btBroadphaseProxy* childProxy = bridgeProxy->m_childProxy; - bridgeProxy->m_childBroadphase->destroyProxy(childProxy,dispatcher); - - multiProxy->m_bridgeProxies.swap( i,multiProxy->m_bridgeProxies.size()-1); - multiProxy->m_bridgeProxies.pop_back(); - - } - } - - - /* - - if (1) - { - - //find broadphase that contain this multiProxy - int numChildBroadphases = getBroadphaseArray().size(); - for (int i=0;igetBroadphaseAabb(worldAabbMin,worldAabbMax); - bool overlapsBroadphase = TestAabbAgainstAabb2(worldAabbMin,worldAabbMax,multiProxy->m_aabbMin,multiProxy->m_aabbMax); - - // fullyContained = fullyContained || boxIsContainedWithinBox(worldAabbMin,worldAabbMax,multiProxy->m_aabbMin,multiProxy->m_aabbMax); - int containingBroadphaseIndex = -1; - - //if already contains this - - for (int i=0;im_bridgeProxies.size();i++) - { - if (multiProxy->m_bridgeProxies[i]->m_childBroadphase == childBroadphase) - { - containingBroadphaseIndex = i; - } - alreadyInSimple = alreadyInSimple || (multiProxy->m_bridgeProxies[i]->m_childBroadphase == m_simpleBroadphase); - } - - if (overlapsBroadphase) - { - if (containingBroadphaseIndex<0) - { - btBroadphaseProxy* childProxy = childBroadphase->createProxy(aabbMin,aabbMax,multiProxy->m_shapeType,multiProxy->m_clientObject,multiProxy->m_collisionFilterGroup,multiProxy->m_collisionFilterMask, dispatcher); - childProxy->m_multiSapParentProxy = multiProxy; - addToChildBroadphase(multiProxy,childProxy,childBroadphase); - } - } else - { - if (containingBroadphaseIndex>=0) - { - //remove - btBridgeProxy* bridgeProxy = multiProxy->m_bridgeProxies[containingBroadphaseIndex]; - - btBroadphaseProxy* childProxy = bridgeProxy->m_childProxy; - bridgeProxy->m_childBroadphase->destroyProxy(childProxy,dispatcher); - - multiProxy->m_bridgeProxies.swap( containingBroadphaseIndex,multiProxy->m_bridgeProxies.size()-1); - multiProxy->m_bridgeProxies.pop_back(); - } - } - } - - - ///If we are in no other child broadphase, stick the proxy in the global 'simple' broadphase (brute force) - ///hopefully we don't end up with many entries here (can assert/provide feedback on stats) - if (0)//!multiProxy->m_bridgeProxies.size()) - { - ///we don't pass the userPtr but our multisap proxy. We need to patch this, before processing an actual collision - ///this is needed to be able to calculate the aabb overlap - btBroadphaseProxy* childProxy = m_simpleBroadphase->createProxy(aabbMin,aabbMax,multiProxy->m_shapeType,multiProxy->m_clientObject,multiProxy->m_collisionFilterGroup,multiProxy->m_collisionFilterMask, dispatcher); - childProxy->m_multiSapParentProxy = multiProxy; - addToChildBroadphase(multiProxy,childProxy,m_simpleBroadphase); - } - } - - if (!multiProxy->m_bridgeProxies.size()) - { - ///we don't pass the userPtr but our multisap proxy. We need to patch this, before processing an actual collision - ///this is needed to be able to calculate the aabb overlap - btBroadphaseProxy* childProxy = m_simpleBroadphase->createProxy(aabbMin,aabbMax,multiProxy->m_shapeType,multiProxy->m_clientObject,multiProxy->m_collisionFilterGroup,multiProxy->m_collisionFilterMask, dispatcher); - childProxy->m_multiSapParentProxy = multiProxy; - addToChildBroadphase(multiProxy,childProxy,m_simpleBroadphase); - } -*/ - - - //update - for ( i=0;im_bridgeProxies.size();i++) - { - btBridgeProxy* bridgeProxyRef = multiProxy->m_bridgeProxies[i]; - bridgeProxyRef->m_childBroadphase->setAabb(bridgeProxyRef->m_childProxy,aabbMin,aabbMax,dispatcher); - } - -} -bool stopUpdating=false; - - - -class btMultiSapBroadphasePairSortPredicate -{ - public: - - bool operator() ( const btBroadphasePair& a1, const btBroadphasePair& b1 ) const - { - btMultiSapBroadphase::btMultiSapProxy* aProxy0 = a1.m_pProxy0 ? (btMultiSapBroadphase::btMultiSapProxy*)a1.m_pProxy0->m_multiSapParentProxy : 0; - btMultiSapBroadphase::btMultiSapProxy* aProxy1 = a1.m_pProxy1 ? (btMultiSapBroadphase::btMultiSapProxy*)a1.m_pProxy1->m_multiSapParentProxy : 0; - btMultiSapBroadphase::btMultiSapProxy* bProxy0 = b1.m_pProxy0 ? (btMultiSapBroadphase::btMultiSapProxy*)b1.m_pProxy0->m_multiSapParentProxy : 0; - btMultiSapBroadphase::btMultiSapProxy* bProxy1 = b1.m_pProxy1 ? (btMultiSapBroadphase::btMultiSapProxy*)b1.m_pProxy1->m_multiSapParentProxy : 0; - - return aProxy0 > bProxy0 || - (aProxy0 == bProxy0 && aProxy1 > bProxy1) || - (aProxy0 == bProxy0 && aProxy1 == bProxy1 && a1.m_algorithm > b1.m_algorithm); - } -}; - - - ///calculateOverlappingPairs is optional: incremental algorithms (sweep and prune) might do it during the set aabb -void btMultiSapBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher) -{ - -// m_simpleBroadphase->calculateOverlappingPairs(dispatcher); - - if (!stopUpdating && getOverlappingPairCache()->hasDeferredRemoval()) - { - - btBroadphasePairArray& overlappingPairArray = getOverlappingPairCache()->getOverlappingPairArray(); - - // quicksort(overlappingPairArray,0,overlappingPairArray.size()); - - overlappingPairArray.quickSort(btMultiSapBroadphasePairSortPredicate()); - - //perform a sort, to find duplicates and to sort 'invalid' pairs to the end - // overlappingPairArray.heapSort(btMultiSapBroadphasePairSortPredicate()); - - overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); - m_invalidPair = 0; - - - int i; - - btBroadphasePair previousPair; - previousPair.m_pProxy0 = 0; - previousPair.m_pProxy1 = 0; - previousPair.m_algorithm = 0; - - - for (i=0;im_multiSapParentProxy : 0; - btMultiSapProxy* aProxy1 = pair.m_pProxy1 ? (btMultiSapProxy*)pair.m_pProxy1->m_multiSapParentProxy : 0; - btMultiSapProxy* bProxy0 = previousPair.m_pProxy0 ? (btMultiSapProxy*)previousPair.m_pProxy0->m_multiSapParentProxy : 0; - btMultiSapProxy* bProxy1 = previousPair.m_pProxy1 ? (btMultiSapProxy*)previousPair.m_pProxy1->m_multiSapParentProxy : 0; - - bool isDuplicate = (aProxy0 == bProxy0) && (aProxy1 == bProxy1); - - previousPair = pair; - - bool needsRemoval = false; - - if (!isDuplicate) - { - bool hasOverlap = testAabbOverlap(pair.m_pProxy0,pair.m_pProxy1); - - if (hasOverlap) - { - needsRemoval = false;//callback->processOverlap(pair); - } else - { - needsRemoval = true; - } - } else - { - //remove duplicate - needsRemoval = true; - //should have no algorithm - btAssert(!pair.m_algorithm); - } - - if (needsRemoval) - { - getOverlappingPairCache()->cleanOverlappingPair(pair,dispatcher); - - // m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1); - // m_overlappingPairArray.pop_back(); - pair.m_pProxy0 = 0; - pair.m_pProxy1 = 0; - m_invalidPair++; - gOverlappingPairs--; - } - - } - - ///if you don't like to skip the invalid pairs in the array, execute following code: - #define CLEAN_INVALID_PAIRS 1 - #ifdef CLEAN_INVALID_PAIRS - - //perform a sort, to sort 'invalid' pairs to the end - //overlappingPairArray.heapSort(btMultiSapBroadphasePairSortPredicate()); - overlappingPairArray.quickSort(btMultiSapBroadphasePairSortPredicate()); - - overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); - m_invalidPair = 0; - #endif//CLEAN_INVALID_PAIRS - - //printf("overlappingPairArray.size()=%d\n",overlappingPairArray.size()); - } - - -} - - -bool btMultiSapBroadphase::testAabbOverlap(btBroadphaseProxy* childProxy0,btBroadphaseProxy* childProxy1) -{ - btMultiSapProxy* multiSapProxy0 = (btMultiSapProxy*)childProxy0->m_multiSapParentProxy; - btMultiSapProxy* multiSapProxy1 = (btMultiSapProxy*)childProxy1->m_multiSapParentProxy; - - return TestAabbAgainstAabb2(multiSapProxy0->m_aabbMin,multiSapProxy0->m_aabbMax, - multiSapProxy1->m_aabbMin,multiSapProxy1->m_aabbMax); - -} - - -void btMultiSapBroadphase::printStats() -{ -/* printf("---------------------------------\n"); - - printf("btMultiSapBroadphase.h\n"); - printf("numHandles = %d\n",m_multiSapProxies.size()); - //find broadphase that contain this multiProxy - int numChildBroadphases = getBroadphaseArray().size(); - for (int i=0;iprintStats(); - - } - */ - -} - -void btMultiSapBroadphase::resetPool(btDispatcher* dispatcher) -{ - // not yet -} diff --git a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.h b/extern/bullet2/src/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.h deleted file mode 100644 index 7bcfe6b132a8..000000000000 --- a/extern/bullet2/src/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.h +++ /dev/null @@ -1,151 +0,0 @@ -/* -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_MULTI_SAP_BROADPHASE -#define BT_MULTI_SAP_BROADPHASE - -#include "btBroadphaseInterface.h" -#include "LinearMath/btAlignedObjectArray.h" -#include "btOverlappingPairCache.h" - - -class btBroadphaseInterface; -class btSimpleBroadphase; - - -typedef btAlignedObjectArray btSapBroadphaseArray; - -///The btMultiSapBroadphase is a research project, not recommended to use in production. Use btAxisSweep3 or btDbvtBroadphase instead. -///The btMultiSapBroadphase is a broadphase that contains multiple SAP broadphases. -///The user can add SAP broadphases that cover the world. A btBroadphaseProxy can be in multiple child broadphases at the same time. -///A btQuantizedBvh acceleration structures finds overlapping SAPs for each btBroadphaseProxy. -///See http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=328 -///and http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=1329 -class btMultiSapBroadphase :public btBroadphaseInterface -{ - btSapBroadphaseArray m_sapBroadphases; - - btSimpleBroadphase* m_simpleBroadphase; - - btOverlappingPairCache* m_overlappingPairs; - - class btQuantizedBvh* m_optimizedAabbTree; - - - bool m_ownsPairCache; - - btOverlapFilterCallback* m_filterCallback; - - int m_invalidPair; - - struct btBridgeProxy - { - btBroadphaseProxy* m_childProxy; - btBroadphaseInterface* m_childBroadphase; - }; - - -public: - - struct btMultiSapProxy : public btBroadphaseProxy - { - - ///array with all the entries that this proxy belongs to - btAlignedObjectArray m_bridgeProxies; - btVector3 m_aabbMin; - btVector3 m_aabbMax; - - int m_shapeType; - -/* void* m_userPtr; - short int m_collisionFilterGroup; - short int m_collisionFilterMask; -*/ - btMultiSapProxy(const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask) - :btBroadphaseProxy(aabbMin,aabbMax,userPtr,collisionFilterGroup,collisionFilterMask), - m_aabbMin(aabbMin), - m_aabbMax(aabbMax), - m_shapeType(shapeType) - { - m_multiSapParentProxy =this; - } - - - }; - -protected: - - - btAlignedObjectArray m_multiSapProxies; - -public: - - btMultiSapBroadphase(int maxProxies = 16384,btOverlappingPairCache* pairCache=0); - - - btSapBroadphaseArray& getBroadphaseArray() - { - return m_sapBroadphases; - } - - const btSapBroadphaseArray& getBroadphaseArray() const - { - return m_sapBroadphases; - } - - virtual ~btMultiSapBroadphase(); - - virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy); - virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher); - virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher); - virtual void getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const; - - virtual void rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback,const btVector3& aabbMin=btVector3(0,0,0),const btVector3& aabbMax=btVector3(0,0,0)); - - void addToChildBroadphase(btMultiSapProxy* parentMultiSapProxy, btBroadphaseProxy* childProxy, btBroadphaseInterface* childBroadphase); - - ///calculateOverlappingPairs is optional: incremental algorithms (sweep and prune) might do it during the set aabb - virtual void calculateOverlappingPairs(btDispatcher* dispatcher); - - bool testAabbOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); - - virtual btOverlappingPairCache* getOverlappingPairCache() - { - return m_overlappingPairs; - } - virtual const btOverlappingPairCache* getOverlappingPairCache() const - { - return m_overlappingPairs; - } - - ///getAabb returns the axis aligned bounding box in the 'global' coordinate frame - ///will add some transform later - virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const - { - aabbMin.setValue(-BT_LARGE_FLOAT,-BT_LARGE_FLOAT,-BT_LARGE_FLOAT); - aabbMax.setValue(BT_LARGE_FLOAT,BT_LARGE_FLOAT,BT_LARGE_FLOAT); - } - - void buildTree(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax); - - virtual void printStats(); - - void quicksort (btBroadphasePairArray& a, int lo, int hi); - - ///reset broadphase internal structures, to ensure determinism/reproducability - virtual void resetPool(btDispatcher* dispatcher); - -}; - -#endif //BT_MULTI_SAP_BROADPHASE diff --git a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp b/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp deleted file mode 100644 index 12997d2e3741..000000000000 --- a/extern/bullet2/src/BulletDynamics/Featherstone/btMultiBodyConstraint.cpp +++ /dev/null @@ -1,375 +0,0 @@ -#include "btMultiBodyConstraint.h" -#include "BulletDynamics/Dynamics/btRigidBody.h" -#include "btMultiBodyPoint2Point.h" //for testing (BTMBP2PCONSTRAINT_BLOCK_ANGULAR_MOTION_TEST macro) - - - -btMultiBodyConstraint::btMultiBodyConstraint(btMultiBody* bodyA,btMultiBody* bodyB,int linkA, int linkB, int numRows, bool isUnilateral) - :m_bodyA(bodyA), - m_bodyB(bodyB), - m_linkA(linkA), - m_linkB(linkB), - m_numRows(numRows), - m_jacSizeA(0), - m_jacSizeBoth(0), - m_isUnilateral(isUnilateral), - m_numDofsFinalized(-1), - m_maxAppliedImpulse(100) -{ - -} - -void btMultiBodyConstraint::updateJacobianSizes() -{ - if(m_bodyA) - { - m_jacSizeA = (6 + m_bodyA->getNumDofs()); - } - - if(m_bodyB) - { - m_jacSizeBoth = m_jacSizeA + 6 + m_bodyB->getNumDofs(); - } - else - m_jacSizeBoth = m_jacSizeA; -} - -void btMultiBodyConstraint::allocateJacobiansMultiDof() -{ - updateJacobianSizes(); - - m_posOffset = ((1 + m_jacSizeBoth)*m_numRows); - m_data.resize((2 + m_jacSizeBoth) * m_numRows); -} - -btMultiBodyConstraint::~btMultiBodyConstraint() -{ -} - -void btMultiBodyConstraint::applyDeltaVee(btMultiBodyJacobianData& data, btScalar* delta_vee, btScalar impulse, int velocityIndex, int ndof) -{ - for (int i = 0; i < ndof; ++i) - data.m_deltaVelocities[velocityIndex+i] += delta_vee[i] * impulse; -} - -btScalar btMultiBodyConstraint::fillMultiBodyConstraint( btMultiBodySolverConstraint& solverConstraint, - btMultiBodyJacobianData& data, - btScalar* jacOrgA, btScalar* jacOrgB, - const btVector3& contactNormalOnB, - const btVector3& posAworld, const btVector3& posBworld, - btScalar posError, - const btContactSolverInfo& infoGlobal, - btScalar lowerLimit, btScalar upperLimit, - btScalar relaxation, - bool isFriction, btScalar desiredVelocity, btScalar cfmSlip) -{ - - - solverConstraint.m_multiBodyA = m_bodyA; - solverConstraint.m_multiBodyB = m_bodyB; - solverConstraint.m_linkA = m_linkA; - solverConstraint.m_linkB = m_linkB; - - btMultiBody* multiBodyA = solverConstraint.m_multiBodyA; - btMultiBody* multiBodyB = solverConstraint.m_multiBodyB; - - btSolverBody* bodyA = multiBodyA ? 0 : &data.m_solverBodyPool->at(solverConstraint.m_solverBodyIdA); - btSolverBody* bodyB = multiBodyB ? 0 : &data.m_solverBodyPool->at(solverConstraint.m_solverBodyIdB); - - btRigidBody* rb0 = multiBodyA ? 0 : bodyA->m_originalBody; - btRigidBody* rb1 = multiBodyB ? 0 : bodyB->m_originalBody; - - btVector3 rel_pos1, rel_pos2; //these two used to be inited to posAworld and posBworld (respectively) but it does not seem necessary - if (bodyA) - rel_pos1 = posAworld - bodyA->getWorldTransform().getOrigin(); - if (bodyB) - rel_pos2 = posBworld - bodyB->getWorldTransform().getOrigin(); - - if (multiBodyA) - { - if (solverConstraint.m_linkA<0) - { - rel_pos1 = posAworld - multiBodyA->getBasePos(); - } else - { - rel_pos1 = posAworld - multiBodyA->getLink(solverConstraint.m_linkA).m_cachedWorldTransform.getOrigin(); - } - - const int ndofA = multiBodyA->getNumDofs() + 6; - - solverConstraint.m_deltaVelAindex = multiBodyA->getCompanionId(); - - if (solverConstraint.m_deltaVelAindex <0) - { - solverConstraint.m_deltaVelAindex = data.m_deltaVelocities.size(); - multiBodyA->setCompanionId(solverConstraint.m_deltaVelAindex); - data.m_deltaVelocities.resize(data.m_deltaVelocities.size()+ndofA); - } else - { - btAssert(data.m_deltaVelocities.size() >= solverConstraint.m_deltaVelAindex+ndofA); - } - - //determine jacobian of this 1D constraint in terms of multibodyA's degrees of freedom - //resize.. - solverConstraint.m_jacAindex = data.m_jacobians.size(); - data.m_jacobians.resize(data.m_jacobians.size()+ndofA); - //copy/determine - if(jacOrgA) - { - for (int i=0;ifillContactJacobianMultiDof(solverConstraint.m_linkA, posAworld, contactNormalOnB, jac1, data.scratch_r, data.scratch_v, data.scratch_m); - } - - //determine the velocity response of multibodyA to reaction impulses of this constraint (i.e. A[i,i] for i=1,...n_con: multibody's inverse inertia with respect to this 1D constraint) - //resize.. - data.m_deltaVelocitiesUnitImpulse.resize(data.m_deltaVelocitiesUnitImpulse.size()+ndofA); //=> each constraint row has the constrained tree dofs allocated in m_deltaVelocitiesUnitImpulse - btAssert(data.m_jacobians.size() == data.m_deltaVelocitiesUnitImpulse.size()); - btScalar* delta = &data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex]; - //determine.. - multiBodyA->calcAccelerationDeltasMultiDof(&data.m_jacobians[solverConstraint.m_jacAindex],delta,data.scratch_r, data.scratch_v); - - btVector3 torqueAxis0 = rel_pos1.cross(contactNormalOnB); - solverConstraint.m_relpos1CrossNormal = torqueAxis0; - solverConstraint.m_contactNormal1 = contactNormalOnB; - } - else //if(rb0) - { - btVector3 torqueAxis0 = rel_pos1.cross(contactNormalOnB); - solverConstraint.m_angularComponentA = rb0 ? rb0->getInvInertiaTensorWorld()*torqueAxis0*rb0->getAngularFactor() : btVector3(0,0,0); - solverConstraint.m_relpos1CrossNormal = torqueAxis0; - solverConstraint.m_contactNormal1 = contactNormalOnB; - } - - if (multiBodyB) - { - if (solverConstraint.m_linkB<0) - { - rel_pos2 = posBworld - multiBodyB->getBasePos(); - } else - { - rel_pos2 = posBworld - multiBodyB->getLink(solverConstraint.m_linkB).m_cachedWorldTransform.getOrigin(); - } - - const int ndofB = multiBodyB->getNumDofs() + 6; - - solverConstraint.m_deltaVelBindex = multiBodyB->getCompanionId(); - if (solverConstraint.m_deltaVelBindex <0) - { - solverConstraint.m_deltaVelBindex = data.m_deltaVelocities.size(); - multiBodyB->setCompanionId(solverConstraint.m_deltaVelBindex); - data.m_deltaVelocities.resize(data.m_deltaVelocities.size()+ndofB); - } - - //determine jacobian of this 1D constraint in terms of multibodyB's degrees of freedom - //resize.. - solverConstraint.m_jacBindex = data.m_jacobians.size(); - data.m_jacobians.resize(data.m_jacobians.size()+ndofB); - //copy/determine.. - if(jacOrgB) - { - for (int i=0;ifillContactJacobianMultiDof(solverConstraint.m_linkB, posBworld, -contactNormalOnB, &data.m_jacobians[solverConstraint.m_jacBindex], data.scratch_r, data.scratch_v, data.scratch_m); - } - - //determine velocity response of multibodyB to reaction impulses of this constraint (i.e. A[i,i] for i=1,...n_con: multibody's inverse inertia with respect to this 1D constraint) - //resize.. - data.m_deltaVelocitiesUnitImpulse.resize(data.m_deltaVelocitiesUnitImpulse.size()+ndofB); - btAssert(data.m_jacobians.size() == data.m_deltaVelocitiesUnitImpulse.size()); - btScalar* delta = &data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex]; - //determine.. - multiBodyB->calcAccelerationDeltasMultiDof(&data.m_jacobians[solverConstraint.m_jacBindex],delta,data.scratch_r, data.scratch_v); - - btVector3 torqueAxis1 = rel_pos2.cross(contactNormalOnB); - solverConstraint.m_relpos2CrossNormal = -torqueAxis1; - solverConstraint.m_contactNormal2 = -contactNormalOnB; - - } - else //if(rb1) - { - btVector3 torqueAxis1 = rel_pos2.cross(contactNormalOnB); - solverConstraint.m_angularComponentB = rb1 ? rb1->getInvInertiaTensorWorld()*-torqueAxis1*rb1->getAngularFactor() : btVector3(0,0,0); - solverConstraint.m_relpos2CrossNormal = -torqueAxis1; - solverConstraint.m_contactNormal2 = -contactNormalOnB; - } - { - - btVector3 vec; - btScalar denom0 = 0.f; - btScalar denom1 = 0.f; - btScalar* jacB = 0; - btScalar* jacA = 0; - btScalar* deltaVelA = 0; - btScalar* deltaVelB = 0; - int ndofA = 0; - //determine the "effective mass" of the constrained multibodyA with respect to this 1D constraint (i.e. 1/A[i,i]) - if (multiBodyA) - { - ndofA = multiBodyA->getNumDofs() + 6; - jacA = &data.m_jacobians[solverConstraint.m_jacAindex]; - deltaVelA = &data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex]; - for (int i = 0; i < ndofA; ++i) - { - btScalar j = jacA[i] ; - btScalar l = deltaVelA[i]; - denom0 += j*l; - } - } - else if(rb0) - { - vec = ( solverConstraint.m_angularComponentA).cross(rel_pos1); - denom0 = rb0->getInvMass() + contactNormalOnB.dot(vec); - } - // - if (multiBodyB) - { - const int ndofB = multiBodyB->getNumDofs() + 6; - jacB = &data.m_jacobians[solverConstraint.m_jacBindex]; - deltaVelB = &data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex]; - for (int i = 0; i < ndofB; ++i) - { - btScalar j = jacB[i] ; - btScalar l = deltaVelB[i]; - denom1 += j*l; - } - - } - else if(rb1) - { - vec = ( -solverConstraint.m_angularComponentB).cross(rel_pos2); - denom1 = rb1->getInvMass() + contactNormalOnB.dot(vec); - } - - // - btScalar d = denom0+denom1; - if (d>SIMD_EPSILON) - { - solverConstraint.m_jacDiagABInv = relaxation/(d); - } - else - { - //disable the constraint row to handle singularity/redundant constraint - solverConstraint.m_jacDiagABInv = 0.f; - } - } - - - //compute rhs and remaining solverConstraint fields - btScalar penetration = isFriction? 0 : posError+infoGlobal.m_linearSlop; - - btScalar rel_vel = 0.f; - int ndofA = 0; - int ndofB = 0; - { - btVector3 vel1,vel2; - if (multiBodyA) - { - ndofA = multiBodyA->getNumDofs() + 6; - btScalar* jacA = &data.m_jacobians[solverConstraint.m_jacAindex]; - for (int i = 0; i < ndofA ; ++i) - rel_vel += multiBodyA->getVelocityVector()[i] * jacA[i]; - } - else if(rb0) - { - rel_vel += rb0->getVelocityInLocalPoint(rel_pos1).dot(solverConstraint.m_contactNormal1); - } - if (multiBodyB) - { - ndofB = multiBodyB->getNumDofs() + 6; - btScalar* jacB = &data.m_jacobians[solverConstraint.m_jacBindex]; - for (int i = 0; i < ndofB ; ++i) - rel_vel += multiBodyB->getVelocityVector()[i] * jacB[i]; - - } - else if(rb1) - { - rel_vel += rb1->getVelocityInLocalPoint(rel_pos2).dot(solverConstraint.m_contactNormal2); - } - - solverConstraint.m_friction = 0.f;//cp.m_combinedFriction; - } - - - ///warm starting (or zero if disabled) - /* - if (infoGlobal.m_solverMode & SOLVER_USE_WARMSTARTING) - { - solverConstraint.m_appliedImpulse = isFriction ? 0 : cp.m_appliedImpulse * infoGlobal.m_warmstartingFactor; - - if (solverConstraint.m_appliedImpulse) - { - if (multiBodyA) - { - btScalar impulse = solverConstraint.m_appliedImpulse; - btScalar* deltaV = &data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex]; - multiBodyA->applyDeltaVee(deltaV,impulse); - applyDeltaVee(data,deltaV,impulse,solverConstraint.m_deltaVelAindex,ndofA); - } else - { - if (rb0) - bodyA->internalApplyImpulse(solverConstraint.m_contactNormal1*bodyA->internalGetInvMass()*rb0->getLinearFactor(),solverConstraint.m_angularComponentA,solverConstraint.m_appliedImpulse); - } - if (multiBodyB) - { - btScalar impulse = solverConstraint.m_appliedImpulse; - btScalar* deltaV = &data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex]; - multiBodyB->applyDeltaVee(deltaV,impulse); - applyDeltaVee(data,deltaV,impulse,solverConstraint.m_deltaVelBindex,ndofB); - } else - { - if (rb1) - bodyB->internalApplyImpulse(-solverConstraint.m_contactNormal2*bodyB->internalGetInvMass()*rb1->getLinearFactor(),-solverConstraint.m_angularComponentB,-(btScalar)solverConstraint.m_appliedImpulse); - } - } - } else - */ - - solverConstraint.m_appliedImpulse = 0.f; - solverConstraint.m_appliedPushImpulse = 0.f; - - { - - btScalar positionalError = 0.f; - btScalar velocityError = desiredVelocity - rel_vel;// * damping; - - - btScalar erp = infoGlobal.m_erp2; - if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold)) - { - erp = infoGlobal.m_erp; - } - - positionalError = -penetration * erp/infoGlobal.m_timeStep; - - btScalar penetrationImpulse = positionalError*solverConstraint.m_jacDiagABInv; - btScalar velocityImpulse = velocityError *solverConstraint.m_jacDiagABInv; - - if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold)) - { - //combine position and velocity into rhs - solverConstraint.m_rhs = penetrationImpulse+velocityImpulse; - solverConstraint.m_rhsPenetration = 0.f; - - } else - { - //split position and velocity into rhs and m_rhsPenetration - solverConstraint.m_rhs = velocityImpulse; - solverConstraint.m_rhsPenetration = penetrationImpulse; - } - - solverConstraint.m_cfm = 0.f; - solverConstraint.m_lowerLimit = lowerLimit; - solverConstraint.m_upperLimit = upperLimit; - } - - return rel_vel; - -} diff --git a/extern/bullet2/src/LinearMath/btScalar.h b/extern/bullet2/src/LinearMath/btScalar.h deleted file mode 100644 index 898669f86e2c..000000000000 --- a/extern/bullet2/src/LinearMath/btScalar.h +++ /dev/null @@ -1,785 +0,0 @@ -/* -Copyright (c) 2003-2009 Erwin Coumans http://bullet.googlecode.com - -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_SCALAR_H -#define BT_SCALAR_H -#if defined(_MSC_VER) && defined(__clang__) /* clang supplies it's own overloads already */ -#define BT_NO_SIMD_OPERATOR_OVERLOADS -#endif - -#ifdef BT_MANAGED_CODE -//Aligned data types not supported in managed code -#pragma unmanaged -#endif - - -#include -#include //size_t for MSVC 6.0 -#include - -/* SVN $Revision$ on $Date$ from http://bullet.googlecode.com*/ -#define BT_BULLET_VERSION 284 - -inline int btGetVersion() -{ - return BT_BULLET_VERSION; -} - -#if defined(DEBUG) || defined (_DEBUG) -#define BT_DEBUG -#endif - - -#ifdef _WIN32 - - #if defined(__MINGW32__) || defined(__CYGWIN__) || (defined (_MSC_VER) && _MSC_VER < 1300) - - #define SIMD_FORCE_INLINE inline - #define ATTRIBUTE_ALIGNED16(a) a - #define ATTRIBUTE_ALIGNED64(a) a - #define ATTRIBUTE_ALIGNED128(a) a - #elif (_M_ARM) - #define SIMD_FORCE_INLINE __forceinline - #define ATTRIBUTE_ALIGNED16(a) __declspec() a - #define ATTRIBUTE_ALIGNED64(a) __declspec() a - #define ATTRIBUTE_ALIGNED128(a) __declspec () a - #else - //#define BT_HAS_ALIGNED_ALLOCATOR - #pragma warning(disable : 4324) // disable padding warning -// #pragma warning(disable:4530) // Disable the exception disable but used in MSCV Stl warning. -// #pragma warning(disable:4996) //Turn off warnings about deprecated C routines -// #pragma warning(disable:4786) // Disable the "debug name too long" warning - - #define SIMD_FORCE_INLINE __forceinline - #define ATTRIBUTE_ALIGNED16(a) __declspec(align(16)) a - #define ATTRIBUTE_ALIGNED64(a) __declspec(align(64)) a - #define ATTRIBUTE_ALIGNED128(a) __declspec (align(128)) a - #ifdef _XBOX - #define BT_USE_VMX128 - - #include - #define BT_HAVE_NATIVE_FSEL - #define btFsel(a,b,c) __fsel((a),(b),(c)) - #else - -#if defined (_M_ARM) - //Do not turn SSE on for ARM (may want to turn on BT_USE_NEON however) -#elif (defined (_WIN32) && (_MSC_VER) && _MSC_VER >= 1400) && (!defined (BT_USE_DOUBLE_PRECISION)) - #if _MSC_VER>1400 - #define BT_USE_SIMD_VECTOR3 - #endif - - #define BT_USE_SSE - #ifdef BT_USE_SSE - -#if (_MSC_FULL_VER >= 170050727)//Visual Studio 2012 can compile SSE4/FMA3 (but SSE4/FMA3 is not enabled by default) - //#define BT_ALLOW_SSE4 //disable this cause blender targets sse2 -#endif //(_MSC_FULL_VER >= 160040219) - - //BT_USE_SSE_IN_API is disabled under Windows by default, because - //it makes it harder to integrate Bullet into your application under Windows - //(structured embedding Bullet structs/classes need to be 16-byte aligned) - //with relatively little performance gain - //If you are not embedded Bullet data in your classes, or make sure that you align those classes on 16-byte boundaries - //you can manually enable this line or set it in the build system for a bit of performance gain (a few percent, dependent on usage) - //#define BT_USE_SSE_IN_API - #endif //BT_USE_SSE - #include -#endif - - #endif//_XBOX - - #endif //__MINGW32__ - -#ifdef BT_DEBUG - #if defined(_MSC_VER) && !defined(__clang__) - #include - #define btAssert(x) { if(!(x)){printf("Assert "__FILE__ ":%u ("#x")\n", __LINE__);__debugbreak(); }} - #else//_MSC_VER - #include - #define btAssert assert - #endif//_MSC_VER -#else - #define btAssert(x) -#endif - //btFullAssert is optional, slows down a lot - #define btFullAssert(x) - - #define btLikely(_c) _c - #define btUnlikely(_c) _c - -#else - -#if defined (__CELLOS_LV2__) - #define SIMD_FORCE_INLINE inline __attribute__((always_inline)) - #define ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16))) - #define ATTRIBUTE_ALIGNED64(a) a __attribute__ ((aligned (64))) - #define ATTRIBUTE_ALIGNED128(a) a __attribute__ ((aligned (128))) - #ifndef assert - #include - #endif -#ifdef BT_DEBUG -#ifdef __SPU__ -#include -#define printf spu_printf - #define btAssert(x) {if(!(x)){printf("Assert "__FILE__ ":%u ("#x")\n", __LINE__);spu_hcmpeq(0,0);}} -#else - #define btAssert assert -#endif - -#else - #define btAssert(x) -#endif - //btFullAssert is optional, slows down a lot - #define btFullAssert(x) - - #define btLikely(_c) _c - #define btUnlikely(_c) _c - -#else - -#ifdef USE_LIBSPE2 - - #define SIMD_FORCE_INLINE __inline - #define ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16))) - #define ATTRIBUTE_ALIGNED64(a) a __attribute__ ((aligned (64))) - #define ATTRIBUTE_ALIGNED128(a) a __attribute__ ((aligned (128))) - #ifndef assert - #include - #endif -#ifdef BT_DEBUG - #define btAssert assert -#else - #define btAssert(x) -#endif - //btFullAssert is optional, slows down a lot - #define btFullAssert(x) - - - #define btLikely(_c) __builtin_expect((_c), 1) - #define btUnlikely(_c) __builtin_expect((_c), 0) - - -#else - //non-windows systems - -#if (defined (__APPLE__) && (!defined (BT_USE_DOUBLE_PRECISION))) - #if defined (__i386__) || defined (__x86_64__) - #define BT_USE_SIMD_VECTOR3 - #define BT_USE_SSE - //BT_USE_SSE_IN_API is enabled on Mac OSX by default, because memory is automatically aligned on 16-byte boundaries - //if apps run into issues, we will disable the next line - #define BT_USE_SSE_IN_API - #ifdef BT_USE_SSE - // include appropriate SSE level - #if defined (__SSE4_1__) - #include - #elif defined (__SSSE3__) - #include - #elif defined (__SSE3__) - #include - #else - #include - #endif - #endif //BT_USE_SSE - #elif defined( __ARM_NEON__ ) - #ifdef __clang__ - #define BT_USE_NEON 1 - #define BT_USE_SIMD_VECTOR3 - - #if defined BT_USE_NEON && defined (__clang__) - #include - #endif//BT_USE_NEON - #endif //__clang__ - #endif//__arm__ - - #define SIMD_FORCE_INLINE inline __attribute__ ((always_inline)) -///@todo: check out alignment methods for other platforms/compilers - #define ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16))) - #define ATTRIBUTE_ALIGNED64(a) a __attribute__ ((aligned (64))) - #define ATTRIBUTE_ALIGNED128(a) a __attribute__ ((aligned (128))) - #ifndef assert - #include - #endif - - #if defined(DEBUG) || defined (_DEBUG) - #if defined (__i386__) || defined (__x86_64__) - #include - #define btAssert(x)\ - {\ - if(!(x))\ - {\ - printf("Assert %s in line %d, file %s\n",#x, __LINE__, __FILE__);\ - asm volatile ("int3");\ - }\ - } - #else//defined (__i386__) || defined (__x86_64__) - #define btAssert assert - #endif//defined (__i386__) || defined (__x86_64__) - #else//defined(DEBUG) || defined (_DEBUG) - #define btAssert(x) - #endif//defined(DEBUG) || defined (_DEBUG) - - //btFullAssert is optional, slows down a lot - #define btFullAssert(x) - #define btLikely(_c) _c - #define btUnlikely(_c) _c - -#else - - #define SIMD_FORCE_INLINE inline - ///@todo: check out alignment methods for other platforms/compilers - ///#define ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16))) - ///#define ATTRIBUTE_ALIGNED64(a) a __attribute__ ((aligned (64))) - ///#define ATTRIBUTE_ALIGNED128(a) a __attribute__ ((aligned (128))) - #define ATTRIBUTE_ALIGNED16(a) a - #define ATTRIBUTE_ALIGNED64(a) a - #define ATTRIBUTE_ALIGNED128(a) a - #ifndef assert - #include - #endif - -#if defined(DEBUG) || defined (_DEBUG) - #define btAssert assert -#else - #define btAssert(x) -#endif - - //btFullAssert is optional, slows down a lot - #define btFullAssert(x) - #define btLikely(_c) _c - #define btUnlikely(_c) _c -#endif //__APPLE__ - -#endif // LIBSPE2 - -#endif //__CELLOS_LV2__ -#endif - - -///The btScalar type abstracts floating point numbers, to easily switch between double and single floating point precision. -#if defined(BT_USE_DOUBLE_PRECISION) - -typedef double btScalar; -//this number could be bigger in double precision -#define BT_LARGE_FLOAT 1e30 -#else - -typedef float btScalar; -//keep BT_LARGE_FLOAT*BT_LARGE_FLOAT < FLT_MAX -#define BT_LARGE_FLOAT 1e18f -#endif - -#ifdef BT_USE_SSE -typedef __m128 btSimdFloat4; -#endif//BT_USE_SSE - -#if defined (BT_USE_SSE) -//#if defined BT_USE_SSE_IN_API && defined (BT_USE_SSE) -#ifdef _WIN32 - -#ifndef BT_NAN -static int btNanMask = 0x7F800001; -#define BT_NAN (*(float*)&btNanMask) -#endif - -#ifndef BT_INFINITY -static int btInfinityMask = 0x7F800000; -#define BT_INFINITY (*(float*)&btInfinityMask) -inline int btGetInfinityMask()//suppress stupid compiler warning -{ - return btInfinityMask; -} -#endif - -//use this, in case there are clashes (such as xnamath.h) -#ifndef BT_NO_SIMD_OPERATOR_OVERLOADS -inline __m128 operator + (const __m128 A, const __m128 B) -{ - return _mm_add_ps(A, B); -} - -inline __m128 operator - (const __m128 A, const __m128 B) -{ - return _mm_sub_ps(A, B); -} - -inline __m128 operator * (const __m128 A, const __m128 B) -{ - return _mm_mul_ps(A, B); -} -#endif //BT_NO_SIMD_OPERATOR_OVERLOADS - -#define btCastfTo128i(a) (_mm_castps_si128(a)) -#define btCastfTo128d(a) (_mm_castps_pd(a)) -#define btCastiTo128f(a) (_mm_castsi128_ps(a)) -#define btCastdTo128f(a) (_mm_castpd_ps(a)) -#define btCastdTo128i(a) (_mm_castpd_si128(a)) -#define btAssign128(r0,r1,r2,r3) _mm_setr_ps(r0,r1,r2,r3) - -#else//_WIN32 - -#define btCastfTo128i(a) ((__m128i)(a)) -#define btCastfTo128d(a) ((__m128d)(a)) -#define btCastiTo128f(a) ((__m128) (a)) -#define btCastdTo128f(a) ((__m128) (a)) -#define btCastdTo128i(a) ((__m128i)(a)) -#define btAssign128(r0,r1,r2,r3) (__m128){r0,r1,r2,r3} -#define BT_INFINITY INFINITY -#define BT_NAN NAN -#endif//_WIN32 -#else - -#ifdef BT_USE_NEON - #include - - typedef float32x4_t btSimdFloat4; - #define BT_INFINITY INFINITY - #define BT_NAN NAN - #define btAssign128(r0,r1,r2,r3) (float32x4_t){r0,r1,r2,r3} -#else//BT_USE_NEON - - #ifndef BT_INFINITY - struct btInfMaskConverter - { - union { - float mask; - int intmask; - }; - btInfMaskConverter(int mask=0x7F800000) - :intmask(mask) - { - } - }; - static btInfMaskConverter btInfinityMask = 0x7F800000; - #define BT_INFINITY (btInfinityMask.mask) - inline int btGetInfinityMask()//suppress stupid compiler warning - { - return btInfinityMask.intmask; - } - #endif -#endif//BT_USE_NEON - -#endif //BT_USE_SSE - -#ifdef BT_USE_NEON -#include - -typedef float32x4_t btSimdFloat4; -#define BT_INFINITY INFINITY -#define BT_NAN NAN -#define btAssign128(r0,r1,r2,r3) (float32x4_t){r0,r1,r2,r3} -#endif - - - - - -#define BT_DECLARE_ALIGNED_ALLOCATOR() \ - SIMD_FORCE_INLINE void* operator new(size_t sizeInBytes) { return btAlignedAlloc(sizeInBytes,16); } \ - SIMD_FORCE_INLINE void operator delete(void* ptr) { btAlignedFree(ptr); } \ - SIMD_FORCE_INLINE void* operator new(size_t, void* ptr) { return ptr; } \ - SIMD_FORCE_INLINE void operator delete(void*, void*) { } \ - SIMD_FORCE_INLINE void* operator new[](size_t sizeInBytes) { return btAlignedAlloc(sizeInBytes,16); } \ - SIMD_FORCE_INLINE void operator delete[](void* ptr) { btAlignedFree(ptr); } \ - SIMD_FORCE_INLINE void* operator new[](size_t, void* ptr) { return ptr; } \ - SIMD_FORCE_INLINE void operator delete[](void*, void*) { } \ - - - -#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) { if (xbtScalar(1)) x=btScalar(1); return acos(x); } -SIMD_FORCE_INLINE btScalar btAsin(btScalar x) { if (xbtScalar(1)) x=btScalar(1); 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); } -SIMD_FORCE_INLINE btScalar btFmod(btScalar x,btScalar y) { return fmod(x,y); } - -#else - -SIMD_FORCE_INLINE btScalar btSqrt(btScalar y) -{ -#ifdef USE_APPROXIMATION -#ifdef __LP64__ - float xhalf = 0.5f*y; - int i = *(int*)&y; - i = 0x5f375a86 - (i>>1); - y = *(float*)&i; - y = y*(1.5f - xhalf*y*y); - y = y*(1.5f - xhalf*y*y); - y = y*(1.5f - xhalf*y*y); - y=1/y; - return y; -#else - double x, z, tempf; - unsigned long *tfptr = ((unsigned long *)&tempf) + 1; - tempf = y; - *tfptr = (0xbfcdd90a - *tfptr)>>1; /* estimate of 1/sqrt(y) */ - x = tempf; - z = y*btScalar(0.5); - x = (btScalar(1.5)*x)-(x*x)*(x*z); /* iteration formula */ - x = (btScalar(1.5)*x)-(x*x)*(x*z); - x = (btScalar(1.5)*x)-(x*x)*(x*z); - x = (btScalar(1.5)*x)-(x*x)*(x*z); - x = (btScalar(1.5)*x)-(x*x)*(x*z); - return x*y; -#endif -#else - return sqrtf(y); -#endif -} -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) { - if (xbtScalar(1)) - x=btScalar(1); - return acosf(x); -} -SIMD_FORCE_INLINE btScalar btAsin(btScalar x) { - if (xbtScalar(1)) - x=btScalar(1); - 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); } -SIMD_FORCE_INLINE btScalar btFmod(btScalar x,btScalar y) { return fmodf(x,y); } - -#endif - -#define SIMD_PI btScalar(3.1415926535897932384626433832795029) -#define SIMD_2_PI (btScalar(2.0) * SIMD_PI) -#define SIMD_HALF_PI (SIMD_PI * btScalar(0.5)) -#define SIMD_RADS_PER_DEG (SIMD_2_PI / btScalar(360.0)) -#define SIMD_DEGS_PER_RAD (btScalar(360.0) / SIMD_2_PI) -#define SIMDSQRT12 btScalar(0.7071067811865475244008443621048490) - -#define btRecipSqrt(x) ((btScalar)(btScalar(1.0)/btSqrt(btScalar(x)))) /* reciprocal square root */ -#define btRecip(x) (btScalar(1.0)/btScalar(x)) - -#ifdef BT_USE_DOUBLE_PRECISION -#define SIMD_EPSILON DBL_EPSILON -#define SIMD_INFINITY DBL_MAX -#define BT_ONE 1.0 -#define BT_ZERO 0.0 -#define BT_TWO 2.0 -#define BT_HALF 0.5 -#else -#define SIMD_EPSILON FLT_EPSILON -#define SIMD_INFINITY FLT_MAX -#define BT_ONE 1.0f -#define BT_ZERO 0.0f -#define BT_TWO 2.0f -#define BT_HALF 0.5f -#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 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 - -#ifndef btFsel -SIMD_FORCE_INLINE btScalar btFsel(btScalar a, btScalar b, btScalar c) -{ - return a >= 0 ? b : c; -} -#endif -#define btFsels(a,b,c) (btScalar)btFsel(a,b,c) - - -SIMD_FORCE_INLINE bool btMachineIsLittleEndian() -{ - long int i = 1; - const char *p = (const char *) &i; - if (p[0] == 1) // Lowest address contains the least significant byte - return true; - else - return false; -} - - - -///btSelect avoids branches, which makes performance much better for consoles like Playstation 3 and XBox 360 -///Thanks Phil Knight. See also http://www.cellperformance.com/articles/2006/04/more_techniques_for_eliminatin_1.html -SIMD_FORCE_INLINE unsigned btSelect(unsigned condition, unsigned valueIfConditionNonZero, unsigned valueIfConditionZero) -{ - // Set testNz to 0xFFFFFFFF if condition is nonzero, 0x00000000 if condition is zero - // Rely on positive value or'ed with its negative having sign bit on - // and zero value or'ed with its negative (which is still zero) having sign bit off - // Use arithmetic shift right, shifting the sign bit through all 32 bits - unsigned testNz = (unsigned)(((int)condition | -(int)condition) >> 31); - unsigned testEqz = ~testNz; - return ((valueIfConditionNonZero & testNz) | (valueIfConditionZero & testEqz)); -} -SIMD_FORCE_INLINE int btSelect(unsigned condition, int valueIfConditionNonZero, int valueIfConditionZero) -{ - unsigned testNz = (unsigned)(((int)condition | -(int)condition) >> 31); - unsigned testEqz = ~testNz; - return static_cast((valueIfConditionNonZero & testNz) | (valueIfConditionZero & testEqz)); -} -SIMD_FORCE_INLINE float btSelect(unsigned condition, float valueIfConditionNonZero, float valueIfConditionZero) -{ -#ifdef BT_HAVE_NATIVE_FSEL - return (float)btFsel((btScalar)condition - btScalar(1.0f), valueIfConditionNonZero, valueIfConditionZero); -#else - return (condition != 0) ? valueIfConditionNonZero : valueIfConditionZero; -#endif -} - -template SIMD_FORCE_INLINE void btSwap(T& a, T& b) -{ - T tmp = a; - a = b; - b = tmp; -} - - -//PCK: endian swapping functions -SIMD_FORCE_INLINE unsigned btSwapEndian(unsigned val) -{ - return (((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); -} - -SIMD_FORCE_INLINE unsigned short btSwapEndian(unsigned short val) -{ - return static_cast(((val & 0xff00) >> 8) | ((val & 0x00ff) << 8)); -} - -SIMD_FORCE_INLINE unsigned btSwapEndian(int val) -{ - return btSwapEndian((unsigned)val); -} - -SIMD_FORCE_INLINE unsigned short btSwapEndian(short val) -{ - return btSwapEndian((unsigned short) val); -} - -///btSwapFloat uses using char pointers to swap the endianness -////btSwapFloat/btSwapDouble will NOT return a float, because the machine might 'correct' invalid floating point values -///Not all values of sign/exponent/mantissa are valid floating point numbers according to IEEE 754. -///When a floating point unit is faced with an invalid value, it may actually change the value, or worse, throw an exception. -///In most systems, running user mode code, you wouldn't get an exception, but instead the hardware/os/runtime will 'fix' the number for you. -///so instead of returning a float/double, we return integer/long long integer -SIMD_FORCE_INLINE unsigned int btSwapEndianFloat(float d) -{ - unsigned int a = 0; - unsigned char *dst = (unsigned char *)&a; - unsigned char *src = (unsigned char *)&d; - - dst[0] = src[3]; - dst[1] = src[2]; - dst[2] = src[1]; - dst[3] = src[0]; - return a; -} - -// unswap using char pointers -SIMD_FORCE_INLINE float btUnswapEndianFloat(unsigned int a) -{ - float d = 0.0f; - unsigned char *src = (unsigned char *)&a; - unsigned char *dst = (unsigned char *)&d; - - dst[0] = src[3]; - dst[1] = src[2]; - dst[2] = src[1]; - dst[3] = src[0]; - - return d; -} - - -// swap using char pointers -SIMD_FORCE_INLINE void btSwapEndianDouble(double d, unsigned char* dst) -{ - unsigned char *src = (unsigned char *)&d; - - dst[0] = src[7]; - dst[1] = src[6]; - dst[2] = src[5]; - dst[3] = src[4]; - dst[4] = src[3]; - dst[5] = src[2]; - dst[6] = src[1]; - dst[7] = src[0]; - -} - -// unswap using char pointers -SIMD_FORCE_INLINE double btUnswapEndianDouble(const unsigned char *src) -{ - double d = 0.0; - unsigned char *dst = (unsigned char *)&d; - - dst[0] = src[7]; - dst[1] = src[6]; - dst[2] = src[5]; - dst[3] = src[4]; - dst[4] = src[3]; - dst[5] = src[2]; - dst[6] = src[1]; - dst[7] = src[0]; - - return d; -} - -template -SIMD_FORCE_INLINE void btSetZero(T* a, int n) -{ - T* acurr = a; - size_t ncurr = n; - while (ncurr > 0) - { - *(acurr++) = 0; - --ncurr; - } -} - - -SIMD_FORCE_INLINE btScalar btLargeDot(const btScalar *a, const btScalar *b, int n) -{ - btScalar 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; -} - - -// returns normalized value in range [-SIMD_PI, SIMD_PI] -SIMD_FORCE_INLINE btScalar btNormalizeAngle(btScalar angleInRadians) -{ - angleInRadians = btFmod(angleInRadians, SIMD_2_PI); - if(angleInRadians < -SIMD_PI) - { - return angleInRadians + SIMD_2_PI; - } - else if(angleInRadians > SIMD_PI) - { - return angleInRadians - SIMD_2_PI; - } - else - { - return angleInRadians; - } -} - - - -///rudimentary class to provide type info -struct btTypedObject -{ - btTypedObject(int objectType) - :m_objectType(objectType) - { - } - int m_objectType; - inline int getObjectType() const - { - return m_objectType; - } -}; - - - -///align a pointer to the provided alignment, upwards -template T* btAlignPointer(T* unalignedPtr, size_t alignment) -{ - - struct btConvertPointerSizeT - { - union - { - T* ptr; - size_t integer; - }; - }; - btConvertPointerSizeT converter; - - - const size_t bit_mask = ~(alignment - 1); - converter.ptr = unalignedPtr; - converter.integer += alignment-1; - converter.integer &= bit_mask; - return converter.ptr; -} - - -#endif //BT_SCALAR_H diff --git a/extern/bullet2/src/LinearMath/btSerializer.cpp b/extern/bullet2/src/LinearMath/btSerializer.cpp deleted file mode 100644 index 8fdcfb142114..000000000000 --- a/extern/bullet2/src/LinearMath/btSerializer.cpp +++ /dev/null @@ -1,1177 +0,0 @@ -char sBulletDNAstr[]= { -char(83),char(68),char(78),char(65),char(78),char(65),char(77),char(69),char(123),char(1),char(0),char(0),char(109),char(95),char(115),char(105),char(122),char(101),char(0),char(109), -char(95),char(99),char(97),char(112),char(97),char(99),char(105),char(116),char(121),char(0),char(42),char(109),char(95),char(100),char(97),char(116),char(97),char(0),char(109),char(95), -char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(115),char(0),char(109),char(95),char(99),char(111), -char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(115),char(0),char(109),char(95),char(99),char(111),char(110), -char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(115),char(0),char(42),char(102),char(105),char(114),char(115),char(116),char(0),char(42),char(108),char(97),char(115), -char(116),char(0),char(109),char(95),char(102),char(108),char(111),char(97),char(116),char(115),char(91),char(52),char(93),char(0),char(109),char(95),char(101),char(108),char(91),char(51), -char(93),char(0),char(109),char(95),char(98),char(97),char(115),char(105),char(115),char(0),char(109),char(95),char(111),char(114),char(105),char(103),char(105),char(110),char(0),char(109), -char(95),char(114),char(111),char(111),char(116),char(78),char(111),char(100),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(115),char(117),char(98), -char(116),char(114),char(101),char(101),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100), -char(65),char(97),char(98),char(98),char(77),char(105),char(110),char(91),char(51),char(93),char(0),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122), -char(101),char(100),char(65),char(97),char(98),char(98),char(77),char(97),char(120),char(91),char(51),char(93),char(0),char(109),char(95),char(97),char(97),char(98),char(98),char(77), -char(105),char(110),char(79),char(114),char(103),char(0),char(109),char(95),char(97),char(97),char(98),char(98),char(77),char(97),char(120),char(79),char(114),char(103),char(0),char(109), -char(95),char(101),char(115),char(99),char(97),char(112),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(115),char(117),char(98),char(80),char(97), -char(114),char(116),char(0),char(109),char(95),char(116),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109), -char(95),char(112),char(97),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(101),char(115),char(99),char(97),char(112),char(101),char(73),char(110),char(100),char(101), -char(120),char(79),char(114),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(98), -char(118),char(104),char(65),char(97),char(98),char(98),char(77),char(105),char(110),char(0),char(109),char(95),char(98),char(118),char(104),char(65),char(97),char(98),char(98),char(77), -char(97),char(120),char(0),char(109),char(95),char(98),char(118),char(104),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(97),char(116),char(105),char(111),char(110), -char(0),char(109),char(95),char(99),char(117),char(114),char(78),char(111),char(100),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(117),char(115), -char(101),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(97),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(110),char(117),char(109),char(67), -char(111),char(110),char(116),char(105),char(103),char(117),char(111),char(117),char(115),char(76),char(101),char(97),char(102),char(78),char(111),char(100),char(101),char(115),char(0),char(109), -char(95),char(110),char(117),char(109),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(67),char(111),char(110),char(116),char(105),char(103),char(117), -char(111),char(117),char(115),char(78),char(111),char(100),char(101),char(115),char(0),char(42),char(109),char(95),char(99),char(111),char(110),char(116),char(105),char(103),char(117),char(111), -char(117),char(115),char(78),char(111),char(100),char(101),char(115),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105), -char(122),char(101),char(100),char(67),char(111),char(110),char(116),char(105),char(103),char(117),char(111),char(117),char(115),char(78),char(111),char(100),char(101),char(115),char(80),char(116), -char(114),char(0),char(42),char(109),char(95),char(115),char(117),char(98),char(84),char(114),char(101),char(101),char(73),char(110),char(102),char(111),char(80),char(116),char(114),char(0), -char(109),char(95),char(116),char(114),char(97),char(118),char(101),char(114),char(115),char(97),char(108),char(77),char(111),char(100),char(101),char(0),char(109),char(95),char(110),char(117), -char(109),char(83),char(117),char(98),char(116),char(114),char(101),char(101),char(72),char(101),char(97),char(100),char(101),char(114),char(115),char(0),char(42),char(109),char(95),char(110), -char(97),char(109),char(101),char(0),char(109),char(95),char(115),char(104),char(97),char(112),char(101),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(112),char(97), -char(100),char(100),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110), -char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(83),char(99),char(97), -char(108),char(105),char(110),char(103),char(0),char(109),char(95),char(112),char(108),char(97),char(110),char(101),char(78),char(111),char(114),char(109),char(97),char(108),char(0),char(109), -char(95),char(112),char(108),char(97),char(110),char(101),char(67),char(111),char(110),char(115),char(116),char(97),char(110),char(116),char(0),char(109),char(95),char(105),char(109),char(112), -char(108),char(105),char(99),char(105),char(116),char(83),char(104),char(97),char(112),char(101),char(68),char(105),char(109),char(101),char(110),char(115),char(105),char(111),char(110),char(115), -char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(77),char(97),char(114),char(103),char(105),char(110),char(0),char(109), -char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(0),char(109),char(95),char(112),char(111),char(115),char(0),char(109),char(95),char(114),char(97),char(100), -char(105),char(117),char(115),char(0),char(109),char(95),char(99),char(111),char(110),char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114),char(110),char(97),char(108), -char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(42),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(80),char(111), -char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(114),char(114),char(97),char(121),char(80),char(116),char(114),char(0),char(109),char(95),char(108),char(111),char(99), -char(97),char(108),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(114),char(114),char(97),char(121),char(83),char(105),char(122),char(101),char(0), -char(109),char(95),char(118),char(97),char(108),char(117),char(101),char(0),char(109),char(95),char(112),char(97),char(100),char(91),char(50),char(93),char(0),char(109),char(95),char(118), -char(97),char(108),char(117),char(101),char(115),char(91),char(51),char(93),char(0),char(109),char(95),char(112),char(97),char(100),char(0),char(42),char(109),char(95),char(118),char(101), -char(114),char(116),char(105),char(99),char(101),char(115),char(51),char(102),char(0),char(42),char(109),char(95),char(118),char(101),char(114),char(116),char(105),char(99),char(101),char(115), -char(51),char(100),char(0),char(42),char(109),char(95),char(105),char(110),char(100),char(105),char(99),char(101),char(115),char(51),char(50),char(0),char(42),char(109),char(95),char(51), -char(105),char(110),char(100),char(105),char(99),char(101),char(115),char(49),char(54),char(0),char(42),char(109),char(95),char(51),char(105),char(110),char(100),char(105),char(99),char(101), -char(115),char(56),char(0),char(42),char(109),char(95),char(105),char(110),char(100),char(105),char(99),char(101),char(115),char(49),char(54),char(0),char(109),char(95),char(110),char(117), -char(109),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(86),char(101),char(114),char(116), -char(105),char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(109),char(101),char(115),char(104),char(80),char(97),char(114),char(116),char(115),char(80),char(116),char(114), -char(0),char(109),char(95),char(115),char(99),char(97),char(108),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(101),char(115),char(104), -char(80),char(97),char(114),char(116),char(115),char(0),char(109),char(95),char(109),char(101),char(115),char(104),char(73),char(110),char(116),char(101),char(114),char(102),char(97),char(99), -char(101),char(0),char(42),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(70),char(108),char(111),char(97),char(116),char(66), -char(118),char(104),char(0),char(42),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(68),char(111),char(117),char(98),char(108), -char(101),char(66),char(118),char(104),char(0),char(42),char(109),char(95),char(116),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111), -char(77),char(97),char(112),char(0),char(109),char(95),char(112),char(97),char(100),char(51),char(91),char(52),char(93),char(0),char(109),char(95),char(116),char(114),char(105),char(109), -char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(116),char(114),char(97),char(110),char(115), -char(102),char(111),char(114),char(109),char(0),char(42),char(109),char(95),char(99),char(104),char(105),char(108),char(100),char(83),char(104),char(97),char(112),char(101),char(0),char(109), -char(95),char(99),char(104),char(105),char(108),char(100),char(83),char(104),char(97),char(112),char(101),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(99),char(104), -char(105),char(108),char(100),char(77),char(97),char(114),char(103),char(105),char(110),char(0),char(42),char(109),char(95),char(99),char(104),char(105),char(108),char(100),char(83),char(104), -char(97),char(112),char(101),char(80),char(116),char(114),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(104),char(105),char(108),char(100),char(83),char(104),char(97), -char(112),char(101),char(115),char(0),char(109),char(95),char(117),char(112),char(65),char(120),char(105),char(115),char(0),char(109),char(95),char(117),char(112),char(73),char(110),char(100), -char(101),char(120),char(0),char(109),char(95),char(102),char(108),char(97),char(103),char(115),char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(86),char(48),char(86), -char(49),char(65),char(110),char(103),char(108),char(101),char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(86),char(49),char(86),char(50),char(65),char(110),char(103), -char(108),char(101),char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(86),char(50),char(86),char(48),char(65),char(110),char(103),char(108),char(101),char(0),char(42), -char(109),char(95),char(104),char(97),char(115),char(104),char(84),char(97),char(98),char(108),char(101),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(110),char(101), -char(120),char(116),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(118),char(97),char(108),char(117),char(101),char(65),char(114),char(114),char(97),char(121),char(80), -char(116),char(114),char(0),char(42),char(109),char(95),char(107),char(101),char(121),char(65),char(114),char(114),char(97),char(121),char(80),char(116),char(114),char(0),char(109),char(95), -char(99),char(111),char(110),char(118),char(101),char(120),char(69),char(112),char(115),char(105),char(108),char(111),char(110),char(0),char(109),char(95),char(112),char(108),char(97),char(110), -char(97),char(114),char(69),char(112),char(115),char(105),char(108),char(111),char(110),char(0),char(109),char(95),char(101),char(113),char(117),char(97),char(108),char(86),char(101),char(114), -char(116),char(101),char(120),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(68), -char(105),char(115),char(116),char(97),char(110),char(99),char(101),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(122), -char(101),char(114),char(111),char(65),char(114),char(101),char(97),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(110), -char(101),char(120),char(116),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(104),char(97),char(115),char(104),char(84),char(97),char(98),char(108),char(101),char(83), -char(105),char(122),char(101),char(0),char(109),char(95),char(110),char(117),char(109),char(86),char(97),char(108),char(117),char(101),char(115),char(0),char(109),char(95),char(110),char(117), -char(109),char(75),char(101),char(121),char(115),char(0),char(109),char(95),char(103),char(105),char(109),char(112),char(97),char(99),char(116),char(83),char(117),char(98),char(84),char(121), -char(112),char(101),char(0),char(42),char(109),char(95),char(117),char(110),char(115),char(99),char(97),char(108),char(101),char(100),char(80),char(111),char(105),char(110),char(116),char(115), -char(70),char(108),char(111),char(97),char(116),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(117),char(110),char(115),char(99),char(97),char(108),char(101),char(100), -char(80),char(111),char(105),char(110),char(116),char(115),char(68),char(111),char(117),char(98),char(108),char(101),char(80),char(116),char(114),char(0),char(109),char(95),char(110),char(117), -char(109),char(85),char(110),char(115),char(99),char(97),char(108),char(101),char(100),char(80),char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(112),char(97), -char(100),char(100),char(105),char(110),char(103),char(51),char(91),char(52),char(93),char(0),char(42),char(109),char(95),char(98),char(114),char(111),char(97),char(100),char(112),char(104), -char(97),char(115),char(101),char(72),char(97),char(110),char(100),char(108),char(101),char(0),char(42),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105), -char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(0),char(42),char(109),char(95),char(114),char(111),char(111),char(116),char(67),char(111),char(108),char(108),char(105), -char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(0),char(109),char(95),char(119),char(111),char(114),char(108),char(100),char(84),char(114),char(97), -char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105), -char(111),char(110),char(87),char(111),char(114),char(108),char(100),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(105), -char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105),char(111),char(110),char(76),char(105),char(110),char(101),char(97),char(114),char(86),char(101), -char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105), -char(111),char(110),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95), -char(97),char(110),char(105),char(115),char(111),char(116),char(114),char(111),char(112),char(105),char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0), -char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(99),char(116),char(80),char(114),char(111),char(99),char(101),char(115),char(115),char(105),char(110),char(103),char(84), -char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(100),char(101),char(97),char(99),char(116),char(105),char(118),char(97),char(116), -char(105),char(111),char(110),char(84),char(105),char(109),char(101),char(0),char(109),char(95),char(102),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109), -char(95),char(114),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(114), -char(101),char(115),char(116),char(105),char(116),char(117),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(104),char(105),char(116),char(70),char(114),char(97),char(99), -char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(99),char(100),char(83),char(119),char(101),char(112),char(116),char(83),char(112),char(104),char(101),char(114), -char(101),char(82),char(97),char(100),char(105),char(117),char(115),char(0),char(109),char(95),char(99),char(99),char(100),char(77),char(111),char(116),char(105),char(111),char(110),char(84), -char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(104),char(97),char(115),char(65),char(110),char(105),char(115),char(111),char(116), -char(114),char(111),char(112),char(105),char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(111),char(108),char(108), -char(105),char(115),char(105),char(111),char(110),char(70),char(108),char(97),char(103),char(115),char(0),char(109),char(95),char(105),char(115),char(108),char(97),char(110),char(100),char(84), -char(97),char(103),char(49),char(0),char(109),char(95),char(99),char(111),char(109),char(112),char(97),char(110),char(105),char(111),char(110),char(73),char(100),char(0),char(109),char(95), -char(97),char(99),char(116),char(105),char(118),char(97),char(116),char(105),char(111),char(110),char(83),char(116),char(97),char(116),char(101),char(49),char(0),char(109),char(95),char(105), -char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(99),char(104),char(101),char(99),char(107),char(67), -char(111),char(108),char(108),char(105),char(100),char(101),char(87),char(105),char(116),char(104),char(0),char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(73), -char(110),char(102),char(111),char(0),char(109),char(95),char(103),char(114),char(97),char(118),char(105),char(116),char(121),char(0),char(109),char(95),char(99),char(111),char(108),char(108), -char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(105),char(110), -char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(84),char(101),char(110),char(115),char(111),char(114),char(87),char(111),char(114),char(108),char(100),char(0), -char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97), -char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103), -char(117),char(108),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(70), -char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(103),char(114),char(97),char(118),char(105),char(116),char(121),char(95),char(97),char(99),char(99),char(101), -char(108),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105), -char(97),char(76),char(111),char(99),char(97),char(108),char(0),char(109),char(95),char(116),char(111),char(116),char(97),char(108),char(70),char(111),char(114),char(99),char(101),char(0), -char(109),char(95),char(116),char(111),char(116),char(97),char(108),char(84),char(111),char(114),char(113),char(117),char(101),char(0),char(109),char(95),char(105),char(110),char(118),char(101), -char(114),char(115),char(101),char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112), -char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103), -char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103), -char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(76), -char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108), -char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103), -char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100), -char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117), -char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(108), -char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(101),char(101),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111), -char(108),char(100),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(108),char(101),char(101),char(112),char(105),char(110),char(103), -char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110), -char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(111),char(110),char(115),char(116), -char(114),char(97),char(105),char(110),char(116),char(82),char(111),char(119),char(115),char(0),char(110),char(117),char(98),char(0),char(42),char(109),char(95),char(114),char(98),char(65), -char(0),char(42),char(109),char(95),char(114),char(98),char(66),char(0),char(109),char(95),char(111),char(98),char(106),char(101),char(99),char(116),char(84),char(121),char(112),char(101), -char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(84),char(121),char(112), -char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(100), -char(0),char(109),char(95),char(110),char(101),char(101),char(100),char(115),char(70),char(101),char(101),char(100),char(98),char(97),char(99),char(107),char(0),char(109),char(95),char(97), -char(112),char(112),char(108),char(105),char(101),char(100),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(100),char(98),char(103),char(68), -char(114),char(97),char(119),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(100),char(105),char(115),char(97),char(98),char(108),char(101),char(67),char(111),char(108), -char(108),char(105),char(115),char(105),char(111),char(110),char(115),char(66),char(101),char(116),char(119),char(101),char(101),char(110),char(76),char(105),char(110),char(107),char(101),char(100), -char(66),char(111),char(100),char(105),char(101),char(115),char(0),char(109),char(95),char(111),char(118),char(101),char(114),char(114),char(105),char(100),char(101),char(78),char(117),char(109), -char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(98), -char(114),char(101),char(97),char(107),char(105),char(110),char(103),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(84),char(104),char(114),char(101),char(115),char(104), -char(111),char(108),char(100),char(0),char(109),char(95),char(105),char(115),char(69),char(110),char(97),char(98),char(108),char(101),char(100),char(0),char(112),char(97),char(100),char(100), -char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(116),char(121),char(112),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97), -char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(112),char(105),char(118),char(111),char(116),char(73),char(110),char(65),char(0),char(109), -char(95),char(112),char(105),char(118),char(111),char(116),char(73),char(110),char(66),char(0),char(109),char(95),char(114),char(98),char(65),char(70),char(114),char(97),char(109),char(101), -char(0),char(109),char(95),char(114),char(98),char(66),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(82),char(101),char(102), -char(101),char(114),char(101),char(110),char(99),char(101),char(70),char(114),char(97),char(109),char(101),char(65),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108), -char(97),char(114),char(79),char(110),char(108),char(121),char(0),char(109),char(95),char(101),char(110),char(97),char(98),char(108),char(101),char(65),char(110),char(103),char(117),char(108), -char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(0),char(109),char(95),char(109),char(111),char(116),char(111),char(114),char(84),char(97),char(114),char(103),char(101), -char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(109),char(97),char(120),char(77),char(111),char(116),char(111),char(114), -char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(108),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116), -char(0),char(109),char(95),char(117),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(108),char(105),char(109),char(105), -char(116),char(83),char(111),char(102),char(116),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(98),char(105),char(97),char(115),char(70),char(97),char(99),char(116), -char(111),char(114),char(0),char(109),char(95),char(114),char(101),char(108),char(97),char(120),char(97),char(116),char(105),char(111),char(110),char(70),char(97),char(99),char(116),char(111), -char(114),char(0),char(109),char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(115),char(119), -char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(49),char(0),char(109),char(95),char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110), -char(50),char(0),char(109),char(95),char(116),char(119),char(105),char(115),char(116),char(83),char(112),char(97),char(110),char(0),char(109),char(95),char(100),char(97),char(109),char(112), -char(105),char(110),char(103),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109), -char(105),char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105), -char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105), -char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105), -char(116),char(0),char(109),char(95),char(117),char(115),char(101),char(76),char(105),char(110),char(101),char(97),char(114),char(82),char(101),char(102),char(101),char(114),char(101),char(110), -char(99),char(101),char(70),char(114),char(97),char(109),char(101),char(65),char(0),char(109),char(95),char(117),char(115),char(101),char(79),char(102),char(102),char(115),char(101),char(116), -char(70),char(111),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(114),char(97),char(109),char(101),char(0),char(109), -char(95),char(54),char(100),char(111),char(102),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(69),char(110), -char(97),char(98),char(108),char(101),char(100),char(91),char(54),char(93),char(0),char(109),char(95),char(101),char(113),char(117),char(105),char(108),char(105),char(98),char(114),char(105), -char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(83), -char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103), -char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(91),char(54),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(66), -char(111),char(117),char(110),char(99),char(101),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82), -char(80),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95), -char(108),char(105),char(110),char(101),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(108),char(105),char(110), -char(101),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114), -char(84),char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(108),char(105),char(110), -char(101),char(97),char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(108), -char(105),char(110),char(101),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0),char(109),char(95),char(108), -char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115), -char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105), -char(110),char(103),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105),char(98),char(114),char(105), -char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(110),char(97),char(98), -char(108),char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83), -char(101),char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97), -char(114),char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(108), -char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115), -char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83), -char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91), -char(52),char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(66),char(111),char(117),char(110),char(99),char(101),char(0),char(109), -char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110), -char(103),char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108), -char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114), -char(77),char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(84),char(97), -char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108), -char(97),char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(97),char(110), -char(103),char(117),char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0),char(109),char(95),char(97), -char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115), -char(115),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109), -char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105), -char(98),char(114),char(105),char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114), -char(69),char(110),char(97),char(98),char(108),char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(97),char(110),char(103), -char(117),char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95), -char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91), -char(52),char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116), -char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95), -char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103), -char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(114),char(111),char(116),char(97),char(116),char(101),char(79), -char(114),char(100),char(101),char(114),char(0),char(109),char(95),char(97),char(120),char(105),char(115),char(73),char(110),char(65),char(0),char(109),char(95),char(97),char(120),char(105), -char(115),char(73),char(110),char(66),char(0),char(109),char(95),char(114),char(97),char(116),char(105),char(111),char(0),char(109),char(95),char(116),char(97),char(117),char(0),char(109), -char(95),char(116),char(105),char(109),char(101),char(83),char(116),char(101),char(112),char(0),char(109),char(95),char(109),char(97),char(120),char(69),char(114),char(114),char(111),char(114), -char(82),char(101),char(100),char(117),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(115),char(111),char(114),char(0),char(109),char(95),char(101),char(114), -char(112),char(0),char(109),char(95),char(101),char(114),char(112),char(50),char(0),char(109),char(95),char(103),char(108),char(111),char(98),char(97),char(108),char(67),char(102),char(109), -char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(80),char(101),char(110),char(101),char(116), -char(114),char(97),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(115),char(112), -char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(84),char(117),char(114),char(110),char(69),char(114),char(112),char(0),char(109),char(95), -char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(111),char(112),char(0),char(109),char(95),char(119),char(97),char(114),char(109),char(115),char(116),char(97), -char(114),char(116),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(109),char(97),char(120),char(71),char(121),char(114), -char(111),char(115),char(99),char(111),char(112),char(105),char(99),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(115),char(105),char(110),char(103),char(108), -char(101),char(65),char(120),char(105),char(115),char(82),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110), -char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(110),char(117),char(109),char(73),char(116),char(101),char(114),char(97), -char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(77),char(111),char(100),char(101),char(0),char(109), -char(95),char(114),char(101),char(115),char(116),char(105),char(110),char(103),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(82),char(101),char(115),char(116),char(105), -char(116),char(117),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(109),char(105), -char(110),char(105),char(109),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(66),char(97),char(116),char(99),char(104),char(83),char(105),char(122),char(101), -char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(108),char(105), -char(110),char(101),char(97),char(114),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97),char(110),char(103),char(117), -char(108),char(97),char(114),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(118),char(111),char(108),char(117),char(109), -char(101),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(116),char(101),char(114),char(105), -char(97),char(108),char(0),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(112),char(114),char(101),char(118), -char(105),char(111),char(117),char(115),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(118),char(101),char(108),char(111),char(99), -char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(99),char(99),char(117),char(109),char(117),char(108),char(97),char(116),char(101),char(100),char(70),char(111),char(114), -char(99),char(101),char(0),char(109),char(95),char(110),char(111),char(114),char(109),char(97),char(108),char(0),char(109),char(95),char(97),char(114),char(101),char(97),char(0),char(109), -char(95),char(97),char(116),char(116),char(97),char(99),char(104),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101), -char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(76),char(101),char(110),char(103),char(116),char(104),char(0),char(109),char(95), -char(98),char(98),char(101),char(110),char(100),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99), -char(101),char(115),char(91),char(51),char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(65),char(114),char(101),char(97),char(0),char(109),char(95),char(99), -char(48),char(91),char(52),char(93),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(52), -char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(99),char(49),char(0), -char(109),char(95),char(99),char(50),char(0),char(109),char(95),char(99),char(48),char(0),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(70),char(114),char(97), -char(109),char(101),char(0),char(42),char(109),char(95),char(114),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(0),char(109),char(95),char(110),char(111), -char(100),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(97),char(101),char(114),char(111),char(77),char(111),char(100),char(101),char(108),char(0), -char(109),char(95),char(98),char(97),char(117),char(109),char(103),char(97),char(114),char(116),char(101),char(0),char(109),char(95),char(100),char(114),char(97),char(103),char(0),char(109), -char(95),char(108),char(105),char(102),char(116),char(0),char(109),char(95),char(112),char(114),char(101),char(115),char(115),char(117),char(114),char(101),char(0),char(109),char(95),char(118), -char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(100),char(121),char(110),char(97),char(109),char(105),char(99),char(70),char(114),char(105),char(99),char(116), -char(105),char(111),char(110),char(0),char(109),char(95),char(112),char(111),char(115),char(101),char(77),char(97),char(116),char(99),char(104),char(0),char(109),char(95),char(114),char(105), -char(103),char(105),char(100),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109), -char(95),char(107),char(105),char(110),char(101),char(116),char(105),char(99),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110), -char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114), -char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114),char(72),char(97),char(114),char(100),char(110),char(101), -char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115),char(116),char(101), -char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75),char(105),char(110),char(101), -char(116),char(105),char(99),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109), -char(95),char(115),char(111),char(102),char(116),char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100), -char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115), -char(116),char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111), -char(102),char(116),char(75),char(105),char(110),char(101),char(116),char(105),char(99),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),char(112),char(117), -char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(83),char(111),char(102),char(116),char(67), -char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109), -char(95),char(109),char(97),char(120),char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(99),char(97), -char(108),char(101),char(0),char(109),char(95),char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(73),char(116),char(101),char(114),char(97),char(116),char(105), -char(111),char(110),char(115),char(0),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(73),char(116),char(101),char(114),char(97),char(116), -char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(100),char(114),char(105),char(102),char(116),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111), -char(110),char(115),char(0),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111), -char(110),char(115),char(0),char(109),char(95),char(114),char(111),char(116),char(0),char(109),char(95),char(115),char(99),char(97),char(108),char(101),char(0),char(109),char(95),char(97), -char(113),char(113),char(0),char(109),char(95),char(99),char(111),char(109),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110), -char(115),char(0),char(42),char(109),char(95),char(119),char(101),char(105),char(103),char(104),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(80),char(111), -char(115),char(105),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(87),char(101),char(105),char(103),char(116),char(115),char(0), -char(109),char(95),char(98),char(118),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(98),char(102),char(114),char(97),char(109),char(101),char(0),char(109), -char(95),char(102),char(114),char(97),char(109),char(101),char(120),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(108),char(111),char(99),char(105),char(105),char(0), -char(109),char(95),char(105),char(110),char(118),char(119),char(105),char(0),char(109),char(95),char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91), -char(50),char(93),char(0),char(109),char(95),char(100),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93),char(0),char(109),char(95), -char(108),char(118),char(0),char(109),char(95),char(97),char(118),char(0),char(42),char(109),char(95),char(102),char(114),char(97),char(109),char(101),char(114),char(101),char(102),char(115), -char(0),char(42),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(109), -char(97),char(115),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(114),char(97),char(109),char(101),char(82),char(101),char(102),char(115), -char(0),char(109),char(95),char(110),char(117),char(109),char(78),char(111),char(100),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(115), -char(115),char(101),char(115),char(0),char(109),char(95),char(105),char(100),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(105),char(109),char(97),char(115),char(115), -char(0),char(109),char(95),char(110),char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(105),char(109), -char(112),char(117),char(108),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95), -char(108),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0), -char(109),char(95),char(109),char(97),char(116),char(99),char(104),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97),char(120),char(83),char(101),char(108),char(102), -char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(115), -char(101),char(108),char(102),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(70), -char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(105),char(110),char(115),char(65),char(110),char(99),char(104), -char(111),char(114),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(100),char(101),char(0),char(109),char(95),char(99),char(108),char(117),char(115),char(116), -char(101),char(114),char(73),char(110),char(100),char(101),char(120),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(0),char(42),char(109),char(95), -char(98),char(111),char(100),char(121),char(66),char(0),char(109),char(95),char(114),char(101),char(102),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(99),char(102), -char(109),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(100),char(101),char(108),char(101),char(116),char(101),char(0),char(109), -char(95),char(114),char(101),char(108),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(91),char(50),char(93),char(0),char(109),char(95),char(98),char(111), -char(100),char(121),char(65),char(116),char(121),char(112),char(101),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(66),char(116),char(121),char(112),char(101),char(0), -char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(101),char(0), -char(42),char(42),char(109),char(95),char(109),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(42),char(109),char(95),char(110),char(111),char(100), -char(101),char(115),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(115),char(0),char(42),char(109),char(95),char(102),char(97),char(99),char(101),char(115), -char(0),char(42),char(109),char(95),char(116),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(42),char(109),char(95),char(97),char(110), -char(99),char(104),char(111),char(114),char(115),char(0),char(42),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(115),char(0),char(42),char(109), -char(95),char(106),char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(116),char(101),char(114),char(105),char(97), -char(108),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(76),char(105),char(110),char(107),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70), -char(97),char(99),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(84),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97), -char(0),char(109),char(95),char(110),char(117),char(109),char(65),char(110),char(99),char(104),char(111),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(67), -char(108),char(117),char(115),char(116),char(101),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(74),char(111),char(105),char(110),char(116),char(115),char(0), -char(109),char(95),char(99),char(111),char(110),char(102),char(105),char(103),char(0),char(109),char(95),char(122),char(101),char(114),char(111),char(82),char(111),char(116),char(80),char(97), -char(114),char(101),char(110),char(116),char(84),char(111),char(84),char(104),char(105),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(67), -char(111),char(109),char(84),char(111),char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102),char(102),char(115),char(101),char(116),char(0),char(109),char(95), -char(116),char(104),char(105),char(115),char(80),char(105),char(118),char(111),char(116),char(84),char(111),char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102), -char(102),char(115),char(101),char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(84),char(111),char(112),char(91), -char(54),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(66),char(111),char(116),char(116),char(111),char(109), -char(91),char(54),char(93),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(106), -char(111),char(105),char(110),char(116),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(67),char(111),char(108),char(108), -char(105),char(100),char(101),char(114),char(0),char(109),char(95),char(108),char(105),char(110),char(107),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(0),char(109), -char(95),char(108),char(105),char(110),char(107),char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(73),char(110), -char(100),char(101),char(120),char(0),char(109),char(95),char(100),char(111),char(102),char(67),char(111),char(117),char(110),char(116),char(0),char(109),char(95),char(112),char(111),char(115), -char(86),char(97),char(114),char(67),char(111),char(117),char(110),char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(80),char(111),char(115),char(91), -char(55),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(86),char(101),char(108),char(91),char(54),char(93),char(0),char(109),char(95),char(106), -char(111),char(105),char(110),char(116),char(84),char(111),char(114),char(113),char(117),char(101),char(91),char(54),char(93),char(0),char(42),char(109),char(95),char(98),char(97),char(115), -char(101),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(98),char(97),char(115),char(101),char(67),char(111),char(108),char(108),char(105),char(100),char(101), -char(114),char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(87),char(111),char(114),char(108),char(100),char(84),char(114),char(97),char(110),char(115),char(102),char(111), -char(114),char(109),char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(0),char(109),char(95),char(98), -char(97),char(115),char(101),char(77),char(97),char(115),char(115),char(0),char(84),char(89),char(80),char(69),char(95),char(0),char(0),char(0),char(99),char(104),char(97),char(114), -char(0),char(117),char(99),char(104),char(97),char(114),char(0),char(115),char(104),char(111),char(114),char(116),char(0),char(117),char(115),char(104),char(111),char(114),char(116),char(0), -char(105),char(110),char(116),char(0),char(108),char(111),char(110),char(103),char(0),char(117),char(108),char(111),char(110),char(103),char(0),char(102),char(108),char(111),char(97),char(116), -char(0),char(100),char(111),char(117),char(98),char(108),char(101),char(0),char(118),char(111),char(105),char(100),char(0),char(80),char(111),char(105),char(110),char(116),char(101),char(114), -char(65),char(114),char(114),char(97),char(121),char(0),char(98),char(116),char(80),char(104),char(121),char(115),char(105),char(99),char(115),char(83),char(121),char(115),char(116),char(101), -char(109),char(0),char(76),char(105),char(115),char(116),char(66),char(97),char(115),char(101),char(0),char(98),char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51), -char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51),char(68), -char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114),char(110),char(105), -char(111),char(110),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114), -char(110),char(105),char(111),char(110),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116), -char(114),char(105),char(120),char(51),char(120),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97), -char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116), -char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98), -char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(66),char(118),char(104),char(83),char(117),char(98),char(116),char(114),char(101),char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116), -char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101), -char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101), -char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98), -char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(97),char(116), -char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(70),char(108),char(111),char(97), -char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104), -char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105), -char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(97),char(116),char(105),char(99), -char(80),char(108),char(97),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110), -char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(110),char(100),char(82),char(97),char(100),char(105),char(117),char(115), -char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(83),char(112),char(104),char(101),char(114),char(101),char(83),char(104),char(97),char(112),char(101),char(68), -char(97),char(116),char(97),char(0),char(98),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98), -char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98), -char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),char(112),char(108),char(101), -char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(104),char(97),char(114),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105), -char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(101),char(115),char(104),char(80),char(97),char(114),char(116),char(68), -char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(114),char(105),char(100),char(105),char(110),char(103),char(77),char(101),char(115),char(104),char(73),char(110), -char(116),char(101),char(114),char(102),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103), -char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114), -char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111),char(77),char(97),char(112),char(68),char(97),char(116),char(97),char(0),char(98),char(116), -char(83),char(99),char(97),char(108),char(101),char(100),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104), -char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104), -char(97),char(112),char(101),char(67),char(104),char(105),char(108),char(100),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111), -char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(121),char(108),char(105),char(110), -char(100),char(101),char(114),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(83), -char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(97),char(112),char(115),char(117),char(108),char(101),char(83),char(104), -char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110), -char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(73),char(109),char(112),char(97),char(99),char(116),char(77),char(101),char(115),char(104), -char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118),char(101),char(120),char(72),char(117), -char(108),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115), -char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0), -char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(70),char(108),char(111), -char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115),char(87),char(111),char(114), -char(108),char(100),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(116),char(97), -char(99),char(116),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97), -char(116),char(97),char(0),char(98),char(116),char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115),char(87),char(111),char(114),char(108),char(100),char(70),char(108), -char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(83),char(111),char(108), -char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82), -char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116), -char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0), -char(98),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(110),char(102),char(111),char(49),char(0),char(98),char(116), -char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116), -char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), -char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(68),char(97), -char(116),char(97),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116), -char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80), -char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68), -char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110), -char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98), -char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), -char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101), -char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108), -char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116), -char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(67), -char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111), -char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116), -char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110), -char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97), -char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(67),char(111),char(110),char(115), -char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116), -char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(67),char(111),char(110), -char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105), -char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110), -char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114), -char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(50),char(67),char(111),char(110),char(115),char(116),char(114),char(97), -char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111), -char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(50),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111), -char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(83),char(108),char(105),char(100),char(101),char(114),char(67),char(111), -char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(108),char(105),char(100),char(101), -char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116), -char(97),char(0),char(98),char(116),char(71),char(101),char(97),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108), -char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(97),char(114),char(67),char(111),char(110),char(115),char(116),char(114), -char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66), -char(111),char(100),char(121),char(77),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116), -char(66),char(111),char(100),char(121),char(78),char(111),char(100),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100), -char(121),char(76),char(105),char(110),char(107),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(70),char(97), -char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(84),char(101),char(116),char(114),char(97), -char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(65),char(110),char(99),char(104),char(111),char(114), -char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(67),char(111),char(110),char(102),char(105),char(103),char(68), -char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(80),char(111),char(115),char(101),char(68),char(97),char(116),char(97), -char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(74),char(111),char(105),char(110),char(116),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(68),char(111),char(117),char(98), -char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(76),char(105), -char(110),char(107),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66), -char(111),char(100),char(121),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116), -char(105),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(0),char(84),char(76),char(69),char(78), -char(1),char(0),char(1),char(0),char(2),char(0),char(2),char(0),char(4),char(0),char(4),char(0),char(4),char(0),char(4),char(0),char(8),char(0),char(0),char(0), -char(12),char(0),char(36),char(0),char(8),char(0),char(16),char(0),char(32),char(0),char(16),char(0),char(32),char(0),char(48),char(0),char(96),char(0),char(64),char(0), -char(-128),char(0),char(20),char(0),char(48),char(0),char(80),char(0),char(16),char(0),char(84),char(0),char(-124),char(0),char(12),char(0),char(52),char(0),char(52),char(0), -char(20),char(0),char(64),char(0),char(4),char(0),char(4),char(0),char(8),char(0),char(4),char(0),char(32),char(0),char(28),char(0),char(60),char(0),char(56),char(0), -char(76),char(0),char(76),char(0),char(24),char(0),char(60),char(0),char(60),char(0),char(60),char(0),char(16),char(0),char(64),char(0),char(68),char(0),char(-48),char(1), -char(0),char(1),char(-72),char(0),char(-104),char(0),char(104),char(0),char(88),char(0),char(-24),char(1),char(-96),char(3),char(8),char(0),char(52),char(0),char(52),char(0), -char(0),char(0),char(68),char(0),char(84),char(0),char(-124),char(0),char(116),char(0),char(92),char(1),char(-36),char(0),char(-116),char(1),char(124),char(1),char(-44),char(0), -char(-4),char(0),char(-52),char(1),char(92),char(1),char(116),char(2),char(-124),char(2),char(-76),char(4),char(-52),char(0),char(108),char(1),char(92),char(0),char(-116),char(0), -char(16),char(0),char(100),char(0),char(20),char(0),char(36),char(0),char(100),char(0),char(92),char(0),char(104),char(0),char(-64),char(0),char(92),char(1),char(104),char(0), -char(-84),char(1),char(-68),char(2),char(108),char(1),char(-68),char(0),char(100),char(0),char(0),char(0),char(83),char(84),char(82),char(67),char(84),char(0),char(0),char(0), -char(10),char(0),char(3),char(0),char(4),char(0),char(0),char(0),char(4),char(0),char(1),char(0),char(9),char(0),char(2),char(0),char(11),char(0),char(3),char(0), -char(10),char(0),char(3),char(0),char(10),char(0),char(4),char(0),char(10),char(0),char(5),char(0),char(12),char(0),char(2),char(0),char(9),char(0),char(6),char(0), -char(9),char(0),char(7),char(0),char(13),char(0),char(1),char(0),char(7),char(0),char(8),char(0),char(14),char(0),char(1),char(0),char(8),char(0),char(8),char(0), -char(15),char(0),char(1),char(0),char(7),char(0),char(8),char(0),char(16),char(0),char(1),char(0),char(8),char(0),char(8),char(0),char(17),char(0),char(1),char(0), -char(13),char(0),char(9),char(0),char(18),char(0),char(1),char(0),char(14),char(0),char(9),char(0),char(19),char(0),char(2),char(0),char(17),char(0),char(10),char(0), -char(13),char(0),char(11),char(0),char(20),char(0),char(2),char(0),char(18),char(0),char(10),char(0),char(14),char(0),char(11),char(0),char(21),char(0),char(4),char(0), -char(4),char(0),char(12),char(0),char(4),char(0),char(13),char(0),char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0),char(22),char(0),char(6),char(0), -char(13),char(0),char(16),char(0),char(13),char(0),char(17),char(0),char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0), -char(0),char(0),char(21),char(0),char(23),char(0),char(6),char(0),char(14),char(0),char(16),char(0),char(14),char(0),char(17),char(0),char(4),char(0),char(18),char(0), -char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0),char(24),char(0),char(3),char(0),char(2),char(0),char(14),char(0), -char(2),char(0),char(15),char(0),char(4),char(0),char(22),char(0),char(25),char(0),char(12),char(0),char(13),char(0),char(23),char(0),char(13),char(0),char(24),char(0), -char(13),char(0),char(25),char(0),char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0), -char(22),char(0),char(30),char(0),char(24),char(0),char(31),char(0),char(21),char(0),char(32),char(0),char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0), -char(26),char(0),char(12),char(0),char(14),char(0),char(23),char(0),char(14),char(0),char(24),char(0),char(14),char(0),char(25),char(0),char(4),char(0),char(26),char(0), -char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0),char(23),char(0),char(30),char(0),char(24),char(0),char(31),char(0), -char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),char(21),char(0),char(32),char(0),char(27),char(0),char(3),char(0),char(0),char(0),char(35),char(0), -char(4),char(0),char(36),char(0),char(0),char(0),char(37),char(0),char(28),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(13),char(0),char(39),char(0), -char(13),char(0),char(40),char(0),char(7),char(0),char(41),char(0),char(0),char(0),char(21),char(0),char(29),char(0),char(5),char(0),char(27),char(0),char(38),char(0), -char(13),char(0),char(39),char(0),char(13),char(0),char(42),char(0),char(7),char(0),char(43),char(0),char(4),char(0),char(44),char(0),char(30),char(0),char(2),char(0), -char(13),char(0),char(45),char(0),char(7),char(0),char(46),char(0),char(31),char(0),char(4),char(0),char(29),char(0),char(47),char(0),char(30),char(0),char(48),char(0), -char(4),char(0),char(49),char(0),char(0),char(0),char(37),char(0),char(32),char(0),char(1),char(0),char(4),char(0),char(50),char(0),char(33),char(0),char(2),char(0), -char(2),char(0),char(50),char(0),char(0),char(0),char(51),char(0),char(34),char(0),char(2),char(0),char(2),char(0),char(52),char(0),char(0),char(0),char(51),char(0), -char(35),char(0),char(2),char(0),char(0),char(0),char(52),char(0),char(0),char(0),char(53),char(0),char(36),char(0),char(8),char(0),char(13),char(0),char(54),char(0), -char(14),char(0),char(55),char(0),char(32),char(0),char(56),char(0),char(34),char(0),char(57),char(0),char(35),char(0),char(58),char(0),char(33),char(0),char(59),char(0), -char(4),char(0),char(60),char(0),char(4),char(0),char(61),char(0),char(37),char(0),char(4),char(0),char(36),char(0),char(62),char(0),char(13),char(0),char(63),char(0), -char(4),char(0),char(64),char(0),char(0),char(0),char(37),char(0),char(38),char(0),char(7),char(0),char(27),char(0),char(38),char(0),char(37),char(0),char(65),char(0), -char(25),char(0),char(66),char(0),char(26),char(0),char(67),char(0),char(39),char(0),char(68),char(0),char(7),char(0),char(43),char(0),char(0),char(0),char(69),char(0), -char(40),char(0),char(2),char(0),char(38),char(0),char(70),char(0),char(13),char(0),char(39),char(0),char(41),char(0),char(4),char(0),char(19),char(0),char(71),char(0), -char(27),char(0),char(72),char(0),char(4),char(0),char(73),char(0),char(7),char(0),char(74),char(0),char(42),char(0),char(4),char(0),char(27),char(0),char(38),char(0), -char(41),char(0),char(75),char(0),char(4),char(0),char(76),char(0),char(7),char(0),char(43),char(0),char(43),char(0),char(3),char(0),char(29),char(0),char(47),char(0), -char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),char(44),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(78),char(0), -char(0),char(0),char(37),char(0),char(45),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0), -char(46),char(0),char(4),char(0),char(4),char(0),char(79),char(0),char(7),char(0),char(80),char(0),char(7),char(0),char(81),char(0),char(7),char(0),char(82),char(0), -char(39),char(0),char(14),char(0),char(4),char(0),char(83),char(0),char(4),char(0),char(84),char(0),char(46),char(0),char(85),char(0),char(4),char(0),char(86),char(0), -char(7),char(0),char(87),char(0),char(7),char(0),char(88),char(0),char(7),char(0),char(89),char(0),char(7),char(0),char(90),char(0),char(7),char(0),char(91),char(0), -char(4),char(0),char(92),char(0),char(4),char(0),char(93),char(0),char(4),char(0),char(94),char(0),char(4),char(0),char(95),char(0),char(0),char(0),char(37),char(0), -char(47),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(37),char(0),char(65),char(0),char(13),char(0),char(39),char(0),char(7),char(0),char(43),char(0), -char(4),char(0),char(96),char(0),char(48),char(0),char(5),char(0),char(29),char(0),char(47),char(0),char(13),char(0),char(97),char(0),char(14),char(0),char(98),char(0), -char(4),char(0),char(99),char(0),char(0),char(0),char(100),char(0),char(49),char(0),char(25),char(0),char(9),char(0),char(101),char(0),char(9),char(0),char(102),char(0), -char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0),char(20),char(0),char(104),char(0),char(20),char(0),char(105),char(0),char(14),char(0),char(106),char(0), -char(14),char(0),char(107),char(0),char(14),char(0),char(108),char(0),char(8),char(0),char(109),char(0),char(8),char(0),char(110),char(0),char(8),char(0),char(111),char(0), -char(8),char(0),char(112),char(0),char(8),char(0),char(113),char(0),char(8),char(0),char(114),char(0),char(8),char(0),char(115),char(0),char(8),char(0),char(116),char(0), -char(4),char(0),char(117),char(0),char(4),char(0),char(118),char(0),char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0),char(4),char(0),char(121),char(0), -char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(0),char(0),char(37),char(0),char(50),char(0),char(25),char(0),char(9),char(0),char(101),char(0), -char(9),char(0),char(102),char(0),char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0),char(19),char(0),char(104),char(0),char(19),char(0),char(105),char(0), -char(13),char(0),char(106),char(0),char(13),char(0),char(107),char(0),char(13),char(0),char(108),char(0),char(7),char(0),char(109),char(0),char(7),char(0),char(110),char(0), -char(7),char(0),char(111),char(0),char(7),char(0),char(112),char(0),char(7),char(0),char(113),char(0),char(7),char(0),char(114),char(0),char(7),char(0),char(115),char(0), -char(7),char(0),char(116),char(0),char(4),char(0),char(117),char(0),char(4),char(0),char(118),char(0),char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0), -char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(0),char(0),char(37),char(0),char(51),char(0),char(2),char(0), -char(52),char(0),char(124),char(0),char(14),char(0),char(125),char(0),char(53),char(0),char(2),char(0),char(54),char(0),char(124),char(0),char(13),char(0),char(125),char(0), -char(55),char(0),char(21),char(0),char(50),char(0),char(126),char(0),char(17),char(0),char(127),char(0),char(13),char(0),char(-128),char(0),char(13),char(0),char(-127),char(0), -char(13),char(0),char(-126),char(0),char(13),char(0),char(-125),char(0),char(13),char(0),char(125),char(0),char(13),char(0),char(-124),char(0),char(13),char(0),char(-123),char(0), -char(13),char(0),char(-122),char(0),char(13),char(0),char(-121),char(0),char(7),char(0),char(-120),char(0),char(7),char(0),char(-119),char(0),char(7),char(0),char(-118),char(0), -char(7),char(0),char(-117),char(0),char(7),char(0),char(-116),char(0),char(7),char(0),char(-115),char(0),char(7),char(0),char(-114),char(0),char(7),char(0),char(-113),char(0), -char(7),char(0),char(-112),char(0),char(4),char(0),char(-111),char(0),char(56),char(0),char(22),char(0),char(49),char(0),char(126),char(0),char(18),char(0),char(127),char(0), -char(14),char(0),char(-128),char(0),char(14),char(0),char(-127),char(0),char(14),char(0),char(-126),char(0),char(14),char(0),char(-125),char(0),char(14),char(0),char(125),char(0), -char(14),char(0),char(-124),char(0),char(14),char(0),char(-123),char(0),char(14),char(0),char(-122),char(0),char(14),char(0),char(-121),char(0),char(8),char(0),char(-120),char(0), -char(8),char(0),char(-119),char(0),char(8),char(0),char(-118),char(0),char(8),char(0),char(-117),char(0),char(8),char(0),char(-116),char(0),char(8),char(0),char(-115),char(0), -char(8),char(0),char(-114),char(0),char(8),char(0),char(-113),char(0),char(8),char(0),char(-112),char(0),char(4),char(0),char(-111),char(0),char(0),char(0),char(37),char(0), -char(57),char(0),char(2),char(0),char(4),char(0),char(-110),char(0),char(4),char(0),char(-109),char(0),char(58),char(0),char(13),char(0),char(55),char(0),char(-108),char(0), -char(55),char(0),char(-107),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-106),char(0),char(4),char(0),char(-105),char(0),char(4),char(0),char(-104),char(0), -char(4),char(0),char(-103),char(0),char(7),char(0),char(-102),char(0),char(7),char(0),char(-101),char(0),char(4),char(0),char(-100),char(0),char(4),char(0),char(-99),char(0), -char(7),char(0),char(-98),char(0),char(4),char(0),char(-97),char(0),char(59),char(0),char(13),char(0),char(60),char(0),char(-108),char(0),char(60),char(0),char(-107),char(0), -char(0),char(0),char(35),char(0),char(4),char(0),char(-106),char(0),char(4),char(0),char(-105),char(0),char(4),char(0),char(-104),char(0),char(4),char(0),char(-103),char(0), -char(7),char(0),char(-102),char(0),char(7),char(0),char(-101),char(0),char(4),char(0),char(-100),char(0),char(4),char(0),char(-99),char(0),char(7),char(0),char(-98),char(0), -char(4),char(0),char(-97),char(0),char(61),char(0),char(14),char(0),char(56),char(0),char(-108),char(0),char(56),char(0),char(-107),char(0),char(0),char(0),char(35),char(0), -char(4),char(0),char(-106),char(0),char(4),char(0),char(-105),char(0),char(4),char(0),char(-104),char(0),char(4),char(0),char(-103),char(0),char(8),char(0),char(-102),char(0), -char(8),char(0),char(-101),char(0),char(4),char(0),char(-100),char(0),char(4),char(0),char(-99),char(0),char(8),char(0),char(-98),char(0),char(4),char(0),char(-97),char(0), -char(0),char(0),char(-96),char(0),char(62),char(0),char(3),char(0),char(59),char(0),char(-95),char(0),char(13),char(0),char(-94),char(0),char(13),char(0),char(-93),char(0), -char(63),char(0),char(3),char(0),char(61),char(0),char(-95),char(0),char(14),char(0),char(-94),char(0),char(14),char(0),char(-93),char(0),char(64),char(0),char(3),char(0), -char(59),char(0),char(-95),char(0),char(14),char(0),char(-94),char(0),char(14),char(0),char(-93),char(0),char(65),char(0),char(13),char(0),char(59),char(0),char(-95),char(0), -char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),char(4),char(0),char(-89),char(0),char(4),char(0),char(-88),char(0), -char(7),char(0),char(-87),char(0),char(7),char(0),char(-86),char(0),char(7),char(0),char(-85),char(0),char(7),char(0),char(-84),char(0),char(7),char(0),char(-83),char(0), -char(7),char(0),char(-82),char(0),char(7),char(0),char(-81),char(0),char(66),char(0),char(13),char(0),char(59),char(0),char(-95),char(0),char(19),char(0),char(-92),char(0), -char(19),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),char(4),char(0),char(-89),char(0),char(4),char(0),char(-88),char(0),char(7),char(0),char(-87),char(0), -char(7),char(0),char(-86),char(0),char(7),char(0),char(-85),char(0),char(7),char(0),char(-84),char(0),char(7),char(0),char(-83),char(0),char(7),char(0),char(-82),char(0), -char(7),char(0),char(-81),char(0),char(67),char(0),char(14),char(0),char(61),char(0),char(-95),char(0),char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0), -char(4),char(0),char(-90),char(0),char(4),char(0),char(-89),char(0),char(4),char(0),char(-88),char(0),char(8),char(0),char(-87),char(0),char(8),char(0),char(-86),char(0), -char(8),char(0),char(-85),char(0),char(8),char(0),char(-84),char(0),char(8),char(0),char(-83),char(0),char(8),char(0),char(-82),char(0),char(8),char(0),char(-81),char(0), -char(0),char(0),char(-80),char(0),char(68),char(0),char(10),char(0),char(61),char(0),char(-95),char(0),char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0), -char(8),char(0),char(-79),char(0),char(8),char(0),char(-78),char(0),char(8),char(0),char(-77),char(0),char(8),char(0),char(-83),char(0),char(8),char(0),char(-82),char(0), -char(8),char(0),char(-81),char(0),char(8),char(0),char(-76),char(0),char(69),char(0),char(11),char(0),char(59),char(0),char(-95),char(0),char(19),char(0),char(-92),char(0), -char(19),char(0),char(-91),char(0),char(7),char(0),char(-79),char(0),char(7),char(0),char(-78),char(0),char(7),char(0),char(-77),char(0),char(7),char(0),char(-83),char(0), -char(7),char(0),char(-82),char(0),char(7),char(0),char(-81),char(0),char(7),char(0),char(-76),char(0),char(0),char(0),char(21),char(0),char(70),char(0),char(9),char(0), -char(59),char(0),char(-95),char(0),char(19),char(0),char(-92),char(0),char(19),char(0),char(-91),char(0),char(13),char(0),char(-75),char(0),char(13),char(0),char(-74),char(0), -char(13),char(0),char(-73),char(0),char(13),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0),char(71),char(0),char(9),char(0), -char(61),char(0),char(-95),char(0),char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0),char(14),char(0),char(-75),char(0),char(14),char(0),char(-74),char(0), -char(14),char(0),char(-73),char(0),char(14),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0),char(72),char(0),char(5),char(0), -char(70),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),char(7),char(0),char(-67),char(0),char(7),char(0),char(-66),char(0),char(7),char(0),char(-65),char(0), -char(73),char(0),char(5),char(0),char(71),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),char(8),char(0),char(-67),char(0),char(8),char(0),char(-66),char(0), -char(8),char(0),char(-65),char(0),char(74),char(0),char(41),char(0),char(59),char(0),char(-95),char(0),char(19),char(0),char(-92),char(0),char(19),char(0),char(-91),char(0), -char(13),char(0),char(-75),char(0),char(13),char(0),char(-74),char(0),char(13),char(0),char(-64),char(0),char(13),char(0),char(-63),char(0),char(13),char(0),char(-62),char(0), -char(13),char(0),char(-61),char(0),char(13),char(0),char(-60),char(0),char(13),char(0),char(-59),char(0),char(13),char(0),char(-58),char(0),char(13),char(0),char(-57),char(0), -char(13),char(0),char(-56),char(0),char(13),char(0),char(-55),char(0),char(13),char(0),char(-54),char(0),char(0),char(0),char(-53),char(0),char(0),char(0),char(-52),char(0), -char(0),char(0),char(-51),char(0),char(0),char(0),char(-50),char(0),char(0),char(0),char(-49),char(0),char(0),char(0),char(-80),char(0),char(13),char(0),char(-73),char(0), -char(13),char(0),char(-72),char(0),char(13),char(0),char(-48),char(0),char(13),char(0),char(-47),char(0),char(13),char(0),char(-46),char(0),char(13),char(0),char(-45),char(0), -char(13),char(0),char(-44),char(0),char(13),char(0),char(-43),char(0),char(13),char(0),char(-42),char(0),char(13),char(0),char(-41),char(0),char(13),char(0),char(-40),char(0), -char(13),char(0),char(-39),char(0),char(13),char(0),char(-38),char(0),char(0),char(0),char(-37),char(0),char(0),char(0),char(-36),char(0),char(0),char(0),char(-35),char(0), -char(0),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0),char(4),char(0),char(-32),char(0),char(75),char(0),char(41),char(0),char(61),char(0),char(-95),char(0), -char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0),char(14),char(0),char(-75),char(0),char(14),char(0),char(-74),char(0),char(14),char(0),char(-64),char(0), -char(14),char(0),char(-63),char(0),char(14),char(0),char(-62),char(0),char(14),char(0),char(-61),char(0),char(14),char(0),char(-60),char(0),char(14),char(0),char(-59),char(0), -char(14),char(0),char(-58),char(0),char(14),char(0),char(-57),char(0),char(14),char(0),char(-56),char(0),char(14),char(0),char(-55),char(0),char(14),char(0),char(-54),char(0), -char(0),char(0),char(-53),char(0),char(0),char(0),char(-52),char(0),char(0),char(0),char(-51),char(0),char(0),char(0),char(-50),char(0),char(0),char(0),char(-49),char(0), -char(0),char(0),char(-80),char(0),char(14),char(0),char(-73),char(0),char(14),char(0),char(-72),char(0),char(14),char(0),char(-48),char(0),char(14),char(0),char(-47),char(0), -char(14),char(0),char(-46),char(0),char(14),char(0),char(-45),char(0),char(14),char(0),char(-44),char(0),char(14),char(0),char(-43),char(0),char(14),char(0),char(-42),char(0), -char(14),char(0),char(-41),char(0),char(14),char(0),char(-40),char(0),char(14),char(0),char(-39),char(0),char(14),char(0),char(-38),char(0),char(0),char(0),char(-37),char(0), -char(0),char(0),char(-36),char(0),char(0),char(0),char(-35),char(0),char(0),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0),char(4),char(0),char(-32),char(0), -char(76),char(0),char(9),char(0),char(59),char(0),char(-95),char(0),char(19),char(0),char(-92),char(0),char(19),char(0),char(-91),char(0),char(7),char(0),char(-75),char(0), -char(7),char(0),char(-74),char(0),char(7),char(0),char(-73),char(0),char(7),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0), -char(77),char(0),char(9),char(0),char(61),char(0),char(-95),char(0),char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0),char(8),char(0),char(-75),char(0), -char(8),char(0),char(-74),char(0),char(8),char(0),char(-73),char(0),char(8),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0), -char(78),char(0),char(5),char(0),char(58),char(0),char(-95),char(0),char(13),char(0),char(-31),char(0),char(13),char(0),char(-30),char(0),char(7),char(0),char(-29),char(0), -char(0),char(0),char(37),char(0),char(79),char(0),char(4),char(0),char(61),char(0),char(-95),char(0),char(14),char(0),char(-31),char(0),char(14),char(0),char(-30),char(0), -char(8),char(0),char(-29),char(0),char(52),char(0),char(22),char(0),char(8),char(0),char(-28),char(0),char(8),char(0),char(-76),char(0),char(8),char(0),char(111),char(0), -char(8),char(0),char(-27),char(0),char(8),char(0),char(113),char(0),char(8),char(0),char(-26),char(0),char(8),char(0),char(-25),char(0),char(8),char(0),char(-24),char(0), -char(8),char(0),char(-23),char(0),char(8),char(0),char(-22),char(0),char(8),char(0),char(-21),char(0),char(8),char(0),char(-20),char(0),char(8),char(0),char(-19),char(0), -char(8),char(0),char(-18),char(0),char(8),char(0),char(-17),char(0),char(8),char(0),char(-16),char(0),char(4),char(0),char(-15),char(0),char(4),char(0),char(-14),char(0), -char(4),char(0),char(-13),char(0),char(4),char(0),char(-12),char(0),char(4),char(0),char(-11),char(0),char(0),char(0),char(37),char(0),char(54),char(0),char(22),char(0), -char(7),char(0),char(-28),char(0),char(7),char(0),char(-76),char(0),char(7),char(0),char(111),char(0),char(7),char(0),char(-27),char(0),char(7),char(0),char(113),char(0), -char(7),char(0),char(-26),char(0),char(7),char(0),char(-25),char(0),char(7),char(0),char(-24),char(0),char(7),char(0),char(-23),char(0),char(7),char(0),char(-22),char(0), -char(7),char(0),char(-21),char(0),char(7),char(0),char(-20),char(0),char(7),char(0),char(-19),char(0),char(7),char(0),char(-18),char(0),char(7),char(0),char(-17),char(0), -char(7),char(0),char(-16),char(0),char(4),char(0),char(-15),char(0),char(4),char(0),char(-14),char(0),char(4),char(0),char(-13),char(0),char(4),char(0),char(-12),char(0), -char(4),char(0),char(-11),char(0),char(0),char(0),char(37),char(0),char(80),char(0),char(4),char(0),char(7),char(0),char(-10),char(0),char(7),char(0),char(-9),char(0), -char(7),char(0),char(-8),char(0),char(4),char(0),char(79),char(0),char(81),char(0),char(10),char(0),char(80),char(0),char(-7),char(0),char(13),char(0),char(-6),char(0), -char(13),char(0),char(-5),char(0),char(13),char(0),char(-4),char(0),char(13),char(0),char(-3),char(0),char(13),char(0),char(-2),char(0),char(7),char(0),char(-120),char(0), -char(7),char(0),char(-1),char(0),char(4),char(0),char(0),char(1),char(4),char(0),char(53),char(0),char(82),char(0),char(4),char(0),char(80),char(0),char(-7),char(0), -char(4),char(0),char(1),char(1),char(7),char(0),char(2),char(1),char(4),char(0),char(3),char(1),char(83),char(0),char(4),char(0),char(13),char(0),char(-2),char(0), -char(80),char(0),char(-7),char(0),char(4),char(0),char(4),char(1),char(7),char(0),char(5),char(1),char(84),char(0),char(7),char(0),char(13),char(0),char(6),char(1), -char(80),char(0),char(-7),char(0),char(4),char(0),char(7),char(1),char(7),char(0),char(8),char(1),char(7),char(0),char(9),char(1),char(7),char(0),char(10),char(1), -char(4),char(0),char(53),char(0),char(85),char(0),char(6),char(0),char(17),char(0),char(11),char(1),char(13),char(0),char(9),char(1),char(13),char(0),char(12),char(1), -char(60),char(0),char(13),char(1),char(4),char(0),char(14),char(1),char(7),char(0),char(10),char(1),char(86),char(0),char(26),char(0),char(4),char(0),char(15),char(1), -char(7),char(0),char(16),char(1),char(7),char(0),char(-76),char(0),char(7),char(0),char(17),char(1),char(7),char(0),char(18),char(1),char(7),char(0),char(19),char(1), -char(7),char(0),char(20),char(1),char(7),char(0),char(21),char(1),char(7),char(0),char(22),char(1),char(7),char(0),char(23),char(1),char(7),char(0),char(24),char(1), -char(7),char(0),char(25),char(1),char(7),char(0),char(26),char(1),char(7),char(0),char(27),char(1),char(7),char(0),char(28),char(1),char(7),char(0),char(29),char(1), -char(7),char(0),char(30),char(1),char(7),char(0),char(31),char(1),char(7),char(0),char(32),char(1),char(7),char(0),char(33),char(1),char(7),char(0),char(34),char(1), -char(4),char(0),char(35),char(1),char(4),char(0),char(36),char(1),char(4),char(0),char(37),char(1),char(4),char(0),char(38),char(1),char(4),char(0),char(118),char(0), -char(87),char(0),char(12),char(0),char(17),char(0),char(39),char(1),char(17),char(0),char(40),char(1),char(17),char(0),char(41),char(1),char(13),char(0),char(42),char(1), -char(13),char(0),char(43),char(1),char(7),char(0),char(44),char(1),char(4),char(0),char(45),char(1),char(4),char(0),char(46),char(1),char(4),char(0),char(47),char(1), -char(4),char(0),char(48),char(1),char(7),char(0),char(8),char(1),char(4),char(0),char(53),char(0),char(88),char(0),char(27),char(0),char(19),char(0),char(49),char(1), -char(17),char(0),char(50),char(1),char(17),char(0),char(51),char(1),char(13),char(0),char(42),char(1),char(13),char(0),char(52),char(1),char(13),char(0),char(53),char(1), -char(13),char(0),char(54),char(1),char(13),char(0),char(55),char(1),char(13),char(0),char(56),char(1),char(4),char(0),char(57),char(1),char(7),char(0),char(58),char(1), -char(4),char(0),char(59),char(1),char(4),char(0),char(60),char(1),char(4),char(0),char(61),char(1),char(7),char(0),char(62),char(1),char(7),char(0),char(63),char(1), -char(4),char(0),char(64),char(1),char(4),char(0),char(65),char(1),char(7),char(0),char(66),char(1),char(7),char(0),char(67),char(1),char(7),char(0),char(68),char(1), -char(7),char(0),char(69),char(1),char(7),char(0),char(70),char(1),char(7),char(0),char(71),char(1),char(4),char(0),char(72),char(1),char(4),char(0),char(73),char(1), -char(4),char(0),char(74),char(1),char(89),char(0),char(12),char(0),char(9),char(0),char(75),char(1),char(9),char(0),char(76),char(1),char(13),char(0),char(77),char(1), -char(7),char(0),char(78),char(1),char(7),char(0),char(-24),char(0),char(7),char(0),char(79),char(1),char(4),char(0),char(80),char(1),char(13),char(0),char(81),char(1), -char(4),char(0),char(82),char(1),char(4),char(0),char(83),char(1),char(4),char(0),char(84),char(1),char(4),char(0),char(53),char(0),char(90),char(0),char(19),char(0), -char(50),char(0),char(126),char(0),char(87),char(0),char(85),char(1),char(80),char(0),char(86),char(1),char(81),char(0),char(87),char(1),char(82),char(0),char(88),char(1), -char(83),char(0),char(89),char(1),char(84),char(0),char(90),char(1),char(85),char(0),char(91),char(1),char(88),char(0),char(92),char(1),char(89),char(0),char(93),char(1), -char(4),char(0),char(94),char(1),char(4),char(0),char(60),char(1),char(4),char(0),char(95),char(1),char(4),char(0),char(96),char(1),char(4),char(0),char(97),char(1), -char(4),char(0),char(98),char(1),char(4),char(0),char(99),char(1),char(4),char(0),char(100),char(1),char(86),char(0),char(101),char(1),char(91),char(0),char(17),char(0), -char(16),char(0),char(102),char(1),char(14),char(0),char(103),char(1),char(14),char(0),char(104),char(1),char(14),char(0),char(105),char(1),char(14),char(0),char(106),char(1), -char(0),char(0),char(107),char(1),char(0),char(0),char(108),char(1),char(49),char(0),char(109),char(1),char(14),char(0),char(110),char(1),char(8),char(0),char(111),char(1), -char(4),char(0),char(112),char(1),char(4),char(0),char(84),char(1),char(4),char(0),char(113),char(1),char(4),char(0),char(114),char(1),char(8),char(0),char(115),char(1), -char(8),char(0),char(116),char(1),char(8),char(0),char(117),char(1),char(92),char(0),char(17),char(0),char(15),char(0),char(102),char(1),char(13),char(0),char(103),char(1), -char(13),char(0),char(104),char(1),char(13),char(0),char(105),char(1),char(13),char(0),char(106),char(1),char(0),char(0),char(107),char(1),char(0),char(0),char(108),char(1), -char(50),char(0),char(109),char(1),char(13),char(0),char(110),char(1),char(4),char(0),char(113),char(1),char(7),char(0),char(111),char(1),char(4),char(0),char(112),char(1), -char(4),char(0),char(84),char(1),char(7),char(0),char(115),char(1),char(7),char(0),char(116),char(1),char(7),char(0),char(117),char(1),char(4),char(0),char(114),char(1), -char(93),char(0),char(8),char(0),char(0),char(0),char(118),char(1),char(91),char(0),char(88),char(1),char(49),char(0),char(119),char(1),char(20),char(0),char(120),char(1), -char(14),char(0),char(121),char(1),char(4),char(0),char(95),char(1),char(8),char(0),char(122),char(1),char(0),char(0),char(37),char(0),char(94),char(0),char(7),char(0), -char(0),char(0),char(118),char(1),char(92),char(0),char(88),char(1),char(50),char(0),char(119),char(1),char(19),char(0),char(120),char(1),char(13),char(0),char(121),char(1), -char(7),char(0),char(122),char(1),char(4),char(0),char(95),char(1),}; -int sBulletDNAlen= sizeof(sBulletDNAstr); - -char sBulletDNAstr64[]= { -char(83),char(68),char(78),char(65),char(78),char(65),char(77),char(69),char(123),char(1),char(0),char(0),char(109),char(95),char(115),char(105),char(122),char(101),char(0),char(109), -char(95),char(99),char(97),char(112),char(97),char(99),char(105),char(116),char(121),char(0),char(42),char(109),char(95),char(100),char(97),char(116),char(97),char(0),char(109),char(95), -char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(115),char(0),char(109),char(95),char(99),char(111), -char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(115),char(0),char(109),char(95),char(99),char(111),char(110), -char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(115),char(0),char(42),char(102),char(105),char(114),char(115),char(116),char(0),char(42),char(108),char(97),char(115), -char(116),char(0),char(109),char(95),char(102),char(108),char(111),char(97),char(116),char(115),char(91),char(52),char(93),char(0),char(109),char(95),char(101),char(108),char(91),char(51), -char(93),char(0),char(109),char(95),char(98),char(97),char(115),char(105),char(115),char(0),char(109),char(95),char(111),char(114),char(105),char(103),char(105),char(110),char(0),char(109), -char(95),char(114),char(111),char(111),char(116),char(78),char(111),char(100),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(115),char(117),char(98), -char(116),char(114),char(101),char(101),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100), -char(65),char(97),char(98),char(98),char(77),char(105),char(110),char(91),char(51),char(93),char(0),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122), -char(101),char(100),char(65),char(97),char(98),char(98),char(77),char(97),char(120),char(91),char(51),char(93),char(0),char(109),char(95),char(97),char(97),char(98),char(98),char(77), -char(105),char(110),char(79),char(114),char(103),char(0),char(109),char(95),char(97),char(97),char(98),char(98),char(77),char(97),char(120),char(79),char(114),char(103),char(0),char(109), -char(95),char(101),char(115),char(99),char(97),char(112),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(115),char(117),char(98),char(80),char(97), -char(114),char(116),char(0),char(109),char(95),char(116),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109), -char(95),char(112),char(97),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(101),char(115),char(99),char(97),char(112),char(101),char(73),char(110),char(100),char(101), -char(120),char(79),char(114),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(98), -char(118),char(104),char(65),char(97),char(98),char(98),char(77),char(105),char(110),char(0),char(109),char(95),char(98),char(118),char(104),char(65),char(97),char(98),char(98),char(77), -char(97),char(120),char(0),char(109),char(95),char(98),char(118),char(104),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(97),char(116),char(105),char(111),char(110), -char(0),char(109),char(95),char(99),char(117),char(114),char(78),char(111),char(100),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(117),char(115), -char(101),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(97),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(110),char(117),char(109),char(67), -char(111),char(110),char(116),char(105),char(103),char(117),char(111),char(117),char(115),char(76),char(101),char(97),char(102),char(78),char(111),char(100),char(101),char(115),char(0),char(109), -char(95),char(110),char(117),char(109),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(67),char(111),char(110),char(116),char(105),char(103),char(117), -char(111),char(117),char(115),char(78),char(111),char(100),char(101),char(115),char(0),char(42),char(109),char(95),char(99),char(111),char(110),char(116),char(105),char(103),char(117),char(111), -char(117),char(115),char(78),char(111),char(100),char(101),char(115),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105), -char(122),char(101),char(100),char(67),char(111),char(110),char(116),char(105),char(103),char(117),char(111),char(117),char(115),char(78),char(111),char(100),char(101),char(115),char(80),char(116), -char(114),char(0),char(42),char(109),char(95),char(115),char(117),char(98),char(84),char(114),char(101),char(101),char(73),char(110),char(102),char(111),char(80),char(116),char(114),char(0), -char(109),char(95),char(116),char(114),char(97),char(118),char(101),char(114),char(115),char(97),char(108),char(77),char(111),char(100),char(101),char(0),char(109),char(95),char(110),char(117), -char(109),char(83),char(117),char(98),char(116),char(114),char(101),char(101),char(72),char(101),char(97),char(100),char(101),char(114),char(115),char(0),char(42),char(109),char(95),char(110), -char(97),char(109),char(101),char(0),char(109),char(95),char(115),char(104),char(97),char(112),char(101),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(112),char(97), -char(100),char(100),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110), -char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(83),char(99),char(97), -char(108),char(105),char(110),char(103),char(0),char(109),char(95),char(112),char(108),char(97),char(110),char(101),char(78),char(111),char(114),char(109),char(97),char(108),char(0),char(109), -char(95),char(112),char(108),char(97),char(110),char(101),char(67),char(111),char(110),char(115),char(116),char(97),char(110),char(116),char(0),char(109),char(95),char(105),char(109),char(112), -char(108),char(105),char(99),char(105),char(116),char(83),char(104),char(97),char(112),char(101),char(68),char(105),char(109),char(101),char(110),char(115),char(105),char(111),char(110),char(115), -char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(77),char(97),char(114),char(103),char(105),char(110),char(0),char(109), -char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(0),char(109),char(95),char(112),char(111),char(115),char(0),char(109),char(95),char(114),char(97),char(100), -char(105),char(117),char(115),char(0),char(109),char(95),char(99),char(111),char(110),char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114),char(110),char(97),char(108), -char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(42),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(80),char(111), -char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(114),char(114),char(97),char(121),char(80),char(116),char(114),char(0),char(109),char(95),char(108),char(111),char(99), -char(97),char(108),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(114),char(114),char(97),char(121),char(83),char(105),char(122),char(101),char(0), -char(109),char(95),char(118),char(97),char(108),char(117),char(101),char(0),char(109),char(95),char(112),char(97),char(100),char(91),char(50),char(93),char(0),char(109),char(95),char(118), -char(97),char(108),char(117),char(101),char(115),char(91),char(51),char(93),char(0),char(109),char(95),char(112),char(97),char(100),char(0),char(42),char(109),char(95),char(118),char(101), -char(114),char(116),char(105),char(99),char(101),char(115),char(51),char(102),char(0),char(42),char(109),char(95),char(118),char(101),char(114),char(116),char(105),char(99),char(101),char(115), -char(51),char(100),char(0),char(42),char(109),char(95),char(105),char(110),char(100),char(105),char(99),char(101),char(115),char(51),char(50),char(0),char(42),char(109),char(95),char(51), -char(105),char(110),char(100),char(105),char(99),char(101),char(115),char(49),char(54),char(0),char(42),char(109),char(95),char(51),char(105),char(110),char(100),char(105),char(99),char(101), -char(115),char(56),char(0),char(42),char(109),char(95),char(105),char(110),char(100),char(105),char(99),char(101),char(115),char(49),char(54),char(0),char(109),char(95),char(110),char(117), -char(109),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(86),char(101),char(114),char(116), -char(105),char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(109),char(101),char(115),char(104),char(80),char(97),char(114),char(116),char(115),char(80),char(116),char(114), -char(0),char(109),char(95),char(115),char(99),char(97),char(108),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(101),char(115),char(104), -char(80),char(97),char(114),char(116),char(115),char(0),char(109),char(95),char(109),char(101),char(115),char(104),char(73),char(110),char(116),char(101),char(114),char(102),char(97),char(99), -char(101),char(0),char(42),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(70),char(108),char(111),char(97),char(116),char(66), -char(118),char(104),char(0),char(42),char(109),char(95),char(113),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(68),char(111),char(117),char(98),char(108), -char(101),char(66),char(118),char(104),char(0),char(42),char(109),char(95),char(116),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111), -char(77),char(97),char(112),char(0),char(109),char(95),char(112),char(97),char(100),char(51),char(91),char(52),char(93),char(0),char(109),char(95),char(116),char(114),char(105),char(109), -char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(116),char(114),char(97),char(110),char(115), -char(102),char(111),char(114),char(109),char(0),char(42),char(109),char(95),char(99),char(104),char(105),char(108),char(100),char(83),char(104),char(97),char(112),char(101),char(0),char(109), -char(95),char(99),char(104),char(105),char(108),char(100),char(83),char(104),char(97),char(112),char(101),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(99),char(104), -char(105),char(108),char(100),char(77),char(97),char(114),char(103),char(105),char(110),char(0),char(42),char(109),char(95),char(99),char(104),char(105),char(108),char(100),char(83),char(104), -char(97),char(112),char(101),char(80),char(116),char(114),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(104),char(105),char(108),char(100),char(83),char(104),char(97), -char(112),char(101),char(115),char(0),char(109),char(95),char(117),char(112),char(65),char(120),char(105),char(115),char(0),char(109),char(95),char(117),char(112),char(73),char(110),char(100), -char(101),char(120),char(0),char(109),char(95),char(102),char(108),char(97),char(103),char(115),char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(86),char(48),char(86), -char(49),char(65),char(110),char(103),char(108),char(101),char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(86),char(49),char(86),char(50),char(65),char(110),char(103), -char(108),char(101),char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(86),char(50),char(86),char(48),char(65),char(110),char(103),char(108),char(101),char(0),char(42), -char(109),char(95),char(104),char(97),char(115),char(104),char(84),char(97),char(98),char(108),char(101),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(110),char(101), -char(120),char(116),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(118),char(97),char(108),char(117),char(101),char(65),char(114),char(114),char(97),char(121),char(80), -char(116),char(114),char(0),char(42),char(109),char(95),char(107),char(101),char(121),char(65),char(114),char(114),char(97),char(121),char(80),char(116),char(114),char(0),char(109),char(95), -char(99),char(111),char(110),char(118),char(101),char(120),char(69),char(112),char(115),char(105),char(108),char(111),char(110),char(0),char(109),char(95),char(112),char(108),char(97),char(110), -char(97),char(114),char(69),char(112),char(115),char(105),char(108),char(111),char(110),char(0),char(109),char(95),char(101),char(113),char(117),char(97),char(108),char(86),char(101),char(114), -char(116),char(101),char(120),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(101),char(100),char(103),char(101),char(68), -char(105),char(115),char(116),char(97),char(110),char(99),char(101),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(122), -char(101),char(114),char(111),char(65),char(114),char(101),char(97),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(110), -char(101),char(120),char(116),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(104),char(97),char(115),char(104),char(84),char(97),char(98),char(108),char(101),char(83), -char(105),char(122),char(101),char(0),char(109),char(95),char(110),char(117),char(109),char(86),char(97),char(108),char(117),char(101),char(115),char(0),char(109),char(95),char(110),char(117), -char(109),char(75),char(101),char(121),char(115),char(0),char(109),char(95),char(103),char(105),char(109),char(112),char(97),char(99),char(116),char(83),char(117),char(98),char(84),char(121), -char(112),char(101),char(0),char(42),char(109),char(95),char(117),char(110),char(115),char(99),char(97),char(108),char(101),char(100),char(80),char(111),char(105),char(110),char(116),char(115), -char(70),char(108),char(111),char(97),char(116),char(80),char(116),char(114),char(0),char(42),char(109),char(95),char(117),char(110),char(115),char(99),char(97),char(108),char(101),char(100), -char(80),char(111),char(105),char(110),char(116),char(115),char(68),char(111),char(117),char(98),char(108),char(101),char(80),char(116),char(114),char(0),char(109),char(95),char(110),char(117), -char(109),char(85),char(110),char(115),char(99),char(97),char(108),char(101),char(100),char(80),char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(112),char(97), -char(100),char(100),char(105),char(110),char(103),char(51),char(91),char(52),char(93),char(0),char(42),char(109),char(95),char(98),char(114),char(111),char(97),char(100),char(112),char(104), -char(97),char(115),char(101),char(72),char(97),char(110),char(100),char(108),char(101),char(0),char(42),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(115),char(105), -char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(0),char(42),char(109),char(95),char(114),char(111),char(111),char(116),char(67),char(111),char(108),char(108),char(105), -char(115),char(105),char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(0),char(109),char(95),char(119),char(111),char(114),char(108),char(100),char(84),char(114),char(97), -char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105), -char(111),char(110),char(87),char(111),char(114),char(108),char(100),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(105), -char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105),char(111),char(110),char(76),char(105),char(110),char(101),char(97),char(114),char(86),char(101), -char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(105),char(110),char(116),char(101),char(114),char(112),char(111),char(108),char(97),char(116),char(105), -char(111),char(110),char(65),char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95), -char(97),char(110),char(105),char(115),char(111),char(116),char(114),char(111),char(112),char(105),char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0), -char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(99),char(116),char(80),char(114),char(111),char(99),char(101),char(115),char(115),char(105),char(110),char(103),char(84), -char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(100),char(101),char(97),char(99),char(116),char(105),char(118),char(97),char(116), -char(105),char(111),char(110),char(84),char(105),char(109),char(101),char(0),char(109),char(95),char(102),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109), -char(95),char(114),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(114), -char(101),char(115),char(116),char(105),char(116),char(117),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(104),char(105),char(116),char(70),char(114),char(97),char(99), -char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(99),char(100),char(83),char(119),char(101),char(112),char(116),char(83),char(112),char(104),char(101),char(114), -char(101),char(82),char(97),char(100),char(105),char(117),char(115),char(0),char(109),char(95),char(99),char(99),char(100),char(77),char(111),char(116),char(105),char(111),char(110),char(84), -char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(104),char(97),char(115),char(65),char(110),char(105),char(115),char(111),char(116), -char(114),char(111),char(112),char(105),char(99),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(99),char(111),char(108),char(108), -char(105),char(115),char(105),char(111),char(110),char(70),char(108),char(97),char(103),char(115),char(0),char(109),char(95),char(105),char(115),char(108),char(97),char(110),char(100),char(84), -char(97),char(103),char(49),char(0),char(109),char(95),char(99),char(111),char(109),char(112),char(97),char(110),char(105),char(111),char(110),char(73),char(100),char(0),char(109),char(95), -char(97),char(99),char(116),char(105),char(118),char(97),char(116),char(105),char(111),char(110),char(83),char(116),char(97),char(116),char(101),char(49),char(0),char(109),char(95),char(105), -char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(84),char(121),char(112),char(101),char(0),char(109),char(95),char(99),char(104),char(101),char(99),char(107),char(67), -char(111),char(108),char(108),char(105),char(100),char(101),char(87),char(105),char(116),char(104),char(0),char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(73), -char(110),char(102),char(111),char(0),char(109),char(95),char(103),char(114),char(97),char(118),char(105),char(116),char(121),char(0),char(109),char(95),char(99),char(111),char(108),char(108), -char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(105),char(110), -char(118),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(84),char(101),char(110),char(115),char(111),char(114),char(87),char(111),char(114),char(108),char(100),char(0), -char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97), -char(110),char(103),char(117),char(108),char(97),char(114),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103), -char(117),char(108),char(97),char(114),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(70), -char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(103),char(114),char(97),char(118),char(105),char(116),char(121),char(95),char(97),char(99),char(99),char(101), -char(108),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(105),char(110),char(118),char(73),char(110),char(101),char(114),char(116),char(105), -char(97),char(76),char(111),char(99),char(97),char(108),char(0),char(109),char(95),char(116),char(111),char(116),char(97),char(108),char(70),char(111),char(114),char(99),char(101),char(0), -char(109),char(95),char(116),char(111),char(116),char(97),char(108),char(84),char(111),char(114),char(113),char(117),char(101),char(0),char(109),char(95),char(105),char(110),char(118),char(101), -char(114),char(115),char(101),char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112), -char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103), -char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103), -char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(76), -char(105),char(110),char(101),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108), -char(100),char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103), -char(117),char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100), -char(83),char(113),char(114),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110),char(97),char(108),char(65),char(110),char(103),char(117), -char(108),char(97),char(114),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(108), -char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(101),char(101),char(112),char(105),char(110),char(103),char(84),char(104),char(114),char(101),char(115),char(104),char(111), -char(108),char(100),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(108),char(101),char(101),char(112),char(105),char(110),char(103), -char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(97),char(100),char(100),char(105),char(116),char(105),char(111),char(110), -char(97),char(108),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(117),char(109),char(67),char(111),char(110),char(115),char(116), -char(114),char(97),char(105),char(110),char(116),char(82),char(111),char(119),char(115),char(0),char(110),char(117),char(98),char(0),char(42),char(109),char(95),char(114),char(98),char(65), -char(0),char(42),char(109),char(95),char(114),char(98),char(66),char(0),char(109),char(95),char(111),char(98),char(106),char(101),char(99),char(116),char(84),char(121),char(112),char(101), -char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(84),char(121),char(112), -char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(100), -char(0),char(109),char(95),char(110),char(101),char(101),char(100),char(115),char(70),char(101),char(101),char(100),char(98),char(97),char(99),char(107),char(0),char(109),char(95),char(97), -char(112),char(112),char(108),char(105),char(101),char(100),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(100),char(98),char(103),char(68), -char(114),char(97),char(119),char(83),char(105),char(122),char(101),char(0),char(109),char(95),char(100),char(105),char(115),char(97),char(98),char(108),char(101),char(67),char(111),char(108), -char(108),char(105),char(115),char(105),char(111),char(110),char(115),char(66),char(101),char(116),char(119),char(101),char(101),char(110),char(76),char(105),char(110),char(107),char(101),char(100), -char(66),char(111),char(100),char(105),char(101),char(115),char(0),char(109),char(95),char(111),char(118),char(101),char(114),char(114),char(105),char(100),char(101),char(78),char(117),char(109), -char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(98), -char(114),char(101),char(97),char(107),char(105),char(110),char(103),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(84),char(104),char(114),char(101),char(115),char(104), -char(111),char(108),char(100),char(0),char(109),char(95),char(105),char(115),char(69),char(110),char(97),char(98),char(108),char(101),char(100),char(0),char(112),char(97),char(100),char(100), -char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(116),char(121),char(112),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97), -char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(112),char(105),char(118),char(111),char(116),char(73),char(110),char(65),char(0),char(109), -char(95),char(112),char(105),char(118),char(111),char(116),char(73),char(110),char(66),char(0),char(109),char(95),char(114),char(98),char(65),char(70),char(114),char(97),char(109),char(101), -char(0),char(109),char(95),char(114),char(98),char(66),char(70),char(114),char(97),char(109),char(101),char(0),char(109),char(95),char(117),char(115),char(101),char(82),char(101),char(102), -char(101),char(114),char(101),char(110),char(99),char(101),char(70),char(114),char(97),char(109),char(101),char(65),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108), -char(97),char(114),char(79),char(110),char(108),char(121),char(0),char(109),char(95),char(101),char(110),char(97),char(98),char(108),char(101),char(65),char(110),char(103),char(117),char(108), -char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(0),char(109),char(95),char(109),char(111),char(116),char(111),char(114),char(84),char(97),char(114),char(103),char(101), -char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(109),char(97),char(120),char(77),char(111),char(116),char(111),char(114), -char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(108),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105),char(116), -char(0),char(109),char(95),char(117),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105),char(116),char(0),char(109),char(95),char(108),char(105),char(109),char(105), -char(116),char(83),char(111),char(102),char(116),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(98),char(105),char(97),char(115),char(70),char(97),char(99),char(116), -char(111),char(114),char(0),char(109),char(95),char(114),char(101),char(108),char(97),char(120),char(97),char(116),char(105),char(111),char(110),char(70),char(97),char(99),char(116),char(111), -char(114),char(0),char(109),char(95),char(112),char(97),char(100),char(100),char(105),char(110),char(103),char(49),char(91),char(52),char(93),char(0),char(109),char(95),char(115),char(119), -char(105),char(110),char(103),char(83),char(112),char(97),char(110),char(49),char(0),char(109),char(95),char(115),char(119),char(105),char(110),char(103),char(83),char(112),char(97),char(110), -char(50),char(0),char(109),char(95),char(116),char(119),char(105),char(115),char(116),char(83),char(112),char(97),char(110),char(0),char(109),char(95),char(100),char(97),char(109),char(112), -char(105),char(110),char(103),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109), -char(105),char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105), -char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(85),char(112),char(112),char(101),char(114),char(76),char(105),char(109),char(105), -char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(76),char(111),char(119),char(101),char(114),char(76),char(105),char(109),char(105), -char(116),char(0),char(109),char(95),char(117),char(115),char(101),char(76),char(105),char(110),char(101),char(97),char(114),char(82),char(101),char(102),char(101),char(114),char(101),char(110), -char(99),char(101),char(70),char(114),char(97),char(109),char(101),char(65),char(0),char(109),char(95),char(117),char(115),char(101),char(79),char(102),char(102),char(115),char(101),char(116), -char(70),char(111),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(114),char(97),char(109),char(101),char(0),char(109), -char(95),char(54),char(100),char(111),char(102),char(68),char(97),char(116),char(97),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(69),char(110), -char(97),char(98),char(108),char(101),char(100),char(91),char(54),char(93),char(0),char(109),char(95),char(101),char(113),char(117),char(105),char(108),char(105),char(98),char(114),char(105), -char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103),char(83), -char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(91),char(54),char(93),char(0),char(109),char(95),char(115),char(112),char(114),char(105),char(110),char(103), -char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(91),char(54),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(66), -char(111),char(117),char(110),char(99),char(101),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82), -char(80),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95), -char(108),char(105),char(110),char(101),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(108),char(105),char(110), -char(101),char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114), -char(84),char(97),char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(108),char(105),char(110), -char(101),char(97),char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(108), -char(105),char(110),char(101),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0),char(109),char(95),char(108), -char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115), -char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105), -char(110),char(103),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105),char(98),char(114),char(105), -char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(69),char(110),char(97),char(98), -char(108),char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83), -char(101),char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97), -char(114),char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91),char(52),char(93),char(0),char(109),char(95),char(108), -char(105),char(110),char(101),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115), -char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(108),char(105),char(110),char(101),char(97),char(114),char(83), -char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91), -char(52),char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(66),char(111),char(117),char(110),char(99),char(101),char(0),char(109), -char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110), -char(103),char(117),char(108),char(97),char(114),char(83),char(116),char(111),char(112),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108), -char(97),char(114),char(77),char(111),char(116),char(111),char(114),char(69),char(82),char(80),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114), -char(77),char(111),char(116),char(111),char(114),char(67),char(70),char(77),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(84),char(97), -char(114),char(103),char(101),char(116),char(86),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108), -char(97),char(114),char(77),char(97),char(120),char(77),char(111),char(116),char(111),char(114),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(97),char(110), -char(103),char(117),char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(84),char(97),char(114),char(103),char(101),char(116),char(0),char(109),char(95),char(97), -char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115), -char(115),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109), -char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(113),char(117),char(105),char(108),char(105), -char(98),char(114),char(105),char(117),char(109),char(80),char(111),char(105),char(110),char(116),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114), -char(69),char(110),char(97),char(98),char(108),char(101),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95),char(97),char(110),char(103), -char(117),char(108),char(97),char(114),char(83),char(101),char(114),char(118),char(111),char(77),char(111),char(116),char(111),char(114),char(91),char(52),char(93),char(0),char(109),char(95), -char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(69),char(110),char(97),char(98),char(108),char(101),char(83),char(112),char(114),char(105),char(110),char(103),char(91), -char(52),char(93),char(0),char(109),char(95),char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(83),char(116), -char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95), -char(97),char(110),char(103),char(117),char(108),char(97),char(114),char(83),char(112),char(114),char(105),char(110),char(103),char(68),char(97),char(109),char(112),char(105),char(110),char(103), -char(76),char(105),char(109),char(105),char(116),char(101),char(100),char(91),char(52),char(93),char(0),char(109),char(95),char(114),char(111),char(116),char(97),char(116),char(101),char(79), -char(114),char(100),char(101),char(114),char(0),char(109),char(95),char(97),char(120),char(105),char(115),char(73),char(110),char(65),char(0),char(109),char(95),char(97),char(120),char(105), -char(115),char(73),char(110),char(66),char(0),char(109),char(95),char(114),char(97),char(116),char(105),char(111),char(0),char(109),char(95),char(116),char(97),char(117),char(0),char(109), -char(95),char(116),char(105),char(109),char(101),char(83),char(116),char(101),char(112),char(0),char(109),char(95),char(109),char(97),char(120),char(69),char(114),char(114),char(111),char(114), -char(82),char(101),char(100),char(117),char(99),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(115),char(111),char(114),char(0),char(109),char(95),char(101),char(114), -char(112),char(0),char(109),char(95),char(101),char(114),char(112),char(50),char(0),char(109),char(95),char(103),char(108),char(111),char(98),char(97),char(108),char(67),char(102),char(109), -char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(80),char(101),char(110),char(101),char(116), -char(114),char(97),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(115),char(112), -char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(84),char(117),char(114),char(110),char(69),char(114),char(112),char(0),char(109),char(95), -char(108),char(105),char(110),char(101),char(97),char(114),char(83),char(108),char(111),char(112),char(0),char(109),char(95),char(119),char(97),char(114),char(109),char(115),char(116),char(97), -char(114),char(116),char(105),char(110),char(103),char(70),char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(109),char(97),char(120),char(71),char(121),char(114), -char(111),char(115),char(99),char(111),char(112),char(105),char(99),char(70),char(111),char(114),char(99),char(101),char(0),char(109),char(95),char(115),char(105),char(110),char(103),char(108), -char(101),char(65),char(120),char(105),char(115),char(82),char(111),char(108),char(108),char(105),char(110),char(103),char(70),char(114),char(105),char(99),char(116),char(105),char(111),char(110), -char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(110),char(117),char(109),char(73),char(116),char(101),char(114),char(97), -char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(115),char(111),char(108),char(118),char(101),char(114),char(77),char(111),char(100),char(101),char(0),char(109), -char(95),char(114),char(101),char(115),char(116),char(105),char(110),char(103),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(82),char(101),char(115),char(116),char(105), -char(116),char(117),char(116),char(105),char(111),char(110),char(84),char(104),char(114),char(101),char(115),char(104),char(111),char(108),char(100),char(0),char(109),char(95),char(109),char(105), -char(110),char(105),char(109),char(117),char(109),char(83),char(111),char(108),char(118),char(101),char(114),char(66),char(97),char(116),char(99),char(104),char(83),char(105),char(122),char(101), -char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(108),char(105), -char(110),char(101),char(97),char(114),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97),char(110),char(103),char(117), -char(108),char(97),char(114),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(118),char(111),char(108),char(117),char(109), -char(101),char(83),char(116),char(105),char(102),char(102),char(110),char(101),char(115),char(115),char(0),char(42),char(109),char(95),char(109),char(97),char(116),char(101),char(114),char(105), -char(97),char(108),char(0),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(112),char(114),char(101),char(118), -char(105),char(111),char(117),char(115),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(0),char(109),char(95),char(118),char(101),char(108),char(111),char(99), -char(105),char(116),char(121),char(0),char(109),char(95),char(97),char(99),char(99),char(117),char(109),char(117),char(108),char(97),char(116),char(101),char(100),char(70),char(111),char(114), -char(99),char(101),char(0),char(109),char(95),char(110),char(111),char(114),char(109),char(97),char(108),char(0),char(109),char(95),char(97),char(114),char(101),char(97),char(0),char(109), -char(95),char(97),char(116),char(116),char(97),char(99),char(104),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101), -char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(76),char(101),char(110),char(103),char(116),char(104),char(0),char(109),char(95), -char(98),char(98),char(101),char(110),char(100),char(105),char(110),char(103),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99), -char(101),char(115),char(91),char(51),char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(65),char(114),char(101),char(97),char(0),char(109),char(95),char(99), -char(48),char(91),char(52),char(93),char(0),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(91),char(52), -char(93),char(0),char(109),char(95),char(114),char(101),char(115),char(116),char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(99),char(49),char(0), -char(109),char(95),char(99),char(50),char(0),char(109),char(95),char(99),char(48),char(0),char(109),char(95),char(108),char(111),char(99),char(97),char(108),char(70),char(114),char(97), -char(109),char(101),char(0),char(42),char(109),char(95),char(114),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(0),char(109),char(95),char(110),char(111), -char(100),char(101),char(73),char(110),char(100),char(101),char(120),char(0),char(109),char(95),char(97),char(101),char(114),char(111),char(77),char(111),char(100),char(101),char(108),char(0), -char(109),char(95),char(98),char(97),char(117),char(109),char(103),char(97),char(114),char(116),char(101),char(0),char(109),char(95),char(100),char(114),char(97),char(103),char(0),char(109), -char(95),char(108),char(105),char(102),char(116),char(0),char(109),char(95),char(112),char(114),char(101),char(115),char(115),char(117),char(114),char(101),char(0),char(109),char(95),char(118), -char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(100),char(121),char(110),char(97),char(109),char(105),char(99),char(70),char(114),char(105),char(99),char(116), -char(105),char(111),char(110),char(0),char(109),char(95),char(112),char(111),char(115),char(101),char(77),char(97),char(116),char(99),char(104),char(0),char(109),char(95),char(114),char(105), -char(103),char(105),char(100),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109), -char(95),char(107),char(105),char(110),char(101),char(116),char(105),char(99),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114),char(100),char(110), -char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(72),char(97),char(114), -char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(97),char(110),char(99),char(104),char(111),char(114),char(72),char(97),char(114),char(100),char(110),char(101), -char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115),char(116),char(101), -char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(75),char(105),char(110),char(101), -char(116),char(105),char(99),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100),char(110),char(101),char(115),char(115),char(0),char(109), -char(95),char(115),char(111),char(102),char(116),char(83),char(111),char(102),char(116),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(72),char(97),char(114),char(100), -char(110),char(101),char(115),char(115),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(67),char(108),char(117),char(115), -char(116),char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111), -char(102),char(116),char(75),char(105),char(110),char(101),char(116),char(105),char(99),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),char(112),char(117), -char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(115),char(111),char(102),char(116),char(83),char(111),char(102),char(116),char(67), -char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(83),char(112),char(108),char(105),char(116),char(0),char(109), -char(95),char(109),char(97),char(120),char(86),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(116),char(105),char(109),char(101),char(83),char(99),char(97), -char(108),char(101),char(0),char(109),char(95),char(118),char(101),char(108),char(111),char(99),char(105),char(116),char(121),char(73),char(116),char(101),char(114),char(97),char(116),char(105), -char(111),char(110),char(115),char(0),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(73),char(116),char(101),char(114),char(97),char(116), -char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(100),char(114),char(105),char(102),char(116),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111), -char(110),char(115),char(0),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(73),char(116),char(101),char(114),char(97),char(116),char(105),char(111), -char(110),char(115),char(0),char(109),char(95),char(114),char(111),char(116),char(0),char(109),char(95),char(115),char(99),char(97),char(108),char(101),char(0),char(109),char(95),char(97), -char(113),char(113),char(0),char(109),char(95),char(99),char(111),char(109),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(105),char(116),char(105),char(111),char(110), -char(115),char(0),char(42),char(109),char(95),char(119),char(101),char(105),char(103),char(104),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(80),char(111), -char(115),char(105),char(116),char(105),char(111),char(110),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(87),char(101),char(105),char(103),char(116),char(115),char(0), -char(109),char(95),char(98),char(118),char(111),char(108),char(117),char(109),char(101),char(0),char(109),char(95),char(98),char(102),char(114),char(97),char(109),char(101),char(0),char(109), -char(95),char(102),char(114),char(97),char(109),char(101),char(120),char(102),char(111),char(114),char(109),char(0),char(109),char(95),char(108),char(111),char(99),char(105),char(105),char(0), -char(109),char(95),char(105),char(110),char(118),char(119),char(105),char(0),char(109),char(95),char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91), -char(50),char(93),char(0),char(109),char(95),char(100),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(91),char(50),char(93),char(0),char(109),char(95), -char(108),char(118),char(0),char(109),char(95),char(97),char(118),char(0),char(42),char(109),char(95),char(102),char(114),char(97),char(109),char(101),char(114),char(101),char(102),char(115), -char(0),char(42),char(109),char(95),char(110),char(111),char(100),char(101),char(73),char(110),char(100),char(105),char(99),char(101),char(115),char(0),char(42),char(109),char(95),char(109), -char(97),char(115),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70),char(114),char(97),char(109),char(101),char(82),char(101),char(102),char(115), -char(0),char(109),char(95),char(110),char(117),char(109),char(78),char(111),char(100),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(115), -char(115),char(101),char(115),char(0),char(109),char(95),char(105),char(100),char(109),char(97),char(115),char(115),char(0),char(109),char(95),char(105),char(109),char(97),char(115),char(115), -char(0),char(109),char(95),char(110),char(118),char(105),char(109),char(112),char(117),char(108),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(105),char(109), -char(112),char(117),char(108),char(115),char(101),char(115),char(0),char(109),char(95),char(110),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95), -char(108),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0),char(109),char(95),char(97),char(100),char(97),char(109),char(112),char(105),char(110),char(103),char(0), -char(109),char(95),char(109),char(97),char(116),char(99),char(104),char(105),char(110),char(103),char(0),char(109),char(95),char(109),char(97),char(120),char(83),char(101),char(108),char(102), -char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(0),char(109),char(95),char(115), -char(101),char(108),char(102),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(73),char(109),char(112),char(117),char(108),char(115),char(101),char(70), -char(97),char(99),char(116),char(111),char(114),char(0),char(109),char(95),char(99),char(111),char(110),char(116),char(97),char(105),char(110),char(115),char(65),char(110),char(99),char(104), -char(111),char(114),char(0),char(109),char(95),char(99),char(111),char(108),char(108),char(105),char(100),char(101),char(0),char(109),char(95),char(99),char(108),char(117),char(115),char(116), -char(101),char(114),char(73),char(110),char(100),char(101),char(120),char(0),char(42),char(109),char(95),char(98),char(111),char(100),char(121),char(65),char(0),char(42),char(109),char(95), -char(98),char(111),char(100),char(121),char(66),char(0),char(109),char(95),char(114),char(101),char(102),char(115),char(91),char(50),char(93),char(0),char(109),char(95),char(99),char(102), -char(109),char(0),char(109),char(95),char(115),char(112),char(108),char(105),char(116),char(0),char(109),char(95),char(100),char(101),char(108),char(101),char(116),char(101),char(0),char(109), -char(95),char(114),char(101),char(108),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(91),char(50),char(93),char(0),char(109),char(95),char(98),char(111), -char(100),char(121),char(65),char(116),char(121),char(112),char(101),char(0),char(109),char(95),char(98),char(111),char(100),char(121),char(66),char(116),char(121),char(112),char(101),char(0), -char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(84),char(121),char(112),char(101),char(0),char(42),char(109),char(95),char(112),char(111),char(115),char(101),char(0), -char(42),char(42),char(109),char(95),char(109),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(115),char(0),char(42),char(109),char(95),char(110),char(111),char(100), -char(101),char(115),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(115),char(0),char(42),char(109),char(95),char(102),char(97),char(99),char(101),char(115), -char(0),char(42),char(109),char(95),char(116),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97),char(0),char(42),char(109),char(95),char(97),char(110), -char(99),char(104),char(111),char(114),char(115),char(0),char(42),char(109),char(95),char(99),char(108),char(117),char(115),char(116),char(101),char(114),char(115),char(0),char(42),char(109), -char(95),char(106),char(111),char(105),char(110),char(116),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(77),char(97),char(116),char(101),char(114),char(105),char(97), -char(108),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(76),char(105),char(110),char(107),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(70), -char(97),char(99),char(101),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(84),char(101),char(116),char(114),char(97),char(104),char(101),char(100),char(114),char(97), -char(0),char(109),char(95),char(110),char(117),char(109),char(65),char(110),char(99),char(104),char(111),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(67), -char(108),char(117),char(115),char(116),char(101),char(114),char(115),char(0),char(109),char(95),char(110),char(117),char(109),char(74),char(111),char(105),char(110),char(116),char(115),char(0), -char(109),char(95),char(99),char(111),char(110),char(102),char(105),char(103),char(0),char(109),char(95),char(122),char(101),char(114),char(111),char(82),char(111),char(116),char(80),char(97), -char(114),char(101),char(110),char(116),char(84),char(111),char(84),char(104),char(105),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(67), -char(111),char(109),char(84),char(111),char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102),char(102),char(115),char(101),char(116),char(0),char(109),char(95), -char(116),char(104),char(105),char(115),char(80),char(105),char(118),char(111),char(116),char(84),char(111),char(84),char(104),char(105),char(115),char(67),char(111),char(109),char(79),char(102), -char(102),char(115),char(101),char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(84),char(111),char(112),char(91), -char(54),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(65),char(120),char(105),char(115),char(66),char(111),char(116),char(116),char(111),char(109), -char(91),char(54),char(93),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(106), -char(111),char(105),char(110),char(116),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(108),char(105),char(110),char(107),char(67),char(111),char(108),char(108), -char(105),char(100),char(101),char(114),char(0),char(109),char(95),char(108),char(105),char(110),char(107),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(0),char(109), -char(95),char(108),char(105),char(110),char(107),char(77),char(97),char(115),char(115),char(0),char(109),char(95),char(112),char(97),char(114),char(101),char(110),char(116),char(73),char(110), -char(100),char(101),char(120),char(0),char(109),char(95),char(100),char(111),char(102),char(67),char(111),char(117),char(110),char(116),char(0),char(109),char(95),char(112),char(111),char(115), -char(86),char(97),char(114),char(67),char(111),char(117),char(110),char(116),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(80),char(111),char(115),char(91), -char(55),char(93),char(0),char(109),char(95),char(106),char(111),char(105),char(110),char(116),char(86),char(101),char(108),char(91),char(54),char(93),char(0),char(109),char(95),char(106), -char(111),char(105),char(110),char(116),char(84),char(111),char(114),char(113),char(117),char(101),char(91),char(54),char(93),char(0),char(42),char(109),char(95),char(98),char(97),char(115), -char(101),char(78),char(97),char(109),char(101),char(0),char(42),char(109),char(95),char(98),char(97),char(115),char(101),char(67),char(111),char(108),char(108),char(105),char(100),char(101), -char(114),char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(87),char(111),char(114),char(108),char(100),char(84),char(114),char(97),char(110),char(115),char(102),char(111), -char(114),char(109),char(0),char(109),char(95),char(98),char(97),char(115),char(101),char(73),char(110),char(101),char(114),char(116),char(105),char(97),char(0),char(109),char(95),char(98), -char(97),char(115),char(101),char(77),char(97),char(115),char(115),char(0),char(84),char(89),char(80),char(69),char(95),char(0),char(0),char(0),char(99),char(104),char(97),char(114), -char(0),char(117),char(99),char(104),char(97),char(114),char(0),char(115),char(104),char(111),char(114),char(116),char(0),char(117),char(115),char(104),char(111),char(114),char(116),char(0), -char(105),char(110),char(116),char(0),char(108),char(111),char(110),char(103),char(0),char(117),char(108),char(111),char(110),char(103),char(0),char(102),char(108),char(111),char(97),char(116), -char(0),char(100),char(111),char(117),char(98),char(108),char(101),char(0),char(118),char(111),char(105),char(100),char(0),char(80),char(111),char(105),char(110),char(116),char(101),char(114), -char(65),char(114),char(114),char(97),char(121),char(0),char(98),char(116),char(80),char(104),char(121),char(115),char(105),char(99),char(115),char(83),char(121),char(115),char(116),char(101), -char(109),char(0),char(76),char(105),char(115),char(116),char(66),char(97),char(115),char(101),char(0),char(98),char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51), -char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(86),char(101),char(99),char(116),char(111),char(114),char(51),char(68), -char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114),char(110),char(105), -char(111),char(110),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(116),char(101),char(114), -char(110),char(105),char(111),char(110),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97),char(116), -char(114),char(105),char(120),char(51),char(120),char(51),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(97), -char(116),char(114),char(105),char(120),char(51),char(120),char(51),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116), -char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98), -char(116),char(84),char(114),char(97),char(110),char(115),char(102),char(111),char(114),char(109),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(66),char(118),char(104),char(83),char(117),char(98),char(116),char(114),char(101),char(101),char(73),char(110),char(102),char(111),char(68),char(97),char(116), -char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101), -char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(79),char(112),char(116),char(105),char(109),char(105),char(122),char(101), -char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98), -char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(78),char(111),char(100),char(101),char(68),char(97),char(116), -char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104),char(70),char(108),char(111),char(97), -char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(81),char(117),char(97),char(110),char(116),char(105),char(122),char(101),char(100),char(66),char(118),char(104), -char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105), -char(111),char(110),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(97),char(116),char(105),char(99), -char(80),char(108),char(97),char(110),char(101),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110), -char(118),char(101),char(120),char(73),char(110),char(116),char(101),char(114),char(110),char(97),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(80),char(111),char(115),char(105),char(116),char(105),char(111),char(110),char(65),char(110),char(100),char(82),char(97),char(100),char(105),char(117),char(115), -char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(83),char(112),char(104),char(101),char(114),char(101),char(83),char(104),char(97),char(112),char(101),char(68), -char(97),char(116),char(97),char(0),char(98),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98), -char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(68),char(97),char(116),char(97),char(0),char(98), -char(116),char(83),char(104),char(111),char(114),char(116),char(73),char(110),char(116),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105),char(112),char(108),char(101), -char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(104),char(97),char(114),char(73),char(110),char(100),char(101),char(120),char(84),char(114),char(105), -char(112),char(108),char(101),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(101),char(115),char(104),char(80),char(97),char(114),char(116),char(68), -char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(116),char(114),char(105),char(100),char(105),char(110),char(103),char(77),char(101),char(115),char(104),char(73),char(110), -char(116),char(101),char(114),char(102),char(97),char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103), -char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114), -char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110),char(102),char(111),char(77),char(97),char(112),char(68),char(97),char(116),char(97),char(0),char(98),char(116), -char(83),char(99),char(97),char(108),char(101),char(100),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(77),char(101),char(115),char(104),char(83),char(104), -char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111),char(117),char(110),char(100),char(83),char(104), -char(97),char(112),char(101),char(67),char(104),char(105),char(108),char(100),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(109),char(112),char(111), -char(117),char(110),char(100),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(121),char(108),char(105),char(110), -char(100),char(101),char(114),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(83), -char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(97),char(112),char(115),char(117),char(108),char(101),char(83),char(104), -char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(114),char(105),char(97),char(110),char(103),char(108),char(101),char(73),char(110), -char(102),char(111),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(73),char(109),char(112),char(97),char(99),char(116),char(77),char(101),char(115),char(104), -char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(118),char(101),char(120),char(72),char(117), -char(108),char(108),char(83),char(104),char(97),char(112),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115), -char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0), -char(98),char(116),char(67),char(111),char(108),char(108),char(105),char(115),char(105),char(111),char(110),char(79),char(98),char(106),char(101),char(99),char(116),char(70),char(108),char(111), -char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115),char(87),char(111),char(114), -char(108),char(100),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(116),char(97), -char(99),char(116),char(83),char(111),char(108),char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97), -char(116),char(97),char(0),char(98),char(116),char(68),char(121),char(110),char(97),char(109),char(105),char(99),char(115),char(87),char(111),char(114),char(108),char(100),char(70),char(108), -char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(116),char(97),char(99),char(116),char(83),char(111),char(108), -char(118),char(101),char(114),char(73),char(110),char(102),char(111),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82), -char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116), -char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0), -char(98),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(73),char(110),char(102),char(111),char(49),char(0),char(98),char(116), -char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116), -char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), -char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(82),char(105),char(103),char(105),char(100),char(66),char(111),char(100),char(121),char(68),char(97), -char(116),char(97),char(0),char(98),char(116),char(84),char(121),char(112),char(101),char(100),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116), -char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80), -char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108),char(111),char(97),char(116),char(68), -char(97),char(116),char(97),char(0),char(98),char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110), -char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98), -char(116),char(80),char(111),char(105),char(110),char(116),char(50),char(80),char(111),char(105),char(110),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105), -char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101), -char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108), -char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(72),char(105),char(110),char(103),char(101),char(67),char(111),char(110),char(115),char(116), -char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(67), -char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111), -char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(67),char(111),char(110),char(101),char(84),char(119),char(105),char(115),char(116), -char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110), -char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97), -char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(67),char(111),char(110),char(115), -char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116), -char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(67),char(111),char(110), -char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105), -char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110), -char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114), -char(105),char(99),char(54),char(68),char(111),char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(50),char(67),char(111),char(110),char(115),char(116),char(114),char(97), -char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(110),char(101),char(114),char(105),char(99),char(54),char(68),char(111), -char(102),char(83),char(112),char(114),char(105),char(110),char(103),char(50),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111), -char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(50),char(0),char(98),char(116),char(83),char(108),char(105),char(100),char(101),char(114),char(67),char(111), -char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(83),char(108),char(105),char(100),char(101), -char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116), -char(97),char(0),char(98),char(116),char(71),char(101),char(97),char(114),char(67),char(111),char(110),char(115),char(116),char(114),char(97),char(105),char(110),char(116),char(70),char(108), -char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(71),char(101),char(97),char(114),char(67),char(111),char(110),char(115),char(116),char(114), -char(97),char(105),char(110),char(116),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66), -char(111),char(100),char(121),char(77),char(97),char(116),char(101),char(114),char(105),char(97),char(108),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116), -char(66),char(111),char(100),char(121),char(78),char(111),char(100),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100), -char(121),char(76),char(105),char(110),char(107),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(70),char(97), -char(99),char(101),char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(84),char(101),char(116),char(114),char(97), -char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(82),char(105),char(103),char(105),char(100),char(65),char(110),char(99),char(104),char(111),char(114), -char(68),char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(67),char(111),char(110),char(102),char(105),char(103),char(68), -char(97),char(116),char(97),char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(80),char(111),char(115),char(101),char(68),char(97),char(116),char(97), -char(0),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(67),char(108),char(117),char(115),char(116),char(101),char(114),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(74),char(111),char(105),char(110),char(116),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(83),char(111),char(102),char(116),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97), -char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(76),char(105),char(110),char(107),char(68),char(111),char(117),char(98), -char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66),char(111),char(100),char(121),char(76),char(105), -char(110),char(107),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116),char(105),char(66), -char(111),char(100),char(121),char(68),char(111),char(117),char(98),char(108),char(101),char(68),char(97),char(116),char(97),char(0),char(98),char(116),char(77),char(117),char(108),char(116), -char(105),char(66),char(111),char(100),char(121),char(70),char(108),char(111),char(97),char(116),char(68),char(97),char(116),char(97),char(0),char(0),char(84),char(76),char(69),char(78), -char(1),char(0),char(1),char(0),char(2),char(0),char(2),char(0),char(4),char(0),char(4),char(0),char(4),char(0),char(4),char(0),char(8),char(0),char(0),char(0), -char(16),char(0),char(48),char(0),char(16),char(0),char(16),char(0),char(32),char(0),char(16),char(0),char(32),char(0),char(48),char(0),char(96),char(0),char(64),char(0), -char(-128),char(0),char(20),char(0),char(48),char(0),char(80),char(0),char(16),char(0),char(96),char(0),char(-112),char(0),char(16),char(0),char(56),char(0),char(56),char(0), -char(20),char(0),char(72),char(0),char(4),char(0),char(4),char(0),char(8),char(0),char(4),char(0),char(56),char(0),char(32),char(0),char(80),char(0),char(72),char(0), -char(96),char(0),char(80),char(0),char(32),char(0),char(64),char(0),char(64),char(0),char(64),char(0),char(16),char(0),char(72),char(0),char(80),char(0),char(-32),char(1), -char(16),char(1),char(-72),char(0),char(-104),char(0),char(104),char(0),char(88),char(0),char(-8),char(1),char(-80),char(3),char(8),char(0),char(64),char(0),char(64),char(0), -char(0),char(0),char(80),char(0),char(96),char(0),char(-112),char(0),char(-128),char(0),char(104),char(1),char(-24),char(0),char(-104),char(1),char(-120),char(1),char(-32),char(0), -char(8),char(1),char(-40),char(1),char(104),char(1),char(-128),char(2),char(-112),char(2),char(-64),char(4),char(-40),char(0),char(120),char(1),char(104),char(0),char(-104),char(0), -char(16),char(0),char(104),char(0),char(24),char(0),char(40),char(0),char(104),char(0),char(96),char(0),char(104),char(0),char(-56),char(0),char(104),char(1),char(112),char(0), -char(-32),char(1),char(-56),char(2),char(120),char(1),char(-56),char(0),char(112),char(0),char(0),char(0),char(83),char(84),char(82),char(67),char(84),char(0),char(0),char(0), -char(10),char(0),char(3),char(0),char(4),char(0),char(0),char(0),char(4),char(0),char(1),char(0),char(9),char(0),char(2),char(0),char(11),char(0),char(3),char(0), -char(10),char(0),char(3),char(0),char(10),char(0),char(4),char(0),char(10),char(0),char(5),char(0),char(12),char(0),char(2),char(0),char(9),char(0),char(6),char(0), -char(9),char(0),char(7),char(0),char(13),char(0),char(1),char(0),char(7),char(0),char(8),char(0),char(14),char(0),char(1),char(0),char(8),char(0),char(8),char(0), -char(15),char(0),char(1),char(0),char(7),char(0),char(8),char(0),char(16),char(0),char(1),char(0),char(8),char(0),char(8),char(0),char(17),char(0),char(1),char(0), -char(13),char(0),char(9),char(0),char(18),char(0),char(1),char(0),char(14),char(0),char(9),char(0),char(19),char(0),char(2),char(0),char(17),char(0),char(10),char(0), -char(13),char(0),char(11),char(0),char(20),char(0),char(2),char(0),char(18),char(0),char(10),char(0),char(14),char(0),char(11),char(0),char(21),char(0),char(4),char(0), -char(4),char(0),char(12),char(0),char(4),char(0),char(13),char(0),char(2),char(0),char(14),char(0),char(2),char(0),char(15),char(0),char(22),char(0),char(6),char(0), -char(13),char(0),char(16),char(0),char(13),char(0),char(17),char(0),char(4),char(0),char(18),char(0),char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0), -char(0),char(0),char(21),char(0),char(23),char(0),char(6),char(0),char(14),char(0),char(16),char(0),char(14),char(0),char(17),char(0),char(4),char(0),char(18),char(0), -char(4),char(0),char(19),char(0),char(4),char(0),char(20),char(0),char(0),char(0),char(21),char(0),char(24),char(0),char(3),char(0),char(2),char(0),char(14),char(0), -char(2),char(0),char(15),char(0),char(4),char(0),char(22),char(0),char(25),char(0),char(12),char(0),char(13),char(0),char(23),char(0),char(13),char(0),char(24),char(0), -char(13),char(0),char(25),char(0),char(4),char(0),char(26),char(0),char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0), -char(22),char(0),char(30),char(0),char(24),char(0),char(31),char(0),char(21),char(0),char(32),char(0),char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0), -char(26),char(0),char(12),char(0),char(14),char(0),char(23),char(0),char(14),char(0),char(24),char(0),char(14),char(0),char(25),char(0),char(4),char(0),char(26),char(0), -char(4),char(0),char(27),char(0),char(4),char(0),char(28),char(0),char(4),char(0),char(29),char(0),char(23),char(0),char(30),char(0),char(24),char(0),char(31),char(0), -char(4),char(0),char(33),char(0),char(4),char(0),char(34),char(0),char(21),char(0),char(32),char(0),char(27),char(0),char(3),char(0),char(0),char(0),char(35),char(0), -char(4),char(0),char(36),char(0),char(0),char(0),char(37),char(0),char(28),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(13),char(0),char(39),char(0), -char(13),char(0),char(40),char(0),char(7),char(0),char(41),char(0),char(0),char(0),char(21),char(0),char(29),char(0),char(5),char(0),char(27),char(0),char(38),char(0), -char(13),char(0),char(39),char(0),char(13),char(0),char(42),char(0),char(7),char(0),char(43),char(0),char(4),char(0),char(44),char(0),char(30),char(0),char(2),char(0), -char(13),char(0),char(45),char(0),char(7),char(0),char(46),char(0),char(31),char(0),char(4),char(0),char(29),char(0),char(47),char(0),char(30),char(0),char(48),char(0), -char(4),char(0),char(49),char(0),char(0),char(0),char(37),char(0),char(32),char(0),char(1),char(0),char(4),char(0),char(50),char(0),char(33),char(0),char(2),char(0), -char(2),char(0),char(50),char(0),char(0),char(0),char(51),char(0),char(34),char(0),char(2),char(0),char(2),char(0),char(52),char(0),char(0),char(0),char(51),char(0), -char(35),char(0),char(2),char(0),char(0),char(0),char(52),char(0),char(0),char(0),char(53),char(0),char(36),char(0),char(8),char(0),char(13),char(0),char(54),char(0), -char(14),char(0),char(55),char(0),char(32),char(0),char(56),char(0),char(34),char(0),char(57),char(0),char(35),char(0),char(58),char(0),char(33),char(0),char(59),char(0), -char(4),char(0),char(60),char(0),char(4),char(0),char(61),char(0),char(37),char(0),char(4),char(0),char(36),char(0),char(62),char(0),char(13),char(0),char(63),char(0), -char(4),char(0),char(64),char(0),char(0),char(0),char(37),char(0),char(38),char(0),char(7),char(0),char(27),char(0),char(38),char(0),char(37),char(0),char(65),char(0), -char(25),char(0),char(66),char(0),char(26),char(0),char(67),char(0),char(39),char(0),char(68),char(0),char(7),char(0),char(43),char(0),char(0),char(0),char(69),char(0), -char(40),char(0),char(2),char(0),char(38),char(0),char(70),char(0),char(13),char(0),char(39),char(0),char(41),char(0),char(4),char(0),char(19),char(0),char(71),char(0), -char(27),char(0),char(72),char(0),char(4),char(0),char(73),char(0),char(7),char(0),char(74),char(0),char(42),char(0),char(4),char(0),char(27),char(0),char(38),char(0), -char(41),char(0),char(75),char(0),char(4),char(0),char(76),char(0),char(7),char(0),char(43),char(0),char(43),char(0),char(3),char(0),char(29),char(0),char(47),char(0), -char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0),char(44),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(78),char(0), -char(0),char(0),char(37),char(0),char(45),char(0),char(3),char(0),char(29),char(0),char(47),char(0),char(4),char(0),char(77),char(0),char(0),char(0),char(37),char(0), -char(46),char(0),char(4),char(0),char(4),char(0),char(79),char(0),char(7),char(0),char(80),char(0),char(7),char(0),char(81),char(0),char(7),char(0),char(82),char(0), -char(39),char(0),char(14),char(0),char(4),char(0),char(83),char(0),char(4),char(0),char(84),char(0),char(46),char(0),char(85),char(0),char(4),char(0),char(86),char(0), -char(7),char(0),char(87),char(0),char(7),char(0),char(88),char(0),char(7),char(0),char(89),char(0),char(7),char(0),char(90),char(0),char(7),char(0),char(91),char(0), -char(4),char(0),char(92),char(0),char(4),char(0),char(93),char(0),char(4),char(0),char(94),char(0),char(4),char(0),char(95),char(0),char(0),char(0),char(37),char(0), -char(47),char(0),char(5),char(0),char(27),char(0),char(38),char(0),char(37),char(0),char(65),char(0),char(13),char(0),char(39),char(0),char(7),char(0),char(43),char(0), -char(4),char(0),char(96),char(0),char(48),char(0),char(5),char(0),char(29),char(0),char(47),char(0),char(13),char(0),char(97),char(0),char(14),char(0),char(98),char(0), -char(4),char(0),char(99),char(0),char(0),char(0),char(100),char(0),char(49),char(0),char(25),char(0),char(9),char(0),char(101),char(0),char(9),char(0),char(102),char(0), -char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0),char(20),char(0),char(104),char(0),char(20),char(0),char(105),char(0),char(14),char(0),char(106),char(0), -char(14),char(0),char(107),char(0),char(14),char(0),char(108),char(0),char(8),char(0),char(109),char(0),char(8),char(0),char(110),char(0),char(8),char(0),char(111),char(0), -char(8),char(0),char(112),char(0),char(8),char(0),char(113),char(0),char(8),char(0),char(114),char(0),char(8),char(0),char(115),char(0),char(8),char(0),char(116),char(0), -char(4),char(0),char(117),char(0),char(4),char(0),char(118),char(0),char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0),char(4),char(0),char(121),char(0), -char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(0),char(0),char(37),char(0),char(50),char(0),char(25),char(0),char(9),char(0),char(101),char(0), -char(9),char(0),char(102),char(0),char(27),char(0),char(103),char(0),char(0),char(0),char(35),char(0),char(19),char(0),char(104),char(0),char(19),char(0),char(105),char(0), -char(13),char(0),char(106),char(0),char(13),char(0),char(107),char(0),char(13),char(0),char(108),char(0),char(7),char(0),char(109),char(0),char(7),char(0),char(110),char(0), -char(7),char(0),char(111),char(0),char(7),char(0),char(112),char(0),char(7),char(0),char(113),char(0),char(7),char(0),char(114),char(0),char(7),char(0),char(115),char(0), -char(7),char(0),char(116),char(0),char(4),char(0),char(117),char(0),char(4),char(0),char(118),char(0),char(4),char(0),char(119),char(0),char(4),char(0),char(120),char(0), -char(4),char(0),char(121),char(0),char(4),char(0),char(122),char(0),char(4),char(0),char(123),char(0),char(0),char(0),char(37),char(0),char(51),char(0),char(2),char(0), -char(52),char(0),char(124),char(0),char(14),char(0),char(125),char(0),char(53),char(0),char(2),char(0),char(54),char(0),char(124),char(0),char(13),char(0),char(125),char(0), -char(55),char(0),char(21),char(0),char(50),char(0),char(126),char(0),char(17),char(0),char(127),char(0),char(13),char(0),char(-128),char(0),char(13),char(0),char(-127),char(0), -char(13),char(0),char(-126),char(0),char(13),char(0),char(-125),char(0),char(13),char(0),char(125),char(0),char(13),char(0),char(-124),char(0),char(13),char(0),char(-123),char(0), -char(13),char(0),char(-122),char(0),char(13),char(0),char(-121),char(0),char(7),char(0),char(-120),char(0),char(7),char(0),char(-119),char(0),char(7),char(0),char(-118),char(0), -char(7),char(0),char(-117),char(0),char(7),char(0),char(-116),char(0),char(7),char(0),char(-115),char(0),char(7),char(0),char(-114),char(0),char(7),char(0),char(-113),char(0), -char(7),char(0),char(-112),char(0),char(4),char(0),char(-111),char(0),char(56),char(0),char(22),char(0),char(49),char(0),char(126),char(0),char(18),char(0),char(127),char(0), -char(14),char(0),char(-128),char(0),char(14),char(0),char(-127),char(0),char(14),char(0),char(-126),char(0),char(14),char(0),char(-125),char(0),char(14),char(0),char(125),char(0), -char(14),char(0),char(-124),char(0),char(14),char(0),char(-123),char(0),char(14),char(0),char(-122),char(0),char(14),char(0),char(-121),char(0),char(8),char(0),char(-120),char(0), -char(8),char(0),char(-119),char(0),char(8),char(0),char(-118),char(0),char(8),char(0),char(-117),char(0),char(8),char(0),char(-116),char(0),char(8),char(0),char(-115),char(0), -char(8),char(0),char(-114),char(0),char(8),char(0),char(-113),char(0),char(8),char(0),char(-112),char(0),char(4),char(0),char(-111),char(0),char(0),char(0),char(37),char(0), -char(57),char(0),char(2),char(0),char(4),char(0),char(-110),char(0),char(4),char(0),char(-109),char(0),char(58),char(0),char(13),char(0),char(55),char(0),char(-108),char(0), -char(55),char(0),char(-107),char(0),char(0),char(0),char(35),char(0),char(4),char(0),char(-106),char(0),char(4),char(0),char(-105),char(0),char(4),char(0),char(-104),char(0), -char(4),char(0),char(-103),char(0),char(7),char(0),char(-102),char(0),char(7),char(0),char(-101),char(0),char(4),char(0),char(-100),char(0),char(4),char(0),char(-99),char(0), -char(7),char(0),char(-98),char(0),char(4),char(0),char(-97),char(0),char(59),char(0),char(13),char(0),char(60),char(0),char(-108),char(0),char(60),char(0),char(-107),char(0), -char(0),char(0),char(35),char(0),char(4),char(0),char(-106),char(0),char(4),char(0),char(-105),char(0),char(4),char(0),char(-104),char(0),char(4),char(0),char(-103),char(0), -char(7),char(0),char(-102),char(0),char(7),char(0),char(-101),char(0),char(4),char(0),char(-100),char(0),char(4),char(0),char(-99),char(0),char(7),char(0),char(-98),char(0), -char(4),char(0),char(-97),char(0),char(61),char(0),char(14),char(0),char(56),char(0),char(-108),char(0),char(56),char(0),char(-107),char(0),char(0),char(0),char(35),char(0), -char(4),char(0),char(-106),char(0),char(4),char(0),char(-105),char(0),char(4),char(0),char(-104),char(0),char(4),char(0),char(-103),char(0),char(8),char(0),char(-102),char(0), -char(8),char(0),char(-101),char(0),char(4),char(0),char(-100),char(0),char(4),char(0),char(-99),char(0),char(8),char(0),char(-98),char(0),char(4),char(0),char(-97),char(0), -char(0),char(0),char(-96),char(0),char(62),char(0),char(3),char(0),char(59),char(0),char(-95),char(0),char(13),char(0),char(-94),char(0),char(13),char(0),char(-93),char(0), -char(63),char(0),char(3),char(0),char(61),char(0),char(-95),char(0),char(14),char(0),char(-94),char(0),char(14),char(0),char(-93),char(0),char(64),char(0),char(3),char(0), -char(59),char(0),char(-95),char(0),char(14),char(0),char(-94),char(0),char(14),char(0),char(-93),char(0),char(65),char(0),char(13),char(0),char(59),char(0),char(-95),char(0), -char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),char(4),char(0),char(-89),char(0),char(4),char(0),char(-88),char(0), -char(7),char(0),char(-87),char(0),char(7),char(0),char(-86),char(0),char(7),char(0),char(-85),char(0),char(7),char(0),char(-84),char(0),char(7),char(0),char(-83),char(0), -char(7),char(0),char(-82),char(0),char(7),char(0),char(-81),char(0),char(66),char(0),char(13),char(0),char(59),char(0),char(-95),char(0),char(19),char(0),char(-92),char(0), -char(19),char(0),char(-91),char(0),char(4),char(0),char(-90),char(0),char(4),char(0),char(-89),char(0),char(4),char(0),char(-88),char(0),char(7),char(0),char(-87),char(0), -char(7),char(0),char(-86),char(0),char(7),char(0),char(-85),char(0),char(7),char(0),char(-84),char(0),char(7),char(0),char(-83),char(0),char(7),char(0),char(-82),char(0), -char(7),char(0),char(-81),char(0),char(67),char(0),char(14),char(0),char(61),char(0),char(-95),char(0),char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0), -char(4),char(0),char(-90),char(0),char(4),char(0),char(-89),char(0),char(4),char(0),char(-88),char(0),char(8),char(0),char(-87),char(0),char(8),char(0),char(-86),char(0), -char(8),char(0),char(-85),char(0),char(8),char(0),char(-84),char(0),char(8),char(0),char(-83),char(0),char(8),char(0),char(-82),char(0),char(8),char(0),char(-81),char(0), -char(0),char(0),char(-80),char(0),char(68),char(0),char(10),char(0),char(61),char(0),char(-95),char(0),char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0), -char(8),char(0),char(-79),char(0),char(8),char(0),char(-78),char(0),char(8),char(0),char(-77),char(0),char(8),char(0),char(-83),char(0),char(8),char(0),char(-82),char(0), -char(8),char(0),char(-81),char(0),char(8),char(0),char(-76),char(0),char(69),char(0),char(11),char(0),char(59),char(0),char(-95),char(0),char(19),char(0),char(-92),char(0), -char(19),char(0),char(-91),char(0),char(7),char(0),char(-79),char(0),char(7),char(0),char(-78),char(0),char(7),char(0),char(-77),char(0),char(7),char(0),char(-83),char(0), -char(7),char(0),char(-82),char(0),char(7),char(0),char(-81),char(0),char(7),char(0),char(-76),char(0),char(0),char(0),char(21),char(0),char(70),char(0),char(9),char(0), -char(59),char(0),char(-95),char(0),char(19),char(0),char(-92),char(0),char(19),char(0),char(-91),char(0),char(13),char(0),char(-75),char(0),char(13),char(0),char(-74),char(0), -char(13),char(0),char(-73),char(0),char(13),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0),char(71),char(0),char(9),char(0), -char(61),char(0),char(-95),char(0),char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0),char(14),char(0),char(-75),char(0),char(14),char(0),char(-74),char(0), -char(14),char(0),char(-73),char(0),char(14),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0),char(72),char(0),char(5),char(0), -char(70),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),char(7),char(0),char(-67),char(0),char(7),char(0),char(-66),char(0),char(7),char(0),char(-65),char(0), -char(73),char(0),char(5),char(0),char(71),char(0),char(-69),char(0),char(4),char(0),char(-68),char(0),char(8),char(0),char(-67),char(0),char(8),char(0),char(-66),char(0), -char(8),char(0),char(-65),char(0),char(74),char(0),char(41),char(0),char(59),char(0),char(-95),char(0),char(19),char(0),char(-92),char(0),char(19),char(0),char(-91),char(0), -char(13),char(0),char(-75),char(0),char(13),char(0),char(-74),char(0),char(13),char(0),char(-64),char(0),char(13),char(0),char(-63),char(0),char(13),char(0),char(-62),char(0), -char(13),char(0),char(-61),char(0),char(13),char(0),char(-60),char(0),char(13),char(0),char(-59),char(0),char(13),char(0),char(-58),char(0),char(13),char(0),char(-57),char(0), -char(13),char(0),char(-56),char(0),char(13),char(0),char(-55),char(0),char(13),char(0),char(-54),char(0),char(0),char(0),char(-53),char(0),char(0),char(0),char(-52),char(0), -char(0),char(0),char(-51),char(0),char(0),char(0),char(-50),char(0),char(0),char(0),char(-49),char(0),char(0),char(0),char(-80),char(0),char(13),char(0),char(-73),char(0), -char(13),char(0),char(-72),char(0),char(13),char(0),char(-48),char(0),char(13),char(0),char(-47),char(0),char(13),char(0),char(-46),char(0),char(13),char(0),char(-45),char(0), -char(13),char(0),char(-44),char(0),char(13),char(0),char(-43),char(0),char(13),char(0),char(-42),char(0),char(13),char(0),char(-41),char(0),char(13),char(0),char(-40),char(0), -char(13),char(0),char(-39),char(0),char(13),char(0),char(-38),char(0),char(0),char(0),char(-37),char(0),char(0),char(0),char(-36),char(0),char(0),char(0),char(-35),char(0), -char(0),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0),char(4),char(0),char(-32),char(0),char(75),char(0),char(41),char(0),char(61),char(0),char(-95),char(0), -char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0),char(14),char(0),char(-75),char(0),char(14),char(0),char(-74),char(0),char(14),char(0),char(-64),char(0), -char(14),char(0),char(-63),char(0),char(14),char(0),char(-62),char(0),char(14),char(0),char(-61),char(0),char(14),char(0),char(-60),char(0),char(14),char(0),char(-59),char(0), -char(14),char(0),char(-58),char(0),char(14),char(0),char(-57),char(0),char(14),char(0),char(-56),char(0),char(14),char(0),char(-55),char(0),char(14),char(0),char(-54),char(0), -char(0),char(0),char(-53),char(0),char(0),char(0),char(-52),char(0),char(0),char(0),char(-51),char(0),char(0),char(0),char(-50),char(0),char(0),char(0),char(-49),char(0), -char(0),char(0),char(-80),char(0),char(14),char(0),char(-73),char(0),char(14),char(0),char(-72),char(0),char(14),char(0),char(-48),char(0),char(14),char(0),char(-47),char(0), -char(14),char(0),char(-46),char(0),char(14),char(0),char(-45),char(0),char(14),char(0),char(-44),char(0),char(14),char(0),char(-43),char(0),char(14),char(0),char(-42),char(0), -char(14),char(0),char(-41),char(0),char(14),char(0),char(-40),char(0),char(14),char(0),char(-39),char(0),char(14),char(0),char(-38),char(0),char(0),char(0),char(-37),char(0), -char(0),char(0),char(-36),char(0),char(0),char(0),char(-35),char(0),char(0),char(0),char(-34),char(0),char(0),char(0),char(-33),char(0),char(4),char(0),char(-32),char(0), -char(76),char(0),char(9),char(0),char(59),char(0),char(-95),char(0),char(19),char(0),char(-92),char(0),char(19),char(0),char(-91),char(0),char(7),char(0),char(-75),char(0), -char(7),char(0),char(-74),char(0),char(7),char(0),char(-73),char(0),char(7),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0), -char(77),char(0),char(9),char(0),char(61),char(0),char(-95),char(0),char(20),char(0),char(-92),char(0),char(20),char(0),char(-91),char(0),char(8),char(0),char(-75),char(0), -char(8),char(0),char(-74),char(0),char(8),char(0),char(-73),char(0),char(8),char(0),char(-72),char(0),char(4),char(0),char(-71),char(0),char(4),char(0),char(-70),char(0), -char(78),char(0),char(5),char(0),char(58),char(0),char(-95),char(0),char(13),char(0),char(-31),char(0),char(13),char(0),char(-30),char(0),char(7),char(0),char(-29),char(0), -char(0),char(0),char(37),char(0),char(79),char(0),char(4),char(0),char(61),char(0),char(-95),char(0),char(14),char(0),char(-31),char(0),char(14),char(0),char(-30),char(0), -char(8),char(0),char(-29),char(0),char(52),char(0),char(22),char(0),char(8),char(0),char(-28),char(0),char(8),char(0),char(-76),char(0),char(8),char(0),char(111),char(0), -char(8),char(0),char(-27),char(0),char(8),char(0),char(113),char(0),char(8),char(0),char(-26),char(0),char(8),char(0),char(-25),char(0),char(8),char(0),char(-24),char(0), -char(8),char(0),char(-23),char(0),char(8),char(0),char(-22),char(0),char(8),char(0),char(-21),char(0),char(8),char(0),char(-20),char(0),char(8),char(0),char(-19),char(0), -char(8),char(0),char(-18),char(0),char(8),char(0),char(-17),char(0),char(8),char(0),char(-16),char(0),char(4),char(0),char(-15),char(0),char(4),char(0),char(-14),char(0), -char(4),char(0),char(-13),char(0),char(4),char(0),char(-12),char(0),char(4),char(0),char(-11),char(0),char(0),char(0),char(37),char(0),char(54),char(0),char(22),char(0), -char(7),char(0),char(-28),char(0),char(7),char(0),char(-76),char(0),char(7),char(0),char(111),char(0),char(7),char(0),char(-27),char(0),char(7),char(0),char(113),char(0), -char(7),char(0),char(-26),char(0),char(7),char(0),char(-25),char(0),char(7),char(0),char(-24),char(0),char(7),char(0),char(-23),char(0),char(7),char(0),char(-22),char(0), -char(7),char(0),char(-21),char(0),char(7),char(0),char(-20),char(0),char(7),char(0),char(-19),char(0),char(7),char(0),char(-18),char(0),char(7),char(0),char(-17),char(0), -char(7),char(0),char(-16),char(0),char(4),char(0),char(-15),char(0),char(4),char(0),char(-14),char(0),char(4),char(0),char(-13),char(0),char(4),char(0),char(-12),char(0), -char(4),char(0),char(-11),char(0),char(0),char(0),char(37),char(0),char(80),char(0),char(4),char(0),char(7),char(0),char(-10),char(0),char(7),char(0),char(-9),char(0), -char(7),char(0),char(-8),char(0),char(4),char(0),char(79),char(0),char(81),char(0),char(10),char(0),char(80),char(0),char(-7),char(0),char(13),char(0),char(-6),char(0), -char(13),char(0),char(-5),char(0),char(13),char(0),char(-4),char(0),char(13),char(0),char(-3),char(0),char(13),char(0),char(-2),char(0),char(7),char(0),char(-120),char(0), -char(7),char(0),char(-1),char(0),char(4),char(0),char(0),char(1),char(4),char(0),char(53),char(0),char(82),char(0),char(4),char(0),char(80),char(0),char(-7),char(0), -char(4),char(0),char(1),char(1),char(7),char(0),char(2),char(1),char(4),char(0),char(3),char(1),char(83),char(0),char(4),char(0),char(13),char(0),char(-2),char(0), -char(80),char(0),char(-7),char(0),char(4),char(0),char(4),char(1),char(7),char(0),char(5),char(1),char(84),char(0),char(7),char(0),char(13),char(0),char(6),char(1), -char(80),char(0),char(-7),char(0),char(4),char(0),char(7),char(1),char(7),char(0),char(8),char(1),char(7),char(0),char(9),char(1),char(7),char(0),char(10),char(1), -char(4),char(0),char(53),char(0),char(85),char(0),char(6),char(0),char(17),char(0),char(11),char(1),char(13),char(0),char(9),char(1),char(13),char(0),char(12),char(1), -char(60),char(0),char(13),char(1),char(4),char(0),char(14),char(1),char(7),char(0),char(10),char(1),char(86),char(0),char(26),char(0),char(4),char(0),char(15),char(1), -char(7),char(0),char(16),char(1),char(7),char(0),char(-76),char(0),char(7),char(0),char(17),char(1),char(7),char(0),char(18),char(1),char(7),char(0),char(19),char(1), -char(7),char(0),char(20),char(1),char(7),char(0),char(21),char(1),char(7),char(0),char(22),char(1),char(7),char(0),char(23),char(1),char(7),char(0),char(24),char(1), -char(7),char(0),char(25),char(1),char(7),char(0),char(26),char(1),char(7),char(0),char(27),char(1),char(7),char(0),char(28),char(1),char(7),char(0),char(29),char(1), -char(7),char(0),char(30),char(1),char(7),char(0),char(31),char(1),char(7),char(0),char(32),char(1),char(7),char(0),char(33),char(1),char(7),char(0),char(34),char(1), -char(4),char(0),char(35),char(1),char(4),char(0),char(36),char(1),char(4),char(0),char(37),char(1),char(4),char(0),char(38),char(1),char(4),char(0),char(118),char(0), -char(87),char(0),char(12),char(0),char(17),char(0),char(39),char(1),char(17),char(0),char(40),char(1),char(17),char(0),char(41),char(1),char(13),char(0),char(42),char(1), -char(13),char(0),char(43),char(1),char(7),char(0),char(44),char(1),char(4),char(0),char(45),char(1),char(4),char(0),char(46),char(1),char(4),char(0),char(47),char(1), -char(4),char(0),char(48),char(1),char(7),char(0),char(8),char(1),char(4),char(0),char(53),char(0),char(88),char(0),char(27),char(0),char(19),char(0),char(49),char(1), -char(17),char(0),char(50),char(1),char(17),char(0),char(51),char(1),char(13),char(0),char(42),char(1),char(13),char(0),char(52),char(1),char(13),char(0),char(53),char(1), -char(13),char(0),char(54),char(1),char(13),char(0),char(55),char(1),char(13),char(0),char(56),char(1),char(4),char(0),char(57),char(1),char(7),char(0),char(58),char(1), -char(4),char(0),char(59),char(1),char(4),char(0),char(60),char(1),char(4),char(0),char(61),char(1),char(7),char(0),char(62),char(1),char(7),char(0),char(63),char(1), -char(4),char(0),char(64),char(1),char(4),char(0),char(65),char(1),char(7),char(0),char(66),char(1),char(7),char(0),char(67),char(1),char(7),char(0),char(68),char(1), -char(7),char(0),char(69),char(1),char(7),char(0),char(70),char(1),char(7),char(0),char(71),char(1),char(4),char(0),char(72),char(1),char(4),char(0),char(73),char(1), -char(4),char(0),char(74),char(1),char(89),char(0),char(12),char(0),char(9),char(0),char(75),char(1),char(9),char(0),char(76),char(1),char(13),char(0),char(77),char(1), -char(7),char(0),char(78),char(1),char(7),char(0),char(-24),char(0),char(7),char(0),char(79),char(1),char(4),char(0),char(80),char(1),char(13),char(0),char(81),char(1), -char(4),char(0),char(82),char(1),char(4),char(0),char(83),char(1),char(4),char(0),char(84),char(1),char(4),char(0),char(53),char(0),char(90),char(0),char(19),char(0), -char(50),char(0),char(126),char(0),char(87),char(0),char(85),char(1),char(80),char(0),char(86),char(1),char(81),char(0),char(87),char(1),char(82),char(0),char(88),char(1), -char(83),char(0),char(89),char(1),char(84),char(0),char(90),char(1),char(85),char(0),char(91),char(1),char(88),char(0),char(92),char(1),char(89),char(0),char(93),char(1), -char(4),char(0),char(94),char(1),char(4),char(0),char(60),char(1),char(4),char(0),char(95),char(1),char(4),char(0),char(96),char(1),char(4),char(0),char(97),char(1), -char(4),char(0),char(98),char(1),char(4),char(0),char(99),char(1),char(4),char(0),char(100),char(1),char(86),char(0),char(101),char(1),char(91),char(0),char(17),char(0), -char(16),char(0),char(102),char(1),char(14),char(0),char(103),char(1),char(14),char(0),char(104),char(1),char(14),char(0),char(105),char(1),char(14),char(0),char(106),char(1), -char(0),char(0),char(107),char(1),char(0),char(0),char(108),char(1),char(49),char(0),char(109),char(1),char(14),char(0),char(110),char(1),char(8),char(0),char(111),char(1), -char(4),char(0),char(112),char(1),char(4),char(0),char(84),char(1),char(4),char(0),char(113),char(1),char(4),char(0),char(114),char(1),char(8),char(0),char(115),char(1), -char(8),char(0),char(116),char(1),char(8),char(0),char(117),char(1),char(92),char(0),char(17),char(0),char(15),char(0),char(102),char(1),char(13),char(0),char(103),char(1), -char(13),char(0),char(104),char(1),char(13),char(0),char(105),char(1),char(13),char(0),char(106),char(1),char(0),char(0),char(107),char(1),char(0),char(0),char(108),char(1), -char(50),char(0),char(109),char(1),char(13),char(0),char(110),char(1),char(4),char(0),char(113),char(1),char(7),char(0),char(111),char(1),char(4),char(0),char(112),char(1), -char(4),char(0),char(84),char(1),char(7),char(0),char(115),char(1),char(7),char(0),char(116),char(1),char(7),char(0),char(117),char(1),char(4),char(0),char(114),char(1), -char(93),char(0),char(8),char(0),char(0),char(0),char(118),char(1),char(91),char(0),char(88),char(1),char(49),char(0),char(119),char(1),char(20),char(0),char(120),char(1), -char(14),char(0),char(121),char(1),char(4),char(0),char(95),char(1),char(8),char(0),char(122),char(1),char(0),char(0),char(37),char(0),char(94),char(0),char(7),char(0), -char(0),char(0),char(118),char(1),char(92),char(0),char(88),char(1),char(50),char(0),char(119),char(1),char(19),char(0),char(120),char(1),char(13),char(0),char(121),char(1), -char(7),char(0),char(122),char(1),char(4),char(0),char(95),char(1),}; -int sBulletDNAlen64= sizeof(sBulletDNAstr64); diff --git a/extern/sdlew/include/SDL2/SDL_gamecontroller.h b/extern/sdlew/include/SDL2/SDL_gamecontroller.h index baed2bd173a5..6d6fe104d19a 100644 --- a/extern/sdlew/include/SDL2/SDL_gamecontroller.h +++ b/extern/sdlew/include/SDL2/SDL_gamecontroller.h @@ -40,6 +40,8 @@ typedef struct SDL_GameControllerButtonBind typedef int SDLCALL tSDL_GameControllerAddMapping( const char* mappingString ); +typedef int SDLCALL tSDL_GameControllerAddMappingsFromRW( SDL_RWops * rw, int freerw ); + typedef char * SDLCALL tSDL_GameControllerMappingForGUID( SDL_JoystickGUID guid ); typedef char * SDLCALL tSDL_GameControllerMapping( SDL_GameController * gamecontroller ); @@ -119,6 +121,8 @@ typedef Uint8 SDLCALL tSDL_GameControllerGetButton(SDL_GameController *gamecontr typedef void SDLCALL tSDL_GameControllerClose(SDL_GameController *gamecontroller); extern tSDL_GameControllerAddMapping *SDL_GameControllerAddMapping; +extern tSDL_GameControllerAddMappingsFromRW *SDL_GameControllerAddMappingsFromRW; +#define SDL_GameControllerAddMappingsFromFile(file) SDL_GameControllerAddMappingsFromRW(SDL_RWFromFile(file, "rb"), 1) extern tSDL_GameControllerMappingForGUID *SDL_GameControllerMappingForGUID; extern tSDL_GameControllerMapping *SDL_GameControllerMapping; extern tSDL_IsGameController *SDL_IsGameController; diff --git a/extern/sdlew/include/SDL2/SDL_haptic.h b/extern/sdlew/include/SDL2/SDL_haptic.h index 88fee82e5491..a8460035574a 100644 --- a/extern/sdlew/include/SDL2/SDL_haptic.h +++ b/extern/sdlew/include/SDL2/SDL_haptic.h @@ -212,12 +212,12 @@ typedef SDL_Haptic * SDLCALL tSDL_HapticOpenFromJoystick(SDL_Joystick * typedef void SDLCALL tSDL_HapticClose(SDL_Haptic * haptic); +typedef unsigned int SDLCALL tSDL_HapticQuery(SDL_Haptic * haptic); + typedef int SDLCALL tSDL_HapticNumEffects(SDL_Haptic * haptic); typedef int SDLCALL tSDL_HapticNumEffectsPlaying(SDL_Haptic * haptic); -extern DECLSPEC unsigned int SDLCALL SDL_HapticQuery(SDL_Haptic * haptic); - typedef int SDLCALL tSDL_HapticNumAxes(SDL_Haptic * haptic); typedef int SDLCALL tSDL_HapticEffectSupported(SDL_Haptic * haptic, @@ -273,6 +273,7 @@ extern tSDL_HapticOpenFromMouse *SDL_HapticOpenFromMouse; extern tSDL_JoystickIsHaptic *SDL_JoystickIsHaptic; extern tSDL_HapticOpenFromJoystick *SDL_HapticOpenFromJoystick; extern tSDL_HapticClose *SDL_HapticClose; +extern tSDL_HapticQuery *SDL_HapticQuery; extern tSDL_HapticNumEffects *SDL_HapticNumEffects; extern tSDL_HapticNumEffectsPlaying *SDL_HapticNumEffectsPlaying; extern tSDL_HapticNumAxes *SDL_HapticNumAxes; diff --git a/extern/sdlew/src/sdlew.c b/extern/sdlew/src/sdlew.c index 3b19f0cef473..c0cd4a95de04 100644 --- a/extern/sdlew/src/sdlew.c +++ b/extern/sdlew/src/sdlew.c @@ -312,6 +312,7 @@ tSDL_SetTextInputRect *SDL_SetTextInputRect; tSDL_HasScreenKeyboardSupport *SDL_HasScreenKeyboardSupport; tSDL_IsScreenKeyboardShown *SDL_IsScreenKeyboardShown; tSDL_GameControllerAddMapping *SDL_GameControllerAddMapping; +tSDL_GameControllerAddMappingsFromRW *SDL_GameControllerAddMappingsFromRW; tSDL_GameControllerMappingForGUID *SDL_GameControllerMappingForGUID; tSDL_GameControllerMapping *SDL_GameControllerMapping; tSDL_IsGameController *SDL_IsGameController; @@ -493,6 +494,7 @@ tSDL_HapticOpenFromMouse *SDL_HapticOpenFromMouse; tSDL_JoystickIsHaptic *SDL_JoystickIsHaptic; tSDL_HapticOpenFromJoystick *SDL_HapticOpenFromJoystick; tSDL_HapticClose *SDL_HapticClose; +tSDL_HapticQuery *SDL_HapticQuery; tSDL_HapticNumEffects *SDL_HapticNumEffects; tSDL_HapticNumEffectsPlaying *SDL_HapticNumEffectsPlaying; tSDL_HapticNumAxes *SDL_HapticNumAxes; @@ -855,6 +857,7 @@ int sdlewInit(void) { SDL_LIBRARY_FIND(SDL_HasScreenKeyboardSupport); SDL_LIBRARY_FIND(SDL_IsScreenKeyboardShown); SDL_LIBRARY_FIND(SDL_GameControllerAddMapping); + SDL_LIBRARY_FIND(SDL_GameControllerAddMappingsFromRW); SDL_LIBRARY_FIND(SDL_GameControllerMappingForGUID); SDL_LIBRARY_FIND(SDL_GameControllerMapping); SDL_LIBRARY_FIND(SDL_IsGameController); @@ -1036,6 +1039,7 @@ int sdlewInit(void) { SDL_LIBRARY_FIND(SDL_JoystickIsHaptic); SDL_LIBRARY_FIND(SDL_HapticOpenFromJoystick); SDL_LIBRARY_FIND(SDL_HapticClose); + SDL_LIBRARY_FIND(SDL_HapticQuery) SDL_LIBRARY_FIND(SDL_HapticNumEffects); SDL_LIBRARY_FIND(SDL_HapticNumEffectsPlaying); SDL_LIBRARY_FIND(SDL_HapticNumAxes); diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt index 499b10486553..b50fafab86fd 100644 --- a/intern/CMakeLists.txt +++ b/intern/CMakeLists.txt @@ -39,6 +39,10 @@ if(WITH_GAMEENGINE_DECKLINK) add_subdirectory(decklink) endif() +if (WITH_GAMEENGINE_BPPLAYER) + add_subdirectory(spindle) +endif() + if(WITH_AUDASPACE) add_subdirectory(audaspace) endif() @@ -63,10 +67,6 @@ if(WITH_IK_ITASC) add_subdirectory(itasc) endif() -if(WITH_GAMEENGINE) - add_subdirectory(moto) -endif() - if(WITH_CYCLES) add_subdirectory(cycles) endif() diff --git a/intern/container/CTR_HashedPtr.h b/intern/container/CTR_HashedPtr.h deleted file mode 100644 index ee832eee153f..000000000000 --- a/intern/container/CTR_HashedPtr.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - * - */ - -/** \file container/CTR_HashedPtr.h - * \ingroup ctr - */ - -#ifndef __CTR_HASHEDPTR_H__ -#define __CTR_HASHEDPTR_H__ - -#include - -inline unsigned int CTR_Hash(void *inDWord) -{ - size_t key = (size_t)inDWord; - return (unsigned int)(key ^ (key >> 4)); -} - -class CTR_HashedPtr -{ - void *m_valptr; -public: - CTR_HashedPtr(void *val) : m_valptr(val) { - } - unsigned int hash() const { - return CTR_Hash(m_valptr); - } - inline friend bool operator ==(const CTR_HashedPtr & rhs, const CTR_HashedPtr & lhs) { - return rhs.m_valptr == lhs.m_valptr; - } - void *getValue() const { - return m_valptr; - } -}; - -#endif /* __CTR_HASHEDPTR_H__ */ - diff --git a/intern/container/CTR_Map.h b/intern/container/CTR_Map.h deleted file mode 100644 index c278fe5330ce..000000000000 --- a/intern/container/CTR_Map.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file container/CTR_Map.h - * \ingroup ctr - */ - -#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; - } - } - - CTR_Map(const CTR_Map& map) - { - m_num_buckets = map.m_num_buckets; - m_buckets = new Entry *[m_num_buckets]; - - for (int i = 0; i < m_num_buckets; ++i) { - m_buckets[i] = 0; - - for (Entry *entry = map.m_buckets[i]; entry; entry = entry->m_next) { - insert(entry->m_key, entry->m_value); - } - } - } - - int size() - { - int count = 0; - for (int i = 0; i < m_num_buckets; i++) { - Entry *bucket = m_buckets[i]; - while (bucket) { - bucket = bucket->m_next; - count++; - } - } - return count; - } - - Value *at(int index) - { - int count = 0; - for (int i = 0; i < m_num_buckets; i++) { - Entry *bucket = m_buckets[i]; - while (bucket) { - if (count == index) { - return &bucket->m_value; - } - bucket = bucket->m_next; - count++; - } - } - return 0; - } - - Key *getKey(int index) - { - int count = 0; - for (int i = 0; i < m_num_buckets; i++) { - Entry *bucket = m_buckets[i]; - while (bucket) { - if (count == index) { - return &bucket->m_key; - } - 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 /* __CTR_MAP_H__ */ diff --git a/intern/debugbreak/COPYING b/intern/debugbreak/COPYING new file mode 100644 index 000000000000..9e51088a5827 --- /dev/null +++ b/intern/debugbreak/COPYING @@ -0,0 +1,23 @@ +Copyright (c) 2011-2016, Scott Tsai + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/intern/debugbreak/README.md b/intern/debugbreak/README.md new file mode 100644 index 000000000000..f6c4882e1320 --- /dev/null +++ b/intern/debugbreak/README.md @@ -0,0 +1,126 @@ +# Debug Break + +[debugbreak.h](https://github.com/scottt/debugbreak/blob/master/debugbreak.h) allows you to put breakpoints in your C/C++ code with a call to **debug_break()**: +```C +#include +#include "debugbreak.h" + +int main() +{ + debug_break(); /* will break into debugger */ + printf("hello world\n"); + return 0; +} +``` +* Include one header file and insert calls to `debug_break()` in the code where you wish to break into the debugger. +* Supports GCC, Clang and MSVC. +* Works well on ARM, AArch64, i686, x86-64, POWER and has a fallback code path for other architectures. +* Works like the **DebugBreak()** fuction provided by [Windows](http://msdn.microsoft.com/en-us/library/ea9yy3ey.aspx) and [QNX](http://www.qnx.com/developers/docs/6.3.0SP3/neutrino/lib_ref/d/debugbreak.html). + +**License**: the very permissive [2-Clause BSD](https://github.com/scottt/debugbreak/blob/master/COPYING). + +Known Problem: if continuing execution after a debugbreak breakpoint hit doesn't work (e.g. on ARM or POWER), see [HOW-TO-USE-DEBUGBREAK-GDB-PY.md](HOW-TO-USE-DEBUGBREAK-GDB-PY.md) for a workaround. + +Implementation Notes +================================ + +The requirements for the **debug_break()** function are: +* Act as a compiler code motion barrier +* Don't cause the compiler optimizers to think the code following it can be removed +* Trigger a software breakpoint hit when executed (e.g. **SIGTRAP** on Linux) +* GDB commands like **continue**, **next**, **step**, **stepi** must work after a **debug_break()** hit + +Ideally, both GCC and Clang would provide a **__builtin_debugtrap()** that satisfies the above on all architectures and operating systems. Unfortunately, that is not the case (yet). +GCC's [__builtin_trap()](http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-g_t_005f_005fbuiltin_005ftrap-3278) causes the optimizers to think the code follwing can be removed ([test/trap.c](https://github.com/scottt/debugbreak/blob/master/test/trap.c)): +```C +#include + +int main() +{ + __builtin_trap(); + printf("hello world\n"); + return 0; +} +``` +compiles to: +``` +main +0x0000000000400390 <+0>: 0f 0b ud2 +``` +Notice how the call to `printf()` is not present in the assembly output. + +Further, on i386 / x86-64 **__builtin_trap()** generates an **ud2** instruction which triggers **SIGILL** instead of **SIGTRAP**. This makes it necessary to change GDB's default behavior on **SIGILL** to not terminate the process being debugged: +``` +(gdb) handle SIGILL stop nopass +``` +Even after this, continuing execution in GDB doesn't work well on some GCC, GDB combinations. See [GCC Bugzilla 84595](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84595). + +On ARM, **__builtin_trap()** generates a call to **abort()**, making it even less suitable. + +**debug_break()** generates an **int3** instruction on i386 / x86-64 ([test/break.c](https://github.com/scottt/debugbreak/blob/master/test/break.c)): +```C +#include +#include "debugbreak.h" + +int main() +{ + debug_break(); + printf("hello world\n"); + return 0; +} +``` +compiles to: +``` +main +0x00000000004003d0 <+0>: 50 push %rax +0x00000000004003d1 <+1>: cc int3 +0x00000000004003d2 <+2>: bf a0 05 40 00 mov $0x4005a0,%edi +0x00000000004003d7 <+7>: e8 d4 ff ff ff callq 0x4003b0 +0x00000000004003dc <+12>: 31 c0 xor %eax,%eax +0x00000000004003de <+14>: 5a pop %rdx +0x00000000004003df <+15>: c3 retq +``` +which correctly trigges **SIGTRAP** and single-stepping in GDB after a **debug_break()** hit works well. + +Clang / LLVM also has a **__builtin_trap()** that generates **ud2** but further provides **__builtin_debugtrap()** that generates **int3** on i386 / x86-64 ([original LLVM intrinsic](http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20120507/142621.html), [further fixes](https://reviews.llvm.org/rL166300#96cef7d3), [Clang builtin support](https://reviews.llvm.org/rL166298)). + +On ARM, **debug_break()** generates **.inst 0xe7f001f0** in ARM mode and **.inst 0xde01** in Thumb mode which correctly triggers *SIGTRAP* on Linux. Unfortunately, stepping in GDB after a **debug_break()** hit doesn't work and requires a workaround like: +``` +(gdb) set $l = 2 +(gdb) tbreak *($pc + $l) +(gdb) jump *($pc + $l) +(gdb) # Change $l from 2 to 4 for ARM mode +``` +to jump over the instruction. +A new GDB command, **debugbreak-step**, is defined in [debugbreak-gdb.py](https://github.com/scottt/debugbreak/blob/master/debugbreak-gdb.py) to automate the above. See [HOW-TO-USE-DEBUGBREAK-GDB-PY.md](HOW-TO-USE-DEBUGBREAK-GDB-PY.md) for sample usage. +``` +$ arm-none-linux-gnueabi-gdb -x debugbreak-gdb.py test/break-c++ +<...> +(gdb) run +Program received signal SIGTRAP, Trace/breakpoint trap. +main () at test/break-c++.cc:6 +6 debug_break(); + +(gdb) debugbreak-step + +7 std::cout << "hello, world\n"; +``` + +On AArch64, **debug_break()** generates **.inst 0xd4200000**. + +On other architectures, **debug_break()** generates a call to **raise(SIGTRAP)**. + +Behavior on Different Architectures +---------------- + +| Architecture | debug_break() | +| ------------- | ------------- | +| x86/x86-64 | `int3` | +| ARM mode, 32-bit | `.inst 0xe7f001f0` | +| Thumb mode, 32-bit | `.inst 0xde01` | +| AArch64, ARMv8 | `.inst 0xd4200000` | +| POWER | `.4byte 0x7d821008` | +| MSVC compiler | `__debugbreak` | +| Apple compiler on AArch64 | `__builtin_trap()` | +| Otherwise | `raise(SIGTRAP)` | + diff --git a/intern/debugbreak/debugbreak.h b/intern/debugbreak/debugbreak.h new file mode 100644 index 000000000000..410706d9031b --- /dev/null +++ b/intern/debugbreak/debugbreak.h @@ -0,0 +1,156 @@ +/* Copyright (c) 2011-2018, Scott Tsai + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE 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 HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef DEBUG_BREAK_H + +#ifdef _MSC_VER + +#define debug_break __debugbreak + +#else + +#ifdef __cplusplus +extern "C" { +#endif + +#define DEBUG_BREAK_USE_TRAP_INSTRUCTION 1 +#define DEBUG_BREAK_USE_BULTIN_TRAP 2 +#define DEBUG_BREAK_USE_SIGTRAP 3 + +#if defined(__i386__) || defined(__x86_64__) + #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION +__inline__ static void trap_instruction(void) +{ + __asm__ volatile("int $0x03"); +} +#elif defined(__thumb__) + #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION +/* FIXME: handle __THUMB_INTERWORK__ */ +__attribute__((gnu_inline, always_inline)) +__inline__ static void trap_instruction(void) +{ + /* See 'arm-linux-tdep.c' in GDB source. + * Both instruction sequences below work. */ +#if 1 + /* 'eabi_linux_thumb_le_breakpoint' */ + __asm__ volatile(".inst 0xde01"); +#else + /* 'eabi_linux_thumb2_le_breakpoint' */ + __asm__ volatile(".inst.w 0xf7f0a000"); +#endif + + /* Known problem: + * After a breakpoint hit, can't 'stepi', 'step', or 'continue' in GDB. + * 'step' would keep getting stuck on the same instruction. + * + * Workaround: use the new GDB commands 'debugbreak-step' and + * 'debugbreak-continue' that become available + * after you source the script from GDB: + * + * $ gdb -x debugbreak-gdb.py <... USUAL ARGUMENTS ...> + * + * 'debugbreak-step' would jump over the breakpoint instruction with + * roughly equivalent of: + * (gdb) set $instruction_len = 2 + * (gdb) tbreak *($pc + $instruction_len) + * (gdb) jump *($pc + $instruction_len) + */ +} +#elif defined(__arm__) && !defined(__thumb__) + #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION +__attribute__((gnu_inline, always_inline)) +__inline__ static void trap_instruction(void) +{ + /* See 'arm-linux-tdep.c' in GDB source, + * 'eabi_linux_arm_le_breakpoint' */ + __asm__ volatile(".inst 0xe7f001f0"); + /* Known problem: + * Same problem and workaround as Thumb mode */ +} +#elif defined(__aarch64__) && defined(__APPLE__) + #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_BULTIN_TRAP +#elif defined(__aarch64__) + #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION +__attribute__((gnu_inline, always_inline)) +__inline__ static void trap_instruction(void) +{ + /* See 'aarch64-tdep.c' in GDB source, + * 'aarch64_default_breakpoint' */ + __asm__ volatile(".inst 0xd4200000"); +} +#elif defined(__powerpc__) + /* PPC 32 or 64-bit, big or little endian */ + #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION +__attribute__((gnu_inline, always_inline)) +__inline__ static void trap_instruction(void) +{ + /* See 'rs6000-tdep.c' in GDB source, + * 'rs6000_breakpoint' */ + __asm__ volatile(".4byte 0x7d821008"); + + /* Known problem: + * After a breakpoint hit, can't 'stepi', 'step', or 'continue' in GDB. + * 'step' stuck on the same instruction ("twge r2,r2"). + * + * The workaround is the same as ARM Thumb mode: use debugbreak-gdb.py + * or manually jump over the instruction. */ +} +#else + #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_SIGTRAP +#endif + + +#ifndef DEBUG_BREAK_IMPL +#error "debugbreak.h is not supported on this target" +#elif DEBUG_BREAK_IMPL == DEBUG_BREAK_USE_TRAP_INSTRUCTION +__attribute__((gnu_inline, always_inline)) +__inline__ static void debug_break(void) +{ + trap_instruction(); +} +#elif DEBUG_BREAK_IMPL == DEBUG_BREAK_USE_BULTIN_TRAP +__attribute__((gnu_inline, always_inline)) +__inline__ static void debug_break(void) +{ + __builtin_trap(); +} +#elif DEBUG_BREAK_IMPL == DEBUG_BREAK_USE_SIGTRAP +#include +__attribute__((gnu_inline, always_inline)) +__inline__ static void debug_break(void) +{ + raise(SIGTRAP); +} +#else +#error "invalid DEBUG_BREAK_IMPL value" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ifdef _MSC_VER */ + +#endif /* ifndef DEBUG_BREAK_H */ diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index 1af0defc4ed4..19078acda8d3 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -251,6 +251,13 @@ elseif(WITH_X11) ) endif() + if(WITH_X11_XINERAMA) + add_definitions(-DWITH_X11_XINERAMA) + list(APPEND INC_SYS + ${X11_Xinerama_INCLUDE_PATH} + ) + endif() + add_definitions(-DWITH_X11) elseif(WIN32) diff --git a/intern/ghost/intern/GHOST_SystemPathsCocoa.mm b/intern/ghost/intern/GHOST_SystemPathsCocoa.mm index 36ae534da87d..7680665ffdef 100644 --- a/intern/ghost/intern/GHOST_SystemPathsCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemPathsCocoa.mm @@ -59,7 +59,7 @@ return NULL; } - snprintf(tempPath, sizeof(tempPath), "%s/Blender/%s", [basePath cStringUsingEncoding:NSASCIIStringEncoding], versionstr); + snprintf(tempPath, sizeof(tempPath), "%s/UPBGE/%s", [basePath cStringUsingEncoding:NSASCIIStringEncoding], versionstr); [pool drain]; return (GHOST_TUns8*)tempPath; @@ -81,7 +81,7 @@ return NULL; } - snprintf(tempPath, sizeof(tempPath), "%s/Blender/%s", [basePath cStringUsingEncoding:NSASCIIStringEncoding], versionstr); + snprintf(tempPath, sizeof(tempPath), "%s/UPBGE/%s", [basePath cStringUsingEncoding:NSASCIIStringEncoding], versionstr); [pool drain]; return (GHOST_TUns8*)tempPath; diff --git a/intern/ghost/intern/GHOST_SystemPathsUnix.cpp b/intern/ghost/intern/GHOST_SystemPathsUnix.cpp index b4e1259d8246..9c16a6d8e11e 100644 --- a/intern/ghost/intern/GHOST_SystemPathsUnix.cpp +++ b/intern/ghost/intern/GHOST_SystemPathsUnix.cpp @@ -63,7 +63,7 @@ const GHOST_TUns8 *GHOST_SystemPathsUnix::getSystemDir(int, const char *versions { /* no prefix assumes a portable build which only uses bundled scripts */ if (static_path) { - static string system_path = string(static_path) + "/blender/" + versionstr; + static string system_path = string(static_path) + "/upbge/" + versionstr; return (GHOST_TUns8 *)system_path.c_str(); } @@ -84,7 +84,7 @@ const GHOST_TUns8 *GHOST_SystemPathsUnix::getUserDir(int version, const char *ve last_version = version; if (home) { - user_path = string(home) + "/.blender/" + versionstr; + user_path = string(home) + "/.upbge/" + versionstr; } else { return NULL; @@ -99,7 +99,7 @@ const GHOST_TUns8 *GHOST_SystemPathsUnix::getUserDir(int version, const char *ve last_version = version; if (home) { - user_path = string(home) + "/blender/" + versionstr; + user_path = string(home) + "/upbge/" + versionstr; } else { home = getenv("HOME"); @@ -107,7 +107,7 @@ const GHOST_TUns8 *GHOST_SystemPathsUnix::getUserDir(int version, const char *ve if (home == NULL) home = getpwuid(getuid())->pw_dir; - user_path = string(home) + "/.config/blender/" + versionstr; + user_path = string(home) + "/.config/upbge/" + versionstr; } } diff --git a/intern/ghost/intern/GHOST_SystemPathsWin32.cpp b/intern/ghost/intern/GHOST_SystemPathsWin32.cpp index d122d3dd51f8..9ffdd35809ae 100644 --- a/intern/ghost/intern/GHOST_SystemPathsWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemPathsWin32.cpp @@ -54,7 +54,7 @@ const GHOST_TUns8 *GHOST_SystemPathsWin32::getSystemDir(int, const char *version if (hResult == S_OK) { conv_utf_16_to_8(knownpath_16, knownpath, MAX_PATH * 3); - strcat(knownpath, "\\Blender Foundation\\Blender\\"); + strcat(knownpath, "\\UPBGE\\Blender\\"); strcat(knownpath, versionstr); return (GHOST_TUns8*)knownpath; } @@ -71,7 +71,7 @@ const GHOST_TUns8 *GHOST_SystemPathsWin32::getUserDir(int, const char *versionst if (hResult == S_OK) { conv_utf_16_to_8(knownpath_16, knownpath, MAX_PATH * 3); - strcat(knownpath, "\\Blender Foundation\\Blender\\"); + strcat(knownpath, "\\UPBGE\\Blender\\"); strcat(knownpath, versionstr); return (GHOST_TUns8*)knownpath; } diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index ae4aae380c55..960baf3aa468 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -448,10 +448,11 @@ GHOST_TSuccess GHOST_SystemWin32::init() } wc.hCursor = ::LoadCursor(0, IDC_ARROW); wc.hbrBackground = -#ifdef INW32_COMPISITING - (HBRUSH)CreateSolidBrush +#ifdef WIN32_COMPOSITING + (HBRUSH)CreateSolidBrush(0x00000000); +#else + (HBRUSH)GetStockBrush(BLACK_BRUSH); #endif - (0x00000000); wc.lpszMenuName = 0; wc.lpszClassName = L"GHOST_WindowClass"; diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index c8984f0e2805..577151820c07 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -55,6 +55,10 @@ # include "GHOST_DropTargetX11.h" #endif +#ifdef WITH_X11_XINERAMA +# include "X11/extensions/Xinerama.h" +#endif + #include "GHOST_Debug.h" #ifdef WITH_XF86KEYSYM @@ -312,9 +316,47 @@ getMainDisplayDimensions( GHOST_TUns32& height) const { if (m_display) { - /* note, for this to work as documented, - * we would need to use Xinerama check r54370 for code that did this, - * we've since removed since its not worth the extra dep - campbell */ + +#ifdef WITH_X11_XINERAMA + GHOST_TInt32 m_x = 1, m_y = 1; + getCursorPosition(m_x, m_y); + + /* NOTE, no way to select a primary monitor, uses the first */ + bool success = false; + int dummy1, dummy2; + if (XineramaQueryExtension(m_display, &dummy1, &dummy2)) { + if (XineramaIsActive(m_display)) { + int heads = 0; + XineramaScreenInfo *p = XineramaQueryScreens(m_display, &heads); + /* with a single head, all dimensions is fine */ + if (heads > 1) { + int i; + for (i = 0; i < heads; i++) { + if ((m_x >= p[i].x_org) && (m_x <= p[i].x_org + p[i].width) && + (m_y >= p[i].y_org) && (m_y <= p[i].y_org + p[i].height)) + { + width = p[i].width; + height = p[i].height; + break; + } + } + /* highly unlikely! */ + if (i == heads) { + width = p[0].width; + height = p[0].height; + } + success = true; + } + XFree(p); + } + } + + if (success) { + return; + } +#endif + + /* fallback to all */ getAllDisplayDimensions(width, height); } } diff --git a/intern/mathfu/LICENSE b/intern/mathfu/LICENSE new file mode 100644 index 000000000000..d64569567334 --- /dev/null +++ b/intern/mathfu/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/intern/mathfu/mathfu.h b/intern/mathfu/mathfu.h new file mode 100644 index 000000000000..95baa176c01e --- /dev/null +++ b/intern/mathfu/mathfu.h @@ -0,0 +1,34 @@ +#ifndef __MATHFU_H__ +#define __MATHFU_H__ + +#define MATHFU_COMPILE_WITH_SIMD + +#include "mathfu/glsl_mappings.h" +#include "mathfu/constants.h" +#include "mathfu/frustum.h" +#include "mathfu/io.h" + +namespace mt = mathfu; + +namespace mathfu { + +static const mt::vec3 zero3 = mt::kZeros3f; +static const mt::vec3 one3 = mt::kOnes3f; +static const mt::vec3 axisX3 = mt::kAxisX3f; +static const mt::vec3 axisY3 = mt::kAxisY3f; +static const mt::vec3 axisZ3 = mt::kAxisZ3f; + +static const mt::vec2 zero2 = mt::kZeros2f; +static const mt::vec2 one2 = mt::kOnes2f; +static const mt::vec2 axisX2 = mt::kAxisX2f; +static const mt::vec2 axisY2 = mt::kAxisY2f; + +static const mt::vec4 zero4 = mt::kZeros4f; +static const mt::vec4 one4 = mt::kOnes4f; +static const mt::vec4 axisX4 = mt::kAxisX4f; +static const mt::vec4 axisY4 = mt::kAxisY4f; +static const mt::vec4 axisW4 = mt::kAxisW4f; + +} + +#endif // __MATHFU_H__ diff --git a/intern/mathfu/mathfu/constants.h b/intern/mathfu/mathfu/constants.h new file mode 100644 index 000000000000..e4f58f891a6c --- /dev/null +++ b/intern/mathfu/mathfu/constants.h @@ -0,0 +1,165 @@ +/* +* Copyright 2014 Google Inc. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef MATHFU_CONSTANTS_H +#define MATHFU_CONSTANTS_H + +#include "mathfu/matrix.h" +#include "mathfu/quaternion.h" +#include "mathfu/vector.h" + +namespace mathfu { + +/// @file mathfu/constants.h +/// @brief Vector constants for specific dimensions. +/// @addtogroup mathfu_constants +/// +/// It is preferable to use these constants rather than constructing them +/// when they're required. Construction most-likely slower than loading them +/// from memory. +///

+/// For example, the following:
+/// +/// lookat = mat4::LookAt(target, position, mathfu::kAxisY3f); +/// +///
is preferable to:
+/// +/// lookat = mat4::LookAt(target, position, +/// mathfu::Vector(0.0f, 1.0f, 0.0f)); +/// +///
in terms of efficiency and in addition to resulting in more concise +/// code. +///

+/// +/// Depending on your linker's sophistication and settings, these constants may +/// be duplicated in every compilation unit in which they're used. However, +/// most linkers should be able to detect and eliminate this duplication. + +/// @addtogroup mathfu_constants +/// @{ + +/// 2-dimensional float Vector of zeros. +static const Vector kZeros2f(0.0f, 0.0f); +/// 2-dimensional float Vector of ones. +static const Vector kOnes2f(1.0f, 1.0f); +/// 2-dimensional float unit Vector pointing along the X axis. +static const Vector kAxisX2f(1.0f, 0.0f); +/// 2-dimensional float unit Vector pointing along the Y axis. +static const Vector kAxisY2f(0.0f, 1.0f); + +/// 3-dimensional float Vector of zeros. +static const Vector kZeros3f(0.0f, 0.0f, 0.0f); +/// 3-dimensional float Vector of ones. +static const Vector kOnes3f(1.0f, 1.0f, 1.0f); +/// 3-dimensional float unit Vector pointing along the X axis. +static const Vector kAxisX3f(1.0f, 0.0f, 0.0f); +/// 3-dimensional float unit Vector pointing along the Y axis. +static const Vector kAxisY3f(0.0f, 1.0f, 0.0f); +/// 3-dimensional float unit Vector pointing along the Z axis. +static const Vector kAxisZ3f(0.0f, 0.0f, 1.0f); + +/// 4-dimensional float Vector of zeros. +static const Vector kZeros4f(0.0f, 0.0f, 0.0f, 0.0f); +/// 4-dimensional float Vector of ones. +static const Vector kOnes4f(1.0f, 1.0f, 1.0f, 1.0f); +/// 4-dimensional float unit Vector pointing along the X axis. +static const Vector kAxisX4f(1.0f, 0.0f, 0.0f, 0.0f); +/// 4-dimensional float unit Vector pointing along the Y axis. +static const Vector kAxisY4f(0.0f, 1.0f, 0.0f, 0.0f); +/// 4-dimensional float unit Vector pointing along the Z axis. +static const Vector kAxisZ4f(0.0f, 0.0f, 1.0f, 0.0f); +/// 4-dimensional float unit Vector pointing along the W axis. +static const Vector kAxisW4f(0.0f, 0.0f, 0.0f, 1.0f); + +/// 2-dimensional double Vector of zeros. +static const Vector kZeros2d(0.0, 0.0); +/// 2-dimensional double Vector of ones. +static const Vector kOnes2d(1.0, 1.0); +/// 2-dimensional double unit Vector pointing along the X axis. +static const Vector kAxisX2d(1.0, 0.0); +/// 2-dimensional double unit Vector pointing along the Y axis. +static const Vector kAxisY2d(0.0, 1.0); + +/// 3-dimensional double Vector of zeros. +static const Vector kZeros3d(0.0, 0.0, 0.0); +/// 3-dimensional double Vector of ones. +static const Vector kOnes3d(1.0, 1.0, 1.0); +/// 3-dimensional double unit Vector pointing along the X axis. +static const Vector kAxisX3d(1.0, 0.0, 0.0); +/// 3-dimensional double unit Vector pointing along the Y axis. +static const Vector kAxisY3d(0.0, 1.0, 0.0); +/// 3-dimensional double unit Vector pointing along the Z axis. +static const Vector kAxisZ3d(0.0, 0.0, 1.0); + +/// 4-dimensional double Vector of zeros. +static const Vector kZeros4d(0.0, 0.0, 0.0, 0.0); +/// 4-dimensional double Vector of ones. +static const Vector kOnes4d(1.0, 1.0, 1.0, 1.0); +/// 4-dimensional double unit Vector pointing along the X axis. +static const Vector kAxisX4d(1.0, 0.0, 0.0, 0.0); +/// 4-dimensional double unit Vector pointing along the Y axis. +static const Vector kAxisY4d(0.0, 1.0, 0.0, 0.0); +/// 4-dimensional double unit Vector pointing along the Z axis. +static const Vector kAxisZ4d(0.0, 0.0, 1.0, 0.0); +/// 4-dimensional double unit Vector pointing along the W axis. +static const Vector kAxisW4d(0.0, 0.0, 0.0, 1.0); + +/// 2-dimensional int Vector of zeros. +static const Vector kOnes2i(1, 1); +/// 2-dimensional int Vector of ones. +static const Vector kZeros2i(0, 0); +/// 2-dimensional int unit Vector pointing along the X axis. +static const Vector kAxisX2i(1, 0); +/// 2-dimensional int unit Vector pointing along the Y axis. +static const Vector kAxisY2i(0, 1); + +/// 3-dimensional int Vector of zeros. +static const Vector kZeros3i(0, 0, 0); +/// 3-dimensional int Vector of ones. +static const Vector kOnes3i(1, 1, 1); +/// 3-dimensional int unit Vector pointing along the X axis. +static const Vector kAxisX3i(1, 0, 0); +/// 3-dimensional int unit Vector pointing along the Y axis. +static const Vector kAxisY3i(0, 1, 0); +/// 3-dimensional int unit Vector pointing along the Z axis. +static const Vector kAxisZ3i(0, 0, 1); + +/// 4-dimensional int Vector of zeros. +static const Vector kZeros4i(0, 0, 0, 0); +/// 4-dimensional int Vector of ones. +static const Vector kOnes4i(1, 1, 1 ,1); +/// 4-dimensional int unit Vector pointing along the X axis. +static const Vector kAxisX4i(1, 0, 0, 0); +/// 4-dimensional int unit Vector pointing along the Z axis. +static const Vector kAxisY4i(0, 1, 0, 0); +/// 4-dimensional int unit Vector pointing along the Y axis. +static const Vector kAxisZ4i(0, 0, 1, 0); +/// 4-dimensional int unit Vector pointing along the W axis. +static const Vector kAxisW4i(0, 0, 0, 1); + +/// Quaternion Identity +static const Quaternion kQuatIdentityf(1.0f, 0.0f, 0.0f, 0.0f); +/// Quaternion Identity +static const Quaternion kQuatIdentityd(1.0, 0.0, 0.0, 0.0); + +// An AffineTransform versoin of the mat4 Identity matrix. +static const AffineTransform kAffineIdentity(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f); +/// @} + +} // namespace mathfu + +#endif // MATHFU_CONSTANTS_H diff --git a/intern/mathfu/mathfu/frustum.h b/intern/mathfu/mathfu/frustum.h new file mode 100644 index 000000000000..9743046abc15 --- /dev/null +++ b/intern/mathfu/mathfu/frustum.h @@ -0,0 +1,75 @@ +#ifndef MATHFU_FRUSTUM_H_ +#define MATHFU_FRUSTUM_H_ + +#include "mathfu/matrix.h" +#include "mathfu/vector.h" +#include + +namespace mathfu { + +static const Vector normalizedBox[8] = { + Vector(-1.0f, -1.0f, -1.0f), + Vector(-1.0f, 1.0f, -1.0f), + Vector(1.0f, 1.0f, -1.0f), + Vector(1.0f, -1.0f, -1.0f), + Vector(-1.0f, -1.0f, 1.0f), + Vector(-1.0f, 1.0f, 1.0f), + Vector(1.0f, 1.0f, 1.0f), + Vector(1.0f, -1.0f, 1.0f) +}; + +static const unsigned short edgeIndices[12][2] = { + {0, 1}, + {1, 2}, + {2, 3}, + {3, 0}, + {4, 5}, + {5, 6}, + {6, 7}, + {7, 0}, + {0, 4}, + {1, 5}, + {2, 6}, + {3, 7} +}; + +inline void FrustumBox(const Matrix& m, std::array, 8>& box) +{ + for (unsigned short i = 0; i < 8; ++i) { + box[i] = m * normalizedBox[i]; + } +} + +inline void FrustumAabb(const Matrix& m, Vector& min, Vector& max) +{ + for (unsigned short i = 0; i < 8; ++i) { + const Vector co = m * normalizedBox[i]; + + if (i == 0) { + min = max = co; + } + else { + min = Vector::Min(min, co); + max = Vector::Max(max, co); + } + } +} + +inline void FrustumEdges(std::array, 8>& box, std::array, 12>& edges) +{ + for (unsigned short i = 0; i < 12; ++i) { + const Vector& p1 = box[edgeIndices[i][0]]; + const Vector& p2 = box[edgeIndices[i][1]]; + + edges[i] = (p2 - p1).Normalized(); + } +} + +inline unsigned short FrustumEdgeVertex(unsigned short edge) +{ + return edgeIndices[edge][0]; +} + +} + +#endif // MATHFU_FRUSTUM_H_ diff --git a/intern/mathfu/mathfu/glsl_mappings.h b/intern/mathfu/mathfu/glsl_mappings.h new file mode 100644 index 000000000000..ae8a2df7184d --- /dev/null +++ b/intern/mathfu/mathfu/glsl_mappings.h @@ -0,0 +1,121 @@ +/* +* Copyright 2014 Google Inc. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef MATHFU_GLSL_MAPPINGS_H_ +#define MATHFU_GLSL_MAPPINGS_H_ + +#include "mathfu/matrix.h" +#include "mathfu/quaternion.h" +#include "mathfu/rect.h" +#include "mathfu/vector.h" + +/// @file mathfu/glsl_mappings.h +/// @brief GLSL compatible data types. +/// @addtogroup mathfu_glsl +/// +/// To simplify the use of MathFu template classes and make it possible to +/// write code that looks similar to +///
GLSL in C++, +/// MathFu provides a set of data types that are similar in style to +/// GLSL Vector and Matrix data types. + +/// @brief Namespace for MathFu library. +namespace mathfu { + +/// @addtogroup mathfu_glsl +/// @{ + +/// 2-dimensional float Vector. +typedef Vector vec2; +/// 3-dimensional float Vector. +typedef Vector vec3; +/// 4-dimensional float Vector. +typedef Vector vec4; + +/// 2-dimensional int Vector. +typedef Vector vec2i; +/// 3-dimensional int Vector. +typedef Vector vec3i; +/// 4-dimensional int Vector. +typedef Vector vec4i; + +/// 2x2 float Matrix. +typedef Matrix mat2; +/// 3x3 float Matrix. +typedef Matrix mat3; +/// 3x3 float Matrix. +typedef Matrix mat4; +/// 4x3 float Matrix. +typedef Matrix mat3x4; + +/// 2-dimensional float packed Vector (VectorPacked). +typedef VectorPacked vec2_packed; +/// 3-dimensional float packed Vector (VectorPacked). +typedef VectorPacked vec3_packed; +/// 4-dimensional float packed Vector (VectorPacked). +typedef VectorPacked vec4_packed; + +/// 2-dimensional int packed Vector (VectorPacked). +typedef VectorPacked vec2i_packed; +/// 3-dimensional int packed Vector (VectorPacked). +typedef VectorPacked vec3i_packed; +/// 4-dimensional int packed Vector (VectorPacked). +typedef VectorPacked vec4i_packed; + +/// Float-based quaternion. Note that this is not technically +/// a GLES type, but is included for convenience. +typedef mathfu::Quaternion quat; + +/// Rect composed of type float. +typedef Rect rectf; +/// Rect composed of type double. +typedef Rect rectd; +/// Rect composed of type int. +typedef Rect recti; + +/// @brief Calculate the cross product of two 3-dimensional Vectors. +/// +/// @param v1 Vector to multiply +/// @param v2 Vector to multiply +/// @return 3-dimensional vector that contains the result. +template +inline Vector cross(const Vector& v1, const Vector& v2) { + return Vector::CrossProduct(v1,v2); +} + +/// @brief Calculate the dot product of two N-dimensional Vectors of any type. +/// +/// @param v1 Vector to multiply +/// @param v2 Vector to multiply +/// @return Scalar dot product result. +template +inline typename TV::Scalar dot(const TV& v1, const TV& v2) { + return TV::DotProduct(v1,v2); +} + +/// @brief Normalize an N-dimensional Vector of an arbitrary type. +/// +/// @param v1 Vector to normalize. +/// @return Normalized vector. +template +inline TV normalize(const TV& v1) { + return v1.Normalized(); +} + +/// @} + +} // namespace mathfu + +#endif // MATHFU_GLSL_MAPPINGS_H_ diff --git a/intern/mathfu/mathfu/hlsl_mappings.h b/intern/mathfu/mathfu/hlsl_mappings.h new file mode 100644 index 000000000000..6db5213217d2 --- /dev/null +++ b/intern/mathfu/mathfu/hlsl_mappings.h @@ -0,0 +1,134 @@ +/* +* Copyright 2017 Google Inc. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef MATHFU_HLSL_MAPPINGS_H_ +#define MATHFU_HLSL_MAPPINGS_H_ + +#include "mathfu/matrix.h" +#include "mathfu/quaternion.h" +#include "mathfu/vector.h" + +/// @file mathfu/hlsl_mappings.h +/// @brief HLSL compatible data types. +/// @addtogroup mathfu_hlsl +/// +/// To simplify the use of MathFu template classes and make it possible to +/// write code that looks similar to +/// HLSL data types in C++, +/// MathFu provides a set of data types that are similar in style to +/// HLSL Vector and Matrix data types. + +/// @brief Namespace for MathFu library. +namespace mathfu { + +/// @addtogroup mathfu_hlsl +/// @{ + +/// Scalar unsigned integer +typedef unsigned int uint; +typedef unsigned int dword; +typedef unsigned short half; + +/// 2-dimensional float Vector. +typedef Vector float2; +/// 3-dimensional float Vector. +typedef Vector float3; +/// 4-dimensional float Vector. +typedef Vector float4; + +/// 2-dimensional int Vector. +typedef Vector int2; +/// 3-dimensional int Vector. +typedef Vector int3; +/// 4-dimensional int Vector. +typedef Vector int4; + +/// 2-dimensional uint Vector. +typedef Vector uint2; +/// 3-dimensional uint Vector. +typedef Vector uint3; +/// 4-dimensional uint Vector. +typedef Vector uint4; + +/// 1x1 float Matrix. +typedef Matrix float1x1; +/// 2x2 float Matrix. +typedef Matrix float2x2; +/// 3x3 float Matrix. +typedef Matrix float3x3; +/// 3x3 float Matrix. +typedef Matrix float4x4; + +/// 1x1 double Matrix. +typedef Matrix double1x1; +/// 2x2 double Matrix. +typedef Matrix double2x2; +/// 3x3 double Matrix. +typedef Matrix double3x3; +/// 3x3 double Matrix. +typedef Matrix double4x4; + +/// 1x1 int Matrix. +typedef Matrix int1x1; +/// 2x2 int Matrix. +typedef Matrix int2x2; +/// 3x3 int Matrix. +typedef Matrix int3x3; +/// 3x3 int Matrix. +typedef Matrix int4x4; + +/// 1x1 int Matrix. +typedef Matrix uint1x1; +/// 2x2 int Matrix. +typedef Matrix uint2x2; +/// 3x3 int Matrix. +typedef Matrix uint3x3; +/// 3x3 int Matrix. +typedef Matrix uint4x4; + +/// @brief Calculate the cross product of two 3-dimensional Vectors. +/// +/// @param v1 Vector to multiply +/// @param v2 Vector to multiply +/// @return 3-dimensional vector that contains the result. +template +inline Vector cross(const Vector& v1, const Vector& v2) { + return Vector::CrossProduct(v1,v2); +} + +/// @brief Calculate the dot product of two N-dimensional Vectors of any type. +/// +/// @param v1 Vector to multiply +/// @param v2 Vector to multiply +/// @return Scalar dot product result. +template +inline typename TV::Scalar dot(const TV& v1, const TV& v2) { + return TV::DotProduct(v1,v2); +} + +/// @brief Normalize an N-dimensional Vector of an arbitrary type. +/// +/// @param v1 Vector to normalize. +/// @return Normalized vector. +template +inline TV normalize(const TV& v1) { + return v1.Normalized(); +} + +/// @} + +} // namespace mathfu + +#endif // MATHFU_HLSL_MAPPINGS_H_ diff --git a/intern/mathfu/mathfu/internal/disable_warnings_begin.h b/intern/mathfu/mathfu/internal/disable_warnings_begin.h new file mode 100644 index 000000000000..9f7bee1fcfad --- /dev/null +++ b/intern/mathfu/mathfu/internal/disable_warnings_begin.h @@ -0,0 +1,35 @@ +/* +* Copyright 2016 Google Inc. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +// Suppress pedantic warnings. +// To re-enable, include "mathfu/internal/disable_warnings_end.h". +// +// We need this to use anonymous unions and structs, which generate the +// the following warning in GCC and Clang, +// error: ISO C++ prohibits anonymous structs [-Werror=pedantic] +// The only way to suppress this warning is to turn off all pedantic warnings. + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#pragma GCC diagnostic ignored "-Wignored-qualifiers" +#endif // defined(__GNUC__) + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpedantic" +#pragma clang diagnostic ignored "-Wignored-qualifiers" +#endif // defined(__clang__) diff --git a/intern/mathfu/mathfu/internal/disable_warnings_end.h b/intern/mathfu/mathfu/internal/disable_warnings_end.h new file mode 100644 index 000000000000..8639ff738352 --- /dev/null +++ b/intern/mathfu/mathfu/internal/disable_warnings_end.h @@ -0,0 +1,23 @@ +/* +* Copyright 2016 Google Inc. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif // defined(__clang__) + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif // defined(__GNUC__) diff --git a/intern/mathfu/mathfu/internal/matrix_4x4_simd.h b/intern/mathfu/mathfu/internal/matrix_4x4_simd.h new file mode 100644 index 000000000000..803da24e27e5 --- /dev/null +++ b/intern/mathfu/mathfu/internal/matrix_4x4_simd.h @@ -0,0 +1,478 @@ +/* +* Copyright 2014 Google Inc. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef MATHFU_MATRIX_4X4_SIMD_H_ +#define MATHFU_MATRIX_4X4_SIMD_H_ + +#include "mathfu/matrix.h" + +#ifdef MATHFU_COMPILE_WITH_SIMD +#include "vectorial/simd4x4f.h" +#endif + +/// @file mathfu/internal/matrix_4x4_simd.h MathFu Matrix +/// Specialization +/// @brief 4x4 specialization of mathfu::Matrix for SIMD optimized builds. +/// @see mathfu::Matrix + +namespace mathfu { + +#ifdef MATHFU_COMPILE_WITH_SIMD + +static const Vector kAffineWColumn(0.0f, 0.0f, 0.0f, 1.0f); + +/// @cond MATHFU_INTERNAL +template <> +class Matrix { + public: + Matrix() {} + + inline Matrix(const Matrix& m) { + simd.x = m.simd.x; + simd.y = m.simd.y; + simd.z = m.simd.z; + simd.w = m.simd.w; + } + + explicit inline Matrix(const float& s) { + simd4f v = simd4f_create(s, s, s, s); + simd = simd4x4f_create(v, v, v, v); + } + + inline Matrix(const float& s00, const float& s10, const float& s20, + const float& s30, const float& s01, const float& s11, + const float& s21, const float& s31, const float& s02, + const float& s12, const float& s22, const float& s32, + const float& s03, const float& s13, const float& s23, + const float& s33) { + simd = simd4x4f_create( + simd4f_create(s00, s10, s20, s30), simd4f_create(s01, s11, s21, s31), + simd4f_create(s02, s12, s22, s32), simd4f_create(s03, s13, s23, s33)); + } + + explicit inline Matrix(const float* m) { + simd = + simd4x4f_create(simd4f_create(m[0], m[1], m[2], m[3]), + simd4f_create(m[4], m[5], m[6], m[7]), + simd4f_create(m[8], m[9], m[10], m[11]), + simd4f_create(m[12], m[13], m[14], m[15])); + } + + explicit inline Matrix(const float m[4][4]) { + simd = + simd4x4f_create(simd4f_create(m[0][0], m[0][1], m[0][2], m[0][3]), + simd4f_create(m[1][0], m[1][1], m[1][2], m[1][3]), + simd4f_create(m[2][0], m[2][1], m[2][2], m[2][3]), + simd4f_create(m[3][0], m[3][1], m[3][2], m[3][3])); + } + + inline Matrix(const Vector& column0, + const Vector& column1, + const Vector& column2, + const Vector& column3) { +#if defined(MATHFU_COMPILE_WITH_PADDING) + simd = simd4x4f_create(column0.simd, column1.simd, + column2.simd, column3.simd); +#else + simd = simd4x4f_create( + simd4f_create(column0[0], column0[1], column0[2], column0[3]), + simd4f_create(column1[0], column1[1], column1[2], column1[3]), + simd4f_create(column2[0], column2[1], column2[2], column2[3]), + simd4f_create(column3[0], column3[1], column3[2], column3[3])); +#endif // defined(MATHFU_COMPILE_WITH_PADDING) + } + + explicit inline Matrix(const VectorPacked* const vectors) { + simd.x = simd4f_uload4(vectors[0].data); + simd.y = simd4f_uload4(vectors[1].data); + simd.z = simd4f_uload4(vectors[2].data); + simd.w = simd4f_uload4(vectors[3].data); + } + + inline const float& operator()(const int i, const int j) const { + return data_[j][i]; + } + + inline float& operator()(const int i, const int j) { + return data_[j][i]; + } + + inline const float& operator()(const int i) const { + return this->operator[](i); + } + + inline float& operator()(const int i) { return this->operator[](i); } + + inline const float& operator[](const int i) const { + return reinterpret_cast(data_)[i]; + } + + inline float& operator[](const int i) { + return reinterpret_cast(data_)[i]; + } + + inline void Pack(VectorPacked* const vector) const { + simd4f_ustore4(simd.x, vector[0].data); + simd4f_ustore4(simd.y, vector[1].data); + simd4f_ustore4(simd.z, vector[2].data); + simd4f_ustore4(simd.w, vector[3].data); + } + + inline void Pack(float a[4][4]) const { + MATHFU_MAT_OPERATION(simd4f_ustore4(data_[i].simd, a[i])); + } + + inline void Pack(float a[16]) const { + MATHFU_MAT_OPERATION(simd4f_ustore4(data_[i].simd, &a[i * 4])); + } + + inline float (&Data() const)[4][4] WARN_UNUSED_RESULT { + return const_cast(float_data_); + } + + inline Vector& GetColumn(const int i) WARN_UNUSED_RESULT { + return data_[i]; + } + + inline const Vector& GetColumn(const int i) const WARN_UNUSED_RESULT { + return data_[i]; + } + + inline Vector GetRow(const int i) const WARN_UNUSED_RESULT { + Vector v; + for (int j = 0; j < 4; ++j) { + v[j] = data_[j][i]; + } + return v; + } + + inline Matrix operator-() const { + Matrix m(0.f); + simd4x4f_sub(&m.simd, &simd, + &m.simd); + return m; + } + + inline Matrix operator+(const Matrix& m) const { + Matrix return_m; + simd4x4f_add(&simd, &m.simd, + &return_m.simd); + return return_m; + } + + inline Matrix operator-(const Matrix& m) const { + Matrix return_m; + simd4x4f_sub(&simd, &m.simd, + &return_m.simd); + return return_m; + } + + inline Matrix operator*(const float& s) const { + Matrix m(s); + simd4x4f_mul(&m.simd, &simd, + &m.simd); + return m; + } + + inline Matrix operator/(const float& s) const { + Matrix m(1 / s); + simd4x4f_mul(&m.simd, &simd, + &m.simd); + return m; + } + + inline Vector operator*(const Vector& v) const { + Vector return_v; + simd4f temp_simd = simd4f_create(v[0], v[1], v[2], 1.0f); + simd4x4f_matrix_vector_mul(&simd, &temp_simd, &return_v.simd); + return_v *= (1.0f / return_v.data_[3]); + return return_v; + } + + inline Vector operator*(const Vector& v) const { + Vector return_v; + simd4x4f_matrix_vector_mul(&simd, &v.simd, + &return_v.simd); + return return_v; + } + + inline Matrix operator*(const Matrix& m) const { + Matrix return_m; + simd4x4f_matrix_mul(&simd, &m.simd, + &return_m.simd); + return return_m; + } + + friend inline Vector operator*(const Vector& v, const Matrix& m) { + return Vector( + simd4f_get_x(simd4f_dot4(v.simd, m.simd.x)), + simd4f_get_x(simd4f_dot4(v.simd, m.simd.y)), + simd4f_get_x(simd4f_dot4(v.simd, m.simd.z)), + simd4f_get_x(simd4f_dot4(v.simd, m.simd.w))); + } + + friend inline Vector operator*(const Vector& v, const Matrix& m) { + Vector return_v; + simd4f temp_simd = simd4f_create(v[0], v[1], v[2], 1.0f); + + return_v.data_[0] = simd4f_get_x(simd4f_dot4(temp_simd, m.simd.x)); + return_v.data_[1] = simd4f_get_x(simd4f_dot4(temp_simd, m.simd.y)); + return_v.data_[2] = simd4f_get_x(simd4f_dot4(temp_simd, m.simd.z)); + return_v.data_[3] = simd4f_get_x(simd4f_dot4(temp_simd, m.simd.w)); + + return_v *= (1.0f / return_v.data_[3]); + + return return_v; + } + + inline Matrix Inverse() const WARN_UNUSED_RESULT { + Matrix return_m; + simd4x4f_inverse(&simd, &return_m.simd); + return return_m; + } + + inline bool InverseWithDeterminantCheck( + Matrix* const inverse) const { + return fabs(simd4f_get_x(simd4x4f_inverse(&simd, + &inverse->simd))) >= + Constants::GetDeterminantThreshold(); + } + + /// Calculate the transpose of matrix. + /// @return The transpose of the specified matrix. + inline Matrix Transpose() const WARN_UNUSED_RESULT { + Matrix transpose; + simd4x4f_transpose(&simd, &transpose.simd); + return transpose; + } + + inline Vector TranslationVector3D() const WARN_UNUSED_RESULT { + return Vector(simd.w); + } + + inline Matrix RotationMatrix() const WARN_UNUSED_RESULT { + return ToRotationMatrix(*this); + } + + inline Vector ScaleVector3D() const WARN_UNUSED_RESULT { + return ToScaleVector3DHelper(*this); + } + + inline Matrix& operator+=(const Matrix& m) { + simd4x4f_add(&simd, &m.simd, &simd); + return *this; + } + + inline Matrix& operator-=(const Matrix& m) { + simd4x4f_sub(&simd, &m.simd, &simd); + return *this; + } + + inline Matrix& operator*=(const float& s) { + Matrix m(s); + simd4x4f_mul(&m.simd, &simd, &simd); + return *this; + } + + inline Matrix& operator/=(const float& s) { + Matrix m(1 / s); + simd4x4f_mul(&m.simd, &simd, &simd); + return *this; + } + + inline Matrix operator*=(const Matrix& m) { + Matrix copy_of_this(*this); + simd4x4f_matrix_mul(©_of_this.simd, &m.simd, + &simd); + return *this; + } + + template + static inline WARN_UNUSED_RESULT Matrix FromType(const CompatibleT& compatible) { + return FromTypeHelper(compatible); + } + + template + static inline WARN_UNUSED_RESULT CompatibleT ToType(const Matrix& m) { + return ToTypeHelper(m); + } + + static inline WARN_UNUSED_RESULT Matrix OuterProduct(const Vector& v1, + const Vector& v2) { + Matrix m; + m.simd = + simd4x4f_create(simd4f_mul(v1.simd, simd4f_splat(v2[0])), + simd4f_mul(v1.simd, simd4f_splat(v2[1])), + simd4f_mul(v1.simd, simd4f_splat(v2[2])), + simd4f_mul(v1.simd, simd4f_splat(v2[3]))); + return m; + } + + static inline WARN_UNUSED_RESULT Matrix HadamardProduct(const Matrix& m1, + const Matrix& m2) WARN_UNUSED_RESULT { + Matrix return_m; + simd4x4f_mul(&m1.simd, &m2.simd, + &return_m.simd); + return return_m; + } + + static inline WARN_UNUSED_RESULT Matrix Identity() WARN_UNUSED_RESULT { + Matrix return_m; + simd4x4f_identity(&return_m.simd); + return return_m; + } + + static inline WARN_UNUSED_RESULT Matrix FromTranslationVector( + const Vector& v) WARN_UNUSED_RESULT { + return Matrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, v[0], v[1], + v[2], 1); + } + + static inline WARN_UNUSED_RESULT Vector ToScaleVector(const Matrix& m) WARN_UNUSED_RESULT { + return ToScaleVectorHelper(m); + } + + static inline WARN_UNUSED_RESULT Matrix FromScaleVector(const Vector& v) WARN_UNUSED_RESULT { + return Matrix(v[0], 0, 0, 0, 0, v[1], 0, 0, 0, 0, v[2], 0, 0, 0, + 0, 1); + } + + static inline WARN_UNUSED_RESULT Matrix ToRotationMatrix(const Matrix& m) WARN_UNUSED_RESULT { + return Matrix(m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], + m[10]); + } + + static inline WARN_UNUSED_RESULT Matrix FromRotationMatrix(const Matrix& m) WARN_UNUSED_RESULT { + return Matrix(m[0], m[1], m[2], 0, m[3], m[4], m[5], 0, m[6], + m[7], m[8], 0, 0, 0, 0, 1); + } + + /// @brief Constructs a Matrix from an AffineTransform. + /// + /// @param affine An AffineTransform reference to be used to construct + /// a Matrix by adding in the 'w' row of [0, 0, 0, 1]. + static inline WARN_UNUSED_RESULT Matrix FromAffineTransform( + const AffineTransform& affine) WARN_UNUSED_RESULT { + Matrix m; + m.simd.x = simd4f_create(affine[0], affine[1], affine[2], 0.0f); + m.simd.y = simd4f_create(affine[3], affine[4], affine[5], 0.0f); + m.simd.z = simd4f_create(affine[6], affine[7], affine[8], 0.0f); + m.simd.w = simd4f_create(affine[9], affine[10], affine[11], 1.0f); + return m; + } + + /// @brief Converts a Matrix into an AffineTransform. + /// + /// @param m A Matrix reference to be converted into an + /// AffineTransform by dropping the fixed 'w' row. + /// + /// @return Returns an AffineTransform that contains the essential + /// transformation data from the Matrix. + static inline WARN_UNUSED_RESULT AffineTransform ToAffineTransform(const Matrix& m) WARN_UNUSED_RESULT { + return AffineTransform(m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], + m[10], m[12], m[13], m[14]); + } + + /// Create a 4x4 perpective matrix. + /// @handedness: 1.0f for RH, -1.0f for LH + static inline WARN_UNUSED_RESULT Matrix Perspective(float fovy, float aspect, + float znear, float zfar, + float handedness = 1.0f) WARN_UNUSED_RESULT { + return PerspectiveHelper(fovy, aspect, znear, zfar, handedness); + } + + /// Create a 4x4 perpective matrix. + /// @handedness: 1.0f for RH, -1.0f for LH + static inline WARN_UNUSED_RESULT Matrix Perspective(float left, float right, + float bottom, float top, + float znear, float zfar, + float handedness = 1.0f) WARN_UNUSED_RESULT { + return PerspectiveHelper(left, right, bottom, top, znear, zfar, handedness); + } + + /// Create a 4x4 orthographic matrix. + /// @param handedness 1.0f for RH, -1.0f for LH + static inline WARN_UNUSED_RESULT Matrix Ortho(float left, float right, float bottom, + float top, float znear, float zfar, + float handedness = 1.0f) WARN_UNUSED_RESULT { + return OrthoHelper(left, right, bottom, top, znear, zfar, handedness); + } + + /// Create a 3-dimensional camera matrix. + /// @param at The look-at target of the camera. + /// @param eye The position of the camera. + /// @param up The up vector in the world, for example (0, 1, 0) if the + /// @handedness: 1.0f for RH, -1.0f for LH + /// TODO: Change default handedness to 1.0f, to match Perspective(). + /// y-axis is up. + static inline WARN_UNUSED_RESULT Matrix LookAt(const Vector& at, + const Vector& eye, + const Vector& up, + float handedness = -1.0f) WARN_UNUSED_RESULT { + return LookAtHelper(at, eye, up, handedness); + } + + /// @brief Get the 3D position in object space from a window coordinate. + /// + /// @param window_coord The window coordinate. The z value is for depth. + /// A window coordinate on the near plane will have 0 as the z value. + /// And a window coordinate on the far plane will have 1 as the z value. + /// z value should be with in [0, 1] here. + /// @param model_view The Model View matrix. + /// @param projection The projection matrix. + /// @param window_width Width of the window. + /// @param window_height Height of the window. + /// @return the mapped 3D position in object space. + static inline WARN_UNUSED_RESULT Vector UnProject( + const Vector& window_coord, + const Matrix& model_view, + const Matrix& projection, const float window_width, + const float window_height) WARN_UNUSED_RESULT { + Vector result; + UnProjectHelper(window_coord, model_view, projection, window_width, + window_height, result); + return result; + } + + // Dimensions of the matrix. + /// Number of rows in the matrix. + static const int kRows = 4; + /// Number of columns in the matrix. + static const int kColumns = 4; + /// Total number of elements in the matrix. + static const int kElements = 4 * 4; + + MATHFU_DEFINE_CLASS_SIMD_AWARE_NEW_DELETE + + // Contents of the Matrix in different representations to work around + // strict aliasing rules. + union { + simd4x4f simd; + struct { + Vector data_[4]; + }; + float float_data_[4][4]; + }; +}; + +inline Matrix operator*(const float& s, const Matrix& m) { + return m * s; +} + +/// @endcond +#endif // MATHFU_COMPILE_WITH_SIMD +} // namespace mathfu + +#endif // MATHFU_MATRIX_4X4_SIMD_H_ diff --git a/intern/mathfu/mathfu/internal/vector_2.h b/intern/mathfu/mathfu/internal/vector_2.h new file mode 100644 index 000000000000..8f2de59ef1d2 --- /dev/null +++ b/intern/mathfu/mathfu/internal/vector_2.h @@ -0,0 +1,194 @@ +/* +* Copyright 2016 Google Inc. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef MATHFU_INTERNAL_VECTOR_2_H_ +#define MATHFU_INTERNAL_VECTOR_2_H_ + +#include "mathfu/vector.h" + +namespace mathfu { + +template +class Vector { + public: + typedef T Scalar; + static const int d = 2; + + inline Vector() {} + + inline Vector(const Vector& v) { + MATHFU_VECTOR_OPERATION(data_[i] = v.data_[i]); + } + + template + explicit inline Vector(const Vector& v) { + MATHFU_VECTOR_OPERATION(data_[i] = static_cast(v[i])); + } + + explicit inline Vector(const T& s) { MATHFU_VECTOR_OPERATION(data_[i] = s); } + + explicit inline Vector(const T* a) { + MATHFU_VECTOR_OPERATION(data_[i] = a[i]); + } + + inline Vector(const T& s1, const T& s2) { + x = s1; + y = s2; + } + + explicit inline Vector(const VectorPacked& vector) { + MATHFU_VECTOR_OPERATION(data_[i] = vector.data[i]); + } + + inline T& operator()(const int i) WARN_UNUSED_RESULT { return data_[i]; } + + inline const T& operator()(const int i) const WARN_UNUSED_RESULT { return data_[i]; } + + inline T& operator[](const int i) WARN_UNUSED_RESULT { return data_[i]; } + + inline const T& operator[](const int i) const WARN_UNUSED_RESULT { return data_[i]; } + + inline Vector xy() WARN_UNUSED_RESULT { return Vector(x, y); } + + inline const Vector xy() const WARN_UNUSED_RESULT { return Vector(x, y); } + + inline void Pack(VectorPacked* const vector) const { + MATHFU_VECTOR_OPERATION(vector->data[i] = data_[i]); + } + + inline void Pack(T a[2]) const { + MATHFU_VECTOR_OPERATION(a[i] = data_[i]); + } + + inline const T (&Data() const)[2] WARN_UNUSED_RESULT { + return data_; + } + + inline T LengthSquared() const WARN_UNUSED_RESULT { return LengthSquaredHelper(*this); } + + inline T Length() const WARN_UNUSED_RESULT { return LengthHelper(*this); } + + inline T Normalize() { return NormalizeHelper(*this); } + + inline T SafeNormalize() { return SafeNormalizeHelper(*this); } + + inline Vector Normalized() const WARN_UNUSED_RESULT { return NormalizedHelper(*this); } + + inline Vector SafeNormalized(const Vector& v) const WARN_UNUSED_RESULT { + return SafeNormalizedHelper(*this, v); + } + + static inline WARN_UNUSED_RESULT bool FuzzyZero(const Vector& v) { + return FuzzyZeroHelper(v); + } + + template + static inline WARN_UNUSED_RESULT Vector FromType(const CompatibleT& compatible) { + return FromTypeHelper(compatible); + } + + template + static inline WARN_UNUSED_RESULT CompatibleT ToType(const Vector& v) { + return ToTypeHelper(v); + } + + static inline WARN_UNUSED_RESULT T DotProduct(const Vector& v1, const Vector& v2) { + return DotProductHelper(v1, v2); + } + + static inline WARN_UNUSED_RESULT Vector HadamardProduct(const Vector& v1, + const Vector& v2) { + return HadamardProductHelper(v1, v2); + } + + static inline WARN_UNUSED_RESULT Vector Lerp(const Vector& v1, + const Vector& v2, const T percent) { + return LerpHelper(v1, v2, percent); + } + + static inline WARN_UNUSED_RESULT Vector RandomInRange(const Vector& min, + const Vector& max) { + return RandomInRangeHelper(min, max); + } + + static inline WARN_UNUSED_RESULT Vector Max(const Vector& v1, + const Vector& v2) { + return MaxHelper(v1, v2); + } + + static inline WARN_UNUSED_RESULT Vector Min(const Vector& v1, + const Vector& v2) { + return MinHelper(v1, v2); + } + + MATHFU_DEFINE_CLASS_SIMD_AWARE_NEW_DELETE + +#include "mathfu/internal/disable_warnings_begin.h" + union { + T data_[2]; + struct { + T x; + T y; + }; + }; +#include "mathfu/internal/disable_warnings_end.h" +}; + +template +struct VectorPacked { + /// Create an uninitialized VectorPacked. + VectorPacked() {} + + /// Create a VectorPacked from a Vector. + /// + /// Both VectorPacked and Vector must have the same number of dimensions. + /// @param vector Vector to create the VectorPacked from. + explicit VectorPacked(const Vector& vector) { vector.Pack(this); } + + explicit VectorPacked(const T * const s) :x(s[0]), y(s[1]) {} + + /// Copy a Vector to a VectorPacked. + /// + /// Both VectorPacked and Vector must have the same number of dimensions. + /// @param vector Vector to copy to the VectorPacked. + /// @returns A reference to this VectorPacked. + VectorPacked& operator=(const Vector& vector) { + vector.Pack(this); + return *this; + } + + inline const T& operator[](int i) const { + return data[i]; + } + + inline T& operator[](int i) { + return data[i]; + } + +#include "mathfu/internal/disable_warnings_begin.h" + /// Elements of the packed vector one per dimension. + union { + T data[2]; + struct { + T x; + T y; + }; + }; +#include "mathfu/internal/disable_warnings_end.h" +}; + +} // namespace mathfu + +#endif // MATHFU_INTERNAL_VECTOR_2_H_ diff --git a/intern/mathfu/mathfu/internal/vector_2_simd.h b/intern/mathfu/mathfu/internal/vector_2_simd.h new file mode 100644 index 000000000000..b36552adb3b1 --- /dev/null +++ b/intern/mathfu/mathfu/internal/vector_2_simd.h @@ -0,0 +1,276 @@ +/* +* Copyright 2014 Google Inc. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef MATHFU_VECTOR_2_SIMD_H_ +#define MATHFU_VECTOR_2_SIMD_H_ + +#include "mathfu/internal/vector_2.h" +#include "mathfu/utilities.h" + +#include + +/// @file mathfu/internal/vector_2_simd.h MathFu Vector Specialization +/// @brief 2-dimensional specialization of mathfu::Vector for SIMD optimized +/// builds. +/// @see mathfu::Vector + +#if !defined(MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT) && defined(__ARM_NEON__) +#include +#endif + +namespace mathfu { + +#if !defined(MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT) && defined(__ARM_NEON__) +/// @cond MATHFU_INTERNAL +template <> +class Vector { + public: + typedef float Scalar; + + inline Vector() {} + + inline Vector(const Vector& v) { simd = v.simd; } + + explicit inline Vector(const Vector& v) { + data_[0] = static_cast(v[0]); + data_[1] = static_cast(v[1]); + } + + explicit inline Vector(const simd2f& v) { simd = v; } + + explicit inline Vector(const float& s) { simd = simd2f_create(s, s); } + + inline Vector(const float& s1, const float& s2) { + simd = simd2f_create(s1, s2); + } + + explicit inline Vector(const float* v) { simd = simd2f_uload2(v); } + + explicit inline Vector(const VectorPacked& vector) { + simd = simd2f_uload2(vector.data); + } + + inline float& operator()(const int i) WARN_UNUSED_RESULT { return data_[i]; } + + inline const float& operator()(const int i) const WARN_UNUSED_RESULT { return data_[i]; } + + inline float& operator[](const int i) WARN_UNUSED_RESULT { return data_[i]; } + + inline const float& operator[](const int i) const WARN_UNUSED_RESULT { return data_[i]; } + + inline void Pack(VectorPacked* const vector) const { + simd2f_ustore2(simd, vector->data); + } + + inline void Pack(float a[2]) const { + simd2f_ustore2(simd, a); + } + + inline const float (&Data() const)[2] WARN_UNUSED_RESULT { + return data_; + } + + inline Vector operator-() const { + return Vector(simd2f_sub(simd2f_zero(), simd)); + } + + inline Vector operator*(const Vector& v) const { + return Vector(simd2f_mul(simd, v.simd)); + } + + inline Vector operator/(const Vector& v) const { + return Vector(simd2f_div(simd, v.simd)); + } + + inline Vector operator+(const Vector& v) const { + return Vector(simd2f_add(simd, v.simd)); + } + + inline Vector operator-(const Vector& v) const { + return Vector(simd2f_sub(simd, v.simd)); + } + + inline Vector operator*(const float& s) const { + return Vector(simd2f_mul(simd, simd2f_splat(s))); + } + + inline Vector operator/(const float& s) const { + return Vector(simd2f_div(simd, simd2f_splat(s))); + } + + inline Vector operator+(const float& s) const { + return Vector(simd2f_add(simd, simd2f_splat(s))); + } + + inline Vector operator-(const float& s) const { + return Vector(simd2f_sub(simd, simd2f_splat(s))); + } + + inline Vector& operator*=(const Vector& v) { + simd = simd2f_mul(simd, v.simd); + return *this; + } + + inline Vector& operator/=(const Vector& v) { + simd = simd2f_div(simd, v.simd); + return *this; + } + + inline Vector& operator+=(const Vector& v) { + simd = simd2f_add(simd, v.simd); + return *this; + } + + inline Vector& operator-=(const Vector& v) { + simd = simd2f_sub(simd, v.simd); + return *this; + } + + inline Vector& operator*=(const float& s) { + simd = simd2f_mul(simd, simd2f_splat(s)); + return *this; + } + + inline Vector& operator/=(const float& s) { + simd = simd2f_div(simd, simd2f_splat(s)); + return *this; + } + + inline Vector& operator+=(const float& s) { + simd = simd2f_add(simd, simd2f_splat(s)); + return *this; + } + + inline Vector& operator-=(const float& s) { + simd = simd2f_sub(simd, simd2f_splat(s)); + return *this; + } + + inline bool operator==(const Vector& v) const { + for (int i = 0; i < 2; ++i) { + if ((*this)[i] != v[i]) return false; + } + return true; + } + + inline bool operator!=(const Vector& v) const { + return !operator==(v); + } + + inline float LengthSquared() const WARN_UNUSED_RESULT { + return simd2f_get_x(simd2f_dot2(simd, simd)); + } + + inline float Length() const WARN_UNUSED_RESULT { return simd2f_get_x(simd2f_length2(simd)); } + + inline float Normalize() { + const float length = Length(); + simd = simd2f_mul(simd, simd2f_splat(1 / length)); + return length; + } + + inline float SafeNormalize() { + const float length = Length(); + if (!FuzzyZero(length)) { + simd = simd2f_mul(simd, simd2f_splat(1 / length)); + } + return length; + } + + inline Vector Normalized() const WARN_UNUSED_RESULT { + return Vector(simd2f_normalize2(simd)); + } + + inline Vector SafeNormalized(const Vector& v) const WARN_UNUSED_RESULT { + if (FuzzyZeroHelper(Length())) { + return v; + } + return Normalized(); + } + + template + static inline WARN_UNUSED_RESULT Vector FromType(const CompatibleT& compatible) { + return FromTypeHelper(compatible); + } + + template + static inline WARN_UNUSED_RESULT CompatibleT ToType(const Vector& v) { + return ToTypeHelper(v); + } + + static inline WARN_UNUSED_RESULT float DotProduct(const Vector& v1, + const Vector& v2) { + return simd2f_get_x(simd2f_dot2(v1.simd, v2.simd)); + } + + static inline WARN_UNUSED_RESULT Vector HadamardProduct(const Vector& v1, + const Vector& v2) { + return Vector(simd2f_mul(v1.simd, v2.simd)); + } + + static inline WARN_UNUSED_RESULT Vector Lerp(const Vector& v1, + const Vector& v2, + float percent) { + const Vector percentv(percent); + const Vector one_minus_percent( + simd2f_sub(simd2f_splat(1.0f), percentv.simd)); + return Vector( + simd2f_add(simd2f_mul(one_minus_percent.simd, v1.simd), + simd2f_mul(percentv.simd, v2.simd))); + } + + /// Generates a random vector, where the range for each component is + /// bounded by min and max. + static inline WARN_UNUSED_RESULT Vector RandomInRange(const Vector& min, + const Vector& max) { + return Vector(mathfu::RandomInRange(min[0], max[0]), + mathfu::RandomInRange(min[1], max[1])); + } + + static inline WARN_UNUSED_RESULT Vector Max(const Vector& v1, + const Vector& v2) { + return Vector(std::max(v1[0], v2[0]), std::max(v1[1], v2[1])); + } + + static inline WARN_UNUSED_RESULT Vector Min(const Vector& v1, + const Vector& v2) { + return Vector(std::min(v1[0], v2[0]), std::min(v1[1], v2[1])); + } + + MATHFU_DEFINE_CLASS_SIMD_AWARE_NEW_DELETE + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpedantic" +#endif // defined(__clang__) + union { + simd2f simd; + float data_[2]; + struct { + float x; + float y; + }; + }; +#if defined(__clang__) +#pragma clang diagnostic pop +#endif // defined(__clang__) +}; +/// @endcond +#endif // !defined(MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT) && + // defined(__ARM_NEON__) + +} // namespace mathfu + +#endif // MATHFU_VECTOR_2_SIMD_H_ diff --git a/intern/mathfu/mathfu/internal/vector_3.h b/intern/mathfu/mathfu/internal/vector_3.h new file mode 100644 index 000000000000..9988edb08bf4 --- /dev/null +++ b/intern/mathfu/mathfu/internal/vector_3.h @@ -0,0 +1,212 @@ +/* +* Copyright 2016 Google Inc. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef MATHFU_INTERNAL_VECTOR_3_H_ +#define MATHFU_INTERNAL_VECTOR_3_H_ + +#include "mathfu/vector.h" + +namespace mathfu { + +template +class Vector { + public: + typedef T Scalar; + static const int d = 3; + + inline Vector() {} + + inline Vector(const Vector& v) { + MATHFU_VECTOR_OPERATION(data_[i] = v.data_[i]); + } + + template + explicit inline Vector(const Vector& v) { + MATHFU_VECTOR_OPERATION(data_[i] = static_cast(v[i])); + } + + explicit inline Vector(const T& s) { MATHFU_VECTOR_OPERATION(data_[i] = s); } + + explicit inline Vector(const T* a) { + MATHFU_VECTOR_OPERATION(data_[i] = a[i]); + } + + inline Vector(const T& s1, const T& s2, const T& s3) { + x = s1; + y = s2; + z = s3; + } + + inline Vector(const Vector& v12, const T& s3) { + x = v12[0]; + y = v12[1]; + z = s3; + } + + explicit inline Vector(const VectorPacked& vector) { + MATHFU_VECTOR_OPERATION(data_[i] = vector.data[i]); + } + + inline T& operator()(const int i) WARN_UNUSED_RESULT { return data_[i]; } + + inline const T& operator()(const int i) const WARN_UNUSED_RESULT { return data_[i]; } + + inline T& operator[](const int i) WARN_UNUSED_RESULT { return data_[i]; } + + inline const T& operator[](const int i) const WARN_UNUSED_RESULT { return data_[i]; } + + inline Vector xyz() WARN_UNUSED_RESULT { return Vector(x, y, z); } + + inline const Vector xyz() const WARN_UNUSED_RESULT { return Vector(x, y, z); } + + inline Vector xy() WARN_UNUSED_RESULT { return Vector(x, y); } + + inline const Vector xy() const WARN_UNUSED_RESULT { return Vector(x, y); } + + inline void Pack(VectorPacked* const vector) const { + MATHFU_VECTOR_OPERATION(vector->data[i] = data_[i]); + } + + inline void Pack(T a[3]) const { + MATHFU_VECTOR_OPERATION(a[i] = data_[i]); + } + + inline const T (&Data() const)[3] WARN_UNUSED_RESULT { + return data_; + } + + inline T LengthSquared() const WARN_UNUSED_RESULT { return LengthSquaredHelper(*this); } + + inline T Length() const WARN_UNUSED_RESULT { return LengthHelper(*this); } + + inline T Normalize() { return NormalizeHelper(*this); } + + inline T SafeNormalize() { return SafeNormalizeHelper(*this); } + + inline Vector Normalized() const WARN_UNUSED_RESULT { return NormalizedHelper(*this); } + + inline Vector SafeNormalized(const Vector& v) const WARN_UNUSED_RESULT { + return SafeNormalizedHelper(*this, v); + } + + static inline WARN_UNUSED_RESULT bool FuzzyZero(const Vector& v) { + return FuzzyZeroHelper(v); + } + + template + static inline WARN_UNUSED_RESULT Vector FromType(const CompatibleT& compatible) { + return FromTypeHelper(compatible); + } + + template + static inline WARN_UNUSED_RESULT CompatibleT ToType(const Vector& v) { + return ToTypeHelper(v); + } + + static inline WARN_UNUSED_RESULT T DotProduct(const Vector& v1, const Vector& v2) { + return DotProductHelper(v1, v2); + } + + static inline WARN_UNUSED_RESULT Vector HadamardProduct(const Vector& v1, + const Vector& v2) { + return HadamardProductHelper(v1, v2); + } + + static inline WARN_UNUSED_RESULT Vector CrossProduct(const Vector& v1, + const Vector& v2) { + return CrossProductHelper(v1, v2); + } + + static inline WARN_UNUSED_RESULT Vector Lerp(const Vector& v1, + const Vector& v2, const T percent) { + return LerpHelper(v1, v2, percent); + } + + static inline WARN_UNUSED_RESULT Vector RandomInRange(const Vector& min, + const Vector& max) { + return RandomInRangeHelper(min, max); + } + + static inline WARN_UNUSED_RESULT Vector Max(const Vector& v1, + const Vector& v2) { + return MaxHelper(v1, v2); + } + + static inline WARN_UNUSED_RESULT Vector Min(const Vector& v1, + const Vector& v2) { + return MinHelper(v1, v2); + } + + MATHFU_DEFINE_CLASS_SIMD_AWARE_NEW_DELETE + +#include "mathfu/internal/disable_warnings_begin.h" + union { + T data_[3]; + struct { + T x; + T y; + T z; + }; + }; +#include "mathfu/internal/disable_warnings_end.h" +}; + +template +struct VectorPacked { + /// Create an uninitialized VectorPacked. + VectorPacked() {} + + /// Create a VectorPacked from a Vector. + /// + /// Both VectorPacked and Vector must have the same number of dimensions. + /// @param vector Vector to create the VectorPacked from. + explicit VectorPacked(const Vector& vector) { vector.Pack(this); } + + explicit VectorPacked(const T * const s) :x(s[0]), y(s[1]), z(s[2]) {} + + /// Copy a Vector to a VectorPacked. + /// + /// Both VectorPacked and Vector must have the same number of dimensions. + /// @param vector Vector to copy to the VectorPacked. + /// @returns A reference to this VectorPacked. + VectorPacked& operator=(const Vector& vector) { + vector.Pack(this); + return *this; + } + + inline const T& operator[](int i) const { + return data[i]; + } + + inline T& operator[](int i) { + return data[i]; + } + +#include "mathfu/internal/disable_warnings_begin.h" + /// Elements of the packed vector one per dimension. + union { + T data[3]; + struct { + T x; + T y; + T z; + }; + }; +#include "mathfu/internal/disable_warnings_end.h" +}; + +} // namespace mathfu + +#endif // MATHFU_INTERNAL_VECTOR_3_H_ diff --git a/intern/mathfu/mathfu/internal/vector_3_simd.h b/intern/mathfu/mathfu/internal/vector_3_simd.h new file mode 100644 index 000000000000..834c99ed905f --- /dev/null +++ b/intern/mathfu/mathfu/internal/vector_3_simd.h @@ -0,0 +1,385 @@ +/* +* Copyright 2014 Google Inc. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef MATHFU_VECTOR_3_SIMD_H_ +#define MATHFU_VECTOR_3_SIMD_H_ + +#include "mathfu/internal/vector_3.h" +#include "mathfu/utilities.h" + +#include + +#ifdef MATHFU_COMPILE_WITH_SIMD +#include "vectorial/simd4f.h" +#endif + +/// @file mathfu/internal/vector_3_simd.h MathFu Vector Specialization +/// @brief 3-dimensional specialization of mathfu::Vector for SIMD optimized +/// builds. +/// @see mathfu::Vector + +/// @cond MATHFU_INTERNAL +/// Add macros to account for both the case where the vector is stored as a +/// simd intrinsic using 4 elements or as 3 values of type T. +/// MATHFU_VECTOR3_STORE3/MATHFU_VECTOR3_LOAD3 are additional operations used +/// to load/store the non simd values from and to simd datatypes. If intrinsics +/// are used these amount to essentially noops. MATHFU_VECTOR3_INIT3 either +/// creates a simd datatype if the intrinsic is used or sets the T values if +/// not. +#ifdef MATHFU_COMPILE_WITH_PADDING +#define MATHFU_VECTOR3_STORE3(simd_to_store, data) \ + { (data).simd = simd_to_store; } +#define MATHFU_VECTOR3_LOAD3(data) (data).simd +#define MATHFU_VECTOR3_INIT3(data, v1, v2, v3) \ + { (data).simd = simd4f_create(v1, v2, v3, 0); } +#else +#define MATHFU_VECTOR3_STORE3(simd_to_store, data) \ + { simd4f_ustore3(simd_to_store, (data).data_); } +#define MATHFU_VECTOR3_LOAD3(data) simd4f_uload3((data).data_) +#define MATHFU_VECTOR3_INIT3(data, v1, v2, v3) \ + { \ + (data).data_[0] = v1; \ + (data).data_[1] = v2; \ + (data).data_[2] = v3; \ + } +#endif // MATHFU_COMPILE_WITH_PADDING +/// @endcond + +namespace mathfu { + +#ifdef MATHFU_COMPILE_WITH_SIMD +/// @cond MATHFU_INTERNAL +// This class should remain plain old data. +template <> +class Vector { + public: + typedef float Scalar; + + inline Vector() {} + + inline Vector(const Vector& v) { +#ifdef MATHFU_COMPILE_WITH_PADDING + simd = v.simd; +#else + MATHFU_VECTOR3_INIT3(*this, v[0], v[1], v[2]); +#endif // MATHFU_COMPILE_WITH_PADDING + } + + explicit inline Vector(const Vector& v) { + MATHFU_VECTOR3_INIT3(*this, static_cast(v[0]), + static_cast(v[1]), static_cast(v[2])); + } + + inline Vector(const simd4f& v) { MATHFU_VECTOR3_STORE3(v, *this); } + + explicit inline Vector(const float& s) { + MATHFU_VECTOR3_INIT3(*this, s, s, s); + } + + inline Vector(const float& v1, const float& v2, const float& v3) { + MATHFU_VECTOR3_INIT3(*this, v1, v2, v3); + } + + inline Vector(const Vector& v12, const float& v3) { + MATHFU_VECTOR3_INIT3(*this, v12[0], v12[1], v3); + } + + explicit inline Vector(const float* v) { +#ifdef MATHFU_COMPILE_WITH_PADDING + simd = simd4f_uload3(v); +#else + MATHFU_VECTOR3_INIT3(*this, v[0], v[1], v[2]); +#endif // MATHFU_COMPILE_WITH_PADDING + } + + explicit inline Vector(const VectorPacked& vector) { +#ifdef MATHFU_COMPILE_WITH_PADDING + simd = simd4f_uload3(vector.data); +#else + MATHFU_VECTOR3_INIT3(*this, vector.data[0], vector.data[1], vector.data[2]); +#endif // MATHFU_COMPILE_WITH_PADDING + } + + inline float& operator()(const int i) WARN_UNUSED_RESULT { return data_[i]; } + + inline const float& operator()(const int i) const WARN_UNUSED_RESULT { return data_[i]; } + + inline float& operator[](const int i) WARN_UNUSED_RESULT { return data_[i]; } + + inline const float& operator[](const int i) const WARN_UNUSED_RESULT { return data_[i]; } + + /// GLSL style multi-component accessors. + inline Vector xy() WARN_UNUSED_RESULT { return Vector(x, y); } + inline const Vector xy() const WARN_UNUSED_RESULT { return Vector(x, y); } + + inline void Pack(VectorPacked* const vector) const { +#ifdef MATHFU_COMPILE_WITH_PADDING + simd4f_ustore3(simd, vector->data); +#else + vector->data[0] = data_[0]; + vector->data[1] = data_[1]; + vector->data[2] = data_[2]; +#endif // MATHFU_COMPILE_WITH_PADDING + } + + inline void Pack(float a[3]) const { +#ifdef MATHFU_COMPILE_WITH_PADDING + simd4f_ustore3(simd, a); +#else + a[0] = data_[0]; + a[1] = data_[1]; + a[2] = data_[2]; +#endif // MATHFU_COMPILE_WITH_PADDING + } + + inline const float (&Data() const)[3] WARN_UNUSED_RESULT { + return reinterpret_cast(data_); + } + + inline Vector operator-() const { + return Vector( + simd4f_sub(simd4f_zero(), MATHFU_VECTOR3_LOAD3(*this))); + } + + inline Vector operator*(const Vector& v) const { + return Vector( + simd4f_mul(MATHFU_VECTOR3_LOAD3(*this), MATHFU_VECTOR3_LOAD3(v))); + } + + inline Vector operator/(const Vector& v) const { + return Vector( + simd4f_div(MATHFU_VECTOR3_LOAD3(*this), MATHFU_VECTOR3_LOAD3(v))); + } + + inline Vector operator+(const Vector& v) const { + return Vector( + simd4f_add(MATHFU_VECTOR3_LOAD3(*this), MATHFU_VECTOR3_LOAD3(v))); + } + + inline Vector operator-(const Vector& v) const { + return Vector( + simd4f_sub(MATHFU_VECTOR3_LOAD3(*this), MATHFU_VECTOR3_LOAD3(v))); + } + + inline Vector operator*(const float& s) const { + return Vector( + simd4f_mul(MATHFU_VECTOR3_LOAD3(*this), simd4f_splat(s))); + } + + inline Vector operator/(const float& s) const { + return Vector( + simd4f_div(MATHFU_VECTOR3_LOAD3(*this), simd4f_splat(s))); + } + + inline Vector operator+(const float& s) const { + return Vector( + simd4f_add(MATHFU_VECTOR3_LOAD3(*this), simd4f_splat(s))); + } + + inline Vector operator-(const float& s) const { + return Vector( + simd4f_sub(MATHFU_VECTOR3_LOAD3(*this), simd4f_splat(s))); + } + + inline Vector& operator*=(const Vector& v) { + *this = simd4f_mul(MATHFU_VECTOR3_LOAD3(*this), MATHFU_VECTOR3_LOAD3(v)); + return *this; + } + + inline Vector& operator/=(const Vector& v) { + *this = simd4f_div(MATHFU_VECTOR3_LOAD3(*this), MATHFU_VECTOR3_LOAD3(v)); + return *this; + } + + inline Vector& operator+=(const Vector& v) { + *this = simd4f_add(MATHFU_VECTOR3_LOAD3(*this), MATHFU_VECTOR3_LOAD3(v)); + return *this; + } + + inline Vector& operator-=(const Vector& v) { + *this = simd4f_sub(MATHFU_VECTOR3_LOAD3(*this), MATHFU_VECTOR3_LOAD3(v)); + return *this; + } + + inline Vector& operator*=(const float& s) { + *this = simd4f_mul(MATHFU_VECTOR3_LOAD3(*this), simd4f_splat(s)); + return *this; + } + + inline Vector& operator/=(const float& s) { + *this = simd4f_div(MATHFU_VECTOR3_LOAD3(*this), simd4f_splat(s)); + return *this; + } + + inline Vector& operator+=(const float& s) { + *this = simd4f_add(MATHFU_VECTOR3_LOAD3(*this), simd4f_splat(s)); + return *this; + } + + inline Vector& operator-=(const float& s) { + *this = simd4f_sub(MATHFU_VECTOR3_LOAD3(*this), simd4f_splat(s)); + return *this; + } + + inline bool operator==(const Vector& v) const { + for (int i = 0; i < 3; ++i) { + if ((*this)[i] != v[i]) return false; + } + return true; + } + + inline bool operator!=(const Vector& v) const { + return !operator==(v); + } + + inline float LengthSquared() const WARN_UNUSED_RESULT { + return simd4f_dot3_scalar(MATHFU_VECTOR3_LOAD3(*this), + MATHFU_VECTOR3_LOAD3(*this)); + } + + inline float Length() const WARN_UNUSED_RESULT { + return simd4f_get_x(simd4f_length3(MATHFU_VECTOR3_LOAD3(*this))); + } + + inline float Normalize() { + const float length = Length(); + *this = simd4f_mul(MATHFU_VECTOR3_LOAD3(*this), simd4f_splat(1 / length)); + return length; + } + + inline float SafeNormalize() { + const float length = Length(); + if (!FuzzyZeroHelper(length)) { + *this = simd4f_mul(MATHFU_VECTOR3_LOAD3(*this), simd4f_splat(1 / length)); + } + return length; + } + + inline Vector Normalized() const WARN_UNUSED_RESULT { + return Vector(simd4f_normalize3(MATHFU_VECTOR3_LOAD3(*this))); + } + + inline Vector SafeNormalized(const Vector& v) const WARN_UNUSED_RESULT { + if (FuzzyZeroHelper(Length())) { + return v; + } + return Normalized(); + } + + static inline WARN_UNUSED_RESULT bool FuzzyZero(const Vector& v) { + return FuzzyZeroHelper(v); + } + + template + static inline WARN_UNUSED_RESULT Vector FromType(const CompatibleT& compatible) { + return FromTypeHelper(compatible); + } + + template + static inline WARN_UNUSED_RESULT CompatibleT ToType(const Vector& v) { + return ToTypeHelper(v); + } + + static inline WARN_UNUSED_RESULT float DotProduct(const Vector& v1, + const Vector& v2) { + return simd4f_dot3_scalar(MATHFU_VECTOR3_LOAD3(v1), + MATHFU_VECTOR3_LOAD3(v2)); + } + + static inline WARN_UNUSED_RESULT Vector CrossProduct(const Vector& v1, + const Vector& v2) { + return Vector( + simd4f_cross3(MATHFU_VECTOR3_LOAD3(v1), MATHFU_VECTOR3_LOAD3(v2))); + } + + static inline WARN_UNUSED_RESULT Vector HadamardProduct(const Vector& v1, + const Vector& v2) { + return Vector( + simd4f_mul(MATHFU_VECTOR3_LOAD3(v1), MATHFU_VECTOR3_LOAD3(v2))); + } + + static inline WARN_UNUSED_RESULT Vector Lerp(const Vector& v1, + const Vector& v2, + float percent) { + const Vector percentv(percent); + const Vector one(1.0f); + const Vector one_minus_percent = one - percentv; + return Vector(simd4f_add( + simd4f_mul(MATHFU_VECTOR3_LOAD3(one_minus_percent), + MATHFU_VECTOR3_LOAD3(v1)), + simd4f_mul(MATHFU_VECTOR3_LOAD3(percentv), MATHFU_VECTOR3_LOAD3(v2)))); + } + + /// Generates a random vector, where the range for each component is + /// bounded by min and max. + static inline WARN_UNUSED_RESULT Vector RandomInRange(const Vector& min, + const Vector& max) { + return Vector(mathfu::RandomInRange(min[0], max[0]), + mathfu::RandomInRange(min[1], max[1]), + mathfu::RandomInRange(min[2], max[2])); + } + + static inline WARN_UNUSED_RESULT Vector Max(const Vector& v1, + const Vector& v2) { +#ifdef MATHFU_COMPILE_WITH_PADDING + return Vector( + simd4f_max(MATHFU_VECTOR3_LOAD3(v1), MATHFU_VECTOR3_LOAD3(v2))); +#else + return Vector(std::max(v1[0], v2[0]), std::max(v1[1], v2[1]), + std::max(v1[2], v2[2])); +#endif // MATHFU_COMPILE_WITH_PADDING + } + + static inline WARN_UNUSED_RESULT Vector Min(const Vector& v1, + const Vector& v2) { +#ifdef MATHFU_COMPILE_WITH_PADDING + return Vector( + simd4f_min(MATHFU_VECTOR3_LOAD3(v1), MATHFU_VECTOR3_LOAD3(v2))); +#else + return Vector(std::min(v1[0], v2[0]), std::min(v1[1], v2[1]), + std::min(v1[2], v2[2])); +#endif // MATHFU_COMPILE_WITH_PADDING + } + + template + friend class Matrix; + template + friend class Vector; + + MATHFU_DEFINE_CLASS_SIMD_AWARE_NEW_DELETE + +#include "mathfu/internal/disable_warnings_begin.h" + union { +#ifdef MATHFU_COMPILE_WITH_PADDING + simd4f simd; + float data_[4]; +#else + float data_[3]; +#endif // MATHFU_COMPILE_WITH_PADDING + + struct { + float x; + float y; + float z; + }; + }; +#include "mathfu/internal/disable_warnings_end.h" +}; +/// @endcond +#endif // MATHFU_COMPILE_WITH_SIMD + +} // namespace mathfu + +#endif // MATHFU_VECTOR_3_SIMD_H_ diff --git a/intern/mathfu/mathfu/internal/vector_4.h b/intern/mathfu/mathfu/internal/vector_4.h new file mode 100644 index 000000000000..c15f4c963166 --- /dev/null +++ b/intern/mathfu/mathfu/internal/vector_4.h @@ -0,0 +1,223 @@ +/* +* Copyright 2016 Google Inc. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef MATHFU_INTERNAL_VECTOR_4_H_ +#define MATHFU_INTERNAL_VECTOR_4_H_ + +// Prefer including vector.h directly, since it includes specializations. +#include "mathfu/vector.h" + +namespace mathfu { + +template +class Vector { + public: + typedef T Scalar; + static const int d = 4; + + inline Vector() {} + + inline Vector(const Vector& v) { + MATHFU_VECTOR_OPERATION(data_[i] = v.data_[i]); + } + + template + explicit inline Vector(const Vector& v) { + MATHFU_VECTOR_OPERATION(data_[i] = static_cast(v[i])); + } + + explicit inline Vector(const T& s) { MATHFU_VECTOR_OPERATION(data_[i] = s); } + + explicit inline Vector(const T* a) { + MATHFU_VECTOR_OPERATION(data_[i] = a[i]); + } + + inline Vector(const T& s1, const T& s2, const T& s3, const T& s4) { + x = s1; + y = s2; + z = s3; + w = s4; + } + + inline Vector(const Vector& vector3, const T& value) { + x = vector3[0]; + y = vector3[1]; + z = vector3[2]; + w = value; + } + + inline Vector(const Vector& v12, const Vector& v34) { + x = v12[0]; + y = v12[1]; + z = v34[0]; + w = v34[1]; + } + + explicit inline Vector(const VectorPacked& vector) { + MATHFU_VECTOR_OPERATION(data_[i] = vector.data[i]); + } + + inline T& operator()(const int i) WARN_UNUSED_RESULT { return data_[i]; } + + inline const T& operator()(const int i) const WARN_UNUSED_RESULT { return data_[i]; } + + inline T& operator[](const int i) WARN_UNUSED_RESULT { return data_[i]; } + + inline const T& operator[](const int i) const WARN_UNUSED_RESULT { return data_[i]; } + + inline Vector xyz() WARN_UNUSED_RESULT { return Vector(x, y, z); } + + inline const Vector xyz() const WARN_UNUSED_RESULT { return Vector(x, y, z); } + + inline Vector xy() WARN_UNUSED_RESULT { return Vector(x, y); } + + inline const Vector xy() const WARN_UNUSED_RESULT { return Vector(x, y); } + + inline Vector zw() WARN_UNUSED_RESULT { return Vector(z, w); } + + inline const Vector zw() const WARN_UNUSED_RESULT { return Vector(z, w); } + + inline void Pack(VectorPacked* const vector) const { + MATHFU_VECTOR_OPERATION(vector->data[i] = data_[i]); + } + + inline void Pack(T a[4]) const { + MATHFU_VECTOR_OPERATION(a[i] = data_[i]); + } + + inline const T (&Data() const)[4] WARN_UNUSED_RESULT { + return data_; + } + + inline T LengthSquared() const WARN_UNUSED_RESULT { return LengthSquaredHelper(*this); } + + inline T Length() const WARN_UNUSED_RESULT { return LengthHelper(*this); } + + inline T Normalize() { return NormalizeHelper(*this); } + + inline T SafeNormalize() { return SafeNormalizeHelper(*this); } + + inline Vector Normalized() const WARN_UNUSED_RESULT { return NormalizedHelper(*this); } + + inline Vector SafeNormalized(const Vector& v) const WARN_UNUSED_RESULT { + return SafeNormalizedHelper(*this, v); + } + + static inline WARN_UNUSED_RESULT bool FuzzyZero(const Vector& v) { + return FuzzyZeroHelper(v); + } + + template + static inline WARN_UNUSED_RESULT Vector FromType(const CompatibleT& compatible) { + return FromTypeHelper(compatible); + } + + template + static inline WARN_UNUSED_RESULT CompatibleT ToType(const Vector& v) { + return ToTypeHelper(v); + } + + static inline WARN_UNUSED_RESULT T DotProduct(const Vector& v1, const Vector& v2) { + return DotProductHelper(v1, v2); + } + + static inline WARN_UNUSED_RESULT Vector HadamardProduct(const Vector& v1, + const Vector& v2) { + return HadamardProductHelper(v1, v2); + } + + static inline WARN_UNUSED_RESULT Vector Lerp(const Vector& v1, + const Vector& v2, const T percent) { + return LerpHelper(v1, v2, percent); + } + + static inline WARN_UNUSED_RESULT Vector RandomInRange(const Vector& min, + const Vector& max) { + return RandomInRangeHelper(min, max); + } + + static inline WARN_UNUSED_RESULT Vector Max(const Vector& v1, + const Vector& v2) { + return MaxHelper(v1, v2); + } + + static inline WARN_UNUSED_RESULT Vector Min(const Vector& v1, + const Vector& v2) { + return MinHelper(v1, v2); + } + + MATHFU_DEFINE_CLASS_SIMD_AWARE_NEW_DELETE + +#include "mathfu/internal/disable_warnings_begin.h" + union { + T data_[4]; + struct { + T x; + T y; + T z; + T w; + }; + }; +#include "mathfu/internal/disable_warnings_end.h" +}; + +template +struct VectorPacked { + /// Create an uninitialized VectorPacked. + VectorPacked() {} + + /// Create a VectorPacked from a Vector. + /// + /// Both VectorPacked and Vector must have the same number of dimensions. + /// @param vector Vector to create the VectorPacked from. + explicit VectorPacked(const Vector& vector) { vector.Pack(this); } + + explicit VectorPacked(const T * const s) :x(s[0]), y(s[1]), z(s[2]), w(s[3]) {} + + /// Copy a Vector to a VectorPacked. + /// + /// Both VectorPacked and Vector must have the same number of dimensions. + /// @param vector Vector to copy to the VectorPacked. + /// @returns A reference to this VectorPacked. + VectorPacked& operator=(const Vector& vector) { + vector.Pack(this); + return *this; + } + + inline const T& operator[](int i) const { + return data[i]; + } + + inline T& operator[](int i) { + return data[i]; + } + +#include "mathfu/internal/disable_warnings_begin.h" + /// Elements of the packed vector one per dimension. + union { + T data[4]; + struct { + T x; + T y; + T z; + T w; + }; + }; +#include "mathfu/internal/disable_warnings_end.h" +}; + +} // namespace mathfu + +#endif // MATHFU_INTERNAL_VECTOR_4_H_ diff --git a/intern/mathfu/mathfu/internal/vector_4_simd.h b/intern/mathfu/mathfu/internal/vector_4_simd.h new file mode 100644 index 000000000000..3c0a72484cd9 --- /dev/null +++ b/intern/mathfu/mathfu/internal/vector_4_simd.h @@ -0,0 +1,310 @@ +/* +* Copyright 2014 Google Inc. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef MATHFU_VECTOR_4_SIMD_H_ +#define MATHFU_VECTOR_4_SIMD_H_ + +#include "mathfu/internal/vector_4.h" +#include "mathfu/utilities.h" + +#include + +#ifdef MATHFU_COMPILE_WITH_SIMD +#include "vectorial/simd4f.h" +#endif + +/// @file mathfu/internal/vector_4_simd.h MathFu Vector Specialization +/// @brief 4-dimensional specialization of mathfu::Vector for SIMD optimized +/// builds. +/// @see mathfu::Vector + +namespace mathfu { + +#ifdef MATHFU_COMPILE_WITH_SIMD + +template <> +class Vector { + public: + typedef float Scalar; + + inline Vector() {} + + inline Vector(const Vector& v) { simd = v.simd; } + + explicit inline Vector(const Vector& v) { + data_[0] = static_cast(v[0]); + data_[1] = static_cast(v[1]); + data_[2] = static_cast(v[2]); + data_[3] = static_cast(v[3]); + } + + explicit inline Vector(const simd4f& v) { simd = v; } + + explicit inline Vector(const float& s) { simd = simd4f_splat(s); } + + inline Vector(const float& s1, const float& s2, const float& s3, + const float& s4) { + simd = simd4f_create(s1, s2, s3, s4); + } + + explicit inline Vector(const float* v) { simd = simd4f_uload4(v); } + + inline Vector(const Vector& vector3, const float& value) { +#ifdef MATHFU_COMPILE_WITH_PADDING + simd = vector3.simd; + (*this)[3] = value; +#else + simd = simd4f_create(vector3[0], vector3[1], vector3[2], value); +#endif // MATHFU_COMPILE_WITH_PADDING + } + + inline Vector(const Vector& vector12, + const Vector& vector34) { + simd = simd4f_create(vector12[0], vector12[1], vector34[0], vector34[1]); + } + + explicit inline Vector(const VectorPacked& vector) { + simd = simd4f_uload4(vector.data); + } + + inline float& operator()(const int i) WARN_UNUSED_RESULT { return data_[i]; } + + inline const float& operator()(const int i) const WARN_UNUSED_RESULT { return data_[i]; } + + inline float& operator[](const int i) WARN_UNUSED_RESULT { return data_[i]; } + + inline const float& operator[](const int i) const WARN_UNUSED_RESULT { return data_[i]; } + + /// GLSL style multi-component accessors. + inline Vector xyz() WARN_UNUSED_RESULT { return Vector(x, y, z); } + inline const Vector xyz() const WARN_UNUSED_RESULT { + return Vector(x, y, z); + } + + inline Vector xy() WARN_UNUSED_RESULT { return Vector(x, y); } + inline const Vector xy() const WARN_UNUSED_RESULT { return Vector(x, y); } + + inline Vector zw() WARN_UNUSED_RESULT { return Vector(z, w); } + inline const Vector zw() const WARN_UNUSED_RESULT { return Vector(z, w); } + + inline void Pack(VectorPacked* const vector) const { + simd4f_ustore4(simd, vector->data); + } + + inline void Pack(float a[4]) const { + simd4f_ustore4(simd, a); + } + + inline const float (&Data() const)[4] WARN_UNUSED_RESULT { + return data_; + } + + inline Vector operator-() const { + return Vector(simd4f_sub(simd4f_zero(), simd)); + } + + inline Vector operator*(const Vector& v) const { + return Vector(simd4f_mul(simd, v.simd)); + } + + inline Vector operator/(const Vector& v) const { + return Vector(simd4f_div(simd, v.simd)); + } + + inline Vector operator+(const Vector& v) const { + return Vector(simd4f_add(simd, v.simd)); + } + + inline Vector operator-(const Vector& v) const { + return Vector(simd4f_sub(simd, v.simd)); + } + + inline Vector operator*(const float& s) const { + return Vector(simd4f_mul(simd, simd4f_splat(s))); + } + + inline Vector operator/(const float& s) const { + return Vector(simd4f_div(simd, simd4f_splat(s))); + } + + inline Vector operator+(const float& s) const { + return Vector(simd4f_add(simd, simd4f_splat(s))); + } + + inline Vector operator-(const float& s) const { + return Vector(simd4f_sub(simd, simd4f_splat(s))); + } + + inline Vector& operator*=(const Vector& v) { + simd = simd4f_mul(simd, v.simd); + return *this; + } + + inline Vector& operator/=(const Vector& v) { + simd = simd4f_div(simd, v.simd); + return *this; + } + + inline Vector& operator+=(const Vector& v) { + simd = simd4f_add(simd, v.simd); + return *this; + } + + inline Vector& operator-=(const Vector& v) { + simd = simd4f_sub(simd, v.simd); + return *this; + } + + inline Vector& operator*=(const float& s) { + simd = simd4f_mul(simd, simd4f_splat(s)); + return *this; + } + + inline Vector& operator/=(const float& s) { + simd = simd4f_div(simd, simd4f_splat(s)); + return *this; + } + + inline Vector& operator+=(const float& s) { + simd = simd4f_add(simd, simd4f_splat(s)); + return *this; + } + + inline Vector& operator-=(const float& s) { + simd = simd4f_sub(simd, simd4f_splat(s)); + return *this; + } + + inline bool operator==(const Vector& v) const { + for (int i = 0; i < 4; ++i) { + if ((*this)[i] != v[i]) return false; + } + return true; + } + + inline bool operator!=(const Vector& v) const { + return !operator==(v); + } + + inline float LengthSquared() const WARN_UNUSED_RESULT { + return simd4f_get_x(simd4f_dot4(simd, simd)); + } + + inline float Length() const WARN_UNUSED_RESULT { return simd4f_get_x(simd4f_length4(simd)); } + + inline float Normalize() { + const float length = Length(); + simd = simd4f_mul(simd, simd4f_splat(1 / length)); + return length; + } + + inline float SafeNormalize() { + const float length = Length(); + if (!FuzzyZeroHelper(length)) { + simd = simd4f_mul(simd, simd4f_splat(1 / length)); + } + return length; + } + + inline Vector Normalized() const WARN_UNUSED_RESULT { + return Vector(simd4f_normalize4(simd)); + } + + inline Vector SafeNormalized(const Vector& v) const WARN_UNUSED_RESULT { + if (FuzzyZeroHelper(Length())) { + return v; + } + return Normalized(); + } + + static inline WARN_UNUSED_RESULT bool FuzzyZero(const Vector& v) { + return FuzzyZeroHelper(v); + } + + template + static inline WARN_UNUSED_RESULT Vector FromType(const CompatibleT& compatible) { + return FromTypeHelper(compatible); + } + + template + static inline WARN_UNUSED_RESULT CompatibleT ToType(const Vector& v) { + return ToTypeHelper(v); + } + + static inline WARN_UNUSED_RESULT float DotProduct(const Vector& v1, + const Vector& v2) { + return simd4f_get_x(simd4f_dot4(v1.simd, v2.simd)); + } + + static inline WARN_UNUSED_RESULT Vector HadamardProduct(const Vector& v1, + const Vector& v2) { + return Vector(simd4f_mul(v1.simd, v2.simd)); + } + + static inline WARN_UNUSED_RESULT Vector Lerp(const Vector& v1, + const Vector& v2, + float percent) { + const Vector percentv(percent); + const Vector one(1.0f); + const Vector one_minus_percent = one - percentv; + return Vector( + simd4f_add(simd4f_mul(one_minus_percent.simd, v1.simd), + simd4f_mul(percentv.simd, v2.simd))); + } + + /// Generates a random vector, where the range for each component is + /// bounded by min and max. + static inline WARN_UNUSED_RESULT Vector RandomInRange(const Vector& min, + const Vector& max) { + return Vector(mathfu::RandomInRange(min[0], max[0]), + mathfu::RandomInRange(min[1], max[1]), + mathfu::RandomInRange(min[2], max[2]), + mathfu::RandomInRange(min[3], max[3])); + } + + static inline WARN_UNUSED_RESULT Vector Max(const Vector& v1, + const Vector& v2) { + return Vector(simd4f_max(v1.simd, v2.simd)); + } + + static inline WARN_UNUSED_RESULT Vector Min(const Vector& v1, + const Vector& v2) { + return Vector(simd4f_min(v1.simd, v2.simd)); + } + + template + friend class Matrix; + + MATHFU_DEFINE_CLASS_SIMD_AWARE_NEW_DELETE + +#include "mathfu/internal/disable_warnings_begin.h" + union { + simd4f simd; + float data_[4]; + struct { + float x; + float y; + float z; + float w; + }; + }; +#include "mathfu/internal/disable_warnings_end.h" +}; +/// @endcond +#endif // MATHFU_COMPILE_WITH_SIMD + +} // namespace mathfu + +#endif // MATHFU_VECTOR_4_SIMD_H_ diff --git a/intern/mathfu/mathfu/io.h b/intern/mathfu/mathfu/io.h new file mode 100644 index 000000000000..d832052b9c60 --- /dev/null +++ b/intern/mathfu/mathfu/io.h @@ -0,0 +1,57 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MATHFU_IO_H_ +#define MATHFU_IO_H_ + +#include + +#include "mathfu/matrix.h" +#include "mathfu/quaternion.h" +#include "mathfu/vector.h" + +namespace mathfu { + +/// @brief Print the vector contents to the output stream. +template +inline std::ostream& operator<<(std::ostream& os, const Vector& v) { + os << "(" << v[0]; + for (int i = 1; i < d; ++i) { + os << ", " << v[i]; + } + return os << ")"; +} + +/// @brief Print the matrix contents to the output stream. +template +inline std::ostream& operator<<(std::ostream& os, + const Matrix& m) { + os << "(" << m[0]; + for (int i = 1; i < rows * columns; ++i) { + os << ", " << m[i]; + } + return os << ")"; +} + +/// @brief Print the quaternion contents to the output stream. +template +inline std::ostream& operator<<(std::ostream& os, const Quaternion& q) { + return os << "(" << q[0] << ", " << q[1] << ", " << q[2] << ", " << q[3] + << ")"; +} + +} // namespace mathfu + +#endif // MATHFU_IO_H_ diff --git a/intern/mathfu/mathfu/matrix.h b/intern/mathfu/mathfu/matrix.h new file mode 100644 index 000000000000..11a874d5c34e --- /dev/null +++ b/intern/mathfu/mathfu/matrix.h @@ -0,0 +1,1903 @@ +/* +* Copyright 2014 Google Inc. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef MATHFU_MATRIX_H_ +#define MATHFU_MATRIX_H_ + +#include "mathfu/utilities.h" +#include "mathfu/vector.h" + +#include + +#include + +/// @file mathfu/matrix.h +/// @brief Matrix class and functions. +/// @addtogroup mathfu_matrix +/// +/// MathFu provides a generic Matrix implementation which is specialized +/// for 4x4 matrices to take advantage of optimization opportunities using +/// SIMD instructions. + +#ifdef _MSC_VER +#pragma warning(push) +// The following disables warnings for MATHFU_MAT_OPERATION. +// The buffer overrun warning must be disabled as MSVC doesn't treat +// "columns" as constant and therefore assumes that it's possible +// to overrun arrays indexed by "i". +// The conditional expression is constant warning is disabled since +// MSVC decides that "columns" *is* constant when unrolling the operation +// loop. +#pragma warning(disable : 4127) // conditional expression is constant +#pragma warning(disable : 4789) // buffer overrun +#if _MSC_VER >= 1900 // MSVC 2015 +#pragma warning(disable : 4456) // allow shadowing in unrolled loops +#pragma warning(disable : 4723) // suppress "potential divide by 0" warning +#endif // _MSC_VER >= 1900 +#endif // _MSC_VER + +/// @cond MATHFU_INTERNAL +/// The stride of a vector (e.g Vector) when cast as an array of floats. +#define MATHFU_VECTOR_STRIDE_FLOATS(vector) (sizeof(vector) / sizeof(float)) +/// @endcond + +/// @cond MATHFU_INTERNAL +/// This will unroll loops for matrices with <= 4 columns +#define MATHFU_MAT_OPERATION(OP) MATHFU_UNROLLED_LOOP(i, kColumns, OP) +/// @endcond + +/// @cond MATHFU_INTERNAL +/// This will perform a given OP on each matrix column and return the result +#define MATHFU_MAT_OPERATOR(OP) \ + { \ + Matrix result; \ + MATHFU_MAT_OPERATION(result.data_[i] = (OP)); \ + return result; \ + } +/// @endcond + +/// @cond MATHFU_INTERNAL +/// This will perform a given OP on each matrix column +#define MATHFU_MAT_SELF_OPERATOR(OP) \ + { \ + MATHFU_MAT_OPERATION(OP); \ + return *this; \ + } +/// @endcond + +/// @cond MATHFU_INTERNAL +/// This macro will take the dot product for a row from data1 and a column from +/// data2. +#define MATHFU_MATRIX_4X4_DOT(data1, data2, r) \ + ((data1)[r] * (data2)[0] + (data1)[(r) + 4] * (data2)[1] + \ + (data1)[(r) + 8] * (data2)[2] + (data1)[(r) + 12] * (data2)[3]) +/// @endcond + +/// @cond MATHFU_INTERNAL +#define MATHFU_MATRIX_3X3_DOT(data1, data2, r, size) \ + ((data1)[r] * (data2)[0] + (data1)[(r) + (size)] * (data2)[1] + \ + (data1)[(r) + 2 * (size)] * (data2)[2]) +/// @endcond + +namespace mathfu { + +/// @cond MATHFU_INTERNAL +template +class Matrix; +template +inline Matrix IdentityHelper(); +template +inline bool InverseHelper(const Matrix& m, + Matrix* const inverse); +template +inline void TimesHelper(const Matrix& m1, + const Matrix& m2, + Matrix* out_m); +template +static inline Matrix OuterProductHelper( + const Vector& v1, const Vector& v2); +template +inline Matrix PerspectiveHelper(T fovy, T aspect, T znear, T zfar, + T handedness); +template +inline Matrix PerspectiveHelper(T left, T right, T bottom, T top, T znear, T zfar, + T handedness); +template +static inline Matrix OrthoHelper(T left, T right, T bottom, T top, + T znear, T zfar, T handedness); +template +static inline Matrix LookAtHelper(const Vector& at, + const Vector& eye, + const Vector& up, + T handedness); +template +static inline bool UnProjectHelper(const Vector& window_coord, + const Matrix& model_view, + const Matrix& projection, + const float window_width, + const float window_height, + Vector& result); + +template +static inline Matrix FromTypeHelper(const CompatibleT& compatible); + +template +static inline CompatibleT ToTypeHelper(const Matrix& m); +/// @endcond + +/// @addtogroup mathfu_matrix +/// @{ +/// @class Matrix +/// @brief Matrix stores a set of "rows" by "columns" elements of type T +/// and provides functions that operate on the set of elements. +/// +/// @tparam T type of each element in the matrix. +/// @tparam rows Number of rows in the matrix. +/// @tparam columns Number of columns in the matrix. +template +class Matrix { + public: + /// @brief Construct a Matrix of uninitialized values. + inline Matrix() {} + + /// @brief Construct a Matrix from another Matrix copying each element. + //// + /// @param m Matrix that the data will be copied from. + inline Matrix(const Matrix& m) { + MATHFU_MAT_OPERATION(data_[i] = m.data_[i]); + } + + /// @brief Construct a Matrix from a single float. + /// + /// @param s Scalar valu(s))); + } + + /// @brief Construct a Matrix from four floats. + /// + /// @note This method only works with a 2x2 Matrix. + /// + /// @param s00 Value of the first row and column. + /// @param s10 Value of the second row, first column. + /// @param s01 Value of the first row, second column. + /// @param s11 Value of the second row and column. + inline Matrix(const T& s00, const T& s10, const T& s01, const T& s11) { + MATHFU_STATIC_ASSERT(rows == 2 && columns == 2); + data_[0] = Vector(s00, s10); + data_[1] = Vector(s01, s11); + } + + /// @brief Create a Matrix from nine floats. + /// + /// @note This method only works with a 3x3 Matrix. + /// + /// @param s00 Value of the first row and column. + /// @param s10 Value of the second row, first column. + /// @param s20 Value of the third row, first column. + /// @param s01 Value of the first row, second column. + /// @param s11 Value of the second row and column. + /// @param s21 Value of the third row, second column. + /// @param s02 Value of the first row, third column. + /// @param s12 Value of the second row, third column. + /// @param s22 Value of the third row and column. + inline Matrix(const T& s00, const T& s10, const T& s20, const T& s01, + const T& s11, const T& s21, const T& s02, const T& s12, + const T& s22) { + MATHFU_STATIC_ASSERT(rows == 3 && columns == 3); + data_[0] = Vector(s00, s10, s20); + data_[1] = Vector(s01, s11, s21); + data_[2] = Vector(s02, s12, s22); + } + + /// @brief Creates a Matrix from twelve floats. + /// + /// @note This method only works with Matrix. + /// + /// + /// @param s00 Value of the first row and column. + /// @param s10 Value of the second row, first column. + /// @param s20 Value of the third row, first column. + /// @param s30 Value of the fourth row, first column. + /// @param s01 Value of the first row, second column. + /// @param s11 Value of the second row and column. + /// @param s21 Value of the third row, second column. + /// @param s31 Value of the fourth row, second column. + /// @param s02 Value of the first row, third column. + /// @param s12 Value of the second row, third column. + /// @param s22 Value of the third row and column. + /// @param s32 Value of the fourth row, third column. + inline Matrix(const T& s00, const T& s10, const T& s20, + const T& s01, const T& s11, const T& s21, + const T& s02, const T& s12, const T& s22, + const T& s03, const T& s13, const T& s23) { + MATHFU_STATIC_ASSERT(rows == 3 && columns == 4); + data_[0] = Vector(s00, s10, s20); + data_[1] = Vector(s01, s11, s21); + data_[2] = Vector(s02, s12, s22); + data_[3] = Vector(s03, s13, s23); + } + + inline Matrix(const Matrix& m, const Vector& v) { + MATHFU_STATIC_ASSERT(rows == 3 && columns == 4); + for (int i = 0; i < 3; ++i) { + data_[i] = m.GetColumn(i); + } + data_[3] = v; + } + + inline Matrix(const Matrix& m, const Vector& v, const Vector& s) { + MATHFU_STATIC_ASSERT(rows == 3 && columns == 4); + for (int i = 0; i < 3; ++i) { + data_[i] = m.GetColumn(i) * s[i]; + } + data_[3] = v; + } + + /// @brief Create a Matrix from sixteen floats. + /// + /// @note This method only works with a 4x4 Matrix. + /// + /// @param s00 Value of the first row and column. + /// @param s10 Value of the second row, first column. + /// @param s20 Value of the third row, first column. + /// @param s30 Value of the fourth row, first column. + /// @param s01 Value of the first row, second column. + /// @param s11 Value of the second row and column. + /// @param s21 Value of the third row, second column. + /// @param s31 Value of the fourth row, second column. + /// @param s02 Value of the first row, third column. + /// @param s12 Value of the second row, third column. + /// @param s22 Value of the third row and column. + /// @param s32 Value of the fourth row, third column. + /// @param s03 Value of the first row, fourth column. + /// @param s13 Value of the second row, fourth column. + /// @param s23 Value of the third row, fourth column. + /// @param s33 Value of the fourth row and column. + inline Matrix(const T& s00, const T& s10, const T& s20, const T& s30, + const T& s01, const T& s11, const T& s21, const T& s31, + const T& s02, const T& s12, const T& s22, const T& s32, + const T& s03, const T& s13, const T& s23, const T& s33) { + MATHFU_STATIC_ASSERT(rows == 4 && columns == 4); + data_[0] = Vector(s00, s10, s20, s30); + data_[1] = Vector(s01, s11, s21, s31); + data_[2] = Vector(s02, s12, s22, s32); + data_[3] = Vector(s03, s13, s23, s33); + } + + /// @brief Create 4x4 Matrix from 4, 4 element vectors. + /// + /// @note This method only works with a 4x4 Matrix. + /// + /// @param column0 Vector used for the first column. + /// @param column1 Vector used for the second column. + /// @param column2 Vector used for the third column. + /// @param column3 Vector used for the fourth column. + inline Matrix(const Vector& column0, const Vector& column1, + const Vector& column2, const Vector& column3) { + MATHFU_STATIC_ASSERT(rows == 4 && columns == 4); + data_[0] = column0; + data_[1] = column1; + data_[2] = column2; + data_[3] = column3; + } + + /// @brief Create 3x3 Matrix from 3, 3 element vectors. + /// + /// @note This method only works with a 3x3 Matrix. + /// + /// @param column0 Vector used for the first column. + /// @param column1 Vector used for the second column. + /// @param column2 Vector used for the third column. + inline Matrix(const Vector& column0, const Vector& column1, + const Vector& column2) { + MATHFU_STATIC_ASSERT(rows == 3 && columns == 3); + data_[0] = column0; + data_[1] = column1; + data_[2] = column2; + } + + /// @brief Create 4x3 Matrix from 3, 4 element vectors. + /// + /// @note This method only works with a 3x4 Matrix. + /// + /// @param column0 Vector used for the first column. + /// @param column1 Vector used for the second column. + /// @param column2 Vector used for the third column. + inline Matrix(const Vector& column0, const Vector& column1, + const Vector& column2, const Vector& column3) { + MATHFU_STATIC_ASSERT(rows == 3 && columns == 4); + data_[0] = column0; + data_[1] = column1; + data_[2] = column2; + data_[3] = column3; + } + + inline Matrix(const T& yaw, const T& pitch, const T& roll) { + MATHFU_STATIC_ASSERT(rows == 3 && columns == 3); + const T ci = cosf(yaw); + const T cj = cosf(pitch); + const T ch = cosf(roll); + const T si = sinf(yaw); + const T sj = sinf(pitch); + const T sh = sinf(roll); + const T cc = ci * ch; + const T cs = ci * sh; + const T sc = si * ch; + const T ss = si * sh; + + data_[0] = Vector(cj * ch, cj * sh, -sj); + data_[1] = Vector(sj * sc - cs, sj * ss + cc, cj * si); + data_[2] = Vector(sj * cc + ss, sj * cs - sc, cj * ci); + } + + inline Matrix(const Vector& euler) + :Matrix(euler.x, euler.y, euler.z) + { + } + + /// @brief Create a Matrix from the first row * column elements of an array. + /// + /// @param a Array of values that the matrix will be iniitlized to. + explicit inline Matrix(const T* const a) { + MATHFU_MAT_OPERATION((data_[i] = Vector(&a[i * columns]))); + } + + /// @brief Create a Matrix from the first row * column elements of an array. + /// + /// @param a Array of values that the matrix will be iniitlized to. + explicit inline Matrix(const T a[columns][rows]) { + MATHFU_MAT_OPERATION((data_[i] = Vector(a[i]))); + } + + /// @brief Create a Matrix from an array of "columns", "rows" element packed + /// vectors. + /// + /// @param vectors Array of "columns", "rows" element packed vectors. + explicit inline Matrix(const VectorPacked* const vectors) { + MATHFU_MAT_OPERATION((data_[i] = Vector(vectors[i]))); + } + + /// @brief Access an element of the matrix. + /// + /// @param row Index of the row to access. + /// @param column Index of the column to access. + /// @return Const reference to the element. + inline const T& operator()(const int row, const int column) const WARN_UNUSED_RESULT { + return data_[column][row]; + } + + /// @brief Access an element of the Matrix. + /// + /// @param row Index of the row to access. + /// @param column Index of the column to access. + /// @return Reference to the data that can be modified by the caller. + inline T& operator()(const int row, const int column) WARN_UNUSED_RESULT { + return data_[column][row]; + } + + /// @brief Access an element of the Matrix. + /// + /// @param i Index of the element to access in flattened memory. Where + /// the column accessed is i / rows and the row is i % rows. + /// @return Reference to the data that can be modified by the caller. + inline const T& operator()(const int i) const WARN_UNUSED_RESULT { return operator[](i); } + + /// @brief Access an element of the Matrix. + /// + /// @param i Index of the element to access in flattened memory. Where + /// the column accessed is i / rows and the row is i % rows. + /// @return Reference to the data that can be modified by the caller. + inline T& operator()(const int i) WARN_UNUSED_RESULT { return operator[](i); } + + /// @brief Access an element of the Matrix. + /// + /// @param i Index of the element to access in flattened memory. Where + /// the column accessed is i / rows and the row is i % rows. + /// @return Const reference to the data. + inline const T& operator[](const int i) const WARN_UNUSED_RESULT { + return const_cast*>(this)->operator[](i); + } + + /// @brief Access an element of the Matrix. + /// + /// @param i Index of the element to access in flattened memory. Where + /// the column accessed is i / rows and the row is i % rows. + /// @return Reference to the data that can be modified by the caller. + inline T& operator[](const int i) WARN_UNUSED_RESULT { +#if defined(MATHFU_COMPILE_WITH_PADDING) + // In this case Vector is padded, so the element offset must be + // accessed using the array operator. + if (rows == 3) { + const int row = i % rows; + const int col = i / rows; + return data_[col][row]; + } else { + return reinterpret_cast(data_)[i]; + } +#else + return reinterpret_cast(data_)[i]; +#endif // defined(MATHFU_COMPILE_WITH_PADDING) + } + + /// @brief Pack the matrix to an array of "rows" element vectors, + /// one vector per matrix column. + /// + /// @param vector Array of "columns" entries to write to. + inline void Pack(VectorPacked* const vector) const { + MATHFU_MAT_OPERATION(GetColumn(i).Pack(&vector[i])); + } + + /// @brief Pack the matrix to an array of "rows" element vectors, + /// one vector per matrix column. + /// + /// @param vector Array of "columns" entries to write to. + inline void Pack(T a[columns][rows]) const { + MATHFU_MAT_OPERATION(GetColumn(i).Pack(a[i])); + } + + inline void Pack(T a[columns * rows]) const { + MATHFU_MAT_OPERATION(GetColumn(i).Pack(&a[i * columns])); + } + + inline void PackFromAffineTransform(T a[4][4]) const { + MATHFU_STATIC_ASSERT(rows == 3 && columns == 4); + MATHFU_MAT_OPERATION(GetColumn(i).Pack(a[i])); + + a[0][3] = 0; + a[1][3] = 0; + a[2][3] = 0; + a[3][3] = 1; + } + + inline void PackFromAffineTransform(T a[16]) const { + MATHFU_STATIC_ASSERT(rows == 3 && columns == 4); + MATHFU_MAT_OPERATION(GetColumn(i).Pack(&a[i * 4])); + + a[3] = 0; + a[7] = 0; + a[11] = 0; + a[15] = 1; + } + + /// @cond MATHFU_INTERNAL + /// @brief Access a column vector of the Matrix. + /// + /// @param i Index of the column to access. + /// @return Reference to the data that can be modified by the caller. + inline Vector& GetColumn(const int i) WARN_UNUSED_RESULT { return data_[i]; } + + /// @brief Access a column vector of the Matrix. + /// + /// @param i Index of the column to access. + /// @return Const reference to the data. + inline const Vector& GetColumn(const int i) const WARN_UNUSED_RESULT { + return data_[i]; + } + /// @endcond + + inline Vector GetRow(const int i) const WARN_UNUSED_RESULT { + Vector v; + for (int j = 0; j < columns; ++j) { + v[j] = data_[j][i]; + } + return v; + } + + /// @brief Negate this Matrix. + /// + /// @return Matrix containing the result. + inline Matrix operator-() const { + MATHFU_MAT_OPERATOR(-data_[i]); + } + + /// @brief Add a Matrix to this Matrix. + /// + /// @param m Matrix to add to this Matrix. + /// @return Matrix containing the result. + inline Matrix operator+( + const Matrix& m) const { + MATHFU_MAT_OPERATOR(data_[i] + m.data_[i]); + } + + /// @brief Subtract a Matrix from this Matrix. + /// + /// @param m Matrix to subtract from this Matrix. + /// @return Matrix containing the result. + inline Matrix operator-( + const Matrix& m) const { + MATHFU_MAT_OPERATOR(data_[i] - m.data_[i]); + } + + /// @brief Add a scalar to each element of this Matrix. + /// + /// @param s Scalar to add to this Matrix. + /// @return Matrix containing the result. + inline Matrix operator+(const T& s) const { + MATHFU_MAT_OPERATOR(data_[i] + s); + } + + /// @brief Subtract a scalar from each element of this Matrix. + /// + /// @param s Scalar to subtract from this matrix. + /// @return Matrix containing the result. + inline Matrix operator-(const T& s) const { + MATHFU_MAT_OPERATOR(data_[i] - s); + } + + /// @brief Multiply each element of this Matrix with a scalar. + /// + /// @param s Scalar to multiply with this Matrix. + /// @return Matrix containing the result. + inline Matrix operator*(const T& s) const { + MATHFU_MAT_OPERATOR(data_[i] * s); + } + + /// @brief Divide each element of this Matrix with a scalar. + /// + /// @param s Scalar to divide this Matrix with. + /// @return Matrix containing the result. + inline Matrix operator/(const T& s) const { + return (*this) * (1 / s); + } + + /// @brief Multiply this Matrix with another Matrix. + /// + /// @param m Matrix to multiply with this Matrix. + /// @return Matrix containing the result. + inline Matrix operator*( + const Matrix& m) const { + Matrix result; + TimesHelper(*this, m, &result); + return result; + } + + /// @brief Add a Matrix to this Matrix (in-place). + /// + /// @param m Matrix to add to this Matrix. + /// @return Reference to this class. + inline Matrix& operator+=( + const Matrix& m) { + MATHFU_MAT_SELF_OPERATOR(data_[i] += m.data_[i]); + } + + /// @brief Subtract a Matrix from this Matrix (in-place). + /// + /// @param m Matrix to subtract from this Matrix. + /// @return Reference to this class. + inline Matrix& operator-=( + const Matrix& m) { + MATHFU_MAT_SELF_OPERATOR(data_[i] -= m.data_[i]); + } + + /// @brief Add a scalar to each element of this Matrix (in-place). + /// + /// @param s Scalar to add to each element of this Matrix. + /// @return Reference to this class. + inline Matrix& operator+=(const T& s) { + MATHFU_MAT_SELF_OPERATOR(data_[i] += s); + } + + /// @brief Subtract a scalar from each element of this Matrix (in-place). + /// + /// @param s Scalar to subtract from each element of this Matrix. + /// @return Reference to this class. + inline Matrix& operator-=(const T& s) { + MATHFU_MAT_SELF_OPERATOR(data_[i] -= s); + } + + /// @brief Multiply each element of this Matrix with a scalar (in-place). + /// + /// @param s Scalar to multiply with each element of this Matrix. + /// @return Reference to this class. + inline Matrix& operator*=(const T& s) { + MATHFU_MAT_SELF_OPERATOR(data_[i] *= s); + } + + /// @brief Divide each element of this Matrix by a scalar (in-place). + /// + /// @param s Scalar to divide this Matrix by. + /// @return Reference to this class. + inline Matrix& operator/=(const T& s) { + return (*this) *= (1 / s); + } + + /// @brief Multiply this Matrix with another Matrix (in-place). + /// + /// @param m Matrix to multiply with this Matrix. + /// @return Reference to this class. + inline Matrix& operator*=( + const Matrix& m) { + const Matrix copy_of_this(*this); + TimesHelper(copy_of_this, m, this); + return *this; + } + + inline Vector GetEuler() const WARN_UNUSED_RESULT { + MATHFU_STATIC_ASSERT(rows == 3 && columns == 3); + return EulerHelper(*this); + } + + /// @brief Calculate the inverse of this Matrix. + /// + /// This calculates the inverse Matrix such that + /// (m * m).Inverse() is the identity. + /// @return Matrix containing the result. + inline Matrix Inverse() const WARN_UNUSED_RESULT { + Matrix inverse; + InverseHelper(*this, &inverse); + return inverse; + } + + /// @brief Calculate the inverse of this Matrix. + /// + /// This calculates the inverse Matrix such that + /// (m * m).Inverse() is the identity. + /// By contrast to Inverse() this returns whether the matrix is invertible. + /// + /// The invertible check simply compares the calculated determinant with + /// Constants::GetDeterminantThreshold() to roughly determine whether the + /// matrix is invertible. This simple check works in common cases but will + /// fail for corner cases where the matrix is a combination of huge and tiny + /// values that can't be accurately represented by the floating point + /// datatype T. More extensive checks (relative to the input values) are + /// possible but far more expensive, complicated and difficult to + /// test. + /// @return Whether the matrix is invertible. + inline bool InverseWithDeterminantCheck( + Matrix* const inverse) const { + return InverseHelper(*this, inverse); + } + + /// @brief Calculate the transpose of this Matrix. + /// + /// @return The transpose of the specified Matrix. + inline Matrix Transpose() const WARN_UNUSED_RESULT { + Matrix transpose; + MATHFU_UNROLLED_LOOP( + i, columns, MATHFU_UNROLLED_LOOP( + j, rows, transpose.GetColumn(j)[i] = GetColumn(i)[j])) + return transpose; + } + + inline Matrix Scale(const Vector& v) const WARN_UNUSED_RESULT { + return ScaleHelper(*this, v); + } + + /// @brief Get the 2-dimensional translation of a 2-dimensional affine + /// transform. + /// + /// @note 2-dimensional affine transforms are represented by 3x3 matrices. + /// @return Vector with the first two components of column 2 of this Matrix. + inline Vector TranslationVector2D() const WARN_UNUSED_RESULT { + MATHFU_STATIC_ASSERT(rows == 3 && columns == 3); + return Vector(data_[2][0], data_[2][1]); + } + + /// @brief Get the 3-dimensional translation of a 3-dimensional affine + /// transform. + /// + /// @note 3-dimensional affine transforms are represented by 4x4 matrices. + /// @return Vector with the first three components of column 3. + inline Vector TranslationVector3D() const WARN_UNUSED_RESULT { + MATHFU_STATIC_ASSERT(rows >= 3 && columns == 4); + return Vector(data_[3][0], data_[3][1], data_[3][2]); + } + + inline Matrix RotationMatrix() const WARN_UNUSED_RESULT { + MATHFU_STATIC_ASSERT(rows >= 3 && columns == 4); + return ToRotationMatrix(*this); + } + + inline Vector ScaleVector3D() const WARN_UNUSED_RESULT { + return ToScaleVector3DHelper(*this); + } + + /// @brief Load from any byte-wise compatible external matrix. + /// + /// Format should be `columns` vectors, each holding `rows` values of type T. + /// + /// Use this for safe conversion from external matrix classes. + /// Often, external libraries will have their own matrix types that are, + /// byte-for-byte, exactly the same as mathfu::Matrix. This function allows + /// you to load a mathfu::Matrix from those external types, without potential + /// aliasing bugs that are caused by casting. + /// + /// @note If your external type gives you access to a T*, then you can + /// equivalently use the Matrix(const T*) constructor. + /// + /// @param compatible reference to a byte-wise compatible matrix structure; + /// array of columns x rows Ts. + /// @returns `compatible` loaded as a mathfu::Matrix. + template + static inline WARN_UNUSED_RESULT Matrix FromType(const CompatibleT& compatible) { + return FromTypeHelper(compatible); + } + + /// @brief Load into any byte-wise compatible external matrix. + /// + /// Format should be `columns` vectors, each holding `rows` values of type T. + /// + /// Use this for safe conversion to external matrix classes. + /// Often, external libraries will have their own matrix types that are, + /// byte-for-byte, exactly the same as mathfu::Matrix. This function allows + /// you to load an external type from a mathfu::Matrix, without potential + /// aliasing bugs that are caused by casting. + /// + /// @param m reference to mathfu::Matrix to convert. + /// @returns CompatibleT loaded from m. + template + static inline WARN_UNUSED_RESULT CompatibleT ToType(const Matrix& m) { + return ToTypeHelper(m); + } + + /// @brief Calculate the outer product of two Vectors. + /// + /// @return Matrix containing the result. + static inline WARN_UNUSED_RESULT Matrix OuterProduct( + const Vector& v1, const Vector& v2) { + return OuterProductHelper(v1, v2); + } + + /// @brief Calculate the hadamard / component-wise product of two matrices. + /// + /// @param m1 First Matrix. + /// @param m2 Second Matrix. + /// @return Matrix containing the result. + static inline WARN_UNUSED_RESULT Matrix HadamardProduct( + const Matrix& m1, const Matrix& m2) WARN_UNUSED_RESULT { + MATHFU_MAT_OPERATOR(m1[i] * m2[i]); + } + + /// @brief Calculate the identity Matrix. + /// + /// @return Matrix containing the result. + static inline WARN_UNUSED_RESULT Matrix Identity() WARN_UNUSED_RESULT { + return IdentityHelper(); + } + + /// @brief Create a 3x3 translation Matrix from a 2-dimensional Vector. + /// + /// This matrix will have an empty or zero rotation component. + /// + /// @param v Vector of size 2. + /// @return Matrix containing the result. + static inline WARN_UNUSED_RESULT Matrix FromTranslationVector(const Vector& v) WARN_UNUSED_RESULT { + return Matrix(1, 0, 0, 0, 1, 0, v[0], v[1], 1); + } + + /// @brief Create a 4x4 translation Matrix from a 3-dimensional Vector. + /// + /// This matrix will have an empty or zero rotation component. + /// + /// @param v The vector of size 3. + /// @return Matrix containing the result. + static inline WARN_UNUSED_RESULT Matrix FromTranslationVector(const Vector& v) WARN_UNUSED_RESULT { + return Matrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, v[0], v[1], v[2], + 1); + } + + /// @brief Create a square Matrix with the diagonal component set to v. + /// + /// This is an affine transform matrix, so the dimension of the vector is + /// one less than the dimension of the matrix. + /// + /// @param v Vector containing components for scaling. + /// @return Matrix with v along the diagonal, and 1 in the bottom right. + static inline WARN_UNUSED_RESULT Matrix FromScaleVector(const Vector& v) WARN_UNUSED_RESULT { + // TODO OPT: Use a helper function in a similar way to Identity to + // construct the matrix for the specialized cases 2, 3, 4, and only run + // this method in the general case. This will also allow you to use the + // helper methods from specialized classes like Matrix. + Matrix return_matrix(Identity()); + for (int i = 0; i < rows - 1; ++i) return_matrix(i, i) = v[i]; + return return_matrix; + } + + static inline WARN_UNUSED_RESULT Vector ToScaleVector(const Matrix& m) WARN_UNUSED_RESULT { + return ToScaleVectorHelper(m); + } + + /// @brief Create a 4x4 Matrix from a 3x3 rotation Matrix. + /// + /// This Matrix will have an empty or zero translation component. + /// + /// @param m 3x3 rotation Matrix. + /// @return Matrix containing the result. + static inline WARN_UNUSED_RESULT Matrix FromRotationMatrix(const Matrix& m) WARN_UNUSED_RESULT { + return Matrix(m[0], m[1], m[2], 0, m[3], m[4], m[5], 0, m[6], m[7], + m[8], 0, 0, 0, 0, 1); + } + + /// @brief Extracts the 3x3 rotation Matrix from a 4x4 Matrix. + /// + /// This resulting Matrix will contain the upper-left 3x3 sub-matrix of the + /// input Matrix. + /// + /// @param m 4x4 Matrix. + /// @return rotation Matrix containing the result. + static inline WARN_UNUSED_RESULT Matrix ToRotationMatrix(const Matrix& m) WARN_UNUSED_RESULT { + return Matrix(m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], + m[10]); + } + + /// @brief Extracts the 3x3 rotation Matrix from a 4x3 Matrix. + /// + /// This resulting Matrix will contain the upper-left 3x3 sub-matrix of the + /// input Matrix. + /// + /// @param m 4x3 Matrix. + /// @return rotation Matrix containing the result. + static inline WARN_UNUSED_RESULT Matrix ToRotationMatrix(const Matrix& m) WARN_UNUSED_RESULT { + return Matrix(m.GetColumn(0), m.GetColumn(1), m.GetColumn(2)); + } + + /// @brief Constructs a Matrix from an AffineTransform. + /// + /// @param affine An AffineTransform reference to be used to construct + /// a Matrix by adding in the 'w' row of [0, 0, 0, 1]. + static inline WARN_UNUSED_RESULT Matrix FromAffineTransform( + const Matrix& affine) WARN_UNUSED_RESULT { + return Matrix(affine[0], affine[1], affine[2], static_cast(0), + affine[3], affine[4], affine[5], static_cast(0), + affine[6], affine[7], affine[8], static_cast(0), + affine[9], affine[10], affine[11], static_cast(1)); + } + + /// @brief Converts a Matrix into an AffineTransform. + /// + /// @param m A Matrix reference to be converted into an + /// AffineTransform by dropping the fixed 'w' row. + /// + /// @return Returns an AffineTransform that contains the essential + /// transformation data from the Matrix. + static inline WARN_UNUSED_RESULT Matrix ToAffineTransform(const Matrix& m) WARN_UNUSED_RESULT { + return Matrix(m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], + m[10], m[12], m[13], m[14]); + } + + /// @brief Create a 3x3 rotation Matrix from a 2D normalized directional + /// Vector around the X axis. + /// + /// @param v 2D normalized directional Vector. + /// @return Matrix containing the result. + static inline WARN_UNUSED_RESULT Matrix RotationX(const Vector& v) WARN_UNUSED_RESULT { + return Matrix(1, 0, 0, 0, v.x, v.y, 0, -v.y, v.x); + } + + /// @brief Create a 3x3 rotation Matrix from a 2D normalized directional + /// Vector around the Y axis. + /// + /// @param v 2D normalized directional Vector. + /// @return Matrix containing the result. + static inline WARN_UNUSED_RESULT Matrix RotationY(const Vector& v) WARN_UNUSED_RESULT { + return Matrix(v.x, 0, -v.y, 0, 1, 0, v.y, 0, v.x); + } + + /// @brief Create a 3x3 rotation Matrix from a 2D normalized directional + /// Vector around the Z axis. + /// + /// @param v 2D normalized directional Vector. + /// @return Matrix containing the result. + static inline WARN_UNUSED_RESULT Matrix RotationZ(const Vector& v) WARN_UNUSED_RESULT { + return Matrix(v.x, v.y, 0, -v.y, v.x, 0, 0, 0, 1); + } + + /// @brief Create a 3x3 rotation Matrix from an angle (in radians) around + /// the X axis. + /// + /// @param angle Angle (in radians). + /// @return Matrix containing the result. + static inline WARN_UNUSED_RESULT Matrix RotationX(T angle) WARN_UNUSED_RESULT { + return RotationX(Vector(cosf(angle), sinf(angle))); + } + + /// @brief Create a 3x3 rotation Matrix from an angle (in radians) around + /// the Y axis. + /// + /// @param angle Angle (in radians). + /// @return Matrix containing the result. + static inline WARN_UNUSED_RESULT Matrix RotationY(T angle) WARN_UNUSED_RESULT { + return RotationY(Vector(cosf(angle), sinf(angle))); + } + + /// @brief Create a 3x3 rotation Matrix from an angle (in radians) + /// around the Z axis. + /// + /// @param angle Angle (in radians). + /// @return Matrix containing the result. + static inline WARN_UNUSED_RESULT Matrix RotationZ(T angle) WARN_UNUSED_RESULT { + return RotationZ(Vector(cosf(angle), sinf(angle))); + } + + /// @brief Create a 4x4 perspective Matrix. + /// + /// @param fovy Field of view. + /// @param aspect Aspect ratio. + /// @param znear Near plane location. + /// @param zfar Far plane location. + /// @param handedness 1.0f for RH, -1.0f for LH + /// @return 4x4 perspective Matrix. + static inline WARN_UNUSED_RESULT Matrix Perspective(T fovy, T aspect, T znear, T zfar, + T handedness = 1) WARN_UNUSED_RESULT { + return PerspectiveHelper(fovy, aspect, znear, zfar, handedness); + } + + /// @brief Create a 4x4 perspective Matrix. + /// + /// @param left Left extent. + /// @param right Right extent. + /// @param bottom Bottom extent. + /// @param top Top extent. + /// @param znear Near plane location. + /// @param zfar Far plane location. + /// @param handedness 1.0f for RH, -1.0f for LH + /// @return 4x4 perspective Matrix. + static inline WARN_UNUSED_RESULT Matrix Perspective(T left, T right, T bottom, T top, T znear, T zfar, + T handedness = 1) WARN_UNUSED_RESULT { + return PerspectiveHelper(left, right, bottom, top, znear, zfar, handedness); + } + + /// @brief Create a 4x4 orthographic Matrix. + /// + /// @param left Left extent. + /// @param right Right extent. + /// @param bottom Bottom extent. + /// @param top Top extent. + /// @param znear Near plane location. + /// @param zfar Far plane location. + /// @param handedness 1.0f for RH, -1.0f for LH + /// @return 4x4 orthographic Matrix. + static inline WARN_UNUSED_RESULT Matrix Ortho(T left, T right, T bottom, T top, T znear, + T zfar, T handedness = 1) WARN_UNUSED_RESULT { + return OrthoHelper(left, right, bottom, top, znear, zfar, handedness); + } + + /// @brief Create a 3-dimensional camera Matrix. + /// + /// @param at The look-at target of the camera. + /// @param eye The position of the camera. + /// @param up The up vector in the world, for example (0, 1, 0) if the + /// y-axis is up. + /// @param handedness 1.0f for RH, -1.0f for LH. + /// @return 3-dimensional camera Matrix. + /// TODO: Change default handedness to +1 so that it matches Perspective(). + static inline WARN_UNUSED_RESULT Matrix LookAt(const Vector& at, + const Vector& eye, + const Vector& up, + T handedness = -1) WARN_UNUSED_RESULT { + return LookAtHelper(at, eye, up, handedness); + } + + /// @brief Get the 3D position in object space from a window coordinate. + /// + /// @param window_coord The window coordinate. The z value is for depth. + /// A window coordinate on the near plane will have 0 as the z value. + /// And a window coordinate on the far plane will have 1 as the z value. + /// z value should be with in [0, 1] here. + /// @param model_view The Model View matrix. + /// @param projection The projection matrix. + /// @param window_width Width of the window. + /// @param window_height Height of the window. + /// @return the mapped 3D position in object space. + static inline WARN_UNUSED_RESULT Vector UnProject(const Vector& window_coord, + const Matrix& model_view, + const Matrix& projection, + const float window_width, + const float window_height) WARN_UNUSED_RESULT { + Vector result; + UnProjectHelper(window_coord, model_view, projection, window_width, + window_height, result); + return result; + } + + /// @brief Multiply a Vector by a Matrix. + /// + /// @param v Vector to multiply. + /// @param m Matrix to multiply. + /// @return Matrix containing the result. + friend inline Vector operator*( + const Vector& v, const Matrix& m) { + const int d = columns; + MATHFU_VECTOR_OPERATOR((Vector::DotProduct(m.data_[i], v))); + } + + // Dimensions of the matrix. + /// Number of rows in the matrix. + static const int kRows = rows; + /// Number of columns in the matrix. + static const int kColumns = columns; + /// Total number of elements in the matrix. + static const int kElements = rows * columns; + + MATHFU_DEFINE_CLASS_SIMD_AWARE_NEW_DELETE + + private: + Vector data_[columns]; +}; +/// @} + +/// @addtogroup mathfu_matrix +/// @{ + +/// @brief Multiply each element of a Matrix by a scalar. +/// +/// @param s Scalar to multiply by. +/// @param m Matrix to multiply. +/// @return Matrix containing the result. +/// @tparam T Type of each element in the Matrix and the scalar type. +/// @tparam rows Number of rows in the matrix. +/// @tparam columns Number of columns in the matrix. +/// +/// @related mathfu::Matrix +template +inline Matrix operator*(const T& s, + const Matrix& m) { + return m * s; +} + +/// @brief Multiply a Matrix by a Vector. +/// +/// @note Template specialized versions are implemented for 2x2, 3x3, and 4x4 +/// matrices to increase performance. The 3x3 float is also specialized +/// to supported padded the 3-dimensional Vector in SIMD build configurations. +/// +/// @param m Matrix to multiply. +/// @param v Vector to multiply. +/// @return Vector containing the result. +/// +/// @related mathfu::Matrix +template +inline Vector operator*(const Matrix& m, + const Vector& v) { + const Vector result(0); + int offset = 0; + for (int column = 0; column < columns; column++) { + for (int row = 0; row < rows; row++) { + result[row] += m[offset + row] * v[column]; + } + offset += rows; + } + return result; +} + +/// @cond MATHFU_INTERNAL +template +inline Vector operator*(const Matrix& m, const Vector& v) { + return Vector(m[0] * v[0] + m[2] * v[1], m[1] * v[0] + m[3] * v[1]); +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +inline Vector operator*(const Matrix& m, const Vector& v) { + return Vector(MATHFU_MATRIX_3X3_DOT(&m[0], v, 0, 3), + MATHFU_MATRIX_3X3_DOT(&m[0], v, 1, 3), + MATHFU_MATRIX_3X3_DOT(&m[0], v, 2, 3)); +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template <> +inline Vector operator*(const Matrix& m, + const Vector& v) { + return Vector( + MATHFU_MATRIX_3X3_DOT(&m[0], v, 0, MATHFU_VECTOR_STRIDE_FLOATS(v)), + MATHFU_MATRIX_3X3_DOT(&m[0], v, 1, MATHFU_VECTOR_STRIDE_FLOATS(v)), + MATHFU_MATRIX_3X3_DOT(&m[0], v, 2, MATHFU_VECTOR_STRIDE_FLOATS(v))); +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +inline Vector operator*(const Matrix& m, const Vector& v) { + return Vector( + MATHFU_MATRIX_4X4_DOT(&m[0], v, 0), MATHFU_MATRIX_4X4_DOT(&m[0], v, 1), + MATHFU_MATRIX_4X4_DOT(&m[0], v, 2), MATHFU_MATRIX_4X4_DOT(&m[0], v, 3)); +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +inline Vector operator*(const Matrix& m, const Vector& v) { + return Vector( + MATHFU_MATRIX_3X3_DOT(&m[0], v, 0, 4) + m(0, 3), + MATHFU_MATRIX_3X3_DOT(&m[0], v, 1, 4) + m(1, 3), + MATHFU_MATRIX_3X3_DOT(&m[0], v, 2, 4) + m(2, 3)); +} +/// @endcond + +/// @brief Multiply a 4x4 Matrix by a 3-dimensional Vector. +/// +/// This is provided as a convenience and assumes the vector has a fourth +/// component equal to 1. +/// +/// @param m 4x4 Matrix. +/// @param v 3-dimensional Vector. +/// @return 3-dimensional Vector result. +/// +/// @related mathfu::Matrix +template +inline Vector operator*(const Matrix& m, const Vector& v) { + Vector v4(v[0], v[1], v[2], 1); + v4 = m * v4; + return Vector(v4[0] / v4[3], v4[1] / v4[3], v4[2] / v4[3]); +} + +/// @cond MATHFU_INTERNAL +/// @brief Multiply a Matrix with another Matrix. +/// +/// @note Template specialized versions are implemented for 2x2, 3x3, and 4x4 +/// matrices to improve performance. 3x3 float is also specialized because if +/// SIMD is used the vectors of this type of length 4. +/// +/// @param m1 Matrix to multiply. +/// @param m2 Matrix to multiply. +/// @param out_m Pointer to a Matrix which receives the result. +/// +/// @tparam T Type of each element in the returned Matrix. +/// @tparam size1 Number of rows in the returned Matrix and columns in m1. +/// @tparam size2 Number of columns in the returned Matrix and rows in m2. +/// @tparam size3 Number of columns in m3. +template +inline void TimesHelper(const Matrix& m1, + const Matrix& m2, + Matrix* out_m) { + for (int i = 0; i < size1; i++) { + for (int j = 0; j < size3; j++) { + Vector row; + for (int k = 0; k < size2; k++) { + row[k] = m1(i, k); + } + (*out_m)(i, j) = Vector::DotProduct(m2.GetColumn(j), row); + } + } +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +inline void TimesHelper(const Matrix& m1, const Matrix& m2, + Matrix* out_m) { + Matrix& out = *out_m; + out[0] = m1[0] * m2[0] + m1[2] * m2[1]; + out[1] = m1[1] * m2[0] + m1[3] * m2[1]; + out[2] = m1[0] * m2[2] + m1[2] * m2[3]; + out[3] = m1[1] * m2[2] + m1[3] * m2[3]; +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +inline void TimesHelper(const Matrix& m1, const Matrix& m2, + Matrix* out_m) { + Matrix& out = *out_m; + { + Vector row(m1[0], m1[3], m1[6]); + out[0] = Vector::DotProduct(m2.GetColumn(0), row); + out[3] = Vector::DotProduct(m2.GetColumn(1), row); + out[6] = Vector::DotProduct(m2.GetColumn(2), row); + } + { + Vector row(m1[1], m1[4], m1[7]); + out[1] = Vector::DotProduct(m2.GetColumn(0), row); + out[4] = Vector::DotProduct(m2.GetColumn(1), row); + out[7] = Vector::DotProduct(m2.GetColumn(2), row); + } + { + Vector row(m1[2], m1[5], m1[8]); + out[2] = Vector::DotProduct(m2.GetColumn(0), row); + out[5] = Vector::DotProduct(m2.GetColumn(1), row); + out[8] = Vector::DotProduct(m2.GetColumn(2), row); + } +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +inline void TimesHelper(const Matrix& m1, const Matrix& m2, + Matrix* out_m) { + Matrix& out = *out_m; + + Vector c1(m2.GetColumn(0), 0); + Vector c2(m2.GetColumn(1), 0); + Vector c3(m2.GetColumn(2), 0); + Vector c4(m2.GetColumn(3), 1); + + { + Vector row(m1[0], m1[3], m1[6], m1[9]); + out[0] = Vector::DotProduct(c1, row); + out[3] = Vector::DotProduct(c2, row); + out[6] = Vector::DotProduct(c3, row); + out[9] = Vector::DotProduct(c4, row); + } + { + Vector row(m1[1], m1[4], m1[7], m1[10]); + out[1] = Vector::DotProduct(c1, row); + out[4] = Vector::DotProduct(c2, row); + out[7] = Vector::DotProduct(c3, row); + out[10] = Vector::DotProduct(c4, row); + } + { + Vector row(m1[2], m1[5], m1[8], m1[11]); + out[2] = Vector::DotProduct(c1, row); + out[5] = Vector::DotProduct(c2, row); + out[8] = Vector::DotProduct(c3, row); + out[11] = Vector::DotProduct(c4, row); + } +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +inline void TimesHelper(const Matrix& m1, const Matrix& m2, + Matrix* out_m) { + Matrix& out = *out_m; + { + Vector row(m1[0], m1[4], m1[8], m1[12]); + out[0] = Vector::DotProduct(m2.GetColumn(0), row); + out[4] = Vector::DotProduct(m2.GetColumn(1), row); + out[8] = Vector::DotProduct(m2.GetColumn(2), row); + out[12] = Vector::DotProduct(m2.GetColumn(3), row); + } + { + Vector row(m1[1], m1[5], m1[9], m1[13]); + out[1] = Vector::DotProduct(m2.GetColumn(0), row); + out[5] = Vector::DotProduct(m2.GetColumn(1), row); + out[9] = Vector::DotProduct(m2.GetColumn(2), row); + out[13] = Vector::DotProduct(m2.GetColumn(3), row); + } + { + Vector row(m1[2], m1[6], m1[10], m1[14]); + out[2] = Vector::DotProduct(m2.GetColumn(0), row); + out[6] = Vector::DotProduct(m2.GetColumn(1), row); + out[10] = Vector::DotProduct(m2.GetColumn(2), row); + out[14] = Vector::DotProduct(m2.GetColumn(3), row); + } + { + Vector row(m1[3], m1[7], m1[11], m1[15]); + out[3] = Vector::DotProduct(m2.GetColumn(0), row); + out[7] = Vector::DotProduct(m2.GetColumn(1), row); + out[11] = Vector::DotProduct(m2.GetColumn(2), row); + out[15] = Vector::DotProduct(m2.GetColumn(3), row); + } +} +/// @endcond + +/// @cond MATHFU_INTERNAL +/// @brief Compute the identity matrix. +/// +/// @note There are template specializations for 2x2, 3x3, and 4x4 matrices to +/// increase performance. +/// +/// @return Identity Matrix. +/// @tparam T Type of each element in the returned Matrix. +/// @tparam rows Number of rows in the returned Matrix. +/// @tparam columns Number of columns in the returned Matrix. +template +inline Matrix IdentityHelper() { + Matrix return_matrix(0.f); + int min_d = rows < columns ? rows : columns; + for (int i = 0; i < min_d; ++i) return_matrix(i, i) = 1; + return return_matrix; +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +inline Matrix IdentityHelper() { + return Matrix(1, 0, 0, 1); +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +inline Matrix IdentityHelper() { + return Matrix(1, 0, 0, 0, 1, 0, 0, 0, 1); +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +inline Matrix IdentityHelper() { + return Matrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +inline Matrix IdentityHelper() { + return Matrix(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0); +} +/// @endcond + +/// @cond MATHFU_INTERNAL +/// @brief Compute the outer product of two vectors. +/// +/// @note There are template specialization for 2x2, 3x3, and 4x4 matrices to +/// increase performance. +template +static inline Matrix OuterProductHelper( + const Vector& v1, const Vector& v2) { + Matrix result(0); + int offset = 0; + for (int column = 0; column < columns; column++) { + for (int row = 0; row < rows; row++) { + result[row + offset] = v1[row] * v2[column]; + } + offset += rows; + } + return result; +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +static inline Matrix OuterProductHelper(const Vector& v1, + const Vector& v2) { + return Matrix(v1[0] * v2[0], v1[1] * v2[0], v1[0] * v2[1], + v1[1] * v2[1]); +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +static inline Matrix OuterProductHelper(const Vector& v1, + const Vector& v2) { + return Matrix(v1[0] * v2[0], v1[1] * v2[0], v1[2] * v2[0], + v1[0] * v2[1], v1[1] * v2[1], v1[2] * v2[1], + v1[0] * v2[2], v1[1] * v2[2], v1[2] * v2[2]); +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +static inline Matrix OuterProductHelper(const Vector& v1, + const Vector& v2) { + return Matrix( + v1[0] * v2[0], v1[1] * v2[0], v1[2] * v2[0], v1[3] * v2[0], v1[0] * v2[1], + v1[1] * v2[1], v1[2] * v2[1], v1[3] * v2[1], v1[0] * v2[2], v1[1] * v2[2], + v1[2] * v2[2], v1[3] * v2[2], v1[0] * v2[3], v1[1] * v2[3], v1[2] * v2[3], + v1[3] * v2[3]); +} +/// @endcond + +/// @cond MATHFU_INTERNAL +/// Struct used for template specialization for functions that +/// returns constants. +template +class Constants { + public: + /// Minimum absolute value of the determinant of an invertible matrix. + static T GetDeterminantThreshold() { + // No constant defined for the general case. + assert(false); + return 0; + } +}; +/// @endcond + +/// Functions that return constants for float values. +template <> +class Constants { + public: + /// @brief Minimum absolute value of the determinant of an invertible + /// float Matrix. + /// + /// float values have 23 bits of precision which is roughly + /// 1e7f, given that the final step of matrix inversion is multiplication + /// with the inverse of the determinant, the minimum value of the + /// determinant is 1e-7f before the precision too low to accurately + /// calculate the inverse. + /// @returns Minimum absolute value of the determinant of an invertible + /// float Matrix. + /// + /// @related mathfu::Matrix::InverseWithDeterminantCheck() + static float GetDeterminantThreshold() { return 1e-7f; } +}; + +/// Functions that return constants for double values. +template <> +class Constants { + public: + /// @brief Minimum absolute value of the determinant of an invertible + /// double Matrix. + /// + /// double values have 46 bits of precision which is roughly + /// 1e15, given that the final step of matrix inversion is multiplication + /// with the inverse of the determinant, the minimum value of the + /// determinant is 1e-15 before the precision too low to accurately + /// calculate the inverse. + /// @returns Minimum absolute value of the determinant of an invertible + /// double Matrix. + /// + /// @related mathfu::Matrix::InverseWithDeterminantCheck() + static double GetDeterminantThreshold() { return 1e-15; } +}; + +template +inline Vector EulerHelper(const Matrix& m) { + const T cy = sqrtf(m(0, 0) * m(0, 0) + m(1, 0) * m(1, 0)); + Vector eul; + + if (cy > (float)(16.0f * Constants::GetDeterminantThreshold())) { + return Vector(atan2f(m(2, 1), m(2, 2)), atan2f(-m(2, 0), cy), atan2f(m(1, 0), m(0, 0))); + } + else { + return Vector(atan2f(-m(1, 2), m(1, 1)), atan2f(-m(2, 0), cy), 0); + } + + return Vector(static_cast(0)); +} + +/// @cond MATHFU_INTERNAL +/// @brief Compute the inverse of a matrix. +/// +/// There is template specialization for 2x2, 3x3, and 4x4 matrices to +/// increase performance. Inverse is not implemented for dense matrices that +/// are not of size 2x2, 3x3, and 4x4. If check_invertible is true the +/// determine of the matrix is compared with +/// Constants::GetDeterminantThreshold() to roughly determine whether the +/// Matrix is invertible. +template +inline bool InverseHelper(const Matrix& m, + Matrix* const inverse) { + assert(false); + (void)m; + *inverse = T::Identity(); + return false; +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +inline bool InverseHelper(const Matrix& m, + Matrix* const inverse) { + T determinant = m[0] * m[3] - m[1] * m[2]; + if (check_invertible && + fabs(determinant) < Constants::GetDeterminantThreshold()) { + return false; + } + T inverseDeterminant = 1 / determinant; + (*inverse)[0] = inverseDeterminant * m[3]; + (*inverse)[1] = -inverseDeterminant * m[1]; + (*inverse)[2] = -inverseDeterminant * m[2]; + (*inverse)[3] = inverseDeterminant * m[0]; + return true; +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +inline bool InverseHelper(const Matrix& m, + Matrix* const inverse) { + // Find determinant of matrix. + T sub11 = m[4] * m[8] - m[5] * m[7], sub12 = -m[1] * m[8] + m[2] * m[7], + sub13 = m[1] * m[5] - m[2] * m[4]; + T determinant = m[0] * sub11 + m[3] * sub12 + m[6] * sub13; + if (check_invertible && + fabs(determinant) < Constants::GetDeterminantThreshold()) { + return false; + } + // Find determinants of 2x2 submatrices for the elements of the inverse. + *inverse = Matrix( + sub11, sub12, sub13, m[6] * m[5] - m[3] * m[8], m[0] * m[8] - m[6] * m[2], + m[3] * m[2] - m[0] * m[5], m[3] * m[7] - m[6] * m[4], + m[6] * m[1] - m[0] * m[7], m[0] * m[4] - m[3] * m[1]); + *(inverse) *= 1 / determinant; + return true; +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +inline bool InverseHelper(const Matrix& m, + Matrix* const inverse) { + // Find determinant of matrix. + T sub11 = m[4] * m[8] - m[5] * m[7], sub12 = -m[1] * m[8] + m[2] * m[7], + sub13 = m[1] * m[5] - m[2] * m[4]; + T determinant = m[0] * sub11 + m[3] * sub12 + m[6] * sub13; + if (check_invertible && + fabs(determinant) < Constants::GetDeterminantThreshold()) { + return false; + } + + sub11 /= determinant; + sub12 /= determinant; + sub13 /= determinant; + + T sub21 = (m[6] * m[5] - m[3] * m[8]) / determinant; + T sub22 = (m[0] * m[8] - m[6] * m[2]) / determinant; + T sub23 = (m[3] * m[2] - m[0] * m[5]) / determinant; + + T sub31 = (m[3] * m[7] - m[6] * m[4]) / determinant; + T sub32 = (m[6] * m[1] - m[0] * m[7]) / determinant; + T sub33 = (m[0] * m[4] - m[3] * m[1]) / determinant; + + T sub41 = -(m[9] * sub11 + m[10] * sub21 + m[11] * sub31); + T sub42 = -(m[9] * sub12 + m[10] * sub22 + m[11] * sub32); + T sub43 = -(m[9] * sub13 + m[10] * sub23 + m[11] * sub33); + + // Find determinants of 4x3 submatrices for the elements of the inverse. + *inverse = Matrix( + sub11, sub12, sub13, + sub21, sub22, sub23, + sub31, sub32, sub33, + sub41, sub42, sub43); + return true; +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +inline int FindLargestPivotElem(const Matrix& m) { + Vector fabs_column(fabs(m[0]), fabs(m[1]), fabs(m[2]), fabs(m[3])); + if (fabs_column[0] > fabs_column[1]) { + if (fabs_column[0] > fabs_column[2]) { + if (fabs_column[0] > fabs_column[3]) { + return 0; + } else { + return 3; + } + } else if (fabs_column[2] > fabs_column[3]) { + return 2; + } else { + return 3; + } + } else if (fabs_column[1] > fabs_column[2]) { + if (fabs_column[1] > fabs_column[3]) { + return 1; + } else { + return 3; + } + } else if (fabs_column[2] > fabs_column[3]) { + return 2; + } else { + return 3; + } +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +bool InverseHelper(const Matrix& m, Matrix* const inverse) { + // This will find the pivot element. + int pivot_elem = FindLargestPivotElem(m); + // This will perform the pivot and find the row, column, and 3x3 submatrix + // for this pivot. + Vector row, column; + Matrix matrix; + if (pivot_elem == 0) { + row = Vector(m[4], m[8], m[12]); + column = Vector(m[1], m[2], m[3]); + matrix = + Matrix(m[5], m[6], m[7], m[9], m[10], m[11], m[13], m[14], m[15]); + } else if (pivot_elem == 1) { + row = Vector(m[5], m[9], m[13]); + column = Vector(m[0], m[2], m[3]); + matrix = + Matrix(m[4], m[6], m[7], m[8], m[10], m[11], m[12], m[14], m[15]); + } else if (pivot_elem == 2) { + row = Vector(m[6], m[10], m[14]); + column = Vector(m[0], m[1], m[3]); + matrix = + Matrix(m[4], m[5], m[7], m[8], m[9], m[11], m[12], m[13], m[15]); + } else { + row = Vector(m[7], m[11], m[15]); + column = Vector(m[0], m[1], m[2]); + matrix = + Matrix(m[4], m[5], m[6], m[8], m[9], m[10], m[12], m[13], m[14]); + } + T pivot_value = m[pivot_elem]; + if (check_invertible && + fabs(pivot_value) < Constants::GetDeterminantThreshold()) { + return false; + } + // This will compute the inverse using the row, column, and 3x3 submatrix. + T inv = -1 / pivot_value; + row *= inv; + matrix += Matrix::OuterProduct(column, row); + Matrix mat_inverse; + if (!InverseHelper(matrix, &mat_inverse) && + check_invertible) { + return false; + } + Vector col_inverse = mat_inverse * (column * inv); + Vector row_inverse = row * mat_inverse; + T pivot_inverse = Vector::DotProduct(row, col_inverse) - inv; + if (pivot_elem == 0) { + *inverse = Matrix( + pivot_inverse, col_inverse[0], col_inverse[1], col_inverse[2], + row_inverse[0], mat_inverse[0], mat_inverse[1], mat_inverse[2], + row_inverse[1], mat_inverse[3], mat_inverse[4], mat_inverse[5], + row_inverse[2], mat_inverse[6], mat_inverse[7], mat_inverse[8]); + } else if (pivot_elem == 1) { + *inverse = Matrix( + row_inverse[0], mat_inverse[0], mat_inverse[1], mat_inverse[2], + pivot_inverse, col_inverse[0], col_inverse[1], col_inverse[2], + row_inverse[1], mat_inverse[3], mat_inverse[4], mat_inverse[5], + row_inverse[2], mat_inverse[6], mat_inverse[7], mat_inverse[8]); + } else if (pivot_elem == 2) { + *inverse = Matrix( + row_inverse[0], mat_inverse[0], mat_inverse[1], mat_inverse[2], + row_inverse[1], mat_inverse[3], mat_inverse[4], mat_inverse[5], + pivot_inverse, col_inverse[0], col_inverse[1], col_inverse[2], + row_inverse[2], mat_inverse[6], mat_inverse[7], mat_inverse[8]); + } else { + *inverse = Matrix( + row_inverse[0], mat_inverse[0], mat_inverse[1], mat_inverse[2], + row_inverse[1], mat_inverse[3], mat_inverse[4], mat_inverse[5], + row_inverse[2], mat_inverse[6], mat_inverse[7], mat_inverse[8], + pivot_inverse, col_inverse[0], col_inverse[1], col_inverse[2]); + } + return true; +} +/// @endcond + + +/// @cond MATHFU_INTERNAL +template +inline Matrix ScaleHelper(const Matrix& m, const Vector& v) { + Matrix ret = m; + for (int i = 0; i < columns; ++i) { + ret.GetColumn(i) *= v[i]; + } + return ret; +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +inline Matrix ScaleHelper(const Matrix& m, const Vector& v) { + Matrix ret = m; + for (int i = 0; i < 3; ++i) { + ret.GetColumn(i).x *= v[i].x; + ret.GetColumn(i).y *= v[i].y; + ret.GetColumn(i).z *= v[i].z; + } + return ret; +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +inline Vector ToScaleVectorHelper(const Matrix& m) { + Vector ret; + for (int i = 0; i < columns; ++i) { + ret[i] = m.GetColumn(i).Length(); + } + return ret; +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +inline Vector ToScaleVector3DHelper(const Matrix& m) { + Vector ret; + for (int i = 0; i < 3; ++i) { + ret[i] = m.GetColumn(i).Length(); + } + return ret; +} + +template +inline Vector ToScaleVector3DHelper(const Matrix& m) { + Vector ret; + for (int i = 0; i < 3; ++i) { + ret[i] = m.GetColumn(i).xyz().Length(); + } + return ret; +} +/// @endcond + +/// @cond MATHFU_INTERNAL +/// Create a 4x4 perpective matrix. +template +inline Matrix PerspectiveHelper(T fovy, T aspect, T znear, T zfar, + T handedness) { + const T y = 1 / std::tan(fovy * static_cast(.5)); + const T x = y / aspect; + const T zdist = (znear - zfar); + const T zfar_per_zdist = zfar / zdist; + return Matrix(x, 0, 0, 0, 0, y, 0, 0, 0, 0, + zfar_per_zdist * handedness, -1 * handedness, 0, 0, + 2.0f * znear * zfar_per_zdist, 0); +} +/// @endcond + +/// @cond MATHFU_INTERNAL +/// Create a 4x4 perpective matrix. +template +inline Matrix PerspectiveHelper(T left, T right, T bottom, T top, T znear, T zfar, + T handedness) { + const T x = right - left; + const T y = top - bottom; + const T z = zfar - znear; + + return Matrix(znear * 2 / x, 0, 0, 0, + 0, znear * 2 / y, 0, 0, + (right + left) / x, (top + bottom) / y, -(zfar + znear) / z, -1, + 0, 0, (-2 * znear * zfar) / z, 0); +} +/// @endcond + +/// @cond MATHFU_INTERNAL +/// Create a 4x4 orthographic matrix. +template +static inline Matrix OrthoHelper(T left, T right, T bottom, T top, + T znear, T zfar, T handedness) { + return Matrix(static_cast(2) / (right - left), 0, 0, 0, 0, + static_cast(2) / (top - bottom), 0, 0, 0, 0, + -handedness * static_cast(2) / (zfar - znear), 0, + -(right + left) / (right - left), + -(top + bottom) / (top - bottom), + -(zfar + znear) / (zfar - znear), static_cast(1)); +} +/// @endcond + +/// @cond MATHFU_INTERNAL +/// Calculate the axes required to construct a 3-dimensional camera matrix that +/// looks at "at" from eye position "eye" with the up vector "up". The axes +/// are returned in a 4 element "axes" array. +template +static void LookAtHelperCalculateAxes(const Vector& at, + const Vector& eye, + const Vector& up, T handedness, + Vector* const axes) { + // Notice that y-axis is always the same regardless of handedness. + axes[2] = (at - eye).Normalized(); + axes[0] = Vector::CrossProduct(up, axes[2]).Normalized(); + axes[1] = Vector::CrossProduct(axes[2], axes[0]); + axes[3] = Vector(handedness * Vector::DotProduct(axes[0], eye), + -Vector::DotProduct(axes[1], eye), + handedness * Vector::DotProduct(axes[2], eye)); + + // Default calculation is left-handed (i.e. handedness=-1). + // Negate x and z axes for right-handed (i.e. handedness=+1) case. + const T neg = -handedness; + axes[0] *= neg; + axes[2] *= neg; +} +/// @endcond + +/// @cond MATHFU_INTERNAL +/// Create a 3-dimensional camera matrix. +template +static inline Matrix LookAtHelper(const Vector& at, + const Vector& eye, + const Vector& up, + T handedness) { + Vector axes[4]; + LookAtHelperCalculateAxes(at, eye, up, handedness, axes); + const Vector column0(axes[0][0], axes[1][0], axes[2][0], 0); + const Vector column1(axes[0][1], axes[1][1], axes[2][1], 0); + const Vector column2(axes[0][2], axes[1][2], axes[2][2], 0); + const Vector column3(axes[3], 1); + return Matrix(column0, column1, column2, column3); +} +/// @endcond + +/// @cond MATHFU_INTERNAL +/// Get the 3D position in object space from a window coordinate. +template +static inline bool UnProjectHelper(const Vector& window_coord, + const Matrix& model_view, + const Matrix& projection, + const float window_width, + const float window_height, + Vector& result) { + if (window_coord.z < static_cast(0) || + window_coord.z > static_cast(1)) { + // window_coord.z should be with in [0, 1] + // 0: near plane + // 1: far plane + return false; + } + Matrix matrix = (projection * model_view).Inverse(); + Vector standardized = Vector( + static_cast(2) * (window_coord.x - window_width) / window_width + + static_cast(1), + static_cast(2) * (window_coord.y - window_height) / window_height + + static_cast(1), + static_cast(2) * window_coord.z - static_cast(1), + static_cast(1)); + + Vector multiply = matrix * standardized; + if (multiply.w == static_cast(0)) { + return false; + } + result = multiply.xyz() / multiply.w; + return true; +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +static inline Matrix FromTypeHelper(const CompatibleT& compatible) { +// C++11 is required for constructed unions. +#if __cplusplus >= 201103L + // Use a union instead of reinterpret_cast to avoid aliasing bugs. + union ConversionUnion { + ConversionUnion() {} // C++11. + CompatibleT compatible; + VectorPacked packed[columns]; + } u; + static_assert(sizeof(u.compatible) == sizeof(u.packed), "Conversion size mismatch."); + + // The read of `compatible` and write to `u.compatible` gets optimized away, + // and this becomes essentially a safe reinterpret_cast. + u.compatible = compatible; + + // Call the packed vector constructor with the `compatible` data. + return Matrix(u.packed); +#else + // Use the less-desirable memcpy technique if C++11 is not available. + // Most compilers understand memcpy deep enough to avoid replace the function + // call with a series of load/stores, which should then get optimized away, + // however in the worst case the optimize away may not happen. + // Note: Memcpy avoids aliasing bugs because it operates via unsigned char*, + // which is allowed to alias any type. + // See: + // http://stackoverflow.com/questions/15745030/type-punning-with-void-without-breaking-the-strict-aliasing-rule-in-c99 + Matrix m; + assert(sizeof(m) == sizeof(compatible)); + memcpy(&m, &compatible, sizeof(m)); + return m; +#endif // __cplusplus >= 201103L +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +static inline CompatibleT ToTypeHelper(const Matrix& m) { +// See FromTypeHelper() for comments. +#if __cplusplus >= 201103L + union ConversionUnion { + ConversionUnion() {} + CompatibleT compatible; + VectorPacked packed[columns]; + } u; + static_assert(sizeof(u.compatible) == sizeof(u.packed), "Conversion size mismatch."); + m.Pack(u.packed); + return u.compatible; +#else + CompatibleT compatible; + assert(sizeof(m) == sizeof(compatible)); + memcpy(&compatible, &m, sizeof(compatible)); + return compatible; +#endif // __cplusplus >= 201103L +} +/// @endcond + +/// @typedef AffineTransform +/// +/// @brief A typedef representing a 4x3 float affine transformation. +/// Since the last row ('w' row) of an affine transformation is fixed, +/// this data type only includes the variable information for the transform. +typedef Matrix AffineTransform; +/// @} + +} // namespace mathfu + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// Include the specializations to avoid template errors. +// See includes at bottom of vector.h for further explanation. +#include "mathfu/matrix_4x4.h" +#include "mathfu/internal/matrix_4x4_simd.h" + +#endif // MATHFU_MATRIX_H_ diff --git a/intern/mathfu/mathfu/matrix_4x4.h b/intern/mathfu/mathfu/matrix_4x4.h new file mode 100644 index 000000000000..063566274828 --- /dev/null +++ b/intern/mathfu/mathfu/matrix_4x4.h @@ -0,0 +1,22 @@ +/* +* Copyright 2016 Google Inc. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef MATHFU_MATRIX_4X4_H_ +#define MATHFU_MATRIX_4X4_H_ + +// Prefer including matrix.h directly, since it includes specializations. +#include "mathfu/matrix.h" + +#endif // MATHFU_MATRIX_4X4_H_ diff --git a/intern/mathfu/mathfu/quaternion.h b/intern/mathfu/mathfu/quaternion.h new file mode 100644 index 000000000000..b62ffec404de --- /dev/null +++ b/intern/mathfu/mathfu/quaternion.h @@ -0,0 +1,587 @@ +/* +* Copyright 2014 Google Inc. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef MATHFU_QUATERNION_H_ +#define MATHFU_QUATERNION_H_ + +#ifdef _WIN32 +#if !defined(_USE_MATH_DEFINES) +#define _USE_MATH_DEFINES // For M_PI. +#endif // !defined(_USE_MATH_DEFINES) +#endif // _WIN32 + +#include "mathfu/matrix.h" +#include "mathfu/vector.h" + +#include + +/// @file mathfu/quaternion.h +/// @brief Quaternion class and functions. +/// @addtogroup mathfu_quaternion +/// +/// MathFu provides a Quaternion class that utilizes SIMD optimized +/// Matrix and Vector classes. + +namespace mathfu { + +/// @addtogroup mathfu_quaternion +/// @{ +/// @class Quaternion +/// +/// @brief Stores a Quaternion of type T and provides a set of utility +/// operations on each Quaternion. +/// @tparam T Type of each element in the Quaternion. +template +class Quaternion { + public: + /// @brief Construct an uninitialized Quaternion. + inline Quaternion() {} + + /// @brief Construct a Quaternion from a copy. + /// @param q Quaternion to copy. + inline Quaternion(const Quaternion& q) { + s_ = q.s_; + v_ = q.v_; + } + + /// @brief Construct a Quaternion using scalar values to initialize each + /// element. + /// + /// @param s1 Scalar component. + /// @param s2 First element of the Vector component. + /// @param s3 Second element of the Vector component. + /// @param s4 Third element of the Vector component. + inline Quaternion(const T& s1, const T& s2, const T& s3, const T& s4) { + s_ = s1; + v_ = Vector(s2, s3, s4); + } + + /// @brief Construct a quaternion from a scalar and 3-dimensional Vector. + /// + /// @param s1 Scalar component. + /// @param v1 Vector component. + inline Quaternion(const T& s1, const Vector& v1) { + s_ = s1; + v_ = v1; + } + + /// @brief Construct a quaternion from an array. + /// + /// @param s1 Scalar component. + /// @param v1 Vector component. + inline Quaternion(const T* const a) { + s_ = a[3]; + v_ = Vector(a[0], a[1], a[2]); + } + + /// @brief Return the scalar component of the quaternion. + /// + /// @return The scalar component + inline T& scalar() { return s_; } + + /// @brief Return the scalar component of the quaternion. + /// + /// @return The scalar component + inline const T& scalar() const { return s_; } + + /// @brief Set the scalar component of the quaternion. + /// + /// @param s Scalar component. + inline void set_scalar(const T& s) { s_ = s; } + + /// @brief Return the vector component of the quaternion. + /// + /// @return The scalar component + inline Vector& vector() { return v_; } + + /// @brief Return the vector component of the quaternion. + /// + /// @return The scalar component + inline const Vector& vector() const { return v_; } + + /// @brief Set the vector component of the quaternion. + /// + /// @param v Vector component. + inline void set_vector(const Vector& v) { v_ = v; } + + /// @brief Calculate the inverse Quaternion. + /// + /// This calculates the inverse such that (q * q).Inverse() + /// is the identity. + /// + /// @return Quaternion containing the result. + inline Quaternion Inverse() const { return Quaternion(s_, -v_); } + + /// @brief Multiply this Quaternion with another Quaternion. + /// + /// @note This is equivalent to + /// FromMatrix(ToMatrix() * q.ToMatrix()). + /// @param q Quaternion to multiply with. + /// @return Quaternion containing the result. + inline Quaternion operator*(const Quaternion& q) const { + return Quaternion( + s_ * q.s_ - Vector::DotProduct(v_, q.v_), + s_ * q.v_ + q.s_ * v_ + Vector::CrossProduct(v_, q.v_)); + } + + /// @brief Multiply this Quaternion by a scalar. + /// + /// This multiplies the angle of the rotation by a scalar factor. + /// @param s1 Scalar to multiply with. + /// @return Quaternion containing the result. + inline Quaternion operator*(const T& s1) const { + T angle; + Vector axis; + ToAngleAxis(&angle, &axis); + angle *= s1; + return Quaternion(cos(0.5f * angle), + axis * static_cast(sin(0.5f * angle))); + } + + /// @brief Multiply a Vector by this Quaternion. + /// + /// This will rotate the specified vector by the rotation specified by this + /// Quaternion. + /// + /// @param v1 Vector to multiply by this Quaternion. + /// @return Rotated Vector. + inline Vector operator*(const Vector& v1) const { + T ss = s_ + s_; + return ss * Vector::CrossProduct(v_, v1) + (ss * s_ - 1) * v1 + + 2 * Vector::DotProduct(v_, v1) * v_; + } + + /// @brief Normalize this quaterion (in-place). + /// + /// @return Length of the quaternion. + inline T Normalize() { + T length = sqrt(s_ * s_ + Vector::DotProduct(v_, v_)); + T scale = (1 / length); + s_ *= scale; + v_ *= scale; + return length; + } + + /// @brief Calculate the normalized version of this quaternion. + /// + /// @return The normalized quaternion. + inline Quaternion Normalized() const { + Quaternion q(*this); + q.Normalize(); + return q; + } + + /// @brief Convert this Quaternion to an Angle and axis. + /// + /// The returned angle is the size of the rotation in radians about the + /// axis represented by this Quaternion. + /// + /// @param angle Receives the angle. + /// @param axis Receives the normalized axis. + inline void ToAngleAxis(T* angle, Vector* axis) const { + *axis = (s_ > 0 ? v_ : -v_); + const float length = axis->SafeNormalize(); + *angle = 2 * atan2(length, s_ > 0 ? s_ : -s_); + } + + /// @brief Convert this Quaternion to 3 Euler Angles. + /// + /// @return 3-dimensional Vector where each element is a angle of rotation + /// (in radians) around the x, y, and z axes. + inline Vector ToEulerAngles() const { + Matrix m(ToMatrix()); + T cos2 = m[0] * m[0] + m[1] * m[1]; + if (cos2 < 1e-6f) { + return Vector( + 0, + m[2] < 0 ? static_cast(0.5 * M_PI) : static_cast(-0.5 * M_PI), + -std::atan2(m[3], m[4])); + } else { + return Vector(std::atan2(m[5], m[8]), + std::atan2(-m[2], std::sqrt(cos2)), + std::atan2(m[1], m[0])); + } + } + + /// @brief Convert to a 3x3 Matrix. + /// + /// @return 3x3 rotation Matrix. + inline Matrix ToMatrix() const { + const T x2 = v_[0] * v_[0], y2 = v_[1] * v_[1], z2 = v_[2] * v_[2]; + const T sx = s_ * v_[0], sy = s_ * v_[1], sz = s_ * v_[2]; + const T xz = v_[0] * v_[2], yz = v_[1] * v_[2], xy = v_[0] * v_[1]; + return Matrix(1 - 2 * (y2 + z2), 2 * (xy + sz), 2 * (xz - sy), + 2 * (xy - sz), 1 - 2 * (x2 + z2), 2 * (sx + yz), + 2 * (sy + xz), 2 * (yz - sx), 1 - 2 * (x2 + y2)); + } + + /// @brief Convert to a 4x4 Matrix. + /// + /// @return 4x4 transform Matrix. + inline Matrix ToMatrix4() const { + const T x2 = v_[0] * v_[0], y2 = v_[1] * v_[1], z2 = v_[2] * v_[2]; + const T sx = s_ * v_[0], sy = s_ * v_[1], sz = s_ * v_[2]; + const T xz = v_[0] * v_[2], yz = v_[1] * v_[2], xy = v_[0] * v_[1]; + return Matrix(1 - 2 * (y2 + z2), 2 * (xy + sz), 2 * (xz - sy), 0.0f, + 2 * (xy - sz), 1 - 2 * (x2 + z2), 2 * (sx + yz), 0.0f, + 2 * (sy + xz), 2 * (yz - sx), 1 - 2 * (x2 + y2), 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + } + + /// @brief Create a Quaternion from an angle and axis. + /// + /// @param angle Angle in radians to rotate by. + /// @param axis Axis in 3D space to rotate around. + /// @return Quaternion containing the result. + static Quaternion FromAngleAxis(const T& angle, const Vector& axis) { + const T halfAngle = static_cast(0.5) * angle; + Vector localAxis(axis); + return Quaternion( + cos(halfAngle), + localAxis.Normalized() * static_cast(sin(halfAngle))); + } + + /// @brief Create a quaternion from 3 euler angles. + /// + /// @param angles 3-dimensional Vector where each element contains an + /// angle in radius to rotate by about the x, y and z axes. + /// @return Quaternion containing the result. + static Quaternion FromEulerAngles(const Vector& angles) { + const Vector halfAngles(static_cast(0.5) * angles[0], + static_cast(0.5) * angles[1], + static_cast(0.5) * angles[2]); + const T sinx = std::sin(halfAngles[0]); + const T cosx = std::cos(halfAngles[0]); + const T siny = std::sin(halfAngles[1]); + const T cosy = std::cos(halfAngles[1]); + const T sinz = std::sin(halfAngles[2]); + const T cosz = std::cos(halfAngles[2]); + return Quaternion(cosx * cosy * cosz + sinx * siny * sinz, + sinx * cosy * cosz - cosx * siny * sinz, + cosx * siny * cosz + sinx * cosy * sinz, + cosx * cosy * sinz - sinx * siny * cosz); + } + + /// @brief Create a quaternion from a rotation Matrix. + /// + /// @param m 3x3 rotation Matrix. + /// @return Quaternion containing the result. + static Quaternion FromMatrix(const Matrix& m) { + const T trace = m(0, 0) + m(1, 1) + m(2, 2); + if (trace > 0) { + const T s = sqrt(trace + 1) * 2; + const T oneOverS = 1 / s; + return Quaternion(static_cast(0.25) * s, (m[5] - m[7]) * oneOverS, + (m[6] - m[2]) * oneOverS, (m[1] - m[3]) * oneOverS); + } else if (m[0] > m[4] && m[0] > m[8]) { + const T s = sqrt(m[0] - m[4] - m[8] + 1) * 2; + const T oneOverS = 1 / s; + return Quaternion((m[5] - m[7]) * oneOverS, static_cast(0.25) * s, + (m[3] + m[1]) * oneOverS, (m[6] + m[2]) * oneOverS); + } else if (m[4] > m[8]) { + const T s = sqrt(m[4] - m[0] - m[8] + 1) * 2; + const T oneOverS = 1 / s; + return Quaternion((m[6] - m[2]) * oneOverS, (m[3] + m[1]) * oneOverS, + static_cast(0.25) * s, (m[5] + m[7]) * oneOverS); + } else { + const T s = sqrt(m[8] - m[0] - m[4] + 1) * 2; + const T oneOverS = 1 / s; + return Quaternion((m[1] - m[3]) * oneOverS, (m[6] + m[2]) * oneOverS, + (m[5] + m[7]) * oneOverS, static_cast(0.25) * s); + } + } + + /// @brief Create a quaternion from the upper-left 3x3 roation Matrix of a 4x4 + /// Matrix. + /// + /// @param m 4x4 Matrix. + /// @return Quaternion containing the result. + static Quaternion FromMatrix(const Matrix& m) { + const T trace = m(0, 0) + m(1, 1) + m(2, 2); + if (trace > 0) { + const T s = sqrt(trace + 1) * 2; + const T oneOverS = 1 / s; + return Quaternion(static_cast(0.25) * s, (m[6] - m[9]) * oneOverS, + (m[8] - m[2]) * oneOverS, (m[1] - m[4]) * oneOverS); + } else if (m[0] > m[5] && m[0] > m[10]) { + const T s = sqrt(m[0] - m[5] - m[10] + 1) * 2; + const T oneOverS = 1 / s; + return Quaternion((m[6] - m[9]) * oneOverS, static_cast(0.25) * s, + (m[4] + m[1]) * oneOverS, (m[8] + m[2]) * oneOverS); + } else if (m[5] > m[10]) { + const T s = sqrt(m[5] - m[0] - m[10] + 1) * 2; + const T oneOverS = 1 / s; + return Quaternion((m[8] - m[2]) * oneOverS, (m[4] + m[1]) * oneOverS, + static_cast(0.25) * s, (m[6] + m[9]) * oneOverS); + } else { + const T s = sqrt(m[10] - m[0] - m[5] + 1) * 2; + const T oneOverS = 1 / s; + return Quaternion((m[1] - m[4]) * oneOverS, (m[8] + m[2]) * oneOverS, + (m[6] + m[9]) * oneOverS, static_cast(0.25) * s); + } + } + + /// @brief Calculate the dot product of two Quaternions. + /// + /// @param q1 First quaternion. + /// @param q2 Second quaternion + /// @return The scalar dot product of both Quaternions. + static inline T DotProduct(const Quaternion& q1, const Quaternion& q2) { + return q1.s_ * q2.s_ + Vector::DotProduct(q1.v_, q2.v_); + } + + /// @brief Calculate the spherical linear interpolation between two + /// Quaternions. + /// + /// @param q1 Start Quaternion. + /// @param q2 End Quaternion. + /// @param s1 The scalar value determining how far from q1 and q2 the + /// resulting quaternion should be. A value of 0 corresponds to q1 and a + /// value of 1 corresponds to q2. + /// @result Quaternion containing the result. + static inline Quaternion Slerp(const Quaternion& q1, + const Quaternion& q2, const T& s1) { + if (q1.s_ * q2.s_ + Vector::DotProduct(q1.v_, q2.v_) > 0.999999f) + return Quaternion(q1.s_ * (1 - s1) + q2.s_ * s1, + q1.v_ * (1 - s1) + q2.v_ * s1); + return q1 * ((q1.Inverse() * q2) * s1); + } + + /// @brief Access an element of the quaternion. + /// + /// @param i Index of the element to access. + /// @return A reference to the accessed data that can be modified by the + /// caller. + inline T& operator[](const int i) { + if (i == 0) return s_; + return v_[i - 1]; + } + + /// @brief Access an element of the quaternion. + /// + /// @param i Index of the element to access. + /// @return A const reference to the accessed. + inline const T& operator[](const int i) const { + return const_cast*>(this)->operator[](i); + } + + /// @brief Pack a quaterion to a array "d" element. + /// + /// @param a array "d" element to write to. + inline void Pack(T *a) const { + a[0] = w; + a[1] = x; + a[2] = y; + a[3] = z; + } + + /// @brief Returns a vector that is perpendicular to the supplied vector. + /// + /// @param v1 An arbitrary vector + /// @return A vector perpendicular to v1. Normally this will just be + /// the cross product of v1, v2. If they are parallel or opposite though, + /// the routine will attempt to pick a vector. + static inline Vector PerpendicularVector(const Vector& v) { + // We start out by taking the cross product of the vector and the x-axis to + // find something parallel to the input vectors. If that cross product + // turns out to be length 0 (i. e. the vectors already lie along the x axis) + // then we use the y-axis instead. + Vector axis = Vector::CrossProduct( + Vector(static_cast(1), static_cast(0), static_cast(0)), + v); + // We use a fairly high epsilon here because we know that if this number + // is too small, the axis we'll get from a cross product with the y axis + // will be much better and more numerically stable. + if (axis.LengthSquared() < static_cast(0.05)) { + axis = Vector::CrossProduct( + Vector(static_cast(0), static_cast(1), static_cast(0)), + v); + } + return axis; + } + + /// @brief Returns the a Quaternion that rotates from start to end. + /// + /// @param v1 The starting vector + /// @param v2 The vector to rotate to + /// @param preferred_axis the axis to use, if v1 and v2 are parallel. + /// @return A Quaternion describing the rotation from v1 to v2 + /// See the comment on RotateFromToWithAxis for an explanation of the math. + static inline Quaternion RotateFromToWithAxis( + const Vector& v1, const Vector& v2, + const Vector& preferred_axis) { + Vector start = v1.Normalized(); + Vector end = v2.Normalized(); + + T dot_product = Vector::DotProduct(start, end); + // Any rotation < 0.1 degrees is treated as no rotation + // in order to avoid division by zero errors. + // So we early-out in cases where it's less then 0.1 degrees. + // cos( 0.1 degrees) = 0.99999847691 + if (dot_product >= static_cast(0.99999847691)) { + return Quaternion::identity; + } + // If the vectors point in opposite directions, return a 180 degree + // rotation, on the axis that they asked for. + if (dot_product <= static_cast(-0.99999847691)) { + return Quaternion(static_cast(0), preferred_axis); + } + // Degenerate cases have been handled, so if we're here, we have to + // actually compute the angle we want: + Vector cross_product = Vector::CrossProduct(start, end); + + return Quaternion(static_cast(1.0) + dot_product, cross_product) + .Normalized(); + } + + /// @brief Returns the a Quaternion that rotates from start to end. + /// + /// @param v1 The starting vector + /// @param v2 The vector to rotate to + /// @return A Quaternion describing the rotation from v1 to v2. In the case + /// where the vectors are parallel, it returns the identity. In the case + /// where + /// they point in opposite directions, it picks an arbitrary axis. (Since + /// there + /// are technically infinite possible quaternions to represent a 180 degree + /// rotation.) + /// + /// The final equation used here is fairly elegant, but its derivation is + /// not obvious: We want to find the quaternion that represents the angle + /// between Start and End. + /// + /// The angle can be expressed as a quaternion with the values: + /// angle: ArcCos(dotproduct(start, end) / (|start|*|end|) + /// axis: crossproduct(start, end).normalized * sin(angle/2) + /// + /// or written as: + /// quaternion(cos(angle/2), axis * sin(angle/2)) + /// + /// Using the trig identity: + /// sin(angle * 2) = 2 * sin(angle) * cos*angle) + /// Via substitution, we can turn this into: + /// sin(angle/2) = 0.5 * sin(angle)/cos(angle/2) + /// + /// Using this substitution, we get: + /// quaternion( cos(angle/2), + /// 0.5 * crossproduct(start, end).normalized + /// * sin(angle) / cos(angle/2)) + /// + /// If we scale the whole thing up by 2 * cos(angle/2) then we get: + /// quaternion(2 * cos(angle/2) * cos(angle/2), + /// crossproduct(start, end).normalized * sin(angle)) + /// + /// (Note that the quaternion is no longer normalized after this scaling) + /// + /// Another trig identity: + /// cos(angle/2) = sqrt((1 + cos(angle) / 2) + /// + /// Substituting this in, we can simplify the quaternion scalar: + /// + /// quaternion(1 + cos(angle), + /// crossproduct(start, end).normalized * sin(angle)) + /// + /// Because cross(start, end) has a magnitude of |start|*|end|*sin(angle), + /// crossproduct(start,end).normalized + /// is equivalent to + /// crossproduct(start,end) / |start| * |end| * sin(angle) + /// So after that substitution: + /// + /// quaternion(1 + cos(angle), + /// crossproduct(start, end) / (|start| * |end|)) + /// + /// dotproduct(start, end) has the value of |start| * |end| * cos(angle), + /// so by algebra, + /// cos(angle) = dotproduct(start, end) / (|start| * |end|) + /// we can replace our quaternion scalar here also: + /// + /// quaternion(1 + dotproduct(start, end) / (|start| * |end|), + /// crossproduct(start, end) / (|start| * |end|)) + /// + /// If start and end are normalized, then |start| * |end| = 1, giving us a + /// final quaternion of: + /// + /// quaternion(1 + dotproduct(start, end), crossproduct(start, end)) + static inline Quaternion RotateFromTo(const Vector& v1, + const Vector& v2) { + Vector start = v1.Normalized(); + Vector end = v2.Normalized(); + + T dot_product = Vector::DotProduct(start, end); + // Any rotation < 0.1 degrees is treated as no rotation + // in order to avoid division by zero errors. + // So we early-out in cases where it's less then 0.1 degrees. + // cos( 0.1 degrees) = 0.99999847691 + if (dot_product >= static_cast(0.99999847691)) { + return Quaternion::identity; + } + // If the vectors point in opposite directions, return a 180 degree + // rotation, on an arbitrary axis. + if (dot_product <= static_cast(-0.99999847691)) { + return Quaternion(0, PerpendicularVector(start)); + } + // Degenerate cases have been handled, so if we're here, we have to + // actually compute the angle we want: + Vector cross_product = Vector::CrossProduct(start, end); + + return Quaternion(static_cast(1.0) + dot_product, cross_product) + .Normalized(); + } + + /// @brief Contains a quaternion doing the identity transform. + static Quaternion identity; + + MATHFU_DEFINE_CLASS_SIMD_AWARE_NEW_DELETE + + union { + struct { + Vector v_; + }; + struct { + T x; + T y; + T z; + }; + }; + union { + T s_; + T w; + }; +}; + +template +Quaternion Quaternion::identity = Quaternion(1, 0, 0, 0); +/// @} + +/// @addtogroup mathfu_quaternion +/// @{ + +/// @brief Multiply a Quaternion by a scalar. +/// +/// This multiplies the angle of the rotation of the specified Quaternion +/// by a scalar factor. +/// @param s Scalar to multiply with. +/// @param q Quaternion to scale. +/// @return Quaternion containing the result. +/// +/// @related Quaternion +template +inline Quaternion operator*(const T& s, const Quaternion& q) { + return q * s; +} +/// @} + +} // namespace mathfu +#endif // MATHFU_QUATERNION_H_ diff --git a/intern/mathfu/mathfu/rect.h b/intern/mathfu/mathfu/rect.h new file mode 100644 index 000000000000..04d3738adefd --- /dev/null +++ b/intern/mathfu/mathfu/rect.h @@ -0,0 +1,82 @@ +/* +* Copyright 2016 Google Inc. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef MATHFU_RECT_H_ +#define MATHFU_RECT_H_ + +#include "mathfu/vector.h" + +namespace mathfu { + +/// @addtogroup mathfu_rect +/// @{ +/// @class Rect "mathfu/rect.h" +/// @brief Rect of type T containing position (pos) and width. +/// +/// Rect contains two 2D Vectors of type T representing position +/// (pos) and size. +/// +/// @tparam T type of Rect elements. +template +struct Rect { + Vector pos; + Vector size; + + /// @brief Create a rect from a vector4 of the same type. + /// + /// @param v Vector that the data will be copied from. + explicit Rect(const Vector& v) + : pos(v.x, v.y), size(v.z, v.w) {} + + /// @brief Create a rect from x, y, width and height values. + /// + /// @param x the given x value. + /// @param y the given y value. + /// @param width the given width value. + /// @param height the given height value. + inline Rect(T x = static_cast(0), T y = static_cast(0), + T width = static_cast(0), T height = static_cast(0)) + : pos(x, y), size(width, height) {} + + /// @brief Create a rect from two vector2 representing position and size. + /// + /// @param pos Vector representing the position vector (x and y values). + /// @param size Vector represening the size vector (width and height values). + inline Rect(const Vector& pos, const Vector& size) + : pos(pos), size(size) {} +}; +/// @} + +/// @brief Check if two rects are identical. +/// +/// @param r1 Rect to be tested. +/// @param r2 Other rect to be tested. +template +bool operator==(const Rect& r1, const Rect& r2) { + return (r1.pos == r2.pos && r1.size == r2.size); +} + +/// @brief Check if two rects are not identical. +/// +/// @param r1 Rect to be tested. +/// @param r2 Other rect to be tested. +template +bool operator!=(const Rect& r1, const Rect& r2) { + return !(r1 == r2); +} + +} // namespace mathfu + +#endif // MATHFU_RECT_H_ diff --git a/intern/mathfu/mathfu/utilities.h b/intern/mathfu/mathfu/utilities.h new file mode 100755 index 000000000000..886b10d3a095 --- /dev/null +++ b/intern/mathfu/mathfu/utilities.h @@ -0,0 +1,660 @@ +/* +* Copyright 2014 Google Inc. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef MATHFU_UTILITIES_H_ +#define MATHFU_UTILITIES_H_ + +#include +#include +#include +#include +#include +#include + +#include +#include + +/// @file mathfu/utilities.h Utilities +/// @brief Utility macros and functions. + +/// @addtogroup mathfu_build_config +/// +/// By default MathFu will attempt to build with SIMD optimizations enabled +/// based upon the target architecture and compiler options. However, it's +/// possible to change the default build configuration using the following +/// macros: +/// +/// @li @ref MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT +/// @li @ref MATHFU_COMPILE_FORCE_PADDING +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +///
MATHFU_COMPILE_WITHOUT_SIMD_SUPPORTMATHFU_COMPILE_FORCE_PADDINGConfiguration
undefinedundefined or 1Default build configuration, SIMD optimization is enabled based upon +/// the target architecture, compiler options and MathFu library +/// support.
undefined0If SIMD is supported, padding of data structures is disabled. See +/// @ref MATHFU_COMPILE_FORCE_PADDING for more information.
definedundefined/0/1Builds MathFu with explicit SIMD optimization disabled. The compiler +/// could still potentially optimize some code paths with SIMD +/// instructions based upon the compiler options.
+ +#ifdef DOXYGEN +/// @addtogroup mathfu_build_config +/// @{ +/// @def MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT +/// @brief Disable SIMD build configuration. +/// +/// When defined, this macro disables the default behavior of trying to +/// build the library with SIMD enabled based upon the target architecture +/// and compiler options. +/// +/// To use this build option, this macro must be defined in all modules +/// of the project. +#define MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT +/// @} +#endif // DOXYGEN +#if !defined(MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT) +#if defined(__SSE__) +#define MATHFU_COMPILE_WITH_SIMD +#elif defined(__ARM_NEON__) +#define MATHFU_COMPILE_WITH_SIMD +#elif defined(_M_IX86_FP) // MSVC +#if _M_IX86_FP >= 1 // SSE enabled +#define MATHFU_COMPILE_WITH_SIMD +#endif // _M_IX86_FP >= 1 +#endif +#endif // !defined(MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT) + +#ifdef DOXYGEN +/// @addtogroup mathfu_build_config +/// @{ +/// @def MATHFU_COMPILE_FORCE_PADDING +/// @brief Enable / disable padding of data structures. +/// +/// By default, when @ref MATHFU_COMPILE_FORCE_PADDING is not defined, +/// data structures are padded when SIMD is enabled +/// (i.e when @ref MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT is also not defined). +/// +/// If @ref MATHFU_COMPILE_FORCE_PADDING is defined as 1, all data +/// structures are padded to a power of 2 size which enables more efficient +/// SIMD operations. This is the default build configuration when SIMD is +/// enabled. +/// +/// If @ref MATHFU_COMPILE_FORCE_PADDING is defined as 0, all data +/// structures are packed by the compiler (with no padding) even when the SIMD +/// build configuration is enabled. This build option can be useful in the +/// rare occasion an application is CPU memory bandwidth constrained, at the +/// expense of additional instructions to copy to / from SIMD registers. +/// +/// To use this build option, this macro must be defined in all modules +/// of the project. +/// +/// @see MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT +#define MATHFU_COMPILE_FORCE_PADDING +/// @} +#endif // DOXYGEN + +#ifdef MATHFU_COMPILE_WITH_SIMD +/// @cond MATHFU_INTERNAL +/// @addtogroup mathfu_build_config +/// @{ +/// @def MATHFU_COMPILE_WITH_PADDING +/// @brief Enable padding of data structures to be efficient with SIMD. +/// +/// When defined, this option enables padding of some data structures (e.g +/// @ref vec3) to be more efficient with SIMD operations. This option is +/// only applicable when @ref MATHFU_COMPILE_WITHOUT_SIMD is not defined and +/// the target architecture and compiler support SIMD. +/// +/// To use this build option, this macro must be defined in all modules +/// of the project. +/// @see MATHFU_COMPILE_FORCE_PADDING +#define MATHFU_COMPILE_WITH_PADDING +/// @} +#if defined(MATHFU_COMPILE_FORCE_PADDING) +#if MATHFU_COMPILE_FORCE_PADDING == 1 +#if !defined(MATHFU_COMPILE_WITH_PADDING) +#define MATHFU_COMPILE_WITH_PADDING +#endif // !defined(MATHFU_COMPILE_WITH_PADDING) +#else +#if defined(MATHFU_COMPILE_WITH_PADDING) +#undef MATHFU_COMPILE_WITH_PADDING +#endif // MATHFU_COMPILE_WITH_PADDING +#endif // MATHFU_COMPILE_FORCE_PADDING == 1 +#endif // MATHFU_COMPILE_FORCE_PADDING +/// @endcond +#endif // MATHFU_COMPILE_WITH_SIMD + +/// @addtogroup mathfu_version +/// @{ + +/// @def MATHFU_VERSION_MAJOR +/// @brief Major version number of the library. +/// @see kMathFuVersionString +#define MATHFU_VERSION_MAJOR 1 +/// @def MATHFU_VERSION_MINOR +/// @brief Minor version number of the library. +/// @see kMathFuVersionString +#define MATHFU_VERSION_MINOR 1 +/// @def MATHFU_VERSION_REVISION +/// @brief Revision number of the library. +/// @see kMathFuVersionString +#define MATHFU_VERSION_REVISION 0 + +/// @} + +/// @cond MATHFU_INTERNAL +#define MATHFU_STRING_EXPAND(X) #X +#define MATHFU_STRING(X) MATHFU_STRING_EXPAND(X) +/// @endcond + +/// @cond MATHFU_INTERNAL +// Generate string which contains build options for the library. +#if defined(MATHFU_COMPILE_WITH_SIMD) +#define MATHFU_BUILD_OPTIONS_SIMD "[simd]" +#else +#define MATHFU_BUILD_OPTIONS_SIMD "[no simd]" +#endif // defined(MATHFU_COMPILE_WITH_SIMD) +#if defined(MATHFU_COMPILE_WITH_PADDING) +#define MATHFU_BUILD_OPTIONS_PADDING "[padding]" +#else +#define MATHFU_BUILD_OPTIONS_PADDING "[no padding]" +#endif // defined(MATHFU_COMPILE_WITH_PADDING) +/// @endcond + +/// @addtogroup mathfu_version +/// @{ +/// @def MATHFU_BUILD_OPTIONS_STRING +/// @brief String that describes the library's build configuration. +#define MATHFU_BUILD_OPTIONS_STRING \ + (MATHFU_BUILD_OPTIONS_SIMD " " MATHFU_BUILD_OPTIONS_PADDING) +/// @} + +// Weak linkage is culled by VS & doesn't work on cygwin. +#if !defined(_WIN32) && !defined(__CYGWIN__) + +extern volatile __attribute__((weak)) const char *kMathFuVersionString; +/// @addtogroup mathfu_version +/// @{ + +/// @var kMathFuVersionString +/// @brief String which identifies the current version of MathFu. +/// +/// @ref kMathFuVersionString is used by Google developers to identify which +/// applications uploaded to Google Play are using this library. This allows +/// the development team at Google to determine the popularity of the library. +/// How it works: Applications that are uploaded to the Google Play Store are +/// scanned for this version string. We track which applications are using it +/// to measure popularity. You are free to remove it (of course) but we would +/// appreciate if you left it in. +/// +/// @see MATHFU_VERSION_MAJOR +/// @see MATHFU_VERSION_MINOR +/// @see MATHFU_VERSION_REVISION +volatile __attribute__((weak)) const char *kMathFuVersionString = + "MathFu " MATHFU_STRING(MATHFU_VERSION_MAJOR) "." MATHFU_STRING( + MATHFU_VERSION_MINOR) "." MATHFU_STRING(MATHFU_VERSION_REVISION); +/// @} + +#endif // !defined(_WIN32) && !defined(__CYGWIN__) + +/// @cond MATHFU_INTERNAL +template +struct static_assert_util; +template <> +struct static_assert_util {}; +/// @endcond + +/// @addtogroup mathfu_utilities +/// @{ +/// @def MATHFU_STATIC_ASSERT +/// @brief Compile time assert for pre-C++11 compilers. +/// +/// For example: +///
+/// MATHFU_STATIC_ASSERT(0 == 1); +///
will result in a compile error. +#define MATHFU_STATIC_ASSERT(x) static_assert_util<(x)>() +/// @} + +/// @cond MATHFU_INTERNAL +/// Unroll an loop up to 4 iterations, where iterator is the identifier +/// used in each operation (e.g "i"), number_of_iterations is a constant which +/// specifies the number of times to perform the operation and "operation" is +/// the statement to execute for each iteration of the loop (e.g data[i] = v). +#define MATHFU_UNROLLED_LOOP(iterator, number_of_iterations, operation) \ + { \ + const int iterator = 0; \ + { operation; } \ + if ((number_of_iterations) > 1) { \ + const int iterator = 1; \ + { operation; } \ + if ((number_of_iterations) > 2) { \ + const int iterator = 2; \ + { operation; } \ + if ((number_of_iterations) > 3) { \ + const int iterator = 3; \ + { operation; } \ + if ((number_of_iterations) > 4) { \ + for (int iterator = 4; iterator < (number_of_iterations); \ + ++iterator) { \ + operation; \ + } \ + } \ + } \ + } \ + } \ + } +/// @endcond + +namespace mathfu { + +/// @addtogroup mathfu_utilities +/// @{ + +template +inline bool FuzzyZeroHelper(const T &x) { + // No constant defined for the general case. + assert(false); + return 0; +} + +template <> +inline bool FuzzyZeroHelper(const float &x) { + return (abs(x) < FLT_EPSILON); +} + +template <> +inline bool FuzzyZeroHelper(const double &x) { + return (abs(x) < DBL_EPSILON); +} + +template +inline bool FuzzyZero(const T &x) { + return FuzzyZeroHelper(x); +} + +/// @brief Clamp x within [lower, upper]. +/// @anchor mathfu_Clamp +/// +/// @note Results are undefined if lower > upper. +/// +/// @param x Value to clamp. +/// @param lower Lower value of the range. +/// @param upper Upper value of the range. +/// @returns Clamped value. +template +T Clamp(const T &x, const T &lower, const T &upper) { + return std::max(lower, std::min(x, upper)); +} + +/// @brief Linearly interpolate between range_start and range_end, based on +/// percent. +/// @anchor mathfu_Lerp +/// +/// @param range_start Start of the range. +/// @param range_end End of the range. +/// @param percent Value between 0.0 and 1.0 used to interpolate between +/// range_start and range_end. Where a value of 0.0 results in a return +/// value of range_start and 1.0 results in a return value of range_end. +/// @return Value between range_start and range_end. +/// +/// @tparam T Type of the range to interpolate over. +/// @tparam T2 Type of the value used to perform interpolation +/// (e.g float or double). +template +T Lerp(const T &range_start, const T &range_end, const T2 &percent) { + const T2 one_minus_percent = static_cast(1.0) - percent; + return range_start * one_minus_percent + range_end * percent; +} + +/// @brief Linearly interpolate between range_start and range_end, based on +/// percent. +/// @anchor mathfu_Lerp2 +/// +/// @param range_start Start of the range. +/// @param range_end End of the range. +/// @param percent Value between 0.0 and 1.0 used to interpolate between +/// range_start and range_end. Where a value of 0.0 results in a return +/// value of range_start and 1.0 results in a return value of range_end. +/// @return Value between range_start and range_end. +/// +/// @tparam T Type of the range to interpolate over. +template +T Lerp(const T &range_start, const T &range_end, const T &percent) { + return Lerp(range_start, range_end, percent); +} + +/// @brief Check if val is within [range_start..range_end). +/// @anchor mathfu_InRange +/// +/// @param val Value to be tested. +/// @param range_start Starting point of the range (inclusive). +/// @param range_end Ending point of the range (non-inclusive). +/// @return Bool indicating success. +/// +/// @tparam T Type of values to test. +template +bool InRange(T val, T range_start, T range_end) { + return val >= range_start && val < range_end; +} + +/// @brief Generate a random value of type T. +/// @anchor mathfu_Random +/// +/// This method generates a random value of type T, greater than or equal to +/// 0.0 and less than 1.0. +/// +/// This function uses the standard C library function rand() from math.h to +/// generate the random number. +/// +/// @returns Random number greater than or equal to 0.0 and less than 1.0. +/// +/// @see RandomRange() +/// @see RandomInRange() +template +inline T Random() { + return static_cast(rand()) / static_cast(RAND_MAX); +} + +/// @cond MATHFU_INTERNAL +template <> +inline float Random() { + return static_cast(rand() >> 8) / + (static_cast((RAND_MAX >> 8) + 1)); +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template <> +inline double Random() { + return static_cast(rand()) / (static_cast(RAND_MAX + 1LL)); +} +/// @endcond + +/// @brief Generate a random value of type T in the range -range...+range +/// @anchor mathfu_RandomRange +/// +/// This function uses the standard C library function rand() from math.h to +/// generate the random number. +/// +/// @param range Range of the random value to generate. +/// @return Random value in the range -range to +range +/// +/// @see Random() +template +inline T RandomRange(T range) { + return (Random() * range * 2) - range; +} + +/// @brief Generate a random number between [range_start, range_end] +/// @anchor mathfu_RandomInRange +/// +/// This function uses the standard C library function rand() from math.h to +/// generate the random number. +/// +/// @param range_start Minimum value. +/// @param range_end Maximum value. +/// @return Random value in the range [range_start, range_end]. +/// +/// @see Lerp() +/// @see Random() +template +inline T RandomInRange(T range_start, T range_end) { + return Lerp(range_start, range_end, Random()); +} + +/// @cond MATHFU_INTERNAL +template <> +inline int RandomInRange(int range_start, int range_end) { + return static_cast(RandomInRange(static_cast(range_start), + static_cast(range_end))); +} +/// @endcond + +/// @brief Round a value up to the nearest power of 2. +/// +/// @param x Value to round up. +/// @returns Value rounded up to the nearest power of 2. +template +T RoundUpToPowerOf2(T x) { + return static_cast( + pow(static_cast(2), ceil(log(x) / log(static_cast(2))))); +} + +/// @brief Specialized version of RoundUpToPowerOf2 for int32_t. +template <> +inline int32_t RoundUpToPowerOf2<>(int32_t x) { + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x++; + return x; +} + +/// @brief Round a value up to the type's size boundary. +/// +/// @param v Value to round up. +/// @returns Value rounded up to the type's size boundary. +template +uint32_t RoundUpToTypeBoundary(uint32_t v) { + return (v + sizeof(T) - 1) & ~(sizeof(T) - 1); +} + +/// @} + +/// @addtogroup mathfu_allocator +/// +/// If you use MathFu with SIMD (SSE in particular), you need to have all +/// your allocations be 16-byte aligned (which isn't the case with the default +/// allocators on most platforms except OS X). +/// +/// You can either use simd_allocator, which solves the problem for +/// any STL containers, but not for manual dynamic allocations or the +/// new/delete override MATHFU_DEFINE_GLOBAL_SIMD_AWARE_NEW_DELETE will +/// solve it for all allocations, at the cost of MATHFU_ALIGNMENT bytes per +/// allocation. + +/// @addtogroup mathfu_allocator +/// @{ + +/// @def MATHFU_ALIGNMENT +/// @brief Alignment (in bytes) of memory allocated by AllocateAligned. +/// +/// @see mathfu::AllocateAligned() +/// @see mathfu::simd_allocator +#define MATHFU_ALIGNMENT 16 + +/// @brief Allocate an aligned block of memory. +/// @anchor mathfu_AllocateAligned +/// +/// This function allocates a block of memory aligned to MATHFU_ALIGNMENT +/// bytes. +/// +/// @param n Size of memory to allocate. +/// @return Pointer to aligned block of allocated memory or NULL if +/// allocation failed. +inline void *AllocateAligned(size_t n) { +#if defined(_MSC_VER) && _MSC_VER >= 1900 // MSVC 2015 + return _aligned_malloc(n, MATHFU_ALIGNMENT); +#elif defined(__APPLE__) + return malloc(n); +#elif defined(__GNUC__) + return aligned_alloc(MATHFU_ALIGNMENT, n); +#else + // We need to allocate extra bytes to guarantee alignment, + // and to store the pointer to the original buffer. + uint8_t *buf = reinterpret_cast(malloc(n + MATHFU_ALIGNMENT)); + if (!buf) return NULL; + // Align to next higher multiple of MATHFU_ALIGNMENT. + uint8_t *aligned_buf = reinterpret_cast( + (reinterpret_cast(buf) + MATHFU_ALIGNMENT) & + ~(MATHFU_ALIGNMENT - 1)); + // Write out original buffer pointer before aligned buffer. + // The assert will fail if the allocator granularity is less than the pointer + // size, or if MATHFU_ALIGNMENT doesn't fit two pointers. + assert(static_cast(aligned_buf - buf) > sizeof(void *)); + *(reinterpret_cast(aligned_buf) - 1) = buf; + return aligned_buf; +#endif // defined(_MSC_VER) && _MSC_VER >= 1900 // MSVC 2015 +} + +/// @brief Deallocate a block of memory allocated with AllocateAligned(). +/// @anchor mathfu_FreeAligned +/// +/// @param p Pointer to memory to deallocate. +inline void FreeAligned(void *p) { +#if defined(_MSC_VER) && _MSC_VER >= 1900 // MSVC 2015 + _aligned_free(p); +#elif defined(__GNUC__) + free(p); +#else + if (p == NULL) return; + free(*(reinterpret_cast(p) - 1)); +#endif // defined(_MSC_VER) && _MSC_VER >= 1900 // MSVC 2015 +} + +/// @brief SIMD-safe memory allocator, for use with STL types like std::vector. +/// +/// For example: +///
+/// std::vector> myvector;
+/// 
+/// +/// @see MATHFU_DEFINE_GLOBAL_SIMD_AWARE_NEW_DELETE +/// @tparam T type allocated by this object. +template +class simd_allocator : public std::allocator { + public: + /// Size type. + typedef size_t size_type; + /// Pointer of type T. + typedef T *pointer; + /// Const pointer of type T. + typedef const T *const_pointer; + + /// Constructs a simd_allocator. + simd_allocator() throw() : std::allocator() {} + /// @brief Constructs and copies a simd_allocator. + /// + /// @param a Allocator to copy. + simd_allocator(const simd_allocator &a) throw() : std::allocator(a) {} + /// @brief Constructs and copies a simd_allocator. + /// + /// @param a Allocator to copy. + /// @tparam U type of the object allocated by the allocator to copy. + template + simd_allocator(const simd_allocator &a) throw() : std::allocator(a) {} + /// @brief Destructs a simd_allocator. + ~simd_allocator() throw() {} + + /// @brief Obtains an allocator of a different type. + /// + /// @tparam _Tp1 type of the new allocator. + template + struct rebind { + /// @brief Allocator of type _Tp1. + typedef simd_allocator<_Tp1> other; + }; + + /// @brief Allocate memory for object T. + /// + /// @param n Number of types to allocate. + /// @return Pointer to the newly allocated memory. + pointer allocate(size_type n) { + return reinterpret_cast(AllocateAligned(n * sizeof(T))); + } + + /// Deallocate memory referenced by pointer p. + /// + /// @param p Pointer to memory to deallocate. + void deallocate(pointer p, size_type) { FreeAligned(p); } +}; + +#if defined(_MSC_VER) +#if _MSC_VER <= 1800 // MSVC 2013 +#if !defined(noexcept) +#define noexcept +#endif // !defined(noexcept) +#endif // _MSC_VER <= 1800 +#endif // defined(_MSC_VER) + +/// @def MATHFU_DEFINE_GLOBAL_SIMD_AWARE_NEW_DELETE +/// @brief Macro which overrides the default new and delete allocators. +/// +/// To globally override new and delete, simply add the line: +///
+/// MATHFU_DEFINE_GLOBAL_SIMD_AWARE_NEW_DELETE
+/// 
+/// to the end of your main .cpp file. +#define MATHFU_DEFINE_GLOBAL_SIMD_AWARE_NEW_DELETE \ + void *operator new(std::size_t n) { return mathfu::AllocateAligned(n); } \ + void *operator new[](std::size_t n) { return mathfu::AllocateAligned(n); } \ + void operator delete(void *p) noexcept { mathfu::FreeAligned(p); } \ + void operator delete[](void *p) noexcept { mathfu::FreeAligned(p); } + +/// @def MATHFU_DEFINE_CLASS_SIMD_AWARE_NEW_DELETE +/// @brief Macro which defines the new and delete for MathFu classes. +#define MATHFU_DEFINE_CLASS_SIMD_AWARE_NEW_DELETE \ + static void *operator new(std::size_t n) { \ + return mathfu::AllocateAligned(n); \ + } \ + static void *operator new[](std::size_t n) { \ + return mathfu::AllocateAligned(n); \ + } \ + static void *operator new(std::size_t /*n*/, void *p) { return p; } \ + static void *operator new[](std::size_t /*n*/, void *p) { return p; } \ + static void operator delete(void *p) { mathfu::FreeAligned(p); } \ + static void operator delete[](void *p) { mathfu::FreeAligned(p); } \ + static void operator delete(void * /*p*/, void * /*place*/) {} \ + static void operator delete[](void * /*p*/, void * /*place*/) {} + +class SimdClassAllocator +{ +public: + MATHFU_DEFINE_CLASS_SIMD_AWARE_NEW_DELETE +}; + +#if defined(__GNUC__) +# define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +# define WARN_UNUSED_RESULT +#endif + +/// @} + +} // namespace mathfu + +#endif // MATHFU_UTILITIES_H_ diff --git a/intern/mathfu/mathfu/vector.h b/intern/mathfu/mathfu/vector.h new file mode 100644 index 000000000000..3310859ce1d8 --- /dev/null +++ b/intern/mathfu/mathfu/vector.h @@ -0,0 +1,1069 @@ +/* +* Copyright 2014 Google Inc. All rights reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef MATHFU_VECTOR_H_ +#define MATHFU_VECTOR_H_ + +#include "mathfu/utilities.h" + +#include + +/// @file mathfu/vector.h Vector +/// @brief Vector class and functions. +/// @addtogroup mathfu_vector + +// Disable spurious warnings generated by MATHFU_VECTOR_OPERATION(). +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable : 4127) // conditional expression is constant +#if _MSC_VER >= 1900 // MSVC 2015 +#pragma warning(disable : 4456) // allow shadowing in unrolled loops +#endif // _MSC_VER >= 1900 +#elif defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warray-bounds" +#endif + +/// @cond MATHFU_INTERNAL +#define MATHFU_VECTOR_OPERATION(OP) MATHFU_UNROLLED_LOOP(i, d, OP) +/// @endcond + +/// @cond MATHFU_INTERNAL +#define MATHFU_VECTOR_OPERATOR(OP) \ + { \ + Vector result; \ + MATHFU_VECTOR_OPERATION(result[i] = OP); \ + return result; \ + } +/// @endcond + +/// @cond MATHFU_INTERNAL +#define MATHFU_VECTOR_SELF_OPERATOR(OP) \ + { \ + MATHFU_VECTOR_OPERATION(OP); \ + return *this; \ + } +/// @endcond + +namespace mathfu { + +template +class Vector; + +/// @cond MATHFU_INTERNAL +template +static inline T DotProductHelper(const Vector& v1, + const Vector& v2); +template +static inline T DotProductHelper(const Vector& v1, + const Vector& v2); +template +static inline T DotProductHelper(const Vector& v1, + const Vector& v2); +template +static inline T DotProductHelper(const Vector& v1, + const Vector& v2); + +template +static inline Vector FromTypeHelper(const CompatibleT& compatible); + +template +static inline CompatibleT ToTypeHelper(const Vector& v); +/// @endcond + +/// @addtogroup mathfu_vector +/// @{ + +/// @class VectorPacked "mathfu/vector.h" +/// @brief Packed N-dimensional vector. +/// +/// Some Vector classes are padded so that it's possible to use the data +/// structures with SIMD instructions. This structure can be used in +/// conjunction with unpacked Vector classes to pack data +/// into flat arrays suitable for sending to a GPU (e.g vertex buffers). +/// +///

+/// For example, to pack (store) an unpacked to packed vector:
+///

+/// VectorPacked packed;
+/// Vector vector(3, 2, 1);
+/// vector.Pack(&packed);
+/// 
+/// or
+///
+/// Vector vector(3, 2, 1);
+/// VectorPacked packed = vector;
+/// 
+///

+/// +///

+/// To initialize a vector from a packed vector:
+///

+/// VectorPacked packed = { 3, 2, 1 };
+/// Vector vector(packed);
+/// 
+/// +/// @tparam T type of VectorPacked elements. +/// @tparam d dimensions (number of elements) in the VectorPacked structure. +template +struct VectorPacked { + /// Create an uninitialized VectorPacked. + VectorPacked() {} + + /// Create a VectorPacked from a Vector. + /// + /// Both VectorPacked and Vector must have the same number of dimensions. + /// @param vector Vector to create the VectorPacked from. + explicit VectorPacked(const Vector& vector) { vector.Pack(this); } + + explicit VectorPacked(const T * const s) { MATHFU_VECTOR_OPERATION(data[i] = s[i]); } + + /// Copy a Vector to a VectorPacked. + /// + /// Both VectorPacked and Vector must have the same number of dimensions. + /// @param vector Vector to copy to the VectorPacked. + /// @returns A reference to this VectorPacked. + VectorPacked& operator=(const Vector& vector) { + vector.Pack(this); + return *this; + } + + inline const T& operator[](int i) const { + return data[i]; + } + + inline T& operator[](int i) { + return data[i]; + } + + /// Elements of the packed vector one per dimension. + T data[d]; +}; +/// @} + +/// @addtogroup mathfu_vector +/// @{ +/// @class Vector "mathfu/vector.h" +/// @brief Vector of d elements with type T +/// +/// Vector stores d elements of type T and provides a set +/// functions to perform operations on the set of elements. +/// +/// @tparam T type of Vector elements. +/// @tparam d dimensions (number of elements) in the Vector structure. +template +class Vector { + public: + /// @brief Element type to enable reference by other classes. + typedef T Scalar; + + /// @brief Create an uninitialized Vector. + inline Vector() {} + + /// @brief Create a vector from another vector copying each element. + /// + /// @param v Vector that the data will be copied from. + inline Vector(const Vector& v) { + MATHFU_VECTOR_OPERATION(data_[i] = v.data_[i]); + } + + /// @brief Create a vector from another vector of a different type. + /// + /// This copies each element of a Vector which makes it possible to between + /// vectors of different types, for example + /// float/double/int vectors. + /// @param v Vector that the data will be copied from. + /// @tparam U type of Vector elements to copy. + template + explicit inline Vector(const Vector& v) { + MATHFU_VECTOR_OPERATION(data_[i] = static_cast(v[i])); + } + + /// @brief Create a vector from a single float. + /// + /// Each elements is set to be equal to the value given. + /// @param s Scalar value that the vector will be initialized to. + explicit inline Vector(const T& s) { MATHFU_VECTOR_OPERATION(data_[i] = s); } + + /// @brief Create a vector form the first d elements of an array. + /// + /// @param a Array of values that the vector will be iniitlized to. + explicit inline Vector(const T* a) { + MATHFU_VECTOR_OPERATION(data_[i] = a[i]); + } + + /// @brief Create a vector from two values. + /// + /// @note This method only works when the vector is of size two. + /// + /// @param s1 Scalar value for the first element of the vector. + /// @param s2 Scalar value for the second element of the vector. + inline Vector(const T& s1, const T& s2) { + MATHFU_STATIC_ASSERT(d == 2); + data_[0] = s1; + data_[1] = s2; + } + + /// @brief Create a vector from three values. + /// + /// @note This method only works when the vector is of size three. + /// + /// @param s1 Scalar value for the first element of the vector. + /// @param s2 Scalar value for the second element of the vector. + /// @param s3 Scalar value for the third element of the vector. + inline Vector(const T& s1, const T& s2, const T& s3) { + MATHFU_STATIC_ASSERT(d == 3); + data_[0] = s1; + data_[1] = s2; + data_[2] = s3; + } + + /// @brief Create a vector from a 2 component vector and a third value. + /// + /// @note This method only works when the vector is of size three. + /// + /// @param v12 Vector containing the first 2 values. + /// @param s3 Scalar value for the third element of the vector. + inline Vector(const Vector& v12, const T& s3) { + MATHFU_STATIC_ASSERT(d == 3); + data_[0] = v12[0]; + data_[1] = v12[1]; + data_[2] = s3; + } + + /// @brief Create a vector from four values. + /// + /// @note This method only works when the vector is of size four. + /// + /// @param s1 Scalar value for the first element of the vector. + /// @param s2 Scalar value for the second element of the vector. + /// @param s3 Scalar value for the third element of the vector. + /// @param s4 Scalar value for the forth element of the vector. + inline Vector(const T& s1, const T& s2, const T& s3, const T& s4) { + MATHFU_STATIC_ASSERT(d == 4); + data_[0] = s1; + data_[1] = s2; + data_[2] = s3; + data_[3] = s4; + } + + /// @brief Create a 4-dimensional vector from a Vector. + /// + /// The last element is initialized to the specified value. + /// @note This method only works with 4 element vectors. + /// + /// @param vector3 Vector used to initialize the first 3 elements. + /// @param value Value used to set the last element of the vector. + inline Vector(const Vector& vector3, const T& value) { + MATHFU_STATIC_ASSERT(d == 4); + data_[0] = vector3[0]; + data_[1] = vector3[1]; + data_[2] = vector3[2]; + data_[3] = value; + } + + /// @brief Create a vector from two 2 component vectors. + /// + /// @note This method only works when the vector is of size four. + /// + /// @param v12 Vector containing the first 2 values. + /// @param v34 Vector containing the last 2 values. + inline Vector(const Vector& v12, const Vector& v34) { + MATHFU_STATIC_ASSERT(d == 4); + data_[0] = v12[0]; + data_[1] = v12[1]; + data_[2] = v34[0]; + data_[3] = v34[1]; + } + + /// @brief Create a vector from packed vector (VectorPacked). + /// + /// @param vector Packed vector used to initialize an unpacked. + explicit inline Vector(const VectorPacked& vector) { + MATHFU_VECTOR_OPERATION(data_[i] = vector.data[i]); + } + + /// @brief Access an element of the vector. + /// + /// @param i Index of the element to access. + /// @return A reference to the accessed data that can be modified by the + /// caller. + inline T& operator()(const int i) WARN_UNUSED_RESULT { return data_[i]; } + + /// @brief Access an element of the vector. + /// + /// @param i Index of the element to access. + /// @return A reference to the accessed data. + inline const T& operator()(const int i) const WARN_UNUSED_RESULT { return data_[i]; } + + /// @brief Access an element of the vector. + /// + /// @param i Index of the element to access. + /// @return A reference to the accessed data that can be modified by the + /// caller. + inline T& operator[](const int i) WARN_UNUSED_RESULT { return data_[i]; } + + /// @brief Access an element of the vector. + /// + /// @param i Index of the element to access. + /// @return A const reference to the accessed. + inline const T& operator[](const int i) const WARN_UNUSED_RESULT { return data_[i]; } + + /// @brief GLSL style 3 element accessor. + /// + /// This only works with vectors that contain more than 3 elements. + /// @returns A 3-dimensional Vector containing the first 3 elements of + // this Vector. + inline Vector xyz() WARN_UNUSED_RESULT { + MATHFU_STATIC_ASSERT(d > 3); + return Vector(data_[0], data_[1], data_[2]); + } + + /// @brief GLSL style 3 element accessor. + /// + /// This only works with vectors that contain more than 3 elements. + /// @returns A 3-dimensional Vector containing the first 3 elements of + // this Vector. + inline const Vector xyz() const WARN_UNUSED_RESULT { + MATHFU_STATIC_ASSERT(d > 3); + return Vector(data_[0], data_[1], data_[2]); + } + + /// @brief GLSL style 2 element accessor. + /// + /// This only works with vectors that contain more than 2 elements. + /// @returns A 2-dimensional Vector with the first 2 elements of this Vector. + inline Vector xy() WARN_UNUSED_RESULT { + MATHFU_STATIC_ASSERT(d > 2); + return Vector(data_[0], data_[1]); + } + + /// @brief GLSL style 2 element accessor. + /// + /// This only works with vectors that contain more than 2 elements. + /// @returns A 2-dimensional Vector with the first 2 elements of this Vector. + inline const Vector xy() const WARN_UNUSED_RESULT { + MATHFU_STATIC_ASSERT(d > 2); + return Vector(data_[0], data_[1]); + } + + /// @brief GLSL style 2 element accessor. + /// + /// This only works with vectors that contain 4 elements. + /// @returns A 2-dimensional Vector with the last 2 elements of this Vector. + inline Vector zw() WARN_UNUSED_RESULT { + MATHFU_STATIC_ASSERT(d == 4); + return Vector(data_[2], data_[3]); + } + + /// @brief GLSL style 2 element accessor. + /// + /// This only works with vectors that contain 4 elements. + /// @returns A 2-dimensional Vector with the last 2 elements of this Vector. + inline const Vector zw() const WARN_UNUSED_RESULT { + MATHFU_STATIC_ASSERT(d == 4); + return Vector(data_[2], data_[3]); + } + + /// @brief Pack a Vector to a packed "d" element vector structure. + /// + /// @param vector Packed "d" element vector to write to. + inline void Pack(VectorPacked* const vector) const WARN_UNUSED_RESULT { + MATHFU_VECTOR_OPERATION(vector->data[i] = data_[i]); + } + + /// @brief Pack a Vector to a array "d" element. + /// + /// @param a array "d" element to write to. + inline void Pack(T *a) const WARN_UNUSED_RESULT { + MATHFU_VECTOR_OPERATION(a[i] = data_[i]); + } + + /// @brief Return the array of this vector. + /// + /// @return The array of this vector. + inline const float (&Data() const)[d] WARN_UNUSED_RESULT { + return data_; + } + + /// @brief Calculate the squared length of this vector. + /// + /// @return The length of this vector squared. + inline T LengthSquared() const WARN_UNUSED_RESULT { return LengthSquaredHelper(*this); } + + /// @brief Calculate the length of this vector. + /// + /// @return The length of this vector. + inline T Length() const WARN_UNUSED_RESULT { return LengthHelper(*this); } + + /// @brief Normalize this vector in-place. + /// + /// @return The length of this vector. + inline T Normalize() { return NormalizeHelper(*this); } + + inline T SafeNormalize() { return SafeNormalizeHelper(*this); } + + /// @brief Calculate the normalized version of this vector. + /// + /// @return The normalized vector. + inline Vector Normalized() const WARN_UNUSED_RESULT { return NormalizedHelper(*this); } + + inline Vector SafeNormalized(const Vector& v) const WARN_UNUSED_RESULT { + return SafeNormalizedHelper(*this, v); + } + + static inline WARN_UNUSED_RESULT bool FuzzyZero(const Vector& v) { + return FuzzyZeroHelper(v); + } + + /// @brief Load from any type that is some formulation of a length d array of + /// type T. + /// + /// Essentially this is just a type cast and a load, but it happens safely + /// so that we avoid aliasing bugs. + /// + /// @return `compatible` cast to `Vector` and dereferenced. + template + static inline WARN_UNUSED_RESULT Vector FromType(const CompatibleT& compatible) { + return FromTypeHelper(compatible); + } + + /// @brief Load into any type that is some formulation of a length d array of + /// type T. + /// + /// Essentially this is just a type cast and a load, but it happens safely + /// so that we avoid aliasing bugs. + /// + /// @return `v` cast to `CompatibleT` and dereferenced. + template + static inline WARN_UNUSED_RESULT CompatibleT ToType(const Vector& v) { + return ToTypeHelper(v); + } + + /// @brief Calculate the dot product of two vectors. + /// + /// @param v1 First vector. + /// @param v2 Second vector. + /// @return The dot product of v1 and v2. + static inline WARN_UNUSED_RESULT T DotProduct(const Vector& v1, const Vector& v2) { + return DotProductHelper(v1, v2); + } + + /// @brief Calculate the hadamard or componentwise product of two vectors. + /// + /// @param v1 First vector. + /// @param v2 Second vector. + /// @return The hadamard product of v1 and v2. + static inline WARN_UNUSED_RESULT Vector HadamardProduct(const Vector& v1, + const Vector& v2) { + return HadamardProductHelper(v1, v2); + } + + /// @brief Calculate the cross product of two vectors. + /// + /// Note that this function is only defined for 3-dimensional Vectors. + /// @param v1 First vector. + /// @param v2 Second vector. + /// @return The cross product of v1 and v2. + static inline WARN_UNUSED_RESULT Vector CrossProduct(const Vector& v1, + const Vector& v2) { + return CrossProductHelper(v1, v2); + } + + /// @brief Linearly interpolate two vectors. + /// + /// @param v1 First vector. + /// @param v2 Second vector. + /// @param percent Percentage from v1 to v2 in range 0.0...1.0. + /// @return The hadamard product of v1 and v2. + static inline WARN_UNUSED_RESULT Vector Lerp(const Vector& v1, + const Vector& v2, const T percent) { + return LerpHelper(v1, v2, percent); + } + + /// @brief Generates a random vector. + /// + /// The range of each component is bounded by min and max. + /// @param min Minimum value of the vector. + /// @param max Maximum value of the vector. + static inline WARN_UNUSED_RESULT Vector RandomInRange(const Vector& min, + const Vector& max) { + return RandomInRangeHelper(min, max); + } + + /// @brief Compare each component and returns max values. + /// + /// @param v1 First vector. + /// @param v2 Second vector. + /// @return Max value of v1 and v2. + static inline WARN_UNUSED_RESULT Vector Max(const Vector& v1, + const Vector& v2) { + return MaxHelper(v1, v2); + } + + /// @brief Compare each component and returns min values. + /// + /// @param v1 First vector. + /// @param v2 Second vector. + /// @return Min value of v1 and v2. + static inline WARN_UNUSED_RESULT Vector Min(const Vector& v1, + const Vector& v2) { + return MinHelper(v1, v2); + } + + MATHFU_DEFINE_CLASS_SIMD_AWARE_NEW_DELETE + + /// Elements of the vector. + T data_[d]; +}; +/// @} + +/// @addtogroup mathfu_vector +/// @{ + +/// @brief Compare 2 Vectors of the same size for equality. +/// +/// @note: The likelyhood of two float values being the same is very small. +/// Instead consider comparing the difference between two float vectors using +/// LengthSquared() with an epsilon value. +/// For example, v1.LengthSquared(v2) < epsilon. +/// +/// @return true if the 2 vectors contains the same value, false otherwise. +template +inline bool operator==(const Vector& lhs, const Vector& rhs) { + for (int i = 0; i < d; ++i) { + if (lhs[i] != rhs[i]) return false; + } + return true; +} + +/// @brief Compare 2 Vectors of the same size for inequality. +/// +/// @return true if the elements of two vectors differ, false otherwise. +template +inline bool operator!=(const Vector& lhs, const Vector& rhs) { + return !(lhs == rhs); +} + +/// @brief Negate all elements of the Vector. +/// +/// @return A new Vector containing the result. +template +inline Vector operator-(const Vector& v) { + MATHFU_VECTOR_OPERATOR(-v.data_[i]); +} + +/// @brief Multiply a Vector by a scalar. +/// +/// Multiplies each component of the specified Vector with a scalar. +/// +/// @param s scalar to multiply. +/// @param v Vector to multiply. +/// @return Vector containing the result. +/// @related Vector +template +inline Vector operator*(const T& s, const Vector& v) { + MATHFU_VECTOR_OPERATOR(v.data_[i] * s); +} + +/// @brief Divide a Vector by a scalar. +/// +/// Divides each component of the specified Vector by a scalar. +/// +/// @param v Vector to be divided. +/// @param s scalar to divide the vector by. +/// @return Vector containing the result. +/// @related Vector +template +inline Vector operator/(const Vector& v, const T& s) { + MATHFU_VECTOR_OPERATOR(v.data_[i] / s); +} + +/// @brief Add a scalar to each element of a Vector. +/// +/// @param s scalar to add to each element of a Vector. +/// @param v Vector to add the scalar to. +/// @return Vector containing the result. +/// @related Vector +template +inline Vector operator+(const T& s, const Vector& v) { + MATHFU_VECTOR_OPERATOR(v.data_[i] + s); +} + +/// @brief Subtract a scalar from each element of a Vector. +/// +/// @param s scalar to subtract from each element of a Vector. +/// @param v Vector to subtract the scalar from. +/// @return Vector containing the result. +/// @related Vector +template +inline Vector operator-(const T& s, const Vector& v) { + MATHFU_VECTOR_OPERATOR(v.data_[i] - s); +} + +/// @brief Multiply a vector by another Vector. +/// +/// In line with GLSL, this performs component-wise multiplication. +/// @param lhs First vector to use as a starting point. +/// @param rhs Second vector to multiply by. +/// @return A new Vector containing the result. +template +inline Vector operator*(const Vector& lhs, + const Vector& rhs) { + return HadamardProductHelper(lhs, rhs); +} + +/// @brief Divide a vector by another Vector. +/// +/// In line with GLSL, this performs component-wise division. +/// @param lhs First vector to use as a starting point. +/// @param rhs Second vector to divide by. +/// @return A new Vector containing the result. +template +inline Vector operator/(const Vector& lhs, + const Vector& rhs) { + MATHFU_VECTOR_OPERATOR(lhs.data_[i] / rhs[i]); +} + +/// @brief Add a vector with another Vector. +/// +/// @param lhs First vector to use as a starting point. +/// @param rhs Second vector to add by. +/// @return A new vector containing the result. +template +inline Vector operator+(const Vector& lhs, + const Vector& rhs) { + MATHFU_VECTOR_OPERATOR(lhs.data_[i] + rhs[i]); +} + +/// @brief subtract a vector with another Vector. +/// +/// @param lhs First vector to use as a starting point. +/// @param rhs Second vector to subtract by. +/// @return A new vector containing the result. +template +inline Vector operator-(const Vector& lhs, + const Vector& rhs) { + MATHFU_VECTOR_OPERATOR(lhs.data_[i] - rhs[i]); +} + +/// @brief Multiply a vector with a scalar. +/// +/// @param v Vector for the operation. +/// @param s A scalar to multiply the vector with. +/// @return A new vector containing the result. +template +inline Vector operator*(const Vector& v, const T& s) { + MATHFU_VECTOR_OPERATOR(v.data_[i] * s); +} + +/// @brief Add a scalar to all elements of a vector. +/// +/// @param v Vector for the operation. +/// @param s A scalar to add to the vector. +/// @return A new vector containing the result. +template +inline Vector operator+(const Vector& v, const T& s) { + MATHFU_VECTOR_OPERATOR(v.data_[i] + s); +} + +/// @brief Subtract a scalar from all elements of a vector. +/// +/// @param v Vector for the operation. +/// @param s A scalar to subtract from a vector. +/// @return A new vector that stores the result. +template +inline Vector operator-(const Vector& v, const T& s) { + MATHFU_VECTOR_OPERATOR(v.data_[i] - s); +} + +/// @brief Multiply (in-place) a vector with another Vector. +/// +/// In line with GLSL, this performs component-wise multiplication. +/// @param lhs First vector to use as a starting point. +/// @param rhs Second vector to multiply by. +/// @return A reference to the input v vector. +template +inline Vector& operator*=(Vector& lhs, const Vector& rhs) { + MATHFU_VECTOR_OPERATION(lhs.data_[i] *= rhs[i]); + return lhs; +} + +/// @brief Divide (in-place) a vector by another Vector. +/// +/// In line with GLSL, this performs component-wise division. +/// @param lhs First vector to use as a starting point. +/// @param rhs Second vector to divide by. +/// @return A reference to the input v vector. +template +inline Vector& operator/=(Vector& lhs, const Vector& rhs) { + MATHFU_VECTOR_OPERATION(lhs.data_[i] /= rhs[i]); + return lhs; +} + +/// @brief Add (in-place) a vector with another Vector. +/// +/// @param lhs First vector to use as a starting point. +/// @param rhs Second vector to add. +/// @return A reference to the input v vector. +template +inline Vector& operator+=(Vector& lhs, const Vector& rhs) { + MATHFU_VECTOR_OPERATION(lhs.data_[i] += rhs[i]); + return lhs; +} + +/// @brief Subtract (in-place) another Vector from a vector. +/// +/// @param lhs First vector to use as a starting point. +/// @param rhs Second vector to subtract by. +/// @return A reference to the input v vector. +template +inline Vector& operator-=(Vector& lhs, const Vector& rhs) { + MATHFU_VECTOR_OPERATION(lhs.data_[i] -= rhs[i]); + return lhs; +} + +/// @brief Multiply (in-place) each element of a vector with a scalar. +/// +/// @param v Vector for the operation. +/// @param s A scalar to multiply the vector with. +/// @return A reference to the input v vector. +template +inline Vector& operator*=(Vector& v, const T& s) { + MATHFU_VECTOR_OPERATION(v.data_[i] *= s); + return v; +} + +/// @brief Divide (in-place) each element of a vector by a scalar. +/// +/// @param v Vector for the operation. +/// @param s A scalar to divide the vector by. +/// @return A reference to the input v vector. +template +inline Vector& operator/=(Vector& v, const T& s) { + MATHFU_VECTOR_OPERATION(v.data_[i] /= s); + return v; +} + +/// @brief Add (in-place) a scalar to each element of a vector. +/// +/// @param v Vector for the operation. +/// @param s A scalar to add the vector to. +/// @return A reference to the input v vector. +template +inline Vector& operator+=(Vector& v, const T& s) { + MATHFU_VECTOR_OPERATION(v.data_[i] += s); + return v; +} + +/// @brief Subtract (in-place) a scalar from each element of a vector. +/// +/// @param v Vector for the operation. +/// @param s A scalar to subtract from the vector. +/// @return A reference to the input v vector. +template +inline Vector& operator-=(Vector& v, const T& s) { + MATHFU_VECTOR_OPERATION(v.data_[i] -= s); + return v; +} + +/// @brief Calculate the hadamard or componentwise product of two vectors. +/// +/// @param v1 First vector. +/// @param v2 Second vector. +/// @return The hadamard product of v1 and v2. +template +inline Vector HadamardProductHelper(const Vector& v1, + const Vector& v2) { + MATHFU_VECTOR_OPERATOR(v1[i] * v2[i]); +} + +/// @brief Calculate the cross product of two vectors. +/// +/// Note that this function is only defined for 3-dimensional Vectors. +/// @param v1 First vector. +/// @param v2 Second vector. +/// @return The cross product of v1 and v2. +template +inline Vector CrossProductHelper(const Vector& v1, + const Vector& v2) { + return Vector(v1[1] * v2[2] - v1[2] * v2[1], + v1[2] * v2[0] - v1[0] * v2[2], + v1[0] * v2[1] - v1[1] * v2[0]); +} + +/// @brief Calculate the squared length of a vector. +/// +/// @param v Vector to get the squared length of. +/// @return The length of the vector squared. +template +inline T LengthSquaredHelper(const Vector& v) { + return DotProductHelper(v, v); +} + +/// @brief Calculate the length of a vector. +/// +/// @param v Vector to get the squared length of. +/// @return The length of the vector. +template +inline T LengthHelper(const Vector& v) { + return sqrt(LengthSquaredHelper(v)); +} + +/// @brief Normalize a vector in-place. +/// +/// @param v Vector to get the squared length of. +/// @return The length of the vector. +template +inline T NormalizeHelper(Vector& v) { + const T length = LengthHelper(v); + v *= (T(1) / length); + return length; +} + +template +inline T SafeNormalizeHelper(Vector& v) { + const T length = LengthHelper(v); + if (!FuzzyZero(length)) { + v *= (T(1) / length); + } + return length; +} + +/// @brief Calculate the normalized version of a vector. +/// +/// @param v Vector to get the squared length of. +/// @return The normalized vector. +template +inline Vector NormalizedHelper(const Vector& v) { + return v * (T(1) / LengthHelper(v)); +} + +template +inline Vector SafeNormalizedHelper(const Vector& v1, const Vector& v2) { + const T length = LengthHelper(v1); + if (FuzzyZero(length)) { + return v2; + } + return v1 * (T(1) / length); +} + +/// @brief Linearly interpolate two vectors. +/// +/// @param v1 First vector. +/// @param v2 Second vector. +/// @param percent Percentage from v1 to v2 in range 0.0...1.0. +/// @return The hadamard product of v1 and v2. +template +inline Vector LerpHelper(const Vector& v1, const Vector& v2, + const T percent) { + const T one_minus_percent = static_cast(1.0) - percent; + MATHFU_VECTOR_OPERATOR(one_minus_percent * v1[i] + percent * v2[i]); +} + +/// @brief Generates a random vector. +/// +/// The range of each component is bounded by min and max. +/// @param min Minimum value of the vector. +/// @param max Maximum value of the vector. +template +inline Vector RandomInRangeHelper(const Vector& min, + const Vector& max) { + Vector result; + MATHFU_VECTOR_OPERATION(result[i] = mathfu::RandomInRange(min[i], max[i])); + return result; +} + +/// @brief Compare each component and returns max values. +/// +/// @param v1 First vector. +/// @param v2 Second vector. +/// @return Max value of v1 and v2. +template +inline Vector MaxHelper(const Vector& v1, const Vector& v2) { + Vector result; + MATHFU_VECTOR_OPERATION(result[i] = std::max(v1[i], v2[i])); + return result; +} + +/// @brief Compare each component and returns min values. +/// +/// @param v1 First vector. +/// @param v2 Second vector. +/// @return Min value of v1 and v2. +template +inline Vector MinHelper(const Vector& v1, const Vector& v2) { + Vector result; + MATHFU_VECTOR_OPERATION(result[i] = std::min(v1[i], v2[i])); + return result; +} + +/// @brief Check if val is within [range_start..range_end), denoting a +/// rectangular area. +/// +/// @param val 2D vector to be tested. +/// @param range_start Starting point of the range (inclusive). +/// @param range_end Ending point of the range (non-inclusive). +/// @return Bool indicating success. +/// +/// @tparam T Type of vector components to test. +template +bool InRange2D(const mathfu::Vector& val, + const mathfu::Vector& range_start, + const mathfu::Vector& range_end) { + return InRange(val[0], range_start[0], range_end[0]) && + InRange(val[1], range_start[1], range_end[1]); +} + +/// @cond MATHFU_INTERNAL +/// @brief Calculate the dot product of two vectors. +/// +/// @param v1 First vector. +/// @param v2 Second vector. +/// @return The dot product of v1 and v2. +/// @related Vector +template +static inline T DotProductHelper(const Vector& v1, + const Vector& v2) { + T result = 0; + MATHFU_VECTOR_OPERATION(result += v1[i] * v2[i]); + return result; +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +static inline T DotProductHelper(const Vector& v1, + const Vector& v2) { + return v1[0] * v2[0] + v1[1] * v2[1]; +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +static inline T DotProductHelper(const Vector& v1, + const Vector& v2) { + return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +static inline T DotProductHelper(const Vector& v1, + const Vector& v2) { + return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2] + v1[3] * v2[3]; +} +/// @endcond + +template +static inline bool FuzzyZeroHelper(const Vector& v) { + T absolute = 0; + for (int i = 0; i < d; ++i) { + absolute += abs(v[i]); + } + + return FuzzyZero(absolute); +} + +/// @cond MATHFU_INTERNAL +template +static inline Vector FromTypeHelper(const CompatibleT& compatible) { +// C++11 is required for constructed unions. +#if __cplusplus >= 201103L + // Use a union instead of reinterpret_cast to avoid aliasing bugs. + union ConversionUnion { + ConversionUnion() {} // C++11. + CompatibleT compatible; + VectorPacked packed; + } u; + static_assert(sizeof(u.compatible) == d * sizeof(T), + "Conversion size mismatch."); + + // The read of `compatible` and write to `u.compatible` gets optimized away, + // and this becomes essentially a safe reinterpret_cast. + u.compatible = compatible; + + // Call the packed vector constructor with the `compatible` data. + return Vector(u.packed); +#else + // Use the less-desirable memcpy technique if C++11 is not available. + // Most compilers understand memcpy deep enough to avoid replace the function + // call with a series of load/stores, which should then get optimized away, + // however in the worst case the optimize away may not happen. + // Note: Memcpy avoids aliasing bugs because it operates via unsigned char*, + // which is allowed to alias any type. + // See: + // http://stackoverflow.com/questions/15745030/type-punning-with-void-without-breaking-the-strict-aliasing-rule-in-c99 + Vector v; + assert(sizeof(compatible) == d * sizeof(T)); + memcpy(&v, &compatible, sizeof(compatible)); + return v; +#endif // __cplusplus >= 201103L +} +/// @endcond + +/// @cond MATHFU_INTERNAL +template +static inline CompatibleT ToTypeHelper(const Vector& v) { +// See FromTypeHelper() for comments. +#if __cplusplus >= 201103L + union ConversionUnion { + ConversionUnion() {} + CompatibleT compatible; + VectorPacked packed; + } u; + static_assert(sizeof(u.compatible) == d * sizeof(T), "Conversion size mismatch."); + v.Pack(&u.packed); + return u.compatible; +#else + CompatibleT compatible; + assert(sizeof(compatible) == d * sizeof(T)); + memcpy(&compatible, &v, sizeof(compatible)); + return compatible; +#endif // __cplusplus >= 201103L +} +/// @endcond + +/// @} + +/// @addtogroup mathfu_utilities +/// @{ + +/// @brief Specialized version of RoundUpToPowerOf2 for vector. +template +inline Vector RoundUpToPowerOf2(const Vector& v) { + Vector ret; + MATHFU_VECTOR_OPERATION(ret(i) = RoundUpToPowerOf2(v(i))); + return ret; +} +/// @} + +} // namespace mathfu + +// Include the specializations to avoid template errors. +// For example, if you include vector.h, use Vector, and then +// include vector_3.h, you the compiler will generate an error since you're +// specializing something that has already been instantiated. +#include "mathfu/internal/vector_2_simd.h" +#include "mathfu/internal/vector_3_simd.h" +#include "mathfu/internal/vector_4_simd.h" + +#if defined(_MSC_VER) +#pragma warning(pop) +#elif defined(__clang__) +#pragma clang diagnostic pop +#endif + +#endif // MATHFU_VECTOR_H_ diff --git a/intern/mathfu/vectorial/LICENSE b/intern/mathfu/vectorial/LICENSE new file mode 100644 index 000000000000..f9d49e0cc11c --- /dev/null +++ b/intern/mathfu/vectorial/LICENSE @@ -0,0 +1,22 @@ +Copyright 2010 Mikko Lehtonen. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list + of conditions and the following disclaimer in the documentation and/or other materials + provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/intern/mathfu/vectorial/README b/intern/mathfu/vectorial/README new file mode 100644 index 000000000000..86d06a8cc707 --- /dev/null +++ b/intern/mathfu/vectorial/README @@ -0,0 +1,60 @@ + + Vectorial - vector math library + + + + Motivation + + I couldn't find an open source math library that was usable and + supported simd - especially the ARM NEON variant. + + + Features + + Supports NEON, SSE, scalar and generic gcc vector extension. + Most basic vector and matrix math is available, but not quite + yet full featured. + + + Design + + Vectorial consists of two main parts, pure-C wrapper around + platform-specific vector instructions in the simd*.h files + and C++ classes for common uses, the vec*.h and mat*.h + + The config.h autodetects approriate vector instructions to use. + + The platform-specific support is done with intrisincs only, + allowing the compiler to have a full view of the code, hopefully + resulting in better optimizations especially with reordering etc. + + + Installation / Usage + + Add vectorial/include to your include path + + #include "vectorial/simd4f.h" + for C-only simd wrapper, using it looks like this: + simd4f v = simd4f_normalize( simd4f_add( simd4f_create(1,2,3,4), y) ); + float z = simd4f_get_z(v); + + #include "vectorial/vectorial.h" + for C++ classes. They reside in vectorial namespace, you might + want to alias them to your own namespace + namespace myproject { + using namespace ::vectorial; + // if you like different name: typedef vec3f Vector3; + } + using myproject::vec4f; + + vec4f v = normalize( vec4f(1,2,3,4) + y ); + float z = v.z(); + + + License + + 2-clause BSD. See LICENSE + + + + diff --git a/intern/mathfu/vectorial/config.h b/intern/mathfu/vectorial/config.h new file mode 100644 index 000000000000..1c5580318a07 --- /dev/null +++ b/intern/mathfu/vectorial/config.h @@ -0,0 +1,100 @@ +/* + Vectorial + Copyright (c) 2010 Mikko Lehtonen + Licensed under the terms of the two-clause BSD License (see LICENSE) +*/ +#ifndef VECTORIAL_CONFIG_H +#define VECTORIAL_CONFIG_H + + +#ifndef VECTORIAL_FORCED + #if defined(__SSE__) || (_M_IX86_FP > 0) || (_M_X64 > 0) + + #define VECTORIAL_SSE + + #elif defined(__ARM_NEON__) + + #define VECTORIAL_NEON + + // Don't use gnu extension for arm, buggy with some gccs with armv6 and -Os, + // Also doesn't seem perform as well + #elif defined(__GNUC__) && !defined(__arm__) + + #define VECTORIAL_GNU + + #else + + #define VECTORIAL_SCALAR + + #endif +#endif + + + +#ifdef VECTORIAL_SCALAR + #define VECTORIAL_SIMD_TYPE "scalar" +#endif + +#ifdef VECTORIAL_SSE + #define VECTORIAL_SIMD_TYPE "sse" +#endif + +#ifdef VECTORIAL_NEON + #define VECTORIAL_SIMD_TYPE "neon" + #define VECTORIAL_HAVE_SIMD2F +#endif + +#ifdef VECTORIAL_GNU + #define VECTORIAL_SIMD_TYPE "gnu" +#endif + + + +#if defined(VECTORIAL_FORCED) && !defined(VECTORIAL_SIMD_TYPE) + #error VECTORIAL_FORCED set but no simd-type found, try f.ex. VECTORIAL_SCALAR +#endif + + +#define vectorial_inline static inline + +#if defined(__GNUC__) + #if defined(__cplusplus) + #define vectorial_restrict __restrict + #endif + #define simd4f_aligned16 __attribute__ ((aligned (16))) +#elif defined(_WIN32) + #define vectorial_restrict + #define simd4f_aligned16 __declspec(align(16)) +#else + #define vectorial_restrict restrict + #define simd4f_aligned16 +#endif +// #define vectorial_restrict + +#ifdef __GNUC__ + #define vectorial_pure __attribute__((pure)) +#else + #define vectorial_pure +#endif + +#ifdef _WIN32 + #if defined(min) || defined(max) +#pragma message ( "set NOMINMAX as preprocessor macro, undefining min/max " ) +#undef min +#undef max + #endif +#endif + +#ifdef __cplusplus + // Hack around msvc badness + #define SIMD_PARAM(t, p) const t& p +#else + #define SIMD_PARAM(t, p) t p +#endif + +#define VECTORIAL_PI 3.14159265f +#define VECTORIAL_HALFPI 1.57079633f + + + +#endif diff --git a/intern/mathfu/vectorial/mat4f.h b/intern/mathfu/vectorial/mat4f.h new file mode 100644 index 000000000000..4e7b31984079 --- /dev/null +++ b/intern/mathfu/vectorial/mat4f.h @@ -0,0 +1,197 @@ +/* + Vectorial + Copyright (c) 2010 Mikko Lehtonen + Licensed under the terms of the two-clause BSD License (see LICENSE) +*/ +#ifndef VECTORIAL_MAT4F_H +#define VECTORIAL_MAT4F_H + +#ifndef VECTORIAL_SIMD4X4F_H + #include "vectorial/simd4x4f.h" +#endif + +#ifndef VECTORIAL_VEC4F_H + #include "vectorial/vec4f.h" +#endif + + +namespace vectorial { + + + class mat4f { + public: + + simd4x4f value; + + inline mat4f() {} + inline mat4f(const mat4f& m) : value(m.value) {} + inline mat4f(const simd4x4f& v) : value(v) {} + inline mat4f(const vec4f& v0, const vec4f& v1, const vec4f& v2, const vec4f& v3) : value(simd4x4f_create(v0.value, v1.value, v2.value, v3.value)) {} + explicit inline mat4f(const float *ary) { simd4x4f_uload(&value, ary); } + + inline void load(const float *ary) { + value.x = simd4f_uload4(ary); + value.y = simd4f_uload4(ary+4); + value.z = simd4f_uload4(ary+8); + value.w = simd4f_uload4(ary+12); + } + + inline void store(float *ary) const { + simd4f_ustore4(value.x, ary); + simd4f_ustore4(value.y, ary+4); + simd4f_ustore4(value.z, ary+8); + simd4f_ustore4(value.w, ary+12); + } + + static mat4f identity() { mat4f m; simd4x4f_identity(&m.value); return m; } + + static mat4f perspective(float fovy, float aspect, float znear, float zfar) { + simd4x4f m; + simd4x4f_perspective(&m, fovy, aspect, znear, zfar); + return m; + } + + static mat4f ortho(float left, float right, float bottom, float top, float znear, float zfar) { + simd4x4f m; + simd4x4f_ortho(&m, left, right, bottom, top, znear, zfar); + return m; + } + + static mat4f lookAt(const vec3f& eye, const vec3f& center, const vec3f& up) { + simd4x4f m; + simd4x4f_lookat(&m, eye.value, center.value, up.value); + return m; + } + + static mat4f translation(const vec3f& pos) { + simd4x4f m; + simd4x4f_translation(&m, pos.x(), pos.y(), pos.z()); + return m; + } + + static mat4f axisRotation(float angle, const vec3f& axis) { + simd4x4f m; + simd4x4f_axis_rotation(&m, angle, axis.value); + return m; + } + + static mat4f scale(float scale) { + return simd4x4f_create( simd4f_create(scale,0,0,0), + simd4f_create(0,scale,0,0), + simd4f_create(0,0,scale,0), + simd4f_create(0,0,0,1) ); + } + + static mat4f scale(const vec3f& scale) { + return simd4x4f_create( simd4f_create(scale.x(),0,0,0), + simd4f_create(0,scale.y(),0,0), + simd4f_create(0,0,scale.z(),0), + simd4f_create(0,0,0,1) ); + } + + }; + + + vectorial_inline mat4f operator*(const mat4f& lhs, const mat4f& rhs) { + mat4f ret; + simd4x4f_matrix_mul(&lhs.value, &rhs.value, &ret.value); + return ret; + } + + vectorial_inline mat4f operator*=(mat4f& lhs, const mat4f& rhs) { + const simd4x4f tmp = lhs.value; + simd4x4f_matrix_mul(&tmp, &rhs.value, &lhs.value); + return lhs; + } + + + vectorial_inline vec4f operator*(const mat4f& lhs, const vec4f& rhs) { + vec4f ret; + simd4x4f_matrix_vector_mul(&lhs.value, &rhs.value, &ret.value); + return ret; + } + + vectorial_inline vec3f transformVector(const mat4f& lhs, const vec3f& rhs) { + vec3f ret; + simd4x4f_matrix_vector3_mul(&lhs.value, &rhs.value, &ret.value); + return ret; + } + + vectorial_inline vec4f transformVector(const mat4f& lhs, const vec4f& rhs) { + vec4f ret; + simd4x4f_matrix_vector_mul(&lhs.value, &rhs.value, &ret.value); + return ret; + } + + vectorial_inline vec3f transformPoint(const mat4f& lhs, const vec3f& rhs) { + vec3f ret; + simd4x4f_matrix_point3_mul(&lhs.value, &rhs.value, &ret.value); + return ret; + } + + vectorial_inline vec3f orthoInverseTransformPoint(const mat4f& lhs, const vec3f& rhs) { + vec3f ret; + simd4x4f_inv_ortho_matrix_point3_mul(&lhs.value, &rhs.value, &ret.value); + return ret; + } + + vectorial_inline vec3f orthoInverseTransformVector(const mat4f& lhs, const vec3f& rhs) { + vec3f ret; + simd4x4f_inv_ortho_matrix_vector3_mul(&lhs.value, &rhs.value, &ret.value); + return ret; + } + + + vectorial_inline mat4f transpose(const mat4f& m) { + mat4f ret; + simd4x4f_transpose(&m.value, &ret.value); + return ret; + } + + + vectorial_inline mat4f inverse(const mat4f& m) { + mat4f ret; + simd4x4f_inverse(&m.value, &ret.value); + return ret; + } + + + +} + + + +#ifdef VECTORIAL_OSTREAM +//#include + +vectorial_inline std::ostream& operator<<(std::ostream& os, const vectorial::mat4f& v) { + + os << "[ "; + os << simd4f_get_x(v.value.x) << ", "; + os << simd4f_get_x(v.value.y) << ", "; + os << simd4f_get_x(v.value.z) << ", "; + os << simd4f_get_x(v.value.w) << " ; "; + + os << simd4f_get_y(v.value.x) << ", "; + os << simd4f_get_y(v.value.y) << ", "; + os << simd4f_get_y(v.value.z) << ", "; + os << simd4f_get_y(v.value.w) << " ; "; + + os << simd4f_get_z(v.value.x) << ", "; + os << simd4f_get_z(v.value.y) << ", "; + os << simd4f_get_z(v.value.z) << ", "; + os << simd4f_get_z(v.value.w) << " ; "; + + os << simd4f_get_w(v.value.x) << ", "; + os << simd4f_get_w(v.value.y) << ", "; + os << simd4f_get_w(v.value.z) << ", "; + os << simd4f_get_w(v.value.w) << " ]"; + + return os; +} +#endif + + + + +#endif diff --git a/intern/mathfu/vectorial/simd2f.h b/intern/mathfu/vectorial/simd2f.h new file mode 100644 index 000000000000..3af19591187b --- /dev/null +++ b/intern/mathfu/vectorial/simd2f.h @@ -0,0 +1,38 @@ +/* + Vectorial + Copyright (c) 2014 Google, Inc. + Licensed under the terms of the two-clause BSD License (see LICENSE) +*/ + +#ifndef VECTORIAL_SIMD2F_H +#define VECTORIAL_SIMD2F_H + +#include "vectorial/config.h" + +#if defined(VECTORIAL_NEON) + #include "simd2f_neon.h" +#else + #error No implementation defined +#endif + +#include "simd2f_common.h" + +#ifdef __cplusplus + + #ifdef VECTORIAL_OSTREAM + #include + + vectorial_inline std::ostream& operator<<(std::ostream& os, const simd2f& v) { + os << "simd2f(" << simd2f_get_x(v) << ", " + << simd2f_get_y(v) << ")"; + return os; + } + #endif + +#endif + + + + +#endif + diff --git a/intern/mathfu/vectorial/simd2f_common.h b/intern/mathfu/vectorial/simd2f_common.h new file mode 100644 index 000000000000..e2046eea9d2c --- /dev/null +++ b/intern/mathfu/vectorial/simd2f_common.h @@ -0,0 +1,22 @@ +/* + Vectorial + Copyright (c) 2014 Google + Licensed under the terms of the two-clause BSD License (see LICENSE) +*/ +#ifndef VECTORIAL_SIMD2F_COMMON_H +#define VECTORIAL_SIMD2F_COMMON_H + +vectorial_inline simd2f simd2f_length2(simd2f v) { + return simd2f_sqrt( simd2f_dot2(v,v) ); +} + +vectorial_inline simd2f simd2f_length2_squared(simd2f v) { + return simd2f_dot2(v,v); +} + +vectorial_inline simd2f simd2f_normalize2(simd2f a) { + simd2f invlen = simd2f_rsqrt( simd2f_dot2(a,a) ); + return simd2f_mul(a, invlen); +} + +#endif diff --git a/intern/mathfu/vectorial/simd2f_neon.h b/intern/mathfu/vectorial/simd2f_neon.h new file mode 100644 index 000000000000..ca72e04f2ff0 --- /dev/null +++ b/intern/mathfu/vectorial/simd2f_neon.h @@ -0,0 +1,159 @@ +/* + Vectorial + Copyright (c) 2010 Mikko Lehtonen + Copyright (c) 2014 Google, Inc. + Licensed under the terms of the two-clause BSD License (see LICENSE) +*/ +#ifndef VECTORIAL_SIMD2F_NEON_H +#define VECTORIAL_SIMD2F_NEON_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef float32x2_t simd2f; + +typedef union { + simd2f s ; + float f[2]; +} _simd2f_union; + + + +vectorial_inline simd2f simd2f_create(float x, float y) { + const float32_t d[2] = { x,y }; + simd2f s = vld1_f32(d); + return s; +} + +vectorial_inline simd2f simd2f_zero() { return vdup_n_f32(0.0f); } + +vectorial_inline simd2f simd2f_uload2(const float *ary) { + const float32_t* ary32 = (const float32_t*)ary; + simd2f s = vld1_f32(ary32); + return s; +} + +vectorial_inline void simd2f_ustore2(const simd2f val, float *ary) { + vst1_f32( (float32_t*)ary, val); +} + +vectorial_inline simd2f simd2f_splat(float v) { + simd2f s = vdup_n_f32(v); + return s; +} + +vectorial_inline simd2f simd2f_splat_x(simd2f v) { + simd2f ret = vdup_lane_f32(v, 0); + return ret; +} + +vectorial_inline simd2f simd2f_splat_y(simd2f v) { + simd2f ret = vdup_lane_f32(v, 1); + return ret; +} + +vectorial_inline simd2f simd2f_reciprocal(simd2f v) { + simd2f estimate = vrecpe_f32(v); + estimate = vmul_f32(vrecps_f32(estimate, v), estimate); + estimate = vmul_f32(vrecps_f32(estimate, v), estimate); + return estimate; +} + +vectorial_inline void simd2f_rsqrt_1iteration(const simd2f& v, simd2f& estimate) { + simd2f estimate2 = vmul_f32(estimate, v); + estimate = vmul_f32(estimate, vrsqrts_f32(estimate2, estimate)); +} + +vectorial_inline simd2f simd2f_rsqrt1(simd2f v) { + simd2f estimate = vrsqrte_f32(v); + simd2f_rsqrt_1iteration(v, estimate); + return estimate; +} + +vectorial_inline simd2f simd2f_rsqrt2(simd2f v) { + simd2f estimate = vrsqrte_f32(v); + simd2f_rsqrt_1iteration(v, estimate); + simd2f_rsqrt_1iteration(v, estimate); + return estimate; +} + +vectorial_inline simd2f simd2f_rsqrt3(simd2f v) { + simd2f estimate = vrsqrte_f32(v); + simd2f_rsqrt_1iteration(v, estimate); + simd2f_rsqrt_1iteration(v, estimate); + simd2f_rsqrt_1iteration(v, estimate); + return estimate; +} + +// http://en.wikipedia.org/wiki/Fast_inverse_square_root makes the argument for +// one iteration but two gives a signficant accuracy improvment. +vectorial_inline simd2f simd2f_rsqrt(simd2f v) { + return simd2f_rsqrt2(v); +} + +vectorial_inline simd2f simd2f_sqrt(simd2f v) { + + return vreinterpret_f32_u32(vand_u32( vtst_u32(vreinterpret_u32_f32(v), + vreinterpret_u32_f32(v)), + vreinterpret_u32_f32( + simd2f_reciprocal(simd2f_rsqrt(v))) + ) + ); + +} + +// arithmetics + +vectorial_inline simd2f simd2f_add(simd2f lhs, simd2f rhs) { + simd2f ret = vadd_f32(lhs, rhs); + return ret; +} + +vectorial_inline simd2f simd2f_sub(simd2f lhs, simd2f rhs) { + simd2f ret = vsub_f32(lhs, rhs); + return ret; +} + +vectorial_inline simd2f simd2f_mul(simd2f lhs, simd2f rhs) { + simd2f ret = vmul_f32(lhs, rhs); + return ret; +} + +vectorial_inline simd2f simd2f_div(simd2f lhs, simd2f rhs) { + simd2f recip = simd2f_reciprocal( rhs ); + simd2f ret = vmul_f32(lhs, recip); + return ret; +} + +vectorial_inline simd2f simd2f_madd(simd2f m1, simd2f m2, simd2f a) { + return vmla_f32( a, m1, m2 ); +} + +vectorial_inline float simd2f_get_x(simd2f s) { return vget_lane_f32(s, 0); } +vectorial_inline float simd2f_get_y(simd2f s) { return vget_lane_f32(s, 1); } + +vectorial_inline simd2f simd2f_dot2(simd2f lhs, simd2f rhs) { + const simd2f m = simd2f_mul(lhs, rhs); + return vpadd_f32(m, m); +} + +vectorial_inline simd2f simd2f_min(simd2f a, simd2f b) { + return vmin_f32( a, b ); +} + +vectorial_inline simd2f simd2f_max(simd2f a, simd2f b) { + return vmax_f32( a, b ); +} + + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/intern/mathfu/vectorial/simd4f.h b/intern/mathfu/vectorial/simd4f.h new file mode 100644 index 000000000000..81037b7d0965 --- /dev/null +++ b/intern/mathfu/vectorial/simd4f.h @@ -0,0 +1,51 @@ +/* + Vectorial + Copyright (c) 2010 Mikko Lehtonen + Licensed under the terms of the two-clause BSD License (see LICENSE) +*/ + +#ifndef VECTORIAL_SIMD4F_H +#define VECTORIAL_SIMD4F_H + +#ifndef VECTORIAL_CONFIG_H + #include "vectorial/config.h" +#endif + + +#ifdef VECTORIAL_SCALAR + #include "simd4f_scalar.h" +#elif defined(VECTORIAL_SSE) + #include "simd4f_sse.h" +#elif defined(VECTORIAL_GNU) + #include "simd4f_gnu.h" +#elif defined(VECTORIAL_NEON) + #include "simd4f_neon.h" +#else + #error No implementation defined +#endif + +#include "simd4f_common.h" + + + +#ifdef __cplusplus + + #ifdef VECTORIAL_OSTREAM + #include + + vectorial_inline std::ostream& operator<<(std::ostream& os, const simd4f& v) { + os << "simd4f(" << simd4f_get_x(v) << ", " + << simd4f_get_y(v) << ", " + << simd4f_get_z(v) << ", " + << simd4f_get_w(v) << ")"; + return os; + } + #endif + +#endif + + + + +#endif + diff --git a/intern/mathfu/vectorial/simd4f_common.h b/intern/mathfu/vectorial/simd4f_common.h new file mode 100644 index 000000000000..f22111f409d9 --- /dev/null +++ b/intern/mathfu/vectorial/simd4f_common.h @@ -0,0 +1,74 @@ +/* + Vectorial + Copyright (c) 2010 Mikko Lehtonen + Copyright (c) 2014 Google, Inc. + Licensed under the terms of the two-clause BSD License (see LICENSE) +*/ +#ifndef VECTORIAL_SIMD4F_COMMON_H +#define VECTORIAL_SIMD4F_COMMON_H + + +vectorial_inline simd4f simd4f_sum(simd4f v) { + const simd4f s1 = simd4f_add(simd4f_splat_x(v), simd4f_splat_y(v)); + const simd4f s2 = simd4f_add(s1, simd4f_splat_z(v)); + const simd4f s3 = simd4f_add(s2, simd4f_splat_w(v)); + return s3; +} + +vectorial_inline simd4f simd4f_dot4(simd4f lhs, simd4f rhs) { + return simd4f_sum( simd4f_mul(lhs, rhs) ); +} + +vectorial_inline simd4f simd4f_dot2(simd4f lhs, simd4f rhs) { + const simd4f m = simd4f_mul(lhs, rhs); + const simd4f s1 = simd4f_add(simd4f_splat_x(m), simd4f_splat_y(m)); + return s1; +} + + +vectorial_inline simd4f simd4f_length4(simd4f v) { + return simd4f_sqrt( simd4f_dot4(v,v) ); +} + +vectorial_inline simd4f simd4f_length3(simd4f v) { + return simd4f_sqrt( simd4f_dot3(v,v) ); +} + +vectorial_inline simd4f simd4f_length2(simd4f v) { + return simd4f_sqrt( simd4f_dot2(v,v) ); +} + +vectorial_inline simd4f simd4f_length4_squared(simd4f v) { + return simd4f_dot4(v,v); +} + +vectorial_inline simd4f simd4f_length3_squared(simd4f v) { + return simd4f_dot3(v,v); +} + +vectorial_inline float simd4f_length3_squared_scalar(simd4f v) { + return simd4f_dot3_scalar(v,v); +} + +vectorial_inline simd4f simd4f_length2_squared(simd4f v) { + return simd4f_dot2(v,v); +} + + +vectorial_inline simd4f simd4f_normalize4(simd4f a) { + simd4f invlen = simd4f_rsqrt( simd4f_dot4(a,a) ); + return simd4f_mul(a, invlen); +} + +vectorial_inline simd4f simd4f_normalize3(simd4f a) { + simd4f invlen = simd4f_rsqrt( simd4f_dot3(a,a) ); + return simd4f_mul(a, invlen); +} + +vectorial_inline simd4f simd4f_normalize2(simd4f a) { + simd4f invlen = simd4f_rsqrt( simd4f_dot2(a,a) ); + return simd4f_mul(a, invlen); +} + + +#endif diff --git a/intern/mathfu/vectorial/simd4f_gnu.h b/intern/mathfu/vectorial/simd4f_gnu.h new file mode 100644 index 000000000000..4e48289be305 --- /dev/null +++ b/intern/mathfu/vectorial/simd4f_gnu.h @@ -0,0 +1,225 @@ +/* + Vectorial + Copyright (c) 2010 Mikko Lehtonen + Licensed under the terms of the two-clause BSD License (see LICENSE) +*/ +#ifndef VECTORIAL_SIMD4F_GNU_H +#define VECTORIAL_SIMD4F_GNU_H + +#include +#include // memcpy + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef float simd4f __attribute__ ((vector_size (16))); + +typedef union { + simd4f s ; + float f[4]; +} _simd4f_union; + +vectorial_inline float simd4f_get_x(simd4f s) { _simd4f_union u={s}; return u.f[0]; } +vectorial_inline float simd4f_get_y(simd4f s) { _simd4f_union u={s}; return u.f[1]; } +vectorial_inline float simd4f_get_z(simd4f s) { _simd4f_union u={s}; return u.f[2]; } +vectorial_inline float simd4f_get_w(simd4f s) { _simd4f_union u={s}; return u.f[3]; } + + +vectorial_inline simd4f simd4f_create(float x, float y, float z, float w) { + simd4f s = { x, y, z, w }; + return s; +} + +vectorial_inline simd4f simd4f_zero() { return simd4f_create(0.0f, 0.0f, 0.0f, 0.0f); } + +vectorial_inline simd4f simd4f_uload4(const float *ary) { + simd4f s = { ary[0], ary[1], ary[2], ary[3] }; + return s; +} + +vectorial_inline simd4f simd4f_uload3(const float *ary) { + simd4f s = { ary[0], ary[1], ary[2], 0 }; + return s; +} + +vectorial_inline simd4f simd4f_uload2(const float *ary) { + simd4f s = { ary[0], ary[1], 0, 0 }; + return s; +} + + +vectorial_inline void simd4f_ustore4(const simd4f val, float *ary) { + memcpy(ary, &val, sizeof(float) * 4); +} + +vectorial_inline void simd4f_ustore3(const simd4f val, float *ary) { + memcpy(ary, &val, sizeof(float) * 3); +} + +vectorial_inline void simd4f_ustore2(const simd4f val, float *ary) { + memcpy(ary, &val, sizeof(float) * 2); +} + + +vectorial_inline simd4f simd4f_splat(float v) { + simd4f s = { v, v, v, v }; + return s; +} + +vectorial_inline simd4f simd4f_splat_x(simd4f v) { + float s = simd4f_get_x(v); + simd4f ret = { s, s, s, s }; + return ret; +} + +vectorial_inline simd4f simd4f_splat_y(simd4f v) { + float s = simd4f_get_y(v); + simd4f ret = { s, s, s, s }; + return ret; +} + +vectorial_inline simd4f simd4f_splat_z(simd4f v) { + float s = simd4f_get_z(v); + simd4f ret = { s, s, s, s }; + return ret; +} + +vectorial_inline simd4f simd4f_splat_w(simd4f v) { + float s = simd4f_get_w(v); + simd4f ret = { s, s, s, s }; + return ret; +} + +vectorial_inline simd4f simd4f_reciprocal(simd4f v) { + return simd4f_splat(1.0f) / v; +} + +vectorial_inline simd4f simd4f_sqrt(simd4f v) { + simd4f ret = { sqrtf(simd4f_get_x(v)), sqrtf(simd4f_get_y(v)), sqrtf(simd4f_get_z(v)), sqrtf(simd4f_get_w(v)) }; + return ret; +} + +vectorial_inline simd4f simd4f_rsqrt(simd4f v) { + return simd4f_splat(1.0f) / simd4f_sqrt(v); +} + + + +vectorial_inline simd4f simd4f_add(simd4f lhs, simd4f rhs) { + simd4f ret = lhs + rhs; + return ret; +} + +vectorial_inline simd4f simd4f_sub(simd4f lhs, simd4f rhs) { + simd4f ret = lhs - rhs; + return ret; +} + +vectorial_inline simd4f simd4f_mul(simd4f lhs, simd4f rhs) { + simd4f ret = lhs * rhs; + return ret; +} + +vectorial_inline simd4f simd4f_div(simd4f lhs, simd4f rhs) { + simd4f ret = lhs / rhs; + return ret; +} + +vectorial_inline simd4f simd4f_madd(simd4f m1, simd4f m2, simd4f a) { + return simd4f_add( simd4f_mul(m1, m2), a ); +} + +vectorial_inline float simd4f_dot3_scalar(simd4f lhs, simd4f rhs) { + _simd4f_union l = {lhs}; + _simd4f_union r = {rhs}; + return l.f[0] * r.f[0] + l.f[1] * r.f[1] + l.f[2] * r.f[2]; +} + +vectorial_inline simd4f simd4f_dot3(simd4f lhs, simd4f rhs) { + return simd4f_splat( simd4f_dot3_scalar(lhs, rhs) ); +} + +vectorial_inline simd4f simd4f_cross3(simd4f l, simd4f r) { + _simd4f_union lhs = {l}; + _simd4f_union rhs = {r}; + + return simd4f_create( lhs.f[1] * rhs.f[2] - lhs.f[2] * rhs.f[1], + lhs.f[2] * rhs.f[0] - lhs.f[0] * rhs.f[2], + lhs.f[0] * rhs.f[1] - lhs.f[1] * rhs.f[0], 0); +} + + +vectorial_inline simd4f simd4f_shuffle_wxyz(simd4f s) { + _simd4f_union u = {s}; + return simd4f_create(u.f[3], u.f[0], u.f[1], u.f[2]); +} + +vectorial_inline simd4f simd4f_shuffle_zwxy(simd4f s) { + _simd4f_union u = {s}; + return simd4f_create(u.f[2], u.f[3], u.f[0], u.f[1]); +} + +vectorial_inline simd4f simd4f_shuffle_yzwx(simd4f s) { + _simd4f_union u = {s}; + return simd4f_create(u.f[1], u.f[2], u.f[3], u.f[0]); +} + + +vectorial_inline simd4f simd4f_zero_w(simd4f s) { + _simd4f_union u = {s}; + return simd4f_create(u.f[0], u.f[1], u.f[2], 0.0f); +} + +vectorial_inline simd4f simd4f_zero_zw(simd4f s) { + _simd4f_union u = {s}; + return simd4f_create(u.f[0], u.f[1], 0.0f, 0.0f); +} + + +vectorial_inline simd4f simd4f_merge_high(simd4f abcd, simd4f xyzw) { + _simd4f_union u1 = {abcd}; + _simd4f_union u2 = {xyzw}; + return simd4f_create(u1.f[2], u1.f[3], u2.f[2], u2.f[3]); +} + +vectorial_inline simd4f simd4f_flip_sign_0101(simd4f s) { + _simd4f_union u = {s}; + return simd4f_create(u.f[0], -u.f[1], u.f[2], -u.f[3]); +} + +vectorial_inline simd4f simd4f_flip_sign_1010(simd4f s) { + _simd4f_union u = {s}; + return simd4f_create(-u.f[0], u.f[1], -u.f[2], u.f[3]); +} + + +vectorial_inline simd4f simd4f_min(simd4f a, simd4f b) { + _simd4f_union ua = {a}; + _simd4f_union ub = {b}; + return simd4f_create( ua.f[0] < ub.f[0] ? ua.f[0] : ub.f[0], + ua.f[1] < ub.f[1] ? ua.f[1] : ub.f[1], + ua.f[2] < ub.f[2] ? ua.f[2] : ub.f[2], + ua.f[3] < ub.f[3] ? ua.f[3] : ub.f[3] ); +} + +vectorial_inline simd4f simd4f_max(simd4f a, simd4f b) { + _simd4f_union ua = {a}; + _simd4f_union ub = {b}; + return simd4f_create( ua.f[0] > ub.f[0] ? ua.f[0] : ub.f[0], + ua.f[1] > ub.f[1] ? ua.f[1] : ub.f[1], + ua.f[2] > ub.f[2] ? ua.f[2] : ub.f[2], + ua.f[3] > ub.f[3] ? ua.f[3] : ub.f[3] ); +} + + + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/intern/mathfu/vectorial/simd4f_neon.h b/intern/mathfu/vectorial/simd4f_neon.h new file mode 100644 index 000000000000..8ec7d7cc1b2b --- /dev/null +++ b/intern/mathfu/vectorial/simd4f_neon.h @@ -0,0 +1,280 @@ +/* + Vectorial + Copyright (c) 2010 Mikko Lehtonen + Copyright (c) 2014 Google, Inc. + Licensed under the terms of the two-clause BSD License (see LICENSE) +*/ +#ifndef VECTORIAL_SIMD4F_NEON_H +#define VECTORIAL_SIMD4F_NEON_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef float32x4_t simd4f; +typedef float32x2_t simd2f; + +typedef union { + simd4f s ; + float f[4]; +} _simd4f_union; + + + +vectorial_inline simd4f simd4f_create(float x, float y, float z, float w) { + const float32_t d[4] = { x,y,z,w }; + simd4f s = vld1q_f32(d); + return s; +} + +vectorial_inline simd4f simd4f_zero() { return vdupq_n_f32(0.0f); } + +vectorial_inline simd4f simd4f_uload4(const float *ary) { + const float32_t* ary32 = (const float32_t*)ary; + simd4f s = vld1q_f32(ary32); + return s; +} + +vectorial_inline simd4f simd4f_uload3(const float *ary) { + simd4f s = simd4f_create(ary[0], ary[1], ary[2], 0); + return s; +} + +vectorial_inline simd4f simd4f_uload2(const float *ary) { + const float32_t* ary32 = (const float32_t*)ary; + float32x2_t low = vld1_f32(ary32); + const float32_t zero = 0; + float32x2_t high = vld1_dup_f32(&zero); // { 0,0 } but stupid warnings from llvm-gcc + return vcombine_f32(low, high); +} + + +vectorial_inline void simd4f_ustore4(const simd4f val, float *ary) { + vst1q_f32( (float32_t*)ary, val); +} + +vectorial_inline void simd4f_ustore3(const simd4f val, float *ary) { + float* local_data = ary; + vst1q_lane_f32(local_data++, val, 0); + vst1q_lane_f32(local_data++, val, 1); + vst1q_lane_f32(local_data, val, 2); +} + +vectorial_inline void simd4f_ustore2(const simd4f val, float *ary) { + const float32x2_t low = vget_low_f32(val); + vst1_f32( (float32_t*)ary, low); +} + + + + +vectorial_inline simd4f simd4f_splat(float v) { + simd4f s = vdupq_n_f32(v); + return s; +} + +// todo: or is simd4f_splat(simd4f_get_x(v)) better? + +vectorial_inline simd4f simd4f_splat_x(simd4f v) { + float32x2_t o = vget_low_f32(v); + simd4f ret = vdupq_lane_f32(o, 0); + return ret; +} + +vectorial_inline simd4f simd4f_splat_y(simd4f v) { + float32x2_t o = vget_low_f32(v); + simd4f ret = vdupq_lane_f32(o, 1); + return ret; +} + +vectorial_inline simd4f simd4f_splat_z(simd4f v) { + float32x2_t o = vget_high_f32(v); + simd4f ret = vdupq_lane_f32(o, 0); + return ret; +} + +vectorial_inline simd4f simd4f_splat_w(simd4f v) { + float32x2_t o = vget_high_f32(v); + simd4f ret = vdupq_lane_f32(o, 1); + return ret; +} + +vectorial_inline simd4f simd4f_reciprocal(simd4f v) { + simd4f estimate = vrecpeq_f32(v); + estimate = vmulq_f32(vrecpsq_f32(estimate, v), estimate); + estimate = vmulq_f32(vrecpsq_f32(estimate, v), estimate); + return estimate; +} + +vectorial_inline void simd4f_rsqrt_1iteration(const simd4f& v, simd4f& estimate) { + simd4f estimate2 = vmulq_f32(estimate, v); + estimate = vmulq_f32(estimate, vrsqrtsq_f32(estimate2, estimate)); +} + +vectorial_inline simd4f simd4f_rsqrt1(simd4f v) { + simd4f estimate = vrsqrteq_f32(v); + simd4f_rsqrt_1iteration(v, estimate); + return estimate; +} + +vectorial_inline simd4f simd4f_rsqrt2(simd4f v) { + simd4f estimate = vrsqrteq_f32(v); + simd4f_rsqrt_1iteration(v, estimate); + simd4f_rsqrt_1iteration(v, estimate); + return estimate; +} + +vectorial_inline simd4f simd4f_rsqrt3(simd4f v) { + simd4f estimate = vrsqrteq_f32(v); + simd4f_rsqrt_1iteration(v, estimate); + simd4f_rsqrt_1iteration(v, estimate); + simd4f_rsqrt_1iteration(v, estimate); + return estimate; +} + +// http://en.wikipedia.org/wiki/Fast_inverse_square_root makes the argument for +// one iteration but two gives a signficant accuracy improvment. +vectorial_inline simd4f simd4f_rsqrt(simd4f v) { + return simd4f_rsqrt2(v); +} + +vectorial_inline simd4f simd4f_sqrt(simd4f v) { + + return vreinterpretq_f32_u32(vandq_u32( vtstq_u32(vreinterpretq_u32_f32(v), + vreinterpretq_u32_f32(v)), + vreinterpretq_u32_f32( + simd4f_reciprocal(simd4f_rsqrt(v))) + ) + ); + +} + + + +// arithmetics + +vectorial_inline simd4f simd4f_add(simd4f lhs, simd4f rhs) { + simd4f ret = vaddq_f32(lhs, rhs); + return ret; +} + +vectorial_inline simd4f simd4f_sub(simd4f lhs, simd4f rhs) { + simd4f ret = vsubq_f32(lhs, rhs); + return ret; +} + +vectorial_inline simd4f simd4f_mul(simd4f lhs, simd4f rhs) { + simd4f ret = vmulq_f32(lhs, rhs); + return ret; +} + +vectorial_inline simd4f simd4f_div(simd4f lhs, simd4f rhs) { + simd4f recip = simd4f_reciprocal( rhs ); + simd4f ret = vmulq_f32(lhs, recip); + return ret; +} + +vectorial_inline simd4f simd4f_madd(simd4f m1, simd4f m2, simd4f a) { + return vmlaq_f32( a, m1, m2 ); +} + + + +vectorial_inline float simd4f_get_x(simd4f s) { return vgetq_lane_f32(s, 0); } +vectorial_inline float simd4f_get_y(simd4f s) { return vgetq_lane_f32(s, 1); } +vectorial_inline float simd4f_get_z(simd4f s) { return vgetq_lane_f32(s, 2); } +vectorial_inline float simd4f_get_w(simd4f s) { return vgetq_lane_f32(s, 3); } + +// This function returns x*x+y*y+z*z and ignores the w component. +vectorial_inline float simd4f_dot3_scalar(simd4f lhs, simd4f rhs) { + const simd4f m = simd4f_mul(lhs, rhs); + simd2f s1 = vpadd_f32(vget_low_f32(m), vget_low_f32(m)); + s1 = vadd_f32(s1, vget_high_f32(m)); + return vget_lane_f32(s1, 0); +} + +vectorial_inline simd4f simd4f_dot3(simd4f lhs, simd4f rhs) { + return simd4f_splat(simd4f_dot3_scalar(lhs, rhs)); +} + +vectorial_inline simd4f simd4f_cross3(simd4f lhs, simd4f rhs) { + // Compute lhs and rhs in order yzx + simd2f lhs_low = vget_low_f32(lhs); + simd2f rhs_low = vget_low_f32(rhs); + simd4f lhs_yzx = vcombine_f32(vext_f32(lhs_low, vget_high_f32(lhs),1), lhs_low); + simd4f rhs_yzx = vcombine_f32(vext_f32(rhs_low, vget_high_f32(rhs),1), rhs_low); + // Compute cross in order zxy + simd4f s3 = simd4f_sub(simd4f_mul(rhs_yzx, lhs), simd4f_mul(lhs_yzx, rhs)); + // Permute cross to order xyz and zero out the fourth value + simd2f low = vget_low_f32(s3); + static const uint32_t mask_array[] = { + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0}; + static const int32x4_t mask = vld1q_s32((const int32_t*)mask_array); + s3 = vcombine_f32(vext_f32(low, vget_high_f32(s3), 1), low); + return (simd4f)vandq_s32((int32x4_t)s3,mask); +} + +vectorial_inline simd4f simd4f_shuffle_wxyz(simd4f s) { + _simd4f_union u = {s}; + return simd4f_create( u.f[3], u.f[0], u.f[1], u.f[2]); +} + +vectorial_inline simd4f simd4f_shuffle_zwxy(simd4f s) { + _simd4f_union u = {s}; + return simd4f_create(u.f[2], u.f[3], u.f[0], u.f[1]); +} + +vectorial_inline simd4f simd4f_shuffle_yzwx(simd4f s) { + _simd4f_union u = {s}; + return simd4f_create(u.f[1], u.f[2], u.f[3], u.f[0]); +} + + +vectorial_inline simd4f simd4f_zero_w(simd4f s) { + _simd4f_union u = {s}; + return simd4f_create(u.f[0], u.f[1], u.f[2], 0.0f); +} + +vectorial_inline simd4f simd4f_zero_zw(simd4f s) { + _simd4f_union u = {s}; + return simd4f_create(u.f[0], u.f[1], 0.0f, 0.0f); +} + + +vectorial_inline simd4f simd4f_merge_high(simd4f xyzw, simd4f abcd) { + _simd4f_union u1 = {xyzw}; + _simd4f_union u2 = {abcd}; + return simd4f_create(u1.f[2], u1.f[3], u2.f[2], u2.f[3]); +} + +vectorial_inline simd4f simd4f_flip_sign_0101(simd4f s) { + const unsigned int upnpn[4] = { 0x00000000, 0x80000000, 0x00000000, 0x80000000 }; + const uint32x4_t pnpn = vld1q_u32( upnpn ); + return vreinterpretq_f32_u32( veorq_u32( vreinterpretq_u32_f32(s), pnpn ) ); +} + +vectorial_inline simd4f simd4f_flip_sign_1010(simd4f s) { + const unsigned int unpnp[4] = { 0x80000000, 0x00000000, 0x80000000, 0x00000000 }; + const uint32x4_t npnp = vld1q_u32( unpnp ); + return vreinterpretq_f32_u32( veorq_u32( vreinterpretq_u32_f32(s), npnp ) ); +} + + +vectorial_inline simd4f simd4f_min(simd4f a, simd4f b) { + return vminq_f32( a, b ); +} + +vectorial_inline simd4f simd4f_max(simd4f a, simd4f b) { + return vmaxq_f32( a, b ); +} + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/intern/mathfu/vectorial/simd4f_scalar.h b/intern/mathfu/vectorial/simd4f_scalar.h new file mode 100644 index 000000000000..3a3ea8ce70ed --- /dev/null +++ b/intern/mathfu/vectorial/simd4f_scalar.h @@ -0,0 +1,199 @@ +/* + Vectorial + Copyright (c) 2010 Mikko Lehtonen + Licensed under the terms of the two-clause BSD License (see LICENSE) +*/ +#ifndef VECTORIAL_SIMD4F_SCALAR_H +#define VECTORIAL_SIMD4F_SCALAR_H + +#include +#include // memcpy + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct { + float x; + float y; + float z; + float w; +} simd4f; + + + +vectorial_inline simd4f simd4f_create(float x, float y, float z, float w) { + simd4f s = { x, y, z, w }; + return s; +} + +vectorial_inline simd4f simd4f_zero() { return simd4f_create(0.0f, 0.0f, 0.0f, 0.0f); } + +vectorial_inline simd4f simd4f_uload4(const float *ary) { + simd4f s = { ary[0], ary[1], ary[2], ary[3] }; + return s; +} + +vectorial_inline simd4f simd4f_uload3(const float *ary) { + simd4f s = { ary[0], ary[1], ary[2], 0 }; + return s; +} + +vectorial_inline simd4f simd4f_uload2(const float *ary) { + simd4f s = { ary[0], ary[1], 0, 0 }; + return s; +} + + +vectorial_inline void simd4f_ustore4(const simd4f val, float *ary) { + memcpy(ary, &val, sizeof(float) * 4); +} + +vectorial_inline void simd4f_ustore3(const simd4f val, float *ary) { + memcpy(ary, &val, sizeof(float) * 3); +} + +vectorial_inline void simd4f_ustore2(const simd4f val, float *ary) { + memcpy(ary, &val, sizeof(float) * 2); +} + + + +// utilities +vectorial_inline simd4f simd4f_splat(float v) { + simd4f s = { v, v, v, v }; + return s; +} + +vectorial_inline simd4f simd4f_splat_x(simd4f v) { + simd4f s = { v.x, v.x, v.x, v.x }; + return s; +} + +vectorial_inline simd4f simd4f_splat_y(simd4f v) { + simd4f s = { v.y, v.y, v.y, v.y }; + return s; +} + +vectorial_inline simd4f simd4f_splat_z(simd4f v) { + simd4f s = { v.z, v.z, v.z, v.z }; + return s; +} + +vectorial_inline simd4f simd4f_splat_w(simd4f v) { + simd4f s = { v.w, v.w, v.w, v.w }; + return s; +} + +vectorial_inline simd4f simd4f_reciprocal(simd4f v) { + simd4f s = { 1.0f/v.x, 1.0f/v.y, 1.0f/v.z, 1.0f/v.w }; + return s; +} + +vectorial_inline simd4f simd4f_sqrt(simd4f v) { + simd4f s = { sqrtf(v.x), sqrtf(v.y), sqrtf(v.z), sqrtf(v.w) }; + return s; +} + +vectorial_inline simd4f simd4f_rsqrt(simd4f v) { + simd4f s = { 1.0f/sqrtf(v.x), 1.0f/sqrtf(v.y), 1.0f/sqrtf(v.z), 1.0f/sqrtf(v.w) }; + return s; +} + + +// arithmetic + +vectorial_inline simd4f simd4f_add(simd4f lhs, simd4f rhs) { + simd4f ret = { lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w }; + return ret; +} + +vectorial_inline simd4f simd4f_sub(simd4f lhs, simd4f rhs) { + simd4f ret = { lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w }; + return ret; +} + +vectorial_inline simd4f simd4f_mul(simd4f lhs, simd4f rhs) { + simd4f ret = { lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w }; + return ret; +} + +vectorial_inline simd4f simd4f_div(simd4f lhs, simd4f rhs) { + simd4f ret = { lhs.x / rhs.x, lhs.y / rhs.y, lhs.z / rhs.z, lhs.w / rhs.w }; + return ret; +} + +vectorial_inline simd4f simd4f_madd(simd4f m1, simd4f m2, simd4f a) { + return simd4f_add( simd4f_mul(m1, m2), a ); +} + +vectorial_inline float simd4f_dot3_scalar(simd4f lhs, simd4f rhs) { + return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z; +} + +vectorial_inline simd4f simd4f_dot3(simd4f lhs, simd4f rhs) { + return simd4f_splat( simd4f_dot3_scalar(lhs, rhs) ); +} + +vectorial_inline simd4f simd4f_cross3(simd4f lhs, simd4f rhs) { + return simd4f_create( lhs.y * rhs.z - lhs.z * rhs.y, + lhs.z * rhs.x - lhs.x * rhs.z, + lhs.x * rhs.y - lhs.y * rhs.x, 0); +} + + +vectorial_inline float simd4f_get_x(simd4f s) { return s.x; } +vectorial_inline float simd4f_get_y(simd4f s) { return s.y; } +vectorial_inline float simd4f_get_z(simd4f s) { return s.z; } +vectorial_inline float simd4f_get_w(simd4f s) { return s.w; } + + +vectorial_inline simd4f simd4f_shuffle_wxyz(simd4f s) { return simd4f_create(s.w, s.x, s.y, s.z); } +vectorial_inline simd4f simd4f_shuffle_zwxy(simd4f s) { return simd4f_create(s.z, s.w, s.x, s.y); } +vectorial_inline simd4f simd4f_shuffle_yzwx(simd4f s) { return simd4f_create(s.y, s.z, s.w, s.x); } + + +vectorial_inline simd4f simd4f_zero_w(simd4f s) { + return simd4f_create(s.x, s.y, s.z, 0.0f); +} + +vectorial_inline simd4f simd4f_zero_zw(simd4f s) { + return simd4f_create(s.x, s.y, 0.0f, 0.0f); +} + + +vectorial_inline simd4f simd4f_merge_high(simd4f abcd, simd4f xyzw) { + return simd4f_create(abcd.z, abcd.w, xyzw.z, xyzw.w); +} + +vectorial_inline simd4f simd4f_flip_sign_0101(simd4f s) { + return simd4f_create(s.x, -s.y, s.z, -s.w); +} + +vectorial_inline simd4f simd4f_flip_sign_1010(simd4f s) { + return simd4f_create(-s.x, s.y, -s.z, s.w); +} + +vectorial_inline simd4f simd4f_min(simd4f a, simd4f b) { + return simd4f_create( a.x < b.x ? a.x : b.x, + a.y < b.y ? a.y : b.y, + a.z < b.z ? a.z : b.z, + a.w < b.w ? a.w : b.w ); +} + +vectorial_inline simd4f simd4f_max(simd4f a, simd4f b) { + return simd4f_create( a.x > b.x ? a.x : b.x, + a.y > b.y ? a.y : b.y, + a.z > b.z ? a.z : b.z, + a.w > b.w ? a.w : b.w ); +} + + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/intern/mathfu/vectorial/simd4f_sse.h b/intern/mathfu/vectorial/simd4f_sse.h new file mode 100644 index 000000000000..c5684b992b46 --- /dev/null +++ b/intern/mathfu/vectorial/simd4f_sse.h @@ -0,0 +1,236 @@ +/* + Vectorial + Copyright (c) 2010 Mikko Lehtonen + Copyright (c) 2014 Google, Inc. + Licensed under the terms of the two-clause BSD License (see LICENSE) +*/ +#ifndef VECTORIAL_SIMD4F_SSE_H +#define VECTORIAL_SIMD4F_SSE_H + +// Conditionally enable SSE4.1 otherwise fallback to SSE. +#if defined(_M_IX86_FP) + #if _M_IX86_FP >=2 + #define VECTORIAL_USE_SSE4_1 + #endif +#elif defined(__SSE4_1__) + #define VECTORIAL_USE_SSE4_1 +#endif + +#include +#if defined(VECTORIAL_USE_SSE4_1) + #include +#endif +#include // memcpy + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef __m128 simd4f; + +typedef union { + simd4f s ; + float f[4]; + unsigned int ui[4]; +} _simd4f_union; + +// creating + +vectorial_inline simd4f simd4f_create(float x, float y, float z, float w) { + simd4f s = { x, y, z, w }; + return s; +} + +vectorial_inline simd4f simd4f_zero() { return _mm_setzero_ps(); } + +vectorial_inline simd4f simd4f_uload4(const float *ary) { + simd4f s = _mm_loadu_ps(ary); + return s; +} + +vectorial_inline simd4f simd4f_uload3(const float *ary) { + simd4f s = simd4f_create(ary[0], ary[1], ary[2], 0); + return s; +} + +vectorial_inline simd4f simd4f_uload2(const float *ary) { + simd4f s = simd4f_create(ary[0], ary[1], 0, 0); + return s; +} + + +vectorial_inline void simd4f_ustore4(const simd4f val, float *ary) { + _mm_storeu_ps(ary, val); +} + +vectorial_inline void simd4f_ustore3(const simd4f val, float *ary) { + memcpy(ary, &val, sizeof(float) * 3); +} + +vectorial_inline void simd4f_ustore2(const simd4f val, float *ary) { + memcpy(ary, &val, sizeof(float) * 2); +} + + +// utilites + +vectorial_inline simd4f simd4f_splat(float v) { + simd4f s = _mm_set1_ps(v); + return s; +} + +vectorial_inline simd4f simd4f_splat_x(simd4f v) { + simd4f s = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0,0,0,0)); + return s; +} + +vectorial_inline simd4f simd4f_splat_y(simd4f v) { + simd4f s = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1,1,1,1)); + return s; +} + +vectorial_inline simd4f simd4f_splat_z(simd4f v) { + simd4f s = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2,2,2,2)); + return s; +} + +vectorial_inline simd4f simd4f_splat_w(simd4f v) { + simd4f s = _mm_shuffle_ps(v, v, _MM_SHUFFLE(3,3,3,3)); + return s; +} + + +// arithmetic + +vectorial_inline simd4f simd4f_add(simd4f lhs, simd4f rhs) { + simd4f ret = _mm_add_ps(lhs, rhs); + return ret; +} + +vectorial_inline simd4f simd4f_sub(simd4f lhs, simd4f rhs) { + simd4f ret = _mm_sub_ps(lhs, rhs); + return ret; +} + +vectorial_inline simd4f simd4f_mul(simd4f lhs, simd4f rhs) { + simd4f ret = _mm_mul_ps(lhs, rhs); + return ret; +} + +vectorial_inline simd4f simd4f_div(simd4f lhs, simd4f rhs) { + simd4f ret = _mm_div_ps(lhs, rhs); + return ret; +} + +vectorial_inline simd4f simd4f_madd(simd4f m1, simd4f m2, simd4f a) { + return simd4f_add( simd4f_mul(m1, m2), a ); +} + + + + +vectorial_inline simd4f simd4f_reciprocal(simd4f v) { + simd4f s = _mm_rcp_ps(v); + const simd4f two = simd4f_create(2.0f, 2.0f, 2.0f, 2.0f); + s = simd4f_mul(s, simd4f_sub(two, simd4f_mul(v, s))); + return s; +} + +vectorial_inline simd4f simd4f_sqrt(simd4f v) { + simd4f s = _mm_sqrt_ps(v); + return s; +} + +vectorial_inline simd4f simd4f_rsqrt(simd4f v) { + simd4f s = _mm_rsqrt_ps(v); + const simd4f half = simd4f_create(0.5f, 0.5f, 0.5f, 0.5f); + const simd4f three = simd4f_create(3.0f, 3.0f, 3.0f, 3.0f); + s = simd4f_mul(simd4f_mul(s, half), simd4f_sub(three, simd4f_mul(s, simd4f_mul(v,s)))); + return s; +} + +vectorial_inline float simd4f_get_x(simd4f s) { _simd4f_union u={s}; return u.f[0]; } +vectorial_inline float simd4f_get_y(simd4f s) { _simd4f_union u={s}; return u.f[1]; } +vectorial_inline float simd4f_get_z(simd4f s) { _simd4f_union u={s}; return u.f[2]; } +vectorial_inline float simd4f_get_w(simd4f s) { _simd4f_union u={s}; return u.f[3]; } + +vectorial_inline simd4f simd4f_dot3(simd4f lhs,simd4f rhs) { +#if defined(VECTORIAL_USE_SSE4_1) + return _mm_dp_ps(lhs, rhs, 0x7f); +#else + simd4f_aligned16 const unsigned int mask_array[] = { 0xffffffff, 0xffffffff, 0xffffffff, 0 }; + const simd4f mask = _mm_load_ps((const float*)mask_array); + const simd4f m = _mm_mul_ps(lhs, rhs); + const simd4f s0 = _mm_and_ps(m, mask); + const simd4f s1 = _mm_add_ps(s0, _mm_movehl_ps(s0, s0)); + const simd4f s2 = _mm_add_ss(s1, _mm_shuffle_ps(s1, s1, 1)); + return _mm_shuffle_ps(s2,s2, 0); +#endif +} + +vectorial_inline float simd4f_dot3_scalar(simd4f lhs,simd4f rhs) { + return simd4f_get_x(simd4f_dot3(lhs, rhs)); +} + +vectorial_inline simd4f simd4f_cross3(simd4f lhs, simd4f rhs) { + + const simd4f lyzx = _mm_shuffle_ps(lhs, lhs, _MM_SHUFFLE(3,0,2,1)); + const simd4f lzxy = _mm_shuffle_ps(lhs, lhs, _MM_SHUFFLE(3,1,0,2)); + + const simd4f ryzx = _mm_shuffle_ps(rhs, rhs, _MM_SHUFFLE(3,0,2,1)); + const simd4f rzxy = _mm_shuffle_ps(rhs, rhs, _MM_SHUFFLE(3,1,0,2)); + + return _mm_sub_ps(_mm_mul_ps(lyzx, rzxy), _mm_mul_ps(lzxy, ryzx)); + +} + +vectorial_inline simd4f simd4f_shuffle_wxyz(simd4f s) { return _mm_shuffle_ps(s,s, _MM_SHUFFLE(2,1,0,3) ); } +vectorial_inline simd4f simd4f_shuffle_zwxy(simd4f s) { return _mm_shuffle_ps(s,s, _MM_SHUFFLE(1,0,3,2) ); } +vectorial_inline simd4f simd4f_shuffle_yzwx(simd4f s) { return _mm_shuffle_ps(s,s, _MM_SHUFFLE(0,3,2,1) ); } + +vectorial_inline simd4f simd4f_zero_w(simd4f s) { + simd4f r = _mm_unpackhi_ps(s, _mm_setzero_ps()); + return _mm_movelh_ps(s, r); +} + +vectorial_inline simd4f simd4f_zero_zw(simd4f s) { + return _mm_movelh_ps(s, _mm_setzero_ps()); +} + +vectorial_inline simd4f simd4f_merge_high(simd4f xyzw, simd4f abcd) { + return _mm_movehl_ps(abcd, xyzw); +} + + +typedef simd4f_aligned16 union { + unsigned int ui[4]; + float f[4]; +} _simd4f_uif; + +vectorial_inline simd4f simd4f_flip_sign_0101(simd4f s) { + const _simd4f_uif upnpn = { { 0x00000000, 0x80000000, 0x00000000, 0x80000000 } }; + return _mm_xor_ps( s, _mm_load_ps(upnpn.f) ); +} + +vectorial_inline simd4f simd4f_flip_sign_1010(simd4f s) { + const _simd4f_uif unpnp = { { 0x80000000, 0x00000000, 0x80000000, 0x00000000 } }; + return _mm_xor_ps( s, _mm_load_ps(unpnp.f) ); +} + +vectorial_inline simd4f simd4f_min(simd4f a, simd4f b) { + return _mm_min_ps( a, b ); +} + +vectorial_inline simd4f simd4f_max(simd4f a, simd4f b) { + return _mm_max_ps( a, b ); +} + + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/intern/mathfu/vectorial/simd4x4f.h b/intern/mathfu/vectorial/simd4x4f.h new file mode 100644 index 000000000000..78266b832ef7 --- /dev/null +++ b/intern/mathfu/vectorial/simd4x4f.h @@ -0,0 +1,412 @@ +/* + Vectorial + Copyright (c) 2010 Mikko Lehtonen + Copyright (c) 2014 Google, Inc. + Licensed under the terms of the two-clause BSD License (see LICENSE) +*/ +#ifndef VECTORIAL_SIMD4X4F_H +#define VECTORIAL_SIMD4X4F_H + + +#include "simd4f.h" + +#include + +/* + Note, x,y,z,w are conceptually columns with matrix math. +*/ + +typedef struct { + simd4f x,y,z,w; +} simd4x4f; + + + +vectorial_inline simd4x4f simd4x4f_create(simd4f x, simd4f y, simd4f z, SIMD_PARAM(simd4f, w)) { + simd4x4f s = { x, y, z, w }; + return s; +} + + +vectorial_inline void simd4x4f_identity(simd4x4f* m) { + *m = simd4x4f_create( simd4f_create(1.0f, 0.0f, 0.0f, 0.0f), + simd4f_create(0.0f, 1.0f, 0.0f, 0.0f), + simd4f_create(0.0f, 0.0f, 1.0f, 0.0f), + simd4f_create(0.0f, 0.0f, 0.0f, 1.0f)); +} + + + +vectorial_inline void simd4x4f_uload(simd4x4f* m, const float *f) { + + m->x = simd4f_uload4(f + 0); + m->y = simd4f_uload4(f + 4); + m->z = simd4f_uload4(f + 8); + m->w = simd4f_uload4(f + 12); + +} + + + + + +#ifdef VECTORIAL_SCALAR + #include "simd4x4f_scalar.h" +#elif defined(VECTORIAL_SSE) + #include "simd4x4f_sse.h" +#elif defined(VECTORIAL_GNU) + #include "simd4x4f_gnu.h" +#elif defined(VECTORIAL_NEON) + #include "simd4x4f_neon.h" +#else + #error No implementation defined +#endif + +vectorial_inline void simd4x4f_sum(const simd4x4f* a, simd4f* out) { + simd4f t; + t = simd4f_add(a->x, a->y); + t = simd4f_add(t, a->z); + t = simd4f_add(t, a->w); + *out = t; +} + +vectorial_inline void simd4x4f_matrix_vector_mul(const simd4x4f* a, const simd4f * b, simd4f* out) { + + const simd4f x = a->x; + const simd4f y = a->y; + const simd4f z = a->z; + const simd4f w = a->w; + const simd4f v = *b; + const simd4f vx = simd4f_splat_x(v); + const simd4f vy = simd4f_splat_y(v); + const simd4f vz = simd4f_splat_z(v); + const simd4f vw = simd4f_splat_w(v); + + #if 0 + // In a hasty benchmark, this actually performed worse on neon + // TODO: revisit and conditionalize accordingly + + *out = simd4f_madd(x, vx, + simd4f_madd(y, vy, + simd4f_madd(z, vz, + simd4f_mul(w, vw) ) ) ); + + #else + + *out = simd4f_add(simd4f_mul(x, vx), + simd4f_add(simd4f_mul(y, vy), + simd4f_add(simd4f_mul(z, vz), + simd4f_mul(w, vw) ) ) ); + + #endif +} + +vectorial_inline void simd4x4f_matrix_vector3_mul(const simd4x4f* a, const simd4f * b, simd4f* out) { + + #if 0 + *out = simd4f_madd( a->x, simd4f_splat_x(*b), + simd4f_madd( a->y, simd4f_splat_y(*b), + simd4f_mul(a->z, simd4f_splat_z(*b)) ) ); + #else + *out = simd4f_add( simd4f_mul(a->x, simd4f_splat_x(*b)), + simd4f_add( simd4f_mul(a->y, simd4f_splat_y(*b)), + simd4f_mul(a->z, simd4f_splat_z(*b)) ) ); + #endif + +} + +vectorial_inline void simd4x4f_matrix_point3_mul(const simd4x4f* a, const simd4f * b, simd4f* out) { + + #if 0 + *out = simd4f_madd( a->x, simd4f_splat_x(*b), + simd4f_madd( a->y, simd4f_splat_y(*b), + simd4f_madd( a->z, simd4f_splat_z(*b), + a->w ) ) ); + #else + *out = simd4f_add( simd4f_mul(a->x, simd4f_splat_x(*b)), + simd4f_add( simd4f_mul(a->y, simd4f_splat_y(*b)), + simd4f_add( simd4f_mul(a->z, simd4f_splat_z(*b)), + a->w ) ) ); + #endif + +} + +vectorial_inline void simd4x4f_inv_ortho_matrix_point3_mul(const simd4x4f* a, const simd4f * b, simd4f* out) { + simd4f translation = simd4f_sub(*b, a->w); + + simd4x4f transpose = *a; + + transpose.w = simd4f_create(0,0,0,0); + simd4x4f_transpose_inplace(&transpose); + + simd4x4f_matrix_point3_mul(&transpose, &translation, out); +} + +vectorial_inline void simd4x4f_inv_ortho_matrix_vector3_mul(const simd4x4f* a, const simd4f * b, simd4f* out) { + simd4f translation = *b; + + simd4x4f transpose = *a; + + transpose.w = simd4f_create(0,0,0,0); + simd4x4f_transpose_inplace(&transpose); + + simd4x4f_matrix_vector3_mul(&transpose, &translation, out); +} + + +vectorial_inline void simd4x4f_matrix_mul(const simd4x4f* a, const simd4x4f* b, simd4x4f* out) { + + simd4x4f_matrix_vector_mul(a, &b->x, &out->x); + simd4x4f_matrix_vector_mul(a, &b->y, &out->y); + simd4x4f_matrix_vector_mul(a, &b->z, &out->z); + simd4x4f_matrix_vector_mul(a, &b->w, &out->w); + +} + + + + +vectorial_inline void simd4x4f_perspective(simd4x4f *m, float fovy_radians, float aspect, float znear, float zfar) { + + float deltaz = zfar - znear; + float cotangent = tanf( VECTORIAL_HALFPI - fovy_radians * 0.5f ); + + float a = cotangent / aspect; + float b = cotangent; + float c = -(zfar + znear) / deltaz; + float d = -2 * znear * zfar / deltaz; + + m->x = simd4f_create( a, 0, 0, 0); + m->y = simd4f_create( 0, b, 0, 0); + m->z = simd4f_create( 0, 0, c, -1); + m->w = simd4f_create( 0, 0, d, 0); + +} + +vectorial_inline void simd4x4f_ortho(simd4x4f *m, float left, float right, float bottom, float top, float znear, float zfar) { + + float deltax = right - left; + float deltay = top - bottom; + float deltaz = zfar - znear; + + float a = 2.0f / deltax; + float b = -(right + left) / deltax; + float c = 2.0f / deltay; + float d = -(top + bottom) / deltay; + float e = -2.0f / deltaz; + float f = -(zfar + znear) / deltaz; + + m->x = simd4f_create( a, 0, 0, 0); + m->y = simd4f_create( 0, c, 0, 0); + m->z = simd4f_create( 0, 0, e, 0); + m->w = simd4f_create( b, d, f, 1); + +} + + +vectorial_inline void simd4x4f_lookat(simd4x4f *m, simd4f eye, simd4f center, simd4f up) { + + simd4f zaxis = simd4f_normalize3( simd4f_sub(center, eye) ); + simd4f xaxis = simd4f_normalize3( simd4f_cross3( zaxis, up ) ); + simd4f yaxis = simd4f_cross3(xaxis, zaxis); + + zaxis = simd4f_sub( simd4f_zero(), zaxis); + + float x = -simd4f_dot3_scalar(xaxis, eye); + float y = -simd4f_dot3_scalar(yaxis, eye); + float z = -simd4f_dot3_scalar(zaxis, eye); + + m->x = xaxis; + m->y = yaxis; + m->z = zaxis; + + m->w = simd4f_create( 0,0,0, 1); + simd4x4f_transpose_inplace(m); + m->w = simd4f_create( x,y,z,1); + +} + + +vectorial_inline void simd4x4f_translation(simd4x4f* m, float x, float y, float z) { + *m = simd4x4f_create( simd4f_create(1.0f, 0.0f, 0.0f, 0.0f), + simd4f_create(0.0f, 1.0f, 0.0f, 0.0f), + simd4f_create(0.0f, 0.0f, 1.0f, 0.0f), + simd4f_create( x, y, z, 1.0f)); +} + + +vectorial_inline void simd4x4f_axis_rotation(simd4x4f* m, float radians, simd4f axis) { + + radians = -radians; + + axis = simd4f_normalize3(axis); + + const float sine = sinf(radians); + const float cosine = cosf(radians); + + const float x = simd4f_get_x(axis); + const float y = simd4f_get_y(axis); + const float z = simd4f_get_z(axis); + + const float ab = x * y * (1 - cosine); + const float bc = y * z * (1 - cosine); + const float ca = z * x * (1 - cosine); + + const float tx = x * x; + const float ty = y * y; + const float tz = z * z; + + const simd4f i = simd4f_create( tx + cosine * (1 - tx), ab - z * sine, ca + y * sine, 0); + const simd4f j = simd4f_create( ab + z * sine, ty + cosine * (1 - ty), bc - x * sine, 0); + const simd4f k = simd4f_create( ca - y * sine, bc + x * sine, tz + cosine * (1 - tz), 0); + + *m = simd4x4f_create( i,j,k, simd4f_create(0, 0, 0, 1) ); + +} + + + +vectorial_inline void simd4x4f_add(const simd4x4f* a, const simd4x4f* b, simd4x4f* out) { + + out->x = simd4f_add(a->x, b->x); + out->y = simd4f_add(a->y, b->y); + out->z = simd4f_add(a->z, b->z); + out->w = simd4f_add(a->w, b->w); + +} + +vectorial_inline void simd4x4f_sub(const simd4x4f* a, const simd4x4f* b, simd4x4f* out) { + + out->x = simd4f_sub(a->x, b->x); + out->y = simd4f_sub(a->y, b->y); + out->z = simd4f_sub(a->z, b->z); + out->w = simd4f_sub(a->w, b->w); + +} + +vectorial_inline void simd4x4f_mul(const simd4x4f* a, const simd4x4f* b, simd4x4f* out) { + + out->x = simd4f_mul(a->x, b->x); + out->y = simd4f_mul(a->y, b->y); + out->z = simd4f_mul(a->z, b->z); + out->w = simd4f_mul(a->w, b->w); + +} + +vectorial_inline void simd4x4f_div(simd4x4f* a, simd4x4f* b, simd4x4f* out) { + + out->x = simd4f_div(a->x, b->x); + out->y = simd4f_div(a->y, b->y); + out->z = simd4f_div(a->z, b->z); + out->w = simd4f_div(a->w, b->w); + +} + +vectorial_inline simd4f simd4x4f_inverse(const simd4x4f* a, simd4x4f* out) { + + const simd4f c0 = a->x; + const simd4f c1 = a->y; + const simd4f c2 = a->z; + const simd4f c3 = a->w; + + const simd4f c0_wxyz = simd4f_shuffle_wxyz(c0); + const simd4f c0_zwxy = simd4f_shuffle_zwxy(c0); + const simd4f c0_yzwx = simd4f_shuffle_yzwx(c0); + + const simd4f c1_wxyz = simd4f_shuffle_wxyz(c1); + const simd4f c1_zwxy = simd4f_shuffle_zwxy(c1); + const simd4f c1_yzwx = simd4f_shuffle_yzwx(c1); + + const simd4f c2_wxyz = simd4f_shuffle_wxyz(c2); + const simd4f c2_zwxy = simd4f_shuffle_zwxy(c2); + const simd4f c2_yzwx = simd4f_shuffle_yzwx(c2); + + const simd4f c3_wxyz = simd4f_shuffle_wxyz(c3); + const simd4f c3_zwxy = simd4f_shuffle_zwxy(c3); + const simd4f c3_yzwx = simd4f_shuffle_yzwx(c3); + + const simd4f c0_wxyz_x_c1 = simd4f_mul(c0_wxyz, c1); + const simd4f c0_wxyz_x_c1_yzwx = simd4f_mul(c0_wxyz, c1_yzwx); + const simd4f c0_wxyz_x_c1_zwxy = simd4f_mul(c0_wxyz, c1_zwxy); + + const simd4f c2_wxyz_x_c3 = simd4f_mul(c2_wxyz, c3); + const simd4f c2_wxyz_x_c3_yzwx = simd4f_mul(c2_wxyz, c3_yzwx); + const simd4f c2_wxyz_x_c3_zwxy = simd4f_mul(c2_wxyz, c3_zwxy); + + const simd4f ar1 = simd4f_sub( simd4f_shuffle_wxyz(c2_wxyz_x_c3_zwxy), simd4f_shuffle_zwxy(c2_wxyz_x_c3) ); + const simd4f ar2 = simd4f_sub( simd4f_shuffle_zwxy(c2_wxyz_x_c3_yzwx), c2_wxyz_x_c3_yzwx ); + const simd4f ar3 = simd4f_sub( c2_wxyz_x_c3_zwxy, simd4f_shuffle_wxyz(c2_wxyz_x_c3) ); + + const simd4f br1 = simd4f_sub( simd4f_shuffle_wxyz(c0_wxyz_x_c1_zwxy), simd4f_shuffle_zwxy(c0_wxyz_x_c1) ); + const simd4f br2 = simd4f_sub( simd4f_shuffle_zwxy(c0_wxyz_x_c1_yzwx), c0_wxyz_x_c1_yzwx ); + const simd4f br3 = simd4f_sub( c0_wxyz_x_c1_zwxy, simd4f_shuffle_wxyz(c0_wxyz_x_c1) ); + + + const simd4f c0_sum = simd4f_madd(c0_yzwx, ar3, + simd4f_madd(c0_zwxy, ar2, + simd4f_mul(c0_wxyz, ar1))); + + const simd4f c1_sum = simd4f_madd(c1_wxyz, ar1, + simd4f_madd(c1_zwxy, ar2, + simd4f_mul(c1_yzwx, ar3))); + + const simd4f c2_sum = simd4f_madd(c2_yzwx, br3, + simd4f_madd(c2_zwxy, br2, + simd4f_mul(c2_wxyz, br1))); + + const simd4f c3_sum = simd4f_madd(c3_yzwx, br3, + simd4f_madd(c3_zwxy, br2, + simd4f_mul(c3_wxyz, br1))); + + + const simd4f d0 = simd4f_mul(c1_sum, c0); + const simd4f d1 = simd4f_add(d0, simd4f_merge_high(d0, d0)); + const simd4f det = simd4f_sub(d1, simd4f_splat_y(d1)); + + const simd4f invdet = simd4f_splat_x( simd4f_div(simd4f_splat(1.0f), det) ); + + const simd4f o0 = simd4f_mul( simd4f_flip_sign_0101(c1_sum), invdet ); + const simd4f o1 = simd4f_mul( simd4f_flip_sign_1010(c0_sum), invdet ); + const simd4f o2 = simd4f_mul( simd4f_flip_sign_0101(c3_sum), invdet ); + const simd4f o3 = simd4f_mul( simd4f_flip_sign_1010(c2_sum), invdet ); + + const simd4x4f mt = simd4x4f_create(o0, o1, o2, o3); + + simd4x4f_transpose( &mt, out); + + return det; +} + +#ifdef __cplusplus + + #ifdef VECTORIAL_OSTREAM + #include + + vectorial_inline std::ostream& operator<<(std::ostream& os, const simd4x4f& v) { + os << "simd4x4f(simd4f(" << simd4f_get_x(v.x) << ", " + << simd4f_get_y(v.x) << ", " + << simd4f_get_z(v.x) << ", " + << simd4f_get_w(v.x) << "),\n" + << " simd4f(" << simd4f_get_x(v.y) << ", " + << simd4f_get_y(v.y) << ", " + << simd4f_get_z(v.y) << ", " + << simd4f_get_w(v.y) << "),\n" + << " simd4f(" << simd4f_get_x(v.z) << ", " + << simd4f_get_y(v.z) << ", " + << simd4f_get_z(v.z) << ", " + << simd4f_get_w(v.z) << "),\n" + << " simd4f(" << simd4f_get_x(v.w) << ", " + << simd4f_get_y(v.w) << ", " + << simd4f_get_z(v.w) << ", " + << simd4f_get_w(v.w) << "))"; + return os; + } + #endif + +#endif + + + + + +#endif diff --git a/intern/mathfu/vectorial/simd4x4f_gnu.h b/intern/mathfu/vectorial/simd4x4f_gnu.h new file mode 100644 index 000000000000..476c9d41e48b --- /dev/null +++ b/intern/mathfu/vectorial/simd4x4f_gnu.h @@ -0,0 +1,36 @@ +/* + Vectorial + Copyright (c) 2010 Mikko Lehtonen + Licensed under the terms of the two-clause BSD License (see LICENSE) +*/ +#ifndef VECTORIAL_SIMD4X4F_GNU_H +#define VECTORIAL_SIMD4X4F_GNU_H + + + +vectorial_inline void simd4x4f_transpose_inplace(simd4x4f* s) { + const _simd4f_union sx = { s->x }; + const _simd4f_union sy = { s->y }; + const _simd4f_union sz = { s->z }; + const _simd4f_union sw = { s->w }; + + const simd4f dx = { sx.f[0], sy.f[0], sz.f[0], sw.f[0] }; + const simd4f dy = { sx.f[1], sy.f[1], sz.f[1], sw.f[1] }; + const simd4f dz = { sx.f[2], sy.f[2], sz.f[2], sw.f[2] }; + const simd4f dw = { sx.f[3], sy.f[3], sz.f[3], sw.f[3] }; + + s->x = dx; + s->y = dy; + s->z = dz; + s->w = dw; + +} + +vectorial_inline void simd4x4f_transpose(const simd4x4f *s, simd4x4f *out) { + *out=*s; + simd4x4f_transpose_inplace(out); +} + + + +#endif diff --git a/intern/mathfu/vectorial/simd4x4f_neon.h b/intern/mathfu/vectorial/simd4x4f_neon.h new file mode 100644 index 000000000000..b59537b7fbc2 --- /dev/null +++ b/intern/mathfu/vectorial/simd4x4f_neon.h @@ -0,0 +1,35 @@ +/* + Vectorial + Copyright (c) 2010 Mikko Lehtonen + Licensed under the terms of the two-clause BSD License (see LICENSE) +*/ +#ifndef VECTORIAL_SIMD4X4F_NEON_H +#define VECTORIAL_SIMD4X4F_NEON_H + + +vectorial_inline void simd4x4f_transpose_inplace(simd4x4f* s) { + const _simd4f_union sx = { s->x }; + const _simd4f_union sy = { s->y }; + const _simd4f_union sz = { s->z }; + const _simd4f_union sw = { s->w }; + + const simd4f dx = simd4f_create( sx.f[0], sy.f[0], sz.f[0], sw.f[0] ); + const simd4f dy = simd4f_create( sx.f[1], sy.f[1], sz.f[1], sw.f[1] ); + const simd4f dz = simd4f_create( sx.f[2], sy.f[2], sz.f[2], sw.f[2] ); + const simd4f dw = simd4f_create( sx.f[3], sy.f[3], sz.f[3], sw.f[3] ); + + s->x = dx; + s->y = dy; + s->z = dz; + s->w = dw; + +} + +vectorial_inline void simd4x4f_transpose(const simd4x4f *s, simd4x4f *out) { + *out=*s; + simd4x4f_transpose_inplace(out); +} + + + +#endif diff --git a/intern/mathfu/vectorial/simd4x4f_scalar.h b/intern/mathfu/vectorial/simd4x4f_scalar.h new file mode 100644 index 000000000000..66bbe2b7d358 --- /dev/null +++ b/intern/mathfu/vectorial/simd4x4f_scalar.h @@ -0,0 +1,41 @@ +/* + Vectorial + Copyright (c) 2010 Mikko Lehtonen + Licensed under the terms of the two-clause BSD License (see LICENSE) +*/ +#ifndef VECTORIAL_SIMD4X4F_SCALAR_H +#define VECTORIAL_SIMD4X4F_SCALAR_H + + +vectorial_inline void simd4x4f_transpose_inplace(simd4x4f *s) { + simd4x4f d=*s; + s->x.x = d.x.x; + s->x.y = d.y.x; + s->x.z = d.z.x; + s->x.w = d.w.x; + + s->y.x = d.x.y; + s->y.y = d.y.y; + s->y.z = d.z.y; + s->y.w = d.w.y; + + s->z.x = d.x.z; + s->z.y = d.y.z; + s->z.z = d.z.z; + s->z.w = d.w.z; + + s->w.x = d.x.w; + s->w.y = d.y.w; + s->w.z = d.z.w; + s->w.w = d.w.w; + +} + +vectorial_inline void simd4x4f_transpose(const simd4x4f *s, simd4x4f *out) { + *out=*s; + simd4x4f_transpose_inplace(out); +} + + + +#endif diff --git a/intern/mathfu/vectorial/simd4x4f_sse.h b/intern/mathfu/vectorial/simd4x4f_sse.h new file mode 100644 index 000000000000..edf632fd6441 --- /dev/null +++ b/intern/mathfu/vectorial/simd4x4f_sse.h @@ -0,0 +1,23 @@ +/* + Vectorial + Copyright (c) 2010 Mikko Lehtonen + Licensed under the terms of the two-clause BSD License (see LICENSE) +*/ +#ifndef VECTORIAL_SIMD4X4F_SSE_H +#define VECTORIAL_SIMD4X4F_SSE_H + + + +vectorial_inline void simd4x4f_transpose_inplace(simd4x4f *s) { + _MM_TRANSPOSE4_PS(s->x, s->y, s->z, s->w); +} + +vectorial_inline void simd4x4f_transpose(const simd4x4f *s, simd4x4f *out) { + *out=*s; + simd4x4f_transpose_inplace(out); +} + + + + +#endif diff --git a/intern/mathfu/vectorial/vec2f.h b/intern/mathfu/vectorial/vec2f.h new file mode 100644 index 000000000000..8eccef92f7eb --- /dev/null +++ b/intern/mathfu/vectorial/vec2f.h @@ -0,0 +1,191 @@ +/* + Vectorial + Copyright (c) 2010 Mikko Lehtonen + Licensed under the terms of the two-clause BSD License (see LICENSE) +*/ +#ifndef VECTORIAL_VEC2F_H + +#ifndef VECTORIAL_SIMD4F_H + #include "vectorial/simd4f.h" +#endif + + + +namespace vectorial { + + class vec4f; + class vec3f; + + class vec2f { + public: + + simd4f value; + + inline vec2f() {} + inline vec2f(const vec2f& v) : value(v.value) {} + inline vec2f(const simd4f& v) : value(v) {} + explicit inline vec2f(float xy) : value( simd4f_splat(xy) ) {} + inline vec2f(float x, float y) : value( simd4f_create(x,y,0,0) ) {} + explicit inline vec2f(const float *ary) : value( simd4f_uload2(ary) ) { } + + inline float x() const { return simd4f_get_x(value); } + inline float y() const { return simd4f_get_y(value); } + + inline void load(const float *ary) { value = simd4f_uload2(ary); } + inline void store(float *ary) const { simd4f_ustore2(value, ary); } + + enum { elements = 2 }; + + static vec2f zero() { return vec2f(simd4f_zero()); } + static vec2f one() { return vec2f(1.0f); } + static vec2f xAxis() { return vec2f(1.0f, 0.0f); } + static vec2f yAxis() { return vec2f(0.0f, 1.0f); } + + inline vec4f xyzw(float z, float w) const; + inline vec4f xy00() const; + inline vec4f xy01() const; + inline vec3f xyz(float z) const; + inline vec3f xy0() const; + inline vec2f xy() const; + + }; + + vectorial_inline vec2f operator-(const vec2f& lhs) { + return vec2f( simd4f_sub(simd4f_zero(), lhs.value) ); + } + + + vectorial_inline vec2f operator+(const vec2f& lhs, const vec2f& rhs) { + return vec2f( simd4f_add(lhs.value, rhs.value) ); + } + + vectorial_inline vec2f operator-(const vec2f& lhs, const vec2f& rhs) { + return vec2f( simd4f_sub(lhs.value, rhs.value) ); + } + + vectorial_inline vec2f operator*(const vec2f& lhs, const vec2f& rhs) { + return vec2f( simd4f_mul(lhs.value, rhs.value) ); + } + + vectorial_inline vec2f operator/(const vec2f& lhs, const vec2f& rhs) { + return vec2f( simd4f_div(lhs.value, rhs.value) ); + } + + + vectorial_inline vec2f operator+=(vec2f& lhs, const vec2f& rhs) { + return lhs = vec2f( simd4f_add(lhs.value, rhs.value) ); + } + + vectorial_inline vec2f operator-=(vec2f& lhs, const vec2f& rhs) { + return lhs = vec2f( simd4f_sub(lhs.value, rhs.value) ); + } + + vectorial_inline vec2f operator*=(vec2f& lhs, const vec2f& rhs) { + return lhs = vec2f( simd4f_mul(lhs.value, rhs.value) ); + } + + vectorial_inline vec2f operator/=(vec2f& lhs, const vec2f& rhs) { + return lhs = vec2f( simd4f_div(lhs.value, rhs.value) ); + } + + + + vectorial_inline vec2f operator+(const vec2f& lhs, float rhs) { + return vec2f( simd4f_add(lhs.value, simd4f_splat(rhs)) ); + } + + vectorial_inline vec2f operator-(const vec2f& lhs, float rhs) { + return vec2f( simd4f_sub(lhs.value, simd4f_splat(rhs)) ); + } + + vectorial_inline vec2f operator*(const vec2f& lhs, float rhs) { + return vec2f( simd4f_mul(lhs.value, simd4f_splat(rhs)) ); + } + + vectorial_inline vec2f operator/(const vec2f& lhs, float rhs) { + return vec2f( simd4f_div(lhs.value, simd4f_splat(rhs)) ); + } + + vectorial_inline vec2f operator+(float lhs, const vec2f& rhs) { + return vec2f( simd4f_add(simd4f_splat(lhs), rhs.value) ); + } + + vectorial_inline vec2f operator-(float lhs, const vec2f& rhs) { + return vec2f( simd4f_sub(simd4f_splat(lhs), rhs.value) ); + } + + vectorial_inline vec2f operator*(float lhs, const vec2f& rhs) { + return vec2f( simd4f_mul(simd4f_splat(lhs), rhs.value) ); + } + + vectorial_inline vec2f operator/(float lhs, const vec2f& rhs) { + return vec2f( simd4f_div(simd4f_splat(lhs), rhs.value) ); + } + + + vectorial_inline vec2f operator+=(vec2f& lhs, float rhs) { + return lhs = vec2f( simd4f_add(lhs.value, simd4f_splat(rhs)) ); + } + + vectorial_inline vec2f operator-=(vec2f& lhs, float rhs) { + return lhs = vec2f( simd4f_sub(lhs.value, simd4f_splat(rhs)) ); + } + + vectorial_inline vec2f operator*=(vec2f& lhs, float rhs) { + return lhs = vec2f( simd4f_mul(lhs.value, simd4f_splat(rhs)) ); + } + + vectorial_inline vec2f operator/=(vec2f& lhs, float rhs) { + return lhs = vec2f( simd4f_div(lhs.value, simd4f_splat(rhs)) ); + } + + + vectorial_inline float dot(const vec2f& lhs, const vec2f& rhs) { + return simd4f_get_x( simd4f_dot2(lhs.value, rhs.value) ); + } + + + vectorial_inline float length(const vec2f& v) { + return simd4f_get_x( simd4f_length2(v.value) ); + } + + vectorial_inline float length_squared(const vec2f& v) { + return simd4f_get_x( simd4f_length2_squared(v.value) ); + } + + vectorial_inline vec2f normalize(const vec2f& v) { + return vec2f( simd4f_normalize2(v.value) ); + } + + vectorial_inline vec2f min(const vec2f& a, const vec2f& b) { + return vec2f( simd4f_min(a.value, b.value) ); + } + + vectorial_inline vec2f max(const vec2f& a, const vec2f& b) { + return vec2f( simd4f_max(a.value, b.value) ); + } + + +} + + +namespace std { + inline ::vectorial::vec2f min(const ::vectorial::vec2f& a, const ::vectorial::vec2f& b) { return ::vectorial::min(a,b); } + inline ::vectorial::vec2f max(const ::vectorial::vec2f& a, const ::vectorial::vec2f& b) { return ::vectorial::max(a,b); } +} + + +#ifdef VECTORIAL_OSTREAM +#include + +vectorial_inline std::ostream& operator<<(std::ostream& os, const vectorial::vec2f& v) { + os << "[ " << v.x() << ", " + << v.y() << " ]"; + return os; +} +#endif + + + + +#endif diff --git a/intern/mathfu/vectorial/vec3f.h b/intern/mathfu/vectorial/vec3f.h new file mode 100644 index 000000000000..c52e7d592da2 --- /dev/null +++ b/intern/mathfu/vectorial/vec3f.h @@ -0,0 +1,197 @@ +/* + Vectorial + Copyright (c) 2010 Mikko Lehtonen + Copyright (c) 2014 Google, Inc. + Licensed under the terms of the two-clause BSD License (see LICENSE) +*/ +#ifndef VECTORIAL_VEC3F_H + +#ifndef VECTORIAL_SIMD4F_H + #include "vectorial/simd4f.h" +#endif + + + +namespace vectorial { + + class vec4f; + class vec2f; + + class vec3f { + public: + + simd4f value; + + inline vec3f() {} + inline vec3f(const vec3f& v) : value(v.value) {} + inline vec3f(const simd4f& v) : value(v) {} + explicit inline vec3f(float xyz) : value( simd4f_splat(xyz) ) {} + inline vec3f(float x, float y, float z) : value( simd4f_create(x,y,z,0) ) {} + explicit inline vec3f(const float *ary) : value( simd4f_uload3(ary) ) { } + + inline float x() const { return simd4f_get_x(value); } + inline float y() const { return simd4f_get_y(value); } + inline float z() const { return simd4f_get_z(value); } + + inline void load(const float *ary) { value = simd4f_uload3(ary); } + inline void store(float *ary) const { simd4f_ustore3(value, ary); } + + enum { elements = 3 }; + + static vec3f zero() { return vec3f(simd4f_zero()); } + static vec3f one() { return vec3f(1.0f); } + static vec3f xAxis() { return vec3f(1.0f, 0.0f, 0.0f); } + static vec3f yAxis() { return vec3f(0.0f, 1.0f, 0.0f); } + static vec3f zAxis() { return vec3f(0.0f, 0.0f, 1.0f); } + + inline vec4f xyz0() const; + inline vec4f xyz1() const; + inline vec4f xyzw(float w) const; + inline vec3f xyz() const; + inline vec3f xy0() const; + inline vec2f xy() const; + }; + + vectorial_inline vec3f operator-(const vec3f& lhs) { + return vec3f( simd4f_sub(simd4f_zero(), lhs.value) ); + } + + + vectorial_inline vec3f operator+(const vec3f& lhs, const vec3f& rhs) { + return vec3f( simd4f_add(lhs.value, rhs.value) ); + } + + vectorial_inline vec3f operator-(const vec3f& lhs, const vec3f& rhs) { + return vec3f( simd4f_sub(lhs.value, rhs.value) ); + } + + vectorial_inline vec3f operator*(const vec3f& lhs, const vec3f& rhs) { + return vec3f( simd4f_mul(lhs.value, rhs.value) ); + } + + vectorial_inline vec3f operator/(const vec3f& lhs, const vec3f& rhs) { + return vec3f( simd4f_div(lhs.value, rhs.value) ); + } + + + vectorial_inline vec3f operator+=(vec3f& lhs, const vec3f& rhs) { + return lhs = vec3f( simd4f_add(lhs.value, rhs.value) ); + } + + vectorial_inline vec3f operator-=(vec3f& lhs, const vec3f& rhs) { + return lhs = vec3f( simd4f_sub(lhs.value, rhs.value) ); + } + + vectorial_inline vec3f operator*=(vec3f& lhs, const vec3f& rhs) { + return lhs = vec3f( simd4f_mul(lhs.value, rhs.value) ); + } + + vectorial_inline vec3f operator/=(vec3f& lhs, const vec3f& rhs) { + return lhs = vec3f( simd4f_div(lhs.value, rhs.value) ); + } + + + + vectorial_inline vec3f operator+(const vec3f& lhs, float rhs) { + return vec3f( simd4f_add(lhs.value, simd4f_splat(rhs)) ); + } + + vectorial_inline vec3f operator-(const vec3f& lhs, float rhs) { + return vec3f( simd4f_sub(lhs.value, simd4f_splat(rhs)) ); + } + + vectorial_inline vec3f operator*(const vec3f& lhs, float rhs) { + return vec3f( simd4f_mul(lhs.value, simd4f_splat(rhs)) ); + } + + vectorial_inline vec3f operator/(const vec3f& lhs, float rhs) { + return vec3f( simd4f_div(lhs.value, simd4f_splat(rhs)) ); + } + + vectorial_inline vec3f operator+(float lhs, const vec3f& rhs) { + return vec3f( simd4f_add(simd4f_splat(lhs), rhs.value) ); + } + + vectorial_inline vec3f operator-(float lhs, const vec3f& rhs) { + return vec3f( simd4f_sub(simd4f_splat(lhs), rhs.value) ); + } + + vectorial_inline vec3f operator*(float lhs, const vec3f& rhs) { + return vec3f( simd4f_mul(simd4f_splat(lhs), rhs.value) ); + } + + vectorial_inline vec3f operator/(float lhs, const vec3f& rhs) { + return vec3f( simd4f_div(simd4f_splat(lhs), rhs.value) ); + } + + + vectorial_inline vec3f operator+=(vec3f& lhs, float rhs) { + return lhs = vec3f( simd4f_add(lhs.value, simd4f_splat(rhs)) ); + } + + vectorial_inline vec3f operator-=(vec3f& lhs, float rhs) { + return lhs = vec3f( simd4f_sub(lhs.value, simd4f_splat(rhs)) ); + } + + vectorial_inline vec3f operator*=(vec3f& lhs, float rhs) { + return lhs = vec3f( simd4f_mul(lhs.value, simd4f_splat(rhs)) ); + } + + vectorial_inline vec3f operator/=(vec3f& lhs, float rhs) { + return lhs = vec3f( simd4f_div(lhs.value, simd4f_splat(rhs)) ); + } + + + vectorial_inline float dot(const vec3f& lhs, const vec3f& rhs) { + return simd4f_dot3_scalar(lhs.value, rhs.value); + } + + vectorial_inline vec3f cross(const vec3f& lhs, const vec3f& rhs) { + return simd4f_cross3(lhs.value, rhs.value); + } + + + vectorial_inline float length(const vec3f& v) { + return simd4f_get_x( simd4f_length3(v.value) ); + } + + vectorial_inline float length_squared(const vec3f& v) { + return simd4f_get_x( simd4f_length3_squared(v.value) ); + } + + vectorial_inline vec3f normalize(const vec3f& v) { + return vec3f( simd4f_normalize3(v.value) ); + } + + vectorial_inline vec3f min(const vec3f& a, const vec3f& b) { + return vec3f( simd4f_min(a.value, b.value) ); + } + + vectorial_inline vec3f max(const vec3f& a, const vec3f& b) { + return vec3f( simd4f_max(a.value, b.value) ); + } + +} + + +namespace std { + inline ::vectorial::vec3f min(const ::vectorial::vec3f& a, const ::vectorial::vec3f& b) { return ::vectorial::min(a,b); } + inline ::vectorial::vec3f max(const ::vectorial::vec3f& a, const ::vectorial::vec3f& b) { return ::vectorial::max(a,b); } +} + + +#ifdef VECTORIAL_OSTREAM +#include + +vectorial_inline std::ostream& operator<<(std::ostream& os, const vectorial::vec3f& v) { + os << "[ " << v.x() << ", " + << v.y() << ", " + << v.z() << " ]"; + return os; +} +#endif + + + + +#endif diff --git a/intern/mathfu/vectorial/vec4f.h b/intern/mathfu/vectorial/vec4f.h new file mode 100644 index 000000000000..ecd59b05f09d --- /dev/null +++ b/intern/mathfu/vectorial/vec4f.h @@ -0,0 +1,195 @@ +/* + Vectorial + Copyright (c) 2010 Mikko Lehtonen + Licensed under the terms of the two-clause BSD License (see LICENSE) +*/ +#ifndef VECTORIAL_VEC4F_H +#define VECTORIAL_VEC4F_H + +#ifndef VECTORIAL_SIMD4F_H + #include "vectorial/simd4f.h" +#endif + + + +namespace vectorial { + + class vec3f; + class vec2f; + + class vec4f { + public: + + simd4f value; + + inline vec4f() {} + inline vec4f(const vec4f& v) : value(v.value) {} + inline vec4f(const simd4f& v) : value(v) {} + explicit inline vec4f(float xyzw) : value( simd4f_splat(xyzw) ) {} + inline vec4f(float x, float y, float z, float w) : value( simd4f_create(x,y,z,w) ) {} + explicit inline vec4f(const float *ary) : value( simd4f_uload4(ary) ) { } + + inline float x() const { return simd4f_get_x(value); } + inline float y() const { return simd4f_get_y(value); } + inline float z() const { return simd4f_get_z(value); } + inline float w() const { return simd4f_get_w(value); } + + inline void load(const float *ary) { value = simd4f_uload4(ary); } + inline void store(float *ary) const { simd4f_ustore4(value, ary); } + + enum { elements = 4 }; + + + static vec4f zero() { return vec4f(simd4f_zero()); } + static vec4f one() { return vec4f(1.0f); } + static vec4f xAxis() { return vec4f(1.0f, 0.0f, 0.0f, 0.0f); } + static vec4f yAxis() { return vec4f(0.0f, 1.0f, 0.0f, 0.0f); } + static vec4f zAxis() { return vec4f(0.0f, 0.0f, 1.0f, 0.0f); } + static vec4f wAxis() { return vec4f(0.0f, 0.0f, 0.0f, 1.0f); } + + + inline vec3f xyz() const; + inline vec2f xy() const; + + }; + + + vectorial_inline vec4f operator-(const vec4f& lhs) { + return vec4f( simd4f_sub(simd4f_zero(), lhs.value) ); + } + + + vectorial_inline vec4f operator+(const vec4f& lhs, const vec4f& rhs) { + return vec4f( simd4f_add(lhs.value, rhs.value) ); + } + + vectorial_inline vec4f operator-(const vec4f& lhs, const vec4f& rhs) { + return vec4f( simd4f_sub(lhs.value, rhs.value) ); + } + + vectorial_inline vec4f operator*(const vec4f& lhs, const vec4f& rhs) { + return vec4f( simd4f_mul(lhs.value, rhs.value) ); + } + + vectorial_inline vec4f operator/(const vec4f& lhs, const vec4f& rhs) { + return vec4f( simd4f_div(lhs.value, rhs.value) ); + } + + + vectorial_inline vec4f operator+=(vec4f& lhs, const vec4f& rhs) { + return lhs = vec4f( simd4f_add(lhs.value, rhs.value) ); + } + + vectorial_inline vec4f operator-=(vec4f& lhs, const vec4f& rhs) { + return lhs = vec4f( simd4f_sub(lhs.value, rhs.value) ); + } + + vectorial_inline vec4f operator*=(vec4f& lhs, const vec4f& rhs) { + return lhs = vec4f( simd4f_mul(lhs.value, rhs.value) ); + } + + vectorial_inline vec4f operator/=(vec4f& lhs, const vec4f& rhs) { + return lhs = vec4f( simd4f_div(lhs.value, rhs.value) ); + } + + + + vectorial_inline vec4f operator+(const vec4f& lhs, float rhs) { + return vec4f( simd4f_add(lhs.value, simd4f_splat(rhs)) ); + } + + vectorial_inline vec4f operator-(const vec4f& lhs, float rhs) { + return vec4f( simd4f_sub(lhs.value, simd4f_splat(rhs)) ); + } + + vectorial_inline vec4f operator*(const vec4f& lhs, float rhs) { + return vec4f( simd4f_mul(lhs.value, simd4f_splat(rhs)) ); + } + + vectorial_inline vec4f operator/(const vec4f& lhs, float rhs) { + return vec4f( simd4f_div(lhs.value, simd4f_splat(rhs)) ); + } + + vectorial_inline vec4f operator+(float lhs, const vec4f& rhs) { + return vec4f( simd4f_add(simd4f_splat(lhs), rhs.value) ); + } + + vectorial_inline vec4f operator-(float lhs, const vec4f& rhs) { + return vec4f( simd4f_sub(simd4f_splat(lhs), rhs.value) ); + } + + vectorial_inline vec4f operator*(float lhs, const vec4f& rhs) { + return vec4f( simd4f_mul(simd4f_splat(lhs), rhs.value) ); + } + + vectorial_inline vec4f operator/(float lhs, const vec4f& rhs) { + return vec4f( simd4f_div(simd4f_splat(lhs), rhs.value) ); + } + + + vectorial_inline vec4f operator+=(vec4f& lhs, float rhs) { + return lhs = vec4f( simd4f_add(lhs.value, simd4f_splat(rhs)) ); + } + + vectorial_inline vec4f operator-=(vec4f& lhs, float rhs) { + return lhs = vec4f( simd4f_sub(lhs.value, simd4f_splat(rhs)) ); + } + + vectorial_inline vec4f operator*=(vec4f& lhs, float rhs) { + return lhs = vec4f( simd4f_mul(lhs.value, simd4f_splat(rhs)) ); + } + + vectorial_inline vec4f operator/=(vec4f& lhs, float rhs) { + return lhs = vec4f( simd4f_div(lhs.value, simd4f_splat(rhs)) ); + } + + + vectorial_inline float dot(const vec4f& lhs, const vec4f& rhs) { + return simd4f_get_x( simd4f_dot4(lhs.value, rhs.value) ); + } + + + vectorial_inline float length(const vec4f& v) { + return simd4f_get_x( simd4f_length4(v.value) ); + } + + vectorial_inline float length_squared(const vec4f& v) { + return simd4f_get_x( simd4f_length4_squared(v.value) ); + } + + vectorial_inline vec4f normalize(const vec4f& v) { + return vec4f( simd4f_normalize4(v.value) ); + } + + vectorial_inline vec4f min(const vec4f& a, const vec4f& b) { + return vec4f( simd4f_min(a.value, b.value) ); + } + + vectorial_inline vec4f max(const vec4f& a, const vec4f& b) { + return vec4f( simd4f_max(a.value, b.value) ); + } + + +} + + +namespace std { + inline ::vectorial::vec4f min(const ::vectorial::vec4f& a, const ::vectorial::vec4f& b) { return ::vectorial::min(a,b); } + inline ::vectorial::vec4f max(const ::vectorial::vec4f& a, const ::vectorial::vec4f& b) { return ::vectorial::max(a,b); } +} + + +#ifdef VECTORIAL_OSTREAM +#include + +vectorial_inline std::ostream& operator<<(std::ostream& os, const vectorial::vec4f& v) { + os << "[ " << v.x() << ", " + << v.y() << ", " + << v.z() << ", " + << v.w() << " ]"; + return os; +} +#endif + + +#endif diff --git a/intern/mathfu/vectorial/vec_convert.h b/intern/mathfu/vectorial/vec_convert.h new file mode 100644 index 000000000000..98aac8ec20ec --- /dev/null +++ b/intern/mathfu/vectorial/vec_convert.h @@ -0,0 +1,31 @@ +/* + Vectorial + Copyright (c) 2010 Mikko Lehtonen + Licensed under the terms of the two-clause BSD License (see LICENSE) +*/ +#ifndef VECTORIAL_VEC_CONVERT_H +#define VECTORIAL_VEC_CONVERT_H + + +namespace vectorial { + + inline vec3f vec4f::xyz() const { return vec3f(value); } + inline vec2f vec4f::xy() const { return vec2f(value); } + + inline vec4f vec3f::xyz0() const { return vec4f(simd4f_zero_w(value)); } + inline vec4f vec3f::xyz1() const { return xyz0() + vec4f(0.0f, 0.0f, 0.0f, 1.0f); } + inline vec4f vec3f::xyzw(float w) const { return xyz0() + vec4f(0.0f, 0.0f, 0.0f, w); } + inline vec3f vec3f::xyz() const { return vec3f(value); } + inline vec3f vec3f::xy0() const { return vec3f(value) * vec3f(1.0f, 1.0f, 0.0f); } + inline vec2f vec3f::xy() const { return vec2f(value); } + + inline vec4f vec2f::xy00() const { return vec4f(simd4f_zero_zw(value)); } + inline vec4f vec2f::xy01() const { return xy00() + vec4f(0.0f, 0.0f, 0.0f, 1.0f); } + inline vec4f vec2f::xyzw(float z, float w) const { return xy00() + vec4f(0.0f, 0.0f, z, w); } + inline vec3f vec2f::xy0() const { return vec3f(simd4f_zero_zw(value)); } + inline vec2f vec2f::xy() const { return vec2f(value); } + +} + + +#endif diff --git a/intern/mathfu/vectorial/vectorial.h b/intern/mathfu/vectorial/vectorial.h new file mode 100644 index 000000000000..31f71b94c780 --- /dev/null +++ b/intern/mathfu/vectorial/vectorial.h @@ -0,0 +1,19 @@ +/* + Vectorial + Copyright (c) 2010 Mikko Lehtonen + Licensed under the terms of the two-clause BSD License (see LICENSE) +*/ +#ifndef VECTORIAL_VECTORIAL_H +#define VECTORIAL_VECTORIAL_H + + +#include "vectorial/vec2f.h" +#include "vectorial/vec3f.h" +#include "vectorial/vec4f.h" + +#include "vectorial/vec_convert.h" + +#include "vectorial/mat4f.h" + + +#endif diff --git a/intern/moto/CMakeLists.txt b/intern/moto/CMakeLists.txt deleted file mode 100644 index d17181c6809d..000000000000 --- a/intern/moto/CMakeLists.txt +++ /dev/null @@ -1,77 +0,0 @@ -# ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 LICENSE BLOCK ***** - -set(INC - include -) - -set(INC_SYS - -) - -set(SRC - intern/MT_Assert.cpp - intern/MT_CmMatrix4x4.cpp - intern/MT_Matrix3x3.cpp - intern/MT_Matrix4x4.cpp - intern/MT_Point3.cpp - intern/MT_Quaternion.cpp - intern/MT_Transform.cpp - intern/MT_Vector2.cpp - intern/MT_Vector3.cpp - intern/MT_Vector4.cpp - intern/MT_random.cpp - - include/MT_CmMatrix4x4.h - include/MT_Matrix3x3.h - include/MT_Matrix4x4.h - include/MT_MinMax.h - include/MT_Optimize.h - include/MT_Point2.h - include/MT_Point3.h - include/MT_Quaternion.h - include/MT_Scalar.h - include/MT_Stream.h - include/MT_Transform.h - include/MT_Tuple2.h - include/MT_Tuple3.h - include/MT_Tuple4.h - include/MT_Vector2.h - include/MT_Vector3.h - include/MT_Vector4.h - include/MT_assert.h - include/MT_random.h - - include/MT_Matrix3x3.inl - include/MT_Matrix4x4.inl - include/MT_Point2.inl - include/MT_Point3.inl - include/MT_Quaternion.inl - include/MT_Vector2.inl - include/MT_Vector3.inl - include/MT_Vector4.inl -) - -blender_add_lib(bf_intern_moto "${SRC}" "${INC}" "${INC_SYS}") diff --git a/intern/moto/include/MT_CmMatrix4x4.h b/intern/moto/include/MT_CmMatrix4x4.h deleted file mode 100644 index 53fdd41fb288..000000000000 --- a/intern/moto/include/MT_CmMatrix4x4.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/include/MT_CmMatrix4x4.h - * \ingroup moto - */ - - -#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 MT_Scalar value[4][4] - ); - - MT_CmMatrix4x4( - ); - - - MT_CmMatrix4x4( - const MT_Scalar 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 - ); - - MT_Scalar* - getPointer( - ); - - const - MT_Scalar* - getPointer( - ) const; - - void - setElem( - int pos, - MT_Scalar newvalue - ); - - MT_Vector3 - GetRight( - ) const; - - MT_Vector3 - GetUp( - ) const; - - MT_Vector3 - GetDir( - ) const; - - MT_Point3 - GetPos( - ) const; - - void - SetPos( - const MT_Vector3 & v - ); - - MT_Scalar& - 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 - { - MT_Scalar m_V[4][4]; - MT_Scalar m_Vflat[16]; - }; -}; - -#endif //MT_CmMatrix4x4 - diff --git a/intern/moto/include/MT_Matrix3x3.h b/intern/moto/include/MT_Matrix3x3.h deleted file mode 100644 index 6f965f590699..000000000000 --- a/intern/moto/include/MT_Matrix3x3.h +++ /dev/null @@ -1,276 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/include/MT_Matrix3x3.h - * \ingroup moto - */ - - -/* - - * 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 setRow(int i, const MT_Vector3& v) { - m_el[i][0] = v[0]; - m_el[i][1] = v[1]; - m_el[i][2] = 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 setValue3x3(const float *m) { - m_el[0][0] = *m++; m_el[1][0] = *m++; m_el[2][0] = *m++; - m_el[0][1] = *m++; m_el[1][1] = *m++; m_el[2][1] = *m++; - m_el[0][2] = *m++; m_el[1][2] = *m++; m_el[2][2] = *m; - } - - void setValue3x3(const double *m) { - m_el[0][0] = *m++; m_el[1][0] = *m++; m_el[2][0] = *m++; - m_el[0][1] = *m++; m_el[1][1] = *m++; m_el[2][1] = *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.0f) / 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.0f) - (yy + zz), xy - wz , xz + wy, - xy + wz , MT_Scalar(1.0f) - (xx + zz), yz - wx, - xz - wy , yz + wx, MT_Scalar(1.0f) - (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 = cosf(euler[0]); - MT_Scalar cj = cosf(euler[1]); - MT_Scalar ch = cosf(euler[2]); - MT_Scalar si = sinf(euler[0]); - MT_Scalar sj = sinf(euler[1]); - MT_Scalar sh = sinf(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 getEuler(MT_Scalar& yaw, MT_Scalar& pitch, MT_Scalar& roll) const - { - if (m_el[2][0] != -1.0f && m_el[2][0] != 1.0f) { - pitch = MT_Scalar(-asinf(m_el[2][0])); - yaw = MT_Scalar(atan2f(m_el[2][1] / cosf(pitch), m_el[2][2] / cosf(pitch))); - roll = MT_Scalar(atan2f(m_el[1][0] / cosf(pitch), m_el[0][0] / cosf(pitch))); - } - else { - roll = MT_Scalar(0); - if (m_el[2][0] == -1.0f) { - pitch = (float)MT_PI / 2.0f; - yaw = MT_Scalar(atan2f(m_el[0][1], m_el[0][2])); - } - else { - pitch = (float)-MT_PI / 2.0f; - yaw = MT_Scalar(atan2f(m_el[0][1], m_el[0][2])); - } - } - } - - 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.0f), MT_Scalar(0.0f), MT_Scalar(0.0f), - MT_Scalar(0.0f), MT_Scalar(1.0f), MT_Scalar(0.0f), - MT_Scalar(0.0f), MT_Scalar(0.0f), MT_Scalar(1.0f)); - } - - 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.0f; - *m++ = (float) m_el[0][1]; *m++ = (float) m_el[1][1]; *m++ = (float) m_el[2][1]; *m++ = (float) 0.0f; - *m++ = (float) m_el[0][2]; *m++ = (float) m_el[1][2]; *m++ = (float) m_el[2][2]; *m = (float) 0.0f; - } - - 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; - } - - void getValue3x3(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[0][1]; *m++ = (float) m_el[1][1]; *m++ = (float) m_el[2][1]; - *m++ = (float) m_el[0][2]; *m++ = (float) m_el[1][2]; *m++ = (float) m_el[2][2]; - } - - void getValue3x3(double *m) const { - *m++ = m_el[0][0]; *m++ = m_el[1][0]; *m++ = m_el[2][0]; - *m++ = m_el[0][1]; *m++ = m_el[1][1]; *m++ = m_el[2][1]; - *m++ = m_el[0][2]; *m++ = m_el[1][2]; *m++ = m_el[2][2]; - } - - 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 deleted file mode 100644 index 614e4f93a813..000000000000 --- a/intern/moto/include/MT_Matrix3x3.inl +++ /dev/null @@ -1,128 +0,0 @@ -#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.0f) - { - MT_Scalar s = sqrtf(trace + MT_Scalar(1.0f)); - result[3] = s * MT_Scalar(0.5f); - s = MT_Scalar(0.5f) / 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 = sqrtf(m_el[i][i] - m_el[j][j] - m_el[k][k] + MT_Scalar(1.0f)); - - result[i] = s * MT_Scalar(0.5f); - - s = MT_Scalar(0.5f) / 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.0f) / 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 deleted file mode 100644 index 2ecac81ea6f3..000000000000 --- a/intern/moto/include/MT_Matrix4x4.h +++ /dev/null @@ -1,262 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/include/MT_Matrix4x4.h - * \ingroup moto - */ - - -/** - - * 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.0f),MT_Scalar(0.0f),MT_Scalar(0.0f),MT_Scalar(1.0f) - ); - } - - /** - * 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; - } - - /** - * Scale the rows of this matrix with x, y, z, w respectively. - */ - void tscale(MT_Scalar x, MT_Scalar y, MT_Scalar z, MT_Scalar w) { - m_el[0][0] *= x; m_el[1][0] *= y; m_el[2][0] *= z; m_el[3][0] *= w; - m_el[0][1] *= x; m_el[1][1] *= y; m_el[2][1] *= z; m_el[3][1] *= w; - m_el[0][2] *= x; m_el[1][2] *= y; m_el[2][2] *= z; m_el[3][2] *= w; - m_el[0][3] *= x; m_el[1][3] *= y; m_el[2][3] *= 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.0f), MT_Scalar(0.0f), MT_Scalar(0.0f), MT_Scalar(0.0f), - MT_Scalar(0.0f), MT_Scalar(1.0f), MT_Scalar(0.0f), MT_Scalar(0.0f), - MT_Scalar(0.0f), MT_Scalar(0.0f), MT_Scalar(1.0f), MT_Scalar(0.0f), - MT_Scalar(0.0f), MT_Scalar(0.0f), MT_Scalar(0.0f), MT_Scalar(1.0f)); - } - - /** - * 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(); - - MT_Matrix4x4 inverse() const; - 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 deleted file mode 100644 index fb72af1f9bf2..000000000000 --- a/intern/moto/include/MT_Matrix4x4.inl +++ /dev/null @@ -1,108 +0,0 @@ -#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.0f; - 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.0f; - 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.0f; - if ( i != j ) { - x = 0.0f; - 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.0f; - for (k = i; k < j; k++ ) - sum += m_el[k][j]*( (i==k) ? 1.0f : 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.0f; - for (k = ((i>j)?i:j); k < 4; k++ ) - sum += ((j==k)?1.0f:m_el[j][k])*m_el[k][i]; - m_el[j][i] = sum; - } -} - -GEN_INLINE MT_Matrix4x4 MT_Matrix4x4::inverse() const -{ - MT_Matrix4x4 invmat = *this; - - invmat.invert(); - - return invmat; -} - -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 deleted file mode 100644 index 42e689f45a43..000000000000 --- a/intern/moto/include/MT_MinMax.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/include/MT_MinMax.h - * \ingroup moto - */ - - -/* - - * 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 deleted file mode 100644 index e16bab1ecf97..000000000000 --- a/intern/moto/include/MT_Optimize.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/include/MT_Optimize.h - * \ingroup moto - */ - - -#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_Point2.h b/intern/moto/include/MT_Point2.h deleted file mode 100644 index 587379b21f48..000000000000 --- a/intern/moto/include/MT_Point2.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/include/MT_Point2.h - * \ingroup moto - */ - - -/* - - * 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 deleted file mode 100644 index ec09a3260e23..000000000000 --- a/intern/moto/include/MT_Point2.inl +++ /dev/null @@ -1,54 +0,0 @@ -#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 deleted file mode 100644 index f19b2e2f324d..000000000000 --- a/intern/moto/include/MT_Point3.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/include/MT_Point3.h - * \ingroup moto - */ - - -/* - - * 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 deleted file mode 100644 index 081a81956945..000000000000 --- a/intern/moto/include/MT_Point3.inl +++ /dev/null @@ -1,59 +0,0 @@ -#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 deleted file mode 100644 index 6aabb1f2ed47..000000000000 --- a/intern/moto/include/MT_Quaternion.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/include/MT_Quaternion.h - * \ingroup moto - */ - - -/* - - * 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 = sinf(mt_angle * MT_Scalar(0.5f)) / d; - setValue(axis[0] * s, axis[1] * s, axis[2] * s, - cosf(mt_angle * MT_Scalar(0.5f))); - } - - void setEuler(MT_Scalar yaw, MT_Scalar pitch, MT_Scalar roll) { - MT_Scalar cosYaw = cosf(yaw * MT_Scalar(0.5f)); - MT_Scalar sinYaw = sinf(yaw * MT_Scalar(0.5f)); - MT_Scalar cosPitch = cosf(pitch * MT_Scalar(0.5f)); - MT_Scalar sinPitch = sinf(pitch * MT_Scalar(0.5f)); - MT_Scalar cosRoll = cosf(roll * MT_Scalar(0.5f)); - MT_Scalar sinRoll = sinf(roll * MT_Scalar(0.5f)); - 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 deleted file mode 100644 index 8fe71b7b2148..000000000000 --- a/intern/moto/include/MT_Quaternion.inl +++ /dev/null @@ -1,100 +0,0 @@ -#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 = sqrtf(MT_Scalar(1.0f) - x0), r2 = sqrtf(x0); - MT_Scalar t1 = (float)MT_2_PI * MT_random(), t2 = (float)MT_2_PI * MT_random(); - MT_Scalar c1 = cosf(t1), s1 = sinf(t1); - MT_Scalar c2 = cosf(t2), s2 = sinf(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 = sqrtf(length2() * q.length2()); - assert(s != MT_Scalar(0.0f)); - - s = dot(q) / s; - - s = MT_clamp(s, -1.0f, 1.0f); - - return acosf(s); -} - -GEN_INLINE MT_Quaternion MT_Quaternion::slerp(const MT_Quaternion& q, const MT_Scalar& t) const -{ - MT_Scalar d, s0, s1; - MT_Scalar s = dot(q); - bool neg = (s < 0.0f); - - if (neg) - s = -s; - if ((1.0f - s) > 0.0001f) - { - MT_Scalar theta = acosf(s); - d = MT_Scalar(1.0f) / sinf(theta); - s0 = sinf((MT_Scalar(1.0f) - t) * theta); - s1 = sinf(t * theta); - } - else - { - d = MT_Scalar(1.0f); - s0 = MT_Scalar(1.0f) - t; - s1 = t; - } - if (neg) - s1 = -s1; - return d*(*this * s0 + q * s1); -} - diff --git a/intern/moto/include/MT_Scalar.h b/intern/moto/include/MT_Scalar.h deleted file mode 100644 index 94723f4d7ec8..000000000000 --- a/intern/moto/include/MT_Scalar.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/include/MT_Scalar.h - * \ingroup moto - */ - - -/* - - * 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" - -typedef float MT_Scalar; - - -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.0e38); - -inline int MT_sign(MT_Scalar x) { - return x < 0.0f ? -1 : x > 0.0f ? 1 : 0; -} - -inline MT_Scalar MT_abs(MT_Scalar x) { return fabs(x); } - -inline bool MT_fuzzyZero(MT_Scalar x) { return MT_abs(x) < (float)MT_EPSILON; } -inline bool MT_fuzzyZero2(MT_Scalar x) { return MT_abs(x) < (float)MT_EPSILON2; } - -inline MT_Scalar MT_radians(MT_Scalar x) { - return x * (float)MT_RADS_PER_DEG; -} - -inline MT_Scalar MT_degrees(MT_Scalar x) { - return x * (float)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_Transform.h b/intern/moto/include/MT_Transform.h deleted file mode 100644 index 9c23482925cd..000000000000 --- a/intern/moto/include/MT_Transform.h +++ /dev/null @@ -1,190 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/include/MT_Transform.h - * \ingroup moto - */ - - -/* - - 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 deleted file mode 100644 index 465b31a67811..000000000000 --- a/intern/moto/include/MT_Tuple2.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/include/MT_Tuple2.h - * \ingroup moto - */ - - -/* - - * 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 deleted file mode 100644 index ddd8ed724ca1..000000000000 --- a/intern/moto/include/MT_Tuple3.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/include/MT_Tuple3.h - * \ingroup moto - */ - - -/* - - * 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 deleted file mode 100644 index aa3b60f1c9b8..000000000000 --- a/intern/moto/include/MT_Tuple4.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/include/MT_Tuple4.h - * \ingroup moto - */ - - -/* - - * 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 deleted file mode 100644 index 8b8f2478ce39..000000000000 --- a/intern/moto/include/MT_Vector2.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/include/MT_Vector2.h - * \ingroup moto - */ - - -/* - - * 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 deleted file mode 100644 index ed16025e7339..000000000000 --- a/intern/moto/include/MT_Vector2.inl +++ /dev/null @@ -1,89 +0,0 @@ -#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.0f / 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.0f / 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 sqrtf(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 = sqrtf(length2() * vv.length2()); - MT_assert(!MT_fuzzyZero(s)); - return acosf(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 deleted file mode 100644 index 545ca1fad0bb..000000000000 --- a/intern/moto/include/MT_Vector3.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/include/MT_Vector3.h - * \ingroup moto - */ - - -/* - - * 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: - 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; - MT_Vector3 safe_normalized_vec(MT_Vector3 vecnormalized) 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 deleted file mode 100644 index 7994bf7c55c7..000000000000 --- a/intern/moto/include/MT_Vector3.inl +++ /dev/null @@ -1,141 +0,0 @@ -#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.0f) / 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.0f) / 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 sqrtf(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.0f), MT_Scalar(0.0f), MT_Scalar(0.0f)); - } -} - -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.0f), MT_Scalar(0.0f), MT_Scalar(0.0f)) : - *this / len; -} - -GEN_INLINE MT_Vector3 MT_Vector3::safe_normalized_vec(MT_Vector3 vecnormalized) const { - MT_Scalar len = length(); - return MT_fuzzyZero(len) ? - vecnormalized : - *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 = sqrtf(length2() * v.length2()); - MT_assert(!MT_fuzzyZero(s)); - return acosf(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.0f) * MT_random() - MT_Scalar(1.0f); - MT_Scalar r = sqrtf(MT_Scalar(1.0f) - z * z); - MT_Scalar t = (float)MT_2_PI * MT_random(); - return MT_Vector3(r * cosf(t), r * sinf(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 deleted file mode 100644 index 440bf9b84f13..000000000000 --- a/intern/moto/include/MT_Vector4.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/include/MT_Vector4.h - * \ingroup moto - */ - - -/* - - * 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: - 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 deleted file mode 100644 index 5b6e6766416f..000000000000 --- a/intern/moto/include/MT_Vector4.inl +++ /dev/null @@ -1,80 +0,0 @@ -#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.0f) / 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.0f) / 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 sqrtf(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 deleted file mode 100644 index 256397036de6..000000000000 --- a/intern/moto/include/MT_assert.h +++ /dev/null @@ -1,103 +0,0 @@ -/* -* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -* -* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. -* All rights reserved. -* -* The Original Code is: all of this file. -* -* Contributor(s): none yet. -* -* ***** END GPL LICENSE BLOCK ***** -*/ - -/** \file moto/include/MT_assert.h - * \ingroup moto - */ - - -#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); - - -#if !defined(DEBUG) -#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 /* !defined(DEBUG) */ - -#endif - diff --git a/intern/moto/intern/MT_Assert.cpp b/intern/moto/intern/MT_Assert.cpp deleted file mode 100644 index 9279b70afec0..000000000000 --- a/intern/moto/intern/MT_Assert.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/intern/MT_Assert.cpp - * \ingroup moto - */ - - -#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 deleted file mode 100644 index 38c93b92761b..000000000000 --- a/intern/moto/intern/MT_CmMatrix4x4.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/intern/MT_CmMatrix4x4.cpp - * \ingroup moto - */ - - -#include "MT_CmMatrix4x4.h" -#include "MT_Vector3.h" -#include "MT_Point3.h" - - -MT_CmMatrix4x4::MT_CmMatrix4x4() -{ - Identity(); -} - - - -MT_CmMatrix4x4::MT_CmMatrix4x4(const MT_Scalar 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 MT_Scalar 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]; -} - - - -MT_Scalar* MT_CmMatrix4x4::getPointer() -{ - return &m_V[0][0]; -} - - - -const MT_Scalar* MT_CmMatrix4x4::getPointer() const -{ - return &m_V[0][0]; -} - - - -void MT_CmMatrix4x4::setElem(int pos,MT_Scalar 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.0f*inNear) / (inRight-inLeft); - mat(1, 0) = 0.0f; - mat(2, 0) = 0.0f; - mat(3, 0) = 0.0f; - - // Column 1 - mat(0, 1) = 0.0f; - mat(1, 1) = (2.0f*inNear) / (inTop-inBottom); - mat(2, 1) = 0.0f; - mat(3, 1) = 0.0f; - - // 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.0f; - - // Column 3 - mat(0, 3) = 0.0f; - mat(1, 3) = 0.0f; - mat(2, 3) = -(2.0f*inFar*inNear) / (inFar-inNear); - mat(3, 3) = 0.0f; - - return mat; -} diff --git a/intern/moto/intern/MT_Matrix4x4.cpp b/intern/moto/intern/MT_Matrix4x4.cpp deleted file mode 100644 index 41d495382129..000000000000 --- a/intern/moto/intern/MT_Matrix4x4.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/intern/MT_Matrix4x4.cpp - * \ingroup moto - */ - - -#include "MT_Matrix4x4.h" - - -#ifndef GEN_INLINED -#include "MT_Matrix4x4.inl" -#endif diff --git a/intern/moto/intern/MT_Quaternion.cpp b/intern/moto/intern/MT_Quaternion.cpp deleted file mode 100644 index a2b634fced52..000000000000 --- a/intern/moto/intern/MT_Quaternion.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/intern/MT_Quaternion.cpp - * \ingroup moto - */ - - -#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 deleted file mode 100644 index 49a75b78e46e..000000000000 --- a/intern/moto/intern/MT_Transform.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/intern/MT_Transform.cpp - * \ingroup moto - */ - - -/* - - 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. - -*/ - -#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.0f; -} - -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.0f), MT_Scalar(0.0f), MT_Scalar(0.0f)); - 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 deleted file mode 100644 index 3c0b0a08f1f9..000000000000 --- a/intern/moto/intern/MT_Vector2.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/intern/MT_Vector2.cpp - * \ingroup moto - */ - - -#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 deleted file mode 100644 index a90551dd0a87..000000000000 --- a/intern/moto/intern/MT_Vector3.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/intern/MT_Vector3.cpp - * \ingroup moto - */ - - -#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 deleted file mode 100644 index b41ec03754d6..000000000000 --- a/intern/moto/intern/MT_Vector4.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/intern/MT_Vector4.cpp - * \ingroup moto - */ - - -#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 deleted file mode 100644 index ab191008d286..000000000000 --- a/intern/moto/intern/MT_random.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file moto/intern/MT_random.cpp - * \ingroup moto - */ - - -/* 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., 51 Franklin Street, Fifth Floor, Boston, MA */ -/* 02110-1301, 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. */ - -#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 int 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 int 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 int MT_rand() -{ - static unsigned int mag01[2] = { 0x0, MATRIX_A }; - /* mag01[x] = x * MATRIX_A for x=0,1 */ - - unsigned int 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/container/CMakeLists.txt b/intern/spindle/CMakeLists.txt similarity index 73% rename from intern/container/CMakeLists.txt rename to intern/spindle/CMakeLists.txt index 4743247af26b..fda814fdd874 100644 --- a/intern/container/CMakeLists.txt +++ b/intern/spindle/CMakeLists.txt @@ -14,18 +14,10 @@ # along with this program; if not, write to the Free Software Foundation, # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 LICENSE BLOCK ***** set(INC . - ../guardedalloc ) set(INC_SYS @@ -33,9 +25,10 @@ set(INC_SYS ) set(SRC - CTR_HashedPtr.h - CTR_Map.h + SpindleEncryption.cpp + + SpindleEncryption.h ) -# infact nothing to compile! -blender_add_lib(bf_intern_ctr "${SRC}" "${INC}" "${INC_SYS}") + +blender_add_lib(bf_intern_spindle "${SRC}" "${INC}" "${INC_SYS}") diff --git a/intern/spindle/SpindleEncryption.cpp b/intern/spindle/SpindleEncryption.cpp new file mode 100644 index 000000000000..f2d34f3cba2d --- /dev/null +++ b/intern/spindle/SpindleEncryption.cpp @@ -0,0 +1,416 @@ +/** + * ***** BEGIN MIT LICENSE BLOCK ***** + * Copyright (C) 2011-2017 by DeltaSpeeds + * All rights reserved. + * + * 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. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END MIT LICENSE BLOCK ***** + */ + +#include "SpindleEncryption.h" +#include +#include +#include +#include + +char *staticKey = NULL; +char *dynamicKey = NULL; +std::string filePath; +const unsigned int currentSupportedVersion = 0; + +// Static functions declaration +// Encryption & Decryption +static void spindle_encrypt(char *data, int dataSize, const unsigned long long key); +static void spindle_decrypt(char *data, int dataSize, const unsigned long long key); +static void spindle_encrypt_hex_64(char *data, int dataSize, const char *key); +static void spindle_decrypt_hex_64(char *data, int dataSize, const char *key); +static void spindle_encrypt_hex(char *data, int dataSize, const char *key); +static void spindle_decrypt_hex(char *data, int dataSize, const char *key); +// Encryption keys +static void spindle_set_static_encryption_key(const char *hexKey); +static void spindle_set_dynamic_encryption_key(const char *hexKey); +// Secure functions +// We want to define these functions ourselves since some platforms will always dynamically link against +// libc even if we build a static executable (ex: Linux) +static void spindle_secure_function_memcpy(void *dest, void *src, int size); +static void spindle_secure_function_memset(void *dest, char value, int size); +static int spindle_secure_function_strlen(const char *str); + + +std::string SPINDLE_FindAndSetEncryptionKeys(char **argv, int i) +{ + /* Find main key */ + int hexStrSize = 0, argPos = 2, maxStringLen = int(strlen(argv[i])); + + for (hexStrSize = 0; ((argv[i][hexStrSize + argPos] != 0) && (argv[i][hexStrSize + argPos] != '.')); hexStrSize++){} + + char *hexKey = new char[hexStrSize + 1]; + spindle_secure_function_memcpy((char *)hexKey, (char *)&(argv[i][argPos]), hexStrSize); + spindle_secure_function_memset((char *)&(argv[i][argPos]), 0, hexStrSize); + hexKey[hexStrSize] = 0; + argPos += hexStrSize + 1; + + /* Find static key */ + if (argPos < maxStringLen) { + for (hexStrSize = 0; ((argv[i][hexStrSize + argPos] != 0) && (argv[i][hexStrSize + argPos] != '.')); hexStrSize++){} + + if (hexStrSize > 0) { + char *statKey = new char[hexStrSize + 1]; + spindle_secure_function_memcpy((char *)statKey, (char *)&(argv[i][argPos]), hexStrSize); + spindle_secure_function_memset((char *)&(argv[i][argPos]), 0, hexStrSize); + statKey[hexStrSize] = 0; + argPos += hexStrSize + 1; + spindle_set_static_encryption_key(statKey); + memset((char *)statKey, 0, hexStrSize); + delete [] statKey; + } + } + + /* Find dynamic key */ + if (argPos < maxStringLen) { + for (hexStrSize = 0; ((argv[i][hexStrSize + argPos] != 0) && (argv[i][hexStrSize + argPos] != '.')); hexStrSize++){} + + if (hexStrSize > 0) { + char *dynaKey = new char[hexStrSize + 1]; + spindle_secure_function_memcpy((char *)dynaKey, (char *)&(argv[i][argPos]), hexStrSize); + spindle_secure_function_memset((char *)&(argv[i][argPos]), 0, hexStrSize); + dynaKey[hexStrSize] = 0; + argPos += hexStrSize + 1; + spindle_set_dynamic_encryption_key(dynaKey); + memset((char *)dynaKey, 0, hexStrSize); + delete [] dynaKey; + } + } + return hexKey; +} + +char *SPINDLE_DecryptFromFile(const char *filename, int *fileSize, const char *encryptKey, int typeEncryption) +{ + std::ifstream inFile(filename, std::ios::in | std::ios::binary | std::ios::ate); + *fileSize = (int)inFile.tellg(); + if (*fileSize <= 10) + return NULL; + + if (encryptKey) { + inFile.seekg(0, std::ios::beg); + char *fileData = new char[*fileSize]; + inFile.read(fileData, *fileSize); + inFile.close(); + if ((fileData[0] != 'B')||(fileData[1] != 'L')||(fileData[2] != 'E')||(fileData[3] != 'N')||(fileData[4] != 'D')) { + spindle_decrypt_hex(fileData, *fileSize, encryptKey); + return fileData; + } + delete[] fileData; + return NULL; + } + else { + if (typeEncryption == SPINDLE_NO_ENCRYPTION) { + inFile.seekg(0, std::ios::beg); + char *fileData = new char[*fileSize]; + inFile.read(fileData, *fileSize); + inFile.close(); + return fileData; + } + else if (typeEncryption == SPINDLE_STATIC_ENCRYPTION) { + inFile.seekg(5, std::ios::beg); + *fileSize -= 5; + char *fileData = new char[*fileSize]; + inFile.read(fileData, *fileSize); + inFile.close(); + spindle_decrypt_hex(fileData, *fileSize, staticKey); + return fileData; + } + else if (typeEncryption == SPINDLE_DYNAMIC_ENCRYPTION) { + inFile.seekg(5, std::ios::beg); + *fileSize -= 5; + char *fileData = new char[*fileSize]; + inFile.read(fileData, *fileSize); + inFile.close(); + spindle_decrypt_hex(fileData, *fileSize, dynamicKey); + return fileData; + } + else { + return NULL; + } + } +} + +int SPINDLE_CheckEncryptionFromFile(const char *filepath) +{ + int keyType = SPINDLE_NO_ENCRYPTION; // -1 = invalid, 0 = blend, 1 = static key, 2 = dynamic key + std::ifstream inFile(filepath, std::ios::in | std::ios::binary | std::ios::ate); + int fileSize = (int)inFile.tellg(); + char *fileData = new char[5]; + + if (fileSize < 5) { + inFile.close(); + return -1; + } + + inFile.seekg(0, std::ios::beg); + inFile.read(fileData, 5); + + if ((fileData[0] == 'S') && (fileData[1] == 'T') && (fileData[2] == 'C')) { //Static encrypted file + if ((unsigned int)fileData[3] > currentSupportedVersion) { + inFile.close(); + std::cout << "Failed to read blend file: " << filepath << ", blend is from a newer version" << std::endl; + return -1; + } + if (staticKey == NULL) { + inFile.close(); + std::cout << "Failed to read blend file: " << filepath << ", No static key provided" << std::endl; + return -1; + } + keyType = SPINDLE_STATIC_ENCRYPTION; + } + else if ((fileData[0] == 'D') && (fileData[1] == 'Y') && (fileData[2] == 'C')) { //Dynamic encrypted file + if ((unsigned int)fileData[3] > currentSupportedVersion) { + inFile.close(); + std::cout << "Failed to read blend file: " << filepath << ", blend is from a newer version" << std::endl; + return -1; + } + if (dynamicKey == NULL) { + inFile.close(); + std::cout << "Failed to read blend file: " << filepath << ", No dynamic key provided" << std::endl; + return -1; + } + keyType = SPINDLE_DYNAMIC_ENCRYPTION; + } + inFile.close(); + + return keyType; +} + +void SPINDLE_SetFilePath(std::string path) +{ + filePath = path; +} + +void SPINDLE_SetFilePath(const char *filepath) +{ + std::string temp(filepath); + filePath = temp; +} + +const char *SPINDLE_GetFilePath() +{ + return filePath.c_str(); +} + +static void spindle_encrypt(char *data, int dataSize, const unsigned long long key) +{ + const int keySize = sizeof(key) * 8; + unsigned long long pieceSize, offset, end, chunkSize = 0, max = ((unsigned long long)(dataSize) << 3); + unsigned int p, t, ii; + long long i; + int iii; + char h; + + for (iii = 0; iii < (keySize >> 4); iii++) { + p = iii * 16; + pieceSize = (((key >> p) % (1 << 8)) + 3) * (dataSize / 256 / 400 + 1); + offset = ((key >> (p + 8)) % (1 << 8)); + if (offset == 0) { + offset++; + } + //cout << "(Encrypt) pieceSize: " << pieceSize << " offset: " << offset << " " << p << "\n"; + end = ((unsigned long long)(dataSize) << 3) - (((unsigned long long)(dataSize) << 3) % pieceSize) - pieceSize * ((int)((((unsigned long long)(dataSize) << 3) % pieceSize) == 0)); + for (i = end; i >= 0; i -= pieceSize) { + chunkSize = pieceSize; + if (i + chunkSize >= max ) { + chunkSize = ((unsigned long long)(dataSize) << 3) - i; + } + //cout << " N: " << i << " " << i + chunkSize << "\n"; + t = (unsigned int)((unsigned long long)(i + chunkSize) >> 3); + ii = (unsigned int)(i >> 3); + h = ((char)offset) * ((char)i) + ((char)i) - ((char)(pieceSize&i)) + (((char)(offset))|((char)(i))) + ((((char)(iii))|pieceSize)&255); + while (ii < t) { + data[ii] += h + (((char)offset) | ((char)ii)); + ii++; + } + } + } +} + +static void spindle_decrypt(char *data, int dataSize, const unsigned long long key) +{ + const int keySize = sizeof(key) * 8; + unsigned long long pieceSize, offset, chunkSize = 0, max = ((unsigned long long)(dataSize) << 3); + unsigned int p, t, ii; + unsigned long long i; + int iii; + char h; + + for (iii = (keySize >> 4) - 1; iii >= 0; iii--) { + p = iii * 16; + pieceSize = (((key >> p) % (1 << 8)) + 3) * (dataSize / 256 / 400 + 1); + offset = ((key >> (p + 8)) % (1 << 8)); + if (offset == 0) { + offset++; + } + chunkSize = pieceSize; + //cout << "(Decrypt) pieceSize: " << pieceSize << " offset: " << offset << " " << p << "\n"; + for (i = 0; i < max; i += chunkSize) { + if (i + chunkSize >= max ) { + chunkSize = (((unsigned long long)(dataSize)) << 3) - i; + } + //cout << " N: " << i << " " << i + chunkSize << "\n"; + t = (unsigned int)(((unsigned long long)(i + chunkSize)) >> 3); + ii = (unsigned int)(i >> 3); + h = ((char)offset) * ((char)i) + ((char)i) - ((char)(pieceSize&i)) + (((char)(offset)) | ((char)(i))) + ((((char)(iii)) | pieceSize)&255); + while (ii < t) { + data[ii] -= h + (((char)offset) | ((char)ii)); + ii++; + } + } + chunkSize = pieceSize; + } +} + +static void spindle_encrypt_hex_64(char *data, int dataSize, const char *key) +{ + int keySize = 0, i; + unsigned long long realKey = 0, s; + if (key == NULL) + return; + keySize = spindle_secure_function_strlen(key); + for (i = 0; i < keySize; i++) { + s = keySize - 1 - i; + if ((key[i] >= '0') && (key[i] <= '9')) + realKey += ((unsigned long long)(key[i] - '0') << (s << 2)); + else if ((key[i] >= 'a') && (key[i] <= 'f')) + realKey += ((unsigned long long)(key[i] - 'a' + 10) << (s << 2)); + else if ((key[i] >= 'A') && (key[i] <= 'F')) + realKey += ((unsigned long long)(key[i] - 'A' + 10) << (s << 2)); + else + realKey += ((unsigned long long)(key[i]) << (s << 2)); + } + spindle_encrypt(data, dataSize, realKey); +} + +static void spindle_decrypt_hex_64(char *data, int dataSize, const char *key) +{ + int keySize = 0, i; + unsigned long long realKey = 0, s; + if (key == NULL) + return; + keySize = spindle_secure_function_strlen(key); + for (i = 0; i < keySize; i++) { + s = keySize - 1 - i; + if ((key[i] >= '0') && (key[i] <= '9')) + realKey += ((unsigned long long)(key[i] - '0') << (s << 2)); + else if ((key[i] >= 'a') && (key[i] <= 'f')) + realKey += ((unsigned long long)(key[i] - 'a' + 10) << (s << 2)); + else if ((key[i] >= 'A') && (key[i] <= 'F')) + realKey += ((unsigned long long)(key[i] - 'A' + 10) << (s << 2)); + else + realKey += ((unsigned long long)(key[i]) << (s << 2)); + } + spindle_decrypt(data, dataSize, realKey); +} + +static void spindle_encrypt_hex(char *data, int dataSize, const char *key) +{ + int keySize = 0, charPos, i; + if (key == NULL) + return; + keySize = spindle_secure_function_strlen(key); + charPos = keySize - (keySize % 16); + if (keySize == charPos) + charPos -= 16; + if (keySize <= 16) { + spindle_encrypt_hex_64(data, dataSize, key); + } + else { + char tempKey[17]; + tempKey[16] = 0; + while (charPos >= 0) { + for (i = 0; ((i < 16) && (i < keySize)); i++) { + tempKey[i] = key[i + charPos]; + } + charPos -= 16; + spindle_encrypt_hex_64(data, dataSize, tempKey); + } + } +} + +static void spindle_decrypt_hex(char *data, int dataSize, const char *key) +{ + int keySize = 0, charPos = 0, i; + if (key == NULL) + return; + keySize = spindle_secure_function_strlen(key); + if (keySize <= 16) { + spindle_decrypt_hex_64(data, dataSize, key); + } + else { + char tempKey[17]; + tempKey[16] = 0; + while (charPos < keySize) { + for (i = 0; ((i < 16) && (i < keySize)); i++) { + tempKey[i] = key[i + charPos]; + } + charPos += 16; + spindle_decrypt_hex_64(data, dataSize, tempKey); + } + } +} + +static void spindle_set_static_encryption_key(const char *hexKey) +{ + if (staticKey != NULL) + free(staticKey); + staticKey = (char *)malloc((int)strlen(hexKey) + 1); + strcpy(staticKey, hexKey); +} + +static void spindle_set_dynamic_encryption_key(const char *hexKey) +{ + if (dynamicKey != NULL) + free(dynamicKey); + dynamicKey = (char *)malloc((int)strlen(hexKey) + 1); + strcpy(dynamicKey, hexKey); +} + +static void spindle_secure_function_memcpy(void *dest, void *src, int size) +{ + for (int i = 0; i < size; i++) + ((char *)dest)[i] = ((char *)src)[i]; +} + +static void spindle_secure_function_memset(void *dest, char value, int size) +{ + for (int i = 0; i < size; i++) + ((char *)dest)[i] = value; +} + +static int spindle_secure_function_strlen(const char *str) +{ + int val = 0; + if (str == NULL) + return 0; + while (str[val] != 0) + val++; + return val; +} diff --git a/intern/spindle/SpindleEncryption.h b/intern/spindle/SpindleEncryption.h new file mode 100644 index 000000000000..3389e88526d2 --- /dev/null +++ b/intern/spindle/SpindleEncryption.h @@ -0,0 +1,56 @@ +/** + * ***** BEGIN MIT LICENSE BLOCK ***** + * Copyright (C) 2011-2012 by DeltaSpeeds + * All rights reserved. + * + * 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. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END MIT LICENSE BLOCK ***** + */ + +#ifndef __SPINDLEENCRYPTION_H__ +#define __SPINDLEENCRYPTION_H__ + + +#define SPINDLE_NO_ENCRYPTION 0 +#define SPINDLE_STATIC_ENCRYPTION 1 +#define SPINDLE_DYNAMIC_ENCRYPTION 2 + + +#ifdef __cplusplus +#include +std::string SPINDLE_FindAndSetEncryptionKeys(char **argv, int i); +void SPINDLE_SetFilePath(std::string path); + +extern "C" { +#endif +char *SPINDLE_DecryptFromFile(const char *filename, int *fileSize, const char *encryptKey, int typeEncryption); +int SPINDLE_CheckEncryptionFromFile(const char *filepath); +void SPINDLE_SetFilePath(const char *filepath); +const char *SPINDLE_GetFilePath(void); + +#ifdef __cplusplus +} +#endif + +#endif // __SPINDLEENCRYPTION_H__ diff --git a/intern/string/STR_String.h b/intern/string/STR_String.h index 4607db45c7c6..2053163db03a 100644 --- a/intern/string/STR_String.h +++ b/intern/string/STR_String.h @@ -46,6 +46,7 @@ #endif #include +#include // Compatibility #include #include @@ -81,6 +82,7 @@ class STR_String 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); + STR_String(const std::string& s); // Compatibility explicit STR_String(int val); explicit STR_String(dword val); explicit STR_String(float val); diff --git a/intern/string/intern/STR_String.cpp b/intern/string/intern/STR_String.cpp index 3ec65ddc725d..863d4c353518 100644 --- a/intern/string/intern/STR_String.cpp +++ b/intern/string/intern/STR_String.cpp @@ -172,7 +172,15 @@ STR_String::STR_String(const char *src1, int len1, const char *src2, int len2) : this->m_data[len1 + len2] = 0; } - +STR_String::STR_String(const std::string& s) : + m_data(new char[s.size() + 8]), + m_len(s.size()), + m_max(s.size() + 8) +{ + assertd(this->m_data != NULL); + memcpy(this->m_data, s.c_str(), s.size()); + this->m_data[s.size()] = 0; +} // // Create a string with an integer value diff --git a/intern/termcolor/LICENSE b/intern/termcolor/LICENSE new file mode 100644 index 000000000000..0905ac6b0910 --- /dev/null +++ b/intern/termcolor/LICENSE @@ -0,0 +1,31 @@ +Copyright (c) 2013 by Igor Kalnitsky. +All rights reserved. + +Redistribution and use in source and binary forms of the software as well +as documentation, 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. + +* The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE AND DOCUMENTATION 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 AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. diff --git a/intern/termcolor/README b/intern/termcolor/README new file mode 100644 index 000000000000..b042d13dc458 --- /dev/null +++ b/intern/termcolor/README @@ -0,0 +1,42 @@ + // termcolor // + + a library for printing colored messages + + by Igor Kalnitsky + + + ~ What is termcolor? + + Termcolor is a header-only C++ library for printing colored + messages to the terminal. Written just for fun with a help of + the Force. + + And yeah, it's BSD licensed so you are free to do whatever you + want as long as copyright sticks around! + + + ~ How to use? + + Add `termcolor.hpp` to the project and use provided stream + manimulators from the `termcolor` namespace. + + For example: + + std::cout << termcolor::red << termcolor::on_blue + << "Red text on blue background!" + << termcolor::reset << std::endl; + + Please, don't forgot to reset termcolor's settings on the stream! + + + ~ What terminals are supported? + + Termcolor supports ANSI color formatting. This formatting is + supported by most popular terminals on Linux, Unix and Mac OS. + On Windows, WinAPI is used instead, however, some limitations + are applied. Check the docs for details! + + + ~ Where the docs? + + https://termcolor.readthedocs.io/ diff --git a/intern/termcolor/termcolor.hpp b/intern/termcolor/termcolor.hpp new file mode 100644 index 000000000000..1ff0e63046b2 --- /dev/null +++ b/intern/termcolor/termcolor.hpp @@ -0,0 +1,518 @@ +//! +//! termcolor +//! ~~~~~~~~~ +//! +//! termcolor is a header-only c++ library for printing colored messages +//! to the terminal. Written just for fun with a help of the Force. +//! +//! :copyright: (c) 2013 by Igor Kalnitsky +//! :license: BSD, see LICENSE for details +//! + +#ifndef TERMCOLOR_HPP_ +#define TERMCOLOR_HPP_ + +// the following snippet of code detects the current OS and +// defines the appropriate macro that is used to wrap some +// platform specific things +#if defined(_WIN32) || defined(_WIN64) +# define TERMCOLOR_OS_WINDOWS +#elif defined(__APPLE__) +# define TERMCOLOR_OS_MACOS +#elif defined(__unix__) || defined(__unix) +# define TERMCOLOR_OS_LINUX +#else +# error unsupported platform +#endif + + +// This headers provides the `isatty()`/`fileno()` functions, +// which are used for testing whether a standart stream refers +// to the terminal. As for Windows, we also need WinApi funcs +// for changing colors attributes of the terminal. +#if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) +# include +#elif defined(TERMCOLOR_OS_WINDOWS) +# include +# include +#endif + + +#include +#include + + + +namespace termcolor +{ + // Forward declaration of the `_internal` namespace. + // All comments are below. + namespace _internal + { + inline FILE* get_standard_stream(const std::ostream& stream); + inline bool is_atty(const std::ostream& stream); + + #if defined(TERMCOLOR_OS_WINDOWS) + inline void win_change_attributes(std::ostream& stream, int foreground, int background=-1); + #endif + } + + + inline + std::ostream& reset(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[00m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + _internal::win_change_attributes(stream, -1, -1); + #endif + } + return stream; + } + + + inline + std::ostream& bold(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[1m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + #endif + } + return stream; + } + + + inline + std::ostream& dark(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[2m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + #endif + } + return stream; + } + + + inline + std::ostream& underline(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[4m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + #endif + } + return stream; + } + + + inline + std::ostream& blink(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[5m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + #endif + } + return stream; + } + + + inline + std::ostream& reverse(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[7m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + #endif + } + return stream; + } + + + inline + std::ostream& concealed(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[8m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + #endif + } + return stream; + } + + + inline + std::ostream& grey(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[30m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + _internal::win_change_attributes(stream, + 0 // grey (black) + ); + #endif + } + return stream; + } + + inline + std::ostream& red(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[31m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + _internal::win_change_attributes(stream, + FOREGROUND_RED + ); + #endif + } + return stream; + } + + inline + std::ostream& green(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[32m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + _internal::win_change_attributes(stream, + FOREGROUND_GREEN + ); + #endif + } + return stream; + } + + inline + std::ostream& yellow(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[33m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + _internal::win_change_attributes(stream, + FOREGROUND_GREEN | FOREGROUND_RED + ); + #endif + } + return stream; + } + + inline + std::ostream& blue(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[34m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + _internal::win_change_attributes(stream, + FOREGROUND_BLUE + ); + #endif + } + return stream; + } + + inline + std::ostream& magenta(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[35m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + _internal::win_change_attributes(stream, + FOREGROUND_BLUE | FOREGROUND_RED + ); + #endif + } + return stream; + } + + inline + std::ostream& cyan(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[36m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + _internal::win_change_attributes(stream, + FOREGROUND_BLUE | FOREGROUND_GREEN + ); + #endif + } + return stream; + } + + inline + std::ostream& white(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[37m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + _internal::win_change_attributes(stream, + FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED + ); + #endif + } + return stream; + } + + + + inline + std::ostream& on_grey(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[40m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + _internal::win_change_attributes(stream, -1, + 0 // grey (black) + ); + #endif + } + return stream; + } + + inline + std::ostream& on_red(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[41m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + _internal::win_change_attributes(stream, -1, + BACKGROUND_RED + ); + #endif + } + return stream; + } + + inline + std::ostream& on_green(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[42m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + _internal::win_change_attributes(stream, -1, + BACKGROUND_GREEN + ); + #endif + } + return stream; + } + + inline + std::ostream& on_yellow(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[43m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + _internal::win_change_attributes(stream, -1, + BACKGROUND_GREEN | BACKGROUND_RED + ); + #endif + } + return stream; + } + + inline + std::ostream& on_blue(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[44m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + _internal::win_change_attributes(stream, -1, + BACKGROUND_BLUE + ); + #endif + } + return stream; + } + + inline + std::ostream& on_magenta(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[45m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + _internal::win_change_attributes(stream, -1, + BACKGROUND_BLUE | BACKGROUND_RED + ); + #endif + } + return stream; + } + + inline + std::ostream& on_cyan(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[46m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + _internal::win_change_attributes(stream, -1, + BACKGROUND_GREEN | BACKGROUND_BLUE + ); + #endif + } + return stream; + } + + inline + std::ostream& on_white(std::ostream& stream) + { + if (_internal::is_atty(stream)) + { + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + stream << "\033[47m"; + #elif defined(TERMCOLOR_OS_WINDOWS) + _internal::win_change_attributes(stream, -1, + BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED + ); + #endif + } + + return stream; + } + + + + //! Since C++ hasn't a way to hide something in the header from + //! the outer access, I have to introduce this namespace which + //! is used for internal purpose and should't be access from + //! the user code. + namespace _internal + { + //! Since C++ hasn't a true way to extract stream handler + //! from the a given `std::ostream` object, I have to write + //! this kind of hack. + inline + FILE* get_standard_stream(const std::ostream& stream) + { + if (&stream == &std::cout) + return stdout; + else if ((&stream == &std::cerr) || (&stream == &std::clog)) + return stderr; + + return 0; + } + + + //! Test whether a given `std::ostream` object refers to + //! a terminal. + inline + bool is_atty(const std::ostream& stream) + { + FILE* std_stream = get_standard_stream(stream); + + #if defined(TERMCOLOR_OS_MACOS) || defined(TERMCOLOR_OS_LINUX) + return ::isatty(fileno(std_stream)); + #elif defined(TERMCOLOR_OS_WINDOWS) + return ::_isatty(_fileno(std_stream)); + #endif + } + + + #if defined(TERMCOLOR_OS_WINDOWS) + //! Change Windows Terminal colors attribute. If some + //! parameter is `-1` then attribute won't changed. + inline void win_change_attributes(std::ostream& stream, int foreground, int background) + { + // yeah, i know.. it's ugly, it's windows. + static WORD defaultAttributes = 0; + + // get terminal handle + HANDLE hTerminal = INVALID_HANDLE_VALUE; + if (&stream == &std::cout) + hTerminal = GetStdHandle(STD_OUTPUT_HANDLE); + else if (&stream == &std::cerr) + hTerminal = GetStdHandle(STD_ERROR_HANDLE); + + // save default terminal attributes if it unsaved + if (!defaultAttributes) + { + CONSOLE_SCREEN_BUFFER_INFO info; + if (!GetConsoleScreenBufferInfo(hTerminal, &info)) + return; + defaultAttributes = info.wAttributes; + } + + // restore all default settings + if (foreground == -1 && background == -1) + { + SetConsoleTextAttribute(hTerminal, defaultAttributes); + return; + } + + // get current settings + CONSOLE_SCREEN_BUFFER_INFO info; + if (!GetConsoleScreenBufferInfo(hTerminal, &info)) + return; + + if (foreground != -1) + { + info.wAttributes &= ~(info.wAttributes & 0x0F); + info.wAttributes |= static_cast(foreground); + } + + if (background != -1) + { + info.wAttributes &= ~(info.wAttributes & 0xF0); + info.wAttributes |= static_cast(background); + } + + SetConsoleTextAttribute(hTerminal, info.wAttributes); + } + #endif // TERMCOLOR_OS_WINDOWS + + } // namespace _internal + +} // namespace termcolor + + +#undef TERMCOLOR_OS_WINDOWS +#undef TERMCOLOR_OS_MACOS +#undef TERMCOLOR_OS_LINUX + +#endif // TERMCOLOR_HPP_ diff --git a/release/datafiles/blender_icons.svg b/release/datafiles/blender_icons.svg index a9c0fd431ebb..023dcf1b527c 100644 --- a/release/datafiles/blender_icons.svg +++ b/release/datafiles/blender_icons.svg @@ -14,7 +14,7 @@ height="640" id="svg2" sodipodi:version="0.32" - inkscape:version="0.91 r13725" + inkscape:version="0.92.3 (2405546, 2018-03-11)" version="1.0" sodipodi:docname="blender_icons.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape" @@ -4357,43 +4357,6 @@ x2="-174.18907" y2="224.99274" gradientUnits="userSpaceOnUse" /> - - - - + originx="0" + originy="-2.7755576e-017" /> @@ -46214,97 +46177,6 @@ inkscape:connector-curvature="0" /> - - - - - - - - - - - - - - - - @@ -92866,7 +92738,7 @@ sodipodi:start="6.1086524" sodipodi:end="7.5049158" sodipodi:open="true" - d="m 45.185432,872.62412 c 0.358149,2.03116 -0.793733,4.02628 -2.731847,4.73169" /> + d="m 45.185432,872.62412 a 4.2499995,4.2499995 0 0 1 -2.731847,4.73169" /> + d="m 39.188267,866.60064 a 7,7 0 0 1 3.623467,0" /> + d="M 36.050253,878.31187 A 6.9999995,6.9999995 0 0 1 34.23852,875.17385" /> + d="m 39.546414,877.35581 a 4.2499995,4.2499995 0 0 1 -2.731846,-4.73169" /> + d="m 36.050253,878.31187 a 6.9999995,6.9999995 0 0 1 -1.11243,-1.44975" /> @@ -93055,9 +92927,9 @@ sodipodi:start="4.0142573" sodipodi:end="4.9741884" sodipodi:open="true" - d="m 38.268153,870.10643 c 1.062216,-0.8913 2.492452,-1.20838 3.831828,-0.84949" /> + d="m 38.268153,870.10643 a 4.25,4.25 0 0 1 3.831828,-0.84949" /> + d="M 39.188267,866.60064 A 6.9999995,6.9999995 0 0 1 41,866.36212" /> + d="m 47.761481,875.17385 a 7,7 0 0 1 -1.811734,3.13802" /> + transform="matrix(0.6425292,0,0,0.642531,44.523834,146.81699)" /> + transform="matrix(-0.5858806,-0.06590218,0.06677852,-0.5812167,198.80048,299.96262)" /> + inkscape:export-ydpi="90" /> @@ -93260,6 +93129,14 @@ inkscape:connector-curvature="0" /> + +Copyright (C) 2017-2018 Philippe Groarke + +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. + diff --git a/release/datafiles/gamecontroller/gamecontrollerdb.txt b/release/datafiles/gamecontroller/gamecontrollerdb.txt new file mode 100644 index 000000000000..1a39ae8b6a6c --- /dev/null +++ b/release/datafiles/gamecontroller/gamecontrollerdb.txt @@ -0,0 +1,436 @@ +# Game Controller DB for SDL in 2.0.6 format +# Source: https://github.com/gabomdq/SDL_GameControllerDB + +# Windows +03000000fa2d00000100000000000000,3DRUDDER,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows, +03000000022000000090000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000203800000900000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000060000000000000,8Bitdo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000061000000000000,8Bitdo SF30 Pro Wireless,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000102800000900000000000000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000a00500003232000000000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, +030000008f0e00001200000000000000,Acme,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows, +03000000341a00003608000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,platform:Windows, +030000006b1400000055000000000000,bigben ps3padstreetnew,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +0300000066f700000500000000000000,BrutalLegendTest,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000d81d00000b00000000000000,BUFFALO BSGP1601 Series ,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows, +03000000e82000006058000000000000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +030000005e0400008e02000000000000,Controller (XBOX 360 For Windows),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000260900008888000000000000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a4,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Windows, +03000000a306000022f6000000000000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000791d00000103000000000000,Dual Box WII,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +030000004f04000023b3000000000000,Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000341a00000108000000000000,EXEQ RF USB Gamepad 8206,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000000d0f00008500000000000000,Fighting Commander 2016 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008400000000000000,Fighting Commander 5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008700000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008800000000000000,Fighting Stick mini 4,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows, +030000000d0f00002700000000000000,FIGHTING STICK V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +78696e70757403000000000000000000,Fightstick TES,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Windows, +03000000790000000600000000000000,G-Shark GS-GP702,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, +03000000260900002625000000000000,Gamecube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows, +030000008f0e00000d31000000000000,GAMEPAD 3 TURBO,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000280400000140000000000000,GamePad Pro USB,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +03000000ffff00000000000000000000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000451300000010000000000000,Generic USB Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000341a00000302000000000000,Hama Scorpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00004900000000000000,Hatsune Miku Sho Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d81400000862000000000000,HitBox Edition Cthulhu+,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005f00000000000000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005e00000000000000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00004000000000000000,Hori Fighting Stick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006e00000000000000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006600000000000000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000ee00000000000000,HORIPAD mini4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00004d00000000000000,HORIPAD3 A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000250900000017000000000000,HRAP2 on PS/SS/N64 Joypad to USB BOX,a:b2,b:b1,back:b9,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b8,x:b3,y:b0,platform:Windows, +030000008f0e00001330000000000000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Windows, +03000000d81d00000f00000000000000,iBUFFALO BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000d81d00001000000000000000,iBUFFALO BSGP1204P Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000830500006020000000000000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Windows, +03000000b50700001403000000000000,IMPACT BLACK,a:b2,b:b3,back:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +030000006f0e00002401000000000000,INJUSTICE FightStick for PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +03000000491900000204000000000000,Ipega PG-9023,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +030000006d04000011c2000000000000,Logitech Cordless Wingman,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows, +030000006d04000016c2000000000000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d04000018c2000000000000,Logitech F510 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d04000019c2000000000000,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700005032000000000000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700005082000000000000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008433000000000000,Mad Catz FightStick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008483000000000000,Mad Catz FightStick TE S+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b6,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008134000000000000,Mad Catz FightStick TE2+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008184000000000000,Mad Catz FightStick TE2+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008034000000000000,Mad Catz TE2 PS3 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008084000000000000,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008532000000000000,Madcatz Arcade Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700003888000000000000,Madcatz Arcade Fightstick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700001888000000000000,MadCatz SFIV FightStick PS3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000380700008081000000000000,MADCATZ SFV Arcade FightStick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000008305000031b0000000000000,MaxfireBlaze3,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,platform:Windows, +03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000790000004318000000000000,Mayflash GameCube Controller Adapter,a:b1,b:b2,back:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b0,leftshoulder:b4,leftstick:b0,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b0,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +030000008f0e00001030000000000000,Mayflash USB Adapter for original Sega Saturn controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,rightshoulder:b2,righttrigger:b7,start:b9,x:b3,y:b4,platform:Windows, +0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows, +03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Windows, +03000000bd12000015d0000000000000,Nintendo Retrolink USB Super SNES Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows, +030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000004b120000014d000000000000,NYKO AIRFLO,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a3,leftstick:a0,lefttrigger:b6,rightshoulder:b5,rightstick:a2,righttrigger:b7,start:b9,x:b2,y:b3,platform:Windows, +03000000362800000100000000000000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows, +03000000120c0000f60e000000000000,P4 Wired Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows, +030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000008f0e00007530000000000000,PS (R) Gamepad,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b1,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000e30500009605000000000000,PS to USB convert cable,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000100800000100000000000000,PS1 USB,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000100800000300000000000000,PS2 USB,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows, +03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, +03000000250900000500000000000000,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows, +03000000100000008200000000000000,PS360+ v1.66,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:h0.4,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000004c050000a00b000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004c050000cc09000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00000011000000000000,QanBa Arcade JoyStick 1008,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b10,x:b0,y:b3,platform:Windows, +03000000300f00001611000000000000,QanBa Arcade JoyStick 4018,a:b1,b:b2,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows, +03000000222c00000020000000000000,QANBA DRONE ARCADE JOYSTICK,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00001210000000000000,QanBa Joystick Plus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows, +03000000341a00000104000000000000,QanBa Joystick Q4RAF,a:b5,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b1,y:b2,platform:Windows, +03000000222c00000223000000000000,Qanba Obsidian Arcade Joystick PS3 Mode,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000222c00000023000000000000,Qanba Obsidian Arcade Joystick PS4 Mode,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f00001100000000000000,REAL ARCADE PRO.3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006a00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006b00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008a00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008b00000000000000,Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00007000000000000000,REAL ARCADE PRO.4 VLX,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00002200000000000000,REAL ARCADE Pro.V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005b00000000000000,Real Arcade Pro.V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005c00000000000000,Real Arcade Pro.V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000790000001100000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows, +0300000000f000000300000000000000,RetroUSB.com RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows, +0300000000f00000f100000000000000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows, +030000006b140000010d000000000000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001e01000000000000,Rock Candy Gamepad for PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000004f04000003d0000000000000,run'n'drive,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000a306000023f6000000000000,Saitek Cyborg V.1 Game pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00001201000000000000,Saitek Dual Analog Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +03000000a30600000cff000000000000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,x:b0,y:b1,platform:Windows, +03000000a30600000c04000000000000,Saitek P2900,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00001001000000000000,Saitek P480 Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +03000000a30600000b04000000000000,Saitek P990,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Windows, +03000000300f00001101000000000000,saitek rumble pad,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +0300000000050000289b000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows, +030000009b2800000500000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows, +03000000341a00000208000000000000,SL-6555-SBK,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,platform:Windows, +030000008f0e00000800000000000000,SpeedLink Strike FX Wireless,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000ff1100003133000000000000,SVEN X-PAD,a:b2,b:b3,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a4,start:b5,x:b0,y:b1,platform:Windows, +03000000fa1900000706000000000000,Team 5,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000b50700001203000000000000,Techmobility X6-38V,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +030000004f04000015b3000000000000,Thrustmaster Dual Analog 2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, +030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Windows, +030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power 3,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, +03000000666600000488000000000000,TigerGame PS/PS2 Game Controller Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000d90400000200000000000000,TwinShock PS2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000380700006652000000000000,UnKnown,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000632500002305000000000000,USB Vibration Joystick (BM),a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +03000000450c00002043000000000000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000172700004431000000000000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000786901006e70000000000000,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, + +# Mac OS X +03000000022000000090000001000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000203800000900000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000102800000900000000000000,8Bitdo SFC30 GamePad Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000a00500003232000009010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, +030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X, +03000000a306000022f6000001030000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000790000000600000000000000,G-Shark GP-702,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000ad1b000001f9000000000000,Gamestop BB-070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +030000000d0f00005f00000000010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00005e00000000010000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00005f00000000000000,HORI Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00005e00000000000000,HORI Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00004d00000000000000,HORI Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00006e00000000010000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00006600000000010000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00006600000000000000,HORIPAD FPS PLUS 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000008f0e00001330000011010000,HuiJia SNES Controller,a:b4,b:b2,back:b16,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b12,rightshoulder:b14,start:b18,x:b6,y:b0,platform:Mac OS X, +03000000830500006020000000010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X, +03000000830500006020000000000000,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X, +030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Mac OS X, +030000006d04000016c2000000020000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000016c2000000030000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000016c2000014040000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d0400001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000006d04000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000380700005032000000010000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000380700005082000000010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000790000004418000000010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Mac OS X, +0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Mac OS X, +03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X, +03000000d8140000cecf000000000000,MC Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Mac OS X, +030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000d62000006dca000000010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X, +030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X, +030000004c050000a00b000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000008916000000fd000000000000,Razer Onza TE,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000321500000010000000010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000790000001100000000000000,Retrolink Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a3,lefty:a4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000c6240000fefa000000000000,Rock Candy Gamepad for PS3,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X, +03000000b40400000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X, +030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004c050000a00b000000000000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000005e0400008e02000001000000,Steam Virtual GamePad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Mac OS X, +03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X, +03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X, +03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X, +03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X, +030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X, +030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X, +03000000bd12000015d0000000000000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000bd12000015d0000000010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X, +050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,platform:Mac OS X, +050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,platform:Mac OS X, +030000005e0400008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000c6240000045d000000000000,Xbox 360 Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000d102000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000dd02000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000e302000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000e002000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X, +030000005e040000e002000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X, +030000005e040000ea02000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000fd02000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000120c0000100e000000010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, + +# Linux +03000000022000000090000011010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000203800000900000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00002038000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000190000011010000,8Bitdo NES30 Pro 8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000102800000900000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00003028000000010000,8Bitdo SFC30 GamePad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +05000000a00500003232000001000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux, +05000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux, +030000006f0e00003901000000430000,Afterglow Prismatic Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00003901000020060000,Afterglow Wired Controller for Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000100000008200000011010000,Akishop Customs PS360+ v1.66,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +05000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux, +03000000666600006706000000010000,boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux, +03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Linux, +03000000a306000022f6000011010000,Cyborg V.3 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000b40400000a01000000010000,CYPRESS USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux, +03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux, +030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000341a000005f7000010010000,GameCube {HuiJia USB box},a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux, +0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00001304000000010000,Generic X-Box pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:a0,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:a3,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00001f01000000010000,Generic X-Box pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000280400000140000000010000,Gravis GamePad Pro USB ,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000008f0e00000610000000010000,GreenAsia Electronics 4Axes 12Keys GamePad ,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Linux, +030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +0500000047532067616d657061640000,GS gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +06000000adde0000efbe000002010000,Hidromancer Game Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d81400000862000011010000,HitBox (PS3/PC) Analog Mode,a:b1,b:b2,back:b8,guide:b9,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux, +03000000c9110000f055000011010000,HJC Game GAMEPAD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +030000000d0f00000d00000000010000,hori,a:b0,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftx:b4,lefty:b5,rightshoulder:b7,start:b9,x:b1,y:b2,platform:Linux, +030000000d0f00001000000011010000,HORI CO. LTD. FIGHTING STICK 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00006a00000011010000,HORI CO. LTD. Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00006b00000011010000,HORI CO. LTD. Real Arcade Pro.4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00005f00000011010000,Hori Fighting Commander 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00005e00000011010000,Hori Fighting Commander 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000000d0f00006e00000011010000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00006600000011010000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00006700000001010000,HORIPAD ONE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000008f0e00001330000010010000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Linux, +03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux, +050000006964726f69643a636f6e0000,idroid:con,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000b50700001503000010010000,impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, +03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),a:b3,b:b4,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b7,x:b0,y:b1,platform:Linux, +030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux, +03000000300f00001001000010010000,Jess Tech Dual Analog Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, +03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d04000016c2000011010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d04000015c2000010010000,Logitech Logitech Extreme 3D,a:b0,b:b4,back:b6,guide:b8,leftshoulder:b9,leftstick:h0.8,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:h0.2,start:b7,x:b2,y:b5,platform:Linux, +030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux, +05000000380700006652000025010000,Mad Catz C.T.R.L.R ,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700005032000011010000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700005082000011010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux, +03000000380700008034000011010000,Mad Catz fightstick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700008084000011010000,Mad Catz fightstick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000380700008433000011010000,Mad Catz FightStick TE S+ PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700008483000011010000,Mad Catz FightStick TE S+ PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000380700001647000010040000,Mad Catz Wired Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000380700003847000090040000,Mad Catz Wired Xbox 360 Controller (SFIV),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000380700001888000010010000,MadCatz PC USB Wired Stick 8818,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700003888000010010000,MadCatz PC USB Wired Stick 8838,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +0300000079000000d218000011010000,MAGIC-NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux, +03000000780000000600000010010000,Microntek USB Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, +030000005e0400000e00000000010000,Microsoft SideWinder,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux, +030000005e0400008e02000004010000,Microsoft X-Box 360 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000062230000,Microsoft X-Box 360 pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000d102000001010000,Microsoft X-Box One pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000d102000003020000,Microsoft X-Box One pad v2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008502000000010000,Microsoft X-Box pad (Japan),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, +030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, +05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, +03000000250900006688000000010000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, +030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Linux, +050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, +05000000010000000100000003000000,Nintendo Wiimote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +030000000d0500000308000010010000,Nostromo n45 Dual Analog Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux, +03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000005e0400000202000000010000,Old Xbox pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, +05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux, +05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux, +03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d62000006dca000011010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, +03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000004c0500006802000010010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +030000004c0500006802000010810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +030000004c0500006802000011810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +050000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:a12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:a13,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +050000004c0500006802000000810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +050000004c0500006802000000800000,PS3 Controller (Bluetooth),a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +05000000504c415953544154494f4e00,PS3 Controller (Bluetooth),a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +030000004c050000a00b000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004c050000a00b000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +030000004c050000c405000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004c050000c405000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +030000004c050000cc09000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004c050000cc09000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +050000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +050000004c050000c405000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +03000000300f00001211000011010000,QanBa Arcade JoyStick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux, +030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux, +030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000321500000010000011010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000c6240000045d000025010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000321500000009000011010000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000790000001100000010010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux, +0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux, +0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux, +030000006b140000010d000011010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00004601000001010000,Rock Candy Wired Controller for Xbox One,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000a30600000cff000010010000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux, +03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux, +03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux, +03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux, +03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000c01600008704000011010000,Serial/Keyboard/Mouse/Joystick,a:b12,b:b10,back:b4,dpdown:b2,dpleft:b3,dpright:b1,dpup:b0,leftshoulder:b9,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b8,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b5,x:b13,y:b11,platform:Linux, +03000000f025000021c1000010010000,ShanWan Gioteck PS3 Wired Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000632500007505000010010000,SHANWAN PS3/PC Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, +030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000ad1b000038f0000090040000,Street Fighter IV FightStick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, +030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, +030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, +030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Linux, +030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000bd12000015d0000010010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux, +03000000d814000007cd000011010000,Toodles 2008 Chimp PC/PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux, +03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +03000000790000001100000000010000,USB Gamepad1,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux, +05000000ac0500003232000001000000,VR-BOX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000a102000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000a102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +0000000058626f782033363020576900,Xbox 360 Wireless Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux, +030000005e040000a102000014010000,Xbox 360 Wireless Receiver (XBOX),a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000450c00002043000010010000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +05000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux, +03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux, +xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, + +# Android +64633436313965656664373634323364,Microsoft X-Box 360 pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android, +37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +61363931656135336130663561616264,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, +05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android, +5477696e20555342204a6f7973746963,Twin USB Joystick,a:b22,b:b21,back:b28,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android, +34356136633366613530316338376136,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android, + +# iOS +4d466947616d65706164010000000000,MFi Extended Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:iOS, +4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:iOS, +05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS, diff --git a/release/datafiles/locale b/release/datafiles/locale index d3349b42856d..507eacde9608 160000 --- a/release/datafiles/locale +++ b/release/datafiles/locale @@ -1 +1 @@ -Subproject commit d3349b42856d00c278f72f2a5909a6c96b9cdb5e +Subproject commit 507eacde9608ce0190c6087fb338dd63f7a1649b diff --git a/release/datafiles/splash.png b/release/datafiles/splash.png index 1cd817a8e8ce..e27128327028 100644 Binary files a/release/datafiles/splash.png and b/release/datafiles/splash.png differ diff --git a/release/datafiles/splash_2x.png b/release/datafiles/splash_2x.png index 2ba54b92cffc..2e7a2ffbd264 100644 Binary files a/release/datafiles/splash_2x.png and b/release/datafiles/splash_2x.png differ diff --git a/release/datafiles/splash_template.xcf b/release/datafiles/splash_template.xcf index 12719b5c1550..e56f1156d19c 100644 Binary files a/release/datafiles/splash_template.xcf and b/release/datafiles/splash_template.xcf differ diff --git a/release/datafiles/startup.blend b/release/datafiles/startup.blend index 23bb2646a54c..2629a4c5c655 100644 Binary files a/release/datafiles/startup.blend and b/release/datafiles/startup.blend differ diff --git a/release/scripts/addons b/release/scripts/addons index 6c3a46dc113d..ff8ef5cb121e 160000 --- a/release/scripts/addons +++ b/release/scripts/addons @@ -1 +1 @@ -Subproject commit 6c3a46dc113de870a03191e4c0685238b0823acd +Subproject commit ff8ef5cb121e590ef1a5f3e5f57b9bf99c46559d diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib index 15b25a42783d..2ff215a19426 160000 --- a/release/scripts/addons_contrib +++ b/release/scripts/addons_contrib @@ -1 +1 @@ -Subproject commit 15b25a42783d1e516b5298d70b582fae2559ae17 +Subproject commit 2ff215a194267434043433d83e4cf48eff58250c diff --git a/release/scripts/bge/interpreter.py b/release/scripts/bge/interpreter.py new file mode 100644 index 000000000000..8f2031b27edd --- /dev/null +++ b/release/scripts/bge/interpreter.py @@ -0,0 +1,25 @@ +import sys +import os +import bge +import code + +# Check if a console exits. +if os.isatty(sys.stdin.fileno()): + try: + import readline + except ImportError: + print("Can not enable autocompletion, readline module is missing") + else: + import rlcompleter + # Autocompletion with tab. + readline.parse_and_bind("tab: complete") + + if sys.platform.startswith("win"): + print("Python interpreter started. Press Ctrl+C or Ctrl+Z+Enter to quit.") + elif sys.platform.startswith("linux"): + print("Python interpreter started. Press Ctrl+D to quit.") + else: + print("Python interpreter started.") #TODO: find OSX shortcut. + + # Launch interactive console with current locals. + code.interact(local=locals()) diff --git a/release/scripts/presets/interface_theme/upbge.xml b/release/scripts/presets/interface_theme/upbge.xml new file mode 100644 index 000000000000..69549e6fc313 --- /dev/null +++ b/release/scripts/presets/interface_theme/upbge.xml @@ -0,0 +1,1177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py index b7880e605b32..5f1b050a8b88 100644 --- a/release/scripts/startup/bl_ui/properties_constraint.py +++ b/release/scripts/startup/bl_ui/properties_constraint.py @@ -553,6 +553,12 @@ def RIGID_BODY_JOINT(self, context, layout, con): row.prop(con, "use_linked_collision", text="Linked Collision") row.prop(con, "show_pivot", text="Display Pivot") + row = layout.row() + row.prop(con, "use_breaking") + row = row.row() + row.active = con.use_breaking + row.prop(con, "breaking_threshold") + split = layout.split() col = split.column(align=True) diff --git a/release/scripts/startup/bl_ui/properties_data_camera.py b/release/scripts/startup/bl_ui/properties_data_camera.py index 14286045704f..461cde6bdf1f 100644 --- a/release/scripts/startup/bl_ui/properties_data_camera.py +++ b/release/scripts/startup/bl_ui/properties_data_camera.py @@ -135,6 +135,76 @@ def draw(self, context): col.prop(cam, "clip_end", text="End") +class DATA_PT_levels_of_detail(CameraButtonsPanel, Panel): + bl_label = "Levels of Detail" + COMPAT_ENGINES = {'BLENDER_GAME'} + + @classmethod + def poll(cls, context): + return context.camera and context.scene.render.engine in cls.COMPAT_ENGINES + + def draw(self, context): + layout = self.layout + cam = context.camera + + col = layout.column() + col.prop(cam, "lod_factor", text="Distance Factor") + + +class DATA_PT_culling(CameraButtonsPanel, Panel): + bl_label = "Culling" + COMPAT_ENGINES = {'BLENDER_GAME'} + + @classmethod + def poll(cls, context): + return context.camera and context.scene.render.engine in cls.COMPAT_ENGINES + + def draw(self, context): + layout = self.layout + cam = context.camera + + split = layout.split() + + col = split.column() + col.label(text="Frustum Culling:") + col.prop(cam, "show_frustum") + col.prop(cam, "override_culling") + + col = split.column() + col.label(text="Object Activity:") + col.prop(cam, "use_object_activity_culling") + + +class DATA_PT_game_viewport(CameraButtonsPanel, Panel): + bl_label = "Custom Viewport" + COMPAT_ENGINES = {'BLENDER_GAME'} + + @classmethod + def poll(cls, context): + return context.camera and context.scene.render.engine in cls.COMPAT_ENGINES + + def draw_header(self, context): + cam = context.camera + + self.layout.prop(cam, "use_viewport", text="") + + def draw(self, context): + layout = self.layout + cam = context.camera + viewport = cam.viewport + + split = layout.split() + split.active = cam.use_viewport + + col = split.column() + col.prop(viewport, "left_ratio") + col.prop(viewport, "right_ratio") + + col = split.column() + col.prop(viewport, "bottom_ratio") + col.prop(viewport, "top_ratio") + + class DATA_PT_camera_stereoscopy(CameraButtonsPanel, Panel): bl_label = "Stereoscopy" COMPAT_ENGINES = {'BLENDER_RENDER'} @@ -331,6 +401,9 @@ def draw_display_safe_settings(layout, safe_data, settings): DATA_PT_context_camera, DATA_PT_lens, DATA_PT_camera, + DATA_PT_levels_of_detail, + DATA_PT_culling, + DATA_PT_game_viewport, DATA_PT_camera_stereoscopy, DATA_PT_camera_dof, DATA_PT_camera_display, diff --git a/release/scripts/startup/bl_ui/properties_data_empty.py b/release/scripts/startup/bl_ui/properties_data_empty.py index c66ff87ecbdf..17eb0666d835 100644 --- a/release/scripts/startup/bl_ui/properties_data_empty.py +++ b/release/scripts/startup/bl_ui/properties_data_empty.py @@ -43,7 +43,7 @@ def draw(self, context): if ob.empty_draw_type == 'IMAGE': layout.template_ID(ob, "data", open="image.open", unlink="object.unlink_data") - layout.template_image(ob, "data", ob.image_user, compact=True) + layout.template_image(ob, "data", ob.image_user, compact=True, color_space=True) row = layout.row(align=True) row = layout.row(align=True) diff --git a/release/scripts/startup/bl_ui/properties_data_lamp.py b/release/scripts/startup/bl_ui/properties_data_lamp.py index f9394139b423..8088eef6f12a 100644 --- a/release/scripts/startup/bl_ui/properties_data_lamp.py +++ b/release/scripts/startup/bl_ui/properties_data_lamp.py @@ -110,6 +110,12 @@ def draw(self, context): sub.prop(lamp, "linear_coefficient", text="Linear") sub.prop(lamp, "quadratic_coefficient", text="Quadratic") + elif lamp.falloff_type == 'INVSQUARE_CUTOFF': + col.label(text="Inverse Square Cutoff:") + sub = col.column(align=True) + sub.prop(lamp, "radius", text="Radius") + sub.prop(lamp, "cutoff_threshold", text="CutOff") + col.prop(lamp, "use_sphere") if lamp.type == 'AREA': diff --git a/release/scripts/startup/bl_ui/properties_game.py b/release/scripts/startup/bl_ui/properties_game.py index ac51b97e87d1..b09b97eecf02 100644 --- a/release/scripts/startup/bl_ui/properties_game.py +++ b/release/scripts/startup/bl_ui/properties_game.py @@ -26,7 +26,6 @@ class PhysicsButtonsPanel: bl_region_type = 'WINDOW' bl_context = "physics" - class PHYSICS_PT_game_physics(PhysicsButtonsPanel, Panel): bl_label = "Physics" COMPAT_ENGINES = {'BLENDER_GAME'} @@ -52,10 +51,18 @@ def draw(self, context): if physics_type == 'CHARACTER': layout.prop(game, "use_actor") layout.prop(ob, "hide_render", text="Invisible") # out of place but useful - layout.prop(game, "step_height", slider=True) - layout.prop(game, "jump_speed") - layout.prop(game, "fall_speed") - layout.prop(game, "jump_max") + + layout.separator() + + split = layout.split() + + col = split.column() + col.prop(game, "step_height", slider=True) + col.prop(game, "fall_speed") + col.prop(game, "max_slope") + col = split.column() + col.prop(game, "jump_speed") + col.prop(game, "jump_max") elif physics_type in {'DYNAMIC', 'RIGID_BODY'}: split = layout.split() @@ -66,7 +73,7 @@ def draw(self, context): col.prop(ob, "hide_render", text="Invisible") # out of place but useful col = split.column() - col.prop(game, "use_material_physics_fh") + col.prop(game, "use_physics_fh") col.prop(game, "use_rotate_from_normal") col.prop(game, "use_sleep") @@ -79,8 +86,19 @@ def draw(self, context): col.prop(game, "mass") col.prop(game, "radius") col.prop(game, "form_factor") + col.prop(game, "elasticity", slider=True) + + col.label(text="Linear Velocity:") + sub = col.column(align=True) + sub.prop(game, "velocity_min", text="Minimum") + sub.prop(game, "velocity_max", text="Maximum") col = split.column() + col.label(text="Friction:") + col.prop(game, "friction") + col.prop(game, "rolling_friction") + col.separator() + sub = col.column() sub.prop(game, "use_anisotropic_friction") subsub = sub.column() @@ -88,13 +106,8 @@ def draw(self, context): subsub.prop(game, "friction_coefficients", text="", slider=True) split = layout.split() - col = split.column() - col.label(text="Linear Velocity:") - sub = col.column(align=True) - sub.prop(game, "velocity_min", text="Minimum") - sub.prop(game, "velocity_max", text="Maximum") - col.label(text="Angular Velocity:") + col.label(text="Angular velocity:") sub = col.column(align=True) sub.prop(game, "angular_velocity_min", text="Minimum") sub.prop(game, "angular_velocity_max", text="Maximum") @@ -107,20 +120,22 @@ def draw(self, context): layout.separator() - split = layout.split() + col = layout.column() - col = split.column() col.label(text="Lock Translation:") - col.prop(game, "lock_location_x", text="X") - col.prop(game, "lock_location_y", text="Y") - col.prop(game, "lock_location_z", text="Z") + row = col.row() + row.prop(game, "lock_location_x", text="X") + row.prop(game, "lock_location_y", text="Y") + row.prop(game, "lock_location_z", text="Z") if physics_type == 'RIGID_BODY': - col = split.column() + col = layout.column() + col.label(text="Lock Rotation:") - col.prop(game, "lock_rotation_x", text="X") - col.prop(game, "lock_rotation_y", text="Y") - col.prop(game, "lock_rotation_z", text="Z") + row = col.row() + row.prop(game, "lock_rotation_x", text="X") + row.prop(game, "lock_rotation_y", text="Y") + row.prop(game, "lock_rotation_z", text="Z") elif physics_type == 'SOFT_BODY': col = layout.column() @@ -133,23 +148,39 @@ def draw(self, context): split = layout.split() col = split.column() - col.label(text="Attributes:") + col.label(text="General Attributes:") col.prop(game, "mass") # disabled in the code # col.prop(soft, "weld_threshold") - col.prop(soft, "location_iterations") col.prop(soft, "linear_stiffness", slider=True) col.prop(soft, "dynamic_friction", slider=True) + col.prop(soft, "kdp", text="Damping", slider=True) col.prop(soft, "collision_margin", slider=True) + col.prop(soft, "kvcf", text="Velocity Correction", slider=True) col.prop(soft, "use_bending_constraints", text="Bending Constraints") - col = split.column() + sub = col.column() + sub.active = soft.use_bending_constraints + sub.prop(soft, "bending_distance") + col.prop(soft, "use_shape_match") + sub = col.column() sub.active = soft.use_shape_match sub.prop(soft, "shape_threshold", slider=True) - col.separator() + col.label(text="Solver Iterations:") + col.prop(soft, "position_solver_iterations", text="Position Solver") + col.prop(soft, "velocity_solver_iterations", text="Velocity Solver") + col.prop(soft, "cluster_solver_iterations", text="Cluster Solver") + col.prop(soft, "drift_solver_iterations", text="Drift Solver") + + col = split.column() + col.label(text="Hardness:") + col.prop(soft, "kchr", text="Rigid Contacts", slider=True) + col.prop(soft, "kkhr", text="Kinetic Contacts", slider=True) + col.prop(soft, "kshr", text="Soft Contacts", slider=True) + col.prop(soft, "kahr", text="Anchors", slider=True) col.label(text="Cluster Collision:") col.prop(soft, "use_cluster_rigid_to_softbody") @@ -157,12 +188,29 @@ def draw(self, context): sub = col.column() sub.active = (soft.use_cluster_rigid_to_softbody or soft.use_cluster_soft_to_softbody) sub.prop(soft, "cluster_iterations", text="Iterations") + sub.prop(soft, "ksrhr_cl", text="Rigid Hardness", slider=True) + sub.prop(soft, "kskhr_cl", text="Kinetic Hardness", slider=True) + sub.prop(soft, "ksshr_cl", text="Soft Hardness", slider=True) + sub.prop(soft, "ksr_split_cl", text="Rigid Impulse Split", slider=True) + sub.prop(soft, "ksk_split_cl", text="Kinetic Impulse Split", slider=True) + sub.prop(soft, "kss_split_cl", text="Soft Impulse Split", slider=True) + + split = layout.split() + + col = split.column() + col.label(text="Volume:") + col.prop(soft, "kpr", text="Pressure Coefficient") + col.prop(soft, "kvc", text="Volume Conservation") + + col = split.column() + col.label(text="Aerodynamics:") + col.prop(soft, "kdg", text="Drag Coefficient") + col.prop(soft, "klf", text="Lift Coefficient") elif physics_type == 'STATIC': col = layout.column() col.prop(game, "use_actor") col.prop(game, "use_ghost") - col.prop(game, "use_record_animation") col.prop(ob, "hide_render", text="Invisible") layout.separator() @@ -172,6 +220,10 @@ def draw(self, context): col = split.column() col.label(text="Attributes:") col.prop(game, "radius") + col.prop(game, "elasticity", slider=True) + col.label(text="Friction:") + col.prop(game, "friction") + col.prop(game, "rolling_friction") col = split.column() sub = col.column() @@ -197,6 +249,18 @@ def draw(self, context): layout.operator("mesh.navmesh_reset") layout.operator("mesh.navmesh_clear") + if physics_type in {"STATIC", "DYNAMIC", "RIGID_BODY"}: + row = layout.row() + row.label(text="Force Field:") + + row = layout.row() + row.prop(game, "fh_force") + row.prop(game, "fh_damping", slider=True) + + row = layout.row() + row.prop(game, "fh_distance") + row.prop(game, "use_fh_normal") + class PHYSICS_PT_game_collision_bounds(PhysicsButtonsPanel, Panel): bl_label = "Collision Bounds" @@ -326,7 +390,6 @@ def draw(self, context): col = layout.column() col.label(text="Quality:") - col.prop(gs, "samples") col = layout.column(align=True) col.prop(gs, "depth", text="Bit Depth", slider=False) col.prop(gs, "frequency", text="Refresh Rate", slider=False) @@ -350,38 +413,6 @@ def draw(self, context): layout.prop(gs, "stereo_mode") layout.prop(gs, "stereo_eye_separation") - # dome: - elif stereo_mode == 'DOME': - layout.prop(gs, "dome_mode", text="Dome Type") - - dome_type = gs.dome_mode - - split = layout.split() - - if dome_type in {'FISHEYE', 'TRUNCATED_REAR', 'TRUNCATED_FRONT'}: - col = split.column() - col.prop(gs, "dome_buffer_resolution", text="Resolution", slider=True) - col.prop(gs, "dome_angle", slider=True) - - col = split.column() - col.prop(gs, "dome_tessellation", text="Tessellation") - col.prop(gs, "dome_tilt") - - elif dome_type == 'PANORAM_SPH': - col = split.column() - col.prop(gs, "dome_buffer_resolution", text="Resolution", slider=True) - - col = split.column() - col.prop(gs, "dome_tessellation", text="Tessellation") - - else: # cube map - col = split.column() - col.prop(gs, "dome_buffer_resolution", text="Resolution", slider=True) - - col = split.column() - - layout.prop(gs, "dome_text") - class RENDER_PT_game_shading(RenderButtonsPanel, Panel): bl_label = "Shading" @@ -391,22 +422,20 @@ def draw(self, context): layout = self.layout gs = context.scene.game_settings + rd = context.scene.render - layout.row().prop(gs, "material_mode", expand=True) - - if gs.material_mode == 'GLSL': - split = layout.split() - - col = split.column() - col.prop(gs, "use_glsl_lights", text="Lights") - col.prop(gs, "use_glsl_shaders", text="Shaders") - col.prop(gs, "use_glsl_shadows", text="Shadows") - col.prop(gs, "use_glsl_environment_lighting", text="Environment Lighting") + split = layout.split() - col = split.column() - col.prop(gs, "use_glsl_ramps", text="Ramps") - col.prop(gs, "use_glsl_nodes", text="Nodes") - col.prop(gs, "use_glsl_extra_textures", text="Extra Textures") + col = split.column() + col.prop(gs, "use_glsl_lights", text="Lights") + col.prop(gs, "use_glsl_shaders", text="Shaders") + col.prop(gs, "use_glsl_shadows", text="Shadows") + col.prop(gs, "use_glsl_environment_lighting", text="Environment Lighting") + col = split.column() + col.prop(gs, "use_glsl_ramps", text="Ramps") + col.prop(gs, "use_glsl_nodes", text="Nodes") + col.prop(gs, "use_glsl_extra_textures", text="Extra Textures") + col.prop(rd, "use_world_space_shading", text="World Space Shading") class RENDER_PT_game_system(RenderButtonsPanel, Panel): @@ -417,25 +446,34 @@ def draw(self, context): layout = self.layout gs = context.scene.game_settings - col = layout.column() - row = col.row() - col = row.column() + split = layout.split(percentage=0.4) + + col = split.column() col.prop(gs, "use_frame_rate") - col.prop(gs, "use_restrict_animation_updates") - col.prop(gs, "use_material_caching") - col = row.column() - col.prop(gs, "use_display_lists") - col.active = gs.raster_storage != 'VERTEX_BUFFER_OBJECT' + col.prop(gs, "use_deprecation_warnings") - row = layout.row() - row.prop(gs, "vsync") + col = split.column() + col.prop(gs, "vsync") + col.prop(gs, "samples") + col.prop(gs, "hdr") row = layout.row() - row.prop(gs, "raster_storage") + col = row.column() + col.label("Exit Key:") + col.prop(gs, "exit_key", text="", event=True) - row = layout.row() - row.label("Exit Key") - row.prop(gs, "exit_key", text="", event=True) + +class RENDER_PT_game_animations(RenderButtonsPanel, Panel): + bl_label = "Animations" + COMPAT_ENGINES = {'BLENDER_GAME'} + + def draw(self, context): + layout = self.layout + + gs = context.scene.game_settings + + layout.prop(context.scene.render, "fps", text="Animation Frame Rate", slider=False) + layout.prop(gs, "use_restrict_animation_updates") class RENDER_PT_game_display(RenderButtonsPanel, Panel): @@ -447,20 +485,46 @@ def draw(self, context): gs = context.scene.game_settings - layout.prop(context.scene.render, "fps", text="Animation Frame Rate", slider=False) - - flow = layout.column_flow() - flow.prop(gs, "show_debug_properties", text="Debug Properties") - flow.prop(gs, "show_framerate_profile", text="Framerate and Profile") - flow.prop(gs, "show_physics_visualization", text="Physics Visualization") - flow.prop(gs, "use_deprecation_warnings") - flow.prop(gs, "show_mouse", text="Mouse Cursor") + col = layout.column() + col.prop(gs, "show_mouse", text="Mouse Cursor") col = layout.column() col.label(text="Framing:") col.row().prop(gs, "frame_type", expand=True) - if gs.frame_type == 'LETTERBOX': - col.prop(gs, "frame_color", text="") + col.prop(gs, "frame_color", text="") + +class RENDER_PT_game_color_management(RenderButtonsPanel, Panel): + bl_label = "Color Management" + COMPAT_ENGINES = {'BLENDER_GAME'} + + def draw(self, context): + layout = self.layout + gs = context.scene.game_settings + + layout.prop(gs, "color_management") + +class RENDER_PT_game_debug(RenderButtonsPanel, Panel): + bl_label = "Debug" + COMPAT_ENGINES = {'BLENDER_GAME'} + + def draw(self, context): + layout = self.layout + + gs = context.scene.game_settings + + split = layout.split(percentage=0.4) + + col = split.column() + col.prop(gs, "show_framerate_profile", text="Framerate and Profile") + col.prop(gs, "show_render_queries", text="Render Queries") + col.prop(gs, "show_debug_properties", text="Properties") + col.prop(gs, "show_physics_visualization", text="Physics Visualization") + + col = split.column() + col.prop(gs, "show_bounding_box", text="Bounding Box") + col.prop(gs, "show_armatures", text="Armatures") + col.prop(gs, "show_camera_frustum", text="Camera Frustum") + col.prop(gs, "show_shadow_frustum", text="Shadow Frustum") class SceneButtonsPanel: @@ -485,6 +549,7 @@ def draw(self, context): layout.prop(gs, "physics_engine", text="Engine") if gs.physics_engine != 'NONE': + layout.prop(gs, "physics_solver") layout.prop(gs, "physics_gravity", text="Gravity") split = layout.split() @@ -494,12 +559,15 @@ def draw(self, context): sub = col.column(align=True) sub.prop(gs, "physics_step_max", text="Max") sub.prop(gs, "physics_step_sub", text="Substeps") - col.prop(gs, "fps", text="FPS") col = split.column() col.label(text="Logic Steps:") col.prop(gs, "logic_step_max", text="Max") + row = layout.row() + row.prop(gs, "fps", text="FPS") + row.prop(gs, "time_scale") + col = layout.column() col.label(text="Physics Deactivation:") sub = col.row(align=True) @@ -508,12 +576,19 @@ def draw(self, context): sub = col.row() sub.prop(gs, "deactivation_time", text="Time") - col = layout.column() + split = layout.split() + + col = split.column() + col.label(text="Culling:") col.prop(gs, "use_occlusion_culling", text="Occlusion Culling") sub = col.column() sub.active = gs.use_occlusion_culling sub.prop(gs, "occlusion_culling_resolution", text="Resolution") + col = split.column() + col.label(text="Object Activity:") + col.prop(gs, "use_activity_culling") + else: split = layout.split() @@ -629,6 +704,57 @@ def draw(self, context): row.prop(gs, "scene_hysteresis_percentage", text="") +class SCENE_PT_game_console(SceneButtonsPanel, Panel): + bl_label = "Python Console" + COMPAT_ENGINES = {'BLENDER_GAME'} + + @classmethod + def poll(cls, context): + scene = context.scene + return (scene and scene.render.engine in cls.COMPAT_ENGINES) + + def draw_header(self, context): + gs = context.scene.game_settings + + self.layout.prop(gs, "use_python_console", text="") + + def draw(self, context): + layout = self.layout + + gs = context.scene.game_settings + row = layout.row(align=True) + row.active = gs.use_python_console + row.label("Keys:") + row.prop(gs, "python_console_key1", text="", event=True) + row.prop(gs, "python_console_key2", text="", event=True) + row.prop(gs, "python_console_key3", text="", event=True) + row.prop(gs, "python_console_key4", text="", event=True) + + +class SCENE_PT_game_audio(SceneButtonsPanel, Panel): + bl_label = "Audio" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_GAME'} + + @classmethod + def poll(cls, context): + scene = context.scene + return (scene and scene.render.engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + + scene = context.scene + + split = layout.split() + + col = layout.column() + col.prop(scene, "audio_distance_model", text="Distance Model") + col = layout.column(align=True) + col.prop(scene, "audio_doppler_speed", text="Speed") + col.prop(scene, "audio_doppler_factor", text="Doppler") + + class WorldButtonsPanel: bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' @@ -671,13 +797,26 @@ def poll(cls, context): def draw(self, context): layout = self.layout + self.layout.template_preview(context.world) + world = context.world + row = layout.row() + row.prop(world, "use_sky_paper") + row.prop(world, "use_sky_blend") + row.prop(world, "use_sky_real") + row = layout.row() row.column().prop(world, "horizon_color") - row.column().prop(world, "zenith_color") + col = row.column() + col.prop(world, "zenith_color") + col.active = world.use_sky_blend row.column().prop(world, "ambient_color") + row = layout.row() + row.prop(world, "exposure") + row.prop(world, "color_range") + class WORLD_PT_game_environment_lighting(WorldButtonsPanel, Panel): bl_label = "Environment Lighting" @@ -767,8 +906,9 @@ def draw(self, context): col = split.column() col.prop(lamp, "shadow_color", text="") - if lamp.type == 'SUN': + if lamp.type in ('SUN', 'SPOT'): col.prop(lamp, "show_shadow_box") + col.prop(lamp, "static_shadow") col = split.column() col.prop(lamp, "use_shadow_layer", text="This Layer Only") @@ -777,11 +917,27 @@ def draw(self, context): col = layout.column() col.label("Buffer Type:") col.prop(lamp, "ge_shadow_buffer_type", text="", toggle=True) + if lamp.ge_shadow_buffer_type == "SIMPLE": + col.label("Filter Type:") + col.prop(lamp, "shadow_filter", text="", toggle=True) + col.label("Quality:") col = layout.column(align=True) col.prop(lamp, "shadow_buffer_size", text="Size") - col.prop(lamp, "shadow_buffer_bias", text="Bias") - col.prop(lamp, "shadow_buffer_bleed_bias", text="Bleed Bias") + if lamp.ge_shadow_buffer_type == "VARIANCE": + col.prop(lamp, "shadow_buffer_sharp", text="Sharpness") + elif lamp.shadow_filter in ("PCF", "PCF_BAIL", "PCF_JITTER"): + col.prop(lamp, "shadow_buffer_samples", text="Samples") + col.prop(lamp, "shadow_buffer_soft", text="Soft") + + row = layout.row() + row.label("Bias:") + row = layout.row(align=True) + row.prop(lamp, "shadow_buffer_bias", text="Bias") + if lamp.ge_shadow_buffer_type == "VARIANCE": + row.prop(lamp, "shadow_buffer_bleed_bias", text="Bleed Bias") + else: + row.prop(lamp, "shadow_buffer_slope_bias", text="Slope Bias") row = layout.row() row.label("Clipping:") @@ -810,6 +966,48 @@ def draw(self, context): layout.operator("object.lod_generate", text="Generate") layout.operator("object.lod_clear_all", text="Clear All", icon='PANEL_CLOSE') +class OBJECT_MT_culling(ObjectButtonsPanel, Panel): + bl_label = "Culling Bounding Volume" + COMPAT_ENGINES = {'BLENDER_GAME'} + + @classmethod + def poll(cls, context): + ob = context.object + return context.scene.render.engine in cls.COMPAT_ENGINES and ob.type not in {'CAMERA', 'EMPTY', 'LAMP'} + + def draw(self, context): + layout = self.layout + game = context.active_object.game + + layout.label(text="Predefined Bound:") + layout.prop(game, "predefined_bound", "") + +class OBJECT_PT_activity_culling(ObjectButtonsPanel, Panel): + bl_label = "Activity Culling" + COMPAT_ENGINES = {'BLENDER_GAME'} + + @classmethod + def poll(cls, context): + ob = context.object + return context.scene.render.engine in cls.COMPAT_ENGINES and ob.type not in {'CAMERA'} + + def draw(self, context): + layout = self.layout + activity = context.object.game.activity_culling + + split = layout.split() + + col = split.column() + col.prop(activity, "use_physics", text="Physics") + sub = col.column() + sub.active = activity.use_physics + sub.prop(activity, "physics_radius") + + col = split.column() + col.prop(activity, "use_logic", text="Logic") + sub = col.column() + sub.active = activity.use_logic + sub.prop(activity, "logic_radius") class OBJECT_PT_levels_of_detail(ObjectButtonsPanel, Panel): bl_label = "Levels of Detail" @@ -817,7 +1015,8 @@ class OBJECT_PT_levels_of_detail(ObjectButtonsPanel, Panel): @classmethod def poll(cls, context): - return context.scene.render.engine in cls.COMPAT_ENGINES + ob = context.object + return context.scene.render.engine in cls.COMPAT_ENGINES and ob.type not in {'CAMERA', 'EMPTY', 'LAMP'} def draw(self, context): layout = self.layout @@ -825,6 +1024,7 @@ def draw(self, context): gs = context.scene.game_settings col = layout.column() + col.prop(ob, "lod_factor", text="Distance Factor") for i, level in enumerate(ob.lod_levels): if i == 0: @@ -861,17 +1061,24 @@ def draw(self, context): RENDER_PT_game_stereo, RENDER_PT_game_shading, RENDER_PT_game_system, + RENDER_PT_game_animations, RENDER_PT_game_display, + RENDER_PT_game_color_management, + RENDER_PT_game_debug, SCENE_PT_game_physics, SCENE_PT_game_physics_obstacles, SCENE_PT_game_navmesh, SCENE_PT_game_hysteresis, + SCENE_PT_game_console, + SCENE_PT_game_audio, WORLD_PT_game_context_world, WORLD_PT_game_world, WORLD_PT_game_environment_lighting, WORLD_PT_game_mist, DATA_PT_shadow_game, OBJECT_MT_lod_tools, + OBJECT_MT_culling, + OBJECT_PT_activity_culling, OBJECT_PT_levels_of_detail, ) diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py index 73740df37e8d..f29dbca94e6f 100644 --- a/release/scripts/startup/bl_ui/properties_material.py +++ b/release/scripts/startup/bl_ui/properties_material.py @@ -513,7 +513,7 @@ def draw(self, context): class MATERIAL_PT_sss(MaterialButtonsPanel, Panel): bl_label = "Subsurface Scattering" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER'} + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} @classmethod def poll(cls, context): @@ -544,22 +544,26 @@ def draw(self, context): split = layout.split() - col = split.column() - col.prop(sss, "ior") - col.prop(sss, "scale") - col.prop(sss, "color", text="") - col.prop(sss, "radius", text="RGB Radius", expand=True) - - col = split.column() - sub = col.column(align=True) - sub.label(text="Blend:") - sub.prop(sss, "color_factor", text="Color") - sub.prop(sss, "texture_factor", text="Texture") - sub.label(text="Scattering Weight:") - sub.prop(sss, "front") - sub.prop(sss, "back") - col.separator() - col.prop(sss, "error_threshold", text="Error") + if context.scene.render.engine != 'BLENDER_GAME': + col = split.column() + col.prop(sss, "ior") + col.prop(sss, "scale") + col.prop(sss, "color", text="") + col.prop(sss, "radius", text="RGB Radius", expand=True) + col = split.column() + sub = col.column(align=True) + sub.label(text="Blend:") + sub.prop(sss, "color_factor", text="Color") + sub.prop(sss, "texture_factor", text="Texture") + sub.label(text="Scattering Weight:") + sub.prop(sss, "front") + sub.prop(sss, "back") + col.separator() + col.prop(sss, "error_threshold", text="Error") + else: + col = split.column() + col.prop(sss, "scale") + col.prop(sss, "radius", text="RGB Radius", expand=True) class MATERIAL_PT_halo(MaterialButtonsPanel, Panel): @@ -660,55 +664,28 @@ def poll(cls, context): def draw(self, context): layout = self.layout - game = context.material.game_settings # don't use node material - - row = layout.row() - row.prop(game, "use_backface_culling") - row.prop(game, "invisible") - row.prop(game, "text") - - row = layout.row() - row.label(text="Alpha Blend:") - row.label(text="Face Orientation:") - row = layout.row() - row.prop(game, "alpha_blend", text="") - row.prop(game, "face_orientation", text="") - - -class MATERIAL_PT_physics(MaterialButtonsPanel, Panel): - bl_label = "Physics" - COMPAT_ENGINES = {'BLENDER_GAME'} - - def draw_header(self, context): - game = context.material.game_settings - self.layout.prop(game, "physics", text="") - - @classmethod - def poll(cls, context): - return context.material and (context.scene.render.engine in cls.COMPAT_ENGINES) - - def draw(self, context): - layout = self.layout - layout.active = context.material.game_settings.physics - - phys = context.material.physics # don't use node material + mat = context.material + game = mat.game_settings # don't use node material split = layout.split() - row = split.row() - row.prop(phys, "friction") - row.prop(phys, "elasticity", slider=True) - - row = layout.row() - row.label(text="Force Field:") - - row = layout.row() - row.prop(phys, "fh_force") - row.prop(phys, "fh_damping", slider=True) - row = layout.row() - row.prop(phys, "fh_distance") - row.prop(phys, "use_fh_normal") + col = split.column() + col.prop(game, "use_backface_culling") + col.prop(game, "invisible") + col.prop(game, "physics") + col.label(text="Face Orientation:") + col.prop(game, "face_orientation", text="") + col.label(text="Alpha Blend:") + col.prop(game, "alpha_blend", text="") + col = split.column() + col.label(text="Constant Values:") + col.prop(mat, "use_constant_material") + col.prop(mat, "use_constant_lamp") + col.prop(mat, "use_constant_texture") + col.prop(mat, "use_constant_texture_uv") + col.prop(mat, "use_constant_world") + col.prop(mat, "use_constant_mist") class MATERIAL_PT_strand(MaterialButtonsPanel, Panel): bl_label = "Strand" @@ -759,7 +736,7 @@ def draw(self, context): class MATERIAL_PT_options(MaterialButtonsPanel, Panel): bl_label = "Options" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER'} @classmethod def poll(cls, context): @@ -807,11 +784,50 @@ def draw(self, context): if simple_material(base_mat): col.prop(mat, "pass_index") +class MATERIAL_PT_game_options(MaterialButtonsPanel, Panel): + bl_label = "Options" + COMPAT_ENGINES = {'BLENDER_GAME'} + + @classmethod + def poll(cls, context): + mat = context.material + engine = context.scene.render.engine + return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + + base_mat = context.material + mat = active_node_mat(base_mat) + + split = layout.split() + + col = split.column() + if simple_material(base_mat): + col.prop(mat, "invert_z") + sub = col.row() + sub.prop(mat, "offset_z") + sub.active = mat.use_transparency and mat.transparency_method == 'Z_TRANSPARENCY' + sub = col.column(align=True) + sub.label(text="Light Group:") + sub.prop(mat, "light_group", text="") + row = sub.row(align=True) + row.active = bool(mat.light_group) + row.prop(mat, "use_light_group_exclusive", text="Exclusive") + row.prop(mat, "use_light_group_local", text="Local") + + col = split.column() + col.prop(mat, "use_mist") + col.prop(mat, "use_vertex_color_paint") + col.prop(mat, "use_vertex_color_light") + col.prop(mat, "use_object_color") + col.prop(mat, "use_instancing") + col.prop(mat, "pass_index") class MATERIAL_PT_shadow(MaterialButtonsPanel, Panel): bl_label = "Shadow" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER'} @classmethod def poll(cls, context): @@ -857,6 +873,33 @@ def draw(self, context): if simple_material(base_mat): col.prop(mat, "use_cast_approximate") +class MATERIAL_PT_game_shadow(MaterialButtonsPanel, Panel): + bl_label = "Shadow" + bl_options = {'DEFAULT_CLOSED'} + COMPAT_ENGINES = {'BLENDER_GAME'} + + @classmethod + def poll(cls, context): + mat = context.material + engine = context.scene.render.engine + return check_material(mat) and (mat.type in {'SURFACE', 'WIRE'}) and (engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + + base_mat = context.material + mat = active_node_mat(base_mat) + + split = layout.split() + + if simple_material(base_mat): + col = split.column() + + col.prop(mat, "use_cast_shadows", text="Cast") + col.prop(mat, "use_cast_shadows_only", text="Cast Only") + + col = split.column() + col.prop(mat, "use_shadows", text="Receive") class MATERIAL_PT_transp_game(MaterialButtonsPanel, Panel): bl_label = "Transparency" @@ -882,6 +925,13 @@ def draw(self, context): layout.active = mat.use_transparency + split = layout.split() + col = split.column() + col.active = mat.use_depth_transparency + col.prop(mat, "depth_transp_factor", text="Depth Factor") + col = split.column() + col.prop(mat, "use_depth_transparency") + if simple_material(base_mat): row = layout.row() row.prop(mat, "transparency_method", expand=True) @@ -1071,10 +1121,11 @@ class MATERIAL_PT_custom_props(MaterialButtonsPanel, PropertyPanel, Panel): MATERIAL_PT_halo, MATERIAL_PT_flare, MATERIAL_PT_game_settings, - MATERIAL_PT_physics, MATERIAL_PT_strand, MATERIAL_PT_options, + MATERIAL_PT_game_options, MATERIAL_PT_shadow, + MATERIAL_PT_game_shadow, MATERIAL_PT_transp_game, MATERIAL_PT_volume_density, MATERIAL_PT_volume_shading, diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py index 9b1f98ec1a4a..dd21ca8f1f69 100644 --- a/release/scripts/startup/bl_ui/properties_scene.py +++ b/release/scripts/startup/bl_ui/properties_scene.py @@ -167,7 +167,7 @@ def _draw_keyframing_setting(context, layout, ks, ksp, label, toggle_prop, prop, class SCENE_PT_keying_sets(SceneButtonsPanel, SceneKeyingSetsPanel, Panel): bl_label = "Keying Sets" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER'} def draw(self, context): layout = self.layout @@ -200,7 +200,7 @@ def draw(self, context): class SCENE_PT_keying_set_paths(SceneButtonsPanel, SceneKeyingSetsPanel, Panel): bl_label = "Active Keying Set" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER'} @classmethod def poll(cls, context): @@ -257,7 +257,7 @@ def draw(self, context): class SCENE_PT_color_management(SceneButtonsPanel, Panel): bl_label = "Color Management" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER'} def draw(self, context): layout = self.layout @@ -282,7 +282,7 @@ def draw(self, context): class SCENE_PT_audio(SceneButtonsPanel, Panel): bl_label = "Audio" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER'} def draw(self, context): layout = self.layout diff --git a/release/scripts/startup/bl_ui/properties_texture.py b/release/scripts/startup/bl_ui/properties_texture.py index 018f3df6f0dd..01c531e4de34 100644 --- a/release/scripts/startup/bl_ui/properties_texture.py +++ b/release/scripts/startup/bl_ui/properties_texture.py @@ -252,7 +252,7 @@ def draw(self, context): class TEXTURE_PT_colors(TextureButtonsPanel, Panel): bl_label = "Colors" bl_options = {'DEFAULT_CLOSED'} - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER'} def draw(self, context): layout = self.layout @@ -528,30 +528,25 @@ def draw_bge(self, context): split = layout.split() - col = split.column() - col.label(text="Alpha:") - col.prop(tex, "use_calculate_alpha", text="Calculate") - col.prop(tex, "invert_alpha", text="Invert") - col = split.column() # Only for Material based textures, not for Lamp/World... if slot and isinstance(idblock, Material): col.prop(tex, "use_normal_map") - row = col.row() - row.active = tex.use_normal_map - row.prop(slot, "normal_map_space", text="") + sub = col.column() + sub.active = tex.use_normal_map + sub.prop(slot, "normal_map_space", text="") - row = col.row() - row.active = not tex.use_normal_map - row.prop(tex, "use_derivative_map") + col = split.column() + col.active = not tex.use_normal_map + col.prop(tex, "use_derivative_map") class TEXTURE_PT_image_mapping(TextureTypePanel, Panel): bl_label = "Image Mapping" bl_options = {'DEFAULT_CLOSED'} tex_type = 'IMAGE' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER'} def draw(self, context): layout = self.layout @@ -622,17 +617,26 @@ def draw(self, context): layout.template_ID(tex, "image", open="image.open") layout.template_image(tex, "image", tex.image_user, compact=True) else: + if env.source == 'REALTIME': + layout.template_ID(tex, "image", new="image.new", open="image.open") + layout.template_image(tex, "image", tex.image_user, compact=True, cubemap=(env.mapping == 'CUBE')) + layout.prop(env, "filtering") + if env.mapping == 'PLANE': + layout.prop(env, "mode") layout.prop(env, "mapping") - if env.mapping == 'PLANE': + + if env.source != 'REALTIME' and env.mapping == 'PLANE': layout.prop(env, "zoom") + layout.prop(env, "viewpoint_object") split = layout.split() col = split.column() col.prop(env, "layers_ignore") - col.prop(env, "resolution") - col.prop(env, "depth") + if env.source != 'REALTIME': + col.prop(env, "resolution") + col.prop(env, "depth") col = split.column(align=True) @@ -640,12 +644,17 @@ def draw(self, context): col.prop(env, "clip_start", text="Start") col.prop(env, "clip_end", text="End") + if env.source == 'REALTIME': + row = layout.row() + row.prop(env, "lod_factor", text="LoD Distance Factor") + row.prop(env, "auto_update") + class TEXTURE_PT_envmap_sampling(TextureTypePanel, Panel): bl_label = "Environment Map Sampling" bl_options = {'DEFAULT_CLOSED'} tex_type = 'ENVIRONMENT_MAP' - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER'} def draw(self, context): layout = self.layout @@ -920,9 +929,80 @@ def draw(self, context): col.prop(ot, "output") +class TEXTURE_PT_game_mapping(TextureSlotPanel, Panel): + bl_label = "Mapping" + COMPAT_ENGINES = {'BLENDER_GAME'} + + @classmethod + def poll(cls, context): + idblock = context_tex_datablock(context) + if isinstance(idblock, Brush) and not context.sculpt_object: + return False + + if not getattr(context, "texture_slot", None): + return False + + engine = context.scene.render.engine + return (engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + + idblock = context_tex_datablock(context) + + tex = context.texture_slot + + if not isinstance(idblock, Brush): + split = layout.split(percentage=0.3) + col = split.column() + col.label(text="Coordinates:") + col = split.column() + col.prop(tex, "texture_coords", text="") + + if tex.texture_coords == 'ORCO': + """ + ob = context.object + if ob and ob.type == 'MESH': + split = layout.split(percentage=0.3) + split.label(text="Mesh:") + split.prop(ob.data, "texco_mesh", text="") + """ + elif tex.texture_coords == 'UV': + split = layout.split(percentage=0.3) + split.label(text="Map:") + ob = context.object + if ob and ob.type == 'MESH': + split.prop_search(tex, "uv_layer", ob.data, "uv_textures", text="") + else: + split.prop(tex, "uv_layer", text="") + + elif tex.texture_coords == 'OBJECT': + split = layout.split(percentage=0.3) + split.label(text="Object:") + split.prop(tex, "object", text="") + + elif tex.texture_coords == 'ALONG_STROKE': + split = layout.split(percentage=0.3) + split.label(text="Use Tips:") + split.prop(tex, "use_tips", text="") + + if isinstance(idblock, Brush): + if context.sculpt_object or context.image_paint_object: + brush_texture_settings(layout, idblock, context.sculpt_object) + else: + split = layout.split() + + col = split.column() + + row = layout.row() + row.column().prop(tex, "offset") + row.column().prop(tex, "scale") + row = layout.row() + row.prop(tex, "rotation") + class TEXTURE_PT_mapping(TextureSlotPanel, Panel): bl_label = "Mapping" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER'} @classmethod def poll(cls, context): @@ -1022,10 +1102,212 @@ def draw(self, context): row.column().prop(tex, "offset") row.column().prop(tex, "scale") +class TEXTURE_PT_color_management(TextureSlotPanel, Panel): + bl_label = "Color Management" + COMPAT_ENGINES = {'BLENDER_GAME'} + + @classmethod + def poll(cls, context): + idblock = context_tex_datablock(context) + if isinstance(idblock, Brush): + return False + + if not getattr(context, "texture_slot", None): + return False + + engine = context.scene.render.engine + + tex = context.texture + if hasattr(tex, "environment_map"): + if tex.environment_map.source == 'REALTIME': + return False + + return (engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + tex = context.texture_slot + + layout.prop(tex, "color_management") + +class TEXTURE_PT_game_parallax(TextureSlotPanel, Panel): + bl_label = "Parallax" + COMPAT_ENGINES = {'BLENDER_GAME'} + + @classmethod + def poll(cls, context): + idblock = context_tex_datablock(context) + if isinstance(idblock, Brush) and not context.sculpt_object: + return False + + if not getattr(context, "texture_slot", None): + return False + + tex = context.texture_slot + + engine = context.scene.render.engine + return (engine in cls.COMPAT_ENGINES and tex.texture_coords == 'UV') + + def draw(self, context): + layout = self.layout + + tex = context.texture_slot + + split = layout.split() + col = split.column() + col.prop(tex, "use_map_parallax") + sub = col.column() + sub.active = not tex.use_map_parallax + sub.prop(tex, "use_parallax_uv") + sub = col.column() + sub.active = tex.use_map_parallax + sub.prop(tex, "parallax_uv_discard", text="Discard Edges") + + col = split.column() + col.active = tex.use_map_parallax + col.prop(tex, "parallax_component", text="") + col.prop(tex, "parallax_steps", text="Steps") + col.prop(tex, "parallax_bump_scale", text="Bump Scale") + +class TEXTURE_PT_game_influence(TextureSlotPanel, Panel): + bl_label = "Influence" + COMPAT_ENGINES = {'BLENDER_GAME'} + + @classmethod + def poll(cls, context): + idblock = context_tex_datablock(context) + if isinstance(idblock, Brush): + return False + + if not getattr(context, "texture_slot", None): + return False + + engine = context.scene.render.engine + return (engine in cls.COMPAT_ENGINES) + + def draw(self, context): + + layout = self.layout + + idblock = context_tex_datablock(context) + + tex = context.texture_slot + + def factor_but(layout, toggle, factor, name): + row = layout.row(align=True) + row.prop(tex, toggle, text="") + sub = row.row(align=True) + sub.active = getattr(tex, toggle) + sub.prop(tex, factor, text=name, slider=True) + return sub # XXX, temp. use_map_normal needs to override. + + if isinstance(idblock, Material): + split = layout.split() + + col = split.column() + col.label(text="Diffuse:") + factor_but(col, "use_map_diffuse", "diffuse_factor", "Intensity") + factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color") + factor_but(col, "use_map_alpha", "alpha_factor", "Alpha") + factor_but(col, "use_map_translucency", "translucency_factor", "Translucency") + + col.label(text="Specular:") + factor_but(col, "use_map_specular", "specular_factor", "Intensity") + factor_but(col, "use_map_color_spec", "specular_color_factor", "Color") + factor_but(col, "use_map_hardness", "hardness_factor", "Hardness") + + col.label(text="Mipmapping:") + col.prop(tex, "lod_bias") + + col = split.column() + col.label(text="Shading:") + factor_but(col, "use_map_ambient", "ambient_factor", "Ambient") + factor_but(col, "use_map_emit", "emit_factor", "Emit") + factor_but(col, "use_map_mirror", "mirror_factor", "Mirror") + factor_but(col, "use_map_raymir", "raymir_factor", "Ray Mirror") + + col.label(text="Geometry:") + # XXX replace 'or' when displacement is fixed to not rely on normal influence value. + sub_tmp = factor_but(col, "use_map_normal", "normal_factor", "Normal") + sub_tmp.active = (tex.use_map_normal or tex.use_map_displacement) + # END XXX + + sub = col.column() + if hasattr(context.texture, "environment_map"): + sub.active = (tex.texture_coords == "REFLECTION" and context.texture.environment_map.mapping == 'CUBE') + else: + sub.active = False + + sub.label(text="Refraction:") + sub.prop(tex, "ior", text="IOR") + sub.prop(tex, "refraction_ratio", text="Ratio") + + elif isinstance(idblock, Lamp): + split = layout.split() + + col = split.column() + factor_but(col, "use_map_color", "color_factor", "Color") + + col = split.column() + factor_but(col, "use_map_shadow", "shadow_factor", "Shadow") + + split = layout.split() + col = split.column() + col.label(text="Mipmapping:") + col.prop(tex, "lod_bias") + col = split.column() + + elif isinstance(idblock, World): + split = layout.split() + + col = split.column() + factor_but(col, "use_map_blend", "blend_factor", "Blend") + factor_but(col, "use_map_horizon", "horizon_factor", "Horizon") + + col = split.column() + factor_but(col, "use_map_zenith_up", "zenith_up_factor", "Zenith Up") + factor_but(col, "use_map_zenith_down", "zenith_down_factor", "Zenith Down") + + split = layout.split() + col = split.column() + col.label(text="Mipmapping:") + col.prop(tex, "lod_bias") + col = split.column() + + if not isinstance(idblock, ParticleSettings): + split = layout.split() + + col = split.column() + col.prop(tex, "blend_type", text="Blend") + col.prop(tex, "use_rgb_to_intensity") + # color is used on gray-scale textures even when use_rgb_to_intensity is disabled. + col.prop(tex, "color", text="") + + col = split.column() + col.prop(tex, "invert", text="Negative") + col.prop(tex, "use_stencil") + + if isinstance(idblock, Material) or isinstance(idblock, World): + col.prop(tex, "default_value", text="DVar", slider=True) + + if isinstance(idblock, Material): + layout.label(text="Bump Mapping:") + + # only show bump settings if activated but not for normal-map images + row = layout.row() + + sub = row.row() + sub.active = (tex.use_map_normal or tex.use_map_warp) and not (tex.texture.type == 'IMAGE' and (tex.texture.use_normal_map or tex.texture.use_derivative_map)) + sub.prop(tex, "bump_method", text="Method") + + # the space setting is supported for: derivative-maps + bump-maps (DEFAULT,BEST_QUALITY), not for normal-maps + sub = row.row() + sub.active = (tex.use_map_normal or tex.use_map_warp) and not (tex.texture.type == 'IMAGE' and tex.texture.use_normal_map) and ((tex.bump_method in {'BUMP_LOW_QUALITY', 'BUMP_MEDIUM_QUALITY', 'BUMP_BEST_QUALITY'}) or (tex.texture.type == 'IMAGE' and tex.texture.use_derivative_map)) + sub.prop(tex, "bump_objectspace", text="Space") class TEXTURE_PT_influence(TextureSlotPanel, Panel): bl_label = "Influence" - COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + COMPAT_ENGINES = {'BLENDER_RENDER'} @classmethod def poll(cls, context): @@ -1087,6 +1369,19 @@ def factor_but(layout, toggle, factor, name): factor_but(col, "use_map_warp", "warp_factor", "Warp") factor_but(col, "use_map_displacement", "displacement_factor", "Displace") + col.label(text="Mipmapping:") + col.prop(tex, "lod_bias") + + sub = col.column() + if hasattr(context.texture, "environment_map"): + sub.active = (tex.texture_coords == "REFLECTION" and context.texture.environment_map.mapping == 'CUBE') + else: + sub.active = False + + sub.label(text="Refraction:") + sub.prop(tex, "ior", text="IOR") + sub.prop(tex, "refraction_ratio", text="Ratio") + # ~ sub = col.column() # ~ sub.active = tex.use_map_translucency or tex.map_emit or tex.map_alpha or tex.map_raymir or tex.map_hardness or tex.map_ambient or tex.map_specularity or tex.map_reflection or tex.map_mirror #~ sub.prop(tex, "default_value", text="Amount", slider=True) @@ -1139,6 +1434,9 @@ def factor_but(layout, toggle, factor, name): col = split.column() factor_but(col, "use_map_shadow", "shadow_factor", "Shadow") + col = split.column() + col.prop(tex, "lod_bias") + elif isinstance(idblock, World): split = layout.split() @@ -1149,6 +1447,9 @@ def factor_but(layout, toggle, factor, name): col = split.column() factor_but(col, "use_map_zenith_up", "zenith_up_factor", "Zenith Up") factor_but(col, "use_map_zenith_down", "zenith_down_factor", "Zenith Down") + + col = split.column() + col.prop(tex, "lod_bias") elif isinstance(idblock, ParticleSettings): split = layout.split() @@ -1263,7 +1564,11 @@ class TEXTURE_PT_custom_props(TextureButtonsPanel, PropertyPanel, Panel): TEXTURE_PT_pointdensity, TEXTURE_PT_pointdensity_turbulence, TEXTURE_PT_ocean, + TEXTURE_PT_game_mapping, TEXTURE_PT_mapping, + TEXTURE_PT_color_management, + TEXTURE_PT_game_parallax, + TEXTURE_PT_game_influence, TEXTURE_PT_influence, TEXTURE_PT_custom_props, ) diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index 9a2215969cfb..4bbfd258aa6b 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -616,7 +616,7 @@ def draw(self, context): sima = context.space_data iuser = sima.image_user - layout.template_image(sima, "image", iuser, multiview=True) + layout.template_image(sima, "image", iuser, multiview=True, color_space=True) class IMAGE_PT_game_properties(Panel): diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py index edae5e2f4528..84e0e813c9f3 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -240,15 +240,32 @@ def draw(self, context): layout.separator() - layout.prop(gs, "show_debug_properties") layout.prop(gs, "show_framerate_profile") - layout.prop(gs, "show_physics_visualization") + layout.prop(gs, "show_render_queries") layout.prop(gs, "use_deprecation_warnings") - layout.prop(gs, "use_animation_record") + layout.menu("INFO_MT_game_show_debug") layout.separator() layout.prop(gs, "use_auto_start") +class INFO_MT_game_show_debug(Menu): + bl_label = "Show Debug" + + def draw(self, context): + layout = self.layout + + gs = context.scene.game_settings + + layout.prop(gs, "show_debug_properties") + layout.prop(gs, "show_physics_visualization") + + layout.separator() + layout.prop_menu_enum(gs, "show_bounding_box") + layout.prop_menu_enum(gs, "show_armatures") + layout.prop_menu_enum(gs, "show_camera_frustum") + layout.prop_menu_enum(gs, "show_shadow_frustum") + + class INFO_MT_render(Menu): bl_label = "Render" @@ -343,8 +360,8 @@ def draw(self, context): layout.separator() layout.operator( - "wm.url_open", text="Python API Reference", icon='URL', - ).url = bpy.types.WM_OT_doc_view._prefix + "wm.url_open", text="Python API Reference", icon='URL', + ).url = "https://pythonapi.upbge.org/" layout.operator("wm.operator_cheat_sheet", icon='TEXT') layout.operator("wm.sysinfo", icon='TEXT') @@ -362,6 +379,7 @@ def draw(self, context): INFO_MT_file_external_data, INFO_MT_file_previews, INFO_MT_game, + INFO_MT_game_show_debug, INFO_MT_render, INFO_MT_opengl_render, INFO_MT_window, diff --git a/release/scripts/startup/bl_ui/space_logic.py b/release/scripts/startup/bl_ui/space_logic.py index b552181f4914..8a424d48c994 100644 --- a/release/scripts/startup/bl_ui/space_logic.py +++ b/release/scripts/startup/bl_ui/space_logic.py @@ -20,6 +20,44 @@ import bpy from bpy.types import Header, Menu, Panel +class LOGIC_PT_components(bpy.types.Panel): + bl_space_type = 'LOGIC_EDITOR' + bl_region_type = 'UI' + bl_label = 'Components' + + @classmethod + def poll(cls, context): + ob = context.active_object + return ob and ob.name + + def draw(self, context): + layout = self.layout + + ob = context.active_object + game = ob.game + + st = context.space_data + + row = layout.row() + row.operator("logic.python_component_register", text="Register Component", icon="ZOOMIN") + row.operator("logic.python_component_create", text="Create Component", icon="ZOOMIN") + + for i, c in enumerate(game.components): + box = layout.box() + row = box.row() + row.prop(c, "show_expanded", text="", emboss=False) + row.label(c.name) + row.operator("logic.python_component_reload", text="", icon='RECOVER_LAST').index = i + row.operator("logic.python_component_remove", text="", icon='X').index = i + + if c.show_expanded and len(c.properties) > 0: + box = box.box() + for prop in c.properties: + row = box.row() + row.label(text=prop.name) + col = row.column() + col.prop(prop, "value", text="") + class LOGIC_PT_properties(Panel): bl_space_type = 'LOGIC_EDITOR' @@ -132,6 +170,7 @@ def draw(self, context): classes = ( + LOGIC_PT_components, LOGIC_PT_properties, LOGIC_MT_logicbricks_add, LOGIC_HT_header, diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 0a365c6a20ca..e33b95134aff 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -1292,6 +1292,7 @@ class INFO_MT_add(Menu): bl_label = "Add" def draw(self, context): + rd = context.scene.render.engine layout = self.layout # note, don't use 'EXEC_SCREEN' or operators wont get the 'v3d' context. @@ -1316,8 +1317,9 @@ def draw(self, context): layout.operator_menu_enum("object.empty_add", "type", text="Empty", icon='OUTLINER_OB_EMPTY') layout.separator() - layout.operator("object.speaker_add", text="Speaker", icon='OUTLINER_OB_SPEAKER') - layout.separator() + if rd != "BLENDER_GAME": + layout.operator("object.speaker_add", text="Speaker", icon='OUTLINER_OB_SPEAKER') + layout.separator() if INFO_MT_camera_add.is_extended(): layout.menu("INFO_MT_camera_add", icon='OUTLINER_OB_CAMERA') @@ -1327,8 +1329,9 @@ def draw(self, context): layout.menu("INFO_MT_lamp_add", icon='OUTLINER_OB_LAMP') layout.separator() - layout.operator_menu_enum("object.effector_add", "type", text="Force Field", icon='OUTLINER_OB_FORCE_FIELD') - layout.separator() + if rd != "BLENDER_GAME": + layout.operator_menu_enum("object.effector_add", "type", text="Force Field", icon='OUTLINER_OB_FORCE_FIELD') + layout.separator() if len(bpy.data.groups) > 10: layout.operator_context = 'INVOKE_REGION_WIN' @@ -3485,6 +3488,7 @@ def draw(self, context): col = layout.column() col.prop(view, "show_only_render") col.prop(view, "show_world") + col.prop(view, "show_mist") col = layout.column() display_all = not view.show_only_render @@ -3577,21 +3581,17 @@ def draw(self, context): view = context.space_data scene = context.scene - gs = scene.game_settings obj = context.object col = layout.column() - if not scene.render.use_shading_nodes: - col.prop(gs, "material_mode", text="") - if view.viewport_shade == 'SOLID': col.prop(view, "show_textured_solid") col.prop(view, "use_matcap") if view.use_matcap: col.template_icon_view(view, "matcap_icon") if view.viewport_shade == 'TEXTURED' or context.mode == 'PAINT_TEXTURE': - if scene.render.use_shading_nodes or gs.material_mode != 'GLSL': + if scene.render.use_shading_nodes: col.prop(view, "show_textured_shadeless") col.prop(view, "show_backface_culling") @@ -3706,8 +3706,10 @@ def draw(self, context): col.label(text="Face Info:") col.prop(mesh, "show_extra_face_area", text="Area") col.prop(mesh, "show_extra_face_angle", text="Angle") - if context.user_preferences.view.show_developer_ui: - layout.prop(mesh, "show_extra_indices") + split = layout.split() + col = split.column() + col.label(text="Vertex Info:") + col.prop(mesh, "show_extra_indices", text="Index") class VIEW3D_PT_view3d_meshstatvis(Panel): diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 4f4190da30b9..90c6006f2d1e 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -149,6 +149,8 @@ def object_shader_nodes_poll(context): ShaderOldNodeCategory("SH_INPUT", "Input", items=[ NodeItem("ShaderNodeMaterial"), NodeItem("ShaderNodeCameraData"), + NodeItem("ShaderNodeObjectData"), + NodeItem("ShaderNodeTime"), NodeItem("ShaderNodeFresnel"), NodeItem("ShaderNodeLayerWeight"), NodeItem("ShaderNodeLampData"), @@ -175,6 +177,7 @@ def object_shader_nodes_poll(context): ShaderOldNodeCategory("SH_OP_VECTOR", "Vector", items=[ NodeItem("ShaderNodeNormal"), NodeItem("ShaderNodeMapping"), + NodeItem("ShaderNodeParallax"), NodeItem("ShaderNodeVectorCurve"), NodeItem("ShaderNodeVectorTransform"), NodeItem("ShaderNodeNormalMap"), @@ -279,6 +282,7 @@ def object_shader_nodes_poll(context): NodeItem("ShaderNodeVectorDisplacement"), NodeItem("ShaderNodeNormalMap"), NodeItem("ShaderNodeNormal"), + NodeItem("ShaderNodeParallax"), NodeItem("ShaderNodeVectorCurve"), NodeItem("ShaderNodeVectorTransform"), ]), diff --git a/release/scripts/templates_py/python_component.py b/release/scripts/templates_py/python_component.py new file mode 100644 index 000000000000..6e170d8fa2ff --- /dev/null +++ b/release/scripts/templates_py/python_component.py @@ -0,0 +1,20 @@ +import bge +from collections import OrderedDict + +class %Name%(bge.types.KX_PythonComponent): + # Put your arguments here of the format ("key", default_value). + # These values are exposed to the UI. + args = OrderedDict([ + ]) + + def start(self, args): + # Put your initialization code here, args stores the values from the UI. + # self.object is the owner object of this component. + # self.object.scene is the main scene. + pass + + def update(self): + # Put your code executed every logic step here. + # self.object is the owner object of this component. + # self.object.scene is the main scene. + pass diff --git a/release/windows/icons/winblender.ico b/release/windows/icons/winblender.ico deleted file mode 100644 index e6b368c562b5..000000000000 Binary files a/release/windows/icons/winblender.ico and /dev/null differ diff --git a/release/windows/icons/winblender.rc b/release/windows/icons/winblender.rc index 244c2cb2e2cd..b0501cf5f6a6 100644 --- a/release/windows/icons/winblender.rc +++ b/release/windows/icons/winblender.rc @@ -10,7 +10,7 @@ 1 RT_MANIFEST "blender.exe.manifest" #endif -APPICON ICON DISCARDABLE "winblender.ico" +APPICON ICON DISCARDABLE "winupbge.ico" BLENDERFILE ICON DISCARDABLE "winblenderfile.ico" IDR_VERSION1 VERSIONINFO @@ -25,11 +25,11 @@ BEGIN BEGIN VALUE "FileVersion", BLEN_VER_RC_STR VALUE "ProductVersion", BLEN_VER_RC_STR - VALUE "CompanyName", "Blender Foundation" - VALUE "FileDescription", "Blender" - VALUE "LegalCopyright", "GPLv2 (Blender Foundation)" - VALUE "OriginalFilename", "blender.exe" - VALUE "ProductName", "Blender" + VALUE "CompanyName", "UPBGE - Blender Fork" + VALUE "FileDescription", "UPBGE" + VALUE "LegalCopyright", "GPLv2" + VALUE "OriginalFilename", "blender-upbge.exe" + VALUE "ProductName", "UPBGE" END END BLOCK "VarFileInfo" diff --git a/release/windows/icons/winupbge.ico b/release/windows/icons/winupbge.ico new file mode 100644 index 000000000000..13c47798b51f Binary files /dev/null and b/release/windows/icons/winupbge.ico differ diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 647291382efc..eb2eec1a7f79 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -47,6 +47,10 @@ void BKE_blender_globals_clear(void); void BKE_blender_version_string( char *version_str, size_t maxncpy, short version, short subversion, bool v_prefix, bool include_subversion); +void BKE_upbge_version_string( + char *version_str, size_t maxncpy, + short version, short subversion, bool v_prefix, bool include_subversion); + void BKE_blender_userdef_data_swap(struct UserDef *userdef_dst, struct UserDef *userdef_src); void BKE_blender_userdef_data_set(struct UserDef *userdef); diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 161152032946..3ae1f110c65e 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -33,6 +33,9 @@ #define BLENDER_MINVERSION 270 #define BLENDER_MINSUBVERSION 6 +#define UPBGE_VERSION 2 +#define UPBGE_SUBVERSION 4 + /* used by packaging tools */ /* can be left blank, otherwise a,b,c... etc with no quotes */ #define BLENDER_VERSION_CHAR @@ -40,5 +43,6 @@ #define BLENDER_VERSION_CYCLE alpha extern char versionstr[]; /* from blender.c */ +extern char upbge_versionstr[]; /* from blender.c */ #endif /* __BKE_BLENDER_VERSION_H__ */ diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index e224155726f2..ff709af0cf85 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -81,6 +81,7 @@ typedef struct Main { struct Main *next, *prev; char name[1024]; /* 1024 = FILE_MAX */ short versionfile, subversionfile; /* see BLENDER_VERSION, BLENDER_SUBVERSION */ + short upbgeversionfile, upbgesubversionfile; short minversionfile, minsubversionfile; uint64_t build_commit_timestamp; /* commit's timestamp from buildinfo */ char build_hash[16]; /* hash from buildinfo */ @@ -142,6 +143,9 @@ typedef struct Main { #define MAIN_VERSION_ATLEAST(main, ver, subver) \ ((main)->versionfile > (ver) || (main->versionfile == (ver) && (main)->subversionfile >= (subver))) +#define MAIN_VERSION_UPBGE_ATLEAST(main, ver, subver) \ + ((main)->upbgeversionfile > (ver) || (main->upbgeversionfile == (ver) && (main)->upbgesubversionfile >= (subver))) + #define MAIN_VERSION_OLDER(main, ver, subver) \ ((main)->versionfile < (ver) || (main->versionfile == (ver) && (main)->subversionfile < (subver))) diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 23ef45416f7e..d63e7533ec11 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -797,6 +797,10 @@ struct ShadeResult; /* 201..700 occupied by other node types, continue from 701 */ #define SH_NODE_BSDF_HAIR_PRINCIPLED 701 +#define SH_NODE_OBJECT 1000 +#define SH_NODE_TIME 1001 +#define SH_NODE_PARALLAX 1002 + /* custom defines options for Material node */ #define SH_NODE_MAT_DIFF 1 #define SH_NODE_MAT_SPEC 2 diff --git a/source/blender/blenkernel/BKE_python_component.h b/source/blender/blenkernel/BKE_python_component.h new file mode 100644 index 000000000000..6381d5ec4bb8 --- /dev/null +++ b/source/blender/blenkernel/BKE_python_component.h @@ -0,0 +1,43 @@ +/** + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Mitchell Stokes, Diego Lopes, Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BKE_PYTHON_COMPONENT_H__ +#define __BKE_PYTHON_COMPONENT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct PythonComponent *BKE_python_component_new(char *import, struct ReportList *reports, struct bContext *context); +struct PythonComponent *BKE_python_component_create_file(char *import, struct ReportList *reports, struct bContext *context); +void BKE_python_component_reload(struct PythonComponent *pc, struct ReportList *reports, struct bContext *context); +void BKE_python_component_copy_list(struct ListBase *lbn, const struct ListBase *lbo); +void BKE_python_component_free(struct PythonComponent *pc); +void BKE_python_component_free_list(struct ListBase *base); + +void *BKE_python_component_argument_dict_new(struct PythonComponent *pc); + +#ifdef __cplusplus +} +#endif + +#endif /* __BKE_PYTHON_COMPONENT_H__ */ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 45f2ac083dd8..8d2d142b2c24 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -40,6 +40,7 @@ set(INC ../nodes ../physics ../render/extern/include + ../windowmanager ../../../intern/ghost ../../../intern/guardedalloc ../../../intern/glew-mx @@ -56,6 +57,7 @@ set(INC set(INC_SYS ${GLEW_INCLUDE_PATH} ${ZLIB_INCLUDE_DIRS} + ${PYTHON_INCLUDE_DIRS} ) set(SRC @@ -163,6 +165,7 @@ set(SRC intern/pbvh_bmesh.c intern/pointcache.c intern/property.c + intern/python_component.c intern/report.c intern/rigidbody.c intern/sca.c @@ -282,6 +285,7 @@ set(SRC BKE_pbvh.h BKE_pointcache.h BKE_property.h + BKE_python_component.h BKE_report.h BKE_rigidbody.h BKE_sca.h diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index ba20dbaddb0a..2f5cb9e9deb9 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -73,6 +73,7 @@ Global G; UserDef U; char versionstr[48] = ""; +char upbge_versionstr[48] = ""; /* ********** free ********** */ @@ -117,6 +118,18 @@ void BKE_blender_version_string(char *version_str, size_t maxncpy, short version } } +void BKE_upbge_version_string(char *version_str, size_t maxncpy, short version, short subversion, bool v_prefix, bool include_subversion) +{ + const char *prefix = v_prefix ? "v" : ""; + + if (include_subversion) { + BLI_snprintf(version_str, maxncpy, "%s0.%d.%d", prefix, version, subversion); + } + else { + BLI_snprintf(version_str, maxncpy, "%s0.%d", prefix, version); + } +} + void BKE_blender_globals_init(void) { memset(&G, 0, sizeof(Global)); @@ -128,6 +141,7 @@ void BKE_blender_globals_init(void) strcpy(G.ima, "//"); BKE_blender_version_string(versionstr, sizeof(versionstr), BLENDER_VERSION, BLENDER_SUBVERSION, true, true); + BKE_upbge_version_string(upbge_versionstr, sizeof(versionstr), UPBGE_VERSION, UPBGE_SUBVERSION, true, true); #ifndef WITH_PYTHON_SECURITY /* default */ G.f |= G_SCRIPT_AUTOEXEC; diff --git a/source/blender/blenkernel/intern/bullet.c b/source/blender/blenkernel/intern/bullet.c index 9630ee389fa8..b495585a3f4e 100644 --- a/source/blender/blenkernel/intern/bullet.c +++ b/source/blender/blenkernel/intern/bullet.c @@ -84,6 +84,7 @@ BulletSoftBody *bsbNew(void) bsb->collisionflags = 0; //bsb->collisionflags = OB_BSB_COL_CL_RS + OB_BSB_COL_CL_SS; bsb->numclusteriterations = 64; + bsb->bending_dist = 2; bsb->welding = 0.f; return bsb; diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index bda26c958157..22be41dfb2ae 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -70,7 +70,9 @@ void BKE_camera_init(Camera *cam) cam->drawsize = 0.5f; cam->ortho_scale = 6.0; cam->flag |= CAM_SHOWPASSEPARTOUT; + cam->gameflag = GAME_CAM_OBJECT_ACTIVITY_CULLING; cam->passepartalpha = 0.5f; + cam->lodfactor = 1.0f; GPU_fx_compositor_init_dof_settings(&cam->gpu_dof); @@ -79,6 +81,10 @@ void BKE_camera_init(Camera *cam) cam->stereo.convergence_distance = 30.f * 0.065f; cam->stereo.pole_merge_angle_from = DEG2RADF(60.0f); cam->stereo.pole_merge_angle_to = DEG2RADF(75.0f); + + /* game viewport */ + cam->gameviewport.rightratio = 1.0f; + cam->gameviewport.topratio = 1.0f; } void *BKE_camera_add(Main *bmain, const char *name) diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c index b8ebdd9cda54..387bb2b0dfec 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -84,6 +84,8 @@ void BKE_lamp_init(Lamp *la) la->coeff_lin = 0.0f; la->coeff_quad = 0.0f; la->curfalloff = curvemapping_add(1, 0.0f, 1.0f, 1.0f, 0.0f); + la->radius = 8.0f; + la->cutoff = 0.001f; la->sun_effect_type = 0; la->horizon_brightness = 1.0; la->spread = 1.0; diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index d59658a2a078..eee8a67971b7 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -500,8 +500,6 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call BKE_rigidbody_world_id_loop(scene->rigidbody_world, library_foreach_rigidbodyworldSceneLooper, &data); } - CALLBACK_INVOKE(scene->gm.dome.warptext, IDWALK_CB_NOP); - break; } diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 91658a140f04..6aa370b8d1e8 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -108,6 +108,7 @@ void BKE_material_free(Material *ma) MEM_SAFE_FREE(ma->texpaintslot); GPU_material_free(&ma->gpumaterial); + GPU_material_free(&ma->gpumaterialinstancing); BKE_icon_id_delete((ID *)ma); BKE_previewimg_free(&ma->preview); @@ -131,7 +132,6 @@ void BKE_material_init(Material *ma) ma->flaresize = ma->subsize = 1.0; ma->flareboost = 1; ma->seed2 = 6; - ma->friction = 0.5; ma->refrac = 4.0; ma->roughness = 0.5; ma->param[0] = 0.5; @@ -202,10 +202,14 @@ void BKE_material_init(Material *ma) ma->game.alpha_blend = 0; ma->game.face_orientation = 0; + ma->depthtranspfactor = 1.0f; + ma->mode = MA_TRACEBLE | MA_SHADBUF | MA_SHADOW | MA_RAYBIAS | MA_TANGENT_STR | MA_ZTRANSP; ma->mode2 = MA_CASTSHADOW; ma->shade_flag = MA_APPROX_OCCLUSION; ma->preview = NULL; + + ma->constflag = MA_CONSTANT_MATERIAL | MA_CONSTANT_LAMP | MA_CONSTANT_TEXTURE | MA_CONSTANT_TEXTURE_UV | MA_CONSTANT_WORLD | MA_CONSTANT_MIST; } Material *BKE_material_add(Main *bmain, const char *name) @@ -255,6 +259,7 @@ void BKE_material_copy_data(Main *bmain, Material *ma_dst, const Material *ma_sr else { ma_dst->preview = NULL; } + BLI_listbase_clear(&ma_dst->gpumaterialinstancing); if (ma_src->texpaintslot != NULL) { ma_dst->texpaintslot = MEM_dupallocN(ma_src->texpaintslot); @@ -303,6 +308,7 @@ Material *BKE_material_localize(Material *ma) man->nodetree = ntreeLocalize(ma->nodetree); BLI_listbase_clear(&man->gpumaterial); + BLI_listbase_clear(&man->gpumaterialinstancing); return man; } @@ -1837,7 +1843,6 @@ static void decode_tfaceflag(Material *ma, int flag, int convertall) /* Special Face Properties */ if ((flag & TF_TWOSIDE) == 0) (*game).flag |= GEMAT_BACKCULL; if (flag & TF_INVISIBLE) (*game).flag |= GEMAT_INVISIBLE; - if (flag & TF_BMFONT) (*game).flag |= GEMAT_TEXT; /* Face Orientation */ if (flag & TF_BILLBOARD) (*game).face_orientation |= GEMAT_HALO; diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index c830917a547d..bf70ae6060a8 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -3566,6 +3566,8 @@ static void registerShaderNodes(void) register_node_type_sh_output(); register_node_type_sh_material(); register_node_type_sh_camera(); + register_node_type_sh_object(); + register_node_type_sh_time(); register_node_type_sh_lamp(); register_node_type_sh_gamma(); register_node_type_sh_brightcontrast(); @@ -3581,6 +3583,7 @@ static void registerShaderNodes(void) register_node_type_sh_normal(); register_node_type_sh_geom(); register_node_type_sh_mapping(); + register_node_type_sh_parallax(); register_node_type_sh_curve_vec(); register_node_type_sh_curve_rgb(); register_node_type_sh_math(); diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 0cf2993133cc..f5a022dbabb1 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -117,6 +117,7 @@ #include "BKE_material.h" #include "BKE_camera.h" #include "BKE_image.h" +#include "BKE_python_component.h" #ifdef WITH_MOD_FLUID #include "LBM_fluidsim.h" @@ -432,6 +433,7 @@ void BKE_object_free(Object *ob) free_sensors(&ob->sensors); free_controllers(&ob->controllers); free_actuators(&ob->actuators); + BKE_python_component_free_list(&ob->components); BKE_constraints_free_ex(&ob->constraints, false); @@ -645,7 +647,9 @@ void BKE_object_init(Object *ob) ob->anisotropicFriction[1] = 1.0f; ob->anisotropicFriction[2] = 1.0f; ob->gameflag = OB_PROP | OB_COLLISION; + ob->gameflag2 = 0; ob->margin = 0.04f; + ob->friction = 0.5; ob->init_state = 1; ob->state = 1; ob->obstacleRad = 1.0f; @@ -653,8 +657,10 @@ void BKE_object_init(Object *ob) ob->jump_speed = 10.0f; ob->fall_speed = 55.0f; ob->max_jumps = 1; + ob->max_slope = M_PI_2; ob->col_group = 0x01; ob->col_mask = 0xffff; + ob->lodfactor = 1.0f; ob->preview = NULL; /* NT fluid sim defaults */ @@ -1149,6 +1155,7 @@ void BKE_object_copy_data(Main *UNUSED(bmain), Object *ob_dst, const Object *ob_ BKE_bproperty_copy_list(&ob_dst->prop, &ob_src->prop); BKE_sca_logic_copy(ob_dst, ob_src, flag_subdata); + BKE_python_component_copy_list(&ob_dst->components, &ob_src->components); if (ob_src->pose) { copy_object_pose(ob_dst, ob_src, flag_subdata); diff --git a/source/blender/blenkernel/intern/python_component.c b/source/blender/blenkernel/intern/python_component.c new file mode 100644 index 000000000000..803395cc1b43 --- /dev/null +++ b/source/blender/blenkernel/intern/python_component.c @@ -0,0 +1,698 @@ +/** + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Mitchell Stokes, Diego Lopes, Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "DNA_python_component_types.h" +#include "DNA_property_types.h" /* For MAX_PROPSTRING */ +#include "DNA_windowmanager_types.h" +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_path_util.h" +#include "BLI_fileops.h" +#include "MEM_guardedalloc.h" + +#include "BKE_python_component.h" +#include "BKE_report.h" +#include "BKE_context.h" +#include "BKE_main.h" +#include "BKE_text.h" +#include "BKE_appdir.h" + +#include "RNA_types.h" + +#ifdef WITH_PYTHON +#include "Python.h" +#include "generic/py_capi_utils.h" +#endif + +#include + +#ifdef WITH_PYTHON + +PyDoc_STRVAR(class_documentation, +"This is the fake BGE class KX_PythonComponent from fake BGE module bge.types" +); + +static PyTypeObject PythonComponentType = { + PyVarObject_HEAD_INIT(NULL, 0) + "KX_PythonComponent", /* tp_name */ + sizeof(PyObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)NULL, /* tp_dealloc */ + NULL, /* tp_print */ + NULL, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + (reprfunc)NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + (hashfunc)NULL, /* tp_hash */ + NULL, /* tp_call */ + NULL, /* tp_str */ + NULL, /* tp_getattro */ + NULL, /* tp_setattro */ + NULL, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + class_documentation, /* tp_doc */ + (traverseproc)NULL, /* tp_traverse */ + (inquiry)NULL, /* tp_clear */ + (richcmpfunc)NULL, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + NULL, /* tp_iter */ + NULL, /* tp_iternext */ + NULL, /* tp_methods */ + NULL, /* tp_members */ + NULL, /* tp_getset */ + NULL, /* tp_base */ + NULL, /* tp_dict */ + NULL, /* tp_descr_get */ + NULL, /* tp_descr_set */ + 0, /* tp_dictoffset */ + NULL, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ + NULL, /* tp_free */ + NULL, /* tp_is_gc */ + NULL, /* tp_bases */ + NULL, /* tp_mro */ + NULL, /* tp_cache */ + NULL, /* tp_subclasses */ + NULL, /* tp_weaklist */ + NULL /* tp_del */ +}; + +PyDoc_STRVAR(module_documentation, +"This is the fake BGE API module used only to import the KX_PythonComponent class from bge.types.KX_PythonComponent" +); + +static struct PyModuleDef bge_module_def = { + PyModuleDef_HEAD_INIT, /* m_base */ + "bge", /* m_name */ + module_documentation, /* m_doc */ + 0, /* m_size */ + NULL, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; + +static struct PyModuleDef bge_types_module_def = { + PyModuleDef_HEAD_INIT, /* m_base */ + "types", /* m_name */ + module_documentation, /* m_doc */ + 0, /* m_size */ + NULL, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; + +static int verify_class(PyObject *cls) +{ + return PyType_IsSubtype((PyTypeObject *)cls, &PythonComponentType); +} + +static PythonComponentProperty *create_property(char *name) +{ + PythonComponentProperty *cprop; + + cprop = MEM_callocN(sizeof(PythonComponentProperty), "PythonComponentProperty"); + BLI_strncpy(cprop->name, name, sizeof(cprop->name)); + + return cprop; +} + +#endif + +static PythonComponentProperty *copy_property(PythonComponentProperty *cprop) +{ + PythonComponentProperty *cpropn; + + cpropn = MEM_dupallocN(cprop); + + BLI_duplicatelist(&cpropn->enumval, &cprop->enumval); + for (LinkData *link = cpropn->enumval.first; link; link = link->next) { + link->data = MEM_dupallocN(link->data); + } + + return cpropn; +} + +static void free_property(PythonComponentProperty *cprop) +{ + for (LinkData *link = cprop->enumval.first; link; link = link->next) { + MEM_freeN(link->data); + } + BLI_freelistN(&cprop->enumval); + MEM_freeN(cprop); +} + +static void free_properties(ListBase *lb) +{ + PythonComponentProperty *cprop; + + while ((cprop = lb->first)) { + BLI_remlink(lb, cprop); + free_property(cprop); + } +} + +#ifdef WITH_PYTHON +static void create_properties(PythonComponent *pycomp, PyObject *cls) +{ + PyObject *args_dict, *pyitems; + ListBase properties; + memset(&properties, 0, sizeof(ListBase)); + + args_dict = PyObject_GetAttrString(cls, "args"); + + // If there is no args dict, then we are already done + if (!args_dict || !PyDict_Check(args_dict)) { + Py_XDECREF(args_dict); + return; + } + + // Otherwise, parse the dict: + // key => value + // key = property name + // value = default value + // type(value) = property type + pyitems = PyMapping_Items(args_dict); + + for (unsigned int i = 0, size = PyList_Size(pyitems); i < size; ++i) { + PythonComponentProperty *cprop; + char name[64]; + bool free = false; + PyObject *pyitem = PyList_GetItem(pyitems, i); + PyObject *pykey = PyTuple_GetItem(pyitem, 0); + PyObject *pyvalue = PyTuple_GetItem(pyitem, 1); + + // Make sure type(key) == string + if (!PyUnicode_Check(pykey)) { + printf("Non-string key found in the args dictionary, skipping\n"); + continue; + } + + BLI_strncpy(name, _PyUnicode_AsString(pykey), sizeof(name)); + + cprop = create_property(name); + + // Determine the type and default value + if (PyBool_Check(pyvalue)) { + cprop->type = CPROP_TYPE_BOOLEAN; + cprop->boolval = PyLong_AsLong(pyvalue) != 0; + } + else if (PyLong_Check(pyvalue)) { + cprop->type = CPROP_TYPE_INT; + cprop->intval = PyLong_AsLong(pyvalue); + } + else if (PyFloat_Check(pyvalue)) { + cprop->type = CPROP_TYPE_FLOAT; + cprop->floatval = (float)PyFloat_AsDouble(pyvalue); + } + else if (PyUnicode_Check(pyvalue)) { + cprop->type = CPROP_TYPE_STRING; + BLI_strncpy((char*)cprop->strval, _PyUnicode_AsString(pyvalue), MAX_PROPSTRING); + } + else if (PySet_Check(pyvalue)) { + PyObject *iterator = PyObject_GetIter(pyvalue), *v = NULL; + unsigned int j = 0; + cprop->type = CPROP_TYPE_SET; + + memset(&cprop->enumval, 0, sizeof(ListBase)); + // Iterate to convert every enums to char. + while ((v = PyIter_Next(iterator))) { + if (!PyUnicode_Check(v)) { + printf("Enum property \"%s\" contains a non-string item (%u)\n", name, j); + continue; + } + + LinkData *link = MEM_callocN(sizeof(LinkData), "PythonComponentProperty set link data"); + char *str = MEM_callocN(MAX_PROPSTRING, "PythonComponentProperty set string"); + BLI_strncpy(str, _PyUnicode_AsString(v), MAX_PROPSTRING); + + link->data = str; + BLI_addtail(&cprop->enumval, link); + + Py_DECREF(v); + ++j; + } + Py_DECREF(iterator); + cprop->itemval = 0; + } + else if (PySequence_Check(pyvalue)) { + int len = PySequence_Size(pyvalue); + switch (len) { + case 2: + cprop->type = CPROP_TYPE_VEC2; + break; + case 3: + cprop->type = CPROP_TYPE_VEC3; + break; + case 4: + cprop->type = CPROP_TYPE_VEC4; + break; + default: + printf("Sequence property \"%s\" length %i out of range [2, 4]\n", name, len); + free = true; + break; + } + + if (!free) { + for (unsigned int j = 0; j < len; ++j) { + PyObject *item = PySequence_GetItem(pyvalue, j); + if (PyFloat_Check(item)) { + cprop->vec[j] = PyFloat_AsDouble(item); + } + else { + printf("Sequence property \"%s\" contains a non-float item (%u)\n", name, j); + } + Py_DECREF(item); + } + } + } + else { + // Unsupported type + printf("Unsupported type %s found for property \"%s\", skipping\n", Py_TYPE(pyvalue)->tp_name, name); + free = true; + } + + if (free) { + free_property(cprop); + continue; + } + + bool found = false; + for (PythonComponentProperty *propit = pycomp->properties.first; propit; propit = propit->next) { + if ((strcmp(propit->name, cprop->name) == 0) && propit->type == cprop->type) { + /* We never reuse a enum property because we don't know if one of the + * enum value was modified and it easier to just copy the current item + * index than the list. + */ + if (cprop->type == CPROP_TYPE_SET) { + /* Unfortunatly the python type set doesn't repect an order even with same + * content. To solve that we iterate on all new enums and find the coresponding + * index for the old enum name. + */ + char *str = ((LinkData *)BLI_findlink(&propit->enumval, propit->itemval))->data; + int j = 0; + for (LinkData *link = cprop->enumval.first; link; link = link->next) { + if (strcmp(link->data, str) == 0) { + cprop->itemval = j; + } + ++j; + } + break; + } + /* We found a coresponding property in the old component, so the new one + * is released, the old property is removed from the original list and + * added to the new list. + */ + free_property(cprop); + /* The exisiting property is removed to allow at the end free properties + * that are no longuer used. + */ + BLI_remlink(&pycomp->properties, propit); + BLI_addtail(&properties, propit); + found = true; + break; + } + } + // If no exisiting property was found we add it simply. + if (!found) { + BLI_addtail(&properties, cprop); + } + } + + // Free properties no used in the new component. + for (PythonComponentProperty *propit = pycomp->properties.first; propit;) { + PythonComponentProperty *prop = propit; + propit = propit->next; + free_property(prop); + } + // Set the new property list. + pycomp->properties = properties; + +} +#endif /* WITH_PYTHON */ + +static bool load_component(PythonComponent *pc, ReportList *reports, Main *maggie) +{ +#ifdef WITH_PYTHON + + /* Macro used to release all python variable if the convertion fail or succeed. + * The "value" argument is false on failure and true on succes. + */ + #define FINISH(value) \ + PyErr_Print(); \ + if (mod) { \ + /* Take the module out of the module list so it's not cached \ + by Python (this allows for simpler reloading of components)*/ \ + PyDict_DelItemString(sys_modules, pc->module); \ + } \ + Py_XDECREF(mod); \ + Py_XDECREF(item); \ + PyDict_DelItemString(sys_modules, "bge"); \ + PyDict_DelItemString(sys_modules, "bge.types"); \ + BLI_split_dir_part(maggie->name, path, sizeof(path)); \ + pypath = PyC_UnicodeFromByte(path); \ + index = PySequence_Index(sys_path, pypath); \ + /* Safely remove the value by finding their index. */ \ + if (index != -1) { \ + PySequence_DelItem(sys_path, index); \ + } \ + Py_DECREF(pypath); \ + for (Library *lib = (Library *)maggie->library.first; lib; lib = (Library *)lib->id.next) { \ + BLI_split_dir_part(lib->filepath, path, sizeof(path)); \ + pypath = PyC_UnicodeFromByte(path); \ + index = PySequence_Index(sys_path, pypath); \ + /* Safely remove the value by finding their index. */ \ + if (index != -1) { \ + PySequence_DelItem(sys_path, index); \ + } \ + Py_DECREF(pypath); \ + } \ + PyGILState_Release(state); \ + return value; + + PyObject *mod, *item = NULL, *sys_path, *pypath, *sys_modules, *bgemod, *bgesubmod; + PyGILState_STATE state; + char path[FILE_MAX]; + int index; + + state = PyGILState_Ensure(); + + // Set the current file directory do import path to allow extern modules. + sys_path = PySys_GetObject("path"); + /* Add to sys.path the path to all the used library to follow game engine sys.path management. + * These path are remove later in FINISH. */ + for (Library *lib = (Library *)maggie->library.first; lib; lib = (Library *)lib->id.next) { + BLI_split_dir_part(lib->filepath, path, sizeof(path)); + pypath = PyC_UnicodeFromByte(path); + PyList_Insert(sys_path, 0, pypath); + Py_DECREF(pypath); + } + /* Add default path */ + BLI_split_dir_part(maggie->name, path, sizeof(path)); + pypath = PyC_UnicodeFromByte(path); + PyList_Insert(sys_path, 0, pypath); + Py_DECREF(pypath); + + // Setup BGE fake module and submodule. + sys_modules = PyThreadState_GET()->interp->modules; + bgemod = PyModule_Create(&bge_module_def); + bgesubmod = PyModule_Create(&bge_types_module_def); + + PyModule_AddObject(bgemod, "types", bgesubmod); + PyType_Ready(&PythonComponentType); + PyModule_AddObject(bgesubmod, "KX_PythonComponent", (PyObject *)&PythonComponentType); + + PyDict_SetItemString(sys_modules, "bge", bgemod); + PyDict_SetItemString(sys_modules, "bge.types", bgesubmod); + PyDict_SetItemString(PyModule_GetDict(bgemod), "__component__", Py_True); + + // Try to load up the module + mod = PyImport_ImportModule(pc->module); + + if (!mod) { + BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, "No module named \"%s\" or script error at loading.", pc->module); + FINISH(false); + } + else if (strlen(pc->module) > 0 && strlen(pc->name) == 0) { + BKE_report(reports, RPT_ERROR_INVALID_INPUT, "No component class was specified, only the module was."); + FINISH(false); + } + + item = PyObject_GetAttrString(mod, pc->name); + if (!item) { + BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, "No class named %s was found.", pc->name); + FINISH(false); + } + + // Check the subclass with our own function since we don't have access to the KX_PythonComponent type object + if (!verify_class(item)) { + BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, "A %s type was found, but it was not a valid subclass of KX_PythonComponent.", pc->name); + FINISH(false); + } + else { + // Setup the properties + create_properties(pc, item); + } + + FINISH(true); + + #undef ERROR + +#else + + (void)pc; + (void)reports; + (void)maggie; + + return true; + +#endif /* WITH_PYTHON */ +} + +PythonComponent *BKE_python_component_new(char *import, ReportList *reports, bContext *context) +{ + char *classname; + char *modulename; + PythonComponent *pc; + + // Don't bother with an empty string + if (strcmp(import, "") == 0) { + BKE_report(reports, RPT_ERROR_INVALID_INPUT, "No component was specified."); + return NULL; + } + + // Extract the module name and the class name. + modulename = strtok(import, "."); + classname = strtok(NULL, "."); + + pc = MEM_callocN(sizeof(PythonComponent), "PythonComponent"); + + // Copy module and class names. + strcpy(pc->module, modulename); + if (classname) { + strcpy(pc->name, classname); + } + + // Try load the component. + if (!load_component(pc, reports, CTX_data_main(context))) { + BKE_python_component_free(pc); + return NULL; + } + + return pc; +} + +PythonComponent *BKE_python_component_create_file(char *import, ReportList *reports, bContext *context) +{ + char *classname; + char *modulename; + char filename[FILE_MAX]; + char respath[FILE_MAX]; + size_t filesize = 0; + unsigned char *orgfilecontent; + char *filecontent; + Main *maggie = CTX_data_main(context); + struct Text *text; + PythonComponent *pc; + + // Don't bother with an empty string + if (strcmp(import, "") == 0) { + BKE_report(reports, RPT_ERROR_INVALID_INPUT, "No component was specified."); + return NULL; + } + + // Extract the module name and the class name. + modulename = strtok(import, "."); + classname = strtok(NULL, "."); + + if (!classname) { + BKE_report(reports, RPT_ERROR_INVALID_INPUT, "No component class name was specified."); + return NULL; + } + + strcpy(filename, modulename); + BLI_path_extension_ensure(filename, FILE_MAX, ".py"); + + if (BLI_findstring(&maggie->text, filename, offsetof(ID, name) + 2)) { + BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, "File %s already exists.", filename); + return NULL; + } + + text = BKE_text_add(maggie, filename); + + BLI_strncpy(respath, BKE_appdir_folder_id(BLENDER_SYSTEM_SCRIPTS, "templates_py"), sizeof(respath)); + BLI_path_append(respath, sizeof(respath), "python_component.py"); + + orgfilecontent = BLI_file_read_text_as_mem(respath, 0, &filesize); + orgfilecontent[filesize] = '\0'; + + filecontent = BLI_str_replaceN((char *)orgfilecontent, "%Name%", classname); + + BKE_text_write(text, NULL, (char *)filecontent); + + MEM_freeN(filecontent); + + pc = MEM_callocN(sizeof(PythonComponent), "PythonComponent"); + + // Copy module and class names. + strcpy(pc->module, modulename); + if (classname) { + strcpy(pc->name, classname); + } + + // Try load the component. + if (!load_component(pc, reports, CTX_data_main(context))) { + BKE_python_component_free(pc); + return NULL; + } + + BKE_reportf(reports, RPT_INFO, "File %s created.", filename); + + return pc; +} + +void BKE_python_component_reload(PythonComponent *pc, ReportList *reports, bContext *context) +{ + load_component(pc, reports, CTX_data_main(context)); +} + +static PythonComponent *copy_component(PythonComponent *comp) +{ + PythonComponent *compn; + PythonComponentProperty *cprop, *cpropn; + + compn = MEM_dupallocN(comp); + + BLI_listbase_clear(&compn->properties); + cprop = comp->properties.first; + while (cprop) { + cpropn = copy_property(cprop); + BLI_addtail(&compn->properties, cpropn); + cprop = cprop->next; + } + + return compn; +} + +void BKE_python_component_copy_list(ListBase *lbn, const ListBase *lbo) +{ + PythonComponent *comp, *compn; + + lbn->first = lbn->last = NULL; + comp = lbo->first; + while (comp) { + compn = copy_component(comp); + BLI_addtail(lbn, compn); + comp = comp->next; + } +} + +void BKE_python_component_free(PythonComponent *pc) +{ + free_properties(&pc->properties); + + MEM_freeN(pc); +} + +void BKE_python_component_free_list(ListBase *lb) +{ + PythonComponent *pc; + + while ((pc = lb->first)) { + BLI_remlink(lb, pc); + BKE_python_component_free(pc); + } +} + +void *BKE_python_component_argument_dict_new(PythonComponent *pc) +{ +#ifdef WITH_PYTHON + PythonComponentProperty *cprop = (PythonComponentProperty *)pc->properties.first; + PyObject *args = PyDict_New(); + + while (cprop) { + PyObject *value; + if (cprop->type == CPROP_TYPE_INT) { + value = PyLong_FromLong(cprop->intval); + } + else if (cprop->type == CPROP_TYPE_FLOAT) { + value = PyFloat_FromDouble(cprop->floatval); + } + else if (cprop->type == CPROP_TYPE_BOOLEAN) { + value = PyBool_FromLong(cprop->boolval); + } + else if (cprop->type == CPROP_TYPE_STRING) { + value = PyUnicode_FromString(cprop->strval); + } + else if (cprop->type == CPROP_TYPE_SET) { + LinkData *link = BLI_findlink(&cprop->enumval, cprop->itemval); + value = PyUnicode_FromString(link->data); + } + else if (cprop->type == CPROP_TYPE_VEC2 || + cprop->type == CPROP_TYPE_VEC3 || + cprop->type == CPROP_TYPE_VEC4) + { + int size; + switch (cprop->type) { + case CPROP_TYPE_VEC2: + size = 2; + break; + case CPROP_TYPE_VEC3: + size = 3; + break; + case CPROP_TYPE_VEC4: + size = 4; + break; + } + value = PyList_New(size); + // Fill the vector list. + for (unsigned int i = 0; i < size; ++i) { + PyList_SetItem(value, i, PyFloat_FromDouble(cprop->vec[i])); + } + } + else { + cprop = cprop->next; + continue; + } + + PyDict_SetItemString(args, cprop->name, value); + + cprop = cprop->next; + } + + return args; + +#else + + (void)pc; + + return NULL; + +#endif /* WITH_PYTHON */ +} diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c index 56e64387096c..711c4ed8c264 100644 --- a/source/blender/blenkernel/intern/sca.c +++ b/source/blender/blenkernel/intern/sca.c @@ -107,6 +107,7 @@ void init_sensor(bSensor *sens) bMouseSensor *ms; bJoystickSensor *js; bRaySensor *rs; + bMovementSensor *movs; if (sens->data) MEM_freeN(sens->data); sens->data= NULL; @@ -139,6 +140,7 @@ void init_sensor(bSensor *sens) case SENS_MOUSE: ms=sens->data= MEM_callocN(sizeof(bMouseSensor), "mousesens"); ms->type= 1; // LEFTMOUSE workaround because Mouse Sensor types enum starts in 1 + ms->mask = (1 << OB_MAX_COL_MASKS) - 1; break; case SENS_COLLISION: sens->data= MEM_callocN(sizeof(bCollisionSensor), "colsens"); @@ -149,10 +151,16 @@ void init_sensor(bSensor *sens) case SENS_RANDOM: sens->data= MEM_callocN(sizeof(bRandomSensor), "randomsens"); break; + case SENS_MOVEMENT: + sens->data = MEM_callocN(sizeof(bMovementSensor), "movementsens"); + movs = sens->data; + movs->threshold = 0.01f; + break; case SENS_RAY: sens->data= MEM_callocN(sizeof(bRaySensor), "raysens"); rs = sens->data; rs->range = 0.01f; + rs->mask = (1 << OB_MAX_COL_MASKS) - 1; break; case SENS_MESSAGE: sens->data= MEM_callocN(sizeof(bMessageSensor), "messagesens"); @@ -160,9 +168,10 @@ void init_sensor(bSensor *sens) case SENS_JOYSTICK: sens->data= MEM_callocN(sizeof(bJoystickSensor), "joysticksens"); js= sens->data; - js->hatf = SENS_JOY_HAT_UP; - js->axis = 1; - js->hat = 1; + js->type = SENS_JOY_AXIS; + js->axis = SENS_JOY_LEFT_STICK; + js->axis_single = SENS_JOY_LEFT_STICK_HORIZONTAL; + js->precision = 5000; break; default: ; /* this is very severe... I cannot make any memory for this */ @@ -329,7 +338,6 @@ void free_actuator(bActuator *act) if (act->data) { switch (act->type) { case ACT_ACTION: - case ACT_SHAPEACTION: { bActionActuator *aa = (bActionActuator *)act->data; if (aa->act) @@ -371,7 +379,6 @@ bActuator *copy_actuator(bActuator *act, const int flag) switch (act->type) { case ACT_ACTION: - case ACT_SHAPEACTION: { bActionActuator *aa = (bActionActuator *)act->data; if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { @@ -415,13 +422,13 @@ void init_actuator(bActuator *act) bArmatureActuator *arma; bMouseActuator *ma; bEditObjectActuator *eoa; + bVibrationActuator *via; if (act->data) MEM_freeN(act->data); act->data= NULL; switch (act->type) { case ACT_ACTION: - case ACT_SHAPEACTION: act->data= MEM_callocN(sizeof(bActionActuator), "actionact"); break; case ACT_SOUND: @@ -474,6 +481,12 @@ void init_actuator(bActuator *act) case ACT_GAME: act->data= MEM_callocN(sizeof(bGameActuator), "game act"); break; + case ACT_VIBRATION: + act->data = MEM_callocN(sizeof(bVibrationActuator), "vibration act"); + via = act->data; + via->duration = 500; //milliseconds + via->strength = 0.4; + break; case ACT_VISIBILITY: act->data= MEM_callocN(sizeof(bVisibilityActuator), "visibility act"); break; @@ -1018,6 +1031,7 @@ void BKE_sca_sensors_id_loop(ListBase *senslist, SCASensorIDFunc func, void *use case SENS_RADAR: case SENS_RANDOM: case SENS_RAY: + case SENS_MOVEMENT: case SENS_JOYSTICK: case SENS_ACTUATOR: case SENS_DELAY: @@ -1151,6 +1165,7 @@ void BKE_sca_actuators_id_loop(ListBase *actlist, SCAActuatorIDFunc func, void * case ACT_GROUP: case ACT_RANDOM: case ACT_GAME: + case ACT_VIBRATION: case ACT_VISIBILITY: case ACT_SHAPEACTION: case ACT_STATE: diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 1eb65519596b..f6ef2877f5d7 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -103,6 +103,8 @@ #include "IMB_colormanagement.h" #include "IMB_imbuf.h" +#include "wm_event_types.h" + #include "bmesh.h" const char *RE_engine_id_BLENDER_RENDER = "BLENDER_RENDER"; @@ -749,12 +751,6 @@ void BKE_scene_init(Scene *sce) sce->gm.stereomode = STEREO_ANAGLYPH; sce->gm.eyeseparation = 0.10; - sce->gm.dome.angle = 180; - sce->gm.dome.mode = DOME_FISHEYE; - sce->gm.dome.res = 4; - sce->gm.dome.resbuf = 1.0f; - sce->gm.dome.tilt = 0; - sce->gm.xplay = 640; sce->gm.yplay = 480; sce->gm.freqplay = 60; @@ -762,19 +758,17 @@ void BKE_scene_init(Scene *sce) sce->gm.gravity = 9.8f; sce->gm.physicsEngine = WOPHY_BULLET; - sce->gm.mode = 32; //XXX ugly harcoding, still not sure we should drop mode. 32 == 1 << 5 == use_occlusion_culling + sce->gm.mode = WO_ACTIVITY_CULLING | WO_DBVT_CULLING; sce->gm.occlusionRes = 128; sce->gm.ticrate = 60; sce->gm.maxlogicstep = 5; sce->gm.physubstep = 1; sce->gm.maxphystep = 5; + sce->gm.timeScale = 1.0f; sce->gm.lineardeactthreshold = 0.8f; sce->gm.angulardeactthreshold = 1.0f; sce->gm.deactivationtime = 0.0f; - sce->gm.flag = GAME_DISPLAY_LISTS; - sce->gm.matmode = GAME_MAT_MULTITEX; - sce->gm.obstacleSimulation = OBSTSIMULATION_NONE; sce->gm.levelHeight = 2.f; @@ -797,6 +791,11 @@ void BKE_scene_init(Scene *sce) sce->gm.exitkey = 218; // Blender key code for ESC + sce->gm.pythonkeys[0] = LEFTCTRLKEY; + sce->gm.pythonkeys[1] = LEFTSHIFTKEY; + sce->gm.pythonkeys[2] = LEFTALTKEY; + sce->gm.pythonkeys[3] = TKEY; + BKE_sound_create_scene(sce); /* color management */ @@ -2334,6 +2333,12 @@ void BKE_scene_disable_color_management(Scene *scene) bool BKE_scene_check_color_management_enabled(const Scene *scene) { +#ifdef WITH_GAMEENGINE + if (BKE_scene_uses_blender_game(scene)) { + return (scene->gm.colorManagement == GAME_COLOR_MANAGEMENT_SRGB); + } +#endif + return !STREQ(scene->display_settings.display_device, "None"); } diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 76df163ee3a6..38e5ebc961cc 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -65,7 +65,6 @@ #include "BKE_text.h" #include "BKE_node.h" - #ifdef WITH_PYTHON #include "BPY_extern.h" #endif @@ -2849,7 +2848,7 @@ static void txt_select_unprefix( void txt_comment(Text *text, TextUndoBuf *utxt) { - const char *prefix = "#"; + const char *prefix = text->cmmt_pfx == NULL ? "#" : text->cmmt_pfx; if (ELEM(NULL, text->curl, text->sell)) { return; @@ -2864,7 +2863,8 @@ void txt_comment(Text *text, TextUndoBuf *utxt) void txt_uncomment(Text *text, TextUndoBuf *utxt) { - const char *prefix = "#"; + const char *prefix = text->cmmt_pfx == NULL ? "#" : text->cmmt_pfx; + ListBase line_index_mask; int line_index_mask_len; diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index a0399c74be14..65adf52ddebf 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -291,6 +291,7 @@ void BKE_texture_default(Tex *tex) tex->env->clipend = 100; tex->env->cuberes = 512; tex->env->depth = 0; + tex->env->flag = ENVMAP_AUTO_UPDATE; } if (tex->pd) { @@ -383,6 +384,9 @@ void BKE_texture_mtex_default(MTex *mtex) mtex->blendtype = MTEX_BLEND; mtex->colfac = 1.0; mtex->norfac = 1.0; + mtex->parallaxbumpsc = 0.03f; + mtex->parallaxsteps = 10.0f; + mtex->parallaxcomp = 3; mtex->varfac = 1.0; mtex->dispfac = 0.2; mtex->colspecfac = 1.0f; @@ -423,6 +427,9 @@ void BKE_texture_mtex_default(MTex *mtex) mtex->brush_map_mode = MTEX_MAP_MODE_TILED; mtex->random_angle = 2.0f * (float)M_PI; mtex->brush_angle_mode = 0; + mtex->ior = 1.0f; + mtex->refrratio = 0.0f; + mtex->colorManagement = GAME_COLOR_MANAGEMENT_SRGB; } @@ -937,6 +944,8 @@ EnvMap *BKE_texture_envmap_add(void) env->clipend = 100.0; env->cuberes = 512; env->viewscale = 0.5; + env->flag = ENVMAP_AUTO_UPDATE; + env->lodfactor = 1.0f; return env; } diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h index 3d4b227ffa7f..3996c34acdbc 100644 --- a/source/blender/blenlib/BLI_utildefines.h +++ b/source/blender/blenlib/BLI_utildefines.h @@ -44,6 +44,10 @@ extern "C" { /* We could remove in future. */ #include "BLI_assert.h" +#ifdef WITH_ASSERT_ABORT +#include +#endif + /* useful for finding bad use of min/max */ #if 0 /* gcc only */ diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt index dd0a8543b9f9..bb7db27578ff 100644 --- a/source/blender/blenloader/CMakeLists.txt +++ b/source/blender/blenloader/CMakeLists.txt @@ -33,6 +33,7 @@ set(INC ../makesdna ../makesrna ../nodes + ../windowmanager ../render/extern/include ../../../intern/guardedalloc @@ -54,6 +55,7 @@ set(SRC intern/versioning_250.c intern/versioning_260.c intern/versioning_270.c + intern/versioning_upbge.c intern/versioning_defaults.c intern/versioning_legacy.c intern/writefile.c @@ -91,6 +93,13 @@ if(WITH_ALEMBIC) add_definitions(-DWITH_ALEMBIC) endif() +if(WITH_GAMEENGINE_BPPLAYER) + list(APPEND INC + ../../../intern/spindle + ) + add_definitions(-DWITH_GAMEENGINE_BPPLAYER) +endif() + blender_add_lib(bf_blenloader "${SRC}" "${INC}" "${INC_SYS}") # needed so writefile.c can use dna_type_offsets.h diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index 7488d62bb3c9..1bbc14e4a42d 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -67,6 +67,10 @@ # include "BLI_winstuff.h" #endif +#ifdef WITH_GAMEENGINE_BPPLAYER +# include "SpindleEncryption.h" +#endif + /* local prototypes --------------------- */ void BLO_blendhandle_print_sizes(BlendHandle *, void *); @@ -351,11 +355,18 @@ BlendFileData *BLO_read_from_memory( BlendFileData *bfd = NULL; FileData *fd; - fd = blo_openblendermemory(mem, memsize, reports); + fd = blo_openblendermemory(mem, memsize, reports); if (fd) { +#ifdef WITH_GAMEENGINE_BPPLAYER + BLI_strncpy(fd->relabase, SPINDLE_GetFilePath(), sizeof(fd->relabase)); +#endif fd->reports = reports; fd->skip_flags = skip_flags; +#ifdef WITH_GAMEENGINE_BPPLAYER + bfd = blo_read_file_internal(fd, SPINDLE_GetFilePath()); +#else bfd = blo_read_file_internal(fd, ""); +#endif blo_freefiledata(fd); } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 08a45f367f4c..7af196251d1f 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -86,6 +86,7 @@ #include "DNA_packedFile_types.h" #include "DNA_particle_types.h" #include "DNA_property_types.h" +#include "DNA_python_component_types.h" #include "DNA_rigidbody_types.h" #include "DNA_text_types.h" #include "DNA_view3d_types.h" @@ -165,6 +166,10 @@ #include +#ifdef WITH_GAMEENGINE_BPPLAYER +# include "SpindleEncryption.h" +#endif // WITH_GAMEENGINE_BPPLAYER + /** * READ * ==== @@ -1154,25 +1159,38 @@ static FileData *blo_decode_and_check(FileData *fd, ReportList *reports) /* on each new library added, it now checks for the current FileData and expands relativeness */ FileData *blo_openblenderfile(const char *filepath, ReportList *reports) { - gzFile gzfile; - errno = 0; - gzfile = BLI_gzopen(filepath, "rb"); +#ifdef WITH_GAMEENGINE_BPPLAYER + const int typeencryption = SPINDLE_CheckEncryptionFromFile(filepath); + if (typeencryption <= SPINDLE_NO_ENCRYPTION) { +#endif + gzFile gzfile; + errno = 0; + gzfile = BLI_gzopen(filepath, "rb"); - if (gzfile == (gzFile)Z_NULL) { - BKE_reportf(reports, RPT_WARNING, "Unable to open '%s': %s", - filepath, errno ? strerror(errno) : TIP_("unknown error reading file")); - return NULL; - } - else { - FileData *fd = filedata_new(); - fd->gzfiledes = gzfile; - fd->read = fd_read_gzip_from_file; + if (gzfile == (gzFile)Z_NULL) { + BKE_reportf(reports, RPT_WARNING, "Unable to open '%s': %s", + filepath, errno ? strerror(errno) : TIP_("unknown error reading file")); + return NULL; + } + else { + FileData *fd = filedata_new(); + fd->gzfiledes = gzfile; + fd->read = fd_read_gzip_from_file; - /* needed for library_append and read_libraries */ - BLI_strncpy(fd->relabase, filepath, sizeof(fd->relabase)); + /* needed for library_append and read_libraries */ + BLI_strncpy(fd->relabase, filepath, sizeof(fd->relabase)); - return blo_decode_and_check(fd, reports); + return blo_decode_and_check(fd, reports); + } +#ifdef WITH_GAMEENGINE_BPPLAYER + } + else { + int filesize = 0; + const char *decrypteddata = SPINDLE_DecryptFromFile(filepath, &filesize, NULL, typeencryption); + SPINDLE_SetFilePath(filepath); + return blo_openblendermemory(decrypteddata, filesize, reports); } +#endif } /** @@ -1267,6 +1285,11 @@ FileData *blo_openblendermemory(const void *mem, int memsize, ReportList *report fd->flags |= FD_FLAGS_NOT_MY_BUFFER; +#ifdef WITH_GAMEENGINE_BPPLAYER + // Set local path before calling blo_decode_and_check. + BLI_strncpy(fd->relabase, SPINDLE_GetFilePath(), sizeof(fd->relabase)); +#endif + return blo_decode_and_check(fd, reports); } } @@ -3792,6 +3815,9 @@ static void direct_link_image(FileData *fd, Image *ima) ima->repbind = NULL; + ima->lastupdate = 0.0f; + ima->lastframe = 0; + /* undo system, try to restore render buffers */ if (fd->imamap) { int a; @@ -4050,6 +4076,7 @@ static void direct_link_material(FileData *fd, Material *ma) ma->preview = direct_link_preview_image(fd, ma->preview); BLI_listbase_clear(&ma->gpumaterial); + BLI_listbase_clear(&ma->gpumaterialinstancing); } /* ************ READ PARTICLE SETTINGS ***************** */ @@ -5027,6 +5054,8 @@ static void lib_link_object(FileData *fd, Main *main) } } + ob->gamePredefinedBound = newlibadr_us(fd, ob->id.lib, ob->gamePredefinedBound); + { FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); @@ -5452,6 +5481,8 @@ static void direct_link_object(FileData *fd, Object *ob) bSensor *sens; bController *cont; bActuator *act; + PythonComponent *pc; + PythonComponentProperty *cprop; /* weak weak... this was only meant as draw flag, now is used in give_base_to_objects too */ ob->flag &= ~OB_FROMGROUP; @@ -5621,6 +5652,9 @@ static void direct_link_object(FileData *fd, Object *ob) else if (!ob->state) { ob->state = 1; } + else if (!ob->init_state) { + ob->init_state = 1; + } for (cont = ob->controllers.first; cont; cont = cont->next) { cont->data = newdataadr(fd, cont->data); cont->links = newdataadr(fd, cont->links); @@ -5634,6 +5668,21 @@ static void direct_link_object(FileData *fd, Object *ob) act->data = newdataadr(fd, act->data); } + link_glob_list(fd, &ob->components); + pc = ob->components.first; + while (pc) { + link_glob_list(fd, &pc->properties); + cprop = pc->properties.first; + while (cprop) { + link_list(fd, &cprop->enumval); + for (LinkData *link = cprop->enumval.first; link; link = link->next) { + link->data = newdataadr(fd, link->data); + } + cprop = cprop->next; + } + pc = pc->next; + } + link_list(fd, &ob->hooks); while (ob->hooks.first) { ObHook *hook = ob->hooks.first; @@ -5894,8 +5943,6 @@ static void lib_link_scene(FileData *fd, Main *main) fls->group = newlibadr_us(fd, sce->id.lib, fls->group); } } - /*Game Settings: Dome Warp Text*/ - sce->gm.dome.warptext = newlibadr(fd, sce->id.lib, sce->gm.dome.warptext); /* Motion Tracking */ sce->clip = newlibadr_us(fd, sce->id.lib, sce->clip); @@ -8408,6 +8455,8 @@ static BHead *read_global(BlendFileData *bfd, FileData *fd, BHead *bhead) /* copy to bfd handle */ bfd->main->subversionfile = fg->subversion; + bfd->main->upbgeversionfile = fg->upbgeversion; + bfd->main->upbgesubversionfile = fg->upbgesubversion; bfd->main->minversionfile = fg->minversion; bfd->main->minsubversionfile = fg->minsubversion; bfd->main->build_commit_timestamp = fg->build_commit_timestamp; @@ -8527,6 +8576,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) blo_do_versions_250(fd, lib, main); blo_do_versions_260(fd, lib, main); blo_do_versions_270(fd, lib, main); + blo_do_versions_upbge(fd, lib, main); /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ /* WATCH IT 2!: Userdef struct init see do_versions_userdef() above! */ @@ -9710,9 +9760,6 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce) } } - if (sce->r.dometext) - expand_doit(fd, mainvar, sce->gm.dome.warptext); - if (sce->gpd) expand_doit(fd, mainvar, sce->gpd); diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index 66161d86f025..89623e00139b 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -171,6 +171,7 @@ void blo_do_versions_pre250(struct FileData *fd, struct Library *lib, struct Mai void blo_do_versions_250(struct FileData *fd, struct Library *lib, struct Main *bmain); void blo_do_versions_260(struct FileData *fd, struct Library *lib, struct Main *bmain); void blo_do_versions_270(struct FileData *fd, struct Library *lib, struct Main *bmain); +void blo_do_versions_upbge(struct FileData *fd, struct Library *lib, struct Main *main); void do_versions_after_linking_270(struct Main *bmain); diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index 28720ef51456..cc46555383e2 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -1021,15 +1021,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain) ts->vgroup_weight = 1.0f; } - /* Game Settings */ - /* Dome */ - sce->gm.dome.angle = sce->r.domeangle; - sce->gm.dome.mode = sce->r.domemode; - sce->gm.dome.res = sce->r.domeres; - sce->gm.dome.resbuf = sce->r.domeresbuf; - sce->gm.dome.tilt = sce->r.dometilt; - sce->gm.dome.warptext = sce->r.dometext; - /* Stand Alone */ sce->gm.playerflag |= (sce->r.fullscreen ? GAME_PLAYER_FULLSCREEN : 0); sce->gm.xplay = sce->r.xplay; @@ -1040,15 +1031,11 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain) /* Stereo */ sce->gm.stereomode = sce->r.stereomode; - /* reassigning stereomode NO_STEREO and DOME to a separeted flag*/ + /* reassigning stereomode NO_STEREO to a separeted flag*/ if (sce->gm.stereomode == 1) { // 1 = STEREO_NOSTEREO sce->gm.stereoflag = STEREO_NOSTEREO; sce->gm.stereomode = STEREO_ANAGLYPH; } - else if (sce->gm.stereomode == 8) { // 8 = STEREO_DOME - sce->gm.stereoflag = STEREO_DOME; - sce->gm.stereomode = STEREO_ANAGLYPH; - } else sce->gm.stereoflag = STEREO_ENABLED; @@ -1098,15 +1085,6 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain) sce->gm.flag |= GAME_GLSL_NO_ENV_LIGHTING; if (fd->fileflags & G_FILE_IGNORE_DEPRECATION_WARNINGS) sce->gm.flag |= GAME_IGNORE_DEPRECATION_WARNINGS; - - if (fd->fileflags & G_FILE_GAME_MAT_GLSL) - sce->gm.matmode = GAME_MAT_GLSL; - else if (fd->fileflags & G_FILE_GAME_MAT) - sce->gm.matmode = GAME_MAT_MULTITEX; - else - sce->gm.matmode = GAME_MAT_TEXFACE; - - sce->gm.flag |= GAME_DISPLAY_LISTS; } for (ob = bmain->object.first; ob; ob = ob->id.next) { diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c index 13b7b7c15591..b774d0580bd5 100644 --- a/source/blender/blenloader/intern/versioning_260.c +++ b/source/blender/blenloader/intern/versioning_260.c @@ -2511,10 +2511,6 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *bmain) if (ts->sculpt) ts->sculpt->flags |= SCULPT_DYNTOPO_SUBDIVIDE; - /* single texture mode removed from game engine */ - if (scene->gm.matmode == GAME_MAT_TEXFACE) - scene->gm.matmode = GAME_MAT_MULTITEX; - /* 'Increment' mode disabled for nodes, use true grid snapping instead */ if (scene->toolsettings->snap_node_mode == SCE_SNAP_MODE_INCREMENT) scene->toolsettings->snap_node_mode = SCE_SNAP_MODE_GRID; diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index 3511aefc2a56..93ae727c39f5 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -3474,17 +3474,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain) } if (bmain->versionfile < 248 || (bmain->versionfile == 248 && bmain->subversionfile < 4)) { - Scene *sce; World *wrld; - /* Dome (Fisheye) default parameters */ - for (sce = bmain->scene.first; sce; sce = sce->id.next) { - sce->r.domeangle = 180; - sce->r.domemode = 1; - sce->r.domeres = 4; - sce->r.domeresbuf = 1.0f; - sce->r.dometilt = 0; - } /* DBVT culling by default */ for (wrld = bmain->world.first; wrld; wrld = wrld->id.next) { wrld->mode |= WO_DBVT_CULLING; diff --git a/source/blender/blenloader/intern/versioning_upbge.c b/source/blender/blenloader/intern/versioning_upbge.c new file mode 100644 index 000000000000..e4361c5e861b --- /dev/null +++ b/source/blender/blenloader/intern/versioning_upbge.c @@ -0,0 +1,350 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/blenloader/intern/versioning_upbge.c + * \ingroup blenloader + */ + +#include "BLI_utildefines.h" +#include "BLI_compiler_attrs.h" + +#include + +/* allow readfile to use deprecated functionality */ +#define DNA_DEPRECATED_ALLOW + +#include "DNA_genfile.h" +#include "DNA_material_types.h" +#include "DNA_object_force_types.h" +#include "DNA_object_types.h" +#include "DNA_camera_types.h" +#include "DNA_sdna_types.h" +#include "DNA_sensor_types.h" +#include "DNA_space_types.h" +#include "DNA_view3d_types.h" +#include "DNA_screen_types.h" +#include "DNA_mesh_types.h" +#include "DNA_material_types.h" +#include "DNA_world_types.h" + +#include "BKE_main.h" +#include "BKE_node.h" + +#include "BLI_math_base.h" + +#include "BLO_readfile.h" + +#include "wm_event_types.h" + +#include "readfile.h" + +#include "MEM_guardedalloc.h" + +void blo_do_versions_upbge(FileData *fd, Library *lib, Main *main) +{ + //printf("UPBGE: open file from version : %i, subversion : %i\n", main->upbgeversionfile, main->upbgesubversionfile); + if (!MAIN_VERSION_UPBGE_ATLEAST(main, 0, 1)) { + if (!DNA_struct_elem_find(fd->filesdna, "bRaySensor", "int", "mask")) { + bRaySensor *raySensor; + + for (Object *ob = main->object.first; ob; ob = ob->id.next) { + for (bSensor* sensor = ob->sensors.first; sensor != NULL; sensor = (bSensor *)sensor->next) { + if (sensor->type == SENS_RAY) { + raySensor = (bRaySensor *)sensor->data; + raySensor->mask = 0xFFFF;//all one, 'cause this was the previous behavior + } + } + } + } + for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + /* Previous value of GAME_GLSL_NO_ENV_LIGHTING was 1 << 18, it was conflicting + * with GAME_SHOW_BOUNDING_BOX. To fix this issue, we replace 1 << 18 by + * 1 << 21 (the new value) when the file come from blender not UPBGE. + */ + if (scene->gm.flag & (1 << 18)) { + scene->gm.flag |= GAME_GLSL_NO_ENV_LIGHTING; + /* Disable bit 18 */ + scene->gm.flag &= ~(1 << 18); + } + } + } + + if (!MAIN_VERSION_UPBGE_ATLEAST(main, 0, 6)) { + if (!DNA_struct_elem_find(fd->filesdna, "Material", "short", "constflag")) { + for (Material *ma = main->mat.first; ma; ma = ma->id.next) { + ma->constflag |= MA_CONSTANT_TEXTURE | MA_CONSTANT_TEXTURE_UV; + } + } + } + + if (!MAIN_VERSION_UPBGE_ATLEAST(main, 0, 9)) { + if (!DNA_struct_elem_find(fd->filesdna, "GameData", "short", "pythonkeys[4]")) { + for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + scene->gm.pythonkeys[0] = LEFTCTRLKEY; + scene->gm.pythonkeys[1] = LEFTSHIFTKEY; + scene->gm.pythonkeys[2] = LEFTALTKEY; + scene->gm.pythonkeys[3] = TKEY; + } + } + } + if (!MAIN_VERSION_UPBGE_ATLEAST(main, 1, 0)) { + if (!DNA_struct_elem_find(fd->filesdna, "Material", "float", "depthtranspfactor")) { + for (Material *ma = main->mat.first; ma; ma = ma->id.next) { + ma->depthtranspfactor = 1.0f; + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "EnvMap", "short", "flag")) { + for (Tex *tex = main->tex.first; tex; tex = tex->id.next) { + if (tex->env) { + tex->env->flag |= ENVMAP_AUTO_UPDATE; + } + } + } + } + + if (!MAIN_VERSION_UPBGE_ATLEAST(main, 1, 1)) { + if (!DNA_struct_elem_find(fd->filesdna, "MTex", "float", "ior")) { + for (Material *ma = main->mat.first; ma; ma = ma->id.next) { + for (unsigned short a = 0; a < MAX_MTEX; ++a) { + if (ma->mtex[a]) { + ma->mtex[a]->ior = 1.0f; + } + } + } + } + } + + if (!MAIN_VERSION_UPBGE_ATLEAST(main, 1, 2)) { + if (!DNA_struct_elem_find(fd->filesdna, "Object", "float", "friction")) { + for (Object *ob = main->object.first; ob; ob = ob->id.next) { + if (ob->type == OB_MESH) { + Mesh *me = blo_do_versions_newlibadr(fd, lib, ob->data); + bool converted = false; + for (unsigned short i = 0; i < me->totcol; ++i) { + Material *ma = blo_do_versions_newlibadr(fd, lib, me->mat[i]); + if (ma) { + ob->friction = ma->friction; + ob->rolling_friction = ma->rolling_friction; + ob->fh = ma->fh; + ob->reflect = ma->reflect; + ob->fhdist = ma->fhdist; + ob->xyfrict = ma->xyfrict; + if (ma->dynamode & MA_FH_NOR) { + ob->dynamode |= OB_FH_NOR; + } + converted = true; + break; + } + } + /* There's no valid material, we use the settings from BKE_object_init. */ + if (!converted) { + ob->friction = 0.5f; + } + } + } + } + } + + if (!MAIN_VERSION_UPBGE_ATLEAST(main, 1, 5)) { + if (!DNA_struct_elem_find(fd->filesdna, "Object", "float", "lodfactor")) { + for (Object *ob = main->object.first; ob; ob = ob->id.next) { + ob->lodfactor = 1.0f; + } + } + if (!DNA_struct_elem_find(fd->filesdna, "Camera", "float", "lodfactor")) { + for (Camera *ca = main->camera.first; ca; ca = ca->id.next) { + ca->lodfactor = 1.0f; + } + } + if (!DNA_struct_elem_find(fd->filesdna, "EnvMap", "float", "lodfactor")) { + for (Tex *tex = main->tex.first; tex; tex = tex->id.next) { + if (tex->env) { + tex->env->lodfactor = 1.0f; + } + } + } + } + + if (!MAIN_VERSION_UPBGE_ATLEAST(main, 1, 6)) { + if (!DNA_struct_elem_find(fd->filesdna, "GameData", "short", "showBoundingBox")) { + for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + scene->gm.showBoundingBox = (scene->gm.flag & GAME_SHOW_BOUNDING_BOX) ? GAME_DEBUG_FORCE : GAME_DEBUG_DISABLE; + } + } + if (!DNA_struct_elem_find(fd->filesdna, "GameData", "short", "showArmatures")) { + for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + scene->gm.showArmatures = (scene->gm.flag & GAME_SHOW_ARMATURES) ? GAME_DEBUG_ALLOW : GAME_DEBUG_DISABLE; + } + } + if (!DNA_struct_elem_find(fd->filesdna, "GameData", "short", "showCameraFrustum")) { + for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + scene->gm.showCameraFrustum = GAME_DEBUG_ALLOW; + } + } + } + + if (!MAIN_VERSION_UPBGE_ATLEAST(main, 1, 7)) { + if (!DNA_struct_elem_find(fd->filesdna, "GameData", "float", "timeScale")) { + for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + scene->gm.timeScale = 1.0f; + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "Camera", "short", "gameflag")) { + for (Camera *camera = main->camera.first; camera; camera = camera->id.next) { + /* Previous value of GAME_CAM_SHOW_FRUSTUM was 1 << 10, it was possibly conflicting + * with new flags. To fix this issue we use a separate flag value: gameflag. + */ + if (camera->flag & (1 << 10)) { + camera->gameflag |= GAME_CAM_SHOW_FRUSTUM; + /* Disable bit 10 */ + camera->flag &= ~(1 << 10); + } + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "bMouseSensor", "int", "mask")) { + for (Object *ob = main->object.first; ob; ob = ob->id.next) { + for (bSensor *sensor = ob->sensors.first; sensor; sensor = (bSensor *)sensor->next) { + if (sensor->type == SENS_MOUSE) { + bMouseSensor *mouseSensor = (bMouseSensor *)sensor->data; + // All one, because this was the previous behavior. + mouseSensor->mask = 0xFFFF; + } + } + } + } + } + + if (!MAIN_VERSION_UPBGE_ATLEAST(main, 2, 1)) { + if (!DNA_struct_elem_find(fd->filesdna, "BulletSoftBody", "int", "bending_dist")) { + for (Object *ob = main->object.first; ob; ob = ob->id.next) { + if (ob->bsoft) { + ob->bsoft->bending_dist = 2; + } + } + } + } + + if (!MAIN_VERSION_UPBGE_ATLEAST(main, 2, 2)) { + for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + scene->gm.mode |= WO_ACTIVITY_CULLING; + } + + for (Camera *camera = main->camera.first; camera; camera = camera->id.next) { + camera->gameflag |= GAME_CAM_OBJECT_ACTIVITY_CULLING; + camera->gameviewport.rightratio = 1.0f; + camera->gameviewport.topratio = 1.0f; + } + } + + if (!MAIN_VERSION_UPBGE_ATLEAST(main, 2, 2)) { + if (!DNA_struct_elem_find(fd->filesdna, "Object", "float", "max_slope")) { + for (Object *ob = main->object.first; ob; ob = ob->id.next) { + ob->max_slope = M_PI_2; + } + } + } + + if (!MAIN_VERSION_UPBGE_ATLEAST(main, 2, 4)) { + FOREACH_NODETREE(main, ntree, id) { + if (ntree->type == NTREE_SHADER) { + for (bNode *node = ntree->nodes.first; node; node = node->next) { + switch (node->type) { + case 194: + { + node->type = SH_NODE_OBJECT; + break; + } + case 195: + { + node->type = SH_NODE_TIME; + break; + } + case 196: + { + node->type = SH_NODE_PARALLAX; + break; + } + } + } + } + } FOREACH_NODETREE_END + + if (!DNA_struct_elem_find(fd->filesdna, "Lamp", "float", "cutoff")) { + for (Lamp *lamp = main->lamp.first; lamp; lamp = lamp->id.next) { + lamp->radius = 8.0f; + lamp->cutoff = 0.001f; + } + } + + for (bScreen *sc = main->screen.first; sc; sc = sc->id.next) { + for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + v3d->flag2 |= V3D_SHOW_MIST; + } + } + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "GameData", "short", "colorManagement")) { + for (Scene *scene = main->scene.first; scene; scene = scene->id.next) { + scene->gm.colorManagement = GAME_COLOR_MANAGEMENT_SRGB; + } + } + + if (!DNA_struct_elem_find(fd->filesdna, "MTex", "short", "colorManagement")) { + for (Material *ma = main->mat.first; ma; ma = ma->id.next) { + for (unsigned short a = 0; a < MAX_MTEX; ++a) { + if (ma->mtex[a]) { + ma->mtex[a]->colorManagement = GAME_COLOR_MANAGEMENT_SRGB; + } + } + } + + for (World *wo = main->world.first; wo; wo = wo->id.next) { + for (unsigned short a = 0; a < MAX_MTEX; ++a) { + if (wo->mtex[a]) { + wo->mtex[a]->colorManagement = GAME_COLOR_MANAGEMENT_SRGB; + } + } + } + } + } + + if (!MAIN_VERSION_UPBGE_ATLEAST(main, 2, 5)) { + if (!DNA_struct_elem_find(fd->filesdna, "MTex", "short", "parallaxcomp")) { + for (Material *ma = main->mat.first; ma; ma = ma->id.next) { + for (unsigned short a = 0; a < MAX_MTEX; ++a) { + if (ma->mtex[a]) { + // Default alpha. + ma->mtex[a]->parallaxcomp = 3; + } + } + } + } + } +} diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 4b64d0a3d3fc..247f3fd420b9 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -131,6 +131,7 @@ #include "DNA_packedFile_types.h" #include "DNA_particle_types.h" #include "DNA_property_types.h" +#include "DNA_python_component_types.h" #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" #include "DNA_sdna_types.h" @@ -1493,6 +1494,9 @@ static void write_sensors(WriteData *wd, ListBase *lb) case SENS_RAY: writestruct(wd, DATA, bRaySensor, 1, sens->data); break; + case SENS_MOVEMENT: + writestruct(wd, DATA, bMovementSensor, 1, sens->data); + break; case SENS_MESSAGE: writestruct(wd, DATA, bMessageSensor, 1, sens->data); break; @@ -1542,7 +1546,6 @@ static void write_actuators(WriteData *wd, ListBase *lb) switch (act->type) { case ACT_ACTION: - case ACT_SHAPEACTION: writestruct(wd, DATA, bActionActuator, 1, act->data); break; case ACT_SOUND: @@ -1578,6 +1581,9 @@ static void write_actuators(WriteData *wd, ListBase *lb) case ACT_GAME: writestruct(wd, DATA, bGameActuator, 1, act->data); break; + case ACT_VIBRATION: + writestruct(wd, DATA, bVibrationActuator, 1, act->data); + break; case ACT_VISIBILITY: writestruct(wd, DATA, bVisibilityActuator, 1, act->data); break; @@ -1607,6 +1613,36 @@ static void write_actuators(WriteData *wd, ListBase *lb) } } +static void write_component_properties(WriteData *wd, ListBase *lb) +{ + PythonComponentProperty *cprop; + cprop = lb->first; + + while (cprop) { + LinkData *link; + writestruct(wd, DATA, PythonComponentProperty, 1, cprop); + writelist(wd, DATA, LinkData, &cprop->enumval); + for (link = cprop->enumval.first; link; link = link->next) { + writedata(wd, DATA, strlen(link->data)+1, link->data); + } + cprop = cprop->next; + } +} + +static void write_components(WriteData *wd, ListBase *lb) +{ + PythonComponent *pc; + + pc = lb->first; + + while(pc) { + writestruct(wd, DATA, PythonComponent, 1, pc); + write_component_properties(wd, &pc->properties); + + pc = pc->next; + } +} + static void write_motionpath(WriteData *wd, bMotionPath *mpath) { /* sanity checks */ @@ -1919,6 +1955,7 @@ static void write_object(WriteData *wd, Object *ob) write_sensors(wd, &ob->sensors); write_controllers(wd, &ob->controllers); write_actuators(wd, &ob->actuators); + write_components(wd, &ob->components); if (ob->type == OB_ARMATURE) { bArmature *arm = ob->data; @@ -3717,10 +3754,12 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar) BLI_strncpy(fg.filename, mainvar->name, sizeof(fg.filename)); sprintf(subvstr, "%4d", BLENDER_SUBVERSION); memcpy(fg.subvstr, subvstr, 4); - - fg.subversion = BLENDER_SUBVERSION; - fg.minversion = BLENDER_MINVERSION; - fg.minsubversion = BLENDER_MINSUBVERSION; + + fg.subversion= BLENDER_SUBVERSION; + fg.upbgeversion = UPBGE_VERSION; + fg.upbgesubversion = UPBGE_SUBVERSION; + fg.minversion= BLENDER_MINVERSION; + fg.minsubversion= BLENDER_MINSUBVERSION; #ifdef WITH_BUILDINFO { extern unsigned long build_commit_timestamp; diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index a38f82bc5fca..dc935a95af40 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -980,7 +980,7 @@ void uiTemplateLayers( void uiTemplateGameStates( uiLayout *layout, struct PointerRNA *ptr, const char *propname, PointerRNA *used_ptr, const char *used_propname, int active_state); -void uiTemplateImage(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *userptr, bool compact, bool multiview); +void uiTemplateImage(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *userptr, bool compact, bool multiview, bool cubemap, bool color_space); void uiTemplateImageSettings(uiLayout *layout, struct PointerRNA *imfptr, bool color_management); void uiTemplateImageStereo3d(uiLayout *layout, struct PointerRNA *stereo3d_format_ptr); void uiTemplateImageViews(uiLayout *layout, struct PointerRNA *imaptr); diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c index b18b6bcb7e78..37e299d3d966 100644 --- a/source/blender/editors/mesh/mesh_navmesh.c +++ b/source/blender/editors/mesh/mesh_navmesh.c @@ -709,6 +709,7 @@ static int navmesh_clear_exec(bContext *C, wmOperator *UNUSED(op)) Mesh *me = ob->data; CustomData_free_layers(&me->pdata, CD_RECAST, me->totpoly); + ob->gameflag &= ~OB_NAVMESH; DAG_id_tag_update(&me->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GEOM | ND_DATA, &me->id); @@ -719,7 +720,7 @@ static int navmesh_clear_exec(bContext *C, wmOperator *UNUSED(op)) void MESH_OT_navmesh_clear(struct wmOperatorType *ot) { /* identifiers */ - ot->name = "NavMesh Clear Data"; + ot->name = "Remove NavMesh"; ot->description = "Remove navmesh data from this mesh"; ot->idname = "MESH_OT_navmesh_clear"; diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index fc967dc424e8..b795b342a3a2 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -2114,6 +2114,13 @@ static int game_physics_copy_exec(bContext *C, wmOperator *UNUSED(op)) ob_iter->max_angvel = ob->max_angvel; ob_iter->obstacleRad = ob->obstacleRad; ob_iter->mass = ob->mass; + ob_iter->friction = ob->friction; + ob_iter->rolling_friction = ob->rolling_friction; + ob_iter->fh = ob->fh; + ob_iter->reflect = ob->reflect; + ob_iter->fhdist = ob->fhdist; + ob_iter->xyfrict = ob->xyfrict; + ob_iter->dynamode = ob->dynamode; copy_v3_v3(ob_iter->anisotropicFriction, ob->anisotropicFriction); ob_iter->collision_boundtype = ob->collision_boundtype; ob_iter->margin = ob->margin; diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 78cedf099a16..b8029248dce7 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -634,7 +634,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) sizey = (scene->r.size * scene->r.ysch) / 100; /* corrects render size with actual size, not every card supports non-power-of-two dimensions */ - ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, err_out); + ofs = GPU_offscreen_create(sizex, sizey, full_samples ? 0 : samples, GPU_HDR_NONE, GPU_OFFSCREEN_DEPTH_COMPARE, err_out); if (!ofs) { BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer, %s", err_out); diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index ceb4c0b27ba1..c1a85263a3ae 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -297,6 +297,8 @@ static void material_changed(Main *bmain, Material *ma) /* glsl */ if (ma->gpumaterial.first) GPU_material_free(&ma->gpumaterial); + if (ma->gpumaterialinstancing.first) + GPU_material_free(&ma->gpumaterialinstancing); /* find node materials using this */ for (parent = bmain->mat.first; parent; parent = parent->id.next) { @@ -311,6 +313,8 @@ static void material_changed(Main *bmain, Material *ma) if (parent->gpumaterial.first) GPU_material_free(&parent->gpumaterial); + if (parent->gpumaterialinstancing.first) + GPU_material_free(&parent->gpumaterialinstancing); } /* find if we have a scene with textured display */ @@ -354,12 +358,17 @@ static void lamp_changed(Main *bmain, Lamp *la) if (ob->data == la && ob->gpulamp.first) GPU_lamp_free(ob); - for (ma = bmain->mat.first; ma; ma = ma->id.next) + for (ma = bmain->mat.first; ma; ma = ma->id.next) { if (ma->gpumaterial.first) GPU_material_free(&ma->gpumaterial); + if (ma->gpumaterialinstancing.first) + GPU_material_free(&ma->gpumaterialinstancing); + } if (defmaterial.gpumaterial.first) GPU_material_free(&defmaterial.gpumaterial); + if (defmaterial.gpumaterialinstancing.first) + GPU_material_free(&defmaterial.gpumaterialinstancing); } static int material_uses_texture(Material *ma, Tex *tex) @@ -398,6 +407,8 @@ static void texture_changed(Main *bmain, Tex *tex) if (ma->gpumaterial.first) GPU_material_free(&ma->gpumaterial); + if (ma->gpumaterialinstancing.first) + GPU_material_free(&ma->gpumaterialinstancing); } /* find lamps */ @@ -476,12 +487,17 @@ static void world_changed(Main *bmain, World *wo) BKE_icon_changed(BKE_icon_id_ensure(&wo->id)); /* glsl */ - for (ma = bmain->mat.first; ma; ma = ma->id.next) + for (ma = bmain->mat.first; ma; ma = ma->id.next) { if (ma->gpumaterial.first) GPU_material_free(&ma->gpumaterial); + if (ma->gpumaterialinstancing.first) + GPU_material_free(&ma->gpumaterialinstancing); + } if (defmaterial.gpumaterial.first) GPU_material_free(&defmaterial.gpumaterial); + if (defmaterial.gpumaterialinstancing.first) + GPU_material_free(&defmaterial.gpumaterialinstancing); if (wo->gpumaterial.first) GPU_material_free(&wo->gpumaterial); @@ -518,9 +534,12 @@ static void scene_changed(Main *bmain, Scene *scene) } } - for (ma = bmain->mat.first; ma; ma = ma->id.next) + for (ma = bmain->mat.first; ma; ma = ma->id.next) { if (ma->gpumaterial.first) GPU_material_free(&ma->gpumaterial); + if (ma->gpumaterialinstancing.first) + GPU_material_free(&ma->gpumaterialinstancing); + } for (wo = bmain->world.first; wo; wo = wo->id.next) if (wo->gpumaterial.first) @@ -528,6 +547,8 @@ static void scene_changed(Main *bmain, Scene *scene) if (defmaterial.gpumaterial.first) GPU_material_free(&defmaterial.gpumaterial); + if (defmaterial.gpumaterialinstancing.first) + GPU_material_free(&defmaterial.gpumaterialinstancing); } void ED_render_id_flush_update(Main *bmain, ID *id) diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt index c60d194b6207..45d62d46f408 100644 --- a/source/blender/editors/space_image/CMakeLists.txt +++ b/source/blender/editors/space_image/CMakeLists.txt @@ -49,6 +49,10 @@ set(SRC image_intern.h ) +if(WITH_GAMEENGINE) + add_definitions(-DWITH_GAMEENGINE) +endif() + if(WITH_INTERNATIONAL) add_definitions(-DWITH_INTERNATIONAL) endif() diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 3fb1d6dd2d0b..fb2ce7651aae 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -29,6 +29,7 @@ #include #include +#include #include "DNA_node_types.h" #include "DNA_scene_types.h" @@ -825,7 +826,7 @@ static void rna_update_cb(bContext *C, void *arg_cb, void *UNUSED(arg)) RNA_property_update(C, &cb->ptr, cb->prop); } -void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *userptr, bool compact, bool multiview) +void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *userptr, bool compact, bool multiview, bool cubemap, bool color_space) { PropertyRNA *prop; PointerRNA imaptr; @@ -959,7 +960,12 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char } col = uiLayoutColumn(layout, false); - uiTemplateColorspaceSettings(col, &imaptr, "colorspace_settings"); +#ifdef WITH_GAMEENGINE + if (color_space || !STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME)) +#endif + { + uiTemplateColorspaceSettings(col, &imaptr, "colorspace_settings"); + } uiItemR(col, &imaptr, "use_view_as_render", 0, NULL, ICON_NONE); if (ima->source != IMA_SRC_GENERATED) { @@ -1041,8 +1047,18 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char split = uiLayoutSplit(layout, 0.0f, false); col = uiLayoutColumn(split, true); + if (cubemap) { + bool invalid = ((ima->gen_x != ceil(ima->gen_y * 3 / 2)) || ((ima->gen_y & (ima->gen_y - 1)) != 0)); + uiLayoutSetRedAlert(col, invalid); + } + uiItemR(col, &imaptr, "generated_width", 0, "X", ICON_NONE); uiItemR(col, &imaptr, "generated_height", 0, "Y", ICON_NONE); + uiLayoutSetRedAlert(col, false); + + if (cubemap) { + uiItemO(col, NULL, ICON_RECOVER_LAST, "IMAGE_OT_resize_cube_map"); + } uiItemR(col, &imaptr, "use_generated_float", 0, NULL, ICON_NONE); diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h index f7fec4ed396b..d90fa5365a67 100644 --- a/source/blender/editors/space_image/image_intern.h +++ b/source/blender/editors/space_image/image_intern.h @@ -74,6 +74,7 @@ void IMAGE_OT_unlink(struct wmOperatorType *ot); void IMAGE_OT_match_movie_length(struct wmOperatorType *ot); void IMAGE_OT_replace(struct wmOperatorType *ot); void IMAGE_OT_reload(struct wmOperatorType *ot); +void IMAGE_OT_resize_cube_map(struct wmOperatorType *ot); void IMAGE_OT_save(struct wmOperatorType *ot); void IMAGE_OT_save_as(struct wmOperatorType *ot); void IMAGE_OT_save_sequence(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 2a015177dacf..3c55ae64f6eb 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -2368,6 +2368,61 @@ void IMAGE_OT_reload(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER; /* no undo, image buffer is not handled by undo */ } +/******************** resize image cube map operator ********************/ + +static int image_resize_cube_map_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + Image *ima = CTX_data_edit_image(C); + SpaceImage *sima = CTX_wm_space_image(C); + Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data; + + if (!ima || !tex) + return OPERATOR_CANCELLED; + + if (tex->env && tex->env->type == ENV_CUBE) { + /* Here we control that envmap width = 3 / 2 * envmap height and that + * envmap height is a power of 2 to be sure to have a supported envmap resolution. + */ + int width = tex->ima->gen_x; + int height = tex->ima->gen_y; + if (!(width == ceil(height * 3 / 2) && ((height & (height - 1)) == 0))) { + int previous = pow(2, ceil(log(height) / log(2))) / 2; + tex->ima->gen_y = previous; + tex->ima->gen_x = previous * 3 / 2; + + DAG_id_tag_update(&tex->id, 0); + WM_main_add_notifier(NC_TEXTURE, tex); + WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, NULL); + } + } + + /* XXX unpackImage frees image buffers */ + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + + // XXX other users? + BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_RELOAD); + DAG_id_tag_update(&ima->id, 0); + + WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima); + + return OPERATOR_FINISHED; +} + +void IMAGE_OT_resize_cube_map(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Resize"; + ot->idname = "IMAGE_OT_resize_cube_map"; + ot->description = "Resize CubeMap texture to a compatible format"; + + /* api callbacks */ + ot->exec = image_resize_cube_map_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER; /* no undo, image buffer is not handled by undo */ +} + /********************** new image operator *********************/ #define IMA_DEF_NAME N_("Untitled") @@ -2384,6 +2439,7 @@ static int image_new_exec(bContext *C, wmOperator *op) Object *obedit; Image *ima; Main *bmain; + Tex *tex; PointerRNA ptr, idptr; PropertyRNA *prop; char name_buffer[MAX_ID_NAME - 2]; @@ -2399,6 +2455,8 @@ static int image_new_exec(bContext *C, wmOperator *op) obedit = CTX_data_edit_object(C); bmain = CTX_data_main(C); + tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data; + prop = RNA_struct_find_property(op->ptr, "name"); RNA_property_string_get(op->ptr, prop, name_buffer); if (!RNA_property_is_set(op->ptr, prop)) { @@ -2476,12 +2534,14 @@ static int image_new_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL); } else { - Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data; - if (tex && tex->type == TEX_IMAGE) { + if (tex && (tex->type == TEX_IMAGE || tex->type == TEX_ENVMAP)) { if (tex->ima) id_us_min(&tex->ima->id); tex->ima = ima; ED_area_tag_redraw(CTX_wm_area(C)); + DAG_id_tag_update(&tex->id, 0); + WM_main_add_notifier(NC_TEXTURE, tex); + WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, NULL); } } diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index fd661883f796..de628a4b8344 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -256,6 +256,7 @@ static void image_operatortypes(void) WM_operatortype_append(IMAGE_OT_match_movie_length); WM_operatortype_append(IMAGE_OT_replace); WM_operatortype_append(IMAGE_OT_reload); + WM_operatortype_append(IMAGE_OT_resize_cube_map); WM_operatortype_append(IMAGE_OT_save); WM_operatortype_append(IMAGE_OT_save_as); WM_operatortype_append(IMAGE_OT_save_sequence); diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index b00cb1fc5855..270de4ad193e 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -445,7 +445,7 @@ static void stats_string(Scene *scene) s = stats->infostr; ofs = 0; - ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, "%s | ", versionstr); + ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, "%s (based on Blender %s) | ", upbge_versionstr, versionstr); if (scene->obedit) { if (BKE_keyblock_from_object(scene->obedit)) diff --git a/source/blender/editors/space_logic/logic_ops.c b/source/blender/editors/space_logic/logic_ops.c index 837e8995cc2b..39a5733e5128 100644 --- a/source/blender/editors/space_logic/logic_ops.c +++ b/source/blender/editors/space_logic/logic_ops.c @@ -35,6 +35,7 @@ #include "DNA_controller_types.h" #include "DNA_actuator_types.h" #include "DNA_scene_types.h" +#include "DNA_python_component_types.h" #include "BLI_blenlib.h" #include "BLI_string_utils.h" @@ -45,6 +46,9 @@ #include "BKE_context.h" #include "BKE_main.h" #include "BKE_sca.h" +#include "BKE_python_component.h" +#include "BKE_global.h" +#include "BKE_report.h" #include "ED_logic.h" #include "ED_object.h" @@ -57,6 +61,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "UI_interface.h" #include "UI_view2d.h" #include "logic_intern.h" @@ -736,6 +741,196 @@ static void LOGIC_OT_view_all(wmOperatorType *ot) ot->flag = 0; } +/* Component operators */ +static int component_register_exec(bContext *C, wmOperator *op) +{ + PythonComponent *pycomp; + Object *ob = CTX_data_active_object(C); + char import[MAX_NAME]; + + if ((G.f & G_SCRIPT_AUTOEXEC) == 0) { + BKE_report(op->reports, RPT_WARNING, "Python script/component auto-execution disable, look in the userpref to activate..."); + return OPERATOR_CANCELLED; + } + + if (!ob) { + return OPERATOR_CANCELLED; + } + + RNA_string_get(op->ptr, "component_name", import); + pycomp = BKE_python_component_new(import, op->reports, C); + + if(!pycomp) { + return OPERATOR_CANCELLED; + } + + BLI_addtail(&ob->components, pycomp); + WM_event_add_notifier(C, NC_LOGIC, NULL); + + return OPERATOR_FINISHED; +} + +static int component_create_exec(bContext *C, wmOperator *op) +{ + PythonComponent *pycomp; + Object *ob = CTX_data_active_object(C); + char import[MAX_NAME]; + + if (!ob) { + return OPERATOR_CANCELLED; + } + + RNA_string_get(op->ptr, "component_name", import); + pycomp = BKE_python_component_create_file(import, op->reports, C); + + if(!pycomp) { + return OPERATOR_CANCELLED; + } + + BLI_addtail(&ob->components, pycomp); + WM_event_add_notifier(C, NC_LOGIC, NULL); + + return OPERATOR_FINISHED; +} + +static int component_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + /* Better for user feedback. */ + return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, UI_UNIT_Y); +} + +static void LOGIC_OT_python_component_register(wmOperatorType *ot) +{ + ot->name = "Add Python Component"; + ot->idname = "LOGIC_OT_python_component_register"; + ot->description = "Add a python component to the selected object"; + + /* api callbacks */ + ot->exec = component_register_exec; + ot->invoke = component_new_invoke; + ot->poll = ED_operator_object_active_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + PropertyRNA *parm; + parm = RNA_def_string(ot->srna, "component_name", "module.Component", 64, "Component", "The component class name with module (module.ComponentName)"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); +} + +static void LOGIC_OT_python_component_create(wmOperatorType *ot) +{ + ot->name = "Create Python Component"; + ot->idname = "LOGIC_OT_python_component_create"; + ot->description = "Create a python component to the selected object"; + + /* api callbacks */ + ot->exec = component_create_exec; + ot->invoke = component_new_invoke; + ot->poll = ED_operator_object_active_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + PropertyRNA *parm; + parm = RNA_def_string(ot->srna, "component_name", "module.Component", 64, "Component", "The component class name with module (module.ComponentName)"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); +} + +static int component_remove_exec(bContext *C, wmOperator *op) +{ + Object *ob = CTX_data_active_object(C); + PythonComponent *pc = NULL; + int index = RNA_int_get(op->ptr, "index"); + + if(!ob) { + return OPERATOR_CANCELLED; + } + + pc = BLI_findlink(&ob->components, index); + + if(!pc) { + return OPERATOR_CANCELLED; + } + + BLI_remlink(&ob->components, pc); + BKE_python_component_free(pc); + + WM_event_add_notifier(C, NC_LOGIC, NULL); + + return OPERATOR_FINISHED; +} + +static void LOGIC_OT_python_component_remove(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Remove Component"; + ot->description = "Remove Component"; + ot->idname = "LOGIC_OT_python_component_remove"; + + /* api callbacks */ + ot->exec = component_remove_exec; + ot->poll = ED_operator_object_active_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Component index to remove", 0, INT_MAX); +} + +static int component_reload_exec(bContext *C, wmOperator *op) +{ + Object *ob = CTX_data_active_object(C); + PythonComponent *pc = NULL, *prev_pc = NULL; + int index = RNA_int_get(op->ptr, "index"); + + if ((G.f & G_SCRIPT_AUTOEXEC) == 0) { + BKE_report(op->reports, RPT_WARNING, "Python script/component auto-execution disable, look in the userpref to activate..."); + return OPERATOR_CANCELLED; + } + + if(!ob) { + return OPERATOR_CANCELLED; + } + + if (index > 0) { + prev_pc = BLI_findlink(&ob->components, index-1); + pc = prev_pc->next; + } + else { + /* pc is at the head */ + pc = BLI_findlink(&ob->components, index); + } + + if(!pc) { + return OPERATOR_CANCELLED; + } + + /* Try to create a new component */ + BKE_python_component_reload(pc, op->reports, C); + + return OPERATOR_FINISHED; +} + +static void LOGIC_OT_python_component_reload(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Reload Component"; + ot->description = "Reload Component"; + ot->idname = "LOGIC_OT_python_component_reload"; + + /* api callbacks */ + ot->exec = component_reload_exec; + ot->poll = ED_operator_object_active_editable; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Component index to reload", 0, INT_MAX); +} + /* ************************* */ void ED_operatortypes_logic(void) @@ -749,5 +944,11 @@ void ED_operatortypes_logic(void) WM_operatortype_append(LOGIC_OT_actuator_remove); WM_operatortype_append(LOGIC_OT_actuator_add); WM_operatortype_append(LOGIC_OT_actuator_move); + + WM_operatortype_append(LOGIC_OT_python_component_register); + WM_operatortype_append(LOGIC_OT_python_component_create); + WM_operatortype_append(LOGIC_OT_python_component_remove); + WM_operatortype_append(LOGIC_OT_python_component_reload); + WM_operatortype_append(LOGIC_OT_view_all); } diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index c8385dfcbe3d..fc5381ed6113 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -359,6 +359,8 @@ static const char *sensor_name(int type) return N_("Random"); case SENS_RAY: return N_("Ray"); + case SENS_MOVEMENT: + return N_("Movement"); case SENS_MESSAGE: return N_("Message"); case SENS_JOYSTICK: @@ -393,8 +395,6 @@ static const char *controller_name(int type) static const char *actuator_name(int type) { switch (type) { - case ACT_SHAPEACTION: - return N_("Shape Action"); case ACT_ACTION: return N_("Action"); case ACT_OBJECT: @@ -423,6 +423,8 @@ static const char *actuator_name(int type) return N_("Message"); case ACT_GAME: return N_("Game"); + case ACT_VIBRATION: + return N_("Vibration"); case ACT_VISIBILITY: return N_("Visibility"); case ACT_2DFILTER: @@ -873,12 +875,10 @@ static void draw_sensor_header(uiLayout *layout, PointerRNA *ptr, PointerRNA *lo RNA_boolean_get(ptr, "active"))); uiItemR(sub, ptr, "pin", UI_ITEM_R_NO_BG, "", ICON_NONE); - if (RNA_boolean_get(ptr, "show_expanded")==0) { - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, RNA_boolean_get(ptr, "active")); - uiItemEnumO(sub, "LOGIC_OT_sensor_move", "", ICON_TRIA_UP, "direction", 1); // up - uiItemEnumO(sub, "LOGIC_OT_sensor_move", "", ICON_TRIA_DOWN, "direction", 2); // down - } + sub = uiLayoutRow(row, true); + uiLayoutSetActive(sub, RNA_boolean_get(ptr, "active")); + uiItemEnumO(sub, "LOGIC_OT_sensor_move", "", ICON_TRIA_UP, "direction", 1); // up + uiItemEnumO(sub, "LOGIC_OT_sensor_move", "", ICON_TRIA_DOWN, "direction", 2); // down sub = uiLayoutRow(row, false); uiItemR(sub, ptr, "active", 0, "", ICON_NONE); @@ -987,41 +987,39 @@ static void draw_sensor_delay(uiLayout *layout, PointerRNA *ptr) static void draw_sensor_joystick(uiLayout *layout, PointerRNA *ptr) { - uiLayout *col, *row; + uiLayout *col, *row, *split; uiItemR(layout, ptr, "joystick_index", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "event_type", 0, NULL, ICON_NONE); + split = uiLayoutSplit(layout, 0.75f, false); + row = uiLayoutRow(split, false); + uiItemR(row, ptr, "event_type", 0, NULL, ICON_NONE); switch (RNA_enum_get(ptr, "event_type")) { case SENS_JOY_BUTTON: - uiItemR(layout, ptr, "use_all_events", 0, NULL, ICON_NONE); + uiItemR(split, ptr, "use_all_events", 0, NULL, ICON_NONE); col = uiLayoutColumn(layout, false); uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_all_events") == false); uiItemR(col, ptr, "button_number", 0, NULL, ICON_NONE); break; case SENS_JOY_AXIS: - row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "axis_number", 0, NULL, ICON_NONE); - uiItemR(row, ptr, "axis_threshold", 0, NULL, ICON_NONE); + uiItemR(split, ptr, "use_all_events", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "use_all_events", 0, NULL, ICON_NONE); col = uiLayoutColumn(layout, false); + uiItemR(col, ptr, "axis_number", 0, NULL, ICON_NONE); uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_all_events") == false); uiItemR(col, ptr, "axis_direction", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "axis_threshold", 0, NULL, ICON_NONE); break; - case SENS_JOY_HAT: - uiItemR(layout, ptr, "hat_number", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "use_all_events", 0, NULL, ICON_NONE); - + case SENS_JOY_AXIS_SINGLE: col = uiLayoutColumn(layout, false); - uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_all_events") == false); - uiItemR(col, ptr, "hat_direction", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "single_axis_number", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "axis_threshold", 0, NULL, ICON_NONE); break; - case SENS_JOY_AXIS_SINGLE: - row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "single_axis_number", 0, NULL, ICON_NONE); - uiItemR(row, ptr, "axis_threshold", 0, NULL, ICON_NONE); + case SENS_JOY_SHOULDER_TRIGGER: + col = uiLayoutColumn(layout, false); + uiItemR(col, ptr, "axis_trigger_number", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "axis_threshold", 0, NULL, ICON_NONE); break; } } @@ -1083,6 +1081,9 @@ static void draw_sensor_mouse(uiLayout *layout, PointerRNA *ptr, bContext *C) uiItemPointerR(split2, ptr, "material", &main_ptr, "materials", "", ICON_MATERIAL_DATA); } uiItemR(split2, ptr, "use_x_ray", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); + + split = uiLayoutSplit(layout, 0.3, false); + uiItemR(split, ptr, "mask", 0, NULL, ICON_NONE); } } @@ -1164,6 +1165,17 @@ static void draw_sensor_ray(uiLayout *layout, PointerRNA *ptr, bContext *C) row = uiLayoutRow(split, false); uiItemR(row, ptr, "range", 0, NULL, ICON_NONE); uiItemR(row, ptr, "use_x_ray", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); + split = uiLayoutSplit(layout, 0.3, false); + uiItemR(split, ptr, "mask", 0, NULL, ICON_NONE); +} + +static void draw_sensor_movement(uiLayout *layout, PointerRNA *ptr) +{ + uiLayout *row; + uiItemR(layout, ptr, "axis", 0, NULL, ICON_NONE); + row = uiLayoutRow(layout, false); + uiItemR(row, ptr, "use_local", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); + uiItemR(row, ptr, "threshold", 0, NULL, ICON_NONE); } static void draw_brick_sensor(uiLayout *layout, PointerRNA *ptr, bContext *C) @@ -1218,6 +1230,9 @@ static void draw_brick_sensor(uiLayout *layout, PointerRNA *ptr, bContext *C) case SENS_RANDOM: draw_sensor_random(box, ptr); break; + case SENS_MOVEMENT: + draw_sensor_movement(box, ptr); + break; case SENS_RAY: draw_sensor_ray(box, ptr, C); break; @@ -1255,12 +1270,10 @@ static void draw_controller_header(uiLayout *layout, PointerRNA *ptr, int xco, i uiLayoutSetActive(sub, RNA_boolean_get(ptr, "active")); uiItemR(sub, ptr, "use_priority", 0, "", ICON_NONE); - if (RNA_boolean_get(ptr, "show_expanded")==0) { - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, RNA_boolean_get(ptr, "active")); - uiItemEnumO(sub, "LOGIC_OT_controller_move", "", ICON_TRIA_UP, "direction", 1); // up - uiItemEnumO(sub, "LOGIC_OT_controller_move", "", ICON_TRIA_DOWN, "direction", 2); // down - } + sub = uiLayoutRow(row, true); + uiLayoutSetActive(sub, RNA_boolean_get(ptr, "active")); + uiItemEnumO(sub, "LOGIC_OT_controller_move", "", ICON_TRIA_UP, "direction", 1); // up + uiItemEnumO(sub, "LOGIC_OT_controller_move", "", ICON_TRIA_DOWN, "direction", 2); // down sub = uiLayoutRow(row, false); uiItemR(sub, ptr, "active", 0, "", ICON_NONE); @@ -1357,12 +1370,10 @@ static void draw_actuator_header(uiLayout *layout, PointerRNA *ptr, PointerRNA * RNA_boolean_get(ptr, "active"))); uiItemR(sub, ptr, "pin", UI_ITEM_R_NO_BG, "", ICON_NONE); - if (RNA_boolean_get(ptr, "show_expanded")==0) { - sub = uiLayoutRow(row, true); - uiLayoutSetActive(sub, RNA_boolean_get(ptr, "active")); - uiItemEnumO(sub, "LOGIC_OT_actuator_move", "", ICON_TRIA_UP, "direction", 1); // up - uiItemEnumO(sub, "LOGIC_OT_actuator_move", "", ICON_TRIA_DOWN, "direction", 2); // down - } + sub = uiLayoutRow(row, true); + uiLayoutSetActive(sub, RNA_boolean_get(ptr, "active")); + uiItemEnumO(sub, "LOGIC_OT_actuator_move", "", ICON_TRIA_UP, "direction", 1); // up + uiItemEnumO(sub, "LOGIC_OT_actuator_move", "", ICON_TRIA_DOWN, "direction", 2); // down sub = uiLayoutRow(row, false); uiItemR(sub, ptr, "active", 0, "", ICON_NONE); @@ -1404,8 +1415,6 @@ static void draw_actuator_action(uiLayout *layout, PointerRNA *ptr) uiItemR(row, ptr, "frame_end", 0, NULL, ICON_NONE); } - uiItemR(row, ptr, "apply_to_children", 0, NULL, ICON_NONE); - row = uiLayoutRow(layout, false); uiItemR(row, ptr, "frame_blend_in", 0, NULL, ICON_NONE); uiItemR(row, ptr, "priority", 0, NULL, ICON_NONE); @@ -1679,6 +1688,7 @@ static void draw_actuator_filter_2d(uiLayout *layout, PointerRNA *ptr) case ACT_2DFILTER_CUSTOMFILTER: uiItemR(layout, ptr, "filter_pass", 0, NULL, ICON_NONE); uiItemR(layout, ptr, "glsl_shader", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_mipmap", 0, NULL, ICON_NONE); break; case ACT_2DFILTER_MOTIONBLUR: split=uiLayoutSplit(layout, 0.75f, true); @@ -1729,11 +1739,13 @@ static void draw_actuator_motion(uiLayout *layout, PointerRNA *ptr) PointerRNA settings_ptr; uiLayout *split, *row, *col, *sub; int physics_type; + bool angular; ob = (Object *)ptr->id.data; RNA_pointer_create((ID *)ob, &RNA_GameObjectSettings, ob, &settings_ptr); physics_type = RNA_enum_get(&settings_ptr, "physics_type"); - + angular = (RNA_enum_get(ptr, "servo_mode") == ACT_SERVO_ANGULAR); + uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE); switch (RNA_enum_get(ptr, "mode")) { @@ -1778,10 +1790,18 @@ static void draw_actuator_motion(uiLayout *layout, PointerRNA *ptr) case ACT_OBJECT_SERVO: uiItemR(layout, ptr, "reference_object", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "servo_mode", 0, NULL, ICON_NONE); + split = uiLayoutSplit(layout, 0.9, false); row = uiLayoutRow(split, false); - uiItemR(row, ptr, "linear_velocity", 0, NULL, ICON_NONE); - uiItemR(split, ptr, "use_local_linear_velocity", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); + if (angular) { + uiItemR(row, ptr, "angular_velocity", 0, NULL, ICON_NONE); + uiItemR(split, ptr, "use_local_angular_velocity", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); + } + else { + uiItemR(row, ptr, "linear_velocity", 0, NULL, ICON_NONE); + uiItemR(split, ptr, "use_local_linear_velocity", UI_ITEM_R_TOGGLE, NULL, ICON_NONE); + } row = uiLayoutRow(layout, false); col = uiLayoutColumn(row, false); @@ -1975,45 +1995,6 @@ static void draw_actuator_scene(uiLayout *layout, PointerRNA *ptr) } } -static void draw_actuator_shape_action(uiLayout *layout, PointerRNA *ptr) -{ - Object *ob = (Object *)ptr->id.data; - PointerRNA settings_ptr; - uiLayout *row; - - if (ob->type != OB_MESH) { - uiItemL(layout, IFACE_("Actuator only available for mesh objects"), ICON_NONE); - return; - } - - RNA_pointer_create((ID *)ob, &RNA_GameObjectSettings, ob, &settings_ptr); - - row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "mode", 0, "", ICON_NONE); - uiItemR(row, ptr, "action", 0, "", ICON_NONE); - uiItemR(row, ptr, "use_continue_last_frame", 0, NULL, ICON_NONE); - - row = uiLayoutRow(layout, false); - if ((RNA_enum_get(ptr, "mode") == ACT_ACTION_FROM_PROP)) - uiItemPointerR(row, ptr, "property", &settings_ptr, "properties", NULL, ICON_NONE); - - else { - uiItemR(row, ptr, "frame_start", 0, NULL, ICON_NONE); - uiItemR(row, ptr, "frame_end", 0, NULL, ICON_NONE); - } - - row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "frame_blend_in", 0, NULL, ICON_NONE); - uiItemR(row, ptr, "priority", 0, NULL, ICON_NONE); - - row = uiLayoutRow(layout, false); - uiItemPointerR(row, ptr, "frame_property", &settings_ptr, "properties", NULL, ICON_NONE); - -#ifdef __NLA_ACTION_BY_MOTION_ACTUATOR - uiItemR(row, "stride_length", 0, NULL, ICON_NONE); -#endif -} - static void draw_actuator_sound(uiLayout *layout, PointerRNA *ptr, bContext *C) { uiLayout *row, *col; @@ -2064,6 +2045,32 @@ static void draw_actuator_state(uiLayout *layout, PointerRNA *ptr) uiTemplateLayers(split, ptr, "states", &settings_ptr, "used_states", 0); } +static void draw_actuator_vibration(uiLayout *layout, PointerRNA *ptr) +{ + uiLayout *row; + row = uiLayoutRow(layout, false); + + uiItemR(layout, ptr, "mode", 0, NULL, 0); + + switch (RNA_enum_get(ptr, "mode")) { + case ACT_VIBRATION_PLAY: + { + uiItemR(row, ptr, "joy_index", 0, NULL, ICON_NONE); + row = uiLayoutRow(layout, false); + uiItemR(row, ptr, "joy_strength_left", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "joy_strength_right", 0, NULL, ICON_NONE); + row = uiLayoutRow(layout, false); + uiItemR(row, ptr, "joy_duration", 0, NULL, ICON_NONE); + break; + } + case ACT_VIBRATION_STOP: + { + uiItemR(row, ptr, "joy_index", 0, NULL, ICON_NONE); + break; + } + } +} + static void draw_actuator_visibility(uiLayout *layout, PointerRNA *ptr) { uiLayout *row; @@ -2232,15 +2239,15 @@ static void draw_brick_actuator(uiLayout *layout, PointerRNA *ptr, bContext *C) case ACT_SCENE: draw_actuator_scene(box, ptr); break; - case ACT_SHAPEACTION: - draw_actuator_shape_action(box, ptr); - break; case ACT_SOUND: draw_actuator_sound(box, ptr, C); break; case ACT_STATE: draw_actuator_state(box, ptr); break; + case ACT_VIBRATION: + draw_actuator_vibration(box, ptr); + break; case ACT_VISIBILITY: draw_actuator_visibility(box, ptr); break; diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 6e52af2898eb..9c82c8ce4796 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -288,6 +288,13 @@ static void node_buts_texture(uiLayout *layout, bContext *UNUSED(C), PointerRNA } } +static void node_buts_parallax(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "texture", 0, "", ICON_NONE); + uiItemR(layout, ptr, "component", 0, "", ICON_NONE); + uiItemR(layout, ptr, "discard", 0, "Discard", ICON_NONE); +} + static void node_buts_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); @@ -850,7 +857,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA static void node_shader_buts_tex_image_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) { PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user"); - uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 0); + uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 0, 0, 1); } static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -1193,6 +1200,9 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_TEXTURE: ntype->draw_buttons = node_buts_texture; break; + case SH_NODE_PARALLAX: + ntype->draw_buttons = node_buts_parallax; + break; case SH_NODE_NORMAL: ntype->draw_buttons = node_buts_normal; break; @@ -1380,7 +1390,7 @@ static void node_composit_buts_image_ex(uiLayout *layout, bContext *C, PointerRN RNA_pointer_create((ID *)ptr->id.data, &RNA_ImageUser, node->storage, &iuserptr); uiLayoutSetContextPointer(layout, "image_user", &iuserptr); - uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 1); + uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 1, 0, 1); } static void node_composit_buts_renderlayers(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -2918,7 +2928,7 @@ static void node_texture_buts_image_ex(uiLayout *layout, bContext *C, PointerRNA PointerRNA iuserptr; RNA_pointer_create((ID *)ptr->id.data, &RNA_ImageUser, node->storage, &iuserptr); - uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 0); + uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 0, 0, 1); } static void node_texture_buts_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) diff --git a/source/blender/editors/space_text/CMakeLists.txt b/source/blender/editors/space_text/CMakeLists.txt index 91420a5d63aa..618c17f38ccd 100644 --- a/source/blender/editors/space_text/CMakeLists.txt +++ b/source/blender/editors/space_text/CMakeLists.txt @@ -41,6 +41,7 @@ set(SRC text_autocomplete.c text_draw.c text_format.c + text_format_glsl.c text_format_lua.c text_format_osl.c text_format_pov.c diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c index fc05fb51c1ab..20402a82ff44 100644 --- a/source/blender/editors/space_text/space_text.c +++ b/source/blender/editors/space_text/space_text.c @@ -330,7 +330,8 @@ static void text_keymap(struct wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "TEXT_OT_indent", TABKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "TEXT_OT_unindent", TABKEY, KM_PRESS, KM_SHIFT, 0); - WM_keymap_add_item(keymap, "TEXT_OT_uncomment", DKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0); + WM_keymap_add_item(keymap, "TEXT_OT_comment", LEFTBRACKETKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "TEXT_OT_uncomment", LEFTBRACKETKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0); RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", HOMEKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_BEGIN); RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", ENDKEY, KM_PRESS, 0, 0)->ptr, "type", LINE_END); @@ -638,4 +639,5 @@ void ED_spacetype_text(void) ED_text_format_register_lua(); ED_text_format_register_pov(); ED_text_format_register_pov_ini(); + ED_text_format_register_glsl(); } diff --git a/source/blender/editors/space_text/text_format.h b/source/blender/editors/space_text/text_format.h index 5912dc2402c8..7e538578ad2f 100644 --- a/source/blender/editors/space_text/text_format.h +++ b/source/blender/editors/space_text/text_format.h @@ -80,6 +80,7 @@ typedef struct TextFormatType { void (*format_line)(SpaceText *st, TextLine *line, const bool do_next); const char **ext; /* NULL terminated extensions */ + const char *comment_prefix; /* Language comment prefix. e.g: # */ } TextFormatType; enum { @@ -90,7 +91,7 @@ enum { FMT_TYPE_STRING = 'l', /* String letters */ FMT_TYPE_DIRECTIVE = 'd', /* Decorator / Preprocessor directive */ FMT_TYPE_SPECIAL = 'v', /* Special variables (class, def) */ - FMT_TYPE_RESERVED = 'r', /* Reserved keywords currently not in use, but still prohibited (OSL -> switch e.g.) */ + FMT_TYPE_RESERVED = 'r', /* Reserved keywords (OSL -> switch e.g.) */ FMT_TYPE_KEYWORD = 'b', /* Built-in names (return, for, etc.) */ FMT_TYPE_DEFAULT = 'q', /* Regular text (identifiers, etc.) */ }; @@ -104,6 +105,7 @@ void ED_text_format_register_osl(void); void ED_text_format_register_lua(void); void ED_text_format_register_pov(void); void ED_text_format_register_pov_ini(void); +void ED_text_format_register_glsl(void); #define STR_LITERAL_STARTSWITH(str, str_literal, len_var) \ (strncmp(str, str_literal, len_var = (sizeof(str_literal) - 1)) == 0) diff --git a/source/blender/editors/space_text/text_format_glsl.c b/source/blender/editors/space_text/text_format_glsl.c new file mode 100644 index 000000000000..f8c6e4e8d779 --- /dev/null +++ b/source/blender/editors/space_text/text_format_glsl.c @@ -0,0 +1,457 @@ + +/* + * ***** 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 + * GNU General Public License for more details. + * + * You 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/space_text/text_format_glsl.c + * \ingroup sptext + */ + +#include + +#include "BLI_blenlib.h" + +#include "DNA_text_types.h" +#include "DNA_space_types.h" + +#include "BKE_text.h" + +#include "text_format.h" + +/* *** glsl Keywords (for format_line) *** */ + +/* Checks the specified source string for a glsl keyword (minus boolean & 'nil'). + * This name must start at the beginning of the source string and must be + * followed by a non-identifier (see text_check_identifier(char)) or null char. + * + * If a keyword is found, the length of the matching word is returned. + * Otherwise, -1 is returned. + * + */ + +static int txtfmt_glsl_find_keyword(const char *string) +{ + int i, len; + + if (STR_LITERAL_STARTSWITH(string, "if", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "else", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "void", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "float", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "int", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "uniform", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "varying", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "location", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "in", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "out", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "discard", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "return", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "vec2", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "vec3", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "vec4", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "mat3", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "mat4", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sampler2D", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sampler1D", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "samplerCube", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "const", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "uint", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "uvec2", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "uvec3", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "uvec4", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "for", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "while", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "continue", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "break", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "inout", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "attribute", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "layout", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "centroid", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "flat", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "smooth", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "patch", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sample", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "do", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "switch", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "case", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "default", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "subroutine", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "double", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "invariant", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "dmat2", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "dmat3", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "dmat4", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "mat2", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ivec2", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ivec3", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ivec4", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "bvec2", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "bvec3", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "bvec4", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "dvec2", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "dvec3", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "dvec4", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "precision", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "lowp", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "highp", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "mediump", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sampler3D", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "struct", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "goto", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sizeof", len)) i = len; + else i = 0; + + /* If next source char is an identifier (eg. 'i' in "definate") no match */ + if (i == 0 || text_check_identifier(string[i])) + return -1; + return i; +} + +/* Checks the specified source string for a glsl special name/function. This + * name must start at the beginning of the source string and must be followed + * by a non-identifier (see text_check_identifier(char)) or null character. + * + * If a special name is found, the length of the matching name is returned. + * Otherwise, -1 is returned. + * + */ + +static int txtfmt_glsl_find_specialvar(const char *string) +{ + int i, len; + + if (STR_LITERAL_STARTSWITH(string, "gl_Position;", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_VertexID;", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_InstanceID;", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_PointSize;", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_ClipDistance", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_PerVertex", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_ViewportIndex", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_Layer", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_ViewportIndex", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_TessLevelOuter", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_TessLevelInner", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_FragCoord", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_FrontFacing", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_PointCoord", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_PrimitiveID", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_SampleID", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_SamplePosition", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_FragColor", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_FragData", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_MaxDrawBuffers", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_FragDepth", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_SampleMask", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_ClipVertex", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_FrontColor", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_BackColor", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_TexCoord", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_FogFragCoord", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_Color", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_Normal", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_MultiTexCoord0", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_MultiTexCoord1", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_MultiTexCoord2", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_MultiTexCoord3", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_MultiTexCoord4", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_MultiTexCoord5", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_MultiTexCoord6", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_MultiTexCoord7", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_FogCoord", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_NormalMatrix", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_ModelViewMatrix", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_ProjectionMatrix", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_ModelViewProjectionMatrix", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ftransform", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_TextureMatrix", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_MaxTextureCoords", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_ModelViewMatrixInverse", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_ProjectionMatrixInverse", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_ModelViewProjectionMatrixInverse", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_ModelViewMatrixTranspose", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_ProjectionMatrixTranspose", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_ModelViewProjectionMatrixTranspose", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_ClipPlane", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_LightSource", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_MaxLights", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_LightModel", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_Fog", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_FrontMaterial", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_BackMaterial", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_Point", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "gl_NormalScale", len)) i = len; + else i = 0; + + /* If next source char is an identifier (eg. 'i' in "definate") no match */ + if (i == 0 || text_check_identifier(string[i])) + return -1; + return i; +} + +static int txtfmt_glsl_find_bool(const char *string) +{ + int i, len; + + if (STR_LITERAL_STARTSWITH(string, "null", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "true", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "false", len)) i = len; + else i = 0; + + /* If next source char is an identifier (eg. 'i' in "Nonetheless") no match */ + if (i == 0 || text_check_identifier(string[i])) + return -1; + return i; +} + +static int txtfmt_glsl_find_reserved(const char *string) { + int i, len; + + if (STR_LITERAL_STARTSWITH(string, "min", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "max", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "abs", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "dot", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "cross", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "reflect", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "refract", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "pow", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "exp", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "dFdx", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "dFdy", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "log", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "cos", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sin", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "tan", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "smoothstep", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "mix", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "radians", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "degrees", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "asin", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "acos", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "atan", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "atan2", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "exp2", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "log2", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sqrt", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "inversesqrt", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "sign", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "floor", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "ceil", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "fract", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "mod", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "clamp", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "step", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "trunc", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "round", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "length", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "distance", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "normalize", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "faceforward", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "any", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "all", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "not", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "texture3DLod", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "texture2DLod", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "texture1DLod", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "textureCubeLod", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "texture3D", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "texture2D", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "texture1D", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "textureCube", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "texture", len)) i = len; + else i = 0; + /* If next source char is an identifier (eg. 'i' in "Nonetheless") no match */ + if(i == 0 || text_check_identifier(string[i])) + return -1; + return i; +} + +static char txtfmt_glsl_format_identifier(const char *str) +{ + char fmt; + if ((txtfmt_glsl_find_specialvar(str)) != -1) fmt = FMT_TYPE_SPECIAL; + else if ((txtfmt_glsl_find_keyword(str)) != -1) fmt = FMT_TYPE_KEYWORD; + else if ((txtfmt_glsl_find_reserved(str)) != -1) fmt = FMT_TYPE_RESERVED; + else fmt = FMT_TYPE_DEFAULT; + return fmt; +} + +static void txtfmt_glsl_format_line(SpaceText *st, TextLine *line, const bool do_next) +{ + FlattenString fs; + const char *str; + char *fmt; + char cont_orig, cont, find, prev = ' '; + int len, i; + + /* Get continuation from previous line */ + if (line->prev && line->prev->format != NULL) { + fmt = line->prev->format; + cont = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */ + BLI_assert((FMT_CONT_ALL & cont) == cont); + } + else { + cont = FMT_CONT_NOP; + } + + /* Get original continuation from this line */ + if (line->format != NULL) { + fmt = line->format; + cont_orig = fmt[strlen(fmt) + 1]; /* Just after the null-terminator */ + BLI_assert((FMT_CONT_ALL & cont_orig) == cont_orig); + } + else { + cont_orig = 0xFF; + } + + len = flatten_string(st, &fs, line->line); + str = fs.buf; + if (!text_check_format_len(line, len)) { + flatten_string_free(&fs); + return; + } + fmt = line->format; + + while (*str) { + /* Handle escape sequences by skipping both \ and next char */ + if (*str == '\\') { + *fmt = prev; fmt++; str++; + if (*str == '\0') break; + *fmt = prev; fmt++; str += BLI_str_utf8_size_safe(str); + continue; + } + /* Handle continuations */ + else if (cont) { + /* Multi-line comments */ + if (cont & FMT_CONT_COMMENT_C) { + if (*str == '*' && *(str + 1) == '/') { + *fmt = FMT_TYPE_COMMENT; fmt++; str++; + *fmt = FMT_TYPE_COMMENT; + cont = FMT_CONT_NOP; + } + else { + *fmt = FMT_TYPE_COMMENT; + } + /* Handle other comments */ + } + else { + find = (cont & FMT_CONT_QUOTEDOUBLE) ? '"' : '\''; + if (*str == find) cont = 0; + *fmt = FMT_TYPE_STRING; + } + + str += BLI_str_utf8_size_safe(str) - 1; + } + /* Not in a string... */ + else { + /* Multi-line comments */ + if (*str == '/' && *(str + 1) == '*') + { + cont = FMT_CONT_COMMENT_C; + *fmt = FMT_TYPE_COMMENT; fmt++; str++; + *fmt = FMT_TYPE_COMMENT; fmt++; str++; + *fmt = FMT_TYPE_COMMENT; fmt++; str++; + *fmt = FMT_TYPE_COMMENT; + } + /* Single line comment */ + else if (*str == '/' && *(str + 1) == '/') { + text_format_fill(&str, &fmt, FMT_TYPE_COMMENT, len - (int)(fmt - line->format)); + } + else if (*str == '"' || *str == '\'') { + /* Strings */ + find = *str; + cont = (*str == '"') ? FMT_CONT_QUOTEDOUBLE : FMT_CONT_QUOTESINGLE; + *fmt = FMT_TYPE_STRING; + } + /* Whitespace (all ws. has been converted to spaces) */ + else if (*str == ' ') { + *fmt = FMT_TYPE_WHITESPACE; + } + /* Numbers (digits not part of an identifier and periods followed by digits) */ + else if ((prev != FMT_TYPE_DEFAULT && text_check_digit(*str)) || + (*str == '.' && text_check_digit(*(str + 1)))) + { + *fmt = FMT_TYPE_NUMERAL; + } + /* Booleans */ + else if (prev != FMT_TYPE_DEFAULT && (i = txtfmt_glsl_find_bool(str)) != -1) { + if (i > 0) { + text_format_fill_ascii(&str, &fmt, FMT_TYPE_NUMERAL, i); + } + else { + str += BLI_str_utf8_size_safe(str) - 1; + *fmt = FMT_TYPE_DEFAULT; + } + } + /* Punctuation */ + else if ((*str != '#') && text_check_delim(*str)) { + *fmt = FMT_TYPE_SYMBOL; + } + + /* Preprocessor */ + else if ((*str == '#')) { + text_format_fill(&str, &fmt, FMT_TYPE_DIRECTIVE, len - (int)(fmt - line->format)); + } + + /* Identifiers and other text (no previous ws. or delims. so text continues) */ + else if (prev == FMT_TYPE_DEFAULT) { + str += BLI_str_utf8_size_safe(str) - 1; + *fmt = FMT_TYPE_DEFAULT; + } + /* Not ws, a digit, punct, or continuing text. Must be new, check for special words */ + else { + /* Special vars(v) or built-in keywords(b) */ + /* keep in sync with 'txtfmt_osl_format_identifier()' */ + if ((i = txtfmt_glsl_find_specialvar(str)) != -1) prev = FMT_TYPE_SPECIAL; + else if ((i = txtfmt_glsl_find_keyword(str)) != -1) prev = FMT_TYPE_KEYWORD; + else if ((i = txtfmt_glsl_find_reserved(str)) != -1) prev = FMT_TYPE_RESERVED; + + if (i > 0) { + text_format_fill_ascii(&str, &fmt, prev, i); + } + else { + str += BLI_str_utf8_size_safe(str) - 1; + *fmt = FMT_TYPE_DEFAULT; + } + } + } + prev = *fmt; fmt++; str++; + } + + /* Terminate and add continuation char */ + *fmt = '\0'; fmt++; + *fmt = cont; + + /* If continuation has changed and we're allowed, process the next line */ + if (cont != cont_orig && do_next && line->next) { + txtfmt_glsl_format_line(st, line->next, do_next); + } + + flatten_string_free(&fs); +} + +void ED_text_format_register_glsl(void) +{ + static TextFormatType tft = {NULL}; + static const char *ext[] = {"glsl", "frag", "vert", "fx", "fs", "vs", NULL}; + + tft.format_identifier = txtfmt_glsl_format_identifier; + tft.format_line = txtfmt_glsl_format_line; + tft.ext = ext; + tft.comment_prefix = "//"; + + ED_text_format_register(&tft); +} diff --git a/source/blender/editors/space_text/text_format_lua.c b/source/blender/editors/space_text/text_format_lua.c index 8b6ec2d804b0..2b044aba5d0e 100644 --- a/source/blender/editors/space_text/text_format_lua.c +++ b/source/blender/editors/space_text/text_format_lua.c @@ -306,6 +306,7 @@ void ED_text_format_register_lua(void) tft.format_identifier = txtfmt_lua_format_identifier; tft.format_line = txtfmt_lua_format_line; tft.ext = ext; + tft.comment_prefix = "--"; ED_text_format_register(&tft); } diff --git a/source/blender/editors/space_text/text_format_osl.c b/source/blender/editors/space_text/text_format_osl.c index 2daaaa348e68..53de7aad6f34 100644 --- a/source/blender/editors/space_text/text_format_osl.c +++ b/source/blender/editors/space_text/text_format_osl.c @@ -324,6 +324,7 @@ void ED_text_format_register_osl(void) tft.format_identifier = txtfmt_osl_format_identifier; tft.format_line = txtfmt_osl_format_line; tft.ext = ext; + tft.comment_prefix = "//"; ED_text_format_register(&tft); } diff --git a/source/blender/editors/space_text/text_format_py.c b/source/blender/editors/space_text/text_format_py.c index 2f6962f04932..f818e1d7683e 100644 --- a/source/blender/editors/space_text/text_format_py.c +++ b/source/blender/editors/space_text/text_format_py.c @@ -87,6 +87,7 @@ static int txtfmt_py_find_builtinfunc(const char *string) else if (STR_LITERAL_STARTSWITH(string, "while", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "with", len)) i = len; else if (STR_LITERAL_STARTSWITH(string, "yield", len)) i = len; + else if (STR_LITERAL_STARTSWITH(string, "self", len)) i = len; else i = 0; /* If next source char is an identifier (eg. 'i' in "definate") no match */ @@ -313,6 +314,7 @@ void ED_text_format_register_py(void) tft.format_identifier = txtfmt_py_format_identifier; tft.format_line = txtfmt_py_format_line; tft.ext = ext; + tft.comment_prefix = "#"; ED_text_format_register(&tft); } diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index c8e9167edf9b..91da2d8b6edc 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -1016,6 +1016,9 @@ static int text_comment_exec(bContext *C, wmOperator *UNUSED(op)) Text *text = CTX_data_edit_text(C); if (txt_has_sel(text)) { + TextFormatType *tft = ED_text_format_get(text); + text->cmmt_pfx = tft->comment_prefix; + text_drawcache_tag_update(CTX_wm_space_text(C), 0); TextUndoBuf *utxt = ED_text_undo_push_init(C); @@ -1054,6 +1057,9 @@ static int text_uncomment_exec(bContext *C, wmOperator *UNUSED(op)) Text *text = CTX_data_edit_text(C); if (txt_has_sel(text)) { + TextFormatType *tft = ED_text_format_get(text); + text->cmmt_pfx = tft->comment_prefix; + text_drawcache_tag_update(CTX_wm_space_text(C), 0); TextUndoBuf *utxt = ED_text_undo_push_init(C); diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index e25a9c04f15b..3141c75a5952 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -76,7 +76,7 @@ endif() if(WITH_GAMEENGINE) list(APPEND INC - ../../../gameengine/BlenderRoutines + ../../../gameengine/Launcher ) add_definitions(-DWITH_GAMEENGINE) endif() diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index c3d60d9ee761..c388d6af8d1c 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -779,149 +779,6 @@ static DMDrawOption wpaint__setSolidDrawOptions_facemask(void *userData, int ind return DM_DRAW_OPTION_NORMAL; } -static void draw_mesh_text(Scene *scene, Object *ob, int glsl) -{ - Mesh *me = ob->data; - DerivedMesh *ddm; - MPoly *mp, *mface = me->mpoly; - MTexPoly *mtpoly = me->mtpoly; - MLoopUV *mloopuv = me->mloopuv; - MLoopUV *luv; - MLoopCol *mloopcol = me->mloopcol; /* why does mcol exist? */ - MLoopCol *lcol; - - bProperty *prop = BKE_bproperty_object_get(ob, "Text"); - GPUVertexAttribs gattribs; - int a, totpoly = me->totpoly; - - /* fake values to pass to GPU_render_text() */ - MCol tmp_mcol[4] = {{0}}; - MCol *tmp_mcol_pt = mloopcol ? tmp_mcol : NULL; - - /* don't draw without tfaces */ - if (!mtpoly || !mloopuv) - return; - - /* don't draw when editing */ - if (ob->mode & OB_MODE_EDIT) - return; - else if (ob == OBACT) - if (BKE_paint_select_elem_test(ob)) - return; - - ddm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); - - for (a = 0, mp = mface; a < totpoly; a++, mtpoly++, mp++) { - short matnr = mp->mat_nr; - const bool mf_smooth = (mp->flag & ME_SMOOTH) != 0; - Material *mat = (me->mat) ? me->mat[matnr] : NULL; - int mode = mat ? mat->game.flag : GEMAT_INVISIBLE; - - - if (!(mode & GEMAT_INVISIBLE) && (mode & GEMAT_TEXT) && mp->totloop >= 3) { - /* get the polygon as a tri/quad */ - int mp_vi[4]; - float v_quad_data[4][3]; - const float *v_quad[4]; - const float *uv_quad[4]; - char string[MAX_PROPSTRING]; - int characters, i, glattrib = -1, badtex = 0; - - - /* TEXFACE */ - if (glsl) { - GPU_object_material_bind(matnr + 1, &gattribs); - - for (i = 0; i < gattribs.totlayer; i++) { - if (gattribs.layer[i].type == CD_MTFACE) { - glattrib = gattribs.layer[i].glindex; - break; - } - } - } - else { - badtex = set_draw_settings_cached(0, mtpoly, mat, &Gtexdraw); - if (badtex) { - continue; - } - } - - mp_vi[0] = me->mloop[mp->loopstart + 0].v; - mp_vi[1] = me->mloop[mp->loopstart + 1].v; - mp_vi[2] = me->mloop[mp->loopstart + 2].v; - mp_vi[3] = (mp->totloop >= 4) ? me->mloop[mp->loopstart + 3].v : 0; - - /* UV */ - luv = &mloopuv[mp->loopstart]; - uv_quad[0] = luv->uv; luv++; - uv_quad[1] = luv->uv; luv++; - uv_quad[2] = luv->uv; luv++; - if (mp->totloop >= 4) { - uv_quad[3] = luv->uv; - } - else { - uv_quad[3] = NULL; - } - - - /* COLOR */ - if (mloopcol) { - unsigned int totloop_clamp = min_ii(4, mp->totloop); - unsigned int j; - lcol = &mloopcol[mp->loopstart]; - - for (j = 0; j < totloop_clamp; j++, lcol++) { - MESH_MLOOPCOL_TO_MCOL(lcol, &tmp_mcol[j]); - } - } - - /* LOCATION */ - ddm->getVertCo(ddm, mp_vi[0], v_quad_data[0]); - ddm->getVertCo(ddm, mp_vi[1], v_quad_data[1]); - ddm->getVertCo(ddm, mp_vi[2], v_quad_data[2]); - if (mp->totloop >= 4) { - ddm->getVertCo(ddm, mp_vi[3], v_quad_data[3]); - } - - v_quad[0] = v_quad_data[0]; - v_quad[1] = v_quad_data[1]; - v_quad[2] = v_quad_data[2]; - if (mp->totloop >= 4) { - v_quad[3] = v_quad_data[2]; - } - else { - v_quad[3] = NULL; - } - - - /* The BM_FONT handling is in the gpu module, shared with the - * game engine, was duplicated previously */ - - BKE_bproperty_set_valstr(prop, string); - characters = strlen(string); - - if (!BKE_image_has_ibuf(mtpoly->tpage, NULL)) - characters = 0; - - if (!mf_smooth) { - float nor[3]; - - normal_tri_v3(nor, v_quad[0], v_quad[1], v_quad[2]); - - glNormal3fv(nor); - } - - GPU_render_text( - mtpoly, mode, string, characters, - (unsigned int *)tmp_mcol_pt, - v_quad, uv_quad, - glattrib); - } - } - - ddm->release(ddm); -} - static int compareDrawOptions(void *userData, int cur_index, int next_index) { drawTFace_userData *data = userData; @@ -1039,13 +896,6 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d } } - /* draw game engine text hack */ - if (rv3d->rflag & RV3D_IS_GAME_ENGINE) { - if (BKE_bproperty_object_get(ob, "Text")) { - draw_mesh_text(scene, ob, 0); - } - } - draw_textured_end(); /* draw edges and selected faces over textured mesh */ diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index c10f8f0ce164..d8329e1e790b 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -309,7 +309,7 @@ bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt) return true; if (v3d->drawtype == OB_TEXTURE) - return (scene->gm.matmode == GAME_MAT_GLSL && !BKE_scene_use_new_shading_nodes(scene)); + return (!BKE_scene_use_new_shading_nodes(scene)); else if (v3d->drawtype == OB_MATERIAL && dt > OB_SOLID) return true; else @@ -1130,18 +1130,8 @@ static void draw_transp_spot_volume(Lamp *la, float x, float z) } #ifdef WITH_GAMEENGINE -static void draw_transp_sun_volume(Lamp *la) +static void draw_shadow_volume(const float box[8][3]) { - float box[8][3]; - - /* construct box */ - box[0][0] = box[1][0] = box[2][0] = box[3][0] = -la->shadow_frustum_size; - box[4][0] = box[5][0] = box[6][0] = box[7][0] = +la->shadow_frustum_size; - box[0][1] = box[1][1] = box[4][1] = box[5][1] = -la->shadow_frustum_size; - box[2][1] = box[3][1] = box[6][1] = box[7][1] = +la->shadow_frustum_size; - box[0][2] = box[3][2] = box[4][2] = box[7][2] = -la->clipend; - box[1][2] = box[2][2] = box[5][2] = box[6][2] = -la->clipsta; - /* draw edges */ draw_box(box, false); @@ -1173,6 +1163,44 @@ static void draw_transp_sun_volume(Lamp *la) glDisable(GL_CULL_FACE); glCullFace(GL_BACK); } + +static void draw_transp_sun_shadow_volume(Lamp *la) +{ + float box[8][3]; + + /* construct box */ + box[0][0] = box[1][0] = box[2][0] = box[3][0] = -la->shadow_frustum_size; + box[4][0] = box[5][0] = box[6][0] = box[7][0] = +la->shadow_frustum_size; + box[0][1] = box[1][1] = box[4][1] = box[5][1] = -la->shadow_frustum_size; + box[2][1] = box[3][1] = box[6][1] = box[7][1] = +la->shadow_frustum_size; + box[0][2] = box[3][2] = box[4][2] = box[7][2] = -la->clipend; + box[1][2] = box[2][2] = box[5][2] = box[6][2] = -la->clipsta; + + draw_shadow_volume(box); +} + +static void draw_transp_spot_shadow_volume(Lamp *la) +{ + float box[8][3]; + + const float x = tanf(la->spotsize * 0.5f); + const float xtop = x * la->clipsta; + const float xbottom = x * la->clipend; + + /* construct box */ + box[0][0] = box[3][0] = -xbottom; + box[2][0] = box[1][0] = -xtop; + box[4][0] = box[7][0] = xbottom; + box[6][0] = box[5][0] = xtop; + box[0][1] = box[4][1] = -xbottom; + box[1][1] = box[5][1] = -xtop; + box[3][1] = box[7][1] = xbottom; + box[2][1] = box[6][1] = xtop; + box[0][2] = box[3][2] = box[4][2] = box[7][2] = -la->clipend; + box[1][2] = box[2][2] = box[5][2] = box[6][2] = -la->clipsta; + + draw_shadow_volume(box); +} #endif static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, @@ -1202,7 +1230,8 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, (rv3d->rflag & RV3D_IS_GAME_ENGINE) && (dt > OB_WIRE) && !(G.f & G_PICKSEL) && - (la->type == LA_SUN) && + ((la->type == LA_SUN) || + (la->type == LA_SPOT)) && ((la->mode & LA_SHAD_BUF) || (la->mode & LA_SHAD_RAY)) && (la->mode & LA_SHOW_SHADOW_BOX) && @@ -1437,6 +1466,12 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, glVertex3f(0.0, 0.0, -la->dist); } glEnd(); + +#ifdef WITH_GAMEENGINE + if (drawshadowbox) { + draw_transp_spot_shadow_volume(la); + } +#endif } else if (ELEM(la->type, LA_HEMI, LA_SUN)) { @@ -1489,7 +1524,7 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, #ifdef WITH_GAMEENGINE if (drawshadowbox) { - draw_transp_sun_volume(la); + draw_transp_sun_shadow_volume(la); } #endif @@ -3905,7 +3940,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, draw_em_measure_stats(ar, v3d, ob, em, &scene->unit); } - if ((G.debug & G_DEBUG) && (me->drawflag & ME_DRAWEXTRA_INDICES) && + if ((me->drawflag & ME_DRAWEXTRA_INDICES) && !(v3d->flag2 & V3D_RENDER_OVERRIDE)) { draw_em_indices(em); @@ -4056,10 +4091,6 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D else dm->drawFacesGLSL(dm, GPU_object_material_bind); -#if 0 /* XXX */ - if (BKE_bproperty_object_get(ob, "Text")) - draw_mesh_text(ob, 1); -#endif GPU_object_material_unbind(); glFrontFace(GL_CCW); diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index fed056333c0d..9fafa91fcac9 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -928,9 +928,7 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w Object *ob = OBACT; if ((v3d->drawtype == OB_MATERIAL) || (ob && (ob->mode == OB_MODE_TEXTURE_PAINT)) || - (v3d->drawtype == OB_TEXTURE && - (scene->gm.matmode == GAME_MAT_GLSL || - BKE_scene_use_new_shading_nodes(scene))) || + (v3d->drawtype == OB_TEXTURE) || !DEG_depsgraph_use_legacy()) #endif { @@ -955,7 +953,7 @@ static void view3d_main_region_listener(bScreen *sc, ScrArea *sa, ARegion *ar, w switch (wmn->data) { case ND_LIGHTING: if ((v3d->drawtype == OB_MATERIAL) || - (v3d->drawtype == OB_TEXTURE && (scene->gm.matmode == GAME_MAT_GLSL)) || + (v3d->drawtype == OB_TEXTURE) || !DEG_depsgraph_use_legacy()) { ED_region_tag_redraw(ar); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 1cf2e71f2bf1..29f81751ebe8 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -97,6 +97,7 @@ #include "GPU_draw.h" #include "GPU_framebuffer.h" +#include "GPU_shader.h" #include "GPU_material.h" #include "GPU_compositing.h" #include "GPU_extensions.h" @@ -1390,7 +1391,7 @@ static void backdrawview3d(Scene *scene, wmWindow *win, ARegion *ar, View3D *v3d } if (!rv3d->gpuoffscreen) { - rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, error); + rv3d->gpuoffscreen = GPU_offscreen_create(w, h, 0, GPU_HDR_NONE, GPU_OFFSCREEN_DEPTH_COMPARE, error); if (!rv3d->gpuoffscreen) fprintf(stderr, "Failed to create offscreen selection buffer for multisample: %s\n", error); @@ -2650,6 +2651,7 @@ static void gpu_update_lamps_shadows_world(Main *bmain, Scene *scene, View3D *v3 int drawtype, lay, winsize, flag2 = v3d->flag2; ARegion ar = {NULL}; RegionView3D rv3d = {{{0}}}; + bool vsm = GPU_lamp_shadow_buffer_type(shadow->lamp) == LA_SHADMAP_VARIANCE; drawtype = v3d->drawtype; lay = v3d->lay; @@ -2659,6 +2661,9 @@ static void gpu_update_lamps_shadows_world(Main *bmain, Scene *scene, View3D *v3 v3d->flag2 &= ~(V3D_SOLID_TEX | V3D_SHOW_SOLID_MATCAP); v3d->flag2 |= V3D_RENDER_OVERRIDE | V3D_RENDER_SHADOW; + if (vsm) { + GPU_shader_bind(GPU_shader_get_builtin_shader(GPU_SHADER_VSM_STORE)); + } GPU_lamp_shadow_buffer_bind(shadow->lamp, viewmat, &winsize, winmat); ar.regiondata = &rv3d; @@ -2675,6 +2680,10 @@ static void gpu_update_lamps_shadows_world(Main *bmain, Scene *scene, View3D *v3 bmain, scene, v3d, &ar, winsize, winsize, viewmat, winmat, false, false, true, NULL, NULL, NULL, NULL); + + if (vsm) { + GPU_shader_unbind(); + } GPU_lamp_shadow_buffer_unbind(shadow->lamp); v3d->drawtype = drawtype; @@ -2686,11 +2695,13 @@ static void gpu_update_lamps_shadows_world(Main *bmain, Scene *scene, View3D *v3 /* update world values */ if (world) { - GPU_mist_update_enable(world->mode & WO_MIST); + GPU_mist_update_enable(world->mode & WO_MIST && v3d->flag2 & V3D_SHOW_MIST); GPU_mist_update_values(world->mistype, world->miststa, world->mistdist, world->misi, &world->horr); GPU_horizon_update_color(&world->horr); GPU_ambient_update_color(&world->ambr); GPU_zenith_update_color(&world->zenr); + GPU_update_exposure_range(world->exp, world->range); + GPU_update_envlight_energy(world->ao_env_energy); } } @@ -2711,7 +2722,7 @@ CustomDataMask ED_view3d_datamask(const Scene *scene, const View3D *v3d) mask |= CD_MASK_ORCO; } else { - if ((scene->gm.matmode == GAME_MAT_GLSL && drawtype == OB_TEXTURE) || + if ((drawtype == OB_TEXTURE) || (drawtype == OB_MATERIAL)) { mask |= CD_MASK_ORCO; @@ -3093,10 +3104,10 @@ static void view3d_main_region_clear(Scene *scene, View3D *v3d, ARegion *ar) { if (scene->world && (v3d->flag2 & V3D_SHOW_WORLD)) { RegionView3D *rv3d = ar->regiondata; - GPUMaterial *gpumat = GPU_material_world(scene, scene->world); + GPUMaterial *gpumat = GPU_material_world(scene, scene->world, 0); /* calculate full shader for background */ - GPU_material_bind(gpumat, 1, 1, 1.0, false, rv3d->viewmat, rv3d->viewinv, rv3d->viewcamtexcofac, (v3d->scenelock != 0)); + GPU_material_bind(gpumat, 1, 1.0, true, rv3d->viewmat, rv3d->viewinv, rv3d->viewcamtexcofac, (v3d->scenelock != 0)); bool material_not_bound = !GPU_material_bound(gpumat); @@ -3326,7 +3337,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf( if (own_ofs) { /* bind */ - ofs = GPU_offscreen_create(sizex, sizey, use_full_sample ? 0 : samples, err_out); + ofs = GPU_offscreen_create(sizex, sizey, use_full_sample ? 0 : samples, GPU_HDR_NONE, GPU_OFFSCREEN_DEPTH_COMPARE, err_out); if (ofs == NULL) { return NULL; } diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index a812950254f1..7dc087b30af4 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -65,7 +65,7 @@ # include "GPU_draw.h" -# include "BL_System.h" +# include "LA_SystemCommandLine.h" #endif #include "view3d_intern.h" /* own include */ @@ -1370,6 +1370,9 @@ static void game_set_commmandline_options(GameData *gm) SYS_WriteCommandLineInt(syshandle, "show_framerate", test); SYS_WriteCommandLineInt(syshandle, "show_profile", test); + test = (gm->flag & GAME_SHOW_RENDER_QUERIES); + SYS_WriteCommandLineInt(syshandle, "show_render_queries", test); + test = (gm->flag & GAME_SHOW_DEBUG_PROPS); SYS_WriteCommandLineInt(syshandle, "show_properties", test); @@ -1379,20 +1382,13 @@ static void game_set_commmandline_options(GameData *gm) test = (gm->flag & GAME_ENABLE_ALL_FRAMES); SYS_WriteCommandLineInt(syshandle, "fixedtime", test); - test = (gm->flag & GAME_ENABLE_ANIMATION_RECORD); - SYS_WriteCommandLineInt(syshandle, "animation_record", test); - test = (gm->flag & GAME_IGNORE_DEPRECATION_WARNINGS); SYS_WriteCommandLineInt(syshandle, "ignore_deprecation_warnings", test); - test = (gm->matmode == GAME_MAT_MULTITEX); - SYS_WriteCommandLineInt(syshandle, "blender_material", test); - test = (gm->matmode == GAME_MAT_GLSL); - SYS_WriteCommandLineInt(syshandle, "blender_glsl_material", test); - test = (gm->flag & GAME_DISPLAY_LISTS); - SYS_WriteCommandLineInt(syshandle, "displaylists", test); - - + SYS_WriteCommandLineInt(syshandle, "show_bounding_box", gm->showBoundingBox); + SYS_WriteCommandLineInt(syshandle, "show_armatures", gm->showArmatures); + SYS_WriteCommandLineInt(syshandle, "show_camera_frustum", gm->showCameraFrustum); + SYS_WriteCommandLineInt(syshandle, "show_shadow_frustum", gm->showShadowFrustum); } } @@ -1450,8 +1446,7 @@ static int game_engine_exec(bContext *C, wmOperator *op) game_set_commmandline_options(&startscene->gm); if ((rv3d->persp == RV3D_CAMOB) && - (startscene->gm.framing.type == SCE_GAMEFRAMING_BARS) && - (startscene->gm.stereoflag != STEREO_DOME)) + (startscene->gm.framing.type == SCE_GAMEFRAMING_BARS)) { /* Letterbox */ rctf cam_framef; diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 0fde0e2a4a9e..9cbb21956df6 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -62,6 +62,9 @@ set(SRC intern/gpu_shader.c intern/gpu_texture.c + shaders/gpu_shader_2d_box_vert.glsl + shaders/gpu_shader_flat_color_frag.glsl + shaders/gpu_shader_flat_color_vert.glsl shaders/gpu_shader_fx_lib.glsl shaders/gpu_shader_fx_ssao_frag.glsl shaders/gpu_shader_fx_dof_frag.glsl @@ -74,6 +77,8 @@ set(SRC shaders/gpu_shader_sep_gaussian_blur_frag.glsl shaders/gpu_shader_sep_gaussian_blur_vert.glsl shaders/gpu_shader_basic_frag.glsl + shaders/gpu_shader_black_frag.glsl + shaders/gpu_shader_black_vert.glsl shaders/gpu_shader_basic_vert.glsl shaders/gpu_shader_basic_geom.glsl shaders/gpu_shader_vertex.glsl @@ -81,6 +86,9 @@ set(SRC shaders/gpu_shader_vsm_store_vert.glsl shaders/gpu_shader_fx_depth_resolve.glsl shaders/gpu_shader_fire_frag.glsl + shaders/gpu_shader_frustum_line_vert.glsl + shaders/gpu_shader_frustum_solid_frag.glsl + shaders/gpu_shader_frustum_solid_vert.glsl shaders/gpu_shader_smoke_frag.glsl shaders/gpu_shader_smoke_vert.glsl @@ -102,7 +110,13 @@ set(SRC intern/gpu_select_private.h ) +data_to_c_simple(shaders/gpu_shader_2d_box_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_geometry.glsl SRC) +data_to_c_simple(shaders/gpu_shader_flat_color_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_flat_color_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_frustum_line_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_frustum_solid_vert.glsl SRC) +data_to_c_simple(shaders/gpu_shader_frustum_solid_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_fire_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_smoke_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_smoke_vert.glsl SRC) @@ -110,8 +124,12 @@ data_to_c_simple(shaders/gpu_shader_material.glsl SRC) data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_sep_gaussian_blur_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_basic_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_black_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_black_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_basic_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_basic_geom.glsl SRC) +data_to_c_simple(shaders/gpu_shader_frame_buffer_frag.glsl SRC) +data_to_c_simple(shaders/gpu_shader_frame_buffer_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_vertex.glsl SRC) data_to_c_simple(shaders/gpu_shader_vertex_world.glsl SRC) data_to_c_simple(shaders/gpu_shader_vsm_store_frag.glsl SRC) @@ -125,6 +143,7 @@ data_to_c_simple(shaders/gpu_shader_fx_dof_hq_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_fx_dof_hq_geo.glsl SRC) data_to_c_simple(shaders/gpu_shader_fx_depth_resolve.glsl SRC) data_to_c_simple(shaders/gpu_shader_fx_lib.glsl SRC) +data_to_c_simple(shaders/gpu_shader_lib.glsl SRC) if(WITH_GAMEENGINE) add_definitions(-DWITH_GAMEENGINE) diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index de53b1e8739b..7b04587bcd37 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -101,15 +101,6 @@ int GPU_scene_object_lights( struct Scene *scene, struct Object *ob, int lay, float viewmat[4][4], int ortho); -/* Text render - * - based on moving uv coordinates */ - -void GPU_render_text( - struct MTexPoly *mtexpoly, int mode, - const char *textstr, int textlen, unsigned int *col, - const float *v_quad[4], const float *uv_quad[4], - int glattrib); - /* Mipmap settings * - these will free textures on changes */ diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h index 2719b8fa6a87..88319d2ab24f 100644 --- a/source/blender/gpu/GPU_framebuffer.h +++ b/source/blender/gpu/GPU_framebuffer.h @@ -36,9 +36,11 @@ extern "C" { #endif +#include "GPU_texture.h" + typedef struct GPUFrameBuffer GPUFrameBuffer; +typedef struct GPURenderBuffer GPURenderBuffer; typedef struct GPUOffScreen GPUOffScreen; -struct GPUTexture; /* GPU Framebuffer * - this is a wrapper for an OpenGL framebuffer object (FBO). in practice @@ -51,33 +53,68 @@ void GPU_texture_bind_as_framebuffer(struct GPUTexture *tex); GPUFrameBuffer *GPU_framebuffer_create(void); int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, char err_out[256]); +int GPU_framebuffer_texture_attach_target(GPUFrameBuffer *fb, struct GPUTexture *tex, int target, int slot, char err_out[256]); void GPU_framebuffer_texture_detach(struct GPUTexture *tex); +void GPU_framebuffer_texture_detach_target(GPUTexture *tex, int target); void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot); void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, struct GPUTexture *tex); void GPU_framebuffer_free(GPUFrameBuffer *fb); bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]); +int GPU_framebuffer_renderbuffer_attach(GPUFrameBuffer *fb, GPURenderBuffer *rb, int slot, char err_out[256]); +void GPU_framebuffer_renderbuffer_detach(GPURenderBuffer *rb); + void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot); +void GPU_framebuffer_bind_simple(GPUFrameBuffer *fb); +void GPU_framebuffer_bind_all_attachments(GPUFrameBuffer *fb); bool GPU_framebuffer_bound(GPUFrameBuffer *fb); void GPU_framebuffer_restore(void); void GPU_framebuffer_blur( GPUFrameBuffer *fb, struct GPUTexture *tex, - GPUFrameBuffer *blurfb, struct GPUTexture *blurtex); + GPUFrameBuffer *blurfb, struct GPUTexture *blurtex, float sharpness); + +typedef enum GPURenderBufferType { + GPU_RENDERBUFFER_COLOR = 0, + GPU_RENDERBUFFER_DEPTH = 1, +} GPURenderBufferType; + +GPURenderBuffer *GPU_renderbuffer_create(int width, int height, int samples, GPUHDRType hdrtype, GPURenderBufferType type, char err_out[256]); +void GPU_renderbuffer_free(GPURenderBuffer *rb); +GPUFrameBuffer *GPU_renderbuffer_framebuffer(GPURenderBuffer *rb); +int GPU_renderbuffer_framebuffer_attachment(GPURenderBuffer *rb); +void GPU_renderbuffer_framebuffer_set(GPURenderBuffer *rb, GPUFrameBuffer *fb, int attachement); +int GPU_renderbuffer_bindcode(const GPURenderBuffer *rb); +bool GPU_renderbuffer_depth(const GPURenderBuffer *rb); +int GPU_renderbuffer_width(const GPURenderBuffer *rb); +int GPU_renderbuffer_height(const GPURenderBuffer *rb); + /* GPU OffScreen * - wrapper around framebuffer and texture for simple offscreen drawing * - changes size if graphics card can't support it */ -GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256]); +typedef enum GPUOffScreenMode { + GPU_OFFSCREEN_MODE_NONE = 0, + GPU_OFFSCREEN_RENDERBUFFER_COLOR = 1 << 0, + GPU_OFFSCREEN_RENDERBUFFER_DEPTH = 1 << 1, + GPU_OFFSCREEN_DEPTH_COMPARE = 1 << 2, +} GPUOffScreenMode; + +GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, GPUHDRType hdrtype, int mode, char err_out[256]); void GPU_offscreen_free(GPUOffScreen *ofs); void GPU_offscreen_bind(GPUOffScreen *ofs, bool save); +void GPU_offscreen_bind_simple(GPUOffScreen *ofs); void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore); void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels); +void GPU_offscreen_blit(GPUOffScreen *srcofs, GPUOffScreen *dstofs, bool color, bool depth); int GPU_offscreen_width(const GPUOffScreen *ofs); int GPU_offscreen_height(const GPUOffScreen *ofs); +int GPU_offscreen_samples(const GPUOffScreen *ofs); int GPU_offscreen_color_texture(const GPUOffScreen *ofs); +GPUTexture *GPU_offscreen_texture(const GPUOffScreen *ofs); +GPUTexture *GPU_offscreen_depth_texture(const GPUOffScreen *ofs); #ifdef __cplusplus } diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index c94d6429f596..6e54f8cc6478 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -68,6 +68,7 @@ typedef struct GPUParticleInfo GPUParticleInfo; /* Functions to create GPU Materials nodes */ typedef enum GPUType { + /* Types taken into account by GPU_DATATYPE_STR and GPU_DATATYPE_SIZE arrays */ /* The value indicates the number of elements in each type */ GPU_NONE = 0, GPU_FLOAT = 1, @@ -77,6 +78,9 @@ typedef enum GPUType { GPU_MAT3 = 9, GPU_MAT4 = 16, + GPU_INT = 17, /* this value doesn't point the number of elements */ + /* end of types taken into account by GPU_DATATYPE_STR and GPU_DATATYPE_SIZE arrays */ + GPU_TEX2D = 1002, GPU_SHADOW2D = 1003, GPU_TEXCUBE = 1004, @@ -84,22 +88,34 @@ typedef enum GPUType { } GPUType; typedef enum GPUBuiltin { - GPU_VIEW_MATRIX = (1 << 0), - GPU_OBJECT_MATRIX = (1 << 1), - GPU_INVERSE_VIEW_MATRIX = (1 << 2), - GPU_INVERSE_OBJECT_MATRIX = (1 << 3), - GPU_VIEW_POSITION = (1 << 4), - GPU_VIEW_NORMAL = (1 << 5), - GPU_OBCOLOR = (1 << 6), - GPU_AUTO_BUMPSCALE = (1 << 7), - GPU_CAMERA_TEXCO_FACTORS = (1 << 8), - GPU_PARTICLE_SCALAR_PROPS = (1 << 9), - GPU_PARTICLE_LOCATION = (1 << 10), - GPU_PARTICLE_VELOCITY = (1 << 11), - GPU_PARTICLE_ANG_VELOCITY = (1 << 12), - GPU_LOC_TO_VIEW_MATRIX = (1 << 13), + GPU_VIEW_MATRIX = (1 << 0), + GPU_OBJECT_MATRIX = (1 << 1), + GPU_INVERSE_VIEW_MATRIX = (1 << 2), + GPU_INVERSE_OBJECT_MATRIX = (1 << 3), + GPU_VIEW_POSITION = (1 << 4), + GPU_VIEW_NORMAL = (1 << 5), + GPU_OBCOLOR = (1 << 6), + GPU_AUTO_BUMPSCALE = (1 << 7), + GPU_CAMERA_TEXCO_FACTORS = (1 << 8), + GPU_PARTICLE_SCALAR_PROPS = (1 << 9), + GPU_PARTICLE_LOCATION = (1 << 10), + GPU_PARTICLE_VELOCITY = (1 << 11), + GPU_PARTICLE_ANG_VELOCITY = (1 << 12), + GPU_LOC_TO_VIEW_MATRIX = (1 << 13), GPU_INVERSE_LOC_TO_VIEW_MATRIX = (1 << 14), - GPU_OBJECT_INFO = (1 << 15) + GPU_INSTANCING_MATRIX = (1 << 15), + GPU_INSTANCING_INVERSE_MATRIX = (1 << 16), + GPU_INSTANCING_COLOR = (1 << 17), + GPU_INSTANCING_LAYER = (1 << 18), + GPU_INSTANCING_INFO = (1 << 19), + GPU_INSTANCING_COLOR_ATTRIB = (1 << 20), + GPU_INSTANCING_MATRIX_ATTRIB = (1 << 21), + GPU_INSTANCING_POSITION_ATTRIB = (1 << 22), + GPU_INSTANCING_LAYER_ATTRIB = (1 << 23), + GPU_INSTANCING_INFO_ATTRIB = (1 << 24), + GPU_TIME = (1 << 25), + GPU_OBJECT_INFO = (1 << 26), + GPU_OBJECT_LAY = (1 << 27) } GPUBuiltin; typedef enum GPUOpenGLBuiltin { @@ -122,6 +138,12 @@ typedef enum GPUBlendMode { GPU_BLEND_ALPHA_TO_COVERAGE = 16 } GPUBlendMode; +typedef enum GPUMaterialFlag { + GPU_MATERIAL_OPENSUBDIV = (1 << 0), + GPU_MATERIAL_INSTANCING = (1 << 1), + GPU_MATERIAL_NO_COLOR_MANAGEMENT = (1 << 2) +} GPUMaterialFlag; + typedef struct GPUNodeStack { GPUType type; const char *name; @@ -142,6 +164,9 @@ typedef struct GPUNodeStack { #define GPU_DYNAMIC_GROUP_MIST 0x00050000 #define GPU_DYNAMIC_GROUP_WORLD 0x00060000 #define GPU_DYNAMIC_GROUP_MAT 0x00070000 +#define GPU_DYNAMIC_GROUP_TEX 0x00080000 +#define GPU_DYNAMIC_GROUP_TEX_UV 0x00090000 +#define GPU_DYNAMIC_GROUP_TIME 0x00100000 typedef enum GPUDynamicType { @@ -162,15 +187,18 @@ typedef enum GPUDynamicType { GPU_DYNAMIC_LAMP_DYNPERSMAT = 4 | GPU_DYNAMIC_GROUP_LAMP, GPU_DYNAMIC_LAMP_DYNENERGY = 5 | GPU_DYNAMIC_GROUP_LAMP, GPU_DYNAMIC_LAMP_DYNCOL = 6 | GPU_DYNAMIC_GROUP_LAMP, - GPU_DYNAMIC_LAMP_DISTANCE = 7 | GPU_DYNAMIC_GROUP_LAMP, - GPU_DYNAMIC_LAMP_ATT1 = 8 | GPU_DYNAMIC_GROUP_LAMP, - GPU_DYNAMIC_LAMP_ATT2 = 9 | GPU_DYNAMIC_GROUP_LAMP, - GPU_DYNAMIC_LAMP_SPOTSIZE = 10 | GPU_DYNAMIC_GROUP_LAMP, - GPU_DYNAMIC_LAMP_SPOTBLEND = 11 | GPU_DYNAMIC_GROUP_LAMP, - GPU_DYNAMIC_LAMP_SPOTSCALE = 12 | GPU_DYNAMIC_GROUP_LAMP, - GPU_DYNAMIC_LAMP_COEFFCONST = 13 | GPU_DYNAMIC_GROUP_LAMP, - GPU_DYNAMIC_LAMP_COEFFLIN = 14 | GPU_DYNAMIC_GROUP_LAMP, - GPU_DYNAMIC_LAMP_COEFFQUAD = 15 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_DYNSPOTSCALE = 7 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_DYNVISI = 8 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_DISTANCE = 9 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_ATT1 = 10 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_ATT2 = 11 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_SPOTSIZE = 12 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_SPOTBLEND = 13 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_COEFFCONST = 14 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_COEFFLIN = 15 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_COEFFQUAD = 16 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_CUTOFF = 17 | GPU_DYNAMIC_GROUP_LAMP, + GPU_DYNAMIC_LAMP_RADIUS = 18 | GPU_DYNAMIC_GROUP_LAMP, GPU_DYNAMIC_SAMPLER_2DBUFFER = 1 | GPU_DYNAMIC_GROUP_SAMPLER, GPU_DYNAMIC_SAMPLER_2DIMAGE = 2 | GPU_DYNAMIC_GROUP_SAMPLER, @@ -186,6 +214,9 @@ typedef enum GPUDynamicType { GPU_DYNAMIC_HORIZON_COLOR = 1 | GPU_DYNAMIC_GROUP_WORLD, GPU_DYNAMIC_AMBIENT_COLOR = 2 | GPU_DYNAMIC_GROUP_WORLD, GPU_DYNAMIC_ZENITH_COLOR = 3 | GPU_DYNAMIC_GROUP_WORLD, + GPU_DYNAMIC_WORLD_LINFAC = 4 | GPU_DYNAMIC_GROUP_WORLD, + GPU_DYNAMIC_WORLD_LOGFAC = 5 | GPU_DYNAMIC_GROUP_WORLD, + GPU_DYNAMIC_ENVLIGHT_ENERGY = 6 | GPU_DYNAMIC_GROUP_WORLD, GPU_DYNAMIC_MAT_DIFFRGB = 1 | GPU_DYNAMIC_GROUP_MAT, GPU_DYNAMIC_MAT_REF = 2 | GPU_DYNAMIC_GROUP_MAT, @@ -195,17 +226,41 @@ typedef enum GPUDynamicType { GPU_DYNAMIC_MAT_EMIT = 6 | GPU_DYNAMIC_GROUP_MAT, GPU_DYNAMIC_MAT_AMB = 7 | GPU_DYNAMIC_GROUP_MAT, GPU_DYNAMIC_MAT_ALPHA = 8 | GPU_DYNAMIC_GROUP_MAT, - GPU_DYNAMIC_MAT_MIR = 9 | GPU_DYNAMIC_GROUP_MAT + GPU_DYNAMIC_MAT_MIR = 9 | GPU_DYNAMIC_GROUP_MAT, + GPU_DYNAMIC_MAT_SPECTRA = 10 | GPU_DYNAMIC_GROUP_MAT, + + GPU_DYNAMIC_TEX_COLINTENS = 1 | GPU_DYNAMIC_GROUP_TEX, + GPU_DYNAMIC_TEX_COLFAC = 2 | GPU_DYNAMIC_GROUP_TEX, + GPU_DYNAMIC_TEX_ALPHA = 3 | GPU_DYNAMIC_GROUP_TEX, + GPU_DYNAMIC_TEX_SPECINTENS = 4 | GPU_DYNAMIC_GROUP_TEX, + GPU_DYNAMIC_TEX_SPECFAC = 5 | GPU_DYNAMIC_GROUP_TEX, + GPU_DYNAMIC_TEX_HARDNESS = 6 | GPU_DYNAMIC_GROUP_TEX, + GPU_DYNAMIC_TEX_EMIT = 7 | GPU_DYNAMIC_GROUP_TEX, + GPU_DYNAMIC_TEX_MIRROR = 8 | GPU_DYNAMIC_GROUP_TEX, + GPU_DYNAMIC_TEX_NORMAL = 9 | GPU_DYNAMIC_GROUP_TEX, + GPU_DYNAMIC_TEX_PARALLAXBUMP = 10 | GPU_DYNAMIC_GROUP_TEX, + GPU_DYNAMIC_TEX_PARALLAXSTEP = 11 | GPU_DYNAMIC_GROUP_TEX, + GPU_DYNAMIC_TEX_LODBIAS = 12 | GPU_DYNAMIC_GROUP_TEX, + GPU_DYNAMIC_TEX_IOR = 13 | GPU_DYNAMIC_GROUP_TEX, + GPU_DYNAMIC_TEX_REFRRATIO = 14 | GPU_DYNAMIC_GROUP_TEX, + + GPU_DYNAMIC_TEX_UVOFFSET = 1 | GPU_DYNAMIC_GROUP_TEX_UV, + GPU_DYNAMIC_TEX_UVSIZE = 2 | GPU_DYNAMIC_GROUP_TEX_UV, + GPU_DYNAMIC_TEX_UVROTATION = 3 | GPU_DYNAMIC_GROUP_TEX_UV, + + GPU_DYNAMIC_TIME = 1 | GPU_DYNAMIC_GROUP_TIME } GPUDynamicType; GPUNodeLink *GPU_attribute(CustomDataType type, const char *name); GPUNodeLink *GPU_uniform(float *num); -GPUNodeLink *GPU_dynamic_uniform(float *num, GPUDynamicType dynamictype, void *data); +GPUNodeLink *GPU_dynamic_uniform(void *num, GPUDynamicType dynamictype, void *data); +GPUNodeLink *GPU_select_uniform(float *num, GPUDynamicType dynamictype, void *data, struct Material *material); GPUNodeLink *GPU_image(struct Image *ima, struct ImageUser *iuser, bool is_data); GPUNodeLink *GPU_cube_map(struct Image *ima, struct ImageUser *iuser, bool is_data); GPUNodeLink *GPU_image_preview(struct PreviewImage *prv); GPUNodeLink *GPU_texture(int size, float *pixels); GPUNodeLink *GPU_dynamic_texture(struct GPUTexture *tex, GPUDynamicType dynamictype, void *data); +GPUNodeLink *GPU_dynamic_texture_ptr(struct GPUTexture **tex, GPUDynamicType dynamictype, void *data); GPUNodeLink *GPU_builtin(GPUBuiltin builtin); GPUNodeLink *GPU_opengl_builtin(GPUOpenGLBuiltin builtin); void GPU_node_link_set_type(GPUNodeLink *link, GPUType type); @@ -216,24 +271,28 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link); void GPU_material_enable_alpha(GPUMaterial *material); GPUBuiltin GPU_get_material_builtins(GPUMaterial *material); -GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4]); +GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, const float obcol[4]); + +/// Possibly translate builtin to instancing builtin if instancing enabled and return node. +GPUNodeLink *GPU_material_builtin(GPUMaterial *mat, GPUBuiltin builtin); /* High level functions to create and use GPU materials */ -GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo); +GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo, GPUMaterialFlag flags); -GPUMaterial *GPU_material_from_blender(struct Scene *scene, struct Material *ma, bool use_opensubdiv); -GPUMaterial *GPU_material_matcap(struct Scene *scene, struct Material *ma, bool use_opensubdiv); +GPUMaterial *GPU_material_from_blender(struct Scene *scene, struct Material *ma, GPUMaterialFlag flags); +GPUMaterial *GPU_material_matcap(struct Scene *scene, struct Material *ma, GPUMaterialFlag flags); void GPU_material_free(struct ListBase *gpumaterial); void GPU_materials_free(struct Main *bmain); bool GPU_lamp_visible(GPULamp *lamp, struct SceneRenderLayer *srl, struct Material *ma); +void GPU_material_update_lamps(GPUMaterial *material, float viewmat[4][4], float viewinv[4][4]); void GPU_material_bind( - GPUMaterial *material, int oblay, int viewlay, double time, int mipmap, + GPUMaterial *material, int viewlay, double time, int mipmap, float viewmat[4][4], float viewinv[4][4], float cameraborder[4], bool scenelock); void GPU_material_bind_uniforms( - GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4], - float autobumpscale, GPUParticleInfo *pi, float object_info[3]); + GPUMaterial *material, float obmat[4][4], float viewmat[4][4], const float obcol[4], + int oblay, float autobumpscale, GPUParticleInfo *pi, float object_info[3]); void GPU_material_unbind(GPUMaterial *material); bool GPU_material_bound(GPUMaterial *material); struct Scene *GPU_material_scene(GPUMaterial *material); @@ -323,7 +382,10 @@ void GPU_lamp_shadow_buffer_bind(GPULamp *lamp, float viewmat[4][4], int *winsiz void GPU_lamp_shadow_buffer_unbind(GPULamp *lamp); int GPU_lamp_shadow_buffer_type(GPULamp *lamp); int GPU_lamp_shadow_bind_code(GPULamp *lamp); -float *GPU_lamp_dynpersmat(GPULamp *lamp); +const float *GPU_lamp_dynpersmat(GPULamp *lamp); +const float *GPU_lamp_get_viewmat(GPULamp *lamp); +const float *GPU_lamp_get_winmat(GPULamp *lamp); + void GPU_lamp_update(GPULamp *lamp, int lay, int hide, float obmat[4][4]); void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float energy); @@ -337,10 +399,12 @@ GPUNodeLink *GPU_lamp_get_data( /* World */ void GPU_mist_update_enable(short enable); -void GPU_mist_update_values(int type, float start, float dist, float inten, float color[3]); -void GPU_horizon_update_color(float color[3]); -void GPU_ambient_update_color(float color[3]); -void GPU_zenith_update_color(float color[3]); +void GPU_mist_update_values(int type, float start, float dist, float inten, const float color[3]); +void GPU_horizon_update_color(const float color[3]); +void GPU_ambient_update_color(const float color[3]); +void GPU_zenith_update_color(const float color[3]); +void GPU_update_exposure_range(float exp, float range); +void GPU_update_envlight_energy(float energy); struct GPUParticleInfo { @@ -356,6 +420,10 @@ void GPU_material_update_fvar_offset(GPUMaterial *gpu_material, struct DerivedMesh *dm); #endif +/* Instancing material */ +bool GPU_material_use_instancing(GPUMaterial *material); +void GPU_material_bind_instancing_attrib(GPUMaterial *material, void *matrixoffset, void *positionoffset, void *coloroffset, void *layeroffset, void *infooffset); + #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 5b94db6e1207..f0d1865ff5a3 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -47,6 +47,7 @@ enum { GPU_SHADER_FLAGS_NONE = 0, GPU_SHADER_FLAGS_SPECIAL_OPENSUBDIV = (1 << 0), GPU_SHADER_FLAGS_NEW_SHADING = (1 << 1), + GPU_SHADER_FLAGS_SPECIAL_INSTANCING = (1 << 2), }; GPUShader *GPU_shader_create( @@ -64,11 +65,23 @@ GPUShader *GPU_shader_create_ex( const char *defines, int input, int output, int number, const int flags); +char *GPU_shader_validate(GPUShader *shader); void GPU_shader_free(GPUShader *shader); void GPU_shader_bind(GPUShader *shader); void GPU_shader_unbind(void); +int GPU_shader_program(GPUShader *shader); + +typedef struct GPUUniformInfo +{ + unsigned int size; + unsigned int type; + char name[255]; +} GPUUniformInfo; + +int GPU_shader_get_uniform_infos(GPUShader *shader, GPUUniformInfo **infos); + void *GPU_shader_get_interface(GPUShader *shader); void GPU_shader_set_interface(GPUShader *shader, void *interface); int GPU_shader_get_uniform(GPUShader *shader, const char *name); @@ -79,17 +92,34 @@ void GPU_shader_uniform_vector_int(GPUShader *shader, int location, int length, void GPU_shader_uniform_texture(GPUShader *shader, int location, struct GPUTexture *tex); void GPU_shader_uniform_int(GPUShader *shader, int location, int value); +void GPU_shader_uniform_float(GPUShader *shader, int location, float value); void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number); int GPU_shader_get_attribute(GPUShader *shader, const char *name); +void GPU_shader_bind_attribute(GPUShader *shader, int location, const char *name); + +void GPU_shader_bind_instancing_attrib(GPUShader *shader, void *matrixoffset, void *positionoffset); /* Builtin/Non-generated shaders */ typedef enum GPUBuiltinShader { - GPU_SHADER_VSM_STORE = 0, - GPU_SHADER_SEP_GAUSSIAN_BLUR = 1, - GPU_SHADER_SMOKE = 2, - GPU_SHADER_SMOKE_FIRE = 3, - GPU_SHADER_SMOKE_COBA = 4, + GPU_SHADER_VSM_STORE = 0, + GPU_SHADER_VSM_STORE_INSTANCING = 1, + GPU_SHADER_SEP_GAUSSIAN_BLUR = 2, + GPU_SHADER_SMOKE = 3, + GPU_SHADER_SMOKE_FIRE = 4, + GPU_SHADER_SMOKE_COBA = 5, + GPU_SHADER_BLACK = 6, + GPU_SHADER_BLACK_INSTANCING = 7, + GPU_SHADER_DRAW_FRAME_BUFFER = 8, + GPU_SHADER_DRAW_FRAME_BUFFER_SRGB = 9, + GPU_SHADER_STEREO_STIPPLE = 10, + GPU_SHADER_STEREO_STIPPLE_SRGB = 11, + GPU_SHADER_STEREO_ANAGLYPH = 12, + GPU_SHADER_STEREO_ANAGLYPH_SRGB = 13, + GPU_SHADER_FRUSTUM_LINE = 14, + GPU_SHADER_FRUSTUM_SOLID = 15, + GPU_SHADER_FLAT_COLOR = 16, + GPU_SHADER_2D_BOX = 17, } GPUBuiltinShader; GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader); diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 1ae3d73991e5..ee484e8fd979 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -61,19 +61,29 @@ typedef enum GPUHDRType { GPU_HDR_FULL_FLOAT = (1 << 1), } GPUHDRType; +typedef enum GPUTextureMode { + GPU_TEXTURE_MODE_NONE = 0, + GPU_TEXTURE_DEPTH = 1 << 0, + GPU_TEXTURE_DEPTH_COMPARE = 1 << 1, +} GPUTextureMode; + GPUTexture *GPU_texture_create_1D(int w, const float *pixels, char err_out[256]); GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, GPUHDRType hdr, char err_out[256]); GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels); -GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]); +GPUTexture *GPU_texture_create_depth(int w, int h, bool compare, char err_out[256]); GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]); -GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]); +GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, bool filter, char err_out[256]); GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]); GPUTexture *GPU_texture_create_2D_multisample( int w, int h, const float *pixels, GPUHDRType hdr, int samples, char err_out[256]); -GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]); +GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, bool compare, char err_out[256]); GPUTexture *GPU_texture_from_blender( struct Image *ima, struct ImageUser *iuser, int textarget, bool is_data, double time, int mipmap); GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap); +GPUTexture *GPU_texture_create_jitter(int w); +GPUTexture *GPU_texture_global_jitter_64(void); +GPUTexture **GPU_texture_global_depth_ptr(void); +void GPU_texture_set_global_depth(GPUTexture *depthtex); void GPU_invalid_tex_init(void); void GPU_invalid_tex_bind(int mode); void GPU_invalid_tex_free(void); @@ -81,12 +91,14 @@ void GPU_invalid_tex_free(void); void GPU_texture_free(GPUTexture *tex); void GPU_texture_ref(GPUTexture *tex); +int GPU_texture_ref_count(GPUTexture *tex); void GPU_texture_bind(GPUTexture *tex, int number); void GPU_texture_unbind(GPUTexture *tex); int GPU_texture_bound_number(GPUTexture *tex); -void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter); +void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter, bool mipmap); +void GPU_texture_generate_mipmap(GPUTexture *tex); struct GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex); int GPU_texture_framebuffer_attachment(GPUTexture *tex); @@ -98,6 +110,9 @@ int GPU_texture_height(const GPUTexture *tex); int GPU_texture_depth(const GPUTexture *tex); int GPU_texture_opengl_bindcode(const GPUTexture *tex); +void GPU_texture_set_opengl_bindcode(GPUTexture *tex, int bindcode); + + #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index cc005e5b6e17..2a82ae12fafe 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -55,6 +55,7 @@ #include #include + extern char datatoc_gpu_shader_material_glsl[]; extern char datatoc_gpu_shader_vertex_glsl[]; extern char datatoc_gpu_shader_vertex_world_glsl[]; @@ -86,9 +87,13 @@ typedef struct GPUFunction { } GPUFunction; /* Indices match the GPUType enum */ -static const char *GPU_DATATYPE_STR[17] = { +static const char *GPU_DATATYPE_STR[18] = { "", "float", "vec2", "vec3", "vec4", - NULL, NULL, NULL, NULL, "mat3", NULL, NULL, NULL, NULL, NULL, NULL, "mat4", + NULL, NULL, NULL, NULL, "mat3", NULL, NULL, NULL, NULL, NULL, NULL, "mat4", "int" +}; +/* Indices match the GPUType size */ +static const unsigned int GPU_DATATYPE_SIZE[18] = { + 0, 1, 2, 3, 4, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 16, 1 }; /* GLSL code parsing for finding function definitions. @@ -172,7 +177,7 @@ static void gpu_parse_functions_string(GHash *hash, char *code) /* test for type */ type = GPU_NONE; - for (i = 1; i <= 16; i++) { + for (i = 1; i < ARRAY_SIZE(GPU_DATATYPE_STR); i++) { if (GPU_DATATYPE_STR[i] && gpu_str_prefix(code, GPU_DATATYPE_STR[i])) { type = i; break; @@ -359,7 +364,7 @@ static void codegen_print_datatype(DynStr *ds, const GPUType type, float *data) BLI_dynstr_appendf(ds, "%s(", GPU_DATATYPE_STR[type]); - for (i = 0; i < type; i++) { + for (i = 0; i < GPU_DATATYPE_SIZE[type]; i++) { BLI_dynstr_appendf(ds, "%.12f", data[i]); if (i == type - 1) BLI_dynstr_append(ds, ")"); @@ -375,7 +380,7 @@ static int codegen_input_has_texture(GPUInput *input) else if (input->ima || input->prv) return 1; else - return input->tex != NULL; + return (input->tex != NULL || input->texptr != NULL); } const char *GPU_builtin_name(GPUBuiltin builtin) @@ -410,8 +415,32 @@ const char *GPU_builtin_name(GPUBuiltin builtin) return "unfparticlevel"; else if (builtin == GPU_PARTICLE_ANG_VELOCITY) return "unfparticleangvel"; + else if (builtin == GPU_INSTANCING_MATRIX) + return "varinstmat"; + else if (builtin == GPU_INSTANCING_INVERSE_MATRIX) + return "varinstinvmat"; + else if (builtin == GPU_INSTANCING_COLOR) + return "varinstcolor"; + else if (builtin == GPU_INSTANCING_LAYER) + return "varinstlayer"; + else if (builtin == GPU_INSTANCING_INFO) + return "varinstinfo"; + else if (builtin == GPU_INSTANCING_COLOR_ATTRIB) + return "ininstcolor"; + else if (builtin == GPU_INSTANCING_MATRIX_ATTRIB) + return "ininstmatrix"; + else if (builtin == GPU_INSTANCING_POSITION_ATTRIB) + return "ininstposition"; + else if (builtin == GPU_INSTANCING_LAYER_ATTRIB) + return "ininstlayer"; + else if (builtin == GPU_INSTANCING_INFO_ATTRIB) + return "ininstinfo"; + else if (builtin == GPU_TIME) + return "unftime"; else if (builtin == GPU_OBJECT_INFO) return "unfobjectinfo"; + else if (builtin == GPU_OBJECT_LAY) + return "unfobjectlay"; else return ""; } @@ -472,6 +501,10 @@ static void codegen_set_unique_ids(ListBase *nodes) /* input is user created texture, check tex pointer */ codegen_set_texid(bindhash, input, &texid, input->tex); } + else if (input->texptr) { + /* input is user created texture, check tex pointer */ + codegen_set_texid(bindhash, input, &texid, input->texptr); + } /* make sure this pixel is defined exactly once */ if (input->source == GPU_SOURCE_TEX_PIXEL) { @@ -530,9 +563,17 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes) GPU_DATATYPE_STR[input->type], name); } else { - BLI_dynstr_appendf(ds, "%s %s %s;\n", - GLEW_VERSION_3_0 ? "in" : "varying", - GPU_DATATYPE_STR[input->type], name); + // GPU_INSTANCING_LAYER is an integer, it must be flat in GLSL. + if (input->builtin == GPU_INSTANCING_LAYER) { + BLI_dynstr_appendf(ds, "%s %s %s;\n", + GLEW_VERSION_3_0 ? "flat in" : "flat varying", + GPU_DATATYPE_STR[input->type], name); + } + else { + BLI_dynstr_appendf(ds, "%s %s %s;\n", + GLEW_VERSION_3_0 ? "in" : "varying", + GPU_DATATYPE_STR[input->type], name); + } } } } @@ -733,7 +774,7 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output) return code; } -static char *code_generate_vertex(ListBase *nodes, const GPUMatType type) +static char *code_generate_vertex(ListBase *nodes, const GPUMatType type, bool use_instancing) { DynStr *ds = BLI_dynstr_new(); GPUNode *node; @@ -789,9 +830,16 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type) #ifdef WITH_OPENSUBDIV BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n"); #endif - BLI_dynstr_appendf( - ds, "\tvar%d.xyz = normalize(gl_NormalMatrix * att%d.xyz);\n", - input->attribid, input->attribid); + if (use_instancing) { + BLI_dynstr_appendf( + ds, "\tvar%d.xyz = normalize(gl_NormalMatrix * (att%d.xyz * %s));\n", + input->attribid, input->attribid, GPU_builtin_name(GPU_INSTANCING_MATRIX_ATTRIB)); + } + else { + BLI_dynstr_appendf( + ds, "\tvar%d.xyz = normalize(gl_NormalMatrix * att%d.xyz);\n", + input->attribid, input->attribid); + } BLI_dynstr_appendf( ds, "\tvar%d.w = att%d.w;\n", input->attribid, input->attribid); @@ -977,15 +1025,16 @@ static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes) continue; } - if (input->ima || input->tex || input->prv) + if (input->ima || input->tex || input->prv || input->texptr) { BLI_snprintf(input->shadername, sizeof(input->shadername), "samp%d", input->texid); + } else BLI_snprintf(input->shadername, sizeof(input->shadername), "unf%d", input->id); /* pass non-dynamic uniforms to opengl */ extract = 0; - if (input->ima || input->tex || input->prv) { + if (input->ima || input->tex || input->prv || input->texptr) { if (input->bindtex) extract = 1; } @@ -1040,6 +1089,10 @@ void GPU_pass_bind(GPUPass *pass, double time, int mipmap) GPU_texture_bind(input->tex, input->texid); GPU_shader_uniform_texture(shader, input->shaderloc, input->tex); } + else if (input->texptr && *input->texptr && input->bindtex) { + GPU_texture_bind(*input->texptr, input->texid); + GPU_shader_uniform_texture(shader, input->shaderloc, *input->texptr); + } } } @@ -1054,11 +1107,9 @@ void GPU_pass_update_uniforms(GPUPass *pass) /* pass dynamic inputs to opengl, others were removed */ for (input = inputs->first; input; input = input->next) { - if (!(input->ima || input->tex || input->prv)) { - if (input->dynamictype == GPU_DYNAMIC_MAT_HARD) { - // The hardness is actually a short pointer, so we convert it here - float val = (float)(*(short *)input->dynamicvec); - GPU_shader_uniform_vector(shader, input->shaderloc, 1, 1, &val); + if (!(input->ima || input->tex || input->prv || input->texptr)) { + if (input->type == GPU_INT) { + GPU_shader_uniform_vector_int(shader, input->shaderloc, 1, 1, (int *)input->dynamicvec); } else { GPU_shader_uniform_vector(shader, input->shaderloc, input->type, 1, @@ -1080,6 +1131,9 @@ void GPU_pass_unbind(GPUPass *pass) for (input = inputs->first; input; input = input->next) { if (input->tex && input->bindtex) GPU_texture_unbind(input->tex); + if (input->texptr && *input->texptr && input->bindtex) { + GPU_texture_unbind(*input->texptr); + } if (input->ima || input->prv) input->tex = NULL; @@ -1185,6 +1239,18 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType input->dynamicdata = link->ptr2; MEM_freeN(link); } + else if (link->dynamictexptr) { + /* dynamic texture, GPUTexture is updated/deleted externally */ + input->type = type; + input->source = GPU_SOURCE_TEX; + + input->texptr = link->dynamictexptr; + input->textarget = GL_TEXTURE_2D; + input->textype = type; + input->dynamictex = true; + input->dynamicdata = link->ptr2; + MEM_freeN(link); + } else if (link->texture) { /* small texture created on the fly, like for colorbands */ input->type = GPU_VEC4; @@ -1240,7 +1306,7 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType input->type = type; input->source = GPU_SOURCE_VEC_UNIFORM; - memcpy(input->vec, link->ptr1, type * sizeof(float)); + memcpy(input->vec, link->ptr1, GPU_DATATYPE_SIZE[type] * sizeof(float)); if (link->dynamic) { input->dynamicvec = link->ptr1; input->dynamictype = link->dynamictype; @@ -1403,7 +1469,7 @@ GPUNodeLink *GPU_uniform(float *num) return link; } -GPUNodeLink *GPU_dynamic_uniform(float *num, GPUDynamicType dynamictype, void *data) +GPUNodeLink *GPU_dynamic_uniform(void *num, GPUDynamicType dynamictype, void *data) { GPUNodeLink *link = GPU_node_link_create(); @@ -1416,6 +1482,36 @@ GPUNodeLink *GPU_dynamic_uniform(float *num, GPUDynamicType dynamictype, void *d return link; } +GPUNodeLink *GPU_select_uniform(float *num, GPUDynamicType dynamictype, void *data, Material *material) +{ + bool dynamic = false; + if (GPU_DYNAMIC_GROUP_FROM_TYPE(dynamictype) == GPU_DYNAMIC_GROUP_MAT) { + dynamic = !(material->constflag & MA_CONSTANT_MATERIAL); + } + else if (GPU_DYNAMIC_GROUP_FROM_TYPE(dynamictype) == GPU_DYNAMIC_GROUP_LAMP) { + dynamic = !(material->constflag & MA_CONSTANT_LAMP); + } + else if (GPU_DYNAMIC_GROUP_FROM_TYPE(dynamictype) == GPU_DYNAMIC_GROUP_TEX) { + dynamic = !(material->constflag & MA_CONSTANT_TEXTURE); + } + else if (GPU_DYNAMIC_GROUP_FROM_TYPE(dynamictype) == GPU_DYNAMIC_GROUP_TEX_UV) { + dynamic = !(material->constflag & MA_CONSTANT_TEXTURE_UV); + } + else if (GPU_DYNAMIC_GROUP_FROM_TYPE(dynamictype) == GPU_DYNAMIC_GROUP_WORLD) { + dynamic = !(material->constflag & MA_CONSTANT_WORLD); + } + else if (GPU_DYNAMIC_GROUP_FROM_TYPE(dynamictype) == GPU_DYNAMIC_GROUP_MIST) { + dynamic = !(material->constflag & MA_CONSTANT_MIST); + } + + if (dynamic) { + return GPU_dynamic_uniform(num, dynamictype, data); + } + else { + return GPU_uniform(num); + } +} + GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser, bool is_data) { GPUNodeLink *link = GPU_node_link_create(); @@ -1474,6 +1570,18 @@ GPUNodeLink *GPU_dynamic_texture(GPUTexture *tex, GPUDynamicType dynamictype, vo return link; } +GPUNodeLink *GPU_dynamic_texture_ptr(GPUTexture **tex, GPUDynamicType dynamictype, void *data) +{ + GPUNodeLink *link = GPU_node_link_create(); + + link->dynamic = true; + link->dynamictexptr = tex; + link->dynamictype = dynamictype; + link->ptr2 = data; + + return link; +} + GPUNodeLink *GPU_builtin(GPUBuiltin builtin) { GPUNodeLink *link = GPU_node_link_create(); @@ -1652,6 +1760,7 @@ GPUPass *GPU_generate_pass( GPUVertexAttribs *attribs, int *builtins, const GPUMatType type, const char *UNUSED(name), const bool use_opensubdiv, + const bool use_instancing, const bool use_new_shading) { GPUShader *shader; @@ -1673,7 +1782,7 @@ GPUPass *GPU_generate_pass( /* generate code and compile with opengl */ fragmentcode = code_generate_fragment(nodes, outlink->output); - vertexcode = code_generate_vertex(nodes, type); + vertexcode = code_generate_vertex(nodes, type, use_instancing); geometrycode = code_generate_geometry(nodes, use_opensubdiv); int flags = GPU_SHADER_FLAGS_NONE; @@ -1683,6 +1792,9 @@ GPUPass *GPU_generate_pass( if (use_new_shading) { flags |= GPU_SHADER_FLAGS_NEW_SHADING; } + if (use_instancing) { + flags |= GPU_SHADER_FLAGS_SPECIAL_INSTANCING; + } shader = GPU_shader_create_ex(vertexcode, fragmentcode, geometrycode, diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h index fbb6a845a96f..bd10e8c397aa 100644 --- a/source/blender/gpu/intern/gpu_codegen.h +++ b/source/blender/gpu/intern/gpu_codegen.h @@ -102,6 +102,7 @@ struct GPUNodeLink { int users; struct GPUTexture *dynamictex; + struct GPUTexture **dynamictexptr; GPUBuiltin builtin; GPUOpenGLBuiltin oglbuiltin; @@ -142,6 +143,7 @@ typedef struct GPUInput { GPUDynamicType dynamictype; /* origin of the dynamic uniform */ void *dynamicdata; /* data source of the dynamic uniform */ struct GPUTexture *tex; /* input texture, only set at runtime */ + struct GPUTexture **texptr; int shaderloc; /* id from opengl */ char shadername[32]; /* name in shader */ @@ -174,6 +176,7 @@ GPUPass *GPU_generate_pass(ListBase *nodes, struct GPUNodeLink *outlink, struct GPUVertexAttribs *attribs, int *builtin, const GPUMatType type, const char *name, const bool use_opensubdiv, + const bool use_instancing, const bool use_new_shading); struct GPUShader *GPU_pass_shader(GPUPass *pass); diff --git a/source/blender/gpu/intern/gpu_compositing.c b/source/blender/gpu/intern/gpu_compositing.c index 15865a730568..1b95396ddabe 100644 --- a/source/blender/gpu/intern/gpu_compositing.c +++ b/source/blender/gpu/intern/gpu_compositing.c @@ -356,21 +356,6 @@ void GPU_fx_compositor_destroy(GPUFX *fx) MEM_freeN(fx); } -static GPUTexture * create_jitter_texture(void) -{ - float jitter[64 * 64][2]; - int i; - - for (i = 0; i < 64 * 64; i++) { - jitter[i][0] = 2.0f * BLI_frand() - 1.0f; - jitter[i][1] = 2.0f * BLI_frand() - 1.0f; - normalize_v2(jitter[i]); - } - - return GPU_texture_create_2D_procedural(64, 64, &jitter[0][0], true, NULL); -} - - bool GPU_fx_compositor_initialize_passes( GPUFX *fx, const rcti *rect, const rcti *scissor_rect, const GPUFXSettings *fx_settings) @@ -430,7 +415,7 @@ bool GPU_fx_compositor_initialize_passes( /* try creating the jitter texture */ if (!fx->jitter_buffer) - fx->jitter_buffer = create_jitter_texture(); + fx->jitter_buffer = GPU_texture_create_jitter(64); /* check if color buffers need recreation */ if (!fx->color_buffer || !fx->depth_buffer || w != fx->gbuffer_dim[0] || h != fx->gbuffer_dim[1]) { @@ -442,7 +427,7 @@ bool GPU_fx_compositor_initialize_passes( return false; } - if (!(fx->depth_buffer = GPU_texture_create_depth(w, h, err_out))) { + if (!(fx->depth_buffer = GPU_texture_create_depth(w, h, true, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); return false; @@ -502,7 +487,7 @@ bool GPU_fx_compositor_initialize_passes( return false; } if (!(fx->dof_nearfar_coc = GPU_texture_create_2D_procedural( - fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, false, err_out))) + fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, false, false, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); @@ -644,7 +629,7 @@ void GPU_fx_compositor_setup_XRay_pass(GPUFX *fx, bool do_xray) if (do_xray) { if (!fx->depth_buffer_xray && - !(fx->depth_buffer_xray = GPU_texture_create_depth(fx->gbuffer_dim[0], fx->gbuffer_dim[1], err_out))) + !(fx->depth_buffer_xray = GPU_texture_create_depth(fx->gbuffer_dim[0], fx->gbuffer_dim[1], true, err_out))) { printf("%.256s\n", err_out); cleanup_fx_gl_data(fx, true); @@ -699,14 +684,14 @@ void GPU_fx_compositor_XRay_resolve(GPUFX *fx) GPU_shader_bind(depth_resolve_shader); GPU_texture_bind(fx->depth_buffer_xray, 0); - GPU_texture_filter_mode(fx->depth_buffer_xray, false, true); + GPU_texture_filter_mode(fx->depth_buffer_xray, false, true, false); GPU_shader_uniform_texture(depth_resolve_shader, interface->depth_uniform, fx->depth_buffer_xray); /* draw */ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* disable bindings */ - GPU_texture_filter_mode(fx->depth_buffer_xray, true, false); + GPU_texture_filter_mode(fx->depth_buffer_xray, true, false, false); GPU_texture_unbind(fx->depth_buffer_xray); GPU_shader_unbind(); @@ -823,7 +808,7 @@ bool GPU_fx_do_composite_pass( GPU_shader_uniform_texture(ssao_shader, interface->color_uniform, src); GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_filter_mode(fx->depth_buffer, false, true); + GPU_texture_filter_mode(fx->depth_buffer, false, true, false); GPU_shader_uniform_texture(ssao_shader, interface->depth_uniform, fx->depth_buffer); GPU_texture_bind(fx->jitter_buffer, numslots++); @@ -839,7 +824,7 @@ bool GPU_fx_do_composite_pass( /* disable bindings */ GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_filter_mode(fx->depth_buffer, true, false, false); GPU_texture_unbind(fx->depth_buffer); GPU_texture_unbind(fx->jitter_buffer); GPU_texture_unbind(fx->ssao_spiral_samples_tex); @@ -915,12 +900,12 @@ bool GPU_fx_do_composite_pass( GPU_shader_uniform_vector(dof_shader_pass1, interface->invrendertargetdim_uniform, 2, 1, invrendertargetdim); GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_filter_mode(fx->depth_buffer, false, false); + GPU_texture_filter_mode(fx->depth_buffer, false, false, false); GPU_shader_uniform_texture(dof_shader_pass1, interface->depth_uniform, fx->depth_buffer); GPU_texture_bind(src, numslots++); /* disable filtering for the texture so custom downsample can do the right thing */ - GPU_texture_filter_mode(src, false, false); + GPU_texture_filter_mode(src, false, false, false); GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, src); /* target is the downsampled coc buffer */ @@ -934,9 +919,9 @@ bool GPU_fx_do_composite_pass( glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* disable bindings */ - GPU_texture_filter_mode(src, false, true); + GPU_texture_filter_mode(src, false, true, false); GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_filter_mode(fx->depth_buffer, true, false, false); GPU_texture_unbind(fx->depth_buffer); GPU_framebuffer_texture_detach(fx->dof_half_downsampled_near); @@ -967,7 +952,7 @@ bool GPU_fx_do_composite_pass( GPU_texture_bind(fx->dof_half_downsampled_far, numslots++); GPU_texture_bind(fx->dof_half_downsampled_near, numslots++); GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_half_downsampled_far); - GPU_texture_filter_mode(fx->dof_half_downsampled_far, false, false); + GPU_texture_filter_mode(fx->dof_half_downsampled_far, false, false, false); /* target is the downsampled coc buffer */ GPU_framebuffer_texture_attach(fx->gbuffer, fx->dof_far_blur, 0, NULL); @@ -987,7 +972,7 @@ bool GPU_fx_do_composite_pass( GPU_framebuffer_texture_detach(fx->dof_far_blur); GPU_shader_uniform_texture(dof_shader_pass2, interface->color_uniform, fx->dof_half_downsampled_near); - GPU_texture_filter_mode(fx->dof_half_downsampled_near, false, false); + GPU_texture_filter_mode(fx->dof_half_downsampled_near, false, false, false); selection[0] = 1.0f; selection[1] = 0.0f; @@ -1027,14 +1012,14 @@ bool GPU_fx_do_composite_pass( GPU_texture_bind(fx->dof_near_blur, numslots++); GPU_shader_uniform_texture(dof_shader_pass3, interface->near_uniform, fx->dof_near_blur); - GPU_texture_filter_mode(fx->dof_near_blur, false, true); + GPU_texture_filter_mode(fx->dof_near_blur, false, true, false); GPU_texture_bind(fx->dof_far_blur, numslots++); GPU_shader_uniform_texture(dof_shader_pass3, interface->far_uniform, fx->dof_far_blur); - GPU_texture_filter_mode(fx->dof_far_blur, false, true); + GPU_texture_filter_mode(fx->dof_far_blur, false, true, false); GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_filter_mode(fx->depth_buffer, false, false); + GPU_texture_filter_mode(fx->depth_buffer, false, false, false); GPU_shader_uniform_texture(dof_shader_pass3, interface->depth_uniform, fx->depth_buffer); GPU_texture_bind(src, numslots++); @@ -1049,7 +1034,7 @@ bool GPU_fx_do_composite_pass( GPU_texture_unbind(fx->dof_near_blur); GPU_texture_unbind(fx->dof_far_blur); GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_filter_mode(fx->depth_buffer, true, false, false); GPU_texture_unbind(fx->depth_buffer); /* may not be attached, in that case this just returns */ @@ -1109,7 +1094,7 @@ bool GPU_fx_do_composite_pass( GPU_shader_uniform_texture(dof_shader_pass1, interface->color_uniform, src); GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_filter_mode(fx->depth_buffer, false, true); + GPU_texture_filter_mode(fx->depth_buffer, false, true, false); GPU_shader_uniform_texture(dof_shader_pass1, interface->depth_uniform, fx->depth_buffer); /* target is the downsampled coc buffer */ @@ -1120,7 +1105,7 @@ bool GPU_fx_do_composite_pass( glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* disable bindings */ GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_filter_mode(fx->depth_buffer, true, false, false); GPU_texture_unbind(fx->depth_buffer); GPU_framebuffer_texture_detach(fx->dof_near_coc_buffer); @@ -1146,7 +1131,7 @@ bool GPU_fx_do_composite_pass( GPU_shader_uniform_vector(dof_shader_pass2, interface->viewvecs_uniform, 4, 3, viewvecs[0]); GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_filter_mode(fx->depth_buffer, false, true); + GPU_texture_filter_mode(fx->depth_buffer, false, true, false); GPU_shader_uniform_texture(dof_shader_pass2, interface->depth_uniform, fx->depth_buffer); GPU_texture_bind(fx->dof_near_coc_buffer, numslots++); @@ -1174,7 +1159,7 @@ bool GPU_fx_do_composite_pass( glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); /* *unbind/detach */ - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_filter_mode(fx->depth_buffer, true, false, false); GPU_texture_unbind(fx->depth_buffer); GPU_texture_unbind(fx->dof_near_coc_final_buffer); @@ -1258,7 +1243,7 @@ bool GPU_fx_do_composite_pass( GPU_shader_uniform_texture(dof_shader_pass5, interface->medium_blurred_uniform, fx->dof_near_coc_buffer); GPU_texture_bind(fx->depth_buffer, numslots++); - GPU_texture_filter_mode(fx->depth_buffer, false, true); + GPU_texture_filter_mode(fx->depth_buffer, false, true, false); GPU_shader_uniform_texture(dof_shader_pass5, interface->depth_uniform, fx->depth_buffer); /* if this is the last pass, prepare for rendering on the frambuffer */ @@ -1269,7 +1254,7 @@ bool GPU_fx_do_composite_pass( GPU_texture_unbind(fx->dof_near_coc_buffer); GPU_texture_unbind(fx->dof_near_coc_blurred_buffer); GPU_texture_unbind(src); - GPU_texture_filter_mode(fx->depth_buffer, true, false); + GPU_texture_filter_mode(fx->depth_buffer, true, false, false); GPU_texture_unbind(fx->depth_buffer); /* may not be attached, in that case this just returns */ diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 022de6c72fef..85110ad33dae 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -99,128 +99,6 @@ extern Material defmaterial; /* from material.c */ -/* Text Rendering */ - -static void gpu_mcol(unsigned int ucol) -{ - /* mcol order is swapped */ - const char *cp = (char *)&ucol; - glColor3ub(cp[3], cp[2], cp[1]); -} - -void GPU_render_text( - MTexPoly *mtexpoly, int mode, - const char *textstr, int textlen, unsigned int *col, - const float *v_quad[4], const float *uv_quad[4], - int glattrib) -{ - if ((mode & GEMAT_TEXT) && (textlen > 0) && mtexpoly->tpage) { - const float *v1 = v_quad[0]; - const float *v2 = v_quad[1]; - const float *v3 = v_quad[2]; - const float *v4 = v_quad[3]; - Image *ima = (Image *)mtexpoly->tpage; - const size_t textlen_st = textlen; - float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance; - - /* multiline */ - float line_start = 0.0f, line_height; - - if (v4) - line_height = max_ffff(v1[1], v2[1], v3[1], v4[2]) - min_ffff(v1[1], v2[1], v3[1], v4[2]); - else - line_height = max_fff(v1[1], v2[1], v3[1]) - min_fff(v1[1], v2[1], v3[1]); - line_height *= 1.2f; /* could be an option? */ - /* end multiline */ - - - /* color has been set */ - if (mtexpoly->mode & TF_OBCOL) - col = NULL; - else if (!col) - glColor3f(1.0f, 1.0f, 1.0f); - - glPushMatrix(); - - /* get the tab width */ - ImBuf *first_ibuf = BKE_image_get_first_ibuf(ima); - matrixGlyph(first_ibuf, ' ', ¢erx, ¢ery, - &sizex, &sizey, &transx, &transy, &movex, &movey, &advance); - - float advance_tab = advance * 4; /* tab width could also be an option */ - - - for (size_t index = 0; index < textlen_st; ) { - unsigned int character; - float uv[4][2]; - - /* lets calculate offset stuff */ - character = BLI_str_utf8_as_unicode_and_size_safe(textstr + index, &index); - - if (character == '\n') { - glTranslatef(line_start, -line_height, 0.0f); - line_start = 0.0f; - continue; - } - else if (character == '\t') { - glTranslatef(advance_tab, 0.0f, 0.0f); - line_start -= advance_tab; /* so we can go back to the start of the line */ - continue; - - } - else if (character > USHRT_MAX) { - /* not much we can do here bmfonts take ushort */ - character = '?'; - } - - /* space starts at offset 1 */ - /* character = character - ' ' + 1; */ - matrixGlyph(first_ibuf, character, & centerx, ¢ery, - &sizex, &sizey, &transx, &transy, &movex, &movey, &advance); - - uv[0][0] = (uv_quad[0][0] - centerx) * sizex + transx; - uv[0][1] = (uv_quad[0][1] - centery) * sizey + transy; - uv[1][0] = (uv_quad[1][0] - centerx) * sizex + transx; - uv[1][1] = (uv_quad[1][1] - centery) * sizey + transy; - uv[2][0] = (uv_quad[2][0] - centerx) * sizex + transx; - uv[2][1] = (uv_quad[2][1] - centery) * sizey + transy; - - glBegin(GL_POLYGON); - if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[0]); - else glTexCoord2fv(uv[0]); - if (col) gpu_mcol(col[0]); - glVertex3f(sizex * v1[0] + movex, sizey * v1[1] + movey, v1[2]); - - if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[1]); - else glTexCoord2fv(uv[1]); - if (col) gpu_mcol(col[1]); - glVertex3f(sizex * v2[0] + movex, sizey * v2[1] + movey, v2[2]); - - if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[2]); - else glTexCoord2fv(uv[2]); - if (col) gpu_mcol(col[2]); - glVertex3f(sizex * v3[0] + movex, sizey * v3[1] + movey, v3[2]); - - if (v4) { - uv[3][0] = (uv_quad[3][0] - centerx) * sizex + transx; - uv[3][1] = (uv_quad[3][1] - centery) * sizey + transy; - - if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[3]); - else glTexCoord2fv(uv[3]); - if (col) gpu_mcol(col[3]); - glVertex3f(sizex * v4[0] + movex, sizey * v4[1] + movey, v4[2]); - } - glEnd(); - - glTranslatef(advance, 0.0f, 0.0f); - line_start -= advance; /* so we can go back to the start of the line */ - } - glPopMatrix(); - - BKE_image_release_ibuf(ima, first_ibuf, NULL); - } -} - /* Checking powers of two for images since OpenGL ES requires it */ static bool is_power_of_2_resolution(int w, int h) @@ -1809,7 +1687,7 @@ void GPU_begin_object_materials( /* viewport material, setup in space_view3d, defaults to matcap using ma->preview now */ if (use_matcap) { GMS.gmatbuf[0] = v3d->defmaterial; - GPU_material_matcap(scene, v3d->defmaterial, use_opensubdiv); + GPU_material_matcap(scene, v3d->defmaterial, use_opensubdiv ? GPU_MATERIAL_OPENSUBDIV : 0); /* do material 1 too, for displists! */ memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed)); @@ -1827,7 +1705,7 @@ void GPU_begin_object_materials( if (glsl) { GMS.gmatbuf[0] = &defmaterial; - GPU_material_from_blender(GMS.gscene, &defmaterial, GMS.is_opensubdiv); + GPU_material_from_blender(GMS.gscene, &defmaterial, GMS.is_opensubdiv ? GPU_MATERIAL_OPENSUBDIV : 0); } GMS.alphablend[0] = GPU_BLEND_SOLID; @@ -1841,7 +1719,7 @@ void GPU_begin_object_materials( if (ma == NULL) ma = &defmaterial; /* create glsl material if requested */ - gpumat = glsl ? GPU_material_from_blender(GMS.gscene, ma, GMS.is_opensubdiv) : NULL; + gpumat = glsl ? GPU_material_from_blender(GMS.gscene, ma, GMS.is_opensubdiv ? GPU_MATERIAL_OPENSUBDIV : 0) : NULL; if (gpumat) { /* do glsl only if creating it succeed, else fallback */ @@ -1957,7 +1835,7 @@ int GPU_object_material_bind(int nr, void *attribs) /* unbind glsl material */ if (GMS.gboundmat) { if (GMS.is_alpha_pass) glDepthMask(0); - GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat, GMS.is_opensubdiv)); + GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat, GMS.is_opensubdiv ? GPU_MATERIAL_OPENSUBDIV : 0)); GMS.gboundmat = NULL; } @@ -1985,7 +1863,7 @@ int GPU_object_material_bind(int nr, void *attribs) float auto_bump_scale; - GPUMaterial *gpumat = GPU_material_from_blender(GMS.gscene, mat, GMS.is_opensubdiv); + GPUMaterial *gpumat = GPU_material_from_blender(GMS.gscene, mat, GMS.is_opensubdiv ? GPU_MATERIAL_OPENSUBDIV : 0); GPU_material_vertex_attributes(gpumat, gattribs); if (GMS.dob) { @@ -1996,12 +1874,13 @@ int GPU_object_material_bind(int nr, void *attribs) GPU_get_object_info(object_info, mat); } + GPU_material_update_lamps(gpumat, GMS.gviewmat, GMS.gviewinv); GPU_material_bind( - gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT), + gpumat, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT), GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac, GMS.gscenelock); auto_bump_scale = GMS.gob->derivedFinal != NULL ? GMS.gob->derivedFinal->auto_bump_scale : 1.0f; - GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, auto_bump_scale, &partile_info, object_info); + GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, GMS.gob->lay, auto_bump_scale, &partile_info, object_info); GMS.gboundmat = mat; /* for glsl use alpha blend mode, unless it's set to solid and @@ -2089,7 +1968,7 @@ void GPU_object_material_unbind(void) glDisable(GL_CULL_FACE); if (GMS.is_alpha_pass) glDepthMask(0); - GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat, GMS.is_opensubdiv)); + GPU_material_unbind(GPU_material_from_blender(GMS.gscene, GMS.gboundmat, GMS.is_opensubdiv ? GPU_MATERIAL_OPENSUBDIV : 0)); GMS.gboundmat = NULL; } else diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index 16f8af2c1b75..225e608ed038 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -235,6 +235,10 @@ void gpu_extensions_init(void) GG.dfdyfactors[1] = 1.0; } + /* Enable globally cube map seamless to avoid edge on mipmapping */ + if (GLEW_ARB_seamless_cube_map) { + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); + } GPU_invalid_tex_init(); GPU_basic_shaders_init(); diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index ff637b5b4de0..19ae052a42e3 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -29,6 +29,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_math_base.h" #include "BKE_global.h" @@ -50,6 +51,8 @@ struct GPUFrameBuffer { GLuint object; GPUTexture *colortex[GPU_FB_MAX_SLOTS]; GPUTexture *depthtex; + GPURenderBuffer *colorrb[GPU_FB_MAX_SLOTS]; + GPURenderBuffer *depthrb; }; static void gpu_print_framebuffer_error(GLenum status, char err_out[256]) @@ -127,6 +130,11 @@ GPUFrameBuffer *GPU_framebuffer_create(void) } int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256]) +{ + return GPU_framebuffer_texture_attach_target(fb, tex, GPU_texture_target(tex), slot, err_out); +} + +int GPU_framebuffer_texture_attach_target(GPUFrameBuffer *fb, GPUTexture *tex, int target, int slot, char err_out[256]) { GLenum attachment; GLenum error; @@ -158,7 +166,7 @@ int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot while (glGetError() != GL_NO_ERROR) {} glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, - GPU_texture_target(tex), GPU_texture_opengl_bindcode(tex), 0); + target, GPU_texture_opengl_bindcode(tex), 0); error = glGetError(); @@ -179,6 +187,11 @@ int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot } void GPU_framebuffer_texture_detach(GPUTexture *tex) +{ + GPU_framebuffer_texture_detach_target(tex, GPU_texture_target(tex)); +} + +void GPU_framebuffer_texture_detach_target(GPUTexture *tex, int target) { GLenum attachment; GPUFrameBuffer *fb = GPU_texture_framebuffer(tex); @@ -202,7 +215,7 @@ void GPU_framebuffer_texture_detach(GPUTexture *tex) attachment = GL_COLOR_ATTACHMENT0_EXT + fb_attachment; } - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, GPU_texture_target(tex), 0, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, target, 0, 0); GPU_texture_framebuffer_set(tex, NULL, -1); } @@ -312,6 +325,35 @@ void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot) GG.currentfb = fb->object; } +void GPU_framebuffer_bind_simple(GPUFrameBuffer *fb) +{ + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + /* last bound prevails here, better allow explicit control here too */ + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); + + GG.currentfb = fb->object; +} + +void GPU_framebuffer_bind_all_attachments(GPUFrameBuffer *fb) +{ + int slots = 0, i; + GLenum attachments[GPU_FB_MAX_SLOTS]; + + for(i = 0; i < GPU_FB_MAX_SLOTS; i++) { + if (fb->colortex[i]) { + attachments[slots] = GL_COLOR_ATTACHMENT0_EXT + i; + slots++; + } + } + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + glDrawBuffers(slots, attachments); + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); + + GG.currentfb = fb->object; +} + bool GPU_framebuffer_bound(GPUFrameBuffer *fb) { return fb->object == GG.currentfb; @@ -338,6 +380,80 @@ bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]) return true; } +int GPU_framebuffer_renderbuffer_attach(GPUFrameBuffer *fb, GPURenderBuffer *rb, int slot, char err_out[256]) +{ + GLenum attachement; + GLenum error; + + if (slot >= GPU_FB_MAX_SLOTS) { + fprintf(stderr, + "Attaching to index %d framebuffer slot unsupported. " + "Use at most %d\n", slot, GPU_FB_MAX_SLOTS); + return 0; + } + + if (GPU_renderbuffer_depth(rb)) { + attachement = GL_DEPTH_ATTACHMENT_EXT; + } + else { + attachement = GL_COLOR_ATTACHMENT0_EXT + slot; + } + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + GG.currentfb = fb->object; + + /* Clean glError buffer. */ + while (glGetError() != GL_NO_ERROR) {} + + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachement, GL_RENDERBUFFER_EXT, GPU_renderbuffer_bindcode(rb)); + + error = glGetError(); + + if (error == GL_INVALID_OPERATION) { + GPU_framebuffer_restore(); + gpu_print_framebuffer_error(error, err_out); + return 0; + } + + if (GPU_renderbuffer_depth(rb)) + fb->depthrb = rb; + else + fb->colorrb[slot] = rb; + + GPU_renderbuffer_framebuffer_set(rb, fb, slot); + + return 1; +} + +void GPU_framebuffer_renderbuffer_detach(GPURenderBuffer *rb) +{ + GLenum attachment; + GPUFrameBuffer *fb = GPU_renderbuffer_framebuffer(rb); + int fb_attachment = GPU_renderbuffer_framebuffer_attachment(rb); + + if (!fb) + return; + + if (GG.currentfb != fb->object) { + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object); + GG.currentfb = fb->object; + } + + if (GPU_renderbuffer_depth(rb)) { + fb->depthrb = NULL; + attachment = GL_DEPTH_ATTACHMENT_EXT; + } + else { + BLI_assert(fb->colorrb[fb_attachment] == rb); + fb->colorrb[fb_attachment] = NULL; + attachment = GL_COLOR_ATTACHMENT0_EXT + fb_attachment; + } + + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attachment, GL_RENDERBUFFER_EXT, 0); + + GPU_renderbuffer_framebuffer_set(rb, NULL, -1); +} + void GPU_framebuffer_free(GPUFrameBuffer *fb) { int i; @@ -350,6 +466,15 @@ void GPU_framebuffer_free(GPUFrameBuffer *fb) } } + if (fb->depthrb) + GPU_framebuffer_renderbuffer_detach(fb->depthrb); + + for (i = 0; i < GPU_FB_MAX_SLOTS; i++) { + if (fb->colorrb[i]) { + GPU_framebuffer_renderbuffer_detach(fb->colorrb[i]); + } + } + if (fb->object) { glDeleteFramebuffersEXT(1, &fb->object); @@ -372,10 +497,10 @@ void GPU_framebuffer_restore(void) void GPU_framebuffer_blur( GPUFrameBuffer *fb, GPUTexture *tex, - GPUFrameBuffer *blurfb, GPUTexture *blurtex) + GPUFrameBuffer *blurfb, GPUTexture *blurtex, float sharpness) { - const float scaleh[2] = {1.0f / GPU_texture_width(blurtex), 0.0f}; - const float scalev[2] = {0.0f, 1.0f / GPU_texture_height(tex)}; + const float scaleh[2] = {(1.0f - sharpness) / GPU_texture_width(blurtex), 0.0f}; + const float scalev[2] = {0.0f, (1.0f - sharpness) / GPU_texture_height(tex)}; GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR); int scale_uniform, texture_source_uniform; @@ -398,21 +523,12 @@ void GPU_framebuffer_blur( GPU_shader_bind(blur_shader); GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scaleh); + GPU_texture_bind(tex, 0); GPU_shader_uniform_texture(blur_shader, texture_source_uniform, tex); glViewport(0, 0, GPU_texture_width(blurtex), GPU_texture_height(blurtex)); - /* Preparing to draw quad */ - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glDisable(GL_DEPTH_TEST); - GPU_texture_bind(tex, 0); - /* Drawing quad */ glBegin(GL_QUADS); glTexCoord2d(0, 0); glVertex2f(1, 1); @@ -428,10 +544,10 @@ void GPU_framebuffer_blur( GG.currentfb = fb->object; - glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex)); GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scalev); - GPU_shader_uniform_texture(blur_shader, texture_source_uniform, blurtex); GPU_texture_bind(blurtex, 0); + GPU_shader_uniform_texture(blur_shader, texture_source_uniform, blurtex); + glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex)); glBegin(GL_QUADS); glTexCoord2d(0, 0); glVertex2f(1, 1); @@ -440,18 +556,150 @@ void GPU_framebuffer_blur( glTexCoord2d(0, 1); glVertex2f(1, -1); glEnd(); + GPU_texture_unbind(blurtex); GPU_shader_unbind(); + + glEnable(GL_DEPTH_TEST); } +/* GPURenderBuffer */ + +struct GPURenderBuffer { + int width; + int height; + int samples; + + GPUFrameBuffer *fb; /* GPUFramebuffer this render buffer is attached to */ + int fb_attachment; /* slot the render buffer is attached to */ + bool depth; + unsigned int bindcode; +}; + +GPURenderBuffer *GPU_renderbuffer_create(int width, int height, int samples, GPUHDRType hdrtype, GPURenderBufferType type, char err_out[256]) +{ + GPURenderBuffer *rb = MEM_callocN(sizeof(GPURenderBuffer), "GPURenderBuffer"); + + glGenRenderbuffers(1, &rb->bindcode); + + if (!rb->bindcode) { + if (err_out) { + BLI_snprintf(err_out, 256, "GPURenderBuffer: render buffer creation failed: %d", + (int)glGetError()); + } + else { + fprintf(stderr, "GPURenderBuffer: render buffer creation failed: %d\n", + (int)glGetError()); + } + GPU_renderbuffer_free(rb); + return NULL; + } + + rb->width = width; + rb->height = height; + rb->samples = samples; + + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, rb->bindcode); + + if (type == GPU_RENDERBUFFER_DEPTH) { + if (samples > 0) { + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, GL_DEPTH_COMPONENT, width, height); + } + else { + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height); + } + rb->depth = true; + } + else { + GLenum internalformat = GL_RGBA12; + switch (hdrtype) { + case GPU_HDR_NONE: + { + internalformat = GL_RGBA12; + break; + } + /* the following formats rely on ARB_texture_float or OpenGL 3.0 */ + case GPU_HDR_HALF_FLOAT: + { + internalformat = GL_RGBA16F_ARB; + break; + } + case GPU_HDR_FULL_FLOAT: + { + internalformat = GL_RGBA32F_ARB; + break; + } + } + if (samples > 0) { + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples, internalformat, width, height); + } + else { + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, internalformat, width, height); + } + } + + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); + + return rb; +} + +void GPU_renderbuffer_free(GPURenderBuffer *rb) +{ + if (rb->bindcode) { + glDeleteRenderbuffersEXT(1, &rb->bindcode); + } + + MEM_freeN(rb); +} + +GPUFrameBuffer *GPU_renderbuffer_framebuffer(GPURenderBuffer *rb) +{ + return rb->fb; +} + +int GPU_renderbuffer_framebuffer_attachment(GPURenderBuffer *rb) +{ + return rb->fb_attachment; +} + +void GPU_renderbuffer_framebuffer_set(GPURenderBuffer *rb, GPUFrameBuffer *fb, int attachement) +{ + rb->fb = fb; + rb->fb_attachment = attachement; +} + +int GPU_renderbuffer_bindcode(const GPURenderBuffer *rb) +{ + return rb->bindcode; +} + +bool GPU_renderbuffer_depth(const GPURenderBuffer *rb) +{ + return rb->depth; +} + +int GPU_renderbuffer_width(const GPURenderBuffer *rb) +{ + return rb->width; +} + +int GPU_renderbuffer_height(const GPURenderBuffer *rb) +{ + return rb->height; +} + + /* GPUOffScreen */ struct GPUOffScreen { GPUFrameBuffer *fb; GPUTexture *color; GPUTexture *depth; + GPURenderBuffer *rbcolor; + GPURenderBuffer *rbdepth; + int samples; }; -GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256]) +GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, GPUHDRType hdrtype, int mode, char err_out[256]) { GPUOffScreen *ofs; @@ -465,39 +713,76 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_ if (samples) { if (!GLEW_EXT_framebuffer_multisample || - !GLEW_ARB_texture_multisample || + /* Disable multisample for texture and not render buffers + * when it's not supported */ + (!GLEW_ARB_texture_multisample && (!(mode & GPU_OFFSCREEN_RENDERBUFFER_COLOR) || !(mode & GPU_OFFSCREEN_RENDERBUFFER_DEPTH))) || /* Only needed for GPU_offscreen_read_pixels. * We could add an arg if we intend to use multi-sample * offscreen buffers w/o reading their pixels */ - !GLEW_EXT_framebuffer_blit || + !GLEW_EXT_framebuffer_blit + + /* Some GPUs works even without this extension. */ +#if 0 /* This is required when blitting from a multi-sampled buffers, * even though we're not scaling. */ - !GLEW_EXT_framebuffer_multisample_blit_scaled) + || !GLEW_EXT_framebuffer_multisample_blit_scaled +#endif + ) { samples = 0; } } - ofs->depth = GPU_texture_create_depth_multisample(width, height, samples, err_out); - if (!ofs->depth) { - GPU_offscreen_free(ofs); - return NULL; + ofs->samples = samples; + + if (mode & GPU_OFFSCREEN_RENDERBUFFER_COLOR) { + ofs->rbcolor = GPU_renderbuffer_create(width, height, samples, hdrtype, GPU_RENDERBUFFER_COLOR, err_out); + if (!ofs->rbcolor) { + GPU_offscreen_free(ofs); + return NULL; + } + + if (!GPU_framebuffer_renderbuffer_attach(ofs->fb, ofs->rbcolor, 0, err_out)) { + GPU_offscreen_free(ofs); + return NULL; + } } + else { + ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, hdrtype, samples, err_out); + if (!ofs->color) { + GPU_offscreen_free(ofs); + return NULL; + } - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, err_out)) { - GPU_offscreen_free(ofs); - return NULL; + if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, err_out)) { + GPU_offscreen_free(ofs); + return NULL; + } } - ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, GPU_HDR_NONE, samples, err_out); - if (!ofs->color) { - GPU_offscreen_free(ofs); - return NULL; + if (mode & GPU_OFFSCREEN_RENDERBUFFER_DEPTH) { + ofs->rbdepth = GPU_renderbuffer_create(width, height, samples, GPU_HDR_NONE, GPU_RENDERBUFFER_DEPTH, err_out); + if (!ofs->rbdepth) { + GPU_offscreen_free(ofs); + return NULL; + } + + if (!GPU_framebuffer_renderbuffer_attach(ofs->fb, ofs->rbdepth, 0, err_out)) { + GPU_offscreen_free(ofs); + return NULL; + } } + else { + ofs->depth = GPU_texture_create_depth_multisample(width, height, samples, (mode & GPU_OFFSCREEN_DEPTH_COMPARE), err_out); + if (!ofs->depth) { + GPU_offscreen_free(ofs); + return NULL; + } - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, err_out)) { - GPU_offscreen_free(ofs); - return NULL; + if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, err_out)) { + GPU_offscreen_free(ofs); + return NULL; + } } /* check validity at the very end! */ @@ -519,6 +804,12 @@ void GPU_offscreen_free(GPUOffScreen *ofs) GPU_texture_free(ofs->color); if (ofs->depth) GPU_texture_free(ofs->depth); + if (ofs->rbcolor) { + GPU_renderbuffer_free(ofs->rbcolor); + } + if (ofs->rbdepth) { + GPU_renderbuffer_free(ofs->rbdepth); + } MEM_freeN(ofs); } @@ -533,6 +824,11 @@ void GPU_offscreen_bind(GPUOffScreen *ofs, bool save) } } +void GPU_offscreen_bind_simple(GPUOffScreen *ofs) +{ + GPU_framebuffer_bind_simple(ofs->fb); +} + void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore) { if (restore) @@ -620,17 +916,76 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels) } } +void GPU_offscreen_blit(GPUOffScreen *srcofs, GPUOffScreen *dstofs, bool color, bool depth) +{ + BLI_assert(color || depth); + + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, srcofs->fb->object); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, dstofs->fb->object); + + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); + + int height = min_ff(GPU_offscreen_height(srcofs), GPU_offscreen_height(dstofs)); + int width = min_ff(GPU_offscreen_width(srcofs), GPU_offscreen_width(dstofs)); + + + int mask = 0; + if (color) { + mask |= GL_COLOR_BUFFER_BIT; + } + if (depth) { + mask |= GL_DEPTH_BUFFER_BIT; + } + + glBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height, mask, GL_NEAREST); + + // Call GPU_framebuffer_bind_simple to change GG.currentfb. + GPU_framebuffer_bind_simple(dstofs->fb); +} + int GPU_offscreen_width(const GPUOffScreen *ofs) { - return GPU_texture_width(ofs->color); + if (ofs->color) { + return GPU_texture_width(ofs->color); + } + else if (ofs->rbcolor) { + return GPU_renderbuffer_width(ofs->rbcolor); + } + + // Should never happen. + return 0; } int GPU_offscreen_height(const GPUOffScreen *ofs) { - return GPU_texture_height(ofs->color); + if (ofs->color) { + return GPU_texture_height(ofs->color); + } + else if (ofs->rbcolor) { + return GPU_renderbuffer_height(ofs->rbcolor); + } + + // Should never happen. + return 0; +} + +int GPU_offscreen_samples(const GPUOffScreen *ofs) +{ + return ofs->samples; } int GPU_offscreen_color_texture(const GPUOffScreen *ofs) { return GPU_texture_opengl_bindcode(ofs->color); } + +GPUTexture *GPU_offscreen_texture(const GPUOffScreen *ofs) +{ + return ofs->color; +} + +GPUTexture *GPU_offscreen_depth_texture(const GPUOffScreen *ofs) +{ + return ofs->depth; +} diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 9db9ed1f5e70..7bbdace9fb00 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -89,6 +89,9 @@ static struct GPUWorld { float horicol[3]; float ambcol[4]; float zencol[3]; + float logfac; + float linfac; + float envlightenergy; } GPUWorld; struct GPUMaterial { @@ -116,6 +119,7 @@ struct GPUMaterial { int localtoviewmatloc, invlocaltoviewmatloc; int obcolloc, obautobumpscaleloc; int cameratexcofacloc; + int timeloc; int partscalarpropsloc; int partcoloc; @@ -123,11 +127,20 @@ struct GPUMaterial { int partangvel; int objectinfoloc; + int objectlayloc; + + int ininstposloc; + int ininstmatloc; + int ininstcolloc; + int ininstlayloc; + int ininstinfoloc; ListBase lamps; bool bound; - bool is_opensubdiv; + GPUMaterialFlag flags; + + float har; }; struct GPULamp { @@ -138,8 +151,10 @@ struct GPULamp { int type, mode, lay, hide; + int dynlayer; float dynenergy, dyncol[3]; float energy, col[3]; + float cutoff, radius; float co[3], vec[3]; float dynco[3], dynvec[3]; @@ -154,7 +169,7 @@ struct GPULamp { float coeff_const, coeff_lin, coeff_quad; float shadow_color[3]; - float bias, d, clipend; + float bias, slopebias, d, clipend; int size; int falloff_type; @@ -181,6 +196,67 @@ static void texture_rgb_blend( /* Functions */ +static bool tex_do_color_management(GPUMaterial *mat, MTex *mtex, Tex *tex) +{ + const bool mtexDoColorManagement = (mtex->colorManagement == GAME_COLOR_MANAGEMENT_SRGB) && GPU_material_do_color_management(mat); + + if (tex->type == TEX_IMAGE) { + return mtexDoColorManagement; + } + else if (tex->type == TEX_ENVMAP) { + // Realtime textures are rendered from game engine without sRGB conversion. + if (tex->env && tex->env->stype == ENV_REALT) { + return !(mat->flags & GPU_MATERIAL_NO_COLOR_MANAGEMENT); + } + else { + return mtexDoColorManagement; + } + } + + return false; +} + +GPUNodeLink *GPU_material_builtin(GPUMaterial *mat, GPUBuiltin builtin) +{ + const bool instancing = GPU_material_use_instancing(mat); + + if (instancing) { + switch (builtin) { + case GPU_OBJECT_MATRIX: + { + builtin = GPU_INSTANCING_MATRIX; + break; + } + case GPU_INVERSE_OBJECT_MATRIX: + { + builtin = GPU_INSTANCING_INVERSE_MATRIX; + break; + } + case GPU_OBCOLOR: + { + builtin = GPU_INSTANCING_COLOR; + break; + } + case GPU_OBJECT_LAY: + { + builtin = GPU_INSTANCING_LAYER; + break; + } + case GPU_OBJECT_INFO: + { + builtin = GPU_INSTANCING_INFO; + break; + } + default: + { + break; + } + } + } + + return GPU_builtin(builtin); +} + static GPUMaterial *GPU_material_construct_begin(Material *ma) { GPUMaterial *material = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial"); @@ -234,7 +310,8 @@ static int gpu_material_construct_end(GPUMaterial *material, const char *passnam material->pass = GPU_generate_pass(&material->nodes, outlink, &material->attribs, &material->builtins, material->type, passname, - material->is_opensubdiv, + material->flags & GPU_MATERIAL_OPENSUBDIV, + material->flags & GPU_MATERIAL_INSTANCING, GPU_material_use_new_shading_nodes(material)); if (!material->pass) @@ -262,6 +339,8 @@ static int gpu_material_construct_end(GPUMaterial *material, const char *passnam material->obautobumpscaleloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_AUTO_BUMPSCALE)); if (material->builtins & GPU_CAMERA_TEXCO_FACTORS) material->cameratexcofacloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_CAMERA_TEXCO_FACTORS)); + if (material->builtins & GPU_TIME) + material->timeloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_TIME)); if (material->builtins & GPU_PARTICLE_SCALAR_PROPS) material->partscalarpropsloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_SCALAR_PROPS)); if (material->builtins & GPU_PARTICLE_LOCATION) @@ -270,8 +349,19 @@ static int gpu_material_construct_end(GPUMaterial *material, const char *passnam material->partvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_VELOCITY)); if (material->builtins & GPU_PARTICLE_ANG_VELOCITY) material->partangvel = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_PARTICLE_ANG_VELOCITY)); - if (material->builtins & GPU_OBJECT_INFO) + if (GPU_material_use_instancing(material)) { + material->ininstposloc = GPU_shader_get_attribute(shader, GPU_builtin_name(GPU_INSTANCING_POSITION_ATTRIB)); + material->ininstmatloc = GPU_shader_get_attribute(shader, GPU_builtin_name(GPU_INSTANCING_MATRIX_ATTRIB)); + material->ininstcolloc = GPU_shader_get_attribute(shader, GPU_builtin_name(GPU_INSTANCING_COLOR_ATTRIB)); + material->ininstlayloc = GPU_shader_get_attribute(shader, GPU_builtin_name(GPU_INSTANCING_LAYER_ATTRIB)); + material->ininstinfoloc = GPU_shader_get_attribute(shader, GPU_builtin_name(GPU_INSTANCING_INFO_ATTRIB)); + } + if (material->builtins & GPU_OBJECT_INFO) { material->objectinfoloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_OBJECT_INFO)); + } + if (material->builtins & GPU_OBJECT_LAY) { + material->objectlayloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_OBJECT_LAY)); + } return 1; } else { @@ -324,12 +414,99 @@ bool GPU_lamp_visible(GPULamp *lamp, SceneRenderLayer *srl, Material *ma) return true; } +bool GPU_material_use_instancing(GPUMaterial *material) +{ + return material->flags & GPU_MATERIAL_INSTANCING; +} + +void GPU_material_bind_instancing_attrib(GPUMaterial *material, void *matrixoffset, void *positionoffset, void *coloroffset, void *layeroffset, void *infooffset) +{ + // Matrix + if (material->ininstmatloc != -1) { + glEnableVertexAttribArray(material->ininstmatloc); + glEnableVertexAttribArray(material->ininstmatloc + 1); + glEnableVertexAttribArray(material->ininstmatloc + 2); + + const unsigned short stride = sizeof(float) * 9; + glVertexAttribPointer(material->ininstmatloc, 3, GL_FLOAT, GL_FALSE, stride, matrixoffset); + glVertexAttribPointer(material->ininstmatloc + 1, 3, GL_FLOAT, GL_FALSE, stride, ((char *)matrixoffset) + 3 * sizeof(float)); + glVertexAttribPointer(material->ininstmatloc + 2, 3, GL_FLOAT, GL_FALSE, stride, ((char *)matrixoffset) + 6 * sizeof(float)); + + glVertexAttribDivisorARB(material->ininstmatloc, 1); + glVertexAttribDivisorARB(material->ininstmatloc + 1, 1); + glVertexAttribDivisorARB(material->ininstmatloc + 2, 1); + } + + // Position + if (material->ininstposloc != -1) { + glEnableVertexAttribArray(material->ininstposloc); + glVertexAttribPointer(material->ininstposloc, 3, GL_FLOAT, GL_FALSE, 0, positionoffset); + glVertexAttribDivisorARB(material->ininstposloc, 1); + } + + // Color + if (material->ininstcolloc != -1) { + glEnableVertexAttribArray(material->ininstcolloc); + glVertexAttribPointer(material->ininstcolloc, 4, GL_FLOAT, GL_FALSE, 0, coloroffset); + glVertexAttribDivisorARB(material->ininstcolloc, 1); + } + + // Layer + if (material->ininstlayloc != -1) { + glEnableVertexAttribArray(material->ininstlayloc); + glVertexAttribIPointer(material->ininstlayloc, 1, GL_INT, 0, layeroffset); + glVertexAttribDivisorARB(material->ininstlayloc, 1); + } + + // Layer + if (material->ininstinfoloc != -1) { + glEnableVertexAttribArray(material->ininstinfoloc); + glVertexAttribPointer(material->ininstinfoloc, 3, GL_FLOAT, GL_FALSE, 0, infooffset); + glVertexAttribDivisorARB(material->ininstinfoloc, 1); + } +} + +void GPU_material_update_lamps(GPUMaterial *material, float viewmat[4][4], float viewinv[4][4]) +{ + for (LinkData *nlink = material->lamps.first; nlink; nlink = nlink->next) { + GPULamp *lamp = nlink->data; + + lamp->dynenergy = lamp->energy; + copy_v3_v3(lamp->dyncol, lamp->col); + + if (material->dynproperty & DYN_LAMP_VEC) { + copy_v3_v3(lamp->dynvec, lamp->vec); + normalize_v3(lamp->dynvec); + negate_v3(lamp->dynvec); + mul_mat3_m4_v3(viewmat, lamp->dynvec); + } + + if (material->dynproperty & DYN_LAMP_CO) { + copy_v3_v3(lamp->dynco, lamp->co); + mul_m4_v3(viewmat, lamp->dynco); + } + + if (material->dynproperty & DYN_LAMP_IMAT) { + mul_m4_m4m4(lamp->dynimat, lamp->imat, viewinv); + } + + if (material->dynproperty & DYN_LAMP_PERSMAT) { + /* The lamp matrices are already updated if we're using shadow buffers */ + if (!GPU_lamp_has_shadow_buffer(lamp)) { + GPU_lamp_update_buffer_mats(lamp); + } + mul_m4_m4m4(lamp->dynpersmat, lamp->persmat, viewinv); + } + } +} + void GPU_material_bind( - GPUMaterial *material, int oblay, int viewlay, double time, int mipmap, + GPUMaterial *material, int viewlay, double time, int mipmap, float viewmat[4][4], float viewinv[4][4], float camerafactors[4], bool scenelock) { if (material->pass) { GPUShader *shader = GPU_pass_shader(material->pass); + SceneRenderLayer *srl = scenelock ? BLI_findlink(&material->scene->r.layers, material->scene->r.actlay) : NULL; if (srl) @@ -339,44 +516,26 @@ void GPU_material_bind( if (material->type == GPU_MATERIAL_TYPE_MESH) { for (LinkData *nlink = material->lamps.first; nlink; nlink = nlink->next) { GPULamp *lamp = nlink->data; - - if ((lamp->lay & viewlay) && (!(lamp->mode & LA_LAYER) || (lamp->lay & oblay)) && - GPU_lamp_visible(lamp, srl, material->ma)) - { - lamp->dynenergy = lamp->energy; - copy_v3_v3(lamp->dyncol, lamp->col); - } - else { - lamp->dynenergy = 0.0f; - lamp->dyncol[0] = lamp->dyncol[1] = lamp->dyncol[2] = 0.0f; - } - - if (material->dynproperty & DYN_LAMP_VEC) { - copy_v3_v3(lamp->dynvec, lamp->vec); - normalize_v3(lamp->dynvec); - negate_v3(lamp->dynvec); - mul_mat3_m4_v3(viewmat, lamp->dynvec); - } - - if (material->dynproperty & DYN_LAMP_CO) { - copy_v3_v3(lamp->dynco, lamp->co); - mul_m4_v3(viewmat, lamp->dynco); + /* If the lamp is hidden, disable all layers or if the lamp is not + * in the same layer than the view, disable the lamp. */ + if (!(lamp->lay & viewlay) || !GPU_lamp_visible(lamp, srl, material->ma)) { + lamp->dynlayer = 0; } - - if (material->dynproperty & DYN_LAMP_IMAT) { - mul_m4_m4m4(lamp->dynimat, lamp->imat, viewinv); + // If the lamp isn't selecting a layer, enable all layers. + else if (!(lamp->mode & LA_LAYER)) { + lamp->dynlayer = (1 << 20) - 1; } - - if (material->dynproperty & DYN_LAMP_PERSMAT) { - /* The lamp matrices are already updated if we're using shadow buffers */ - if (!GPU_lamp_has_shadow_buffer(lamp)) { - GPU_lamp_update_buffer_mats(lamp); - } - mul_m4_m4m4(lamp->dynpersmat, lamp->persmat, viewinv); + // Let the layer as it to check with object layer. + else { + lamp->dynlayer = lamp->lay; } } } + if (material->ma) { + material->har = material->ma->har; + } + /* note material must be bound before setting uniforms */ GPU_pass_bind(material->pass, time, mipmap); @@ -397,6 +556,10 @@ void GPU_material_bind( GPU_shader_uniform_vector(shader, material->cameratexcofacloc, 4, 1, (float *)borders); } } + if (material->builtins & GPU_TIME) { + float ftime = (float)time; + GPU_shader_uniform_vector(shader, material->timeloc, 1, 1, &ftime); + } GPU_pass_update_uniforms(material->pass); @@ -410,7 +573,7 @@ GPUBuiltin GPU_get_material_builtins(GPUMaterial *material) } void GPU_material_bind_uniforms( - GPUMaterial *material, float obmat[4][4], float viewmat[4][4], float obcol[4], + GPUMaterial *material, float obmat[4][4], float viewmat[4][4], const float obcol[4], int oblay, float autobumpscale, GPUParticleInfo *pi, float object_info[3]) { if (material->pass) { @@ -463,7 +626,9 @@ void GPU_material_bind_uniforms( if (material->builtins & GPU_OBJECT_INFO) { GPU_shader_uniform_vector(shader, material->objectinfoloc, 3, 1, object_info); } - + if (material->builtins & GPU_OBJECT_LAY) { + GPU_shader_uniform_vector_int(shader, material->objectlayloc, 1, 1, &oblay); + } } } @@ -490,7 +655,6 @@ GPUMatType GPU_Material_get_type(GPUMaterial *material) return material->type; } - void GPU_material_vertex_attributes(GPUMaterial *material, GPUVertexAttribs *attribs) { *attribs = material->attribs; @@ -507,7 +671,7 @@ void GPU_material_enable_alpha(GPUMaterial *material) material->alpha = 1; } -GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4]) +GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, const float obcol[4]) { if (material->alpha || (material->obcolalpha && obcol[3] < 1.0f)) return GPU_BLEND_ALPHA; @@ -524,10 +688,7 @@ void gpu_material_add_node(GPUMaterial *material, GPUNode *node) bool GPU_material_do_color_management(GPUMaterial *mat) { - if (!BKE_scene_check_color_management_enabled(mat->scene)) - return false; - - return true; + return BKE_scene_check_color_management_enabled(mat->scene); } bool GPU_material_use_new_shading_nodes(GPUMaterial *mat) @@ -542,6 +703,7 @@ bool GPU_material_use_world_space_shading(GPUMaterial *mat) static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **lv, GPUNodeLink **dist) { + Material *ma = mat->ma; GPUNodeLink *visifac; /* from get_lamp_visibility */ @@ -554,7 +716,7 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode else { mat->dynproperty |= DYN_LAMP_CO; GPU_link(mat, "lamp_visibility_other", - GPU_builtin(GPU_VIEW_POSITION), + GPU_material_builtin(mat, GPU_VIEW_POSITION), GPU_dynamic_uniform(lamp->dynco, GPU_DYNAMIC_LAMP_DYNCO, lamp->ob), lv, dist, &visifac); if (lamp->type == LA_AREA) @@ -565,23 +727,23 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode break; case LA_FALLOFF_INVLINEAR: GPU_link(mat, "lamp_falloff_invlinear", - GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), *dist, &visifac); + GPU_select_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob, ma), *dist, &visifac); break; case LA_FALLOFF_INVSQUARE: GPU_link(mat, "lamp_falloff_invsquare", - GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), *dist, &visifac); + GPU_select_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob, ma), *dist, &visifac); break; case LA_FALLOFF_SLIDERS: GPU_link(mat, "lamp_falloff_sliders", - GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), - GPU_dynamic_uniform(&lamp->att1, GPU_DYNAMIC_LAMP_ATT1, lamp->ob), - GPU_dynamic_uniform(&lamp->att2, GPU_DYNAMIC_LAMP_ATT2, lamp->ob), *dist, &visifac); + GPU_select_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob, ma), + GPU_select_uniform(&lamp->att1, GPU_DYNAMIC_LAMP_ATT1, lamp->ob, ma), + GPU_select_uniform(&lamp->att2, GPU_DYNAMIC_LAMP_ATT2, lamp->ob, ma), *dist, &visifac); break; case LA_FALLOFF_INVCOEFFICIENTS: GPU_link(mat, "lamp_falloff_invcoefficients", - GPU_dynamic_uniform(&lamp->coeff_const, GPU_DYNAMIC_LAMP_COEFFCONST, lamp->ob), - GPU_dynamic_uniform(&lamp->coeff_lin, GPU_DYNAMIC_LAMP_COEFFLIN, lamp->ob), - GPU_dynamic_uniform(&lamp->coeff_quad, GPU_DYNAMIC_LAMP_COEFFQUAD, lamp->ob), *dist, &visifac); + GPU_select_uniform(&lamp->coeff_const, GPU_DYNAMIC_LAMP_COEFFCONST, lamp->ob, ma), + GPU_select_uniform(&lamp->coeff_lin, GPU_DYNAMIC_LAMP_COEFFLIN, lamp->ob, ma), + GPU_select_uniform(&lamp->coeff_quad, GPU_DYNAMIC_LAMP_COEFFQUAD, lamp->ob, ma), *dist, &visifac); break; case LA_FALLOFF_CURVE: { @@ -591,16 +753,25 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode curvemapping_initialize(lamp->curfalloff); curvemapping_table_RGBA(lamp->curfalloff, &array, &size); GPU_link(mat, "lamp_falloff_curve", - GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), + GPU_select_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob, ma), GPU_texture(size, array), *dist, &visifac); break; } + case LA_FALLOFF_INVSQUARE_CUTOFF: + { + GPU_link(mat, "lamp_falloff_invsquarecutoff", + GPU_select_uniform(&lamp->radius, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob, ma), + *dist, + GPU_select_uniform(&lamp->cutoff, GPU_DYNAMIC_LAMP_CUTOFF, lamp->ob, ma), + &visifac); + break; + } } if (lamp->mode & LA_SPHERE) GPU_link(mat, "lamp_visibility_sphere", - GPU_dynamic_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob), + GPU_select_uniform(&lamp->dist, GPU_DYNAMIC_LAMP_DISTANCE, lamp->ob, ma), *dist, visifac, &visifac); if (lamp->type == LA_SPOT) { @@ -611,19 +782,19 @@ static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNode GPU_link(mat, "lamp_visibility_spot_square", GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), GPU_dynamic_uniform((float *)lamp->dynimat, GPU_DYNAMIC_LAMP_DYNIMAT, lamp->ob), - GPU_dynamic_uniform((float *)lamp->spotvec, GPU_DYNAMIC_LAMP_SPOTSCALE, lamp->ob), *lv, &inpr); + GPU_dynamic_uniform((float *)lamp->spotvec, GPU_DYNAMIC_LAMP_DYNSPOTSCALE, lamp->ob), *lv, &inpr); } else { mat->dynproperty |= DYN_LAMP_VEC | DYN_LAMP_IMAT; GPU_link(mat, "lamp_visibility_spot_circle", GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), - GPU_dynamic_uniform((float *)lamp->dynimat, GPU_DYNAMIC_LAMP_DYNIMAT, lamp->ob), - GPU_dynamic_uniform((float *)lamp->spotvec, GPU_DYNAMIC_LAMP_SPOTSCALE, lamp->ob), *lv, &inpr); + GPU_dynamic_uniform((float *)lamp->dynimat, GPU_DYNAMIC_LAMP_DYNIMAT, lamp->ob), + GPU_dynamic_uniform((float *)lamp->spotvec, GPU_DYNAMIC_LAMP_DYNSPOTSCALE, lamp->ob), *lv, &inpr); } GPU_link(mat, "lamp_visibility_spot", - GPU_dynamic_uniform(&lamp->spotsi, GPU_DYNAMIC_LAMP_SPOTSIZE, lamp->ob), - GPU_dynamic_uniform(&lamp->spotbl, GPU_DYNAMIC_LAMP_SPOTBLEND, lamp->ob), + GPU_select_uniform(&lamp->spotsi, GPU_DYNAMIC_LAMP_SPOTSIZE, lamp->ob, ma), + GPU_select_uniform(&lamp->spotbl, GPU_DYNAMIC_LAMP_SPOTBLEND, lamp->ob, ma), inpr, visifac, &visifac); } @@ -825,8 +996,9 @@ static void shade_light_textures(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink ** GPUNodeLink *tex_rgb; GPU_link(mat, "shade_light_texture", - GPU_builtin(GPU_VIEW_POSITION), - GPU_image(mtex->tex->ima, &mtex->tex->iuser, false), + GPU_material_builtin(mat, GPU_VIEW_POSITION), + GPU_image(mtex->tex->ima, &mtex->tex->iuser, false), GPU_uniform(mtex->size), + GPU_select_uniform(&mtex->lodbias, GPU_DYNAMIC_TEX_LODBIAS, NULL, mat->ma), GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), &tex_rgb); texture_rgb_blend(mat, tex_rgb, *rgb, GPU_uniform(&one), GPU_uniform(&mtex->colfac), mtex->blendtype, rgb); @@ -839,7 +1011,7 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la Material *ma = shi->mat; GPUMaterial *mat = shi->gpumat; GPUNodeLink *lv, *dist, *is, *inp, *i; - GPUNodeLink *outcol, *specfac, *t, *shadfac = NULL, *lcol; + GPUNodeLink *outcol, *specfac, *t, *shadfac = NULL, *lcol, *col, *energy; float one = 1.0f; if ((lamp->mode & LA_ONLYSHADOW) && !(ma->mode & MA_SHADOW)) @@ -855,6 +1027,13 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la GPU_link(mat, "shade_tangent_v", lv, GPU_attribute(CD_TANGENT, ""), &vn); #endif + GPU_link(mat, "lamp_visible", + GPU_dynamic_uniform(&lamp->dynlayer, GPU_DYNAMIC_LAMP_DYNVISI, lamp->ob), + GPU_material_builtin(mat, GPU_OBJECT_LAY), + GPU_dynamic_uniform(lamp->dyncol, GPU_DYNAMIC_LAMP_DYNCOL, lamp->ob), + GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob), + &col, &energy); + GPU_link(mat, "shade_inp", vn, lv, &inp); if (lamp->mode & LA_NO_DIFF) { @@ -869,7 +1048,7 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la mat->dynproperty |= DYN_LAMP_VEC | DYN_LAMP_CO; GPU_link(mat, "shade_inp_area", - GPU_builtin(GPU_VIEW_POSITION), + GPU_material_builtin(mat, GPU_VIEW_POSITION), GPU_dynamic_uniform(lamp->dynco, GPU_DYNAMIC_LAMP_DYNCO, lamp->ob), GPU_dynamic_uniform(lamp->dynvec, GPU_DYNAMIC_LAMP_DYNVEC, lamp->ob), vn, GPU_uniform((float *)area), @@ -902,10 +1081,9 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la i = is; GPU_link(mat, "shade_visifac", i, visifac, shi->refl, &i); - GPU_link(mat, "set_rgb", GPU_dynamic_uniform(lamp->dyncol, GPU_DYNAMIC_LAMP_DYNCOL, lamp->ob), &lcol); + GPU_link(mat, "set_rgb", col, &lcol); shade_light_textures(mat, lamp, &lcol); - GPU_link(mat, "shade_mul_value_v3", - GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob), lcol, &lcol); + GPU_link(mat, "shade_mul_value_v3", energy, lcol, &lcol); #if 0 if (ma->mode & MA_TANGENT_VN) @@ -920,25 +1098,58 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la mat->dynproperty |= DYN_LAMP_PERSMAT; if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) { - GPU_link(mat, "test_shadowbuf_vsm", - GPU_builtin(GPU_VIEW_POSITION), + GPU_link(mat, "shadow_vsm", + GPU_material_builtin(mat, GPU_VIEW_POSITION), GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob), GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), GPU_uniform(&lamp->bias), GPU_uniform(&lamp->la->bleedbias), inp, &shadfac); } else { - GPU_link(mat, "test_shadowbuf", - GPU_builtin(GPU_VIEW_POSITION), - GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob), - GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), - GPU_uniform(&lamp->bias), inp, &shadfac); + if (lamp->la->samp > 1 && lamp->la->soft >= 0.01f && lamp->la->shadow_filter != LA_SHADOW_FILTER_NONE) { + float samp = lamp->la->samp; + float samplesize = lamp->la->soft / lamp->la->shadow_frustum_size; + if (lamp->la->shadow_filter == LA_SHADOW_FILTER_PCF) { + GPU_link(mat, "shadow_pcf", + GPU_material_builtin(mat, GPU_VIEW_POSITION), + GPU_material_builtin(mat, GPU_VIEW_NORMAL), + GPU_dynamic_texture(lamp->depthtex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob), + GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), + GPU_uniform(&lamp->bias), GPU_uniform(&lamp->slopebias), + GPU_uniform(&samp), GPU_uniform(&samplesize), inp, &shadfac); + } + if (lamp->la->shadow_filter == LA_SHADOW_FILTER_PCF_JITTER) { + GPU_link(mat, "shadow_pcf_jitter", + GPU_material_builtin(mat, GPU_VIEW_POSITION), + GPU_material_builtin(mat, GPU_VIEW_NORMAL), + GPU_dynamic_texture(lamp->depthtex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob), + GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), + GPU_uniform(&lamp->bias), GPU_uniform(&lamp->slopebias), + GPU_dynamic_texture(GPU_texture_global_jitter_64(), GPU_DYNAMIC_SAMPLER_2DIMAGE, NULL), + GPU_uniform(&samp), GPU_uniform(&samplesize), inp, &shadfac); + } + else if (lamp->la->shadow_filter == LA_SHADOW_FILTER_PCF_BAIL) { + GPU_link(mat, "shadow_pcf_early_bail", + GPU_material_builtin(mat, GPU_VIEW_POSITION), + GPU_material_builtin(mat, GPU_VIEW_NORMAL), + GPU_dynamic_texture(lamp->depthtex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob), + GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), + GPU_uniform(&lamp->bias), GPU_uniform(&lamp->slopebias), + GPU_uniform(&samp), GPU_uniform(&samplesize), inp, &shadfac); + } + } + else { + GPU_link(mat, "shadow_simple", + GPU_material_builtin(mat, GPU_VIEW_POSITION), + GPU_material_builtin(mat, GPU_VIEW_NORMAL), + GPU_dynamic_texture(lamp->depthtex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob), + GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), + GPU_uniform(&lamp->bias), GPU_uniform(&lamp->slopebias), inp, &shadfac); + } } if (lamp->mode & LA_ONLYSHADOW) { GPUNodeLink *shadrgb; - GPU_link(mat, "shade_only_shadow", i, shadfac, - GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob), - GPU_uniform(lamp->shadow_color), &shadrgb); + GPU_link(mat, "shade_only_shadow", i, shadfac, energy, GPU_uniform(lamp->shadow_color), &shadrgb); if (!(lamp->mode & LA_NO_DIFF)) { GPU_link(mat, "shade_only_shadow_diffuse", shadrgb, shi->rgb, @@ -964,7 +1175,14 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la else GPU_link(mat, "set_value", GPU_uniform(&one), &shadfac); - if (GPU_link_changed(shi->refl) || ma->ref != 0.0f) { + if (ma->sss_flag && lamp->type != LA_SPOT) { + GPU_link(mat, "set_sss", energy, visifac, col, + GPU_uniform(&ma->sss_scale), GPU_uniform((float *)&ma->sss_radius), + shi->rgb, i, view, lv, vn, &shr->combined); + GPU_link(mat, "shade_add", shr->combined, shr->diff, &shr->diff); + } + + if (GPU_link_changed(shi->refl) || ma->ref != 0.0f || !(ma->constflag & MA_CONSTANT_MATERIAL)) { if (!(lamp->mode & LA_NO_DIFF)) { GPUNodeLink *rgb; GPU_link(mat, "shade_mul_value", i, lcol, &rgb); @@ -979,10 +1197,10 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la /* pass */ } else if (!(lamp->mode & LA_NO_SPEC) && !(lamp->mode & LA_ONLYSHADOW) && - (GPU_link_changed(shi->spec) || ma->spec != 0.0f)) + (GPU_link_changed(shi->spec) || ma->spec != 0.0f || !(ma->constflag & MA_CONSTANT_MATERIAL))) { if (lamp->type == LA_HEMI) { - GPU_link(mat, "shade_hemi_spec", vn, lv, view, GPU_uniform(&ma->spec), shi->har, visifac, &t); + GPU_link(mat, "shade_hemi_spec", vn, lv, view, GPU_select_uniform(&ma->spec, GPU_DYNAMIC_MAT_SPEC, NULL, ma), shi->har, visifac, &t); GPU_link(mat, "shade_add_spec", t, lcol, shi->specrgb, &outcol); GPU_link(mat, "shade_add_clamped", shr->spec, outcol, &shr->spec); } @@ -1173,13 +1391,16 @@ static void do_material_tex(GPUShadeInput *shi) GPUMaterial *mat = shi->gpumat; MTex *mtex; Tex *tex; - GPUNodeLink *texco, *tin, *trgb, *tnor, *tcol, *stencil, *tnorfac; + GPUNodeLink *texco, *tin, *trgb, *tnor, *tcol, *stencil, *tnorfac, *tangent; GPUNodeLink *texco_norm, *texco_orco, *texco_object; GPUNodeLink *texco_global, *texco_uv = NULL; GPUNodeLink *newnor, *orn; float one = 1.0f; + GPUNodeLink *parco = NULL; int rgbnor, talpha; bool init_done = false; + float discard; + int tex_nr; int iBumpSpacePrev = 0; /* Not necessary, quieting gcc warning. */ GPUNodeLink *vNorg, *vNacc, *fPrevMagnitude; int iFirstTimeNMap = 1; @@ -1187,26 +1408,78 @@ static void do_material_tex(GPUShadeInput *shi) GPU_link(mat, "set_value", GPU_uniform(&one), &stencil); - GPU_link(mat, "texco_norm", GPU_builtin(GPU_VIEW_NORMAL), &texco_norm); + GPU_link(mat, "texco_norm", GPU_material_builtin(mat, GPU_VIEW_NORMAL), &texco_norm); GPU_link(mat, "texco_orco", GPU_attribute(CD_ORCO, ""), &texco_orco); - GPU_link(mat, "texco_object", GPU_builtin(GPU_INVERSE_VIEW_MATRIX), - GPU_builtin(GPU_INVERSE_OBJECT_MATRIX), - GPU_builtin(GPU_VIEW_POSITION), &texco_object); + GPU_link(mat, "texco_object", GPU_material_builtin(mat, GPU_INVERSE_VIEW_MATRIX), + GPU_material_builtin(mat, GPU_INVERSE_OBJECT_MATRIX), + GPU_material_builtin(mat, GPU_VIEW_POSITION), &texco_object); #if 0 GPU_link(mat, "texco_tangent", GPU_attribute(CD_TANGENT, ""), &texco_tangent); #endif - GPU_link(mat, "texco_global", GPU_builtin(GPU_INVERSE_VIEW_MATRIX), - GPU_builtin(GPU_VIEW_POSITION), &texco_global); + GPU_link(mat, "texco_global", GPU_material_builtin(mat, GPU_INVERSE_VIEW_MATRIX), + GPU_material_builtin(mat, GPU_VIEW_POSITION), &texco_global); orn = texco_norm; + + /* find parallax texco (parco) */ + for (tex_nr = 0; tex_nr < MAX_MTEX; tex_nr++) { + /* separate tex switching */ + if (ma->septex & (1 << tex_nr)) continue; + if (ma->mtex[tex_nr]) { + mtex = ma->mtex[tex_nr]; + tex = mtex->tex; + + if (tex == NULL || !(mtex->mapto & MAP_PARALLAX)) { + continue; + } + + tangent = GPU_attribute(CD_TANGENT, ""); + if (!(ma->constflag & MA_CONSTANT_TEXTURE_UV) || (mtex->rot != 0.0f)) { + GPU_link(mat, "mtex_tangent_rotate", tangent, orn, + GPU_select_uniform(&mtex->rot, GPU_DYNAMIC_TEX_UVROTATION, NULL, ma), + &tangent); + } + + GPU_link(mat, "texco_uv", GPU_attribute(CD_MTFACE, mtex->uvname), &texco_uv); + texco = texco_uv; + + if (!(ma->constflag & MA_CONSTANT_TEXTURE_UV) || + ((mtex->size[0] != 1.0f || mtex->size[1] != 1.0f || mtex->size[2] != 1.0f) || + (mtex->ofs[0] == 0.0f || mtex->ofs[1] == 0.0f) || + (mtex->rot != 0.0f))) + { + GPU_link(mat, "mtex_mapping_transform", texco, + GPU_select_uniform(&mtex->rot, GPU_DYNAMIC_TEX_UVROTATION, NULL, ma), + GPU_select_uniform(mtex->ofs, GPU_DYNAMIC_TEX_UVOFFSET, NULL, ma), + GPU_select_uniform(mtex->size, GPU_DYNAMIC_TEX_UVSIZE, NULL, ma), + &texco); + } + + discard = (mtex->parflag & MTEX_DISCARD_AT_EDGES) != 0 ? 1.0f : 0.0f; + float comp = mtex->parallaxcomp; + GPU_link(mat, "mtex_parallax", texco, + GPU_material_builtin(mat, GPU_VIEW_POSITION), tangent, orn, + GPU_image(tex->ima, &tex->iuser, false), + GPU_select_uniform(&mtex->parallaxsteps, GPU_DYNAMIC_TEX_PARALLAXSTEP, NULL, ma), + GPU_select_uniform(&mtex->parallaxbumpsc, GPU_DYNAMIC_TEX_PARALLAXBUMP, NULL, ma), + GPU_select_uniform(mtex->size, GPU_DYNAMIC_TEX_UVSIZE, NULL, ma), + GPU_uniform(&discard), + GPU_uniform(&comp), + &parco); + + // only one parallax per material. + break; + } + } /* go over texture slots */ - for (int tex_nr = 0; tex_nr < MAX_MTEX; tex_nr++) { + for (tex_nr = 0; tex_nr < MAX_MTEX; tex_nr++) { /* separate tex switching */ if (ma->septex & (1 << tex_nr)) continue; if (ma->mtex[tex_nr]) { mtex = ma->mtex[tex_nr]; + bool use_parallax = (mtex->texflag & MTEX_PARALLAX_UV) || (mtex->mapto & MAP_PARALLAX); tex = mtex->tex; if (tex == NULL) continue; @@ -1235,22 +1508,26 @@ static void do_material_tex(GPUShadeInput *shi) } else continue; - + + /*if parallax has modified uv*/ + if (use_parallax && parco) { + texco = parco; + } /* in case of uv, this would just undo a multiplication in texco_uv */ if (mtex->texco != TEXCO_UV) GPU_link(mat, "mtex_2d_mapping", texco, &texco); - if (mtex->size[0] != 1.0f || mtex->size[1] != 1.0f || mtex->size[2] != 1.0f) - GPU_link(mat, "mtex_mapping_size", texco, GPU_uniform(mtex->size), &texco); - - float ofs[3] = { - mtex->ofs[0] + 0.5f - 0.5f * mtex->size[0], - mtex->ofs[1] + 0.5f - 0.5f * mtex->size[1], - 0.0f - }; - - if (ofs[0] != 0.0f || ofs[1] != 0.0f || ofs[2] != 0.0f) - GPU_link(mat, "mtex_mapping_ofs", texco, GPU_uniform(ofs), &texco); + if (!use_parallax && (!(ma->constflag & MA_CONSTANT_TEXTURE_UV) || + (mtex->size[0] != 1.0f || mtex->size[1] != 1.0f || mtex->size[2] != 1.0f) || + (mtex->ofs[0] == 0.0f || mtex->ofs[1] == 0.0f) || + (mtex->rot != 0.0f))) + { + GPU_link(mat, "mtex_mapping_transform", texco, + GPU_select_uniform(&mtex->rot, GPU_DYNAMIC_TEX_UVROTATION, NULL, ma), + GPU_select_uniform(mtex->ofs, GPU_DYNAMIC_TEX_UVOFFSET, NULL, ma), + GPU_select_uniform(mtex->size, GPU_DYNAMIC_TEX_UVSIZE, NULL, ma), + &texco); + } talpha = 0; @@ -1259,13 +1536,29 @@ static void do_material_tex(GPUShadeInput *shi) ((tex->type == TEX_ENVMAP) && (mtex->texco == TEXCO_REFL)))) { if (tex->type == TEX_IMAGE) { - GPU_link(mat, "mtex_image", texco, GPU_image(tex->ima, &tex->iuser, false), &tin, &trgb); + GPU_link(mat, "mtex_image", texco, GPU_image(tex->ima, &tex->iuser, false), + GPU_select_uniform(&mtex->lodbias, GPU_DYNAMIC_TEX_LODBIAS, NULL, ma), &tin, &trgb); } - else { - GPU_link(mat, "mtex_cube_map_refl", - GPU_cube_map(tex->ima, &tex->iuser, false), shi->view, shi->vn, - GPU_builtin(GPU_INVERSE_VIEW_MATRIX), - GPU_builtin(GPU_VIEW_MATRIX), &tin, &trgb); + else if (tex->type == TEX_ENVMAP) { + if (tex->env->type == ENV_PLANE) { + GPU_link(mat, "mtex_image_refl", + GPU_material_builtin(mat, GPU_VIEW_POSITION), + GPU_material_builtin(mat, GPU_CAMERA_TEXCO_FACTORS), + GPU_image(tex->ima, &tex->iuser, false), + GPU_select_uniform(&mtex->lodbias, GPU_DYNAMIC_TEX_LODBIAS, NULL, ma), + GPU_material_builtin(mat, GPU_OBJECT_MATRIX), + GPU_material_builtin(mat, GPU_VIEW_MATRIX), + shi->view, shi->vn, &tin, &trgb); + } + else if (tex->env->type == ENV_CUBE) { + GPU_link(mat, "mtex_cube_map_refl_refr", + GPU_cube_map(tex->ima, &tex->iuser, false), shi->view, shi->vn, + GPU_select_uniform(&mtex->lodbias, GPU_DYNAMIC_TEX_LODBIAS, NULL, ma), + GPU_material_builtin(mat, GPU_INVERSE_VIEW_MATRIX), + GPU_select_uniform(&mtex->ior, GPU_DYNAMIC_TEX_IOR, NULL, ma), + GPU_select_uniform(&mtex->refrratio, GPU_DYNAMIC_TEX_REFRRATIO, NULL, ma), + &tin, &trgb); + } } rgbnor = TEX_RGB; @@ -1312,19 +1605,15 @@ static void do_material_tex(GPUShadeInput *shi) GPU_link(mat, "set_value_one", &tin); } - if ((tex->type == TEX_IMAGE) || - ((tex->type == TEX_ENVMAP) && (mtex->texco == TEXCO_REFL))) - { - if (GPU_material_do_color_management(mat)) { - GPU_link(mat, "srgb_to_linearrgb", tcol, &tcol); - } + if (tex_do_color_management(mat, mtex, tex)) { + GPU_link(mat, "srgb_to_linearrgb", tcol, &tcol); } if (mtex->mapto & MAP_COL) { GPUNodeLink *colfac; - if (mtex->colfac == 1.0f) colfac = stencil; - else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->colfac), stencil, &colfac); + if (mtex->colfac == 1.0f && (ma->constflag & MA_CONSTANT_TEXTURE)) colfac = stencil; + else GPU_link(mat, "math_multiply", GPU_select_uniform(&mtex->colfac, GPU_DYNAMIC_TEX_COLFAC, NULL, ma), stencil, &colfac); texture_rgb_blend(mat, tcol, shi->rgb, tin, colfac, mtex->blendtype, &shi->rgb); } @@ -1332,8 +1621,8 @@ static void do_material_tex(GPUShadeInput *shi) if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && (mtex->mapto & MAP_COLSPEC)) { GPUNodeLink *colspecfac; - if (mtex->colspecfac == 1.0f) colspecfac = stencil; - else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->colspecfac), stencil, &colspecfac); + if (mtex->colspecfac == 1.0f && (ma->constflag & MA_CONSTANT_TEXTURE)) colspecfac = stencil; + else GPU_link(mat, "math_multiply", GPU_select_uniform(&mtex->colspecfac, GPU_DYNAMIC_TEX_SPECFAC, NULL, ma), stencil, &colspecfac); texture_rgb_blend(mat, tcol, shi->specrgb, tin, colspecfac, mtex->blendtype, &shi->specrgb); } @@ -1341,8 +1630,8 @@ static void do_material_tex(GPUShadeInput *shi) if (mtex->mapto & MAP_COLMIR) { GPUNodeLink *colmirfac; - if (mtex->mirrfac == 1.0f) colmirfac = stencil; - else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->mirrfac), stencil, &colmirfac); + if (mtex->mirrfac == 1.0f && (ma->constflag & MA_CONSTANT_TEXTURE)) colmirfac = stencil; + else GPU_link(mat, "math_multiply", GPU_select_uniform(&mtex->mirrfac, GPU_DYNAMIC_TEX_MIRROR, NULL, ma), stencil, &colmirfac); /* exception for envmap only */ if (tex->type == TEX_ENVMAP && mtex->blendtype == MTEX_BLEND) { @@ -1359,24 +1648,32 @@ static void do_material_tex(GPUShadeInput *shi) if (tex->imaflag & TEX_NORMALMAP) { /* normalmap image */ - GPU_link(mat, "mtex_normal", texco, GPU_image(tex->ima, &tex->iuser, true), &tnor); + GPU_link(mat, "mtex_normal", texco, GPU_image(tex->ima, &tex->iuser, true), + GPU_select_uniform(&mtex->lodbias, GPU_DYNAMIC_TEX_LODBIAS, NULL, ma), &tnor); if (mtex->norfac < 0.0f) GPU_link(mat, "mtex_negate_texnormal", tnor, &tnor); if (mtex->normapspace == MTEX_NSPACE_TANGENT) { + tangent = GPU_attribute(CD_TANGENT, ""); + if (!(ma->constflag & MA_CONSTANT_TEXTURE_UV) || (mtex->rot != 0.0f)) { + GPU_link(mat, "mtex_tangent_rotate", tangent, orn, + GPU_select_uniform(&mtex->rot, GPU_DYNAMIC_TEX_UVROTATION, NULL, ma), + &tangent); + } + if (iFirstTimeNMap != 0) { // use unnormalized normal (this is how we bake it - closer to gamedev) GPUNodeLink *vNegNorm; GPU_link(mat, "vec_math_negate", - GPU_builtin(GPU_VIEW_NORMAL), &vNegNorm); + GPU_material_builtin(mat, GPU_VIEW_NORMAL), &vNegNorm); GPU_link(mat, "mtex_nspace_tangent", - GPU_attribute(CD_TANGENT, ""), vNegNorm, tnor, &newnor); + tangent, vNegNorm, tnor, &newnor); iFirstTimeNMap = 0; } else { /* otherwise use accumulated perturbations */ GPU_link(mat, "mtex_nspace_tangent", - GPU_attribute(CD_TANGENT, ""), shi->vn, tnor, &newnor); + tangent, shi->vn, tnor, &newnor); } } else if (mtex->normapspace == MTEX_NSPACE_OBJECT) { @@ -1385,7 +1682,7 @@ static void do_material_tex(GPUShadeInput *shi) } else if (mtex->normapspace == MTEX_NSPACE_WORLD) { /* transform normal by view matrix */ - GPU_link(mat, "mtex_nspace_world", GPU_builtin(GPU_VIEW_MATRIX), tnor, &newnor); + GPU_link(mat, "mtex_nspace_world", GPU_material_builtin(mat, GPU_VIEW_MATRIX), tnor, &newnor); } else { /* no transform, normal in camera space */ @@ -1394,11 +1691,11 @@ static void do_material_tex(GPUShadeInput *shi) float norfac = min_ff(fabsf(mtex->norfac), 1.0f); - if (norfac == 1.0f && !GPU_link_changed(stencil)) { + if (norfac == 1.0f && !GPU_link_changed(stencil) && (ma->constflag & MA_CONSTANT_TEXTURE)) { shi->vn = newnor; } else { - tnorfac = GPU_uniform(&norfac); + tnorfac = GPU_select_uniform(&mtex->norfac, GPU_DYNAMIC_TEX_NORMAL, NULL, ma); if (GPU_link_changed(stencil)) GPU_link(mat, "math_multiply", tnorfac, stencil, &tnorfac); @@ -1451,7 +1748,7 @@ static void do_material_tex(GPUShadeInput *shi) tnorfac = GPU_uniform(&norfac); if (found_deriv_map) - GPU_link(mat, "math_multiply", tnorfac, GPU_builtin(GPU_AUTO_BUMPSCALE), &tnorfac); + GPU_link(mat, "math_multiply", tnorfac, GPU_material_builtin(mat, GPU_AUTO_BUMPSCALE), &tnorfac); if (GPU_link_changed(stencil)) GPU_link(mat, "math_multiply", tnorfac, stencil, &tnorfac); @@ -1473,15 +1770,15 @@ static void do_material_tex(GPUShadeInput *shi) /* re-initialize if bump space changed */ if (iBumpSpacePrev != iBumpSpace) { - GPUNodeLink *surf_pos = GPU_builtin(GPU_VIEW_POSITION); + GPUNodeLink *surf_pos = GPU_material_builtin(mat, GPU_VIEW_POSITION); if (mtex->texflag & MTEX_BUMP_OBJECTSPACE) GPU_link(mat, "mtex_bump_init_objspace", surf_pos, vNorg, - GPU_builtin(GPU_VIEW_MATRIX), - GPU_builtin(GPU_INVERSE_VIEW_MATRIX), - GPU_builtin(GPU_OBJECT_MATRIX), - GPU_builtin(GPU_INVERSE_OBJECT_MATRIX), + GPU_material_builtin(mat, GPU_VIEW_MATRIX), + GPU_material_builtin(mat, GPU_INVERSE_VIEW_MATRIX), + GPU_material_builtin(mat, GPU_OBJECT_MATRIX), + GPU_material_builtin(mat, GPU_INVERSE_OBJECT_MATRIX), fPrevMagnitude, vNacc, &fPrevMagnitude, &vNacc, &vR1, &vR2, &fDet); @@ -1508,25 +1805,30 @@ static void do_material_tex(GPUShadeInput *shi) GPU_link(mat, "mtex_bump_deriv", texco, GPU_image(tex->ima, &tex->iuser, true), GPU_uniform(&ima_x), GPU_uniform(&ima_y), tnorfac, + GPU_select_uniform(&mtex->lodbias, GPU_DYNAMIC_TEX_LODBIAS, NULL, ma), &dBs, &dBt); } else if (mtex->texflag & MTEX_3TAP_BUMP) GPU_link(mat, "mtex_bump_tap3", texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac, + GPU_select_uniform(&mtex->lodbias, GPU_DYNAMIC_TEX_LODBIAS, NULL, ma), &dBs, &dBt); else if (mtex->texflag & MTEX_5TAP_BUMP) GPU_link(mat, "mtex_bump_tap5", texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac, + GPU_select_uniform(&mtex->lodbias, GPU_DYNAMIC_TEX_LODBIAS, NULL, ma), &dBs, &dBt); else if (mtex->texflag & MTEX_BICUBIC_BUMP) { if (GPU_bicubic_bump_support()) { GPU_link(mat, "mtex_bump_bicubic", texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac, + GPU_select_uniform(&mtex->lodbias, GPU_DYNAMIC_TEX_LODBIAS, NULL, ma), &dBs, &dBt); } else { GPU_link(mat, "mtex_bump_tap5", texco, GPU_image(tex->ima, &tex->iuser, true), tnorfac, + GPU_select_uniform(&mtex->lodbias, GPU_DYNAMIC_TEX_LODBIAS, NULL, ma), &dBs, &dBt); } } @@ -1563,8 +1865,8 @@ static void do_material_tex(GPUShadeInput *shi) if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_REF) { GPUNodeLink *difffac; - if (mtex->difffac == 1.0f) difffac = stencil; - else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->difffac), stencil, &difffac); + if (mtex->difffac == 1.0f && (ma->constflag & MA_CONSTANT_TEXTURE)) difffac = stencil; + else GPU_link(mat, "math_multiply", GPU_select_uniform(&mtex->difffac, GPU_DYNAMIC_TEX_COLINTENS, NULL, ma), stencil, &difffac); texture_value_blend( mat, GPU_uniform(&mtex->def_var), shi->refl, tin, difffac, @@ -1574,8 +1876,8 @@ static void do_material_tex(GPUShadeInput *shi) if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_SPEC) { GPUNodeLink *specfac; - if (mtex->specfac == 1.0f) specfac = stencil; - else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->specfac), stencil, &specfac); + if (mtex->specfac == 1.0f && (ma->constflag & MA_CONSTANT_TEXTURE)) specfac = stencil; + else GPU_link(mat, "math_multiply", GPU_select_uniform(&mtex->specfac, GPU_DYNAMIC_TEX_SPECINTENS, NULL, ma), stencil, &specfac); texture_value_blend( mat, GPU_uniform(&mtex->def_var), shi->spec, tin, specfac, @@ -1585,8 +1887,8 @@ static void do_material_tex(GPUShadeInput *shi) if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_EMIT) { GPUNodeLink *emitfac; - if (mtex->emitfac == 1.0f) emitfac = stencil; - else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->emitfac), stencil, &emitfac); + if (mtex->emitfac == 1.0f && (ma->constflag & MA_CONSTANT_TEXTURE)) emitfac = stencil; + else GPU_link(mat, "math_multiply", GPU_select_uniform(&mtex->emitfac, GPU_DYNAMIC_TEX_EMIT, NULL, ma), stencil, &emitfac); texture_value_blend( mat, GPU_uniform(&mtex->def_var), shi->emit, tin, emitfac, @@ -1596,8 +1898,8 @@ static void do_material_tex(GPUShadeInput *shi) if (!(mat->scene->gm.flag & GAME_GLSL_NO_EXTRA_TEX) && mtex->mapto & MAP_HAR) { GPUNodeLink *hardfac; - if (mtex->hardfac == 1.0f) hardfac = stencil; - else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->hardfac), stencil, &hardfac); + if (mtex->hardfac == 1.0f && (ma->constflag & MA_CONSTANT_TEXTURE)) hardfac = stencil; + else GPU_link(mat, "math_multiply", GPU_select_uniform(&mtex->hardfac, GPU_DYNAMIC_TEX_HARDNESS, NULL, ma), stencil, &hardfac); GPU_link(mat, "mtex_har_divide", shi->har, &shi->har); texture_value_blend( @@ -1608,8 +1910,8 @@ static void do_material_tex(GPUShadeInput *shi) if (mtex->mapto & MAP_ALPHA) { GPUNodeLink *alphafac; - if (mtex->alphafac == 1.0f) alphafac = stencil; - else GPU_link(mat, "math_multiply", GPU_uniform(&mtex->alphafac), stencil, &alphafac); + if (mtex->alphafac == 1.0f && (ma->constflag & MA_CONSTANT_TEXTURE)) alphafac = stencil; + else GPU_link(mat, "math_multiply", GPU_select_uniform(&mtex->alphafac, GPU_DYNAMIC_TEX_ALPHA, NULL, ma), stencil, &alphafac); texture_value_blend( mat, GPU_uniform(&mtex->def_var), shi->alpha, tin, alphafac, @@ -1641,26 +1943,26 @@ void GPU_shadeinput_set(GPUMaterial *mat, Material *ma, GPUShadeInput *shi) shi->gpumat = mat; shi->mat = ma; - GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->r, GPU_DYNAMIC_MAT_DIFFRGB, ma), &shi->rgb); - GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->specr, GPU_DYNAMIC_MAT_SPECRGB, ma), &shi->specrgb); - GPU_link(mat, "set_rgb", GPU_dynamic_uniform(&ma->mirr, GPU_DYNAMIC_MAT_MIR, ma), &shi->mir); + GPU_link(mat, "set_rgb", GPU_select_uniform(&ma->r, GPU_DYNAMIC_MAT_DIFFRGB, ma, ma), &shi->rgb); + GPU_link(mat, "set_rgb", GPU_select_uniform(&ma->specr, GPU_DYNAMIC_MAT_SPECRGB, ma, ma), &shi->specrgb); + GPU_link(mat, "set_rgb", GPU_select_uniform(&ma->mirr, GPU_DYNAMIC_MAT_MIR, ma, ma), &shi->mir); GPU_link(mat, "set_rgba_zero", &shi->refcol); - GPU_link(mat, "shade_norm", GPU_builtin(GPU_VIEW_NORMAL), &shi->vn); + GPU_link(mat, "shade_norm", GPU_material_builtin(mat, GPU_VIEW_NORMAL), &shi->vn); if (mat->alpha) - GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->alpha, GPU_DYNAMIC_MAT_ALPHA, ma), &shi->alpha); + GPU_link(mat, "set_value", GPU_select_uniform(&ma->alpha, GPU_DYNAMIC_MAT_ALPHA, ma, ma), &shi->alpha); else GPU_link(mat, "set_value", GPU_uniform(&one), &shi->alpha); - GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->ref, GPU_DYNAMIC_MAT_REF, ma), &shi->refl); - GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->spec, GPU_DYNAMIC_MAT_SPEC, ma), &shi->spec); - GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->emit, GPU_DYNAMIC_MAT_EMIT, ma), &shi->emit); - GPU_link(mat, "set_value", GPU_dynamic_uniform((float *)&ma->har, GPU_DYNAMIC_MAT_HARD, ma), &shi->har); - GPU_link(mat, "set_value", GPU_dynamic_uniform(&ma->amb, GPU_DYNAMIC_MAT_AMB, ma), &shi->amb); - GPU_link(mat, "set_value", GPU_uniform(&ma->spectra), &shi->spectra); - GPU_link(mat, "shade_view", GPU_builtin(GPU_VIEW_POSITION), &shi->view); + GPU_link(mat, "set_value", GPU_select_uniform(&ma->ref, GPU_DYNAMIC_MAT_REF, ma, ma), &shi->refl); + GPU_link(mat, "set_value", GPU_select_uniform(&ma->spec, GPU_DYNAMIC_MAT_SPEC, ma, ma), &shi->spec); + GPU_link(mat, "set_value", GPU_select_uniform(&ma->emit, GPU_DYNAMIC_MAT_EMIT, ma, ma), &shi->emit); + GPU_link(mat, "set_value", GPU_select_uniform(&mat->har, GPU_DYNAMIC_MAT_HARD, ma, ma), &shi->har); + GPU_link(mat, "set_value", GPU_select_uniform(&ma->amb, GPU_DYNAMIC_MAT_AMB, ma, ma), &shi->amb); + GPU_link(mat, "set_value", GPU_select_uniform(&ma->spectra, GPU_DYNAMIC_MAT_SPECTRA, ma, ma), &shi->spectra); + GPU_link(mat, "shade_view", GPU_material_builtin(mat, GPU_VIEW_POSITION), &shi->view); GPU_link(mat, "vcol_attribute", GPU_attribute(CD_MCOL, ""), &shi->vcol); - if (GPU_material_do_color_management(mat)) + if (GPU_material_do_color_management(mat) && !(ma->sss_flag)) GPU_link(mat, "srgb_to_linearrgb", shi->vcol, &shi->vcol); GPU_link(mat, "texco_refl", shi->vn, shi->view, &shi->ref); } @@ -1670,7 +1972,7 @@ void GPU_mist_update_enable(short enable) GPUWorld.mistenabled = (float)enable; } -void GPU_mist_update_values(int type, float start, float dist, float inten, float color[3]) +void GPU_mist_update_values(int type, float start, float dist, float inten, const float color[3]) { GPUWorld.mistype = (float)type; GPUWorld.miststart = start; @@ -1680,30 +1982,41 @@ void GPU_mist_update_values(int type, float start, float dist, float inten, floa GPUWorld.mistcol[3] = 1.0f; } -void GPU_horizon_update_color(float color[3]) +void GPU_horizon_update_color(const float color[3]) { copy_v3_v3(GPUWorld.horicol, color); } -void GPU_ambient_update_color(float color[3]) +void GPU_ambient_update_color(const float color[3]) { copy_v3_v3(GPUWorld.ambcol, color); GPUWorld.ambcol[3] = 1.0f; } -void GPU_zenith_update_color(float color[3]) +void GPU_zenith_update_color(const float color[3]) { copy_v3_v3(GPUWorld.zencol, color); } +void GPU_update_exposure_range(float exp, float range) +{ + GPUWorld.linfac = 1.0f + powf((2.0f * exp + 0.5f), -10.0f); + GPUWorld.logfac = log((GPUWorld.linfac - 1.0f) / GPUWorld.linfac) / range; +} + +void GPU_update_envlight_energy(float energy) +{ + GPUWorld.envlightenergy = energy; +} + void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr) { GPUMaterial *mat = shi->gpumat; - GPUNodeLink *emit, *ulinfac, *ulogfac, *mistfac; + GPUNodeLink *emit, *mistfac; Material *ma = shi->mat; World *world = mat->scene->world; - float linfac, logfac; + mat->dynproperty |= DYN_LAMP_CO; memset(shr, 0, sizeof(*shr)); if (ma->mode & MA_VERTEXCOLP) @@ -1718,7 +2031,7 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr) shr->combined = shr->diff; } else { - if (GPU_link_changed(shi->emit) || ma->emit != 0.0f) { + if (GPU_link_changed(shi->emit) || ma->emit != 0.0f || !(ma->constflag & MA_CONSTANT_MATERIAL)) { if ((ma->mode & (MA_VERTEXCOL | MA_VERTEXCOLP)) == MA_VERTEXCOL) { GPU_link(mat, "shade_add", shi->emit, shi->vcol, &emit); GPU_link(mat, "shade_mul", emit, shi->rgb, &shr->diff); @@ -1739,17 +2052,15 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr) if (world) { /* exposure correction */ - if (world->exp != 0.0f || world->range != 1.0f) { - linfac = 1.0f + powf((2.0f * world->exp + 0.5f), -10); - logfac = logf((linfac - 1.0f) / linfac) / world->range; - - GPU_link(mat, "set_value", GPU_uniform(&linfac), &ulinfac); - GPU_link(mat, "set_value", GPU_uniform(&logfac), &ulogfac); - + if (world->exp != 0.0f || world->range != 1.0f || !(ma->constflag & MA_CONSTANT_WORLD)) { GPU_link(mat, "shade_exposure_correct", shr->combined, - ulinfac, ulogfac, &shr->combined); + GPU_select_uniform(&GPUWorld.linfac, GPU_DYNAMIC_WORLD_LINFAC, NULL, ma), + GPU_select_uniform(&GPUWorld.logfac, GPU_DYNAMIC_WORLD_LOGFAC, NULL, ma), + &shr->combined); GPU_link(mat, "shade_exposure_correct", shr->spec, - ulinfac, ulogfac, &shr->spec); + GPU_select_uniform(&GPUWorld.linfac, GPU_DYNAMIC_WORLD_LINFAC, NULL, ma), + GPU_select_uniform(&GPUWorld.logfac, GPU_DYNAMIC_WORLD_LOGFAC, NULL, ma), + &shr->spec); } /* environment lighting */ @@ -1758,40 +2069,54 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr) (mat->scene->r.mode & R_SHADOW) && !BKE_scene_use_new_shading_nodes(mat->scene)) { - if ((world->ao_env_energy != 0.0f) && (GPU_link_changed(shi->amb) || ma->amb != 0.0f) && - (GPU_link_changed(shi->refl) || ma->ref != 0.0f)) + if (((world->ao_env_energy != 0.0f) && (GPU_link_changed(shi->amb) || ma->amb != 0.0f) && + (GPU_link_changed(shi->refl) || ma->ref != 0.0f)) || !(ma->constflag & MA_CONSTANT_WORLD)) { - if (world->aocolor != WO_AOPLAIN) { - if (!(is_zero_v3(&world->horr) & is_zero_v3(&world->zenr))) { + if (world->aocolor == WO_AOSKYCOL) { + if (!(is_zero_v3(&world->horr) & is_zero_v3(&world->zenr)) || !(ma->constflag & MA_CONSTANT_WORLD)) { GPUNodeLink *fcol, *f; GPU_link(mat, "math_multiply", shi->amb, shi->refl, &f); - GPU_link(mat, "math_multiply", f, GPU_uniform(&world->ao_env_energy), &f); + GPU_link(mat, "math_multiply", f, GPU_select_uniform(&GPUWorld.envlightenergy, GPU_DYNAMIC_ENVLIGHT_ENERGY, NULL, ma), &f); GPU_link(mat, "shade_mul_value", f, shi->rgb, &fcol); GPU_link(mat, "env_apply", shr->combined, - GPU_dynamic_uniform(GPUWorld.horicol, GPU_DYNAMIC_HORIZON_COLOR, NULL), - GPU_dynamic_uniform(GPUWorld.zencol, GPU_DYNAMIC_ZENITH_COLOR, NULL), fcol, - GPU_builtin(GPU_VIEW_MATRIX), shi->vn, &shr->combined); + GPU_select_uniform(GPUWorld.horicol, GPU_DYNAMIC_HORIZON_COLOR, NULL, ma), + GPU_select_uniform(GPUWorld.zencol, GPU_DYNAMIC_ZENITH_COLOR, NULL, ma), fcol, + GPU_material_builtin(mat, GPU_VIEW_MATRIX), shi->vn, &shr->combined); + } + } + else if (world->aocolor == WO_AOSKYTEX) { + if (world->mtex[0] && world->mtex[0]->tex && world->mtex[0]->tex->ima) { + GPUNodeLink *fcol, *f; + Tex* tex = world->mtex[0]->tex; + GPU_link(mat, "math_multiply", shi->amb, shi->refl, &f); + GPU_link(mat, "math_multiply", f, GPU_select_uniform(&GPUWorld.envlightenergy, GPU_DYNAMIC_ENVLIGHT_ENERGY, NULL, ma), &f); + GPU_link(mat, "shade_mul_value", f, shi->rgb, &fcol); + GPU_link(mat, "env_apply_tex", shr->combined, fcol, + GPU_cube_map(tex->ima, &tex->iuser, false), + GPU_material_builtin(mat, GPU_VIEW_NORMAL), + GPU_material_builtin(mat, GPU_INVERSE_VIEW_MATRIX), + &shr->combined); } } else { GPUNodeLink *f; GPU_link(mat, "math_multiply", shi->amb, shi->refl, &f); - GPU_link(mat, "math_multiply", f, GPU_uniform(&world->ao_env_energy), &f); + GPU_link(mat, "math_multiply", f, GPU_select_uniform(&GPUWorld.envlightenergy, GPU_DYNAMIC_ENVLIGHT_ENERGY, NULL, ma), &f); GPU_link(mat, "shade_maddf", shr->combined, f, shi->rgb, &shr->combined); } } } /* ambient color */ - if (GPU_link_changed(shi->amb) || ma->amb != 0.0f) { - GPU_link(mat, "shade_maddf", shr->combined, GPU_uniform(&ma->amb), - GPU_dynamic_uniform(GPUWorld.ambcol, GPU_DYNAMIC_AMBIENT_COLOR, NULL), + if (GPU_link_changed(shi->amb) || ma->amb != 0.0f || !(ma->constflag & MA_CONSTANT_MATERIAL)) { + GPU_link(mat, "shade_maddf", shr->combined, GPU_select_uniform(&ma->amb, GPU_DYNAMIC_MAT_AMB, NULL, ma), + GPU_select_uniform(GPUWorld.ambcol, GPU_DYNAMIC_AMBIENT_COLOR, NULL, ma), &shr->combined); } } if (ma->mode & MA_TRANSP && (ma->mode & (MA_ZTRANSP | MA_RAYTRANSP))) { - if (GPU_link_changed(shi->spectra) || ma->spectra != 0.0f) { + if (GPU_link_changed(shi->spectra) || ma->spectra != 0.0f || !(ma->constflag & MA_CONSTANT_MATERIAL)) { GPU_link(mat, "alpha_spec_correction", shr->spec, shi->spectra, shi->alpha, &shr->alpha); } @@ -1803,30 +2128,38 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr) if (GPU_link_changed(shi->refcol)) GPU_link(mat, "shade_add_mirror", shi->mir, shi->refcol, shr->combined, &shr->combined); - if (GPU_link_changed(shi->spec) || ma->spec != 0.0f) + if (GPU_link_changed(shi->spec) || ma->spec != 0.0f || !(ma->constflag & MA_CONSTANT_MATERIAL)) GPU_link(mat, "shade_add", shr->combined, shr->spec, &shr->combined); } + if (ma->mode & MA_TRANSP && ma->mode2 & MA_DEPTH_TRANSP) { + GPU_link(mat, "shade_alpha_depth", + GPU_material_builtin(mat, GPU_VIEW_POSITION), + GPU_dynamic_texture_ptr(GPU_texture_global_depth_ptr(), GPU_DYNAMIC_SAMPLER_2DBUFFER, ma), + shr->alpha, GPU_uniform(&ma->depthtranspfactor), &shr->alpha); + } + GPU_link(mat, "mtex_alpha_to_col", shr->combined, shr->alpha, &shr->combined); - if (ma->shade_flag & MA_OBCOLOR) - GPU_link(mat, "shade_obcolor", shr->combined, GPU_builtin(GPU_OBCOLOR), &shr->combined); + if (ma->shade_flag & MA_OBCOLOR) { + GPU_link(mat, "shade_obcolor", shr->combined, GPU_material_builtin(mat, GPU_OBCOLOR), &shr->combined); + } if (!(ma->mode & MA_NOMIST)) { - GPU_link(mat, "shade_mist_factor", GPU_builtin(GPU_VIEW_POSITION), + GPU_link(mat, "shade_mist_factor", GPU_material_builtin(mat, GPU_VIEW_POSITION), GPU_dynamic_uniform(&GPUWorld.mistenabled, GPU_DYNAMIC_MIST_ENABLE, NULL), - GPU_dynamic_uniform(&GPUWorld.miststart, GPU_DYNAMIC_MIST_START, NULL), - GPU_dynamic_uniform(&GPUWorld.mistdistance, GPU_DYNAMIC_MIST_DISTANCE, NULL), - GPU_dynamic_uniform(&GPUWorld.mistype, GPU_DYNAMIC_MIST_TYPE, NULL), - GPU_dynamic_uniform(&GPUWorld.mistintensity, GPU_DYNAMIC_MIST_INTENSITY, NULL), &mistfac); + GPU_select_uniform(&GPUWorld.miststart, GPU_DYNAMIC_MIST_START, NULL, ma), + GPU_select_uniform(&GPUWorld.mistdistance, GPU_DYNAMIC_MIST_DISTANCE, NULL, ma), + GPU_select_uniform(&GPUWorld.mistype, GPU_DYNAMIC_MIST_TYPE, NULL, ma), + GPU_select_uniform(&GPUWorld.mistintensity, GPU_DYNAMIC_MIST_INTENSITY, NULL, ma), &mistfac); GPU_link(mat, "mix_blend", mistfac, shr->combined, - GPU_dynamic_uniform(GPUWorld.mistcol, GPU_DYNAMIC_MIST_COLOR, NULL), &shr->combined); + GPU_select_uniform(GPUWorld.mistcol, GPU_DYNAMIC_MIST_COLOR, NULL, ma), &shr->combined); } if (!mat->alpha) { - if (world && (GPU_link_changed(shr->alpha) || ma->alpha != 1.0f)) - GPU_link(mat, "shade_world_mix", GPU_dynamic_uniform(GPUWorld.horicol, GPU_DYNAMIC_HORIZON_COLOR, NULL), + if (world && (GPU_link_changed(shr->alpha) || ma->alpha != 1.0f || !(ma->constflag & MA_CONSTANT_WORLD))) + GPU_link(mat, "shade_world_mix", GPU_select_uniform(GPUWorld.horicol, GPU_DYNAMIC_HORIZON_COLOR, NULL, ma), shr->combined, &shr->combined); GPU_link(mat, "shade_alpha_opaque", shr->combined, &shr->combined); @@ -1834,7 +2167,7 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr) if (ma->shade_flag & MA_OBCOLOR) { mat->obcolalpha = 1; - GPU_link(mat, "shade_alpha_obcolor", shr->combined, GPU_builtin(GPU_OBCOLOR), &shr->combined); + GPU_link(mat, "shade_alpha_obcolor", shr->combined, GPU_material_builtin(mat, GPU_OBCOLOR), &shr->combined); } } @@ -1855,7 +2188,7 @@ static GPUNodeLink *gpu_material_diffuse_bsdf(GPUMaterial *mat, Material *ma) GPUNodeLink *outlink; GPU_link(mat, "node_bsdf_diffuse", - GPU_uniform(&ma->r), GPU_uniform(&roughness), GPU_builtin(GPU_VIEW_NORMAL), &outlink); + GPU_uniform(&ma->r), GPU_uniform(&roughness), GPU_material_builtin(mat, GPU_VIEW_NORMAL), &outlink); return outlink; } @@ -1875,7 +2208,7 @@ static GPUNodeLink *gpu_material_preview_matcap(GPUMaterial *mat, Material *ma) } /* new solid draw mode with glsl matcaps */ -GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma, bool use_opensubdiv) +GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma, GPUMaterialFlag flags) { GPUMaterial *mat; GPUNodeLink *outlink; @@ -1884,7 +2217,7 @@ GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma, bool use_opensubdiv for (link = ma->gpumaterial.first; link; link = link->next) { GPUMaterial *current_material = (GPUMaterial *)link->data; if (current_material->scene == scene && - current_material->is_opensubdiv == use_opensubdiv) + current_material->flags == flags) { return current_material; } @@ -1894,7 +2227,7 @@ GPUMaterial *GPU_material_matcap(Scene *scene, Material *ma, bool use_opensubdiv mat = GPU_material_construct_begin(ma); mat->scene = scene; mat->type = GPU_MATERIAL_TYPE_MESH; - mat->is_opensubdiv = use_opensubdiv; + mat->flags = flags; if (ma->preview && ma->preview->rect[0]) { outlink = gpu_material_preview_matcap(mat, ma); @@ -1938,15 +2271,15 @@ static void do_world_tex(GPUShadeInput *shi, struct World *wo, GPUNodeLink **hor /* which coords */ if (mtex->texco == TEXCO_VIEW || mtex->texco == TEXCO_GLOB) { if (tex->type == TEX_IMAGE) - texco = GPU_builtin(GPU_VIEW_POSITION); + texco = GPU_material_builtin(mat, GPU_VIEW_POSITION); else if (tex->type == TEX_ENVMAP) - GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &texco); + GPU_link(mat, "background_transform_to_world", GPU_material_builtin(mat, GPU_VIEW_POSITION), &texco); } else if (mtex->texco == TEXCO_EQUIRECTMAP || mtex->texco == TEXCO_ANGMAP) { if ((tex->type == TEX_IMAGE && wo->skytype & WO_SKYREAL) || tex->type == TEX_ENVMAP) - GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &texco); + GPU_link(mat, "background_transform_to_world", GPU_material_builtin(mat, GPU_VIEW_POSITION), &texco); else - texco = GPU_builtin(GPU_VIEW_POSITION); + texco = GPU_material_builtin(mat, GPU_VIEW_POSITION); } else continue; @@ -1974,21 +2307,21 @@ static void do_world_tex(GPUShadeInput *shi, struct World *wo, GPUNodeLink **hor if (ofs[0] != 0.0f || ofs[1] != 0.0f || ofs[2] != 0.0f) GPU_link(mat, "mtex_mapping_ofs", texco, GPU_uniform(ofs), &texco); if (mtex->texco == TEXCO_EQUIRECTMAP) { - GPU_link(mat, "node_tex_environment_equirectangular", texco, GPU_image(tex->ima, &tex->iuser, false), &trgb); + GPU_link(mat, "node_tex_environment_equirectangular", texco, GPU_image(tex->ima, &tex->iuser, false), GPU_uniform(&mtex->lodbias), &trgb); } else if (mtex->texco == TEXCO_ANGMAP) { - GPU_link(mat, "node_tex_environment_mirror_ball", texco, GPU_image(tex->ima, &tex->iuser, false), &trgb); + GPU_link(mat, "node_tex_environment_mirror_ball", texco, GPU_image(tex->ima, &tex->iuser, false), GPU_uniform(&mtex->lodbias), &trgb); } else { if (tex->type == TEX_ENVMAP) - GPU_link(mat, "mtex_cube_map", texco, GPU_cube_map(tex->ima, &tex->iuser, false), &tin, &trgb); + GPU_link(mat, "mtex_cube_map", texco, GPU_cube_map(tex->ima, &tex->iuser, false), GPU_uniform(&mtex->lodbias), &tin, &trgb); else if (tex->type == TEX_IMAGE) - GPU_link(mat, "mtex_image", texco, GPU_image(tex->ima, &tex->iuser, false), &tin, &trgb); + GPU_link(mat, "mtex_image", texco, GPU_image(tex->ima, &tex->iuser, false), GPU_uniform(&mtex->lodbias), &tin, &trgb); } rgbnor = TEX_RGB; - if (tex->type == TEX_IMAGE || tex->type == TEX_ENVMAP) - if (GPU_material_do_color_management(mat)) - GPU_link(mat, "srgb_to_linearrgb", trgb, &trgb); + if (tex_do_color_management(mat, mtex, tex)) { + GPU_link(mat, "srgb_to_linearrgb", trgb, &trgb); + } /* texture output */ if ((rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) { GPU_link(mat, "mtex_rgbtoint", trgb, &tin); @@ -2077,17 +2410,17 @@ static void gpu_material_old_world(struct GPUMaterial *mat, struct World *wo) } else { GPU_link(mat, "set_rgb_zero", &shi.rgb); - GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &ray); + GPU_link(mat, "background_transform_to_world", GPU_material_builtin(mat, GPU_VIEW_POSITION), &ray); if (wo->skytype & WO_SKYPAPER) - GPU_link(mat, "world_paper_view", GPU_builtin(GPU_VIEW_POSITION), &shi.view); + GPU_link(mat, "world_paper_view", GPU_material_builtin(mat, GPU_VIEW_POSITION), &shi.view); else GPU_link(mat, "shade_view", ray, &shi.view); if (wo->skytype & WO_SKYBLEND) { if (wo->skytype & WO_SKYPAPER) { if (wo->skytype & WO_SKYREAL) - GPU_link(mat, "world_blend_paper_real", GPU_builtin(GPU_VIEW_POSITION), &blend); + GPU_link(mat, "world_blend_paper_real", GPU_material_builtin(mat, GPU_VIEW_POSITION), &blend); else - GPU_link(mat, "world_blend_paper", GPU_builtin(GPU_VIEW_POSITION), &blend); + GPU_link(mat, "world_blend_paper", GPU_material_builtin(mat, GPU_VIEW_POSITION), &blend); } else { if (wo->skytype & WO_SKYREAL) @@ -2111,19 +2444,25 @@ static void gpu_material_old_world(struct GPUMaterial *mat, struct World *wo) GPU_material_output_link(mat, shr.combined); } -GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo) +GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo, GPUMaterialFlag flags) { LinkData *link; GPUMaterial *mat; - for (link = wo->gpumaterial.first; link; link = link->next) - if (((GPUMaterial *)link->data)->scene == scene) + for (link = wo->gpumaterial.first; link; link = link->next) { + GPUMaterial *current_material = (GPUMaterial *)link->data; + if (current_material->scene == scene && + current_material->flags == flags) + { return link->data; + } + } /* allocate material */ mat = GPU_material_construct_begin(NULL); mat->scene = scene; mat->type = GPU_MATERIAL_TYPE_WORLD; + mat->flags = flags; /* create nodes */ if (BKE_scene_use_new_shading_nodes(scene) && wo->nodetree && wo->use_nodes) { @@ -2133,7 +2472,7 @@ GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo) gpu_material_old_world(mat, wo); } - if (GPU_material_do_color_management(mat)) + if (GPU_material_do_color_management(mat) && !(mat->flags & GPU_MATERIAL_NO_COLOR_MANAGEMENT)) if (mat->outlink) GPU_link(mat, "linearrgb_to_srgb", mat->outlink, &mat->outlink); @@ -2151,16 +2490,24 @@ GPUMaterial *GPU_material_world(struct Scene *scene, struct World *wo) } -GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_opensubdiv) +GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, GPUMaterialFlag flags) { GPUMaterial *mat; GPUNodeLink *outlink; LinkData *link; + ListBase *gpumaterials; - for (link = ma->gpumaterial.first; link; link = link->next) { + if (flags & GPU_MATERIAL_INSTANCING) { + gpumaterials = &ma->gpumaterialinstancing; + } + else { + gpumaterials = &ma->gpumaterial; + } + + for (link = gpumaterials->first; link; link = link->next) { GPUMaterial *current_material = (GPUMaterial *)link->data; if (current_material->scene == scene && - current_material->is_opensubdiv == use_opensubdiv) + current_material->flags == flags) { return current_material; } @@ -2170,7 +2517,8 @@ GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_open mat = GPU_material_construct_begin(ma); mat->scene = scene; mat->type = GPU_MATERIAL_TYPE_MESH; - mat->is_opensubdiv = use_opensubdiv; + mat->flags = flags; + mat->har = ma->har; /* render pipeline option */ bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene); @@ -2199,7 +2547,7 @@ GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_open GPU_material_output_link(mat, outlink); } - if (GPU_material_do_color_management(mat)) + if (GPU_material_do_color_management(mat) && !(ma->sss_flag) && !(mat->flags & GPU_MATERIAL_NO_COLOR_MANAGEMENT)) if (mat->outlink) GPU_link(mat, "linearrgb_to_srgb", mat->outlink, &mat->outlink); @@ -2211,7 +2559,7 @@ GPUMaterial *GPU_material_from_blender(Scene *scene, Material *ma, bool use_open link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink"); link->data = mat; - BLI_addtail(&ma->gpumaterial, link); + BLI_addtail(gpumaterials, link); return mat; } @@ -2223,13 +2571,16 @@ void GPU_materials_free(Main *bmain) World *wo; extern Material defmaterial; - for (ma = bmain->mat.first; ma; ma = ma->id.next) + for (ma = bmain->mat.first; ma; ma = ma->id.next) { GPU_material_free(&ma->gpumaterial); + GPU_material_free(&ma->gpumaterialinstancing); + } for (wo = bmain->world.first; wo; wo = wo->id.next) GPU_material_free(&wo->gpumaterial); GPU_material_free(&defmaterial.gpumaterial); + GPU_material_free(&defmaterial.gpumaterialinstancing); for (ob = bmain->object.first; ob; ob = ob->id.next) GPU_lamp_free(ob); @@ -2349,9 +2700,12 @@ static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *l lamp->coeff_lin = la->coeff_lin; lamp->coeff_quad = la->coeff_quad; lamp->curfalloff = la->curfalloff; + lamp->cutoff = la->cutoff; + lamp->radius = la->radius; /* initshadowbuf */ lamp->bias = 0.02f * la->bias; + lamp->slopebias = la->slopebias; lamp->size = la->bufsize; lamp->d = la->clipsta; lamp->clipend = la->clipend; @@ -2418,7 +2772,7 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) { /* Shadow depth map */ - lamp->depthtex = GPU_texture_create_depth(lamp->size, lamp->size, NULL); + lamp->depthtex = GPU_texture_create_depth(lamp->size, lamp->size, true, NULL); if (!lamp->depthtex) { gpu_lamp_shadow_free(lamp); return lamp; @@ -2475,13 +2829,13 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) GPU_framebuffer_texture_unbind(lamp->blurfb, lamp->blurtex); } else { - lamp->tex = GPU_texture_create_depth(lamp->size, lamp->size, NULL); - if (!lamp->tex) { + lamp->depthtex = GPU_texture_create_depth(lamp->size, lamp->size, true, NULL); + if (!lamp->depthtex) { gpu_lamp_shadow_free(lamp); return lamp; } - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, NULL)) { + if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->depthtex, 0, NULL)) { gpu_lamp_shadow_free(lamp); return lamp; } @@ -2524,6 +2878,8 @@ void GPU_lamp_free(Object *ob) if (ma->gpumaterial.first) GPU_material_free(&ma->gpumaterial); + if (ma->gpumaterialinstancing.first) + GPU_material_free(&ma->gpumaterialinstancing); } gpu_lamp_shadow_free(lamp); @@ -2538,7 +2894,7 @@ bool GPU_lamp_has_shadow_buffer(GPULamp *lamp) { return (!(lamp->scene->gm.flag & GAME_GLSL_NO_SHADOWS) && !(lamp->scene->gm.flag & GAME_GLSL_NO_LIGHTS) && - lamp->tex && lamp->fb); + lamp->depthtex && lamp->fb); } void GPU_lamp_update_buffer_mats(GPULamp *lamp) @@ -2572,9 +2928,12 @@ void GPU_lamp_shadow_buffer_bind(GPULamp *lamp, float viewmat[4][4], int *winsiz /* opengl */ glDisable(GL_SCISSOR_TEST); - GPU_texture_bind_as_framebuffer(lamp->tex); - if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) - GPU_shader_bind(GPU_shader_get_builtin_shader(GPU_SHADER_VSM_STORE)); + if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) { + GPU_texture_bind_as_framebuffer(lamp->tex); + } + else { + GPU_texture_bind_as_framebuffer(lamp->depthtex); + } /* set matrices */ copy_m4_m4(viewmat, lamp->viewmat); @@ -2586,7 +2945,7 @@ void GPU_lamp_shadow_buffer_unbind(GPULamp *lamp) { if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) { GPU_shader_unbind(); - GPU_framebuffer_blur(lamp->fb, lamp->tex, lamp->blurfb, lamp->blurtex); + GPU_framebuffer_blur(lamp->fb, lamp->tex, lamp->blurfb, lamp->blurtex, lamp->la->bufsharp); } GPU_framebuffer_texture_unbind(lamp->fb, lamp->tex); @@ -2601,17 +2960,33 @@ int GPU_lamp_shadow_buffer_type(GPULamp *lamp) int GPU_lamp_shadow_bind_code(GPULamp *lamp) { - return lamp->tex ? GPU_texture_opengl_bindcode(lamp->tex) : -1; + if (lamp->tex) { + return GPU_texture_opengl_bindcode(lamp->tex); + } + else if (lamp->depthtex) { + return GPU_texture_opengl_bindcode(lamp->depthtex); + } + return -1; } -float *GPU_lamp_dynpersmat(GPULamp *lamp) +const float *GPU_lamp_dynpersmat(GPULamp *lamp) { return &lamp->dynpersmat[0][0]; } +const float *GPU_lamp_get_viewmat(GPULamp *lamp) +{ + return &lamp->viewmat[0][0]; +} + +const float *GPU_lamp_get_winmat(GPULamp *lamp) +{ + return &lamp->winmat[0][0]; +} + int GPU_lamp_shadow_layer(GPULamp *lamp) { - if (lamp->fb && lamp->tex && (lamp->mode & (LA_LAYER | LA_LAYER_SHADOW))) + if (lamp->fb && lamp->depthtex && (lamp->mode & (LA_LAYER | LA_LAYER_SHADOW))) return lamp->lay; else return -1; @@ -2622,9 +2997,15 @@ GPUNodeLink *GPU_lamp_get_data( GPUNodeLink **r_col, GPUNodeLink **r_lv, GPUNodeLink **r_dist, GPUNodeLink **r_shadow, GPUNodeLink **r_energy) { GPUNodeLink *visifac; + GPUNodeLink *shadowfac; + + GPU_link(mat, "lamp_visible", + GPU_dynamic_uniform(&lamp->dynlayer, GPU_DYNAMIC_LAMP_DYNVISI, lamp->ob), + GPU_material_builtin(mat, GPU_OBJECT_LAY), + GPU_dynamic_uniform(lamp->dyncol, GPU_DYNAMIC_LAMP_DYNCOL, lamp->ob), + GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob), + r_col, r_energy); - *r_col = GPU_dynamic_uniform(lamp->dyncol, GPU_DYNAMIC_LAMP_DYNCOL, lamp->ob); - *r_energy = GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob); visifac = lamp_get_visibility(mat, lamp, r_lv, r_dist); shade_light_textures(mat, lamp, r_col); @@ -2632,25 +3013,61 @@ GPUNodeLink *GPU_lamp_get_data( if (GPU_lamp_has_shadow_buffer(lamp)) { GPUNodeLink *vn, *inp; - GPU_link(mat, "shade_norm", GPU_builtin(GPU_VIEW_NORMAL), &vn); + GPU_link(mat, "shade_norm", GPU_material_builtin(mat, GPU_VIEW_NORMAL), &vn); GPU_link(mat, "shade_inp", vn, *r_lv, &inp); mat->dynproperty |= DYN_LAMP_PERSMAT; if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) { - GPU_link(mat, "shadows_only_vsm", - GPU_builtin(GPU_VIEW_POSITION), + GPU_link(mat, "shadow_vsm", + GPU_material_builtin(mat, GPU_VIEW_POSITION), GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob), GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), - GPU_uniform(&lamp->bias), GPU_uniform(&lamp->la->bleedbias), - GPU_uniform(lamp->shadow_color), inp, r_shadow); + GPU_uniform(&lamp->bias), GPU_uniform(&lamp->la->bleedbias), inp, &shadowfac); } else { - GPU_link(mat, "shadows_only", - GPU_builtin(GPU_VIEW_POSITION), - GPU_dynamic_texture(lamp->tex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob), - GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), - GPU_uniform(&lamp->bias), GPU_uniform(lamp->shadow_color), inp, r_shadow); + if (lamp->la->samp > 1 && lamp->la->soft >= 0.01f && lamp->la->shadow_filter != LA_SHADOW_FILTER_NONE) { + float samp = lamp->la->samp; + float samplesize = lamp->la->soft / lamp->la->shadow_frustum_size; + if (lamp->la->shadow_filter == LA_SHADOW_FILTER_PCF) { + GPU_link(mat, "shadow_pcf", + GPU_material_builtin(mat, GPU_VIEW_POSITION), + GPU_material_builtin(mat, GPU_VIEW_NORMAL), + GPU_dynamic_texture(lamp->depthtex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob), + GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), + GPU_uniform(&lamp->bias), GPU_uniform(&lamp->slopebias), + GPU_uniform(&samp), GPU_uniform(&samplesize), inp, &shadowfac); + } + if (lamp->la->shadow_filter == LA_SHADOW_FILTER_PCF_JITTER) { + GPU_link(mat, "shadow_pcf_jitter", + GPU_material_builtin(mat, GPU_VIEW_POSITION), + GPU_material_builtin(mat, GPU_VIEW_NORMAL), + GPU_dynamic_texture(lamp->depthtex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob), + GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), + GPU_uniform(&lamp->bias), GPU_uniform(&lamp->slopebias), + GPU_dynamic_texture(GPU_texture_global_jitter_64(), GPU_DYNAMIC_SAMPLER_2DIMAGE, NULL), + GPU_uniform(&samp), GPU_uniform(&samplesize), inp, &shadowfac); + } + else if (lamp->la->shadow_filter == LA_SHADOW_FILTER_PCF_BAIL) { + GPU_link(mat, "shadow_pcf_early_bail", + GPU_material_builtin(mat, GPU_VIEW_POSITION), + GPU_material_builtin(mat, GPU_VIEW_NORMAL), + GPU_dynamic_texture(lamp->depthtex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob), + GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), + GPU_uniform(&lamp->bias), GPU_uniform(&lamp->slopebias), + GPU_uniform(&samp), GPU_uniform(&samplesize), inp, &shadowfac); + } + } + else { + GPU_link(mat, "shadow_simple", + GPU_material_builtin(mat, GPU_VIEW_POSITION), + GPU_material_builtin(mat, GPU_VIEW_NORMAL), + GPU_dynamic_texture(lamp->depthtex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob), + GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob), + GPU_uniform(&lamp->bias), GPU_uniform(&lamp->slopebias), inp, &shadowfac); + } } + + GPU_link(mat, "shadows_only", inp, shadowfac, GPU_uniform(lamp->shadow_color), r_shadow); } else { GPU_link(mat, "set_rgb_one", r_shadow); @@ -2680,6 +3097,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma) { GPU_INVERSE_LOC_TO_VIEW_MATRIX, GPU_DYNAMIC_OBJECT_LOCTOVIEWIMAT, GPU_DATA_16F }, { GPU_OBCOLOR, GPU_DYNAMIC_OBJECT_COLOR, GPU_DATA_4F }, { GPU_AUTO_BUMPSCALE, GPU_DYNAMIC_OBJECT_AUTOBUMPSCALE, GPU_DATA_1F }, + { GPU_TIME, GPU_DYNAMIC_TIME, GPU_DATA_1F }, { 0 } }; @@ -2688,7 +3106,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma) int liblen, fraglen; /* TODO(sergey): How to determine whether we need OSD or not here? */ - GPUMaterial *mat = GPU_material_from_blender(scene, ma, false); + GPUMaterial *mat = GPU_material_from_blender(scene, ma, 0); GPUPass *pass = (mat) ? mat->pass : NULL; if (pass && pass->fragmentcode && pass->vertexcode) { @@ -2735,6 +3153,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma) case GPU_VEC4: case GPU_MAT3: case GPU_MAT4: + case GPU_INT: case GPU_ATTRIB: break; } @@ -2763,6 +3182,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma) break; case GPU_NONE: + case GPU_INT: case GPU_TEX2D: case GPU_TEXCUBE: case GPU_SHADOW2D: diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 66945b13abad..e59721b7ff7e 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -42,13 +42,24 @@ #include "GPU_shader.h" #include "GPU_texture.h" #include "GPU_material.h" +#include "gpu_codegen.h" /* TODO(sergey): Find better default values for this constants. */ #define MAX_DEFINE_LENGTH 1024 #define MAX_EXT_DEFINE_LENGTH 1024 /* Non-generated shaders */ +extern char datatoc_gpu_shader_2d_box_vert_glsl[]; +extern char datatoc_gpu_shader_black_frag_glsl[]; +extern char datatoc_gpu_shader_black_vert_glsl[]; extern char datatoc_gpu_shader_fire_frag_glsl[]; +extern char datatoc_gpu_shader_flat_color_frag_glsl[]; +extern char datatoc_gpu_shader_flat_color_vert_glsl[]; +extern char datatoc_gpu_shader_frame_buffer_frag_glsl[]; +extern char datatoc_gpu_shader_frame_buffer_vert_glsl[]; +extern char datatoc_gpu_shader_frustum_line_vert_glsl[]; +extern char datatoc_gpu_shader_frustum_solid_vert_glsl[]; +extern char datatoc_gpu_shader_frustum_solid_frag_glsl[]; extern char datatoc_gpu_shader_smoke_vert_glsl[]; extern char datatoc_gpu_shader_smoke_frag_glsl[]; extern char datatoc_gpu_shader_vsm_store_vert_glsl[]; @@ -64,14 +75,25 @@ extern char datatoc_gpu_shader_fx_dof_hq_vert_glsl[]; extern char datatoc_gpu_shader_fx_dof_hq_geo_glsl[]; extern char datatoc_gpu_shader_fx_depth_resolve_glsl[]; extern char datatoc_gpu_shader_fx_lib_glsl[]; +extern char datatoc_gpu_shader_lib_glsl[]; static struct GPUShadersGlobal { struct { GPUShader *vsm_store; + GPUShader *vsm_store_instancing; GPUShader *sep_gaussian_blur; GPUShader *smoke; GPUShader *smoke_fire; GPUShader *smoke_coba; + GPUShader *black; + GPUShader *black_instancing; + GPUShader *draw_frame_buffer[2]; + GPUShader *stereo_stipple[2]; + GPUShader *stereo_anaglyph[2]; + GPUShader *frustum_line; + GPUShader *frustum_solid; + GPUShader *flat_color; + GPUShader *box2d; /* cache for shader fx. Those can exist in combinations so store them here */ GPUShader *fx_shaders[MAX_FX_SHADERS * 2]; } shaders; @@ -122,6 +144,29 @@ static void shader_print_errors(const char *task, const char *log, const char ** static const char *gpu_shader_version(void) { + if (GLEW_ARB_compatibility) { + if (GLEW_VERSION_4_5) { + return "#version 450 compatibility\n"; + } + else if (GLEW_VERSION_4_4) { + return "#version 440 compatibility\n"; + } + else if (GLEW_VERSION_4_3) { + return "#version 430 compatibility\n"; + } + else if (GLEW_VERSION_4_2) { + return "#version 420 compatibility\n"; + } + else if (GLEW_VERSION_4_1) { + return "#version 410 compatibility\n"; + } + else if (GLEW_VERSION_4_0) { + return "#version 400 compatibility\n"; + } + else if (GLEW_VERSION_3_3) { + return "#version 330 compatibility\n"; + } + } if (GLEW_VERSION_3_2) { if (GLEW_ARB_compatibility) { return "#version 150 compatibility\n"; @@ -191,6 +236,7 @@ static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH], static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH], bool use_opensubdiv, + bool use_instancing, bool use_new_shading) { /* some useful defines to detect GPU type */ @@ -234,6 +280,10 @@ static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH], UNUSED_VARS(use_opensubdiv); #endif + if (use_instancing) { + strcat(defines, "#define USE_INSTANCING\n"); + } + if (use_new_shading) { strcat(defines, "#define USE_NEW_SHADING\n"); } @@ -328,6 +378,7 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, UNUSED_VARS(flags); bool use_opensubdiv = false; #endif + bool use_instancing = (flags & GPU_SHADER_FLAGS_SPECIAL_INSTANCING) != 0; GLint status; GLchar log[5000]; GLsizei length = 0; @@ -362,17 +413,19 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, gpu_shader_standard_defines(standard_defines, use_opensubdiv, + use_instancing, (flags & GPU_SHADER_FLAGS_NEW_SHADING) != 0); gpu_shader_standard_extensions(standard_extensions, geocode != NULL); if (vertexcode) { - const char *source[5]; + const char *source[6]; /* custom limit, may be too small, beware */ int num_source = 0; source[num_source++] = gpu_shader_version(); source[num_source++] = standard_extensions; source[num_source++] = standard_defines; + source[num_source++] = datatoc_gpu_shader_lib_glsl; if (defines) source[num_source++] = defines; source[num_source++] = vertexcode; @@ -395,12 +448,13 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, } if (fragcode) { - const char *source[7]; + const char *source[8]; int num_source = 0; source[num_source++] = gpu_shader_version(); source[num_source++] = standard_extensions; source[num_source++] = standard_defines; + source[num_source++] = datatoc_gpu_shader_lib_glsl; #ifdef WITH_OPENSUBDIV /* TODO(sergey): Move to fragment shader source code generation. */ @@ -442,6 +496,7 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, source[num_source++] = gpu_shader_version(); source[num_source++] = standard_extensions; source[num_source++] = standard_defines; + source[num_source++] = datatoc_gpu_shader_lib_glsl; if (defines) source[num_source++] = defines; source[num_source++] = geocode; @@ -508,6 +563,23 @@ GPUShader *GPU_shader_create_ex(const char *vertexcode, return shader; } +char *GPU_shader_validate(GPUShader *shader) +{ + int stat = 0; + glValidateProgram(shader->program); + glGetObjectParameterivARB(shader->program, GL_OBJECT_VALIDATE_STATUS_ARB, (GLint *)&stat); + + if (stat > 0) { + int charlen = 0; + char *log = (char *)MEM_mallocN(stat, "GPU_shader_validate"); + + glGetInfoLogARB(shader->program, stat, (GLsizei *)&charlen, log); + + return log; + } + return NULL; +} + #undef DEBUG_SHADER_GEOMETRY #undef DEBUG_SHADER_FRAGMENT #undef DEBUG_SHADER_VERTEX @@ -527,6 +599,11 @@ void GPU_shader_unbind(void) GPU_ASSERT_NO_GL_ERRORS("Post Shader Unbind"); } +int GPU_shader_program(GPUShader *shader) +{ + return shader->program; +} + void GPU_shader_free(GPUShader *shader) { if (shader->vertex) @@ -544,6 +621,26 @@ void GPU_shader_free(GPUShader *shader) MEM_freeN(shader); } +int GPU_shader_get_uniform_infos(GPUShader *shader, GPUUniformInfo **infos) +{ + int count; + glGetProgramiv(shader->program, GL_ACTIVE_UNIFORMS, &count); + + if (count == 0) { + *infos = NULL; + return 0; + } + + *infos = MEM_callocN(sizeof(GPUUniformInfo) * count, "GPUUniformInfo"); + + for (unsigned int i = 0; i < count; ++i) { + GPUUniformInfo *info = &((*infos)[i]); + glGetActiveUniform(shader->program, i, 255, NULL, (int *)&info->size, &info->type, info->name); + } + + return count; +} + int GPU_shader_get_uniform(GPUShader *shader, const char *name) { return glGetUniformLocation(shader->program, name); @@ -599,6 +696,14 @@ void GPU_shader_uniform_int(GPUShader *UNUSED(shader), int location, int value) GPU_CHECK_ERRORS_AROUND(glUniform1i(location, value)); } +void GPU_shader_uniform_float(GPUShader *UNUSED(shader), int location, float value) +{ + if (location == -1) + return; + + GPU_CHECK_ERRORS_AROUND(glUniform1f(location, value)); +} + void GPU_shader_geometry_stage_primitive_io(GPUShader *shader, int input, int output, int number) { if (GPU_geometry_shader_support_via_extension()) { @@ -652,6 +757,41 @@ int GPU_shader_get_attribute(GPUShader *shader, const char *name) return index; } +void GPU_shader_bind_attribute(GPUShader *shader, int location, const char *name) +{ + GPU_CHECK_ERRORS_AROUND(glBindAttribLocation(shader->program, location, name)); +} + +// Used only for VSM shader with geometry instancing support. +void GPU_shader_bind_instancing_attrib(GPUShader *shader, void *matrixoffset, void *positionoffset) +{ + const int posloc = GPU_shader_get_attribute(shader, GPU_builtin_name(GPU_INSTANCING_POSITION_ATTRIB)); + const int matloc = GPU_shader_get_attribute(shader, GPU_builtin_name(GPU_INSTANCING_MATRIX_ATTRIB)); + + // Matrix + if (matloc != -1) { + glEnableVertexAttribArray(matloc); + glEnableVertexAttribArray(matloc + 1); + glEnableVertexAttribArray(matloc + 2); + + const unsigned short stride = sizeof(float) * 9; + glVertexAttribPointer(matloc, 3, GL_FLOAT, GL_FALSE, stride, matrixoffset); + glVertexAttribPointer(matloc + 1, 3, GL_FLOAT, GL_FALSE, stride, ((char *)matrixoffset) + 3 * sizeof(float)); + glVertexAttribPointer(matloc + 2, 3, GL_FLOAT, GL_FALSE, stride, ((char *)matrixoffset) + 6 * sizeof(float)); + + glVertexAttribDivisorARB(matloc, 1); + glVertexAttribDivisorARB(matloc + 1, 1); + glVertexAttribDivisorARB(matloc + 2, 1); + } + + // Position + if (posloc != -1) { + glEnableVertexAttribArray(posloc); + glVertexAttribPointer(posloc, 3, GL_FLOAT, GL_FALSE, 0, positionoffset); + glVertexAttribDivisorARB(posloc, 1); + } +} + GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) { GPUShader *retval = NULL; @@ -664,6 +804,13 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) NULL, NULL, NULL, 0, 0, 0); retval = GG.shaders.vsm_store; break; + case GPU_SHADER_VSM_STORE_INSTANCING: + if (!GG.shaders.vsm_store_instancing) + GG.shaders.vsm_store_instancing = GPU_shader_create( + datatoc_gpu_shader_vsm_store_vert_glsl, datatoc_gpu_shader_vsm_store_frag_glsl, + NULL, NULL, "#define USE_INSTANCING;\n", 0, 0, 0); + retval = GG.shaders.vsm_store_instancing; + break; case GPU_SHADER_SEP_GAUSSIAN_BLUR: if (!GG.shaders.sep_gaussian_blur) GG.shaders.sep_gaussian_blur = GPU_shader_create( @@ -693,6 +840,90 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) NULL, NULL, "#define USE_COBA;\n", 0, 0, 0); retval = GG.shaders.smoke_coba; break; + case GPU_SHADER_BLACK: + if (!GG.shaders.black) + GG.shaders.black = GPU_shader_create( + datatoc_gpu_shader_black_vert_glsl, datatoc_gpu_shader_black_frag_glsl, + NULL, NULL, NULL, 0, 0, 0); + retval = GG.shaders.black; + break; + case GPU_SHADER_BLACK_INSTANCING: + if (!GG.shaders.black_instancing) + GG.shaders.black_instancing = GPU_shader_create( + datatoc_gpu_shader_black_vert_glsl, datatoc_gpu_shader_black_frag_glsl, + NULL, NULL, "#define USE_INSTANCING;\n", 0, 0, 0); + retval = GG.shaders.black_instancing; + break; + case GPU_SHADER_DRAW_FRAME_BUFFER: + if (!GG.shaders.draw_frame_buffer[0]) + GG.shaders.draw_frame_buffer[0] = GPU_shader_create( + datatoc_gpu_shader_frame_buffer_vert_glsl, datatoc_gpu_shader_frame_buffer_frag_glsl, + NULL, NULL, NULL, 0, 0, 0); + retval = GG.shaders.draw_frame_buffer[0]; + break; + case GPU_SHADER_DRAW_FRAME_BUFFER_SRGB: + if (!GG.shaders.draw_frame_buffer[1]) + GG.shaders.draw_frame_buffer[1] = GPU_shader_create( + datatoc_gpu_shader_frame_buffer_vert_glsl, datatoc_gpu_shader_frame_buffer_frag_glsl, + NULL, NULL, "#define COLOR_MANAGEMENT;\n", 0, 0, 0); + retval = GG.shaders.draw_frame_buffer[1]; + break; + case GPU_SHADER_STEREO_STIPPLE: + if (!GG.shaders.stereo_stipple[0]) + GG.shaders.stereo_stipple[0] = GPU_shader_create( + datatoc_gpu_shader_frame_buffer_vert_glsl, datatoc_gpu_shader_frame_buffer_frag_glsl, + NULL, NULL, "#define STIPPLE;\n", 0, 0, 0); + retval = GG.shaders.stereo_stipple[0]; + break; + case GPU_SHADER_STEREO_STIPPLE_SRGB: + if (!GG.shaders.stereo_stipple[1]) + GG.shaders.stereo_stipple[1] = GPU_shader_create( + datatoc_gpu_shader_frame_buffer_vert_glsl, datatoc_gpu_shader_frame_buffer_frag_glsl, + NULL, NULL, "#define COLOR_MANAGEMENT;\n #define STIPPLE;\n", 0, 0, 0); + retval = GG.shaders.stereo_stipple[1]; + break; + case GPU_SHADER_STEREO_ANAGLYPH: + if (!GG.shaders.stereo_anaglyph[0]) + GG.shaders.stereo_anaglyph[0] = GPU_shader_create( + datatoc_gpu_shader_frame_buffer_vert_glsl, datatoc_gpu_shader_frame_buffer_frag_glsl, + NULL, NULL, "#define ANAGLYPH;\n", 0, 0, 0); + retval = GG.shaders.stereo_anaglyph[0]; + break; + case GPU_SHADER_STEREO_ANAGLYPH_SRGB: + if (!GG.shaders.stereo_anaglyph[1]) + GG.shaders.stereo_anaglyph[1] = GPU_shader_create( + datatoc_gpu_shader_frame_buffer_vert_glsl, datatoc_gpu_shader_frame_buffer_frag_glsl, + NULL, NULL, "#define COLOR_MANAGEMENT;\n #define ANAGLYPH;\n", 0, 0, 0); + retval = GG.shaders.stereo_anaglyph[1]; + break; + case GPU_SHADER_FRUSTUM_LINE: + if (!GG.shaders.frustum_line) + GG.shaders.frustum_line = GPU_shader_create( + datatoc_gpu_shader_frustum_line_vert_glsl, datatoc_gpu_shader_flat_color_frag_glsl, + NULL, NULL, NULL, 0, 0, 0); + retval = GG.shaders.frustum_line; + break; + case GPU_SHADER_FRUSTUM_SOLID: + if (!GG.shaders.frustum_solid) + GG.shaders.frustum_solid = GPU_shader_create( + datatoc_gpu_shader_frustum_solid_vert_glsl, datatoc_gpu_shader_frustum_solid_frag_glsl, + NULL, NULL, NULL, 0, 0, 0); + retval = GG.shaders.frustum_solid; + break; + case GPU_SHADER_FLAT_COLOR: + if (!GG.shaders.flat_color) + GG.shaders.flat_color = GPU_shader_create( + datatoc_gpu_shader_flat_color_vert_glsl, datatoc_gpu_shader_flat_color_frag_glsl, + NULL, NULL, NULL, 0, 0, 0); + retval = GG.shaders.flat_color; + break; + case GPU_SHADER_2D_BOX: + if (!GG.shaders.box2d) + GG.shaders.box2d = GPU_shader_create( + datatoc_gpu_shader_2d_box_vert_glsl, datatoc_gpu_shader_flat_color_frag_glsl, + NULL, NULL, NULL, 0, 0, 0); + retval = GG.shaders.box2d; + break; } if (retval == NULL) @@ -809,6 +1040,53 @@ void GPU_shader_free_builtin_shaders(void) GG.shaders.smoke_coba = NULL; } + if (GG.shaders.black) { + GPU_shader_free(GG.shaders.black); + GG.shaders.black = NULL; + } + + if (GG.shaders.black_instancing) { + GPU_shader_free(GG.shaders.black_instancing); + GG.shaders.black_instancing = NULL; + } + + for (unsigned short i = 0; i < 2; ++i) { + if (GG.shaders.draw_frame_buffer[i]) { + GPU_shader_free(GG.shaders.draw_frame_buffer[i]); + GG.shaders.draw_frame_buffer[i] = NULL; + } + + if (GG.shaders.stereo_stipple[i]) { + GPU_shader_free(GG.shaders.stereo_stipple[i]); + GG.shaders.stereo_stipple[i] = NULL; + } + + if (GG.shaders.stereo_anaglyph[i]) { + GPU_shader_free(GG.shaders.stereo_anaglyph[i]); + GG.shaders.stereo_anaglyph[i] = NULL; + } + } + + if (GG.shaders.frustum_line) { + GPU_shader_free(GG.shaders.frustum_line); + GG.shaders.frustum_line = NULL; + } + + if (GG.shaders.frustum_solid) { + GPU_shader_free(GG.shaders.frustum_solid); + GG.shaders.frustum_solid = NULL; + } + + if (GG.shaders.flat_color) { + GPU_shader_free(GG.shaders.flat_color); + GG.shaders.flat_color = NULL; + } + + if (GG.shaders.box2d) { + GPU_shader_free(GG.shaders.box2d); + GG.shaders.box2d = NULL; + } + for (i = 0; i < 2 * MAX_FX_SHADERS; ++i) { if (GG.shaders.fx_shaders[i]) { GPU_shader_free(GG.shaders.fx_shaders[i]); diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index c201254ffaeb..7cf0f07566ed 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -32,6 +32,9 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_math_base.h" +#include "BLI_math_vector.h" +#include "BLI_rand.h" +#include "BLI_alloca.h" #include "BKE_global.h" @@ -46,7 +49,9 @@ static struct GPUTextureGlobal { GPUTexture *invalid_tex_1D; /* texture used in place of invalid textures (not loaded correctly, missing) */ GPUTexture *invalid_tex_2D; GPUTexture *invalid_tex_3D; -} GG = {NULL, NULL, NULL}; + GPUTexture *jitter_64_tex; + GPUTexture *depth_tex; +} GG = {NULL, NULL, NULL, NULL}; /* GPUTexture */ @@ -92,7 +97,7 @@ static void gpu_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, i } static GPUTexture *GPU_texture_create_nD( - int w, int h, int n, const float *fpixels, int depth, + int w, int h, int n, const float *fpixels, int mode, GPUHDRType hdr_type, int components, int samples, char err_out[256]) { @@ -110,7 +115,7 @@ static GPUTexture *GPU_texture_create_nD( tex->refcount = 1; tex->target = (n == 1) ? GL_TEXTURE_1D : (samples ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D); tex->target_base = (n == 1) ? GL_TEXTURE_1D : GL_TEXTURE_2D; - tex->depth = depth; + tex->depth = (mode & GPU_TEXTURE_DEPTH); tex->fb_attachment = -1; glGenTextures(1, &tex->bindcode); @@ -136,7 +141,7 @@ static GPUTexture *GPU_texture_create_nD( tex->number = 0; glBindTexture(tex->target, tex->bindcode); - if (depth) { + if (tex->depth) { type = GL_UNSIGNED_BYTE; format = GL_DEPTH_COMPONENT; internalformat = GL_DEPTH_COMPONENT; @@ -148,7 +153,7 @@ static GPUTexture *GPU_texture_create_nD( format = GL_RGBA; switch (hdr_type) { case GPU_HDR_NONE: - internalformat = GL_RGBA8; + internalformat = GL_RGBA12; break; /* the following formats rely on ARB_texture_float or OpenGL 3.0 */ case GPU_HDR_HALF_FLOAT: @@ -222,11 +227,13 @@ static GPUTexture *GPU_texture_create_nD( if (pixels) MEM_freeN(pixels); - if (depth) { + if (tex->depth) { glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); - glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + if (mode & GPU_TEXTURE_DEPTH_COMPARE) { + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + } glTexParameteri(tex->target_base, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); } else { @@ -244,7 +251,6 @@ static GPUTexture *GPU_texture_create_nD( return tex; } - GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels) { GLenum type, format, internalformat; @@ -477,7 +483,7 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) GPUTexture *GPU_texture_create_1D(int w, const float *fpixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, GPU_HDR_NONE, 4, 0, err_out); + GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, GPU_TEXTURE_MODE_NONE, GPU_HDR_NONE, 4, 0, err_out); if (tex) GPU_texture_unbind(tex); @@ -487,7 +493,7 @@ GPUTexture *GPU_texture_create_1D(int w, const float *fpixels, char err_out[256] GPUTexture *GPU_texture_create_2D(int w, int h, const float *fpixels, GPUHDRType hdr, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, 0, err_out); + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, GPU_TEXTURE_MODE_NONE, hdr, 4, 0, err_out); if (tex) GPU_texture_unbind(tex); @@ -497,7 +503,7 @@ GPUTexture *GPU_texture_create_2D(int w, int h, const float *fpixels, GPUHDRType GPUTexture *GPU_texture_create_2D_multisample( int w, int h, const float *fpixels, GPUHDRType hdr, int samples, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, samples, err_out); + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, GPU_TEXTURE_MODE_NONE, hdr, 4, samples, err_out); if (tex) GPU_texture_unbind(tex); @@ -505,18 +511,20 @@ GPUTexture *GPU_texture_create_2D_multisample( return tex; } -GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]) +GPUTexture *GPU_texture_create_depth(int w, int h, bool compare, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, 0, err_out); + const int mode = GPU_TEXTURE_DEPTH | (compare ? GPU_TEXTURE_DEPTH_COMPARE : 0); + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, mode, GPU_HDR_NONE, 1, 0, err_out); if (tex) GPU_texture_unbind(tex); return tex; } -GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]) +GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, bool compare, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, samples, err_out); + const int mode = GPU_TEXTURE_DEPTH | (compare ? GPU_TEXTURE_DEPTH_COMPARE : 0); + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, mode, GPU_HDR_NONE, 1, samples, err_out); if (tex) GPU_texture_unbind(tex); @@ -529,7 +537,7 @@ GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char */ GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, GPU_HDR_FULL_FLOAT, 2, 0, err_out); + GPUTexture *tex = GPU_texture_create_nD(size, size, 2, NULL, GPU_TEXTURE_MODE_NONE, GPU_HDR_FULL_FLOAT, 2, 0, err_out); if (tex) { /* Now we tweak some of the settings */ @@ -542,9 +550,9 @@ GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]) return tex; } -GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]) +GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, bool filter, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out); + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, GPU_TEXTURE_MODE_NONE, GPU_HDR_HALF_FLOAT, 2, 0, err_out); if (tex) { /* Now we tweak some of the settings */ @@ -552,8 +560,10 @@ GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + if (!filter) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } GPU_texture_unbind(tex); } @@ -563,7 +573,7 @@ GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]) { - GPUTexture *tex = GPU_texture_create_nD(w, 0, 1, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out); + GPUTexture *tex = GPU_texture_create_nD(w, 0, 1, pixels, GPU_TEXTURE_MODE_NONE, GPU_HDR_HALF_FLOAT, 2, 0, err_out); if (tex) { /* Now we tweak some of the settings */ @@ -577,12 +587,48 @@ GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char er return tex; } +GPUTexture *GPU_texture_create_jitter(int w) +{ + float *jitter = BLI_array_alloca(jitter, w * w * 2); + int i; + + for (i = 0; i < (w * w); i++) { + jitter[i * 2] = 2.0f * BLI_frand() - 1.0f; + jitter[i * 2 + 1] = 2.0f * BLI_frand() - 1.0f; + normalize_v2(&jitter[i * 2]); + } + + return GPU_texture_create_2D_procedural(w, w, jitter, true, true, NULL); +} + +GPUTexture *GPU_texture_global_jitter_64(void) +{ + return GG.jitter_64_tex; +} + +GPUTexture **GPU_texture_global_depth_ptr(void) +{ + return &GG.depth_tex; +} + +void GPU_texture_set_global_depth(GPUTexture *depthtex) +{ + if (depthtex) { + GG.depth_tex = depthtex; + } + else { + GG.depth_tex = GG.invalid_tex_2D; + } +} + void GPU_invalid_tex_init(void) { const float color[4] = {1.0f, 0.0f, 1.0f, 1.0f}; GG.invalid_tex_1D = GPU_texture_create_1D(1, color, NULL); GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, GPU_HDR_NONE, NULL); GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, 4, color); + GG.jitter_64_tex = GPU_texture_create_jitter(64); + GG.depth_tex = GG.invalid_tex_2D; } void GPU_invalid_tex_bind(int mode) @@ -608,6 +654,9 @@ void GPU_invalid_tex_free(void) GPU_texture_free(GG.invalid_tex_2D); if (GG.invalid_tex_3D) GPU_texture_free(GG.invalid_tex_3D); + if (GG.jitter_64_tex) { + GPU_texture_free(GG.jitter_64_tex); + } } @@ -672,7 +721,7 @@ int GPU_texture_bound_number(GPUTexture *tex) return tex->number; } -void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter) +void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter, bool mipmap) { if (tex->number >= GPU_max_textures()) { fprintf(stderr, "Not enough texture slots.\n"); @@ -687,26 +736,59 @@ void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter) GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number); if (tex->number != 0) glActiveTexture(arbnumber); + int target = tex->target; if (tex->depth) { if (compare) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + glTexParameteri(target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); else - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); + glTexParameteri(target, GL_TEXTURE_COMPARE_MODE, GL_NONE); } if (use_filter) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + if (mipmap) { + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + } + else { + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } if (tex->number != 0) glActiveTexture(GL_TEXTURE0); GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind"); } +void GPU_texture_generate_mipmap(GPUTexture *tex) +{ + if (tex->number >= GPU_max_textures()) { + fprintf(stderr, "Not enough texture slots.\n"); + return; + } + + if (tex->number == -1) { + return; + } + + GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind"); + + GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number); + if (tex->number != 0) { + glActiveTexture(arbnumber); + } + + glGenerateMipmap(tex->target); + + if (tex->number != 0) { + glActiveTexture(GL_TEXTURE0); + } + + GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind"); +} + void GPU_texture_free(GPUTexture *tex) { tex->refcount--; @@ -729,6 +811,11 @@ void GPU_texture_ref(GPUTexture *tex) tex->refcount++; } +int GPU_texture_ref_count(GPUTexture *tex) +{ + return tex->refcount; +} + int GPU_texture_target(const GPUTexture *tex) { return tex->target; @@ -754,6 +841,11 @@ int GPU_texture_opengl_bindcode(const GPUTexture *tex) return tex->bindcode; } +void GPU_texture_set_opengl_bindcode(GPUTexture *tex, int bindcode) +{ + tex->bindcode = bindcode; +} + GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex) { return tex->fb; diff --git a/source/blender/gpu/shaders/gpu_shader_2d_box_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2d_box_vert.glsl new file mode 100644 index 000000000000..6480f25aa982 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_2d_box_vert.glsl @@ -0,0 +1,11 @@ +in vec2 pos; +in vec4 trans; +in vec4 color; + +flat out vec4 finalColor; + +void main() +{ + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(pos * trans.zw + trans.xy, 0.0, 1.0); + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_black_frag.glsl b/source/blender/gpu/shaders/gpu_shader_black_frag.glsl new file mode 100644 index 000000000000..da5c89f3a192 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_black_frag.glsl @@ -0,0 +1,4 @@ +void main() +{ + gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); +} diff --git a/source/blender/gpu/shaders/gpu_shader_black_vert.glsl b/source/blender/gpu/shaders/gpu_shader_black_vert.glsl new file mode 100644 index 000000000000..57824d3d3cf0 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_black_vert.glsl @@ -0,0 +1,18 @@ +#ifdef USE_INSTANCING +in mat3 ininstmatrix; +in vec3 ininstposition; +#endif + +void main() +{ +#ifdef USE_INSTANCING + mat4 instmat = mat4(vec4(ininstmatrix[0], ininstposition.x), + vec4(ininstmatrix[1], ininstposition.y), + vec4(ininstmatrix[2], ininstposition.z), + vec4(0.0, 0.0, 0.0, 1.0)); + + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * (gl_Vertex * instmat); +#else + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; +#endif +} diff --git a/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl new file mode 100644 index 000000000000..7079d47e73f7 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl @@ -0,0 +1,6 @@ +flat in vec4 finalColor; + +void main() +{ + gl_FragColor = finalColor; +} diff --git a/source/blender/gpu/shaders/gpu_shader_flat_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_flat_color_vert.glsl new file mode 100644 index 000000000000..773f9011cbea --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_flat_color_vert.glsl @@ -0,0 +1,10 @@ +in vec3 pos; +in vec4 color; + +flat out vec4 finalColor; + +void main() +{ + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(pos, 1.0); + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_frame_buffer_frag.glsl b/source/blender/gpu/shaders/gpu_shader_frame_buffer_frag.glsl new file mode 100644 index 000000000000..36d651bb4706 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_frame_buffer_frag.glsl @@ -0,0 +1,68 @@ +#if defined(ANAGLYPH) || defined(STIPPLE) +uniform sampler2D lefteyetex; +uniform sampler2D righteyetex; +#else +uniform sampler2D colortex; +# ifdef DEPTH +uniform sampler2D depthtex; +# endif +#endif + +#ifdef STIPPLE +#define STIPPLE_COLUMN 0 +#define STIPPLE_ROW 1 + +uniform int stippleid; +#endif + +float linearrgb_to_srgb(float c) +{ + if (c < 0.0031308) + return (c < 0.0) ? 0.0 : c * 12.92; + else + return 1.055 * pow(c, 1.0 / 2.4) - 0.055; +} + +void linearrgb_to_srgb(vec4 col_from, out vec4 col_to) +{ + col_to.r = linearrgb_to_srgb(col_from.r); + col_to.g = linearrgb_to_srgb(col_from.g); + col_to.b = linearrgb_to_srgb(col_from.b); + col_to.a = col_from.a; +} + +void main() +{ + vec2 co = gl_TexCoord[0].xy; +#ifdef STIPPLE + if (stippleid == STIPPLE_ROW) { + int result = int(mod(gl_FragCoord.y, 2)); + if (result != 0) { + gl_FragColor = texture2D(lefteyetex, co); + } + else { + gl_FragColor = texture2D(righteyetex, co); + } + } + else if (stippleid == STIPPLE_COLUMN) { + int result = int(mod(gl_FragCoord.x, 2)); + if (result == 0) { + gl_FragColor = texture2D(lefteyetex, co); + } + else { + gl_FragColor = texture2D(righteyetex, co); + } + } +#elif defined(ANAGLYPH) + gl_FragColor = vec4(texture2D(lefteyetex, co).r, texture2D(righteyetex, co).gb, 1.0); +#else + gl_FragColor = texture2D(colortex, co); +# ifdef DEPTH + gl_FragDepth = texture2D(depthtex, co).x; +# endif +#endif + +#ifdef COLOR_MANAGEMENT + linearrgb_to_srgb(gl_FragColor, gl_FragColor); +#endif +} diff --git a/source/blender/gpu/shaders/gpu_shader_frame_buffer_vert.glsl b/source/blender/gpu/shaders/gpu_shader_frame_buffer_vert.glsl new file mode 100644 index 000000000000..a8fb0cf5e28d --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_frame_buffer_vert.glsl @@ -0,0 +1,5 @@ +void main() +{ + gl_Position = gl_Vertex; + gl_TexCoord[0] = gl_MultiTexCoord0; +} diff --git a/source/blender/gpu/shaders/gpu_shader_frustum_line_vert.glsl b/source/blender/gpu/shaders/gpu_shader_frustum_line_vert.glsl new file mode 100644 index 000000000000..8fd431fd6b79 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_frustum_line_vert.glsl @@ -0,0 +1,11 @@ +in vec3 pos; +in mat4 mat; +in vec4 color; + +flat out vec4 finalColor; + +void main() +{ + gl_Position = gl_ModelViewProjectionMatrix * mat * vec4(pos, 1.0); + finalColor = color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_frustum_solid_frag.glsl b/source/blender/gpu/shaders/gpu_shader_frustum_solid_frag.glsl new file mode 100644 index 000000000000..e6baf7b3d4d9 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_frustum_solid_frag.glsl @@ -0,0 +1,8 @@ +flat in vec4 insideFinalColor; +flat in vec4 outsideFinalColor; +out vec4 fragColor; + +void main() +{ + gl_FragColor = gl_FrontFacing ? insideFinalColor : outsideFinalColor; +} diff --git a/source/blender/gpu/shaders/gpu_shader_frustum_solid_vert.glsl b/source/blender/gpu/shaders/gpu_shader_frustum_solid_vert.glsl new file mode 100644 index 000000000000..a31983c94e8b --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_frustum_solid_vert.glsl @@ -0,0 +1,14 @@ +in vec3 pos; +in mat4 mat; +in vec4 insideColor; +in vec4 outsideColor; + +flat out vec4 insideFinalColor; +flat out vec4 outsideFinalColor; + +void main() +{ + gl_Position = gl_ModelViewProjectionMatrix * mat * vec4(pos, 1.0); + insideFinalColor = insideColor; + outsideFinalColor = outsideColor; +} diff --git a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl index f19ff4ec65ab..2b4882e63a6e 100644 --- a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl @@ -33,7 +33,7 @@ vec3 calculate_view_space_normal(in vec3 viewposition) float calculate_ssao_factor(float depth) { /* take the normalized ray direction here */ - vec2 rotX = texture2D(jitter_tex, uvcoordsvar.xy * ssao_sample_params.yz).rg; + vec2 rotX = texture2DLod(jitter_tex, uvcoordsvar.xy * ssao_sample_params.yz, 0).rg; vec2 rotY = vec2(-rotX.y, rotX.x); /* occlusion is zero in full depth */ diff --git a/source/blender/gpu/shaders/gpu_shader_lib.glsl b/source/blender/gpu/shaders/gpu_shader_lib.glsl new file mode 100644 index 000000000000..de98521f2fda --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_lib.glsl @@ -0,0 +1,70 @@ +#if __VERSION__ < 140 && !defined(GPU_ATI) +/* Manual implementation of inverse(mat4) for GLSL version before 1.40, + * copied from https://github.com/stackgl/glsl-inverse/blob/master/index.glsl + */ + +float inverse(float m) { + return 1.0 / m; +} + +mat2 inverse(mat2 m) { + return mat2(m[1][1],-m[0][1], + -m[1][0], m[0][0]) / (m[0][0]*m[1][1] - m[0][1]*m[1][0]); +} + +mat3 inverse(mat3 m) { + float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2]; + float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2]; + float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2]; + + float b01 = a22 * a11 - a12 * a21; + float b11 = -a22 * a10 + a12 * a20; + float b21 = a21 * a10 - a11 * a20; + + float det = a00 * b01 + a01 * b11 + a02 * b21; + + return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11), + b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10), + b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det; +} + +mat4 inverse(mat4 m) { + float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2], a03 = m[0][3], + a10 = m[1][0], a11 = m[1][1], a12 = m[1][2], a13 = m[1][3], + a20 = m[2][0], a21 = m[2][1], a22 = m[2][2], a23 = m[2][3], + a30 = m[3][0], a31 = m[3][1], a32 = m[3][2], a33 = m[3][3], + + b00 = a00 * a11 - a01 * a10, + b01 = a00 * a12 - a02 * a10, + b02 = a00 * a13 - a03 * a10, + b03 = a01 * a12 - a02 * a11, + b04 = a01 * a13 - a03 * a11, + b05 = a02 * a13 - a03 * a12, + b06 = a20 * a31 - a21 * a30, + b07 = a20 * a32 - a22 * a30, + b08 = a20 * a33 - a23 * a30, + b09 = a21 * a32 - a22 * a31, + b10 = a21 * a33 - a23 * a31, + b11 = a22 * a33 - a23 * a32, + + det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + + return mat4( + a11 * b11 - a12 * b10 + a13 * b09, + a02 * b10 - a01 * b11 - a03 * b09, + a31 * b05 - a32 * b04 + a33 * b03, + a22 * b04 - a21 * b05 - a23 * b03, + a12 * b08 - a10 * b11 - a13 * b07, + a00 * b11 - a02 * b08 + a03 * b07, + a32 * b02 - a30 * b05 - a33 * b01, + a20 * b05 - a22 * b02 + a23 * b01, + a10 * b10 - a11 * b08 + a13 * b06, + a01 * b08 - a00 * b10 - a03 * b06, + a30 * b04 - a31 * b02 + a33 * b00, + a21 * b02 - a20 * b04 - a23 * b00, + a11 * b07 - a10 * b09 - a12 * b06, + a00 * b09 - a01 * b07 + a02 * b06, + a31 * b01 - a30 * b03 - a32 * b00, + a20 * b03 - a21 * b01 + a22 * b00) / det; +} +#endif diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index ab044fff100f..44bbac84ee2f 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -452,6 +452,12 @@ void vec_math_add(vec3 v1, vec3 v2, out vec3 outvec, out float outval) outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) / 3.0; } +void vec_math_mul(vec3 v1, vec3 v2, out vec3 outvec, out float outval) +{ + outvec = v1 * v2; + outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) / 3.0; +} + void vec_math_sub(vec3 v1, vec3 v2, out vec3 outvec, out float outval) { outvec = v1 - v2; @@ -482,6 +488,13 @@ void vec_math_cross(vec3 v1, vec3 v2, out vec3 outvec, out float outval) outvec /= outval; } +void vec_math_reflect(vec3 v1, vec3 v2, out vec3 outvec, out float outval) +{ + outvec = reflect(v1, v2); + outval = length(outvec); + outvec /= outval; +} + void vec_math_normalize(vec3 v, out vec3 outvec, out float outval) { outval = length(v); @@ -539,6 +552,37 @@ void set_value(float val, out float outval) outval = val; } +float half_lambert(in vec3 vect1, in vec3 vect2) +{ + float product = dot(vect1, vect2); + return product * 0.5 + 0.5; +} + +vec3 sub_scatter_fs(float brightness, float visifac, vec3 lightcol, float scale, vec3 radius, vec3 col, float i, vec3 view, vec3 lv, vec3 normal) +{ + vec3 extinctioncoefficient = radius * 0.1; + float attenuation = visifac * brightness; + vec3 evec = normalize(-view); + + vec3 dotLN = vec3(half_lambert(lv, -normal) * attenuation); + dotLN *= col; + + vec3 indirectlightcomponent = vec3(scale * max(0.0, dot(-normal, lv))); + indirectlightcomponent += scale * vec3(half_lambert(-evec, lv)); + indirectlightcomponent *= attenuation; + indirectlightcomponent *= extinctioncoefficient; + + vec3 finalcol = dotLN + vec3(indirectlightcomponent); + + finalcol.rgb *= lightcol.rgb; + return finalcol; +} + +void set_sss(float brightness, float visifac, vec3 lightcol, float scale, vec3 radius, vec3 col, float i, vec3 view, vec3 lv, vec3 normal, out vec4 outcol) +{ + outcol = vec4(sub_scatter_fs(brightness, visifac, lightcol, scale, radius, col, i, view, lv, normal), 1.0); +} + void set_rgb(vec3 col, out vec3 outcol) { outcol = col; @@ -965,9 +1009,9 @@ void texture_wood_sin(vec3 vec, out float value, out vec4 color, out vec3 normal normal = vec3(0.0, 0.0, 0.0); } -void texture_image(vec3 vec, sampler2D ima, out float value, out vec4 color, out vec3 normal) +void texture_image(vec3 vec, float lodbias, sampler2D ima, out float value, out vec4 color, out vec3 normal) { - color = texture2D(ima, (vec.xy + vec2(1.0, 1.0)) * 0.5); + color = texture2D(ima, (vec.xy + vec2(1.0, 1.0)) * 0.5, lodbias); value = color.a; normal.x = 2.0 * (color.r - 0.5); @@ -1363,11 +1407,27 @@ void mtex_mapping_ofs(vec3 texco, vec3 ofs, out vec3 outtexco) outtexco = texco + ofs; } +void mtex_tangent_rotate(vec4 tangent, vec3 n, float rot, out vec4 outtangent) +{ + float cosr = cos(rot); + float sinr = sin(rot); + outtangent.xyz = tangent.xyz * cosr + cross(tangent.xyz, n) * sinr - n * dot(tangent.xyz, n) * (1.0 - cosr); + outtangent.w = tangent.w; +} + void mtex_mapping_size(vec3 texco, vec3 size, out vec3 outtexco) { outtexco = size * texco; } +void mtex_mapping_transform(vec3 texco, float rot, vec3 ofs, vec3 size, out vec3 outtexco) +{ + mat2 mat = mat2(cos(rot), -sin(rot), + sin(rot), cos(rot)); + + outtexco = vec3((texco.xy - vec2(0.5)) * mat, texco.z - 0.5) * size + vec3(0.5) + ofs; +} + void mtex_2d_mapping(vec3 vec, out vec3 outvec) { outvec = vec3(vec.xy * 0.5 + vec2(0.5), vec.z); @@ -1378,44 +1438,94 @@ vec3 mtex_2d_mapping(vec3 vec) return vec3(vec.xy * 0.5 + vec2(0.5), vec.z); } -void mtex_cube_map(vec3 co, samplerCube ima, out float value, out vec4 color) +void mtex_cube_map(vec3 co, samplerCube ima, float lodbias, out float value, out vec4 color) { - color = textureCube(ima, co); + color = textureCube(ima, co, lodbias); value = 1.0; } void mtex_cube_map_refl_from_refldir( - samplerCube ima, vec3 reflecteddirection, out float value, out vec4 color) + samplerCube ima, vec3 reflecteddirection, float lodbias, out float value, out vec4 color) { - color = textureCube(ima, reflecteddirection); + color = textureCube(ima, reflecteddirection, lodbias); value = color.a; } +vec4 mtex_cube_map_refl_color(samplerCube ima, mat4 viewmatrixinverse, float lodbias, vec3 vn, vec3 viewdirection) +{ + vec3 normaldirection = normalize(viewmatrixinverse * vec4(vn, 0.0)).xyz; + vec3 reflecteddirection = reflect(viewdirection, normaldirection); + vec4 col = textureCube(ima, reflecteddirection, lodbias); + return col; +} + +vec4 mtex_cube_map_refr_color(samplerCube ima, mat4 viewmatrixinverse, float ior, float lodbias, vec3 vn, vec3 viewdirection) +{ + vec3 normaldirection = normalize(viewmatrixinverse * vec4(vec3(vn.x, vn.y, -vn.z), 0.0)).xyz; + vec3 refracteddirection = refract(viewdirection, normaldirection, 1.0 / ior); + vec4 col = textureCube(ima, refracteddirection, lodbias); + return col; +} + void mtex_cube_map_refl( - samplerCube ima, vec3 vp, vec3 vn, mat4 viewmatrixinverse, mat4 viewmatrix, + samplerCube ima, vec3 vp, vec3 vn, float lodbias, mat4 viewmatrixinverse, out float value, out vec4 color) { vec3 viewdirection = vec3(viewmatrixinverse * vec4(vp, 0.0)); - vec3 normaldirection = normalize(vec3(vec4(vn, 0.0) * viewmatrix)); - vec3 reflecteddirection = reflect(viewdirection, normaldirection); - color = textureCube(ima, reflecteddirection); + color = mtex_cube_map_refl_color(ima, viewmatrixinverse, lodbias, vn, viewdirection); + value = 1.0; +} + +void mtex_cube_map_refl_refr( + samplerCube ima, vec3 vp, vec3 vn, float lodbias, mat4 viewmatrixinverse, + float ior, float ratio, out float value, out vec4 color) +{ + vec3 viewdirection = vec3(viewmatrixinverse * vec4(vp, 0.0)); + + if (ratio <= 0.0) { + color = mtex_cube_map_refl_color(ima, viewmatrixinverse, lodbias, vn, viewdirection); + } + else if (ratio >= 1.0) { + color = mtex_cube_map_refr_color(ima, viewmatrixinverse, ior, lodbias, vn, viewdirection); + } + else { + vec4 refl = mtex_cube_map_refl_color(ima, viewmatrixinverse, lodbias, vn, viewdirection); + vec4 refr = mtex_cube_map_refr_color(ima, viewmatrixinverse, ior, lodbias, vn, viewdirection); + color = mix(refl, refr, ratio); + } + value = 1.0; +} + +void mtex_image(vec3 texco, sampler2D ima, float lodbias, out float value, out vec4 color) +{ + color = texture2D(ima, texco.xy, lodbias); value = 1.0; } -void mtex_image(vec3 texco, sampler2D ima, out float value, out vec4 color) +void mtex_image_refl(vec3 I, vec4 camerafac, sampler2D ima, float lodbias, mat4 objectmatrix, mat4 viewmatrix, vec3 vp, vec3 vn, out float value, out vec4 color) { - color = texture2D(ima, texco.xy); + vec4 projvec = gl_ProjectionMatrix * vec4(I, 1.0); + vec3 window = vec3(mtex_2d_mapping(projvec.xyz / projvec.w).xy * camerafac.xy + camerafac.zw, 0.0); + + vec3 Z = normalize(vec3(viewmatrix * objectmatrix * vec4( 0.0, 0.0, 1.0, 0.0))); + + vec3 reflecteddirection = reflect(vp, vn) - reflect(vp, Z); + + // 0.25 is an artistic constant, normal map distortion needs to be scaled down to give proper results + vec2 uv = window.xy + vec2(reflecteddirection.x, reflecteddirection.y) * 0.25; + + color = texture2D(ima, uv, lodbias); value = 1.0; } -void mtex_normal(vec3 texco, sampler2D ima, out vec3 normal) +void mtex_normal(vec3 texco, sampler2D ima, float lodbias, out vec3 normal) { // The invert of the red channel is to make // the normal map compliant with the outside world. // It needs to be done because in Blender // the normal used points inward. // Should this ever change this negate must be removed. - vec4 color = texture2D(ima, texco.xy); + vec4 color = texture2D(ima, texco.xy, lodbias); normal = 2.0 * (vec3(-color.r, color.g, color.b) - vec3(-0.5, 0.5, 0.5)); } @@ -1504,16 +1614,16 @@ void mtex_bump_init_viewspace( void mtex_bump_tap3( vec3 texco, sampler2D ima, float hScale, - out float dBs, out float dBt) + float lodbias, out float dBs, out float dBt) { vec2 STll = texco.xy; vec2 STlr = texco.xy + dFdx(texco.xy); vec2 STul = texco.xy + dFdy(texco.xy); float Hll, Hlr, Hul; - rgbtobw(texture2D(ima, STll), Hll); - rgbtobw(texture2D(ima, STlr), Hlr); - rgbtobw(texture2D(ima, STul), Hul); + rgbtobw(texture2D(ima, STll, lodbias), Hll); + rgbtobw(texture2D(ima, STlr, lodbias), Hlr); + rgbtobw(texture2D(ima, STul, lodbias), Hul); dBs = hScale * (Hlr - Hll); dBt = hScale * (Hul - Hll); @@ -1523,7 +1633,7 @@ void mtex_bump_tap3( void mtex_bump_bicubic( vec3 texco, sampler2D ima, float hScale, - out float dBs, out float dBt ) + float lodbias, out float dBs, out float dBt ) { float Hl; float Hr; @@ -1538,10 +1648,10 @@ void mtex_bump_bicubic( vec2 STd = texco.xy - 0.5 * TexDy; vec2 STu = texco.xy + 0.5 * TexDy; - rgbtobw(texture2D(ima, STl), Hl); - rgbtobw(texture2D(ima, STr), Hr); - rgbtobw(texture2D(ima, STd), Hd); - rgbtobw(texture2D(ima, STu), Hu); + rgbtobw(texture2D(ima, STl, lodbias), Hl); + rgbtobw(texture2D(ima, STr, lodbias), Hr); + rgbtobw(texture2D(ima, STd, lodbias), Hd); + rgbtobw(texture2D(ima, STu, lodbias), Hu); vec2 dHdxy = vec2(Hr - Hl, Hu - Hd); float fBlend = clamp(1.0 - textureQueryLOD(ima, texco.xy).x, 0.0, 1.0); @@ -1615,7 +1725,7 @@ void mtex_bump_bicubic( void mtex_bump_tap5( vec3 texco, sampler2D ima, float hScale, - out float dBs, out float dBt) + float lodbias, out float dBs, out float dBt) { vec2 TexDx = dFdx(texco.xy); vec2 TexDy = dFdy(texco.xy); @@ -1627,11 +1737,11 @@ void mtex_bump_tap5( vec2 STu = texco.xy + 0.5 * TexDy; float Hc, Hl, Hr, Hd, Hu; - rgbtobw(texture2D(ima, STc), Hc); - rgbtobw(texture2D(ima, STl), Hl); - rgbtobw(texture2D(ima, STr), Hr); - rgbtobw(texture2D(ima, STd), Hd); - rgbtobw(texture2D(ima, STu), Hu); + rgbtobw(texture2D(ima, STc, lodbias), Hc); + rgbtobw(texture2D(ima, STl, lodbias), Hl); + rgbtobw(texture2D(ima, STr, lodbias), Hr); + rgbtobw(texture2D(ima, STd, lodbias), Hd); + rgbtobw(texture2D(ima, STu, lodbias), Hu); dBs = hScale * (Hr - Hl); dBt = hScale * (Hu - Hd); @@ -1639,7 +1749,7 @@ void mtex_bump_tap5( void mtex_bump_deriv( vec3 texco, sampler2D ima, float ima_x, float ima_y, float hScale, - out float dBs, out float dBt) + float lodbias, out float dBs, out float dBt) { float s = 1.0; // negate this if flipped texture coordinate vec2 TexDx = dFdx(texco.xy); @@ -1648,7 +1758,7 @@ void mtex_bump_deriv( // this variant using a derivative map is described here // http://mmikkelsen3d.blogspot.com/2011/07/derivative-maps.html vec2 dim = vec2(ima_x, ima_y); - vec2 dBduv = hScale * dim * (2.0 * texture2D(ima, texco.xy).xy - 1.0); + vec2 dBduv = hScale * dim * (2.0 * texture2D(ima, texco.xy, lodbias).xy - 1.0); dBs = dBduv.x * TexDx.x + s * dBduv.y * TexDx.y; dBt = dBduv.x * TexDy.x + s * dBduv.y * TexDy.y; @@ -1760,6 +1870,21 @@ void lamp_falloff_curve(float lampdist, sampler2D curvemap, float dist, out floa visifac = texture2D(curvemap, vec2(dist / lampdist, 0.0)).x; } +void lamp_falloff_invsquarecutoff(float radius, float dist, float cutoff, out float visifac) +{ + float d = dist - radius; + if (d <= 0.0) { + visifac = 1.0; + } + else { + float denom = d / radius + 1.0; + float att = 1.0 / (denom * denom); + att = (att - cutoff) / (1.0 - cutoff); + att = max(att, 0.0); + visifac = att; + } +} + void lamp_visibility_sphere(float lampdist, float dist, float visifac, out float outvisifac) { float t = lampdist - dist; @@ -1821,6 +1946,18 @@ void lamp_visibility_clamp(float visifac, out float outvisifac) outvisifac = (visifac < 0.001) ? 0.0 : visifac; } +void shade_alpha_depth(vec3 vp, sampler2D ima, float alpha, float factor, out float outalpha) +{ + float depth = texelFetch(ima, ivec2(gl_FragCoord.xy), 0).x; + + vec4 depthvp = gl_ProjectionMatrix * vec4(vp.xy, vp.z - factor, 1.0); + + float startfade = gl_FragCoord.z; + float endfade = (1.0 + depthvp.z / depthvp.w) * 0.5; + + outalpha = alpha * smoothstep(startfade, endfade, depth); +} + void world_paper_view(vec3 vec, out vec3 outvec) { vec3 nvec = normalize(vec); @@ -1971,6 +2108,13 @@ void shade_diffuse_oren_nayer(float nl, vec3 n, vec3 l, vec3 v, float rough, out } } +void lamp_visible(int lay, int oblay, vec3 col, float energy, out vec3 outcol, out float outenergy) +{ + int mask = min((lay & oblay), 1); + outcol = col * mask; + outenergy = energy * mask; +} + void shade_diffuse_toon(vec3 n, vec3 l, vec3 v, float size, float tsmooth, out float is) { float rslt = dot(n, l); @@ -2064,6 +2208,26 @@ void shade_hemi_spec(vec3 vn, vec3 lv, vec3 view, float spec, float hard, float t = visifac * spec * pow(t, hard); } +float InScatter(vec3 start, vec3 dir, vec3 lightPos, float d) +{ + // calculate quadratic coefficients a,b,c + vec3 q = start - lightPos; + float b = dot(dir, q); + float c = dot(q, q); + + // evaluate integral + float s = 1.0 / sqrt(c - b*b); + + float l = s * (atan( (d + b) * s) - atan( b*s )); + + return l; +} + +vec3 linePlaneIntersect(in vec3 lp, in vec3 lv, in vec3 pc, in vec3 pn) +{ + return lp+lv*(dot(pn,pc-lp)/dot(pn,lv)); +} + void shade_phong_spec(vec3 n, vec3 l, vec3 v, float hard, out float specfac) { vec3 h = normalize(l + v); @@ -2222,6 +2386,13 @@ void env_apply(vec4 col, vec3 hor, vec3 zen, vec4 f, mat4 vm, vec3 vn, out vec4 outcol = col + f * vec4(mix(hor, zen, skyfac), 0); } +void env_apply_tex(vec4 col, vec4 f, samplerCube wtex, vec3 vn, mat4 ivm, out vec4 outcol) +{ + vec3 ndir = normalize(ivm * vec4(vn, 0.0)).xyz; + vec4 cubeD = textureCubeLod(wtex, ndir, 9.0); + outcol = col + f * cubeD * (1.0 / 3.141592654); +} + void shade_maddf(vec4 col, float f, vec4 col1, out vec4 outcol) { outcol = col + f * col1; @@ -2272,53 +2443,200 @@ void shade_clamp_positive(vec4 col, out vec4 outcol) outcol = max(col, vec4(0.0)); } -void test_shadowbuf( - vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat, float shadowbias, float inp, +bool shadow_visibility(vec4 co) +{ + return (co.w > 0.0 && co.x > 0.0 && co.x / co.w < 1.0 && co.y > 0.0 && co.y / co.w < 1.0); +} + +vec4 shadow_proj_coord(vec3 rco, mat4 shadowpersmat) +{ + vec4 lco = shadowpersmat * vec4(rco, 1.0); + return lco; +} + +vec4 shadow_proj_coord(vec3 rco, vec3 vn, mat4 shadowpersmat, float bias, float slopebias) +{ + vec4 lco = shadowpersmat * vec4(rco + vn * slopebias, 1.0); + lco.z -= bias * lco.w; + return lco; +} + +float test_shadow_simple(sampler2DShadow shadowmap, vec4 co) +{ + return shadow2DProj(shadowmap, co).x; +} + +float texture_shadow_offset(sampler2DShadow shadowmap, vec4 co, vec2 offset) +{ + return shadow2DProj(shadowmap, vec4(co.xy + offset, co.z, co.w)).x; +} + +float test_shadow_pcf_early_bail(sampler2DShadow shadowmap, vec4 co, float samples, float samplesize) +{ + float step = samplesize / samples; + float fullstep = samplesize - step * 0.98; + float halfsample = samplesize * 0.5 - step * 0.49; + + float result = 0.0; + for (float y = -halfsample; y <= halfsample; y += fullstep) { + for (float x = -halfsample; x <= halfsample; x += fullstep) { + result += texture_shadow_offset(shadowmap, co, vec2(x, y) * 0.1); + } + } + + if (result > 0.0 && result < 4.0) { + float sampleoffset = halfsample - step; + for (float y = -sampleoffset; y <= sampleoffset; y += step) { + for (float x = -halfsample; x <= halfsample; x += step) { + result += texture_shadow_offset(shadowmap, co, vec2(x, y) * 0.1); + } + } + for (float y = -halfsample; y <= halfsample; y += fullstep) { + for (float x = -sampleoffset; x <= sampleoffset; x += step) { + result += texture_shadow_offset(shadowmap, co, vec2(x, y) * 0.1); + } + } + result /= (samples * samples); + } + else { + result /= 4.0; + } + + return result; +} + +float test_shadow_pcf(sampler2DShadow shadowmap, vec4 co, float samples, float samplesize) +{ + float step = samplesize / samples; + float halfsample = samplesize * 0.5 - step * 0.49; + + float result = 0.0; + for (float y = -halfsample; y <= halfsample; y += step) { + for (float x = -halfsample; x <= halfsample; x += step) { + result += texture_shadow_offset(shadowmap, co, vec2(x, y) * 0.1); + } + } + result /= (samples * samples); + + return result; +} + +float test_shadow_pcf_jitter(sampler2DShadow shadowmap, vec4 co, sampler2D jitter, float samples, float samplesize) +{ + float step = samplesize / samples; + float halfsample = samplesize * 0.5 - step * 0.49; + + vec2 jitterco = co.xy * 43543.0; + vec2 vec = texture2D(jitter, jitterco).xy; + + mat2 rot = mat2(vec.x, vec.y, + -vec.y, vec.x); + + float result = 0.0; + for (float y = -halfsample; y <= halfsample; y += step) { + for (float x = -halfsample; x <= halfsample; x += step) { + vec2 ofs = vec2(x, y) * 0.1; + result += texture_shadow_offset(shadowmap, co, (vec2(x, y) * rot) * 0.1); + } + } + result /= (samples * samples); + + return result; +} + +float test_shadow_vsm(sampler2D shadowmap, vec4 co, float bias, float bleedbias) +{ + vec2 moments = texture2DProj(shadowmap, co).rg; + float dist = co.z / co.w; + float p = 0.0; + + if (dist <= moments.x) + p = 1.0; + + float variance = moments.y - (moments.x * moments.x); + variance = max(variance, bias / 10.0); + + float d = moments.x - dist; + float p_max = variance / (variance + d * d); + + // Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1] + p_max = clamp((p_max - bleedbias) / (1.0 - bleedbias), 0.0, 1.0); + + return max(p, p_max); +} + +void shadow_simple( + vec3 rco, vec3 vn, sampler2DShadow shadowmap, mat4 shadowpersmat, float bias, float slopebias, float inp, out float result) { if (inp <= 0.0) { result = 0.0; } else { - vec4 co = shadowpersmat * vec4(rco, 1.0); - - //float bias = (1.5 - inp*inp)*shadowbias; - co.z -= shadowbias * co.w; + vec4 co = shadow_proj_coord(rco, vn, shadowpersmat, bias, slopebias); - if (co.w > 0.0 && co.x > 0.0 && co.x / co.w < 1.0 && co.y > 0.0 && co.y / co.w < 1.0) - result = shadow2DProj(shadowmap, co).x; - else + if (shadow_visibility(co)) { + result = test_shadow_simple(shadowmap, co); + } + else { result = 1.0; + } } } -void test_shadowbuf_vsm( - vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, float shadowbias, float bleedbias, float inp, +void shadow_pcf( + vec3 rco, vec3 vn, sampler2DShadow shadowmap, mat4 shadowpersmat, float bias, float slopebias, + float samples, float samplesize, float inp, out float result) { if (inp <= 0.0) { result = 0.0; } else { - vec4 co = shadowpersmat * vec4(rco, 1.0); - if (co.w > 0.0 && co.x > 0.0 && co.x / co.w < 1.0 && co.y > 0.0 && co.y / co.w < 1.0) { - vec2 moments = texture2DProj(shadowmap, co).rg; - float dist = co.z / co.w; - float p = 0.0; + vec4 co = shadow_proj_coord(rco, vn, shadowpersmat, bias, slopebias); - if (dist <= moments.x) - p = 1.0; + if (shadow_visibility(co)) { + result = test_shadow_pcf(shadowmap, co, samples, samplesize); + } + else { + result = 1.0; + } + } +} - float variance = moments.y - (moments.x * moments.x); - variance = max(variance, shadowbias / 10.0); +void shadow_pcf_jitter( + vec3 rco, vec3 vn, sampler2DShadow shadowmap, mat4 shadowpersmat, float bias, float slopebias, + sampler2D jitter, float samples, float samplesize, float inp, + out float result) +{ + if (inp <= 0.0) { + result = 0.0; + } + else { + vec4 co = shadow_proj_coord(rco, vn, shadowpersmat, bias, slopebias); - float d = moments.x - dist; - float p_max = variance / (variance + d * d); + if (shadow_visibility(co)) { + result = test_shadow_pcf_jitter(shadowmap, co, jitter, samples, samplesize); + } + else { + result = 1.0; + } + } +} - // Now reduce light-bleeding by removing the [0, x] tail and linearly rescaling (x, 1] - p_max = clamp((p_max - bleedbias) / (1.0 - bleedbias), 0.0, 1.0); +void shadow_pcf_early_bail( + vec3 rco, vec3 vn, sampler2DShadow shadowmap, mat4 shadowpersmat, float bias, float slopebias, + float samples, float samplesize, float inp, + out float result) +{ + if (inp <= 0.0) { + result = 0.0; + } + else { + vec4 co = shadow_proj_coord(rco, vn, shadowpersmat, bias, slopebias); - result = max(p, p_max); + if (shadow_visibility(co)) { + result = test_shadow_pcf_early_bail(shadowmap, co, samples, samplesize); } else { result = 1.0; @@ -2326,42 +2644,40 @@ void test_shadowbuf_vsm( } } -void shadows_only( - vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat, - float shadowbias, vec3 shadowcolor, float inp, - out vec3 result) +void shadow_vsm( + vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, float bias, float bleedbias, float inp, + out float result) { - result = vec3(1.0); - - if (inp > 0.0) { - float shadfac; + if (inp <= 0.0) { + result = 0.0; + } + else { + vec4 co = shadow_proj_coord(rco, shadowpersmat); - test_shadowbuf(rco, shadowmap, shadowpersmat, shadowbias, inp, shadfac); - result -= (1.0 - shadfac) * (vec3(1.0) - shadowcolor); + if (shadow_visibility(co)) { + result = test_shadow_vsm(shadowmap, co, bias, bleedbias); + } + else { + result = 1.0; + } } } -void shadows_only_vsm( - vec3 rco, sampler2D shadowmap, mat4 shadowpersmat, - float shadowbias, float bleedbias, vec3 shadowcolor, float inp, - out vec3 result) +void shadows_only(float inp, float shadfac, vec3 shadowcolor, out vec3 result) { result = vec3(1.0); if (inp > 0.0) { - float shadfac; - - test_shadowbuf_vsm(rco, shadowmap, shadowpersmat, shadowbias, bleedbias, inp, shadfac); result -= (1.0 - shadfac) * (vec3(1.0) - shadowcolor); } } -void shade_light_texture(vec3 rco, sampler2D cookie, mat4 shadowpersmat, out vec4 result) +void shade_light_texture(vec3 rco, sampler2D cookie, vec3 scale, float lodbias, mat4 shadowpersmat, out vec4 result) { vec4 co = shadowpersmat * vec4(rco, 1.0); - result = texture2DProj(cookie, co); + result = texture2DProj(cookie, co * vec4(scale, 1.0), lodbias); } void shade_exposure_correct(vec3 col, float linfac, float logfac, out vec3 outcol) @@ -3117,16 +3433,16 @@ void node_tex_clouds(vec3 co, float size, out vec4 color, out float fac) fac = 1.0; } -void node_tex_environment_equirectangular(vec3 co, sampler2D ima, out vec4 color) +void node_tex_environment_equirectangular(vec3 co, sampler2D ima, float lodbias, out vec4 color) { vec3 nco = normalize(co); float u = -atan(nco.y, nco.x) / (2.0 * M_PI) + 0.5; float v = atan(nco.z, hypot(nco.x, nco.y)) / M_PI + 0.5; - color = texture2D(ima, vec2(u, v)); + color = texture2D(ima, vec2(u, v), lodbias); } -void node_tex_environment_mirror_ball(vec3 co, sampler2D ima, out vec4 color) +void node_tex_environment_mirror_ball(vec3 co, sampler2D ima, float lodbias, out vec4 color) { vec3 nco = normalize(co); @@ -3139,7 +3455,7 @@ void node_tex_environment_mirror_ball(vec3 co, sampler2D ima, out vec4 color) float u = 0.5 * (nco.x + 1.0); float v = 0.5 * (nco.z + 1.0); - color = texture2D(ima, vec2(u, v)); + color = texture2D(ima, vec2(u, v), lodbias); } void node_tex_environment_empty(vec3 co, out vec4 color) @@ -3905,6 +4221,86 @@ void node_output_world(vec4 surface, vec4 volume, out vec4 result) result = surface; } +void mtex_parallax(vec3 texco, vec3 vp, vec4 tangent, vec3 vn, sampler2D ima, float numsteps, + float bumpscale, vec3 scale, float discarduv, float comp, out vec3 ptexcoord) +{ + // Compute binormal/bitangent from tangent and normal. + vec3 binormal = cross(-vn, tangent.xyz) * tangent.w; + // Transform the fragment position in texture space. + vec3 vvec = vec3(dot(tangent.xyz, vp), dot(binormal, vp), dot(-vn, vp)); + vec3 vv = normalize(vvec); + + // The component to extract the height information from + int ci = int(comp); + + // The uv shift per depth step. + vec2 delta = (vec3(-vv.x, gl_FrontFacing ? vv.y : -vv.y, 0.0) * bumpscale / vv.z).xy; + + float height = 0.0; + + // The depth to start from, top to bottom. + float depth = 1.0; + float depthstep = 1.0 / numsteps; + + /* Uv is computed with the current depth value using the formula: + * uv = original_uv * delta_uv * (1.0 - depth) + */ + + // Linear sample from top. + for (int i = 0; i < numsteps; ++i) { + height = textureLod(ima, texco.xy - delta * (1.0 - depth), 0)[ci]; + // Stop if the texture height is greater than current depth. + if (height > depth) { + break; + } + + depth -= depthstep; + } + + vec2 texuv = texco.xy - delta * (1.0 - depth); + + /* Interpolation. + * Compare the distance of the height texture with current level and previous level. + */ + + // Compute the depth before the last step, reverse operation. + float depthprelay = depth + depthstep; + // Compute the uv with the pre depth. + vec2 texuvprelay = texco.xy - delta * (1.0 - depthprelay); + + // The shift between the texture height and the last depth. + float depthshiftcurlay = height - depth; + // The shift between the texture height with precedent uv computed with pre detph and the pre depth. + float depthshiftprelay = textureLod(ima, texuvprelay, 0)[ci] - depthprelay; + + float weight = 1.0; + // If the height is right in the middle of two step the difference of the two shifts will be null. + if ((depthshiftcurlay - depthshiftprelay) > 0.0) { + // Get shift ratio. + weight = depthshiftcurlay / (depthshiftcurlay - depthshiftprelay); + } + + vec2 finaltexuv = mix(texuv, texuvprelay, weight); + + // Discard if uv is out of the range 0 to 1. + vec2 clampmin = vec2(-0.5) * scale.xy; + vec2 clampmax = vec2(0.5) * scale.xy; + + if ((discarduv == 1.0) && + (finaltexuv.x - 0.5 < clampmin.x || finaltexuv.x - 0.5 > clampmax.x || + finaltexuv.y - 0.5 < clampmin.y || finaltexuv.y - 0.5 > clampmax.y)) + { + discard; + } + + ptexcoord = vec3(finaltexuv, texco.z); +} + +void parallax_uv_attribute(vec3 uv, out vec3 outuv) +{ + outuv = vec3(uv.xy * 2.0 - vec2(1.0), uv.z); +} + /* ********************** matcap style render ******************** */ void material_preview_matcap(vec4 color, sampler2D ima, vec4 N, vec4 mask, out vec4 result) diff --git a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl index 5d00108b052b..a8fb0cf5e28d 100644 --- a/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_sep_gaussian_blur_vert.glsl @@ -1,6 +1,5 @@ - void main() { - gl_Position = ftransform(); + gl_Position = gl_Vertex; gl_TexCoord[0] = gl_MultiTexCoord0; } diff --git a/source/blender/gpu/shaders/gpu_shader_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_vertex.glsl index 2c5bcd54b33e..6c487d8b7c53 100644 --- a/source/blender/gpu/shaders/gpu_shader_vertex.glsl +++ b/source/blender/gpu/shaders/gpu_shader_vertex.glsl @@ -7,8 +7,24 @@ out block { } outpt; #endif -varying vec3 varposition; -varying vec3 varnormal; +#ifdef USE_INSTANCING +in mat3 ininstmatrix; +in vec3 ininstposition; +in vec4 ininstcolor; +in int ininstlayer; +in vec3 ininstinfo; + +out vec4 varinstcolor; +out mat4 varinstmat; +out mat4 varinstinvmat; +flat out int varinstlayer; +out vec3 varinstinfo; + +uniform mat4 unfviewmat; +#endif + +out vec3 varposition; +out vec3 varnormal; #ifdef CLIP_WORKAROUND varying float gl_ClipDistance[6]; @@ -89,6 +105,26 @@ void main() vec3 normal = gl_Normal; #endif +#ifdef USE_INSTANCING + mat4 instmat = mat4(vec4(ininstmatrix[0], ininstposition.x), + vec4(ininstmatrix[1], ininstposition.y), + vec4(ininstmatrix[2], ininstposition.z), + vec4(0.0, 0.0, 0.0, 1.0)); + + varinstmat = transpose(instmat); +#if !defined(GPU_ATI) + varinstinvmat = inverse(varinstmat); +#else + varinstinvmat = varinstmat; +#endif + varinstcolor = ininstcolor; + varinstlayer = ininstlayer; + varinstinfo = ininstinfo; + + position *= instmat; + normal *= ininstmatrix; +#endif + vec4 co = gl_ModelViewMatrix * position; varposition = co.xyz; diff --git a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl index a81d2bcef693..97388d82cfba 100644 --- a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl +++ b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl @@ -2,6 +2,7 @@ varying vec3 varposition; varying vec3 varnormal; +varying float gl_ClipDistance[6]; /* Color, keep in sync with: gpu_shader_vertex.glsl */ @@ -78,3 +79,7 @@ void main() varposition = gl_Vertex.xyz; varnormal = normalize(-varposition); + // Always set clip distance to 1 to disable clipping. + for (int i = 0; i < 6; ++i) { + gl_ClipDistance[i] = 1.0; + } diff --git a/source/blender/gpu/shaders/gpu_shader_vsm_store_vert.glsl b/source/blender/gpu/shaders/gpu_shader_vsm_store_vert.glsl index 224c3e78adc1..58af4b76f65e 100644 --- a/source/blender/gpu/shaders/gpu_shader_vsm_store_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_vsm_store_vert.glsl @@ -1,7 +1,22 @@ varying vec4 v_position; +#ifdef USE_INSTANCING +in mat3 ininstmatrix; +in vec3 ininstposition; +#endif + void main() { - gl_Position = ftransform(); +#ifdef USE_INSTANCING + mat4 instmat = mat4(vec4(ininstmatrix[0], ininstposition.x), + vec4(ininstmatrix[1], ininstposition.y), + vec4(ininstmatrix[2], ininstposition.z), + vec4(0.0, 0.0, 0.0, 1.0)); + + v_position = gl_ProjectionMatrix * gl_ModelViewMatrix * (gl_Vertex * instmat); + gl_Position = v_position; +#else + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex; v_position = gl_Position; +#endif } diff --git a/source/blender/makesdna/DNA_actuator_types.h b/source/blender/makesdna/DNA_actuator_types.h index 6461ad5445ff..70fe722719d3 100644 --- a/source/blender/makesdna/DNA_actuator_types.h +++ b/source/blender/makesdna/DNA_actuator_types.h @@ -60,8 +60,8 @@ typedef struct bActionActuator { short end_reset; /* Ending the actuator (negative pulse) wont reset the action to its starting frame */ short strideaxis; /* Displacement axis */ short blend_mode; /* Layer blending mode */ - float stridelength; /* Displacement incurred by cycle */ // not in use float layer_weight; /* How much of the previous layer to use for blending. (<0 = disable, 0 = add mode) */ + int pad; } bActionActuator; typedef struct Sound3D { @@ -87,7 +87,7 @@ typedef struct bSoundActuator { } bSoundActuator; typedef struct bEditObjectActuator { - int time; + float time; short type, flag; struct Object *ob; struct Mesh *me; @@ -117,6 +117,8 @@ typedef struct bPropertyActuator { typedef struct bObjectActuator { short flag, type, otype; short damping; + short servotype; + short pad2[3]; float forceloc[3], forcerot[3]; float pad[3], pad1[3]; float dloc[3], drot[3]; /* angle in radians */ @@ -190,6 +192,13 @@ typedef struct bGameActuator { char loadaniname[64]; } bGameActuator; +typedef struct bVibrationActuator { + int joyindex; + short mode, pad1; /* mode: 0 = Play, 1 = Stop */ + float strength, strength_right; /* strength --> low frequency motor, strength_right --> high frequency motor */ + int duration; +} bVibrationActuator; + typedef struct bVisibilityActuator { /** bit 0: Is this object visible? ** bit 1: Apply recursively @@ -198,13 +207,13 @@ typedef struct bVisibilityActuator { } bVisibilityActuator; typedef struct bTwoDFilterActuator { - char pad[4]; /* Tells what type of 2D Filter */ short type; /* (flag == 0) means 2D filter is activate and * (flag != 0) means 2D filter is inactive */ short flag; int int_arg; + int mipmap; /* a float argument */ float float_arg; struct Text *text; @@ -301,6 +310,10 @@ typedef struct bActuator { #define ACT_OBJECT_SERVO 1 #define ACT_OBJECT_CHARACTER 2 +/* objectactuator->servotype */ +#define ACT_SERVO_LINEAR 0 +#define ACT_SERVO_ANGULAR 1 + /* actuator->type */ #define ACT_OBJECT 0 #define ACT_IPO 1 @@ -329,6 +342,7 @@ typedef struct bActuator { #define ACT_ARMATURE 23 #define ACT_STEERING 24 #define ACT_MOUSE 25 +#define ACT_VIBRATION 26 /* actuator flag */ #define ACT_SHOW 1 @@ -378,7 +392,6 @@ typedef struct bActuator { #define ACT_IPOFORCE (1 << 0) #define ACT_IPOEND (1 << 1) #define ACT_IPOLOCAL (1 << 2) -#define ACT_IPOCHILD (1 << 4) #define ACT_IPOADD (1 << 5) /* property actuator->type */ @@ -454,7 +467,8 @@ typedef struct bActuator { #define ACT_EDOB_ENABLE_RB 2 #define ACT_EDOB_DISABLE_RB 3 #define ACT_EDOB_SET_MASS 4 - +#define ACT_EDOB_RESTORE_PHY 5 +#define ACT_EDOB_SUSPEND_PHY 6 /* SceneActuator->type */ #define ACT_SCENE_RESTART 0 @@ -580,4 +594,8 @@ typedef struct bActuator { #define ACT_MOUSE_OBJECT_AXIS_Y 1 #define ACT_MOUSE_OBJECT_AXIS_Z 2 +/* vibrationactuator->mode */ +#define ACT_VIBRATION_PLAY 0 +#define ACT_VIBRATION_STOP 1 + #endif /* __DNA_ACTUATOR_TYPES_H__ */ diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h index 961f32246d36..e011ef123476 100644 --- a/source/blender/makesdna/DNA_camera_types.h +++ b/source/blender/makesdna/DNA_camera_types.h @@ -59,6 +59,13 @@ typedef struct CameraStereoSettings { float pole_merge_angle_to; } CameraStereoSettings; +typedef struct GameCameraViewportSettings { + float leftratio; + float rightratio; + float bottomratio; + float topratio; +} GameCameraViewportSettings; + typedef struct Camera { ID id; struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */ @@ -66,16 +73,21 @@ typedef struct Camera { char type; /* CAM_PERSP, CAM_ORTHO or CAM_PANO */ char dtx; /* draw type extra */ short flag; + short gameflag; + short pad2; + struct GameCameraViewportSettings gameviewport; float passepartalpha; float clipsta, clipend; float lens, ortho_scale, drawsize; float sensor_x, sensor_y; float shiftx, shifty; + float lodfactor, pad; /* yafray: dof params */ /* qdn: yafray var 'YF_dofdist' now enabled for defocus composite node as well. * The name was not changed so that no other files need to be modified */ float YF_dofdist; + int pad3; struct Ipo *ipo DNA_DEPRECATED; /* old animation system, deprecated for 2.5 */ @@ -83,7 +95,7 @@ typedef struct Camera { struct GPUDOFSettings gpu_dof; char sensor_fit; - char pad[7]; + char pad1[7]; /* Stereo settings */ struct CameraStereoSettings stereo; @@ -126,6 +138,14 @@ enum { CAM_SHOW_SAFE_CENTER = (1 << 9), }; +/* gameflag */ +enum { + GAME_CAM_SHOW_FRUSTUM = (1 << 0), + GAME_CAM_OVERRIDE_CULLING = (1 << 1), + GAME_CAM_OBJECT_ACTIVITY_CULLING = (1 << 2), + GAME_CAM_VIEWPORT = (1 << 3), +}; + /* yafray: dof sampling switch */ /* #define CAM_YF_NO_QMC 512 */ /* deprecated */ diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index 2ae686d178ef..4d9b85b38ad9 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -316,8 +316,7 @@ typedef struct bRigidBodyJointConstraint { float extraFz; short flag; short pad; - short pad1; - short pad2; + float breaking; } bRigidBodyJointConstraint; /* Clamp-To Constraint */ @@ -844,6 +843,7 @@ typedef enum eObjectSolver_Flags { /* Rigid-Body Constraint */ #define CONSTRAINT_DRAW_PIVOT 0x40 #define CONSTRAINT_DISABLE_LINKED_COLLISION 0x80 +#define CONSTRAINT_USE_BREAKING 0x100 /* ObjectSolver Constraint -> flag */ typedef enum eStretchTo_Flags { diff --git a/source/blender/makesdna/DNA_fileglobal_types.h b/source/blender/makesdna/DNA_fileglobal_types.h index 98d433d84547..a38c03e52229 100644 --- a/source/blender/makesdna/DNA_fileglobal_types.h +++ b/source/blender/makesdna/DNA_fileglobal_types.h @@ -42,8 +42,10 @@ struct Scene; typedef struct FileGlobal { char subvstr[4]; /* needs to be here, for human fileformat recognition */ short subversion; + short upbgeversion; + short upbgesubversion; short minversion, minsubversion; - char pad[6]; + char pad[2]; struct bScreen *curscreen; struct Scene *curscene; int fileflags; diff --git a/source/blender/makesdna/DNA_lamp_types.h b/source/blender/makesdna/DNA_lamp_types.h index ca1a07fbcae4..e7eb54cd2e54 100644 --- a/source/blender/makesdna/DNA_lamp_types.h +++ b/source/blender/makesdna/DNA_lamp_types.h @@ -62,12 +62,15 @@ typedef struct Lamp { float att1, att2; /* Quad1 and Quad2 attenuation */ float coeff_const, coeff_lin, coeff_quad, coeff_pad; + float cutoff, radius; struct CurveMapping *curfalloff; short falloff_type; short pad2; float clipsta, clipend; - float bias, soft, compressthresh, bleedbias, pad5; + float bias, slopebias, soft, compressthresh; + float bleedbias, pad; + float bufsharp; short bufsize, samp, buffers, filtertype; char bufflag, buftype; @@ -78,6 +81,7 @@ typedef struct Lamp { float adapt_thresh; short ray_samp_method; short shadowmap_type; + short shadow_filter, pad3[3]; /* texact is for buttons */ short texact, shadhalostep; @@ -151,6 +155,13 @@ typedef struct Lamp { #define LA_SHAD_TEX (1 << 16) #define LA_SHOW_CONE (1 << 17) #define LA_SHOW_SHADOW_BOX (1 << 18) +#define LA_STATIC_SHADOW (1 << 19) + +/* shadow_filter */ +#define LA_SHADOW_FILTER_NONE 0 +#define LA_SHADOW_FILTER_PCF 1 +#define LA_SHADOW_FILTER_PCF_BAIL 2 +#define LA_SHADOW_FILTER_PCF_JITTER 3 /* layer_shadow */ #define LA_LAYER_SHADOW_BOTH 0 @@ -168,7 +179,7 @@ typedef struct Lamp { #define LA_FALLOFF_CURVE 3 #define LA_FALLOFF_SLIDERS 4 #define LA_FALLOFF_INVCOEFFICIENTS 5 - +#define LA_FALLOFF_INVSQUARE_CUTOFF 6 /* buftype, no flag */ #define LA_SHADBUF_REGULAR 0 diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h index dfe7b441c714..bf9cae5ddc7e 100644 --- a/source/blender/makesdna/DNA_material_types.h +++ b/source/blender/makesdna/DNA_material_types.h @@ -80,7 +80,7 @@ typedef struct GameSettings { int flag; int alpha_blend; int face_orientation; - int pad1; + int pad; } GameSettings; typedef struct TexPaintSlot { @@ -171,9 +171,10 @@ typedef struct Material { struct PreviewImage *preview; /* dynamic properties */ - float friction, fh, reflect; - float fhdist, xyfrict; - short dynamode, pad2; + float friction DNA_DEPRECATED, rolling_friction DNA_DEPRECATED; + float fh DNA_DEPRECATED, reflect DNA_DEPRECATED; + float fhdist DNA_DEPRECATED, xyfrict DNA_DEPRECATED; + short dynamode DNA_DEPRECATED, pad2[3]; /* subsurface scattering */ float sss_radius[3], sss_col[3]; @@ -195,7 +196,12 @@ typedef struct Material { short paint_active_slot; short paint_clone_slot; short tot_slots; - short pad4[3]; + + /* Constants settings */ + short constflag; + + /* Depth transparency settings */ + float depthtranspfactor; /* multiple tangent (Normal Map node) */ char nmap_tangent_names[9][64]; /* [MAX_MTFACE+1][MAX_NAME]; +1 for empty name */ @@ -204,6 +210,7 @@ typedef struct Material { struct TexPaintSlot *texpaintslot; /* cached slot for painting. Make sure to recalculate before use * with refresh_texpaint_image_cache */ ListBase gpumaterial; /* runtime */ + ListBase gpumaterialinstancing; /* runtime */ } Material; @@ -219,8 +226,7 @@ typedef struct Material { // Game Options - flag #define GEMAT_BACKCULL 16 /* KX_BACKCULL */ #define GEMAT_SHADED 32 /* KX_LIGHT */ -#define GEMAT_TEXT 64 /* RAS_RENDER_3DPOLYGON_TEXT */ -#define GEMAT_NOPHYSICS 128 +#define GEMAT_NOPHYSICS 128 #define GEMAT_INVISIBLE 256 // Face Orientation Options - face_orientation @@ -229,10 +235,6 @@ typedef struct Material { #define GEMAT_BILLBOARD 1024 /* BILLBOARD_AXISALIGNED */ #define GEMAT_SHADOW 2048 /* SHADOW */ -// Use Textures - not defined directly in the UI -#define GEMAT_TEX 4096 /* KX_TEX */ - - /* **************** MATERIAL ********************* */ /* maximum number of materials per material array. @@ -247,6 +249,14 @@ typedef struct Material { #define MA_TYPE_VOLUME 2 #define MA_TYPE_WIRE 3 +/* constflag */ +#define MA_CONSTANT_MATERIAL (1 << 0) +#define MA_CONSTANT_LAMP (1 << 1) +#define MA_CONSTANT_TEXTURE (1 << 2) +#define MA_CONSTANT_WORLD (1 << 3) +#define MA_CONSTANT_MIST (1 << 4) +#define MA_CONSTANT_TEXTURE_UV (1 << 5) + /* flag */ /* for render */ #define MA_IS_USED 1 @@ -310,6 +320,7 @@ typedef struct Material { #define MA_CASTSHADOW (1 << 0) #define MA_MODE2_PIPELINE (MA_CASTSHADOW) #define MA_TANGENT_CONCRETE (1 << 1) +#define MA_DEPTH_TRANSP (1 << 2) /* mapflag */ #define MA_MAPFLAG_UVPROJECT (1 << 0) @@ -328,6 +339,7 @@ typedef struct Material { #define MA_OBCOLOR 2 #define MA_APPROX_OCCLUSION 4 #define MA_GROUP_LOCAL 8 +#define MA_INSTANCING 16 /* diff_shader */ #define MA_DIFF_LAMBERT 0 @@ -344,8 +356,9 @@ typedef struct Material { #define MA_SPEC_WARDISO 4 /* dynamode */ -// #define MA_DRAW_DYNABUTS 1 /* deprecated */ -#define MA_FH_NOR 2 +#ifdef DNA_DEPRECATED +# define MA_FH_NOR 2 +#endif /* ramps */ #define MA_RAMP_IN_SHADER 0 @@ -409,6 +422,7 @@ typedef struct Material { #define MAP_DISPLACE 4096 #define MAP_WARP 8192 // #define MAP_LAYER 16384 /* unused */ +#define MAP_PARALLAX 32768 /* volume mapto - reuse definitions for now - a bit naughty! */ #define MAP_DENSITY 128 diff --git a/source/blender/makesdna/DNA_object_force_types.h b/source/blender/makesdna/DNA_object_force_types.h index 6b963bb66a14..117a5a3272d7 100644 --- a/source/blender/makesdna/DNA_object_force_types.h +++ b/source/blender/makesdna/DNA_object_force_types.h @@ -247,6 +247,7 @@ typedef struct BulletSoftBody { float kAHR; /* Anchors hardness [0,1] */ int collisionflags; /* Vertex/Face or Signed Distance Field(SDF) or Clusters, Soft versus Soft or Rigid */ int numclusteriterations; /* number of iterations to refine collision clusters*/ + int bending_dist; /* Bending constraint distance */ float welding; /* welding limit to remove duplicate/nearby vertices, 0.0..0.01 */ float margin; /* margin specific to softbody */ } BulletSoftBody; diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index a9b43a5a9571..290659fe7f9e 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -114,6 +114,21 @@ typedef struct LodLevel { int obhysteresis; } LodLevel; +typedef struct ObjectActivityCulling { + /* For game engine, values around active camera where physics or logic are suspended */ + float physicsRadius; + float logicRadius; + + int flags; + int pad; +} ObjectActivityCulling; + +/* object activity flags */ +enum { + OB_ACTIVITY_PHYSICS = (1 << 0), + OB_ACTIVITY_LOGIC = (1 << 1), +}; + typedef struct Object { ID id; struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */ @@ -225,6 +240,8 @@ typedef struct Object { float step_height; float jump_speed; float fall_speed; + float max_slope; + int pad5; unsigned char max_jumps; char pad2[3]; @@ -246,6 +263,9 @@ typedef struct Object { ListBase sensors; /* game logic sensors */ ListBase controllers; /* game logic controllers */ ListBase actuators; /* game logic actuators */ + ListBase components; /* python components */ + + struct ObjectActivityCulling activityCulling; float sf; /* sf is time-offset */ @@ -261,6 +281,11 @@ typedef struct Object { short softflag; /* softbody settings */ float anisotropicFriction[3]; + /* dynamic properties */ + float friction, rolling_friction, fh, reflect; + float fhdist, xyfrict; + short dynamode, pad6[3]; + ListBase constraints; /* object constraints */ ListBase nlastrips DNA_DEPRECATED; // XXX deprecated... old animation system ListBase hooks DNA_DEPRECATED; // XXX deprecated... old animation system @@ -300,8 +325,11 @@ typedef struct Object { ListBase lodlevels; /* contains data for levels of detail */ LodLevel *currentlod; + float lodfactor, pad4; struct PreviewImage *preview; + + struct Mesh *gamePredefinedBound; } Object; /* Warning, this is not used anymore because hooks are now modifiers */ @@ -344,6 +372,9 @@ typedef struct DupliObject { /* **************** OBJECT ********************* */ +/* dynamode */ +#define OB_FH_NOR 2 + /* used many places... should be specialized */ #define SELECT 1 @@ -489,6 +520,7 @@ enum { OB_BOUND_CONVEX_HULL = 5, /* OB_BOUND_DYN_MESH = 6, */ /*UNUSED*/ OB_BOUND_CAPSULE = 7, + OB_BOUND_EMPTY = 8, }; /* lod flags */ @@ -574,13 +606,10 @@ enum { OB_NAVMESH = 1 << 20, OB_HASOBSTACLE = 1 << 21, OB_CHARACTER = 1 << 22, - - OB_RECORD_ANIMATION = 1 << 23, }; /* ob->gameflag2 */ enum { - OB_NEVER_DO_ACTIVITY_CULLING = 1 << 0, OB_LOCK_RIGID_BODY_X_AXIS = 1 << 2, OB_LOCK_RIGID_BODY_Y_AXIS = 1 << 3, OB_LOCK_RIGID_BODY_Z_AXIS = 1 << 4, diff --git a/source/blender/makesdna/DNA_python_component_types.h b/source/blender/makesdna/DNA_python_component_types.h new file mode 100644 index 000000000000..fbd91c7c739f --- /dev/null +++ b/source/blender/makesdna/DNA_python_component_types.h @@ -0,0 +1,65 @@ +/** + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Mitchell Stokes, Diego Lopes, Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __DNA_COMPONENT_TYPES_H__ +#define __DNA_COMPONENT_TYPES_H__ + +#include "DNA_listBase.h" + +typedef struct PythonComponentProperty { + struct PythonComponentProperty *next, *prev; + char name[128]; /* 128 = MAX_PROPSTRING */ + short type; + short boolval; + int intval; + float floatval; + char strval[128]; /* 128 = MAX_PROPSTRING */ + int itemval; + float vec[4]; + ListBase enumval; +} PythonComponentProperty; + +typedef struct PythonComponent { + struct PythonComponent *next, *prev; + ListBase properties; + char name[1024]; /* 1024 = FILE_MAX */ + char module[1024]; /* 1024 = FILE_MAX */ + int flag; + int pad; +} PythonComponent; + + +/* PythonComponentProperty.type */ +#define CPROP_TYPE_INT 0 +#define CPROP_TYPE_FLOAT 1 +#define CPROP_TYPE_STRING 2 +#define CPROP_TYPE_BOOLEAN 3 +#define CPROP_TYPE_SET 4 +#define CPROP_TYPE_VEC2 5 +#define CPROP_TYPE_VEC3 6 +#define CPROP_TYPE_VEC4 7 + +enum { + COMPONENT_SHOW = (1 << 0) +}; + +#endif /* __DNA_COMPONENT_TYPES_H__ */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 2a62adae21ff..666a67093c20 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -747,13 +747,6 @@ typedef struct RenderData { short jp2_preset DNA_DEPRECATED, jp2_depth DNA_DEPRECATED; /*deprecated*/ int rpad3; - /* Dome variables */ // XXX deprecated since 2.5 - short domeres DNA_DEPRECATED, domemode DNA_DEPRECATED; // XXX deprecated since 2.5 - short domeangle DNA_DEPRECATED, dometilt DNA_DEPRECATED; // XXX deprecated since 2.5 - float domeresbuf DNA_DEPRECATED; // XXX deprecated since 2.5 - float pad2; - struct Text *dometext DNA_DEPRECATED; // XXX deprecated since 2.5 - /* Freestyle line thickness options */ int line_thickness_mode; float unit_line_thickness; /* in pixels */ @@ -799,24 +792,6 @@ typedef struct RenderProfile { } RenderProfile; -/* *************************************************************** */ -/* Game Engine - Dome */ - -typedef struct GameDome { - short res, mode; - short angle, tilt; - float resbuf, pad2; - struct Text *warptext; -} GameDome; - -/* GameDome.mode */ -#define DOME_FISHEYE 1 -#define DOME_TRUNCATED_FRONT 2 -#define DOME_TRUNCATED_REAR 3 -#define DOME_ENVMAP 4 -#define DOME_PANORAM_SPH 5 -#define DOME_NUM_MODES 6 - /* *************************************************************** */ /* Game Engine */ @@ -860,59 +835,59 @@ typedef struct GameData { struct GameFraming framing; short playerflag, xplay, yplay, freqplay; short depth, attrib, rt1, rt2; - short aasamples, pad4[3]; - - /* stereo/dome mode */ - struct GameDome dome; - short stereoflag, stereomode; - float eyeseparation; - RecastData recastData; - + short aasamples; + short hdr; /* physics (it was in world)*/ float gravity; /*Gravitation constant for the game world*/ - /* - * Radius of the activity bubble, in Manhattan length. Objects - * outside the box are activity-culled. */ - float activityBoxRadius; + short stereoflag, stereomode; + float eyeseparation; + RecastData recastData; /* * bit 3: (gameengine): Activity culling is enabled. * bit 5: (gameengine) : enable Bullet DBVT tree for view frustum culling */ int flag; - short mode, matmode; + short mode; short occlusionRes; /* resolution of occlusion Z buffer in pixel */ short physicsEngine; + short solverType; short exitkey; + short pythonkeys[4]; short vsync; /* Controls vsync: off, on, or adaptive (if supported) */ - short ticrate, maxlogicstep, physubstep, maxphystep; short obstacleSimulation; - short raster_storage; + short ticrate, maxlogicstep, physubstep, maxphystep; + short pad5; + float timeScale; float levelHeight; float deactivationtime, lineardeactthreshold, angulardeactthreshold; + /* Debug options */ + short showBoundingBox; + short showArmatures; + short showCameraFrustum; + short showShadowFrustum; + /* Scene LoD */ short lodflag, pad2; - int scehysteresis, pad5; + int scehysteresis; + short colorManagement, pad3[3]; } GameData; /* GameData.stereoflag */ #define STEREO_NOSTEREO 1 #define STEREO_ENABLED 2 -#define STEREO_DOME 3 /* GameData.stereomode */ -//#define STEREO_NOSTEREO 1 #define STEREO_QUADBUFFERED 2 #define STEREO_ABOVEBELOW 3 #define STEREO_INTERLACED 4 #define STEREO_ANAGLYPH 5 #define STEREO_SIDEBYSIDE 6 #define STEREO_VINTERLACE 7 -//#define STEREO_DOME 8 #define STEREO_3DTVTOPBOTTOM 9 /* GameData.physicsEngine */ @@ -924,16 +899,12 @@ typedef struct GameData { #define OBSTSIMULATION_TOI_rays 1 #define OBSTSIMULATION_TOI_cells 2 -/* GameData.raster_storage */ -#define RAS_STORE_AUTO 0 -/* #define RAS_STORE_IMMEDIATE 1 */ /* DEPRECATED */ -#define RAS_STORE_VA 2 -#define RAS_STORE_VBO 3 - /* GameData.vsync */ -#define VSYNC_ON 0 -#define VSYNC_OFF 1 -#define VSYNC_ADAPTIVE 2 +enum { + VSYNC_ON = 0, + VSYNC_OFF, + VSYNC_ADAPTIVE +}; /* GameData.flag */ #define GAME_RESTRICT_ANIM_UPDATES (1 << 0) @@ -941,7 +912,6 @@ typedef struct GameData { #define GAME_SHOW_DEBUG_PROPS (1 << 2) #define GAME_SHOW_FRAMERATE (1 << 3) #define GAME_SHOW_PHYSICS (1 << 4) -#define GAME_DISPLAY_LISTS (1 << 5) #define GAME_GLSL_NO_LIGHTS (1 << 6) #define GAME_GLSL_NO_SHADERS (1 << 7) #define GAME_GLSL_NO_SHADOWS (1 << 8) @@ -949,14 +919,21 @@ typedef struct GameData { #define GAME_GLSL_NO_NODES (1 << 10) #define GAME_GLSL_NO_EXTRA_TEX (1 << 11) #define GAME_IGNORE_DEPRECATION_WARNINGS (1 << 12) -#define GAME_ENABLE_ANIMATION_RECORD (1 << 13) #define GAME_SHOW_MOUSE (1 << 14) -#define GAME_GLSL_NO_COLOR_MANAGEMENT (1 << 15) #define GAME_SHOW_OBSTACLE_SIMULATION (1 << 16) -#define GAME_NO_MATERIAL_CACHING (1 << 17) -#define GAME_GLSL_NO_ENV_LIGHTING (1 << 18) +#ifdef DNA_DEPRECATED +# define GAME_SHOW_BOUNDING_BOX (1 << 18) +# define GAME_SHOW_ARMATURES (1 << 19) +#endif +#define GAME_PYTHON_CONSOLE (1 << 20) +#define GAME_GLSL_NO_ENV_LIGHTING (1 << 21) +#define GAME_SHOW_RENDER_QUERIES (1 << 22) /* Note: GameData.flag is now an int (max 32 flags). A short could only take 16 flags */ +#define GAME_DEBUG_DISABLE 0 +#define GAME_DEBUG_FORCE 1 +#define GAME_DEBUG_ALLOW 2 + /* GameData.playerflag */ #define GAME_PLAYER_FULLSCREEN (1 << 0) #define GAME_PLAYER_DESKTOP_RESOLUTION (1 << 1) @@ -965,14 +942,33 @@ typedef struct GameData { enum { #ifdef DNA_DEPRECATED GAME_MAT_TEXFACE = 0, /* deprecated */ -#endif GAME_MAT_MULTITEX = 1, GAME_MAT_GLSL = 2, +#endif }; /* GameData.lodflag */ #define SCE_LOD_USE_HYST (1 << 0) +/* GameData.hdr */ +#define GAME_HDR_NONE 0 +#define GAME_HDR_HALF_FLOAT 1 +#define GAME_HDR_FULL_FLOAT 2 + +/* GameData.solverType */ +enum { + GAME_SOLVER_SEQUENTIAL = 0, + GAME_SOLVER_NNCG, + GAME_SOLVER_MLCP_DANTZIG, + GAME_SOLVER_MLCP_LEMKE, +}; + +/* GameData.colorManagement */ +enum { + GAME_COLOR_MANAGEMENT_LINEAR = 0, + GAME_COLOR_MANAGEMENT_SRGB +}; + /* UV Paint */ /* ToolSettings.uv_sculpt_settings */ #define UV_SCULPT_LOCK_BORDERS 1 diff --git a/source/blender/makesdna/DNA_sensor_types.h b/source/blender/makesdna/DNA_sensor_types.h index 1fee490319f8..cd57d06adb31 100644 --- a/source/blender/makesdna/DNA_sensor_types.h +++ b/source/blender/makesdna/DNA_sensor_types.h @@ -60,6 +60,7 @@ typedef struct bMouseSensor { short mode; /* flag to choose material or property */ char propname[64]; char matname[64]; + int mask; } bMouseSensor; /* DEPRECATED */ @@ -134,6 +135,7 @@ typedef struct bRaySensor { short mode; short pad1; int axisflag; + int mask; } bRaySensor; typedef struct bArmatureSensor { @@ -188,11 +190,15 @@ typedef struct bJoystickSensor { short axis_single; int axisf; int button; - int hat; - int hatf; int precision; } bJoystickSensor; +typedef struct bMovementSensor { + int axisflag; + int localflag; + float threshold, pad; +} bMovementSensor; + /* bMouseSensor->type: uses blender event defines */ /* bMouseSensor->flag: only pulse for now */ @@ -217,6 +223,20 @@ typedef struct bJoystickSensor { #define SENS_RAY_NEG_Z_AXIS 5 //#define SENS_RAY_NEGATIVE_AXIS 1 +/* movementSensor->axisflag */ +/* flip x and y to make y default!!! */ +#define SENS_MOVEMENT_X_AXIS 0 +#define SENS_MOVEMENT_Y_AXIS 1 +#define SENS_MOVEMENT_Z_AXIS 2 +#define SENS_MOVEMENT_NEG_X_AXIS 3 +#define SENS_MOVEMENT_NEG_Y_AXIS 4 +#define SENS_MOVEMENT_NEG_Z_AXIS 5 +#define SENS_MOVEMENT_ALL_AXIS 6 + +/* movementSensor->localflag */ +/* Flag to toggle local/global coordinates*/ +#define SENS_MOVEMENT_LOCAL 1 + /* bRadarSensor->axis */ #define SENS_RADAR_X_AXIS 0 #define SENS_RADAR_Y_AXIS 1 @@ -254,6 +274,7 @@ typedef struct bJoystickSensor { #define SENS_ACTUATOR 12 #define SENS_DELAY 13 #define SENS_ARMATURE 14 +#define SENS_MOVEMENT 15 /* sensor->flag */ #define SENS_SHOW 1 #define SENS_DEL 2 @@ -303,15 +324,34 @@ typedef struct bJoystickSensor { #define SENS_JOY_ANY_EVENT 1 #define SENS_JOY_BUTTON 0 /* axis type */ +#define SENS_JOY_BUTTON_PRESSED 0 +#define SENS_JOY_BUTTON_RELEASED 1 +#define SENS_JOY_BUTTON_A 0 +#define SENS_JOY_BUTTON_B 1 +#define SENS_JOY_BUTTON_X 2 +#define SENS_JOY_BUTTON_Y 3 +#define SENS_JOY_BUTTON_BACK 4 +#define SENS_JOY_BUTTON_GUIDE 5 +#define SENS_JOY_BUTTON_START 6 +#define SENS_JOY_BUTTON_STICK_LEFT 7 +#define SENS_JOY_BUTTON_STICK_RIGHT 8 +#define SENS_JOY_BUTTON_SHOULDER_LEFT 9 +#define SENS_JOY_BUTTON_SHOULDER_RIGHT 10 +#define SENS_JOY_BUTTON_DPAD_UP 11 +#define SENS_JOY_BUTTON_DPAD_DOWN 12 +#define SENS_JOY_BUTTON_DPAD_LEFT 13 +#define SENS_JOY_BUTTON_DPAD_RIGHT 14 #define SENS_JOY_AXIS 1 /* axis type */ +#define SENS_JOY_LEFT_STICK 1 +#define SENS_JOY_RIGHT_STICK 2 #define SENS_JOY_X_AXIS 0 #define SENS_JOY_Y_AXIS 1 #define SENS_JOY_NEG_X_AXIS 2 #define SENS_JOY_NEG_Y_AXIS 3 #define SENS_JOY_PRECISION 4 -#define SENS_JOY_HAT 2 /* axis type */ +#define SENS_JOY_HAT 2 /* axis type */ /* Unused all Hat related defines */ #define SENS_JOY_HAT_DIR 0 #define SENS_JOY_HAT_UP 1 #define SENS_JOY_HAT_RIGHT 2 @@ -323,9 +363,15 @@ typedef struct bJoystickSensor { #define SENS_JOY_HAT_UP_LEFT SENS_JOY_HAT_UP | SENS_JOY_HAT_LEFT #define SENS_JOY_HAT_DOWN_LEFT SENS_JOY_HAT_DOWN | SENS_JOY_HAT_LEFT - #define SENS_JOY_AXIS_SINGLE 3 /* axis type */ - +#define SENS_JOY_LEFT_STICK_HORIZONTAL 1 +#define SENS_JOY_LEFT_STICK_VERTICAL 2 +#define SENS_JOY_RIGHT_STICK_HORIZONTAL 3 +#define SENS_JOY_RIGHT_STICK_VERTICAL 4 + +#define SENS_JOY_SHOULDER_TRIGGER 4 /* axis type */ +#define SENS_JOY_LEFT_SHOULDER_TRIGGER 1 +#define SENS_JOY_RIGHT_SHOULDER_TRIGGER 2 #define SENS_DELAY_REPEAT 1 // should match JOYINDEX_MAX in SCA_JoystickDefines.h */ diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 6879c3044a6c..6988a8e53be7 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -1261,6 +1261,8 @@ typedef struct SpaceLogic { short flag, scaflag; int pad; + char import_string[64]; + struct bGPdata *gpd; /* grease-pencil data */ } SpaceLogic; diff --git a/source/blender/makesdna/DNA_text_types.h b/source/blender/makesdna/DNA_text_types.h index 78902598fdb5..65ab0324de6d 100644 --- a/source/blender/makesdna/DNA_text_types.h +++ b/source/blender/makesdna/DNA_text_types.h @@ -60,6 +60,8 @@ typedef struct Text { int curc, selc; double mtime; + + const char *cmmt_pfx; } Text; #define TXT_TABSIZE 4 diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index 3972cbd2a0e7..e84a207c3dbd 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -63,7 +63,9 @@ typedef struct MTex { char projx, projy, projz, mapping; char brush_map_mode, brush_angle_mode; - char pad[2]; + + short colorManagement; + float ofs[3], size[3], rot, random_angle; short texflag, colormodel, pmapto, pmaptoneg; @@ -76,11 +78,13 @@ typedef struct MTex { /* material */ float norfac, dispfac, warpfac; + float parallaxsteps, parallaxbumpsc; float colspecfac, mirrfac, alphafac; float difffac, specfac, emitfac, hardfac; float raymirrfac, translfac, ambfac; float colemitfac, colreflfac, coltransfac; float densfac, scatterfac, reflfac; + float ior, refrratio; /* particles */ float timefac, lengthfac, clumpfac, dampfac; @@ -93,6 +97,11 @@ typedef struct MTex { /* world */ float zenupfac, zendownfac, blendfac; + + float lodbias; + + /* parallax */ + short parflag, parallaxcomp; } MTex; #ifndef DNA_USHORT_FIX @@ -134,6 +143,9 @@ typedef struct EnvMap { short cuberes, depth; int ok, lastframe; short recalc, lastsize; + int flag, filtering; + int mode; + float lodfactor; } EnvMap; typedef struct PointDensity { @@ -467,6 +479,20 @@ typedef struct ColorMapping { #define TEX_PR_OTHER 1 #define TEX_PR_BOTH 2 +/* **************** ENVMAP ****************** */ + +/* flag */ +#define ENVMAP_AUTO_UPDATE (1 << 0) + +/* mode */ +#define ENVMAP_REFLECTION 0 +#define ENVMAP_REFRACTION 1 + +/* filtering */ +#define ENVMAP_MIPMAP_NONE 0 +#define ENVMAP_MIPMAP_LINEAR 1 +#define ENVMAP_MIPMAP_MIPMAP 2 + /* **************** MTEX ********************* */ /* proj */ @@ -493,6 +519,10 @@ typedef struct ColorMapping { #define MTEX_BICUBIC_BUMP 8192 #define MTEX_MAPTO_BOUNDS 16384 +#define MTEX_PARALLAX_UV 32768 // texflag +#define MTEX_DISCARD_AT_EDGES 1 // parflag + + /* blendtype */ #define MTEX_BLEND 0 #define MTEX_MUL 1 @@ -560,6 +590,7 @@ enum { #define ENV_STATIC 0 #define ENV_ANIM 1 #define ENV_LOAD 2 +#define ENV_REALT 3 /* ok */ #define ENV_NORMAL 1 diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 1b3eef0f3ec7..9fde815464c0 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -314,6 +314,7 @@ typedef struct View3D { #define V3D_OCCLUDE_WIRE (1 << 14) #define V3D_SHADELESS_TEX (1 << 15) #define V3D_SHOW_WORLD (1 << 16) +#define V3D_SHOW_MIST (1 << 17) /* View3D->around */ diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index 3b8d0e01ace2..8b4d5a4ab4e0 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -129,6 +129,7 @@ static const char *includefiles[] = { "DNA_rigidbody_types.h", "DNA_freestyle_types.h", "DNA_linestyle_types.h", + "DNA_python_component_types.h", "DNA_cachefile_types.h", /* see comment above before editing! */ @@ -1342,5 +1343,6 @@ int main(int argc, char **argv) #include "DNA_rigidbody_types.h" #include "DNA_freestyle_types.h" #include "DNA_linestyle_types.h" +#include "DNA_python_component_types.h" #include "DNA_cachefile_types.h" /* end of list */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index a026d8e875ee..641a10dbfae9 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -421,6 +421,7 @@ extern StructRNA RNA_Modifier; extern StructRNA RNA_MotionPath; extern StructRNA RNA_MotionPathVert; extern StructRNA RNA_MouseSensor; +extern StructRNA RNA_MovementSensor; extern StructRNA RNA_MovieSequence; extern StructRNA RNA_MovieClipSequence; extern StructRNA RNA_MovieTracking; @@ -489,6 +490,7 @@ extern StructRNA RNA_Property; extern StructRNA RNA_PropertyGroup; extern StructRNA RNA_PropertyGroupItem; extern StructRNA RNA_PropertySensor; +extern StructRNA RNA_PythonComponent; extern StructRNA RNA_PythonConstraint; extern StructRNA RNA_PythonController; extern StructRNA RNA_RadarSensor; @@ -525,6 +527,7 @@ extern StructRNA RNA_SequenceTransform; extern StructRNA RNA_NormalEditModifier; extern StructRNA RNA_ShaderNode; extern StructRNA RNA_ShaderNodeCameraData; +extern StructRNA RNA_ShaderNodeObjectData; extern StructRNA RNA_ShaderNodeCombineRGB; extern StructRNA RNA_ShaderNodeExtendedMaterial; extern StructRNA RNA_ShaderNodeGeometry; diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h index 64740098db4a..196895451ba8 100644 --- a/source/blender/makesrna/RNA_enum_types.h +++ b/source/blender/makesrna/RNA_enum_types.h @@ -177,6 +177,7 @@ extern const EnumPropertyItem rna_enum_node_icon_items[]; extern const EnumPropertyItem rna_enum_node_math_items[]; extern const EnumPropertyItem rna_enum_node_vec_math_items[]; extern const EnumPropertyItem rna_enum_node_filter_items[]; +extern const EnumPropertyItem rna_enum_node_parallax_items[]; extern const EnumPropertyItem rna_enum_ramp_blend_items[]; diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 5e7438ce4ee1..c84f06203c34 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -72,6 +72,7 @@ set(DEFSRC rna_palette.c rna_particle.c rna_pose.c + rna_python_component.c rna_property.c rna_render.c rna_rigidbody.c diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 4b58e13d994c..4bb250bf8462 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -3389,6 +3389,7 @@ static RNAProcessItem PROCESS_ITEMS[] = { {"rna_palette.c", NULL, RNA_def_palette}, {"rna_particle.c", NULL, RNA_def_particle}, {"rna_pose.c", "rna_pose_api.c", RNA_def_pose}, + {"rna_python_component.c", NULL, RNA_def_py_component}, {"rna_property.c", NULL, RNA_def_gameproperty}, {"rna_render.c", NULL, RNA_def_render}, {"rna_rigidbody.c", NULL, RNA_def_rigidbody}, diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c index 6f0ff9aa5565..22fdbaa9ba1c 100644 --- a/source/blender/makesrna/intern/rna_actuator.c +++ b/source/blender/makesrna/intern/rna_actuator.c @@ -65,6 +65,7 @@ static const EnumPropertyItem actuator_type_items[] = { {ACT_SOUND, "SOUND", 0, "Sound", ""}, {ACT_STATE, "STATE", 0, "State", ""}, {ACT_STEERING, "STEERING", 0, "Steering", ""}, + {ACT_VIBRATION, "VIBRATION", 0, "Vibration", ""}, {ACT_VISIBILITY, "VISIBILITY", 0, "Visibility", ""}, {0, NULL, 0, NULL, NULL} }; @@ -100,6 +101,8 @@ static StructRNA *rna_Actuator_refine(struct PointerRNA *ptr) return &RNA_MessageActuator; case ACT_GAME: return &RNA_GameActuator; + case ACT_VIBRATION: + return &RNA_VibrationActuator; case ACT_VISIBILITY: return &RNA_VisibilityActuator; case ACT_2DFILTER: @@ -469,6 +472,7 @@ const EnumPropertyItem *rna_Actuator_type_itemf(bContext *C, PointerRNA *ptr, Pr RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_SOUND); RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_STATE); + RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_VIBRATION); RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_VISIBILITY); RNA_enum_item_end(&item, &totitem); @@ -689,11 +693,6 @@ static void rna_def_action_actuator(BlenderRNA *brna) RNA_def_property_ui_text(prop, "L", "Let the Action act in local coordinates, used in Force and Add mode"); RNA_def_property_update(prop, NC_LOGIC, NULL); - prop = RNA_def_property(srna, "apply_to_children", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_IPOCHILD); - RNA_def_property_ui_text(prop, "Child", "Update Action on all children Objects as well"); - RNA_def_property_update(prop, NC_LOGIC, NULL); - prop = RNA_def_property(srna, "blend_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "blend_mode"); RNA_def_property_enum_items(prop, prop_blend_items); @@ -721,6 +720,12 @@ static void rna_def_object_actuator(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem prop_servo_type_items[] = { + {ACT_SERVO_LINEAR, "SERVO_LINEAR", 0, "Linear", ""}, + {ACT_SERVO_ANGULAR, "SERVO_ANGULAR", 0, "Angular", ""}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "ObjectActuator", "Actuator"); RNA_def_struct_ui_text(srna, "Motion Actuator", "Actuator to control the object movement"); RNA_def_struct_sdna_from(srna, "bObjectActuator", "data"); @@ -733,6 +738,11 @@ static void rna_def_object_actuator(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Motion Type", "Specify the motion system"); RNA_def_property_update(prop, NC_LOGIC, NULL); + prop = RNA_def_property(srna, "servo_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "servotype"); + RNA_def_property_enum_items(prop, prop_servo_type_items); + RNA_def_property_ui_text(prop, "Servo Type", "Specify the servo control system"); + prop = RNA_def_property(srna, "reference_object", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "Object"); RNA_def_property_pointer_sdna(prop, NULL, "reference"); @@ -891,17 +901,17 @@ static void rna_def_object_actuator(BlenderRNA *brna) prop = RNA_def_property(srna, "use_servo_limit_x", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_SERVO_LIMIT_X); - RNA_def_property_ui_text(prop, "X", "Set limit to force along the X axis"); + RNA_def_property_ui_text(prop, "X", "Set limit to force/torque along the X axis"); RNA_def_property_update(prop, NC_LOGIC, NULL); prop = RNA_def_property(srna, "use_servo_limit_y", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_SERVO_LIMIT_Y); - RNA_def_property_ui_text(prop, "Y", "Set limit to force along the Y axis"); + RNA_def_property_ui_text(prop, "Y", "Set limit to force/torque along the Y axis"); RNA_def_property_update(prop, NC_LOGIC, NULL); prop = RNA_def_property(srna, "use_servo_limit_z", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_SERVO_LIMIT_Z); - RNA_def_property_ui_text(prop, "Z", "Set limit to force along the Z axis"); + RNA_def_property_ui_text(prop, "Z", "Set limit to force/torque along the Z axis"); RNA_def_property_update(prop, NC_LOGIC, NULL); prop = RNA_def_property(srna, "use_character_jump", PROP_BOOLEAN, PROP_NONE); @@ -1345,6 +1355,8 @@ static void rna_def_edit_object_actuator(BlenderRNA *brna) {ACT_EDOB_ENABLE_RB, "ENABLERIGIDBODY", 0, "Enable Rigid Body", ""}, {ACT_EDOB_DISABLE_RB, "DISABLERIGIDBODY", 0, "Disable Rigid Body", ""}, {ACT_EDOB_SET_MASS, "SETMASS", 0, "Set Mass", ""}, + {ACT_EDOB_RESTORE_PHY, "RESTOREPHY", 0, "Restore Physics", ""}, + {ACT_EDOB_SUSPEND_PHY, "SUSPENDPHY", 0, "Suspend Physics", ""}, {0, NULL, 0, NULL, NULL} }; @@ -1426,8 +1438,8 @@ static void rna_def_edit_object_actuator(BlenderRNA *brna) RNA_def_property_pointer_funcs(prop, NULL, "rna_Actuator_editobject_mesh_set", NULL, NULL); RNA_def_property_update(prop, NC_LOGIC, NULL); - prop = RNA_def_property(srna, "time", PROP_INT, PROP_NONE); - RNA_def_property_ui_range(prop, 0, 2000, 1, 1); + prop = RNA_def_property(srna, "time", PROP_FLOAT, PROP_NONE); + RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, 2); RNA_def_property_ui_text(prop, "Time", "Duration the new Object lives or the track takes"); RNA_def_property_update(prop, NC_LOGIC, NULL); @@ -1730,6 +1742,52 @@ static void rna_def_game_actuator(BlenderRNA *brna) /*XXX to do: an operator that calls file_browse with relative_path on and blender filtering active */ } +static void rna_def_vibration_actuator(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static EnumPropertyItem prop_mode_items[] = { + {ACT_VIBRATION_PLAY, "PLAY", 0, "Play", ""}, + {ACT_VIBRATION_STOP, "STOP", 0, "Stop", ""}, + {0, NULL, 0, NULL, NULL} + }; + + srna = RNA_def_struct(brna, "VibrationActuator", "Actuator"); + RNA_def_struct_ui_text(srna, "Vibration Actuator", "Actuator to set vibration of a joystick"); + RNA_def_struct_sdna_from(srna, "bVibrationActuator", "data"); + + prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "mode"); + RNA_def_property_enum_items(prop, prop_mode_items); + RNA_def_property_ui_text(prop, "Vibration Mode", "Joystick vibration mode"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop = RNA_def_property(srna, "joy_index", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "joyindex"); + RNA_def_property_range(prop, 0, 7); + RNA_def_property_ui_text(prop, "JoyIndex", "Joystick index"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop = RNA_def_property(srna, "joy_duration", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "duration"); + RNA_def_property_range(prop, 0, INT_MAX); + RNA_def_property_ui_text(prop, "Duration", "Joystick vibration duration"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop = RNA_def_property(srna, "joy_strength_left", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "strength"); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_ui_text(prop, "Strength Low Freq", "Joystick vibration strength for low frequency motor"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop = RNA_def_property(srna, "joy_strength_right", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "strength_right"); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_ui_text(prop, "Strength High Freq", "Joystick vibration strength for high frequency motor"); + RNA_def_property_update(prop, NC_LOGIC, NULL); +} + static void rna_def_visibility_actuator(BlenderRNA *brna) { StructRNA *srna; @@ -1808,6 +1866,11 @@ static void rna_def_twodfilter_actuator(BlenderRNA *brna) RNA_def_property_range(prop, 0, 99); /*MAX_RENDER_PASS-1 */ RNA_def_property_update(prop, NC_LOGIC, NULL); + prop = RNA_def_property(srna, "use_mipmap", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mipmap", 1); + RNA_def_property_ui_text(prop, "Use MipMap", "Enable MipMap for rendered texture"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + prop = RNA_def_property(srna, "motion_blur_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "float_arg"); RNA_def_property_ui_text(prop, "Value", "Motion blur factor"); @@ -2208,6 +2271,7 @@ void RNA_def_actuator(BlenderRNA *brna) rna_def_random_actuator(brna); rna_def_message_actuator(brna); rna_def_game_actuator(brna); + rna_def_vibration_actuator(brna); rna_def_visibility_actuator(brna); rna_def_twodfilter_actuator(brna); rna_def_parent_actuator(brna); diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c index 981ae75e7c5c..4942c77b4a56 100644 --- a/source/blender/makesrna/intern/rna_camera.c +++ b/source/blender/makesrna/intern/rna_camera.c @@ -182,6 +182,35 @@ static void rna_def_camera_stereo_data(BlenderRNA *brna) RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); } +static void rna_def_game_camera_viewport_data(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "GameCameraViewportData", NULL); + RNA_def_struct_sdna(srna, "GameCameraViewportSettings"); + RNA_def_struct_nested(brna, srna, "Camera"); + RNA_def_struct_ui_text(srna, "Viewport", "Game custom camera viewport settings"); + + prop = RNA_def_property(srna, "left_ratio", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "leftratio"); + RNA_def_property_ui_text(prop, "Left Ratio", "Set camera viewport left to a ratio of the entire viewport width"); + + prop = RNA_def_property(srna, "right_ratio", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "rightratio"); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_ui_text(prop, "Right Ratio", "Set camera viewport right to a ratio of the entire viewport width"); + + prop = RNA_def_property(srna, "bottom_ratio", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "bottomratio"); + RNA_def_property_ui_text(prop, "Bottom Ratio", "Set camera viewport bottom to a ratio of the entire viewport height"); + + prop = RNA_def_property(srna, "top_ratio", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "topratio"); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_ui_text(prop, "Top Ratio", "Set camera viewport top to a ratio of the entire viewport height"); +} + void RNA_def_camera(BlenderRNA *brna) { StructRNA *srna; @@ -336,6 +365,13 @@ void RNA_def_camera(BlenderRNA *brna) RNA_def_property_ui_text(prop, "DOF Distance", "Distance to the focus point for depth of field"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Camera_dof_update"); + prop = RNA_def_property(srna, "lod_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "lodfactor"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_ui_text(prop, "Level of Detail Distance Factor", "The factor applied to distance computed in Lod"); + RNA_def_property_update(prop, NC_OBJECT | ND_LOD, NULL); + /* Stereo Settings */ prop = RNA_def_property(srna, "stereo", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); @@ -343,7 +379,32 @@ void RNA_def_camera(BlenderRNA *brna) RNA_def_property_struct_type(prop, "CameraStereoData"); RNA_def_property_ui_text(prop, "Stereo", ""); + /* Stereo Settings */ + prop = RNA_def_property(srna, "viewport", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_pointer_sdna(prop, NULL, "gameviewport"); + RNA_def_property_struct_type(prop, "GameCameraViewportData"); + /* flag */ + prop = RNA_def_property(srna, "override_culling", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "gameflag", GAME_CAM_OVERRIDE_CULLING); + RNA_def_property_ui_text(prop, "Override Culling", "Use only this camera for scene culling in Game Engine"); + RNA_def_property_update(prop, NC_CAMERA, NULL); + + prop = RNA_def_property(srna, "show_frustum", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "gameflag", GAME_CAM_SHOW_FRUSTUM); + RNA_def_property_ui_text(prop, "Show Frustum", "Show a visualization of frustum in Game Engine"); + RNA_def_property_update(prop, NC_CAMERA, NULL); + + prop = RNA_def_property(srna, "use_viewport", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "gameflag", GAME_CAM_VIEWPORT); + RNA_def_property_ui_text(prop, "Show Frustum", "Show a visualization of frustum in Game Engine"); + RNA_def_property_update(prop, NC_CAMERA, NULL); + + prop = RNA_def_property(srna, "use_object_activity_culling", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "gameflag", GAME_CAM_OBJECT_ACTIVITY_CULLING); + RNA_def_property_ui_text(prop, "Activity Culling", "Enable object activity culling with this camera"); + prop = RNA_def_property(srna, "show_limits", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_SHOWLIMITS); RNA_def_property_ui_text(prop, "Show Limits", "Draw the clipping range and focus point on the camera"); @@ -407,6 +468,9 @@ void RNA_def_camera(BlenderRNA *brna) /* *** Animated *** */ rna_def_camera_stereo_data(brna); + /* Game Data */ + rna_def_game_camera_viewport_data(brna); + /* Camera API */ RNA_api_camera(srna); } diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index 4b563bf66598..e3e7b68dbc90 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -1494,6 +1494,15 @@ static void rna_def_constraint_rigid_body_joint(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", 32); RNA_def_property_ui_text(prop, "Angular Z Limit", "Use minimum/maximum Z angular limit"); RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update"); + + prop = RNA_def_property(srna, "use_breaking", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", CONSTRAINT_USE_BREAKING); + RNA_def_property_ui_text(prop, "Use Breaking", "Allow breaking on high impulse"); + + prop = RNA_def_property(srna, "breaking_threshold", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "breaking"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_text(prop, "Breaking Impulse Threshold", "Break on impulse greater than threshold"); } static void rna_def_constraint_clamp_to(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index c3ccdc6f446f..e640800ec5ba 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -166,6 +166,7 @@ void RNA_def_packedfile(struct BlenderRNA *brna); void RNA_def_palette(struct BlenderRNA *brna); void RNA_def_particle(struct BlenderRNA *brna); void RNA_def_pose(struct BlenderRNA *brna); +void RNA_def_py_component(struct BlenderRNA *brna); void RNA_def_render(struct BlenderRNA *brna); void RNA_def_rigidbody(struct BlenderRNA *brna); void RNA_def_rna(struct BlenderRNA *brna); diff --git a/source/blender/makesrna/intern/rna_lamp.c b/source/blender/makesrna/intern/rna_lamp.c index 1e1ae2e81832..b4a68fe778be 100644 --- a/source/blender/makesrna/intern/rna_lamp.c +++ b/source/blender/makesrna/intern/rna_lamp.c @@ -223,6 +223,12 @@ static void rna_def_lamp_mtex(BlenderRNA *brna) RNA_def_property_ui_range(prop, 0, 1, 10, 3); RNA_def_property_ui_text(prop, "Shadow Factor", "Amount texture affects shadow"); RNA_def_property_update(prop, 0, "rna_Lamp_update"); + + prop = RNA_def_property(srna, "lod_bias", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "lodbias"); + RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 10, 3); + RNA_def_property_ui_text(prop, "Lod Bias", "Amount bias on mipmapping"); + RNA_def_property_update(prop, 0, "rna_Lamp_update"); } static void rna_def_lamp_sky_settings(BlenderRNA *brna) @@ -420,6 +426,7 @@ static void rna_def_lamp_falloff(StructRNA *srna) {LA_FALLOFF_CONSTANT, "CONSTANT", 0, "Constant", ""}, {LA_FALLOFF_INVLINEAR, "INVERSE_LINEAR", 0, "Inverse Linear", ""}, {LA_FALLOFF_INVSQUARE, "INVERSE_SQUARE", 0, "Inverse Square", ""}, + {LA_FALLOFF_INVSQUARE_CUTOFF, "INVSQUARE_CUTOFF", 0, "Inverse Square Cutoff", ""}, {LA_FALLOFF_INVCOEFFICIENTS, "INVERSE_COEFFICIENTS", 0, "Inverse Coefficients", ""}, {LA_FALLOFF_CURVE, "CUSTOM_CURVE", 0, "Custom Curve", ""}, {LA_FALLOFF_SLIDERS, "LINEAR_QUADRATIC_WEIGHTED", 0, "Lin/Quad Weighted", ""}, @@ -473,6 +480,19 @@ static void rna_def_lamp_falloff(StructRNA *srna) RNA_def_property_ui_text(prop, "Quadratic Coefficient", "Quadratic distance attenuation coefficient"); RNA_def_property_update(prop, 0, "rna_Lamp_draw_update"); + + prop = RNA_def_property(srna, "radius", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "radius"); + RNA_def_property_range(prop, 0.001, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001, 1000, 1, 3); + RNA_def_property_ui_text(prop, "Radius", "The ligth's radius"); + RNA_def_property_update(prop, 0, "rna_Lamp_draw_update"); + + prop = RNA_def_property(srna, "cutoff_threshold", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "cutoff"); + RNA_def_property_range(prop, 0.000f, 0.999f); + RNA_def_property_ui_text(prop, "Cutoff", "Cutoff Threshold"); + RNA_def_property_update(prop, 0, "rna_Lamp_draw_update"); } static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area) @@ -539,6 +559,14 @@ static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem prop_shadow_filter_type_items[] = { + {LA_SHADOW_FILTER_NONE, "NONE", 0, "None", "None filtering"}, + {LA_SHADOW_FILTER_PCF, "PCF", 0, "PCF", "Percentage Closer Filtering"}, + {LA_SHADOW_FILTER_PCF_BAIL, "PCF_BAIL", 0, "PCF Early Bail", "Percentage Closer Filtering Early Bail"}, + {LA_SHADOW_FILTER_PCF_JITTER, "PCF_JITTER", 0, "PCF Jitter", "Percentage Closer Filtering Jitter"}, + {0, NULL, 0, NULL, NULL} + }; + prop = RNA_def_property(srna, "use_shadow", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_use_shadow_get", "rna_use_shadow_set"); RNA_def_property_update(prop, 0, "rna_Lamp_draw_update"); @@ -557,6 +585,11 @@ static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area) RNA_def_property_int_funcs(prop, NULL, "rna_Lamp_buffer_size_set", NULL); RNA_def_property_update(prop, 0, "rna_Lamp_update"); + prop = RNA_def_property(srna, "static_shadow", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_STATIC_SHADOW); + RNA_def_property_ui_text(prop, "Static Shadow", + "Enable static shadows"); + prop = RNA_def_property(srna, "shadow_filter_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "filtertype"); RNA_def_property_enum_items(prop, prop_shadbuffiltertype_items); @@ -590,6 +623,12 @@ static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area) RNA_def_property_ui_text(prop, "Shadow Buffer Bias", "Shadow buffer sampling bias"); RNA_def_property_update(prop, 0, "rna_Lamp_update"); + prop = RNA_def_property(srna, "shadow_buffer_slope_bias", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "slopebias"); + RNA_def_property_range(prop, 0.0f, 5.0f); + RNA_def_property_ui_text(prop, "Shadow Buffer Slope Bias", "Shadow buffer sampling slope bias"); + RNA_def_property_update(prop, 0, "rna_Lamp_update"); + prop = RNA_def_property(srna, "shadow_buffer_bleed_bias", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "bleedbias"); RNA_def_property_range(prop, 0.f, 1.f); @@ -602,6 +641,12 @@ static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area) RNA_def_property_ui_text(prop, "Shadow Buffer Soft", "Size of shadow buffer sampling area"); RNA_def_property_update(prop, 0, "rna_Lamp_update"); + prop = RNA_def_property(srna, "shadow_buffer_sharp", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "bufsharp"); + RNA_def_property_range(prop, -1.0f, 1.0f); + RNA_def_property_ui_text(prop, "Shadow Buffer Sharpness", "Sharpness of buffer sampling"); + RNA_def_property_update(prop, 0, "rna_Lamp_update"); + prop = RNA_def_property(srna, "shadow_buffer_samples", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "samp"); RNA_def_property_range(prop, 1, 16); @@ -620,6 +665,11 @@ static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area) RNA_def_property_ui_text(prop, "Shadow Map Type", "The shadow mapping algorithm used"); RNA_def_property_update(prop, 0, "rna_Lamp_update"); + prop = RNA_def_property(srna, "shadow_filter", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "shadow_filter"); + RNA_def_property_enum_items(prop, prop_shadow_filter_type_items); + RNA_def_property_ui_text(prop, "Shadow Map Filter Type", "The shadow mapping filtering algorithm used"); + RNA_def_property_update(prop, 0, "rna_Lamp_update"); prop = RNA_def_property(srna, "use_auto_clip_start", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "bufflag", LA_SHADBUF_AUTO_START); @@ -690,6 +740,12 @@ static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area) RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_LAYER_SHADOW); RNA_def_property_ui_text(prop, "Shadow Layer", "Objects on the same layers only cast shadows"); RNA_def_property_update(prop, 0, "rna_Lamp_update"); + + prop = RNA_def_property(srna, "show_shadow_box", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_SHOW_SHADOW_BOX); + RNA_def_property_ui_text(prop, "Show Shadow Box", + "Draw a box in 3D view to visualize which objects are contained in it"); + RNA_def_property_update(prop, 0, "rna_Lamp_draw_update"); } static void rna_def_point_lamp(BlenderRNA *brna) @@ -847,12 +903,6 @@ static void rna_def_sun_lamp(BlenderRNA *brna) RNA_def_property_ui_range(prop, 0.001, 100.0, 2, 1); RNA_def_property_ui_text(prop, "Frustum Size", "Size of the frustum used for creating the shadow map"); RNA_def_property_update(prop, 0, "rna_Lamp_draw_update"); - - prop = RNA_def_property(srna, "show_shadow_box", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "mode", LA_SHOW_SHADOW_BOX); - RNA_def_property_ui_text(prop, "Show Shadow Box", - "Draw a box in 3D view to visualize which objects are contained in it"); - RNA_def_property_update(prop, 0, "rna_Lamp_draw_update"); } static void rna_def_hemi_lamp(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index 4947557af103..c2e8962745e5 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -29,6 +29,7 @@ #include "DNA_material_types.h" #include "DNA_texture_types.h" +#include "DNA_scene_types.h" #include "RNA_define.h" #include "RNA_enum_types.h" @@ -149,11 +150,6 @@ static PointerRNA rna_Material_strand_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_MaterialStrand, ptr->id.data); } -static PointerRNA rna_Material_physics_get(PointerRNA *ptr) -{ - return rna_pointer_inherit_refine(ptr, &RNA_MaterialPhysics, ptr->id.data); -} - static void rna_Material_type_set(PointerRNA *ptr, int value) { Material *ma = (Material *)ptr->data; @@ -500,6 +496,20 @@ static void rna_def_material_mtex(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem color_management_items[] = { + {GAME_COLOR_MANAGEMENT_LINEAR, "COLOR_MANAGEMENT_LINEAR", 0, "Linear", "Linear color space"}, + {GAME_COLOR_MANAGEMENT_SRGB, "COLOR_MANAGEMENT_SRGB", 0, "sRGB", "sRGB color space"}, + {0, NULL, 0, NULL, NULL} + }; + + static const EnumPropertyItem node_parallax_items[] = { + {0, "RED", ICON_COLOR_RED, "Red", ""}, + {1, "GREEN", ICON_COLOR_GREEN, "Green", ""}, + {2, "BLUE", ICON_COLOR_BLUE, "Blue", ""}, + {3, "ALPHA", ICON_IMAGE_ALPHA, "Alpha", ""}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "MaterialTextureSlot", "TextureSlot"); RNA_def_struct_sdna(srna, "MTex"); RNA_def_struct_ui_text(srna, "Material Texture Slot", "Texture slot for textures in a Material data-block"); @@ -552,6 +562,16 @@ static void rna_def_material_mtex(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Normal", "The texture affects the rendered normal"); RNA_def_property_update(prop, 0, "rna_Material_update"); + prop = RNA_def_property(srna, "use_map_parallax", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_PARALLAX); + RNA_def_property_ui_text(prop, "Parallax", "The texture affects the relief depth"); + RNA_def_property_update(prop, 0, "rna_Material_update"); + + prop = RNA_def_property(srna, "use_parallax_uv", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "texflag", MTEX_PARALLAX_UV); + RNA_def_property_ui_text(prop, "Use Parallax UV", "This is necessary for proper use of the parallax mapping"); + RNA_def_property_update(prop, 0, "rna_Material_update"); + prop = RNA_def_property(srna, "use_map_color_spec", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mapto", MAP_COLSPEC); RNA_def_property_ui_text(prop, "Specular Color", "The texture affects the specularity color"); @@ -659,6 +679,41 @@ static void rna_def_material_mtex(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Warp Factor", "Amount texture affects texture coordinates of next channels"); RNA_def_property_update(prop, 0, "rna_Material_update"); + prop = RNA_def_property(srna, "parallax_steps", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "parallaxsteps"); + RNA_def_property_ui_range(prop, 0.0, 100.0, 1.0, 3); + RNA_def_property_ui_text(prop, "Parallax Steps", "Number of steps taken to achieve result"); + RNA_def_property_update(prop, 0, "rna_Material_update"); + + prop = RNA_def_property(srna, "parallax_bump_scale", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "parallaxbumpsc"); + RNA_def_property_ui_range(prop, 0.0, 0.5, 1.0, 3); + RNA_def_property_ui_text(prop, "Parallax Bump Scale", "Height of SPOM"); + RNA_def_property_update(prop, 0, "rna_Material_update"); + + prop = RNA_def_property(srna, "parallax_uv_discard", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "parflag", MTEX_DISCARD_AT_EDGES); + RNA_def_property_ui_text(prop, "Parallax UV discard", "To discard parallax UV at edges"); + RNA_def_property_update(prop, 0, "rna_Material_update"); + + prop = RNA_def_property(srna, "parallax_component", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "parallaxcomp"); + RNA_def_property_enum_items(prop, node_parallax_items); + RNA_def_property_ui_text(prop, "Parallax Component", "The color component to extract the height information from"); + RNA_def_property_update(prop, 0, "rna_Material_update"); + + prop = RNA_def_property(srna, "color_management", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "colorManagement"); + RNA_def_property_enum_items(prop, color_management_items); + RNA_def_property_ui_text(prop, "Color Space", "The color space of the image"); + RNA_def_property_update(prop, 0, "rna_Material_update"); + + prop = RNA_def_property(srna, "lod_bias", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "lodbias"); + RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 10, 3); + RNA_def_property_ui_text(prop, "Lod Bias", "Amount bias on mipmapping"); + RNA_def_property_update(prop, 0, "rna_Material_update"); + prop = RNA_def_property(srna, "specular_color_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "colspecfac"); RNA_def_property_ui_range(prop, 0, 1, 10, 3); @@ -805,6 +860,20 @@ static void rna_def_material_mtex(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Reflection Factor", "Amount texture affects brightness of out-scattered light"); RNA_def_property_update(prop, 0, "rna_Material_update"); + prop = RNA_def_property(srna, "ior", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "ior"); + RNA_def_property_range(prop, 1.0, 50.0); + RNA_def_property_ui_range(prop, 1.0, 50.0, 1, 2); + RNA_def_property_ui_text(prop, "Refraction Indice", "Indice of refraction"); + RNA_def_property_update(prop, 0, "rna_Material_update"); + + prop = RNA_def_property(srna, "refraction_ratio", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "refrratio"); + RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 2); + RNA_def_property_ui_text(prop, "Refraction Ratio", "Amount refraction mixed with reflection"); + RNA_def_property_update(prop, 0, "rna_Material_update"); + /* end volume material */ prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE); @@ -861,11 +930,6 @@ static void rna_def_material_gamesettings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Backface Culling", "Hide Back of the face in Game Engine "); RNA_def_property_update(prop, 0, "rna_Material_draw_update"); - prop = RNA_def_property(srna, "text", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GEMAT_TEXT); /* use bitflags */ - RNA_def_property_ui_text(prop, "Text", "Use material as text in Game Engine "); - RNA_def_property_update(prop, 0, "rna_Material_draw_update"); - prop = RNA_def_property(srna, "invisible", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GEMAT_INVISIBLE); /* use bitflags */ RNA_def_property_ui_text(prop, "Invisible", "Make face invisible"); @@ -882,8 +946,8 @@ static void rna_def_material_gamesettings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Face Orientations", "Especial face orientation options"); prop = RNA_def_property(srna, "physics", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GEMAT_NOPHYSICS); /* use bitflags */ - RNA_def_property_ui_text(prop, "Physics", "Use physics properties of materials "); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GEMAT_NOPHYSICS); + RNA_def_property_ui_text(prop, "Physics", "Use physics for this materials"); } static void rna_def_material_colors(StructRNA *srna) @@ -1723,50 +1787,6 @@ static void rna_def_material_strand(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Material_update"); } -static void rna_def_material_physics(BlenderRNA *brna) -{ - StructRNA *srna; - PropertyRNA *prop; - - srna = RNA_def_struct(brna, "MaterialPhysics", NULL); - RNA_def_struct_sdna(srna, "Material"); - RNA_def_struct_nested(brna, srna, "Material"); - RNA_def_struct_ui_text(srna, "Material Physics", "Physics settings for a Material data-block"); - - prop = RNA_def_property(srna, "friction", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "friction"); - RNA_def_property_range(prop, 0, 100); - RNA_def_property_ui_text(prop, "Friction", "Coulomb friction coefficient, when inside the physics distance area"); - - prop = RNA_def_property(srna, "elasticity", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "reflect"); - RNA_def_property_range(prop, 0, 1); - RNA_def_property_ui_text(prop, "Elasticity", "Elasticity of collisions"); - - /* FH/Force Field Settings */ - prop = RNA_def_property(srna, "use_fh_normal", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "dynamode", MA_FH_NOR); - RNA_def_property_ui_text(prop, "Align to Normal", - "Align dynamic game objects along the surface normal, " - "when inside the physics distance area"); - - prop = RNA_def_property(srna, "fh_force", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "fh"); - RNA_def_property_range(prop, 0, 1); - RNA_def_property_ui_range(prop, 0.0, 1.0, 10, 2); - RNA_def_property_ui_text(prop, "Force", "Upward spring force, when inside the physics distance area"); - - prop = RNA_def_property(srna, "fh_distance", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "fhdist"); - RNA_def_property_range(prop, 0, 20); - RNA_def_property_ui_text(prop, "Distance", "Distance of the physics area"); - - prop = RNA_def_property(srna, "fh_damping", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "xyfrict"); - RNA_def_property_range(prop, 0, 1); - RNA_def_property_ui_text(prop, "Damping", "Damping of the spring force, when inside the physics distance area"); -} - void RNA_def_material(BlenderRNA *brna) { StructRNA *srna; @@ -1817,6 +1837,36 @@ void RNA_def_material(BlenderRNA *brna) RNA_def_property_enum_funcs(prop, NULL, "rna_Material_type_set", NULL); RNA_def_property_update(prop, 0, "rna_Material_draw_update"); + prop = RNA_def_property(srna, "use_constant_material", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "constflag", MA_CONSTANT_MATERIAL); + RNA_def_property_ui_text(prop, "Material", "Use constant values for material"); + RNA_def_property_update(prop, 0, "rna_Material_draw_update"); + + prop = RNA_def_property(srna, "use_constant_lamp", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "constflag", MA_CONSTANT_LAMP); + RNA_def_property_ui_text(prop, "Lamp", "Use constant values for lamps"); + RNA_def_property_update(prop, 0, "rna_Material_draw_update"); + + prop = RNA_def_property(srna, "use_constant_texture", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "constflag", MA_CONSTANT_TEXTURE); + RNA_def_property_ui_text(prop, "Texture", "Use constant values for textures"); + RNA_def_property_update(prop, 0, "rna_Material_draw_update"); + + prop = RNA_def_property(srna, "use_constant_texture_uv", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "constflag", MA_CONSTANT_TEXTURE_UV); + RNA_def_property_ui_text(prop, "Texture Uv", "Use constant values for textures uv transformation"); + RNA_def_property_update(prop, 0, "rna_Material_draw_update"); + + prop = RNA_def_property(srna, "use_constant_world", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "constflag", MA_CONSTANT_WORLD); + RNA_def_property_ui_text(prop, "World", "Use constant values for world"); + RNA_def_property_update(prop, 0, "rna_Material_draw_update"); + + prop = RNA_def_property(srna, "use_constant_mist", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "constflag", MA_CONSTANT_MIST); + RNA_def_property_ui_text(prop, "Mist", "Use constant values for mist"); + RNA_def_property_update(prop, 0, "rna_Material_draw_update"); + prop = RNA_def_property(srna, "use_transparency", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", MA_TRANSP); RNA_def_property_ui_text(prop, "Transparency", "Render material as transparent"); @@ -1828,6 +1878,18 @@ void RNA_def_material(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Transparency Method", "Method to use for rendering transparency"); RNA_def_property_update(prop, 0, "rna_Material_update"); + /* For depth transparency */ + prop = RNA_def_property(srna, "use_depth_transparency", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "mode2", MA_DEPTH_TRANSP); + RNA_def_property_ui_text(prop, "Depth Transparency", "Render material as transparent depending on the depth"); + RNA_def_property_update(prop, 0, "rna_Material_draw_update"); + + prop = RNA_def_property(srna, "depth_transp_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "depthtranspfactor"); + RNA_def_property_range(prop, 0.001f, FLT_MAX); + RNA_def_property_ui_text(prop, "Depth Transparency Factor", "Amount of transparency depending on the depth"); + RNA_def_property_update(prop, 0, "rna_Material_update"); + /* For Preview Render */ prop = RNA_def_property(srna, "preview_render_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "pr_type"); @@ -1863,6 +1925,10 @@ void RNA_def_material(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Object Color", "Modulate the result with a per-object color"); RNA_def_property_update(prop, 0, "rna_Material_draw_update"); + prop = RNA_def_property(srna, "use_instancing", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "shade_flag", MA_INSTANCING); + RNA_def_property_ui_text(prop, "Geometry Instancing", "Use special vertex shader for instancing rendering in game engine"); + prop = RNA_def_property(srna, "shadow_ray_bias", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "sbias"); RNA_def_property_range(prop, 0, 0.25); @@ -2075,12 +2141,6 @@ void RNA_def_material(BlenderRNA *brna) RNA_def_property_pointer_funcs(prop, "rna_Material_strand_get", NULL, NULL, NULL); RNA_def_property_ui_text(prop, "Strand", "Strand settings for the material"); - prop = RNA_def_property(srna, "physics", PROP_POINTER, PROP_NONE); - RNA_def_property_flag(prop, PROP_NEVER_NULL); - RNA_def_property_struct_type(prop, "MaterialPhysics"); - RNA_def_property_pointer_funcs(prop, "rna_Material_physics_get", NULL, NULL, NULL); - RNA_def_property_ui_text(prop, "Physics", "Game physics settings"); - /* game settings */ prop = RNA_def_property(srna, "game_settings", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); @@ -2135,7 +2195,6 @@ void RNA_def_material(BlenderRNA *brna) rna_def_material_sss(brna); rna_def_material_mtex(brna); rna_def_material_strand(brna); - rna_def_material_physics(brna); rna_def_material_gamesettings(brna); RNA_api_material(srna); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 847de75c604b..e0895cfa20bc 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -66,6 +66,8 @@ #include "NOD_composite.h" +#include "UI_resources.h" + const EnumPropertyItem rna_enum_node_socket_in_out_items[] = { { SOCK_IN, "IN", 0, "Input", "" }, { SOCK_OUT, "OUT", 0, "Output", "" }, @@ -155,6 +157,8 @@ const EnumPropertyItem rna_enum_node_vec_math_items[] = { {3, "DOT_PRODUCT", 0, "Dot Product", ""}, {4, "CROSS_PRODUCT", 0, "Cross Product", ""}, {5, "NORMALIZE", 0, "Normalize", ""}, + {6, "REFLECT", 0, "Reflect", ""}, + {7, "MULTIPLY", 0, "Multiply", ""}, {0, NULL, 0, NULL, NULL} }; @@ -169,6 +173,14 @@ const EnumPropertyItem rna_enum_node_filter_items[] = { {0, NULL, 0, NULL, NULL} }; +const EnumPropertyItem rna_enum_node_parallax_items[] = { + {0, "RED", ICON_COLOR_RED, "Red", ""}, + {1, "GREEN", ICON_COLOR_GREEN, "Green", ""}, + {2, "BLUE", ICON_COLOR_BLUE, "Blue", ""}, + {3, "ALPHA", ICON_IMAGE_ALPHA, "Alpha", ""}, + {0, NULL, 0, NULL, NULL} +}; + #ifndef RNA_RUNTIME static const EnumPropertyItem node_sampler_type_items[] = { {0, "NEAREST", 0, "Nearest", ""}, @@ -3588,6 +3600,30 @@ static void def_texture(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_parallax(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "texture", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "id"); + RNA_def_property_struct_type(prop, "Texture"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Texture", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "component", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "custom1"); + RNA_def_property_enum_items(prop, rna_enum_node_parallax_items); + RNA_def_property_ui_text(prop, "Component", "The color component to extract the height information from"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "discard", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "custom2", 1); + RNA_def_property_ui_text(prop, "Discard", "Discard parallax edges"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + +} + /* -- Shader Nodes ---------------------------------------------------------- */ diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 1d62f438047f..9dca3d9f17d9 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -56,6 +56,7 @@ #include "rna_internal.h" #include "BLI_sys_types.h" /* needed for intptr_t used in ED_mesh.h */ +#include "BLI_math_base.h" #include "ED_mesh.h" #include "WM_api.h" @@ -116,6 +117,7 @@ static const EnumPropertyItem collision_bounds_items[] = { {OB_BOUND_CONVEX_HULL, "CONVEX_HULL", ICON_MESH_ICOSPHERE, "Convex Hull", ""}, {OB_BOUND_TRIANGLE_MESH, "TRIANGLE_MESH", ICON_MESH_MONKEY, "Triangle Mesh", ""}, {OB_BOUND_CAPSULE, "CAPSULE", ICON_MESH_CAPSULE, "Capsule", ""}, + {OB_BOUND_EMPTY, "Empty", ICON_EMPTY_DATA, "Empty", ""}, /*{OB_DYN_MESH, "DYNAMIC_MESH", 0, "Dynamic Mesh", ""}, */ {0, NULL, 0, NULL, NULL} }; @@ -514,6 +516,7 @@ static const EnumPropertyItem *rna_Object_collision_bounds_itemf(bContext *UNUSE RNA_enum_items_add_value(&item, &totitem, collision_bounds_items, OB_BOUND_SPHERE); RNA_enum_items_add_value(&item, &totitem, collision_bounds_items, OB_BOUND_BOX); RNA_enum_items_add_value(&item, &totitem, collision_bounds_items, OB_BOUND_CAPSULE); + RNA_enum_items_add_value(&item, &totitem, collision_bounds_items, OB_BOUND_EMPTY); } RNA_enum_item_end(&item, &totitem); @@ -1147,7 +1150,7 @@ static void rna_GameObjectSettings_state_get(PointerRNA *ptr, bool *values) int i; int all_states = (ob->scaflag & OB_ALLSTATE) ? 1 : 0; - memset(values, 0, sizeof(int) * OB_MAX_STATES); + memset(values, 0, sizeof(bool) * OB_MAX_STATES); for (i = 0; i < OB_MAX_STATES; i++) { values[i] = (ob->state & (1 << i)) ? 1 : 0 | all_states; } @@ -1177,7 +1180,7 @@ static void rna_GameObjectSettings_used_state_get(PointerRNA *ptr, bool *values) Object *ob = (Object *)ptr->data; bController *cont; - memset(values, 0, sizeof(int) * OB_MAX_STATES); + memset(values, 0, sizeof(bool) * OB_MAX_STATES); for (cont = ob->controllers.first; cont; cont = cont->next) { int i; @@ -1636,6 +1639,35 @@ static void rna_def_material_slot(BlenderRNA *brna) RNA_def_struct_path_func(srna, "rna_MaterialSlot_path"); } +static void rna_def_game_object_activity_culling(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "ObjectActivityCulling", NULL); + RNA_def_struct_sdna(srna, "ObjectActivityCulling"); + RNA_def_struct_nested(brna, srna, "Object"); + RNA_def_struct_ui_text(srna, "Object Activity Culling", "Object activity culling info"); + + prop = RNA_def_property(srna, "physics_radius", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "physicsRadius"); + RNA_def_property_range(prop, 0.0, FLT_MAX); + RNA_def_property_ui_text(prop, "Physics Radius", "Distance to begin suspend physics of this object"); + + prop = RNA_def_property(srna, "logic_radius", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "logicRadius"); + RNA_def_property_range(prop, 0.0, FLT_MAX); + RNA_def_property_ui_text(prop, "Logic Radius", "Distance to begin suspend logic and animation of this object"); + + prop = RNA_def_property(srna, "use_physics", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", OB_ACTIVITY_PHYSICS); + RNA_def_property_ui_text(prop, "Cull Physics", "Suspend physics of this object by its distance to nearest camera"); + + prop = RNA_def_property(srna, "use_logic", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flags", OB_ACTIVITY_LOGIC); + RNA_def_property_ui_text(prop, "Cull Logic", "Suspend logic and animation of this object by its distance to nearest camera"); +} + static void rna_def_object_game_settings(BlenderRNA *brna) { StructRNA *srna; @@ -1683,6 +1715,11 @@ static void rna_def_object_game_settings(BlenderRNA *brna) RNA_def_property_struct_type(prop, "GameProperty"); /* rna_property.c */ RNA_def_property_ui_text(prop, "Properties", "Game engine properties"); + prop = RNA_def_property(srna, "components", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "components", NULL); + RNA_def_property_struct_type(prop, "PythonComponent"); /* rna_python_component.c */ + RNA_def_property_ui_text(prop, "Components", "Game engine components"); + prop = RNA_def_property(srna, "show_sensors", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "scaflag", OB_SHOWSENS); RNA_def_property_ui_text(prop, "Show Sensors", "Shows sensors for this object in the user interface"); @@ -1706,10 +1743,6 @@ static void rna_def_object_game_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Physics Type", "Select the type of physical representation"); RNA_def_property_update(prop, NC_LOGIC, NULL); - prop = RNA_def_property(srna, "use_record_animation", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "gameflag", OB_RECORD_ANIMATION); - RNA_def_property_ui_text(prop, "Record Animation", "Record animation objects without physics"); - prop = RNA_def_property(srna, "use_actor", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "gameflag", OB_ACTOR); RNA_def_property_ui_text(prop, "Actor", "Object is detected by the Near and Radar sensor"); @@ -1719,7 +1752,7 @@ static void rna_def_object_game_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Ghost", "Object does not react to collisions, like a ghost"); prop = RNA_def_property(srna, "mass", PROP_FLOAT, PROP_NONE); - RNA_def_property_range(prop, 0.01, 10000.0); + RNA_def_property_range(prop, 0.01, 1000000.0); RNA_def_property_float_default(prop, 1.0f); RNA_def_property_ui_text(prop, "Mass", "Mass of the object"); @@ -1791,6 +1824,12 @@ static void rna_def_object_game_settings(BlenderRNA *brna) RNA_def_property_float_default(prop, 55.0f); RNA_def_property_ui_text(prop, "Fall Speed Max", "Maximum speed at which the character will fall"); + prop = RNA_def_property(srna, "max_slope", PROP_FLOAT, PROP_ANGLE); + RNA_def_property_float_sdna(prop, NULL, "max_slope"); + RNA_def_property_range(prop, 0.0, M_PI_2); + RNA_def_property_float_default(prop, M_PI_2); + RNA_def_property_ui_text(prop, "Max Slope", "Maximum slope angle which the character will climb"); + prop = RNA_def_property(srna, "jump_max", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "max_jumps"); RNA_def_property_range(prop, 1, CHAR_MAX); @@ -1839,15 +1878,16 @@ static void rna_def_object_game_settings(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "gameflag2", OB_LOCK_RIGID_BODY_Z_ROT_AXIS); RNA_def_property_ui_text(prop, "Lock Z Rotation Axis", "Disable simulation of angular motion along the Z axis"); - /* is this used anywhere ? */ - prop = RNA_def_property(srna, "use_activity_culling", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "gameflag2", OB_NEVER_DO_ACTIVITY_CULLING); - RNA_def_property_ui_text(prop, "Lock Z Rotation Axis", "Disable simulation of angular motion along the Z axis"); + prop = RNA_def_property(srna, "predefined_bound", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "Mesh"); + RNA_def_property_pointer_sdna(prop, NULL, "gamePredefinedBound"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Predefined Bound", "Predefined mesh bounding volume used when Auto Update Bound is disable"); - prop = RNA_def_property(srna, "use_material_physics_fh", PROP_BOOLEAN, PROP_NONE); + prop = RNA_def_property(srna, "use_physics_fh", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "gameflag", OB_DO_FH); - RNA_def_property_ui_text(prop, "Use Material Force Field", "React to force field physics settings in materials"); + RNA_def_property_ui_text(prop, "Use Force Field", "React to force field physics settings"); prop = RNA_def_property(srna, "use_rotate_from_normal", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "gameflag", OB_ROT_FH); @@ -1856,7 +1896,7 @@ static void rna_def_object_game_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "form_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "formfactor"); - RNA_def_property_range(prop, 0.0, 1.0); + RNA_def_property_range(prop, 0.0, 1000.0); RNA_def_property_float_default(prop, 0.4f); RNA_def_property_ui_text(prop, "Form Factor", "Form factor scales the inertia tensor"); @@ -1893,7 +1933,8 @@ static void rna_def_object_game_settings(BlenderRNA *brna) RNA_def_property_float_default(prop, 0.04f); RNA_def_property_ui_text(prop, "Collision Margin", "Extra margin around object for collision detection, small amount required " - "for stability"); + "for stability. In most cases margin can be set to 0.0 for static/not moving objects." + "If you have jittering, decrease the margin"); prop = RNA_def_property(srna, "soft_body", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "bsoft"); @@ -1909,6 +1950,44 @@ static void rna_def_object_game_settings(BlenderRNA *brna) RNA_def_property_float_default(prop, 1.0f); RNA_def_property_ui_text(prop, "Obstacle Radius", "Radius of object representation in obstacle simulation"); + prop = RNA_def_property(srna, "friction", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "friction"); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Friction", "Coulomb friction coefficient, when inside the physics distance area"); + + prop = RNA_def_property(srna, "rolling_friction", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "rolling_friction"); + RNA_def_property_range(prop, 0, 100); + RNA_def_property_ui_text(prop, "Rolling Friction", "Coulomb friction coefficient of rounded shapes"); + + prop = RNA_def_property(srna, "elasticity", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "reflect"); + RNA_def_property_range(prop, 0, 1); + RNA_def_property_ui_text(prop, "Elasticity", "Elasticity of collisions"); + + /* FH/Force Field Settings */ + prop = RNA_def_property(srna, "use_fh_normal", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "dynamode", OB_FH_NOR); + RNA_def_property_ui_text(prop, "Align to Normal", + "Align dynamic game objects along the surface normal, " + "when inside the physics distance area"); + + prop = RNA_def_property(srna, "fh_force", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "fh"); + RNA_def_property_range(prop, 0, 1); + RNA_def_property_ui_range(prop, 0.0, 1.0, 10, 2); + RNA_def_property_ui_text(prop, "Force", "Upward spring force, when inside the physics distance area"); + + prop = RNA_def_property(srna, "fh_distance", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "fhdist"); + RNA_def_property_range(prop, 0, 20); + RNA_def_property_ui_text(prop, "Distance", "Distance of the physics area"); + + prop = RNA_def_property(srna, "fh_damping", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "xyfrict"); + RNA_def_property_range(prop, 0, 1); + RNA_def_property_ui_text(prop, "Damping", "Damping of the spring force, when inside the physics distance area"); + /* state */ prop = RNA_def_property(srna, "states_visible", PROP_BOOLEAN, PROP_LAYER_MEMBER); @@ -1941,6 +2020,15 @@ static void rna_def_object_game_settings(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "scaflag", OB_SHOWSTATE); RNA_def_property_ui_text(prop, "States", "Show state panel"); RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1); + + /* activity culling */ + prop = RNA_def_property(srna, "activity_culling", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_pointer_sdna(prop, NULL, "activityCulling"); + RNA_def_property_struct_type(prop, "ObjectActivityCulling"); + RNA_def_property_ui_text(prop, "Object Activity Culling", ""); + + rna_def_game_object_activity_culling(brna); } static void rna_def_object_constraints(BlenderRNA *brna, PropertyRNA *cprop) @@ -2172,7 +2260,6 @@ static void rna_def_object_lodlevel(BlenderRNA *brna) RNA_def_property_update(prop, NC_OBJECT | ND_LOD, NULL); } - static void rna_def_object(BlenderRNA *brna) { StructRNA *srna; @@ -2855,6 +2942,13 @@ static void rna_def_object(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Level of Detail Levels", "A collection of detail levels to automatically switch between"); RNA_def_property_update(prop, NC_OBJECT | ND_LOD, NULL); + prop = RNA_def_property(srna, "lod_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "lodfactor"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_ui_text(prop, "Level of Detail Distance Factor", "The factor applied to distance computed in Lod"); + RNA_def_property_update(prop, NC_OBJECT | ND_LOD, NULL); + RNA_api_object(srna); } diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index 7da859c000ce..56b1c224a538 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -1556,18 +1556,112 @@ static void rna_def_game_softbody(BlenderRNA *brna) "=> set to 0.0 to disable welding test and speed up scene loading " "(ok if the mesh has no duplicates)"); + prop = RNA_def_property(srna, "ksrhr_cl", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "kSRHR_CL"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Soft vs Rigid Hardness", "Soft vs rigid hardness"); + + prop = RNA_def_property(srna, "kskhr_cl", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "kSKHR_CL"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Soft vs Kinetic Hardness", "Soft vs kinetic hardness"); + + prop = RNA_def_property(srna, "ksshr_cl", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "kSSHR_CL"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Soft vs Soft Hardness", "Soft vs soft hardness"); + + prop = RNA_def_property(srna, "ksr_split_cl", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "kSR_SPLT_CL"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Rigid Impulse Split", "Rigid impulse split"); + + prop = RNA_def_property(srna, "ksk_split_cl", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "kSK_SPLT_CL"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Kinetic Impulse Split", "Kinetic impulse split"); + + prop = RNA_def_property(srna, "kss_split_cl", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "kSS_SPLT_CL"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Soft Impulse Split", "Soft impulse split"); + + prop = RNA_def_property(srna, "kvcf", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "kVCF"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Velocity Correction Factor", "Velocity correction factor"); + + prop = RNA_def_property(srna, "kdp", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "kDP"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Damping Coefficient", "Damping coefficient"); + + prop = RNA_def_property(srna, "kdg", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "kDG"); + RNA_def_property_range(prop, 0.0f, 1000.0f); + RNA_def_property_ui_text(prop, "Drag Coeffient", "Drag coeffient"); + + prop = RNA_def_property(srna, "klf", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "kLF"); + RNA_def_property_range(prop, 0.0f, 1000.0f); + RNA_def_property_ui_text(prop, "Lift Coefficient", "Lift coefficient"); + + prop = RNA_def_property(srna, "kpr", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "kPR"); + RNA_def_property_range(prop, -1000.0f, 1000.0f); + RNA_def_property_ui_text(prop, "Pressure Coefficient", "Pressure coefficient"); + + prop = RNA_def_property(srna, "kvc", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "kVC"); + RNA_def_property_range(prop, 0.0f, 1000.0f); + RNA_def_property_ui_text(prop, "Volume Conservation Coefficient", "Volume conservation coefficient"); + + prop = RNA_def_property(srna, "kchr", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "kCHR"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Rigid Contacts Hardness", "Rigid contacts hardness"); + + prop = RNA_def_property(srna, "kkhr", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "kKHR"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Kinetic Contacts Hardness", "Kinetic contacts hardness"); + + prop = RNA_def_property(srna, "kshr", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "kSHR"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Soft Contacts Hardness", "Soft contacts hardness"); + + prop = RNA_def_property(srna, "kahr", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "kAHR"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Anchors Hardness", "Anchors hardness"); /* Integers */ - prop = RNA_def_property(srna, "location_iterations", PROP_INT, PROP_NONE); + prop = RNA_def_property(srna, "position_solver_iterations", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "piterations"); - RNA_def_property_range(prop, 0, 10); - RNA_def_property_ui_text(prop, "Position Iterations", "Position solver iterations"); + RNA_def_property_range(prop, 1, 1000); + RNA_def_property_ui_text(prop, "Position Solver Iterations", "Position solver iterations"); + + prop = RNA_def_property(srna, "velocity_solver_iterations", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "viterations"); + RNA_def_property_range(prop, 0, 1000); + RNA_def_property_ui_text(prop, "Velocity Solver Iterations", "Position solver iterations"); + + prop = RNA_def_property(srna, "drift_solver_iterations", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "diterations"); + RNA_def_property_range(prop, 0, 1000); + RNA_def_property_ui_text(prop, "Drift Solver Iterations", "Drift solver iterations"); + + prop = RNA_def_property(srna, "cluster_solver_iterations", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "citerations"); + RNA_def_property_range(prop, 1, 1000); + RNA_def_property_ui_text(prop, "Cluster Solver Iterations", "Cluster solver iterations"); prop = RNA_def_property(srna, "cluster_iterations", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "numclusteriterations"); - RNA_def_property_range(prop, 1, 128); + RNA_def_property_range(prop, 1, 1000); RNA_def_property_ui_text(prop, "Cluster Iterations", "Number of cluster iterations"); - + /* Booleans */ prop = RNA_def_property(srna, "use_shape_match", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_property.c b/source/blender/makesrna/intern/rna_property.c index 9a79aa4023cd..6084b21d8b12 100644 --- a/source/blender/makesrna/intern/rna_property.c +++ b/source/blender/makesrna/intern/rna_property.c @@ -87,7 +87,7 @@ static float rna_GameFloatProperty_value_get(PointerRNA *ptr) static void rna_GameFloatProperty_value_set(PointerRNA *ptr, float value) { bProperty *prop = (bProperty *)(ptr->data); - CLAMP(value, -10000.0f, 10000.0f); + CLAMP(value, -FLT_MAX, FLT_MAX); *(float *)(&prop->data) = value; } @@ -160,7 +160,7 @@ void RNA_def_gameproperty(BlenderRNA *brna) prop = RNA_def_property(srna, "value", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "data"); RNA_def_property_ui_text(prop, "Value", "Property value"); - RNA_def_property_range(prop, -10000, 10000); + RNA_def_property_range(prop, -INT_MAX, INT_MAX); RNA_def_property_update(prop, NC_LOGIC, NULL); /* GameFloatProperty */ @@ -171,7 +171,7 @@ void RNA_def_gameproperty(BlenderRNA *brna) prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE); /* RNA_def_property_float_sdna(prop, NULL, "data"); */ RNA_def_property_ui_text(prop, "Value", "Property value"); - RNA_def_property_range(prop, -10000, 10000); + RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); RNA_def_property_float_funcs(prop, "rna_GameFloatProperty_value_get", "rna_GameFloatProperty_value_set", NULL); RNA_def_property_update(prop, NC_LOGIC, NULL); @@ -183,7 +183,7 @@ void RNA_def_gameproperty(BlenderRNA *brna) prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE); /* RNA_def_property_float_sdna(prop, NULL, "data"); */ RNA_def_property_ui_text(prop, "Value", "Property value"); - RNA_def_property_range(prop, -10000, 10000); + RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); RNA_def_property_float_funcs(prop, "rna_GameFloatProperty_value_get", "rna_GameFloatProperty_value_set", NULL); RNA_def_property_update(prop, NC_LOGIC, NULL); diff --git a/source/blender/makesrna/intern/rna_python_component.c b/source/blender/makesrna/intern/rna_python_component.c new file mode 100644 index 000000000000..e5a3b8588a9a --- /dev/null +++ b/source/blender/makesrna/intern/rna_python_component.c @@ -0,0 +1,249 @@ +/** + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Mitchell Stokes, Diego Lopes, Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include + +#include "RNA_define.h" + +#include "rna_internal.h" +#include "DNA_python_component_types.h" +#include "DNA_property_types.h" + +#include "WM_types.h" + +#ifdef RNA_RUNTIME + +static StructRNA* rna_PythonComponentProperty_refine(struct PointerRNA *ptr) +{ + PythonComponentProperty *cprop = (PythonComponentProperty *)ptr->data; + + switch(cprop->type) { + case CPROP_TYPE_BOOLEAN: + return &RNA_ComponentBooleanProperty; + case CPROP_TYPE_INT: + return &RNA_ComponentIntProperty; + case CPROP_TYPE_FLOAT: + return &RNA_ComponentFloatProperty; + case CPROP_TYPE_STRING: + return &RNA_ComponentStringProperty; + case CPROP_TYPE_SET: + return &RNA_ComponentSetProperty; + case CPROP_TYPE_VEC2: + return &RNA_ComponentVector2DProperty; + case CPROP_TYPE_VEC3: + return &RNA_ComponentVector3DProperty; + case CPROP_TYPE_VEC4: + return &RNA_ComponentVector4DProperty; + default: + return &RNA_PythonComponentProperty; + } +} + +static int rna_ComponentSetProperty_get(struct PointerRNA *ptr) +{ + PythonComponentProperty *cprop = (PythonComponentProperty *)(ptr->data); + return cprop->itemval; +} + +static void rna_ComponentSetProperty_set(struct PointerRNA *ptr, int value) +{ + PythonComponentProperty *cprop = (PythonComponentProperty *)(ptr->data); + cprop->itemval = value; +} + +static EnumPropertyItem *rna_ComponentSetProperty_itemf(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) +{ + PythonComponentProperty *cprop = (PythonComponentProperty *)(ptr->data); + EnumPropertyItem *items = NULL; + int totitem = 0; + int j = 0; + + for (LinkData *link = cprop->enumval.first; link; link = link->next, ++j) { + EnumPropertyItem item = {0, "", 0, "", ""}; + item.value = j; + item.identifier = link->data; + item.icon = 0; + item.name = link->data; + item.description = ""; + RNA_enum_item_add(&items, &totitem, &item); + } + + RNA_enum_item_end(&items, &totitem); + *r_free = true; + + return items; +} +#else + +static void rna_def_py_component(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + /* Python Component */ + srna = RNA_def_struct(brna, "PythonComponent", NULL); + RNA_def_struct_sdna(srna, "PythonComponent"); + RNA_def_struct_ui_text(srna, "Python Component", ""); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "name"); + RNA_def_property_ui_text(prop, "Name", ""); + RNA_def_struct_name_property(srna, prop); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop = RNA_def_property(srna, "module", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "module"); + RNA_def_property_ui_text(prop, "Module", ""); + RNA_def_struct_name_property(srna, prop); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", COMPONENT_SHOW); + RNA_def_property_ui_text(prop, "Expanded", "Set sensor expanded in the user interface"); + RNA_def_property_ui_icon(prop, ICON_TRIA_RIGHT, 1); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop = RNA_def_property(srna, "properties", PROP_COLLECTION, PROP_NONE); + RNA_def_property_collection_sdna(prop, NULL, "properties", NULL); + RNA_def_property_struct_type(prop, "PythonComponentProperty"); + RNA_def_property_ui_text(prop, "Properties", "Component properties"); +} + +static void rna_def_py_component_property(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static EnumPropertyItem empty_items[] = { + {0, "EMPTY", 0, "Empty", ""}, + {0, NULL, 0, NULL, NULL} + }; + + /* Base Python Component Property */ + srna = RNA_def_struct(brna, "PythonComponentProperty", NULL); + RNA_def_struct_sdna(srna, "PythonComponentProperty"); + RNA_def_struct_ui_text(srna, "Python Component Property", "A property of a Python Component"); + RNA_def_struct_refine_func(srna, "rna_PythonComponentProperty_refine"); + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "name"); + RNA_def_property_ui_text(prop, "Name", ""); + RNA_def_struct_name_property(srna, prop); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + /* Boolean */ + srna = RNA_def_struct(brna, "ComponentBooleanProperty", "PythonComponentProperty"); + RNA_def_struct_sdna(srna, "PythonComponentProperty"); + RNA_def_struct_ui_text(srna, "Python Component Boolean Property", "A boolean property of a Python Component"); + + prop = RNA_def_property(srna, "value", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "boolval", 1); + RNA_def_property_ui_text(prop, "Value", "Property value"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + /* Int */ + srna = RNA_def_struct(brna, "ComponentIntProperty", "PythonComponentProperty"); + RNA_def_struct_sdna(srna, "PythonComponentProperty"); + RNA_def_struct_ui_text(srna, "Python Component Integer Property", "An integer property of a Python Component"); + + prop = RNA_def_property(srna, "value", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "intval"); + RNA_def_property_ui_text(prop, "Value", "Property value"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + /* Float */ + srna = RNA_def_struct(brna, "ComponentFloatProperty", "PythonComponentProperty"); + RNA_def_struct_sdna(srna, "PythonComponentProperty"); + RNA_def_struct_ui_text(srna, "Python Component Float Property", "A float property of a Python Component"); + + prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "floatval"); + RNA_def_property_ui_text(prop, "Value", "Property value"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + /* String */ + srna = RNA_def_struct(brna, "ComponentStringProperty", "PythonComponentProperty"); + RNA_def_struct_sdna(srna, "PythonComponentProperty"); + RNA_def_struct_ui_text(srna, "Python Component String Property", "A string property of a Python Component"); + + prop = RNA_def_property(srna, "value", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "strval"); + RNA_def_property_string_maxlength(prop, MAX_PROPSTRING); + RNA_def_property_ui_text(prop, "Value", "Property value"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + /* Set */ + srna = RNA_def_struct(brna, "ComponentSetProperty", "PythonComponentProperty"); + RNA_def_struct_sdna(srna, "PythonComponentProperty"); + RNA_def_struct_ui_text(srna, "Python Component Set Property", "A set property of a Python Component"); + + prop = RNA_def_property(srna, "value", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, empty_items); + RNA_def_property_enum_funcs(prop, "rna_ComponentSetProperty_get", "rna_ComponentSetProperty_set", "rna_ComponentSetProperty_itemf"); + RNA_def_property_enum_default(prop, 0); + RNA_def_property_ui_text(prop, "Value", "Property value"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + /* Vector 2D */ + srna = RNA_def_struct(brna, "ComponentVector2DProperty", "PythonComponentProperty"); + RNA_def_struct_sdna(srna, "PythonComponentProperty"); + RNA_def_struct_ui_text(srna, "Python Component Vector 2D Property", "A 2D vector property of a Python Component"); + + prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_COORDS); + RNA_def_property_float_sdna(prop, NULL, "vec"); + RNA_def_property_array(prop, 2); + RNA_def_property_ui_text(prop, "Value", "Property value"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + /* Vector 3D */ + srna = RNA_def_struct(brna, "ComponentVector3DProperty", "PythonComponentProperty"); + RNA_def_struct_sdna(srna, "PythonComponentProperty"); + RNA_def_struct_ui_text(srna, "Python Component Vector 3D Property", "A 3D vector property of a Python Component"); + + prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_COORDS); + RNA_def_property_float_sdna(prop, NULL, "vec"); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Value", "Property value"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + /* Vector 4D */ + srna = RNA_def_struct(brna, "ComponentVector4DProperty", "PythonComponentProperty"); + RNA_def_struct_sdna(srna, "PythonComponentProperty"); + RNA_def_struct_ui_text(srna, "Python Component Vector 4D Property", "A 4D vector property of a Python Component"); + + prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_COORDS); + RNA_def_property_float_sdna(prop, NULL, "vec"); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Value", "Property value"); + RNA_def_property_update(prop, NC_LOGIC, NULL); +} + +void RNA_def_py_component(BlenderRNA *brna) +{ + rna_def_py_component(brna); + rna_def_py_component_property(brna); +} + +#endif /* RNA_RUNTIME */ diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 3c8cc9ee2be7..60fbc3d9be84 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -28,6 +28,7 @@ #include "DNA_brush_types.h" #include "DNA_group_types.h" +#include "DNA_material_types.h" #include "DNA_modifier_types.h" #include "DNA_particle_types.h" #include "DNA_rigidbody_types.h" @@ -1841,6 +1842,54 @@ static void rna_GameSettings_exit_key_set(PointerRNA *ptr, int value) gm->exitkey = value; } +static void rna_GameSettings_python_key1_set(PointerRNA *ptr, int value) +{ + GameData *gm = (GameData *)ptr->data; + + if (ISKEYBOARD(value)) { + gm->pythonkeys[0] = value; + } + else { + gm->pythonkeys[0] = EVENT_NONE; + } +} + +static void rna_GameSettings_python_key2_set(PointerRNA *ptr, int value) +{ + GameData *gm = (GameData *)ptr->data; + + if (ISKEYBOARD(value)) { + gm->pythonkeys[1] = value; + } + else { + gm->pythonkeys[1] = EVENT_NONE; + } +} + +static void rna_GameSettings_python_key3_set(PointerRNA *ptr, int value) +{ + GameData *gm = (GameData *)ptr->data; + + if (ISKEYBOARD(value)) { + gm->pythonkeys[2] = value; + } + else { + gm->pythonkeys[2] = EVENT_NONE; + } +} + +static void rna_GameSettings_python_key4_set(PointerRNA *ptr, int value) +{ + GameData *gm = (GameData *)ptr->data; + + if (ISKEYBOARD(value)) { + gm->pythonkeys[3] = value; + } + else { + gm->pythonkeys[3] = EVENT_NONE; + } +} + static TimeMarker *rna_TimeLine_add(Scene *scene, const char name[], int frame) { TimeMarker *marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker"); @@ -4425,6 +4474,27 @@ static void rna_def_scene_game_data(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem hdr_items[] = { + {GAME_HDR_NONE, "HDR_NONE", 0, "None", "8 bits per channel"}, + {GAME_HDR_HALF_FLOAT, "HDR_HALF_FLOAT", 0, "Half", "16 bits per channel"}, + {GAME_HDR_FULL_FLOAT, "HDR_FULL_FLOAT", 0, "Full", "32 bits per channel"}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem color_management_items[] = { + {GAME_COLOR_MANAGEMENT_LINEAR, "COLOR_MANAGEMENT_LINEAR", 0, "Linear", "Linear color space"}, + {GAME_COLOR_MANAGEMENT_SRGB, "COLOR_MANAGEMENT_SRGB", 0, "sRGB", "sRGB color space"}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem solver_items[] = { + {GAME_SOLVER_SEQUENTIAL, "SOLVER_SEQUENTIAL", 0, "Sequential", "Sequential physics solver, default solver"}, + {GAME_SOLVER_NNCG, "SOLVER_NNGC", 0, "NNGC", "NNGC physics solver"}, + {GAME_SOLVER_MLCP_DANTZIG, "SOLVER_MLCP_DANTZIG", 0, "MLCP Dantzig", "MLCP Dantzig physics solver"}, + {GAME_SOLVER_MLCP_LEMKE, "SOLVER_MLCP_LEMKE", 0, "MLCP Lemke", "MLCP Lemke physics solver"}, + {0, NULL, 0, NULL, NULL} + }; + static const EnumPropertyItem framing_types_items[] = { {SCE_GAMEFRAMING_BARS, "LETTERBOX", 0, "Letterbox", "Show the entire viewport in the display window, using bar horizontally or vertically"}, @@ -4435,15 +4505,6 @@ static void rna_def_scene_game_data(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; - static const EnumPropertyItem dome_modes_items[] = { - {DOME_FISHEYE, "FISHEYE", 0, "Fisheye", ""}, - {DOME_TRUNCATED_FRONT, "TRUNCATED_FRONT", 0, "Front-Truncated", ""}, - {DOME_TRUNCATED_REAR, "TRUNCATED_REAR", 0, "Rear-Truncated", ""}, - {DOME_ENVMAP, "ENVMAP", 0, "Cube Map", ""}, - {DOME_PANORAM_SPH, "PANORAM_SPH", 0, "Spherical Panoramic", ""}, - {0, NULL, 0, NULL, NULL} - }; - static const EnumPropertyItem stereo_modes_items[] = { {STEREO_QUADBUFFERED, "QUADBUFFERED", 0, "Quad-Buffer", ""}, {STEREO_ABOVEBELOW, "ABOVEBELOW", 0, "Above-Below", ""}, @@ -4458,7 +4519,6 @@ static void rna_def_scene_game_data(BlenderRNA *brna) static const EnumPropertyItem stereo_items[] = { {STEREO_NOSTEREO, "NONE", 0, "None", "Disable Stereo and Dome environments"}, {STEREO_ENABLED, "STEREO", 0, "Stereo", "Enable Stereo environment"}, - {STEREO_DOME, "DOME", 0, "Dome", "Enable Dome environment"}, {0, NULL, 0, NULL, NULL} }; @@ -4468,12 +4528,6 @@ static void rna_def_scene_game_data(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; - static const EnumPropertyItem material_items[] = { - {GAME_MAT_MULTITEX, "MULTITEXTURE", 0, "Multitexture", "Multitexture materials"}, - {GAME_MAT_GLSL, "GLSL", 0, "GLSL", "OpenGL shading language shaders"}, - {0, NULL, 0, NULL, NULL} - }; - static const EnumPropertyItem obstacle_simulation_items[] = { {OBSTSIMULATION_NONE, "NONE", 0, "None", ""}, {OBSTSIMULATION_TOI_rays, "RVO_RAYS", 0, "RVO (rays)", ""}, @@ -4488,12 +4542,12 @@ static void rna_def_scene_game_data(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; - static const EnumPropertyItem storage_items[] = { - {RAS_STORE_AUTO, "AUTO", 0, "Auto Select", "Choose the best supported mode"}, - {RAS_STORE_VA, "VERTEX_ARRAY", 0, "Vertex Arrays", "Usually the best choice (good performance with display lists)"}, - {RAS_STORE_VBO, "VERTEX_BUFFER_OBJECT", 0, "Vertex Buffer Objects", - "Typically slower than vertex arrays with display lists, requires at least OpenGL 1.4"}, - {0, NULL, 0, NULL, NULL}}; + static const EnumPropertyItem debug_items[] = { + {GAME_DEBUG_DISABLE, "DISABLE", 0, "Disable", "Disable debugging"}, + {GAME_DEBUG_FORCE, "FORCE", 0, "Force", "Force debugging"}, + {GAME_DEBUG_ALLOW, "ALLOW", 0, "Allow", "Allow debugging from individual settings"}, + {0, NULL, 0, NULL, NULL} + }; srna = RNA_def_struct(brna, "SceneGameData", NULL); RNA_def_struct_sdna(srna, "GameData"); @@ -4524,6 +4578,11 @@ static void rna_def_scene_game_data(BlenderRNA *brna) RNA_def_property_enum_items(prop, aasamples_items); RNA_def_property_ui_text(prop, "AA Samples", "The number of AA Samples to use for MSAA"); + prop = RNA_def_property(srna, "hdr", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "hdr"); + RNA_def_property_enum_items(prop, hdr_items); + RNA_def_property_ui_text(prop, "HDR", "The precision of screen display"); + prop = RNA_def_property(srna, "depth", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "depth"); RNA_def_property_range(prop, 8, 32); @@ -4531,6 +4590,12 @@ static void rna_def_scene_game_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Bits", "Display bit depth of full screen display"); RNA_def_property_update(prop, NC_SCENE, NULL); + prop = RNA_def_property(srna, "color_management", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "colorManagement"); + RNA_def_property_enum_items(prop, color_management_items); + RNA_def_property_ui_text(prop, "Color Space", "The color space of the display"); + RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_glsl_update"); + prop = RNA_def_property(srna, "exit_key", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "exitkey"); RNA_def_property_enum_items(prop, rna_enum_event_type_items); @@ -4540,12 +4605,6 @@ static void rna_def_scene_game_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Exit Key", "The key that exits the Game Engine"); RNA_def_property_update(prop, NC_SCENE, NULL); - prop = RNA_def_property(srna, "raster_storage", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "raster_storage"); - RNA_def_property_enum_items(prop, storage_items); - RNA_def_property_ui_text(prop, "Storage", "Set the storage mode used by the rasterizer"); - RNA_def_property_update(prop, NC_SCENE, NULL); - /* Do we need it here ? (since we already have it in World */ prop = RNA_def_property(srna, "frequency", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "freqplay"); @@ -4600,47 +4659,6 @@ static void rna_def_scene_game_data(BlenderRNA *brna) "Set the distance between the eyes - the camera focal distance/30 should be fine"); RNA_def_property_update(prop, NC_SCENE, NULL); - /* Dome */ - prop = RNA_def_property(srna, "dome_mode", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "dome.mode"); - RNA_def_property_enum_items(prop, dome_modes_items); - RNA_def_property_ui_text(prop, "Dome Mode", "Dome physical configurations"); - RNA_def_property_update(prop, NC_SCENE, NULL); - - prop = RNA_def_property(srna, "dome_tessellation", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "dome.res"); - RNA_def_property_ui_range(prop, 1, 8, 1, 1); - RNA_def_property_int_default(prop, 4); - RNA_def_property_ui_text(prop, "Tessellation", "Tessellation level - check the generated mesh in wireframe mode"); - RNA_def_property_update(prop, NC_SCENE, NULL); - - prop = RNA_def_property(srna, "dome_buffer_resolution", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "dome.resbuf"); - RNA_def_property_ui_range(prop, 0.1, 1.0, 0.1, 2); - RNA_def_property_float_default(prop, 1.0f); - RNA_def_property_ui_text(prop, "Buffer Resolution", "Buffer Resolution - decrease it to increase speed"); - RNA_def_property_update(prop, NC_SCENE, NULL); - - prop = RNA_def_property(srna, "dome_angle", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "dome.angle"); - RNA_def_property_ui_range(prop, 90, 250, 1, 1); - RNA_def_property_int_default(prop, 180); - RNA_def_property_ui_text(prop, "Angle", "Field of View of the Dome - it only works in mode Fisheye and Truncated"); - RNA_def_property_update(prop, NC_SCENE, NULL); - - prop = RNA_def_property(srna, "dome_tilt", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "dome.tilt"); - RNA_def_property_ui_range(prop, -180, 180, 1, 1); - RNA_def_property_ui_text(prop, "Tilt", "Camera rotation in horizontal axis"); - RNA_def_property_update(prop, NC_SCENE, NULL); - - prop = RNA_def_property(srna, "dome_text", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "dome.warptext"); - RNA_def_property_struct_type(prop, "Text"); - RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Warp Data", "Custom Warp Mesh data file"); - RNA_def_property_update(prop, NC_SCENE, NULL); - /* physics */ prop = RNA_def_property(srna, "physics_engine", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "physicsEngine"); @@ -4658,6 +4676,11 @@ static void rna_def_scene_game_data(BlenderRNA *brna) "Gravitational constant used for physics simulation in the game engine"); RNA_def_property_update(prop, NC_SCENE, NULL); + prop = RNA_def_property(srna, "physics_solver", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "solverType"); + RNA_def_property_enum_items(prop, solver_items); + RNA_def_property_ui_text(prop, "Physics Solver", "Physics constraint solver"); + prop = RNA_def_property(srna, "occlusion_culling_resolution", PROP_INT, PROP_PIXEL); RNA_def_property_int_sdna(prop, NULL, "occlusionRes"); RNA_def_property_range(prop, 128.0, 1024.0); @@ -4706,6 +4729,15 @@ static void rna_def_scene_game_data(BlenderRNA *brna) "higher value give better physics precision"); RNA_def_property_update(prop, NC_SCENE, NULL); + prop = RNA_def_property(srna, "time_scale", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "timeScale"); + RNA_def_property_ui_range(prop, 0.001, 10000.0, 2, 3); + RNA_def_property_range(prop, 0.001, 10000.0); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_ui_text(prop, "Time Scale", + "Time scale to slow down or speed up animations and physics in game"); + RNA_def_property_update(prop, NC_SCENE, NULL); + prop = RNA_def_property(srna, "deactivation_linear_threshold", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "lineardeactthreshold"); RNA_def_property_ui_range(prop, 0.001, 10000.0, 2, 3); @@ -4734,25 +4766,15 @@ static void rna_def_scene_game_data(BlenderRNA *brna) RNA_def_property_update(prop, NC_SCENE, NULL); /* mode */ - /* not used *//* deprecated !!!!!!!!!!!!! */ prop = RNA_def_property(srna, "use_occlusion_culling", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", WO_DBVT_CULLING); RNA_def_property_ui_text(prop, "DBVT Culling", "Use optimized Bullet DBVT tree for view frustum and occlusion culling (more efficient, " "but it can waste unnecessary CPU if the scene doesn't have occluder objects)"); - /* not used *//* deprecated !!!!!!!!!!!!! */ prop = RNA_def_property(srna, "use_activity_culling", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", WO_ACTIVITY_CULLING); - RNA_def_property_ui_text(prop, "Activity Culling", "Activity culling is enabled"); - - /* not used *//* deprecated !!!!!!!!!!!!! */ - prop = RNA_def_property(srna, "activity_culling_box_radius", PROP_FLOAT, PROP_NONE); - RNA_def_property_float_sdna(prop, NULL, "activityBoxRadius"); - RNA_def_property_range(prop, 0.0, 1000.0); - RNA_def_property_ui_text(prop, "Box Radius", - "Radius of the activity bubble, in Manhattan length " - "(objects outside the box are activity-culled)"); + RNA_def_property_ui_text(prop, "Activity Culling", "Enable object activity culling in this scene"); /* booleans */ prop = RNA_def_property(srna, "show_debug_properties", PROP_BOOLEAN, PROP_NONE); @@ -4765,6 +4787,11 @@ static void rna_def_scene_game_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Show Framerate and Profile", "Show framerate and profiling information while the game runs"); + prop = RNA_def_property(srna, "show_render_queries", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GAME_SHOW_RENDER_QUERIES); + RNA_def_property_ui_text(prop, "Show Render Queries", + "Show render queries information while the game runs"); + prop = RNA_def_property(srna, "show_physics_visualization", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GAME_SHOW_PHYSICS); RNA_def_property_ui_text(prop, "Show Physics Visualization", @@ -4780,20 +4807,11 @@ static void rna_def_scene_game_data(BlenderRNA *brna) "Respect the frame rate from the Physics panel in the world properties " "rather than rendering as many frames as possible"); - prop = RNA_def_property(srna, "use_display_lists", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GAME_DISPLAY_LISTS); - RNA_def_property_ui_text(prop, "Display Lists", - "Use display lists to speed up rendering by keeping geometry on the GPU"); - prop = RNA_def_property(srna, "use_deprecation_warnings", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_IGNORE_DEPRECATION_WARNINGS); RNA_def_property_ui_text(prop, "Deprecation Warnings", "Print warnings when using deprecated features in the python API"); - prop = RNA_def_property(srna, "use_animation_record", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GAME_ENABLE_ANIMATION_RECORD); - RNA_def_property_ui_text(prop, "Record Animation", "Record animation to F-Curves"); - prop = RNA_def_property(srna, "use_auto_start", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_GameSettings_auto_start_get", "rna_GameSettings_auto_start_set"); RNA_def_property_ui_text(prop, "Auto Start", "Automatically start game at load time"); @@ -4804,13 +4822,65 @@ static void rna_def_scene_game_data(BlenderRNA *brna) "Restrict the number of animation updates to the animation FPS (this is " "better for performance, but can cause issues with smooth playback)"); - /* materials */ - prop = RNA_def_property(srna, "material_mode", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "matmode"); - RNA_def_property_enum_items(prop, material_items); - RNA_def_property_ui_text(prop, "Material Mode", "Material mode to use for rendering"); - RNA_def_property_update(prop, NC_SCENE | NA_EDITED, NULL); + prop = RNA_def_property(srna, "show_bounding_box", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "showBoundingBox"); + RNA_def_property_enum_items(prop, debug_items); + RNA_def_property_ui_text(prop, "Show Bounding Box", "Show a visualization of bounding volume box"); + + prop = RNA_def_property(srna, "show_armatures", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "showArmatures"); + RNA_def_property_enum_items(prop, debug_items); + RNA_def_property_ui_text(prop, "Show Armatures", "Show a visualization of armatures"); + + prop = RNA_def_property(srna, "show_camera_frustum", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "showCameraFrustum"); + RNA_def_property_enum_items(prop, debug_items); + RNA_def_property_ui_text(prop, "Show Camera Frustum", "Show a visualization of the camera frustum " + "according to the current viewport dimensions"); + + prop = RNA_def_property(srna, "show_shadow_frustum", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "showShadowFrustum"); + RNA_def_property_enum_items(prop, debug_items); + RNA_def_property_ui_text(prop, "Show Shadow Frustum", "Show a visualization of the light shadow frustum"); + + prop = RNA_def_property(srna, "use_python_console", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GAME_PYTHON_CONSOLE); + RNA_def_property_ui_text(prop, "Python Console", "Create a python interpreter console in game"); + + prop = RNA_def_property(srna, "python_console_key1", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "pythonkeys[0]"); + RNA_def_property_enum_items(prop, rna_enum_event_type_items); + RNA_def_property_enum_funcs(prop, NULL, "rna_GameSettings_python_key1_set", NULL); + RNA_def_property_enum_default(prop, LEFTCTRLKEY); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS); + RNA_def_property_ui_text(prop, "Python Console Key", "First python console shortcut key"); + + prop = RNA_def_property(srna, "python_console_key2", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "pythonkeys[1]"); + RNA_def_property_enum_items(prop, rna_enum_event_type_items); + RNA_def_property_enum_funcs(prop, NULL, "rna_GameSettings_python_key2_set", NULL); + RNA_def_property_enum_default(prop, LEFTSHIFTKEY); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS); + RNA_def_property_ui_text(prop, "Python Console Key", "Second python console shortcut key"); + + prop = RNA_def_property(srna, "python_console_key3", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "pythonkeys[2]"); + RNA_def_property_enum_items(prop, rna_enum_event_type_items); + RNA_def_property_enum_funcs(prop, NULL, "rna_GameSettings_python_key3_set", NULL); + RNA_def_property_enum_default(prop, LEFTALTKEY); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS); + RNA_def_property_ui_text(prop, "Python Console Key", "Third python console shortcut key"); + + prop = RNA_def_property(srna, "python_console_key4", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "pythonkeys[3]"); + RNA_def_property_enum_items(prop, rna_enum_event_type_items); + RNA_def_property_enum_funcs(prop, NULL, "rna_GameSettings_python_key4_set", NULL); + RNA_def_property_enum_default(prop, TKEY); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_UI_EVENTS); + RNA_def_property_ui_text(prop, "Python Console Key", "Fourth python console shortcut key"); + + /* materials */ prop = RNA_def_property(srna, "use_glsl_lights", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_GLSL_NO_LIGHTS); RNA_def_property_ui_text(prop, "GLSL Lights", "Use lights for GLSL rendering"); @@ -4836,11 +4906,6 @@ static void rna_def_scene_game_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "GLSL Nodes", "Use nodes for GLSL rendering"); RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_glsl_update"); - prop = RNA_def_property(srna, "use_glsl_color_management", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_GLSL_NO_COLOR_MANAGEMENT); - RNA_def_property_ui_text(prop, "GLSL Color Management", "Use color management for GLSL rendering"); - RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_glsl_update"); - prop = RNA_def_property(srna, "use_glsl_extra_textures", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_GLSL_NO_EXTRA_TEX); RNA_def_property_ui_text(prop, "GLSL Extra Textures", @@ -4852,12 +4917,6 @@ static void rna_def_scene_game_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "GLSL Environment Lighting", "Use environment lighting for GLSL rendering"); RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_glsl_update"); - prop = RNA_def_property(srna, "use_material_caching", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_NO_MATERIAL_CACHING); - RNA_def_property_ui_text(prop, "Use Material Caching", - "Cache materials in the converter (this is faster, but can cause problems with older " - "Singletexture and Multitexture games)"); - /* obstacle simulation */ prop = RNA_def_property(srna, "obstacle_simulation", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "obstacleSimulation"); diff --git a/source/blender/makesrna/intern/rna_sensor.c b/source/blender/makesrna/intern/rna_sensor.c index e04e78f3ac74..0cfdfa54ef22 100644 --- a/source/blender/makesrna/intern/rna_sensor.c +++ b/source/blender/makesrna/intern/rna_sensor.c @@ -58,6 +58,7 @@ static const EnumPropertyItem sensor_type_items[] = { {SENS_NEAR, "NEAR", 0, "Near", ""}, {SENS_PROPERTY, "PROPERTY", 0, "Property", ""}, {SENS_RADAR, "RADAR", 0, "Radar", ""}, + {SENS_MOVEMENT, "MOVEMENT", 0, "Movement", ""}, {SENS_RANDOM, "RANDOM", 0, "Random", ""}, {SENS_RAY, "RAY", 0, "Ray", ""}, {0, NULL, 0, NULL, NULL} @@ -93,6 +94,8 @@ static StructRNA *rna_Sensor_refine(struct PointerRNA *ptr) return &RNA_RandomSensor; case SENS_RAY: return &RNA_RaySensor; + case SENS_MOVEMENT: + return &RNA_MovementSensor; case SENS_MESSAGE: return &RNA_MessageSensor; case SENS_JOYSTICK: @@ -165,6 +168,7 @@ const EnumPropertyItem *rna_Sensor_type_itemf(bContext *C, PointerRNA *ptr, Prop RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_KEYBOARD); RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_MESSAGE); RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_MOUSE); + RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_MOVEMENT); RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_NEAR); RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_PROPERTY); RNA_enum_items_add_value(&item, &totitem, sensor_type_items, SENS_RADAR); @@ -445,6 +449,12 @@ static void rna_def_mouse_sensor(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", SENS_RAY_XRAY); RNA_def_property_ui_text(prop, "X-Ray", "Toggle X-Ray option (see through objects that don't have the property)"); RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop = RNA_def_property(srna, "mask", PROP_BOOLEAN, PROP_LAYER_MEMBER); + RNA_def_property_boolean_sdna(prop, NULL, "mask", 1); + RNA_def_property_array(prop, OB_MAX_COL_MASKS); + RNA_def_property_ui_text(prop, "Mask", "Mask filter compared with object's collision group"); + RNA_def_property_update(prop, NC_LOGIC, NULL); } static void rna_def_keyboard_sensor(BlenderRNA *brna) @@ -794,6 +804,52 @@ static void rna_def_ray_sensor(BlenderRNA *brna) RNA_def_property_enum_items(prop, axis_items); RNA_def_property_ui_text(prop, "Axis", "Along which axis the ray is cast"); RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop = RNA_def_property(srna, "mask", PROP_BOOLEAN, PROP_LAYER_MEMBER); + RNA_def_property_boolean_sdna(prop, NULL, "mask", 1); + RNA_def_property_array(prop, OB_MAX_COL_MASKS); + RNA_def_property_ui_text(prop, "Mask", "Mask filter compared with object's collision group"); + RNA_def_property_update(prop, NC_LOGIC, NULL); +} + +static void rna_def_movement_sensor(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + static const EnumPropertyItem axis_items[] = { + { SENS_MOVEMENT_X_AXIS, "XAXIS", 0, "+X axis", "" }, + { SENS_MOVEMENT_Y_AXIS, "YAXIS", 0, "+Y axis", "" }, + { SENS_MOVEMENT_Z_AXIS, "ZAXIS", 0, "+Z axis", "" }, + { SENS_MOVEMENT_NEG_X_AXIS, "NEGXAXIS", 0, "-X axis", "" }, + { SENS_MOVEMENT_NEG_Y_AXIS, "NEGYAXIS", 0, "-Y axis", "" }, + { SENS_MOVEMENT_NEG_Z_AXIS, "NEGZAXIS", 0, "-Z axis", "" }, + { SENS_MOVEMENT_ALL_AXIS, "ALLAXIS", 0, "All axis", "" }, + { 0, NULL, 0, NULL, NULL } + }; + + srna = RNA_def_struct(brna, "MovementSensor", "Sensor"); + RNA_def_struct_ui_text(srna, "Movement Sensor", "Sensor to detect if the owner has moved"); + RNA_def_struct_sdna_from(srna, "bMovementSensor", "data"); + + prop = RNA_def_property(srna, "axis", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "axisflag"); + RNA_def_property_enum_items(prop, axis_items); + RNA_def_property_ui_text(prop, "Axis", "Along which axis movement has to be detected"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop = RNA_def_property(srna, "use_local", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "localflag", SENS_MOVEMENT_LOCAL); + RNA_def_property_ui_text(prop, "Local", + "Toggle beetween local/global coordinates"); + RNA_def_property_update(prop, NC_LOGIC, NULL); + + prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "threshold"); + RNA_def_property_float_default(prop, 0.01f); + RNA_def_property_ui_text(prop, "Threshold", "Set Threshold"); + RNA_def_property_range(prop, 0.001f, 10000.0f); + RNA_def_property_ui_range(prop, 0.001, 10000.0, 0.1, 3); + RNA_def_property_update(prop, NC_LOGIC, NULL); } static void rna_def_message_sensor(BlenderRNA *brna) @@ -818,31 +874,57 @@ static void rna_def_joystick_sensor(BlenderRNA *brna) PropertyRNA *prop; static const EnumPropertyItem event_type_joystick_items[] = { - {SENS_JOY_BUTTON, "BUTTON", 0, "Button", ""}, - {SENS_JOY_AXIS, "AXIS", 0, "Axis", ""}, - {SENS_JOY_HAT, "HAT", 0, "Hat", ""}, - {SENS_JOY_AXIS_SINGLE, "AXIS_SINGLE", 0, "Single Axis", ""}, + {SENS_JOY_AXIS, "STICK_DIRECTIONS", 0, "Stick Directions", ""}, + {SENS_JOY_AXIS_SINGLE, "STICK_AXIS", 0, "Stick Axis", ""}, + {SENS_JOY_SHOULDER_TRIGGER, "SHOULDER_TRIGGERS", 0, "Shoulder Triggers", ""}, + {SENS_JOY_BUTTON, "BUTTONS", 0, "Buttons", ""}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem axis_items[] = { + {SENS_JOY_LEFT_STICK, "LEFT_STICK", 0, "Left Stick", ""}, + {SENS_JOY_RIGHT_STICK, "RIGHT_STICK", 0, "Right Stick", ""}, {0, NULL, 0, NULL, NULL} }; static const EnumPropertyItem axis_direction_items[] = { - {SENS_JOY_X_AXIS, "RIGHTAXIS", 0, "Right Axis", ""}, - {SENS_JOY_Y_AXIS, "UPAXIS", 0, "Up Axis", ""}, - {SENS_JOY_NEG_X_AXIS, "LEFTAXIS", 0, "Left Axis", ""}, - {SENS_JOY_NEG_Y_AXIS, "DOWNAXIS", 0, "Down Axis", ""}, + {SENS_JOY_X_AXIS, "RIGHTAXIS", 0, "Right", ""}, + {SENS_JOY_Y_AXIS, "UPAXIS", 0, "Up", ""}, + {SENS_JOY_NEG_X_AXIS, "LEFTAXIS", 0, "Left", ""}, + {SENS_JOY_NEG_Y_AXIS, "DOWNAXIS", 0, "Down", ""}, + {0, NULL, 0, NULL, NULL} + }; + + static const EnumPropertyItem axis_trigger_items[] = { + {SENS_JOY_LEFT_SHOULDER_TRIGGER, "LEFT_SHOULDER_TRIGGER", 0, "Left Shoulder Trigger", ""}, + {SENS_JOY_RIGHT_SHOULDER_TRIGGER, "RIGHT_SHOULDER_TRIGGER", 0, "Right Shoulder Trigger", ""}, {0, NULL, 0, NULL, NULL} }; - static const EnumPropertyItem hat_direction_items[] = { - {SENS_JOY_HAT_UP, "UP", 0, "Up", ""}, - {SENS_JOY_HAT_DOWN, "DOWN", 0, "Down", ""}, - {SENS_JOY_HAT_LEFT, "LEFT", 0, "Left", ""}, - {SENS_JOY_HAT_RIGHT, "RIGHT", 0, "Right", ""}, + static EnumPropertyItem axis_single_items[] = { + {SENS_JOY_LEFT_STICK_HORIZONTAL, "LEFT_STICK_HORIZONTAL", 0, "Left Stick Horizontal", ""}, + {SENS_JOY_LEFT_STICK_VERTICAL, "LEFT_STICK_VERTICAL", 0, "Left Stick Vertical", ""}, + {SENS_JOY_RIGHT_STICK_HORIZONTAL, "RIGHT_STICK_HORIZONTAL", 0, "Right Stick Horizontal", ""}, + {SENS_JOY_RIGHT_STICK_VERTICAL, "RIGHT_STICK_VERTICAL", 0, "Right Stick Vertical", ""}, + {0, NULL, 0, NULL, NULL} + }; - {SENS_JOY_HAT_UP_RIGHT, "UPRIGHT", 0, "Up/Right", ""}, - {SENS_JOY_HAT_DOWN_LEFT, "DOWNLEFT", 0, "Down/Left", ""}, - {SENS_JOY_HAT_UP_LEFT, "UPLEFT", 0, "Up/Left", ""}, - {SENS_JOY_HAT_DOWN_RIGHT, "DOWNRIGHT", 0, "Down/Right", ""}, + static EnumPropertyItem button_items[] = { + {SENS_JOY_BUTTON_A, "BUTTON_A", 0, "A", ""}, + {SENS_JOY_BUTTON_B, "BUTTON_B", 0, "B", ""}, + {SENS_JOY_BUTTON_X, "BUTTON_X", 0, "X", ""}, + {SENS_JOY_BUTTON_Y, "BUTTON_Y", 0, "Y", ""}, + {SENS_JOY_BUTTON_BACK, "BUTTON_BACK", 0, "Back", ""}, + {SENS_JOY_BUTTON_GUIDE, "BUTTON_GUIDE", 0, "Guide", ""}, + {SENS_JOY_BUTTON_START, "BUTTON_START", 0, "Start", ""}, + {SENS_JOY_BUTTON_STICK_LEFT, "BUTTON_STICK_LEFT", 0, "Left Stick", ""}, + {SENS_JOY_BUTTON_STICK_RIGHT, "BUTTON_STICK_RIGHT", 0, "Right Stick", ""}, + {SENS_JOY_BUTTON_SHOULDER_LEFT, "BUTTON_SHOULDER_LEFT", 0, "Left Shoulder", ""}, + {SENS_JOY_BUTTON_SHOULDER_RIGHT, "BUTTON_SHOULDER_RIGHT", 0, "Right Shoulder", ""}, + {SENS_JOY_BUTTON_DPAD_UP, "BUTTON_DPAD_UP", 0, "Dpad Up", ""}, + {SENS_JOY_BUTTON_DPAD_DOWN, "BUTTON_DPAD_DOWN", 0, "Dpad Down", ""}, + {SENS_JOY_BUTTON_DPAD_LEFT, "BUTTON_DPAD_LEFT", 0, "Dpad Left", ""}, + {SENS_JOY_BUTTON_DPAD_RIGHT, "BUTTON_DPAD_RIGHT", 0, "Dpad Right", ""}, {0, NULL, 0, NULL, NULL} }; @@ -852,7 +934,7 @@ static void rna_def_joystick_sensor(BlenderRNA *brna) prop = RNA_def_property(srna, "joystick_index", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "joyindex"); - RNA_def_property_ui_text(prop, "Index", "Which joystick to use"); + RNA_def_property_ui_text(prop, "Joystick Index", "Which joystick to use"); RNA_def_property_range(prop, 0, SENS_JOY_MAXINDEX - 1); RNA_def_property_update(prop, NC_LOGIC, NULL); @@ -866,53 +948,48 @@ static void rna_def_joystick_sensor(BlenderRNA *brna) prop = RNA_def_property(srna, "use_all_events", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SENS_JOY_ANY_EVENT); RNA_def_property_ui_text(prop, "All Events", - "Triggered by all events on this joystick's current type (axis/button/hat)"); + "Triggered by all events on this joystick's current type (axis/button)"); RNA_def_property_update(prop, NC_LOGIC, NULL); /* Button */ - prop = RNA_def_property(srna, "button_number", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "button"); - RNA_def_property_ui_text(prop, "Button Number", "Which button to use"); - RNA_def_property_range(prop, 0, 18); + prop = RNA_def_property(srna, "button_number", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "button"); + RNA_def_property_enum_items(prop, button_items); + RNA_def_property_ui_text(prop, "Button", "Which button to use"); RNA_def_property_update(prop, NC_LOGIC, NULL); /* Axis */ - prop = RNA_def_property(srna, "axis_number", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "axis"); - RNA_def_property_ui_text(prop, "Axis Number", "Which axis pair to use, 1 is usually the main direction input"); - RNA_def_property_range(prop, 1, 8); - RNA_def_property_update(prop, NC_LOGIC, NULL); - - prop = RNA_def_property(srna, "axis_threshold", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "precision"); - RNA_def_property_ui_text(prop, "Axis Threshold", "Precision of the axis"); - RNA_def_property_range(prop, 0, 32768); + prop = RNA_def_property(srna, "axis_number", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "axis"); + RNA_def_property_enum_items(prop, axis_items); + RNA_def_property_ui_text(prop, "Stick", "Which Stick to use"); RNA_def_property_update(prop, NC_LOGIC, NULL); prop = RNA_def_property(srna, "axis_direction", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "axisf"); RNA_def_property_enum_items(prop, axis_direction_items); - RNA_def_property_ui_text(prop, "Axis Direction", "The direction of the axis"); + RNA_def_property_ui_text(prop, "Stick Direction", "The direction of the stick"); RNA_def_property_update(prop, NC_LOGIC, NULL); - /* Single Axis */ - prop = RNA_def_property(srna, "single_axis_number", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "axis_single"); - RNA_def_property_ui_text(prop, "Axis Number", "Single axis (vertical/horizontal/other) to detect"); - RNA_def_property_range(prop, 1, 16); + /* Triggers */ + prop = RNA_def_property(srna, "axis_trigger_number", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "axis_single"); + RNA_def_property_enum_items(prop, axis_trigger_items); + RNA_def_property_ui_text(prop, "Triggers", "Which trigger to detect"); RNA_def_property_update(prop, NC_LOGIC, NULL); - /* Hat */ - prop = RNA_def_property(srna, "hat_number", PROP_INT, PROP_NONE); - RNA_def_property_int_sdna(prop, NULL, "hat"); - RNA_def_property_ui_text(prop, "Hat Number", "Which hat to use"); - RNA_def_property_range(prop, 1, 2); + /* Single Axis */ + prop = RNA_def_property(srna, "single_axis_number", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "axis_single"); + RNA_def_property_enum_items(prop, axis_single_items); + RNA_def_property_ui_text(prop, "Stick Axis", "Which stick single axis (vertical/horizontal/other) to detect"); RNA_def_property_update(prop, NC_LOGIC, NULL); - prop = RNA_def_property(srna, "hat_direction", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "hatf"); - RNA_def_property_enum_items(prop, hat_direction_items); - RNA_def_property_ui_text(prop, "Hat Direction", "Hat direction"); + /* Common */ + prop = RNA_def_property(srna, "axis_threshold", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "precision"); + RNA_def_property_ui_text(prop, "Threshold", "Threshold minimum to detect the stick/trigger"); + RNA_def_property_range(prop, 0, 32768); RNA_def_property_update(prop, NC_LOGIC, NULL); } @@ -932,6 +1009,7 @@ void RNA_def_sensor(BlenderRNA *brna) rna_def_radar_sensor(brna); rna_def_random_sensor(brna); rna_def_ray_sensor(brna); + rna_def_movement_sensor(brna); rna_def_message_sensor(brna); rna_def_joystick_sensor(brna); } diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index ae1761faec1b..e569c8958bfb 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -500,6 +500,14 @@ static void rna_SpaceView3D_lock_camera_and_layers_set(PointerRNA *ptr, bool val } } +static void rna_SpaceView3D_material_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr) +{ + View3D *v3d = (View3D *)(ptr->data); + if (v3d->scenelock) { + DAG_id_tag_update(&scene->id, 0); + } +} + static void rna_View3D_CursorLocation_get(PointerRNA *ptr, float *values) { View3D *v3d = (View3D *)(ptr->data); @@ -2625,6 +2633,11 @@ static void rna_def_space_view3d(BlenderRNA *brna) RNA_def_property_ui_text(prop, "World Background", "Display world colors in the background"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + prop = RNA_def_property(srna, "show_mist", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag2", V3D_SHOW_MIST); + RNA_def_property_ui_text(prop, "World Mist", "Display world mist"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_material_update"); + prop = RNA_def_property(srna, "use_occlude_geometry", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_ZBUF_SELECT); RNA_def_property_ui_text(prop, "Occlude Geometry", "Limit selection to visible (clipped with depth buffer)"); @@ -4484,6 +4497,11 @@ static void rna_def_space_logic(BlenderRNA *brna) RNA_def_struct_sdna(srna, "SpaceLogic"); RNA_def_struct_ui_text(srna, "Space Logic Editor", "Logic editor space data"); + /* Properties */ + prop = RNA_def_property(srna, "import_string", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "import_string"); + RNA_def_property_ui_text(prop, "Import String", "Import string used to find the component when adding a new component"); + /* sensors */ prop = RNA_def_property(srna, "show_sensors_selected_objects", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "scaflag", BUTS_SENS_SEL); diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index b2271c3903d9..aaefa3fd2a99 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -674,6 +674,11 @@ static void rna_def_mtex(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Size", "Set scaling for the texture's X, Y and Z sizes"); RNA_def_property_update(prop, 0, "rna_TextureSlot_update"); + prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_EULER); + RNA_def_property_float_sdna(prop, NULL, "rot"); + RNA_def_property_ui_text(prop, "Rotation", "Set rotation for the texture"); + RNA_def_property_update(prop, 0, "rna_TextureSlot_update"); + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); RNA_def_property_float_sdna(prop, NULL, "r"); RNA_def_property_array(prop, 3); @@ -776,6 +781,7 @@ static void rna_def_environment_map(BlenderRNA *brna) {ENV_STATIC, "STATIC", 0, "Static", "Calculate environment map only once"}, {ENV_ANIM, "ANIMATED", 0, "Animated", "Calculate environment map at each rendering"}, {ENV_LOAD, "IMAGE_FILE", 0, "Image File", "Load a saved environment map image from disk"}, + {ENV_REALT, "REALTIME", 0, "Realtime", "Image generated for realtime reflections in the game engine"}, {0, NULL, 0, NULL, NULL} }; @@ -785,6 +791,19 @@ static void rna_def_environment_map(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem prop_filtering_items[] = { + {ENVMAP_MIPMAP_NONE, "NONE", 0, "None", "None texture filtering"}, + {ENVMAP_MIPMAP_LINEAR, "LINEAR", 0, "Linear Filtering", "Linear texture filtering"}, + {ENVMAP_MIPMAP_MIPMAP, "MIPMAP", 0, "Mipmap Filtering", "Mipmap texture filtering"}, + {0, NULL, 0, NULL, NULL} + }; + + static EnumPropertyItem prop_mode_items[] = { + {ENVMAP_REFLECTION, "REFLECTION", 0, "Reflection", "Reflection rendering"}, + {ENVMAP_REFRACTION, "REFRACTION", 0, "Refraction", "Refraction rendering"}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "EnvironmentMap", NULL); RNA_def_struct_sdna(srna, "EnvMap"); RNA_def_struct_ui_text(srna, "EnvironmentMap", @@ -852,6 +871,26 @@ static void rna_def_environment_map(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Validity", "True if this map is ready for use, False if it needs rendering"); + prop = RNA_def_property(srna, "auto_update", PROP_BOOLEAN, 0); + RNA_def_property_boolean_sdna(prop, NULL, "flag", ENVMAP_AUTO_UPDATE); + RNA_def_property_ui_text(prop, "Auto Update", "True if the cube map is updated every frame"); + + prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "mode"); + RNA_def_property_enum_items(prop, prop_mode_items); + RNA_def_property_ui_text(prop, "Rendering Mode", "Texture rendering method"); + + prop = RNA_def_property(srna, "lod_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "lodfactor"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_ui_text(prop, "Level of Detail Distance Factor", "The factor applied to distance computed in Lod"); + + prop = RNA_def_property(srna, "filtering", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "filtering"); + RNA_def_property_enum_items(prop, prop_filtering_items); + RNA_def_property_ui_text(prop, "Filtering", "Texture filtering method"); + RNA_api_environment_map(srna); } diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index d647876796ac..014eea310854 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -830,6 +830,8 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_boolean(func, "compact", false, "", "Use more compact layout"); RNA_def_boolean(func, "multiview", false, "", "Expose Multi-View options"); + RNA_def_boolean(func, "cubemap", false, "", "Warn for invalid cube map size"); + RNA_def_boolean(func, "color_space", false, "", "Display color space option"); func = RNA_def_function(srna, "template_image_settings", "uiTemplateImageSettings"); RNA_def_function_ui_description(func, "User interface for setting image format options"); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index c3e30de10af8..3f72df223e29 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -3371,9 +3371,7 @@ static void rna_def_userdef_view(BlenderRNA *brna) prop = RNA_def_property(srna, "show_developer_ui", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_DEVELOPER_UI); - RNA_def_property_ui_text( - prop, "Developer Extras", - "Show options for developers (edit source in context menu, geometry indices)"); + RNA_def_property_ui_text(prop, "Developer Extras", "Show options for developers (edit source in context menu)"); prop = RNA_def_property(srna, "show_object_info", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_DRAWVIEWINFO); @@ -4089,7 +4087,7 @@ static void rna_def_userdef_system(BlenderRNA *brna) prop = RNA_def_property(srna, "use_scripts_auto_execute", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", USER_SCRIPT_AUTOEXEC_DISABLE); - RNA_def_property_ui_text(prop, "Auto Run Python Scripts", + RNA_def_property_ui_text(prop, "Auto Run Python Scripts and Components", "Allow any .blend file to run scripts automatically " "(unsafe with blend files from an untrusted source)"); RNA_def_property_update(prop, 0, "rna_userdef_script_autoexec_update"); diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c index 08287308e08b..ed5963f8c16f 100644 --- a/source/blender/makesrna/intern/rna_world.c +++ b/source/blender/makesrna/intern/rna_world.c @@ -35,6 +35,7 @@ #include "DNA_material_types.h" #include "DNA_texture_types.h" #include "DNA_world_types.h" +#include "DNA_scene_types.h" #include "WM_types.h" @@ -139,6 +140,12 @@ static void rna_def_world_mtex(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem color_management_items[] = { + {GAME_COLOR_MANAGEMENT_LINEAR, "COLOR_MANAGEMENT_LINEAR", 0, "Linear", "Linear color space"}, + {GAME_COLOR_MANAGEMENT_SRGB, "COLOR_MANAGEMENT_SRGB", 0, "sRGB", "sRGB color space"}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "WorldTextureSlot", "TextureSlot"); RNA_def_struct_sdna(srna, "MTex"); RNA_def_struct_ui_text(srna, "World Texture Slot", "Texture slot for textures in a World data-block"); @@ -164,6 +171,18 @@ static void rna_def_world_mtex(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Zenith Down", "Affect the color of the zenith below"); RNA_def_property_update(prop, 0, "rna_World_update"); + prop = RNA_def_property(srna, "color_management", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "colorManagement"); + RNA_def_property_enum_items(prop, color_management_items); + RNA_def_property_ui_text(prop, "Color Space", "The color space of the image"); + RNA_def_property_update(prop, 0, "rna_World_update"); + + prop = RNA_def_property(srna, "lod_bias", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "lodbias"); + RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 10, 3); + RNA_def_property_ui_text(prop, "Lod Bias", "Amount bias on mipmapping"); + RNA_def_property_update(prop, 0, "rna_World_update"); + prop = RNA_def_property(srna, "texture_coords", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "texco"); RNA_def_property_enum_items(prop, texco_items); diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 7ef41b25de89..fbae0f76114d 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -185,12 +185,14 @@ set(SRC shader/nodes/node_shader_light_path.c shader/nodes/node_shader_mix_shader.c shader/nodes/node_shader_normal_map.c + shader/nodes/node_shader_object.c shader/nodes/node_shader_object_info.c shader/nodes/node_shader_hair_info.c shader/nodes/node_shader_output_lamp.c shader/nodes/node_shader_output_material.c shader/nodes/node_shader_output_world.c shader/nodes/node_shader_output_linestyle.c + shader/nodes/node_shader_parallax.c shader/nodes/node_shader_particle_info.c shader/nodes/node_shader_script.c shader/nodes/node_shader_subsurface_scattering.c @@ -211,6 +213,7 @@ set(SRC shader/nodes/node_shader_tex_sky.c shader/nodes/node_shader_tex_voronoi.c shader/nodes/node_shader_tex_wave.c + shader/nodes/node_shader_time.c shader/nodes/node_shader_volume_scatter.c shader/nodes/node_shader_volume_absorption.c shader/nodes/node_shader_volume_principled.c diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h index d4134f09597f..108e18902102 100644 --- a/source/blender/nodes/NOD_shader.h +++ b/source/blender/nodes/NOD_shader.h @@ -47,6 +47,8 @@ void register_node_type_sh_group(void); void register_node_type_sh_output(void); void register_node_type_sh_material(void); void register_node_type_sh_camera(void); +void register_node_type_sh_object(void); +void register_node_type_sh_time(void); void register_node_type_sh_lamp(void); void register_node_type_sh_value(void); void register_node_type_sh_rgb(void); @@ -59,6 +61,7 @@ void register_node_type_sh_gamma(void); void register_node_type_sh_brightcontrast(void); void register_node_type_sh_geom(void); void register_node_type_sh_mapping(void); +void register_node_type_sh_parallax(void); void register_node_type_sh_curve_vec(void); void register_node_type_sh_curve_rgb(void); void register_node_type_sh_math(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 2fa8cda56a56..739ebe47a25f 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -53,9 +53,12 @@ DefNode( ShaderNode, SH_NODE_GAMMA, 0, "GAMMA DefNode( ShaderNode, SH_NODE_BRIGHTCONTRAST, 0, "BRIGHTCONTRAST", BrightContrast, "Bright Contrast", "" ) DefNode( ShaderNode, SH_NODE_GEOMETRY, def_sh_geometry, "GEOMETRY", Geometry, "Geometry", "" ) DefNode( ShaderNode, SH_NODE_MAPPING, def_sh_mapping, "MAPPING", Mapping, "Mapping", "" ) +DefNode( ShaderNode, SH_NODE_PARALLAX, def_parallax, "PARALLAX", Parallax, "Parallax", "" ) DefNode( ShaderNode, SH_NODE_CURVE_VEC, def_vector_curve, "CURVE_VEC", VectorCurve, "Vector Curves", "" ) DefNode( ShaderNode, SH_NODE_CURVE_RGB, def_rgb_curve, "CURVE_RGB", RGBCurve, "RGB Curves", "" ) DefNode( ShaderNode, SH_NODE_CAMERA, 0, "CAMERA", CameraData, "Camera Data", "" ) +DefNode( ShaderNode, SH_NODE_OBJECT, 0, "OBJECT", ObjectData, "Object Data", "" ) +DefNode( ShaderNode, SH_NODE_TIME, 0, "TIME", Time, "Time", "" ) DefNode( ShaderNode, SH_NODE_LAMP, def_sh_lamp, "LAMP", LampData, "Lamp Data", "" ) DefNode( ShaderNode, SH_NODE_MATH, def_math, "MATH", Math, "Math", "" ) DefNode( ShaderNode, SH_NODE_VECT_MATH, def_vector_math, "VECT_MATH", VectorMath, "Vector Math", "" ) diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c index 19529794c7cc..1c52d0e4ac40 100644 --- a/source/blender/nodes/intern/node_util.c +++ b/source/blender/nodes/intern/node_util.c @@ -118,6 +118,13 @@ void node_filter_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int m BLI_strncpy(label, IFACE_(name), maxlen); } +void node_parallax_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) +{ + const char *name; + RNA_enum_name(rna_enum_node_parallax_items, node->custom1, &name); + BLI_strncpy(label, IFACE_(name), maxlen); +} + /*** Link Insertion ***/ diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h index 5c0e53c2399e..cd6699fe8597 100644 --- a/source/blender/nodes/intern/node_util.h +++ b/source/blender/nodes/intern/node_util.h @@ -76,6 +76,7 @@ void node_image_label(struct bNodeTree *ntree, struct bNode *node, char *label, void node_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); void node_vect_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); void node_filter_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); +void node_parallax_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen); /*** Link Handling */ diff --git a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c index 995ff0cfd401..c453b730a449 100644 --- a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c +++ b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c @@ -44,7 +44,7 @@ static bNodeSocketTemplate sh_node_ambient_occlusion_out[] = { static int node_shader_gpu_ambient_occlusion(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { - return GPU_stack_link(mat, "node_ambient_occlusion", in, out, GPU_builtin(GPU_VIEW_NORMAL)); + return GPU_stack_link(mat, "node_ambient_occlusion", in, out, GPU_material_builtin(mat, GPU_VIEW_NORMAL)); } static void node_shader_init_ambient_occlusion(bNodeTree *UNUSED(ntree), bNode *node) diff --git a/source/blender/nodes/shader/nodes/node_shader_background.c b/source/blender/nodes/shader/nodes/node_shader_background.c index b387529e456c..772c273a3b8e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_background.c +++ b/source/blender/nodes/shader/nodes/node_shader_background.c @@ -42,7 +42,7 @@ static bNodeSocketTemplate sh_node_background_out[] = { static int node_shader_gpu_background(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { - return GPU_stack_link(mat, "node_background", in, out, GPU_builtin(GPU_VIEW_NORMAL)); + return GPU_stack_link(mat, "node_background", in, out, GPU_material_builtin(mat, GPU_VIEW_NORMAL)); } /* node type definition */ diff --git a/source/blender/nodes/shader/nodes/node_shader_bevel.c b/source/blender/nodes/shader/nodes/node_shader_bevel.c index e2e4da21ef3f..ee36cf73e3ca 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bevel.c +++ b/source/blender/nodes/shader/nodes/node_shader_bevel.c @@ -48,7 +48,7 @@ static void node_shader_init_bevel(bNodeTree *UNUSED(ntree), bNode *node) static int gpu_shader_bevel(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { if (!in[1].link) { - GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL), GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &in[1].link); + GPU_link(mat, "direction_transform_m4v3", GPU_material_builtin(mat, GPU_VIEW_NORMAL), GPU_material_builtin(mat, GPU_INVERSE_VIEW_MATRIX), &in[1].link); } return GPU_stack_link(mat, "node_bevel", in, out); diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c index 6410441797a6..5fc6cd8413e5 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c @@ -52,9 +52,9 @@ static void node_shader_init_anisotropic(bNodeTree *UNUSED(ntree), bNode *node) static int node_shader_gpu_bsdf_anisotropic(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { if (!in[4].link) - in[4].link = GPU_builtin(GPU_VIEW_NORMAL); + in[4].link = GPU_material_builtin(mat, GPU_VIEW_NORMAL); else - GPU_link(mat, "direction_transform_m4v3", in[4].link, GPU_builtin(GPU_VIEW_MATRIX), &in[4].link); + GPU_link(mat, "direction_transform_m4v3", in[4].link, GPU_material_builtin(mat, GPU_VIEW_MATRIX), &in[4].link); return GPU_stack_link(mat, "node_bsdf_anisotropic", in, out); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c index e86d2677a61e..c129473bc9a6 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c @@ -44,9 +44,9 @@ static bNodeSocketTemplate sh_node_bsdf_diffuse_out[] = { static int node_shader_gpu_bsdf_diffuse(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { if (!in[2].link) - in[2].link = GPU_builtin(GPU_VIEW_NORMAL); + in[2].link = GPU_material_builtin(mat, GPU_VIEW_NORMAL); else - GPU_link(mat, "direction_transform_m4v3", in[2].link, GPU_builtin(GPU_VIEW_MATRIX), &in[2].link); + GPU_link(mat, "direction_transform_m4v3", in[2].link, GPU_material_builtin(mat, GPU_VIEW_MATRIX), &in[2].link); return GPU_stack_link(mat, "node_bsdf_diffuse", in, out); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c index 529dfbc3df48..99dc2272e5ab 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c @@ -50,9 +50,9 @@ static void node_shader_init_glass(bNodeTree *UNUSED(ntree), bNode *node) static int node_shader_gpu_bsdf_glass(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { if (!in[3].link) - in[3].link = GPU_builtin(GPU_VIEW_NORMAL); + in[3].link = GPU_material_builtin(mat, GPU_VIEW_NORMAL); else - GPU_link(mat, "direction_transform_m4v3", in[3].link, GPU_builtin(GPU_VIEW_MATRIX), &in[3].link); + GPU_link(mat, "direction_transform_m4v3", in[3].link, GPU_material_builtin(mat, GPU_VIEW_MATRIX), &in[3].link); return GPU_stack_link(mat, "node_bsdf_glass", in, out); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c index fd55ab0ce175..f7ec2d1b5435 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c @@ -49,9 +49,9 @@ static void node_shader_init_glossy(bNodeTree *UNUSED(ntree), bNode *node) static int node_shader_gpu_bsdf_glossy(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { if (!in[2].link) - in[2].link = GPU_builtin(GPU_VIEW_NORMAL); + in[2].link = GPU_material_builtin(mat, GPU_VIEW_NORMAL); else - GPU_link(mat, "direction_transform_m4v3", in[2].link, GPU_builtin(GPU_VIEW_MATRIX), &in[2].link); + GPU_link(mat, "direction_transform_m4v3", in[2].link, GPU_material_builtin(mat, GPU_VIEW_MATRIX), &in[2].link); return GPU_stack_link(mat, "node_bsdf_glossy", in, out); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c index e3b3f0fc9a60..dd025ed513d3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c @@ -68,17 +68,17 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, bNode *UNUSED(node) { // normal if (!in[17].link) - in[17].link = GPU_builtin(GPU_VIEW_NORMAL); + in[17].link = GPU_material_builtin(mat, GPU_VIEW_NORMAL); else - GPU_link(mat, "direction_transform_m4v3", in[17].link, GPU_builtin(GPU_VIEW_MATRIX), &in[17].link); + GPU_link(mat, "direction_transform_m4v3", in[17].link, GPU_material_builtin(mat, GPU_VIEW_MATRIX), &in[17].link); // clearcoat normal if (!in[18].link) - in[18].link = GPU_builtin(GPU_VIEW_NORMAL); + in[18].link = GPU_material_builtin(mat, GPU_VIEW_NORMAL); else - GPU_link(mat, "direction_transform_m4v3", in[18].link, GPU_builtin(GPU_VIEW_MATRIX), &in[18].link); + GPU_link(mat, "direction_transform_m4v3", in[18].link, GPU_material_builtin(mat, GPU_VIEW_MATRIX), &in[18].link); - return GPU_stack_link(mat, "node_bsdf_principled", in, out, GPU_builtin(GPU_VIEW_POSITION)); + return GPU_stack_link(mat, "node_bsdf_principled", in, out, GPU_material_builtin(mat, GPU_VIEW_POSITION)); } static void node_shader_update_principled(bNodeTree *UNUSED(ntree), bNode *node) diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c index 4b16fcab081f..31f364903eba 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c @@ -50,9 +50,9 @@ static void node_shader_init_refraction(bNodeTree *UNUSED(ntree), bNode *node) static int node_shader_gpu_bsdf_refraction(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { if (!in[3].link) - in[3].link = GPU_builtin(GPU_VIEW_NORMAL); + in[3].link = GPU_material_builtin(mat, GPU_VIEW_NORMAL); else - GPU_link(mat, "direction_transform_m4v3", in[3].link, GPU_builtin(GPU_VIEW_MATRIX), &in[3].link); + GPU_link(mat, "direction_transform_m4v3", in[3].link, GPU_material_builtin(mat, GPU_VIEW_MATRIX), &in[3].link); return GPU_stack_link(mat, "node_bsdf_refraction", in, out); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c index b268779d6bb3..6a7fe85237d4 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c @@ -45,9 +45,9 @@ static bNodeSocketTemplate sh_node_bsdf_toon_out[] = { static int node_shader_gpu_bsdf_toon(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { if (!in[3].link) - in[3].link = GPU_builtin(GPU_VIEW_NORMAL); + in[3].link = GPU_material_builtin(mat, GPU_VIEW_NORMAL); else - GPU_link(mat, "direction_transform_m4v3", in[3].link, GPU_builtin(GPU_VIEW_MATRIX), &in[3].link); + GPU_link(mat, "direction_transform_m4v3", in[3].link, GPU_material_builtin(mat, GPU_VIEW_MATRIX), &in[3].link); return GPU_stack_link(mat, "node_bsdf_toon", in, out); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c index 3eee8a08fa2f..fda6922fa64a 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c @@ -43,9 +43,9 @@ static bNodeSocketTemplate sh_node_bsdf_translucent_out[] = { static int node_shader_gpu_bsdf_translucent(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { if (!in[1].link) - in[1].link = GPU_builtin(GPU_VIEW_NORMAL); + in[1].link = GPU_material_builtin(mat, GPU_VIEW_NORMAL); else - GPU_link(mat, "direction_transform_m4v3", in[1].link, GPU_builtin(GPU_VIEW_MATRIX), &in[1].link); + GPU_link(mat, "direction_transform_m4v3", in[1].link, GPU_material_builtin(mat, GPU_VIEW_MATRIX), &in[1].link); return GPU_stack_link(mat, "node_bsdf_translucent", in, out); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c index 69bc74793e76..88a1b62d853a 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c @@ -44,9 +44,9 @@ static bNodeSocketTemplate sh_node_bsdf_velvet_out[] = { static int node_shader_gpu_bsdf_velvet(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { if (!in[2].link) - in[2].link = GPU_builtin(GPU_VIEW_NORMAL); + in[2].link = GPU_material_builtin(mat, GPU_VIEW_NORMAL); else - GPU_link(mat, "direction_transform_m4v3", in[2].link, GPU_builtin(GPU_VIEW_MATRIX), &in[2].link); + GPU_link(mat, "direction_transform_m4v3", in[2].link, GPU_material_builtin(mat, GPU_VIEW_MATRIX), &in[2].link); return GPU_stack_link(mat, "node_bsdf_velvet", in, out); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.c b/source/blender/nodes/shader/nodes/node_shader_bump.c index 41df17cef674..c39cc890ac4a 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bump.c +++ b/source/blender/nodes/shader/nodes/node_shader_bump.c @@ -48,18 +48,18 @@ static bNodeSocketTemplate sh_node_bump_out[] = { static int gpu_shader_bump(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { if (!in[3].link) - in[3].link = GPU_builtin(GPU_VIEW_NORMAL); + in[3].link = GPU_material_builtin(mat, GPU_VIEW_NORMAL); else - GPU_link(mat, "direction_transform_m4v3", in[3].link, GPU_builtin(GPU_VIEW_MATRIX), &in[3].link); + GPU_link(mat, "direction_transform_m4v3", in[3].link, GPU_material_builtin(mat, GPU_VIEW_MATRIX), &in[3].link); float invert = node->custom1; - GPU_stack_link(mat, "node_bump", in, out, GPU_builtin(GPU_VIEW_POSITION), GPU_uniform(&invert)); + GPU_stack_link(mat, "node_bump", in, out, GPU_material_builtin(mat, GPU_VIEW_POSITION), GPU_uniform(&invert)); /* Other nodes are applying view matrix if the input Normal has a link. * We don't want normal to have view matrix applied twice, so we cancel it here. * * TODO(sergey): This is an extra multiplication which cancels each other, * better avoid this but that requires bigger refactor. */ - return GPU_link(mat, "direction_transform_m4v3", out[0].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[0].link); + return GPU_link(mat, "direction_transform_m4v3", out[0].link, GPU_material_builtin(mat, GPU_INVERSE_VIEW_MATRIX), &out[0].link); } /* node type definition */ diff --git a/source/blender/nodes/shader/nodes/node_shader_camera.c b/source/blender/nodes/shader/nodes/node_shader_camera.c index b1c3a817b84e..4e250d593412 100644 --- a/source/blender/nodes/shader/nodes/node_shader_camera.c +++ b/source/blender/nodes/shader/nodes/node_shader_camera.c @@ -56,7 +56,7 @@ static int gpu_shader_camera(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecDat { GPUNodeLink *viewvec; - viewvec = GPU_builtin(GPU_VIEW_POSITION); + viewvec = GPU_material_builtin(mat, GPU_VIEW_POSITION); /* Blender has negative Z, Cycles positive Z convention */ if (GPU_material_use_new_shading_nodes(mat)) diff --git a/source/blender/nodes/shader/nodes/node_shader_displacement.c b/source/blender/nodes/shader/nodes/node_shader_displacement.c index e259a9e3f6d2..9ed982e2a479 100644 --- a/source/blender/nodes/shader/nodes/node_shader_displacement.c +++ b/source/blender/nodes/shader/nodes/node_shader_displacement.c @@ -57,14 +57,14 @@ static void node_shader_init_displacement(bNodeTree *UNUSED(ntree), bNode *node) static int gpu_shader_displacement(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { if (!in[3].link) { - GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL), GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &in[3].link); + GPU_link(mat, "direction_transform_m4v3", GPU_material_builtin(mat, GPU_VIEW_NORMAL), GPU_material_builtin(mat, GPU_INVERSE_VIEW_MATRIX), &in[3].link); } if (node->custom1 == SHD_SPACE_OBJECT) { - return GPU_stack_link(mat, "node_displacement_object", in, out, GPU_builtin(GPU_OBJECT_MATRIX)); + return GPU_stack_link(mat, "node_displacement_object", in, out, GPU_material_builtin(mat, GPU_OBJECT_MATRIX)); } else { - return GPU_stack_link(mat, "node_displacement_world", in, out, GPU_builtin(GPU_OBJECT_MATRIX)); + return GPU_stack_link(mat, "node_displacement_world", in, out, GPU_material_builtin(mat, GPU_OBJECT_MATRIX)); } } diff --git a/source/blender/nodes/shader/nodes/node_shader_emission.c b/source/blender/nodes/shader/nodes/node_shader_emission.c index 2838e9dc54d7..bf3a19ce2ee1 100644 --- a/source/blender/nodes/shader/nodes/node_shader_emission.c +++ b/source/blender/nodes/shader/nodes/node_shader_emission.c @@ -42,7 +42,7 @@ static bNodeSocketTemplate sh_node_emission_out[] = { static int node_shader_gpu_emission(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { - return GPU_stack_link(mat, "node_emission", in, out, GPU_builtin(GPU_VIEW_NORMAL)); + return GPU_stack_link(mat, "node_emission", in, out, GPU_material_builtin(mat, GPU_VIEW_NORMAL)); } /* node type definition */ diff --git a/source/blender/nodes/shader/nodes/node_shader_fresnel.c b/source/blender/nodes/shader/nodes/node_shader_fresnel.c index 393d2c5fee01..9d559f001f57 100644 --- a/source/blender/nodes/shader/nodes/node_shader_fresnel.c +++ b/source/blender/nodes/shader/nodes/node_shader_fresnel.c @@ -42,13 +42,13 @@ static bNodeSocketTemplate sh_node_fresnel_out[] = { static int node_shader_gpu_fresnel(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { if (!in[1].link) { - in[1].link = GPU_builtin(GPU_VIEW_NORMAL); + in[1].link = GPU_material_builtin(mat, GPU_VIEW_NORMAL); } else if (GPU_material_use_world_space_shading(mat)) { - GPU_link(mat, "direction_transform_m4v3", in[1].link, GPU_builtin(GPU_VIEW_MATRIX), &in[1].link); + GPU_link(mat, "direction_transform_m4v3", in[1].link, GPU_material_builtin(mat, GPU_VIEW_MATRIX), &in[1].link); } - return GPU_stack_link(mat, "node_fresnel", in, out, GPU_builtin(GPU_VIEW_POSITION)); + return GPU_stack_link(mat, "node_fresnel", in, out, GPU_material_builtin(mat, GPU_VIEW_POSITION)); } static void node_shader_exec_fresnel(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) diff --git a/source/blender/nodes/shader/nodes/node_shader_geom.c b/source/blender/nodes/shader/nodes/node_shader_geom.c index 0a51ee8dc68b..42d9ef41b999 100644 --- a/source/blender/nodes/shader/nodes/node_shader_geom.c +++ b/source/blender/nodes/shader/nodes/node_shader_geom.c @@ -137,11 +137,11 @@ static int gpu_shader_geom(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED( GPUNodeLink *mcol = GPU_attribute(CD_MCOL, ngeo->colname); bool ret = GPU_stack_link(mat, "geom", in, out, - GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL), - GPU_builtin(GPU_INVERSE_VIEW_MATRIX), orco, mtface, mcol); + GPU_material_builtin(mat, GPU_VIEW_POSITION), GPU_material_builtin(mat, GPU_VIEW_NORMAL), + GPU_material_builtin(mat, GPU_INVERSE_VIEW_MATRIX), orco, mtface, mcol); if (GPU_material_use_world_space_shading(mat)) { GPU_link(mat, "vec_math_negate", out[5].link, &out[5].link); - ret &= GPU_link(mat, "direction_transform_m4v3", out[5].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[5].link); + ret &= GPU_link(mat, "direction_transform_m4v3", out[5].link, GPU_material_builtin(mat, GPU_INVERSE_VIEW_MATRIX), &out[5].link); } return ret; } diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.c b/source/blender/nodes/shader/nodes/node_shader_geometry.c index d73628ebd670..e48450af0030 100644 --- a/source/blender/nodes/shader/nodes/node_shader_geometry.c +++ b/source/blender/nodes/shader/nodes/node_shader_geometry.c @@ -44,8 +44,8 @@ static bNodeSocketTemplate sh_node_geometry_out[] = { static int node_shader_gpu_geometry(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { return GPU_stack_link(mat, "node_geometry", in, out, - GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL), - GPU_builtin(GPU_INVERSE_VIEW_MATRIX)); + GPU_material_builtin(mat, GPU_VIEW_POSITION), GPU_material_builtin(mat, GPU_VIEW_NORMAL), + GPU_material_builtin(mat, GPU_INVERSE_VIEW_MATRIX)); } /* node type definition */ diff --git a/source/blender/nodes/shader/nodes/node_shader_lamp.c b/source/blender/nodes/shader/nodes/node_shader_lamp.c index 5dd3a9cd5075..913c361cd7a9 100644 --- a/source/blender/nodes/shader/nodes/node_shader_lamp.c +++ b/source/blender/nodes/shader/nodes/node_shader_lamp.c @@ -70,7 +70,7 @@ static int gpu_shader_lamp(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED( bool ret = GPU_stack_link(mat, "lamp", in, out, col, energy, lv, dist, shadow, visifac); if (GPU_material_use_world_space_shading(mat)) - ret &= GPU_link(mat, "direction_transform_m4v3", out[1].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[1].link); + ret &= GPU_link(mat, "direction_transform_m4v3", out[1].link, GPU_material_builtin(mat, GPU_INVERSE_VIEW_MATRIX), &out[1].link); return ret; } diff --git a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c b/source/blender/nodes/shader/nodes/node_shader_layer_weight.c index 3d27d6bef7f8..187dd8ab2c02 100644 --- a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c +++ b/source/blender/nodes/shader/nodes/node_shader_layer_weight.c @@ -44,12 +44,12 @@ static bNodeSocketTemplate sh_node_layer_weight_out[] = { static int node_shader_gpu_layer_weight(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { if (!in[1].link) - in[1].link = GPU_builtin(GPU_VIEW_NORMAL); + in[1].link = GPU_material_builtin(mat, GPU_VIEW_NORMAL); else if (GPU_material_use_world_space_shading(mat)) { - GPU_link(mat, "direction_transform_m4v3", in[1].link, GPU_builtin(GPU_VIEW_MATRIX), &in[1].link); + GPU_link(mat, "direction_transform_m4v3", in[1].link, GPU_material_builtin(mat, GPU_VIEW_MATRIX), &in[1].link); } - return GPU_stack_link(mat, "node_layer_weight", in, out, GPU_builtin(GPU_VIEW_POSITION)); + return GPU_stack_link(mat, "node_layer_weight", in, out, GPU_material_builtin(mat, GPU_VIEW_POSITION)); } static void node_shader_exec_layer_weight(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) diff --git a/source/blender/nodes/shader/nodes/node_shader_material.c b/source/blender/nodes/shader/nodes/node_shader_material.c index 8a73ddc11940..fa4087fa7efe 100644 --- a/source/blender/nodes/shader/nodes/node_shader_material.c +++ b/source/blender/nodes/shader/nodes/node_shader_material.c @@ -280,7 +280,7 @@ static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNU shi.vn = gpu_get_input_link(mat, &in[MAT_IN_NORMAL]); if (GPU_material_use_world_space_shading(mat)) { GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn); - GPU_link(mat, "direction_transform_m4v3", shi.vn, GPU_builtin(GPU_VIEW_MATRIX), &shi.vn); + GPU_link(mat, "direction_transform_m4v3", shi.vn, GPU_material_builtin(mat, GPU_VIEW_MATRIX), &shi.vn); } GPU_link(mat, "vec_math_normalize", shi.vn, &shi.vn, &tmp); } @@ -328,7 +328,7 @@ static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNU out[MAT_OUT_NORMAL].link = shi.vn; if (GPU_material_use_world_space_shading(mat)) { GPU_link(mat, "vec_math_negate", out[MAT_OUT_NORMAL].link, &out[MAT_OUT_NORMAL].link); - GPU_link(mat, "direction_transform_m4v3", out[MAT_OUT_NORMAL].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[MAT_OUT_NORMAL].link); + GPU_link(mat, "direction_transform_m4v3", out[MAT_OUT_NORMAL].link, GPU_material_builtin(mat, GPU_INVERSE_VIEW_MATRIX), &out[MAT_OUT_NORMAL].link); } if (node->type == SH_NODE_MATERIAL_EXT) { diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.c index 7584b5eba4dd..b3b6f6655fb7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c +++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c @@ -142,7 +142,7 @@ static int gpu_shader_normal_map(GPUMaterial *mat, bNode *node, bNodeExecData *U else realnorm = GPU_uniform(in[1].vec); - negnorm = GPU_builtin(GPU_VIEW_NORMAL); + negnorm = GPU_material_builtin(mat, GPU_VIEW_NORMAL); GPU_link(mat, "math_max", strength, GPU_uniform(d), &strength); if (GPU_material_use_world_space_shading(mat)) { @@ -156,20 +156,20 @@ static int gpu_shader_normal_map(GPUMaterial *mat, bNode *node, bNodeExecData *U case SHD_SPACE_TANGENT: GPU_link(mat, "color_to_normal_new_shading", realnorm, &realnorm); GPU_link(mat, "node_normal_map", GPU_attribute(CD_TANGENT, nm->uv_map), negnorm, realnorm, &realnorm); - GPU_link(mat, "vec_math_mix", strength, realnorm, GPU_builtin(GPU_VIEW_NORMAL), &out[0].link); + GPU_link(mat, "vec_math_mix", strength, realnorm, GPU_material_builtin(mat, GPU_VIEW_NORMAL), &out[0].link); /* for uniform scale this is sufficient to match Cycles */ - GPU_link(mat, "direction_transform_m4v3", out[0].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &out[0].link); + GPU_link(mat, "direction_transform_m4v3", out[0].link, GPU_material_builtin(mat, GPU_INVERSE_VIEW_MATRIX), &out[0].link); GPU_link(mat, "vect_normalize", out[0].link, &out[0].link); return true; case SHD_SPACE_OBJECT: case SHD_SPACE_BLENDER_OBJECT: - GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm); + GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_material_builtin(mat, GPU_INVERSE_VIEW_MATRIX), &negnorm); GPU_link(mat, color_to_normal_fnc_name, realnorm, &realnorm); - GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_OBJECT_MATRIX), &realnorm); + GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_material_builtin(mat, GPU_OBJECT_MATRIX), &realnorm); break; case SHD_SPACE_WORLD: case SHD_SPACE_BLENDER_WORLD: - GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &negnorm); + GPU_link(mat, "direction_transform_m4v3", negnorm, GPU_material_builtin(mat, GPU_INVERSE_VIEW_MATRIX), &negnorm); GPU_link(mat, color_to_normal_fnc_name, realnorm, &realnorm); break; } @@ -189,11 +189,11 @@ static int gpu_shader_normal_map(GPUMaterial *mat, bNode *node, bNodeExecData *U break; case SHD_SPACE_OBJECT: case SHD_SPACE_BLENDER_OBJECT: - GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_LOC_TO_VIEW_MATRIX), &realnorm); + GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_material_builtin(mat, GPU_LOC_TO_VIEW_MATRIX), &realnorm); break; case SHD_SPACE_WORLD: case SHD_SPACE_BLENDER_WORLD: - GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_builtin(GPU_VIEW_MATRIX), &realnorm); + GPU_link(mat, "direction_transform_m4v3", realnorm, GPU_material_builtin(mat, GPU_VIEW_MATRIX), &realnorm); break; } } diff --git a/source/blender/nodes/shader/nodes/node_shader_object.c b/source/blender/nodes/shader/nodes/node_shader_object.c new file mode 100644 index 000000000000..1243c3876342 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_object.c @@ -0,0 +1,59 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/nodes/shader/nodes/node_shader_object.c + * \ingroup shdnodes + */ + + +#include "node_shader_util.h" + +/* **************** OBJECT INFO ******************** */ +static bNodeSocketTemplate sh_node_object_out[] = { + { SOCK_RGBA, 0, N_("Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { -1, 0, "" } +}; + +static int gpu_shader_object(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) +{ + GPUNodeLink *obcolor = GPU_material_builtin(mat, GPU_OBCOLOR); + + return GPU_stack_link(mat, "set_rgba", in, out, obcolor); +} + +void register_node_type_sh_object(void) +{ + static bNodeType ntype; + + sh_node_type_base(&ntype, SH_NODE_OBJECT, "Object Data", NODE_CLASS_INPUT, 0); + node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING); + node_type_socket_templates(&ntype, NULL, sh_node_object_out); + node_type_storage(&ntype, "", NULL, NULL); + node_type_gpu(&ntype, gpu_shader_object); + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/shader/nodes/node_shader_object_info.c b/source/blender/nodes/shader/nodes/node_shader_object_info.c index 9c7ea549ea50..8728d95680a7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_object_info.c +++ b/source/blender/nodes/shader/nodes/node_shader_object_info.c @@ -39,7 +39,7 @@ static bNodeSocketTemplate sh_node_object_info_out[] = { static int node_shader_gpu_object_info(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { - return GPU_stack_link(mat, "node_object_info", in, out, GPU_builtin(GPU_OBJECT_MATRIX), GPU_builtin(GPU_OBJECT_INFO)); + return GPU_stack_link(mat, "node_object_info", in, out, GPU_material_builtin(mat, GPU_OBJECT_MATRIX), GPU_material_builtin(mat, GPU_OBJECT_INFO)); } static void node_shader_exec_object_info(void *data, int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **UNUSED(in), bNodeStack **out) diff --git a/source/blender/nodes/shader/nodes/node_shader_parallax.c b/source/blender/nodes/shader/nodes/node_shader_parallax.c new file mode 100644 index 000000000000..9147aedd44e1 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_parallax.c @@ -0,0 +1,87 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/nodes/shader/nodes/node_shader_parallax.c + * \ingroup shdnodes + */ + + +#include "node_shader_util.h" + +/* **************** OBJECT INFO ******************** */ +static bNodeSocketTemplate sh_node_mapping_in[] = { + { SOCK_VECTOR, 1, N_("UV")}, + { SOCK_FLOAT, 1, N_("Steps"), 10.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f, PROP_NONE, 0 }, + { SOCK_FLOAT, 1, N_("Bump Scale"), 0.01f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f, PROP_NONE, 0 }, + { -1, 0, "" } +}; + +static bNodeSocketTemplate sh_node_parallax_out[] = { + { SOCK_VECTOR, 0, N_("UV")}, + { -1, 0, "" } +}; + +static int gpu_shader_parallax(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) +{ + Tex *tex = (Tex *)node->id; + + if (tex && tex->ima && (tex->type == TEX_IMAGE)) { + GPUNodeLink *texlink = GPU_image(tex->ima, &tex->iuser, false); + GPUNodeLink *texco; + GPUNodeLink *norm; + GPUNodeLink *outuv; + float one[3] = { 1.0f, 1.0f, 1.0f }; + + for (unsigned short i = 0; i < 3; ++i) { + if (!in[i].link) { + in[i].link = GPU_uniform(in[i].vec); + } + } + + GPU_link(mat, "texco_norm", GPU_material_builtin(mat, GPU_VIEW_NORMAL), &norm); + GPU_link(mat, "mtex_2d_mapping", in[0].link, &texco); + + float comp = (float) node->custom1; + float discard = (float) node->custom2; + GPU_link(mat, "mtex_parallax", texco, GPU_material_builtin(mat, GPU_VIEW_POSITION), GPU_attribute(CD_TANGENT, ""), norm, texlink, + in[1].link, in[2].link, GPU_uniform(one), GPU_uniform(&discard), GPU_uniform(&comp), &outuv); + + GPU_link(mat, "parallax_uv_attribute", outuv, &out[0].link); + + return true; + } + + return false; +} + +void register_node_type_sh_parallax(void) +{ + static bNodeType ntype; + + sh_node_type_base(&ntype, SH_NODE_PARALLAX, "Parallax", NODE_CLASS_INPUT, 0); + node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING); + node_type_socket_templates(&ntype, sh_node_mapping_in, sh_node_parallax_out); + node_type_label(&ntype, node_parallax_label); + node_type_gpu(&ntype, gpu_shader_parallax); + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/shader/nodes/node_shader_particle_info.c b/source/blender/nodes/shader/nodes/node_shader_particle_info.c index 6dd8fbee3d28..a77066180f28 100644 --- a/source/blender/nodes/shader/nodes/node_shader_particle_info.c +++ b/source/blender/nodes/shader/nodes/node_shader_particle_info.c @@ -53,10 +53,10 @@ static int gpu_shader_particle_info(GPUMaterial *mat, bNode *UNUSED(node), bNode { return GPU_stack_link(mat, "particle_info", in, out, - GPU_builtin(GPU_PARTICLE_SCALAR_PROPS), - GPU_builtin(GPU_PARTICLE_LOCATION), - GPU_builtin(GPU_PARTICLE_VELOCITY), - GPU_builtin(GPU_PARTICLE_ANG_VELOCITY)); + GPU_material_builtin(mat, GPU_PARTICLE_SCALAR_PROPS), + GPU_material_builtin(mat, GPU_PARTICLE_LOCATION), + GPU_material_builtin(mat, GPU_PARTICLE_VELOCITY), + GPU_material_builtin(mat, GPU_PARTICLE_ANG_VELOCITY)); } /* node type definition */ diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c index 78757782203e..4ec6b061d64e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c +++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c @@ -52,9 +52,9 @@ static void node_shader_init_subsurface_scattering(bNodeTree *UNUSED(ntree), bNo static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { if (!in[5].link) - in[5].link = GPU_builtin(GPU_VIEW_NORMAL); + in[5].link = GPU_material_builtin(mat, GPU_VIEW_NORMAL); else - GPU_link(mat, "direction_transform_m4v3", in[5].link, GPU_builtin(GPU_VIEW_MATRIX), &in[5].link); + GPU_link(mat, "direction_transform_m4v3", in[5].link, GPU_material_builtin(mat, GPU_VIEW_MATRIX), &in[5].link); return GPU_stack_link(mat, "node_subsurface_scattering", in, out); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c index f1721fe55679..73b3e6742d0d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c @@ -50,15 +50,15 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat, bNode *UNUSED(node), bNod if (type == GPU_MATERIAL_TYPE_MESH) { return GPU_stack_link(mat, "node_tex_coord", in, out, - GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL), - GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_INVERSE_OBJECT_MATRIX), - GPU_builtin(GPU_CAMERA_TEXCO_FACTORS), orco, mtface); + GPU_material_builtin(mat, GPU_VIEW_POSITION), GPU_material_builtin(mat, GPU_VIEW_NORMAL), + GPU_material_builtin(mat, GPU_INVERSE_VIEW_MATRIX), GPU_material_builtin(mat, GPU_INVERSE_OBJECT_MATRIX), + GPU_material_builtin(mat, GPU_CAMERA_TEXCO_FACTORS), orco, mtface); } else { return GPU_stack_link(mat, "node_tex_coord_background", in, out, - GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL), - GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_INVERSE_OBJECT_MATRIX), - GPU_builtin(GPU_CAMERA_TEXCO_FACTORS), orco, mtface); + GPU_material_builtin(mat, GPU_VIEW_POSITION), GPU_material_builtin(mat, GPU_VIEW_NORMAL), + GPU_material_builtin(mat, GPU_INVERSE_VIEW_MATRIX), GPU_material_builtin(mat, GPU_INVERSE_OBJECT_MATRIX), + GPU_material_builtin(mat, GPU_CAMERA_TEXCO_FACTORS), orco, mtface); } } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c index 9b485a30083e..f38e6202ee06 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c @@ -68,9 +68,9 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, bNode *node, bNodeE GPUMatType type = GPU_Material_get_type(mat); if (type == GPU_MATERIAL_TYPE_MESH) - in[0].link = GPU_builtin(GPU_VIEW_POSITION); + in[0].link = GPU_material_builtin(mat, GPU_VIEW_POSITION); else - GPU_link(mat, "background_transform_to_world", GPU_builtin(GPU_VIEW_POSITION), &in[0].link); + GPU_link(mat, "background_transform_to_world", GPU_material_builtin(mat, GPU_VIEW_POSITION), &in[0].link); } node_shader_gpu_tex_mapping(mat, node, in, out); diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c index ae9124d05881..4a965faea72b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c @@ -78,11 +78,11 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata)); break; case SHD_PROJ_BOX: - GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL), - GPU_builtin(GPU_INVERSE_VIEW_MATRIX), + GPU_link(mat, "direction_transform_m4v3", GPU_material_builtin(mat, GPU_VIEW_NORMAL), + GPU_material_builtin(mat, GPU_INVERSE_VIEW_MATRIX), &norm); GPU_link(mat, "direction_transform_m4v3", norm, - GPU_builtin(GPU_INVERSE_OBJECT_MATRIX), + GPU_material_builtin(mat, GPU_INVERSE_OBJECT_MATRIX), &norm); GPU_link(mat, "node_tex_image_box", in[0].link, norm, diff --git a/source/blender/nodes/shader/nodes/node_shader_texture.c b/source/blender/nodes/shader/nodes/node_shader_texture.c index 737ec7d1c4b1..770e4adf1e77 100644 --- a/source/blender/nodes/shader/nodes/node_shader_texture.c +++ b/source/blender/nodes/shader/nodes/node_shader_texture.c @@ -38,6 +38,7 @@ /* **************** TEXTURE ******************** */ static bNodeSocketTemplate sh_node_texture_in[] = { { SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, /* no limit */ + { SOCK_FLOAT, 1, "Lod Bias", 0.0f, 0.0f, 0.0f, 0.0f, -99.0f, 99.0f, PROP_NONE, 0 }, { -1, 0, "" } }; static bNodeSocketTemplate sh_node_texture_out[] = { @@ -131,10 +132,13 @@ static int gpu_shader_texture(GPUMaterial *mat, bNode *node, bNodeExecData *UNUS else { /* TEX_ENVMAP */ if (!in[0].link) in[0].link = GPU_uniform(in[0].vec); + if (!in[1].link) { + in[1].link = GPU_uniform(&in[1].vec[0]); + } if (!GPU_material_use_world_space_shading(mat)) - GPU_link(mat, "direction_transform_m4v3", in[0].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &in[0].link); + GPU_link(mat, "direction_transform_m4v3", in[0].link, GPU_material_builtin(mat, GPU_INVERSE_VIEW_MATRIX), &in[0].link); GPU_link(mat, "mtex_cube_map_refl_from_refldir", - GPU_cube_map(tex->ima, &tex->iuser, false), in[0].link, &out[0].link, &out[1].link); + GPU_cube_map(tex->ima, &tex->iuser, false), in[0].link, in[1].link, &out[0].link, &out[1].link); GPU_link(mat, "color_to_normal", out[1].link, &out[2].link); } diff --git a/source/blender/nodes/shader/nodes/node_shader_time.c b/source/blender/nodes/shader/nodes/node_shader_time.c new file mode 100644 index 000000000000..94544a651b9c --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_time.c @@ -0,0 +1,54 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/nodes/shader/nodes/node_shader_time.c + * \ingroup shdnodes + */ + + +#include "node_shader_util.h" + +/* **************** OBJECT INFO ******************** */ +static bNodeSocketTemplate sh_node_time_out[] = { + { SOCK_FLOAT, 1, N_("Time"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE}, + { -1, 0, "" } +}; + +static int gpu_shader_time(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) +{ + GPUNodeLink *time = GPU_material_builtin(mat, GPU_TIME); + + return GPU_stack_link(mat, "set_value", in, out, time); +} + +void register_node_type_sh_time(void) +{ + static bNodeType ntype; + + sh_node_type_base(&ntype, SH_NODE_TIME, "Time", NODE_CLASS_INPUT, 0); + node_type_compatibility(&ntype, NODE_OLD_SHADING | NODE_NEW_SHADING); + node_type_socket_templates(&ntype, NULL, sh_node_time_out); + node_type_storage(&ntype, "", NULL, NULL); + node_type_gpu(&ntype, gpu_shader_time); + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/shader/nodes/node_shader_vectMath.c b/source/blender/nodes/shader/nodes/node_shader_vectMath.c index 02cff52e1a03..d1ba1cc43ede 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vectMath.c +++ b/source/blender/nodes/shader/nodes/node_shader_vectMath.c @@ -96,6 +96,27 @@ static void node_shader_exec_vect_math(void *UNUSED(data), int UNUSED(thread), b out[1]->vec[0] = normalize_v3(out[0]->vec); } + else if (node->custom1 == 6) { /* Reflect */ + float dotNI = 2.0f * dot_v3v3(vec1, vec2); + float v[3] = { 0.0f, 0.0f, 0.0f }; + mul_v3_v3fl(v, vec2, dotNI); + + float fv[3] = { 0.0f, 0.0f, 0.0f }; + sub_v3_v3v3(fv, vec1, v); + + out[0]->vec[0] = fv[0]; + out[0]->vec[1] = fv[1]; + out[0]->vec[2] = fv[2]; + + out[1]->vec[0] = normalize_v3(out[0]->vec); + } + else if (node->custom1 == 7) { /* Multiply */ + out[0]->vec[0] = vec1[0] * vec2[0]; + out[0]->vec[1] = vec1[1] * vec2[1]; + out[0]->vec[2] = vec1[2] * vec2[2]; + + out[1]->vec[0] = (fabsf(out[0]->vec[0]) + fabsf(out[0]->vec[1]) + fabsf(out[0]->vec[2])) / 3.0f; + } } @@ -103,7 +124,7 @@ static int gpu_shader_vect_math(GPUMaterial *mat, bNode *node, bNodeExecData *UN { static const char *names[] = {"vec_math_add", "vec_math_sub", "vec_math_average", "vec_math_dot", "vec_math_cross", - "vec_math_normalize"}; + "vec_math_normalize", "vec_math_reflect", "vec_math_mul"}; switch (node->custom1) { case 0: @@ -111,6 +132,8 @@ static int gpu_shader_vect_math(GPUMaterial *mat, bNode *node, bNodeExecData *UN case 2: case 3: case 4: + case 6: + case 7: GPU_stack_link(mat, names[node->custom1], in, out); break; case 5: diff --git a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c b/source/blender/nodes/shader/nodes/node_shader_vectTransform.c index af36e7cea221..291c537b823f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vectTransform.c +++ b/source/blender/nodes/shader/nodes/node_shader_vectTransform.c @@ -116,7 +116,7 @@ static void node_shader_exec_vect_transform(void *data, int UNUSED(thread), bNod } } -static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to) +static GPUNodeLink *get_gpulink_matrix_from_to(GPUMaterial *mat, short from, short to) { switch (from) { case SHD_VECT_TRANSFORM_SPACE_OBJECT: @@ -124,9 +124,9 @@ static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to) case SHD_VECT_TRANSFORM_SPACE_OBJECT: return NULL; case SHD_VECT_TRANSFORM_SPACE_WORLD: - return GPU_builtin(GPU_OBJECT_MATRIX); + return GPU_material_builtin(mat, GPU_OBJECT_MATRIX); case SHD_VECT_TRANSFORM_SPACE_CAMERA: - return GPU_builtin(GPU_LOC_TO_VIEW_MATRIX); + return GPU_material_builtin(mat, GPU_LOC_TO_VIEW_MATRIX); } break; case SHD_VECT_TRANSFORM_SPACE_WORLD: @@ -134,9 +134,9 @@ static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to) case SHD_VECT_TRANSFORM_SPACE_WORLD: return NULL; case SHD_VECT_TRANSFORM_SPACE_CAMERA: - return GPU_builtin(GPU_VIEW_MATRIX); + return GPU_material_builtin(mat, GPU_VIEW_MATRIX); case SHD_VECT_TRANSFORM_SPACE_OBJECT: - return GPU_builtin(GPU_INVERSE_OBJECT_MATRIX); + return GPU_material_builtin(mat, GPU_INVERSE_OBJECT_MATRIX); } break; case SHD_VECT_TRANSFORM_SPACE_CAMERA: @@ -144,9 +144,9 @@ static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to) case SHD_VECT_TRANSFORM_SPACE_CAMERA: return NULL; case SHD_VECT_TRANSFORM_SPACE_WORLD: - return GPU_builtin(GPU_INVERSE_VIEW_MATRIX); + return GPU_material_builtin(mat, GPU_INVERSE_VIEW_MATRIX); case SHD_VECT_TRANSFORM_SPACE_OBJECT: - return GPU_builtin(GPU_INVERSE_LOC_TO_VIEW_MATRIX); + return GPU_material_builtin(mat, GPU_INVERSE_LOC_TO_VIEW_MATRIX); } break; } @@ -170,7 +170,7 @@ static int gpu_shader_vect_transform(GPUMaterial *mat, bNode *node, bNodeExecDat else inputlink = GPU_uniform(in[0].vec); - fromto = get_gpulink_matrix_from_to(nodeprop->convert_from, nodeprop->convert_to); + fromto = get_gpulink_matrix_from_to(mat, nodeprop->convert_from, nodeprop->convert_to); func_name = (nodeprop->type == SHD_VECT_TRANSFORM_TYPE_POINT) ? ptransform : vtransform; if (fromto) { diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.c b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.c index 073bc3110f6f..7401776c253d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.c +++ b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.c @@ -54,12 +54,12 @@ static int gpu_shader_vector_displacement(GPUMaterial *mat, bNode *node, bNodeEx in, out, GPU_attribute(CD_TANGENT, ""), - GPU_builtin(GPU_VIEW_NORMAL), - GPU_builtin(GPU_OBJECT_MATRIX), - GPU_builtin(GPU_VIEW_MATRIX)); + GPU_material_builtin(mat, GPU_VIEW_NORMAL), + GPU_material_builtin(mat, GPU_OBJECT_MATRIX), + GPU_material_builtin(mat, GPU_VIEW_MATRIX)); } else if (node->custom1 == SHD_SPACE_OBJECT) { - return GPU_stack_link(mat, "node_vector_displacement_object", in, out, GPU_builtin(GPU_OBJECT_MATRIX)); + return GPU_stack_link(mat, "node_vector_displacement_object", in, out, GPU_material_builtin(mat, GPU_OBJECT_MATRIX)); } else { return GPU_stack_link(mat, "node_vector_displacement_world", in, out); diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c index 7b9292827b04..4f7a867184ad 100644 --- a/source/blender/python/generic/bgl.c +++ b/source/blender/python/generic/bgl.c @@ -925,9 +925,8 @@ static int Buffer_ass_slice(Buffer *self, int begin, int end, PyObject *seq) /* re-use count var */ if ((count = PySequence_Size(seq)) != (end - begin)) { - PyErr_Format(PyExc_TypeError, - "buffer[:] = value, size mismatch in assignment. " - "Expected: %d (given: %d)", count, end - begin); + PyErr_Format(PyExc_ValueError, + "Mismatch in assignment. bgl.Buffer dimension: %d and template size: %d", end - begin, count); return -1; } @@ -1619,6 +1618,21 @@ BGL_Wrap(BindVertexArray, void, (GLuint)) BGL_Wrap(DeleteVertexArrays, void, (GLsizei, GLuintP)) BGL_Wrap(GenVertexArrays, void, (GLsizei, GLuintP)) BGL_Wrap(IsVertexArray, GLboolean, (GLuint)) +BGL_Wrap(BindFramebuffer, void, (GLenum, GLuint)) +BGL_Wrap(DeleteFramebuffers, void, (GLsizei, GLuintP)) +BGL_Wrap(GenFramebuffers, void, (GLsizei, GLuintP)) +BGL_Wrap(IsFramebuffer, GLboolean, (GLuint)) +BGL_Wrap(CheckFramebufferStatus, GLenum, (GLenum)) +BGL_Wrap(FramebufferRenderbuffer, void, (GLenum, GLenum, GLenum, GLuint)) +BGL_Wrap(FramebufferTexture1D, void, (GLenum, GLenum, GLenum, GLuint, GLint)) +BGL_Wrap(FramebufferTexture2D, void, (GLenum, GLenum, GLenum, GLuint, GLint)) +BGL_Wrap(FramebufferTexture3D, void, (GLenum, GLenum, GLenum, GLuint, GLint, GLint)) +BGL_Wrap(BindRenderbuffer, void, (GLenum, GLuint)) +BGL_Wrap(DeleteRenderbuffers, void, (GLsizei, GLuintP)) +BGL_Wrap(GenRenderbuffers, void, (GLsizei, GLuintP)) +BGL_Wrap(IsRenderbuffer, GLboolean, (GLuint)) +BGL_Wrap(RenderbufferStorage, void, (GLenum, GLenum, GLsizei, GLsizei)) + /* GL_VERSION_3_1 */ @@ -2332,6 +2346,20 @@ PyObject *BPyInit_bgl(void) PY_MOD_ADD_METHOD(DeleteVertexArrays); PY_MOD_ADD_METHOD(GenVertexArrays); PY_MOD_ADD_METHOD(IsVertexArray); + PY_MOD_ADD_METHOD(BindFramebuffer); + PY_MOD_ADD_METHOD(DeleteFramebuffers); + PY_MOD_ADD_METHOD(GenFramebuffers); + PY_MOD_ADD_METHOD(IsFramebuffer); + PY_MOD_ADD_METHOD(CheckFramebufferStatus); + PY_MOD_ADD_METHOD(FramebufferRenderbuffer); + PY_MOD_ADD_METHOD(FramebufferTexture1D); + PY_MOD_ADD_METHOD(FramebufferTexture2D); + PY_MOD_ADD_METHOD(FramebufferTexture3D); + PY_MOD_ADD_METHOD(BindRenderbuffer); + PY_MOD_ADD_METHOD(DeleteRenderbuffers); + PY_MOD_ADD_METHOD(GenRenderbuffers); + PY_MOD_ADD_METHOD(IsRenderbuffer); + PY_MOD_ADD_METHOD(RenderbufferStorage); } diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 82f710e4acfc..d1d91f577a96 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -373,4 +373,10 @@ void BPy_init_modules(void) /* add our own modules dir, this is a python package */ bpy_package_py = bpy_import_test("bpy"); + bpy_sys_module_backup = PyDict_Copy(PyImport_GetModuleDict()); +} + +void BPy_end_modules(void) +{ + Py_DECREF(bpy_sys_module_backup); } diff --git a/source/blender/python/intern/bpy.h b/source/blender/python/intern/bpy.h index b647d0d450cd..3906030ec2cd 100644 --- a/source/blender/python/intern/bpy.h +++ b/source/blender/python/intern/bpy.h @@ -27,7 +27,9 @@ #define __BPY_H__ void BPy_init_modules(void); +void BPy_end_modules(void); extern PyObject *bpy_package_py; +PyObject *bpy_sys_module_backup; /* bpy_interface_atexit.c */ void BPY_atexit_register(void); diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c index 66c64b580f3e..23980fa679b3 100644 --- a/source/blender/python/intern/bpy_app.c +++ b/source/blender/python/intern/bpy_app.c @@ -86,6 +86,8 @@ static PyStructSequence_Field app_info_fields[] = { {(char *)"version", (char *)"The Blender version as a tuple of 3 numbers. eg. (2, 50, 11)"}, {(char *)"version_string", (char *)"The Blender version formatted as a string"}, {(char *)"version_char", (char *)"The Blender version character (for minor releases)"}, + {(char *)"upbge_version", (char *)"The UPBGE version as a tuple of 3 numbers. eg. (0, 2, 4)"}, + {(char *)"upbge_version_string", (char *)"The UPBGE version formatted as a string"}, {(char *)"version_cycle", (char *)"The release status of this build alpha/beta/rc/release"}, {(char *)"binary_path", (char *)"The location of blenders executable, useful for utilities that spawn new instances"}, {(char *)"background", (char *)"Boolean, True when blender is running without a user interface (started with -b)"}, @@ -162,6 +164,11 @@ static PyObject *make_app_info(void) BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION)); SetStrItem(STRINGIFY(BLENDER_VERSION_CHAR)); + + SetObjItem(PyC_Tuple_Pack_I32(UPBGE_VERSION / 100, UPBGE_VERSION % 100, UPBGE_SUBVERSION)); + SetObjItem(PyUnicode_FromFormat("%d.%d (sub %d)", + UPBGE_VERSION / 100, UPBGE_VERSION % 100, UPBGE_SUBVERSION)); + SetStrItem(STRINGIFY(BLENDER_VERSION_CYCLE)); SetStrItem(BKE_appdir_program_path()); SetObjItem(PyBool_FromLong(G.background)); diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 9b685d5ba6e6..3403fef9752f 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -360,6 +360,9 @@ void BPY_python_end(void) /* bpy.app modules that need cleanup */ BPY_app_translations_end(); + /* Release copy of clear sys modules dictionary */ + BPy_end_modules(); + #ifndef WITH_PYTHON_MODULE BPY_atexit_unregister(); /* without this we get recursive calls to WM_exit */ diff --git a/source/blender/python/intern/gpu.c b/source/blender/python/intern/gpu.c index 7cf669e875b7..d99dd6c2ea9f 100644 --- a/source/blender/python/intern/gpu.c +++ b/source/blender/python/intern/gpu.c @@ -108,12 +108,12 @@ static PyObject *PyInit_gpu(void) PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNPERSMAT); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNENERGY); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNCOL); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DYNSPOTSCALE); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_ATT1); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_ATT2); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_DISTANCE); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTSIZE); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTBLEND); - PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_LAMP_SPOTSCALE); /* GPU_DYNAMIC_GROUP_SAMPLER */ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DBUFFER); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_SAMPLER_2DIMAGE); @@ -129,6 +129,7 @@ static PyObject *PyInit_gpu(void) PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_HORIZON_COLOR); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_AMBIENT_COLOR); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_ZENITH_COLOR); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_ENVLIGHT_ENERGY); /* GPU_DYNAMIC_GROUP_MAT */ PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_DIFFRGB); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_REF); @@ -139,6 +140,24 @@ static PyObject *PyInit_gpu(void) PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_AMB); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_ALPHA); PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_MIR); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_MAT_SPECTRA); + /* GPU_DYNAMIC_GROUP_TEX */ + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_TEX_COLINTENS); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_TEX_COLFAC); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_TEX_ALPHA); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_TEX_SPECINTENS); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_TEX_SPECFAC); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_TEX_HARDNESS); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_TEX_EMIT); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_TEX_MIRROR); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_TEX_NORMAL); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_TEX_PARALLAXBUMP); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_TEX_PARALLAXSTEP); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_TEX_IOR); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_TEX_REFRRATIO); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_TEX_UVOFFSET); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_TEX_UVSIZE); + PY_MODULE_ADD_CONSTANT(m, GPU_DYNAMIC_TEX_UVROTATION); /* -------------------------------------------------------------------- */ diff --git a/source/blender/python/intern/gpu_offscreen.c b/source/blender/python/intern/gpu_offscreen.c index 3b9b3c70ead5..c7c106757b15 100644 --- a/source/blender/python/intern/gpu_offscreen.c +++ b/source/blender/python/intern/gpu_offscreen.c @@ -352,7 +352,7 @@ static PyObject *pygpu_offscreen_new(PyObject *UNUSED(self), PyObject *args, PyO return NULL; } - ofs = GPU_offscreen_create(width, height, samples, err_out); + ofs = GPU_offscreen_create(width, height, samples, GPU_HDR_NONE, GPU_OFFSCREEN_DEPTH_COMPARE, err_out); if (ofs == NULL) { PyErr_Format(PyExc_RuntimeError, diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c index 0c365ad192c5..ec2ccd31d0f6 100644 --- a/source/blender/python/mathutils/mathutils.c +++ b/source/blender/python/mathutils/mathutils.c @@ -422,7 +422,7 @@ PyObject *mathutils_dynstr_to_py(struct DynStr *ds) /* Mathutils Callbacks */ /* for mathutils internal use only, eventually should re-alloc but to start with we only have a few users */ -#define MATHUTILS_TOT_CB 17 +#define MATHUTILS_TOT_CB 19 static Mathutils_Callback *mathutils_callbacks[MATHUTILS_TOT_CB] = {NULL}; unsigned char Mathutils_RegisterCallback(Mathutils_Callback *cb) @@ -435,7 +435,7 @@ unsigned char Mathutils_RegisterCallback(Mathutils_Callback *cb) return i; } - BLI_assert(i + 1 < MATHUTILS_TOT_CB); + BLI_assert(i < MATHUTILS_TOT_CB); mathutils_callbacks[i] = cb; return i; diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c b/source/blender/python/mathutils/mathutils_bvhtree.c index c044cc549653..eab04c58d3dd 100644 --- a/source/blender/python/mathutils/mathutils_bvhtree.c +++ b/source/blender/python/mathutils/mathutils_bvhtree.c @@ -117,7 +117,7 @@ typedef struct { /** \name Utility helper functions * \{ */ -static PyObject *bvhtree_CreatePyObject( +PyObject *bvhtree_CreatePyObject( BVHTree *tree, float epsilon, float (*coords)[3], unsigned int coords_len, diff --git a/source/blender/python/mathutils/mathutils_bvhtree.h b/source/blender/python/mathutils/mathutils_bvhtree.h index 445a393b93ed..6378500445a7 100644 --- a/source/blender/python/mathutils/mathutils_bvhtree.h +++ b/source/blender/python/mathutils/mathutils_bvhtree.h @@ -26,6 +26,8 @@ #ifndef __MATHUTILS_BVHTREE_H__ #define __MATHUTILS_BVHTREE_H__ +typedef struct BVHTree BVHTree; + PyMODINIT_FUNC PyInit_mathutils_bvhtree(void); extern PyTypeObject PyBVHTree_Type; @@ -33,4 +35,13 @@ extern PyTypeObject PyBVHTree_Type; #define PyBVHTree_Check(v) PyObject_TypeCheck((v), &PyBVHTree_Type) #define PyBVHTree_CheckExact(v) (Py_TYPE(v) == &PyBVHTree_Type) +PyObject *bvhtree_CreatePyObject( + BVHTree *tree, float epsilon, + + float (*coords)[3], unsigned int coords_len, + unsigned int (*tris)[3], unsigned int tris_len, + + /* optional arrays */ + int *orig_index, float (*orig_normal)[3]); + #endif /* __MATHUTILS_BVHTREE_H__ */ diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 64e6aa54a9e9..a07d7bf6da37 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -576,6 +576,7 @@ typedef struct LampRen { short falloff_type; float ld1, ld2; float coeff_const, coeff_lin, coeff_quad; + float radius, cutoff; struct CurveMapping *curfalloff; /* copied from Lamp, to decouple more rendering stuff */ diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 15432af4915f..316fb63af1c8 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -3823,6 +3823,8 @@ static GroupObject *add_render_lamp(Render *re, Object *ob) lar->coeff_lin= la->coeff_lin; lar->coeff_quad= la->coeff_quad; lar->curfalloff = curvemapping_copy(la->curfalloff); + lar->radius = la->radius; + lar->cutoff = la->cutoff; if (lar->curfalloff) { /* so threads don't conflict on init */ diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index 3520a3120120..61a97b57cc6d 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -76,7 +76,7 @@ static RenderEngineType internal_render_type = { static RenderEngineType internal_game_type = { NULL, NULL, - "BLENDER_GAME", N_("Blender Game"), RE_INTERNAL | RE_GAME, + "BLENDER_GAME", N_("UPBGE"), RE_INTERNAL | RE_GAME, NULL, NULL, NULL, NULL, NULL, NULL, NULL, {NULL, NULL, NULL} }; diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c index b9c703a05280..7d96cc664294 100644 --- a/source/blender/render/intern/source/shadeoutput.c +++ b/source/blender/render/intern/source/shadeoutput.c @@ -1234,6 +1234,21 @@ float lamp_get_visibility(LampRen *lar, const float co[3], float lv[3], float *d /* curvemapping_initialize is called from #add_render_lamp */ visifac = curvemapping_evaluateF(lar->curfalloff, 0, dist[0]/lar->dist); break; + case LA_FALLOFF_INVSQUARE_CUTOFF: + { + float d = lar->dist - lar->radius; + if (d <= 0.0f) { + visifac = 1.0f; + } + else { + float denom = d / lar->radius + 1.0f; + float att = 1.0f / (denom * denom); + att = (att - lar->cutoff) / (1.0f - lar->cutoff); + att = max_ff(att, 0.0f); + visifac = att; + } + } + break; } if (lar->mode & LA_SPHERE) { diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index 810cceb5fc37..42863bceccf1 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -38,7 +38,7 @@ set(INC ../makesrna ../nodes ../render/extern/include - ../../gameengine/BlenderRoutines + ../../gameengine/Launcher ../../../intern/clog ../../../intern/ghost ../../../intern/guardedalloc diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 477699fccaaa..08da03408cc4 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -324,6 +324,11 @@ static void wm_init_userdef(Main *bmain, const bool read_userdef_from_memory) /* versioning is here */ UI_init_userdef(bmain); + /* avoid re-saving for every small change to our prefs, allow overrides */ + if (read_userdef_from_memory) { + BLO_update_defaults_userpref_blend(); + } + MEM_CacheLimiter_set_maximum(((size_t)U.memcachelimit) * 1024 * 1024); BKE_sound_init(bmain); @@ -336,11 +341,6 @@ static void wm_init_userdef(Main *bmain, const bool read_userdef_from_memory) SET_FLAG_FROM_TEST(G.f, (U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0, G_SCRIPT_AUTOEXEC); } - /* avoid re-saving for every small change to our prefs, allow overrides */ - if (read_userdef_from_memory) { - BLO_update_defaults_userpref_blend(); - } - /* update tempdir from user preferences */ BKE_tempdir_init(U.tempdir); } diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 185cf3fad4fc..185f7a81ac42 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -87,7 +87,7 @@ #endif #ifdef WITH_GAMEENGINE -# include "BL_System.h" +# include "LA_SystemCommandLine.h" #endif #include "GHOST_Path-api.h" #include "GHOST_C-api.h" diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 1b73f40bb8db..b9f117738a56 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1513,7 +1513,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar BLENDER_VERSION / 100, BLENDER_VERSION % 100); } else { - BLI_snprintf(url, sizeof(url), "https://docs.blender.org/api/master"); + BLI_snprintf(url, sizeof(url), "https://pythonapi.upbge.org/"); } uiItemStringO(col, IFACE_("Python API Reference"), ICON_URL, "WM_OT_url_open", "url", url); uiItemL(col, "", ICON_NONE); diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 97df94af38d5..4e381bdadbcf 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -500,13 +500,13 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win) /* this is set to 1 if you don't have startup.blend open */ if (G.save_over && BKE_main_blendfile_path_from_global()[0]) { char str[sizeof(((Main *)NULL)->name) + 24]; - BLI_snprintf(str, sizeof(str), "Blender%s [%s%s]", wm->file_saved ? "" : "*", + BLI_snprintf(str, sizeof(str), "UPBGE%s [%s%s]", wm->file_saved ? "" : "*", BKE_main_blendfile_path_from_global(), G_MAIN->recovered ? " (Recovered)" : ""); GHOST_SetTitle(win->ghostwin, str); } else - GHOST_SetTitle(win->ghostwin, "Blender"); + GHOST_SetTitle(win->ghostwin, "UPBGE"); /* Informs GHOST of unsaved changes, to set window modified visual indicator (MAC OS X) * and to give hint of unsaved changes for a user warning mechanism @@ -1532,6 +1532,13 @@ void wm_window_testbreak(void) } } +void wm_window_set_order(wmWindow *win, int order) +{ + if (win->ghostwin) { + GHOST_SetWindowOrder(win->ghostwin, (order == 0) ? GHOST_kWindowOrderBottom : GHOST_kWindowOrderTop); + } +} + /* **************** init ********************** */ void wm_ghost_init(bContext *C) diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h index 5fccbd74250c..44e415e88327 100644 --- a/source/blender/windowmanager/wm_window.h +++ b/source/blender/windowmanager/wm_window.h @@ -69,6 +69,8 @@ void wm_cursor_position_to_ghost (wmWindow *win, int *x, int *y); void wm_window_testbreak (void); +void wm_window_set_order(wmWindow *win, int order); + #ifdef WITH_INPUT_IME void wm_window_IME_begin (wmWindow *win, int x, int y, int w, int h, bool complete); void wm_window_IME_end (wmWindow *win); diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt index dbfd1d9d5200..73f3cfa6fe1e 100644 --- a/source/blenderplayer/CMakeLists.txt +++ b/source/blenderplayer/CMakeLists.txt @@ -82,8 +82,7 @@ add_dependencies(blenderplayer makesdna) get_property(BLENDER_LINK_LIBS GLOBAL PROPERTY BLENDER_LINK_LIBS) list(APPEND BLENDER_LINK_LIBS - ge_player_common - ge_player_ghost + ge_player blenkernel_blc ) @@ -94,73 +93,92 @@ endif() # if(UNIX) # Sort libraries set(BLENDER_SORTED_LIBS - ge_player_ghost - ge_player_common - bf_intern_string - bf_intern_ghost + ge_player + ge_launcher + ge_player + ge_logic_ketsji + ge_converter + ge_logic_ketsji + ge_phys_bullet + ge_phys_dummy + ge_logic + ge_device + ge_rasterizer + ge_oglrasterizer + ge_logic_expressions + ge_common + ge_scenegraph + ge_logic_network + ge_videotex + + bf_editor_datafiles + bf_rna + bf_blenloader + bf_modifiers bf_blenkernel + bf_physics bf_depsgraph bf_physics bf_intern_rigidbody bf_blenloader ge_blen_routines bf_editor_datafiles - ge_converter - ge_logic_ketsji - ge_phys_bullet + ge_converter + ge_logic_ketsji + ge_phys_bullet ge_phys_dummy - ge_logic - ge_rasterizer - ge_oglrasterizer - ge_logic_expressions + ge_logic + ge_rasterizer + ge_oglrasterizer + ge_logic_expressions ge_scenegraph bf_ikplugin bf_intern_itasc bf_intern_iksolver bf_intern_smoke bf_modifiers - bf_intern_moto bf_nodes bf_gpu bf_imbuf bf_avi - ge_logic_network - ge_logic_ngnetwork - ge_logic_loopbacknetwork - extern_bullet - bf_intern_guardedalloc - bf_intern_memutil bf_python_ext bf_python_mathutils bf_python_bmesh - bf_intern_utfconv bf_imbuf_cineon bf_imbuf_openexr bf_imbuf_openimageio - extern_openjpeg bf_imbuf_dds bf_dna - ge_videotex bf_blenfont bf_blentranslation - bf_intern_audaspace - blenkernel_blc bf_bmesh bf_blenlib + blenkernel_blc + + bf_intern_string + bf_intern_ghost + bf_intern_rigidbody + bf_intern_itasc + bf_intern_iksolver + bf_intern_smoke + bf_intern_guardedalloc + bf_intern_memutil bf_intern_utfconv - extern_binreloc - extern_minilzo - bf_intern_ghost # duplicate for linking - bf_blenkernel # duplicate for linking bf_intern_mikktspace - extern_recastnavigation bf_intern_opencolorio bf_intern_glew_mx bf_intern_eigen + bf_intern_libmv + bf_intern_audaspace + + extern_bullet + extern_openjpeg + extern_binreloc + extern_minilzo + extern_recastnavigation extern_rangetree extern_wcwidth - bf_intern_libmv extern_sdlew ) @@ -204,6 +222,10 @@ endif() list(APPEND BLENDER_SORTED_LIBS bf_intern_decklink) endif() + if(WITH_GAMEENGINE_BPPLAYER) + list(APPEND BLENDER_SORTED_LIBS bf_intern_spindle) + endif() + if(WIN32) list(APPEND BLENDER_SORTED_LIBS bf_intern_gpudirect) endif() diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 9f34729cd2f2..eb8bbabffc01 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -622,7 +622,7 @@ void uiTemplateRunningJobs(struct uiLayout *layout, struct bContext *C) RET_NONE void uiTemplateOperatorSearch(struct uiLayout *layout) RET_NONE void uiTemplateHeader3D(struct uiLayout *layout, struct bContext *C) RET_NONE void uiTemplateEditModeSelection(struct uiLayout *layout, struct bContext *C) RET_NONE -void uiTemplateImage(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *userptr, bool compact, bool multiview) RET_NONE +void uiTemplateImage(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *userptr, bool compact, bool multiview, bool cubemap, bool color_space) RET_NONE void uiTemplateColorPicker(uiLayout *layout, struct PointerRNA *ptr, const char *propname, bool value_slider, bool lock, bool lock_luminosity, bool cubic) RET_NONE void uiTemplateHistogram(uiLayout *layout, struct PointerRNA *ptr, const char *propname) RET_NONE void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C) RET_NONE diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index e6772a003f5b..c2008668cafe 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -77,7 +77,7 @@ if(WITH_HEADLESS) endif() if(WITH_GAMEENGINE) - blender_include_dirs(../gameengine/BlenderRoutines) + blender_include_dirs(../gameengine/Launcher) add_definitions(-DWITH_GAMEENGINE) endif() @@ -311,7 +311,7 @@ if(UNIX AND NOT APPLE) if(WITH_INSTALL_PORTABLE) set(TARGETDIR_VER ${BLENDER_VERSION}) else() - set(TARGETDIR_VER share/blender/${BLENDER_VERSION}) + set(TARGETDIR_VER share/upbge/${BLENDER_VERSION}) endif() endif() @@ -428,6 +428,14 @@ if(WITH_OPENCOLORIO) ) endif() +# game controller data base +if(WITH_GAMEENGINE AND WITH_SDL) + install( + DIRECTORY ${CMAKE_SOURCE_DIR}/release/datafiles/gamecontroller + DESTINATION ${TARGETDIR_VER}/datafiles + ) +endif() + # helpful tip when using make if("${CMAKE_GENERATOR}" MATCHES ".*Makefiles.*") # message after building. diff --git a/source/creator/creator.c b/source/creator/creator.c index 33da54faaeb1..c96abc63eb75 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -87,7 +87,7 @@ /* for passing information between creator and gameengine */ #ifdef WITH_GAMEENGINE -# include "BL_System.h" +# include "LA_SystemCommandLine.h" #else /* dummy */ # define SYS_SystemHandle int #endif diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index 7ad44916047c..dec1df2a9cbe 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -85,7 +85,7 @@ /* for passing information between creator and gameengine */ #ifdef WITH_GAMEENGINE -# include "BL_System.h" +# include "LA_SystemCommandLine.h" #else /* dummy */ # define SYS_SystemHandle int #endif diff --git a/source/creator/creator_signals.c b/source/creator/creator_signals.c index cd1188f5750c..17728ee02d5e 100644 --- a/source/creator/creator_signals.c +++ b/source/creator/creator_signals.c @@ -67,7 +67,7 @@ /* for passing information between creator and gameengine */ #ifdef WITH_GAMEENGINE -# include "BL_System.h" +# include "LA_SystemCommandLine.h" #else /* dummy */ # define SYS_SystemHandle int #endif diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp index 22616458b54f..cb73afd1e9fc 100644 --- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp +++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp @@ -30,90 +30,48 @@ * \ingroup blroutines */ - -#include -#include -#include - #ifdef _MSC_VER - /* don't show stl-warnings */ +/* don't show stl-warnings */ # pragma warning (disable:4786) #endif -#include "GPU_glew.h" +#include "KX_PythonInit.h" +#include "KX_Globals.h" -#include "KX_BlenderCanvas.h" -#include "KX_BlenderKeyboardDevice.h" -#include "KX_BlenderMouseDevice.h" -#include "KX_BlenderSystem.h" -#include "BL_Material.h" +#include "GHOST_ISystem.h" -#include "KX_KetsjiEngine.h" -#include "KX_BlenderSceneConverter.h" -#include "KX_PythonInit.h" -#include "KX_PyConstraintBinding.h" -#include "KX_PythonMain.h" +#include "LA_BlenderLauncher.h" -#include "RAS_OpenGLRasterizer.h" -#include "RAS_ListRasterizer.h" +#include "CM_Message.h" -#include "NG_LoopBackNetworkDeviceInterface.h" +extern "C" { +# include "DNA_scene_types.h" -#include "BL_System.h" +# include "BKE_global.h" +# include "BKE_report.h" +# include "BKE_main.h" +# include "BKE_context.h" +# include "BKE_sound.h" -#include "GPU_extensions.h" -#include "EXP_Value.h" +# include "BLI_blenlib.h" +# include "BLO_readfile.h" +# include "WM_api.h" +# include "wm_cursors.h" -extern "C" { - #include "DNA_object_types.h" - #include "DNA_view3d_types.h" - #include "DNA_screen_types.h" - #include "DNA_userdef_types.h" - #include "DNA_scene_types.h" - #include "DNA_windowmanager_types.h" - - #include "BKE_global.h" - #include "BKE_report.h" - #include "BKE_ipo.h" - #include "BKE_main.h" - #include "BKE_context.h" - #include "BKE_sound.h" - - /* avoid c++ conflict with 'new' */ - #define new _new - #include "BKE_screen.h" - #undef new - - #include "MEM_guardedalloc.h" - - #include "BLI_blenlib.h" - #include "BLO_readfile.h" - - #include "../../blender/windowmanager/WM_types.h" - #include "../../blender/windowmanager/wm_window.h" - -/* avoid more includes (not used by BGE) */ -typedef void * wmUIHandlerFunc; -typedef void * wmUIHandlerRemoveFunc; - - #include "../../blender/windowmanager/wm_event_system.h" +void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *cam_frame, int always_use_expand_framing); } -#ifdef WITH_AUDASPACE -# include AUD_DEVICE_H -#endif - static BlendFileData *load_game_data(const char *filename) { ReportList reports; BlendFileData *bfd; BKE_reports_init(&reports, RPT_STORE); - bfd= BLO_read_from_file(filename, &reports, BLO_READ_SKIP_USERDEF); + bfd = BLO_read_from_file(filename, &reports, BLO_READ_SKIP_USERDEF); if (!bfd) { - printf("Loading %s failed: ", filename); + CM_Error("loading " << filename << " failed: "); BKE_reports_print(&reports, RPT_ERROR); } @@ -122,273 +80,54 @@ static BlendFileData *load_game_data(const char *filename) return bfd; } -static int BL_KetsjiNextFrame(KX_KetsjiEngine *ketsjiengine, bContext *C, wmWindow *win, Scene *scene, ARegion *ar, - KX_BlenderKeyboardDevice* keyboarddevice, KX_BlenderMouseDevice* mousedevice, int draw_letterbox) -{ - int exitrequested; - - // first check if we want to exit - exitrequested = ketsjiengine->GetExitCode(); - - // kick the engine - bool render = ketsjiengine->NextFrame(); - - if (render) { - if (draw_letterbox) { - // Clear screen to border color - // We do this here since we set the canvas to be within the frames. This means the engine - // itself is unaware of the extra space, so we clear the whole region for it. - glClearColor(scene->gm.framing.col[0], scene->gm.framing.col[1], scene->gm.framing.col[2], 1.0f); - glViewport(ar->winrct.xmin, ar->winrct.ymin, - BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct)); - glClear(GL_COLOR_BUFFER_BIT); - } - - // render the frame - ketsjiengine->Render(); - } - - wm_window_process_events_nosleep(); - - // test for the ESC key - //XXX while (qtest()) - while (wmEvent *event= (wmEvent *)win->queue.first) { - short val = 0; - //unsigned short event = 0; //XXX extern_qread(&val); - unsigned int unicode = event->utf8_buf[0] ? BLI_str_utf8_as_unicode(event->utf8_buf) : event->ascii; - - if (keyboarddevice->ConvertBlenderEvent(event->type, event->val, unicode)) - exitrequested = KX_EXIT_REQUEST_BLENDER_ESC; - - /* Coordinate conversion... where - * should this really be? - */ - if (event->type == MOUSEMOVE) { - /* Note, not nice! XXX 2.5 event hack */ - val = event->x - ar->winrct.xmin; - mousedevice->ConvertBlenderEvent(MOUSEX, val, 0); - - val = ar->winy - (event->y - ar->winrct.ymin) - 1; - mousedevice->ConvertBlenderEvent(MOUSEY, val, 0); - } - else { - mousedevice->ConvertBlenderEvent(event->type, event->val, 0); - } - - BLI_remlink(&win->queue, event); - wm_event_free(event); - } - - if (win != CTX_wm_window(C)) { - exitrequested= KX_EXIT_REQUEST_OUTSIDE; /* window closed while bge runs */ - } - return exitrequested; -} - - -#ifdef WITH_PYTHON -static struct BL_KetsjiNextFrameState { - class KX_KetsjiEngine* ketsjiengine; - struct bContext *C; - struct wmWindow* win; - struct Scene* scene; - struct ARegion *ar; - KX_BlenderKeyboardDevice* keyboarddevice; - KX_BlenderMouseDevice* mousedevice; - int draw_letterbox; -} ketsjinextframestate; - -static int BL_KetsjiPyNextFrame(void *state0) -{ - BL_KetsjiNextFrameState *state = (BL_KetsjiNextFrameState *) state0; - return BL_KetsjiNextFrame( - state->ketsjiengine, - state->C, - state->win, - state->scene, - state->ar, - state->keyboarddevice, - state->mousedevice, - state->draw_letterbox); -} -#endif - extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *cam_frame, int always_use_expand_framing) { /* context values */ - struct wmWindowManager *wm= CTX_wm_manager(C); - struct wmWindow *win= CTX_wm_window(C); - struct Scene *startscene= CTX_data_scene(C); - struct Main* maggie1= CTX_data_main(C); + Scene *startscene = CTX_data_scene(C); + Main *maggie1 = CTX_data_main(C); + KX_ExitInfo exitInfo; + Main *blenderdata = maggie1; - RAS_Rect area_rect; - area_rect.SetLeft(cam_frame->xmin); - area_rect.SetBottom(cam_frame->ymin); - area_rect.SetRight(cam_frame->xmax); - area_rect.SetTop(cam_frame->ymax); + char *startscenename = startscene->id.name + 2; + char pathname[FILE_MAXDIR + FILE_MAXFILE]; + char prevPathName[FILE_MAXDIR + FILE_MAXFILE]; + BlendFileData *bfd = nullptr; - int exitrequested = KX_EXIT_REQUEST_NO_REQUEST; - Main* blenderdata = maggie1; + BLI_strncpy(pathname, blenderdata->name, sizeof(pathname)); + BLI_strncpy(prevPathName, G.main->name, sizeof(prevPathName)); - char* startscenename = startscene->id.name+2; - char pathname[FILE_MAXDIR+FILE_MAXFILE], oldsce[FILE_MAXDIR+FILE_MAXFILE]; - STR_String exitstring = ""; - BlendFileData *bfd= NULL; + KX_SetOrigPath(std::string(blenderdata->name)); - BLI_strncpy(pathname, blenderdata->name, sizeof(pathname)); - BLI_strncpy(oldsce, G.main->name, sizeof(oldsce)); #ifdef WITH_PYTHON - resetGamePythonPath(); // need this so running a second time wont use an old blendfiles path - setGamePythonPath(G.main->name); // Acquire Python's GIL (global interpreter lock) // so we can safely run Python code and API calls PyGILState_STATE gilstate = PyGILState_Ensure(); - PyObject *pyGlobalDict = PyDict_New(); /* python utility storage, spans blend file loading */ -#endif - - // Globals to be carried on over blender files - GlobalSettings gs; - gs.matmode= startscene->gm.matmode; - gs.glslflag= startscene->gm.flag; - - do - { - View3D *v3d= CTX_wm_view3d(C); - RegionView3D *rv3d= CTX_wm_region_view3d(C); - - // get some preferences - SYS_SystemHandle syshandle = SYS_GetSystem(); - bool properties = (SYS_GetCommandLineInt(syshandle, "show_properties", 0) != 0); - bool usefixed = (SYS_GetCommandLineInt(syshandle, "fixedtime", 0) != 0); - bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0); - bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0); - bool animation_record = (SYS_GetCommandLineInt(syshandle, "animation_record", 0) != 0); - bool displaylists = (SYS_GetCommandLineInt(syshandle, "displaylists", 0) != 0) && GPU_display_list_support(); -#ifdef WITH_PYTHON - bool nodepwarnings = (SYS_GetCommandLineInt(syshandle, "ignore_deprecation_warnings", 0) != 0); -#endif - // bool novertexarrays = (SYS_GetCommandLineInt(syshandle, "novertexarrays", 0) != 0); - bool mouse_state = (startscene->gm.flag & GAME_SHOW_MOUSE) != 0; - bool restrictAnimFPS = (startscene->gm.flag & GAME_RESTRICT_ANIM_UPDATES) != 0; - - short drawtype = v3d->drawtype; - - /* we do not support material mode in game engine, force change to texture mode */ - if (drawtype == OB_MATERIAL) drawtype = OB_TEXTURE; - if (animation_record) usefixed= false; /* override since you don't want to run full-speed for sim recording */ - - // create the canvas and rasterizer - RAS_ICanvas* canvas = new KX_BlenderCanvas(wm, win, area_rect, ar); - - // default mouse state set on render panel - if (mouse_state) - canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL); - else - canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE); - - // Setup vsync - int previous_vsync = 0; - canvas->GetSwapInterval(previous_vsync); - if (startscene->gm.vsync == VSYNC_ADAPTIVE) - canvas->SetSwapInterval(-1); - else - canvas->SetSwapInterval((startscene->gm.vsync == VSYNC_ON) ? 1 : 0); - - RAS_IRasterizer* rasterizer = NULL; - RAS_STORAGE_TYPE raster_storage = RAS_AUTO_STORAGE; - - if (startscene->gm.raster_storage == RAS_STORE_VBO) { - raster_storage = RAS_VBO; - } - else if (startscene->gm.raster_storage == RAS_STORE_VA) { - raster_storage = RAS_VA; - } - //Don't use displaylists with VBOs - //If auto starts using VBOs, make sure to check for that here - if (displaylists && raster_storage != RAS_VBO) - rasterizer = new RAS_ListRasterizer(canvas, true, raster_storage); - else - rasterizer = new RAS_OpenGLRasterizer(canvas, raster_storage); - - RAS_IRasterizer::MipmapOption mipmapval = rasterizer->GetMipmapping(); - - - // create the inputdevices - KX_BlenderKeyboardDevice* keyboarddevice = new KX_BlenderKeyboardDevice(); - KX_BlenderMouseDevice* mousedevice = new KX_BlenderMouseDevice(); - - // create a networkdevice - NG_NetworkDeviceInterface* networkdevice = new - NG_LoopBackNetworkDeviceInterface(); - - // - // create a ketsji/blendersystem (only needed for timing and stuff) - KX_BlenderSystem* kxsystem = new KX_BlenderSystem(); - - // create the ketsjiengine - KX_KetsjiEngine* ketsjiengine = new KX_KetsjiEngine(kxsystem); - - // set the devices - ketsjiengine->SetKeyboardDevice(keyboarddevice); - ketsjiengine->SetMouseDevice(mousedevice); - ketsjiengine->SetNetworkDevice(networkdevice); - ketsjiengine->SetCanvas(canvas); - ketsjiengine->SetRasterizer(rasterizer); - ketsjiengine->SetUseFixedTime(usefixed); - ketsjiengine->SetTimingDisplay(frameRate, profile, properties); - ketsjiengine->SetRestrictAnimationFPS(restrictAnimFPS); - ketsjiengine->SetRender(true); - KX_KetsjiEngine::SetExitKey(ConvertKeyCode(startscene->gm.exitkey)); - - //set the global settings (carried over if restart/load new files) - ketsjiengine->SetGlobalSettings(&gs); + PyObject *globalDict = PyDict_New(); -#ifdef WITH_PYTHON - CValue::SetDeprecationWarnings(nodepwarnings); #endif - //lock frame and camera enabled - storing global values - int tmp_lay= startscene->lay; - Object *tmp_camera = startscene->camera; - - if (v3d->scenelock==0) { - startscene->lay= v3d->lay; - startscene->camera= v3d->camera; - } - - // some blender stuff - float camzoom = 1.0f; - int draw_letterbox = 0; - - if (rv3d->persp==RV3D_CAMOB) { - if (startscene->gm.framing.type == SCE_GAMEFRAMING_BARS) { /* Letterbox */ - draw_letterbox = 1; - } - else { - camzoom = 1.0f / BKE_screen_view3d_zoom_to_fac(rv3d->camzoom); + GlobalSettings gs; + gs.glslflag = startscene->gm.flag; + + do { + // if we got an exitcode 3 (KX_ExitInfo::START_OTHER_GAME) load a different file + if (ELEM(exitInfo.m_code, KX_ExitInfo::START_OTHER_GAME, KX_ExitInfo::RESTART_GAME)) { + exitInfo.m_code = KX_ExitInfo::NO_REQUEST; + if (bfd) { + BLO_blendfiledata_free(bfd); } - } - - rasterizer->SetDrawingMode(drawtype); - ketsjiengine->SetCameraZoom(camzoom); - ketsjiengine->SetCameraOverrideZoom(2.0f); - - // if we got an exitcode 3 (KX_EXIT_REQUEST_START_OTHER_GAME) load a different file - if (exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME || exitrequested == KX_EXIT_REQUEST_RESTART_GAME) - { - exitrequested = KX_EXIT_REQUEST_NO_REQUEST; - if (bfd) BLO_blendfiledata_free(bfd); char basedpath[FILE_MAX]; // base the actuator filename with respect // to the original file working directory - if (exitstring != "") - BLI_strncpy(basedpath, exitstring.ReadPtr(), sizeof(basedpath)); + if (!exitInfo.m_fileName.empty()) { + BLI_strncpy(basedpath, exitInfo.m_fileName.c_str(), sizeof(basedpath)); + } // load relative to the last loaded file, this used to be relative // to the first file but that makes no sense, relative paths in @@ -398,8 +137,7 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c bfd = load_game_data(basedpath); // if it wasn't loaded, try it forced relative - if (!bfd) - { + if (!bfd) { // just add "//" in front of it char temppath[FILE_MAX] = "//"; BLI_strncpy(temppath + 2, basedpath, FILE_MAX - 2); @@ -409,275 +147,105 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c } // if we got a loaded blendfile, proceed - if (bfd) - { + if (bfd) { blenderdata = bfd->main; startscenename = bfd->curscene->id.name + 2; if (blenderdata) { - BLI_strncpy(G.main->name, blenderdata->name, sizeof(G.main->name)); BLI_strncpy(pathname, blenderdata->name, sizeof(pathname)); -#ifdef WITH_PYTHON - setGamePythonPath(G.main->name); -#endif + // Change G.main path to ensure loading of data using relative paths. + BLI_strncpy(G.main->name, pathname, sizeof(G.main->name)); } } // else forget it, we can't find it - else - { - exitrequested = KX_EXIT_REQUEST_QUIT_GAME; + else { + exitInfo.m_code = KX_ExitInfo::QUIT_GAME; } } - Scene *scene= bfd ? bfd->curscene : (Scene *)BLI_findstring(&blenderdata->scene, startscenename, offsetof(ID, name) + 2); - - if (scene) - { - int startFrame = scene->r.cfra; - ketsjiengine->SetAnimRecordMode(animation_record, startFrame); + Scene *scene = bfd ? bfd->curscene : (Scene *)BLI_findstring(&blenderdata->scene, startscenename, offsetof(ID, name) + 2); + RAS_Rasterizer::StereoMode stereoMode = RAS_Rasterizer::RAS_STEREO_NOSTEREO; + if (scene) { // Quad buffered needs a special window. if (scene->gm.stereoflag == STEREO_ENABLED) { - if (scene->gm.stereomode != RAS_IRasterizer::RAS_STEREO_QUADBUFFERED) - rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) scene->gm.stereomode); - - rasterizer->SetEyeSeparation(scene->gm.eyeseparation); - } - - rasterizer->SetBackColor(scene->gm.framing.col); - } - - if (exitrequested != KX_EXIT_REQUEST_QUIT_GAME) - { - if (rv3d->persp != RV3D_CAMOB) - { - ketsjiengine->EnableCameraOverride(startscenename); - ketsjiengine->SetCameraOverrideUseOrtho((rv3d->persp == RV3D_ORTHO)); - ketsjiengine->SetCameraOverrideProjectionMatrix(MT_CmMatrix4x4(rv3d->winmat)); - ketsjiengine->SetCameraOverrideViewMatrix(MT_CmMatrix4x4(rv3d->viewmat)); - ketsjiengine->SetCameraOverrideClipping(v3d->near, v3d->far); - ketsjiengine->SetCameraOverrideLens(v3d->lens); - } - - // create a scene converter, create and convert the startingscene - KX_ISceneConverter* sceneconverter = new KX_BlenderSceneConverter(blenderdata, ketsjiengine); - ketsjiengine->SetSceneConverter(sceneconverter); - if (always_use_expand_framing) - sceneconverter->SetAlwaysUseExpandFraming(true); - - sceneconverter->SetMaterials(true); - - if (gs.matmode == GAME_MAT_GLSL) - sceneconverter->SetGLSLMaterials(true); - if (scene->gm.flag & GAME_NO_MATERIAL_CACHING) - sceneconverter->SetCacheMaterials(false); - - KX_Scene* startscene = new KX_Scene(keyboarddevice, - mousedevice, - networkdevice, - startscenename, - scene, - canvas); - -#ifdef WITH_PYTHON - // some python things - PyObject *gameLogic, *gameLogic_keys; - setupGamePython(ketsjiengine, startscene, blenderdata, pyGlobalDict, &gameLogic, &gameLogic_keys, 0, NULL); -#endif // WITH_PYTHON - - //initialize Dome Settings - if (scene->gm.stereoflag == STEREO_DOME) - ketsjiengine->InitDome(scene->gm.dome.res, scene->gm.dome.mode, scene->gm.dome.angle, scene->gm.dome.resbuf, scene->gm.dome.tilt, scene->gm.dome.warptext); - - // initialize 3D Audio Settings - AUD_Device* device = BKE_sound_get_device(); - AUD_Device_setSpeedOfSound(device, scene->audio.speed_of_sound); - AUD_Device_setDopplerFactor(device, scene->audio.doppler_factor); - AUD_Device_setDistanceModel(device, AUD_DistanceModel(scene->audio.distance_model)); - - // from see blender.c: - // FIXME: this version patching should really be part of the file-reading code, - // but we still get too many unrelated data-corruption crashes otherwise... - if (blenderdata->versionfile < 250) - do_versions_ipos_to_animato(blenderdata); - - if (sceneconverter) - { - // convert and add scene - sceneconverter->ConvertScene( - startscene, - rasterizer, - canvas); - ketsjiengine->AddScene(startscene); - - // init the rasterizer - rasterizer->Init(); - - // start the engine - ketsjiengine->StartEngine(true); - - - // Set the animation playback rate for ipo's and actions - // the framerate below should patch with FPS macro defined in blendef.h - // Could be in StartEngine set the framerate, we need the scene to do this - ketsjiengine->SetAnimFrameRate(FPS); - -#ifdef WITH_PYTHON - char *python_main = NULL; - pynextframestate.state = NULL; - pynextframestate.func = NULL; - python_main = KX_GetPythonMain(scene); - - // the mainloop - printf("\nBlender Game Engine Started\n"); - if (python_main) { - char *python_code = KX_GetPythonCode(blenderdata, python_main); - if (python_code) { - // Set python environement variable. - KX_SetActiveScene(startscene); - PHY_SetActiveEnvironment(startscene->GetPhysicsEnvironment()); - - ketsjinextframestate.ketsjiengine = ketsjiengine; - ketsjinextframestate.C = C; - ketsjinextframestate.win = win; - ketsjinextframestate.scene = scene; - ketsjinextframestate.ar = ar; - ketsjinextframestate.keyboarddevice = keyboarddevice; - ketsjinextframestate.mousedevice = mousedevice; - ketsjinextframestate.draw_letterbox = draw_letterbox; - - pynextframestate.state = &ketsjinextframestate; - pynextframestate.func = &BL_KetsjiPyNextFrame; - printf("Yielding control to Python script '%s'...\n", python_main); - PyRun_SimpleString(python_code); - printf("Exit Python script '%s'\n", python_main); - MEM_freeN(python_code); - } - } - else -#endif /* WITH_PYTHON */ - { - while (!exitrequested) - { - exitrequested = BL_KetsjiNextFrame(ketsjiengine, C, win, scene, ar, keyboarddevice, mousedevice, draw_letterbox); + if (scene->gm.stereomode != RAS_Rasterizer::RAS_STEREO_QUADBUFFERED) { + switch (scene->gm.stereomode) { + case STEREO_QUADBUFFERED: + { + stereoMode = RAS_Rasterizer::RAS_STEREO_QUADBUFFERED; + break; + } + case STEREO_ABOVEBELOW: + { + stereoMode = RAS_Rasterizer::RAS_STEREO_ABOVEBELOW; + break; + } + case STEREO_INTERLACED: + { + stereoMode = RAS_Rasterizer::RAS_STEREO_INTERLACED; + break; + } + case STEREO_ANAGLYPH: + { + stereoMode = RAS_Rasterizer::RAS_STEREO_ANAGLYPH; + break; + } + case STEREO_SIDEBYSIDE: + { + stereoMode = RAS_Rasterizer::RAS_STEREO_SIDEBYSIDE; + break; + } + case STEREO_VINTERLACE: + { + stereoMode = RAS_Rasterizer::RAS_STEREO_VINTERLACE; + break; + } + case STEREO_3DTVTOPBOTTOM: + { + stereoMode = RAS_Rasterizer::RAS_STEREO_3DTVTOPBOTTOM; + break; + } } } - printf("Blender Game Engine Finished\n"); - exitstring = ketsjiengine->GetExitString(); -#ifdef WITH_PYTHON - if (python_main) MEM_freeN(python_main); -#endif /* WITH_PYTHON */ - - gs = *(ketsjiengine->GetGlobalSettings()); - - // when exiting the mainloop -#ifdef WITH_PYTHON - // Clears the dictionary by hand: - // This prevents, extra references to global variables - // inside the GameLogic dictionary when the python interpreter is finalized. - // which allows the scene to safely delete them :) - // see: (space.c)->start_game - - //PyDict_Clear(PyModule_GetDict(gameLogic)); - - // Keep original items, means python plugins will autocomplete members - PyObject *gameLogic_keys_new = PyDict_Keys(PyModule_GetDict(gameLogic)); - const Py_ssize_t numitems= PyList_GET_SIZE(gameLogic_keys_new); - Py_ssize_t listIndex; - for (listIndex=0; listIndex < numitems; listIndex++) { - PyObject *item = PyList_GET_ITEM(gameLogic_keys_new, listIndex); - if (!PySequence_Contains(gameLogic_keys, item)) { - PyDict_DelItem( PyModule_GetDict(gameLogic), item); - } - } - Py_DECREF(gameLogic_keys_new); - gameLogic_keys_new = NULL; -#endif - ketsjiengine->StopEngine(); -#ifdef WITH_PYTHON - exitGamePythonScripting(); -#endif - networkdevice->Disconnect(); - } - if (sceneconverter) - { - delete sceneconverter; - sceneconverter = NULL; } + } + GHOST_ISystem *system = GHOST_ISystem::getSystem(); + LA_BlenderLauncher launcher = LA_BlenderLauncher(system, blenderdata, scene, &gs, stereoMode, 0, nullptr, C, cam_frame, ar, always_use_expand_framing); #ifdef WITH_PYTHON - Py_DECREF(gameLogic_keys); - gameLogic_keys = NULL; -#endif - } - //lock frame and camera enabled - restoring global values - if (v3d->scenelock==0) { - startscene->lay= tmp_lay; - startscene->camera= tmp_camera; - } + launcher.SetPythonGlobalDict(globalDict); +#endif // WITH_PYTHON - if (exitrequested != KX_EXIT_REQUEST_OUTSIDE) - { - // set the cursor back to normal - canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL); + launcher.InitEngine(); - // set mipmap setting back to its original value - rasterizer->SetMipmapping(mipmapval); - } + CM_Message(std::endl << "Blender Game Engine Started"); + exitInfo = launcher.EngineMainLoop(); + CM_Message("Blender Game Engine Finished"); - // clean up some stuff - if (ketsjiengine) - { - delete ketsjiengine; - ketsjiengine = NULL; - } - if (kxsystem) - { - delete kxsystem; - kxsystem = NULL; - } - if (networkdevice) - { - delete networkdevice; - networkdevice = NULL; - } - if (keyboarddevice) - { - delete keyboarddevice; - keyboarddevice = NULL; - } - if (mousedevice) - { - delete mousedevice; - mousedevice = NULL; - } - if (rasterizer) - { - delete rasterizer; - rasterizer = NULL; - } - if (canvas) - { - canvas->SetSwapInterval(previous_vsync); // Set the swap interval back - delete canvas; - canvas = NULL; - } + gs = *launcher.GetGlobalSettings(); - // stop all remaining playing sounds - AUD_Device_stopAll(BKE_sound_get_device()); + launcher.ExitEngine(); - } while (exitrequested == KX_EXIT_REQUEST_RESTART_GAME || exitrequested == KX_EXIT_REQUEST_START_OTHER_GAME); + } while (ELEM(exitInfo.m_code, KX_ExitInfo::RESTART_GAME, KX_ExitInfo::START_OTHER_GAME)); - if (bfd) BLO_blendfiledata_free(bfd); + // Restore cursor. + wmWindow *win = CTX_wm_window(C); + WM_cursor_set(win, CURSOR_STD); - BLI_strncpy(G.main->name, oldsce, sizeof(G.main->name)); + if (bfd) { + BLO_blendfiledata_free(bfd); + } #ifdef WITH_PYTHON - PyDict_Clear(pyGlobalDict); - Py_DECREF(pyGlobalDict); + + PyDict_Clear(globalDict); + Py_DECREF(globalDict); // Release Python's GIL PyGILState_Release(gilstate); #endif + // Restore G.main path. + BLI_strncpy(G.main->name, prevPathName, sizeof(G.main->name)); } diff --git a/source/gameengine/BlenderRoutines/CMakeLists.txt b/source/gameengine/BlenderRoutines/CMakeLists.txt index aaeb2e104626..ac570cfe27f3 100644 --- a/source/gameengine/BlenderRoutines/CMakeLists.txt +++ b/source/gameengine/BlenderRoutines/CMakeLists.txt @@ -1,14 +1,16 @@ set(INC . + ../Common ../Converter + ../Device ../Expressions ../GameLogic ../Ketsji - ../Network - ../Network/LoopBackNetwork + ../Ketsji/KXNetwork + ../Launcher ../Physics/Bullet - ../Physics/common + ../Physics/Common ../Rasterizer ../Rasterizer/RAS_OpenGLRasterizer ../SceneGraph @@ -23,34 +25,24 @@ set(INC ../../blender/makesdna ../../blender/makesrna ../../blender/windowmanager - ../../../intern/container - ../../../intern/glew-mx ../../../intern/guardedalloc ../../../intern/string + ../../../intern/termcolor + ../../../intern/ghost ) set(INC_SYS - ../../../intern/moto/include + ../../../intern/debugbreak + ../../../intern/mathfu ${PTHREADS_INCLUDE_DIRS} - ${GLEW_INCLUDE_PATH} ${BOOST_INCLUDE_DIR} ) set(SRC BL_KetsjiEmbedStart.cpp - BL_System.cpp KX_BlenderCanvas.cpp - KX_BlenderInputDevice.cpp - KX_BlenderKeyboardDevice.cpp - KX_BlenderMouseDevice.cpp - KX_BlenderSystem.cpp - BL_System.h KX_BlenderCanvas.h - KX_BlenderInputDevice.h - KX_BlenderKeyboardDevice.h - KX_BlenderMouseDevice.h - KX_BlenderSystem.h ) add_definitions(${GL_DEFINITIONS}) diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp index fdfa64cbd91b..357aa2835382 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp +++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp @@ -29,40 +29,37 @@ * \ingroup blroutines */ -#include "GPU_glew.h" - #include "MEM_guardedalloc.h" #include "KX_BlenderCanvas.h" +#include "KX_Globals.h" #include "DNA_screen_types.h" #include "DNA_scene_types.h" #include "DNA_windowmanager_types.h" +#include "BLI_string.h" +#include "BLI_path_util.h" + #include "BKE_image.h" -#include -#include +#include "RAS_Rasterizer.h" + +#include "GHOST_IWindow.h" extern "C" { -#include "WM_api.h" -#include "wm_cursors.h" -#include "wm_window.h" +# include "WM_api.h" +# include "wm_cursors.h" +# include "wm_window.h" } -KX_BlenderCanvas::KX_BlenderCanvas(wmWindowManager *wm, wmWindow *win, RAS_Rect &rect, struct ARegion *ar) : -m_wm(wm), -m_win(win), -m_frame_rect(rect) +KX_BlenderCanvas::KX_BlenderCanvas(RAS_Rasterizer *rasty, wmWindowManager *wm, wmWindow *win, RAS_Rect &rect) + :RAS_ICanvas(rasty), + m_wm(wm), + m_win(win), + m_area_rect(rect) // initialize area so that it's available for game logic on frame 1 (ImageViewport) { - // initialize area so that it's available for game logic on frame 1 (ImageViewport) - m_area_rect = rect; - // area boundaries needed for mouse coordinates in Letterbox framing mode - m_area_left = ar->winrct.xmin; - m_area_top = ar->winrct.ymax; - m_frame = 1; - - glGetIntegerv(GL_VIEWPORT, (GLint *)m_viewport); + m_rasterizer->GetViewport(m_viewport); } KX_BlenderCanvas::~KX_BlenderCanvas() @@ -71,23 +68,17 @@ KX_BlenderCanvas::~KX_BlenderCanvas() void KX_BlenderCanvas::Init() { - glDepthFunc(GL_LEQUAL); } - void KX_BlenderCanvas::SwapBuffers() { wm_window_swap_buffers(m_win); } -void KX_BlenderCanvas::SetSwapInterval(int interval) -{ - wm_window_set_swap_interval(m_win, interval); -} - -bool KX_BlenderCanvas::GetSwapInterval(int &intervalOut) +void KX_BlenderCanvas::SetSwapControl(SwapControl control) { - return wm_window_get_swap_interval(m_win, &intervalOut); + wm_window_set_swap_interval(m_win, swapInterval[control]); + RAS_ICanvas::SetSwapControl(control); } void KX_BlenderCanvas::GetDisplayDimensions(int &width, int &height) @@ -100,6 +91,11 @@ void KX_BlenderCanvas::ResizeWindow(int width, int height) // Not implemented for the embedded player } +void KX_BlenderCanvas::Resize(int width, int height) +{ + // Not implemented for the embedded player +} + void KX_BlenderCanvas::SetFullScreen(bool enable) { // Not implemented for the embedded player @@ -111,15 +107,13 @@ bool KX_BlenderCanvas::GetFullScreen() return false; } -bool KX_BlenderCanvas::BeginDraw() +void KX_BlenderCanvas::BeginDraw() { // in case of multi-window we need to ensure we are drawing to the correct // window always, because it may change in window event handling wm_window_make_drawable(m_wm, m_win); - return true; } - void KX_BlenderCanvas::EndDraw() { // nothing needs to be done here @@ -127,134 +121,83 @@ void KX_BlenderCanvas::EndDraw() void KX_BlenderCanvas::BeginFrame() { - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); } - void KX_BlenderCanvas::EndFrame() { - glDisable(GL_FOG); } - - -void KX_BlenderCanvas::ClearColor(float r,float g,float b,float a) +int KX_BlenderCanvas::GetWidth() const { - glClearColor(r,g,b,a); + return m_area_rect.GetWidth(); } - - -void KX_BlenderCanvas::ClearBuffer(int type) +int KX_BlenderCanvas::GetHeight() const { - int ogltype = 0; - - if (type & RAS_ICanvas::COLOR_BUFFER ) - ogltype |= GL_COLOR_BUFFER_BIT; - - if (type & RAS_ICanvas::DEPTH_BUFFER ) - ogltype |= GL_DEPTH_BUFFER_BIT; - glClear(ogltype); -} - -int KX_BlenderCanvas::GetWidth( -) const { - return m_frame_rect.GetWidth(); + return m_area_rect.GetHeight(); } -int KX_BlenderCanvas::GetHeight( -) const { - return m_frame_rect.GetHeight(); +int KX_BlenderCanvas::GetMaxX() const +{ + return m_area_rect.GetMaxX(); } -int KX_BlenderCanvas::GetMouseX(int x) +int KX_BlenderCanvas::GetMaxY() const { - int left = GetWindowArea().GetLeft(); - return x - (left - m_area_left); + return m_area_rect.GetMaxY(); } -int KX_BlenderCanvas::GetMouseY(int y) +void KX_BlenderCanvas::ConvertMousePosition(int x, int y, int &r_x, int &r_y, bool screen) { - int top = GetWindowArea().GetTop(); - return y - (m_area_top - top); + if (screen) { + wm_cursor_position_from_ghost(m_win, &x, &y); + } + + r_x = x - m_area_rect.GetLeft(); + r_y = -y + m_area_rect.GetTop(); } float KX_BlenderCanvas::GetMouseNormalizedX(int x) { - int can_x = GetMouseX(x); - return float(can_x)/this->GetWidth(); + return float(x) / GetMaxX(); } float KX_BlenderCanvas::GetMouseNormalizedY(int y) { - int can_y = GetMouseY(y); - return float(can_y)/this->GetHeight(); + return float(y) / GetMaxY(); } -RAS_Rect & -KX_BlenderCanvas:: -GetWindowArea( -) { +RAS_Rect &KX_BlenderCanvas::GetWindowArea() +{ return m_area_rect; } - void -KX_BlenderCanvas:: -SetViewPort( - int x1, int y1, - int x2, int y2 -) { - /* x1 and y1 are the min pixel coordinate (e.g. 0) - * x2 and y2 are the max pixel coordinate - * the width,height is calculated including both pixels - * therefore: max - min + 1 - */ - int vp_width = (x2 - x1) + 1; - int vp_height = (y2 - y1) + 1; - int minx = m_frame_rect.GetLeft(); - int miny = m_frame_rect.GetBottom(); - - m_area_rect.SetLeft(minx + x1); - m_area_rect.SetBottom(miny + y1); - m_area_rect.SetRight(minx + x2); - m_area_rect.SetTop(miny + y2); - - m_viewport[0] = minx+x1; - m_viewport[1] = miny+y1; - m_viewport[2] = vp_width; - m_viewport[3] = vp_height; - - glViewport(minx + x1, miny + y1, vp_width, vp_height); - glScissor(minx + x1, miny + y1, vp_width, vp_height); +void KX_BlenderCanvas::SetViewPort(int x, int y, int width, int height) +{ + int minx = m_area_rect.GetLeft(); + int miny = m_area_rect.GetBottom(); + + m_area_rect.SetLeft(minx + x); + m_area_rect.SetBottom(miny + y); + m_area_rect.SetRight(minx + x + width - 1); + m_area_rect.SetTop(miny + y + height - 1); + + m_viewport[0] = minx + x; + m_viewport[1] = miny + y; + m_viewport[2] = width; + m_viewport[3] = height; } - void -KX_BlenderCanvas:: -UpdateViewPort( - int x1, int y1, - int x2, int y2 -) { - m_viewport[0] = x1; - m_viewport[1] = y1; - m_viewport[2] = x2; - m_viewport[3] = y2; +void KX_BlenderCanvas::UpdateViewPort(int x, int y, int width, int height) +{ + m_viewport[0] = x; + m_viewport[1] = y; + m_viewport[2] = width; + m_viewport[3] = height; } - const int* -KX_BlenderCanvas:: -GetViewPort() { -#ifdef DEBUG - // If we're in a debug build, we might as well make sure our values don't differ - // from what the gpu thinks we have. This could lead to nasty, hard to find bugs. - int viewport[4]; - glGetIntegerv(GL_VIEWPORT, viewport); - assert(viewport[0] == m_viewport[0]); - assert(viewport[1] == m_viewport[1]); - assert(viewport[2] == m_viewport[2]); - assert(viewport[3] == m_viewport[3]); -#endif - +const int *KX_BlenderCanvas::GetViewPort() +{ return m_viewport; } @@ -262,92 +205,61 @@ void KX_BlenderCanvas::SetMouseState(RAS_MouseState mousestate) { m_mousestate = mousestate; - switch (mousestate) - { - case MOUSE_INVISIBLE: + switch (mousestate) { + case MOUSE_INVISIBLE: { WM_cursor_set(m_win, CURSOR_NONE); break; } - case MOUSE_WAIT: + case MOUSE_WAIT: { WM_cursor_set(m_win, CURSOR_WAIT); break; } - case MOUSE_NORMAL: + case MOUSE_NORMAL: { WM_cursor_set(m_win, CURSOR_STD); break; } - default: + default: { } } } - - -// (0,0) is top left, (width,height) is bottom right -void KX_BlenderCanvas::SetMousePosition(int x,int y) -{ - int winX = m_frame_rect.GetLeft(); - int winY = m_frame_rect.GetBottom(); - int winH = m_frame_rect.GetHeight(); - - WM_cursor_warp(m_win, winX + x, winY + (winH-y)); -} - - -/* get shot from frontbuffer sort of a copy from screendump.c */ -static unsigned int *screenshot(ScrArea *curarea, int *dumpsx, int *dumpsy) +void KX_BlenderCanvas::SetMousePosition(int x, int y) { - int x=0, y=0; - unsigned int *dumprect= NULL; - - x= curarea->totrct.xmin; - y= curarea->totrct.ymin; - *dumpsx= curarea->totrct.xmax-x; - *dumpsy= curarea->totrct.ymax-y; - - if (*dumpsx && *dumpsy) { - - dumprect= (unsigned int *)MEM_mallocN(sizeof(int) * (*dumpsx) * (*dumpsy), "dumprect"); - glReadBuffer(GL_FRONT); - glReadPixels(x, y, *dumpsx, *dumpsy, GL_RGBA, GL_UNSIGNED_BYTE, dumprect); - glFinish(); - glReadBuffer(GL_BACK); - } + int winX = m_area_rect.GetLeft(); + int winY = m_area_rect.GetBottom(); + int winMaxY = m_area_rect.GetMaxY(); - return dumprect; + WM_cursor_warp(m_win, winX + x, winY + (winMaxY - y)); } -void KX_BlenderCanvas::MakeScreenShot(const char *filename) +void KX_BlenderCanvas::MakeScreenShot(const std::string& filename) { - ScrArea area_dummy= {0}; bScreen *screen = m_win->screen; - unsigned int *dumprect; - int dumpsx, dumpsy; - - area_dummy.totrct.xmin = m_frame_rect.GetLeft(); - area_dummy.totrct.xmax = m_frame_rect.GetRight(); - area_dummy.totrct.ymin = m_frame_rect.GetBottom(); - area_dummy.totrct.ymax = m_frame_rect.GetTop(); - - dumprect = screenshot(&area_dummy, &dumpsx, &dumpsy); - if (!dumprect) { - std::cerr << "KX_BlenderCanvas: Unable to take screenshot!" << std::endl; - return; - } + + int x = m_area_rect.GetLeft(); + int y = m_area_rect.GetBottom(); + int width = m_area_rect.GetWidth(); + int height = m_area_rect.GetHeight(); /* initialize image file format data */ - Scene *scene = (screen)? screen->scene: NULL; + Scene *scene = (screen) ? screen->scene : nullptr; ImageFormatData *im_format = (ImageFormatData *)MEM_mallocN(sizeof(ImageFormatData), "im_format"); - if (scene) + if (scene) { *im_format = scene->r.im_format; - else + } + else { BKE_imformat_defaults(im_format); + } + + // create file path + char path[FILE_MAX]; + BLI_strncpy(path, filename.c_str(), FILE_MAX); + BLI_path_abs(path, KX_GetMainPath().c_str()); - /* save_screenshot() frees dumprect and im_format */ - save_screenshot(filename, dumpsx, dumpsy, dumprect, im_format); + AddScreenshot(path, x, y, width, height, im_format); } diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h index 8029360273b1..7391433a7a4d 100644 --- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h +++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h @@ -39,11 +39,6 @@ #include "RAS_ICanvas.h" #include "RAS_Rect.h" -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -struct ARegion; struct wmWindow; struct wmWindowManager; @@ -55,168 +50,54 @@ struct wmWindowManager; class KX_BlenderCanvas : public RAS_ICanvas { private: - /** - * Rect that defines the area used for rendering, - * relative to the context */ - RAS_Rect m_displayarea; int m_viewport[4]; + wmWindowManager *m_wm; + wmWindow *m_win; + RAS_Rect m_area_rect; + public: - /* Construct a new canvas. - * - * \param area The Blender ARegion to run the game within. - */ - KX_BlenderCanvas(struct wmWindowManager *wm, struct wmWindow* win, RAS_Rect &rect, struct ARegion* ar); - ~KX_BlenderCanvas(); - - void - Init( - ); - - void - SwapBuffers( - ); - - void - SetSwapInterval( - int interval - ); - - bool - GetSwapInterval( - int &intervalOut - ); - - void GetDisplayDimensions(int &width, int &height); - - void - ResizeWindow( - int width, - int height - ); - - void - SetFullScreen( - bool enable - ); - - bool - GetFullScreen(); - - void - BeginFrame( - ); - - void - EndFrame( - ); - - void - ClearColor( - float r, - float g, - float b, - float a - ); - - void - ClearBuffer( - int type - ); - - int - GetWidth( - ) const; - - int - GetHeight( - ) const; - - int - GetMouseX(int x - ); - - int - GetMouseY(int y - ); - - float - GetMouseNormalizedX(int x - ); - - float - GetMouseNormalizedY(int y - ); - - const - RAS_Rect & - GetDisplayArea( - ) const { - return m_displayarea; - }; - - void - SetDisplayArea(RAS_Rect *rect - ) { - m_displayarea= *rect; - }; - - RAS_Rect & - GetWindowArea( - ); - - void - SetViewPort( - int x1, int y1, - int x2, int y2 - ); - - void - UpdateViewPort( - int x1, int y1, - int x2, int y2 - ); - - const int* - GetViewPort(); - - void - SetMouseState( - RAS_MouseState mousestate - ); - - void - SetMousePosition( - int x, - int y - ); - - void - MakeScreenShot( - const char* filename - ); - - bool - BeginDraw( - ); - - void - EndDraw( - ); + KX_BlenderCanvas(RAS_Rasterizer *rasty, wmWindowManager *wm, wmWindow *win, RAS_Rect &rect); + virtual ~KX_BlenderCanvas(); -private: - /** Blender area the game engine is running within */ - struct wmWindowManager *m_wm; - struct wmWindow* m_win; - RAS_Rect m_frame_rect; - RAS_Rect m_area_rect; - int m_area_left; - int m_area_top; + virtual void Init(); + virtual void SwapBuffers(); + virtual void SetSwapControl(SwapControl control); -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_BlenderCanvas") -#endif + virtual void GetDisplayDimensions(int &width, int &height); + virtual void ResizeWindow(int width, int height); + virtual void Resize(int width, int height); + + virtual void SetFullScreen(bool enable); + virtual bool GetFullScreen(); + + virtual void BeginFrame(); + virtual void EndFrame(); + + virtual int GetWidth() const; + virtual int GetHeight() const; + virtual int GetMaxX() const; + virtual int GetMaxY() const; + + virtual void ConvertMousePosition(int x, int y, int &r_x, int &r_y, bool screen); + + virtual float GetMouseNormalizedX(int x); + virtual float GetMouseNormalizedY(int y); + + virtual RAS_Rect &GetWindowArea(); + + virtual void SetViewPort(int x, int y, int width, int height); + virtual void UpdateViewPort(int x, int y, int width, int height); + virtual const int *GetViewPort(); + + virtual void SetMouseState(RAS_MouseState mousestate); + virtual void SetMousePosition(int x, int y); + + virtual void MakeScreenShot(const std::string& filename); + + virtual void BeginDraw(); + virtual void EndDraw(); }; -#endif /* __KX_BLENDERCANVAS_H__ */ +#endif // __KX_BLENDERCANVAS_H__ diff --git a/source/gameengine/BlenderRoutines/KX_BlenderInputDevice.cpp b/source/gameengine/BlenderRoutines/KX_BlenderInputDevice.cpp deleted file mode 100644 index 50daf89d8c8d..000000000000 --- a/source/gameengine/BlenderRoutines/KX_BlenderInputDevice.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/BlenderRoutines/KX_BlenderInputDevice.cpp - * \ingroup blroutines - */ - -#include "KX_BlenderInputDevice.h" diff --git a/source/gameengine/BlenderRoutines/KX_BlenderInputDevice.h b/source/gameengine/BlenderRoutines/KX_BlenderInputDevice.h deleted file mode 100644 index a936f3285453..000000000000 --- a/source/gameengine/BlenderRoutines/KX_BlenderInputDevice.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file KX_BlenderInputDevice.h - * \ingroup blroutines - */ - -#ifndef __KX_BLENDERINPUTDEVICE_H__ -#define __KX_BLENDERINPUTDEVICE_H__ - -#ifdef _MSC_VER -# pragma warning(disable:4786) // shut off 255 char limit debug template warning -#endif - -#include - -#include "wm_event_types.h" -#include "WM_types.h" -#include "SCA_IInputDevice.h" -#include "BL_BlenderDataConversion.h" - -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -/** - * Base Class for Blender specific inputdevices. - * Blender specific inputdevices are used when the gameengine is running in embedded mode instead of standalone mode. - */ -class BL_BlenderInputDevice : public SCA_IInputDevice -{ -public: - BL_BlenderInputDevice() - { - } - - virtual ~BL_BlenderInputDevice() - { - - } - - KX_EnumInputs ToNative(unsigned short incode) { - return ConvertKeyCode(incode); - } - - virtual bool IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode)=0; - // virtual const SCA_InputEvent& GetEventValue(SCA_IInputDevice::KX_EnumInputs inputcode)=0; - virtual bool ConvertBlenderEvent(unsigned short incode, short val, unsigned int unicode)=0; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_BlenderInputDevice") -#endif -}; - -#endif /* __KX_BLENDERINPUTDEVICE_H__ */ diff --git a/source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.cpp b/source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.cpp deleted file mode 100644 index 073f91bf8c47..000000000000 --- a/source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.cpp - * \ingroup blroutines - */ - - -#ifdef _MSC_VER - /* annoying warnings about truncated STL debug info */ -# pragma warning (disable:4786) -#endif - -#include "KX_BlenderKeyboardDevice.h" -#include "KX_KetsjiEngine.h" - -KX_BlenderKeyboardDevice::KX_BlenderKeyboardDevice() - : m_hookesc(false) -{ - -} -KX_BlenderKeyboardDevice::~KX_BlenderKeyboardDevice() -{ - -} - -/** - * IsPressed gives boolean information about keyboard status, true if pressed, false if not - */ - -bool KX_BlenderKeyboardDevice::IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode) -{ - const SCA_InputEvent & inevent = m_eventStatusTables[m_currentTable][inputcode]; - bool pressed = (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED || - inevent.m_status == SCA_InputEvent::KX_ACTIVE); - return pressed; -} -/*const SCA_InputEvent& KX_BlenderKeyboardDevice::GetEventValue(SCA_IInputDevice::KX_EnumInputs inputcode) -{ - return m_eventStatusTables[m_currentTable][inputcode]; -} -*/ -/** - * NextFrame toggles currentTable with previousTable, - * and copy relevant event information from previous to current - * (pressed keys need to be remembered) - */ -void KX_BlenderKeyboardDevice::NextFrame() -{ - SCA_IInputDevice::NextFrame(); - - // now convert justpressed keyevents into regular (active) keyevents - int previousTable = 1-m_currentTable; - for (int keyevent= KX_BEGINKEY; keyevent<= KX_ENDKEY;keyevent++) - { - SCA_InputEvent& oldevent = m_eventStatusTables[previousTable][keyevent]; - if (oldevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED || - oldevent.m_status == SCA_InputEvent::KX_ACTIVE ) - { - m_eventStatusTables[m_currentTable][keyevent] = oldevent; - m_eventStatusTables[m_currentTable][keyevent].m_status = SCA_InputEvent::KX_ACTIVE; - } - } -} - -/** - * ConvertBlenderEvent translates blender keyboard events into ketsji kbd events - * extra event information is stored, like ramp-mode (just released/pressed) -*/ -bool KX_BlenderKeyboardDevice::ConvertBlenderEvent(unsigned short incode, short val, unsigned int unicode) -{ - bool result = false; - - // convert event - KX_EnumInputs kxevent = this->ToNative(incode); - - // only process it, if it's a key - if (kxevent >= KX_BEGINKEY && kxevent <= KX_ENDKEY) - { - int previousTable = 1-m_currentTable; - - if (val == KM_PRESS || val == KM_DBL_CLICK) - { - if (kxevent == KX_KetsjiEngine::GetExitKey() && val != 0 && !m_hookesc) - result = true; - if (kxevent == KX_PAUSEKEY && val && (IsPressed(KX_LEFTCTRLKEY) || IsPressed(KX_RIGHTCTRLKEY))) - result = true; - - // todo: convert val ?? - m_eventStatusTables[m_currentTable][kxevent].m_eventval = val ; //??? - m_eventStatusTables[m_currentTable][kxevent].m_unicode = unicode; - - switch (m_eventStatusTables[previousTable][kxevent].m_status) - { - case SCA_InputEvent::KX_JUSTACTIVATED: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_ACTIVE; - break; - } - case SCA_InputEvent::KX_ACTIVE: - - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_ACTIVE; - break; - } - case SCA_InputEvent::KX_NO_INPUTSTATUS: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTACTIVATED; - break; - } - default: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTACTIVATED; - } - } - - } else if (val == KM_RELEASE) - { - // blender eventval == 0 - switch (m_eventStatusTables[previousTable][kxevent].m_status) - { - case SCA_InputEvent::KX_JUSTACTIVATED: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTRELEASED; - break; - } - case SCA_InputEvent::KX_ACTIVE: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTRELEASED; - break; - } - default: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_NO_INPUTSTATUS; - } - } - } - } - return result; -} - -void KX_BlenderKeyboardDevice::HookEscape() -{ - m_hookesc = true; -} diff --git a/source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.h b/source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.h deleted file mode 100644 index 10a5b00937d0..000000000000 --- a/source/gameengine/BlenderRoutines/KX_BlenderKeyboardDevice.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file KX_BlenderKeyboardDevice.h - * \ingroup blroutines - */ - -#ifndef __KX_BLENDERKEYBOARDDEVICE_H__ -#define __KX_BLENDERKEYBOARDDEVICE_H__ - -#include "KX_BlenderInputDevice.h" - -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -class KX_BlenderKeyboardDevice : public BL_BlenderInputDevice -{ - bool m_hookesc; -public: - KX_BlenderKeyboardDevice(); - virtual ~KX_BlenderKeyboardDevice(); - - virtual bool IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode); -// virtual const SCA_InputEvent& GetEventValue(SCA_IInputDevice::KX_EnumInputs inputcode); - virtual bool ConvertBlenderEvent(unsigned short incode, short val, unsigned int unicode); - virtual void NextFrame(); - virtual void HookEscape(); -private: - /* short m_exit_key; */ /* UNUSED */ - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_BlenderKeyboardDevice") -#endif -}; - -#endif /* __KX_BLENDERKEYBOARDDEVICE_H__ */ diff --git a/source/gameengine/BlenderRoutines/KX_BlenderMouseDevice.cpp b/source/gameengine/BlenderRoutines/KX_BlenderMouseDevice.cpp deleted file mode 100644 index fee184e19028..000000000000 --- a/source/gameengine/BlenderRoutines/KX_BlenderMouseDevice.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/BlenderRoutines/KX_BlenderMouseDevice.cpp - * \ingroup blroutines - */ - -#ifdef _MSC_VER - /* annoying warnings about truncated STL debug info */ -# pragma warning (disable:4786) -#endif - -#include "KX_BlenderMouseDevice.h" - -KX_BlenderMouseDevice::KX_BlenderMouseDevice() -{ - -} -KX_BlenderMouseDevice::~KX_BlenderMouseDevice() -{ - -} - -/** - * IsPressed gives boolean information about mouse status, true if pressed, false if not - */ - -bool KX_BlenderMouseDevice::IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode) -{ - const SCA_InputEvent & inevent = m_eventStatusTables[m_currentTable][inputcode]; - bool pressed = (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED || - inevent.m_status == SCA_InputEvent::KX_ACTIVE); - return pressed; -} -/*const SCA_InputEvent& KX_BlenderMouseDevice::GetEventValue(SCA_IInputDevice::KX_EnumInputs inputcode) -{ - return m_eventStatusTables[m_currentTable][inputcode]; -} -*/ - -/** - * NextFrame toggles currentTable with previousTable, - * and copy relevant event information from previous to current - * (pressed keys need to be remembered) - */ -void KX_BlenderMouseDevice::NextFrame() -{ - SCA_IInputDevice::NextFrame(); - - // now convert justpressed keyevents into regular (active) keyevents - int previousTable = 1-m_currentTable; - for (int mouseevent= KX_BEGINMOUSE; mouseevent< KX_ENDMOUSEBUTTONS;mouseevent++) - { - SCA_InputEvent& oldevent = m_eventStatusTables[previousTable][mouseevent]; - if (oldevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED || - oldevent.m_status == SCA_InputEvent::KX_ACTIVE ) - { - m_eventStatusTables[m_currentTable][mouseevent] = oldevent; - m_eventStatusTables[m_currentTable][mouseevent].m_status = SCA_InputEvent::KX_ACTIVE; - } - } - for (int mousemove= KX_ENDMOUSEBUTTONS; mousemove< KX_ENDMOUSE;mousemove++) - { - SCA_InputEvent& oldevent = m_eventStatusTables[previousTable][mousemove]; - m_eventStatusTables[m_currentTable][mousemove] = oldevent; - if (oldevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED || - oldevent.m_status == SCA_InputEvent::KX_ACTIVE ) - { - - m_eventStatusTables[m_currentTable][mousemove].m_status = SCA_InputEvent::KX_JUSTRELEASED; - } else - { - if (oldevent.m_status == SCA_InputEvent::KX_JUSTRELEASED) - { - - m_eventStatusTables[m_currentTable][mousemove].m_status = SCA_InputEvent::KX_NO_INPUTSTATUS; - } - } - } -} - - -/** - * ConvertBlenderEvent translates blender mouse events into ketsji kbd events - * extra event information is stored, like ramp-mode (just released/pressed) - */ -bool KX_BlenderMouseDevice::ConvertBlenderEvent(unsigned short incode, short val, unsigned int unicode) -{ - bool result = false; - - // convert event - KX_EnumInputs kxevent = this->ToNative(incode); - int previousTable = 1-m_currentTable; - - // only process it, if it's a key - if (kxevent > KX_BEGINMOUSE && kxevent < KX_ENDMOUSEBUTTONS) - { - if (val == KM_PRESS || val == KM_DBL_CLICK) - { - m_eventStatusTables[m_currentTable][kxevent].m_eventval = val ; //??? - - switch (m_eventStatusTables[previousTable][kxevent].m_status) - { - - case SCA_InputEvent::KX_ACTIVE: - case SCA_InputEvent::KX_JUSTACTIVATED: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_ACTIVE; - break; - } - case SCA_InputEvent::KX_JUSTRELEASED: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTACTIVATED; - break; - } - default: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTACTIVATED; - } - } - - } else if (val == KM_RELEASE) - { - // blender eventval == 0 - switch (m_eventStatusTables[previousTable][kxevent].m_status) - { - case SCA_InputEvent::KX_JUSTACTIVATED: - case SCA_InputEvent::KX_ACTIVE: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTRELEASED; - break; - } - default: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_NO_INPUTSTATUS; - } - } - } - } - - if (kxevent > KX_ENDMOUSEBUTTONS && kxevent < KX_ENDMOUSE) - { - m_eventStatusTables[m_currentTable][kxevent].m_eventval = val ; //remember mouse position - - switch (m_eventStatusTables[previousTable][kxevent].m_status) - { - - case SCA_InputEvent::KX_ACTIVE: - case SCA_InputEvent::KX_JUSTACTIVATED: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_ACTIVE; - break; - } - case SCA_InputEvent::KX_JUSTRELEASED: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_ACTIVE; - break; - } - default: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTACTIVATED; - } - } - } - - - return result; -} diff --git a/source/gameengine/BlenderRoutines/KX_BlenderMouseDevice.h b/source/gameengine/BlenderRoutines/KX_BlenderMouseDevice.h deleted file mode 100644 index 04b78aff05cd..000000000000 --- a/source/gameengine/BlenderRoutines/KX_BlenderMouseDevice.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file KX_BlenderMouseDevice.h - * \ingroup blroutines - */ - -#ifndef __KX_BLENDERMOUSEDEVICE_H__ -#define __KX_BLENDERMOUSEDEVICE_H__ - -#include "KX_BlenderInputDevice.h" - -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -class KX_BlenderMouseDevice : public BL_BlenderInputDevice -{ -public: - KX_BlenderMouseDevice(); - virtual ~KX_BlenderMouseDevice(); - - virtual bool IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode); -// virtual const SCA_InputEvent& GetEventValue(SCA_IInputDevice::KX_EnumInputs inputcode); - virtual bool ConvertBlenderEvent(unsigned short incode, short val, unsigned int unicode); - virtual void NextFrame(); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_BlenderMouseDevice") -#endif -}; - -#endif /* __KX_BLENDERMOUSEDEVICE_H__ */ diff --git a/source/gameengine/BlenderRoutines/KX_BlenderSystem.cpp b/source/gameengine/BlenderRoutines/KX_BlenderSystem.cpp deleted file mode 100644 index 0582e79d2699..000000000000 --- a/source/gameengine/BlenderRoutines/KX_BlenderSystem.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/BlenderRoutines/KX_BlenderSystem.cpp - * \ingroup blroutines - */ - - -#include "KX_ISystem.h" - -#ifdef _MSC_VER -# pragma warning (disable:4786) -#endif - -#ifdef WIN32 -#include -#endif - -#include -#include -#include "KX_BlenderInputDevice.h" -#include "KX_BlenderSystem.h" - -#include "PIL_time.h" - -KX_BlenderSystem::KX_BlenderSystem() -: KX_ISystem() -{ - m_starttime = PIL_check_seconds_timer(); -} - -double KX_BlenderSystem::GetTimeInSeconds() -{ - return PIL_check_seconds_timer() - m_starttime; -} diff --git a/source/gameengine/BlenderRoutines/KX_BlenderSystem.h b/source/gameengine/BlenderRoutines/KX_BlenderSystem.h deleted file mode 100644 index 0867ef2421f5..000000000000 --- a/source/gameengine/BlenderRoutines/KX_BlenderSystem.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file KX_BlenderSystem.h - * \ingroup blroutines - * \brief Blender System embedding. Needed when gameengine runs embedded within Blender. - */ - -#ifndef __KX_BLENDERSYSTEM_H__ -#define __KX_BLENDERSYSTEM_H__ - -#include "KX_ISystem.h" - -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -class KX_BlenderSystem : public KX_ISystem -{ - double m_starttime; - -public: - KX_BlenderSystem(); - virtual ~KX_BlenderSystem() {} - virtual double GetTimeInSeconds(); - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_BlenderSystem") -#endif -}; - -#endif /* __KX_BLENDERSYSTEM_H__ */ diff --git a/source/gameengine/CMakeLists.txt b/source/gameengine/CMakeLists.txt index 62523175f46e..89bb3343e886 100644 --- a/source/gameengine/CMakeLists.txt +++ b/source/gameengine/CMakeLists.txt @@ -25,22 +25,31 @@ remove_extra_strict_flags() +blender_include_dirs_sys("${TBB_INCLUDE_DIR}") + # there are too many inter-includes so best define here if(WITH_PYTHON) blender_include_dirs_sys("${PYTHON_INCLUDE_DIRS}") add_definitions(-DWITH_PYTHON) endif() +if(WITH_GAMEENGINE_TEST) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SANITIZER_OPTIONS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SANITIZER_OPTIONS}") +endif() + add_subdirectory(BlenderRoutines) +add_subdirectory(Common) add_subdirectory(Converter) +add_subdirectory(Device) add_subdirectory(Expressions) add_subdirectory(GameLogic) add_subdirectory(Ketsji) add_subdirectory(Ketsji/KXNetwork) -add_subdirectory(Network) -add_subdirectory(Network/LoopBackNetwork) +add_subdirectory(Launcher) add_subdirectory(Physics/Dummy) add_subdirectory(Rasterizer) +add_subdirectory(Rasterizer/Node) add_subdirectory(Rasterizer/RAS_OpenGLRasterizer) add_subdirectory(SceneGraph) diff --git a/source/gameengine/Common/CM_Clock.cpp b/source/gameengine/Common/CM_Clock.cpp new file mode 100644 index 000000000000..59bfd7a458b2 --- /dev/null +++ b/source/gameengine/Common/CM_Clock.cpp @@ -0,0 +1,22 @@ +#include "CM_Clock.h" + +CM_Clock::CM_Clock() +{ + Reset(); +} + +void CM_Clock::Reset() +{ + m_start = m_clock.now(); +} + +double CM_Clock::GetTimeSecond() const +{ + return GetTimeNano() * 1e-9; +} + +CM_Clock::Rep CM_Clock::GetTimeNano() const +{ + const std::chrono::high_resolution_clock::time_point now = m_clock.now(); + return std::chrono::duration_cast(now - m_start).count(); +} diff --git a/source/gameengine/Common/CM_Clock.h b/source/gameengine/Common/CM_Clock.h new file mode 100644 index 000000000000..536768d53dfc --- /dev/null +++ b/source/gameengine/Common/CM_Clock.h @@ -0,0 +1,24 @@ +#ifndef __CM_CLOCK_H__ +#define __CM_CLOCK_H__ + +#include + +class CM_Clock +{ +public: + using Rep = std::chrono::nanoseconds::rep; + +private: + std::chrono::high_resolution_clock::time_point m_start; + std::chrono::high_resolution_clock m_clock; + +public: + CM_Clock(); + + void Reset(); + + double GetTimeSecond() const; + Rep GetTimeNano() const; +}; + +#endif // __CM_CLOCK_H__ diff --git a/intern/moto/intern/MT_Point3.cpp b/source/gameengine/Common/CM_Format.h similarity index 70% rename from intern/moto/intern/MT_Point3.cpp rename to source/gameengine/Common/CM_Format.h index 48003a8e60b2..446a988da1e7 100644 --- a/intern/moto/intern/MT_Point3.cpp +++ b/source/gameengine/Common/CM_Format.h @@ -15,24 +15,28 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. + * Contributor(s): Tristan Porteries. * * ***** END GPL LICENSE BLOCK ***** */ -/** \file moto/intern/MT_Point3.cpp - * \ingroup moto +/** \file CM_Format.h + * \ingroup common */ +#ifndef __CM_FORMAT_H__ +#define __CM_FORMAT_H__ + +#include +#include -#include "MT_Point3.h" +template +bool CM_StringTo(const std::string& string, T& out) +{ + std::stringstream stream(string); + stream >> out; + return !stream.fail(); +} -#ifndef GEN_INLINED -#include "MT_Point3.inl" -#endif +#endif // __CM_FORMAT_H__ diff --git a/source/gameengine/Ketsji/KX_RayEventManager.cpp b/source/gameengine/Common/CM_List.h similarity index 56% rename from source/gameengine/Ketsji/KX_RayEventManager.cpp rename to source/gameengine/Common/CM_List.h index d561dacba09e..64bc2e3dff6c 100644 --- a/source/gameengine/Ketsji/KX_RayEventManager.cpp +++ b/source/gameengine/Common/CM_List.h @@ -1,7 +1,4 @@ /* - * Manager for ray events - * - * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -18,35 +15,39 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. + * Contributor(s): Tristan Porteries. * * ***** END GPL LICENSE BLOCK ***** */ -/** \file gameengine/Ketsji/KX_RayEventManager.cpp - * \ingroup ketsji +/** \file CM_List.h + * \ingroup common */ -#include "KX_RayEventManager.h" -#include "SCA_LogicManager.h" -#include "SCA_ISensor.h" -#include +#ifndef __CM_LIST_H__ +#define __CM_LIST_H__ -using namespace std; +#include -#include -#include +template +inline bool CM_ListRemoveIfFound(List& list, const Item& item) +{ + const typename List::iterator it = std::find(list.begin(), list.end(), item); + if (it != list.end()) { + list.erase(it); + return true; + } + return false; +} -void KX_RayEventManager::NextFrame() +template +inline bool CM_ListAddIfNotFound(List& list, const Item& item) { - SG_DList::iterator it(m_sensors); - for (it.begin();!it.end();++it) - { - (*it)->Activate(m_logicmgr); + if (std::find(list.begin(), list.end(), item) == list.end()) { + list.push_back(item); + return true; } + return false; } + +#endif // __CM_LIST_H__ diff --git a/source/gameengine/Common/CM_Map.h b/source/gameengine/Common/CM_Map.h new file mode 100644 index 000000000000..5a46f218909f --- /dev/null +++ b/source/gameengine/Common/CM_Map.h @@ -0,0 +1,70 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file CM_List.h + * \ingroup common + */ + +#ifndef __CM_MAP_H__ +#define __CM_MAP_H__ + +#include +#include + +template +inline const Item CM_MapGetItemNoInsert(const std::map& map, const Key& key, const Item defaultItem = nullptr) +{ + const typename std::map::const_iterator it = map.find(key); + if (it != map.end()) { + return it->second; + } + return defaultItem; +} + +template +inline const Item CM_MapGetItemNoInsert(const std::unordered_map& map, const Key& key, const Item defaultItem = nullptr) +{ + const typename std::map::const_iterator it = map.find(key); + if (it != map.end()) { + return it->second; + } + return defaultItem; +} + +template +inline bool CM_MapRemoveIfItemFound(Map& map, const Item& item) +{ + bool found = false; + for (typename Map::iterator it = map.begin(); it != map.end();) { + if (it->second == item) { + it = map.erase(it); + found = true; + } + else { + ++it; + } + } + + return found; +} + +#endif // __CM_LIST_H__ diff --git a/source/gameengine/Common/CM_Message.cpp b/source/gameengine/Common/CM_Message.cpp new file mode 100644 index 000000000000..57342a535449 --- /dev/null +++ b/source/gameengine/Common/CM_Message.cpp @@ -0,0 +1,139 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Common/CM_Message.cpp + * \ingroup common + */ + +#include "CM_Message.h" +#include "SCA_ILogicBrick.h" + +#include "BLI_path_util.h" + +#include "termcolor.hpp" + +#ifdef WITH_PYTHON + +# include "EXP_Python.h" +extern "C" { +# include "py_capi_utils.h" // for PyC_FileAndNum only +} + +#endif // WITH_PYTHON + +std::ostream& _CM_PrefixWarning(std::ostream& stream) +{ + stream << termcolor::yellow << termcolor::bold << "Warning" << termcolor::reset << ": "; + return stream; +} + +std::ostream& _CM_PrefixError(std::ostream& stream) +{ + stream << termcolor::red << termcolor::bold << "Error" << termcolor::reset << ": "; + return stream; +} + +std::ostream& _CM_PrefixDebug(std::ostream& stream) +{ + stream << termcolor::bold << "Debug" << termcolor::reset << ": "; + return stream; +} + +#ifdef WITH_PYTHON + +std::ostream& _CM_PythonPrefix(std::ostream& stream) +{ + int line; + const char *path; + char file[FILE_MAX]; + PyC_FileAndNum(&path, &line); + if (!path) { + return stream; + } + + BLI_split_file_part(path, file, sizeof(file)); + + stream << termcolor::bold << file << termcolor::reset << "(" << termcolor::bold << line << termcolor::reset << "), "; + return stream; +} + +_CM_PythonAttributPrefix::_CM_PythonAttributPrefix(std::string className, std::string attributName) + :m_className(className), + m_attributName(attributName) +{ +} + +std::ostream& operator<<(std::ostream& stream, const _CM_PythonAttributPrefix& prefix) +{ + stream << termcolor::green << prefix.m_className << termcolor::reset << "." << termcolor::green + << termcolor::bold << prefix.m_attributName << termcolor::reset << ", "; + return stream; +} + +_CM_PythonFunctionPrefix::_CM_PythonFunctionPrefix(std::string className, std::string attributName) + :m_className(className), + m_attributName(attributName) +{ +} + +std::ostream& operator<<(std::ostream& stream, const _CM_PythonFunctionPrefix& prefix) +{ + stream << termcolor::green << prefix.m_className << termcolor::reset << "." << termcolor::green + << termcolor::bold << prefix.m_attributName << termcolor::reset << "(...), "; + return stream; +} + +#endif // WITH_PYTHON + +_CM_LogicBrickPrefix::_CM_LogicBrickPrefix(SCA_ILogicBrick *brick) +{ + m_brickName = brick->GetName(); + if (brick->GetParent()) { + m_objectName = brick->GetParent()->GetName(); + } + else { + m_objectName = "None"; + } +} + +std::ostream& operator<<(std::ostream& stream, const _CM_LogicBrickPrefix& prefix) +{ + stream << termcolor::bold << prefix.m_brickName << termcolor::reset << "(" << termcolor::bold + << prefix.m_objectName << termcolor::reset << "), "; + return stream; +} + +_CM_FunctionPrefix::_CM_FunctionPrefix(std::string functionName) + :m_functionName(functionName) +{ +} + +std::ostream& operator<<(std::ostream& stream, const _CM_FunctionPrefix& prefix) +{ + const std::string& functionName = prefix.m_functionName; + const size_t colons = functionName.find("::"); + const size_t begin = functionName.substr(0, colons).rfind(" ") + 1; + const size_t end = functionName.rfind("(") - begin; + + stream << termcolor::bold << functionName.substr(begin, end) << termcolor::reset << "(...), "; + return stream; +} diff --git a/source/gameengine/Common/CM_Message.h b/source/gameengine/Common/CM_Message.h new file mode 100644 index 000000000000..99cb10b4a3d3 --- /dev/null +++ b/source/gameengine/Common/CM_Message.h @@ -0,0 +1,209 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file CM_Message.h + * \ingroup common + */ + +#ifndef __CM_MESSAGE_H__ +#define __CM_MESSAGE_H__ + +#include +#include + +class SCA_ILogicBrick; + +std::ostream& _CM_PrefixWarning(std::ostream& stream); +std::ostream& _CM_PrefixError(std::ostream& stream); +std::ostream& _CM_PrefixDebug(std::ostream& stream); + +#ifdef WITH_PYTHON + +std::ostream& _CM_PythonPrefix(std::ostream& stream); + +class _CM_PythonAttributPrefix +{ +private: + std::string m_className; + std::string m_attributName; + +public: + _CM_PythonAttributPrefix(std::string className, std::string attributName); + + friend std::ostream& operator<<(std::ostream& stream, const _CM_PythonAttributPrefix& prefix); +}; + +std::ostream& operator<<(std::ostream& stream, const _CM_PythonAttributPrefix& prefix); + +class _CM_PythonFunctionPrefix +{ +private: + std::string m_className; + std::string m_attributName; + +public: + _CM_PythonFunctionPrefix(std::string className, std::string attributName); + + friend std::ostream& operator<<(std::ostream& stream, const _CM_PythonFunctionPrefix& prefix); +}; + +std::ostream& operator<<(std::ostream& stream, const _CM_PythonFunctionPrefix& prefix); + +#endif // WITH_PYTHON + +class _CM_LogicBrickPrefix +{ +private: + std::string m_brickName; + std::string m_objectName; + +public: + _CM_LogicBrickPrefix(SCA_ILogicBrick *brick); + + friend std::ostream& operator<<(std::ostream& stream, const _CM_LogicBrickPrefix& prefix); +}; + +std::ostream& operator<<(std::ostream& stream, const _CM_LogicBrickPrefix& prefix); + +class _CM_FunctionPrefix +{ +private: + std::string m_functionName; + +public: + _CM_FunctionPrefix(std::string functionName); + + friend std::ostream& operator<<(std::ostream& stream, const _CM_FunctionPrefix& prefix); +}; + +std::ostream& operator<<(std::ostream& stream, const _CM_FunctionPrefix& prefix); + +#define CM_Message(msg) std::cout << msg << std::endl; + +/** Format message: + * Warning: msg + */ +#define CM_Warning(msg) std::cout << _CM_PrefixWarning << msg << std::endl; + +/** Format message: + * Error: msg + */ +#define CM_Error(msg) std::cout << _CM_PrefixError << msg << std::endl; + +/** Format message: + * Debug: msg + */ +#define CM_Debug(msg) std::cout << _CM_PrefixDebug << msg << std::endl; + + +#ifdef _MSC_VER +# define CM_FunctionName __FUNCSIG__ +#else +# define CM_FunctionName __PRETTY_FUNCTION__ +#endif + +/** Format message: + * Warning: class::function(...) msg + */ +#define CM_FunctionWarning(msg) std::cout << _CM_PrefixWarning << _CM_FunctionPrefix(CM_FunctionName) << msg << std::endl; + +/** Format message: + * Error: class::function(...) msg + */ +#define CM_FunctionError(msg) std::cout << _CM_PrefixError << _CM_FunctionPrefix(CM_FunctionName) << msg << std::endl; + +/** Format message: + * Debug: class::function(...) msg + */ +#define CM_FunctionDebug(msg) std::cout << _CM_PrefixDebug << _CM_FunctionPrefix(CM_FunctionName) << msg << std::endl; + + +#ifdef WITH_PYTHON + +/** Format message: + * prefix: script(line), msg + */ +#define _CM_PythonMsg(prefix, msg) std::cout << prefix << _CM_PythonPrefix << msg << std::endl; + +/** Format message: + * Warning: script(line), msg + */ +#define CM_PythonWarning(msg) _CM_PythonMsg(_CM_PrefixWarning, msg) + +/** Format message: + * Error: script(line), msg + */ +#define CM_PythonError(msg) _CM_PythonMsg(_CM_PrefixError, msg) + + +/** Format message: + * prefix: script(line), class.attribut, msg + */ +#define _CM_PythonAttributMsg(prefix, class, attribut, msg) \ + std::cout << prefix << _CM_PythonPrefix << _CM_PythonAttributPrefix(class, attribut) << msg << std::endl; + +/** Format message: + * Warning: script(line), class.attribut, msg + */ +#define CM_PythonAttributWarning(class, attribut, msg) _CM_PythonAttributMsg(_CM_PrefixWarning, class, attribut, msg) + +/** Format message: + * Error: script(line), class.attribut, msg + */ +#define CM_PythonAttributError(class, attribut, msg) _CM_PythonAttributMsg(_CM_PrefixError, class, attribut, msg) + + +/** Format message: + * prefix: script(line), class.function(...), msg + */ +#define _CM_PythonFunctionMsg(prefix, class, function, msg) \ + std::cout << prefix << _CM_PythonPrefix << _CM_PythonFunctionPrefix(class, function) << msg << std::endl; + +/** Format message: + * Warning: script(line), class.function(...), msg + */ +#define CM_PythonFunctionWarning(class, function, msg) _CM_PythonFunctionMsg(_CM_PrefixWarning, class, function, msg) + +/** Format message: + * Error: script(line), class.function(...), msg + */ +#define CM_PythonFunctionError(class, function, msg) _CM_PythonFunctionMsg(_CM_PrefixError, class, function, msg) + +#endif // WITH_PYTHON + + +/** Format message: + * prefix: brick(object), msg + */ +#define _CM_LogicBrickMsg(prefix, brick, msg) std::cout << prefix << _CM_LogicBrickPrefix(brick) << msg << std::endl; + +/** Format message: + * Warning: brick(object), msg + */ +#define CM_LogicBrickWarning(brick, msg) _CM_LogicBrickMsg(_CM_PrefixWarning, brick, msg) + +/** Format message: + * Error: brick(object), msg + */ +#define CM_LogicBrickError(brick, msg) _CM_LogicBrickMsg(_CM_PrefixError, brick, msg) + +#endif // __CM_MESSAGE_H__ diff --git a/source/gameengine/Common/CM_RefCount.h b/source/gameengine/Common/CM_RefCount.h new file mode 100644 index 000000000000..a33fb6b246fe --- /dev/null +++ b/source/gameengine/Common/CM_RefCount.h @@ -0,0 +1,102 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file CM_RefCount.h + * \ingroup common + */ + +#ifndef __CM_REFCOUNT_H__ +#define __CM_REFCOUNT_H__ + +#include "BLI_utildefines.h" + +/** \brief Reference counter base class. This class manages the destruction of an object + * based on a reference counter, when the counter is to zero the object is destructed. + */ +template +class CM_RefCount +{ +private: + int m_refCount; + +public: + CM_RefCount() + :m_refCount(1) + { + } + + virtual ~CM_RefCount() + { + } + + CM_RefCount(const CM_RefCount& UNUSED(other)) + { + m_refCount = 1; + } + + /// Increase the reference count of the object. + T *AddRef() + { + BLI_assert(m_refCount > 0); + ++m_refCount; + + return static_cast(this); + } + + /// Decrease the reference count of the object and destruct at zero. + T *Release() + { + BLI_assert(m_refCount > 0); + --m_refCount; + if (m_refCount == 0) { + delete this; + return nullptr; + } + + return static_cast(this); + } + + int GetRefCount() const + { + return m_refCount; + } +}; + +/** Increase the reference count of a object. Used in case of multiple levels + * inheritance in the goal to return the value back. + */ +template +T *CM_AddRef(T *val) +{ + return static_cast(val->AddRef()); +} + +/** Decrease the reference count of a object and destruct at zero. Used in case + * of multiple levels inheritance in the goal to return the value back. + */ +template +T *CM_Release(T *val) +{ + return static_cast(val->Release()); +} + +#endif // __CM_REFCOUNT_H__ diff --git a/source/gameengine/Common/CM_Template.h b/source/gameengine/Common/CM_Template.h new file mode 100644 index 000000000000..cf2c7b338ef3 --- /dev/null +++ b/source/gameengine/Common/CM_Template.h @@ -0,0 +1,34 @@ +#ifndef __CM_TEMPLATE_H__ +#define __CM_TEMPLATE_H__ + +#include +#include + +template class Object, class Tuple, class Key, unsigned int index, class ... Args> +typename std::enable_if::value == index, BaseObject *>::type +_CM_InstantiateTemplateCase(const Key& UNUSED(key), Args ... UNUSED(args)) +{ + return nullptr; +} + +template class Object, class Tuple, class Key, unsigned int index, class ... Args> +typename std::enable_if::value != index, BaseObject *>::type +_CM_InstantiateTemplateCase(const Key& key, Args ... args) +{ + using KeyType = typename std::tuple_element::type; + if (KeyType() == key) { + return (new Object(args ...)); + } + else { + return _CM_InstantiateTemplateCase(key, args ...); + } + return nullptr; +} + +template class Object, class Tuple, class Key, class ... Args> +BaseObject *CM_InstantiateTemplateSwitch(const Key& key, Args ... args) +{ + return _CM_InstantiateTemplateCase(key, args ...); +} + +#endif // __CM_TEMPLATE_H__ diff --git a/source/gameengine/GameLogic/SCA_PropertyEventManager.cpp b/source/gameengine/Common/CM_Thread.cpp similarity index 54% rename from source/gameengine/GameLogic/SCA_PropertyEventManager.cpp rename to source/gameengine/Common/CM_Thread.cpp index 854069690da6..10afd65089d5 100644 --- a/source/gameengine/GameLogic/SCA_PropertyEventManager.cpp +++ b/source/gameengine/Common/CM_Thread.cpp @@ -15,43 +15,61 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. + * Contributor(s): Tristan Porteries. * * ***** END GPL LICENSE BLOCK ***** */ -/** \file gameengine/GameLogic/SCA_PropertyEventManager.cpp - * \ingroup gamelogic +/** \file gameengine/Common/CM_Thread.cpp + * \ingroup common */ +#include "CM_Thread.h" + +CM_ThreadLock::CM_ThreadLock() +{ +} -#include "SCA_ISensor.h" -#include "SCA_PropertyEventManager.h" +CM_ThreadLock::~CM_ThreadLock() +{ +} + +CM_ThreadSpinLock::CM_ThreadSpinLock() +{ + BLI_spin_init(&m_spinlock); +} +CM_ThreadSpinLock::~CM_ThreadSpinLock() +{ + BLI_spin_end(&m_spinlock); +} -SCA_PropertyEventManager::SCA_PropertyEventManager(class SCA_LogicManager* logicmgr) - : SCA_EventManager(logicmgr, PROPERTY_EVENTMGR) +void CM_ThreadSpinLock::Lock() { + BLI_spin_lock(&m_spinlock); } +void CM_ThreadSpinLock::Unlock() +{ + BLI_spin_unlock(&m_spinlock); +} +CM_ThreadMutex::CM_ThreadMutex() +{ + BLI_mutex_init(&m_mutex); +} -SCA_PropertyEventManager::~SCA_PropertyEventManager() +CM_ThreadMutex::~CM_ThreadMutex() { + BLI_mutex_end(&m_mutex); +} +void CM_ThreadMutex::Lock() +{ + BLI_mutex_lock(&m_mutex); } -void SCA_PropertyEventManager::NextFrame() +void CM_ThreadMutex::Unlock() { - // check for changed properties - SG_DList::iterator it(m_sensors); - for (it.begin();!it.end();++it) - { - (*it)->Activate(m_logicmgr); - } + BLI_mutex_unlock(&m_mutex); } diff --git a/intern/moto/include/MT_Stream.h b/source/gameengine/Common/CM_Thread.h similarity index 55% rename from intern/moto/include/MT_Stream.h rename to source/gameengine/Common/CM_Thread.h index 42861e6c0995..e662d08a3216 100644 --- a/intern/moto/include/MT_Stream.h +++ b/source/gameengine/Common/CM_Thread.h @@ -15,45 +15,54 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. + * Contributor(s): Tristan Porteries. * * ***** END GPL LICENSE BLOCK ***** */ -/** \file moto/include/MT_Stream.h - * \ingroup moto +/** \file CM_Thread.h + * \ingroup common */ +#ifndef __CM_THREAD_H__ +#define __CM_THREAD_H__ -#ifndef GEN_STREAM_H -#define GEN_STREAM_H - -#ifdef __CUSTOM_STREAM +#include "BLI_threads.h" -class MT_OStream +class CM_ThreadLock { public: - inline MT_OStream& operator<<(double); - inline MT_OStream& operator<<(int); - inline MT_OStream& operator<<(char*); -}; + CM_ThreadLock(); + virtual ~CM_ThreadLock(); -const char GEN_endl = '\n'; + virtual void Lock() = 0; + virtual void Unlock() = 0; +}; -#else +class CM_ThreadSpinLock : public CM_ThreadLock +{ +public: + CM_ThreadSpinLock(); + virtual ~CM_ThreadSpinLock(); -#include + virtual void Lock(); + virtual void Unlock(); -typedef std::ostream MT_OStream; +private: + SpinLock m_spinlock; +}; -inline MT_OStream& GEN_endl(MT_OStream& os) { return std::endl(os); } +class CM_ThreadMutex : public CM_ThreadLock +{ +public: + CM_ThreadMutex(); + virtual ~CM_ThreadMutex(); -#endif + virtual void Lock(); + virtual void Unlock(); -#endif +private: + ThreadMutex m_mutex; +}; +#endif // __CM_THREAD_H__ diff --git a/source/gameengine/Common/CM_Update.h b/source/gameengine/Common/CM_Update.h new file mode 100644 index 000000000000..d99fb7e2aa95 --- /dev/null +++ b/source/gameengine/Common/CM_Update.h @@ -0,0 +1,107 @@ +#ifndef __CM_UPDATE_H__ +#define __CM_UPDATE_H__ + +#include "CM_List.h" + +#include + +template +class CM_UpdateServer; + +template +class CM_UpdateClient +{ +friend class CM_UpdateServer; + +private: + unsigned int m_invalid; + unsigned int m_filter; + CM_UpdateServer *m_server; + +public: + CM_UpdateClient(unsigned int filter, unsigned int invalid) + :m_invalid(invalid), + m_filter(filter), + m_server(nullptr) + { + } + + CM_UpdateClient(unsigned int filter) + :CM_UpdateClient(filter, false) + { + } + + ~CM_UpdateClient() + { + if (m_server) { + m_server->RemoveUpdateClient(this); + } + } + + unsigned int GetInvalid() const + { + return m_invalid; + } + + void ClearInvalid() + { + m_invalid = 0; + } + + unsigned int GetInvalidAndClear() + { + const unsigned int invalid = m_invalid; + m_invalid = 0; + return invalid; + } +}; + +template +class CM_UpdateServer +{ +public: + using ClientType = CM_UpdateClient; + +private: + std::vector m_clients; + +public: + CM_UpdateServer() = default; + virtual ~CM_UpdateServer() + { + for (ClientType *client : m_clients) { + client->m_server = nullptr; + } + } + + void MoveUpdateClient(ClientType *client, unsigned int invalid) + { + if (client->m_server) { + client->m_server->RemoveUpdateClient(client); + } + + client->m_invalid |= invalid; + AddUpdateClient(client); + } + + void AddUpdateClient(ClientType *client) + { + m_clients.push_back(client); + client->m_server = this; + } + + void RemoveUpdateClient(ClientType *client) + { + CM_ListRemoveIfFound(m_clients, client); + client->m_server = nullptr; + } + + void NotifyUpdate(unsigned int flag) + { + for (ClientType *client : m_clients) { + client->m_invalid |= (flag & client->m_filter); + } + } +}; + +#endif // __CM_UPDATE_H__ diff --git a/source/gameengine/Network/CMakeLists.txt b/source/gameengine/Common/CMakeLists.txt similarity index 69% rename from source/gameengine/Network/CMakeLists.txt rename to source/gameengine/Common/CMakeLists.txt index 019fc3e6032d..13f165b8a85b 100644 --- a/source/gameengine/Network/CMakeLists.txt +++ b/source/gameengine/Common/CMakeLists.txt @@ -19,30 +19,41 @@ # # The Original Code is: all of this file. # -# Contributor(s): Jacques Beaurain. +# Contributor(s): Tristan Porteries. # # ***** END GPL LICENSE BLOCK ***** set(INC . - ../../../intern/container - ../../../intern/string + ../Expressions + ../GameLogic + ../SceneGraph ../../blender/blenlib + ../../blender/python/generic + ../../../intern/guardedalloc + ../../../intern/string + ../../../intern/termcolor ) set(INC_SYS - ../../../intern/moto/include + ../../../intern/debugbreak + ../../../intern/mathfu ) set(SRC - NG_NetworkMessage.cpp - NG_NetworkObject.cpp - NG_NetworkScene.cpp + CM_Clock.cpp + CM_Message.cpp + CM_Thread.cpp - NG_NetworkDeviceInterface.h - NG_NetworkMessage.h - NG_NetworkObject.h - NG_NetworkScene.h + CM_Clock.h + CM_Format.h + CM_List.h + CM_Map.h + CM_Message.h + CM_RefCount.h + CM_Template.h + CM_Thread.h + CM_Update.h ) -blender_add_lib(ge_logic_ngnetwork "${SRC}" "${INC}" "${INC_SYS}") +blender_add_lib(ge_common "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/gameengine/Converter/BL_ActionActuator.cpp b/source/gameengine/Converter/BL_ActionActuator.cpp index 558fd6cd2b55..2fe5398cbbef 100644 --- a/source/gameengine/Converter/BL_ActionActuator.cpp +++ b/source/gameengine/Converter/BL_ActionActuator.cpp @@ -34,10 +34,10 @@ #include "BL_ActionActuator.h" #include "BL_ArmatureObject.h" #include "BL_SkinDeformer.h" -#include "BL_Action.h" #include "BL_ActionManager.h" #include "KX_GameObject.h" -#include "STR_HashedString.h" +#include "KX_Globals.h" +#include #include "MEM_guardedalloc.h" #include "DNA_nla_types.h" #include "DNA_action_types.h" @@ -46,7 +46,6 @@ #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_utildefines.h" -#include "MT_Matrix4x4.h" #include "BKE_action.h" #include "EXP_FloatValue.h" @@ -61,45 +60,38 @@ extern "C" { } BL_ActionActuator::BL_ActionActuator(SCA_IObject *gameobj, - const STR_String& propname, - const STR_String& framepropname, - float starttime, - float endtime, - struct bAction *action, - short playtype, - short blend_mode, - short blendin, - short priority, - short layer, - float layer_weight, - short ipo_flags, - short end_reset, - float stride) - : SCA_IActuator(gameobj, KX_ACT_ACTION), - - m_lastpos(0, 0, 0), - m_blendframe(0), + const std::string& propname, + const std::string& framepropname, + float starttime, + float endtime, + const std::string& actionName, + short playtype, + short blend_mode, + short blendin, + short priority, + short layer, + float layer_weight, + short ipo_flags, + short end_reset) + :SCA_IActuator(gameobj, KX_ACT_ACTION), m_flag(0), - m_startframe (starttime), - m_endframe(endtime) , - m_starttime(0), + m_startframe(starttime), + m_endframe(endtime), m_localtime(starttime), - m_lastUpdate(-1), m_blendin(blendin), - m_blendstart(0), - m_stridelength(stride), m_layer_weight(layer_weight), m_playtype(playtype), m_blendmode(blend_mode), m_priority(priority), m_layer(layer), m_ipo_flags(ipo_flags), - m_action(action), + m_actionName(actionName), m_propname(propname), m_framepropname(framepropname) { - if (!end_reset) + if (!end_reset) { m_flag |= ACT_FLAG_CONTINUE; + } }; BL_ActionActuator::~BL_ActionActuator() @@ -110,195 +102,135 @@ void BL_ActionActuator::ProcessReplica() { SCA_IActuator::ProcessReplica(); - m_localtime=m_startframe; - m_lastUpdate=-1; - -} - -void BL_ActionActuator::SetBlendTime(float newtime) -{ - m_blendframe = newtime; -} - -void BL_ActionActuator::SetLocalTime(float curtime) -{ - float dt = (curtime-m_starttime)*KX_KetsjiEngine::GetAnimFrameRate(); - - if (m_endframe < m_startframe) - dt = -dt; - - m_localtime = m_startframe + dt; - - // Handle wrap around - if (m_localtime < min(m_startframe, m_endframe) || m_localtime > max(m_startframe, m_endframe)) - { - switch (m_playtype) { - case ACT_ACTION_PLAY: - // Clamp - m_localtime = m_endframe; - break; - case ACT_ACTION_LOOP_END: - // Put the time back to the beginning - m_localtime = m_startframe; - m_starttime = curtime; - break; - case ACT_ACTION_PINGPONG: - // Swap the start and end frames - float temp = m_startframe; - m_startframe = m_endframe; - m_endframe = temp; - - m_starttime = curtime; - - m_flag ^= ACT_FLAG_REVERSE; - - break; - } - } -} - -void BL_ActionActuator::ResetStartTime(float curtime) -{ - float dt = m_localtime - m_startframe; - - m_starttime = curtime - dt / (KX_KetsjiEngine::GetAnimFrameRate()); - //SetLocalTime(curtime); + m_flag = m_flag & ACT_FLAG_CONTINUE; + m_localtime = m_startframe; } -CValue* BL_ActionActuator::GetReplica() +EXP_Value *BL_ActionActuator::GetReplica() { - BL_ActionActuator* replica = new BL_ActionActuator(*this);//m_float,GetName()); + BL_ActionActuator *replica = new BL_ActionActuator(*this);//m_float,GetName()); replica->ProcessReplica(); return replica; } -bool BL_ActionActuator::Update(double curtime, bool frame) +bool BL_ActionActuator::Update(double curtime) { - bool bNegativeEvent = false; - bool bPositiveEvent = false; - bool bUseContinue = false; - KX_GameObject *obj = (KX_GameObject*)GetParent(); + KX_GameObject *obj = (KX_GameObject *)GetParent(); short playtype = BL_Action::ACT_MODE_PLAY; - short blendmode = (m_blendmode == ACT_ACTION_ADD) ? BL_Action::ACT_BLEND_ADD : BL_Action::ACT_BLEND_BLEND; float start = m_startframe; float end = m_endframe; // If we don't have an action, we can't do anything - if (!m_action) + if (m_actionName.empty()) { return false; + } // Convert our playtype to one that BL_Action likes switch (m_playtype) { case ACT_ACTION_LOOP_END: case ACT_ACTION_LOOP_STOP: + { playtype = BL_Action::ACT_MODE_LOOP; break; - + } case ACT_ACTION_PINGPONG: - // We handle ping pong ourselves to increase compabitility - // with files made prior to animation changes from GSoC 2011. - playtype = BL_Action::ACT_MODE_PLAY; - - if (m_flag & ACT_FLAG_REVERSE) - { - start = m_endframe; - end = m_startframe; - } - - break; - case ACT_ACTION_FROM_PROP: - CValue* prop = GetParent()->GetProperty(m_propname); - - // If we don't have a property, we can't do anything, so just bail - if (!prop) return false; - - playtype = BL_Action::ACT_MODE_PLAY; - start = end = prop->GetNumber(); - + { + playtype = BL_Action::ACT_MODE_PING_PONG; break; + } } - if (m_flag & ACT_FLAG_CONTINUE) - bUseContinue = true; - + const bool useContinue = (m_flag & ACT_FLAG_CONTINUE); // Handle events - if (frame) - { - bNegativeEvent = m_negevent; - bPositiveEvent = m_posevent; - RemoveAllEvents(); - } + const bool negativeEvent = m_negevent; + const bool positiveEvent = m_posevent; + RemoveAllEvents(); - // "Active" actions need to keep updating their current frame - if (bUseContinue && (m_flag & ACT_FLAG_ACTIVE)) + if (m_flag & ACT_FLAG_ACTIVE) { + // "Active" actions need to keep updating their current frame m_localtime = obj->GetActionFrame(m_layer); - if (m_flag & ACT_FLAG_ATTEMPT_PLAY) - SetLocalTime(curtime); - else - ResetStartTime(curtime); - - // Handle a frame property if it's defined - if ((m_flag & ACT_FLAG_ACTIVE) && m_framepropname[0] != 0) - { - CValue* oldprop = obj->GetProperty(m_framepropname); - CValue* newval = new CFloatValue(obj->GetActionFrame(m_layer)); - if (oldprop) - oldprop->SetValue(newval); - else - obj->SetProperty(m_framepropname, newval); - - newval->Release(); + // Handle a frame property if it's defined + if (!m_framepropname.empty()) { + EXP_Value *oldprop = obj->GetProperty(m_framepropname); + EXP_Value *newval = new EXP_FloatValue(obj->GetActionFrame(m_layer)); + if (oldprop) { + oldprop->SetValue(newval); + } + else { + obj->SetProperty(m_framepropname, newval); + } + + newval->Release(); + } } // Handle a finished animation - if ((m_flag & ACT_FLAG_PLAY_END) && (m_flag & ACT_FLAG_ACTIVE) && obj->IsActionDone(m_layer)) - { + if ((m_flag & ACT_FLAG_PLAY_END) && (m_flag & ACT_FLAG_ACTIVE) && obj->IsActionDone(m_layer)) { m_flag &= ~ACT_FLAG_ACTIVE; - - if (m_playtype == ACT_ACTION_PINGPONG) { - m_flag ^= ACT_FLAG_REVERSE; - } - else { - m_flag &= ~ACT_FLAG_ATTEMPT_PLAY; - return false; - } + m_flag &= ~ACT_FLAG_PLAY_END; + return false; } // If a different action is playing, we've been overruled and are no longer active - if (obj->GetCurrentAction(m_layer) != m_action && !obj->IsActionDone(m_layer)) + if (obj->GetCurrentActionName(m_layer) != m_actionName && !obj->IsActionDone(m_layer)) { m_flag &= ~ACT_FLAG_ACTIVE; + } - if (bPositiveEvent || (m_flag & ACT_FLAG_ATTEMPT_PLAY && !(m_flag & ACT_FLAG_ACTIVE))) - { - if (bPositiveEvent && m_playtype == ACT_ACTION_PLAY) - { - if (obj->IsActionDone(m_layer)) - m_localtime = start; - ResetStartTime(curtime); - } - - if (obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, m_blendin, playtype, m_layer_weight, m_ipo_flags, 1.f, blendmode)) - { - m_flag |= ACT_FLAG_ACTIVE; - if (bUseContinue) - obj->SetActionFrame(m_layer, m_localtime); - - if (m_playtype == ACT_ACTION_PLAY || m_playtype == ACT_ACTION_PINGPONG) - m_flag |= ACT_FLAG_PLAY_END; - else - m_flag &= ~ACT_FLAG_PLAY_END; + if (positiveEvent) { + switch (m_playtype) { + case ACT_ACTION_PLAY: + { + if (!(m_flag & ACT_FLAG_ACTIVE)) { + m_localtime = start; + m_flag |= ACT_FLAG_PLAY_END; + } + ATTR_FALLTHROUGH; + } + case ACT_ACTION_LOOP_END: + case ACT_ACTION_LOOP_STOP: + case ACT_ACTION_PINGPONG: + { + if (!(m_flag & ACT_FLAG_ACTIVE) && Play(obj, start, end, playtype)) { + m_flag |= ACT_FLAG_ACTIVE; + if (useContinue) { + obj->SetActionFrame(m_layer, m_localtime); + } + } + break; + } + case ACT_ACTION_FROM_PROP: + { + EXP_Value *prop = GetParent()->GetProperty(m_propname); + // If we don't have a property, we can't do anything, so just bail + if (!prop) { + return false; + } + + const float frame = prop->GetNumber(); + if (Play(obj, frame, frame, playtype)) { + m_flag |= ACT_FLAG_ACTIVE; + } + break; + } + case ACT_ACTION_FLIPPER: + { + if ((!(m_flag & ACT_FLAG_ACTIVE) || m_flag & ACT_FLAG_PLAY_END) && Play(obj, start, end, playtype)) { + m_flag |= ACT_FLAG_ACTIVE; + m_flag &= ~ACT_FLAG_PLAY_END; + if (useContinue) { + obj->SetActionFrame(m_layer, m_localtime); + } + } + break; + } } - m_flag |= ACT_FLAG_ATTEMPT_PLAY; } - else if ((m_flag & ACT_FLAG_ACTIVE) && bNegativeEvent) - { - m_flag &= ~ACT_FLAG_ATTEMPT_PLAY; + else if ((m_flag & ACT_FLAG_ACTIVE) && negativeEvent) { m_localtime = obj->GetActionFrame(m_layer); - bAction *curr_action = obj->GetCurrentAction(m_layer); - if (curr_action && curr_action != m_action) - { + const std::string curr_action = obj->GetCurrentActionName(m_layer); + if (!curr_action.empty() && curr_action != m_actionName) { // Someone changed the action on us, so we wont mess with it // Hopefully there wont be too many problems with two actuators using // the same action... @@ -309,27 +241,32 @@ bool BL_ActionActuator::Update(double curtime, bool frame) switch (m_playtype) { case ACT_ACTION_FROM_PROP: case ACT_ACTION_LOOP_STOP: + { obj->StopAction(m_layer); // Stop the action after getting the frame // We're done m_flag &= ~ACT_FLAG_ACTIVE; return false; + } case ACT_ACTION_LOOP_END: + { // Convert into a play and let it finish obj->SetPlayMode(m_layer, BL_Action::ACT_MODE_PLAY); m_flag |= ACT_FLAG_PLAY_END; break; + } case ACT_ACTION_FLIPPER: + { // Convert into a play action and play back to the beginning float temp = end; end = start; - start = curr_action ? obj->GetActionFrame(m_layer) : temp; - obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, 0, BL_Action::ACT_MODE_PLAY, m_layer_weight, m_ipo_flags, 1.f, blendmode); - + start = curr_action.empty() ? temp : obj->GetActionFrame(m_layer); + Play(obj, start, end, BL_Action::ACT_MODE_PLAY); m_flag |= ACT_FLAG_PLAY_END; break; + } } } @@ -347,180 +284,22 @@ void BL_ActionActuator::DecLink() } } -#ifdef WITH_PYTHON - -/* ------------------------------------------------------------------------- */ -/* Python functions */ -/* ------------------------------------------------------------------------- */ - -PyObject *BL_ActionActuator::PyGetChannel(PyObject *value) +bool BL_ActionActuator::Play(KX_GameObject *obj, float start, float end, short mode) { - PyErr_SetString(PyExc_NotImplementedError, "BL_ActionActuator.getChannel() no longer works, please use BL_ArmatureObject.channels instead"); - return NULL; -#if 0 // XXX To be removed in a later version (first removed in 2.64) - const char *string= _PyUnicode_AsString(value); - - if (GetParent()->GetGameObjectType() != SCA_IObject::OBJ_ARMATURE) - { - PyErr_SetString(PyExc_NotImplementedError, "actuator.getChannel(): Only armatures support channels"); - return NULL; - } - - if (!string) { - PyErr_SetString(PyExc_TypeError, "expected a single string"); - return NULL; - } - - bPoseChannel *pchan; - - if (m_userpose==NULL && m_pose==NULL) { - BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent(); - obj->GetPose(&m_pose); /* Get the underlying pose from the armature */ - } - - // BKE_pose_channel_find_name accounts for NULL pose, run on both in case one exists but - // the channel doesnt - if ( !(pchan=BKE_pose_channel_find_name(m_userpose, string)) && - !(pchan=BKE_pose_channel_find_name(m_pose, string)) ) - { - PyErr_SetString(PyExc_ValueError, "channel doesnt exist"); - return NULL; - } - - PyObject *ret = PyTuple_New(3); - - PyObject *list = PyList_New(3); - PyList_SET_ITEM(list, 0, PyFloat_FromDouble(pchan->loc[0])); - PyList_SET_ITEM(list, 1, PyFloat_FromDouble(pchan->loc[1])); - PyList_SET_ITEM(list, 2, PyFloat_FromDouble(pchan->loc[2])); - PyTuple_SET_ITEM(ret, 0, list); - - list = PyList_New(3); - PyList_SET_ITEM(list, 0, PyFloat_FromDouble(pchan->size[0])); - PyList_SET_ITEM(list, 1, PyFloat_FromDouble(pchan->size[1])); - PyList_SET_ITEM(list, 2, PyFloat_FromDouble(pchan->size[2])); - PyTuple_SET_ITEM(ret, 1, list); - - list = PyList_New(4); - PyList_SET_ITEM(list, 0, PyFloat_FromDouble(pchan->quat[0])); - PyList_SET_ITEM(list, 1, PyFloat_FromDouble(pchan->quat[1])); - PyList_SET_ITEM(list, 2, PyFloat_FromDouble(pchan->quat[2])); - PyList_SET_ITEM(list, 3, PyFloat_FromDouble(pchan->quat[3])); - PyTuple_SET_ITEM(ret, 2, list); - - return ret; -#if 0 - return Py_BuildValue("([fff][fff][ffff])", - pchan->loc[0], pchan->loc[1], pchan->loc[2], - pchan->size[0], pchan->size[1], pchan->size[2], - pchan->quat[0], pchan->quat[1], pchan->quat[2], pchan->quat[3] ); -#endif -#endif + const short blendmode = (m_blendmode == ACT_ACTION_ADD) ? BL_Action::ACT_BLEND_ADD : BL_Action::ACT_BLEND_BLEND; + return obj->PlayAction(m_actionName, start, end, m_layer, m_priority, m_blendin, mode, m_layer_weight, m_ipo_flags, 1.0f, blendmode); } -/* setChannel */ -KX_PYMETHODDEF_DOC(BL_ActionActuator, setChannel, -"setChannel(channel, matrix)\n" -"\t - channel : A string specifying the name of the bone channel.\n" -"\t - matrix : A 4x4 matrix specifying the overriding transformation\n" -"\t as an offset from the bone's rest position.\n") -{ - PyErr_SetString(PyExc_NotImplementedError, "BL_ActionActuator.setChannel() no longer works, please use BL_ArmatureObject.channels instead"); - return NULL; - -#if 0 // XXX To be removed in a later version (first removed in 2.64) - BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent(); - char *string; - PyObject *pymat= NULL; - PyObject *pyloc= NULL, *pysize= NULL, *pyquat= NULL; - bPoseChannel *pchan; - - if (GetParent()->GetGameObjectType() != SCA_IObject::OBJ_ARMATURE) - { - PyErr_SetString(PyExc_NotImplementedError, "actuator.setChannel(): Only armatures support channels"); - return NULL; - } - - if (PyTuple_Size(args)==2) { - if (!PyArg_ParseTuple(args,"sO:setChannel", &string, &pymat)) // matrix - return NULL; - } - else if (PyTuple_Size(args)==4) { - if (!PyArg_ParseTuple(args,"sOOO:setChannel", &string, &pyloc, &pysize, &pyquat)) // loc/size/quat - return NULL; - } - else { - PyErr_SetString(PyExc_ValueError, "Expected a string and a 4x4 matrix (2 args) or a string and loc/size/quat sequences (4 args)"); - return NULL; - } - - if (pymat) { - float matrix[4][4]; - MT_Matrix4x4 mat; - - if (!PyMatTo(pymat, mat)) - return NULL; - - mat.getValue((float*)matrix); - - BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent(); - - if (!m_userpose) { - if (!m_pose) - obj->GetPose(&m_pose); /* Get the underlying pose from the armature */ - game_copy_pose(&m_userpose, m_pose, 0); - } - // pchan= BKE_pose_channel_verify(m_userpose, string); // adds the channel if its not there. - pchan= BKE_pose_channel_find_name(m_userpose, string); // adds the channel if its not there. - - if (pchan) { - copy_v3_v3(pchan->loc, matrix[3]); - mat4_to_size(pchan->size, matrix); - mat4_to_quat(pchan->quat, matrix); - } - } - else { - MT_Vector3 loc; - MT_Vector3 size; - MT_Quaternion quat; - - if (!PyVecTo(pyloc, loc) || !PyVecTo(pysize, size) || !PyQuatTo(pyquat, quat)) - return NULL; - - // same as above - if (!m_userpose) { - if (!m_pose) - obj->GetPose(&m_pose); /* Get the underlying pose from the armature */ - game_copy_pose(&m_userpose, m_pose, 0); - } - // pchan= BKE_pose_channel_verify(m_userpose, string); - pchan= BKE_pose_channel_find_name(m_userpose, string); // adds the channel if its not there. - - // for some reason loc.setValue(pchan->loc) fails - if (pchan) { - pchan->loc[0] = loc[0]; pchan->loc[1] = loc[1]; pchan->loc[2] = loc[2]; - pchan->size[0] = size[0]; pchan->size[1] = size[1]; pchan->size[2] = size[2]; - pchan->quat[0] = quat[3]; pchan->quat[1] = quat[0]; pchan->quat[2] = quat[1]; pchan->quat[3] = quat[2]; /* notice xyzw -> wxyz is intentional */ - } - } - - if (pchan==NULL) { - PyErr_SetString(PyExc_ValueError, "Channel could not be found, use the 'channelNames' attribute to get a list of valid channels"); - return NULL; - } - - Py_RETURN_NONE; -#endif -} +#ifdef WITH_PYTHON /* ------------------------------------------------------------------------- */ /* Python Integration Hooks */ /* ------------------------------------------------------------------------- */ PyTypeObject BL_ActionActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "BL_ActionActuator", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -528,135 +307,97 @@ PyTypeObject BL_ActionActuator::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IActuator::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef BL_ActionActuator::Methods[] = { - {"getChannel", (PyCFunction) BL_ActionActuator::sPyGetChannel, METH_O}, - KX_PYMETHODTABLE(BL_ActionActuator, setChannel), - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef BL_ActionActuator::Attributes[] = { - KX_PYATTRIBUTE_FLOAT_RW("frameStart", 0, MAXFRAMEF, BL_ActionActuator, m_startframe), - KX_PYATTRIBUTE_FLOAT_RW("frameEnd", 0, MAXFRAMEF, BL_ActionActuator, m_endframe), - KX_PYATTRIBUTE_FLOAT_RW("blendIn", 0, MAXFRAMEF, BL_ActionActuator, m_blendin), - KX_PYATTRIBUTE_RW_FUNCTION("action", BL_ActionActuator, pyattr_get_action, pyattr_set_action), - KX_PYATTRIBUTE_RO_FUNCTION("channelNames", BL_ActionActuator, pyattr_get_channel_names), - KX_PYATTRIBUTE_SHORT_RW("priority", 0, 100, false, BL_ActionActuator, m_priority), - KX_PYATTRIBUTE_SHORT_RW("layer", 0, MAX_ACTION_LAYERS-1, true, BL_ActionActuator, m_layer), - KX_PYATTRIBUTE_FLOAT_RW("layerWeight", 0, 1.0, BL_ActionActuator, m_layer_weight), - KX_PYATTRIBUTE_RW_FUNCTION("frame", BL_ActionActuator, pyattr_get_frame, pyattr_set_frame), - KX_PYATTRIBUTE_STRING_RW("propName", 0, MAX_PROP_NAME, false, BL_ActionActuator, m_propname), - KX_PYATTRIBUTE_STRING_RW("framePropName", 0, MAX_PROP_NAME, false, BL_ActionActuator, m_framepropname), - KX_PYATTRIBUTE_RW_FUNCTION("useContinue", BL_ActionActuator, pyattr_get_use_continue, pyattr_set_use_continue), - KX_PYATTRIBUTE_FLOAT_RW_CHECK("blendTime", 0, MAXFRAMEF, BL_ActionActuator, m_blendframe, CheckBlendTime), - KX_PYATTRIBUTE_SHORT_RW_CHECK("mode",0,100,false,BL_ActionActuator,m_playtype,CheckType), - { NULL } //Sentinel + EXP_PYATTRIBUTE_FLOAT_RW("frameStart", 0, MAXFRAMEF, BL_ActionActuator, m_startframe), + EXP_PYATTRIBUTE_FLOAT_RW("frameEnd", 0, MAXFRAMEF, BL_ActionActuator, m_endframe), + EXP_PYATTRIBUTE_FLOAT_RW("blendIn", 0, MAXFRAMEF, BL_ActionActuator, m_blendin), + EXP_PYATTRIBUTE_RW_FUNCTION("action", BL_ActionActuator, pyattr_get_action, pyattr_set_action), + EXP_PYATTRIBUTE_SHORT_RW("priority", 0, 100, false, BL_ActionActuator, m_priority), + EXP_PYATTRIBUTE_SHORT_RW("layer", 0, MAX_ACTION_LAYERS - 1, true, BL_ActionActuator, m_layer), + EXP_PYATTRIBUTE_FLOAT_RW("layerWeight", 0, 1.0, BL_ActionActuator, m_layer_weight), + EXP_PYATTRIBUTE_RW_FUNCTION("frame", BL_ActionActuator, pyattr_get_frame, pyattr_set_frame), + EXP_PYATTRIBUTE_STRING_RW("propName", 0, MAX_PROP_NAME, false, BL_ActionActuator, m_propname), + EXP_PYATTRIBUTE_STRING_RW("framePropName", 0, MAX_PROP_NAME, false, BL_ActionActuator, m_framepropname), + EXP_PYATTRIBUTE_RW_FUNCTION("useContinue", BL_ActionActuator, pyattr_get_use_continue, pyattr_set_use_continue), + EXP_PYATTRIBUTE_SHORT_RW_CHECK("mode", 0, 100, false, BL_ActionActuator, m_playtype, CheckType), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *BL_ActionActuator::pyattr_get_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *BL_ActionActuator::pyattr_get_action(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - BL_ActionActuator* self = static_cast(self_v); - return PyUnicode_FromString(self->GetAction() ? self->GetAction()->id.name+2 : ""); + BL_ActionActuator *self = static_cast(self_v); + return PyUnicode_FromStdString(self->m_actionName); } -int BL_ActionActuator::pyattr_set_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int BL_ActionActuator::pyattr_set_action(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - BL_ActionActuator* self = static_cast(self_v); + BL_ActionActuator *self = static_cast(self_v); - if (!PyUnicode_Check(value)) - { + if (!PyUnicode_Check(value)) { PyErr_SetString(PyExc_ValueError, "actuator.action = val: Action Actuator, expected the string name of the action"); return PY_SET_ATTR_FAIL; } - bAction *action= NULL; - STR_String val = _PyUnicode_AsString(value); + std::string val = _PyUnicode_AsString(value); - if (val != "") - { - action= (bAction*)self->GetLogicManager()->GetActionByName(val); - if (!action) - { + if (!val.empty()) { + if (!self->GetLogicManager()->GetActionByName(val)) { PyErr_SetString(PyExc_ValueError, "actuator.action = val: Action Actuator, action not found!"); return PY_SET_ATTR_FAIL; } } - self->SetAction(action); + self->m_actionName = val; return PY_SET_ATTR_SUCCESS; } -PyObject *BL_ActionActuator::pyattr_get_channel_names(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - PyErr_SetString(PyExc_NotImplementedError, "BL_ActionActuator.channelNames no longer works, please use BL_ArmatureObject.channels instead"); - return NULL; - -#if 0 // XXX To be removed in a later version (first removed in 2.64) - BL_ActionActuator* self = static_cast(self_v); - PyObject *ret= PyList_New(0); - PyObject *item; - - if (self->GetParent()->GetGameObjectType() != SCA_IObject::OBJ_ARMATURE) - { - PyErr_SetString(PyExc_NotImplementedError, "actuator.channelNames: Only armatures support channels"); - return NULL; - } - - bPose *pose= ((BL_ArmatureObject*)self->GetParent())->GetOrigPose(); - - if (pose) { - bPoseChannel *pchan; - for (pchan= (bPoseChannel *)pose->chanbase.first; pchan; pchan= (bPoseChannel *)pchan->next) { - item= PyUnicode_FromString(pchan->name); - PyList_Append(ret, item); - Py_DECREF(item); - } - } - - return ret; -#endif -} - -PyObject *BL_ActionActuator::pyattr_get_use_continue(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *BL_ActionActuator::pyattr_get_use_continue(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - BL_ActionActuator* self = static_cast(self_v); + BL_ActionActuator *self = static_cast(self_v); return PyBool_FromLong(self->m_flag & ACT_FLAG_CONTINUE); } -int BL_ActionActuator::pyattr_set_use_continue(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int BL_ActionActuator::pyattr_set_use_continue(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - BL_ActionActuator* self = static_cast(self_v); + BL_ActionActuator *self = static_cast(self_v); - if (PyObject_IsTrue(value)) + if (PyObject_IsTrue(value)) { self->m_flag |= ACT_FLAG_CONTINUE; - else + } + else { self->m_flag &= ~ACT_FLAG_CONTINUE; + } return PY_SET_ATTR_SUCCESS; } -PyObject *BL_ActionActuator::pyattr_get_frame(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *BL_ActionActuator::pyattr_get_frame(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - BL_ActionActuator* self = static_cast(self_v); - return PyFloat_FromDouble(((KX_GameObject*)self->m_gameobj)->GetActionFrame(self->m_layer)); + BL_ActionActuator *self = static_cast(self_v); + return PyFloat_FromDouble(((KX_GameObject *)self->m_gameobj)->GetActionFrame(self->m_layer)); } -int BL_ActionActuator::pyattr_set_frame(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int BL_ActionActuator::pyattr_set_frame(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - BL_ActionActuator* self = static_cast(self_v); + BL_ActionActuator *self = static_cast(self_v); - ((KX_GameObject*)self->m_gameobj)->SetActionFrame(self->m_layer, PyFloat_AsDouble(value)); + ((KX_GameObject *)self->m_gameobj)->SetActionFrame(self->m_layer, PyFloat_AsDouble(value)); return PY_SET_ATTR_SUCCESS; } diff --git a/source/gameengine/Converter/BL_ActionActuator.h b/source/gameengine/Converter/BL_ActionActuator.h index 034e0b4ab5bd..0c6d75d33326 100644 --- a/source/gameengine/Converter/BL_ActionActuator.h +++ b/source/gameengine/Converter/BL_ActionActuator.h @@ -32,21 +32,20 @@ #ifndef __BL_ACTIONACTUATOR_H__ #define __BL_ACTIONACTUATOR_H__ -#include "CTR_HashedPtr.h" #include "SCA_IActuator.h" #include "DNA_actuator_types.h" -#include "MT_Point3.h" +#include "BL_Action.h" // For BL_Action::PlayMode. -class BL_ActionActuator : public SCA_IActuator +class BL_ActionActuator : public SCA_IActuator { public: Py_Header BL_ActionActuator(SCA_IObject* gameobj, - const STR_String& propname, - const STR_String& framepropname, + const std::string& propname, + const std::string& framepropname, float starttime, float endtime, - struct bAction *action, + const std::string& actionName, short playtype, short blend_mode, short blendin, @@ -54,47 +53,30 @@ class BL_ActionActuator : public SCA_IActuator short layer, float layer_weight, short ipo_flags, - short end_reset, - float stride); + short end_reset); virtual ~BL_ActionActuator(); - virtual bool Update(double curtime, bool frame); - virtual CValue* GetReplica(); + virtual bool Update(double curtime); + virtual EXP_Value* GetReplica(); virtual void ProcessReplica(); - - void SetBlendTime(float newtime); + void SetLocalTime(float curtime); void ResetStartTime(float curtime); - - bAction* GetAction() { return m_action; } - void SetAction(bAction* act) { m_action= act; } - + virtual void DecLink(); -#ifdef WITH_PYTHON - - KX_PYMETHOD_O(BL_ActionActuator,GetChannel) - KX_PYMETHOD_DOC(BL_ActionActuator,setChannel) - - static PyObject* pyattr_get_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_channel_names(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_use_continue(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_use_continue(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_frame(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_frame(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - - static int CheckBlendTime(void *self, const PyAttributeDef*) - { - BL_ActionActuator* act = reinterpret_cast(self); + bool Play(KX_GameObject *obj, float start, float end, short mode); - if (act->m_blendframe > act->m_blendin) - act->m_blendframe = act->m_blendin; +#ifdef WITH_PYTHON - return 0; - } + static PyObject* pyattr_get_action(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_action(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_use_continue(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_use_continue(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_frame(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_frame(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int CheckType(void *self, const PyAttributeDef*) + static int CheckType(EXP_PyObjectPlus *self, const PyAttributeDef*) { BL_ActionActuator* act = reinterpret_cast(self); @@ -112,46 +94,33 @@ class BL_ActionActuator : public SCA_IActuator } } #endif /* WITH_PYTHON */ - + protected: - MT_Point3 m_lastpos; - float m_blendframe; int m_flag; /** The frame this action starts */ float m_startframe; /** The frame this action ends */ float m_endframe; - /** The time this action started */ - float m_starttime; /** The current time of the action */ float m_localtime; - - float m_lastUpdate; float m_blendin; float m_blendstart; - float m_stridelength; float m_layer_weight; short m_playtype; short m_blendmode; short m_priority; short m_layer; short m_ipo_flags; - struct bAction *m_action; - STR_String m_propname; - STR_String m_framepropname; + std::string m_actionName; + std::string m_propname; + std::string m_framepropname; }; -// Not all of these values are used in BL_ActionActuator anymore, -// but BL_ShapeActionActuator still uses them, so we keep them around -// for now. enum { - ACT_FLAG_REVERSE = 1<<0, - ACT_FLAG_LOCKINPUT = 1<<1, - ACT_FLAG_KEYUP = 1<<2, - ACT_FLAG_ACTIVE = 1<<3, - ACT_FLAG_CONTINUE = 1<<4, - ACT_FLAG_PLAY_END = 1<<5, - ACT_FLAG_ATTEMPT_PLAY = 1<<6, + ACT_FLAG_ACTIVE = 1<<1, + ACT_FLAG_CONTINUE = 1<<2, + ACT_FLAG_PLAY_END = 1<<3, }; #endif + diff --git a/source/gameengine/Converter/BL_ActionData.cpp b/source/gameengine/Converter/BL_ActionData.cpp new file mode 100644 index 000000000000..500bb2c436a4 --- /dev/null +++ b/source/gameengine/Converter/BL_ActionData.cpp @@ -0,0 +1,38 @@ +#include "BL_ActionData.h" + +extern "C" { +# include "DNA_action_types.h" +# include "DNA_anim_types.h" +# include "BKE_fcurve.h" +} + +BL_ActionData::BL_ActionData(bAction *action) + :m_action(action) +{ + for (FCurve *fcu = (FCurve *)action->curves.first; fcu; fcu = fcu->next) { + if (fcu->rna_path) { + m_interpolators.emplace_back(fcu); + } + } +} + +std::string BL_ActionData::GetName() const +{ + return m_action->id.name + 2; +} + +bAction *BL_ActionData::GetAction() const +{ + return m_action; +} + +BL_ScalarInterpolator *BL_ActionData::GetScalarInterpolator(const std::string& rna_path, int array_index) +{ + for (BL_ScalarInterpolator &interp : m_interpolators) { + FCurve *fcu = interp.GetFCurve(); + if (array_index == fcu->array_index && rna_path == fcu->rna_path) { + return &interp; + } + } + return nullptr; +} diff --git a/source/gameengine/Converter/BL_ActionData.h b/source/gameengine/Converter/BL_ActionData.h new file mode 100644 index 000000000000..5956255645db --- /dev/null +++ b/source/gameengine/Converter/BL_ActionData.h @@ -0,0 +1,31 @@ +#ifndef __BL_ACTION_DATA_H__ +#define __BL_ACTION_DATA_H__ + +#include "BL_Resource.h" +#include "BL_ScalarInterpolator.h" + +#include + +struct bAction; + +/** Data related to a blender animation. + */ +class BL_ActionData : public BL_Resource +{ +private: + /// The blender action. + bAction *m_action; + /// The interpolators for each curve (FCurve) of the action. + std::vector m_interpolators; + +public: + BL_ActionData(bAction *action); + ~BL_ActionData() = default; + + std::string GetName() const; + bAction *GetAction() const; + + BL_ScalarInterpolator *GetScalarInterpolator(const std::string& rna_path, int array_index); +}; + +#endif // __BL_ACTION_DATA_H__ diff --git a/source/gameengine/Converter/BL_ArmatureActuator.cpp b/source/gameengine/Converter/BL_ArmatureActuator.cpp index 4ce61d859315..d674752c76d7 100644 --- a/source/gameengine/Converter/BL_ArmatureActuator.cpp +++ b/source/gameengine/Converter/BL_ArmatureActuator.cpp @@ -47,16 +47,16 @@ * Later it will also be possible to create constraint on the fly */ -BL_ArmatureActuator::BL_ArmatureActuator(SCA_IObject* obj, - int type, - const char *posechannel, - const char *constraintname, - KX_GameObject* targetobj, - KX_GameObject* subtargetobj, - float weight, - float influence) : +BL_ArmatureActuator::BL_ArmatureActuator(SCA_IObject *obj, + int type, + const char *posechannel, + const char *constraintname, + KX_GameObject *targetobj, + KX_GameObject *subtargetobj, + float weight, + float influence) : SCA_IActuator(obj, KX_ACT_ARMATURE), - m_constraint(NULL), + m_constraint(nullptr), m_gametarget(targetobj), m_gamesubtarget(subtargetobj), m_posechannel(posechannel), @@ -65,85 +65,91 @@ BL_ArmatureActuator::BL_ArmatureActuator(SCA_IObject* obj, m_influence(influence), m_type(type) { - if (m_gametarget) + if (m_gametarget) { m_gametarget->RegisterActuator(this); - if (m_gamesubtarget) + } + if (m_gamesubtarget) { m_gamesubtarget->RegisterActuator(this); + } FindConstraint(); } BL_ArmatureActuator::~BL_ArmatureActuator() { - if (m_gametarget) + if (m_gametarget) { m_gametarget->UnregisterActuator(this); - if (m_gamesubtarget) + } + if (m_gamesubtarget) { m_gamesubtarget->UnregisterActuator(this); + } } void BL_ArmatureActuator::ProcessReplica() { // the replica is tracking the same object => register it (this may be changed in Relnk()) - if (m_gametarget) + if (m_gametarget) { m_gametarget->RegisterActuator(this); - if (m_gamesubtarget) + } + if (m_gamesubtarget) { m_gamesubtarget->UnregisterActuator(this); + } SCA_IActuator::ProcessReplica(); } -void BL_ArmatureActuator::ReParent(SCA_IObject* parent) +void BL_ArmatureActuator::ReParent(SCA_IObject *parent) { SCA_IActuator::ReParent(parent); // must remap the constraint FindConstraint(); } -bool BL_ArmatureActuator::UnlinkObject(SCA_IObject* clientobj) +bool BL_ArmatureActuator::UnlinkObject(SCA_IObject *clientobj) { - bool res=false; - if (clientobj == m_gametarget) - { + bool res = false; + if (clientobj == m_gametarget) { // this object is being deleted, we cannot continue to track it. - m_gametarget = NULL; + m_gametarget = nullptr; res = true; } - if (clientobj == m_gamesubtarget) - { + if (clientobj == m_gamesubtarget) { // this object is being deleted, we cannot continue to track it. - m_gamesubtarget = NULL; + m_gamesubtarget = nullptr; res = true; } return res; } -void BL_ArmatureActuator::Relink(CTR_Map *obj_map) +void BL_ArmatureActuator::Relink(std::map& obj_map) { - void **h_obj = (*obj_map)[m_gametarget]; - if (h_obj) { - if (m_gametarget) + KX_GameObject *obj = static_cast(obj_map[m_gametarget]); + if (obj) { + if (m_gametarget) { m_gametarget->UnregisterActuator(this); - m_gametarget = (KX_GameObject*)(*h_obj); + } + m_gametarget = obj; m_gametarget->RegisterActuator(this); } - h_obj = (*obj_map)[m_gamesubtarget]; - if (h_obj) { - if (m_gamesubtarget) + obj = static_cast(obj_map[m_gamesubtarget]); + if (obj) { + if (m_gamesubtarget) { m_gamesubtarget->UnregisterActuator(this); - m_gamesubtarget = (KX_GameObject*)(*h_obj); + } + m_gamesubtarget = obj; m_gamesubtarget->RegisterActuator(this); } } void BL_ArmatureActuator::FindConstraint() { - m_constraint = NULL; + m_constraint = nullptr; if (m_gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) { - BL_ArmatureObject* armobj = (BL_ArmatureObject*)m_gameobj; + BL_ArmatureObject *armobj = (BL_ArmatureObject *)m_gameobj; m_constraint = armobj->GetConstraint(m_posechannel, m_constraintname); } } -bool BL_ArmatureActuator::Update(double curtime, bool frame) +bool BL_ArmatureActuator::Update(double curtime) { // the only role of this actuator is to ensure that the armature pose will be evaluated bool result = false; @@ -151,34 +157,50 @@ bool BL_ArmatureActuator::Update(double curtime, bool frame) RemoveAllEvents(); if (!bNegativeEvent) { - BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent(); + BL_ArmatureObject *obj = (BL_ArmatureObject *)GetParent(); switch (m_type) { - case ACT_ARM_RUN: - result = true; - obj->UpdateTimestep(curtime); - break; - case ACT_ARM_ENABLE: - if (m_constraint) - m_constraint->ClrConstraintFlag(CONSTRAINT_OFF); - break; - case ACT_ARM_DISABLE: - if (m_constraint) - m_constraint->SetConstraintFlag(CONSTRAINT_OFF); - break; - case ACT_ARM_SETTARGET: - if (m_constraint) { - m_constraint->SetTarget(m_gametarget); - m_constraint->SetSubtarget(m_gamesubtarget); + case ACT_ARM_RUN: + { + result = true; + obj->UpdateTimestep(curtime); + break; + } + case ACT_ARM_ENABLE: + { + if (m_constraint) { + m_constraint->ClrConstraintFlag(CONSTRAINT_OFF); + } + break; + } + case ACT_ARM_DISABLE: + { + if (m_constraint) { + m_constraint->SetConstraintFlag(CONSTRAINT_OFF); + } + break; + } + case ACT_ARM_SETTARGET: + { + if (m_constraint) { + m_constraint->SetTarget(m_gametarget); + m_constraint->SetSubtarget(m_gamesubtarget); + } + break; + } + case ACT_ARM_SETWEIGHT: + { + if (m_constraint) { + m_constraint->SetWeight(m_weight); + } + break; + } + case ACT_ARM_SETINFLUENCE: + { + if (m_constraint) { + m_constraint->SetInfluence(m_influence); + } + break; } - break; - case ACT_ARM_SETWEIGHT: - if (m_constraint) - m_constraint->SetWeight(m_weight); - break; - case ACT_ARM_SETINFLUENCE: - if (m_constraint) - m_constraint->SetInfluence(m_influence); - break; } } return result; @@ -191,80 +213,88 @@ bool BL_ArmatureActuator::Update(double curtime, bool frame) /* ------------------------------------------------------------------------- */ PyTypeObject BL_ArmatureActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "BL_ArmatureActuator", - sizeof(PyObjectPlus_Proxy), - 0, - py_base_dealloc, - 0, - 0, - 0, - 0, - py_base_repr, - 0,0,0,0,0,0,0,0,0, - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, - Methods, - 0, - 0, - &SCA_IActuator::Type, - 0,0,0,0,0,0, - py_base_new + PyVarObject_HEAD_INIT(nullptr, 0) + "BL_ArmatureActuator", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &SCA_IActuator::Type, + 0, 0, 0, 0, 0, 0, + py_base_new }; PyMethodDef BL_ArmatureActuator::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef BL_ArmatureActuator::Attributes[] = { - KX_PYATTRIBUTE_RO_FUNCTION("constraint", BL_ArmatureActuator, pyattr_get_constraint), - KX_PYATTRIBUTE_RW_FUNCTION("target", BL_ArmatureActuator, pyattr_get_object, pyattr_set_object), - KX_PYATTRIBUTE_RW_FUNCTION("subtarget", BL_ArmatureActuator, pyattr_get_object, pyattr_set_object), - KX_PYATTRIBUTE_FLOAT_RW("weight",0.0f,1.0f,BL_ArmatureActuator,m_weight), - KX_PYATTRIBUTE_FLOAT_RW("influence",0.0f,1.0f,BL_ArmatureActuator,m_influence), - KX_PYATTRIBUTE_INT_RW("type",0,ACT_ARM_MAXTYPE,false,BL_ArmatureActuator,m_type), - { NULL } //Sentinel + EXP_PYATTRIBUTE_RO_FUNCTION("constraint", BL_ArmatureActuator, pyattr_get_constraint), + EXP_PYATTRIBUTE_RW_FUNCTION("target", BL_ArmatureActuator, pyattr_get_object, pyattr_set_object), + EXP_PYATTRIBUTE_RW_FUNCTION("subtarget", BL_ArmatureActuator, pyattr_get_object, pyattr_set_object), + EXP_PYATTRIBUTE_FLOAT_RW("weight", 0.0f, 1.0f, BL_ArmatureActuator, m_weight), + EXP_PYATTRIBUTE_FLOAT_RW("influence", 0.0f, 1.0f, BL_ArmatureActuator, m_influence), + EXP_PYATTRIBUTE_INT_RW("type", 0, ACT_ARM_MAXTYPE, false, BL_ArmatureActuator, m_type), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *BL_ArmatureActuator::pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *BL_ArmatureActuator::pyattr_get_object(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - BL_ArmatureActuator* actuator = static_cast(self); - KX_GameObject *target = (!strcmp(attrdef->m_name, "target")) ? actuator->m_gametarget : actuator->m_gamesubtarget; - if (!target) + BL_ArmatureActuator *actuator = static_cast(self); + KX_GameObject *target = (attrdef->m_name == "target") ? actuator->m_gametarget : actuator->m_gamesubtarget; + if (!target) { Py_RETURN_NONE; - else + } + else { return target->GetProxy(); + } } -int BL_ArmatureActuator::pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int BL_ArmatureActuator::pyattr_set_object(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - BL_ArmatureActuator* actuator = static_cast(self); - KX_GameObject* &target = (!strcmp(attrdef->m_name, "target")) ? actuator->m_gametarget : actuator->m_gamesubtarget; + BL_ArmatureActuator *actuator = static_cast(self); + KX_GameObject * &target = (attrdef->m_name == "target") ? actuator->m_gametarget : actuator->m_gamesubtarget; KX_GameObject *gameobj; - if (!ConvertPythonToGameObject(actuator->GetLogicManager(), value, &gameobj, true, "actuator.object = value: BL_ArmatureActuator")) + if (!ConvertPythonToGameObject(actuator->GetLogicManager(), value, &gameobj, true, "actuator.object = value: BL_ArmatureActuator")) { return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error - if (target != NULL) + } + if (target != nullptr) { target->UnregisterActuator(actuator); + } target = gameobj; - if (target) + if (target) { target->RegisterActuator(actuator); + } return PY_SET_ATTR_SUCCESS; } -PyObject *BL_ArmatureActuator::pyattr_get_constraint(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *BL_ArmatureActuator::pyattr_get_constraint(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - BL_ArmatureActuator* actuator = static_cast(self); - BL_ArmatureConstraint* constraint = actuator->m_constraint; - if (!constraint) + BL_ArmatureActuator *actuator = static_cast(self); + BL_ArmatureConstraint *constraint = actuator->m_constraint; + if (!constraint) { Py_RETURN_NONE; - else + } + else { return constraint->GetProxy(); + } } #endif // WITH_PYTHON + diff --git a/source/gameengine/Converter/BL_ArmatureActuator.h b/source/gameengine/Converter/BL_ArmatureActuator.h index 3c455498508b..a964744a0ee2 100644 --- a/source/gameengine/Converter/BL_ArmatureActuator.h +++ b/source/gameengine/Converter/BL_ArmatureActuator.h @@ -38,8 +38,8 @@ /** * This class is the conversion of the Pose channel constraint. * It makes a link between the pose constraint and the KX scene. - * The main purpose is to give access to the constraint target - * to link it to a game object. + * The main purpose is to give access to the constraint target + * to link it to a game object. * It also allows to activate/deactivate constraints during the game. * Later it will also be possible to create constraint on the fly */ @@ -59,23 +59,23 @@ class BL_ArmatureActuator : public SCA_IActuator virtual ~BL_ArmatureActuator(); - virtual CValue* GetReplica() { + virtual EXP_Value* GetReplica() { BL_ArmatureActuator* replica = new BL_ArmatureActuator(*this); replica->ProcessReplica(); return replica; }; virtual void ProcessReplica(); virtual bool UnlinkObject(SCA_IObject* clientobj); - virtual void Relink(CTR_Map *obj_map); - virtual bool Update(double curtime, bool frame); + virtual void Relink(std::map& obj_map); + virtual bool Update(double curtime); virtual void ReParent(SCA_IObject* parent); - + #ifdef WITH_PYTHON /* These are used to get and set m_target */ - static PyObject *pyattr_get_constraint(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_constraint(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_object(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_object(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); #endif /* WITH_PYTHON */ @@ -86,8 +86,8 @@ class BL_ArmatureActuator : public SCA_IActuator BL_ArmatureConstraint* m_constraint; KX_GameObject* m_gametarget; KX_GameObject* m_gamesubtarget; - STR_String m_posechannel; - STR_String m_constraintname; + std::string m_posechannel; + std::string m_constraintname; float m_weight; float m_influence; int m_type; diff --git a/source/gameengine/Converter/BL_ArmatureChannel.cpp b/source/gameengine/Converter/BL_ArmatureChannel.cpp index 711c96e32c1e..0383b896b0e0 100644 --- a/source/gameengine/Converter/BL_ArmatureChannel.cpp +++ b/source/gameengine/Converter/BL_ArmatureChannel.cpp @@ -41,9 +41,9 @@ #ifdef WITH_PYTHON PyTypeObject BL_ArmatureChannel::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "BL_ArmatureChannel", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -51,22 +51,17 @@ PyTypeObject BL_ArmatureChannel::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, - &CValue::Type, - 0,0,0,0,0,0, + &EXP_Value::Type, + 0, 0, 0, 0, 0, 0, py_base_new }; -PyObject *BL_ArmatureChannel::py_repr(void) -{ - return PyUnicode_FromString(m_posechannel->name); -} - PyObject *BL_ArmatureChannel::GetProxy() { return GetProxyPlus_Ext(this, &Type, m_posechannel); @@ -79,10 +74,9 @@ PyObject *BL_ArmatureChannel::NewProxy(bool py_owns) #endif // WITH_PYTHON -BL_ArmatureChannel::BL_ArmatureChannel( - BL_ArmatureObject *armature, - bPoseChannel *posechannel) - : PyObjectPlus(), m_posechannel(posechannel), m_armature(armature) +BL_ArmatureChannel::BL_ArmatureChannel(BL_ArmatureObject *armature, + bPoseChannel *posechannel) + :m_posechannel(posechannel), m_armature(armature) { } @@ -95,91 +89,94 @@ BL_ArmatureChannel::~BL_ArmatureChannel() // PYTHON PyMethodDef BL_ArmatureChannel::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; // order of definition of attributes, must match Attributes[] array -#define BCA_BONE 0 -#define BCA_PARENT 1 +#define BCA_BONE 0 +#define BCA_PARENT 1 PyAttributeDef BL_ArmatureChannel::Attributes[] = { // Keep these attributes in order of BCA_ defines!!! used by py_attr_getattr and py_attr_setattr - KX_PYATTRIBUTE_RO_FUNCTION("bone",BL_ArmatureChannel,py_attr_getattr), - KX_PYATTRIBUTE_RO_FUNCTION("parent",BL_ArmatureChannel,py_attr_getattr), - - { NULL } //Sentinel + EXP_PYATTRIBUTE_RO_FUNCTION("bone", BL_ArmatureChannel, py_attr_getattr), + EXP_PYATTRIBUTE_RO_FUNCTION("parent", BL_ArmatureChannel, py_attr_getattr), + EXP_PYATTRIBUTE_NULL //Sentinel }; /* attributes directly taken from bPoseChannel */ PyAttributeDef BL_ArmatureChannel::AttributesPtr[] = { - KX_PYATTRIBUTE_CHAR_RO("name",bPoseChannel,name), - KX_PYATTRIBUTE_FLAG_RO("has_ik",bPoseChannel,flag, POSE_CHAIN), - KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_x",bPoseChannel,ikflag, BONE_IK_NO_XDOF), - KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_y",bPoseChannel,ikflag, BONE_IK_NO_YDOF), - KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_z",bPoseChannel,ikflag, BONE_IK_NO_ZDOF), - KX_PYATTRIBUTE_FLAG_RO("ik_limit_x",bPoseChannel,ikflag, BONE_IK_XLIMIT), - KX_PYATTRIBUTE_FLAG_RO("ik_limit_y",bPoseChannel,ikflag, BONE_IK_YLIMIT), - KX_PYATTRIBUTE_FLAG_RO("ik_limit_z",bPoseChannel,ikflag, BONE_IK_ZLIMIT), - KX_PYATTRIBUTE_FLAG_RO("ik_rot_control",bPoseChannel,ikflag, BONE_IK_ROTCTL), - KX_PYATTRIBUTE_FLAG_RO("ik_lin_control",bPoseChannel,ikflag, BONE_IK_LINCTL), - KX_PYATTRIBUTE_FLOAT_VECTOR_RW("location",-FLT_MAX,FLT_MAX,bPoseChannel,loc,3), - KX_PYATTRIBUTE_FLOAT_VECTOR_RW("scale",-FLT_MAX,FLT_MAX,bPoseChannel,size,3), - KX_PYATTRIBUTE_FLOAT_VECTOR_RW("rotation_quaternion",-1.0f,1.0f,bPoseChannel,quat,4), - KX_PYATTRIBUTE_FLOAT_VECTOR_RW("rotation_euler",-10.f,10.f,bPoseChannel,eul,3), - KX_PYATTRIBUTE_SHORT_RW("rotation_mode",ROT_MODE_MIN,ROT_MODE_MAX,false,bPoseChannel,rotmode), - KX_PYATTRIBUTE_FLOAT_MATRIX_RO("channel_matrix",bPoseChannel,chan_mat,4), - KX_PYATTRIBUTE_FLOAT_MATRIX_RO("pose_matrix",bPoseChannel,pose_mat,4), - KX_PYATTRIBUTE_FLOAT_VECTOR_RO("pose_head",bPoseChannel,pose_head,3), - KX_PYATTRIBUTE_FLOAT_VECTOR_RO("pose_tail",bPoseChannel,pose_tail,3), - KX_PYATTRIBUTE_FLOAT_RO("ik_min_x",bPoseChannel,limitmin[0]), - KX_PYATTRIBUTE_FLOAT_RO("ik_max_x",bPoseChannel,limitmax[0]), - KX_PYATTRIBUTE_FLOAT_RO("ik_min_y",bPoseChannel,limitmin[1]), - KX_PYATTRIBUTE_FLOAT_RO("ik_max_y",bPoseChannel,limitmax[1]), - KX_PYATTRIBUTE_FLOAT_RO("ik_min_z",bPoseChannel,limitmin[2]), - KX_PYATTRIBUTE_FLOAT_RO("ik_max_z",bPoseChannel,limitmax[2]), - KX_PYATTRIBUTE_FLOAT_RO("ik_stiffness_x",bPoseChannel,stiffness[0]), - KX_PYATTRIBUTE_FLOAT_RO("ik_stiffness_y",bPoseChannel,stiffness[1]), - KX_PYATTRIBUTE_FLOAT_RO("ik_stiffness_z",bPoseChannel,stiffness[2]), - KX_PYATTRIBUTE_FLOAT_RO("ik_stretch",bPoseChannel,ikstretch), - KX_PYATTRIBUTE_FLOAT_RW("ik_rot_weight",0,1.0f,bPoseChannel,ikrotweight), - KX_PYATTRIBUTE_FLOAT_RW("ik_lin_weight",0,1.0f,bPoseChannel,iklinweight), - KX_PYATTRIBUTE_RW_FUNCTION("joint_rotation",BL_ArmatureChannel,py_attr_get_joint_rotation,py_attr_set_joint_rotation), - { NULL } //Sentinel + EXP_PYATTRIBUTE_CHAR_RO("name", bPoseChannel, name), + EXP_PYATTRIBUTE_FLAG_RO("has_ik", bPoseChannel, flag, POSE_CHAIN), + EXP_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_x", bPoseChannel, ikflag, BONE_IK_NO_XDOF), + EXP_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_y", bPoseChannel, ikflag, BONE_IK_NO_YDOF), + EXP_PYATTRIBUTE_FLAG_NEGATIVE_RO("ik_dof_z", bPoseChannel, ikflag, BONE_IK_NO_ZDOF), + EXP_PYATTRIBUTE_FLAG_RO("ik_limit_x", bPoseChannel, ikflag, BONE_IK_XLIMIT), + EXP_PYATTRIBUTE_FLAG_RO("ik_limit_y", bPoseChannel, ikflag, BONE_IK_YLIMIT), + EXP_PYATTRIBUTE_FLAG_RO("ik_limit_z", bPoseChannel, ikflag, BONE_IK_ZLIMIT), + EXP_PYATTRIBUTE_FLAG_RO("ik_rot_control", bPoseChannel, ikflag, BONE_IK_ROTCTL), + EXP_PYATTRIBUTE_FLAG_RO("ik_lin_control", bPoseChannel, ikflag, BONE_IK_LINCTL), + EXP_PYATTRIBUTE_FLOAT_VECTOR_RW("location", -FLT_MAX, FLT_MAX, bPoseChannel, loc, 3), + EXP_PYATTRIBUTE_FLOAT_VECTOR_RW("scale", -FLT_MAX, FLT_MAX, bPoseChannel, size, 3), + EXP_PYATTRIBUTE_FLOAT_VECTOR_RW("rotation_quaternion", -1.0f, 1.0f, bPoseChannel, quat, 4), + EXP_PYATTRIBUTE_FLOAT_VECTOR_RW("rotation_euler", -10.f, 10.f, bPoseChannel, eul, 3), + EXP_PYATTRIBUTE_SHORT_RW("rotation_mode", ROT_MODE_MIN, ROT_MODE_MAX, false, bPoseChannel, rotmode), + EXP_PYATTRIBUTE_FLOAT_MATRIX_RO("channel_matrix", bPoseChannel, chan_mat, 4), + EXP_PYATTRIBUTE_FLOAT_MATRIX_RO("pose_matrix", bPoseChannel, pose_mat, 4), + EXP_PYATTRIBUTE_FLOAT_VECTOR_RO("pose_head", bPoseChannel, pose_head, 3), + EXP_PYATTRIBUTE_FLOAT_VECTOR_RO("pose_tail", bPoseChannel, pose_tail, 3), + EXP_PYATTRIBUTE_FLOAT_RO("ik_min_x", bPoseChannel, limitmin[0]), + EXP_PYATTRIBUTE_FLOAT_RO("ik_max_x", bPoseChannel, limitmax[0]), + EXP_PYATTRIBUTE_FLOAT_RO("ik_min_y", bPoseChannel, limitmin[1]), + EXP_PYATTRIBUTE_FLOAT_RO("ik_max_y", bPoseChannel, limitmax[1]), + EXP_PYATTRIBUTE_FLOAT_RO("ik_min_z", bPoseChannel, limitmin[2]), + EXP_PYATTRIBUTE_FLOAT_RO("ik_max_z", bPoseChannel, limitmax[2]), + EXP_PYATTRIBUTE_FLOAT_RO("ik_stiffness_x", bPoseChannel, stiffness[0]), + EXP_PYATTRIBUTE_FLOAT_RO("ik_stiffness_y", bPoseChannel, stiffness[1]), + EXP_PYATTRIBUTE_FLOAT_RO("ik_stiffness_z", bPoseChannel, stiffness[2]), + EXP_PYATTRIBUTE_FLOAT_RO("ik_stretch", bPoseChannel, ikstretch), + EXP_PYATTRIBUTE_FLOAT_RW("ik_rot_weight", 0, 1.0f, bPoseChannel, ikrotweight), + EXP_PYATTRIBUTE_FLOAT_RW("ik_lin_weight", 0, 1.0f, bPoseChannel, iklinweight), + EXP_PYATTRIBUTE_RW_FUNCTION("joint_rotation", BL_ArmatureChannel, py_attr_get_joint_rotation, py_attr_set_joint_rotation), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *BL_ArmatureChannel::py_attr_getattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *BL_ArmatureChannel::py_attr_getattr(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - BL_ArmatureChannel* self = static_cast(self_v); - bPoseChannel* channel = self->m_posechannel; - int attr_order = attrdef-Attributes; + BL_ArmatureChannel *self = static_cast(self_v); + bPoseChannel *channel = self->m_posechannel; + int attr_order = attrdef - Attributes; if (!channel) { - PyErr_SetString(PyExc_AttributeError, "channel is NULL"); - return NULL; + PyErr_SetString(PyExc_AttributeError, "channel is nullptr"); + return nullptr; } switch (attr_order) { - case BCA_BONE: - // bones are standalone proxy - return NewProxyPlus_Ext(NULL,&BL_ArmatureBone::Type,channel->bone,false); - case BCA_PARENT: + case BCA_BONE: { - BL_ArmatureChannel* parent = self->m_armature->GetChannel(channel->parent); - if (parent) + // bones are standalone proxy + return NewProxyPlus_Ext(nullptr, &BL_ArmatureBone::Type, channel->bone, false); + } + case BCA_PARENT: + { + BL_ArmatureChannel *parent = self->m_armature->GetChannel(channel->parent); + if (parent) { return parent->GetProxy(); - else + } + else { Py_RETURN_NONE; + } } } PyErr_SetString(PyExc_AttributeError, "channel unknown attribute"); - return NULL; + return nullptr; } -int BL_ArmatureChannel::py_attr_setattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int BL_ArmatureChannel::py_attr_setattr(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - BL_ArmatureChannel* self = static_cast(self_v); - bPoseChannel* channel = self->m_posechannel; - int attr_order = attrdef-Attributes; + BL_ArmatureChannel *self = static_cast(self_v); + bPoseChannel *channel = self->m_posechannel; + int attr_order = attrdef - Attributes; // int ival; // double dval; @@ -187,22 +184,25 @@ int BL_ArmatureChannel::py_attr_setattr(void *self_v, const struct KX_PYATTRIBUT // KX_GameObject *oval; if (!channel) { - PyErr_SetString(PyExc_AttributeError, "channel is NULL"); + PyErr_SetString(PyExc_AttributeError, "channel is nullptr"); return PY_SET_ATTR_FAIL; } switch (attr_order) { - default: - break; + default: + { + break; + } } PyErr_SetString(PyExc_AttributeError, "channel unknown attribute"); return PY_SET_ATTR_FAIL; } -PyObject *BL_ArmatureChannel::py_attr_get_joint_rotation(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *BL_ArmatureChannel::py_attr_get_joint_rotation(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - bPoseChannel* pchan = static_cast(self_v); + BL_ArmatureChannel *self = static_cast(self_v); + bPoseChannel *pchan = self->m_posechannel; // decompose the pose matrix in euler rotation float rest_mat[3][3]; float pose_mat[3][3]; @@ -217,7 +217,8 @@ PyObject *BL_ArmatureChannel::py_attr_get_joint_rotation(void *self_v, const str // bone has a parent, compute the rest pose of the bone taking actual pose of parent mul_m3_m3m4(rest_mat, pchan->parent->pose_mat, pchan->bone->bone_mat); normalize_m3(rest_mat); - } else { + } + else { // otherwise, the bone matrix in armature space is the rest pose copy_m3_m4(rest_mat, pchan->bone->arm_mat); } @@ -227,81 +228,91 @@ PyObject *BL_ArmatureChannel::py_attr_get_joint_rotation(void *self_v, const str joints[0] = joints[1] = joints[2] = 0.f; // returns a 3 element list that gives corresponding joint int flag = 0; - if (!(pchan->ikflag & BONE_IK_NO_XDOF)) + if (!(pchan->ikflag & BONE_IK_NO_XDOF)) { flag |= 1; - if (!(pchan->ikflag & BONE_IK_NO_YDOF)) + } + if (!(pchan->ikflag & BONE_IK_NO_YDOF)) { flag |= 2; - if (!(pchan->ikflag & BONE_IK_NO_ZDOF)) + } + if (!(pchan->ikflag & BONE_IK_NO_ZDOF)) { flag |= 4; + } switch (flag) { - case 0: // fixed joint - break; - case 1: // X only - mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat); - joints[1] = joints[2] = 0.f; - break; - case 2: // Y only - mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat); - joints[0] = joints[2] = 0.f; - break; - case 3: // X+Y - mat3_to_eulO( joints, EULER_ORDER_ZYX,joint_mat); - joints[2] = 0.f; - break; - case 4: // Z only - mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat); - joints[0] = joints[1] = 0.f; - break; - case 5: // X+Z - // decompose this as an equivalent rotation vector in X/Z plane - joints[0] = joint_mat[1][2]; - joints[2] = -joint_mat[1][0]; - norm = normalize_v3(joints); - if (norm < FLT_EPSILON) { - norm = (joint_mat[1][1] < 0.0f) ? (float)M_PI : 0.0f; - } else { - norm = acos(joint_mat[1][1]); + case 0: // fixed joint + {break;} + case 1: // X only + {mat3_to_eulO(joints, EULER_ORDER_XYZ, joint_mat); + joints[1] = joints[2] = 0.f; + break;} + case 2: // Y only + {mat3_to_eulO(joints, EULER_ORDER_XYZ, joint_mat); + joints[0] = joints[2] = 0.f; + break;} + case 3: // X+Y + {mat3_to_eulO(joints, EULER_ORDER_ZYX, joint_mat); + joints[2] = 0.f; + break;} + case 4: // Z only + {mat3_to_eulO(joints, EULER_ORDER_XYZ, joint_mat); + joints[0] = joints[1] = 0.f; + break;} + case 5: // X+Z + {// decompose this as an equivalent rotation vector in X/Z plane + joints[0] = joint_mat[1][2]; + joints[2] = -joint_mat[1][0]; + norm = normalize_v3(joints); + if (norm < FLT_EPSILON) { + norm = (joint_mat[1][1] < 0.0f) ? (float)M_PI : 0.0f; + } + else { + norm = acos(joint_mat[1][1]); + } + mul_v3_fl(joints, norm); + break; } - mul_v3_fl(joints, norm); - break; - case 6: // Y+Z - mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat); - joints[0] = 0.f; - break; - case 7: // X+Y+Z - // equivalent axis - joints[0] = (joint_mat[1][2]-joint_mat[2][1])*0.5f; - joints[1] = (joint_mat[2][0]-joint_mat[0][2])*0.5f; - joints[2] = (joint_mat[0][1]-joint_mat[1][0])*0.5f; - sa = len_v3(joints); - ca = (joint_mat[0][0]+joint_mat[1][1]+joint_mat[1][1]-1.0f)*0.5f; - if (sa > (double)FLT_EPSILON) { - norm = atan2(sa,ca)/sa; - } else { - if (ca < 0.0) { - norm = M_PI; - mul_v3_fl(joints,0.f); - if (joint_mat[0][0] > 0.f) { - joints[0] = 1.0f; - } else if (joint_mat[1][1] > 0.f) { - joints[1] = 1.0f; - } else { - joints[2] = 1.0f; + case 6: // Y+Z + {mat3_to_eulO(joints, EULER_ORDER_XYZ, joint_mat); + joints[0] = 0.f; + break;} + case 7: // X+Y+Z + {// equivalent axis + joints[0] = (joint_mat[1][2] - joint_mat[2][1]) * 0.5f; + joints[1] = (joint_mat[2][0] - joint_mat[0][2]) * 0.5f; + joints[2] = (joint_mat[0][1] - joint_mat[1][0]) * 0.5f; + sa = len_v3(joints); + ca = (joint_mat[0][0] + joint_mat[1][1] + joint_mat[1][1] - 1.0f) * 0.5f; + if (sa > (double)FLT_EPSILON) { + norm = atan2(sa, ca) / sa; + } + else { + if (ca < 0.0) { + norm = M_PI; + mul_v3_fl(joints, 0.f); + if (joint_mat[0][0] > 0.f) { + joints[0] = 1.0f; + } + else if (joint_mat[1][1] > 0.f) { + joints[1] = 1.0f; + } + else { + joints[2] = 1.0f; + } + } + else { + norm = 0.0; } - } else { - norm = 0.0; } + mul_v3_fl(joints, norm); + break; } - mul_v3_fl(joints,norm); - break; } - return Vector_CreatePyObject(joints, 3, NULL); + return Vector_CreatePyObject(joints, 3, nullptr); } -int BL_ArmatureChannel::py_attr_set_joint_rotation(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int BL_ArmatureChannel::py_attr_set_joint_rotation(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - BL_ArmatureChannel* self = static_cast(self_v); - bPoseChannel* pchan = self->m_posechannel; + BL_ArmatureChannel *self = static_cast(self_v); + bPoseChannel *pchan = self->m_posechannel; PyObject *item; float joints[3]; float quat[4]; @@ -310,7 +321,7 @@ int BL_ArmatureChannel::py_attr_set_joint_rotation(void *self_v, const struct KX PyErr_SetString(PyExc_AttributeError, "expected a sequence of 3 floats"); return PY_SET_ATTR_FAIL; } - for (int i=0; i<3; i++) { + for (int i = 0; i < 3; i++) { item = PySequence_GetItem(value, i); /* new ref */ joints[i] = PyFloat_AsDouble(item); Py_DECREF(item); @@ -321,51 +332,58 @@ int BL_ArmatureChannel::py_attr_set_joint_rotation(void *self_v, const struct KX } int flag = 0; - if (!(pchan->ikflag & BONE_IK_NO_XDOF)) + if (!(pchan->ikflag & BONE_IK_NO_XDOF)) { flag |= 1; - if (!(pchan->ikflag & BONE_IK_NO_YDOF)) + } + if (!(pchan->ikflag & BONE_IK_NO_YDOF)) { flag |= 2; - if (!(pchan->ikflag & BONE_IK_NO_ZDOF)) + } + if (!(pchan->ikflag & BONE_IK_NO_ZDOF)) { flag |= 4; + } unit_qt(quat); switch (flag) { - case 0: // fixed joint - break; - case 1: // X only - joints[1] = joints[2] = 0.f; - eulO_to_quat( quat,joints, EULER_ORDER_XYZ); - break; - case 2: // Y only - joints[0] = joints[2] = 0.f; - eulO_to_quat( quat,joints, EULER_ORDER_XYZ); - break; - case 3: // X+Y - joints[2] = 0.f; - eulO_to_quat( quat,joints, EULER_ORDER_ZYX); - break; - case 4: // Z only - joints[0] = joints[1] = 0.f; - eulO_to_quat( quat,joints, EULER_ORDER_XYZ); - break; - case 5: // X+Z - // X and Z are components of an equivalent rotation axis - joints[1] = 0; - axis_angle_to_quat( quat,joints, len_v3(joints)); - break; - case 6: // Y+Z - joints[0] = 0.f; - eulO_to_quat( quat,joints, EULER_ORDER_XYZ); - break; - case 7: // X+Y+Z - // equivalent axis - axis_angle_to_quat( quat,joints, len_v3(joints)); - break; + case 0: // fixed joint + {break;} + case 1: // X only + {joints[1] = joints[2] = 0.f; + eulO_to_quat(quat, joints, EULER_ORDER_XYZ); + break;} + case 2: // Y only + {joints[0] = joints[2] = 0.f; + eulO_to_quat(quat, joints, EULER_ORDER_XYZ); + break;} + case 3: // X+Y + {joints[2] = 0.f; + eulO_to_quat(quat, joints, EULER_ORDER_ZYX); + break;} + case 4: // Z only + {joints[0] = joints[1] = 0.f; + eulO_to_quat(quat, joints, EULER_ORDER_XYZ); + break;} + case 5: // X+Z + {// X and Z are components of an equivalent rotation axis + joints[1] = 0; + axis_angle_to_quat(quat, joints, len_v3(joints)); + break; + } + case 6: // Y+Z + {joints[0] = 0.f; + eulO_to_quat(quat, joints, EULER_ORDER_XYZ); + break;} + case 7: // X+Y+Z + {// equivalent axis + axis_angle_to_quat(quat, joints, len_v3(joints)); + break; + } } if (pchan->rotmode > 0) { - quat_to_eulO( joints, pchan->rotmode,quat); + quat_to_eulO(joints, pchan->rotmode, quat); copy_v3_v3(pchan->eul, joints); - } else + } + else { copy_qt_qt(pchan->quat, quat); + } return PY_SET_ATTR_SUCCESS; } @@ -374,9 +392,9 @@ int BL_ArmatureChannel::py_attr_set_joint_rotation(void *self_v, const struct KX // // Access to Bone structure PyTypeObject BL_ArmatureBone::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "BL_ArmatureBone", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -384,84 +402,86 @@ PyTypeObject BL_ArmatureBone::Type = { 0, 0, py_bone_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, - &CValue::Type, - 0,0,0,0,0,0, + &EXP_Value::Type, + 0, 0, 0, 0, 0, 0, py_base_new }; // not used since this class is never instantiated PyObject *BL_ArmatureBone::GetProxy() { - return NULL; + return nullptr; } PyObject *BL_ArmatureBone::NewProxy(bool py_owns) { - return NULL; + return nullptr; } PyObject *BL_ArmatureBone::py_bone_repr(PyObject *self) { - Bone* bone = static_castBGE_PROXY_PTR(self); + Bone *bone = static_castEXP_PROXY_PTR(self); return PyUnicode_FromString(bone->name); } PyMethodDef BL_ArmatureBone::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; /* no attributes on C++ class since it is never instantiated */ PyAttributeDef BL_ArmatureBone::Attributes[] = { - { NULL } //Sentinel + EXP_PYATTRIBUTE_NULL //Sentinel }; // attributes that work on proxy ptr (points to a Bone structure) PyAttributeDef BL_ArmatureBone::AttributesPtr[] = { - KX_PYATTRIBUTE_CHAR_RO("name",Bone,name), - KX_PYATTRIBUTE_FLAG_RO("connected",Bone,flag, BONE_CONNECTED), - KX_PYATTRIBUTE_FLAG_RO("hinge",Bone,flag, BONE_HINGE), - KX_PYATTRIBUTE_FLAG_NEGATIVE_RO("inherit_scale",Bone,flag, BONE_NO_SCALE), - KX_PYATTRIBUTE_SHORT_RO("bbone_segments",Bone,segments), - KX_PYATTRIBUTE_FLOAT_RO("roll",Bone,roll), - KX_PYATTRIBUTE_FLOAT_VECTOR_RO("head",Bone,head,3), - KX_PYATTRIBUTE_FLOAT_VECTOR_RO("tail",Bone,tail,3), - KX_PYATTRIBUTE_FLOAT_RO("length",Bone,length), - KX_PYATTRIBUTE_FLOAT_VECTOR_RO("arm_head",Bone,arm_head,3), - KX_PYATTRIBUTE_FLOAT_VECTOR_RO("arm_tail",Bone,arm_tail,3), - KX_PYATTRIBUTE_FLOAT_MATRIX_RO("arm_mat",Bone,arm_mat,4), - KX_PYATTRIBUTE_FLOAT_MATRIX_RO("bone_mat",Bone,bone_mat,3), - KX_PYATTRIBUTE_RO_FUNCTION("parent",BL_ArmatureBone,py_bone_get_parent), - KX_PYATTRIBUTE_RO_FUNCTION("children",BL_ArmatureBone,py_bone_get_children), - { NULL } //Sentinel + EXP_PYATTRIBUTE_CHAR_RO("name", Bone, name), + EXP_PYATTRIBUTE_FLAG_RO("connected", Bone, flag, BONE_CONNECTED), + EXP_PYATTRIBUTE_FLAG_RO("hinge", Bone, flag, BONE_HINGE), + EXP_PYATTRIBUTE_FLAG_NEGATIVE_RO("inherit_scale", Bone, flag, BONE_NO_SCALE), + EXP_PYATTRIBUTE_SHORT_RO("bbone_segments", Bone, segments), + EXP_PYATTRIBUTE_FLOAT_RO("roll", Bone, roll), + EXP_PYATTRIBUTE_FLOAT_VECTOR_RO("head", Bone, head, 3), + EXP_PYATTRIBUTE_FLOAT_VECTOR_RO("tail", Bone, tail, 3), + EXP_PYATTRIBUTE_FLOAT_RO("length", Bone, length), + EXP_PYATTRIBUTE_FLOAT_VECTOR_RO("arm_head", Bone, arm_head, 3), + EXP_PYATTRIBUTE_FLOAT_VECTOR_RO("arm_tail", Bone, arm_tail, 3), + EXP_PYATTRIBUTE_FLOAT_MATRIX_RO("arm_mat", Bone, arm_mat, 4), + EXP_PYATTRIBUTE_FLOAT_MATRIX_RO("bone_mat", Bone, bone_mat, 3), + EXP_PYATTRIBUTE_RO_FUNCTION("parent", BL_ArmatureBone, py_bone_get_parent), + EXP_PYATTRIBUTE_RO_FUNCTION("children", BL_ArmatureBone, py_bone_get_children), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *BL_ArmatureBone::py_bone_get_parent(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *BL_ArmatureBone::py_bone_get_parent(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - Bone* bone = reinterpret_cast(self); + Bone *bone = reinterpret_cast(self); if (bone->parent) { // create a proxy unconnected to any GE object - return NewProxyPlus_Ext(NULL,&Type,bone->parent,false); + return NewProxyPlus_Ext(nullptr, &Type, bone->parent, false); } Py_RETURN_NONE; } -PyObject *BL_ArmatureBone::py_bone_get_children(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *BL_ArmatureBone::py_bone_get_children(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - Bone* bone = reinterpret_cast(self); - Bone* child; + Bone *bone = reinterpret_cast(self); + Bone *child; int count = 0; - for (child = (Bone *)bone->childbase.first; child; child = child->next) + for (child = (Bone *)bone->childbase.first; child; child = child->next) { count++; + } PyObject *childrenlist = PyList_New(count); - for (count = 0, child = (Bone *)bone->childbase.first; child; child = child->next, ++count) - PyList_SET_ITEM(childrenlist,count,NewProxyPlus_Ext(NULL,&Type,child,false)); + for (count = 0, child = (Bone *)bone->childbase.first; child; child = child->next, ++count) { + PyList_SET_ITEM(childrenlist, count, NewProxyPlus_Ext(nullptr, &Type, child, false)); + } return childrenlist; } diff --git a/source/gameengine/Converter/BL_ArmatureChannel.h b/source/gameengine/Converter/BL_ArmatureChannel.h index 8e6bc94c488e..b17d5536c406 100644 --- a/source/gameengine/Converter/BL_ArmatureChannel.h +++ b/source/gameengine/Converter/BL_ArmatureChannel.h @@ -33,9 +33,7 @@ #define __BL_ARMATURECHANNEL_H__ #include "DNA_action_types.h" -#include "CTR_HashedPtr.h" -#include "CTR_Map.h" -#include "EXP_PyObjectPlus.h" +#include "EXP_Value.h" class SCA_IObject; class KX_GameObject; @@ -45,7 +43,7 @@ struct bPoseChannel; struct Object; struct bPose; -class BL_ArmatureChannel : public PyObjectPlus +class BL_ArmatureChannel : public EXP_Value { // use Py_HeaderPtr since we use generic pointer in proxy Py_HeaderPtr; @@ -56,30 +54,28 @@ class BL_ArmatureChannel : public PyObjectPlus BL_ArmatureObject* m_armature; public: - BL_ArmatureChannel(class BL_ArmatureObject *armature, + BL_ArmatureChannel(class BL_ArmatureObject *armature, struct bPoseChannel *posechannel); virtual ~BL_ArmatureChannel(); - inline const char *GetName() + virtual std::string GetName() { return m_posechannel->name; } #ifdef WITH_PYTHON // Python access - virtual PyObject *py_repr(void); - - static PyObject *py_attr_getattr(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static int py_attr_setattr(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject *py_attr_get_joint_rotation(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static int py_attr_set_joint_rotation(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *py_attr_getattr(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static int py_attr_setattr(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *py_attr_get_joint_rotation(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static int py_attr_set_joint_rotation(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); #endif /* WITH_PYTHON */ }; /* this is a factory class to access bBone data field in the GE. * It's not supposed to be instantiated, we only need it for the Attributes and Method array. * The actual proxy object will be manually created using NewProxyPtr */ -class BL_ArmatureBone : public PyObjectPlus +class BL_ArmatureBone : public EXP_PyObjectPlus { // use Py_HeaderPtr since we use generic pointer in proxy Py_HeaderPtr; @@ -92,8 +88,8 @@ class BL_ArmatureBone : public PyObjectPlus #ifdef WITH_PYTHON static PyObject *py_bone_repr(PyObject *self); - static PyObject *py_bone_get_parent(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *py_bone_get_children(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static PyObject *py_bone_get_parent(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *py_bone_get_children(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); #endif }; diff --git a/source/gameengine/Converter/BL_ArmatureConstraint.cpp b/source/gameengine/Converter/BL_ArmatureConstraint.cpp index 224ae259fa24..f42ac3e3a05f 100644 --- a/source/gameengine/Converter/BL_ArmatureConstraint.cpp +++ b/source/gameengine/Converter/BL_ArmatureConstraint.cpp @@ -30,20 +30,27 @@ */ -#include "DNA_constraint_types.h" -#include "DNA_action_types.h" #include "BL_ArmatureConstraint.h" #include "BL_ArmatureObject.h" + +#include "KX_Globals.h" + +#include "DNA_constraint_types.h" +#include "DNA_action_types.h" + +#include "BKE_object.h" +#include "BKE_constraint.h" +#include "BKE_global.h" + #include "BLI_math.h" #include "BLI_string.h" -#include "KX_PythonInit.h" #ifdef WITH_PYTHON PyTypeObject BL_ArmatureConstraint::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "BL_ArmatureConstraint", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -51,127 +58,163 @@ PyTypeObject BL_ArmatureConstraint::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, - &CValue::Type, - 0,0,0,0,0,0, + &EXP_Value::Type, + 0, 0, 0, 0, 0, 0, py_base_new }; -PyObject *BL_ArmatureConstraint::py_repr(void) -{ - return PyUnicode_FromString(m_name); -} - #endif // WITH_PYTHON -BL_ArmatureConstraint::BL_ArmatureConstraint( - BL_ArmatureObject *armature, - bPoseChannel *posechannel, - bConstraint *constraint, - KX_GameObject* target, - KX_GameObject* subtarget) - : PyObjectPlus(), m_constraint(constraint), m_posechannel(posechannel), m_armature(armature) +BL_ArmatureConstraint::BL_ArmatureConstraint(BL_ArmatureObject *armature, + bPoseChannel *posechannel, + bConstraint *constraint, + KX_GameObject *target, + KX_GameObject *subtarget) + :m_constraint(constraint), + m_posechannel(posechannel), + m_armature(armature), + m_target(target), + m_subtarget(subtarget), + m_blendtarget(nullptr), + m_blendsubtarget(nullptr) { - m_target = target; - m_blendtarget = (target) ? target->GetBlenderObject() : NULL; - m_subtarget = subtarget; - m_blendsubtarget = (subtarget) ? subtarget->GetBlenderObject() : NULL; - m_pose = m_subpose = NULL; - if (m_blendtarget) { - copy_m4_m4(m_blendmat, m_blendtarget->obmat); - if (m_blendtarget->type == OB_ARMATURE) - m_pose = m_blendtarget->pose; - } - if (m_blendsubtarget) { - copy_m4_m4(m_blendsubmat, m_blendsubtarget->obmat); - if (m_blendsubtarget->type == OB_ARMATURE) - m_subpose = m_blendsubtarget->pose; - } - if (m_target) + BLI_assert(m_constraint != nullptr && m_posechannel != nullptr); + + m_name = std::string(m_posechannel->name) + ":" + std::string(m_constraint->name); + + if (m_target) { m_target->RegisterObject(m_armature); - if (m_subtarget) + } + if (m_subtarget) { m_subtarget->RegisterObject(m_armature); - BLI_snprintf(m_name, sizeof(m_name), "%s:%s", m_posechannel->name, m_constraint->name); + } + + CopyBlenderTargets(); } BL_ArmatureConstraint::~BL_ArmatureConstraint() { - if (m_target) + if (m_target) { m_target->UnregisterObject(m_armature); - if (m_subtarget) + } + if (m_subtarget) { m_subtarget->UnregisterObject(m_armature); + } + + // Free the fake blender object targets without freeing the pose of an armature set in these objects. + if (m_blendtarget) { + m_blendtarget->pose = nullptr; + BKE_object_free(m_blendtarget); + } + if (m_blendsubtarget) { + m_blendsubtarget->pose = nullptr; + BKE_object_free(m_blendsubtarget); + } } -BL_ArmatureConstraint* BL_ArmatureConstraint::GetReplica() const +EXP_Value *BL_ArmatureConstraint::GetReplica() { - BL_ArmatureConstraint* replica = new BL_ArmatureConstraint(*this); - replica->ProcessReplica(); + BL_ArmatureConstraint *replica = new BL_ArmatureConstraint(*this); + return replica; } -void BL_ArmatureConstraint::ReParent(BL_ArmatureObject* armature) +void BL_ArmatureConstraint::CopyBlenderTargets() +{ + // Create the fake blender object target. + if (m_target) { + m_blendtarget = BKE_object_add_only_object(G.main, OB_EMPTY, m_target->GetName().c_str()); + } + if (m_subtarget) { + m_blendsubtarget = BKE_object_add_only_object(G.main, OB_EMPTY, m_subtarget->GetName().c_str()); + } + + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(m_constraint); + if (cti && cti->get_constraint_targets) { + ListBase listb = {nullptr, nullptr}; + cti->get_constraint_targets(m_constraint, &listb); + if (listb.first) { + bConstraintTarget *target = (bConstraintTarget *)listb.first; + if (m_blendtarget) { + target->tar = m_blendtarget; + } + if (target->next && m_blendsubtarget) { + target->next->tar = m_blendsubtarget; + } + } + if (cti->flush_constraint_targets) { + cti->flush_constraint_targets(m_constraint, &listb, 0); + } + } +} + +void BL_ArmatureConstraint::ReParent(BL_ArmatureObject *armature) { m_armature = armature; - if (m_target) + if (m_target) { m_target->RegisterObject(armature); - if (m_subtarget) + } + if (m_subtarget) { m_subtarget->RegisterObject(armature); + } + + const std::string constraintname = m_constraint->name; + const std::string posechannelname = m_posechannel->name; + m_constraint = nullptr; + m_posechannel = nullptr; + + bPose *newpose = m_armature->GetPose(); + // find the corresponding constraint in the new armature object - if (m_constraint) { - bPose* newpose = armature->GetOrigPose(); - char* constraint = m_constraint->name; - char* posechannel = m_posechannel->name; - bPoseChannel* pchan; - bConstraint* pcon; - m_constraint = NULL; - m_posechannel = NULL; - // and locate the constraint - for (pchan = (bPoseChannel*)newpose->chanbase.first; pchan; pchan = (bPoseChannel*)pchan->next) { - if (!strcmp(pchan->name, posechannel)) { - // now locate the constraint - for (pcon = (bConstraint *)pchan->constraints.first; pcon; pcon = (bConstraint *)pcon->next) { - if (!strcmp(pcon->name, constraint)) { - m_constraint = pcon; - m_posechannel = pchan; - break; - } + // and locate the constraint + for (bPoseChannel *pchan = (bPoseChannel *)newpose->chanbase.first; pchan; pchan = (bPoseChannel *)pchan->next) { + if (posechannelname == pchan->name) { + // now locate the constraint + for (bConstraint *pcon = (bConstraint *)pchan->constraints.first; pcon; pcon = (bConstraint *)pcon->next) { + if (constraintname == pcon->name) { + m_constraint = pcon; + m_posechannel = pchan; + break; } - break; } + break; } } + + CopyBlenderTargets(); } -void BL_ArmatureConstraint::Relink(CTR_Map *obj_map) +void BL_ArmatureConstraint::Relink(std::map& obj_map) { - void **h_obj = (*obj_map)[m_target]; - if (h_obj) { + KX_GameObject *obj = static_cast(obj_map[m_target]); + if (obj) { m_target->UnregisterObject(m_armature); - m_target = (KX_GameObject*)(*h_obj); + m_target = obj; m_target->RegisterObject(m_armature); } - h_obj = (*obj_map)[m_subtarget]; - if (h_obj) { + obj = static_cast(obj_map[m_subtarget]); + if (obj) { m_subtarget->UnregisterObject(m_armature); - m_subtarget = (KX_GameObject*)(*h_obj); + m_subtarget = obj; m_subtarget->RegisterObject(m_armature); } } -bool BL_ArmatureConstraint::UnlinkObject(SCA_IObject* clientobj) +bool BL_ArmatureConstraint::UnlinkObject(SCA_IObject *clientobj) { - bool res=false; + bool res = false; if (clientobj == m_target) { - m_target = NULL; + m_target = nullptr; res = true; } if (clientobj == m_subtarget) { - m_subtarget = NULL; + m_subtarget = nullptr; res = true; } return res; @@ -179,64 +222,53 @@ bool BL_ArmatureConstraint::UnlinkObject(SCA_IObject* clientobj) void BL_ArmatureConstraint::UpdateTarget() { - if (m_constraint && !(m_constraint->flag&CONSTRAINT_OFF) && (!m_blendtarget || m_target)) { + if (!(m_constraint->flag & CONSTRAINT_OFF) && (!m_blendtarget || m_target)) { if (m_blendtarget) { // external target, must be updated m_target->UpdateBlenderObjectMatrix(m_blendtarget); - if (m_pose && m_target->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) + + if (m_target->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) { // update the pose in case a bone is specified in the constraint target - m_blendtarget->pose = ((BL_ArmatureObject*)m_target)->GetOrigPose(); + m_blendtarget->pose = static_cast(m_target)->GetPose(); + } } if (m_blendsubtarget && m_subtarget) { m_subtarget->UpdateBlenderObjectMatrix(m_blendsubtarget); - if (m_subpose && m_subtarget->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) - m_blendsubtarget->pose = ((BL_ArmatureObject*)m_subtarget)->GetOrigPose(); - } - } -} - -void BL_ArmatureConstraint::RestoreTarget() -{ - if (m_constraint && !(m_constraint->flag&CONSTRAINT_OFF) && (!m_blendtarget || m_target)) { - if (m_blendtarget) { - copy_m4_m4(m_blendtarget->obmat, m_blendmat); - if (m_pose) - m_blendtarget->pose = m_pose; - } - if (m_blendsubtarget && m_subtarget) { - copy_m4_m4(m_blendsubtarget->obmat, m_blendsubmat); - if (m_subpose) - m_blendsubtarget->pose = m_subpose; + if (m_subtarget->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) { + m_blendsubtarget->pose = static_cast(m_subtarget)->GetPose(); + } } } } -bool BL_ArmatureConstraint::Match(const char* posechannel, const char* constraint) +bool BL_ArmatureConstraint::Match(const std::string& posechannel, const std::string& constraint) { - return (!strcmp(m_posechannel->name, posechannel) && !strcmp(m_constraint->name, constraint)); + return ((m_posechannel->name == posechannel) && (m_constraint->name == constraint)); } -void BL_ArmatureConstraint::SetTarget(KX_GameObject* target) +void BL_ArmatureConstraint::SetTarget(KX_GameObject *target) { if (m_blendtarget) { if (target != m_target) { m_target->UnregisterObject(m_armature); m_target = target; - if (m_target) + if (m_target) { m_target->RegisterObject(m_armature); + } } } } -void BL_ArmatureConstraint::SetSubtarget(KX_GameObject* subtarget) +void BL_ArmatureConstraint::SetSubtarget(KX_GameObject *subtarget) { if (m_blendsubtarget) { if (subtarget != m_subtarget) { m_subtarget->UnregisterObject(m_armature); m_subtarget = subtarget; - if (m_subtarget) + if (m_subtarget) { m_subtarget->RegisterObject(m_armature); + } } } @@ -247,117 +279,148 @@ void BL_ArmatureConstraint::SetSubtarget(KX_GameObject* subtarget) // PYTHON PyMethodDef BL_ArmatureConstraint::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; // order of definition of attributes, must match Attributes[] array -#define BCA_TYPE 0 -#define BCA_NAME 1 -#define BCA_ENFORCE 2 -#define BCA_HEADTAIL 3 -#define BCA_LINERROR 4 -#define BCA_ROTERROR 5 -#define BCA_TARGET 6 -#define BCA_SUBTARGET 7 -#define BCA_ACTIVE 8 -#define BCA_IKWEIGHT 9 -#define BCA_IKTYPE 10 -#define BCA_IKFLAG 11 -#define BCA_IKDIST 12 -#define BCA_IKMODE 13 +#define BCA_TYPE 0 +#define BCA_NAME 1 +#define BCA_ENFORCE 2 +#define BCA_HEADTAIL 3 +#define BCA_LINERROR 4 +#define BCA_ROTERROR 5 +#define BCA_TARGET 6 +#define BCA_SUBTARGET 7 +#define BCA_ACTIVE 8 +#define BCA_IKWEIGHT 9 +#define BCA_IKTYPE 10 +#define BCA_IKFLAG 11 +#define BCA_IKDIST 12 +#define BCA_IKMODE 13 PyAttributeDef BL_ArmatureConstraint::Attributes[] = { // Keep these attributes in order of BCA_ defines!!! used by py_attr_getattr and py_attr_setattr - KX_PYATTRIBUTE_RO_FUNCTION("type",BL_ArmatureConstraint,py_attr_getattr), - KX_PYATTRIBUTE_RO_FUNCTION("name",BL_ArmatureConstraint,py_attr_getattr), - KX_PYATTRIBUTE_RW_FUNCTION("enforce",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), - KX_PYATTRIBUTE_RW_FUNCTION("headtail",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), - KX_PYATTRIBUTE_RO_FUNCTION("lin_error",BL_ArmatureConstraint,py_attr_getattr), - KX_PYATTRIBUTE_RO_FUNCTION("rot_error",BL_ArmatureConstraint,py_attr_getattr), - KX_PYATTRIBUTE_RW_FUNCTION("target",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), - KX_PYATTRIBUTE_RW_FUNCTION("subtarget",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), - KX_PYATTRIBUTE_RW_FUNCTION("active",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), - KX_PYATTRIBUTE_RW_FUNCTION("ik_weight",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), - KX_PYATTRIBUTE_RO_FUNCTION("ik_type",BL_ArmatureConstraint,py_attr_getattr), - KX_PYATTRIBUTE_RO_FUNCTION("ik_flag",BL_ArmatureConstraint,py_attr_getattr), - KX_PYATTRIBUTE_RW_FUNCTION("ik_dist",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), - KX_PYATTRIBUTE_RW_FUNCTION("ik_mode",BL_ArmatureConstraint,py_attr_getattr,py_attr_setattr), - - { NULL } //Sentinel + EXP_PYATTRIBUTE_RO_FUNCTION("type", BL_ArmatureConstraint, py_attr_getattr), + EXP_PYATTRIBUTE_RO_FUNCTION("name", BL_ArmatureConstraint, py_attr_getattr), + EXP_PYATTRIBUTE_RW_FUNCTION("enforce", BL_ArmatureConstraint, py_attr_getattr, py_attr_setattr), + EXP_PYATTRIBUTE_RW_FUNCTION("headtail", BL_ArmatureConstraint, py_attr_getattr, py_attr_setattr), + EXP_PYATTRIBUTE_RO_FUNCTION("lin_error", BL_ArmatureConstraint, py_attr_getattr), + EXP_PYATTRIBUTE_RO_FUNCTION("rot_error", BL_ArmatureConstraint, py_attr_getattr), + EXP_PYATTRIBUTE_RW_FUNCTION("target", BL_ArmatureConstraint, py_attr_getattr, py_attr_setattr), + EXP_PYATTRIBUTE_RW_FUNCTION("subtarget", BL_ArmatureConstraint, py_attr_getattr, py_attr_setattr), + EXP_PYATTRIBUTE_RW_FUNCTION("active", BL_ArmatureConstraint, py_attr_getattr, py_attr_setattr), + EXP_PYATTRIBUTE_RW_FUNCTION("ik_weight", BL_ArmatureConstraint, py_attr_getattr, py_attr_setattr), + EXP_PYATTRIBUTE_RO_FUNCTION("ik_type", BL_ArmatureConstraint, py_attr_getattr), + EXP_PYATTRIBUTE_RO_FUNCTION("ik_flag", BL_ArmatureConstraint, py_attr_getattr), + EXP_PYATTRIBUTE_RW_FUNCTION("ik_dist", BL_ArmatureConstraint, py_attr_getattr, py_attr_setattr), + EXP_PYATTRIBUTE_RW_FUNCTION("ik_mode", BL_ArmatureConstraint, py_attr_getattr, py_attr_setattr), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *BL_ArmatureConstraint::py_attr_getattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *BL_ArmatureConstraint::py_attr_getattr(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - BL_ArmatureConstraint* self = static_cast(self_v); - bConstraint* constraint = self->m_constraint; - bKinematicConstraint* ikconstraint = (constraint && constraint->type == CONSTRAINT_TYPE_KINEMATIC) ? (bKinematicConstraint*)constraint->data : NULL; - int attr_order = attrdef-Attributes; + BL_ArmatureConstraint *self = static_cast(self_v); + bConstraint *constraint = self->m_constraint; + bKinematicConstraint *ikconstraint = (constraint && constraint->type == CONSTRAINT_TYPE_KINEMATIC) ? (bKinematicConstraint *)constraint->data : nullptr; + int attr_order = attrdef - Attributes; if (!constraint) { - PyErr_SetString(PyExc_AttributeError, "constraint is NULL"); - return NULL; + PyErr_SetString(PyExc_AttributeError, "constraint is nullptr"); + return nullptr; } switch (attr_order) { - case BCA_TYPE: - return PyLong_FromLong(constraint->type); - case BCA_NAME: - return PyUnicode_FromString(constraint->name); - case BCA_ENFORCE: - return PyFloat_FromDouble(constraint->enforce); - case BCA_HEADTAIL: - return PyFloat_FromDouble(constraint->headtail); - case BCA_LINERROR: - return PyFloat_FromDouble(constraint->lin_error); - case BCA_ROTERROR: - return PyFloat_FromDouble(constraint->rot_error); - case BCA_TARGET: - if (!self->m_target) - Py_RETURN_NONE; - else - return self->m_target->GetProxy(); - case BCA_SUBTARGET: - if (!self->m_subtarget) - Py_RETURN_NONE; - else - return self->m_subtarget->GetProxy(); - case BCA_ACTIVE: - return PyBool_FromLong((constraint->flag & CONSTRAINT_OFF) == 0); - case BCA_IKWEIGHT: - case BCA_IKTYPE: - case BCA_IKFLAG: - case BCA_IKDIST: - case BCA_IKMODE: - if (!ikconstraint) { - PyErr_SetString(PyExc_AttributeError, "constraint is not of IK type"); - return NULL; + case BCA_TYPE: + { + return PyLong_FromLong(constraint->type); + } + case BCA_NAME: + { + return PyUnicode_FromString(constraint->name); + } + case BCA_ENFORCE: + { + return PyFloat_FromDouble(constraint->enforce); + } + case BCA_HEADTAIL: + { + return PyFloat_FromDouble(constraint->headtail); + } + case BCA_LINERROR: + { + return PyFloat_FromDouble(constraint->lin_error); + } + case BCA_ROTERROR: + { + return PyFloat_FromDouble(constraint->rot_error); + } + case BCA_TARGET: + { + if (!self->m_target) { + Py_RETURN_NONE; + } + else { + return self->m_target->GetProxy(); + } + } + case BCA_SUBTARGET: + { + if (!self->m_subtarget) { + Py_RETURN_NONE; + } + else { + return self->m_subtarget->GetProxy(); + } + } + case BCA_ACTIVE: + { + return PyBool_FromLong((constraint->flag & CONSTRAINT_OFF) == 0); } - switch (attr_order) { case BCA_IKWEIGHT: - return PyFloat_FromDouble(ikconstraint->weight); case BCA_IKTYPE: - return PyLong_FromLong(ikconstraint->type); case BCA_IKFLAG: - return PyLong_FromLong(ikconstraint->flag); case BCA_IKDIST: - return PyFloat_FromDouble(ikconstraint->dist); case BCA_IKMODE: - return PyLong_FromLong(ikconstraint->mode); + { + if (!ikconstraint) { + PyErr_SetString(PyExc_AttributeError, "constraint is not of IK type"); + return nullptr; + } + switch (attr_order) { + case BCA_IKWEIGHT: + { + return PyFloat_FromDouble(ikconstraint->weight); + } + case BCA_IKTYPE: + { + return PyLong_FromLong(ikconstraint->type); + } + case BCA_IKFLAG: + { + return PyLong_FromLong(ikconstraint->flag); + } + case BCA_IKDIST: + { + return PyFloat_FromDouble(ikconstraint->dist); + } + case BCA_IKMODE: + return PyLong_FromLong(ikconstraint->mode); + } + // should not come here + break; } - // should not come here - break; } PyErr_SetString(PyExc_AttributeError, "constraint unknown attribute"); - return NULL; + return nullptr; } -int BL_ArmatureConstraint::py_attr_setattr(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int BL_ArmatureConstraint::py_attr_setattr(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - BL_ArmatureConstraint* self = static_cast(self_v); - bConstraint* constraint = self->m_constraint; - bKinematicConstraint* ikconstraint = (constraint && constraint->type == CONSTRAINT_TYPE_KINEMATIC) ? (bKinematicConstraint*)constraint->data : NULL; - int attr_order = attrdef-Attributes; + BL_ArmatureConstraint *self = static_cast(self_v); + bConstraint *constraint = self->m_constraint; + bKinematicConstraint *ikconstraint = (constraint && constraint->type == CONSTRAINT_TYPE_KINEMATIC) ? (bKinematicConstraint *)constraint->data : nullptr; + int attr_order = attrdef - Attributes; int ival; double dval; // char* sval; @@ -365,87 +428,105 @@ int BL_ArmatureConstraint::py_attr_setattr(void *self_v, const struct KX_PYATTRI KX_GameObject *oval; if (!constraint) { - PyErr_SetString(PyExc_AttributeError, "constraint is NULL"); + PyErr_SetString(PyExc_AttributeError, "constraint is nullptr"); return PY_SET_ATTR_FAIL; } switch (attr_order) { - case BCA_ENFORCE: - dval = PyFloat_AsDouble(value); - if (dval < 0.0 || dval > 1.0) { /* also accounts for non float */ - PyErr_SetString(PyExc_AttributeError, "constraint.enforce = float: BL_ArmatureConstraint, expected a float between 0 and 1"); - return PY_SET_ATTR_FAIL; - } - constraint->enforce = dval; - return PY_SET_ATTR_SUCCESS; - - case BCA_HEADTAIL: - dval = PyFloat_AsDouble(value); - if (dval < 0.0 || dval > 1.0) { /* also accounts for non float */ - PyErr_SetString(PyExc_AttributeError, "constraint.headtail = float: BL_ArmatureConstraint, expected a float between 0 and 1"); - return PY_SET_ATTR_FAIL; - } - constraint->headtail = dval; - return PY_SET_ATTR_SUCCESS; - - case BCA_TARGET: - if (!ConvertPythonToGameObject(logicmgr, value, &oval, true, "constraint.target = value: BL_ArmatureConstraint")) - return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error - self->SetTarget(oval); - return PY_SET_ATTR_SUCCESS; - - case BCA_SUBTARGET: - if (!ConvertPythonToGameObject(logicmgr, value, &oval, true, "constraint.subtarget = value: BL_ArmatureConstraint")) - return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error - self->SetSubtarget(oval); - return PY_SET_ATTR_SUCCESS; - - case BCA_ACTIVE: - ival = PyObject_IsTrue( value ); - if (ival == -1) { - PyErr_SetString(PyExc_AttributeError, "constraint.active = bool: BL_ArmatureConstraint, expected True or False"); - return PY_SET_ATTR_FAIL; - } - self->m_constraint->flag = (self->m_constraint->flag & ~CONSTRAINT_OFF) | ((ival)?0:CONSTRAINT_OFF); - return PY_SET_ATTR_SUCCESS; - - case BCA_IKWEIGHT: - case BCA_IKDIST: - case BCA_IKMODE: - if (!ikconstraint) { - PyErr_SetString(PyExc_AttributeError, "constraint is not of IK type"); - return PY_SET_ATTR_FAIL; - } - switch (attr_order) { - case BCA_IKWEIGHT: + case BCA_ENFORCE: + { dval = PyFloat_AsDouble(value); if (dval < 0.0 || dval > 1.0) { /* also accounts for non float */ - PyErr_SetString(PyExc_AttributeError, "constraint.weight = float: BL_ArmatureConstraint, expected a float between 0 and 1"); + PyErr_SetString(PyExc_AttributeError, "constraint.enforce = float: BL_ArmatureConstraint, expected a float between 0 and 1"); return PY_SET_ATTR_FAIL; } - ikconstraint->weight = dval; + constraint->enforce = dval; return PY_SET_ATTR_SUCCESS; - case BCA_IKDIST: + } + case BCA_HEADTAIL: + { dval = PyFloat_AsDouble(value); - if (dval < 0.0) { /* also accounts for non float */ - PyErr_SetString(PyExc_AttributeError, "constraint.ik_dist = float: BL_ArmatureConstraint, expected a positive float"); + if (dval < 0.0 || dval > 1.0) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, "constraint.headtail = float: BL_ArmatureConstraint, expected a float between 0 and 1"); return PY_SET_ATTR_FAIL; } - ikconstraint->dist = dval; + constraint->headtail = dval; return PY_SET_ATTR_SUCCESS; - case BCA_IKMODE: - ival = PyLong_AsLong(value); - if (ival < 0) { - PyErr_SetString(PyExc_AttributeError, "constraint.ik_mode = integer: BL_ArmatureConstraint, expected a positive integer"); + } + case BCA_TARGET: + { + if (!ConvertPythonToGameObject(logicmgr, value, &oval, true, "constraint.target = value: BL_ArmatureConstraint")) { + return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error + } + self->SetTarget(oval); + return PY_SET_ATTR_SUCCESS; + + } + case BCA_SUBTARGET: + { + if (!ConvertPythonToGameObject(logicmgr, value, &oval, true, "constraint.subtarget = value: BL_ArmatureConstraint")) { + return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error + } + self->SetSubtarget(oval); + return PY_SET_ATTR_SUCCESS; + + } + case BCA_ACTIVE: + { + ival = PyObject_IsTrue(value); + if (ival == -1) { + PyErr_SetString(PyExc_AttributeError, "constraint.active = bool: BL_ArmatureConstraint, expected True or False"); return PY_SET_ATTR_FAIL; } - ikconstraint->mode = ival; + self->m_constraint->flag = (self->m_constraint->flag & ~CONSTRAINT_OFF) | ((ival) ? 0 : CONSTRAINT_OFF); return PY_SET_ATTR_SUCCESS; + + } + case BCA_IKWEIGHT: + case BCA_IKDIST: + case BCA_IKMODE: + { + if (!ikconstraint) { + PyErr_SetString(PyExc_AttributeError, "constraint is not of IK type"); + return PY_SET_ATTR_FAIL; + } + switch (attr_order) { + case BCA_IKWEIGHT: + { + dval = PyFloat_AsDouble(value); + if (dval < 0.0 || dval > 1.0) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, "constraint.weight = float: BL_ArmatureConstraint, expected a float between 0 and 1"); + return PY_SET_ATTR_FAIL; + } + ikconstraint->weight = dval; + return PY_SET_ATTR_SUCCESS; + + } + case BCA_IKDIST: + { + dval = PyFloat_AsDouble(value); + if (dval < 0.0) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, "constraint.ik_dist = float: BL_ArmatureConstraint, expected a positive float"); + return PY_SET_ATTR_FAIL; + } + ikconstraint->dist = dval; + return PY_SET_ATTR_SUCCESS; + + } + case BCA_IKMODE: + ival = PyLong_AsLong(value); + if (ival < 0) { + PyErr_SetString(PyExc_AttributeError, "constraint.ik_mode = integer: BL_ArmatureConstraint, expected a positive integer"); + return PY_SET_ATTR_FAIL; + } + ikconstraint->mode = ival; + return PY_SET_ATTR_SUCCESS; + } + // should not come here + break; } - // should not come here - break; } diff --git a/source/gameengine/Converter/BL_ArmatureConstraint.h b/source/gameengine/Converter/BL_ArmatureConstraint.h index a2c70f37902a..2ad14f821214 100644 --- a/source/gameengine/Converter/BL_ArmatureConstraint.h +++ b/source/gameengine/Converter/BL_ArmatureConstraint.h @@ -33,9 +33,9 @@ #define __BL_ARMATURECONSTRAINT_H__ #include "DNA_constraint_types.h" -#include "CTR_HashedPtr.h" -#include "CTR_Map.h" -#include "EXP_PyObjectPlus.h" +#include "EXP_Value.h" + +#include class SCA_IObject; class KX_GameObject; @@ -45,12 +45,7 @@ struct bPoseChannel; struct Object; struct bPose; -/** - * SG_DList : element of controlled constraint list - * head = BL_ArmatureObject::m_controlledConstraints - * SG_QList : not used - */ -class BL_ArmatureConstraint : public PyObjectPlus +class BL_ArmatureConstraint : public EXP_Value { Py_Header @@ -58,34 +53,30 @@ class BL_ArmatureConstraint : public PyObjectPlus struct bConstraint* m_constraint; struct bPoseChannel* m_posechannel; class BL_ArmatureObject* m_armature; - char m_name[64]; + std::string m_name; KX_GameObject* m_target; KX_GameObject* m_subtarget; struct Object* m_blendtarget; struct Object* m_blendsubtarget; - float m_blendmat[4][4]; - float m_blendsubmat[4][4]; - struct bPose* m_pose; - struct bPose* m_subpose; public: - BL_ArmatureConstraint(class BL_ArmatureObject *armature, - struct bPoseChannel *posechannel, - struct bConstraint *constraint, + BL_ArmatureConstraint(class BL_ArmatureObject *armature, + struct bPoseChannel *posechannel, + struct bConstraint *constraint, KX_GameObject* target, KX_GameObject* subtarget); virtual ~BL_ArmatureConstraint(); - BL_ArmatureConstraint* GetReplica() const; + virtual EXP_Value *GetReplica(); + void CopyBlenderTargets(); void ReParent(BL_ArmatureObject* armature); - void Relink(CTR_Map *map); + void Relink(std::map& map); bool UnlinkObject(SCA_IObject* clientobj); void UpdateTarget(); - void RestoreTarget(); - bool Match(const char* posechannel, const char* constraint); - const char* GetName() { return m_name; } + bool Match(const std::string& posechannel, const std::string& constraint); + virtual std::string GetName() { return m_name; } void SetConstraintFlag(int flag) { @@ -115,10 +106,8 @@ class BL_ArmatureConstraint : public PyObjectPlus #ifdef WITH_PYTHON // Python access - virtual PyObject *py_repr(void); - - static PyObject *py_attr_getattr(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static int py_attr_setattr(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *py_attr_getattr(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static int py_attr_setattr(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); #endif /* WITH_PYTHON */ }; diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp index d9ecfd1cbee9..ec523fd499a4 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.cpp +++ b/source/gameengine/Converter/BL_ArmatureObject.cpp @@ -29,43 +29,35 @@ * \ingroup bgeconv */ - -#include "BL_ArmatureObject.h" -#include "BL_ActionActuator.h" -#include "BL_Action.h" -#include "KX_BlenderSceneConverter.h" #include "MEM_guardedalloc.h" -#include "BLI_blenlib.h" +#include "BLI_listbase.h" #include "BLI_math.h" -#include "BLI_utildefines.h" #include "BLI_ghash.h" -#include "BIK_api.h" #include "BKE_action.h" #include "BKE_armature.h" #include "BKE_object.h" #include "BKE_library.h" #include "BKE_global.h" +#include "BKE_constraint.h" +#include "DNA_armature_types.h" +#include "RNA_access.h" extern "C" { -#include "BKE_animsys.h" +# include "BKE_animsys.h" } -#include "BKE_constraint.h" -#include "CTR_Map.h" -#include "CTR_HashedPtr.h" -#include "MEM_guardedalloc.h" -#include "DNA_action_types.h" -#include "DNA_armature_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_constraint_types.h" -#include "RNA_access.h" -#include "KX_PythonInit.h" +#include "BL_ArmatureObject.h" +#include "BL_ActionActuator.h" +#include "BL_Action.h" +#include "BL_SceneConverter.h" +#include "KX_Globals.h" #include "KX_KetsjiEngine.h" +#include "RAS_DebugDraw.h" + #include "EXP_ListWrapper.h" -#include "MT_Matrix4x4.h" +#include "CM_Message.h" /** * Move here pose function for game engine so that we can mix with GE objects @@ -80,50 +72,47 @@ extern "C" { */ static void game_copy_pose(bPose **dst, bPose *src, int copy_constraint) { - bPose *out; - bPoseChannel *pchan, *outpchan; - GHash *ghash; - - /* the game engine copies the current armature pose and then swaps + /* The game engine copies the current armature pose and then swaps * the object pose pointer. this makes it possible to change poses * without affecting the original blender data. */ if (!src) { - *dst=NULL; + *dst = nullptr; return; } - else if (*dst==src) { - printf("game_copy_pose source and target are the same\n"); - *dst=NULL; + else if (*dst == src) { + CM_Warning("game_copy_pose source and target are the same"); + *dst = nullptr; return; } - out= (bPose*)MEM_dupallocN(src); - out->chanhash = NULL; - out->agroups.first= out->agroups.last= NULL; - out->ikdata = NULL; + bPose *out = (bPose *)MEM_dupallocN(src); + out->chanhash = nullptr; + out->agroups.first = out->agroups.last = nullptr; + out->ikdata = nullptr; out->ikparam = MEM_dupallocN(src->ikparam); out->flag |= POSE_GAME_ENGINE; BLI_duplicatelist(&out->chanbase, &src->chanbase); /* remap pointers */ - ghash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "game_copy_pose gh"); + GHash *ghash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "game_copy_pose gh"); - pchan= (bPoseChannel *)src->chanbase.first; - outpchan= (bPoseChannel *)out->chanbase.first; - for (; pchan; pchan=pchan->next, outpchan=outpchan->next) + bPoseChannel *pchan = (bPoseChannel *)src->chanbase.first; + bPoseChannel *outpchan = (bPoseChannel *)out->chanbase.first; + for (; pchan; pchan = pchan->next, outpchan = outpchan->next) { BLI_ghash_insert(ghash, pchan, outpchan); + } for (pchan = (bPoseChannel *)out->chanbase.first; pchan; pchan = pchan->next) { - pchan->parent= (bPoseChannel *)BLI_ghash_lookup(ghash, pchan->parent); - pchan->child= (bPoseChannel *)BLI_ghash_lookup(ghash, pchan->child); + pchan->parent = (bPoseChannel *)BLI_ghash_lookup(ghash, pchan->parent); + pchan->child = (bPoseChannel *)BLI_ghash_lookup(ghash, pchan->child); if (copy_constraint) { ListBase listb; // copy all constraint for backward compatibility - // BKE_constraints_copy NULLs listb, no need to make extern for this operation. + // BKE_constraints_copy nullptrs listb, no need to make extern for this operation. BKE_constraints_copy(&listb, &pchan->constraints, false); - pchan->constraints= listb; + pchan->constraints = listb; } else { BLI_listbase_clear(&pchan->constraints); @@ -135,41 +124,36 @@ static void game_copy_pose(bPose **dst, bPose *src, int copy_constraint) // fails to link, props are not used in the BGE yet. #if 0 - if (pchan->prop) - pchan->prop= IDP_CopyProperty(pchan->prop); + if (pchan->prop) { + pchan->prop = IDP_CopyProperty(pchan->prop); + } #endif - pchan->prop= NULL; + pchan->prop = nullptr; } - BLI_ghash_free(ghash, NULL, NULL); + BLI_ghash_free(ghash, nullptr, nullptr); // set acceleration structure for channel lookup BKE_pose_channels_hash_make(out); - *dst=out; + *dst = out; } - - -/* Only allowed for Poses with identical channels */ +// Only allowed for Poses with identical channels. static void game_blend_poses(bPose *dst, bPose *src, float srcweight, short mode) { - bPoseChannel *dchan; - const bPoseChannel *schan; - bConstraint *dcon, *scon; float dstweight; - int i; - if (mode == BL_Action::ACT_BLEND_BLEND) - { + if (mode == BL_Action::ACT_BLEND_BLEND) { dstweight = 1.0f - srcweight; - } else if (mode == BL_Action::ACT_BLEND_ADD) - { + } + else if (mode == BL_Action::ACT_BLEND_ADD) { dstweight = 1.0f; - } else { + } + else { dstweight = 1.0f; } - schan= (bPoseChannel *)src->chanbase.first; - for (dchan = (bPoseChannel *)dst->chanbase.first; dchan; dchan=(bPoseChannel *)dchan->next, schan= (bPoseChannel *)schan->next) { + bPoseChannel *schan = (bPoseChannel *)src->chanbase.first; + for (bPoseChannel *dchan = (bPoseChannel *)dst->chanbase.first; dchan; dchan = (bPoseChannel *)dchan->next, schan = (bPoseChannel *)schan->next) { // always blend on all channels since we don't know which one has been set /* quat interpolation done separate */ if (schan->rotmode == ROT_MODE_QUAT) { @@ -181,8 +165,9 @@ static void game_blend_poses(bPose *dst, bPose *src, float srcweight, short mode normalize_qt(dquat); normalize_qt(squat); - if (mode==BL_Action::ACT_BLEND_BLEND) + if (mode == BL_Action::ACT_BLEND_BLEND) { interp_qt_qtqt(dchan->quat, dquat, squat, srcweight); + } else { mul_fac_qt_fl(squat, srcweight); mul_qt_qtqt(dchan->quat, dquat, squat); @@ -191,239 +176,198 @@ static void game_blend_poses(bPose *dst, bPose *src, float srcweight, short mode normalize_qt(dchan->quat); } - for (i=0; i<3; i++) { + for (unsigned short i = 0; i < 3; i++) { /* blending for loc and scale are pretty self-explanatory... */ - dchan->loc[i] = (dchan->loc[i]*dstweight) + (schan->loc[i]*srcweight); - dchan->size[i] = 1.0f + ((dchan->size[i]-1.0f)*dstweight) + ((schan->size[i]-1.0f)*srcweight); + dchan->loc[i] = (dchan->loc[i] * dstweight) + (schan->loc[i] * srcweight); + dchan->size[i] = 1.0f + ((dchan->size[i] - 1.0f) * dstweight) + ((schan->size[i] - 1.0f) * srcweight); /* euler-rotation interpolation done here instead... */ // FIXME: are these results decent? - if (schan->rotmode) - dchan->eul[i] = (dchan->eul[i]*dstweight) + (schan->eul[i]*srcweight); + if (schan->rotmode) { + dchan->eul[i] = (dchan->eul[i] * dstweight) + (schan->eul[i] * srcweight); + } } - for (dcon= (bConstraint *)dchan->constraints.first, scon= (bConstraint *)schan->constraints.first; + for (bConstraint *dcon = (bConstraint *)dchan->constraints.first, *scon = (bConstraint *)schan->constraints.first; dcon && scon; dcon = dcon->next, scon = scon->next) { /* no 'add' option for constraint blending */ - dcon->enforce= dcon->enforce*(1.0f-srcweight) + scon->enforce*srcweight; + dcon->enforce = dcon->enforce * (1.0f - srcweight) + scon->enforce * srcweight; } } /* this pose is now in src time */ - dst->ctime= src->ctime; + dst->ctime = src->ctime; } -BL_ArmatureObject::BL_ArmatureObject( - void* sgReplicationInfo, - SG_Callbacks callbacks, - Object *armature, - Scene *scene, - int vert_deform_type) - -: KX_GameObject(sgReplicationInfo,callbacks), - m_controlledConstraints(), - m_poseChannels(), - m_scene(scene), // maybe remove later. needed for BKE_pose_where_is +BL_ArmatureObject::BL_ArmatureObject(void *sgReplicationInfo, + SG_Callbacks callbacks, + Object *armature, + Scene *scene) + :KX_GameObject(sgReplicationInfo, callbacks), + m_scene(scene), m_lastframe(0.0), - m_timestep(0.040), - m_vert_deform_type(vert_deform_type), - m_constraintNumber(0), - m_channelNumber(0), + m_drawDebug(false), m_lastapplyframe(0.0) { - m_origObjArma = armature; // Keep a copy of the original armature so we can fix drivers later + m_controlledConstraints = new EXP_ListValue(); + + // Keep a copy of the original armature so we can fix drivers later + m_origObjArma = armature; m_objArma = BKE_object_copy(G.main, armature); m_objArma->data = BKE_armature_copy(G.main, (bArmature *)armature->data); // During object replication ob->data is increase, we decrease it now because we get a copy. id_us_min(&((bArmature *)m_origObjArma->data)->id); - m_pose = m_objArma->pose; // need this to get iTaSC working ok in the BGE - m_pose->flag |= POSE_GAME_ENGINE; + m_objArma->pose->flag |= POSE_GAME_ENGINE; memcpy(m_obmat, m_objArma->obmat, sizeof(m_obmat)); - // The side-effect of this method registers this object as "animatable" with the KX_Scene. - GetActionManager(); + LoadChannels(); } BL_ArmatureObject::~BL_ArmatureObject() { - BL_ArmatureConstraint* constraint; - while ((constraint = m_controlledConstraints.Remove()) != NULL) { - delete constraint; - } - BL_ArmatureChannel* channel; - while ((channel = static_cast(m_poseChannels.Remove())) != NULL) { - delete channel; - } + m_poseChannels->Release(); + m_controlledConstraints->Release(); if (m_objArma) { BKE_libblock_free(G.main, m_objArma->data); + /* avoid BKE_libblock_free(G.main, m_objArma) + try to access m_objArma->data */ + m_objArma->data = nullptr; BKE_libblock_free(G.main, m_objArma); } } - -void BL_ArmatureObject::LoadConstraints(KX_BlenderSceneConverter* converter) +void BL_ArmatureObject::LoadConstraints(BL_SceneConverter& converter) { // first delete any existing constraint (should not have any) - while (!m_controlledConstraints.Empty()) { - BL_ArmatureConstraint* constraint = m_controlledConstraints.Remove(); - delete constraint; - } - m_constraintNumber = 0; + m_controlledConstraints->ReleaseAndRemoveAll(); // list all the constraint and convert them to BL_ArmatureConstraint // get the persistent pose structure - bPoseChannel* pchan; - bConstraint* pcon; - const bConstraintTypeInfo* cti; - Object* blendtarget; - KX_GameObject* gametarget; - KX_GameObject* gamesubtarget; // and locate the constraint - for (pchan = (bPoseChannel *)m_pose->chanbase.first; pchan; pchan = pchan->next) { - for (pcon = (bConstraint *)pchan->constraints.first; pcon; pcon = pcon->next) { - if (pcon->flag & CONSTRAINT_DISABLE) + for (bPoseChannel *pchan = (bPoseChannel *)m_objArma->pose->chanbase.first; pchan; pchan = pchan->next) { + for (bConstraint *pcon = (bConstraint *)pchan->constraints.first; pcon; pcon = pcon->next) { + if (pcon->flag & CONSTRAINT_DISABLE) { continue; + } // which constraint should we support? switch (pcon->type) { - case CONSTRAINT_TYPE_TRACKTO: - case CONSTRAINT_TYPE_DAMPTRACK: - case CONSTRAINT_TYPE_KINEMATIC: - case CONSTRAINT_TYPE_ROTLIKE: - case CONSTRAINT_TYPE_LOCLIKE: - case CONSTRAINT_TYPE_MINMAX: - case CONSTRAINT_TYPE_SIZELIKE: - case CONSTRAINT_TYPE_LOCKTRACK: - case CONSTRAINT_TYPE_STRETCHTO: - case CONSTRAINT_TYPE_CLAMPTO: - case CONSTRAINT_TYPE_TRANSFORM: - case CONSTRAINT_TYPE_DISTLIMIT: - case CONSTRAINT_TYPE_TRANSLIKE: - cti = BKE_constraint_typeinfo_get(pcon); - gametarget = gamesubtarget = NULL; - if (cti && cti->get_constraint_targets) { - ListBase listb = { NULL, NULL }; - cti->get_constraint_targets(pcon, &listb); - if (listb.first) { - bConstraintTarget* target = (bConstraintTarget*)listb.first; - if (target->tar && target->tar != m_objArma) { - // only remember external objects, self target is handled automatically - blendtarget = target->tar; - gametarget = converter->FindGameObject(blendtarget); - } - if (target->next != NULL) { - // secondary target - target = target->next; + case CONSTRAINT_TYPE_TRACKTO: + case CONSTRAINT_TYPE_DAMPTRACK: + case CONSTRAINT_TYPE_KINEMATIC: + case CONSTRAINT_TYPE_ROTLIKE: + case CONSTRAINT_TYPE_LOCLIKE: + case CONSTRAINT_TYPE_MINMAX: + case CONSTRAINT_TYPE_SIZELIKE: + case CONSTRAINT_TYPE_LOCKTRACK: + case CONSTRAINT_TYPE_STRETCHTO: + case CONSTRAINT_TYPE_CLAMPTO: + case CONSTRAINT_TYPE_TRANSFORM: + case CONSTRAINT_TYPE_DISTLIMIT: + case CONSTRAINT_TYPE_TRANSLIKE: + { + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(pcon); + KX_GameObject *gametarget = nullptr; + KX_GameObject *gamesubtarget = nullptr; + if (cti && cti->get_constraint_targets) { + ListBase listb = { nullptr, nullptr }; + cti->get_constraint_targets(pcon, &listb); + if (listb.first) { + bConstraintTarget *target = (bConstraintTarget *)listb.first; if (target->tar && target->tar != m_objArma) { - // only track external object - blendtarget = target->tar; - gamesubtarget = converter->FindGameObject(blendtarget); + // only remember external objects, self target is handled automatically + gametarget = converter.FindGameObject(target->tar); + } + if (target->next != nullptr) { + // secondary target + target = target->next; + if (target->tar && target->tar != m_objArma) { + // only track external object + gamesubtarget = converter.FindGameObject(target->tar); + } } } + if (cti->flush_constraint_targets) { + cti->flush_constraint_targets(pcon, &listb, 1); + } } - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(pcon, &listb, 1); + BL_ArmatureConstraint *constraint = new BL_ArmatureConstraint(this, pchan, pcon, gametarget, gamesubtarget); + m_controlledConstraints->Add(constraint); } - BL_ArmatureConstraint* constraint = new BL_ArmatureConstraint(this, pchan, pcon, gametarget, gamesubtarget); - m_controlledConstraints.AddBack(constraint); - m_constraintNumber++; } } } // If we have constraints, make sure we get treated as an "animated" object - if (m_constraintNumber > 0) + if (m_controlledConstraints->GetCount() > 0) { GetActionManager(); + } } -BL_ArmatureConstraint* BL_ArmatureObject::GetConstraint(const char* posechannel, const char* constraintname) +size_t BL_ArmatureObject::GetConstraintNumber() const { - SG_DList::iterator cit(m_controlledConstraints); - for (cit.begin(); !cit.end(); ++cit) { - BL_ArmatureConstraint* constraint = *cit; - if (constraint->Match(posechannel, constraintname)) - return constraint; - } - return NULL; + return m_controlledConstraints->GetCount(); } -BL_ArmatureConstraint* BL_ArmatureObject::GetConstraint(const char* posechannelconstraint) +BL_ArmatureConstraint *BL_ArmatureObject::GetConstraint(const std::string& posechannel, const std::string& constraintname) { - // performance: use hash string instead of plain string compare - SG_DList::iterator cit(m_controlledConstraints); - for (cit.begin(); !cit.end(); ++cit) { - BL_ArmatureConstraint* constraint = *cit; - if (!strcmp(constraint->GetName(), posechannelconstraint)) - return constraint; - } - return NULL; + return m_controlledConstraints->FindIf( + [&posechannel, &constraintname](BL_ArmatureConstraint *constraint) { + return constraint->Match(posechannel, constraintname); + }); +} + +BL_ArmatureConstraint *BL_ArmatureObject::GetConstraint(const std::string& posechannelconstraint) +{ + return static_cast(m_controlledConstraints->FindValue(posechannelconstraint)); } -BL_ArmatureConstraint* BL_ArmatureObject::GetConstraint(int index) +BL_ArmatureConstraint *BL_ArmatureObject::GetConstraint(int index) { - SG_DList::iterator cit(m_controlledConstraints); - for (cit.begin(); !cit.end() && index; ++cit, --index); - return (cit.end()) ? NULL : *cit; + return static_cast(m_controlledConstraints->GetValue(index)); } /* this function is called to populate the m_poseChannels list */ void BL_ArmatureObject::LoadChannels() { - if (m_poseChannels.Empty()) { - bPoseChannel* pchan; - BL_ArmatureChannel* proxy; - - m_channelNumber = 0; - for (pchan = (bPoseChannel *)m_pose->chanbase.first; pchan; pchan=(bPoseChannel *)pchan->next) { - proxy = new BL_ArmatureChannel(this, pchan); - m_poseChannels.AddBack(proxy); - m_channelNumber++; - } + m_poseChannels = new EXP_ListValue(); + for (bPoseChannel *pchan = (bPoseChannel *)m_objArma->pose->chanbase.first; pchan; pchan = (bPoseChannel *)pchan->next) { + BL_ArmatureChannel *channel = new BL_ArmatureChannel(this, pchan); + m_poseChannels->Add(channel); } } -BL_ArmatureChannel* BL_ArmatureObject::GetChannel(bPoseChannel* pchan) +size_t BL_ArmatureObject::GetChannelNumber() const { - LoadChannels(); - SG_DList::iterator cit(m_poseChannels); - for (cit.begin(); !cit.end(); ++cit) - { - BL_ArmatureChannel* channel = *cit; - if (channel->m_posechannel == pchan) - return channel; - } - return NULL; + return m_poseChannels->GetCount(); } -BL_ArmatureChannel* BL_ArmatureObject::GetChannel(const char* str) +BL_ArmatureChannel *BL_ArmatureObject::GetChannel(bPoseChannel *pchan) { - LoadChannels(); - SG_DList::iterator cit(m_poseChannels); - for (cit.begin(); !cit.end(); ++cit) - { - BL_ArmatureChannel* channel = *cit; - if (!strcmp(channel->m_posechannel->name, str)) - return channel; - } - return NULL; + return m_poseChannels->FindIf([&pchan](BL_ArmatureChannel *channel) { + return channel->m_posechannel == pchan; + }); } -BL_ArmatureChannel* BL_ArmatureObject::GetChannel(int index) +BL_ArmatureChannel *BL_ArmatureObject::GetChannel(const std::string& str) { - LoadChannels(); - if (index < 0 || index >= m_channelNumber) - return NULL; - SG_DList::iterator cit(m_poseChannels); - for (cit.begin(); !cit.end() && index; ++cit, --index); - return (cit.end()) ? NULL : *cit; + return static_cast(m_poseChannels->FindValue(str)); } -CValue* BL_ArmatureObject::GetReplica() +BL_ArmatureChannel *BL_ArmatureObject::GetChannel(int index) { - BL_ArmatureObject* replica = new BL_ArmatureObject(*this); + if (index < 0 || index >= m_poseChannels->GetCount()) { + return nullptr; + } + return static_cast(m_poseChannels->GetValue(index)); +} + +EXP_Value *BL_ArmatureObject::GetReplica() +{ + BL_ArmatureObject *replica = new BL_ArmatureObject(*this); replica->ProcessReplica(); return replica; } @@ -432,106 +376,104 @@ void BL_ArmatureObject::ProcessReplica() { KX_GameObject::ProcessReplica(); - bArmature* tmp = (bArmature*)m_objArma->data; + // Replicate each constraints. + m_controlledConstraints = static_cast *>(m_controlledConstraints->GetReplica()); + + bArmature *tmp = (bArmature *)m_objArma->data; m_objArma = BKE_object_copy(G.main, m_objArma); m_objArma->data = BKE_armature_copy(G.main, tmp); - m_pose = m_objArma->pose; + + LoadChannels(); +} + +int BL_ArmatureObject::GetGameObjectType() const +{ + return OBJ_ARMATURE; } void BL_ArmatureObject::ReParentLogic() { - SG_DList::iterator cit(m_controlledConstraints); - for (cit.begin(); !cit.end(); ++cit) { - (*cit)->ReParent(this); + for (BL_ArmatureConstraint *constraint : m_controlledConstraints) { + constraint->ReParent(this); } KX_GameObject::ReParentLogic(); } -void BL_ArmatureObject::Relink(CTR_Map *obj_map) +void BL_ArmatureObject::Relink(std::map& obj_map) { - SG_DList::iterator cit(m_controlledConstraints); - for (cit.begin(); !cit.end(); ++cit) { - (*cit)->Relink(obj_map); + for (BL_ArmatureConstraint *constraint : m_controlledConstraints) { + constraint->Relink(obj_map); } KX_GameObject::Relink(obj_map); } -bool BL_ArmatureObject::UnlinkObject(SCA_IObject* clientobj) +bool BL_ArmatureObject::UnlinkObject(SCA_IObject *clientobj) { // clientobj is being deleted, make sure we don't hold any reference to it bool res = false; - SG_DList::iterator cit(m_controlledConstraints); - for (cit.begin(); !cit.end(); ++cit) { - res |= (*cit)->UnlinkObject(clientobj); + for (BL_ArmatureConstraint *constraint : m_controlledConstraints) { + res |= constraint->UnlinkObject(clientobj); } return res; } -void BL_ArmatureObject::ApplyPose() +void BL_ArmatureObject::ApplyPose() // TODO: bouger dans SetPoseByAction ? { - m_armpose = m_objArma->pose; - m_objArma->pose = m_pose; - // in the GE, we use ctime to store the timestep - m_pose->ctime = (float)m_timestep; - //m_scene->r.cfra++; if (m_lastapplyframe != m_lastframe) { // update the constraint if any, first put them all off so that only the active ones will be updated - SG_DList::iterator cit(m_controlledConstraints); - for (cit.begin(); !cit.end(); ++cit) { - (*cit)->UpdateTarget(); + for (BL_ArmatureConstraint *constraint : m_controlledConstraints) { + constraint->UpdateTarget(); } // update ourself UpdateBlenderObjectMatrix(m_objArma); - BKE_pose_where_is(m_scene, m_objArma); // XXX + BKE_pose_where_is(m_scene, m_objArma); // restore ourself - memcpy(m_objArma->obmat, m_obmat, sizeof(m_obmat)); - // restore active targets - for (cit.begin(); !cit.end(); ++cit) { - (*cit)->RestoreTarget(); - } + memcpy(m_objArma->obmat, m_obmat, sizeof(m_obmat)); // TODO: Pourquoi restorer ? m_lastapplyframe = m_lastframe; } } -void BL_ArmatureObject::RestorePose() -{ - m_objArma->pose = m_armpose; - m_armpose = NULL; -} - -void BL_ArmatureObject::SetPose(bPose *pose) -{ - extract_pose_from_pose(m_pose, pose); - m_lastapplyframe = -1.0; -} - void BL_ArmatureObject::SetPoseByAction(bAction *action, float localtime) { - Object *arm = GetArmatureObject(); - PointerRNA ptrrna; - RNA_id_pointer_create(&arm->id, &ptrrna); + RNA_id_pointer_create(&m_objArma->id, &ptrrna); - animsys_evaluate_action(&ptrrna, action, NULL, localtime); + animsys_evaluate_action(&ptrrna, action, nullptr, localtime); } void BL_ArmatureObject::BlendInPose(bPose *blend_pose, float weight, short mode) { - game_blend_poses(m_pose, blend_pose, weight, mode); + game_blend_poses(m_objArma->pose, blend_pose, weight, mode); } bool BL_ArmatureObject::UpdateTimestep(double curtime) { if (curtime != m_lastframe) { - // compute the timestep for the underlying IK algorithm - m_timestep = curtime-m_lastframe; - m_lastframe= curtime; + /* Compute the timestep for the underlying IK algorithm, + * in the GE, we use ctime to store the timestep. + */ + m_objArma->pose->ctime = (float)(curtime - m_lastframe); + m_lastframe = curtime; } return false; } -void BL_ArmatureObject::GetPose(bPose **pose) +Object *BL_ArmatureObject::GetArmatureObject() +{ + return m_objArma; +} +Object *BL_ArmatureObject::GetOrigArmatureObject() +{ + return m_origObjArma; +} + +int BL_ArmatureObject::GetVertDeformType() const +{ + return ((bArmature *)m_objArma->data)->gevertdeformer; +} + +void BL_ArmatureObject::GetPose(bPose **pose) const { /* If the caller supplies a null pose, create a new one. */ /* Otherwise, copy the armature's pose channels into the caller-supplied pose */ @@ -542,38 +484,62 @@ void BL_ArmatureObject::GetPose(bPose **pose) * a crash and memory leakage when * &BL_ActionActuator::m_pose is freed */ - game_copy_pose(pose, m_pose, 0); + game_copy_pose(pose, m_objArma->pose, 0); } else { - if (*pose == m_pose) + if (*pose == m_objArma->pose) { // no need to copy if the pointers are the same return; + } - extract_pose_from_pose(*pose, m_pose); + extract_pose_from_pose(*pose, m_objArma->pose); } } +bPose *BL_ArmatureObject::GetPose() const +{ + return m_objArma->pose; +} + double BL_ArmatureObject::GetLastFrame() { return m_lastframe; } -bool BL_ArmatureObject::GetBoneMatrix(Bone* bone, MT_Matrix4x4& matrix) +bool BL_ArmatureObject::GetBoneTransform(Bone *bone, mt::mat3x4& trans) { - bPoseChannel *pchan; - ApplyPose(); - pchan = BKE_pose_channel_find_name(m_objArma->pose, bone->name); - if (pchan) - matrix.setValue(&pchan->pose_mat[0][0]); - RestorePose(); + bPoseChannel *pchan = BKE_pose_channel_find_name(m_objArma->pose, bone->name); + if (pchan) { + trans = mt::mat3x4(mt::vec3(pchan->pose_mat[0]), mt::vec3(pchan->pose_mat[1]), + mt::vec3(pchan->pose_mat[2]), mt::vec3(pchan->pose_mat[3])); + } - return (pchan != NULL); + return (pchan != nullptr); } -float BL_ArmatureObject::GetBoneLength(Bone* bone) const +bool BL_ArmatureObject::GetDrawDebug() const { - return (float)(MT_Point3(bone->head) - MT_Point3(bone->tail)).length(); + return m_drawDebug; +} + +void BL_ArmatureObject::DrawDebug(RAS_DebugDraw& debugDraw) +{ + const mt::vec3& scale = NodeGetWorldScaling(); + const mt::mat3& rot = NodeGetWorldOrientation(); + const mt::vec3& pos = NodeGetWorldPosition(); + + for (bPoseChannel *pchan = (bPoseChannel *)m_objArma->pose->chanbase.first; pchan; pchan = pchan->next) { + mt::vec3 head = rot * (mt::vec3(pchan->pose_head) * scale) + pos; + mt::vec3 tail = rot * (mt::vec3(pchan->pose_tail) * scale) + pos; + debugDraw.DrawLine(tail, head, mt::vec4(1.0f, 0.0f, 0.0f, 1.0f)); + } + m_drawDebug = false; +} + +float BL_ArmatureObject::GetBoneLength(Bone *bone) const +{ + return (float)(mt::vec3(bone->head) - mt::vec3(bone->tail)).Length(); } #ifdef WITH_PYTHON @@ -581,9 +547,9 @@ float BL_ArmatureObject::GetBoneLength(Bone* bone) const // PYTHON PyTypeObject BL_ArmatureObject::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "BL_ArmatureObject", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -594,93 +560,61 @@ PyTypeObject BL_ArmatureObject::Type = { 0, &KX_GameObject::Sequence, &KX_GameObject::Mapping, - 0,0,0, - NULL, - NULL, + 0, 0, 0, + nullptr, + nullptr, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &KX_GameObject::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef BL_ArmatureObject::Methods[] = { - KX_PYMETHODTABLE_NOARGS(BL_ArmatureObject, update), - {NULL,NULL} //Sentinel + EXP_PYMETHODTABLE_NOARGS(BL_ArmatureObject, update), + EXP_PYMETHODTABLE_NOARGS(BL_ArmatureObject, draw), + {nullptr, nullptr} //Sentinel }; PyAttributeDef BL_ArmatureObject::Attributes[] = { - KX_PYATTRIBUTE_RO_FUNCTION("constraints", BL_ArmatureObject, pyattr_get_constraints), - KX_PYATTRIBUTE_RO_FUNCTION("channels", BL_ArmatureObject, pyattr_get_channels), - {NULL} //Sentinel + EXP_PYATTRIBUTE_RO_FUNCTION("constraints", BL_ArmatureObject, pyattr_get_constraints), + EXP_PYATTRIBUTE_RO_FUNCTION("channels", BL_ArmatureObject, pyattr_get_channels), + EXP_PYATTRIBUTE_NULL //Sentinel }; -static int bl_armature_object_get_constraints_size_cb(void *self_v) -{ - return ((BL_ArmatureObject *)self_v)->GetConstraintNumber(); -} - -static PyObject *bl_armature_object_get_constraints_item_cb(void *self_v, int index) -{ - return ((BL_ArmatureObject *)self_v)->GetConstraint(index)->GetProxy(); -} - -static const char *bl_armature_object_get_constraints_item_name_cb(void *self_v, int index) +PyObject *BL_ArmatureObject::pyattr_get_constraints(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - return ((BL_ArmatureObject *)self_v)->GetConstraint(index)->GetName(); -} - -PyObject *BL_ArmatureObject::pyattr_get_constraints(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - return (new CListWrapper(self_v, - ((BL_ArmatureObject *)self_v)->GetProxy(), - NULL, - bl_armature_object_get_constraints_size_cb, - bl_armature_object_get_constraints_item_cb, - bl_armature_object_get_constraints_item_name_cb, - NULL))->NewProxy(true); -} - -static int bl_armature_object_get_channels_size_cb(void *self_v) -{ - return ((BL_ArmatureObject *)self_v)->GetChannelNumber(); + BL_ArmatureObject *self = static_cast(self_v); + return self->m_controlledConstraints->GetProxy(); } -static PyObject *bl_armature_object_get_channels_item_cb(void *self_v, int index) +PyObject *BL_ArmatureObject::pyattr_get_channels(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - return ((BL_ArmatureObject *)self_v)->GetChannel(index)->GetProxy(); + BL_ArmatureObject *self = static_cast(self_v); + return self->m_poseChannels->GetProxy(); } -static const char *bl_armature_object_get_channels_item_name_cb(void *self_v, int index) +EXP_PYMETHODDEF_DOC_NOARGS(BL_ArmatureObject, update, + "update()\n" + "Make sure that the armature will be updated on next graphic frame.\n" + "This is automatically done if a KX_ArmatureActuator with mode run is active\n" + "or if an action is playing. This function is useful in other cases.\n") { - return ((BL_ArmatureObject *)self_v)->GetChannel(index)->GetName(); + UpdateTimestep(KX_GetActiveEngine()->GetFrameTime()); + Py_RETURN_NONE; } -PyObject *BL_ArmatureObject::pyattr_get_channels(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +EXP_PYMETHODDEF_DOC_NOARGS(BL_ArmatureObject, draw, + "Draw Debug Armature") { - BL_ArmatureObject *self = static_cast(self_v); - self->LoadChannels(); // make sure we have the channels - return (new CListWrapper(self_v, - self->GetProxy(), - NULL, - bl_armature_object_get_channels_size_cb, - bl_armature_object_get_channels_item_cb, - bl_armature_object_get_channels_item_name_cb, - NULL))->NewProxy(true); -} - -KX_PYMETHODDEF_DOC_NOARGS(BL_ArmatureObject, update, - "update()\n" - "Make sure that the armature will be updated on next graphic frame.\n" - "This is automatically done if a KX_ArmatureActuator with mode run is active\n" - "or if an action is playing. This function is useful in other cases.\n") -{ - UpdateTimestep(KX_GetActiveEngine()->GetFrameTime()); + /* Armature bones are updated later, so we only set to true a flag + * to request a debug draw later in ApplyPose after updating bones. */ + m_drawDebug = true; Py_RETURN_NONE; } diff --git a/source/gameengine/Converter/BL_ArmatureObject.h b/source/gameengine/Converter/BL_ArmatureObject.h index 65513aa579c4..9a49d8a4cb91 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.h +++ b/source/gameengine/Converter/BL_ArmatureObject.h @@ -36,110 +36,97 @@ #include "BL_ArmatureConstraint.h" #include "BL_ArmatureChannel.h" -#include "SG_IObject.h" -#include -#include - struct bArmature; struct Bone; +struct bPose; struct bConstraint; -class BL_ActionActuator; -class BL_ArmatureActuator; -class MT_Matrix4x4; struct Object; -class KX_BlenderSceneConverter; +class RAS_DebugDraw; class BL_ArmatureObject : public KX_GameObject { Py_Header + +protected: + /// List element: BL_ArmatureConstraint. + EXP_ListValue *m_controlledConstraints; + /// List element: BL_ArmatureChannel. + EXP_ListValue *m_poseChannels; + Object *m_objArma; + Object *m_origObjArma; + // Need for BKE_pose_where_is. + Scene *m_scene; + double m_lastframe; + size_t m_constraintNumber; + size_t m_channelNumber; + /// Store the original armature object matrix. + float m_obmat[4][4]; + /// Set to true to allow draw debug info for one frame, reset in DrawDebugArmature. + bool m_drawDebug; + + double m_lastapplyframe; + public: + BL_ArmatureObject(void *sgReplicationInfo, + SG_Callbacks callbacks, + Object *armature, + Scene *scene); + virtual ~BL_ArmatureObject(); - double GetLastFrame (); + virtual EXP_Value *GetReplica(); virtual void ProcessReplica(); + virtual int GetGameObjectType() const; virtual void ReParentLogic(); - virtual void Relink(CTR_Map *obj_map); - virtual bool UnlinkObject(SCA_IObject* clientobj); - - BL_ArmatureObject( - void* sgReplicationInfo, - SG_Callbacks callbacks, - Object *armature, - Scene *scene, - int vert_deform_type - ); - virtual ~BL_ArmatureObject(); + virtual void Relink(std::map& obj_map); + virtual bool UnlinkObject(SCA_IObject *clientobj); - virtual CValue* GetReplica(); - void GetPose(struct bPose **pose); - void SetPose (struct bPose *pose); - struct bPose *GetOrigPose() {return m_pose;} // never edit this, only for accessing names + double GetLastFrame(); + void GetPose(bPose **pose) const; + /// Never edit this, only for accessing names. + bPose *GetPose() const; void ApplyPose(); - void SetPoseByAction(struct bAction* action, float localtime); - void BlendInPose(struct bPose *blend_pose, float weight, short mode); - void RestorePose(); + void SetPoseByAction(bAction *action, float localtime); + void BlendInPose(bPose *blend_pose, float weight, short mode); bool UpdateTimestep(double curtime); - struct bArmature *GetArmature() { return (bArmature*)m_objArma->data; } - const struct bArmature * GetArmature() const { return (bArmature*)m_objArma->data; } - const struct Scene * GetScene() const { return m_scene; } - - Object* GetArmatureObject() {return m_objArma;} - Object* GetOrigArmatureObject() {return m_origObjArma;} - - int GetVertDeformType() {return m_vert_deform_type;} + Object *GetArmatureObject(); + Object *GetOrigArmatureObject(); + int GetVertDeformType() const; + bool GetDrawDebug() const; + void DrawDebug(RAS_DebugDraw& debugDraw); // for constraint python API - void LoadConstraints(KX_BlenderSceneConverter* converter); - size_t GetConstraintNumber() const { return m_constraintNumber; } - BL_ArmatureConstraint* GetConstraint(const char* posechannel, const char* constraint); - BL_ArmatureConstraint* GetConstraint(const char* posechannelconstraint); - BL_ArmatureConstraint* GetConstraint(int index); + void LoadConstraints(BL_SceneConverter& converter); + size_t GetConstraintNumber() const; + BL_ArmatureConstraint *GetConstraint(const std::string& posechannel, const std::string& constraint); + BL_ArmatureConstraint *GetConstraint(const std::string& posechannelconstraint); + BL_ArmatureConstraint *GetConstraint(int index); + // for pose channel python API void LoadChannels(); - size_t GetChannelNumber() const { return m_channelNumber; } - BL_ArmatureChannel* GetChannel(bPoseChannel* channel); - BL_ArmatureChannel* GetChannel(const char* channel); - BL_ArmatureChannel* GetChannel(int index); + size_t GetChannelNumber() const; + BL_ArmatureChannel *GetChannel(bPoseChannel *channel); + BL_ArmatureChannel *GetChannel(const std::string& channel); + BL_ArmatureChannel *GetChannel(int index); - /// Retrieve the pose matrix for the specified bone. + /// Retrieve the pose transform for the specified bone. /// Returns true on success. - bool GetBoneMatrix(Bone* bone, MT_Matrix4x4& matrix); + bool GetBoneTransform(Bone *bone, mt::mat3x4& trans); /// Returns the bone length. The end of the bone is in the local y direction. - float GetBoneLength(Bone* bone) const; - - virtual int GetGameObjectType() { return OBJ_ARMATURE; } + float GetBoneLength(Bone *bone) const; #ifdef WITH_PYTHON // PYTHON - static PyObject *pyattr_get_constraints(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_channels(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - KX_PYMETHOD_DOC_NOARGS(BL_ArmatureObject, update); + static PyObject *pyattr_get_constraints(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_channels(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + EXP_PYMETHOD_DOC_NOARGS(BL_ArmatureObject, update); + EXP_PYMETHOD_DOC_NOARGS(BL_ArmatureObject, draw); #endif /* WITH_PYTHON */ - -protected: - /* list element: BL_ArmatureConstraint. Use SG_DListHead to have automatic list replication */ - SG_DListHead m_controlledConstraints; - /* list element: BL_ArmatureChannel. Use SG_DList to avoid list replication */ - SG_DList m_poseChannels; - Object *m_objArma; - Object *m_origObjArma; - struct bPose *m_pose; - struct bPose *m_armpose; - struct Scene *m_scene; // need for BKE_pose_where_is - double m_lastframe; - double m_timestep; // delta since last pose evaluation. - int m_vert_deform_type; - size_t m_constraintNumber; - size_t m_channelNumber; - // store the original armature object matrix - float m_obmat[4][4]; - - double m_lastapplyframe; }; #endif /* __BL_ARMATUREOBJECT_H__ */ diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index 43ec225f789e..ee7cd6c3c414 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -51,64 +51,85 @@ #include #include -#include "BL_BlenderDataConversion.h" -#include "MT_Transform.h" -#include "MT_MinMax.h" +#include "mathfu.h" -#include "PHY_Pro.h" #include "PHY_IPhysicsEnvironment.h" +#include "DummyPhysicsEnvironment.h" + +#ifdef WITH_BULLET +# include "CcdPhysicsEnvironment.h" +# include "CcdGraphicController.h" +#endif -#include "RAS_MeshObject.h" -#include "RAS_IRasterizer.h" +#include "RAS_Rasterizer.h" #include "RAS_ILightObject.h" -#include "KX_ConvertActuators.h" -#include "KX_ConvertControllers.h" -#include "KX_ConvertSensors.h" +#include "RAS_ICanvas.h" +#include "RAS_BucketManager.h" +#include "RAS_BoundingBoxManager.h" +#include "RAS_IMaterial.h" + +#include "SG_Node.h" +#include "SG_BBox.h" + #include "SCA_LogicManager.h" #include "SCA_TimeEventManager.h" +#include "KX_SoftBodyDeformer.h" #include "KX_ClientObjectInfo.h" #include "KX_Scene.h" #include "KX_GameObject.h" -#include "KX_Light.h" +#include "KX_LightObject.h" #include "KX_Camera.h" #include "KX_EmptyObject.h" #include "KX_FontObject.h" - -#include "RAS_TexMatrix.h" -#include "RAS_ICanvas.h" -#include "RAS_Polygon.h" -#include "RAS_TexVert.h" -#include "RAS_BucketManager.h" -#include "RAS_IPolygonMaterial.h" -#include "BL_Material.h" +#include "KX_LodManager.h" +#include "KX_PythonComponent.h" +#include "KX_WorldInfo.h" +#include "KX_Mesh.h" #include "KX_BlenderMaterial.h" -#include "BL_Texture.h" +#include "KX_TextureRendererManager.h" +#include "KX_Globals.h" +#include "KX_PyConstraintBinding.h" +#include "KX_KetsjiEngine.h" +#include "KX_NodeRelationships.h" +#include "KX_BoneParentNodeRelationship.h" +#include "KX_MotionState.h" +#include "KX_NavMeshObject.h" +#include "KX_ObstacleSimulation.h" -#include "BKE_main.h" -#include "BKE_global.h" -#include "BKE_object.h" +#include "BL_BlenderDataConversion.h" #include "BL_ModifierDeformer.h" #include "BL_ShapeDeformer.h" #include "BL_SkinDeformer.h" #include "BL_MeshDeformer.h" -#include "KX_SoftBodyDeformer.h" -#include "BLI_utildefines.h" -#include "BLI_listbase.h" +#include "BL_Texture.h" +#include "BL_SceneConverter.h" +#include "BL_ConvertActuators.h" +#include "BL_ConvertControllers.h" +#include "BL_ConvertSensors.h" +#include "BL_ConvertProperties.h" +#include "BL_ConvertObjectInfo.h" +#include "BL_ArmatureObject.h" +#include "BL_ActionData.h" -#include "KX_WorldInfo.h" +#include "LA_SystemCommandLine.h" -#include "KX_KetsjiEngine.h" -#include "KX_BlenderSceneConverter.h" +#include "CM_Message.h" + +#include "GPU_texture.h" -/* This little block needed for linking to Blender... */ +// This little block needed for linking to Blender... #ifdef WIN32 #include "BLI_winstuff.h" #endif -/* This list includes only data type definitions */ +#include "BLI_utildefines.h" +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_threads.h" + #include "DNA_object_types.h" #include "DNA_material_types.h" #include "DNA_texture_types.h" @@ -132,1298 +153,721 @@ #include "DNA_action_types.h" #include "DNA_object_force_types.h" #include "DNA_constraint_types.h" +#include "DNA_python_component_types.h" #include "MEM_guardedalloc.h" +#include "BKE_main.h" +#include "BKE_global.h" +#include "BKE_object.h" +#include "BKE_python_component.h" #include "BKE_key.h" #include "BKE_mesh.h" -#include "BLI_math.h" - extern "C" { -#include "BKE_scene.h" -#include "BKE_customdata.h" -#include "BKE_cdderivedmesh.h" -#include "BKE_DerivedMesh.h" -#include "BKE_material.h" /* give_current_material */ -#include "BKE_image.h" -#include "IMB_imbuf_types.h" -#include "BKE_displist.h" - -extern Material defmaterial; /* material.c */ +# include "BKE_scene.h" +# include "BKE_customdata.h" +# include "BKE_cdderivedmesh.h" +# include "BKE_DerivedMesh.h" +# include "BKE_material.h" // Needed for give_current_material. +# include "BKE_image.h" +# include "IMB_imbuf_types.h" +# include "BKE_displist.h" + +extern Material defmaterial; } -/* end of blender include block */ +#include "wm_event_types.h" -#include "KX_BlenderInputDevice.h" -#include "KX_ConvertProperties.h" - -#include "SG_Node.h" -#include "SG_BBox.h" -#include "SG_Tree.h" -#include "KX_SG_NodeRelationships.h" -#include "KX_SG_BoneParentNodeRelationship.h" - -#ifdef WITH_BULLET -#include "CcdPhysicsEnvironment.h" -#include "CcdGraphicController.h" -#endif - -#include "KX_MotionState.h" - -#include "BL_ArmatureObject.h" -#include "BL_DeformableGameObject.h" - -#include "KX_NavMeshObject.h" -#include "KX_ObstacleSimulation.h" - -#include "BLI_threads.h" - - -static bool default_light_mode = 0; - -static std::map create_translate_table() -{ - std::map m; - - /* The reverse table. In order to not confuse ourselves, we */ - /* immediately convert all events that come in to KX codes. */ - m[LEFTMOUSE ] = SCA_IInputDevice::KX_LEFTMOUSE; - m[MIDDLEMOUSE ] = SCA_IInputDevice::KX_MIDDLEMOUSE; - m[RIGHTMOUSE ] = SCA_IInputDevice::KX_RIGHTMOUSE; - m[WHEELUPMOUSE ] = SCA_IInputDevice::KX_WHEELUPMOUSE; - m[WHEELDOWNMOUSE ] = SCA_IInputDevice::KX_WHEELDOWNMOUSE; - m[MOUSEX ] = SCA_IInputDevice::KX_MOUSEX; - m[MOUSEY ] = SCA_IInputDevice::KX_MOUSEY; - - // TIMERS - - m[TIMER0 ] = SCA_IInputDevice::KX_TIMER0; - m[TIMER1 ] = SCA_IInputDevice::KX_TIMER1; - m[TIMER2 ] = SCA_IInputDevice::KX_TIMER2; - - // SYSTEM - -#if 0 - /* **** XXX **** */ - m[KEYBD ] = SCA_IInputDevice::KX_KEYBD; - m[RAWKEYBD ] = SCA_IInputDevice::KX_RAWKEYBD; - m[REDRAW ] = SCA_IInputDevice::KX_REDRAW; - m[INPUTCHANGE ] = SCA_IInputDevice::KX_INPUTCHANGE; - m[QFULL ] = SCA_IInputDevice::KX_QFULL; - m[WINFREEZE ] = SCA_IInputDevice::KX_WINFREEZE; - m[WINTHAW ] = SCA_IInputDevice::KX_WINTHAW; - m[WINCLOSE ] = SCA_IInputDevice::KX_WINCLOSE; - m[WINQUIT ] = SCA_IInputDevice::KX_WINQUIT; - m[Q_FIRSTTIME ] = SCA_IInputDevice::KX_Q_FIRSTTIME; - /* **** XXX **** */ -#endif - - // standard keyboard - - m[AKEY ] = SCA_IInputDevice::KX_AKEY; - m[BKEY ] = SCA_IInputDevice::KX_BKEY; - m[CKEY ] = SCA_IInputDevice::KX_CKEY; - m[DKEY ] = SCA_IInputDevice::KX_DKEY; - m[EKEY ] = SCA_IInputDevice::KX_EKEY; - m[FKEY ] = SCA_IInputDevice::KX_FKEY; - m[GKEY ] = SCA_IInputDevice::KX_GKEY; - m[HKEY ] = SCA_IInputDevice::KX_HKEY; - m[IKEY ] = SCA_IInputDevice::KX_IKEY; - m[JKEY ] = SCA_IInputDevice::KX_JKEY; - m[KKEY ] = SCA_IInputDevice::KX_KKEY; - m[LKEY ] = SCA_IInputDevice::KX_LKEY; - m[MKEY ] = SCA_IInputDevice::KX_MKEY; - m[NKEY ] = SCA_IInputDevice::KX_NKEY; - m[OKEY ] = SCA_IInputDevice::KX_OKEY; - m[PKEY ] = SCA_IInputDevice::KX_PKEY; - m[QKEY ] = SCA_IInputDevice::KX_QKEY; - m[RKEY ] = SCA_IInputDevice::KX_RKEY; - m[SKEY ] = SCA_IInputDevice::KX_SKEY; - m[TKEY ] = SCA_IInputDevice::KX_TKEY; - m[UKEY ] = SCA_IInputDevice::KX_UKEY; - m[VKEY ] = SCA_IInputDevice::KX_VKEY; - m[WKEY ] = SCA_IInputDevice::KX_WKEY; - m[XKEY ] = SCA_IInputDevice::KX_XKEY; - m[YKEY ] = SCA_IInputDevice::KX_YKEY; - m[ZKEY ] = SCA_IInputDevice::KX_ZKEY; - - m[ZEROKEY ] = SCA_IInputDevice::KX_ZEROKEY; - m[ONEKEY ] = SCA_IInputDevice::KX_ONEKEY; - m[TWOKEY ] = SCA_IInputDevice::KX_TWOKEY; - m[THREEKEY ] = SCA_IInputDevice::KX_THREEKEY; - m[FOURKEY ] = SCA_IInputDevice::KX_FOURKEY; - m[FIVEKEY ] = SCA_IInputDevice::KX_FIVEKEY; - m[SIXKEY ] = SCA_IInputDevice::KX_SIXKEY; - m[SEVENKEY ] = SCA_IInputDevice::KX_SEVENKEY; - m[EIGHTKEY ] = SCA_IInputDevice::KX_EIGHTKEY; - m[NINEKEY ] = SCA_IInputDevice::KX_NINEKEY; - - m[CAPSLOCKKEY ] = SCA_IInputDevice::KX_CAPSLOCKKEY; - - m[LEFTCTRLKEY ] = SCA_IInputDevice::KX_LEFTCTRLKEY; - m[LEFTALTKEY ] = SCA_IInputDevice::KX_LEFTALTKEY; - m[RIGHTALTKEY ] = SCA_IInputDevice::KX_RIGHTALTKEY; - m[RIGHTCTRLKEY ] = SCA_IInputDevice::KX_RIGHTCTRLKEY; - m[RIGHTSHIFTKEY ] = SCA_IInputDevice::KX_RIGHTSHIFTKEY; - m[LEFTSHIFTKEY ] = SCA_IInputDevice::KX_LEFTSHIFTKEY; - - m[ESCKEY ] = SCA_IInputDevice::KX_ESCKEY; - m[TABKEY ] = SCA_IInputDevice::KX_TABKEY; - m[RETKEY ] = SCA_IInputDevice::KX_RETKEY; - m[SPACEKEY ] = SCA_IInputDevice::KX_SPACEKEY; - m[LINEFEEDKEY ] = SCA_IInputDevice::KX_LINEFEEDKEY; - m[BACKSPACEKEY ] = SCA_IInputDevice::KX_BACKSPACEKEY; - m[DELKEY ] = SCA_IInputDevice::KX_DELKEY; - m[SEMICOLONKEY ] = SCA_IInputDevice::KX_SEMICOLONKEY; - m[PERIODKEY ] = SCA_IInputDevice::KX_PERIODKEY; - m[COMMAKEY ] = SCA_IInputDevice::KX_COMMAKEY; - m[QUOTEKEY ] = SCA_IInputDevice::KX_QUOTEKEY; - m[ACCENTGRAVEKEY ] = SCA_IInputDevice::KX_ACCENTGRAVEKEY; - m[MINUSKEY ] = SCA_IInputDevice::KX_MINUSKEY; - m[PLUSKEY ] = SCA_IInputDevice::KX_PLUSKEY; - m[SLASHKEY ] = SCA_IInputDevice::KX_SLASHKEY; - m[BACKSLASHKEY ] = SCA_IInputDevice::KX_BACKSLASHKEY; - m[EQUALKEY ] = SCA_IInputDevice::KX_EQUALKEY; - m[LEFTBRACKETKEY ] = SCA_IInputDevice::KX_LEFTBRACKETKEY; - m[RIGHTBRACKETKEY ] = SCA_IInputDevice::KX_RIGHTBRACKETKEY; - - m[LEFTARROWKEY ] = SCA_IInputDevice::KX_LEFTARROWKEY; - m[DOWNARROWKEY ] = SCA_IInputDevice::KX_DOWNARROWKEY; - m[RIGHTARROWKEY ] = SCA_IInputDevice::KX_RIGHTARROWKEY; - m[UPARROWKEY ] = SCA_IInputDevice::KX_UPARROWKEY; - - m[PAD2 ] = SCA_IInputDevice::KX_PAD2; - m[PAD4 ] = SCA_IInputDevice::KX_PAD4; - m[PAD6 ] = SCA_IInputDevice::KX_PAD6; - m[PAD8 ] = SCA_IInputDevice::KX_PAD8; - - m[PAD1 ] = SCA_IInputDevice::KX_PAD1; - m[PAD3 ] = SCA_IInputDevice::KX_PAD3; - m[PAD5 ] = SCA_IInputDevice::KX_PAD5; - m[PAD7 ] = SCA_IInputDevice::KX_PAD7; - m[PAD9 ] = SCA_IInputDevice::KX_PAD9; - - m[PADPERIOD ] = SCA_IInputDevice::KX_PADPERIOD; - m[PADSLASHKEY ] = SCA_IInputDevice::KX_PADSLASHKEY; - m[PADASTERKEY ] = SCA_IInputDevice::KX_PADASTERKEY; - - m[PAD0 ] = SCA_IInputDevice::KX_PAD0; - m[PADMINUS ] = SCA_IInputDevice::KX_PADMINUS; - m[PADENTER ] = SCA_IInputDevice::KX_PADENTER; - m[PADPLUSKEY ] = SCA_IInputDevice::KX_PADPLUSKEY; - - - m[F1KEY ] = SCA_IInputDevice::KX_F1KEY; - m[F2KEY ] = SCA_IInputDevice::KX_F2KEY; - m[F3KEY ] = SCA_IInputDevice::KX_F3KEY; - m[F4KEY ] = SCA_IInputDevice::KX_F4KEY; - m[F5KEY ] = SCA_IInputDevice::KX_F5KEY; - m[F6KEY ] = SCA_IInputDevice::KX_F6KEY; - m[F7KEY ] = SCA_IInputDevice::KX_F7KEY; - m[F8KEY ] = SCA_IInputDevice::KX_F8KEY; - m[F9KEY ] = SCA_IInputDevice::KX_F9KEY; - m[F10KEY ] = SCA_IInputDevice::KX_F10KEY; - m[F11KEY ] = SCA_IInputDevice::KX_F11KEY; - m[F12KEY ] = SCA_IInputDevice::KX_F12KEY; - m[F13KEY ] = SCA_IInputDevice::KX_F13KEY; - m[F14KEY ] = SCA_IInputDevice::KX_F14KEY; - m[F15KEY ] = SCA_IInputDevice::KX_F15KEY; - m[F16KEY ] = SCA_IInputDevice::KX_F16KEY; - m[F17KEY ] = SCA_IInputDevice::KX_F17KEY; - m[F18KEY ] = SCA_IInputDevice::KX_F18KEY; - m[F19KEY ] = SCA_IInputDevice::KX_F19KEY; - - m[OSKEY ] = SCA_IInputDevice::KX_OSKEY; - - m[PAUSEKEY ] = SCA_IInputDevice::KX_PAUSEKEY; - m[INSERTKEY ] = SCA_IInputDevice::KX_INSERTKEY; - m[HOMEKEY ] = SCA_IInputDevice::KX_HOMEKEY; - m[PAGEUPKEY ] = SCA_IInputDevice::KX_PAGEUPKEY; - m[PAGEDOWNKEY ] = SCA_IInputDevice::KX_PAGEDOWNKEY; - m[ENDKEY ] = SCA_IInputDevice::KX_ENDKEY; - - return m; -} - -static std::map gReverseKeyTranslateTable = create_translate_table(); - -SCA_IInputDevice::KX_EnumInputs ConvertKeyCode(int key_code) -{ - return gReverseKeyTranslateTable[key_code]; -} - -static unsigned int KX_rgbaint2uint_new(unsigned int icol) -{ - union - { - unsigned int integer; - unsigned char cp[4]; - } out_color, in_color; - - in_color.integer = icol; - out_color.cp[0] = in_color.cp[3]; // red - out_color.cp[1] = in_color.cp[2]; // green - out_color.cp[2] = in_color.cp[1]; // blue - out_color.cp[3] = in_color.cp[0]; // alpha +// For construction to find shared vertices. +struct BL_SharedVertex { + RAS_DisplayArray *array; + unsigned int offset; +}; - return out_color.integer; -} +using BL_SharedVertexList = std::vector; +using BL_SharedVertexMap = std::vector; -/* Now the real converting starts... */ -static unsigned int KX_Mcol2uint_new(MCol col) +class BL_SharedVertexPredicate { - /* color has to be converted without endian sensitivity. So no shifting! */ - union +private: + RAS_DisplayArray *m_array; + mt::vec3_packed m_normal; + mt::vec4_packed m_tangent; + mt::vec2_packed m_uvs[RAS_Texture::MaxUnits]; + unsigned int m_colors[RAS_Texture::MaxUnits]; + +public: + BL_SharedVertexPredicate(RAS_DisplayArray *array, const mt::vec3_packed& normal, const mt::vec4_packed& tangent, mt::vec2_packed uvs[], unsigned int colors[]) + :m_array(array), + m_normal(normal), + m_tangent(tangent) { - MCol col; - unsigned int integer; - unsigned char cp[4]; - } out_color, in_color; - - in_color.col = col; - out_color.cp[0] = in_color.cp[3]; // red - out_color.cp[1] = in_color.cp[2]; // green - out_color.cp[2] = in_color.cp[1]; // blue - out_color.cp[3] = in_color.cp[0]; // alpha - - return out_color.integer; -} - -static void SetDefaultLightMode(Scene* scene) -{ - default_light_mode = false; - Scene *sce_iter; - Base *base; + const RAS_DisplayArray::Format& format = m_array->GetFormat(); - for (SETLOOPER(scene, sce_iter, base)) - { - if (base->object->type == OB_LAMP) - { - default_light_mode = true; - return; + for (unsigned short i = 0, size = format.uvSize; i < size; ++i) { + m_uvs[i] = uvs[i]; } - } -} - -static bool GetMaterialUseVColor(Material *ma, const bool glslmat) -{ - if (ma) { - /* glsl uses vertex colors, otherwise use material setting - * defmaterial doesn't have VERTEXCOLP as default [#34505] */ - return (glslmat || ma == &defmaterial || (ma->mode & MA_VERTEXCOLP) != 0); - } - else { - /* no material, use vertex colors */ - return true; - } -} - -// -- -static void GetRGB( - const bool use_vcol, - MFace* mface, - MCol* mmcol, - Material *mat, - unsigned int c[4]) -{ - unsigned int color = 0xFFFFFFFFL; - if (use_vcol == true) { - if (mmcol) { - c[0] = KX_Mcol2uint_new(mmcol[0]); - c[1] = KX_Mcol2uint_new(mmcol[1]); - c[2] = KX_Mcol2uint_new(mmcol[2]); - if (mface->v4) - c[3] = KX_Mcol2uint_new(mmcol[3]); - } - else { // backup white - c[0] = KX_rgbaint2uint_new(color); - c[1] = KX_rgbaint2uint_new(color); - c[2] = KX_rgbaint2uint_new(color); - if (mface->v4) - c[3] = KX_rgbaint2uint_new( color ); + for (unsigned short i = 0, size = format.colorSize; i < size; ++i) { + m_colors[i] = colors[i]; } } - else { - /* material rgba */ - if (mat) { - union { - unsigned char cp[4]; - unsigned int integer; - } col_converter; - col_converter.cp[3] = (unsigned char) (mat->r * 255.0f); - col_converter.cp[2] = (unsigned char) (mat->g * 255.0f); - col_converter.cp[1] = (unsigned char) (mat->b * 255.0f); - col_converter.cp[0] = (unsigned char) (mat->alpha * 255.0f); - color = col_converter.integer; - } - c[0] = KX_rgbaint2uint_new(color); - c[1] = KX_rgbaint2uint_new(color); - c[2] = KX_rgbaint2uint_new(color); - if (mface->v4) { - c[3] = KX_rgbaint2uint_new(color); - } - } - -#if 0 /* white, unused */ - { - c[0] = KX_rgbaint2uint_new(color); - c[1] = KX_rgbaint2uint_new(color); - c[2] = KX_rgbaint2uint_new(color); - if (mface->v4) - c[3] = KX_rgbaint2uint_new(color); - } -#endif -} - -typedef struct MTF_localLayer { - MTFace *face; - const char *name; -} MTF_localLayer; - -static void GetUVs(BL_Material *material, MTF_localLayer *layers, MFace *mface, MTFace *tface, MT_Point2 uvs[4][MAXTEX]) -{ - int unit = 0; - if (tface) - { - - uvs[0][0].setValue(tface->uv[0]); - uvs[1][0].setValue(tface->uv[1]); - uvs[2][0].setValue(tface->uv[2]); - - if (mface->v4) - uvs[3][0].setValue(tface->uv[3]); - } - else - { - uvs[0][0] = uvs[1][0] = uvs[2][0] = uvs[3][0] = MT_Point2(0.f, 0.f); - } - vector found_layers; - - for (int vind = 0; vindmapping[vind]; - - if (!(map.mapping & USEUV)) continue; - - if (std::find(found_layers.begin(), found_layers.end(), map.uvCoName) != found_layers.end()) - continue; - - //If no UVSet is specified, try grabbing one from the UV/Image editor - if (map.uvCoName.IsEmpty() && tface) - { - uvs[0][unit].setValue(tface->uv[0]); - uvs[1][unit].setValue(tface->uv[1]); - uvs[2][unit].setValue(tface->uv[2]); - - if (mface->v4) - uvs[3][unit].setValue(tface->uv[3]); - - ++unit; - continue; + RAS_DisplayArray *otherArray = sharedVert.array; + if (m_array != otherArray) { + return false; } + const unsigned int offset = sharedVert.offset; - for (int lay=0; layGetNormal(offset).data, m_normal.data, eps) || + !compare_v3v3(m_array->GetTangent(offset).data, m_tangent.data, eps)) { - MTF_localLayer& layer = layers[lay]; - if (layer.face == 0) break; - - if (map.uvCoName.IsEmpty() || strcmp(map.uvCoName.ReadPtr(), layer.name)==0) - { - uvs[0][unit].setValue(layer.face->uv[0]); - uvs[1][unit].setValue(layer.face->uv[1]); - uvs[2][unit].setValue(layer.face->uv[2]); - - if (mface->v4) - uvs[3][unit].setValue(layer.face->uv[3]); - else - uvs[3][unit].setValue(0.0f, 0.0f); - - ++unit; - found_layers.push_back(map.uvCoName); - break; - } + return false; } - } -} - -// ------------------------------------ -static bool ConvertMaterial( - BL_Material *material, - Material *mat, - MTFace *tface, - const char *tfaceName, - MFace *mface, - MCol *mmcol, - bool glslmat) -{ - material->Initialize(); - int texalpha = 0; - const bool validmat = (mat != NULL); - const bool validface = (tface != NULL); - const bool use_vcol = GetMaterialUseVColor(mat, glslmat); - - material->IdMode = DEFAULT_BLENDER; - material->glslmat = (validmat) ? glslmat: false; - material->materialindex = mface->mat_nr; - - // -------------------------------- - if (validmat) { - - // use lighting? - material->ras_mode |= (mat->mode & MA_SHLESS) ? 0 : USE_LIGHT; - material->ras_mode |= (mat->game.flag & GEMAT_BACKCULL) ? 0 : TWOSIDED; - - // cast shadows? - material->ras_mode |= ((mat->mode2 & MA_CASTSHADOW) && (mat->mode & MA_SHADBUF)) ? CAST_SHADOW : 0; - - // only shadows? - material->ras_mode |= (mat->mode & MA_ONLYCAST) ? ONLY_SHADOW : 0; - - MTex *mttmp = NULL; - int valid_index = 0; - - /* In Multitexture use the face texture if and only if - * it is set in the buttons - * In GLSL is not working yet :/ 3.2011 */ - bool facetex = false; - if (validface && mat->mode & MA_FACETEXTURE) { - facetex = true; - } - - // foreach MTex - for (int i = 0; i < MAXTEX; i++) { - // use face tex - if (i == 0 && facetex ) { - facetex = false; - Image *tmp = (Image *)(tface->tpage); - - if (tmp) { - material->img[i] = tmp; - material->texname[i] = material->img[i]->id.name; - material->flag[i] |= MIPMAP; - - material->flag[i] |= (mat->game.alpha_blend & GEMAT_ALPHA_SORT) ? USEALPHA : 0; - material->flag[i] |= (mat->game.alpha_blend & GEMAT_ALPHA) ? USEALPHA : 0; - material->flag[i] |= (mat->game.alpha_blend & GEMAT_ADD) ? CALCALPHA : 0; - - if (material->img[i]->flag & IMA_REFLECT) { - material->mapping[i].mapping |= USEREFL; - } - else { - mttmp = getMTexFromMaterial(mat, i); - if (mttmp && (mttmp->texco & TEXCO_UV)) { - /* string may be "" but thats detected as empty after */ - material->mapping[i].uvCoName = mttmp->uvname; - } - material->mapping[i].mapping |= USEUV; - } - valid_index++; - } - else { - material->img[i] = 0; - material->texname[i] = ""; - } - continue; - } - - mttmp = getMTexFromMaterial(mat, i); - if (mttmp) { - if (mttmp->tex) { - if (mttmp->tex->type == TEX_IMAGE) { - material->mtexname[i] = mttmp->tex->id.name; - material->img[i] = mttmp->tex->ima; - if (material->img[i]) { - - material->texname[i] = material->img[i]->id.name; - material->flag[i] |= (mttmp->tex->imaflag &TEX_MIPMAP) ? MIPMAP : 0; - if (material->img[i] && (material->img[i]->flag & IMA_IGNORE_ALPHA) == 0) { - material->flag[i] |= USEALPHA; - } - if (mttmp->tex->imaflag & TEX_CALCALPHA) { - material->flag[i] |= CALCALPHA; - } - else if (mttmp->tex->flag & TEX_NEGALPHA) { - material->flag[i] |= USENEGALPHA; - } - - material->color_blend[i] = mttmp->colfac; - material->flag[i] |= (mttmp->mapto & MAP_ALPHA) ? TEXALPHA : 0; - material->flag[i] |= (mttmp->texflag & MTEX_NEGATIVE) ? TEXNEG : 0; - - if (!glslmat && (material->flag[i] & TEXALPHA)) { - texalpha = 1; - } - } - } - else if (mttmp->tex->type == TEX_ENVMAP) { - if (mttmp->tex->env->stype == ENV_LOAD) { - material->mtexname[i] = mttmp->tex->id.name; - EnvMap *env = mttmp->tex->env; - env->ima = mttmp->tex->ima; - material->cubemap[i] = env; - - if (material->cubemap[i]) { - if (!material->cubemap[i]->cube[0]) { - BL_Texture::SplitEnvMap(material->cubemap[i]); - } - - material->texname[i] = material->cubemap[i]->ima->id.name; - material->mapping[i].mapping |= USEENV; - } - } - } -#if 0 /* this flag isn't used anymore */ - material->flag[i] |= (BKE_animdata_from_id(mat->id) != NULL) ? HASIPO : 0; -#endif - /// -------------------------------- - // mapping methods - if (mat->septex & (1 << i)) { - // If this texture slot isn't in use, set it to disabled to prevent multi-uv problems - material->mapping[i].mapping = DISABLE; - } - else { - material->mapping[i].mapping |= (mttmp->texco & TEXCO_REFL) ? USEREFL : 0; - - if (mttmp->texco & TEXCO_OBJECT) { - material->mapping[i].mapping |= USEOBJ; - if (mttmp->object) { - material->mapping[i].objconame = mttmp->object->id.name; - } - } - else if (mttmp->texco & TEXCO_REFL) { - material->mapping[i].mapping |= USEREFL; - } - else if (mttmp->texco & (TEXCO_ORCO | TEXCO_GLOB)) { - material->mapping[i].mapping |= USEORCO; - } - else if (mttmp->texco & TEXCO_UV) { - /* string may be "" but thats detected as empty after */ - material->mapping[i].uvCoName = mttmp->uvname; - material->mapping[i].mapping |= USEUV; - } - else if (mttmp->texco & TEXCO_NORM) { - material->mapping[i].mapping |= USENORM; - } - else if (mttmp->texco & TEXCO_TANGENT) { - material->mapping[i].mapping |= USETANG; - } - else { - material->mapping[i].mapping |= DISABLE; - } - - material->mapping[i].scale[0] = mttmp->size[0]; - material->mapping[i].scale[1] = mttmp->size[1]; - material->mapping[i].scale[2] = mttmp->size[2]; - material->mapping[i].offsets[0] = mttmp->ofs[0]; - material->mapping[i].offsets[1] = mttmp->ofs[1]; - material->mapping[i].offsets[2] = mttmp->ofs[2]; - - material->mapping[i].projplane[0] = mttmp->projx; - material->mapping[i].projplane[1] = mttmp->projy; - material->mapping[i].projplane[2] = mttmp->projz; - } - /// -------------------------------- - - switch (mttmp->blendtype) { - case MTEX_BLEND: - material->blend_mode[i] = BLEND_MIX; - break; - case MTEX_MUL: - material->blend_mode[i] = BLEND_MUL; - break; - case MTEX_ADD: - material->blend_mode[i] = BLEND_ADD; - break; - case MTEX_SUB: - material->blend_mode[i] = BLEND_SUB; - break; - case MTEX_SCREEN: - material->blend_mode[i] = BLEND_SCR; - break; - } - valid_index++; - } + const RAS_DisplayArray::Format& format = m_array->GetFormat(); + for (unsigned short i = 0, size = format.uvSize; i < size; ++i) { + if (!compare_v2v2(m_array->GetUv(offset, i).data, m_uvs[i].data, eps)) { + return false; } } - // above one tex the switches here - // are not used - switch (valid_index) { - case 0: - material->IdMode = DEFAULT_BLENDER; - break; - case 1: - material->IdMode = ONETEX; - break; - default: - material->IdMode = GREATERTHAN2; - break; - } - material->SetUsers(mat->id.us); - - material->num_enabled = valid_index; - - material->speccolor[0] = mat->specr; - material->speccolor[1] = mat->specg; - material->speccolor[2] = mat->specb; - material->hard = (float)mat->har / 4.0f; - material->matcolor[0] = mat->r; - material->matcolor[1] = mat->g; - material->matcolor[2] = mat->b; - material->matcolor[3] = mat->alpha; - material->alpha = mat->alpha; - material->emit = mat->emit; - material->spec_f = mat->spec; - material->ref = mat->ref; - material->amb = mat->amb; - - material->ras_mode |= (mat->material_type == MA_TYPE_WIRE) ? WIRE : 0; - } - else { // No Material - int valid = 0; - - // check for tface tex to fallback on - if (validface) { - material->img[0] = (Image *)(tface->tpage); - // ------------------------ - if (material->img[0]) { - material->texname[0] = material->img[0]->id.name; - material->mapping[0].mapping |= ((material->img[0]->flag & IMA_REFLECT) != 0) ? USEREFL : 0; - - /* see if depth of the image is 32bits */ - if (BKE_image_has_alpha(material->img[0])) { - material->flag[0] |= USEALPHA; - material->alphablend = GEMAT_ALPHA; - } - else { - material->alphablend = GEMAT_SOLID; - } - valid++; + for (unsigned short i = 0, size = format.colorSize; i < size; ++i) { + if (m_array->GetRawColor(offset, i) != m_colors[i]) { + return false; } } - else { - material->alphablend = GEMAT_SOLID; - } - - material->SetUsers(-1); - material->num_enabled = valid; - material->IdMode = TEXFACE; - material->speccolor[0] = 1.0f; - material->speccolor[1] = 1.0f; - material->speccolor[2] = 1.0f; - material->hard = 35.0f; - material->matcolor[0] = 0.5f; - material->matcolor[1] = 0.5f; - material->matcolor[2] = 0.5f; - material->spec_f = 0.5f; - material->ref = 0.8f; - // No material - old default TexFace properties - material->ras_mode |= USE_LIGHT; + return true; } +}; - /* No material, what to do? let's see what is in the UV and set the material accordingly - * light and visible is always on */ - if (validface) { - material->tile = tface->tile; - } - else { - // nothing at all - material->alphablend = GEMAT_SOLID; - material->tile = 0; - } +/* The reverse table. In order to not confuse ourselves, we + * immediately convert all events that come in to KX codes. */ +static std::map gReverseKeyTranslateTable = { + {LEFTMOUSE, SCA_IInputDevice::LEFTMOUSE}, + {MIDDLEMOUSE, SCA_IInputDevice::MIDDLEMOUSE}, + {RIGHTMOUSE, SCA_IInputDevice::RIGHTMOUSE}, + {WHEELUPMOUSE, SCA_IInputDevice::WHEELUPMOUSE}, + {WHEELDOWNMOUSE, SCA_IInputDevice::WHEELDOWNMOUSE}, + {MOUSEMOVE, SCA_IInputDevice::MOUSEX}, + {ACTIONMOUSE, SCA_IInputDevice::MOUSEY}, + // Standard keyboard. + {AKEY, SCA_IInputDevice::AKEY}, + {BKEY, SCA_IInputDevice::BKEY}, + {CKEY, SCA_IInputDevice::CKEY}, + {DKEY, SCA_IInputDevice::DKEY}, + {EKEY, SCA_IInputDevice::EKEY}, + {FKEY, SCA_IInputDevice::FKEY}, + {GKEY, SCA_IInputDevice::GKEY}, + {HKEY, SCA_IInputDevice::HKEY_}, + {IKEY, SCA_IInputDevice::IKEY}, + {JKEY, SCA_IInputDevice::JKEY}, + {KKEY, SCA_IInputDevice::KKEY}, + {LKEY, SCA_IInputDevice::LKEY}, + {MKEY, SCA_IInputDevice::MKEY}, + {NKEY, SCA_IInputDevice::NKEY}, + {OKEY, SCA_IInputDevice::OKEY}, + {PKEY, SCA_IInputDevice::PKEY}, + {QKEY, SCA_IInputDevice::QKEY}, + {RKEY, SCA_IInputDevice::RKEY}, + {SKEY, SCA_IInputDevice::SKEY}, + {TKEY, SCA_IInputDevice::TKEY}, + {UKEY, SCA_IInputDevice::UKEY}, + {VKEY, SCA_IInputDevice::VKEY}, + {WKEY, SCA_IInputDevice::WKEY}, + {XKEY, SCA_IInputDevice::XKEY}, + {YKEY, SCA_IInputDevice::YKEY}, + {ZKEY, SCA_IInputDevice::ZKEY}, + + {ZEROKEY, SCA_IInputDevice::ZEROKEY}, + {ONEKEY, SCA_IInputDevice::ONEKEY}, + {TWOKEY, SCA_IInputDevice::TWOKEY}, + {THREEKEY, SCA_IInputDevice::THREEKEY}, + {FOURKEY, SCA_IInputDevice::FOURKEY}, + {FIVEKEY, SCA_IInputDevice::FIVEKEY}, + {SIXKEY, SCA_IInputDevice::SIXKEY}, + {SEVENKEY, SCA_IInputDevice::SEVENKEY}, + {EIGHTKEY, SCA_IInputDevice::EIGHTKEY}, + {NINEKEY, SCA_IInputDevice::NINEKEY}, + + {CAPSLOCKKEY, SCA_IInputDevice::CAPSLOCKKEY}, + + {LEFTCTRLKEY, SCA_IInputDevice::LEFTCTRLKEY}, + {LEFTALTKEY, SCA_IInputDevice::LEFTALTKEY}, + {RIGHTALTKEY, SCA_IInputDevice::RIGHTALTKEY}, + {RIGHTCTRLKEY, SCA_IInputDevice::RIGHTCTRLKEY}, + {RIGHTSHIFTKEY, SCA_IInputDevice::RIGHTSHIFTKEY}, + {LEFTSHIFTKEY, SCA_IInputDevice::LEFTSHIFTKEY}, + + {ESCKEY, SCA_IInputDevice::ESCKEY}, + {TABKEY, SCA_IInputDevice::TABKEY}, + {RETKEY, SCA_IInputDevice::RETKEY}, + {SPACEKEY, SCA_IInputDevice::SPACEKEY}, + {LINEFEEDKEY, SCA_IInputDevice::LINEFEEDKEY}, + {BACKSPACEKEY, SCA_IInputDevice::BACKSPACEKEY}, + {DELKEY, SCA_IInputDevice::DELKEY}, + {SEMICOLONKEY, SCA_IInputDevice::SEMICOLONKEY}, + {PERIODKEY, SCA_IInputDevice::PERIODKEY}, + {COMMAKEY, SCA_IInputDevice::COMMAKEY}, + {QUOTEKEY, SCA_IInputDevice::QUOTEKEY}, + {ACCENTGRAVEKEY, SCA_IInputDevice::ACCENTGRAVEKEY}, + {MINUSKEY, SCA_IInputDevice::MINUSKEY}, + {SLASHKEY, SCA_IInputDevice::SLASHKEY}, + {BACKSLASHKEY, SCA_IInputDevice::BACKSLASHKEY}, + {EQUALKEY, SCA_IInputDevice::EQUALKEY}, + {LEFTBRACKETKEY, SCA_IInputDevice::LEFTBRACKETKEY}, + {RIGHTBRACKETKEY, SCA_IInputDevice::RIGHTBRACKETKEY}, + + {LEFTARROWKEY, SCA_IInputDevice::LEFTARROWKEY}, + {DOWNARROWKEY, SCA_IInputDevice::DOWNARROWKEY}, + {RIGHTARROWKEY, SCA_IInputDevice::RIGHTARROWKEY}, + {UPARROWKEY, SCA_IInputDevice::UPARROWKEY}, + + {PAD2, SCA_IInputDevice::PAD2}, + {PAD4, SCA_IInputDevice::PAD4}, + {PAD6, SCA_IInputDevice::PAD6}, + {PAD8, SCA_IInputDevice::PAD8}, + + {PAD1, SCA_IInputDevice::PAD1}, + {PAD3, SCA_IInputDevice::PAD3}, + {PAD5, SCA_IInputDevice::PAD5}, + {PAD7, SCA_IInputDevice::PAD7}, + {PAD9, SCA_IInputDevice::PAD9}, + + {PADPERIOD, SCA_IInputDevice::PADPERIOD}, + {PADSLASHKEY, SCA_IInputDevice::PADSLASHKEY}, + {PADASTERKEY, SCA_IInputDevice::PADASTERKEY}, + + {PAD0, SCA_IInputDevice::PAD0}, + {PADMINUS, SCA_IInputDevice::PADMINUS}, + {PADENTER, SCA_IInputDevice::PADENTER}, + {PADPLUSKEY, SCA_IInputDevice::PADPLUSKEY}, + + {F1KEY, SCA_IInputDevice::F1KEY}, + {F2KEY, SCA_IInputDevice::F2KEY}, + {F3KEY, SCA_IInputDevice::F3KEY}, + {F4KEY, SCA_IInputDevice::F4KEY}, + {F5KEY, SCA_IInputDevice::F5KEY}, + {F6KEY, SCA_IInputDevice::F6KEY}, + {F7KEY, SCA_IInputDevice::F7KEY}, + {F8KEY, SCA_IInputDevice::F8KEY}, + {F9KEY, SCA_IInputDevice::F9KEY}, + {F10KEY, SCA_IInputDevice::F10KEY}, + {F11KEY, SCA_IInputDevice::F11KEY}, + {F12KEY, SCA_IInputDevice::F12KEY}, + {F13KEY, SCA_IInputDevice::F13KEY}, + {F14KEY, SCA_IInputDevice::F14KEY}, + {F15KEY, SCA_IInputDevice::F15KEY}, + {F16KEY, SCA_IInputDevice::F16KEY}, + {F17KEY, SCA_IInputDevice::F17KEY}, + {F18KEY, SCA_IInputDevice::F18KEY}, + {F19KEY, SCA_IInputDevice::F19KEY}, + + {OSKEY, SCA_IInputDevice::OSKEY}, + + {PAUSEKEY, SCA_IInputDevice::PAUSEKEY}, + {INSERTKEY, SCA_IInputDevice::INSERTKEY}, + {HOMEKEY, SCA_IInputDevice::HOMEKEY}, + {PAGEUPKEY, SCA_IInputDevice::PAGEUPKEY}, + {PAGEDOWNKEY, SCA_IInputDevice::PAGEDOWNKEY}, + {ENDKEY, SCA_IInputDevice::ENDKEY} +}; - if (validmat && validface) { - material->alphablend = mat->game.alpha_blend; - } +SCA_IInputDevice::SCA_EnumInputs BL_ConvertKeyCode(int key_code) +{ + return gReverseKeyTranslateTable[key_code]; +} - // with ztransp enabled, enforce alpha blending mode - if (validmat && (mat->mode & MA_TRANSP) && (mat->mode & MA_ZTRANSP) && (material->alphablend == GEMAT_SOLID)) { - material->alphablend = GEMAT_ALPHA; - } +static void BL_GetUvRgba(const RAS_Mesh::LayersInfo& layersInfo, std::vector& uvLayers, + std::vector& colorLayers, unsigned int loop, mt::vec2_packed uvs[RAS_Texture::MaxUnits], + unsigned int rgba[RAS_Texture::MaxUnits]) +{ + // No need to initialize layers to zero as all the converted layer are all the layers needed. - // always zsort alpha + add - if ((ELEM(material->alphablend, GEMAT_ALPHA, GEMAT_ALPHA_SORT, GEMAT_ADD) || texalpha) && (material->alphablend != GEMAT_CLIP)) { - material->ras_mode |= ALPHA; - material->ras_mode |= (mat && (mat->game.alpha_blend & GEMAT_ALPHA_SORT)) ? ZSORT : 0; - } + for (const RAS_Mesh::Layer& layer : layersInfo.colorLayers) { + const unsigned short index = layer.index; + const MLoopCol& col = colorLayers[index][loop]; - // XXX The RGB values here were meant to be temporary storage for the conversion process, - // but fonts now make use of them too, so we leave them in for now. - unsigned int rgb[4]; - GetRGB(use_vcol, mface, mmcol, mat, rgb); + union Convert + { + // Color isn't swapped in MLoopCol. + MLoopCol col; + unsigned int val; + }; + Convert con; + con.col = col; - // swap the material color, so MCol on bitmap font works - if (validmat && (use_vcol == false) && (mat->game.flag & GEMAT_TEXT)) { - material->rgb[0] = KX_rgbaint2uint_new(rgb[0]); - material->rgb[1] = KX_rgbaint2uint_new(rgb[1]); - material->rgb[2] = KX_rgbaint2uint_new(rgb[2]); - material->rgb[3] = KX_rgbaint2uint_new(rgb[3]); + rgba[index] = con.val; } - if (validmat) { - material->matname =(mat->id.name); + for (const RAS_Mesh::Layer& layer : layersInfo.uvLayers) { + const unsigned short index = layer.index; + const MLoopUV& uv = uvLayers[index][loop]; + uvs[index] = mt::vec2_packed(uv.uv); } - if (tface) { - ME_MTEXFACE_CPY(&material->mtexpoly, tface); + /* All vertices have at least one uv and color layer accessible to the user + * even if it they are not used in any shaders. Initialize this layer to zero + * when no uv or color layer exist. + */ + if (layersInfo.uvLayers.empty()) { + uvs[0] = mt::zero2; } - else { - memset(&material->mtexpoly, 0, sizeof(material->mtexpoly)); + if (layersInfo.colorLayers.empty()) { + rgba[0] = 0xFFFFFFFF; } - material->material = mat; - return true; } -static RAS_MaterialBucket *material_from_mesh(Material *ma, MFace *mface, MTFace *tface, MCol *mcol, MTF_localLayer *layers, int lightlayer, unsigned int *rgb, MT_Point2 uvs[4][RAS_TexVert::MAX_UNIT], const char *tfaceName, KX_Scene* scene, KX_BlenderSceneConverter *converter) +static RAS_MaterialBucket *BL_ConvertMaterial(Material *ma, KX_Scene *scene, BL_SceneConverter& converter) { - RAS_IPolyMaterial* polymat = converter->FindCachedPolyMaterial(scene, ma); - BL_Material* bl_mat = converter->FindCachedBlenderMaterial(scene, ma); - KX_BlenderMaterial* kx_blmat = NULL; - - /* first is the BL_Material */ - if (!bl_mat) - { - bl_mat = new BL_Material(); + KX_BlenderMaterial *mat = converter.FindMaterial(ma); - ConvertMaterial(bl_mat, ma, tface, tfaceName, mface, mcol, - converter->GetGLSLMaterials()); - - if (ma && (ma->mode & MA_FACETEXTURE) == 0) - converter->CacheBlenderMaterial(scene, ma, bl_mat); - } - - const bool use_vcol = GetMaterialUseVColor(ma, bl_mat->glslmat); - GetRGB(use_vcol, mface, mcol, ma, rgb); - - GetUVs(bl_mat, layers, mface, tface, uvs); + if (!mat) { + std::string name = ma->id.name; + // Always ensure that the name of a material start with "MA" prefix due to video texture name check. + if (name.empty()) { + name = "MA"; + } - /* then the KX_BlenderMaterial */ - if (polymat == NULL) - { - kx_blmat = new KX_BlenderMaterial(); + mat = new KX_BlenderMaterial(ma, name, scene); - kx_blmat->Initialize(scene, bl_mat, (ma?&ma->game:NULL), lightlayer); - polymat = static_cast(kx_blmat); - if (ma && (ma->mode & MA_FACETEXTURE) == 0) - converter->CachePolyMaterial(scene, ma, polymat); + // this is needed to free up memory afterwards. + converter.RegisterMaterial(mat, ma); } // see if a bucket was reused or a new one was created // this way only one KX_BlenderMaterial object has to exist per bucket bool bucketCreated; - RAS_MaterialBucket* bucket = scene->FindBucket(polymat, bucketCreated); - - // this is needed to free up memory afterwards. - // the converter will also prevent duplicates from being registered, - // so just register everything. - converter->RegisterPolyMaterial(polymat); - converter->RegisterBlenderMaterial(bl_mat); + RAS_MaterialBucket *bucket = scene->GetBucketManager()->FindBucket(mat, bucketCreated); return bucket; } -/* blenderobj can be NULL, make sure its checked for */ -RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, KX_Scene* scene, KX_BlenderSceneConverter *converter, bool libloading) +/* blenderobj can be nullptr, make sure its checked for */ +KX_Mesh *BL_ConvertMesh(Mesh *me, Object *blenderobj, KX_Scene *scene, BL_SceneConverter& converter) { - RAS_MeshObject *meshobj; - int lightlayer = blenderobj ? blenderobj->lay:(1<<20)-1; // all layers if no object. + KX_Mesh *meshobj; // Without checking names, we get some reuse we don't want that can cause // problems with material LoDs. - if (blenderobj && ((meshobj = converter->FindGameMesh(mesh/*, ob->lay*/)) != NULL)) { - const char *bge_name = meshobj->GetName().ReadPtr(); - const char *blender_name = ((ID *)blenderobj->data)->name + 2; - if (STREQ(bge_name, blender_name)) { + if (blenderobj && ((meshobj = converter.FindGameMesh(me)) != nullptr)) { + const std::string bge_name = meshobj->GetName(); + const std::string blender_name = ((ID *)blenderobj->data)->name + 2; + if (bge_name == blender_name) { return meshobj; } } - // Get DerivedMesh data - DerivedMesh *dm = CDDM_from_mesh(mesh); - DM_ensure_tessface(dm); - - MVert *mvert = dm->getVertArray(dm); - int totvert = dm->getNumVerts(dm); - - MFace *mface = dm->getTessFaceArray(dm); - MTFace *tface = static_cast(dm->getTessFaceDataArray(dm, CD_MTFACE)); - MCol *mcol = static_cast(dm->getTessFaceDataArray(dm, CD_MCOL)); - float (*tangent)[4] = NULL; - int totface = dm->getNumTessFaces(dm); - const char *tfaceName = ""; + // Get DerivedMesh data. + DerivedMesh *dm = CDDM_from_mesh(me); - /* needs to be rewritten for loopdata */ - if (tface) { - if (CustomData_get_layer_index(&dm->faceData, CD_TANGENT) == -1) { - bool generate_data = false; - if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1) { - DM_calc_loop_tangents(dm, true, NULL, 0); - generate_data = true; - } - DM_generate_tangent_tessface_data(dm, generate_data); - } - tangent = (float(*)[4])dm->getTessFaceDataArray(dm, CD_TANGENT); - } + /* Extract available layers. + * Get the active color and uv layer. */ + const short activeUv = CustomData_get_active_layer(&dm->loopData, CD_MLOOPUV); + const short activeColor = CustomData_get_active_layer(&dm->loopData, CD_MLOOPCOL); + const unsigned short uvCount = CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV); + const unsigned short colorCount = CustomData_number_of_layers(&dm->loopData, CD_MLOOPCOL); - meshobj = new RAS_MeshObject(mesh); + RAS_Mesh::LayersInfo layersInfo; + layersInfo.activeUv = (activeUv == -1) ? 0 : activeUv; + layersInfo.activeColor = (activeColor == -1) ? 0 : activeColor; - // Extract avaiable layers - MTF_localLayer *layers = new MTF_localLayer[MAX_MTFACE]; - for (int lay=0; layloopData, CD_MLOOPUV, i); + layersInfo.uvLayers.push_back({i, name}); } - - int validLayers = 0; - for (int i=0; ifaceData.totlayer; i++) - { - if (dm->faceData.layers[i].type == CD_MTFACE) - { - if (validLayers >= MAX_MTFACE) { - printf("%s: corrupted mesh %s - too many CD_MTFACE layers\n", __func__, mesh->id.name); - break; - } - - layers[validLayers].face = (MTFace*)(dm->faceData.layers[i].data); - layers[validLayers].name = dm->faceData.layers[i].name; - if (tface == layers[validLayers].face) - tfaceName = layers[validLayers].name; - validLayers++; - } + // Extract color loops. + for (unsigned short i = 0; i < colorCount; ++i) { + const std::string name = CustomData_get_layer_name(&dm->loopData, CD_MLOOPCOL, i); + layersInfo.colorLayers.push_back({i, name}); } - meshobj->SetName(mesh->id.name + 2); - meshobj->m_sharedvertex_map.resize(totvert); - - Material* ma = 0; - MT_Point2 uvs[4][RAS_TexVert::MAX_UNIT]; - unsigned int rgb[4] = {0}; - - MT_Point3 pt[4]; - MT_Vector3 no[4]; - MT_Vector4 tan[4]; + // Initialize vertex format with used uv and color layers. + RAS_DisplayArray::Format vertformat; + vertformat.uvSize = max_ii(1, uvCount); + vertformat.colorSize = max_ii(1, colorCount); - /* ugh, if there is a less annoying way to do this please use that. - * since these are converted from floats to floats, theres no real - * advantage to use MT_ types - campbell */ - for (unsigned int i = 0; i < 4; i++) { - const float zero_vec[4] = {0.0f}; - pt[i].setValue(zero_vec); - no[i].setValue(zero_vec); - tan[i].setValue(zero_vec); - } - - /* we need to manually initialize the uvs (MoTo doesn't do that) [#34550] */ - for (unsigned int i = 0; i < RAS_TexVert::MAX_UNIT; i++) { - uvs[0][i] = uvs[1][i] = uvs[2][i] = uvs[3][i] = MT_Point2(0.f, 0.f); - } + meshobj = new KX_Mesh(scene, me, layersInfo); - for (int f=0;fv1].co); - pt[1].setValue(mvert[mface->v2].co); - pt[2].setValue(mvert[mface->v3].co); - if (mface->v4) pt[3].setValue(mvert[mface->v4].co); - - if (mface->flag & ME_SMOOTH) { - float n0[3], n1[3], n2[3], n3[3]; - - normal_short_to_float_v3(n0, mvert[mface->v1].no); - normal_short_to_float_v3(n1, mvert[mface->v2].no); - normal_short_to_float_v3(n2, mvert[mface->v3].no); - no[0] = n0; - no[1] = n1; - no[2] = n2; - - if (mface->v4) { - normal_short_to_float_v3(n3, mvert[mface->v4].no); - no[3] = n3; - } + const unsigned short totmat = max_ii(me->totcol, 1); + std::vector mats(totmat); + // Convert all the materials contained in the mesh. + for (unsigned short i = 0; i < totmat; ++i) { + Material *ma = nullptr; + if (blenderobj) { + ma = give_current_material(blenderobj, i + 1); } else { - float fno[3]; - - if (mface->v4) - normal_quad_v3(fno,mvert[mface->v1].co, mvert[mface->v2].co, mvert[mface->v3].co, mvert[mface->v4].co); - else - normal_tri_v3(fno,mvert[mface->v1].co, mvert[mface->v2].co, mvert[mface->v3].co); - - no[0] = no[1] = no[2] = no[3] = MT_Vector3(fno); - } - - if (tangent) { - tan[0] = tangent[f*4 + 0]; - tan[1] = tangent[f*4 + 1]; - tan[2] = tangent[f*4 + 2]; - - if (mface->v4) - tan[3] = tangent[f*4 + 3]; + ma = me->mat ? me->mat[i] : nullptr; } - if (blenderobj) - ma = give_current_material(blenderobj, mface->mat_nr+1); - else - ma = mesh->mat ? mesh->mat[mface->mat_nr]:NULL; - // Check for blender material - if (ma == NULL) { - ma= &defmaterial; - } - - { - - RAS_MaterialBucket* bucket = material_from_mesh(ma, mface, tface, mcol, layers, lightlayer, rgb, uvs, tfaceName, scene, converter); - - // set render flags - bool visible = ((ma->game.flag & GEMAT_INVISIBLE)==0); - bool twoside = ((ma->game.flag & GEMAT_BACKCULL)==0); - bool collider = ((ma->game.flag & GEMAT_NOPHYSICS)==0); - - /* mark face as flat, so vertices are split */ - bool flat = (mface->flag & ME_SMOOTH) == 0; - - int nverts = (mface->v4)? 4: 3; - - RAS_Polygon *poly = meshobj->AddPolygon(bucket, nverts); - - poly->SetVisible(visible); - poly->SetCollider(collider); - poly->SetTwoside(twoside); - //poly->SetEdgeCode(mface->edcode); - - meshobj->AddVertex(poly,0,pt[0],uvs[0],tan[0],rgb[0],no[0],flat,mface->v1); - meshobj->AddVertex(poly,1,pt[1],uvs[1],tan[1],rgb[1],no[1],flat,mface->v2); - meshobj->AddVertex(poly,2,pt[2],uvs[2],tan[2],rgb[2],no[2],flat,mface->v3); - - if (nverts==4) - meshobj->AddVertex(poly,3,pt[3],uvs[3],tan[3],rgb[3],no[3],flat,mface->v4); + if (!ma) { + ma = &defmaterial; } - if (tface) - tface++; - if (mcol) - mcol+=4; - - for (int lay=0; layAddMaterial(bucket, i, vertformat); + RAS_IMaterial *mat = meshmat->GetBucket()->GetMaterial(); - layer.face++; - } + mats[i] = {meshmat->GetDisplayArray(), bucket, mat->IsVisible(), mat->IsTwoSided(), mat->IsCollider(), mat->IsWire()}; } - // keep meshobj->m_sharedvertex_map for reinstance phys mesh. - // 2.49a and before it did: meshobj->m_sharedvertex_map.clear(); - // but this didnt save much ram. - Campbell - meshobj->EndConversion(); - // pre calculate texture generation - // However, we want to delay this if we're libloading so we can make sure we have the right scene. - if (!libloading) { - for (list::iterator mit = meshobj->GetFirstMaterial(); - mit != meshobj->GetLastMaterial(); ++ mit) { - mit->m_bucket->GetPolyMaterial()->OnConstruction(); - } - } + BL_ConvertDerivedMeshToArray(dm, me, mats, layersInfo); - if (layers) - delete []layers; + meshobj->EndConversion(scene->GetBoundingBoxManager()); dm->release(dm); - converter->RegisterGameMesh(meshobj, mesh); + // Needed for python scripting. + scene->GetLogicManager()->RegisterMeshName(meshobj->GetName(), meshobj); + converter.RegisterGameMesh(meshobj, me); + return meshobj; } - - -static PHY_MaterialProps *CreateMaterialFromBlenderObject(struct Object* blenderobject) +void BL_ConvertDerivedMeshToArray(DerivedMesh *dm, Mesh *me, const std::vector& mats, + const RAS_Mesh::LayersInfo& layersInfo) { - PHY_MaterialProps *materialProps = new PHY_MaterialProps; - - MT_assert(materialProps && "Create physics material properties failed"); - - Material* blendermat = give_current_material(blenderobject, 1); + const MVert *mverts = dm->getVertArray(dm); + const int totverts = dm->getNumVerts(dm); + const MPoly *mpolys = (MPoly *)dm->getPolyArray(dm); + const MLoopTri *mlooptris = (MLoopTri *)dm->getLoopTriArray(dm); + const MLoop *mloops = (MLoop *)dm->getLoopArray(dm); + const MEdge *medges = (MEdge *)dm->getEdgeArray(dm); + const unsigned int numpolys = dm->getNumPolys(dm); + + if (CustomData_get_layer_index(&dm->loopData, CD_NORMAL) == -1) { + dm->calcLoopNormals(dm, (me->flag & ME_AUTOSMOOTH), me->smoothresh); + } + const float(*normals)[3] = (float(*)[3])dm->getLoopDataArray(dm, CD_NORMAL); + + float(*tangent)[4] = nullptr; + if (!layersInfo.uvLayers.empty()) { + if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1) { + DM_calc_loop_tangents(dm, true, nullptr, 0); + } + tangent = (float(*)[4])dm->getLoopDataArray(dm, CD_TANGENT); + } - if (blendermat) - { - MT_assert(0.0f <= blendermat->reflect && blendermat->reflect <= 1.0f); + // List of MLoopUV per uv layer index. + std::vector uvLayers(layersInfo.uvLayers.size()); + // List of MLoopCol per color layer index. + std::vector colorLayers(layersInfo.colorLayers.size()); - materialProps->m_restitution = blendermat->reflect; - materialProps->m_friction = blendermat->friction; - materialProps->m_fh_spring = blendermat->fh; - materialProps->m_fh_damping = blendermat->xyfrict; - materialProps->m_fh_distance = blendermat->fhdist; - materialProps->m_fh_normal = (blendermat->dynamode & MA_FH_NOR) != 0; + for (const RAS_Mesh::Layer& layer : layersInfo.uvLayers) { + const unsigned short index = layer.index; + uvLayers[index] = (MLoopUV *)CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, index); } - else { - //give some defaults - materialProps->m_restitution = 0.f; - materialProps->m_friction = 0.5; - materialProps->m_fh_spring = 0.f; - materialProps->m_fh_damping = 0.f; - materialProps->m_fh_distance = 0.f; - materialProps->m_fh_normal = false; - + for (const RAS_Mesh::Layer& layer : layersInfo.colorLayers) { + const unsigned short index = layer.index; + colorLayers[index] = (MLoopCol *)CustomData_get_layer_n(&dm->loopData, CD_MLOOPCOL, index); } - return materialProps; -} + BL_SharedVertexMap sharedMap(totverts); -static PHY_ShapeProps *CreateShapePropsFromBlenderObject(struct Object* blenderobject) -{ - PHY_ShapeProps *shapeProps = new PHY_ShapeProps; + // Tracked vertices during a mpoly conversion, should never be used by the next mpoly. + std::vector vertices(totverts, -1); - MT_assert(shapeProps); + for (unsigned int i = 0; i < numpolys; ++i) { + const MPoly& mpoly = mpolys[i]; - shapeProps->m_mass = blenderobject->mass; + const BL_MeshMaterial& mat = mats[mpoly.mat_nr]; + RAS_DisplayArray *array = mat.array; -// This needs to be fixed in blender. For now, we use: + // Mark face as flat, so vertices are split. + const bool flat = (mpoly.flag & ME_SMOOTH) == 0; -// in Blender, inertia stands for the size value which is equivalent to -// the sphere radius - shapeProps->m_inertia = blenderobject->formfactor; + const unsigned int lpstart = mpoly.loopstart; + const unsigned int totlp = mpoly.totloop; + for (unsigned int j = lpstart; j < lpstart + totlp; ++j) { + const MLoop& mloop = mloops[j]; + const unsigned int vertid = mloop.v; + const MVert& mvert = mverts[vertid]; - MT_assert(0.0f <= blenderobject->damping && blenderobject->damping <= 1.0f); - MT_assert(0.0f <= blenderobject->rdamping && blenderobject->rdamping <= 1.0f); + static const float dummyTangent[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + const mt::vec4_packed tan(tangent ? tangent[j] : dummyTangent); + const mt::vec3_packed nor(normals[j]); + const mt::vec3_packed pos(mvert.co); + mt::vec2_packed uvs[RAS_Texture::MaxUnits]; + unsigned int rgba[RAS_Texture::MaxUnits]; - shapeProps->m_lin_drag = 1.0f - blenderobject->damping; - shapeProps->m_ang_drag = 1.0f - blenderobject->rdamping; + BL_GetUvRgba(layersInfo, uvLayers, colorLayers, j, uvs, rgba); - shapeProps->m_friction_scaling[0] = blenderobject->anisotropicFriction[0]; - shapeProps->m_friction_scaling[1] = blenderobject->anisotropicFriction[1]; - shapeProps->m_friction_scaling[2] = blenderobject->anisotropicFriction[2]; - shapeProps->m_do_anisotropic = ((blenderobject->gameflag & OB_ANISOTROPIC_FRICTION) != 0); + BL_SharedVertexList& sharedList = sharedMap[vertid]; + BL_SharedVertexList::iterator it = std::find_if(sharedList.begin(), sharedList.end(), + BL_SharedVertexPredicate(array, nor, tan, uvs, rgba)); - shapeProps->m_do_fh = (blenderobject->gameflag & OB_DO_FH) != 0; - shapeProps->m_do_rot_fh = (blenderobject->gameflag & OB_ROT_FH) != 0; + unsigned int offset; + if (it != sharedList.end()) { + offset = it->offset; + } + else { + offset = array->AddVertex(pos, nor, tan, uvs, rgba, vertid, flat); + sharedList.push_back({array, offset}); + } -// velocity clamping XXX - shapeProps->m_clamp_vel_min = blenderobject->min_vel; - shapeProps->m_clamp_vel_max = blenderobject->max_vel; - shapeProps->m_clamp_angvel_min = blenderobject->min_angvel; - shapeProps->m_clamp_angvel_max = blenderobject->max_angvel; + // Add tracked vertices by the mpoly. + vertices[vertid] = offset; + } -// Character physics properties - shapeProps->m_step_height = blenderobject->step_height; - shapeProps->m_jump_speed = blenderobject->jump_speed; - shapeProps->m_fall_speed = blenderobject->fall_speed; - shapeProps->m_max_jumps = blenderobject->max_jumps; + const unsigned int ltstart = poly_to_tri_count(i, mpoly.loopstart); + const unsigned int lttot = ME_POLY_TRI_TOT(&mpoly); + + if (mat.visible) { + if (mat.wire) { + // Convert to edges if material is rendering wire. + for (unsigned int j = lpstart; j < (lpstart + totlp); ++j) { + const MLoop& mloop = mloops[j]; + const MEdge& edge = medges[mloop.e]; + array->AddPrimitiveIndex(vertices[edge.v1]); + array->AddPrimitiveIndex(vertices[edge.v2]); + } + } + else { + for (unsigned int j = ltstart; j < (ltstart + lttot); ++j) { + const MLoopTri& mlooptri = mlooptris[j]; + for (unsigned short k = 0; k < 3; ++k) { + array->AddPrimitiveIndex(vertices[mloops[mlooptri.tri[k]].v]); + } + } + } + } - return shapeProps; + for (unsigned int j = ltstart; j < (ltstart + lttot); ++j) { + const MLoopTri& mlooptri = mlooptris[j]; + for (unsigned short k = 0; k < 3; ++k) { + // Add triangle index into display array. + array->AddTriangleIndex(vertices[mloops[mlooptri.tri[k]].v]); + } + } + } } - - - - -////////////////////////////////////////////////////////// - - - -static float my_boundbox_mesh(Mesh *me, float *loc, float *size) +RAS_Deformer *BL_ConvertDeformer(KX_GameObject *object, KX_Mesh *meshobj) { - MVert *mvert; - BoundBox *bb; - float min[3], max[3]; - float mloc[3], msize[3]; - float radius_sq=0.0f, vert_radius_sq, *co; - int a; + Mesh *mesh = meshobj->GetMesh(); - if (me->bb==0) { - me->bb = BKE_boundbox_alloc_unit(); + if (!mesh) { + return nullptr; } - bb= me->bb; - - INIT_MINMAX(min, max); - - if (!loc) loc= mloc; - if (!size) size= msize; - mvert= me->mvert; - for (a = 0; atotvert; a++, mvert++) { - co = mvert->co; - - /* bounds */ - minmax_v3v3_v3(min, max, co); + KX_Scene *scene = object->GetScene(); + Scene *blenderScene = scene->GetBlenderScene(); + // We must create a new deformer but which one? + KX_GameObject *parentobj = object->GetParent(); + /* Object that owns the mesh. If this is not the current blender object, look at one of the object registered + * along the blender mesh. */ + Object *meshblendobj; + Object *blenderobj = object->GetBlenderObject(); + if (blenderobj->data != mesh) { + meshblendobj = static_cast(scene->GetLogicManager()->FindBlendObjByGameMeshName(meshobj->GetName())); + } + else { + meshblendobj = blenderobj; + } - /* radius */ + const bool isParentArmature = parentobj && parentobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE; + const bool bHasModifier = BL_ModifierDeformer::HasCompatibleDeformer(blenderobj); + const bool bHasShapeKey = mesh->key && mesh->key->type == KEY_RELATIVE; + const bool bHasDvert = mesh->dvert && blenderobj->defbase.first; + const bool bHasArmature = BL_ModifierDeformer::HasArmatureDeformer(blenderobj) && + isParentArmature && meshblendobj && bHasDvert; +#ifdef WITH_BULLET + const bool bHasSoftBody = (!parentobj && (blenderobj->gameflag & OB_SOFT_BODY)); +#endif - vert_radius_sq = len_squared_v3(co); - if (vert_radius_sq > radius_sq) - radius_sq = vert_radius_sq; + if (!meshblendobj) { + if (bHasModifier || bHasShapeKey || bHasDvert || bHasArmature) { + CM_FunctionWarning("new mesh is not used in an object from the current scene, you will get incorrect behavior."); + return nullptr; + } } - if (me->totvert) { - loc[0] = (min[0] + max[0]) / 2.0f; - loc[1] = (min[1] + max[1]) / 2.0f; - loc[2] = (min[2] + max[2]) / 2.0f; - - size[0] = (max[0] - min[0]) / 2.0f; - size[1] = (max[1] - min[1]) / 2.0f; - size[2] = (max[2] - min[2]) / 2.0f; + RAS_Deformer *deformer = nullptr; + if (bHasModifier) { + if (isParentArmature) { + BL_ModifierDeformer *modifierDeformer = new BL_ModifierDeformer(object, blenderScene, meshblendobj, blenderobj, + meshobj, static_cast(parentobj)); + modifierDeformer->LoadShapeDrivers(parentobj); + deformer = modifierDeformer; + } + else { + deformer = new BL_ModifierDeformer(object, blenderScene, meshblendobj, blenderobj, meshobj, nullptr); + } } - else { - loc[0] = loc[1] = loc[2] = 0.0f; - size[0] = size[1] = size[2] = 0.0f; + else if (bHasShapeKey) { + if (isParentArmature) { + BL_ShapeDeformer *shapeDeformer = new BL_ShapeDeformer(object, meshblendobj, blenderobj, meshobj, + static_cast(parentobj)); + shapeDeformer->LoadShapeDrivers(parentobj); + deformer = shapeDeformer; + } + else { + deformer = new BL_ShapeDeformer(object, meshblendobj, blenderobj, meshobj, nullptr); + } + } + else if (bHasArmature) { + deformer = new BL_SkinDeformer(object, meshblendobj, blenderobj, meshobj, + static_cast(parentobj)); + } + else if (bHasDvert) { + deformer = new BL_MeshDeformer(object, meshblendobj, meshobj); } +#ifdef WITH_BULLET + else if (bHasSoftBody) { + deformer = new KX_SoftBodyDeformer(meshobj, object); + } +#endif - bb->vec[0][0] = bb->vec[1][0] = bb->vec[2][0] = bb->vec[3][0] = loc[0]-size[0]; - bb->vec[4][0] = bb->vec[5][0] = bb->vec[6][0] = bb->vec[7][0] = loc[0]+size[0]; + if (deformer) { + deformer->InitializeDisplayArrays(); + } - bb->vec[0][1] = bb->vec[1][1] = bb->vec[4][1] = bb->vec[5][1] = loc[1]-size[1]; - bb->vec[2][1] = bb->vec[3][1] = bb->vec[6][1] = bb->vec[7][1] = loc[1]+size[1]; + return deformer; +} - bb->vec[0][2] = bb->vec[3][2] = bb->vec[4][2] = bb->vec[7][2] = loc[2]-size[2]; - bb->vec[1][2] = bb->vec[2][2] = bb->vec[5][2] = bb->vec[6][2] = loc[2]+size[2]; +BL_ActionData *BL_ConvertAction(bAction *action, KX_Scene *scene, BL_SceneConverter& converter) +{ + BL_ActionData *data = new BL_ActionData(action); + converter.RegisterActionData(data); + scene->GetLogicManager()->RegisterActionName(action->id.name + 2, data); - return sqrtf_signed(radius_sq); + return data; } -////////////////////////////////////////////////////// - +void BL_ConvertActions(KX_Scene *scene, Main *maggie, BL_SceneConverter& converter) +{ + // Convert all actions and register. + for (bAction *act = (bAction *)maggie->action.first; act; act = (bAction *)act->id.next) { + BL_ConvertAction(act, scene, converter); + } +} -static void BL_CreateGraphicObjectNew(KX_GameObject* gameobj, - const MT_Point3& localAabbMin, - const MT_Point3& localAabbMax, - KX_Scene* kxscene, - bool isActive, - e_PhysicsEngine physics_engine) +static void BL_CreateGraphicObjectNew(KX_GameObject *gameobj, KX_Scene *kxscene, bool isActive, PHY_IPhysicsEnvironment *phyEnv) { - if (gameobj->GetMeshCount() > 0) - { - switch (physics_engine) - { #ifdef WITH_BULLET - case UseBullet: - { - CcdPhysicsEnvironment* env = (CcdPhysicsEnvironment*)kxscene->GetPhysicsEnvironment(); - assert(env); - PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode()); - CcdGraphicController* ctrl = new CcdGraphicController(env, motionstate); - gameobj->SetGraphicController(ctrl); - ctrl->SetNewClientInfo(gameobj->getClientInfo()); - ctrl->SetLocalAabb(localAabbMin, localAabbMax); - if (isActive) { - // add first, this will create the proxy handle, only if the object is visible - if (gameobj->GetVisible()) - env->AddCcdGraphicController(ctrl); - // update the mesh if there is a deformer, this will also update the bounding box for modifiers - RAS_Deformer* deformer = gameobj->GetDeformer(); - if (deformer) - deformer->UpdateBuckets(); - } - } - break; -#endif - default: - break; + CcdPhysicsEnvironment *env = static_cast(phyEnv); + PHY_IMotionState *motionstate = new KX_MotionState(gameobj->GetNode()); + CcdGraphicController *ctrl = new CcdGraphicController(env, motionstate); + gameobj->SetGraphicController(ctrl); + ctrl->SetNewClientInfo(&gameobj->GetClientInfo()); + if (isActive) { + // add first, this will create the proxy handle, only if the object is visible or occluder + if (gameobj->GetVisible() || gameobj->GetOccluder()) { + env->AddCcdGraphicController(ctrl); } } +#endif } -static void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj, - struct Object* blenderobject, - RAS_MeshObject* meshobj, - KX_Scene* kxscene, - int activeLayerBitInfo, - KX_BlenderSceneConverter *converter, - bool processCompoundChildren - ) +static void BL_CreatePhysicsObjectNew(KX_GameObject *gameobj, Object *blenderobject, KX_Mesh *meshobj, + KX_Scene *kxscene, int activeLayerBitInfo, BL_SceneConverter& converter, bool processCompoundChildren) { - //SYS_SystemHandle syshandle = SYS_GetSystem(); /*unused*/ - //int userigidbody = SYS_GetCommandLineInt(syshandle,"norigidbody",0); - //bool bRigidBody = (userigidbody == 0); - - // object has physics representation? + // Object has physics representation? if (!(blenderobject->gameflag & OB_COLLISION)) { - // Respond to all collisions so that Near sensors work on No Collision - // objects. - gameobj->SetUserCollisionGroup(0xffff); - gameobj->SetUserCollisionMask(0xffff); return; } - gameobj->SetUserCollisionGroup(blenderobject->col_group); - gameobj->SetUserCollisionMask(blenderobject->col_mask); - - // get Root Parent of blenderobject - struct Object* parent= blenderobject->parent; - while (parent && parent->parent) { - parent= parent->parent; - } + Object *parent = blenderobject->parent; bool isCompoundChild = false; - bool hasCompoundChildren = !parent && (blenderobject->gameflag & OB_CHILD) && !(blenderobject->gameflag & OB_SOFT_BODY); - - /* When the parent is not OB_DYNAMIC and has no OB_COLLISION then it gets no bullet controller - * and cant be apart of the parents compound shape, same goes for OB_SOFT_BODY */ - if (parent && (parent->gameflag & (OB_DYNAMIC | OB_COLLISION))) { - if ((parent->gameflag & OB_CHILD)!=0 && (blenderobject->gameflag & OB_CHILD) && !(parent->gameflag & OB_SOFT_BODY)) { - isCompoundChild = true; + bool hasCompoundChildren = false; + + // Pretend for compound parent or child if the object has compound option and use a physics type with solid shape. + if ((blenderobject->gameflag & (OB_CHILD)) && (blenderobject->gameflag & (OB_DYNAMIC | OB_COLLISION | OB_RIGID_BODY)) && + !(blenderobject->gameflag & OB_SOFT_BODY)) { + hasCompoundChildren = true; + while (parent) { + if ((parent->gameflag & OB_CHILD) && (parent->gameflag & (OB_COLLISION | OB_DYNAMIC | OB_RIGID_BODY)) && + !(parent->gameflag & OB_SOFT_BODY)) { + // Found a parent in the tree with compound shape. + isCompoundChild = true; + /* The object is not a parent compound shape if it has a parent + * object with compound shape. */ + hasCompoundChildren = false; + break; + } + parent = parent->parent; } } - if (processCompoundChildren != isCompoundChild) - return; + if (processCompoundChildren != isCompoundChild) { + return; + } - PHY_ShapeProps* shapeprops = - CreateShapePropsFromBlenderObject(blenderobject); - - - PHY_MaterialProps* smmaterial = - CreateMaterialFromBlenderObject(blenderobject); - - DerivedMesh* dm = NULL; - if (gameobj->GetDeformer()) - dm = gameobj->GetDeformer()->GetPhysicsMesh(); - - class PHY_IMotionState* motionstate = new KX_MotionState(gameobj->GetSGNode()); + PHY_IMotionState *motionstate = new KX_MotionState(gameobj->GetNode()); - kxscene->GetPhysicsEnvironment()->ConvertObject(gameobj, meshobj, dm, kxscene, shapeprops, smmaterial, motionstate, activeLayerBitInfo, isCompoundChild, hasCompoundChildren); + PHY_IPhysicsEnvironment *phyenv = kxscene->GetPhysicsEnvironment(); + phyenv->ConvertObject(converter, gameobj, meshobj, kxscene, motionstate, activeLayerBitInfo, + isCompoundChild, hasCompoundChildren); - bool isActor = (blenderobject->gameflag & OB_ACTOR)!=0; + bool isActor = (blenderobject->gameflag & OB_ACTOR) != 0; bool isSensor = (blenderobject->gameflag & OB_SENSOR) != 0; - gameobj->getClientInfo()->m_type = + gameobj->GetClientInfo().m_type = (isSensor) ? ((isActor) ? KX_ClientObjectInfo::OBACTORSENSOR : KX_ClientObjectInfo::OBSENSOR) : (isActor) ? KX_ClientObjectInfo::ACTOR : KX_ClientObjectInfo::STATIC; +} - // should we record animation for this object? - if ((blenderobject->gameflag & OB_RECORD_ANIMATION) != 0) - gameobj->SetRecordAnimation(true); +static KX_LodManager *BL_LodManagerFromBlenderObject(Object *ob, KX_Scene *scene, BL_SceneConverter& converter) +{ + if (BLI_listbase_count(&ob->lodlevels) <= 1) { + return nullptr; + } - delete shapeprops; - delete smmaterial; - if (dm) { - dm->needsFree = 1; - dm->release(dm); + KX_LodManager *lodManager = new KX_LodManager(ob, scene, converter); + // The lod manager is useless ? + if (lodManager->GetLevelCount() <= 1) { + lodManager->Release(); + return nullptr; } -} + return lodManager; +} +/** Convert the object activity culling settings from blender to a KX_GameObject::ActivityCullingInfo. + * \param ob The object to convert the activity culling settings from. + */ +static KX_GameObject::ActivityCullingInfo activityCullingInfoFromBlenderObject(Object *ob) +{ + KX_GameObject::ActivityCullingInfo cullingInfo; + const ObjectActivityCulling& blenderInfo = ob->activityCulling; + // Convert the flags. + if (blenderInfo.flags & OB_ACTIVITY_PHYSICS) { + // Enable physics culling. + cullingInfo.m_flags = (KX_GameObject::ActivityCullingInfo::Flag)( + cullingInfo.m_flags | KX_GameObject::ActivityCullingInfo::ACTIVITY_PHYSICS); + } + if (blenderInfo.flags & OB_ACTIVITY_LOGIC) { + // Enable logic culling. + cullingInfo.m_flags = (KX_GameObject::ActivityCullingInfo::Flag)( + cullingInfo.m_flags | KX_GameObject::ActivityCullingInfo::ACTIVITY_LOGIC); + } + // Set culling radius. + cullingInfo.m_physicsRadius = blenderInfo.physicsRadius * blenderInfo.physicsRadius; + cullingInfo.m_logicRadius = blenderInfo.logicRadius * blenderInfo.logicRadius; + return cullingInfo; +} -static KX_LightObject *gamelight_from_blamp(Object *ob, Lamp *la, unsigned int layerflag, KX_Scene *kxscene, RAS_IRasterizer *rasterizer, KX_BlenderSceneConverter *converter) +static KX_LightObject *BL_GameLightFromBlenderLamp(Lamp *la, unsigned int layerflag, KX_Scene *kxscene, RAS_Rasterizer *rasterizer) { RAS_ILightObject *lightobj = rasterizer->CreateLight(); - KX_LightObject *gamelight; lightobj->m_att1 = la->att1; lightobj->m_att2 = (la->mode & LA_QUAD) ? la->att2 : 0.0f; lightobj->m_coeff_const = la->coeff_const; lightobj->m_coeff_lin = la->coeff_lin; lightobj->m_coeff_quad = la->coeff_quad; - lightobj->m_color[0] = la->r; - lightobj->m_color[1] = la->g; - lightobj->m_color[2] = la->b; + lightobj->m_color = mt::vec3(la->r, la->g, la->b); lightobj->m_distance = la->dist; lightobj->m_energy = la->energy; lightobj->m_shadowclipstart = la->clipsta; @@ -1432,308 +876,246 @@ static KX_LightObject *gamelight_from_blamp(Object *ob, Lamp *la, unsigned int l lightobj->m_shadowbleedbias = la->bleedbias; lightobj->m_shadowmaptype = la->shadowmap_type; lightobj->m_shadowfrustumsize = la->shadow_frustum_size; - lightobj->m_shadowcolor[0] = la->shdwr; - lightobj->m_shadowcolor[1] = la->shdwg; - lightobj->m_shadowcolor[2] = la->shdwb; + lightobj->m_shadowcolor = mt::vec3(la->shdwr, la->shdwg, la->shdwb); lightobj->m_layer = layerflag; lightobj->m_spotblend = la->spotblend; lightobj->m_spotsize = la->spotsize; + lightobj->m_staticShadow = la->mode & LA_STATIC_SHADOW; + // Set to true to make at least one shadow render in static mode. + lightobj->m_requestShadowUpdate = true; lightobj->m_nodiffuse = (la->mode & LA_NO_DIFF) != 0; lightobj->m_nospecular = (la->mode & LA_NO_SPEC) != 0; - bool glslmat = converter->GetGLSLMaterials(); - - // in GLSL NEGATIVE LAMP is handled inside the lamp update function - if (glslmat==0) { - if (la->mode & LA_NEG) + switch (la->type) { + case LA_SUN: { - lightobj->m_color[0] = -lightobj->m_color[0]; - lightobj->m_color[1] = -lightobj->m_color[1]; - lightobj->m_color[2] = -lightobj->m_color[2]; + lightobj->m_type = RAS_ILightObject::LIGHT_SUN; + break; + } + case LA_SPOT: + { + lightobj->m_type = RAS_ILightObject::LIGHT_SPOT; + break; + } + case LA_HEMI: + { + lightobj->m_type = RAS_ILightObject::LIGHT_HEMI; + break; + } + default: + { + lightobj->m_type = RAS_ILightObject::LIGHT_NORMAL; } } - if (la->type==LA_SUN) { - lightobj->m_type = RAS_ILightObject::LIGHT_SUN; - } else if (la->type==LA_SPOT) { - lightobj->m_type = RAS_ILightObject::LIGHT_SPOT; - } else { - lightobj->m_type = RAS_ILightObject::LIGHT_NORMAL; - } + KX_LightObject *gamelight = new KX_LightObject(kxscene, KX_Scene::m_callbacks, rasterizer, lightobj); - gamelight = new KX_LightObject(kxscene, KX_Scene::m_callbacks, rasterizer, - lightobj, glslmat); + gamelight->SetShowShadowFrustum((la->mode & LA_SHOW_SHADOW_BOX) && (la->mode & LA_SHAD_RAY)); return gamelight; } -static KX_Camera *gamecamera_from_bcamera(Object *ob, KX_Scene *kxscene, KX_BlenderSceneConverter *converter) +static KX_Camera *BL_GameCameraFromBlenderCamera(Object *ob, KX_Scene *kxscene, RAS_ICanvas *canvas, float camZoom) { - Camera* ca = static_cast(ob->data); - RAS_CameraData camdata(ca->lens, ca->ortho_scale, ca->sensor_x, ca->sensor_y, ca->sensor_fit, ca->shiftx, ca->shifty, ca->clipsta, ca->clipend, ca->type == CAM_PERSP, ca->YF_dofdist); + Camera *ca = static_cast(ob->data); + RAS_CameraData camdata(ca->lens, ca->ortho_scale, ca->sensor_x, ca->sensor_y, ca->sensor_fit, ca->shiftx, ca->shifty, ca->clipsta, ca->clipend, ca->type == CAM_PERSP, ca->YF_dofdist, camZoom); KX_Camera *gamecamera; - gamecamera= new KX_Camera(kxscene, KX_Scene::m_callbacks, camdata); + gamecamera = new KX_Camera(kxscene, KX_Scene::m_callbacks, camdata); gamecamera->SetName(ca->id.name + 2); + if (ca->gameflag & GAME_CAM_VIEWPORT) { + const GameCameraViewportSettings& settings = ca->gameviewport; + if (settings.leftratio > settings.rightratio || settings.bottomratio > settings.topratio) { + CM_Warning("\"" << gamecamera->GetName() << "\" uses invalid custom viewport ratios, disabling custom viewport."); + } + else { + gamecamera->EnableViewport(true); + const int maxx = canvas->GetMaxX(); + const int maxy = canvas->GetMaxY(); + gamecamera->SetViewport(maxx * settings.leftratio, maxy * settings.bottomratio, + maxx * settings.rightratio, maxy * settings.topratio); + } + } + + gamecamera->SetShowCameraFrustum(ca->gameflag & GAME_CAM_SHOW_FRUSTUM); + gamecamera->SetLodDistanceFactor(ca->lodfactor); + + gamecamera->SetActivityCulling(ca->gameflag & GAME_CAM_OBJECT_ACTIVITY_CULLING); + + if (ca->gameflag & GAME_CAM_OVERRIDE_CULLING) { + if (kxscene->GetOverrideCullingCamera()) { + CM_Warning("\"" << gamecamera->GetName() << "\" sets for culling override whereas \"" + << kxscene->GetOverrideCullingCamera()->GetName() << "\" is already used for culling override."); + } + else { + kxscene->SetOverrideCullingCamera(gamecamera); + } + } + return gamecamera; } -static KX_GameObject *gameobject_from_blenderobject( - Object *ob, - KX_Scene *kxscene, - RAS_IRasterizer *rendertools, - KX_BlenderSceneConverter *converter, - bool libloading) +static KX_GameObject *BL_GameObjectFromBlenderObject(Object *ob, KX_Scene *kxscene, RAS_Rasterizer *rendertools, + RAS_ICanvas *canvas, BL_SceneConverter &converter, float camZoom) { - KX_GameObject *gameobj = NULL; + KX_GameObject *gameobj = nullptr; Scene *blenderscene = kxscene->GetBlenderScene(); switch (ob->type) { - case OB_LAMP: - { - KX_LightObject* gamelight = gamelight_from_blamp(ob, static_cast(ob->data), ob->lay, kxscene, rendertools, converter); - gameobj = gamelight; - - if (blenderscene->lay & ob->lay) + case OB_LAMP: { + KX_LightObject *gamelight = BL_GameLightFromBlenderLamp(static_cast(ob->data), ob->lay, kxscene, rendertools); + gameobj = gamelight; gamelight->AddRef(); kxscene->GetLightList()->Add(gamelight); - } - - break; - } - - case OB_CAMERA: - { - KX_Camera* gamecamera = gamecamera_from_bcamera(ob, kxscene, converter); - gameobj = gamecamera; - //don't add a reference: the camera list in kxscene->m_cameras is not released at the end - //gamecamera->AddRef(); - kxscene->AddCamera(gamecamera); - - break; - } + break; + } - case OB_MESH: - { - Mesh* mesh = static_cast(ob->data); - float center[3], extents[3]; - float radius = my_boundbox_mesh((Mesh*) ob->data, center, extents); - RAS_MeshObject* meshobj = BL_ConvertMesh(mesh,ob,kxscene,converter, libloading); + case OB_CAMERA: + { + KX_Camera *gamecamera = BL_GameCameraFromBlenderCamera(ob, kxscene, canvas, camZoom); + gameobj = gamecamera; - // needed for python scripting - kxscene->GetLogicManager()->RegisterMeshName(meshobj->GetName(),meshobj); + kxscene->GetCameraList()->Add(CM_AddRef(gamecamera)); - if (ob->gameflag & OB_NAVMESH) - { - gameobj = new KX_NavMeshObject(kxscene,KX_Scene::m_callbacks); - gameobj->AddMesh(meshobj); break; } - gameobj = new BL_DeformableGameObject(ob,kxscene,KX_Scene::m_callbacks); - - // set transformation - gameobj->AddMesh(meshobj); + case OB_MESH: + { + Mesh *mesh = static_cast(ob->data); + KX_Mesh *meshobj = BL_ConvertMesh(mesh, ob, kxscene, converter); - // gather levels of detail - if (BLI_listbase_count_at_most(&ob->lodlevels, 2) > 1) { - LodLevel *lod = ((LodLevel*)ob->lodlevels.first)->next; - Mesh* lodmesh = mesh; - Object* lodmatob = ob; - gameobj->AddLodMesh(meshobj); - for (; lod; lod = lod->next) { - if (!lod->source || lod->source->type != OB_MESH) continue; - if (lod->flags & OB_LOD_USE_MESH) { - lodmesh = static_cast(lod->source->data); - } - if (lod->flags & OB_LOD_USE_MAT) { - lodmatob = lod->source; - } - gameobj->AddLodMesh(BL_ConvertMesh(lodmesh, lodmatob, kxscene, converter, libloading)); - } - if (blenderscene->gm.lodflag & SCE_LOD_USE_HYST) { - kxscene->SetLodHysteresis(true); - kxscene->SetLodHysteresisValue(blenderscene->gm.scehysteresis); + if (ob->gameflag & OB_NAVMESH) { + gameobj = new KX_NavMeshObject(kxscene, KX_Scene::m_callbacks); + gameobj->AddMesh(meshobj); + break; } - } - // for all objects: check whether they want to - // respond to updates - bool ignoreActivityCulling = - ((ob->gameflag2 & OB_NEVER_DO_ACTIVITY_CULLING)!=0); - gameobj->SetIgnoreActivityCulling(ignoreActivityCulling); - gameobj->SetOccluder((ob->gameflag & OB_OCCLUDER) != 0, false); - // we only want obcolor used if there is a material in the mesh - // that requires it - Material *mat= NULL; - bool bUseObjectColor=false; + KX_GameObject *deformableGameObj = new KX_GameObject(kxscene, KX_Scene::m_callbacks); + gameobj = deformableGameObj; + + // set transformation + gameobj->AddMesh(meshobj); - for (int i=0;itotcol;i++) { - mat=mesh->mat[i]; - if (!mat) break; - if ((mat->shade_flag & MA_OBCOLOR)) { - bUseObjectColor = true; - break; + // gather levels of detail + KX_LodManager *lodManager = BL_LodManagerFromBlenderObject(ob, kxscene, converter); + gameobj->SetLodManager(lodManager); + if (lodManager) { + lodManager->Release(); } - } - if (bUseObjectColor) - gameobj->SetObjectColor(ob->col); - // two options exists for deform: shape keys and armature - // only support relative shape key - bool bHasShapeKey = mesh->key != NULL && mesh->key->type==KEY_RELATIVE; - bool bHasDvert = mesh->dvert != NULL && ob->defbase.first; - bool bHasArmature = (BL_ModifierDeformer::HasArmatureDeformer(ob) && ob->parent && ob->parent->type == OB_ARMATURE && bHasDvert); - bool bHasModifier = BL_ModifierDeformer::HasCompatibleDeformer(ob); -#ifdef WITH_BULLET - bool bHasSoftBody = (!ob->parent && (ob->gameflag & OB_SOFT_BODY)); -#endif - if (bHasModifier) { - BL_ModifierDeformer *dcont = new BL_ModifierDeformer((BL_DeformableGameObject *)gameobj, - kxscene->GetBlenderScene(), ob, meshobj); - ((BL_DeformableGameObject*)gameobj)->SetDeformer(dcont); - } else if (bHasShapeKey) { - // not that we can have shape keys without dvert! - BL_ShapeDeformer *dcont = new BL_ShapeDeformer((BL_DeformableGameObject*)gameobj, - ob, meshobj); - ((BL_DeformableGameObject*)gameobj)->SetDeformer(dcont); - } else if (bHasArmature) { - BL_SkinDeformer *dcont = new BL_SkinDeformer((BL_DeformableGameObject*)gameobj, - ob, meshobj); - ((BL_DeformableGameObject*)gameobj)->SetDeformer(dcont); - } else if (bHasDvert) { - // this case correspond to a mesh that can potentially deform but not with the - // object to which it is attached for the moment. A skin mesh was created in - // BL_ConvertMesh() so must create a deformer too! - BL_MeshDeformer *dcont = new BL_MeshDeformer((BL_DeformableGameObject*)gameobj, - ob, meshobj); - ((BL_DeformableGameObject*)gameobj)->SetDeformer(dcont); -#ifdef WITH_BULLET - } else if (bHasSoftBody) { - KX_SoftBodyDeformer *dcont = new KX_SoftBodyDeformer(meshobj, (BL_DeformableGameObject*)gameobj); - ((BL_DeformableGameObject*)gameobj)->SetDeformer(dcont); -#endif + gameobj->SetOccluder((ob->gameflag & OB_OCCLUDER) != 0, false); + gameobj->SetActivityCullingInfo(activityCullingInfoFromBlenderObject(ob)); + break; } - MT_Point3 min = MT_Point3(center) - MT_Vector3(extents); - MT_Point3 max = MT_Point3(center) + MT_Vector3(extents); - SG_BBox bbox = SG_BBox(min, max); - gameobj->GetSGNode()->SetBBox(bbox); - gameobj->GetSGNode()->SetRadius(radius); + case OB_ARMATURE: + { + gameobj = new BL_ArmatureObject(kxscene, KX_Scene::m_callbacks, ob, kxscene->GetBlenderScene()); - break; - } + break; + } - case OB_ARMATURE: - { - bArmature *arm = (bArmature*)ob->data; - gameobj = new BL_ArmatureObject( - kxscene, - KX_Scene::m_callbacks, - ob, - kxscene->GetBlenderScene(), // handle - arm->gevertdeformer - ); - /* Get the current pose from the armature object and apply it as the rest pose */ - break; - } - - case OB_EMPTY: - { - gameobj = new KX_EmptyObject(kxscene,KX_Scene::m_callbacks); - // set transformation - break; - } + case OB_EMPTY: + { + gameobj = new KX_EmptyObject(kxscene, KX_Scene::m_callbacks); - case OB_FONT: - { - bool do_color_management = BKE_scene_check_color_management_enabled(blenderscene); - /* font objects have no bounding box */ - gameobj = new KX_FontObject(kxscene,KX_Scene::m_callbacks, rendertools, ob, do_color_management); + break; + } - /* add to the list only the visible fonts */ - if ((ob->lay & kxscene->GetBlenderScene()->lay) != 0) - kxscene->AddFont(static_cast(gameobj)); - break; - } + case OB_FONT: + { + // Font objects have no bounding box. + KX_FontObject *fontobj = new KX_FontObject(kxscene, KX_Scene::m_callbacks, rendertools, + kxscene->GetBoundingBoxManager(), ob); + gameobj = fontobj; + + kxscene->GetFontList()->Add(CM_AddRef(fontobj)); + break; + } #ifdef THREADED_DAG_WORKAROUND - case OB_CURVE: - { - if (ob->curve_cache == NULL) { - BKE_displist_make_curveTypes(blenderscene, ob, false); + case OB_CURVE: + { + if (ob->curve_cache == nullptr) { + BKE_displist_make_curveTypes(blenderscene, ob, false); + } + /* We can convert curves as empty for experimental purposes in 2.7 + * and to prepare transition to 2.8. + * Note: if we use eevee render in 2.8, to finalize stuff about curves, + * see : https://github.com/youle31/EEVEEinUPBGE/commit/ff11e0fdea4dfc121a7eaa7b7d48183eaf5fd9f6 + * for comments about culling. + */ + gameobj = new KX_EmptyObject(kxscene, KX_Scene::m_callbacks); + break; } - } #endif - } - if (gameobj) - { + if (gameobj) { gameobj->SetLayer(ob->lay); - gameobj->SetBlenderObject(ob); - /* set the visibility state based on the objects render option in the outliner */ - if (ob->restrictflag & OB_RESTRICT_RENDER) gameobj->SetVisible(0, 0); + gameobj->SetPassIndex(ob->index); + BL_ConvertObjectInfo *info = converter.GetObjectInfo(ob); + gameobj->SetConvertObjectInfo(info); + gameobj->SetObjectColor(mt::vec4(ob->col)); + // Set the visibility state based on the objects render option in the outliner. + if (ob->restrictflag & OB_RESTRICT_RENDER) { + gameobj->SetVisible(false, false); + } } + return gameobj; } -struct parentChildLink { - struct Object* m_blenderchild; - SG_Node* m_gamechildnode; +struct BL_ParentChildLink { + struct Object *m_blenderchild; + SG_Node *m_gamechildnode; }; -static bPoseChannel *get_active_posechannel2(Object *ob) + +static bPoseChannel *BL_GetActivePoseChannel(Object *ob) { - bArmature *arm= (bArmature*)ob->data; + bArmature *arm = (bArmature *)ob->data; bPoseChannel *pchan; /* find active */ - for (pchan= (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan= pchan->next) { - if (pchan->bone && (pchan->bone == arm->act_bone) && (pchan->bone->layer & arm->layer)) + for (pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { + if (pchan->bone && (pchan->bone == arm->act_bone) && (pchan->bone->layer & arm->layer)) { return pchan; + } } - return NULL; + return nullptr; } -static ListBase *get_active_constraints2(Object *ob) +static ListBase *BL_GetActiveConstraint(Object *ob) { - if (!ob) - return NULL; + if (!ob) { + return nullptr; + } - // XXX - shouldnt we care about the pose data and not the mode??? + // XXX - shouldnt we care about the pose data and not the mode??? if (ob->mode & OB_MODE_POSE) { bPoseChannel *pchan; - pchan = get_active_posechannel2(ob); - if (pchan) + pchan = BL_GetActivePoseChannel(ob); + if (pchan) { return &pchan->constraints; + } } - else + else { return &ob->constraints; - - return NULL; -} - -static void UNUSED_FUNCTION(print_active_constraints2)(Object *ob) //not used, use to debug -{ - bConstraint* curcon; - ListBase* conlist = get_active_constraints2(ob); - - if (conlist) { - for (curcon = (bConstraint *)conlist->first; curcon; curcon = (bConstraint *)curcon->next) { - printf("%i\n",curcon->type); - } } + + return nullptr; } // Copy base layer to object layer like in BKE_scene_set_background -static void blenderSceneSetBackground(Scene *blenderscene) +static void BL_SetBlenderSceneBackground(Scene *blenderscene) { Scene *it; Base *base; @@ -1744,155 +1126,181 @@ static void blenderSceneSetBackground(Scene *blenderscene) } } -static KX_GameObject* getGameOb(STR_String busc,CListValue* sumolist) +static void BL_ConvertComponentsObject(KX_GameObject *gameobj, Object *blenderobj) { +#ifdef WITH_PYTHON + PythonComponent *pc = (PythonComponent *)blenderobj->components.first; + PyObject *arg_dict = nullptr, *args = nullptr, *mod = nullptr, *cls = nullptr, *pycomp = nullptr, *ret = nullptr; - for (int j=0;jGetCount();j++) - { - KX_GameObject* gameobje = (KX_GameObject*) sumolist->GetValue(j); - if (gameobje->GetName()==busc) - return gameobje; + if (!pc) { + return; } - return 0; + EXP_ListValue *components = new EXP_ListValue(); -} + while (pc) { + // Make sure to clean out anything from previous loops + Py_XDECREF(args); + Py_XDECREF(arg_dict); + Py_XDECREF(mod); + Py_XDECREF(cls); + Py_XDECREF(ret); + Py_XDECREF(pycomp); + args = arg_dict = mod = cls = pycomp = ret = nullptr; -static bool bl_isConstraintInList(KX_GameObject *gameobj, set convertedlist) -{ - set::iterator gobit; - for (gobit = convertedlist.begin(); gobit != convertedlist.end(); gobit++) { - if ((*gobit)->GetName() == gameobj->GetName()) - return true; + // Grab the module + mod = PyImport_ImportModule(pc->module); + + if (mod == nullptr) { + if (PyErr_Occurred()) { + PyErr_Print(); + } + CM_Error("coulding import the module '" << pc->module << "'"); + pc = pc->next; + continue; + } + + // Grab the class object + cls = PyObject_GetAttrString(mod, pc->name); + if (cls == nullptr) { + if (PyErr_Occurred()) { + PyErr_Print(); + } + CM_Error("python module found, but failed to find the component '" << pc->name << "'"); + pc = pc->next; + continue; + } + + // Lastly make sure we have a class and it's an appropriate sub type + if (!PyType_Check(cls) || !PyObject_IsSubclass(cls, (PyObject *)&KX_PythonComponent::Type)) { + CM_Error(pc->module << "." << pc->name << " is not a KX_PythonComponent subclass"); + pc = pc->next; + continue; + } + + // Every thing checks out, now generate the args dictionary and init the component + args = PyTuple_Pack(1, gameobj->GetProxy()); + + pycomp = PyObject_Call(cls, args, nullptr); + + if (PyErr_Occurred()) { + // The component is invalid, drop it + PyErr_Print(); + } + else { + KX_PythonComponent *comp = static_cast(EXP_PROXY_REF(pycomp)); + comp->SetBlenderPythonComponent(pc); + comp->SetGameObject(gameobj); + components->Add(comp); + } + + pc = pc->next; } - return false; + + Py_XDECREF(args); + Py_XDECREF(mod); + Py_XDECREF(cls); + Py_XDECREF(pycomp); + + gameobj->SetComponents(components); +#endif // WITH_PYTHON } /* helper for BL_ConvertBlenderObjects, avoids code duplication * note: all var names match args are passed from the caller */ -static void bl_ConvertBlenderObject_Single( - KX_BlenderSceneConverter *converter, - Object *blenderobject, - vector &vec_parent_child, - CListValue* logicbrick_conversionlist, - CListValue* objectlist, CListValue* inactivelist, CListValue* sumolist, - KX_Scene* kxscene, KX_GameObject* gameobj, - SCA_LogicManager* logicmgr, SCA_TimeEventManager* timemgr, - bool isInActiveLayer - ) +static void bl_ConvertBlenderObject_Single(BL_SceneConverter& converter, + Object *blenderobject, + std::vector &vec_parent_child, + EXP_ListValue *logicbrick_conversionlist, + EXP_ListValue *objectlist, EXP_ListValue *inactivelist, + KX_Scene *kxscene, KX_GameObject *gameobj, + SCA_LogicManager *logicmgr, SCA_TimeEventManager *timemgr, + bool isInActiveLayer) { - MT_Point3 pos( - blenderobject->loc[0]+blenderobject->dloc[0], - blenderobject->loc[1]+blenderobject->dloc[1], - blenderobject->loc[2]+blenderobject->dloc[2] - ); + const mt::vec3 pos( + blenderobject->loc[0] + blenderobject->dloc[0], + blenderobject->loc[1] + blenderobject->dloc[1], + blenderobject->loc[2] + blenderobject->dloc[2]); - MT_Matrix3x3 rotation; float rotmat[3][3]; BKE_object_rot_to_mat3(blenderobject, rotmat, false); - rotation.setValue3x3((float*)rotmat); + const mt::mat3 rotation(rotmat); - MT_Vector3 scale(blenderobject->size); + const mt::vec3 scale( + blenderobject->size[0] * blenderobject->dscale[0], + blenderobject->size[1] * blenderobject->dscale[1], + blenderobject->size[2] * blenderobject->dscale[2]); gameobj->NodeSetLocalPosition(pos); gameobj->NodeSetLocalOrientation(rotation); gameobj->NodeSetLocalScale(scale); - gameobj->NodeUpdateGS(0); - - sumolist->Add(gameobj->AddRef()); + gameobj->NodeUpdate(); - BL_ConvertProperties(blenderobject,gameobj,timemgr,kxscene,isInActiveLayer); + BL_ConvertProperties(blenderobject, gameobj, timemgr, kxscene, isInActiveLayer); gameobj->SetName(blenderobject->id.name + 2); - // update children/parent hierarchy - if (blenderobject->parent != 0) - { - // blender has an additional 'parentinverse' offset in each object - SG_Callbacks callback(NULL,NULL,NULL,KX_Scene::KX_ScenegraphUpdateFunc,KX_Scene::KX_ScenegraphRescheduleFunc); - SG_Node* parentinversenode = new SG_Node(NULL,kxscene,callback); + // Update children/parent hierarchy. + if (blenderobject->parent != 0) { + // Blender has an additional 'parentinverse' offset in each object. + SG_Callbacks callback(nullptr, nullptr, nullptr, KX_Scene::KX_ScenegraphUpdateFunc, KX_Scene::KX_ScenegraphRescheduleFunc); + SG_Node *parentinversenode = new SG_Node(nullptr, kxscene, callback); - // define a normal parent relationship for this node. - KX_NormalParentRelation * parent_relation = KX_NormalParentRelation::New(); + // Define a normal parent relationship for this node. + KX_NormalParentRelation *parent_relation = new KX_NormalParentRelation(); parentinversenode->SetParentRelation(parent_relation); - parentChildLink pclink; + BL_ParentChildLink pclink; pclink.m_blenderchild = blenderobject; pclink.m_gamechildnode = parentinversenode; vec_parent_child.push_back(pclink); - float* fl = (float*) blenderobject->parentinv; - MT_Transform parinvtrans(fl); - parentinversenode->SetLocalPosition(parinvtrans.getOrigin()); - // problem here: the parent inverse transform combines scaling and rotation - // in the basis but the scenegraph needs separate rotation and scaling. - // This is not important for OpenGL (it uses 4x4 matrix) but it is important - // for the physic engine that needs a separate scaling - //parentinversenode->SetLocalOrientation(parinvtrans.getBasis()); - - // Extract the rotation and the scaling from the basis - MT_Matrix3x3 ori(parinvtrans.getBasis()); - MT_Vector3 x(ori.getColumn(0)); - MT_Vector3 y(ori.getColumn(1)); - MT_Vector3 z(ori.getColumn(2)); - MT_Vector3 parscale(x.length(), y.length(), z.length()); - if (!MT_fuzzyZero(parscale[0])) - x /= parscale[0]; - if (!MT_fuzzyZero(parscale[1])) - y /= parscale[1]; - if (!MT_fuzzyZero(parscale[2])) - z /= parscale[2]; - ori.setColumn(0, x); - ori.setColumn(1, y); - ori.setColumn(2, z); - parentinversenode->SetLocalOrientation(ori); - parentinversenode->SetLocalScale(parscale); - - parentinversenode->AddChild(gameobj->GetSGNode()); - } - - // needed for python scripting - logicmgr->RegisterGameObjectName(gameobj->GetName(),gameobj); - - // needed for group duplication + // Extract location, orientation and scale out of the inverse parent matrix. + float invp_loc[3], invp_rot[3][3], invp_size[3]; + mat4_to_loc_rot_size(invp_loc, invp_rot, invp_size, blenderobject->parentinv); + + parentinversenode->SetLocalPosition(mt::vec3(invp_loc)); + parentinversenode->SetLocalOrientation(mt::mat3(invp_rot)); + parentinversenode->SetLocalScale(mt::vec3(invp_size)); + parentinversenode->AddChild(gameobj->GetNode()); + } + + // Needed for python scripting. + logicmgr->RegisterGameObjectName(gameobj->GetName(), gameobj); + + // Needed for group duplication. logicmgr->RegisterGameObj(blenderobject, gameobj); - for (int i = 0; i < gameobj->GetMeshCount(); i++) - logicmgr->RegisterGameMeshName(gameobj->GetMesh(i)->GetName(), blenderobject); + for (RAS_Mesh *meshobj : gameobj->GetMeshList()) { + logicmgr->RegisterGameMeshName(meshobj->GetName(), blenderobject); + } - converter->RegisterGameObject(gameobj, blenderobject); - // this was put in rapidly, needs to be looked at more closely - // only draw/use objects in active 'blender' layers + converter.RegisterGameObject(gameobj, blenderobject); - logicbrick_conversionlist->Add(gameobj->AddRef()); + logicbrick_conversionlist->Add(CM_AddRef(gameobj)); - if (isInActiveLayer) - { - objectlist->Add(gameobj->AddRef()); - //tf.Add(gameobj->GetSGNode()); + // Only draw/use objects in active 'blender' layers. + if (isInActiveLayer) { + objectlist->Add(CM_AddRef(gameobj)); - gameobj->NodeUpdateGS(0); - gameobj->AddMeshUser(); + gameobj->NodeUpdate(); } - else - { - //we must store this object otherwise it will be deleted - //at the end of this function if it is not a root object - inactivelist->Add(gameobj->AddRef()); + else { + // We must store this object otherwise it will be deleted at the end of this function if it is not a root object. + inactivelist->Add(CM_AddRef(gameobj)); } } -// convert blender objects into ketsji gameobjects -void BL_ConvertBlenderObjects(struct Main* maggie, - KX_Scene* kxscene, - KX_KetsjiEngine* ketsjiEngine, - e_PhysicsEngine physics_engine, - RAS_IRasterizer* rendertools, - RAS_ICanvas* canvas, - KX_BlenderSceneConverter* converter, - bool alwaysUseExpandFraming, - bool libloading - ) +/// Convert blender objects into ketsji gameobjects. +void BL_ConvertBlenderObjects(struct Main *maggie, + KX_Scene *kxscene, + KX_KetsjiEngine *ketsjiEngine, + RAS_Rasterizer *rendertools, + RAS_ICanvas *canvas, + BL_SceneConverter& converter, + bool alwaysUseExpandFraming, + float camZoom, + bool libloading) { #define BL_CONVERTBLENDEROBJECT_SINGLE \ @@ -1900,7 +1308,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie, blenderobject, \ vec_parent_child, \ logicbrick_conversionlist, \ - objectlist, inactivelist, sumolist, \ + objectlist, inactivelist, \ kxscene, gameobj, \ logicmgr, timemgr, \ isInActiveLayer \ @@ -1909,40 +1317,67 @@ void BL_ConvertBlenderObjects(struct Main* maggie, Scene *blenderscene = kxscene->GetBlenderScene(); - // for SETLOOPER - Scene *sce_iter; - Base *base; - - // Get the frame settings of the canvas. - // Get the aspect ratio of the canvas as designed by the user. - - RAS_FrameSettings::RAS_FrameType frame_type; - int aspect_width; - int aspect_height; - set grouplist; // list of groups to be converted - set allblobj; // all objects converted - set groupobj; // objects from groups (never in active layer) - // This is bad, but we use this to make sure the first time this is called - // is not in a separate thread. - BL_Texture::GetMaxUnits(); + // List of groups to be converted + std::set grouplist; + // All objects converted. + std::set allblobj; + // Objects from groups (never in active layer). + std::set groupobj; /* We have to ensure that group definitions are only converted once * push all converted group members to this set. * This will happen when a group instance is made from a linked group instance * and both are on the active layer. */ - set convertedlist; + EXP_ListValue *convertedlist = new EXP_ListValue(); + + // Find out which physics engine + PHY_IPhysicsEnvironment *phyEnv = nullptr; + e_PhysicsEngine physicsEngine = UseBullet; + + switch (blenderscene->gm.physicsEngine) { +#ifdef WITH_BULLET + case WOPHY_BULLET: + { + SYS_SystemHandle syshandle = SYS_GetSystem(); + int visualizePhysics = SYS_GetCommandLineInt(syshandle, "show_physics", 0); + + phyEnv = CcdPhysicsEnvironment::Create(blenderscene, visualizePhysics); + physicsEngine = UseBullet; + break; + } +#endif + case WOPHY_NONE: + default: + { + // We should probably use some sort of factory here + phyEnv = new DummyPhysicsEnvironment(); + physicsEngine = UseNone; + break; + } + } + kxscene->SetPhysicsEnvironment(phyEnv); + + + // Get the frame settings of the canvas. + // Get the aspect ratio of the canvas as designed by the user. + RAS_FrameSettings::RAS_FrameType frame_type; + int aspect_width; + int aspect_height; if (alwaysUseExpandFraming) { frame_type = RAS_FrameSettings::e_frame_extend; aspect_width = canvas->GetWidth(); aspect_height = canvas->GetHeight(); - } else { + } + else { if (blenderscene->gm.framing.type == SCE_GAMEFRAMING_BARS) { frame_type = RAS_FrameSettings::e_frame_bars; - } else if (blenderscene->gm.framing.type == SCE_GAMEFRAMING_EXTEND) { + } + else if (blenderscene->gm.framing.type == SCE_GAMEFRAMING_EXTEND) { frame_type = RAS_FrameSettings::e_frame_extend; - } else { + } + else { frame_type = RAS_FrameSettings::e_frame_scale; } @@ -1956,69 +1391,76 @@ void BL_ConvertBlenderObjects(struct Main* maggie, blenderscene->gm.framing.col[1], blenderscene->gm.framing.col[2], aspect_width, - aspect_height - ); + aspect_height); kxscene->SetFramingType(frame_settings); - kxscene->SetGravity(MT_Vector3(0,0, -blenderscene->gm.gravity)); + kxscene->SetGravity(mt::vec3(0.0f, 0.0f, -blenderscene->gm.gravity)); - /* set activity culling parameters */ - kxscene->SetActivityCulling( (blenderscene->gm.mode & WO_ACTIVITY_CULLING) != 0); - kxscene->SetActivityCullingRadius(blenderscene->gm.activityBoxRadius); + // Set activity culling parameters. + kxscene->SetActivityCulling((blenderscene->gm.mode & WO_ACTIVITY_CULLING) != 0); kxscene->SetDbvtCulling((blenderscene->gm.mode & WO_DBVT_CULLING) != 0); - // no occlusion culling by default + // No occlusion culling by default. kxscene->SetDbvtOcclusionRes(0); - int activeLayerBitInfo = blenderscene->lay; - - // list of all object converted, active and inactive - CListValue* sumolist = new CListValue(); + if (blenderscene->gm.lodflag & SCE_LOD_USE_HYST) { + kxscene->SetLodHysteresis(true); + kxscene->SetLodHysteresisValue(blenderscene->gm.scehysteresis); + } - vector vec_parent_child; + // Convert world. + KX_WorldInfo *worldinfo = new KX_WorldInfo(blenderscene, blenderscene->world); + worldinfo->UpdateWorldSettings(rendertools); + worldinfo->UpdateBackGround(rendertools); + kxscene->SetWorldInfo(worldinfo); - CListValue* objectlist = kxscene->GetObjectList(); - CListValue* inactivelist = kxscene->GetInactiveList(); - CListValue* parentlist = kxscene->GetRootParentList(); + const bool showObstacleSimulation = (blenderscene->gm.flag & GAME_SHOW_OBSTACLE_SIMULATION) != 0; + KX_ObstacleSimulation *obstacleSimulation = nullptr; + switch (blenderscene->gm.obstacleSimulation) { + case OBSTSIMULATION_TOI_rays: + { + obstacleSimulation = new KX_ObstacleSimulationTOI_rays(blenderscene->gm.levelHeight, showObstacleSimulation); + break; + } + case OBSTSIMULATION_TOI_cells: + { + obstacleSimulation = new KX_ObstacleSimulationTOI_cells(blenderscene->gm.levelHeight, showObstacleSimulation); + break; + } + } + kxscene->SetObstacleSimulation(obstacleSimulation); - SCA_LogicManager* logicmgr = kxscene->GetLogicManager(); - SCA_TimeEventManager* timemgr = kxscene->GetTimeEventManager(); + int activeLayerBitInfo = blenderscene->lay; - CListValue* logicbrick_conversionlist = new CListValue(); + std::vector vec_parent_child; - //SG_TreeFactory tf; + EXP_ListValue *objectlist = kxscene->GetObjectList(); + EXP_ListValue *inactivelist = kxscene->GetInactiveList(); + EXP_ListValue *parentlist = kxscene->GetRootParentList(); - // Convert actions to actionmap - bAction *curAct; - for (curAct = (bAction*)maggie->action.first; curAct; curAct=(bAction*)curAct->id.next) - { - logicmgr->RegisterActionName(curAct->id.name + 2, curAct); - } + SCA_LogicManager *logicmgr = kxscene->GetLogicManager(); + SCA_TimeEventManager *timemgr = kxscene->GetTimeEventManager(); - SetDefaultLightMode(blenderscene); + EXP_ListValue *logicbrick_conversionlist = new EXP_ListValue(); - blenderSceneSetBackground(blenderscene); + BL_SetBlenderSceneBackground(blenderscene); - // Let's support scene set. - // Beware of name conflict in linked data, it will not crash but will create confusion - // in Python scripting and in certain actuators (replace mesh). Linked scene *should* have - // no conflicting name for Object, Object data and Action. - for (SETLOOPER(blenderscene, sce_iter, base)) - { - Object* blenderobject = base->object; + /* Let's support scene set. + * Beware of name conflict in linked data, it will not crash but will create confusion + * in Python scripting and in certain actuators (replace mesh). Linked scene *should* have + * no conflicting name for Object, Object data and Action. + */ + Scene *sce_iter; + Base *base; + for (SETLOOPER(blenderscene, sce_iter, base)) { + Object *blenderobject = base->object; allblobj.insert(blenderobject); - KX_GameObject* gameobj = gameobject_from_blenderobject( - base->object, - kxscene, - rendertools, - converter, - libloading); + KX_GameObject *gameobj = BL_GameObjectFromBlenderObject(base->object, kxscene, rendertools, canvas, converter, camZoom); - bool isInActiveLayer = (blenderobject->lay & activeLayerBitInfo) !=0; - if (gameobj) - { - /* macro calls object conversion funcs */ + bool isInActiveLayer = (blenderobject->lay & activeLayerBitInfo) != 0; + if (gameobj) { + // Macro calls object conversion funcs. BL_CONVERTBLENDEROBJECT_SINGLE; if (gameobj->IsDupliGroup()) { @@ -2026,66 +1468,49 @@ void BL_ConvertBlenderObjects(struct Main* maggie, } /* Note about memory leak issues: - * When a CValue derived class is created, m_refcount is initialized to 1 + * When a EXP_Value derived class is created, m_refcount is initialized to 1 * so the class must be released after being used to make sure that it won't * hang in memory. If the object needs to be stored for a long time, * use AddRef() so that this Release() does not free the object. * Make sure that for any AddRef() there is a Release()!!!! - * Do the same for any object derived from CValue, CExpression and NG_NetworkMessage + * Do the same for any object derived from EXP_Value, EXP_Expression and NG_NetworkMessage */ gameobj->Release(); } } - if (!grouplist.empty()) - { - // now convert the group referenced by dupli group object - // keep track of all groups already converted - set allgrouplist = grouplist; - set tempglist; - // recurse - while (!grouplist.empty()) - { - set::iterator git; + if (!grouplist.empty()) { + /* Now convert the group referenced by dupli group object + * keep track of all groups already converted. */ + std::set allgrouplist = grouplist; + std::set tempglist; + while (!grouplist.empty()) { tempglist.clear(); tempglist.swap(grouplist); - for (git=tempglist.begin(); git!=tempglist.end(); git++) - { - Group* group = *git; - GroupObject* go; - for (go=(GroupObject*)group->gobject.first; go; go=(GroupObject*)go->next) - { - Object* blenderobject = go->ob; - if (converter->FindGameObject(blenderobject) == NULL) - { + for (Group *group : tempglist) { + for (GroupObject *go = (GroupObject *)group->gobject.first; go; go = (GroupObject *)go->next) { + Object *blenderobject = go->ob; + if (!converter.FindGameObject(blenderobject)) { allblobj.insert(blenderobject); groupobj.insert(blenderobject); - KX_GameObject* gameobj = gameobject_from_blenderobject( - blenderobject, - kxscene, - rendertools, - converter, - libloading); + KX_GameObject *gameobj = BL_GameObjectFromBlenderObject(blenderobject, kxscene, rendertools, canvas, converter, camZoom); bool isInActiveLayer = false; if (gameobj) { /* Insert object to the constraint game object list * so we can check later if there is a instance in the scene or * an instance and its actual group definition. */ - convertedlist.insert((KX_GameObject*)gameobj->AddRef()); + convertedlist->Add(CM_AddRef(gameobj)); - /* macro calls object conversion funcs */ + // Macro calls object conversion funcs. BL_CONVERTBLENDEROBJECT_SINGLE; - if (gameobj->IsDupliGroup()) - { - if (allgrouplist.insert(blenderobject->dup_group).second) - { + if (gameobj->IsDupliGroup()) { + if (allgrouplist.insert(blenderobject->dup_group).second) { grouplist.insert(blenderobject->dup_group); } } - /* see comment above re: mem leaks */ gameobj->Release(); } } @@ -2094,373 +1519,397 @@ void BL_ConvertBlenderObjects(struct Main* maggie, } } - // non-camera objects not supported as camera currently + // Non-camera objects not supported as camera currently. if (blenderscene->camera && blenderscene->camera->type == OB_CAMERA) { - KX_Camera *gamecamera= (KX_Camera*) converter->FindGameObject(blenderscene->camera); - - if (gamecamera) + KX_Camera *gamecamera = static_cast(converter.FindGameObject(blenderscene->camera)); + if (gamecamera) { kxscene->SetActiveCamera(gamecamera); - } - - // Set up armatures - set::iterator oit; - for (oit=allblobj.begin(); oit!=allblobj.end(); oit++) - { - Object* blenderobj = *oit; - if (blenderobj->type==OB_MESH) { - Mesh *me = (Mesh*)blenderobj->data; - - if (me->dvert) { - BL_DeformableGameObject *obj = (BL_DeformableGameObject*)converter->FindGameObject(blenderobj); - - if (obj && BL_ModifierDeformer::HasArmatureDeformer(blenderobj) && blenderobj->parent && blenderobj->parent->type==OB_ARMATURE) { - KX_GameObject *par = converter->FindGameObject(blenderobj->parent); - if (par && obj->GetDeformer()) - ((BL_SkinDeformer*)obj->GetDeformer())->SetArmature((BL_ArmatureObject*) par); - } - } } } - // create hierarchy information - int i; - vector::iterator pcit; + // Create hierarchy information. + for (const BL_ParentChildLink& link : vec_parent_child) { - for (pcit = vec_parent_child.begin();!(pcit==vec_parent_child.end());++pcit) - { - - struct Object* blenderchild = pcit->m_blenderchild; - struct Object* blenderparent = blenderchild->parent; - KX_GameObject* parentobj = converter->FindGameObject(blenderparent); - KX_GameObject* childobj = converter->FindGameObject(blenderchild); + Object *blenderchild = link.m_blenderchild; + Object *blenderparent = blenderchild->parent; + KX_GameObject *parentobj = converter.FindGameObject(blenderparent); + KX_GameObject *childobj = converter.FindGameObject(blenderchild); - assert(childobj); + BLI_assert(childobj); - if (!parentobj || objectlist->SearchValue(childobj) != objectlist->SearchValue(parentobj)) - { - // special case: the parent and child object are not in the same layer. - // This weird situation is used in Apricot for test purposes. - // Resolve it by not converting the child - childobj->GetSGNode()->DisconnectFromParent(); - delete pcit->m_gamechildnode; - // Now destroy the child object but also all its descendent that may already be linked - // Remove the child reference in the local list! - // Note: there may be descendents already if the children of the child were processed - // by this loop before the child. In that case, we must remove the children also - CListValue* childrenlist = childobj->GetChildrenRecursive(); - childrenlist->Add(childobj->AddRef()); - for ( i=0;iGetCount();i++) - { - KX_GameObject* obj = static_cast(childrenlist->GetValue(i)); - if (sumolist->RemoveValue(obj)) + if (!parentobj || objectlist->SearchValue(childobj) != objectlist->SearchValue(parentobj)) { + /* Special case: the parent and child object are not in the same layer. + * This weird situation is used in Apricot for test purposes. + * Resolve it by not converting the child + */ + childobj->GetNode()->DisconnectFromParent(); + delete link.m_gamechildnode; + /* Now destroy the child object but also all its descendent that may already be linked + * Remove the child reference in the local list! + * Note: there may be descendents already if the children of the child were processed + * by this loop before the child. In that case, we must remove the children also + */ + std::vector childrenlist = childobj->GetChildrenRecursive(); + // The returned list by GetChildrenRecursive is not owned by anyone and must not own items, so no AddRef(). + childrenlist.push_back(childobj); + for (KX_GameObject *obj : childrenlist) { + if (logicbrick_conversionlist->RemoveValue(obj)) { obj->Release(); - if (logicbrick_conversionlist->RemoveValue(obj)) + } + if (convertedlist->RemoveValue(obj)) { obj->Release(); + } } - childrenlist->Release(); - // now destroy recursively - converter->UnregisterGameObject(childobj); // removing objects during conversion make sure this runs too + converter.UnregisterGameObject(childobj); kxscene->RemoveObject(childobj); continue; } - switch (blenderchild->partype) - { + switch (blenderchild->partype) { case PARVERT1: { - // creat a new vertex parent relationship for this node. - KX_VertexParentRelation * vertex_parent_relation = KX_VertexParentRelation::New(); - pcit->m_gamechildnode->SetParentRelation(vertex_parent_relation); + // Create a new vertex parent relationship for this node. + KX_VertexParentRelation *vertex_parent_relation = new KX_VertexParentRelation(); + link.m_gamechildnode->SetParentRelation(vertex_parent_relation); break; } case PARSLOW: { - // creat a new slow parent relationship for this node. - KX_SlowParentRelation * slow_parent_relation = KX_SlowParentRelation::New(blenderchild->sf); - pcit->m_gamechildnode->SetParentRelation(slow_parent_relation); + // Create a new slow parent relationship for this node. + KX_SlowParentRelation *slow_parent_relation = new KX_SlowParentRelation(blenderchild->sf); + link.m_gamechildnode->SetParentRelation(slow_parent_relation); break; } case PARBONE: { - // parent this to a bone + // Parent this to a bone. Bone *parent_bone = BKE_armature_find_bone_name(BKE_armature_from_object(blenderchild->parent), blenderchild->parsubstr); if (parent_bone) { - KX_BoneParentRelation *bone_parent_relation = KX_BoneParentRelation::New(parent_bone); - pcit->m_gamechildnode->SetParentRelation(bone_parent_relation); + KX_BoneParentRelation *bone_parent_relation = new KX_BoneParentRelation(parent_bone); + link.m_gamechildnode->SetParentRelation(bone_parent_relation); } break; } - case PARSKEL: // skinned - ignore - break; - case PAROBJECT: - case PARVERT3: default: - // unhandled + { + // Unhandled. break; + } } - parentobj-> GetSGNode()->AddChild(pcit->m_gamechildnode); + parentobj->GetNode()->AddChild(link.m_gamechildnode); } vec_parent_child.clear(); - // find 'root' parents (object that has not parents in SceneGraph) - for (i=0;iGetCount();++i) - { - KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i); - if (gameobj->GetSGNode()->GetSGParent() == 0) - { - parentlist->Add(gameobj->AddRef()); - gameobj->NodeUpdateGS(0); + const std::vector& sumolist = converter.GetObjects(); + + // Find 'root' parents (object that has not parents in SceneGraph). + for (KX_GameObject *gameobj : sumolist) { + if (!gameobj->GetNode()->GetParent()) { + parentlist->Add(CM_AddRef(gameobj)); + gameobj->NodeUpdate(); } } - // create graphic controller for culling - if (kxscene->GetDbvtCulling()) - { + for (KX_GameObject *gameobj : objectlist) { + // Init mesh users, mesh slots and deformers. + gameobj->AddMeshUser(); + + // Add active armature for update. + if (gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) { + kxscene->AddAnimatedObject(gameobj); + } + } + + // Create graphic controller for culling. + if (kxscene->GetDbvtCulling()) { bool occlusion = false; - for (i=0; iGetCount();i++) - { - KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i); - if (gameobj->GetMeshCount() > 0) - { - MT_Point3 box[2]; - gameobj->GetSGNode()->BBox().getmm(box, MT_Transform::Identity()); - // box[0] is the min, box[1] is the max - bool isactive = objectlist->SearchValue(gameobj); - BL_CreateGraphicObjectNew(gameobj,box[0],box[1],kxscene,isactive,physics_engine); - if (gameobj->GetOccluder()) - occlusion = true; + for (KX_GameObject *gameobj : sumolist) { + // The object can't be culled ? + if (gameobj->GetMeshList().empty() && gameobj->GetGameObjectType() != SCA_IObject::OBJ_TEXT) { + continue; + } + + if (physicsEngine == UseBullet) { + const bool isactive = objectlist->SearchValue(gameobj); + BL_CreateGraphicObjectNew(gameobj, kxscene, isactive, phyEnv); + } + if (gameobj->GetOccluder()) { + occlusion = true; } } - if (occlusion) + if (occlusion) { kxscene->SetDbvtOcclusionRes(blenderscene->gm.occlusionRes); + } } - if (blenderscene->world) + + if (blenderscene->world) { kxscene->GetPhysicsEnvironment()->SetNumTimeSubSteps(blenderscene->gm.physubstep); + } - // now that the scenegraph is complete, let's instantiate the deformers. - // We need that to create reusable derived mesh and physic shapes - for (i=0;iGetCount();++i) - { - KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i); - if (gameobj->GetDeformer()) + for (KX_GameObject *gameobj : sumolist) { + /* Now that the scenegraph is complete, let's instantiate the deformers. + * We need that to create reusable derived mesh and physic shapes. + */ + if (gameobj->GetDeformer()) { gameobj->GetDeformer()->UpdateBuckets(); - } + } - // Set up armature constraints and shapekey drivers - for (i=0;iGetCount();++i) - { - KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i); - if (gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) - { - BL_ArmatureObject *armobj = (BL_ArmatureObject*)gameobj; + // Set up armature constraints and shapekey drivers. + if (gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) { + BL_ArmatureObject *armobj = static_cast(gameobj); armobj->LoadConstraints(converter); - CListValue *children = armobj->GetChildren(); - for (int j=0; jGetCount();++j) - { - BL_ShapeDeformer *deform = dynamic_cast(((KX_GameObject*)children->GetValue(j))->GetDeformer()); - if (deform) - deform->LoadShapeDrivers(armobj); + const std::vector children = armobj->GetChildren(); + for (KX_GameObject *child : children) { + BL_ShapeDeformer *deformer = dynamic_cast(child->GetDeformer()); + if (deformer) { + deformer->LoadShapeDrivers(armobj); + } } - - children->Release(); } } - bool processCompoundChildren = false; - // create physics information - for (i=0;iGetCount();i++) - { - KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i); - struct Object* blenderobject = gameobj->GetBlenderObject(); - int nummeshes = gameobj->GetMeshCount(); - RAS_MeshObject* meshobj = 0; - if (nummeshes > 0) - { - meshobj = gameobj->GetMesh(0); + // Create physics information. + for (unsigned short i = 0; i < 2; ++i) { + const bool processCompoundChildren = (i == 1); + for (KX_GameObject *gameobj : sumolist) { + Object *blenderobject = gameobj->GetBlenderObject(); + + const std::vector& meshes = gameobj->GetMeshList(); + KX_Mesh *meshobj = (meshes.empty()) ? nullptr : meshes.front(); + + int layerMask = (groupobj.find(blenderobject) == groupobj.end()) ? activeLayerBitInfo : 0; + BL_CreatePhysicsObjectNew(gameobj, blenderobject, meshobj, kxscene, layerMask, converter, processCompoundChildren); } - int layerMask = (groupobj.find(blenderobject) == groupobj.end()) ? activeLayerBitInfo : 0; - BL_CreatePhysicsObjectNew(gameobj,blenderobject,meshobj,kxscene,layerMask,converter,processCompoundChildren); } - processCompoundChildren = true; - // create physics information - for (i=0;iGetCount();i++) - { - KX_GameObject* gameobj = (KX_GameObject*) sumolist->GetValue(i); - struct Object* blenderobject = gameobj->GetBlenderObject(); - int nummeshes = gameobj->GetMeshCount(); - RAS_MeshObject* meshobj = 0; - if (nummeshes > 0) - { - meshobj = gameobj->GetMesh(0); + // Create and set bounding volume. + for (KX_GameObject *gameobj : sumolist) { + Object *blenderobject = gameobj->GetBlenderObject(); + Mesh *predifinedBoundMesh = blenderobject->gamePredefinedBound; + + if (predifinedBoundMesh) { + KX_Mesh *meshobj = converter.FindGameMesh(predifinedBoundMesh); + // In case of mesh taken in a other scene. + if (!meshobj) { + continue; + } + + gameobj->SetAutoUpdateBounds(false); + + // AABB Box : min/max. + mt::vec3 aabbMin; + mt::vec3 aabbMax; + // Get the mesh bounding box for none deformer. + RAS_BoundingBox *boundingBox = meshobj->GetBoundingBox(); + // Get the AABB. + boundingBox->GetAabb(aabbMin, aabbMax); + gameobj->SetBoundsAabb(aabbMin, aabbMax); + } + else { + // The object allow AABB auto update only if there's no predefined bound. + gameobj->SetAutoUpdateBounds(true); + + gameobj->UpdateBounds(true); } - int layerMask = (groupobj.find(blenderobject) == groupobj.end()) ? activeLayerBitInfo : 0; - BL_CreatePhysicsObjectNew(gameobj,blenderobject,meshobj,kxscene,layerMask,converter,processCompoundChildren); } - // create physics joints - for (i=0;iGetCount();i++) - { + // Create physics joints. + for (KX_GameObject *gameobj : sumolist) { PHY_IPhysicsEnvironment *physEnv = kxscene->GetPhysicsEnvironment(); - KX_GameObject *gameobj = (KX_GameObject *)sumolist->GetValue(i); - struct Object *blenderobject = gameobj->GetBlenderObject(); - ListBase *conlist = get_active_constraints2(blenderobject); - bConstraint *curcon; + Object *blenderobject = gameobj->GetBlenderObject(); + ListBase *conlist = BL_GetActiveConstraint(blenderobject); - if (!conlist) + if (!conlist) { continue; + } - for (curcon = (bConstraint *)conlist->first; curcon; curcon = (bConstraint *)curcon->next) { - if (curcon->type != CONSTRAINT_TYPE_RIGIDBODYJOINT) + BL_ConvertObjectInfo *info = gameobj->GetConvertObjectInfo(); + + for (bConstraint *curcon = (bConstraint *)conlist->first; curcon; curcon = (bConstraint *)curcon->next) { + if (curcon->type != CONSTRAINT_TYPE_RIGIDBODYJOINT) { continue; + } bRigidBodyJointConstraint *dat = (bRigidBodyJointConstraint *)curcon->data; - /* Skip if no target or a child object is selected or constraints are deactivated */ - if (!dat->tar || dat->child || (curcon->flag & CONSTRAINT_OFF)) + // Skip if no target or a child object is selected or constraints are deactivated. + if (!dat->tar || dat->child || (curcon->flag & CONSTRAINT_OFF)) { continue; + } - /* Store constraints of grouped and instanced objects for all layers */ - gameobj->AddConstraint(dat); + // Store constraints of grouped and instanced objects for all layers. + info->m_constraints.push_back(dat); /** if it's during libload we only add constraints in the object but * doesn't create it. Constraint will be replicated later in scene->MergeScene */ - if (libloading) + if (libloading) { continue; + } /* Skipped already converted constraints. * This will happen when a group instance is made from a linked group instance * and both are on the active layer. */ - if (bl_isConstraintInList(gameobj, convertedlist)) + if (convertedlist->FindValue(gameobj->GetName())) { continue; + } - KX_GameObject *gotar = getGameOb(dat->tar->id.name + 2, sumolist); - - if (gotar && (gotar->GetLayer()&activeLayerBitInfo) && gotar->GetPhysicsController() && - (gameobj->GetLayer()&activeLayerBitInfo) && gameobj->GetPhysicsController()) - { - physEnv->SetupObjectConstraints(gameobj, gotar, dat); + for (KX_GameObject *gotar : sumolist) { + if (gotar->GetName() == (dat->tar->id.name + 2) && + (gotar->GetLayer() & activeLayerBitInfo) && gotar->GetPhysicsController() && + (gameobj->GetLayer() & activeLayerBitInfo) && gameobj->GetPhysicsController()) + { + physEnv->SetupObjectConstraints(gameobj, gotar, dat); + break; + } } } } - /* cleanup converted set of group objects */ - set::iterator gobit; - for (gobit = convertedlist.begin(); gobit != convertedlist.end(); gobit++) - (*gobit)->Release(); - - convertedlist.clear(); - sumolist->Release(); - - // convert world - KX_WorldInfo* worldinfo = new KX_WorldInfo(blenderscene, blenderscene->world); - converter->RegisterWorldInfo(worldinfo); - kxscene->SetWorldInfo(worldinfo); - - //create object representations for obstacle simulation - KX_ObstacleSimulation* obssimulation = kxscene->GetObstacleSimulation(); - if (obssimulation) - { - for ( i=0;iGetCount();i++) - { - KX_GameObject* gameobj = static_cast(objectlist->GetValue(i)); - struct Object* blenderobject = gameobj->GetBlenderObject(); - if (blenderobject->gameflag & OB_HASOBSTACLE) - { + // Create object representations for obstacle simulation. + KX_ObstacleSimulation *obssimulation = kxscene->GetObstacleSimulation(); + if (obssimulation) { + for (KX_GameObject *gameobj : objectlist) { + Object *blenderobject = gameobj->GetBlenderObject(); + if (blenderobject->gameflag & OB_HASOBSTACLE) { obssimulation->AddObstacleForObj(gameobj); } } } - //process navigation mesh objects - for ( i=0; iGetCount();i++) - { - KX_GameObject* gameobj = static_cast(objectlist->GetValue(i)); - struct Object* blenderobject = gameobj->GetBlenderObject(); - if (blenderobject->type==OB_MESH && (blenderobject->gameflag & OB_NAVMESH)) - { - KX_NavMeshObject* navmesh = static_cast(gameobj); - navmesh->SetVisible(0, true); + // Process navigation mesh objects. + for (KX_GameObject *gameobj : objectlist) { + Object *blenderobject = gameobj->GetBlenderObject(); + if (blenderobject->type == OB_MESH && (blenderobject->gameflag & OB_NAVMESH)) { + KX_NavMeshObject *navmesh = static_cast(gameobj); + navmesh->SetVisible(false, true); navmesh->BuildNavMesh(); - if (obssimulation) - obssimulation->AddObstaclesForNavMesh(navmesh); } } - for ( i=0; iGetCount();i++) - { - KX_GameObject* gameobj = static_cast(inactivelist->GetValue(i)); - struct Object* blenderobject = gameobj->GetBlenderObject(); - if (blenderobject->type==OB_MESH && (blenderobject->gameflag & OB_NAVMESH)) - { - KX_NavMeshObject* navmesh = static_cast(gameobj); - navmesh->SetVisible(0, true); + for (KX_GameObject *gameobj : inactivelist) { + Object *blenderobject = gameobj->GetBlenderObject(); + if (blenderobject->type == OB_MESH && (blenderobject->gameflag & OB_NAVMESH)) { + KX_NavMeshObject *navmesh = static_cast(gameobj); + navmesh->SetVisible(false, true); } } - // convert logic bricks, sensors, controllers and actuators - for (i=0;iGetCount();i++) - { - KX_GameObject* gameobj = static_cast(logicbrick_conversionlist->GetValue(i)); - struct Object* blenderobj = gameobj->GetBlenderObject(); + // Convert logic bricks, sensors, controllers and actuators. + for (KX_GameObject *gameobj : logicbrick_conversionlist) { + Object *blenderobj = gameobj->GetBlenderObject(); int layerMask = (groupobj.find(blenderobj) == groupobj.end()) ? activeLayerBitInfo : 0; - bool isInActiveLayer = (blenderobj->lay & layerMask)!=0; - BL_ConvertActuators(maggie->name, blenderobj,gameobj,logicmgr,kxscene,ketsjiEngine,layerMask,isInActiveLayer,converter); + bool isInActiveLayer = (blenderobj->lay & layerMask) != 0; + BL_ConvertActuators(maggie->name, blenderobj, gameobj, logicmgr, kxscene, ketsjiEngine, layerMask, isInActiveLayer, converter); } - for ( i=0;iGetCount();i++) - { - KX_GameObject* gameobj = static_cast(logicbrick_conversionlist->GetValue(i)); - struct Object* blenderobj = gameobj->GetBlenderObject(); + + for (KX_GameObject *gameobj : logicbrick_conversionlist) { + Object *blenderobj = gameobj->GetBlenderObject(); int layerMask = (groupobj.find(blenderobj) == groupobj.end()) ? activeLayerBitInfo : 0; - bool isInActiveLayer = (blenderobj->lay & layerMask)!=0; - BL_ConvertControllers(blenderobj,gameobj,logicmgr, layerMask,isInActiveLayer,converter, libloading); + bool isInActiveLayer = (blenderobj->lay & layerMask) != 0; + BL_ConvertControllers(blenderobj, gameobj, logicmgr, layerMask, isInActiveLayer, converter, libloading); } - for ( i=0;iGetCount();i++) - { - KX_GameObject* gameobj = static_cast(logicbrick_conversionlist->GetValue(i)); - struct Object* blenderobj = gameobj->GetBlenderObject(); + + for (KX_GameObject *gameobj : logicbrick_conversionlist) { + Object *blenderobj = gameobj->GetBlenderObject(); int layerMask = (groupobj.find(blenderobj) == groupobj.end()) ? activeLayerBitInfo : 0; - bool isInActiveLayer = (blenderobj->lay & layerMask)!=0; - BL_ConvertSensors(blenderobj,gameobj,logicmgr,kxscene,ketsjiEngine,layerMask,isInActiveLayer,canvas,converter); - // set the init state to all objects - gameobj->SetInitState((blenderobj->init_state)?blenderobj->init_state:blenderobj->state); + bool isInActiveLayer = (blenderobj->lay & layerMask) != 0; + BL_ConvertSensors(blenderobj, gameobj, logicmgr, kxscene, ketsjiEngine, layerMask, isInActiveLayer, canvas, converter); + // Set the init state to all objects. + gameobj->SetInitState((blenderobj->init_state) ? blenderobj->init_state : blenderobj->state); } - // apply the initial state to controllers, only on the active objects as this registers the sensors - for ( i=0;iGetCount();i++) - { - KX_GameObject* gameobj = static_cast(objectlist->GetValue(i)); + + // Apply the initial state to controllers, only on the active objects as this registers the sensors. + for (KX_GameObject *gameobj : objectlist) { gameobj->ResetState(); } + // Cleanup converted set of group objects. + convertedlist->Release(); logicbrick_conversionlist->Release(); - // Calculate the scene btree - - // too slow - commented out. - //kxscene->SetNodeTree(tf.MakeTree()); - - // instantiate dupli group, we will loop trough the object - // that are in active layers. Note that duplicating group - // has the effect of adding objects at the end of objectlist. - // Only loop through the first part of the list. + /* Instantiate dupli group, we will loop trough the object + * that are in active layers. Note that duplicating group + * has the effect of adding objects at the end of objectlist. + * Only loop through the first part of the list. + */ int objcount = objectlist->GetCount(); - for (i=0;iGetValue(i); - if (gameobj->IsDupliGroup()) - { + for (unsigned int i = 0; i < objcount; ++i) { + KX_GameObject *gameobj = objectlist->GetValue(i); + if (gameobj->IsDupliGroup()) { kxscene->DupliGroupRecurse(gameobj, 0); } } +} + +void BL_PostConvertBlenderObjects(KX_Scene *kxscene, const BL_SceneConverter& sceneconverter) +{ + const std::vector& sumolist = sceneconverter.GetObjects(); + EXP_ListValue *objectlist = kxscene->GetObjectList(); + +#ifdef WITH_PYTHON + + // Convert the python components of each object if the component execution is available. + if (G.f & G_SCRIPT_AUTOEXEC) { + for (KX_GameObject *gameobj : sumolist) { + Object *blenderobj = gameobj->GetBlenderObject(); + BL_ConvertComponentsObject(gameobj, blenderobj); + } + + for (KX_GameObject *gameobj : objectlist) { + if (gameobj->GetComponents()) { + // Register object for component update. + kxscene->GetPythonComponentManager().RegisterObject(gameobj); + } + } + } + else { + CM_Warning("Python components auto-execution disabled"); + } - KX_Camera *activecam = kxscene->GetActiveCamera(); - MT_Scalar distance = (activecam)? activecam->GetCameraFar() - activecam->GetCameraNear(): 100.0f; - RAS_BucketManager *bucketmanager = kxscene->GetBucketManager(); - bucketmanager->OptimizeBuckets(distance); +#endif // WITH_PYTHON + + // Init textures for all materials. + for (KX_BlenderMaterial *mat : sceneconverter.GetMaterials()) { + mat->InitTextures(); + } + + // Look at every material texture and ask to create realtime map. + for (KX_GameObject *gameobj : sumolist) { + for (KX_Mesh *mesh : gameobj->GetMeshList()) { + for (RAS_MeshMaterial *meshmat : mesh->GetMeshMaterialList()) { + RAS_IMaterial *mat = meshmat->GetBucket()->GetMaterial(); + + for (unsigned short k = 0; k < RAS_Texture::MaxUnits; ++k) { + RAS_Texture *tex = mat->GetTexture(k); + if (!tex || !tex->Ok()) { + continue; + } + + EnvMap *env = tex->GetTex()->env; + if (!env || env->stype != ENV_REALT) { + continue; + } + + KX_GameObject *viewpoint = gameobj; + if (env->object) { + KX_GameObject *obj = sceneconverter.FindGameObject(env->object); + if (obj) { + viewpoint = obj; + } + } + + KX_TextureRendererManager::RendererType type = tex->IsCubeMap() ? KX_TextureRendererManager::CUBE : KX_TextureRendererManager::PLANAR; + kxscene->GetTextureRendererManager()->AddRenderer(type, tex, viewpoint); + } + } + } + } } + diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.h b/source/gameengine/Converter/BL_BlenderDataConversion.h index c120de85d741..1fbea3c3a1f7 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.h +++ b/source/gameengine/Converter/BL_BlenderDataConversion.h @@ -32,25 +32,48 @@ #ifndef __BL_BLENDERDATACONVERSION_H__ #define __BL_BLENDERDATACONVERSION_H__ -#include "CTR_HashedPtr.h" -#include "STR_String.h" -#include "EXP_Python.h" +#include "RAS_Mesh.h" #include "KX_PhysicsEngineEnums.h" #include "SCA_IInputDevice.h" -class RAS_MeshObject* BL_ConvertMesh(struct Mesh* mesh,struct Object* lightobj,class KX_Scene* scene, class KX_BlenderSceneConverter *converter, bool libloading); +class RAS_Rasterizer; +class RAS_ICanvas; +class KX_KetsjiEngine; +class KX_Scene; +class BL_SceneConverter; +class BL_ActionData; +struct Mesh; +struct DerivedMesh; +struct Object; +struct Main; +struct bAction; -void BL_ConvertBlenderObjects(struct Main* maggie, - class KX_Scene* kxscene, - class KX_KetsjiEngine* ketsjiEngine, - e_PhysicsEngine physics_engine, - class RAS_IRasterizer* rendertools, - class RAS_ICanvas* canvas, - class KX_BlenderSceneConverter* sceneconverter, - bool alwaysUseExpandFraming, - bool libloading=false - ); +struct BL_MeshMaterial { + RAS_DisplayArray *array; + RAS_MaterialBucket *bucket; + bool visible; + bool twoside; + bool collider; + bool wire; +}; -SCA_IInputDevice::KX_EnumInputs ConvertKeyCode(int key_code); +KX_Mesh *BL_ConvertMesh(Mesh *mesh, Object *lightobj, KX_Scene *scene, BL_SceneConverter& converter); +void BL_ConvertDerivedMeshToArray(DerivedMesh *dm, Mesh *me, const std::vector& mats, + const RAS_Mesh::LayersInfo& layersInfo); -#endif /* __BL_BLENDERDATACONVERSION_H__ */ +RAS_Deformer *BL_ConvertDeformer(KX_GameObject *object, KX_Mesh *meshobj); + +BL_ActionData *BL_ConvertAction(bAction *action, KX_Scene *scene, BL_SceneConverter& converter); +/// Convert all actions of a library and register them in a converter. +void BL_ConvertActions(KX_Scene *scene, Main *maggie, BL_SceneConverter& converter); + +void BL_ConvertBlenderObjects(Main *maggie, KX_Scene *kxscene, KX_KetsjiEngine *ketsjiEngine, + RAS_Rasterizer *rendertools, RAS_ICanvas *canvas, BL_SceneConverter& sceneconverter, + bool alwaysUseExpandFraming, float camZoom, bool libloading); +// Non-multithreadable conversion. +void BL_PostConvertBlenderObjects(KX_Scene *kxscene, const BL_SceneConverter& sceneconverter); + + +SCA_IInputDevice::SCA_EnumInputs BL_ConvertKeyCode(int key_code); + +#endif // __BL_BLENDERDATACONVERSION_H__ diff --git a/source/gameengine/Converter/BL_ConvertActuators.cpp b/source/gameengine/Converter/BL_ConvertActuators.cpp new file mode 100644 index 000000000000..175874e868db --- /dev/null +++ b/source/gameengine/Converter/BL_ConvertActuators.cpp @@ -0,0 +1,1272 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * Convert Blender actuators for use in the GameEngine + */ + +/** \file gameengine/Converter/BL_ConvertActuators.cpp + * \ingroup bgeconv + */ + +#ifdef _MSC_VER +# pragma warning (disable:4786) +#endif + +#include + +#include "MEM_guardedalloc.h" + +#include "BL_SceneConverter.h" +#include "BL_ConvertActuators.h" + +#ifdef WITH_AUDASPACE +# include AUD_SOUND_H +#endif + +// Actuators +//SCA logiclibrary native logicbricks +#include "SCA_PropertyActuator.h" +#include "SCA_LogicManager.h" +#include "SCA_RandomActuator.h" +#include "SCA_VibrationActuator.h" +#include "SCA_2DFilterActuator.h" + +#include "RAS_2DFilterManager.h" // for filter type. + +// Ketsji specific logicbricks +#include "KX_SceneActuator.h" +#include "KX_SoundActuator.h" +#include "KX_ObjectActuator.h" +#include "KX_TrackToActuator.h" +#include "KX_ConstraintActuator.h" +#include "KX_CameraActuator.h" +#include "KX_GameActuator.h" +#include "KX_StateActuator.h" +#include "KX_VisibilityActuator.h" +#include "KX_AddObjectActuator.h" +#include "KX_EndObjectActuator.h" +#include "KX_ReplaceMeshActuator.h" +#include "KX_ParentActuator.h" +#include "KX_DynamicActuator.h" +#include "KX_SteeringActuator.h" +#include "KX_MouseActuator.h" + +#include "KX_Scene.h" +#include "KX_2DFilterManager.h" +#include "KX_KetsjiEngine.h" + +#include "EXP_IntValue.h" +#include "KX_GameObject.h" + +#include "CM_Message.h" + +/* This little block needed for linking to Blender... */ +#include "BKE_text.h" +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_path_util.h" + +#include "KX_NetworkMessageActuator.h" + +#ifdef WIN32 +#include "BLI_winstuff.h" +#endif + +#include "DNA_object_types.h" +#include "DNA_sound_types.h" +#include "DNA_scene_types.h" +#include "DNA_actuator_types.h" +#include "DNA_packedFile_types.h" +#include "BL_ActionActuator.h" +#include "BL_ArmatureActuator.h" +#include "RNA_access.h" +#include "BL_Action.h" +/* end of blender include block */ + +#include "BL_BlenderDataConversion.h" + +/** + * KX_flt_trunc needed to round 'almost' zero values to zero, else velocities etc. are incorrectly set + */ + +BLI_INLINE float KX_flt_trunc(const float x) +{ + return (x < 0.0001f && x > -0.0001f) ? 0.0f : x; +} + +void BL_ConvertActuators(const char *maggiename, + struct Object *blenderobject, + KX_GameObject *gameobj, + SCA_LogicManager *logicmgr, + KX_Scene *scene, + KX_KetsjiEngine *ketsjiEngine, + int activeLayerBitInfo, + bool isInActiveLayer, + BL_SceneConverter& converter) +{ + + int uniqueint = 0; + int actcount = 0; + int executePriority = 0; + bActuator *bact = (bActuator *)blenderobject->actuators.first; + while (bact) + { + actcount++; + bact = bact->next; + } + bact = (bActuator *)blenderobject->actuators.first; + while (bact) + { + std::string uniquename = bact->name; + std::string objectname = gameobj->GetName(); + + SCA_IActuator *baseact = nullptr; + switch (bact->type) { + case ACT_OBJECT: + { + bObjectActuator *obact = (bObjectActuator *)bact->data; + KX_GameObject *obref = nullptr; + mt::vec3 forcevec(KX_flt_trunc(obact->forceloc[0]), + KX_flt_trunc(obact->forceloc[1]), + KX_flt_trunc(obact->forceloc[2])); + mt::vec3 torquevec(obact->forcerot[0], + obact->forcerot[1], + obact->forcerot[2]); + mt::vec3 dlocvec(KX_flt_trunc(obact->dloc[0]), + KX_flt_trunc(obact->dloc[1]), + KX_flt_trunc(obact->dloc[2])); + mt::vec3 drotvec(KX_flt_trunc(obact->drot[0]), + obact->drot[1], obact->drot[2]); + mt::vec3 linvelvec(KX_flt_trunc(obact->linearvelocity[0]), + KX_flt_trunc(obact->linearvelocity[1]), + KX_flt_trunc(obact->linearvelocity[2])); + mt::vec3 angvelvec(KX_flt_trunc(obact->angularvelocity[0]), + KX_flt_trunc(obact->angularvelocity[1]), + KX_flt_trunc(obact->angularvelocity[2])); + short damping = obact->damping; + + /* Blender uses a bit vector internally for the local-flags. In */ + /* KX, we have four bools. The compiler should be smart enough */ + /* to do the right thing. We need to explicitly convert here! */ + + KX_LocalFlags bitLocalFlag; + + bitLocalFlag.Force = bool((obact->flag & ACT_FORCE_LOCAL) != 0); + bitLocalFlag.Torque = bool((obact->flag & ACT_TORQUE_LOCAL) != 0);//rlocal; + bitLocalFlag.DLoc = bool((obact->flag & ACT_DLOC_LOCAL) != 0); + bitLocalFlag.DRot = bool((obact->flag & ACT_DROT_LOCAL) != 0); + bitLocalFlag.LinearVelocity = bool((obact->flag & ACT_LIN_VEL_LOCAL) != 0); + bitLocalFlag.AngularVelocity = bool((obact->flag & ACT_ANG_VEL_LOCAL) != 0); + bitLocalFlag.ServoControl = bool(obact->type == ACT_OBJECT_SERVO); + bitLocalFlag.CharacterMotion = bool(obact->type == ACT_OBJECT_CHARACTER); + bitLocalFlag.CharacterJump = bool((obact->flag & ACT_CHAR_JUMP) != 0); + bitLocalFlag.AddOrSetLinV = bool((obact->flag & ACT_ADD_LIN_VEL) != 0); + bitLocalFlag.AddOrSetCharLoc = bool((obact->flag & ACT_ADD_CHAR_LOC) != 0); + bitLocalFlag.ServoControlAngular = (obact->servotype == ACT_SERVO_ANGULAR); + if (obact->reference && bitLocalFlag.ServoControl) { + obref = converter.FindGameObject(obact->reference); + } + + KX_ObjectActuator *tmpbaseact = new KX_ObjectActuator( + gameobj, + obref, + forcevec, + torquevec, + dlocvec, + drotvec, + linvelvec, + angvelvec, + damping, + bitLocalFlag); + baseact = tmpbaseact; + break; + } + case ACT_ACTION: + { + bActionActuator *actact = (bActionActuator *)bact->data; + std::string propname = actact->name; + std::string propframe = actact->frameProp; + + short ipo_flags = 0; + + // Convert flags + if (actact->flag & ACT_IPOFORCE) { + ipo_flags |= BL_Action::ACT_IPOFLAG_FORCE; + } + if (actact->flag & ACT_IPOLOCAL) { + ipo_flags |= BL_Action::ACT_IPOFLAG_LOCAL; + } + if (actact->flag & ACT_IPOADD) { + ipo_flags |= BL_Action::ACT_IPOFLAG_ADD; + } + + const std::string actionName = (actact->act) ? actact->act->id.name + 2 : ""; + + BL_ActionActuator *tmpbaseact = new BL_ActionActuator( + gameobj, + propname, + propframe, + actact->sta, + actact->end, + actionName, + actact->type, // + 1, because Blender starts to count at zero, + actact->blend_mode, + actact->blendin, + actact->priority, + actact->layer, + actact->layer_weight, + ipo_flags, + actact->end_reset); + baseact = tmpbaseact; + break; + } + case ACT_LAMP: + { + break; + } + case ACT_CAMERA: + { + bCameraActuator *camact = (bCameraActuator *)bact->data; + if (camact->ob) { + KX_GameObject *tmpgob = converter.FindGameObject(camact->ob); + + /* visifac, fac and axis are not copied from the struct... */ + /* that's some internal state... */ + KX_CameraActuator *tmpcamact = new KX_CameraActuator( + gameobj, + tmpgob, + camact->height, + camact->min, + camact->max, + camact->axis, + camact->damping); + baseact = tmpcamact; + } + break; + } + case ACT_MESSAGE: + { + bMessageActuator *msgAct = (bMessageActuator *)bact->data; + + /* Get the name of the properties that objects must own that + * we're sending to, if present + */ + std::string toPropName = msgAct->toPropName; + + /* Get the Message Subject to send. + */ + std::string subject = msgAct->subject; + + /* Get the bodyType + */ + int bodyType = msgAct->bodyType; + + /* Get the body (text message or property name whose value + * we'll be sending, might be empty + */ + const std::string body = msgAct->body; + + KX_NetworkMessageActuator *tmpmsgact = new KX_NetworkMessageActuator( + gameobj, // actuator controlling object + scene->GetNetworkMessageScene(), // needed for replication + toPropName, + subject, + bodyType, + body); + baseact = tmpmsgact; + break; + } + case ACT_MATERIAL: + { + break; + } + case ACT_SOUND: + { + bSoundActuator *soundact = (bSoundActuator *)bact->data; + /* get type, and possibly a start and end frame */ + KX_SoundActuator::KX_SOUNDACT_TYPE + soundActuatorType = KX_SoundActuator::KX_SOUNDACT_NODEF; + + switch (soundact->type) { + case ACT_SND_PLAY_STOP_SOUND: + { + soundActuatorType = KX_SoundActuator::KX_SOUNDACT_PLAYSTOP; + break; + } + case ACT_SND_PLAY_END_SOUND: + { + soundActuatorType = KX_SoundActuator::KX_SOUNDACT_PLAYEND; + break; + } + case ACT_SND_LOOP_STOP_SOUND: + { + soundActuatorType = KX_SoundActuator::KX_SOUNDACT_LOOPSTOP; + break; + } + case ACT_SND_LOOP_END_SOUND: + { + soundActuatorType = KX_SoundActuator::KX_SOUNDACT_LOOPEND; + break; + } + case ACT_SND_LOOP_BIDIRECTIONAL_SOUND: + { + soundActuatorType = KX_SoundActuator::KX_SOUNDACT_LOOPBIDIRECTIONAL; + break; + } + case ACT_SND_LOOP_BIDIRECTIONAL_STOP_SOUND: + { + soundActuatorType = KX_SoundActuator::KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP; + break; + } + + default: + /* This is an error!!! */ + soundActuatorType = KX_SoundActuator::KX_SOUNDACT_NODEF; + } + + if (soundActuatorType != KX_SoundActuator::KX_SOUNDACT_NODEF) { + bSound *sound = soundact->sound; + bool is3d = soundact->flag & ACT_SND_3D_SOUND ? true : false; +#ifdef WITH_AUDASPACE + AUD_Sound *snd_sound = nullptr; +#endif // WITH_AUDASPACE + KX_3DSoundSettings settings; + settings.cone_inner_angle = RAD2DEGF(soundact->sound3D.cone_inner_angle); + settings.cone_outer_angle = RAD2DEGF(soundact->sound3D.cone_outer_angle); + settings.cone_outer_gain = soundact->sound3D.cone_outer_gain; + settings.max_distance = soundact->sound3D.max_distance; + settings.max_gain = soundact->sound3D.max_gain; + settings.min_gain = soundact->sound3D.min_gain; + settings.reference_distance = soundact->sound3D.reference_distance; + settings.rolloff_factor = soundact->sound3D.rolloff_factor; + + if (!sound) { + CM_Warning("sound actuator \"" << bact->name << "\" from object \"" << blenderobject->id.name + 2 + << "\" has no sound datablock."); + } + else { +#ifdef WITH_AUDASPACE + snd_sound = sound->playback_handle; + + // if sound shall be 3D but isn't mono, we have to make it mono! + if (is3d) { + snd_sound = AUD_Sound_rechannel(snd_sound, AUD_CHANNELS_MONO); + } +#endif // WITH_AUDASPACE + } + KX_SoundActuator *tmpsoundact = + new KX_SoundActuator(gameobj, +#ifdef WITH_AUDASPACE + snd_sound, +#endif // WITH_AUDASPACE + soundact->volume, + (float)(expf((soundact->pitch / 12.0f) * (float)M_LN2)), + is3d, + settings, + soundActuatorType); + +#ifdef WITH_AUDASPACE + // if we made it mono, we have to free it + if (sound && snd_sound && snd_sound != sound->playback_handle) { + AUD_Sound_free(snd_sound); + } +#endif // WITH_AUDASPACE + + tmpsoundact->SetName(bact->name); + baseact = tmpsoundact; + } + break; + } + case ACT_PROPERTY: + { + bPropertyActuator *propact = (bPropertyActuator *)bact->data; + SCA_IObject *destinationObj = nullptr; + + /* + * here the destinationobject is searched. problem with multiple scenes: other scenes + * have not been converted yet, so the destobj will not be found, so the prop will + * not be copied. + * possible solutions: + * - convert everything when possible and not realtime only when needed. + * - let the object-with-property report itself to the act when converted + */ + if (propact->ob) { + destinationObj = converter.FindGameObject(propact->ob); + } + + SCA_PropertyActuator *tmppropact = new SCA_PropertyActuator( + gameobj, + destinationObj, + propact->name, + propact->value, + propact->type + 1); // + 1 because Ketsji Logic starts + // with 0 for KX_ACT_PROP_NODEF + baseact = tmppropact; + break; + } + case ACT_EDIT_OBJECT: + { + bEditObjectActuator *editobact + = (bEditObjectActuator *)bact->data; + /* There are four different kinds of 'edit object' thingies */ + /* The alternative to this lengthy conversion is packing */ + /* several actuators in one, which is not very nice design.. */ + switch (editobact->type) { + case ACT_EDOB_ADD_OBJECT: + { + + // does the 'original' for replication exists, and + // is it in a non-active layer ? + KX_GameObject *originalval = nullptr; + if (editobact->ob) { + if (editobact->ob->lay & activeLayerBitInfo) { + CM_Warning("object \"" << objectname << "\" from AddObject actuator \"" << uniquename + << "\" is not in a hidden layer."); + } + else { + originalval = converter.FindGameObject(editobact->ob); + } + } + KX_AddObjectActuator *tmpaddact = new KX_AddObjectActuator( + gameobj, + originalval, + editobact->time, + scene, + mt::vec3(editobact->linVelocity), + (editobact->localflag & ACT_EDOB_LOCAL_LINV) != 0, + mt::vec3(editobact->angVelocity), + (editobact->localflag & ACT_EDOB_LOCAL_ANGV) != 0); + + //editobact->ob to gameobj + baseact = tmpaddact; + break; + } + case ACT_EDOB_END_OBJECT: + { + KX_EndObjectActuator *tmpendact + = new KX_EndObjectActuator(gameobj, scene); + baseact = tmpendact; + break; + } + case ACT_EDOB_REPLACE_MESH: + { + KX_Mesh *tmpmesh = converter.FindGameMesh(editobact->me); + + if (!tmpmesh) { + CM_Warning("object \"" << objectname << "\" from ReplaceMesh actuator \"" << uniquename + << "\" uses a mesh not owned by an object in scene \"" << scene->GetName() << "\"."); + } + + KX_ReplaceMeshActuator *tmpreplaceact = new KX_ReplaceMeshActuator( + gameobj, + tmpmesh, + (editobact->flag & ACT_EDOB_REPLACE_MESH_NOGFX) == 0, + (editobact->flag & ACT_EDOB_REPLACE_MESH_PHYS) != 0); + + baseact = tmpreplaceact; + break; + } + case ACT_EDOB_TRACK_TO: + { + SCA_IObject *originalval = nullptr; + if (editobact->ob) { + originalval = converter.FindGameObject(editobact->ob); + } + + KX_TrackToActuator *tmptrackact = new KX_TrackToActuator( + gameobj, + originalval, + editobact->time, + editobact->flag, + editobact->trackflag, + editobact->upflag); + baseact = tmptrackact; + break; + } + case ACT_EDOB_DYNAMICS: + { + KX_DynamicActuator *tmpdynact = new KX_DynamicActuator( + gameobj, + editobact->dyn_operation, + editobact->mass); + baseact = tmpdynact; + } + } + break; + } + case ACT_CONSTRAINT: + { + float min = 0.0, max = 0.0; + char *prop = nullptr; + KX_ConstraintActuator::KX_CONSTRAINTTYPE locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_NODEF; + bConstraintActuator *conact + = (bConstraintActuator *)bact->data; + /* convert settings... degrees in the ui become radians */ + /* internally */ + if (conact->type == ACT_CONST_TYPE_ORI) { + min = conact->minloc[0]; + max = conact->maxloc[0]; + switch (conact->mode) { + case ACT_CONST_DIRPX: + { + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ORIX; + break; + } + case ACT_CONST_DIRPY: + { + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ORIY; + break; + } + case ACT_CONST_DIRPZ: + { + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ORIZ; + break; + } + } + } + else if (conact->type == ACT_CONST_TYPE_DIST) { + switch (conact->mode) { + case ACT_CONST_DIRPX: + { + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRPX; + min = conact->minloc[0]; + max = conact->maxloc[0]; + break; + } + case ACT_CONST_DIRPY: + { + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRPY; + min = conact->minloc[1]; + max = conact->maxloc[1]; + break; + } + case ACT_CONST_DIRPZ: + { + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRPZ; + min = conact->minloc[2]; + max = conact->maxloc[2]; + break; + } + case ACT_CONST_DIRNX: + { + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRNX; + min = conact->minloc[0]; + max = conact->maxloc[0]; + break; + } + case ACT_CONST_DIRNY: + { + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRNY; + min = conact->minloc[1]; + max = conact->maxloc[1]; + break; + } + case ACT_CONST_DIRNZ: + { + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRNZ; + min = conact->minloc[2]; + max = conact->maxloc[2]; + break; + } + } + prop = conact->matprop; + } + else if (conact->type == ACT_CONST_TYPE_FH) { + switch (conact->mode) { + case ACT_CONST_DIRPX: + { + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHPX; + min = conact->minloc[0]; + max = conact->maxloc[0]; + break; + } + case ACT_CONST_DIRPY: + { + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHPY; + min = conact->minloc[1]; + max = conact->maxloc[1]; + break; + } + case ACT_CONST_DIRPZ: + { + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHPZ; + min = conact->minloc[2]; + max = conact->maxloc[2]; + break; + } + case ACT_CONST_DIRNX: + { + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHNX; + min = conact->minloc[0]; + max = conact->maxloc[0]; + break; + } + case ACT_CONST_DIRNY: + { + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHNY; + min = conact->minloc[1]; + max = conact->maxloc[1]; + break; + } + case ACT_CONST_DIRNZ: + { + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHNZ; + min = conact->minloc[2]; + max = conact->maxloc[2]; + break; + } + } + prop = conact->matprop; + } + else { + switch (conact->flag) { + case ACT_CONST_LOCX: + { + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCX; + min = conact->minloc[0]; + max = conact->maxloc[0]; + break; + } + case ACT_CONST_LOCY: + { + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCY; + min = conact->minloc[1]; + max = conact->maxloc[1]; + break; + } + case ACT_CONST_LOCZ: + { + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCZ; + min = conact->minloc[2]; + max = conact->maxloc[2]; + break; + } + case ACT_CONST_ROTX: + { + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTX; + min = DEG2RADF(conact->minrot[0]); + max = DEG2RADF(conact->maxrot[0]); + break; + } + case ACT_CONST_ROTY: + { + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTY; + min = DEG2RADF(conact->minrot[1]); + max = DEG2RADF(conact->maxrot[1]); + break; + } + case ACT_CONST_ROTZ: + { + locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTZ; + min = DEG2RADF(conact->minrot[2]); + max = DEG2RADF(conact->maxrot[2]); + break; + } + default: + ; /* error */ + } + } + KX_ConstraintActuator *tmpconact = new KX_ConstraintActuator( + gameobj, + conact->damp, + conact->rotdamp, + min, + max, + mt::vec3(conact->maxrot), + locrot, + conact->time, + conact->flag, + prop); + baseact = tmpconact; + break; + } + case ACT_GROUP: + { + // deprecated + break; + } + case ACT_SCENE: + { + bSceneActuator *sceneact = (bSceneActuator *)bact->data; + std::string nextSceneName(""); + + KX_SceneActuator *tmpsceneact; + int mode = KX_SceneActuator::KX_SCENE_NODEF; + KX_Camera *cam = nullptr; + //KX_Scene* scene = nullptr; + switch (sceneact->type) { + case ACT_SCENE_RESUME: + case ACT_SCENE_SUSPEND: + case ACT_SCENE_ADD_FRONT: + case ACT_SCENE_ADD_BACK: + case ACT_SCENE_REMOVE: + case ACT_SCENE_SET: + { + switch (sceneact->type) { + case ACT_SCENE_RESUME: + { + mode = KX_SceneActuator::KX_SCENE_RESUME; + break; + } + case ACT_SCENE_SUSPEND: + { + mode = KX_SceneActuator::KX_SCENE_SUSPEND; + break; + } + case ACT_SCENE_ADD_FRONT: + { + mode = KX_SceneActuator::KX_SCENE_ADD_FRONT_SCENE; + break; + } + case ACT_SCENE_ADD_BACK: + { + mode = KX_SceneActuator::KX_SCENE_ADD_BACK_SCENE; + break; + } + case ACT_SCENE_REMOVE: + { + mode = KX_SceneActuator::KX_SCENE_REMOVE_SCENE; + break; + } + case ACT_SCENE_SET: + default: + { + mode = KX_SceneActuator::KX_SCENE_SET_SCENE; + break; + } + } + ; + + if (sceneact->scene) { + nextSceneName = sceneact->scene->id.name + 2; + } + + break; + } + case ACT_SCENE_CAMERA: + { + mode = KX_SceneActuator::KX_SCENE_SET_CAMERA; + if (sceneact->camera) { + KX_GameObject *tmp = converter.FindGameObject(sceneact->camera); + if (tmp && tmp->GetGameObjectType() == SCA_IObject::OBJ_CAMERA) { + cam = (KX_Camera *)tmp; + } + } + break; + } + case ACT_SCENE_RESTART: + { + + mode = KX_SceneActuator::KX_SCENE_RESTART; + break; + } + default: + ; /* flag error */ + } + tmpsceneact = new KX_SceneActuator( + gameobj, + mode, + scene, + ketsjiEngine, + nextSceneName, + cam); + baseact = tmpsceneact; + break; + } + case ACT_GAME: + { + bGameActuator *gameact = (bGameActuator *)bact->data; + KX_GameActuator *tmpgameact; + std::string filename = maggiename; + std::string loadinganimationname = ""; + int mode = KX_GameActuator::KX_GAME_NODEF; + switch (gameact->type) { + case ACT_GAME_LOAD: + { + mode = KX_GameActuator::KX_GAME_LOAD; + filename = gameact->filename; + loadinganimationname = gameact->loadaniname; + break; + } + case ACT_GAME_START: + { + mode = KX_GameActuator::KX_GAME_START; + filename = gameact->filename; + loadinganimationname = gameact->loadaniname; + break; + } + case ACT_GAME_RESTART: + { + mode = KX_GameActuator::KX_GAME_RESTART; + break; + } + case ACT_GAME_QUIT: + { + mode = KX_GameActuator::KX_GAME_QUIT; + break; + } + case ACT_GAME_SAVECFG: + { + mode = KX_GameActuator::KX_GAME_SAVECFG; + break; + } + case ACT_GAME_LOADCFG: + { + mode = KX_GameActuator::KX_GAME_LOADCFG; + break; + } + case ACT_GAME_SCREENSHOT: + { + mode = KX_GameActuator::KX_GAME_SCREENSHOT; + filename = gameact->filename; + break; + } + default: + ; /* flag error */ + } + tmpgameact = new KX_GameActuator( + gameobj, + mode, + filename, + loadinganimationname, + scene, + ketsjiEngine); + baseact = tmpgameact; + + break; + } + case ACT_RANDOM: + { + bRandomActuator *randAct + = (bRandomActuator *)bact->data; + + unsigned long seedArg = randAct->seed; + if (seedArg == 0) { + seedArg = (int)(ketsjiEngine->GetRealTime() * 100000.0); + seedArg ^= (intptr_t)randAct; + } + SCA_RandomActuator::KX_RANDOMACT_MODE modeArg + = SCA_RandomActuator::KX_RANDOMACT_NODEF; + SCA_RandomActuator *tmprandomact; + float paraArg1 = 0.0; + float paraArg2 = 0.0; + + switch (randAct->distribution) { + case ACT_RANDOM_BOOL_CONST: + { + modeArg = SCA_RandomActuator::KX_RANDOMACT_BOOL_CONST; + paraArg1 = (float)randAct->int_arg_1; + break; + } + case ACT_RANDOM_BOOL_UNIFORM: + { + modeArg = SCA_RandomActuator::KX_RANDOMACT_BOOL_UNIFORM; + break; + } + case ACT_RANDOM_BOOL_BERNOUILLI: + { + paraArg1 = randAct->float_arg_1; + modeArg = SCA_RandomActuator::KX_RANDOMACT_BOOL_BERNOUILLI; + break; + } + case ACT_RANDOM_INT_CONST: + { + modeArg = SCA_RandomActuator::KX_RANDOMACT_INT_CONST; + paraArg1 = (float)randAct->int_arg_1; + break; + } + case ACT_RANDOM_INT_UNIFORM: + { + paraArg1 = (float)randAct->int_arg_1; + paraArg2 = (float)randAct->int_arg_2; + modeArg = SCA_RandomActuator::KX_RANDOMACT_INT_UNIFORM; + break; + } + case ACT_RANDOM_INT_POISSON: + { + paraArg1 = randAct->float_arg_1; + modeArg = SCA_RandomActuator::KX_RANDOMACT_INT_POISSON; + break; + } + case ACT_RANDOM_FLOAT_CONST: + { + paraArg1 = randAct->float_arg_1; + modeArg = SCA_RandomActuator::KX_RANDOMACT_FLOAT_CONST; + break; + } + case ACT_RANDOM_FLOAT_UNIFORM: + { + paraArg1 = randAct->float_arg_1; + paraArg2 = randAct->float_arg_2; + modeArg = SCA_RandomActuator::KX_RANDOMACT_FLOAT_UNIFORM; + break; + } + case ACT_RANDOM_FLOAT_NORMAL: + { + paraArg1 = randAct->float_arg_1; + paraArg2 = randAct->float_arg_2; + modeArg = SCA_RandomActuator::KX_RANDOMACT_FLOAT_NORMAL; + break; + } + case ACT_RANDOM_FLOAT_NEGATIVE_EXPONENTIAL: + { + paraArg1 = randAct->float_arg_1; + modeArg = SCA_RandomActuator::KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL; + break; + } + default: + ; /* error */ + } + tmprandomact = new SCA_RandomActuator( + gameobj, + seedArg, + modeArg, + paraArg1, + paraArg2, + randAct->propname); + baseact = tmprandomact; + break; + } + case ACT_VIBRATION: + { + bVibrationActuator *vib_act = (bVibrationActuator *)bact->data; + SCA_VibrationActuator *tmp_vib_act = nullptr; + short mode = SCA_VibrationActuator::KX_ACT_VIBRATION_NONE; + + switch (vib_act->mode) { + case ACT_VIBRATION_PLAY: + { + mode = SCA_VibrationActuator::KX_ACT_VIBRATION_PLAY; + break; + } + case ACT_VIBRATION_STOP: + { + mode = SCA_VibrationActuator::KX_ACT_VIBRATION_STOP; + break; + } + } + + int joyindex = vib_act->joyindex; + float strengthLeft = vib_act->strength; + float strengthRight = vib_act->strength_right; + int duration = vib_act->duration; + + tmp_vib_act = new SCA_VibrationActuator(gameobj, mode, joyindex, strengthLeft, strengthRight, duration); + + baseact = tmp_vib_act; + break; + } + case ACT_VISIBILITY: + { + bVisibilityActuator *vis_act = (bVisibilityActuator *)bact->data; + KX_VisibilityActuator *tmp_vis_act = nullptr; + bool v = ((vis_act->flag & ACT_VISIBILITY_INVISIBLE) != 0); + bool o = ((vis_act->flag & ACT_VISIBILITY_OCCLUSION) != 0); + bool recursive = ((vis_act->flag & ACT_VISIBILITY_RECURSIVE) != 0); + + tmp_vis_act = new KX_VisibilityActuator(gameobj, !v, o, recursive); + + baseact = tmp_vis_act; + break; + } + + case ACT_STATE: + { + bStateActuator *sta_act = (bStateActuator *)bact->data; + KX_StateActuator *tmp_sta_act = nullptr; + + tmp_sta_act = + new KX_StateActuator(gameobj, sta_act->type, sta_act->mask); + + baseact = tmp_sta_act; + break; + } + + case ACT_2DFILTER: + { + bTwoDFilterActuator *_2dfilter = (bTwoDFilterActuator *)bact->data; + SCA_2DFilterActuator *tmp = nullptr; + + RAS_2DFilterManager::FILTER_MODE filtermode; + switch (_2dfilter->type) { + case ACT_2DFILTER_MOTIONBLUR: + { + filtermode = RAS_2DFilterManager::FILTER_MOTIONBLUR; + break; + } + case ACT_2DFILTER_BLUR: + { + filtermode = RAS_2DFilterManager::FILTER_BLUR; + break; + } + case ACT_2DFILTER_SHARPEN: + { + filtermode = RAS_2DFilterManager::FILTER_SHARPEN; + break; + } + case ACT_2DFILTER_DILATION: + { + filtermode = RAS_2DFilterManager::FILTER_DILATION; + break; + } + case ACT_2DFILTER_EROSION: + { + filtermode = RAS_2DFilterManager::FILTER_EROSION; + break; + } + case ACT_2DFILTER_LAPLACIAN: + { + filtermode = RAS_2DFilterManager::FILTER_LAPLACIAN; + break; + } + case ACT_2DFILTER_SOBEL: + { + filtermode = RAS_2DFilterManager::FILTER_SOBEL; + break; + } + case ACT_2DFILTER_PREWITT: + { + filtermode = RAS_2DFilterManager::FILTER_PREWITT; + break; + } + case ACT_2DFILTER_GRAYSCALE: + { + filtermode = RAS_2DFilterManager::FILTER_GRAYSCALE; + break; + } + case ACT_2DFILTER_SEPIA: + { + filtermode = RAS_2DFilterManager::FILTER_SEPIA; + break; + } + case ACT_2DFILTER_INVERT: + { + filtermode = RAS_2DFilterManager::FILTER_INVERT; + break; + } + case ACT_2DFILTER_CUSTOMFILTER: + { + filtermode = RAS_2DFilterManager::FILTER_CUSTOMFILTER; + break; + } + case ACT_2DFILTER_NOFILTER: + { + filtermode = RAS_2DFilterManager::FILTER_NOFILTER; + break; + } + case ACT_2DFILTER_DISABLED: + { + filtermode = RAS_2DFilterManager::FILTER_DISABLED; + break; + } + case ACT_2DFILTER_ENABLED: + { + filtermode = RAS_2DFilterManager::FILTER_ENABLED; + break; + } + default: + { + filtermode = RAS_2DFilterManager::FILTER_NOFILTER; + break; + } + } + + tmp = new SCA_2DFilterActuator(gameobj, filtermode, _2dfilter->flag, + _2dfilter->float_arg, _2dfilter->int_arg, _2dfilter->mipmap, + ketsjiEngine->GetRasterizer(), scene->Get2DFilterManager(), scene); + + if (_2dfilter->text) { + char *buf; + // this is some blender specific code + buf = txt_to_buf(_2dfilter->text); + if (buf) { + tmp->SetShaderText(buf); + MEM_freeN(buf); + } + } + + baseact = tmp; + + break; + } + case ACT_PARENT: + { + bParentActuator *parAct = (bParentActuator *)bact->data; + int mode = KX_ParentActuator::KX_PARENT_NODEF; + bool addToCompound = true; + bool ghost = true; + KX_GameObject *tmpgob = nullptr; + + switch (parAct->type) { + case ACT_PARENT_SET: + { + mode = KX_ParentActuator::KX_PARENT_SET; + tmpgob = converter.FindGameObject(parAct->ob); + addToCompound = !(parAct->flag & ACT_PARENT_COMPOUND); + ghost = !(parAct->flag & ACT_PARENT_GHOST); + break; + } + case ACT_PARENT_REMOVE: + { + mode = KX_ParentActuator::KX_PARENT_REMOVE; + tmpgob = nullptr; + break; + } + } + + KX_ParentActuator *tmpparact + = new KX_ParentActuator(gameobj, + mode, + addToCompound, + ghost, + tmpgob); + baseact = tmpparact; + break; + } + + case ACT_ARMATURE: + { + bArmatureActuator *armAct = (bArmatureActuator *)bact->data; + KX_GameObject *tmpgob = converter.FindGameObject(armAct->target); + KX_GameObject *subgob = converter.FindGameObject(armAct->subtarget); + BL_ArmatureActuator *tmparmact = new BL_ArmatureActuator( + gameobj, + armAct->type, + armAct->posechannel, + armAct->constraint, + tmpgob, + subgob, + armAct->weight, + armAct->influence); + baseact = tmparmact; + break; + } + case ACT_STEERING: + { + bSteeringActuator *stAct = (bSteeringActuator *)bact->data; + KX_GameObject *navmeshob = nullptr; + if (stAct->navmesh) { + PointerRNA settings_ptr; + RNA_pointer_create((ID *)stAct->navmesh, &RNA_GameObjectSettings, stAct->navmesh, &settings_ptr); + if (RNA_enum_get(&settings_ptr, "physics_type") == OB_BODY_TYPE_NAVMESH) { + navmeshob = converter.FindGameObject(stAct->navmesh); + } + } + KX_GameObject *targetob = converter.FindGameObject(stAct->target); + + int mode = KX_SteeringActuator::KX_STEERING_NODEF; + switch (stAct->type) { + case ACT_STEERING_SEEK: + { + mode = KX_SteeringActuator::KX_STEERING_SEEK; + break; + } + case ACT_STEERING_FLEE: + { + mode = KX_SteeringActuator::KX_STEERING_FLEE; + break; + } + case ACT_STEERING_PATHFOLLOWING: + { + mode = KX_SteeringActuator::KX_STEERING_PATHFOLLOWING; + break; + } + } + + bool selfTerminated = (stAct->flag & ACT_STEERING_SELFTERMINATED) != 0; + bool enableVisualization = (stAct->flag & ACT_STEERING_ENABLEVISUALIZATION) != 0; + short facingMode = (stAct->flag & ACT_STEERING_AUTOMATICFACING) ? stAct->facingaxis : 0; + bool normalup = (stAct->flag & ACT_STEERING_NORMALUP) != 0; + bool lockzvel = (stAct->flag & ACT_STEERING_LOCKZVEL) != 0; + KX_SteeringActuator *tmpstact + = new KX_SteeringActuator(gameobj, mode, targetob, navmeshob, stAct->dist, + stAct->velocity, stAct->acceleration, stAct->turnspeed, + selfTerminated, stAct->updateTime, + scene->GetObstacleSimulation(), facingMode, normalup, enableVisualization, lockzvel); + baseact = tmpstact; + break; + } + case ACT_MOUSE: + { + bMouseActuator *mouAct = (bMouseActuator *)bact->data; + int mode = KX_MouseActuator::KX_ACT_MOUSE_NODEF; + + switch (mouAct->type) { + case ACT_MOUSE_VISIBILITY: + { + mode = KX_MouseActuator::KX_ACT_MOUSE_VISIBILITY; + break; + } + case ACT_MOUSE_LOOK: + { + mode = KX_MouseActuator::KX_ACT_MOUSE_LOOK; + break; + } + } + + const bool visible = (mouAct->flag & ACT_MOUSE_VISIBLE) != 0; + const bool use_axis[2] = {(mouAct->flag & ACT_MOUSE_USE_AXIS_X) != 0, (mouAct->flag & ACT_MOUSE_USE_AXIS_Y) != 0}; + const bool reset[2] = {(mouAct->flag & ACT_MOUSE_RESET_X) != 0, (mouAct->flag & ACT_MOUSE_RESET_Y) != 0}; + const bool local[2] = {(mouAct->flag & ACT_MOUSE_LOCAL_X) != 0, (mouAct->flag & ACT_MOUSE_LOCAL_Y) != 0}; + const mt::vec2 limit[2] = {mt::vec2(mouAct->limit_x), mt::vec2(mouAct->limit_y)}; + + SCA_MouseManager *eventmgr = (SCA_MouseManager *)logicmgr->FindEventManager(SCA_EventManager::MOUSE_EVENTMGR); + if (eventmgr) { + KX_MouseActuator* tmpbaseact = new KX_MouseActuator(gameobj, ketsjiEngine, eventmgr, mode, visible, + use_axis, mt::vec2(mouAct->threshold), reset, mouAct->object_axis, local, + mt::vec2(mouAct->sensitivity), limit); + baseact = tmpbaseact; + } + break; + } + default: + ; /* generate some error */ + } + + if (baseact && !(bact->flag & ACT_DEACTIVATE)) { + baseact->SetExecutePriority(executePriority++); + uniquename += "#ACT#"; + uniqueint++; + EXP_IntValue *uniqueval = new EXP_IntValue(uniqueint); + uniquename += uniqueval->GetText(); + uniqueval->Release(); + baseact->SetName(bact->name); + baseact->SetLogicManager(logicmgr); + //gameobj->SetProperty(uniquename,baseact); + gameobj->AddActuator(baseact); + + converter.RegisterGameActuator(baseact, bact); + // done with baseact, release it + baseact->Release(); + } + else if (baseact) { + baseact->Release(); + } + + bact = bact->next; + } +} + + diff --git a/source/gameengine/Converter/KX_ConvertActuators.h b/source/gameengine/Converter/BL_ConvertActuators.h similarity index 93% rename from source/gameengine/Converter/KX_ConvertActuators.h rename to source/gameengine/Converter/BL_ConvertActuators.h index 688b5db50ce4..f7f42de59f6e 100644 --- a/source/gameengine/Converter/KX_ConvertActuators.h +++ b/source/gameengine/Converter/BL_ConvertActuators.h @@ -25,7 +25,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file KX_ConvertActuators.h +/** \file BL_ConvertActuators.h * \ingroup bgeconv */ @@ -40,6 +40,6 @@ void BL_ConvertActuators(const char* maggiename, class KX_KetsjiEngine* ketsjiEngine, int activeLayerBitInfo, bool isInActiveLayer, - class KX_BlenderSceneConverter* converter); + class BL_SceneConverter& converter); #endif /* __KX_CONVERTACTUATORS_H__ */ diff --git a/source/gameengine/Converter/KX_ConvertControllers.cpp b/source/gameengine/Converter/BL_ConvertControllers.cpp similarity index 65% rename from source/gameengine/Converter/KX_ConvertControllers.cpp rename to source/gameengine/Converter/BL_ConvertControllers.cpp index a00a90428da5..c71ab61a7c04 100644 --- a/source/gameengine/Converter/KX_ConvertControllers.cpp +++ b/source/gameengine/Converter/BL_ConvertControllers.cpp @@ -25,15 +25,15 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file gameengine/Converter/KX_ConvertControllers.cpp +/** \file gameengine/Converter/BL_ConvertControllers.cpp * \ingroup bgeconv */ #include "MEM_guardedalloc.h" -#include "KX_BlenderSceneConverter.h" -#include "KX_ConvertControllers.h" +#include "BL_SceneConverter.h" +#include "BL_ConvertControllers.h" #include "EXP_Python.h" // Controller @@ -48,6 +48,7 @@ #include "SCA_LogicManager.h" #include "KX_GameObject.h" +#include "KX_Globals.h" #include "EXP_IntValue.h" /* This little block needed for linking to Blender... */ @@ -65,22 +66,20 @@ /* end of blender include block */ +#include "CM_Message.h" - static void -LinkControllerToActuators( - SCA_IController *game_controller, - bController* bcontr, - SCA_LogicManager* logicmgr, - KX_BlenderSceneConverter* converter -) { +static void LinkControllerToActuators(SCA_IController *game_controller, + bController *bcontr, + SCA_LogicManager *logicmgr, + BL_SceneConverter& converter) +{ // Iterate through the actuators of the game blender // controller and find the corresponding ketsji actuator. - game_controller->ReserveActuator(bcontr->totlinks); - for (int i=0;itotlinks;i++) + for (int i = 0; i < bcontr->totlinks; i++) { - bActuator* bact = (bActuator*) bcontr->links[i]; - SCA_IActuator *game_actuator = converter->FindGameActuator(bact); + bActuator *bact = (bActuator *)bcontr->links[i]; + SCA_IActuator *game_actuator = converter.FindGameActuator(bact); if (game_actuator) { logicmgr->RegisterToActuator(game_controller, game_actuator); } @@ -88,29 +87,27 @@ LinkControllerToActuators( } -void BL_ConvertControllers( - struct Object* blenderobject, - class KX_GameObject* gameobj, - SCA_LogicManager* logicmgr, - int activeLayerBitInfo, - bool isInActiveLayer, - KX_BlenderSceneConverter* converter, - bool libloading -) { - int uniqueint=0; +void BL_ConvertControllers(struct Object *blenderobject, + class KX_GameObject *gameobj, + SCA_LogicManager *logicmgr, + int activeLayerBitInfo, + bool isInActiveLayer, + BL_SceneConverter& converter, + bool libloading) +{ + int uniqueint = 0; int count = 0; - int executePriority=0; - bController* bcontr = (bController*)blenderobject->controllers.first; + int executePriority = 0; + bController *bcontr = (bController *)blenderobject->controllers.first; while (bcontr) { bcontr = bcontr->next; count++; } - gameobj->ReserveController(count); - bcontr = (bController*)blenderobject->controllers.first; + bcontr = (bController *)blenderobject->controllers.first; while (bcontr) { - SCA_IController* gamecontroller = NULL; + SCA_IController *gamecontroller = nullptr; switch (bcontr->type) { case CONT_LOGIC_AND: { @@ -144,34 +141,27 @@ void BL_ConvertControllers( } case CONT_EXPRESSION: { - bExpressionCont* bexpcont = (bExpressionCont*) bcontr->data; - STR_String expressiontext = STR_String(bexpcont->str); - if (expressiontext.Length() > 0) - { - gamecontroller = new SCA_ExpressionController(gameobj,expressiontext); + bExpressionCont *bexpcont = (bExpressionCont *)bcontr->data; + std::string expressiontext = std::string(bexpcont->str); + if (!expressiontext.empty()) { + gamecontroller = new SCA_ExpressionController(gameobj, expressiontext); } break; } case CONT_PYTHON: { - bPythonCont* pycont = (bPythonCont*) bcontr->data; - SCA_PythonController* pyctrl = new SCA_PythonController(gameobj, pycont->mode); + bPythonCont *pycont = (bPythonCont *)bcontr->data; + SCA_PythonController *pyctrl = new SCA_PythonController(gameobj, pycont->mode); gamecontroller = pyctrl; #ifdef WITH_PYTHON - // When libloading, this is delayed to KX_Scene::MergeScene_LogicBrick to avoid GIL issues - if (!libloading) - pyctrl->SetNamespace(converter->GetPyNamespace()); - - if (pycont->mode==SCA_PythonController::SCA_PYEXEC_SCRIPT) { - if (pycont->text) - { + if (pycont->mode == SCA_PythonController::SCA_PYEXEC_SCRIPT) { + if (pycont->text) { char *buf; // this is some blender specific code - buf= txt_to_buf(pycont->text); - if (buf) - { - pyctrl->SetScriptText(STR_String(buf)); - pyctrl->SetScriptName(pycont->text->id.name+2); + buf = txt_to_buf(pycont->text); + if (buf) { + pyctrl->SetScriptText(std::string(buf)); + pyctrl->SetScriptName(pycont->text->id.name + 2); MEM_freeN(buf); } @@ -179,11 +169,12 @@ void BL_ConvertControllers( } else { /* let the controller print any warnings here when importing */ - pyctrl->SetScriptText(STR_String(pycont->module)); + pyctrl->SetScriptText(std::string(pycont->module)); pyctrl->SetScriptName(pycont->module); /* will be something like module.func so using it as the name is OK */ if (pycont->flag & CONT_PY_DEBUG) { - printf("\nDebuging \"%s\", module for object %s\n\texpect worse performance.\n", pycont->module, blenderobject->id.name+2); + CM_Warning("debuging \"" << pycont->module << "\", module for object " << blenderobject->id.name + 2 + << " expect worse performance."); pyctrl->SetDebug(true); } } @@ -197,16 +188,15 @@ void BL_ConvertControllers( } } - if (gamecontroller && !(bcontr->flag & CONT_DEACTIVATE)) - { - LinkControllerToActuators(gamecontroller,bcontr,logicmgr,converter); + if (gamecontroller && !(bcontr->flag & CONT_DEACTIVATE)) { + LinkControllerToActuators(gamecontroller, bcontr, logicmgr, converter); gamecontroller->SetExecutePriority(executePriority++); gamecontroller->SetBookmark((bcontr->flag & CONT_PRIO) != 0); gamecontroller->SetState(bcontr->state_mask); - STR_String uniquename = bcontr->name; + std::string uniquename = bcontr->name; uniquename += "#CONTR#"; uniqueint++; - CIntValue* uniqueval = new CIntValue(uniqueint); + EXP_IntValue *uniqueval = new EXP_IntValue(uniqueint); uniquename += uniqueval->GetText(); uniqueval->Release(); //unique name was never implemented for sensors and actuators, only for controllers @@ -217,16 +207,17 @@ void BL_ConvertControllers( gamecontroller->SetLogicManager(logicmgr); gameobj->AddController(gamecontroller); - converter->RegisterGameController(gamecontroller, bcontr); + converter.RegisterGameController(gamecontroller, bcontr); -#ifdef WITH_PYTHON +#ifdef WITH_PYTHON // TODO why ??? // When libloading, this is delayed to KX_Scene::MergeScene_LogicBrick to avoid GIL issues - if (!libloading && bcontr->type==CONT_PYTHON) { - SCA_PythonController *pyctrl= static_cast(gamecontroller); + if (!libloading && bcontr->type == CONT_PYTHON) { + SCA_PythonController *pyctrl = static_cast(gamecontroller); /* not strictly needed but gives syntax errors early on and * gives more predictable performance for larger scripts */ - if (pyctrl->m_mode==SCA_PythonController::SCA_PYEXEC_SCRIPT) + if (pyctrl->m_mode == SCA_PythonController::SCA_PYEXEC_SCRIPT) { pyctrl->Compile(); + } else { /* We cant do this because importing runs the script which could end up accessing * internal BGE functions, this is unstable while we're converting the scene. @@ -241,8 +232,9 @@ void BL_ConvertControllers( //done with gamecontroller gamecontroller->Release(); } - else if (gamecontroller) + else if (gamecontroller) { gamecontroller->Release(); + } bcontr = bcontr->next; } diff --git a/source/gameengine/Converter/KX_ConvertControllers.h b/source/gameengine/Converter/BL_ConvertControllers.h similarity index 92% rename from source/gameengine/Converter/KX_ConvertControllers.h rename to source/gameengine/Converter/BL_ConvertControllers.h index b5bc4148e1a6..c43cc1c91fad 100644 --- a/source/gameengine/Converter/KX_ConvertControllers.h +++ b/source/gameengine/Converter/BL_ConvertControllers.h @@ -25,7 +25,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file KX_ConvertControllers.h +/** \file BL_ConvertControllers.h * \ingroup bgeconv */ @@ -39,8 +39,8 @@ void BL_ConvertControllers( class KX_GameObject* gameobj, class SCA_LogicManager* logicmgr, int activeLayerBitInfo, - bool isInActiveLayer, - class KX_BlenderSceneConverter* converter, + bool isInActiveLayer, + class BL_SceneConverter& converter, bool libloading ); diff --git a/source/gameengine/Converter/BL_ConvertObjectInfo.cpp b/source/gameengine/Converter/BL_ConvertObjectInfo.cpp new file mode 100644 index 000000000000..e99ad270083a --- /dev/null +++ b/source/gameengine/Converter/BL_ConvertObjectInfo.cpp @@ -0,0 +1,6 @@ +#include "BL_ConvertObjectInfo.h" + +BL_ConvertObjectInfo::BL_ConvertObjectInfo(Object *blendobj) + :m_blenderObject(blendobj) +{ +} diff --git a/source/gameengine/Converter/BL_ConvertObjectInfo.h b/source/gameengine/Converter/BL_ConvertObjectInfo.h new file mode 100644 index 000000000000..7900da52a1a9 --- /dev/null +++ b/source/gameengine/Converter/BL_ConvertObjectInfo.h @@ -0,0 +1,22 @@ +#ifndef __BL_CONVERT_OBJECT_INFO__ +#define __BL_CONVERT_OBJECT_INFO__ + +#include "BL_Resource.h" + +#include + +struct bRigidBodyJointConstraint; +struct Object; + +class BL_ConvertObjectInfo : public BL_Resource +{ +public: + /// Blender object used during conversion. + Object *m_blenderObject; + /// Object constraints defined by the user. + std::vector m_constraints; + + BL_ConvertObjectInfo(Object *blendobj); +}; + +#endif // __BL_CONVERT_OBJECT_INFO__ diff --git a/source/gameengine/Converter/KX_ConvertProperties.cpp b/source/gameengine/Converter/BL_ConvertProperties.cpp similarity index 51% rename from source/gameengine/Converter/KX_ConvertProperties.cpp rename to source/gameengine/Converter/BL_ConvertProperties.cpp index 03360c0e2a89..6f271a4a8d00 100644 --- a/source/gameengine/Converter/KX_ConvertProperties.cpp +++ b/source/gameengine/Converter/BL_ConvertProperties.cpp @@ -25,12 +25,12 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file gameengine/Converter/KX_ConvertProperties.cpp +/** \file gameengine/Converter/BL_ConvertProperties.cpp * \ingroup bgeconv */ -#include "KX_ConvertProperties.h" +#include "BL_ConvertProperties.h" #include "DNA_object_types.h" @@ -39,7 +39,6 @@ #include "EXP_Value.h" -#include "EXP_VectorValue.h" #include "EXP_BoolValue.h" #include "EXP_StringValue.h" #include "EXP_FloatValue.h" @@ -60,67 +59,71 @@ extern "C" { #include "BKE_property.h" } +#include "CM_Message.h" + +#include +#include + /* prototype */ -void BL_ConvertTextProperty(Object* object, KX_FontObject* fontobj,SCA_TimeEventManager* timemgr,SCA_IScene* scene, bool isInActiveLayer); +void BL_ConvertTextProperty(Object *object, KX_FontObject *fontobj, SCA_TimeEventManager *timemgr, SCA_IScene *scene, bool isInActiveLayer); -void BL_ConvertProperties(Object* object,KX_GameObject* gameobj,SCA_TimeEventManager* timemgr,SCA_IScene* scene, bool isInActiveLayer) +void BL_ConvertProperties(Object *object, KX_GameObject *gameobj, SCA_TimeEventManager *timemgr, SCA_IScene *scene, bool isInActiveLayer) { - bProperty* prop = (bProperty*)object->prop.first; - CValue* propval; + bProperty *prop = (bProperty *)object->prop.first; + EXP_Value *propval; bool show_debug_info; while (prop) { - propval = NULL; - show_debug_info = bool (prop->flag & PROP_DEBUG); + propval = nullptr; + show_debug_info = bool(prop->flag & PROP_DEBUG); switch (prop->type) { case GPROP_BOOL: { - propval = new CBoolValue((bool)(prop->data != 0)); - gameobj->SetProperty(prop->name,propval); + propval = new EXP_BoolValue((bool)(prop->data != 0)); + gameobj->SetProperty(prop->name, propval); //promp->poin= &prop->data; break; } case GPROP_INT: { - propval = new CIntValue((int)prop->data); - gameobj->SetProperty(prop->name,propval); + propval = new EXP_IntValue((int)prop->data); + gameobj->SetProperty(prop->name, propval); break; } case GPROP_FLOAT: { //prop->poin= &prop->data; - float floatprop = *((float*)&prop->data); - propval = new CFloatValue(floatprop); - gameobj->SetProperty(prop->name,propval); + float floatprop = *((float *)&prop->data); + propval = new EXP_FloatValue(floatprop); + gameobj->SetProperty(prop->name, propval); + break; } - break; case GPROP_STRING: { //prop->poin= callocN(MAX_PROPSTRING, "property string"); - propval = new CStringValue((char*)prop->poin,""); - gameobj->SetProperty(prop->name,propval); + propval = new EXP_StringValue((char *)prop->poin, ""); + gameobj->SetProperty(prop->name, propval); break; } case GPROP_TIME: { - float floatprop = *((float*)&prop->data); + float floatprop = *((float *)&prop->data); - CValue* timeval = new CFloatValue(floatprop); + EXP_Value *timeval = new EXP_FloatValue(floatprop); // set a subproperty called 'timer' so that // we can register the replica of this property // at the time a game object is replicated (AddObjectActuator triggers this) - CValue *bval = new CBoolValue(true); - timeval->SetProperty("timer",bval); + EXP_Value *bval = new EXP_BoolValue(true); + timeval->SetProperty("timer", bval); bval->Release(); - if (isInActiveLayer) - { + if (isInActiveLayer) { timemgr->AddTimeProperty(timeval); } propval = timeval; - gameobj->SetProperty(prop->name,timeval); + gameobj->SetProperty(prop->name, timeval); } default: @@ -129,11 +132,9 @@ void BL_ConvertProperties(Object* object,KX_GameObject* gameobj,SCA_TimeEventMan } } - if (propval) - { - if (show_debug_info && isInActiveLayer) - { - scene->AddDebugProperty(gameobj,STR_String(prop->name)); + if (propval) { + if (show_debug_info && isInActiveLayer) { + scene->AddDebugProperty(gameobj, prop->name); } // done with propval, release it propval->Release(); @@ -141,15 +142,17 @@ void BL_ConvertProperties(Object* object,KX_GameObject* gameobj,SCA_TimeEventMan #ifdef WITH_PYTHON /* Warn if we double up on attributes, this isn't quite right since it wont find inherited attributes however there arnt many */ - for (PyAttributeDef *attrdef = KX_GameObject::Attributes; attrdef->m_name; attrdef++) { - if (strcmp(prop->name, attrdef->m_name)==0) { - printf("Warning! user defined property name \"%s\" is also a python attribute for object \"%s\"\n\tUse ob[\"%s\"] syntax to avoid conflict\n", prop->name, object->id.name+2, prop->name); + for (PyAttributeDef *attrdef = KX_GameObject::Attributes; !attrdef->m_name.empty(); attrdef++) { + if (prop->name == attrdef->m_name) { + CM_Warning("user defined property name \"" << prop->name << "\" is also a python attribute for object \"" + << object->id.name + 2 << "\". Use ob[\"" << prop->name << "\"] syntax to avoid conflict"); break; } } for (PyMethodDef *methdef = KX_GameObject::Methods; methdef->ml_name; methdef++) { - if (strcmp(prop->name, methdef->ml_name)==0) { - printf("Warning! user defined property name \"%s\" is also a python method for object \"%s\"\n\tUse ob[\"%s\"] syntax to avoid conflict\n", prop->name, object->id.name+2, prop->name); + if (strcmp(prop->name, methdef->ml_name) == 0) { + CM_Warning("user defined property name \"" << prop->name << "\" is also a python method for object \"" + << object->id.name + 2 << "\". Use ob[\"" << prop->name << "\"] syntax to avoid conflict"); break; } } @@ -159,84 +162,90 @@ void BL_ConvertProperties(Object* object,KX_GameObject* gameobj,SCA_TimeEventMan prop = prop->next; } // check if state needs to be debugged - if (object->scaflag & OB_DEBUGSTATE && isInActiveLayer) - { + if (object->scaflag & OB_DEBUGSTATE && isInActiveLayer) { // reserve name for object state - scene->AddDebugProperty(gameobj,STR_String("__state__")); + scene->AddDebugProperty(gameobj, "__state__"); } /* Font Objects need to 'copy' the Font Object data body to ["Text"] */ - if (object->type == OB_FONT) - { + if (object->type == OB_FONT) { BL_ConvertTextProperty(object, (KX_FontObject *)gameobj, timemgr, scene, isInActiveLayer); } } -void BL_ConvertTextProperty(Object* object, KX_FontObject* fontobj,SCA_TimeEventManager* timemgr,SCA_IScene* scene, bool isInActiveLayer) +void BL_ConvertTextProperty(Object *object, KX_FontObject *fontobj, SCA_TimeEventManager *timemgr, SCA_IScene *scene, bool isInActiveLayer) { - CValue* tprop = fontobj->GetProperty("Text"); - if (!tprop) return; - bProperty* prop = BKE_bproperty_object_get(object, "Text"); - if (!prop) return; + EXP_Value *tprop = fontobj->GetProperty("Text"); + if (!tprop) { + return; + } + bProperty *prop = BKE_bproperty_object_get(object, "Text"); + if (!prop) { + return; + } Curve *curve = static_cast(object->data); - STR_String str = curve->str; - CValue* propval = NULL; + const std::string str = curve->str; + std::stringstream stream(str); + EXP_Value *propval = nullptr; switch (prop->type) { case GPROP_BOOL: { - int value = atoi(str); - propval = new CBoolValue((bool)(value != 0)); - tprop->SetValue(propval); + bool value; + stream >> value; + propval = new EXP_BoolValue(value != 0); break; } case GPROP_INT: { - int value = atoi(str); - propval = new CIntValue(value); - tprop->SetValue(propval); + int value; + stream >> value; + propval = new EXP_IntValue(value); break; } case GPROP_FLOAT: { - float floatprop = (float)atof(str); - propval = new CFloatValue(floatprop); - tprop->SetValue(propval); + float floatprop; + stream >> floatprop; + propval = new EXP_FloatValue(floatprop); break; } case GPROP_STRING: { - propval = new CStringValue(str, ""); - tprop->SetValue(propval); + propval = new EXP_StringValue(str, ""); break; } case GPROP_TIME: { - float floatprop = (float)atof(str); + float floatprop; + stream >> floatprop; - CValue* timeval = new CFloatValue(floatprop); + propval = new EXP_FloatValue(floatprop); // set a subproperty called 'timer' so that // we can register the replica of this property // at the time a game object is replicated (AddObjectActuator triggers this) - CValue *bval = new CBoolValue(true); - timeval->SetProperty("timer",bval); + EXP_Value *bval = new EXP_BoolValue(true); + propval->SetProperty("timer", bval); bval->Release(); - if (isInActiveLayer) - { - timemgr->AddTimeProperty(timeval); + if (isInActiveLayer) { + timemgr->AddTimeProperty(propval); } - - propval = timeval; - tprop->SetValue(timeval); + break; } default: { - // todo make an assert etc. + BLI_assert(0); } } + if (stream.fail() || stream.bad()) { + CM_Error("failed convert font property \"Text\""); + } + if (propval) { + tprop->SetValue(propval); propval->Release(); } } + diff --git a/source/gameengine/Converter/KX_ConvertProperties.h b/source/gameengine/Converter/BL_ConvertProperties.h similarity index 97% rename from source/gameengine/Converter/KX_ConvertProperties.h rename to source/gameengine/Converter/BL_ConvertProperties.h index 8f96cc21af6e..471734263aa0 100644 --- a/source/gameengine/Converter/KX_ConvertProperties.h +++ b/source/gameengine/Converter/BL_ConvertProperties.h @@ -25,7 +25,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file KX_ConvertProperties.h +/** \file BL_ConvertProperties.h * \ingroup bgeconv */ diff --git a/source/gameengine/Converter/BL_ConvertSensors.cpp b/source/gameengine/Converter/BL_ConvertSensors.cpp new file mode 100644 index 000000000000..972724c4e079 --- /dev/null +++ b/source/gameengine/Converter/BL_ConvertSensors.cpp @@ -0,0 +1,688 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Converter/BL_ConvertSensors.cpp + * \ingroup bgeconv + * + * Conversion of Blender data blocks to KX sensor system + */ + +#ifdef _MSC_VER +# pragma warning (disable:4786) +#endif + +#include "wm_event_types.h" +#include "BL_SceneConverter.h" +#include "BL_ConvertSensors.h" + +/* This little block needed for linking to Blender... */ +#ifdef _MSC_VER +//# include "BLI_winstuff.h" +#endif + +#include "DNA_object_types.h" +#include "DNA_material_types.h" +#include "DNA_sensor_types.h" +#include "DNA_controller_types.h" +#include "DNA_actuator_types.h" /* for SENS_ALL_KEYS ? this define is + * probably misplaced */ +/* end of blender include block */ + +#include "RAS_IMaterial.h" +// Sensors +#include "KX_GameObject.h" +#include "RAS_Mesh.h" +#include "SCA_KeyboardSensor.h" +#include "SCA_MouseSensor.h" +#include "SCA_AlwaysSensor.h" +#include "KX_CollisionSensor.h" +#include "KX_NearSensor.h" +#include "KX_RadarSensor.h" +#include "KX_MouseFocusSensor.h" +#include "KX_ArmatureSensor.h" +#include "SCA_JoystickSensor.h" +#include "KX_NetworkMessageSensor.h" +#include "SCA_ActuatorSensor.h" +#include "SCA_DelaySensor.h" + + +#include "SCA_PropertySensor.h" +#include "SCA_RandomSensor.h" +#include "KX_RaySensor.h" +#include "KX_MovementSensor.h" +#include "SCA_EventManager.h" +#include "SCA_LogicManager.h" +#include "KX_Scene.h" +#include "EXP_IntValue.h" +#include "RAS_ICanvas.h" +#include "PHY_IPhysicsEnvironment.h" + +#include "KX_KetsjiEngine.h" +#include "KX_Globals.h" +#include "BL_BlenderDataConversion.h" + +#include "CM_Message.h" + +void BL_ConvertSensors(struct Object *blenderobject, + class KX_GameObject *gameobj, + SCA_LogicManager *logicmgr, + KX_Scene *kxscene, + KX_KetsjiEngine *kxengine, + int activeLayerBitInfo, + bool isInActiveLayer, + RAS_ICanvas *canvas, + BL_SceneConverter& converter) +{ + + int executePriority = 0; + int uniqueint = 0; + int count = 0; + bSensor *sens = (bSensor *)blenderobject->sensors.first; + bool pos_pulsemode = false; + bool neg_pulsemode = false; + int skipped_ticks = 0; + bool invert = false; + bool level = false; + bool tap = false; + + while (sens) + { + sens = sens->next; + count++; + } + sens = (bSensor *)blenderobject->sensors.first; + + while (sens) { + if (!(sens->flag & SENS_DEACTIVATE)) { + SCA_ISensor *gamesensor = nullptr; + /* All sensors have a pulse toggle, skipped ticks parameter, and invert field. */ + /* These are extracted here, and set when the sensor is added to the */ + /* list. */ + pos_pulsemode = (sens->pulse & SENS_PULSE_REPEAT) != 0; + neg_pulsemode = (sens->pulse & SENS_NEG_PULSE_MODE) != 0; + + skipped_ticks = sens->freq; + invert = !(sens->invert == 0); + level = !(sens->level == 0); + tap = !(sens->tap == 0); + + switch (sens->type) { + case SENS_ALWAYS: + { + + SCA_EventManager *eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); + if (eventmgr) { + gamesensor = new SCA_AlwaysSensor(eventmgr, gameobj); + } + + break; + } + + case SENS_DELAY: + { + // we can reuse the Always event manager for the delay sensor + SCA_EventManager *eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); + if (eventmgr) { + bDelaySensor *delaysensor = (bDelaySensor *)sens->data; + gamesensor = new SCA_DelaySensor(eventmgr, + gameobj, + delaysensor->delay, + delaysensor->duration, + (delaysensor->flag & SENS_DELAY_REPEAT) != 0); + } + break; + } + + case SENS_COLLISION: + { + SCA_EventManager *eventmgr = logicmgr->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR); + if (eventmgr) { + // collision sensor can sense both materials and properties. + + bool bFindMaterial = false, bCollisionPulse = false; + + bCollisionSensor *blendercollisionsensor = (bCollisionSensor *)sens->data; + + bFindMaterial = (blendercollisionsensor->mode & SENS_COLLISION_MATERIAL); + bCollisionPulse = (blendercollisionsensor->mode & SENS_COLLISION_PULSE); + + + const std::string touchPropOrMatName = bFindMaterial ? + blendercollisionsensor->materialName : blendercollisionsensor->name; + + + if (gameobj->GetPhysicsController()) { + gamesensor = new KX_CollisionSensor(eventmgr, + gameobj, + bFindMaterial, + bCollisionPulse, + touchPropOrMatName); + } + + } + + break; + } + case SENS_MESSAGE: + { + SCA_EventManager *eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); + bMessageSensor *msgSens = (bMessageSensor *)sens->data; + + /* Get our NetworkScene */ + KX_NetworkMessageScene *NetworkScene = kxscene->GetNetworkMessageScene(); + /* filter on the incoming subjects, might be empty */ + const std::string subject = msgSens->subject; + + gamesensor = new KX_NetworkMessageSensor( + eventmgr, // our eventmanager + NetworkScene, // our NetworkScene + gameobj, // the sensor controlling object + subject); // subject to filter on + break; + } + case SENS_NEAR: + { + + SCA_EventManager *eventmgr = logicmgr->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR); + if (eventmgr) { + bNearSensor *blendernearsensor = (bNearSensor *)sens->data; + const std::string nearpropertyname = (char *)blendernearsensor->name; + + //DT_ShapeHandle shape = DT_Sphere(0.0); + + // this sumoObject is not deleted by a gameobj, so delete it ourself + // later (memleaks)! + float radius = blendernearsensor->dist; + const mt::vec3& wpos = gameobj->NodeGetWorldPosition(); + bool bFindMaterial = false; + PHY_IPhysicsController *physCtrl = kxscene->GetPhysicsEnvironment()->CreateSphereController(radius, wpos); + + //will be done in KX_CollisionEventManager::RegisterSensor() + //if (isInActiveLayer) + // kxscene->GetPhysicsEnvironment()->addSensor(physCtrl); + + + + gamesensor = new KX_NearSensor(eventmgr, gameobj, + blendernearsensor->dist, + blendernearsensor->resetdist, + bFindMaterial, + nearpropertyname, + physCtrl); + + } + break; + } + + + case SENS_KEYBOARD: + { + /* temporary input device, for converting the code for the keyboard sensor */ + + bKeyboardSensor *blenderkeybdsensor = (bKeyboardSensor *)sens->data; + SCA_KeyboardManager *eventmgr = (SCA_KeyboardManager *)logicmgr->FindEventManager(SCA_EventManager::KEYBOARD_EVENTMGR); + if (eventmgr) { + gamesensor = new SCA_KeyboardSensor(eventmgr, + BL_ConvertKeyCode(blenderkeybdsensor->key), + BL_ConvertKeyCode(blenderkeybdsensor->qual), + BL_ConvertKeyCode(blenderkeybdsensor->qual2), + (blenderkeybdsensor->type == SENS_ALL_KEYS), + blenderkeybdsensor->targetName, + blenderkeybdsensor->toggleName, + gameobj, + KX_GetActiveEngine()->GetExitKey()); // blenderkeybdsensor->pad); + + } + + break; + } + case SENS_MOUSE: + { + int keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_NODEF; + int trackfocus = 0; + bMouseSensor *bmouse = (bMouseSensor *)sens->data; + + /* There are two main types of mouse sensors. If there is + * no focus-related behavior requested, we can make do + * with a basic sensor. This cuts down memory usage and + * gives a slight performance gain. */ + + SCA_MouseManager *eventmgr + = (SCA_MouseManager *)logicmgr->FindEventManager(SCA_EventManager::MOUSE_EVENTMGR); + if (eventmgr) { + + /* Determine key mode. There is at most one active mode. */ + switch (bmouse->type) { + case BL_SENS_MOUSE_LEFT_BUTTON: + { + keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_LEFTBUTTON; + break; + } + case BL_SENS_MOUSE_MIDDLE_BUTTON: + { + keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_MIDDLEBUTTON; + break; + } + case BL_SENS_MOUSE_RIGHT_BUTTON: + { + keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_RIGHTBUTTON; + break; + } + case BL_SENS_MOUSE_WHEEL_UP: + { + keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_WHEELUP; + break; + } + case BL_SENS_MOUSE_WHEEL_DOWN: + { + keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_WHEELDOWN; + break; + } + case BL_SENS_MOUSE_MOVEMENT: + { + keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_MOVEMENT; + break; + } + case BL_SENS_MOUSE_MOUSEOVER: + { + trackfocus = 1; + break; + } + case BL_SENS_MOUSE_MOUSEOVER_ANY: + { + trackfocus = 2; + break; + } + + default: + ; /* error */ + } + + /* initial mouse position */ + int startx = canvas->GetMaxX() / 2; + int starty = canvas->GetMaxY() / 2; + + if (!trackfocus) { + /* plain, simple mouse sensor */ + gamesensor = new SCA_MouseSensor(eventmgr, + startx, starty, + keytype, + gameobj); + } + else { + /* give us a focus-aware sensor */ + bool bFindMaterial = (bmouse->mode & SENS_COLLISION_MATERIAL); + bool bXRay = (bmouse->flag & SENS_RAY_XRAY); + int mask = bmouse->mask; + std::string checkname = (bFindMaterial ? bmouse->matname : bmouse->propname); + + gamesensor = new KX_MouseFocusSensor(eventmgr, + startx, + starty, + keytype, + trackfocus, + (bmouse->flag & SENS_MOUSE_FOCUS_PULSE) ? true : false, + checkname, + bFindMaterial, + bXRay, + mask, + kxscene, + kxengine, + gameobj); + } + } + break; + } + case SENS_PROPERTY: + { + bPropertySensor *blenderpropsensor = (bPropertySensor *)sens->data; + SCA_EventManager *eventmgr + = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); + if (eventmgr) { + std::string propname = blenderpropsensor->name; + std::string propval = blenderpropsensor->value; + std::string propmaxval = blenderpropsensor->maxvalue; + + SCA_PropertySensor::KX_PROPSENSOR_TYPE + propchecktype = SCA_PropertySensor::KX_PROPSENSOR_NODEF; + + /* Better do an explicit conversion here! (was implicit */ + /* before...) */ + switch (blenderpropsensor->type) { + case SENS_PROP_EQUAL: + { + propchecktype = SCA_PropertySensor::KX_PROPSENSOR_EQUAL; + break; + } + case SENS_PROP_NEQUAL: + { + propchecktype = SCA_PropertySensor::KX_PROPSENSOR_NOTEQUAL; + break; + } + case SENS_PROP_INTERVAL: + { + propchecktype = SCA_PropertySensor::KX_PROPSENSOR_INTERVAL; + break; + } + case SENS_PROP_CHANGED: + { + propchecktype = SCA_PropertySensor::KX_PROPSENSOR_CHANGED; + break; + } + case SENS_PROP_EXPRESSION: + { + propchecktype = SCA_PropertySensor::KX_PROPSENSOR_EXPRESSION; + /* error */ + break; + } + case SENS_PROP_LESSTHAN: + { + propchecktype = SCA_PropertySensor::KX_PROPSENSOR_LESSTHAN; + break; + } + case SENS_PROP_GREATERTHAN: + { + propchecktype = SCA_PropertySensor::KX_PROPSENSOR_GREATERTHAN; + break; + } + default: + ; /* error */ + } + gamesensor = new SCA_PropertySensor(eventmgr, gameobj, propname, propval, propmaxval, propchecktype); + } + + break; + } + case SENS_ACTUATOR: + { + bActuatorSensor *blenderactsensor = (bActuatorSensor *)sens->data; + // we will reuse the property event manager, there is nothing special with this sensor + SCA_EventManager *eventmgr + = logicmgr->FindEventManager(SCA_EventManager::ACTUATOR_EVENTMGR); + if (eventmgr) { + std::string propname = blenderactsensor->name; + gamesensor = new SCA_ActuatorSensor(eventmgr, gameobj, propname); + } + break; + } + + case SENS_ARMATURE: + { + bArmatureSensor *blenderarmsensor = (bArmatureSensor *)sens->data; + // we will reuse the property event manager, there is nothing special with this sensor + SCA_EventManager *eventmgr + = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); + if (eventmgr) { + std::string bonename = blenderarmsensor->posechannel; + std::string constraintname = blenderarmsensor->constraint; + gamesensor = new KX_ArmatureSensor(eventmgr, gameobj, bonename, constraintname, blenderarmsensor->type, blenderarmsensor->value); + } + break; + } + + case SENS_RADAR: + { + + SCA_EventManager *eventmgr = logicmgr->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR); + if (eventmgr) { + bRadarSensor *blenderradarsensor = (bRadarSensor *)sens->data; + const std::string radarpropertyname = blenderradarsensor->name; + + int radaraxis = blenderradarsensor->axis; + + float coneheight = blenderradarsensor->range; + + // janco: the angle was doubled, so should I divide the factor in 2 + // or the blenderradarsensor->angle? + // nzc: the angle is the opening angle. We need to init with + // the axis-hull angle,so /2.0. + float factor = tan(blenderradarsensor->angle * 0.5f); + //float coneradius = coneheight * (factor / 2); + float coneradius = coneheight * factor; + + + // this sumoObject is not deleted by a gameobj, so delete it ourself + // later (memleaks)! + float smallmargin = 0.0; + float largemargin = 0.0; + + bool bFindMaterial = false; + PHY_IPhysicsController *ctrl = kxscene->GetPhysicsEnvironment()->CreateConeController((float)coneradius, (float)coneheight); + + gamesensor = new KX_RadarSensor( + eventmgr, + gameobj, + ctrl, + coneradius, + coneheight, + radaraxis, + smallmargin, + largemargin, + bFindMaterial, + radarpropertyname); + + } + + break; + } + case SENS_RAY: + { + bRaySensor *blenderraysensor = (bRaySensor *)sens->data; + + //blenderradarsensor->angle; + SCA_EventManager *eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); + if (eventmgr) { + bool bFindMaterial = (blenderraysensor->mode & SENS_COLLISION_MATERIAL); + bool bXRay = (blenderraysensor->mode & SENS_RAY_XRAY); + + std::string checkname = (bFindMaterial ? blenderraysensor->matname : blenderraysensor->propname); + + // don't want to get rays of length 0.0 or so + double distance = (blenderraysensor->range < 0.01f ? 0.01f : blenderraysensor->range); + int axis = blenderraysensor->axisflag; + int mask = blenderraysensor->mask; + + gamesensor = new KX_RaySensor(eventmgr, + gameobj, + checkname, + bFindMaterial, + bXRay, + distance, + axis, + mask, + kxscene); + + } + break; + } + + case SENS_RANDOM: + { + bRandomSensor *blenderrndsensor = (bRandomSensor *)sens->data; + // some files didn't write randomsensor, avoid crash now for nullptr ptr's + if (blenderrndsensor) { + SCA_EventManager *eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); + if (eventmgr) { + int randomSeed = blenderrndsensor->seed; + if (randomSeed == 0) { + randomSeed = (int)(kxengine->GetRealTime() * 100000.0); + randomSeed ^= (intptr_t)blenderrndsensor; + } + gamesensor = new SCA_RandomSensor(eventmgr, gameobj, randomSeed); + } + } + break; + } + case SENS_MOVEMENT: + { + bMovementSensor *blendermovsensor = (bMovementSensor *)sens->data; + // some files didn't write movementsensor, avoid crash now for nullptr ptr's + if (blendermovsensor) { + SCA_EventManager *eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); + if (eventmgr) { + bool localflag = (blendermovsensor->localflag & SENS_MOVEMENT_LOCAL); + int axis = blendermovsensor->axisflag; + float threshold = blendermovsensor->threshold; + gamesensor = new KX_MovementSensor(eventmgr, gameobj, axis, localflag, threshold); + } + } + break; + } + case SENS_JOYSTICK: + { + int joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_NODEF; + + bJoystickSensor *bjoy = (bJoystickSensor *)sens->data; + + SCA_JoystickManager *eventmgr + = (SCA_JoystickManager *)logicmgr->FindEventManager(SCA_EventManager::JOY_EVENTMGR); + if (eventmgr) { + int axis = 0; + int axisf = 0; + int button = 0; + int prec = 0; + + switch (bjoy->type) { + case SENS_JOY_AXIS: + { + axis = bjoy->axis; + axisf = bjoy->axisf; + prec = bjoy->precision; + joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_AXIS; + break; + } + case SENS_JOY_BUTTON: + { + button = bjoy->button; + joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_BUTTON; + break; + } + case SENS_JOY_AXIS_SINGLE: + { + axis = bjoy->axis_single; + prec = bjoy->precision; + joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_AXIS_SINGLE; + break; + } + case SENS_JOY_SHOULDER_TRIGGER: + { + axis = bjoy->axis_single; + prec = bjoy->precision; + joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_SHOULDER_TRIGGER; + break; + } + default: + { + CM_Error("bad case statement"); + break; + } + } + gamesensor = new SCA_JoystickSensor( + eventmgr, + gameobj, + bjoy->joyindex, + joysticktype, + axis, axisf, + prec, + button, + (bjoy->flag & SENS_JOY_ANY_EVENT)); + } + else { + CM_Error("problem finding the event manager"); + } + + break; + } + default: + { + } + } + + if (gamesensor) { + gamesensor->SetExecutePriority(executePriority++); + std::string uniquename = sens->name; + uniquename += "#SENS#"; + uniqueint++; + EXP_IntValue *uniqueval = new EXP_IntValue(uniqueint); + uniquename += uniqueval->GetText(); + uniqueval->Release(); + + /* Conversion succeeded, so we can set the generic props here. */ + gamesensor->SetPulseMode(pos_pulsemode, + neg_pulsemode, + skipped_ticks); + gamesensor->SetInvert(invert); + gamesensor->SetLevel(level); + gamesensor->SetTap(tap); + gamesensor->SetName(sens->name); + gamesensor->SetLogicManager(logicmgr); + + gameobj->AddSensor(gamesensor); + + for (int i = 0; i < sens->totlinks; i++) + { + bController *linkedcont = (bController *)sens->links[i]; + if (linkedcont) { + // If the controller is deactived doesn't register it + if (!(linkedcont->flag & CONT_DEACTIVATE)) { + SCA_IController *gamecont = converter.FindGameController(linkedcont); + + if (gamecont) { + logicmgr->RegisterToSensor(gamecont, gamesensor); + } + else { + CM_Warning("sensor \"" << sens->name << "\" could not find its controller (link " + << (i + 1) << " of " << sens->totlinks << ") from object \"" << blenderobject->id.name + 2 + << "\". There has been an error converting the blender controller for the game engine, " + << "logic may be incorrect"); + } + } + } + else { + CM_Warning("sensor \"" << sens->name << "\" has lost a link to a controller (link " + << (i + 1) << " of " << sens->totlinks << ") from object \"" << blenderobject->id.name + 2 + << "\". Possible causes are partially appended objects or an error reading the file, " + << "logic may be incorrect"); + } + } + // special case: Keyboard sensor with no link + // this combination is usually used for key logging. + if (sens->type == SENS_KEYBOARD && sens->totlinks == 0) { + // Force the registration so that the sensor runs + gamesensor->IncLink(); + } + + // done with gamesensor + gamesensor->Release(); + + } + } + + sens = sens->next; + } +} + diff --git a/source/gameengine/Converter/KX_ConvertSensors.h b/source/gameengine/Converter/BL_ConvertSensors.h similarity index 92% rename from source/gameengine/Converter/KX_ConvertSensors.h rename to source/gameengine/Converter/BL_ConvertSensors.h index 2ed2c9b32269..adb7d1c372c4 100644 --- a/source/gameengine/Converter/KX_ConvertSensors.h +++ b/source/gameengine/Converter/BL_ConvertSensors.h @@ -25,7 +25,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file KX_ConvertSensors.h +/** \file BL_ConvertSensors.h * \ingroup bgeconv */ @@ -39,7 +39,7 @@ void BL_ConvertSensors(struct Object* blenderobject, class KX_KetsjiEngine* kxengine, int activeLayerBitInfo, bool isInActiveLayer, - class RAS_ICanvas* canvas, - class KX_BlenderSceneConverter* converter); + class RAS_ICanvas* canvas, + class BL_SceneConverter& converter); #endif /* __KX_CONVERTSENSORS_H__ */ diff --git a/source/gameengine/Converter/BL_Converter.cpp b/source/gameengine/Converter/BL_Converter.cpp new file mode 100644 index 000000000000..ddbad2860723 --- /dev/null +++ b/source/gameengine/Converter/BL_Converter.cpp @@ -0,0 +1,838 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Converter/BL_Converter.cpp + * \ingroup bgeconv + */ + +#ifdef _MSC_VER +# pragma warning (disable:4786) // suppress stl-MSVC debug info warning +#endif + +#include "KX_Scene.h" +#include "KX_GameObject.h" +#include "KX_Mesh.h" +#include "RAS_BucketManager.h" +#include "KX_PhysicsEngineEnums.h" +#include "KX_KetsjiEngine.h" +#include "KX_PythonInit.h" // So we can handle adding new text datablocks for Python to import +#include "KX_LibLoadStatus.h" +#include "BL_ActionData.h" +#include "BL_Converter.h" +#include "BL_SceneConverter.h" +#include "BL_BlenderDataConversion.h" +#include "BL_ConvertObjectInfo.h" +#include "BL_ActionActuator.h" +#include "KX_BlenderMaterial.h" + +#include "EXP_StringValue.h" + +#ifdef WITH_PYTHON +# include "Texture.h" // For FreeAllTextures. +#endif // WITH_PYTHON + +// This list includes only data type definitions +#include "DNA_scene_types.h" +#include "BKE_main.h" + +extern "C" { +# include "DNA_mesh_types.h" +# include "DNA_material_types.h" +# include "BLI_blenlib.h" +# include "BLI_linklist.h" +# include "BLO_readfile.h" +# include "BKE_global.h" +# include "BKE_library.h" +# include "BKE_material.h" // BKE_material_copy +# include "BKE_mesh.h" // BKE_mesh_copy +# include "BKE_idcode.h" +# include "BKE_report.h" +} + +#include "BLI_task.h" +#include "CM_Message.h" + +#include +#include + +BL_Converter::SceneSlot::SceneSlot() = default; + +BL_Converter::SceneSlot::SceneSlot(const BL_SceneConverter& converter) +{ + Merge(converter); +} + +BL_Converter::SceneSlot::~SceneSlot() = default; + +void BL_Converter::SceneSlot::Merge(BL_Converter::SceneSlot& other) +{ + m_materials.insert(m_materials.begin(), + std::make_move_iterator(other.m_materials.begin()), + std::make_move_iterator(other.m_materials.end())); + m_meshobjects.insert(m_meshobjects.begin(), + std::make_move_iterator(other.m_meshobjects.begin()), + std::make_move_iterator(other.m_meshobjects.end())); + m_objectInfos.insert(m_objectInfos.begin(), + std::make_move_iterator(other.m_objectInfos.begin()), + std::make_move_iterator(other.m_objectInfos.end())); + m_actions.insert(m_actions.begin(), + std::make_move_iterator(other.m_actions.begin()), + std::make_move_iterator(other.m_actions.end())); +} + +void BL_Converter::SceneSlot::Merge(const BL_SceneConverter& converter) +{ + for (KX_BlenderMaterial *mat : converter.m_materials) { + m_materials.emplace_back(mat); + } + for (KX_Mesh *meshobj : converter.m_meshobjects) { + m_meshobjects.emplace_back(meshobj); + } + for (BL_ConvertObjectInfo *info : converter.m_objectInfos) { + m_objectInfos.emplace_back(info); + } + for (BL_ActionData *action : converter.m_actions) { + m_actions.emplace_back(action); + } +} + +BL_Converter::BL_Converter(Main *maggie, KX_KetsjiEngine *engine, bool alwaysUseExpandFraming, float camZoom) + :m_maggie(maggie), + m_ketsjiEngine(engine), + m_alwaysUseExpandFraming(alwaysUseExpandFraming), + m_camZoom(camZoom) +{ + BKE_main_id_tag_all(maggie, LIB_TAG_DOIT, false); // avoid re-tagging later on + m_threadinfo.m_pool = BLI_task_pool_create(engine->GetTaskScheduler(), nullptr); + + m_maggies.push_back(m_maggie); +} + +BL_Converter::~BL_Converter() +{ + // free any data that was dynamically loaded + while (!m_dynamicMaggies.empty()) { + FreeBlendFile(m_dynamicMaggies.front()); + } + + /* Thread infos like mutex must be freed after FreeBlendFile function. + Because it needs to lock the mutex, even if there's no active task when it's + in the scene converter destructor. */ + BLI_task_pool_free(m_threadinfo.m_pool); +} + +Scene *BL_Converter::GetBlenderSceneForName(const std::string &name) +{ + for (Main *maggie : m_maggies) { + Scene *sce = (Scene *)BLI_findstring(&maggie->scene, name.c_str(), offsetof(ID, name) + 2); + if (sce) { + return sce; + } + } + + return nullptr; +} + +EXP_ListValue *BL_Converter::GetInactiveSceneNames() +{ + EXP_ListValue *list = new EXP_ListValue(); + + for (Scene *sce = (Scene *)m_maggie->scene.first; sce; sce = (Scene *)sce->id.next) { + const char *name = sce->id.name + 2; + if (m_ketsjiEngine->CurrentScenes()->FindValue(name)) { + continue; + } + EXP_StringValue *item = new EXP_StringValue(name, name); + list->Add(item); + } + + return list; +} + +void BL_Converter::ConvertScene(KX_Scene *scene) +{ + BL_SceneConverter converter(scene, BL_Resource::Library(m_maggie)); + ConvertScene(converter, false, true); + PostConvertScene(converter); + m_sceneSlots.emplace(scene, converter); + ReloadShaders(scene); +} + +void BL_Converter::ConvertScene(BL_SceneConverter& converter, bool libloading, bool actions) +{ + KX_Scene *scene = converter.GetScene(); + + BL_ConvertBlenderObjects( + m_maggie, + scene, + m_ketsjiEngine, + m_ketsjiEngine->GetRasterizer(), + m_ketsjiEngine->GetCanvas(), + converter, + m_alwaysUseExpandFraming, + m_camZoom, + libloading); + + // Handle actions. + if (actions) { + BL_ConvertActions(scene, m_maggie, converter); + } +} + +void BL_Converter::PostConvertScene(const BL_SceneConverter& converter) +{ + BL_PostConvertBlenderObjects(converter.GetScene(), converter); +} + +void BL_Converter::RemoveScene(KX_Scene *scene) +{ +#ifdef WITH_PYTHON + Texture::FreeAllTextures(scene); +#endif // WITH_PYTHON + + /* Delete the meshes as some one of them depends to the data owned by the scene + * e.g the display array bucket owned by the meshes and needed to be unregistered + * from the bucket manager in the scene. + */ + SceneSlot& sceneSlot = m_sceneSlots[scene]; + sceneSlot.m_meshobjects.clear(); + + // Delete the scene. + scene->Release(); + + m_sceneSlots.erase(scene); +} + +void BL_Converter::RegisterMesh(KX_Scene *scene, KX_Mesh *mesh) +{ + scene->GetLogicManager()->RegisterMeshName(mesh->GetName(), mesh); + m_sceneSlots[scene].m_meshobjects.emplace_back(mesh); +} + +void BL_Converter::UnregisterMesh(KX_Scene *scene, KX_Mesh *mesh) +{ + scene->GetLogicManager()->UnregisterMeshName(mesh->GetName(), mesh); + + std::array *, 2> objLists{{scene->GetObjectList(), scene->GetInactiveList()}}; + + for (EXP_ListValue *list : objLists) { + for (KX_GameObject *gameobj : list) { + for (KX_Mesh *objmesh : gameobj->GetMeshList()) { + if (objmesh == mesh) { + gameobj->RemoveMeshes(); + break; + } + } + } + } + + UniquePtrList& meshes = m_sceneSlots[scene].m_meshobjects; + UniquePtrList::iterator it = std::find_if(meshes.begin(), meshes.end(), + [mesh](std::unique_ptr& item){ return (mesh == item.get()); }); + + if (it != meshes.end()) { + meshes.erase(it); + } +} + +Main *BL_Converter::CreateLibrary(const std::string& path) +{ + Main *maggie = BKE_main_new(); + strncpy(maggie->name, path.c_str(), sizeof(maggie->name) - 1); + m_dynamicMaggies.push_back(maggie); + + return maggie; +} + +bool BL_Converter::ExistLibrary(const std::string& path) const +{ + for (Main *maggie : m_dynamicMaggies) { + if (BLI_path_cmp(maggie->name, path.c_str()) == 0) { + return true; + } + } + + return false; +} + +std::vector BL_Converter::GetLibraryNames() const +{ + std::vector names; + for (Main *maggie : m_dynamicMaggies) { + names.push_back(maggie->name); + } + + return names; +} + +void BL_Converter::ProcessScheduledLibraries() +{ + m_threadinfo.m_mutex.Lock(); + const std::vector mergeQueue = m_mergequeue; + m_mergequeue.clear(); + m_threadinfo.m_mutex.Unlock(); + + for (KX_LibLoadStatus *libload : mergeQueue) { + KX_Scene *mergeScene = libload->GetMergeScene(); + std::vector& converters = libload->GetSceneConverters(); + for (const BL_SceneConverter& converter : converters) { + MergeScene(mergeScene, converter); + } + + libload->Finish(); + } + + for (Main *maggie : m_freeQueue) { + FreeBlendFileData(maggie); + } + m_freeQueue.clear(); +} + +void BL_Converter::FinalizeAsyncLoads() +{ + // Finish all loading libraries. + BLI_task_pool_work_and_wait(m_threadinfo.m_pool); + // Merge all libraries data in the current scene, to avoid memory leak of unmerged scenes. + ProcessScheduledLibraries(); +} + +void BL_Converter::AddScenesToMergeQueue(KX_LibLoadStatus *status) +{ + m_threadinfo.m_mutex.Lock(); + m_mergequeue.push_back(status); + m_threadinfo.m_mutex.Unlock(); +} + +void BL_Converter::AsyncConvertTask(TaskPool *pool, void *ptr, int UNUSED(threadid)) +{ + KX_LibLoadStatus *status = static_cast(ptr); + BL_Converter *converter = status->GetConverter(); + + std::vector& converters = status->GetSceneConverters(); + for (BL_SceneConverter& sceneConverter : converters) { + converter->ConvertScene(sceneConverter, true, false); + status->AddProgress((1.0f / converters.size()) * 0.9f); // We'll call conversion 90% and merging 10% for now + } + + status->GetConverter()->AddScenesToMergeQueue(status); +} + +Main *BL_Converter::GetLibraryPath(const std::string& path) +{ + for (Main *maggie : m_dynamicMaggies) { + if (BLI_path_cmp(maggie->name, path.c_str()) == 0) { + return maggie; + } + } + + return nullptr; +} + +KX_LibLoadStatus *BL_Converter::LinkBlendFileMemory(void *data, int length, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options) +{ + BlendHandle *blendlib = BLO_blendhandle_from_memory(data, length); + + // Error checking is done in LinkBlendFile + return LinkBlendFile(blendlib, path, group, scene_merge, err_str, options); +} + +KX_LibLoadStatus *BL_Converter::LinkBlendFilePath(const char *filepath, char *group, KX_Scene *scene_merge, char **err_str, short options) +{ + BlendHandle *blendlib = BLO_blendhandle_from_file(filepath, nullptr); + + // Error checking is done in LinkBlendFile + return LinkBlendFile(blendlib, filepath, group, scene_merge, err_str, options); +} + +static void load_datablocks(Main *main_tmp, BlendHandle *blendlib, const char *path, int idcode) +{ + LinkNode *names = nullptr; + + int totnames_dummy; + names = BLO_blendhandle_get_datablock_names(blendlib, idcode, &totnames_dummy); + + int i = 0; + LinkNode *n = names; + while (n) { + BLO_library_link_named_part(main_tmp, &blendlib, idcode, (char *)n->link); + n = (LinkNode *)n->next; + i++; + } + BLI_linklist_free(names, free); // free linklist *and* each node's data +} + +KX_LibLoadStatus *BL_Converter::LinkBlendFile(BlendHandle *blendlib, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options) +{ + const int idcode = BKE_idcode_from_name(group); + static char err_local[255]; + + // only scene and mesh supported right now + if (!ELEM(idcode, ID_SCE, ID_ME, ID_AC)) { + snprintf(err_local, sizeof(err_local), "invalid ID type given \"%s\"\n", group); + *err_str = err_local; + BLO_blendhandle_close(blendlib); + return nullptr; + } + + if (ExistLibrary(path)) { + snprintf(err_local, sizeof(err_local), "blend file already open \"%s\"\n", path); + *err_str = err_local; + BLO_blendhandle_close(blendlib); + return nullptr; + } + + if (blendlib == nullptr) { + snprintf(err_local, sizeof(err_local), "could not open blendfile \"%s\"\n", path); + *err_str = err_local; + return nullptr; + } + + Main *main_newlib = BKE_main_new(); + + ReportList reports; + BKE_reports_init(&reports, RPT_STORE); + + // Created only for linking, then freed. + Main *main_tmp = BLO_library_link_begin(main_newlib, &blendlib, path); + load_datablocks(main_tmp, blendlib, path, idcode); + + // In case of scene, optionally link texts and actions. + if (idcode == ID_SCE) { + if (options & LIB_LOAD_LOAD_SCRIPTS) { + load_datablocks(main_tmp, blendlib, path, ID_TXT); + } + if (options & LIB_LOAD_LOAD_ACTIONS) { + load_datablocks(main_tmp, blendlib, path, ID_AC); + } + } + + // Don't need any special options. + const short flag = 0; + BLO_library_link_end(main_tmp, &blendlib, flag, nullptr, nullptr); + BLO_blendhandle_close(blendlib); + + BKE_reports_clear(&reports); + + BLI_strncpy(main_newlib->name, path, sizeof(main_newlib->name)); + + // Debug data to load. + if (options & LIB_LOAD_VERBOSE) { + if (idcode == ID_AC || (options & LIB_LOAD_LOAD_ACTIONS && idcode == ID_SCE)) { + for (bAction *act = (bAction *)main_newlib->action.first; act; act = (bAction *)act->id.next) { + CM_Debug("action name: " << act->id.name + 2); + } + } + if (ELEM(idcode, ID_ME, ID_SCE)) { + for (Mesh *mesh = (Mesh *)main_newlib->mesh.first; mesh; mesh = (Mesh *)mesh->id.next) { + CM_Debug("mesh name: " << mesh->id.name + 2); + } + } + if (idcode == ID_SCE) { + for (Scene *bscene = (Scene *)main_newlib->scene.first; bscene; bscene = (Scene *)bscene->id.next) { + CM_Debug("scene name: " << bscene->id.name + 2); + } + } + } + + // Linking done. + + KX_LibLoadStatus *status = new KX_LibLoadStatus(this, m_ketsjiEngine, scene_merge, path); + + const BL_Resource::Library libraryId(main_newlib); + + switch (idcode) { + case ID_ME: + { + BL_SceneConverter sceneConverter(scene_merge, libraryId); + // Convert all new meshes into BGE meshes + for (Mesh *mesh = (Mesh *)main_newlib->mesh.first; mesh; mesh = (Mesh *)mesh->id.next) { + BL_ConvertMesh((Mesh *)mesh, nullptr, scene_merge, sceneConverter); + } + + // Merge the meshes and materials in the targeted scene. + MergeSceneData(scene_merge, sceneConverter); + // Load shaders for new created materials. + ReloadShaders(scene_merge); + break; + } + case ID_AC: + { + BL_SceneConverter sceneConverter(scene_merge, libraryId); + // Convert all actions and register. + BL_ConvertActions(scene_merge, main_newlib, sceneConverter); + // Merge the actions in the targeted scene. + MergeSceneData(scene_merge, sceneConverter); + break; + } + case ID_SCE: + { + // Merge all new linked scenes into the existing one + + if (options & LIB_LOAD_LOAD_SCRIPTS) { +#ifdef WITH_PYTHON + // Handle any text datablocks + addImportMain(main_newlib); +#endif + } + + /** Actions aren't owned by scenes, to merge them in the targeted scene, + * a global scene converter is created and register every action, then this + * converter is merged into the targeted scene. + */ + if (options & LIB_LOAD_LOAD_ACTIONS) { + BL_SceneConverter sceneConverter(scene_merge, libraryId); + // Convert all actions and register. + BL_ConvertActions(scene_merge, main_newlib, sceneConverter); + // Merge the actions in the targeted scene. + MergeSceneData(scene_merge, sceneConverter); + } + + for (Scene *bscene = (Scene *)main_newlib->scene.first; bscene; bscene = (Scene *)bscene->id.next) { + KX_Scene *scene = m_ketsjiEngine->CreateScene(bscene); + + // Schedule conversion and merge. + if (options & LIB_LOAD_ASYNC) { + status->AddSceneConverter(scene, libraryId); + } + // Or proceed direct conversion and merge. + else { + BL_SceneConverter sceneConverter(scene, libraryId); + ConvertScene(sceneConverter, true, false); + MergeScene(scene_merge, sceneConverter); + } + } + break; + } + } + + if (options & LIB_LOAD_ASYNC) { + BLI_task_pool_push(m_threadinfo.m_pool, AsyncConvertTask, (void *)status, false, TASK_PRIORITY_LOW); + } + else { + status->Finish(); + } + + // Register new library. + m_dynamicMaggies.push_back(main_newlib); + m_maggies.push_back(main_newlib); + + // Register associated KX_LibLoadStatus. + m_libloadStatus[main_newlib].reset(status); + + return status; +} + +bool BL_Converter::FreeBlendFileData(Main *maggie) +{ + // Indentifier used to recognize ressources of this library. + const BL_Resource::Library libraryId(maggie); + + KX_LibLoadStatus *status = m_libloadStatus[maggie].get(); + // If the given library is currently in loading, we do nothing. + m_threadinfo.m_mutex.Lock(); + const bool finished = status->IsFinished(); + m_threadinfo.m_mutex.Unlock(); + + if (!finished) { + CM_Error("Library (" << maggie->name << ") is currently being loaded asynchronously, and cannot be freed until this process is done"); + return false; + } + + // For each scene try to remove any usage of ressources from the library. + for (KX_Scene *scene : m_ketsjiEngine->CurrentScenes()) { + // Both list containing all the scene objects. + std::array *, 2> allObjects{{scene->GetObjectList(), scene->GetInactiveList()}}; + + for (EXP_ListValue *objectList : allObjects) { + for (KX_GameObject *gameobj : objectList) { + BL_ConvertObjectInfo *info = gameobj->GetConvertObjectInfo(); + // Object as default camera are not linked to a blender resource. + if (!info) { + continue; + } + + // Free object directly depending on blender object of the library. + if (info->Belong(libraryId)) { + scene->DelayedRemoveObject(gameobj); + } + // Else try to remove used ressource (e.g actions, meshes, materials...). + else { + gameobj->RemoveRessources(libraryId); + } + } + } + + scene->RemoveEuthanasyObjects(); + } + + // Free ressources belonging to the library and unregister them. + for (auto& pair : m_sceneSlots) { + KX_Scene *scene = pair.first; + SCA_LogicManager *logicmgr = scene->GetLogicManager(); + SceneSlot& sceneSlot = pair.second; + + // Free meshes. + for (UniquePtrList::iterator it = sceneSlot.m_meshobjects.begin(); it != sceneSlot.m_meshobjects.end(); ) { + KX_Mesh *mesh = it->get(); + if (mesh->Belong(libraryId)) { + logicmgr->UnregisterMesh(mesh); + it = sceneSlot.m_meshobjects.erase(it); + } + else { + ++it; + } + } + + // Free materials. + for (UniquePtrList::iterator it = sceneSlot.m_materials.begin(); it != sceneSlot.m_materials.end(); ) { + KX_BlenderMaterial *mat = it->get(); + if (mat->Belong(libraryId)) { + scene->GetBucketManager()->RemoveMaterial(mat); + it = sceneSlot.m_materials.erase(it); + } + else { + ++it; + } + } + + // Free actions. + for (UniquePtrList::iterator it = sceneSlot.m_actions.begin(); it != sceneSlot.m_actions.end(); ) { + BL_ActionData *act = it->get(); + if (act->Belong(libraryId)) { + logicmgr->UnregisterAction(act); + it = sceneSlot.m_actions.erase(it); + } + else { + ++it; + } + } + + // Free object infos. + for (UniquePtrList::iterator it = sceneSlot.m_objectInfos.begin(); it != sceneSlot.m_objectInfos.end(); ) { + BL_ConvertObjectInfo *info = it->get(); + if (info->Belong(libraryId)) { + it = sceneSlot.m_objectInfos.erase(it); + } + else { + ++it; + } + } + + // Reload materials cause they used lamps removed now. + scene->GetBucketManager()->ReloadMaterials(); + } + + // Remove and destruct the KX_LibLoadStatus associated to the just free library. + m_libloadStatus.erase(maggie); + + // Actual free of the blender library. + FreeBlendFile(maggie); + + return true; +} + +void BL_Converter::FreeBlendFile(Main *maggie) +{ +#ifdef WITH_PYTHON + /* make sure this maggie is removed from the import list if it's there + * (this operation is safe if it isn't in the list) */ + removeImportMain(maggie); +#endif + + // Remove the library from lists. + CM_ListRemoveIfFound(m_maggies, maggie); + CM_ListRemoveIfFound(m_dynamicMaggies, maggie); + + BKE_main_free(maggie); +} + +bool BL_Converter::FreeBlendFile(const std::string& path) +{ + Main *maggie = GetLibraryPath(path); + if (!maggie) { + return false; + } + + // Delay library free in ProcessScheduledLibraries. + m_freeQueue.push_back(maggie); + return true; +} + +void BL_Converter::MergeSceneData(KX_Scene *to, const BL_SceneConverter& converter) +{ + for (KX_Mesh *mesh : converter.m_meshobjects) { + mesh->ReplaceScene(to); + } + + // Do this after lights are available (scene merged) so materials can use the lights in shaders. + for (KX_BlenderMaterial *mat : converter.m_materials) { + mat->ReplaceScene(to); + } + + m_sceneSlots[to].Merge(converter); +} + +void BL_Converter::MergeScene(KX_Scene *to, const BL_SceneConverter& converter) +{ + PostConvertScene(converter); + + MergeSceneData(to, converter); + + KX_Scene *from = converter.GetScene(); + to->MergeScene(from); + + ReloadShaders(to); + + delete from; +} + +void BL_Converter::ReloadShaders(KX_Scene *scene) +{ + for (std::unique_ptr& mat : m_sceneSlots[scene].m_materials) { + mat->ReloadMaterial(); + } + + KX_WorldInfo *world = scene->GetWorldInfo(); + if (world) { + world->ReloadMaterial(); + } +} + +void BL_Converter::ReloadShaders(const BL_SceneConverter& converter) +{ + for (KX_BlenderMaterial *mat : converter.m_materials) { + mat->ReloadMaterial(); + } +} + +/** This function merges a mesh from the current scene into another main + * it does not convert */ +KX_Mesh *BL_Converter::ConvertMeshSpecial(KX_Scene *kx_scene, Main *maggie, const std::string& name) +{ + Main *from_maggie; + ID *me = nullptr; + for (Main *main : m_maggies) { + me = static_cast(BLI_findstring(&main->mesh, name.c_str(), offsetof(ID, name) + 2)); + if (me) { + from_maggie = main; + break; + } + } + + if (me == nullptr) { + CM_Error("could not be found \"" << name << "\""); + return nullptr; + } + + // Watch this!, if its used in the original scene can cause big troubles + if (me->us > 0) { +#ifdef DEBUG + CM_Debug("mesh has a user \"" << name << "\""); +#endif // DEBUG + me = (ID *)BKE_mesh_copy(from_maggie, (Mesh *)me); + id_us_min(me); + } + BLI_remlink(&from_maggie->mesh, me); // even if we made the copy it needs to be removed + BLI_addtail(&maggie->mesh, me); + + // Must copy the materials this uses else we cant free them + { + Mesh *mesh = (Mesh *)me; + + // ensure all materials are tagged + for (int i = 0; i < mesh->totcol; i++) { + if (mesh->mat[i]) { + mesh->mat[i]->id.tag &= ~LIB_TAG_DOIT; + } + } + + for (int i = 0; i < mesh->totcol; i++) { + Material *mat_old = mesh->mat[i]; + + // if its tagged its a replaced material + if (mat_old && (mat_old->id.tag & LIB_TAG_DOIT) == 0) { + Material *mat_new = BKE_material_copy(from_maggie, mat_old); + + mat_new->id.tag |= LIB_TAG_DOIT; + id_us_min(&mat_old->id); + + BLI_remlink(&from_maggie->mat, mat_new); // BKE_material_copy uses G.main, and there is no BKE_material_copy_ex + BLI_addtail(&maggie->mat, mat_new); + + mesh->mat[i] = mat_new; + + // the same material may be used twice + for (int j = i + 1; j < mesh->totcol; j++) { + if (mesh->mat[j] == mat_old) { + mesh->mat[j] = mat_new; + id_us_plus(&mat_new->id); + id_us_min(&mat_old->id); + } + } + } + } + } + + BL_SceneConverter sceneConverter(kx_scene, BL_Resource::Library(maggie)); + + KX_Mesh *meshobj = BL_ConvertMesh((Mesh *)me, nullptr, kx_scene, sceneConverter); + + MergeSceneData(kx_scene, sceneConverter); + ReloadShaders(sceneConverter); + + return meshobj; +} + +void BL_Converter::PrintStats() +{ + CM_Message("BGE STATS"); + CM_Message(std::endl << "Assets:"); + + unsigned int nummat = 0; + unsigned int nummesh = 0; + unsigned int numacts = 0; + + for (const auto& pair : m_sceneSlots) { + KX_Scene *scene = pair.first; + const SceneSlot& sceneSlot = pair.second; + + nummat += sceneSlot.m_materials.size(); + nummesh += sceneSlot.m_meshobjects.size(); + numacts += sceneSlot.m_actions.size(); + + CM_Message("\tscene: " << scene->GetName()) + CM_Message("\t\t materials: " << sceneSlot.m_materials.size()); + CM_Message("\t\t meshes: " << sceneSlot.m_meshobjects.size()); + CM_Message("\t\t actions: " << sceneSlot.m_actions.size()); + } + + CM_Message(std::endl << "Total:"); + CM_Message("\t scenes: " << m_sceneSlots.size()); + CM_Message("\t materials: " << nummat); + CM_Message("\t meshes: " << nummesh); + CM_Message("\t actions: " << numacts); +} diff --git a/source/gameengine/Converter/BL_Converter.h b/source/gameengine/Converter/BL_Converter.h new file mode 100644 index 000000000000..5ed244ef0d68 --- /dev/null +++ b/source/gameengine/Converter/BL_Converter.h @@ -0,0 +1,217 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file BL_Converter.h + * \ingroup bgeconv + */ + +#ifndef __KX_BLENDERCONVERTER_H__ +#define __KX_BLENDERCONVERTER_H__ + +#include +#include + +#ifdef _MSC_VER // MSVC doesn't support incomplete type in std::unique_ptr. +# include "KX_BlenderMaterial.h" +# include "KX_Mesh.h" +# include "BL_ConvertObjectInfo.h" +# include "BL_ScalarInterpolator.h" +# include "BL_ActionData.h" +#endif + +#include "BL_SceneConverter.h" + +#include "CM_Thread.h" + +class EXP_StringValue; +class BL_SceneConverter; +class BL_ConvertObjectInfo; +class KX_KetsjiEngine; +class KX_LibLoadStatus; +class KX_BlenderMaterial; +class SCA_IActuator; +class SCA_IController; +class KX_Mesh; +struct Main; +struct BlendHandle; +struct Mesh; +struct Scene; +struct Material; +struct bAction; +struct bActuator; +struct bController; +struct TaskPool; + +template +using UniquePtrList = std::vector >; + +class BL_Converter +{ +private: + class SceneSlot + { + public: + UniquePtrList m_materials; + UniquePtrList m_meshobjects; + UniquePtrList m_actions; + UniquePtrList m_objectInfos; + + SceneSlot(); + SceneSlot(const BL_SceneConverter& converter); + ~SceneSlot(); + + void Merge(SceneSlot& other); + void Merge(const BL_SceneConverter& converter); + }; + + std::map m_sceneSlots; + + struct ThreadInfo { + TaskPool *m_pool; + CM_ThreadMutex m_mutex; + } m_threadinfo; + + /// List of loaded libraries to merge. + std::vector m_mergequeue; + /// List of libraries to free. + std::vector
m_freeQueue; + + /// Blender current maggie at game start. + Main *m_maggie; + /// Libloaded maggies. + std::vector
m_dynamicMaggies; + /// All maggies, original and loaded. + std::vector
m_maggies; + /// Loaded library status associated to library. + std::unordered_map
> m_libloadStatus; + + KX_KetsjiEngine *m_ketsjiEngine; + bool m_alwaysUseExpandFraming; + float m_camZoom; + + /// Partially convert a potential libloaded scene. + void ConvertScene(BL_SceneConverter& converter, bool libloading, bool actions); + + /** Convert all scene data that can't in a separate thread such as python components. + * \param converter The scene convert to finalize. + */ + void PostConvertScene(const BL_SceneConverter& converter); + + /** Merge all data contained in the scene converter to the scene slot of + * the destination scene and update the data to use the destination scene. + * \param to The destination scene. + * \param converter The scene converted of the data to merge. + */ + void MergeSceneData(KX_Scene *to, const BL_SceneConverter& converter); + + /** Complete process of scene merging: + * - post convert + * - merge data + * - merge scene (KX_Scene::MergeScene) + * - finalize data + */ + void MergeScene(KX_Scene *to, const BL_SceneConverter& converter); + + /** Regenerate material shader after a converting or merging a scene + * depending on all the lights into the destination scene. + */ + void ReloadShaders(KX_Scene *scene); + /// Regenerate shaders of material in given scene converter, used when creating mesh. + void ReloadShaders(const BL_SceneConverter& converter); + + /// Delay library merging to ProcessScheduledLibraries. + void AddScenesToMergeQueue(KX_LibLoadStatus *status); + + /** Asynchronously convert scenes from a library. + * \param ptr Pointer to the library status. + */ + static void AsyncConvertTask(TaskPool *pool, void *ptr, int UNUSED(threadid)); + + Main *GetLibraryPath(const std::string& path); + + KX_LibLoadStatus *LinkBlendFile(BlendHandle *blendlib, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options); + + /// Free blend file and remove data from merged scene. + bool FreeBlendFileData(Main *maggie); + /// Free blend file and remove library from internal lists. + void FreeBlendFile(Main *maggie); + +public: + BL_Converter(Main *maggie, KX_KetsjiEngine *engine, bool alwaysUseExpandFraming, float camZoom); + virtual ~BL_Converter(); + + /// Fully convert a non-libloaded scene. + void ConvertScene(KX_Scene *scene); + + /** This function removes all entities stored in the converter for that scene + * It should be used instead of direct delete scene + * Note that there was some provision for sharing entities (meshes...) between + * scenes but that is now disabled so all scene will have their own copy + * and we can delete them here. + * \param scene The scene to clean. + */ + void RemoveScene(KX_Scene *scene); + + + /// Dynamically register mesh created after conversion. + void RegisterMesh(KX_Scene *scene, KX_Mesh *mesh); + void UnregisterMesh(KX_Scene *scene, KX_Mesh *mesh); + + Scene *GetBlenderSceneForName(const std::string& name); + EXP_ListValue *GetInactiveSceneNames(); + + /// Return a new empty library of name path. + Main *CreateLibrary(const std::string& path); + bool ExistLibrary(const std::string& path) const; + std::vector GetLibraryNames() const; + + KX_LibLoadStatus *LinkBlendFileMemory(void *data, int length, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options); + KX_LibLoadStatus *LinkBlendFilePath(const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options); + + /// Register library to free by name. + bool FreeBlendFile(const std::string& path); + + KX_Mesh *ConvertMeshSpecial(KX_Scene *kx_scene, Main *maggie, const std::string& name); + + /// Merge scheduled loaded libraries and remove scheduled libraries. + void ProcessScheduledLibraries(); + /// Wait until all libraries are loaded. + void FinalizeAsyncLoads(); + + void PrintStats(); + + // LibLoad Options. + enum + { + LIB_LOAD_LOAD_ACTIONS = 1, + LIB_LOAD_VERBOSE = 2, + LIB_LOAD_LOAD_SCRIPTS = 4, + LIB_LOAD_ASYNC = 8, + }; +}; + +#endif // __KX_BLENDERCONVERTER_H__ diff --git a/source/gameengine/Converter/BL_DeformableGameObject.cpp b/source/gameengine/Converter/BL_DeformableGameObject.cpp deleted file mode 100644 index e78debe1ea94..000000000000 --- a/source/gameengine/Converter/BL_DeformableGameObject.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Converter/BL_DeformableGameObject.cpp - * \ingroup bgeconv - */ - - -#include "BL_DeformableGameObject.h" -#include "BL_ShapeDeformer.h" -#include "BL_ShapeActionActuator.h" -#include "RAS_MaterialBucket.h" - - -BL_DeformableGameObject::~BL_DeformableGameObject() -{ - if (m_pDeformer) - delete m_pDeformer; // __NLA : Temporary until we decide where to put this -} - -void BL_DeformableGameObject::ProcessReplica() -{ - KX_GameObject::ProcessReplica(); - - if (m_pDeformer) - m_pDeformer= (BL_MeshDeformer*)m_pDeformer->GetReplica(); -} - -CValue* BL_DeformableGameObject::GetReplica() -{ - - BL_DeformableGameObject* replica = new BL_DeformableGameObject(*this);//m_float,GetName()); - replica->ProcessReplica(); - return replica; -} - -bool BL_DeformableGameObject::SetActiveAction(BL_ShapeActionActuator *act, short priority, double curtime) -{ - if (curtime != m_lastframe) { - m_activePriority = 9999; - m_lastframe= curtime; - m_activeAct = NULL; - } - - if (priority<=m_activePriority) - { - if (m_activeAct && (m_activeAct!=act)) - m_activeAct->SetBlendTime(0.0f); /* Reset the blend timer */ - m_activeAct = act; - m_activePriority = priority; - m_lastframe = curtime; - - return true; - } - else { - act->SetBlendTime(0.0f); - return false; - } -} - -bool BL_DeformableGameObject::GetShape(vector &shape) -{ - shape.clear(); - BL_ShapeDeformer* shape_deformer = dynamic_cast(m_pDeformer); - if (shape_deformer) - { - // this check is normally superfluous: a shape deformer can only be created if the mesh - // has relative keys - Key* key = shape_deformer->GetKey(); - if (key && key->type==KEY_RELATIVE) - { - KeyBlock *kb; - for (kb = (KeyBlock *)key->block.first; kb; kb = (KeyBlock *)kb->next) - { - shape.push_back(kb->curval); - } - } - } - return !shape.empty(); -} - -void BL_DeformableGameObject::SetDeformer(class RAS_Deformer* deformer) -{ - m_pDeformer = deformer; - - SG_QList::iterator mit(m_meshSlots); - for (mit.begin(); !mit.end(); ++mit) - { - (*mit)->SetDeformer(deformer); - } -} diff --git a/source/gameengine/Converter/BL_DeformableGameObject.h b/source/gameengine/Converter/BL_DeformableGameObject.h deleted file mode 100644 index 6a97e57e4779..000000000000 --- a/source/gameengine/Converter/BL_DeformableGameObject.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file BL_DeformableGameObject.h - * \ingroup bgeconv - */ - -#ifndef __BL_DEFORMABLEGAMEOBJECT_H__ -#define __BL_DEFORMABLEGAMEOBJECT_H__ - -#ifdef _MSC_VER -# pragma warning (disable:4786) // get rid of stupid stl-visual compiler debug warning -#endif - -#include "DNA_mesh_types.h" -#include "KX_GameObject.h" -#include "BL_MeshDeformer.h" -#include "KX_SoftBodyDeformer.h" -#include - -class BL_ShapeActionActuator; -struct Key; - -class BL_DeformableGameObject : public KX_GameObject -{ -public: - CValue* GetReplica(); - - double GetLastFrame () - { - return m_lastframe; - } - Object* GetBlendObject() - { - return m_blendobj; - } - virtual void Relink(CTR_Map*map) - { - if (m_pDeformer) - m_pDeformer->Relink (map); - KX_GameObject::Relink(map); - }; - void ProcessReplica(); - - BL_DeformableGameObject(Object* blendobj, void* sgReplicationInfo, SG_Callbacks callbacks) : - KX_GameObject(sgReplicationInfo,callbacks), - m_pDeformer(NULL), - m_activeAct(NULL), - m_lastframe(0.0), - m_blendobj(blendobj), - m_activePriority(9999) - { - m_isDeformable = true; - }; - virtual ~BL_DeformableGameObject(); - bool SetActiveAction(class BL_ShapeActionActuator *act, short priority, double curtime); - - bool GetShape(vector &shape); - - virtual void SetDeformer(class RAS_Deformer* deformer); - virtual class RAS_Deformer* GetDeformer() - { - return m_pDeformer; - } - -public: - -protected: - - RAS_Deformer *m_pDeformer; - - class BL_ShapeActionActuator *m_activeAct; - double m_lastframe; - Object* m_blendobj; - short m_activePriority; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_DeformableGameObject") -#endif -}; - -#endif /* __BL_DEFORMABLEGAMEOBJECT_H__ */ diff --git a/source/gameengine/Converter/BL_IpoConvert.cpp b/source/gameengine/Converter/BL_IpoConvert.cpp new file mode 100644 index 000000000000..80b1653b813b --- /dev/null +++ b/source/gameengine/Converter/BL_IpoConvert.cpp @@ -0,0 +1,436 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Converter/BL_IpoConvert.cpp + * \ingroup bgeconv + */ + +#ifdef _MSC_VER +/* don't show stl-warnings */ +# pragma warning (disable:4786) +#endif + +#include "BKE_material.h" /* give_current_material */ + +#include "KX_GameObject.h" +#include "BL_IpoConvert.h" +#include "SG_Interpolator.h" + +#include "BL_ActionData.h" +#include "BL_Converter.h" +#include "KX_Globals.h" + +#include "RAS_IMaterial.h" + +#include "DNA_object_types.h" +#include "DNA_action_types.h" +#include "DNA_anim_types.h" +#include "DNA_ipo_types.h" +#include "DNA_lamp_types.h" +#include "DNA_world_types.h" +#include "DNA_camera_types.h" +#include "DNA_material_types.h" +/* end of blender include block */ + +#include "KX_IpoController.h" +#include "KX_LightIpoSGController.h" +#include "KX_CameraIpoSGController.h" +#include "KX_WorldIpoController.h" +#include "KX_ObColorIpoSGController.h" +#include "KX_MaterialIpoController.h" + +#include "SG_Node.h" +#include "SG_Interpolator.h" + +SG_Controller *BL_CreateIPO(BL_ActionData *action, KX_GameObject *gameobj, KX_Scene *scene) +{ + KX_IpoController *ipocontr = new KX_IpoController(); + + Object *blenderobject = gameobj->GetBlenderObject(); + + ipocontr->GetIPOTransform().SetPosition(mt::vec3(blenderobject->loc)); + ipocontr->GetIPOTransform().SetEulerAngles(mt::vec3(blenderobject->rot)); + ipocontr->GetIPOTransform().SetScaling(mt::vec3(blenderobject->size)); + + const char *rotmode, *drotmode; + + switch (blenderobject->rotmode) { + case ROT_MODE_AXISANGLE: + { + rotmode = "rotation_axis_angle"; + drotmode = "delta_rotation_axis_angle"; + break; + } + case ROT_MODE_QUAT: /* XXX, this isn't working, currently only eulers are supported [#28853] */ + {rotmode = "rotation_quaternion"; + drotmode = "delta_rotation_quaternion"; + break;} + default: + { + rotmode = "rotation_euler"; + drotmode = "delta_rotation_euler"; + break; + } + } + + // For each active channel in the action add an + // interpolator to the game object. + + BL_ScalarInterpolator *interp; + + for (int i = 0; i < 3; i++) { + if ((interp = action->GetScalarInterpolator("location", i))) { + SG_Interpolator interpolator(&(ipocontr->GetIPOTransform().GetPosition()[i]), interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetIPOChannelActive(OB_LOC_X + i, true); + } + } + for (int i = 0; i < 3; i++) { + if ((interp = action->GetScalarInterpolator("delta_location", i))) { + SG_Interpolator interpolator(&(ipocontr->GetIPOTransform().GetDeltaPosition()[i]), interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetIPOChannelActive(OB_DLOC_X + i, true); + } + } + for (int i = 0; i < 3; i++) { + if ((interp = action->GetScalarInterpolator(rotmode, i))) { + SG_Interpolator interpolator(&(ipocontr->GetIPOTransform().GetEulerAngles()[i]), interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetIPOChannelActive(OB_ROT_X + i, true); + } + } + for (int i = 0; i < 3; i++) { + if ((interp = action->GetScalarInterpolator(drotmode, i))) { + SG_Interpolator interpolator(&(ipocontr->GetIPOTransform().GetDeltaEulerAngles()[i]), interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetIPOChannelActive(OB_DROT_X + i, true); + } + } + for (int i = 0; i < 3; i++) { + if ((interp = action->GetScalarInterpolator("scale", i))) { + SG_Interpolator interpolator(&(ipocontr->GetIPOTransform().GetScaling()[i]), interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetIPOChannelActive(OB_SIZE_X + i, true); + } + } + for (int i = 0; i < 3; i++) { + if ((interp = action->GetScalarInterpolator("delta_scale", i))) { + SG_Interpolator interpolator(&(ipocontr->GetIPOTransform().GetDeltaScaling()[i]), interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetIPOChannelActive(OB_DSIZE_X + i, true); + } + } + + + return ipocontr; +} + + +SG_Controller *BL_CreateObColorIPO(BL_ActionData *action, KX_GameObject *gameobj, KX_Scene *scene) +{ + KX_ObColorIpoSGController *ipocontr_obcol = nullptr; + BL_ScalarInterpolator *interp; + + for (int i = 0; i < 4; i++) { + if ((interp = action->GetScalarInterpolator("color", i))) { + if (!ipocontr_obcol) { + ipocontr_obcol = new KX_ObColorIpoSGController(); + } + SG_Interpolator interpolator(&ipocontr_obcol->m_rgba[i], interp); + ipocontr_obcol->AddInterpolator(interpolator); + } + } + + return ipocontr_obcol; +} + +SG_Controller *BL_CreateLampIPO(BL_ActionData *action, KX_GameObject *lightobj, KX_Scene *scene) +{ + KX_LightIpoSGController *ipocontr = new KX_LightIpoSGController(); + + Lamp *blenderlamp = (Lamp *)lightobj->GetBlenderObject()->data; + + ipocontr->m_energy = blenderlamp->energy; + ipocontr->m_col_rgb[0] = blenderlamp->r; + ipocontr->m_col_rgb[1] = blenderlamp->g; + ipocontr->m_col_rgb[2] = blenderlamp->b; + ipocontr->m_dist = blenderlamp->dist; + + // For each active channel in the action add an + // interpolator to the game object. + + BL_ScalarInterpolator *interp; + + if ((interp = action->GetScalarInterpolator("energy", 0))) { + SG_Interpolator interpolator(&ipocontr->m_energy, interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyEnergy(true); + } + + if ((interp = action->GetScalarInterpolator("distance", 0))) { + SG_Interpolator interpolator(&ipocontr->m_dist, interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyDist(true); + } + + for (int i = 0; i < 3; i++) { + if ((interp = action->GetScalarInterpolator("color", i))) { + SG_Interpolator interpolator(&ipocontr->m_col_rgb[i], interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyColor(true); + } + } + + return ipocontr; +} + +SG_Controller *BL_CreateCameraIPO(BL_ActionData *action, KX_GameObject *cameraobj, KX_Scene *scene) +{ + KX_CameraIpoSGController *ipocontr = new KX_CameraIpoSGController(); + + Camera *blendercamera = (Camera *)cameraobj->GetBlenderObject()->data; + + ipocontr->m_lens = blendercamera->lens; + ipocontr->m_clipstart = blendercamera->clipsta; + ipocontr->m_clipend = blendercamera->clipend; + + // For each active channel in the action add an + // interpolator to the game object. + + BL_ScalarInterpolator *interp; + + if ((interp = action->GetScalarInterpolator("lens", 0))) { + SG_Interpolator interpolator(&ipocontr->m_lens, interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyLens(true); + } + + if ((interp = action->GetScalarInterpolator("clip_start", 0))) { + SG_Interpolator interpolator(&ipocontr->m_clipstart, interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyClipStart(true); + } + + if ((interp = action->GetScalarInterpolator("clip_end", 0))) { + SG_Interpolator interpolator(&ipocontr->m_clipend, interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyClipEnd(true); + } + + return ipocontr; +} + + +SG_Controller *BL_CreateWorldIPO(BL_ActionData *action, struct World *blenderworld, KX_Scene *scene) +{ + KX_WorldIpoController *ipocontr = nullptr; + + if (blenderworld) { + // For each active channel in the action add an interpolator to the game object. + BL_ScalarInterpolator *interp; + + for (int i = 0; i < 3; i++) { + if ((interp = action->GetScalarInterpolator("ambient_color", i))) { + if (!ipocontr) { + ipocontr = new KX_WorldIpoController(); + } + SG_Interpolator interpolator(&ipocontr->m_ambi_rgb[i], interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyAmbientColor(true); + } + } + + for (int i = 0; i < 3; i++) { + if ((interp = action->GetScalarInterpolator("horizon_color", i))) { + if (!ipocontr) { + ipocontr = new KX_WorldIpoController(); + } + SG_Interpolator interpolator(&ipocontr->m_hori_rgb[i], interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyHorizonColor(true); + } + } + + for (int i = 0; i < 3; i++) { + if ((interp = action->GetScalarInterpolator("zenith_color", i))) { + if (!ipocontr) { + ipocontr = new KX_WorldIpoController(); + } + SG_Interpolator interpolator(&ipocontr->m_zeni_rgb[i], interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyZenithColor(true); + } + } + + if ((interp = action->GetScalarInterpolator("mist_settings.start", 0))) { + if (!ipocontr) { + ipocontr = new KX_WorldIpoController(); + } + SG_Interpolator interpolator(&ipocontr->m_mist_start, interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyMistStart(true); + } + + if ((interp = action->GetScalarInterpolator("mist_settings.depth", 0))) { + if (!ipocontr) { + ipocontr = new KX_WorldIpoController(); + } + SG_Interpolator interpolator(&ipocontr->m_mist_dist, interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyMistDist(true); + } + + if ((interp = action->GetScalarInterpolator("mist_settings.intensity", 0))) { + if (!ipocontr) { + ipocontr = new KX_WorldIpoController(); + } + SG_Interpolator interpolator(&ipocontr->m_mist_intensity, interp); + ipocontr->AddInterpolator(interpolator); + ipocontr->SetModifyMistIntensity(true); + } + + if (ipocontr) { + ipocontr->m_mist_start = blenderworld->miststa; + ipocontr->m_mist_dist = blenderworld->mistdist; + ipocontr->m_mist_intensity = blenderworld->misi; + ipocontr->m_hori_rgb[0] = blenderworld->horr; + ipocontr->m_hori_rgb[1] = blenderworld->horg; + ipocontr->m_hori_rgb[2] = blenderworld->horb; + ipocontr->m_ambi_rgb[0] = blenderworld->ambr; + ipocontr->m_ambi_rgb[1] = blenderworld->ambg; + ipocontr->m_ambi_rgb[2] = blenderworld->ambb; + } + } + return ipocontr; +} + +SG_Controller *BL_CreateMaterialIpo(BL_ActionData *action, + RAS_IMaterial *mat, + KX_GameObject *gameobj, + KX_Scene *scene) +{ + KX_MaterialIpoController *ipocontr = nullptr; + + BL_ScalarInterpolator *sinterp; + + for (int i = 0; i < 3; i++) { + if ((sinterp = action->GetScalarInterpolator("diffuse_color", i))) { + if (!ipocontr) { + ipocontr = new KX_MaterialIpoController(mat); + } + SG_Interpolator interpolator(&ipocontr->m_rgba[i], sinterp); + ipocontr->AddInterpolator(interpolator); + } + } + + if ((sinterp = action->GetScalarInterpolator("alpha", 0))) { + if (!ipocontr) { + ipocontr = new KX_MaterialIpoController(mat); + } + SG_Interpolator interpolator(&ipocontr->m_rgba[3], sinterp); + ipocontr->AddInterpolator(interpolator); + } + + for (int i = 0; i < 3; i++) { + if ((sinterp = action->GetScalarInterpolator("specular_color", i))) { + if (!ipocontr) { + ipocontr = new KX_MaterialIpoController(mat); + } + SG_Interpolator interpolator(&ipocontr->m_specrgb[i], sinterp); + ipocontr->AddInterpolator(interpolator); + } + } + + if ((sinterp = action->GetScalarInterpolator("specular_hardness", 0))) { + if (!ipocontr) { + ipocontr = new KX_MaterialIpoController(mat); + } + SG_Interpolator interpolator(&ipocontr->m_hard, sinterp); + ipocontr->AddInterpolator(interpolator); + } + + if ((sinterp = action->GetScalarInterpolator("specular_intensity", 0))) { + if (!ipocontr) { + ipocontr = new KX_MaterialIpoController(mat); + } + SG_Interpolator interpolator(&ipocontr->m_spec, sinterp); + ipocontr->AddInterpolator(interpolator); + } + + if ((sinterp = action->GetScalarInterpolator("diffuse_intensity", 0))) { + if (!ipocontr) { + ipocontr = new KX_MaterialIpoController(mat); + } + SG_Interpolator interpolator(&ipocontr->m_ref, sinterp); + ipocontr->AddInterpolator(interpolator); + } + + if ((sinterp = action->GetScalarInterpolator("emit", 0))) { + if (!ipocontr) { + ipocontr = new KX_MaterialIpoController(mat); + } + SG_Interpolator interpolator(&ipocontr->m_emit, sinterp); + ipocontr->AddInterpolator(interpolator); + } + + if ((sinterp = action->GetScalarInterpolator("ambient", 0))) { + if (!ipocontr) { + ipocontr = new KX_MaterialIpoController(mat); + } + SG_Interpolator interpolator(&ipocontr->m_ambient, sinterp); + ipocontr->AddInterpolator(interpolator); + } + + if ((sinterp = action->GetScalarInterpolator("specular_alpha", 0))) { + if (!ipocontr) { + ipocontr = new KX_MaterialIpoController(mat); + } + SG_Interpolator interpolator(&ipocontr->m_specAlpha, sinterp); + ipocontr->AddInterpolator(interpolator); + } + + if (ipocontr) { + Material *blendermaterial = mat->GetBlenderMaterial(); + ipocontr->m_rgba[0] = blendermaterial->r; + ipocontr->m_rgba[1] = blendermaterial->g; + ipocontr->m_rgba[2] = blendermaterial->b; + ipocontr->m_rgba[3] = blendermaterial->alpha; + + ipocontr->m_specrgb[0] = blendermaterial->specr; + ipocontr->m_specrgb[1] = blendermaterial->specg; + ipocontr->m_specrgb[2] = blendermaterial->specb; + + ipocontr->m_hard = blendermaterial->har; + ipocontr->m_spec = blendermaterial->spec; + ipocontr->m_ref = blendermaterial->ref; + ipocontr->m_emit = blendermaterial->emit; + ipocontr->m_ambient = blendermaterial->amb; + ipocontr->m_alpha = blendermaterial->alpha; + } + + return ipocontr; +} diff --git a/source/gameengine/Ketsji/KX_IpoConvert.h b/source/gameengine/Converter/BL_IpoConvert.h similarity index 67% rename from source/gameengine/Ketsji/KX_IpoConvert.h rename to source/gameengine/Converter/BL_IpoConvert.h index 6db435528114..a1b98addb668 100644 --- a/source/gameengine/Ketsji/KX_IpoConvert.h +++ b/source/gameengine/Converter/BL_IpoConvert.h @@ -25,45 +25,44 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file KX_IpoConvert.h +/** \file BL_IpoConvert.h * \ingroup bgeconv */ #ifndef __KX_IPOCONVERT_H__ #define __KX_IPOCONVERT_H__ -struct Object; -struct bAction; class SG_Controller; +class BL_ActionData; class KX_GameObject; -class KX_BlenderSceneConverter; +class KX_Scene; +class RAS_IMaterial; -SG_Controller *BL_CreateIPO(bAction *action, +SG_Controller *BL_CreateIPO(BL_ActionData *action, KX_GameObject* gameobj, - KX_BlenderSceneConverter *converter); + KX_Scene *scene); -SG_Controller *BL_CreateObColorIPO(bAction *action, +SG_Controller *BL_CreateObColorIPO(BL_ActionData *action, KX_GameObject* gameobj, - KX_BlenderSceneConverter *converter); + KX_Scene *scene); -SG_Controller *BL_CreateLampIPO(bAction *action, +SG_Controller *BL_CreateLampIPO(BL_ActionData *action, KX_GameObject* lightobj, - KX_BlenderSceneConverter *converter); + KX_Scene *scene); -SG_Controller *BL_CreateWorldIPO(bAction *action, +SG_Controller *BL_CreateWorldIPO(BL_ActionData *action, struct World *blenderworld, - KX_BlenderSceneConverter *converter); + KX_Scene *scene); -SG_Controller *BL_CreateCameraIPO(bAction *action, +SG_Controller *BL_CreateCameraIPO(BL_ActionData *action, KX_GameObject* cameraobj, - KX_BlenderSceneConverter *converter); + KX_Scene *scene); SG_Controller *BL_CreateMaterialIpo( - bAction *action, - struct Material* blendermaterial, - dword matname_hash, + BL_ActionData *action, + RAS_IMaterial *mat, KX_GameObject* gameobj, - KX_BlenderSceneConverter *converter); + KX_Scene *scene); #endif /* __KX_IPOCONVERT_H__ */ diff --git a/source/gameengine/Converter/BL_MeshDeformer.cpp b/source/gameengine/Converter/BL_MeshDeformer.cpp index 106afc9fd5d0..3c8a5b5c8f85 100644 --- a/source/gameengine/Converter/BL_MeshDeformer.cpp +++ b/source/gameengine/Converter/BL_MeshDeformer.cpp @@ -31,82 +31,62 @@ */ #ifdef _MSC_VER - /* This warning tells us about truncation of __long__ stl-generated names. - * It can occasionally cause DevStudio to have internal compiler warnings. */ +/* 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 -#include "RAS_IPolygonMaterial.h" -#include "BL_DeformableGameObject.h" +#include "RAS_IMaterial.h" +#include "RAS_DisplayArray.h" #include "BL_MeshDeformer.h" -#include "RAS_MeshObject.h" +#include "KX_GameObject.h" +#include "RAS_BoundingBoxManager.h" +#include "RAS_Mesh.h" +#include "RAS_MeshUser.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "CTR_Map.h" -#include "STR_HashedString.h" +#include #include "BLI_math.h" -bool BL_MeshDeformer::Apply(RAS_IPolyMaterial*) +void BL_MeshDeformer::Apply(RAS_DisplayArray *UNUSED(array)) { - size_t i; - // only apply once per frame if the mesh is actually modified - if (m_pMeshObject->MeshModified() && - m_lastDeformUpdate != m_gameobj->GetLastFrame()) - { - // For each material - for (list::iterator mit= m_pMeshObject->GetFirstMaterial(); - mit != m_pMeshObject->GetLastMaterial(); ++ mit) { - if (!mit->m_slots[(void*)m_gameobj]) - continue; - - RAS_MeshSlot *slot = *mit->m_slots[(void*)m_gameobj]; - RAS_MeshSlot::iterator it; - - // for each array - for (slot->begin(it); !slot->end(it); slot->next(it)) { - // For each vertex - for (i=it.startvertex; imvert[v.getOrigIndex()].co); - } + if (m_lastDeformUpdate != m_lastFrame) { + // For each display array + for (const DisplayArraySlot& slot : m_slots) { + RAS_DisplayArray *array = slot.m_displayArray; + + // For each vertex + for (unsigned int i = 0, size = array->GetVertexCount(); i < size; ++i) { + const RAS_VertexInfo& vinfo = array->GetVertexInfo(i); + array->SetPosition(i, mt::vec3_packed(m_bmesh->mvert[vinfo.GetOrigIndex()].co)); } - } - m_lastDeformUpdate = m_gameobj->GetLastFrame(); + array->NotifyUpdate(RAS_DisplayArray::POSITION_MODIFIED); + } - return true; + m_lastDeformUpdate = m_lastFrame; } - - return false; -} - -BL_MeshDeformer::~BL_MeshDeformer() -{ - if (m_transverts) - delete [] m_transverts; - if (m_transnors) - delete [] m_transnors; } -void BL_MeshDeformer::ProcessReplica() +BL_MeshDeformer::BL_MeshDeformer(KX_GameObject *gameobj, Object *obj, RAS_Mesh *meshobj) + :RAS_Deformer(meshobj), + m_bmesh((Mesh *)(obj->data)), + m_objMesh(obj), + m_gameobj(gameobj), + m_lastDeformUpdate(-1.0), + m_lastFrame(0.0) { - m_transverts = NULL; - m_transnors = NULL; - m_tvtot = 0; - m_bDynamic=false; - m_lastDeformUpdate = -1; + KX_Scene *scene = m_gameobj->GetScene(); + RAS_BoundingBoxManager *boundingBoxManager = scene->GetBoundingBoxManager(); + m_boundingBox = boundingBoxManager->CreateBoundingBox(); + // Set AABB default to mesh bounding box AABB. + m_boundingBox->CopyAabb(m_mesh->GetBoundingBox()); } -void BL_MeshDeformer::Relink(CTR_Map*map) +BL_MeshDeformer::~BL_MeshDeformer() { - void **h_obj = (*map)[m_gameobj]; - - if (h_obj) - m_gameobj = (BL_DeformableGameObject*)(*h_obj); - else - m_gameobj = NULL; } /** @@ -118,105 +98,51 @@ void BL_MeshDeformer::RecalcNormals() * gives area-weight normals which often look better anyway, and use * GL_NORMALIZE so we don't have to do per vertex normalization either * since the GPU can do it faster */ - list::iterator mit; - RAS_MeshSlot::iterator it; - size_t i; /* set vertex normals to zero */ - memset(m_transnors, 0, sizeof(float)*3*m_bmesh->totvert); - - /* add face normals to vertices. */ - for (mit = m_pMeshObject->GetFirstMaterial(); - mit != m_pMeshObject->GetLastMaterial(); ++ mit) { - if (!mit->m_slots[(void*)m_gameobj]) - continue; + std::fill(m_transnors.begin(), m_transnors.end(), mt::zero3); - RAS_MeshSlot *slot = *mit->m_slots[(void*)m_gameobj]; + for (const DisplayArraySlot& slot : m_slots) { + RAS_DisplayArray *array = slot.m_displayArray; + for (unsigned int i = 0, size = array->GetTriangleIndexCount(); i < size; i += 3) { + mt::vec3_packed co[3]; + bool flat = false; - for (slot->begin(it); !slot->end(it); slot->next(it)) { - int nvert = (int)it.array->m_type; + for (unsigned short j = 0; j < 3; ++j) { + const unsigned int index = array->GetTriangleIndex(i + j); + const RAS_VertexInfo& vinfo = array->GetVertexInfo(index); + const unsigned int origindex = vinfo.GetOrigIndex(); - for (i=0; igetOrigIndex()]; + mt::vec3_packed pnorm; + normal_tri_v3(pnorm.data, co[0].data, co[1].data, co[2].data); - n1[0] = co1[0] - co3[0]; - n1[1] = co1[1] - co3[1]; - n1[2] = co1[2] - co3[2]; + for (unsigned short j = 0; j < 3; ++j) { + const unsigned int index = array->GetTriangleIndex(i + j); - n2[0] = co2[0] - co4[0]; - n2[1] = co2[1] - co4[1]; - n2[2] = co2[2] - co4[2]; + if (flat) { + array->SetNormal(index, pnorm); } else { - n1[0] = co1[0] - co2[0]; - n2[0] = co2[0] - co3[0]; - n1[1] = co1[1] - co2[1]; - - n2[1] = co2[1] - co3[1]; - n1[2] = co1[2] - co2[2]; - n2[2] = co2[2] - co3[2]; - } - - fnor[0] = n1[1] * n2[2] - n1[2] * n2[1]; - fnor[1] = n1[2] * n2[0] - n1[0] * n2[2]; - fnor[2] = n1[0] * n2[1] - n1[1] * n2[0]; - normalize_v3(fnor); - - /* add to vertices for smooth normals */ - float *vn1 = m_transnors[v1.getOrigIndex()]; - float *vn2 = m_transnors[v2.getOrigIndex()]; - float *vn3 = m_transnors[v3.getOrigIndex()]; - - vn1[0] += fnor[0]; vn1[1] += fnor[1]; vn1[2] += fnor[2]; - vn2[0] += fnor[0]; vn2[1] += fnor[1]; vn2[2] += fnor[2]; - vn3[0] += fnor[0]; vn3[1] += fnor[1]; vn3[2] += fnor[2]; - - if (v4) { - float *vn4 = m_transnors[v4->getOrigIndex()]; - vn4[0] += fnor[0]; vn4[1] += fnor[1]; vn4[2] += fnor[2]; - } - - /* in case of flat - just assign, the vertices are split */ - if (v1.getFlag() & RAS_TexVert::FLAT) { - v1.SetNormal(fnor); - v2.SetNormal(fnor); - v3.SetNormal(fnor); - if (v4) - v4->SetNormal(fnor); + const RAS_VertexInfo& vinfo = array->GetVertexInfo(index); + const unsigned int origindex = vinfo.GetOrigIndex(); + add_v3_v3(m_transnors[origindex].data, pnorm.data); } } } } - /* assign smooth vertex normals */ - for (mit = m_pMeshObject->GetFirstMaterial(); - mit != m_pMeshObject->GetLastMaterial(); ++ mit) { - if (!mit->m_slots[(void*)m_gameobj]) - continue; - - RAS_MeshSlot *slot = *mit->m_slots[(void*)m_gameobj]; + // Assign smooth vertex normals. + for (const DisplayArraySlot& slot : m_slots) { + RAS_DisplayArray *array = slot.m_displayArray; + for (unsigned int i = 0, size = array->GetVertexCount(); i < size; ++i) { + const RAS_VertexInfo& vinfo = array->GetVertexInfo(i); - for (slot->begin(it); !slot->end(it); slot->next(it)) { - for (i=it.startvertex; iSetNormal(i, m_transnors[vinfo.GetOrigIndex()]); } } } @@ -225,14 +151,20 @@ void BL_MeshDeformer::RecalcNormals() void BL_MeshDeformer::VerifyStorage() { /* Ensure that we have the right number of verts assigned */ - if (m_tvtot!=m_bmesh->totvert) { - if (m_transverts) - delete [] m_transverts; - if (m_transnors) - delete [] m_transnors; - - m_transverts=new float[m_bmesh->totvert][3]; - m_transnors=new float[m_bmesh->totvert][3]; - m_tvtot = m_bmesh->totvert; + const unsigned int totvert = m_bmesh->totvert; + if (m_transverts.size() != totvert) { + m_transverts.resize(totvert); + m_transnors.resize(totvert); + } + + for (unsigned int v = 0; v < totvert; ++v) { + copy_v3_v3(m_transverts[v].data, m_bmesh->mvert[v].co); + normal_short_to_float_v3(m_transnors[v].data, m_bmesh->mvert[v].no); } } + +void BL_MeshDeformer::SetLastFrame(double lastFrame) +{ + m_lastFrame = lastFrame; +} + diff --git a/source/gameengine/Converter/BL_MeshDeformer.h b/source/gameengine/Converter/BL_MeshDeformer.h index 8b5fa2d5174c..a5583d097fd0 100644 --- a/source/gameengine/Converter/BL_MeshDeformer.h +++ b/source/gameengine/Converter/BL_MeshDeformer.h @@ -35,63 +35,55 @@ #include "RAS_Deformer.h" #include "DNA_object_types.h" #include "DNA_key_types.h" -#include "MT_Point3.h" -#include #ifdef _MSC_VER # pragma warning (disable:4786) /* get rid of stupid stl-visual compiler debug warning */ #endif -class BL_DeformableGameObject; +struct Object; +struct Mesh; +class KX_GameObject; +class RAS_Mesh; +class RAS_IMaterial; class BL_MeshDeformer : public RAS_Deformer { public: void VerifyStorage(); void RecalcNormals(); - virtual void Relink(CTR_Map*map); - BL_MeshDeformer(BL_DeformableGameObject *gameobj, - struct Object* obj, - class RAS_MeshObject *meshobj ): - m_pMeshObject(meshobj), - m_bmesh((struct Mesh*)(obj->data)), - m_transverts(0), - m_transnors(0), - m_objMesh(obj), - m_tvtot(0), - m_gameobj(gameobj), - m_lastDeformUpdate(-1) - {}; + + BL_MeshDeformer(KX_GameObject *gameobj, Object *obj, RAS_Mesh *meshobj); virtual ~BL_MeshDeformer(); - virtual void SetSimulatedTime(double time) {} - virtual bool Apply(class RAS_IPolyMaterial *mat); - virtual bool Update(void) { return false; } - virtual bool UpdateBuckets(void) { return false; } - virtual RAS_Deformer* GetReplica() {return NULL;} - virtual void ProcessReplica(); - struct Mesh* GetMesh() { return m_bmesh; } - virtual class RAS_MeshObject* GetRasMesh() { return m_pMeshObject; } - virtual float (* GetTransVerts(int *tot))[3] { *tot= m_tvtot; return m_transverts; } - // virtual void InitDeform(double time) {} + virtual void Apply(RAS_DisplayArray *array); + virtual bool Update() + { + return false; + } + virtual void UpdateBuckets() + { + } + Mesh *GetMesh() + { + return m_bmesh; + } + + void SetLastFrame(double lastFrame); protected: - class RAS_MeshObject* m_pMeshObject; - struct Mesh* m_bmesh; + Mesh *m_bmesh; // this is so m_transverts doesn't need to be converted // before deformation - float (*m_transverts)[3]; - float (*m_transnors)[3]; - struct Object* m_objMesh; - // -- - int m_tvtot; - BL_DeformableGameObject* m_gameobj; - double m_lastDeformUpdate; - + std::vector m_transverts; + std::vector m_transnors; + Object *m_objMesh; -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_MeshDeformer") -#endif + KX_GameObject *m_gameobj; + /// Last update frame. + double m_lastDeformUpdate; + /// Last action update frame. + double m_lastFrame; }; #endif + diff --git a/source/gameengine/Converter/BL_ModifierDeformer.cpp b/source/gameengine/Converter/BL_ModifierDeformer.cpp index 44b24927843a..515bff6aaf73 100644 --- a/source/gameengine/Converter/BL_ModifierDeformer.cpp +++ b/source/gameengine/Converter/BL_ModifierDeformer.cpp @@ -35,11 +35,13 @@ #include "MEM_guardedalloc.h" #include "BL_ModifierDeformer.h" -#include "CTR_Map.h" -#include "STR_HashedString.h" -#include "RAS_IPolygonMaterial.h" -#include "RAS_MeshObject.h" -#include "PHY_IGraphicController.h" +#include "BL_BlenderDataConversion.h" +#include +#include "RAS_IMaterial.h" +#include "RAS_MaterialBucket.h" +#include "RAS_Mesh.h" +#include "RAS_MeshUser.h" +#include "RAS_BoundingBox.h" #include "DNA_armature_types.h" #include "DNA_action_types.h" @@ -54,9 +56,8 @@ #include "BKE_action.h" #include "BKE_key.h" #include "BKE_ipo.h" -#include "MT_Point3.h" -extern "C"{ +extern "C" { #include "BKE_customdata.h" #include "BKE_DerivedMesh.h" #include "BKE_lattice.h" @@ -69,50 +70,32 @@ extern "C"{ BL_ModifierDeformer::~BL_ModifierDeformer() { if (m_dm) { - // deformedOnly is used as a user counter - if (--m_dm->deformedOnly == 0) { - m_dm->needsFree = 1; - m_dm->release(m_dm); - } + m_dm->needsFree = 1; + m_dm->release(m_dm); } -}; - -RAS_Deformer *BL_ModifierDeformer::GetReplica() -{ - BL_ModifierDeformer *result; - - result = new BL_ModifierDeformer(*this); - result->ProcessReplica(); - return result; -} - -void BL_ModifierDeformer::ProcessReplica() -{ - /* Note! - This is not inherited from PyObjectPlus */ - BL_ShapeDeformer::ProcessReplica(); - if (m_dm) - // by default try to reuse mesh, deformedOnly is used as a user count - m_dm->deformedOnly++; - // this will force an update and if the mesh cannot be reused, a new one will be created - m_lastModifierUpdate = -1; } bool BL_ModifierDeformer::HasCompatibleDeformer(Object *ob) { - if (!ob->modifiers.first) + if (!ob->modifiers.first) { return false; + } // soft body cannot use mesh modifiers - if ((ob->gameflag & OB_SOFT_BODY) != 0) + if ((ob->gameflag & OB_SOFT_BODY) != 0) { return false; - ModifierData* md; + } + ModifierData *md; for (md = (ModifierData *)ob->modifiers.first; md; md = md->next) { - if (modifier_dependsOnTime(md)) + if (modifier_dependsOnTime(md)) { continue; - if (!(md->mode & eModifierMode_Realtime)) + } + if (!(md->mode & eModifierMode_Realtime)) { continue; + } /* armature modifier are handled by SkinDeformer, not ModifierDeformer */ - if (md->type == eModifierType_Armature ) + if (md->type == eModifierType_Armature) { continue; + } return true; } return false; @@ -120,100 +103,97 @@ bool BL_ModifierDeformer::HasCompatibleDeformer(Object *ob) bool BL_ModifierDeformer::HasArmatureDeformer(Object *ob) { - if (!ob->modifiers.first) + if (!ob->modifiers.first) { return false; + } - ModifierData* md = (ModifierData*)ob->modifiers.first; - if (md->type == eModifierType_Armature ) + ModifierData *md = (ModifierData *)ob->modifiers.first; + if (md->type == eModifierType_Armature) { return true; + } return false; } -// return a deformed mesh that supports mapping (with a valid CD_ORIGINDEX layer) -struct DerivedMesh* BL_ModifierDeformer::GetPhysicsMesh() -{ - /* we need to compute the deformed mesh taking into account the current - * shape and skin deformers, we cannot just call mesh_create_derived_physics() - * because that would use the m_transvers already deformed previously by BL_ModifierDeformer::Update(), - * so restart from scratch by forcing a full update the shape/skin deformers - * (will do nothing if there is no such deformer) */ - BL_ShapeDeformer::ForceUpdate(); - BL_ShapeDeformer::Update(); - // now apply the modifiers but without those that don't support mapping - Object* blendobj = m_gameobj->GetBlendObject(); - /* hack: the modifiers require that the mesh is attached to the object - * It may not be the case here because of replace mesh actuator */ - Mesh *oldmesh = (Mesh*)blendobj->data; - blendobj->data = m_bmesh; - DerivedMesh *dm = mesh_create_derived_physics(m_scene, blendobj, m_transverts, CD_MASK_MESH); - /* restore object data */ - blendobj->data = oldmesh; - /* m_transverts is correct here (takes into account deform only modifiers) */ - /* the derived mesh returned by this function must be released by the caller !!! */ - return dm; -} - bool BL_ModifierDeformer::Update(void) { - bool bShapeUpdate = BL_ShapeDeformer::Update(); + bool bShapeUpdate = BL_ShapeDeformer::UpdateInternal(false); - if (bShapeUpdate || m_lastModifierUpdate != m_gameobj->GetLastFrame()) { + if (bShapeUpdate || m_lastModifierUpdate != m_lastFrame) { // static derived mesh are not updated - if (m_dm == NULL || m_bDynamic) { + if (m_dm == nullptr || m_bDynamic) { /* execute the modifiers */ - Object* blendobj = m_gameobj->GetBlendObject(); + Object *blendobj = m_gameobj->GetBlenderObject(); /* hack: the modifiers require that the mesh is attached to the object * It may not be the case here because of replace mesh actuator */ - Mesh *oldmesh = (Mesh*)blendobj->data; + Mesh *oldmesh = (Mesh *)blendobj->data; blendobj->data = m_bmesh; /* execute the modifiers */ - DerivedMesh *dm = mesh_create_derived_no_virtual(m_scene, blendobj, m_transverts, CD_MASK_MESH); + DerivedMesh *dm = mesh_create_derived_no_virtual(m_scene, blendobj, (float(*)[3])m_transverts.data(), CD_MASK_MESH); /* restore object data */ blendobj->data = oldmesh; - /* free the current derived mesh and replace, (dm should never be NULL) */ - if (m_dm != NULL) { - // HACK! use deformedOnly as a user counter - if (--m_dm->deformedOnly == 0) { - m_dm->needsFree = 1; - m_dm->release(m_dm); - } + /* free the current derived mesh and replace, (dm should never be nullptr) */ + if (m_dm) { + m_dm->needsFree = 1; + m_dm->release(m_dm); } m_dm = dm; // get rid of temporary data m_dm->needsFree = 0; m_dm->release(m_dm); - // HACK! use deformedOnly as a user counter - m_dm->deformedOnly = 1; DM_update_materials(m_dm, blendobj); - /* update the graphic controller */ - PHY_IGraphicController *ctrl = m_gameobj->GetGraphicController(); - if (ctrl) { - float min[3], max[3]; - INIT_MINMAX(min, max); - m_dm->getMinMax(m_dm, min, max); - ctrl->SetLocalAabb(min, max); - } - } - m_lastModifierUpdate=m_gameobj->GetLastFrame(); - bShapeUpdate = true; - int nmat = m_pMeshObject->NumMaterials(); - for (int imat=0; imatGetMeshMaterial(imat); - RAS_MeshSlot **slot = mmat->m_slots[(void*)m_gameobj]; - if (!slot || !*slot) - continue; - (*slot)->m_pDerivedMesh = m_dm; + UpdateBounds(); + UpdateTransverts(); } + m_lastModifierUpdate = m_lastFrame; + bShapeUpdate = true; } + return bShapeUpdate; } -bool BL_ModifierDeformer::Apply(RAS_IPolyMaterial *mat) +void BL_ModifierDeformer::UpdateBounds() { - if (!Update()) - return false; + float min[3], max[3]; + INIT_MINMAX(min, max); + m_dm->getMinMax(m_dm, min, max); + m_boundingBox->SetAabb(mt::vec3(min), mt::vec3(max)); +} + +void BL_ModifierDeformer::UpdateTransverts() +{ + if (!m_dm) { + return; + } + + const unsigned short nummat = m_slots.size(); + std::vector mats(nummat); + + for (unsigned short i = 0; i < nummat; ++i) { + const DisplayArraySlot& slot = m_slots[i]; + RAS_MeshMaterial *meshmat = slot.m_meshMaterial; + RAS_DisplayArray *array = slot.m_displayArray; + array->Clear(); - return true; + RAS_IMaterial *mat = meshmat->GetBucket()->GetMaterial(); + mats[i] = {array, meshmat->GetBucket(), mat->IsVisible(), mat->IsTwoSided(), mat->IsCollider(), mat->IsWire()}; + } + + BL_ConvertDerivedMeshToArray(m_dm, m_bmesh, mats, m_mesh->GetLayersInfo()); + + for (const DisplayArraySlot& slot : m_slots) { + RAS_DisplayArray *array = slot.m_displayArray; + array->NotifyUpdate(RAS_DisplayArray::SIZE_MODIFIED); + } + + // Update object's AABB. + if (m_gameobj->GetAutoUpdateBounds()) { + UpdateBounds(); + } +} + +void BL_ModifierDeformer::Apply(RAS_DisplayArray *array) +{ + Update(); } diff --git a/source/gameengine/Converter/BL_ModifierDeformer.h b/source/gameengine/Converter/BL_ModifierDeformer.h index 7de64745534e..365a129ca452 100644 --- a/source/gameengine/Converter/BL_ModifierDeformer.h +++ b/source/gameengine/Converter/BL_ModifierDeformer.h @@ -37,9 +37,8 @@ #endif #include "BL_ShapeDeformer.h" -#include "BL_DeformableGameObject.h" -#include +class RAS_Mesh; struct DerivedMesh; struct Object; @@ -49,67 +48,35 @@ class BL_ModifierDeformer : public BL_ShapeDeformer static bool HasCompatibleDeformer(Object *ob); static bool HasArmatureDeformer(Object *ob); - - BL_ModifierDeformer(BL_DeformableGameObject *gameobj, - Scene *scene, - Object *bmeshobj, - RAS_MeshObject *mesh) - : - BL_ShapeDeformer(gameobj,bmeshobj, mesh), - m_lastModifierUpdate(-1), - m_scene(scene), - m_dm(NULL) + BL_ModifierDeformer(KX_GameObject *gameobj, + Scene *scene, + Object *bmeshobj_old, + Object *bmeshobj_new, + RAS_Mesh *mesh, + BL_ArmatureObject *arma) + :BL_ShapeDeformer(gameobj, bmeshobj_old, bmeshobj_new, mesh, arma), + m_lastModifierUpdate(-1), + m_scene(scene), + m_dm(nullptr) { - m_recalcNormal = false; } - /* this second constructor is needed for making a mesh deformable on the fly. */ - BL_ModifierDeformer(BL_DeformableGameObject *gameobj, - struct Scene *scene, - struct Object *bmeshobj_old, - struct Object *bmeshobj_new, - class RAS_MeshObject *mesh, - bool release_object, - BL_ArmatureObject* arma = NULL) - : - BL_ShapeDeformer(gameobj, bmeshobj_old, bmeshobj_new, mesh, release_object, false, arma), - m_lastModifierUpdate(-1), - m_scene(scene), - m_dm(NULL) - { - /* pass */ - } - - virtual void ProcessReplica(); - virtual RAS_Deformer *GetReplica(); virtual ~BL_ModifierDeformer(); - virtual bool UseVertexArray() - { - return false; - } - bool Update (void); - bool Apply(RAS_IPolyMaterial *mat); + bool Update(); + virtual void Apply(RAS_DisplayArray *array); void ForceUpdate() { m_lastModifierUpdate = -1.0; - }; - virtual struct DerivedMesh* GetFinalMesh() - { - return m_dm; } - // The derived mesh returned by this function must be released! - virtual struct DerivedMesh* GetPhysicsMesh(); protected: - double m_lastModifierUpdate; - Scene *m_scene; - DerivedMesh *m_dm; + void UpdateBounds(); + virtual void UpdateTransverts(); - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_ModifierDeformer") -#endif + double m_lastModifierUpdate; + Scene *m_scene; + DerivedMesh *m_dm; }; #endif /* __BL_MODIFIERDEFORMER_H__ */ diff --git a/source/gameengine/Converter/BL_Resource.cpp b/source/gameengine/Converter/BL_Resource.cpp new file mode 100644 index 000000000000..c72d9a8d37c2 --- /dev/null +++ b/source/gameengine/Converter/BL_Resource.cpp @@ -0,0 +1,31 @@ +#include "BL_Resource.h" + +#include "BLI_utildefines.h" + +BL_Resource::Library::Library() + :m_id(0) +{ +} + +BL_Resource::Library::Library(Main *maggie) + :m_id((uintptr_t)maggie) +{ +} + +bool BL_Resource::Library::Valid() const +{ + return (m_id != 0); +} + +void BL_Resource::SetOwner(const Library& libraryId) +{ + // Forbid changing of library, replacing a valid library. + BLI_assert(!m_libraryId.Valid()); + + m_libraryId = libraryId; +} + +bool BL_Resource::Belong(const Library& libraryId) const +{ + return (m_libraryId == libraryId); +} diff --git a/source/gameengine/Converter/BL_Resource.h b/source/gameengine/Converter/BL_Resource.h new file mode 100644 index 000000000000..f3381d60c490 --- /dev/null +++ b/source/gameengine/Converter/BL_Resource.h @@ -0,0 +1,47 @@ +#ifndef __BL_RESOURCE_H__ +#define __BL_RESOURCE_H__ + +#include + +class BL_SceneConverter; +struct Main; + +/** Base class of resources. Used to identify the library of the resource. + */ +class BL_Resource +{ +public: + /// Opaque library identifier. + class Library + { + private: + uintptr_t m_id; + + public: + Library(); + explicit Library(Main *maggie); + + /// Return true if the identifier was constructed along an existing library. + bool Valid() const; + + inline bool operator==(const Library& other) const + { + return (m_id == other.m_id); + } + }; + +private: + /// The identifier of library owning the resource. + Library m_libraryId; + +public: + /// Initialize the library of this resource, must be called only once. + void SetOwner(const Library& libraryId); + + /** Return true if the libraryId match m_libraryId. + * Meaning the resource was converted with date from this library. + */ + bool Belong(const Library& libraryId) const; +}; + +#endif // __BL_RESOURCE_H__ diff --git a/source/gameengine/GamePlayer/ghost/GPG_System.cpp b/source/gameengine/Converter/BL_ScalarInterpolator.cpp similarity index 69% rename from source/gameengine/GamePlayer/ghost/GPG_System.cpp rename to source/gameengine/Converter/BL_ScalarInterpolator.cpp index c3e52d847352..0598a06f263c 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_System.cpp +++ b/source/gameengine/Converter/BL_ScalarInterpolator.cpp @@ -23,29 +23,30 @@ * Contributor(s): none yet. * * ***** END GPL LICENSE BLOCK ***** - * Blender Player system on GHOST. */ -/** \file gameengine/GamePlayer/ghost/GPG_System.cpp - * \ingroup player +/** \file gameengine/Converter/BL_ScalarInterpolator.cpp + * \ingroup bgeconv */ +#include "BL_ScalarInterpolator.h" -#include "GPG_System.h" -#include -#include "GHOST_ISystem.h" +extern "C" { +# include "DNA_anim_types.h" +# include "BKE_fcurve.h" +} -GPG_System::GPG_System(GHOST_ISystem* system) -: m_system(system) +BL_ScalarInterpolator::BL_ScalarInterpolator(FCurve *fcu) + :m_fcu(fcu) { - assert(m_system); } +float BL_ScalarInterpolator::GetValue(float currentTime) const +{ + return evaluate_fcurve(m_fcu, currentTime); +} -double GPG_System::GetTimeInSeconds() +FCurve *BL_ScalarInterpolator::GetFCurve() const { - GHOST_TInt64 millis = (GHOST_TInt64)m_system->getMilliSeconds(); - double time = (double)millis; - time /= 1000.0; - return time; + return m_fcu; } diff --git a/source/gameengine/GameLogic/SCA_RandomEventManager.h b/source/gameengine/Converter/BL_ScalarInterpolator.h similarity index 66% rename from source/gameengine/GameLogic/SCA_RandomEventManager.h rename to source/gameengine/Converter/BL_ScalarInterpolator.h index 2d83c5fcdca9..27ad12d4aad6 100644 --- a/source/gameengine/GameLogic/SCA_RandomEventManager.h +++ b/source/gameengine/Converter/BL_ScalarInterpolator.h @@ -25,30 +25,32 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file SCA_RandomEventManager.h - * \ingroup gamelogic - * \brief Manager for random events +/** \file BL_ScalarInterpolator.h + * \ingroup bgeconv */ -#ifndef __SCA_RANDOMEVENTMANAGER_H__ -#define __SCA_RANDOMEVENTMANAGER_H__ +#ifndef __KX_BLENDERSCALARINTERPOLATOR_H__ +#define __KX_BLENDERSCALARINTERPOLATOR_H__ + +#include "SG_ScalarInterpolator.h" -#include "SCA_EventManager.h" #include +#include -using namespace std; +struct bAction; +struct FCurve; -class SCA_RandomEventManager : public SCA_EventManager +class BL_ScalarInterpolator : public SG_ScalarInterpolator { -public: - SCA_RandomEventManager(class SCA_LogicManager* logicmgr); - - virtual void NextFrame(); +private: + FCurve *m_fcu; +public: + BL_ScalarInterpolator(FCurve *fcu); + virtual ~BL_ScalarInterpolator() = default; -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:SCA_RandomEventManager") -#endif + virtual float GetValue(float currentTime) const; + FCurve *GetFCurve() const; }; -#endif /* __SCA_RANDOMEVENTMANAGER_H__ */ +#endif /* __KX_BLENDERSCALARINTERPOLATOR_H__ */ diff --git a/source/gameengine/Converter/BL_SceneConverter.cpp b/source/gameengine/Converter/BL_SceneConverter.cpp new file mode 100644 index 000000000000..4b50f8ec1a30 --- /dev/null +++ b/source/gameengine/Converter/BL_SceneConverter.cpp @@ -0,0 +1,177 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Converter/BL_SceneConverter.cpp + * \ingroup bgeconv + */ + +#include "BL_SceneConverter.h" +#include "BL_ConvertObjectInfo.h" +#include "BL_ActionData.h" +#include "KX_GameObject.h" +#include "KX_Mesh.h" +#include "KX_BlenderMaterial.h" + +#include "CM_List.h" +#include "CM_Map.h" + +BL_SceneConverter::BL_SceneConverter(KX_Scene *scene, const BL_Resource::Library& libraryId) + :m_scene(scene), + m_libraryId(libraryId) +{ +} + +BL_SceneConverter::BL_SceneConverter(BL_SceneConverter&& other) + :m_scene(other.m_scene), + m_libraryId(other.m_libraryId), + m_materials(std::move(other.m_materials)), + m_meshobjects(std::move(other.m_meshobjects)), + m_objectInfos(std::move(other.m_objectInfos)), + m_actions(std::move(other.m_actions)), + m_objects(std::move(other.m_objects)), + m_blenderToObjectInfos(std::move(other.m_blenderToObjectInfos)), + m_map_blender_to_gameobject(std::move(other.m_map_blender_to_gameobject)), + m_map_mesh_to_gamemesh(std::move(other.m_map_mesh_to_gamemesh)), + m_map_mesh_to_polyaterial(std::move(other.m_map_mesh_to_polyaterial)), + m_map_blender_to_gameactuator(std::move(other.m_map_blender_to_gameactuator)), + m_map_blender_to_gamecontroller(std::move(other.m_map_blender_to_gamecontroller)) +{ +} + +KX_Scene *BL_SceneConverter::GetScene() const +{ + return m_scene; +} + +void BL_SceneConverter::RegisterGameObject(KX_GameObject *gameobject, Object *for_blenderobject) +{ + // only maintained while converting, freed during game runtime + m_map_blender_to_gameobject[for_blenderobject] = gameobject; + m_objects.push_back(gameobject); +} + +/** only need to run this during conversion since + * m_map_blender_to_gameobject is freed after conversion */ +void BL_SceneConverter::UnregisterGameObject(KX_GameObject *gameobject) +{ + Object *bobp = gameobject->GetBlenderObject(); + if (bobp) { + std::map::iterator it = m_map_blender_to_gameobject.find(bobp); + if (it->second == gameobject) { + // also maintain m_map_blender_to_gameobject if the gameobject + // being removed is matching the blender object + m_map_blender_to_gameobject.erase(it); + } + } + + CM_ListRemoveIfFound(m_objects, gameobject); +} + +KX_GameObject *BL_SceneConverter::FindGameObject(Object *for_blenderobject) const +{ + return CM_MapGetItemNoInsert(m_map_blender_to_gameobject, for_blenderobject); +} + +void BL_SceneConverter::RegisterGameMesh(KX_Mesh *gamemesh, Mesh *for_blendermesh) +{ + gamemesh->SetOwner(m_libraryId); + + if (for_blendermesh) { // dynamically loaded meshes we don't want to keep lookups for + m_map_mesh_to_gamemesh[for_blendermesh] = gamemesh; + } + m_meshobjects.push_back(gamemesh); +} + +KX_Mesh *BL_SceneConverter::FindGameMesh(Mesh *for_blendermesh) const +{ + return CM_MapGetItemNoInsert(m_map_mesh_to_gamemesh, for_blendermesh); +} + +void BL_SceneConverter::RegisterMaterial(KX_BlenderMaterial *blmat, Material *mat) +{ + blmat->SetOwner(m_libraryId); + + if (mat) { + m_map_mesh_to_polyaterial[mat] = blmat; + } + m_materials.push_back(blmat); +} + +KX_BlenderMaterial *BL_SceneConverter::FindMaterial(Material *mat) const +{ + return CM_MapGetItemNoInsert(m_map_mesh_to_polyaterial, mat); +} + +void BL_SceneConverter::RegisterActionData(BL_ActionData *data) +{ + data->SetOwner(m_libraryId); + m_actions.push_back(data); +} + +void BL_SceneConverter::RegisterGameActuator(SCA_IActuator *act, bActuator *for_actuator) +{ + m_map_blender_to_gameactuator[for_actuator] = act; +} + +SCA_IActuator *BL_SceneConverter::FindGameActuator(bActuator *for_actuator) const +{ + return CM_MapGetItemNoInsert(m_map_blender_to_gameactuator, for_actuator); +} + +void BL_SceneConverter::RegisterGameController(SCA_IController *cont, bController *for_controller) +{ + m_map_blender_to_gamecontroller[for_controller] = cont; +} + +SCA_IController *BL_SceneConverter::FindGameController(bController *for_controller) const +{ + return CM_MapGetItemNoInsert(m_map_blender_to_gamecontroller, for_controller); +} + +BL_ConvertObjectInfo *BL_SceneConverter::GetObjectInfo(Object *blenderobj) +{ + const auto& it = m_blenderToObjectInfos.find(blenderobj); + if (it == m_blenderToObjectInfos.end()) { + BL_ConvertObjectInfo *info = m_blenderToObjectInfos[blenderobj] = new BL_ConvertObjectInfo(blenderobj); + info->SetOwner(m_libraryId); + + m_objectInfos.push_back(info); + return info; + } + + return it->second; +} + +const std::vector &BL_SceneConverter::GetObjects() const +{ + return m_objects; +} + +const std::vector &BL_SceneConverter::GetMaterials() const +{ + return m_materials; +} diff --git a/source/gameengine/Converter/BL_SceneConverter.h b/source/gameengine/Converter/BL_SceneConverter.h new file mode 100644 index 000000000000..8849a92ef6ff --- /dev/null +++ b/source/gameengine/Converter/BL_SceneConverter.h @@ -0,0 +1,119 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file BL_SceneConverter.h + * \ingroup bgeconv + */ + +#ifndef __KX_BLENDERSCENECONVERTER_H__ +#define __KX_BLENDERSCENECONVERTER_H__ + +#include "BL_Resource.h" + +#include +#include + +class SCA_IActuator; +class SCA_IController; +class KX_Mesh; +class KX_BlenderMaterial; +class BL_Converter; +class BL_ConvertObjectInfo; +class BL_ActionData; +class KX_GameObject; +class KX_Scene; +class KX_LibLoadStatus; +struct Main; +struct BlendHandle; +struct Object; +struct Scene; +struct Mesh; +struct Material; +struct bAction; +struct bActuator; +struct bController; + +class BL_SceneConverter +{ + friend BL_Converter; + +private: + KX_Scene *m_scene; + const BL_Resource::Library m_libraryId; + + /// Ressources from the scene. + + std::vector m_materials; + std::vector m_meshobjects; + std::vector m_objectInfos; + std::vector m_actions; + + /// List of all object converted, active and inactive, not considered as a ressource. + std::vector m_objects; + + std::map m_blenderToObjectInfos; + std::map m_map_blender_to_gameobject; + std::map m_map_mesh_to_gamemesh; + std::map m_map_mesh_to_polyaterial; + std::map m_map_blender_to_gameactuator; + std::map m_map_blender_to_gamecontroller; + +public: + BL_SceneConverter(KX_Scene *scene, const BL_Resource::Library& libraryId); + ~BL_SceneConverter() = default; + + // Disable dangerous copy. + BL_SceneConverter(const BL_SceneConverter& other) = delete; + BL_SceneConverter(BL_SceneConverter&& other); + + KX_Scene *GetScene() const; + + void RegisterGameObject(KX_GameObject *gameobject, Object *for_blenderobject); + void UnregisterGameObject(KX_GameObject *gameobject); + KX_GameObject *FindGameObject(Object *for_blenderobject) const; + + void RegisterGameMesh(KX_Mesh *gamemesh, Mesh *for_blendermesh); + KX_Mesh *FindGameMesh(Mesh *for_blendermesh) const; + + void RegisterMaterial(KX_BlenderMaterial *blmat, Material *mat); + KX_BlenderMaterial *FindMaterial(Material *mat) const; + + void RegisterActionData(BL_ActionData *data); + + void RegisterGameActuator(SCA_IActuator *act, bActuator *for_actuator); + SCA_IActuator *FindGameActuator(bActuator *for_actuator) const; + + void RegisterGameController(SCA_IController *cont, bController *for_controller); + SCA_IController *FindGameController(bController *for_controller) const; + + BL_ConvertObjectInfo *GetObjectInfo(Object *blenderobj); + + const std::vector& GetObjects() const; + const std::vector& GetMaterials() const; +}; + +#endif // __KX_BLENDERSCENECONVERTER_H__ diff --git a/source/gameengine/Converter/BL_ShapeActionActuator.cpp b/source/gameengine/Converter/BL_ShapeActionActuator.cpp deleted file mode 100644 index 38eab7d5c308..000000000000 --- a/source/gameengine/Converter/BL_ShapeActionActuator.cpp +++ /dev/null @@ -1,563 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Converter/BL_ShapeActionActuator.cpp - * \ingroup bgeconv - */ - - -#include - -#include "SCA_LogicManager.h" -#include "BL_ShapeActionActuator.h" -#include "BL_ShapeDeformer.h" -#include "KX_GameObject.h" -#include "STR_HashedString.h" -#include "DNA_nla_types.h" -#include "DNA_action_types.h" -#include "DNA_anim_types.h" -#include "DNA_scene_types.h" -#include "BKE_action.h" -#include "DNA_armature_types.h" -#include "MEM_guardedalloc.h" -#include "BLI_blenlib.h" -#include "BLI_math.h" -#include "MT_Matrix4x4.h" - -#include "EXP_FloatValue.h" -#include "EXP_PyObjectPlus.h" - -extern "C" { - #include "BKE_animsys.h" - #include "BKE_key.h" - #include "RNA_access.h" -} - -BL_ShapeActionActuator::BL_ShapeActionActuator(SCA_IObject* gameobj, - const STR_String& propname, - const STR_String& framepropname, - float starttime, - float endtime, - struct bAction *action, - short playtype, - short blendin, - short priority, - float stride) - : SCA_IActuator(gameobj, KX_ACT_SHAPEACTION), - - m_lastpos(0, 0, 0), - m_blendframe(0), - m_flag(0), - m_startframe (starttime), - m_endframe(endtime) , - m_starttime(0), - m_localtime(starttime), - m_lastUpdate(-1), - m_blendin(blendin), - m_blendstart(0), - m_stridelength(stride), - m_playtype(playtype), - m_priority(priority), - m_action(action), - m_framepropname(framepropname), - m_propname(propname) -{ - m_idptr = new PointerRNA(); - BL_DeformableGameObject *obj = (BL_DeformableGameObject*)GetParent(); - BL_ShapeDeformer *shape_deformer = dynamic_cast(obj->GetDeformer()); - RNA_id_pointer_create(&shape_deformer->GetKey()->id, m_idptr); -}; - -BL_ShapeActionActuator::~BL_ShapeActionActuator() -{ - if (m_idptr) - delete m_idptr; -} - -void BL_ShapeActionActuator::ProcessReplica() -{ - SCA_IActuator::ProcessReplica(); - m_localtime=m_startframe; - m_lastUpdate=-1; -} - -void BL_ShapeActionActuator::SetBlendTime(float newtime) -{ - m_blendframe = newtime; -} - -CValue* BL_ShapeActionActuator::GetReplica() -{ - BL_ShapeActionActuator* replica = new BL_ShapeActionActuator(*this);//m_float,GetName()); - replica->ProcessReplica(); - return replica; -} - -bool BL_ShapeActionActuator::ClampLocalTime() -{ - if (m_startframe < m_endframe) { - if (m_localtime < m_startframe) - { - m_localtime = m_startframe; - return true; - } - else if (m_localtime > m_endframe) - { - m_localtime = m_endframe; - return true; - } - } else { - if (m_localtime > m_startframe) - { - m_localtime = m_startframe; - return true; - } - else if (m_localtime < m_endframe) - { - m_localtime = m_endframe; - return true; - } - } - return false; -} - -void BL_ShapeActionActuator::SetStartTime(float curtime) -{ - float direction = m_startframe < m_endframe ? 1.0 : -1.0; - - if (!(m_flag & ACT_FLAG_REVERSE)) - m_starttime = curtime - direction*(m_localtime - m_startframe)/KX_KetsjiEngine::GetAnimFrameRate(); - else - m_starttime = curtime - direction*(m_endframe - m_localtime)/KX_KetsjiEngine::GetAnimFrameRate(); -} - -void BL_ShapeActionActuator::SetLocalTime(float curtime) -{ - float delta_time = (curtime - m_starttime)*KX_KetsjiEngine::GetAnimFrameRate(); - - if (m_endframe < m_startframe) - delta_time = -delta_time; - - if (!(m_flag & ACT_FLAG_REVERSE)) - m_localtime = m_startframe + delta_time; - else - m_localtime = m_endframe - delta_time; -} - -void BL_ShapeActionActuator::BlendShape(Key* key, float srcweight) -{ - vector::const_iterator it; - float dstweight; - KeyBlock *kb; - - dstweight = 1.0F - srcweight; - - for (it=m_blendshape.begin(), kb = (KeyBlock *)key->block.first; - kb && it != m_blendshape.end(); - kb = (KeyBlock *)kb->next, it++) - { - kb->curval = kb->curval * dstweight + (*it) * srcweight; - } -} - -bool BL_ShapeActionActuator::Update(double curtime, bool frame) -{ - bool bNegativeEvent = false; - bool bPositiveEvent = false; - bool keepgoing = true; - bool wrap = false; - bool apply=true; - int priority; - float newweight; - - curtime -= KX_KetsjiEngine::GetSuspendedDelta(); - - // result = true if animation has to be continued, false if animation stops - // maybe there are events for us in the queue ! - if (frame) - { - bNegativeEvent = m_negevent; - bPositiveEvent = m_posevent; - RemoveAllEvents(); - - if (bPositiveEvent) - m_flag |= ACT_FLAG_ACTIVE; - - if (bNegativeEvent) - { - if (!(m_flag & ACT_FLAG_ACTIVE)) - return false; - m_flag &= ~ACT_FLAG_ACTIVE; - } - } - - /* This action can only be attached to a deform object */ - BL_DeformableGameObject *obj = (BL_DeformableGameObject*)GetParent(); - float length = m_endframe - m_startframe; - - priority = m_priority; - - /* Determine pre-incrementation behavior and set appropriate flags */ - switch (m_playtype) { - case ACT_ACTION_MOTION: - if (bNegativeEvent) { - keepgoing=false; - apply=false; - }; - break; - case ACT_ACTION_FROM_PROP: - if (bNegativeEvent) { - apply=false; - keepgoing=false; - } - break; - case ACT_ACTION_LOOP_END: - if (bPositiveEvent) { - if (!(m_flag & ACT_FLAG_LOCKINPUT)) { - m_flag &= ~ACT_FLAG_KEYUP; - m_flag &= ~ACT_FLAG_REVERSE; - m_flag |= ACT_FLAG_LOCKINPUT; - m_localtime = m_startframe; - m_starttime = curtime; - } - } - if (bNegativeEvent) { - m_flag |= ACT_FLAG_KEYUP; - } - break; - case ACT_ACTION_LOOP_STOP: - if (bPositiveEvent) { - if (!(m_flag & ACT_FLAG_LOCKINPUT)) { - m_flag &= ~ACT_FLAG_REVERSE; - m_flag &= ~ACT_FLAG_KEYUP; - m_flag |= ACT_FLAG_LOCKINPUT; - SetStartTime(curtime); - } - } - if (bNegativeEvent) { - m_flag |= ACT_FLAG_KEYUP; - m_flag &= ~ACT_FLAG_LOCKINPUT; - keepgoing=false; - apply=false; - } - break; - case ACT_ACTION_PINGPONG: - if (bPositiveEvent) { - if (!(m_flag & ACT_FLAG_LOCKINPUT)) { - m_flag &= ~ACT_FLAG_KEYUP; - m_localtime = m_starttime; - m_starttime = curtime; - m_flag |= ACT_FLAG_LOCKINPUT; - } - } - break; - case ACT_ACTION_FLIPPER: - if (bPositiveEvent) { - if (!(m_flag & ACT_FLAG_LOCKINPUT)) { - m_flag &= ~ACT_FLAG_REVERSE; - m_flag |= ACT_FLAG_LOCKINPUT; - SetStartTime(curtime); - } - } - else if (bNegativeEvent) { - m_flag |= ACT_FLAG_REVERSE; - m_flag &= ~ACT_FLAG_LOCKINPUT; - SetStartTime(curtime); - } - break; - case ACT_ACTION_PLAY: - if (bPositiveEvent) { - if (!(m_flag & ACT_FLAG_LOCKINPUT)) { - m_flag &= ~ACT_FLAG_REVERSE; - m_localtime = m_starttime; - m_starttime = curtime; - m_flag |= ACT_FLAG_LOCKINPUT; - } - } - break; - default: - break; - } - - /* Perform increment */ - if (keepgoing) { - if (m_playtype == ACT_ACTION_MOTION) { - MT_Point3 newpos; - MT_Point3 deltapos; - - newpos = obj->NodeGetWorldPosition(); - - /* Find displacement */ - deltapos = newpos-m_lastpos; - m_localtime += (length/m_stridelength) * deltapos.length(); - m_lastpos = newpos; - } - else { - SetLocalTime(curtime); - } - } - - /* Check if a wrapping response is needed */ - if (length) { - if (m_localtime < m_startframe || m_localtime > m_endframe) - { - m_localtime = m_startframe + fmod(m_localtime, length); - wrap = true; - } - } - else - m_localtime = m_startframe; - - /* Perform post-increment tasks */ - switch (m_playtype) { - case ACT_ACTION_FROM_PROP: - { - CValue* propval = GetParent()->GetProperty(m_propname); - if (propval) - m_localtime = propval->GetNumber(); - - if (bNegativeEvent) { - keepgoing=false; - } - } - break; - case ACT_ACTION_MOTION: - break; - case ACT_ACTION_LOOP_STOP: - break; - case ACT_ACTION_PINGPONG: - if (wrap) { - if (!(m_flag & ACT_FLAG_REVERSE)) - m_localtime = m_endframe; - else - m_localtime = m_startframe; - - m_flag &= ~ACT_FLAG_LOCKINPUT; - m_flag ^= ACT_FLAG_REVERSE; //flip direction - keepgoing = false; - } - break; - case ACT_ACTION_FLIPPER: - if (wrap) { - if (!(m_flag & ACT_FLAG_REVERSE)) { - m_localtime=m_endframe; - //keepgoing = false; - } - else { - m_localtime=m_startframe; - keepgoing = false; - } - } - break; - case ACT_ACTION_LOOP_END: - if (wrap) { - if (m_flag & ACT_FLAG_KEYUP) { - keepgoing = false; - m_localtime = m_endframe; - m_flag &= ~ACT_FLAG_LOCKINPUT; - } - SetStartTime(curtime); - } - break; - case ACT_ACTION_PLAY: - if (wrap) { - m_localtime = m_endframe; - keepgoing = false; - m_flag &= ~ACT_FLAG_LOCKINPUT; - } - break; - default: - keepgoing = false; - break; - } - - /* Set the property if its defined */ - if (m_framepropname[0] != '\0') { - CValue* propowner = GetParent(); - CValue* oldprop = propowner->GetProperty(m_framepropname); - CValue* newval = new CFloatValue(m_localtime); - if (oldprop) { - oldprop->SetValue(newval); - } else { - propowner->SetProperty(m_framepropname, newval); - } - newval->Release(); - } - - if (bNegativeEvent) - m_blendframe=0.0f; - - /* Apply the pose if necessary*/ - if (apply) { - - /* Priority test */ - if (obj->SetActiveAction(this, priority, curtime)) { - BL_ShapeDeformer *shape_deformer = dynamic_cast(obj->GetDeformer()); - Key *key = NULL; - - if (shape_deformer) - key = shape_deformer->GetKey(); - - if (!key) { - // this could happen if the mesh was changed in the middle of an action - // and the new mesh has no key, stop the action - keepgoing = false; - } - else { - ListBase tchanbase= {NULL, NULL}; - - if (m_blendin && m_blendframe==0.0f) { - // this is the start of the blending, remember the startup shape - obj->GetShape(m_blendshape); - m_blendstart = curtime; - } - - KeyBlock *kb; - // We go through and clear out the keyblocks so there isn't any interference - // from other shape actions - for (kb=(KeyBlock *)key->block.first; kb; kb=(KeyBlock *)kb->next) - kb->curval = 0.f; - - animsys_evaluate_action(m_idptr, m_action, NULL, m_localtime); - - // XXX - in 2.5 theres no way to do this. possibly not that important to support - Campbell - if (0) { // XXX !execute_ipochannels(&tchanbase)) { - // no update, this is possible if action does not match the keys, stop the action - keepgoing = false; - } - else { - // the key have changed, apply blending if needed - if (m_blendin && (m_blendframem_blendin) - m_blendframe = m_blendin; - } - m_lastUpdate = m_localtime; - } - BLI_freelistN(&tchanbase); - } - } - else { - m_blendframe = 0.0f; - } - } - - if (!keepgoing) { - m_blendframe = 0.0f; - } - return keepgoing; -}; - -#ifdef WITH_PYTHON - -/* ------------------------------------------------------------------------- */ -/* Python functions */ -/* ------------------------------------------------------------------------- */ - -/* Integration hooks ------------------------------------------------------- */ - -PyTypeObject BL_ShapeActionActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "BL_ShapeActionActuator", - sizeof(PyObjectPlus_Proxy), - 0, - py_base_dealloc, - 0, - 0, - 0, - 0, - py_base_repr, - 0,0,0,0,0,0,0,0,0, - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, - Methods, - 0, - 0, - &SCA_IActuator::Type, - 0,0,0,0,0,0, - py_base_new -}; - - -PyMethodDef BL_ShapeActionActuator::Methods[] = { - {NULL,NULL} //Sentinel -}; - -PyAttributeDef BL_ShapeActionActuator::Attributes[] = { - KX_PYATTRIBUTE_FLOAT_RW("frameStart", 0, MAXFRAMEF, BL_ShapeActionActuator, m_startframe), - KX_PYATTRIBUTE_FLOAT_RW("frameEnd", 0, MAXFRAMEF, BL_ShapeActionActuator, m_endframe), - KX_PYATTRIBUTE_FLOAT_RW("blendIn", 0, MAXFRAMEF, BL_ShapeActionActuator, m_blendin), - KX_PYATTRIBUTE_RW_FUNCTION("action", BL_ShapeActionActuator, pyattr_get_action, pyattr_set_action), - KX_PYATTRIBUTE_SHORT_RW("priority", 0, 100, false, BL_ShapeActionActuator, m_priority), - KX_PYATTRIBUTE_FLOAT_RW_CHECK("frame", 0, MAXFRAMEF, BL_ShapeActionActuator, m_localtime, CheckFrame), - KX_PYATTRIBUTE_STRING_RW("propName", 0, MAX_PROP_NAME, false, BL_ShapeActionActuator, m_propname), - KX_PYATTRIBUTE_STRING_RW("framePropName", 0, MAX_PROP_NAME, false, BL_ShapeActionActuator, m_framepropname), - KX_PYATTRIBUTE_FLOAT_RW_CHECK("blendTime", 0, MAXFRAMEF, BL_ShapeActionActuator, m_blendframe, CheckBlendTime), - KX_PYATTRIBUTE_SHORT_RW_CHECK("mode",0,100,false,BL_ShapeActionActuator,m_playtype,CheckType), - { NULL } //Sentinel -}; - -PyObject *BL_ShapeActionActuator::pyattr_get_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - BL_ShapeActionActuator* self = static_cast(self_v); - return PyUnicode_FromString(self->GetAction() ? self->GetAction()->id.name+2 : ""); -} - -int BL_ShapeActionActuator::pyattr_set_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) -{ - BL_ShapeActionActuator* self = static_cast(self_v); - /* exact copy of BL_ActionActuator's function from here down */ - if (!PyUnicode_Check(value)) - { - PyErr_SetString(PyExc_ValueError, "actuator.action = val: Shape Action Actuator, expected the string name of the action"); - return PY_SET_ATTR_FAIL; - } - - bAction *action= NULL; - STR_String val = _PyUnicode_AsString(value); - - if (val != "") - { - action= (bAction*)self->GetLogicManager()->GetActionByName(val); - if (action==NULL) - { - PyErr_SetString(PyExc_ValueError, "actuator.action = val: Shape Action Actuator, action not found!"); - return PY_SET_ATTR_FAIL; - } - } - - self->SetAction(action); - return PY_SET_ATTR_SUCCESS; - -} - -#endif // WITH_PYTHON diff --git a/source/gameengine/Converter/BL_ShapeActionActuator.h b/source/gameengine/Converter/BL_ShapeActionActuator.h deleted file mode 100644 index 899bbbc616db..000000000000 --- a/source/gameengine/Converter/BL_ShapeActionActuator.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file BL_ShapeActionActuator.h - * \ingroup bgeconv - */ - -#ifndef __BL_SHAPEACTIONACTUATOR_H__ -#define __BL_SHAPEACTIONACTUATOR_H__ - -#include "CTR_HashedPtr.h" -#include "SCA_IActuator.h" -#include "BL_ActionActuator.h" -#include "MT_Point3.h" -#include - -struct Key; -class BL_ShapeActionActuator : public SCA_IActuator -{ -public: - Py_Header - BL_ShapeActionActuator(SCA_IObject* gameobj, - const STR_String& propname, - const STR_String& framepropname, - float starttime, - float endtime, - struct bAction *action, - short playtype, - short blendin, - short priority, - float stride); - virtual ~BL_ShapeActionActuator(); - virtual bool Update(double curtime, bool frame); - virtual CValue* GetReplica(); - virtual void ProcessReplica(); - - void SetBlendTime (float newtime); - void BlendShape(struct Key* key, float weight); - - bAction* GetAction() { return m_action; } - void SetAction(bAction* act) { m_action= act; } - -#ifdef WITH_PYTHON - - static PyObject* pyattr_get_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - - static int CheckBlendTime(void *self, const PyAttributeDef*) - { - BL_ShapeActionActuator* act = reinterpret_cast(self); - - if (act->m_blendframe > act->m_blendin) - act->m_blendframe = act->m_blendin; - - return 0; - } - static int CheckFrame(void *self, const PyAttributeDef*) - { - BL_ShapeActionActuator* act = reinterpret_cast(self); - - if (act->m_localtime < act->m_startframe) - act->m_localtime = act->m_startframe; - else if (act->m_localtime > act->m_endframe) - act->m_localtime = act->m_endframe; - - return 0; - } - static int CheckType(void *self, const PyAttributeDef*) - { - BL_ShapeActionActuator* act = reinterpret_cast(self); - - switch (act->m_playtype) { - case ACT_ACTION_PLAY: - case ACT_ACTION_PINGPONG: - case ACT_ACTION_FLIPPER: - case ACT_ACTION_LOOP_STOP: - case ACT_ACTION_LOOP_END: - case ACT_ACTION_FROM_PROP: - return 0; - default: - PyErr_SetString(PyExc_ValueError, "Shape Action Actuator, invalid play type supplied"); - return 1; - } - - } - -#endif /* WITH_PYTHON */ - -protected: - - void SetStartTime(float curtime); - void SetLocalTime(float curtime); - bool ClampLocalTime(); - - MT_Point3 m_lastpos; - float m_blendframe; - int m_flag; - /** The frame this action starts */ - float m_startframe; - /** The frame this action ends */ - float m_endframe; - /** The time this action started */ - float m_starttime; - /** The current time of the action */ - float m_localtime; - - float m_lastUpdate; - float m_blendin; - float m_blendstart; - float m_stridelength; - short m_playtype; - short m_priority; - struct bAction *m_action; - STR_String m_framepropname; - STR_String m_propname; - vector m_blendshape; - struct PointerRNA *m_idptr; -}; - -#endif /* __BL_SHAPEACTIONACTUATOR_H__ */ diff --git a/source/gameengine/Converter/BL_ShapeDeformer.cpp b/source/gameengine/Converter/BL_ShapeDeformer.cpp index 7653bb3f99b3..ab17621eefce 100644 --- a/source/gameengine/Converter/BL_ShapeDeformer.cpp +++ b/source/gameengine/Converter/BL_ShapeDeformer.cpp @@ -35,10 +35,9 @@ #include "MEM_guardedalloc.h" #include "BL_ShapeDeformer.h" -#include "CTR_Map.h" -#include "STR_HashedString.h" -#include "RAS_IPolygonMaterial.h" -#include "RAS_MeshObject.h" +#include +#include "RAS_IMaterial.h" +#include "RAS_Mesh.h" #include "DNA_anim_types.h" #include "DNA_armature_types.h" @@ -54,9 +53,8 @@ #include "BKE_fcurve.h" #include "BKE_ipo.h" #include "BKE_library.h" -#include "MT_Point3.h" -extern "C"{ +extern "C" { #include "BKE_lattice.h" #include "BKE_animsys.h" } @@ -64,84 +62,48 @@ extern "C"{ #include "BLI_blenlib.h" #include "BLI_math.h" -#define __NLA_DEFNORMALS -//#undef __NLA_DEFNORMALS - -BL_ShapeDeformer::BL_ShapeDeformer(BL_DeformableGameObject *gameobj, - Object *bmeshobj, - RAS_MeshObject *mesh) - : - BL_SkinDeformer(gameobj,bmeshobj, mesh), - m_useShapeDrivers(false), - m_lastShapeUpdate(-1) -{ - m_key = m_bmesh->key ? BKE_key_copy(G.main, m_bmesh->key) : NULL; -}; - -/* this second constructor is needed for making a mesh deformable on the fly. */ -BL_ShapeDeformer::BL_ShapeDeformer(BL_DeformableGameObject *gameobj, - Object *bmeshobj_old, - Object *bmeshobj_new, - RAS_MeshObject *mesh, - bool release_object, - bool recalc_normal, - BL_ArmatureObject* arma) - : - BL_SkinDeformer(gameobj, bmeshobj_old, bmeshobj_new, mesh, release_object, recalc_normal, arma), - m_useShapeDrivers(false), - m_lastShapeUpdate(-1) +BL_ShapeDeformer::BL_ShapeDeformer(KX_GameObject *gameobj, + Object *bmeshobj_old, + Object *bmeshobj_new, + RAS_Mesh *mesh, + BL_ArmatureObject *arma) + :BL_SkinDeformer(gameobj, bmeshobj_old, bmeshobj_new, mesh, arma), + m_useShapeDrivers(false), + m_lastShapeUpdate(-1) { - m_key = m_bmesh->key ? BKE_key_copy(G.main, m_bmesh->key) : NULL; -}; + m_key = m_bmesh->key ? BKE_key_copy(G.main, m_bmesh->key) : nullptr; +} BL_ShapeDeformer::~BL_ShapeDeformer() { - if (m_key) - { + if (m_key) { BKE_libblock_free(G.main, m_key); - m_key = NULL; + m_key = nullptr; } -}; - -RAS_Deformer *BL_ShapeDeformer::GetReplica() -{ - BL_ShapeDeformer *result; - - result = new BL_ShapeDeformer(*this); - result->ProcessReplica(); - return result; } -void BL_ShapeDeformer::ProcessReplica() -{ - BL_SkinDeformer::ProcessReplica(); - m_lastShapeUpdate = -1; - - m_key = m_key ? BKE_key_copy(G.main, m_key) : NULL; -} - -bool BL_ShapeDeformer::LoadShapeDrivers(KX_GameObject* parent) +bool BL_ShapeDeformer::LoadShapeDrivers(KX_GameObject *parent) { // Only load shape drivers if we have a key - if (GetKey() == NULL) { + if (!m_key) { m_useShapeDrivers = false; return false; } // Fix drivers since BL_ArmatureObject makes copies - if (parent->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE && GetKey()->adt) { - BL_ArmatureObject *arma = (BL_ArmatureObject*)parent; + if (m_armobj && m_key->adt) { FCurve *fcu; - for (fcu = (FCurve*)GetKey()->adt->drivers.first; fcu; fcu = (FCurve*)fcu->next) { + for (fcu = (FCurve *)m_key->adt->drivers.first; fcu; fcu = (FCurve *)fcu->next) { DriverVar *dvar; - for (dvar = (DriverVar*)fcu->driver->variables.first; dvar; dvar = (DriverVar*)dvar->next) { + for (dvar = (DriverVar *)fcu->driver->variables.first; dvar; dvar = (DriverVar *)dvar->next) { DRIVER_TARGETS_USED_LOOPER(dvar) { if (dtar->id) { - if ((Object*)dtar->id == arma->GetOrigArmatureObject()) - dtar->id = (ID*)arma->GetArmatureObject(); + if ((Object *)dtar->id == m_armobj->GetOrigArmatureObject()) { + dtar->id = (ID *)m_armobj->GetArmatureObject(); + } } } DRIVER_TARGETS_LOOPER_END @@ -157,11 +119,11 @@ bool BL_ShapeDeformer::LoadShapeDrivers(KX_GameObject* parent) return true; } -bool BL_ShapeDeformer::ExecuteShapeDrivers(void) +bool BL_ShapeDeformer::ExecuteShapeDrivers() { if (m_useShapeDrivers && PoseUpdated()) { // We don't need an actual time, just use 0 - BKE_animsys_evaluate_animdata(NULL, &GetKey()->id, GetKey()->adt, 0.f, ADT_RECALC_DRIVERS); + BKE_animsys_evaluate_animdata(nullptr, &m_key->id, m_key->adt, 0.f, ADT_RECALC_DRIVERS); ForceUpdate(); m_bDynamic = true; @@ -170,7 +132,7 @@ bool BL_ShapeDeformer::ExecuteShapeDrivers(void) return false; } -bool BL_ShapeDeformer::Update(void) +bool BL_ShapeDeformer::UpdateInternal(bool recalcNormal) { bool bShapeUpdate = false; bool bSkinUpdate = false; @@ -178,22 +140,22 @@ bool BL_ShapeDeformer::Update(void) ExecuteShapeDrivers(); /* See if the object shape has changed */ - if (m_lastShapeUpdate != m_gameobj->GetLastFrame()) { + if (m_lastShapeUpdate != m_lastFrame) { /* the key coefficient have been set already, we just need to blend the keys */ - Object* blendobj = m_gameobj->GetBlendObject(); + Object *blendobj = m_gameobj->GetBlenderObject(); /* we will blend the key directly in m_transverts array: it is used by armature as the start position */ - /* m_key can be NULL in case of Modifier deformer */ + /* m_key can be nullptr in case of Modifier deformer */ if (m_key) { - WeightsArrayCache cache = {0, NULL}; + WeightsArrayCache cache = {0, nullptr}; float **per_keyblock_weights; /* store verts locally */ VerifyStorage(); per_keyblock_weights = BKE_keyblock_get_per_block_weights(blendobj, m_key, &cache); - BKE_key_evaluate_relative(0, m_bmesh->totvert, m_bmesh->totvert, (char *)(float *)m_transverts, - m_key, NULL, per_keyblock_weights, 0); /* last arg is ignored */ + BKE_key_evaluate_relative(0, m_bmesh->totvert, m_bmesh->totvert, (char *)(float *)m_transverts.data(), + m_key, nullptr, per_keyblock_weights, 0); /* last arg is ignored */ BKE_keyblock_free_per_block_weights(m_key, per_keyblock_weights, &cache); m_bDynamic = true; @@ -203,7 +165,7 @@ bool BL_ShapeDeformer::Update(void) // The weight array are ultimately deleted when the skin mesh is destroyed /* Update the current frame */ - m_lastShapeUpdate=m_gameobj->GetLastFrame(); + m_lastShapeUpdate = m_lastFrame; // As we have changed, the mesh, the skin deformer must update as well. // This will force the update @@ -211,18 +173,10 @@ bool BL_ShapeDeformer::Update(void) bShapeUpdate = true; } // check for armature deform - bSkinUpdate = BL_SkinDeformer::UpdateInternal(bShapeUpdate && m_bDynamic); + bSkinUpdate = BL_SkinDeformer::UpdateInternal(bShapeUpdate && m_bDynamic, recalcNormal); // non dynamic deformer = Modifer without armature and shape keys, no need to create storage if (!bSkinUpdate && bShapeUpdate && m_bDynamic) { - // this means that there is no armature, we still need to - // update the normal (was not done after shape key calculation) - -#ifdef __NLA_DEFNORMALS - if (m_recalcNormal) - RecalcNormals(); -#endif - // We also need to handle transverts now (used to be in BL_SkinDeformer::Apply()) UpdateTransverts(); bSkinUpdate = true; @@ -231,7 +185,25 @@ bool BL_ShapeDeformer::Update(void) return bSkinUpdate; } +bool BL_ShapeDeformer::Update() +{ + return UpdateInternal(true); +} + Key *BL_ShapeDeformer::GetKey() { return m_key; } + +bool BL_ShapeDeformer::GetShape(std::vector &shape) const +{ + shape.clear(); + // this check is normally superfluous: a shape deformer can only be created if the mesh + // has relative keys + if (m_key && m_key->type == KEY_RELATIVE) { + for (KeyBlock *kb = (KeyBlock *)m_key->block.first; kb; kb = (KeyBlock *)kb->next) { + shape.push_back(kb->curval); + } + } + return !shape.empty(); +} diff --git a/source/gameengine/Converter/BL_ShapeDeformer.h b/source/gameengine/Converter/BL_ShapeDeformer.h index 276e51f85063..ce37365586db 100644 --- a/source/gameengine/Converter/BL_ShapeDeformer.h +++ b/source/gameengine/Converter/BL_ShapeDeformer.h @@ -37,49 +37,41 @@ #endif #include "BL_SkinDeformer.h" -#include "BL_DeformableGameObject.h" #include +struct Object; +struct Key; +class RAS_Mesh; + class BL_ShapeDeformer : public BL_SkinDeformer { public: - BL_ShapeDeformer(BL_DeformableGameObject *gameobj, - Object *bmeshobj, - RAS_MeshObject *mesh); - - /* this second constructor is needed for making a mesh deformable on the fly. */ - BL_ShapeDeformer(BL_DeformableGameObject *gameobj, - struct Object *bmeshobj_old, - struct Object *bmeshobj_new, - class RAS_MeshObject *mesh, - bool release_object, - bool recalc_normal, - BL_ArmatureObject* arma = NULL); + BL_ShapeDeformer(KX_GameObject *gameobj, + Object *bmeshobj_old, + Object *bmeshobj_new, + RAS_Mesh *mesh, + BL_ArmatureObject *arma); - virtual RAS_Deformer *GetReplica(); - virtual void ProcessReplica(); virtual ~BL_ShapeDeformer(); - bool Update (void); - bool LoadShapeDrivers(KX_GameObject* parent); - bool ExecuteShapeDrivers(void); + bool UpdateInternal(bool recalcNormal); + virtual bool Update(); + bool LoadShapeDrivers(KX_GameObject *parent); + bool ExecuteShapeDrivers(); - struct Key *GetKey(); + Key *GetKey(); + bool GetShape(std::vector &shape) const; void ForceUpdate() { m_lastShapeUpdate = -1.0; - }; + } protected: - bool m_useShapeDrivers; - double m_lastShapeUpdate; - struct Key* m_key; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_ShapeDeformer") -#endif + bool m_useShapeDrivers; + double m_lastShapeUpdate; + Key *m_key; }; #endif + diff --git a/source/gameengine/Converter/BL_SkinDeformer.cpp b/source/gameengine/Converter/BL_SkinDeformer.cpp index 16700859ebeb..8229460489de 100644 --- a/source/gameengine/Converter/BL_SkinDeformer.cpp +++ b/source/gameengine/Converter/BL_SkinDeformer.cpp @@ -38,12 +38,13 @@ #include #include "BL_SkinDeformer.h" -#include "CTR_Map.h" -#include "STR_HashedString.h" -#include "RAS_IPolygonMaterial.h" -#include "RAS_MeshObject.h" +#include +#include "RAS_IMaterial.h" +#include "RAS_DisplayArray.h" +#include "RAS_Mesh.h" +#include "RAS_MeshUser.h" +#include "RAS_BoundingBox.h" -//#include "BL_ArmatureController.h" #include "DNA_armature_types.h" #include "DNA_action_types.h" #include "DNA_mesh_types.h" @@ -52,9 +53,8 @@ #include "BLI_utildefines.h" #include "BKE_armature.h" #include "BKE_action.h" -#include "MT_Point3.h" -extern "C"{ +extern "C" { #include "BKE_lattice.h" #include "BKE_deform.h" } @@ -63,19 +63,14 @@ extern "C"{ #include "BLI_blenlib.h" #include "BLI_math.h" -#define __NLA_DEFNORMALS -//#undef __NLA_DEFNORMALS - -static short get_deformflags(struct Object *bmeshobj) +static short get_deformflags(Object *bmeshobj) { short flags = ARM_DEF_VGROUP; ModifierData *md; - for (md = (ModifierData *)bmeshobj->modifiers.first; md; md = md->next) - { - if (md->type == eModifierType_Armature) - { - flags |= ((ArmatureModifierData*)md)->deformflag; + for (md = (ModifierData *)bmeshobj->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Armature) { + flags |= ((ArmatureModifierData *)md)->deformflag; break; } } @@ -83,191 +78,126 @@ static short get_deformflags(struct Object *bmeshobj) return flags; } -BL_SkinDeformer::BL_SkinDeformer(BL_DeformableGameObject *gameobj, - struct Object *bmeshobj, - class RAS_MeshObject *mesh, - BL_ArmatureObject* arma) - : // - BL_MeshDeformer(gameobj, bmeshobj, mesh), - m_armobj(arma), - m_lastArmaUpdate(-1), - //m_defbase(&bmeshobj->defbase), - m_releaseobject(false), - m_poseApplied(false), - m_recalcNormal(true), - m_copyNormals(false), - m_dfnrToPC(NULL) +BL_SkinDeformer::BL_SkinDeformer(KX_GameObject *gameobj, + Object *bmeshobj_old, // Blender object that owns the new mesh + Object *bmeshobj_new, // Blender object that owns the original mesh + RAS_Mesh *mesh, + BL_ArmatureObject *arma) + :BL_MeshDeformer(gameobj, bmeshobj_old, mesh), + m_armobj(arma), + m_lastArmaUpdate(-1), + m_copyNormals(false) { - copy_m4_m4(m_obmat, bmeshobj->obmat); - m_deformflags = get_deformflags(bmeshobj); -}; - -BL_SkinDeformer::BL_SkinDeformer( - BL_DeformableGameObject *gameobj, - struct Object *bmeshobj_old, // Blender object that owns the new mesh - struct Object *bmeshobj_new, // Blender object that owns the original mesh - class RAS_MeshObject *mesh, - bool release_object, - bool recalc_normal, - BL_ArmatureObject* arma) : - BL_MeshDeformer(gameobj, bmeshobj_old, mesh), - m_armobj(arma), - m_lastArmaUpdate(-1), - //m_defbase(&bmeshobj_old->defbase), - m_releaseobject(release_object), - m_recalcNormal(recalc_normal), - m_copyNormals(false), - m_dfnrToPC(NULL) - { - // this is needed to ensure correct deformation of mesh: - // the deformation is done with Blender's armature_deform_verts() function - // that takes an object as parameter and not a mesh. The object matrice is used - // in the calculation, so we must use the matrix of the original object to - // simulate a pure replacement of the mesh. - copy_m4_m4(m_obmat, bmeshobj_new->obmat); - m_deformflags = get_deformflags(bmeshobj_new); - } + // this is needed to ensure correct deformation of mesh: + // the deformation is done with Blender's armature_deform_verts() function + // that takes an object as parameter and not a mesh. The object matrice is used + // in the calculation, so we must use the matrix of the original object to + // simulate a pure replacement of the mesh. + copy_m4_m4(m_obmat, bmeshobj_new->obmat); + m_deformflags = get_deformflags(bmeshobj_new); +} BL_SkinDeformer::~BL_SkinDeformer() { - if (m_releaseobject && m_armobj) - m_armobj->Release(); - if (m_dfnrToPC) - delete [] m_dfnrToPC; } -void BL_SkinDeformer::Relink(CTR_Map*map) +void BL_SkinDeformer::Apply(RAS_DisplayArray *array) { - if (m_armobj) { - void **h_obj = (*map)[m_armobj]; + for (DisplayArraySlot& slot : m_slots) { + if (slot.m_displayArray == array) { + const short modifiedFlag = slot.m_arrayUpdateClient.GetInvalidAndClear(); + if (modifiedFlag != RAS_DisplayArray::NONE_MODIFIED) { + /// Update vertex data from the original mesh. + array->UpdateFrom(slot.m_origDisplayArray, modifiedFlag); + } - if (h_obj) - m_armobj = (BL_ArmatureObject*)(*h_obj); - else - m_armobj=NULL; + break; + } } - - BL_MeshDeformer::Relink(map); -} - -bool BL_SkinDeformer::Apply(RAS_IPolyMaterial *mat) -{ - // We do everything in UpdateInternal() now so we can thread it. - // All that is left is telling the rasterizer if we've changed the mesh - bool retval = !m_poseApplied; - m_poseApplied = true; - return retval; -} - -RAS_Deformer *BL_SkinDeformer::GetReplica() -{ - BL_SkinDeformer *result; - - result = new BL_SkinDeformer(*this); - /* there is m_armobj that must be fixed but we cannot do it now, it will be done in Relink */ - result->ProcessReplica(); - return result; -} - -void BL_SkinDeformer::ProcessReplica() -{ - BL_MeshDeformer::ProcessReplica(); - m_lastArmaUpdate = -1; - m_releaseobject = false; - m_dfnrToPC = NULL; } -void BL_SkinDeformer::BlenderDeformVerts() +void BL_SkinDeformer::BlenderDeformVerts(bool recalcNormal) { - float obmat[4][4]; // the original object matrix - Object* par_arma = m_armobj->GetArmatureObject(); + float obmat[4][4]; // the original object matrix + Object *par_arma = m_armobj->GetArmatureObject(); // save matrix first copy_m4_m4(obmat, m_objMesh->obmat); // set reference matrix copy_m4_m4(m_objMesh->obmat, m_obmat); - armature_deform_verts( par_arma, m_objMesh, NULL, m_transverts, NULL, m_bmesh->totvert, m_deformflags, NULL, NULL ); + armature_deform_verts(par_arma, m_objMesh, nullptr, (float(*)[3])m_transverts.data(), nullptr, m_bmesh->totvert, m_deformflags, nullptr, nullptr); // restore matrix copy_m4_m4(m_objMesh->obmat, obmat); -#ifdef __NLA_DEFNORMALS - if (m_recalcNormal) - RecalcNormals(); -#endif + if (recalcNormal) { + RecalcNormals(); + } } -void BL_SkinDeformer::BGEDeformVerts() +void BL_SkinDeformer::BGEDeformVerts(bool recalcNormal) { Object *par_arma = m_armobj->GetArmatureObject(); MDeformVert *dverts = m_bmesh->dvert; - bDeformGroup *dg; - int defbase_tot; Eigen::Matrix4f pre_mat, post_mat, chan_mat, norm_chan_mat; - if (!dverts) + if (!dverts) { return; + } - defbase_tot = BLI_listbase_count(&m_objMesh->defbase); + const unsigned short defbase_tot = BLI_listbase_count(&m_objMesh->defbase); - if (m_dfnrToPC == NULL) - { - m_dfnrToPC = new bPoseChannel*[defbase_tot]; + if (m_dfnrToPC.empty()) { + m_dfnrToPC.resize(defbase_tot); int i; - for (i=0, dg=(bDeformGroup*)m_objMesh->defbase.first; - dg; - ++i, dg = dg->next) - { + bDeformGroup *dg; + for (i = 0, dg = (bDeformGroup *)m_objMesh->defbase.first; dg; ++i, dg = dg->next) { m_dfnrToPC[i] = BKE_pose_channel_find_name(par_arma->pose, dg->name); - if (m_dfnrToPC[i] && m_dfnrToPC[i]->bone->flag & BONE_NO_DEFORM) - m_dfnrToPC[i] = NULL; + if (m_dfnrToPC[i] && m_dfnrToPC[i]->bone->flag & BONE_NO_DEFORM) { + m_dfnrToPC[i] = nullptr; + } } } - post_mat = Eigen::Matrix4f::Map((float*)m_obmat).inverse() * Eigen::Matrix4f::Map((float*)m_armobj->GetArmatureObject()->obmat); + post_mat = Eigen::Matrix4f::Map((float *)m_obmat).inverse() * Eigen::Matrix4f::Map((float *)m_armobj->GetArmatureObject()->obmat); pre_mat = post_mat.inverse(); - MDeformVert *dv= dverts; + MDeformVert *dv = dverts; MDeformWeight *dw; - for (int i=0; itotvert; ++i, dv++) - { - float contrib = 0.f, weight, max_weight=-1.f; - bPoseChannel *pchan=NULL; - Eigen::Map norm = Eigen::Vector3f::Map(m_transnors[i]); - Eigen::Vector4f vec(0, 0, 0, 1); - Eigen::Vector4f co(m_transverts[i][0], - m_transverts[i][1], - m_transverts[i][2], - 1.f); - - if (!dv->totweight) + for (int i = 0; i < m_bmesh->totvert; ++i, dv++) { + if (!dv->totweight) { continue; + } + + float contrib = 0.0f, weight, max_weight = -1.0f; + bPoseChannel *pchan = nullptr; + Eigen::Vector4f vec(0.0f, 0.0f, 0.0f, 1.0f); + Eigen::Vector4f co(m_transverts[i].x, + m_transverts[i].y, + m_transverts[i].z, + 1.0f); co = pre_mat * co; - dw= dv->dw; + dw = dv->dw; - for (unsigned int j= dv->totweight; j != 0; j--, dw++) - { + for (unsigned int j = dv->totweight; j != 0; j--, dw++) { const int index = dw->def_nr; - if (index < defbase_tot && (pchan=m_dfnrToPC[index])) - { + if (index < defbase_tot && (pchan = m_dfnrToPC[index])) { weight = dw->weight; - if (weight) - { - chan_mat = Eigen::Matrix4f::Map((float*)pchan->chan_mat); + if (weight) { + chan_mat = Eigen::Matrix4f::Map((float *)pchan->chan_mat); // Update Vertex Position - vec.noalias() += (chan_mat*co - co)*weight; + vec.noalias() += (chan_mat * co - co) * weight; // Save the most influential channel so we can use it to update the vertex normal - if (weight > max_weight) - { + if (weight > max_weight) { max_weight = weight; norm_chan_mat = chan_mat; } @@ -277,93 +207,95 @@ void BL_SkinDeformer::BGEDeformVerts() } } - // Update Vertex Normal - norm = norm_chan_mat.topLeftCorner<3, 3>()*norm; + if (recalcNormal) { + const Eigen::Vector3f normorg(m_bmesh->mvert[i].no[0], m_bmesh->mvert[i].no[1], m_bmesh->mvert[i].no[2]); + Eigen::Map norm = Eigen::Vector3f::Map(m_transnors[i].data); + // Update Vertex Normal + norm = norm_chan_mat.topLeftCorner<3, 3>() * normorg; + } - co.noalias() += vec/contrib; - co[3] = 1.f; // Make sure we have a 1 for the w component! + co.noalias() += vec / contrib; + co[3] = 1.0f; // Make sure we have a 1 for the w component! co = post_mat * co; - m_transverts[i][0] = co[0]; - m_transverts[i][1] = co[1]; - m_transverts[i][2] = co[2]; + m_transverts[i] = mt::vec3(co[0], co[1], co[2]); } m_copyNormals = true; } void BL_SkinDeformer::UpdateTransverts() { - RAS_MeshSlot::iterator it; - RAS_MeshMaterial *mmat; - RAS_MeshSlot *slot; - size_t i, nmat, imat; - - if (m_transverts) { - // the vertex cache is unique to this deformer, no need to update it - // if it wasn't updated! We must update all the materials at once - // because we will not get here again for the other material - nmat = m_pMeshObject->NumMaterials(); - for (imat=0; imatGetMeshMaterial(imat); - if (!mmat->m_slots[(void*)m_gameobj]) - continue; - - slot = *mmat->m_slots[(void*)m_gameobj]; - - // for each array - for (slot->begin(it); !slot->end(it); slot->next(it)) { - // for each vertex - // copy the untransformed data from the original mvert - for (i=it.startvertex; iGetAutoUpdateBounds(); + + // the vertex cache is unique to this deformer, no need to update it + // if it wasn't updated! We must update all the materials at once + // because we will not get here again for the other material + for (const DisplayArraySlot& slot : m_slots) { + RAS_DisplayArray *array = slot.m_displayArray; + // for each vertex + // copy the untransformed data from the original mvert + for (unsigned int i = 0, size = array->GetVertexCount(); i < size; ++i) { + const RAS_VertexInfo& vinfo = array->GetVertexInfo(i); + const mt::vec3 pos = mt::vec3(m_transverts[vinfo.GetOrigIndex()]); + array->SetPosition(i, pos); + + if (autoUpdate) { + aabbMin = mt::vec3::Min(aabbMin, pos); + aabbMax = mt::vec3::Max(aabbMax, pos); + } + } + if (m_copyNormals) { + for (unsigned int i = 0, size = array->GetVertexCount(); i < size; ++i) { + const RAS_VertexInfo& vinfo = array->GetVertexInfo(i); + array->SetNormal(i, m_transnors[vinfo.GetOrigIndex()]); } } - if (m_copyNormals) - m_copyNormals = false; + array->NotifyUpdate(RAS_DisplayArray::POSITION_MODIFIED | RAS_DisplayArray::NORMAL_MODIFIED); + } + + m_boundingBox->SetAabb(aabbMin, aabbMax); + + if (m_copyNormals) { + m_copyNormals = false; } } -bool BL_SkinDeformer::UpdateInternal(bool shape_applied) +bool BL_SkinDeformer::UpdateInternal(bool shape_applied, bool recalcNormal) { /* See if the armature has been updated for this frame */ if (PoseUpdated()) { - if (!shape_applied) { /* store verts locally */ VerifyStorage(); - - /* duplicate */ - for (int v =0; vtotvert; v++) - { - copy_v3_v3(m_transverts[v], m_bmesh->mvert[v].co); - normal_short_to_float_v3(m_transnors[v], m_bmesh->mvert[v].no); - } } m_armobj->ApplyPose(); - if (m_armobj->GetVertDeformType() == ARM_VDEF_BGE_CPU) - BGEDeformVerts(); - else - BlenderDeformVerts(); + if (m_armobj->GetVertDeformType() == ARM_VDEF_BGE_CPU) { + BGEDeformVerts(recalcNormal); + } + else { + BlenderDeformVerts(recalcNormal); + } /* Update the current frame */ - m_lastArmaUpdate=m_armobj->GetLastFrame(); + m_lastArmaUpdate = m_armobj->GetLastFrame(); - m_armobj->RestorePose(); /* dynamic vertex, cannot use display list */ m_bDynamic = true; UpdateTransverts(); - m_poseApplied = false; - /* indicate that the m_transverts and normals are up to date */ return true; } @@ -373,12 +305,5 @@ bool BL_SkinDeformer::UpdateInternal(bool shape_applied) bool BL_SkinDeformer::Update(void) { - return UpdateInternal(false); -} - -/* XXX note: I propose to drop this function */ -void BL_SkinDeformer::SetArmature(BL_ArmatureObject *armobj) -{ - // only used to set the object now - m_armobj = armobj; + return UpdateInternal(false, true); } diff --git a/source/gameengine/Converter/BL_SkinDeformer.h b/source/gameengine/Converter/BL_SkinDeformer.h index 1feed3c3d164..96cac5e9f2ee 100644 --- a/source/gameengine/Converter/BL_SkinDeformer.h +++ b/source/gameengine/Converter/BL_SkinDeformer.h @@ -36,7 +36,6 @@ # pragma warning (disable:4786) /* get rid of stupid stl-visual compiler debug warning */ #endif /* WIN32 */ -#include "CTR_HashedPtr.h" #include "BL_MeshDeformer.h" #include "BL_ArmatureObject.h" @@ -45,81 +44,54 @@ #include "DNA_object_types.h" #include "BKE_armature.h" -#include "RAS_Deformer.h" - +struct Object; +struct bPoseChannel; +class RAS_Mesh; +class RAS_IMaterial; class BL_SkinDeformer : public BL_MeshDeformer { public: -// void SetArmatureController (BL_ArmatureController *cont); - virtual void Relink(CTR_Map*map); - void SetArmature (class BL_ArmatureObject *armobj); - - BL_SkinDeformer(BL_DeformableGameObject *gameobj, - struct Object *bmeshobj, - class RAS_MeshObject *mesh, - BL_ArmatureObject* arma = NULL); - - /* this second constructor is needed for making a mesh deformable on the fly. */ - BL_SkinDeformer(BL_DeformableGameObject *gameobj, - struct Object *bmeshobj_old, - struct Object *bmeshobj_new, - class RAS_MeshObject *mesh, - bool release_object, - bool recalc_normal, - BL_ArmatureObject* arma = NULL); - - virtual RAS_Deformer *GetReplica(); - virtual void ProcessReplica(); + BL_SkinDeformer(KX_GameObject *gameobj, + Object *bmeshobj_old, + Object *bmeshobj_new, + RAS_Mesh *mesh, + BL_ArmatureObject *arma); virtual ~BL_SkinDeformer(); - bool Update (void); - bool UpdateInternal (bool shape_applied); - bool Apply (class RAS_IPolyMaterial *polymat); - bool UpdateBuckets(void) + virtual bool Update(); + bool UpdateInternal(bool shape_applied, bool recalcNormal); + virtual void Apply(RAS_DisplayArray *array); + virtual void UpdateBuckets() { // update the deformer and all the mesh slots; Apply() does it well, so just call it. - return Apply(NULL); + Apply(nullptr); } - bool PoseUpdated(void) - { - if (m_armobj && m_lastArmaUpdate!=m_armobj->GetLastFrame()) { - return true; - } - return false; + bool PoseUpdated() + { + if (m_armobj && m_lastArmaUpdate != m_armobj->GetLastFrame()) { + return true; } + return false; + } void ForceUpdate() { m_lastArmaUpdate = -1.0; - }; - virtual bool ShareVertexArray() - { - return false; } protected: - BL_ArmatureObject* m_armobj; // Our parent object - float m_time; - double m_lastArmaUpdate; - //ListBase* m_defbase; - float m_obmat[4][4]; // the reference matrix for skeleton deform - bool m_releaseobject; - bool m_poseApplied; - bool m_recalcNormal; - bool m_copyNormals; // dirty flag so we know if Apply() needs to copy normal information (used for BGEDeformVerts()) - struct bPoseChannel** m_dfnrToPC; - short m_deformflags; - - void BlenderDeformVerts(); - void BGEDeformVerts(); - - void UpdateTransverts(); + BL_ArmatureObject *m_armobj; // Our parent object + double m_lastArmaUpdate; + float m_obmat[4][4]; // the reference matrix for skeleton deform + bool m_copyNormals; // dirty flag so we know if Apply() needs to copy normal information (used for BGEDeformVerts()) + std::vector m_dfnrToPC; + short m_deformflags; + void BlenderDeformVerts(bool recalcNormal); + void BGEDeformVerts(bool recalcNormal); -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_SkinDeformer") -#endif + virtual void UpdateTransverts(); }; #endif /* __BL_SKINDEFORMER_H__ */ diff --git a/source/gameengine/Converter/CMakeLists.txt b/source/gameengine/Converter/CMakeLists.txt index 4db9fcebd06a..c4ad9fdbcea7 100644 --- a/source/gameengine/Converter/CMakeLists.txt +++ b/source/gameengine/Converter/CMakeLists.txt @@ -26,18 +26,21 @@ set(INC . ../BlenderRoutines + ../Common + ../Device ../Expressions ../GameLogic ../Ketsji ../Ketsji/KXNetwork - ../Network - ../Network/LoopBackNetwork + ../Launcher ../Physics/Bullet ../Physics/Dummy - ../Physics/common + ../Physics/Common ../Rasterizer + ../Rasterizer/Node ../Rasterizer/RAS_OpenGLRasterizer ../SceneGraph + ../VideoTexture ../../blender ../../blender/blenkernel ../../blender/blenlib @@ -48,13 +51,13 @@ set(INC ../../blender/makesdna ../../blender/makesrna ../../blender/windowmanager - ../../../intern/container ../../../intern/guardedalloc - ../../../intern/string + ../../../intern/termcolor ) set(INC_SYS - ../../../intern/moto/include + ../../../intern/debugbreak + ../../../intern/mathfu ../../../extern/recastnavigation/Detour/Include ${EIGEN3_INCLUDE_DIRS} ${PTHREADS_INCLUDE_DIRS} @@ -63,46 +66,48 @@ set(INC_SYS set(SRC BL_ActionActuator.cpp + BL_ActionData.cpp BL_ArmatureActuator.cpp BL_ArmatureChannel.cpp BL_ArmatureConstraint.cpp BL_ArmatureObject.cpp BL_BlenderDataConversion.cpp - BL_DeformableGameObject.cpp + BL_Converter.cpp BL_MeshDeformer.cpp BL_ModifierDeformer.cpp - BL_ShapeActionActuator.cpp + BL_Resource.cpp BL_ShapeDeformer.cpp BL_SkinDeformer.cpp - KX_BlenderScalarInterpolator.cpp - KX_BlenderSceneConverter.cpp - KX_ConvertActuators.cpp - KX_ConvertControllers.cpp - KX_ConvertProperties.cpp - KX_ConvertSensors.cpp - KX_LibLoadStatus.cpp - KX_SoftBodyDeformer.cpp + BL_ScalarInterpolator.cpp + BL_SceneConverter.cpp + BL_ConvertActuators.cpp + BL_ConvertControllers.cpp + BL_ConvertObjectInfo.cpp + BL_ConvertProperties.cpp + BL_ConvertSensors.cpp + BL_IpoConvert.cpp BL_ActionActuator.h + BL_ActionData.h BL_ArmatureActuator.h BL_ArmatureChannel.h BL_ArmatureConstraint.h BL_ArmatureObject.h BL_BlenderDataConversion.h - BL_DeformableGameObject.h + BL_Converter.h BL_MeshDeformer.h BL_ModifierDeformer.h - BL_ShapeActionActuator.h + BL_Resource.h BL_ShapeDeformer.h BL_SkinDeformer.h - KX_BlenderScalarInterpolator.h - KX_BlenderSceneConverter.h - KX_ConvertActuators.h - KX_ConvertControllers.h - KX_ConvertProperties.h - KX_ConvertSensors.h - KX_LibLoadStatus.h - KX_SoftBodyDeformer.h + BL_ScalarInterpolator.h + BL_SceneConverter.h + BL_ConvertActuators.h + BL_ConvertControllers.h + BL_ConvertObjectInfo.h + BL_ConvertProperties.h + BL_ConvertSensors.h + BL_IpoConvert.h ) if(WITH_BULLET) diff --git a/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp b/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp deleted file mode 100644 index 7a7a76de6a48..000000000000 --- a/source/gameengine/Converter/KX_BlenderScalarInterpolator.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Converter/KX_BlenderScalarInterpolator.cpp - * \ingroup bgeconv - */ - - -#include "KX_BlenderScalarInterpolator.h" - -#include - -extern "C" { -#include "DNA_action_types.h" -#include "DNA_anim_types.h" -#include "BKE_fcurve.h" -} - -float BL_ScalarInterpolator::GetValue(float currentTime) const -{ - // XXX 2.4x IPO_GetFloatValue(m_blender_adt, m_channel, currentTime); - return evaluate_fcurve(m_fcu, currentTime); -} - -BL_InterpolatorList::BL_InterpolatorList(bAction *action) -{ - if (action==NULL) - return; - - for (FCurve *fcu = (FCurve *)action->curves.first; fcu; fcu = fcu->next) { - if (fcu->rna_path) { - BL_ScalarInterpolator *new_ipo = new BL_ScalarInterpolator(fcu); - //assert(new_ipo); - push_back(new_ipo); - } - } -} - -BL_InterpolatorList::~BL_InterpolatorList() -{ - BL_InterpolatorList::iterator i; - for (i = begin(); !(i == end()); ++i) { - delete *i; - } -} - -KX_IScalarInterpolator *BL_InterpolatorList::GetScalarInterpolator(const char *rna_path, int array_index) -{ - for (BL_InterpolatorList::iterator i = begin(); (i != end()) ; i++ ) - { - FCurve *fcu= (static_cast(*i))->GetFCurve(); - if (array_index==fcu->array_index && strcmp(rna_path, fcu->rna_path)==0) - return *i; - } - return NULL; -} diff --git a/source/gameengine/Converter/KX_BlenderScalarInterpolator.h b/source/gameengine/Converter/KX_BlenderScalarInterpolator.h deleted file mode 100644 index a82688cea20f..000000000000 --- a/source/gameengine/Converter/KX_BlenderScalarInterpolator.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file KX_BlenderScalarInterpolator.h - * \ingroup bgeconv - */ - -#ifndef __KX_BLENDERSCALARINTERPOLATOR_H__ -#define __KX_BLENDERSCALARINTERPOLATOR_H__ - -#include - -#include "KX_IScalarInterpolator.h" - -typedef unsigned short BL_IpoChannel; - -class BL_ScalarInterpolator : public KX_IScalarInterpolator { -public: - BL_ScalarInterpolator() {} // required for use in STL list - BL_ScalarInterpolator(struct FCurve* fcu) : - m_fcu(fcu) - {} - - virtual ~BL_ScalarInterpolator() {} - - virtual float GetValue(float currentTime) const; - struct FCurve *GetFCurve() { return m_fcu; } - -private: - struct FCurve *m_fcu; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_ScalarInterpolator") -#endif -}; - - -class BL_InterpolatorList : public std::vector { -public: - BL_InterpolatorList(struct bAction *action); - ~BL_InterpolatorList(); - - KX_IScalarInterpolator *GetScalarInterpolator(const char *rna_path, int array_index); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_InterpolatorList") -#endif -}; - -#endif /* __KX_BLENDERSCALARINTERPOLATOR_H__ */ diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp deleted file mode 100644 index 5d9f32a09694..000000000000 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp +++ /dev/null @@ -1,1477 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Converter/KX_BlenderSceneConverter.cpp - * \ingroup bgeconv - */ - -#ifdef _MSC_VER -# pragma warning (disable:4786) /* suppress stl-MSVC debug info warning */ -#endif - -#include "KX_Scene.h" -#include "KX_GameObject.h" -#include "KX_IpoConvert.h" -#include "RAS_MeshObject.h" -#include "KX_PhysicsEngineEnums.h" -#include "PHY_IPhysicsEnvironment.h" -#include "KX_KetsjiEngine.h" -#include "KX_PythonInit.h" // So we can handle adding new text datablocks for Python to import -#include "BL_Material.h" -#include "BL_ActionActuator.h" -#include "KX_BlenderMaterial.h" - - -#include "BL_System.h" - -#include "DummyPhysicsEnvironment.h" - - -#ifdef WITH_BULLET -#include "CcdPhysicsEnvironment.h" -#endif - -#include "KX_LibLoadStatus.h" -#include "KX_BlenderScalarInterpolator.h" -#include "BL_BlenderDataConversion.h" -#include "KX_WorldInfo.h" - -/* This little block needed for linking to Blender... */ -#ifdef WIN32 -#include "BLI_winstuff.h" -#endif - -/* This list includes only data type definitions */ -#include "DNA_scene_types.h" -#include "DNA_world_types.h" -#include "BKE_main.h" -#include "BKE_fcurve.h" - -#include "BLI_math.h" - -extern "C" -{ -#include "DNA_object_types.h" -#include "DNA_curve_types.h" -#include "DNA_mesh_types.h" -#include "DNA_material_types.h" -#include "BLI_blenlib.h" -#include "MEM_guardedalloc.h" -#include "BKE_global.h" -#include "BKE_animsys.h" -#include "BKE_library.h" -#include "BKE_material.h" // BKE_material_copy -#include "BKE_mesh.h" // BKE_mesh_copy -#include "DNA_space_types.h" -#include "DNA_anim_types.h" -#include "DNA_action_types.h" -#include "RNA_define.h" -#include "../../blender/editors/include/ED_keyframing.h" -} - -/* Only for dynamic loading and merging */ -#include "RAS_BucketManager.h" // XXX cant stay -#include "KX_BlenderSceneConverter.h" -#include "KX_MeshProxy.h" -extern "C" { - #include "PIL_time.h" - #include "BKE_context.h" - #include "BLO_readfile.h" - #include "BKE_idcode.h" - #include "BKE_report.h" - #include "DNA_space_types.h" - #include "DNA_windowmanager_types.h" /* report api */ - #include "../../blender/blenlib/BLI_linklist.h" -} - -#include "BLI_task.h" - -// This is used to avoid including BLI_task.h in KX_BlenderSceneConverter.h -typedef struct ThreadInfo { - TaskPool *m_pool; - ThreadMutex m_mutex; -} ThreadInfo; - -KX_BlenderSceneConverter::KX_BlenderSceneConverter( - Main *maggie, - KX_KetsjiEngine *engine) - :m_maggie(maggie), - m_ketsjiEngine(engine), - m_alwaysUseExpandFraming(false), - m_usemat(false), - m_useglslmat(false), - m_use_mat_cache(true) -{ - BKE_main_id_tag_all(maggie, LIB_TAG_DOIT, false); /* avoid re-tagging later on */ - m_newfilename = ""; - m_threadinfo = new ThreadInfo(); - m_threadinfo->m_pool = BLI_task_pool_create(engine->GetTaskScheduler(), NULL); - BLI_mutex_init(&m_threadinfo->m_mutex); -} - -KX_BlenderSceneConverter::~KX_BlenderSceneConverter() -{ - // clears meshes, and hashmaps from blender to gameengine data - // delete sumoshapes - - int numAdtLists = m_map_blender_to_gameAdtList.size(); - for (int i = 0; i < numAdtLists; i++) { - BL_InterpolatorList *adtList = *m_map_blender_to_gameAdtList.at(i); - - delete (adtList); - } - - vector >::iterator itw = m_worldinfos.begin(); - while (itw != m_worldinfos.end()) { - delete itw->second; - itw++; - } - m_worldinfos.clear(); - - vector >::iterator itp = m_polymaterials.begin(); - while (itp != m_polymaterials.end()) { - delete itp->second; - itp++; - } - m_polymaterials.clear(); - - // delete after RAS_IPolyMaterial - vector >::iterator itmat = m_materials.begin(); - while (itmat != m_materials.end()) { - delete itmat->second; - itmat++; - } - m_materials.clear(); - - vector >::iterator itm = m_meshobjects.begin(); - while (itm != m_meshobjects.end()) { - delete itm->second; - itm++; - } - m_meshobjects.clear(); - - /* free any data that was dynamically loaded */ - while (m_DynamicMaggie.size() != 0) { - FreeBlendFile(m_DynamicMaggie[0]); - } - - m_DynamicMaggie.clear(); - - if (m_threadinfo) { - /* Thread infos like mutex must be freed after FreeBlendFile function. - Because it needs to lock the mutex, even if there's no active task when it's - in the scene converter destructor. */ - BLI_task_pool_free(m_threadinfo->m_pool); - BLI_mutex_end(&m_threadinfo->m_mutex); - delete m_threadinfo; - } -} - -void KX_BlenderSceneConverter::SetNewFileName(const STR_String &filename) -{ - m_newfilename = filename; -} - -bool KX_BlenderSceneConverter::TryAndLoadNewFile() -{ - bool result = false; - - return result; -} - -Scene *KX_BlenderSceneConverter::GetBlenderSceneForName(const STR_String &name) -{ - Scene *sce; - - /** - * Find the specified scene by name, or NULL if nothing matches. - */ - if ((sce = (Scene *)BLI_findstring(&m_maggie->scene, name.ReadPtr(), offsetof(ID, name) + 2))) - return sce; - - for (vector
::iterator it=m_DynamicMaggie.begin(); !(it == m_DynamicMaggie.end()); it++) { - Main *main = *it; - - if ((sce= (Scene *)BLI_findstring(&main->scene, name.ReadPtr(), offsetof(ID, name) + 2))) - return sce; - } - - return NULL; -} - -void KX_BlenderSceneConverter::ConvertScene(KX_Scene *destinationscene, RAS_IRasterizer *rendertools, - RAS_ICanvas *canvas, bool libloading) -{ - //find out which physics engine - Scene *blenderscene = destinationscene->GetBlenderScene(); - - PHY_IPhysicsEnvironment *phy_env = NULL; - - e_PhysicsEngine physics_engine = UseBullet; - // hook for registration function during conversion. - m_currentScene = destinationscene; - destinationscene->SetSceneConverter(this); - - // This doesn't really seem to do anything except cause potential issues - // when doing threaded conversion, so it's disabled for now. - // SG_SetActiveStage(SG_STAGE_CONVERTER); - - switch (blenderscene->gm.physicsEngine) { -#ifdef WITH_BULLET - case WOPHY_BULLET: - { - SYS_SystemHandle syshandle = SYS_GetSystem(); /*unused*/ - int visualizePhysics = SYS_GetCommandLineInt(syshandle, "show_physics", 0); - - phy_env = CcdPhysicsEnvironment::Create(blenderscene, visualizePhysics); - physics_engine = UseBullet; - break; - } -#endif - default: - case WOPHY_NONE: - { - // We should probably use some sort of factory here - phy_env = new DummyPhysicsEnvironment(); - physics_engine = UseNone; - break; - } - } - - destinationscene->SetPhysicsEnvironment(phy_env); - - BL_ConvertBlenderObjects( - m_maggie, - destinationscene, - m_ketsjiEngine, - physics_engine, - rendertools, - canvas, - this, - m_alwaysUseExpandFraming, - libloading); - - //These lookup are not needed during game - m_map_blender_to_gameactuator.clear(); - m_map_blender_to_gamecontroller.clear(); - m_map_blender_to_gameobject.clear(); - - //Clearing this lookup table has the effect of disabling the cache of meshes - //between scenes, even if they are shared in the blend file. - //This cache mecanism is buggy so I leave it disable and the memory leak - //that would result from this is fixed in RemoveScene() - m_map_mesh_to_gamemesh.clear(); -} - -// This function removes all entities stored in the converter for that scene -// It should be used instead of direct delete scene -// Note that there was some provision for sharing entities (meshes...) between -// scenes but that is now disabled so all scene will have their own copy -// and we can delete them here. If the sharing is reactivated, change this code too.. -// (see KX_BlenderSceneConverter::ConvertScene) -void KX_BlenderSceneConverter::RemoveScene(KX_Scene *scene) -{ - int i, size; - // delete the scene first as it will stop the use of entities - delete scene; - // delete the entities of this scene - vector >::iterator worldit; - size = m_worldinfos.size(); - for (i = 0, worldit = m_worldinfos.begin(); i < size; ) { - if (worldit->first == scene) { - delete worldit->second; - *worldit = m_worldinfos.back(); - m_worldinfos.pop_back(); - size--; - } - else { - i++; - worldit++; - } - } - - vector >::iterator polymit; - size = m_polymaterials.size(); - for (i = 0, polymit = m_polymaterials.begin(); i < size; ) { - if (polymit->first == scene) { - m_polymat_cache[scene].erase(polymit->second->GetBlenderMaterial()); - delete polymit->second; - *polymit = m_polymaterials.back(); - m_polymaterials.pop_back(); - size--; - } - else { - i++; - polymit++; - } - } - - m_polymat_cache.erase(scene); - - vector >::iterator matit; - size = m_materials.size(); - for (i = 0, matit = m_materials.begin(); i < size; ) { - if (matit->first == scene) { - m_mat_cache[scene].erase(matit->second->material); - delete matit->second; - *matit = m_materials.back(); - m_materials.pop_back(); - size--; - } - else { - i++; - matit++; - } - } - - m_mat_cache.erase(scene); - - vector >::iterator meshit; - size = m_meshobjects.size(); - for (i = 0, meshit = m_meshobjects.begin(); i < size; ) { - if (meshit->first == scene) { - delete meshit->second; - *meshit = m_meshobjects.back(); - m_meshobjects.pop_back(); - size--; - } - else { - i++; - meshit++; - } - } -} - -// use blender materials -void KX_BlenderSceneConverter::SetMaterials(bool val) -{ - m_usemat = val; - m_useglslmat = false; -} - -void KX_BlenderSceneConverter::SetGLSLMaterials(bool val) -{ - m_usemat = val; - m_useglslmat = val; -} - -void KX_BlenderSceneConverter::SetCacheMaterials(bool val) -{ - m_use_mat_cache = val; -} - -bool KX_BlenderSceneConverter::GetMaterials() -{ - return m_usemat; -} - -bool KX_BlenderSceneConverter::GetGLSLMaterials() -{ - return m_useglslmat; -} - -bool KX_BlenderSceneConverter::GetCacheMaterials() -{ - return m_use_mat_cache; -} - -void KX_BlenderSceneConverter::RegisterBlenderMaterial(BL_Material *mat) -{ - // First make sure we don't register the material twice - vector >::iterator it; - for (it = m_materials.begin(); it != m_materials.end(); ++it) - if (it->second == mat) - return; - - m_materials.push_back(pair (m_currentScene, mat)); -} - -void KX_BlenderSceneConverter::SetAlwaysUseExpandFraming(bool to_what) -{ - m_alwaysUseExpandFraming= to_what; -} - -void KX_BlenderSceneConverter::RegisterGameObject(KX_GameObject *gameobject, Object *for_blenderobject) -{ - /* only maintained while converting, freed during game runtime */ - m_map_blender_to_gameobject.insert(CHashedPtr(for_blenderobject), gameobject); -} - -/* only need to run this during conversion since - * m_map_blender_to_gameobject is freed after conversion */ -void KX_BlenderSceneConverter::UnregisterGameObject(KX_GameObject *gameobject) -{ - Object *bobp = gameobject->GetBlenderObject(); - if (bobp) { - CHashedPtr bptr(bobp); - KX_GameObject **gobp = m_map_blender_to_gameobject[bptr]; - if (gobp && *gobp == gameobject) { - // also maintain m_map_blender_to_gameobject if the gameobject - // being removed is matching the blender object - m_map_blender_to_gameobject.remove(bptr); - } - } -} - -KX_GameObject *KX_BlenderSceneConverter::FindGameObject(Object *for_blenderobject) -{ - KX_GameObject **obp = m_map_blender_to_gameobject[CHashedPtr(for_blenderobject)]; - - return obp ? *obp : NULL; -} - -void KX_BlenderSceneConverter::RegisterGameMesh(RAS_MeshObject *gamemesh, Mesh *for_blendermesh) -{ - if (for_blendermesh) { /* dynamically loaded meshes we don't want to keep lookups for */ - m_map_mesh_to_gamemesh.insert(CHashedPtr(for_blendermesh),gamemesh); - } - m_meshobjects.push_back(pair (m_currentScene,gamemesh)); -} - -RAS_MeshObject *KX_BlenderSceneConverter::FindGameMesh(Mesh *for_blendermesh) -{ - RAS_MeshObject **meshp = m_map_mesh_to_gamemesh[CHashedPtr(for_blendermesh)]; - - if (meshp) { - return *meshp; - } - else { - return NULL; - } -} - -void KX_BlenderSceneConverter::RegisterPolyMaterial(RAS_IPolyMaterial *polymat) -{ - // First make sure we don't register the material twice - vector >::iterator it; - for (it = m_polymaterials.begin(); it != m_polymaterials.end(); ++it) - if (it->second == polymat) - return; - m_polymaterials.push_back(pair (m_currentScene, polymat)); -} - -void KX_BlenderSceneConverter::CachePolyMaterial(KX_Scene *scene, Material *mat, RAS_IPolyMaterial *polymat) -{ - if (m_use_mat_cache && mat) - m_polymat_cache[scene][mat] = polymat; -} - -RAS_IPolyMaterial *KX_BlenderSceneConverter::FindCachedPolyMaterial(KX_Scene *scene, Material *mat) -{ - return (m_use_mat_cache) ? m_polymat_cache[scene][mat] : NULL; -} - -void KX_BlenderSceneConverter::CacheBlenderMaterial(KX_Scene *scene, Material *mat, BL_Material *blmat) -{ - if (m_use_mat_cache && mat) - m_mat_cache[scene][mat] = blmat; -} - -BL_Material *KX_BlenderSceneConverter::FindCachedBlenderMaterial(KX_Scene *scene, Material *mat) -{ - return (m_use_mat_cache) ? m_mat_cache[scene][mat] : NULL; -} - -void KX_BlenderSceneConverter::RegisterInterpolatorList(BL_InterpolatorList *actList, bAction *for_act) -{ - m_map_blender_to_gameAdtList.insert(CHashedPtr(for_act), actList); -} - -BL_InterpolatorList *KX_BlenderSceneConverter::FindInterpolatorList(bAction *for_act) -{ - BL_InterpolatorList **listp = m_map_blender_to_gameAdtList[CHashedPtr(for_act)]; - return listp ? *listp : NULL; -} - -void KX_BlenderSceneConverter::RegisterGameActuator(SCA_IActuator *act, bActuator *for_actuator) -{ - m_map_blender_to_gameactuator.insert(CHashedPtr(for_actuator), act); -} - -SCA_IActuator *KX_BlenderSceneConverter::FindGameActuator(bActuator *for_actuator) -{ - SCA_IActuator **actp = m_map_blender_to_gameactuator[CHashedPtr(for_actuator)]; - return actp ? *actp : NULL; -} - -void KX_BlenderSceneConverter::RegisterGameController(SCA_IController *cont, bController *for_controller) -{ - m_map_blender_to_gamecontroller.insert(CHashedPtr(for_controller), cont); -} - -SCA_IController *KX_BlenderSceneConverter::FindGameController(bController *for_controller) -{ - SCA_IController **contp = m_map_blender_to_gamecontroller[CHashedPtr(for_controller)]; - return contp ? *contp : NULL; -} - -void KX_BlenderSceneConverter::RegisterWorldInfo(KX_WorldInfo *worldinfo) -{ - m_worldinfos.push_back(pair (m_currentScene, worldinfo)); -} - -void KX_BlenderSceneConverter::ResetPhysicsObjectsAnimationIpo(bool clearIpo) -{ - //TODO this entire function is deprecated, written for 2.4x - //the functionality should be rewritten, currently it does nothing - - KX_SceneList *scenes = m_ketsjiEngine->CurrentScenes(); - int numScenes = scenes->size(); - int i; - for (i = 0; i < numScenes; i++) { - KX_Scene *scene = scenes->at(i); - CListValue *parentList = scene->GetRootParentList(); - int numObjects = parentList->GetCount(); - int g; - for (g = 0; g < numObjects; g++) { - KX_GameObject *gameObj = (KX_GameObject *)parentList->GetValue(g); - if (gameObj->IsRecordAnimation()) { - Object *blenderObject = gameObj->GetBlenderObject(); - if (blenderObject) { -#if 0 - //erase existing ipo's - Ipo* ipo = blenderObject->ipo;//findIpoForName(blenderObject->id.name+2); - if (ipo) { //clear the curve data - if (clearIpo) {//rcruiz - IpoCurve *icu1; - - int numCurves = 0; - for ( icu1 = (IpoCurve*)ipo->curve.first; icu1; ) { - - IpoCurve* tmpicu = icu1; - - /*int i; - BezTriple *bezt; - for ( bezt = tmpicu->bezt, i = 0; i < tmpicu->totvert; i++, bezt++) { - printf("(%f,%f,%f),(%f,%f,%f),(%f,%f,%f)\n",bezt->vec[0][0],bezt->vec[0][1],bezt->vec[0][2],bezt->vec[1][0],bezt->vec[1][1],bezt->vec[1][2],bezt->vec[2][0],bezt->vec[2][1],bezt->vec[2][2]); - }*/ - - icu1 = icu1->next; - numCurves++; - - BLI_remlink( &( blenderObject->ipo->curve ), tmpicu ); - if ( tmpicu->bezt ) - MEM_freeN( tmpicu->bezt ); - MEM_freeN( tmpicu ); - localDel_ipoCurve( tmpicu ); - } - } - } - else { - ipo = NULL; // XXX add_ipo(blenderObject->id.name+2, ID_OB); - blenderObject->ipo = ipo; - } -#endif - } - } - } - } -} - -void KX_BlenderSceneConverter::resetNoneDynamicObjectToIpo() -{ - //TODO the functionality should be rewritten -} - -// this generates ipo curves for position, rotation, allowing to use game physics in animation -void KX_BlenderSceneConverter::WritePhysicsObjectToAnimationIpo(int frameNumber) -{ - KX_SceneList *scenes = m_ketsjiEngine->CurrentScenes(); - int numScenes = scenes->size(); - int i; - for (i = 0; i < numScenes; i++) { - KX_Scene *scene = scenes->at(i); - //PHY_IPhysicsEnvironment* physEnv = scene->GetPhysicsEnvironment(); - CListValue *parentList = scene->GetObjectList(); - int numObjects = parentList->GetCount(); - int g; - for (g = 0; g < numObjects; g++) { - KX_GameObject *gameObj = (KX_GameObject *)parentList->GetValue(g); - Object *blenderObject = gameObj->GetBlenderObject(); - if (blenderObject && blenderObject->parent == NULL && gameObj->IsRecordAnimation()) { - if (blenderObject->adt == NULL) - BKE_animdata_add_id(&blenderObject->id); - - if (blenderObject->adt) { - const MT_Point3 &position = gameObj->NodeGetWorldPosition(); - //const MT_Vector3& scale = gameObj->NodeGetWorldScaling(); - const MT_Matrix3x3 &orn = gameObj->NodeGetWorldOrientation(); - - position.getValue(blenderObject->loc); - - float tmat[3][3]; - for (int r = 0; r < 3; r++) - for (int c = 0; c < 3; c++) - tmat[r][c] = (float)orn[c][r]; - - mat3_to_compatible_eul(blenderObject->rot, blenderObject->rot, tmat); - - insert_keyframe(G.main, NULL, &blenderObject->id, NULL, NULL, "location", -1, (float)frameNumber, BEZT_KEYTYPE_JITTER, INSERTKEY_FAST); - insert_keyframe(G.main, NULL, &blenderObject->id, NULL, NULL, "rotation_euler", -1, (float)frameNumber, BEZT_KEYTYPE_JITTER, INSERTKEY_FAST); - -#if 0 - const MT_Point3& position = gameObj->NodeGetWorldPosition(); - //const MT_Vector3& scale = gameObj->NodeGetWorldScaling(); - const MT_Matrix3x3& orn = gameObj->NodeGetWorldOrientation(); - - float eulerAngles[3]; - float eulerAnglesOld[3] = {0.0f, 0.0f, 0.0f}; - float tmat[3][3]; - - // XXX animato - Ipo* ipo = blenderObject->ipo; - - //create the curves, if not existing, set linear if new - - IpoCurve *icu_lx = findIpoCurve((IpoCurve *)ipo->curve.first,"LocX"); - if (!icu_lx) { - icu_lx = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_X, 1); - if (icu_lx) icu_lx->ipo = IPO_LIN; - } - IpoCurve *icu_ly = findIpoCurve((IpoCurve *)ipo->curve.first,"LocY"); - if (!icu_ly) { - icu_ly = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Y, 1); - if (icu_ly) icu_ly->ipo = IPO_LIN; - } - IpoCurve *icu_lz = findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ"); - if (!icu_lz) { - icu_lz = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_LOC_Z, 1); - if (icu_lz) icu_lz->ipo = IPO_LIN; - } - IpoCurve *icu_rx = findIpoCurve((IpoCurve *)ipo->curve.first,"RotX"); - if (!icu_rx) { - icu_rx = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_X, 1); - if (icu_rx) icu_rx->ipo = IPO_LIN; - } - IpoCurve *icu_ry = findIpoCurve((IpoCurve *)ipo->curve.first,"RotY"); - if (!icu_ry) { - icu_ry = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Y, 1); - if (icu_ry) icu_ry->ipo = IPO_LIN; - } - IpoCurve *icu_rz = findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ"); - if (!icu_rz) { - icu_rz = verify_ipocurve(&blenderObject->id, ipo->blocktype, NULL, NULL, NULL, OB_ROT_Z, 1); - if (icu_rz) icu_rz->ipo = IPO_LIN; - } - - if (icu_rx) eulerAnglesOld[0] = eval_icu( icu_rx, frameNumber - 1 ) / ((180 / 3.14159265f) / 10); - if (icu_ry) eulerAnglesOld[1] = eval_icu( icu_ry, frameNumber - 1 ) / ((180 / 3.14159265f) / 10); - if (icu_rz) eulerAnglesOld[2] = eval_icu( icu_rz, frameNumber - 1 ) / ((180 / 3.14159265f) / 10); - - // orn.getValue((float *)tmat); // uses the wrong ordering, cant use this - for (int r = 0; r < 3; r++) - for (int c = 0; c < 3; c++) - tmat[r][c] = orn[c][r]; - - // mat3_to_eul( eulerAngles,tmat); // better to use Mat3ToCompatibleEul - mat3_to_compatible_eul( eulerAngles, eulerAnglesOld,tmat); - - //eval_icu - for (int x = 0; x < 3; x++) - eulerAngles[x] *= (float) ((180 / 3.14159265f) / 10.0); - - //fill the curves with data - if (icu_lx) insert_vert_icu(icu_lx, frameNumber, position.x(), 1); - if (icu_ly) insert_vert_icu(icu_ly, frameNumber, position.y(), 1); - if (icu_lz) insert_vert_icu(icu_lz, frameNumber, position.z(), 1); - if (icu_rx) insert_vert_icu(icu_rx, frameNumber, eulerAngles[0], 1); - if (icu_ry) insert_vert_icu(icu_ry, frameNumber, eulerAngles[1], 1); - if (icu_rz) insert_vert_icu(icu_rz, frameNumber, eulerAngles[2], 1); - - // Handles are corrected at the end, testhandles_ipocurve isn't needed yet -#endif - } - } - } - } -} - -void KX_BlenderSceneConverter::TestHandlesPhysicsObjectToAnimationIpo() -{ - KX_SceneList *scenes = m_ketsjiEngine->CurrentScenes(); - int numScenes = scenes->size(); - int i; - for (i = 0; i < numScenes; i++) { - KX_Scene *scene = scenes->at(i); - //PHY_IPhysicsEnvironment* physEnv = scene->GetPhysicsEnvironment(); - CListValue *parentList = scene->GetRootParentList(); - int numObjects = parentList->GetCount(); - int g; - for (g = 0; g < numObjects; g++) { - KX_GameObject *gameObj = (KX_GameObject *)parentList->GetValue(g); - if (gameObj->IsRecordAnimation()) { - Object *blenderObject = gameObj->GetBlenderObject(); - if (blenderObject && blenderObject->adt) { - bAction *act = verify_adt_action(G.main, &blenderObject->id, false); - FCurve *fcu; - - if (!act) { - continue; - } - - /* for now, not much choice but to run this on all curves... */ - for (fcu = (FCurve *)act->curves.first; fcu; fcu = fcu->next) { - /* Note: calling `sort_time_fcurve()` here is not needed, since - * all keys have been added in 'right' order. */ - calchandles_fcurve(fcu); - } -#if 0 - // XXX animato - Ipo* ipo = blenderObject->ipo; - - //create the curves, if not existing - //testhandles_ipocurve checks for NULL - testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"LocX")); - testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"LocY")); - testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"LocZ")); - testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"RotX")); - testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"RotY")); - testhandles_ipocurve(findIpoCurve((IpoCurve *)ipo->curve.first,"RotZ")); -#endif - } - } - } - } -} - -#ifdef WITH_PYTHON -PyObject *KX_BlenderSceneConverter::GetPyNamespace() -{ - return m_ketsjiEngine->GetPyNamespace(); -} -#endif - -vector
&KX_BlenderSceneConverter::GetMainDynamic() -{ - return m_DynamicMaggie; -} - -Main *KX_BlenderSceneConverter::GetMainDynamicPath(const char *path) -{ - for (vector
::iterator it = m_DynamicMaggie.begin(); !(it == m_DynamicMaggie.end()); it++) - if (BLI_path_cmp((*it)->name, path) == 0) - return *it; - - return NULL; -} - -void KX_BlenderSceneConverter::MergeAsyncLoads() -{ - vector *merge_scenes; - - vector::iterator mit; - vector::iterator sit; - - BLI_mutex_lock(&m_threadinfo->m_mutex); - - for (mit = m_mergequeue.begin(); mit != m_mergequeue.end(); ++mit) { - merge_scenes = (vector *)(*mit)->GetData(); - - for (sit=merge_scenes->begin(); sit!=merge_scenes->end(); ++sit) { - (*mit)->GetMergeScene()->MergeScene(*sit); - delete (*sit); - } - - delete merge_scenes; - (*mit)->SetData(NULL); - - (*mit)->Finish(); - } - - m_mergequeue.clear(); - - BLI_mutex_unlock(&m_threadinfo->m_mutex); -} - -void KX_BlenderSceneConverter::FinalizeAsyncLoads() -{ - // Finish all loading libraries. - if (m_threadinfo) { - BLI_task_pool_work_and_wait(m_threadinfo->m_pool); - } - // Merge all libraries data in the current scene, to avoid memory leak of unmerged scenes. - MergeAsyncLoads(); -} - -void KX_BlenderSceneConverter::AddScenesToMergeQueue(KX_LibLoadStatus *status) -{ - BLI_mutex_lock(&m_threadinfo->m_mutex); - m_mergequeue.push_back(status); - BLI_mutex_unlock(&m_threadinfo->m_mutex); -} - -static void async_convert(TaskPool *pool, void *ptr, int UNUSED(threadid)) -{ - KX_Scene *new_scene = NULL; - KX_LibLoadStatus *status = (KX_LibLoadStatus *)ptr; - vector *scenes = (vector *)status->GetData(); - vector *merge_scenes = new vector(); // Deleted in MergeAsyncLoads - - for (unsigned int i = 0; i < scenes->size(); ++i) { - new_scene = status->GetEngine()->CreateScene((*scenes)[i], true); - - if (new_scene) - merge_scenes->push_back(new_scene); - - status->AddProgress((1.0f / scenes->size()) * 0.9f); // We'll call conversion 90% and merging 10% for now - } - - delete scenes; - status->SetData(merge_scenes); - - status->GetConverter()->AddScenesToMergeQueue(status); -} - -KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFileMemory(void *data, int length, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options) -{ - BlendHandle *bpy_openlib = BLO_blendhandle_from_memory(data, length); - - // Error checking is done in LinkBlendFile - return LinkBlendFile(bpy_openlib, path, group, scene_merge, err_str, options); -} - -KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFilePath(const char *filepath, char *group, KX_Scene *scene_merge, char **err_str, short options) -{ - BlendHandle *bpy_openlib = BLO_blendhandle_from_file(filepath, NULL); - - // Error checking is done in LinkBlendFile - return LinkBlendFile(bpy_openlib, filepath, group, scene_merge, err_str, options); -} - -static void load_datablocks(Main *main_tmp, BlendHandle *bpy_openlib, const char *path, int idcode) -{ - LinkNode *names = NULL; - - int totnames_dummy; - names = BLO_blendhandle_get_datablock_names(bpy_openlib, idcode, &totnames_dummy); - - int i = 0; - LinkNode *n = names; - while (n) { - BLO_library_link_named_part(main_tmp, &bpy_openlib, idcode, (char *)n->link); - n = (LinkNode *)n->next; - i++; - } - BLI_linklist_free(names, free); /* free linklist *and* each node's data */ -} - -KX_LibLoadStatus *KX_BlenderSceneConverter::LinkBlendFile(BlendHandle *bpy_openlib, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options) -{ - Main *main_newlib; /* stored as a dynamic 'main' until we free it */ - const int idcode = BKE_idcode_from_name(group); - ReportList reports; - static char err_local[255]; - -// TIMEIT_START(bge_link_blend_file); - - KX_LibLoadStatus *status; - - /* only scene and mesh supported right now */ - if (idcode != ID_SCE && idcode != ID_ME && idcode != ID_AC) { - snprintf(err_local, sizeof(err_local), "invalid ID type given \"%s\"\n", group); - *err_str = err_local; - BLO_blendhandle_close(bpy_openlib); - return NULL; - } - - if (GetMainDynamicPath(path)) { - snprintf(err_local, sizeof(err_local), "blend file already open \"%s\"\n", path); - *err_str = err_local; - BLO_blendhandle_close(bpy_openlib); - return NULL; - } - - if (bpy_openlib == NULL) { - snprintf(err_local, sizeof(err_local), "could not open blendfile \"%s\"\n", path); - *err_str = err_local; - return NULL; - } - - main_newlib = BKE_main_new(); - BKE_reports_init(&reports, RPT_STORE); - - short flag = 0; /* don't need any special options */ - /* created only for linking, then freed */ - Main *main_tmp = BLO_library_link_begin(main_newlib, &bpy_openlib, (char *)path); - - load_datablocks(main_tmp, bpy_openlib, path, idcode); - - if (idcode == ID_SCE && options & LIB_LOAD_LOAD_SCRIPTS) { - load_datablocks(main_tmp, bpy_openlib, path, ID_TXT); - } - - /* now do another round of linking for Scenes so all actions are properly loaded */ - if (idcode == ID_SCE && options & LIB_LOAD_LOAD_ACTIONS) { - load_datablocks(main_tmp, bpy_openlib, path, ID_AC); - } - - BLO_library_link_end(main_tmp, &bpy_openlib, flag, NULL, NULL); - - BLO_blendhandle_close(bpy_openlib); - - BKE_reports_clear(&reports); - /* done linking */ - - /* needed for lookups*/ - GetMainDynamic().push_back(main_newlib); - BLI_strncpy(main_newlib->name, path, sizeof(main_newlib->name)); - - - status = new KX_LibLoadStatus(this, m_ketsjiEngine, scene_merge, path); - - if (idcode == ID_ME) { - /* Convert all new meshes into BGE meshes */ - ID *mesh; - - for (mesh = (ID *)main_newlib->mesh.first; mesh; mesh = (ID *)mesh->next ) { - if (options & LIB_LOAD_VERBOSE) - printf("MeshName: %s\n", mesh->name + 2); - RAS_MeshObject *meshobj = BL_ConvertMesh((Mesh *)mesh, NULL, scene_merge, this, false); // For now only use the libloading option for scenes, which need to handle materials/shaders - scene_merge->GetLogicManager()->RegisterMeshName(meshobj->GetName(), meshobj); - } - } - else if (idcode == ID_AC) { - /* Convert all actions */ - ID *action; - - for (action= (ID *)main_newlib->action.first; action; action = (ID *)action->next) { - if (options & LIB_LOAD_VERBOSE) - printf("ActionName: %s\n", action->name + 2); - scene_merge->GetLogicManager()->RegisterActionName(action->name + 2, action); - } - } - else if (idcode == ID_SCE) { - /* Merge all new linked in scene into the existing one */ - ID *scene; - // scenes gets deleted by the thread when it's done using it (look in async_convert()) - vector *scenes = (options & LIB_LOAD_ASYNC) ? new vector() : NULL; - - for (scene = (ID *)main_newlib->scene.first; scene; scene = (ID *)scene->next ) { - if (options & LIB_LOAD_VERBOSE) - printf("SceneName: %s\n", scene->name + 2); - - if (options & LIB_LOAD_ASYNC) { - scenes->push_back((Scene *)scene); - } - else { - /* merge into the base scene */ - KX_Scene* other = m_ketsjiEngine->CreateScene((Scene *)scene, true); - scene_merge->MergeScene(other); - - // RemoveScene(other); // Don't run this, it frees the entire scene converter data, just delete the scene - delete other; - } - } - - if (options & LIB_LOAD_ASYNC) { - status->SetData(scenes); - BLI_task_pool_push(m_threadinfo->m_pool, async_convert, (void *)status, false, TASK_PRIORITY_LOW); - } - -#ifdef WITH_PYTHON - /* Handle any text datablocks */ - if (options & LIB_LOAD_LOAD_SCRIPTS) - addImportMain(main_newlib); -#endif - - /* Now handle all the actions */ - if (options & LIB_LOAD_LOAD_ACTIONS) { - ID *action; - - for (action = (ID *)main_newlib->action.first; action; action = (ID *)action->next) { - if (options & LIB_LOAD_VERBOSE) - printf("ActionName: %s\n", action->name + 2); - scene_merge->GetLogicManager()->RegisterActionName(action->name + 2, action); - } - } - } - - if (!(options & LIB_LOAD_ASYNC)) - status->Finish(); - -// TIMEIT_END(bge_link_blend_file); - - m_status_map[main_newlib->name] = status; - return status; -} - -/* Note m_map_*** are all ok and don't need to be freed - * most are temp and NewRemoveObject frees m_map_gameobject_to_blender */ -bool KX_BlenderSceneConverter::FreeBlendFile(Main *maggie) -{ - int maggie_index = -1; - int i = 0; - - if (maggie == NULL) - return false; - - // If the given library is currently in loading, we do nothing. - if (m_status_map.count(maggie->name)) { - BLI_mutex_lock(&m_threadinfo->m_mutex); - const bool finished = m_status_map[maggie->name]->IsFinished(); - BLI_mutex_unlock(&m_threadinfo->m_mutex); - - if (!finished) { - printf("Library (%s) is currently being loaded asynchronously, and cannot be freed until this process is done\n", maggie->name); - return false; - } - } - - /* tag all false except the one we remove */ - for (vector
::iterator it = m_DynamicMaggie.begin(); !(it == m_DynamicMaggie.end()); it++) { - Main *main = *it; - if (main != maggie) { - BKE_main_id_tag_all(main, LIB_TAG_DOIT, false); - } - else { - maggie_index = i; - } - i++; - } - - /* should never happen but just to be safe */ - if (maggie_index == -1) - return false; - - m_DynamicMaggie.erase(m_DynamicMaggie.begin() + maggie_index); - BKE_main_id_tag_all(maggie, LIB_TAG_DOIT, true); - - /* free all tagged objects */ - KX_SceneList *scenes = m_ketsjiEngine->CurrentScenes(); - int numScenes = scenes->size(); - - for (int scene_idx = 0; scene_idx < numScenes; scene_idx++) { - KX_Scene *scene = scenes->at(scene_idx); - if (IS_TAGGED(scene->GetBlenderScene())) { - m_ketsjiEngine->RemoveScene(scene->GetName()); - m_mat_cache.erase(scene); - m_polymat_cache.erase(scene); - scene_idx--; - numScenes--; - } - else { - /* in case the mesh might be refered to later */ - { - CTR_Map &mapStringToMeshes = scene->GetLogicManager()->GetMeshMap(); - - for (int i = 0; i < mapStringToMeshes.size(); i++) { - RAS_MeshObject *meshobj = (RAS_MeshObject *) *mapStringToMeshes.at(i); - if (meshobj && IS_TAGGED(meshobj->GetMesh())) { - STR_HashedString mn = meshobj->GetName(); - mapStringToMeshes.remove(mn); - m_map_mesh_to_gamemesh.remove(CHashedPtr(meshobj->GetMesh())); - i--; - } - } - } - - /* Now unregister actions */ - { - CTR_Map &mapStringToActions = scene->GetLogicManager()->GetActionMap(); - - for (int i = 0; i < mapStringToActions.size(); i++) { - ID *action = (ID*) *mapStringToActions.at(i); - - if (IS_TAGGED(action)) { - STR_HashedString an = action->name + 2; - mapStringToActions.remove(an); - m_map_blender_to_gameAdtList.remove(CHashedPtr(action)); - i--; - } - } - } - - //scene->FreeTagged(); /* removed tagged objects and meshes*/ - CListValue *obj_lists[] = {scene->GetObjectList(), scene->GetInactiveList(), NULL}; - - for (int ob_ls_idx = 0; obj_lists[ob_ls_idx]; ob_ls_idx++) { - CListValue *obs = obj_lists[ob_ls_idx]; - RAS_MeshObject *mesh; - - for (int ob_idx = 0; ob_idx < obs->GetCount(); ob_idx++) { - KX_GameObject *gameobj = (KX_GameObject*)obs->GetValue(ob_idx); - if (IS_TAGGED(gameobj->GetBlenderObject())) { - int size_before = obs->GetCount(); - - /* Eventually calls RemoveNodeDestructObject - * frees m_map_gameobject_to_blender from UnregisterGameObject */ - scene->RemoveObject(gameobj); - - if (size_before != obs->GetCount()) - ob_idx--; - else { - printf("ERROR COULD NOT REMOVE \"%s\"\n", gameobj->GetName().ReadPtr()); - } - } - else { - gameobj->RemoveTaggedActions(); - /* free the mesh, we could be referecing a linked one! */ - int mesh_index = gameobj->GetMeshCount(); - while (mesh_index--) { - mesh = gameobj->GetMesh(mesh_index); - if (IS_TAGGED(mesh->GetMesh())) { - gameobj->RemoveMeshes(); /* XXX - slack, should only remove meshes that are library items but mostly objects only have 1 mesh */ - break; - } - else { - /* also free the mesh if it's using a tagged material */ - int mat_index = mesh->NumMaterials(); - while (mat_index--) { - if (IS_TAGGED(mesh->GetMeshMaterial(mat_index)->m_bucket->GetPolyMaterial()->GetBlenderMaterial())) { - gameobj->RemoveMeshes(); /* XXX - slack, same as above */ - break; - } - } - } - } - - /* make sure action actuators are not referencing tagged actions */ - for (unsigned int act_idx = 0; act_idx < gameobj->GetActuators().size(); act_idx++) { - if (gameobj->GetActuators()[act_idx]->IsType(SCA_IActuator::KX_ACT_ACTION)) { - BL_ActionActuator *act = (BL_ActionActuator *)gameobj->GetActuators()[act_idx]; - if (IS_TAGGED(act->GetAction())) - act->SetAction(NULL); - } - } - } - } - } - } - } - - int size; - - // delete the entities of this scene - /* TODO - */ -#if 0 - vector >::iterator worldit; - size = m_worldinfos.size(); - for (i=0, worldit=m_worldinfos.begin(); i KX_WorldInfoSet; - KX_WorldInfoSet worldset; - for (int scene_idx = 0; scene_idx < numScenes; scene_idx++) { - KX_Scene *scene = scenes->at(scene_idx); - if (scene->GetWorldInfo()) - worldset.insert(scene->GetWorldInfo()); - } - - vector >::iterator worldit; - size = m_worldinfos.size(); - for (i = 0, worldit = m_worldinfos.begin(); i < size;) { - if (worldit->second && (worldset.count(worldit->second)) == 0) { - delete worldit->second; - *worldit = m_worldinfos.back(); - m_worldinfos.pop_back(); - size--; - } - else { - i++; - worldit++; - } - } - worldset.clear(); - /* done freeing the worlds */ - - vector >::iterator polymit; - size = m_polymaterials.size(); - - for (i = 0, polymit = m_polymaterials.begin(); i < size; ) { - RAS_IPolyMaterial *mat = polymit->second; - Material *bmat = NULL; - - KX_BlenderMaterial *bl_mat = static_cast(mat); - bmat = bl_mat->GetBlenderMaterial(); - - if (IS_TAGGED(bmat)) { - /* only remove from bucket */ - polymit->first->GetBucketManager()->RemoveMaterial(mat); - } - - i++; - polymit++; - } - - for (i = 0, polymit = m_polymaterials.begin(); i < size; ) { - RAS_IPolyMaterial *mat = polymit->second; - Material *bmat = NULL; - - KX_BlenderMaterial *bl_mat = static_cast(mat); - bmat = bl_mat->GetBlenderMaterial(); - - if (IS_TAGGED(bmat)) { - // Remove the poly material coresponding to this Blender Material. - m_polymat_cache[polymit->first].erase(bmat); - delete polymit->second; - *polymit = m_polymaterials.back(); - m_polymaterials.pop_back(); - size--; - } else { - i++; - polymit++; - } - } - - vector >::iterator matit; - size = m_materials.size(); - for (i = 0, matit = m_materials.begin(); i < size; ) { - BL_Material *mat = matit->second; - if (IS_TAGGED(mat->material)) { - // Remove the bl material coresponding to this Blender Material. - m_mat_cache[matit->first].erase(mat->material); - delete matit->second; - *matit = m_materials.back(); - m_materials.pop_back(); - size--; - } - else { - i++; - matit++; - } - } - - vector >::iterator meshit; - RAS_BucketManager::BucketList::iterator bit; - list::iterator msit; - RAS_BucketManager::BucketList buckets; - - size = m_meshobjects.size(); - for (i = 0, meshit = m_meshobjects.begin(); i < size;) { - RAS_MeshObject *me = meshit->second; - if (IS_TAGGED(me->GetMesh())) { - // Before deleting the mesh object, make sure the rasterizer is - // no longer referencing it. - buckets = meshit->first->GetBucketManager()->GetSolidBuckets(); - for (bit = buckets.begin(); bit != buckets.end(); bit++) { - msit = (*bit)->msBegin(); - - while (msit != (*bit)->msEnd()) { - if (msit->m_mesh == meshit->second) - (*bit)->RemoveMesh(&(*msit++)); - else - msit++; - } - } - - // And now the alpha buckets - buckets = meshit->first->GetBucketManager()->GetAlphaBuckets(); - for (bit = buckets.begin(); bit != buckets.end(); bit++) { - msit = (*bit)->msBegin(); - - while (msit != (*bit)->msEnd()) { - if (msit->m_mesh == meshit->second) - (*bit)->RemoveMesh(&(*msit++)); - else - msit++; - } - } - - // Now it should be safe to delete - delete meshit->second; - *meshit = m_meshobjects.back(); - m_meshobjects.pop_back(); - size--; - } - else { - i++; - meshit++; - } - } - -#ifdef WITH_PYTHON - /* make sure this maggie is removed from the import list if it's there - * (this operation is safe if it isn't in the list) */ - removeImportMain(maggie); -#endif - - delete m_status_map[maggie->name]; - m_status_map.erase(maggie->name); - - BKE_main_free(maggie); - - return true; -} - -bool KX_BlenderSceneConverter::FreeBlendFile(const char *path) -{ - return FreeBlendFile(GetMainDynamicPath(path)); -} - -bool KX_BlenderSceneConverter::MergeScene(KX_Scene *to, KX_Scene *from) -{ - { - vector >::iterator itp = m_worldinfos.begin(); - while (itp != m_worldinfos.end()) { - if (itp->first == from) - itp->first = to; - itp++; - } - } - - { - vector >::iterator itp = m_polymaterials.begin(); - while (itp != m_polymaterials.end()) { - if (itp->first == from) { - itp->first = to; - - /* also switch internal data */ - RAS_IPolyMaterial *mat = itp->second; - mat->Replace_IScene(to); - } - itp++; - } - } - - { - vector >::iterator itp = m_meshobjects.begin(); - while (itp != m_meshobjects.end()) { - if (itp->first == from) - itp->first = to; - itp++; - } - } - - { - vector >::iterator itp = m_materials.begin(); - while (itp != m_materials.end()) { - if (itp->first == from) - itp->first = to; - itp++; - } - } - - MaterialCache::iterator matcacheit = m_mat_cache.find(from); - if (matcacheit != m_mat_cache.end()) { - // Merge cached BL_Material map. - m_mat_cache[to].insert(matcacheit->second.begin(), matcacheit->second.end()); - m_mat_cache.erase(matcacheit); - } - - PolyMaterialCache::iterator polymatcacheit = m_polymat_cache.find(from); - if (polymatcacheit != m_polymat_cache.end()) { - // Merge cached RAS_IPolyMaterial map. - m_polymat_cache[to].insert(polymatcacheit->second.begin(), polymatcacheit->second.end()); - m_polymat_cache.erase(polymatcacheit); - } - - return true; -} - -/* This function merges a mesh from the current scene into another main - * it does not convert */ -RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scene *kx_scene, Main *maggie, const char *name) -{ - /* Find a mesh in the current main */ - ID *me= static_cast(BLI_findstring(&m_maggie->mesh, name, offsetof(ID, name) + 2)); - Main *from_maggie = m_maggie; - - if (me == NULL) { - // The mesh wasn't in the current main, try any dynamic (i.e., LibLoaded) ones - vector
::iterator it; - - for (it = GetMainDynamic().begin(); it != GetMainDynamic().end(); it++) { - me = static_cast(BLI_findstring(&(*it)->mesh, name, offsetof(ID, name) + 2)); - from_maggie = *it; - - if (me) - break; - } - } - - if (me == NULL) { - printf("Could not be found \"%s\"\n", name); - return NULL; - } - - /* Watch this!, if its used in the original scene can cause big troubles */ - if (me->us > 0) { -#ifdef DEBUG - printf("Mesh has a user \"%s\"\n", name); -#endif - me = (ID*)BKE_mesh_copy(from_maggie, (Mesh*)me); - id_us_min(me); - } - BLI_remlink(&from_maggie->mesh, me); /* even if we made the copy it needs to be removed */ - BLI_addtail(&maggie->mesh, me); - - /* Must copy the materials this uses else we cant free them */ - { - Mesh *mesh = (Mesh *)me; - - /* ensure all materials are tagged */ - for (int i = 0; i < mesh->totcol; i++) { - if (mesh->mat[i]) - mesh->mat[i]->id.tag &= ~LIB_TAG_DOIT; - } - - for (int i = 0; i < mesh->totcol; i++) { - Material *mat_old = mesh->mat[i]; - - /* if its tagged its a replaced material */ - if (mat_old && (mat_old->id.tag & LIB_TAG_DOIT) == 0) { - Material *mat_old = mesh->mat[i]; - Material *mat_new = BKE_material_copy(from_maggie, mat_old); - - mat_new->id.tag |= LIB_TAG_DOIT; - id_us_min(&mat_old->id); - - BLI_remlink(&from_maggie->mat, mat_new); // BKE_material_copy uses G.main, and there is no BKE_material_copy_ex - BLI_addtail(&maggie->mat, mat_new); - - mesh->mat[i] = mat_new; - - /* the same material may be used twice */ - for (int j = i + 1; j < mesh->totcol; j++) { - if (mesh->mat[j] == mat_old) { - mesh->mat[j] = mat_new; - id_us_plus(&mat_new->id); - id_us_min(&mat_old->id); - } - } - } - } - } - - m_currentScene = kx_scene; // This needs to be set in case we LibLoaded earlier - RAS_MeshObject *meshobj = BL_ConvertMesh((Mesh *)me, NULL, kx_scene, this, false); - kx_scene->GetLogicManager()->RegisterMeshName(meshobj->GetName(),meshobj); - m_map_mesh_to_gamemesh.clear(); /* This is at runtime so no need to keep this, BL_ConvertMesh adds */ - return meshobj; -} diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.h b/source/gameengine/Converter/KX_BlenderSceneConverter.h deleted file mode 100644 index 3379f00c38a7..000000000000 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file KX_BlenderSceneConverter.h - * \ingroup bgeconv - */ - -#ifndef __KX_BLENDERSCENECONVERTER_H__ -#define __KX_BLENDERSCENECONVERTER_H__ - -#include "EXP_HashedPtr.h" -#include "CTR_Map.h" -#include - -#include "KX_ISceneConverter.h" -#include "KX_IpoConvert.h" - -#include - -using namespace std; - -class KX_WorldInfo; -class SCA_IActuator; -class SCA_IController; -class RAS_MeshObject; -class RAS_IPolyMaterial; -class BL_InterpolatorList; -class BL_Material; -struct Main; -struct Scene; -struct ThreadInfo; -struct Material; - -typedef map > MaterialCache; -typedef map > PolyMaterialCache; - -class KX_BlenderSceneConverter : public KX_ISceneConverter -{ - // Use vector of pairs to allow removal of entities between scene switch - vector > m_worldinfos; - vector > m_polymaterials; - vector > m_meshobjects; - vector > m_materials; - - vector m_mergequeue; - ThreadInfo *m_threadinfo; - - // Cached material conversions - MaterialCache m_mat_cache; - PolyMaterialCache m_polymat_cache; - - // Saved KX_LibLoadStatus objects - map m_status_map; - - // Should also have a list of collision shapes. - // For the time being this is held in KX_Scene::m_shapes - - CTR_Map m_map_blender_to_gameobject; /* cleared after conversion */ - CTR_Map m_map_mesh_to_gamemesh; /* cleared after conversion */ - CTR_Map m_map_blender_to_gameactuator; /* cleared after conversion */ - CTR_Mapm_map_blender_to_gamecontroller; /* cleared after conversion */ - - CTR_Map m_map_blender_to_gameAdtList; - - Main* m_maggie; - vector m_DynamicMaggie; - - STR_String m_newfilename; - class KX_KetsjiEngine* m_ketsjiEngine; - class KX_Scene* m_currentScene; // Scene being converted - bool m_alwaysUseExpandFraming; - bool m_usemat; - bool m_useglslmat; - bool m_use_mat_cache; - -public: - KX_BlenderSceneConverter( - Main* maggie, - class KX_KetsjiEngine* engine - ); - - virtual ~KX_BlenderSceneConverter(); - - /* Scenename: name of the scene to be converted. - * destinationscene: pass an empty scene, everything goes into this - * dictobj: python dictionary (for pythoncontrollers) - */ - virtual void ConvertScene( - class KX_Scene* destinationscene, - class RAS_IRasterizer* rendertools, - class RAS_ICanvas* canvas, - bool libloading=false - ); - virtual void RemoveScene(class KX_Scene *scene); - - void SetNewFileName(const STR_String& filename); - bool TryAndLoadNewFile(); - - void SetAlwaysUseExpandFraming(bool to_what); - - void RegisterGameObject(KX_GameObject *gameobject, struct Object *for_blenderobject); - void UnregisterGameObject(KX_GameObject *gameobject); - KX_GameObject *FindGameObject(struct Object *for_blenderobject); - - void RegisterGameMesh(RAS_MeshObject *gamemesh, struct Mesh *for_blendermesh); - RAS_MeshObject *FindGameMesh(struct Mesh *for_blendermesh/*, unsigned int onlayer*/); - - void RegisterPolyMaterial(RAS_IPolyMaterial *polymat); - void CachePolyMaterial(KX_Scene *scene, Material *mat, RAS_IPolyMaterial *polymat); - RAS_IPolyMaterial *FindCachedPolyMaterial(KX_Scene *scene, Material *mat); - - void RegisterBlenderMaterial(BL_Material *mat); - void CacheBlenderMaterial(KX_Scene *scene, Material *mat, BL_Material *blmat); - BL_Material *FindCachedBlenderMaterial(KX_Scene *scene, Material *mat); - - void RegisterInterpolatorList(BL_InterpolatorList *actList, struct bAction *for_act); - BL_InterpolatorList *FindInterpolatorList(struct bAction *for_act); - - void RegisterGameActuator(SCA_IActuator *act, struct bActuator *for_actuator); - SCA_IActuator *FindGameActuator(struct bActuator *for_actuator); - - void RegisterGameController(SCA_IController *cont, struct bController *for_controller); - SCA_IController *FindGameController(struct bController *for_controller); - - void RegisterWorldInfo(KX_WorldInfo *worldinfo); - - virtual void ResetPhysicsObjectsAnimationIpo(bool clearIpo); - - ///this is for reseting the position,rotation and scale of the gameobjet that is not dynamic - virtual void resetNoneDynamicObjectToIpo(); - - ///this generates ipo curves for position, rotation, allowing to use game physics in animation - virtual void WritePhysicsObjectToAnimationIpo(int frameNumber); - virtual void TestHandlesPhysicsObjectToAnimationIpo(); - - // use blender materials - virtual void SetMaterials(bool val); - virtual bool GetMaterials(); - - // use blender glsl materials - virtual void SetGLSLMaterials(bool val); - virtual bool GetGLSLMaterials(); - - // cache materials during conversion - virtual void SetCacheMaterials(bool val); - virtual bool GetCacheMaterials(); - - struct Scene* GetBlenderSceneForName(const STR_String& name); - -// struct Main* GetMain() { return m_maggie; } - struct Main* GetMainDynamicPath(const char *path); - vector &GetMainDynamic(); - - class KX_LibLoadStatus *LinkBlendFileMemory(void *data, int length, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options); - class KX_LibLoadStatus *LinkBlendFilePath(const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options); - class KX_LibLoadStatus *LinkBlendFile(struct BlendHandle *bpy_openlib, const char *path, char *group, KX_Scene *scene_merge, char **err_str, short options); - bool MergeScene(KX_Scene *to, KX_Scene *from); - RAS_MeshObject *ConvertMeshSpecial(KX_Scene* kx_scene, Main *maggie, const char *name); - bool FreeBlendFile(struct Main *maggie); - bool FreeBlendFile(const char *path); - - virtual void MergeAsyncLoads(); - virtual void FinalizeAsyncLoads(); - void AddScenesToMergeQueue(class KX_LibLoadStatus *status); - - void PrintStats() { - printf("BGE STATS!\n"); - - printf("\nAssets...\n"); - printf("\t m_worldinfos: %d\n", (int)m_worldinfos.size()); - printf("\t m_polymaterials: %d\n", (int)m_polymaterials.size()); - printf("\t m_meshobjects: %d\n", (int)m_meshobjects.size()); - printf("\t m_materials: %d\n", (int)m_materials.size()); - - printf("\nMappings...\n"); - printf("\t m_map_blender_to_gameobject: %d\n", m_map_blender_to_gameobject.size()); - printf("\t m_map_mesh_to_gamemesh: %d\n", m_map_mesh_to_gamemesh.size()); - printf("\t m_map_blender_to_gameactuator: %d\n", m_map_blender_to_gameactuator.size()); - printf("\t m_map_blender_to_gamecontroller: %d\n", m_map_blender_to_gamecontroller.size()); - printf("\t m_map_blender_to_gameAdtList: %d\n", m_map_blender_to_gameAdtList.size()); - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_printmemlist_pydict(); -#endif -// /printf("\t m_ketsjiEngine->m_scenes: %d\n", m_ketsjiEngine->CurrentScenes()->size()); - } - - /* LibLoad Options */ - enum - { - LIB_LOAD_LOAD_ACTIONS = 1, - LIB_LOAD_VERBOSE = 2, - LIB_LOAD_LOAD_SCRIPTS = 4, - LIB_LOAD_ASYNC = 8, - }; - - - -#ifdef WITH_PYTHON - PyObject *GetPyNamespace(); -#endif - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_BlenderSceneConverter") -#endif -}; - -#endif /* __KX_BLENDERSCENECONVERTER_H__ */ diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp deleted file mode 100644 index 92ea47e07561..000000000000 --- a/source/gameengine/Converter/KX_ConvertActuators.cpp +++ /dev/null @@ -1,1144 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - * Convert Blender actuators for use in the GameEngine - */ - -/** \file gameengine/Converter/KX_ConvertActuators.cpp - * \ingroup bgeconv - */ - -#ifdef _MSC_VER -# pragma warning (disable:4786) -#endif - -#include - -#include "MEM_guardedalloc.h" - -#include "KX_BlenderSceneConverter.h" -#include "KX_ConvertActuators.h" - -#ifdef WITH_AUDASPACE -# include AUD_SOUND_H -#endif - -// Actuators -//SCA logiclibrary native logicbricks -#include "SCA_PropertyActuator.h" -#include "SCA_LogicManager.h" -#include "SCA_RandomActuator.h" -#include "SCA_2DFilterActuator.h" - -// Ketsji specific logicbricks -#include "KX_SceneActuator.h" -#include "KX_SoundActuator.h" -#include "KX_ObjectActuator.h" -#include "KX_TrackToActuator.h" -#include "KX_ConstraintActuator.h" -#include "KX_CameraActuator.h" -#include "KX_GameActuator.h" -#include "KX_StateActuator.h" -#include "KX_VisibilityActuator.h" -#include "KX_SCA_AddObjectActuator.h" -#include "KX_SCA_EndObjectActuator.h" -#include "KX_SCA_ReplaceMeshActuator.h" -#include "KX_ParentActuator.h" -#include "KX_SCA_DynamicActuator.h" -#include "KX_SteeringActuator.h" -#include "KX_MouseActuator.h" - -#include "KX_Scene.h" -#include "KX_KetsjiEngine.h" - -#include "EXP_IntValue.h" -#include "KX_GameObject.h" - -/* This little block needed for linking to Blender... */ -#include "BKE_text.h" -#include "BLI_blenlib.h" -#include "BLI_math.h" -#include "BLI_path_util.h" - -#include "KX_NetworkMessageActuator.h" - -#ifdef WIN32 -#include "BLI_winstuff.h" -#endif - -#include "DNA_object_types.h" -#include "DNA_sound_types.h" -#include "DNA_scene_types.h" -#include "DNA_actuator_types.h" -#include "DNA_packedFile_types.h" -#include "BL_ActionActuator.h" -#include "BL_ShapeActionActuator.h" -#include "BL_ArmatureActuator.h" -#include "RNA_access.h" -#include "BL_Action.h" -/* end of blender include block */ - -#include "BL_BlenderDataConversion.h" - -/** - * KX_flt_trunc needed to round 'almost' zero values to zero, else velocities etc. are incorrectly set - */ - -BLI_INLINE float KX_flt_trunc(const float x) -{ - return ( x < 0.0001f && x > -0.0001f ) ? 0.0f : x; -} - -void BL_ConvertActuators(const char* maggiename, - struct Object* blenderobject, - KX_GameObject* gameobj, - SCA_LogicManager* logicmgr, - KX_Scene* scene, - KX_KetsjiEngine* ketsjiEngine, - int activeLayerBitInfo, - bool isInActiveLayer, - KX_BlenderSceneConverter* converter - ) -{ - - int uniqueint = 0; - int actcount = 0; - int executePriority = 0; - bActuator* bact = (bActuator*) blenderobject->actuators.first; - while (bact) - { - actcount++; - bact = bact->next; - } - gameobj->ReserveActuator(actcount); - bact = (bActuator*) blenderobject->actuators.first; - while (bact) - { - STR_String uniquename = bact->name; - STR_String& objectname = gameobj->GetName(); - - SCA_IActuator* baseact = NULL; - switch (bact->type) - { - case ACT_OBJECT: - { - bObjectActuator* obact = (bObjectActuator*) bact->data; - KX_GameObject* obref = NULL; - MT_Vector3 forcevec(KX_flt_trunc(obact->forceloc[0]), - KX_flt_trunc(obact->forceloc[1]), - KX_flt_trunc(obact->forceloc[2])); - MT_Vector3 torquevec(obact->forcerot[0], - obact->forcerot[1], - obact->forcerot[2]); - MT_Vector3 dlocvec(KX_flt_trunc(obact->dloc[0]), - KX_flt_trunc(obact->dloc[1]), - KX_flt_trunc(obact->dloc[2])); - MT_Vector3 drotvec(KX_flt_trunc(obact->drot[0]), - obact->drot[1],obact->drot[2]); - MT_Vector3 linvelvec(KX_flt_trunc(obact->linearvelocity[0]), - KX_flt_trunc(obact->linearvelocity[1]), - KX_flt_trunc(obact->linearvelocity[2])); - MT_Vector3 angvelvec(KX_flt_trunc(obact->angularvelocity[0]), - KX_flt_trunc(obact->angularvelocity[1]), - KX_flt_trunc(obact->angularvelocity[2])); - short damping = obact->damping; - - /* Blender uses a bit vector internally for the local-flags. In */ - /* KX, we have four bools. The compiler should be smart enough */ - /* to do the right thing. We need to explicitly convert here! */ - - KX_LocalFlags bitLocalFlag; - - bitLocalFlag.Force = bool((obact->flag & ACT_FORCE_LOCAL)!=0); - bitLocalFlag.Torque = bool((obact->flag & ACT_TORQUE_LOCAL) !=0);//rlocal; - bitLocalFlag.DLoc = bool((obact->flag & ACT_DLOC_LOCAL)!=0); - bitLocalFlag.DRot = bool((obact->flag & ACT_DROT_LOCAL)!=0); - bitLocalFlag.LinearVelocity = bool((obact->flag & ACT_LIN_VEL_LOCAL)!=0); - bitLocalFlag.AngularVelocity = bool((obact->flag & ACT_ANG_VEL_LOCAL)!=0); - bitLocalFlag.ServoControl = bool(obact->type == ACT_OBJECT_SERVO); - bitLocalFlag.CharacterMotion = bool(obact->type == ACT_OBJECT_CHARACTER); - bitLocalFlag.CharacterJump = bool((obact->flag & ACT_CHAR_JUMP)!=0); - bitLocalFlag.AddOrSetLinV = bool((obact->flag & ACT_ADD_LIN_VEL)!=0); - bitLocalFlag.AddOrSetCharLoc = bool((obact->flag & ACT_ADD_CHAR_LOC)!=0); - if (obact->reference && bitLocalFlag.ServoControl) - { - obref = converter->FindGameObject(obact->reference); - } - - KX_ObjectActuator* tmpbaseact = new KX_ObjectActuator( - gameobj, - obref, - forcevec.getValue(), - torquevec.getValue(), - dlocvec.getValue(), - drotvec.getValue(), - linvelvec.getValue(), - angvelvec.getValue(), - damping, - bitLocalFlag); - baseact = tmpbaseact; - break; - } - case ACT_ACTION: - { - bActionActuator* actact = (bActionActuator*) bact->data; - STR_String propname = actact->name; - STR_String propframe = actact->frameProp; - - short ipo_flags = 0; - - // Convert flags - if (actact->flag & ACT_IPOFORCE) ipo_flags |= BL_Action::ACT_IPOFLAG_FORCE; - if (actact->flag & ACT_IPOLOCAL) ipo_flags |= BL_Action::ACT_IPOFLAG_LOCAL; - if (actact->flag & ACT_IPOADD) ipo_flags |= BL_Action::ACT_IPOFLAG_ADD; - if (actact->flag & ACT_IPOCHILD) ipo_flags |= BL_Action::ACT_IPOFLAG_CHILD; - - BL_ActionActuator* tmpbaseact = new BL_ActionActuator( - gameobj, - propname, - propframe, - actact->sta, - actact->end, - actact->act, - actact->type, // + 1, because Blender starts to count at zero, - actact->blend_mode, - actact->blendin, - actact->priority, - actact->layer, - actact->layer_weight, - ipo_flags, - actact->end_reset, - actact->stridelength - // Ketsji at 1, because zero is reserved for "NoDef" - ); - baseact= tmpbaseact; - break; - } - case ACT_SHAPEACTION: - { - if (blenderobject->type==OB_MESH) { - bActionActuator* actact = (bActionActuator*) bact->data; - STR_String propname = actact->name; - STR_String propframe = actact->frameProp; - - BL_ShapeActionActuator* tmpbaseact = new BL_ShapeActionActuator( - gameobj, - propname, - propframe, - actact->sta, - actact->end, - actact->act, - actact->type, // + 1, because Blender starts to count at zero, - actact->blendin, - actact->priority, - actact->stridelength); - // Ketsji at 1, because zero is reserved for "NoDef" - baseact= tmpbaseact; - break; - } - else - printf ("Discarded shape action actuator from non-mesh object [%s]\n", blenderobject->id.name+2); - } - case ACT_LAMP: - { - break; - } - case ACT_CAMERA: - { - bCameraActuator *camact = (bCameraActuator *) bact->data; - if (camact->ob) { - KX_GameObject *tmpgob = converter->FindGameObject(camact->ob); - - /* visifac, fac and axis are not copied from the struct... */ - /* that's some internal state... */ - KX_CameraActuator *tmpcamact = new KX_CameraActuator( - gameobj, - tmpgob, - camact->height, - camact->min, - camact->max, - camact->axis, - camact->damping); - baseact = tmpcamact; - } - break; - } - case ACT_MESSAGE: - { - bMessageActuator *msgAct = (bMessageActuator *) bact->data; - - /* Get the name of the properties that objects must own that - * we're sending to, if present - */ - STR_String toPropName = msgAct->toPropName; - - /* Get the Message Subject to send. - */ - STR_String subject = msgAct->subject; - - /* Get the bodyType - */ - int bodyType = msgAct->bodyType; - - /* Get the body (text message or property name whose value - * we'll be sending, might be empty - */ - const STR_String body = msgAct->body; - - KX_NetworkMessageActuator *tmpmsgact = new KX_NetworkMessageActuator( - gameobj, // actuator controlling object - scene->GetNetworkScene(), // needed for replication - toPropName, - subject, - bodyType, - body); - baseact = tmpmsgact; - break; - } - case ACT_MATERIAL: - { - break; - } - case ACT_SOUND: - { - bSoundActuator* soundact = (bSoundActuator*) bact->data; - /* get type, and possibly a start and end frame */ - KX_SoundActuator::KX_SOUNDACT_TYPE - soundActuatorType = KX_SoundActuator::KX_SOUNDACT_NODEF; - - switch (soundact->type) { - case ACT_SND_PLAY_STOP_SOUND: - soundActuatorType = KX_SoundActuator::KX_SOUNDACT_PLAYSTOP; - break; - case ACT_SND_PLAY_END_SOUND: - soundActuatorType = KX_SoundActuator::KX_SOUNDACT_PLAYEND; - break; - case ACT_SND_LOOP_STOP_SOUND: - soundActuatorType = KX_SoundActuator::KX_SOUNDACT_LOOPSTOP; - break; - case ACT_SND_LOOP_END_SOUND: - soundActuatorType = KX_SoundActuator::KX_SOUNDACT_LOOPEND; - break; - case ACT_SND_LOOP_BIDIRECTIONAL_SOUND: - soundActuatorType = KX_SoundActuator::KX_SOUNDACT_LOOPBIDIRECTIONAL; - break; - case ACT_SND_LOOP_BIDIRECTIONAL_STOP_SOUND: - soundActuatorType = KX_SoundActuator::KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP; - break; - - default: - /* This is an error!!! */ - soundActuatorType = KX_SoundActuator::KX_SOUNDACT_NODEF; - } - - if (soundActuatorType != KX_SoundActuator::KX_SOUNDACT_NODEF) - { - bSound* sound = soundact->sound; - bool is3d = soundact->flag & ACT_SND_3D_SOUND ? true : false; - AUD_Sound* snd_sound = NULL; - KX_3DSoundSettings settings; - settings.cone_inner_angle = RAD2DEGF(soundact->sound3D.cone_inner_angle); - settings.cone_outer_angle = RAD2DEGF(soundact->sound3D.cone_outer_angle); - settings.cone_outer_gain = soundact->sound3D.cone_outer_gain; - settings.max_distance = soundact->sound3D.max_distance; - settings.max_gain = soundact->sound3D.max_gain; - settings.min_gain = soundact->sound3D.min_gain; - settings.reference_distance = soundact->sound3D.reference_distance; - settings.rolloff_factor = soundact->sound3D.rolloff_factor; - - if (!sound) - { - std::cout << "WARNING: Sound actuator \"" << bact->name << - "\" from object \"" << blenderobject->id.name+2 << - "\" has no sound datablock." << std::endl; - } - else - { - snd_sound = sound->playback_handle; - - // if sound shall be 3D but isn't mono, we have to make it mono! - if (is3d) - { - snd_sound = AUD_Sound_rechannel(snd_sound, AUD_CHANNELS_MONO); - } - } - KX_SoundActuator* tmpsoundact = - new KX_SoundActuator(gameobj, - snd_sound, - soundact->volume, - (float)(expf((soundact->pitch / 12.0f) * (float)M_LN2)), - is3d, - settings, - soundActuatorType); - - // if we made it mono, we have to free it - if (sound && snd_sound && snd_sound != sound->playback_handle) { - AUD_Sound_free(snd_sound); - } - - tmpsoundact->SetName(bact->name); - baseact = tmpsoundact; - } - break; - } - case ACT_PROPERTY: - { - bPropertyActuator* propact = (bPropertyActuator*) bact->data; - SCA_IObject* destinationObj = NULL; - - /* - * here the destinationobject is searched. problem with multiple scenes: other scenes - * have not been converted yet, so the destobj will not be found, so the prop will - * not be copied. - * possible solutions: - * - convert everything when possible and not realtime only when needed. - * - let the object-with-property report itself to the act when converted - */ - if (propact->ob) - destinationObj = converter->FindGameObject(propact->ob); - - SCA_PropertyActuator* tmppropact = new SCA_PropertyActuator( - gameobj, - destinationObj, - propact->name, - propact->value, - propact->type + 1); // + 1 because Ketsji Logic starts - // with 0 for KX_ACT_PROP_NODEF - baseact = tmppropact; - break; - } - case ACT_EDIT_OBJECT: - { - bEditObjectActuator *editobact - = (bEditObjectActuator *) bact->data; - /* There are four different kinds of 'edit object' thingies */ - /* The alternative to this lengthy conversion is packing */ - /* several actuators in one, which is not very nice design.. */ - switch (editobact->type) { - case ACT_EDOB_ADD_OBJECT: - { - - // does the 'original' for replication exists, and - // is it in a non-active layer ? - SCA_IObject* originalval = NULL; - if (editobact->ob) - { - if (editobact->ob->lay & activeLayerBitInfo) - { - fprintf(stderr, "Warning, object \"%s\" from AddObject actuator \"%s\" is not in a hidden layer.\n", objectname.Ptr(), uniquename.Ptr()); - } - else { - originalval = converter->FindGameObject(editobact->ob); - } - } - - KX_SCA_AddObjectActuator* tmpaddact = new KX_SCA_AddObjectActuator( - gameobj, - originalval, - editobact->time, - scene, - editobact->linVelocity, - (editobact->localflag & ACT_EDOB_LOCAL_LINV) != 0, - editobact->angVelocity, - (editobact->localflag & ACT_EDOB_LOCAL_ANGV) != 0); - - //editobact->ob to gameobj - baseact = tmpaddact; - } - break; - case ACT_EDOB_END_OBJECT: - { - KX_SCA_EndObjectActuator* tmpendact - = new KX_SCA_EndObjectActuator(gameobj,scene); - baseact = tmpendact; - } - break; - case ACT_EDOB_REPLACE_MESH: - { - RAS_MeshObject *tmpmesh = converter->FindGameMesh(editobact->me); - - if (!tmpmesh) { - std::cout << "Warning: object \"" << objectname << - "\" from ReplaceMesh actuator \"" << uniquename << - "\" uses a mesh not owned by an object in scene \"" << - scene->GetName() << "\"." << std::endl; - } - - KX_SCA_ReplaceMeshActuator* tmpreplaceact = new KX_SCA_ReplaceMeshActuator( - gameobj, - tmpmesh, - scene, - (editobact->flag & ACT_EDOB_REPLACE_MESH_NOGFX) == 0, - (editobact->flag & ACT_EDOB_REPLACE_MESH_PHYS) != 0); - - baseact = tmpreplaceact; - } - break; - case ACT_EDOB_TRACK_TO: - { - SCA_IObject* originalval = NULL; - if (editobact->ob) - originalval = converter->FindGameObject(editobact->ob); - - KX_TrackToActuator* tmptrackact = new KX_TrackToActuator( - gameobj, - originalval, - editobact->time, - editobact->flag, - editobact->trackflag, - editobact->upflag); - baseact = tmptrackact; - break; - } - case ACT_EDOB_DYNAMICS: - { - KX_SCA_DynamicActuator* tmpdynact = new KX_SCA_DynamicActuator( - gameobj, - editobact->dyn_operation, - editobact->mass); - baseact = tmpdynact; - } - } - break; - } - case ACT_CONSTRAINT: - { - float min = 0.0, max = 0.0; - char *prop = NULL; - KX_ConstraintActuator::KX_CONSTRAINTTYPE locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_NODEF; - bConstraintActuator *conact - = (bConstraintActuator*) bact->data; - /* convert settings... degrees in the ui become radians */ - /* internally */ - if (conact->type == ACT_CONST_TYPE_ORI) { - min = conact->minloc[0]; - max = conact->maxloc[0]; - switch (conact->mode) { - case ACT_CONST_DIRPX: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ORIX; - break; - case ACT_CONST_DIRPY: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ORIY; - break; - case ACT_CONST_DIRPZ: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ORIZ; - break; - } - } else if (conact->type == ACT_CONST_TYPE_DIST) { - switch (conact->mode) { - case ACT_CONST_DIRPX: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRPX; - min = conact->minloc[0]; - max = conact->maxloc[0]; - break; - case ACT_CONST_DIRPY: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRPY; - min = conact->minloc[1]; - max = conact->maxloc[1]; - break; - case ACT_CONST_DIRPZ: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRPZ; - min = conact->minloc[2]; - max = conact->maxloc[2]; - break; - case ACT_CONST_DIRNX: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRNX; - min = conact->minloc[0]; - max = conact->maxloc[0]; - break; - case ACT_CONST_DIRNY: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRNY; - min = conact->minloc[1]; - max = conact->maxloc[1]; - break; - case ACT_CONST_DIRNZ: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_DIRNZ; - min = conact->minloc[2]; - max = conact->maxloc[2]; - break; - } - prop = conact->matprop; - } else if (conact->type == ACT_CONST_TYPE_FH) { - switch (conact->mode) { - case ACT_CONST_DIRPX: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHPX; - min = conact->minloc[0]; - max = conact->maxloc[0]; - break; - case ACT_CONST_DIRPY: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHPY; - min = conact->minloc[1]; - max = conact->maxloc[1]; - break; - case ACT_CONST_DIRPZ: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHPZ; - min = conact->minloc[2]; - max = conact->maxloc[2]; - break; - case ACT_CONST_DIRNX: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHNX; - min = conact->minloc[0]; - max = conact->maxloc[0]; - break; - case ACT_CONST_DIRNY: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHNY; - min = conact->minloc[1]; - max = conact->maxloc[1]; - break; - case ACT_CONST_DIRNZ: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_FHNZ; - min = conact->minloc[2]; - max = conact->maxloc[2]; - break; - } - prop = conact->matprop; - } else { - switch (conact->flag) { - case ACT_CONST_LOCX: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCX; - min = conact->minloc[0]; - max = conact->maxloc[0]; - break; - case ACT_CONST_LOCY: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCY; - min = conact->minloc[1]; - max = conact->maxloc[1]; - break; - case ACT_CONST_LOCZ: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCZ; - min = conact->minloc[2]; - max = conact->maxloc[2]; - break; - case ACT_CONST_ROTX: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTX; - min = conact->minrot[0] * (float)MT_RADS_PER_DEG; - max = conact->maxrot[0] * (float)MT_RADS_PER_DEG; - break; - case ACT_CONST_ROTY: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTY; - min = conact->minrot[1] * (float)MT_RADS_PER_DEG; - max = conact->maxrot[1] * (float)MT_RADS_PER_DEG; - break; - case ACT_CONST_ROTZ: - locrot = KX_ConstraintActuator::KX_ACT_CONSTRAINT_ROTZ; - min = conact->minrot[2] * (float)MT_RADS_PER_DEG; - max = conact->maxrot[2] * (float)MT_RADS_PER_DEG; - break; - default: - ; /* error */ - } - } - KX_ConstraintActuator *tmpconact = new KX_ConstraintActuator( - gameobj, - conact->damp, - conact->rotdamp, - min, - max, - conact->maxrot, - locrot, - conact->time, - conact->flag, - prop); - baseact = tmpconact; - break; - } - case ACT_GROUP: - { - // deprecated - } - break; - case ACT_SCENE: - { - bSceneActuator *sceneact = (bSceneActuator *) bact->data; - STR_String nextSceneName(""); - - KX_SceneActuator* tmpsceneact; - int mode = KX_SceneActuator::KX_SCENE_NODEF; - KX_Camera *cam = NULL; - //KX_Scene* scene = NULL; - switch (sceneact->type) - { - case ACT_SCENE_RESUME: - case ACT_SCENE_SUSPEND: - case ACT_SCENE_ADD_FRONT: - case ACT_SCENE_ADD_BACK: - case ACT_SCENE_REMOVE: - case ACT_SCENE_SET: - { - switch (sceneact->type) - { - case ACT_SCENE_RESUME: - mode = KX_SceneActuator::KX_SCENE_RESUME; - break; - case ACT_SCENE_SUSPEND: - mode = KX_SceneActuator::KX_SCENE_SUSPEND; - break; - case ACT_SCENE_ADD_FRONT: - mode = KX_SceneActuator::KX_SCENE_ADD_FRONT_SCENE; - break; - case ACT_SCENE_ADD_BACK: - mode = KX_SceneActuator::KX_SCENE_ADD_BACK_SCENE; - break; - case ACT_SCENE_REMOVE: - mode = KX_SceneActuator::KX_SCENE_REMOVE_SCENE; - break; - case ACT_SCENE_SET: - default: - mode = KX_SceneActuator::KX_SCENE_SET_SCENE; - break; - }; - - if (sceneact->scene) { - nextSceneName = sceneact->scene->id.name + 2; - } - - break; - } - case ACT_SCENE_CAMERA: - mode = KX_SceneActuator::KX_SCENE_SET_CAMERA; - if (sceneact->camera) - { - KX_GameObject *tmp = converter->FindGameObject(sceneact->camera); - if (tmp && tmp->GetGameObjectType() == SCA_IObject::OBJ_CAMERA) - cam = (KX_Camera*)tmp; - } - break; - case ACT_SCENE_RESTART: - { - - mode = KX_SceneActuator::KX_SCENE_RESTART; - break; - } - default: - ; /* flag error */ - } - tmpsceneact = new KX_SceneActuator( - gameobj, - mode, - scene, - ketsjiEngine, - nextSceneName, - cam); - baseact = tmpsceneact; - break; - } - case ACT_GAME: - { - bGameActuator *gameact = (bGameActuator *) bact->data; - KX_GameActuator* tmpgameact; - STR_String filename = maggiename; - STR_String loadinganimationname = ""; - int mode = KX_GameActuator::KX_GAME_NODEF; - switch (gameact->type) - { - case ACT_GAME_LOAD: - { - mode = KX_GameActuator::KX_GAME_LOAD; - filename = gameact->filename; - loadinganimationname = gameact->loadaniname; - break; - } - case ACT_GAME_START: - { - mode = KX_GameActuator::KX_GAME_START; - filename = gameact->filename; - loadinganimationname = gameact->loadaniname; - break; - } - case ACT_GAME_RESTART: - { - mode = KX_GameActuator::KX_GAME_RESTART; - break; - } - case ACT_GAME_QUIT: - { - mode = KX_GameActuator::KX_GAME_QUIT; - break; - } - case ACT_GAME_SAVECFG: - { - mode = KX_GameActuator::KX_GAME_SAVECFG; - break; - } - case ACT_GAME_LOADCFG: - { - mode = KX_GameActuator::KX_GAME_LOADCFG; - break; - } - case ACT_GAME_SCREENSHOT: - { - mode = KX_GameActuator::KX_GAME_SCREENSHOT; - filename = gameact->filename; - break; - } - default: - ; /* flag error */ - } - tmpgameact = new KX_GameActuator( - gameobj, - mode, - filename, - loadinganimationname, - scene, - ketsjiEngine); - baseact = tmpgameact; - - break; - } - case ACT_RANDOM: - { - bRandomActuator *randAct - = (bRandomActuator *) bact->data; - - unsigned long seedArg = randAct->seed; - if (seedArg == 0) - { - seedArg = (int)(ketsjiEngine->GetRealTime()*100000.0); - seedArg ^= (intptr_t)randAct; - } - SCA_RandomActuator::KX_RANDOMACT_MODE modeArg - = SCA_RandomActuator::KX_RANDOMACT_NODEF; - SCA_RandomActuator *tmprandomact; - float paraArg1 = 0.0; - float paraArg2 = 0.0; - - switch (randAct->distribution) { - case ACT_RANDOM_BOOL_CONST: - modeArg = SCA_RandomActuator::KX_RANDOMACT_BOOL_CONST; - paraArg1 = (float) randAct->int_arg_1; - break; - case ACT_RANDOM_BOOL_UNIFORM: - modeArg = SCA_RandomActuator::KX_RANDOMACT_BOOL_UNIFORM; - break; - case ACT_RANDOM_BOOL_BERNOUILLI: - paraArg1 = randAct->float_arg_1; - modeArg = SCA_RandomActuator::KX_RANDOMACT_BOOL_BERNOUILLI; - break; - case ACT_RANDOM_INT_CONST: - modeArg = SCA_RandomActuator::KX_RANDOMACT_INT_CONST; - paraArg1 = (float) randAct->int_arg_1; - break; - case ACT_RANDOM_INT_UNIFORM: - paraArg1 = (float) randAct->int_arg_1; - paraArg2 = (float) randAct->int_arg_2; - modeArg = SCA_RandomActuator::KX_RANDOMACT_INT_UNIFORM; - break; - case ACT_RANDOM_INT_POISSON: - paraArg1 = randAct->float_arg_1; - modeArg = SCA_RandomActuator::KX_RANDOMACT_INT_POISSON; - break; - case ACT_RANDOM_FLOAT_CONST: - paraArg1 = randAct->float_arg_1; - modeArg = SCA_RandomActuator::KX_RANDOMACT_FLOAT_CONST; - break; - case ACT_RANDOM_FLOAT_UNIFORM: - paraArg1 = randAct->float_arg_1; - paraArg2 = randAct->float_arg_2; - modeArg = SCA_RandomActuator::KX_RANDOMACT_FLOAT_UNIFORM; - break; - case ACT_RANDOM_FLOAT_NORMAL: - paraArg1 = randAct->float_arg_1; - paraArg2 = randAct->float_arg_2; - modeArg = SCA_RandomActuator::KX_RANDOMACT_FLOAT_NORMAL; - break; - case ACT_RANDOM_FLOAT_NEGATIVE_EXPONENTIAL: - paraArg1 = randAct->float_arg_1; - modeArg = SCA_RandomActuator::KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL; - break; - default: - ; /* error */ - } - tmprandomact = new SCA_RandomActuator( - gameobj, - seedArg, - modeArg, - paraArg1, - paraArg2, - randAct->propname); - baseact = tmprandomact; - } - break; - - case ACT_VISIBILITY: - { - bVisibilityActuator *vis_act = (bVisibilityActuator *) bact->data; - KX_VisibilityActuator * tmp_vis_act = NULL; - bool v = ((vis_act->flag & ACT_VISIBILITY_INVISIBLE) != 0); - bool o = ((vis_act->flag & ACT_VISIBILITY_OCCLUSION) != 0); - bool recursive = ((vis_act->flag & ACT_VISIBILITY_RECURSIVE) != 0); - - tmp_vis_act = new KX_VisibilityActuator(gameobj, !v, o, recursive); - - baseact = tmp_vis_act; - } - break; - - case ACT_STATE: - { - bStateActuator *sta_act = (bStateActuator *) bact->data; - KX_StateActuator * tmp_sta_act = NULL; - - tmp_sta_act = - new KX_StateActuator(gameobj, sta_act->type, sta_act->mask); - - baseact = tmp_sta_act; - } - break; - - case ACT_2DFILTER: - { - bTwoDFilterActuator *_2dfilter = (bTwoDFilterActuator*) bact->data; - SCA_2DFilterActuator *tmp = NULL; - - RAS_2DFilterManager::RAS_2DFILTER_MODE filtermode; - switch (_2dfilter->type) { - case ACT_2DFILTER_MOTIONBLUR: - filtermode = RAS_2DFilterManager::RAS_2DFILTER_MOTIONBLUR; - break; - case ACT_2DFILTER_BLUR: - filtermode = RAS_2DFilterManager::RAS_2DFILTER_BLUR; - break; - case ACT_2DFILTER_SHARPEN: - filtermode = RAS_2DFilterManager::RAS_2DFILTER_SHARPEN; - break; - case ACT_2DFILTER_DILATION: - filtermode = RAS_2DFilterManager::RAS_2DFILTER_DILATION; - break; - case ACT_2DFILTER_EROSION: - filtermode = RAS_2DFilterManager::RAS_2DFILTER_EROSION; - break; - case ACT_2DFILTER_LAPLACIAN: - filtermode = RAS_2DFilterManager::RAS_2DFILTER_LAPLACIAN; - break; - case ACT_2DFILTER_SOBEL: - filtermode = RAS_2DFilterManager::RAS_2DFILTER_SOBEL; - break; - case ACT_2DFILTER_PREWITT: - filtermode = RAS_2DFilterManager::RAS_2DFILTER_PREWITT; - break; - case ACT_2DFILTER_GRAYSCALE: - filtermode = RAS_2DFilterManager::RAS_2DFILTER_GRAYSCALE; - break; - case ACT_2DFILTER_SEPIA: - filtermode = RAS_2DFilterManager::RAS_2DFILTER_SEPIA; - break; - case ACT_2DFILTER_INVERT: - filtermode = RAS_2DFilterManager::RAS_2DFILTER_INVERT; - break; - case ACT_2DFILTER_CUSTOMFILTER: - filtermode = RAS_2DFilterManager::RAS_2DFILTER_CUSTOMFILTER; - break; - case ACT_2DFILTER_NOFILTER: - filtermode = RAS_2DFilterManager::RAS_2DFILTER_NOFILTER; - break; - case ACT_2DFILTER_DISABLED: - filtermode = RAS_2DFilterManager::RAS_2DFILTER_DISABLED; - break; - case ACT_2DFILTER_ENABLED: - filtermode = RAS_2DFilterManager::RAS_2DFILTER_ENABLED; - break; - default: - filtermode = RAS_2DFilterManager::RAS_2DFILTER_NOFILTER; - break; - } - - tmp = new SCA_2DFilterActuator(gameobj, filtermode, _2dfilter->flag, - _2dfilter->float_arg, _2dfilter->int_arg, - ketsjiEngine->GetRasterizer(), scene); - - if (_2dfilter->text) - { - char *buf; - // this is some blender specific code - buf = txt_to_buf(_2dfilter->text); - if (buf) - { - tmp->SetShaderText(buf); - MEM_freeN(buf); - } - } - - baseact = tmp; - - } - break; - case ACT_PARENT: - { - bParentActuator *parAct = (bParentActuator *) bact->data; - int mode = KX_ParentActuator::KX_PARENT_NODEF; - bool addToCompound = true; - bool ghost = true; - KX_GameObject *tmpgob = NULL; - - switch (parAct->type) { - case ACT_PARENT_SET: - mode = KX_ParentActuator::KX_PARENT_SET; - tmpgob = converter->FindGameObject(parAct->ob); - addToCompound = !(parAct->flag & ACT_PARENT_COMPOUND); - ghost = !(parAct->flag & ACT_PARENT_GHOST); - break; - case ACT_PARENT_REMOVE: - mode = KX_ParentActuator::KX_PARENT_REMOVE; - tmpgob = NULL; - break; - } - - KX_ParentActuator *tmpparact - = new KX_ParentActuator(gameobj, - mode, - addToCompound, - ghost, - tmpgob); - baseact = tmpparact; - break; - } - - case ACT_ARMATURE: - { - bArmatureActuator* armAct = (bArmatureActuator*) bact->data; - KX_GameObject *tmpgob = converter->FindGameObject(armAct->target); - KX_GameObject *subgob = converter->FindGameObject(armAct->subtarget); - BL_ArmatureActuator* tmparmact = new BL_ArmatureActuator( - gameobj, - armAct->type, - armAct->posechannel, - armAct->constraint, - tmpgob, - subgob, - armAct->weight, - armAct->influence); - baseact = tmparmact; - break; - } - case ACT_STEERING: - { - bSteeringActuator *stAct = (bSteeringActuator *) bact->data; - KX_GameObject *navmeshob = NULL; - if (stAct->navmesh) - { - PointerRNA settings_ptr; - RNA_pointer_create((ID *)stAct->navmesh, &RNA_GameObjectSettings, stAct->navmesh, &settings_ptr); - if (RNA_enum_get(&settings_ptr, "physics_type") == OB_BODY_TYPE_NAVMESH) - navmeshob = converter->FindGameObject(stAct->navmesh); - } - KX_GameObject *targetob = converter->FindGameObject(stAct->target); - - int mode = KX_SteeringActuator::KX_STEERING_NODEF; - switch (stAct->type) { - case ACT_STEERING_SEEK: - mode = KX_SteeringActuator::KX_STEERING_SEEK; - break; - case ACT_STEERING_FLEE: - mode = KX_SteeringActuator::KX_STEERING_FLEE; - break; - case ACT_STEERING_PATHFOLLOWING: - mode = KX_SteeringActuator::KX_STEERING_PATHFOLLOWING; - break; - } - - bool selfTerminated = (stAct->flag & ACT_STEERING_SELFTERMINATED) !=0; - bool enableVisualization = (stAct->flag & ACT_STEERING_ENABLEVISUALIZATION) !=0; - short facingMode = (stAct->flag & ACT_STEERING_AUTOMATICFACING) ? stAct->facingaxis : 0; - bool normalup = (stAct->flag & ACT_STEERING_NORMALUP) !=0; - bool lockzvel = (stAct->flag & ACT_STEERING_LOCKZVEL) !=0; - KX_SteeringActuator *tmpstact - = new KX_SteeringActuator(gameobj, mode, targetob, navmeshob,stAct->dist, - stAct->velocity, stAct->acceleration, stAct->turnspeed, - selfTerminated, stAct->updateTime, - scene->GetObstacleSimulation(), facingMode, normalup, enableVisualization, lockzvel); - baseact = tmpstact; - break; - } - case ACT_MOUSE: - { - bMouseActuator* mouAct = (bMouseActuator*) bact->data; - int mode = KX_MouseActuator::KX_ACT_MOUSE_NODEF; - - switch (mouAct->type) { - case ACT_MOUSE_VISIBILITY: - { - mode = KX_MouseActuator::KX_ACT_MOUSE_VISIBILITY; - break; - } - case ACT_MOUSE_LOOK: - { - mode = KX_MouseActuator::KX_ACT_MOUSE_LOOK; - break; - } - } - - bool visible = (mouAct->flag & ACT_MOUSE_VISIBLE) != 0; - bool use_axis[2] = {(mouAct->flag & ACT_MOUSE_USE_AXIS_X) != 0, (mouAct->flag & ACT_MOUSE_USE_AXIS_Y) != 0}; - bool reset[2] = {(mouAct->flag & ACT_MOUSE_RESET_X) != 0, (mouAct->flag & ACT_MOUSE_RESET_Y) != 0}; - bool local[2] = {(mouAct->flag & ACT_MOUSE_LOCAL_X) != 0, (mouAct->flag & ACT_MOUSE_LOCAL_Y) != 0}; - - SCA_MouseManager* eventmgr = (SCA_MouseManager*) logicmgr->FindEventManager(SCA_EventManager::MOUSE_EVENTMGR); - if (eventmgr) { - KX_MouseActuator* tmpbaseact = new KX_MouseActuator(gameobj, - ketsjiEngine, - eventmgr, - mode, - visible, - use_axis, - mouAct->threshold, - reset, - mouAct->object_axis, - local, - mouAct->sensitivity, - mouAct->limit_x, - mouAct->limit_y); - baseact = tmpbaseact; - } else { - //cout << "\n Couldn't find mouse event manager..."; - should throw an error here... - } - break; - } - default: - ; /* generate some error */ - } - - if (baseact && !(bact->flag & ACT_DEACTIVATE)) - { - baseact->SetExecutePriority(executePriority++); - uniquename += "#ACT#"; - uniqueint++; - CIntValue* uniqueval = new CIntValue(uniqueint); - uniquename += uniqueval->GetText(); - uniqueval->Release(); - baseact->SetName(bact->name); - baseact->SetLogicManager(logicmgr); - //gameobj->SetProperty(uniquename,baseact); - gameobj->AddActuator(baseact); - - converter->RegisterGameActuator(baseact, bact); - // done with baseact, release it - baseact->Release(); - } - else if (baseact) - baseact->Release(); - - bact = bact->next; - } -} diff --git a/source/gameengine/Converter/KX_ConvertSensors.cpp b/source/gameengine/Converter/KX_ConvertSensors.cpp deleted file mode 100644 index 89645cd9456d..000000000000 --- a/source/gameengine/Converter/KX_ConvertSensors.cpp +++ /dev/null @@ -1,662 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Converter/KX_ConvertSensors.cpp - * \ingroup bgeconv - * - * Conversion of Blender data blocks to KX sensor system - */ - -#include - -#ifdef _MSC_VER -# pragma warning (disable:4786) -#endif - -#include "wm_event_types.h" -#include "KX_BlenderSceneConverter.h" -#include "KX_ConvertSensors.h" - -/* This little block needed for linking to Blender... */ -#ifdef _MSC_VER -# include "BLI_winstuff.h" -#endif - -#include "DNA_object_types.h" -#include "DNA_material_types.h" -#include "DNA_sensor_types.h" -#include "DNA_controller_types.h" -#include "DNA_actuator_types.h" /* for SENS_ALL_KEYS ? this define is - * probably misplaced */ -/* end of blender include block */ - -#include "RAS_IPolygonMaterial.h" -// Sensors -#include "KX_GameObject.h" -#include "RAS_MeshObject.h" -#include "SCA_KeyboardSensor.h" -#include "SCA_MouseSensor.h" -#include "SCA_AlwaysSensor.h" -#include "KX_TouchSensor.h" -#include "KX_NearSensor.h" -#include "KX_RadarSensor.h" -#include "KX_MouseFocusSensor.h" -#include "KX_ArmatureSensor.h" -#include "SCA_JoystickSensor.h" -#include "KX_NetworkMessageSensor.h" -#include "SCA_ActuatorSensor.h" -#include "SCA_DelaySensor.h" - - -#include "SCA_PropertySensor.h" -#include "SCA_RandomSensor.h" -#include "KX_RaySensor.h" -#include "SCA_EventManager.h" -#include "SCA_LogicManager.h" -#include "KX_BlenderInputDevice.h" -#include "KX_Scene.h" -#include "EXP_IntValue.h" -#include "KX_BlenderKeyboardDevice.h" -#include "RAS_ICanvas.h" -#include "PHY_IPhysicsEnvironment.h" - -#include "KX_KetsjiEngine.h" -#include "BL_BlenderDataConversion.h" - -void BL_ConvertSensors(struct Object* blenderobject, - class KX_GameObject* gameobj, - SCA_LogicManager* logicmgr, - KX_Scene* kxscene, - KX_KetsjiEngine* kxengine, - int activeLayerBitInfo, - bool isInActiveLayer, - RAS_ICanvas* canvas, - KX_BlenderSceneConverter* converter - ) -{ - - int executePriority = 0; - int uniqueint = 0; - int count = 0; - bSensor* sens = (bSensor*)blenderobject->sensors.first; - bool pos_pulsemode = false; - bool neg_pulsemode = false; - int skipped_ticks = 0; - bool invert = false; - bool level = false; - bool tap = false; - - while (sens) - { - sens = sens->next; - count++; - } - gameobj->ReserveSensor(count); - sens = (bSensor*)blenderobject->sensors.first; - - while (sens) { - if (!(sens->flag & SENS_DEACTIVATE)) { - SCA_ISensor* gamesensor=NULL; - /* All sensors have a pulse toggle, skipped ticks parameter, and invert field. */ - /* These are extracted here, and set when the sensor is added to the */ - /* list. */ - pos_pulsemode = (sens->pulse & SENS_PULSE_REPEAT)!=0; - neg_pulsemode = (sens->pulse & SENS_NEG_PULSE_MODE)!=0; - - skipped_ticks = sens->freq; - invert = !(sens->invert == 0); - level = !(sens->level == 0); - tap = !(sens->tap == 0); - - switch (sens->type) - { - case SENS_ALWAYS: - { - - SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); - if (eventmgr) - { - gamesensor = new SCA_AlwaysSensor(eventmgr, gameobj); - } - - break; - } - - case SENS_DELAY: - { - // we can reuse the Always event manager for the delay sensor - SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); - if (eventmgr) - { - bDelaySensor* delaysensor = (bDelaySensor*)sens->data; - gamesensor = new SCA_DelaySensor(eventmgr, - gameobj, - delaysensor->delay, - delaysensor->duration, - (delaysensor->flag & SENS_DELAY_REPEAT) != 0); - } - break; - } - - case SENS_COLLISION: - { - SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR); - if (eventmgr) - { - // collision sensor can sense both materials and properties. - - bool bFindMaterial = false, bTouchPulse = false; - - bCollisionSensor* blendertouchsensor = (bCollisionSensor*)sens->data; - - bFindMaterial = (blendertouchsensor->mode & SENS_COLLISION_MATERIAL); - bTouchPulse = (blendertouchsensor->mode & SENS_COLLISION_PULSE); - - - const STR_String touchPropOrMatName = bFindMaterial ? - blendertouchsensor->materialName : blendertouchsensor->name; - - - if (gameobj->GetPhysicsController()) - { - gamesensor = new KX_TouchSensor(eventmgr, - gameobj, - bFindMaterial, - bTouchPulse, - touchPropOrMatName); - } - - } - - break; - } - case SENS_MESSAGE: - { - KX_NetworkEventManager* eventmgr = (KX_NetworkEventManager*) - logicmgr->FindEventManager(SCA_EventManager::NETWORK_EVENTMGR); - if (eventmgr) { - bMessageSensor* msgSens = (bMessageSensor*) sens->data; - - /* Get our NetworkScene */ - NG_NetworkScene *NetworkScene = kxscene->GetNetworkScene(); - /* filter on the incoming subjects, might be empty */ - const STR_String subject = msgSens->subject; - - gamesensor = new KX_NetworkMessageSensor( - eventmgr, // our eventmanager - NetworkScene, // our NetworkScene - gameobj, // the sensor controlling object - subject); // subject to filter on - } - break; - } - case SENS_NEAR: - { - - SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR); - if (eventmgr) - { - bNearSensor* blendernearsensor = (bNearSensor*)sens->data; - const STR_String nearpropertyname = (char *)blendernearsensor->name; - - //DT_ShapeHandle shape = DT_Sphere(0.0); - - // this sumoObject is not deleted by a gameobj, so delete it ourself - // later (memleaks)! - float radius = blendernearsensor->dist; - const MT_Vector3& wpos = gameobj->NodeGetWorldPosition(); - bool bFindMaterial = false; - PHY_IPhysicsController* physCtrl = kxscene->GetPhysicsEnvironment()->CreateSphereController(radius,wpos); - - //will be done in KX_TouchEventManager::RegisterSensor() - //if (isInActiveLayer) - // kxscene->GetPhysicsEnvironment()->addSensor(physCtrl); - - - - gamesensor = new KX_NearSensor(eventmgr,gameobj, - blendernearsensor->dist, - blendernearsensor->resetdist, - bFindMaterial, - nearpropertyname, - physCtrl); - - } - break; - } - - - case SENS_KEYBOARD: - { - /* temporary input device, for converting the code for the keyboard sensor */ - - bKeyboardSensor* blenderkeybdsensor = (bKeyboardSensor*)sens->data; - SCA_KeyboardManager* eventmgr = (SCA_KeyboardManager*) logicmgr->FindEventManager(SCA_EventManager::KEYBOARD_EVENTMGR); - if (eventmgr) - { - gamesensor = new SCA_KeyboardSensor(eventmgr, - ConvertKeyCode(blenderkeybdsensor->key), - ConvertKeyCode(blenderkeybdsensor->qual), - ConvertKeyCode(blenderkeybdsensor->qual2), - (blenderkeybdsensor->type == SENS_ALL_KEYS), - blenderkeybdsensor->targetName, - blenderkeybdsensor->toggleName, - gameobj, - KX_KetsjiEngine::GetExitKey()); // blenderkeybdsensor->pad); - - } - - break; - } - case SENS_MOUSE: - { - int keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_NODEF; - int trackfocus = 0; - bMouseSensor *bmouse = (bMouseSensor *)sens->data; - - /* There are two main types of mouse sensors. If there is - * no focus-related behavior requested, we can make do - * with a basic sensor. This cuts down memory usage and - * gives a slight performance gain. */ - - SCA_MouseManager *eventmgr - = (SCA_MouseManager*) logicmgr->FindEventManager(SCA_EventManager::MOUSE_EVENTMGR); - if (eventmgr) { - - /* Determine key mode. There is at most one active mode. */ - switch (bmouse->type) { - case BL_SENS_MOUSE_LEFT_BUTTON: - keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_LEFTBUTTON; - break; - case BL_SENS_MOUSE_MIDDLE_BUTTON: - keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_MIDDLEBUTTON; - break; - case BL_SENS_MOUSE_RIGHT_BUTTON: - keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_RIGHTBUTTON; - break; - case BL_SENS_MOUSE_WHEEL_UP: - keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_WHEELUP; - break; - case BL_SENS_MOUSE_WHEEL_DOWN: - keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_WHEELDOWN; - break; - case BL_SENS_MOUSE_MOVEMENT: - keytype = SCA_MouseSensor::KX_MOUSESENSORMODE_MOVEMENT; - break; - case BL_SENS_MOUSE_MOUSEOVER: - trackfocus = 1; - break; - case BL_SENS_MOUSE_MOUSEOVER_ANY: - trackfocus = 2; - break; - - default: - ; /* error */ - } - - /* initial mouse position */ - int startx = canvas->GetWidth()/2; - int starty = canvas->GetHeight()/2; - - if (!trackfocus) { - /* plain, simple mouse sensor */ - gamesensor = new SCA_MouseSensor(eventmgr, - startx,starty, - keytype, - gameobj); - } else { - /* give us a focus-aware sensor */ - bool bFindMaterial = (bmouse->mode & SENS_COLLISION_MATERIAL); - bool bXRay = (bmouse->flag & SENS_RAY_XRAY); - STR_String checkname = (bFindMaterial? bmouse->matname : bmouse->propname); - - gamesensor = new KX_MouseFocusSensor(eventmgr, - startx, - starty, - keytype, - trackfocus, - (bmouse->flag & SENS_MOUSE_FOCUS_PULSE) ? true:false, - checkname, - bFindMaterial, - bXRay, - kxscene, - kxengine, - gameobj); - } - } else { - // cout << "\n Could't find mouse event manager..."; - should throw an error here... - } - break; - } - case SENS_PROPERTY: - { - bPropertySensor* blenderpropsensor = (bPropertySensor*) sens->data; - SCA_EventManager* eventmgr - = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); - if (eventmgr) - { - STR_String propname=blenderpropsensor->name; - STR_String propval=blenderpropsensor->value; - STR_String propmaxval=blenderpropsensor->maxvalue; - - SCA_PropertySensor::KX_PROPSENSOR_TYPE - propchecktype = SCA_PropertySensor::KX_PROPSENSOR_NODEF; - - /* Better do an explicit conversion here! (was implicit */ - /* before...) */ - switch (blenderpropsensor->type) { - case SENS_PROP_EQUAL: - propchecktype = SCA_PropertySensor::KX_PROPSENSOR_EQUAL; - break; - case SENS_PROP_NEQUAL: - propchecktype = SCA_PropertySensor::KX_PROPSENSOR_NOTEQUAL; - break; - case SENS_PROP_INTERVAL: - propchecktype = SCA_PropertySensor::KX_PROPSENSOR_INTERVAL; - break; - case SENS_PROP_CHANGED: - propchecktype = SCA_PropertySensor::KX_PROPSENSOR_CHANGED; - break; - case SENS_PROP_EXPRESSION: - propchecktype = SCA_PropertySensor::KX_PROPSENSOR_EXPRESSION; - /* error */ - break; - case SENS_PROP_LESSTHAN: - propchecktype = SCA_PropertySensor::KX_PROPSENSOR_LESSTHAN; - break; - case SENS_PROP_GREATERTHAN: - propchecktype = SCA_PropertySensor::KX_PROPSENSOR_GREATERTHAN; - break; - default: - ; /* error */ - } - gamesensor = new SCA_PropertySensor(eventmgr,gameobj,propname,propval,propmaxval,propchecktype); - } - - break; - } - case SENS_ACTUATOR: - { - bActuatorSensor* blenderactsensor = (bActuatorSensor*) sens->data; - // we will reuse the property event manager, there is nothing special with this sensor - SCA_EventManager* eventmgr - = logicmgr->FindEventManager(SCA_EventManager::ACTUATOR_EVENTMGR); - if (eventmgr) - { - STR_String propname=blenderactsensor->name; - gamesensor = new SCA_ActuatorSensor(eventmgr,gameobj,propname); - } - break; - } - - case SENS_ARMATURE: - { - bArmatureSensor* blenderarmsensor = (bArmatureSensor*) sens->data; - // we will reuse the property event manager, there is nothing special with this sensor - SCA_EventManager* eventmgr - = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); - if (eventmgr) - { - STR_String bonename=blenderarmsensor->posechannel; - STR_String constraintname=blenderarmsensor->constraint; - gamesensor = new KX_ArmatureSensor(eventmgr,gameobj,bonename,constraintname, blenderarmsensor->type, blenderarmsensor->value); - } - break; - } - - case SENS_RADAR: - { - - SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::TOUCH_EVENTMGR); - if (eventmgr) - { - bRadarSensor* blenderradarsensor = (bRadarSensor*) sens->data; - const STR_String radarpropertyname = blenderradarsensor->name; - - int radaraxis = blenderradarsensor->axis; - - MT_Scalar coneheight = blenderradarsensor->range; - - // janco: the angle was doubled, so should I divide the factor in 2 - // or the blenderradarsensor->angle? - // nzc: the angle is the opening angle. We need to init with - // the axis-hull angle,so /2.0. - MT_Scalar factor = tan(blenderradarsensor->angle * 0.5f); - //MT_Scalar coneradius = coneheight * (factor / 2); - MT_Scalar coneradius = coneheight * factor; - - - // this sumoObject is not deleted by a gameobj, so delete it ourself - // later (memleaks)! - MT_Scalar smallmargin = 0.0; - MT_Scalar largemargin = 0.0; - - bool bFindMaterial = false; - PHY_IPhysicsController* ctrl = kxscene->GetPhysicsEnvironment()->CreateConeController((float)coneradius, (float)coneheight); - - gamesensor = new KX_RadarSensor( - eventmgr, - gameobj, - ctrl, - coneradius, - coneheight, - radaraxis, - smallmargin, - largemargin, - bFindMaterial, - radarpropertyname); - - } - - break; - } - case SENS_RAY: - { - bRaySensor* blenderraysensor = (bRaySensor*) sens->data; - - //blenderradarsensor->angle; - SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); - if (eventmgr) - { - bool bFindMaterial = (blenderraysensor->mode & SENS_COLLISION_MATERIAL); - bool bXRay = (blenderraysensor->mode & SENS_RAY_XRAY); - - STR_String checkname = (bFindMaterial? blenderraysensor->matname : blenderraysensor->propname); - - // don't want to get rays of length 0.0 or so - double distance = (blenderraysensor->range < 0.01f ? 0.01f : blenderraysensor->range); - int axis = blenderraysensor->axisflag; - - - gamesensor = new KX_RaySensor(eventmgr, - gameobj, - checkname, - bFindMaterial, - bXRay, - distance, - axis, - kxscene); - - } - break; - } - - case SENS_RANDOM: - { - bRandomSensor* blenderrndsensor = (bRandomSensor*) sens->data; - // some files didn't write randomsensor, avoid crash now for NULL ptr's - if (blenderrndsensor) - { - SCA_EventManager* eventmgr = logicmgr->FindEventManager(SCA_EventManager::BASIC_EVENTMGR); - if (eventmgr) - { - int randomSeed = blenderrndsensor->seed; - if (randomSeed == 0) - { - randomSeed = (int)(kxengine->GetRealTime()*100000.0); - randomSeed ^= (intptr_t)blenderrndsensor; - } - gamesensor = new SCA_RandomSensor(eventmgr, gameobj, randomSeed); - } - } - break; - } - case SENS_JOYSTICK: - { - int joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_NODEF; - - bJoystickSensor* bjoy = (bJoystickSensor*) sens->data; - - SCA_JoystickManager *eventmgr - = (SCA_JoystickManager*) logicmgr->FindEventManager(SCA_EventManager::JOY_EVENTMGR); - if (eventmgr) - { - int axis =0; - int axisf =0; - int button =0; - int hat =0; - int hatf =0; - int prec =0; - - switch (bjoy->type) { - case SENS_JOY_AXIS: - axis = bjoy->axis; - axisf = bjoy->axisf; - prec = bjoy->precision; - joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_AXIS; - break; - case SENS_JOY_BUTTON: - button = bjoy->button; - joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_BUTTON; - break; - case SENS_JOY_HAT: - hat = bjoy->hat; - hatf = bjoy->hatf; - joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_HAT; - break; - case SENS_JOY_AXIS_SINGLE: - axis = bjoy->axis_single; - prec = bjoy->precision; - joysticktype = SCA_JoystickSensor::KX_JOYSENSORMODE_AXIS_SINGLE; - break; - default: - printf("Error: bad case statement\n"); - break; - } - gamesensor = new SCA_JoystickSensor( - eventmgr, - gameobj, - bjoy->joyindex, - joysticktype, - axis,axisf, - prec, - button, - hat,hatf, - (bjoy->flag & SENS_JOY_ANY_EVENT)); - } - else - { - printf("Error there was a problem finding the event manager\n"); - } - - break; - } - default: - { - } - } - - if (gamesensor) - { - gamesensor->SetExecutePriority(executePriority++); - STR_String uniquename = sens->name; - uniquename += "#SENS#"; - uniqueint++; - CIntValue* uniqueval = new CIntValue(uniqueint); - uniquename += uniqueval->GetText(); - uniqueval->Release(); - - /* Conversion succeeded, so we can set the generic props here. */ - gamesensor->SetPulseMode(pos_pulsemode, - neg_pulsemode, - skipped_ticks); - gamesensor->SetInvert(invert); - gamesensor->SetLevel(level); - gamesensor->SetTap(tap); - gamesensor->SetName(sens->name); - gamesensor->SetLogicManager(logicmgr); - - gameobj->AddSensor(gamesensor); - - // only register to manager if it's in an active layer - // Make registration dynamic: only when sensor is activated - //if (isInActiveLayer) - // gamesensor->RegisterToManager(); - - gamesensor->ReserveController(sens->totlinks); - for (int i=0;itotlinks;i++) - { - bController* linkedcont = (bController*) sens->links[i]; - if (linkedcont) { - // If the controller is deactived doesn't register it - if (!(linkedcont->flag & CONT_DEACTIVATE)) { - SCA_IController* gamecont = converter->FindGameController(linkedcont); - - if (gamecont) { - logicmgr->RegisterToSensor(gamecont,gamesensor); - } - else { - printf("Warning, sensor \"%s\" could not find its controller " - "(link %d of %d) from object \"%s\"\n" - "\tthere has been an error converting the blender controller for the game engine," - "logic may be incorrect\n", sens->name, i+1, sens->totlinks, blenderobject->id.name+2); - } - } - } - else { - printf("Warning, sensor \"%s\" has lost a link to a controller " - "(link %d of %d) from object \"%s\"\n" - "\tpossible causes are partially appended objects or an error reading the file," - "logic may be incorrect\n", sens->name, i+1, sens->totlinks, blenderobject->id.name+2); - } - } - // special case: Keyboard sensor with no link - // this combination is usually used for key logging. - if (sens->type == SENS_KEYBOARD && sens->totlinks == 0) { - // Force the registration so that the sensor runs - gamesensor->IncLink(); - } - - // done with gamesensor - gamesensor->Release(); - - } - } - - sens=sens->next; - } -} diff --git a/source/gameengine/Converter/KX_LibLoadStatus.cpp b/source/gameengine/Converter/KX_LibLoadStatus.cpp deleted file mode 100644 index c43958ebc85e..000000000000 --- a/source/gameengine/Converter/KX_LibLoadStatus.cpp +++ /dev/null @@ -1,255 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Contributor(s): Mitchell Stokes - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file KX_LibLoadStatus.cpp - * \ingroup bgeconv - */ - -#include "KX_LibLoadStatus.h" -#include "PIL_time.h" - -KX_LibLoadStatus::KX_LibLoadStatus(class KX_BlenderSceneConverter* kx_converter, - class KX_KetsjiEngine* kx_engine, - class KX_Scene* merge_scene, - const char *path) : - m_converter(kx_converter), - m_engine(kx_engine), - m_mergescene(merge_scene), - m_data(NULL), - m_libname(path), - m_progress(0.0f), - m_finished(false) -#ifdef WITH_PYTHON - , - m_finish_cb(NULL), - m_progress_cb(NULL) -#endif -{ - m_endtime = m_starttime = PIL_check_seconds_timer(); -} - -void KX_LibLoadStatus::Finish() -{ - m_finished = true; - m_progress = 1.f; - m_endtime = PIL_check_seconds_timer(); - - RunFinishCallback(); - RunProgressCallback(); -} - -void KX_LibLoadStatus::RunFinishCallback() -{ -#ifdef WITH_PYTHON - if (m_finish_cb) { - PyObject* args = Py_BuildValue("(O)", GetProxy()); - - if (!PyObject_Call(m_finish_cb, args, NULL)) { - PyErr_Print(); - PyErr_Clear(); - } - - Py_DECREF(args); - } -#endif -} - -void KX_LibLoadStatus::RunProgressCallback() -{ -// Progess callbacks are causing threading problems with Python, so they're disabled for now -#if 0 -#ifdef WITH_PYTHON - if (m_progress_cb) { - //PyGILState_STATE gstate = PyGILState_Ensure(); - PyObject* args = Py_BuildValue("(O)", GetProxy()); - - if (!PyObject_Call(m_progress_cb, args, NULL)) { - PyErr_Print(); - PyErr_Clear(); - } - - Py_DECREF(args); - //PyGILState_Release(gstate); - } -#endif -#endif -} - -class KX_BlenderSceneConverter *KX_LibLoadStatus::GetConverter() -{ - return m_converter; -} - -class KX_KetsjiEngine *KX_LibLoadStatus::GetEngine() -{ - return m_engine; -} - -class KX_Scene *KX_LibLoadStatus::GetMergeScene() -{ - return m_mergescene; -} - -void KX_LibLoadStatus::SetLibName(const char *name) -{ - m_libname = name; -} - -const char *KX_LibLoadStatus::GetLibName() -{ - return m_libname; -} - -void KX_LibLoadStatus::SetData(void *data) -{ - m_data = data; -} - -void *KX_LibLoadStatus::GetData() -{ - return m_data; -} - -void KX_LibLoadStatus::SetProgress(float progress) -{ - m_progress = progress; - RunProgressCallback(); -} - -float KX_LibLoadStatus::GetProgress() -{ - return m_progress; -} - -void KX_LibLoadStatus::AddProgress(float progress) -{ - m_progress += progress; - RunProgressCallback(); -} - -#ifdef WITH_PYTHON - -PyMethodDef KX_LibLoadStatus::Methods[] = -{ - {NULL} //Sentinel -}; - -PyAttributeDef KX_LibLoadStatus::Attributes[] = { - KX_PYATTRIBUTE_RW_FUNCTION("onFinish", KX_LibLoadStatus, pyattr_get_onfinish, pyattr_set_onfinish), - // KX_PYATTRIBUTE_RW_FUNCTION("onProgress", KX_LibLoadStatus, pyattr_get_onprogress, pyattr_set_onprogress), - KX_PYATTRIBUTE_FLOAT_RO("progress", KX_LibLoadStatus, m_progress), - KX_PYATTRIBUTE_STRING_RO("libraryName", KX_LibLoadStatus, m_libname), - KX_PYATTRIBUTE_RO_FUNCTION("timeTaken", KX_LibLoadStatus, pyattr_get_timetaken), - KX_PYATTRIBUTE_BOOL_RO("finished", KX_LibLoadStatus, m_finished), - { NULL } //Sentinel -}; - -PyTypeObject KX_LibLoadStatus::Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "KX_LibLoadStatus", - sizeof(PyObjectPlus_Proxy), - 0, - py_base_dealloc, - 0, - 0, - 0, - 0, - py_base_repr, - 0,0,0,0,0,0,0,0,0, - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, - Methods, - 0, - 0, - &PyObjectPlus::Type, - 0,0,0,0,0,0, - py_base_new -}; - - -PyObject* KX_LibLoadStatus::pyattr_get_onfinish(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LibLoadStatus* self = static_cast(self_v); - - if (self->m_finish_cb) { - Py_INCREF(self->m_finish_cb); - return self->m_finish_cb; - } - - Py_RETURN_NONE; -} - -int KX_LibLoadStatus::pyattr_set_onfinish(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) -{ - KX_LibLoadStatus* self = static_cast(self_v); - - if (!PyCallable_Check(value)) { - PyErr_SetString(PyExc_TypeError, "KX_LibLoadStatus.onFinished requires a callable object"); - return PY_SET_ATTR_FAIL; - } - - if (self->m_finish_cb) - Py_DECREF(self->m_finish_cb); - - Py_INCREF(value); - self->m_finish_cb = value; - - return PY_SET_ATTR_SUCCESS; -} - -PyObject* KX_LibLoadStatus::pyattr_get_onprogress(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LibLoadStatus* self = static_cast(self_v); - - if (self->m_progress_cb) { - Py_INCREF(self->m_progress_cb); - return self->m_progress_cb; - } - - Py_RETURN_NONE; -} - -int KX_LibLoadStatus::pyattr_set_onprogress(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) -{ - KX_LibLoadStatus* self = static_cast(self_v); - - if (!PyCallable_Check(value)) { - PyErr_SetString(PyExc_TypeError, "KX_LibLoadStatus.onProgress requires a callable object"); - return PY_SET_ATTR_FAIL; - } - - if (self->m_progress_cb) - Py_DECREF(self->m_progress_cb); - - Py_INCREF(value); - self->m_progress_cb = value; - - return PY_SET_ATTR_SUCCESS; -} - -PyObject* KX_LibLoadStatus::pyattr_get_timetaken(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LibLoadStatus* self = static_cast(self_v); - - return PyFloat_FromDouble(self->m_endtime - self->m_starttime); -} -#endif // WITH_PYTHON diff --git a/source/gameengine/Converter/KX_LibLoadStatus.h b/source/gameengine/Converter/KX_LibLoadStatus.h deleted file mode 100644 index fd51bfddd85c..000000000000 --- a/source/gameengine/Converter/KX_LibLoadStatus.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Contributor(s): Mitchell Stokes - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file KX_LibLoadStatus.h - * \ingroup bgeconv - */ - -#ifndef __KX_LIBLOADSTATUS_H__ -#define __KX_LIBLOADSTATUS_H__ - -#include "EXP_PyObjectPlus.h" - -class KX_LibLoadStatus : public PyObjectPlus -{ - Py_Header -private: - class KX_BlenderSceneConverter* m_converter; - class KX_KetsjiEngine* m_engine; - class KX_Scene* m_mergescene; - void* m_data; - STR_String m_libname; - - float m_progress; - double m_starttime; - double m_endtime; - - // The current status of this libload, used by the scene converter. - bool m_finished; - -#ifdef WITH_PYTHON - PyObject* m_finish_cb; - PyObject* m_progress_cb; -#endif - -public: - KX_LibLoadStatus(class KX_BlenderSceneConverter* kx_converter, - class KX_KetsjiEngine* kx_engine, - class KX_Scene* merge_scene, - const char *path); - - void Finish(); // Called when the libload is done - void RunFinishCallback(); - void RunProgressCallback(); - - class KX_BlenderSceneConverter *GetConverter(); - class KX_KetsjiEngine *GetEngine(); - class KX_Scene *GetMergeScene(); - - void SetLibName(const char *name); - const char *GetLibName(); - - void SetData(void *data); - void *GetData(); - - inline bool IsFinished() const - { - return m_finished; - } - - void SetProgress(float progress); - float GetProgress(); - void AddProgress(float progress); - -#ifdef WITH_PYTHON - static PyObject* pyattr_get_onfinish(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_onfinish(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_onprogress(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_onprogress(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - - static PyObject* pyattr_get_timetaken(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); -#endif -}; - -#endif // __KX_LIBLOADSTATUS_H__ diff --git a/source/gameengine/Converter/KX_SoftBodyDeformer.cpp b/source/gameengine/Converter/KX_SoftBodyDeformer.cpp deleted file mode 100644 index 6c8b7fc3e290..000000000000 --- a/source/gameengine/Converter/KX_SoftBodyDeformer.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Converter/KX_SoftBodyDeformer.cpp - * \ingroup bgeconv - */ - - -#ifdef _MSC_VER -# pragma warning (disable:4786) -#endif //WIN32 - -#include "MT_assert.h" - -#include "KX_SoftBodyDeformer.h" -#include "RAS_MeshObject.h" -#include "CTR_Map.h" -#include "CTR_HashedPtr.h" - -#ifdef WITH_BULLET - -#include "CcdPhysicsEnvironment.h" -#include "CcdPhysicsController.h" -#include "BulletSoftBody/btSoftBody.h" - -#include "btBulletDynamicsCommon.h" - -void KX_SoftBodyDeformer::Relink(CTR_Map*map) -{ - void **h_obj = (*map)[m_gameobj]; - - if (h_obj) { - m_gameobj = (BL_DeformableGameObject*)(*h_obj); - m_pMeshObject = m_gameobj->GetMesh(0); - } else { - m_gameobj = NULL; - m_pMeshObject = NULL; - } -} - -bool KX_SoftBodyDeformer::Apply(class RAS_IPolyMaterial *polymat) -{ - CcdPhysicsController* ctrl = (CcdPhysicsController*) m_gameobj->GetPhysicsController(); - if (!ctrl) - return false; - - btSoftBody* softBody= ctrl->GetSoftBody(); - if (!softBody) - return false; - - //printf("apply\n"); - RAS_MeshSlot::iterator it; - RAS_MeshMaterial *mmat; - RAS_MeshSlot *slot; - size_t i; - - // update the vertex in m_transverts - Update(); - - // The vertex cache can only be updated for this deformer: - // Duplicated objects with more than one ploymaterial (=multiple mesh slot per object) - // share the same mesh (=the same cache). As the rendering is done per polymaterial - // cycling through the objects, the entire mesh cache cannot be updated in one shot. - mmat = m_pMeshObject->GetMeshMaterial(polymat); - if (!mmat->m_slots[(void*)m_gameobj]) - return true; - - slot = *mmat->m_slots[(void*)m_gameobj]; - - // for each array - for (slot->begin(it); !slot->end(it); slot->next(it)) - { - btSoftBody::tNodeArray& nodes(softBody->m_nodes); - - int index = 0; - for (i=it.startvertex; i= 0); - - MT_Point3 pt ( - nodes[v.getSoftBodyIndex()].m_x.getX(), - nodes[v.getSoftBodyIndex()].m_x.getY(), - nodes[v.getSoftBodyIndex()].m_x.getZ()); - v.SetXYZ(pt); - - MT_Vector3 normal ( - nodes[v.getSoftBodyIndex()].m_n.getX(), - nodes[v.getSoftBodyIndex()].m_n.getY(), - nodes[v.getSoftBodyIndex()].m_n.getZ()); - v.SetNormal(normal); - - } - } - return true; -} - -#endif diff --git a/source/gameengine/Device/CMakeLists.txt b/source/gameengine/Device/CMakeLists.txt new file mode 100644 index 000000000000..24dd99eb00ff --- /dev/null +++ b/source/gameengine/Device/CMakeLists.txt @@ -0,0 +1,67 @@ +# ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# Contributor(s): Tristan Porteries. +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + ../Common + ../Expressions + ../GameLogic + ../Ketsji + ../Rasterizer + ../SceneGraph + ../../blender/blenlib + ../../blender/blenkernel + ../../../intern/ghost + ../../../intern/string + ../../../intern/termcolor +) + +set(INC_SYS + ../../../intern/debugbreak + ../../../intern/mathfu +) + +set(SRC + DEV_EventConsumer.cpp + DEV_InputDevice.cpp + DEV_Joystick.cpp + DEV_JoystickEvents.cpp + DEV_JoystickVibration.cpp + + DEV_EventConsumer.h + DEV_InputDevice.h + DEV_Joystick.h + DEV_JoystickDefines.h + DEV_JoystickPrivate.h +) + +if(WITH_SDL) + list(APPEND INC_SYS + ${SDL_INCLUDE_DIR} + ) + + add_definitions(-DWITH_SDL) +endif() + +if(WITH_INPUT_NDOF) + add_definitions(-DWITH_INPUT_NDOF) +endif() + +blender_add_lib(ge_device "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/gameengine/Device/DEV_EventConsumer.cpp b/source/gameengine/Device/DEV_EventConsumer.cpp new file mode 100644 index 000000000000..7055b5ffa14a --- /dev/null +++ b/source/gameengine/Device/DEV_EventConsumer.cpp @@ -0,0 +1,144 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Device/DEV_EventConsumer.cpp + * \ingroup device + */ + + +#include "DEV_EventConsumer.h" +#include "DEV_InputDevice.h" + +#include "GHOST_IEvent.h" +#include "GHOST_IWindow.h" +#include "GHOST_ISystem.h" + +#include "RAS_ICanvas.h" + +#include "BLI_string_utf8.h" + +#include + +DEV_EventConsumer::DEV_EventConsumer(GHOST_ISystem *system, DEV_InputDevice *device, RAS_ICanvas *canvas) + :m_device(device), + m_canvas(canvas) +{ + // Setup the default mouse position. + int cursorx, cursory; + system->getCursorPosition(cursorx, cursory); + int x, y; + m_canvas->ConvertMousePosition(cursorx, cursory, x, y, true); + m_device->ConvertMoveEvent(x, y); +} + +DEV_EventConsumer::~DEV_EventConsumer() +{ +} + +void DEV_EventConsumer::HandleWindowEvent(GHOST_TEventType type) +{ + m_device->ConvertWindowEvent(type); +} + +void DEV_EventConsumer::HandleKeyEvent(GHOST_TEventDataPtr data, bool down) +{ + GHOST_TEventKeyData *keyData = (GHOST_TEventKeyData *)data; + unsigned int unicode = keyData->utf8_buf[0] ? BLI_str_utf8_as_unicode(keyData->utf8_buf) : keyData->ascii; + m_device->ConvertKeyEvent(keyData->key, down, unicode); +} + +void DEV_EventConsumer::HandleCursorEvent(GHOST_TEventDataPtr data, GHOST_IWindow *window) +{ + GHOST_TEventCursorData *cursorData = (GHOST_TEventCursorData *)data; + int x, y; + m_canvas->ConvertMousePosition(cursorData->x, cursorData->y, x, y, false); + + m_device->ConvertMoveEvent(x, y); +} + +void DEV_EventConsumer::HandleWheelEvent(GHOST_TEventDataPtr data) +{ + GHOST_TEventWheelData *wheelData = (GHOST_TEventWheelData *)data; + + m_device->ConvertWheelEvent(wheelData->z); +} + +void DEV_EventConsumer::HandleButtonEvent(GHOST_TEventDataPtr data, bool down) +{ + GHOST_TEventButtonData *buttonData = (GHOST_TEventButtonData *)data; + + m_device->ConvertButtonEvent(buttonData->button, down); +} + +bool DEV_EventConsumer::processEvent(GHOST_IEvent *event) +{ + GHOST_TEventDataPtr eventData = ((GHOST_IEvent *)event)->getData(); + switch (event->getType()) { + case GHOST_kEventButtonDown: + { + HandleButtonEvent(eventData, true); + break; + } + + case GHOST_kEventButtonUp: + { + HandleButtonEvent(eventData, false); + break; + } + + case GHOST_kEventWheel: + { + HandleWheelEvent(eventData); + break; + } + + case GHOST_kEventCursorMove: + { + HandleCursorEvent(eventData, event->getWindow()); + break; + } + + case GHOST_kEventKeyDown: + { + HandleKeyEvent(eventData, true); + break; + } + case GHOST_kEventKeyUp: + { + HandleKeyEvent(eventData, false); + break; + } + case GHOST_kEventWindowSize: + case GHOST_kEventWindowClose: + case GHOST_kEventQuit: + { + HandleWindowEvent(event->getType()); + break; + } + default: + { + break; + } + } + + return true; +} diff --git a/source/gameengine/Device/DEV_EventConsumer.h b/source/gameengine/Device/DEV_EventConsumer.h new file mode 100644 index 000000000000..daaf2e168317 --- /dev/null +++ b/source/gameengine/Device/DEV_EventConsumer.h @@ -0,0 +1,57 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file DEV_EventConsumer.h + * \ingroup device + */ + +#ifndef __DEV_EVENTCONSUMER_H__ +#define __DEV_EVENTCONSUMER_H__ + +#include "GHOST_IEventConsumer.h" + +class DEV_InputDevice; +class GHOST_ISystem; + +class RAS_ICanvas; + +class DEV_EventConsumer : public GHOST_IEventConsumer +{ +private: + DEV_InputDevice *m_device; + RAS_ICanvas *m_canvas; + + void HandleWindowEvent(GHOST_TEventType type); + void HandleKeyEvent(GHOST_TEventDataPtr data, bool down); + void HandleCursorEvent(GHOST_TEventDataPtr data, GHOST_IWindow *window); + void HandleWheelEvent(GHOST_TEventDataPtr data); + void HandleButtonEvent(GHOST_TEventDataPtr data, bool down); + +public: + DEV_EventConsumer(GHOST_ISystem *system, DEV_InputDevice *device, RAS_ICanvas *canvas); + virtual ~DEV_EventConsumer(); + + /// Function called by GHOST to process all events. + virtual bool processEvent(GHOST_IEvent *event); +}; + +#endif // __DEV_EVENTCONSUMER_H__ diff --git a/source/gameengine/Device/DEV_InputDevice.cpp b/source/gameengine/Device/DEV_InputDevice.cpp new file mode 100644 index 000000000000..ae59e207d7bd --- /dev/null +++ b/source/gameengine/Device/DEV_InputDevice.cpp @@ -0,0 +1,229 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Device/DEV_InputDevice.cpp + * \ingroup device + */ + + +#include "DEV_InputDevice.h" +#include "GHOST_Types.h" + +#include + +DEV_InputDevice::DEV_InputDevice() +{ + m_reverseKeyTranslateTable[GHOST_kKeyA] = AKEY; + m_reverseKeyTranslateTable[GHOST_kKeyB] = BKEY; + m_reverseKeyTranslateTable[GHOST_kKeyC] = CKEY; + m_reverseKeyTranslateTable[GHOST_kKeyD] = DKEY; + m_reverseKeyTranslateTable[GHOST_kKeyE] = EKEY; + m_reverseKeyTranslateTable[GHOST_kKeyF] = FKEY; + m_reverseKeyTranslateTable[GHOST_kKeyG] = GKEY; + m_reverseKeyTranslateTable[GHOST_kKeyH] = HKEY_; + m_reverseKeyTranslateTable[GHOST_kKeyI] = IKEY; + m_reverseKeyTranslateTable[GHOST_kKeyJ] = JKEY; + m_reverseKeyTranslateTable[GHOST_kKeyK] = KKEY; + m_reverseKeyTranslateTable[GHOST_kKeyL] = LKEY; + m_reverseKeyTranslateTable[GHOST_kKeyM] = MKEY; + m_reverseKeyTranslateTable[GHOST_kKeyN] = NKEY; + m_reverseKeyTranslateTable[GHOST_kKeyO] = OKEY; + m_reverseKeyTranslateTable[GHOST_kKeyP] = PKEY; + m_reverseKeyTranslateTable[GHOST_kKeyQ] = QKEY; + m_reverseKeyTranslateTable[GHOST_kKeyR] = RKEY; + m_reverseKeyTranslateTable[GHOST_kKeyS] = SKEY; + m_reverseKeyTranslateTable[GHOST_kKeyT] = TKEY; + m_reverseKeyTranslateTable[GHOST_kKeyU] = UKEY; + m_reverseKeyTranslateTable[GHOST_kKeyV] = VKEY; + m_reverseKeyTranslateTable[GHOST_kKeyW] = WKEY; + m_reverseKeyTranslateTable[GHOST_kKeyX] = XKEY; + m_reverseKeyTranslateTable[GHOST_kKeyY] = YKEY; + m_reverseKeyTranslateTable[GHOST_kKeyZ] = ZKEY; + + m_reverseKeyTranslateTable[GHOST_kKey0] = ZEROKEY; + m_reverseKeyTranslateTable[GHOST_kKey1] = ONEKEY; + m_reverseKeyTranslateTable[GHOST_kKey2] = TWOKEY; + m_reverseKeyTranslateTable[GHOST_kKey3] = THREEKEY; + m_reverseKeyTranslateTable[GHOST_kKey4] = FOURKEY; + m_reverseKeyTranslateTable[GHOST_kKey5] = FIVEKEY; + m_reverseKeyTranslateTable[GHOST_kKey6] = SIXKEY; + m_reverseKeyTranslateTable[GHOST_kKey7] = SEVENKEY; + m_reverseKeyTranslateTable[GHOST_kKey8] = EIGHTKEY; + m_reverseKeyTranslateTable[GHOST_kKey9] = NINEKEY; + + // Middle keyboard area keys + m_reverseKeyTranslateTable[GHOST_kKeyPause] = PAUSEKEY; + m_reverseKeyTranslateTable[GHOST_kKeyInsert] = INSERTKEY; + m_reverseKeyTranslateTable[GHOST_kKeyDelete] = DELKEY; + m_reverseKeyTranslateTable[GHOST_kKeyHome] = HOMEKEY; + m_reverseKeyTranslateTable[GHOST_kKeyEnd] = ENDKEY; + m_reverseKeyTranslateTable[GHOST_kKeyUpPage] = PAGEUPKEY; + m_reverseKeyTranslateTable[GHOST_kKeyDownPage] = PAGEDOWNKEY; + + // Arrow keys + m_reverseKeyTranslateTable[GHOST_kKeyUpArrow] = UPARROWKEY; + m_reverseKeyTranslateTable[GHOST_kKeyDownArrow] = DOWNARROWKEY; + m_reverseKeyTranslateTable[GHOST_kKeyLeftArrow] = LEFTARROWKEY; + m_reverseKeyTranslateTable[GHOST_kKeyRightArrow] = RIGHTARROWKEY; + + // Function keys + m_reverseKeyTranslateTable[GHOST_kKeyF1] = F1KEY; + m_reverseKeyTranslateTable[GHOST_kKeyF2] = F2KEY; + m_reverseKeyTranslateTable[GHOST_kKeyF3] = F3KEY; + m_reverseKeyTranslateTable[GHOST_kKeyF4] = F4KEY; + m_reverseKeyTranslateTable[GHOST_kKeyF5] = F5KEY; + m_reverseKeyTranslateTable[GHOST_kKeyF6] = F6KEY; + m_reverseKeyTranslateTable[GHOST_kKeyF7] = F7KEY; + m_reverseKeyTranslateTable[GHOST_kKeyF8] = F8KEY; + m_reverseKeyTranslateTable[GHOST_kKeyF9] = F9KEY; + m_reverseKeyTranslateTable[GHOST_kKeyF10] = F10KEY; + m_reverseKeyTranslateTable[GHOST_kKeyF11] = F11KEY; + m_reverseKeyTranslateTable[GHOST_kKeyF12] = F12KEY; + m_reverseKeyTranslateTable[GHOST_kKeyF13] = F13KEY; + m_reverseKeyTranslateTable[GHOST_kKeyF14] = F14KEY; + m_reverseKeyTranslateTable[GHOST_kKeyF15] = F15KEY; + m_reverseKeyTranslateTable[GHOST_kKeyF16] = F16KEY; + m_reverseKeyTranslateTable[GHOST_kKeyF17] = F17KEY; + m_reverseKeyTranslateTable[GHOST_kKeyF18] = F18KEY; + m_reverseKeyTranslateTable[GHOST_kKeyF19] = F19KEY; + + // Numpad keys + m_reverseKeyTranslateTable[GHOST_kKeyNumpad0] = PAD0; + m_reverseKeyTranslateTable[GHOST_kKeyNumpad1] = PAD1; + m_reverseKeyTranslateTable[GHOST_kKeyNumpad2] = PAD2; + m_reverseKeyTranslateTable[GHOST_kKeyNumpad3] = PAD3; + m_reverseKeyTranslateTable[GHOST_kKeyNumpad4] = PAD4; + m_reverseKeyTranslateTable[GHOST_kKeyNumpad5] = PAD5; + m_reverseKeyTranslateTable[GHOST_kKeyNumpad6] = PAD6; + m_reverseKeyTranslateTable[GHOST_kKeyNumpad7] = PAD7; + m_reverseKeyTranslateTable[GHOST_kKeyNumpad8] = PAD8; + m_reverseKeyTranslateTable[GHOST_kKeyNumpad9] = PAD9; + m_reverseKeyTranslateTable[GHOST_kKeyNumpadAsterisk] = PADASTERKEY; + m_reverseKeyTranslateTable[GHOST_kKeyNumpadPlus] = PADPLUSKEY; + m_reverseKeyTranslateTable[GHOST_kKeyNumpadPeriod] = PADPERIOD; + m_reverseKeyTranslateTable[GHOST_kKeyNumpadMinus] = PADMINUS; + m_reverseKeyTranslateTable[GHOST_kKeyNumpadSlash] = PADSLASHKEY; + m_reverseKeyTranslateTable[GHOST_kKeyNumpadEnter] = PADENTER; + + // Other keys + m_reverseKeyTranslateTable[GHOST_kKeyCapsLock] = CAPSLOCKKEY; + m_reverseKeyTranslateTable[GHOST_kKeyEsc] = ESCKEY; + m_reverseKeyTranslateTable[GHOST_kKeyTab] = TABKEY; + m_reverseKeyTranslateTable[GHOST_kKeySpace] = SPACEKEY; + m_reverseKeyTranslateTable[GHOST_kKeyEnter] = RETKEY; + m_reverseKeyTranslateTable[GHOST_kKeyBackSpace] = BACKSPACEKEY; + m_reverseKeyTranslateTable[GHOST_kKeySemicolon] = SEMICOLONKEY; + m_reverseKeyTranslateTable[GHOST_kKeyPeriod] = PERIODKEY; + m_reverseKeyTranslateTable[GHOST_kKeyComma] = COMMAKEY; + m_reverseKeyTranslateTable[GHOST_kKeyQuote] = QUOTEKEY; + m_reverseKeyTranslateTable[GHOST_kKeyAccentGrave] = ACCENTGRAVEKEY; + m_reverseKeyTranslateTable[GHOST_kKeyMinus] = MINUSKEY; + m_reverseKeyTranslateTable[GHOST_kKeySlash] = SLASHKEY; + m_reverseKeyTranslateTable[GHOST_kKeyBackslash] = BACKSLASHKEY; + m_reverseKeyTranslateTable[GHOST_kKeyEqual] = EQUALKEY; + m_reverseKeyTranslateTable[GHOST_kKeyLeftBracket] = LEFTBRACKETKEY; + m_reverseKeyTranslateTable[GHOST_kKeyRightBracket] = RIGHTBRACKETKEY; + + m_reverseKeyTranslateTable[GHOST_kKeyOS] = OSKEY; + + // Modifier keys. + m_reverseKeyTranslateTable[GHOST_kKeyLeftControl] = LEFTCTRLKEY; + m_reverseKeyTranslateTable[GHOST_kKeyRightControl] = RIGHTCTRLKEY; + m_reverseKeyTranslateTable[GHOST_kKeyLeftAlt] = LEFTALTKEY; + m_reverseKeyTranslateTable[GHOST_kKeyRightAlt] = RIGHTALTKEY; + m_reverseKeyTranslateTable[GHOST_kKeyLeftShift] = LEFTSHIFTKEY; + m_reverseKeyTranslateTable[GHOST_kKeyRightShift] = RIGHTSHIFTKEY; + + // Mouse buttons. + m_reverseButtonTranslateTable[GHOST_kButtonMaskMiddle] = MIDDLEMOUSE; + m_reverseButtonTranslateTable[GHOST_kButtonMaskRight] = RIGHTMOUSE; + m_reverseButtonTranslateTable[GHOST_kButtonMaskLeft] = LEFTMOUSE; + + // Window events. + m_reverseWindowTranslateTable[GHOST_kEventWindowSize] = WINRESIZE; + m_reverseWindowTranslateTable[GHOST_kEventQuit] = WINQUIT; + m_reverseWindowTranslateTable[GHOST_kEventWindowClose] = WINCLOSE; +} + +DEV_InputDevice::~DEV_InputDevice() +{ +} + +void DEV_InputDevice::ConvertKeyEvent(int incode, int val, unsigned int unicode) +{ + ConvertEvent(m_reverseKeyTranslateTable[incode], val, unicode); +} + +void DEV_InputDevice::ConvertButtonEvent(int incode, int val) +{ + ConvertEvent(m_reverseButtonTranslateTable[incode], val, 0); +} + +void DEV_InputDevice::ConvertWindowEvent(int incode) +{ + ConvertEvent(m_reverseWindowTranslateTable[incode], 1, 0); +} + +void DEV_InputDevice::ConvertEvent(SCA_IInputDevice::SCA_EnumInputs type, int val, unsigned int unicode) +{ + SCA_InputEvent &event = m_inputsTable[type]; + + if (event.m_values[event.m_values.size() - 1] != val) { + // The key event value changed, we considerate it as the real event. + event.m_status.push_back((val > 0) ? SCA_InputEvent::ACTIVE : SCA_InputEvent::NONE); + event.m_queue.push_back((val > 0) ? SCA_InputEvent::JUSTACTIVATED : SCA_InputEvent::JUSTRELEASED); + event.m_values.push_back(val); + event.m_unicode = unicode; + + // Avoid pushing nullptr string character. + if (val > 0 && unicode != 0) { + m_text += (wchar_t)unicode; + } + } +} + +void DEV_InputDevice::ConvertMoveEvent(int x, int y) +{ + SCA_InputEvent &xevent = m_inputsTable[MOUSEX]; + xevent.m_values.push_back(x); + if (xevent.m_status[xevent.m_status.size() - 1] != SCA_InputEvent::ACTIVE) { + xevent.m_status.push_back(SCA_InputEvent::ACTIVE); + xevent.m_queue.push_back(SCA_InputEvent::JUSTACTIVATED); + } + + SCA_InputEvent &yevent = m_inputsTable[MOUSEY]; + yevent.m_values.push_back(y); + if (yevent.m_status[yevent.m_status.size() - 1] != SCA_InputEvent::ACTIVE) { + yevent.m_status.push_back(SCA_InputEvent::ACTIVE); + yevent.m_queue.push_back(SCA_InputEvent::JUSTACTIVATED); + } +} + +void DEV_InputDevice::ConvertWheelEvent(int z) +{ + SCA_InputEvent &event = m_inputsTable[(z > 0) ? WHEELUPMOUSE : WHEELDOWNMOUSE]; + event.m_values.push_back(z); + if (event.m_status[event.m_status.size() - 1] != SCA_InputEvent::ACTIVE) { + event.m_status.push_back(SCA_InputEvent::ACTIVE); + event.m_queue.push_back(SCA_InputEvent::JUSTACTIVATED); + } +} diff --git a/source/gameengine/Device/DEV_InputDevice.h b/source/gameengine/Device/DEV_InputDevice.h new file mode 100644 index 000000000000..d40241a42841 --- /dev/null +++ b/source/gameengine/Device/DEV_InputDevice.h @@ -0,0 +1,54 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file DEV_InputDevice.h + * \ingroup device + */ + +#ifndef __DEV_INPUTDEVICE_H__ +#define __DEV_INPUTDEVICE_H__ + +#include "SCA_IInputDevice.h" + +#include + +class DEV_InputDevice : public SCA_IInputDevice +{ +protected: + /// These maps converts GHOST input number to SCA input enum. + std::map m_reverseKeyTranslateTable; + std::map m_reverseButtonTranslateTable; + std::map m_reverseWindowTranslateTable; + +public: + DEV_InputDevice(); + virtual ~DEV_InputDevice(); + + void ConvertKeyEvent(int incode, int val, unsigned int unicode); + void ConvertButtonEvent(int incode, int val); + void ConvertWindowEvent(int incode); + void ConvertMoveEvent(int x, int y); + void ConvertWheelEvent(int z); + void ConvertEvent(SCA_IInputDevice::SCA_EnumInputs type, int val, unsigned int unicode); +}; + +#endif // __DEV_INPUTDEVICE_H__ diff --git a/source/gameengine/Device/DEV_Joystick.cpp b/source/gameengine/Device/DEV_Joystick.cpp new file mode 100644 index 000000000000..a2fe49430be7 --- /dev/null +++ b/source/gameengine/Device/DEV_Joystick.cpp @@ -0,0 +1,400 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): snailrose, lordloki + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Device/DEV_Joystick.cpp + * \ingroup device + */ + +#ifdef WITH_SDL +# include + +extern "C" { +# include "BKE_appdir.h" +# include "BLI_path_util.h" +} +#endif + +#include + +#include "DEV_Joystick.h" +#include "DEV_JoystickPrivate.h" + +#include "CM_Message.h" + +#ifdef WITH_SDL +# define SDL_CHECK(x) ((x) != (void *)0) +#endif + +DEV_Joystick::DEV_Joystick(short index) + : + m_joyindex(index), + m_prec(3200), + m_axismax(-1), + m_buttonmax(-1), + m_isinit(0), + m_istrig_axis(0), + m_istrig_button(0) +{ + for (int i = 0; i < JOYAXIS_MAX; i++) { + m_axis_array[i] = 0; + } + +#ifdef WITH_SDL + m_private = new PrivateData(); +#endif +} + + +DEV_Joystick::~DEV_Joystick() +{ +} + +DEV_Joystick *DEV_Joystick::m_instance[JOYINDEX_MAX]; + + +void DEV_Joystick::Init() +{ +#ifdef WITH_SDL + + if (!(SDL_CHECK(SDL_InitSubSystem)) || + !(SDL_CHECK(SDL_GameControllerAddMapping)) || + !(SDL_CHECK(SDL_GameControllerAddMappingsFromRW))) { + return; + } + + /* Initializing Game Controller related subsystems */ + bool success = (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC) != -1); + + if (success) { + // Loading mapping file from blender datafiles directory + const char *path = BKE_appdir_folder_id(BLENDER_DATAFILES, "gamecontroller"); + if (path) { + char fullpath[FILE_MAX]; + BLI_join_dirfile(fullpath, sizeof(fullpath), path, "gamecontrollerdb.txt"); + + if ((SDL_GameControllerAddMappingsFromFile(fullpath)) == -1) { + CM_Error("gamecontrollerdb.txt not loaded"); + } + } + } + else { + CM_Error("initializing SDL Game Controller: " << SDL_GetError()); + } +#endif +} + +void DEV_Joystick::Close() +{ +#ifdef WITH_SDL + /* Closing possible connected Joysticks */ + for (int i = 0; i < JOYINDEX_MAX; i++) { + m_instance[i]->ReleaseInstance(i); + } + + /* Closing SDL Game controller system */ + if (SDL_CHECK(SDL_QuitSubSystem)) { + SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC); + } +#endif +} + +DEV_Joystick *DEV_Joystick::GetInstance(short joyindex) +{ +#ifndef WITH_SDL + return nullptr; +#else /* WITH_SDL */ + + if (joyindex < 0 || joyindex >= JOYINDEX_MAX) { + CM_Error("invalid joystick index: " << joyindex); + return nullptr; + } + + return m_instance[joyindex]; +#endif /* WITH_SDL */ +} + +void DEV_Joystick::ReleaseInstance(short joyindex) +{ +#ifdef WITH_SDL + if (m_instance[joyindex]) { + m_instance[joyindex]->DestroyJoystickDevice(); + delete m_private; + delete m_instance[joyindex]; + } + m_instance[joyindex] = nullptr; +#endif /* WITH_SDL */ +} + +void DEV_Joystick::cSetPrecision(int val) +{ + m_prec = val; +} + + +bool DEV_Joystick::aAxisPairIsPositive(int axis) +{ + return (pAxisTest(axis) > m_prec) ? true : false; +} + +bool DEV_Joystick::aAxisPairDirectionIsPositive(int axis, int dir) +{ + + int res; + + if (dir == JOYAXIS_UP || dir == JOYAXIS_DOWN) { + res = pGetAxis(axis, 1); + } + else { /* JOYAXIS_LEFT || JOYAXIS_RIGHT */ + res = pGetAxis(axis, 0); + } + + if (dir == JOYAXIS_DOWN || dir == JOYAXIS_RIGHT) { + return (res > m_prec) ? true : false; + } + else { /* JOYAXIS_UP || JOYAXIS_LEFT */ + return (res < -m_prec) ? true : false; + } +} + +bool DEV_Joystick::aAxisIsPositive(int axis_single) +{ + return std::abs(m_axis_array[axis_single]) > m_prec ? true : false; +} + +bool DEV_Joystick::aAnyButtonPressIsPositive(void) +{ +#ifdef WITH_SDL + if (!(SDL_CHECK(SDL_GameControllerGetButton))) { + return false; + } + + /* this is needed for the "all events" option + * so we know if there are no buttons pressed */ + for (int i = 0; i < m_buttonmax; i++) { + if (SDL_GameControllerGetButton(m_private->m_gamecontroller, (SDL_GameControllerButton)i)) { + return true; + } + } +#endif + return false; +} + +bool DEV_Joystick::aButtonPressIsPositive(int button) +{ +#ifdef WITH_SDL + if ((SDL_CHECK(SDL_GameControllerGetButton) && + SDL_GameControllerGetButton(m_private->m_gamecontroller, (SDL_GameControllerButton)button))) { + return true; + } +#endif + return false; +} + + +bool DEV_Joystick::aButtonReleaseIsPositive(int button) +{ +#ifdef WITH_SDL + if (!(SDL_CHECK(SDL_GameControllerGetButton) && + SDL_GameControllerGetButton(m_private->m_gamecontroller, (SDL_GameControllerButton)button))) { + return true; + } +#endif + return false; +} + +bool DEV_Joystick::CreateJoystickDevice(void) +{ + bool joy_error = false; + +#ifndef WITH_SDL + m_isinit = true; + joy_error = true; +#else /* WITH_SDL */ + if (!m_isinit) { + + if (!(SDL_CHECK(SDL_IsGameController) && + SDL_CHECK(SDL_GameControllerOpen) && + SDL_CHECK(SDL_GameControllerEventState) && + SDL_CHECK(SDL_GameControllerGetJoystick) && + SDL_CHECK(SDL_JoystickInstanceID))) { + joy_error = true; + } + + if (!joy_error && !SDL_IsGameController(m_joyindex)) { + /* mapping instruccions if joystick is not a game controller */ + CM_Error("Game Controller index " << m_joyindex << ": Could not be initialized\n" + << "Please, generate Xbox360 compatible mapping using Antimicro (https://github.com/AntiMicro/antimicro)\n" + << "or SDL2 Gamepad Tool (http://www.generalarcade.com/gamepadtool) or Steam big mode applications\n" + << "and after, set the SDL controller variable before you launch the executable, i.e:\n" + << "export SDL_GAMECONTROLLERCONFIG=\"[the string you received from controllermap]\""); + /* Need this so python args can return empty lists */ + joy_error = true; + } + + if (!joy_error) { + m_private->m_gamecontroller = SDL_GameControllerOpen(m_joyindex); + if (!m_private->m_gamecontroller) { + joy_error = true; + } + } + + SDL_Joystick *joy; + if (!joy_error) { + joy = SDL_GameControllerGetJoystick(m_private->m_gamecontroller); + if (!joy) { + joy_error = true; + } + } + + if (!joy_error) { + m_private->m_instance_id = SDL_JoystickInstanceID(joy); + if (m_private->m_instance_id < 0) { + joy_error = true; + CM_Error("joystick instanced failed: " << SDL_GetError()); + } + } + + if (!joy_error) { + CM_Debug("Game Controller (" << GetName() << ") with index " << m_joyindex << " initialized"); + + /* A Game Controller has: + * + * 6 axis availables: AXIS_LEFTSTICK_X, AXIS_LEFTSTICK_Y, + * (in order from 0 to 5) AXIS_RIGHTSTICK_X, AXIS_RIGHTSTICK_Y, + * AXIS_TRIGGERLEFT and AXIS_TRIGGERRIGHT. + * + * 15 buttons availables: BUTTON_A, BUTTON_B, BUTTON_X, BUTTON_Y, + * (in order from 0 to 14) BUTTON_BACK, BUTTON_GUIDE, BUTTON_START, + * BUTTON_LEFTSTICK, BUTTON_RIGHTSTICK, + * BUTTON_LEFTSHOULDER, BUTTON_RIGHTSHOULDER, + * BUTTON_DPAD_UP, BUTTON_DPAD_DOWN, + * BUTTON_DPAD_LEFT and BUTTON_DPAD_RIGHT. + */ + m_axismax = SDL_CONTROLLER_AXIS_MAX; + m_buttonmax = SDL_CONTROLLER_BUTTON_MAX; + } + + /* Haptic configuration */ + if (!joy_error && SDL_CHECK(SDL_HapticOpen)) { + m_private->m_haptic = SDL_HapticOpen(m_joyindex); + if (!m_private->m_haptic) { + CM_Warning("Game Controller (" << GetName() << ") with index " << m_joyindex + << " has not force feedback (vibration) available"); + } + } + } +#endif /* WITH_SDL */ + + if (joy_error) { + m_axismax = m_buttonmax = 0; + return false; + } + else { + m_isinit = true; + return true; + } +} + + +void DEV_Joystick::DestroyJoystickDevice(void) +{ +#ifdef WITH_SDL + if (m_isinit) { + + if (m_private->m_haptic && SDL_CHECK(SDL_HapticClose)) { + SDL_HapticClose(m_private->m_haptic); + m_private->m_haptic = nullptr; + } + + if (m_private->m_gamecontroller && SDL_CHECK(SDL_GameControllerClose)) { + CM_Debug("Game Controller (" << GetName() << ") with index " << m_joyindex << " closed"); + SDL_GameControllerClose(m_private->m_gamecontroller); + m_private->m_gamecontroller = nullptr; + } + + m_isinit = false; + } +#endif /* WITH_SDL */ +} + +int DEV_Joystick::Connected(void) +{ +#ifdef WITH_SDL + if (m_isinit && + (SDL_CHECK(SDL_GameControllerGetAttached) && + SDL_GameControllerGetAttached(m_private->m_gamecontroller))) { + return 1; + } +#endif + return 0; +} + +int DEV_Joystick::pGetAxis(int axisnum, int udlr) +{ +#ifdef WITH_SDL + return m_axis_array[(axisnum * 2) + udlr]; +#endif + return 0; +} + +int DEV_Joystick::pAxisTest(int axisnum) +{ +#ifdef WITH_SDL + /* Use ints instead of shorts here to avoid problems when we get -32768. + * When we take the negative of that later, we should get 32768, which is greater + * than what a short can hold. In other words, abs(MIN_SHORT) > MAX_SHRT. */ + int i1 = m_axis_array[(axisnum * 2)]; + int i2 = m_axis_array[(axisnum * 2) + 1]; + + /* long winded way to do: + * return max_ff(absf(i1), absf(i2)) + * ...avoid abs from math.h */ + if (i1 < 0) { + i1 = -i1; + } + if (i2 < 0) { + i2 = -i2; + } + if (i1 < i2) { + return i2; + } + else { + return i1; + } +#else /* WITH_SDL */ + return 0; +#endif /* WITH_SDL */ +} + +const std::string DEV_Joystick::GetName() +{ +#ifdef WITH_SDL + return (SDL_CHECK(SDL_GameControllerName)) ? SDL_GameControllerName(m_private->m_gamecontroller) : ""; +#else /* WITH_SDL */ + return ""; +#endif /* WITH_SDL */ +} diff --git a/source/gameengine/GameLogic/Joystick/SCA_Joystick.h b/source/gameengine/Device/DEV_Joystick.h similarity index 72% rename from source/gameengine/GameLogic/Joystick/SCA_Joystick.h rename to source/gameengine/Device/DEV_Joystick.h index e315f0c01d75..444fdda5ec5e 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_Joystick.h +++ b/source/gameengine/Device/DEV_Joystick.h @@ -25,14 +25,14 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file SCA_Joystick.h - * \ingroup gamelogic +/** \file DEV_Joystick.h + * \ingroup device */ -#ifndef __SCA_JOYSTICK_H__ -#define __SCA_JOYSTICK_H__ +#ifndef __DEV_JOYSTICK_H__ +#define __DEV_JOYSTICK_H__ -#include "SCA_JoystickDefines.h" +#include "DEV_JoystickDefines.h" #ifdef WITH_SDL /* SDL force defines __SSE__ and __SSE2__ flags, which generates warnings * because we pass those defines via command line as well. For until there's @@ -48,6 +48,8 @@ # endif #endif +#include + /** * Basic Joystick class * I will make this class a singleton because there should be only one joystick @@ -55,12 +57,10 @@ * The underlying joystick should only be removed when the last scene is removed */ -class SCA_Joystick +class DEV_Joystick { - static SCA_Joystick *m_instance[JOYINDEX_MAX]; - static int m_joynum; - static int m_refCount; + static DEV_Joystick *m_instance[JOYINDEX_MAX]; class PrivateData; #ifdef WITH_SDL @@ -68,16 +68,11 @@ class SCA_Joystick #endif int m_joyindex; - /** + /** *support for JOYAXIS_MAX axes (in pairs) */ int m_axis_array[JOYAXIS_MAX]; - - /** - *support for JOYHAT_MAX hats (each is a direction) - */ - int m_hat_array[JOYHAT_MAX]; - + /** * Precision or range of the axes */ @@ -86,33 +81,26 @@ class SCA_Joystick /** * max # of buttons avail */ - + int m_axismax; int m_buttonmax; - int m_hatmax; - + /** is the joystick initialized ?*/ bool m_isinit; - + /** is triggered for each event type */ bool m_istrig_axis; bool m_istrig_button; - bool m_istrig_hat; #ifdef WITH_SDL /** * event callbacks */ - void OnAxisMotion(SDL_Event *sdl_event); - void OnHatMotion(SDL_Event *sdl_event); - void OnButtonUp(SDL_Event *sdl_event); - void OnButtonDown(SDL_Event *sdl_event); + void OnAxisEvent(SDL_Event *sdl_event); + void OnButtonEvent(SDL_Event *sdl_event); void OnNothing(SDL_Event *sdl_event); -#if 0 /* not used yet */ - void OnBallMotion(SDL_Event *sdl_event) {} -#endif - + #endif /* WITH_SDL */ /** * Open the joystick @@ -124,11 +112,6 @@ class SCA_Joystick */ void DestroyJoystickDevice(void); - /** - * fills the axis member values - */ - void pFillButtons(void); - /** * returns m_axis_array */ @@ -139,16 +122,17 @@ class SCA_Joystick */ int pGetAxis(int axisnum, int udlr); - SCA_Joystick(short int index); - - ~SCA_Joystick(); + DEV_Joystick(short index); + ~DEV_Joystick(); + public: - static SCA_Joystick *GetInstance(short int joyindex); - static void HandleEvents(void); - void ReleaseInstance(); - + static DEV_Joystick *GetInstance(short joyindex); + static bool HandleEvents(short (&addrem)[JOYINDEX_MAX]); + void ReleaseInstance(short joyindex); + static void Init(); + static void Close(); /* */ @@ -159,7 +143,6 @@ class SCA_Joystick bool aAnyButtonPressIsPositive(void); bool aButtonPressIsPositive(int button); bool aButtonReleaseIsPositive(int button); - bool aHatIsPositive(int hatnum, int dir); /** * precision is default '3200' which is overridden by input @@ -171,33 +154,26 @@ class SCA_Joystick return m_axis_array[index]; } - int GetHat(int index) { - return m_hat_array[index]; - } - - int GetThreshold(void) { - return m_prec; - } - bool IsTrigAxis(void) { return m_istrig_axis; } - + bool IsTrigButton(void) { return m_istrig_button; } - bool IsTrigHat(void) { - return m_istrig_hat; - } - /** - * returns the # of... + * Force Feedback - Vibration + * We could add many optional arguments to these functions to take into account different sort of vibrations. + * But we propose to keep the UI simple with only joyindex, force (in both motors) and duration. + * As the vibration strength and duration can be updated on-fly it is possible to generate several types of vibration + * (sinus, periodic, custom, etc) using BGE python scripts for more advanced uses. */ - - int GetNumberOfAxes(void); - int GetNumberOfButtons(void); - int GetNumberOfHats(void); + bool RumblePlay(float strengthLeft, float strengthRight, unsigned int duration); + bool RumbleStop(); + bool GetRumbleStatus(); + bool GetRumbleSupport(); + void ProcessRumbleStatus(); /** * Test if the joystick is connected @@ -207,7 +183,8 @@ class SCA_Joystick /** * Name of the joytsick */ - const char *GetName(); + const std::string GetName(); }; -#endif +#endif // __DEV_JOYSTICK_H__ + diff --git a/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h b/source/gameengine/Device/DEV_JoystickDefines.h similarity index 71% rename from source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h rename to source/gameengine/Device/DEV_JoystickDefines.h index 566e55675072..40b59547d0f5 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h +++ b/source/gameengine/Device/DEV_JoystickDefines.h @@ -20,37 +20,35 @@ * * The Original Code is: all of this file. * - * Contributor(s): snailrose. + * Contributor(s): snailrose, lordloki. * * ***** END GPL LICENSE BLOCK ***** */ -/** \file SCA_JoystickDefines.h - * \ingroup gamelogic +/** \file DEV_JoystickDefines.h + * \ingroup device */ -#ifndef __SCA_JOYSTICKDEFINES_H__ -#define __SCA_JOYSTICKDEFINES_H__ +#ifndef __DEV_JOYSTICKDEFINES_H__ +#define __DEV_JOYSTICKDEFINES_H__ #ifdef main #undef main #endif -#ifndef DEBUG -# define JOYSTICK_ECHO(x) -#else -# include -# define JOYSTICK_ECHO(x) std::cout << x << std::endl; -#endif - #define JOYINDEX_MAX 8 -#define JOYAXIS_MAX 16 -#define JOYBUT_MAX 18 -#define JOYHAT_MAX 4 +#define JOYAXIS_MAX 6 +#define JOYBUT_MAX 15 #define JOYAXIS_RIGHT 0 #define JOYAXIS_UP 1 #define JOYAXIS_DOWN 3 #define JOYAXIS_LEFT 2 -#endif +#define JOYHAPTIC_PLAYING_EFFECT 0 +#define JOYHAPTIC_PLAYING_RUMBLE_EFFECT 1 +#define JOYHAPTIC_UPDATING_EFFECT 2 +#define JOYHAPTIC_UPDATING_RUMBLE_EFFECT 3 +#define JOYHAPTIC_STOPPED 4 + +#endif // __DEV_JOYSTICKDEFINES_H__ diff --git a/source/gameengine/Device/DEV_JoystickEvents.cpp b/source/gameengine/Device/DEV_JoystickEvents.cpp new file mode 100644 index 000000000000..d524f006d8d0 --- /dev/null +++ b/source/gameengine/Device/DEV_JoystickEvents.cpp @@ -0,0 +1,158 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): snailrose. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Device/DEV_JoystickEvents.cpp + * \ingroup device + */ + +#include "DEV_Joystick.h" +#include "DEV_JoystickPrivate.h" + +#include "CM_Message.h" + +#ifdef WITH_SDL +void DEV_Joystick::OnAxisEvent(SDL_Event *sdl_event) +{ + if (sdl_event->caxis.axis >= JOYAXIS_MAX) { + return; + } + + m_axis_array[sdl_event->caxis.axis] = sdl_event->caxis.value; + m_istrig_axis = 1; +} + +/* See notes below in the event loop */ +void DEV_Joystick::OnButtonEvent(SDL_Event *sdl_event) +{ + m_istrig_button = 1; +} + + +void DEV_Joystick::OnNothing(SDL_Event *sdl_event) +{ + m_istrig_axis = m_istrig_button = 0; +} + +bool DEV_Joystick::HandleEvents(short(&addrem)[JOYINDEX_MAX]) +{ + SDL_Event sdl_event; + bool remap = false; + + if (SDL_PollEvent == (void *)0) { + return 0; + } + + for (int i = 0; i < JOYINDEX_MAX; i++) { + if (DEV_Joystick::m_instance[i]) { + DEV_Joystick::m_instance[i]->OnNothing(&sdl_event); + } + } + + while (SDL_PollEvent(&sdl_event)) { + /* Note! m_instance[instance] + * will segfault if over JOYINDEX_MAX, not too nice but what are the chances? */ + + /* Note!, with buttons, this wont care which button is pressed, + * only to set 'm_istrig_button', actual pressed buttons are detected by SDL_ControllerGetButton */ + + /* Note!, if you manage to press and release a button within 1 logic tick + * it wont work as it should */ + + /* Note!, we need to use SDL_JOYDEVICE ADDED to find new controllers as SDL_CONTROLLERDEVICEADDED + * doesn't report about all devices connected at beginning. Additionally we capture all devices this + * way and we can inform properly (with ways to solve it) if the joystick it is not a game controller */ + + switch (sdl_event.type) { + case SDL_JOYDEVICEADDED: + { + if (sdl_event.jdevice.which < JOYINDEX_MAX) { + if (!DEV_Joystick::m_instance[sdl_event.jdevice.which]) { + DEV_Joystick::m_instance[sdl_event.jdevice.which] = new DEV_Joystick(sdl_event.jdevice.which); + DEV_Joystick::m_instance[sdl_event.jdevice.which]->CreateJoystickDevice(); + addrem[sdl_event.jdevice.which] = 1; + remap = true; + break; + } + else { + CM_Warning("conflicts with Joysticks trying to use the same index." + << " Please, reconnect Joysticks in different order than before"); + } + } + else { + CM_Warning("maximum quantity (8) of Game Controllers connected. It is not possible to set up additional ones."); + } + break; + } + case SDL_CONTROLLERDEVICEREMOVED: + { + for (int i = 0; i < JOYINDEX_MAX; i++) { + if (DEV_Joystick::m_instance[i]) { + if (sdl_event.cdevice.which == DEV_Joystick::m_instance[i]->m_private->m_instance_id) { + DEV_Joystick::m_instance[i]->ReleaseInstance(i); + addrem[i] = 2; + remap = true; + break; + } + } + } + break; + } + case SDL_CONTROLLERBUTTONDOWN: + case SDL_CONTROLLERBUTTONUP: + { + for (int i = 0; i < JOYINDEX_MAX; i++) { + if (DEV_Joystick::m_instance[i]) { + if (sdl_event.cdevice.which == DEV_Joystick::m_instance[i]->m_private->m_instance_id) { + DEV_Joystick::m_instance[i]->OnButtonEvent(&sdl_event); + break; + } + } + } + break; + } + case SDL_CONTROLLERAXISMOTION: + { + for (int i = 0; i < JOYINDEX_MAX; i++) { + if (DEV_Joystick::m_instance[i]) { + if (sdl_event.cdevice.which == DEV_Joystick::m_instance[i]->m_private->m_instance_id) { + DEV_Joystick::m_instance[i]->OnAxisEvent(&sdl_event); + break; + } + } + } + break; + } + default: + { + /* ignore old SDL_JOYSTICKS events */ + break; + } + } + } + return remap; +} +#endif /* WITH_SDL */ diff --git a/source/gameengine/GameLogic/Joystick/SCA_JoystickPrivate.h b/source/gameengine/Device/DEV_JoystickPrivate.h similarity index 61% rename from source/gameengine/GameLogic/Joystick/SCA_JoystickPrivate.h rename to source/gameengine/Device/DEV_JoystickPrivate.h index ab42eb570790..3a1f10899839 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_JoystickPrivate.h +++ b/source/gameengine/Device/DEV_JoystickPrivate.h @@ -20,33 +20,43 @@ * * The Original Code is: all of this file. * - * Contributor(s): snailrose. + * Contributor(s): snailrose, lordloki. * * ***** END GPL LICENSE BLOCK ***** */ - -/** \file SCA_JoystickPrivate.h - * \ingroup gamelogic + +/** \file DEV_JoystickPrivate.h + * \ingroup device */ -#ifndef __SCA_JOYSTICKPRIVATE_H__ -#define __SCA_JOYSTICKPRIVATE_H__ -#include "SCA_Joystick.h" +#ifndef __DEV_JOYSTICKPRIVATE_H__ +#define __DEV_JOYSTICKPRIVATE_H__ + +#include "DEV_JoystickDefines.h" #ifdef WITH_SDL -class SCA_Joystick::PrivateData +class DEV_Joystick::PrivateData { public: /* - * The Joystick + * The Game controller */ - SDL_Joystick* m_joystick; + SDL_GameController *m_gamecontroller; + SDL_JoystickID m_instance_id; + SDL_Haptic *m_haptic; + SDL_HapticEffect m_hapticeffect; + int m_hapticEffectId; + int m_hapticEffectStatus; + double m_hapticEndTime; PrivateData() - : m_joystick(NULL) + :m_gamecontroller(nullptr), + m_haptic(nullptr), + m_hapticEffectStatus(JOYHAPTIC_STOPPED), + m_hapticEndTime(0.0) { } }; -#endif /* WITH_SDL */ +#endif // WITH_SDL -#endif +#endif // __DEV_JOYSTICKPRIVATE_H__ diff --git a/source/gameengine/Device/DEV_JoystickVibration.cpp b/source/gameengine/Device/DEV_JoystickVibration.cpp new file mode 100644 index 000000000000..0dd08211a130 --- /dev/null +++ b/source/gameengine/Device/DEV_JoystickVibration.cpp @@ -0,0 +1,220 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + ** Contributor(s): youle, lordloki + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Device/DEV_JoystickVibration.cpp + * \ingroup device + */ + +#include // We have to include that on Windows to make memset available + +#include "DEV_Joystick.h" +#include "DEV_JoystickPrivate.h" +#include "DEV_JoystickDefines.h" +#include "CM_Message.h" +#include "PIL_time.h" // Module to get real time in Game Engine + + +bool DEV_Joystick::RumblePlay(float strengthLeft, float strengthRight, unsigned int duration) +{ +#ifdef WITH_SDL + unsigned int effects; + bool run_by_effect = false; + bool effects_issue = false; + + if (m_private->m_haptic == nullptr) { + return false; + } + + // Managing vibration logic + if (m_private->m_hapticEffectStatus == JOYHAPTIC_STOPPED) { + memset(&m_private->m_hapticeffect, 0, sizeof(SDL_HapticEffect)); // 0 is safe default + } + else if (m_private->m_hapticEffectStatus == JOYHAPTIC_PLAYING_EFFECT) { + m_private->m_hapticEffectStatus = JOYHAPTIC_UPDATING_EFFECT; + } + else if (m_private->m_hapticEffectStatus == JOYHAPTIC_PLAYING_RUMBLE_EFFECT) { + m_private->m_hapticEffectStatus = JOYHAPTIC_UPDATING_RUMBLE_EFFECT; + } + + // Checking supported effects + effects = SDL_HapticQuery(m_private->m_haptic); + + // LeftRight is the most supported effect by XInput game controllers + if ((effects & SDL_HAPTIC_LEFTRIGHT) && m_private->m_hapticEffectStatus != JOYHAPTIC_UPDATING_RUMBLE_EFFECT) { + if (m_private->m_hapticEffectStatus != JOYHAPTIC_UPDATING_EFFECT) { + m_private->m_hapticeffect.type = SDL_HAPTIC_LEFTRIGHT; + } + + m_private->m_hapticeffect.leftright.length = duration; + m_private->m_hapticeffect.leftright.large_magnitude = (unsigned int)(strengthLeft * 0x7FFF); + m_private->m_hapticeffect.leftright.small_magnitude = (unsigned int)(strengthRight * 0x7FFF); + run_by_effect = true; + + } + // Some Game Controllers only supports large/small magnitude motors using a custom effect + else if ((effects & SDL_HAPTIC_CUSTOM) && m_private->m_hapticEffectStatus != JOYHAPTIC_UPDATING_RUMBLE_EFFECT) { + + Uint16 data[2]; // data = channels * samples + data[0] = (Uint16)(strengthLeft * 0x7FFF); + data[1] = (Uint16)(strengthRight * 0x7FFF); + + if (m_private->m_hapticEffectStatus != JOYHAPTIC_UPDATING_EFFECT) { + m_private->m_hapticeffect.type = SDL_HAPTIC_CUSTOM; + } + m_private->m_hapticeffect.custom.length = duration; + m_private->m_hapticeffect.custom.channels = 2; + m_private->m_hapticeffect.custom.period = 1; + m_private->m_hapticeffect.custom.samples = 1; + m_private->m_hapticeffect.custom.data = data; + + run_by_effect = true; + } + + if (run_by_effect) { + bool new_effect = true; + + if (m_private->m_hapticEffectStatus == JOYHAPTIC_UPDATING_EFFECT) { + if (SDL_HapticUpdateEffect(m_private->m_haptic, m_private->m_hapticEffectId, &m_private->m_hapticeffect) == 0) { + m_private->m_hapticEffectStatus = JOYHAPTIC_PLAYING_EFFECT; + new_effect = false; + } + else { + SDL_HapticDestroyEffect(m_private->m_haptic, m_private->m_hapticEffectId); + m_private->m_hapticEffectId = -1; + } + } + + if (new_effect) { + // Upload the effect + m_private->m_hapticEffectId = SDL_HapticNewEffect(m_private->m_haptic, &m_private->m_hapticeffect); + } + + // Run the effect + if (m_private->m_hapticEffectId >= 0 && + SDL_HapticRunEffect(m_private->m_haptic, m_private->m_hapticEffectId, 1) != -1) { + m_private->m_hapticEffectStatus = JOYHAPTIC_PLAYING_EFFECT; + } + else { + effects_issue = true; + } + } + + // Initialize simplest rumble effect for both motors if more complex effects are not supported + // Most controllers can use SINE effect, but XInput only has LEFTRIGHT. + if (effects_issue || m_private->m_hapticEffectStatus == JOYHAPTIC_UPDATING_RUMBLE_EFFECT) { + bool new_effect = true; + + if (m_private->m_hapticEffectStatus != JOYHAPTIC_UPDATING_RUMBLE_EFFECT) { + m_private->m_hapticeffect.type = SDL_HAPTIC_SINE; + } + + m_private->m_hapticeffect.periodic.period = 1000; + m_private->m_hapticeffect.periodic.magnitude = (unsigned int)(strengthLeft * 0x7FFF); + m_private->m_hapticeffect.periodic.length = duration; + m_private->m_hapticeffect.periodic.attack_length = 0; + m_private->m_hapticeffect.periodic.fade_length = 0; + + if (m_private->m_hapticEffectStatus == JOYHAPTIC_UPDATING_RUMBLE_EFFECT) { + if (SDL_HapticUpdateEffect(m_private->m_haptic, m_private->m_hapticEffectId, &m_private->m_hapticeffect) == 0) { + m_private->m_hapticEffectStatus = JOYHAPTIC_PLAYING_RUMBLE_EFFECT; + new_effect = false; + } + else { + SDL_HapticDestroyEffect(m_private->m_haptic, m_private->m_hapticEffectId); + m_private->m_hapticEffectId = -1; + CM_Error("Vibration can not be updated. Trying other approach."); + } + } + + if (new_effect) { + // Upload the effect + m_private->m_hapticEffectId = SDL_HapticNewEffect(m_private->m_haptic, &m_private->m_hapticeffect); + } + + // Run the effect + if (m_private->m_hapticEffectId >= 0 && + SDL_HapticRunEffect(m_private->m_haptic, m_private->m_hapticEffectId, 1) != -1) { + m_private->m_hapticEffectStatus = JOYHAPTIC_PLAYING_RUMBLE_EFFECT; + } + else { + SDL_HapticDestroyEffect(m_private->m_haptic, m_private->m_hapticEffectId); + m_private->m_hapticEffectId = -1; + m_private->m_hapticEffectStatus = JOYHAPTIC_STOPPED; + CM_Error("Vibration not reproduced. Rumble can not initialized/played"); + m_private->m_hapticEndTime = 0.0; + return false; + } + } + m_private->m_hapticEndTime = PIL_check_seconds_timer() * 1000.0 + (double)duration; + return true; +#endif // WITH_SDL + return false; +} + +bool DEV_Joystick::RumbleStop() +{ +#ifdef WITH_SDL + if (m_private->m_haptic == nullptr) { + return false; + } + + if (m_private->m_hapticEffectStatus != JOYHAPTIC_STOPPED) { + m_private->m_hapticEffectStatus = JOYHAPTIC_STOPPED; + } + SDL_HapticDestroyEffect(m_private->m_haptic, m_private->m_hapticEffectId); + m_private->m_hapticEndTime = 0.0; + return true; +#endif + return false; +} + +bool DEV_Joystick::GetRumbleStatus() +{ +#ifdef WITH_SDL + return (m_private->m_hapticEffectStatus != JOYHAPTIC_STOPPED); +#endif + return false; +} + +bool DEV_Joystick::GetRumbleSupport() +{ +#ifdef WITH_SDL + return (m_private->m_haptic); +#endif + return false; +} + +// We can not trust in SDL_HapticGetEffectStatus function as it is not supported +// in the most used game controllers. Then we work around it using own time management. +void DEV_Joystick::ProcessRumbleStatus() +{ +#ifdef WITH_SDL + if (m_private->m_haptic == nullptr) { + return; + } + + if ((PIL_check_seconds_timer() * 1000.0) >= m_private->m_hapticEndTime) { + RumbleStop(); + } +#endif + return; +} diff --git a/source/gameengine/Expressions/CMakeLists.txt b/source/gameengine/Expressions/CMakeLists.txt index 9c563a46ea2b..1d1856369e69 100644 --- a/source/gameengine/Expressions/CMakeLists.txt +++ b/source/gameengine/Expressions/CMakeLists.txt @@ -25,17 +25,22 @@ set(INC . + ../Common ../SceneGraph ../../blender/blenlib ../../../intern/guardedalloc - ../../../intern/string + ../../../intern/termcolor ) set(INC_SYS - ../../../intern/moto/include + ../../../intern/debugbreak + ../../../intern/mathfu + ${BOOST_INCLUDE_DIR} ) set(SRC + intern/BaseListValue.cpp + intern/BaseListWrapper.cpp intern/BoolValue.cpp intern/ConstExpr.cpp intern/EmptyValue.cpp @@ -46,38 +51,31 @@ set(SRC intern/IfExpr.cpp intern/InputParser.cpp intern/IntValue.cpp - intern/HashedPtr.cpp - intern/ListValue.cpp intern/Operator1Expr.cpp intern/Operator2Expr.cpp intern/PyObjectPlus.cpp intern/StringValue.cpp intern/Value.cpp - intern/VectorValue.cpp - intern/ListWrapper.cpp + EXP_BaseListValue.h + EXP_BaseListWrapper.h EXP_BoolValue.h EXP_ConstExpr.h EXP_EmptyValue.h EXP_ErrorValue.h EXP_Expression.h EXP_FloatValue.h - EXP_HashedPtr.h EXP_IdentifierExpr.h EXP_IfExpr.h EXP_InputParser.h EXP_IntValue.h - EXP_ListValue.h EXP_Operator1Expr.h EXP_Operator2Expr.h EXP_PyObjectPlus.h EXP_Python.h EXP_StringValue.h EXP_Value.h - EXP_VectorValue.h - EXP_VoidValue.h EXP_ListWrapper.h - ) if(WITH_PYTHON) diff --git a/source/gameengine/Expressions/EXP_BaseListValue.h b/source/gameengine/Expressions/EXP_BaseListValue.h new file mode 100644 index 000000000000..d1c6eb988909 --- /dev/null +++ b/source/gameengine/Expressions/EXP_BaseListValue.h @@ -0,0 +1,85 @@ +/* + * ListValue.h: interface for the EXP_BaseListValue class. + * Copyright (c) 1996-2000 Erwin Coumans + * + * 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. Erwin Coumans makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +/** \file EXP_BaseListValue.h + * \ingroup expressions + */ + +#ifndef __EXP_BASELISTVALUE_H__ +#define __EXP_BASELISTVALUE_H__ + +#include "EXP_Value.h" + +class EXP_BaseListValue : public EXP_PropValue +{ + Py_Header + +public: + typedef std::vector VectorType; + typedef VectorType::iterator VectorTypeIterator; + typedef VectorType::const_iterator VectorTypeConstIterator; + +protected: + VectorType m_valueArray; + bool m_bReleaseContents; + + void SetValue(int i, EXP_Value *val); + EXP_Value *GetValue(int i); + EXP_Value *FindValue(const std::string& name) const; + bool SearchValue(EXP_Value *val) const; + void Add(EXP_Value *value); + void Insert(unsigned int i, EXP_Value *value); + bool RemoveValue(EXP_Value *val); + bool CheckEqual(EXP_Value *first, EXP_Value *second); + +public: + EXP_BaseListValue(); + virtual ~EXP_BaseListValue(); + + virtual int GetValueType(); + virtual EXP_Value *GetReplica() = 0; + virtual std::string GetText(); + + void SetReleaseOnDestruct(bool bReleaseContents); + + void Remove(int i); + void Resize(int num); + void ReleaseAndRemoveAll(); + int GetCount() const; + bool Empty() const; + +#ifdef WITH_PYTHON + + EXP_PYMETHOD_O(EXP_BaseListValue, append); + EXP_PYMETHOD_NOARGS(EXP_BaseListValue, reverse); + EXP_PYMETHOD_O(EXP_BaseListValue, index); + EXP_PYMETHOD_O(EXP_BaseListValue, count); + EXP_PYMETHOD_VARARGS(EXP_BaseListValue, get); + EXP_PYMETHOD_VARARGS(EXP_BaseListValue, filter); + EXP_PYMETHOD_O(EXP_BaseListValue, from_id); + + static Py_ssize_t bufferlen(PyObject *self); + static PyObject *buffer_item(PyObject *self, Py_ssize_t index); + static PyObject *buffer_slice(EXP_BaseListValue *list, Py_ssize_t start, Py_ssize_t stop); + static PyObject *mapping_subscript(PyObject *self, PyObject *key); + static PyObject *buffer_concat(PyObject *self, PyObject *other); + static int buffer_contains(PyObject *self_v, PyObject *value); + + static PySequenceMethods as_sequence; + static PyMappingMethods instance_as_mapping; +#endif +}; + +#endif // __EXP_LISTVALUE_H__ + diff --git a/source/gameengine/Expressions/EXP_BaseListWrapper.h b/source/gameengine/Expressions/EXP_BaseListWrapper.h new file mode 100644 index 000000000000..a65673ed7f3a --- /dev/null +++ b/source/gameengine/Expressions/EXP_BaseListWrapper.h @@ -0,0 +1,106 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Porteries Tristan. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file EXP_BaseListWrapper.h + * \ingroup expressions + */ + +#ifdef WITH_PYTHON + +#ifndef __EXP_BASELISTWRAPPER_H__ +#define __EXP_BASELISTWRAPPER_H__ + +#include "EXP_Value.h" + +class EXP_BaseListWrapper : public EXP_Value +{ + Py_Header +public: + + using GetItemFunction = PyObject *(*)(EXP_PyObjectPlus *, unsigned int); + using GetItemNameFunction = std::string (*)(EXP_PyObjectPlus *, unsigned int); + using GetSizeFunction = unsigned int (*)(EXP_PyObjectPlus *); + using SetItemFunction = bool (*)(EXP_PyObjectPlus *, unsigned int, PyObject *); +private: + /// The client instance passed as first argument of each callback. + EXP_PyObjectPlus *m_client; + /// Weak reference to the client proxy. + PyObject *m_weakRef; + /// Returns the list size. + GetSizeFunction m_getSize; + /// Returns the list item for the giving index. + GetItemFunction m_getItem; + /// Returns name item for the giving index, used for python operator list["name"]. + GetItemNameFunction m_getItemName; + /// Sets the new item to the index place, return false when failed item conversion. + SetItemFunction m_setItem; + + /// Flags used to define special behaviours of the list. + int m_flag; + +public: + enum Flag { + FLAG_NONE = 0, + /// Allow iterating on all items and compare the value of it with a research key. + FLAG_FIND_VALUE = (1 << 0), + /// Allow no validation using weak ref. + FLAG_NO_WEAK_REF = (1 << 1) + }; + + EXP_BaseListWrapper(EXP_PyObjectPlus *client, + GetSizeFunction getSize, GetItemFunction getItem, + GetItemNameFunction getItemName, SetItemFunction setItem, Flag flag = FLAG_NONE); + virtual ~EXP_BaseListWrapper(); + + /// \section Python Interface + static bool CheckValid(EXP_BaseListWrapper *list); + unsigned int GetSize() const; + PyObject *GetItem(int index) const; + std::string GetItemName(int index) const; + bool SetItem(int index, PyObject *item); + bool AllowSetItem() const; + bool AllowGetItemByName() const; + bool AllowFindValue() const; + + /// \section EXP_Value Inherited Functions. + virtual std::string GetName(); + virtual std::string GetText(); + virtual int GetValueType(); + + // Python list operators. + static PySequenceMethods py_as_sequence; + // Python dictionnary operators. + static PyMappingMethods py_as_mapping; + + static Py_ssize_t py_len(PyObject *self); + static PyObject *py_get_item(PyObject *self, Py_ssize_t index); + static int py_set_item(PyObject *self, Py_ssize_t index, PyObject *value); + static PyObject *py_mapping_subscript(PyObject *self, PyObject *key); + static int py_mapping_ass_subscript(PyObject *self, PyObject *key, PyObject *value); + static int py_contains(PyObject *self, PyObject *key); + + EXP_PYMETHOD_VARARGS(EXP_BaseListWrapper, Get); +}; + +#endif // __EXP_BASELISTWRAPPER_H__ + +#endif // WITH_PYTHON diff --git a/source/gameengine/Expressions/EXP_BoolValue.h b/source/gameengine/Expressions/EXP_BoolValue.h index 89c724e87ee1..2416dcc5ae13 100644 --- a/source/gameengine/Expressions/EXP_BoolValue.h +++ b/source/gameengine/Expressions/EXP_BoolValue.h @@ -1,5 +1,5 @@ /* - * BoolValue.h: interface for the CBoolValue class. + * BoolValue.h: interface for the EXP_BoolValue class. * Copyright (c) 1996-2000 Erwin Coumans * * Permission to use, copy, modify, distribute and sell this software @@ -21,45 +21,35 @@ #include "EXP_Value.h" -/** - * Smart Boolean Value class. +/** Smart Boolean Value class. * Is used by parser when an expression tree is build containing booleans. */ - -class CBoolValue : public CPropValue +class EXP_BoolValue : public EXP_PropValue { - - //PLUGIN_DECLARE_SERIAL(CBoolValue,CValue) - public: - static const STR_String sTrueString; - static const STR_String sFalseString; + static const std::string sTrueString; + static const std::string sFalseString; - CBoolValue(); - CBoolValue(bool inBool); - CBoolValue(bool innie, const char *name, AllocationTYPE alloctype = CValue::HEAPVALUE); + EXP_BoolValue(); + EXP_BoolValue(bool inBool); + EXP_BoolValue(bool innie, const std::string& name); - virtual const STR_String& GetText(); - virtual double GetNumber(); - virtual int GetValueType(); - bool GetBool(); - virtual void SetValue(CValue* newval); + virtual std::string GetText(); + virtual double GetNumber(); + virtual int GetValueType(); + bool GetBool(); + virtual void SetValue(EXP_Value *newval); - virtual CValue* Calc(VALUE_OPERATOR op, CValue *val); - virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); + virtual EXP_Value *Calc(VALUE_OPERATOR op, EXP_Value *val); + virtual EXP_Value *CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, EXP_Value *val); - void Configure(CValue* menuvalue); - virtual CValue* GetReplica(); + virtual EXP_Value *GetReplica(); #ifdef WITH_PYTHON - virtual PyObject* ConvertValueToPython(); + virtual PyObject *ConvertValueToPython(); #endif private: - bool m_bool; - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:CBoolValue") -#endif + bool m_bool; }; -#endif /* __EXP_BOOLVALUE_H__ */ +#endif // __EXP_BOOLVALUE_H__ diff --git a/source/gameengine/Expressions/EXP_ConstExpr.h b/source/gameengine/Expressions/EXP_ConstExpr.h index ddc7df14ff16..3582a056f592 100644 --- a/source/gameengine/Expressions/EXP_ConstExpr.h +++ b/source/gameengine/Expressions/EXP_ConstExpr.h @@ -1,5 +1,5 @@ /* - * ConstExpr.h: interface for the CConstExpr class. + * ConstExpr.h: interface for the EXP_ConstExpr class. * Copyright (c) 1996-2000 Erwin Coumans * * Permission to use, copy, modify, distribute and sell this software @@ -20,35 +20,21 @@ #define __EXP_CONSTEXPR_H__ #include "EXP_Expression.h" -#include "EXP_Value.h" // Added by ClassView +#include "EXP_Value.h" -class CConstExpr : public CExpression +class EXP_ConstExpr : public EXP_Expression { - //PLUGIN_DECLARE_SERIAL_EXPRESSION (CConstExpr,CExpression) public: - virtual bool MergeExpression(CExpression* otherexpr); - - void BroadcastOperators(VALUE_OPERATOR op); + EXP_ConstExpr(); + EXP_ConstExpr(EXP_Value *constval); + virtual ~EXP_ConstExpr(); virtual unsigned char GetExpressionID(); - CExpression* CheckLink(std::vector& brokenlinks); - //bool IsInside(float x,float y,float z,bool bBorderInclude=true); - bool NeedsRecalculated(); - void ClearModified(); virtual double GetNumber(); - virtual CValue* Calculate(); - CConstExpr(CValue* constval); - CConstExpr(); - virtual ~CConstExpr(); - + virtual EXP_Value *Calculate(); private: - CValue* m_value; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:CConstExpr") -#endif + EXP_Value *m_value; }; -#endif /* __EXP_CONSTEXPR_H__ */ +#endif // __EXP_CONSTEXPR_H__ diff --git a/source/gameengine/Expressions/EXP_EmptyValue.h b/source/gameengine/Expressions/EXP_EmptyValue.h index e3be9f0c2c46..27a30304c950 100644 --- a/source/gameengine/Expressions/EXP_EmptyValue.h +++ b/source/gameengine/Expressions/EXP_EmptyValue.h @@ -1,5 +1,5 @@ /* - * EmptyValue.h: interface for the CEmptyValue class. + * EmptyValue.h: interface for the EXP_EmptyValue class. * Copyright (c) 1996-2000 Erwin Coumans * * Permission to use, copy, modify, distribute and sell this software @@ -21,29 +21,18 @@ #include "EXP_Value.h" -class CListValue; - -class CEmptyValue : public CPropValue +class EXP_EmptyValue : public EXP_PropValue { - //PLUGIN_DECLARE_SERIAL (CEmptyValue,CValue) public: - CEmptyValue(); - virtual ~CEmptyValue(); - - virtual const STR_String & GetText(); - virtual double GetNumber(); - virtual int GetValueType(); - CListValue* GetPolySoup(); - virtual double* GetVector3(bool bGetTransformedVec=false); - bool IsInside(CValue* testpoint,bool bBorderInclude=true); - CValue * Calc(VALUE_OPERATOR op, CValue *val); - CValue * CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); - virtual CValue* GetReplica(); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:CEmptyValue") -#endif + EXP_EmptyValue(); + virtual ~EXP_EmptyValue(); + + virtual std::string GetText(); + virtual double GetNumber(); + virtual int GetValueType(); + virtual EXP_Value *Calc(VALUE_OPERATOR op, EXP_Value *val); + virtual EXP_Value *CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, EXP_Value *val); + virtual EXP_Value *GetReplica(); }; -#endif /* __EXP_EMPTYVALUE_H__ */ +#endif // __EXP_EMPTYVALUE_H__ diff --git a/source/gameengine/Expressions/EXP_ErrorValue.h b/source/gameengine/Expressions/EXP_ErrorValue.h index aa2b1a682417..06abc2cbc0d9 100644 --- a/source/gameengine/Expressions/EXP_ErrorValue.h +++ b/source/gameengine/Expressions/EXP_ErrorValue.h @@ -1,5 +1,5 @@ /* - * ErrorValue.h: interface for the CErrorValue class. + * ErrorValue.h: interface for the EXP_ErrorValue class. * Copyright (c) 1996-2000 Erwin Coumans * * Permission to use, copy, modify, distribute and sell this software @@ -21,27 +21,22 @@ #include "EXP_Value.h" -class CErrorValue : public CPropValue +class EXP_ErrorValue : public EXP_PropValue { - public: - virtual const STR_String & GetText(); - virtual double GetNumber(); + EXP_ErrorValue(); + EXP_ErrorValue(const std::string& errmsg); + virtual ~EXP_ErrorValue(); + + virtual std::string GetText(); virtual int GetValueType(); - CErrorValue(); - CErrorValue(const char *errmsg); - virtual ~CErrorValue(); - virtual CValue* Calc(VALUE_OPERATOR op, CValue* val); - virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); - virtual CValue* GetReplica(); + virtual EXP_Value *Calc(VALUE_OPERATOR op, EXP_Value *val); + virtual EXP_Value *CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, EXP_Value *val); + virtual EXP_Value *GetReplica(); + virtual bool IsError() const; private: - STR_String m_strErrorText; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:CErrorValue") -#endif + std::string m_strErrorText; }; -#endif /* __EXP_ERRORVALUE_H__ */ +#endif // __EXP_ERRORVALUE_H__ diff --git a/source/gameengine/Expressions/EXP_Expression.h b/source/gameengine/Expressions/EXP_Expression.h index 0ed8c9503b39..a20b6c8e099b 100644 --- a/source/gameengine/Expressions/EXP_Expression.h +++ b/source/gameengine/Expressions/EXP_Expression.h @@ -1,5 +1,5 @@ /* - * Expression.h: interface for the CExpression class. + * Expression.h: interface for the EXP_Expression class. * Copyright (c) 1996-2000 Erwin Coumans * * Permission to use, copy, modify, distribute and sell this software @@ -21,129 +21,26 @@ #include "EXP_Value.h" -//extern int gRefCountExpr; // only for debugging purposes (detect mem.leaks) - - -#define PLUGIN_DECLARE_SERIAL_EXPRESSION(class_name, base_class_name) \ -public: \ - virtual base_class_name * Copy() { \ - return new class_name; \ - } \ - virtual bool EdSerialize(CompressorArchive& arch, \ - class CFactoryManager* facmgr, \ - bool bIsStoring); \ - virtual bool EdIdSerialize(CompressorArchive& arch, \ - class CFactoryManager* facmgr, \ - bool bIsStoring) \ - { \ - if (bIsStoring) \ - { \ - unsigned char exprID = GetExpressionID(); \ - arch << exprID; \ - } \ - return true; \ - } \ - - - -class CExpression; - - -// for undo/redo system the deletion in the expressiontree can be restored by replacing broken links 'inplace' -class CBrokenLinkInfo -{ - public: - CBrokenLinkInfo(CExpression** pmemexpr,CExpression* expr) - :m_pmemExpr(pmemexpr), - m_pExpr(expr) - { - assertd(pmemexpr); - m_bRestored=false; - }; - - virtual ~CBrokenLinkInfo(); - void RestoreLink(); - void BreakLink(); - - - // members vars - private: - CExpression** m_pmemExpr; - CExpression* m_pExpr; - bool m_bRestored; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:CBrokenLinkInfo") -#endif -}; - - - - - - - - -class CExpression +class EXP_Expression : public CM_RefCount { public: enum { - COPERATOR1EXPRESSIONID = 1, - COPERATOR2EXPRESSIONID = 2, - CCONSTEXPRESSIONID = 3, - CIFEXPRESSIONID = 4, - COPERATORVAREXPRESSIONID = 5, - CIDENTIFIEREXPRESSIONID = 6 + COPERATOR1EXPRESSIONID = 1, + COPERATOR2EXPRESSIONID = 2, + CCONSTEXPRESSIONID = 3, + CIFEXPRESSIONID = 4, + COPERATORVAREXPRESSIONID = 5, + CIDENTIFIEREXPRESSIONID = 6 }; - protected: - virtual ~CExpression() = 0; //pure virtual -public: - virtual bool MergeExpression(CExpression* otherexpr) = 0; - CExpression(); - - - virtual CValue* Calculate() = 0; //pure virtual - virtual unsigned char GetExpressionID() = 0; - //virtual bool IsInside(float x,float y,float z,bool bBorderInclude=true) = 0; //pure virtual - virtual bool NeedsRecalculated() = 0; // another pure one - virtual CExpression * CheckLink(std::vector& brokenlinks) =0; // another pure one - virtual void ClearModified() = 0; // another pure one - //virtual CExpression * Copy() =0; - virtual void BroadcastOperators(VALUE_OPERATOR op) =0; - - virtual CExpression * AddRef() { // please leave multiline, for debugger !!! - -#ifdef DEBUG - //gRefCountExpr++; - assertd(m_refcount < 255); -#endif - m_refcount++; - return this; - }; - virtual CExpression* Release(CExpression* complicatedtrick=NULL) { -#ifdef DEBUG - //gRefCountExpr--; -#endif - if (--m_refcount < 1) - { - delete this; - } //else - // return this; - return complicatedtrick; - }; - - -protected: - - int m_refcount; + virtual ~EXP_Expression() = 0; +public: + EXP_Expression(); -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:CExpression") -#endif + virtual EXP_Value *Calculate() = 0; + virtual unsigned char GetExpressionID() = 0; }; -#endif /* __EXP_EXPRESSION_H__ */ +#endif // __EXP_EXPRESSION_H__ diff --git a/source/gameengine/Expressions/EXP_FloatValue.h b/source/gameengine/Expressions/EXP_FloatValue.h index 5ec22d0fcb4e..234c53dbb005 100644 --- a/source/gameengine/Expressions/EXP_FloatValue.h +++ b/source/gameengine/Expressions/EXP_FloatValue.h @@ -1,5 +1,5 @@ /* - * FloatValue.h: interface for the CFloatValue class. + * FloatValue.h: interface for the EXP_FloatValue class. * Copyright (c) 1996-2000 Erwin Coumans * * Permission to use, copy, modify, distribute and sell this software @@ -21,38 +21,30 @@ #include "EXP_Value.h" -class CFloatValue : public CPropValue +class EXP_FloatValue : public EXP_PropValue { - //PLUGIN_DECLARE_SERIAL (CFloatValue,CValue) public: - CFloatValue(); - CFloatValue(float fl); - CFloatValue(float fl,const char *name,AllocationTYPE alloctype=CValue::HEAPVALUE); + EXP_FloatValue(); + EXP_FloatValue(float fl); + EXP_FloatValue(float fl, const std::string& name); - virtual const STR_String & GetText(); + virtual std::string GetText(); - void Configure(CValue* menuvalue); virtual double GetNumber(); virtual int GetValueType(); - virtual void SetValue(CValue* newval); + virtual void SetValue(EXP_Value *newval); float GetFloat(); void SetFloat(float fl); - virtual ~CFloatValue(); - virtual CValue* GetReplica(); - virtual CValue* Calc(VALUE_OPERATOR op, CValue *val); - virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); + virtual ~EXP_FloatValue(); + virtual EXP_Value *GetReplica(); + virtual EXP_Value *Calc(VALUE_OPERATOR op, EXP_Value *val); + virtual EXP_Value *CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, EXP_Value *val); #ifdef WITH_PYTHON - virtual PyObject* ConvertValueToPython(); + virtual PyObject *ConvertValueToPython(); #endif protected: float m_float; - STR_String* m_pstrRep; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:CFloatValue") -#endif }; -#endif /* __EXP_FLOATVALUE_H__ */ +#endif // __EXP_FLOATVALUE_H__ diff --git a/source/gameengine/Expressions/EXP_IdentifierExpr.h b/source/gameengine/Expressions/EXP_IdentifierExpr.h index 96ef3677cf36..081c6809a79f 100644 --- a/source/gameengine/Expressions/EXP_IdentifierExpr.h +++ b/source/gameengine/Expressions/EXP_IdentifierExpr.h @@ -34,26 +34,18 @@ #include "EXP_Expression.h" -class CIdentifierExpr : public CExpression +class EXP_IdentifierExpr : public EXP_Expression { - CValue* m_idContext; - STR_String m_identifier; -public: - CIdentifierExpr(const STR_String& identifier,CValue* id_context); - virtual ~CIdentifierExpr(); - - virtual CValue* Calculate(); - virtual bool MergeExpression(CExpression* otherexpr); - virtual unsigned char GetExpressionID(); - virtual bool NeedsRecalculated(); - virtual CExpression* CheckLink(std::vector& brokenlinks); - virtual void ClearModified(); - virtual void BroadcastOperators(VALUE_OPERATOR op); +private: + EXP_Value *m_idContext; + std::string m_identifier; +public: + EXP_IdentifierExpr(const std::string& identifier, EXP_Value *id_context); + virtual ~EXP_IdentifierExpr(); -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:CIdentifierExpr") -#endif + virtual EXP_Value *Calculate(); + virtual unsigned char GetExpressionID(); }; -#endif /* __EXP_IDENTIFIEREXPR_H__ */ +#endif // __EXP_IDENTIFIEREXPR_H__ diff --git a/source/gameengine/Expressions/EXP_IfExpr.h b/source/gameengine/Expressions/EXP_IfExpr.h index 929f3a3ada97..189facc58f57 100644 --- a/source/gameengine/Expressions/EXP_IfExpr.h +++ b/source/gameengine/Expressions/EXP_IfExpr.h @@ -1,5 +1,5 @@ /* - * IfExpr.h: interface for the CIfExpr class. + * IfExpr.h: interface for the EXP_IfExpr class. * Copyright (c) 1996-2000 Erwin Coumans * * Permission to use, copy, modify, distribute and sell this software @@ -21,34 +21,20 @@ #include "EXP_Expression.h" -class CIfExpr : public CExpression +class EXP_IfExpr : public EXP_Expression { - //PLUGIN_DECLARE_SERIAL_EXPRESSION (CIfExpr,CExpression) - private: - CExpression *m_guard, *m_e1, *m_e2; + EXP_Expression *m_guard; + EXP_Expression *m_e1; + EXP_Expression *m_e2; public: - virtual bool MergeExpression(CExpression* otherexpr); - CIfExpr(CExpression *guard, CExpression *e1, CExpression *e2); - CIfExpr(); + EXP_IfExpr(); + EXP_IfExpr(EXP_Expression *guard, EXP_Expression *e1, EXP_Expression *e2); + virtual ~EXP_IfExpr(); virtual unsigned char GetExpressionID(); - virtual ~CIfExpr(); - virtual CValue* Calculate(); - - virtual bool IsInside(float x,float y,float z,bool bBorderInclude=true); - virtual bool NeedsRecalculated(); - - - virtual CExpression* CheckLink(std::vector& brokenlinks); - virtual void ClearModified(); - virtual void BroadcastOperators(VALUE_OPERATOR op); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:CIfExpr") -#endif + virtual EXP_Value *Calculate(); }; -#endif /* __EXP_IFEXPR_H__ */ +#endif // __EXP_IFEXPR_H__ diff --git a/source/gameengine/Expressions/EXP_InputParser.h b/source/gameengine/Expressions/EXP_InputParser.h index 655695db3c01..14ceeba11ffc 100644 --- a/source/gameengine/Expressions/EXP_InputParser.h +++ b/source/gameengine/Expressions/EXP_InputParser.h @@ -1,5 +1,5 @@ /* - * Parser.h: interface for the CParser class. + * Parser.h: interface for the EXP_Parser class. * Eindhoven University of Technology 1997 * OOPS team (Serge vd Boom, Erwin Coumans, Tom Geelen, Wynke Stuylemeier) * Copyright (c) 1996-2000 Erwin Coumans @@ -21,20 +21,18 @@ #ifndef __EXP_INPUTPARSER_H__ #define __EXP_INPUTPARSER_H__ -class CParser; +class EXP_Parser; #include "EXP_Expression.h" -class CParser +class EXP_Parser { public: - CParser(); - virtual ~CParser(); + EXP_Parser(); + virtual ~EXP_Parser(); - float GetFloat(STR_String& txt); - CValue* GetValue(STR_String& txt, bool bFallbackToText=false); - CExpression* ProcessText(const char *intext); - void SetContext(CValue* context); + EXP_Expression* ProcessText(const std::string& intext); + void SetContext(EXP_Value* context); private: enum symbols { @@ -75,23 +73,23 @@ class CParser floattype, stringtype }; // all kinds of constants - + int sym, // current symbol opkind, // kind of operator, if symbol is an operator constkind; // kind of operator, if symbol is a constant - + char ch; // current character int chcount; // index to character in input string - CExpression *errmsg; // contains a errormessage, if scanner error - - STR_String text, // contains a copy of the original text + EXP_Expression *errmsg; // contains a errormessage, if scanner error + + std::string text, // contains a copy of the original text const_as_string; // string representation of the symbol, if symbol is a constant bool boolvalue; // value of the boolean, if symbol is a constant of type boolean - CValue* m_identifierContext;// context in which identifiers are looked up - - - void ScanError(const char *str); - CExpression* Error(const char *str); + EXP_Value* m_identifierContext;// context in which identifiers are looked up + + + void ScanError(const std::string& str); + EXP_Expression* Error(const std::string& str); void NextCh(); void TermChar(char c); void DigRep(); @@ -99,19 +97,12 @@ class CParser void GrabString(int start); void GrabRealString(int start); void NextSym(); -#if 0 /* not used yet */ - int MakeInt(); -#endif - const char *Symbol2Str(int s); + const std::string Symbol2Str(int s); void Term(int s); int Priority(int optor); - CExpression *Ex(int i); - CExpression *Expr(); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:CParser") -#endif + EXP_Expression *Ex(int i); + EXP_Expression *Expr(); }; #endif /* __EXP_INPUTPARSER_H__ */ + diff --git a/source/gameengine/Expressions/EXP_IntValue.h b/source/gameengine/Expressions/EXP_IntValue.h index 8c66ba7c3bf9..bc9cc3bd216f 100644 --- a/source/gameengine/Expressions/EXP_IntValue.h +++ b/source/gameengine/Expressions/EXP_IntValue.h @@ -1,5 +1,5 @@ /* - * IntValue.h: interface for the CIntValue class. + * IntValue.h: interface for the EXP_IntValue class. * Copyright (c) 1996-2000 Erwin Coumans * * Permission to use, copy, modify, distribute and sell this software @@ -24,50 +24,33 @@ typedef long long cInt; -class CIntValue : public CPropValue +class EXP_IntValue : public EXP_PropValue { - //PLUGIN_DECLARE_SERIAL (CIntValue,CValue) - public: - virtual const STR_String& GetText(); - virtual double GetNumber(); - virtual int GetValueType(); + EXP_IntValue(); + EXP_IntValue(cInt innie); + EXP_IntValue(cInt innie, const std::string& name); + virtual ~EXP_IntValue(); - cInt GetInt(); - CIntValue(); - CIntValue(cInt innie); - CIntValue(cInt innie, - const char *name, - AllocationTYPE alloctype=CValue::HEAPVALUE); + virtual std::string GetText(); + virtual double GetNumber(); + virtual int GetValueType(); - virtual CValue* Calc(VALUE_OPERATOR op, - CValue *val); + cInt GetInt(); - virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, - VALUE_OPERATOR op, - CValue *val); + virtual EXP_Value *Calc(VALUE_OPERATOR op, EXP_Value *val); + virtual EXP_Value *CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, EXP_Value *val); - virtual void SetValue(CValue* newval); + virtual void SetValue(EXP_Value *newval); - void Configure(CValue* menuvalue); - void AddConfigurationData(CValue* menuvalue); - virtual CValue* GetReplica(); + virtual EXP_Value *GetReplica(); #ifdef WITH_PYTHON - virtual PyObject* ConvertValueToPython(); + virtual PyObject *ConvertValueToPython(); #endif -protected: - virtual ~CIntValue(); - private: - cInt m_int; - STR_String* m_pstrRep; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:CIntValue") -#endif + cInt m_int; }; -#endif /* __EXP_INTVALUE_H__ */ +#endif // __EXP_INTVALUE_H__ diff --git a/source/gameengine/Expressions/EXP_ListValue.h b/source/gameengine/Expressions/EXP_ListValue.h index d448f5cbe170..dcfcdefe700c 100644 --- a/source/gameengine/Expressions/EXP_ListValue.h +++ b/source/gameengine/Expressions/EXP_ListValue.h @@ -1,5 +1,5 @@ /* - * ListValue.h: interface for the CListValue class. + * ListValue.h: interface for the EXP_ListValue class. * Copyright (c) 1996-2000 Erwin Coumans * * Permission to use, copy, modify, distribute and sell this software @@ -19,73 +19,172 @@ #ifndef __EXP_LISTVALUE_H__ #define __EXP_LISTVALUE_H__ -#include "EXP_Value.h" +#include "EXP_BaseListValue.h" +#include "EXP_BoolValue.h" -class CListValue : public CPropValue -{ - Py_Header - //PLUGIN_DECLARE_SERIAL (CListValue,CValue) +#include -public: - CListValue(); - virtual ~CListValue(); - - void AddConfigurationData(CValue* menuvalue); - void Configure(CValue* menuvalue); - void Add(CValue* value); - - /** \attention not implemented yet :( */ - virtual CValue* Calc(VALUE_OPERATOR op,CValue *val); - virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, - VALUE_OPERATOR op, - CValue* val); - virtual double GetNumber(); - virtual int GetValueType(); - virtual CValue* GetReplica(); +#include +template +class EXP_ListValue : public EXP_BaseListValue +{ public: - void MergeList(CListValue* otherlist); - bool RemoveValue(CValue* val); - void SetReleaseOnDestruct(bool bReleaseContents); - bool SearchValue(CValue* val); - - CValue* FindValue(const STR_String & name); - CValue* FindValue(const char *name); - - void ReleaseAndRemoveAll(); - virtual void SetModified(bool bModified); - virtual inline bool IsModified(); - void Remove(int i); - void Resize(int num); - void SetValue(int i,CValue* val); - CValue* GetValue(int i) { assertd(i < m_pValueArray.size()); return m_pValueArray[i]; } - int GetCount() { return m_pValueArray.size(); } - virtual const STR_String & GetText(); - - bool CheckEqual(CValue* first,CValue* second); - -#ifdef WITH_PYTHON - virtual PyObject *py_repr(void) { - PyObject *py_proxy= this->GetProxy(); - PyObject *py_list= PySequence_List(py_proxy); - PyObject *py_string= PyObject_Repr(py_list); - Py_DECREF(py_list); - Py_DECREF(py_proxy); - return py_string; - } - - KX_PYMETHOD_O(CListValue,append); - KX_PYMETHOD_NOARGS(CListValue,reverse); - KX_PYMETHOD_O(CListValue,index); - KX_PYMETHOD_O(CListValue,count); - KX_PYMETHOD_VARARGS(CListValue,get); - KX_PYMETHOD_O(CListValue,from_id); -#endif - -private: - - std::vector m_pValueArray; - bool m_bReleaseContents; + class const_iterator + { + public: + VectorTypeConstIterator m_it; + + const_iterator(VectorTypeConstIterator it) + : m_it(it) + { + } + + inline void operator++() + { + ++m_it; + } + + inline ItemType *operator*() const + { + return static_cast(*m_it); + } + }; + + EXP_ListValue() + { + } + + EXP_ListValue(const std::vector& rawList) + { + const unsigned int size = rawList.size(); + m_valueArray.resize(size); + for (unsigned int i = 0; i < size; ++i) { + m_valueArray[i] = rawList[i]; + } + } + + virtual ~EXP_ListValue() + { + } + + virtual EXP_ListValue *GetReplica() + { + EXP_ListValue *replica = new EXP_ListValue(*this); + + replica->ProcessReplica(); + + replica->m_bReleaseContents = true; // For copy, complete array is copied for now... + // Copy all values. + const int numelements = m_valueArray.size(); + replica->m_valueArray.resize(numelements); + for (unsigned int i = 0; i < numelements; i++) { + replica->m_valueArray[i] = m_valueArray[i]->GetReplica(); + } + + return replica; + } + + void Add(ItemType *value) + { + EXP_BaseListValue::Add(value); + } + + void Insert(unsigned int i, ItemType *value) + { + EXP_BaseListValue::Insert(i, value); + } + + ItemType *FindIf(std::function function) + { + for (EXP_Value *val : m_valueArray) { + ItemType *item = static_cast(val); + if (function(item)) { + return item; + } + } + return nullptr; + } + + void MergeList(EXP_ListValue *otherlist) + { + const unsigned int numelements = GetCount(); + const unsigned int numotherelements = otherlist->GetCount(); + + Resize(numelements + numotherelements); + + for (int i = 0; i < numotherelements; i++) { + SetValue(i + numelements, CM_AddRef(otherlist->GetValue(i))); + } + } + bool CheckEqual(ItemType *first, ItemType *second) + { + return EXP_BaseListValue::CheckEqual(first, second); + } + + bool SearchValue(ItemType *val) const + { + return EXP_BaseListValue::SearchValue(val); + } + ItemType *FindValue(const std::string& name) const + { + return static_cast(EXP_BaseListValue::FindValue(name)); + } + + /** \note Allow to remove by base class pointer as an upcast from this class type + * to the item type could failed if the pointer is dangling, in example when it was + * just deleted. + */ + bool RemoveValue(EXP_Value *val) + { + return EXP_BaseListValue::RemoveValue(val); + } + + void SetValue(int i, ItemType *val) + { + EXP_BaseListValue::SetValue(i, val); + } + ItemType *GetValue(int i) + { + return static_cast(EXP_BaseListValue::GetValue(i)); + } + + ItemType *GetFront() + { + return static_cast(m_valueArray.front()); + } + ItemType *GetBack() + { + return static_cast(m_valueArray.back()); + } + + const_iterator begin() + { + return const_iterator(m_valueArray.begin()); + } + const_iterator end() + { + return const_iterator(m_valueArray.end()); + } }; -#endif /* __EXP_LISTVALUE_H__ */ +template +typename EXP_ListValue::const_iterator begin(EXP_ListValue *list) +{ + return list->begin(); +} + +template +typename EXP_ListValue::const_iterator end(EXP_ListValue *list) +{ + return list->end(); +} + +template ().m_it) > +bool operator!=(const Iterator& it1, const Iterator& it2) +{ + return it1.m_it != it2.m_it; +} + +#endif // __EXP_LISTVALUE_H__ + diff --git a/source/gameengine/Expressions/EXP_ListWrapper.h b/source/gameengine/Expressions/EXP_ListWrapper.h index c0f149aa1af3..2f5ea34132dd 100644 --- a/source/gameengine/Expressions/EXP_ListWrapper.h +++ b/source/gameengine/Expressions/EXP_ListWrapper.h @@ -29,79 +29,46 @@ #ifndef __EXP_LISTWRAPPER_H__ #define __EXP_LISTWRAPPER_H__ -#include "EXP_Value.h" - -class CListWrapper : public CValue +#include "EXP_BaseListWrapper.h" + +template +class EXP_ListWrapper : public EXP_BaseListWrapper { - Py_Header private: - /** The client instance passed as first argument of each callback. - * We use a void * instead of a template to avoid to declare this class - * for each use in KX_PythonInitTypes. - */ - void *m_client; - - // The python object which owned this list. - PyObject *m_base; - - /// Returns true if the list is still valid, else each call will raise an error. - bool (*m_checkValid)(void *); - - /// Returns the list size. - int (*m_getSize)(void *); - - /// Returns the list item for the giving index. - PyObject *(*m_getItem)(void *, int); - - /// Returns name item for the giving index, used for python operator list["name"]. - const char *(*m_getItemName)(void *, int); - - /// Sets the nex item to the index place, return false when failed item conversion. - bool (*m_setItem)(void *, int, PyObject *); + static PyObject *GetItem(EXP_PyObjectPlus *self, unsigned int index) + { + return (static_cast(self)->*GetItemFunc)(index); + } + + static std::string GetItemName(EXP_PyObjectPlus *self, unsigned int index) + { + return (static_cast(self)->*GetItemNameFunc)(index); + } + + static unsigned int GetSize(EXP_PyObjectPlus *self) + { + return (static_cast(self)->*GetSizeFunc)(); + } + + static bool SetItem(EXP_PyObjectPlus *self, unsigned int index, PyObject *item) + { + return (static_cast(self)->*SetItemFunc)(index, item); + } public: - CListWrapper(void *client, - PyObject *base, - bool (*checkValid)(void *), - int (*getSize)(void *), - PyObject *(*getItem)(void *, int), - const char *(*getItemName)(void *, int), - bool (*setItem)(void *, int, PyObject *)); - ~CListWrapper(); - - /// \section Python Interface - bool CheckValid(); - int GetSize(); - PyObject *GetItem(int index); - const char *GetItemName(int index); - bool SetItem(int index, PyObject *item); - bool AllowSetItem(); - bool AllowGetItemByName(); - - /// \section CValue Inherited Functions. - virtual const STR_String &GetText(); - virtual void SetName(const char *name); - virtual STR_String &GetName(); - virtual CValue *GetReplica(); - virtual CValue *Calc(VALUE_OPERATOR op, CValue *val); - virtual CValue *CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); - virtual double GetNumber(); - virtual int GetValueType(); - virtual PyObject *py_repr(); - - // Python list operators. - static PySequenceMethods py_as_sequence; - // Python dictionnary operators. - static PyMappingMethods py_as_mapping; - - static Py_ssize_t py_len(PyObject *self); - static PyObject *py_get_item(PyObject *self, Py_ssize_t index); - static int py_set_item(PyObject *self, Py_ssize_t index, PyObject *value); - static PyObject *py_mapping_subscript(PyObject *self, PyObject *key); - static int py_mapping_ass_subscript(PyObject *self, PyObject *key, PyObject *value); - static int py_contains(PyObject *self, PyObject *key); - - KX_PYMETHOD_VARARGS(CListWrapper, Get); + EXP_ListWrapper(EXP_PyObjectPlus *client, Flag flag = FLAG_NONE) + :EXP_BaseListWrapper(client, GetSize, GetItem, + GetItemNameFunc ? GetItemName : nullptr, + SetItemFunc ? SetItem : nullptr, flag) + { + } + virtual ~EXP_ListWrapper() + { + } }; #endif // __EXP_LISTWRAPPER_H__ diff --git a/source/gameengine/Expressions/EXP_Operator1Expr.h b/source/gameengine/Expressions/EXP_Operator1Expr.h index e8b5e07a03dc..cad713dd2708 100644 --- a/source/gameengine/Expressions/EXP_Operator1Expr.h +++ b/source/gameengine/Expressions/EXP_Operator1Expr.h @@ -1,5 +1,5 @@ /* - * Operator1Expr.h: interface for the COperator1Expr class. + * Operator1Expr.h: interface for the EXP_Operator1Expr class. * Copyright (c) 1996-2000 Erwin Coumans * * Permission to use, copy, modify, distribute and sell this software @@ -21,39 +21,19 @@ #include "EXP_Expression.h" -class COperator1Expr : public CExpression +class EXP_Operator1Expr : public EXP_Expression { - //PLUGIN_DECLARE_SERIAL_EXPRESSION (COperator1Expr,CExpression) - - - public: - virtual bool MergeExpression(CExpression* otherexpr); - virtual void BroadcastOperators(VALUE_OPERATOR op); - - virtual unsigned char GetExpressionID() { return COPERATOR1EXPRESSIONID; } - CExpression* CheckLink(std::vector& brokenlinks); - //virtual bool IsInside(float x,float y,float z,bool bBorderInclude = true); - virtual bool NeedsRecalculated(); - void ClearModified() { - if (m_lhs) - m_lhs->ClearModified(); - } - virtual CValue* Calculate(); - COperator1Expr(VALUE_OPERATOR op, CExpression *lhs); - COperator1Expr(); - virtual ~COperator1Expr(); - + EXP_Operator1Expr(); + EXP_Operator1Expr(VALUE_OPERATOR op, EXP_Expression *lhs); + virtual ~EXP_Operator1Expr(); + virtual unsigned char GetExpressionID(); + virtual EXP_Value *Calculate(); private: VALUE_OPERATOR m_op; - CExpression * m_lhs; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:") -#endif + EXP_Expression *m_lhs; }; -#endif /* __EXP_OPERATOR1EXPR_H__ */ +#endif // __EXP_OPERATOR1EXPR_H__ diff --git a/source/gameengine/Expressions/EXP_Operator2Expr.h b/source/gameengine/Expressions/EXP_Operator2Expr.h index d64f8245b6ef..a51ccdf65f1a 100644 --- a/source/gameengine/Expressions/EXP_Operator2Expr.h +++ b/source/gameengine/Expressions/EXP_Operator2Expr.h @@ -1,5 +1,5 @@ /* - * Operator2Expr.h: interface for the COperator2Expr class. + * Operator2Expr.h: interface for the EXP_Operator2Expr class. * Copyright (c) 1996-2000 Erwin Coumans * * Permission to use, copy, modify, distribute and sell this software @@ -19,47 +19,26 @@ #ifndef __EXP_OPERATOR2EXPR_H__ #define __EXP_OPERATOR2EXPR_H__ - #include "EXP_Expression.h" -#include "EXP_Value.h" // Added by ClassView +#include "EXP_Value.h" -class COperator2Expr : public CExpression +class EXP_Operator2Expr : public EXP_Expression { - //PLUGIN_DECLARE_SERIAL_EXPRESSION (COperator2Expr,CExpression) - public: - virtual bool MergeExpression(CExpression* otherexpr); - virtual unsigned char GetExpressionID() { return COPERATOR2EXPRESSIONID; } - virtual void BroadcastOperators(VALUE_OPERATOR op); - CExpression* CheckLink(std::vector& brokenlinks); - //virtual bool IsInside(float x,float y,float z,bool bBorderInclude=true); - //virtual bool IsLeftInside(float x,float y,float z,bool bBorderInclude); - //virtual bool IsRightInside(float x,float y,float z,bool bBorderInclude); - bool NeedsRecalculated(); - void ClearModified() { - if (m_lhs) - m_lhs->ClearModified(); - if (m_rhs) - m_rhs->ClearModified(); - } - virtual CValue* Calculate(); - COperator2Expr(VALUE_OPERATOR op, CExpression *lhs, CExpression *rhs); - COperator2Expr(); - virtual ~COperator2Expr(); + EXP_Operator2Expr(); + EXP_Operator2Expr(VALUE_OPERATOR op, EXP_Expression *lhs, EXP_Expression *rhs); + virtual ~EXP_Operator2Expr(); + virtual unsigned char GetExpressionID(); + virtual EXP_Value *Calculate(); protected: - CExpression * m_rhs; - CExpression * m_lhs; - CValue* m_cached_calculate; // cached result + EXP_Expression *m_rhs; + EXP_Expression *m_lhs; private: VALUE_OPERATOR m_op; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:COperator2Expr") -#endif }; -#endif /* __EXP_OPERATOR2EXPR_H__ */ +#endif // __EXP_OPERATOR2EXPR_H__ + diff --git a/source/gameengine/Expressions/EXP_PyObjectPlus.h b/source/gameengine/Expressions/EXP_PyObjectPlus.h index 308fae6e6afe..69c2d7eb4ae3 100644 --- a/source/gameengine/Expressions/EXP_PyObjectPlus.h +++ b/source/gameengine/Expressions/EXP_PyObjectPlus.h @@ -32,517 +32,492 @@ #ifndef __EXP_PYOBJECTPLUS_H__ #define __EXP_PYOBJECTPLUS_H__ -/* for now keep weakrefs optional */ +// For now keep weakrefs optional. #define USE_WEAKREFS +#include "EXP_Python.h" -#ifndef __cplusplus // c++ only -#error Must be compiled with C++ -#endif +#include "BLI_utildefines.h" -#include "EXP_Python.h" -#include "STR_String.h" -#include "MT_Vector3.h" -#include "SG_QList.h" -#include +#include +#include +#include // For offsetof. +#include "mathfu.h" #ifdef WITH_PYTHON #ifdef USE_MATHUTILS extern "C" { -#include "../../blender/python/mathutils/mathutils.h" /* so we can have mathutils callbacks */ -#include "../../blender/python/generic/py_capi_utils.h" /* for PyC_LineSpit only */ +# include "../../blender/python/mathutils/mathutils.h" // So we can have mathutils callbacks. } #endif #define MAX_PROP_NAME 64 -/* Use with ShowDeprecationWarning macro */ +// Use with EXP_ShowDeprecationWarning macro. typedef struct { bool warn_done; void *link; -} WarnLink; - -#define ShowDeprecationWarning(old_way, new_way) \ -{ \ - static WarnLink wlink = {false, NULL}; \ - if ((PyObjectPlus::m_ignore_deprecation_warnings || wlink.warn_done)==0) \ - { \ - PyObjectPlus::ShowDeprecationWarning_func(old_way, new_way); \ - \ - WarnLink *wlink_last= PyObjectPlus::GetDeprecationWarningLinkLast(); \ - wlink.warn_done = true; \ - wlink.link = NULL; \ - \ - if (wlink_last) { \ - wlink_last->link= (void *)&(wlink); \ - PyObjectPlus::SetDeprecationWarningLinkLast(&(wlink)); \ - } \ - else { \ - PyObjectPlus::SetDeprecationWarningFirst(&(wlink)); \ - PyObjectPlus::SetDeprecationWarningLinkLast(&(wlink)); \ - } \ - } \ -} \ - - - -typedef struct PyObjectPlus_Proxy { - PyObject_HEAD /* required python macro */ - class PyObjectPlus *ref; // pointer to GE object, it holds a reference to this proxy - void *ptr; // optional pointer to generic structure, the structure holds no reference to this proxy - bool py_owns; // true if the object pointed by ref should be deleted when the proxy is deleted - bool py_ref; // true if proxy is connected to a GE object (ref is used) +} EXP_WarnLink; + +#define EXP_ShowDeprecationWarning(old_way, new_way) \ + { \ + static EXP_WarnLink wlink = {false, nullptr}; \ + if ((EXP_PyObjectPlus::GetDerprecationWarnings() || wlink.warn_done) == 0) \ + { \ + EXP_PyObjectPlus::ShowDeprecationWarning_func(old_way, new_way); \ +\ + EXP_WarnLink *wlink_last = EXP_PyObjectPlus::GetDeprecationWarningLinkLast(); \ + wlink.warn_done = true; \ + wlink.link = nullptr; \ +\ + if (wlink_last) { \ + wlink_last->link = (void *)&(wlink); \ + EXP_PyObjectPlus::SetDeprecationWarningLinkLast(&(wlink)); \ + } \ + else { \ + EXP_PyObjectPlus::SetDeprecationWarningFirst(&(wlink)); \ + EXP_PyObjectPlus::SetDeprecationWarningLinkLast(&(wlink)); \ + } \ + } \ + } + +typedef struct EXP_PyObjectPlus_Proxy { + /// Required python macro. + PyObject_HEAD + /// Pointer to GE object, it holds a reference to this proxy. + class EXP_PyObjectPlus *ref; + /// Optional pointer to generic structure, the structure holds no reference to this proxy. + void *ptr; + /// True if the object pointed by ref should be deleted when the proxy is deleted. + bool py_owns; + /// True if proxy is connected to a GE object (ref is used). + bool py_ref; #ifdef USE_WEAKREFS - PyObject *in_weakreflist; // weak reference enabler + /// Weak reference enabler. + PyObject *in_weakreflist; #endif -} PyObjectPlus_Proxy; +} EXP_PyObjectPlus_Proxy; -#define BGE_PROXY_ERROR_MSG "Blender Game Engine data has been freed, cannot use this python variable" -#define BGE_PROXY_REF(_self) (((PyObjectPlus_Proxy *)_self)->ref) -#define BGE_PROXY_PTR(_self) (((PyObjectPlus_Proxy *)_self)->ptr) -#define BGE_PROXY_PYOWNS(_self) (((PyObjectPlus_Proxy *)_self)->py_owns) -#define BGE_PROXY_PYREF(_self) (((PyObjectPlus_Proxy *)_self)->py_ref) +#define EXP_PROXY_ERROR_MSG "Blender Game Engine data has been freed, cannot use this python variable" +#define EXP_PROXY_REF(_self) (((EXP_PyObjectPlus_Proxy *)_self)->ref) +#define EXP_PROXY_PTR(_self) (((EXP_PyObjectPlus_Proxy *)_self)->ptr) +#define EXP_PROXY_PYOWNS(_self) (((EXP_PyObjectPlus_Proxy *)_self)->py_owns) +#define EXP_PROXY_PYREF(_self) (((EXP_PyObjectPlus_Proxy *)_self)->py_ref) #ifdef USE_WEAKREFS -# define BGE_PROXY_WKREF(_self) (((PyObjectPlus_Proxy *)_self)->in_weakreflist) +# define EXP_PROXY_WKREF(_self) (((EXP_PyObjectPlus_Proxy *)_self)->in_weakreflist) #endif -/* Note, sometimes we don't care what BGE type this is as long as its a proxy */ -#define BGE_PROXY_CHECK_TYPE(_type) ((_type)->tp_dealloc == PyObjectPlus::py_base_dealloc) - -/* Opposite of BGE_PROXY_REF */ -#define BGE_PROXY_FROM_REF(_self) (((PyObjectPlus *)_self)->GetProxy()) -/* Same as 'BGE_PROXY_REF' but doesn't incref. */ -#define BGE_PROXY_FROM_REF_BORROW(_self) _bge_proxy_from_ref_borrow((void *)_self) - - -// This must be the first line of each -// PyC++ class -// AttributesPtr correspond to attributes of proxy generic pointer -// each PyC++ class must be registered in KX_PythonInitTypes.cpp -#define __Py_Header \ -public: \ - static PyTypeObject Type; \ - static PyMethodDef Methods[]; \ - static PyAttributeDef Attributes[]; \ - virtual PyTypeObject *GetType(void) { \ - return &Type; \ - } \ - virtual PyObject *GetProxy() { \ - return GetProxyPlus_Ext(this, &Type, NULL); \ - } \ - virtual PyObject *NewProxy(bool py_owns) { \ - return NewProxyPlus_Ext(this, &Type, NULL, py_owns); \ - } \ - -// leave above line empty (macro)! -// use this macro for class that use generic pointer in proxy -// GetProxy() and NewProxy() must be defined to set the correct pointer in the proxy -#define __Py_HeaderPtr \ -public: \ - static PyTypeObject Type; \ - static PyMethodDef Methods[]; \ - static PyAttributeDef Attributes[]; \ - static PyAttributeDef AttributesPtr[]; \ - virtual PyTypeObject *GetType(void) { \ - return &Type; \ - } \ - virtual PyObject *GetProxy(); \ - virtual PyObject *NewProxy(bool py_owns); \ - -// leave above line empty (macro)! -#ifdef WITH_CXX_GUARDEDALLOC -#define Py_Header __Py_Header \ - void *operator new(size_t num_bytes) { \ - return MEM_mallocN(num_bytes, Type.tp_name); \ - } \ - void operator delete(void *mem) { \ - MEM_freeN(mem); \ - } \ - -#else -# define Py_Header __Py_Header -#endif +/// Note, sometimes we don't care what BGE type this is as long as its a proxy. +#define EXP_PROXY_CHECK_TYPE(_type) ((_type)->tp_dealloc == EXP_PyObjectPlus::py_base_dealloc) -#ifdef WITH_CXX_GUARDEDALLOC -#define Py_HeaderPtr __Py_HeaderPtr \ - void *operator new(size_t num_bytes) { \ - return MEM_mallocN(num_bytes, Type.tp_name); \ - } \ - void operator delete(void *mem) { \ - MEM_freeN(mem); \ - } \ - -#else -# define Py_HeaderPtr __Py_HeaderPtr -#endif +/// Opposite of EXP_PROXY_REF. +#define EXP_PROXY_FROM_REF(_self) (((EXP_PyObjectPlus *)_self)->GetProxy()) +/// Same as 'EXP_PROXY_REF' but doesn't incref. +#define EXP_PROXY_FROM_REF_BORROW(_self) _bge_proxy_from_ref_borrow(_self) -/* - * nonzero values are an error for setattr + +/** This must be the first line of each + * PyC++ class + * AttributesPtr correspond to attributes of proxy generic pointer + * each PyC++ class must be registered in KX_PythonInitTypes.cpp + */ +#define Py_Header \ +public: \ + static PyTypeObject Type; \ + static PyMethodDef Methods[]; \ + static PyAttributeDef Attributes[]; \ + virtual PyTypeObject *GetType(void) \ + { \ + return &Type; \ + } \ + virtual PyObject *GetProxy() \ + { \ + return GetProxyPlus_Ext(this, &Type, nullptr); \ + } \ + virtual PyObject *NewProxy(bool py_owns) \ + { \ + return NewProxyPlus_Ext(this, &Type, nullptr, py_owns); \ + } + +/** Use this macro for class that use generic pointer in proxy + * GetProxy() and NewProxy() must be defined to set the correct pointer in the proxy. + */ +#define Py_HeaderPtr \ +public: \ + static PyTypeObject Type; \ + static PyMethodDef Methods[]; \ + static PyAttributeDef Attributes[]; \ + static PyAttributeDef AttributesPtr[]; \ + virtual PyTypeObject *GetType(void) \ + { \ + return &Type; \ + } \ + virtual PyObject *GetProxy(); \ + virtual PyObject *NewProxy(bool py_owns); + +/** Nonzero values are an error for setattr * however because of the nested lookups we need to know if the errors - * was because the attribute didnt exits of if there was some problem setting the value + * was because the attribute didnt exits of if there was some problem setting the value. */ +#define PY_SET_ATTR_FAIL 1 +#define PY_SET_ATTR_SUCCESS 0 -#define PY_SET_ATTR_COERCE_FAIL 2 -#define PY_SET_ATTR_FAIL 1 -#define PY_SET_ATTR_MISSING -1 -#define PY_SET_ATTR_SUCCESS 0 - -/** - * These macros are helpful when embedding Python routines. The second +/** These macros are helpful when embedding Python routines. The second * macro is one that also requires a documentation string */ -#define KX_PYMETHOD(class_name, method_name) \ - PyObject *Py##method_name(PyObject *args, PyObject *kwds); \ - static PyObject * \ - sPy##method_name(PyObject *self, PyObject *args, PyObject *kwds) { \ - if (BGE_PROXY_REF(self)==NULL) { \ - PyErr_SetString(PyExc_RuntimeError, \ - #class_name "." #method_name "() - " \ - BGE_PROXY_ERROR_MSG); \ - return NULL; \ - } \ - return((class_name*)BGE_PROXY_REF(self))->Py##method_name(args, kwds); \ - } \ - -#define KX_PYMETHOD_VARARGS(class_name, method_name) \ - PyObject *Py##method_name(PyObject *args); \ - static PyObject* \ - sPy##method_name(PyObject *self, PyObject *args) { \ - if (BGE_PROXY_REF(self)==NULL) { \ - PyErr_SetString(PyExc_RuntimeError, \ - #class_name "." #method_name "() - " \ - BGE_PROXY_ERROR_MSG); return NULL; \ - } \ - return((class_name*)BGE_PROXY_REF(self))->Py##method_name(args); \ - } \ - -#define KX_PYMETHOD_NOARGS(class_name, method_name) \ - PyObject *Py##method_name(); \ - static PyObject* \ - sPy##method_name(PyObject *self) { \ - if (BGE_PROXY_REF(self)==NULL) { \ - PyErr_SetString(PyExc_RuntimeError, \ - #class_name "." #method_name "() - " \ - BGE_PROXY_ERROR_MSG); return NULL; \ - } \ - return((class_name*)BGE_PROXY_REF(self))->Py##method_name(); \ - } \ - -#define KX_PYMETHOD_O(class_name, method_name) \ - PyObject *Py##method_name(PyObject *value); \ - static PyObject* \ - sPy##method_name(PyObject *self, PyObject *value) { \ - if (BGE_PROXY_REF(self)==NULL) { \ - PyErr_SetString(PyExc_RuntimeError, \ - #class_name "." #method_name "(value) - " \ - BGE_PROXY_ERROR_MSG); return NULL; \ - } \ - return((class_name*)BGE_PROXY_REF(self))->Py##method_name(value); \ - } \ - -#define KX_PYMETHOD_DOC(class_name, method_name) \ - PyObject *Py##method_name(PyObject *args, PyObject *kwds); \ - static PyObject* \ - sPy##method_name(PyObject *self, PyObject *args, PyObject *kwds) { \ - if (BGE_PROXY_REF(self)==NULL) { \ - PyErr_SetString(PyExc_RuntimeError, \ - #class_name "." #method_name "(...) - " \ - BGE_PROXY_ERROR_MSG); return NULL; \ - } \ - return((class_name*)BGE_PROXY_REF(self))->Py##method_name(args, kwds); \ - } \ - static const char method_name##_doc[]; \ - -#define KX_PYMETHOD_DOC_VARARGS(class_name, method_name) \ - PyObject *Py##method_name(PyObject *args); \ - static PyObject* \ - sPy##method_name(PyObject *self, PyObject *args) { \ - if (BGE_PROXY_REF(self)==NULL) { \ - PyErr_SetString(PyExc_RuntimeError, \ - #class_name "." #method_name "(...) - " \ - BGE_PROXY_ERROR_MSG); \ - return NULL; \ - } \ - return((class_name*)BGE_PROXY_REF(self))->Py##method_name(args); \ - } \ - static const char method_name##_doc[]; \ - -#define KX_PYMETHOD_DOC_O(class_name, method_name) \ - PyObject *Py##method_name(PyObject *value); \ - static PyObject * \ - sPy##method_name(PyObject *self, PyObject *value) { \ - if (BGE_PROXY_REF(self)==NULL) { \ - PyErr_SetString(PyExc_RuntimeError, \ - #class_name "." #method_name "(value) - " \ - BGE_PROXY_ERROR_MSG); \ - return NULL; \ - } \ - return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(value); \ - } \ - static const char method_name##_doc[]; \ - -#define KX_PYMETHOD_DOC_NOARGS(class_name, method_name) \ - PyObject *Py##method_name(); \ - static PyObject * \ - sPy##method_name(PyObject *self) { \ - if (BGE_PROXY_REF(self)==NULL) { \ - PyErr_SetString(PyExc_RuntimeError, \ - #class_name "." #method_name "() - " \ - BGE_PROXY_ERROR_MSG); \ - return NULL; \ - } \ - return ((class_name*)BGE_PROXY_REF(self))->Py##method_name(); \ - } \ - static const char method_name##_doc[]; \ - - -/* The line above should remain empty */ -/** - * Method table macro (with doc) - */ -#define KX_PYMETHODTABLE(class_name, method_name) \ +#define EXP_PYMETHOD(class_name, method_name) \ + PyObject * Py##method_name(PyObject * args, PyObject * kwds); \ + static PyObject * \ + sPy##method_name(PyObject * self, PyObject * args, PyObject * kwds) \ + { \ + if (EXP_PROXY_REF(self) == nullptr) { \ + PyErr_SetString(PyExc_RuntimeError, \ + #class_name "." #method_name "() - " \ + EXP_PROXY_ERROR_MSG); \ + return nullptr; \ + } \ + return ((class_name *)EXP_PROXY_REF(self))->Py##method_name(args, kwds); \ + } + +#define EXP_PYMETHOD_VARARGS(class_name, method_name) \ + PyObject * Py##method_name(PyObject * args); \ + static PyObject * \ + sPy##method_name(PyObject * self, PyObject * args) \ + { \ + if (EXP_PROXY_REF(self) == nullptr) { \ + PyErr_SetString(PyExc_RuntimeError, \ + #class_name "." #method_name "() - " \ + EXP_PROXY_ERROR_MSG); return nullptr; \ + } \ + return ((class_name *)EXP_PROXY_REF(self))->Py##method_name(args); \ + } + +#define EXP_PYMETHOD_NOARGS(class_name, method_name) \ + PyObject * Py##method_name(); \ + static PyObject * \ + sPy##method_name(PyObject * self) \ + { \ + if (EXP_PROXY_REF(self) == nullptr) { \ + PyErr_SetString(PyExc_RuntimeError, \ + #class_name "." #method_name "() - " \ + EXP_PROXY_ERROR_MSG); return nullptr; \ + } \ + return ((class_name *)EXP_PROXY_REF(self))->Py##method_name(); \ + } + +#define EXP_PYMETHOD_O(class_name, method_name) \ + PyObject * Py##method_name(PyObject * value); \ + static PyObject * \ + sPy##method_name(PyObject * self, PyObject * value) \ + { \ + if (EXP_PROXY_REF(self) == nullptr) { \ + PyErr_SetString(PyExc_RuntimeError, \ + #class_name "." #method_name "(value) - " \ + EXP_PROXY_ERROR_MSG); return nullptr; \ + } \ + return ((class_name *)EXP_PROXY_REF(self))->Py##method_name(value); \ + } + +#define EXP_PYMETHOD_DOC(class_name, method_name) \ + PyObject * Py##method_name(PyObject * args, PyObject * kwds); \ + static PyObject * \ + sPy##method_name(PyObject * self, PyObject * args, PyObject * kwds) \ + { \ + if (EXP_PROXY_REF(self) == nullptr) { \ + PyErr_SetString(PyExc_RuntimeError, \ + #class_name "." #method_name "(...) - " \ + EXP_PROXY_ERROR_MSG); return nullptr; \ + } \ + return ((class_name *)EXP_PROXY_REF(self))->Py##method_name(args, kwds); \ + } \ + static const char method_name##_doc[]; + +#define EXP_PYMETHOD_DOC_VARARGS(class_name, method_name) \ + PyObject * Py##method_name(PyObject * args); \ + static PyObject * \ + sPy##method_name(PyObject * self, PyObject * args) \ + { \ + if (EXP_PROXY_REF(self) == nullptr) { \ + PyErr_SetString(PyExc_RuntimeError, \ + #class_name "." #method_name "(...) - " \ + EXP_PROXY_ERROR_MSG); \ + return nullptr; \ + } \ + return ((class_name *)EXP_PROXY_REF(self))->Py##method_name(args); \ + } \ + static const char method_name##_doc[]; + +#define EXP_PYMETHOD_DOC_O(class_name, method_name) \ + PyObject * Py##method_name(PyObject * value); \ + static PyObject * \ + sPy##method_name(PyObject * self, PyObject * value) \ + { \ + if (EXP_PROXY_REF(self) == nullptr) { \ + PyErr_SetString(PyExc_RuntimeError, \ + #class_name "." #method_name "(value) - " \ + EXP_PROXY_ERROR_MSG); \ + return nullptr; \ + } \ + return ((class_name *)EXP_PROXY_REF(self))->Py##method_name(value); \ + } \ + static const char method_name##_doc[]; + +#define EXP_PYMETHOD_DOC_NOARGS(class_name, method_name) \ + PyObject * Py##method_name(); \ + static PyObject * \ + sPy##method_name(PyObject * self) \ + { \ + if (EXP_PROXY_REF(self) == nullptr) { \ + PyErr_SetString(PyExc_RuntimeError, \ + #class_name "." #method_name "() - " \ + EXP_PROXY_ERROR_MSG); \ + return nullptr; \ + } \ + return ((class_name *)EXP_PROXY_REF(self))->Py##method_name(); \ + } \ + static const char method_name##_doc[]; + +/// Method table macro (with doc). +#define EXP_PYMETHODTABLE(class_name, method_name) \ {#method_name, (PyCFunction) class_name::sPy##method_name, METH_VARARGS, (const char *)class_name::method_name##_doc} -#define KX_PYMETHODTABLE_O(class_name, method_name) \ +#define EXP_PYMETHODTABLE_O(class_name, method_name) \ {#method_name, (PyCFunction) class_name::sPy##method_name, METH_O, (const char *)class_name::method_name##_doc} -#define KX_PYMETHODTABLE_NOARGS(class_name, method_name) \ +#define EXP_PYMETHODTABLE_NOARGS(class_name, method_name) \ {#method_name, (PyCFunction) class_name::sPy##method_name, METH_NOARGS, (const char *)class_name::method_name##_doc} -#define KX_PYMETHODTABLE_KEYWORDS(class_name, method_name) \ - {#method_name, (PyCFunction) class_name::sPy##method_name, METH_VARARGS|METH_KEYWORDS, (const char *)class_name::method_name##_doc} - -/** - * Function implementation macro - */ -#define KX_PYMETHODDEF_DOC(class_name, method_name, doc_string) \ -const char class_name::method_name##_doc[] = doc_string; \ -PyObject *class_name::Py##method_name(PyObject *args, PyObject *kwds) - -#define KX_PYMETHODDEF_DOC_VARARGS(class_name, method_name, doc_string) \ -const char class_name::method_name##_doc[] = doc_string; \ -PyObject *class_name::Py##method_name(PyObject *args) - -#define KX_PYMETHODDEF_DOC_O(class_name, method_name, doc_string) \ -const char class_name::method_name##_doc[] = doc_string; \ -PyObject *class_name::Py##method_name(PyObject *value) - -#define KX_PYMETHODDEF_DOC_NOARGS(class_name, method_name, doc_string) \ -const char class_name::method_name##_doc[] = doc_string; \ -PyObject *class_name::Py##method_name() - -/** - * Attribute management - */ -enum KX_PYATTRIBUTE_TYPE { - KX_PYATTRIBUTE_TYPE_BOOL, - KX_PYATTRIBUTE_TYPE_ENUM, - KX_PYATTRIBUTE_TYPE_SHORT, - KX_PYATTRIBUTE_TYPE_INT, - KX_PYATTRIBUTE_TYPE_FLOAT, - KX_PYATTRIBUTE_TYPE_STRING, - KX_PYATTRIBUTE_TYPE_DUMMY, - KX_PYATTRIBUTE_TYPE_FUNCTION, - KX_PYATTRIBUTE_TYPE_VECTOR, - KX_PYATTRIBUTE_TYPE_FLAG, - KX_PYATTRIBUTE_TYPE_CHAR +#define EXP_PYMETHODTABLE_KEYWORDS(class_name, method_name) \ + {#method_name, (PyCFunction) class_name::sPy##method_name, METH_VARARGS | METH_KEYWORDS, (const char *)class_name::method_name##_doc} + +/// Function implementation macro. +#define EXP_PYMETHODDEF_DOC(class_name, method_name, doc_string) \ + const char class_name::method_name##_doc[] = doc_string; \ + PyObject *class_name::Py##method_name(PyObject * args, PyObject * kwds) + +#define EXP_PYMETHODDEF_DOC_VARARGS(class_name, method_name, doc_string) \ + const char class_name::method_name##_doc[] = doc_string; \ + PyObject *class_name::Py##method_name(PyObject * args) + +#define EXP_PYMETHODDEF_DOC_O(class_name, method_name, doc_string) \ + const char class_name::method_name##_doc[] = doc_string; \ + PyObject *class_name::Py##method_name(PyObject * value) + +#define EXP_PYMETHODDEF_DOC_NOARGS(class_name, method_name, doc_string) \ + const char class_name::method_name##_doc[] = doc_string; \ + PyObject *class_name::Py##method_name() + +/// Attribute management. +enum EXP_PYATTRIBUTE_TYPE { + EXP_PYATTRIBUTE_TYPE_BOOL, + EXP_PYATTRIBUTE_TYPE_ENUM, + EXP_PYATTRIBUTE_TYPE_SHORT, + EXP_PYATTRIBUTE_TYPE_INT, + EXP_PYATTRIBUTE_TYPE_FLOAT, + EXP_PYATTRIBUTE_TYPE_STRING, + EXP_PYATTRIBUTE_TYPE_FUNCTION, + EXP_PYATTRIBUTE_TYPE_VECTOR, + EXP_PYATTRIBUTE_TYPE_FLAG, + EXP_PYATTRIBUTE_TYPE_CHAR }; -enum KX_PYATTRIBUTE_ACCESS { - KX_PYATTRIBUTE_RW, - KX_PYATTRIBUTE_RO +enum EXP_PYATTRIBUTE_ACCESS { + EXP_PYATTRIBUTE_RW, + EXP_PYATTRIBUTE_RO }; -struct KX_PYATTRIBUTE_DEF; -typedef int (*KX_PYATTRIBUTE_CHECK_FUNCTION)(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); -typedef int (*KX_PYATTRIBUTE_SET_FUNCTION)(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); -typedef PyObject *(*KX_PYATTRIBUTE_GET_FUNCTION)(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - -typedef struct KX_PYATTRIBUTE_DEF { - const char *m_name; // name of the python attribute - KX_PYATTRIBUTE_TYPE m_type; // type of value - KX_PYATTRIBUTE_ACCESS m_access; // read/write access or read-only - int m_imin; // minimum value in case of integer attributes - // (for string: minimum string length, for flag: mask value, for float: matrix row size) - int m_imax; // maximum value in case of integer attributes - // (for string: maximum string length, for flag: 1 if flag is negative, float: vector/matrix col size) - float m_fmin; // minimum value in case of float attributes - float m_fmax; // maximum value in case of float attributes - bool m_clamp; // enforce min/max value by clamping - bool m_usePtr; // the attribute uses the proxy generic pointer, set at runtime - size_t m_offset; // position of field in structure - size_t m_size; // size of field for runtime verification (enum only) - size_t m_length; // length of array, 1=simple attribute - KX_PYATTRIBUTE_CHECK_FUNCTION m_checkFunction; // static function to check the assignment, returns 0 if no error - KX_PYATTRIBUTE_SET_FUNCTION m_setFunction; // static function to check the assignment, returns 0 if no error - KX_PYATTRIBUTE_GET_FUNCTION m_getFunction; // static function to check the assignment, returns 0 if no error - - // The following pointers are just used to have compile time check for attribute type. - // It would have been good to use a union but that would require C99 compatibility - // to initialize specific union fields through designated initializers. - struct { - bool *m_boolPtr; - short int *m_shortPtr; - int *m_intPtr; - float *m_floatPtr; - STR_String *m_stringPtr; - MT_Vector3 *m_vectorPtr; - char *m_charPtr; - } m_typeCheck; +struct EXP_PYATTRIBUTE_DEF; +typedef int (*EXP_PYATTRIBUTE_CHECK_FUNCTION)(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); +typedef int (*EXP_PYATTRIBUTE_SET_FUNCTION)(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); +typedef PyObject *(*EXP_PYATTRIBUTE_GET_FUNCTION)(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + +typedef struct EXP_PYATTRIBUTE_DEF { + /// Name of the python attribute. + const std::string m_name; + /// Type of value. + EXP_PYATTRIBUTE_TYPE m_type; + /// Read/write access or read-only. + EXP_PYATTRIBUTE_ACCESS m_access; + /** Minimum value in case of integer attributes + * (for string: minimum string length, for flag: mask value, for float: matrix row size). + */ + int m_imin; + /** Maximum value in case of integer attributes + * (for string: maximum string length, for flag: 1 if flag is negative, float: vector/matrix col size). + */ + int m_imax; + /// Minimum value in case of float attributes. + float m_fmin; + /// Maximum value in case of float attributes. + float m_fmax; + /// Enforce min/max value by clamping. + bool m_clamp; + /// The attribute uses the proxy generic pointer, set at runtime. + bool m_usePtr; + /// Position of field in structure. + size_t m_offset; + /// Size of field for runtime verification (enum only). + size_t m_size; + /// Length of array, 1=simple attribute. + size_t m_length; + /// Static function to check the assignment, returns 0 if no error. + EXP_PYATTRIBUTE_CHECK_FUNCTION m_checkFunction; + /// Static function to check the assignment, returns 0 if no error. + EXP_PYATTRIBUTE_SET_FUNCTION m_setFunction; + /// Static function to check the assignment, returns 0 if no error. + EXP_PYATTRIBUTE_GET_FUNCTION m_getFunction; } PyAttributeDef; -#define KX_PYATTRIBUTE_BOOL_RW(name, object, field) \ - { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_BOOL_RW_CHECK(name, object, field, function) \ - { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, &object::function, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_BOOL_RO(name, object, field) \ - { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RO, 0, 1, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL, NULL, NULL} } - -/* attribute points to a single bit of an integer field, attribute=true if bit is set */ -#define KX_PYATTRIBUTE_FLAG_RW(name, object, field, bit) \ - { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 0, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLAG_RW_CHECK(name, object, field, bit, function) \ - { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 0, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLAG_RO(name, object, field, bit) \ - { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RO, bit, 0, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } - -/* attribute points to a single bit of an integer field, attribute=true if bit is set*/ -#define KX_PYATTRIBUTE_FLAG_NEGATIVE_RW(name, object, field, bit) \ - { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 1, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLAG_NEGATIVE_RW_CHECK(name, object, field, bit, function) \ - { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RW, bit, 1, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLAG_NEGATIVE_RO(name, object, field, bit) \ - { name, KX_PYATTRIBUTE_TYPE_FLAG, KX_PYATTRIBUTE_RO, bit, 1, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } - -// enum field cannot be mapped to pointer (because we would need a pointer for each enum) -// use field size to verify mapping at runtime only, assuming enum size is equal to int size. -#define KX_PYATTRIBUTE_ENUM_RW(name, min, max, clamp, object, field) \ - { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_ENUM_RW_CHECK(name, min, max, clamp, object, field, function) \ - { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_ENUM_RO(name, object, field) \ - { name, KX_PYATTRIBUTE_TYPE_ENUM, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } - -#define KX_PYATTRIBUTE_SHORT_RW(name, min, max, clamp, object, field) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_SHORT_RW_CHECK(name, min, max, clamp, object, field, function) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_SHORT_RO(name, object, field) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_SHORT_ARRAY_RW(name, min, max, clamp, object, field, length) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_SHORT_ARRAY_RW_CHECK(name, min, max, clamp, object, field, length, function) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, &object::function, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_SHORT_ARRAY_RO(name, object, field, length) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, ((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } -// SHORT_LIST -#define KX_PYATTRIBUTE_SHORT_LIST_RW(name, min, max, clamp, object, field, length) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_SHORT_LIST_RW_CHECK(name, min, max, clamp, object, field, length, function) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, &object::function, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_SHORT_LIST_RO(name, object, field, length) \ - { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL, NULL, NULL} } - -#define KX_PYATTRIBUTE_INT_RW(name, min, max, clamp, object, field) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_INT_RW_CHECK(name, min, max, clamp, object, field, function) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_INT_RO(name, object, field) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_INT_ARRAY_RW(name, min, max, clamp, object, field, length) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_INT_ARRAY_RW_CHECK(name, min, max, clamp, object, field, length, function) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, &object::function, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_INT_ARRAY_RO(name, object, field, length) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, NULL, ((object *)0)->field, NULL, NULL, NULL, NULL} } -// INT_LIST -#define KX_PYATTRIBUTE_INT_LIST_RW(name, min, max, clamp, object, field, length) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_INT_LIST_RW_CHECK(name, min, max, clamp, object, field, length, function) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, &object::function, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_INT_LIST_RO(name, object, field, length) \ - { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL, NULL, NULL} } - -// always clamp for float -#define KX_PYATTRIBUTE_FLOAT_RW(name, min, max, object, field) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLOAT_RW_CHECK(name, min, max, object, field, function) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLOAT_RO(name, object, field) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL, NULL, NULL} } -// field must be float[n], returns a sequence -#define KX_PYATTRIBUTE_FLOAT_ARRAY_RW(name, min, max, object, field, length) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLOAT_ARRAY_RW_CHECK(name, min, max, object, field, length, function) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, length, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLOAT_ARRAY_RO(name, object, field, length) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, length, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } -// field must be float[n], returns a vector -#define KX_PYATTRIBUTE_FLOAT_VECTOR_RW(name, min, max, object, field, length) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, length, min, max, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLOAT_VECTOR_RW_CHECK(name, min, max, object, field, length, function) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, length, min, max, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLOAT_VECTOR_RO(name, object, field, length) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, length, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field, NULL, NULL, NULL} } -// field must be float[n][n], returns a matrix -#define KX_PYATTRIBUTE_FLOAT_MATRIX_RW(name, min, max, object, field, length) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, length, length, min, max, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field[0], NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLOAT_MATRIX_RW_CHECK(name, min, max, object, field, length, function) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, length, length, min, max, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field[0], NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_FLOAT_MATRIX_RO(name, object, field, length) \ - { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, length, length, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, ((object *)0)->field[0], NULL, NULL, NULL} } - -// only for STR_String member -#define KX_PYATTRIBUTE_STRING_RW(name, min, max, clamp, object, field) \ - { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } -#define KX_PYATTRIBUTE_STRING_RW_CHECK(name, min, max, clamp, object, field, function) \ - { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } -#define KX_PYATTRIBUTE_STRING_RO(name, object, field) \ - { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field, NULL, NULL} } - -// only for char [] array -#define KX_PYATTRIBUTE_CHAR_RW(name, object, field) \ - { name, KX_PYATTRIBUTE_TYPE_CHAR, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, ((object *)0)->field} } -#define KX_PYATTRIBUTE_CHAR_RW_CHECK(name, object, field, function) \ - { name, KX_PYATTRIBUTE_TYPE_CHAR, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, ((object *)0)->field} } -#define KX_PYATTRIBUTE_CHAR_RO(name, object, field) \ - { name, KX_PYATTRIBUTE_TYPE_CHAR, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, NULL, ((object *)0)->field} } - -// for MT_Vector3 member -#define KX_PYATTRIBUTE_VECTOR_RW(name, min, max, object, field) \ - { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, 1, NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } -#define KX_PYATTRIBUTE_VECTOR_RW_CHECK(name, min, max, clamp, object, field, function) \ - { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, 1, &object::function, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } -#define KX_PYATTRIBUTE_VECTOR_RO(name, object, field) \ - { name, KX_PYATTRIBUTE_TYPE_VECTOR, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, 1 , NULL, NULL, NULL, {NULL, NULL, NULL, NULL, NULL, &((object *)0)->field, NULL} } - -#define KX_PYATTRIBUTE_RW_FUNCTION(name, object, getfunction, setfunction) \ - { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, false, false, 0, 0, 1, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_RO_FUNCTION(name, object, getfunction) \ - { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, 0, 0, 1, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_ARRAY_RW_FUNCTION(name, object, length, getfunction, setfunction) \ - { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RW, 0, 0, 0.f, 0, f, false, false, 0, 0, length, NULL, &object::setfunction, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } -#define KX_PYATTRIBUTE_ARRAY_RO_FUNCTION(name, object, length, getfunction) \ - { name, KX_PYATTRIBUTE_TYPE_FUNCTION, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0, f, false, false, 0, 0, length, NULL, NULL, &object::getfunction, {NULL, NULL, NULL, NULL, NULL, NULL, NULL} } - +#define EXP_PYATTRIBUTE_NULL \ + {"", EXP_PYATTRIBUTE_TYPE_BOOL, EXP_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, false, 0, 0, 1, nullptr, nullptr, nullptr} + +#define EXP_PYATTRIBUTE_BOOL_RW(name, object, field) \ + { name, EXP_PYATTRIBUTE_TYPE_BOOL, EXP_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, nullptr, nullptr, nullptr} +#define EXP_PYATTRIBUTE_BOOL_RW_CHECK(name, object, field, function) \ + { name, EXP_PYATTRIBUTE_TYPE_BOOL, EXP_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, &object::function, nullptr, nullptr} +#define EXP_PYATTRIBUTE_BOOL_RO(name, object, field) \ + { name, EXP_PYATTRIBUTE_TYPE_BOOL, EXP_PYATTRIBUTE_RO, 0, 1, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, nullptr, nullptr, nullptr} + +/// Attribute points to a single bit of an integer field, attribute=true if bit is set. +#define EXP_PYATTRIBUTE_FLAG_RW(name, object, field, bit) \ + { name, EXP_PYATTRIBUTE_TYPE_FLAG, EXP_PYATTRIBUTE_RW, bit, 0, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, nullptr, nullptr, nullptr} +#define EXP_PYATTRIBUTE_FLAG_RW_CHECK(name, object, field, bit, function) \ + { name, EXP_PYATTRIBUTE_TYPE_FLAG, EXP_PYATTRIBUTE_RW, bit, 0, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, nullptr, nullptr} +#define EXP_PYATTRIBUTE_FLAG_RO(name, object, field, bit) \ + { name, EXP_PYATTRIBUTE_TYPE_FLAG, EXP_PYATTRIBUTE_RO, bit, 0, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, nullptr, nullptr, nullptr} + +/// Attribute points to a single bit of an integer field, attribute=true if bit is set. +#define EXP_PYATTRIBUTE_FLAG_NEGATIVE_RW(name, object, field, bit) \ + { name, EXP_PYATTRIBUTE_TYPE_FLAG, EXP_PYATTRIBUTE_RW, bit, 1, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, nullptr, nullptr, nullptr} +#define EXP_PYATTRIBUTE_FLAG_NEGATIVE_RW_CHECK(name, object, field, bit, function) \ + { name, EXP_PYATTRIBUTE_TYPE_FLAG, EXP_PYATTRIBUTE_RW, bit, 1, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, nullptr, nullptr} +#define EXP_PYATTRIBUTE_FLAG_NEGATIVE_RO(name, object, field, bit) \ + { name, EXP_PYATTRIBUTE_TYPE_FLAG, EXP_PYATTRIBUTE_RO, bit, 1, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, nullptr, nullptr, nullptr} + +/** Enum field cannot be mapped to pointer (because we would need a pointer for each enum) + * use field size to verify mapping at runtime only, assuming enum size is equal to int size. + */ +#define EXP_PYATTRIBUTE_ENUM_RW(name, min, max, clamp, object, field) \ + { name, EXP_PYATTRIBUTE_TYPE_ENUM, EXP_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), sizeof(((object *)0)->field), 1, nullptr, nullptr, nullptr} +#define EXP_PYATTRIBUTE_ENUM_RW_CHECK(name, min, max, clamp, object, field, function) \ + { name, EXP_PYATTRIBUTE_TYPE_ENUM, EXP_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, nullptr, nullptr} +#define EXP_PYATTRIBUTE_ENUM_RO(name, object, field) \ + { name, EXP_PYATTRIBUTE_TYPE_ENUM, EXP_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, nullptr, nullptr, nullptr} + +#define EXP_PYATTRIBUTE_SHORT_RW(name, min, max, clamp, object, field) \ + { name, EXP_PYATTRIBUTE_TYPE_SHORT, EXP_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, nullptr, nullptr, nullptr} +#define EXP_PYATTRIBUTE_SHORT_RW_CHECK(name, min, max, clamp, object, field, function) \ + { name, EXP_PYATTRIBUTE_TYPE_SHORT, EXP_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, &object::function, nullptr, nullptr} +#define EXP_PYATTRIBUTE_SHORT_RO(name, object, field) \ + { name, EXP_PYATTRIBUTE_TYPE_SHORT, EXP_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, nullptr, nullptr, nullptr} +#define EXP_PYATTRIBUTE_SHORT_ARRAY_RW(name, min, max, clamp, object, field, length) \ + { name, EXP_PYATTRIBUTE_TYPE_SHORT, EXP_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, nullptr, nullptr, nullptr} +#define EXP_PYATTRIBUTE_SHORT_ARRAY_RW_CHECK(name, min, max, clamp, object, field, length, function) \ + { name, EXP_PYATTRIBUTE_TYPE_SHORT, EXP_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, &object::function, nullptr, nullptr} +#define EXP_PYATTRIBUTE_SHORT_ARRAY_RO(name, object, field, length) \ + { name, EXP_PYATTRIBUTE_TYPE_SHORT, EXP_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, length, nullptr, nullptr, nullptr} + +#define EXP_PYATTRIBUTE_SHORT_LIST_RW(name, min, max, clamp, object, field, length) \ + { name, EXP_PYATTRIBUTE_TYPE_SHORT, EXP_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, nullptr, nullptr, nullptr} +#define EXP_PYATTRIBUTE_SHORT_LIST_RW_CHECK(name, min, max, clamp, object, field, length, function) \ + { name, EXP_PYATTRIBUTE_TYPE_SHORT, EXP_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, &object::function, nullptr, nullptr} +#define EXP_PYATTRIBUTE_SHORT_LIST_RO(name, object, field, length) \ + { name, EXP_PYATTRIBUTE_TYPE_SHORT, EXP_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, length, nullptr, nullptr, nullptr} + +#define EXP_PYATTRIBUTE_INT_RW(name, min, max, clamp, object, field) \ + { name, EXP_PYATTRIBUTE_TYPE_INT, EXP_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, nullptr, nullptr, nullptr} +#define EXP_PYATTRIBUTE_INT_RW_CHECK(name, min, max, clamp, object, field, function) \ + { name, EXP_PYATTRIBUTE_TYPE_INT, EXP_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, &object::function, nullptr, nullptr} +#define EXP_PYATTRIBUTE_INT_RO(name, object, field) \ + { name, EXP_PYATTRIBUTE_TYPE_INT, EXP_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, nullptr, nullptr, nullptr} +#define EXP_PYATTRIBUTE_INT_ARRAY_RW(name, min, max, clamp, object, field, length) \ + { name, EXP_PYATTRIBUTE_TYPE_INT, EXP_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, nullptr, nullptr, nullptr} +#define EXP_PYATTRIBUTE_INT_ARRAY_RW_CHECK(name, min, max, clamp, object, field, length, function) \ + { name, EXP_PYATTRIBUTE_TYPE_INT, EXP_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, &object::function, nullptr, nullptr} +#define EXP_PYATTRIBUTE_INT_ARRAY_RO(name, object, field, length) \ + { name, EXP_PYATTRIBUTE_TYPE_INT, EXP_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, length, nullptr, nullptr, nullptr} + +#define EXP_PYATTRIBUTE_INT_LIST_RW(name, min, max, clamp, object, field, length) \ + { name, EXP_PYATTRIBUTE_TYPE_INT, EXP_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, nullptr, nullptr, nullptr} +#define EXP_PYATTRIBUTE_INT_LIST_RW_CHECK(name, min, max, clamp, object, field, length, function) \ + { name, EXP_PYATTRIBUTE_TYPE_INT, EXP_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, length, &object::function, nullptr, nullptr} +#define EXP_PYATTRIBUTE_INT_LIST_RO(name, object, field, length) \ + { name, EXP_PYATTRIBUTE_TYPE_INT, EXP_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, length, nullptr, nullptr, nullptr} + +/// Always clamp for float. +#define EXP_PYATTRIBUTE_FLOAT_RW(name, min, max, object, field) \ + { name, EXP_PYATTRIBUTE_TYPE_FLOAT, EXP_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, 1, nullptr, nullptr, nullptr} +#define EXP_PYATTRIBUTE_FLOAT_RW_CHECK(name, min, max, object, field, function) \ + { name, EXP_PYATTRIBUTE_TYPE_FLOAT, EXP_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, 1, &object::function, nullptr, nullptr} +#define EXP_PYATTRIBUTE_FLOAT_RO(name, object, field) \ + { name, EXP_PYATTRIBUTE_TYPE_FLOAT, EXP_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, nullptr, nullptr, nullptr} +/// Field must be float[n], returns a sequence. +#define EXP_PYATTRIBUTE_FLOAT_ARRAY_RW(name, min, max, object, field, length) \ + { name, EXP_PYATTRIBUTE_TYPE_FLOAT, EXP_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, length, nullptr, nullptr, nullptr} +#define EXP_PYATTRIBUTE_FLOAT_ARRAY_RW_CHECK(name, min, max, object, field, length, function) \ + { name, EXP_PYATTRIBUTE_TYPE_FLOAT, EXP_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), 0, length, &object::function, nullptr, nullptr} +#define EXP_PYATTRIBUTE_FLOAT_ARRAY_RO(name, object, field, length) \ + { name, EXP_PYATTRIBUTE_TYPE_FLOAT, EXP_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, length, nullptr, nullptr, nullptr} +/// Field must be float[n], returns a vector. +#define EXP_PYATTRIBUTE_FLOAT_VECTOR_RW(name, min, max, object, field, length) \ + { name, EXP_PYATTRIBUTE_TYPE_FLOAT, EXP_PYATTRIBUTE_RW, 0, length, min, max, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, nullptr, nullptr, nullptr} +#define EXP_PYATTRIBUTE_FLOAT_VECTOR_RW_CHECK(name, min, max, object, field, length, function) \ + { name, EXP_PYATTRIBUTE_TYPE_FLOAT, EXP_PYATTRIBUTE_RW, 0, length, min, max, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, nullptr, nullptr} +#define EXP_PYATTRIBUTE_FLOAT_VECTOR_RO(name, object, field, length) \ + { name, EXP_PYATTRIBUTE_TYPE_FLOAT, EXP_PYATTRIBUTE_RO, 0, length, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, nullptr, nullptr, nullptr} +/// Field must be float[n][n], returns a matrix. +#define EXP_PYATTRIBUTE_FLOAT_MATRIX_RW(name, min, max, object, field, length) \ + { name, EXP_PYATTRIBUTE_TYPE_FLOAT, EXP_PYATTRIBUTE_RW, length, length, min, max, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, nullptr, nullptr, nullptr} +#define EXP_PYATTRIBUTE_FLOAT_MATRIX_RW_CHECK(name, min, max, object, field, length, function) \ + { name, EXP_PYATTRIBUTE_TYPE_FLOAT, EXP_PYATTRIBUTE_RW, length, length, min, max, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, nullptr, nullptr} +#define EXP_PYATTRIBUTE_FLOAT_MATRIX_RO(name, object, field, length) \ + { name, EXP_PYATTRIBUTE_TYPE_FLOAT, EXP_PYATTRIBUTE_RO, length, length, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, nullptr, nullptr, nullptr} + +/// Only for std::string member. +#define EXP_PYATTRIBUTE_STRING_RW(name, min, max, clamp, object, field) \ + { name, EXP_PYATTRIBUTE_TYPE_STRING, EXP_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, nullptr, nullptr, nullptr} +#define EXP_PYATTRIBUTE_STRING_RW_CHECK(name, min, max, clamp, object, field, function) \ + { name, EXP_PYATTRIBUTE_TYPE_STRING, EXP_PYATTRIBUTE_RW, min, max, 0.f, 0.f, clamp, false, offsetof(object, field), 0, 1, &object::function, nullptr, nullptr} +#define EXP_PYATTRIBUTE_STRING_RO(name, object, field) \ + { name, EXP_PYATTRIBUTE_TYPE_STRING, EXP_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), 0, 1, nullptr, nullptr, nullptr} + +/// Only for char [] array. +#define EXP_PYATTRIBUTE_CHAR_RW(name, object, field) \ + { name, EXP_PYATTRIBUTE_TYPE_CHAR, EXP_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, nullptr, nullptr, nullptr} +#define EXP_PYATTRIBUTE_CHAR_RW_CHECK(name, object, field, function) \ + { name, EXP_PYATTRIBUTE_TYPE_CHAR, EXP_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, true, false, offsetof(object, field), sizeof(((object *)0)->field), 1, &object::function, nullptr, nullptr} +#define EXP_PYATTRIBUTE_CHAR_RO(name, object, field) \ + { name, EXP_PYATTRIBUTE_TYPE_CHAR, EXP_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), sizeof(((object *)0)->field), 1, nullptr, nullptr, nullptr} + +/// For mt::vec3 member. +#define EXP_PYATTRIBUTE_VECTOR_RW(name, min, max, object, field, size) \ + { name, EXP_PYATTRIBUTE_TYPE_VECTOR, EXP_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), size, 1, nullptr, nullptr, nullptr} +#define EXP_PYATTRIBUTE_VECTOR_RW_CHECK(name, min, max, clamp, object, field, size, function) \ + { name, EXP_PYATTRIBUTE_TYPE_VECTOR, EXP_PYATTRIBUTE_RW, 0, 0, min, max, true, false, offsetof(object, field), size, 1, &object::function, nullptr, nullptr} +#define EXP_PYATTRIBUTE_VECTOR_RO(name, object, field, size) \ + { name, EXP_PYATTRIBUTE_TYPE_VECTOR, EXP_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, offsetof(object, field), size, 1, nullptr, nullptr, nullptr} + +#define EXP_PYATTRIBUTE_RW_FUNCTION(name, object, getfunction, setfunction) \ + { name, EXP_PYATTRIBUTE_TYPE_FUNCTION, EXP_PYATTRIBUTE_RW, 0, 0, 0.f, 0.f, false, false, 0, 0, 1, nullptr, &object::setfunction, &object::getfunction} +#define EXP_PYATTRIBUTE_RO_FUNCTION(name, object, getfunction) \ + { name, EXP_PYATTRIBUTE_TYPE_FUNCTION, EXP_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, false, false, 0, 0, 1, nullptr, nullptr, &object::getfunction} +#define EXP_PYATTRIBUTE_ARRAY_RW_FUNCTION(name, object, length, getfunction, setfunction) \ + { name, EXP_PYATTRIBUTE_TYPE_FUNCTION, EXP_PYATTRIBUTE_RW, 0, 0, 0.f, 0, f, false, false, 0, 0, length, nullptr, &object::setfunction, &object::getfunction} +#define EXP_PYATTRIBUTE_ARRAY_RO_FUNCTION(name, object, length, getfunction) \ + { name, EXP_PYATTRIBUTE_TYPE_FUNCTION, EXP_PYATTRIBUTE_RO, 0, 0, 0.f, 0, f, false, false, 0, 0, length, nullptr, nullptr, &object::getfunction} + +template +inline bool EXP_ParseTupleArgsAndKeywords(PyObject *pyargs, PyObject *pykwds, const char *format, std::initializer_list keyword, Args ... args) +{ + BLI_assert((keyword.size() - 1) == (sizeof...(Args))); + static _PyArg_Parser _parser = {format, keyword.begin(), 0}; + return _PyArg_ParseTupleAndKeywordsFast(pyargs, pykwds, &_parser, args ...); +} /*------------------------------ - * PyObjectPlus + * EXP_PyObjectPlus *------------------------------ */ -typedef PyTypeObject *PyParentObject; /* Define the PyParent Object */ - -#else // WITH_PYTHON - -#ifdef WITH_CXX_GUARDEDALLOC -#define Py_Header \ -public: \ - MEM_CXX_CLASS_ALLOC_FUNCS("GE:PyObjectPlus") \ - - -#define Py_HeaderPtr \ - MEM_CXX_CLASS_ALLOC_FUNCS("GE:PyObjectPlusPtr") \ - -#else // WITH_CXX_GUARDEDALLOC +#else // WITH_PYTHON #define Py_Header \ public: \ @@ -550,93 +525,83 @@ public: \ #define Py_HeaderPtr \ public: \ -#endif /* WITH_CXX_GUARDEDALLOC */ - #endif +/// The EXP_PyObjectPlus abstract class. +class EXP_PyObjectPlus +{ + Py_Header // Always start with Py_Header -// By making SG_QList the ultimate parent for PyObjectPlus objects, it -// allows to put them in 2 different dynamic lists at the same time -// The use of these links is interesting because they free of memory allocation -// but it's very important not to mess up with them. If you decide that -// the SG_QList or SG_DList component is used for something for a certain class, -// they cannot can be used for anything else at a parent level! -// What these lists are and what they are used for must be carefully documented -// at the level where they are used. -// DON'T MAKE ANY USE OF THESE LIST AT THIS LEVEL, they are already used -// at SCA_IActuator, SCA_ISensor, SCA_IController level which rules out the -// possibility to use them at SCA_ILogicBrick, CValue and PyObjectPlus level. -class PyObjectPlus : public SG_QList -{ // The PyObjectPlus abstract class - Py_Header // Always start with Py_Header +protected: + /** Called when the object is freed from a python owner proxy. + * It has effect to use reference count for deletion and to not + * be every time deleted in EXP_Value. + */ + virtual void DestructFromPython(); -public: - PyObjectPlus(); + static bool m_ignore_deprecation_warnings; - virtual ~PyObjectPlus(); // destructor +public: + EXP_PyObjectPlus(); + virtual ~EXP_PyObjectPlus(); #ifdef WITH_PYTHON - PyObject *m_proxy; /* actually a PyObjectPlus_Proxy */ + PyObject *m_proxy; // Actually a EXP_PyObjectPlus_Proxy. - /* These static functions are referenced by ALL PyObjectPlus_Proxy types - * they take the C++ reference from the PyObjectPlus_Proxy and call + /* These static functions are referenced by ALL EXP_PyObjectPlus_Proxy types + * they take the C++ reference from the EXP_PyObjectPlus_Proxy and call * its own virtual py_repr, py_base_dealloc, etc. functions. */ - - static PyObject* py_base_new(PyTypeObject *type, PyObject *args, PyObject *kwds); /* allows subclassing */ - static void py_base_dealloc(PyObject *self); - static PyObject* py_base_repr(PyObject *self); + static PyObject *py_base_new(PyTypeObject *type, PyObject *args, PyObject *kwds); // Allows subclassing. + static void py_base_dealloc(PyObject *self); + static PyObject *py_base_repr(PyObject *self); /* These are all virtual python methods that are defined in each class * Our own fake subclassing calls these on each class, then calls the parent */ - virtual PyObject* py_repr(void); - /* subclass may overwrite this function to implement more sophisticated method of validating a proxy */ - virtual bool py_is_valid(void) { return true; } - - static PyObject* py_get_attrdef(PyObject *self_py, const PyAttributeDef *attrdef); - static int py_set_attrdef(PyObject *self_py, PyObject *value, const PyAttributeDef *attrdef); - - /* Kindof dumb, always returns True, the false case is checked for, before this function gets accessed */ - static PyObject* pyattr_get_invalid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - - static PyObject *GetProxyPlus_Ext(PyObjectPlus *self, PyTypeObject *tp, void *ptr); - /* self=NULL => proxy to generic pointer detached from GE object - * if py_owns is true, the memory pointed by ptr will be deleted automatically with MEM_freeN - * self!=NULL=> proxy attached to GE object, ptr is optional and point to a struct from which attributes can be defined - * if py_owns is true, the object will be deleted automatically, ptr will NOT be deleted - * (assume object destructor takes care of it) */ - static PyObject *NewProxyPlus_Ext(PyObjectPlus *self, PyTypeObject *tp, void *ptr, bool py_owns); - - static WarnLink* GetDeprecationWarningLinkFirst(void); - static WarnLink* GetDeprecationWarningLinkLast(void); - static void SetDeprecationWarningFirst(WarnLink* wlink); - static void SetDeprecationWarningLinkLast(WarnLink* wlink); - static void NullDeprecationWarning(); - - /** enable/disable display of deprecation warnings */ - static void SetDeprecationWarnings(bool ignoreDeprecationWarnings); - /** Shows a deprecation warning */ - static void ShowDeprecationWarning_func(const char *method, const char *prop); - static void ClearDeprecationWarning(); + virtual PyObject *py_repr(); + /// Subclass may overwrite this function to implement more sophisticated method of validating a proxy. + virtual bool py_is_valid(); + + static PyObject *py_get_attrdef(PyObject *self_py, const PyAttributeDef *attrdef); + static int py_set_attrdef(PyObject *self_py, PyObject *value, const PyAttributeDef *attrdef); + + /// Kindof dumb, always returns True, the false case is checked for, before this function gets accessed. + static PyObject *pyattr_get_invalid(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + + static PyObject *GetProxyPlus_Ext(EXP_PyObjectPlus *self, PyTypeObject *tp, void *ptr); + /** self=nullptr => proxy to generic pointer detached from GE object + * if py_owns is true, the memory pointed by ptr will be deleted automatically with MEM_freeN + * self!=nullptr=> proxy attached to GE object, ptr is optional and point to a struct from which attributes can be defined + * if py_owns is true, the object will be deleted automatically, ptr will NOT be deleted + * (assume object destructor takes care of it) */ + static PyObject *NewProxyPlus_Ext(EXP_PyObjectPlus *self, PyTypeObject *tp, void *ptr, bool py_owns); + + static EXP_WarnLink *GetDeprecationWarningLinkFirst(); + static EXP_WarnLink *GetDeprecationWarningLinkLast(); + static void SetDeprecationWarningFirst(EXP_WarnLink *wlink); + static void SetDeprecationWarningLinkLast(EXP_WarnLink *wlink); + static void NullDeprecationWarning(); + + static bool GetDerprecationWarnings(); + /// Enable/disable display of deprecation warnings. + static void SetDeprecationWarnings(bool ignoreDeprecationWarnings); + /// Shows a deprecation warning. + static void ShowDeprecationWarning_func(const std::string& old_way, const std::string& new_way); + static void ClearDeprecationWarning(); #endif - void InvalidateProxy(); + void InvalidateProxy(); - /** - * Makes sure any internal data owned by this class is deep copied. - */ - virtual void ProcessReplica(); - - static bool m_ignore_deprecation_warnings; -}; + /// Makes sure any internal data owned by this class is deep copied. + virtual void ProcessReplica();}; #ifdef WITH_PYTHON -PyObject *PyUnicode_From_STR_String(const STR_String& str); +PyObject *PyUnicode_FromStdString(const std::string& str); -inline PyObject *_bge_proxy_from_ref_borrow(void *self_v) +inline PyObject *_bge_proxy_from_ref_borrow(EXP_PyObjectPlus *self_v) { - PyObject *self_proxy = BGE_PROXY_FROM_REF(self_v); + PyObject *self_proxy = EXP_PROXY_FROM_REF(self_v); /* this is typically _very_ bad practice, * however we know the proxy is owned by 'self_v' */ self_proxy->ob_refcnt--; @@ -645,4 +610,4 @@ inline PyObject *_bge_proxy_from_ref_borrow(void *self_v) #endif -#endif /* __EXP_PYOBJECTPLUS_H__ */ +#endif // __EXP_PYOBJECTPLUS_H__ diff --git a/source/gameengine/Expressions/EXP_Python.h b/source/gameengine/Expressions/EXP_Python.h index f904151085ea..2f041ac1a253 100644 --- a/source/gameengine/Expressions/EXP_Python.h +++ b/source/gameengine/Expressions/EXP_Python.h @@ -32,9 +32,7 @@ #ifndef __EXP_PYTHON_H__ #define __EXP_PYTHON_H__ -//#define USE_DL_EXPORT - -/* python redefines, quiet the compiler */ +// Python redefines, quiet the compiler. #ifdef _XOPEN_SOURCE #undef _XOPEN_SOURCE #endif @@ -79,4 +77,4 @@ #undef toupper #endif -#endif /* __EXP_PYTHON_H__ */ +#endif // __EXP_PYTHON_H__ diff --git a/source/gameengine/Expressions/EXP_PythonCallBack.h b/source/gameengine/Expressions/EXP_PythonCallBack.h index f0cbcac0c6fa..f79295c3e6f9 100644 --- a/source/gameengine/Expressions/EXP_PythonCallBack.h +++ b/source/gameengine/Expressions/EXP_PythonCallBack.h @@ -29,12 +29,20 @@ #include "EXP_Python.h" +/** Check and call a python callable object. + * \param value Callable object candidate. + * \param arglist The first item in the tuple to execute callbacks (can be nullptr for no arguments). + * \param minargcount The minimum of arguments possible. + * \param maxargcount The maximum of arguments possible. + */ +void EXP_RunPythonCallback(PyObject *value, PyObject **arglist, unsigned int minargcount, unsigned int maxargcount); + /** Execute each functions with at least one argument * \param functionlist The python list which contains callbacks. - * \param arglist The first item in the tuple to execute callbacks (can be NULL for no arguments). + * \param arglist The first item in the tuple to execute callbacks (can be nullptr for no arguments). * \param minargcount The minimum of quantity of arguments possible. * \param maxargcount The maximum of quantity of arguments possible. */ -void RunPythonCallBackList(PyObject *functionlist, PyObject **arglist, unsigned int minargcount, unsigned int maxargcount); +void EXP_RunPythonCallBackList(PyObject *functionlist, PyObject **arglist, unsigned int minargcount, unsigned int maxargcount); #endif // __EXP_PYTHON_CALLBACK_H__ diff --git a/source/gameengine/Expressions/EXP_StringValue.h b/source/gameengine/Expressions/EXP_StringValue.h index 57c5de2206b5..11f78f230e70 100644 --- a/source/gameengine/Expressions/EXP_StringValue.h +++ b/source/gameengine/Expressions/EXP_StringValue.h @@ -1,5 +1,5 @@ /* - * StringValue.h: interface for the CStringValue class. + * StringValue.h: interface for the EXP_StringValue class. * Copyright (c) 1996-2000 Erwin Coumans * * Permission to use, copy, modify, distribute and sell this software @@ -21,41 +21,36 @@ #include "EXP_Value.h" -class CStringValue : public CPropValue +class EXP_StringValue : public EXP_PropValue { +public: + EXP_StringValue(); + EXP_StringValue(const std::string& txt, const std::string& name); + virtual ~EXP_StringValue() + { + } + /// EXP_Value implementation + virtual bool IsEqual(const std::string & other); + virtual std::string GetText(); + virtual double GetNumber(); + virtual int GetValueType(); + + virtual EXP_Value *Calc(VALUE_OPERATOR op, EXP_Value *val); + virtual EXP_Value *CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, EXP_Value *val); + virtual void SetValue(EXP_Value *newval); + virtual EXP_Value *GetReplica(); - //PLUGIN_DECLARE_SERIAL(CStringValue,CValue) -public: - /// Construction / destruction - CStringValue(); - CStringValue(const char *txt, const char *name, AllocationTYPE alloctype = CValue::HEAPVALUE); - - virtual ~CStringValue() {} - /// CValue implementation - virtual bool IsEqual(const STR_String & other); - virtual const STR_String & GetText(); - virtual double GetNumber(); - virtual int GetValueType(); - - virtual CValue* Calc(VALUE_OPERATOR op, CValue *val); - virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); - virtual void SetValue(CValue* newval) { m_strString = newval->GetText(); SetModified(true); } - virtual CValue* GetReplica(); #ifdef WITH_PYTHON - virtual PyObject* ConvertValueToPython() { - return PyUnicode_From_STR_String(m_strString); + virtual PyObject *ConvertValueToPython() + { + return PyUnicode_FromStdString(m_strString); } -#endif /* WITH_PYTHON */ +#endif // WITH_PYTHON private: - // data member - STR_String m_strString; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:CStringValue") -#endif + /// Data member. + std::string m_strString; }; -#endif /* __EXP_STRINGVALUE_H__ */ +#endif // __EXP_STRINGVALUE_H__ diff --git a/source/gameengine/Expressions/EXP_Value.h b/source/gameengine/Expressions/EXP_Value.h index dd0cee3dbb89..1f1fc89fa55c 100644 --- a/source/gameengine/Expressions/EXP_Value.h +++ b/source/gameengine/Expressions/EXP_Value.h @@ -1,5 +1,5 @@ /* - * Value.h: interface for the CValue class. + * Value.h: interface for the EXP_Value class. * Copyright (c) 1996-2000 Erwin Coumans * * Permission to use, copy, modify, distribute and sell this software @@ -23,59 +23,39 @@ # pragma warning (disable:4786) #endif -#include // array functionality for the propertylist -#include "STR_String.h" // STR_String class - -using namespace std; - -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -#ifndef GEN_NO_ASSERT -#undef assert -#define assert(exp) ((void)NULL) -#endif +#include "CM_RefCount.h" +#include // Array functionality for the property list. +#include +#include // std::string class. #ifndef GEN_NO_TRACE #undef trace -#define trace(exp) ((void)NULL) -#endif - -#ifndef GEN_NO_DEBUG -#undef debug -#define debug(exp) ((void)NULL) -#endif - -#ifndef GEN_NO_ASSERTD -#undef assertd -#define assertd(exp) ((void)NULL) +#define trace(exp) ((void)nullptr) #endif enum VALUE_OPERATOR { - - VALUE_MOD_OPERATOR, // % - VALUE_ADD_OPERATOR, // + - VALUE_SUB_OPERATOR, // - - VALUE_MUL_OPERATOR, // * - VALUE_DIV_OPERATOR, // / - VALUE_NEG_OPERATOR, // - - VALUE_POS_OPERATOR, // + - VALUE_AND_OPERATOR, // && - VALUE_OR_OPERATOR, // || - VALUE_EQL_OPERATOR, // == - VALUE_NEQ_OPERATOR, // != - VALUE_GRE_OPERATOR, // > - VALUE_LES_OPERATOR, // < - VALUE_GEQ_OPERATOR, // >= - VALUE_LEQ_OPERATOR, // <= - VALUE_NOT_OPERATOR, // ! - VALUE_NO_OPERATOR // no operation at all + VALUE_MOD_OPERATOR, // % + VALUE_ADD_OPERATOR, // + + VALUE_SUB_OPERATOR, // - + VALUE_MUL_OPERATOR, // * + VALUE_DIV_OPERATOR, // / + VALUE_NEG_OPERATOR, // - + VALUE_POS_OPERATOR, // + + VALUE_AND_OPERATOR, // && + VALUE_OR_OPERATOR, // || + VALUE_EQL_OPERATOR, // == + VALUE_NEQ_OPERATOR, // != + VALUE_GRE_OPERATOR, // > + VALUE_LES_OPERATOR, // < + VALUE_GEQ_OPERATOR, // >= + VALUE_LEQ_OPERATOR, // <= + VALUE_NOT_OPERATOR, // ! + VALUE_NO_OPERATOR // no operation at all }; enum VALUE_DATA_TYPE { - VALUE_NO_TYPE, // abstract baseclass + VALUE_NO_TYPE, // Abstract baseclass. VALUE_INT_TYPE, VALUE_FLOAT_TYPE, VALUE_STRING_TYPE, @@ -85,89 +65,18 @@ enum VALUE_DATA_TYPE { VALUE_LIST_TYPE, VALUE_VOID_TYPE, VALUE_VECTOR_TYPE, - VALUE_MAX_TYPE //only here to provide number of types -}; - - - -#ifdef DEBUG -//extern int gRefCountValue; // debugonly variable to check if all CValue Refences are Dereferenced at programexit -#endif - -struct HashableInt -{ - HashableInt(int id) : mData(id) { } - - unsigned long Hash() const { return 0;} ////}gHash(&mData, sizeof(int));} - - bool operator==(HashableInt rhs) { return mData == rhs.mData; } - - int mData; -}; - - -// -// Bitfield that stores the flags for each CValue derived class -// -struct ValueFlags { - ValueFlags() : - Modified(true), - Selected(false), - Affected(false), - ReleaseRequested(false), - Error(false), - RefCountDisabled(false), - HasProperties(false), - HasName(false), - Visible(true), - CustomFlag1(false), - CustomFlag2(false) - { - } - - unsigned short Modified : 1; - unsigned short Selected : 1; - unsigned short Affected : 1; - unsigned short ReleaseRequested : 1; - unsigned short Error : 1; - unsigned short RefCountDisabled : 1; - unsigned short HasProperties : 1; - unsigned short HasName : 1; - unsigned short Visible : 1; - unsigned short CustomFlag1 : 1; - unsigned short CustomFlag2 : 1; - - + VALUE_MAX_TYPE // Only here to provide number of types. }; -/** - * Base Class for all Actions performed on CValue's. Can be extended for undo/redo system in future. - */ -class CAction -{ -public: - CAction() { - }; - virtual ~CAction() { - }; - virtual void Execute() const =0; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:CAction") -#endif -}; - - #include "EXP_PyObjectPlus.h" #ifdef WITH_PYTHON #include "object.h" #endif /** - * Baseclass CValue + * Baseclass EXP_Value * - * Together with CExpression, CValue and it's derived classes can be used to + * Together with EXP_Expression, EXP_Value and it's derived classes can be used to * parse expressions into a parsetree with error detecting/correcting capabilities * also expandable by a CFactory pluginsystem * @@ -175,258 +84,119 @@ class CAction * calculations and uses reference counting for memory management. * * Features: - * - Reference Counting (AddRef() / Release()) * - Calculations (Calc() / CalcFinal()) - * - Configuration (Configure()) - * - Serialization (EdSerialize() / EdIdSerialize() / EdPtrSerialize() and macro PLUGIN_DECLARE_SERIAL * - Property system (SetProperty() / GetProperty() / FindIdentifier()) * - Replication (GetReplica()) - * - Flags (IsSelected() / IsModified() / SetSelected()...) + * - Flags (IsError()) * * - Some small editor-specific things added * - A helperclass CompressorArchive handles the serialization * */ -class CValue : public PyObjectPlus - +class EXP_Value : public EXP_PyObjectPlus, public CM_RefCount { -Py_Header + Py_Header public: - enum AllocationTYPE { - STACKVALUE = 0, - HEAPVALUE = 1 - }; - - enum DrawTYPE { - STARTFRAME = 0, - ENDFRAME = 1, - INTERFRAME = 2 - }; - - - // Construction / Destruction - CValue(); + EXP_Value(); + virtual ~EXP_Value(); #ifdef WITH_PYTHON - //static PyObject *PyMake(PyObject *, PyObject *); virtual PyObject *py_repr(void) { - return PyUnicode_From_STR_String(GetText()); + return PyUnicode_FromStdString(GetText()); } - virtual PyObject *ConvertValueToPython() { - return NULL; - } - - virtual CValue *ConvertPythonToValue(PyObject *pyobj, const bool do_type_exception, const char *error_prefix); - - static PyObject *pyattr_get_name(void *self, const KX_PYATTRIBUTE_DEF *attrdef); - - virtual PyObject *ConvertKeysToPython( void ); -#endif /* WITH_PYTHON */ - - - - // Expression Calculation - virtual CValue* Calc(VALUE_OPERATOR op, CValue *val) = 0; - virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val) = 0; - virtual void SetOwnerExpression(class CExpression* expr); - - - - void Execute(const CAction& a) + virtual PyObject *ConvertValueToPython() { - a.Execute(); - }; - - /// Reference Counting - int GetRefCount() - { - return m_refcount; + return nullptr; } - // Add a reference to this value - CValue *AddRef() - { - // Increase global reference count, used to see at the end of the program - // if all CValue-derived classes have been dereferenced to 0 - //debug(gRefCountValue++); -#ifdef DEBUG - //gRefCountValue++; -#endif - m_refcount++; - return this; - } + virtual EXP_Value *ConvertPythonToValue(PyObject *pyobj, const bool do_type_exception, const char *error_prefix); - // Release a reference to this value (when reference count reaches 0, the value is removed from the heap) - int Release() - { - // Decrease global reference count, used to see at the end of the program - // if all CValue-derived classes have been dereferenced to 0 - //debug(gRefCountValue--); -#ifdef DEBUG - //gRefCountValue--; -#endif - // Decrease local reference count, if it reaches 0 the object should be freed - if (--m_refcount > 0) - { - // Reference count normal, return new reference count - return m_refcount; - } - else - { - // Reference count reached 0, delete ourselves and return 0 - // MT_assert(m_refcount==0, "Reference count reached sub-zero, object released too much"); + static PyObject *pyattr_get_name(EXP_PyObjectPlus *self, const EXP_PYATTRIBUTE_DEF *attrdef); - delete this; - return 0; - } - } + virtual PyObject *ConvertKeysToPython(void); +#endif // WITH_PYTHON + /// Expression Calculation + virtual EXP_Value *Calc(VALUE_OPERATOR op, EXP_Value *val); + virtual EXP_Value *CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, EXP_Value *val); /// Property Management - virtual void SetProperty(const STR_String& name,CValue* ioProperty); // Set property , overwrites and releases a previous property with the same name if needed - virtual void SetProperty(const char* name,CValue* ioProperty); - virtual CValue* GetProperty(const char* inName); // Get pointer to a property with name , returns NULL if there is no property named - virtual CValue* GetProperty(const STR_String & inName); - const STR_String& GetPropertyText(const STR_String & inName); // Get text description of property with name , returns an empty string if there is no property named - float GetPropertyNumber(const STR_String& inName,float defnumber); - virtual bool RemoveProperty(const char *inName); // Remove the property named , returns true if the property was succesfully removed, false if property was not found or could not be removed - virtual vector GetPropertyNames(); - virtual void ClearProperties(); // Clear all properties - - virtual void SetPropertiesModified(bool inModified); // Set all properties' modified flag to - virtual bool IsAnyPropertyModified(); // Check if any of the properties in this value have been modified - - virtual CValue* GetProperty(int inIndex); // Get property number - virtual int GetPropertyCount(); // Get the amount of properties assiocated with this value - - virtual CValue* FindIdentifier(const STR_String& identifiername); - /** Set the wireframe color of this value depending on the CSG - * operator type - * \attention: not implemented */ - virtual void SetColorOperator(VALUE_OPERATOR op); - - virtual const STR_String & GetText() = 0; - virtual double GetNumber() = 0; - virtual int GetValueType(); // Get Prop value type - double* ZeroVector() { return m_sZeroVec; } - virtual double* GetVector3(bool bGetTransformedVec = false); - - virtual STR_String& GetName() = 0; // Retrieve the name of the value - virtual void SetName(const char *name) = 0; // Set the name of the value + /// Set property , overwrites and releases a previous property with the same name if needed. + virtual void SetProperty(const std::string& name, EXP_Value *ioProperty); + virtual EXP_Value *GetProperty(const std::string & inName); + /// Get text description of property with name , returns an empty string if there is no property named . + const std::string GetPropertyText(const std::string & inName); + float GetPropertyNumber(const std::string& inName, float defnumber); + /// Remove the property named , returns true if the property was succesfully removed, false if property was not found or could not be removed. + virtual bool RemoveProperty(const std::string& inName); + virtual std::vector GetPropertyNames(); + /// Clear all properties. + virtual void ClearProperties(); + + /// Get property number . + virtual EXP_Value *GetProperty(int inIndex); + /// Get the amount of properties assiocated with this value. + virtual int GetPropertyCount(); + + virtual EXP_Value *FindIdentifier(const std::string& identifiername); + + virtual std::string GetText(); + virtual double GetNumber(); + /// Get Prop value type. + virtual int GetValueType(); + + /// Retrieve the name of the value. + virtual std::string GetName() = 0; + /// Set the name of the value. + virtual void SetName(const std::string& name); /** Sets the value to this cvalue. - * \attention this particular function should never be called. Why not abstract? */ - virtual void SetValue(CValue* newval); - virtual CValue* GetReplica() =0; - virtual void ProcessReplica(); - //virtual CValue* Copy() = 0; - - STR_String op2str(VALUE_OPERATOR op); + * \attention this particular function should never be called. Why not abstract? + */ + virtual void SetValue(EXP_Value *newval); + virtual EXP_Value *GetReplica(); + virtual void ProcessReplica(); - // setting / getting flags - inline void SetSelected(bool bSelected) { m_ValFlags.Selected = bSelected; } - virtual void SetModified(bool bModified) { m_ValFlags.Modified = bModified; } - virtual void SetAffected(bool bAffected=true) { m_ValFlags.Affected = bAffected; } - inline void SetReleaseRequested(bool bReleaseRequested) { m_ValFlags.ReleaseRequested=bReleaseRequested; } - inline void SetError(bool err) { m_ValFlags.Error=err; } - inline void SetVisible (bool vis) { m_ValFlags.Visible=vis; } + std::string op2str(VALUE_OPERATOR op); - virtual bool IsModified() { return m_ValFlags.Modified; } - inline bool IsError() { return m_ValFlags.Error; } - virtual bool IsAffected() { return m_ValFlags.Affected || m_ValFlags.Modified; } - virtual bool IsSelected() { return m_ValFlags.Selected; } - inline bool IsReleaseRequested() { return m_ValFlags.ReleaseRequested; } - virtual bool IsVisible() { return m_ValFlags.Visible;} - virtual void SetCustomFlag1(bool bCustomFlag) { m_ValFlags.CustomFlag1 = bCustomFlag;} - virtual bool IsCustomFlag1() { return m_ValFlags.CustomFlag1;} - - virtual void SetCustomFlag2(bool bCustomFlag) { m_ValFlags.CustomFlag2 = bCustomFlag;} - virtual bool IsCustomFlag2() { return m_ValFlags.CustomFlag2;} + virtual bool IsError() const; protected: - virtual void DisableRefCount(); // Disable reference counting for this value - //virtual void AddDataToReplica(CValue* replica); - virtual ~CValue(); -private: - // Member variables - std::map* m_pNamedPropertyArray; // Properties for user/game etc - ValueFlags m_ValFlags; // Frequently used flags in a bitfield (low memoryusage) - int m_refcount; // Reference Counter - static double m_sZeroVec[3]; + virtual void DestructFromPython(); +private: + /// Properties for user/game etc. + std::map m_properties; }; - - -// -// Declare a CValue or CExpression or CWhatever to be serialized by the editor. -// -// This macro introduces the EdSerialize() function (which must be implemented by -// the client) and the EdIdSerialize() function (which is implemented by this macro). -// -// The generated Copy() function returns a pointer to type -// of object. So, for *any* CValue-derived object this should be set to CValue, -// for *any* CExpression-derived object this should be set to CExpression. -// -#define PLUGIN_DECLARE_SERIAL(class_name, root_base_class_name) \ -public: \ - virtual root_base_class_name *Copy() { \ - return new class_name; \ - } \ - virtual bool EdSerialize(CompressorArchive& arch, \ - class CFactoryManager* facmgr, \ - bool bIsStoring); \ - virtual bool EdIdSerialize(CompressorArchive& arch, \ - class CFactoryManager* facmgr, \ - bool bIsStoring) \ - { \ - if (bIsStoring) \ - arch.StoreString(#class_name); \ - return false; \ - } \ - - -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -// CPropValue is a CValue derived class, that implements the identification (String name) -// SetName() / GetName(), -// normal classes should derive from CPropValue, real lightweight classes straight from CValue - - -class CPropValue : public CValue +/** EXP_PropValue is a EXP_Value derived class, that implements the identification (String name) + * SetName() / GetName(), + * normal classes should derive from EXP_PropValue, real lightweight classes straight from EXP_Value + */ +class EXP_PropValue : public EXP_Value { public: - CPropValue() : - CValue(), - m_strNewName() - + EXP_PropValue() { } - virtual ~CPropValue() + virtual ~EXP_PropValue() { } - virtual void SetName(const char *name) { + virtual void SetName(const std::string& name) + { m_strNewName = name; } - virtual STR_String& GetName() { - //STR_String namefromprop = GetPropertyText("Name"); - //if (namefromprop.Length() > 0) - // return namefromprop; + virtual std::string GetName() + { return m_strNewName; - } // name of Value + } protected: - STR_String m_strNewName; // Identification - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:CPropValue") -#endif + std::string m_strNewName; }; -#endif /* __EXP_VALUE_H__ */ +#endif // __EXP_VALUE_H__ diff --git a/source/gameengine/Expressions/EXP_VectorValue.h b/source/gameengine/Expressions/EXP_VectorValue.h deleted file mode 100644 index 8eda8f3ac6b9..000000000000 --- a/source/gameengine/Expressions/EXP_VectorValue.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * VectorValue.h: interface for the CVectorValue class. - * Copyright (c) 1996-2000 Erwin Coumans - * - * 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. Erwin Coumans makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - */ - -/** \file EXP_VectorValue.h - * \ingroup expressions - */ - -#ifndef __EXP_VECTORVALUE_H__ -#define __EXP_VECTORVALUE_H__ - -#include "EXP_Value.h" - -#define KX_X 0 -#define KX_Y 1 -#define KX_Z 2 - - -class CVectorValue : public CPropValue -{ - //PLUGIN_DECLARE_SERIAL(CVectorValue,CValue) - -public: - //void Transform(rcMatrix4x4 mat); - virtual void SetValue(CValue* newval); - void SetVector(double newvec[]); - void Configure(CValue* menuvalue); - virtual double* GetVector3(bool bGetTransformedVec=false); - virtual double GetNumber(); - virtual int GetValueType(); - - CValue* Calc(VALUE_OPERATOR op, CValue *val) { - return val->CalcFinal(VALUE_VECTOR_TYPE, op, this); - } - - CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); - - - CVectorValue(double vec[3], const char *name,AllocationTYPE alloctype=CValue::HEAPVALUE); - CVectorValue() {}; - - CVectorValue(double vec[3], AllocationTYPE alloctype=CValue::HEAPVALUE); - CVectorValue(float x,float y,float z, AllocationTYPE alloctype = CValue::HEAPVALUE); - virtual ~CVectorValue(); - //virtual bool ExportT3D(File *txtfile,bool bNoName=false); - void AddConfigurationData(CValue* menuvalue); - - - - virtual CValue* GetReplica(); - virtual const STR_String & GetText(); - -#if 0 - void SnapPoint(float num,int snap) - { - if (num > 0) num += ((float)snap / 2); - else num -= ((float)snap / 2); - num = (long)(((long)(num / snap)) * snap); - }; - - void SnapPosition(const double snapvec[]) - { - - if (snapvec[KX_X] >= 1) - SnapPoint(m_vec[KX_X],snapvec[KX_X]); - if (snapvec[KX_Y] >= 1) - SnapPoint(m_vec[KX_Y],snapvec[KX_Y]); - if (snapvec[KX_Z] >= 1) - SnapPoint(m_vec[KX_Z],snapvec[KX_Z]); - - } -#endif - -protected: - double m_vec[3]; - double m_transformedvec[3]; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:CVectorValue") -#endif -}; - -#endif /* __EXP_VECTORVALUE_H__ */ diff --git a/source/gameengine/Expressions/EXP_VoidValue.h b/source/gameengine/Expressions/EXP_VoidValue.h deleted file mode 100644 index ba7a383e9119..000000000000 --- a/source/gameengine/Expressions/EXP_VoidValue.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * VoidValue.h: interface for the CVoidValue class. - * - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file EXP_VoidValue.h - * \ingroup expressions - */ - -#ifndef __EXP_VOIDVALUE_H__ -#define __EXP_VOIDVALUE_H__ - -#include "EXP_Value.h" - -// -// Void value, used to transport *any* type of data -// -class CVoidValue : public CPropValue -{ - //PLUGIN_DECLARE_SERIAL (CVoidValue,CValue) - -public: - /// Construction/destruction - CVoidValue() : m_bDeleteOnDestruct(false), m_pAnything(NULL) { } - CVoidValue(void *voidptr, bool bDeleteOnDestruct, AllocationTYPE alloctype) : - m_bDeleteOnDestruct(bDeleteOnDestruct), - m_pAnything(voidptr) - { - if (alloctype == STACKVALUE) { - CValue::DisableRefCount(); - } - } - virtual ~CVoidValue(); /* Destruct void value, delete memory if we're owning it */ - - /// Value -> String or number - virtual const STR_String & GetText(); /* Get string description of void value (unimplemented) */ - virtual double GetNumber() { return -1; } - virtual int GetValueType() { return VALUE_VOID_TYPE; } - - /// Value calculation - virtual CValue* Calc(VALUE_OPERATOR op, CValue *val); - virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue* val); - - /// Value replication - virtual CValue* GetReplica(); - - /// Data members - bool m_bDeleteOnDestruct; - void* m_pAnything; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:CVoidValue") -#endif -}; - -#endif /* __EXP_VOIDVALUE_H__ */ diff --git a/source/gameengine/Expressions/intern/BaseListValue.cpp b/source/gameengine/Expressions/intern/BaseListValue.cpp new file mode 100644 index 000000000000..9f9657f6a614 --- /dev/null +++ b/source/gameengine/Expressions/intern/BaseListValue.cpp @@ -0,0 +1,617 @@ +/** \file gameengine/Expressions/BaseListValue.cpp + * \ingroup expressions + */ +// ListValue.cpp: implementation of the EXP_BaseListValue class. +// +////////////////////////////////////////////////////////////////////// +/* + * Copyright (c) 1996-2000 Erwin Coumans + * + * 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. 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 +#include + +#include "EXP_ListValue.h" +#include "EXP_StringValue.h" +#include +#include "EXP_BoolValue.h" + +#include "BLI_sys_types.h" // For intptr_t support. + +EXP_BaseListValue::EXP_BaseListValue() + :m_bReleaseContents(true) +{ +} + +EXP_BaseListValue::~EXP_BaseListValue() +{ + if (m_bReleaseContents) { + for (EXP_Value *item : m_valueArray) { + item->Release(); + } + } +} + +void EXP_BaseListValue::SetValue(int i, EXP_Value *val) +{ + m_valueArray[i] = val; +} + +EXP_Value *EXP_BaseListValue::GetValue(int i) +{ + return m_valueArray[i]; +} + +EXP_Value *EXP_BaseListValue::FindValue(const std::string& name) const +{ + const VectorTypeConstIterator it = std::find_if(m_valueArray.begin(), m_valueArray.end(), + [&name](EXP_Value *item) { + return item->GetName() == name; + }); + + if (it != m_valueArray.end()) { + return *it; + } + return nullptr; +} + +bool EXP_BaseListValue::SearchValue(EXP_Value *val) const +{ + return (std::find(m_valueArray.begin(), m_valueArray.end(), val) != m_valueArray.end()); +} + +void EXP_BaseListValue::Add(EXP_Value *value) +{ + m_valueArray.push_back(value); +} + +void EXP_BaseListValue::Insert(unsigned int i, EXP_Value *value) +{ + m_valueArray.insert(m_valueArray.begin() + i, value); +} + +bool EXP_BaseListValue::RemoveValue(EXP_Value *val) +{ + bool result = false; + for (VectorTypeIterator it = m_valueArray.begin(); it != m_valueArray.end(); ) { + if (*it == val) { + it = m_valueArray.erase(it); + result = true; + } + else { + ++it; + } + } + return result; +} + +bool EXP_BaseListValue::CheckEqual(EXP_Value *first, EXP_Value *second) +{ + bool result = false; + EXP_Value *eqval = first->Calc(VALUE_EQL_OPERATOR, second); + if (eqval == nullptr) { + return false; + } + std::string text = eqval->GetText(); + if (text == EXP_BoolValue::sTrueString) { + result = true; + } + eqval->Release(); + return result; +} + +std::string EXP_BaseListValue::GetText() +{ + std::string strListRep = "["; + std::string commastr = ""; + + for (EXP_Value *item : m_valueArray) { + strListRep += commastr; + strListRep += item->GetText(); + commastr = ", "; + } + strListRep += "]"; + + return strListRep; +} + +int EXP_BaseListValue::GetValueType() +{ + return VALUE_LIST_TYPE; +} + +void EXP_BaseListValue::SetReleaseOnDestruct(bool bReleaseContents) +{ + m_bReleaseContents = bReleaseContents; +} + +void EXP_BaseListValue::Remove(int i) +{ + m_valueArray.erase(m_valueArray.begin() + i); +} + +void EXP_BaseListValue::Resize(int num) +{ + m_valueArray.resize(num); +} + +void EXP_BaseListValue::ReleaseAndRemoveAll() +{ + for (EXP_Value *item : m_valueArray) { + item->Release(); + } + m_valueArray.clear(); +} + +int EXP_BaseListValue::GetCount() const +{ + return m_valueArray.size(); +} + +bool EXP_BaseListValue::Empty() const +{ + return m_valueArray.empty(); +} + +#ifdef WITH_PYTHON + +/* --------------------------------------------------------------------- */ +/* Python interface ---------------------------------------------------- */ +/* --------------------------------------------------------------------- */ + +Py_ssize_t EXP_BaseListValue::bufferlen(PyObject *self) +{ + EXP_BaseListValue *list = static_cast(EXP_PROXY_REF(self)); + if (list == nullptr) { + return 0; + } + + return (Py_ssize_t)list->GetCount(); +} + +PyObject *EXP_BaseListValue::buffer_item(PyObject *self, Py_ssize_t index) +{ + EXP_BaseListValue *list = static_cast(EXP_PROXY_REF(self)); + + if (list == nullptr) { + PyErr_SetString(PyExc_SystemError, "val = list[i], " EXP_PROXY_ERROR_MSG); + return nullptr; + } + + int count = list->GetCount(); + + if (index < 0) { + index = count + index; + } + + if (index < 0 || index >= count) { + PyErr_SetString(PyExc_IndexError, "list[i]: Python ListIndex out of range in EXP_ValueList"); + return nullptr; + } + + EXP_Value *cval = list->GetValue(index); + + PyObject *pyobj = cval->ConvertValueToPython(); + if (pyobj) { + return pyobj; + } + else { + return cval->GetProxy(); + } +} + +// Just slice it into a python list... +PyObject *EXP_BaseListValue::buffer_slice(EXP_BaseListValue *list, Py_ssize_t start, Py_ssize_t stop) +{ + PyObject *newlist = PyList_New(stop - start); + if (!newlist) { + return nullptr; + } + + for (Py_ssize_t i = start, j = 0; i < stop; i++, j++) { + PyObject *pyobj = list->GetValue(i)->ConvertValueToPython(); + if (!pyobj) { + pyobj = list->GetValue(i)->GetProxy(); + } + PyList_SET_ITEM(newlist, j, pyobj); + } + return newlist; +} + + +PyObject *EXP_BaseListValue::mapping_subscript(PyObject *self, PyObject *key) +{ + EXP_BaseListValue *list = static_cast(EXP_PROXY_REF(self)); + if (list == nullptr) { + PyErr_SetString(PyExc_SystemError, "value = list[i], " EXP_PROXY_ERROR_MSG); + return nullptr; + } + + if (PyUnicode_Check(key)) { + EXP_Value *item = list->FindValue(_PyUnicode_AsString(key)); + if (item) { + PyObject *pyobj = item->ConvertValueToPython(); + if (pyobj) { + return pyobj; + } + else { + return item->GetProxy(); + } + } + } + else if (PyIndex_Check(key)) { + Py_ssize_t index = PyLong_AsSsize_t(key); + return buffer_item(self, index); // Wont add a ref. + } + else if (PySlice_Check(key)) { + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx(key, list->GetCount(), &start, &stop, &step, &slicelength) < 0) { + return nullptr; + } + + if (slicelength <= 0) { + return PyList_New(0); + } + else if (step == 1) { + return buffer_slice(list, start, stop); + } + else { + PyErr_SetString(PyExc_TypeError, "list[slice]: slice steps not supported"); + return nullptr; + } + } + + PyErr_Format(PyExc_KeyError, "list[key]: '%R' key not in list", key); + return nullptr; +} + +// clist + list, return a list that python owns. +PyObject *EXP_BaseListValue::buffer_concat(PyObject *self, PyObject *other) +{ + EXP_BaseListValue *listval = static_cast(EXP_PROXY_REF(self)); + + if (listval == nullptr) { + PyErr_SetString(PyExc_SystemError, "list+other, " EXP_PROXY_ERROR_MSG); + return nullptr; + } + + Py_ssize_t numitems_orig = listval->GetCount(); + + /* For now, we support EXP_BaseListValue concatenated with items + * and EXP_BaseListValue concatenated to Python Lists + * and EXP_BaseListValue concatenated with another EXP_BaseListValue. + */ + + // Shallow copy, don't use listval->GetReplica(), it will screw up with KX_GameObjects. + EXP_ListValue *listval_new = new EXP_ListValue(); + + if (PyList_Check(other)) { + Py_ssize_t numitems = PyList_GET_SIZE(other); + + // Copy the first part of the list. + listval_new->Resize(numitems_orig + numitems); + for (Py_ssize_t i = 0; i < numitems_orig; i++) { + listval_new->SetValue(i, listval->GetValue(i)->AddRef()); + } + + for (Py_ssize_t i = 0; i < numitems; i++) { + EXP_Value *listitemval = listval->ConvertPythonToValue(PyList_GET_ITEM(other, i), true, "list + pyList: EXP_BaseListValue, "); + + if (listitemval) { + listval_new->SetValue(i + numitems_orig, listitemval); + } + else { + listval_new->Resize(numitems_orig + i); // Resize so we don't try release nullptr pointers. + listval_new->Release(); + return nullptr; // ConvertPythonToValue above sets the error. + } + } + } + else if (PyObject_TypeCheck(other, &EXP_BaseListValue::Type)) { + // Add items from otherlist to this list. + EXP_BaseListValue *otherval = static_cast(EXP_PROXY_REF(other)); + if (otherval == nullptr) { + listval_new->Release(); + PyErr_SetString(PyExc_SystemError, "list+other, " EXP_PROXY_ERROR_MSG); + return nullptr; + } + + Py_ssize_t numitems = otherval->GetCount(); + + // Copy the first part of the list. + listval_new->Resize(numitems_orig + numitems); // Resize so we don't try release nullptr pointers. + for (Py_ssize_t i = 0; i < numitems_orig; i++) { + listval_new->SetValue(i, listval->GetValue(i)->AddRef()); + } + + // Now copy the other part of the list. + for (Py_ssize_t i = 0; i < numitems; i++) { + listval_new->SetValue(i + numitems_orig, otherval->GetValue(i)->AddRef()); + } + + } + return listval_new->NewProxy(true); // Python owns this list. +} + +int EXP_BaseListValue::buffer_contains(PyObject *self_v, PyObject *value) +{ + EXP_BaseListValue *self = static_cast(EXP_PROXY_REF(self_v)); + + if (self == nullptr) { + PyErr_SetString(PyExc_SystemError, "val in list, " EXP_PROXY_ERROR_MSG); + return -1; + } + + if (PyUnicode_Check(value)) { + if (self->FindValue(_PyUnicode_AsString(value))) { + return 1; + } + } + // Not dict like at all but this worked before __contains__ was used. + else if (PyObject_TypeCheck(value, &EXP_Value::Type)) { + EXP_Value *item = static_cast(EXP_PROXY_REF(value)); + for (int i = 0; i < self->GetCount(); i++) { + if (self->GetValue(i) == item) { + return 1; + } + } + } + + return 0; +} + +PySequenceMethods EXP_BaseListValue::as_sequence = { + bufferlen, //(inquiry)buffer_length, /*sq_length*/ + buffer_concat, /*sq_concat*/ + nullptr, /*sq_repeat*/ + buffer_item, /*sq_item*/ +// TODO, slicing in py3 + nullptr, // buffer_slice, /*sq_slice*/ + nullptr, /*sq_ass_item*/ + nullptr, /*sq_ass_slice*/ + (objobjproc)buffer_contains, /* sq_contains */ + (binaryfunc)nullptr, /* sq_inplace_concat */ + (ssizeargfunc)nullptr, /* sq_inplace_repeat */ +}; + +// Is this one used ? +PyMappingMethods EXP_BaseListValue::instance_as_mapping = { + bufferlen, /*mp_length*/ + mapping_subscript, /*mp_subscript*/ + nullptr /*mp_ass_subscript*/ +}; + +PyTypeObject EXP_BaseListValue::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "EXP_ListValue", /*tp_name*/ + sizeof(EXP_PyObjectPlus_Proxy), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + py_base_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + py_base_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + &as_sequence, /*tp_as_sequence*/ + &instance_as_mapping, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call */ + 0, + nullptr, + nullptr, + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &EXP_Value::Type, + 0, 0, 0, 0, 0, 0, + py_base_new +}; + +PyMethodDef EXP_BaseListValue::Methods[] = { + // List style access. + {"append", (PyCFunction)EXP_BaseListValue::sPyappend, METH_O}, + {"reverse", (PyCFunction)EXP_BaseListValue::sPyreverse, METH_NOARGS}, + {"index", (PyCFunction)EXP_BaseListValue::sPyindex, METH_O}, + {"count", (PyCFunction)EXP_BaseListValue::sPycount, METH_O}, + + // Dict style access. + {"get", (PyCFunction)EXP_BaseListValue::sPyget, METH_VARARGS}, + {"filter", (PyCFunction)EXP_BaseListValue::sPyfilter, METH_VARARGS}, + + // Own cvalue funcs. + {"from_id", (PyCFunction)EXP_BaseListValue::sPyfrom_id, METH_O}, + + {nullptr, nullptr} // Sentinel +}; + +PyAttributeDef EXP_BaseListValue::Attributes[] = { + EXP_PYATTRIBUTE_NULL // Sentinel +}; + +PyObject *EXP_BaseListValue::Pyappend(PyObject *value) +{ + EXP_Value *objval = ConvertPythonToValue(value, true, "list.append(i): EXP_ValueList, "); + + if (!objval) { + // ConvertPythonToValue sets the error. + return nullptr; + } + + if (!EXP_PROXY_PYOWNS(m_proxy)) { + PyErr_SetString(PyExc_TypeError, "list.append(i): internal values can't be modified"); + return nullptr; + } + + Add(objval); + + Py_RETURN_NONE; +} + +PyObject *EXP_BaseListValue::Pyreverse() +{ + if (!EXP_PROXY_PYOWNS(m_proxy)) { + PyErr_SetString(PyExc_TypeError, "list.reverse(): internal values can't be modified"); + return nullptr; + } + + std::reverse(m_valueArray.begin(), m_valueArray.end()); + Py_RETURN_NONE; +} + +PyObject *EXP_BaseListValue::Pyindex(PyObject *value) +{ + PyObject *result = nullptr; + + EXP_Value *checkobj = ConvertPythonToValue(value, true, "val = list[i]: EXP_ValueList, "); + if (checkobj == nullptr) { + // ConvertPythonToValue sets the error. + return nullptr; + } + int numelem = GetCount(); + for (int i = 0; i < numelem; i++) { + EXP_Value *elem = GetValue(i); + if (checkobj == elem || CheckEqual(checkobj, elem)) { + result = PyLong_FromLong(i); + break; + } + } + checkobj->Release(); + + if (result == nullptr) { + PyErr_SetString(PyExc_ValueError, "list.index(x): x not in EXP_BaseListValue"); + } + return result; +} + +PyObject *EXP_BaseListValue::Pycount(PyObject *value) +{ + int numfound = 0; + + EXP_Value *checkobj = ConvertPythonToValue(value, false, ""); // Error ignored. + + // in this case just return that there are no items in the list. + if (checkobj == nullptr) { + PyErr_Clear(); + return PyLong_FromLong(0); + } + + int numelem = GetCount(); + for (int i = 0; i < numelem; i++) { + EXP_Value *elem = GetValue(i); + if (checkobj == elem || CheckEqual(checkobj, elem)) { + numfound++; + } + } + checkobj->Release(); + + return PyLong_FromLong(numfound); +} + +// Matches python dict.get(key, [default]). +PyObject *EXP_BaseListValue::Pyget(PyObject *args) +{ + char *key; + PyObject *def = Py_None; + + if (!PyArg_ParseTuple(args, "s|O:get", &key, &def)) { + return nullptr; + } + + EXP_Value *item = FindValue(key); + if (item) { + PyObject *pyobj = item->ConvertValueToPython(); + if (pyobj) { + return pyobj; + } + else { + return item->GetProxy(); + } + } + + Py_INCREF(def); + return def; +} + +PyObject *EXP_BaseListValue::Pyfilter(PyObject *args) +{ + const char *namestr = ""; + const char *propstr = ""; + + if (!PyArg_ParseTuple(args, "s|s:filter", &namestr, &propstr)) { + return nullptr; + } + + if (strlen(namestr) == 0 && strlen(propstr) == 0) { + PyErr_SetString(PyExc_ValueError, "list.filter(name, prop): empty expressions."); + return nullptr; + } + + std::regex namereg; + std::regex propreg; + try { + namereg = std::regex(namestr); + propreg = std::regex(propstr); + } + catch (const std::regex_error& error) { + PyErr_Format(PyExc_ValueError, "list.filter(name, prop): invalid expression: %s.", error.what()); + return nullptr; + } + + EXP_ListValue *result = new EXP_ListValue(); + result->SetReleaseOnDestruct(false); + + for (EXP_Value *item : m_valueArray) { + if (strlen(namestr) == 0 || std::regex_match(item->GetName(), namereg)) { + if (strlen(propstr) == 0) { + result->Add(item); + } + else { + const std::vector propnames = item->GetPropertyNames(); + for (const std::string& propname : propnames) { + if (std::regex_match(propname, propreg)) { + result->Add(item); + break; + } + } + } + } + } + + return result->NewProxy(true); +} + +PyObject *EXP_BaseListValue::Pyfrom_id(PyObject *value) +{ + uintptr_t id = (uintptr_t)PyLong_AsVoidPtr(value); + + if (PyErr_Occurred()) { + return nullptr; + } + + int numelem = GetCount(); + for (int i = 0; i < numelem; i++) { + if (reinterpret_cast(m_valueArray[i]->m_proxy) == id) { + return GetValue(i)->GetProxy(); + } + } + + PyErr_SetString(PyExc_IndexError, "from_id(#): id not found in EXP_ValueList"); + return nullptr; +} + +#endif // WITH_PYTHON diff --git a/source/gameengine/Expressions/intern/BaseListWrapper.cpp b/source/gameengine/Expressions/intern/BaseListWrapper.cpp new file mode 100644 index 000000000000..59f8a2a0931f --- /dev/null +++ b/source/gameengine/Expressions/intern/BaseListWrapper.cpp @@ -0,0 +1,414 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Porteries Tristan. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ListWrapper.cpp + * \ingroup expressions + */ + +#ifdef WITH_PYTHON + +#include "EXP_BaseListWrapper.h" + +EXP_BaseListWrapper::EXP_BaseListWrapper(EXP_PyObjectPlus *client, + GetSizeFunction getSize, GetItemFunction getItem, + GetItemNameFunction getItemName, SetItemFunction setItem, Flag flag) + :m_client(client), + m_weakRef(nullptr), + m_getSize(getSize), + m_getItem(getItem), + m_getItemName(getItemName), + m_setItem(setItem), + m_flag(flag) +{ + if (!(m_flag & FLAG_NO_WEAK_REF)) { + PyObject *proxy = client->GetProxy(); + m_weakRef = PyWeakref_NewRef(proxy, nullptr); + Py_DECREF(proxy); + } +} + +EXP_BaseListWrapper::~EXP_BaseListWrapper() +{ + Py_XDECREF(m_weakRef); +} + +bool EXP_BaseListWrapper::CheckValid(EXP_BaseListWrapper *list) +{ + if (!list) { + return false; + } + + if (list->m_flag & FLAG_NO_WEAK_REF) { + return true; + } + + PyObject *proxy = PyWeakref_GET_OBJECT(list->m_weakRef); + if (proxy == Py_None) { + return false; + } + + EXP_PyObjectPlus *ref = EXP_PROXY_REF(proxy); + if (!ref) { + return false; + } + + BLI_assert(ref == list->m_client); + + return true; +} + +unsigned int EXP_BaseListWrapper::GetSize() const +{ + return (*m_getSize)(m_client); +} + +PyObject *EXP_BaseListWrapper::GetItem(int index) const +{ + return (*m_getItem)(m_client, index); +} + +std::string EXP_BaseListWrapper::GetItemName(int index) const +{ + return (*m_getItemName)(m_client, index); +} + +bool EXP_BaseListWrapper::SetItem(int index, PyObject *item) +{ + return (*m_setItem)(m_client, index, item); +} + +bool EXP_BaseListWrapper::AllowSetItem() const +{ + return m_setItem != nullptr; +} + +bool EXP_BaseListWrapper::AllowGetItemByName() const +{ + return m_getItemName != nullptr; +} + +bool EXP_BaseListWrapper::AllowFindValue() const +{ + return (m_flag & FLAG_FIND_VALUE); +} + +std::string EXP_BaseListWrapper::GetName() +{ + return "ListWrapper"; +} + +std::string EXP_BaseListWrapper::GetText() +{ + std::string strListRep = "["; + std::string commastr = ""; + + for (unsigned int i = 0, size = GetSize(); i < size; ++i) { + strListRep += commastr; + strListRep += _PyUnicode_AsString(PyObject_Repr(GetItem(i))); + commastr = ", "; + } + strListRep += "]"; + + return strListRep; +} + +int EXP_BaseListWrapper::GetValueType() +{ + return -1; +} + +Py_ssize_t EXP_BaseListWrapper::py_len(PyObject *self) +{ + EXP_BaseListWrapper *list = (EXP_BaseListWrapper *)EXP_PROXY_REF(self); + // Invalid list. + if (!CheckValid(list)) { + PyErr_SetString(PyExc_SystemError, "len(EXP_BaseListWrapper), " EXP_PROXY_ERROR_MSG); + return 0; + } + + return (Py_ssize_t)list->GetSize(); +} + +PyObject *EXP_BaseListWrapper::py_get_item(PyObject *self, Py_ssize_t index) +{ + EXP_BaseListWrapper *list = (EXP_BaseListWrapper *)EXP_PROXY_REF(self); + // Invalid list. + if (!CheckValid(list)) { + PyErr_SetString(PyExc_SystemError, "val = EXP_BaseListWrapper[i], " EXP_PROXY_ERROR_MSG); + return nullptr; + } + + int size = list->GetSize(); + + if (index < 0) { + index = size + index; + } + if (index < 0 || index >= size) { + PyErr_SetString(PyExc_IndexError, "EXP_BaseListWrapper[i]: List index out of range in EXP_BaseListWrapper"); + return nullptr; + } + + PyObject *pyobj = list->GetItem(index); + + return pyobj; +} + +int EXP_BaseListWrapper::py_set_item(PyObject *self, Py_ssize_t index, PyObject *value) +{ + EXP_BaseListWrapper *list = (EXP_BaseListWrapper *)EXP_PROXY_REF(self); + // Invalid list. + if (!CheckValid(list)) { + PyErr_SetString(PyExc_SystemError, "EXP_BaseListWrapper[i] = val, " EXP_PROXY_ERROR_MSG); + return -1; + } + + if (!list->AllowSetItem()) { + PyErr_SetString(PyExc_TypeError, "EXP_BaseListWrapper's item type doesn't support assignment"); + return -1; + } + + if (!value) { + PyErr_SetString(PyExc_TypeError, "EXP_BaseListWrapper doesn't support item deletion"); + return -1; + } + + int size = list->GetSize(); + + if (index < 0) { + index = size + index; + } + if (index < 0 || index >= size) { + PyErr_SetString(PyExc_IndexError, "EXP_BaseListWrapper[i]: List index out of range in EXP_BaseListWrapper"); + return -1; + } + + if (!list->SetItem(index, value)) { + return -1; + } + return 0; +} + +PyObject *EXP_BaseListWrapper::py_mapping_subscript(PyObject *self, PyObject *key) +{ + EXP_BaseListWrapper *list = (EXP_BaseListWrapper *)EXP_PROXY_REF(self); + // Invalid list. + if (!CheckValid(list)) { + PyErr_SetString(PyExc_SystemError, "val = EXP_BaseListWrapper[key], " EXP_PROXY_ERROR_MSG); + return nullptr; + } + + if (PyIndex_Check(key)) { + Py_ssize_t index = PyLong_AsSsize_t(key); + return py_get_item(self, index); + } + else if (PyUnicode_Check(key)) { + if (!list->AllowGetItemByName()) { + PyErr_SetString(PyExc_SystemError, "EXP_BaseListWrapper's item type doesn't support access by key"); + return nullptr; + } + + const char *name = _PyUnicode_AsString(key); + int size = list->GetSize(); + + for (unsigned int i = 0; i < size; ++i) { + if (list->GetItemName(i) == name) { + return list->GetItem(i); + } + } + + PyErr_Format(PyExc_KeyError, "requested item \"%s\" does not exist", name); + return nullptr; + } + + PyErr_Format(PyExc_KeyError, "EXP_BaseListWrapper[key]: '%R' key not in list", key); + return nullptr; +} + +int EXP_BaseListWrapper::py_mapping_ass_subscript(PyObject *self, PyObject *key, PyObject *value) +{ + EXP_BaseListWrapper *list = (EXP_BaseListWrapper *)EXP_PROXY_REF(self); + // Invalid list. + if (!CheckValid(list)) { + PyErr_SetString(PyExc_SystemError, "val = EXP_BaseListWrapper[key], " EXP_PROXY_ERROR_MSG); + return -1; + } + + if (!list->AllowSetItem()) { + PyErr_SetString(PyExc_TypeError, "EXP_BaseListWrapper's item type doesn't support assignment"); + return -1; + } + + if (PyIndex_Check(key)) { + Py_ssize_t index = PyLong_AsSsize_t(key); + return py_set_item(self, index, value); + } + else if (PyUnicode_Check(key)) { + if (!list->AllowGetItemByName()) { + PyErr_SetString(PyExc_SystemError, "EXP_BaseListWrapper's item type doesn't support access by key"); + return -1; + } + + const char *name = _PyUnicode_AsString(key); + int size = list->GetSize(); + + for (unsigned int i = 0; i < size; ++i) { + if (list->GetItemName(i) == name) { + if (!list->SetItem(i, value)) { + return -1; + } + return 0; + } + } + + PyErr_Format(PyExc_KeyError, "requested item \"%s\" does not exist", name); + return -1; + } + + PyErr_Format(PyExc_KeyError, "EXP_BaseListWrapper[key]: '%R' key not in list", key); + return -1; +} + +int EXP_BaseListWrapper::py_contains(PyObject *self, PyObject *key) +{ + EXP_BaseListWrapper *list = (EXP_BaseListWrapper *)EXP_PROXY_REF(self); + // Invalid list. + if (!CheckValid(list)) { + PyErr_SetString(PyExc_SystemError, "val = EXP_BaseListWrapper[i], " EXP_PROXY_ERROR_MSG); + return -1; + } + + if (PyUnicode_Check(key)) { + if (!list->AllowGetItemByName()) { + PyErr_SetString(PyExc_SystemError, "EXP_BaseListWrapper's item type doesn't support access by key"); + return -1; + } + + const char *name = _PyUnicode_AsString(key); + + for (unsigned int i = 0, size = list->GetSize(); i < size; ++i) { + if (list->GetItemName(i) == name) { + return 1; + } + } + } + + if (list->AllowFindValue()) { + for (unsigned int i = 0, size = list->GetSize(); i < size; ++i) { + if (PyObject_RichCompareBool(list->GetItem(i), key, Py_EQ) == 1) { + return 1; + } + } + } + + return 0; +} + +PySequenceMethods EXP_BaseListWrapper::py_as_sequence = { + py_len, // sq_length + nullptr, // sq_concat + nullptr, // sq_repeat + py_get_item, // sq_item + nullptr, // sq_slice + py_set_item, // sq_ass_item + nullptr, // sq_ass_slice + (objobjproc)py_contains, // sq_contains + (binaryfunc)nullptr, // sq_inplace_concat + (ssizeargfunc)nullptr, // sq_inplace_repeat +}; + +PyMappingMethods EXP_BaseListWrapper::py_as_mapping = { + py_len, // mp_length + py_mapping_subscript, // mp_subscript + py_mapping_ass_subscript // mp_ass_subscript +}; + +PyTypeObject EXP_BaseListWrapper::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "EXP_ListWrapper", // tp_name + sizeof(EXP_PyObjectPlus_Proxy), // tp_basicsize + 0, // tp_itemsize + py_base_dealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + py_base_repr, // tp_repr + 0, // tp_as_number + &py_as_sequence, // tp_as_sequence + &py_as_mapping, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, + nullptr, + nullptr, + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &EXP_Value::Type, + 0, 0, 0, 0, 0, 0, + py_base_new +}; + +PyMethodDef EXP_BaseListWrapper::Methods[] = { + {"get", (PyCFunction)EXP_BaseListWrapper::sPyGet, METH_VARARGS}, + {nullptr, nullptr} // Sentinel +}; + +PyAttributeDef EXP_BaseListWrapper::Attributes[] = { + EXP_PYATTRIBUTE_NULL // Sentinel +}; + +// Matches python dict.get(key, [default]). +PyObject *EXP_BaseListWrapper::PyGet(PyObject *args) +{ + char *name; + PyObject *def = Py_None; + + // Invalid list. + if (!CheckValid(this)) { + PyErr_SetString(PyExc_SystemError, "val = EXP_BaseListWrapper[i], " EXP_PROXY_ERROR_MSG); + return nullptr; + } + + if (!AllowGetItemByName()) { + PyErr_SetString(PyExc_SystemError, "EXP_BaseListWrapper's item type doesn't support access by key"); + return nullptr; + } + + if (!PyArg_ParseTuple(args, "s|O:get", &name, &def)) { + return nullptr; + } + + for (unsigned int i = 0; i < GetSize(); ++i) { + if (GetItemName(i) == name) { + return GetItem(i); + } + } + + Py_INCREF(def); + return def; +} + +#endif // WITH_PYTHON diff --git a/source/gameengine/Expressions/intern/BoolValue.cpp b/source/gameengine/Expressions/intern/BoolValue.cpp index 6d29a07aada4..8fe3b1e8c8bc 100644 --- a/source/gameengine/Expressions/intern/BoolValue.cpp +++ b/source/gameengine/Expressions/intern/BoolValue.cpp @@ -2,7 +2,7 @@ * \ingroup expressions */ -// BoolValue.cpp: implementation of the CBoolValue class. +// BoolValue.cpp: implementation of the EXP_BoolValue class. /* * Copyright (c) 1996-2000 Erwin Coumans * @@ -19,73 +19,46 @@ #include "EXP_BoolValue.h" #include "EXP_StringValue.h" #include "EXP_ErrorValue.h" -#include "EXP_VoidValue.h" -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// +const std::string EXP_BoolValue::sTrueString = "TRUE"; +const std::string EXP_BoolValue::sFalseString = "FALSE"; -const STR_String CBoolValue::sTrueString = "TRUE"; -const STR_String CBoolValue::sFalseString = "FALSE"; - -CBoolValue::CBoolValue() -/* - * pre: false - * effect: constructs a new CBoolValue - */ +EXP_BoolValue::EXP_BoolValue() { trace("Bool constructor error"); } - - -CBoolValue::CBoolValue(bool inBool) -: m_bool(inBool) +EXP_BoolValue::EXP_BoolValue(bool inBool) + :m_bool(inBool) { -} // Constructs a new CBoolValue containing - - +} -CBoolValue::CBoolValue(bool innie,const char *name,AllocationTYPE alloctype) +EXP_BoolValue::EXP_BoolValue(bool innie, const std::string& name) + :m_bool(innie) { - m_bool = innie; SetName(name); - - if (alloctype == CValue::STACKVALUE) - CValue::DisableRefCount(); } - - -void CBoolValue::SetValue(CValue* newval) +void EXP_BoolValue::SetValue(EXP_Value *newval) { m_bool = (newval->GetNumber() != 0); - SetModified(true); } - - -CValue* CBoolValue::Calc(VALUE_OPERATOR op, CValue *val) -/* -pre: -ret: a new object containing the result of applying operator op to this -object and val -*/ +EXP_Value *EXP_BoolValue::Calc(VALUE_OPERATOR op, EXP_Value *val) { - switch (op) - { - case VALUE_POS_OPERATOR: - case VALUE_NEG_OPERATOR: + switch (op) { + case VALUE_POS_OPERATOR: + case VALUE_NEG_OPERATOR: { - return new CErrorValue (op2str(op) + GetText()); + return new EXP_ErrorValue(op2str(op) + GetText()); break; } - case VALUE_NOT_OPERATOR: + case VALUE_NOT_OPERATOR: { - return new CBoolValue (!m_bool); + return new EXP_BoolValue(!m_bool); break; } - default: + default: { return val->CalcFinal(VALUE_BOOL_TYPE, op, this); break; @@ -93,16 +66,9 @@ object and val } } - - -CValue* CBoolValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val) -/* -pre: the type of val is dtype -ret: a new object containing the result of applying operator op to val and -this object -*/ +EXP_Value *EXP_BoolValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, EXP_Value *val) { - CValue *ret; + EXP_Value *ret; switch (dtype) { case VALUE_EMPTY_TYPE: @@ -111,33 +77,33 @@ this object switch (op) { case VALUE_AND_OPERATOR: { - ret = new CBoolValue (((CBoolValue *) val)->GetBool() && m_bool); + ret = new EXP_BoolValue(((EXP_BoolValue *)val)->GetBool() && m_bool); break; } case VALUE_OR_OPERATOR: { - ret = new CBoolValue (((CBoolValue *) val)->GetBool() || m_bool); + ret = new EXP_BoolValue(((EXP_BoolValue *)val)->GetBool() || m_bool); break; } case VALUE_EQL_OPERATOR: { - ret = new CBoolValue (((CBoolValue *) val)->GetBool() == m_bool); + ret = new EXP_BoolValue(((EXP_BoolValue *)val)->GetBool() == m_bool); break; } case VALUE_NEQ_OPERATOR: { - ret = new CBoolValue (((CBoolValue *) val)->GetBool() != m_bool); + ret = new EXP_BoolValue(((EXP_BoolValue *)val)->GetBool() != m_bool); break; } case VALUE_NOT_OPERATOR: { - return new CBoolValue (!m_bool); + return new EXP_BoolValue(!m_bool); break; } default: { - ret = new CErrorValue(val->GetText() + op2str(op) + - "[operator not allowed on booleans]"); + ret = new EXP_ErrorValue(val->GetText() + op2str(op) + + "[operator not allowed on booleans]"); break; } } @@ -148,69 +114,55 @@ this object switch (op) { case VALUE_ADD_OPERATOR: { - ret = new CStringValue(val->GetText() + GetText(),""); + ret = new EXP_StringValue(val->GetText() + GetText(), ""); break; } default: { - ret = new CErrorValue(val->GetText() + op2str(op) + "[Only + allowed on boolean and string]"); + ret = new EXP_ErrorValue(val->GetText() + op2str(op) + "[Only + allowed on boolean and string]"); break; } } break; } default: - ret = new CErrorValue("[type mismatch]" + op2str(op) + GetText()); + ret = new EXP_ErrorValue("[type mismatch]" + op2str(op) + GetText()); } return ret; } - - -bool CBoolValue::GetBool() -/* -pre: -ret: the bool stored in the object -*/ +bool EXP_BoolValue::GetBool() { return m_bool; } - - -double CBoolValue::GetNumber() +double EXP_BoolValue::GetNumber() { return (double)m_bool; } - - -int CBoolValue::GetValueType() +int EXP_BoolValue::GetValueType() { return VALUE_BOOL_TYPE; } - - -const STR_String& CBoolValue::GetText() +std::string EXP_BoolValue::GetText() { return m_bool ? sTrueString : sFalseString; } - - -CValue* CBoolValue::GetReplica() +EXP_Value *EXP_BoolValue::GetReplica() { - CBoolValue* replica = new CBoolValue(*this); + EXP_BoolValue *replica = new EXP_BoolValue(*this); replica->ProcessReplica(); return replica; } #ifdef WITH_PYTHON -PyObject *CBoolValue::ConvertValueToPython() +PyObject *EXP_BoolValue::ConvertValueToPython() { return PyBool_FromLong(m_bool != 0); } -#endif // WITH_PYTHON +#endif // WITH_PYTHON diff --git a/source/gameengine/Expressions/intern/ConstExpr.cpp b/source/gameengine/Expressions/intern/ConstExpr.cpp index f7853d2dfac4..1c70ad4afe1f 100644 --- a/source/gameengine/Expressions/intern/ConstExpr.cpp +++ b/source/gameengine/Expressions/intern/ConstExpr.cpp @@ -1,7 +1,7 @@ /** \file gameengine/Expressions/ConstExpr.cpp * \ingroup expressions */ -// ConstExpr.cpp: implementation of the CConstExpr class. +// ConstExpr.cpp: implementation of the EXP_ConstExpr class. /* * Copyright (c) 1996-2000 Erwin Coumans @@ -16,116 +16,36 @@ * */ -#include "EXP_Value.h" // for precompiled header +#include "EXP_Value.h" #include "EXP_ConstExpr.h" -#include "EXP_VectorValue.h" -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CConstExpr::CConstExpr() +EXP_ConstExpr::EXP_ConstExpr() { } - - -CConstExpr::CConstExpr(CValue* constval) -/* -pre: -effect: constructs a CConstExpr cointing the value constval -*/ +EXP_ConstExpr::EXP_ConstExpr(EXP_Value *constval) { m_value = constval; -// m_bModified=true; } - - -CConstExpr::~CConstExpr() -/* -pre: -effect: deletes the object -*/ +EXP_ConstExpr::~EXP_ConstExpr() { - if (m_value) + if (m_value) { m_value->Release(); + } } - - -unsigned char CConstExpr::GetExpressionID() +unsigned char EXP_ConstExpr::GetExpressionID() { return CCONSTEXPRESSIONID; } - - -CValue* CConstExpr::Calculate() -/* -pre: -ret: a new object containing the value of the stored CValue -*/ +EXP_Value *EXP_ConstExpr::Calculate() { return m_value->AddRef(); } - - -void CConstExpr::ClearModified() -{ - if (m_value) - { - m_value->SetModified(false); - m_value->SetAffected(false); - } -} - - - -double CConstExpr::GetNumber() -{ - return -1; -} - - - -bool CConstExpr::NeedsRecalculated() -{ - return m_value->IsAffected(); // IsAffected is m_bModified OR m_bAffected !!! -} - - - -CExpression* CConstExpr::CheckLink(std::vector& brokenlinks) -{ -// parent checks if child is still useful. -// When for example it's value it's deleted flag set -// then release Value, and return NULL in case of constexpression -// else return this... - - assertd(m_value); - if (m_value->IsReleaseRequested()) - { - AddRef(); //numchanges++; - return Release(); - } - else - return this; -} - - - -void CConstExpr::BroadcastOperators(VALUE_OPERATOR op) -{ - assertd(m_value); - m_value->SetColorOperator(op); -} - - - -bool CConstExpr::MergeExpression(CExpression *otherexpr) +double EXP_ConstExpr::GetNumber() { - assertd(false); - return false; + return -1.0; } diff --git a/source/gameengine/Expressions/intern/EmptyValue.cpp b/source/gameengine/Expressions/intern/EmptyValue.cpp index da02515fd812..d9c5700536c7 100644 --- a/source/gameengine/Expressions/intern/EmptyValue.cpp +++ b/source/gameengine/Expressions/intern/EmptyValue.cpp @@ -2,7 +2,7 @@ * \ingroup expressions */ -// EmptyValue.cpp: implementation of the CEmptyValue class. +// EmptyValue.cpp: implementation of the EXP_EmptyValue class. /* * Copyright (c) 1996-2000 Erwin Coumans * @@ -17,116 +17,44 @@ */ #include "EXP_EmptyValue.h" -#include "EXP_IntValue.h" -#include "EXP_FloatValue.h" -#include "EXP_StringValue.h" -#include "EXP_ErrorValue.h" -#include "EXP_ListValue.h" -#include "EXP_VoidValue.h" -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CEmptyValue::CEmptyValue() -/* - * pre: - * effect: constructs a new CEmptyValue - */ +EXP_EmptyValue::EXP_EmptyValue() { - SetModified(false); } - - -CEmptyValue::~CEmptyValue() -/* - * pre: - * effect: deletes the object - */ +EXP_EmptyValue::~EXP_EmptyValue() { - } - - -CValue *CEmptyValue::Calc(VALUE_OPERATOR op, CValue *val) -/* - * pre: - * ret: a new object containing the result of applying operator op to this - * object and val - */ +EXP_Value *EXP_EmptyValue::Calc(VALUE_OPERATOR op, EXP_Value *val) { return val->CalcFinal(VALUE_EMPTY_TYPE, op, this); - } - - -CValue * CEmptyValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val) -/* - * pre: the type of val is dtype - * ret: a new object containing the result of applying operator op to val and - * this object - */ +EXP_Value *EXP_EmptyValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, EXP_Value *val) { return val->AddRef(); } - - -double CEmptyValue::GetNumber() +double EXP_EmptyValue::GetNumber() { - return 0; + return 0.0; } - - -int CEmptyValue::GetValueType() +int EXP_EmptyValue::GetValueType() { return VALUE_EMPTY_TYPE; } - - -CListValue* CEmptyValue::GetPolySoup() +std::string EXP_EmptyValue::GetText() { - CListValue* soup = new CListValue(); - //don't add any poly, while it's an empty value - return soup; + return ""; } - - -bool CEmptyValue::IsInside(CValue* testpoint,bool bBorderInclude) +EXP_Value *EXP_EmptyValue::GetReplica() { - // empty space is solid, so always inside - return true; -} - - - -double* CEmptyValue::GetVector3(bool bGetTransformedVec) -{ - assertd(false); // don't get vector from me - return ZeroVector(); -} - - - -static STR_String emptyString = STR_String(""); - - -const STR_String & CEmptyValue::GetText() -{ - return emptyString; -} - - - -CValue* CEmptyValue::GetReplica() -{ - CEmptyValue* replica = new CEmptyValue(*this); + EXP_EmptyValue *replica = new EXP_EmptyValue(*this); replica->ProcessReplica(); return replica; } + diff --git a/source/gameengine/Expressions/intern/ErrorValue.cpp b/source/gameengine/Expressions/intern/ErrorValue.cpp index 502608a6dcf7..f4d0a57ae7ae 100644 --- a/source/gameengine/Expressions/intern/ErrorValue.cpp +++ b/source/gameengine/Expressions/intern/ErrorValue.cpp @@ -1,7 +1,7 @@ /** \file gameengine/Expressions/ErrorValue.cpp * \ingroup expressions */ -// ErrorValue.cpp: implementation of the CErrorValue class. +// ErrorValue.cpp: implementation of the EXP_ErrorValue class. /* * Copyright (c) 1996-2000 Erwin Coumans * @@ -17,66 +17,33 @@ #include "EXP_ErrorValue.h" -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CErrorValue::CErrorValue() -/* -pre: -effect: constructs a new CErrorValue containing errormessage "Error" -*/ +EXP_ErrorValue::EXP_ErrorValue() + :m_strErrorText("Error") { - m_strErrorText = "Error"; - SetError(true); } - - -CErrorValue::CErrorValue(const char *errmsg) -/* -pre: -effect: constructs a new CErrorValue containing errormessage errmsg -*/ +EXP_ErrorValue::EXP_ErrorValue(const std::string& errmsg) + :m_strErrorText("[" + errmsg + "]") { - m_strErrorText = "["; - m_strErrorText += errmsg; - m_strErrorText += "]"; - SetError(true); } - - -CErrorValue::~CErrorValue() -/* -pre: -effect: deletes the object -*/ +EXP_ErrorValue::~EXP_ErrorValue() { - } - - -CValue* CErrorValue::Calc(VALUE_OPERATOR op, CValue *val) -/* -pre: -ret: a new object containing the result of applying operator op to this - object and val -*/ +EXP_Value *EXP_ErrorValue::Calc(VALUE_OPERATOR op, EXP_Value *val) { - CValue* errorval; + EXP_Value *errorval; - switch (op) - { - case VALUE_POS_OPERATOR: - case VALUE_NEG_OPERATOR: - case VALUE_NOT_OPERATOR: + switch (op) { + case VALUE_POS_OPERATOR: + case VALUE_NEG_OPERATOR: + case VALUE_NOT_OPERATOR: { - errorval = new CErrorValue (op2str(op) + GetText()); + errorval = new EXP_ErrorValue(op2str(op) + GetText()); break; } - default: + default: { errorval = val->CalcFinal(VALUE_ERROR_TYPE, op, this); break; @@ -86,46 +53,30 @@ ret: a new object containing the result of applying operator op to this return errorval; } - - -CValue* CErrorValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val) -/* -pre: the type of val is dtype -ret: a new object containing the result of applying operator op to val and - this object -*/ +EXP_Value *EXP_ErrorValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, EXP_Value *val) { - return new CErrorValue (val->GetText() + op2str(op) + GetText()); + return new EXP_ErrorValue(val->GetText() + op2str(op) + GetText()); } - - -double CErrorValue::GetNumber() -{ - return -1; -} - - - -int CErrorValue::GetValueType() +int EXP_ErrorValue::GetValueType() { return VALUE_ERROR_TYPE; } - - -const STR_String & CErrorValue::GetText() +std::string EXP_ErrorValue::GetText() { return m_strErrorText; } +EXP_Value *EXP_ErrorValue::GetReplica() +{ + // Who would want a copy of an error ? + BLI_assert(false && "ErrorValue::GetReplica() not implemented yet"); + return nullptr; +} -CValue* CErrorValue::GetReplica() +bool EXP_ErrorValue::IsError() const { - // who would want a copy of an error ? - trace ("Error: ErrorValue::GetReplica() not implemented yet"); - assertd(false); - - return NULL; + return true; } diff --git a/source/gameengine/Expressions/intern/Expression.cpp b/source/gameengine/Expressions/intern/Expression.cpp index c5496262f0a0..7e8e9f7d567f 100644 --- a/source/gameengine/Expressions/intern/Expression.cpp +++ b/source/gameengine/Expressions/intern/Expression.cpp @@ -1,7 +1,7 @@ /** \file gameengine/Expressions/Expression.cpp * \ingroup expressions */ -// Expression.cpp: implementation of the CExpression class. +// Expression.cpp: implementation of the EXP_Expression class. /* * Copyright (c) 1996-2000 Erwin Coumans * @@ -18,59 +18,10 @@ #include "EXP_Expression.h" #include "EXP_ErrorValue.h" -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// -#ifdef DEBUG -//int gRefCountExpr; -#endif -CExpression::CExpression()// : m_cached_calculate(NULL) +EXP_Expression::EXP_Expression() { - m_refcount = 1; -#ifdef DEBUG - //gRefCountExpr++; -#endif } -CExpression::~CExpression() +EXP_Expression::~EXP_Expression() { - assert (m_refcount == 0); -} - - - -// destuctor for CBrokenLinkInfo -CBrokenLinkInfo::~CBrokenLinkInfo() -{ - if (m_pExpr && !m_bRestored) - m_pExpr->Release(); -} - - -void CBrokenLinkInfo::RestoreLink() -{ - - - assertd(m_pExpr); - - if (m_pExpr) - { - if (!m_bRestored) { - m_bRestored=true; - - } - if (*m_pmemExpr) - { - (*m_pmemExpr)->Release(); - } - *m_pmemExpr = m_pExpr; - -// m_pExpr=NULL; - } -} - -void CBrokenLinkInfo::BreakLink() -{ - m_bRestored=false; - m_pExpr->AddRef(); } diff --git a/source/gameengine/Expressions/intern/FloatValue.cpp b/source/gameengine/Expressions/intern/FloatValue.cpp index 814d3d3b9080..5ce2d73558b6 100644 --- a/source/gameengine/Expressions/intern/FloatValue.cpp +++ b/source/gameengine/Expressions/intern/FloatValue.cpp @@ -1,7 +1,7 @@ /** \file gameengine/Expressions/FloatValue.cpp * \ingroup expressions */ -// FloatValue.cpp: implementation of the CFloatValue class. +// FloatValue.cpp: implementation of the EXP_FloatValue class. /* * Copyright (c) 1996-2000 Erwin Coumans * @@ -20,152 +20,138 @@ #include "EXP_StringValue.h" #include "EXP_BoolValue.h" #include "EXP_ErrorValue.h" -#include "EXP_VoidValue.h" -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// +#include -CFloatValue::CFloatValue() -/* -pre: false -effect: constructs a new CFloatValue -*/ +EXP_FloatValue::EXP_FloatValue() { - m_pstrRep=NULL; } - - -CFloatValue::CFloatValue(float fl) -/* -pre: -effect: constructs a new CFloatValue containing value fl -*/ +EXP_FloatValue::EXP_FloatValue(float fl) + :m_float(fl) { - m_float = fl; - m_pstrRep=NULL; } - - -CFloatValue::CFloatValue(float fl,const char *name,AllocationTYPE alloctype) -/* -pre: -effect: constructs a new CFloatValue containing value fl -*/ +EXP_FloatValue::EXP_FloatValue(float fl, const std::string& name) + :m_float(fl) { - - m_float = fl; SetName(name); - if (alloctype==CValue::STACKVALUE) - { - CValue::DisableRefCount(); - - } - m_pstrRep=NULL; } - - -CFloatValue::~CFloatValue() -/* -pre: -effect: deletes the object -*/ +EXP_FloatValue::~EXP_FloatValue() { - if (m_pstrRep) - delete m_pstrRep; } - - -CValue* CFloatValue::Calc(VALUE_OPERATOR op, CValue *val) -/* -pre: -ret: a new object containing the result of applying operator op to this - object and val -*/ +EXP_Value *EXP_FloatValue::Calc(VALUE_OPERATOR op, EXP_Value *val) { - //return val->CalcFloat(op, this); - switch (op) - { - case VALUE_POS_OPERATOR: - return new CFloatValue (m_float); - break; - case VALUE_NEG_OPERATOR: - return new CFloatValue (-m_float); - break; - case VALUE_NOT_OPERATOR: - return new CBoolValue (m_float == 0.f); - break; - case VALUE_AND_OPERATOR: - case VALUE_OR_OPERATOR: - return new CErrorValue(val->GetText() + op2str(op) + "only allowed on booleans"); - break; - default: - return val->CalcFinal(VALUE_FLOAT_TYPE, op, this); - break; + switch (op) { + case VALUE_POS_OPERATOR: + { + return new EXP_FloatValue(m_float); + break; + } + case VALUE_NEG_OPERATOR: + { + return new EXP_FloatValue(-m_float); + break; + } + case VALUE_NOT_OPERATOR: + { + return new EXP_BoolValue(m_float == 0.0f); + break; + } + case VALUE_AND_OPERATOR: + case VALUE_OR_OPERATOR: + { + return new EXP_ErrorValue(val->GetText() + op2str(op) + "only allowed on booleans"); + break; + } + default: + { + return val->CalcFinal(VALUE_FLOAT_TYPE, op, this); + break; + } } } - - -CValue* CFloatValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val) -/* -pre: the type of val is dtype -ret: a new object containing the result of applying operator op to val and - this object -*/ +EXP_Value *EXP_FloatValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, EXP_Value *val) { - CValue *ret; + EXP_Value *ret; switch (dtype) { case VALUE_INT_TYPE: { switch (op) { case VALUE_MOD_OPERATOR: - ret = new CFloatValue(fmod(((CIntValue *) val)->GetInt(), m_float)); + { + ret = new EXP_FloatValue(fmod(((EXP_IntValue *)val)->GetInt(), m_float)); break; + } case VALUE_ADD_OPERATOR: - ret = new CFloatValue(((CIntValue *) val)->GetInt() + m_float); + { + ret = new EXP_FloatValue(((EXP_IntValue *)val)->GetInt() + m_float); break; + } case VALUE_SUB_OPERATOR: - ret = new CFloatValue(((CIntValue *) val)->GetInt() - m_float); + { + ret = new EXP_FloatValue(((EXP_IntValue *)val)->GetInt() - m_float); break; + } case VALUE_MUL_OPERATOR: - ret = new CFloatValue(((CIntValue *) val)->GetInt() * m_float); + { + ret = new EXP_FloatValue(((EXP_IntValue *)val)->GetInt() * m_float); break; + } case VALUE_DIV_OPERATOR: - if (m_float == 0) - ret = new CErrorValue("Division by zero"); - else - ret = new CFloatValue (((CIntValue *) val)->GetInt() / m_float); + { + if (m_float == 0) { + ret = new EXP_ErrorValue("Division by zero"); + } + else { + ret = new EXP_FloatValue(((EXP_IntValue *)val)->GetInt() / m_float); + } break; + } case VALUE_EQL_OPERATOR: - ret = new CBoolValue(((CIntValue *) val)->GetInt() == m_float); + { + ret = new EXP_BoolValue(((EXP_IntValue *)val)->GetInt() == m_float); break; + } case VALUE_NEQ_OPERATOR: - ret = new CBoolValue(((CIntValue *) val)->GetInt() != m_float); + { + ret = new EXP_BoolValue(((EXP_IntValue *)val)->GetInt() != m_float); break; + } case VALUE_GRE_OPERATOR: - ret = new CBoolValue(((CIntValue *) val)->GetInt() > m_float); + { + ret = new EXP_BoolValue(((EXP_IntValue *)val)->GetInt() > m_float); break; + } case VALUE_LES_OPERATOR: - ret = new CBoolValue(((CIntValue *) val)->GetInt() < m_float); + { + ret = new EXP_BoolValue(((EXP_IntValue *)val)->GetInt() < m_float); break; + } case VALUE_GEQ_OPERATOR: - ret = new CBoolValue(((CIntValue *) val)->GetInt() >= m_float); + { + ret = new EXP_BoolValue(((EXP_IntValue *)val)->GetInt() >= m_float); break; + } case VALUE_LEQ_OPERATOR: - ret = new CBoolValue(((CIntValue *) val)->GetInt() <= m_float); + { + ret = new EXP_BoolValue(((EXP_IntValue *)val)->GetInt() <= m_float); break; + } case VALUE_NOT_OPERATOR: - ret = new CBoolValue(m_float == 0); + { + ret = new EXP_BoolValue(m_float == 0); break; + } default: - ret = new CErrorValue("illegal operator. please send a bug report."); + { + ret = new EXP_ErrorValue("illegal operator. please send a bug report."); break; + } } break; } @@ -174,53 +160,85 @@ ret: a new object containing the result of applying operator op to val and { switch (op) { case VALUE_MOD_OPERATOR: - ret = new CFloatValue(fmod(((CFloatValue *) val)->GetFloat(), m_float)); + { + ret = new EXP_FloatValue(fmod(((EXP_FloatValue *)val)->GetFloat(), m_float)); break; + } case VALUE_ADD_OPERATOR: - ret = new CFloatValue(((CFloatValue *) val)->GetFloat() + m_float); + { + ret = new EXP_FloatValue(((EXP_FloatValue *)val)->GetFloat() + m_float); break; + } case VALUE_SUB_OPERATOR: - ret = new CFloatValue(((CFloatValue *) val)->GetFloat() - m_float); + { + ret = new EXP_FloatValue(((EXP_FloatValue *)val)->GetFloat() - m_float); break; + } case VALUE_MUL_OPERATOR: - ret = new CFloatValue(((CFloatValue *) val)->GetFloat() * m_float); + { + ret = new EXP_FloatValue(((EXP_FloatValue *)val)->GetFloat() * m_float); break; + } case VALUE_DIV_OPERATOR: - if (m_float == 0) - ret = new CErrorValue("Division by zero"); - else - ret = new CFloatValue (((CFloatValue *) val)->GetFloat() / m_float); + { + if (m_float == 0) { + ret = new EXP_ErrorValue("Division by zero"); + } + else { + ret = new EXP_FloatValue(((EXP_FloatValue *)val)->GetFloat() / m_float); + } break; + } case VALUE_EQL_OPERATOR: - ret = new CBoolValue(((CFloatValue *) val)->GetFloat() == m_float); + { + ret = new EXP_BoolValue(((EXP_FloatValue *)val)->GetFloat() == m_float); break; + } case VALUE_NEQ_OPERATOR: - ret = new CBoolValue(((CFloatValue *) val)->GetFloat() != m_float); + { + ret = new EXP_BoolValue(((EXP_FloatValue *)val)->GetFloat() != m_float); break; + } case VALUE_GRE_OPERATOR: - ret = new CBoolValue(((CFloatValue *) val)->GetFloat() > m_float); + { + ret = new EXP_BoolValue(((EXP_FloatValue *)val)->GetFloat() > m_float); break; + } case VALUE_LES_OPERATOR: - ret = new CBoolValue(((CFloatValue *) val)->GetFloat() < m_float); + { + ret = new EXP_BoolValue(((EXP_FloatValue *)val)->GetFloat() < m_float); break; + } case VALUE_GEQ_OPERATOR: - ret = new CBoolValue(((CFloatValue *) val)->GetFloat() >= m_float); + { + ret = new EXP_BoolValue(((EXP_FloatValue *)val)->GetFloat() >= m_float); break; + } case VALUE_LEQ_OPERATOR: - ret = new CBoolValue(((CFloatValue *) val)->GetFloat() <= m_float); + { + ret = new EXP_BoolValue(((EXP_FloatValue *)val)->GetFloat() <= m_float); break; + } case VALUE_NEG_OPERATOR: - ret = new CFloatValue (-m_float); + { + ret = new EXP_FloatValue(-m_float); break; + } case VALUE_POS_OPERATOR: - ret = new CFloatValue (m_float); + { + ret = new EXP_FloatValue(m_float); break; + } case VALUE_NOT_OPERATOR: - ret = new CBoolValue(m_float == 0); + { + ret = new EXP_BoolValue(m_float == 0); break; + } default: - ret = new CErrorValue("illegal operator. please send a bug report."); + { + ret = new EXP_ErrorValue("illegal operator. please send a bug report."); break; + } } break; } @@ -228,102 +246,90 @@ ret: a new object containing the result of applying operator op to val and { switch (op) { case VALUE_ADD_OPERATOR: - ret = new CStringValue(val->GetText() + GetText(),""); + { + ret = new EXP_StringValue(val->GetText() + GetText(), ""); break; + } case VALUE_EQL_OPERATOR: case VALUE_NEQ_OPERATOR: case VALUE_GRE_OPERATOR: case VALUE_LES_OPERATOR: case VALUE_GEQ_OPERATOR: case VALUE_LEQ_OPERATOR: - ret = new CErrorValue("[Cannot compare string with float]" + op2str(op) + GetText()); + { + ret = new EXP_ErrorValue("[Cannot compare string with float]" + op2str(op) + GetText()); break; + } default: - ret = new CErrorValue("[operator not allowed on strings]" + op2str(op) + GetText()); + { + ret = new EXP_ErrorValue("[operator not allowed on strings]" + op2str(op) + GetText()); break; + } } break; } case VALUE_BOOL_TYPE: - ret = new CErrorValue("[operator not valid on boolean and float]" + op2str(op) + GetText()); + { + ret = new EXP_ErrorValue("[operator not valid on boolean and float]" + op2str(op) + GetText()); break; + } case VALUE_ERROR_TYPE: - ret = new CErrorValue(val->GetText() + op2str(op) + GetText()); + { + ret = new EXP_ErrorValue(val->GetText() + op2str(op) + GetText()); break; + } default: - ret = new CErrorValue("illegal type. contact your dealer (if any)"); + { + ret = new EXP_ErrorValue("illegal type. contact your dealer (if any)"); break; + } } return ret; } -void CFloatValue::SetFloat(float fl) +void EXP_FloatValue::SetFloat(float fl) { m_float = fl; - SetModified(true); } - - -float CFloatValue::GetFloat() -/* -pre: -ret: the float stored in the object -*/ +float EXP_FloatValue::GetFloat() { return m_float; } - - -double CFloatValue::GetNumber() +double EXP_FloatValue::GetNumber() { return m_float; } - - -int CFloatValue::GetValueType() +int EXP_FloatValue::GetValueType() { return VALUE_FLOAT_TYPE; } - - -void CFloatValue::SetValue(CValue* newval) +void EXP_FloatValue::SetValue(EXP_Value *newval) { m_float = (float)newval->GetNumber(); - SetModified(true); } - - -const STR_String & CFloatValue::GetText() +std::string EXP_FloatValue::GetText() { - if (!m_pstrRep) - m_pstrRep = new STR_String(); - - m_pstrRep->Format("%f",m_float); - return *m_pstrRep; + return std::to_string(m_float); } - - -CValue* CFloatValue::GetReplica() +EXP_Value *EXP_FloatValue::GetReplica() { - CFloatValue* replica = new CFloatValue(*this); - replica->m_pstrRep = NULL; /* should be in CFloatValue::ProcessReplica() but its not defined, no matter */ + EXP_FloatValue *replica = new EXP_FloatValue(*this); replica->ProcessReplica(); return replica; } - #ifdef WITH_PYTHON -PyObject *CFloatValue::ConvertValueToPython() +PyObject *EXP_FloatValue::ConvertValueToPython() { return PyFloat_FromDouble(m_float); } -#endif // WITH_PYTHON +#endif // WITH_PYTHON diff --git a/source/gameengine/Expressions/intern/IdentifierExpr.cpp b/source/gameengine/Expressions/intern/IdentifierExpr.cpp index 3a1342815afb..6834f6e4a56a 100644 --- a/source/gameengine/Expressions/intern/IdentifierExpr.cpp +++ b/source/gameengine/Expressions/intern/IdentifierExpr.cpp @@ -32,72 +32,35 @@ #include "EXP_IdentifierExpr.h" -CIdentifierExpr::CIdentifierExpr(const STR_String& identifier,CValue* id_context) -:m_identifier(identifier) +EXP_IdentifierExpr::EXP_IdentifierExpr(const std::string& identifier, EXP_Value *id_context) + :m_identifier(identifier) { - if (id_context) + if (id_context) { m_idContext = id_context->AddRef(); - else - m_idContext=NULL; + } + else { + m_idContext = nullptr; + } } - -CIdentifierExpr::~CIdentifierExpr() +EXP_IdentifierExpr::~EXP_IdentifierExpr() { - if (m_idContext) + if (m_idContext) { m_idContext->Release(); + } } - - -CValue* CIdentifierExpr::Calculate() +EXP_Value *EXP_IdentifierExpr::Calculate() { - CValue* result = NULL; - if (m_idContext) + EXP_Value *result = nullptr; + if (m_idContext) { result = m_idContext->FindIdentifier(m_identifier); + } return result; } - - -bool CIdentifierExpr::MergeExpression(CExpression* otherexpr) -{ - return false; -} - - - -unsigned char CIdentifierExpr::GetExpressionID() +unsigned char EXP_IdentifierExpr::GetExpressionID() { return CIDENTIFIEREXPRESSIONID; } - - - -bool CIdentifierExpr::NeedsRecalculated() -{ - return true; -} - - - -CExpression* CIdentifierExpr::CheckLink(std::vector& brokenlinks) -{ - assertd(false); // not implemented yet - return NULL; -} - - - -void CIdentifierExpr::ClearModified() -{ - assertd(false); // not implemented yet -} - - - -void CIdentifierExpr::BroadcastOperators(VALUE_OPERATOR op) -{ - assertd(false); // not implemented yet -} diff --git a/source/gameengine/Expressions/intern/IfExpr.cpp b/source/gameengine/Expressions/intern/IfExpr.cpp index 549f53749d65..a7cc3b771cb4 100644 --- a/source/gameengine/Expressions/intern/IfExpr.cpp +++ b/source/gameengine/Expressions/intern/IfExpr.cpp @@ -1,7 +1,7 @@ /** \file gameengine/Expressions/IfExpr.cpp * \ingroup expressions */ -// IfExpr.cpp: implementation of the CIfExpr class. +// IfExpr.cpp: implementation of the EXP_IfExpr class. /* * Copyright (c) 1996-2000 Erwin Coumans * @@ -20,125 +20,50 @@ #include "EXP_ErrorValue.h" #include "EXP_BoolValue.h" -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - - -CIfExpr::CIfExpr() +EXP_IfExpr::EXP_IfExpr() { } - - -/* - * pre: - * effect: constructs an CifExpr-object corresponding to IF(guard, e1, e2) - */ -CIfExpr::CIfExpr(CExpression *guard, CExpression *e1, CExpression *e2) +EXP_IfExpr::EXP_IfExpr(EXP_Expression *guard, EXP_Expression *e1, EXP_Expression *e2) + :m_guard(guard), + m_e1(e1), + m_e2(e2) { - m_guard = guard; - m_e1 = e1; - m_e2 = e2; } - - -/* - * pre: - * effect: dereferences the object - */ -CIfExpr::~CIfExpr() +EXP_IfExpr::~EXP_IfExpr() { - if (m_guard) + if (m_guard) { m_guard->Release(); + } - if (m_e1) + if (m_e1) { m_e1->Release(); + } - if (m_e2) + if (m_e2) { m_e2->Release(); + } } - - -/** - * pre: - * ret: a new object containing the value of m_e1 if m_guard is a boolean true - * a new object containing the value of m_e2 if m_guard is a boolean false - * an new errorvalue if m_guard is not a boolean - */ -CValue* CIfExpr::Calculate() +EXP_Value *EXP_IfExpr::Calculate() { - CValue *guardval; - guardval = m_guard->Calculate(); - const STR_String& text = guardval->GetText(); + EXP_Value *guardval = m_guard->Calculate(); + const std::string& text = guardval->GetText(); guardval->Release(); - if (&text == &CBoolValue::sTrueString) - { + if (text == EXP_BoolValue::sTrueString) { return m_e1->Calculate(); } - else if (&text == &CBoolValue::sFalseString) - { + else if (text == EXP_BoolValue::sFalseString) { return m_e2->Calculate(); } - else - { - return new CErrorValue("Guard should be of boolean type"); + else { + return new EXP_ErrorValue("Guard should be of boolean type"); } } - - -bool CIfExpr::MergeExpression(CExpression *otherexpr) -{ - assertd(false); - return false; -} - - - -bool CIfExpr::IsInside(float x,float y,float z,bool bBorderInclude) -{ - assertd(false); - return false; -} - - - -bool CIfExpr::NeedsRecalculated() -{ - return (m_guard->NeedsRecalculated() || - m_e1->NeedsRecalculated() || - m_e2->NeedsRecalculated()); -} - - - -CExpression* CIfExpr::CheckLink(std::vector& brokenlinks) -{ - assertd(false); - return NULL; -} - - - -void CIfExpr::ClearModified() -{ - assertd(false); -} - - - -void CIfExpr::BroadcastOperators(VALUE_OPERATOR op) -{ - assertd(false); -} - - - -unsigned char CIfExpr::GetExpressionID() +unsigned char EXP_IfExpr::GetExpressionID() { return CIFEXPRESSIONID; } diff --git a/source/gameengine/Expressions/intern/InputParser.cpp b/source/gameengine/Expressions/intern/InputParser.cpp index 1f5f9800a33c..8b8ae2a116e5 100644 --- a/source/gameengine/Expressions/intern/InputParser.cpp +++ b/source/gameengine/Expressions/intern/InputParser.cpp @@ -1,7 +1,7 @@ /** \file gameengine/Expressions/InputParser.cpp * \ingroup expressions */ -// Parser.cpp: implementation of the CParser class. +// Parser.cpp: implementation of the EXP_Parser class. /* * Copyright (c) 1996-2000 Erwin Coumans * @@ -17,7 +17,7 @@ #include -#include "MT_assert.h" +#include "BLI_utildefines.h" #include "EXP_Value.h" #include "EXP_InputParser.h" @@ -32,141 +32,126 @@ #include "EXP_Operator1Expr.h" #include "EXP_IdentifierExpr.h" +#include "CM_Message.h" + +#include +#include + // this is disable at the moment, I expected a memleak from it, but the error-cleanup was the reason // well, looks we don't need it anyway, until maybe the Curved Surfaces are integrated into CSG // cool things like (IF(LOD==1,CCurvedValue,IF(LOD==2,CCurvedValue2)) etc... #include "EXP_IfExpr.h" #if defined(WIN32) || defined(WIN64) -#define strcasecmp _stricmp +#define strcasecmp _stricmp #ifndef strtoll -#define strtoll _strtoi64 +#define strtoll _strtoi64 #endif #endif /* Def WIN32 or Def WIN64 */ #define NUM_PRIORITY 6 -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// -CParser::CParser() : m_identifierContext(NULL) +EXP_Parser::EXP_Parser() :m_identifierContext(nullptr) { } - - -CParser::~CParser() +EXP_Parser::~EXP_Parser() { - if (m_identifierContext) + if (m_identifierContext) { m_identifierContext->Release(); + } } - - -void CParser::ScanError(const char *str) +void EXP_Parser::ScanError(const std::string& str) { - // sets the global variable errmsg to an errormessage with - // contents str, appending if it already exists - // AfxMessageBox("Parse Error:"+str,MB_ICONERROR); - if (errmsg) - errmsg = new COperator2Expr(VALUE_ADD_OPERATOR, errmsg, Error(str)); - else + /* Sets the global variable errmsg to an errormessage with + * contents str, appending if it already exists. + */ + if (errmsg) { + errmsg = new EXP_Operator2Expr(VALUE_ADD_OPERATOR, errmsg, Error(str)); + } + else { errmsg = Error(str); + } sym = errorsym; } - - -CExpression* CParser::Error(const char *str) +EXP_Expression *EXP_Parser::Error(const std::string& str) { - // makes and returns a new CConstExpr filled with an CErrorValue - // with string str - // AfxMessageBox("Error:"+str,MB_ICONERROR); - return new CConstExpr(new CErrorValue(str)); + // Makes and returns a new EXP_ConstExpr filled with an EXP_ErrorValue with string str. + return new EXP_ConstExpr(new EXP_ErrorValue(str)); } - - -void CParser::NextCh() +void EXP_Parser::NextCh() { - // sets the global variable ch to the next character, if it exists - // and increases the global variable chcount - chcount++; + /* Sets the global variable ch to the next character, if it exists + * and increases the global variable chcount + */ + ++chcount; - if (chcount < text.Length()) + if (chcount < text.size()) { ch = text[chcount]; - else + } + else { ch = 0x00; + } } - - -void CParser::TermChar(char c) +void EXP_Parser::TermChar(char c) { - // generates an error if the next char isn't the specified char c, - // otherwise, skip the char - if (ch == c) - { + /* Generates an error if the next char isn't the specified char c, + * otherwise, skip the char. + */ + if (ch == c) { NextCh(); } - else - { - STR_String str; - str.Format("Warning: %c expected\ncontinuing without it", c); - trace(str); + else { + CM_Warning(c << " expected. Continuing without it."); } } - - -void CParser::DigRep() +void EXP_Parser::DigRep() { - // changes the current character to the first character that - // isn't a decimal - while ((ch >= '0') && (ch <= '9')) + // Changes the current character to the first character that isn't a decimal. + while ((ch >= '0') && (ch <= '9')) { NextCh(); + } } - - -void CParser::CharRep() +void EXP_Parser::CharRep() { - // changes the current character to the first character that - // isn't an alphanumeric character + // Changes the current character to the first character that isn't an alphanumeric character. while (((ch >= '0') && (ch <= '9')) - || ((ch >= 'a') && (ch <= 'z')) - || ((ch >= 'A') && (ch <= 'Z')) - || (ch == '.') || (ch == '_')) + || ((ch >= 'a') && (ch <= 'z')) + || ((ch >= 'A') && (ch <= 'Z')) + || (ch == '.') || (ch == '_')) + { NextCh(); + } } - - -void CParser::GrabString(int start) +void EXP_Parser::GrabString(int start) { - // puts part of the input string into the global variable - // const_as_string, from position start, to position chchount - const_as_string = text.Mid(start, chcount-start); + /* Puts part of the input string into the global variable + * const_as_string, from position start, to position chchount. + */ + const_as_string = text.substr(start, chcount - start); } - - -void CParser::GrabRealString(int start) +void EXP_Parser::GrabRealString(int start) { - // works like GrabString but converting \\n to \n - // puts part of the input string into the global variable - // const_as_string, from position start, to position chchount - - int i; - char tmpch; + /* Works like GrabString but converting \\n to \n + * puts part of the input string into the global variable + * const_as_string, from position start, to position chchount. + */ - const_as_string = STR_String(); - for (i=start;i': + { sym = opsym; NextCh(); - if (ch == '=') - { + if (ch == '=') { opkind = OPgreaterequal; NextCh(); } - else - { + else { opkind = OPgreater; } break; + } case '<': + { sym = opsym; NextCh(); if (ch == '=') { opkind = OPlessequal; NextCh(); - } else { + } + else { opkind = OPless; } break; - case '\"' : + } + case '\"': { - int start; sym = constsym; constkind = stringtype; NextCh(); - start = chcount; - while ((ch != '\"') && (ch != 0x0)) + int start = chcount; + while ((ch != '\"') && (ch != 0x0)) { NextCh(); + } GrabRealString(start); - TermChar('\"'); // check for eol before '\"' + TermChar('\"'); // check for eol before '\"' + break; + } + case 0x0: + { + sym = eolsym; break; } - case 0x0: sym = eolsym; break; default: { - int start; - start = chcount; + int start = chcount; DigRep(); if ((start != chcount) || (ch == '.')) { // number sym = constsym; @@ -286,13 +299,16 @@ void CParser::NextSym() NextCh(); DigRep(); } - else constkind = inttype; + else { + constkind = inttype; + } if ((ch == 'e') || (ch == 'E')) { - int mark; constkind = floattype; NextCh(); - if ((ch == '+') || (ch == '-')) NextCh(); - mark = chcount; + if ((ch == '+') || (ch == '-')) { + NextCh(); + } + int mark = chcount; DigRep(); if (mark == chcount) { ScanError("Number expected after 'E'"); @@ -300,43 +316,43 @@ void CParser::NextSym() } } GrabString(start); - } else if (((ch >= 'a') && (ch <= 'z')) - || ((ch >= 'A') && (ch <= 'Z'))) - { // reserved word? - + } + else if (((ch >= 'a') && (ch <= 'z')) + || ((ch >= 'A') && (ch <= 'Z'))) { start = chcount; CharRep(); GrabString(start); - if (!strcasecmp(const_as_string, "SUM")) { + if (boost::iequals(const_as_string, "SUM")) { sym = sumsym; } - else if (!strcasecmp(const_as_string, "NOT")) { + else if (boost::iequals(const_as_string, "NOT")) { sym = opsym; opkind = OPnot; } - else if (!strcasecmp(const_as_string, "AND")) { + else if (boost::iequals(const_as_string, "AND")) { sym = opsym; opkind = OPand; } - else if (!strcasecmp(const_as_string, "OR")) { + else if (boost::iequals(const_as_string, "OR")) { sym = opsym; opkind = OPor; } - else if (!strcasecmp(const_as_string, "IF")) + else if (boost::iequals(const_as_string, "IF")) { sym = ifsym; - else if (!strcasecmp(const_as_string, "WHOMADE")) + } + else if (boost::iequals(const_as_string, "WHOMADE")) { sym = whocodedsym; - else if (!strcasecmp(const_as_string, "FALSE")) { + } + else if (boost::iequals(const_as_string, "FALSE")) { sym = constsym; constkind = booltype; boolvalue = false; - } else if (!strcasecmp(const_as_string, "TRUE")) { + } + else if (boost::iequals(const_as_string, "TRUE")) { sym = constsym; constkind = booltype; boolvalue = true; - } else { + } + else { sym = idsym; - //STR_String str; - //str.Format("'%s' makes no sense here", (const char*)funstr); - //ScanError(str); } - } else { // unknown symbol - STR_String str; - str.Format("Unexpected character '%c'", ch); + } + else { + std::string str = (boost::format("Unexpected character '%c'") % ch).str(); NextCh(); ScanError(str); return; @@ -345,117 +361,172 @@ void CParser::NextSym() } } -#if 0 -int CParser::MakeInt() +const std::string EXP_Parser::Symbol2Str(int s) { - // returns the integer representation of the value in the global - // variable const_as_string - // pre: const_as_string contains only numercal chars - return atoi(const_as_string); -} -#endif - -const char *CParser::Symbol2Str(int s) -{ - // returns a string representation of of symbol s, - // for use in Term when generating an error + // Returns a string representation of of symbol s, for use in Term when generating an error. switch (s) { - case errorsym: return "error"; - case lbracksym: return "("; - case rbracksym: return ")"; - case commasym: return ","; - case opsym: return "operator"; - case constsym: return "constant"; - case sumsym: return "SUM"; - case ifsym: return "IF"; - case whocodedsym: return "WHOMADE"; - case eolsym: return "end of line"; - case idsym: return "identifier"; + case errorsym: + { + return "error"; + } + case lbracksym: + { + return "("; + } + case rbracksym: + { + return ")"; + } + case commasym: + { + return ","; + } + case opsym: + { + return "operator"; + } + case constsym: + { + return "constant"; + } + case sumsym: + { + return "SUM"; + } + case ifsym: + { + return "IF"; + } + case whocodedsym: + { + return "WHOMADE"; + } + case eolsym: + { + return "end of line"; + } + case idsym: + { + return "identifier"; + } } - return "unknown"; // should not happen + return "unknown"; // should not happen } -void CParser::Term(int s) +void EXP_Parser::Term(int s) { - // generates an error if the next symbol isn't the specified symbol s - // otherwise, skip the symbol + /* Generates an error if the next symbol isn't the specified symbol s + * otherwise, skip the symbol. + */ if (s == sym) { NextSym(); } else { - STR_String msg; - msg.Format("Warning: %s expected\ncontinuing without it", Symbol2Str(s)); - -// AfxMessageBox(msg,MB_ICONERROR); - - trace(msg); + CM_Warning(Symbol2Str(s) << "expected. Continuing without it."); } } -int CParser::Priority(int optorkind) +int EXP_Parser::Priority(int optorkind) { - // returns the priority of an operator - // higher number means higher priority + // Returns the priority of an operator higher number means higher priority. switch (optorkind) { - case OPor: return 1; - case OPand: return 2; + case OPor: + { return 1;} + case OPand: + { return 2;} case OPgreater: case OPless: case OPgreaterequal: case OPlessequal: case OPequal: - case OPunequal: return 3; + case OPunequal: + { return 3;} case OPplus: - case OPminus: return 4; + case OPminus: + { return 4;} case OPmodulus: case OPtimes: case OPdivide: return 5; } - MT_assert(false); - return 0; // should not happen + BLI_assert(false); + return 0; // should not happen } -CExpression *CParser::Ex(int i) +EXP_Expression *EXP_Parser::Ex(int i) { - // parses an expression in the imput, starting at priority i, and - // returns an CExpression, containing the parsed input - CExpression *e1 = NULL, *e2 = NULL; - int opkind2; + /* Parses an expression in the imput, starting at priority i, and + * returns an EXP_Expression, containing the parsed input. + */ + EXP_Expression *e1 = nullptr, *e2 = nullptr; if (i < NUM_PRIORITY) { e1 = Ex(i + 1); while ((sym == opsym) && (Priority(opkind) == i)) { - opkind2 = opkind; + int opkind2 = opkind; NextSym(); e2 = Ex(i + 1); switch (opkind2) { - case OPmodulus: e1 = new COperator2Expr(VALUE_MOD_OPERATOR,e1, e2); break; - case OPplus: e1 = new COperator2Expr(VALUE_ADD_OPERATOR,e1, e2); break; - case OPminus: e1 = new COperator2Expr(VALUE_SUB_OPERATOR,e1, e2); break; - case OPtimes: e1 = new COperator2Expr(VALUE_MUL_OPERATOR,e1, e2); break; - case OPdivide: e1 = new COperator2Expr(VALUE_DIV_OPERATOR,e1, e2); break; - case OPand: e1 = new COperator2Expr(VALUE_AND_OPERATOR,e1, e2); break; - case OPor: e1 = new COperator2Expr(VALUE_OR_OPERATOR,e1, e2); break; - case OPequal: e1 = new COperator2Expr(VALUE_EQL_OPERATOR,e1, e2); break; - case OPunequal: e1 = new COperator2Expr(VALUE_NEQ_OPERATOR,e1, e2); break; - case OPgreater: e1 = new COperator2Expr(VALUE_GRE_OPERATOR,e1, e2); break; - case OPless: e1 = new COperator2Expr(VALUE_LES_OPERATOR,e1, e2); break; - case OPgreaterequal: e1 = new COperator2Expr(VALUE_GEQ_OPERATOR,e1, e2); break; - case OPlessequal: e1 = new COperator2Expr(VALUE_LEQ_OPERATOR,e1, e2); break; - default: MT_assert(false); break; // should not happen + case OPmodulus: + { e1 = new EXP_Operator2Expr(VALUE_MOD_OPERATOR, e1, e2);} + break; + case OPplus: + { e1 = new EXP_Operator2Expr(VALUE_ADD_OPERATOR, e1, e2);} + break; + case OPminus: + { e1 = new EXP_Operator2Expr(VALUE_SUB_OPERATOR, e1, e2);} + break; + case OPtimes: + { e1 = new EXP_Operator2Expr(VALUE_MUL_OPERATOR, e1, e2);} + break; + case OPdivide: + { e1 = new EXP_Operator2Expr(VALUE_DIV_OPERATOR, e1, e2);} + break; + case OPand: + { e1 = new EXP_Operator2Expr(VALUE_AND_OPERATOR, e1, e2);} + break; + case OPor: + { e1 = new EXP_Operator2Expr(VALUE_OR_OPERATOR, e1, e2);} + break; + case OPequal: + { e1 = new EXP_Operator2Expr(VALUE_EQL_OPERATOR, e1, e2);} + break; + case OPunequal: + { e1 = new EXP_Operator2Expr(VALUE_NEQ_OPERATOR, e1, e2);} + break; + case OPgreater: + { e1 = new EXP_Operator2Expr(VALUE_GRE_OPERATOR, e1, e2);} + break; + case OPless: + { e1 = new EXP_Operator2Expr(VALUE_LES_OPERATOR, e1, e2);} + break; + case OPgreaterequal: + { e1 = new EXP_Operator2Expr(VALUE_GEQ_OPERATOR, e1, e2);} + break; + case OPlessequal: + { e1 = new EXP_Operator2Expr(VALUE_LEQ_OPERATOR, e1, e2);} + break; + default: + { BLI_assert(false);} + break; // should not happen } } - } else if (i == NUM_PRIORITY) { + } + else if (i == NUM_PRIORITY) { if ((sym == opsym) - && ( (opkind == OPminus) || (opkind == OPnot) || (opkind == OPplus) ) - ) - { + && ((opkind == OPminus) || (opkind == OPnot) || (opkind == OPplus)) + ) { NextSym(); switch (opkind) { /* +1 is also a valid number! */ - case OPplus: e1 = new COperator1Expr(VALUE_POS_OPERATOR, Ex(NUM_PRIORITY)); break; - case OPminus: e1 = new COperator1Expr(VALUE_NEG_OPERATOR, Ex(NUM_PRIORITY)); break; - case OPnot: e1 = new COperator1Expr(VALUE_NOT_OPERATOR, Ex(NUM_PRIORITY)); break; + case OPplus: + { e1 = new EXP_Operator1Expr(VALUE_POS_OPERATOR, Ex(NUM_PRIORITY));} + break; + case OPminus: + { e1 = new EXP_Operator1Expr(VALUE_NEG_OPERATOR, Ex(NUM_PRIORITY));} + break; + case OPnot: + { e1 = new EXP_Operator1Expr(VALUE_NOT_OPERATOR, Ex(NUM_PRIORITY));} + break; default: { // should not happen @@ -469,40 +540,48 @@ CExpression *CParser::Ex(int i) { switch (constkind) { case booltype: - e1 = new CConstExpr(new CBoolValue(boolvalue)); + { + e1 = new EXP_ConstExpr(new EXP_BoolValue(boolvalue)); break; + } case inttype: { cInt temp; - temp = strtoll(const_as_string, NULL, 10); /* atoi is for int only */ - e1 = new CConstExpr(new CIntValue(temp)); + temp = std::stol(const_as_string, nullptr, 10); /* atoi is for int only */ + e1 = new EXP_ConstExpr(new EXP_IntValue(temp)); break; } case floattype: { double temp; - temp = atof(const_as_string); - e1 = new CConstExpr(new CFloatValue(temp)); + temp = std::stof(const_as_string); + e1 = new EXP_ConstExpr(new EXP_FloatValue(temp)); break; } case stringtype: - e1 = new CConstExpr(new CStringValue(const_as_string,"")); + { + e1 = new EXP_ConstExpr(new EXP_StringValue(const_as_string, "")); break; - default : - MT_assert(false); + } + default: + { + BLI_assert(false); break; + } } NextSym(); break; } case lbracksym: + { NextSym(); e1 = Ex(1); Term(rbracksym); break; + } case ifsym: { - CExpression *e3; + EXP_Expression *e3; NextSym(); Term(lbracksym); e1 = Ex(1); @@ -511,38 +590,38 @@ CExpression *CParser::Ex(int i) if (sym == commasym) { NextSym(); e3 = Ex(1); - } else { - e3 = new CConstExpr(new CEmptyValue()); + } + else { + e3 = new EXP_ConstExpr(new EXP_EmptyValue()); } Term(rbracksym); - e1 = new CIfExpr(e1, e2, e3); + e1 = new EXP_IfExpr(e1, e2, e3); break; } case idsym: { - e1 = new CIdentifierExpr(const_as_string,m_identifierContext); + e1 = new EXP_IdentifierExpr(const_as_string, m_identifierContext); NextSym(); break; } case errorsym: { - MT_assert(!e1); - STR_String errtext="[no info]"; - if (errmsg) - { - CValue* errmsgval = errmsg->Calculate(); - errtext=errmsgval->GetText(); + BLI_assert(!e1); + std::string errtext = "[no info]"; + if (errmsg) { + EXP_Value *errmsgval = errmsg->Calculate(); + errtext = errmsgval->GetText(); errmsgval->Release(); - //e1 = Error(errmsg->Calculate()->GetText());//new CConstExpr(errmsg->Calculate()); + //e1 = Error(errmsg->Calculate()->GetText());//new EXP_ConstExpr(errmsg->Calculate()); - if ( !(errmsg->Release()) ) - { - errmsg=NULL; - } else { + if (!(errmsg->Release())) { + errmsg = nullptr; + } + else { // does this happen ? - MT_assert("does this happen"); + BLI_assert("does this happen"); } } e1 = Error(errtext); @@ -552,7 +631,7 @@ CExpression *CParser::Ex(int i) default: NextSym(); //return Error("Expression expected"); - MT_assert(!e1); + BLI_assert(!e1); e1 = Error("Expression expected"); } } @@ -560,31 +639,31 @@ CExpression *CParser::Ex(int i) return e1; } -CExpression *CParser::Expr() +EXP_Expression *EXP_Parser::Expr() { // parses an expression in the imput, and - // returns an CExpression, containing the parsed input + // returns an EXP_Expression, containing the parsed input return Ex(1); } -CExpression* CParser::ProcessText -(const char *intext) { +EXP_Expression *EXP_Parser::ProcessText(const std::string& intext) +{ // and parses the string in intext and returns it. - CExpression* expr; + EXP_Expression *expr; text = intext; chcount = 0; - if (text.Length() == 0) { - return NULL; + if (text.empty()) { + return nullptr; } ch = text[0]; /* if (ch != '=') { - * expr = new CConstExpr(new CStringValue(text)); + * expr = new EXP_ConstExpr(new EXP_StringValue(text)); * *dependent = deplist; * return expr; * } else @@ -593,76 +672,20 @@ CExpression* CParser::ProcessText NextSym(); expr = Expr(); if (sym != eolsym) { - CExpression* oldexpr = expr; - expr = new COperator2Expr(VALUE_ADD_OPERATOR, - oldexpr, Error(STR_String("Extra characters after expression")));//new CConstExpr(new CErrorValue("Extra characters after expression"))); + EXP_Expression *oldexpr = expr; + expr = new EXP_Operator2Expr(VALUE_ADD_OPERATOR, + oldexpr, Error("Extra characters after expression"));//new EXP_ConstExpr(new EXP_ErrorValue("Extra characters after expression"))); } - if (errmsg) + if (errmsg) { errmsg->Release(); - - return expr; -} - - - -float CParser::GetFloat(STR_String& txt) -{ - // returns parsed text into a float - // empty string returns -1 - -// AfxMessageBox("parsed string="+txt); - CValue* val=NULL; - float result=-1; -// String tmpstr; - - CExpression* expr = ProcessText(txt); - if (expr) { - val = expr->Calculate(); - result=(float)val->GetNumber(); - - - - val->Release(); - expr->Release(); } -// tmpstr.Format("parseresult=%g",result); -// AfxMessageBox(tmpstr); - return result; -} -CValue* CParser::GetValue(STR_String& txt, bool bFallbackToText) -{ - // returns parsed text into a value, - // empty string returns NULL value ! - // if bFallbackToText then unparsed stuff is put into text - - CValue* result=NULL; - CExpression* expr = ProcessText(txt); - if (expr) { - result = expr->Calculate(); - expr->Release(); - } - if (result) - { - // if the parsed stuff lead to an errorvalue, don't return errors, just NULL - if (result->IsError()) { - result->Release(); - result=NULL; - if (bFallbackToText) { - if (txt.Length()>0) - { - result = new CStringValue(txt,""); - } - } - } - } - return result; + return expr; } -void CParser::SetContext(CValue* context) +void EXP_Parser::SetContext(EXP_Value *context) { - if (m_identifierContext) - { + if (m_identifierContext) { m_identifierContext->Release(); } m_identifierContext = context; diff --git a/source/gameengine/Expressions/intern/IntValue.cpp b/source/gameengine/Expressions/intern/IntValue.cpp index 3315b3a3e3c1..4e499ae7dfd8 100644 --- a/source/gameengine/Expressions/intern/IntValue.cpp +++ b/source/gameengine/Expressions/intern/IntValue.cpp @@ -1,7 +1,7 @@ /** \file gameengine/Expressions/IntValue.cpp * \ingroup expressions */ -// IntValue.cpp: implementation of the CIntValue class. +// IntValue.cpp: implementation of the EXP_IntValue class. /* * Copyright (c) 1996-2000 Erwin Coumans * @@ -15,109 +15,70 @@ * */ -#include - #include "EXP_IntValue.h" #include "EXP_ErrorValue.h" #include "EXP_FloatValue.h" #include "EXP_BoolValue.h" #include "EXP_StringValue.h" -#include "EXP_VoidValue.h" -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// +#include "CM_Message.h" -CIntValue::CIntValue() -/* -pre: false -effect: constructs a new CIntValue -*/ -{ +#include -#ifdef DEBUG_ - m_textval = "Int illegal constructor"; -#endif - m_pstrRep=NULL; +EXP_IntValue::EXP_IntValue() +{ } - - -CIntValue::CIntValue(cInt innie) -/* -pre: -effect: constructs a new CIntValue containing cInt innie -*/ +EXP_IntValue::EXP_IntValue(cInt innie) + :m_int(innie) { - m_int = innie; - m_pstrRep=NULL; } - - -CIntValue::CIntValue(cInt innie,const char *name,AllocationTYPE alloctype) +EXP_IntValue::EXP_IntValue(cInt innie, const std::string& name) + :m_int(innie) { - m_int = innie; SetName(name); - - if (alloctype==CValue::STACKVALUE) - { - CValue::DisableRefCount(); - } - m_pstrRep=NULL; - } - - -CIntValue::~CIntValue() -/* -pre: -effect: deletes the object -*/ +EXP_IntValue::~EXP_IntValue() { - if (m_pstrRep) - delete m_pstrRep; } - - -CValue* CIntValue::Calc(VALUE_OPERATOR op, CValue *val) -/* -pre: -ret: a new object containing the result of applying operator op to this -object and val -*/ +EXP_Value *EXP_IntValue::Calc(VALUE_OPERATOR op, EXP_Value *val) { - //return val->CalcInt(op, this); switch (op) { - case VALUE_POS_OPERATOR: - return new CIntValue (m_int); - break; - case VALUE_NEG_OPERATOR: - return new CIntValue (-m_int); - break; - case VALUE_NOT_OPERATOR: - return new CBoolValue (m_int == 0); - break; - case VALUE_AND_OPERATOR: - case VALUE_OR_OPERATOR: - return new CErrorValue(val->GetText() + op2str(op) + "only allowed on booleans"); - break; - default: - return val->CalcFinal(VALUE_INT_TYPE, op, this); - break; + case VALUE_POS_OPERATOR: + { + return new EXP_IntValue(m_int); + break; + } + case VALUE_NEG_OPERATOR: + { + return new EXP_IntValue(-m_int); + break; + } + case VALUE_NOT_OPERATOR: + { + return new EXP_BoolValue(m_int == 0); + break; + } + case VALUE_AND_OPERATOR: + case VALUE_OR_OPERATOR: + { + return new EXP_ErrorValue(val->GetText() + op2str(op) + "only allowed on booleans"); + break; + } + default: + { + return val->CalcFinal(VALUE_INT_TYPE, op, this); + break; + } } } -/* - * pre: the type of val is dtype - * ret: a new object containing the result of applying operator op to val and - * this object - */ -CValue* CIntValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val) +EXP_Value *EXP_IntValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, EXP_Value *val) { - CValue *ret; + EXP_Value *ret; switch (dtype) { case VALUE_EMPTY_TYPE: @@ -125,60 +86,91 @@ CValue* CIntValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *v { switch (op) { case VALUE_MOD_OPERATOR: - ret = new CIntValue (((CIntValue *) val)->GetInt() % m_int); + { + ret = new EXP_IntValue(((EXP_IntValue *)val)->GetInt() % m_int); break; + } case VALUE_ADD_OPERATOR: - ret = new CIntValue (((CIntValue *) val)->GetInt() + m_int); + { + ret = new EXP_IntValue(((EXP_IntValue *)val)->GetInt() + m_int); break; + } case VALUE_SUB_OPERATOR: - ret = new CIntValue (((CIntValue *) val)->GetInt() - m_int); + { + ret = new EXP_IntValue(((EXP_IntValue *)val)->GetInt() - m_int); break; + } case VALUE_MUL_OPERATOR: - ret = new CIntValue (((CIntValue *) val)->GetInt() * m_int); + { + ret = new EXP_IntValue(((EXP_IntValue *)val)->GetInt() * m_int); break; + } case VALUE_DIV_OPERATOR: + { if (m_int == 0) { if (val->GetNumber() == 0) { - ret = new CErrorValue("Not a Number"); + ret = new EXP_ErrorValue("Not a Number"); } else { - ret = new CErrorValue("Division by zero"); + ret = new EXP_ErrorValue("Division by zero"); } } - else - ret = new CIntValue (((CIntValue *) val)->GetInt() / m_int); + else { + ret = new EXP_IntValue(((EXP_IntValue *)val)->GetInt() / m_int); + } break; + } case VALUE_EQL_OPERATOR: - ret = new CBoolValue(((CIntValue *) val)->GetInt() == m_int); + { + ret = new EXP_BoolValue(((EXP_IntValue *)val)->GetInt() == m_int); break; + } case VALUE_NEQ_OPERATOR: - ret = new CBoolValue(((CIntValue *) val)->GetInt() != m_int); + { + ret = new EXP_BoolValue(((EXP_IntValue *)val)->GetInt() != m_int); break; + } case VALUE_GRE_OPERATOR: - ret = new CBoolValue(((CIntValue *) val)->GetInt() > m_int); + { + ret = new EXP_BoolValue(((EXP_IntValue *)val)->GetInt() > m_int); break; + } case VALUE_LES_OPERATOR: - ret = new CBoolValue(((CIntValue *) val)->GetInt() < m_int); + { + ret = new EXP_BoolValue(((EXP_IntValue *)val)->GetInt() < m_int); break; + } case VALUE_GEQ_OPERATOR: - ret = new CBoolValue(((CIntValue *) val)->GetInt() >= m_int); + { + ret = new EXP_BoolValue(((EXP_IntValue *)val)->GetInt() >= m_int); break; + } case VALUE_LEQ_OPERATOR: - ret = new CBoolValue(((CIntValue *) val)->GetInt() <= m_int); + { + ret = new EXP_BoolValue(((EXP_IntValue *)val)->GetInt() <= m_int); break; + } case VALUE_NEG_OPERATOR: - ret = new CIntValue (-m_int); + { + ret = new EXP_IntValue(-m_int); break; + } case VALUE_POS_OPERATOR: - ret = new CIntValue (m_int); + { + ret = new EXP_IntValue(m_int); break; + } case VALUE_NOT_OPERATOR: - ret = new CBoolValue(m_int == 0); + { + ret = new EXP_BoolValue(m_int == 0); break; + } default: - printf("Found op: %d\n", op); - ret = new CErrorValue("illegal operator. please send a bug report."); + { + CM_Error("found op: " << op); + ret = new EXP_ErrorValue("illegal operator. please send a bug report."); break; + } } break; } @@ -186,47 +178,75 @@ CValue* CIntValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *v { switch (op) { case VALUE_MOD_OPERATOR: - ret = new CFloatValue(fmod(((CFloatValue *) val)->GetFloat(), m_int)); + { + ret = new EXP_FloatValue(fmod(((EXP_FloatValue *)val)->GetFloat(), m_int)); break; + } case VALUE_ADD_OPERATOR: - ret = new CFloatValue (((CFloatValue *) val)->GetFloat() + m_int); + { + ret = new EXP_FloatValue(((EXP_FloatValue *)val)->GetFloat() + m_int); break; + } case VALUE_SUB_OPERATOR: - ret = new CFloatValue (((CFloatValue *) val)->GetFloat() - m_int); + { + ret = new EXP_FloatValue(((EXP_FloatValue *)val)->GetFloat() - m_int); break; + } case VALUE_MUL_OPERATOR: - ret = new CFloatValue (((CFloatValue *) val)->GetFloat() * m_int); + { + ret = new EXP_FloatValue(((EXP_FloatValue *)val)->GetFloat() * m_int); break; + } case VALUE_DIV_OPERATOR: - if (m_int == 0) - ret = new CErrorValue("Division by zero"); - else - ret = new CFloatValue (((CFloatValue *) val)->GetFloat() / m_int); + { + if (m_int == 0) { + ret = new EXP_ErrorValue("Division by zero"); + } + else { + ret = new EXP_FloatValue(((EXP_FloatValue *)val)->GetFloat() / m_int); + } break; + } case VALUE_EQL_OPERATOR: - ret = new CBoolValue(((CFloatValue *) val)->GetFloat() == m_int); + { + ret = new EXP_BoolValue(((EXP_FloatValue *)val)->GetFloat() == m_int); break; + } case VALUE_NEQ_OPERATOR: - ret = new CBoolValue(((CFloatValue *) val)->GetFloat() != m_int); + { + ret = new EXP_BoolValue(((EXP_FloatValue *)val)->GetFloat() != m_int); break; + } case VALUE_GRE_OPERATOR: - ret = new CBoolValue(((CFloatValue *) val)->GetFloat() > m_int); + { + ret = new EXP_BoolValue(((EXP_FloatValue *)val)->GetFloat() > m_int); break; + } case VALUE_LES_OPERATOR: - ret = new CBoolValue(((CFloatValue *) val)->GetFloat() < m_int); + { + ret = new EXP_BoolValue(((EXP_FloatValue *)val)->GetFloat() < m_int); break; + } case VALUE_GEQ_OPERATOR: - ret = new CBoolValue(((CFloatValue *) val)->GetFloat() >= m_int); + { + ret = new EXP_BoolValue(((EXP_FloatValue *)val)->GetFloat() >= m_int); break; + } case VALUE_LEQ_OPERATOR: - ret = new CBoolValue(((CFloatValue *) val)->GetFloat() <= m_int); + { + ret = new EXP_BoolValue(((EXP_FloatValue *)val)->GetFloat() <= m_int); break; + } case VALUE_NOT_OPERATOR: - ret = new CBoolValue(m_int == 0); + { + ret = new EXP_BoolValue(m_int == 0); break; + } default: - ret = new CErrorValue("illegal operator. please send a bug report."); + { + ret = new EXP_ErrorValue("illegal operator. please send a bug report."); break; + } } break; } @@ -234,111 +254,83 @@ CValue* CIntValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *v { switch (op) { case VALUE_ADD_OPERATOR: - ret = new CStringValue(val->GetText() + GetText(),""); + { + ret = new EXP_StringValue(val->GetText() + GetText(), ""); break; + } case VALUE_EQL_OPERATOR: case VALUE_NEQ_OPERATOR: case VALUE_GRE_OPERATOR: case VALUE_LES_OPERATOR: case VALUE_GEQ_OPERATOR: case VALUE_LEQ_OPERATOR: - ret = new CErrorValue("[Cannot compare string with integer]" + op2str(op) + GetText()); + { + ret = new EXP_ErrorValue("[Cannot compare string with integer]" + op2str(op) + GetText()); break; + } default: - ret = new CErrorValue("[operator not allowed on strings]" + op2str(op) + GetText()); + { + ret = new EXP_ErrorValue("[operator not allowed on strings]" + op2str(op) + GetText()); break; + } } break; } case VALUE_BOOL_TYPE: - ret = new CErrorValue("[operator not valid on boolean and integer]" + op2str(op) + GetText()); + { + ret = new EXP_ErrorValue("[operator not valid on boolean and integer]" + op2str(op) + GetText()); break; -#if 0 - case VALUE_EMPTY_TYPE: + } + case VALUE_ERROR_TYPE: { - switch (op) { - case VALUE_ADD_OPERATOR: - ret = new CIntValue (m_int); - break; - case VALUE_SUB_OPERATOR: - ret = new CIntValue (-m_int); - break; - default: - { - ret = new CErrorValue(op2str(op) + GetText()); - } - } + ret = new EXP_ErrorValue(val->GetText() + op2str(op) + GetText()); + break; + } + default: + { + ret = new EXP_ErrorValue("illegal type. contact your dealer (if any)"); break; } -#endif - case VALUE_ERROR_TYPE: - ret = new CErrorValue(val->GetText() + op2str(op) + GetText()); - break; - default: - ret = new CErrorValue("illegal type. contact your dealer (if any)"); - break; } return ret; } - -/** - * pre: - * ret: the cInt stored in the object - */ -cInt CIntValue::GetInt() +cInt EXP_IntValue::GetInt() { return m_int; } - - -double CIntValue::GetNumber() +double EXP_IntValue::GetNumber() { - return (double) m_int; + return (double)m_int; } - - -int CIntValue::GetValueType() +int EXP_IntValue::GetValueType() { return VALUE_INT_TYPE; } - - -const STR_String & CIntValue::GetText() +std::string EXP_IntValue::GetText() { - if (!m_pstrRep) - m_pstrRep=new STR_String(); - m_pstrRep->Format("%lld",m_int); - - return *m_pstrRep; + return (boost::format("%lld") % m_int).str(); } - - -CValue* CIntValue::GetReplica() +EXP_Value *EXP_IntValue::GetReplica() { - CIntValue* replica = new CIntValue(*this); + EXP_IntValue *replica = new EXP_IntValue(*this); replica->ProcessReplica(); - replica->m_pstrRep = NULL; return replica; } - - -void CIntValue::SetValue(CValue* newval) +void EXP_IntValue::SetValue(EXP_Value *newval) { m_int = (cInt)newval->GetNumber(); - SetModified(true); } - #ifdef WITH_PYTHON -PyObject *CIntValue::ConvertValueToPython() +PyObject *EXP_IntValue::ConvertValueToPython() { return PyLong_FromLongLong(m_int); } -#endif // WITH_PYTHON +#endif // WITH_PYTHON diff --git a/source/gameengine/Expressions/intern/ListValue.cpp b/source/gameengine/Expressions/intern/ListValue.cpp deleted file mode 100644 index ce45c6cf8f5e..000000000000 --- a/source/gameengine/Expressions/intern/ListValue.cpp +++ /dev/null @@ -1,702 +0,0 @@ -/** \file gameengine/Expressions/ListValue.cpp - * \ingroup expressions - */ -// ListValue.cpp: implementation of the CListValue class. -// -////////////////////////////////////////////////////////////////////// -/* - * Copyright (c) 1996-2000 Erwin Coumans - * - * 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. 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 - -#include "EXP_ListValue.h" -#include "EXP_StringValue.h" -#include "EXP_VoidValue.h" -#include -#include "EXP_BoolValue.h" - -#include "BLI_sys_types.h" /* for intptr_t support */ - - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CListValue::CListValue() -: CPropValue() -{ - m_bReleaseContents=true; -} - - - -CListValue::~CListValue() -{ - - if (m_bReleaseContents) { - for (unsigned int i=0;iRelease(); - } - } -} - - -static STR_String gstrListRep=STR_String("List"); - -const STR_String & CListValue::GetText() -{ - gstrListRep = "["; - STR_String commastr = ""; - - for (int i=0;iGetText(); - commastr = ","; - } - gstrListRep += "]"; - - return gstrListRep; -} - - - -CValue* CListValue::GetReplica() -{ - CListValue* replica = new CListValue(*this); - - replica->ProcessReplica(); - - replica->m_bReleaseContents=true; // for copy, complete array is copied for now... - // copy all values - int numelements = m_pValueArray.size(); - unsigned int i=0; - replica->m_pValueArray.resize(numelements); - for (i=0;im_pValueArray[i] = m_pValueArray[i]->GetReplica(); - - - return replica; -}; - - - -void CListValue::SetValue(int i, CValue *val) -{ - assertd(i < m_pValueArray.size()); - m_pValueArray[i]=val; -} - - - -void CListValue::Resize(int num) -{ - m_pValueArray.resize(num); -} - - - -void CListValue::Remove(int i) -{ - assertd(iRelease(); - m_pValueArray.clear();//.Clear(); -} - - - -CValue* CListValue::FindValue(const STR_String &name) -{ - for (int i=0; i < GetCount(); i++) - if (GetValue(i)->GetName() == name) - return GetValue(i); - - return NULL; -} - -CValue* CListValue::FindValue(const char *name) -{ - for (int i=0; i < GetCount(); i++) - if (GetValue(i)->GetName() == name) - return GetValue(i); - - return NULL; -} - -bool CListValue::SearchValue(CValue *val) -{ - for (int i=0;i=0;i--) - if (val == GetValue(i)) - { - Remove(i); - result=true; - } - return result; -} - - - -void CListValue::MergeList(CListValue *otherlist) -{ - - int numelements = this->GetCount(); - int numotherelements = otherlist->GetCount(); - - - Resize(numelements+numotherelements); - - for (int i=0;iGetValue(i)->AddRef()); - } -} - -bool CListValue::CheckEqual(CValue* first,CValue* second) -{ - bool result = false; - - CValue* eqval = ((CValue*)first)->Calc(VALUE_EQL_OPERATOR,(CValue*)second); - - if (eqval==NULL) - return false; - const STR_String& text = eqval->GetText(); - if (&text==&CBoolValue::sTrueString) - { - result = true; - } - eqval->Release(); - return result; - -} - - -/* --------------------------------------------------------------------- - * Some stuff taken from the header - * --------------------------------------------------------------------- */ -CValue* CListValue::Calc(VALUE_OPERATOR op,CValue *val) -{ - //assert(false); // todo: implement me! - static int error_printed = 0; - if (error_printed==0) { - fprintf(stderr, "CValueList::Calc not yet implemented\n"); - error_printed = 1; - } - return NULL; -} - -CValue* CListValue::CalcFinal(VALUE_DATA_TYPE dtype, - VALUE_OPERATOR op, - CValue* val) -{ - //assert(false); // todo: implement me! - static int error_printed = 0; - if (error_printed==0) { - fprintf(stderr, "CValueList::CalcFinal not yet implemented\n"); - error_printed = 1; - } - return NULL; -} - - - -void CListValue::Add(CValue* value) -{ - m_pValueArray.push_back(value); -} - - - -double CListValue::GetNumber() -{ - return -1; -} - - - -int CListValue::GetValueType() -{ - return VALUE_LIST_TYPE; -} - - - -void CListValue::SetModified(bool bModified) -{ - CValue::SetModified(bModified); - int numels = GetCount(); - - for (int i=0;iSetModified(bModified); -} - - - -bool CListValue::IsModified() -{ - bool bmod = CValue::IsModified(); //normal own flag - int numels = GetCount(); - - for (int i=0;iIsModified(); - - return bmod; -} - -#ifdef WITH_PYTHON - -/* --------------------------------------------------------------------- */ -/* Python interface ---------------------------------------------------- */ -/* --------------------------------------------------------------------- */ - -static Py_ssize_t listvalue_bufferlen(PyObject *self) -{ - CListValue *list= static_cast(BGE_PROXY_REF(self)); - if (list==NULL) - return 0; - - return (Py_ssize_t)list->GetCount(); -} - -static PyObject *listvalue_buffer_item(PyObject *self, Py_ssize_t index) -{ - CListValue *list= static_cast(BGE_PROXY_REF(self)); - CValue *cval; - - if (list==NULL) { - PyErr_SetString(PyExc_SystemError, "val = CList[i], " BGE_PROXY_ERROR_MSG); - return NULL; - } - - int count = list->GetCount(); - - if (index < 0) - index = count+index; - - if (index < 0 || index >= count) { - PyErr_SetString(PyExc_IndexError, "CList[i]: Python ListIndex out of range in CValueList"); - return NULL; - } - - cval= list->GetValue(index); - - PyObject *pyobj = cval->ConvertValueToPython(); - if (pyobj) - return pyobj; - else - return cval->GetProxy(); -} - - -/* just slice it into a python list... */ -static PyObject *listvalue_buffer_slice(CListValue *list, Py_ssize_t start, Py_ssize_t stop) -{ - PyObject *newlist; - Py_ssize_t i, j; - - /* caller needs to validate negative index */ -#if 0 - Py_ssize_t len = list->GetCount(); - - if (start > len) start = len; - if (stop > len) stop = len; -#endif - - newlist = PyList_New(stop - start); - if (!newlist) - return NULL; - - for (i = start, j = 0; i < stop; i++, j++) { - PyObject *pyobj = list->GetValue(i)->ConvertValueToPython(); - if (!pyobj) { - pyobj = list->GetValue(i)->GetProxy(); - } - PyList_SET_ITEM(newlist, j, pyobj); - } - return newlist; -} - - -static PyObject *listvalue_mapping_subscript(PyObject *self, PyObject *key) -{ - CListValue *list= static_cast(BGE_PROXY_REF(self)); - if (list==NULL) { - PyErr_SetString(PyExc_SystemError, "value = CList[i], " BGE_PROXY_ERROR_MSG); - return NULL; - } - - if (PyUnicode_Check(key)) { - CValue *item = ((CListValue*) list)->FindValue(_PyUnicode_AsString(key)); - if (item) { - PyObject *pyobj = item->ConvertValueToPython(); - if (pyobj) - return pyobj; - else - return item->GetProxy(); - } - } - else if (PyIndex_Check(key)) { - Py_ssize_t index = PyLong_AsSsize_t(key); - return listvalue_buffer_item(self, index); /* wont add a ref */ - } - else if (PySlice_Check(key)) { - Py_ssize_t start, stop, step, slicelength; - - if (PySlice_GetIndicesEx(key, list->GetCount(), &start, &stop, &step, &slicelength) < 0) - return NULL; - - if (slicelength <= 0) { - return PyList_New(0); - } - else if (step == 1) { - return listvalue_buffer_slice(list, start, stop); - } - else { - PyErr_SetString(PyExc_TypeError, "CList[slice]: slice steps not supported"); - return NULL; - } - } - - PyErr_Format(PyExc_KeyError, - "CList[key]: '%R' key not in list", key); - return NULL; -} - -/* clist + list, return a list that python owns */ -static PyObject *listvalue_buffer_concat(PyObject *self, PyObject *other) -{ - CListValue *listval= static_cast(BGE_PROXY_REF(self)); - Py_ssize_t i, numitems, numitems_orig; - - if (listval==NULL) { - PyErr_SetString(PyExc_SystemError, "CList+other, " BGE_PROXY_ERROR_MSG); - return NULL; - } - - numitems_orig= listval->GetCount(); - - // for now, we support CListValue concatenated with items - // and CListValue concatenated to Python Lists - // and CListValue concatenated with another CListValue - - /* Shallow copy, don't use listval->GetReplica(), it will screw up with KX_GameObjects */ - CListValue* listval_new = new CListValue(); - - if (PyList_Check(other)) - { - CValue* listitemval; - bool error = false; - - numitems = PyList_GET_SIZE(other); - - /* copy the first part of the list */ - listval_new->Resize(numitems_orig + numitems); - for (i=0;iSetValue(i, listval->GetValue(i)->AddRef()); - - for (i=0;iConvertPythonToValue(PyList_GET_ITEM(other, i), true, "cList + pyList: CListValue, "); - - if (listitemval) { - listval_new->SetValue(i+numitems_orig, listitemval); - } else { - error= true; - break; - } - } - - if (error) { - listval_new->Resize(numitems_orig+i); /* resize so we don't try release NULL pointers */ - listval_new->Release(); - return NULL; /* ConvertPythonToValue above sets the error */ - } - - } - else if (PyObject_TypeCheck(other, &CListValue::Type)) { - // add items from otherlist to this list - CListValue* otherval = static_cast(BGE_PROXY_REF(other)); - if (otherval==NULL) { - listval_new->Release(); - PyErr_SetString(PyExc_SystemError, "CList+other, " BGE_PROXY_ERROR_MSG); - return NULL; - } - - numitems = otherval->GetCount(); - - /* copy the first part of the list */ - listval_new->Resize(numitems_orig + numitems); /* resize so we don't try release NULL pointers */ - for (i=0;iSetValue(i, listval->GetValue(i)->AddRef()); - - /* now copy the other part of the list */ - for (i=0;iSetValue(i+numitems_orig, otherval->GetValue(i)->AddRef()); - - } - return listval_new->NewProxy(true); /* python owns this list */ -} - -static int listvalue_buffer_contains(PyObject *self_v, PyObject *value) -{ - CListValue *self = static_cast(BGE_PROXY_REF(self_v)); - - if (self == NULL) { - PyErr_SetString(PyExc_SystemError, "val in CList, " BGE_PROXY_ERROR_MSG); - return -1; - } - - if (PyUnicode_Check(value)) { - if (self->FindValue((const char *)_PyUnicode_AsString(value))) { - return 1; - } - } - else if (PyObject_TypeCheck(value, &CValue::Type)) { /* not dict like at all but this worked before __contains__ was used */ - CValue *item= static_cast(BGE_PROXY_REF(value)); - for (int i=0; i < self->GetCount(); i++) - if (self->GetValue(i) == item) // Com - return 1; - - } // not using CheckEqual - - return 0; -} - - -static PySequenceMethods listvalue_as_sequence = { - listvalue_bufferlen,//(inquiry)buffer_length, /*sq_length*/ - listvalue_buffer_concat, /*sq_concat*/ - NULL, /*sq_repeat*/ - listvalue_buffer_item, /*sq_item*/ -// TODO, slicing in py3 - NULL, // listvalue_buffer_slice, /*sq_slice*/ - NULL, /*sq_ass_item*/ - NULL, /*sq_ass_slice*/ - (objobjproc)listvalue_buffer_contains, /* sq_contains */ - (binaryfunc) NULL, /* sq_inplace_concat */ - (ssizeargfunc) NULL, /* sq_inplace_repeat */ -}; - - - -/* Is this one used ? */ -static PyMappingMethods instance_as_mapping = { - listvalue_bufferlen, /*mp_length*/ - listvalue_mapping_subscript, /*mp_subscript*/ - NULL /*mp_ass_subscript*/ -}; - - - -PyTypeObject CListValue::Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "CListValue", /*tp_name*/ - sizeof(PyObjectPlus_Proxy), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /* methods */ - py_base_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - py_base_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - &listvalue_as_sequence, /*tp_as_sequence*/ - &instance_as_mapping, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call */ - 0, - NULL, - NULL, - 0, - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, - Methods, - 0, - 0, - &CValue::Type, - 0,0,0,0,0,0, - py_base_new -}; - -PyMethodDef CListValue::Methods[] = { - /* List style access */ - {"append", (PyCFunction)CListValue::sPyappend,METH_O}, - {"reverse", (PyCFunction)CListValue::sPyreverse,METH_NOARGS}, - {"index", (PyCFunction)CListValue::sPyindex,METH_O}, - {"count", (PyCFunction)CListValue::sPycount,METH_O}, - - /* Dict style access */ - {"get", (PyCFunction)CListValue::sPyget,METH_VARARGS}, - - /* Own cvalue funcs */ - {"from_id", (PyCFunction)CListValue::sPyfrom_id,METH_O}, - - {NULL,NULL} //Sentinel -}; - -PyAttributeDef CListValue::Attributes[] = { - { NULL } //Sentinel -}; - -PyObject *CListValue::Pyappend(PyObject *value) -{ - CValue *objval = ConvertPythonToValue(value, true, "CList.append(i): CValueList, "); - - if (!objval) /* ConvertPythonToValue sets the error */ - return NULL; - - if (!BGE_PROXY_PYOWNS(m_proxy)) { - PyErr_SetString(PyExc_TypeError, - "CList.append(i): internal values can't be modified"); - return NULL; - } - - Add(objval); - - Py_RETURN_NONE; -} - -PyObject *CListValue::Pyreverse() -{ - if (!BGE_PROXY_PYOWNS(m_proxy)) { - PyErr_SetString(PyExc_TypeError, - "CList.reverse(): internal values can't be modified"); - return NULL; - } - - std::reverse(m_pValueArray.begin(),m_pValueArray.end()); - Py_RETURN_NONE; -} - -PyObject *CListValue::Pyindex(PyObject *value) -{ - PyObject *result = NULL; - - CValue *checkobj = ConvertPythonToValue(value, true, "val = cList[i]: CValueList, "); - if (checkobj==NULL) - return NULL; /* ConvertPythonToValue sets the error */ - - int numelem = GetCount(); - for (int i=0;iRelease(); - - if (result==NULL) { - PyErr_SetString(PyExc_ValueError, "CList.index(x): x not in CListValue"); - } - return result; - -} - - - -PyObject *CListValue::Pycount(PyObject *value) -{ - int numfound = 0; - - CValue *checkobj = ConvertPythonToValue(value, false, ""); /* error ignored */ - - if (checkobj==NULL) { /* in this case just return that there are no items in the list */ - PyErr_Clear(); - return PyLong_FromLong(0); - } - - int numelem = GetCount(); - for (int i=0;iRelease(); - - return PyLong_FromLong(numfound); -} - -/* Matches python dict.get(key, [default]) */ -PyObject *CListValue::Pyget(PyObject *args) -{ - char *key; - PyObject *def = Py_None; - - if (!PyArg_ParseTuple(args, "s|O:get", &key, &def)) - return NULL; - - CValue *item = FindValue((const char *)key); - if (item) { - PyObject *pyobj = item->ConvertValueToPython(); - if (pyobj) - return pyobj; - else - return item->GetProxy(); - } - Py_INCREF(def); - return def; -} - - -PyObject *CListValue::Pyfrom_id(PyObject *value) -{ - uintptr_t id= (uintptr_t)PyLong_AsVoidPtr(value); - - if (PyErr_Occurred()) - return NULL; - - int numelem = GetCount(); - for (int i=0;i(m_pValueArray[i]->m_proxy) == id) - return GetValue(i)->GetProxy(); - } - PyErr_SetString(PyExc_IndexError, "from_id(#): id not found in CValueList"); - return NULL; - -} - -#endif // WITH_PYTHON diff --git a/source/gameengine/Expressions/intern/ListWrapper.cpp b/source/gameengine/Expressions/intern/ListWrapper.cpp deleted file mode 100644 index db1518a4388f..000000000000 --- a/source/gameengine/Expressions/intern/ListWrapper.cpp +++ /dev/null @@ -1,424 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Contributor(s): Porteries Tristan. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file ListWrapper.cpp - * \ingroup expressions - */ - -#ifdef WITH_PYTHON - -#include "EXP_ListWrapper.h" - -static STR_String pythonGeneratorList = "ListWrapper"; - -CListWrapper::CListWrapper(void *client, - PyObject *base, - bool (*checkValid)(void *), - int (*getSize)(void *), - PyObject *(*getItem)(void *, int), - const char *(*getItemName)(void *, int), - bool (*setItem)(void *, int, PyObject *)) -:m_client(client), -m_base(base), -m_checkValid(checkValid), -m_getSize(getSize), -m_getItem(getItem), -m_getItemName(getItemName), -m_setItem(setItem) -{ - // Incref to always have a existing pointer. - Py_INCREF(m_base); -} - -CListWrapper::~CListWrapper() -{ - Py_DECREF(m_base); -} - -bool CListWrapper::CheckValid() -{ - if (m_base && !BGE_PROXY_REF(m_base)) { - return false; - } - return m_checkValid ? (*m_checkValid)(m_client) : true; -} - -int CListWrapper::GetSize() -{ - return (*m_getSize)(m_client); -} - -PyObject *CListWrapper::GetItem(int index) -{ - return (*m_getItem)(m_client, index); -} - -const char *CListWrapper::GetItemName(int index) -{ - return (*m_getItemName)(m_client, index); -} - -bool CListWrapper::SetItem(int index, PyObject *item) -{ - return (*m_setItem)(m_client, index, item); -} - -bool CListWrapper::AllowSetItem() -{ - return m_setItem != NULL; -} - -bool CListWrapper::AllowGetItemByName() -{ - return m_getItemName != NULL; -} - -// ================================================================ - -const STR_String &CListWrapper::GetText() -{ - return pythonGeneratorList; -} - -void CListWrapper::SetName(const char *name) -{ -} - -STR_String &CListWrapper::GetName() -{ - return pythonGeneratorList; -} - -CValue *CListWrapper::GetReplica() -{ - return NULL; -} - -CValue *CListWrapper::Calc(VALUE_OPERATOR op, CValue *val) -{ - return NULL; -} - -CValue *CListWrapper::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val) -{ - return NULL; -} - -double CListWrapper::GetNumber() -{ - return -1; -} - -int CListWrapper::GetValueType() -{ - return -1; -} - -// We convert all elements to python objects to make a proper repr string. -PyObject *CListWrapper::py_repr() -{ - if (!CheckValid()) { - PyErr_SetString(PyExc_SystemError, "CListWrapper : repr, " BGE_PROXY_ERROR_MSG); - return NULL; - } - - PyObject *py_proxy = GetProxy(); - PyObject *py_list = PySequence_List(py_proxy); - PyObject *py_string = PyObject_Repr(py_list); - Py_DECREF(py_list); - Py_DECREF(py_proxy); - return py_string; -} - - -Py_ssize_t CListWrapper::py_len(PyObject *self) -{ - CListWrapper *list = (CListWrapper *)BGE_PROXY_REF(self); - // Invalid list. - if (!list->CheckValid()) { - PyErr_SetString(PyExc_SystemError, "len(CListWrapper), " BGE_PROXY_ERROR_MSG); - return 0; - } - - return (Py_ssize_t)list->GetSize(); -} - -PyObject *CListWrapper::py_get_item(PyObject *self, Py_ssize_t index) -{ - CListWrapper *list = (CListWrapper *)BGE_PROXY_REF(self); - // Invalid list. - if (!list->CheckValid()) { - PyErr_SetString(PyExc_SystemError, "val = CListWrapper[i], " BGE_PROXY_ERROR_MSG); - return NULL; - } - - int size = list->GetSize(); - - if (index < 0) { - index = size + index; - } - if (index < 0 || index >= size) { - PyErr_SetString(PyExc_IndexError, "CListWrapper[i]: List index out of range in CListWrapper"); - return NULL; - } - - PyObject *pyobj = list->GetItem(index); - - return pyobj; -} - -int CListWrapper::py_set_item(PyObject *self, Py_ssize_t index, PyObject *value) -{ - CListWrapper *list = (CListWrapper *)BGE_PROXY_REF(self); - // Invalid list. - if (!list->CheckValid()) { - PyErr_SetString(PyExc_SystemError, "CListWrapper[i] = val, " BGE_PROXY_ERROR_MSG); - return -1; - } - - if (!list->AllowSetItem()) { - PyErr_SetString(PyExc_TypeError, "CListWrapper's item type doesn't support assignment"); - return -1; - } - - if (!value) { - PyErr_SetString(PyExc_TypeError, "CListWrapper doesn't support item deletion"); - return -1; - } - - int size = list->GetSize(); - - if (index < 0) { - index = size + index; - } - if (index < 0 || index >= size) { - PyErr_SetString(PyExc_IndexError, "CListWrapper[i]: List index out of range in CListWrapper"); - return -1; - } - - if (!list->SetItem(index, value)) { - return -1; - } - return 0; -} - -PyObject *CListWrapper::py_mapping_subscript(PyObject *self, PyObject *key) -{ - CListWrapper *list = (CListWrapper *)BGE_PROXY_REF(self); - // Invalid list. - if (!list->CheckValid()) { - PyErr_SetString(PyExc_SystemError, "val = CListWrapper[key], " BGE_PROXY_ERROR_MSG); - return NULL; - } - - if (PyIndex_Check(key)) { - Py_ssize_t index = PyLong_AsSsize_t(key); - return py_get_item(self, index); - } - else if (PyUnicode_Check(key)) { - if (!list->AllowGetItemByName()) { - PyErr_SetString(PyExc_SystemError, "CListWrapper's item type doesn't support access by key"); - return NULL; - } - - const char *name = _PyUnicode_AsString(key); - int size = list->GetSize(); - - for (unsigned int i = 0; i < size; ++i) { - if (strcmp(list->GetItemName(i), name) == 0) { - return list->GetItem(i); - } - } - - PyErr_Format(PyExc_KeyError, "requested item \"%s\" does not exist", name); - return NULL; - } - - PyErr_Format(PyExc_KeyError, "CListWrapper[key]: '%R' key not in list", key); - return NULL; -} - -int CListWrapper::py_mapping_ass_subscript(PyObject *self, PyObject *key, PyObject *value) -{ - CListWrapper *list = (CListWrapper *)BGE_PROXY_REF(self); - // Invalid list. - if (!list->CheckValid()) { - PyErr_SetString(PyExc_SystemError, "val = CListWrapper[key], " BGE_PROXY_ERROR_MSG); - return -1; - } - - if (!list->AllowSetItem()) { - PyErr_SetString(PyExc_TypeError, "CListWrapper's item type doesn't support assignment"); - return -1; - } - - if (PyIndex_Check(key)) { - Py_ssize_t index = PyLong_AsSsize_t(key); - return py_set_item(self, index, value); - } - else if (PyUnicode_Check(key)) { - if (!list->AllowGetItemByName()) { - PyErr_SetString(PyExc_SystemError, "CListWrapper's item type doesn't support access by key"); - return -1; - } - - const char *name = _PyUnicode_AsString(key); - int size = list->GetSize(); - - for (unsigned int i = 0; i < size; ++i) { - if (strcmp(list->GetItemName(i), name) == 0) { - if (!list->SetItem(i, value)) { - return -1; - } - return 0; - } - } - - PyErr_Format(PyExc_KeyError, "requested item \"%s\" does not exist", name); - return -1; - } - - PyErr_Format(PyExc_KeyError, "CListWrapper[key]: '%R' key not in list", key); - return -1; -} - -int CListWrapper::py_contains(PyObject *self, PyObject *key) -{ - CListWrapper *list = (CListWrapper *)BGE_PROXY_REF(self); - // Invalid list. - if (!list->CheckValid()) { - PyErr_SetString(PyExc_SystemError, "val = CListWrapper[i], " BGE_PROXY_ERROR_MSG); - return -1; - } - - if (!list->AllowGetItemByName()) { - PyErr_SetString(PyExc_SystemError, "CListWrapper's item type doesn't support access by key"); - return -1; - } - - if (!PyUnicode_Check(key)) { - PyErr_SetString(PyExc_SystemError, "key in list, CListWrapper: key must be a string"); - return -1; - } - - const char *name = _PyUnicode_AsString(key); - int size = list->GetSize(); - - for (unsigned int i = 0; i < size; ++i) { - if (strcmp(list->GetItemName(i), name) == 0) { - return 1; - } - } - - return 0; -} - -PySequenceMethods CListWrapper::py_as_sequence = { - py_len, // sq_length - NULL, // sq_concat - NULL, // sq_repeat - py_get_item, // sq_item - NULL, // sq_slice - py_set_item, // sq_ass_item - NULL, // sq_ass_slice - (objobjproc)py_contains, // sq_contains - (binaryfunc) NULL, // sq_inplace_concat - (ssizeargfunc) NULL, // sq_inplace_repeat -}; - -PyMappingMethods CListWrapper::py_as_mapping = { - py_len, // mp_length - py_mapping_subscript, // mp_subscript - py_mapping_ass_subscript // mp_ass_subscript -}; - -PyTypeObject CListWrapper::Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "CListWrapper", // tp_name - sizeof(PyObjectPlus_Proxy), // tp_basicsize - 0, // tp_itemsize - py_base_dealloc, // tp_dealloc - 0, // tp_print - 0, // tp_getattr - 0, // tp_setattr - 0, // tp_compare - py_base_repr, // tp_repr - 0, // tp_as_number - &py_as_sequence, // tp_as_sequence - &py_as_mapping, // tp_as_mapping - 0, // tp_hash - 0, // tp_call - 0, - NULL, - NULL, - 0, - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, - Methods, - 0, - 0, - &CValue::Type, - 0,0,0,0,0,0, - py_base_new -}; - -PyMethodDef CListWrapper::Methods[] = { - {"get", (PyCFunction)CListWrapper::sPyGet, METH_VARARGS}, - {NULL, NULL} //Sentinel -}; - -PyAttributeDef CListWrapper::Attributes[] = { - {NULL} //Sentinel -}; - -/* Matches python dict.get(key, [default]) */ -PyObject *CListWrapper::PyGet(PyObject *args) -{ - char *name; - PyObject *def = Py_None; - - // Invalid list. - if (!CheckValid()) { - PyErr_SetString(PyExc_SystemError, "val = CListWrapper[i], " BGE_PROXY_ERROR_MSG); - return NULL; - } - - if (!AllowGetItemByName()) { - PyErr_SetString(PyExc_SystemError, "CListWrapper's item type doesn't support access by key"); - return NULL; - } - - if (!PyArg_ParseTuple(args, "s|O:get", &name, &def)) { - return NULL; - } - - for (unsigned int i = 0; i < GetSize(); ++i) { - if (strcmp(GetItemName(i), name) == 0) { - return GetItem(i); - } - } - - Py_INCREF(def); - return def; -} - -#endif // WITH_PYTHON diff --git a/source/gameengine/Expressions/intern/Operator1Expr.cpp b/source/gameengine/Expressions/intern/Operator1Expr.cpp index 11bb2c06caf7..daf06b8e04cc 100644 --- a/source/gameengine/Expressions/intern/Operator1Expr.cpp +++ b/source/gameengine/Expressions/intern/Operator1Expr.cpp @@ -1,7 +1,7 @@ /** \file gameengine/Expressions/Operator1Expr.cpp * \ingroup expressions */ -// Operator1Expr.cpp: implementation of the COperator1Expr class. +// Operator1Expr.cpp: implementation of the EXP_Operator1Expr class. /* * Copyright (c) 1996-2000 Erwin Coumans * @@ -18,134 +18,37 @@ #include "EXP_Operator1Expr.h" #include "EXP_EmptyValue.h" -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -COperator1Expr::COperator1Expr() -/* -pre: -effect: constucts an empty COperator1Expr -*/ -{ - m_lhs = NULL; -} - -COperator1Expr::COperator1Expr(VALUE_OPERATOR op, CExpression *lhs) -/* -pre: -effect: constucts a COperator1Expr with op and lhs in it -*/ +EXP_Operator1Expr::EXP_Operator1Expr() + :m_lhs(nullptr) { - m_lhs = lhs; - m_op = op; } -COperator1Expr::~COperator1Expr() -/* -pre: -effect: deletes the object -*/ +EXP_Operator1Expr::EXP_Operator1Expr(VALUE_OPERATOR op, EXP_Expression *lhs) + :m_op(op), + m_lhs(lhs) { - if (m_lhs) m_lhs->Release(); } -CValue * COperator1Expr::Calculate() -/* -pre: -ret: a new object containing the result of applying the operator m_op to the - value of m_lhs -*/ +EXP_Operator1Expr::~EXP_Operator1Expr() { - CValue *ret; - CValue *temp = m_lhs->Calculate(); - CValue* empty = new CEmptyValue(); - ret = empty->Calc(m_op, temp); - empty->Release(); - temp->Release(); - - return ret; -} - -/* -bool COperator1Expr::IsInside(float x, float y, float z,bool bBorderInclude) -{ - - bool result = true; - switch (m_op) - { - - case VALUE_ADD_OPERATOR: - { - - if (m_lhs) - { - result = result || m_lhs->IsInside(x,y,z,bBorderInclude); - } - break; - } - case VALUE_SUB_OPERATOR: - { - result = true; - if (m_lhs) - { - result = result && (!m_lhs->IsInside(x,y,z,bBorderInclude)); - } - break; - } + if (m_lhs) { + m_lhs->Release(); } - return result; } -*/ -bool COperator1Expr::NeedsRecalculated() +unsigned char EXP_Operator1Expr::GetExpressionID() { - return m_lhs->NeedsRecalculated(); + return COPERATOR1EXPRESSIONID; } -CExpression* COperator1Expr::CheckLink(std::vector& brokenlinks) +EXP_Value *EXP_Operator1Expr::Calculate() { + EXP_Value *temp = m_lhs->Calculate(); + EXP_Value *empty = new EXP_EmptyValue(); + EXP_Value *ret = empty->Calc(m_op, temp); - CExpression* newlhs = m_lhs->CheckLink(brokenlinks); - - if (newlhs) - { - if (newlhs==m_lhs) { - // not changed - } else { - // changed - //numchanges++; - newlhs->AddRef(); - - //m_lhs->Release(); - brokenlinks.push_back(new CBrokenLinkInfo(&m_lhs,m_lhs)); - - m_lhs = newlhs; - } - return this; - } else { - //numchanges++; - AddRef(); - - return Release(); - } - -} - -void COperator1Expr::BroadcastOperators(VALUE_OPERATOR op) -{ - if (m_lhs) - m_lhs->BroadcastOperators(m_op); -} - - - - -bool COperator1Expr::MergeExpression(CExpression *otherexpr) -{ - if (m_lhs) - return m_lhs->MergeExpression(otherexpr); + empty->Release(); + temp->Release(); - assertd(false); // should not get here, expression is not compatible for merge - return false; + return ret; } diff --git a/source/gameengine/Expressions/intern/Operator2Expr.cpp b/source/gameengine/Expressions/intern/Operator2Expr.cpp index aaf6f49943d0..cb60f34ffd08 100644 --- a/source/gameengine/Expressions/intern/Operator2Expr.cpp +++ b/source/gameengine/Expressions/intern/Operator2Expr.cpp @@ -1,7 +1,7 @@ /** \file gameengine/Expressions/Operator2Expr.cpp * \ingroup expressions */ -// Operator2Expr.cpp: implementation of the COperator2Expr class. +// Operator2Expr.cpp: implementation of the EXP_Operator2Expr class. /* * Copyright (c) 1996-2000 Erwin Coumans * @@ -14,263 +14,48 @@ * purpose. It is provided "as is" without express or implied warranty. * */ -// 31 dec 1998 - big update: try to use the cached data for updating, instead of -// rebuilding completely it from left and right node. Modified flags and bounding boxes -// have to do the trick -// when expression is cached, there will be a call to UpdateCalc() instead of Calc() #include "EXP_Operator2Expr.h" #include "EXP_StringValue.h" -#include "EXP_VoidValue.h" -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -COperator2Expr::COperator2Expr(VALUE_OPERATOR op, CExpression *lhs, CExpression *rhs) -: -m_rhs(rhs), -m_lhs(lhs), -m_cached_calculate(NULL), -m_op(op) -/* -pre: -effect: constucts a COperator2Expr with op, lhs and rhs in it -*/ +EXP_Operator2Expr::EXP_Operator2Expr(VALUE_OPERATOR op, EXP_Expression *lhs, EXP_Expression *rhs) + :m_rhs(rhs), + m_lhs(lhs), + m_op(op) { - } -COperator2Expr::COperator2Expr(): -m_rhs(NULL), -m_lhs(NULL), -m_cached_calculate(NULL) - -/* -pre: -effect: constucts an empty COperator2Expr -*/ +EXP_Operator2Expr::EXP_Operator2Expr() : + m_rhs(nullptr), + m_lhs(nullptr) { - } -COperator2Expr::~COperator2Expr() -/* -pre: -effect: deletes the object -*/ +EXP_Operator2Expr::~EXP_Operator2Expr() { - if (m_lhs) + if (m_lhs) { m_lhs->Release(); - if (m_rhs) - m_rhs->Release(); - if (m_cached_calculate) - m_cached_calculate->Release(); - -} -CValue* COperator2Expr::Calculate() -/* -pre: -ret: a new object containing the result of applying operator m_op to m_lhs -and m_rhs -*/ -{ - - bool leftmodified,rightmodified; - leftmodified = m_lhs->NeedsRecalculated(); - rightmodified = m_rhs->NeedsRecalculated(); - - // if no modifications on both left and right subtree, and result is already calculated - // then just return cached result... - if (!leftmodified && !rightmodified && (m_cached_calculate)) - { - // not modified, just return m_cached_calculate - } else { - // if not yet calculated, or modified... - - - if (m_cached_calculate) { - m_cached_calculate->Release(); - m_cached_calculate=NULL; - } - - CValue* ffleft = m_lhs->Calculate(); - CValue* ffright = m_rhs->Calculate(); - - ffleft->SetOwnerExpression(this);//->m_pOwnerExpression=this; - ffright->SetOwnerExpression(this);//->m_pOwnerExpression=this; - - m_cached_calculate = ffleft->Calc(m_op,ffright); - - //if (m_cached_calculate) - // m_cached_calculate->Action(CValue::SETOWNEREXPR,&CVoidValue(this,false,CValue::STACKVALUE)); - - ffleft->Release(); - ffright->Release(); } - - return m_cached_calculate->AddRef(); - -} - -#if 0 -bool COperator2Expr::IsInside(float x, float y, float z,bool bBorderInclude) -{ - bool inside; - inside = false; - - switch (m_op) { - case VALUE_ADD_OPERATOR: - { - // inside = first || second; // optimized with early out if first is inside - // todo: calculate smallest leaf first ! is much faster... - - bool second;//first ;//,second; - - //first = m_lhs->IsInside(x,y,z); - second = m_rhs->IsInside(x,y,z,bBorderInclude); - if (second) - return true; //early out - - // second = m_rhs->IsInside(x,y,z); - - return m_lhs->IsInside(x,y,z,bBorderInclude); - - break; - } - - case VALUE_SUB_OPERATOR: - { - //inside = first && !second; // optimized with early out - // todo: same as with add_operator: calc smallest leaf first - - bool second;//first ;//,second; - //first = m_lhs->IsInside(x,y,z); - second = m_rhs->IsInside(x,y,z,bBorderInclude); - if (second) - return false; - - // second space get subtracted -> negate! - //second = m_rhs->IsInside(x,y,z); - - return (m_lhs->IsInside(x,y,z,bBorderInclude)); - - - break; - } - default: - { - assert(false); - // not yet implemented, only add or sub csg operations - } + if (m_rhs) { + m_rhs->Release(); } - - return inside; -} - -bool COperator2Expr::IsRightInside(float x, float y, float z,bool bBorderInclude) -{ - return m_rhs->IsInside(x,y,z,bBorderInclude); -} - -bool COperator2Expr::IsLeftInside(float x, float y, float z,bool bBorderInclude) -{ - return m_lhs->IsInside(x,y,z,bBorderInclude); } -#endif -bool COperator2Expr::NeedsRecalculated() +unsigned char EXP_Operator2Expr::GetExpressionID() { - // added some lines, just for debugging purposes, it could be a one-liner :) - //bool modleft - //bool modright; - assertd(m_lhs); - assertd(m_rhs); - - //modright = m_rhs->NeedsRecalculated(); - if (m_rhs->NeedsRecalculated()) // early out - return true; - return m_lhs->NeedsRecalculated(); - //modleft = m_lhs->NeedsRecalculated(); - //return (modleft || modright); - + return COPERATOR2EXPRESSIONID; } - - -CExpression* COperator2Expr::CheckLink(std::vector& brokenlinks) +EXP_Value *EXP_Operator2Expr::Calculate() { -// if both children are 'dead', return NULL -// if only one child is alive, return that child -// if both childresn are alive, return this - - -// bool leftalive = true,rightalive=true; - /* Does this mean the function will always bomb? */ - assertd(false); - assert(m_lhs); - assert(m_rhs); -/* - if (m_cached_calculate) - m_cached_calculate->Action(CValue::REFRESH_CACHE); - - CExpression* newlhs = m_lhs->CheckLink(brokenlinks); - CExpression* newrhs = m_rhs->CheckLink(brokenlinks); - if (m_lhs != newlhs) - { - brokenlinks.push_back(new CBrokenLinkInfo(&m_lhs,m_lhs)); - } - - if (m_rhs != newrhs) - { - brokenlinks.push_back(new CBrokenLinkInfo(&m_rhs,m_rhs)); - } - - - - m_lhs = newlhs; - m_rhs = newrhs; - - if (m_lhs && m_rhs) { - return this; - } - - AddRef(); - if (m_lhs) - return Release(m_lhs->AddRef()); + EXP_Value *ffleft = m_lhs->Calculate(); + EXP_Value *ffright = m_rhs->Calculate(); - if (m_rhs) - return Release(m_rhs->AddRef()); -/ + EXP_Value *calculate = ffleft->Calc(m_op, ffright); - */ - return Release(); -} - - -bool COperator2Expr::MergeExpression(CExpression *otherexpr) -{ - if (m_lhs) - { - if (m_lhs->GetExpressionID() == CExpression::CCONSTEXPRESSIONID) - { - // cross fingers ;) replace constexpr by new tree... - m_lhs->Release(); - m_lhs = otherexpr->AddRef(); - return true; - } - } + ffleft->Release(); + ffright->Release(); - assertd(false); - return false; -} - - -void COperator2Expr::BroadcastOperators(VALUE_OPERATOR op) -{ - if (m_lhs) - m_lhs->BroadcastOperators(m_op); - if (m_rhs) - m_rhs->BroadcastOperators(m_op); + return calculate; } diff --git a/source/gameengine/Expressions/intern/PyObjectPlus.cpp b/source/gameengine/Expressions/intern/PyObjectPlus.cpp index 317faac7fa9b..189ccbf357d7 100644 --- a/source/gameengine/Expressions/intern/PyObjectPlus.cpp +++ b/source/gameengine/Expressions/intern/PyObjectPlus.cpp @@ -25,13 +25,13 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file gameengine/Expressions/PyObjectPlus.cpp +/** \file gameengine/Expressions/EXP_PyObjectPlus.cpp * \ingroup expressions */ /*------------------------------ - * PyObjectPlus cpp + * EXP_PyObjectPlus cpp * * C++ library routines for Crawl 3.2 * @@ -44,38 +44,32 @@ * http://www.python.org/doc/PyCPP.html * * ----------------------------- */ -#include -#include #include "EXP_PyObjectPlus.h" -#include "STR_String.h" -#include "MT_Vector3.h" #include "MEM_guardedalloc.h" -PyObjectPlus::~PyObjectPlus() +#include "CM_Message.h" + +EXP_PyObjectPlus::EXP_PyObjectPlus() { -#ifdef WITH_PYTHON - if (m_proxy) { - BGE_PROXY_REF(m_proxy)= NULL; - Py_DECREF(m_proxy); /* Remove own reference, python may still have 1 */ - } -// assert(ob_refcnt==0); -#endif + #ifdef WITH_PYTHON + m_proxy = nullptr; + #endif } -PyObjectPlus::PyObjectPlus() : SG_QList() // constructor +EXP_PyObjectPlus::~EXP_PyObjectPlus() { #ifdef WITH_PYTHON - m_proxy= NULL; + InvalidateProxy(); #endif -}; +} -void PyObjectPlus::ProcessReplica() +void EXP_PyObjectPlus::ProcessReplica() { #ifdef WITH_PYTHON /* Clear the proxy, will be created again if needed with GetProxy() * otherwise the PyObject will point to the wrong reference */ - m_proxy= NULL; + m_proxy = nullptr; #endif } @@ -87,43 +81,52 @@ void PyObjectPlus::ProcessReplica() * and will raise an error on access. However if python can get access * to this class again it will make a new proxy and work as expected. */ -void PyObjectPlus::InvalidateProxy() // check typename of each parent +void EXP_PyObjectPlus::InvalidateProxy() // check typename of each parent { #ifdef WITH_PYTHON if (m_proxy) { - BGE_PROXY_REF(m_proxy)=NULL; - Py_DECREF(m_proxy); - m_proxy= NULL; + EXP_PROXY_REF(m_proxy) = nullptr; + // Decrement proxy only if python doesn't own it. + if (!EXP_PROXY_PYOWNS(m_proxy)) { + Py_DECREF(m_proxy); + } + m_proxy = nullptr; } #endif } +void EXP_PyObjectPlus::DestructFromPython() +{ +#ifdef WITH_PYTHON + delete this; +#endif +} #ifdef WITH_PYTHON /*------------------------------ - * PyObjectPlus Type -- Every class, even the abstract one should have a Type + * EXP_PyObjectPlus Type -- Every class, even the abstract one should have a Type * ----------------------------- */ -PyTypeObject PyObjectPlus::Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "PyObjectPlus", /*tp_name*/ - sizeof(PyObjectPlus_Proxy), /*tp_basicsize*/ - 0, /*tp_itemsize*/ +PyTypeObject EXP_PyObjectPlus::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "EXP_PyObjectPlus", /*tp_name*/ + sizeof(EXP_PyObjectPlus_Proxy), /*tp_basicsize*/ + 0, /*tp_itemsize*/ /* methods */ - py_base_dealloc, /* tp_dealloc */ - 0, /* printfunc tp_print; */ - 0, /* getattrfunc tp_getattr; */ - 0, /* setattrfunc tp_setattr; */ - 0, /* tp_compare */ /* DEPRECATED in python 3.0! */ - py_base_repr, /* tp_repr */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Method suites for standard classes */ + py_base_dealloc, /* tp_dealloc */ + 0, /* printfunc tp_print; */ + 0, /* getattrfunc tp_getattr; */ + 0, /* setattrfunc tp_setattr; */ + 0, /* tp_compare */ /* DEPRECATED in python 3.0! */ + py_base_repr, /* tp_repr */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Method suites for standard classes */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* long tp_flags; */ 0, 0, 0, 0, /* weak reference enabler */ #ifdef USE_WEAKREFS - offsetof(PyObjectPlus_Proxy, in_weakreflist), /* long tp_weaklistoffset; */ + offsetof(EXP_PyObjectPlus_Proxy, in_weakreflist), /* long tp_weaklistoffset; */ #else 0, #endif @@ -131,39 +134,39 @@ PyTypeObject PyObjectPlus::Type = { Methods, 0, 0, - NULL // no subtype + nullptr // no subtype }; -PyObject *PyObjectPlus::py_base_repr(PyObject *self) // This should be the entry in Type. +/// This should be the entry in Type. +PyObject *EXP_PyObjectPlus::py_base_repr(PyObject *self) { - PyObjectPlus *self_plus= BGE_PROXY_REF(self); - if (self_plus==NULL) { - PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); - return NULL; + EXP_PyObjectPlus *self_plus = EXP_PROXY_REF(self); + if (self_plus == nullptr) { + PyErr_SetString(PyExc_SystemError, EXP_PROXY_ERROR_MSG); + return nullptr; } return self_plus->py_repr(); } -PyObject *PyObjectPlus::py_base_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +PyObject *EXP_PyObjectPlus::py_base_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyTypeObject *base_type; - /* one or more args is needed */ + // One or more args is needed. if (!PyTuple_GET_SIZE(args)) { - PyErr_SetString(PyExc_TypeError, - "Expected at least one argument"); - return NULL; + PyErr_SetString(PyExc_TypeError, "Expected at least one argument"); + return nullptr; } - PyObjectPlus_Proxy *base = (PyObjectPlus_Proxy *)PyTuple_GET_ITEM(args, 0); + EXP_PyObjectPlus_Proxy *base = (EXP_PyObjectPlus_Proxy *)PyTuple_GET_ITEM(args, 0); /** * the 'base' PyObject may be subclassed (multiple times even) * we need to find the first C++ defined class to check 'type' * is a subclass of the base arguments type. * - * This way we can share one tp_new function for every PyObjectPlus + * This way we can share one tp_new function for every EXP_PyObjectPlus * * eg. * @@ -176,279 +179,283 @@ PyObject *PyObjectPlus::py_base_new(PyTypeObject *type, PyObject *args, PyObject * ob = CustomOb(cont.owner) * \endcode * */ - base_type= Py_TYPE(base); - while (base_type && !BGE_PROXY_CHECK_TYPE(base_type)) - base_type= base_type->tp_base; + base_type = Py_TYPE(base); + while (base_type && !EXP_PROXY_CHECK_TYPE(base_type)) { + base_type = base_type->tp_base; + } - if (base_type==NULL || !BGE_PROXY_CHECK_TYPE(base_type)) { + if (base_type == nullptr || !EXP_PROXY_CHECK_TYPE(base_type)) { PyErr_SetString(PyExc_TypeError, "can't subclass from a blender game type because the argument given is not a game class or subclass"); - return NULL; + return nullptr; } - /* use base_type rather than Py_TYPE(base) because we could already be subtyped */ + // Use base_type rather than Py_TYPE(base) because we could already be subtyped. if (!PyType_IsSubtype(type, base_type)) { PyErr_Format(PyExc_TypeError, "can't subclass blender game type <%s> from <%s> because it is not a subclass", base_type->tp_name, type->tp_name); - return NULL; + return nullptr; } /* invalidate the existing base and return a new subclassed one, * this is a bit dodgy in that it also attaches its self to the existing object * which is not really 'correct' python OO but for our use its OK. */ - PyObjectPlus_Proxy *ret = (PyObjectPlus_Proxy *) type->tp_alloc(type, 0); /* starts with 1 ref, used for the return ref' */ - ret->ref= base->ref; - ret->ptr= base->ptr; - ret->py_owns= base->py_owns; + EXP_PyObjectPlus_Proxy *ret = (EXP_PyObjectPlus_Proxy *)type->tp_alloc(type, 0); // Starts with 1 ref, used for the return ref'. + ret->ref = base->ref; + ret->ptr = base->ptr; + ret->py_owns = base->py_owns; ret->py_ref = base->py_ref; if (ret->py_ref) { - base->ref= NULL; /* invalidate! disallow further access */ - base->ptr = NULL; - if (ret->ref) - ret->ref->m_proxy= NULL; + base->ref = nullptr; // Invalidate! disallow further access. + base->ptr = nullptr; + if (ret->ref) { + ret->ref->m_proxy = nullptr; + } /* 'base' may be freed after this func finished but not necessarily * there is no reference to the BGE data now so it will throw an error on access */ Py_DECREF(base); if (ret->ref) { - ret->ref->m_proxy= (PyObject *)ret; /* no need to add a ref because one is added when creating. */ - Py_INCREF(ret); /* we return a new ref but m_proxy holds a ref so we need to add one */ + ret->ref->m_proxy = (PyObject *)ret; + + // Incref the proxy in case the python doesn't own the ref. + if (!ret->py_owns) { + Py_INCREF(ret); + } + } + } + else { + // Generic structures don't hold a reference to this proxy, so don't increment ref count. + if (ret->py_owns) { + // But if the proxy owns the structure, there can be only one owner. + base->ptr = nullptr; } - } else { - // generic structures don't hold a reference to this proxy, so don't increment ref count - if (ret->py_owns) - // but if the proxy owns the structure, there can be only one owner - base->ptr= NULL; } return (PyObject *)ret; } /** - * \param self A PyObjectPlus_Proxy + * \param self A EXP_PyObjectPlus_Proxy */ -void PyObjectPlus::py_base_dealloc(PyObject *self) // python wrapper +void EXP_PyObjectPlus::py_base_dealloc(PyObject *self) { #ifdef USE_WEAKREFS - if (BGE_PROXY_WKREF(self) != NULL) - PyObject_ClearWeakRefs((PyObject *) self); + if (EXP_PROXY_WKREF(self) != nullptr) { + PyObject_ClearWeakRefs((PyObject *)self); + } #endif - if (BGE_PROXY_PYREF(self)) { - PyObjectPlus *self_plus= BGE_PROXY_REF(self); + if (EXP_PROXY_PYREF(self)) { + EXP_PyObjectPlus *self_plus = EXP_PROXY_REF(self); if (self_plus) { - if (BGE_PROXY_PYOWNS(self)) { /* Does python own this?, then delete it */ - self_plus->m_proxy = NULL; /* Need this to stop ~PyObjectPlus from decrefing m_proxy otherwise its decref'd twice and py-debug crashes */ - delete self_plus; + // Does python own this?, then delete it. + if (EXP_PROXY_PYOWNS(self)) { + self_plus->DestructFromPython(); } - BGE_PROXY_REF(self)= NULL; // not really needed + EXP_PROXY_REF(self) = nullptr; // Not really needed. } - // the generic pointer is not deleted directly, only through self_plus - BGE_PROXY_PTR(self)= NULL; // not really needed - } else { - void *ptr= BGE_PROXY_PTR(self); + // The generic pointer is not deleted directly, only through self_plus. + EXP_PROXY_PTR(self) = nullptr; // Not really needed. + } + else { + void *ptr = EXP_PROXY_PTR(self); if (ptr) { - if (BGE_PROXY_PYOWNS(self)) { /* Does python own this?, then delete it */ - // generic structure owned by python MUST be created though MEM_alloc + // Does python own this?, then delete it. + if (EXP_PROXY_PYOWNS(self)) { + // Generic structure owned by python MUST be created though MEM_alloc. MEM_freeN(ptr); } - BGE_PROXY_PTR(self)= NULL; // not really needed + EXP_PROXY_PTR(self) = nullptr; // Not really needed. } } -#if 0 - /* is ok normally but not for subtyping, use tp_free instead. */ - PyObject_DEL( self ); -#else + /* is ok normally but not for subtyping, use tp_free instead. + * PyObject_DEL(self); + */ Py_TYPE(self)->tp_free(self); -#endif }; /*------------------------------ - * PyObjectPlus Methods -- Every class, even the abstract one should have a Methods -------------------------------*/ -PyMethodDef PyObjectPlus::Methods[] = { - {NULL, NULL} /* Sentinel */ +* EXP_PyObjectPlus Methods -- Every class, even the abstract one should have a Methods + ------------------------------*/ +PyMethodDef EXP_PyObjectPlus::Methods[] = { + {nullptr, nullptr} // Sentinel }; -#define BGE_PY_ATTR_INVALID (&(PyObjectPlus::Attributes[0])) -PyAttributeDef PyObjectPlus::Attributes[] = { - KX_PYATTRIBUTE_RO_FUNCTION("invalid", PyObjectPlus, pyattr_get_invalid), - {NULL} //Sentinel +#define BGE_PY_ATTR_INVALID (&(EXP_PyObjectPlus::Attributes[0])) +PyAttributeDef EXP_PyObjectPlus::Attributes[] = { + EXP_PYATTRIBUTE_RO_FUNCTION("invalid", EXP_PyObjectPlus, pyattr_get_invalid), + EXP_PYATTRIBUTE_NULL // Sentinel }; - - -PyObject *PyObjectPlus::pyattr_get_invalid(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *EXP_PyObjectPlus::pyattr_get_invalid(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - return PyBool_FromLong(self_v ? 0:1); + return PyBool_FromLong(self_v ? 0 : 1); } -/* note, this is called as a python 'getset, where the PyAttributeDef is the closure */ -PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef *attrdef) +// Note, this is called as a python 'getset, where the PyAttributeDef is the closure. +PyObject *EXP_PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef *attrdef) { - PyObjectPlus *ref= (BGE_PROXY_REF(self_py)); - char* ptr = (attrdef->m_usePtr) ? (char*)BGE_PROXY_PTR(self_py) : (char*)ref; - if (ptr == NULL || (BGE_PROXY_PYREF(self_py) && (ref==NULL || !ref->py_is_valid()))) { - if (attrdef == BGE_PY_ATTR_INVALID) - Py_RETURN_TRUE; // don't bother running the function - - PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); - return NULL; + EXP_PyObjectPlus *ref = (EXP_PROXY_REF(self_py)); + void *vptr = (attrdef->m_usePtr) ? (char *)EXP_PROXY_PTR(self_py) : (char *)ref; + if (vptr == nullptr || (EXP_PROXY_PYREF(self_py) && (ref == nullptr || !ref->py_is_valid()))) { + if (attrdef == BGE_PY_ATTR_INVALID) { + Py_RETURN_TRUE; // Don't bother running the function. + } + PyErr_SetString(PyExc_SystemError, EXP_PROXY_ERROR_MSG); + return nullptr; } - if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_DUMMY) - { - // fake attribute, ignore - return NULL; - } - if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_FUNCTION) - { - // the attribute has no field correspondence, handover processing to function. - if (attrdef->m_getFunction == NULL) - return NULL; - return (*attrdef->m_getFunction)(ptr, attrdef); + if (attrdef->m_type == EXP_PYATTRIBUTE_TYPE_FUNCTION) { + // The attribute has no field correspondence, handover processing to function. + if (attrdef->m_getFunction == nullptr) { + return nullptr; + } + return (*attrdef->m_getFunction)(static_cast(vptr), attrdef); } + char *ptr = static_cast (vptr); ptr += attrdef->m_offset; - if (attrdef->m_length > 1) - { + if (attrdef->m_length > 1) { PyObject *resultlist = PyList_New(attrdef->m_length); - for (unsigned int i=0; im_length; i++) + for (unsigned int i = 0; i < attrdef->m_length; i++) { switch (attrdef->m_type) { - case KX_PYATTRIBUTE_TYPE_BOOL: + case EXP_PYATTRIBUTE_TYPE_BOOL: { - bool *val = reinterpret_cast(ptr); + bool *val = reinterpret_cast(ptr); ptr += sizeof(bool); PyList_SET_ITEM(resultlist, i, PyBool_FromLong(*val)); break; } - case KX_PYATTRIBUTE_TYPE_SHORT: + case EXP_PYATTRIBUTE_TYPE_SHORT: { - short int *val = reinterpret_cast(ptr); + short int *val = reinterpret_cast(ptr); ptr += sizeof(short int); PyList_SET_ITEM(resultlist, i, PyLong_FromLong(*val)); break; } - case KX_PYATTRIBUTE_TYPE_ENUM: - // enum are like int, just make sure the field size is the same - if (sizeof(int) != attrdef->m_size) + case EXP_PYATTRIBUTE_TYPE_ENUM: { - Py_DECREF(resultlist); - return NULL; + // Enum are like int, just make sure the field size is the same. + if (sizeof(int) != attrdef->m_size) { + Py_DECREF(resultlist); + return nullptr; + } + ATTR_FALLTHROUGH; } - ATTR_FALLTHROUGH; - case KX_PYATTRIBUTE_TYPE_INT: + case EXP_PYATTRIBUTE_TYPE_INT: { - int *val = reinterpret_cast(ptr); + int *val = reinterpret_cast(ptr); ptr += sizeof(int); PyList_SET_ITEM(resultlist, i, PyLong_FromLong(*val)); break; } - case KX_PYATTRIBUTE_TYPE_FLOAT: + case EXP_PYATTRIBUTE_TYPE_FLOAT: { - float *val = reinterpret_cast(ptr); + float *val = reinterpret_cast(ptr); ptr += sizeof(float); PyList_SET_ITEM(resultlist, i, PyFloat_FromDouble(*val)); break; } - default: - // no support for array of complex data - Py_DECREF(resultlist); - return NULL; + default: + // No support for array of complex data. + Py_DECREF(resultlist); + return nullptr; } } return resultlist; } - else - { + else { switch (attrdef->m_type) { - case KX_PYATTRIBUTE_TYPE_FLAG: + case EXP_PYATTRIBUTE_TYPE_FLAG: { bool bval; switch (attrdef->m_size) { - case 1: + case 1: { - unsigned char *val = reinterpret_cast(ptr); + unsigned char *val = reinterpret_cast(ptr); bval = (*val & attrdef->m_imin); break; } - case 2: + case 2: { - unsigned short *val = reinterpret_cast(ptr); + unsigned short *val = reinterpret_cast(ptr); bval = (*val & attrdef->m_imin); break; } - case 4: + case 4: { - unsigned int *val = reinterpret_cast(ptr); + unsigned int *val = reinterpret_cast(ptr); bval = (*val & attrdef->m_imin); break; } - default: - return NULL; + default: + return nullptr; } - if (attrdef->m_imax) + if (attrdef->m_imax) { bval = !bval; + } return PyBool_FromLong(bval); } - case KX_PYATTRIBUTE_TYPE_BOOL: + case EXP_PYATTRIBUTE_TYPE_BOOL: { - bool *val = reinterpret_cast(ptr); + bool *val = reinterpret_cast(ptr); return PyBool_FromLong(*val); } - case KX_PYATTRIBUTE_TYPE_SHORT: + case EXP_PYATTRIBUTE_TYPE_SHORT: { - short int *val = reinterpret_cast(ptr); + short int *val = reinterpret_cast(ptr); return PyLong_FromLong(*val); } - case KX_PYATTRIBUTE_TYPE_ENUM: - // enum are like int, just make sure the field size is the same - if (sizeof(int) != attrdef->m_size) + case EXP_PYATTRIBUTE_TYPE_ENUM: { - return NULL; + // Enum are like int, just make sure the field size is the same. + if (sizeof(int) != attrdef->m_size) { + return nullptr; + } } - ATTR_FALLTHROUGH; - case KX_PYATTRIBUTE_TYPE_INT: + ATTR_FALLTHROUGH; + case EXP_PYATTRIBUTE_TYPE_INT: { - int *val = reinterpret_cast(ptr); + int *val = reinterpret_cast(ptr); return PyLong_FromLong(*val); } - case KX_PYATTRIBUTE_TYPE_FLOAT: + case EXP_PYATTRIBUTE_TYPE_FLOAT: { - float *val = reinterpret_cast(ptr); + float *val = reinterpret_cast(ptr); if (attrdef->m_imin == 0) { if (attrdef->m_imax == 0) { return PyFloat_FromDouble(*val); - } else { - // vector, verify size - if (attrdef->m_size != attrdef->m_imax*sizeof(float)) - { - return NULL; + } + else { + // Vector, verify size. + if (attrdef->m_size != attrdef->m_imax * sizeof(float)) { + return nullptr; } #ifdef USE_MATHUTILS - return Vector_CreatePyObject(val, attrdef->m_imax, NULL); + return Vector_CreatePyObject(val, attrdef->m_imax, nullptr); #else PyObject *resultlist = PyList_New(attrdef->m_imax); - for (unsigned int i=0; im_imax; i++) + for (unsigned int i = 0; i < attrdef->m_imax; i++) { PyList_SET_ITEM(resultlist, i, PyFloat_FromDouble(val[i])); } return resultlist; #endif } - } else { - // matrix case - if (attrdef->m_size != attrdef->m_imax*attrdef->m_imin*sizeof(float)) - { - return NULL; + } + else { + // Matrix case. + if (attrdef->m_size != attrdef->m_imax * attrdef->m_imin * sizeof(float)) { + return nullptr; } #ifdef USE_MATHUTILS - return Matrix_CreatePyObject_wrap(val, attrdef->m_imin, attrdef->m_imax, NULL); + return Matrix_CreatePyObject_wrap(val, attrdef->m_imin, attrdef->m_imax, nullptr); #else PyObject *collist = PyList_New(attrdef->m_imin); - for (unsigned int i=0; im_imin; i++) + for (unsigned int i = 0; i < attrdef->m_imin; i++) { PyObject *col = PyList_New(attrdef->m_imax); - for (unsigned int j=0; jm_imax; j++) + for (unsigned int j = 0; j < attrdef->m_imax; j++) { PyList_SET_ITEM(col, j, PyFloat_FromDouble(val[j])); } @@ -459,33 +466,50 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef * #endif } } - case KX_PYATTRIBUTE_TYPE_VECTOR: + case EXP_PYATTRIBUTE_TYPE_VECTOR: { - MT_Vector3 *val = reinterpret_cast(ptr); + switch (attrdef->m_size) { + case 2: + { + mt::vec2 *val = reinterpret_cast(ptr); #ifdef USE_MATHUTILS - float fval[3]; - val->getValue(fval); - return Vector_CreatePyObject(fval, 3, NULL); + return Vector_CreatePyObject(val->Data(), 2, nullptr); #else - PyObject *resultlist = PyList_New(3); - for (unsigned int i=0; i<3; i++) - { - PyList_SET_ITEM(resultlist, i, PyFloat_FromDouble((*val)[i])); - } - return resultlist; + PyObject *resultlist = PyList_New(2); + for (unsigned int i = 0; i < 2; i++) + { + PyList_SET_ITEM(resultlist, i, PyFloat_FromDouble((*val)[i])); + } + return resultlist; #endif + } + case 3: + { + mt::vec3 *val = reinterpret_cast(ptr); +#ifdef USE_MATHUTILS + return Vector_CreatePyObject(val->Data(), 3, nullptr); +#else + PyObject *resultlist = PyList_New(3); + for (unsigned int i = 0; i < 3; i++) + { + PyList_SET_ITEM(resultlist, i, PyFloat_FromDouble((*val)[i])); + } + return resultlist; +#endif + } + } } - case KX_PYATTRIBUTE_TYPE_STRING: + case EXP_PYATTRIBUTE_TYPE_STRING: { - STR_String *val = reinterpret_cast(ptr); - return PyUnicode_From_STR_String(*val); + std::string *val = reinterpret_cast(ptr); + return PyUnicode_FromStdString(*val); } - case KX_PYATTRIBUTE_TYPE_CHAR: + case EXP_PYATTRIBUTE_TYPE_CHAR: { return PyUnicode_FromString(ptr); } - default: - return NULL; + default: + return nullptr; } } } @@ -494,675 +518,694 @@ PyObject *PyObjectPlus::py_get_attrdef(PyObject *self_py, const PyAttributeDef * static bool py_check_attr_float(float *var, PyObject *value, const PyAttributeDef *attrdef) { float val = PyFloat_AsDouble(value); - if (val == -1.0f && PyErr_Occurred()) - { - PyErr_Format(PyExc_TypeError, "expected float value for attribute \"%s\"", attrdef->m_name); + if (val == -1.0f && PyErr_Occurred()) { + PyErr_Format(PyExc_TypeError, "expected float value for attribute \"%s\"", attrdef->m_name.c_str()); return false; } - if (attrdef->m_clamp) - { - if (val < attrdef->m_fmin) + if (attrdef->m_clamp) { + if (val < attrdef->m_fmin) { val = attrdef->m_fmin; - else if (val > attrdef->m_fmax) + } + else if (val > attrdef->m_fmax) { val = attrdef->m_fmax; + } } - else if (val < attrdef->m_fmin || val > attrdef->m_fmax) - { - PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name); + else if (val < attrdef->m_fmin || val > attrdef->m_fmax) { + PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name.c_str()); return false; } *var = (float)val; return true; } -/* note, this is called as a python getset */ -int PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAttributeDef *attrdef) +// Note, this is called as a python getset. +int EXP_PyObjectPlus::py_set_attrdef(PyObject *self_py, PyObject *value, const PyAttributeDef *attrdef) { - PyObjectPlus *ref= (BGE_PROXY_REF(self_py)); - char* ptr = (attrdef->m_usePtr) ? (char*)BGE_PROXY_PTR(self_py) : (char*)ref; - if (ref==NULL || !ref->py_is_valid() || ptr==NULL) { - PyErr_SetString(PyExc_SystemError, BGE_PROXY_ERROR_MSG); + EXP_PyObjectPlus *ref = (EXP_PROXY_REF(self_py)); + char *ptr = (attrdef->m_usePtr) ? (char *)EXP_PROXY_PTR(self_py) : (char *)ref; + if (ref == nullptr || !ref->py_is_valid() || ptr == nullptr) { + PyErr_SetString(PyExc_SystemError, EXP_PROXY_ERROR_MSG); return PY_SET_ATTR_FAIL; } - void *undoBuffer = NULL; - void *sourceBuffer = NULL; + void *undoBuffer = nullptr; + void *sourceBuffer = nullptr; size_t bufferSize = 0; - PyObject *item = NULL; // to store object that must be dereferenced in case of error - PyObject *list = NULL; // to store object that must be dereferenced in case of error + PyObject *item = nullptr; // To store object that must be dereferenced in case of error. + PyObject *list = nullptr; // To store object that must be dereferenced in case of error. ptr += attrdef->m_offset; - if (attrdef->m_length > 1) - { - if (!PySequence_Check(value)) - { - PyErr_Format(PyExc_TypeError, "expected a sequence for attribute \"%s\"", attrdef->m_name); + if (attrdef->m_length > 1) { + if (!PySequence_Check(value)) { + PyErr_Format(PyExc_TypeError, "expected a sequence for attribute \"%s\"", attrdef->m_name.c_str()); return PY_SET_ATTR_FAIL; } - if (PySequence_Size(value) != attrdef->m_length) - { - PyErr_Format(PyExc_TypeError, "incorrect number of elements in sequence for attribute \"%s\"", attrdef->m_name); + if (PySequence_Size(value) != attrdef->m_length) { + PyErr_Format(PyExc_TypeError, "incorrect number of elements in sequence for attribute \"%s\"", attrdef->m_name.c_str()); return PY_SET_ATTR_FAIL; } - switch (attrdef->m_type) - { - case KX_PYATTRIBUTE_TYPE_FUNCTION: - if (attrdef->m_setFunction == NULL) + switch (attrdef->m_type) { + case EXP_PYATTRIBUTE_TYPE_FUNCTION: { - PyErr_Format(PyExc_AttributeError, "function attribute without function for attribute \"%s\", report to blender.org", attrdef->m_name); - return PY_SET_ATTR_FAIL; + if (attrdef->m_setFunction == nullptr) { + PyErr_Format(PyExc_AttributeError, "function attribute without function for attribute \"%s\", report to blender.org", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; + } + return (*attrdef->m_setFunction)(ref, attrdef, value); } - return (*attrdef->m_setFunction)(ref, attrdef, value); - case KX_PYATTRIBUTE_TYPE_BOOL: - bufferSize = sizeof(bool); - break; - case KX_PYATTRIBUTE_TYPE_SHORT: - bufferSize = sizeof(short int); - break; - case KX_PYATTRIBUTE_TYPE_ENUM: - case KX_PYATTRIBUTE_TYPE_INT: - bufferSize = sizeof(int); - break; - case KX_PYATTRIBUTE_TYPE_FLOAT: - bufferSize = sizeof(float); - break; - default: - // should not happen - PyErr_Format(PyExc_AttributeError, "Unsupported attribute type for attribute \"%s\", report to blender.org", attrdef->m_name); - return PY_SET_ATTR_FAIL; + case EXP_PYATTRIBUTE_TYPE_BOOL: + { + bufferSize = sizeof(bool); + break; + } + case EXP_PYATTRIBUTE_TYPE_SHORT: + { + bufferSize = sizeof(short int); + break; + } + case EXP_PYATTRIBUTE_TYPE_ENUM: + case EXP_PYATTRIBUTE_TYPE_INT: + { + bufferSize = sizeof(int); + break; + } + case EXP_PYATTRIBUTE_TYPE_FLOAT: + { + bufferSize = sizeof(float); + break; + } + default: + // Should not happen. + PyErr_Format(PyExc_AttributeError, "Unsupported attribute type for attribute \"%s\", report to blender.org", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; } - // let's implement a smart undo method + // Let's implement a smart undo method. bufferSize *= attrdef->m_length; undoBuffer = malloc(bufferSize); sourceBuffer = ptr; - if (undoBuffer) - { + if (undoBuffer) { memcpy(undoBuffer, sourceBuffer, bufferSize); } - for (int i=0; im_length; i++) + for (int i = 0; i < attrdef->m_length; i++) { - item = PySequence_GetItem(value, i); /* new ref */ - switch (attrdef->m_type) - { - case KX_PYATTRIBUTE_TYPE_BOOL: + item = PySequence_GetItem(value, i); // new ref + switch (attrdef->m_type) { + case EXP_PYATTRIBUTE_TYPE_BOOL: { - bool *var = reinterpret_cast(ptr); + bool *var = reinterpret_cast(ptr); ptr += sizeof(bool); - if (PyLong_Check(item)) - { + if (PyLong_Check(item)) { *var = (PyLong_AsLong(item) != 0); } - else if (PyBool_Check(item)) - { + else if (PyBool_Check(item)) { *var = (item == Py_True); } - else - { - PyErr_Format(PyExc_TypeError, "expected an integer or a bool for attribute \"%s\"", attrdef->m_name); + else { + PyErr_Format(PyExc_TypeError, "expected an integer or a bool for attribute \"%s\"", attrdef->m_name.c_str()); goto UNDO_AND_ERROR; } break; } - case KX_PYATTRIBUTE_TYPE_SHORT: + case EXP_PYATTRIBUTE_TYPE_SHORT: { - short int *var = reinterpret_cast(ptr); + short int *var = reinterpret_cast(ptr); ptr += sizeof(short int); - if (PyLong_Check(item)) - { + if (PyLong_Check(item)) { int val = PyLong_AsLong(item); - if (attrdef->m_clamp) - { - if (val < attrdef->m_imin) + if (attrdef->m_clamp) { + if (val < attrdef->m_imin) { val = attrdef->m_imin; - else if (val > attrdef->m_imax) + } + else if (val > attrdef->m_imax) { val = attrdef->m_imax; + } } - else if (val < attrdef->m_imin || val > attrdef->m_imax) - { - PyErr_Format(PyExc_ValueError, "item value out of range for attribute \"%s\"", attrdef->m_name); + else if (val < attrdef->m_imin || val > attrdef->m_imax) { + PyErr_Format(PyExc_ValueError, "item value out of range for attribute \"%s\"", attrdef->m_name.c_str()); goto UNDO_AND_ERROR; } *var = (short int)val; } - else - { - PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name); + else { + PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name.c_str()); goto UNDO_AND_ERROR; } break; } - case KX_PYATTRIBUTE_TYPE_ENUM: - // enum are equivalent to int, just make sure that the field size matches: - if (sizeof(int) != attrdef->m_size) + case EXP_PYATTRIBUTE_TYPE_ENUM: { - PyErr_Format(PyExc_AttributeError, "Size check error for attribute, \"%s\", report to blender.org", attrdef->m_name); - goto UNDO_AND_ERROR; + // Enum are equivalent to int, just make sure that the field size matches. + if (sizeof(int) != attrdef->m_size) { + PyErr_Format(PyExc_AttributeError, "Size check error for attribute, \"%s\", report to blender.org", attrdef->m_name.c_str()); + goto UNDO_AND_ERROR; + } + ATTR_FALLTHROUGH; } - ATTR_FALLTHROUGH; - case KX_PYATTRIBUTE_TYPE_INT: + case EXP_PYATTRIBUTE_TYPE_INT: { - int *var = reinterpret_cast(ptr); + int *var = reinterpret_cast(ptr); ptr += sizeof(int); - if (PyLong_Check(item)) - { + if (PyLong_Check(item)) { int val = PyLong_AsLong(item); - if (attrdef->m_clamp) - { - if (val < attrdef->m_imin) + if (attrdef->m_clamp) { + if (val < attrdef->m_imin) { val = attrdef->m_imin; - else if (val > attrdef->m_imax) + } + else if (val > attrdef->m_imax) { val = attrdef->m_imax; + } } - else if (val < attrdef->m_imin || val > attrdef->m_imax) - { - PyErr_Format(PyExc_ValueError, "item value out of range for attribute \"%s\"", attrdef->m_name); + else if (val < attrdef->m_imin || val > attrdef->m_imax) { + PyErr_Format(PyExc_ValueError, "item value out of range for attribute \"%s\"", attrdef->m_name.c_str()); goto UNDO_AND_ERROR; } *var = (int)val; } - else - { - PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name); + else { + PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name.c_str()); goto UNDO_AND_ERROR; } break; } - case KX_PYATTRIBUTE_TYPE_FLOAT: + case EXP_PYATTRIBUTE_TYPE_FLOAT: { - float *var = reinterpret_cast(ptr); + float *var = reinterpret_cast(ptr); ptr += sizeof(float); float val = PyFloat_AsDouble(item); - if (val == -1.0f && PyErr_Occurred()) - { - PyErr_Format(PyExc_TypeError, "expected a float for attribute \"%s\"", attrdef->m_name); + if (val == -1.0f && PyErr_Occurred()) { + PyErr_Format(PyExc_TypeError, "expected a float for attribute \"%s\"", attrdef->m_name.c_str()); goto UNDO_AND_ERROR; } - else if (attrdef->m_clamp) - { - if (val < attrdef->m_fmin) + else if (attrdef->m_clamp) { + if (val < attrdef->m_fmin) { val = attrdef->m_fmin; - else if (val > attrdef->m_fmax) + } + else if (val > attrdef->m_fmax) { val = attrdef->m_fmax; + } } - else if (val < attrdef->m_fmin || val > attrdef->m_fmax) - { - PyErr_Format(PyExc_ValueError, "item value out of range for attribute \"%s\"", attrdef->m_name); + else if (val < attrdef->m_fmin || val > attrdef->m_fmax) { + PyErr_Format(PyExc_ValueError, "item value out of range for attribute \"%s\"", attrdef->m_name.c_str()); goto UNDO_AND_ERROR; } *var = (float)val; break; } - default: - // should not happen - PyErr_Format(PyExc_AttributeError, "type check error for attribute \"%s\", report to blender.org", attrdef->m_name); - goto UNDO_AND_ERROR; + default: + // Should not happen. + PyErr_Format(PyExc_AttributeError, "type check error for attribute \"%s\", report to blender.org", attrdef->m_name.c_str()); + goto UNDO_AND_ERROR; } - // finished using item, release + // Finished using item, release. Py_DECREF(item); - item = NULL; + item = nullptr; } - // no error, call check function if any - if (attrdef->m_checkFunction != NULL) - { - if ((*attrdef->m_checkFunction)(ref, attrdef) != 0) - { - // if the checing function didnt set an error then set a generic one here so we don't set an error with no exception - if (PyErr_Occurred()==0) - PyErr_Format(PyExc_AttributeError, "type check error for attribute \"%s\", reasion unknown", attrdef->m_name); + // No error, call check function if any. + if (attrdef->m_checkFunction != nullptr) { + if ((*attrdef->m_checkFunction)(ref, attrdef) != 0) { + // If the checing function didnt set an error then set a generic one here so we don't set an error with no exception. + if (PyErr_Occurred() == 0) { + PyErr_Format(PyExc_AttributeError, "type check error for attribute \"%s\", reasion unknown", attrdef->m_name.c_str()); + } - // post check returned an error, restore values - UNDO_AND_ERROR: - if (undoBuffer) - { + // Post check returned an error, restore values. +UNDO_AND_ERROR: + if (undoBuffer) { memcpy(sourceBuffer, undoBuffer, bufferSize); free(undoBuffer); } - if (item) + if (item) { Py_DECREF(item); + } return PY_SET_ATTR_FAIL; } } - if (undoBuffer) + if (undoBuffer) { free(undoBuffer); + } return PY_SET_ATTR_SUCCESS; } - else // simple attribute value - { - if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_FUNCTION) - { - if (attrdef->m_setFunction == NULL) - { - PyErr_Format(PyExc_AttributeError, "function attribute without function \"%s\", report to blender.org", attrdef->m_name); + else { + if (attrdef->m_type == EXP_PYATTRIBUTE_TYPE_FUNCTION) { + if (attrdef->m_setFunction == nullptr) { + PyErr_Format(PyExc_AttributeError, "function attribute without function \"%s\", report to blender.org", attrdef->m_name.c_str()); return PY_SET_ATTR_FAIL; } return (*attrdef->m_setFunction)(ref, attrdef, value); } - if (attrdef->m_checkFunction != NULL || attrdef->m_type == KX_PYATTRIBUTE_TYPE_VECTOR) - { - // post check function is provided, prepare undo buffer + if (attrdef->m_checkFunction != nullptr || attrdef->m_type == EXP_PYATTRIBUTE_TYPE_VECTOR) { + // Post check function is provided, prepare undo buffer. sourceBuffer = ptr; - switch (attrdef->m_type) - { - case KX_PYATTRIBUTE_TYPE_BOOL: - bufferSize = sizeof(bool); - break; - case KX_PYATTRIBUTE_TYPE_SHORT: - bufferSize = sizeof(short); - break; - case KX_PYATTRIBUTE_TYPE_ENUM: - case KX_PYATTRIBUTE_TYPE_FLAG: - case KX_PYATTRIBUTE_TYPE_CHAR: - bufferSize = attrdef->m_size; - break; - case KX_PYATTRIBUTE_TYPE_INT: - bufferSize = sizeof(int); - break; - case KX_PYATTRIBUTE_TYPE_FLOAT: - bufferSize = sizeof(float); - if (attrdef->m_imax) - bufferSize *= attrdef->m_imax; - if (attrdef->m_imin) - bufferSize *= attrdef->m_imin; - break; - case KX_PYATTRIBUTE_TYPE_STRING: - sourceBuffer = reinterpret_cast(ptr)->Ptr(); - if (sourceBuffer) - bufferSize = strlen(reinterpret_cast(sourceBuffer))+1; - break; - case KX_PYATTRIBUTE_TYPE_VECTOR: - bufferSize = sizeof(MT_Vector3); - break; - default: - PyErr_Format(PyExc_AttributeError, "unknown type for attribute \"%s\", report to blender.org", attrdef->m_name); - return PY_SET_ATTR_FAIL; + switch (attrdef->m_type) { + case EXP_PYATTRIBUTE_TYPE_BOOL: + { + bufferSize = sizeof(bool); + break; + } + case EXP_PYATTRIBUTE_TYPE_SHORT: + { + bufferSize = sizeof(short); + break; + } + case EXP_PYATTRIBUTE_TYPE_ENUM: + case EXP_PYATTRIBUTE_TYPE_FLAG: + case EXP_PYATTRIBUTE_TYPE_CHAR: + { + bufferSize = attrdef->m_size; + break; + } + case EXP_PYATTRIBUTE_TYPE_INT: + { + bufferSize = sizeof(int); + break; + } + case EXP_PYATTRIBUTE_TYPE_FLOAT: + { + bufferSize = sizeof(float); + if (attrdef->m_imax) { + bufferSize *= attrdef->m_imax; + } + if (attrdef->m_imin) { + bufferSize *= attrdef->m_imin; + } + break; + } + case EXP_PYATTRIBUTE_TYPE_STRING: + { + sourceBuffer = (char *)reinterpret_cast(ptr)->c_str(); + if (sourceBuffer) { + bufferSize = strlen(reinterpret_cast(sourceBuffer)) + 1; + } + break; + } + case EXP_PYATTRIBUTE_TYPE_VECTOR: + { + switch (attrdef->m_size) { + case 2: + { + bufferSize = sizeof(mt::vec2); + break; + } + case 3: + { + bufferSize = sizeof(mt::vec3); + break; + } + } + break; + } + default: + PyErr_Format(PyExc_AttributeError, "unknown type for attribute \"%s\", report to blender.org", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; } - if (bufferSize) - { + if (bufferSize) { undoBuffer = malloc(bufferSize); - if (undoBuffer) - { + if (undoBuffer) { memcpy(undoBuffer, sourceBuffer, bufferSize); } } } - switch (attrdef->m_type) - { - case KX_PYATTRIBUTE_TYPE_BOOL: + switch (attrdef->m_type) { + case EXP_PYATTRIBUTE_TYPE_BOOL: { - bool *var = reinterpret_cast(ptr); - if (PyLong_Check(value)) - { + bool *var = reinterpret_cast(ptr); + if (PyLong_Check(value)) { *var = (PyLong_AsLong(value) != 0); } - else if (PyBool_Check(value)) - { + else if (PyBool_Check(value)) { *var = (value == Py_True); } - else - { - PyErr_Format(PyExc_TypeError, "expected an integer or a bool for attribute \"%s\"", attrdef->m_name); + else { + PyErr_Format(PyExc_TypeError, "expected an integer or a bool for attribute \"%s\"", attrdef->m_name.c_str()); goto FREE_AND_ERROR; } break; } - case KX_PYATTRIBUTE_TYPE_FLAG: + case EXP_PYATTRIBUTE_TYPE_FLAG: { bool bval; - if (PyLong_Check(value)) - { + if (PyLong_Check(value)) { bval = (PyLong_AsLong(value) != 0); } - else if (PyBool_Check(value)) - { + else if (PyBool_Check(value)) { bval = (value == Py_True); } - else - { - PyErr_Format(PyExc_TypeError, "expected an integer or a bool for attribute \"%s\"", attrdef->m_name); + else { + PyErr_Format(PyExc_TypeError, "expected an integer or a bool for attribute \"%s\"", attrdef->m_name.c_str()); goto FREE_AND_ERROR; } - if (attrdef->m_imax) + if (attrdef->m_imax) { bval = !bval; + } switch (attrdef->m_size) { - case 1: + case 1: { - unsigned char *val = reinterpret_cast(ptr); - *val = (*val & ~attrdef->m_imin) | ((bval)?attrdef->m_imin:0); + unsigned char *val = reinterpret_cast(ptr); + *val = (*val & ~attrdef->m_imin) | ((bval) ? attrdef->m_imin : 0); break; } - case 2: + case 2: { - unsigned short *val = reinterpret_cast(ptr); - *val = (*val & ~attrdef->m_imin) | ((bval)?attrdef->m_imin:0); + unsigned short *val = reinterpret_cast(ptr); + *val = (*val & ~attrdef->m_imin) | ((bval) ? attrdef->m_imin : 0); break; } - case 4: + case 4: { - unsigned int *val = reinterpret_cast(ptr); - *val = (*val & ~attrdef->m_imin) | ((bval)?attrdef->m_imin:0); + unsigned int *val = reinterpret_cast(ptr); + *val = (*val & ~attrdef->m_imin) | ((bval) ? attrdef->m_imin : 0); break; } - default: - PyErr_Format(PyExc_TypeError, "internal error: unsupported flag field \"%s\"", attrdef->m_name); - goto FREE_AND_ERROR; + default: + PyErr_Format(PyExc_TypeError, "internal error: unsupported flag field \"%s\"", attrdef->m_name.c_str()); + goto FREE_AND_ERROR; } break; } - case KX_PYATTRIBUTE_TYPE_SHORT: + case EXP_PYATTRIBUTE_TYPE_SHORT: { - short int *var = reinterpret_cast(ptr); - if (PyLong_Check(value)) - { + short int *var = reinterpret_cast(ptr); + if (PyLong_Check(value)) { int val = PyLong_AsLong(value); - if (attrdef->m_clamp) - { - if (val < attrdef->m_imin) + if (attrdef->m_clamp) { + if (val < attrdef->m_imin) { val = attrdef->m_imin; - else if (val > attrdef->m_imax) + } + else if (val > attrdef->m_imax) { val = attrdef->m_imax; + } } - else if (val < attrdef->m_imin || val > attrdef->m_imax) - { - PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name); + else if (val < attrdef->m_imin || val > attrdef->m_imax) { + PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name.c_str()); goto FREE_AND_ERROR; } *var = (short int)val; } - else - { - PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name); + else { + PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name.c_str()); goto FREE_AND_ERROR; } break; } - case KX_PYATTRIBUTE_TYPE_ENUM: - // enum are equivalent to int, just make sure that the field size matches: - if (sizeof(int) != attrdef->m_size) + case EXP_PYATTRIBUTE_TYPE_ENUM: { - PyErr_Format(PyExc_AttributeError, "attribute size check error for attribute \"%s\", report to blender.org", attrdef->m_name); - goto FREE_AND_ERROR; + // Enum are equivalent to int, just make sure that the field size matches: + if (sizeof(int) != attrdef->m_size) { + PyErr_Format(PyExc_AttributeError, "attribute size check error for attribute \"%s\", report to blender.org", attrdef->m_name.c_str()); + goto FREE_AND_ERROR; + } + ATTR_FALLTHROUGH; } - ATTR_FALLTHROUGH; - case KX_PYATTRIBUTE_TYPE_INT: + case EXP_PYATTRIBUTE_TYPE_INT: { - int *var = reinterpret_cast(ptr); - if (PyLong_Check(value)) - { + int *var = reinterpret_cast(ptr); + if (PyLong_Check(value)) { int val = PyLong_AsLong(value); - if (attrdef->m_clamp) - { - if (val < attrdef->m_imin) + if (attrdef->m_clamp) { + if (val < attrdef->m_imin) { val = attrdef->m_imin; - else if (val > attrdef->m_imax) + } + else if (val > attrdef->m_imax) { val = attrdef->m_imax; + } } - else if (val < attrdef->m_imin || val > attrdef->m_imax) - { - PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name); + else if (val < attrdef->m_imin || val > attrdef->m_imax) { + PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name.c_str()); goto FREE_AND_ERROR; } *var = (int)val; } - else - { - PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name); + else { + PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name.c_str()); goto FREE_AND_ERROR; } break; } - case KX_PYATTRIBUTE_TYPE_FLOAT: + case EXP_PYATTRIBUTE_TYPE_FLOAT: { - float *var = reinterpret_cast(ptr); - if (attrdef->m_imin != 0) - { - if (attrdef->m_size != attrdef->m_imin*attrdef->m_imax*sizeof(float)) - { - PyErr_Format(PyExc_TypeError, "internal error: incorrect field size for attribute \"%s\"", attrdef->m_name); + float *var = reinterpret_cast(ptr); + if (attrdef->m_imin != 0) { + if (attrdef->m_size != attrdef->m_imin * attrdef->m_imax * sizeof(float)) { + PyErr_Format(PyExc_TypeError, "internal error: incorrect field size for attribute \"%s\"", attrdef->m_name.c_str()); goto FREE_AND_ERROR; } - if (!PySequence_Check(value) || PySequence_Size(value) != attrdef->m_imin) - { - PyErr_Format(PyExc_TypeError, "expected a sequence of [%d][%d] floats for attribute \"%s\"", attrdef->m_imin, attrdef->m_imax, attrdef->m_name); + if (!PySequence_Check(value) || PySequence_Size(value) != attrdef->m_imin) { + PyErr_Format(PyExc_TypeError, "expected a sequence of [%d][%d] floats for attribute \"%s\"", attrdef->m_imin, attrdef->m_imax, attrdef->m_name.c_str()); goto FREE_AND_ERROR; } - for (int i=0; im_imin; i++) + for (int i = 0; i < attrdef->m_imin; i++) { - PyObject *list = PySequence_GetItem(value, i); /* new ref */ - if (!PySequence_Check(list) || PySequence_Size(list) != attrdef->m_imax) - { - PyErr_Format(PyExc_TypeError, "expected a sequence of [%d][%d] floats for attribute \"%s\"", attrdef->m_imin, attrdef->m_imax, attrdef->m_name); + list = PySequence_GetItem(value, i); /* new ref */ + if (!PySequence_Check(list) || PySequence_Size(list) != attrdef->m_imax) { + PyErr_Format(PyExc_TypeError, "expected a sequence of [%d][%d] floats for attribute \"%s\"", attrdef->m_imin, attrdef->m_imax, attrdef->m_name.c_str()); goto RESTORE_AND_ERROR; } - for (int j=0; jm_imax; j++) + for (int j = 0; j < attrdef->m_imax; j++) { item = PySequence_GetItem(list, j); /* new ref */ - if (!py_check_attr_float(var, item, attrdef)) - { - PyErr_Format(PyExc_TypeError, "expected a sequence of [%d][%d] floats for attribute \"%s\"", attrdef->m_imin, attrdef->m_imax, attrdef->m_name); + if (!py_check_attr_float(var, item, attrdef)) { + PyErr_Format(PyExc_TypeError, "expected a sequence of [%d][%d] floats for attribute \"%s\"", attrdef->m_imin, attrdef->m_imax, attrdef->m_name.c_str()); goto RESTORE_AND_ERROR; } Py_DECREF(item); - item = NULL; + item = nullptr; ++var; } Py_DECREF(list); - list = NULL; + list = nullptr; } } - else if (attrdef->m_imax != 0) - { - if (attrdef->m_size != attrdef->m_imax*sizeof(float)) - { - PyErr_Format(PyExc_TypeError, "internal error: incorrect field size for attribute \"%s\"", attrdef->m_name); + else if (attrdef->m_imax != 0) { + if (attrdef->m_size != attrdef->m_imax * sizeof(float)) { + PyErr_Format(PyExc_TypeError, "internal error: incorrect field size for attribute \"%s\"", attrdef->m_name.c_str()); goto FREE_AND_ERROR; } - if (!PySequence_Check(value) || PySequence_Size(value) != attrdef->m_imax) - { - PyErr_Format(PyExc_TypeError, "expected a sequence of [%d] floats for attribute \"%s\"", attrdef->m_imax, attrdef->m_name); + if (!PySequence_Check(value) || PySequence_Size(value) != attrdef->m_imax) { + PyErr_Format(PyExc_TypeError, "expected a sequence of [%d] floats for attribute \"%s\"", attrdef->m_imax, attrdef->m_name.c_str()); goto FREE_AND_ERROR; } - for (int i=0; im_imax; i++) + for (int i = 0; i < attrdef->m_imax; i++) { item = PySequence_GetItem(value, i); /* new ref */ - if (!py_check_attr_float(var, item, attrdef)) - { + if (!py_check_attr_float(var, item, attrdef)) { goto RESTORE_AND_ERROR; } Py_DECREF(item); - item = NULL; + item = nullptr; ++var; } } - else - { - if (!py_check_attr_float(var, value, attrdef)) + else { + if (!py_check_attr_float(var, value, attrdef)) { goto FREE_AND_ERROR; + } } break; } - case KX_PYATTRIBUTE_TYPE_VECTOR: + case EXP_PYATTRIBUTE_TYPE_VECTOR: { - if (!PySequence_Check(value) || PySequence_Size(value) != 3) - { - PyErr_Format(PyExc_TypeError, "expected a sequence of 3 floats for attribute \"%s\"", attrdef->m_name); + if (!PySequence_Check(value) || PySequence_Size(value) != attrdef->m_size) { + PyErr_Format(PyExc_TypeError, "expected a sequence of %i floats for attribute \"%s\"", attrdef->m_size, attrdef->m_name.c_str()); goto FREE_AND_ERROR; } - MT_Vector3 *var = reinterpret_cast(ptr); - for (int i=0; i<3; i++) - { - item = PySequence_GetItem(value, i); /* new ref */ - float val = PyFloat_AsDouble(item); - Py_DECREF(item); - item = NULL; - if (val == -1.0f && PyErr_Occurred()) - { - PyErr_Format(PyExc_TypeError, "expected a sequence of 3 floats for attribute \"%s\"", attrdef->m_name); - goto RESTORE_AND_ERROR; - } - else if (attrdef->m_clamp) + switch (attrdef->m_size) { + case 2: { - if (val < attrdef->m_fmin) - val = attrdef->m_fmin; - else if (val > attrdef->m_fmax) - val = attrdef->m_fmax; + mt::vec2 *var = reinterpret_cast(ptr); + for (int i = 0; i < 2; i++) + { + item = PySequence_GetItem(value, i); // new ref + float val = PyFloat_AsDouble(item); + Py_DECREF(item); + item = nullptr; + if (val == -1.0f && PyErr_Occurred()) { + PyErr_Format(PyExc_TypeError, "expected a sequence of 2 floats for attribute \"%s\"", attrdef->m_name.c_str()); + goto RESTORE_AND_ERROR; + } + else if (attrdef->m_clamp) { + if (val < attrdef->m_fmin) { + val = attrdef->m_fmin; + } + else if (val > attrdef->m_fmax) { + val = attrdef->m_fmax; + } + } + else if (val < attrdef->m_fmin || val > attrdef->m_fmax) { + PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name.c_str()); + goto RESTORE_AND_ERROR; + } + (*var)[i] = (float)val; + } + break; } - else if (val < attrdef->m_fmin || val > attrdef->m_fmax) + case 3: { - PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name); - goto RESTORE_AND_ERROR; + mt::vec3 *var = reinterpret_cast(ptr); + for (int i = 0; i < 3; i++) + { + item = PySequence_GetItem(value, i); // new ref + float val = PyFloat_AsDouble(item); + Py_DECREF(item); + item = nullptr; + if (val == -1.0f && PyErr_Occurred()) { + PyErr_Format(PyExc_TypeError, "expected a sequence of 3 floats for attribute \"%s\"", attrdef->m_name.c_str()); + goto RESTORE_AND_ERROR; + } + else if (attrdef->m_clamp) { + if (val < attrdef->m_fmin) { + val = attrdef->m_fmin; + } + else if (val > attrdef->m_fmax) { + val = attrdef->m_fmax; + } + } + else if (val < attrdef->m_fmin || val > attrdef->m_fmax) { + PyErr_Format(PyExc_ValueError, "value out of range for attribute \"%s\"", attrdef->m_name.c_str()); + goto RESTORE_AND_ERROR; + } + (*var)[i] = (float)val; + } + break; } - (*var)[i] = (MT_Scalar)val; } break; } - case KX_PYATTRIBUTE_TYPE_CHAR: + case EXP_PYATTRIBUTE_TYPE_CHAR: { - if (PyUnicode_Check(value)) - { + if (PyUnicode_Check(value)) { Py_ssize_t val_size; const char *val = _PyUnicode_AsStringAndSize(value, &val_size); strncpy(ptr, val, attrdef->m_size); - ptr[attrdef->m_size-1] = 0; + ptr[attrdef->m_size - 1] = 0; } - else - { - PyErr_Format(PyExc_TypeError, "expected a string for attribute \"%s\"", attrdef->m_name); + else { + PyErr_Format(PyExc_TypeError, "expected a string for attribute \"%s\"", attrdef->m_name.c_str()); goto FREE_AND_ERROR; } break; } - case KX_PYATTRIBUTE_TYPE_STRING: + case EXP_PYATTRIBUTE_TYPE_STRING: { - STR_String *var = reinterpret_cast(ptr); - if (PyUnicode_Check(value)) - { + std::string *var = reinterpret_cast(ptr); + if (PyUnicode_Check(value)) { Py_ssize_t val_len; const char *val = _PyUnicode_AsStringAndSize(value, &val_len); /* XXX, should be 'const' but we do a silly trick to have a shorter string */ - if (attrdef->m_clamp) - { - if (val_len < attrdef->m_imin) - { - // can't increase the length of the string - PyErr_Format(PyExc_ValueError, "string length too short for attribute \"%s\"", attrdef->m_name); + if (attrdef->m_clamp) { + if (val_len < attrdef->m_imin) { + // Can't increase the length of the string. + PyErr_Format(PyExc_ValueError, "string length too short for attribute \"%s\"", attrdef->m_name.c_str()); goto FREE_AND_ERROR; } - else if (val_len > attrdef->m_imax) - { - // trim the string - var->SetLength(attrdef->m_imax); - memcpy(var->Ptr(), val, attrdef->m_imax - 1); + else if (val_len > attrdef->m_imax) { + // Trim the string. + *var = var->substr(0, attrdef->m_imax); break; } - } else if (val_len < attrdef->m_imin || val_len > attrdef->m_imax) - { - PyErr_Format(PyExc_ValueError, "string length out of range for attribute \"%s\"", attrdef->m_name); + } + else if (val_len < attrdef->m_imin || val_len > attrdef->m_imax) { + PyErr_Format(PyExc_ValueError, "string length out of range for attribute \"%s\"", attrdef->m_name.c_str()); goto FREE_AND_ERROR; } *var = val; } - else - { - PyErr_Format(PyExc_TypeError, "expected a string for attribute \"%s\"", attrdef->m_name); + else { + PyErr_Format(PyExc_TypeError, "expected a string for attribute \"%s\"", attrdef->m_name.c_str()); goto FREE_AND_ERROR; } break; } - default: - // should not happen - PyErr_Format(PyExc_AttributeError, "unknown type for attribute \"%s\", report to blender.org", attrdef->m_name); - goto FREE_AND_ERROR; + default: + // Should not happen + PyErr_Format(PyExc_AttributeError, "unknown type for attribute \"%s\", report to blender.org", attrdef->m_name.c_str()); + goto FREE_AND_ERROR; } } - // check if post processing is needed - if (attrdef->m_checkFunction != NULL) - { - if ((*attrdef->m_checkFunction)(ref, attrdef) != 0) - { - // restore value - RESTORE_AND_ERROR: - if (undoBuffer) - { - if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_STRING) - { - // special case for STR_String: restore the string - STR_String *var = reinterpret_cast(ptr); - *var = reinterpret_cast(undoBuffer); + // Check if post processing is needed. + if (attrdef->m_checkFunction != nullptr) { + if ((*attrdef->m_checkFunction)(ref, attrdef) != 0) { + // Restore value. +RESTORE_AND_ERROR: + if (undoBuffer) { + if (attrdef->m_type == EXP_PYATTRIBUTE_TYPE_STRING) { + // Special case for std::string: restore the string. + std::string *var = reinterpret_cast(ptr); + *var = reinterpret_cast(undoBuffer); } - else - { - // other field type have direct values + else { + // Other field type have direct values. memcpy(ptr, undoBuffer, bufferSize); } } - FREE_AND_ERROR: - if (undoBuffer) +FREE_AND_ERROR: + if (undoBuffer) { free(undoBuffer); - if (list) + } + if (list) { Py_DECREF(list); - if (item) + } + if (item) { Py_DECREF(item); + } return 1; } } - if (undoBuffer) + if (undoBuffer) { free(undoBuffer); + } return 0; } - - /*------------------------------ - * PyObjectPlus repr -- representations -------------------------------*/ -PyObject *PyObjectPlus::py_repr(void) +* EXP_PyObjectPlus repr -- representations + ------------------------------*/ +PyObject *EXP_PyObjectPlus::py_repr(void) { PyErr_SetString(PyExc_SystemError, "Representation not overridden by object."); - return NULL; + return nullptr; +} + +bool EXP_PyObjectPlus::py_is_valid(void) +{ + return true; } -PyObject *PyObjectPlus::GetProxyPlus_Ext(PyObjectPlus *self, PyTypeObject *tp, void *ptr) +PyObject *EXP_PyObjectPlus::GetProxyPlus_Ext(EXP_PyObjectPlus *self, PyTypeObject *tp, void *ptr) { - if (self->m_proxy==NULL) - { - self->m_proxy = reinterpret_castPyObject_NEW( PyObjectPlus_Proxy, tp); - BGE_PROXY_PYOWNS(self->m_proxy) = false; - BGE_PROXY_PYREF(self->m_proxy) = true; + if (self->m_proxy == nullptr) { + self->m_proxy = reinterpret_castPyObject_NEW(EXP_PyObjectPlus_Proxy, tp); + EXP_PROXY_PYOWNS(self->m_proxy) = false; + EXP_PROXY_PYREF(self->m_proxy) = true; #ifdef USE_WEAKREFS - BGE_PROXY_WKREF(self->m_proxy) = NULL; + EXP_PROXY_WKREF(self->m_proxy) = nullptr; #endif } - //PyObject_Print(self->m_proxy, stdout, 0); - //printf("ref %d\n", self->m_proxy->ob_refcnt); - BGE_PROXY_REF(self->m_proxy) = self; /* Its possible this was set to NULL, so set it back here */ - BGE_PROXY_PTR(self->m_proxy) = ptr; - Py_INCREF(self->m_proxy); /* we own one, thos ones fore the return */ + EXP_PROXY_REF(self->m_proxy) = self; // Its possible this was set to nullptr, so set it back here. + EXP_PROXY_PTR(self->m_proxy) = ptr; + Py_INCREF(self->m_proxy); // We own one, thos ones fore the return. return self->m_proxy; } -PyObject *PyObjectPlus::NewProxyPlus_Ext(PyObjectPlus *self, PyTypeObject *tp, void *ptr, bool py_owns) +PyObject *EXP_PyObjectPlus::NewProxyPlus_Ext(EXP_PyObjectPlus *self, PyTypeObject *tp, void *ptr, bool py_owns) { - if (!self) - { - // in case of proxy without reference to game object - PyObject *proxy = reinterpret_castPyObject_NEW( PyObjectPlus_Proxy, tp); - BGE_PROXY_PYREF(proxy) = false; - BGE_PROXY_PYOWNS(proxy) = py_owns; - BGE_PROXY_REF(proxy) = NULL; - BGE_PROXY_PTR(proxy) = ptr; + if (!self) { + // In case of proxy without reference to game object. + PyObject *proxy = reinterpret_castPyObject_NEW(EXP_PyObjectPlus_Proxy, tp); + EXP_PROXY_PYREF(proxy) = false; + EXP_PROXY_PYOWNS(proxy) = py_owns; + EXP_PROXY_REF(proxy) = nullptr; + EXP_PROXY_PTR(proxy) = ptr; #ifdef USE_WEAKREFS - BGE_PROXY_WKREF(proxy) = NULL; + EXP_PROXY_WKREF(proxy) = nullptr; #endif return proxy; } - if (self->m_proxy) - { - if (py_owns) - { /* Free */ - BGE_PROXY_REF(self->m_proxy) = NULL; + if (self->m_proxy) { + if (py_owns) { // Free + EXP_PROXY_REF(self->m_proxy) = nullptr; Py_DECREF(self->m_proxy); - self->m_proxy= NULL; + self->m_proxy = nullptr; } else { Py_INCREF(self->m_proxy); @@ -1173,54 +1216,75 @@ PyObject *PyObjectPlus::NewProxyPlus_Ext(PyObjectPlus *self, PyTypeObject *tp, v GetProxyPlus_Ext(self, tp, ptr); if (py_owns) { - BGE_PROXY_PYOWNS(self->m_proxy) = py_owns; - Py_DECREF(self->m_proxy); /* could avoid thrashing here but for now its ok */ + EXP_PROXY_PYOWNS(self->m_proxy) = py_owns; + Py_DECREF(self->m_proxy); // Could avoid thrashing here but for now its ok. } return self->m_proxy; } -PyObject *PyUnicode_From_STR_String(const STR_String& str) +PyObject *PyUnicode_FromStdString(const std::string& str) { - return PyUnicode_FromStringAndSize(str.ReadPtr(), str.Length()); + return PyUnicode_FromStringAndSize(str.c_str(), str.size()); } -/////////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////// -/* deprecation warning management */ +// Deprecation warning management. +bool EXP_PyObjectPlus::m_ignore_deprecation_warnings = false; -bool PyObjectPlus::m_ignore_deprecation_warnings(false); -void PyObjectPlus::SetDeprecationWarnings(bool ignoreDeprecationWarnings) +bool EXP_PyObjectPlus::GetDerprecationWarnings() +{ + return m_ignore_deprecation_warnings; +} + +void EXP_PyObjectPlus::SetDeprecationWarnings(bool ignoreDeprecationWarnings) { m_ignore_deprecation_warnings = ignoreDeprecationWarnings; } -void PyObjectPlus::ShowDeprecationWarning_func(const char *old_way, const char *new_way) +void EXP_PyObjectPlus::ShowDeprecationWarning_func(const std::string& old_way, const std::string& new_way) { - printf("Method %s is deprecated, please use %s instead.\n", old_way, new_way); - PyC_LineSpit(); + CM_PythonWarning("method " << old_way << " is deprecated, please use " << new_way << " instead."); } -void PyObjectPlus::ClearDeprecationWarning() +void EXP_PyObjectPlus::ClearDeprecationWarning() { - WarnLink *wlink_next; - WarnLink *wlink = GetDeprecationWarningLinkFirst(); + EXP_WarnLink *wlink_next; + EXP_WarnLink *wlink = GetDeprecationWarningLinkFirst(); while (wlink) { - wlink->warn_done= false; /* no need to NULL the link, its cleared before adding to the list next time round */ - wlink_next= reinterpret_cast(wlink->link); - wlink->link= NULL; - wlink= wlink_next; + wlink->warn_done = false; // No need to nullptr the link, its cleared before adding to the list next time round. + wlink_next = reinterpret_cast(wlink->link); + wlink->link = nullptr; + wlink = wlink_next; } NullDeprecationWarning(); } -static WarnLink *m_base_wlink_first = NULL; -static WarnLink *m_base_wlink_last = NULL; +static EXP_WarnLink *m_base_wlink_first = nullptr; +static EXP_WarnLink *m_base_wlink_last = nullptr; + +EXP_WarnLink *EXP_PyObjectPlus::GetDeprecationWarningLinkFirst(void) +{ + return m_base_wlink_first; +} + +EXP_WarnLink *EXP_PyObjectPlus::GetDeprecationWarningLinkLast(void) +{ + return m_base_wlink_last; +} -WarnLink* PyObjectPlus::GetDeprecationWarningLinkFirst(void) {return m_base_wlink_first;} -WarnLink* PyObjectPlus::GetDeprecationWarningLinkLast(void) {return m_base_wlink_last;} -void PyObjectPlus::SetDeprecationWarningFirst(WarnLink* wlink) {m_base_wlink_first= wlink;} -void PyObjectPlus::SetDeprecationWarningLinkLast(WarnLink* wlink) {m_base_wlink_last= wlink;} -void PyObjectPlus::NullDeprecationWarning() {m_base_wlink_first= m_base_wlink_last= NULL;} +void EXP_PyObjectPlus::SetDeprecationWarningFirst(EXP_WarnLink *wlink) +{ + m_base_wlink_first = wlink; +} + +void EXP_PyObjectPlus::SetDeprecationWarningLinkLast(EXP_WarnLink *wlink) +{ + m_base_wlink_last = wlink; +} + +void EXP_PyObjectPlus::NullDeprecationWarning() +{ + m_base_wlink_first = m_base_wlink_last = nullptr; +} -#endif // WITH_PYTHON +#endif // WITH_PYTHON diff --git a/source/gameengine/Expressions/intern/PythonCallBack.cpp b/source/gameengine/Expressions/intern/PythonCallBack.cpp index 3fb84569eca1..8d0f87fcbe6a 100644 --- a/source/gameengine/Expressions/intern/PythonCallBack.cpp +++ b/source/gameengine/Expressions/intern/PythonCallBack.cpp @@ -49,17 +49,18 @@ static PyObject *CheckPythonFunction(PyObject *value, unsigned int minargcount, // *args support r_argcount = (code->co_flags & CO_VARARGS) ? maxargcount : code->co_argcount; } - else { // is not a methode or a function + // Is not a methode or a function. + else { PyErr_Format(PyExc_TypeError, "items must be functions or methodes, not %s", - Py_TYPE(value)->tp_name); - return NULL; + Py_TYPE(value)->tp_name); + return nullptr; } if (r_argcount < minargcount || r_argcount > maxargcount) { - // wrong number of arguments + // Wrong number of arguments. PyErr_Format(PyExc_TypeError, "methode or function (%s) has invalid number of arguments (%i) must be between %i and %i", - Py_TYPE(value)->tp_name, r_argcount, minargcount, maxargcount); - return NULL; + Py_TYPE(value)->tp_name, r_argcount, minargcount, maxargcount); + return nullptr; } return value; @@ -75,7 +76,7 @@ static PyObject *CreatePythonTuple(unsigned int argcount, PyObject **arglist) for (unsigned int i = 0; i < argcount; ++i) { PyObject *item = arglist[i]; - // increment reference and copy it in a new tuple + // Increment reference and copy it in a new tuple. Py_INCREF(item); PyTuple_SET_ITEM(tuple, i, item); } @@ -83,37 +84,37 @@ static PyObject *CreatePythonTuple(unsigned int argcount, PyObject **arglist) return tuple; } -void RunPythonCallBackList(PyObject *functionlist, PyObject **arglist, unsigned int minargcount, unsigned int maxargcount) +void EXP_RunPythonCallback(PyObject *value, PyObject **arglist, unsigned int minargcount, unsigned int maxargcount) { - unsigned int size = PyList_Size(functionlist); - PyObject **argTuples = (PyObject **)BLI_array_alloca(argTuples, maxargcount - minargcount + 1); - memset(argTuples, 0, sizeof(PyObject *) * (maxargcount - minargcount + 1)); - - for (unsigned int i = 0; i < size; ++i) { unsigned int funcargcount = 0; - PyObject *item = PyList_GET_ITEM(functionlist, i); - PyObject *func = CheckPythonFunction(item, minargcount, maxargcount, funcargcount); - if (!func) { // this item fails the check + PyObject *func = CheckPythonFunction(value, minargcount, maxargcount, funcargcount); + // This value fails the check. + if (!func) { PyErr_Print(); PyErr_Clear(); - continue; + return; } - // get correct argument tuple. - PyObject *tuple = argTuples[funcargcount - minargcount]; - if (!tuple) - argTuples[funcargcount - minargcount] = tuple = CreatePythonTuple(funcargcount, arglist); + // Get correct argument tuple. + PyObject *tuple = CreatePythonTuple(funcargcount, arglist); - PyObject *ret = PyObject_Call(func, tuple, NULL); - if (!ret) { // if ret is NULL this seems that the function doesn't work ! + PyObject *ret = PyObject_Call(func, tuple, nullptr); + if (!ret) { // If ret is nullptr this seems that the function doesn't work. PyErr_Print(); PyErr_Clear(); } - else + else { Py_DECREF(ret); - } + } +} - for (unsigned int i = 0; i <= (maxargcount - minargcount); ++i) - Py_XDECREF(argTuples[i]); +void EXP_RunPythonCallBackList(PyObject *functionlist, PyObject **arglist, unsigned int minargcount, unsigned int maxargcount) +{ + const unsigned int size = PyList_Size(functionlist); + + for (unsigned int i = 0; i < size; ++i) { + PyObject *item = PyList_GET_ITEM(functionlist, i); + EXP_RunPythonCallback(item, arglist, minargcount, maxargcount); + } } diff --git a/source/gameengine/Expressions/intern/StringValue.cpp b/source/gameengine/Expressions/intern/StringValue.cpp index e20a62378f7d..01ddce22d2d9 100644 --- a/source/gameengine/Expressions/intern/StringValue.cpp +++ b/source/gameengine/Expressions/intern/StringValue.cpp @@ -1,7 +1,7 @@ /** \file gameengine/Expressions/StringValue.cpp * \ingroup expressions */ -// StringValue.cpp: implementation of the CStringValue class. +// StringValue.cpp: implementation of the EXP_StringValue class. /* * Copyright (c) 1996-2000 Erwin Coumans * @@ -18,128 +18,110 @@ #include "EXP_StringValue.h" #include "EXP_BoolValue.h" #include "EXP_ErrorValue.h" -#include "EXP_VoidValue.h" -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -/** - * pre: false - * effect: constructs a new CStringValue - */ -CStringValue::CStringValue() +EXP_StringValue::EXP_StringValue() + :m_strString("[Illegal String constructor call]") { - m_strString = "[Illegal String constructor call]"; } -/** - * pre: - * effect: constructs a new CStringValue containing text txt - */ -CStringValue::CStringValue(const char *txt,const char *name,AllocationTYPE alloctype) +EXP_StringValue::EXP_StringValue(const std::string& txt, const std::string& name) + :m_strString(txt) { - m_strString = txt; SetName(name); - - if (alloctype==CValue::STACKVALUE) - { - CValue::DisableRefCount(); - - } - - } - -/** - * pre: - * ret: a new object containing the result of applying operator op to this - * object and val - */ -CValue* CStringValue::Calc(VALUE_OPERATOR op, CValue *val) +EXP_Value *EXP_StringValue::Calc(VALUE_OPERATOR op, EXP_Value *val) { - //return val->CalrcString(op, this); return val->CalcFinal(VALUE_STRING_TYPE, op, this); } -/** - * pre: the type of val is dtype - * ret: a new object containing the result of applying operator op to val and - * this object - */ -CValue* CStringValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val) +EXP_Value *EXP_StringValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, EXP_Value *val) { - CValue *ret; + EXP_Value *ret; if (op == VALUE_ADD_OPERATOR) { - if (dtype == VALUE_ERROR_TYPE) - ret = new CErrorValue(val->GetText() + op2str(op) + GetText()); - else - ret = new CStringValue(val->GetText() + GetText(),""); + if (dtype == VALUE_ERROR_TYPE) { + ret = new EXP_ErrorValue(val->GetText() + op2str(op) + GetText()); + } + else { + ret = new EXP_StringValue(val->GetText() + GetText(), ""); + } } else { if (dtype == VALUE_STRING_TYPE || dtype == VALUE_EMPTY_TYPE) { switch (op) { case VALUE_EQL_OPERATOR: - ret = new CBoolValue(val->GetText() == GetText()); + { + ret = new EXP_BoolValue(val->GetText() == GetText()); break; + } case VALUE_NEQ_OPERATOR: - ret = new CBoolValue(val->GetText() != GetText()); + { + ret = new EXP_BoolValue(val->GetText() != GetText()); break; + } case VALUE_GRE_OPERATOR: - ret = new CBoolValue(val->GetText() > GetText()); + { + ret = new EXP_BoolValue(val->GetText() > GetText()); break; + } case VALUE_LES_OPERATOR: - ret = new CBoolValue(val->GetText() < GetText()); + { + ret = new EXP_BoolValue(val->GetText() < GetText()); break; + } case VALUE_GEQ_OPERATOR: - ret = new CBoolValue(val->GetText() >= GetText()); + { + ret = new EXP_BoolValue(val->GetText() >= GetText()); break; + } case VALUE_LEQ_OPERATOR: - ret = new CBoolValue(val->GetText() <= GetText()); + { + ret = new EXP_BoolValue(val->GetText() <= GetText()); break; + } default: - ret = new CErrorValue(val->GetText() + op2str(op) + "[operator not allowed on strings]"); + { + ret = new EXP_ErrorValue(val->GetText() + op2str(op) + "[operator not allowed on strings]"); break; + } } } else { - ret = new CErrorValue(val->GetText() + op2str(op) + "[operator not allowed on strings]"); + ret = new EXP_ErrorValue(val->GetText() + op2str(op) + "[operator not allowed on strings]"); } } return ret; } +void EXP_StringValue::SetValue(EXP_Value *newval) +{ + m_strString = newval->GetText(); +} - -double CStringValue::GetNumber() +double EXP_StringValue::GetNumber() { return -1; } - - -int CStringValue::GetValueType() +int EXP_StringValue::GetValueType() { return VALUE_STRING_TYPE; } - - -const STR_String & CStringValue::GetText() +std::string EXP_StringValue::GetText() { return m_strString; } -bool CStringValue::IsEqual(const STR_String & other) +bool EXP_StringValue::IsEqual(const std::string & other) { return (m_strString == other); } -CValue* CStringValue::GetReplica() +EXP_Value *EXP_StringValue::GetReplica() { - CStringValue* replica = new CStringValue(*this); + EXP_StringValue *replica = new EXP_StringValue(*this); replica->ProcessReplica(); return replica; -}; +} diff --git a/source/gameengine/Expressions/intern/Value.cpp b/source/gameengine/Expressions/intern/Value.cpp index 9b42bdb7bff7..3b7536813613 100644 --- a/source/gameengine/Expressions/intern/Value.cpp +++ b/source/gameengine/Expressions/intern/Value.cpp @@ -1,7 +1,7 @@ /** \file gameengine/Expressions/Value.cpp * \ingroup expressions */ -// Value.cpp: implementation of the CValue class. +// Value.cpp: implementation of the EXP_Value class. // developed at Eindhoven University of Technology, 1997 // by the OOPS team ////////////////////////////////////////////////////////////////////// @@ -21,24 +21,16 @@ #include "EXP_BoolValue.h" #include "EXP_FloatValue.h" #include "EXP_IntValue.h" -#include "EXP_VectorValue.h" -#include "EXP_VoidValue.h" #include "EXP_StringValue.h" #include "EXP_ErrorValue.h" #include "EXP_ListValue.h" -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -double CValue::m_sZeroVec[3] = {0.0,0.0,0.0}; - #ifdef WITH_PYTHON -PyTypeObject CValue::Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "CValue", - sizeof(PyObjectPlus_Proxy), +PyTypeObject EXP_Value::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "EXP_Value", + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -47,626 +39,376 @@ PyTypeObject CValue::Type = { 0, py_base_repr, 0, - 0,0,0,0,0, - NULL, - NULL, + 0, 0, 0, 0, 0, + nullptr, + nullptr, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, - &PyObjectPlus::Type, - 0,0,0,0,0,0, + &EXP_PyObjectPlus::Type, + 0, 0, 0, 0, 0, 0, py_base_new }; -PyMethodDef CValue::Methods[] = { - {NULL,NULL} //Sentinel +PyMethodDef EXP_Value::Methods[] = { + {nullptr, nullptr} // Sentinel }; -#endif // WITH_PYTHON - - -/*#define CVALUE_DEBUG*/ -#ifdef CVALUE_DEBUG -int gRefCount; -struct SmartCValueRef -{ - CValue *m_ref; - int m_count; - SmartCValueRef(CValue *ref) - { - m_ref = ref; - m_count = gRefCount++; - } -}; - -#include - -std::vector gRefList; -#endif +#endif // WITH_PYTHON -#ifdef DEBUG -//int gRefCountValue; -#endif - -CValue::CValue() - : PyObjectPlus(), - -m_pNamedPropertyArray(NULL), -m_refcount(1) -/* -pre: false -effect: constucts a CValue -*/ +EXP_Value::EXP_Value() { - //debug(gRefCountValue++) // debugging -#ifdef DEBUG - //gRefCountValue++; -#ifdef CVALUE_DEBUG - gRefList.push_back(SmartCValueRef(this)); -#endif -#endif } - - -CValue::~CValue() -/* -pre: -effect: deletes the object -*/ +EXP_Value::~EXP_Value() { ClearProperties(); - - assertd (m_refcount==0); -#ifdef CVALUE_DEBUG - std::vector::iterator it; - for (it=gRefList.begin(); it!=gRefList.end(); it++) - { - if (it->m_ref == this) - { - *it = gRefList.back(); - gRefList.pop_back(); - break; - } - } -#endif } - -/* UNUSED */ -#if 0 -#define VALUE_SUB(val1, val2) (val1)->Calc(VALUE_SUB_OPERATOR, val2) -#define VALUE_MUL(val1, val2) (val1)->Calc(VALUE_MUL_OPERATOR, val2) -#define VALUE_DIV(val1, val2) (val1)->Calc(VALUE_DIV_OPERATOR, val2) -#define VALUE_NEG(val1) (val1)->Calc(VALUE_NEG_OPERATOR, val1) -#define VALUE_POS(val1) (val1)->Calc(VALUE_POS_OPERATOR, val1) -#endif - -STR_String CValue::op2str(VALUE_OPERATOR op) +std::string EXP_Value::op2str(VALUE_OPERATOR op) { - //pre: - //ret: the stringrepresentation of operator op - - STR_String opmsg; + std::string opmsg; switch (op) { - case VALUE_MOD_OPERATOR: - opmsg = " % "; - break; - case VALUE_ADD_OPERATOR: - opmsg = " + "; - break; - case VALUE_SUB_OPERATOR: - opmsg = " - "; - break; - case VALUE_MUL_OPERATOR: - opmsg = " * "; - break; - case VALUE_DIV_OPERATOR: - opmsg = " / "; - break; - case VALUE_NEG_OPERATOR: - opmsg = " -"; - break; - case VALUE_POS_OPERATOR: - opmsg = " +"; - break; - case VALUE_AND_OPERATOR: - opmsg = " & "; - break; - case VALUE_OR_OPERATOR: - opmsg = " | "; - break; - case VALUE_EQL_OPERATOR: - opmsg = " = "; - break; - case VALUE_NEQ_OPERATOR: - opmsg = " != "; - break; - case VALUE_NOT_OPERATOR: - opmsg = " !"; - break; - default: - opmsg="Error in Errorhandling routine."; - // AfxMessageBox("Invalid operator"); - break; + case VALUE_MOD_OPERATOR: + { + opmsg = " % "; + break; + } + case VALUE_ADD_OPERATOR: + { + opmsg = " + "; + break; + } + case VALUE_SUB_OPERATOR: + { + opmsg = " - "; + break; + } + case VALUE_MUL_OPERATOR: + { + opmsg = " * "; + break; + } + case VALUE_DIV_OPERATOR: + { + opmsg = " / "; + break; + } + case VALUE_NEG_OPERATOR: + { + opmsg = " -"; + break; + } + case VALUE_POS_OPERATOR: + { + opmsg = " +"; + break; + } + case VALUE_AND_OPERATOR: + { + opmsg = " & "; + break; + } + case VALUE_OR_OPERATOR: + { + opmsg = " | "; + break; + } + case VALUE_EQL_OPERATOR: + { + opmsg = " = "; + break; + } + case VALUE_NEQ_OPERATOR: + { + opmsg = " != "; + break; + } + case VALUE_NOT_OPERATOR: + { + opmsg = " !"; + break; + } + default: + { + opmsg = "Error in Errorhandling routine."; + break; + } } return opmsg; } - - - - //--------------------------------------------------------------------------------------------------------------------- // Property Management //--------------------------------------------------------------------------------------------------------------------- - - -// -// Set property , overwrites and releases a previous property with the same name if needed -// -void CValue::SetProperty(const STR_String & name,CValue* ioProperty) +/// Set property , overwrites and releases a previous property with the same name if needed. +void EXP_Value::SetProperty(const std::string & name, EXP_Value *ioProperty) { - if (ioProperty==NULL) - { // Check if somebody is setting an empty property + // Check if somebody is setting an empty property. + if (ioProperty == nullptr) { trace("Warning:trying to set empty property!"); return; } - if (m_pNamedPropertyArray) - { // Try to replace property (if so -> exit as soon as we replaced it) - CValue* oldval = (*m_pNamedPropertyArray)[name]; - if (oldval) - oldval->Release(); - } - else { // Make sure we have a property array - m_pNamedPropertyArray = new std::map; + // Try to replace property (if so -> exit as soon as we replaced it). + EXP_Value *oldval = m_properties[name]; + if (oldval) { + oldval->Release(); } - // Add property at end of array - (*m_pNamedPropertyArray)[name] = ioProperty->AddRef();//->Add(ioProperty); + // Add property at end of array. + m_properties[name] = ioProperty->AddRef(); } -void CValue::SetProperty(const char* name,CValue* ioProperty) +/// Get pointer to a property with name , returns nullptr if there is no property named . +EXP_Value *EXP_Value::GetProperty(const std::string & inName) { - if (ioProperty==NULL) - { // Check if somebody is setting an empty property - trace("Warning:trying to set empty property!"); - return; - } - - if (m_pNamedPropertyArray) - { // Try to replace property (if so -> exit as soon as we replaced it) - CValue* oldval = (*m_pNamedPropertyArray)[name]; - if (oldval) - oldval->Release(); + std::map::iterator it = m_properties.find(inName); + if (it != m_properties.end()) { + return it->second; } - else { // Make sure we have a property array - m_pNamedPropertyArray = new std::map; - } - - // Add property at end of array - (*m_pNamedPropertyArray)[name] = ioProperty->AddRef();//->Add(ioProperty); + return nullptr; } -// -// Get pointer to a property with name , returns NULL if there is no property named -// -CValue* CValue::GetProperty(const STR_String & inName) +/// Get text description of property with name , returns an empty string if there is no property named . +const std::string EXP_Value::GetPropertyText(const std::string & inName) { - if (m_pNamedPropertyArray) { - std::map::iterator it = m_pNamedPropertyArray->find(inName); - if (it != m_pNamedPropertyArray->end()) - return (*it).second; + EXP_Value *property = GetProperty(inName); + if (property) { + return property->GetText(); } - return NULL; -} - -CValue* CValue::GetProperty(const char *inName) -{ - if (m_pNamedPropertyArray) { - std::map::iterator it = m_pNamedPropertyArray->find(inName); - if (it != m_pNamedPropertyArray->end()) - return (*it).second; + else { + return ""; } - return NULL; } -// -// Get text description of property with name , returns an empty string if there is no property named -// -const STR_String& CValue::GetPropertyText(const STR_String & inName) +float EXP_Value::GetPropertyNumber(const std::string& inName, float defnumber) { - const static STR_String sEmpty(""); - - CValue *property = GetProperty(inName); - if (property) - return property->GetText(); - else - return sEmpty; -} - -float CValue::GetPropertyNumber(const STR_String& inName,float defnumber) -{ - CValue *property = GetProperty(inName); - if (property) + EXP_Value *property = GetProperty(inName); + if (property) { return property->GetNumber(); - else + } + else { return defnumber; + } } - - -// -// Remove the property named , returns true if the property was succesfully removed, false if property was not found or could not be removed -// -bool CValue::RemoveProperty(const char *inName) +/// Remove the property named , returns true if the property was succesfully removed, false if property was not found or could not be removed. +bool EXP_Value::RemoveProperty(const std::string& inName) { - // Check if there are properties at all which can be removed - if (m_pNamedPropertyArray) - { - std::map::iterator it = m_pNamedPropertyArray->find(inName); - if (it != m_pNamedPropertyArray->end()) - { - ((*it).second)->Release(); - m_pNamedPropertyArray->erase(it); - return true; - } + std::map::iterator it = m_properties.find(inName); + if (it != m_properties.end()) { + (*it).second->Release(); + m_properties.erase(it); + return true; } return false; } -// -// Get Property Names -// -vector CValue::GetPropertyNames() +/// Get Property Names. +std::vector EXP_Value::GetPropertyNames() { - vector result; - if (!m_pNamedPropertyArray) return result; - result.reserve(m_pNamedPropertyArray->size()); - - std::map::iterator it; - for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++) - { - result.push_back((*it).first); + const unsigned short size = m_properties.size(); + std::vector result(size); + + unsigned short i = 0; + for (const auto& pair : m_properties) { + result[i++] = pair.first; } return result; } -// -// Clear all properties -// -void CValue::ClearProperties() +/// Clear all properties. +void EXP_Value::ClearProperties() { - // Check if we have any properties - if (m_pNamedPropertyArray == NULL) - return; - - // Remove all properties - std::map::iterator it; - for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++) - { - CValue* tmpval = (*it).second; - //STR_String name = (*it).first; - tmpval->Release(); + // Remove all properties. + for (const auto& pair : m_properties) { + pair.second->Release(); } - - // Delete property array - delete m_pNamedPropertyArray; - m_pNamedPropertyArray=NULL; -} - - - -// -// Set all properties' modified flag to -// -void CValue::SetPropertiesModified(bool inModified) -{ - if (!m_pNamedPropertyArray) return; - std::map::iterator it; - - for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++) - ((*it).second)->SetModified(inModified); -} - - - -// -// Check if any of the properties in this value have been modified -// -bool CValue::IsAnyPropertyModified() -{ - if (!m_pNamedPropertyArray) return false; - std::map::iterator it; - - for (it= m_pNamedPropertyArray->begin();(it != m_pNamedPropertyArray->end()); it++) - if (((*it).second)->IsModified()) - return true; - - return false; + m_properties.clear(); } - - -// -// Get property number -// -CValue* CValue::GetProperty(int inIndex) +/// Get property number . +EXP_Value *EXP_Value::GetProperty(int inIndex) { - - int count=0; - CValue* result = NULL; - - if (m_pNamedPropertyArray) - { - std::map::iterator it; - for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++) - { - if (count++ == inIndex) - { - result = (*it).second; - break; - } + int count = 0; + for (const auto& pair : m_properties) { + if (count++ == inIndex) { + return pair.second; } - } - return result; + return nullptr; } - - -// -// Get the amount of properties assiocated with this value -// -int CValue::GetPropertyCount() +/// Get the amount of properties assiocated with this value. +int EXP_Value::GetPropertyCount() { - if (m_pNamedPropertyArray) - return m_pNamedPropertyArray->size(); - else - return 0; + return m_properties.size(); } - -double* CValue::GetVector3(bool bGetTransformedVec) +void EXP_Value::DestructFromPython() { - assertd(false); // don't get vector from me - return m_sZeroVec;//::sZero; +#ifdef WITH_PYTHON + // Avoid decrefing freed proxy in destructor. + m_proxy = nullptr; + Release(); +#endif // WITH_PYTHON } - -/*--------------------------------------------------------------------------------------------------------------------- - Reference Counting ----------------------------------------------------------------------------------------------------------------------*/ - - - -// -// Release a reference to this value (when reference count reaches 0, the value is removed from the heap) -// - - - -// -// Disable reference counting for this value -// -void CValue::DisableRefCount() +void EXP_Value::ProcessReplica() { - assertd(m_refcount == 1); - m_refcount--; - - //debug(gRefCountValue--); -#ifdef DEBUG - //gRefCountValue--; -#endif - m_ValFlags.RefCountDisabled=true; -} - + EXP_PyObjectPlus::ProcessReplica(); - -void CValue::ProcessReplica() /* was AddDataToReplica in 2.48 */ -{ - m_refcount = 1; - -#ifdef DEBUG - //gRefCountValue++; -#endif - PyObjectPlus::ProcessReplica(); - - m_ValFlags.RefCountDisabled = false; - - /* copy all props */ - if (m_pNamedPropertyArray) - { - std::map *pOldArray = m_pNamedPropertyArray; - m_pNamedPropertyArray=NULL; - std::map::iterator it; - for (it= pOldArray->begin(); (it != pOldArray->end()); it++) - { - CValue *val = (*it).second->GetReplica(); - SetProperty((*it).first,val); - val->Release(); - } + // Copy all props. + for (auto& pair : m_properties) { + pair.second = pair.second->GetReplica(); } } - - -int CValue::GetValueType() +int EXP_Value::GetValueType() { return VALUE_NO_TYPE; } - - -CValue* CValue::FindIdentifier(const STR_String& identifiername) +EXP_Value *EXP_Value::FindIdentifier(const std::string& identifiername) { - - CValue* result = NULL; + EXP_Value *result = nullptr; int pos = 0; // if a dot exists, explode the name into pieces to get the subcontext - if ((pos=identifiername.Find('.'))>=0) - { - const STR_String rightstring = identifiername.Right(identifiername.Length() -1 - pos); - const STR_String leftstring = identifiername.Left(pos); - CValue* tempresult = GetProperty(leftstring); - if (tempresult) - { - result=tempresult->FindIdentifier(rightstring); + if ((pos = identifiername.find('.')) != std::string::npos) { + const std::string rightstring = identifiername.substr(pos + 1); + const std::string leftstring = identifiername.substr(0, pos); + EXP_Value *tempresult = GetProperty(leftstring); + if (tempresult) { + result = tempresult->FindIdentifier(rightstring); } - } else - { + } + else { result = GetProperty(identifiername); - if (result) + if (result) { return result->AddRef(); + } } - if (!result) - { - // warning here !!! - result = new CErrorValue(identifiername+" not found"); + if (!result) { + result = new EXP_ErrorValue(identifiername + " not found"); } return result; } #ifdef WITH_PYTHON -PyAttributeDef CValue::Attributes[] = { - KX_PYATTRIBUTE_RO_FUNCTION("name", CValue, pyattr_get_name), - { NULL } //Sentinel +PyAttributeDef EXP_Value::Attributes[] = { + EXP_PYATTRIBUTE_RO_FUNCTION("name", EXP_Value, pyattr_get_name), + EXP_PYATTRIBUTE_NULL // Sentinel }; -PyObject *CValue::pyattr_get_name(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *EXP_Value::pyattr_get_name(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - CValue * self = static_cast (self_v); - return PyUnicode_From_STR_String(self->GetName()); + EXP_Value *self = static_cast (self_v); + return PyUnicode_FromStdString(self->GetName()); } /** - * There are 2 reasons this could return NULL + * There are 2 reasons this could return nullptr * - unsupported type. * - error converting (overflow). * * \param do_type_exception Use to skip raising an exception for unknown types. */ -CValue *CValue::ConvertPythonToValue(PyObject *pyobj, const bool do_type_exception, const char *error_prefix) +EXP_Value *EXP_Value::ConvertPythonToValue(PyObject *pyobj, const bool do_type_exception, const char *error_prefix) { - CValue *vallie; - /* refcounting is broking here! - this crashes anyway, just store a python list for KX_GameObject */ -#if 0 - if (PyList_Check(pyobj)) - { - CListValue* listval = new CListValue(); - bool error = false; - - Py_ssize_t i; - Py_ssize_t numitems = PyList_GET_SIZE(pyobj); - for (i=0;iAdd(listitemval); - } else - { - error = true; - } - } - if (!error) - { - // jippie! could be converted - vallie = listval; - } else - { - // list could not be converted... bad luck - listval->Release(); - } - - } else -#endif - /* note: Boolean check should go before Int check [#34677] */ - if (PyBool_Check(pyobj)) - { - vallie = new CBoolValue( (bool)PyLong_AsLongLong(pyobj) ); - } else - if (PyFloat_Check(pyobj)) - { + EXP_Value *vallie; + // Note: Boolean check should go before Int check [#34677]. + if (PyBool_Check(pyobj)) { + vallie = new EXP_BoolValue((bool)PyLong_AsLongLong(pyobj)); + } + else if (PyFloat_Check(pyobj)) { const double tval = PyFloat_AsDouble(pyobj); if (tval > (double)FLT_MAX || tval < (double)-FLT_MAX) { PyErr_Format(PyExc_OverflowError, "%soverflow converting from float, out of internal range", error_prefix); - vallie = NULL; + vallie = nullptr; } else { - vallie = new CFloatValue((float)tval); + vallie = new EXP_FloatValue((float)tval); } - } else - if (PyLong_Check(pyobj)) - { - vallie = new CIntValue( (cInt)PyLong_AsLongLong(pyobj) ); - } else - if (PyUnicode_Check(pyobj)) - { - vallie = new CStringValue(_PyUnicode_AsString(pyobj),""); - } else - if (PyObject_TypeCheck(pyobj, &CValue::Type)) /* Note, don't let these get assigned to GameObject props, must check elsewhere */ - { - vallie = (static_cast(BGE_PROXY_REF(pyobj)))->AddRef(); + } + else if (PyLong_Check(pyobj)) { + vallie = new EXP_IntValue((cInt)PyLong_AsLongLong(pyobj)); + } + else if (PyUnicode_Check(pyobj)) { + vallie = new EXP_StringValue(_PyUnicode_AsString(pyobj), ""); + } + // Note, don't let these get assigned to GameObject props, must check elsewhere. + else if (PyObject_TypeCheck(pyobj, &EXP_Value::Type)) { + vallie = (static_cast(EXP_PROXY_REF(pyobj)))->AddRef(); } else { if (do_type_exception) { - /* return an error value from the caller */ + // Return an error value from the caller. PyErr_Format(PyExc_TypeError, "%scould convert python value to a game engine property", error_prefix); } - vallie = NULL; + vallie = nullptr; } return vallie; } -PyObject *CValue::ConvertKeysToPython(void) +PyObject *EXP_Value::ConvertKeysToPython(void) { - if (m_pNamedPropertyArray) - { - PyObject *pylist= PyList_New(m_pNamedPropertyArray->size()); - Py_ssize_t i= 0; - - std::map::iterator it; - for (it= m_pNamedPropertyArray->begin(); (it != m_pNamedPropertyArray->end()); it++) - { - PyList_SET_ITEM(pylist, i++, PyUnicode_From_STR_String((*it).first)); - } + PyObject *pylist = PyList_New(m_properties.size()); - return pylist; - } - else { - return PyList_New(0); + Py_ssize_t i = 0; + for (const auto& pair : m_properties) { + PyList_SET_ITEM(pylist, i++, PyUnicode_FromStdString(pair.first)); } + + return pylist; +} + +#endif // WITH_PYTHON + +EXP_Value *EXP_Value::Calc(VALUE_OPERATOR op, EXP_Value *val) +{ + return nullptr; } -#endif // WITH_PYTHON +EXP_Value *EXP_Value::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, EXP_Value *val) +{ + return nullptr; +} +void EXP_Value::SetValue(EXP_Value *newval) +{ + // No one should get here. + BLI_assert(false); +} -/////////////////////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////////////////////// -/* These implementations were moved out of the header */ +std::string EXP_Value::GetText() +{ + return GetName(); +} -void CValue::SetOwnerExpression(class CExpression* expr) +double EXP_Value::GetNumber() { - /* intentionally empty */ + return -1.0; } -void CValue::SetColorOperator(VALUE_OPERATOR op) +void EXP_Value::SetName(const std::string& name) { - /* intentionally empty */ } -void CValue::SetValue(CValue* newval) + +EXP_Value *EXP_Value::GetReplica() { - // no one should get here - assertd(newval->GetNumber() == 10121969); + return nullptr; +} + +bool EXP_Value::IsError() const +{ + return false; } diff --git a/source/gameengine/Expressions/intern/VectorValue.cpp b/source/gameengine/Expressions/intern/VectorValue.cpp deleted file mode 100644 index dcb1f11ad1a0..000000000000 --- a/source/gameengine/Expressions/intern/VectorValue.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/** \file gameengine/Expressions/VectorValue.cpp - * \ingroup expressions - */ -// VectorValue.cpp: implementation of the CVectorValue class. -/* - * Copyright (c) 1996-2000 Erwin Coumans - * - * 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. Erwin Coumans makes no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied warranty. - * - */ - -#ifdef _MSC_VER -# pragma warning (disable:4786) -#endif - -#include "EXP_Value.h" -#include "EXP_VectorValue.h" -#include "EXP_ErrorValue.h" -//#include "MatrixValue.h" -#include "EXP_VoidValue.h" -#include "EXP_StringValue.h" -//#include "FactoryManager.h" - - - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CVectorValue::CVectorValue(float x,float y,float z, AllocationTYPE alloctype) -{ - SetCustomFlag1(false);//FancyOutput=false; - - if (alloctype == STACKVALUE) - { - CValue::DisableRefCount(); - }; - - m_vec[KX_X] = m_transformedvec[KX_X] = x; - m_vec[KX_Y] = m_transformedvec[KX_Y] = y; - m_vec[KX_Z] = m_transformedvec[KX_Z] = z; - -} -CVectorValue::CVectorValue(double vec[3], const char *name,AllocationTYPE alloctype) -{ - - SetCustomFlag1(false);//FancyOutput=false; - - m_vec[KX_X] = m_transformedvec[KX_X] = vec[KX_X]; - m_vec[KX_Y] = m_transformedvec[KX_Y] = vec[KX_Y]; - m_vec[KX_Z] = m_transformedvec[KX_Z] = vec[KX_Z]; - - if (alloctype == STACKVALUE) - { - CValue::DisableRefCount(); - - } - - SetName(name); -} - -CVectorValue::CVectorValue(double vec[3], AllocationTYPE alloctype) -{ - - SetCustomFlag1(false);//FancyOutput=false; - - m_vec[KX_X] = m_transformedvec[KX_X] = vec[KX_X]; - m_vec[KX_Y] = m_transformedvec[KX_Y] = vec[KX_Y]; - m_vec[KX_Z] = m_transformedvec[KX_Z] = vec[KX_Z]; - - if (alloctype == STACKVALUE) - { - CValue::DisableRefCount(); - - } - - -} -CVectorValue::~CVectorValue() -{ - -} - -/** - * pre: the type of val is dtype - * ret: a new object containing the result of applying operator op to val and - * this object - */ -CValue* CVectorValue::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val) -{ - CValue *ret = NULL; - - switch (op) { - case VALUE_ADD_OPERATOR: - { - switch (dtype) - { - case VALUE_EMPTY_TYPE: - case VALUE_VECTOR_TYPE: - { - ret = new CVectorValue( - val->GetVector3()[KX_X] + GetVector3()[KX_X], - val->GetVector3()[KX_Y] + GetVector3()[KX_Y], - val->GetVector3()[KX_Z] + GetVector3()[KX_Z], - CValue::HEAPVALUE); - ret->SetName(GetName()); - break; - } - - default: - ret = new CErrorValue(val->GetText() + op2str(op) + GetText()); - } - break; - } - case VALUE_MUL_OPERATOR: - { - switch (dtype) - { - - case VALUE_EMPTY_TYPE: - case VALUE_VECTOR_TYPE: - { - //MT_Vector3 supports 'scaling' by another vector, instead of using general transform, Gino? - //ret = new CVectorValue(val->GetVector3().Scaled(GetVector3()),GetName()); - break; - } - case VALUE_FLOAT_TYPE: - { - ret = new CVectorValue( - val->GetVector3()[KX_X] * GetVector3()[KX_X], - val->GetVector3()[KX_Y] * GetVector3()[KX_Y], - val->GetVector3()[KX_Z] * GetVector3()[KX_Z], - CValue::HEAPVALUE); - ret->SetName(GetName()); - break; - } - - default: - ret = new CErrorValue(val->GetText() + op2str(op) + GetText()); - } - break; - - } - - default: - ret = new CErrorValue(val->GetText() + op2str(op) + GetText()); - } - - - return ret; -} - -double CVectorValue::GetNumber() -{ - return m_vec[KX_X]; -} - - - -int CVectorValue::GetValueType() -{ - return VALUE_VECTOR_TYPE; -} - - - -double* CVectorValue::GetVector3(bool bGetTransformedVec) -{ - if (bGetTransformedVec) - return m_transformedvec; - // else - return m_vec; -} - - - - - -void CVectorValue::SetVector(double newvec[]) -{ - m_vec[KX_X] = m_transformedvec[KX_X] = newvec[KX_X]; - m_vec[KX_Y] = m_transformedvec[KX_Y] = newvec[KX_Y]; - m_vec[KX_Z] = m_transformedvec[KX_Z] = newvec[KX_Z]; - - SetModified(true); -} - - -void CVectorValue::SetValue(CValue *newval) -{ - - double* newvec = ((CVectorValue*)newval)->GetVector3(); - m_vec[KX_X] = m_transformedvec[KX_X] = newvec[KX_X]; - m_vec[KX_Y] = m_transformedvec[KX_Y] = newvec[KX_Y]; - m_vec[KX_Z] = m_transformedvec[KX_Z] = newvec[KX_Z]; - - SetModified(true); -} - -static const STR_String gstrVectorStr=STR_String(); -const STR_String & CVectorValue::GetText() -{ - assertd(false); - return gstrVectorStr; -} - -CValue* CVectorValue::GetReplica() -{ - CVectorValue* replica = new CVectorValue(*this); - replica->ProcessReplica(); - return replica; -}; - -#if 0 -void CVectorValue::Transform(rcMatrix4x4 mat) -{ - m_transformedvec = mat*m_vec; -} -#endif diff --git a/source/gameengine/GameLogic/CMakeLists.txt b/source/gameengine/GameLogic/CMakeLists.txt index b9eec74f6f4d..6518b0383416 100644 --- a/source/gameengine/GameLogic/CMakeLists.txt +++ b/source/gameengine/GameLogic/CMakeLists.txt @@ -25,17 +25,21 @@ set(INC . + ../Common + ../Device ../Expressions ../Rasterizer ../SceneGraph ../../blender/blenlib - ../../../intern/container - ../../../intern/string + ../../blender/python/generic + ../../../intern/termcolor ../../../intern/ghost ) set(INC_SYS - ../../../intern/moto/include + ../../../intern/debugbreak + ../../../intern/mathfu + ${BOOST_INCLUDE_DIR} ) set(SRC @@ -43,7 +47,6 @@ set(SRC SCA_ANDController.cpp SCA_ActuatorEventManager.cpp SCA_ActuatorSensor.cpp - SCA_AlwaysEventManager.cpp SCA_AlwaysSensor.cpp SCA_BasicEventManager.cpp SCA_DelaySensor.cpp @@ -53,6 +56,7 @@ set(SRC SCA_IController.cpp SCA_IInputDevice.cpp SCA_ILogicBrick.cpp + SCA_InputEvent.cpp SCA_IObject.cpp SCA_IScene.cpp SCA_ISensor.cpp @@ -67,27 +71,23 @@ set(SRC SCA_NORController.cpp SCA_ORController.cpp SCA_PropertyActuator.cpp - SCA_PropertyEventManager.cpp SCA_PropertySensor.cpp SCA_PythonController.cpp SCA_PythonJoystick.cpp SCA_PythonKeyboard.cpp SCA_PythonMouse.cpp SCA_RandomActuator.cpp - SCA_RandomEventManager.cpp SCA_RandomNumberGenerator.cpp SCA_RandomSensor.cpp SCA_TimeEventManager.cpp + SCA_VibrationActuator.cpp SCA_XNORController.cpp SCA_XORController.cpp - Joystick/SCA_Joystick.cpp - Joystick/SCA_JoystickEvents.cpp SCA_2DFilterActuator.h SCA_ANDController.h SCA_ActuatorEventManager.h SCA_ActuatorSensor.h - SCA_AlwaysEventManager.h SCA_AlwaysSensor.h SCA_BasicEventManager.h SCA_DelaySensor.h @@ -97,6 +97,7 @@ set(SRC SCA_IController.h SCA_IInputDevice.h SCA_ILogicBrick.h + SCA_InputEvent.h SCA_IObject.h SCA_IScene.h SCA_ISensor.h @@ -111,22 +112,18 @@ set(SRC SCA_NORController.h SCA_ORController.h SCA_PropertyActuator.h - SCA_PropertyEventManager.h SCA_PropertySensor.h SCA_PythonController.h SCA_PythonJoystick.h SCA_PythonKeyboard.h SCA_PythonMouse.h SCA_RandomActuator.h - SCA_RandomEventManager.h SCA_RandomNumberGenerator.h SCA_RandomSensor.h SCA_TimeEventManager.h + SCA_VibrationActuator.h SCA_XNORController.h SCA_XORController.h - Joystick/SCA_Joystick.h - Joystick/SCA_JoystickDefines.h - Joystick/SCA_JoystickPrivate.h ) if(WITH_SDL) diff --git a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp deleted file mode 100644 index 369ec4257cf3..000000000000 --- a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp +++ /dev/null @@ -1,382 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): snailrose. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/GameLogic/Joystick/SCA_Joystick.cpp - * \ingroup gamelogic - */ - -#include -#include - -#include "SCA_Joystick.h" -#include "SCA_JoystickPrivate.h" - -#include "BLI_path_util.h" - -#ifdef WITH_SDL -# ifdef WITH_SDL_DYNLOAD -# define SDL_CHECK(x) ((x) != (void *)0) -# else -# define SDL_CHECK(x) true -# endif -#endif - -SCA_Joystick::SCA_Joystick(short int index) - : - m_joyindex(index), - m_prec(3200), - m_axismax(-1), - m_buttonmax(-1), - m_hatmax(-1), - m_isinit(0), - m_istrig_axis(0), - m_istrig_button(0), - m_istrig_hat(0) -{ - for (int i=0; i < JOYAXIS_MAX; i++) - m_axis_array[i] = 0; - - for (int i=0; i < JOYHAT_MAX; i++) - m_hat_array[i] = 0; - -#ifdef WITH_SDL - m_private = new PrivateData(); -#endif -} - - -SCA_Joystick::~SCA_Joystick() - -{ -#ifdef WITH_SDL - delete m_private; -#endif -} - -SCA_Joystick *SCA_Joystick::m_instance[JOYINDEX_MAX]; -int SCA_Joystick::m_joynum = 0; -int SCA_Joystick::m_refCount = 0; - -SCA_Joystick *SCA_Joystick::GetInstance( short int joyindex ) -{ -#ifndef WITH_SDL - return NULL; -#else /* WITH_SDL */ - if (!SDL_CHECK(SDL_InitSubSystem)) { - return NULL; - } - if (joyindex < 0 || joyindex >= JOYINDEX_MAX) { - JOYSTICK_ECHO("Error-invalid joystick index: " << joyindex); - return NULL; - } - - if (m_refCount == 0) - { - int i; - - /* The video subsystem is required for joystick input to work. However, - * when GHOST is running under SDL, video is initialized elsewhere. We - * also need to set the videodriver to dummy, and do it here to avoid - * interfering with addons that may use SDL too. - * - * We also init SDL once only. */ -# ifdef WITH_GHOST_SDL - int success = (SDL_InitSubSystem(SDL_INIT_JOYSTICK) != -1 ); -# else - /* set and restore environment variable */ - char *videodriver = getenv("SDL_VIDEODRIVER"); - BLI_setenv("SDL_VIDEODRIVER", "dummy"); - -#if SDL_VERSION_ATLEAST(2, 0, 0) - int success = (SDL_InitSubSystem(SDL_INIT_JOYSTICK) != -1 ); -#else - int success = (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO) != -1 ); -#endif - - BLI_setenv("SDL_VIDEODRIVER", videodriver); -# endif - - if (!success) { - JOYSTICK_ECHO("Error-Initializing-SDL: " << SDL_GetError()); - return NULL; - } - - m_joynum = SDL_NumJoysticks(); - - for (i = 0; i < m_joynum; i++) { - m_instance[i] = new SCA_Joystick(i); - m_instance[i]->CreateJoystickDevice(); - } - m_refCount = 1; - } - else - { - m_refCount++; - } - return m_instance[joyindex]; -#endif /* WITH_SDL */ -} - -void SCA_Joystick::ReleaseInstance() -{ - if (--m_refCount == 0) - { -#ifdef WITH_SDL - if (!SDL_CHECK(SDL_QuitSubSystem)) { - return; - } - for (int i = 0; i < m_joynum; i++) { - if (m_instance[i]) { - m_instance[i]->DestroyJoystickDevice(); - delete m_instance[i]; - } - m_instance[i] = NULL; - } - - /* The video subsystem is required for joystick input to work. However, - * when GHOST is running under SDL, video is freed elsewhere. - * Do this once only. */ -#if SDL_VERSION_ATLEAST(2, 0, 0) - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); -#else - SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO); -#endif -#endif /* WITH_SDL */ - } -} - -void SCA_Joystick::cSetPrecision(int val) -{ - m_prec = val; -} - - -bool SCA_Joystick::aAxisPairIsPositive(int axis) -{ - return (pAxisTest(axis) > m_prec) ? true:false; -} - -bool SCA_Joystick::aAxisPairDirectionIsPositive(int axis, int dir) -{ - - int res; - - if (dir==JOYAXIS_UP || dir==JOYAXIS_DOWN) - res = pGetAxis(axis, 1); - else /* JOYAXIS_LEFT || JOYAXIS_RIGHT */ - res = pGetAxis(axis, 0); - - if (dir==JOYAXIS_DOWN || dir==JOYAXIS_RIGHT) - return (res > m_prec) ? true : false; - else /* JOYAXIS_UP || JOYAXIS_LEFT */ - return (res < -m_prec) ? true : false; -} - -bool SCA_Joystick::aAxisIsPositive(int axis_single) -{ - return abs(m_axis_array[axis_single]) > m_prec ? true:false; -} - -bool SCA_Joystick::aAnyButtonPressIsPositive(void) -{ -#ifdef WITH_SDL - if (!SDL_CHECK(SDL_JoystickGetButton)) { - return false; - } - /* this is needed for the "all events" option - * so we know if there are no buttons pressed */ - for (int i=0; im_joystick, i)) - return true; -#endif - return false; -} - -bool SCA_Joystick::aButtonPressIsPositive(int button) -{ -#ifndef WITH_SDL - return false; -#else - bool result; - result = SDL_CHECK(SDL_JoystickGetButton) && SDL_JoystickGetButton(m_private->m_joystick, button); - return result; -#endif -} - - -bool SCA_Joystick::aButtonReleaseIsPositive(int button) -{ -#ifndef WITH_SDL - return false; -#else - bool result; - result = !(SDL_CHECK(SDL_JoystickGetButton) && SDL_JoystickGetButton(m_private->m_joystick, button)); - return result; -#endif -} - - -bool SCA_Joystick::aHatIsPositive(int hatnum, int dir) -{ - return (GetHat(hatnum)==dir) ? true : false; -} - -int SCA_Joystick::GetNumberOfAxes() -{ - return m_axismax; -} - - -int SCA_Joystick::GetNumberOfButtons() -{ - return m_buttonmax; -} - - -int SCA_Joystick::GetNumberOfHats() -{ - return m_hatmax; -} - -bool SCA_Joystick::CreateJoystickDevice(void) -{ -#ifndef WITH_SDL - m_isinit = true; - m_axismax = m_buttonmax = m_hatmax = 0; - return false; -#else /* WITH_SDL */ - if (m_isinit == false && SDL_CHECK(SDL_JoystickOpen)) { - if (m_joyindex>=m_joynum) { - /* don't print a message, because this is done anyway */ - //JOYSTICK_ECHO("Joystick-Error: " << SDL_NumJoysticks() << " avaiable joystick(s)"); - - /* Need this so python args can return empty lists */ - m_axismax = m_buttonmax = m_hatmax = 0; - return false; - } - - m_private->m_joystick = SDL_JoystickOpen(m_joyindex); - SDL_JoystickEventState(SDL_ENABLE); - m_isinit = true; - - JOYSTICK_ECHO("Joystick " << m_joyindex << " initialized"); - - /* must run after being initialized */ - m_axismax = SDL_JoystickNumAxes(m_private->m_joystick); - m_buttonmax = SDL_JoystickNumButtons(m_private->m_joystick); - m_hatmax = SDL_JoystickNumHats(m_private->m_joystick); - - if (m_axismax > JOYAXIS_MAX) m_axismax = JOYAXIS_MAX; /* very unlikely */ - else if (m_axismax < 0) m_axismax = 0; - - if (m_hatmax > JOYHAT_MAX) m_hatmax = JOYHAT_MAX; /* very unlikely */ - else if (m_hatmax < 0) m_hatmax = 0; - - if (m_buttonmax < 0) m_buttonmax = 0; - - } - return true; -#endif /* WITH_SDL */ -} - - -void SCA_Joystick::DestroyJoystickDevice(void) -{ -#ifdef WITH_SDL - if (m_isinit) { -#if SDL_VERSION_ATLEAST(2, 0, 0) - if (SDL_CHECK(SDL_JoystickGetAttached) && SDL_JoystickGetAttached(m_private->m_joystick)) -#else - if (SDL_CHECK(SDL_JoystickOpened) && SDL_JoystickOpened(m_joyindex)) -#endif - { - JOYSTICK_ECHO("Closing-joystick " << m_joyindex); - SDL_JoystickClose(m_private->m_joystick); - } - m_isinit = false; - } -#endif /* WITH_SDL */ -} - -int SCA_Joystick::Connected(void) -{ -#ifdef WITH_SDL - if (m_isinit && -#if SDL_VERSION_ATLEAST(2, 0, 0) - SDL_CHECK(SDL_JoystickGetAttached) && SDL_JoystickGetAttached(m_private->m_joystick) -#else - SDL_CHECK(SDL_JoystickOpened) && SDL_JoystickOpened(m_joyindex) -#endif - ) - { - return 1; - } -#endif - return 0; -} - -int SCA_Joystick::pGetAxis(int axisnum, int udlr) -{ -#ifdef WITH_SDL - return m_axis_array[(axisnum*2)+udlr]; -#endif - return 0; -} - -int SCA_Joystick::pAxisTest(int axisnum) -{ -#ifdef WITH_SDL - /* Use ints instead of shorts here to avoid problems when we get -32768. - * When we take the negative of that later, we should get 32768, which is greater - * than what a short can hold. In other words, abs(MIN_SHORT) > MAX_SHRT. */ - int i1 = m_axis_array[(axisnum * 2)]; - int i2 = m_axis_array[(axisnum * 2) + 1]; - - /* long winded way to do: - * return max_ff(absf(i1), absf(i2)) - * ...avoid abs from math.h */ - if (i1 < 0) i1 = -i1; - if (i2 < 0) i2 = -i2; - if (i1 m_joystick) : ""; -#else - return (SDL_CHECK(SDL_JoystickName)) ? SDL_JoystickName(m_joyindex) : ""; -#endif -#else /* WITH_SDL */ - return ""; -#endif /* WITH_SDL */ -} diff --git a/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp b/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp deleted file mode 100644 index b1ce31662ed6..000000000000 --- a/source/gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): snailrose. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/GameLogic/Joystick/SCA_JoystickEvents.cpp - * \ingroup gamelogic - */ - -#include "SCA_Joystick.h" -#include "SCA_JoystickPrivate.h" - -#ifdef _MSC_VER -# include /* printf */ -#endif - -#ifdef WITH_SDL -void SCA_Joystick::OnAxisMotion(SDL_Event* sdl_event) -{ - if (sdl_event->jaxis.axis >= JOYAXIS_MAX) - return; - - m_axis_array[sdl_event->jaxis.axis] = sdl_event->jaxis.value; - m_istrig_axis = 1; -} - -/* See notes below in the event loop */ -void SCA_Joystick::OnHatMotion(SDL_Event* sdl_event) -{ - if (sdl_event->jhat.hat >= JOYHAT_MAX) - return; - - m_hat_array[sdl_event->jhat.hat] = sdl_event->jhat.value; - m_istrig_hat = 1; -} - -/* See notes below in the event loop */ -void SCA_Joystick::OnButtonUp(SDL_Event* sdl_event) -{ - m_istrig_button = 1; -} - - -void SCA_Joystick::OnButtonDown(SDL_Event* sdl_event) -{ - //if (sdl_event->jbutton.button > m_buttonmax) /* unsigned int so always above 0 */ - // return; - // sdl_event->jbutton.button; - - m_istrig_button = 1; -} - - -void SCA_Joystick::OnNothing(SDL_Event* sdl_event) -{ - m_istrig_axis = m_istrig_button = m_istrig_hat = 0; -} - -void SCA_Joystick::HandleEvents(void) -{ - SDL_Event sdl_event; - -#ifdef WITH_SDL_DYNLOAD - if (SDL_PollEvent == (void*)0) { - return; - } -#endif - - int i; - for (i=0; iOnNothing(&sdl_event); - } - - while (SDL_PollEvent(&sdl_event)) { - /* Note! m_instance[sdl_event.jaxis.which] - * will segfault if over JOYINDEX_MAX, not too nice but what are the chances? */ - - /* Note!, with buttons, this wont care which button is pressed, - * only to set 'm_istrig_button', actual pressed buttons are detected by SDL_JoystickGetButton */ - - /* Note!, if you manage to press and release a button within 1 logic tick - * it wont work as it should */ - - switch (sdl_event.type) { - case SDL_JOYAXISMOTION: - SCA_Joystick::m_instance[sdl_event.jaxis.which]->OnAxisMotion(&sdl_event); - break; - case SDL_JOYHATMOTION: - SCA_Joystick::m_instance[sdl_event.jhat.which]->OnHatMotion(&sdl_event); - break; - case SDL_JOYBUTTONUP: - SCA_Joystick::m_instance[sdl_event.jbutton.which]->OnButtonUp(&sdl_event); - break; - case SDL_JOYBUTTONDOWN: - SCA_Joystick::m_instance[sdl_event.jbutton.which]->OnButtonDown(&sdl_event); - break; -#if 0 /* Not used yet */ - case SDL_JOYBALLMOTION: - SCA_Joystick::m_instance[sdl_event.jball.which]->OnBallMotion(&sdl_event); - break; -#endif -#if SDL_VERSION_ATLEAST(2, 0, 0) - case SDL_JOYDEVICEADDED: - case SDL_JOYDEVICEREMOVED: - /* pass */ - break; -#endif - default: - printf("SCA_Joystick::HandleEvents, Unknown SDL event (%d), this should not happen\n", sdl_event.type); - break; - } - } -} -#endif /* WITH_SDL */ diff --git a/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp b/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp index 6a87d3ccb982..206b2f247c33 100644 --- a/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp +++ b/source/gameengine/GameLogic/SCA_2DFilterActuator.cpp @@ -27,44 +27,43 @@ */ -#include - #include "SCA_IActuator.h" #include "SCA_2DFilterActuator.h" - -#include - -SCA_2DFilterActuator::~SCA_2DFilterActuator() +#include "RAS_2DFilterData.h" +#include "RAS_2DFilterManager.h" +#include "RAS_2DFilter.h" + +#include "CM_Message.h" + +SCA_2DFilterActuator::SCA_2DFilterActuator(SCA_IObject *gameobj, + int type, + short flag, + float float_arg, + int int_arg, + bool mipmap, + RAS_Rasterizer *rasterizer, + RAS_2DFilterManager *filterManager, + SCA_IScene *scene) + :SCA_IActuator(gameobj, KX_ACT_2DFILTER), + m_type(type), + m_disableMotionBlur(flag), + m_float_arg(float_arg), + m_int_arg(int_arg), + m_mipmap(mipmap), + m_rasterizer(rasterizer), + m_filterManager(filterManager), + m_scene(scene) { + m_propNames = m_gameobj->GetPropertyNames(); } -SCA_2DFilterActuator::SCA_2DFilterActuator( - SCA_IObject *gameobj, - RAS_2DFilterManager::RAS_2DFILTER_MODE type, - short flag, - float float_arg, - int int_arg, - RAS_IRasterizer* rasterizer, - SCA_IScene* scene) - : SCA_IActuator(gameobj, KX_ACT_2DFILTER), - m_type(type), - m_disableMotionBlur(flag), - m_float_arg(float_arg), - m_int_arg(int_arg), - m_rasterizer(rasterizer), - m_scene(scene) +SCA_2DFilterActuator::~SCA_2DFilterActuator() { - m_gameobj = NULL; - if (gameobj) { - m_propNames = gameobj->GetPropertyNames(); - m_gameobj = gameobj; - } } - -CValue* SCA_2DFilterActuator::GetReplica() +EXP_Value *SCA_2DFilterActuator::GetReplica() { - SCA_2DFilterActuator* replica = new SCA_2DFilterActuator(*this); + SCA_2DFilterActuator *replica = new SCA_2DFilterActuator(*this); replica->ProcessReplica(); return replica; } @@ -76,33 +75,74 @@ bool SCA_2DFilterActuator::Update() RemoveAllEvents(); - if (bNegativeEvent) + if (bNegativeEvent) { return false; // do nothing on negative events - if ( m_type == RAS_2DFilterManager::RAS_2DFILTER_MOTIONBLUR ) - { - if (!m_disableMotionBlur) - m_rasterizer->EnableMotionBlur(m_float_arg); - else - m_rasterizer->DisableMotionBlur(); - - return false; } - else if (m_type < RAS_2DFilterManager::RAS_2DFILTER_NUMBER_OF_FILTERS) - { - m_scene->Update2DFilter(m_propNames, m_gameobj, m_type, m_int_arg, m_shaderText); + RAS_2DFilter *filter = m_filterManager->GetFilterPass(m_int_arg); + switch (m_type) { + case RAS_2DFilterManager::FILTER_ENABLED: + { + if (filter) { + filter->SetEnabled(true); + } + break; + } + case RAS_2DFilterManager::FILTER_DISABLED: + { + if (filter) { + filter->SetEnabled(false); + } + break; + } + case RAS_2DFilterManager::FILTER_NOFILTER: + { + m_filterManager->RemoveFilterPass(m_int_arg); + break; + } + case RAS_2DFilterManager::FILTER_MOTIONBLUR: + { + if (m_disableMotionBlur) { + m_rasterizer->DisableMotionBlur(); + } + else { + m_rasterizer->EnableMotionBlur(m_float_arg); + } + break; + } + default: + { + if (!filter) { + RAS_2DFilterData info; + info.filterPassIndex = m_int_arg; + info.gameObject = m_gameobj; + info.filterMode = m_type; + info.propertyNames = m_propNames; + info.shaderText = m_shaderText; + info.mipmap = m_mipmap; + + m_filterManager->AddFilter(info); + } + else { + CM_LogicBrickWarning(this, "2D Filter for pass index: " << m_int_arg << + " already exists, do nothing."); + } + break; + } } + // once the filter is in place, no need to update it again => disable the actuator return false; } -void SCA_2DFilterActuator::SetScene(SCA_IScene *scene) +void SCA_2DFilterActuator::SetScene(SCA_IScene *scene, RAS_2DFilterManager *filterManager) { m_scene = scene; + m_filterManager = filterManager; } -void SCA_2DFilterActuator::SetShaderText(const char *text) +void SCA_2DFilterActuator::SetShaderText(const std::string& text) { m_shaderText = text; } @@ -115,9 +155,9 @@ void SCA_2DFilterActuator::SetShaderText(const char *text) /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_2DFilterActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_2DFilterActuator", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -125,29 +165,29 @@ PyTypeObject SCA_2DFilterActuator::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IActuator::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_2DFilterActuator::Methods[] = { /* add python functions to deal with m_msg... */ - {NULL,NULL} + {nullptr, nullptr} }; PyAttributeDef SCA_2DFilterActuator::Attributes[] = { - KX_PYATTRIBUTE_STRING_RW("shaderText", 0, 64000, false, SCA_2DFilterActuator, m_shaderText), - KX_PYATTRIBUTE_SHORT_RW("disableMotionBlur", 0, 1, true, SCA_2DFilterActuator, m_disableMotionBlur), - KX_PYATTRIBUTE_ENUM_RW("mode",RAS_2DFilterManager::RAS_2DFILTER_ENABLED,RAS_2DFilterManager::RAS_2DFILTER_NUMBER_OF_FILTERS,false,SCA_2DFilterActuator,m_type), - KX_PYATTRIBUTE_INT_RW("passNumber", 0, 100, true, SCA_2DFilterActuator, m_int_arg), - KX_PYATTRIBUTE_FLOAT_RW("value", 0.0, 100.0, SCA_2DFilterActuator, m_float_arg), - { NULL } //Sentinel + EXP_PYATTRIBUTE_STRING_RW("shaderText", 0, 64000, false, SCA_2DFilterActuator, m_shaderText), + EXP_PYATTRIBUTE_SHORT_RW("disableMotionBlur", 0, 1, true, SCA_2DFilterActuator, m_disableMotionBlur), + EXP_PYATTRIBUTE_ENUM_RW("mode", RAS_2DFilterManager::FILTER_ENABLED, RAS_2DFilterManager::FILTER_NUMBER_OF_FILTERS, false, SCA_2DFilterActuator, m_type), + EXP_PYATTRIBUTE_INT_RW("passNumber", 0, 100, true, SCA_2DFilterActuator, m_int_arg), + EXP_PYATTRIBUTE_FLOAT_RW("value", 0.0, 100.0, SCA_2DFilterActuator, m_float_arg), + EXP_PYATTRIBUTE_NULL //Sentinel }; #endif diff --git a/source/gameengine/GameLogic/SCA_2DFilterActuator.h b/source/gameengine/GameLogic/SCA_2DFilterActuator.h index 4635a8ad9f8b..fcb9e3ca0b9f 100644 --- a/source/gameengine/GameLogic/SCA_2DFilterActuator.h +++ b/source/gameengine/GameLogic/SCA_2DFilterActuator.h @@ -31,41 +31,46 @@ #ifndef __SCA_2DFILTERACTUATOR_H__ #define __SCA_2DFILTERACTUATOR_H__ -#include "RAS_IRasterizer.h" +#include "RAS_Rasterizer.h" #include "SCA_IActuator.h" #include "SCA_IScene.h" +class RAS_2DFilterManager; + class SCA_2DFilterActuator : public SCA_IActuator { Py_Header private: - vector m_propNames; - RAS_2DFilterManager::RAS_2DFILTER_MODE m_type; + std::vector m_propNames; + int m_type; short m_disableMotionBlur; float m_float_arg; int m_int_arg; - STR_String m_shaderText; - RAS_IRasterizer* m_rasterizer; + bool m_mipmap; + std::string m_shaderText; + RAS_Rasterizer* m_rasterizer; + RAS_2DFilterManager *m_filterManager; SCA_IScene* m_scene; public: - SCA_2DFilterActuator( class SCA_IObject* gameobj, - RAS_2DFilterManager::RAS_2DFILTER_MODE type, + int type, short flag, float float_arg, int int_arg, - RAS_IRasterizer* rasterizer, + bool mipmap, + RAS_Rasterizer* rasterizer, + RAS_2DFilterManager *filterManager, SCA_IScene* scene); - void SetShaderText(const char *text); + void SetShaderText(const std::string& text); virtual ~SCA_2DFilterActuator(); virtual bool Update(); - void SetScene(SCA_IScene *scene); + void SetScene(SCA_IScene *scene, RAS_2DFilterManager *filterManager); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); }; #endif diff --git a/source/gameengine/GameLogic/SCA_ANDController.cpp b/source/gameengine/GameLogic/SCA_ANDController.cpp index 26380105e919..4d2781eb6b50 100644 --- a/source/gameengine/GameLogic/SCA_ANDController.cpp +++ b/source/gameengine/GameLogic/SCA_ANDController.cpp @@ -42,7 +42,7 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_ANDController::SCA_ANDController(SCA_IObject* gameobj) +SCA_ANDController::SCA_ANDController(SCA_IObject *gameobj) : SCA_IController(gameobj) { @@ -56,35 +56,28 @@ SCA_ANDController::~SCA_ANDController() -void SCA_ANDController::Trigger(SCA_LogicManager* logicmgr) +void SCA_ANDController::Trigger(SCA_LogicManager *logicmgr) { bool sensorresult = true; - for (vector::const_iterator is=m_linkedsensors.begin(); - !(is==m_linkedsensors.end());is++) - { - SCA_ISensor* sensor = *is; - if (!sensor->GetState()) - { + for (SCA_ISensor *sensor : m_linkedsensors) { + if (!sensor->GetState()) { sensorresult = false; break; } } - for (vector::const_iterator i=m_linkedactuators.begin(); - !(i==m_linkedactuators.end());i++) - { - SCA_IActuator* actua = *i; - logicmgr->AddActiveActuator(actua,sensorresult); + for (SCA_IActuator *actuator : m_linkedactuators) { + logicmgr->AddActiveActuator(actuator, sensorresult); } } -CValue* SCA_ANDController::GetReplica() +EXP_Value *SCA_ANDController::GetReplica() { - CValue* replica = new SCA_ANDController(*this); + EXP_Value *replica = new SCA_ANDController(*this); // this will copy properties and so on... replica->ProcessReplica(); @@ -99,9 +92,9 @@ CValue* SCA_ANDController::GetReplica() /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_ANDController::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_ANDController", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -109,23 +102,23 @@ PyTypeObject SCA_ANDController::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IController::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_ANDController::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef SCA_ANDController::Attributes[] = { - { NULL } //Sentinel + EXP_PYATTRIBUTE_NULL //Sentinel }; #endif // WITH_PYTHON /* eof */ diff --git a/source/gameengine/GameLogic/SCA_ANDController.h b/source/gameengine/GameLogic/SCA_ANDController.h index ff152d6d2fb7..ea302c651a71 100644 --- a/source/gameengine/GameLogic/SCA_ANDController.h +++ b/source/gameengine/GameLogic/SCA_ANDController.h @@ -44,7 +44,7 @@ class SCA_ANDController : public SCA_IController public: SCA_ANDController(SCA_IObject* gameobj); virtual ~SCA_ANDController(); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); virtual void Trigger(SCA_LogicManager* logicmgr); }; diff --git a/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp b/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp index fcb236f0913a..cdbbc2a91a05 100644 --- a/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_ActuatorEventManager.cpp @@ -35,8 +35,8 @@ #include "SCA_ActuatorSensor.h" -SCA_ActuatorEventManager::SCA_ActuatorEventManager(class SCA_LogicManager* logicmgr) - : SCA_EventManager(logicmgr, ACTUATOR_EVENTMGR) +SCA_ActuatorEventManager::SCA_ActuatorEventManager(class SCA_LogicManager *logicmgr) + :SCA_EventManager(logicmgr, ACTUATOR_EVENTMGR) { } @@ -50,19 +50,15 @@ SCA_ActuatorEventManager::~SCA_ActuatorEventManager() void SCA_ActuatorEventManager::NextFrame() { // check for changed actuator - SG_DList::iterator it(m_sensors); - for (it.begin();!it.end();++it) - { - (*it)->Activate(m_logicmgr); + for (SCA_ISensor *sensor : m_sensors) { + sensor->Activate(m_logicmgr); } } void SCA_ActuatorEventManager::UpdateFrame() { // update the state of actuator before executing them - SG_DList::iterator it(m_sensors); - for (it.begin();!it.end();++it) - { - (*it)->Update(); + for (SCA_ISensor *sensor : m_sensors) { + static_cast(sensor)->Update(); } } diff --git a/source/gameengine/GameLogic/SCA_ActuatorEventManager.h b/source/gameengine/GameLogic/SCA_ActuatorEventManager.h index 997be1145db0..9c8974c6448e 100644 --- a/source/gameengine/GameLogic/SCA_ActuatorEventManager.h +++ b/source/gameengine/GameLogic/SCA_ActuatorEventManager.h @@ -34,10 +34,6 @@ #include "SCA_EventManager.h" -#include - -using namespace std; - class SCA_ActuatorEventManager : public SCA_EventManager { public: @@ -45,12 +41,6 @@ class SCA_ActuatorEventManager : public SCA_EventManager virtual ~SCA_ActuatorEventManager(); virtual void NextFrame(); virtual void UpdateFrame(); - //SCA_LogicManager* GetLogicManager() { return m_logicmgr;} - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:SCA_ActuatorEventManager") -#endif }; #endif /* __SCA_ACTUATOREVENTMANAGER_H__ */ diff --git a/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp b/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp index 03c142e8c147..84f5206bf50c 100644 --- a/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp +++ b/source/gameengine/GameLogic/SCA_ActuatorSensor.cpp @@ -40,11 +40,11 @@ #include "SCA_EventManager.h" #include "SCA_LogicManager.h" -SCA_ActuatorSensor::SCA_ActuatorSensor(SCA_EventManager* eventmgr, - SCA_IObject* gameobj, - const STR_String& actname) - : SCA_ISensor(gameobj,eventmgr), - m_checkactname(actname) +SCA_ActuatorSensor::SCA_ActuatorSensor(SCA_EventManager *eventmgr, + SCA_IObject *gameobj, + const std::string& actname) + :SCA_ISensor(gameobj, eventmgr), + m_checkactname(actname) { m_actuator = GetParent()->FindActuator(m_checkactname); Init(); @@ -52,14 +52,14 @@ SCA_ActuatorSensor::SCA_ActuatorSensor(SCA_EventManager* eventmgr, void SCA_ActuatorSensor::Init() { - m_lastresult = m_invert?true:false; + m_lastresult = m_invert ? true : false; m_midresult = m_lastresult; m_reset = true; } -CValue* SCA_ActuatorSensor::GetReplica() +EXP_Value *SCA_ActuatorSensor::GetReplica() { - SCA_ActuatorSensor* replica = new SCA_ActuatorSensor(*this); + SCA_ActuatorSensor *replica = new SCA_ActuatorSensor(*this); // m_range_expr must be recalculated on replica! replica->ProcessReplica(); replica->Init(); @@ -67,7 +67,7 @@ CValue* SCA_ActuatorSensor::GetReplica() return replica; } -void SCA_ActuatorSensor::ReParent(SCA_IObject* parent) +void SCA_ActuatorSensor::ReParent(SCA_IObject *parent) { m_actuator = parent->FindActuator(m_checkactname); SCA_ISensor::ReParent(parent); @@ -76,8 +76,9 @@ void SCA_ActuatorSensor::ReParent(SCA_IObject* parent) bool SCA_ActuatorSensor::IsPositiveTrigger() { bool result = m_lastresult; - if (m_invert) + if (m_invert) { result = !result; + } return result; } @@ -92,14 +93,12 @@ SCA_ActuatorSensor::~SCA_ActuatorSensor() bool SCA_ActuatorSensor::Evaluate() { - if (m_actuator) - { + if (m_actuator) { bool result = m_actuator->IsActive(); bool reset = m_reset && m_level; m_reset = false; - if (m_lastresult != result || m_midresult != result) - { + if (m_lastresult != result || m_midresult != result) { m_lastresult = m_midresult = result; return true; } @@ -110,8 +109,7 @@ bool SCA_ActuatorSensor::Evaluate() void SCA_ActuatorSensor::Update() { - if (m_actuator) - { + if (m_actuator) { m_midresult = m_actuator->IsActive() && !m_actuator->IsNegativeEvent(); } } @@ -124,9 +122,9 @@ void SCA_ActuatorSensor::Update() /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_ActuatorSensor::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_ActuatorSensor", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -134,30 +132,30 @@ PyTypeObject SCA_ActuatorSensor::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_ISensor::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_ActuatorSensor::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef SCA_ActuatorSensor::Attributes[] = { - KX_PYATTRIBUTE_STRING_RW_CHECK("actuator",0,MAX_PROP_NAME,false,SCA_ActuatorSensor,m_checkactname,CheckActuator), - { NULL } //Sentinel + EXP_PYATTRIBUTE_STRING_RW_CHECK("actuator", 0, MAX_PROP_NAME, false, SCA_ActuatorSensor, m_checkactname, CheckActuator), + EXP_PYATTRIBUTE_NULL //Sentinel }; -int SCA_ActuatorSensor::CheckActuator(void *self, const PyAttributeDef*) +int SCA_ActuatorSensor::CheckActuator(EXP_PyObjectPlus *self, const PyAttributeDef *) { - SCA_ActuatorSensor* sensor = reinterpret_cast(self); - SCA_IActuator* act = sensor->GetParent()->FindActuator(sensor->m_checkactname); + SCA_ActuatorSensor *sensor = reinterpret_cast(self); + SCA_IActuator *act = sensor->GetParent()->FindActuator(sensor->m_checkactname); if (act) { sensor->m_actuator = act; return 0; diff --git a/source/gameengine/GameLogic/SCA_ActuatorSensor.h b/source/gameengine/GameLogic/SCA_ActuatorSensor.h index f728dc5c0caf..8e4f1c34325c 100644 --- a/source/gameengine/GameLogic/SCA_ActuatorSensor.h +++ b/source/gameengine/GameLogic/SCA_ActuatorSensor.h @@ -38,7 +38,7 @@ class SCA_ActuatorSensor : public SCA_ISensor { Py_Header - STR_String m_checkactname; + std::string m_checkactname; bool m_lastresult; bool m_midresult; protected: @@ -46,10 +46,10 @@ class SCA_ActuatorSensor : public SCA_ISensor public: SCA_ActuatorSensor(class SCA_EventManager* eventmgr, SCA_IObject* gameobj, - const STR_String& actname); - + const std::string& actname); + virtual ~SCA_ActuatorSensor(); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); virtual void Init(); virtual bool Evaluate(); virtual bool IsPositiveTrigger(); @@ -62,8 +62,8 @@ class SCA_ActuatorSensor : public SCA_ISensor /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - static int CheckActuator(void *self, const PyAttributeDef*); - + static int CheckActuator(EXP_PyObjectPlus *self, const PyAttributeDef*); + #endif /* WITH_PYTHON */ }; diff --git a/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp b/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp deleted file mode 100644 index 284bd3da8537..000000000000 --- a/source/gameengine/GameLogic/SCA_AlwaysEventManager.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Manager for 'always' events. Since always sensors can operate in pulse - * mode, they need to be activated. - * - * - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/GameLogic/SCA_AlwaysEventManager.cpp - * \ingroup gamelogic - */ - - -#include "SCA_AlwaysEventManager.h" -#include "SCA_LogicManager.h" -#include -#include "SCA_ISensor.h" - -using namespace std; - -SCA_AlwaysEventManager::SCA_AlwaysEventManager(class SCA_LogicManager* logicmgr) - : SCA_EventManager(logicmgr, ALWAYS_EVENTMGR) -{ -} - - - -void SCA_AlwaysEventManager::NextFrame() -{ - SG_DList::iterator it(m_sensors); - for (it.begin();!it.end();++it) - { - (*it)->Activate(m_logicmgr); - } -} diff --git a/source/gameengine/GameLogic/SCA_AlwaysEventManager.h b/source/gameengine/GameLogic/SCA_AlwaysEventManager.h deleted file mode 100644 index 47293c75726d..000000000000 --- a/source/gameengine/GameLogic/SCA_AlwaysEventManager.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file SCA_AlwaysEventManager.h - * \ingroup gamelogic - */ - -#ifndef __SCA_ALWAYSEVENTMANAGER_H__ -#define __SCA_ALWAYSEVENTMANAGER_H__ -#include "SCA_EventManager.h" -#include - -using namespace std; -class SCA_AlwaysEventManager : public SCA_EventManager -{ -public: - SCA_AlwaysEventManager(class SCA_LogicManager* logicmgr); - virtual void NextFrame(); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:SCA_AlwaysEventManager") -#endif -}; - -#endif /* __SCA_ALWAYSEVENTMANAGER_H__ */ diff --git a/source/gameengine/GameLogic/SCA_AlwaysSensor.cpp b/source/gameengine/GameLogic/SCA_AlwaysSensor.cpp index 28f8b2123e1c..ec18cec73c81 100644 --- a/source/gameengine/GameLogic/SCA_AlwaysSensor.cpp +++ b/source/gameengine/GameLogic/SCA_AlwaysSensor.cpp @@ -33,8 +33,8 @@ */ #ifdef _MSC_VER - /* This warning tells us about truncation of __long__ stl-generated names. - * It can occasionally cause DevStudio to have internal compiler warnings. */ +/* 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 @@ -46,9 +46,9 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_AlwaysSensor::SCA_AlwaysSensor(class SCA_EventManager* eventmgr, - SCA_IObject* gameobj) - : SCA_ISensor(gameobj,eventmgr) +SCA_AlwaysSensor::SCA_AlwaysSensor(class SCA_EventManager *eventmgr, + SCA_IObject *gameobj) + :SCA_ISensor(gameobj, eventmgr) { //SetDrawColor(255,0,0); Init(); @@ -66,9 +66,9 @@ SCA_AlwaysSensor::~SCA_AlwaysSensor() -CValue* SCA_AlwaysSensor::GetReplica() +EXP_Value *SCA_AlwaysSensor::GetReplica() { - CValue* replica = new SCA_AlwaysSensor(*this);//m_float,GetName()); + EXP_Value *replica = new SCA_AlwaysSensor(*this);//m_float,GetName()); // this will copy properties and so on... replica->ProcessReplica(); @@ -87,9 +87,9 @@ bool SCA_AlwaysSensor::IsPositiveTrigger() bool SCA_AlwaysSensor::Evaluate() { /* Nice! :) */ - //return true; + //return true; /* even nicer ;) */ - //return false; + //return false; /* nicest ! */ bool result = m_alwaysresult; @@ -105,9 +105,9 @@ bool SCA_AlwaysSensor::Evaluate() /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_AlwaysSensor::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_AlwaysSensor", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -115,23 +115,23 @@ PyTypeObject SCA_AlwaysSensor::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_ISensor::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_AlwaysSensor::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef SCA_AlwaysSensor::Attributes[] = { - { NULL } //Sentinel + EXP_PYATTRIBUTE_NULL //Sentinel }; #endif diff --git a/source/gameengine/GameLogic/SCA_AlwaysSensor.h b/source/gameengine/GameLogic/SCA_AlwaysSensor.h index e0ab4279b1cd..95bb4c21f964 100644 --- a/source/gameengine/GameLogic/SCA_AlwaysSensor.h +++ b/source/gameengine/GameLogic/SCA_AlwaysSensor.h @@ -44,7 +44,7 @@ class SCA_AlwaysSensor : public SCA_ISensor SCA_AlwaysSensor(class SCA_EventManager* eventmgr, SCA_IObject* gameobj); virtual ~SCA_AlwaysSensor(); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); virtual bool Evaluate(); virtual bool IsPositiveTrigger(); virtual void Init(); diff --git a/source/gameengine/GameLogic/SCA_BasicEventManager.cpp b/source/gameengine/GameLogic/SCA_BasicEventManager.cpp index 9cf65fdd1261..48b5cfbc2bd3 100644 --- a/source/gameengine/GameLogic/SCA_BasicEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_BasicEventManager.cpp @@ -36,13 +36,10 @@ #include "SCA_BasicEventManager.h" #include "SCA_LogicManager.h" -#include #include "SCA_ISensor.h" -using namespace std; - -SCA_BasicEventManager::SCA_BasicEventManager(class SCA_LogicManager* logicmgr) - : SCA_EventManager(logicmgr, BASIC_EVENTMGR) +SCA_BasicEventManager::SCA_BasicEventManager(class SCA_LogicManager *logicmgr) + :SCA_EventManager(logicmgr, BASIC_EVENTMGR) { } @@ -52,9 +49,8 @@ SCA_BasicEventManager::~SCA_BasicEventManager() void SCA_BasicEventManager::NextFrame() { - SG_DList::iterator it(m_sensors); - for (it.begin();!it.end();++it) - { - (*it)->Activate(m_logicmgr); + for (SCA_ISensor *sensor : m_sensors) { + sensor->Activate(m_logicmgr); } } + diff --git a/source/gameengine/GameLogic/SCA_BasicEventManager.h b/source/gameengine/GameLogic/SCA_BasicEventManager.h index a015233454b1..22bc291d9e9a 100644 --- a/source/gameengine/GameLogic/SCA_BasicEventManager.h +++ b/source/gameengine/GameLogic/SCA_BasicEventManager.h @@ -36,9 +36,6 @@ #define __SCA_BASICEVENTMANAGER_H__ #include "SCA_EventManager.h" -#include - -using namespace std; class SCA_BasicEventManager : public SCA_EventManager { @@ -47,11 +44,6 @@ class SCA_BasicEventManager : public SCA_EventManager ~SCA_BasicEventManager(); virtual void NextFrame(); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:SCA_BasicEventManager") -#endif }; #endif /* __SCA_BASICEVENTMANAGER_H__ */ diff --git a/source/gameengine/GameLogic/SCA_DelaySensor.cpp b/source/gameengine/GameLogic/SCA_DelaySensor.cpp index 5222d1961afc..a65046eca212 100644 --- a/source/gameengine/GameLogic/SCA_DelaySensor.cpp +++ b/source/gameengine/GameLogic/SCA_DelaySensor.cpp @@ -33,8 +33,8 @@ */ #ifdef _MSC_VER - /* This warning tells us about truncation of __long__ stl-generated names. - * It can occasionally cause DevStudio to have internal compiler warnings. */ +/* 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 @@ -48,12 +48,12 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_DelaySensor::SCA_DelaySensor(class SCA_EventManager* eventmgr, - SCA_IObject* gameobj, - int delay, - int duration, - bool repeat) - : SCA_ISensor(gameobj,eventmgr), +SCA_DelaySensor::SCA_DelaySensor(class SCA_EventManager *eventmgr, + SCA_IObject *gameobj, + int delay, + int duration, + bool repeat) + :SCA_ISensor(gameobj, eventmgr), m_repeat(repeat), m_delay(delay), m_duration(duration) @@ -73,9 +73,9 @@ SCA_DelaySensor::~SCA_DelaySensor() /* intentionally empty */ } -CValue* SCA_DelaySensor::GetReplica() +EXP_Value *SCA_DelaySensor::GetReplica() { - CValue* replica = new SCA_DelaySensor(*this); + EXP_Value *replica = new SCA_DelaySensor(*this); // this will copy properties and so on... replica->ProcessReplica(); @@ -94,32 +94,38 @@ bool SCA_DelaySensor::Evaluate() bool trigger = false; bool result; - if (m_frameCount==-1) { + if (m_frameCount == -1) { // this is needed to ensure ON trigger in case delay==0 // and avoid spurious OFF trigger when duration==0 m_lastResult = false; m_frameCount = 0; } - if (m_frameCount 0) { - if (m_frameCount < m_delay+m_duration) { + } + else if (m_duration > 0) { + if (m_frameCount < m_delay + m_duration) { m_frameCount++; result = true; - } else { + } + else { result = false; - if (m_repeat) + if (m_repeat) { m_frameCount = -1; + } } - } else { + } + else { result = true; - if (m_repeat) + if (m_repeat) { m_frameCount = -1; + } } - if ((m_reset && m_level) || result != m_lastResult) + if ((m_reset && m_level) || result != m_lastResult) { trigger = true; + } m_reset = false; m_lastResult = result; return trigger; @@ -133,9 +139,9 @@ bool SCA_DelaySensor::Evaluate() /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_DelaySensor::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_DelaySensor", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -143,26 +149,26 @@ PyTypeObject SCA_DelaySensor::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_ISensor::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_DelaySensor::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef SCA_DelaySensor::Attributes[] = { - KX_PYATTRIBUTE_INT_RW("delay",0,100000,true,SCA_DelaySensor,m_delay), - KX_PYATTRIBUTE_INT_RW("duration",0,100000,true,SCA_DelaySensor,m_duration), - KX_PYATTRIBUTE_BOOL_RW("repeat",SCA_DelaySensor,m_repeat), - { NULL } //Sentinel + EXP_PYATTRIBUTE_INT_RW("delay", 0, 100000, true, SCA_DelaySensor, m_delay), + EXP_PYATTRIBUTE_INT_RW("duration", 0, 100000, true, SCA_DelaySensor, m_duration), + EXP_PYATTRIBUTE_BOOL_RW("repeat", SCA_DelaySensor, m_repeat), + EXP_PYATTRIBUTE_NULL //Sentinel }; #endif // WITH_PYTHON diff --git a/source/gameengine/GameLogic/SCA_DelaySensor.h b/source/gameengine/GameLogic/SCA_DelaySensor.h index 0544bfef8c43..64d0de778ae7 100644 --- a/source/gameengine/GameLogic/SCA_DelaySensor.h +++ b/source/gameengine/GameLogic/SCA_DelaySensor.h @@ -41,7 +41,7 @@ class SCA_DelaySensor : public SCA_ISensor Py_Header bool m_lastResult; bool m_repeat; - int m_delay; + int m_delay; int m_duration; int m_frameCount; @@ -52,7 +52,7 @@ class SCA_DelaySensor : public SCA_ISensor int duration, bool repeat); virtual ~SCA_DelaySensor(); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); virtual bool Evaluate(); virtual bool IsPositiveTrigger(); virtual void Init(); diff --git a/source/gameengine/GameLogic/SCA_EventManager.cpp b/source/gameengine/GameLogic/SCA_EventManager.cpp index ffe1ea2dc306..2b32c7bd815e 100644 --- a/source/gameengine/GameLogic/SCA_EventManager.cpp +++ b/source/gameengine/GameLogic/SCA_EventManager.cpp @@ -30,12 +30,12 @@ */ -#include #include "SCA_EventManager.h" #include "SCA_ISensor.h" +#include "CM_List.h" -SCA_EventManager::SCA_EventManager(SCA_LogicManager* logicmgr, EVENT_MANAGER_TYPE mgrtype) +SCA_EventManager::SCA_EventManager(SCA_LogicManager *logicmgr, EVENT_MANAGER_TYPE mgrtype) :m_logicmgr(logicmgr), m_mgrtype(mgrtype) { @@ -46,17 +46,17 @@ SCA_EventManager::SCA_EventManager(SCA_LogicManager* logicmgr, EVENT_MANAGER_TYP SCA_EventManager::~SCA_EventManager() { // all sensors should be removed - assert(m_sensors.Empty()); + BLI_assert(m_sensors.empty()); } -void SCA_EventManager::RegisterSensor(class SCA_ISensor* sensor) +bool SCA_EventManager::RegisterSensor(class SCA_ISensor *sensor) { - m_sensors.AddBack(sensor); + return CM_ListAddIfNotFound(m_sensors, sensor); } -void SCA_EventManager::RemoveSensor(class SCA_ISensor* sensor) +bool SCA_EventManager::RemoveSensor(class SCA_ISensor *sensor) { - sensor->Delink(); + return CM_ListRemoveIfFound(m_sensors, sensor); } void SCA_EventManager::NextFrame(double curtime, double fixedtime) @@ -66,7 +66,7 @@ void SCA_EventManager::NextFrame(double curtime, double fixedtime) void SCA_EventManager::NextFrame() { - assert(false); // && "Event managers should override a NextFrame method"); + BLI_assert(false); // && "Event managers should override a NextFrame method"); } void SCA_EventManager::EndFrame() @@ -79,5 +79,5 @@ void SCA_EventManager::UpdateFrame() int SCA_EventManager::GetType() { - return (int) m_mgrtype; + return (int)m_mgrtype; } diff --git a/source/gameengine/GameLogic/SCA_EventManager.h b/source/gameengine/GameLogic/SCA_EventManager.h index 845a8c4c4ace..b46aee552cbd 100644 --- a/source/gameengine/GameLogic/SCA_EventManager.h +++ b/source/gameengine/GameLogic/SCA_EventManager.h @@ -36,23 +36,21 @@ #include #include -#include "SG_DList.h" +class SCA_ISensor; class SCA_EventManager { protected: class SCA_LogicManager* m_logicmgr; /* all event manager subclasses use this (other then TimeEventManager) */ - // use a set to speed-up insertion/removal - //std::set m_sensors; - SG_DList m_sensors; + std::vector m_sensors; public: enum EVENT_MANAGER_TYPE { KEYBOARD_EVENTMGR = 0, MOUSE_EVENTMGR, - ALWAYS_EVENTMGR, - TOUCH_EVENTMGR, + ALWAYS_EVENTMGR, + TOUCH_EVENTMGR, PROPERTY_EVENTMGR, TIME_EVENTMGR, RANDOM_EVENTMGR, @@ -65,26 +63,18 @@ class SCA_EventManager SCA_EventManager(SCA_LogicManager* logicmgr, EVENT_MANAGER_TYPE mgrtype); virtual ~SCA_EventManager(); - - virtual void RemoveSensor(class SCA_ISensor* sensor); + + virtual bool RemoveSensor(class SCA_ISensor* sensor); virtual void NextFrame(double curtime, double fixedtime); virtual void NextFrame(); virtual void UpdateFrame(); virtual void EndFrame(); - virtual void RegisterSensor(class SCA_ISensor* sensor); + virtual bool RegisterSensor(class SCA_ISensor* sensor); int GetType(); - //SG_DList &GetSensors() { return m_sensors; } - - - void Replace_LogicManager(SCA_LogicManager* logicmgr) { m_logicmgr= logicmgr; } protected: EVENT_MANAGER_TYPE m_mgrtype; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:SCA_EventManager") -#endif }; #endif + diff --git a/source/gameengine/GameLogic/SCA_ExpressionController.cpp b/source/gameengine/GameLogic/SCA_ExpressionController.cpp index ef058e215d63..530e54da3df7 100644 --- a/source/gameengine/GameLogic/SCA_ExpressionController.cpp +++ b/source/gameengine/GameLogic/SCA_ExpressionController.cpp @@ -38,20 +38,19 @@ #include "SCA_LogicManager.h" #include "EXP_BoolValue.h" #include "EXP_InputParser.h" -#include "MT_Transform.h" // for fuzzyZero - -#include +#include "mathfu.h" // for FuzzyZero +#include "CM_Message.h" /* ------------------------------------------------------------------------- */ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_ExpressionController::SCA_ExpressionController(SCA_IObject* gameobj, - const STR_String& exprtext) +SCA_ExpressionController::SCA_ExpressionController(SCA_IObject *gameobj, + const std::string& exprtext) :SCA_IController(gameobj), m_exprText(exprtext), - m_exprCache(NULL) + m_exprCache(nullptr) { } @@ -59,17 +58,18 @@ SCA_ExpressionController::SCA_ExpressionController(SCA_IObject* gameobj, SCA_ExpressionController::~SCA_ExpressionController() { - if (m_exprCache) + if (m_exprCache) { m_exprCache->Release(); + } } -CValue* SCA_ExpressionController::GetReplica() +EXP_Value *SCA_ExpressionController::GetReplica() { - SCA_ExpressionController* replica = new SCA_ExpressionController(*this); + SCA_ExpressionController *replica = new SCA_ExpressionController(*this); replica->m_exprText = m_exprText; - replica->m_exprCache = NULL; + replica->m_exprCache = nullptr; // this will copy properties and so on... replica->ProcessReplica(); @@ -81,65 +81,59 @@ CValue* SCA_ExpressionController::GetReplica() // Use this function when you know that you won't use the sensor anymore void SCA_ExpressionController::Delete() { - if (m_exprCache) - { + if (m_exprCache) { m_exprCache->Release(); - m_exprCache = NULL; + m_exprCache = nullptr; } Release(); } -void SCA_ExpressionController::Trigger(SCA_LogicManager* logicmgr) +void SCA_ExpressionController::Trigger(SCA_LogicManager *logicmgr) { bool expressionresult = false; - if (!m_exprCache) - { - CParser parser; + if (!m_exprCache) { + EXP_Parser parser; parser.SetContext(this->AddRef()); m_exprCache = parser.ProcessText(m_exprText); } - if (m_exprCache) - { - CValue* value = m_exprCache->Calculate(); - if (value) - { - if (value->IsError()) - { - printf("%s\n", value->GetText().ReadPtr()); - } else - { + if (m_exprCache) { + EXP_Value *value = m_exprCache->Calculate(); + if (value) { + if (value->IsError()) { + CM_LogicBrickError(this, value->GetText()); + } + else { float num = (float)value->GetNumber(); - expressionresult = !MT_fuzzyZero(num); + expressionresult = !mt::FuzzyZero(num); } value->Release(); } } - for (vector::const_iterator i=m_linkedactuators.begin(); - !(i==m_linkedactuators.end());i++) + for (std::vector::const_iterator i = m_linkedactuators.begin(); + !(i == m_linkedactuators.end()); i++) { - SCA_IActuator* actua = *i; - logicmgr->AddActiveActuator(actua,expressionresult); + SCA_IActuator *actua = *i; + logicmgr->AddActiveActuator(actua, expressionresult); } } -CValue* SCA_ExpressionController::FindIdentifier(const STR_String& identifiername) +EXP_Value *SCA_ExpressionController::FindIdentifier(const std::string& identifiername) { - CValue* identifierval = NULL; + EXP_Value *identifierval = nullptr; - for (vector::const_iterator is=m_linkedsensors.begin(); - !(is==m_linkedsensors.end());is++) + for (std::vector::const_iterator is = m_linkedsensors.begin(); + !(is == m_linkedsensors.end()); is++) { - SCA_ISensor* sensor = *is; - if (sensor->GetName() == identifiername) - { - identifierval = new CBoolValue(sensor->GetState()); + SCA_ISensor *sensor = *is; + if (sensor->GetName() == identifiername) { + identifierval = new EXP_BoolValue(sensor->GetState()); //identifierval = sensor->AddRef(); break; } @@ -151,9 +145,10 @@ CValue* SCA_ExpressionController::FindIdentifier(const STR_String& identifiernam //} } - if (identifierval) + if (identifierval) { return identifierval; + } - return GetParent()->FindIdentifier(identifiername); + return GetParent()->FindIdentifier(identifiername); } diff --git a/source/gameengine/GameLogic/SCA_ExpressionController.h b/source/gameengine/GameLogic/SCA_ExpressionController.h index 993b3b67a966..e82063ac4268 100644 --- a/source/gameengine/GameLogic/SCA_ExpressionController.h +++ b/source/gameengine/GameLogic/SCA_ExpressionController.h @@ -37,30 +37,27 @@ #include "SCA_IController.h" +class EXP_Expression; + class SCA_ExpressionController : public SCA_IController { // Py_Header - STR_String m_exprText; - CExpression* m_exprCache; + std::string m_exprText; + EXP_Expression* m_exprCache; public: SCA_ExpressionController(SCA_IObject* gameobj, - const STR_String& exprtext); + const std::string& exprtext); virtual ~SCA_ExpressionController(); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); virtual void Trigger(SCA_LogicManager* logicmgr); - virtual CValue* FindIdentifier(const STR_String& identifiername); - /** + virtual EXP_Value* FindIdentifier(const std::string& identifiername); + /** * used to release the expression cache * so that self references are removed before the controller itself is released */ virtual void Delete(); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:SCA_ExpressionController") -#endif }; #endif /* __SCA_EXPRESSIONCONTROLLER_H__ */ diff --git a/source/gameengine/GameLogic/SCA_IActuator.cpp b/source/gameengine/GameLogic/SCA_IActuator.cpp index b86a863ba426..efdcefacc6f5 100644 --- a/source/gameengine/GameLogic/SCA_IActuator.cpp +++ b/source/gameengine/GameLogic/SCA_IActuator.cpp @@ -31,57 +31,82 @@ #include "SCA_IActuator.h" -#include -using namespace std; +#include "CM_Message.h" +#include "CM_List.h" -SCA_IActuator::SCA_IActuator(SCA_IObject* gameobj, KX_ACTUATOR_TYPE type) : +SCA_IActuator::SCA_IActuator(SCA_IObject *gameobj, KX_ACTUATOR_TYPE type) : SCA_ILogicBrick(gameobj), m_type(type), m_links(0), m_posevent(false), m_negevent(false) { - // nothing to do } -bool SCA_IActuator::Update(double curtime, bool frame) +void SCA_IActuator::RemoveAllEvents() { - if (frame) - return Update(); + m_posevent = false; + m_negevent = false; +} + +bool SCA_IActuator::UnlinkObject(SCA_IObject *clientobj) +{ + return false; +} - return true; +bool SCA_IActuator::Update(double curtime) +{ + return Update(); } bool SCA_IActuator::Update() { - assert(false && "Actuators should override an Update method."); + BLI_assert(false && "Actuators should override an Update method."); return false; } +void SCA_IActuator::AddEvent(bool event) +{ + if (event) { + m_posevent = true; + } + else { + m_negevent = true; + } +} + +bool SCA_IActuator::IsNegativeEvent() const +{ + return !m_posevent && m_negevent; +} + +bool SCA_IActuator::IsPositiveEvent() const +{ + return m_posevent && !m_negevent; +} + void SCA_IActuator::Activate(SG_DList& head) { - if (QEmpty()) - { - InsertActiveQList(m_gameobj->m_activeActuators); - head.AddBack(&m_gameobj->m_activeActuators); + if (QEmpty()) { + SG_QList& list = m_gameobj->GetActiveActuators(); + InsertActiveQList(list); + head.AddBack(&list); } } -// this function is only used to deactivate actuators outside the logic loop -// e.g. when an object is deleted. void SCA_IActuator::Deactivate() { - if (QDelink()) - { + if (QDelink()) { + SG_QList& list = m_gameobj->GetActiveActuators(); // the actuator was in the active list - if (m_gameobj->m_activeActuators.QEmpty()) + if (list.QEmpty()) { // the owner object has no more active actuators, remove it from the global list - m_gameobj->m_activeActuators.Delink(); + list.Delink(); + } } } - void SCA_IActuator::ProcessReplica() { SCA_ILogicBrick::ProcessReplica(); @@ -89,51 +114,55 @@ void SCA_IActuator::ProcessReplica() m_linkedcontrollers.clear(); } - - SCA_IActuator::~SCA_IActuator() { RemoveAllEvents(); } +void SCA_IActuator::ClrLink() +{ + m_links = 0; +} +void SCA_IActuator::IncLink() +{ + m_links++; +} + void SCA_IActuator::DecLink() { - m_links--; - if (m_links < 0) - { - printf("Warning: actuator %s has negative m_links: %d\n", m_name.Ptr(), m_links); + --m_links; + if (m_links < 0) { + CM_LogicBrickWarning(this, "actuator " << m_name << " has negative m_links: " << m_links); m_links = 0; } } -void SCA_IActuator::LinkToController(SCA_IController* controller) +bool SCA_IActuator::IsNoLink() const +{ + return !m_links; +} +bool SCA_IActuator::IsType(KX_ACTUATOR_TYPE type) +{ + return m_type == type; +} + +void SCA_IActuator::LinkToController(SCA_IController *controller) { m_linkedcontrollers.push_back(controller); } -void SCA_IActuator::UnlinkController(SCA_IController* controller) +void SCA_IActuator::UnlinkController(SCA_IController *controller) { - std::vector::iterator contit; - for (contit = m_linkedcontrollers.begin();!(contit==m_linkedcontrollers.end());++contit) - { - if ((*contit) == controller) - { - *contit = m_linkedcontrollers.back(); - m_linkedcontrollers.pop_back(); - return; - } + if (!CM_ListRemoveIfFound(m_linkedcontrollers, controller)) { + CM_LogicBrickWarning(this, "Missing link from actuator " << m_gameobj->GetName() << ":" + << GetName() << " to controller " << controller->GetParent()->GetName() << ":" << controller->GetName()); } - printf("Missing link from actuator %s:%s to controller %s:%s\n", - m_gameobj->GetName().ReadPtr(), GetName().ReadPtr(), - controller->GetParent()->GetName().ReadPtr(), controller->GetName().ReadPtr()); } void SCA_IActuator::UnlinkAllControllers() { - std::vector::iterator contit; - for (contit = m_linkedcontrollers.begin();!(contit==m_linkedcontrollers.end());++contit) - { - (*contit)->UnlinkActuator(this); + for (SCA_IController *controller : m_linkedcontrollers) { + controller->UnlinkActuator(this); } m_linkedcontrollers.clear(); } diff --git a/source/gameengine/GameLogic/SCA_IActuator.h b/source/gameengine/GameLogic/SCA_IActuator.h index bca0b1ad764c..8a27f479ab44 100644 --- a/source/gameengine/GameLogic/SCA_IActuator.h +++ b/source/gameengine/GameLogic/SCA_IActuator.h @@ -33,7 +33,6 @@ #define __SCA_IACTUATOR_H__ #include "SCA_IController.h" -#include /** * Use of SG_DList : None @@ -43,22 +42,17 @@ class SCA_IActuator : public SCA_ILogicBrick { friend class SCA_LogicManager; -protected: - int m_type; - int m_links; // number of active links to controllers - // when 0, the actuator is automatically stopped - //std::vector m_events; - bool m_posevent; - bool m_negevent; - std::vector m_linkedcontrollers; +protected: + int m_type; + /// Number of active links to controllers when 0, the actuator is automatically stopped. + int m_links; + bool m_posevent; + bool m_negevent; - void RemoveAllEvents() - { - m_posevent = false; - m_negevent = false; - } + std::vector m_linkedcontrollers; + void RemoveAllEvents(); public: /** @@ -82,6 +76,7 @@ class SCA_IActuator : public SCA_ILogicBrick KX_ACT_ACTION, KX_ACT_CD, KX_ACT_GAME, + KX_ACT_VIBRATION, KX_ACT_VISIBILITY, KX_ACT_2DFILTER, KX_ACT_PARENT, @@ -92,7 +87,8 @@ class SCA_IActuator : public SCA_ILogicBrick KX_ACT_MOUSE, }; - SCA_IActuator(SCA_IObject* gameobj, KX_ACTUATOR_TYPE type); + SCA_IActuator(SCA_IObject *gameobj, KX_ACTUATOR_TYPE type); + virtual ~SCA_IActuator(); /** * UnlinkObject(...) @@ -101,7 +97,7 @@ class SCA_IActuator : public SCA_ILogicBrick * sure that the actuator will not use it anymore. */ - virtual bool UnlinkObject(SCA_IObject* clientobj) { return false; } + virtual bool UnlinkObject(SCA_IObject *clientobj); /** * Update(...) @@ -114,20 +110,13 @@ class SCA_IActuator : public SCA_ILogicBrick */ - virtual bool Update(double curtime, bool frame); + virtual bool Update(double curtime); virtual bool Update(); /** * Add an event to an actuator. */ - //void AddEvent(CValue* event) - void AddEvent(bool event) - { - if (event) - m_posevent = true; - else - m_negevent = true; - } + void AddEvent(bool event); virtual void ProcessReplica(); @@ -137,32 +126,26 @@ class SCA_IActuator : public SCA_ILogicBrick * not immediately clear. But usually refers to key-up events * or events where no action is required. */ - bool IsNegativeEvent() const - { - return !m_posevent && m_negevent; - } - - virtual ~SCA_IActuator(); + bool IsNegativeEvent() const; + bool IsPositiveEvent() const; /** - * remove this actuator from the list of active actuators + * Remove this actuator from the list of active actuators. + * This function is only used to deactivate actuators outside the logic loop + * e.g. when an object is deleted. */ virtual void Deactivate(); virtual void Activate(SG_DList& head); - void LinkToController(SCA_IController* controller); - void UnlinkController(class SCA_IController* cont); - void UnlinkAllControllers(); + void LinkToController(SCA_IController *controller); + void UnlinkController(SCA_IController *cont); + void UnlinkAllControllers(); - void ClrLink() { m_links=0; } - void IncLink() { m_links++; } + void ClrLink(); + void IncLink(); virtual void DecLink(); - bool IsNoLink() const { return !m_links; } - bool IsType(KX_ACTUATOR_TYPE type) { return m_type == type; } - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:SCA_IActuator") -#endif + bool IsNoLink() const; + bool IsType(KX_ACTUATOR_TYPE type); }; -#endif /* __SCA_IACTUATOR_H__ */ +#endif // __SCA_IACTUATOR_H__ diff --git a/source/gameengine/GameLogic/SCA_IController.cpp b/source/gameengine/GameLogic/SCA_IController.cpp index 46ea2910a74b..963834eb3d7f 100644 --- a/source/gameengine/GameLogic/SCA_IController.cpp +++ b/source/gameengine/GameLogic/SCA_IController.cpp @@ -29,185 +29,180 @@ * \ingroup gamelogic */ - -#include - #include "SCA_IController.h" -#include "SCA_LogicManager.h" #include "SCA_IActuator.h" #include "SCA_ISensor.h" -#include "EXP_PyObjectPlus.h" #include "EXP_ListWrapper.h" -#include +#include "CM_Message.h" +#include "CM_List.h" + +#include -SCA_IController::SCA_IController(SCA_IObject* gameobj) - : - SCA_ILogicBrick(gameobj), +SCA_IController::SCA_IController(SCA_IObject *gameobj) + :SCA_ILogicBrick(gameobj), m_statemask(0), m_justActivated(false) { } - - SCA_IController::~SCA_IController() { - //UnlinkAllActuators(); } - - -std::vector& SCA_IController::GetLinkedSensors() +std::vector& SCA_IController::GetLinkedSensors() { return m_linkedsensors; } - - -std::vector& SCA_IController::GetLinkedActuators() +std::vector& SCA_IController::GetLinkedActuators() { return m_linkedactuators; } - - void SCA_IController::UnlinkAllSensors() { - std::vector::iterator sensit; - for (sensit = m_linkedsensors.begin();!(sensit==m_linkedsensors.end());++sensit) - { - if (IsActive()) - { - (*sensit)->DecLink(); + for (SCA_ISensor *sensor : m_linkedsensors) { + if (IsActive()) { + sensor->DecLink(); } - (*sensit)->UnlinkController(this); + sensor->UnlinkController(this); } m_linkedsensors.clear(); } - - void SCA_IController::UnlinkAllActuators() { - std::vector::iterator actit; - for (actit = m_linkedactuators.begin();!(actit==m_linkedactuators.end());++actit) - { - if (IsActive()) - { - (*actit)->DecLink(); + for (SCA_IActuator *actuator : m_linkedactuators) { + if (IsActive()) { + actuator->DecLink(); } - (*actit)->UnlinkController(this); + actuator->UnlinkController(this); } m_linkedactuators.clear(); } -void SCA_IController::LinkToActuator(SCA_IActuator* actua) +void SCA_IController::LinkToActuator(SCA_IActuator *actua) { m_linkedactuators.push_back(actua); - if (IsActive()) - { + if (IsActive()) { actua->IncLink(); } } -void SCA_IController::UnlinkActuator(class SCA_IActuator* actua) +void SCA_IController::UnlinkActuator(SCA_IActuator *actua) { - std::vector::iterator actit; - for (actit = m_linkedactuators.begin();!(actit==m_linkedactuators.end());++actit) - { - if ((*actit) == actua) - { - if (IsActive()) - { - (*actit)->DecLink(); - } - *actit = m_linkedactuators.back(); - m_linkedactuators.pop_back(); - return; + if (CM_ListRemoveIfFound(m_linkedactuators, actua)) { + if (IsActive()) { + actua->DecLink(); } } - printf("Missing link from controller %s:%s to actuator %s:%s\n", - m_gameobj->GetName().ReadPtr(), GetName().ReadPtr(), - actua->GetParent()->GetName().ReadPtr(), actua->GetName().ReadPtr()); + else { + CM_LogicBrickWarning(this, "missing link from controller " << m_gameobj->GetName() << ":" << GetName() + << " to actuator " << actua->GetParent()->GetName() << ":" << actua->GetName()); + } } -void SCA_IController::LinkToSensor(SCA_ISensor* sensor) +void SCA_IController::LinkToSensor(SCA_ISensor *sensor) { m_linkedsensors.push_back(sensor); - if (IsActive()) - { + if (IsActive()) { sensor->IncLink(); } } -void SCA_IController::UnlinkSensor(class SCA_ISensor* sensor) +void SCA_IController::UnlinkSensor(SCA_ISensor *sensor) { - std::vector::iterator sensit; - for (sensit = m_linkedsensors.begin();!(sensit==m_linkedsensors.end());++sensit) - { - if ((*sensit) == sensor) - { - if (IsActive()) - { - sensor->DecLink(); - } - *sensit = m_linkedsensors.back(); - m_linkedsensors.pop_back(); - return; + if (CM_ListRemoveIfFound(m_linkedsensors, sensor)) { + if (IsActive()) { + sensor->DecLink(); } } - printf("Missing link from controller %s:%s to sensor %s:%s\n", - m_gameobj->GetName().ReadPtr(), GetName().ReadPtr(), - sensor->GetParent()->GetName().ReadPtr(), sensor->GetName().ReadPtr()); + else { + CM_LogicBrickWarning(this, "missing link from controller " << m_gameobj->GetName() << ":" << GetName() + << " to sensor " << sensor->GetParent()->GetName() << ":" << sensor->GetName()); + } } +void SCA_IController::SetState(unsigned int state) +{ + m_statemask = state; +} void SCA_IController::ApplyState(unsigned int state) { - std::vector::iterator actit; - std::vector::iterator sensit; - - if (m_statemask & state) - { - if (!IsActive()) - { + if (m_statemask & state) { + if (!IsActive()) { // reactive the controller, all the links to actuator are valid again - for (actit = m_linkedactuators.begin();!(actit==m_linkedactuators.end());++actit) - { - (*actit)->IncLink(); + for (SCA_IActuator *actuator : m_linkedactuators) { + actuator->IncLink(); } - for (sensit = m_linkedsensors.begin();!(sensit==m_linkedsensors.end());++sensit) - { - (*sensit)->IncLink(); + for (SCA_ISensor *sensor : m_linkedsensors) { + sensor->IncLink(); } SetActive(true); m_justActivated = true; } - } else if (IsActive()) - { - for (actit = m_linkedactuators.begin();!(actit==m_linkedactuators.end());++actit) - { - (*actit)->DecLink(); + } + else if (IsActive()) { + for (SCA_IActuator *actuator : m_linkedactuators) { + actuator->DecLink(); } - for (sensit = m_linkedsensors.begin();!(sensit==m_linkedsensors.end());++sensit) - { - (*sensit)->DecLink(); + + for (SCA_ISensor *sensor : m_linkedsensors) { + sensor->DecLink(); } SetActive(false); m_justActivated = false; } } +void SCA_IController::Deactivate() +{ + // the controller can only be part of a sensor m_newControllers list + Delink(); +} + +bool SCA_IController::IsJustActivated() +{ + return m_justActivated; +} + +void SCA_IController::ClrJustActivated() +{ + m_justActivated = false; +} + +void SCA_IController::SetBookmark(bool bookmark) +{ + m_bookmark = bookmark; +} + +void SCA_IController::Activate(SG_DList& head) +{ + if (QEmpty()) { + if (m_bookmark) { + SG_QList& list = SCA_IObject::GetActiveBookmarkedControllers(); + list.QAddBack(this); + head.AddFront(&list); + } + else { + SG_QList& list = m_gameobj->GetActiveControllers(); + InsertActiveQList(list); + head.AddBack(&list); + } + } +} + #ifdef WITH_PYTHON /* Python api */ PyTypeObject SCA_IController::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_IController", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -215,84 +210,74 @@ PyTypeObject SCA_IController::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_ILogicBrick::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_IController::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} // Sentinel }; PyAttributeDef SCA_IController::Attributes[] = { - KX_PYATTRIBUTE_RO_FUNCTION("state", SCA_IController, pyattr_get_state), - KX_PYATTRIBUTE_RO_FUNCTION("sensors", SCA_IController, pyattr_get_sensors), - KX_PYATTRIBUTE_RO_FUNCTION("actuators", SCA_IController, pyattr_get_actuators), - KX_PYATTRIBUTE_BOOL_RW("useHighPriority",SCA_IController,m_bookmark), - { NULL } //Sentinel + EXP_PYATTRIBUTE_RO_FUNCTION("state", SCA_IController, pyattr_get_state), + EXP_PYATTRIBUTE_RO_FUNCTION("sensors", SCA_IController, pyattr_get_sensors), + EXP_PYATTRIBUTE_RO_FUNCTION("actuators", SCA_IController, pyattr_get_actuators), + EXP_PYATTRIBUTE_BOOL_RW("useHighPriority", SCA_IController, m_bookmark), + EXP_PYATTRIBUTE_NULL // Sentinel }; -PyObject *SCA_IController::pyattr_get_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_IController::pyattr_get_state(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_IController* self = static_cast(self_v); + SCA_IController *self = static_cast(self_v); return PyLong_FromLong(self->m_statemask); } -static int sca_icontroller_get_sensors_size_cb(void *self_v) +unsigned int SCA_IController::py_get_sensors_size() { - return ((SCA_IController *)self_v)->GetLinkedSensors().size(); + return m_linkedsensors.size(); } -static PyObject *sca_icontroller_get_sensors_item_cb(void *self_v, int index) +PyObject *SCA_IController::py_get_sensors_item(unsigned int index) { - return ((SCA_IController *)self_v)->GetLinkedSensors()[index]->GetProxy(); + return m_linkedsensors[index]->GetProxy(); } -static const char *sca_icontroller_get_sensors_item_name_cb(void *self_v, int index) +std::string SCA_IController::py_get_sensors_item_name(unsigned int index) { - return ((SCA_IController *)self_v)->GetLinkedSensors()[index]->GetName().ReadPtr(); + return m_linkedsensors[index]->GetName(); } -PyObject *SCA_IController::pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_IController::pyattr_get_sensors(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - return (new CListWrapper(self_v, - ((SCA_IController *)self_v)->GetProxy(), - NULL, - sca_icontroller_get_sensors_size_cb, - sca_icontroller_get_sensors_item_cb, - sca_icontroller_get_sensors_item_name_cb, - NULL))->NewProxy(true); + return (new EXP_ListWrapper(self_v))->NewProxy(true); } -static int sca_icontroller_get_actuators_size_cb(void *self_v) +unsigned int SCA_IController::py_get_actuators_size() { - return ((SCA_IController *)self_v)->GetLinkedActuators().size(); + return m_linkedactuators.size(); } -static PyObject *sca_icontroller_get_actuators_item_cb(void *self_v, int index) +PyObject *SCA_IController::py_get_actuators_item(unsigned int index) { - return ((SCA_IController *)self_v)->GetLinkedActuators()[index]->GetProxy(); + return m_linkedactuators[index]->GetProxy(); } -static const char *sca_icontroller_get_actuators_item_name_cb(void *self_v, int index) +std::string SCA_IController::py_get_actuators_item_name(unsigned int index) { - return ((SCA_IController *)self_v)->GetLinkedActuators()[index]->GetName().ReadPtr(); + return m_linkedactuators[index]->GetName(); } -PyObject *SCA_IController::pyattr_get_actuators(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_IController::pyattr_get_actuators(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - return (new CListWrapper(self_v, - ((SCA_IController *)self_v)->GetProxy(), - NULL, - sca_icontroller_get_actuators_size_cb, - sca_icontroller_get_actuators_item_cb, - sca_icontroller_get_actuators_item_name_cb, - NULL))->NewProxy(true); + return (new EXP_ListWrapper(self_v))->NewProxy(true); } #endif // WITH_PYTHON diff --git a/source/gameengine/GameLogic/SCA_IController.h b/source/gameengine/GameLogic/SCA_IController.h index a249a6e85f9c..d9c3f7f0f46a 100644 --- a/source/gameengine/GameLogic/SCA_IController.h +++ b/source/gameengine/GameLogic/SCA_IController.h @@ -33,7 +33,6 @@ #define __SCA_ICONTROLLER_H__ #include "SCA_ILogicBrick.h" -#include "EXP_PyObjectPlus.h" /** * Use of SG_DList element: none @@ -43,70 +42,49 @@ class SCA_IController : public SCA_ILogicBrick { Py_Header + protected: - std::vector m_linkedsensors; - std::vector m_linkedactuators; - unsigned int m_statemask; - bool m_justActivated; - bool m_bookmark; + std::vector m_linkedsensors; + std::vector m_linkedactuators; + unsigned int m_statemask; + bool m_justActivated; + bool m_bookmark; + public: - SCA_IController(SCA_IObject* gameobj); + SCA_IController(SCA_IObject *gameobj); virtual ~SCA_IController(); - virtual void Trigger(class SCA_LogicManager* logicmgr)=0; - void LinkToSensor(SCA_ISensor* sensor); - void LinkToActuator(SCA_IActuator*); - std::vector& GetLinkedSensors(); - std::vector& GetLinkedActuators(); - void ReserveActuator(int num) - { - m_linkedactuators.reserve(num); - } - void UnlinkAllSensors(); - void UnlinkAllActuators(); - void UnlinkActuator(class SCA_IActuator* actua); - void UnlinkSensor(class SCA_ISensor* sensor); - void SetState(unsigned int state) { m_statemask = state; } - void ApplyState(unsigned int state); - void Deactivate() - { - // the controller can only be part of a sensor m_newControllers list - Delink(); - } - bool IsJustActivated() - { - return m_justActivated; - } - void ClrJustActivated() - { - m_justActivated = false; - } - void SetBookmark(bool bookmark) - { - m_bookmark = bookmark; - } - void Activate(SG_DList& head) - { - if (QEmpty()) - { - if (m_bookmark) - { - m_gameobj->m_activeBookmarkedControllers.QAddBack(this); - head.AddFront(&m_gameobj->m_activeBookmarkedControllers); - } - else - { - InsertActiveQList(m_gameobj->m_activeControllers); - head.AddBack(&m_gameobj->m_activeControllers); - } - } - } + virtual void Trigger(SCA_LogicManager *logicmgr) = 0; + + void LinkToSensor(SCA_ISensor *sensor); + void LinkToActuator(SCA_IActuator *); + std::vector& GetLinkedSensors(); + std::vector& GetLinkedActuators(); + void UnlinkAllSensors(); + void UnlinkAllActuators(); + void UnlinkActuator(SCA_IActuator *actua); + void UnlinkSensor(SCA_ISensor *sensor); + void SetState(unsigned int state); + void ApplyState(unsigned int state); + void Deactivate(); + bool IsJustActivated(); + void ClrJustActivated(); + void SetBookmark(bool bookmark); + void Activate(SG_DList& head); #ifdef WITH_PYTHON - static PyObject* pyattr_get_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_actuators(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); -#endif /* WITH_PYTHON */ + static PyObject *pyattr_get_state(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_sensors(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_actuators(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + + unsigned int py_get_sensors_size(); + PyObject *py_get_sensors_item(unsigned int index); + std::string py_get_sensors_item_name(unsigned int index); + + unsigned int py_get_actuators_size(); + PyObject *py_get_actuators_item(unsigned int index); + std::string py_get_actuators_item_name(unsigned int index); +#endif // WITH_PYTHON }; -#endif /* __SCA_ICONTROLLER_H__ */ +#endif // __SCA_ICONTROLLER_H__ diff --git a/source/gameengine/GameLogic/SCA_IInputDevice.cpp b/source/gameengine/GameLogic/SCA_IInputDevice.cpp index 0808028fed37..cfdf67c7c911 100644 --- a/source/gameengine/GameLogic/SCA_IInputDevice.cpp +++ b/source/gameengine/GameLogic/SCA_IInputDevice.cpp @@ -30,110 +30,161 @@ */ -#include +#include "BLI_utildefines.h" #include "SCA_IInputDevice.h" -SCA_IInputDevice::SCA_IInputDevice() - : - m_currentTable(0) +/** Initialize conversion table key to char (shifted too), this function is a long function but + * is easier to maintain than key index conversion way. + */ +static std::map > createKeyToCharMap() { - ClearStatusTable(0); - ClearStatusTable(1); + std::map > map; + + map[SCA_IInputDevice::RETKEY] = std::make_pair('\n', '\n'); + map[SCA_IInputDevice::SPACEKEY] = std::make_pair(' ', ' '); + map[SCA_IInputDevice::COMMAKEY] = std::make_pair(',', '<'); + map[SCA_IInputDevice::MINUSKEY] = std::make_pair('-', '_'); + map[SCA_IInputDevice::PERIODKEY] = std::make_pair('.', '>'); + map[SCA_IInputDevice::ZEROKEY] = std::make_pair('0', ')'); + map[SCA_IInputDevice::ONEKEY] = std::make_pair('1', '!'); + map[SCA_IInputDevice::TWOKEY] = std::make_pair('2', '@'); + map[SCA_IInputDevice::THREEKEY] = std::make_pair('3', '#'); + map[SCA_IInputDevice::FOURKEY] = std::make_pair('4', '$'); + map[SCA_IInputDevice::FIVEKEY] = std::make_pair('5', '%'); + map[SCA_IInputDevice::SIXKEY] = std::make_pair('6', '^'); + map[SCA_IInputDevice::SEVENKEY] = std::make_pair('7', '&'); + map[SCA_IInputDevice::EIGHTKEY] = std::make_pair('8', '*'); + map[SCA_IInputDevice::NINEKEY] = std::make_pair('9', '('); + map[SCA_IInputDevice::AKEY] = std::make_pair('a', 'A'); + map[SCA_IInputDevice::BKEY] = std::make_pair('b', 'B'); + map[SCA_IInputDevice::CKEY] = std::make_pair('c', 'C'); + map[SCA_IInputDevice::DKEY] = std::make_pair('d', 'D'); + map[SCA_IInputDevice::EKEY] = std::make_pair('e', 'E'); + map[SCA_IInputDevice::FKEY] = std::make_pair('f', 'F'); + map[SCA_IInputDevice::GKEY] = std::make_pair('g', 'G'); + map[SCA_IInputDevice::HKEY_] = std::make_pair('h', 'H'); + map[SCA_IInputDevice::IKEY] = std::make_pair('i', 'I'); + map[SCA_IInputDevice::JKEY] = std::make_pair('j', 'J'); + map[SCA_IInputDevice::KKEY] = std::make_pair('k', 'K'); + map[SCA_IInputDevice::LKEY] = std::make_pair('l', 'L'); + map[SCA_IInputDevice::MKEY] = std::make_pair('m', 'M'); + map[SCA_IInputDevice::NKEY] = std::make_pair('n', 'N'); + map[SCA_IInputDevice::OKEY] = std::make_pair('o', 'O'); + map[SCA_IInputDevice::PKEY] = std::make_pair('p', 'P'); + map[SCA_IInputDevice::QKEY] = std::make_pair('q', 'Q'); + map[SCA_IInputDevice::RKEY] = std::make_pair('r', 'R'); + map[SCA_IInputDevice::SKEY] = std::make_pair('s', 'S'); + map[SCA_IInputDevice::TKEY] = std::make_pair('t', 'T'); + map[SCA_IInputDevice::UKEY] = std::make_pair('u', 'U'); + map[SCA_IInputDevice::VKEY] = std::make_pair('v', 'V'); + map[SCA_IInputDevice::WKEY] = std::make_pair('w', 'W'); + map[SCA_IInputDevice::XKEY] = std::make_pair('x', 'X'); + map[SCA_IInputDevice::YKEY] = std::make_pair('y', 'Y'); + map[SCA_IInputDevice::ZKEY] = std::make_pair('z', 'Z'); + map[SCA_IInputDevice::TABKEY] = std::make_pair('\t', '\t'); + map[SCA_IInputDevice::SEMICOLONKEY] = std::make_pair(';', ':'); + map[SCA_IInputDevice::QUOTEKEY] = std::make_pair('\'', '\"'); + map[SCA_IInputDevice::ACCENTGRAVEKEY] = std::make_pair('`', '~'); + map[SCA_IInputDevice::SLASHKEY] = std::make_pair('/', '?'); + map[SCA_IInputDevice::BACKSLASHKEY] = std::make_pair('\\', '|'); + map[SCA_IInputDevice::EQUALKEY] = std::make_pair('=', '+'); + map[SCA_IInputDevice::LEFTBRACKETKEY] = std::make_pair('[', '{'); + map[SCA_IInputDevice::RIGHTBRACKETKEY] = std::make_pair(']', '}'); + map[SCA_IInputDevice::PAD1] = std::make_pair('1', '1'); + map[SCA_IInputDevice::PAD2] = std::make_pair('2', '2'); + map[SCA_IInputDevice::PAD3] = std::make_pair('3', '3'); + map[SCA_IInputDevice::PAD4] = std::make_pair('4', '4'); + map[SCA_IInputDevice::PAD5] = std::make_pair('5', '5'); + map[SCA_IInputDevice::PAD6] = std::make_pair('6', '6'); + map[SCA_IInputDevice::PAD7] = std::make_pair('7', '7'); + map[SCA_IInputDevice::PAD9] = std::make_pair('8', '8'); + map[SCA_IInputDevice::PAD0] = std::make_pair('9', '9'); + map[SCA_IInputDevice::PADASTERKEY] = std::make_pair('*', '*'); + map[SCA_IInputDevice::PADPERIOD] = std::make_pair('.', '.'); + map[SCA_IInputDevice::PADSLASHKEY] = std::make_pair('/', '/'); + map[SCA_IInputDevice::PADMINUS] = std::make_pair('-', '-'); + map[SCA_IInputDevice::PADENTER] = std::make_pair('\n', '\n'); + map[SCA_IInputDevice::PADPLUSKEY] = std::make_pair('+', '+'); + + return map; } +std::map > SCA_IInputDevice::m_keyToChar = createKeyToCharMap(); +SCA_IInputDevice::SCA_IInputDevice() + :m_hookExitKey(false) +{ + for (int i = 0; i < SCA_IInputDevice::MAX_KEYS; ++i) { + m_inputsTable[i] = SCA_InputEvent(i); + } +} SCA_IInputDevice::~SCA_IInputDevice() { + for (int i = 0; i < SCA_IInputDevice::MAX_KEYS; ++i) { + m_inputsTable[i].InvalidateProxy(); + } } -void SCA_IInputDevice::HookEscape() +void SCA_IInputDevice::SetHookExitKey(bool hook) { - assert(false && "This device does not support hooking escape."); + m_hookExitKey = hook; } -void SCA_IInputDevice::ClearStatusTable(int tableid) +bool SCA_IInputDevice::GetHookExitKey() const { - for (int i=0;i >::iterator it = m_keyToChar.find(input); + if (it == m_keyToChar.end()) { + return 0; } - return num; + return (shifted) ? it->second.second : it->second.first; } - - -void SCA_IInputDevice::NextFrame() +SCA_InputEvent& SCA_IInputDevice::GetInput(SCA_IInputDevice::SCA_EnumInputs inputcode) { - m_currentTable = 1 - m_currentTable; - - // cerr << "SCA_IInputDevice::NextFrame " << GetNumActiveEvents() << endl; - - for (int i=0;i - SCA_EnumInputs m_status; - int m_eventval; - unsigned int m_unicode; -}; - -/* Originally from wm_event_types.h, now only used by GameEngine */ -#define MOUSEX MOUSEMOVE -#define MOUSEY ACTIONMOUSE - -class SCA_IInputDevice +class SCA_IInputDevice { - - public: - SCA_IInputDevice(); virtual ~SCA_IInputDevice(); - enum KX_EnumInputs { - - KX_NOKEY = 0, - - // TIMERS - - KX_TIMER0, - KX_TIMER1, - KX_TIMER2, - - // SYSTEM - - /* Moved to avoid clashes with KX_RETKEY */ - KX_KEYBD, - KX_RAWKEYBD, - KX_REDRAW, - KX_INPUTCHANGE, - KX_QFULL, - KX_WINFREEZE, - KX_WINTHAW, - /* thaw is 11 */ - - /* move past retkey*/ - KX_WINCLOSE = 14, - KX_WINQUIT, - KX_Q_FIRSTTIME, - /* sequence ends on 16 */ - - // standard keyboard - - /* Because of the above preamble, KX_BEGINKEY is 15 ! This - * means that KX_RETKEY on 13d (0Dh)) will double up with - * KX_WINQUIT! Why is it 13? Because ascii 13d is Ctrl-M aka - * CR! Its little brother, LF has 10d (0Ah). This is - * dangerous, since the keyboards start scanning at - * KX_BEGINKEY. I think the keyboard system should push its - * key events instead of demanding the user to poll the - * table... But that's for another time... The fix for now is - * to move the above system events into a 'safe' (ie. unused) - * range. I am loathe to move it away from this 'magical' - * coincidence.. it's probably exploited somewhere. I hope the - * close and quit events don't mess up 'normal' kb code - * scanning. - * */ - KX_BEGINKEY = 12, - - KX_RETKEY = 13, - KX_SPACEKEY = 32, - KX_PADASTERKEY = 42, - KX_COMMAKEY = 44, - KX_MINUSKEY = 45, - KX_PERIODKEY = 46, - KX_PLUSKEY = 47, - KX_ZEROKEY = 48, - - KX_ONEKEY, // =49 - KX_TWOKEY, - KX_THREEKEY, - KX_FOURKEY, - KX_FIVEKEY, - KX_SIXKEY, - KX_SEVENKEY, - KX_EIGHTKEY, - KX_NINEKEY, // = 57 - - KX_AKEY = 97, - KX_BKEY, - KX_CKEY, - KX_DKEY, - KX_EKEY, - KX_FKEY, - KX_GKEY, - KX_HKEY, - KX_IKEY, - KX_JKEY, - KX_KKEY, - KX_LKEY, - KX_MKEY, - KX_NKEY, // =110 - KX_OKEY, - KX_PKEY, - KX_QKEY, - KX_RKEY, - KX_SKEY, - KX_TKEY, - KX_UKEY, - KX_VKEY, - KX_WKEY, - KX_XKEY, // =120 - KX_YKEY, - KX_ZKEY, // =122 - - - - KX_CAPSLOCKKEY, // 123 - - KX_LEFTCTRLKEY, // 124 - KX_LEFTALTKEY, - KX_RIGHTALTKEY, - KX_RIGHTCTRLKEY, - KX_RIGHTSHIFTKEY, - KX_LEFTSHIFTKEY,// 129 - - KX_ESCKEY, // 130 - KX_TABKEY, //131 - - - KX_LINEFEEDKEY, // 132 - KX_BACKSPACEKEY, - KX_DELKEY, - KX_SEMICOLONKEY, // 135 - - - KX_QUOTEKEY, //136 - KX_ACCENTGRAVEKEY, //137 - - KX_SLASHKEY, //138 - KX_BACKSLASHKEY, - KX_EQUALKEY, - KX_LEFTBRACKETKEY, - KX_RIGHTBRACKETKEY, // 142 - - KX_LEFTARROWKEY, // 145 - KX_DOWNARROWKEY, - KX_RIGHTARROWKEY, - KX_UPARROWKEY, // 148 - - KX_PAD2 , - KX_PAD4 , - KX_PAD6 , - KX_PAD8 , - - KX_PAD1 , - KX_PAD3 , - KX_PAD5 , - KX_PAD7 , - KX_PAD9 , - - KX_PADPERIOD, - KX_PADSLASHKEY, - - - - KX_PAD0 , - KX_PADMINUS, - KX_PADENTER, - KX_PADPLUSKEY, - - - KX_F1KEY , - KX_F2KEY , - KX_F3KEY , - KX_F4KEY , - KX_F5KEY , - KX_F6KEY , - KX_F7KEY , - KX_F8KEY , - KX_F9KEY , - KX_F10KEY, - KX_F11KEY, - KX_F12KEY, - KX_F13KEY, - KX_F14KEY, - KX_F15KEY, - KX_F16KEY, - KX_F17KEY, - KX_F18KEY, - KX_F19KEY, - - KX_OSKEY, - - KX_PAUSEKEY, - KX_INSERTKEY, - KX_HOMEKEY , - KX_PAGEUPKEY, - KX_PAGEDOWNKEY, - KX_ENDKEY, - - // MOUSE - KX_BEGINMOUSE, - - KX_BEGINMOUSEBUTTONS, - - KX_LEFTMOUSE, - KX_MIDDLEMOUSE, - KX_RIGHTMOUSE, - - KX_ENDMOUSEBUTTONS, - - KX_WHEELUPMOUSE, - KX_WHEELDOWNMOUSE, - - KX_MOUSEX, - KX_MOUSEY, - - KX_ENDMOUSE, - - - - KX_MAX_KEYS - + enum SCA_EnumInputs { + NOKEY = 0, + + BEGINWIN, + + WINRESIZE, + WINCLOSE, + WINQUIT, + + ENDWIN, + + BEGINKEY, + + RETKEY, + SPACEKEY, + PADASTERKEY, + COMMAKEY, + MINUSKEY, + PERIODKEY, + + ZEROKEY, + ONEKEY, + TWOKEY, + THREEKEY, + FOURKEY, + FIVEKEY, + SIXKEY, + SEVENKEY, + EIGHTKEY, + NINEKEY, + + AKEY, + BKEY, + CKEY, + DKEY, + EKEY, + FKEY, + GKEY, + /* To avoid conflict with typedef HKEY () + * we rename HKEY to HKEY_ */ + HKEY_, + IKEY, + JKEY, + KKEY, + LKEY, + MKEY, + NKEY, + OKEY, + PKEY, + QKEY, + RKEY, + SKEY, + TKEY, + UKEY, + VKEY, + WKEY, + XKEY, + YKEY, + ZKEY, + + CAPSLOCKKEY, + + LEFTCTRLKEY, + LEFTALTKEY, + RIGHTALTKEY, + RIGHTCTRLKEY, + RIGHTSHIFTKEY, + LEFTSHIFTKEY, + + ESCKEY, + TABKEY, + + LINEFEEDKEY, + BACKSPACEKEY, + DELKEY, + SEMICOLONKEY, + + QUOTEKEY, + ACCENTGRAVEKEY, + + SLASHKEY, + BACKSLASHKEY, + EQUALKEY, + LEFTBRACKETKEY, + RIGHTBRACKETKEY, + + LEFTARROWKEY, + DOWNARROWKEY, + RIGHTARROWKEY, + UPARROWKEY, + + PAD2, + PAD4, + PAD6, + PAD8, + + PAD1, + PAD3, + PAD5, + PAD7, + PAD9, + + PADPERIOD, + PADSLASHKEY, + + PAD0, + PADMINUS, + PADENTER, + PADPLUSKEY, + + F1KEY, + F2KEY, + F3KEY, + F4KEY, + F5KEY, + F6KEY, + F7KEY, + F8KEY, + F9KEY, + F10KEY, + F11KEY, + F12KEY, + F13KEY, + F14KEY, + F15KEY, + F16KEY, + F17KEY, + F18KEY, + F19KEY, + + OSKEY, + + PAUSEKEY, + INSERTKEY, + HOMEKEY, + PAGEUPKEY, + PAGEDOWNKEY, + ENDKEY, + + BEGINMOUSE, + + BEGINMOUSEBUTTONS, + + LEFTMOUSE, + MIDDLEMOUSE, + RIGHTMOUSE, + + ENDMOUSEBUTTONS, + + WHEELUPMOUSE, + WHEELDOWNMOUSE, + + MOUSEX, + MOUSEY, + + ENDMOUSE, + + MAX_KEYS }; // enum protected: - /** - * m_eventStatusTables are two tables that contain current and previous - * status of all events - */ + /// Table of all possible input. + SCA_InputEvent m_inputsTable[SCA_IInputDevice::MAX_KEYS]; + /// Typed text in unicode during a frame. + std::wstring m_text; - SCA_InputEvent m_eventStatusTables[2][SCA_IInputDevice::KX_MAX_KEYS]; - /** - * m_currentTable is index for m_keyStatusTable that toggle between 0 or 1 + /// True when a sensor handle the same key as the exit key. + bool m_hookExitKey; + + /** Translation table used to get the character from a key number with shift or not. + * Key -> (Character, Character shifted) */ - int m_currentTable; - void ClearStatusTable(int tableid); + static std::map > m_keyToChar; public: - virtual bool IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode)=0; - virtual const SCA_InputEvent& GetEventValue(SCA_IInputDevice::KX_EnumInputs inputcode); + virtual SCA_InputEvent& GetInput(SCA_IInputDevice::SCA_EnumInputs inputcode); - /** - * Count active events(active and just_activated) - */ - virtual int GetNumActiveEvents(); + void SetHookExitKey(bool hook); + bool GetHookExitKey() const; - /** - * Get the number of remapping events (just_activated, just_released) + /** Clear inputs: + * - Clear status and copy last status to first status. + * - Clear queue + * - Clear values and copy last value to first value. */ - virtual int GetNumJustEvents(); - - virtual void HookEscape(); - - /** - * Next frame: we calculate the new key states. This goes as follows: - * - * KX_NO_INPUTSTATUS -> KX_NO_INPUTSTATUS - * KX_JUSTACTIVATED -> KX_ACTIVE - * KX_ACTIVE -> KX_ACTIVE - * KX_JUSTRELEASED -> KX_NO_INPUTSTATUS - * - * Getting new events provides the - * KX_NO_INPUTSTATUS->KX_JUSTACTIVATED and - * KX_ACTIVE->KX_JUSTRELEASED transitions. + virtual void ClearInputs(); + + /** Manage move event like mouse by releasing if possible. + * These kind of events are precise of one frame. */ - virtual void NextFrame(); + virtual void ReleaseMoveEvent(); + /// Return typed unicode text during a frame. + const std::wstring& GetText() const; -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:SCA_InputEvent") -#endif + static const char ConvertKeyToChar(SCA_EnumInputs input, bool shifted); }; #endif /* __SCA_IINPUTDEVICE_H__ */ + diff --git a/source/gameengine/GameLogic/SCA_ILogicBrick.cpp b/source/gameengine/GameLogic/SCA_ILogicBrick.cpp index d388317ce6a6..20b6c3de5e4a 100644 --- a/source/gameengine/GameLogic/SCA_ILogicBrick.cpp +++ b/source/gameengine/GameLogic/SCA_ILogicBrick.cpp @@ -35,17 +35,16 @@ #include "SCA_ILogicBrick.h" #include "EXP_PyObjectPlus.h" -SCA_ILogicBrick::SCA_ILogicBrick(SCA_IObject* gameobj) +SCA_ILogicBrick::SCA_ILogicBrick(SCA_IObject *gameobj) : - CValue(), + EXP_Value(), m_gameobj(gameobj), - m_logicManager(NULL), + m_logicManager(nullptr), m_Execute_Priority(0), m_Execute_Ueber_Priority(0), m_bActive(false), m_eventval(0) { - m_text = "KX_LogicBrick"; } @@ -71,77 +70,26 @@ void SCA_ILogicBrick::SetUeberExecutePriority(int execute_Priority) -void SCA_ILogicBrick::ReParent(SCA_IObject* parent) +void SCA_ILogicBrick::ReParent(SCA_IObject *parent) { m_gameobj = parent; } -void SCA_ILogicBrick::Relink(CTR_Map *obj_map) +void SCA_ILogicBrick::Relink(std::map& obj_map) { // nothing to do } -CValue* SCA_ILogicBrick::Calc(VALUE_OPERATOR op, CValue *val) -{ - CValue* temp = new CBoolValue(false,""); - CValue* result = temp->Calc(op,val); - temp->Release(); - - return result; -} - - - -CValue* SCA_ILogicBrick::CalcFinal(VALUE_DATA_TYPE dtype, - VALUE_OPERATOR op, - CValue *val) -{ - // same as bool implementation, so... - CValue* temp = new CBoolValue(false,""); - CValue* result = temp->CalcFinal(dtype,op,val); - temp->Release(); - - return result; -} - - - -const STR_String& SCA_ILogicBrick::GetText() -{ - if (m_name.Length()) - return m_name; - - return m_text; -} - - - -double SCA_ILogicBrick::GetNumber() -{ - return -1; -} - - - -STR_String& SCA_ILogicBrick::GetName() +std::string SCA_ILogicBrick::GetName() { return m_name; } - - -void SCA_ILogicBrick::SetName(const char *name) +void SCA_ILogicBrick::SetName(const std::string& name) { m_name = name; } -bool SCA_ILogicBrick::LessComparedTo(SCA_ILogicBrick* other) -{ - return (this->m_Execute_Ueber_Priority < other->m_Execute_Ueber_Priority) - || ((this->m_Execute_Ueber_Priority == other->m_Execute_Ueber_Priority) && - (this->m_Execute_Priority < other->m_Execute_Priority)); -} - void SCA_ILogicBrick::SetLogicManager(SCA_LogicManager *logicmgr) { m_logicManager = logicmgr; @@ -152,46 +100,22 @@ SCA_LogicManager *SCA_ILogicBrick::GetLogicManager() return m_logicManager; } -void SCA_ILogicBrick::RegisterEvent(CValue* eventval) -{ - if (m_eventval) - m_eventval->Release(); - - m_eventval = eventval->AddRef(); -} - - void SCA_ILogicBrick::RemoveEvent() { - if (m_eventval) - { + if (m_eventval) { m_eventval->Release(); - m_eventval = NULL; - } -} - - - -CValue* SCA_ILogicBrick::GetEvent() -{ - if (m_eventval) - { - return m_eventval->AddRef(); + m_eventval = nullptr; } - - return NULL; } - - #ifdef WITH_PYTHON /* python stuff */ PyTypeObject SCA_ILogicBrick::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_ILogicBrick", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -199,37 +123,36 @@ PyTypeObject SCA_ILogicBrick::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, - &CValue::Type, - 0,0,0,0,0,0, + &EXP_Value::Type, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_ILogicBrick::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef SCA_ILogicBrick::Attributes[] = { - KX_PYATTRIBUTE_RO_FUNCTION("owner", SCA_ILogicBrick, pyattr_get_owner), - KX_PYATTRIBUTE_INT_RW("executePriority",0,100000,false,SCA_ILogicBrick,m_Execute_Priority), - KX_PYATTRIBUTE_STRING_RO("name", SCA_ILogicBrick, m_name), - {NULL} //Sentinel + EXP_PYATTRIBUTE_RO_FUNCTION("owner", SCA_ILogicBrick, pyattr_get_owner), + EXP_PYATTRIBUTE_INT_RW("executePriority", 0, 100000, false, SCA_ILogicBrick, m_Execute_Priority), + EXP_PYATTRIBUTE_NULL //Sentinel }; -int SCA_ILogicBrick::CheckProperty(void *self, const PyAttributeDef *attrdef) +int SCA_ILogicBrick::CheckProperty(EXP_PyObjectPlus *self, const PyAttributeDef *attrdef) { - if (attrdef->m_type != KX_PYATTRIBUTE_TYPE_STRING || attrdef->m_length != 1) { + if (attrdef->m_type != EXP_PYATTRIBUTE_TYPE_STRING || attrdef->m_length != 1) { PyErr_SetString(PyExc_AttributeError, "inconsistent check function for attribute type, report to blender.org"); return 1; } - SCA_ILogicBrick* brick = reinterpret_cast(self); - STR_String* var = reinterpret_cast((char*)self+attrdef->m_offset); - CValue* prop = brick->GetParent()->FindIdentifier(*var); + SCA_ILogicBrick *brick = reinterpret_cast(self); + std::string *var = reinterpret_cast((char *)self + attrdef->m_offset); + EXP_Value *prop = brick->GetParent()->FindIdentifier(*var); bool error = prop->IsError(); prop->Release(); if (error) { @@ -240,32 +163,16 @@ int SCA_ILogicBrick::CheckProperty(void *self, const PyAttributeDef *attrdef) } /*Attribute functions */ -PyObject *SCA_ILogicBrick::pyattr_get_owner(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_ILogicBrick::pyattr_get_owner(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_ILogicBrick* self = static_cast(self_v); - CValue* parent = self->GetParent(); + SCA_ILogicBrick *self = static_cast(self_v); + EXP_Value *parent = self->GetParent(); - if (parent) + if (parent) { return parent->GetProxy(); - - Py_RETURN_NONE; -} - - - -/* Conversions for making life better. */ -bool SCA_ILogicBrick::PyArgToBool(int boolArg) -{ - if (boolArg) { - return true; - } else { - return false; } -} -PyObject *SCA_ILogicBrick::BoolToPyArg(bool boolarg) -{ - return PyLong_FromLong(boolarg ? KX_TRUE: KX_FALSE); + Py_RETURN_NONE; } #endif // WITH_PYTHON diff --git a/source/gameengine/GameLogic/SCA_ILogicBrick.h b/source/gameengine/GameLogic/SCA_ILogicBrick.h index 46c62f0258ac..70cd85fe9e82 100644 --- a/source/gameengine/GameLogic/SCA_ILogicBrick.h +++ b/source/gameengine/GameLogic/SCA_ILogicBrick.h @@ -35,14 +35,12 @@ #include "EXP_Value.h" #include "SCA_IObject.h" #include "EXP_BoolValue.h" -#include "CTR_Map.h" -#include "CTR_HashedPtr.h" -class NG_NetworkScene; +class KX_NetworkMessageScene; class SCA_IScene; class SCA_LogicManager; -class SCA_ILogicBrick : public CValue +class SCA_ILogicBrick : public EXP_Value, public SG_QList { Py_Header protected: @@ -52,13 +50,10 @@ class SCA_ILogicBrick : public CValue int m_Execute_Ueber_Priority; bool m_bActive; - CValue* m_eventval; - STR_String m_text; - STR_String m_name; + EXP_Value* m_eventval; + std::string m_name; //unsigned long m_drawcolor; - void RegisterEvent(CValue* eventval); void RemoveEvent(); - CValue* GetEvent(); public: SCA_ILogicBrick(SCA_IObject* gameobj); @@ -70,18 +65,12 @@ class SCA_ILogicBrick : public CValue SCA_IObject* GetParent() { return m_gameobj; } virtual void ReParent(SCA_IObject* parent); - virtual void Relink(CTR_Map *obj_map); + virtual void Relink(std::map& obj_map); virtual void Delete() { Release(); } - // act as a BoolValue (with value IsPositiveTrigger) - virtual CValue* Calc(VALUE_OPERATOR op, CValue *val); - virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); - - virtual const STR_String & GetText(); - virtual double GetNumber(); - virtual STR_String& GetName(); - virtual void SetName(const char *); - + virtual std::string GetName(); + virtual void SetName(const std::string& name); + bool IsActive() { return m_bActive; @@ -101,10 +90,10 @@ class SCA_ILogicBrick : public CValue } // insert in a QList at position corresponding to m_Execute_Priority - // inside a longer list that contains elements of other objects. + // inside a longer list that contains elements of other objects. // Sorting is done only between the elements of the same object. // head is the head of the combined list - // current points to the first element of the object in the list, NULL if none yet + // current points to the first element of the object in the list, nullptr if none yet void InsertSelfActiveQList(SG_QList& head, SG_QList** current) { if (!*current) @@ -127,22 +116,20 @@ class SCA_ILogicBrick : public CValue it.add_back(this); } - virtual bool LessComparedTo(SCA_ILogicBrick* other); - virtual void SetLogicManager(SCA_LogicManager *logicmgr); SCA_LogicManager *GetLogicManager(); /* for moving logic bricks between scenes */ virtual void Replace_IScene(SCA_IScene *val) {} - virtual void Replace_NetworkScene(NG_NetworkScene *val) {} + virtual void Replace_NetworkScene(KX_NetworkMessageScene *val) {} #ifdef WITH_PYTHON // python methods - - static PyObject* pyattr_get_owner(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + + static PyObject* pyattr_get_owner(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); // check that attribute is a property - static int CheckProperty(void *self, const PyAttributeDef *attrdef); + static int CheckProperty(EXP_PyObjectPlus *self, const PyAttributeDef *attrdef); enum KX_BOOL_TYPE { KX_BOOL_NODEF = 0, @@ -150,16 +137,6 @@ class SCA_ILogicBrick : public CValue KX_FALSE, KX_BOOL_MAX }; - - -protected: - /* Some conversions to go with the bool type. */ - /** Convert a KX_TRUE, KX_FALSE in Python to a c++ value. */ - bool PyArgToBool(int boolArg); - - /** Convert a a c++ value to KX_TRUE, KX_FALSE in Python. */ - PyObject *BoolToPyArg(bool); - #endif /* WITH_PYTHON */ }; diff --git a/source/gameengine/GameLogic/SCA_IObject.cpp b/source/gameengine/GameLogic/SCA_IObject.cpp index c5eab53d67e3..986c1c7be606 100644 --- a/source/gameengine/GameLogic/SCA_IObject.cpp +++ b/source/gameengine/GameLogic/SCA_IObject.cpp @@ -36,277 +36,281 @@ #include "SCA_ISensor.h" #include "SCA_IController.h" #include "SCA_IActuator.h" -#include "MT_Point3.h" #include "EXP_ListValue.h" -MT_Point3 SCA_IObject::m_sDummy=MT_Point3(0,0,0); +#include "CM_List.h" + SG_QList SCA_IObject::m_activeBookmarkedControllers; -SCA_IObject::SCA_IObject(): - CValue(), +SCA_IObject::SCA_IObject() + :m_suspended(false), m_initState(0), m_state(0), - m_firstState(NULL) + m_firstState(nullptr) +{ +} + +SCA_IObject::SCA_IObject(const SCA_IObject& other) + :EXP_Value(other), + m_sensors(other.m_sensors), + m_controllers(other.m_controllers), + m_actuators(other.m_actuators), + m_suspended(other.m_suspended), + m_initState(other.m_initState), + m_state(0), + m_firstState(other.m_firstState) { - m_suspended = false; + /* Registered objects and actuator are intentionally left empty. + * A new object cannot be client of any actuator. */ } SCA_IObject::~SCA_IObject() { - SCA_SensorList::iterator its; - for (its = m_sensors.begin(); !(its == m_sensors.end()); ++its) - { - //Use Delete for sensor to ensure proper cleaning - (*its)->Delete(); - //((CValue*)(*its))->Release(); + for (SCA_ISensor *sensor : m_sensors) { + // Use Delete for sensor to ensure proper cleaning. + sensor->Delete(); } - SCA_ControllerList::iterator itc; - for (itc = m_controllers.begin(); !(itc == m_controllers.end()); ++itc) - { - //Use Delete for controller to ensure proper cleaning (expression controller) - (*itc)->Delete(); - //((CValue*)(*itc))->Release(); + for (SCA_IController *controller : m_controllers) { + // Use Delete for controller to ensure proper cleaning (expression controller). + controller->Delete(); } - SCA_ActuatorList::iterator ita; - for (ita = m_registeredActuators.begin(); !(ita==m_registeredActuators.end()); ++ita) - { - (*ita)->UnlinkObject(this); + for (SCA_IActuator *actuator : m_registeredActuators) { + actuator->UnlinkObject(this); } - for (ita = m_actuators.begin(); !(ita==m_actuators.end()); ++ita) - { - (*ita)->Delete(); + for (SCA_IActuator *actuator : m_actuators) { + actuator->Delete(); } - SCA_ObjectList::iterator ito; - for (ito = m_registeredObjects.begin(); !(ito==m_registeredObjects.end()); ++ito) - { - (*ito)->UnlinkObject(this); + for (SCA_IObject *object : m_registeredObjects) { + object->UnlinkObject(this); } +} + +SCA_ControllerList& SCA_IObject::GetControllers() +{ + return m_controllers; +} +SCA_SensorList& SCA_IObject::GetSensors() +{ + return m_sensors; +} +SCA_ActuatorList& SCA_IObject::GetActuators() +{ + return m_actuators; +} +SG_QList& SCA_IObject::GetActiveActuators() +{ + return m_activeActuators; +} + +SG_QList& SCA_IObject::GetActiveControllers() +{ + return m_activeControllers; +} - //T_InterpolatorList::iterator i; - //for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) { - // delete *i; - //} +SG_QList& SCA_IObject::GetActiveBookmarkedControllers() +{ + return m_activeBookmarkedControllers; } -void SCA_IObject::AddSensor(SCA_ISensor* act) +void SCA_IObject::AddSensor(SCA_ISensor *act) { act->AddRef(); m_sensors.push_back(act); } +void SCA_IObject::ReserveSensor(int num) +{ + m_sensors.reserve(num); +} - -void SCA_IObject::AddController(SCA_IController* act) +void SCA_IObject::AddController(SCA_IController *act) { act->AddRef(); m_controllers.push_back(act); } +void SCA_IObject::ReserveController(int num) +{ + m_controllers.reserve(num); +} - -void SCA_IObject::AddActuator(SCA_IActuator* act) +void SCA_IObject::AddActuator(SCA_IActuator *act) { act->AddRef(); m_actuators.push_back(act); } -void SCA_IObject::RegisterActuator(SCA_IActuator* act) +void SCA_IObject::ReserveActuator(int num) { - // don't increase ref count, it would create dead lock + m_actuators.reserve(num); +} + +void SCA_IObject::RegisterActuator(SCA_IActuator *act) +{ + // Don't increase ref count, it would create dead lock. m_registeredActuators.push_back(act); } -void SCA_IObject::UnregisterActuator(SCA_IActuator* act) +void SCA_IObject::UnregisterActuator(SCA_IActuator *act) { - SCA_ActuatorList::iterator ita; - for (ita = m_registeredActuators.begin(); ita != m_registeredActuators.end(); ++ita) - { - if ((*ita) == act) { - (*ita) = m_registeredActuators.back(); - m_registeredActuators.pop_back(); - break; - } - } + CM_ListRemoveIfFound(m_registeredActuators, act); } -void SCA_IObject::RegisterObject(SCA_IObject* obj) +void SCA_IObject::RegisterObject(SCA_IObject *obj) { - // one object may be registered multiple times via constraint target - // store multiple reference, this will serve as registration counter + /* One object may be registered multiple times via constraint target + * store multiple reference, this will serve as registration counter. */ m_registeredObjects.push_back(obj); } -void SCA_IObject::UnregisterObject(SCA_IObject* obj) +void SCA_IObject::UnregisterObject(SCA_IObject *obj) { - SCA_ObjectList::iterator ito; - for (ito = m_registeredObjects.begin(); ito != m_registeredObjects.end(); ++ito) - { - if ((*ito) == obj) { - (*ito) = m_registeredObjects.back(); - m_registeredObjects.pop_back(); - break; - } - } + CM_ListRemoveIfFound(m_registeredObjects, obj); +} + +bool SCA_IObject::UnlinkObject(SCA_IObject *clientobj) +{ + return false; } void SCA_IObject::ReParentLogic() { - SCA_ActuatorList& oldactuators = GetActuators(); - int act = 0; - SCA_ActuatorList::iterator ita; - for (ita = oldactuators.begin(); !(ita==oldactuators.end()); ++ita) - { - SCA_IActuator* newactuator = (SCA_IActuator*) (*ita)->GetReplica(); + SCA_ActuatorList& oldactuators = GetActuators(); + for (unsigned short i = 0, size = oldactuators.size(); i < size; ++i) { + SCA_IActuator *newactuator = static_cast(oldactuators[i]->GetReplica()); newactuator->ReParent(this); - // actuators are initially not connected to any controller + // Actuators are initially not connected to any controller. newactuator->SetActive(false); newactuator->ClrLink(); - oldactuators[act++] = newactuator; + oldactuators[i] = newactuator; } SCA_ControllerList& oldcontrollers = GetControllers(); - int con = 0; - SCA_ControllerList::iterator itc; - for (itc = oldcontrollers.begin(); !(itc==oldcontrollers.end()); ++itc) - { - SCA_IController* newcontroller = (SCA_IController*)(*itc)->GetReplica(); + for (unsigned short i = 0, size = oldcontrollers.size(); i < size; ++i) { + SCA_IController *newcontroller = static_cast(oldcontrollers[i]->GetReplica()); newcontroller->ReParent(this); newcontroller->SetActive(false); - oldcontrollers[con++]=newcontroller; - + oldcontrollers[i] = newcontroller; } - // convert sensors last so that actuators are already available for Actuator sensor + // Convert sensors last so that actuators are already available for Actuator sensor. SCA_SensorList& oldsensors = GetSensors(); - int sen = 0; - SCA_SensorList::iterator its; - for (its = oldsensors.begin(); !(its==oldsensors.end()); ++its) - { - SCA_ISensor* newsensor = (SCA_ISensor*)(*its)->GetReplica(); + for (unsigned short i = 0, size = oldsensors.size(); i < size; ++i) { + SCA_ISensor *newsensor = static_cast(oldsensors[i]->GetReplica()); newsensor->ReParent(this); newsensor->SetActive(false); // sensors are initially not connected to any controller newsensor->ClrLink(); - oldsensors[sen++] = newsensor; + oldsensors[i] = newsensor; } - - // a new object cannot be client of any actuator - m_registeredActuators.clear(); - m_registeredObjects.clear(); } - - -SCA_ISensor* SCA_IObject::FindSensor(const STR_String& sensorname) +SCA_ISensor *SCA_IObject::FindSensor(const std::string& sensorname) { - SCA_ISensor* foundsensor = NULL; - - for (SCA_SensorList::iterator its = m_sensors.begin();!(its==m_sensors.end());++its) - { - if ((*its)->GetName() == sensorname) - { - foundsensor = (*its); - break; + for (SCA_ISensor *sensor : m_sensors) { + if (sensor->GetName() == sensorname) { + return sensor; } } - return foundsensor; + return nullptr; } - - -SCA_IController* SCA_IObject::FindController(const STR_String& controllername) +SCA_IController *SCA_IObject::FindController(const std::string& controllername) { - SCA_IController* foundcontroller = NULL; - - for (SCA_ControllerList::iterator itc = m_controllers.begin();!(itc==m_controllers.end());++itc) - { - if ((*itc)->GetName() == controllername) - { - foundcontroller = (*itc); - break; + for (SCA_IController *controller : m_controllers) { + if (controller->GetName() == controllername) { + return controller; } } - return foundcontroller; + return nullptr; } - - -SCA_IActuator* SCA_IObject::FindActuator(const STR_String& actuatorname) +SCA_IActuator *SCA_IObject::FindActuator(const std::string& actuatorname) { - SCA_IActuator* foundactuator = NULL; - - for (SCA_ActuatorList::iterator ita = m_actuators.begin();!(ita==m_actuators.end());++ita) - { - if ((*ita)->GetName() == actuatorname) - { - foundactuator = (*ita); - break; + for (SCA_IActuator *actuator : m_actuators) { + if (actuator->GetName() == actuatorname) { + return actuator; } } - - return foundactuator; + return nullptr; } - -void SCA_IObject::Suspend() +void SCA_IObject::SuspendLogic() { - if ((!m_ignore_activity_culling) - && (!m_suspended)) { + if (!m_suspended) { m_suspended = true; /* flag suspend for all sensors */ - SCA_SensorList::iterator i = m_sensors.begin(); - while (i != m_sensors.end()) { - (*i)->Suspend(); - ++i; + for (SCA_ISensor *sensor : m_sensors) { + sensor->Suspend(); } } } - - -void SCA_IObject::Resume(void) +void SCA_IObject::ResumeLogic() { if (m_suspended) { m_suspended = false; /* unflag suspend for all sensors */ - SCA_SensorList::iterator i = m_sensors.begin(); - while (i != m_sensors.end()) { - (*i)->Resume(); - ++i; + for (SCA_ISensor *sensor : m_sensors) { + sensor->Resume(); } } } +void SCA_IObject::SetInitState(unsigned int initState) +{ + m_initState = initState; +} + +void SCA_IObject::ResetState() +{ + SetState(m_initState); +} + void SCA_IObject::SetState(unsigned int state) { - unsigned int tmpstate; - SCA_ControllerList::iterator contit; - - // we will update the state in two steps: - // 1) set the new state bits that are 1 - // 2) clr the new state bits that are 0 - // This to ensure continuity if a sensor is attached to two states - // that are switching state: no need to deactive and reactive the sensor - - tmpstate = m_state | state; - if (tmpstate != m_state) - { - // update the status of the controllers - for (contit = m_controllers.begin(); contit != m_controllers.end(); ++contit) - { - (*contit)->ApplyState(tmpstate); + /* We will update the state in two steps: + * 1) set the new state bits that are 1 + * 2) clr the new state bits that are 0 + * This to ensure continuity if a sensor is attached to two states + * that are switching state: no need to deactive and reactive the sensor + */ + + const unsigned int tmpstate = m_state | state; + if (tmpstate != m_state) { + // Update the status of the controllers. + for (SCA_IController *controller : m_controllers) { + controller->ApplyState(tmpstate); } } m_state = state; - if (m_state != tmpstate) - { - for (contit = m_controllers.begin(); contit != m_controllers.end(); ++contit) - { - (*contit)->ApplyState(m_state); + if (m_state != tmpstate) { + for (SCA_IController *controller : m_controllers) { + controller->ApplyState(m_state); } } } +unsigned int SCA_IObject::GetState() +{ + return m_state; +} + +SG_QList **SCA_IObject::GetFirstState() +{ + return &m_firstState; +} + +void SCA_IObject::SetFirstState(SG_QList *firstState) +{ + m_firstState = firstState; +} + +int SCA_IObject::GetGameObjectType() const +{ + return -1; +} + #ifdef WITH_PYTHON /* ------------------------------------------------------------------------- */ @@ -315,9 +319,9 @@ void SCA_IObject::SetState(unsigned int state) /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_IObject::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_IObject", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -325,25 +329,23 @@ PyTypeObject SCA_IObject::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, - &CValue::Type, - 0,0,0,0,0,0, + &EXP_Value::Type, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_IObject::Methods[] = { - //{"setOrientation", (PyCFunction) SCA_IObject::sPySetOrientation, METH_VARARGS}, - //{"getOrientation", (PyCFunction) SCA_IObject::sPyGetOrientation, METH_VARARGS}, - {NULL,NULL} //Sentinel + {nullptr, nullptr} // Sentinel }; PyAttributeDef SCA_IObject::Attributes[] = { - { NULL } //Sentinel + EXP_PYATTRIBUTE_NULL // Sentinel }; #endif // WITH_PYTHON diff --git a/source/gameengine/GameLogic/SCA_IObject.h b/source/gameengine/GameLogic/SCA_IObject.h index 5c2dd351fb33..636ef3e4a6f5 100644 --- a/source/gameengine/GameLogic/SCA_IObject.h +++ b/source/gameengine/GameLogic/SCA_IObject.h @@ -35,6 +35,8 @@ #define __SCA_IOBJECT_H__ #include "EXP_Value.h" + +#include "SG_QList.h" #include class SCA_IObject; @@ -42,188 +44,123 @@ class SCA_ISensor; class SCA_IController; class SCA_IActuator; -#ifdef WITH_PYTHON -template T PyVecTo(PyObject *); -#endif - -typedef std::vector SCA_SensorList; -typedef std::vector SCA_ControllerList; -typedef std::vector SCA_ActuatorList; -typedef std::vector SCA_ObjectList; +typedef std::vector SCA_SensorList; +typedef std::vector SCA_ControllerList; +typedef std::vector SCA_ActuatorList; +typedef std::vector SCA_ObjectList; -class SCA_IObject : public CValue +class SCA_IObject : public EXP_Value { - Py_Header protected: - friend class KX_StateActuator; - friend class SCA_IActuator; - friend class SCA_IController; - SCA_SensorList m_sensors; - SCA_ControllerList m_controllers; - SCA_ActuatorList m_actuators; - SCA_ActuatorList m_registeredActuators; // actuators that use a pointer to this object - SCA_ObjectList m_registeredObjects; // objects that hold reference to this object - - // SG_Dlist: element of objects with active actuators - // Head: SCA_LogicManager::m_activeActuators - // SG_QList: Head of active actuators list on this object - // Elements: SCA_IActuator - SG_QList m_activeActuators; - // SG_Dlist: element of list os lists with active controllers - // Head: SCA_LogicManager::m_activeControllers - // SG_QList: Head of active controller list on this object - // Elements: SCA_IController - SG_QList m_activeControllers; - // SG_Dlist: element of list of lists of active controllers - // Head: SCA_LogicManager::m_activeControllers - // SG_QList: Head of active bookmarked controller list globally - // Elements: SCA_IController with bookmark option - static SG_QList m_activeBookmarkedControllers; - - static class MT_Point3 m_sDummy; + SCA_SensorList m_sensors; + SCA_ControllerList m_controllers; + SCA_ActuatorList m_actuators; + /// Actuators that use a pointer to this object. + SCA_ActuatorList m_registeredActuators; + /// Objects that hold reference to this object. + SCA_ObjectList m_registeredObjects; + + /** SG_Dlist: element of objects with active actuators + * Head: SCA_LogicManager::m_activeActuators + * SG_QList: Head of active actuators list on this object + * Elements: SCA_IActuator + */ + SG_QList m_activeActuators; - /** - * Ignore activity culling requests? + /** SG_Dlist: element of list os lists with active controllers + * Head: SCA_LogicManager::m_activeControllers + * SG_QList: Head of active controller list on this object + * Elements: SCA_IController */ - bool m_ignore_activity_culling; + SG_QList m_activeControllers; - /** - * Ignore updates? + /** SG_Dlist: element of list of lists of active controllers + * Head: SCA_LogicManager::m_activeControllers + * SG_QList: Head of active bookmarked controller list globally + * Elements: SCA_IController with bookmark option */ + static SG_QList m_activeBookmarkedControllers; + + /// Ignore updates? bool m_suspended; - /** - * init state of object (used when object is created) - */ - unsigned int m_initState; + /// Init state of object (used when object is created). + unsigned int m_initState; - /** - * current state = bit mask of state that are active - */ - unsigned int m_state; + /// Current state = bit mask of state that are active. + unsigned int m_state; - /** - * pointer inside state actuator list for sorting - */ - SG_QList* m_firstState; + /// Pointer inside state actuator list for sorting. + SG_QList *m_firstState; public: - SCA_IObject(); + SCA_IObject(const SCA_IObject& other); virtual ~SCA_IObject(); - SCA_ControllerList& GetControllers() - { - return m_controllers; - } - SCA_SensorList& GetSensors() - { - return m_sensors; - } - SCA_ActuatorList& GetActuators() - { - return m_actuators; - } - SG_QList& GetActiveActuators() - { - return m_activeActuators; - } - - void AddSensor(SCA_ISensor* act); - void ReserveSensor(int num) - { - m_sensors.reserve(num); - } - void AddController(SCA_IController* act); - void ReserveController(int num) - { - m_controllers.reserve(num); - } - void AddActuator(SCA_IActuator* act); - void ReserveActuator(int num) - { - m_actuators.reserve(num); - } - void RegisterActuator(SCA_IActuator* act); - void UnregisterActuator(SCA_IActuator* act); - - void RegisterObject(SCA_IObject* objs); - void UnregisterObject(SCA_IObject* objs); + SCA_ControllerList& GetControllers(); + SCA_SensorList& GetSensors(); + SCA_ActuatorList& GetActuators(); + SG_QList& GetActiveActuators(); + SG_QList& GetActiveControllers(); + static SG_QList& GetActiveBookmarkedControllers(); + + void AddSensor(SCA_ISensor *act); + void ReserveSensor(int num); + void AddController(SCA_IController *act); + void ReserveController(int num); + void AddActuator(SCA_IActuator *act); + void ReserveActuator(int num); + void RegisterActuator(SCA_IActuator *act); + void UnregisterActuator(SCA_IActuator *act); + + void RegisterObject(SCA_IObject *objs); + void UnregisterObject(SCA_IObject *objs); /** * UnlinkObject(...) * this object is informed that one of the object to which it holds a reference is deleted * returns true if there was indeed a reference. */ - virtual bool UnlinkObject(SCA_IObject* clientobj) { return false; } - - SCA_ISensor* FindSensor(const STR_String& sensorname); - SCA_IActuator* FindActuator(const STR_String& actuatorname); - SCA_IController* FindController(const STR_String& controllername); + virtual bool UnlinkObject(SCA_IObject *clientobj); - void SetCurrentTime(float currentTime) {} + SCA_ISensor *FindSensor(const std::string& sensorname); + SCA_IActuator *FindActuator(const std::string& actuatorname); + SCA_IController *FindController(const std::string& controllername); virtual void ReParentLogic(); - /** - * Set whether or not to ignore activity culling requests - */ - void SetIgnoreActivityCulling(bool b) - { - m_ignore_activity_culling = b; - } - - /** - * Set whether or not this object wants to ignore activity culling - * requests - */ - bool GetIgnoreActivityCulling() - { - return m_ignore_activity_culling; - } + /// Suspend all progress. + void SuspendLogic(); - /** - * Suspend all progress. - */ - void Suspend(void); + /// Resume progress. + void ResumeLogic(); - /** - * Resume progress - */ - void Resume(void); + /// Set init state. + void SetInitState(unsigned int initState); - /** - * Set init state - */ - void SetInitState(unsigned int initState) { m_initState = initState; } + /// Initialize the state when object is created. + void ResetState(); - /** - * initialize the state when object is created - */ - void ResetState(void) { SetState(m_initState); } - - /** - * Set the object state - */ + /// Set the object state. void SetState(unsigned int state); - /** - * Get the object state - */ - unsigned int GetState(void) { return m_state; } + /// Get the object state. + unsigned int GetState(); -// const class MT_Point3& ConvertPythonPylist(PyObject *pylist); + SG_QList **GetFirstState(); + void SetFirstState(SG_QList *firstState); - virtual int GetGameObjectType() {return -1;} + virtual int GetGameObjectType() const; typedef enum ObjectTypes { - OBJ_ARMATURE=0, - OBJ_CAMERA=1, - OBJ_LIGHT=2, - OBJ_TEXT=3 + OBJ_ARMATURE = 0, + OBJ_CAMERA = 1, + OBJ_LIGHT = 2, + OBJ_TEXT = 3, + OBJ_NAVMESH = 4 } ObjectTypes; - }; -#endif /* __SCA_IOBJECT_H__ */ +#endif // __SCA_IOBJECT_H__ diff --git a/source/gameengine/GameLogic/SCA_IScene.cpp b/source/gameengine/GameLogic/SCA_IScene.cpp index a1ead43a8740..5468672b3983 100644 --- a/source/gameengine/GameLogic/SCA_IScene.cpp +++ b/source/gameengine/GameLogic/SCA_IScene.cpp @@ -29,18 +29,19 @@ * \ingroup gamelogic */ - #include "SCA_IScene.h" -#include "EXP_Value.h" +#include "SCA_IObject.h" + +#define DEBUG_MAX_DISPLAY 100 -SCA_DebugProp::SCA_DebugProp(): m_obj(NULL) +SCA_DebugProp::SCA_DebugProp(SCA_IObject *gameobj, const std::string& name) + :m_obj(gameobj), + m_name(name) { } SCA_DebugProp::~SCA_DebugProp() { - if (m_obj) - m_obj->Release(); } SCA_IScene::SCA_IScene() @@ -49,96 +50,72 @@ SCA_IScene::SCA_IScene() void SCA_IScene::RemoveAllDebugProperties() { - for (std::vector::iterator it = m_debugList.begin(); - !(it==m_debugList.end());++it) - { - delete (*it); - } m_debugList.clear(); } - SCA_IScene::~SCA_IScene() { RemoveAllDebugProperties(); } - -std::vector& SCA_IScene::GetDebugProperties() +const std::vector& SCA_IScene::GetDebugProperties() const { return m_debugList; } - -bool SCA_IScene::PropertyInDebugList( class CValue *gameobj, const STR_String &name ) +bool SCA_IScene::PropertyInDebugList(SCA_IObject *gameobj, const std::string &name) { - for (std::vector::iterator it = m_debugList.begin(); - !(it==m_debugList.end());++it) { - STR_String debugname = (*it)->m_name; - CValue *debugobj = (*it)->m_obj; - - if (debugobj == gameobj && debugname == name) + for (const SCA_DebugProp& prop : m_debugList) { + if (prop.m_obj == gameobj && prop.m_name == name) { return true; + } } return false; } - -bool SCA_IScene::ObjectInDebugList( class CValue *gameobj ) +bool SCA_IScene::ObjectInDebugList(SCA_IObject *gameobj) { - for (std::vector::iterator it = m_debugList.begin(); - !(it==m_debugList.end());++it) { - CValue* debugobj = (*it)->m_obj; - - if (debugobj == gameobj) + for (const SCA_DebugProp& prop : m_debugList) { + if (prop.m_obj == gameobj) { return true; + } } return false; } - -void SCA_IScene::AddDebugProperty(class CValue* debugprop, - const STR_String &name) +void SCA_IScene::AddDebugProperty(SCA_IObject *gameobj, const std::string &name) { if (m_debugList.size() < DEBUG_MAX_DISPLAY) { - SCA_DebugProp* dprop = new SCA_DebugProp(); - dprop->m_obj = debugprop; - debugprop->AddRef(); - dprop->m_name = name; - m_debugList.push_back(dprop); + m_debugList.emplace_back(gameobj, name); } } - -void SCA_IScene::RemoveDebugProperty(class CValue *gameobj, - const STR_String &name) +void SCA_IScene::RemoveDebugProperty(SCA_IObject *gameobj, const std::string &name) { - vector::iterator it = m_debugList.begin(); - while (it != m_debugList.end()) { - STR_String debugname = (*it)->m_name; - CValue *debugobj = (*it)->m_obj; - - if (debugobj == gameobj && debugname == name) { - delete (*it); - m_debugList.erase(it); + for (std::vector::iterator it = m_debugList.begin(); it != m_debugList.end(); ) { + const SCA_DebugProp& prop = *it; + + if (prop.m_obj == gameobj && prop.m_name == name) { + it = m_debugList.erase(it); break; } - ++it; + else { + ++it; + } } } - -void SCA_IScene::RemoveObjectDebugProperties(class CValue* gameobj) +void SCA_IScene::RemoveObjectDebugProperties(SCA_IObject *gameobj) { - vector::iterator it = m_debugList.begin(); - while (it != m_debugList.end()) { - CValue* debugobj = (*it)->m_obj; + for (std::vector::iterator it = m_debugList.begin(); it != m_debugList.end(); ) { + const SCA_DebugProp& prop = *it; - if (debugobj == gameobj) { - delete (*it); - m_debugList.erase(it); + if (prop.m_obj == gameobj) { + it = m_debugList.erase(it); continue; } - ++it; + else { + ++it; + } } } diff --git a/source/gameengine/GameLogic/SCA_IScene.h b/source/gameengine/GameLogic/SCA_IScene.h index e08c68f63e4f..809ba1a78b55 100644 --- a/source/gameengine/GameLogic/SCA_IScene.h +++ b/source/gameengine/GameLogic/SCA_IScene.h @@ -33,55 +33,37 @@ #define __SCA_ISCENE_H__ #include +#include -#include "STR_String.h" -#include "RAS_2DFilterManager.h" +class SCA_IObject; -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -#define DEBUG_MAX_DISPLAY 100 +class SCA_IObject; struct SCA_DebugProp { - class CValue* m_obj; - STR_String m_name; - SCA_DebugProp(); + SCA_IObject *m_obj; + std::string m_name; + + SCA_DebugProp(SCA_IObject *gameobj, const std::string& name); ~SCA_DebugProp(); }; class SCA_IScene { - std::vector m_debugList; +private: + std::vector m_debugList; + public: SCA_IScene(); virtual ~SCA_IScene(); - virtual class SCA_IObject* AddReplicaObject(class CValue* gameobj, - class CValue* locationobj, - int lifespan=0)=0; - virtual void RemoveObject(class CValue* gameobj)=0; - virtual void DelayedRemoveObject(class CValue* gameobj)=0; - //virtual void DelayedReleaseObject(class CValue* gameobj)=0; - - virtual void ReplaceMesh(class CValue* gameobj, - void* meshobj, bool use_gfx, bool use_phys)=0; - std::vector& GetDebugProperties(); - bool PropertyInDebugList(class CValue *gameobj, const STR_String &name); - bool ObjectInDebugList(class CValue *gameobj); - void RemoveAllDebugProperties(); - void AddDebugProperty(class CValue* debugprop, const STR_String &name); - void RemoveDebugProperty(class CValue *gameobj, const STR_String &name); - void RemoveObjectDebugProperties(class CValue* gameobj); - - virtual void Update2DFilter(std::vector& propNames, void* gameObj, - RAS_2DFilterManager::RAS_2DFILTER_MODE filtermode, - int pass, STR_String& text) {} - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:SCA_IScene") -#endif + const std::vector& GetDebugProperties() const; + bool PropertyInDebugList(SCA_IObject *gameobj, const std::string &name); + bool ObjectInDebugList(SCA_IObject *gameobj); + void RemoveAllDebugProperties(); + void AddDebugProperty(SCA_IObject *gameobj, const std::string &name); + void RemoveDebugProperty(SCA_IObject *gameobj, const std::string &name); + void RemoveObjectDebugProperties(SCA_IObject *gameobj); }; -#endif /* __SCA_ISCENE_H__ */ +#endif // __SCA_ISCENE_H__ diff --git a/source/gameengine/GameLogic/SCA_ISensor.cpp b/source/gameengine/GameLogic/SCA_ISensor.cpp index 44fbe1d4692d..957f0f399b3c 100644 --- a/source/gameengine/GameLogic/SCA_ISensor.cpp +++ b/source/gameengine/GameLogic/SCA_ISensor.cpp @@ -32,52 +32,41 @@ * \ingroup gamelogic */ - -#include - #include "SCA_ISensor.h" #include "SCA_EventManager.h" #include "SCA_LogicManager.h" // needed for IsTriggered() #include "SCA_PythonController.h" -#include +#include "CM_Message.h" +#include "CM_List.h" -/* Native functions */ -void SCA_ISensor::ReParent(SCA_IObject* parent) +void SCA_ISensor::ReParent(SCA_IObject *parent) { SCA_ILogicBrick::ReParent(parent); - // will be done when the sensor is activated - //m_eventmgr->RegisterSensor(this); - //this->SetActive(false); } - -SCA_ISensor::SCA_ISensor(SCA_IObject* gameobj, - class SCA_EventManager* eventmgr) : - SCA_ILogicBrick(gameobj) +SCA_ISensor::SCA_ISensor(SCA_IObject *gameobj, SCA_EventManager *eventmgr) + :SCA_ILogicBrick(gameobj), + m_eventmgr(eventmgr), + m_pos_pulsemode(false), + m_neg_pulsemode(false), + m_skipped_ticks(0), + m_pos_ticks(0), + m_neg_ticks(0), + m_invert(false), + m_level(false), + m_tap(false), + m_reset(false), + m_suspended(false), + m_links(0), + m_state(false), + m_prev_state(false) { - m_links = 0; - m_suspended = false; - m_invert = false; - m_level = false; - m_tap = false; - m_reset = false; - m_pos_ticks = 0; - m_neg_ticks = 0; - m_pos_pulsemode = false; - m_neg_pulsemode = false; - m_skipped_ticks = 0; - m_state = false; - m_prev_state = false; - - m_eventmgr = eventmgr; } - SCA_ISensor::~SCA_ISensor() { - // intentionally empty } void SCA_ISensor::ProcessReplica() @@ -100,9 +89,7 @@ bool SCA_ISensor::IsPositiveTrigger() return result; } -void SCA_ISensor::SetPulseMode(bool posmode, - bool negmode, - int skippedticks) +void SCA_ISensor::SetPulseMode(bool posmode, bool negmode, int skippedticks) { m_pos_pulsemode = posmode; m_neg_pulsemode = negmode; @@ -124,12 +111,16 @@ void SCA_ISensor::SetTap(bool tap) m_tap = tap; } - double SCA_ISensor::GetNumber() { return GetState(); } +SCA_ISensor::sensortype SCA_ISensor::GetSensorType() +{ + return ST_NONE; +} + void SCA_ISensor::Suspend() { m_suspended = true; @@ -145,21 +136,56 @@ void SCA_ISensor::Resume() m_suspended = false; } +bool SCA_ISensor::GetState() +{ + return m_state; +} + +bool SCA_ISensor::GetPrevState() +{ + return m_prev_state; +} + +int SCA_ISensor::GetPosTicks() +{ + return m_pos_ticks; +} + +int SCA_ISensor::GetNegTicks() +{ + return m_neg_ticks; +} + +void SCA_ISensor::ClrLink() +{ + m_links = 0; +} + +void SCA_ISensor::IncLink() +{ + if (!m_links++) { + RegisterToManager(); + } +} + +bool SCA_ISensor::IsNoLink() const +{ + return !m_links; +} + void SCA_ISensor::Init() { - printf("Sensor %s has no init function, please report this bug to Blender.org\n", m_name.Ptr()); + CM_LogicBrickError(this, "sensor " << m_name << " has no init function, please report this bug to Blender.org"); } void SCA_ISensor::DecLink() { - m_links--; - if (m_links < 0) - { - printf("Warning: sensor %s has negative m_links: %d\n", m_name.Ptr(), m_links); + --m_links; + if (m_links < 0) { + CM_LogicBrickWarning(this, "sensor " << m_name << " has negative m_links: " << m_links); m_links = 0; } - if (!m_links) - { + if (!m_links) { // sensor is detached from all controllers, remove it from manager UnregisterToManager(); } @@ -173,47 +199,36 @@ void SCA_ISensor::RegisterToManager() m_eventmgr->RegisterSensor(this); } -void SCA_ISensor::Replace_EventManager(class SCA_LogicManager* logicmgr) +void SCA_ISensor::Replace_EventManager(class SCA_LogicManager *logicmgr) { - if (m_links) { /* true if we're used currently */ - + // True if we're used currently. + if (m_links) { m_eventmgr->RemoveSensor(this); - m_eventmgr= logicmgr->FindEventManager(m_eventmgr->GetType()); + m_eventmgr = logicmgr->FindEventManager(m_eventmgr->GetType()); m_eventmgr->RegisterSensor(this); } else { - m_eventmgr= logicmgr->FindEventManager(m_eventmgr->GetType()); + m_eventmgr = logicmgr->FindEventManager(m_eventmgr->GetType()); } } -void SCA_ISensor::LinkToController(SCA_IController* controller) +void SCA_ISensor::LinkToController(SCA_IController *controller) { m_linkedcontrollers.push_back(controller); } -void SCA_ISensor::UnlinkController(SCA_IController* controller) +void SCA_ISensor::UnlinkController(SCA_IController *controller) { - std::vector::iterator contit; - for (contit = m_linkedcontrollers.begin();!(contit==m_linkedcontrollers.end());++contit) - { - if ((*contit) == controller) - { - *contit = m_linkedcontrollers.back(); - m_linkedcontrollers.pop_back(); - return; - } + if (!CM_ListRemoveIfFound(m_linkedcontrollers, controller)) { + CM_LogicBrickWarning(this, "missing link from sensor " << m_gameobj->GetName() << ":" << GetName() + << " to controller " << controller->GetParent()->GetName() << ":" << controller->GetName()); } - printf("Missing link from sensor %s:%s to controller %s:%s\n", - m_gameobj->GetName().ReadPtr(), GetName().ReadPtr(), - controller->GetParent()->GetName().ReadPtr(), controller->GetName().ReadPtr()); } void SCA_ISensor::UnlinkAllControllers() { - std::vector::iterator contit; - for (contit = m_linkedcontrollers.begin();!(contit==m_linkedcontrollers.end());++contit) - { - (*contit)->UnlinkSensor(this); + for (SCA_IController *controller : m_linkedcontrollers) { + controller->UnlinkSensor(this); } m_linkedcontrollers.clear(); } @@ -224,22 +239,20 @@ void SCA_ISensor::UnregisterToManager() m_links = 0; } -void SCA_ISensor::ActivateControllers(class SCA_LogicManager* logicmgr) +void SCA_ISensor::ActivateControllers(class SCA_LogicManager *logicmgr) { - for (vector::const_iterator c= m_linkedcontrollers.begin(); - c!=m_linkedcontrollers.end();++c) - { - SCA_IController* contr = *c; - if (contr->IsActive()) - logicmgr->AddTriggeredController(contr, this); + for (SCA_IController *controller : m_linkedcontrollers) { + if (controller->IsActive()) { + logicmgr->AddTriggeredController(controller, this); + } } } -void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr) +void SCA_ISensor::Activate(class SCA_LogicManager *logicmgr) { - - // calculate if a __triggering__ is wanted - // don't evaluate a sensor that is not connected to any controller + /* Calculate if a __triggering__ is wanted + * don't evaluate a sensor that is not connected to any controller + */ if (m_links && !m_suspended) { bool result = this->Evaluate(); // store the state for the rest of the logic system @@ -252,20 +265,19 @@ void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr) // reset these counters so that pulse are synchronized with transition m_pos_ticks = 0; m_neg_ticks = 0; - } else - { + } + else { result = false; } - } else - { + } + else { /* First, the pulsing behavior, if pulse mode is * active. It seems something goes wrong if pulse mode is * not set :( */ if (m_pos_pulsemode) { m_pos_ticks++; if (m_pos_ticks > m_skipped_ticks) { - if ( m_state ) - { + if (m_state) { ActivateControllers(logicmgr); result = true; } @@ -273,12 +285,10 @@ void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr) } } // negative pulse doesn't make sense in tap mode, skip - if (m_neg_pulsemode && !m_tap) - { + if (m_neg_pulsemode && !m_tap) { m_neg_ticks++; if (m_neg_ticks > m_skipped_ticks) { - if (!m_state ) - { + if (!m_state) { ActivateControllers(logicmgr); result = true; } @@ -286,14 +296,11 @@ void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr) } } } - if (m_tap) - { + if (m_tap) { // in tap mode: we send always a negative pulse immediately after a positive pulse - if (!result) - { + if (!result) { // the sensor did not trigger on this frame - if (m_prev_state) - { + if (m_prev_state) { // but it triggered on previous frame => send a negative pulse ActivateControllers(logicmgr); result = true; @@ -302,16 +309,13 @@ void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr) m_state = false; } } - if (!result && m_level) - { + if (!result && m_level) { // This level sensor is connected to at least one controller that was just made // active but it did not generate an event yet, do it now to those controllers only - for (vector::const_iterator c= m_linkedcontrollers.begin(); - c!=m_linkedcontrollers.end();++c) - { - SCA_IController* contr = *c; - if (contr->IsJustActivated()) - logicmgr->AddTriggeredController(contr, this); + for (SCA_IController *controller : m_linkedcontrollers) { + if (controller->IsJustActivated()) { + logicmgr->AddTriggeredController(controller, this); + } } } } @@ -323,10 +327,10 @@ void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr) /* Python Functions */ /* ----------------------------------------------- */ -KX_PYMETHODDEF_DOC_NOARGS(SCA_ISensor, reset, -"reset()\n" -"\tReset sensor internal state, effect depends on the type of sensor and settings.\n" -"\tThe sensor is put in its initial state as if it was just activated.\n") +EXP_PYMETHODDEF_DOC_NOARGS(SCA_ISensor, reset, + "reset()\n" + "\tReset sensor internal state, effect depends on the type of sensor and settings.\n" + "\tThe sensor is put in its initial state as if it was just activated.\n") { Init(); m_prev_state = false; @@ -338,9 +342,9 @@ KX_PYMETHODDEF_DOC_NOARGS(SCA_ISensor, reset, /* ----------------------------------------------- */ PyTypeObject SCA_ISensor::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_ISensor", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -348,115 +352,114 @@ PyTypeObject SCA_ISensor::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_ILogicBrick::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_ISensor::Methods[] = { - KX_PYMETHODTABLE_NOARGS(SCA_ISensor, reset), - {NULL,NULL} //Sentinel + EXP_PYMETHODTABLE_NOARGS(SCA_ISensor, reset), + {nullptr, nullptr} // Sentinel }; PyAttributeDef SCA_ISensor::Attributes[] = { - KX_PYATTRIBUTE_BOOL_RW("usePosPulseMode",SCA_ISensor,m_pos_pulsemode), - KX_PYATTRIBUTE_BOOL_RW("useNegPulseMode",SCA_ISensor,m_neg_pulsemode), - KX_PYATTRIBUTE_INT_RW("skippedTicks",0,100000,true,SCA_ISensor,m_skipped_ticks), - KX_PYATTRIBUTE_BOOL_RW("invert",SCA_ISensor,m_invert), - KX_PYATTRIBUTE_BOOL_RW_CHECK("level",SCA_ISensor,m_level,pyattr_check_level), - KX_PYATTRIBUTE_BOOL_RW_CHECK("tap",SCA_ISensor,m_tap,pyattr_check_tap), - KX_PYATTRIBUTE_RO_FUNCTION("triggered", SCA_ISensor, pyattr_get_triggered), - KX_PYATTRIBUTE_RO_FUNCTION("positive", SCA_ISensor, pyattr_get_positive), - KX_PYATTRIBUTE_RO_FUNCTION("status", SCA_ISensor, pyattr_get_status), - KX_PYATTRIBUTE_RO_FUNCTION("pos_ticks", SCA_ISensor, pyattr_get_posTicks), - KX_PYATTRIBUTE_RO_FUNCTION("neg_ticks", SCA_ISensor, pyattr_get_negTicks), - KX_PYATTRIBUTE_RW_FUNCTION("frequency", SCA_ISensor, pyattr_get_frequency, pyattr_set_frequency), - { NULL } //Sentinel + EXP_PYATTRIBUTE_BOOL_RW("usePosPulseMode", SCA_ISensor, m_pos_pulsemode), + EXP_PYATTRIBUTE_BOOL_RW("useNegPulseMode", SCA_ISensor, m_neg_pulsemode), + EXP_PYATTRIBUTE_INT_RW("skippedTicks", 0, 100000, true, SCA_ISensor, m_skipped_ticks), + EXP_PYATTRIBUTE_BOOL_RW("invert", SCA_ISensor, m_invert), + EXP_PYATTRIBUTE_BOOL_RW_CHECK("level", SCA_ISensor, m_level, pyattr_check_level), + EXP_PYATTRIBUTE_BOOL_RW_CHECK("tap", SCA_ISensor, m_tap, pyattr_check_tap), + EXP_PYATTRIBUTE_RO_FUNCTION("triggered", SCA_ISensor, pyattr_get_triggered), + EXP_PYATTRIBUTE_RO_FUNCTION("positive", SCA_ISensor, pyattr_get_positive), + EXP_PYATTRIBUTE_RO_FUNCTION("status", SCA_ISensor, pyattr_get_status), + EXP_PYATTRIBUTE_RO_FUNCTION("pos_ticks", SCA_ISensor, pyattr_get_posTicks), + EXP_PYATTRIBUTE_RO_FUNCTION("neg_ticks", SCA_ISensor, pyattr_get_negTicks), + EXP_PYATTRIBUTE_RW_FUNCTION("frequency", SCA_ISensor, pyattr_get_frequency, pyattr_set_frequency), + EXP_PYATTRIBUTE_NULL // Sentinel }; -PyObject *SCA_ISensor::pyattr_get_triggered(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_ISensor::pyattr_get_triggered(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_ISensor* self = static_cast(self_v); + SCA_ISensor *self = static_cast(self_v); bool retval = false; - if (SCA_PythonController::m_sCurrentController) + if (SCA_PythonController::m_sCurrentController) { retval = SCA_PythonController::m_sCurrentController->IsTriggered(self); + } return PyBool_FromLong(retval); } -PyObject *SCA_ISensor::pyattr_get_positive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_ISensor::pyattr_get_positive(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_ISensor* self = static_cast(self_v); + SCA_ISensor *self = static_cast(self_v); return PyBool_FromLong(self->GetState()); } -PyObject *SCA_ISensor::pyattr_get_status(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_ISensor::pyattr_get_status(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_ISensor* self = static_cast(self_v); - int status = 0; - if (self->GetState()) - { - if (self->GetState() == self->GetPrevState()) - { - status = 2; + SCA_ISensor *self = static_cast(self_v); + int status = KX_SENSOR_INACTIVE; + if (self->GetState()) { + if (self->GetState() == self->GetPrevState()) { + status = KX_SENSOR_ACTIVE; } - else - { - status = 1; + else { + status = KX_SENSOR_JUST_ACTIVATED; } } - else if (self->GetState() != self->GetPrevState()) - { - status = 3; + else if (self->GetState() != self->GetPrevState()) { + status = KX_SENSOR_JUST_DEACTIVATED; } return PyLong_FromLong(status); } -PyObject *SCA_ISensor::pyattr_get_posTicks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_ISensor::pyattr_get_posTicks(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_ISensor* self = static_cast(self_v); + SCA_ISensor *self = static_cast(self_v); return PyLong_FromLong(self->GetPosTicks()); } -PyObject *SCA_ISensor::pyattr_get_negTicks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_ISensor::pyattr_get_negTicks(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_ISensor* self = static_cast(self_v); + SCA_ISensor *self = static_cast(self_v); return PyLong_FromLong(self->GetNegTicks()); } -int SCA_ISensor::pyattr_check_level(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +int SCA_ISensor::pyattr_check_level(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_ISensor* self = static_cast(self_v); - if (self->m_level) + SCA_ISensor *self = static_cast(self_v); + if (self->m_level) { self->m_tap = false; + } return 0; } -int SCA_ISensor::pyattr_check_tap(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +int SCA_ISensor::pyattr_check_tap(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_ISensor* self = static_cast(self_v); - if (self->m_tap) + SCA_ISensor *self = static_cast(self_v); + if (self->m_tap) { self->m_level = false; + } return 0; } -PyObject *SCA_ISensor::pyattr_get_frequency(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_ISensor::pyattr_get_frequency(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_ISensor *self = static_cast(self_v); - ShowDeprecationWarning("SCA_ISensor.frequency", "SCA_ISensor.skippedTicks"); + SCA_ISensor *self = static_cast(self_v); + EXP_ShowDeprecationWarning("SCA_ISensor.frequency", "SCA_ISensor.skippedTicks"); return PyLong_FromLong(self->m_skipped_ticks); } -int SCA_ISensor::pyattr_set_frequency(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int SCA_ISensor::pyattr_set_frequency(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - SCA_ISensor *self = static_cast(self_v); - ShowDeprecationWarning("SCA_ISensor.frequency", "SCA_ISensor.skippedTicks"); + SCA_ISensor *self = static_cast(self_v); + EXP_ShowDeprecationWarning("SCA_ISensor.frequency", "SCA_ISensor.skippedTicks"); if (PyLong_Check(value)) { self->m_skipped_ticks = PyLong_AsLong(value); return PY_SET_ATTR_SUCCESS; @@ -467,5 +470,3 @@ int SCA_ISensor::pyattr_set_frequency(void *self_v, const struct KX_PYATTRIBUTE_ } } #endif // WITH_PYTHON - -/* eof */ diff --git a/source/gameengine/GameLogic/SCA_ISensor.h b/source/gameengine/GameLogic/SCA_ISensor.h index f8276b1c79f3..13f5cdfe5d5f 100644 --- a/source/gameengine/GameLogic/SCA_ISensor.h +++ b/source/gameengine/GameLogic/SCA_ISensor.h @@ -36,61 +36,61 @@ #include "SCA_IController.h" -#include +class SCA_EventManager; /** * Interface Class for all logic Sensors. Implements * pulsemode,pulsefrequency - * Use of SG_DList element: link sensors to their respective event manager - * Head: SCA_EventManager::m_sensors + * Use of SG_DList element: not used * Use of SG_QList element: not used */ class SCA_ISensor : public SCA_ILogicBrick { Py_Header + protected: - class SCA_EventManager* m_eventmgr; + SCA_EventManager *m_eventmgr; - /** Pulse positive pulses? */ + /// Pulse positive pulses? bool m_pos_pulsemode; - /** Pulse negative pulses? */ + /// Pulse negative pulses? bool m_neg_pulsemode; - /** Number of skipped ticks between two active pulses. */ + /// Number of skipped ticks between two active pulses. int m_skipped_ticks; - /** Number of ticks since the last positive pulse. */ + /// Number of ticks since the last positive pulse. int m_pos_ticks; - /** Number of ticks since the last negative pulse. */ + /// Number of ticks since the last negative pulse. int m_neg_ticks; - /** invert the output signal*/ + /// Invert the output signal. bool m_invert; - /** detect level instead of edge*/ + /// Detect level instead of edge. bool m_level; - /** tap mode */ + /// Tap mode. bool m_tap; - /** sensor has been reset */ + /// Sensor has been reset. bool m_reset; - /** Sensor must ignore updates? */ + /// Sensor must ignore updates? bool m_suspended; - /** number of connections to controller */ + /// Number of connections to controller. int m_links; - /** current sensor state */ + /// Current sensor state. bool m_state; - /** previous state (for tap option) */ + /// Previous state (for tap option). bool m_prev_state; - std::vector m_linkedcontrollers; + std::vector m_linkedcontrollers; public: @@ -102,30 +102,28 @@ class SCA_ISensor : public SCA_ILogicBrick // to be updated as needed }; - SCA_ISensor(SCA_IObject* gameobj, - class SCA_EventManager* eventmgr); - ~SCA_ISensor(); - virtual void ReParent(SCA_IObject* parent); + SCA_ISensor(SCA_IObject *gameobj, SCA_EventManager *eventmgr); + virtual ~SCA_ISensor(); + + virtual void ReParent(SCA_IObject *parent); /** Because we want sensors to share some behavior, the Activate has */ /* an implementation on this level. It requires an evaluate on the lower */ /* level of individual sensors. Mapping the old activate()s is easy. */ /* The IsPosTrig() also has to change, to keep things consistent. */ - void Activate(class SCA_LogicManager* logicmgr); + void Activate(SCA_LogicManager *logicmgr); virtual bool Evaluate() = 0; virtual bool IsPositiveTrigger(); virtual void Init(); - virtual CValue* GetReplica()=0; + virtual EXP_Value *GetReplica() = 0; /** Set parameters for the pulsing behavior. * \param posmode Trigger positive pulses? * \param negmode Trigger negative pulses? * \param freq Frequency to use when doing pulsing. */ - void SetPulseMode(bool posmode, - bool negmode, - int skippedticks); + void SetPulseMode(bool posmode, bool negmode, int skippedticks); /** Set inversion of pulses on or off. */ void SetInvert(bool inv); @@ -135,77 +133,57 @@ class SCA_ISensor : public SCA_ILogicBrick virtual void RegisterToManager(); virtual void UnregisterToManager(); - void Replace_EventManager(class SCA_LogicManager* logicmgr); - void ReserveController(int num) - { - m_linkedcontrollers.reserve(num); - } - void LinkToController(SCA_IController* controller); - void UnlinkController(SCA_IController* controller); + void Replace_EventManager(SCA_LogicManager *logicmgr); + void LinkToController(SCA_IController *controller); + void UnlinkController(SCA_IController *controller); void UnlinkAllControllers(); - void ActivateControllers(class SCA_LogicManager* logicmgr); + void ActivateControllers(SCA_LogicManager *logicmgr); virtual void ProcessReplica(); virtual double GetNumber(); - virtual sensortype GetSensorType() { return ST_NONE; } + virtual sensortype GetSensorType(); - /** Stop sensing for a while. */ + /// Stop sensing for a while. void Suspend(); - /** Is this sensor switched off? */ + /// Is this sensor switched off? bool IsSuspended(); - /** get the state of the sensor: positive or negative */ - bool GetState() - { - return m_state; - } - - /** get the previous state of the sensor: positive or negative */ - bool GetPrevState() - { - return m_prev_state; - } - - /** get the number of ticks since the last positive pulse */ - int GetPosTicks() - { - return m_pos_ticks; - } - - /** get the number of ticks since the last negative pulse */ - int GetNegTicks() - { - return m_neg_ticks; - } - - /** Resume sensing. */ + /// Get the state of the sensor: positive or negative. + bool GetState(); + + /// Get the previous state of the sensor: positive or negative. + bool GetPrevState(); + + /// Get the number of ticks since the last positive pulse. + int GetPosTicks(); + + /// Get the number of ticks since the last negative pulse. + int GetNegTicks(); + + /// Resume sensing. void Resume(); - void ClrLink() - { m_links = 0; } - void IncLink() - { if (!m_links++) RegisterToManager(); } + void ClrLink(); + void IncLink(); void DecLink(); - bool IsNoLink() const - { return !m_links; } + bool IsNoLink() const; #ifdef WITH_PYTHON - /* Python functions: */ - KX_PYMETHOD_DOC_NOARGS(SCA_ISensor,reset); + EXP_PYMETHOD_DOC_NOARGS(SCA_ISensor, reset); - static PyObject* pyattr_get_triggered(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_positive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_status(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_posTicks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_negTicks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_frequency(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_frequency(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_triggered(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_positive(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_status(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_posTicks(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_negTicks(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_frequency(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_frequency(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_check_level(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_check_tap(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_check_level(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_check_tap(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); enum SensorStatus { KX_SENSOR_INACTIVE = 0, @@ -214,7 +192,7 @@ class SCA_ISensor : public SCA_ILogicBrick KX_SENSOR_JUST_DEACTIVATED }; -#endif /* WITH_PYTHON */ +#endif // WITH_PYTHON }; -#endif /* __SCA_ISENSOR_H__ */ +#endif // __SCA_ISENSOR_H__ diff --git a/source/gameengine/GameLogic/SCA_InputEvent.cpp b/source/gameengine/GameLogic/SCA_InputEvent.cpp new file mode 100644 index 000000000000..f62e6d556ead --- /dev/null +++ b/source/gameengine/GameLogic/SCA_InputEvent.cpp @@ -0,0 +1,208 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/GameLogic/SCA_InputEvent.cpp + * \ingroup gamelogic + */ + + +#include "SCA_InputEvent.h" + +#include "EXP_ListWrapper.h" + +#include + +SCA_InputEvent::SCA_InputEvent() + :m_unicode(0) +{ + m_status.push_back(NONE); + m_values.push_back(0); +} + +SCA_InputEvent::SCA_InputEvent(int type) + :m_unicode(0), + m_type(type) +{ + m_status.push_back(NONE); + m_values.push_back(0); +} + +std::string SCA_InputEvent::GetName() +{ + return "SCA_InputEvent"; +} + +void SCA_InputEvent::Clear() +{ + SCA_EnumInputs status = m_status[m_status.size() - 1]; + m_status.clear(); + m_status.push_back(status); + + int value = m_values[m_values.size() - 1]; + m_values.clear(); + m_values.push_back(value); + + m_queue.clear(); +} + +bool SCA_InputEvent::Find(SCA_EnumInputs inputenum) const +{ + if (inputenum == NONE || inputenum == ACTIVE) { + return std::count(m_status.begin(), m_status.end(), inputenum); + } + else { + return std::count(m_queue.begin(), m_queue.end(), inputenum); + } +} + +bool SCA_InputEvent::End(SCA_EnumInputs inputenum) const +{ + if (inputenum == NONE || inputenum == ACTIVE) { + return m_status[m_status.size() - 1] == inputenum; + } + else { + if (m_queue.empty()) { + return false; + } + return m_queue[m_queue.size() - 1] == inputenum; + } +} + +#ifdef WITH_PYTHON + +PyTypeObject SCA_InputEvent::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "SCA_InputEvent", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, + 0, + 0, 0, 0, + Methods, + 0, + 0, + &EXP_PyObjectPlus::Type, + 0, 0, 0, 0, 0, 0, + py_base_new +}; + +PyMethodDef SCA_InputEvent::Methods[] = { + {nullptr, nullptr} //Sentinel +}; + +PyAttributeDef SCA_InputEvent::Attributes[] = { + EXP_PYATTRIBUTE_RO_FUNCTION("status", SCA_InputEvent, pyattr_get_status), + EXP_PYATTRIBUTE_RO_FUNCTION("queue", SCA_InputEvent, pyattr_get_queue), + EXP_PYATTRIBUTE_RO_FUNCTION("values", SCA_InputEvent, pyattr_get_values), + EXP_PYATTRIBUTE_RO_FUNCTION("inactive", SCA_InputEvent, pyattr_get_inactive), + EXP_PYATTRIBUTE_RO_FUNCTION("active", SCA_InputEvent, pyattr_get_active), + EXP_PYATTRIBUTE_RO_FUNCTION("activated", SCA_InputEvent, pyattr_get_activated), + EXP_PYATTRIBUTE_RO_FUNCTION("released", SCA_InputEvent, pyattr_get_released), + EXP_PYATTRIBUTE_INT_RO("type", SCA_InputEvent, m_type), + EXP_PYATTRIBUTE_NULL //Sentinel +}; + +unsigned int SCA_InputEvent::get_status_size() +{ + return m_status.size(); +} + +PyObject *SCA_InputEvent::get_status_item(unsigned int index) +{ + return PyLong_FromLong(m_status[index]); +} + +PyObject *SCA_InputEvent::pyattr_get_status(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + return (new EXP_ListWrapper + (self_v, EXP_BaseListWrapper::FLAG_FIND_VALUE))->NewProxy(true); +} + +unsigned int SCA_InputEvent::get_queue_size() +{ + return m_queue.size(); +} + +PyObject *SCA_InputEvent::get_queue_item(unsigned int index) +{ + return PyLong_FromLong(m_queue[index]); +} + +PyObject *SCA_InputEvent::pyattr_get_queue(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + return (new EXP_ListWrapper + (self_v, EXP_BaseListWrapper::FLAG_FIND_VALUE))->NewProxy(true); +} + +unsigned int SCA_InputEvent::get_values_size() +{ + return m_values.size(); +} + +PyObject *SCA_InputEvent::get_values_item(unsigned int index) +{ + return PyLong_FromLong(m_values[index]); +} + +PyObject *SCA_InputEvent::pyattr_get_values(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + return (new EXP_ListWrapper + (self_v, EXP_BaseListWrapper::FLAG_FIND_VALUE))->NewProxy(true); +} + +PyObject *SCA_InputEvent::pyattr_get_inactive(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + SCA_InputEvent *self = static_cast(self_v); + + return PyBool_FromLong(self->Find(SCA_InputEvent::NONE)); +} + +PyObject *SCA_InputEvent::pyattr_get_active(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + SCA_InputEvent *self = static_cast(self_v); + + return PyBool_FromLong(self->Find(SCA_InputEvent::ACTIVE)); +} + +PyObject *SCA_InputEvent::pyattr_get_activated(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + SCA_InputEvent *self = static_cast(self_v); + + return PyBool_FromLong(self->Find(SCA_InputEvent::JUSTACTIVATED)); +} + +PyObject *SCA_InputEvent::pyattr_get_released(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + SCA_InputEvent *self = static_cast(self_v); + + return PyBool_FromLong(self->Find(SCA_InputEvent::JUSTRELEASED)); +} + +#endif // WITH_PYTHON diff --git a/source/gameengine/GameLogic/SCA_InputEvent.h b/source/gameengine/GameLogic/SCA_InputEvent.h new file mode 100644 index 000000000000..f857215745b7 --- /dev/null +++ b/source/gameengine/GameLogic/SCA_InputEvent.h @@ -0,0 +1,89 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file SCA_InputEvent.h + * \ingroup gamelogic + */ + +#ifndef __SCA_INPUTEVENT_H__ +#define __SCA_INPUTEVENT_H__ + +#include "EXP_Value.h" + +#include + +class SCA_InputEvent : public EXP_Value +{ +Py_Header +public: + enum SCA_EnumInputs { + NONE = 0, + JUSTACTIVATED, + ACTIVE, + JUSTRELEASED, + }; + + SCA_InputEvent(); + SCA_InputEvent(int type); + + virtual std::string GetName(); + + /// Clear status, values and queue but keep status and value from before. + void Clear(); + + /// Find an exisiting event or status. + bool Find(SCA_EnumInputs inputenum) const; + + /// Compare the last event or status with passed value. + bool End(SCA_EnumInputs inputenum) const; + + /// All recorded status during a frame, always contains one value. + std::vector m_status; + /// All recorded event for this input during a frame, can contain none value. + std::vector m_queue; + /// All recorded values of this input (used for mouse), always contains one value. + std::vector m_values; + /// Keyboard unicode value. + unsigned int m_unicode; + /// Event type. + int m_type; + +#ifdef WITH_PYTHON + unsigned int get_status_size(); + PyObject *get_status_item(unsigned int index); + unsigned int get_queue_size(); + PyObject *get_queue_item(unsigned int index); + unsigned int get_values_size(); + PyObject *get_values_item(unsigned int index); + + static PyObject *pyattr_get_status(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_queue(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_values(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_inactive(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_active(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_activated(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_released(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); +#endif +}; + +#endif // __SCA_IINPUTDEVICE_H__ + diff --git a/source/gameengine/GameLogic/SCA_JoystickManager.cpp b/source/gameengine/GameLogic/SCA_JoystickManager.cpp index 780e4e9ce882..12e9a2d16469 100644 --- a/source/gameengine/GameLogic/SCA_JoystickManager.cpp +++ b/source/gameengine/GameLogic/SCA_JoystickManager.cpp @@ -32,61 +32,32 @@ #include "SCA_JoystickSensor.h" #include "SCA_JoystickManager.h" #include "SCA_LogicManager.h" -//#include #include "SCA_ISensor.h" -//using namespace std; - -SCA_JoystickManager::SCA_JoystickManager(class SCA_LogicManager* logicmgr) - : SCA_EventManager(logicmgr, JOY_EVENTMGR) +SCA_JoystickManager::SCA_JoystickManager(class SCA_LogicManager *logicmgr) + :SCA_EventManager(logicmgr, JOY_EVENTMGR) { - int i; - for (i=0; iReleaseInstance(); - } } -void SCA_JoystickManager::NextFrame(double curtime,double deltatime) +void SCA_JoystickManager::NextFrame(double curtime, double deltatime) { - // We should always handle events in case we want to grab them with Python -#ifdef WITH_SDL - SCA_Joystick::HandleEvents(); /* Handle all SDL Joystick events */ -#endif - - if (m_sensors.Empty()) { - return; - } - else { - ; - SG_DList::iterator it(m_sensors); - for (it.begin();!it.end();++it) - { - SCA_JoystickSensor* joysensor = *it; - if (!joysensor->IsSuspended()) - { - joysensor->Activate(m_logicmgr); - } - } + for (SCA_ISensor *sensor : m_sensors) { + sensor->Activate(m_logicmgr); } } -SCA_Joystick *SCA_JoystickManager::GetJoystickDevice( short int joyindex) +DEV_Joystick *SCA_JoystickManager::GetJoystickDevice(short int joyindex) { /* - *Return the instance of SCA_Joystick for use + * Return the instance of DEV_Joystick for use */ - return m_joystick[joyindex]; + return DEV_Joystick::GetInstance(joyindex); } diff --git a/source/gameengine/GameLogic/SCA_JoystickManager.h b/source/gameengine/GameLogic/SCA_JoystickManager.h index bac764a08edc..c68dc26cb6f6 100644 --- a/source/gameengine/GameLogic/SCA_JoystickManager.h +++ b/source/gameengine/GameLogic/SCA_JoystickManager.h @@ -33,26 +33,17 @@ #define __SCA_JOYSTICKMANAGER_H__ #include "SCA_EventManager.h" -#include "Joystick/SCA_Joystick.h" -#include +#include "DEV_Joystick.h" -using namespace std; class SCA_JoystickManager : public SCA_EventManager { - /** - * SDL Joystick Class Instance - */ - SCA_Joystick *m_joystick[JOYINDEX_MAX]; + public: SCA_JoystickManager(class SCA_LogicManager* logicmgr); virtual ~SCA_JoystickManager(); virtual void NextFrame(double curtime,double deltatime); - SCA_Joystick* GetJoystickDevice(short int joyindex); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:SCA_JoystickManager") -#endif + DEV_Joystick* GetJoystickDevice(short int joyindex); }; #endif + diff --git a/source/gameengine/GameLogic/SCA_JoystickSensor.cpp b/source/gameengine/GameLogic/SCA_JoystickSensor.cpp index c98efd6db080..70ebc8c0cae5 100644 --- a/source/gameengine/GameLogic/SCA_JoystickSensor.cpp +++ b/source/gameengine/GameLogic/SCA_JoystickSensor.cpp @@ -37,45 +37,32 @@ #include "EXP_PyObjectPlus.h" -#include -#include -#include - - - -SCA_JoystickSensor::SCA_JoystickSensor(class SCA_JoystickManager* eventmgr, - SCA_IObject* gameobj, - short int joyindex, - short int joymode, - int axis, int axisf,int prec, - int button, - int hat, int hatf, bool allevents) - :SCA_ISensor(gameobj,eventmgr), - m_axis(axis), - m_axisf(axisf), - m_button(button), - m_hat(hat), - m_hatf(hatf), - m_precision(prec), - m_joymode(joymode), - m_joyindex(joyindex), - m_bAllEvents(allevents) +#include "CM_Message.h" + +#include "BLI_compiler_attrs.h" + +SCA_JoystickSensor::SCA_JoystickSensor(class SCA_JoystickManager *eventmgr, + SCA_IObject *gameobj, + short int joyindex, + short int joymode, + int axis, int axisf, int prec, + int button, bool allevents) + :SCA_ISensor(gameobj, eventmgr), + m_axis(axis), + m_axisf(axisf), + m_button(button), + m_precision(prec), + m_joymode(joymode), + m_joyindex(joyindex), + m_bAllEvents(allevents) { -/* -std::cout << " axis " << m_axis << std::endl; -std::cout << " axis flag " << m_axisf << std::endl; -std::cout << " precision " << m_precision << std::endl; -std::cout << " button " << m_button << std::endl; -std::cout << " hat " << m_hat << std::endl; -std::cout << " hat flag " << m_hatf << std::endl; -*/ Init(); } void SCA_JoystickSensor::Init() { - m_istrig=(m_invert)?1:0; - m_istrig_prev=0; + m_istrig = (m_invert) ? 1 : 0; + m_istrig_prev = 0; m_reset = true; } @@ -84,9 +71,9 @@ SCA_JoystickSensor::~SCA_JoystickSensor() } -CValue* SCA_JoystickSensor::GetReplica() +EXP_Value *SCA_JoystickSensor::GetReplica() { - SCA_JoystickSensor* replica = new SCA_JoystickSensor(*this); + SCA_JoystickSensor *replica = new SCA_JoystickSensor(*this); // this will copy properties and so on... replica->ProcessReplica(); replica->Init(); @@ -96,21 +83,24 @@ CValue* SCA_JoystickSensor::GetReplica() bool SCA_JoystickSensor::IsPositiveTrigger() { - bool result = m_istrig; - if (m_invert) + bool result = m_istrig; + if (m_invert) { result = !result; + } return result; } bool SCA_JoystickSensor::Evaluate() { - SCA_Joystick *js = ((SCA_JoystickManager *)m_eventmgr)->GetJoystickDevice(m_joyindex); + DEV_Joystick *js = ((SCA_JoystickManager *)m_eventmgr)->GetJoystickDevice(m_joyindex); bool result = false; bool reset = m_reset && m_level; + int axis_single_index = m_axis; - if (js==NULL) /* no joystick - don't do anything */ + if (js == nullptr) { /* no joystick - don't do anything */ return false; + } m_reset = false; @@ -129,12 +119,13 @@ bool SCA_JoystickSensor::Evaluate() * with expect a zero index. */ - if (!js->IsTrigAxis() && !reset) /* No events from SDL? - don't bother */ + if (!js->IsTrigAxis() && !reset) { /* No events from SDL? - don't bother */ return false; + } js->cSetPrecision(m_precision); if (m_bAllEvents) { - if (js->aAxisPairIsPositive(m_axis-1)) { /* use zero based axis index internally */ + if (js->aAxisPairIsPositive(m_axis - 1)) { /* use zero based axis index internally */ m_istrig = 1; result = true; } @@ -146,7 +137,7 @@ bool SCA_JoystickSensor::Evaluate() } } else { - if (js->aAxisPairDirectionIsPositive(m_axis-1, m_axisf)) { /* use zero based axis index internally */ + if (js->aAxisPairDirectionIsPositive(m_axis - 1, m_axisf)) { /* use zero based axis index internally */ m_istrig = 1; result = true; } @@ -159,15 +150,21 @@ bool SCA_JoystickSensor::Evaluate() } break; } + case KX_JOYSENSORMODE_SHOULDER_TRIGGER: + { + axis_single_index = m_axis + 4; + } + ATTR_FALLTHROUGH; case KX_JOYSENSORMODE_AXIS_SINGLE: { /* Like KX_JOYSENSORMODE_AXIS but don't pair up axis */ - if (!js->IsTrigAxis() && !reset) /* No events from SDL? - don't bother */ + if (!js->IsTrigAxis() && !reset) { /* No events from SDL? - don't bother */ return false; + } /* No need for 'm_bAllEvents' check here since were only checking 1 axis */ js->cSetPrecision(m_precision); - if (js->aAxisIsPositive(m_axis-1)) { /* use zero based axis index internally */ + if (js->aAxisIsPositive(axis_single_index - 1)) { /* use zero based axis index internally */ m_istrig = 1; result = true; } @@ -179,38 +176,16 @@ bool SCA_JoystickSensor::Evaluate() } break; } - case KX_JOYSENSORMODE_BUTTON: { /* what is what! * m_button = the actual button in question */ - if (!js->IsTrigButton() && !reset) /* No events from SDL? - don't bother */ + if (!js->IsTrigButton() && !reset) { /* No events from SDL? - don't bother */ return false; - - if (( m_bAllEvents && js->aAnyButtonPressIsPositive()) || (!m_bAllEvents && js->aButtonPressIsPositive(m_button))) { - m_istrig = 1; - result = true; } - else { - if (m_istrig) { - m_istrig = 0; - result = true; - } - } - break; - } - case KX_JOYSENSORMODE_HAT: - { - /* what is what! - * numberof = m_hat -- max 4 - * direction= m_hatf -- max 12 - */ - - if (!js->IsTrigHat() && !reset) /* No events from SDL? - don't bother */ - return false; - if ((m_bAllEvents && js->GetHat(m_hat-1)) || js->aHatIsPositive(m_hat-1, m_hatf)) { + if ((m_bAllEvents && js->aAnyButtonPressIsPositive()) || (!m_bAllEvents && js->aButtonPressIsPositive(m_button))) { m_istrig = 1; result = true; } @@ -222,10 +197,12 @@ bool SCA_JoystickSensor::Evaluate() } break; } - /* test for ball anyone ?*/ + /* test for ball anyone ?*/ default: - printf("Error invalid switch statement\n"); + { + CM_LogicBrickError(this, "invalid switch statement"); break; + } } /* if not all events are enabled, only send a positive pulse when @@ -239,31 +216,24 @@ bool SCA_JoystickSensor::Evaluate() } } - if (reset) + if (reset) { result = true; + } return result; } - -bool SCA_JoystickSensor::isValid(SCA_JoystickSensor::KX_JOYSENSORMODE m) -{ - bool res = false; - res = ((m > KX_JOYSENSORMODE_NODEF) && (m < KX_JOYSENSORMODE_MAX)); - return res; -} - #ifdef WITH_PYTHON /* ------------------------------------------------------------------------- */ -/* Python functions */ +/* Python functions */ /* ------------------------------------------------------------------------- */ /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_JoystickSensor::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_JoystickSensor", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -271,53 +241,53 @@ PyTypeObject SCA_JoystickSensor::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_ISensor::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_JoystickSensor::Methods[] = { - {"getButtonActiveList",(PyCFunction) SCA_JoystickSensor::sPyGetButtonActiveList, METH_NOARGS,(const char *)GetButtonActiveList_doc}, - {"getButtonStatus",(PyCFunction) SCA_JoystickSensor::sPyGetButtonStatus, METH_VARARGS,(const char *)GetButtonStatus_doc}, - {NULL,NULL} //Sentinel + {"getButtonActiveList", (PyCFunction)SCA_JoystickSensor::sPyGetButtonActiveList, METH_NOARGS, (const char *)GetButtonActiveList_doc}, + {"getButtonStatus", (PyCFunction)SCA_JoystickSensor::sPyGetButtonStatus, METH_VARARGS, (const char *)GetButtonStatus_doc}, + {nullptr, nullptr} //Sentinel }; PyAttributeDef SCA_JoystickSensor::Attributes[] = { - KX_PYATTRIBUTE_SHORT_RW("index",0,JOYINDEX_MAX-1,true,SCA_JoystickSensor,m_joyindex), - KX_PYATTRIBUTE_INT_RW("threshold",0,32768,true,SCA_JoystickSensor,m_precision), - KX_PYATTRIBUTE_INT_RW("button",0,100,false,SCA_JoystickSensor,m_button), - KX_PYATTRIBUTE_INT_LIST_RW_CHECK("axis",0,3,true,SCA_JoystickSensor,m_axis,2,CheckAxis), - KX_PYATTRIBUTE_INT_LIST_RW_CHECK("hat",0,12,true,SCA_JoystickSensor,m_hat,2,CheckHat), - KX_PYATTRIBUTE_RO_FUNCTION("axisValues", SCA_JoystickSensor, pyattr_get_axis_values), - KX_PYATTRIBUTE_RO_FUNCTION("axisSingle", SCA_JoystickSensor, pyattr_get_axis_single), - KX_PYATTRIBUTE_RO_FUNCTION("hatValues", SCA_JoystickSensor, pyattr_get_hat_values), - KX_PYATTRIBUTE_RO_FUNCTION("hatSingle", SCA_JoystickSensor, pyattr_get_hat_single), - KX_PYATTRIBUTE_RO_FUNCTION("numAxis", SCA_JoystickSensor, pyattr_get_num_axis), - KX_PYATTRIBUTE_RO_FUNCTION("numButtons", SCA_JoystickSensor, pyattr_get_num_buttons), - KX_PYATTRIBUTE_RO_FUNCTION("numHats", SCA_JoystickSensor, pyattr_get_num_hats), - KX_PYATTRIBUTE_RO_FUNCTION("connected", SCA_JoystickSensor, pyattr_get_connected), - { NULL } //Sentinel + EXP_PYATTRIBUTE_SHORT_RW("index", 0, JOYINDEX_MAX - 1, true, SCA_JoystickSensor, m_joyindex), + EXP_PYATTRIBUTE_INT_RW("threshold", 0, 32768, true, SCA_JoystickSensor, m_precision), + EXP_PYATTRIBUTE_INT_RW("button", 0, KX_JOYSENS_BUTTON_MAX - 1, false, SCA_JoystickSensor, m_button), + EXP_PYATTRIBUTE_INT_LIST_RW_CHECK("axis", 0, 3, true, SCA_JoystickSensor, m_axis, 2, CheckAxis), + EXP_PYATTRIBUTE_RO_FUNCTION("hat", SCA_JoystickSensor, pyattr_check_hat), + EXP_PYATTRIBUTE_RO_FUNCTION("axisValues", SCA_JoystickSensor, pyattr_get_axis_values), + EXP_PYATTRIBUTE_RO_FUNCTION("axisSingle", SCA_JoystickSensor, pyattr_get_axis_single), + EXP_PYATTRIBUTE_RO_FUNCTION("hatValues", SCA_JoystickSensor, pyattr_get_hat_values), + EXP_PYATTRIBUTE_RO_FUNCTION("hatSingle", SCA_JoystickSensor, pyattr_get_hat_single), + EXP_PYATTRIBUTE_RO_FUNCTION("numAxis", SCA_JoystickSensor, pyattr_get_num_axis), + EXP_PYATTRIBUTE_RO_FUNCTION("numButtons", SCA_JoystickSensor, pyattr_get_num_buttons), + EXP_PYATTRIBUTE_RO_FUNCTION("numHats", SCA_JoystickSensor, pyattr_get_num_hats), + EXP_PYATTRIBUTE_RO_FUNCTION("connected", SCA_JoystickSensor, pyattr_get_connected), + EXP_PYATTRIBUTE_NULL //Sentinel }; /* get button active list -------------------------------------------------- */ const char SCA_JoystickSensor::GetButtonActiveList_doc[] = -"getButtonActiveList\n" -"\tReturns a list containing the indices of the button currently pressed.\n"; -PyObject *SCA_JoystickSensor::PyGetButtonActiveList( ) + "getButtonActiveList\n" + "\tReturns a list containing the indices of the button currently pressed.\n"; +PyObject *SCA_JoystickSensor::PyGetButtonActiveList() { - SCA_Joystick *joy = ((SCA_JoystickManager *)m_eventmgr)->GetJoystickDevice(m_joyindex); + DEV_Joystick *joy = ((SCA_JoystickManager *)m_eventmgr)->GetJoystickDevice(m_joyindex); PyObject *ls = PyList_New(0); PyObject *value; int i; if (joy) { - for (i=0; i < joy->GetNumberOfButtons(); i++) { + for (i = 0; i < JOYBUT_MAX; i++) { if (joy->aButtonPressIsPositive(i)) { value = PyLong_FromLong(i); PyList_Append(ls, value); @@ -330,28 +300,28 @@ PyObject *SCA_JoystickSensor::PyGetButtonActiveList( ) /* get button status -------------------------------------------------- */ const char SCA_JoystickSensor::GetButtonStatus_doc[] = -"getButtonStatus(buttonIndex)\n" -"\tReturns a bool of the current pressed state of the specified button.\n"; -PyObject *SCA_JoystickSensor::PyGetButtonStatus( PyObject *args ) + "getButtonStatus(buttonIndex)\n" + "\tReturns a bool of the current pressed state of the specified button.\n"; +PyObject *SCA_JoystickSensor::PyGetButtonStatus(PyObject *args) { - SCA_Joystick *joy = ((SCA_JoystickManager *)m_eventmgr)->GetJoystickDevice(m_joyindex); + DEV_Joystick *joy = ((SCA_JoystickManager *)m_eventmgr)->GetJoystickDevice(m_joyindex); int index; if (!PyArg_ParseTuple(args, "i:getButtonStatus", &index)) { - return NULL; + return nullptr; } - if (joy && index >= 0 && index < joy->GetNumberOfButtons()) { + if (joy && index >= 0 && index < JOYBUT_MAX) { return PyBool_FromLong(joy->aButtonPressIsPositive(index) ? 1 : 0); } return PyBool_FromLong(0); } -PyObject *SCA_JoystickSensor::pyattr_get_axis_values(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_JoystickSensor::pyattr_get_axis_values(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_JoystickSensor* self = static_cast(self_v); - SCA_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex); + SCA_JoystickSensor *self = static_cast(self_v); + DEV_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex); - int axis_index = (joy ? joy->GetNumberOfAxes() : 0); + int axis_index = (joy ? JOYAXIS_MAX : 0); PyObject *list = PyList_New(axis_index); while (axis_index--) { @@ -361,68 +331,62 @@ PyObject *SCA_JoystickSensor::pyattr_get_axis_values(void *self_v, const KX_PYAT return list; } -PyObject *SCA_JoystickSensor::pyattr_get_axis_single(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_JoystickSensor::pyattr_get_axis_single(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_JoystickSensor* self = static_cast(self_v); - SCA_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex); + SCA_JoystickSensor *self = static_cast(self_v); + DEV_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex); if (self->m_joymode != KX_JOYSENSORMODE_AXIS_SINGLE) { PyErr_SetString(PyExc_AttributeError, "val = sensor.axisSingle: Joystick Sensor, not 'Single Axis' type"); - return NULL; + return nullptr; } return PyLong_FromLong(joy ? joy->GetAxisPosition(self->m_axis - 1) : 0); } -PyObject *SCA_JoystickSensor::pyattr_get_hat_values(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_JoystickSensor::pyattr_check_hat(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_JoystickSensor* self = static_cast(self_v); - SCA_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex); - - int hat_index = (joy ? joy->GetNumberOfHats() : 0); - PyObject *list = PyList_New(hat_index); - - while (hat_index--) { - PyList_SET_ITEM(list, hat_index, PyLong_FromLong(joy->GetHat(hat_index))); - } - - return list; + EXP_ShowDeprecationWarning("SCA_JoystickSensor.hat", "SCA_JoystickSensor.button"); + return nullptr; } -PyObject *SCA_JoystickSensor::pyattr_get_hat_single(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_JoystickSensor::pyattr_get_hat_values(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_JoystickSensor* self = static_cast(self_v); - SCA_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex); + EXP_ShowDeprecationWarning("SCA_JoystickSensor.hat", "SCA_JoystickSensor.button"); + return nullptr; +} - return PyLong_FromLong(joy ? joy->GetHat(self->m_hat - 1) : 0); +PyObject *SCA_JoystickSensor::pyattr_get_hat_single(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + EXP_ShowDeprecationWarning("SCA_JoystickSensor.hatSingle", "SCA_JoystickSensor.button"); + return nullptr; } -PyObject *SCA_JoystickSensor::pyattr_get_num_axis(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_JoystickSensor::pyattr_get_num_axis(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_JoystickSensor* self = static_cast(self_v); - SCA_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex); - return PyLong_FromLong( joy ? joy->GetNumberOfAxes() : 0 ); + SCA_JoystickSensor *self = static_cast(self_v); + DEV_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex); + return PyLong_FromLong(joy ? JOYAXIS_MAX : 0); } -PyObject *SCA_JoystickSensor::pyattr_get_num_buttons(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_JoystickSensor::pyattr_get_num_buttons(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_JoystickSensor* self = static_cast(self_v); - SCA_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex); - return PyLong_FromLong( joy ? joy->GetNumberOfButtons() : 0 ); + SCA_JoystickSensor *self = static_cast(self_v); + DEV_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex); + return PyLong_FromLong(joy ? JOYBUT_MAX : 0); } -PyObject *SCA_JoystickSensor::pyattr_get_num_hats(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_JoystickSensor::pyattr_get_num_hats(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_JoystickSensor* self = static_cast(self_v); - SCA_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex); - return PyLong_FromLong( joy ? joy->GetNumberOfHats() : 0 ); + EXP_ShowDeprecationWarning("SCA_JoystickSensor.numHats", "SCA_JoystickSensor.numButtons"); + return nullptr; } -PyObject *SCA_JoystickSensor::pyattr_get_connected(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_JoystickSensor::pyattr_get_connected(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_JoystickSensor* self = static_cast(self_v); - SCA_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex); - return PyBool_FromLong( joy ? joy->Connected() : 0 ); + SCA_JoystickSensor *self = static_cast(self_v); + DEV_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex); + return PyBool_FromLong(joy ? joy->Connected() : 0); } #endif diff --git a/source/gameengine/GameLogic/SCA_JoystickSensor.h b/source/gameengine/GameLogic/SCA_JoystickSensor.h index 30c2d1a30c3d..55ce17bfb077 100644 --- a/source/gameengine/GameLogic/SCA_JoystickSensor.h +++ b/source/gameengine/GameLogic/SCA_JoystickSensor.h @@ -34,12 +34,12 @@ #define __JOYSENSOR_H__ #include "SCA_ISensor.h" -#include "Joystick/SCA_JoystickDefines.h" +#include "DEV_JoystickDefines.h" class SCA_JoystickSensor :public SCA_ISensor { Py_Header - + /** * Axis 1-JOYAXIS_MAX, MUST be followed by m_axisf */ @@ -56,14 +56,6 @@ class SCA_JoystickSensor :public SCA_ISensor * Flag for a pressed or released button */ int m_buttonf; - /** - * The actual hat 1-JOYHAT_MAX. MUST be followed by m_hatf - */ - int m_hat; - /** - * Flag to find direction 1-12, MUST be an int - */ - int m_hatf; /** * The threshold value the axis acts upon */ @@ -92,31 +84,79 @@ class SCA_JoystickSensor :public SCA_ISensor */ bool m_bAllEvents; +public: + enum KX_JOYSENSORMODE { KX_JOYSENSORMODE_NODEF = 0, - KX_JOYSENSORMODE_AXIS, KX_JOYSENSORMODE_BUTTON, - KX_JOYSENSORMODE_HAT, + KX_JOYSENSORMODE_AXIS, + KX_JOYSENSORMODE_HAT, //unused KX_JOYSENSORMODE_AXIS_SINGLE, + KX_JOYSENSORMODE_SHOULDER_TRIGGER, KX_JOYSENSORMODE_MAX }; - bool isValid(KX_JOYSENSORMODE); -public: + enum KX_JOYSENS_BUTTON { + KX_JOYSENS_BUTTON_NODEF = -1, + KX_JOYSENS_BUTTON_A, + KX_JOYSENS_BUTTON_B, + KX_JOYSENS_BUTTON_X, + KX_JOYSENS_BUTTON_Y, + KX_JOYSENS_BUTTON_BACK, + KX_JOYSENS_BUTTON_GUIDE, + KX_JOYSENS_BUTTON_START, + KX_JOYSENS_BUTTON_STICK_LEFT, + KX_JOYSENS_BUTTON_STICK_RIGHT, + KX_JOYSENS_BUTTON_SHOULDER_LEFT, + KX_JOYSENS_BUTTON_SHOULDER_RIGHT, + KX_JOYSENS_BUTTON_DPAD_UP, + KX_JOYSENS_BUTTON_DPAD_DOWN, + KX_JOYSENS_BUTTON_DPAD_LEFT, + KX_JOYSENS_BUTTON_DPAD_RIGHT, + KX_JOYSENS_BUTTON_MAX + }; + + enum KX_JOYSENS_AXIS_SINGLE { + KX_JOYSENS_AXIS_SINGLE_NODEF = 0, + KX_JOYSENS_AXIS_SINGLE_LEFT_STICK_HORIZONTAL, + KX_JOYSENS_AXIS_SINGLE_LEFT_STICK_VERTICAL, + KX_JOYSENS_AXIS_SINGLE_RIGHT_STICK_HORIZONTAL, + KX_JOYSENS_AXIS_SINGLE_RIGHT_STICK_VERTICAL, + KX_JOYSENS_AXIS_SINGLE_LEFT_SHOULDER_TRIGGER, + KX_JOYSENS_AXIS_SINGLE_RIGHT_SHOULDER_TRIGGER, + KX_JOYSENS_AXIS_SINGLE_MAX + }; + + enum KX_JOYSENS_AXIS { + KX_JOYSENS_AXIS_NODEF = 0, + KX_JOYSENS_AXIS_LEFT_STICK, + KX_JOYSENS_AXIS_RIGHT_STICK, + KX_JOYSENS_AXIS_SHOULDER_TRIGGER, + KX_JOYSENS_AXIS_MAX + }; + + enum KX_JOYSENS_AXIS_STICK_DIRECTION { + KX_JOYSENS_AXIS_STICK_DIRECTION_NODEF = -1, + KX_JOYSENS_AXIS_STICK_DIRECTION_RIGHT, + KX_JOYSENS_AXIS_STICK_DIRECTION_UP, + KX_JOYSENS_AXIS_STICK_DIRECTION_LEFT, + KX_JOYSENS_AXIS_STICK_DIRECTION_DOWN, + KX_JOYSENS_AXIS_STICK_DIRECTION_MAX + }; + SCA_JoystickSensor(class SCA_JoystickManager* eventmgr, SCA_IObject* gameobj, short int joyindex, short int joymode, int axis, int axisf,int prec, - int button, - int hat, int hatf, bool allevents); + int button, bool allevents); virtual ~SCA_JoystickSensor(); - virtual CValue* GetReplica(); - + virtual EXP_Value* GetReplica(); + virtual bool Evaluate(); virtual bool IsPositiveTrigger(); virtual void Init(); - + short int GetJoyIndex(void) { return m_joyindex; } @@ -128,21 +168,22 @@ class SCA_JoystickSensor :public SCA_ISensor /* --------------------------------------------------------------------- */ /* Joystick Index */ - KX_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,GetButtonActiveList) - KX_PYMETHOD_DOC_VARARGS(SCA_JoystickSensor,GetButtonStatus) - - static PyObject* pyattr_get_axis_values(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_axis_single(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_hat_values(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_hat_single(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_num_axis(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_num_buttons(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_num_hats(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_connected(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - + EXP_PYMETHOD_DOC_NOARGS(SCA_JoystickSensor,GetButtonActiveList) + EXP_PYMETHOD_DOC_VARARGS(SCA_JoystickSensor,GetButtonStatus) + + static PyObject* pyattr_get_axis_values(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_axis_single(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_check_hat(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_hat_values(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_hat_single(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_num_axis(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_num_buttons(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_num_hats(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_connected(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + /* attribute check */ - static int CheckAxis(void *self, const PyAttributeDef*) + static int CheckAxis(EXP_PyObjectPlus *self, const PyAttributeDef*) { SCA_JoystickSensor* sensor = reinterpret_cast(self); if (sensor->m_axis < 1) @@ -151,16 +192,7 @@ class SCA_JoystickSensor :public SCA_ISensor sensor->m_axis = JOYAXIS_MAX; return 0; } - static int CheckHat(void *self, const PyAttributeDef*) - { - SCA_JoystickSensor* sensor = reinterpret_cast(self); - if (sensor->m_hat < 1) - sensor->m_hat = 1; - else if (sensor->m_hat > JOYHAT_MAX) - sensor->m_hat = JOYHAT_MAX; - return 0; - } - + #endif /* WITH_PYTHON */ }; diff --git a/source/gameengine/GameLogic/SCA_KeyboardManager.cpp b/source/gameengine/GameLogic/SCA_KeyboardManager.cpp index 1d3f81cd2132..27d453b1bc91 100644 --- a/source/gameengine/GameLogic/SCA_KeyboardManager.cpp +++ b/source/gameengine/GameLogic/SCA_KeyboardManager.cpp @@ -39,10 +39,10 @@ #include "EXP_IntValue.h" #include -SCA_KeyboardManager::SCA_KeyboardManager(SCA_LogicManager* logicmgr, - SCA_IInputDevice* inputdev) - : SCA_EventManager(logicmgr, KEYBOARD_EVENTMGR), - m_inputDevice(inputdev) +SCA_KeyboardManager::SCA_KeyboardManager(SCA_LogicManager *logicmgr, + SCA_IInputDevice *inputdev) + :SCA_EventManager(logicmgr, KEYBOARD_EVENTMGR), + m_inputDevice(inputdev) { } @@ -54,7 +54,7 @@ SCA_KeyboardManager::~SCA_KeyboardManager() -SCA_IInputDevice* SCA_KeyboardManager::GetInputDevice() +SCA_IInputDevice *SCA_KeyboardManager::GetInputDevice() { return m_inputDevice; } @@ -63,17 +63,7 @@ SCA_IInputDevice* SCA_KeyboardManager::GetInputDevice() void SCA_KeyboardManager::NextFrame() { - //const SCA_InputEvent& event = GetEventValue(SCA_IInputDevice::KX_EnumInputs inputcode)=0; -// cerr << "SCA_KeyboardManager::NextFrame"<< endl; - SG_DList::iterator it(m_sensors); - for (it.begin();!it.end();++it) - { - (*it)->Activate(m_logicmgr); + for (SCA_ISensor *sensor : m_sensors) { + sensor->Activate(m_logicmgr); } } - -bool SCA_KeyboardManager::IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode) -{ - return false; - //return m_kxsystem->IsPressed(inputcode); -} diff --git a/source/gameengine/GameLogic/SCA_KeyboardManager.h b/source/gameengine/GameLogic/SCA_KeyboardManager.h index 5a5c8e77b21c..852dd7d8ff20 100644 --- a/source/gameengine/GameLogic/SCA_KeyboardManager.h +++ b/source/gameengine/GameLogic/SCA_KeyboardManager.h @@ -36,31 +36,19 @@ #include "SCA_EventManager.h" - -#include - -using namespace std; - #include "SCA_IInputDevice.h" class SCA_KeyboardManager : public SCA_EventManager { class SCA_IInputDevice* m_inputDevice; - + public: SCA_KeyboardManager(class SCA_LogicManager* logicmgr,class SCA_IInputDevice* inputdev); virtual ~SCA_KeyboardManager(); - bool IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode); - virtual void NextFrame(); SCA_IInputDevice* GetInputDevice(); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:SCA_KeyboardManager") -#endif }; #endif /* __SCA_KEYBOARDMANAGER_H__ */ diff --git a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp index a502158f4530..cd5052be0b1d 100644 --- a/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp +++ b/source/gameengine/GameLogic/SCA_KeyboardSensor.cpp @@ -31,43 +31,44 @@ */ -#include - #include "SCA_KeyboardSensor.h" #include "SCA_KeyboardManager.h" #include "SCA_LogicManager.h" #include "EXP_StringValue.h" #include "SCA_IInputDevice.h" -extern "C" { - #include "BLI_string_utf8.h" - #include "BLI_string_cursor_utf8.h" -} +#include +#include /* ------------------------------------------------------------------------- */ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_KeyboardSensor::SCA_KeyboardSensor(SCA_KeyboardManager* keybdmgr, - short int hotkey, - short int qual, - short int qual2, - bool bAllKeys, - const STR_String& targetProp, - const STR_String& toggleProp, - SCA_IObject* gameobj, - short int exitKey) - :SCA_ISensor(gameobj,keybdmgr), - m_hotkey(hotkey), - m_qual(qual), - m_qual2(qual2), - m_bAllKeys(bAllKeys), - m_targetprop(targetProp), - m_toggleprop(toggleProp) +SCA_KeyboardSensor::SCA_KeyboardSensor(SCA_KeyboardManager *keybdmgr, + short int hotkey, + short int qual, + short int qual2, + bool bAllKeys, + const std::string& targetProp, + const std::string& toggleProp, + SCA_IObject *gameobj, + short int exitKey) + :SCA_ISensor(gameobj, keybdmgr), + m_hotkey(hotkey), + m_qual(qual), + m_qual2(qual2), + m_bAllKeys(bAllKeys), + m_targetprop(targetProp), + m_toggleprop(toggleProp) { - if (hotkey == exitKey) - keybdmgr->GetInputDevice()->HookEscape(); -// SetDrawColor(0xff0000ff); + if (hotkey == exitKey) { + keybdmgr->GetInputDevice()->SetHookExitKey(true); + } + + m_status[0] = false; + m_status[1] = false; + m_status[2] = false; + Init(); } @@ -83,221 +84,97 @@ void SCA_KeyboardSensor::Init() // by the state engine. It reinitializes the sensor as if it was just created. // However, if the target key is pressed when the sensor is reactivated, it // will not generated an event (see remark in Evaluate()). - m_val = (m_invert)?1:0; + m_val = (m_invert) ? 1 : 0; m_reset = true; } -CValue* SCA_KeyboardSensor::GetReplica() +EXP_Value *SCA_KeyboardSensor::GetReplica() { - SCA_KeyboardSensor* replica = new SCA_KeyboardSensor(*this); + SCA_KeyboardSensor *replica = new SCA_KeyboardSensor(*this); // this will copy properties and so on... replica->ProcessReplica(); replica->Init(); return replica; } - - -short int SCA_KeyboardSensor::GetHotkey() -{ - return m_hotkey; -} - - - bool SCA_KeyboardSensor::IsPositiveTrigger() { bool result = (m_val != 0); - if (m_invert) + if (m_invert) { result = !result; + } return result; } - - -bool SCA_KeyboardSensor::TriggerOnAllKeys() -{ - return m_bAllKeys; -} - - - bool SCA_KeyboardSensor::Evaluate() { bool result = false; bool reset = m_reset && m_level; - bool qual = true; - bool qual_change = false; - short int m_val_orig = m_val; - SCA_IInputDevice* inputdev = ((SCA_KeyboardManager *)m_eventmgr)->GetInputDevice(); - // cerr << "SCA_KeyboardSensor::Eval event, sensing for "<< m_hotkey << " at device " << inputdev << "\n"; + SCA_IInputDevice *inputdev = ((SCA_KeyboardManager *)m_eventmgr)->GetInputDevice(); + // cerr << "SCA_KeyboardSensor::Eval event, sensing for "<< m_hotkey << " at device " << inputdev << "\n"; /* See if we need to do logging: togPropState exists and is * different from 0 */ - CValue* myparent = GetParent(); - CValue* togPropState = myparent->GetProperty(m_toggleprop); + EXP_Value *myparent = GetParent(); + EXP_Value *togPropState = myparent->GetProperty(m_toggleprop); if (togPropState && - (((int)togPropState->GetNumber()) != 0) ) - { + (((int)togPropState->GetNumber()) != 0)) { LogKeystrokes(); } m_reset = false; /* Now see whether events must be bounced. */ - if (m_bAllKeys) - { - bool justactivated = false; - bool justreleased = false; - bool active = false; - - for (int i=SCA_IInputDevice::KX_BEGINKEY ; i<= SCA_IInputDevice::KX_ENDKEY;i++) - { - const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i); - switch (inevent.m_status) - { - case SCA_InputEvent::KX_JUSTACTIVATED: - justactivated = true; - break; - case SCA_InputEvent::KX_JUSTRELEASED: - justreleased = true; - break; - case SCA_InputEvent::KX_ACTIVE: - active = true; - break; - case SCA_InputEvent::KX_NO_INPUTSTATUS: - /* do nothing */ + if (m_bAllKeys) { + bool status = false; + bool events = false; + + for (int i = SCA_IInputDevice::BEGINKEY; i <= SCA_IInputDevice::ENDKEY; ++i) { + const SCA_InputEvent& input = inputdev->GetInput((SCA_IInputDevice::SCA_EnumInputs)i); + if (input.End(SCA_InputEvent::ACTIVE)) { + status = true; break; } } - if (justactivated) - { - m_val=1; - result = true; - } else - { - if (justreleased) - { - m_val=(active)?1:0; - result = true; - } else - { - if (active) - { - if (m_val == 0) - { - m_val = 1; - if (m_level) { - result = true; - } - } - } else - { - if (m_val == 1) - { - m_val = 0; - result = true; - } - } + for (int i = SCA_IInputDevice::BEGINKEY; i <= SCA_IInputDevice::ENDKEY; ++i) { + const SCA_InputEvent& input = inputdev->GetInput((SCA_IInputDevice::SCA_EnumInputs)i); + if (!input.m_queue.empty()) { + events = true; + break; } - if (m_tap) - // special case for tap mode: only generate event for new activation - result = false; } - - } else - { - - // cerr << "======= SCA_KeyboardSensor::Evaluate:: peeking at key status" << endl; - const SCA_InputEvent & inevent = inputdev->GetEventValue( - (SCA_IInputDevice::KX_EnumInputs) m_hotkey); - - // cerr << "======= SCA_KeyboardSensor::Evaluate:: status: " << inevent.m_status << endl; - + m_val = status; + result = events; + } + else { + bool status[3] = {false, false, false}; + bool events[3] = {false, false, false}; + const SCA_InputEvent & input = inputdev->GetInput((SCA_IInputDevice::SCA_EnumInputs)m_hotkey); /* Check qualifier keys * - see if the qualifiers we request are pressed - 'qual' true/false * - see if the qualifiers we request changed their state - 'qual_change' true/false */ if (m_qual > 0) { - const SCA_InputEvent & qualevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) m_qual); - switch (qualevent.m_status) { - case SCA_InputEvent::KX_NO_INPUTSTATUS: - qual = false; - break; - case SCA_InputEvent::KX_JUSTRELEASED: - qual_change = true; - qual = false; - break; - case SCA_InputEvent::KX_JUSTACTIVATED: - qual_change = true; - case SCA_InputEvent::KX_ACTIVE: - /* do nothing */ - break; - } + const SCA_InputEvent & qualevent = inputdev->GetInput((SCA_IInputDevice::SCA_EnumInputs)m_qual); + status[1] = qualevent.End(SCA_InputEvent::ACTIVE); + events[1] = !qualevent.m_queue.empty(); } - if (m_qual2 > 0 && qual==true) { - const SCA_InputEvent & qualevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) m_qual2); + if (m_qual2 > 0) { + const SCA_InputEvent & qualevent = inputdev->GetInput((SCA_IInputDevice::SCA_EnumInputs)m_qual2); /* copy of above */ - switch (qualevent.m_status) { - case SCA_InputEvent::KX_NO_INPUTSTATUS: - qual = false; - break; - case SCA_InputEvent::KX_JUSTRELEASED: - qual_change = true; - qual = false; - break; - case SCA_InputEvent::KX_JUSTACTIVATED: - qual_change = true; - case SCA_InputEvent::KX_ACTIVE: - /* do nothing */ - break; - } + status[2] = qualevent.End(SCA_InputEvent::ACTIVE); + events[2] = !qualevent.m_queue.empty(); } /* done reading qualifiers */ - if (inevent.m_status == SCA_InputEvent::KX_NO_INPUTSTATUS) - { - if (m_val == 1) - { - // this situation may occur after a scene suspend: the keyboard release - // event was not captured, produce now the event off - m_val = 0; - result = true; - } - } else - { - if (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED) - { - m_val=1; - result = true; - } else - { - if (inevent.m_status == SCA_InputEvent::KX_JUSTRELEASED) - { - m_val = 0; - result = true; - } else - { - if (inevent.m_status == SCA_InputEvent::KX_ACTIVE) - { - if (m_val == 0) - { - m_val = 1; - if (m_level) - { - result = true; - } - } - } - } - } - } + status[0] = input.End(SCA_InputEvent::ACTIVE); + events[0] = !input.m_queue.empty(); /* Modify the key state based on qual(s) * Tested carefully. don't touch unless your really sure. @@ -309,117 +186,59 @@ bool SCA_KeyboardSensor::Evaluate() * When ANY of the modifiers or main key become inactive, * - pulse false */ - if (qual==false) { /* one of the qualifiers are not pressed */ - if (m_val_orig && qual_change) { /* we were originally enabled, but a qualifier changed */ - result = true; - } else { - result = false; - } - m_val = 0; /* since one of the qualifiers is not on, set the state to false */ - } else { /* we done have any qualifiers or they are all pressed */ - if (m_val && qual_change) { /* the main key state is true and our qualifier just changed */ - result = true; - } + + // One of the third keys value from last logic frame changed. + if (events[0] || events[1] || events[2]) { + result = true; } - /* done with key quals */ + if (!status[0] || (m_qual > 0 && !status[0]) || (m_qual2 > 0 && !status[1])) { /* one of the used qualifiers are not pressed */ + m_val = false; /* since one of the qualifiers is not on, set the state to false */ + } + else { + m_val = true; + } + /* done with key quals */ } - if (reset) + if (reset) { // force an event result = true; + } return result; } -void SCA_KeyboardSensor::AddToTargetProp(int keyIndex, int unicode) -{ - if (IsPrintable(keyIndex)) { - CValue* tprop = GetParent()->GetProperty(m_targetprop); - - if (IsDelete(keyIndex)) { - /* Make a new property. Deletes can be ignored. */ - if (tprop) { - /* overwrite the old property */ - /* strip one char, if possible */ - STR_String newprop = tprop->GetText(); - int oldlength = newprop.Length(); - if (oldlength >= 1 ) { - int newlength=oldlength; - - BLI_str_cursor_step_prev_utf8(newprop, newprop.Length(), &newlength); - newprop.SetLength(newlength); - - CStringValue * newstringprop = new CStringValue(newprop, m_targetprop); - GetParent()->SetProperty(m_targetprop, newstringprop); - newstringprop->Release(); - } - } - } - else { - char utf8_buf[7]; - size_t utf8_len; - - utf8_len = BLI_str_utf8_from_unicode(unicode, utf8_buf); - utf8_buf[utf8_len] = '\0'; - - STR_String newprop = tprop ? (tprop->GetText() + utf8_buf) : utf8_buf; - - CStringValue * newstringprop = new CStringValue(newprop, m_targetprop); - GetParent()->SetProperty(m_targetprop, newstringprop); - newstringprop->Release(); - } - } -} - -/** - * Tests whether shift is pressed - */ -bool SCA_KeyboardSensor::IsShifted(void) +void SCA_KeyboardSensor::LogKeystrokes() { - SCA_IInputDevice* inputdev = ((SCA_KeyboardManager *)m_eventmgr)->GetInputDevice(); - - if ( (inputdev->GetEventValue(SCA_IInputDevice::KX_RIGHTSHIFTKEY).m_status - == SCA_InputEvent::KX_ACTIVE) - || (inputdev->GetEventValue(SCA_IInputDevice::KX_RIGHTSHIFTKEY).m_status - == SCA_InputEvent::KX_JUSTACTIVATED) - || (inputdev->GetEventValue(SCA_IInputDevice::KX_LEFTSHIFTKEY).m_status - == SCA_InputEvent::KX_ACTIVE) - || (inputdev->GetEventValue(SCA_IInputDevice::KX_LEFTSHIFTKEY).m_status - == SCA_InputEvent::KX_JUSTACTIVATED) - ) { - return true; - } - else { - return false; - } -} + EXP_Value *tprop = GetParent()->GetProperty(m_targetprop); -void SCA_KeyboardSensor::LogKeystrokes(void) -{ - SCA_IInputDevice* inputdev = ((SCA_KeyboardManager *)m_eventmgr)->GetInputDevice(); - int num = inputdev->GetNumActiveEvents(); + SCA_IInputDevice *inputdev = ((SCA_KeyboardManager *)m_eventmgr)->GetInputDevice(); - /* weird loop, this one... */ - if (num > 0) - { + std::wstring_convert > converter; + const std::wstring typedtext = inputdev->GetText(); + std::wstring proptext = converter.from_bytes(tprop->GetText()); - int index = 0; - /* Check on all keys whether they were pushed. This does not - * untangle the ordering, so don't type too fast :) */ - for (int i=SCA_IInputDevice::KX_BEGINKEY ; i<= SCA_IInputDevice::KX_ENDKEY;i++) - { - const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i); - if (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED) //NO_INPUTSTATUS) - { - if (index < num) - { - AddToTargetProp(i, inevent.m_unicode); - index++; - } + /* Convert all typed key in the prop string, if the key are del or + * backspace we remove the last string item. + */ + for (const wchar_t item : typedtext) { + if (item == '\b' || item == 127) { + if (!proptext.empty()) { + proptext.resize(proptext.size() - 1); } } + else if (item == '\r') { + proptext.push_back('\n'); + } + else { + proptext.push_back(item); + } } + + EXP_StringValue *newstringprop = new EXP_StringValue(converter.to_bytes(proptext), m_targetprop); + GetParent()->SetProperty(m_targetprop, newstringprop); + newstringprop->Release(); } #ifdef WITH_PYTHON @@ -428,27 +247,29 @@ void SCA_KeyboardSensor::LogKeystrokes(void) /* Python Functions */ /* ------------------------------------------------------------------------- */ -KX_PYMETHODDEF_DOC_O(SCA_KeyboardSensor, getKeyStatus, -"getKeyStatus(keycode)\n" -"\tGet the given key's status (KX_NO_INPUTSTATUS, KX_JUSTACTIVATED, KX_ACTIVE or KX_JUSTRELEASED).\n") +EXP_PYMETHODDEF_DOC_O(SCA_KeyboardSensor, getKeyStatus, + "getKeyStatus(keycode)\n" + "\tGet the given key's status (NONE, JUSTACTIVATED, ACTIVE or JUSTRELEASED).\n") { + EXP_ShowDeprecationWarning("sensor.getKeyStatus(keycode)", "logic.keyboard.events[keycode]"); + if (!PyLong_Check(value)) { PyErr_SetString(PyExc_ValueError, "sensor.getKeyStatus(int): Keyboard Sensor, expected an int"); - return NULL; + return nullptr; } - SCA_IInputDevice::KX_EnumInputs keycode = (SCA_IInputDevice::KX_EnumInputs)PyLong_AsLong(value); + SCA_IInputDevice::SCA_EnumInputs keycode = (SCA_IInputDevice::SCA_EnumInputs)PyLong_AsLong(value); - if ((keycode < SCA_IInputDevice::KX_BEGINKEY) || - (keycode > SCA_IInputDevice::KX_ENDKEY)) - { + if ((keycode < SCA_IInputDevice::BEGINKEY) || + (keycode > SCA_IInputDevice::ENDKEY)) { PyErr_SetString(PyExc_AttributeError, "sensor.getKeyStatus(int): Keyboard Sensor, invalid keycode specified!"); - return NULL; + return nullptr; } - SCA_IInputDevice* inputdev = ((SCA_KeyboardManager *)m_eventmgr)->GetInputDevice(); - const SCA_InputEvent & inevent = inputdev->GetEventValue(keycode); - return PyLong_FromLong(inevent.m_status); + SCA_IInputDevice *inputdev = ((SCA_KeyboardManager *)m_eventmgr)->GetInputDevice(); + const SCA_InputEvent & input = inputdev->GetInput(keycode); + return PyLong_FromLong(input.m_status[input.m_status.size() - 1]); + Py_RETURN_NONE; } /* ------------------------------------------------------------------------- */ @@ -456,9 +277,9 @@ KX_PYMETHODDEF_DOC_O(SCA_KeyboardSensor, getKeyStatus, /* ------------------------------------------------------------------------- */ PyTypeObject SCA_KeyboardSensor::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_KeyboardSensor", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -466,203 +287,87 @@ PyTypeObject SCA_KeyboardSensor::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_ISensor::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_KeyboardSensor::Methods[] = { - KX_PYMETHODTABLE_O(SCA_KeyboardSensor, getKeyStatus), - {NULL,NULL} //Sentinel + EXP_PYMETHODTABLE_O(SCA_KeyboardSensor, getKeyStatus), + {nullptr, nullptr} //Sentinel }; PyAttributeDef SCA_KeyboardSensor::Attributes[] = { - KX_PYATTRIBUTE_RO_FUNCTION("events", SCA_KeyboardSensor, pyattr_get_events), - KX_PYATTRIBUTE_BOOL_RW("useAllKeys",SCA_KeyboardSensor,m_bAllKeys), - KX_PYATTRIBUTE_INT_RW("key",0,SCA_IInputDevice::KX_ENDKEY,true,SCA_KeyboardSensor,m_hotkey), - KX_PYATTRIBUTE_SHORT_RW("hold1",0,SCA_IInputDevice::KX_ENDKEY,true,SCA_KeyboardSensor,m_qual), - KX_PYATTRIBUTE_SHORT_RW("hold2",0,SCA_IInputDevice::KX_ENDKEY,true,SCA_KeyboardSensor,m_qual2), - KX_PYATTRIBUTE_STRING_RW("toggleProperty",0,MAX_PROP_NAME,false,SCA_KeyboardSensor,m_toggleprop), - KX_PYATTRIBUTE_STRING_RW("targetProperty",0,MAX_PROP_NAME,false,SCA_KeyboardSensor,m_targetprop), - { NULL } //Sentinel + EXP_PYATTRIBUTE_RO_FUNCTION("events", SCA_KeyboardSensor, pyattr_get_events), + EXP_PYATTRIBUTE_RO_FUNCTION("inputs", SCA_KeyboardSensor, pyattr_get_inputs), + EXP_PYATTRIBUTE_BOOL_RW("useAllKeys", SCA_KeyboardSensor, m_bAllKeys), + EXP_PYATTRIBUTE_INT_RW("key", 0, SCA_IInputDevice::ENDKEY, true, SCA_KeyboardSensor, m_hotkey), + EXP_PYATTRIBUTE_SHORT_RW("hold1", 0, SCA_IInputDevice::ENDKEY, true, SCA_KeyboardSensor, m_qual), + EXP_PYATTRIBUTE_SHORT_RW("hold2", 0, SCA_IInputDevice::ENDKEY, true, SCA_KeyboardSensor, m_qual2), + EXP_PYATTRIBUTE_STRING_RW("toggleProperty", 0, MAX_PROP_NAME, false, SCA_KeyboardSensor, m_toggleprop), + EXP_PYATTRIBUTE_STRING_RW("targetProperty", 0, MAX_PROP_NAME, false, SCA_KeyboardSensor, m_targetprop), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *SCA_KeyboardSensor::pyattr_get_events(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_KeyboardSensor::pyattr_get_inputs(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_KeyboardSensor* self = static_cast(self_v); + SCA_KeyboardSensor *self = static_cast(self_v); - SCA_IInputDevice* inputdev = ((SCA_KeyboardManager *)self->m_eventmgr)->GetInputDevice(); + SCA_IInputDevice *inputdev = ((SCA_KeyboardManager *)self->m_eventmgr)->GetInputDevice(); - PyObject *resultlist = PyList_New(0); + PyObject *dict = PyDict_New(); - for (int i=SCA_IInputDevice::KX_BEGINKEY ; i<= SCA_IInputDevice::KX_ENDKEY;i++) + for (int i = SCA_IInputDevice::BEGINKEY; i <= SCA_IInputDevice::ENDKEY; i++) { - const SCA_InputEvent & inevent = inputdev->GetEventValue((SCA_IInputDevice::KX_EnumInputs) i); - if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS) - { - PyObject *keypair = PyList_New(2); - PyList_SET_ITEM(keypair,0,PyLong_FromLong(i)); - PyList_SET_ITEM(keypair,1,PyLong_FromLong(inevent.m_status)); - PyList_Append(resultlist,keypair); - Py_DECREF(keypair); - } - } - return resultlist; -} - -#endif // WITH_PYTHON + SCA_InputEvent& input = inputdev->GetInput((SCA_IInputDevice::SCA_EnumInputs)i); + if (input.Find(SCA_InputEvent::ACTIVE)) { + PyObject *key = PyLong_FromLong(i); -/* Accessed from python */ + PyDict_SetItem(dict, key, input.GetProxy()); -// this code looks ugly, please use an ordinary hashtable - -char ToCharacter(int keyIndex, bool shifted) -{ - /* numerals */ - if ( (keyIndex >= SCA_IInputDevice::KX_ZEROKEY) - && (keyIndex <= SCA_IInputDevice::KX_NINEKEY) ) { - if (shifted) { - char numshift[] = ")!@#$%^&*("; - return numshift[keyIndex - '0']; - } else { - return keyIndex - SCA_IInputDevice::KX_ZEROKEY + '0'; - } - } - - /* letters... always lowercase... is that desirable? */ - if ( (keyIndex >= SCA_IInputDevice::KX_AKEY) - && (keyIndex <= SCA_IInputDevice::KX_ZKEY) ) { - if (shifted) { - return keyIndex - SCA_IInputDevice::KX_AKEY + 'A'; - } else { - return keyIndex - SCA_IInputDevice::KX_AKEY + 'a'; + Py_DECREF(key); } } + return dict; +} - if (keyIndex == SCA_IInputDevice::KX_SPACEKEY) { - return ' '; - } - if (keyIndex == SCA_IInputDevice::KX_RETKEY || keyIndex == SCA_IInputDevice::KX_PADENTER) { - return '\n'; - } +PyObject *SCA_KeyboardSensor::pyattr_get_events(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + SCA_KeyboardSensor *self = static_cast(self_v); + EXP_ShowDeprecationWarning("sensor.events", "sensor.inputs"); - if (keyIndex == SCA_IInputDevice::KX_PADASTERKEY) { - return '*'; - } + SCA_IInputDevice *inputdev = ((SCA_KeyboardManager *)self->m_eventmgr)->GetInputDevice(); - if (keyIndex == SCA_IInputDevice::KX_TABKEY) { - return '\t'; - } + PyObject *resultlist = PyList_New(0); - /* comma to period */ - char commatoperiod[] = ",-."; - char commatoperiodshifted[] = "<_>"; - if (keyIndex == SCA_IInputDevice::KX_COMMAKEY) { - if (shifted) { - return commatoperiodshifted[0]; - } else { - return commatoperiod[0]; - } - } - if (keyIndex == SCA_IInputDevice::KX_MINUSKEY) { - if (shifted) { - return commatoperiodshifted[1]; - } else { - return commatoperiod[1]; + for (int i = SCA_IInputDevice::BEGINKEY; i <= SCA_IInputDevice::ENDKEY; i++) + { + SCA_InputEvent& input = inputdev->GetInput((SCA_IInputDevice::SCA_EnumInputs)i); + int event = 0; + if (input.m_queue.empty()) { + event = input.m_status[input.m_status.size() - 1]; } - } - if (keyIndex == SCA_IInputDevice::KX_PERIODKEY) { - if (shifted) { - return commatoperiodshifted[2]; - } else { - return commatoperiod[2]; + else { + event = input.m_queue[input.m_queue.size() - 1]; } - } - /* semicolon to rightbracket */ - char semicolontorightbracket[] = ";\'`/\\=[]"; - char semicolontorightbracketshifted[] = ":\"~\?|+{}"; - if ((keyIndex >= SCA_IInputDevice::KX_SEMICOLONKEY) - && (keyIndex <= SCA_IInputDevice::KX_RIGHTBRACKETKEY)) { - if (shifted) { - return semicolontorightbracketshifted[keyIndex - SCA_IInputDevice::KX_SEMICOLONKEY]; - } else { - return semicolontorightbracket[keyIndex - SCA_IInputDevice::KX_SEMICOLONKEY]; + if (event != SCA_InputEvent::NONE) { + PyObject *keypair = PyList_New(2); + PyList_SET_ITEM(keypair, 0, PyLong_FromLong(i)); + PyList_SET_ITEM(keypair, 1, PyLong_FromLong(event)); + PyList_Append(resultlist, keypair); + Py_DECREF(keypair); } } - - /* keypad2 to padplus */ - char pad2topadplus[] = "246813579. 0- +"; - if ((keyIndex >= SCA_IInputDevice::KX_PAD2) - && (keyIndex <= SCA_IInputDevice::KX_PADPLUSKEY)) { - return pad2topadplus[keyIndex - SCA_IInputDevice::KX_PAD2]; - } - - return '!'; -} - - - -/** - * Determine whether this character can be printed. We cannot use - * the library functions here, because we need to test our own - * keycodes. */ -bool IsPrintable(int keyIndex) -{ - /* only print - * - numerals: KX_ZEROKEY to KX_NINEKEY - * - alphas: KX_AKEY to KX_ZKEY. - * - specials: KX_RETKEY, KX_PADASTERKEY, KX_PADCOMMAKEY to KX_PERIODKEY, - * KX_TABKEY, KX_SEMICOLONKEY to KX_RIGHTBRACKETKEY, - * KX_PAD2 to KX_PADPLUSKEY - * - delete and backspace: also printable in the sense that they modify - * the string - * - retkey: should this be printable? - * - virgule: prints a space... don't know which key that's supposed - * to be... - */ - if ( ((keyIndex >= SCA_IInputDevice::KX_ZEROKEY) - && (keyIndex <= SCA_IInputDevice::KX_NINEKEY)) - || ((keyIndex >= SCA_IInputDevice::KX_AKEY) - && (keyIndex <= SCA_IInputDevice::KX_ZKEY)) - || (keyIndex == SCA_IInputDevice::KX_SPACEKEY) - || (keyIndex == SCA_IInputDevice::KX_RETKEY) - || (keyIndex == SCA_IInputDevice::KX_PADENTER) - || (keyIndex == SCA_IInputDevice::KX_PADASTERKEY) - || (keyIndex == SCA_IInputDevice::KX_TABKEY) - || ((keyIndex >= SCA_IInputDevice::KX_COMMAKEY) - && (keyIndex <= SCA_IInputDevice::KX_PERIODKEY)) - || ((keyIndex >= SCA_IInputDevice::KX_SEMICOLONKEY) - && (keyIndex <= SCA_IInputDevice::KX_RIGHTBRACKETKEY)) - || ((keyIndex >= SCA_IInputDevice::KX_PAD2) - && (keyIndex <= SCA_IInputDevice::KX_PADPLUSKEY)) - || (keyIndex == SCA_IInputDevice::KX_DELKEY) - || (keyIndex == SCA_IInputDevice::KX_BACKSPACEKEY) - ) - { - return true; - } else { - return false; - } + return resultlist; } -/** - * Tests whether this is a delete key. - */ -bool IsDelete(int keyIndex) -{ - if ( (keyIndex == SCA_IInputDevice::KX_DELKEY) - || (keyIndex == SCA_IInputDevice::KX_BACKSPACEKEY) ) { - return true; - } else { - return false; - } -} +#endif // WITH_PYTHON diff --git a/source/gameengine/GameLogic/SCA_KeyboardSensor.h b/source/gameengine/GameLogic/SCA_KeyboardSensor.h index 0429ccf9bd1e..9de5b92b0d70 100644 --- a/source/gameengine/GameLogic/SCA_KeyboardSensor.h +++ b/source/gameengine/GameLogic/SCA_KeyboardSensor.h @@ -52,6 +52,7 @@ class SCA_KeyboardSensor : public SCA_ISensor int m_hotkey; short int m_qual,m_qual2; short int m_val; + bool m_status[3]; /** * If this toggle is true, all incoming key events generate a * response. @@ -62,29 +63,19 @@ class SCA_KeyboardSensor : public SCA_ISensor * The name of the property to which logged text is appended. If * this property is not defined, no logging takes place. */ - STR_String m_targetprop; + std::string m_targetprop; /** * The property that indicates whether or not to log text when in * logging mode. If the property equals 0, no logging is done. For * all other values, logging is active. Logging can only become * active if there is a property to log to. Logging is independent * from hotkey settings. */ - STR_String m_toggleprop; + std::string m_toggleprop; /** * Log the keystrokes from the current input buffer. */ - void LogKeystrokes(void); - - /** - * Adds this key-code to the target prop. - */ - void AddToTargetProp(int keyIndex, int unicode); - - /** - * Tests whether shift is pressed. - */ - bool IsShifted(void); + void LogKeystrokes(); public: SCA_KeyboardSensor(class SCA_KeyboardManager* keybdmgr, @@ -92,50 +83,30 @@ class SCA_KeyboardSensor : public SCA_ISensor short int qual, short int qual2, bool bAllKeys, - const STR_String& targetProp, - const STR_String& toggleProp, + const std::string& targetProp, + const std::string& toggleProp, SCA_IObject* gameobj, short int exitKey); virtual ~SCA_KeyboardSensor(); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); virtual void Init(); - - short int GetHotkey(); virtual bool Evaluate(); virtual bool IsPositiveTrigger(); - bool TriggerOnAllKeys(); #ifdef WITH_PYTHON /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - // KeyEvents: - KX_PYMETHOD_DOC_NOARGS(SCA_KeyboardSensor,getEventList); - // KeyStatus: - KX_PYMETHOD_DOC_O(SCA_KeyboardSensor,getKeyStatus); - - static PyObject* pyattr_get_events(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + // KeyEvents: + EXP_PYMETHOD_DOC_NOARGS(SCA_KeyboardSensor,getEventList); + // KeyStatus: + EXP_PYMETHOD_DOC_O(SCA_KeyboardSensor,getKeyStatus); + + static PyObject* pyattr_get_events(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_inputs(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); #endif }; - -/** - * Transform keycodes to something printable. - */ -char ToCharacter(int keyIndex, bool shifted); - -/** - * Determine whether this character can be printed. We cannot use - * the library functions here, because we need to test our own - * keycodes. */ -bool IsPrintable(int keyIndex); - -/** - * Tests whether this is a delete key. - */ -bool IsDelete(int keyIndex); - - #endif /* __SCA_KEYBOARDSENSOR_H__ */ diff --git a/source/gameengine/GameLogic/SCA_LogicManager.cpp b/source/gameengine/GameLogic/SCA_LogicManager.cpp index 0913f576d00e..aa61e654a98b 100644 --- a/source/gameengine/GameLogic/SCA_LogicManager.cpp +++ b/source/gameengine/GameLogic/SCA_LogicManager.cpp @@ -37,8 +37,8 @@ #include "SCA_IActuator.h" #include "SCA_EventManager.h" #include "SCA_PythonController.h" -#include +#include "CM_Map.h" SCA_LogicManager::SCA_LogicManager() { @@ -48,110 +48,79 @@ SCA_LogicManager::SCA_LogicManager() SCA_LogicManager::~SCA_LogicManager() { - for (vector::iterator it = m_eventmanagers.begin();!(it==m_eventmanagers.end());++it) - { - delete (*it); - } - m_eventmanagers.clear(); - assert(m_activeActuators.Empty()); + BLI_assert(m_activeActuators.Empty()); } -#if 0 -// this kind of fixes bug 398 but breakes games, so better leave it out for now. -// a removed object's gameobject (and logicbricks and stuff) didn't get released -// because it was still in the m_mapStringToGameObjects map. -void SCA_LogicManager::RemoveGameObject(const STR_String& gameobjname) +void SCA_LogicManager::RegisterEventManager(SCA_EventManager *eventmgr) { - int numgameobj = m_mapStringToGameObjects.size(); - for (int i = 0; i < numgameobj; i++) - { - CValue** gameobjptr = m_mapStringToGameObjects.at(i); - assert(gameobjptr); - - if (gameobjptr) - { - if ((*gameobjptr)->GetName() == gameobjname) - (*gameobjptr)->Release(); - } - } - - m_mapStringToGameObjects.remove(gameobjname); + m_eventmanagers.emplace_back(eventmgr); } -#endif -void SCA_LogicManager::RegisterEventManager(SCA_EventManager* eventmgr) + +void SCA_LogicManager::RegisterGameObjectName(const std::string& gameobjname, + EXP_Value *gameobj) { - m_eventmanagers.push_back(eventmgr); + std::string mn = gameobjname; + m_mapStringToGameObjects[mn] = gameobj; } - - -void SCA_LogicManager::RegisterGameObjectName(const STR_String& gameobjname, - CValue* gameobj) +void SCA_LogicManager::UnregisterGameObjectName(const std::string& gameobjname) { - STR_HashedString mn = gameobjname; - m_mapStringToGameObjects.insert(mn,gameobj); + m_mapStringToGameObjects.erase(gameobjname); } - -void SCA_LogicManager::RegisterGameMeshName(const STR_String& gamemeshname, void* blendobj) +void SCA_LogicManager::RegisterGameMeshName(const std::string& gamemeshname, void *blendobj) { - STR_HashedString mn = gamemeshname; - m_map_gamemeshname_to_blendobj.insert(mn, blendobj); + std::string mn = gamemeshname; + m_map_gamemeshname_to_blendobj[mn] = blendobj; } -void SCA_LogicManager::RegisterGameObj(void* blendobj, CValue* gameobj) +void SCA_LogicManager::RegisterGameObj(void *blendobj, EXP_Value *gameobj) { - m_map_blendobj_to_gameobj.insert(CHashedPtr(blendobj), gameobj); + m_map_blendobj_to_gameobj[blendobj] = gameobj; } -void SCA_LogicManager::UnregisterGameObj(void* blendobj, CValue* gameobj) +void SCA_LogicManager::UnregisterGameObj(void *blendobj, EXP_Value *gameobj) { - void **obp = m_map_blendobj_to_gameobj[CHashedPtr(blendobj)]; - if (obp && (CValue*)(*obp) == gameobj) - m_map_blendobj_to_gameobj.remove(CHashedPtr(blendobj)); + std::map::iterator it = m_map_blendobj_to_gameobj.find(blendobj); + if (it != m_map_blendobj_to_gameobj.end() && it->second == gameobj) { + m_map_blendobj_to_gameobj.erase(it); + } } -CValue* SCA_LogicManager::GetGameObjectByName(const STR_String& gameobjname) +EXP_Value *SCA_LogicManager::GetGameObjectByName(const std::string& gameobjname) { - STR_HashedString mn = gameobjname; - CValue** gameptr = m_mapStringToGameObjects[mn]; - - if (gameptr) - return *gameptr; - - return NULL; + std::string mn = gameobjname; + return m_mapStringToGameObjects[mn]; } -CValue* SCA_LogicManager::FindGameObjByBlendObj(void* blendobj) +EXP_Value *SCA_LogicManager::FindGameObjByBlendObj(void *blendobj) { - void **obp= m_map_blendobj_to_gameobj[CHashedPtr(blendobj)]; - return obp?(CValue*)(*obp):NULL; + return m_map_blendobj_to_gameobj[blendobj]; } -void* SCA_LogicManager::FindBlendObjByGameMeshName(const STR_String& gamemeshname) +void *SCA_LogicManager::FindBlendObjByGameMeshName(const std::string& gamemeshname) { - STR_HashedString mn = gamemeshname; - void **obp= m_map_gamemeshname_to_blendobj[mn]; - return obp?*obp:NULL; + std::string mn = gamemeshname; + return m_map_gamemeshname_to_blendobj[mn]; } -void SCA_LogicManager::RemoveSensor(SCA_ISensor* sensor) +void SCA_LogicManager::RemoveSensor(SCA_ISensor *sensor) { sensor->UnlinkAllControllers(); sensor->UnregisterToManager(); } -void SCA_LogicManager::RemoveController(SCA_IController* controller) +void SCA_LogicManager::RemoveController(SCA_IController *controller) { controller->UnlinkAllSensors(); controller->UnlinkAllActuators(); @@ -159,7 +128,7 @@ void SCA_LogicManager::RemoveController(SCA_IController* controller) } -void SCA_LogicManager::RemoveActuator(SCA_IActuator* actuator) +void SCA_LogicManager::RemoveActuator(SCA_IActuator *actuator) { actuator->UnlinkAllControllers(); actuator->Deactivate(); @@ -168,7 +137,7 @@ void SCA_LogicManager::RemoveActuator(SCA_IActuator* actuator) -void SCA_LogicManager::RegisterToSensor(SCA_IController* controller,SCA_ISensor* sensor) +void SCA_LogicManager::RegisterToSensor(SCA_IController *controller, SCA_ISensor *sensor) { sensor->LinkToController(controller); controller->LinkToSensor(sensor); @@ -176,7 +145,7 @@ void SCA_LogicManager::RegisterToSensor(SCA_IController* controller,SCA_ISensor* -void SCA_LogicManager::RegisterToActuator(SCA_IController* controller,SCA_IActuator* actua) +void SCA_LogicManager::RegisterToActuator(SCA_IController *controller, SCA_IActuator *actua) { actua->LinkToController(controller); controller->LinkToActuator(actua); @@ -186,16 +155,17 @@ void SCA_LogicManager::RegisterToActuator(SCA_IController* controller,SCA_IActua void SCA_LogicManager::BeginFrame(double curtime, double fixedtime) { - for (vector::const_iterator ie=m_eventmanagers.begin(); !(ie==m_eventmanagers.end()); ie++) - (*ie)->NextFrame(curtime, fixedtime); + for (std::unique_ptr& mgr : m_eventmanagers) { + mgr->NextFrame(curtime, fixedtime); + } - for (SG_QList* obj = (SG_QList*)m_triggeredControllerSet.Remove(); - obj != NULL; - obj = (SG_QList*)m_triggeredControllerSet.Remove()) + for (SG_QList *obj = (SG_QList *)m_triggeredControllerSet.Remove(); + obj != nullptr; + obj = (SG_QList *)m_triggeredControllerSet.Remove()) { - for (SCA_IController* contr = (SCA_IController*)obj->QRemove(); - contr != NULL; - contr = (SCA_IController*)obj->QRemove()) + for (SCA_IController *contr = (SCA_IController *)obj->QRemove(); + contr != nullptr; + contr = (SCA_IController *)obj->QRemove()) { contr->Trigger(this); contr->ClrJustActivated(); @@ -205,30 +175,30 @@ void SCA_LogicManager::BeginFrame(double curtime, double fixedtime) -void SCA_LogicManager::UpdateFrame(double curtime, bool frame) +void SCA_LogicManager::UpdateFrame(double curtime) { - for (vector::const_iterator ie=m_eventmanagers.begin(); !(ie==m_eventmanagers.end()); ie++) - (*ie)->UpdateFrame(); + for (std::unique_ptr& mgr : m_eventmanagers) { + mgr->UpdateFrame(); + } SG_DList::iterator io(m_activeActuators); for (io.begin(); !io.end(); ) { - SG_QList* ahead = *io; + SG_QList *ahead = *io; // increment now so that we can remove the current element ++io; SG_QList::iterator ia(*ahead); - for (ia.begin(); !ia.end(); ) + for (ia.begin(); !ia.end(); ) { - SCA_IActuator* actua = *ia; + SCA_IActuator *actua = *ia; // increment first to allow removal of inactive actuators. ++ia; - if (!actua->Update(curtime, frame)) - { + if (!actua->Update(curtime)) { // this actuator is not active anymore, remove actua->QDelink(); actua->SetActive(false); - } else if (actua->IsNoLink()) - { + } + else if (actua->IsNoLink()) { // This actuator has no more links but it still active // make sure it will get a negative event on next frame to stop it // Do this check after Update() rather than before to make sure @@ -239,8 +209,7 @@ void SCA_LogicManager::UpdateFrame(double curtime, bool frame) actua->AddEvent(event); } } - if (ahead->QEmpty()) - { + if (ahead->QEmpty()) { // no more active controller, remove from main list ahead->Delink(); } @@ -249,64 +218,61 @@ void SCA_LogicManager::UpdateFrame(double curtime, bool frame) -void *SCA_LogicManager::GetActionByName(const STR_String& actname) +void *SCA_LogicManager::GetActionByName(const std::string& actname) { - STR_HashedString an = actname; - void** actptr = m_mapStringToActions[an]; - - if (actptr) - return *actptr; + const auto it = m_mapStringToActions.find(actname); + if (it != m_mapStringToActions.end()) { + return it->second; + } - return NULL; + return nullptr; } - - -void* SCA_LogicManager::GetMeshByName(const STR_String& meshname) +void *SCA_LogicManager::GetMeshByName(const std::string& meshname) { - STR_HashedString mn = meshname; - void** meshptr = m_mapStringToMeshes[mn]; - - if (meshptr) - return *meshptr; + const auto it = m_mapStringToMeshes.find(meshname); + if (it != m_mapStringToMeshes.end()) { + return it->second; + } - return NULL; + return nullptr; } - - -void SCA_LogicManager::RegisterMeshName(const STR_String& meshname,void* mesh) +void SCA_LogicManager::RegisterMeshName(const std::string& meshname, void *mesh) { - STR_HashedString mn = meshname; - m_mapStringToMeshes.insert(mn,mesh); + m_mapStringToMeshes[meshname] = mesh; } -void SCA_LogicManager::UnregisterMeshName(const STR_String& meshname,void* mesh) +void SCA_LogicManager::UnregisterMeshName(const std::string& meshname, void *mesh) { - STR_HashedString mn = meshname; - m_mapStringToMeshes.remove(mn); + m_mapStringToMeshes.erase(meshname); } - -void SCA_LogicManager::RegisterActionName(const STR_String& actname,void* action) +void SCA_LogicManager::UnregisterMesh(void *mesh) { - STR_HashedString an = actname; - m_mapStringToActions.insert(an, action); + CM_MapRemoveIfItemFound(m_mapStringToMeshes, mesh); } +void SCA_LogicManager::RegisterActionName(const std::string& actname, void *action) +{ + std::string an = actname; + m_mapStringToActions[an] = action; +} +void SCA_LogicManager::UnregisterAction(void *action) +{ + CM_MapRemoveIfItemFound(m_mapStringToActions, action); +} void SCA_LogicManager::EndFrame() { - for (vector::const_iterator ie=m_eventmanagers.begin(); - !(ie==m_eventmanagers.end());ie++) - { - (*ie)->EndFrame(); + for (std::unique_ptr& emgr : m_eventmanagers) { + emgr->EndFrame(); } } -void SCA_LogicManager::AddTriggeredController(SCA_IController* controller, SCA_ISensor* sensor) +void SCA_LogicManager::AddTriggeredController(SCA_IController *controller, SCA_ISensor *sensor) { controller->Activate(m_triggeredControllerSet); @@ -315,26 +281,21 @@ void SCA_LogicManager::AddTriggeredController(SCA_IController* controller, SCA_I // so that the controller knows which sensor has activited it // only needed for python controller // Note that this is safe even if the controller is subclassed. - if (controller->GetType() == &SCA_PythonController::Type) - { - SCA_PythonController* pythonController = (SCA_PythonController*)controller; + if (controller->GetType() == &SCA_PythonController::Type) { + SCA_PythonController *pythonController = (SCA_PythonController *)controller; pythonController->AddTriggeredSensor(sensor); } #endif } -SCA_EventManager* SCA_LogicManager::FindEventManager(int eventmgrtype) +SCA_EventManager *SCA_LogicManager::FindEventManager(int eventmgrtype) { // find an eventmanager of a certain type - SCA_EventManager* eventmgr = NULL; + SCA_EventManager *eventmgr = nullptr; - for (vector::const_iterator i= - m_eventmanagers.begin();!(i==m_eventmanagers.end());i++) - { - SCA_EventManager* emgr = *i; - if (emgr->GetType() == eventmgrtype) - { - eventmgr = emgr; + for (std::unique_ptr& emgr : m_eventmanagers) { + if (emgr->GetType() == eventmgrtype) { + eventmgr = emgr.get(); break; } } diff --git a/source/gameengine/GameLogic/SCA_LogicManager.h b/source/gameengine/GameLogic/SCA_LogicManager.h index 231af077c8e7..c4969a28208b 100644 --- a/source/gameengine/GameLogic/SCA_LogicManager.h +++ b/source/gameengine/GameLogic/SCA_LogicManager.h @@ -33,22 +33,16 @@ #ifdef _MSC_VER # pragma warning (disable:4786) -#endif +#endif #include -//#include "CTR_Map.h" -#include #include #include -#include "CTR_Map.h" -#include "STR_HashedString.h" +#include #include "EXP_Value.h" #include "SG_QList.h" -#include "EXP_HashedPtr.h" - -using namespace std; typedef std::list controllerlist; typedef std::map sensormap_t; @@ -69,11 +63,12 @@ typedef std::map sensormap_t; #include "SCA_IActuator.h" #include "SCA_EventManager.h" +#include class SCA_LogicManager { - vector m_eventmanagers; - + std::vector > m_eventmanagers; + // SG_DList: Head of objects having activated actuators // element: SCA_IObject::m_activeActuators SG_DList m_activeActuators; @@ -83,12 +78,12 @@ class SCA_LogicManager // need to find better way for this // also known as FactoryManager... - CTR_Map m_mapStringToGameObjects; - CTR_Map m_mapStringToMeshes; - CTR_Map m_mapStringToActions; + std::map m_mapStringToGameObjects; + std::map m_mapStringToMeshes; + std::map m_mapStringToActions; - CTR_Map m_map_gamemeshname_to_blendobj; - CTR_Map m_map_blendobj_to_gameobj; + std::map m_map_gamemeshname_to_blendobj; + std::map m_map_blendobj_to_gameobj; public: SCA_LogicManager(); virtual ~SCA_LogicManager(); @@ -99,9 +94,9 @@ class SCA_LogicManager class SCA_ISensor* sensor); void RegisterToActuator(SCA_IController* controller, class SCA_IActuator* actuator); - + void BeginFrame(double curtime, double fixedtime); - void UpdateFrame(double curtime, bool frame); + void UpdateFrame(double curtime); void EndFrame(); void AddActiveActuator(SCA_IActuator* actua,bool event) { @@ -112,9 +107,6 @@ class SCA_LogicManager void AddTriggeredController(SCA_IController* controller, SCA_ISensor* sensor); SCA_EventManager* FindEventManager(int eventmgrtype); - vector GetEventManagers() { return m_eventmanagers; } - - void RemoveGameObject(const STR_String& gameobjname); /** * remove Logic Bricks from the running logicmanager @@ -122,33 +114,29 @@ class SCA_LogicManager void RemoveSensor(SCA_ISensor* sensor); void RemoveController(SCA_IController* controller); void RemoveActuator(SCA_IActuator* actuator); - + // for the scripting... needs a FactoryManager later (if we would have time... ;) - void RegisterMeshName(const STR_String& meshname,void* mesh); - void UnregisterMeshName(const STR_String& meshname,void* mesh); - CTR_Map& GetMeshMap() { return m_mapStringToMeshes; } - CTR_Map& GetActionMap() { return m_mapStringToActions; } - - void RegisterActionName(const STR_String& actname,void* action); - - void* GetActionByName (const STR_String& actname); - void* GetMeshByName(const STR_String& meshname); + void RegisterMeshName(const std::string& meshname,void* mesh); + void UnregisterMeshName(const std::string& meshname,void* mesh); + void UnregisterMesh(void *mesh); - void RegisterGameObjectName(const STR_String& gameobjname,CValue* gameobj); - class CValue* GetGameObjectByName(const STR_String& gameobjname); + void RegisterActionName(const std::string& actname,void* action); + void UnregisterAction(void *action); - void RegisterGameMeshName(const STR_String& gamemeshname, void* blendobj); - void* FindBlendObjByGameMeshName(const STR_String& gamemeshname); + void* GetActionByName (const std::string& actname); + void* GetMeshByName(const std::string& meshname); - void RegisterGameObj(void* blendobj, CValue* gameobj); - void UnregisterGameObj(void* blendobj, CValue* gameobj); - CValue* FindGameObjByBlendObj(void* blendobj); + void RegisterGameObjectName(const std::string& gameobjname,EXP_Value* gameobj); + void UnregisterGameObjectName(const std::string& gameobjname); + class EXP_Value* GetGameObjectByName(const std::string& gameobjname); + void RegisterGameMeshName(const std::string& gamemeshname, void* blendobj); + void* FindBlendObjByGameMeshName(const std::string& gamemeshname); -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:SCA_LogicManager") -#endif + void RegisterGameObj(void* blendobj, EXP_Value* gameobj); + void UnregisterGameObj(void* blendobj, EXP_Value* gameobj); + EXP_Value* FindGameObjByBlendObj(void* blendobj); }; #endif /* __SCA_LOGICMANAGER_H__ */ diff --git a/source/gameengine/GameLogic/SCA_MouseManager.cpp b/source/gameengine/GameLogic/SCA_MouseManager.cpp index 1842b7a9ded7..8a6d00c37d17 100644 --- a/source/gameengine/GameLogic/SCA_MouseManager.cpp +++ b/source/gameengine/GameLogic/SCA_MouseManager.cpp @@ -35,8 +35,8 @@ #ifdef _MSC_VER - /* This warning tells us about truncation of __long__ stl-generated names. - * It can occasionally cause DevStudio to have internal compiler warnings. */ +/* 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 @@ -44,18 +44,13 @@ #include "SCA_MouseManager.h" #include "SCA_MouseSensor.h" #include "EXP_IntValue.h" -#include "RAS_ICanvas.h" -SCA_MouseManager::SCA_MouseManager(SCA_LogicManager* logicmgr, - SCA_IInputDevice* mousedev, - RAS_ICanvas* canvas) - : SCA_EventManager(logicmgr, MOUSE_EVENTMGR), - m_mousedevice (mousedev), - m_canvas(canvas) +SCA_MouseManager::SCA_MouseManager(SCA_LogicManager *logicmgr, + SCA_IInputDevice *mousedev) + :SCA_EventManager(logicmgr, MOUSE_EVENTMGR), + m_mousedevice(mousedev) { - m_xpos = 0; - m_ypos = 0; } @@ -66,7 +61,7 @@ SCA_MouseManager::~SCA_MouseManager() -SCA_IInputDevice* SCA_MouseManager::GetInputDevice() +SCA_IInputDevice *SCA_MouseManager::GetInputDevice() { return m_mousedevice; } @@ -75,23 +70,19 @@ SCA_IInputDevice* SCA_MouseManager::GetInputDevice() void SCA_MouseManager::NextFrame() { - if (m_mousedevice) - { - SG_DList::iterator it(m_sensors); - for (it.begin();!it.end();++it) - { - SCA_MouseSensor* mousesensor = (SCA_MouseSensor*)(*it); + if (m_mousedevice) { + for (SCA_ISensor *sensor : m_sensors) { + SCA_MouseSensor *mousesensor = static_cast(sensor); // (0,0) is the Upper Left corner in our local window // coordinates - if (!mousesensor->IsSuspended()) - { + if (!mousesensor->IsSuspended()) { const SCA_InputEvent& event1 = - m_mousedevice->GetEventValue(SCA_IInputDevice::KX_MOUSEX); + m_mousedevice->GetInput(SCA_IInputDevice::MOUSEX); const SCA_InputEvent& event2 = - m_mousedevice->GetEventValue(SCA_IInputDevice::KX_MOUSEY); + m_mousedevice->GetInput(SCA_IInputDevice::MOUSEY); - int mx = this->m_canvas->GetMouseX(event1.m_eventval); - int my = this->m_canvas->GetMouseY(event2.m_eventval); + int mx = event1.m_values[event1.m_values.size() - 1]; + int my = event2.m_values[event2.m_values.size() - 1]; mousesensor->setX(mx); mousesensor->setY(my); @@ -101,12 +92,3 @@ void SCA_MouseManager::NextFrame() } } } - -bool SCA_MouseManager::IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode) -{ - /* We should guard for non-mouse events maybe? A rather silly side */ - /* effect here is that position-change events are considered presses as */ - /* well. */ - - return m_mousedevice->IsPressed(inputcode); -} diff --git a/source/gameengine/GameLogic/SCA_MouseManager.h b/source/gameengine/GameLogic/SCA_MouseManager.h index de932584edea..e9ba5e24bd21 100644 --- a/source/gameengine/GameLogic/SCA_MouseManager.h +++ b/source/gameengine/GameLogic/SCA_MouseManager.h @@ -37,39 +37,19 @@ #include "SCA_EventManager.h" - -#include - -using namespace std; - #include "SCA_IInputDevice.h" class SCA_MouseManager : public SCA_EventManager { - class SCA_IInputDevice* m_mousedevice; - class RAS_ICanvas* m_canvas; - - unsigned short m_xpos; // Cached location of the mouse pointer - unsigned short m_ypos; public: - SCA_MouseManager(class SCA_LogicManager* logicmgr,class SCA_IInputDevice* mousedev, class RAS_ICanvas* canvas); + SCA_MouseManager(class SCA_LogicManager* logicmgr,class SCA_IInputDevice* mousedev); virtual ~SCA_MouseManager(); - /** - * Checks whether a mouse button is depressed. Ignores requests on non- - * mouse related events. Can also flag mouse movement. - */ - bool IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode); virtual void NextFrame(); SCA_IInputDevice* GetInputDevice(); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:SCA_MouseManager") -#endif }; #endif /* __SCA_MOUSEMANAGER_H__ */ diff --git a/source/gameengine/GameLogic/SCA_MouseSensor.cpp b/source/gameengine/GameLogic/SCA_MouseSensor.cpp index c1ad1c4543a7..f7584ad93b1b 100644 --- a/source/gameengine/GameLogic/SCA_MouseSensor.cpp +++ b/source/gameengine/GameLogic/SCA_MouseSensor.cpp @@ -48,24 +48,23 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_MouseSensor::SCA_MouseSensor(SCA_MouseManager* eventmgr, - int startx,int starty, +SCA_MouseSensor::SCA_MouseSensor(SCA_MouseManager *eventmgr, + int startx, int starty, short int mousemode, - SCA_IObject* gameobj) - : SCA_ISensor(gameobj,eventmgr), - m_x(startx), - m_y(starty) + SCA_IObject *gameobj) + :SCA_ISensor(gameobj, eventmgr), + m_x(startx), + m_y(starty) { m_mousemode = mousemode; m_triggermode = true; - UpdateHotkey(this); Init(); } void SCA_MouseSensor::Init() { - m_val = (m_invert)?1:0; /* stores the latest attribute */ + m_val = (m_invert) ? 1 : 0; /* stores the latest attribute */ m_reset = true; } @@ -74,39 +73,9 @@ SCA_MouseSensor::~SCA_MouseSensor() /* Nothing to be done here. */ } -void SCA_MouseSensor::UpdateHotkey(void *self) +EXP_Value *SCA_MouseSensor::GetReplica() { - // gosh, this function is so damn stupid - // its here because of a design mistake in the mouse sensor, it should only - // have 3 trigger modes (button, wheel, move), and let the user set the - // hotkey separately, like the other sensors. but instead it has a mode for - // each friggin key and i have to update the hotkey based on it... genius! - SCA_MouseSensor* sensor = reinterpret_cast(self); - - switch (sensor->m_mousemode) { - case KX_MOUSESENSORMODE_LEFTBUTTON: - sensor->m_hotkey = SCA_IInputDevice::KX_LEFTMOUSE; - break; - case KX_MOUSESENSORMODE_MIDDLEBUTTON: - sensor->m_hotkey = SCA_IInputDevice::KX_MIDDLEMOUSE; - break; - case KX_MOUSESENSORMODE_RIGHTBUTTON: - sensor->m_hotkey = SCA_IInputDevice::KX_RIGHTMOUSE; - break; - case KX_MOUSESENSORMODE_WHEELUP: - sensor->m_hotkey = SCA_IInputDevice::KX_WHEELUPMOUSE; - break; - case KX_MOUSESENSORMODE_WHEELDOWN: - sensor->m_hotkey = SCA_IInputDevice::KX_WHEELDOWNMOUSE; - break; - default: - ; /* ignore, no hotkey */ - } -} - -CValue* SCA_MouseSensor::GetReplica() -{ - SCA_MouseSensor* replica = new SCA_MouseSensor(*this); + SCA_MouseSensor *replica = new SCA_MouseSensor(*this); // this will copy properties and so on... replica->ProcessReplica(); replica->Init(); @@ -119,107 +88,72 @@ CValue* SCA_MouseSensor::GetReplica() bool SCA_MouseSensor::IsPositiveTrigger() { bool result = (m_val != 0); - if (m_invert) + if (m_invert) { result = !result; + } return result; } - - -short int SCA_MouseSensor::GetModeKey() -{ - return m_mousemode; -} - - - -SCA_IInputDevice::KX_EnumInputs SCA_MouseSensor::GetHotKey() -{ - return m_hotkey; -} - - - bool SCA_MouseSensor::Evaluate() { bool result = false; bool reset = m_reset && m_level; - SCA_IInputDevice* mousedev = ((SCA_MouseManager *)m_eventmgr)->GetInputDevice(); + int previousval = m_val; + SCA_IInputDevice *mousedev = ((SCA_MouseManager *)m_eventmgr)->GetInputDevice(); m_reset = false; switch (m_mousemode) { - case KX_MOUSESENSORMODE_LEFTBUTTON: - case KX_MOUSESENSORMODE_MIDDLEBUTTON: - case KX_MOUSESENSORMODE_RIGHTBUTTON: - case KX_MOUSESENSORMODE_WHEELUP: - case KX_MOUSESENSORMODE_WHEELDOWN: + case KX_MOUSESENSORMODE_LEFTBUTTON: + case KX_MOUSESENSORMODE_MIDDLEBUTTON: + case KX_MOUSESENSORMODE_RIGHTBUTTON: + case KX_MOUSESENSORMODE_WHEELUP: + case KX_MOUSESENSORMODE_WHEELDOWN: { - const SCA_InputEvent& mevent = mousedev->GetEventValue(m_hotkey); - switch (mevent.m_status) { - case SCA_InputEvent::KX_JUSTACTIVATED: + static const SCA_IInputDevice::SCA_EnumInputs convertTable[KX_MOUSESENSORMODE_MAX] = { + SCA_IInputDevice::NOKEY, // KX_MOUSESENSORMODE_NODEF + SCA_IInputDevice::LEFTMOUSE, // KX_MOUSESENSORMODE_LEFTBUTTON + SCA_IInputDevice::MIDDLEMOUSE, // KX_MOUSESENSORMODE_MIDDLEBUTTON + SCA_IInputDevice::RIGHTMOUSE, // KX_MOUSESENSORMODE_RIGHTBUTTON + SCA_IInputDevice::WHEELUPMOUSE, // KX_MOUSESENSORMODE_WHEELUP + SCA_IInputDevice::WHEELDOWNMOUSE // KX_MOUSESENSORMODE_WHEELDOWN + }; + + const SCA_InputEvent& mevent = mousedev->GetInput(convertTable[m_mousemode]); + if (mevent.Find(SCA_InputEvent::ACTIVE)) { m_val = 1; - result = true; - break; - case SCA_InputEvent::KX_JUSTRELEASED: + } + else { m_val = 0; - result = true; - break; - case SCA_InputEvent::KX_ACTIVE: - if (m_val == 0) - { - m_val = 1; - if (m_level) - result = true; - } - break; - default: - if (m_val == 1) - { - m_val = 0; - result = true; - } - break; } break; } - case KX_MOUSESENSORMODE_MOVEMENT: + case KX_MOUSESENSORMODE_MOVEMENT: { - const SCA_InputEvent& eventX = mousedev->GetEventValue(SCA_IInputDevice::KX_MOUSEX); - const SCA_InputEvent& eventY = mousedev->GetEventValue(SCA_IInputDevice::KX_MOUSEY); - - if (eventX.m_status == SCA_InputEvent::KX_JUSTACTIVATED || - eventY.m_status == SCA_InputEvent::KX_JUSTACTIVATED || - eventX.m_status == SCA_InputEvent::KX_ACTIVE || - eventY.m_status == SCA_InputEvent::KX_ACTIVE) - { + const SCA_InputEvent& eventX = mousedev->GetInput(SCA_IInputDevice::MOUSEX); + const SCA_InputEvent& eventY = mousedev->GetInput(SCA_IInputDevice::MOUSEY); + + if (eventX.Find(SCA_InputEvent::ACTIVE) || eventY.Find(SCA_InputEvent::ACTIVE)) { m_val = 1; result = true; } - else if (eventX.m_status == SCA_InputEvent::KX_JUSTRELEASED || - eventY.m_status == SCA_InputEvent::KX_JUSTRELEASED ) - { + else { m_val = 0; - result = true; - } - else //KX_NO_IMPUTSTATUS - { - if (m_val == 1) - { - m_val = 0; - result = true; - } } - break; } - default: - ; /* error */ + default: + ; /* error */ + } + + if (previousval != m_val) { + result = true; } - if (reset) + if (reset) { // force an event result = true; + } return result; } @@ -233,35 +167,30 @@ void SCA_MouseSensor::setY(short y) m_y = y; } -bool SCA_MouseSensor::isValid(SCA_MouseSensor::KX_MOUSESENSORMODE m) -{ - return ((m > KX_MOUSESENSORMODE_NODEF) && (m < KX_MOUSESENSORMODE_MAX)); -} - #ifdef WITH_PYTHON /* ------------------------------------------------------------------------- */ /* Python functions */ /* ------------------------------------------------------------------------- */ -KX_PYMETHODDEF_DOC_O(SCA_MouseSensor, getButtonStatus, -"getButtonStatus(button)\n" -"\tGet the given button's status (KX_INPUT_NONE, KX_INPUT_NONE, KX_INPUT_JUST_ACTIVATED, KX_INPUT_ACTIVE, KX_INPUT_JUST_RELEASED).\n") +EXP_PYMETHODDEF_DOC_O(SCA_MouseSensor, getButtonStatus, + "getButtonStatus(button)\n" + "\tGet the given button's status (KX_INPUT_NONE, KX_INPUT_NONE, KX_INPUT_JUST_ACTIVATED, KX_INPUT_ACTIVE, KX_INPUT_JUST_RELEASED).\n") { - if (PyLong_Check(value)) - { - SCA_IInputDevice::KX_EnumInputs button = (SCA_IInputDevice::KX_EnumInputs)PyLong_AsLong(value); + EXP_ShowDeprecationWarning("sensor.getButtonStatus(button)", "logic.mouse.events[button]"); - if ((button < SCA_IInputDevice::KX_LEFTMOUSE) || - (button > SCA_IInputDevice::KX_RIGHTMOUSE)) - { + if (PyLong_Check(value)) { + SCA_IInputDevice::SCA_EnumInputs button = (SCA_IInputDevice::SCA_EnumInputs)PyLong_AsLong(value); + + if ((button < SCA_IInputDevice::LEFTMOUSE) || + (button > SCA_IInputDevice::RIGHTMOUSE)) { PyErr_SetString(PyExc_ValueError, "sensor.getButtonStatus(int): Mouse Sensor, invalid button specified!"); - return NULL; + return nullptr; } - SCA_IInputDevice* mousedev = ((SCA_MouseManager *)m_eventmgr)->GetInputDevice(); - const SCA_InputEvent& event = mousedev->GetEventValue(button); - return PyLong_FromLong(event.m_status); + SCA_IInputDevice *mousedev = ((SCA_MouseManager *)m_eventmgr)->GetInputDevice(); + const SCA_InputEvent& event = mousedev->GetInput(button); + return PyLong_FromLong(event.m_status[event.m_status.size() - 1]); } Py_RETURN_NONE; @@ -272,9 +201,9 @@ KX_PYMETHODDEF_DOC_O(SCA_MouseSensor, getButtonStatus, /* ------------------------------------------------------------------------- */ PyTypeObject SCA_MouseSensor::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_MouseSensor", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -282,34 +211,26 @@ PyTypeObject SCA_MouseSensor::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_ISensor::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_MouseSensor::Methods[] = { - KX_PYMETHODTABLE_O(SCA_MouseSensor, getButtonStatus), - {NULL,NULL} //Sentinel + EXP_PYMETHODTABLE_O(SCA_MouseSensor, getButtonStatus), + {nullptr, nullptr} //Sentinel }; -int SCA_MouseSensor::UpdateHotkeyPy(void *self, const PyAttributeDef*) -{ - UpdateHotkey(self); - // return value is used in py_setattro(), - // 0=attribute checked ok (see Attributes array definition) - return 0; -} - PyAttributeDef SCA_MouseSensor::Attributes[] = { - KX_PYATTRIBUTE_SHORT_RW_CHECK("mode",KX_MOUSESENSORMODE_NODEF,KX_MOUSESENSORMODE_MAX-1,true,SCA_MouseSensor,m_mousemode,UpdateHotkeyPy), - KX_PYATTRIBUTE_SHORT_LIST_RO("position",SCA_MouseSensor,m_x,2), - { NULL } //Sentinel + EXP_PYATTRIBUTE_SHORT_RW("mode", KX_MOUSESENSORMODE_NODEF, KX_MOUSESENSORMODE_MAX - 1, true, SCA_MouseSensor, m_mousemode), + EXP_PYATTRIBUTE_SHORT_LIST_RO("position", SCA_MouseSensor, m_x, 2), + EXP_PYATTRIBUTE_NULL //Sentinel }; #endif // WITH_PYTHON diff --git a/source/gameengine/GameLogic/SCA_MouseSensor.h b/source/gameengine/GameLogic/SCA_MouseSensor.h index 53785fa40daf..cf520e5ee220 100644 --- a/source/gameengine/GameLogic/SCA_MouseSensor.h +++ b/source/gameengine/GameLogic/SCA_MouseSensor.h @@ -40,7 +40,7 @@ class SCA_MouseSensor : public SCA_ISensor { Py_Header - + /** * Use SCA_IInputDevice values to encode the mouse mode for now. */ @@ -51,12 +51,12 @@ class SCA_MouseSensor : public SCA_ISensor */ bool m_triggermode; /** - * Remember the last state update + * Remember the last state update */ int m_val; - SCA_IInputDevice::KX_EnumInputs m_hotkey; - + SCA_IInputDevice::SCA_EnumInputs m_hotkey; + /** * valid x coordinate, MUST be followed by y coordinate */ @@ -66,7 +66,7 @@ class SCA_MouseSensor : public SCA_ISensor * valid y coordinate */ short m_y; - + public: /** * Allowable modes for the trigger status of the mouse sensor. @@ -78,42 +78,30 @@ class SCA_MouseSensor : public SCA_ISensor KX_MOUSESENSORMODE_RIGHTBUTTON, KX_MOUSESENSORMODE_WHEELUP, KX_MOUSESENSORMODE_WHEELDOWN, - KX_MOUSESENSORMODE_POSITION, - KX_MOUSESENSORMODE_POSITIONX, - KX_MOUSESENSORMODE_POSITIONY, KX_MOUSESENSORMODE_MOVEMENT, KX_MOUSESENSORMODE_MAX }; - bool isValid(KX_MOUSESENSORMODE); - SCA_MouseSensor(class SCA_MouseManager* keybdmgr, int startx,int starty, short int mousemode, SCA_IObject* gameobj); virtual ~SCA_MouseSensor(); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); virtual bool Evaluate(); virtual void Init(); virtual bool IsPositiveTrigger(); - short int GetModeKey(); - SCA_IInputDevice::KX_EnumInputs GetHotKey(); void setX(short x); void setY(short y); - static void UpdateHotkey(void *self); - - #ifdef WITH_PYTHON /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - static int UpdateHotkeyPy(void *self, const PyAttributeDef *); - // get button status - KX_PYMETHOD_DOC_O(SCA_MouseSensor,getButtonStatus); + EXP_PYMETHOD_DOC_O(SCA_MouseSensor,getButtonStatus); #endif }; diff --git a/source/gameengine/GameLogic/SCA_NANDController.cpp b/source/gameengine/GameLogic/SCA_NANDController.cpp index ce98c8a5d7c5..279ab3df3931 100644 --- a/source/gameengine/GameLogic/SCA_NANDController.cpp +++ b/source/gameengine/GameLogic/SCA_NANDController.cpp @@ -42,7 +42,7 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_NANDController::SCA_NANDController(SCA_IObject* gameobj) +SCA_NANDController::SCA_NANDController(SCA_IObject *gameobj) : SCA_IController(gameobj) { @@ -56,35 +56,28 @@ SCA_NANDController::~SCA_NANDController() -void SCA_NANDController::Trigger(SCA_LogicManager* logicmgr) +void SCA_NANDController::Trigger(SCA_LogicManager *logicmgr) { bool sensorresult = false; - for (vector::const_iterator is=m_linkedsensors.begin(); - !(is==m_linkedsensors.end());is++) - { - SCA_ISensor* sensor = *is; - if (!sensor->GetState()) - { + for (SCA_ISensor *sensor : m_linkedsensors) { + if (!sensor->GetState()) { sensorresult = true; break; } } - for (vector::const_iterator i=m_linkedactuators.begin(); - !(i==m_linkedactuators.end());i++) - { - SCA_IActuator* actua = *i; - logicmgr->AddActiveActuator(actua,sensorresult); + for (SCA_IActuator *actuator : m_linkedactuators) { + logicmgr->AddActiveActuator(actuator, sensorresult); } } -CValue* SCA_NANDController::GetReplica() +EXP_Value *SCA_NANDController::GetReplica() { - CValue* replica = new SCA_NANDController(*this); + EXP_Value *replica = new SCA_NANDController(*this); // this will copy properties and so on... replica->ProcessReplica(); @@ -99,9 +92,9 @@ CValue* SCA_NANDController::GetReplica() /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_NANDController::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_NANDController", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -109,23 +102,23 @@ PyTypeObject SCA_NANDController::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IController::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_NANDController::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef SCA_NANDController::Attributes[] = { - { NULL } //Sentinel + EXP_PYATTRIBUTE_NULL //Sentinel }; #endif diff --git a/source/gameengine/GameLogic/SCA_NANDController.h b/source/gameengine/GameLogic/SCA_NANDController.h index a3f02908dd2d..9087bfaafa8d 100644 --- a/source/gameengine/GameLogic/SCA_NANDController.h +++ b/source/gameengine/GameLogic/SCA_NANDController.h @@ -41,7 +41,7 @@ class SCA_NANDController : public SCA_IController public: SCA_NANDController(SCA_IObject* gameobj); virtual ~SCA_NANDController(); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); virtual void Trigger(SCA_LogicManager* logicmgr); /* --------------------------------------------------------------------- */ diff --git a/source/gameengine/GameLogic/SCA_NORController.cpp b/source/gameengine/GameLogic/SCA_NORController.cpp index 16a82a6d23ee..158775faa5c5 100644 --- a/source/gameengine/GameLogic/SCA_NORController.cpp +++ b/source/gameengine/GameLogic/SCA_NORController.cpp @@ -42,7 +42,7 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_NORController::SCA_NORController(SCA_IObject* gameobj) +SCA_NORController::SCA_NORController(SCA_IObject *gameobj) : SCA_IController(gameobj) { @@ -56,35 +56,28 @@ SCA_NORController::~SCA_NORController() -void SCA_NORController::Trigger(SCA_LogicManager* logicmgr) +void SCA_NORController::Trigger(SCA_LogicManager *logicmgr) { bool sensorresult = true; - for (vector::const_iterator is=m_linkedsensors.begin(); - !(is==m_linkedsensors.end());is++) - { - SCA_ISensor* sensor = *is; - if (sensor->GetState()) - { + for (SCA_ISensor *sensor : m_linkedsensors) { + if (sensor->GetState()) { sensorresult = false; break; } } - for (vector::const_iterator i=m_linkedactuators.begin(); - !(i==m_linkedactuators.end());i++) - { - SCA_IActuator* actua = *i; - logicmgr->AddActiveActuator(actua,sensorresult); + for (SCA_IActuator *actuator : m_linkedactuators) { + logicmgr->AddActiveActuator(actuator, sensorresult); } } -CValue* SCA_NORController::GetReplica() +EXP_Value *SCA_NORController::GetReplica() { - CValue* replica = new SCA_NORController(*this); + EXP_Value *replica = new SCA_NORController(*this); // this will copy properties and so on... replica->ProcessReplica(); @@ -99,9 +92,9 @@ CValue* SCA_NORController::GetReplica() /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_NORController::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_NORController", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -109,23 +102,23 @@ PyTypeObject SCA_NORController::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IController::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_NORController::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef SCA_NORController::Attributes[] = { - { NULL } //Sentinel + EXP_PYATTRIBUTE_NULL //Sentinel }; #endif // WITH_PYTHON diff --git a/source/gameengine/GameLogic/SCA_NORController.h b/source/gameengine/GameLogic/SCA_NORController.h index ec8159de8d1e..06941a60ee6d 100644 --- a/source/gameengine/GameLogic/SCA_NORController.h +++ b/source/gameengine/GameLogic/SCA_NORController.h @@ -41,7 +41,7 @@ class SCA_NORController : public SCA_IController public: SCA_NORController(SCA_IObject* gameobj); virtual ~SCA_NORController(); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); virtual void Trigger(SCA_LogicManager* logicmgr); }; diff --git a/source/gameengine/GameLogic/SCA_ORController.cpp b/source/gameengine/GameLogic/SCA_ORController.cpp index f758c096cc0a..09496de0d244 100644 --- a/source/gameengine/GameLogic/SCA_ORController.cpp +++ b/source/gameengine/GameLogic/SCA_ORController.cpp @@ -42,8 +42,8 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_ORController::SCA_ORController(SCA_IObject* gameobj) - :SCA_IController(gameobj) +SCA_ORController::SCA_ORController(SCA_IObject *gameobj) + :SCA_IController(gameobj) { } @@ -55,9 +55,9 @@ SCA_ORController::~SCA_ORController() -CValue* SCA_ORController::GetReplica() +EXP_Value *SCA_ORController::GetReplica() { - CValue* replica = new SCA_ORController(*this); + EXP_Value *replica = new SCA_ORController(*this); // this will copy properties and so on... replica->ProcessReplica(); @@ -65,25 +65,19 @@ CValue* SCA_ORController::GetReplica() } -void SCA_ORController::Trigger(SCA_LogicManager* logicmgr) +void SCA_ORController::Trigger(SCA_LogicManager *logicmgr) { bool sensorresult = false; - SCA_ISensor* sensor; - - vector::const_iterator is=m_linkedsensors.begin(); - while ( (!sensorresult) && (!(is==m_linkedsensors.end())) ) - { - sensor = *is; - if (sensor->GetState()) sensorresult = true; - is++; + + for (SCA_ISensor *sensor : m_linkedsensors) { + if (sensor->GetState()) { + sensorresult = true; + } } - for (vector::const_iterator i=m_linkedactuators.begin(); - !(i==m_linkedactuators.end());i++) - { - SCA_IActuator* actua = *i; - logicmgr->AddActiveActuator(actua,sensorresult); + for (SCA_IActuator *actuator : m_linkedactuators) { + logicmgr->AddActiveActuator(actuator, sensorresult); } } @@ -95,9 +89,9 @@ void SCA_ORController::Trigger(SCA_LogicManager* logicmgr) /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_ORController::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_ORController", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -105,23 +99,23 @@ PyTypeObject SCA_ORController::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IController::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_ORController::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef SCA_ORController::Attributes[] = { - { NULL } //Sentinel + EXP_PYATTRIBUTE_NULL //Sentinel }; #endif // WITH_PYTHON diff --git a/source/gameengine/GameLogic/SCA_ORController.h b/source/gameengine/GameLogic/SCA_ORController.h index 9499c893c724..acdd72fbd9a7 100644 --- a/source/gameengine/GameLogic/SCA_ORController.h +++ b/source/gameengine/GameLogic/SCA_ORController.h @@ -42,7 +42,7 @@ class SCA_ORController : public SCA_IController SCA_ORController(SCA_IObject* gameobj); virtual ~SCA_ORController(); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); virtual void Trigger(SCA_LogicManager* logicmgr); }; diff --git a/source/gameengine/GameLogic/SCA_PropertyActuator.cpp b/source/gameengine/GameLogic/SCA_PropertyActuator.cpp index 87b0503ede81..ab4b10ece617 100644 --- a/source/gameengine/GameLogic/SCA_PropertyActuator.cpp +++ b/source/gameengine/GameLogic/SCA_PropertyActuator.cpp @@ -44,8 +44,8 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_PropertyActuator::SCA_PropertyActuator(SCA_IObject* gameobj,SCA_IObject* sourceObj,const STR_String& propname,const STR_String& expr,int acttype) - : SCA_IActuator(gameobj, KX_ACT_PROPERTY), +SCA_PropertyActuator::SCA_PropertyActuator(SCA_IObject *gameobj, SCA_IObject *sourceObj, const std::string& propname, const std::string& expr, int acttype) + :SCA_IActuator(gameobj, KX_ACT_PROPERTY), m_type(acttype), m_propname(propname), m_exprtxt(expr), @@ -53,14 +53,16 @@ SCA_PropertyActuator::SCA_PropertyActuator(SCA_IObject* gameobj,SCA_IObject* sou { // protect ourselves against someone else deleting the source object // don't protect against ourselves: it would create a dead lock - if (m_sourceObj) + if (m_sourceObj) { m_sourceObj->RegisterActuator(this); + } } SCA_PropertyActuator::~SCA_PropertyActuator() { - if (m_sourceObj) + if (m_sourceObj) { m_sourceObj->UnregisterActuator(this); + } } bool SCA_PropertyActuator::Update() @@ -69,16 +71,13 @@ bool SCA_PropertyActuator::Update() bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); - CValue* propowner = GetParent(); - - if (bNegativeEvent) - { - if (m_type==KX_ACT_PROP_LEVEL) - { - CValue* newval = new CBoolValue(false); - CValue* oldprop = propowner->GetProperty(m_propname); - if (oldprop) - { + EXP_Value *propowner = GetParent(); + + if (bNegativeEvent) { + if (m_type == KX_ACT_PROP_LEVEL) { + EXP_Value *newval = new EXP_BoolValue(false); + EXP_Value *oldprop = propowner->GetProperty(m_propname); + if (oldprop) { oldprop->SetValue(newval); } newval->Release(); @@ -87,69 +86,62 @@ bool SCA_PropertyActuator::Update() } - CParser parser; - parser.SetContext( propowner->AddRef()); + EXP_Parser parser; + parser.SetContext(propowner->AddRef()); - CExpression* userexpr= NULL; + EXP_Expression *userexpr = nullptr; - if (m_type==KX_ACT_PROP_TOGGLE) - { + if (m_type == KX_ACT_PROP_TOGGLE) { /* don't use */ - CValue* newval; - CValue* oldprop = propowner->GetProperty(m_propname); - if (oldprop) - { - newval = new CBoolValue((oldprop->GetNumber()==0.0) ? true:false); + EXP_Value *newval; + EXP_Value *oldprop = propowner->GetProperty(m_propname); + if (oldprop) { + newval = new EXP_BoolValue((oldprop->GetNumber() == 0.0) ? true : false); oldprop->SetValue(newval); - } else - { /* as not been assigned, evaluate as false, so assign true */ - newval = new CBoolValue(true); - propowner->SetProperty(m_propname,newval); + } + else { /* as not been assigned, evaluate as false, so assign true */ + newval = new EXP_BoolValue(true); + propowner->SetProperty(m_propname, newval); } newval->Release(); } - else if (m_type==KX_ACT_PROP_LEVEL) - { - CValue* newval = new CBoolValue(true); - CValue* oldprop = propowner->GetProperty(m_propname); - if (oldprop) - { + else if (m_type == KX_ACT_PROP_LEVEL) { + EXP_Value *newval = new EXP_BoolValue(true); + EXP_Value *oldprop = propowner->GetProperty(m_propname); + if (oldprop) { oldprop->SetValue(newval); - } else - { - propowner->SetProperty(m_propname,newval); + } + else { + propowner->SetProperty(m_propname, newval); } newval->Release(); } else if ((userexpr = parser.ProcessText(m_exprtxt))) { - switch (m_type) - { + switch (m_type) { - case KX_ACT_PROP_ASSIGN: + case KX_ACT_PROP_ASSIGN: { - CValue* newval = userexpr->Calculate(); - CValue* oldprop = propowner->GetProperty(m_propname); - if (oldprop) - { + EXP_Value *newval = userexpr->Calculate(); + EXP_Value *oldprop = propowner->GetProperty(m_propname); + if (oldprop) { oldprop->SetValue(newval); - } else - { - propowner->SetProperty(m_propname,newval); + } + else { + propowner->SetProperty(m_propname, newval); } newval->Release(); break; } - case KX_ACT_PROP_ADD: + case KX_ACT_PROP_ADD: { - CValue* oldprop = propowner->GetProperty(m_propname); - if (oldprop) - { + EXP_Value *oldprop = propowner->GetProperty(m_propname); + if (oldprop) { // int waarde = (int)oldprop->GetNumber(); /*unused*/ - CExpression* expr = new COperator2Expr(VALUE_ADD_OPERATOR,new CConstExpr(oldprop->AddRef()), - userexpr->AddRef()); + EXP_Expression *expr = new EXP_Operator2Expr(VALUE_ADD_OPERATOR, new EXP_ConstExpr(oldprop->AddRef()), + userexpr->AddRef()); - CValue* newprop = expr->Calculate(); + EXP_Value *newprop = expr->Calculate(); oldprop->SetValue(newprop); newprop->Release(); expr->Release(); @@ -158,25 +150,23 @@ bool SCA_PropertyActuator::Update() break; } - case KX_ACT_PROP_COPY: + case KX_ACT_PROP_COPY: { - if (m_sourceObj) - { - CValue* copyprop = m_sourceObj->GetProperty(m_exprtxt); - if (copyprop) - { - CValue *val = copyprop->GetReplica(); + if (m_sourceObj) { + EXP_Value *copyprop = m_sourceObj->GetProperty(m_exprtxt); + if (copyprop) { + EXP_Value *val = copyprop->GetReplica(); GetParent()->SetProperty( - m_propname, - val); + m_propname, + val); val->Release(); } } break; } - /* case KX_ACT_PROP_TOGGLE: */ /* accounted for above, no need for userexpr */ - default: + /* case KX_ACT_PROP_TOGGLE: */ /* accounted for above, no need for userexpr */ + default: { } @@ -188,29 +178,10 @@ bool SCA_PropertyActuator::Update() return result; } - bool - -SCA_PropertyActuator:: - -isValid( - - SCA_PropertyActuator::KX_ACT_PROP_MODE mode - -) { - bool res = false; - res = ((mode > KX_ACT_PROP_NODEF) && (mode < KX_ACT_PROP_MAX)); - return res; -} - - - CValue* - -SCA_PropertyActuator:: - -GetReplica() +EXP_Value *SCA_PropertyActuator::GetReplica() { - SCA_PropertyActuator* replica = new SCA_PropertyActuator(*this); + SCA_PropertyActuator *replica = new SCA_PropertyActuator(*this); replica->ProcessReplica(); return replica; @@ -221,29 +192,30 @@ void SCA_PropertyActuator::ProcessReplica() { // no need to check for self reference like in the constructor: // the replica will always have a different parent - if (m_sourceObj) + if (m_sourceObj) { m_sourceObj->RegisterActuator(this); + } SCA_IActuator::ProcessReplica(); } -bool SCA_PropertyActuator::UnlinkObject(SCA_IObject* clientobj) +bool SCA_PropertyActuator::UnlinkObject(SCA_IObject *clientobj) { - if (clientobj == m_sourceObj) - { + if (clientobj == m_sourceObj) { // this object is being deleted, we cannot continue to track it. - m_sourceObj = NULL; + m_sourceObj = nullptr; return true; } return false; } -void SCA_PropertyActuator::Relink(CTR_Map *obj_map) +void SCA_PropertyActuator::Relink(std::map& obj_map) { - void **h_obj = (*obj_map)[m_sourceObj]; - if (h_obj) { - if (m_sourceObj) + SCA_IObject *obj = obj_map[m_sourceObj]; + if (obj) { + if (m_sourceObj) { m_sourceObj->UnregisterActuator(this); - m_sourceObj = (SCA_IObject*)(*h_obj); + } + m_sourceObj = obj; m_sourceObj->RegisterActuator(this); } } @@ -256,9 +228,9 @@ void SCA_PropertyActuator::Relink(CTR_Map *obj_map) /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_PropertyActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_PropertyActuator", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -266,26 +238,26 @@ PyTypeObject SCA_PropertyActuator::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IActuator::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_PropertyActuator::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef SCA_PropertyActuator::Attributes[] = { - KX_PYATTRIBUTE_STRING_RW_CHECK("propName",0,MAX_PROP_NAME,false,SCA_PropertyActuator,m_propname,CheckProperty), - KX_PYATTRIBUTE_STRING_RW("value",0,100,false,SCA_PropertyActuator,m_exprtxt), - KX_PYATTRIBUTE_INT_RW("mode", KX_ACT_PROP_NODEF+1, KX_ACT_PROP_MAX-1, false, SCA_PropertyActuator, m_type), /* ATTR_TODO add constents to game logic dict */ - { NULL } //Sentinel + EXP_PYATTRIBUTE_STRING_RW_CHECK("propName", 0, MAX_PROP_NAME, false, SCA_PropertyActuator, m_propname, CheckProperty), + EXP_PYATTRIBUTE_STRING_RW("value", 0, 100, false, SCA_PropertyActuator, m_exprtxt), + EXP_PYATTRIBUTE_INT_RW("mode", KX_ACT_PROP_NODEF + 1, KX_ACT_PROP_MAX - 1, false, SCA_PropertyActuator, m_type), /* ATTR_TODO add constents to game logic dict */ + EXP_PYATTRIBUTE_NULL //Sentinel }; #endif diff --git a/source/gameengine/GameLogic/SCA_PropertyActuator.h b/source/gameengine/GameLogic/SCA_PropertyActuator.h index 57483bd0e057..3c3026f0e876 100644 --- a/source/gameengine/GameLogic/SCA_PropertyActuator.h +++ b/source/gameengine/GameLogic/SCA_PropertyActuator.h @@ -37,7 +37,7 @@ class SCA_PropertyActuator : public SCA_IActuator { Py_Header - + enum KX_ACT_PROP_MODE { KX_ACT_PROP_NODEF = 0, KX_ACT_PROP_ASSIGN, @@ -48,12 +48,9 @@ class SCA_PropertyActuator : public SCA_IActuator KX_ACT_PROP_MAX }; - /**check whether this value is valid */ - bool isValid(KX_ACT_PROP_MODE mode); - int m_type; - STR_String m_propname; - STR_String m_exprtxt; + std::string m_propname; + std::string m_exprtxt; SCA_IObject* m_sourceObj; // for copy property actuator public: @@ -63,28 +60,28 @@ class SCA_PropertyActuator : public SCA_IActuator SCA_PropertyActuator( SCA_IObject* gameobj, SCA_IObject* sourceObj, - const STR_String& propname, - const STR_String& expr, + const std::string& propname, + const std::string& expr, int acttype); ~SCA_PropertyActuator(); - CValue* + EXP_Value* GetReplica( ); virtual void ProcessReplica(); virtual bool UnlinkObject(SCA_IObject* clientobj); - virtual void Relink(CTR_Map *obj_map); + virtual void Relink(std::map& obj_map); - virtual bool + virtual bool Update(); /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - + }; #endif /* __KX_PROPERTYACTUATOR_DOC */ diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.cpp b/source/gameengine/GameLogic/SCA_PropertySensor.cpp index f823320a4172..6cee6d4e0a0e 100644 --- a/source/gameengine/GameLogic/SCA_PropertySensor.cpp +++ b/source/gameengine/GameLogic/SCA_PropertySensor.cpp @@ -33,39 +33,35 @@ */ -#include - -#include #include "SCA_PropertySensor.h" -#include "EXP_Operator2Expr.h" -#include "EXP_ConstExpr.h" -#include "EXP_InputParser.h" #include "EXP_StringValue.h" -#include "SCA_EventManager.h" -#include "SCA_LogicManager.h" #include "EXP_BoolValue.h" #include "EXP_FloatValue.h" -#include - -SCA_PropertySensor::SCA_PropertySensor(SCA_EventManager* eventmgr, - SCA_IObject* gameobj, - const STR_String& propname, - const STR_String& propval, - const STR_String& propmaxval, - KX_PROPSENSOR_TYPE checktype) - : SCA_ISensor(gameobj,eventmgr), - m_checktype(checktype), - m_checkpropval(propval), - m_checkpropmaxval(propmaxval), - m_checkpropname(propname) + +#include "BLI_compiler_attrs.h" + +#include "CM_Format.h" + +#include + +SCA_PropertySensor::SCA_PropertySensor(SCA_EventManager *eventmgr, + SCA_IObject *gameobj, + const std::string& propname, + const std::string& propval, + const std::string& propmaxval, + KX_PROPSENSOR_TYPE checktype) + :SCA_ISensor(gameobj, eventmgr), + m_checktype(checktype), + m_checkpropval(propval), + m_checkpropmaxval(propmaxval), + m_checkpropname(propname) { - //CParser pars; + //EXP_Parser pars; //pars.SetContext(this->AddRef()); - //CValue* resultval = m_rightexpr->Calculate(); + //EXP_Value* resultval = m_rightexpr->Calculate(); - CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname); - if (!orgprop->IsError()) - { + EXP_Value *orgprop = GetParent()->FindIdentifier(m_checkpropname); + if (!orgprop->IsError()) { m_previoustext = orgprop->GetText(); } orgprop->Release(); @@ -76,13 +72,13 @@ SCA_PropertySensor::SCA_PropertySensor(SCA_EventManager* eventmgr, void SCA_PropertySensor::Init() { m_recentresult = false; - m_lastresult = m_invert?true:false; + m_lastresult = m_invert ? true : false; m_reset = true; } -CValue* SCA_PropertySensor::GetReplica() +EXP_Value *SCA_PropertySensor::GetReplica() { - SCA_PropertySensor* replica = new SCA_PropertySensor(*this); + SCA_PropertySensor *replica = new SCA_PropertySensor(*this); // m_range_expr must be recalculated on replica! replica->ProcessReplica(); replica->Init(); @@ -95,8 +91,9 @@ CValue* SCA_PropertySensor::GetReplica() bool SCA_PropertySensor::IsPositiveTrigger() { bool result = m_recentresult;//CheckPropertyCondition(); - if (m_invert) + if (m_invert) { result = !result; + } return result; } @@ -115,8 +112,7 @@ bool SCA_PropertySensor::Evaluate() bool reset = m_reset && m_level; m_reset = false; - if (m_lastresult!=result) - { + if (m_lastresult != result) { m_lastresult = result; return true; } @@ -124,83 +120,66 @@ bool SCA_PropertySensor::Evaluate() } -bool SCA_PropertySensor::CheckPropertyCondition() +bool SCA_PropertySensor::CheckPropertyCondition() { - m_recentresult=false; - bool result=false; + m_recentresult = false; + bool result = false; bool reverse = false; - switch (m_checktype) - { - case KX_PROPSENSOR_NOTEQUAL: - reverse = true; - ATTR_FALLTHROUGH; - case KX_PROPSENSOR_EQUAL: + switch (m_checktype) { + case KX_PROPSENSOR_NOTEQUAL: + { + reverse = true; + ATTR_FALLTHROUGH; + } + case KX_PROPSENSOR_EQUAL: { - CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname); - if (!orgprop->IsError()) - { - const STR_String& testprop = orgprop->GetText(); + EXP_Value *orgprop = GetParent()->FindIdentifier(m_checkpropname); + if (!orgprop->IsError()) { + const std::string& testprop = orgprop->GetText(); // Force strings to upper case, to avoid confusion in // bool tests. It's stupid the prop's identity is lost // on the way here... - if ((&testprop == &CBoolValue::sTrueString) || (&testprop == &CBoolValue::sFalseString)) { - m_checkpropval.Upper(); + if ((testprop == EXP_BoolValue::sTrueString) || (testprop == EXP_BoolValue::sFalseString)) { + boost::to_upper(m_checkpropval); } result = (testprop == m_checkpropval); /* Patch: floating point values cant use strings usefully since you can have "0.0" == "0.0000" * this could be made into a generic Value class function for comparing values with a string. */ - if (result==false && (orgprop->GetValueType() == VALUE_FLOAT_TYPE)) { + if (result == false && (orgprop->GetValueType() == VALUE_FLOAT_TYPE)) { float f; - if (sscanf(m_checkpropval.ReadPtr(), "%f", &f) == 1) { - result = (f == ((CFloatValue *)orgprop)->GetFloat()); - } - else { - /* error */ + if (CM_StringTo(m_checkpropval, f)) { + result = (f == ((EXP_FloatValue *)orgprop)->GetFloat()); } } /* end patch */ } orgprop->Release(); - if (reverse) + if (reverse) { result = !result; + } break; } - case KX_PROPSENSOR_EXPRESSION: + case KX_PROPSENSOR_EXPRESSION: { -#if 0 - if (m_rightexpr) - { - CValue* resultval = m_rightexpr->Calculate(); - if (resultval->IsError()) - { - int i=0; - STR_String errortest = resultval->GetText(); - printf(errortest); - - } else - { - result = resultval->GetNumber() != 0; - } - } -#endif break; } - case KX_PROPSENSOR_INTERVAL: + case KX_PROPSENSOR_INTERVAL: { - CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname); - if (!orgprop->IsError()) - { - const float min = m_checkpropval.ToFloat(); - const float max = m_checkpropmaxval.ToFloat(); + EXP_Value *orgprop = GetParent()->FindIdentifier(m_checkpropname); + if (!orgprop->IsError()) { + float min; + float max; float val; + CM_StringTo(m_checkpropval, min); + CM_StringTo(m_checkpropmaxval, max); if (orgprop->GetValueType() == VALUE_STRING_TYPE) { - val = orgprop->GetText().ToFloat(); + CM_StringTo(orgprop->GetText(), val); } else { val = orgprop->GetNumber(); @@ -210,38 +189,37 @@ bool SCA_PropertySensor::CheckPropertyCondition() } orgprop->Release(); - break; + break; } - case KX_PROPSENSOR_CHANGED: + case KX_PROPSENSOR_CHANGED: { - CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname); + EXP_Value *orgprop = GetParent()->FindIdentifier(m_checkpropname); - if (!orgprop->IsError()) - { - if (m_previoustext != orgprop->GetText()) - { + if (!orgprop->IsError()) { + if (m_previoustext != orgprop->GetText()) { m_previoustext = orgprop->GetText(); result = true; } } orgprop->Release(); - //cout << " \nSens:Prop:changed!"; /* need implementation here!!! */ break; } - case KX_PROPSENSOR_LESSTHAN: - reverse = true; - ATTR_FALLTHROUGH; - case KX_PROPSENSOR_GREATERTHAN: + case KX_PROPSENSOR_LESSTHAN: + { + reverse = true; + ATTR_FALLTHROUGH; + } + case KX_PROPSENSOR_GREATERTHAN: { - CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname); - if (!orgprop->IsError()) - { - const float ref = m_checkpropval.ToFloat(); + EXP_Value *orgprop = GetParent()->FindIdentifier(m_checkpropname); + if (!orgprop->IsError()) { + float ref; + CM_StringTo(m_checkpropval, ref); float val; if (orgprop->GetValueType() == VALUE_STRING_TYPE) { - val = orgprop->GetText().ToFloat(); + CM_StringTo(orgprop->GetText(), val); } else { val = orgprop->GetNumber(); @@ -259,8 +237,8 @@ bool SCA_PropertySensor::CheckPropertyCondition() break; } - default: - ; /* error */ + default: + ; /* error */ } //the concept of Edge and Level triggering has unwanted effect for KX_PROPSENSOR_CHANGED @@ -270,9 +248,9 @@ bool SCA_PropertySensor::CheckPropertyCondition() return result; } -CValue* SCA_PropertySensor::FindIdentifier(const STR_String& identifiername) +EXP_Value *SCA_PropertySensor::FindIdentifier(const std::string& identifiername) { - return GetParent()->FindIdentifier(identifiername); + return GetParent()->FindIdentifier(identifiername); } #ifdef WITH_PYTHON @@ -281,7 +259,7 @@ CValue* SCA_PropertySensor::FindIdentifier(const STR_String& identifiername) /* Python functions */ /* ------------------------------------------------------------------------- */ -int SCA_PropertySensor::validValueForProperty(void *self, const PyAttributeDef*) +int SCA_PropertySensor::validValueForProperty(EXP_PyObjectPlus *self, const PyAttributeDef *) { /* If someone actually do type checking please make sure the 'max' and 'min' * are checked as well (currently they are calling the PrecalculateRangeExpression @@ -293,9 +271,9 @@ int SCA_PropertySensor::validValueForProperty(void *self, const PyAttributeDef*) /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_PropertySensor::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_PropertySensor", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -303,28 +281,28 @@ PyTypeObject SCA_PropertySensor::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_ISensor::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_PropertySensor::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef SCA_PropertySensor::Attributes[] = { - KX_PYATTRIBUTE_INT_RW("mode",KX_PROPSENSOR_NODEF,KX_PROPSENSOR_MAX-1,false,SCA_PropertySensor,m_checktype), - KX_PYATTRIBUTE_STRING_RW_CHECK("propName",0,MAX_PROP_NAME,false,SCA_PropertySensor,m_checkpropname,CheckProperty), - KX_PYATTRIBUTE_STRING_RW_CHECK("value",0,100,false,SCA_PropertySensor,m_checkpropval,validValueForProperty), - KX_PYATTRIBUTE_STRING_RW_CHECK("min",0,100,false,SCA_PropertySensor,m_checkpropval,validValueForProperty), - KX_PYATTRIBUTE_STRING_RW_CHECK("max",0,100,false,SCA_PropertySensor,m_checkpropmaxval,validValueForProperty), - { NULL } //Sentinel + EXP_PYATTRIBUTE_INT_RW("mode", KX_PROPSENSOR_NODEF, KX_PROPSENSOR_MAX - 1, false, SCA_PropertySensor, m_checktype), + EXP_PYATTRIBUTE_STRING_RW_CHECK("propName", 0, MAX_PROP_NAME, false, SCA_PropertySensor, m_checkpropname, CheckProperty), + EXP_PYATTRIBUTE_STRING_RW_CHECK("value", 0, 100, false, SCA_PropertySensor, m_checkpropval, validValueForProperty), + EXP_PYATTRIBUTE_STRING_RW_CHECK("min", 0, 100, false, SCA_PropertySensor, m_checkpropval, validValueForProperty), + EXP_PYATTRIBUTE_STRING_RW_CHECK("max", 0, 100, false, SCA_PropertySensor, m_checkpropmaxval, validValueForProperty), + EXP_PYATTRIBUTE_NULL //Sentinel }; #endif // WITH_PYTHON diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.h b/source/gameengine/GameLogic/SCA_PropertySensor.h index 4183abeaf952..9a5e8e5fc9d8 100644 --- a/source/gameengine/GameLogic/SCA_PropertySensor.h +++ b/source/gameengine/GameLogic/SCA_PropertySensor.h @@ -38,12 +38,12 @@ class SCA_PropertySensor : public SCA_ISensor { Py_Header - //class CExpression* m_rightexpr; + //class EXP_Expression* m_rightexpr; int m_checktype; - STR_String m_checkpropval; - STR_String m_checkpropmaxval; - STR_String m_checkpropname; - STR_String m_previoustext; + std::string m_checkpropval; + std::string m_checkpropmaxval; + std::string m_checkpropname; + std::string m_previoustext; bool m_lastresult; bool m_recentresult; @@ -62,23 +62,23 @@ class SCA_PropertySensor : public SCA_ISensor KX_PROPSENSOR_MAX }; - const STR_String S_KX_PROPSENSOR_EQ_STRING; - + const std::string S_KX_PROPSENSOR_EQ_STRING; + SCA_PropertySensor(class SCA_EventManager* eventmgr, SCA_IObject* gameobj, - const STR_String& propname, - const STR_String& propval, - const STR_String& propmaxval, + const std::string& propname, + const std::string& propval, + const std::string& propmaxval, KX_PROPSENSOR_TYPE checktype); virtual ~SCA_PropertySensor(); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); virtual void Init(); bool CheckPropertyCondition(); virtual bool Evaluate(); virtual bool IsPositiveTrigger(); - virtual CValue* FindIdentifier(const STR_String& identifiername); + virtual EXP_Value* FindIdentifier(const std::string& identifiername); #ifdef WITH_PYTHON @@ -89,9 +89,10 @@ class SCA_PropertySensor : public SCA_ISensor /** * Test whether this is a sensible value (type check) */ - static int validValueForProperty(void* self, const PyAttributeDef*); + static int validValueForProperty(EXP_PyObjectPlus *self, const PyAttributeDef*); #endif }; #endif + diff --git a/source/gameengine/GameLogic/SCA_PythonController.cpp b/source/gameengine/GameLogic/SCA_PythonController.cpp index 8da660686ef1..7c5ea3c7a55b 100644 --- a/source/gameengine/GameLogic/SCA_PythonController.cpp +++ b/source/gameengine/GameLogic/SCA_PythonController.cpp @@ -32,65 +32,48 @@ * \ingroup gamelogic */ - -#include - #include "SCA_PythonController.h" #include "SCA_LogicManager.h" #include "SCA_ISensor.h" #include "SCA_IActuator.h" #include "EXP_PyObjectPlus.h" -#ifdef WITH_PYTHON -#include "compile.h" -#include "eval.h" -#endif // WITH_PYTHON - -#include +extern "C" { +# ifdef WITH_PYTHON +# include "compile.h" +# include "eval.h" +# include "py_capi_utils.h" +# endif // WITH_PYTHON +} +#include "CM_Message.h" // initialize static member variables -SCA_PythonController* SCA_PythonController::m_sCurrentController = NULL; +SCA_PythonController *SCA_PythonController::m_sCurrentController = nullptr; -SCA_PythonController::SCA_PythonController(SCA_IObject* gameobj, int mode) - : SCA_IController(gameobj), +SCA_PythonController::SCA_PythonController(SCA_IObject *gameobj, int mode) + :SCA_IController(gameobj), #ifdef WITH_PYTHON - m_bytecode(NULL), - m_function(NULL), + m_bytecode(nullptr), + m_function(nullptr), #endif m_function_argc(0), m_bModified(true), m_debug(false), m_mode(mode) #ifdef WITH_PYTHON - , m_pythondictionary(NULL) + , m_pythondictionary(nullptr) #endif { } -#if 0 -//debugging -CValue *SCA_PythonController::AddRef() -{ - //printf("AddRef refcount = %i\n",GetRefCount()); - return CValue::AddRef(); -} -int SCA_PythonController::Release() -{ - //printf("Release refcount = %i\n",GetRefCount()); - return CValue::Release(); -} -#endif - SCA_PythonController::~SCA_PythonController() { #ifdef WITH_PYTHON - //printf("released python byte script\n"); - Py_XDECREF(m_bytecode); Py_XDECREF(m_function); @@ -104,27 +87,29 @@ SCA_PythonController::~SCA_PythonController() -CValue* SCA_PythonController::GetReplica() +EXP_Value *SCA_PythonController::GetReplica() { - SCA_PythonController* replica = new SCA_PythonController(*this); + SCA_PythonController *replica = new SCA_PythonController(*this); #ifdef WITH_PYTHON - /* why is this needed at all??? - m_bytecode is NULL'd below so this doesnt make sense + /* why is this needed at all??? - m_bytecode is nullptr'd below so this doesnt make sense * but removing it crashes blender (with YoFrankie). so leave in for now - Campbell */ Py_XINCREF(replica->m_bytecode); - Py_XINCREF(replica->m_function); // this is ok since its not set to NULL - replica->m_bModified = replica->m_bytecode == NULL; + Py_XINCREF(replica->m_function); // this is ok since its not set to nullptr + replica->m_bModified = replica->m_bytecode == nullptr; // The replica->m_pythondictionary is stolen - replace with a copy. - if (m_pythondictionary) + if (m_pythondictionary) { replica->m_pythondictionary = PyDict_Copy(m_pythondictionary); + } #if 0 // The other option is to incref the replica->m_pythondictionary - // the replica objects can then share data. - if (m_pythondictionary) + if (m_pythondictionary) { Py_INCREF(replica->m_pythondictionary); + } #endif #endif /* WITH_PYTHON */ @@ -137,7 +122,7 @@ CValue* SCA_PythonController::GetReplica() -void SCA_PythonController::SetScriptText(const STR_String& text) +void SCA_PythonController::SetScriptText(const std::string& text) { m_scriptText = text; m_bModified = true; @@ -145,76 +130,48 @@ void SCA_PythonController::SetScriptText(const STR_String& text) -void SCA_PythonController::SetScriptName(const STR_String& name) +void SCA_PythonController::SetScriptName(const std::string& name) { m_scriptName = name; } - -#ifdef WITH_PYTHON -void SCA_PythonController::SetNamespace(PyObject* pythondictionary) +bool SCA_PythonController::IsTriggered(class SCA_ISensor *sensor) { - if (m_pythondictionary) - { - PyDict_Clear(m_pythondictionary); - Py_DECREF(m_pythondictionary); - } - m_pythondictionary = PyDict_Copy(pythondictionary); /* new reference */ - - /* Without __file__ set the sys.argv[0] is used for the filename - * which ends up with lines from the blender binary being printed in the console */ - PyObject *value = PyUnicode_From_STR_String(m_scriptName); - PyDict_SetItemString(m_pythondictionary, "__file__", value); - Py_DECREF(value); - -} -#endif - -bool SCA_PythonController::IsTriggered(class SCA_ISensor* sensor) -{ - if (std::find(m_triggeredSensors.begin(), m_triggeredSensors.end(), sensor) != - m_triggeredSensors.end()) - { - return true; - } - else { - return false; - } + return (std::find(m_triggeredSensors.begin(), m_triggeredSensors.end(), sensor) != m_triggeredSensors.end()); } #ifdef WITH_PYTHON -/* warning, self is not the SCA_PythonController, its a PyObjectPlus_Proxy */ +/* warning, self is not the SCA_PythonController, its a EXP_PyObjectPlus_Proxy */ PyObject *SCA_PythonController::sPyGetCurrentController(PyObject *self) { - if (m_sCurrentController==NULL) - { + if (m_sCurrentController == nullptr) { PyErr_SetString(PyExc_SystemError, "bge.logic.getCurrentController(), this function is being run outside the python controllers context, or blenders internal state is corrupt."); - return NULL; + return nullptr; } return m_sCurrentController->GetProxy(); } -SCA_IActuator* SCA_PythonController::LinkedActuatorFromPy(PyObject *value) +SCA_IActuator *SCA_PythonController::LinkedActuatorFromPy(PyObject *value) { // for safety, todo: only allow for registered actuators (pointertable) // we don't want to crash gameengine/blender by python scripts - std::vector lacts = m_sCurrentController->GetLinkedActuators(); - std::vector::iterator it; + std::vector lacts = m_sCurrentController->GetLinkedActuators(); + std::vector::iterator it; if (PyUnicode_Check(value)) { /* get the actuator from the name */ - const char *name= _PyUnicode_AsString(value); - for (it = lacts.begin(); it!= lacts.end(); ++it) { - if ( name == (*it)->GetName() ) { + const char *name = _PyUnicode_AsString(value); + for (it = lacts.begin(); it != lacts.end(); ++it) { + if (name == (*it)->GetName()) { return *it; } } } else if (PyObject_TypeCheck(value, &SCA_IActuator::Type)) { - PyObjectPlus *value_plus= BGE_PROXY_REF(value); - for (it = lacts.begin(); it!= lacts.end(); ++it) { - if (static_cast(value_plus) == (*it)) { + EXP_PyObjectPlus *value_plus = EXP_PROXY_REF(value); + for (it = lacts.begin(); it != lacts.end(); ++it) { + if (static_cast(value_plus) == (*it)) { return *it; } } @@ -224,15 +181,15 @@ SCA_IActuator* SCA_PythonController::LinkedActuatorFromPy(PyObject *value) PyErr_Format(PyExc_ValueError, "%R not in this python controllers actuator list", value); - return NULL; + return nullptr; } -const char* SCA_PythonController::sPyGetCurrentController__doc__ = "getCurrentController()"; +const char *SCA_PythonController::sPyGetCurrentController__doc__ = "getCurrentController()"; PyTypeObject SCA_PythonController::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_PythonController", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -240,70 +197,63 @@ PyTypeObject SCA_PythonController::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IController::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_PythonController::Methods[] = { - {"activate", (PyCFunction) SCA_PythonController::sPyActivate, METH_O}, - {"deactivate", (PyCFunction) SCA_PythonController::sPyDeActivate, METH_O}, - {NULL,NULL} //Sentinel + {"activate", (PyCFunction)SCA_PythonController::sPyActivate, METH_O}, + {"deactivate", (PyCFunction)SCA_PythonController::sPyDeActivate, METH_O}, + {nullptr, nullptr} //Sentinel }; PyAttributeDef SCA_PythonController::Attributes[] = { - KX_PYATTRIBUTE_RW_FUNCTION("script", SCA_PythonController, pyattr_get_script, pyattr_set_script), - KX_PYATTRIBUTE_INT_RO("mode", SCA_PythonController, m_mode), - { NULL } //Sentinel + EXP_PYATTRIBUTE_RW_FUNCTION("script", SCA_PythonController, pyattr_get_script, pyattr_set_script), + EXP_PYATTRIBUTE_INT_RO("mode", SCA_PythonController, m_mode), + EXP_PYATTRIBUTE_NULL //Sentinel }; void SCA_PythonController::ErrorPrint(const char *error_msg) { - // If GetParent() is NULL, then most likely the object this controller + // If GetParent() is nullptr, then most likely the object this controller // was attached to is gone (e.g., removed by LibFree()). Also, GetName() - // can be a bad pointer if GetParent() is NULL, so better be safe and + // can be a bad pointer if GetParent() is nullptr, so better be safe and // flag it as unavailable as well - const char *obj_name, *ctr_name; - if (GetParent()) { - obj_name = GetParent()->GetName().ReadPtr(); - ctr_name = GetName().ReadPtr(); - } else { - obj_name = ctr_name = "Unavailable"; - } - printf("%s - object '%s', controller '%s':\n", error_msg, obj_name, ctr_name); + CM_LogicBrickError(this, error_msg); PyErr_Print(); /* Added in 2.48a, the last_traceback can reference Objects for example, increasing * their user count. Not to mention holding references to wrapped data. * This is especially bad when the PyObject for the wrapped data is freed, after blender * has already dealocated the pointer */ - PySys_SetObject("last_traceback", NULL); + PySys_SetObject("last_traceback", nullptr); PyErr_Clear(); /* just to be sure */ } bool SCA_PythonController::Compile() { - //printf("py script modified '%s'\n", m_scriptName.Ptr()); - m_bModified= false; + m_bModified = false; // if a script already exists, decref it before replace the pointer to a new script if (m_bytecode) { Py_DECREF(m_bytecode); - m_bytecode=NULL; + m_bytecode = nullptr; } // recompile the scripttext into bytecode - m_bytecode = Py_CompileString(m_scriptText.Ptr(), m_scriptName.Ptr(), Py_file_input); + m_bytecode = Py_CompileString(m_scriptText.c_str(), m_scriptName.c_str(), Py_file_input); if (m_bytecode) { return true; - } else { + } + else { ErrorPrint("Python error compiling script"); return false; } @@ -311,73 +261,76 @@ bool SCA_PythonController::Compile() bool SCA_PythonController::Import() { - //printf("py module modified '%s'\n", m_scriptName.Ptr()); - m_bModified= false; + m_bModified = false; /* in case we re-import */ Py_XDECREF(m_function); - m_function= NULL; + m_function = nullptr; - STR_String mod_path_str= m_scriptText; /* just for storage, use C style string access */ - char *mod_path= mod_path_str.Ptr(); - char *function_string; + std::string mod_path = m_scriptText; /* just for storage, use C style string access */ + std::string function_string; - function_string= strrchr(mod_path, '.'); + const int pos = mod_path.rfind('.'); + if (pos != std::string::npos) { + function_string = mod_path.substr(pos + 1); + mod_path = mod_path.substr(0, pos); + } - if (function_string == NULL) { - printf("Python module name formatting error in object '%s', controller '%s':\n\texpected 'SomeModule.Func', got '%s'\n", GetParent()->GetName().Ptr(), GetName().Ptr(), m_scriptText.Ptr()); + if (function_string.empty()) { + CM_LogicBrickError(this, "python module name formatting expected 'SomeModule.Func', got '" << m_scriptText << "'"); return false; } - *function_string= '\0'; - function_string++; - // Import the module and print an error if it's not found - PyObject *mod = PyImport_ImportModule(mod_path); + PyObject *mod = PyImport_ImportModule(mod_path.c_str()); - if (mod == NULL) { + if (mod == nullptr) { ErrorPrint("Python module can't be imported"); return false; } - if (m_debug) + if (m_debug) { mod = PyImport_ReloadModule(mod); + } - if (mod == NULL) { + if (mod == nullptr) { ErrorPrint("Python module can't be reloaded"); return false; } // Get the function object - m_function = PyObject_GetAttrString(mod, function_string); + m_function = PyObject_GetAttrString(mod, function_string.c_str()); // DECREF the module as we don't need it anymore Py_DECREF(mod); - if (m_function==NULL) { - if (PyErr_Occurred()) - ErrorPrint("Python controller found the module but could not access the function"); - else - printf("Python module error in object '%s', controller '%s':\n '%s' module found but function missing\n", GetParent()->GetName().Ptr(), GetName().Ptr(), m_scriptText.Ptr()); + if (m_function == nullptr) { + if (PyErr_Occurred()) { + ErrorPrint("python controller found the module but could not access the function"); + } + else { + CM_LogicBrickError(this, "python module '" << m_scriptText << "' found but function missing"); + } return false; } if (!PyCallable_Check(m_function)) { Py_DECREF(m_function); - m_function = NULL; - printf("Python module function error in object '%s', controller '%s':\n '%s' not callable\n", GetParent()->GetName().Ptr(), GetName().Ptr(), m_scriptText.Ptr()); + m_function = nullptr; + CM_LogicBrickError(this, "python module function '" << m_scriptText << "' not callable"); return false; } m_function_argc = 0; /* rare cases this could be a function that isn't defined in python, assume zero args */ if (PyFunction_Check(m_function)) { - m_function_argc= ((PyCodeObject *)PyFunction_GET_CODE(m_function))->co_argcount; + m_function_argc = ((PyCodeObject *)PyFunction_GET_CODE(m_function))->co_argcount; } if (m_function_argc > 1) { Py_DECREF(m_function); - m_function = NULL; - printf("Python module function in object '%s', controller '%s':\n '%s' takes %d args, should be zero or 1 controller arg\n", GetParent()->GetName().Ptr(), GetName().Ptr(), m_scriptText.Ptr(), m_function_argc); + m_function = nullptr; + CM_LogicBrickError(this, "python module function:\n '" << m_scriptText << "' takes " << m_function_argc + << " args, should be zero or 1 controller arg"); return false; } @@ -385,21 +338,24 @@ bool SCA_PythonController::Import() } -void SCA_PythonController::Trigger(SCA_LogicManager* logicmgr) +void SCA_PythonController::Trigger(SCA_LogicManager *logicmgr) { m_sCurrentController = this; - PyObject *excdict= NULL; - PyObject *resultobj= NULL; + PyObject *excdict = nullptr; + PyObject *resultobj = nullptr; switch (m_mode) { case SCA_PYEXEC_SCRIPT: { - if (m_bModified) - if (Compile()==false) // sets m_bModified to false + if (m_bModified) { + if (Compile() == false) { // sets m_bModified to false return; - if (!m_bytecode) + } + } + if (!m_bytecode) { return; + } /* * This part here with excdict is a temporary patch @@ -419,7 +375,13 @@ void SCA_PythonController::Trigger(SCA_LogicManager* logicmgr) * should always ensure excdict is cleared). */ - excdict= PyDict_Copy(m_pythondictionary); + if (!m_pythondictionary) { + /* Without __file__ set the sys.argv[0] is used for the filename + * which ends up with lines from the blender binary being printed in the console */ + m_pythondictionary = PyDict_Copy(PyC_DefaultNameSpace(m_scriptName.c_str())); /* new reference */ + } + + excdict = PyDict_Copy(m_pythondictionary); resultobj = PyEval_EvalCode((PyObject *)m_bytecode, excdict, excdict); @@ -428,15 +390,18 @@ void SCA_PythonController::Trigger(SCA_LogicManager* logicmgr) } case SCA_PYEXEC_MODULE: { - if (m_bModified || m_debug) - if (Import()==false) // sets m_bModified to false + if (m_bModified || m_debug) { + if (Import() == false) { // sets m_bModified to false return; - if (!m_function) + } + } + if (!m_function) { return; + } - PyObject *args= NULL; + PyObject *args = nullptr; - if (m_function_argc==1) { + if (m_function_argc == 1) { args = PyTuple_New(1); PyTuple_SET_ITEM(args, 0, GetProxy()); } @@ -450,13 +415,14 @@ void SCA_PythonController::Trigger(SCA_LogicManager* logicmgr) /* Free the return value and print the error */ - if (resultobj) + if (resultobj) { Py_DECREF(resultobj); - else + } + else { ErrorPrint("Python script error"); + } - if (excdict) /* Only for SCA_PYEXEC_SCRIPT types */ - { + if (excdict) { /* Only for SCA_PYEXEC_SCRIPT types */ /* clear after PyErrPrint - seems it can be using * something in this dictionary and crash? */ // This doesn't appear to be needed anymore @@ -465,21 +431,22 @@ void SCA_PythonController::Trigger(SCA_LogicManager* logicmgr) } m_triggeredSensors.clear(); - m_sCurrentController = NULL; + m_sCurrentController = nullptr; } PyObject *SCA_PythonController::PyActivate(PyObject *value) { if (m_sCurrentController != this) { PyErr_SetString(PyExc_SystemError, "Cannot activate an actuator from a non-active controller"); - return NULL; + return nullptr; } - SCA_IActuator* actu = LinkedActuatorFromPy(value); - if (actu==NULL) - return NULL; + SCA_IActuator *actu = LinkedActuatorFromPy(value); + if (actu == nullptr) { + return nullptr; + } - m_logicManager->AddActiveActuator((SCA_IActuator*)actu, true); + m_logicManager->AddActiveActuator((SCA_IActuator *)actu, true); Py_RETURN_NONE; } @@ -487,35 +454,36 @@ PyObject *SCA_PythonController::PyDeActivate(PyObject *value) { if (m_sCurrentController != this) { PyErr_SetString(PyExc_SystemError, "Cannot deactivate an actuator from a non-active controller"); - return NULL; + return nullptr; } - SCA_IActuator* actu = LinkedActuatorFromPy(value); - if (actu==NULL) - return NULL; + SCA_IActuator *actu = LinkedActuatorFromPy(value); + if (actu == nullptr) { + return nullptr; + } - m_logicManager->AddActiveActuator((SCA_IActuator*)actu, false); + m_logicManager->AddActiveActuator((SCA_IActuator *)actu, false); Py_RETURN_NONE; } -PyObject *SCA_PythonController::pyattr_get_script(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_PythonController::pyattr_get_script(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - //SCA_PythonController* self = static_cast(static_cast(static_cast(static_cast(static_cast(self_v))))); + //SCA_PythonController* self = static_cast(static_cast(static_cast(static_cast(static_cast(self_v))))); // static_cast(dynamic_cast(obj)) - static_cast(obj) - SCA_PythonController* self = static_cast(self_v); - return PyUnicode_From_STR_String(self->m_scriptText); + SCA_PythonController *self = static_cast(self_v); + return PyUnicode_FromStdString(self->m_scriptText); } -int SCA_PythonController::pyattr_set_script(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int SCA_PythonController::pyattr_set_script(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - SCA_PythonController* self = static_cast(self_v); + SCA_PythonController *self = static_cast(self_v); const char *scriptArg = _PyUnicode_AsString(value); - if (scriptArg==NULL) { + if (scriptArg == nullptr) { PyErr_SetString(PyExc_TypeError, "controller.script = string: Python Controller, expected a string script text"); return PY_SET_ATTR_FAIL; } @@ -529,7 +497,7 @@ int SCA_PythonController::pyattr_set_script(void *self_v, const KX_PYATTRIBUTE_D #else // WITH_PYTHON -void SCA_PythonController::Trigger(SCA_LogicManager* logicmgr) +void SCA_PythonController::Trigger(SCA_LogicManager *logicmgr) { /* intentionally blank */ } diff --git a/source/gameengine/GameLogic/SCA_PythonController.h b/source/gameengine/GameLogic/SCA_PythonController.h index ffb23c152ea8..f99e75e58994 100644 --- a/source/gameengine/GameLogic/SCA_PythonController.h +++ b/source/gameengine/GameLogic/SCA_PythonController.h @@ -52,16 +52,16 @@ class SCA_PythonController : public SCA_IController bool m_debug; /* use with SCA_PYEXEC_MODULE for reloading every logic run */ int m_mode; - + protected: - STR_String m_scriptText; - STR_String m_scriptName; + std::string m_scriptText; + std::string m_scriptName; #ifdef WITH_PYTHON PyObject* m_pythondictionary; /* for SCA_PYEXEC_SCRIPT only */ PyObject* m_pythonfunction; /* for SCA_PYEXEC_MODULE only */ #endif std::vector m_triggeredSensors; - + public: enum SCA_PyExecMode { @@ -73,20 +73,17 @@ class SCA_PythonController : public SCA_IController static SCA_PythonController* m_sCurrentController; // protected !!! //for debugging - //virtual CValue* AddRef(); + //virtual EXP_Value* AddRef(); //virtual int Release(); // Release a reference to this value (when reference count reaches 0, the value is removed from the heap) SCA_PythonController(SCA_IObject* gameobj, int mode); virtual ~SCA_PythonController(); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); virtual void Trigger(class SCA_LogicManager* logicmgr); - - void SetScriptText(const STR_String& text); - void SetScriptName(const STR_String& name); -#ifdef WITH_PYTHON - void SetNamespace(PyObject* pythondictionary); -#endif + + void SetScriptText(const std::string& text); + void SetScriptName(const std::string& name); void SetDebug(bool debug) { m_debug = debug; } void AddTriggeredSensor(class SCA_ISensor* sensor) { m_triggeredSensors.push_back(sensor); } @@ -94,7 +91,7 @@ class SCA_PythonController : public SCA_IController bool Compile(); bool Import(); void ErrorPrint(const char *error_msg); - + #ifdef WITH_PYTHON static const char *sPyGetCurrentController__doc__; static PyObject *sPyGetCurrentController(PyObject *self); @@ -103,15 +100,15 @@ class SCA_PythonController : public SCA_IController PyObject *args); static SCA_IActuator* LinkedActuatorFromPy(PyObject *value); + + EXP_PYMETHOD_O(SCA_PythonController,Activate); + EXP_PYMETHOD_O(SCA_PythonController,DeActivate); + EXP_PYMETHOD_O(SCA_PythonController,SetScript); + EXP_PYMETHOD_NOARGS(SCA_PythonController,GetScript); - KX_PYMETHOD_O(SCA_PythonController,Activate); - KX_PYMETHOD_O(SCA_PythonController,DeActivate); - KX_PYMETHOD_O(SCA_PythonController,SetScript); - KX_PYMETHOD_NOARGS(SCA_PythonController,GetScript); - - - static PyObject* pyattr_get_script(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_script(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + + static PyObject* pyattr_get_script(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_script(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); #endif }; diff --git a/source/gameengine/GameLogic/SCA_PythonJoystick.cpp b/source/gameengine/GameLogic/SCA_PythonJoystick.cpp index 06f42e841477..9e426d23eb31 100644 --- a/source/gameengine/GameLogic/SCA_PythonJoystick.cpp +++ b/source/gameengine/GameLogic/SCA_PythonJoystick.cpp @@ -26,7 +26,7 @@ #include "SCA_PythonJoystick.h" -#include "./Joystick/SCA_Joystick.h" +#include "DEV_Joystick.h" #include "SCA_IInputDevice.h" //#include "GHOST_C-api.h" @@ -35,9 +35,9 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_PythonJoystick::SCA_PythonJoystick(SCA_Joystick* joystick) -: PyObjectPlus(), -m_joystick(joystick) +SCA_PythonJoystick::SCA_PythonJoystick(DEV_Joystick *joystick, int joyindex) + :m_joystick(joystick), + m_joyindex(joyindex) { #ifdef WITH_PYTHON m_event_dict = PyDict_New(); @@ -46,32 +46,28 @@ m_joystick(joystick) SCA_PythonJoystick::~SCA_PythonJoystick() { - // The joystick reference we got in the constructor was a new instance, - // so we release it here - m_joystick->ReleaseInstance(); - #ifdef WITH_PYTHON PyDict_Clear(m_event_dict); Py_DECREF(m_event_dict); #endif } +std::string SCA_PythonJoystick::GetName() +{ + return m_joystick->GetName(); +} + #ifdef WITH_PYTHON /* ------------------------------------------------------------------------- */ /* Python functions */ /* ------------------------------------------------------------------------- */ -PyObject* SCA_PythonJoystick::py_repr(void) -{ - return PyUnicode_FromString(m_joystick->GetName()); -} - /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_PythonJoystick::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_PythonJoystick", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -79,59 +75,61 @@ PyTypeObject SCA_PythonJoystick::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, - &PyObjectPlus::Type, - 0,0,0,0,0,0, + &EXP_PyObjectPlus::Type, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_PythonJoystick::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef SCA_PythonJoystick::Attributes[] = { - KX_PYATTRIBUTE_RO_FUNCTION("numButtons", SCA_PythonJoystick, pyattr_get_num_x), - KX_PYATTRIBUTE_RO_FUNCTION("numHats", SCA_PythonJoystick, pyattr_get_num_x), - KX_PYATTRIBUTE_RO_FUNCTION("numAxis", SCA_PythonJoystick, pyattr_get_num_x), - KX_PYATTRIBUTE_RO_FUNCTION("activeButtons", SCA_PythonJoystick, pyattr_get_active_buttons), - KX_PYATTRIBUTE_RO_FUNCTION("hatValues", SCA_PythonJoystick, pyattr_get_hat_values), - KX_PYATTRIBUTE_RO_FUNCTION("axisValues", SCA_PythonJoystick, pyattr_get_axis_values), - KX_PYATTRIBUTE_RO_FUNCTION("name", SCA_PythonJoystick, pyattr_get_name), - { NULL } //Sentinel + EXP_PYATTRIBUTE_RO_FUNCTION("numButtons", SCA_PythonJoystick, pyattr_get_num_x), + EXP_PYATTRIBUTE_RO_FUNCTION("numHats", SCA_PythonJoystick, pyattr_get_num_x), + EXP_PYATTRIBUTE_RO_FUNCTION("numAxis", SCA_PythonJoystick, pyattr_get_num_x), + EXP_PYATTRIBUTE_RO_FUNCTION("activeButtons", SCA_PythonJoystick, pyattr_get_active_buttons), + EXP_PYATTRIBUTE_RO_FUNCTION("hatValues", SCA_PythonJoystick, pyattr_get_hat_values), + EXP_PYATTRIBUTE_RO_FUNCTION("axisValues", SCA_PythonJoystick, pyattr_get_axis_values), + EXP_PYATTRIBUTE_RO_FUNCTION("name", SCA_PythonJoystick, pyattr_get_name), + EXP_PYATTRIBUTE_NULL //Sentinel }; // Use one function for numAxis, numButtons, and numHats -PyObject* SCA_PythonJoystick::pyattr_get_num_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_PythonJoystick::pyattr_get_num_x(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_PythonJoystick* self = static_cast(self_v); - - if (strcmp(attrdef->m_name, "numButtons") == 0) - return PyLong_FromLong(self->m_joystick->GetNumberOfButtons()); - else if (strcmp(attrdef->m_name, "numAxis") == 0) - return PyLong_FromLong(self->m_joystick->GetNumberOfAxes()); - else if (strcmp(attrdef->m_name, "numHats") == 0) - return PyLong_FromLong(self->m_joystick->GetNumberOfHats()); + if (attrdef->m_name == "numButtons") { + return PyLong_FromLong(JOYBUT_MAX); + } + else if (attrdef->m_name == "numAxis") { + return PyLong_FromLong(JOYAXIS_MAX); + } + else if (attrdef->m_name == "numHats") { + EXP_ShowDeprecationWarning("SCA_PythonJoystick.numHats", "SCA_PythonJoystick.numButtons"); + return PyLong_FromLong(0); + } // If we got here, we have a problem... PyErr_SetString(PyExc_AttributeError, "invalid attribute"); - return NULL; + return nullptr; } -PyObject* SCA_PythonJoystick::pyattr_get_active_buttons(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_PythonJoystick::pyattr_get_active_buttons(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_PythonJoystick* self = static_cast(self_v); + SCA_PythonJoystick *self = static_cast(self_v); - const int button_number = self->m_joystick->GetNumberOfButtons(); + const int button_number = JOYBUT_MAX; PyObject *list = PyList_New(0); PyObject *value; - for (int i=0; i < button_number; i++) { + for (int i = 0; i < button_number; i++) { if (self->m_joystick->aButtonPressIsPositive(i)) { value = PyLong_FromLong(i); PyList_Append(list, value); @@ -139,28 +137,21 @@ PyObject* SCA_PythonJoystick::pyattr_get_active_buttons(void *self_v, const KX_P } } + /* XXX return list adapted to new names (A, B, X, Y, START, etc) */ return list; } -PyObject* SCA_PythonJoystick::pyattr_get_hat_values(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_PythonJoystick::pyattr_get_hat_values(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_PythonJoystick* self = static_cast(self_v); - - int hat_index = self->m_joystick->GetNumberOfHats(); - PyObject *list = PyList_New(hat_index); - - while (hat_index--) { - PyList_SET_ITEM(list, hat_index, PyLong_FromLong(self->m_joystick->GetHat(hat_index))); - } - - return list; + EXP_ShowDeprecationWarning("SCA_PythonJoystick.hatValues", "SCA_PythonJoystick.activeButtons"); + return PyList_New(0); } -PyObject* SCA_PythonJoystick::pyattr_get_axis_values(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_PythonJoystick::pyattr_get_axis_values(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_PythonJoystick* self = static_cast(self_v); + SCA_PythonJoystick *self = static_cast(self_v); - int axis_index = self->m_joystick->GetNumberOfAxes(); + int axis_index = JOYAXIS_MAX; PyObject *list = PyList_New(axis_index); int position; @@ -170,19 +161,21 @@ PyObject* SCA_PythonJoystick::pyattr_get_axis_values(void *self_v, const KX_PYAT // We get back a range from -32768 to 32767, so we use an if here to // get a perfect -1.0 to 1.0 mapping. Some oddball system might have an // actual min of -32767 for shorts, so we use SHRT_MIN/MAX to be safe. - if (position < 0) - PyList_SET_ITEM(list, axis_index, PyFloat_FromDouble(position/((double)-SHRT_MIN))); - else - PyList_SET_ITEM(list, axis_index, PyFloat_FromDouble(position/(double)SHRT_MAX)); + if (position < 0) { + PyList_SET_ITEM(list, axis_index, PyFloat_FromDouble(position / ((double)-SHRT_MIN))); + } + else { + PyList_SET_ITEM(list, axis_index, PyFloat_FromDouble(position / (double)SHRT_MAX)); + } } return list; } -PyObject* SCA_PythonJoystick::pyattr_get_name(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_PythonJoystick::pyattr_get_name(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_PythonJoystick* self = static_cast(self_v); + SCA_PythonJoystick *self = static_cast(self_v); - return PyUnicode_FromString(self->m_joystick->GetName()); + return PyUnicode_FromStdString(self->m_joystick->GetName()); } #endif diff --git a/source/gameengine/GameLogic/SCA_PythonJoystick.h b/source/gameengine/GameLogic/SCA_PythonJoystick.h index fdecba604c61..ab17668c145f 100644 --- a/source/gameengine/GameLogic/SCA_PythonJoystick.h +++ b/source/gameengine/GameLogic/SCA_PythonJoystick.h @@ -27,29 +27,31 @@ #ifndef __SCA_PYTHONJOYSTICK_H__ #define __SCA_PYTHONJOYSTICK_H__ -#include "EXP_PyObjectPlus.h" +#include "EXP_Value.h" -class SCA_PythonJoystick : public PyObjectPlus +class SCA_PythonJoystick : public EXP_Value { Py_Header private: - class SCA_Joystick *m_joystick; + class DEV_Joystick *m_joystick; + int m_joyindex; #ifdef WITH_PYTHON PyObject* m_event_dict; #endif public: - SCA_PythonJoystick(class SCA_Joystick* joystick); + SCA_PythonJoystick(class DEV_Joystick* joystick, int joyindex); virtual ~SCA_PythonJoystick(); -#ifdef WITH_PYTHON - virtual PyObject* py_repr(void); + virtual std::string GetName(); - static PyObject* pyattr_get_num_x(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_active_buttons(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_hat_values(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_axis_values(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_name(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); +#ifdef WITH_PYTHON + static PyObject* pyattr_get_num_x(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_active_buttons(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_hat_values(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_axis_values(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_name(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); #endif }; #endif //__SCA_PYTHONJOYSTICK_H__ + diff --git a/source/gameengine/GameLogic/SCA_PythonKeyboard.cpp b/source/gameengine/GameLogic/SCA_PythonKeyboard.cpp index 388ee5b9d4f9..b2ce8609e122 100644 --- a/source/gameengine/GameLogic/SCA_PythonKeyboard.cpp +++ b/source/gameengine/GameLogic/SCA_PythonKeyboard.cpp @@ -34,21 +34,14 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_PythonKeyboard::SCA_PythonKeyboard(SCA_IInputDevice* keyboard) -: PyObjectPlus(), -m_keyboard(keyboard) +SCA_PythonKeyboard::SCA_PythonKeyboard(SCA_IInputDevice *keyboard) + :EXP_PyObjectPlus(), + m_keyboard(keyboard) { -#ifdef WITH_PYTHON - m_event_dict = PyDict_New(); -#endif } SCA_PythonKeyboard::~SCA_PythonKeyboard() { -#ifdef WITH_PYTHON - PyDict_Clear(m_event_dict); - Py_DECREF(m_event_dict); -#endif } #ifdef WITH_PYTHON @@ -61,14 +54,15 @@ SCA_PythonKeyboard::~SCA_PythonKeyboard() static PyObject *gPyGetClipboard(PyObject *args, PyObject *kwds) { char *buf = (char *)GHOST_getClipboard(0); - return PyUnicode_FromString(buf?buf:""); + return PyUnicode_FromString(buf ? buf : ""); } static PyObject *gPySetClipboard(PyObject *args, PyObject *value) { - char* buf; - if (!PyArg_ParseTuple(value,"s:setClipboard",&buf)) + char *buf; + if (!PyArg_ParseTuple(value, "s:setClipboard", &buf)) { Py_RETURN_NONE; + } GHOST_putClipboard((GHOST_TInt8 *)buf, 0); Py_RETURN_NONE; @@ -76,9 +70,9 @@ static PyObject *gPySetClipboard(PyObject *args, PyObject *value) /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_PythonKeyboard::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_PythonKeyboard", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -86,68 +80,140 @@ PyTypeObject SCA_PythonKeyboard::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, - &PyObjectPlus::Type, - 0,0,0,0,0,0, + &EXP_PyObjectPlus::Type, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_PythonKeyboard::Methods[] = { - {"getClipboard", (PyCFunction) gPyGetClipboard, METH_VARARGS, "getCliboard doc"}, - {"setClipboard", (PyCFunction) gPySetClipboard, METH_VARARGS, "setCliboard doc"}, - {NULL,NULL} //Sentinel + {"getClipboard", (PyCFunction)gPyGetClipboard, METH_VARARGS, "getCliboard doc"}, + {"setClipboard", (PyCFunction)gPySetClipboard, METH_VARARGS, "setCliboard doc"}, + {nullptr, nullptr} //Sentinel }; PyAttributeDef SCA_PythonKeyboard::Attributes[] = { - KX_PYATTRIBUTE_RO_FUNCTION("events", SCA_PythonKeyboard, pyattr_get_events), - KX_PYATTRIBUTE_RO_FUNCTION("active_events", SCA_PythonKeyboard, pyattr_get_active_events), - { NULL } //Sentinel + EXP_PYATTRIBUTE_RO_FUNCTION("events", SCA_PythonKeyboard, pyattr_get_events), + EXP_PYATTRIBUTE_RO_FUNCTION("inputs", SCA_PythonKeyboard, pyattr_get_inputs), + EXP_PYATTRIBUTE_RO_FUNCTION("active_events", SCA_PythonKeyboard, pyattr_get_active_events), + EXP_PYATTRIBUTE_RO_FUNCTION("activeInputs", SCA_PythonKeyboard, pyattr_get_active_inputs), + EXP_PYATTRIBUTE_RO_FUNCTION("text", SCA_PythonKeyboard, pyattr_get_text), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *SCA_PythonKeyboard::pyattr_get_events(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_PythonKeyboard::pyattr_get_events(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_PythonKeyboard* self = static_cast(self_v); + SCA_PythonKeyboard *self = static_cast(self_v); + + EXP_ShowDeprecationWarning("keyboard.events", "keyboard.inputs"); + + PyObject *dict = PyDict_New(); + + for (int i = SCA_IInputDevice::BEGINKEY; i <= SCA_IInputDevice::ENDKEY; i++) + { + SCA_InputEvent& input = self->m_keyboard->GetInput((SCA_IInputDevice::SCA_EnumInputs)i); + int event = 0; + if (input.m_queue.empty()) { + event = input.m_status[input.m_status.size() - 1]; + } + else { + event = input.m_queue[input.m_queue.size() - 1]; + } - for (int i = SCA_IInputDevice::KX_BEGINKEY; i <= SCA_IInputDevice::KX_ENDKEY; i++) { - const SCA_InputEvent & inevent = self->m_keyboard->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i); - PyObject *key = PyLong_FromLong(i); - PyObject *value = PyLong_FromLong(inevent.m_status); + PyObject *key = PyLong_FromLong(i); + PyObject *value = PyLong_FromLong(event); - PyDict_SetItem(self->m_event_dict, key, value); + PyDict_SetItem(dict, key, value); Py_DECREF(key); Py_DECREF(value); } - Py_INCREF(self->m_event_dict); - return self->m_event_dict; + return dict; } -PyObject *SCA_PythonKeyboard::pyattr_get_active_events(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_PythonKeyboard::pyattr_get_inputs(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_PythonKeyboard* self = static_cast(self_v); + SCA_PythonKeyboard *self = static_cast(self_v); - PyDict_Clear(self->m_event_dict); + PyObject *dict = PyDict_New(); + + for (int i = SCA_IInputDevice::BEGINKEY; i <= SCA_IInputDevice::ENDKEY; i++) + { + SCA_InputEvent& input = self->m_keyboard->GetInput((SCA_IInputDevice::SCA_EnumInputs)i); + + PyObject *key = PyLong_FromLong(i); + + PyDict_SetItem(dict, key, input.GetProxy()); + + Py_DECREF(key); + } + return dict; +} + +PyObject *SCA_PythonKeyboard::pyattr_get_active_inputs(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + SCA_PythonKeyboard *self = static_cast(self_v); - for (int i = SCA_IInputDevice::KX_BEGINKEY; i <= SCA_IInputDevice::KX_ENDKEY; i++) { - const SCA_InputEvent & inevent = self->m_keyboard->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i); + PyObject *dict = PyDict_New(); - if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS) { - PyObject *key = PyLong_FromLong(i); - PyObject *value = PyLong_FromLong(inevent.m_status); + for (int i = SCA_IInputDevice::BEGINKEY; i <= SCA_IInputDevice::ENDKEY; i++) + { + SCA_InputEvent& input = self->m_keyboard->GetInput((SCA_IInputDevice::SCA_EnumInputs)i); - PyDict_SetItem(self->m_event_dict, key, value); + if (input.Find(SCA_InputEvent::ACTIVE)) { + PyObject *key = PyLong_FromLong(i); + + PyDict_SetItem(dict, key, input.GetProxy()); + + Py_DECREF(key); + } + } + return dict; +} + +PyObject *SCA_PythonKeyboard::pyattr_get_active_events(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + SCA_PythonKeyboard *self = static_cast(self_v); + + EXP_ShowDeprecationWarning("keyboard.active_events", "keyboard.activeInputs"); + + PyObject *dict = PyDict_New(); + + for (int i = SCA_IInputDevice::BEGINKEY; i <= SCA_IInputDevice::ENDKEY; i++) + { + SCA_InputEvent& input = self->m_keyboard->GetInput((SCA_IInputDevice::SCA_EnumInputs)i); + + if (input.Find(SCA_InputEvent::ACTIVE)) { + int event = 0; + if (input.m_queue.empty()) { + event = input.m_status[input.m_status.size() - 1]; + } + else { + event = input.m_queue[input.m_queue.size() - 1]; + } + + PyObject *key = PyLong_FromLong(i); + PyObject *value = PyLong_FromLong(event); + + PyDict_SetItem(dict, key, value); Py_DECREF(key); Py_DECREF(value); } } - Py_INCREF(self->m_event_dict); - return self->m_event_dict; + return dict; +} + +PyObject *SCA_PythonKeyboard::pyattr_get_text(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + SCA_PythonKeyboard *self = (SCA_PythonKeyboard *)self_v; + + return PyUnicode_FromWideChar(self->m_keyboard->GetText().c_str(), self->m_keyboard->GetText().size()); } #endif diff --git a/source/gameengine/GameLogic/SCA_PythonKeyboard.h b/source/gameengine/GameLogic/SCA_PythonKeyboard.h index 3cbe250378c8..61b3f1d5c9dc 100644 --- a/source/gameengine/GameLogic/SCA_PythonKeyboard.h +++ b/source/gameengine/GameLogic/SCA_PythonKeyboard.h @@ -29,21 +29,22 @@ #include "EXP_PyObjectPlus.h" -class SCA_PythonKeyboard : public PyObjectPlus +class SCA_PythonKeyboard : public EXP_PyObjectPlus { Py_Header private: class SCA_IInputDevice *m_keyboard; -#ifdef WITH_PYTHON - PyObject *m_event_dict; -#endif + public: SCA_PythonKeyboard(class SCA_IInputDevice* keyboard); virtual ~SCA_PythonKeyboard(); #ifdef WITH_PYTHON - static PyObject* pyattr_get_events(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_active_events(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_inputs(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_events(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_active_events(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_active_inputs(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_text(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); #endif }; diff --git a/source/gameengine/GameLogic/SCA_PythonMouse.cpp b/source/gameengine/GameLogic/SCA_PythonMouse.cpp index 111d8abe8c59..2760aba9846f 100644 --- a/source/gameengine/GameLogic/SCA_PythonMouse.cpp +++ b/source/gameengine/GameLogic/SCA_PythonMouse.cpp @@ -33,10 +33,10 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_PythonMouse::SCA_PythonMouse(SCA_IInputDevice* mouse, RAS_ICanvas* canvas) -: PyObjectPlus(), -m_mouse(mouse), -m_canvas(canvas) +SCA_PythonMouse::SCA_PythonMouse(SCA_IInputDevice *mouse, RAS_ICanvas *canvas) + :EXP_PyObjectPlus(), + m_mouse(mouse), + m_canvas(canvas) { #ifdef WITH_PYTHON m_event_dict = PyDict_New(); @@ -59,9 +59,9 @@ SCA_PythonMouse::~SCA_PythonMouse() /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_PythonMouse::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_PythonMouse", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -69,37 +69,50 @@ PyTypeObject SCA_PythonMouse::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, - &PyObjectPlus::Type, - 0,0,0,0,0,0, + &EXP_PyObjectPlus::Type, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_PythonMouse::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef SCA_PythonMouse::Attributes[] = { - KX_PYATTRIBUTE_RO_FUNCTION("events", SCA_PythonMouse, pyattr_get_events), - KX_PYATTRIBUTE_RO_FUNCTION("active_events", SCA_PythonMouse, pyattr_get_active_events), - KX_PYATTRIBUTE_RW_FUNCTION("position", SCA_PythonMouse, pyattr_get_position, pyattr_set_position), - KX_PYATTRIBUTE_RW_FUNCTION("visible", SCA_PythonMouse, pyattr_get_visible, pyattr_set_visible), - { NULL } //Sentinel + EXP_PYATTRIBUTE_RO_FUNCTION("events", SCA_PythonMouse, pyattr_get_events), + EXP_PYATTRIBUTE_RO_FUNCTION("inputs", SCA_PythonMouse, pyattr_get_inputs), + EXP_PYATTRIBUTE_RO_FUNCTION("active_events", SCA_PythonMouse, pyattr_get_active_events), + EXP_PYATTRIBUTE_RO_FUNCTION("activeInputs", SCA_PythonMouse, pyattr_get_active_inputs), + EXP_PYATTRIBUTE_RW_FUNCTION("position", SCA_PythonMouse, pyattr_get_position, pyattr_set_position), + EXP_PYATTRIBUTE_RW_FUNCTION("visible", SCA_PythonMouse, pyattr_get_visible, pyattr_set_visible), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *SCA_PythonMouse::pyattr_get_events(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_PythonMouse::pyattr_get_events(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_PythonMouse* self = static_cast(self_v); + SCA_PythonMouse *self = static_cast(self_v); - for (int i = SCA_IInputDevice::KX_BEGINMOUSE; i <= SCA_IInputDevice::KX_ENDMOUSE; i++) { - const SCA_InputEvent &inevent = self->m_mouse->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i); - PyObject *key = PyLong_FromLong(i); - PyObject *value = PyLong_FromLong(inevent.m_status); + EXP_ShowDeprecationWarning("mouse.events", "mouse.inputs"); + + for (int i = SCA_IInputDevice::BEGINMOUSE; i <= SCA_IInputDevice::ENDMOUSE; i++) + { + SCA_InputEvent& input = self->m_mouse->GetInput((SCA_IInputDevice::SCA_EnumInputs)i); + int event = 0; + if (input.m_queue.empty()) { + event = input.m_status[input.m_status.size() - 1]; + } + else { + event = input.m_queue[input.m_queue.size() - 1]; + } + + PyObject *key = PyLong_FromLong(i); + PyObject *value = PyLong_FromLong(event); PyDict_SetItem(self->m_event_dict, key, value); @@ -110,19 +123,47 @@ PyObject *SCA_PythonMouse::pyattr_get_events(void *self_v, const KX_PYATTRIBUTE_ return self->m_event_dict; } -PyObject *SCA_PythonMouse::pyattr_get_active_events(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_PythonMouse::pyattr_get_inputs(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + SCA_PythonMouse *self = static_cast(self_v); + + for (int i = SCA_IInputDevice::BEGINMOUSE; i <= SCA_IInputDevice::ENDMOUSE; i++) + { + SCA_InputEvent& input = self->m_mouse->GetInput((SCA_IInputDevice::SCA_EnumInputs)i); + + PyObject *key = PyLong_FromLong(i); + + PyDict_SetItem(self->m_event_dict, key, input.GetProxy()); + + Py_DECREF(key); + } + Py_INCREF(self->m_event_dict); + return self->m_event_dict; +} + +PyObject *SCA_PythonMouse::pyattr_get_active_events(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_PythonMouse* self = static_cast(self_v); + SCA_PythonMouse *self = static_cast(self_v); + + EXP_ShowDeprecationWarning("mouse.active_events", "mouse.activeInputs"); PyDict_Clear(self->m_event_dict); - for (int i = SCA_IInputDevice::KX_BEGINMOUSE; i <= SCA_IInputDevice::KX_ENDMOUSE; i++) { - const SCA_InputEvent &inevent = self->m_mouse->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i); + for (int i = SCA_IInputDevice::BEGINMOUSE; i <= SCA_IInputDevice::ENDMOUSE; i++) + { + SCA_InputEvent& input = self->m_mouse->GetInput((SCA_IInputDevice::SCA_EnumInputs)i); - if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS) { + if (input.Find(SCA_InputEvent::ACTIVE)) { + int event = 0; + if (input.m_queue.empty()) { + event = input.m_status[input.m_status.size() - 1]; + } + else { + event = input.m_queue[input.m_queue.size() - 1]; + } - PyObject *key = PyLong_FromLong(i); - PyObject *value = PyLong_FromLong(inevent.m_status); + PyObject *key = PyLong_FromLong(i); + PyObject *value = PyLong_FromLong(event); PyDict_SetItem(self->m_event_dict, key, value); @@ -134,16 +175,38 @@ PyObject *SCA_PythonMouse::pyattr_get_active_events(void *self_v, const KX_PYATT return self->m_event_dict; } -PyObject *SCA_PythonMouse::pyattr_get_position(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_PythonMouse::pyattr_get_active_inputs(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + SCA_PythonMouse *self = static_cast(self_v); + + PyDict_Clear(self->m_event_dict); + + for (int i = SCA_IInputDevice::BEGINMOUSE; i <= SCA_IInputDevice::ENDMOUSE; i++) + { + SCA_InputEvent& input = self->m_mouse->GetInput((SCA_IInputDevice::SCA_EnumInputs)i); + + if (input.Find(SCA_InputEvent::ACTIVE)) { + PyObject *key = PyLong_FromLong(i); + + PyDict_SetItem(self->m_event_dict, key, input.GetProxy()); + + Py_DECREF(key); + } + } + Py_INCREF(self->m_event_dict); + return self->m_event_dict; +} + +PyObject *SCA_PythonMouse::pyattr_get_position(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_PythonMouse* self = static_cast(self_v); - const SCA_InputEvent & xevent = self->m_mouse->GetEventValue(SCA_IInputDevice::KX_MOUSEX); - const SCA_InputEvent & yevent = self->m_mouse->GetEventValue(SCA_IInputDevice::KX_MOUSEY); + SCA_PythonMouse *self = static_cast(self_v); + const SCA_InputEvent& xevent = self->m_mouse->GetInput(SCA_IInputDevice::MOUSEX); + const SCA_InputEvent& yevent = self->m_mouse->GetInput(SCA_IInputDevice::MOUSEY); float x_coord, y_coord; - x_coord = self->m_canvas->GetMouseNormalizedX(xevent.m_eventval); - y_coord = self->m_canvas->GetMouseNormalizedY(yevent.m_eventval); + x_coord = self->m_canvas->GetMouseNormalizedX(xevent.m_values[xevent.m_values.size() - 1]); + y_coord = self->m_canvas->GetMouseNormalizedY(yevent.m_values[yevent.m_values.size() - 1]); PyObject *ret = PyTuple_New(2); @@ -153,52 +216,56 @@ PyObject *SCA_PythonMouse::pyattr_get_position(void *self_v, const KX_PYATTRIBUT return ret; } -int SCA_PythonMouse::pyattr_set_position(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int SCA_PythonMouse::pyattr_set_position(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - SCA_PythonMouse* self = static_cast(self_v); + SCA_PythonMouse *self = static_cast(self_v); int x, y; float pyx, pyy; - if (!PyArg_ParseTuple(value, "ff:position", &pyx, &pyy)) + if (!PyArg_ParseTuple(value, "ff:position", &pyx, &pyy)) { return PY_SET_ATTR_FAIL; + } - x = (int)(pyx*self->m_canvas->GetWidth()); - y = (int)(pyy*self->m_canvas->GetHeight()); + x = (int)(pyx * self->m_canvas->GetMaxX()); + y = (int)(pyy * self->m_canvas->GetMaxY()); self->m_canvas->SetMousePosition(x, y); return PY_SET_ATTR_SUCCESS; } -PyObject *SCA_PythonMouse::pyattr_get_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_PythonMouse::pyattr_get_visible(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_PythonMouse* self = static_cast(self_v); + SCA_PythonMouse *self = static_cast(self_v); int visible; - if (self->m_canvas->GetMouseState() == RAS_ICanvas::MOUSE_INVISIBLE) + if (self->m_canvas->GetMouseState() == RAS_ICanvas::MOUSE_INVISIBLE) { visible = 0; - else + } + else { visible = 1; + } return PyBool_FromLong(visible); } -int SCA_PythonMouse::pyattr_set_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int SCA_PythonMouse::pyattr_set_visible(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - SCA_PythonMouse* self = static_cast(self_v); + SCA_PythonMouse *self = static_cast(self_v); int visible = PyObject_IsTrue(value); - if (visible == -1) - { + if (visible == -1) { PyErr_SetString(PyExc_AttributeError, "SCA_PythonMouse.visible = bool: SCA_PythonMouse, expected True or False"); return PY_SET_ATTR_FAIL; } - if (visible) + if (visible) { self->m_canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL); - else + } + else { self->m_canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE); + } return PY_SET_ATTR_SUCCESS; } diff --git a/source/gameengine/GameLogic/SCA_PythonMouse.h b/source/gameengine/GameLogic/SCA_PythonMouse.h index 6dde90b34820..00dbf9f57da3 100644 --- a/source/gameengine/GameLogic/SCA_PythonMouse.h +++ b/source/gameengine/GameLogic/SCA_PythonMouse.h @@ -29,7 +29,7 @@ #include "EXP_PyObjectPlus.h" -class SCA_PythonMouse : public PyObjectPlus +class SCA_PythonMouse : public EXP_PyObjectPlus { Py_Header private: @@ -45,14 +45,16 @@ class SCA_PythonMouse : public PyObjectPlus void Show(bool visible); #ifdef WITH_PYTHON - KX_PYMETHOD_DOC(SCA_PythonMouse, show); - - static PyObject *pyattr_get_events(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_active_events(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_position(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_position(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject *pyattr_get_visible(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_visible(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + EXP_PYMETHOD_DOC(SCA_PythonMouse, show); + + static PyObject *pyattr_get_events(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_inputs(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_active_events(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_active_inputs(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_position(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_position(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_visible(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_visible(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); #endif }; diff --git a/source/gameengine/GameLogic/SCA_RandomActuator.cpp b/source/gameengine/GameLogic/SCA_RandomActuator.cpp index 121be5f003ed..8cbb5ac0bcaa 100644 --- a/source/gameengine/GameLogic/SCA_RandomActuator.cpp +++ b/source/gameengine/GameLogic/SCA_RandomActuator.cpp @@ -33,15 +33,16 @@ */ -#include #include +#include #include "EXP_BoolValue.h" #include "EXP_IntValue.h" #include "EXP_FloatValue.h" #include "SCA_IActuator.h" #include "SCA_RandomActuator.h" -#include "MT_Transform.h" + +#include "CM_Message.h" /* ------------------------------------------------------------------------- */ /* Native functions */ @@ -52,12 +53,12 @@ SCA_RandomActuator::SCA_RandomActuator(SCA_IObject *gameobj, SCA_RandomActuator::KX_RANDOMACT_MODE mode, float para1, float para2, - const STR_String &propName) - : SCA_IActuator(gameobj, KX_ACT_RANDOM), - m_propname(propName), - m_parameter1(para1), - m_parameter2(para2), - m_distribution(mode) + const std::string &propName) + :SCA_IActuator(gameobj, KX_ACT_RANDOM), + m_propname(propName), + m_parameter1(para1), + m_parameter2(para2), + m_distribution(mode) { m_base = new SCA_RandomNumberGenerator(seed); m_counter = 0; @@ -73,9 +74,9 @@ SCA_RandomActuator::~SCA_RandomActuator() -CValue* SCA_RandomActuator::GetReplica() +EXP_Value *SCA_RandomActuator::GetReplica() { - SCA_RandomActuator* replica = new SCA_RandomActuator(*this); + SCA_RandomActuator *replica = new SCA_RandomActuator(*this); // replication just copy the m_base pointer => common random generator replica->ProcessReplica(); return replica; @@ -98,152 +99,166 @@ bool SCA_RandomActuator::Update() RemoveAllEvents(); - CValue *tmpval = NULL; + EXP_Value *tmpval = nullptr; - if (bNegativeEvent) + if (bNegativeEvent) { return false; // do nothing on negative events - switch (m_distribution) { - case KX_RANDOMACT_BOOL_CONST: { - /* un petit peu filthy */ - bool res = !(m_parameter1 < 0.5); - tmpval = new CBoolValue(res); } - break; - case KX_RANDOMACT_BOOL_UNIFORM: { - /* flip a coin */ - bool res; - if (m_counter > 31) { - m_previous = m_base->Draw(); - res = ((m_previous & 0x1) == 0); - m_counter = 1; - } else { - res = (((m_previous >> m_counter) & 0x1) == 0); - m_counter++; + switch (m_distribution) { + case KX_RANDOMACT_BOOL_CONST: + { + /* un petit peu filthy */ + bool res = !(m_parameter1 < 0.5); + tmpval = new EXP_BoolValue(res); + break; } - tmpval = new CBoolValue(res); - } - break; - case KX_RANDOMACT_BOOL_BERNOUILLI: { - /* 'percentage' */ - bool res; - res = (m_base->DrawFloat() < m_parameter1); - tmpval = new CBoolValue(res); - } - break; - case KX_RANDOMACT_INT_CONST: { - /* constant */ - tmpval = new CIntValue((int) floor(m_parameter1)); - } - break; - case KX_RANDOMACT_INT_UNIFORM: { - /* uniform (toss a die) */ - int res; - /* The [0, 1] interval is projected onto the [min, max+1] domain, */ - /* and then rounded. */ - res = (int)floor( ((m_parameter2 - m_parameter1 + 1) * m_base->DrawFloat()) + m_parameter1); - tmpval = new CIntValue(res); - } - break; - case KX_RANDOMACT_INT_POISSON: { - /* poisson (queues) */ - /* If x_1, x_2, ... is a sequence of random numbers with uniform */ - /* distribution between zero and one, k is the first integer for */ - /* which the product x_1*x_2*...*x_k < exp(-\lamba). */ - float a, b; - int res = 0; - /* The - sign is important here! The number to test for, a, must be */ - /* between 0 and 1. */ - a = exp(-m_parameter1); - /* a quickly reaches 0.... so we guard explicitly for that. */ - if (a < FLT_MIN) a = FLT_MIN; - b = m_base->DrawFloat(); - while (b >= a) { - b = b * m_base->DrawFloat(); - res++; - }; - tmpval = new CIntValue(res); - } - break; - case KX_RANDOMACT_FLOAT_CONST: { - /* constant */ - tmpval = new CFloatValue(m_parameter1); - } - break; - case KX_RANDOMACT_FLOAT_UNIFORM: { - float res = ((m_parameter2 - m_parameter1) * m_base->DrawFloat()) + m_parameter1; - tmpval = new CFloatValue(res); - } - break; - case KX_RANDOMACT_FLOAT_NORMAL: { - /* normal (big numbers): para1 = mean, para2 = std dev */ - - /* 070301 - nzc: Changed the termination condition. I think I - * made a small mistake here, but it only affects distro's where - * the seed equals 0. In that case, the algorithm locks. Let's - * just guard that case separately. - */ - - float x = 0.0, y = 0.0, s = 0.0, t = 0.0; - if (m_base->GetSeed() == 0) { - /* 070301 - nzc: Just taking the mean here seems reasonable. */ - tmpval = new CFloatValue(m_parameter1); + case KX_RANDOMACT_BOOL_UNIFORM: + { + /* flip a coin */ + bool res; + if (m_counter > 31) { + m_previous = m_base->Draw(); + res = ((m_previous & 0x1) == 0); + m_counter = 1; + } + else { + res = (((m_previous >> m_counter) & 0x1) == 0); + m_counter++; + } + tmpval = new EXP_BoolValue(res); + break; } - else { - /* 070301 - nzc - * Now, with seed != 0, we will most assuredly get some - * sensible values. The termination condition states two - * things: - * 1. s >= 0 is not allowed: to prevent the distro from - * getting a bias towards high values. This is a small - * correction, really, and might also be left out. - * 2. s == 0 is not allowed: to prevent a division by zero - * when renormalising the drawn value to the desired - * distribution shape. As a side effect, the distro will - * never yield the exact mean. - * I am not sure whether this is consistent, since the error - * cause by #2 is of the same magnitude as the one - * prevented by #1. The error introduced into the SD will be - * improved, though. By how much? Hard to say... If you like - * the maths, feel free to analyse. Be aware that this is - * one of the really old standard algorithms. I think the - * original came in Fortran, was translated to Pascal, and - * then someone came up with the C code. My guess it that - * this will be quite sufficient here. - */ - do { - x = 2.0f * m_base->DrawFloat() - 1.0f; - y = 2.0f * m_base->DrawFloat() - 1.0f; - s = x * x + y * y; - } while ((s >= 1.0f) || (s == 0.0f)); - t = x * sqrtf((-2.0 * log(s)) / s); - tmpval = new CFloatValue(m_parameter1 + m_parameter2 * t); + case KX_RANDOMACT_BOOL_BERNOUILLI: + { + /* 'percentage' */ + bool res; + res = (m_base->DrawFloat() < m_parameter1); + tmpval = new EXP_BoolValue(res); + break; } - } - break; - case KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL: { - /* 1st order fall-off. I am very partial to using the half-life as */ - /* controlling parameter. Using the 'normal' exponent is not very */ - /* intuitive... */ - /* tmpval = new CFloatValue( (1.0 / m_parameter1) */ - tmpval = new CFloatValue((m_parameter1) * (-log(1.0 - m_base->DrawFloat()))); + case KX_RANDOMACT_INT_CONST: + { + /* constant */ + tmpval = new EXP_IntValue((int)floor(m_parameter1)); + break; + } + case KX_RANDOMACT_INT_UNIFORM: + { + /* uniform (toss a die) */ + int res; + /* The [0, 1] interval is projected onto the [min, max+1] domain, */ + /* and then rounded. */ + res = (int)floor(((m_parameter2 - m_parameter1 + 1) * m_base->DrawFloat()) + m_parameter1); + tmpval = new EXP_IntValue(res); + break; + } + case KX_RANDOMACT_INT_POISSON: + { + /* poisson (queues) */ + /* If x_1, x_2, ... is a sequence of random numbers with uniform */ + /* distribution between zero and one, k is the first integer for */ + /* which the product x_1*x_2*...*x_k < exp(-\lamba). */ + float a, b; + int res = 0; + /* The - sign is important here! The number to test for, a, must be */ + /* between 0 and 1. */ + a = exp(-m_parameter1); + /* a quickly reaches 0.... so we guard explicitly for that. */ + if (a < FLT_MIN) { + a = FLT_MIN; + } + b = m_base->DrawFloat(); + while (b >= a) { + b = b * m_base->DrawFloat(); + res++; + }; + tmpval = new EXP_IntValue(res); + break; + } + case KX_RANDOMACT_FLOAT_CONST: + { + /* constant */ + tmpval = new EXP_FloatValue(m_parameter1); + break; + } + case KX_RANDOMACT_FLOAT_UNIFORM: + { + float res = ((m_parameter2 - m_parameter1) * m_base->DrawFloat()) + m_parameter1; + tmpval = new EXP_FloatValue(res); + break; + } + case KX_RANDOMACT_FLOAT_NORMAL: + { + /* normal (big numbers): para1 = mean, para2 = std dev */ + + /* 070301 - nzc: Changed the termination condition. I think I + * made a small mistake here, but it only affects distro's where + * the seed equals 0. In that case, the algorithm locks. Let's + * just guard that case separately. + */ - } - break; - default: - { - /* unknown distribution... */ - static bool randomWarning = false; - if (!randomWarning) { - randomWarning = true; - std::cout << "RandomActuator '" << GetName() << "' has an unknown distribution." << std::endl; + float x = 0.0, y = 0.0, s = 0.0, t = 0.0; + if (m_base->GetSeed() == 0) { + /* 070301 - nzc: Just taking the mean here seems reasonable. */ + tmpval = new EXP_FloatValue(m_parameter1); + } + else { + /* 070301 - nzc + * Now, with seed != 0, we will most assuredly get some + * sensible values. The termination condition states two + * things: + * 1. s >= 0 is not allowed: to prevent the distro from + * getting a bias towards high values. This is a small + * correction, really, and might also be left out. + * 2. s == 0 is not allowed: to prevent a division by zero + * when renormalising the drawn value to the desired + * distribution shape. As a side effect, the distro will + * never yield the exact mean. + * I am not sure whether this is consistent, since the error + * cause by #2 is of the same magnitude as the one + * prevented by #1. The error introduced into the SD will be + * improved, though. By how much? Hard to say... If you like + * the maths, feel free to analyse. Be aware that this is + * one of the really old standard algorithms. I think the + * original came in Fortran, was translated to Pascal, and + * then someone came up with the C code. My guess it that + * this will be quite sufficient here. + */ + do { + x = 2.0f * m_base->DrawFloat() - 1.0f; + y = 2.0f * m_base->DrawFloat() - 1.0f; + s = x * x + y * y; + } while ((s >= 1.0f) || (s == 0.0f)); + t = x * sqrtf((-2.0 * log(s)) / s); + tmpval = new EXP_FloatValue(m_parameter1 + m_parameter2 * t); + } + break; + } + case KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL: + { + /* 1st order fall-off. I am very partial to using the half-life as */ + /* controlling parameter. Using the 'normal' exponent is not very */ + /* intuitive... */ + /* tmpval = new EXP_FloatValue( (1.0 / m_parameter1) */ + tmpval = new EXP_FloatValue((m_parameter1) * (-log(1.0 - m_base->DrawFloat()))); + + break; + } + default: + { + /* unknown distribution... */ + static bool randomWarning = false; + if (!randomWarning) { + randomWarning = true; + CM_LogicBrickWarning(this, "unknown distribution."); + } + return false; } - return false; - } } /* Round up: assign it */ - CValue *prop = GetParent()->GetProperty(m_propname); + EXP_Value *prop = GetParent()->GetProperty(m_propname); if (prop) { prop->SetValue(tmpval); } @@ -258,43 +273,54 @@ void SCA_RandomActuator::enforceConstraints() /* the various distributions. Limitations of the algorithms are checked */ /* elsewhere (or they should be... ). */ switch (m_distribution) { - case KX_RANDOMACT_BOOL_CONST: - case KX_RANDOMACT_BOOL_UNIFORM: - case KX_RANDOMACT_INT_CONST: - case KX_RANDOMACT_INT_UNIFORM: - case KX_RANDOMACT_FLOAT_UNIFORM: - case KX_RANDOMACT_FLOAT_CONST: - ; /* Nothing to be done here. We allow uniform distro's to have */ - /* 'funny' domains, i.e. max < min. This does not give problems. */ - break; - case KX_RANDOMACT_BOOL_BERNOUILLI: - /* clamp to [0, 1] */ - if (m_parameter1 < 0.0) { - m_parameter1 = 0.0; - } else if (m_parameter1 > 1.0) { - m_parameter1 = 1.0; + case KX_RANDOMACT_BOOL_CONST: + case KX_RANDOMACT_BOOL_UNIFORM: + case KX_RANDOMACT_INT_CONST: + case KX_RANDOMACT_INT_UNIFORM: + case KX_RANDOMACT_FLOAT_UNIFORM: + case KX_RANDOMACT_FLOAT_CONST: + { + ; /* Nothing to be done here. We allow uniform distro's to have */ + /* 'funny' domains, i.e. max < min. This does not give problems. */ + break; + } + case KX_RANDOMACT_BOOL_BERNOUILLI: + { + /* clamp to [0, 1] */ + if (m_parameter1 < 0.0) { + m_parameter1 = 0.0; + } + else if (m_parameter1 > 1.0) { + m_parameter1 = 1.0; + } + break; } - break; - case KX_RANDOMACT_INT_POISSON: - /* non-negative */ - if (m_parameter1 < 0.0) { - m_parameter1 = 0.0; + case KX_RANDOMACT_INT_POISSON: + { + /* non-negative */ + if (m_parameter1 < 0.0) { + m_parameter1 = 0.0; + } + break; } - break; - case KX_RANDOMACT_FLOAT_NORMAL: - /* standard dev. is non-negative */ - if (m_parameter2 < 0.0) { - m_parameter2 = 0.0; + case KX_RANDOMACT_FLOAT_NORMAL: + { + /* standard dev. is non-negative */ + if (m_parameter2 < 0.0) { + m_parameter2 = 0.0; + } + break; } - break; - case KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL: - /* halflife must be non-negative */ - if (m_parameter1 < 0.0) { - m_parameter1 = 0.0; + case KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL: + { + /* halflife must be non-negative */ + if (m_parameter1 < 0.0) { + m_parameter1 = 0.0; + } + break; } - break; - default: - ; /* unknown distribution... */ + default: + ; /* unknown distribution... */ } } @@ -306,9 +332,9 @@ void SCA_RandomActuator::enforceConstraints() /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_RandomActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_RandomActuator", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -316,51 +342,51 @@ PyTypeObject SCA_RandomActuator::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IActuator::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_RandomActuator::Methods[] = { - KX_PYMETHODTABLE(SCA_RandomActuator, setBoolConst), - KX_PYMETHODTABLE_NOARGS(SCA_RandomActuator, setBoolUniform), - KX_PYMETHODTABLE(SCA_RandomActuator, setBoolBernouilli), - - KX_PYMETHODTABLE(SCA_RandomActuator, setIntConst), - KX_PYMETHODTABLE(SCA_RandomActuator, setIntUniform), - KX_PYMETHODTABLE(SCA_RandomActuator, setIntPoisson), - - KX_PYMETHODTABLE(SCA_RandomActuator, setFloatConst), - KX_PYMETHODTABLE(SCA_RandomActuator, setFloatUniform), - KX_PYMETHODTABLE(SCA_RandomActuator, setFloatNormal), - KX_PYMETHODTABLE(SCA_RandomActuator, setFloatNegativeExponential), - {NULL,NULL} //Sentinel + EXP_PYMETHODTABLE(SCA_RandomActuator, setBoolConst), + EXP_PYMETHODTABLE_NOARGS(SCA_RandomActuator, setBoolUniform), + EXP_PYMETHODTABLE(SCA_RandomActuator, setBoolBernouilli), + + EXP_PYMETHODTABLE(SCA_RandomActuator, setIntConst), + EXP_PYMETHODTABLE(SCA_RandomActuator, setIntUniform), + EXP_PYMETHODTABLE(SCA_RandomActuator, setIntPoisson), + + EXP_PYMETHODTABLE(SCA_RandomActuator, setFloatConst), + EXP_PYMETHODTABLE(SCA_RandomActuator, setFloatUniform), + EXP_PYMETHODTABLE(SCA_RandomActuator, setFloatNormal), + EXP_PYMETHODTABLE(SCA_RandomActuator, setFloatNegativeExponential), + {nullptr, nullptr} //Sentinel }; PyAttributeDef SCA_RandomActuator::Attributes[] = { - KX_PYATTRIBUTE_FLOAT_RO("para1",SCA_RandomActuator,m_parameter1), - KX_PYATTRIBUTE_FLOAT_RO("para2",SCA_RandomActuator,m_parameter2), - KX_PYATTRIBUTE_ENUM_RO("distribution",SCA_RandomActuator,m_distribution), - KX_PYATTRIBUTE_STRING_RW_CHECK("propName",0,MAX_PROP_NAME,false,SCA_RandomActuator,m_propname,CheckProperty), - KX_PYATTRIBUTE_RW_FUNCTION("seed",SCA_RandomActuator,pyattr_get_seed,pyattr_set_seed), - { NULL } //Sentinel + EXP_PYATTRIBUTE_FLOAT_RO("para1", SCA_RandomActuator, m_parameter1), + EXP_PYATTRIBUTE_FLOAT_RO("para2", SCA_RandomActuator, m_parameter2), + EXP_PYATTRIBUTE_ENUM_RO("distribution", SCA_RandomActuator, m_distribution), + EXP_PYATTRIBUTE_STRING_RW_CHECK("propName", 0, MAX_PROP_NAME, false, SCA_RandomActuator, m_propname, CheckProperty), + EXP_PYATTRIBUTE_RW_FUNCTION("seed", SCA_RandomActuator, pyattr_get_seed, pyattr_set_seed), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *SCA_RandomActuator::pyattr_get_seed(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_RandomActuator::pyattr_get_seed(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_RandomActuator* act = static_cast(self); + SCA_RandomActuator *act = static_cast(self); return PyLong_FromLong(act->m_base->GetSeed()); } -int SCA_RandomActuator::pyattr_set_seed(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int SCA_RandomActuator::pyattr_set_seed(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - SCA_RandomActuator* act = static_cast(self); + SCA_RandomActuator *act = static_cast(self); if (PyLong_Check(value)) { act->m_base->SetSeed(PyLong_AsLong(value)); return PY_SET_ATTR_SUCCESS; @@ -372,14 +398,14 @@ int SCA_RandomActuator::pyattr_set_seed(void *self, const struct KX_PYATTRIBUTE_ } /* 11. setBoolConst */ -KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setBoolConst, -"setBoolConst(value)\n" -"\t- value: 0 or 1\n" -"\tSet this generator to produce a constant boolean value.\n") +EXP_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setBoolConst, + "setBoolConst(value)\n" + "\t- value: 0 or 1\n" + "\tSet this generator to produce a constant boolean value.\n") { int paraArg; if (!PyArg_ParseTuple(args, "i:setBoolConst", ¶Arg)) { - return NULL; + return nullptr; } m_distribution = KX_RANDOMACT_BOOL_CONST; @@ -388,9 +414,9 @@ KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setBoolConst, Py_RETURN_NONE; } /* 12. setBoolUniform, */ -KX_PYMETHODDEF_DOC_NOARGS(SCA_RandomActuator, setBoolUniform, -"setBoolUniform()\n" -"\tSet this generator to produce true and false, each with 50%% chance of occurring\n") +EXP_PYMETHODDEF_DOC_NOARGS(SCA_RandomActuator, setBoolUniform, + "setBoolUniform()\n" + "\tSet this generator to produce true and false, each with 50%% chance of occurring\n") { /* no args */ m_distribution = KX_RANDOMACT_BOOL_UNIFORM; @@ -398,14 +424,14 @@ KX_PYMETHODDEF_DOC_NOARGS(SCA_RandomActuator, setBoolUniform, Py_RETURN_NONE; } /* 13. setBoolBernouilli, */ -KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setBoolBernouilli, -"setBoolBernouilli(value)\n" -"\t- value: a float between 0 and 1\n" -"\tReturn false value * 100%% of the time.\n") +EXP_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setBoolBernouilli, + "setBoolBernouilli(value)\n" + "\t- value: a float between 0 and 1\n" + "\tReturn false value * 100%% of the time.\n") { float paraArg; if (!PyArg_ParseTuple(args, "f:setBoolBernouilli", ¶Arg)) { - return NULL; + return nullptr; } m_distribution = KX_RANDOMACT_BOOL_BERNOUILLI; @@ -414,14 +440,14 @@ KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setBoolBernouilli, Py_RETURN_NONE; } /* 14. setIntConst,*/ -KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setIntConst, -"setIntConst(value)\n" -"\t- value: integer\n" -"\tAlways return value\n") +EXP_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setIntConst, + "setIntConst(value)\n" + "\t- value: integer\n" + "\tAlways return value\n") { int paraArg; if (!PyArg_ParseTuple(args, "i:setIntConst", ¶Arg)) { - return NULL; + return nullptr; } m_distribution = KX_RANDOMACT_INT_CONST; @@ -430,16 +456,16 @@ KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setIntConst, Py_RETURN_NONE; } /* 15. setIntUniform,*/ -KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setIntUniform, -"setIntUniform(lower_bound, upper_bound)\n" -"\t- lower_bound: integer\n" -"\t- upper_bound: integer\n" -"\tReturn a random integer between lower_bound and\n" -"\tupper_bound. The boundaries are included.\n") +EXP_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setIntUniform, + "setIntUniform(lower_bound, upper_bound)\n" + "\t- lower_bound: integer\n" + "\t- upper_bound: integer\n" + "\tReturn a random integer between lower_bound and\n" + "\tupper_bound. The boundaries are included.\n") { int paraArg1, paraArg2; if (!PyArg_ParseTuple(args, "ii:setIntUniform", ¶Arg1, ¶Arg2)) { - return NULL; + return nullptr; } m_distribution = KX_RANDOMACT_INT_UNIFORM; @@ -449,16 +475,16 @@ KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setIntUniform, Py_RETURN_NONE; } /* 16. setIntPoisson, */ -KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setIntPoisson, -"setIntPoisson(value)\n" -"\t- value: float\n" -"\tReturn a Poisson-distributed number. This performs a series\n" -"\tof Bernouilli tests with parameter value. It returns the\n" -"\tnumber of tries needed to achieve succes.\n") +EXP_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setIntPoisson, + "setIntPoisson(value)\n" + "\t- value: float\n" + "\tReturn a Poisson-distributed number. This performs a series\n" + "\tof Bernouilli tests with parameter value. It returns the\n" + "\tnumber of tries needed to achieve succes.\n") { float paraArg; if (!PyArg_ParseTuple(args, "f:setIntPoisson", ¶Arg)) { - return NULL; + return nullptr; } m_distribution = KX_RANDOMACT_INT_POISSON; @@ -467,14 +493,14 @@ KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setIntPoisson, Py_RETURN_NONE; } /* 17. setFloatConst */ -KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setFloatConst, -"setFloatConst(value)\n" -"\t- value: float\n" -"\tAlways return value\n") +EXP_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setFloatConst, + "setFloatConst(value)\n" + "\t- value: float\n" + "\tAlways return value\n") { float paraArg; if (!PyArg_ParseTuple(args, "f:setFloatConst", ¶Arg)) { - return NULL; + return nullptr; } m_distribution = KX_RANDOMACT_FLOAT_CONST; @@ -483,16 +509,16 @@ KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setFloatConst, Py_RETURN_NONE; } /* 18. setFloatUniform, */ -KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setFloatUniform, -"setFloatUniform(lower_bound, upper_bound)\n" -"\t- lower_bound: float\n" -"\t- upper_bound: float\n" -"\tReturn a random integer between lower_bound and\n" -"\tupper_bound.\n") +EXP_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setFloatUniform, + "setFloatUniform(lower_bound, upper_bound)\n" + "\t- lower_bound: float\n" + "\t- upper_bound: float\n" + "\tReturn a random integer between lower_bound and\n" + "\tupper_bound.\n") { float paraArg1, paraArg2; if (!PyArg_ParseTuple(args, "ff:setFloatUniform", ¶Arg1, ¶Arg2)) { - return NULL; + return nullptr; } m_distribution = KX_RANDOMACT_FLOAT_UNIFORM; @@ -502,16 +528,16 @@ KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setFloatUniform, Py_RETURN_NONE; } /* 19. setFloatNormal, */ -KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setFloatNormal, -"setFloatNormal(mean, standard_deviation)\n" -"\t- mean: float\n" -"\t- standard_deviation: float\n" -"\tReturn normal-distributed numbers. The average is mean, and the\n" -"\tdeviation from the mean is characterized by standard_deviation.\n") +EXP_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setFloatNormal, + "setFloatNormal(mean, standard_deviation)\n" + "\t- mean: float\n" + "\t- standard_deviation: float\n" + "\tReturn normal-distributed numbers. The average is mean, and the\n" + "\tdeviation from the mean is characterized by standard_deviation.\n") { float paraArg1, paraArg2; if (!PyArg_ParseTuple(args, "ff:setFloatNormal", ¶Arg1, ¶Arg2)) { - return NULL; + return nullptr; } m_distribution = KX_RANDOMACT_FLOAT_NORMAL; @@ -521,15 +547,15 @@ KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setFloatNormal, Py_RETURN_NONE; } /* 20. setFloatNegativeExponential, */ -KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setFloatNegativeExponential, -"setFloatNegativeExponential(half_life)\n" -"\t- half_life: float\n" -"\tReturn negative-exponentially distributed numbers. The half-life 'time'\n" -"\tis characterized by half_life.\n") +EXP_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setFloatNegativeExponential, + "setFloatNegativeExponential(half_life)\n" + "\t- half_life: float\n" + "\tReturn negative-exponentially distributed numbers. The half-life 'time'\n" + "\tis characterized by half_life.\n") { float paraArg; if (!PyArg_ParseTuple(args, "f:setFloatNegativeExponential", ¶Arg)) { - return NULL; + return nullptr; } m_distribution = KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL; diff --git a/source/gameengine/GameLogic/SCA_RandomActuator.h b/source/gameengine/GameLogic/SCA_RandomActuator.h index 07ceff1e9c58..46599d4ff5dd 100644 --- a/source/gameengine/GameLogic/SCA_RandomActuator.h +++ b/source/gameengine/GameLogic/SCA_RandomActuator.h @@ -40,12 +40,12 @@ class SCA_RandomActuator : public SCA_IActuator { Py_Header /** Property to assign to */ - STR_String m_propname; - - /** First parameter. The meaning of the parameters depends on the + std::string m_propname; + + /** First parameter. The meaning of the parameters depends on the * distribution */ float m_parameter1; - /** Second parameter. The meaning of the parameters depends on the + /** Second parameter. The meaning of the parameters depends on the * distribution */ float m_parameter2; @@ -60,7 +60,7 @@ class SCA_RandomActuator : public SCA_IActuator /** apply constraints for the chosen distribution to the parameters */ void enforceConstraints(void); - + public: enum KX_RANDOMACT_MODE { @@ -79,41 +79,42 @@ class SCA_RandomActuator : public SCA_IActuator }; /** distribution type */ KX_RANDOMACT_MODE m_distribution; - + SCA_RandomActuator(class SCA_IObject* gameobj, long seed, KX_RANDOMACT_MODE mode, float para1, float para2, - const STR_String &propName); + const std::string &propName); virtual ~SCA_RandomActuator(); virtual bool Update(); - - virtual CValue* GetReplica(); + + virtual EXP_Value* GetReplica(); virtual void ProcessReplica(); #ifdef WITH_PYTHON - + /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - static PyObject *pyattr_get_seed(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_seed(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_seed(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_seed(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); - KX_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setBoolConst); - KX_PYMETHOD_DOC_NOARGS(SCA_RandomActuator, setBoolUniform); - KX_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setBoolBernouilli); - KX_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setIntConst); - KX_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setIntUniform); - KX_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setIntPoisson); - KX_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setFloatConst); - KX_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setFloatUniform); - KX_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setFloatNormal); - KX_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setFloatNegativeExponential); + EXP_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setBoolConst); + EXP_PYMETHOD_DOC_NOARGS(SCA_RandomActuator, setBoolUniform); + EXP_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setBoolBernouilli); + EXP_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setIntConst); + EXP_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setIntUniform); + EXP_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setIntPoisson); + EXP_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setFloatConst); + EXP_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setFloatUniform); + EXP_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setFloatNormal); + EXP_PYMETHOD_DOC_VARARGS(SCA_RandomActuator, setFloatNegativeExponential); #endif /* WITH_PYTHON */ }; /* end of class KX_EditObjectActuator : public SCA_PropertyActuator */ #endif + diff --git a/source/gameengine/GameLogic/SCA_RandomEventManager.cpp b/source/gameengine/GameLogic/SCA_RandomEventManager.cpp deleted file mode 100644 index dd268a0cd44b..000000000000 --- a/source/gameengine/GameLogic/SCA_RandomEventManager.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Manager for random events - * - * - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/GameLogic/SCA_RandomEventManager.cpp - * \ingroup gamelogic - */ - -#include "SCA_RandomEventManager.h" -#include "SCA_LogicManager.h" -#include "SCA_ISensor.h" -#include -using namespace std; - -#include -#include - -SCA_RandomEventManager::SCA_RandomEventManager(class SCA_LogicManager* logicmgr) - : SCA_EventManager(logicmgr, RANDOM_EVENTMGR) -{ -} - - -void SCA_RandomEventManager::NextFrame() -{ - SG_DList::iterator it(m_sensors); - for (it.begin();!it.end();++it) - { - (*it)->Activate(m_logicmgr); - } -} diff --git a/source/gameengine/GameLogic/SCA_RandomNumberGenerator.cpp b/source/gameengine/GameLogic/SCA_RandomNumberGenerator.cpp index e6c1b51ea235..19d59fe53bb4 100644 --- a/source/gameengine/GameLogic/SCA_RandomNumberGenerator.cpp +++ b/source/gameengine/GameLogic/SCA_RandomNumberGenerator.cpp @@ -74,11 +74,15 @@ void SCA_RandomNumberGenerator::SetStartVector(void) /* [KNUTH 1981, The Art of Computer Programming */ /* Vol. 2 (2nd Ed.), pp102] */ mt[0] = m_seed & 0xffffffff; - for (mti = 1; mti < N; mti++) - mt[mti] = (69069 * mt[mti-1]) & 0xffffffff; + for (mti = 1; mti < N; mti++) { + mt[mti] = (69069 * mt[mti - 1]) & 0xffffffff; + } } -long SCA_RandomNumberGenerator::GetSeed() { return m_seed; } +long SCA_RandomNumberGenerator::GetSeed() +{ + return m_seed; +} void SCA_RandomNumberGenerator::SetSeed(long newseed) { m_seed = newseed; @@ -103,15 +107,15 @@ unsigned long SCA_RandomNumberGenerator::Draw() // GEN_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]; + 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]; + 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]; + y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK); + mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1]; mti = 0; } @@ -127,7 +131,7 @@ unsigned long SCA_RandomNumberGenerator::Draw() float SCA_RandomNumberGenerator::DrawFloat() { - return ( (float) Draw()/ (unsigned long) 0xffffffff ); + return ((float)Draw() / (unsigned long)0xffffffff); } /* eof */ diff --git a/source/gameengine/GameLogic/SCA_RandomNumberGenerator.h b/source/gameengine/GameLogic/SCA_RandomNumberGenerator.h index 2c6a45833175..ecc63d9ac36e 100644 --- a/source/gameengine/GameLogic/SCA_RandomNumberGenerator.h +++ b/source/gameengine/GameLogic/SCA_RandomNumberGenerator.h @@ -35,10 +35,6 @@ #ifndef __SCA_RANDOMNUMBERGENERATOR_H__ #define __SCA_RANDOMNUMBERGENERATOR_H__ -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - class SCA_RandomNumberGenerator { /* reference counted for memleak */ @@ -74,11 +70,7 @@ class SCA_RandomNumberGenerator { if (--m_refcount == 0) delete this; } - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:SCA_RandomNumberGenerator") -#endif }; #endif /* __SCA_RANDOMNUMBERGENERATOR_H__ */ + diff --git a/source/gameengine/GameLogic/SCA_RandomSensor.cpp b/source/gameengine/GameLogic/SCA_RandomSensor.cpp index 0757655e7db9..ce187e85a59a 100644 --- a/source/gameengine/GameLogic/SCA_RandomSensor.cpp +++ b/source/gameengine/GameLogic/SCA_RandomSensor.cpp @@ -37,7 +37,6 @@ #include "SCA_RandomSensor.h" #include "SCA_EventManager.h" -#include "SCA_RandomEventManager.h" #include "SCA_LogicManager.h" #include "EXP_ConstExpr.h" #include @@ -46,10 +45,10 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_RandomSensor::SCA_RandomSensor(SCA_EventManager* eventmgr, - SCA_IObject* gameobj, +SCA_RandomSensor::SCA_RandomSensor(SCA_EventManager *eventmgr, + SCA_IObject *gameobj, int startseed) - : SCA_ISensor(gameobj,eventmgr) + :SCA_ISensor(gameobj, eventmgr) { m_basegenerator = new SCA_RandomNumberGenerator(startseed); Init(); @@ -71,9 +70,9 @@ void SCA_RandomSensor::Init() } -CValue* SCA_RandomSensor::GetReplica() +EXP_Value *SCA_RandomSensor::GetReplica() { - CValue* replica = new SCA_RandomSensor(*this); + EXP_Value *replica = new SCA_RandomSensor(*this); // this will copy properties and so on... replica->ProcessReplica(); @@ -90,7 +89,7 @@ void SCA_RandomSensor::ProcessReplica() bool SCA_RandomSensor::IsPositiveTrigger() { - return (m_invert !=m_lastdraw); + return (m_invert != m_lastdraw); } @@ -114,7 +113,8 @@ bool SCA_RandomSensor::Evaluate() m_currentDraw = m_basegenerator->Draw(); drawResult = (m_currentDraw & 0x1) == 0; m_iteration = 1; - } else { + } + else { drawResult = ((m_currentDraw >> m_iteration) & 0x1) == 0; m_iteration++; } @@ -134,9 +134,9 @@ bool SCA_RandomSensor::Evaluate() /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_RandomSensor::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_RandomSensor", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -144,36 +144,36 @@ PyTypeObject SCA_RandomSensor::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_ISensor::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_RandomSensor::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef SCA_RandomSensor::Attributes[] = { - KX_PYATTRIBUTE_BOOL_RO("lastDraw",SCA_RandomSensor,m_lastdraw), - KX_PYATTRIBUTE_RW_FUNCTION("seed", SCA_RandomSensor, pyattr_get_seed, pyattr_set_seed), - {NULL} //Sentinel + EXP_PYATTRIBUTE_BOOL_RO("lastDraw", SCA_RandomSensor, m_lastdraw), + EXP_PYATTRIBUTE_RW_FUNCTION("seed", SCA_RandomSensor, pyattr_get_seed, pyattr_set_seed), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *SCA_RandomSensor::pyattr_get_seed(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *SCA_RandomSensor::pyattr_get_seed(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - SCA_RandomSensor* self = static_cast(self_v); + SCA_RandomSensor *self = static_cast(self_v); return PyLong_FromLong(self->m_basegenerator->GetSeed()); } -int SCA_RandomSensor::pyattr_set_seed(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int SCA_RandomSensor::pyattr_set_seed(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - SCA_RandomSensor* self = static_cast(self_v); + SCA_RandomSensor *self = static_cast(self_v); if (!PyLong_Check(value)) { PyErr_SetString(PyExc_TypeError, "sensor.seed = int: Random Sensor, expected an integer"); return PY_SET_ATTR_FAIL; diff --git a/source/gameengine/GameLogic/SCA_RandomSensor.h b/source/gameengine/GameLogic/SCA_RandomSensor.h index 40d7d7d66cd5..4196ef82e245 100644 --- a/source/gameengine/GameLogic/SCA_RandomSensor.h +++ b/source/gameengine/GameLogic/SCA_RandomSensor.h @@ -51,7 +51,7 @@ class SCA_RandomSensor : public SCA_ISensor SCA_IObject* gameobj, int startseed); virtual ~SCA_RandomSensor(); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); virtual void ProcessReplica(); virtual bool Evaluate(); virtual bool IsPositiveTrigger(); @@ -62,9 +62,9 @@ class SCA_RandomSensor : public SCA_ISensor /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - - static PyObject* pyattr_get_seed(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_seed(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + + static PyObject* pyattr_get_seed(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_seed(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); #endif }; diff --git a/source/gameengine/GameLogic/SCA_TimeEventManager.cpp b/source/gameengine/GameLogic/SCA_TimeEventManager.cpp index 5c8468e5485a..f5bc8dd5c4f6 100644 --- a/source/gameengine/GameLogic/SCA_TimeEventManager.cpp +++ b/source/gameengine/GameLogic/SCA_TimeEventManager.cpp @@ -30,8 +30,8 @@ */ #ifdef _MSC_VER - /* This warning tells us about truncation of __long__ stl-generated names. - * It can occasionally cause DevStudio to have internal compiler warnings. */ +/* 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 @@ -40,8 +40,10 @@ #include "SCA_LogicManager.h" #include "EXP_FloatValue.h" -SCA_TimeEventManager::SCA_TimeEventManager(SCA_LogicManager* logicmgr) -: SCA_EventManager(NULL, TIME_EVENTMGR) +#include "CM_List.h" + +SCA_TimeEventManager::SCA_TimeEventManager(SCA_LogicManager *logicmgr) + :SCA_EventManager(nullptr, TIME_EVENTMGR) { } @@ -49,49 +51,48 @@ SCA_TimeEventManager::SCA_TimeEventManager(SCA_LogicManager* logicmgr) SCA_TimeEventManager::~SCA_TimeEventManager() { - for (vector::iterator it = m_timevalues.begin(); - !(it == m_timevalues.end()); ++it) - { - (*it)->Release(); + for (EXP_Value *prop : m_timevalues) { + prop->Release(); } } -void SCA_TimeEventManager::RegisterSensor(SCA_ISensor* sensor) +bool SCA_TimeEventManager::RegisterSensor(SCA_ISensor *sensor) { // not yet + return false; } -void SCA_TimeEventManager::RemoveSensor(SCA_ISensor* sensor) +bool SCA_TimeEventManager::RemoveSensor(SCA_ISensor *sensor) { // empty + return false; } void SCA_TimeEventManager::NextFrame(double curtime, double fixedtime) { - if (m_timevalues.size() > 0 && fixedtime > 0.0) - { - CFloatValue* floatval = new CFloatValue(curtime); - - // update sensors, but ... need deltatime ! - for (vector::iterator it = m_timevalues.begin(); - !(it == m_timevalues.end()); ++it) - { - float newtime = (*it)->GetNumber() + fixedtime; - floatval->SetFloat(newtime); - (*it)->SetValue(floatval); - } - - floatval->Release(); + if (m_timevalues.empty() && fixedtime <= 0.0) { + return; + } + + EXP_FloatValue *floatval = new EXP_FloatValue(curtime); + + // update sensors, but ... need deltatime ! + for (EXP_Value *prop : m_timevalues) { + float newtime = prop->GetNumber() + fixedtime; + floatval->SetFloat(newtime); + prop->SetValue(floatval); } + + floatval->Release(); } -void SCA_TimeEventManager::AddTimeProperty(CValue* timeval) +void SCA_TimeEventManager::AddTimeProperty(EXP_Value *timeval) { timeval->AddRef(); m_timevalues.push_back(timeval); @@ -99,21 +100,13 @@ void SCA_TimeEventManager::AddTimeProperty(CValue* timeval) -void SCA_TimeEventManager::RemoveTimeProperty(CValue* timeval) +void SCA_TimeEventManager::RemoveTimeProperty(EXP_Value *timeval) { - for (vector::iterator it = m_timevalues.begin(); - !(it == m_timevalues.end()); ++it) - { - if ((*it) == timeval) - { - this->m_timevalues.erase(it); - timeval->Release(); - break; - } - } + CM_ListRemoveIfFound(m_timevalues, timeval); } -vector SCA_TimeEventManager::GetTimeValues() +std::vector SCA_TimeEventManager::GetTimeValues() { return m_timevalues; } + diff --git a/source/gameengine/GameLogic/SCA_TimeEventManager.h b/source/gameengine/GameLogic/SCA_TimeEventManager.h index 723a6ee10a78..796db4810455 100644 --- a/source/gameengine/GameLogic/SCA_TimeEventManager.h +++ b/source/gameengine/GameLogic/SCA_TimeEventManager.h @@ -36,27 +36,21 @@ #include "EXP_Value.h" #include -using namespace std; - class SCA_TimeEventManager : public SCA_EventManager { - vector m_timevalues; // values that need their time updated regularly - + std::vector m_timevalues; // values that need their time updated regularly + public: SCA_TimeEventManager(class SCA_LogicManager* logicmgr); virtual ~SCA_TimeEventManager(); virtual void NextFrame(double curtime, double fixedtime); - virtual void RegisterSensor(class SCA_ISensor* sensor); - virtual void RemoveSensor(class SCA_ISensor* sensor); - void AddTimeProperty(CValue* timeval); - void RemoveTimeProperty(CValue* timeval); - - vector GetTimeValues(); + virtual bool RegisterSensor(class SCA_ISensor* sensor); + virtual bool RemoveSensor(class SCA_ISensor* sensor); + void AddTimeProperty(EXP_Value* timeval); + void RemoveTimeProperty(EXP_Value* timeval); -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:SCA_TimeEventManager") -#endif + std::vector GetTimeValues(); }; #endif /* __SCA_TIMEEVENTMANAGER_H__ */ diff --git a/source/gameengine/GameLogic/SCA_VibrationActuator.cpp b/source/gameengine/GameLogic/SCA_VibrationActuator.cpp new file mode 100644 index 000000000000..97435515e567 --- /dev/null +++ b/source/gameengine/GameLogic/SCA_VibrationActuator.cpp @@ -0,0 +1,197 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/GameLogic/SCA_VibrationActuator.cpp + * \ingroup GameLogic + */ + + +#include "SCA_VibrationActuator.h" +#include "SCA_JoystickManager.h" + + +SCA_VibrationActuator::SCA_VibrationActuator(SCA_IObject *gameobj, short mode, int joyindex, float strengthLeft, float strengthRight, int duration) + :SCA_IActuator(gameobj, KX_ACT_VIBRATION), + m_joyindex(joyindex), + m_mode(mode), + m_strengthLeft(strengthLeft), + m_strengthRight(strengthRight), + m_duration(duration) +{ +} + +SCA_VibrationActuator::~SCA_VibrationActuator(void) +{ +} + +EXP_Value *SCA_VibrationActuator::GetReplica(void) +{ + SCA_VibrationActuator *replica = new SCA_VibrationActuator(*this); + replica->ProcessReplica(); + return replica; +} + +bool SCA_VibrationActuator::Update() +{ + /* Can't init instance in constructor because m_joystick list is not available yet */ + SCA_JoystickManager *mgr = (SCA_JoystickManager *)GetLogicManager(); + DEV_Joystick *instance = mgr->GetJoystickDevice(m_joyindex); + + if (!instance) { + return false; + } + + bool bPositiveEvent = IsPositiveEvent(); + + RemoveAllEvents(); + + if (bPositiveEvent) { + switch (m_mode) { + case KX_ACT_VIBRATION_PLAY: + { + instance->RumblePlay(m_strengthLeft, m_strengthRight, m_duration); + break; + } + case KX_ACT_VIBRATION_STOP: + { + instance->RumbleStop(); + break; + } + } + } + + instance->ProcessRumbleStatus(); + + return instance->GetRumbleStatus(); +} + +#ifdef WITH_PYTHON + +/* ------------------------------------------------------------------------- */ +/* Python functions */ +/* ------------------------------------------------------------------------- */ + + + +/* Integration hooks ------------------------------------------------------- */ +PyTypeObject SCA_VibrationActuator::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "SCA_VibrationActuator", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &SCA_IActuator::Type, + 0, 0, 0, 0, 0, 0, + py_base_new +}; + +PyMethodDef SCA_VibrationActuator::Methods[] = { + EXP_PYMETHODTABLE_NOARGS(SCA_VibrationActuator, startVibration), + EXP_PYMETHODTABLE_NOARGS(SCA_VibrationActuator, stopVibration), + { nullptr, nullptr } //Sentinel +}; + +PyAttributeDef SCA_VibrationActuator::Attributes[] = { + EXP_PYATTRIBUTE_INT_RW("duration", 0, INT_MAX, true, SCA_VibrationActuator, m_duration), + EXP_PYATTRIBUTE_INT_RW("joyindex", 0, 7, true, SCA_VibrationActuator, m_joyindex), + EXP_PYATTRIBUTE_FLOAT_RW("strengthLeft", 0.0, 1.0, SCA_VibrationActuator, m_strengthLeft), + EXP_PYATTRIBUTE_FLOAT_RW("strengthRight", 0.0, 1.0, SCA_VibrationActuator, m_strengthRight), + EXP_PYATTRIBUTE_RO_FUNCTION("isVibrating", SCA_VibrationActuator, pyattr_get_isVibrating), + EXP_PYATTRIBUTE_RO_FUNCTION("hasVibration", SCA_VibrationActuator, pyattr_get_hasVibration), + EXP_PYATTRIBUTE_NULL //Sentinel +}; + +EXP_PYMETHODDEF_DOC_NOARGS(SCA_VibrationActuator, startVibration, + "startVibration()\n" + "\tStarts the joystick vibration.\n") +{ + SCA_JoystickManager *mgr = (SCA_JoystickManager *)GetLogicManager(); + DEV_Joystick *instance = mgr->GetJoystickDevice(m_joyindex); + + if (!instance) { + Py_RETURN_NONE; + } + + instance->RumblePlay(m_strengthLeft, m_strengthRight, m_duration); + + Py_RETURN_NONE; +} + +EXP_PYMETHODDEF_DOC_NOARGS(SCA_VibrationActuator, stopVibration, + "StopVibration()\n" + "\tStops the joystick vibration.\n") +{ + SCA_JoystickManager *mgr = (SCA_JoystickManager *)GetLogicManager(); + DEV_Joystick *instance = mgr->GetJoystickDevice(m_joyindex); + + if (!instance) { + Py_RETURN_NONE; + } + + instance->RumbleStop(); + + Py_RETURN_NONE; +} + +PyObject *SCA_VibrationActuator::pyattr_get_isVibrating(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef) +{ + SCA_VibrationActuator *self = static_cast(self_v); + SCA_JoystickManager *mgr = (SCA_JoystickManager *)self->GetLogicManager(); + DEV_Joystick *instance = mgr->GetJoystickDevice(self->m_joyindex); + + if (!instance) { + return Py_False; + } + + instance->ProcessRumbleStatus(); + + return PyBool_FromLong(instance->GetRumbleStatus()); +} + +PyObject *SCA_VibrationActuator::pyattr_get_hasVibration(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef) +{ + SCA_VibrationActuator *self = static_cast(self_v); + SCA_JoystickManager *mgr = (SCA_JoystickManager *)self->GetLogicManager(); + DEV_Joystick *instance = mgr->GetJoystickDevice(self->m_joyindex); + + if (!instance) { + return Py_False; + } + + return PyBool_FromLong(instance->GetRumbleSupport()); +} + +#endif // WITH_PYTHON diff --git a/source/gameengine/GameLogic/SCA_VibrationActuator.h b/source/gameengine/GameLogic/SCA_VibrationActuator.h new file mode 100644 index 000000000000..15aed03416ee --- /dev/null +++ b/source/gameengine/GameLogic/SCA_VibrationActuator.h @@ -0,0 +1,72 @@ +/* +* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* +* The Original Code is: all of this file. +* +* Contributor(s): none yet. +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +/** \file SCA_VibrationActuator.h +* \ingroup GameLogic +*/ + +#ifndef __SCA_VIBRATIONACTUATOR_H__ +#define __SCA_VIBRATIONACTUATOR_H__ + +#include "SCA_IActuator.h" + +class SCA_VibrationActuator : public SCA_IActuator +{ + Py_Header + +private: + int m_joyindex; + short m_mode; + float m_strengthLeft; + float m_strengthRight; + int m_duration; + +public: + enum KX_ACT_VIBRATION_MODE { + KX_ACT_VIBRATION_NONE = 0, + KX_ACT_VIBRATION_PLAY, + KX_ACT_VIBRATION_STOP, + KX_ACT_VIBRATION_MAX + }; + + SCA_VibrationActuator(SCA_IObject *gameobj, short mode, int joyindex, float strengthLeft, float strengthRight, int duration); + virtual ~SCA_VibrationActuator(); + + virtual EXP_Value *GetReplica(); + + virtual bool Update(); + +#ifdef WITH_PYTHON + EXP_PYMETHOD_DOC_NOARGS(SCA_VibrationActuator, startVibration); + EXP_PYMETHOD_DOC_NOARGS(SCA_VibrationActuator, stopVibration); + + static PyObject *pyattr_get_isVibrating(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_hasVibration(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef); +#endif // WITH_PYTHON + +}; + +#endif + diff --git a/source/gameengine/GameLogic/SCA_XNORController.cpp b/source/gameengine/GameLogic/SCA_XNORController.cpp index f97d11cabf32..ad7a3425274c 100644 --- a/source/gameengine/GameLogic/SCA_XNORController.cpp +++ b/source/gameengine/GameLogic/SCA_XNORController.cpp @@ -42,7 +42,7 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_XNORController::SCA_XNORController(SCA_IObject* gameobj) +SCA_XNORController::SCA_XNORController(SCA_IObject *gameobj) : SCA_IController(gameobj) { @@ -56,19 +56,14 @@ SCA_XNORController::~SCA_XNORController() -void SCA_XNORController::Trigger(SCA_LogicManager* logicmgr) +void SCA_XNORController::Trigger(SCA_LogicManager *logicmgr) { bool sensorresult = true; - for (vector::const_iterator is=m_linkedsensors.begin(); - !(is==m_linkedsensors.end());is++) - { - SCA_ISensor* sensor = *is; - if (sensor->GetState()) - { - if (sensorresult == false) - { + for (SCA_ISensor *sensor : m_linkedsensors) { + if (sensor->GetState()) { + if (sensorresult == false) { sensorresult = true; break; } @@ -76,19 +71,16 @@ void SCA_XNORController::Trigger(SCA_LogicManager* logicmgr) } } - for (vector::const_iterator i=m_linkedactuators.begin(); - !(i==m_linkedactuators.end());i++) - { - SCA_IActuator* actua = *i; - logicmgr->AddActiveActuator(actua,sensorresult); + for (SCA_IActuator *actuator : m_linkedactuators) { + logicmgr->AddActiveActuator(actuator, sensorresult); } } -CValue* SCA_XNORController::GetReplica() +EXP_Value *SCA_XNORController::GetReplica() { - CValue* replica = new SCA_XNORController(*this); + EXP_Value *replica = new SCA_XNORController(*this); // this will copy properties and so on... replica->ProcessReplica(); @@ -103,9 +95,9 @@ CValue* SCA_XNORController::GetReplica() /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_XNORController::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_XNORController", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -113,23 +105,23 @@ PyTypeObject SCA_XNORController::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IController::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_XNORController::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef SCA_XNORController::Attributes[] = { - { NULL } //Sentinel + EXP_PYATTRIBUTE_NULL //Sentinel }; #endif // WITH_PYTHON diff --git a/source/gameengine/GameLogic/SCA_XNORController.h b/source/gameengine/GameLogic/SCA_XNORController.h index c257b71273ea..90e55069e9ee 100644 --- a/source/gameengine/GameLogic/SCA_XNORController.h +++ b/source/gameengine/GameLogic/SCA_XNORController.h @@ -41,7 +41,7 @@ class SCA_XNORController : public SCA_IController public: SCA_XNORController(SCA_IObject* gameobj); virtual ~SCA_XNORController(); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); virtual void Trigger(SCA_LogicManager* logicmgr); /* --------------------------------------------------------------------- */ diff --git a/source/gameengine/GameLogic/SCA_XORController.cpp b/source/gameengine/GameLogic/SCA_XORController.cpp index 70e99a7f819e..436ba43879dc 100644 --- a/source/gameengine/GameLogic/SCA_XORController.cpp +++ b/source/gameengine/GameLogic/SCA_XORController.cpp @@ -42,7 +42,7 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -SCA_XORController::SCA_XORController(SCA_IObject* gameobj) +SCA_XORController::SCA_XORController(SCA_IObject *gameobj) : SCA_IController(gameobj) { @@ -56,19 +56,14 @@ SCA_XORController::~SCA_XORController() -void SCA_XORController::Trigger(SCA_LogicManager* logicmgr) +void SCA_XORController::Trigger(SCA_LogicManager *logicmgr) { bool sensorresult = false; - for (vector::const_iterator is=m_linkedsensors.begin(); - !(is==m_linkedsensors.end());is++) - { - SCA_ISensor* sensor = *is; - if (sensor->GetState()) - { - if (sensorresult == true) - { + for (SCA_ISensor *sensor : m_linkedsensors) { + if (sensor->GetState()) { + if (sensorresult == true) { sensorresult = false; break; } @@ -76,19 +71,16 @@ void SCA_XORController::Trigger(SCA_LogicManager* logicmgr) } } - for (vector::const_iterator i=m_linkedactuators.begin(); - !(i==m_linkedactuators.end());i++) - { - SCA_IActuator* actua = *i; - logicmgr->AddActiveActuator(actua,sensorresult); + for (SCA_IActuator *actuator : m_linkedactuators) { + logicmgr->AddActiveActuator(actuator, sensorresult); } } -CValue* SCA_XORController::GetReplica() +EXP_Value *SCA_XORController::GetReplica() { - CValue* replica = new SCA_XORController(*this); + EXP_Value *replica = new SCA_XORController(*this); // this will copy properties and so on... replica->ProcessReplica(); @@ -103,9 +95,9 @@ CValue* SCA_XORController::GetReplica() /* Integration hooks ------------------------------------------------------- */ PyTypeObject SCA_XORController::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "SCA_XORController", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -113,23 +105,23 @@ PyTypeObject SCA_XORController::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IController::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef SCA_XORController::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef SCA_XORController::Attributes[] = { - { NULL } //Sentinel + EXP_PYATTRIBUTE_NULL //Sentinel }; #endif // WITH_PYTHON diff --git a/source/gameengine/GameLogic/SCA_XORController.h b/source/gameengine/GameLogic/SCA_XORController.h index c64a3380edea..a5f2503d8fc6 100644 --- a/source/gameengine/GameLogic/SCA_XORController.h +++ b/source/gameengine/GameLogic/SCA_XORController.h @@ -41,7 +41,7 @@ class SCA_XORController : public SCA_IController public: SCA_XORController(SCA_IObject* gameobj); virtual ~SCA_XORController(); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); virtual void Trigger(SCA_LogicManager* logicmgr); }; diff --git a/source/gameengine/GamePlayer/CMakeLists.txt b/source/gameengine/GamePlayer/CMakeLists.txt index e77609985dc5..a333e38b3088 100644 --- a/source/gameengine/GamePlayer/CMakeLists.txt +++ b/source/gameengine/GamePlayer/CMakeLists.txt @@ -23,5 +23,90 @@ # # ***** END GPL LICENSE BLOCK ***** -add_subdirectory(common) -add_subdirectory(ghost) +set(INC + . + .. + ../BlenderRoutines + ../Common + ../Converter + ../Device + ../Expressions + ../GameLogic + ../Ketsji + ../Ketsji/KXNetwork + ../Launcher + ../Physics/Common + ../Rasterizer + ../Rasterizer/RAS_OpenGLRasterizer + ../SceneGraph + ../../blender + ../../blender/blenfont + ../../blender/blenkernel + ../../blender/blenlib + ../../blender/blenloader + ../../blender/blentranslation + ../../blender/gpu + ../../blender/imbuf + ../../blender/makesdna + ../../blender/makesrna + ../../../intern/ghost + ../../../intern/guardedalloc + ../../../intern/string + ../../../intern/memutil +) + +set(INC_SYS + ../../../intern/debugbreak + ../../../intern/mathfu + ${PYTHON_INCLUDE_DIRS} + ${BOOST_INCLUDE_DIR} +) + +set(SRC + GPG_Canvas.cpp + GPG_ghost.cpp + + GPG_Canvas.h +) + +add_definitions(${GL_DEFINITIONS}) + +if(WIN32) + blender_include_dirs(../../../intern/utfconv) +endif() + +if(WITH_INPUT_NDOF) + add_definitions(-DWITH_INPUT_NDOF) +endif(WITH_INPUT_NDOF) + +if(WITH_CODEC_FFMPEG) + add_definitions(-DWITH_FFMPEG) +endif() + +if(WITH_INTERNATIONAL) + add_definitions(-DWITH_INTERNATIONAL) +endif() + +if(WITH_AUDASPACE) + add_definitions(${AUDASPACE_DEFINITIONS}) + + list(APPEND INC_SYS + ${AUDASPACE_C_INCLUDE_DIRS} + ) +endif() + +if(WITH_SDL AND WITH_SDL_DYNLOAD) + list(APPEND INC + ../../../extern/sdlew/include + ) + add_definitions(-DWITH_SDL_DYNLOAD) +endif() + +if(WITH_GAMEENGINE_BPPLAYER) + list(APPEND INC + ../../../intern/spindle + ) + add_definitions(-DWITH_GAMEENGINE_BPPLAYER) +endif() + +blender_add_lib_nolist(ge_player "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/gameengine/GamePlayer/GPG_Canvas.cpp b/source/gameengine/GamePlayer/GPG_Canvas.cpp new file mode 100644 index 000000000000..bc45129276ad --- /dev/null +++ b/source/gameengine/GamePlayer/GPG_Canvas.cpp @@ -0,0 +1,288 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/GamePlayer/GPG_Canvas.cpp + * \ingroup player + */ + +#include "GPG_Canvas.h" +#include "GHOST_ISystem.h" + +#include "KX_Globals.h" + +#include "RAS_Rasterizer.h" + +#include "BLI_string.h" +#include "BLI_path_util.h" +#include "BLI_utildefines.h" + +#include "BKE_image.h" +#include "MEM_guardedalloc.h" +#include "DNA_space_types.h" + +GPG_Canvas::GPG_Canvas(RAS_Rasterizer *rasty, GHOST_IWindow *window) + :RAS_ICanvas(rasty), + m_window(window), + m_width(0), + m_height(0) +{ + m_rasterizer->GetViewport(m_viewport); + + if (m_window) { + GHOST_Rect bnds; + m_window->getClientBounds(bnds); + this->Resize(bnds.getWidth(), bnds.getHeight()); + } +} + +GPG_Canvas::~GPG_Canvas() +{ +} + +int GPG_Canvas::GetWidth() const +{ + return m_width; +} + +int GPG_Canvas::GetHeight() const +{ + return m_height; +} + +int GPG_Canvas::GetMaxX() const +{ + return (m_width - 1); +} + +int GPG_Canvas::GetMaxY() const +{ + return (m_height - 1); +} + +RAS_Rect &GPG_Canvas::GetWindowArea() +{ + return m_area; +} + +void GPG_Canvas::BeginFrame() +{ +} + +void GPG_Canvas::EndFrame() +{ +} + +void GPG_Canvas::BeginDraw() +{ +} + +void GPG_Canvas::EndDraw() +{ +} + +void GPG_Canvas::Resize(int width, int height) +{ + m_width = width; + m_height = height; + + // initialize area so that it's available for game logic on frame 1 (ImageViewport) + m_area.SetLeft(0); + m_area.SetBottom(0); + m_area.SetRight(width - 1); + m_area.SetTop(height - 1); +} + +void GPG_Canvas::SetViewPort(int x, int y, int width, int height) +{ + m_viewport[0] = x; + m_viewport[1] = y; + m_viewport[2] = width; + m_viewport[3] = height; +} + +void GPG_Canvas::UpdateViewPort(int x, int y, int width, int height) +{ + m_viewport[0] = x; + m_viewport[1] = y; + m_viewport[2] = width; + m_viewport[3] = height; +} + +const int *GPG_Canvas::GetViewPort() +{ + return m_viewport; +} + +void GPG_Canvas::MakeScreenShot(const std::string& filename) +{ + // copy image data + unsigned int dumpsx = GetWidth(); + unsigned int dumpsy = GetHeight(); + + // initialize image file format data + ImageFormatData *im_format = (ImageFormatData *)MEM_mallocN(sizeof(ImageFormatData), "im_format"); + BKE_imformat_defaults(im_format); + + // create file path + char path[FILE_MAX]; + BLI_strncpy(path, filename.c_str(), FILE_MAX); + BLI_path_abs(path, KX_GetMainPath().c_str()); + + AddScreenshot(path, 0, 0, dumpsx, dumpsy, im_format); +} + +void GPG_Canvas::Init() +{ + if (m_window) { + m_window->setDrawingContextType(GHOST_kDrawingContextTypeOpenGL); + BLI_assert(m_window->getDrawingContextType() == GHOST_kDrawingContextTypeOpenGL); + } +} + +void GPG_Canvas::SetMousePosition(int x, int y) +{ + GHOST_ISystem *system = GHOST_ISystem::getSystem(); + if (system && m_window) { + GHOST_TInt32 gx = (GHOST_TInt32)x; + GHOST_TInt32 gy = (GHOST_TInt32)y; + GHOST_TInt32 cx; + GHOST_TInt32 cy; + m_window->clientToScreen(gx, gy, cx, cy); + system->setCursorPosition(cx, cy); + } +} + + +void GPG_Canvas::SetMouseState(RAS_MouseState mousestate) +{ + m_mousestate = mousestate; + + if (m_window) { + switch (mousestate) { + case MOUSE_INVISIBLE: + { + m_window->setCursorVisibility(false); + break; + } + case MOUSE_WAIT: + { + m_window->setCursorShape(GHOST_kStandardCursorWait); + m_window->setCursorVisibility(true); + break; + } + case MOUSE_NORMAL: + { + m_window->setCursorShape(GHOST_kStandardCursorDefault); + m_window->setCursorVisibility(true); + break; + } + } + } +} + +void GPG_Canvas::SwapBuffers() +{ + if (m_window) { + m_window->swapBuffers(); + } +} + +void GPG_Canvas::SetSwapControl(SwapControl control) +{ + if (m_window) { + m_window->setSwapInterval(swapInterval[control]); + } + RAS_ICanvas::SetSwapControl(control); +} + +void GPG_Canvas::GetDisplayDimensions(int &width, int &height) +{ + unsigned int uiwidth; + unsigned int uiheight; + + GHOST_ISystem *system = GHOST_ISystem::getSystem(); + system->getMainDisplayDimensions(uiwidth, uiheight); + + width = uiwidth; + height = uiheight; +} + +void GPG_Canvas::ResizeWindow(int width, int height) +{ + if (m_window->getState() == GHOST_kWindowStateFullScreen) { + GHOST_ISystem *system = GHOST_ISystem::getSystem(); + GHOST_DisplaySetting setting; + setting.xPixels = width; + setting.yPixels = height; + //XXX allow these to be changed or kept from previous state + setting.bpp = 32; + setting.frequency = 60; + + system->updateFullScreen(setting, &m_window); + } + + m_window->setClientSize(width, height); + + Resize(width, height); +} + +void GPG_Canvas::SetFullScreen(bool enable) +{ + if (enable) { + m_window->setState(GHOST_kWindowStateFullScreen); + } + else { + m_window->setState(GHOST_kWindowStateNormal); + } +} + +bool GPG_Canvas::GetFullScreen() +{ + return (m_window->getState() == GHOST_kWindowStateFullScreen); +} + +void GPG_Canvas::ConvertMousePosition(int x, int y, int &r_x, int &r_y, bool UNUSED(screen)) +{ + int _x; + int _y; + m_window->screenToClient(x, y, _x, _y); + + const float fac = m_window->getNativePixelSize(); + + r_x = _x * fac; + r_y = _y * fac; +} + +float GPG_Canvas::GetMouseNormalizedX(int x) +{ + return float(x) / GetMaxX(); +} + +float GPG_Canvas::GetMouseNormalizedY(int y) +{ + return float(y) / GetMaxY(); +} diff --git a/source/gameengine/GamePlayer/ghost/GPG_Canvas.h b/source/gameengine/GamePlayer/GPG_Canvas.h similarity index 54% rename from source/gameengine/GamePlayer/ghost/GPG_Canvas.h rename to source/gameengine/GamePlayer/GPG_Canvas.h index 18afbf6cd9e3..9ac02203f6e3 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_Canvas.h +++ b/source/gameengine/GamePlayer/GPG_Canvas.h @@ -34,43 +34,74 @@ #ifdef WIN32 #pragma warning (disable:4786) -#endif /* WIN32 */ +#endif // WIN32 -#include "GPC_Canvas.h" +#include "RAS_ICanvas.h" +#include "RAS_Rect.h" #include "GHOST_IWindow.h" +class RAS_Rasterizer; -class GPG_Canvas : public GPC_Canvas +class GPG_Canvas : public RAS_ICanvas { protected: - /** GHOST window. */ - GHOST_IWindow* m_window; + /// GHOST window. + GHOST_IWindow *m_window; + /// Width of the context. + int m_width; + /// Height of the context. + int m_height; + /** Rect that defines the area used for rendering, + * relative to the context. + */ + RAS_Rect m_area; + + int m_viewport[4]; public: - GPG_Canvas(GHOST_IWindow* window); - virtual ~GPG_Canvas(void); + GPG_Canvas(RAS_Rasterizer *rasty, GHOST_IWindow *window); + virtual ~GPG_Canvas(); + + /** + * \section Methods inherited from abstract base class RAS_ICanvas. + */ + + virtual int GetWidth() const; + virtual int GetHeight() const; + virtual int GetMaxX() const; + virtual int GetMaxY() const; + virtual RAS_Rect &GetWindowArea(); + virtual void BeginFrame(); + + /// Draws overlay banners and progress bars. + virtual void EndFrame(); + + virtual void SetViewPort(int x, int y, int width, int height); + virtual void UpdateViewPort(int x, int y, int width, int height); + virtual const int *GetViewPort(); + + virtual void MakeScreenShot(const std::string& filename); - virtual void Init(void); + virtual void Init(); virtual void SetMousePosition(int x, int y); virtual void SetMouseState(RAS_MouseState mousestate); virtual void SwapBuffers(); - virtual void SetSwapInterval(int interval); - virtual bool GetSwapInterval(int& intervalOut); + virtual void SetSwapControl(SwapControl control); - virtual int GetMouseX(int x) { return x; } - virtual int GetMouseY(int y) { return y; } + virtual void ConvertMousePosition(int x, int y, int &r_x, int &r_y, bool screen); virtual float GetMouseNormalizedX(int x); virtual float GetMouseNormalizedY(int y); virtual void GetDisplayDimensions(int &width, int &height); + virtual void Resize(int width, int height); virtual void ResizeWindow(int width, int height); virtual void SetFullScreen(bool enable); virtual bool GetFullScreen(); - bool BeginDraw() { return true; } - void EndDraw() {}; + virtual void BeginDraw(); + virtual void EndDraw(); }; -#endif /* __GPG_CANVAS_H__ */ +#endif // __GPG_CANVAS_H__ diff --git a/source/gameengine/GamePlayer/GPG_ghost.cpp b/source/gameengine/GamePlayer/GPG_ghost.cpp new file mode 100644 index 000000000000..78c8e0a01c03 --- /dev/null +++ b/source/gameengine/GamePlayer/GPG_ghost.cpp @@ -0,0 +1,1625 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * Start up of the Blender Player on GHOST. + */ + +/** \file gameengine/GamePlayer/GPG_ghost.cpp + * \ingroup player + */ + + +#include +#include +#include + +#ifdef __linux__ +# ifdef __alpha__ +# include +# endif /* __alpha__ */ +#endif /* __linux__ */ + +extern "C" +{ +# include "MEM_guardedalloc.h" +# include "MEM_CacheLimiterC-Api.h" + +# include "BLI_threads.h" +# include "BLI_mempool.h" +# include "BLI_blenlib.h" + +# include "DNA_scene_types.h" +# include "DNA_genfile.h" + +# include "BLO_readfile.h" +# include "BLO_runtime.h" + +# include "BKE_appdir.h" +# include "BKE_blender.h" +# include "BKE_depsgraph.h" +# include "BKE_global.h" +# include "BKE_icons.h" +# include "BKE_image.h" +# include "BKE_node.h" +# include "BKE_report.h" +# include "BKE_library.h" +# include "BKE_library_remap.h" +# include "BKE_modifier.h" +# include "BKE_material.h" +# include "BKE_text.h" +# include "BKE_sound.h" + +# include "IMB_imbuf.h" +# include "IMB_moviecache.h" + +# ifdef __APPLE__ +int GHOST_HACK_getFirstFile(char buf[]); +# endif + +// For BLF +# include "BLF_api.h" +# include "BLT_translation.h" +# include "BLT_lang.h" + +# include "BLI_system.h" + +extern int datatoc_bfont_ttf_size; +extern char datatoc_bfont_ttf[]; +extern int datatoc_bmonofont_ttf_size; +extern char datatoc_bmonofont_ttf[]; + +} + +#include "GPU_init_exit.h" +#include "GPU_draw.h" + +#include "KX_Globals.h" +#include "KX_PythonInit.h" + +#include "LA_SystemCommandLine.h" +#include "LA_PlayerLauncher.h" + +#include "GHOST_ISystem.h" + +#include "BKE_main.h" + +#include "RNA_define.h" + +#ifdef WIN32 +# include +# if !defined(DEBUG) +# include +# endif // !defined(DEBUG) +# if defined(_MSC_VER) && defined(_M_X64) +# include /* needed for _set_FMA3_enable */ +# endif +# include "utfconv.h" +#endif // WIN32 + +#ifdef WITH_SDL_DYNLOAD +# include "sdlew.h" +#endif + +#ifdef WITH_GAMEENGINE_BPPLAYER +# include "SpindleEncryption.h" +#endif // WITH_GAMEENGINE_BPPLAYER + +#include + +#include "BKE_blender_version.h" + +#define BLEND_VERSION_FMT "Blender %d.%02d (sub %d)" +#define BLEND_VERSION_ARG BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION +/* pass directly to printf */ +#define BLEND_VERSION_STRING_FMT BLEND_VERSION_FMT "\n", BLEND_VERSION_ARG + +#include "CM_Message.h" + +const int kMinWindowWidth = 100; +const int kMinWindowHeight = 100; + +static void mem_error_cb(const char *errorStr) +{ + fprintf(stderr, "%s", errorStr); + fflush(stderr); +} + +// library.c will only free window managers with a callback function. +// We don't actually use a wmWindowManager, but loading a blendfile +// loads wmWindows, so we need to free those. +static void wm_free(bContext *C, wmWindowManager *wm) +{ + BLI_freelistN(&wm->windows); +} + +#ifdef WIN32 +typedef enum { + SCREEN_SAVER_MODE_NONE = 0, + SCREEN_SAVER_MODE_PREVIEW, + SCREEN_SAVER_MODE_SAVER, + SCREEN_SAVER_MODE_CONFIGURATION, + SCREEN_SAVER_MODE_PASSWORD, +} ScreenSaverMode; + +static ScreenSaverMode scr_saver_mode = SCREEN_SAVER_MODE_NONE; +static HWND scr_saver_hwnd = nullptr; + +static BOOL scr_saver_init(int argc, char **argv) +{ + scr_saver_mode = SCREEN_SAVER_MODE_NONE; + scr_saver_hwnd = nullptr; + BOOL ret = false; + + int len = ::strlen(argv[0]); + if (len > 4 && !::stricmp(".scr", argv[0] + len - 4)) { + scr_saver_mode = SCREEN_SAVER_MODE_CONFIGURATION; + ret = true; + if (argc >= 2) { + if (argc >= 3) { + scr_saver_hwnd = (HWND)::atoi(argv[2]); + } + if (!::stricmp("/c", argv[1])) { + scr_saver_mode = SCREEN_SAVER_MODE_CONFIGURATION; + if (scr_saver_hwnd == nullptr) { + scr_saver_hwnd = ::GetForegroundWindow(); + } + } + else if (!::stricmp("/s", argv[1])) { + scr_saver_mode = SCREEN_SAVER_MODE_SAVER; + } + else if (!::stricmp("/a", argv[1])) { + scr_saver_mode = SCREEN_SAVER_MODE_PASSWORD; + } + else if (!::stricmp("/p", argv[1]) + || !::stricmp("/l", argv[1])) { + scr_saver_mode = SCREEN_SAVER_MODE_PREVIEW; + } + } + } + return ret; +} + +#define SCR_SAVE_MOUSE_MOVE_THRESHOLD 15 + +static HWND found_ghost_window_hwnd; +static GHOST_IWindow *ghost_window_to_find; +static WNDPROC ghost_wnd_proc; +static POINT scr_save_mouse_pos; + +static LRESULT CALLBACK screenSaverWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + BOOL close = false; + switch (uMsg) { + case WM_MOUSEMOVE: + { + POINT pt; + GetCursorPos(&pt); + LONG dx = scr_save_mouse_pos.x - pt.x; + LONG dy = scr_save_mouse_pos.y - pt.y; + if (abs(dx) > SCR_SAVE_MOUSE_MOVE_THRESHOLD + || abs(dy) > SCR_SAVE_MOUSE_MOVE_THRESHOLD) { + close = true; + } + scr_save_mouse_pos = pt; + break; + } + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_KEYDOWN: + close = true; + } + if (close) { + PostMessage(hwnd, WM_CLOSE, 0, 0); + } + return CallWindowProc(ghost_wnd_proc, hwnd, uMsg, wParam, lParam); +} + +BOOL CALLBACK findGhostWindowHWNDProc(HWND hwnd, LPARAM lParam) +{ + GHOST_IWindow *p = (GHOST_IWindow *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + BOOL ret = true; + if (p == ghost_window_to_find) { + found_ghost_window_hwnd = hwnd; + ret = false; + } + return ret; +} + +static HWND findGhostWindowHWND(GHOST_IWindow *window) +{ + found_ghost_window_hwnd = nullptr; + ghost_window_to_find = window; + LPARAM lParam = 0; + EnumWindows(findGhostWindowHWNDProc, lParam); + return found_ghost_window_hwnd; +} + +static GHOST_IWindow *startScreenSaverPreview(GHOST_ISystem *system, + HWND parentWindow, + const bool stereoVisual) +{ + RECT rc; + if (GetWindowRect(parentWindow, &rc)) { + int windowWidth = rc.right - rc.left; + int windowHeight = rc.bottom - rc.top; + std::string title = ""; + GHOST_GLSettings glSettings = {0}; + + if (stereoVisual) { + glSettings.flags |= GHOST_glStereoVisual; + } + + GHOST_IWindow *window = system->createWindow(title, 0, 0, windowWidth, windowHeight, GHOST_kWindowStateMinimized, + GHOST_kDrawingContextTypeOpenGL, glSettings); + if (!window) { + CM_Error("could not create main window"); + exit(-1); + } + + HWND ghost_hwnd = findGhostWindowHWND(window); + if (!ghost_hwnd) { + CM_Error("could find main window"); + exit(-1); + } + + SetParent(ghost_hwnd, parentWindow); + LONG_PTR style = GetWindowLongPtr(ghost_hwnd, GWL_STYLE); + LONG_PTR exstyle = GetWindowLongPtr(ghost_hwnd, GWL_EXSTYLE); + + RECT adjrc = { 0, 0, windowWidth, windowHeight }; + AdjustWindowRectEx(&adjrc, style, false, exstyle); + + style = (style & (~(WS_POPUP | WS_OVERLAPPEDWINDOW | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_TILEDWINDOW))) | WS_CHILD; + SetWindowLongPtr(ghost_hwnd, GWL_STYLE, style); + SetWindowPos(ghost_hwnd, nullptr, adjrc.left, adjrc.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); + + /* Check the size of the client rectangle of the window and resize the window + * so that the client rectangle has the size requested. + */ + window->setClientSize(windowWidth, windowHeight); + + return window; + } + + return nullptr; +} + +#endif // WIN32 + +static GHOST_IWindow *startFullScreen(GHOST_ISystem *system, + int width, + int height, + int bpp, int frequency, + const bool stereoVisual, + const int alphaBackground, + bool useDesktop) +{ + GHOST_TUns32 sysWidth = 0, sysHeight = 0; + system->getMainDisplayDimensions(sysWidth, sysHeight); + // Create the main window + GHOST_DisplaySetting setting; + setting.xPixels = (useDesktop) ? sysWidth : width; + setting.yPixels = (useDesktop) ? sysHeight : height; + setting.bpp = bpp; + setting.frequency = frequency; + + GHOST_IWindow *window = nullptr; + system->beginFullScreen(setting, &window, stereoVisual, alphaBackground); + window->setCursorVisibility(false); + /* note that X11 ignores this (it uses a window internally for fullscreen) */ + window->setState(GHOST_kWindowStateFullScreen); + + return window; +} + +#ifdef WIN32 + +static GHOST_IWindow *startScreenSaverFullScreen(GHOST_ISystem *system, + int width, + int height, + int bpp, int frequency, + const bool stereoVisual, + const int alphaBackground) +{ + GHOST_IWindow *window = startFullScreen(system, width, height, bpp, frequency, stereoVisual, alphaBackground, 0); + HWND ghost_hwnd = findGhostWindowHWND(window); + if (ghost_hwnd != nullptr) { + GetCursorPos(&scr_save_mouse_pos); + ghost_wnd_proc = (WNDPROC)GetWindowLongPtr(ghost_hwnd, GWLP_WNDPROC); + SetWindowLongPtr(ghost_hwnd, GWLP_WNDPROC, (uintptr_t)screenSaverWindowProc); + } + + return window; +} + +#endif // WIN32 + +static GHOST_IWindow *startWindow(GHOST_ISystem *system, + std::string& title, + int windowLeft, + int windowTop, + int windowWidth, + int windowHeight, + const bool stereoVisual, + const int alphaBackground) +{ + GHOST_GLSettings glSettings = {0}; + // Create the main window + //std::string title ("Blender Player - GHOST"); + if (stereoVisual) { + glSettings.flags |= GHOST_glStereoVisual; + } + if (alphaBackground) { + glSettings.flags |= GHOST_glAlphaBackground; + } + + GHOST_IWindow *window = system->createWindow(title, windowLeft, windowTop, windowWidth, windowHeight, GHOST_kWindowStateNormal, + GHOST_kDrawingContextTypeOpenGL, glSettings); + if (!window) { + CM_Error("could not create main window"); + exit(-1); + } + + /* Check the size of the client rectangle of the window and resize the window + * so that the client rectangle has the size requested. + */ + window->setClientSize(windowWidth, windowHeight); + window->setCursorVisibility(false); + + return window; +} + +static GHOST_IWindow *startEmbeddedWindow(GHOST_ISystem *system, + std::string& title, + const GHOST_TEmbedderWindowID parentWindow, + const bool stereoVisual, + const int alphaBackground) +{ + GHOST_TWindowState state = GHOST_kWindowStateNormal; + GHOST_GLSettings glSettings = {0}; + + if (stereoVisual) { + glSettings.flags |= GHOST_glStereoVisual; + } + if (alphaBackground) { + glSettings.flags |= GHOST_glAlphaBackground; + } + + if (parentWindow != 0) { + state = GHOST_kWindowStateEmbedded; + } + GHOST_IWindow *window = system->createWindow(title, 0, 0, 0, 0, state, + GHOST_kDrawingContextTypeOpenGL, glSettings, false, parentWindow); + + if (!window) { + CM_Error("could not create main window"); + exit(-1); + } + + return window; +} + +static void usage(const std::string& program, bool isBlenderPlayer) +{ + std::string example_filename = ""; + std::string example_pathname = ""; + +#ifdef _WIN32 + const std::string consoleoption = "[-c] "; +#else + const std::string consoleoption = ""; +#endif + + if (isBlenderPlayer) { + example_filename = "filename.blend"; +#ifdef _WIN32 + example_pathname = "c:\\"; +#else + example_pathname = "/home/user/"; +#endif + } + CM_Message(std::endl) + CM_Message("usage: " << program << " [--options] " << example_filename << std::endl); + CM_Message("Available options are: [-w [w h l t]] [-f [fw fh fb ff]] " << consoleoption << "[-g gamengineoptions] " + << "[-s stereomode] [-m aasamples]"); + CM_Message("Optional parameters must be passed in order."); + CM_Message("Default values are set in the blend file." << std::endl); + CM_Message(" -h: Prints this command summary" << std::endl); + CM_Message(" -w: display in a window"); + CM_Message(" --Optional parameters--"); + CM_Message(" w = window width"); + CM_Message(" h = window height"); + CM_Message(" l = window left coordinate"); + CM_Message(" t = window top coordinate"); + CM_Message(" Note: To define 'w' or 'h', both must be used." + << "Also, to define 'l' or 't', all four parameters must be used."); + CM_Message(" Example: -w or -w 500 300 or -w 500 300 0 0" << std::endl); + CM_Message(" -f: start game in fullscreen mode"); + CM_Message(" --Optional parameters--"); + CM_Message(" fw = fullscreen mode pixel width (use 0 to detect automatically)"); + CM_Message(" fh = fullscreen mode pixel height (use 0 to detect automatically)"); + CM_Message(" fb = fullscreen mode bits per pixel (default unless set in the blend file: 32)"); + CM_Message(" ff = fullscreen mode frequency (default unless set in the blend file: 60)"); + CM_Message(" Note: To define 'fw'' or 'fh'', both must be used."); + CM_Message(" Example: -f or -f 1024 768 or -f 0 0 16 or -f 1024 728 16 30" << std::endl); + CM_Message(" -s: start player in stereoscopy mode (requires 3D capable hardware)"); + CM_Message(" stereomode: nostereo (default unless stereo is set in the blend file)"); + CM_Message(" anaglyph (Red-Blue glasses)"); + CM_Message(" sidebyside (Left Right)"); + CM_Message(" syncdoubling (Above Below)"); + CM_Message(" 3dtvtopbottom (Squashed Top-Bottom for passive glasses)"); + CM_Message(" interlace (Interlace horizontally)"); + CM_Message(" vinterlace (Vertical interlace for autostereo display)"); + CM_Message(" hwpageflip (Quad buffered shutter glasses)"); + CM_Message(" Example: -s sidebyside or -s vinterlace" << std::endl); + CM_Message(" -m: maximum anti-aliasing (eg. 2,4,8,16)" << std::endl); + CM_Message(" -n: maximum anisotropic filtering (eg. 2,4,8,16)" << std::endl); + CM_Message(" -i: parent window's ID" << std::endl); +#ifdef _WIN32 + CM_Message(" -c: keep console window open" << std::endl); +#endif + CM_Message(" -d: debugging options:"); + CM_Message(" memory Debug memory leaks"); + CM_Message(" gpu Debug gpu error and warnings" << std::endl); + CM_Message(" -g: game engine options:" << std::endl); + CM_Message(" Name Default Description"); + CM_Message(" ------------------------------------------------------------------------"); + CM_Message(" fixedtime 0 \"Enable all frames\""); + CM_Message(" nomipmap 0 Disable mipmaps"); + CM_Message(" wireframe 0 Wireframe render"); + CM_Message(" show_framerate 0 Show the frame rate"); + CM_Message(" show_render_queries 0 Show the render queries"); + CM_Message(" show_properties 0 Show debug properties"); + CM_Message(" show_profile 0 Show profiling information"); + CM_Message(" show_bounding_box 0 Show debug bounding box volume"); + CM_Message(" show_armatures 0 Show debug armatures"); + CM_Message(" show_camera_frustum 0 Show debug camera frustum volume"); + CM_Message(" show_shadow_frustum 0 Show debug light shadow frustum volume"); + CM_Message(" ignore_deprecation_warnings 1 Ignore deprecation warnings" << std::endl); + CM_Message(" -p: override python main loop script"); + CM_Message(std::endl); + CM_Message(" - : all arguments after this are ignored, allowing python to access them from sys.argv"); + CM_Message(std::endl); + CM_Message("example: " << program << " -w 320 200 10 10 -g noaudio " << example_pathname << example_filename); + CM_Message("example: " << program << " -g show_framerate = 0 " << example_pathname << example_filename); + CM_Message("example: " << program << " -i 232421 -m 16 " << example_pathname << example_filename); +} + +static void get_filename(int argc, char **argv, char *filename) +{ +#ifdef __APPLE__ + /* On Mac we park the game file (called game.blend) in the application bundle. + * The executable is located in the bundle as well. + * Therefore, we can locate the game relative to the executable. + */ + int srclen = ::strlen(argv[0]); + int len = 0; + char *gamefile = nullptr; + + filename[0] = '\0'; + + if (argc > 1) { + if (BLI_exists(argv[argc - 1])) { + BLI_strncpy(filename, argv[argc - 1], FILE_MAX); + } + if (::strncmp(argv[argc - 1], "-psn_", 5) == 0) { + static char firstfilebuf[512]; + if (GHOST_HACK_getFirstFile(firstfilebuf)) { + BLI_strncpy(filename, firstfilebuf, FILE_MAX); + } + } + } + + srclen -= ::strlen("MacOS/blenderplayer"); + if (srclen > 0) { + len = srclen + ::strlen("Resources/game.blend"); + gamefile = new char[len + 1]; + ::strcpy(gamefile, argv[0]); + ::strcpy(gamefile + srclen, "Resources/game.blend"); + + if (BLI_exists(gamefile)) { + BLI_strncpy(filename, gamefile, FILE_MAX); + } + + delete[] gamefile; + } + +#else + filename[0] = '\0'; + + if (argc > 1) { + BLI_strncpy(filename, argv[argc - 1], FILE_MAX); + } +#endif // !_APPLE +} + +static BlendFileData *load_game_data(const char *progname, char *filename = nullptr) +{ + ReportList reports; + BlendFileData *bfd = nullptr; + + BKE_reports_init(&reports, RPT_STORE); + + /* try to load ourself, will only work if we are a runtime */ + if (BLO_is_a_runtime(progname)) { + bfd = BLO_read_runtime(progname, &reports); + if (bfd) { + bfd->type = BLENFILETYPE_RUNTIME; + BLI_strncpy(bfd->main->name, progname, sizeof(bfd->main->name)); + } + } + else { + bfd = BLO_read_from_file(progname, &reports, BLO_READ_SKIP_NONE); + } + + if (!bfd && filename) { + bfd = load_game_data(filename); + if (!bfd) { + CM_Error("loading " << filename << " failed: "); + BKE_reports_print(&reports, RPT_ERROR); + } + } + + BKE_reports_clear(&reports); + + return bfd; +} + +#ifdef WITH_GAMEENGINE_BPPLAYER + +static BlendFileData *load_encrypted_game_data(const char *filename, std::string encryptKey) +{ + ReportList reports; + BlendFileData *bfd = nullptr; + char *fileData = nullptr; + int fileSize; + std::string localPath(SPINDLE_GetFilePath()); + BKE_reports_init(&reports, RPT_STORE); + + if (filename == nullptr) { + return nullptr; + } + + if (!localPath.empty() && !encryptKey.empty()) { + // Load file and decrypt. + fileData = SPINDLE_DecryptFromFile(filename, &fileSize, encryptKey.c_str(), 0); + } + + if (fileData) { + bfd = BLO_read_from_memory(fileData, fileSize, &reports, BLO_READ_SKIP_USERDEF); + delete[] fileData; + } + + if (!bfd) { + BKE_reports_print(&reports, RPT_ERROR); + } + + BKE_reports_clear(&reports); + return bfd; +} + +#endif // WITH_GAMEENGINE_BPPLAYER + +static void sigHandleCrashBacktrace(FILE *fp) +{ + fputs("\n# backtrace\n", fp); + BLI_system_backtrace(fp); +} + +static void sigHandleCrash(int signum) +{ + FILE *fp; + char header[512]; + + char fname[FILE_MAX]; + + if (!G.main || !G.main->name[0]) { + BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), "blender.crash.txt"); + } + else { + BLI_join_dirfile(fname, sizeof(fname), BKE_tempdir_base(), BLI_path_basename(G_MAIN->name)); + BLI_path_extension_replace(fname, sizeof(fname), ".crash.txt"); + } + + printf("Writing: %s\n", fname); + fflush(stdout); + +#ifndef BUILD_DATE + BLI_snprintf(header, sizeof(header), "# " BLEND_VERSION_FMT ", Unknown revision\n", BLEND_VERSION_ARG); +#else + BLI_snprintf(header, sizeof(header), "# " BLEND_VERSION_FMT ", Commit date: %s %s, Hash %s\n", + BLEND_VERSION_ARG, build_commit_date, build_commit_time, build_hash); +#endif + + /* open the crash log */ + errno = 0; + fp = BLI_fopen(fname, "wb"); + if (fp == NULL) { + fprintf(stderr, "Unable to save '%s': %s\n", + fname, errno ? strerror(errno) : "Unknown error opening file"); + } + else { + sigHandleCrashBacktrace(fp); + + fclose(fp); + } + + /* really crash */ + signal(signum, SIG_DFL); +#ifndef WIN32 + kill(getpid(), signum); +#else + TerminateProcess(GetCurrentProcess(), signum); +#endif +} + +#ifdef WIN32 +LONG WINAPI windowsExceptionHandler(EXCEPTION_POINTERS *ExceptionInfo) +{ + switch (ExceptionInfo->ExceptionRecord->ExceptionCode) { + case EXCEPTION_ACCESS_VIOLATION: + fputs("Error : EXCEPTION_ACCESS_VIOLATION\n", stderr); + break; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + fputs("Error : EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr); + break; + case EXCEPTION_BREAKPOINT: + fputs("Error : EXCEPTION_BREAKPOINT\n", stderr); + break; + case EXCEPTION_DATATYPE_MISALIGNMENT: + fputs("Error : EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr); + break; + case EXCEPTION_FLT_DENORMAL_OPERAND: + fputs("Error : EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr); + break; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + fputs("Error : EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr); + break; + case EXCEPTION_FLT_INEXACT_RESULT: + fputs("Error : EXCEPTION_FLT_INEXACT_RESULT\n", stderr); + break; + case EXCEPTION_FLT_INVALID_OPERATION: + fputs("Error : EXCEPTION_FLT_INVALID_OPERATION\n", stderr); + break; + case EXCEPTION_FLT_OVERFLOW: + fputs("Error : EXCEPTION_FLT_OVERFLOW\n", stderr); + break; + case EXCEPTION_FLT_STACK_CHECK: + fputs("Error : EXCEPTION_FLT_STACK_CHECK\n", stderr); + break; + case EXCEPTION_FLT_UNDERFLOW: + fputs("Error : EXCEPTION_FLT_UNDERFLOW\n", stderr); + break; + case EXCEPTION_ILLEGAL_INSTRUCTION: + fputs("Error : EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr); + break; + case EXCEPTION_IN_PAGE_ERROR: + fputs("Error : EXCEPTION_IN_PAGE_ERROR\n", stderr); + break; + case EXCEPTION_INT_DIVIDE_BY_ZERO: + fputs("Error : EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr); + break; + case EXCEPTION_INT_OVERFLOW: + fputs("Error : EXCEPTION_INT_OVERFLOW\n", stderr); + break; + case EXCEPTION_INVALID_DISPOSITION: + fputs("Error : EXCEPTION_INVALID_DISPOSITION\n", stderr); + break; + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + fputs("Error : EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr); + break; + case EXCEPTION_PRIV_INSTRUCTION: + fputs("Error : EXCEPTION_PRIV_INSTRUCTION\n", stderr); + break; + case EXCEPTION_SINGLE_STEP: + fputs("Error : EXCEPTION_SINGLE_STEP\n", stderr); + break; + case EXCEPTION_STACK_OVERFLOW: + fputs("Error : EXCEPTION_STACK_OVERFLOW\n", stderr); + break; + default: + fputs("Error : Unrecognized Exception\n", stderr); + break; + } + + fflush(stderr); + + /* If this is a stack overflow then we can't walk the stack, so just show + * where the error happened */ + if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) { + HMODULE mod; + CHAR modulename[MAX_PATH]; + LPVOID address = ExceptionInfo->ExceptionRecord->ExceptionAddress; + + fprintf(stderr, "Address : 0x%p\n", address); + if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCSTR)address, &mod)) { + if (GetModuleFileName(mod, modulename, MAX_PATH)) { + fprintf(stderr, "Module : %s\n", modulename); + } + } + + fflush(stderr); + +#ifdef NDEBUG + TerminateProcess(GetCurrentProcess(), SIGSEGV); +#else + sigHandleCrash(SIGSEGV); +#endif + } + + return EXCEPTION_EXECUTE_HANDLER; +} +#endif + +int main(int argc, +#ifdef WIN32 + char **UNUSED(argv_c) +#else + char **argv +#endif + ) +{ + int i; + int argc_py_clamped = argc; /* use this so python args can be added after ' - ' */ + bool error = false; + SYS_SystemHandle syshandle = SYS_GetSystem(); + bool fullScreen = false; + bool fullScreenParFound = false; + bool windowParFound = false; +#ifdef WIN32 + bool closeConsole = true; +#endif + +#ifdef WITH_GAMEENGINE_BPPLAYER + bool useLocalPath = false; + std::string hexKey; +#endif // WITH_GAMEENGINE_BPPLAYER + RAS_Rasterizer::StereoMode stereomode = RAS_Rasterizer::RAS_STEREO_NOSTEREO; + bool stereoWindow = false; + bool stereoParFound = false; + int windowLeft = 100; + int windowTop = 100; + int windowWidth = 640; + int windowHeight = 480; + GHOST_TUns32 fullScreenWidth = 0; + GHOST_TUns32 fullScreenHeight = 0; + GHOST_IWindow *window = nullptr; + int fullScreenBpp = 32; + int fullScreenFrequency = 60; + GHOST_TEmbedderWindowID parentWindow = 0; + bool isBlenderPlayer = false; //true when lauching from blender or command line. false for bundled player + int validArguments = 0; + bool samplesParFound = false; + std::string pythonControllerFile; + GHOST_TUns16 aasamples = 0; + int alphaBackground = 0; + +#ifdef WIN32 + char **argv; + int argv_num; + + /* We delay loading of openmp so we can set the policy here. */ +# if defined(_MSC_VER) + _putenv_s("OMP_WAIT_POLICY", "PASSIVE"); +# endif + + /* FMA3 support in the 2013 CRT is broken on Vista and Windows 7 RTM (fixed in SP1). Just disable it. */ +# if defined(_MSC_VER) && defined(_M_X64) + _set_FMA3_enable(0); +# endif + + /* Win32 Unicode Args */ + /* NOTE: cannot use guardedalloc malloc here, as it's not yet initialized + * (it depends on the args passed in, which is what we're getting here!) + */ + { + wchar_t **argv_16 = CommandLineToArgvW(GetCommandLineW(), &argc); + argv = (char **)malloc(argc * sizeof(char *)); + for (argv_num = 0; argv_num < argc; argv_num++) { + argv[argv_num] = alloc_utf_8_from_16(argv_16[argv_num], 0); + } + LocalFree(argv_16); + } +#endif /* WIN32 */ + +#ifdef __linux__ +#ifdef __alpha__ + signal(SIGFPE, SIG_IGN); +#endif /* __alpha__ */ +#endif /* __linux__ */ + +#ifdef WIN32 + SetUnhandledExceptionFilter(windowsExceptionHandler); +#else + /* after parsing args */ + signal(SIGSEGV, sigHandleCrash); +#endif // WIN32 + +#ifdef WITH_SDL_DYNLOAD + sdlewInit(); +#endif + + BKE_appdir_program_path_init(argv[0]); + BKE_tempdir_init(nullptr); + + // We don't use threads directly in the BGE, but we need to call this so things like + // freeing up GPU_Textures works correctly. + BLI_threadapi_init(); + + DNA_sdna_current_init(); + + RNA_init(); + + init_nodesystem(); + + BKE_blender_globals_init(); + + SET_FLAG_FROM_TEST(G.f, (U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0, G_SCRIPT_AUTOEXEC); + + // We load our own G.main, so free the one that BKE_blender_globals_init() gives us + BKE_main_free(G.main); + G.main = nullptr; + + MEM_CacheLimiter_set_disabled(true); + IMB_init(); + BKE_images_init(); + BKE_modifier_init(); + DAG_init(); + +#ifdef WITH_FFMPEG + IMB_ffmpeg_init(); +#endif + + // Setup builtin font for BLF (mostly copied from creator.c, wm_init_exit.c and interface_style.c) + BLF_init(); + BLT_lang_init(); + BLT_lang_set(""); + + BLF_load_mem("default", (unsigned char *)datatoc_bfont_ttf, datatoc_bfont_ttf_size); + if (blf_mono_font == -1) { + blf_mono_font = BLF_load_mem_unique("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size); + } + + // Parse command line options +#if defined(DEBUG) + CM_Debug("argv[0] = '" << argv[0] << "'"); +#endif + +#ifdef WIN32 + if (scr_saver_init(argc, argv)) { + switch (scr_saver_mode) { + case SCREEN_SAVER_MODE_CONFIGURATION: + { + MessageBox(scr_saver_hwnd, "This screen saver has no options that you can set", "Screen Saver", MB_OK); + break; + } + case SCREEN_SAVER_MODE_PASSWORD: + /* This is W95 only, which we currently do not support. + * Fall-back to normal screen saver behavior in that case... */ + case SCREEN_SAVER_MODE_SAVER: + { + fullScreen = true; + fullScreenParFound = true; + break; + } + + case SCREEN_SAVER_MODE_PREVIEW: + case SCREEN_SAVER_MODE_NONE: + { + /* This will actually be handled somewhere below... */ + break; + } + + } + } +#endif + // XXX add the ability to change this values to the command line parsing. + U.mixbufsize = 2048; + U.audiodevice = 2; + U.audiorate = 48000; + U.audioformat = 0x24; + U.audiochannels = 2; + + U.anisotropic_filter = 2; + // enable fast mipmap generation + U.use_gpu_mipmap = 1; + + BKE_sound_init_once(); + + // Initialize a default material for meshes without materials. + init_def_material(); + + BKE_library_callback_free_window_manager_set(wm_free); + + /* if running blenderplayer the last argument can't be parsed since it has to be the filename. else it is bundled */ + isBlenderPlayer = !BLO_is_a_runtime(argv[0]); + if (isBlenderPlayer) { + validArguments = argc - 1; + } + else { + validArguments = argc; + } + + + /* Parsing command line arguments (can be set from WM_OT_blenderplayer_start) */ +#if defined(DEBUG) + CM_Debug("parsing command line arguments..."); + CM_Debug("num of arguments is: " << validArguments - 1); //-1 because i starts at 1 +#endif + + for (i = 1; (i < validArguments) && !error +#ifdef WIN32 + && scr_saver_mode == SCREEN_SAVER_MODE_NONE +#endif + ; ) + + { +#if defined(DEBUG) + CM_Debug("argv[" << i << "] = '" << argv[i] << "'"); +#endif + if (argv[i][0] == '-') { + /* ignore all args after " - ", allow python to have own args */ + if (argv[i][1] == '\0') { + argc_py_clamped = i; + break; + } + + switch (argv[i][1]) { + case 'g': //game engine options (show_framerate, fixedtime, etc) + { + i++; + if (i <= validArguments) { + char *paramname = argv[i]; + // Check for single value versus assignment + if (i + 1 <= validArguments && (*(argv[i + 1]) == '=')) { + i++; + if (i + 1 <= validArguments) { + i++; + // Assignment + SYS_WriteCommandLineInt(syshandle, paramname, atoi(argv[i])); + SYS_WriteCommandLineFloat(syshandle, paramname, atof(argv[i])); + SYS_WriteCommandLineString(syshandle, paramname, argv[i]); +#if defined(DEBUG) + CM_Debug(paramname << " = '" << argv[i] << "'"); +#endif + i++; + } + else { + error = true; + CM_Error("argument assignment " << paramname << " without value."); + } + } + else { +// SYS_WriteCommandLineInt(syshandle, argv[i++], 1); + } + } + break; + } + case 'd': //debug on + { + ++i; + + if (strcmp(argv[i], "gpu") == 0) { + G.debug |= G_DEBUG_GPU | G_DEBUG; + ++i; + } + else if (strcmp(argv[i], "memory") == 0) { + G.debug |= G_DEBUG; + + CM_Debug("Switching to fully guarded memory allocator."); + MEM_use_guarded_allocator(); + + MEM_set_memory_debug(); +#ifndef NDEBUG + BLI_mempool_set_memory_debug(); +#endif + ++i; + } + else { + CM_Error("debug mode '" << argv[i] << "' unrecognized."); + } + + break; + } +#ifdef WITH_GAMEENGINE_BPPLAYER + case 'L': + { + // Find the requested base file directory. + if (!useLocalPath) { + SPINDLE_SetFilePath(&argv[i][2]); + useLocalPath = true; + } + i++; + break; + } + case 'K': + { + //Find and set keys + hexKey = SPINDLE_FindAndSetEncryptionKeys(argv, i); + i++; + break; + } +#endif // WITH_GAMEENGINE_BPPLAYER + case 'f': //fullscreen mode + { + i++; + fullScreen = true; + fullScreenParFound = true; + if ((i + 2) <= validArguments && argv[i][0] != '-' && argv[i + 1][0] != '-') { + fullScreenWidth = atoi(argv[i++]); + fullScreenHeight = atoi(argv[i++]); + if ((i + 1) <= validArguments && argv[i][0] != '-') { + fullScreenBpp = atoi(argv[i++]); + if ((i + 1) <= validArguments && argv[i][0] != '-') { + fullScreenFrequency = atoi(argv[i++]); + } + } + } + else if ((i + 1) <= validArguments && argv[i][0] != '-' && argv[i + 1][0] != '-') { + error = true; + CM_Error("to define fullscreen width or height, both options must be used."); + } + break; + } + case 'w': //display in a window + { + i++; + fullScreen = false; + windowParFound = true; + + // Parse window position and size options + if ((i + 2) <= validArguments && argv[i][0] != '-' && argv[i + 1][0] != '-') { + windowWidth = atoi(argv[i++]); + windowHeight = atoi(argv[i++]); + + if ((i + 2) <= validArguments && argv[i][0] != '-' && argv[i + 1][0] != '-') { + windowLeft = atoi(argv[i++]); + windowTop = atoi(argv[i++]); + } + else if ((i + 1) <= validArguments && argv[i][0] != '-' && argv[i + 1][0] != '-') { + error = true; + CM_Error("to define the window left or right coordinates, both options must be used."); + } + } + else if ((i + 1) <= validArguments && argv[i][0] != '-' && argv[i + 1][0] != '-') { + error = true; + CM_Error("to define the window's width or height, both options must be used."); + } + break; + } + case 'h': //display help + { + usage(argv[0], isBlenderPlayer); + return 0; + break; + } + case 'i': //parent window ID + { + i++; + if ((i + 1) <= validArguments) { + parentWindow = (GHOST_TEmbedderWindowID)atoll(argv[i++]); + } + else { + error = true; + CM_Error("too few options for parent window argument."); + } +#if defined(DEBUG) + CM_Debug("XWindows ID = " << int(parentWindow)); +#endif // defined(DEBUG) + break; + } + case 'm': //maximum anti-aliasing (eg. 2,4,8,16) + { + i++; + samplesParFound = true; + if ((i + 1) <= validArguments) { + aasamples = atoi(argv[i++]); + } + else { + error = true; + CM_Error("no argument supplied for -m"); + } + break; + } + case 'n': + { + ++i; + if ((i + 1) <= validArguments) { + U.anisotropic_filter = atoi(argv[i++]); + } + else { + error = true; + CM_Error("no argument supplied for -n"); + } + break; + } + case 'c': //keep console (windows only) + { + i++; +#ifdef WIN32 + closeConsole = false; +#endif + break; + } + case 's': //stereo mode + { + i++; + if ((i + 1) <= validArguments) { + stereoParFound = true; + + if (!strcmp(argv[i], "nostereo")) { // may not be redundant if the file has different setting + stereomode = RAS_Rasterizer::RAS_STEREO_NOSTEREO; + } + + // only the hardware pageflip method needs a stereo window + else if (!strcmp(argv[i], "hwpageflip")) { + stereomode = RAS_Rasterizer::RAS_STEREO_QUADBUFFERED; + stereoWindow = true; + } + else if (!strcmp(argv[i], "syncdoubling")) { + stereomode = RAS_Rasterizer::RAS_STEREO_ABOVEBELOW; + } + + else if (!strcmp(argv[i], "3dtvtopbottom")) { + stereomode = RAS_Rasterizer::RAS_STEREO_3DTVTOPBOTTOM; + } + + else if (!strcmp(argv[i], "anaglyph")) { + stereomode = RAS_Rasterizer::RAS_STEREO_ANAGLYPH; + } + + else if (!strcmp(argv[i], "sidebyside")) { + stereomode = RAS_Rasterizer::RAS_STEREO_SIDEBYSIDE; + } + + else if (!strcmp(argv[i], "interlace")) { + stereomode = RAS_Rasterizer::RAS_STEREO_INTERLACED; + } + + else if (!strcmp(argv[i], "vinterlace")) { + stereomode = RAS_Rasterizer::RAS_STEREO_VINTERLACE; + } + +#if 0 +// // future stuff +// else if (!strcmp(argv[i], "stencil") +// stereomode = RAS_STEREO_STENCIL; +#endif + else { + error = true; + CM_Error("stereomode '" << argv[i] << "' unrecognized."); + } + + i++; + } + else { + error = true; + CM_Error("too few options for stereo argument."); + } + break; + } + case 'a': // allow window to blend with display background + { + i++; + alphaBackground = 1; + break; + } + case 'p': + { + ++i; + pythonControllerFile = argv[i++]; + break; + } + default: //not recognized + { + CM_Warning("unknown argument: " << argv[i++]); + break; + } + } + } + else { + i++; + } + } + + if ((windowWidth < kMinWindowWidth) || (windowHeight < kMinWindowHeight)) { + error = true; + CM_Error("window size too small."); + } + + if (error) { + usage(argv[0], isBlenderPlayer); + return 0; + } + +#ifdef WIN32 + if (scr_saver_mode != SCREEN_SAVER_MODE_CONFIGURATION) +#endif + { + // Create the system + if (GHOST_ISystem::createSystem() == GHOST_kSuccess) { + GHOST_ISystem *system = GHOST_ISystem::getSystem(); + BLI_assert(system); + + if (!fullScreenWidth || !fullScreenHeight) { + system->getMainDisplayDimensions(fullScreenWidth, fullScreenHeight); + } + // process first batch of events. If the user + // drops a file on top off the blenderplayer icon, we + // receive an event with the filename + + system->processEvents(0); + +#ifdef WITH_PYTHON + // Initialize python and the global dictionary. + initPlayerPython(argc, argv); + PyObject *globalDict = PyDict_New(); +#endif // WITH_PYTHON + + // this bracket is needed for app (see below) to get out + // of scope before GHOST_ISystem::disposeSystem() is called. + { + KX_ExitInfo exitInfo; + bool firstTimeRunning = true; + char filename[FILE_MAX]; + char pathname[FILE_MAX]; + char *titlename; + + get_filename(argc_py_clamped, argv, filename); + if (filename[0]) { + BLI_path_cwd(filename, sizeof(filename)); + } + + + // fill the GlobalSettings with the first scene files + // those may change during the game and persist after using Game Actuator + GlobalSettings gs; + + do { + // Read the Blender file + BlendFileData *bfd; + + // if we got an exitcode 3 (KX_ExitInfo::START_OTHER_GAME) load a different file + if (exitInfo.m_code == KX_ExitInfo::START_OTHER_GAME) { + char basedpath[FILE_MAX]; + + // base the actuator filename relative to the last file + BLI_strncpy(basedpath, exitInfo.m_fileName.c_str(), sizeof(basedpath)); + BLI_path_abs(basedpath, pathname); + bfd = load_game_data(basedpath); + + if (!bfd) { + // just add "//" in front of it + char temppath[FILE_MAX] = "//"; + BLI_strncpy(temppath + 2, basedpath, FILE_MAX - 2); + + BLI_path_abs(temppath, pathname); + bfd = load_game_data(temppath); + } + } + else { +#ifdef WITH_GAMEENGINE_BPPLAYER + if (useLocalPath) { + bfd = load_encrypted_game_data(filename[0] ? filename : nullptr, hexKey); + + // The file is valid and it's the original file name. + if (bfd) { + remove(filename); + KX_SetOrigPath(bfd->main->name); + } + } + else +#endif // WITH_GAMEENGINE_BPPLAYER + { + bfd = load_game_data(BKE_appdir_program_path(), filename[0] ? filename : nullptr); + // The file is valid and it's the original file name. + if (bfd) { + KX_SetOrigPath(bfd->main->name); + } + } + } + +#if defined(DEBUG) + CM_Debug("game data loaded from " << filename); +#endif + + if (!bfd) { + usage(argv[0], isBlenderPlayer); + error = true; + exitInfo.m_code = KX_ExitInfo::QUIT_GAME; + } + else { + /* Setting options according to the blend file if not overriden in the command line */ +#ifdef WIN32 +#if !defined(DEBUG) + if (closeConsole) { + system->toggleConsole(0); // Close a console window + } +#endif // !defined(DEBUG) +#endif // WIN32 + Main *maggie = bfd->main; + Scene *scene = bfd->curscene; + G.main = maggie; + + if (firstTimeRunning) { + G.fileflags = bfd->fileflags; + + gs.glslflag = scene->gm.flag; + } + + //Seg Fault; icon.c gIcons == 0 + BKE_icons_init(1); + + titlename = maggie->name; + + // Check whether the game should be displayed full-screen + if ((!fullScreenParFound) && (!windowParFound)) { + // Only use file settings when command line did not override + if ((scene->gm.playerflag & GAME_PLAYER_FULLSCREEN)) { + fullScreen = true; + fullScreenWidth = scene->gm.xplay; + fullScreenHeight = scene->gm.yplay; + fullScreenFrequency = scene->gm.freqplay; + fullScreenBpp = scene->gm.depth; + } + else { + fullScreen = false; + windowWidth = scene->gm.xplay; + windowHeight = scene->gm.yplay; + } + } + + + // Check whether the game should be displayed in stereo + if (!stereoParFound) { + // Only use file settings when command line did not override + if (scene->gm.stereoflag == STEREO_ENABLED) { + switch (scene->gm.stereomode) { + case STEREO_QUADBUFFERED: + { + stereomode = RAS_Rasterizer::RAS_STEREO_QUADBUFFERED; + break; + } + case STEREO_ABOVEBELOW: + { + stereomode = RAS_Rasterizer::RAS_STEREO_ABOVEBELOW; + break; + } + case STEREO_INTERLACED: + { + stereomode = RAS_Rasterizer::RAS_STEREO_INTERLACED; + break; + } + case STEREO_ANAGLYPH: + { + stereomode = RAS_Rasterizer::RAS_STEREO_ANAGLYPH; + break; + } + case STEREO_SIDEBYSIDE: + { + stereomode = RAS_Rasterizer::RAS_STEREO_SIDEBYSIDE; + break; + } + case STEREO_VINTERLACE: + { + stereomode = RAS_Rasterizer::RAS_STEREO_VINTERLACE; + break; + } + case STEREO_3DTVTOPBOTTOM: + { + stereomode = RAS_Rasterizer::RAS_STEREO_3DTVTOPBOTTOM; + break; + } + } + if (stereomode == RAS_Rasterizer::RAS_STEREO_QUADBUFFERED) { + stereoWindow = true; + } + } + } + else { + scene->gm.stereoflag = STEREO_ENABLED; + } + + if (!samplesParFound) { + aasamples = scene->gm.aasamples; + } + + BLI_strncpy(pathname, maggie->name, sizeof(pathname)); + if (firstTimeRunning) { + firstTimeRunning = false; + + if (fullScreen) { +#ifdef WIN32 + if (scr_saver_mode == SCREEN_SAVER_MODE_SAVER) { + window = startScreenSaverFullScreen(system, fullScreenWidth, fullScreenHeight, + fullScreenBpp, fullScreenFrequency, stereoWindow, + alphaBackground); + } + else +#endif + { + window = startFullScreen(system, fullScreenWidth, fullScreenHeight, fullScreenBpp, + fullScreenFrequency, stereoWindow, alphaBackground, + (scene->gm.playerflag & GAME_PLAYER_DESKTOP_RESOLUTION)); + } + } + else { +#ifdef __APPLE__ + // on Mac's we'll show the executable name instead of the 'game.blend' name + char tempname[1024], *appstring; + ::strcpy(tempname, titlename); + + appstring = strstr(tempname, ".app/"); + if (appstring) { + appstring[2] = 0; + titlename = &tempname[0]; + } +#endif + // Strip the path so that we have the name of the game file + std::string path = titlename; + std::vector parts; +#ifndef WIN32 + boost::split(parts, path, boost::is_any_of("/")); +#else // WIN32 + boost::split(parts, path, boost::is_any_of("\\")); +#endif // WIN32 + std::string title; + if (parts.size()) { + title = parts[parts.size() - 1]; + std::vector sublastparts; + boost::split(sublastparts, title, boost::is_any_of(".")); + if (sublastparts.size() > 1) { + title = sublastparts[0]; + } + } + else { + title = "blenderplayer"; + } +#ifdef WIN32 + if (scr_saver_mode == SCREEN_SAVER_MODE_PREVIEW) { + window = startScreenSaverPreview(system, scr_saver_hwnd, stereoWindow); + } + else +#endif + { + if (parentWindow != 0) { + window = startEmbeddedWindow(system, title, parentWindow, stereoWindow, alphaBackground); + } + else { + window = startWindow(system, title, windowLeft, windowTop, windowWidth, + windowHeight, stereoWindow, alphaBackground); + } + } + } + + GPU_init(); + + if (SYS_GetCommandLineInt(syshandle, "nomipmap", 0)) { + GPU_set_mipmap(G.main, 0); + } + + GPU_set_anisotropic(G.main, U.anisotropic_filter); + GPU_set_gpu_mipmapping(G.main, U.use_gpu_mipmap); + GPU_set_linear_mipmap(true); + } + + // This argc cant be argc_py_clamped, since python uses it. + LA_PlayerLauncher launcher(system, window, maggie, scene, &gs, stereomode, aasamples, + argc, argv, pythonControllerFile); + +#ifdef WITH_PYTHON + launcher.SetPythonGlobalDict(globalDict); +#endif // WITH_PYTHON + + launcher.InitEngine(); + + // Enter main loop + exitInfo = launcher.EngineMainLoop(); + + gs = *launcher.GetGlobalSettings(); + + launcher.ExitEngine(); + + BLO_blendfiledata_free(bfd); + /* G.main == bfd->main, it gets referenced in free_nodesystem so we can't have a dangling pointer */ + G.main = nullptr; + } + } while (ELEM(exitInfo.m_code, KX_ExitInfo::RESTART_GAME, KX_ExitInfo::START_OTHER_GAME)); + } + + GPU_exit(); + +#ifdef WITH_PYTHON + PyDict_Clear(globalDict); + Py_DECREF(globalDict); + exitPlayerPython(); +#endif // WITH_PYTHON + + // Seg Fault; icon.c gIcons == 0 + BKE_icons_free(); + + window->setCursorShape(GHOST_kStandardCursorDefault); + window->setCursorVisibility(true); + + if (window) { + system->disposeWindow(window); + } + + // Dispose the system + GHOST_ISystem::disposeSystem(); + } + else { + error = true; + CM_Error("couldn't create a system."); + } + } + + /* refer to WM_exit_ext() and BKE_blender_free(), + * these are not called in the player but we need to match some of there behavior here, + * if the order of function calls or blenders state isn't matching that of blender proper, + * we may get troubles later on */ + + free_nodesystem(); + + // Cleanup + RNA_exit(); + DNA_sdna_current_free(); + BLF_exit(); + +#ifdef WITH_INTERNATIONAL + BLF_free_unifont(); + BLF_free_unifont_mono(); + BLT_lang_free(); +#endif + + IMB_exit(); + BKE_images_exit(); + DAG_exit(); + IMB_moviecache_destruct(); + + SYS_DeleteSystem(syshandle); + + BLI_threadapi_exit(); + + int totblock = MEM_get_memory_blocks_in_use(); + if (totblock != 0) { + CM_Error("totblock: " << totblock); + MEM_set_error_callback(mem_error_cb); + MEM_printmemlist(); + } + + BKE_tempdir_session_purge(); + +#ifdef WIN32 + while (argv_num) { + free(argv[--argv_num]); + } + free(argv); + argv = nullptr; +#endif + + return error ? -1 : 0; +} diff --git a/source/gameengine/GamePlayer/common/CMakeLists.txt b/source/gameengine/GamePlayer/common/CMakeLists.txt deleted file mode 100644 index e6c980de5660..000000000000 --- a/source/gameengine/GamePlayer/common/CMakeLists.txt +++ /dev/null @@ -1,75 +0,0 @@ -# ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 LICENSE BLOCK ***** - -set(INC - . - ../ghost - ../../BlenderRoutines - ../../Converter - ../../Expressions - ../../GameLogic - ../../Ketsji - ../../Network - ../../Network/LoopBackNetwork - ../../Physics/common - ../../Rasterizer - ../../Rasterizer/RAS_OpenGLRasterizer - ../../SceneGraph - ../../../blender - ../../../blender/blenfont - ../../../blender/blenkernel - ../../../blender/blenlib - ../../../blender/blenloader - ../../../blender/gpu - ../../../blender/imbuf - ../../../blender/makesdna - ../../../../intern/container - ../../../../intern/ghost - ../../../../intern/glew-mx - ../../../../intern/guardedalloc - ../../../../intern/string -) - -set(INC_SYS - ../../../../intern/moto/include - ${GLEW_INCLUDE_PATH} - ${PYTHON_INCLUDE_DIRS} - ${PNG_INCLUDE_DIRS} - ${ZLIB_INCLUDE_DIRS} -) - -set(SRC - GPC_Canvas.cpp - GPC_KeyboardDevice.cpp - GPC_MouseDevice.cpp - - GPC_Canvas.h - GPC_KeyboardDevice.h - GPC_MouseDevice.h -) - -add_definitions(${GL_DEFINITIONS}) - -blender_add_lib_nolist(ge_player_common "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/gameengine/GamePlayer/common/GPC_Canvas.cpp b/source/gameengine/GamePlayer/common/GPC_Canvas.cpp deleted file mode 100644 index c6d9bfb80bfc..000000000000 --- a/source/gameengine/GamePlayer/common/GPC_Canvas.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/GamePlayer/common/GPC_Canvas.cpp - * \ingroup player - */ - - -#include "RAS_IPolygonMaterial.h" -#include "GPC_Canvas.h" - -#include "DNA_scene_types.h" -#include "DNA_space_types.h" - -#include "BKE_image.h" -#include "MEM_guardedalloc.h" - - -GPC_Canvas::GPC_Canvas( - int width, - int height -) : - m_width(width), - m_height(height) -{ - // initialize area so that it's available for game logic on frame 1 (ImageViewport) - m_displayarea.m_x1 = 0; - m_displayarea.m_y1 = 0; - m_displayarea.m_x2 = width; - m_displayarea.m_y2 = height; - m_frame = 1; - - glGetIntegerv(GL_VIEWPORT, (GLint*)m_viewport); -} - - -GPC_Canvas::~GPC_Canvas() -{ -} - - -void GPC_Canvas::Resize(int width, int height) -{ - m_width = width; - m_height = height; - - // initialize area so that it's available for game logic on frame 1 (ImageViewport) - m_displayarea.m_x1 = 0; - m_displayarea.m_y1 = 0; - m_displayarea.m_x2 = width; - m_displayarea.m_y2 = height; -} - - -void GPC_Canvas::ClearColor(float r, float g, float b, float a) -{ - ::glClearColor(r,g,b,a); -} - -void GPC_Canvas::SetViewPort(int x1, int y1, int x2, int y2) -{ - /* x1 and y1 are the min pixel coordinate (e.g. 0) - x2 and y2 are the max pixel coordinate - the width,height is calculated including both pixels - therefore: max - min + 1 - */ - - /* XXX, nasty, this needs to go somewhere else, - * but where... definitely need to clean up this - * whole canvas/rendertools mess. - */ - glEnable(GL_SCISSOR_TEST); - - m_viewport[0] = x1; - m_viewport[1] = y1; - m_viewport[2] = x2-x1 + 1; - m_viewport[3] = y2-y1 + 1; - - glViewport(x1,y1,x2-x1 + 1,y2-y1 + 1); - glScissor(x1,y1,x2-x1 + 1,y2-y1 + 1); -} - -void GPC_Canvas::UpdateViewPort(int x1, int y1, int x2, int y2) -{ - m_viewport[0] = x1; - m_viewport[1] = y1; - m_viewport[2] = x2; - m_viewport[3] = y2; -} - -const int *GPC_Canvas::GetViewPort() -{ -#ifdef DEBUG - // If we're in a debug build, we might as well make sure our values don't differ - // from what the gpu thinks we have. This could lead to nasty, hard to find bugs. - int viewport[4]; - glGetIntegerv(GL_VIEWPORT, viewport); - assert(viewport[0] == m_viewport[0]); - assert(viewport[1] == m_viewport[1]); - assert(viewport[2] == m_viewport[2]); - assert(viewport[3] == m_viewport[3]); -#endif - - return m_viewport; -} - -void GPC_Canvas::ClearBuffer( - int type -) { - - int ogltype = 0; - if (type & RAS_ICanvas::COLOR_BUFFER ) - ogltype |= GL_COLOR_BUFFER_BIT; - if (type & RAS_ICanvas::DEPTH_BUFFER ) - ogltype |= GL_DEPTH_BUFFER_BIT; - - ::glClear(ogltype); -} - - void -GPC_Canvas:: -MakeScreenShot( - const char* filename -) { - // copy image data - unsigned int dumpsx = GetWidth(); - unsigned int dumpsy = GetHeight(); - unsigned int *pixels = (unsigned int *)MEM_mallocN(sizeof(int) * dumpsx * dumpsy, "pixels"); - - if (!pixels) { - std::cout << "Cannot allocate pixels array" << std::endl; - return; - } - - glReadPixels(0, 0, dumpsx, dumpsy, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - - // initialize image file format data - ImageFormatData *im_format = (ImageFormatData *)MEM_mallocN(sizeof(ImageFormatData), "im_format"); - BKE_imformat_defaults(im_format); - - /* save_screenshot() frees dumprect and im_format */ - save_screenshot(filename, dumpsx, dumpsy, pixels, im_format); -} diff --git a/source/gameengine/GamePlayer/common/GPC_Canvas.h b/source/gameengine/GamePlayer/common/GPC_Canvas.h deleted file mode 100644 index 615e3eaaf9e1..000000000000 --- a/source/gameengine/GamePlayer/common/GPC_Canvas.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file GPC_Canvas.h - * \ingroup player - */ - -#ifndef __GPC_CANVAS_H__ -#define __GPC_CANVAS_H__ - -#include "RAS_ICanvas.h" -#include "RAS_Rect.h" - -#ifdef WIN32 -# pragma warning (disable:4786) // suppress stl-MSVC debug info warning -# include -#endif /* WIN32 */ - -#include "GPU_glew.h" - -#include - - -class GPC_Canvas : public RAS_ICanvas -{ -protected: - - /** Width of the context. */ - int m_width; - /** Height of the context. */ - int m_height; - /** Rect that defines the area used for rendering, - * relative to the context */ - RAS_Rect m_displayarea; - - int m_viewport[4]; - -public: - - GPC_Canvas(int width, int height); - - virtual ~GPC_Canvas(); - - void Resize(int width, int height); - - virtual void ResizeWindow(int width, int height) {} - - virtual void GetDisplayDimensions(int &width, int &height) {} - - /** - * \section Methods inherited from abstract base class RAS_ICanvas. - */ - - int - GetWidth( - ) const { - return m_width; - } - - int - GetHeight( - ) const { - return m_height; - } - - const - RAS_Rect & - GetDisplayArea( - ) const { - return m_displayarea; - }; - - void - SetDisplayArea( - RAS_Rect *rect - ) { - m_displayarea= *rect; - }; - - RAS_Rect & - GetWindowArea( - ) { - return m_displayarea; - } - - void - BeginFrame( - ) {}; - - /** - * Draws overlay banners and progress bars. - */ - void - EndFrame( - ) {}; - - void SetViewPort(int x1, int y1, int x2, int y2); - void UpdateViewPort(int x1, int y1, int x2, int y2); - const int *GetViewPort(); - - void ClearColor(float r, float g, float b, float a); - - /** - * \section Methods inherited from abstract base class RAS_ICanvas. - * Semantics are not yet honored. - */ - - void SetMouseState(RAS_MouseState mousestate) - { - // not yet - } - - void SetMousePosition(int x, int y) - { - // not yet - } - - virtual void MakeScreenShot(const char* filename); - - void ClearBuffer(int type); -}; - -#endif /* __GPC_CANVAS_H__ */ diff --git a/source/gameengine/GamePlayer/common/GPC_KeyboardDevice.cpp b/source/gameengine/GamePlayer/common/GPC_KeyboardDevice.cpp deleted file mode 100644 index a48540e2bdb4..000000000000 --- a/source/gameengine/GamePlayer/common/GPC_KeyboardDevice.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/GamePlayer/common/GPC_KeyboardDevice.cpp - * \ingroup player - */ - - -#include "GPC_KeyboardDevice.h" - -#include - -/** - * NextFrame toggles currentTable with previousTable, - * and copies relevant event information from previous to current table - * (pressed keys need to be remembered). - */ -void GPC_KeyboardDevice::NextFrame() -{ - SCA_IInputDevice::NextFrame(); - - // Now convert justpressed key events into regular (active) keyevents - int previousTable = 1-m_currentTable; - for (int keyevent= KX_BEGINKEY; keyevent<= KX_ENDKEY;keyevent++) - { - SCA_InputEvent& oldevent = m_eventStatusTables[previousTable][keyevent]; - if (oldevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED || - oldevent.m_status == SCA_InputEvent::KX_ACTIVE ) - { - m_eventStatusTables[m_currentTable][keyevent] = oldevent; - m_eventStatusTables[m_currentTable][keyevent].m_status = SCA_InputEvent::KX_ACTIVE; - //m_eventStatusTables[m_currentTable][keyevent].m_status = SCA_InputEvent::KX_JUSTACTIVATED; - } - } -} - - - -/** - * ConvertBPEvent translates Windows keyboard events into ketsji kbd events. - * Extra event information is stored, like ramp-mode (just released/pressed) - */ -bool GPC_KeyboardDevice::ConvertEvent(int incode, int val, unsigned int unicode) -{ - bool result = false; - - // convert event - KX_EnumInputs kxevent = this->ToNative(incode); - - // only process it, if it's a key - if (kxevent >= KX_BEGINKEY && kxevent <= KX_ENDKEY) - { - int previousTable = 1-m_currentTable; - - if (val > 0) - { - if (kxevent == SCA_IInputDevice::KX_ESCKEY && val != 0 && !m_hookesc) - result = true; - - // todo: convert val ?? - m_eventStatusTables[m_currentTable][kxevent].m_eventval = val ; //??? - m_eventStatusTables[m_currentTable][kxevent].m_unicode = unicode ; - - switch (m_eventStatusTables[previousTable][kxevent].m_status) - { - case SCA_InputEvent::KX_JUSTACTIVATED: - case SCA_InputEvent::KX_ACTIVE: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_ACTIVE; - break; - } - - case SCA_InputEvent::KX_NO_INPUTSTATUS: - default: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTACTIVATED; - } - } - - } else - { - - switch (m_eventStatusTables[previousTable][kxevent].m_status) - { - case SCA_InputEvent::KX_JUSTACTIVATED: - case SCA_InputEvent::KX_ACTIVE: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTRELEASED; - break; - } - default: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_NO_INPUTSTATUS; - } - } - } - } - return result; -} - -void GPC_KeyboardDevice::HookEscape() -{ - m_hookesc = true; -} diff --git a/source/gameengine/GamePlayer/common/GPC_KeyboardDevice.h b/source/gameengine/GamePlayer/common/GPC_KeyboardDevice.h deleted file mode 100644 index dc517b6ec251..000000000000 --- a/source/gameengine/GamePlayer/common/GPC_KeyboardDevice.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file GPC_KeyboardDevice.h - * \ingroup player - */ - -#ifndef __GPC_KEYBOARDDEVICE_H__ -#define __GPC_KEYBOARDDEVICE_H__ - -#ifdef WIN32 -#pragma warning (disable:4786) -#endif /* WIN32 */ - -#include "SCA_IInputDevice.h" - -#include - - -/** - * System independent implementation of SCA_IInputDevice. - * System dependent keyboard devices need only to inherit this class - * and fill the m_reverseKeyTranslateTable key translation map. - * \see SCA_IInputDevice - */ - -class GPC_KeyboardDevice : public SCA_IInputDevice -{ -protected: - - /** - * This map converts system dependent keyboard codes into Ketsji codes. - * System dependent keyboard codes are stored as ints. - */ - std::map m_reverseKeyTranslateTable; - short m_exitkey; - -public: - bool m_hookesc; - GPC_KeyboardDevice() - : m_hookesc(false) - { - } - - virtual ~GPC_KeyboardDevice(void) - { - } - - virtual bool IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode) - { - return false; - } - - virtual void NextFrame(); - - virtual KX_EnumInputs ToNative(int incode) - { - return m_reverseKeyTranslateTable[incode]; - } - - virtual bool ConvertEvent(int incode, int val, unsigned int unicode); - - virtual void HookEscape(); -}; - -#endif /* __GPC_KEYBOARDDEVICE_H__ */ diff --git a/source/gameengine/GamePlayer/common/GPC_MouseDevice.cpp b/source/gameengine/GamePlayer/common/GPC_MouseDevice.cpp deleted file mode 100644 index df388d4f5db8..000000000000 --- a/source/gameengine/GamePlayer/common/GPC_MouseDevice.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/GamePlayer/common/GPC_MouseDevice.cpp - * \ingroup player - */ - - -#include "GPC_MouseDevice.h" - -GPC_MouseDevice::GPC_MouseDevice() -{ - -} -GPC_MouseDevice::~GPC_MouseDevice() -{ - -} - -/** - * IsPressed gives boolean information about mouse status, true if pressed, false if not. - */ -bool GPC_MouseDevice::IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode) -{ - const SCA_InputEvent & inevent = m_eventStatusTables[m_currentTable][inputcode]; - bool pressed = (inevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED || - inevent.m_status == SCA_InputEvent::KX_ACTIVE); - return pressed; -} - - -/** - * NextFrame toggles currentTable with previousTable, - * and copies relevant event information from previous to current table - * (pressed keys need to be remembered). - */ -void GPC_MouseDevice::NextFrame() -{ - SCA_IInputDevice::NextFrame(); - - // Convert just pressed events into regular (active) events - int previousTable = 1-m_currentTable; - for (int mouseevent= KX_BEGINMOUSE; mouseevent< KX_ENDMOUSEBUTTONS; mouseevent++) { - SCA_InputEvent& oldevent = m_eventStatusTables[previousTable][mouseevent]; - if (oldevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED || - oldevent.m_status == SCA_InputEvent::KX_ACTIVE) - { - m_eventStatusTables[m_currentTable][mouseevent] = oldevent; - m_eventStatusTables[m_currentTable][mouseevent].m_status = SCA_InputEvent::KX_ACTIVE; - } - } - for (int mousemove= KX_ENDMOUSEBUTTONS; mousemove< KX_ENDMOUSE; mousemove++) { - SCA_InputEvent& oldevent = m_eventStatusTables[previousTable][mousemove]; - m_eventStatusTables[m_currentTable][mousemove] = oldevent; - if (oldevent.m_status == SCA_InputEvent::KX_JUSTACTIVATED || - oldevent.m_status == SCA_InputEvent::KX_ACTIVE) - { - m_eventStatusTables[m_currentTable][mousemove].m_status = SCA_InputEvent::KX_JUSTRELEASED; - } - else { - if (oldevent.m_status == SCA_InputEvent::KX_JUSTRELEASED) { - m_eventStatusTables[m_currentTable][mousemove].m_status = SCA_InputEvent::KX_NO_INPUTSTATUS; - } - } - } -} - - -bool GPC_MouseDevice::ConvertButtonEvent(TButtonId button, bool isDown) -{ - bool result = false; - - switch (button) - { - case buttonLeft: - result = ConvertEvent(KX_LEFTMOUSE, isDown, 0); - break; - case buttonMiddle: - result = ConvertEvent(KX_MIDDLEMOUSE, isDown, 0); - break; - case buttonRight: - result = ConvertEvent(KX_RIGHTMOUSE, isDown, 0); - break; - case buttonWheelUp: - result = ConvertEvent(KX_WHEELUPMOUSE, isDown, 0); - break; - case buttonWheelDown: - result = ConvertEvent(KX_WHEELDOWNMOUSE, isDown, 0); - break; - default: - // Should not happen! - break; - } - - return result; -} - -/** - * Splits combined button and x,y cursor move events into separate Ketsji - * x and y move and button events. - */ -bool GPC_MouseDevice::ConvertButtonEvent(TButtonId button, bool isDown, int x, int y) -{ - // First update state tables for cursor move. - bool result = ConvertMoveEvent(x, y); - - // Now update for button state. - if (result) { - result = ConvertButtonEvent(button, isDown); - } - - return result; -} - -/** - * Splits combined x,y move into separate Ketsji x and y move events. - */ -bool GPC_MouseDevice::ConvertMoveEvent(int x, int y) -{ - bool result; - - // Convert to local coordinates? - result = ConvertEvent(KX_MOUSEX, x, 0); - if (result) { - result = ConvertEvent(KX_MOUSEY, y, 0); - } - - return result; -} - - -bool GPC_MouseDevice::ConvertEvent(KX_EnumInputs kxevent, int eventval, unsigned int unicode) -{ - bool result = true; - - // Only process it, if it's a mouse event - if (kxevent > KX_BEGINMOUSE && kxevent < KX_ENDMOUSE) { - int previousTable = 1-m_currentTable; - - if (eventval > 0) { - m_eventStatusTables[m_currentTable][kxevent].m_eventval = eventval; - - switch (m_eventStatusTables[previousTable][kxevent].m_status) - { - case SCA_InputEvent::KX_ACTIVE: - case SCA_InputEvent::KX_JUSTACTIVATED: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_ACTIVE; - break; - } - case SCA_InputEvent::KX_JUSTRELEASED: - { - if ( kxevent > KX_BEGINMOUSEBUTTONS && kxevent < KX_ENDMOUSEBUTTONS) - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTACTIVATED; - } else - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_ACTIVE; - - } - break; - } - default: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTACTIVATED; - } - } - - } - else { - switch (m_eventStatusTables[previousTable][kxevent].m_status) - { - case SCA_InputEvent::KX_JUSTACTIVATED: - case SCA_InputEvent::KX_ACTIVE: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_JUSTRELEASED; - break; - } - default: - { - m_eventStatusTables[m_currentTable][kxevent].m_status = SCA_InputEvent::KX_NO_INPUTSTATUS; - } - } - } - } - else { - result = false; - } - return result; -} diff --git a/source/gameengine/GamePlayer/common/GPC_MouseDevice.h b/source/gameengine/GamePlayer/common/GPC_MouseDevice.h deleted file mode 100644 index 249221977233..000000000000 --- a/source/gameengine/GamePlayer/common/GPC_MouseDevice.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file GPC_MouseDevice.h - * \ingroup player - */ - -#ifndef __GPC_MOUSEDEVICE_H__ -#define __GPC_MOUSEDEVICE_H__ - -#ifdef WIN32 -#pragma warning (disable:4786) -#endif /* WIN32 */ - -#include "SCA_IInputDevice.h" - - -/** - * Generic Ketsji mouse device. - * \see SCA_IInputDevice - */ -class GPC_MouseDevice : public SCA_IInputDevice -{ -public: - /** - * Button identifier. - */ - typedef enum { - buttonLeft, - buttonMiddle, - buttonRight, - buttonWheelUp, - buttonWheelDown - } TButtonId; - - GPC_MouseDevice(); - virtual ~GPC_MouseDevice(void); - - virtual bool IsPressed(SCA_IInputDevice::KX_EnumInputs inputcode); - virtual void NextFrame(); - - /** - * Call this routine to update the mouse device when a button state changes. - * \param button Which button state changes. - * \param isDown The new state of the button. - * \return Indication as to whether the event was processed. - */ - virtual bool ConvertButtonEvent(TButtonId button, bool isDown); - - /** - * Call this routine to update the mouse device when a button state and - * cursor position changes at the same time (e.g. in Win32 messages). - * \param button Which button state changes. - * \param isDown The new state of the button. - * \param x Position x-coordinate of the cursor at the time of the state change. - * \param y Position y-coordinate of the cursor at the time of the state change. - * \return Indication as to whether the event was processed. - */ - virtual bool ConvertButtonEvent(TButtonId button, bool isDown, int x, int y); - - /** - * Call this routine to update the mouse device when the cursor has moved. - * \param x Position x-coordinate of the cursor. - * \param y Position y-coordinate of the cursor. - * \return Indication as to whether the event was processed. - */ - virtual bool ConvertMoveEvent(int x, int y); - -protected: - /** - * This routine converts a single mouse event to a Ketsji mouse event. - * \param kxevent Ketsji event code. - * \param eventval Value for this event. - * \return Indication as to whether the event was processed. - */ - virtual bool ConvertEvent(KX_EnumInputs kxevent, int eventval, unsigned int unicode); -}; - -#endif /* __GPC_MOUSEDEVICE_H__ */ diff --git a/source/gameengine/GamePlayer/ghost/CMakeLists.txt b/source/gameengine/GamePlayer/ghost/CMakeLists.txt deleted file mode 100644 index 577e25d61988..000000000000 --- a/source/gameengine/GamePlayer/ghost/CMakeLists.txt +++ /dev/null @@ -1,111 +0,0 @@ -# ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 LICENSE BLOCK ***** - -set(INC - . - ../common - ../../BlenderRoutines - ../../Converter - ../../Expressions - ../../GameLogic - ../../Ketsji - ../../Network - ../../Network/LoopBackNetwork - ../../Physics/common - ../../Rasterizer - ../../Rasterizer/RAS_OpenGLRasterizer - ../../SceneGraph - ../../../blender - ../../../blender/blenfont - ../../../blender/blenkernel - ../../../blender/blenlib - ../../../blender/blenloader - ../../../blender/blentranslation - ../../../blender/gpu - ../../../blender/imbuf - ../../../blender/makesdna - ../../../blender/makesrna - ../../../../intern/container - ../../../../intern/ghost - ../../../../intern/glew-mx - ../../../../intern/guardedalloc - ../../../../intern/string - ../../../../intern/memutil -) - -set(INC_SYS - ../../../../intern/moto/include - ${GLEW_INCLUDE_PATH} - ${PYTHON_INCLUDE_DIRS} - ${BOOST_INCLUDE_DIR} -) - -set(SRC - GPG_Application.cpp - GPG_Canvas.cpp - GPG_KeyboardDevice.cpp - GPG_System.cpp - GPG_ghost.cpp - - GPG_Application.h - GPG_Canvas.h - GPG_KeyboardDevice.h - GPG_System.h -) - -add_definitions(${GL_DEFINITIONS}) - -if(WIN32) - blender_include_dirs(../../../../intern/utfconv) -endif() - -if(WITH_INPUT_NDOF) - add_definitions(-DWITH_INPUT_NDOF) -endif(WITH_INPUT_NDOF) - -if(WITH_CODEC_FFMPEG) - add_definitions(-DWITH_FFMPEG) -endif() - -if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) -endif() - -if(WITH_AUDASPACE) - add_definitions(${AUDASPACE_DEFINITIONS}) - - list(APPEND INC_SYS - ${AUDASPACE_C_INCLUDE_DIRS} - ) -endif() - -if(WITH_SDL AND WITH_SDL_DYNLOAD) - list(APPEND INC - ../../../../extern/sdlew/include - ) - add_definitions(-DWITH_SDL_DYNLOAD) -endif() - -blender_add_lib_nolist(ge_player_ghost "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp deleted file mode 100644 index 8cdeb0f28499..000000000000 --- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp +++ /dev/null @@ -1,998 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - * GHOST Blender Player application implementation file. - */ - -/** \file gameengine/GamePlayer/ghost/GPG_Application.cpp - * \ingroup player - */ - - -#ifdef WIN32 -# pragma warning (disable:4786) // suppress stl-MSVC debug info warning -# include -#endif - -#include "GPU_glew.h" -#include "GPU_extensions.h" -#include "GPU_init_exit.h" - -#include "GPG_Application.h" -#include "BL_BlenderDataConversion.h" - -#include -#include -#include - -/********************************** - * Begin Blender include block - **********************************/ -#ifdef __cplusplus -extern "C" -{ -#endif // __cplusplus -#include "BLI_blenlib.h" -#include "BLO_readfile.h" -#include "BKE_global.h" -#include "BKE_main.h" -#include "BKE_sound.h" -#include "IMB_imbuf.h" -#include "DNA_scene_types.h" -#ifdef __cplusplus -} -#endif // __cplusplus -/********************************** - * End Blender include block - **********************************/ - - -#include "BL_System.h" -#include "KX_KetsjiEngine.h" - -// include files needed by "KX_BlenderSceneConverter.h" -#include "CTR_Map.h" -#include "SCA_IActuator.h" -#include "RAS_MeshObject.h" -#include "RAS_OpenGLRasterizer.h" -#include "RAS_ListRasterizer.h" -#include "KX_PythonInit.h" -#include "KX_PyConstraintBinding.h" -#include "BL_Material.h" // MAXTEX - -#include "KX_BlenderSceneConverter.h" -#include "NG_LoopBackNetworkDeviceInterface.h" - -#include "GPC_MouseDevice.h" -#include "GPG_Canvas.h" -#include "GPG_KeyboardDevice.h" -#include "GPG_System.h" - -#include "STR_String.h" - -#include "GHOST_ISystem.h" -#include "GHOST_IEvent.h" -#include "GHOST_IEventConsumer.h" -#include "GHOST_IWindow.h" -#include "GHOST_Rect.h" - -#ifdef WITH_AUDASPACE -# include AUD_DEVICE_H -#endif - -static void frameTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time); - -static GHOST_ISystem* fSystem = 0; -static const int kTimerFreq = 10; - -GPG_Application::GPG_Application(GHOST_ISystem* system) - : m_startSceneName(""), - m_startScene(0), - m_maggie(0), - m_kxStartScene(NULL), - m_exitRequested(0), - m_system(system), - m_mainWindow(0), - m_frameTimer(0), - m_cursor(GHOST_kStandardCursorFirstCursor), - m_engineInitialized(0), - m_engineRunning(0), - m_isEmbedded(false), - m_ketsjiengine(0), - m_kxsystem(0), - m_keyboard(0), - m_mouse(0), - m_canvas(0), - m_rasterizer(0), - m_sceneconverter(0), - m_networkdevice(0), - m_blendermat(0), - m_blenderglslmat(0), - m_pyGlobalDictString(0), - m_pyGlobalDictString_Length(0) -{ - fSystem = system; -} - - - -GPG_Application::~GPG_Application(void) -{ - if (m_pyGlobalDictString) { - delete [] m_pyGlobalDictString; - m_pyGlobalDictString = 0; - m_pyGlobalDictString_Length = 0; - } - - exitEngine(); - fSystem->disposeWindow(m_mainWindow); -} - - - -bool GPG_Application::SetGameEngineData(struct Main* maggie, Scene *scene, GlobalSettings *gs, int argc, char **argv) -{ - bool result = false; - - if (maggie != NULL && scene != NULL) - { -// XXX G.scene = scene; - m_maggie = maggie; - m_startSceneName = scene->id.name+2; - m_startScene = scene; - result = true; - } - - /* Python needs these */ - m_argc= argc; - m_argv= argv; - - /* Global Settings */ - m_globalSettings= gs; - - return result; -} - - -#ifdef WIN32 -#define SCR_SAVE_MOUSE_MOVE_THRESHOLD 15 - -static HWND found_ghost_window_hwnd; -static GHOST_IWindow* ghost_window_to_find; -static WNDPROC ghost_wnd_proc; -static POINT scr_save_mouse_pos; - -static LRESULT CALLBACK screenSaverWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - BOOL close = false; - switch (uMsg) - { - case WM_MOUSEMOVE: - { - POINT pt; - GetCursorPos(&pt); - LONG dx = scr_save_mouse_pos.x - pt.x; - LONG dy = scr_save_mouse_pos.y - pt.y; - if (abs(dx) > SCR_SAVE_MOUSE_MOVE_THRESHOLD - || abs(dy) > SCR_SAVE_MOUSE_MOVE_THRESHOLD) - { - close = true; - } - scr_save_mouse_pos = pt; - break; - } - case WM_LBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_RBUTTONDOWN: - case WM_KEYDOWN: - close = true; - } - if (close) - PostMessage(hwnd,WM_CLOSE,0,0); - return CallWindowProc(ghost_wnd_proc, hwnd, uMsg, wParam, lParam); -} - -BOOL CALLBACK findGhostWindowHWNDProc(HWND hwnd, LPARAM lParam) -{ - GHOST_IWindow *p = (GHOST_IWindow*) GetWindowLongPtr(hwnd, GWLP_USERDATA); - BOOL ret = true; - if (p == ghost_window_to_find) - { - found_ghost_window_hwnd = hwnd; - ret = false; - } - return ret; -} - -static HWND findGhostWindowHWND(GHOST_IWindow* window) -{ - found_ghost_window_hwnd = NULL; - ghost_window_to_find = window; - EnumWindows(findGhostWindowHWNDProc, NULL); - return found_ghost_window_hwnd; -} - -bool GPG_Application::startScreenSaverPreview( - HWND parentWindow, - const bool stereoVisual, - const int stereoMode, - const GHOST_TUns16 samples) -{ - bool success = false; - - RECT rc; - if (GetWindowRect(parentWindow, &rc)) - { - int windowWidth = rc.right - rc.left; - int windowHeight = rc.bottom - rc.top; - STR_String title = ""; - GHOST_GLSettings glSettings = {0}; - - if (stereoVisual) { - glSettings.flags |= GHOST_glStereoVisual; - } - glSettings.numOfAASamples = samples; - - m_mainWindow = fSystem->createWindow(title, 0, 0, windowWidth, windowHeight, GHOST_kWindowStateMinimized, - GHOST_kDrawingContextTypeOpenGL, glSettings); - if (!m_mainWindow) { - printf("error: could not create main window\n"); - exit(-1); - } - - HWND ghost_hwnd = findGhostWindowHWND(m_mainWindow); - if (!ghost_hwnd) { - printf("error: could find main window\n"); - exit(-1); - } - - SetParent(ghost_hwnd, parentWindow); - LONG_PTR style = GetWindowLongPtr(ghost_hwnd, GWL_STYLE); - LONG_PTR exstyle = GetWindowLongPtr(ghost_hwnd, GWL_EXSTYLE); - - RECT adjrc = { 0, 0, windowWidth, windowHeight }; - AdjustWindowRectEx(&adjrc, style, false, exstyle); - - style = (style & (~(WS_POPUP|WS_OVERLAPPEDWINDOW|WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_TILEDWINDOW ))) | WS_CHILD; - SetWindowLongPtr(ghost_hwnd, GWL_STYLE, style); - SetWindowPos(ghost_hwnd, NULL, adjrc.left, adjrc.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE); - - /* Check the size of the client rectangle of the window and resize the window - * so that the client rectangle has the size requested. - */ - m_mainWindow->setClientSize(windowWidth, windowHeight); - - success = initEngine(m_mainWindow, stereoMode); - if (success) { - success = startEngine(); - } - - } - return success; -} - -bool GPG_Application::startScreenSaverFullScreen( - int width, - int height, - int bpp,int frequency, - const bool stereoVisual, - const int stereoMode, - const GHOST_TUns16 samples) -{ - bool ret = startFullScreen(width, height, bpp, frequency, stereoVisual, stereoMode, 0, samples); - if (ret) - { - HWND ghost_hwnd = findGhostWindowHWND(m_mainWindow); - if (ghost_hwnd != NULL) - { - GetCursorPos(&scr_save_mouse_pos); - ghost_wnd_proc = (WNDPROC) GetWindowLongPtr(ghost_hwnd, GWLP_WNDPROC); - SetWindowLongPtr(ghost_hwnd,GWLP_WNDPROC, (uintptr_t) screenSaverWindowProc); - } - } - return ret; -} - -#endif - -bool GPG_Application::startWindow( - STR_String& title, - int windowLeft, - int windowTop, - int windowWidth, - int windowHeight, - const bool stereoVisual, - const int stereoMode, - const int alphaBackground, - const GHOST_TUns16 samples) -{ - GHOST_GLSettings glSettings = {0}; - bool success; - // Create the main window - //STR_String title ("Blender Player - GHOST"); - if (stereoVisual) - glSettings.flags |= GHOST_glStereoVisual; - if (alphaBackground) - glSettings.flags |= GHOST_glAlphaBackground; - glSettings.numOfAASamples = samples; - - m_mainWindow = fSystem->createWindow(title, windowLeft, windowTop, windowWidth, windowHeight, GHOST_kWindowStateNormal, - GHOST_kDrawingContextTypeOpenGL, glSettings); - if (!m_mainWindow) { - printf("error: could not create main window\n"); - exit(-1); - } - - /* Check the size of the client rectangle of the window and resize the window - * so that the client rectangle has the size requested. - */ - m_mainWindow->setClientSize(windowWidth, windowHeight); - m_mainWindow->setCursorVisibility(false); - - success = initEngine(m_mainWindow, stereoMode); - if (success) { - success = startEngine(); - } - return success; -} - -bool GPG_Application::startEmbeddedWindow( - STR_String& title, - const GHOST_TEmbedderWindowID parentWindow, - const bool stereoVisual, - const int stereoMode, - const int alphaBackground, - const GHOST_TUns16 samples) -{ - GHOST_TWindowState state = GHOST_kWindowStateNormal; - GHOST_GLSettings glSettings = {0}; - - if (stereoVisual) - glSettings.flags |= GHOST_glStereoVisual; - if (alphaBackground) - glSettings.flags |= GHOST_glAlphaBackground; - glSettings.numOfAASamples = samples; - - if (parentWindow != 0) - state = GHOST_kWindowStateEmbedded; - m_mainWindow = fSystem->createWindow(title, 0, 0, 0, 0, state, - GHOST_kDrawingContextTypeOpenGL, glSettings, parentWindow); - - if (!m_mainWindow) { - printf("error: could not create main window\n"); - exit(-1); - } - m_isEmbedded = true; - - bool success = initEngine(m_mainWindow, stereoMode); - if (success) { - success = startEngine(); - } - return success; -} - - -bool GPG_Application::startFullScreen( - int width, - int height, - int bpp,int frequency, - const bool stereoVisual, - const int stereoMode, - const int alphaBackground, - const GHOST_TUns16 samples, - bool useDesktop) -{ - bool success; - GHOST_TUns32 sysWidth=0, sysHeight=0; - fSystem->getMainDisplayDimensions(sysWidth, sysHeight); - // Create the main window - GHOST_DisplaySetting setting; - setting.xPixels = (useDesktop) ? sysWidth : width; - setting.yPixels = (useDesktop) ? sysHeight : height; - setting.bpp = bpp; - setting.frequency = frequency; - - fSystem->beginFullScreen(setting, &m_mainWindow, stereoVisual, alphaBackground, samples); - m_mainWindow->setCursorVisibility(false); - /* note that X11 ignores this (it uses a window internally for fullscreen) */ - m_mainWindow->setState(GHOST_kWindowStateFullScreen); - - success = initEngine(m_mainWindow, stereoMode); - if (success) { - success = startEngine(); - } - return success; -} - - - - -bool GPG_Application::StartGameEngine(int stereoMode) -{ - bool success = initEngine(m_mainWindow, stereoMode); - - if (success) - success = startEngine(); - - return success; -} - - - -void GPG_Application::StopGameEngine() -{ - exitEngine(); -} - - - -bool GPG_Application::processEvent(GHOST_IEvent* event) -{ - bool handled = true; - - switch (event->getType()) - { - case GHOST_kEventUnknown: - break; - - case GHOST_kEventButtonDown: - handled = handleButton(event, true); - break; - - case GHOST_kEventButtonUp: - handled = handleButton(event, false); - break; - - case GHOST_kEventWheel: - handled = handleWheel(event); - break; - - case GHOST_kEventCursorMove: - handled = handleCursorMove(event); - break; - - case GHOST_kEventKeyDown: - handleKey(event, true); - break; - - case GHOST_kEventKeyUp: - handleKey(event, false); - break; - - - case GHOST_kEventWindowClose: - case GHOST_kEventQuit: - m_exitRequested = KX_EXIT_REQUEST_OUTSIDE; - break; - - case GHOST_kEventWindowActivate: - handled = false; - break; - case GHOST_kEventWindowDeactivate: - handled = false; - break; - - // The player now runs as often as it can (repsecting vsync and fixedtime). - // This allows the player to break 100fps, but this code is being left here - // as reference. (see EngineNextFrame) - //case GHOST_kEventWindowUpdate: - // { - // GHOST_IWindow* window = event->getWindow(); - // if (!m_system->validWindow(window)) break; - // // Update the state of the game engine - // if (m_kxsystem && !m_exitRequested) - // { - // // Proceed to next frame - // window->activateDrawingContext(); - - // // first check if we want to exit - // m_exitRequested = m_ketsjiengine->GetExitCode(); - // - // // kick the engine - // bool renderFrame = m_ketsjiengine->NextFrame(); - // if (renderFrame) - // { - // // render the frame - // m_ketsjiengine->Render(); - // } - // } - // m_exitString = m_ketsjiengine->GetExitString(); - // } - // break; - // - case GHOST_kEventWindowSize: - { - GHOST_IWindow* window = event->getWindow(); - if (!m_system->validWindow(window)) break; - if (m_canvas) { - GHOST_Rect bnds; - window->getClientBounds(bnds); - m_canvas->Resize(bnds.getWidth(), bnds.getHeight()); - m_ketsjiengine->Resize(); - } - } - break; - - default: - handled = false; - break; - } - return handled; -} - - - -int GPG_Application::getExitRequested(void) -{ - return m_exitRequested; -} - - -GlobalSettings* GPG_Application::getGlobalSettings(void) -{ - return m_ketsjiengine->GetGlobalSettings(); -} - - - -const STR_String& GPG_Application::getExitString(void) -{ - return m_exitString; -} - - - -bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode) -{ - if (!m_engineInitialized) - { - GPU_init(); - - // get and set the preferences - SYS_SystemHandle syshandle = SYS_GetSystem(); - if (!syshandle) - return false; - - // SYS_WriteCommandLineInt(syshandle, "fixedtime", 0); - // SYS_WriteCommandLineInt(syshandle, "vertexarrays",1); - GameData *gm= &m_startScene->gm; - bool properties = (SYS_GetCommandLineInt(syshandle, "show_properties", 0) != 0); - bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0); - - bool showPhysics = (gm->flag & GAME_SHOW_PHYSICS); - SYS_WriteCommandLineInt(syshandle, "show_physics", showPhysics); - - bool fixed_framerate= (SYS_GetCommandLineInt(syshandle, "fixedtime", (gm->flag & GAME_ENABLE_ALL_FRAMES)) != 0); - bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0); - bool useLists = (SYS_GetCommandLineInt(syshandle, "displaylists", gm->flag & GAME_DISPLAY_LISTS) != 0) && GPU_display_list_support(); - bool nodepwarnings = (SYS_GetCommandLineInt(syshandle, "ignore_deprecation_warnings", 1) != 0); - bool restrictAnimFPS = (gm->flag & GAME_RESTRICT_ANIM_UPDATES) != 0; - - m_blendermat = (SYS_GetCommandLineInt(syshandle, "blender_material", 1) != 0); - m_blenderglslmat = (SYS_GetCommandLineInt(syshandle, "blender_glsl_material", 1) != 0); - - // create the canvas, rasterizer and rendertools - m_canvas = new GPG_Canvas(window); - if (!m_canvas) - return false; - - if (gm->vsync == VSYNC_ADAPTIVE) - m_canvas->SetSwapInterval(-1); - else - m_canvas->SetSwapInterval((gm->vsync == VSYNC_ON) ? 1 : 0); - - m_canvas->Init(); - if (gm->flag & GAME_SHOW_MOUSE) - m_canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL); - - RAS_STORAGE_TYPE raster_storage = RAS_AUTO_STORAGE; - - if (gm->raster_storage == RAS_STORE_VBO) { - raster_storage = RAS_VBO; - } - else if (gm->raster_storage == RAS_STORE_VA) { - raster_storage = RAS_VA; - } - //Don't use displaylists with VBOs - //If auto starts using VBOs, make sure to check for that here - if (useLists && raster_storage != RAS_VBO) - m_rasterizer = new RAS_ListRasterizer(m_canvas, true, raster_storage); - else - m_rasterizer = new RAS_OpenGLRasterizer(m_canvas, raster_storage); - - /* Stereo parameters - Eye Separation from the UI - stereomode from the command-line/UI */ - m_rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) stereoMode); - m_rasterizer->SetEyeSeparation(m_startScene->gm.eyeseparation); - - if (!m_rasterizer) - goto initFailed; - - m_rasterizer->PrintHardwareInfo(); - - // create the inputdevices - m_keyboard = new GPG_KeyboardDevice(); - if (!m_keyboard) - goto initFailed; - - m_mouse = new GPC_MouseDevice(); - if (!m_mouse) - goto initFailed; - - // create a networkdevice - m_networkdevice = new NG_LoopBackNetworkDeviceInterface(); - if (!m_networkdevice) - goto initFailed; - - BKE_sound_init(m_maggie); - - // create a ketsjisystem (only needed for timing and stuff) - m_kxsystem = new GPG_System (m_system); - if (!m_kxsystem) - goto initFailed; - - // create the ketsjiengine - m_ketsjiengine = new KX_KetsjiEngine(m_kxsystem); - - // set the devices - m_ketsjiengine->SetKeyboardDevice(m_keyboard); - m_ketsjiengine->SetMouseDevice(m_mouse); - m_ketsjiengine->SetNetworkDevice(m_networkdevice); - m_ketsjiengine->SetCanvas(m_canvas); - m_ketsjiengine->SetRasterizer(m_rasterizer); - - KX_KetsjiEngine::SetExitKey(ConvertKeyCode(gm->exitkey)); -#ifdef WITH_PYTHON - CValue::SetDeprecationWarnings(nodepwarnings); -#else - (void)nodepwarnings; -#endif - - m_ketsjiengine->SetUseFixedTime(fixed_framerate); - m_ketsjiengine->SetTimingDisplay(frameRate, profile, properties); - m_ketsjiengine->SetRestrictAnimationFPS(restrictAnimFPS); - - //set the global settings (carried over if restart/load new files) - m_ketsjiengine->SetGlobalSettings(m_globalSettings); - m_ketsjiengine->SetRender(true); - - m_engineInitialized = true; - } - - return m_engineInitialized; -initFailed: - BKE_sound_exit(); - delete m_kxsystem; - delete m_networkdevice; - delete m_mouse; - delete m_keyboard; - delete m_rasterizer; - delete m_canvas; - m_canvas = NULL; - m_rasterizer = NULL; - m_keyboard = NULL; - m_mouse = NULL; - m_networkdevice = NULL; - m_kxsystem = NULL; - return false; -} - - - -bool GPG_Application::startEngine(void) -{ - if (m_engineRunning) { - return false; - } - - // Temporary hack to disable banner display for NaN approved content. - /* - m_canvas->SetBannerDisplayEnabled(true); - Camera* cam; - cam = (Camera*)scene->camera->data; - if (cam) { - if (((cam->flag) & 48)==48) { - m_canvas->SetBannerDisplayEnabled(false); - } - } - else { - showError(CString("Camera data invalid.")); - return false; - } - */ - - // create a scene converter, create and convert the stratingscene - m_sceneconverter = new KX_BlenderSceneConverter(m_maggie, m_ketsjiengine); - if (m_sceneconverter) - { - STR_String m_kxStartScenename = m_startSceneName.Ptr(); - m_ketsjiengine->SetSceneConverter(m_sceneconverter); - - // if (always_use_expand_framing) - // sceneconverter->SetAlwaysUseExpandFraming(true); - if (m_blendermat) - m_sceneconverter->SetMaterials(true); - if (m_blenderglslmat && (m_globalSettings->matmode == GAME_MAT_GLSL)) - m_sceneconverter->SetGLSLMaterials(true); - if (m_startScene->gm.flag & GAME_NO_MATERIAL_CACHING) - m_sceneconverter->SetCacheMaterials(false); - - m_kxStartScene = new KX_Scene(m_keyboard, - m_mouse, - m_networkdevice, - m_kxStartScenename, - m_startScene, - m_canvas); - -#ifdef WITH_PYTHON - // some python things - PyObject *gameLogic, *gameLogic_keys; - setupGamePython(m_ketsjiengine, m_kxStartScene, m_maggie, NULL, &gameLogic, &gameLogic_keys, m_argc, m_argv); -#endif // WITH_PYTHON - - //initialize Dome Settings - if (m_startScene->gm.stereoflag == STEREO_DOME) - m_ketsjiengine->InitDome(m_startScene->gm.dome.res, m_startScene->gm.dome.mode, m_startScene->gm.dome.angle, m_startScene->gm.dome.resbuf, m_startScene->gm.dome.tilt, m_startScene->gm.dome.warptext); - - // initialize 3D Audio Settings - AUD_Device* device = BKE_sound_get_device(); - AUD_Device_setSpeedOfSound(device, m_startScene->audio.speed_of_sound); - AUD_Device_setDopplerFactor(device, m_startScene->audio.doppler_factor); - AUD_Device_setDistanceModel(device, AUD_DistanceModel(m_startScene->audio.distance_model)); - -#ifdef WITH_PYTHON - // Set the GameLogic.globalDict from marshal'd data, so we can - // load new blend files and keep data in GameLogic.globalDict - loadGamePythonConfig(m_pyGlobalDictString, m_pyGlobalDictString_Length); -#endif - m_sceneconverter->ConvertScene( - m_kxStartScene, - m_rasterizer, - m_canvas); - m_ketsjiengine->AddScene(m_kxStartScene); - - // Create a timer that is used to kick the engine - if (!m_frameTimer) { - m_frameTimer = m_system->installTimer(0, kTimerFreq, frameTimerProc, m_mainWindow); - } - m_rasterizer->Init(); - m_ketsjiengine->StartEngine(true); - m_engineRunning = true; - - // Set the animation playback rate for ipo's and actions - // the framerate below should patch with FPS macro defined in blendef.h - // Could be in StartEngine set the framerate, we need the scene to do this - Scene *scene= m_kxStartScene->GetBlenderScene(); // needed for macro - m_ketsjiengine->SetAnimFrameRate(FPS); - } - - if (!m_engineRunning) - { - stopEngine(); - } - - return m_engineRunning; -} - - -void GPG_Application::stopEngine() -{ -#ifdef WITH_PYTHON - // GameLogic.globalDict gets converted into a buffer, and sorted in - // m_pyGlobalDictString so we can restore after python has stopped - // and started between .blend file loads. - if (m_pyGlobalDictString) { - delete [] m_pyGlobalDictString; - m_pyGlobalDictString = 0; - } - - m_pyGlobalDictString_Length = saveGamePythonConfig(&m_pyGlobalDictString); -#endif - - m_ketsjiengine->StopEngine(); - m_networkdevice->Disconnect(); - - if (m_sceneconverter) { - delete m_sceneconverter; - m_sceneconverter = 0; - } - if (m_system && m_frameTimer) { - m_system->removeTimer(m_frameTimer); - m_frameTimer = 0; - } - - m_engineRunning = false; -} - -void GPG_Application::EngineNextFrame() -{ - // Update the state of the game engine - if (m_kxsystem && !m_exitRequested) - { - // Proceed to next frame - if (m_mainWindow) - m_mainWindow->activateDrawingContext(); - - // first check if we want to exit - m_exitRequested = m_ketsjiengine->GetExitCode(); - - // kick the engine - bool renderFrame = m_ketsjiengine->NextFrame(); - if (renderFrame && m_mainWindow) - { - // render the frame - m_ketsjiengine->Render(); - } - } - m_exitString = m_ketsjiengine->GetExitString(); -} - -void GPG_Application::exitEngine() -{ - // We only want to kill the engine if it has been initialized - if (!m_engineInitialized) - return; - - BKE_sound_exit(); - if (m_ketsjiengine) - { - stopEngine(); - delete m_ketsjiengine; - m_ketsjiengine = 0; - } - if (m_kxsystem) - { - delete m_kxsystem; - m_kxsystem = 0; - } - if (m_networkdevice) - { - delete m_networkdevice; - m_networkdevice = 0; - } - if (m_mouse) - { - delete m_mouse; - m_mouse = 0; - } - if (m_keyboard) - { - delete m_keyboard; - m_keyboard = 0; - } - if (m_rasterizer) - { - delete m_rasterizer; - m_rasterizer = 0; - } - if (m_canvas) - { - delete m_canvas; - m_canvas = 0; - } - - GPU_exit(); - -#ifdef WITH_PYTHON - // Call this after we're sure nothing needs Python anymore (e.g., destructors) - exitGamePlayerPythonScripting(); -#endif - - m_exitRequested = 0; - m_engineInitialized = false; -} - -bool GPG_Application::handleWheel(GHOST_IEvent* event) -{ - bool handled = false; - MT_assert(event); - if (m_mouse) - { - GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData(); - GHOST_TEventWheelData* wheelData = static_cast(eventData); - GPC_MouseDevice::TButtonId button; - if (wheelData->z > 0) - button = GPC_MouseDevice::buttonWheelUp; - else - button = GPC_MouseDevice::buttonWheelDown; - m_mouse->ConvertButtonEvent(button, true); - handled = true; - } - return handled; -} - -bool GPG_Application::handleButton(GHOST_IEvent* event, bool isDown) -{ - bool handled = false; - MT_assert(event); - if (m_mouse) - { - GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData(); - GHOST_TEventButtonData* buttonData = static_cast(eventData); - GPC_MouseDevice::TButtonId button; - switch (buttonData->button) - { - case GHOST_kButtonMaskMiddle: - button = GPC_MouseDevice::buttonMiddle; - break; - case GHOST_kButtonMaskRight: - button = GPC_MouseDevice::buttonRight; - break; - case GHOST_kButtonMaskLeft: - default: - button = GPC_MouseDevice::buttonLeft; - break; - } - m_mouse->ConvertButtonEvent(button, isDown); - handled = true; - } - return handled; -} - - -bool GPG_Application::handleCursorMove(GHOST_IEvent* event) -{ - bool handled = false; - MT_assert(event); - if (m_mouse && m_mainWindow) - { - GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData(); - GHOST_TEventCursorData* cursorData = static_cast(eventData); - GHOST_TInt32 x, y; - m_mainWindow->screenToClient(cursorData->x, cursorData->y, x, y); - m_mouse->ConvertMoveEvent(x, y); - handled = true; - } - return handled; -} - - -bool GPG_Application::handleKey(GHOST_IEvent* event, bool isDown) -{ - bool handled = false; - MT_assert(event); - if (m_keyboard) - { - GHOST_TEventDataPtr eventData = ((GHOST_IEvent*)event)->getData(); - GHOST_TEventKeyData* keyData = static_cast(eventData); - unsigned int unicode = keyData->utf8_buf[0] ? BLI_str_utf8_as_unicode(keyData->utf8_buf) : keyData->ascii; - - if (m_keyboard->ToNative(keyData->key) == KX_KetsjiEngine::GetExitKey() && !m_keyboard->m_hookesc && !m_isEmbedded) { - m_exitRequested = KX_EXIT_REQUEST_OUTSIDE; - } - m_keyboard->ConvertEvent(keyData->key, isDown, unicode); - handled = true; - } - return handled; -} - - - -static void frameTimerProc(GHOST_ITimerTask* task, GHOST_TUns64 time) -{ - GHOST_IWindow* window = (GHOST_IWindow*)task->getUserData(); - if (fSystem->validWindow(window)) { - window->invalidate(); - } -} diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.h b/source/gameengine/GamePlayer/ghost/GPG_Application.h deleted file mode 100644 index 37e3ea15f8a7..000000000000 --- a/source/gameengine/GamePlayer/ghost/GPG_Application.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file GPG_Application.h - * \ingroup player - * \brief GHOST Blender Player application declaration file. - */ - -#include "GHOST_IEventConsumer.h" -#include "STR_String.h" - -#ifdef WIN32 -#include -#endif - -#include "KX_KetsjiEngine.h" - -class KX_KetsjiEngine; -class KX_Scene; -class KX_ISceneConverter; -class NG_LoopBackNetworkDeviceInterface; -class RAS_IRasterizer; -class GHOST_IEvent; -class GHOST_ISystem; -class GHOST_ITimerTask; -class GHOST_IWindow; -class GPC_MouseDevice; -class GPG_Canvas; -class GPG_KeyboardDevice; -class GPG_System; -struct Main; -struct Scene; - -class GPG_Application : public GHOST_IEventConsumer -{ -public: - GPG_Application(GHOST_ISystem* system); - ~GPG_Application(void); - - bool SetGameEngineData(struct Main* maggie, struct Scene* scene, GlobalSettings* gs, int argc, char** argv); - bool startWindow(STR_String& title, - int windowLeft, int windowTop, - int windowWidth, int windowHeight, - const bool stereoVisual, const int stereoMode, const int alphaBackground=0, const GHOST_TUns16 samples=0); - bool startFullScreen(int width, int height, - int bpp, int frequency, - const bool stereoVisual, const int stereoMode, const int alphaBackground = 0, - const GHOST_TUns16 samples=0, bool useDesktop=false); - bool startEmbeddedWindow(STR_String& title, const GHOST_TEmbedderWindowID parent_window, - const bool stereoVisual, const int stereoMode, const int alphaBackground=0, const GHOST_TUns16 samples=0); -#ifdef WIN32 - bool startScreenSaverFullScreen(int width, int height, - int bpp, int frequency, - const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0); - bool startScreenSaverPreview(HWND parentWindow, - const bool stereoVisual, const int stereoMode, const GHOST_TUns16 samples=0); -#endif - - virtual bool processEvent(GHOST_IEvent* event); - int getExitRequested(void); - const STR_String& getExitString(void); - GlobalSettings* getGlobalSettings(void); - - inline KX_Scene *GetStartScene() const - { - return m_kxStartScene; - } - - bool StartGameEngine(int stereoMode); - void StopGameEngine(); - void EngineNextFrame(); - -protected: - bool handleWheel(GHOST_IEvent* event); - bool handleButton(GHOST_IEvent* event, bool isDown); - bool handleCursorMove(GHOST_IEvent* event); - bool handleKey(GHOST_IEvent* event, bool isDown); - - /** - * Initializes the game engine. - */ - bool initEngine(GHOST_IWindow* window, int stereoMode); - - /** - * Starts the game engine. - */ - bool startEngine(void); - - /** - * Stop the game engine. - */ - void stopEngine(void); - - /** - * Shuts the game engine down. - */ - void exitEngine(void); - short m_exitkey; - - /* The game data */ - STR_String m_startSceneName; - struct Scene* m_startScene; - struct Main* m_maggie; - KX_Scene *m_kxStartScene; - - /* Exit state. */ - int m_exitRequested; - STR_String m_exitString; - GlobalSettings* m_globalSettings; - - /* GHOST system abstraction. */ - GHOST_ISystem* m_system; - /* Main window. */ - GHOST_IWindow* m_mainWindow; - /* Timer to advance frames. */ - GHOST_ITimerTask* m_frameTimer; - /* The cursor shape displayed. */ - GHOST_TStandardCursor m_cursor; - - /** Engine construction state. */ - bool m_engineInitialized; - /** Engine state. */ - bool m_engineRunning; - /** Running on embedded window */ - bool m_isEmbedded; - - /** the gameengine itself */ - KX_KetsjiEngine* m_ketsjiengine; - /** The game engine's system abstraction. */ - GPG_System* m_kxsystem; - /** The game engine's keyboard abstraction. */ - GPG_KeyboardDevice* m_keyboard; - /** The game engine's mouse abstraction. */ - GPC_MouseDevice* m_mouse; - /** The game engine's canvas abstraction. */ - GPG_Canvas* m_canvas; - /** the rasterizer */ - RAS_IRasterizer* m_rasterizer; - /** Converts Blender data files. */ - KX_ISceneConverter* m_sceneconverter; - /** Network interface. */ - NG_LoopBackNetworkDeviceInterface* m_networkdevice; - - bool m_blendermat; - bool m_blenderglslmat; - - /* - * GameLogic.globalDict as a string so that loading new blend files can use the same dict. - * Do this because python starts/stops when loading blend files. - */ - char* m_pyGlobalDictString; - int m_pyGlobalDictString_Length; - - /* argc and argv need to be passed on to python */ - int m_argc; - char** m_argv; -}; diff --git a/source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp b/source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp deleted file mode 100644 index 09eb1691dae7..000000000000 --- a/source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/GamePlayer/ghost/GPG_Canvas.cpp - * \ingroup player - */ - - -#include "GPG_Canvas.h" -#include -#include "GHOST_ISystem.h" - -GPG_Canvas::GPG_Canvas(GHOST_IWindow* window) -: GPC_Canvas(0, 0), m_window(window) -{ - if (m_window) - { - GHOST_Rect bnds; - m_window->getClientBounds(bnds); - this->Resize(bnds.getWidth(), bnds.getHeight()); - } -} - - -GPG_Canvas::~GPG_Canvas(void) -{ -} - - -void GPG_Canvas::Init() -{ - if (m_window) - { - m_window->setDrawingContextType(GHOST_kDrawingContextTypeOpenGL); - assert(m_window->getDrawingContextType() == GHOST_kDrawingContextTypeOpenGL); - } -} - -void GPG_Canvas::SetMousePosition(int x, int y) -{ - GHOST_ISystem* system = GHOST_ISystem::getSystem(); - if (system && m_window) - { - GHOST_TInt32 gx = (GHOST_TInt32)x; - GHOST_TInt32 gy = (GHOST_TInt32)y; - GHOST_TInt32 cx; - GHOST_TInt32 cy; - m_window->clientToScreen(gx, gy, cx, cy); - system->setCursorPosition(cx, cy); - } -} - - -void GPG_Canvas::SetMouseState(RAS_MouseState mousestate) -{ - m_mousestate = mousestate; - - if (m_window) - { - switch (mousestate) - { - case MOUSE_INVISIBLE: - m_window->setCursorVisibility(false); - break; - case MOUSE_WAIT: - m_window->setCursorShape(GHOST_kStandardCursorWait); - m_window->setCursorVisibility(true); - break; - case MOUSE_NORMAL: - m_window->setCursorShape(GHOST_kStandardCursorDefault); - m_window->setCursorVisibility(true); - break; - } - } -} - - -void GPG_Canvas::SwapBuffers() -{ - if (m_window) - { - m_window->swapBuffers(); - } -} - -void GPG_Canvas::SetSwapInterval(int interval) -{ - if (m_window) - m_window->setSwapInterval(interval); -} - -bool GPG_Canvas::GetSwapInterval(int& intervalOut) -{ - if (m_window) - return (bool)m_window->getSwapInterval(intervalOut); - - return false; -} - -void GPG_Canvas::GetDisplayDimensions(int &width, int &height) - { - unsigned int uiwidth; - unsigned int uiheight; - - GHOST_ISystem *system = GHOST_ISystem::getSystem(); - system->getMainDisplayDimensions(uiwidth, uiheight); - - width = uiwidth; - height = uiheight; -} - -void GPG_Canvas::ResizeWindow(int width, int height) -{ - if (m_window->getState() == GHOST_kWindowStateFullScreen) - { - GHOST_ISystem* system = GHOST_ISystem::getSystem(); - GHOST_DisplaySetting setting; - setting.xPixels = width; - setting.yPixels = height; - //XXX allow these to be changed or kept from previous state - setting.bpp = 32; - setting.frequency = 60; - - system->updateFullScreen(setting, &m_window); - } - - m_window->setClientSize(width, height); - - Resize(width, height); -} - -void GPG_Canvas::SetFullScreen(bool enable) -{ - if (enable) - m_window->setState(GHOST_kWindowStateFullScreen); - else - m_window->setState(GHOST_kWindowStateNormal); -} - -bool GPG_Canvas::GetFullScreen() -{ - return m_window->getState() == GHOST_kWindowStateFullScreen; -} - -float GPG_Canvas::GetMouseNormalizedX(int x) -{ - return float(x)/this->GetWidth(); -} - -float GPG_Canvas::GetMouseNormalizedY(int y) -{ - return float(y)/this->GetHeight(); -} diff --git a/source/gameengine/GamePlayer/ghost/GPG_KeyboardDevice.cpp b/source/gameengine/GamePlayer/ghost/GPG_KeyboardDevice.cpp deleted file mode 100644 index eefaa3730cf6..000000000000 --- a/source/gameengine/GamePlayer/ghost/GPG_KeyboardDevice.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - * GHOST Blender Player keyboard device implementation. - */ - -/** \file gameengine/GamePlayer/ghost/GPG_KeyboardDevice.cpp - * \ingroup player - */ - - -#include "GPG_KeyboardDevice.h" - -GPG_KeyboardDevice::GPG_KeyboardDevice(void) -{ - m_reverseKeyTranslateTable[GHOST_kKeyA ] = KX_AKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyB ] = KX_BKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyC ] = KX_CKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyD ] = KX_DKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyE ] = KX_EKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyF ] = KX_FKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyG ] = KX_GKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyH ] = KX_HKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyI ] = KX_IKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyJ ] = KX_JKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyK ] = KX_KKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyL ] = KX_LKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyM ] = KX_MKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyN ] = KX_NKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyO ] = KX_OKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyP ] = KX_PKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyQ ] = KX_QKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyR ] = KX_RKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyS ] = KX_SKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyT ] = KX_TKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyU ] = KX_UKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyV ] = KX_VKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyW ] = KX_WKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyX ] = KX_XKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyY ] = KX_YKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyZ ] = KX_ZKEY ; - - m_reverseKeyTranslateTable[GHOST_kKey0 ] = KX_ZEROKEY ; - m_reverseKeyTranslateTable[GHOST_kKey1 ] = KX_ONEKEY ; - m_reverseKeyTranslateTable[GHOST_kKey2 ] = KX_TWOKEY ; - m_reverseKeyTranslateTable[GHOST_kKey3 ] = KX_THREEKEY ; - m_reverseKeyTranslateTable[GHOST_kKey4 ] = KX_FOURKEY ; - m_reverseKeyTranslateTable[GHOST_kKey5 ] = KX_FIVEKEY ; - m_reverseKeyTranslateTable[GHOST_kKey6 ] = KX_SIXKEY ; - m_reverseKeyTranslateTable[GHOST_kKey7 ] = KX_SEVENKEY ; - m_reverseKeyTranslateTable[GHOST_kKey8 ] = KX_EIGHTKEY ; - m_reverseKeyTranslateTable[GHOST_kKey9 ] = KX_NINEKEY ; - - // Middle keyboard area keys - m_reverseKeyTranslateTable[GHOST_kKeyPause ] = KX_PAUSEKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyInsert ] = KX_INSERTKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyDelete ] = KX_DELKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyHome ] = KX_HOMEKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyEnd ] = KX_ENDKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyUpPage ] = KX_PAGEUPKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyDownPage ] = KX_PAGEDOWNKEY ; - - // Arrow keys - m_reverseKeyTranslateTable[GHOST_kKeyUpArrow ] = KX_UPARROWKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyDownArrow ] = KX_DOWNARROWKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyLeftArrow ] = KX_LEFTARROWKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyRightArrow ] = KX_RIGHTARROWKEY ; - - // Function keys - m_reverseKeyTranslateTable[GHOST_kKeyF1 ] = KX_F1KEY ; - m_reverseKeyTranslateTable[GHOST_kKeyF2 ] = KX_F2KEY ; - m_reverseKeyTranslateTable[GHOST_kKeyF3 ] = KX_F3KEY ; - m_reverseKeyTranslateTable[GHOST_kKeyF4 ] = KX_F4KEY ; - m_reverseKeyTranslateTable[GHOST_kKeyF5 ] = KX_F5KEY ; - m_reverseKeyTranslateTable[GHOST_kKeyF6 ] = KX_F6KEY ; - m_reverseKeyTranslateTable[GHOST_kKeyF7 ] = KX_F7KEY ; - m_reverseKeyTranslateTable[GHOST_kKeyF8 ] = KX_F8KEY ; - m_reverseKeyTranslateTable[GHOST_kKeyF9 ] = KX_F9KEY ; - m_reverseKeyTranslateTable[GHOST_kKeyF10 ] = KX_F10KEY ; - m_reverseKeyTranslateTable[GHOST_kKeyF11 ] = KX_F11KEY ; - m_reverseKeyTranslateTable[GHOST_kKeyF12 ] = KX_F12KEY ; - m_reverseKeyTranslateTable[GHOST_kKeyF13 ] = KX_F13KEY ; - m_reverseKeyTranslateTable[GHOST_kKeyF14 ] = KX_F14KEY ; - m_reverseKeyTranslateTable[GHOST_kKeyF15 ] = KX_F15KEY ; - m_reverseKeyTranslateTable[GHOST_kKeyF16 ] = KX_F16KEY ; - m_reverseKeyTranslateTable[GHOST_kKeyF17 ] = KX_F17KEY ; - m_reverseKeyTranslateTable[GHOST_kKeyF18 ] = KX_F18KEY ; - m_reverseKeyTranslateTable[GHOST_kKeyF19 ] = KX_F19KEY ; - - - // Numpad keys - m_reverseKeyTranslateTable[GHOST_kKeyNumpad0 ] = KX_PAD0 ; - m_reverseKeyTranslateTable[GHOST_kKeyNumpad1 ] = KX_PAD1 ; - m_reverseKeyTranslateTable[GHOST_kKeyNumpad2 ] = KX_PAD2 ; - m_reverseKeyTranslateTable[GHOST_kKeyNumpad3 ] = KX_PAD3 ; - m_reverseKeyTranslateTable[GHOST_kKeyNumpad4 ] = KX_PAD4 ; - m_reverseKeyTranslateTable[GHOST_kKeyNumpad5 ] = KX_PAD5 ; - m_reverseKeyTranslateTable[GHOST_kKeyNumpad6 ] = KX_PAD6 ; - m_reverseKeyTranslateTable[GHOST_kKeyNumpad7 ] = KX_PAD7 ; - m_reverseKeyTranslateTable[GHOST_kKeyNumpad8 ] = KX_PAD8 ; - m_reverseKeyTranslateTable[GHOST_kKeyNumpad9 ] = KX_PAD9 ; - m_reverseKeyTranslateTable[GHOST_kKeyNumpadAsterisk ] = KX_PADASTERKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyNumpadPlus ] = KX_PADPLUSKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyNumpadPeriod ] = KX_PADPERIOD ; - m_reverseKeyTranslateTable[GHOST_kKeyNumpadMinus ] = KX_PADMINUS ; - m_reverseKeyTranslateTable[GHOST_kKeyNumpadSlash ] = KX_PADSLASHKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyNumpadEnter ] = KX_PADENTER ; - - // Other keys - m_reverseKeyTranslateTable[GHOST_kKeyCapsLock ] = KX_CAPSLOCKKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyEsc ] = KX_ESCKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyTab ] = KX_TABKEY ; - m_reverseKeyTranslateTable[GHOST_kKeySpace ] = KX_SPACEKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyEnter ] = KX_RETKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyBackSpace ] = KX_BACKSPACEKEY ; - m_reverseKeyTranslateTable[GHOST_kKeySemicolon ] = KX_SEMICOLONKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyPeriod ] = KX_PERIODKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyComma ] = KX_COMMAKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyQuote ] = KX_QUOTEKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyAccentGrave ] = KX_ACCENTGRAVEKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyMinus ] = KX_MINUSKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyPlus ] = KX_PLUSKEY ; - m_reverseKeyTranslateTable[GHOST_kKeySlash ] = KX_SLASHKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyBackslash ] = KX_BACKSLASHKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyEqual ] = KX_EQUALKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyLeftBracket ] = KX_LEFTBRACKETKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyRightBracket ] = KX_RIGHTBRACKETKEY ; - - m_reverseKeyTranslateTable[GHOST_kKeyOS ] = KX_OSKEY ; - - // Modifier keys. - m_reverseKeyTranslateTable[GHOST_kKeyLeftControl ] = KX_LEFTCTRLKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyRightControl ] = KX_RIGHTCTRLKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyLeftAlt ] = KX_LEFTALTKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyRightAlt ] = KX_RIGHTALTKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyLeftShift ] = KX_LEFTSHIFTKEY ; - m_reverseKeyTranslateTable[GHOST_kKeyRightShift ] = KX_RIGHTSHIFTKEY ; -} - - -GPG_KeyboardDevice::~GPG_KeyboardDevice(void) -{ -} diff --git a/source/gameengine/GamePlayer/ghost/GPG_KeyboardDevice.h b/source/gameengine/GamePlayer/ghost/GPG_KeyboardDevice.h deleted file mode 100644 index ff8d56db40a3..000000000000 --- a/source/gameengine/GamePlayer/ghost/GPG_KeyboardDevice.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file GPG_KeyboardDevice.h - * \ingroup player - * \brief GHOST Blender Player keyboard device. - */ - -#ifndef __GPG_KEYBOARDDEVICE_H__ -#define __GPG_KEYBOARDDEVICE_H__ - -#ifdef WIN32 -#pragma warning (disable:4786) -#endif /* WIN32 */ - -#include "GHOST_Types.h" -#include "GPC_KeyboardDevice.h" - -/** - * GHOST implementation of GPC_KeyboardDevice. - * The contructor fills the keyboard code translation map. - * Base class GPC_KeyboardDevice does the rest. - * \see SCA_IInputDevice - */ -class GPG_KeyboardDevice : public GPC_KeyboardDevice -{ -public: - GPG_KeyboardDevice(void); - virtual ~GPG_KeyboardDevice(void); -}; - -#endif /* __GPG_KEYBOARDDEVICE_H__ */ diff --git a/source/gameengine/GamePlayer/ghost/GPG_System.h b/source/gameengine/GamePlayer/ghost/GPG_System.h deleted file mode 100644 index 1ec7a06d1cfd..000000000000 --- a/source/gameengine/GamePlayer/ghost/GPG_System.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file GPG_System.h - * \ingroup player - * \brief Blender Player system on GHOST. - */ - -#ifndef __GPG_SYSTEM_H__ -#define __GPG_SYSTEM_H__ - -#ifdef WIN32 -#pragma warning (disable:4786) // suppress stl-MSVC debug info warning -#endif /* WIN32 */ - -#include "KX_ISystem.h" - -class GHOST_ISystem; - -class GPG_System : public KX_ISystem -{ - GHOST_ISystem* m_system; - -public: - GPG_System(GHOST_ISystem* system); - - virtual double GetTimeInSeconds(); -}; - -#endif /* __GPG_SYSTEM_H__ */ diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp deleted file mode 100644 index 42b603f8980e..000000000000 --- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp +++ /dev/null @@ -1,1227 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - * Start up of the Blender Player on GHOST. - */ - -/** \file gameengine/GamePlayer/ghost/GPG_ghost.cpp - * \ingroup player - */ - - -#include -#include - -#ifdef __linux__ -#ifdef __alpha__ -#include -#endif /* __alpha__ */ -#endif /* __linux__ */ - -#include "KX_KetsjiEngine.h" -#include "KX_PythonInit.h" -#include "KX_PythonMain.h" -#include "KX_PyConstraintBinding.h" // for PHY_SetActiveEnvironment - -/********************************** - * Begin Blender include block - **********************************/ -#ifdef __cplusplus -extern "C" -{ -#endif // __cplusplus -#include "MEM_guardedalloc.h" -#include "MEM_CacheLimiterC-Api.h" - -#include "BLI_threads.h" -#include "BLI_mempool.h" -#include "BLI_blenlib.h" - -#include "DNA_scene_types.h" -#include "DNA_userdef_types.h" -#include "DNA_genfile.h" - -#include "BLO_readfile.h" -#include "BLO_runtime.h" - -#include "BKE_appdir.h" -#include "BKE_blender.h" -#include "BKE_depsgraph.h" -#include "BKE_global.h" -#include "BKE_icons.h" -#include "BKE_image.h" -#include "BKE_node.h" -#include "BKE_report.h" -#include "BKE_library.h" -#include "BKE_library_remap.h" -#include "BKE_modifier.h" -#include "BKE_material.h" -#include "BKE_text.h" -#include "BKE_sound.h" - -#include "IMB_imbuf.h" -#include "IMB_moviecache.h" - -#ifdef __APPLE__ - int GHOST_HACK_getFirstFile(char buf[]); -#endif - -// For BLF -#include "BLF_api.h" -#include "BLT_translation.h" -#include "BLT_lang.h" -extern int datatoc_bfont_ttf_size; -extern char datatoc_bfont_ttf[]; -extern int datatoc_bmonofont_ttf_size; -extern char datatoc_bmonofont_ttf[]; - -#ifdef __cplusplus -} -#endif // __cplusplus - -#include "GPU_draw.h" - -/********************************** - * End Blender include block - **********************************/ - -#include "BL_System.h" -#include "GPG_Application.h" - -#include "GHOST_ISystem.h" -#include "RAS_IRasterizer.h" - -#include "BKE_main.h" - -#include "RNA_define.h" - -#ifdef WIN32 -# include -# if !defined(DEBUG) -# include -# endif // !defined(DEBUG) -# if defined(_MSC_VER) && defined(_M_X64) -# include /* needed for _set_FMA3_enable */ -# endif -# include "utfconv.h" -#endif // WIN32 - -#ifdef WITH_SDL_DYNLOAD -# include "sdlew.h" -#endif - -const int kMinWindowWidth = 100; -const int kMinWindowHeight = 100; - -static void mem_error_cb(const char *errorStr) -{ - fprintf(stderr, "%s", errorStr); - fflush(stderr); -} - -// library.c will only free window managers with a callback function. -// We don't actually use a wmWindowManager, but loading a blendfile -// loads wmWindows, so we need to free those. -static void wm_free(bContext *C, wmWindowManager *wm) -{ - BLI_freelistN(&wm->windows); -} - -#ifdef WIN32 -typedef enum { - SCREEN_SAVER_MODE_NONE = 0, - SCREEN_SAVER_MODE_PREVIEW, - SCREEN_SAVER_MODE_SAVER, - SCREEN_SAVER_MODE_CONFIGURATION, - SCREEN_SAVER_MODE_PASSWORD, -} ScreenSaverMode; - -static ScreenSaverMode scr_saver_mode = SCREEN_SAVER_MODE_NONE; -static HWND scr_saver_hwnd = NULL; - -static BOOL scr_saver_init(int argc, char **argv) -{ - scr_saver_mode = SCREEN_SAVER_MODE_NONE; - scr_saver_hwnd = NULL; - BOOL ret = false; - - int len = ::strlen(argv[0]); - if (len > 4 && !::stricmp(".scr", argv[0] + len - 4)) - { - scr_saver_mode = SCREEN_SAVER_MODE_CONFIGURATION; - ret = true; - if (argc >= 2) - { - if (argc >= 3) - { - scr_saver_hwnd = (HWND) ::atoi(argv[2]); - } - if (!::stricmp("/c", argv[1])) - { - scr_saver_mode = SCREEN_SAVER_MODE_CONFIGURATION; - if (scr_saver_hwnd == NULL) - scr_saver_hwnd = ::GetForegroundWindow(); - } - else if (!::stricmp("/s", argv[1])) - { - scr_saver_mode = SCREEN_SAVER_MODE_SAVER; - } - else if (!::stricmp("/a", argv[1])) - { - scr_saver_mode = SCREEN_SAVER_MODE_PASSWORD; - } - else if (!::stricmp("/p", argv[1]) - || !::stricmp("/l", argv[1])) - { - scr_saver_mode = SCREEN_SAVER_MODE_PREVIEW; - } - } - } - return ret; -} - -#endif /* WIN32 */ - -static void usage(const char* program, bool isBlenderPlayer) -{ - const char * consoleoption; - const char * example_filename = ""; - const char * example_pathname = ""; - -#ifdef _WIN32 - consoleoption = "[-c] "; -#else - consoleoption = ""; -#endif - - if (isBlenderPlayer) { - example_filename = "filename.blend"; -#ifdef _WIN32 - example_pathname = "c:\\"; -#else - example_pathname = "/home/user/"; -#endif - } - printf("\n"); - printf("usage: %s [--options] %s\n\n", program, example_filename); - printf("Available options are: [-w [w h l t]] [-f [fw fh fb ff]] %s[-g gamengineoptions] ", consoleoption); - printf("[-s stereomode] [-m aasamples]\n"); - printf("Optional parameters must be passed in order.\n"); - printf("Default values are set in the blend file.\n\n"); - printf(" -h: Prints this command summary\n\n"); - printf(" -w: display in a window\n"); - printf(" --Optional parameters--\n"); - printf(" w = window width\n"); - printf(" h = window height\n"); - printf(" l = window left coordinate\n"); - printf(" t = window top coordinate\n"); - printf(" Note: To define 'w' or 'h', both must be used."); - printf("Also, to define 'l' or 't', all four parameters must be used.\n"); - printf(" Example: -w or -w 500 300 or -w 500 300 0 0\n\n"); - printf(" -f: start game in fullscreen mode\n"); - printf(" --Optional parameters--\n"); - printf(" fw = fullscreen mode pixel width (use 0 to detect automatically)\n"); - printf(" fh = fullscreen mode pixel height (use 0 to detect automatically)\n"); - printf(" fb = fullscreen mode bits per pixel (default unless set in the blend file: 32)\n"); - printf(" ff = fullscreen mode frequency (default unless set in the blend file: 60)\n"); - printf(" Note: To define 'fw'' or 'fh'', both must be used.\n"); - printf(" Example: -f or -f 1024 768 or -f 0 0 16 or -f 1024 728 16 30\n\n"); - printf(" -s: start player in stereoscopy mode (requires 3D capable hardware)\n"); - printf(" stereomode: nostereo (default unless stereo is set in the blend file)\n"); - printf(" anaglyph (Red-Blue glasses)\n"); - printf(" sidebyside (Left Right)\n"); - printf(" syncdoubling (Above Below)\n"); - printf(" 3dtvtopbottom (Squashed Top-Bottom for passive glasses)\n"); - printf(" interlace (Interlace horizontally)\n"); - printf(" vinterlace (Vertical interlace for autostereo display)\n"); - printf(" hwpageflip (Quad buffered shutter glasses)\n"); - printf(" Example: -s sidebyside or -s vinterlace\n\n"); - printf(" -D: start player in dome mode\n"); - printf(" --Optional parameters--\n"); - printf(" angle = field of view in degrees\n"); - printf(" tilt = tilt angle in degrees\n"); - printf(" warpdata = a file to use for warping the image (absolute path)\n"); - printf(" mode: fisheye (Fisheye)\n"); - printf(" truncatedfront (Front-Truncated)\n"); - printf(" truncatedrear (Rear-Truncated)\n"); - printf(" cubemap (Cube Map)\n"); - printf(" sphericalpanoramic (Spherical Panoramic)\n"); - printf(" Example: -D or -D mode cubemap\n\n"); - printf(" -m: maximum anti-aliasing (eg. 2,4,8,16)\n\n"); - printf(" -i: parent window's ID\n\n"); -#ifdef _WIN32 - printf(" -c: keep console window open\n\n"); -#endif - printf(" -d: turn debugging on\n\n"); - printf(" -g: game engine options:\n\n"); - printf(" Name Default Description\n"); - printf(" ------------------------------------------------------------------------\n"); - printf(" fixedtime 0 \"Enable all frames\"\n"); - printf(" nomipmap 0 Disable mipmaps\n"); - printf(" show_framerate 0 Show the frame rate\n"); - printf(" show_properties 0 Show debug properties\n"); - printf(" show_profile 0 Show profiling information\n"); - printf(" blender_material 0 Enable material settings\n"); - printf(" ignore_deprecation_warnings 1 Ignore deprecation warnings\n"); - printf("\n"); - printf(" - : all arguments after this are ignored, allowing python to access them from sys.argv\n"); - printf("\n"); - printf("example: %s -w 320 200 10 10 -g noaudio %s%s\n", program, example_pathname, example_filename); - printf("example: %s -g show_framerate = 0 %s%s\n", program, example_pathname, example_filename); - printf("example: %s -i 232421 -m 16 %s%s\n\n", program, example_pathname, example_filename); -} - -static void get_filename(int argc, char **argv, char *filename) -{ -#ifdef __APPLE__ - /* On Mac we park the game file (called game.blend) in the application bundle. - * The executable is located in the bundle as well. - * Therefore, we can locate the game relative to the executable. - */ - int srclen = ::strlen(argv[0]); - int len = 0; - char *gamefile = NULL; - - filename[0] = '\0'; - - if (argc > 1) { - if (BLI_exists(argv[argc-1])) { - BLI_strncpy(filename, argv[argc-1], FILE_MAX); - } - if (::strncmp(argv[argc-1], "-psn_", 5)==0) { - static char firstfilebuf[512]; - if (GHOST_HACK_getFirstFile(firstfilebuf)) { - BLI_strncpy(filename, firstfilebuf, FILE_MAX); - } - } - } - - srclen -= ::strlen("MacOS/blenderplayer"); - if (srclen > 0) { - len = srclen + ::strlen("Resources/game.blend"); - gamefile = new char [len + 1]; - ::strcpy(gamefile, argv[0]); - ::strcpy(gamefile + srclen, "Resources/game.blend"); - //::printf("looking for file: %s\n", filename); - - if (BLI_exists(gamefile)) - BLI_strncpy(filename, gamefile, FILE_MAX); - - delete [] gamefile; - } - -#else - filename[0] = '\0'; - - if (argc > 1) - BLI_strncpy(filename, argv[argc-1], FILE_MAX); -#endif // !_APPLE -} - -static BlendFileData *load_game_data(const char *progname, char *filename = NULL, char *relativename = NULL) -{ - ReportList reports; - BlendFileData *bfd = NULL; - - BKE_reports_init(&reports, RPT_STORE); - - /* try to load ourself, will only work if we are a runtime */ - if (BLO_is_a_runtime(progname)) { - bfd= BLO_read_runtime(progname, &reports); - if (bfd) { - bfd->type= BLENFILETYPE_RUNTIME; - BLI_strncpy(bfd->main->name, progname, sizeof(bfd->main->name)); - } - } else { - bfd= BLO_read_from_file(progname, &reports, BLO_READ_SKIP_NONE); - } - - if (!bfd && filename) { - bfd = load_game_data(filename); - if (!bfd) { - printf("Loading %s failed: ", filename); - BKE_reports_print(&reports, RPT_ERROR); - } - } - - BKE_reports_clear(&reports); - - return bfd; -} - -static bool GPG_NextFrame(GHOST_ISystem* system, GPG_Application *app, int &exitcode, STR_String &exitstring, GlobalSettings *gs) -{ - bool run = true; - system->processEvents(false); - system->dispatchEvents(); - app->EngineNextFrame(); - if ((exitcode = app->getExitRequested())) { - run = false; - exitstring = app->getExitString(); - *gs = *app->getGlobalSettings(); - } - return run; -} - -struct GPG_NextFrameState { - GHOST_ISystem* system; - GPG_Application *app; - GlobalSettings *gs; -} gpg_nextframestate; - -static int GPG_PyNextFrame(void *state0) -{ - GPG_NextFrameState *state = (GPG_NextFrameState *) state0; - int exitcode; - STR_String exitstring; - bool run = GPG_NextFrame(state->system, state->app, exitcode, exitstring, state->gs); - if (run) return 0; - else { - if (exitcode) - fprintf(stderr, "Exit code %d: %s\n", exitcode, exitstring.ReadPtr()); - return 1; - } -} - -int main( - int argc, -#ifdef WIN32 - char **UNUSED(argv_c) -#else - char **argv -#endif - ) -{ - int i; - int argc_py_clamped= argc; /* use this so python args can be added after ' - ' */ - bool error = false; - SYS_SystemHandle syshandle = SYS_GetSystem(); - bool fullScreen = false; - bool fullScreenParFound = false; - bool windowParFound = false; -#ifdef WIN32 - bool closeConsole = true; -#endif - RAS_IRasterizer::StereoMode stereomode = RAS_IRasterizer::RAS_STEREO_NOSTEREO; - bool stereoWindow = false; - bool stereoParFound = false; - int stereoFlag = STEREO_NOSTEREO; - int domeFov = -1; - int domeTilt = -200; - int domeMode = 0; - char* domeWarp = NULL; - Text *domeText = NULL; - int windowLeft = 100; - int windowTop = 100; - int windowWidth = 640; - int windowHeight = 480; - GHOST_TUns32 fullScreenWidth = 0; - GHOST_TUns32 fullScreenHeight= 0; - int fullScreenBpp = 32; - int fullScreenFrequency = 60; - GHOST_TEmbedderWindowID parentWindow = 0; - bool isBlenderPlayer = false; //true when lauching from blender or command line. false for bundled player - int validArguments=0; - bool samplesParFound = false; - GHOST_TUns16 aasamples = 0; - int alphaBackground = 0; - -#ifdef WIN32 - char **argv; - int argv_num; - - /* We delay loading of openmp so we can set the policy here. */ -# if defined(_MSC_VER) - _putenv_s("OMP_WAIT_POLICY", "PASSIVE"); -# endif - - /* FMA3 support in the 2013 CRT is broken on Vista and Windows 7 RTM (fixed in SP1). Just disable it. */ -# if defined(_MSC_VER) && defined(_M_X64) - _set_FMA3_enable(0); -# endif - - /* Win32 Unicode Args */ - /* NOTE: cannot use guardedalloc malloc here, as it's not yet initialized - * (it depends on the args passed in, which is what we're getting here!) - */ - { - wchar_t **argv_16 = CommandLineToArgvW(GetCommandLineW(), &argc); - argv = (char**)malloc(argc * sizeof(char *)); - for (argv_num = 0; argv_num < argc; argv_num++) { - argv[argv_num] = alloc_utf_8_from_16(argv_16[argv_num], 0); - } - LocalFree(argv_16); - } -#endif /* WIN32 */ - -#ifdef __linux__ -#ifdef __alpha__ - signal (SIGFPE, SIG_IGN); -#endif /* __alpha__ */ -#endif /* __linux__ */ - -#ifdef WITH_SDL_DYNLOAD - sdlewInit(); -#endif - - BKE_appdir_program_path_init(argv[0]); - BKE_tempdir_init(NULL); - - // We don't use threads directly in the BGE, but we need to call this so things like - // freeing up GPU_Textures works correctly. - BLI_threadapi_init(); - - DNA_sdna_current_init(); - - RNA_init(); - - init_nodesystem(); - - BKE_blender_globals_init(); - - // We load our own G.main, so free the one that BKE_blender_globals_init() gives us - BKE_main_free(G.main); - G.main = NULL; - - MEM_CacheLimiter_set_disabled(true); - IMB_init(); - BKE_images_init(); - BKE_modifier_init(); - DAG_init(); - -#ifdef WITH_FFMPEG - IMB_ffmpeg_init(); -#endif - - // Setup builtin font for BLF (mostly copied from creator.c, wm_init_exit.c and interface_style.c) - BLF_init(); - BLT_lang_init(); - BLT_lang_set(""); - - BLF_load_mem("default", (unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size); - if (blf_mono_font == -1) - blf_mono_font = BLF_load_mem_unique("monospace", (unsigned char*)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size); - - // Parse command line options -#if defined(DEBUG) - printf("argv[0] = '%s'\n", argv[0]); -#endif - -#ifdef WIN32 - if (scr_saver_init(argc, argv)) - { - switch (scr_saver_mode) - { - case SCREEN_SAVER_MODE_CONFIGURATION: - MessageBox(scr_saver_hwnd, "This screen saver has no options that you can set", "Screen Saver", MB_OK); - break; - case SCREEN_SAVER_MODE_PASSWORD: - /* This is W95 only, which we currently do not support. - * Fall-back to normal screen saver behavior in that case... */ - case SCREEN_SAVER_MODE_SAVER: - fullScreen = true; - fullScreenParFound = true; - break; - - case SCREEN_SAVER_MODE_PREVIEW: - /* This will actually be handled somewhere below... */ - break; - } - } -#endif - // XXX add the ability to change this values to the command line parsing. - U.mixbufsize = 2048; - U.audiodevice = 2; - U.audiorate = 44100; - U.audioformat = 0x24; - U.audiochannels = 2; - - // XXX this one too - U.anisotropic_filter = 2; - // enable fast mipmap generation - U.use_gpu_mipmap = 1; - - BKE_sound_init_once(); - - // Initialize a default material for meshes without materials. - init_def_material(); - - BKE_library_callback_free_window_manager_set(wm_free); - - /* if running blenderplayer the last argument can't be parsed since it has to be the filename. else it is bundled */ - isBlenderPlayer = !BLO_is_a_runtime(argv[0]); - if (isBlenderPlayer) - validArguments = argc - 1; - else - validArguments = argc; - - - /* Parsing command line arguments (can be set from WM_OT_blenderplayer_start) */ -#if defined(DEBUG) - printf("Parsing command line arguments...\n"); - printf("Num of arguments is: %i\n", validArguments-1); //-1 because i starts at 1 -#endif - - for (i = 1; (i < validArguments) && !error -#ifdef WIN32 - && scr_saver_mode == SCREEN_SAVER_MODE_NONE -#endif - ;) - - { -#if defined(DEBUG) - printf("argv[%d] = '%s'\n", i, argv[i]); -#endif - if (argv[i][0] == '-') - { - /* ignore all args after " - ", allow python to have own args */ - if (argv[i][1]=='\0') { - argc_py_clamped= i; - break; - } - - switch (argv[i][1]) - { - case 'g': //game engine options (show_framerate, fixedtime, etc) - { - i++; - if (i <= validArguments) - { - char* paramname = argv[i]; - // Check for single value versus assignment - if (i+1 <= validArguments && (*(argv[i+1]) == '=')) - { - i++; - if (i + 1 <= validArguments) - { - i++; - // Assignment - SYS_WriteCommandLineInt(syshandle, paramname, atoi(argv[i])); - SYS_WriteCommandLineFloat(syshandle, paramname, atof(argv[i])); - SYS_WriteCommandLineString(syshandle, paramname, argv[i]); -#if defined(DEBUG) - printf("%s = '%s'\n", paramname, argv[i]); -#endif - i++; - } - else - { - error = true; - printf("error: argument assignment %s without value.\n", paramname); - } - } - else - { -// SYS_WriteCommandLineInt(syshandle, argv[i++], 1); - } - } - break; - } - case 'd': //debug on - { - i++; - G.debug |= G_DEBUG; - MEM_set_memory_debug(); -#ifndef NDEBUG - BLI_mempool_set_memory_debug(); -#endif - break; - } - case 'f': //fullscreen mode - { - i++; - fullScreen = true; - fullScreenParFound = true; - if ((i + 2) <= validArguments && argv[i][0] != '-' && argv[i+1][0] != '-') - { - fullScreenWidth = atoi(argv[i++]); - fullScreenHeight = atoi(argv[i++]); - if ((i + 1) <= validArguments && argv[i][0] != '-') - { - fullScreenBpp = atoi(argv[i++]); - if ((i + 1) <= validArguments && argv[i][0] != '-') - fullScreenFrequency = atoi(argv[i++]); - } - } - else if ((i + 1) <= validArguments && argv[i][0] != '-' && argv[i+1][0] != '-') - { - error = true; - printf("error: to define fullscreen width or height, both options must be used.\n"); - } - break; - } - case 'w': //display in a window - { - i++; - fullScreen = false; - windowParFound = true; - - // Parse window position and size options - if ((i + 2) <= validArguments && argv[i][0] != '-' && argv[i+1][0] != '-') - { - windowWidth = atoi(argv[i++]); - windowHeight = atoi(argv[i++]); - - if ((i + 2) <= validArguments && argv[i][0] != '-' && argv[i+1][0] != '-') - { - windowLeft = atoi(argv[i++]); - windowTop = atoi(argv[i++]); - } - else if ((i + 1) <= validArguments && argv[i][0] != '-' && argv[i+1][0] != '-') - { - error = true; - printf("error: to define the window left or right coordinates, both options must be used.\n"); - } - } - else if ((i + 1) <= validArguments && argv[i][0] != '-' && argv[i+1][0] != '-') - { - error = true; - printf("error: to define the window's width or height, both options must be used.\n"); - } - break; - } - case 'h': //display help - { - usage(argv[0], isBlenderPlayer); - return 0; - break; - } - case 'i': //parent window ID - { - i++; - if ( (i + 1) <= validArguments ) - parentWindow = (GHOST_TEmbedderWindowID)atoll(argv[i++]); - else { - error = true; - printf("error: too few options for parent window argument.\n"); - } -#if defined(DEBUG) - printf("XWindows ID = %d\n", parentWindow); -#endif // defined(DEBUG) - break; - } - case 'm': //maximum anti-aliasing (eg. 2,4,8,16) - { - i++; - samplesParFound = true; - if ((i+1) <= validArguments ) - aasamples = atoi(argv[i++]); - else - { - error = true; - printf("error: No argument supplied for -m"); - } - break; - } - case 'c': //keep console (windows only) - { - i++; -#ifdef WIN32 - closeConsole = false; -#endif - break; - } - case 's': //stereo mode - { - i++; - if ((i + 1) <= validArguments) - { - stereoParFound = true; - stereoFlag = STEREO_ENABLED; - - if (!strcmp(argv[i], "nostereo")) // may not be redundant if the file has different setting - { - stereomode = RAS_IRasterizer::RAS_STEREO_NOSTEREO; - stereoFlag = STEREO_NOSTEREO; - } - - // only the hardware pageflip method needs a stereo window - else if (!strcmp(argv[i], "hwpageflip")) { - stereomode = RAS_IRasterizer::RAS_STEREO_QUADBUFFERED; - stereoWindow = true; - } - else if (!strcmp(argv[i], "syncdoubling")) - stereomode = RAS_IRasterizer::RAS_STEREO_ABOVEBELOW; - - else if (!strcmp(argv[i], "3dtvtopbottom")) - stereomode = RAS_IRasterizer::RAS_STEREO_3DTVTOPBOTTOM; - - else if (!strcmp(argv[i], "anaglyph")) - stereomode = RAS_IRasterizer::RAS_STEREO_ANAGLYPH; - - else if (!strcmp(argv[i], "sidebyside")) - stereomode = RAS_IRasterizer::RAS_STEREO_SIDEBYSIDE; - - else if (!strcmp(argv[i], "interlace")) - stereomode = RAS_IRasterizer::RAS_STEREO_INTERLACED; - - else if (!strcmp(argv[i], "vinterlace")) - stereomode = RAS_IRasterizer::RAS_STEREO_VINTERLACE; - -#if 0 -// // future stuff -// else if (!strcmp(argv[i], "stencil") -// stereomode = RAS_STEREO_STENCIL; -#endif - else - { - error = true; - printf("error: stereomode '%s' unrecognized.\n", argv[i]); - } - - i++; - } - else - { - error = true; - printf("error: too few options for stereo argument.\n"); - } - break; - } - case 'D': //dome mode - { - stereoFlag = STEREO_DOME; - stereomode = RAS_IRasterizer::RAS_STEREO_DOME; - i++; - if ((i + 1) <= validArguments) - { - if (!strcmp(argv[i], "angle")) { - i++; - domeFov = atoi(argv[i++]); - } - if (!strcmp(argv[i], "tilt")) { - i++; - domeTilt = atoi(argv[i++]); - } - if (!strcmp(argv[i], "warpdata")) { - i++; - domeWarp = argv[i++]; - } - if (!strcmp(argv[i], "mode")) { - i++; - if (!strcmp(argv[i], "fisheye")) - domeMode = DOME_FISHEYE; - - else if (!strcmp(argv[i], "truncatedfront")) - domeMode = DOME_TRUNCATED_FRONT; - - else if (!strcmp(argv[i], "truncatedrear")) - domeMode = DOME_TRUNCATED_REAR; - - else if (!strcmp(argv[i], "cubemap")) - domeMode = DOME_ENVMAP; - - else if (!strcmp(argv[i], "sphericalpanoramic")) - domeMode = DOME_PANORAM_SPH; - - else - printf("error: %s is not a valid dome mode.\n", argv[i]); - } - i++; - } - break; - } - case 'a': // allow window to blend with display background - { - i++; - alphaBackground = 1; - break; - } - default: //not recognized - { - printf("Unknown argument: %s\n", argv[i++]); - break; - } - } - } - else - { - i++; - } - } - - if ((windowWidth < kMinWindowWidth) || (windowHeight < kMinWindowHeight)) - { - error = true; - printf("error: window size too small.\n"); - } - - if (error ) - { - usage(argv[0], isBlenderPlayer); - return 0; - } - -#ifdef WIN32 - if (scr_saver_mode != SCREEN_SAVER_MODE_CONFIGURATION) -#endif - { - // Create the system - if (GHOST_ISystem::createSystem() == GHOST_kSuccess) { - GHOST_ISystem* system = GHOST_ISystem::getSystem(); - assertd(system); - - if (!fullScreenWidth || !fullScreenHeight) - system->getMainDisplayDimensions(fullScreenWidth, fullScreenHeight); - // process first batch of events. If the user - // drops a file on top off the blenderplayer icon, we - // receive an event with the filename - - system->processEvents(0); - - // this bracket is needed for app (see below) to get out - // of scope before GHOST_ISystem::disposeSystem() is called. - { - int exitcode = KX_EXIT_REQUEST_NO_REQUEST; - STR_String exitstring = ""; - GPG_Application app(system); - bool firstTimeRunning = true; - char filename[FILE_MAX]; - char pathname[FILE_MAX]; - char *titlename; - - get_filename(argc_py_clamped, argv, filename); - if (filename[0]) - BLI_path_cwd(filename, sizeof(filename)); - - - // fill the GlobalSettings with the first scene files - // those may change during the game and persist after using Game Actuator - GlobalSettings gs; - - do { - // Read the Blender file - BlendFileData *bfd; - - // if we got an exitcode 3 (KX_EXIT_REQUEST_START_OTHER_GAME) load a different file - if (exitcode == KX_EXIT_REQUEST_START_OTHER_GAME) - { - char basedpath[FILE_MAX]; - - // base the actuator filename relative to the last file - BLI_strncpy(basedpath, exitstring.Ptr(), sizeof(basedpath)); - BLI_path_abs(basedpath, pathname); - - bfd = load_game_data(basedpath); - - if (!bfd) { - // just add "//" in front of it - char temppath[FILE_MAX] = "//"; - BLI_strncpy(temppath + 2, basedpath, FILE_MAX - 2); - - BLI_path_abs(temppath, pathname); - bfd = load_game_data(temppath); - } - } - else { - bfd = load_game_data(BKE_appdir_program_path(), filename[0]? filename: NULL); - } - -#if defined(DEBUG) - printf("Game data loaded from %s\n", filename); -#endif - - if (!bfd) { - usage(argv[0], isBlenderPlayer); - error = true; - exitcode = KX_EXIT_REQUEST_QUIT_GAME; - } - else { - /* Setting options according to the blend file if not overriden in the command line */ -#ifdef WIN32 -#if !defined(DEBUG) - if (closeConsole) { - system->toggleConsole(0); // Close a console window - } -#endif // !defined(DEBUG) -#endif // WIN32 - Main *maggie = bfd->main; - Scene *scene = bfd->curscene; - G.main = maggie; - - if (firstTimeRunning) { - G.fileflags = bfd->fileflags; - - gs.matmode= scene->gm.matmode; - gs.glslflag= scene->gm.flag; - } - - //Seg Fault; icon.c gIcons == 0 - BKE_icons_init(1); - - titlename = maggie->name; - - // Check whether the game should be displayed full-screen - if ((!fullScreenParFound) && (!windowParFound)) { - // Only use file settings when command line did not override - if ((scene->gm.playerflag & GAME_PLAYER_FULLSCREEN)) { - //printf("fullscreen option found in Blender file\n"); - fullScreen = true; - fullScreenWidth= scene->gm.xplay; - fullScreenHeight= scene->gm.yplay; - fullScreenFrequency= scene->gm.freqplay; - fullScreenBpp = scene->gm.depth; - } - else - { - fullScreen = false; - windowWidth = scene->gm.xplay; - windowHeight = scene->gm.yplay; - } - } - - - // Check whether the game should be displayed in stereo (dome included) - if (!stereoParFound) { - // Only use file settings when command line did not override - if (scene->gm.stereoflag == STEREO_ENABLED) { - stereomode = (RAS_IRasterizer::StereoMode) scene->gm.stereomode; - if (stereomode == RAS_IRasterizer::RAS_STEREO_QUADBUFFERED) - stereoWindow = true; - } - } - else { - scene->gm.stereoflag = STEREO_ENABLED; - } - - if (!samplesParFound) - aasamples = scene->gm.aasamples; - - // Dome specific settings - if (stereoFlag == STEREO_DOME) { - stereomode = RAS_IRasterizer::RAS_STEREO_DOME; - scene->gm.stereoflag = STEREO_DOME; - if (domeFov > 89) - scene->gm.dome.angle = domeFov; - if (domeTilt > -180) - scene->gm.dome.tilt = domeTilt; - if (domeMode > 0) - scene->gm.dome.mode = domeMode; - if (domeWarp) { - //XXX to do: convert relative to absolute path - domeText= BKE_text_load(G.main, domeWarp, ""); - if (!domeText) - printf("error: invalid warpdata text file - %s\n", domeWarp); - else - scene->gm.dome.warptext = domeText; - } - } - - // GPG_Application app (system, maggie, startscenename); - app.SetGameEngineData(maggie, scene, &gs, argc, argv); /* this argc cant be argc_py_clamped, since python uses it */ - BLI_strncpy(pathname, maggie->name, sizeof(pathname)); - if (G.main != maggie) { - BLI_strncpy(G.main->name, maggie->name, sizeof(G.main->name)); - } -#ifdef WITH_PYTHON - setGamePythonPath(G.main->name); -#endif - if (firstTimeRunning) { - firstTimeRunning = false; - - if (fullScreen) { -#ifdef WIN32 - if (scr_saver_mode == SCREEN_SAVER_MODE_SAVER) - { - app.startScreenSaverFullScreen(fullScreenWidth, fullScreenHeight, fullScreenBpp, fullScreenFrequency, - stereoWindow, stereomode, aasamples); - } - else -#endif - { - app.startFullScreen(fullScreenWidth, fullScreenHeight, fullScreenBpp, fullScreenFrequency, - stereoWindow, stereomode, alphaBackground, aasamples, (scene->gm.playerflag & GAME_PLAYER_DESKTOP_RESOLUTION)); - } - } - else - { -#ifdef __APPLE__ - // on Mac's we'll show the executable name instead of the 'game.blend' name - char tempname[1024], *appstring; - ::strcpy(tempname, titlename); - - appstring = strstr(tempname, ".app/"); - if (appstring) { - appstring[2] = 0; - titlename = &tempname[0]; - } -#endif - // Strip the path so that we have the name of the game file - STR_String path = titlename; -#ifndef WIN32 - vector parts = path.Explode('/'); -#else // WIN32 - vector parts = path.Explode('\\'); -#endif // WIN32 - STR_String title; - if (parts.size()) { - title = parts[parts.size()-1]; - parts = title.Explode('.'); - if (parts.size() > 1) - { - title = parts[0]; - } - } - else { - title = "blenderplayer"; - } -#ifdef WIN32 - if (scr_saver_mode == SCREEN_SAVER_MODE_PREVIEW) - { - app.startScreenSaverPreview(scr_saver_hwnd, stereoWindow, stereomode, aasamples); - } - else -#endif - { - if (parentWindow != 0) - app.startEmbeddedWindow(title, parentWindow, stereoWindow, stereomode, aasamples); - else - app.startWindow(title, windowLeft, windowTop, windowWidth, windowHeight, - stereoWindow, stereomode, alphaBackground, aasamples); - - if (SYS_GetCommandLineInt(syshandle, "nomipmap", 0)) { - GPU_set_mipmap(G_MAIN, 0); - } - - GPU_set_anisotropic(G_MAIN, U.anisotropic_filter); - GPU_set_gpu_mipmapping(G_MAIN, U.use_gpu_mipmap); - } - } - } - else { - app.StartGameEngine(stereomode); - exitcode = KX_EXIT_REQUEST_NO_REQUEST; - } - - // Add the application as event consumer - system->addEventConsumer(&app); - - // Enter main loop - bool run = true; - char *python_main = NULL; - pynextframestate.state = NULL; - pynextframestate.func = NULL; -#ifdef WITH_PYTHON - python_main = KX_GetPythonMain(scene); -#endif // WITH_PYTHON - if (python_main) { - char *python_code = KX_GetPythonCode(maggie, python_main); - if (python_code) { -#ifdef WITH_PYTHON - // Set python environement variable. - KX_Scene *startscene = app.GetStartScene(); - KX_SetActiveScene(startscene); - PHY_SetActiveEnvironment(startscene->GetPhysicsEnvironment()); - - gpg_nextframestate.system = system; - gpg_nextframestate.app = &app; - gpg_nextframestate.gs = &gs; - pynextframestate.state = &gpg_nextframestate; - pynextframestate.func = &GPG_PyNextFrame; - - printf("Yielding control to Python script '%s'...\n", python_main); - PyRun_SimpleString(python_code); - printf("Exit Python script '%s'\n", python_main); -#endif // WITH_PYTHON - MEM_freeN(python_code); - } - else { - fprintf(stderr, "ERROR: cannot yield control to Python: no Python text data-block named '%s'\n", python_main); - } - } - else { - while (run) { - run = GPG_NextFrame(system, &app, exitcode, exitstring, &gs); - } - } - app.StopGameEngine(); - - /* 'app' is freed automatic when out of scope. - * removal is needed else the system will free an already freed value */ - system->removeEventConsumer(&app); - - BLO_blendfiledata_free(bfd); - /* G.main == bfd->main, it gets referenced in free_nodesystem so we can't have a dangling pointer */ - G.main = NULL; - if (python_main) MEM_freeN(python_main); - } - } while (exitcode == KX_EXIT_REQUEST_RESTART_GAME || exitcode == KX_EXIT_REQUEST_START_OTHER_GAME); - } - - // Seg Fault; icon.c gIcons == 0 - BKE_icons_free(); - - // Dispose the system - GHOST_ISystem::disposeSystem(); - } - else { - error = true; - printf("error: couldn't create a system.\n"); - } - } - - /* refer to WM_exit_ext() and BKE_blender_free(), - * these are not called in the player but we need to match some of there behavior here, - * if the order of function calls or blenders state isn't matching that of blender proper, - * we may get troubles later on */ - - free_nodesystem(); - - // Cleanup - RNA_exit(); - BLF_exit(); - -#ifdef WITH_INTERNATIONAL - BLF_free_unifont(); - BLF_free_unifont_mono(); - BLT_lang_free(); -#endif - - IMB_exit(); - BKE_images_exit(); - DAG_exit(); - IMB_moviecache_destruct(); - - SYS_DeleteSystem(syshandle); - - int totblock= MEM_get_memory_blocks_in_use(); - if (totblock!=0) { - printf("Error Totblock: %d\n",totblock); - MEM_set_error_callback(mem_error_cb); - MEM_printmemlist(); - } - - BKE_tempdir_session_purge(); - -#ifdef WIN32 - while (argv_num) { - free(argv[--argv_num]); - } - free(argv); - argv = NULL; -#endif - - return error ? -1 : 0; -} diff --git a/source/gameengine/Ketsji/BL_Action.cpp b/source/gameengine/Ketsji/BL_Action.cpp index 43ec3016f51e..bf1b3d559513 100644 --- a/source/gameengine/Ketsji/BL_Action.cpp +++ b/source/gameengine/Ketsji/BL_Action.cpp @@ -24,20 +24,24 @@ * \ingroup ketsji */ -#include -#include +#include "CM_Message.h" #include "BL_Action.h" #include "BL_ArmatureObject.h" -#include "BL_DeformableGameObject.h" #include "BL_ShapeDeformer.h" -#include "KX_IpoConvert.h" +#include "BL_IpoConvert.h" +#include "BL_ActionData.h" #include "KX_GameObject.h" +#include "KX_Globals.h" +#include "KX_Mesh.h" + +#include "RAS_MaterialBucket.h" #include "SG_Controller.h" // These three are for getting the action from the logic manager #include "KX_Scene.h" +#include "BL_Converter.h" #include "SCA_LogicManager.h" extern "C" { @@ -56,21 +60,11 @@ extern "C" { #include "BKE_library.h" #include "BKE_global.h" -#include "BLI_threads.h" // for lock - -/* Lock to solve animation thread issues. - * A spin lock is better than a mutex in case of short wait - * because spin lock stop the thread by a loop contrary to mutex - * which switch all memory, process. - */ -static SpinLock BL_ActionLock; - -BL_Action::BL_Action(class KX_GameObject* gameobj) -: - m_action(NULL), - m_tmpaction(NULL), - m_blendpose(NULL), - m_blendinpose(NULL), +BL_Action::BL_Action(KX_GameObject *gameobj) + :m_actionData(nullptr), + m_tmpaction(nullptr), + m_blendpose(nullptr), + m_blendinpose(nullptr), m_obj(gameobj), m_startframe(0.f), m_endframe(0.f), @@ -84,64 +78,74 @@ BL_Action::BL_Action(class KX_GameObject* gameobj) m_blendmode(ACT_BLEND_BLEND), m_ipo_flags(0), m_done(true), + m_appliedToObject(true), + m_requestIpo(false), m_calc_localtime(true), - m_initializedTime(false) + m_prevUpdate(-1.0f) { } BL_Action::~BL_Action() { - if (m_blendpose) + if (m_blendpose) { BKE_pose_free(m_blendpose); - if (m_blendinpose) + } + if (m_blendinpose) { BKE_pose_free(m_blendinpose); + } ClearControllerList(); if (m_tmpaction) { BKE_libblock_free(G.main, m_tmpaction); - m_tmpaction = NULL; + m_tmpaction = nullptr; } } +void BL_Action::AddController(SG_Controller *cont) +{ + if (!cont || cont->Empty()) { + return; + } + + m_controllers.push_back(cont); +} + void BL_Action::ClearControllerList() { // Clear out the controller list - std::vector::iterator it; - for (it = m_sg_contr_list.begin(); it != m_sg_contr_list.end(); it++) - { - m_obj->GetSGNode()->RemoveSGController((*it)); - delete *it; + for (SG_Controller *cont : m_controllers) { + delete cont; } - m_sg_contr_list.clear(); + m_controllers.clear(); } -bool BL_Action::Play(const char* name, - float start, - float end, - short priority, - float blendin, - short play_mode, - float layer_weight, - short ipo_flags, - float playback_speed, - short blend_mode) +bool BL_Action::Play(const std::string& name, + float start, + float end, + short priority, + float blendin, + short play_mode, + float layer_weight, + short ipo_flags, + float playback_speed, + short blend_mode) { // Only start playing a new action if we're done, or if // the new action has a higher priority - if (!IsDone() && priority > m_priority) + if (!IsDone() && priority > m_priority) { return false; + } m_priority = priority; - bAction* prev_action = m_action; + BL_ActionData *prev_action = m_actionData; - KX_Scene* kxscene = m_obj->GetScene(); + KX_Scene *kxscene = m_obj->GetScene(); // First try to load the action - m_action = (bAction*)kxscene->GetLogicManager()->GetActionByName(name); - if (!m_action) - { - printf("Failed to load action: %s\n", name); + m_actionData = static_cast(kxscene->GetLogicManager()->GetActionByName(name)); + if (!m_actionData) { + CM_Error("failed to load action: " << name); m_done = true; return false; } @@ -152,115 +156,70 @@ bool BL_Action::Play(const char* name, // However, this may eventually lead to issues where a user wants to override an already // playing action with the same action and settings. If this becomes an issue, // then this fix may have to be re-evaluated. - if (!IsDone() && m_action == prev_action && m_startframe == start && m_endframe == end - && m_priority == priority && m_speed == playback_speed) + if (!IsDone() && m_actionData == prev_action && m_startframe == start && m_endframe == end + && m_priority == priority && m_speed == playback_speed) { return false; + } // Keep a copy of the action for threading purposes if (m_tmpaction) { BKE_libblock_free(G.main, m_tmpaction); - m_tmpaction = NULL; + m_tmpaction = nullptr; } - m_tmpaction = BKE_action_copy(G.main, m_action); + + m_tmpaction = BKE_action_copy(G.main, m_actionData->GetAction()); // First get rid of any old controllers ClearControllerList(); // Create an SG_Controller - SG_Controller *sg_contr = BL_CreateIPO(m_action, m_obj, kxscene->GetSceneConverter()); - m_sg_contr_list.push_back(sg_contr); - m_obj->GetSGNode()->AddSGController(sg_contr); - sg_contr->SetObject(m_obj->GetSGNode()); - + AddController(BL_CreateIPO(m_actionData, m_obj, kxscene)); // World - sg_contr = BL_CreateWorldIPO(m_action, kxscene->GetBlenderScene()->world, kxscene->GetSceneConverter()); - if (sg_contr) { - m_sg_contr_list.push_back(sg_contr); - m_obj->GetSGNode()->AddSGController(sg_contr); - sg_contr->SetObject(m_obj->GetSGNode()); - } - + AddController(BL_CreateWorldIPO(m_actionData, kxscene->GetBlenderScene()->world, kxscene)); // Try obcolor - sg_contr = BL_CreateObColorIPO(m_action, m_obj, kxscene->GetSceneConverter()); - if (sg_contr) { - m_sg_contr_list.push_back(sg_contr); - m_obj->GetSGNode()->AddSGController(sg_contr); - sg_contr->SetObject(m_obj->GetSGNode()); - } + AddController(BL_CreateObColorIPO(m_actionData, m_obj, kxscene)); // Now try materials - if (m_obj->GetBlenderObject()->totcol==1) { - Material *mat = give_current_material(m_obj->GetBlenderObject(), 1); - if (mat) { - sg_contr = BL_CreateMaterialIpo(m_action, mat, 0, m_obj, kxscene->GetSceneConverter()); - if (sg_contr) { - m_sg_contr_list.push_back(sg_contr); - m_obj->GetSGNode()->AddSGController(sg_contr); - sg_contr->SetObject(m_obj->GetSGNode()); - } - } - } else { - Material *mat; - STR_HashedString matname; - - for (int matidx = 1; matidx <= m_obj->GetBlenderObject()->totcol; ++matidx) { - mat = give_current_material(m_obj->GetBlenderObject(), matidx); - if (mat) { - matname = mat->id.name; - sg_contr = BL_CreateMaterialIpo(m_action, mat, matname.hash(), m_obj, kxscene->GetSceneConverter()); - if (sg_contr) { - m_sg_contr_list.push_back(sg_contr); - m_obj->GetSGNode()->AddSGController(sg_contr); - sg_contr->SetObject(m_obj->GetSGNode()); - } - } + for (KX_Mesh *mesh : m_obj->GetMeshList()) { + for (RAS_MeshMaterial *meshmat : mesh->GetMeshMaterialList()) { + RAS_IMaterial *mat = meshmat->GetBucket()->GetMaterial(); + AddController(BL_CreateMaterialIpo(m_actionData, mat, m_obj, kxscene)); } } // Extra controllers - if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_LIGHT) - { - sg_contr = BL_CreateLampIPO(m_action, m_obj, kxscene->GetSceneConverter()); - m_sg_contr_list.push_back(sg_contr); - m_obj->GetSGNode()->AddSGController(sg_contr); - sg_contr->SetObject(m_obj->GetSGNode()); + if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_LIGHT) { + AddController(BL_CreateLampIPO(m_actionData, m_obj, kxscene)); } - else if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_CAMERA) - { - sg_contr = BL_CreateCameraIPO(m_action, m_obj, kxscene->GetSceneConverter()); - m_sg_contr_list.push_back(sg_contr); - m_obj->GetSGNode()->AddSGController(sg_contr); - sg_contr->SetObject(m_obj->GetSGNode()); + else if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_CAMERA) { + AddController(BL_CreateCameraIPO(m_actionData, m_obj, kxscene)); } m_ipo_flags = ipo_flags; InitIPO(); // Setup blendin shapes/poses - if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) - { - BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj; + if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) { + BL_ArmatureObject *obj = (BL_ArmatureObject *)m_obj; obj->GetPose(&m_blendinpose); } - else - { - BL_DeformableGameObject *obj = (BL_DeformableGameObject*)m_obj; - BL_ShapeDeformer *shape_deformer = dynamic_cast(obj->GetDeformer()); + else { + BL_ShapeDeformer *shape_deformer = dynamic_cast(m_obj->GetDeformer()); - if (shape_deformer && shape_deformer->GetKey()) - { - obj->GetShape(m_blendinshape); + if (shape_deformer && shape_deformer->GetKey()) { + shape_deformer->GetShape(m_blendinshape); // Now that we have the previous blend shape saved, we can clear out the key to avoid any // further interference. KeyBlock *kb; - for (kb=(KeyBlock *)shape_deformer->GetKey()->block.first; kb; kb=(KeyBlock *)kb->next) + for (kb = (KeyBlock *)shape_deformer->GetKey()->block.first; kb; kb = (KeyBlock *)kb->next) { kb->curval = 0.f; + } } } // Now that we have an action, we have something we can play - m_starttime = -1.f; // We get the start time on our first update + m_starttime = KX_GetActiveEngine()->GetFrameTime() - kxscene->GetSuspendedDelta(); m_startframe = m_localframe = start; m_endframe = end; m_blendin = blendin; @@ -272,7 +231,10 @@ bool BL_Action::Play(const char* name, m_layer_weight = layer_weight; m_done = false; - m_initializedTime = false; + m_appliedToObject = false; + m_requestIpo = false; + + m_prevUpdate = -1.0f; return true; } @@ -285,19 +247,17 @@ bool BL_Action::IsDone() void BL_Action::InitIPO() { // Initialize the IPOs - std::vector::iterator it; - for (it = m_sg_contr_list.begin(); it != m_sg_contr_list.end(); it++) - { - (*it)->SetOption(SG_Controller::SG_CONTR_IPO_RESET, true); - (*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_AS_FORCE, m_ipo_flags & ACT_IPOFLAG_FORCE); - (*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_ADD, m_ipo_flags & ACT_IPOFLAG_ADD); - (*it)->SetOption(SG_Controller::SG_CONTR_IPO_LOCAL, m_ipo_flags & ACT_IPOFLAG_LOCAL); + for (SG_Controller *cont : m_controllers) { + cont->SetOption(SG_Controller::SG_CONTR_IPO_RESET, true); + cont->SetOption(SG_Controller::SG_CONTR_IPO_IPO_AS_FORCE, m_ipo_flags & ACT_IPOFLAG_FORCE); + cont->SetOption(SG_Controller::SG_CONTR_IPO_IPO_ADD, m_ipo_flags & ACT_IPOFLAG_ADD); + cont->SetOption(SG_Controller::SG_CONTR_IPO_LOCAL, m_ipo_flags & ACT_IPOFLAG_LOCAL); } } -bAction *BL_Action::GetAction() +BL_ActionData *BL_Action::GetActionData() { - return (IsDone()) ? NULL : m_action; + return (IsDone()) ? nullptr : m_actionData; } float BL_Action::GetFrame() @@ -305,25 +265,20 @@ float BL_Action::GetFrame() return m_localframe; } -const char *BL_Action::GetName() +const std::string BL_Action::GetName() { - if (m_action != NULL) { - return m_action->id.name + 2; - } - else { - return ""; - } - - + return (m_actionData) ? m_actionData->GetName() : ""; } void BL_Action::SetFrame(float frame) { // Clamp the frame to the start and end frame - if (frame < min(m_startframe, m_endframe)) - frame = min(m_startframe, m_endframe); - else if (frame > max(m_startframe, m_endframe)) - frame = max(m_startframe, m_endframe); + if (frame < std::min(m_startframe, m_endframe)) { + frame = std::min(m_startframe, m_endframe); + } + else if (frame > std::max(m_startframe, m_endframe)) { + frame = std::max(m_startframe, m_endframe); + } m_localframe = frame; m_calc_localtime = false; @@ -334,18 +289,13 @@ void BL_Action::SetPlayMode(short play_mode) m_playmode = play_mode; } -void BL_Action::SetTimes(float start, float end) -{ - m_startframe = start; - m_endframe = end; -} - void BL_Action::SetLocalTime(float curtime) { - float dt = (curtime-m_starttime)*(float)KX_KetsjiEngine::GetAnimFrameRate()*m_speed; + float dt = (curtime - m_starttime) * (float)KX_GetActiveEngine()->GetAnimFrameRate() * m_speed; - if (m_endframe < m_startframe) + if (m_endframe < m_startframe) { dt = -dt; + } m_localframe = m_startframe + dt; } @@ -354,109 +304,131 @@ void BL_Action::ResetStartTime(float curtime) { float dt = (m_localframe > m_startframe) ? m_localframe - m_startframe : m_startframe - m_localframe; - m_starttime = curtime - dt / ((float)KX_KetsjiEngine::GetAnimFrameRate()*m_speed); + m_starttime = curtime - dt / ((float)KX_GetActiveEngine()->GetAnimFrameRate() * m_speed); SetLocalTime(curtime); } void BL_Action::IncrementBlending(float curtime) { // Setup m_blendstart if we need to - if (m_blendstart == 0.f) + if (m_blendstart == 0.f) { m_blendstart = curtime; + } // Bump the blend frame - m_blendframe = (curtime - m_blendstart)*(float)KX_KetsjiEngine::GetAnimFrameRate(); + m_blendframe = (curtime - m_blendstart) * (float)KX_GetActiveEngine()->GetAnimFrameRate(); // Clamp - if (m_blendframe>m_blendin) + if (m_blendframe > m_blendin) { m_blendframe = m_blendin; + } } -void BL_Action::BlendShape(Key* key, float srcweight, std::vector& blendshape) +void BL_Action::BlendShape(Key *key, float srcweight, std::vector& blendshape) { - vector::const_iterator it; + std::vector::const_iterator it; float dstweight; KeyBlock *kb; dstweight = 1.0F - srcweight; - //printf("Dst: %f\tSrc: %f\n", srcweight, dstweight); - for (it=blendshape.begin(), kb = (KeyBlock *)key->block.first; + for (it = blendshape.begin(), kb = (KeyBlock *)key->block.first; kb && it != blendshape.end(); kb = (KeyBlock *)kb->next, it++) { - //printf("OirgKeys: %f\t%f\n", kb->curval, (*it)); kb->curval = kb->curval * dstweight + (*it) * srcweight; - //printf("NewKey: %f\n", kb->curval); } - //printf("\n"); } -void BL_Action::Update(float curtime) +void BL_Action::Update(float curtime, bool applyToObject) { - // Don't bother if we're done with the animation - if (m_done) + /* Don't bother if we're done with the animation and if the animation was already applied to the object. + * of if the animation made a double update for the same time and that it was applied to the object. + */ + if ((m_done || m_prevUpdate == curtime) && m_appliedToObject) { return; - - curtime -= (float)KX_KetsjiEngine::GetSuspendedDelta(); - - // Grab the start time here so we don't end up with a negative m_localframe when - // suspending and resuming scenes. - if (!m_initializedTime) { - m_starttime = curtime; - m_initializedTime = true; } + m_prevUpdate = curtime; + + KX_Scene *scene = m_obj->GetScene(); + curtime -= (float)scene->GetSuspendedDelta(); - if (m_calc_localtime) + if (m_calc_localtime) { SetLocalTime(curtime); - else - { + } + else { ResetStartTime(curtime); m_calc_localtime = true; } + // Compute minimum and maximum action frame. + const float minFrame = std::min(m_startframe, m_endframe); + const float maxFrame = std::max(m_startframe, m_endframe); + // Handle wrap around - if (m_localframe < min(m_startframe, m_endframe) || m_localframe > max(m_startframe, m_endframe)) { + if (m_localframe < minFrame || m_localframe > maxFrame) { switch (m_playmode) { case ACT_MODE_PLAY: + { // Clamp m_localframe = m_endframe; m_done = true; break; + } case ACT_MODE_LOOP: + { // Put the time back to the beginning m_localframe = m_startframe; m_starttime = curtime; break; + } case ACT_MODE_PING_PONG: + { + m_localframe = m_endframe; + m_starttime = curtime; + // Swap the start and end frames float temp = m_startframe; m_startframe = m_endframe; m_endframe = temp; - - m_starttime = curtime; - break; + } } } - if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) - { - BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj; + BLI_assert(m_localframe >= minFrame && m_localframe <= maxFrame); + + m_appliedToObject = applyToObject; + // In case of culled armatures (doesn't requesting to transform the object) we only manages time. + if (!applyToObject) { + return; + } + + m_requestIpo = true; - if (m_layer_weight >= 0) + SG_Node *node = m_obj->GetNode(); + // Update controllers time. + for (SG_Controller *cont : m_controllers) { + cont->SetSimulatedTime(m_localframe); // update spatial controllers + cont->Update(node); + } + + if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) { + BL_ArmatureObject *obj = (BL_ArmatureObject *)m_obj; + + if (m_layer_weight >= 0) { obj->GetPose(&m_blendpose); + } // Extract the pose from the action obj->SetPoseByAction(m_tmpaction, m_localframe); // Handle blending between armature actions - if (m_blendin && m_blendframeBlendInPose(m_blendinpose, weight, ACT_BLEND_BLEND); @@ -464,71 +436,61 @@ void BL_Action::Update(float curtime) // Handle layer blending - if (m_layer_weight >= 0) + if (m_layer_weight >= 0) { obj->BlendInPose(m_blendpose, m_layer_weight, m_blendmode); + } obj->UpdateTimestep(curtime); } - else - { - BL_DeformableGameObject *obj = (BL_DeformableGameObject*)m_obj; - BL_ShapeDeformer *shape_deformer = dynamic_cast(obj->GetDeformer()); + else { + BL_ShapeDeformer *shape_deformer = dynamic_cast(m_obj->GetDeformer()); // Handle shape actions if we have any - if (shape_deformer && shape_deformer->GetKey()) - { + if (shape_deformer && shape_deformer->GetKey()) { Key *key = shape_deformer->GetKey(); PointerRNA ptrrna; RNA_id_pointer_create(&key->id, &ptrrna); - animsys_evaluate_action(&ptrrna, m_tmpaction, NULL, m_localframe); + animsys_evaluate_action(&ptrrna, m_tmpaction, nullptr, m_localframe); // Handle blending between shape actions - if (m_blendin && m_blendframe < m_blendin) - { + if (m_blendin && m_blendframe < m_blendin) { IncrementBlending(curtime); - float weight = 1.f - (m_blendframe/m_blendin); + float weight = 1.f - (m_blendframe / m_blendin); // We go through and clear out the keyblocks so there isn't any interference // from other shape actions KeyBlock *kb; - for (kb=(KeyBlock *)key->block.first; kb; kb=(KeyBlock *)kb->next) + for (kb = (KeyBlock *)key->block.first; kb; kb = (KeyBlock *)kb->next) { kb->curval = 0.f; + } // Now blend the shape BlendShape(key, weight, m_blendinshape); } // Handle layer blending - if (m_layer_weight >= 0) - { - obj->GetShape(m_blendshape); + if (m_layer_weight >= 0) { + shape_deformer->GetShape(m_blendshape); BlendShape(key, m_layer_weight, m_blendshape); } - obj->SetActiveAction(NULL, 0, curtime); + shape_deformer->SetLastFrame(curtime); } } - BLI_spin_lock(&BL_ActionLock); - /* This function is not thread safe because of recursive scene graph transform - * updates on children. e.g: If an object and one of its children is animated, - * the both can write transform at the same time. A thread lock avoid problems. */ - m_obj->UpdateIPO(m_localframe, m_ipo_flags & ACT_IPOFLAG_CHILD); - BLI_spin_unlock(&BL_ActionLock); - - if (m_done) + // If the action is done we can remove its scene graph IPO controller. + if (m_done) { ClearControllerList(); + } } -void BL_Action::InitLock() -{ - BLI_spin_init(&BL_ActionLock); -} - -void BL_Action::EndLock() +void BL_Action::UpdateIPOs() { - BLI_spin_end(&BL_ActionLock); + if (m_requestIpo) { + m_obj->GetNode()->UpdateWorldDataThread(); + m_requestIpo = false; + } } diff --git a/source/gameengine/Ketsji/BL_Action.h b/source/gameengine/Ketsji/BL_Action.h index f4c2975a5474..f4b421fc3387 100644 --- a/source/gameengine/Ketsji/BL_Action.h +++ b/source/gameengine/Ketsji/BL_Action.h @@ -27,22 +27,24 @@ #ifndef __BL_ACTION_H__ #define __BL_ACTION_H__ - +#include #include -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif +class KX_GameObject; +class SG_Controller; +class BL_ActionData; +struct bAction; +struct bPose; class BL_Action { private: - struct bAction* m_action; - struct bAction* m_tmpaction; - struct bPose* m_blendpose; - struct bPose* m_blendinpose; - std::vector m_sg_contr_list; - class KX_GameObject* m_obj; + BL_ActionData *m_actionData; + bAction* m_tmpaction; + bPose* m_blendpose; + bPose* m_blendinpose; + std::vector m_controllers; + KX_GameObject* m_obj; std::vector m_blendshape; std::vector m_blendinshape; @@ -68,11 +70,20 @@ class BL_Action short m_ipo_flags; bool m_done; + /** Set to true when the last action update applies transformations + * to the object. + */ + bool m_appliedToObject; + + /// Set to true when the action was updated and applied. Back to false in the IPO update (UpdateIPO). + bool m_requestIpo; bool m_calc_localtime; - /// Set to true when m_starttime is initialized in Update. - bool m_initializedTime; + + // The last update time to avoid double animation update. + float m_prevUpdate; void ClearControllerList(); + void AddController(SG_Controller *cont); void InitIPO(); void SetLocalTime(float curtime); void ResetStartTime(float curtime); @@ -85,7 +96,7 @@ class BL_Action /** * Play an action */ - bool Play(const char* name, + bool Play(const std::string& name, float start, float end, short priority, @@ -101,19 +112,25 @@ class BL_Action bool IsDone(); /** * Update the action's frame, etc. + * \param curtime The current time used to compute the action's' frame. + * \param applyToObject Set to true when the action must be applied to the object, + * else it only manages action's' time/end. */ - void Update(float curtime); + void Update(float curtime, bool applyToObject); + /** + * Update object IPOs (note: not thread-safe!) + */ + void UpdateIPOs(); // Accessors float GetFrame(); - const char *GetName(); + const std::string GetName(); - struct bAction *GetAction(); + BL_ActionData *GetActionData(); // Mutators void SetFrame(float frame); void SetPlayMode(short play_mode); - void SetTimes(float start, float end); enum { @@ -135,17 +152,7 @@ class BL_Action ACT_IPOFLAG_FORCE = 1, ACT_IPOFLAG_LOCAL = 2, ACT_IPOFLAG_ADD = 4, - ACT_IPOFLAG_CHILD = 8, }; - - /// Initialize a lock for animation thread issues. - static void InitLock(); - /// Finalize a lock for animation thread issues. - static void EndLock(); - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_Action") -#endif }; #endif /* BL_ACTION */ diff --git a/source/gameengine/Ketsji/BL_ActionManager.cpp b/source/gameengine/Ketsji/BL_ActionManager.cpp index 35f605f1a5f6..e3272a876d04 100644 --- a/source/gameengine/Ketsji/BL_ActionManager.cpp +++ b/source/gameengine/Ketsji/BL_ActionManager.cpp @@ -25,14 +25,12 @@ */ #include "BL_Action.h" +#include "BL_ActionData.h" #include "BL_ActionManager.h" -#include "DNA_ID.h" -#define IS_TAGGED(_id) ((_id) && (((ID *)_id)->tag & LIB_TAG_DOIT)) - -BL_ActionManager::BL_ActionManager(class KX_GameObject *obj): +BL_ActionManager::BL_ActionManager(class KX_GameObject *obj) : m_obj(obj), - m_prevUpdate(-1.0f) + m_suspended(false) { } @@ -40,17 +38,18 @@ BL_ActionManager::~BL_ActionManager() { BL_ActionMap::iterator it; - for (it = m_layers.begin(); it != m_layers.end(); it++) + for (it = m_layers.begin(); it != m_layers.end(); it++) { delete it->second; + } m_layers.clear(); } -BL_Action *BL_ActionManager::GetAction(short layer) +BL_Action *BL_ActionManager::GetAction(short layer) const { - BL_ActionMap::iterator it = m_layers.find(layer); + BL_ActionMap::const_iterator it = m_layers.find(layer); - return (it != m_layers.end()) ? it->second : 0; + return (it != m_layers.end()) ? it->second : nullptr; } float BL_ActionManager::GetActionFrame(short layer) @@ -60,7 +59,7 @@ float BL_ActionManager::GetActionFrame(short layer) return action ? action->GetFrame() : 0.f; } -const char *BL_ActionManager::GetActionName(short layer) +const std::string BL_ActionManager::GetActionName(short layer) { BL_Action *action = GetAction(layer); return action ? action->GetName() : ""; @@ -70,41 +69,38 @@ void BL_ActionManager::SetActionFrame(short layer, float frame) { BL_Action *action = GetAction(layer); - if (action) action->SetFrame(frame); + if (action) { + action->SetFrame(frame); + } } -struct bAction *BL_ActionManager::GetCurrentAction(short layer) +std::string BL_ActionManager::GetCurrentActionName(short layer) const { BL_Action *action = GetAction(layer); - return action ? action->GetAction() : 0; + return action ? action->GetName() : ""; } void BL_ActionManager::SetPlayMode(short layer, short mode) { BL_Action *action = GetAction(layer); - if (action) action->SetPlayMode(mode); -} - -void BL_ActionManager::SetTimes(short layer, float start, float end) -{ - BL_Action *action = GetAction(layer); - - if (action) action->SetTimes(start, end); + if (action) { + action->SetPlayMode(mode); + } } -bool BL_ActionManager::PlayAction(const char* name, - float start, - float end, - short layer, - short priority, - float blendin, - short play_mode, - float layer_weight, - short ipo_flags, - float playback_speed, - short blend_mode) +bool BL_ActionManager::PlayAction(const std::string& name, + float start, + float end, + short layer, + short priority, + float blendin, + short play_mode, + float layer_weight, + short ipo_flags, + float playback_speed, + short blend_mode) { // Only this method will create layer if non-existent BL_Action *action = GetAction(layer); @@ -114,7 +110,9 @@ bool BL_ActionManager::PlayAction(const char* name, } // Disable layer blending on the first layer - if (layer == 0) layer_weight = -1.f; + if (layer == 0) { + layer_weight = -1.f; + } return action->Play(name, start, end, priority, blendin, play_mode, layer_weight, ipo_flags, playback_speed, blend_mode); } @@ -129,15 +127,16 @@ void BL_ActionManager::StopAction(short layer) } } -void BL_ActionManager::RemoveTaggedActions() +void BL_ActionManager::RemoveActions(const BL_Resource::Library& libraryId) { - for (BL_ActionMap::iterator it = m_layers.begin(); it != m_layers.end();) { - if (IS_TAGGED(it->second->GetAction())) { + for (BL_ActionMap::iterator it = m_layers.begin(); it != m_layers.end(); ) { + if (it->second->GetActionData()->Belong(libraryId)) { delete it->second; - m_layers.erase(it++); + it = m_layers.erase(it); } - else + else { ++it; + } } } @@ -148,17 +147,28 @@ bool BL_ActionManager::IsActionDone(short layer) return action ? action->IsDone() : true; } -void BL_ActionManager::Update(float curtime) +void BL_ActionManager::Suspend() { - if (m_prevUpdate == curtime) - return; - m_prevUpdate = curtime; + m_suspended = true; +} - BL_ActionMap::iterator it; - for (it = m_layers.begin(); it != m_layers.end(); ++it) - { - if (!it->second->IsDone()) { - it->second->Update(curtime); - } +void BL_ActionManager::Resume() +{ + m_suspended = false; +} + +bool BL_ActionManager::IsSuspended() const +{ + return m_suspended; +} + +void BL_ActionManager::Update(float curtime, bool applyToObject) +{ + for (const auto& pair : m_layers) { + pair.second->Update(curtime, applyToObject); + } + + for (const auto& pair : m_layers) { + pair.second->UpdateIPOs(); } } diff --git a/source/gameengine/Ketsji/BL_ActionManager.h b/source/gameengine/Ketsji/BL_ActionManager.h index 90fa164853e6..34d6657ecbc2 100644 --- a/source/gameengine/Ketsji/BL_ActionManager.h +++ b/source/gameengine/Ketsji/BL_ActionManager.h @@ -27,10 +27,6 @@ #ifndef __BL_ACTIONMANAGER_H__ #define __BL_ACTIONMANAGER_H__ -#ifdef WITH_CXX_GUARDEDALLOC - #include "MEM_guardedalloc.h" -#endif - #include // Currently, we use the max value of a short. @@ -51,19 +47,19 @@ class BL_ActionManager class KX_GameObject* m_obj; BL_ActionMap m_layers; - // The last update time to avoid double animation update. - float m_prevUpdate; + /// Suspend action update? + bool m_suspended; /** * Check if an action exists */ - BL_Action* GetAction(short layer); + BL_Action* GetAction(short layer) const; public: BL_ActionManager(class KX_GameObject* obj); ~BL_ActionManager(); - bool PlayAction(const char* name, + bool PlayAction(const std::string& name, float start, float end, short layer=0, @@ -81,52 +77,51 @@ class BL_ActionManager /** * Gets the name of the current action - */ - const char *GetActionName(short layer); + */ + const std::string GetActionName(short layer); /** * Sets the current frame of an action */ void SetActionFrame(short layer, float frame); - + /** * Gets the currently running action on the given layer */ - struct bAction *GetCurrentAction(short layer); + std::string GetCurrentActionName(short layer) const; /** * Sets play mode of the action on the given layer */ void SetPlayMode(short layer, short mode); - /** - * Sets the start and end times of the action on the given layer - */ - void SetTimes(short layer, float start, float end); - /** * Stop playing the action on the given layer */ void StopAction(short layer); - /** - * Remove playing tagged actions. - */ - void RemoveTaggedActions(); + void RemoveActions(const BL_Resource::Library& libraryId); /** * Check if an action has finished playing */ bool IsActionDone(short layer); + void Suspend(); + void Resume(); + bool IsSuspended() const; + /** * Update any running actions + * \param curtime The current time used to compute the actions' frame. + * \param applyToObject Set to true if the actions must transform the object, else it only manages actions' frames. */ - void Update(float); + void Update(float curtime, bool applyToObject); -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_ActionManager") -#endif + /** + * Update object IPOs (note: not thread-safe!) + */ + void UpdateIPOs(); }; #endif /* BL_ACTIONMANAGER */ diff --git a/source/gameengine/Ketsji/BL_BlenderShader.cpp b/source/gameengine/Ketsji/BL_BlenderShader.cpp index afcd6ca3a5c2..c677aa3ba04e 100644 --- a/source/gameengine/Ketsji/BL_BlenderShader.cpp +++ b/source/gameengine/Ketsji/BL_BlenderShader.cpp @@ -22,167 +22,182 @@ * \ingroup ketsji */ -#include "DNA_customdata_types.h" #include "DNA_material_types.h" #include "DNA_scene_types.h" -#include "BLI_utildefines.h" - -#include "BKE_global.h" -#include "BKE_main.h" -#include "BKE_DerivedMesh.h" - -#include "BL_BlenderShader.h" -#include "BL_Material.h" - #include "GPU_material.h" #include "GPU_shader.h" +#include "GPU_extensions.h" + +#include "BL_BlenderShader.h" #include "RAS_BucketManager.h" -#include "RAS_MeshObject.h" -#include "RAS_IRasterizer.h" - -BL_BlenderShader::BL_BlenderShader(KX_Scene *scene, struct Material *ma, int lightlayer) -: - mMat(ma), - mLightLayer(lightlayer), - mGPUMat(NULL) +#include "RAS_Mesh.h" +#include "RAS_MeshUser.h" +#include "RAS_InstancingBuffer.h" +#include "RAS_Rasterizer.h" +#include "RAS_IMaterial.h" + +#include "KX_Scene.h" + +#include + +BL_BlenderShader::BL_BlenderShader(KX_Scene *scene, struct Material *ma, + CM_UpdateServer *materialUpdateServer) + :m_blenderScene(scene->GetBlenderScene()), + m_mat(ma), + m_alphaBlend(GPU_BLEND_SOLID), + m_gpuMat(nullptr), + m_materialUpdateServer(materialUpdateServer) { - mBlenderScene = scene->GetBlenderScene(); - mAlphaBlend = GPU_BLEND_SOLID; - ReloadMaterial(); } BL_BlenderShader::~BL_BlenderShader() { - if (mGPUMat) - GPU_material_unbind(mGPUMat); -} - -void BL_BlenderShader::ReloadMaterial() -{ - mGPUMat = (mMat) ? GPU_material_from_blender(mBlenderScene, mMat, false) : NULL; } -void BL_BlenderShader::SetProg(bool enable, double time, RAS_IRasterizer* rasty) +const RAS_AttributeArray::AttribList BL_BlenderShader::GetAttribs(const RAS_Mesh::LayersInfo& layersInfo) const { - if (VerifyShader()) { - if (enable) { - assert(rasty != NULL); // XXX Kinda hacky, but SetProg() should always have the rasterizer if enable is true - - float viewmat[4][4], viewinvmat[4][4]; - const MT_Matrix4x4& view = rasty->GetViewMatrix(); - const MT_Matrix4x4& viewinv = rasty->GetViewInvMatrix(); - view.getValue(&viewmat[0][0]); - viewinv.getValue(&viewinvmat[0][0]); - - GPU_material_bind(mGPUMat, mLightLayer, mBlenderScene->lay, time, 1, viewmat, viewinvmat, NULL, false); + RAS_AttributeArray::AttribList attribs; + GPUVertexAttribs gpuAttribs; + GPU_material_vertex_attributes(m_gpuMat, &gpuAttribs); + + for (unsigned int i = 0; i < gpuAttribs.totlayer; ++i) { + const int type = gpuAttribs.layer[i].type; + const unsigned short glindex = gpuAttribs.layer[i].glindex; + + if (type == CD_MTFACE || type == CD_MCOL) { + const char *attribname = gpuAttribs.layer[i].name; + if (strlen(attribname) == 0) { + // The color or uv layer is not specified, then use the active color or uv layer. + if (type == CD_MTFACE) { + attribs.push_back({glindex, RAS_AttributeArray::RAS_ATTRIB_UV, false, layersInfo.activeUv}); + } + else { + attribs.push_back({glindex, RAS_AttributeArray::RAS_ATTRIB_COLOR, false, layersInfo.activeColor}); + } + continue; + } + + if (type == CD_MTFACE) { + for (const RAS_Mesh::Layer& layer : layersInfo.uvLayers) { + if (layer.name == attribname) { + attribs.push_back({glindex, RAS_AttributeArray::RAS_ATTRIB_UV, false, layer.index}); + break; + } + } + } + else { + for (const RAS_Mesh::Layer& layer : layersInfo.colorLayers) { + if (layer.name == attribname) { + attribs.push_back({glindex, RAS_AttributeArray::RAS_ATTRIB_COLOR, false, layer.index}); + break; + } + } + } + } + else if (type == CD_TANGENT) { + attribs.push_back({glindex, RAS_AttributeArray::RAS_ATTRIB_TANGENT, false, 0}); + } + else if (type == CD_ORCO) { + attribs.push_back({glindex, RAS_AttributeArray::RAS_ATTRIB_POS, false, 0}); + } + else if (type == CD_NORMAL) { + attribs.push_back({glindex, RAS_AttributeArray::RAS_ATTRIB_NORM, false, 0}); } - else - GPU_material_unbind(mGPUMat); } + + return attribs; } -int BL_BlenderShader::GetAttribNum() +RAS_InstancingBuffer::Attrib BL_BlenderShader::GetInstancingAttribs() const { - GPUVertexAttribs attribs; - int i, enabled = 0; + GPUBuiltin builtins = GPU_get_material_builtins(m_gpuMat); - if (!VerifyShader()) - return enabled; - - GPU_material_vertex_attributes(mGPUMat, &attribs); - - for (i = 0; i < attribs.totlayer; i++) - if (attribs.layer[i].glindex+1 > enabled) - enabled= attribs.layer[i].glindex+1; - - if (enabled > BL_MAX_ATTRIB) - enabled = BL_MAX_ATTRIB; + RAS_InstancingBuffer::Attrib attrib = RAS_InstancingBuffer::DEFAULT_ATTRIBS; + if (builtins & GPU_INSTANCING_COLOR) { + attrib = (RAS_InstancingBuffer::Attrib)(attrib | RAS_InstancingBuffer::COLOR_ATTRIB); + } + if (builtins & GPU_INSTANCING_LAYER) { + attrib = (RAS_InstancingBuffer::Attrib)(attrib | RAS_InstancingBuffer::LAYER_ATTRIB); + } + if (builtins & GPU_INSTANCING_INFO) { + attrib = (RAS_InstancingBuffer::Attrib)(attrib | RAS_InstancingBuffer::INFO_ATTRIB); + } - return enabled; + return attrib; } -void BL_BlenderShader::SetAttribs(RAS_IRasterizer* ras, const BL_Material *mat) +bool BL_BlenderShader::Ok() const { - GPUVertexAttribs attribs; - GPUMaterial *gpumat; - int i, attrib_num, uv = 0; - - ras->SetAttribNum(0); - - if (!VerifyShader()) - return; + return (m_gpuMat != nullptr); +} - gpumat = mGPUMat; - if (ras->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED || (ras->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW && - mat->alphablend != GEMAT_SOLID && !ras->GetUsingOverrideShader())) { - GPU_material_vertex_attributes(gpumat, &attribs); - attrib_num = GetAttribNum(); +void BL_BlenderShader::ReloadMaterial() +{ + // Force regenerating shader by deleting it. + if (m_gpuMat) { + GPU_material_free(&m_mat->gpumaterial); + GPU_material_free(&m_mat->gpumaterialinstancing); + } - ras->SetTexCoordNum(0); - ras->SetAttribNum(attrib_num); - for (i = 0; i < attrib_num; i++) - ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_DISABLE, i); + GPUMaterialFlag flags = (GPUMaterialFlag) + (GPU_MATERIAL_NO_COLOR_MANAGEMENT | (UseInstancing() ? GPU_MATERIAL_INSTANCING : 0)); + m_gpuMat = (m_mat) ? GPU_material_from_blender(m_blenderScene, m_mat, flags) : nullptr; - for (i = 0; i < attribs.totlayer; i++) { - if (attribs.layer[i].glindex > attrib_num) - continue; + m_materialUpdateServer->NotifyUpdate(RAS_IMaterial::SHADER_MODIFIED); +} - if (attribs.layer[i].type == CD_MTFACE) - ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_UV, attribs.layer[i].glindex, uv++); - else if (attribs.layer[i].type == CD_TANGENT) - ras->SetAttrib(RAS_IRasterizer::RAS_TEXTANGENT, attribs.layer[i].glindex); - else if (attribs.layer[i].type == CD_ORCO) - ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_ORCO, attribs.layer[i].glindex); - else if (attribs.layer[i].type == CD_NORMAL) - ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_NORM, attribs.layer[i].glindex); - else if (attribs.layer[i].type == CD_MCOL) - ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_VCOL, attribs.layer[i].glindex); - else - ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_DISABLE, attribs.layer[i].glindex); - } - } +void BL_BlenderShader::BindProg(RAS_Rasterizer *rasty) +{ + GPU_material_bind(m_gpuMat, m_blenderScene->lay, rasty->GetTime(), 1, + rasty->GetViewMatrix().Data(), rasty->GetViewInvMatrix().Data(), nullptr, false); } -void BL_BlenderShader::Update(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty ) +void BL_BlenderShader::UnbindProg() { - float obmat[4][4], viewmat[4][4], obcol[4]; - GPUMaterial *gpumat; + GPU_material_unbind(m_gpuMat); +} - gpumat = mGPUMat; +void BL_BlenderShader::UpdateLights(RAS_Rasterizer *rasty) +{ + GPU_material_update_lamps(m_gpuMat, rasty->GetViewMatrix().Data(), rasty->GetViewInvMatrix().Data()); +} - if (!gpumat || !GPU_material_bound(gpumat)) +void BL_BlenderShader::Update(RAS_MeshUser *meshUser, short matPassIndex, RAS_Rasterizer *rasty) +{ + if (!GPU_material_bound(m_gpuMat)) { return; + } - MT_Matrix4x4 model; - model.setValue(ms.m_OpenGLMatrix); - - // note: getValue gives back column major as needed by OpenGL - model.getValue(&obmat[0][0]); + const float (&obcol)[4] = meshUser->GetColor().Data(); - if (ms.m_bObjectColor) - ms.m_RGBAcolor.getValue(&obcol[0]); - else - obcol[0] = obcol[1] = obcol[2] = obcol[3] = 1.0f; + float objectInfo[3]; + if (GPU_get_material_builtins(m_gpuMat) & GPU_OBJECT_INFO) { + objectInfo[0] = float(meshUser->GetPassIndex()); + objectInfo[1] = float(matPassIndex); + objectInfo[2] = meshUser->GetRandom(); + } - rasty->GetViewMatrix().getValue(&viewmat[0][0]); - float auto_bump_scale = ms.m_pDerivedMesh!=0 ? ms.m_pDerivedMesh->auto_bump_scale : 1.0f; - GPU_material_bind_uniforms(gpumat, obmat, viewmat, obcol, auto_bump_scale, NULL, NULL); + GPU_material_bind_uniforms(m_gpuMat, meshUser->GetMatrix().Data(), rasty->GetViewMatrix().Data(), + obcol, meshUser->GetLayer(), 1.0f, nullptr, objectInfo); - mAlphaBlend = GPU_material_alpha_blend(gpumat, obcol); + m_alphaBlend = GPU_material_alpha_blend(m_gpuMat, obcol); } -int BL_BlenderShader::GetAlphaBlend() +bool BL_BlenderShader::UseInstancing() const { - return mAlphaBlend; + return (GPU_instanced_drawing_support() && (m_mat->shade_flag & MA_INSTANCING)); } -bool BL_BlenderShader::Equals(BL_BlenderShader *blshader) +void BL_BlenderShader::ActivateInstancing(RAS_InstancingBuffer *buffer) { - /* to avoid unneeded state switches */ - return (blshader && mMat == blshader->mMat && mLightLayer == blshader->mLightLayer); + GPU_material_bind_instancing_attrib(m_gpuMat, (void *)buffer->GetMatrixOffset(), (void *)buffer->GetPositionOffset(), + (void *)buffer->GetColorOffset(), (void *)buffer->GetLayerOffset(), (void *)buffer->GetInfoOffset()); } -// eof +int BL_BlenderShader::GetAlphaBlend() +{ + return m_alphaBlend; +} diff --git a/source/gameengine/Ketsji/BL_BlenderShader.h b/source/gameengine/Ketsji/BL_BlenderShader.h index 5222369c6b5d..bbf3cee5700a 100644 --- a/source/gameengine/Ketsji/BL_BlenderShader.h +++ b/source/gameengine/Ketsji/BL_BlenderShader.h @@ -32,65 +32,60 @@ #ifndef __BL_BLENDERSHADER_H__ #define __BL_BLENDERSHADER_H__ -#include "GPU_material.h" +#include "RAS_AttributeArray.h" +#include "RAS_Mesh.h" +#include "RAS_Texture.h" // for MaxUnits +#include "RAS_InstancingBuffer.h" -#include "MT_Matrix4x4.h" -#include "MT_Matrix3x3.h" -#include "MT_Tuple2.h" -#include "MT_Tuple3.h" -#include "MT_Tuple4.h" +#include "CM_Update.h" -#include "RAS_IPolygonMaterial.h" - -#include "KX_Scene.h" +#include struct Material; struct Scene; -class BL_Material; - -#define BL_MAX_ATTRIB 16 +struct GPUMaterial; +class KX_Scene; +class RAS_MeshSlot; +class RAS_IMaterial; /** * BL_BlenderShader - * Blender GPU shader material + * Blender GPU shader material */ class BL_BlenderShader { private: - struct Scene *mBlenderScene; - struct Material *mMat; - int mLightLayer; - int mAlphaBlend; - GPUMaterial *mGPUMat; - - bool VerifyShader() - { - return (NULL != mGPUMat); - } + Scene *m_blenderScene; + Material *m_mat; + int m_alphaBlend; + GPUMaterial *m_gpuMat; + CM_UpdateServer *m_materialUpdateServer; public: - BL_BlenderShader(KX_Scene *scene, struct Material *ma, int lightlayer); + BL_BlenderShader(KX_Scene *scene, Material *ma, CM_UpdateServer *materialUpdateServer); virtual ~BL_BlenderShader(); - bool Ok() - { - // same as VerifyShared - return (NULL != mGPUMat); - } - void SetProg(bool enable, double time=0.0, RAS_IRasterizer* rasty=NULL); + bool Ok() const; - int GetAttribNum(); - void SetAttribs(class RAS_IRasterizer* ras, const BL_Material *mat); - void Update(const class RAS_MeshSlot & ms, class RAS_IRasterizer* rasty); - void ReloadMaterial(); - int GetAlphaBlend(); + void BindProg(RAS_Rasterizer *rasty); + void UnbindProg(); + + /** Return a map of the corresponding attribut layer for a given attribut index. + * \param layers The list of the mesh layers used to link with uv and color material attributes. + * \return The map of attributes layers. + */ + const RAS_AttributeArray::AttribList GetAttribs(const RAS_Mesh::LayersInfo& layersInfo) const; + RAS_InstancingBuffer::Attrib GetInstancingAttribs() const; - bool Equals(BL_BlenderShader *blshader); + void UpdateLights(RAS_Rasterizer *rasty); + void Update(RAS_MeshUser *meshUser, short matPassIndex, RAS_Rasterizer *rasty); + /// Return true if the shader uses a special vertex shader for geometry instancing. + bool UseInstancing() const; + void ActivateInstancing(RAS_InstancingBuffer *buffer); -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_BlenderShader") -#endif + void ReloadMaterial(); + int GetAlphaBlend(); }; -#endif /* __BL_BLENDERSHADER_H__ */ +#endif // __BL_BLENDERSHADER_H__ diff --git a/source/gameengine/Ketsji/BL_Material.cpp b/source/gameengine/Ketsji/BL_Material.cpp deleted file mode 100644 index 89321bed7327..000000000000 --- a/source/gameengine/Ketsji/BL_Material.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Ketsji/BL_Material.cpp - * \ingroup ketsji - */ - -#include "BL_Material.h" -#include "DNA_material_types.h" -#include "DNA_texture_types.h" -#include "DNA_image_types.h" -#include "DNA_mesh_types.h" -#include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" - -MTex* getMTexFromMaterial(Material *mat, int index) -{ - if (mat && (index >= 0) && (index < MAX_MTEX)) { - return mat->mtex[index]; - } - else { - return NULL; - } -} - -BL_Material::BL_Material() -{ - Initialize(); -} - -void BL_Material::Initialize() -{ - rgb[0] = 0xFFFFFFFFL; - rgb[1] = 0xFFFFFFFFL; - rgb[2] = 0xFFFFFFFFL; - rgb[3] = 0xFFFFFFFFL; - IdMode = 0; - ras_mode = 0; - glslmat = 0; - tile = 0; - matname = "NoMaterial"; - matcolor[0] = 0.5f; - matcolor[1] = 0.5f; - matcolor[2] = 0.5f; - matcolor[3] = 0.5f; - speccolor[0] = 1.f; - speccolor[1] = 1.f; - speccolor[2] = 1.f; - alphablend = 0; - hard = 50.f; - spec_f = 0.5f; - alpha = 1.f; - emit = 0.f; - material = 0; - memset(&mtexpoly, 0, sizeof(mtexpoly)); - materialindex = 0; - amb=0.5f; - num_enabled = 0; - num_users = 1; - share = false; - - int i; - - for (i = 0; i < MAXTEX; i++) // :( - { - mapping[i].mapping = 0; - mapping[i].offsets[0] = 0.f; - mapping[i].offsets[1] = 0.f; - mapping[i].offsets[2] = 0.f; - mapping[i].scale[0] = 1.f; - mapping[i].scale[1] = 1.f; - mapping[i].scale[2] = 1.f; - mapping[i].projplane[0] = PROJX; - mapping[i].projplane[1] = PROJY; - mapping[i].projplane[2] = PROJZ; - mapping[i].objconame = ""; - mtexname[i] = "NULL"; - imageId[i]="NULL"; - flag[i] = 0; - texname[i] = "NULL"; - tilexrep[i] = 1; - tileyrep[i] = 1; - color_blend[i] = 1.f; - blend_mode[i] = 0; - img[i] = 0; - cubemap[i] = 0; - } -} - -void BL_Material::SetSharedMaterial(bool v) -{ - if ((v && num_users == -1) || num_users > 1 ) - share = true; - else - share = false; -} - -bool BL_Material::IsShared() -{ - return share; -} - -void BL_Material::SetUsers(int num) -{ - num_users = num; -} diff --git a/source/gameengine/Ketsji/BL_Material.h b/source/gameengine/Ketsji/BL_Material.h deleted file mode 100644 index bb12ef868727..000000000000 --- a/source/gameengine/Ketsji/BL_Material.h +++ /dev/null @@ -1,181 +0,0 @@ - -/** \file BL_Material.h - * \ingroup ketsji - */ - -#ifndef __BL_MATERIAL_H__ -#define __BL_MATERIAL_H__ - -#include "STR_String.h" -#include "MT_Point2.h" -#include "DNA_meshdata_types.h" - -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -// -- -struct MTex; -struct Material; -struct Image; -struct MTFace; -struct MTex; -struct Material; -struct EnvMap; -// -- - -/** max units - * this will default to users available units - * to build with more available, just increment this value - * although the more you add the slower the search time will be. - * we will go for eight, which should be enough - */ -#define MAXTEX 8 //match in RAS_TexVert & RAS_OpenGLRasterizer - -// different mapping modes -class BL_Mapping -{ -public: - int mapping; - float scale[3]; - float offsets[3]; - int projplane[3]; - STR_String objconame; - STR_String uvCoName; -}; - -// base material struct -class BL_Material -{ -private: - int num_users; - bool share; - -public: - // ----------------------------------- - BL_Material(); - void Initialize(); - - int IdMode; - unsigned int ras_mode; - bool glslmat; - - STR_String texname[MAXTEX]; - unsigned int flag[MAXTEX]; - int tile,tilexrep[MAXTEX],tileyrep[MAXTEX]; - STR_String matname; - STR_String mtexname[MAXTEX]; - int materialindex; - - float matcolor[4]; - float speccolor[3]; - short alphablend, pad; - - float hard, spec_f; - float alpha, emit, color_blend[MAXTEX], ref; - float amb; - - int blend_mode[MAXTEX]; - - int num_enabled; - - BL_Mapping mapping[MAXTEX]; - STR_String imageId[MAXTEX]; - - - Material* material; - MTexPoly mtexpoly; /* copy of the derived meshes tface */ - Image* img[MAXTEX]; - EnvMap* cubemap[MAXTEX]; - - unsigned int rgb[4]; - - void SetSharedMaterial(bool v); - bool IsShared(); - void SetUsers(int num); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_Material") -#endif -}; - -// BL_Material::IdMode -enum BL_IdMode { - DEFAULT_BLENDER=-1, - TEXFACE, - ONETEX, - TWOTEX, - GREATERTHAN2 -}; - -// BL_Material::blend_mode[index] -enum BL_BlendMode -{ - BLEND_MIX=1, - BLEND_ADD, - BLEND_SUB, - BLEND_MUL, - BLEND_SCR -}; - -// ------------------------------------- -// BL_Material::flag[index] -enum BL_flag -{ - MIPMAP=1, // set to use mipmaps - CALCALPHA=2, // additive - USEALPHA=4, // use actual alpha channel - TEXALPHA=8, // use alpha combiner functions - TEXNEG=16, // negate blending - /*HASIPO=32,*/ // unused, commeted for now. - USENEGALPHA=64 -}; - -// BL_Material::ras_mode -enum BL_ras_mode -{ - // POLY_VIS=1, - COLLIDER=2, - ZSORT=4, - ALPHA=8, - // TRIANGLE=16, - USE_LIGHT=32, - WIRE=64, - CAST_SHADOW=128, - TEX=256, - TWOSIDED=512, - ONLY_SHADOW=1024, -}; - -// ------------------------------------- -// BL_Material::mapping[index]::mapping -enum BL_MappingFlag -{ - USEENV =1, - // -- - USEREFL =2, - USEOBJ =4, - USENORM =8, - USEORCO =16, - USEUV =32, - USETANG =64, - DISABLE =128, - USECUSTOMUV=256 -}; - -// BL_Material::BL_Mapping::projplane -enum BL_MappingProj -{ - PROJN=0, - PROJX, - PROJY, - PROJZ -}; - -// ------------------------------------ -//extern void initBL_Material(BL_Material* mat); -extern MTex* getMTexFromMaterial(Material *mat, int index); -// ------------------------------------ - -#endif diff --git a/source/gameengine/Ketsji/BL_Shader.cpp b/source/gameengine/Ketsji/BL_Shader.cpp index 660924e2e67e..4660ff708691 100644 --- a/source/gameengine/Ketsji/BL_Shader.cpp +++ b/source/gameengine/Ketsji/BL_Shader.cpp @@ -22,779 +22,200 @@ * \ingroup ketsji */ -#include "GPU_glew.h" -#include #include "BL_Shader.h" -#include "BL_Material.h" -#include "MT_assert.h" -#include "MT_Matrix4x4.h" -#include "MT_Matrix3x3.h" +#include "RAS_MeshSlot.h" +#include "RAS_MeshUser.h" +#include "RAS_IMaterial.h" + #include "KX_PyMath.h" #include "KX_PythonInit.h" -#include "MEM_guardedalloc.h" +#include "KX_GameObject.h" -#include "RAS_MeshObject.h" -#include "RAS_IRasterizer.h" +#include "DNA_material_types.h" -#define spit(x) std::cout << x << std::endl; +#ifdef WITH_PYTHON +# include "EXP_PythonCallBack.h" +#endif // WITH_PYTHON -#define SORT_UNIFORMS 1 -#define UNIFORM_MAX_LEN (int)sizeof(float) * 16 -#define MAX_LOG_LEN 262144 // bounds +#include -BL_Uniform::BL_Uniform(int data_size) - : - mLoc(-1), - mDirty(true), - mType(UNI_NONE), - mTranspose(0), - mDataLen(data_size) -{ -#ifdef SORT_UNIFORMS - MT_assert((int)mDataLen <= UNIFORM_MAX_LEN); - mData = (void *)MEM_mallocN(mDataLen, "shader-uniform-alloc"); -#endif -} +#include "CM_Message.h" -BL_Uniform::~BL_Uniform() +BL_Shader::BL_Shader(CM_UpdateServer *materialUpdateServer) + :m_attr(SHD_NONE), + m_materialUpdateServer(materialUpdateServer) { -#ifdef SORT_UNIFORMS - if (mData) { - MEM_freeN(mData); - mData = NULL; - } -#endif -} - -bool BL_Uniform::Apply(class BL_Shader *shader) -{ -#ifdef SORT_UNIFORMS - RAS_IRasterizer *ras; - MT_assert(mType > UNI_NONE && mType < UNI_MAX && mData); - - if (!mDirty) - return false; - - mDirty = false; - switch (mType) { - case UNI_FLOAT: - { - float *f = (float *)mData; - glUniform1fARB(mLoc, (GLfloat)*f); - break; - } - case UNI_FLOAT_EYE: - { - float *f = (float*)mData; - ras = KX_GetActiveEngine()->GetRasterizer(); - *f = (ras->GetEye() == RAS_IRasterizer::RAS_STEREO_LEFTEYE) ? 0.0f : 0.5f; - glUniform1fARB(mLoc, (GLfloat)*f); - mDirty = (ras->Stereo()) ? true : false; - break; - } - case UNI_INT: - { - int *f = (int *)mData; - glUniform1iARB(mLoc, (GLint)*f); - break; - } - case UNI_FLOAT2: - { - float *f = (float *)mData; - glUniform2fvARB(mLoc, 1, (GLfloat *)f); - break; - } - case UNI_FLOAT3: - { - float *f = (float *)mData; - glUniform3fvARB(mLoc, 1, (GLfloat *)f); - break; - } - case UNI_FLOAT4: - { - float *f = (float *)mData; - glUniform4fvARB(mLoc, 1, (GLfloat *)f); - break; - } - case UNI_INT2: - { - int *f = (int *)mData; - glUniform2ivARB(mLoc, 1, (GLint *)f); - break; - } - case UNI_INT3: - { - int *f = (int *)mData; - glUniform3ivARB(mLoc, 1, (GLint *)f); - break; - } - case UNI_INT4: - { - int *f = (int *)mData; - glUniform4ivARB(mLoc, 1, (GLint *)f); - break; - } - case UNI_MAT4: - { - float *f = (float *)mData; - glUniformMatrix4fvARB(mLoc, 1, mTranspose ? GL_TRUE : GL_FALSE, (GLfloat *)f); - break; - } - case UNI_MAT3: - { - float *f = (float *)mData; - glUniformMatrix3fvARB(mLoc, 1, mTranspose ? GL_TRUE : GL_FALSE, (GLfloat *)f); - break; - } +#ifdef WITH_PYTHON + for (unsigned short i = 0; i < CALLBACKS_MAX; ++i) { + m_callbacks[i] = PyList_New(0); } - return mDirty; -#endif -} - -void BL_Uniform::SetData(int location, int type, bool transpose) -{ -#ifdef SORT_UNIFORMS - mType = type; - mLoc = location; - mDirty = true; -#endif -} - -bool BL_Shader::Ok()const -{ - return (mShader != 0 && mOk && mUse); -} - -BL_Shader::BL_Shader() - : - PyObjectPlus(), - mShader(0), - mPass(1), - mOk(0), - mUse(0), - mAttr(0), - vertProg(NULL), - fragProg(NULL), - mError(0), - mDirty(true) -{ - // if !GLEW_ARB_shader_objects this class will not be used - //for (int i=0; iDeleteTex(); - // } - //} - ClearUniforms(); - - if (mShader) { - glDeleteObjectARB(mShader); - mShader = 0; - } - - vertProg = NULL; - fragProg = NULL; - mOk = 0; - glUseProgramObjectARB(0); -} - -void BL_Shader::ClearUniforms() -{ - BL_UniformVec::iterator it = mUniforms.begin(); - while (it != mUniforms.end()) { - delete *it; - it++; - } - mUniforms.clear(); - - BL_UniformVecDef::iterator itp = mPreDef.begin(); - while (itp != mPreDef.end()) { - delete *itp; - itp++; - } - mPreDef.clear(); -} - -BL_Uniform *BL_Shader::FindUniform(const int location) -{ -#ifdef SORT_UNIFORMS - BL_UniformVec::iterator it = mUniforms.begin(); - while (it != mUniforms.end()) { - if ((*it)->GetLocation() == location) { - return *it; - } - it++; - } -#endif - return NULL; -} - -void BL_Shader::SetUniformfv(int location, int type, float *param, int size, bool transpose) -{ -#ifdef SORT_UNIFORMS - BL_Uniform *uni = FindUniform(location); - - if (uni) { - memcpy(uni->getData(), param, size); - uni->SetData(location, type, transpose); - } - else { - uni = new BL_Uniform(size); - memcpy(uni->getData(), param, size); - uni->SetData(location, type, transpose); - mUniforms.push_back(uni); - } - - mDirty = true; -#endif -} - -void BL_Shader::SetUniformiv(int location, int type, int *param, int size, bool transpose) -{ -#ifdef SORT_UNIFORMS - BL_Uniform *uni = FindUniform(location); - - if (uni) { - memcpy(uni->getData(), param, size); - uni->SetData(location, type, transpose); - } - else { - uni = new BL_Uniform(size); - memcpy(uni->getData(), param, size); - uni->SetData(location, type, transpose); - mUniforms.push_back(uni); +#ifdef WITH_PYTHON + for (unsigned short i = 0; i < CALLBACKS_MAX; ++i) { + Py_XDECREF(m_callbacks[i]); } - - mDirty = true; -#endif -} - -void BL_Shader::ApplyShader() -{ -#ifdef SORT_UNIFORMS - if (!mDirty) { - return; - } - - mDirty = false; - for (unsigned int i=0; iApply(this); - } -#endif -} - -void BL_Shader::UnloadShader() -{ - // +#endif // WITH_PYTHON } bool BL_Shader::LinkProgram() { - int vertlen = 0, fraglen = 0, proglen = 0; - int vertstatus = 0, fragstatus = 0, progstatus = 0; - unsigned int tmpVert = 0, tmpFrag = 0, tmpProg = 0; - int char_len = 0; - char *logInf = NULL; - - if (mError) { - goto programError; - } - - if (!vertProg || !fragProg) { - spit("Invalid GLSL sources"); - return false; - } - - if (!GLEW_ARB_fragment_shader) { - spit("Fragment shaders not supported"); - return false; - } - - if (!GLEW_ARB_vertex_shader) { - spit("Vertex shaders not supported"); - return false; + // Can be null in case of filter shaders. + if (m_materialUpdateServer) { + // Notify all clients tracking this shader that shader is recompiled and attributes are invalidated. + m_materialUpdateServer->NotifyUpdate(RAS_IMaterial::SHADER_MODIFIED | RAS_IMaterial::ATTRIBUTES_MODIFIED); } - if (vertProg[0] != 0) { - // -- vertex shader ------------------ - tmpVert = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); - glShaderSourceARB(tmpVert, 1, (const char**)&vertProg, 0); - glCompileShaderARB(tmpVert); - glGetObjectParameterivARB(tmpVert, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*)&vertlen); - - // print info if any - if (vertlen > 0 && vertlen < MAX_LOG_LEN) { - logInf = (char*)MEM_mallocN(vertlen, "vert-log"); - glGetInfoLogARB(tmpVert, vertlen, (GLsizei*)&char_len, logInf); - if (char_len > 0) { - spit("---- Vertex Shader Error ----"); - spit(logInf); - } - MEM_freeN(logInf); - logInf = 0; - } - // check for compile errors - glGetObjectParameterivARB(tmpVert, GL_OBJECT_COMPILE_STATUS_ARB, (GLint*)&vertstatus); - if (!vertstatus) { - spit("---- Vertex shader failed to compile ----"); - goto programError; - } - } - - if (fragProg[0] != 0) { - // -- fragment shader ---------------- - tmpFrag = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); - glShaderSourceARB(tmpFrag, 1, (const char**)&fragProg, 0); - glCompileShaderARB(tmpFrag); - glGetObjectParameterivARB(tmpFrag, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint*)&fraglen); - if (fraglen > 0 && fraglen < MAX_LOG_LEN) { - logInf = (char*)MEM_mallocN(fraglen, "frag-log"); - glGetInfoLogARB(tmpFrag, fraglen, (GLsizei*)&char_len, logInf); - if (char_len > 0) { - spit("---- Fragment Shader Error ----"); - spit(logInf); - } - MEM_freeN(logInf); - logInf = 0; - } - - glGetObjectParameterivARB(tmpFrag, GL_OBJECT_COMPILE_STATUS_ARB, (GLint*)&fragstatus); - if (!fragstatus) { - spit("---- Fragment shader failed to compile ----"); - goto programError; - } - } - - if (!tmpFrag && !tmpVert) { - spit("---- No shader given ----"); - goto programError; - } - - // -- program ------------------------ - // set compiled vert/frag shader & link - tmpProg = glCreateProgramObjectARB(); - if (tmpVert) { - glAttachObjectARB(tmpProg, tmpVert); - } - if (tmpFrag) { - glAttachObjectARB(tmpProg, tmpFrag); - } - glLinkProgramARB(tmpProg); - glGetObjectParameterivARB(tmpProg, GL_OBJECT_INFO_LOG_LENGTH_ARB, (GLint *)&proglen); - glGetObjectParameterivARB(tmpProg, GL_OBJECT_LINK_STATUS_ARB, (GLint *)&progstatus); - - if (proglen > 0 && proglen < MAX_LOG_LEN) { - logInf = (char *)MEM_mallocN(proglen, "prog-log"); - glGetInfoLogARB(tmpProg, proglen, (GLsizei *)&char_len, logInf); - - if (char_len > 0) { - spit("---- GLSL Program ----"); - spit(logInf); - } - - MEM_freeN(logInf); - logInf = 0; - } - - if (!progstatus) { - spit("---- GLSL program failed to link ----"); - goto programError; - } - - // set - mShader = tmpProg; - if (tmpVert) { - glDeleteObjectARB(tmpVert); - } - if (tmpFrag) { - glDeleteObjectARB(tmpFrag); - } - mOk = 1; - mError = 0; - return true; - -programError: - if (tmpVert) { - glDeleteObjectARB(tmpVert); - tmpVert = 0; - } - - if (tmpFrag) { - glDeleteObjectARB(tmpFrag); - tmpFrag = 0; - } - - if (tmpProg) { - glDeleteObjectARB(tmpProg); - tmpProg = 0; - } - - mOk = 0; - mUse = 0; - mError = 1; - return false; + return RAS_Shader::LinkProgram(); } -const char *BL_Shader::GetVertPtr() +std::string BL_Shader::GetName() { - return vertProg ? vertProg : NULL; + return "BL_Shader"; } -const char *BL_Shader::GetFragPtr() +std::string BL_Shader::GetText() { - return fragProg ? fragProg : NULL; + return (boost::format("BL_Shader\n\tvertex shader:%s\n\n\tfragment shader%s\n\n") % + m_progs[VERTEX_PROGRAM] % m_progs[FRAGMENT_PROGRAM]).str(); } -void BL_Shader::SetVertPtr(char *vert) -{ - vertProg = vert; -} -void BL_Shader::SetFragPtr(char *frag) -{ - fragProg = frag; -} +#ifdef WITH_PYTHON -unsigned int BL_Shader::GetProg() +PyObject *BL_Shader::GetCallbacks(BL_Shader::CallbacksType type) { - return mShader; + return m_callbacks[type]; } -//const BL_Sampler *BL_Shader::GetSampler(int i) -//{ -// MT_assert(i<=MAXTEX); -// return &mSampler[i]; -//} - -void BL_Shader::SetSampler(int loc, int unit) +void BL_Shader::SetCallbacks(BL_Shader::CallbacksType type, PyObject *callbacks) { - if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) { - glUniform1iARB(loc, unit); - } + Py_XDECREF(m_callbacks[type]); + Py_INCREF(callbacks); + m_callbacks[type] = callbacks; } -//void BL_Shader::InitializeSampler(int unit, BL_Texture *texture) -//{ -// MT_assert(unit <= MAXTEX); -// mSampler[unit].mTexture = texture; -// mSampler[unit].mLoc = -1; -// mSampler[unit].mOwn = 0; -//} - -void BL_Shader::SetProg(bool enable) -{ - if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) { - if (mShader != 0 && mOk && enable) { - glUseProgramObjectARB(mShader); - } - else { - glUseProgramObjectARB(0); - } - } -} +#endif // WITH_PYTHON -void BL_Shader::Update(const RAS_MeshSlot &ms, RAS_IRasterizer *rasty) +RAS_AttributeArray::AttribList BL_Shader::GetAttribs(const RAS_Mesh::LayersInfo& layersInfo, + RAS_Texture *const textures[RAS_Texture::MaxUnits]) const { - if (!Ok() || !mPreDef.size()) { - return; - } - - if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) { - MT_Matrix4x4 model; - model.setValue(ms.m_OpenGLMatrix); - const MT_Matrix4x4 &view = rasty->GetViewMatrix(); - - if (mAttr == SHD_TANGENT) { - ms.m_mesh->SetMeshModified(true); - } - - BL_UniformVecDef::iterator it; - for (it = mPreDef.begin(); it != mPreDef.end(); it++) { - BL_DefUniform *uni = (*it); - - if (uni->mLoc == -1) { - continue; + RAS_AttributeArray::AttribList attribs; + // Initialize textures attributes. + for (unsigned short i = 0; i < RAS_Texture::MaxUnits; ++i) { + RAS_Texture *texture = textures[i]; + /* Here textures can return false to Ok() because we're looking only at + * texture attributes and not texture bind id like for the binding and + * unbinding of textures. A nullptr RAS_Texture means that the corresponding + * mtex is nullptr too (see KX_BlenderMaterial::InitTextures).*/ + if (texture) { + MTex *mtex = texture->GetMTex(); + if (mtex->texco & (TEXCO_OBJECT | TEXCO_REFL)) { + attribs.push_back({i, RAS_AttributeArray::RAS_ATTRIB_POS, true, 0}); } - - switch (uni->mType) { - case MODELMATRIX: - { - SetUniform(uni->mLoc, model); - break; - } - case MODELMATRIX_TRANSPOSE: - { - SetUniform(uni->mLoc, model, true); - break; - } - case MODELMATRIX_INVERSE: - { - model.invert(); - SetUniform(uni->mLoc, model); - break; - } - case MODELMATRIX_INVERSETRANSPOSE: - { - model.invert(); - SetUniform(uni->mLoc, model, true); - break; - } - case MODELVIEWMATRIX: - { - SetUniform(uni->mLoc, view * model); - break; - } - case MODELVIEWMATRIX_TRANSPOSE: - { - MT_Matrix4x4 mat(view * model); - SetUniform(uni->mLoc, mat, true); - break; - } - case MODELVIEWMATRIX_INVERSE: - { - MT_Matrix4x4 mat(view * model); - mat.invert(); - SetUniform(uni->mLoc, mat); - break; - } - case MODELVIEWMATRIX_INVERSETRANSPOSE: - { - MT_Matrix4x4 mat(view * model); - mat.invert(); - SetUniform(uni->mLoc, mat, true); - break; - } - case CAM_POS: - { - MT_Point3 pos(rasty->GetCameraPosition()); - SetUniform(uni->mLoc, pos); - break; - } - case VIEWMATRIX: - { - SetUniform(uni->mLoc, view); - break; - } - case VIEWMATRIX_TRANSPOSE: - { - SetUniform(uni->mLoc, view, true); - break; - } - case VIEWMATRIX_INVERSE: - { - MT_Matrix4x4 viewinv = view; - viewinv.invert(); - SetUniform(uni->mLoc, view); - break; - } - case VIEWMATRIX_INVERSETRANSPOSE: - { - MT_Matrix4x4 viewinv = view; - viewinv.invert(); - SetUniform(uni->mLoc, view, true); - break; + else if (mtex->texco & (TEXCO_ORCO | TEXCO_GLOB)) { + attribs.push_back({i, RAS_AttributeArray::RAS_ATTRIB_POS, true, 0}); + } + else if (mtex->texco & TEXCO_UV) { + // UV layer not specified, use default layer. + if (strlen(mtex->uvname) == 0) { + attribs.push_back({i, RAS_AttributeArray::RAS_ATTRIB_UV, true, layersInfo.activeUv}); } - case CONSTANT_TIMER: - { - SetUniform(uni->mLoc, (float)rasty->GetTime()); - break; + + // Search for the UV layer index used by the texture. + for (const RAS_Mesh::Layer& layer : layersInfo.uvLayers) { + if (layer.name == mtex->uvname) { + attribs.push_back({i, RAS_AttributeArray::RAS_ATTRIB_UV, true, layer.index}); + break; + } } - default: - break; + } + else if (mtex->texco & TEXCO_NORM) { + attribs.push_back({i, RAS_AttributeArray::RAS_ATTRIB_NORM, true, 0}); + } + else if (mtex->texco & TEXCO_TANGENT) { + attribs.push_back({i, RAS_AttributeArray::RAS_ATTRIB_TANGENT, true, 0}); } } } -} - -int BL_Shader::GetAttribLocation(const char *name) -{ - if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) { - return glGetAttribLocationARB(mShader, name); - } - - return -1; -} - -void BL_Shader::BindAttribute(const char *attr, int loc) -{ - if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) { - glBindAttribLocationARB(mShader, loc, attr); - } -} - -int BL_Shader::GetUniformLocation(const char *name) -{ - if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) { - MT_assert(mShader != 0); - int location = glGetUniformLocationARB(mShader, name); - - if (location == -1) { - spit("Invalid uniform value: " << name << "."); - } - - return location; - } - return -1; -} -void BL_Shader::SetUniform(int uniform, const MT_Tuple2 &vec) -{ - if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) { - float value[2]; - vec.getValue(value); - glUniform2fvARB(uniform, 1, value); + if (m_attr == SHD_TANGENT) { + attribs.push_back({1, RAS_AttributeArray::RAS_ATTRIB_TANGENT, false, 0}); } -} - -void BL_Shader::SetUniform(int uniform, const MT_Tuple3 &vec) -{ - if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) { - float value[3]; - vec.getValue(value); - glUniform3fvARB(uniform, 1, value); - } -} -void BL_Shader::SetUniform(int uniform, const MT_Tuple4 &vec) -{ - if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) { - float value[4]; - vec.getValue(value); - glUniform4fvARB(uniform, 1, value); - } + return attribs; } -void BL_Shader::SetUniform(int uniform, const unsigned int &val) +void BL_Shader::BindProg() { - if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) { - glUniform1iARB(uniform, val); - } -} - -void BL_Shader::SetUniform(int uniform, const int val) -{ - if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) { - glUniform1iARB(uniform, val); - } -} - -void BL_Shader::SetUniform(int uniform, const float &val) -{ - if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) { - glUniform1fARB(uniform, val); +#ifdef WITH_PYTHON + if (PyList_GET_SIZE(m_callbacks[CALLBACKS_BIND]) > 0) { + EXP_RunPythonCallBackList(m_callbacks[CALLBACKS_BIND], nullptr, 0, 0); } -} +#endif // WITH_PYTHON -void BL_Shader::SetUniform(int uniform, const MT_Matrix4x4 &vec, bool transpose) -{ - if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) { - float value[16]; - // note: getValue gives back column major as needed by OpenGL - vec.getValue(value); - glUniformMatrix4fvARB(uniform, 1, transpose ? GL_TRUE : GL_FALSE, value); - } + RAS_Shader::BindProg(); } -void BL_Shader::SetUniform(int uniform, const MT_Matrix3x3 &vec, bool transpose) +void BL_Shader::Update(RAS_Rasterizer *rasty, RAS_MeshUser *meshUser) { - if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) { - float value[9]; - value[0] = (float)vec[0][0]; - value[1] = (float)vec[1][0]; - value[2] = (float)vec[2][0]; - value[3] = (float)vec[0][1]; - value[4] = (float)vec[1][1]; - value[5] = (float)vec[2][1]; - value[6] = (float)vec[0][2]; - value[7] = (float)vec[1][2]; - value[8] = (float)vec[2][2]; - glUniformMatrix3fvARB(uniform, 1, transpose ? GL_TRUE : GL_FALSE, value); +#ifdef WITH_PYTHON + if (PyList_GET_SIZE(m_callbacks[CALLBACKS_OBJECT]) > 0) { + KX_GameObject *gameobj = KX_GameObject::GetClientObject((KX_ClientObjectInfo *)meshUser->GetClientObject()); + PyObject *args[] = {gameobj->GetProxy()}; + EXP_RunPythonCallBackList(m_callbacks[CALLBACKS_OBJECT], args, 0, ARRAY_SIZE(args)); } -} +#endif // WITH_PYTHON -void BL_Shader::SetUniform(int uniform, const float *val, int len) -{ - if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) { - if (len == 2) { - glUniform2fvARB(uniform, 1, (GLfloat *)val); - } - else if (len == 3) { - glUniform3fvARB(uniform, 1, (GLfloat *)val); - } - else if (len == 4) { - glUniform4fvARB(uniform, 1, (GLfloat *)val); - } - else { - MT_assert(0); - } - } -} - -void BL_Shader::SetUniform(int uniform, const int *val, int len) -{ - if (GLEW_ARB_fragment_shader && GLEW_ARB_vertex_shader && GLEW_ARB_shader_objects) { - if (len == 2) { - glUniform2ivARB(uniform, 1, (GLint *)val); - } - else if (len == 3) { - glUniform3ivARB(uniform, 1, (GLint *)val); - } - else if (len == 4) { - glUniform4ivARB(uniform, 1, (GLint *)val); - } - else { - MT_assert(0); - } - } + RAS_Shader::Update(rasty, meshUser->GetMatrix()); } #ifdef WITH_PYTHON PyMethodDef BL_Shader::Methods[] = { // creation - KX_PYMETHODTABLE(BL_Shader, setSource), - KX_PYMETHODTABLE(BL_Shader, delSource), - KX_PYMETHODTABLE(BL_Shader, getVertexProg), - KX_PYMETHODTABLE(BL_Shader, getFragmentProg), - KX_PYMETHODTABLE(BL_Shader, setNumberOfPasses), - KX_PYMETHODTABLE(BL_Shader, validate), + EXP_PYMETHODTABLE(BL_Shader, setSource), + EXP_PYMETHODTABLE(BL_Shader, setSourceList), + EXP_PYMETHODTABLE(BL_Shader, delSource), + EXP_PYMETHODTABLE(BL_Shader, getVertexProg), + EXP_PYMETHODTABLE(BL_Shader, getFragmentProg), + EXP_PYMETHODTABLE(BL_Shader, validate), // access functions - KX_PYMETHODTABLE(BL_Shader, isValid), - KX_PYMETHODTABLE(BL_Shader, setUniformEyef), - KX_PYMETHODTABLE(BL_Shader, setUniform1f), - KX_PYMETHODTABLE(BL_Shader, setUniform2f), - KX_PYMETHODTABLE(BL_Shader, setUniform3f), - KX_PYMETHODTABLE(BL_Shader, setUniform4f), - KX_PYMETHODTABLE(BL_Shader, setUniform1i), - KX_PYMETHODTABLE(BL_Shader, setUniform2i), - KX_PYMETHODTABLE(BL_Shader, setUniform3i), - KX_PYMETHODTABLE(BL_Shader, setUniform4i), - KX_PYMETHODTABLE(BL_Shader, setAttrib), - KX_PYMETHODTABLE(BL_Shader, setUniformfv), - KX_PYMETHODTABLE(BL_Shader, setUniformiv), - KX_PYMETHODTABLE(BL_Shader, setUniformDef), - KX_PYMETHODTABLE(BL_Shader, setSampler), - KX_PYMETHODTABLE(BL_Shader, setUniformMatrix4), - KX_PYMETHODTABLE(BL_Shader, setUniformMatrix3), - {NULL, NULL} //Sentinel + EXP_PYMETHODTABLE(BL_Shader, isValid), + EXP_PYMETHODTABLE(BL_Shader, setUniformEyef), + EXP_PYMETHODTABLE(BL_Shader, setUniform1f), + EXP_PYMETHODTABLE(BL_Shader, setUniform2f), + EXP_PYMETHODTABLE(BL_Shader, setUniform3f), + EXP_PYMETHODTABLE(BL_Shader, setUniform4f), + EXP_PYMETHODTABLE(BL_Shader, setUniform1i), + EXP_PYMETHODTABLE(BL_Shader, setUniform2i), + EXP_PYMETHODTABLE(BL_Shader, setUniform3i), + EXP_PYMETHODTABLE(BL_Shader, setUniform4i), + EXP_PYMETHODTABLE(BL_Shader, setAttrib), + EXP_PYMETHODTABLE(BL_Shader, setUniformfv), + EXP_PYMETHODTABLE(BL_Shader, setUniformiv), + EXP_PYMETHODTABLE(BL_Shader, setUniformDef), + EXP_PYMETHODTABLE(BL_Shader, setSampler), + EXP_PYMETHODTABLE(BL_Shader, setUniformMatrix4), + EXP_PYMETHODTABLE(BL_Shader, setUniformMatrix3), + {nullptr, nullptr} //Sentinel }; PyAttributeDef BL_Shader::Attributes[] = { - {NULL} //Sentinel + EXP_PYATTRIBUTE_RW_FUNCTION("enabled", BL_Shader, pyattr_get_enabled, pyattr_set_enabled), + EXP_PYATTRIBUTE_RW_FUNCTION("bindCallbacks", BL_Shader, pyattr_get_callbacks, pyattr_set_callbacks), + EXP_PYATTRIBUTE_RW_FUNCTION("objectCallbacks", BL_Shader, pyattr_get_callbacks, pyattr_set_callbacks), + EXP_PYATTRIBUTE_NULL //Sentinel }; PyTypeObject BL_Shader::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "BL_Shader", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -808,14 +229,58 @@ PyTypeObject BL_Shader::Type = { Methods, 0, 0, - &PyObjectPlus::Type, + &EXP_PyObjectPlus::Type, 0, 0, 0, 0, 0, 0, py_base_new }; -KX_PYMETHODDEF_DOC(BL_Shader, setSource, " setSource(vertexProgram, fragmentProgram)") +PyObject *BL_Shader::pyattr_get_enabled(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - if (mShader != 0 && mOk) { + BL_Shader *self = static_cast(self_v); + return PyBool_FromLong(self->GetEnabled()); +} + +int BL_Shader::pyattr_set_enabled(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_Shader *self = static_cast(self_v); + int param = PyObject_IsTrue(value); + if (param == -1) { + PyErr_SetString(PyExc_AttributeError, "shader.enabled = bool: BL_Shader, expected True or False"); + return PY_SET_ATTR_FAIL; + } + + self->SetEnabled(param); + return PY_SET_ATTR_SUCCESS; +} + +static std::map callbacksTable = { + {"bindCallbacks", BL_Shader::CALLBACKS_BIND}, + {"objectCallbacks", BL_Shader::CALLBACKS_OBJECT} +}; + +PyObject *BL_Shader::pyattr_get_callbacks(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + BL_Shader *self = static_cast(self_v); + PyObject *callbacks = self->GetCallbacks(callbacksTable[attrdef->m_name]); + Py_INCREF(callbacks); + return callbacks; +} + +int BL_Shader::pyattr_set_callbacks(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_Shader *self = static_cast(self_v); + if (!PyList_CheckExact(value)) { + PyErr_Format(PyExc_AttributeError, "shader.%s = bool: BL_Shader, expected a list", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; + } + + self->SetCallbacks(callbacksTable[attrdef->m_name], value); + return PY_SET_ATTR_SUCCESS; +} + +EXP_PYMETHODDEF_DOC(BL_Shader, setSource, " setSource(vertexProgram, fragmentProgram, apply)") +{ + if (m_shader) { // already set... Py_RETURN_NONE; } @@ -824,85 +289,117 @@ KX_PYMETHODDEF_DOC(BL_Shader, setSource, " setSource(vertexProgram, fragmentProg int apply = 0; if (PyArg_ParseTuple(args, "ssi:setSource", &v, &f, &apply)) { - vertProg = v; - fragProg = f; + m_progs[VERTEX_PROGRAM] = std::string(v); + m_progs[FRAGMENT_PROGRAM] = std::string(f); + m_progs[GEOMETRY_PROGRAM] = ""; if (LinkProgram()) { - glUseProgramObjectARB(mShader); - mUse = apply != 0; + m_use = apply != 0; Py_RETURN_NONE; } - vertProg = NULL; - fragProg = NULL; - mUse = 0; + m_progs[VERTEX_PROGRAM] = ""; + m_progs[FRAGMENT_PROGRAM] = ""; + m_use = false; Py_RETURN_NONE; } - return NULL; + return nullptr; } +EXP_PYMETHODDEF_DOC(BL_Shader, setSourceList, " setSourceList(sources, apply)") +{ + if (m_shader) { + // already set... + Py_RETURN_NONE; + } + + PyObject *pydict; + int apply = 0; + + if (!PyArg_ParseTuple(args, "O!i:setSourceList", &PyDict_Type, &pydict, &apply)) { + return nullptr; + } + + bool error = false; + static const char *progname[MAX_PROGRAM] = {"vertex", "fragment", "geometry"}; + static const bool optional[MAX_PROGRAM] = {false, false, true}; + + for (unsigned short i = 0; i < MAX_PROGRAM; ++i) { + PyObject *pyprog = PyDict_GetItemString(pydict, progname[i]); + if (!optional[i]) { + if (!pyprog) { + error = true; + PyErr_Format(PyExc_SystemError, "setSourceList(sources, apply): BL_Shader, non optional %s program missing", progname[i]); + break; + } + else if (!PyUnicode_Check(pyprog)) { + error = true; + PyErr_Format(PyExc_SystemError, "setSourceList(sources, apply): BL_Shader, non optional %s program is not a string", progname[i]); + break; + } + } + if (pyprog) { + m_progs[i] = std::string(_PyUnicode_AsString(pyprog)); + } + } + + if (error) { + for (unsigned short i = 0; i < MAX_PROGRAM; ++i) { + m_progs[i] = ""; + } + m_use = false; + return nullptr; + } -KX_PYMETHODDEF_DOC(BL_Shader, delSource, "delSource( )") + if (LinkProgram()) { + m_use = apply != 0; + } + + Py_RETURN_NONE; +} + +EXP_PYMETHODDEF_DOC(BL_Shader, delSource, "delSource( )") { ClearUniforms(); - glUseProgramObjectARB(0); - glDeleteObjectARB(mShader); - mShader = 0; - mOk = 0; - mUse = 0; + DeleteShader(); Py_RETURN_NONE; } -KX_PYMETHODDEF_DOC(BL_Shader, isValid, "isValid()") +EXP_PYMETHODDEF_DOC(BL_Shader, isValid, "isValid()") { - return PyBool_FromLong((mShader != 0 && mOk)); + return PyBool_FromLong(m_shader != nullptr); } -KX_PYMETHODDEF_DOC(BL_Shader, getVertexProg, "getVertexProg( )") +EXP_PYMETHODDEF_DOC(BL_Shader, getVertexProg, "getVertexProg( )") { - return PyUnicode_FromString(vertProg ? vertProg : ""); + return PyUnicode_FromStdString(m_progs[VERTEX_PROGRAM]); } -KX_PYMETHODDEF_DOC(BL_Shader, getFragmentProg, "getFragmentProg( )") +EXP_PYMETHODDEF_DOC(BL_Shader, getFragmentProg, "getFragmentProg( )") { - return PyUnicode_FromString(fragProg ? fragProg : ""); + return PyUnicode_FromStdString(m_progs[FRAGMENT_PROGRAM]); } -KX_PYMETHODDEF_DOC(BL_Shader, validate, "validate()") +EXP_PYMETHODDEF_DOC(BL_Shader, validate, "validate()") { - if (mError) { + if (!m_shader) { Py_RETURN_NONE; } - if (mShader == 0) { + if (!m_shader) { PyErr_SetString(PyExc_TypeError, "shader.validate(): BL_Shader, invalid shader object"); - return NULL; + return nullptr; } - int stat = 0; - glValidateProgramARB(mShader); - glGetObjectParameterivARB(mShader, GL_OBJECT_VALIDATE_STATUS_ARB, (GLint *)&stat); + ValidateProgram(); - if (stat > 0 && stat < MAX_LOG_LEN) { - int char_len = 0; - char *logInf = (char *)MEM_mallocN(stat, "validate-log"); - - glGetInfoLogARB(mShader, stat, (GLsizei *)&char_len, logInf); - - if (char_len > 0) { - spit("---- GLSL Validation ----"); - spit(logInf); - } - MEM_freeN(logInf); - logInf = NULL; - } Py_RETURN_NONE; } -KX_PYMETHODDEF_DOC(BL_Shader, setSampler, "setSampler(name, index)") +EXP_PYMETHODDEF_DOC(BL_Shader, setSampler, "setSampler(name, index)") { - if (mError) { + if (!m_shader) { Py_RETURN_NONE; } @@ -913,40 +410,24 @@ KX_PYMETHODDEF_DOC(BL_Shader, setSampler, "setSampler(name, index)") int loc = GetUniformLocation(uniform); if (loc != -1) { - if (index >= MAXTEX || index < 0) { - spit("Invalid texture sample index: " << index); + if (index >= RAS_Texture::MaxUnits || index < 0) { + CM_Warning("invalid texture sample index: " << index); } #ifdef SORT_UNIFORMS - SetUniformiv(loc, BL_Uniform::UNI_INT, &index, (sizeof(int))); + SetUniformiv(loc, RAS_Uniform::UNI_INT, &index, (sizeof(int)), 1); #else SetUniform(loc, index); #endif - //if (index <= MAXTEX) - // mSampler[index].mLoc = loc; - //else - // spit("Invalid texture sample index: " << index); } Py_RETURN_NONE; } - return NULL; -} - -KX_PYMETHODDEF_DOC(BL_Shader, setNumberOfPasses, "setNumberOfPasses( max-pass )") -{ - int pass = 1; - - if (!PyArg_ParseTuple(args, "i:setNumberOfPasses", &pass)) { - return NULL; - } - - mPass = 1; - Py_RETURN_NONE; + return nullptr; } /// access functions -KX_PYMETHODDEF_DOC(BL_Shader, setUniform1f, "setUniform1f(name, fx)") +EXP_PYMETHODDEF_DOC(BL_Shader, setUniform1f, "setUniform1f(name, fx)") { - if (mError) { + if (!m_shader) { Py_RETURN_NONE; } @@ -958,19 +439,19 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniform1f, "setUniform1f(name, fx)") if (loc != -1) { #ifdef SORT_UNIFORMS - SetUniformfv(loc, BL_Uniform::UNI_FLOAT, &value, sizeof(float)); + SetUniformfv(loc, RAS_Uniform::UNI_FLOAT, &value, sizeof(float), 1); #else SetUniform(loc, (float)value); #endif } Py_RETURN_NONE; } - return NULL; + return nullptr; } -KX_PYMETHODDEF_DOC(BL_Shader, setUniform2f, "setUniform2f(name, fx, fy)") +EXP_PYMETHODDEF_DOC(BL_Shader, setUniform2f, "setUniform2f(name, fx, fy)") { - if (mError) { + if (!m_shader) { Py_RETURN_NONE; } @@ -982,19 +463,19 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniform2f, "setUniform2f(name, fx, fy)") if (loc != -1) { #ifdef SORT_UNIFORMS - SetUniformfv(loc, BL_Uniform::UNI_FLOAT2, array, (sizeof(float) * 2)); + SetUniformfv(loc, RAS_Uniform::UNI_FLOAT2, array, (sizeof(float) * 2), 1); #else SetUniform(loc, array, 2); #endif } Py_RETURN_NONE; } - return NULL; + return nullptr; } -KX_PYMETHODDEF_DOC(BL_Shader, setUniform3f, "setUniform3f(name, fx,fy,fz) ") +EXP_PYMETHODDEF_DOC(BL_Shader, setUniform3f, "setUniform3f(name, fx,fy,fz) ") { - if (mError) { + if (!m_shader) { Py_RETURN_NONE; } @@ -1006,19 +487,19 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniform3f, "setUniform3f(name, fx,fy,fz) ") if (loc != -1) { #ifdef SORT_UNIFORMS - SetUniformfv(loc, BL_Uniform::UNI_FLOAT3, array, (sizeof(float) * 3)); + SetUniformfv(loc, RAS_Uniform::UNI_FLOAT3, array, (sizeof(float) * 3), 1); #else SetUniform(loc, array, 3); #endif } Py_RETURN_NONE; } - return NULL; + return nullptr; } -KX_PYMETHODDEF_DOC(BL_Shader, setUniform4f, "setUniform4f(name, fx,fy,fz, fw) ") +EXP_PYMETHODDEF_DOC(BL_Shader, setUniform4f, "setUniform4f(name, fx,fy,fz, fw) ") { - if (mError) { + if (!m_shader) { Py_RETURN_NONE; } @@ -1030,40 +511,51 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniform4f, "setUniform4f(name, fx,fy,fz, fw) ") if (loc != -1) { #ifdef SORT_UNIFORMS - SetUniformfv(loc, BL_Uniform::UNI_FLOAT4, array, (sizeof(float) * 4)); + SetUniformfv(loc, RAS_Uniform::UNI_FLOAT4, array, (sizeof(float) * 4), 1); #else SetUniform(loc, array, 4); #endif } Py_RETURN_NONE; } - return NULL; + return nullptr; } -KX_PYMETHODDEF_DOC(BL_Shader, setUniformEyef, "setUniformEyef(name)") +EXP_PYMETHODDEF_DOC(BL_Shader, setUniformEyef, "setUniformEyef(name)") { - if (mError) { + if (!m_shader) { Py_RETURN_NONE; } const char *uniform; - float value = 0.0f; if (PyArg_ParseTuple(args, "s:setUniformEyef", &uniform)) { int loc = GetUniformLocation(uniform); if (loc != -1) { -#ifdef SORT_UNIFORMS - SetUniformfv(loc, BL_Uniform::UNI_FLOAT_EYE, &value, sizeof(float)); -#else - SetUniform(loc, (int)value); -#endif + bool defined = false; + for (RAS_DefUniform *defuni : m_preDef) { + if (defuni->m_loc == loc) { + defined = true; + break; + } + } + + if (defined) { + Py_RETURN_NONE; + } + + RAS_DefUniform *uni = new RAS_DefUniform(); + uni->m_loc = loc; + uni->m_type = EYE; + uni->m_flag = 0; + m_preDef.push_back(uni); } Py_RETURN_NONE; } - return NULL; + return nullptr; } -KX_PYMETHODDEF_DOC(BL_Shader, setUniform1i, "setUniform1i(name, ix)") +EXP_PYMETHODDEF_DOC(BL_Shader, setUniform1i, "setUniform1i(name, ix)") { - if (mError) { + if (!m_shader) { Py_RETURN_NONE; } @@ -1075,19 +567,19 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniform1i, "setUniform1i(name, ix)") if (loc != -1) { #ifdef SORT_UNIFORMS - SetUniformiv(loc, BL_Uniform::UNI_INT, &value, sizeof(int)); + SetUniformiv(loc, RAS_Uniform::UNI_INT, &value, sizeof(int), 1); #else SetUniform(loc, (int)value); #endif } Py_RETURN_NONE; } - return NULL; + return nullptr; } -KX_PYMETHODDEF_DOC(BL_Shader, setUniform2i, "setUniform2i(name, ix, iy)") +EXP_PYMETHODDEF_DOC(BL_Shader, setUniform2i, "setUniform2i(name, ix, iy)") { - if (mError) { + if (!m_shader) { Py_RETURN_NONE; } @@ -1099,19 +591,19 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniform2i, "setUniform2i(name, ix, iy)") if (loc != -1) { #ifdef SORT_UNIFORMS - SetUniformiv(loc, BL_Uniform::UNI_INT2, array, sizeof(int) * 2); + SetUniformiv(loc, RAS_Uniform::UNI_INT2, array, sizeof(int) * 2, 1); #else SetUniform(loc, array, 2); #endif } Py_RETURN_NONE; } - return NULL; + return nullptr; } -KX_PYMETHODDEF_DOC(BL_Shader, setUniform3i, "setUniform3i(name, ix,iy,iz) ") +EXP_PYMETHODDEF_DOC(BL_Shader, setUniform3i, "setUniform3i(name, ix,iy,iz) ") { - if (mError) { + if (!m_shader) { Py_RETURN_NONE; } @@ -1123,19 +615,19 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniform3i, "setUniform3i(name, ix,iy,iz) ") if (loc != -1) { #ifdef SORT_UNIFORMS - SetUniformiv(loc, BL_Uniform::UNI_INT3, array, sizeof(int) * 3); + SetUniformiv(loc, RAS_Uniform::UNI_INT3, array, sizeof(int) * 3, 1); #else SetUniform(loc, array, 3); #endif } Py_RETURN_NONE; } - return NULL; + return nullptr; } -KX_PYMETHODDEF_DOC(BL_Shader, setUniform4i, "setUniform4i(name, ix,iy,iz, iw) ") +EXP_PYMETHODDEF_DOC(BL_Shader, setUniform4i, "setUniform4i(name, ix,iy,iz, iw) ") { - if (mError) { + if (!m_shader) { Py_RETURN_NONE; } @@ -1147,24 +639,24 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniform4i, "setUniform4i(name, ix,iy,iz, iw) ") if (loc != -1) { #ifdef SORT_UNIFORMS - SetUniformiv(loc, BL_Uniform::UNI_INT4, array, sizeof(int) * 4); + SetUniformiv(loc, RAS_Uniform::UNI_INT4, array, sizeof(int) * 4, 1); #else SetUniform(loc, array, 4); #endif } Py_RETURN_NONE; } - return NULL; + return nullptr; } -KX_PYMETHODDEF_DOC(BL_Shader, setUniformfv, "setUniformfv(float (list2 or list3 or list4))") +EXP_PYMETHODDEF_DOC(BL_Shader, setUniformfv, "setUniformfv(float (list2 or list3 or list4))") { - if (mError) { + if (!m_shader) { Py_RETURN_NONE; } const char *uniform = ""; - PyObject *listPtr = NULL; + PyObject *listPtr = nullptr; float array_data[4] = {0.0f, 0.0f, 0.0f, 0.0f}; if (PyArg_ParseTuple(args, "sO:setUniformfv", &uniform, &listPtr)) { @@ -1184,7 +676,7 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniformfv, "setUniformfv(float (list2 or list3 { float array2[2] = {array_data[0], array_data[1]}; #ifdef SORT_UNIFORMS - SetUniformfv(loc, BL_Uniform::UNI_FLOAT2, array2, sizeof(float) * 2); + SetUniformfv(loc, RAS_Uniform::UNI_FLOAT2, array2, sizeof(float) * 2, 1); #else SetUniform(loc, array2, 2); #endif @@ -1195,7 +687,7 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniformfv, "setUniformfv(float (list2 or list3 { float array3[3] = {array_data[0], array_data[1], array_data[2]}; #ifdef SORT_UNIFORMS - SetUniformfv(loc, BL_Uniform::UNI_FLOAT3, array3, sizeof(float) * 3); + SetUniformfv(loc, RAS_Uniform::UNI_FLOAT3, array3, sizeof(float) * 3, 1); #else SetUniform(loc, array3, 3); #endif @@ -1206,7 +698,7 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniformfv, "setUniformfv(float (list2 or list3 { float array4[4] = {array_data[0], array_data[1], array_data[2], array_data[3]}; #ifdef SORT_UNIFORMS - SetUniformfv(loc, BL_Uniform::UNI_FLOAT4, array4, sizeof(float) * 4); + SetUniformfv(loc, RAS_Uniform::UNI_FLOAT4, array4, sizeof(float) * 4, 1); #else SetUniform(loc, array4, 4); #endif @@ -1217,28 +709,28 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniformfv, "setUniformfv(float (list2 or list3 { PyErr_SetString(PyExc_TypeError, "shader.setUniform4i(name, ix,iy,iz, iw): BL_Shader. invalid list size"); - return NULL; + return nullptr; break; } } } } } - return NULL; + return nullptr; } -KX_PYMETHODDEF_DOC(BL_Shader, setUniformiv, "setUniformiv(uniform_name, (list2 or list3 or list4))") +EXP_PYMETHODDEF_DOC(BL_Shader, setUniformiv, "setUniformiv(uniform_name, (list2 or list3 or list4))") { - if (mError) { + if (!m_shader) { Py_RETURN_NONE; } const char *uniform = ""; - PyObject *listPtr = NULL; + PyObject *listPtr = nullptr; int array_data[4] = {0, 0, 0, 0}; if (!PyArg_ParseTuple(args, "sO:setUniformiv", &uniform, &listPtr)) { - return NULL; + return nullptr; } int loc = GetUniformLocation(uniform); @@ -1246,12 +738,12 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniformiv, "setUniformiv(uniform_name, (list2 o if (loc == -1) { PyErr_SetString(PyExc_TypeError, "shader.setUniformiv(...): BL_Shader, first string argument is not a valid uniform value"); - return NULL; + return nullptr; } if (!PySequence_Check(listPtr)) { PyErr_SetString(PyExc_TypeError, "shader.setUniformiv(...): BL_Shader, second argument is not a sequence"); - return NULL; + return nullptr; } unsigned int list_size = PySequence_Size(listPtr); @@ -1265,7 +757,7 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniformiv, "setUniformiv(uniform_name, (list2 o if (PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "shader.setUniformiv(...): BL_Shader, one or more values in the list is not an int"); - return NULL; + return nullptr; } // Sanity checks done! @@ -1274,7 +766,7 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniformiv, "setUniformiv(uniform_name, (list2 o { int array2[2] = {array_data[0], array_data[1]}; #ifdef SORT_UNIFORMS - SetUniformiv(loc, BL_Uniform::UNI_INT2, array2, sizeof(int) * 2); + SetUniformiv(loc, RAS_Uniform::UNI_INT2, array2, sizeof(int) * 2, 1); #else SetUniform(loc, array2, 2); #endif @@ -1285,7 +777,7 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniformiv, "setUniformiv(uniform_name, (list2 o { int array3[3] = {array_data[0], array_data[1], array_data[2]}; #ifdef SORT_UNIFORMS - SetUniformiv(loc, BL_Uniform::UNI_INT3, array3, sizeof(int) * 3); + SetUniformiv(loc, RAS_Uniform::UNI_INT3, array3, sizeof(int) * 3, 1); #else SetUniform(loc, array3, 3); #endif @@ -1296,7 +788,7 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniformiv, "setUniformiv(uniform_name, (list2 o { int array4[4] = {array_data[0], array_data[1], array_data[2], array_data[3]}; #ifdef SORT_UNIFORMS - SetUniformiv(loc, BL_Uniform::UNI_INT4, array4, sizeof(int) * 4); + SetUniformiv(loc, RAS_Uniform::UNI_INT4, array4, sizeof(int) * 4, 1); #else SetUniform(loc, array4, 4); #endif @@ -1308,33 +800,26 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniformiv, "setUniformiv(uniform_name, (list2 o PyErr_SetString(PyExc_TypeError, "shader.setUniformiv(...): BL_Shader, second argument, invalid list size, expected an int " "list between 2 and 4"); - return NULL; + return nullptr; break; } } Py_RETURN_NONE; } -KX_PYMETHODDEF_DOC(BL_Shader, setUniformMatrix4, - "setUniformMatrix4(uniform_name, mat-4x4, transpose(row-major=true, col-major=false)") +EXP_PYMETHODDEF_DOC(BL_Shader, setUniformMatrix4, + "setUniformMatrix4(uniform_name, mat-4x4, transpose(row-major=true, col-major=false)") { - if (mError) { + if (!m_shader) { Py_RETURN_NONE; } - float matr[16] = { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - }; - const char *uniform; - PyObject *matrix = NULL; + PyObject *matrix = nullptr; int transp = 0; // python use column major by default, so no transpose.... if (!PyArg_ParseTuple(args, "sO|i:setUniformMatrix4", &uniform, &matrix, &transp)) { - return NULL; + return nullptr; } int loc = GetUniformLocation(uniform); @@ -1342,21 +827,20 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniformMatrix4, if (loc == -1) { PyErr_SetString(PyExc_TypeError, "shader.setUniformMatrix4(...): BL_Shader, first string argument is not a valid uniform value"); - return NULL; + return nullptr; } - MT_Matrix4x4 mat; + mt::mat4 mat; if (!PyMatTo(matrix, mat)) { PyErr_SetString(PyExc_TypeError, "shader.setUniformMatrix4(...): BL_Shader, second argument cannot be converted into a 4x4 matrix"); - return NULL; + return nullptr; } // Sanity checks done! #ifdef SORT_UNIFORMS - mat.getValue(matr); - SetUniformfv(loc, BL_Uniform::UNI_MAT4, matr, (sizeof(float) * 16), (transp != 0)); + SetUniformfv(loc, RAS_Uniform::UNI_MAT4, (float *)mat.Data(), (sizeof(float) * 16), 1, (transp != 0)); #else SetUniform(loc, mat, (transp != 0)); #endif @@ -1364,25 +848,19 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniformMatrix4, } -KX_PYMETHODDEF_DOC(BL_Shader, setUniformMatrix3, - "setUniformMatrix3(uniform_name, list[3x3], transpose(row-major=true, col-major=false)") +EXP_PYMETHODDEF_DOC(BL_Shader, setUniformMatrix3, + "setUniformMatrix3(uniform_name, list[3x3], transpose(row-major=true, col-major=false)") { - if (mError) { + if (!m_shader) { Py_RETURN_NONE; } - float matr[9] = { - 1.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 1.0f, - }; - const char *uniform; - PyObject *matrix = NULL; + PyObject *matrix = nullptr; int transp = 0; // python use column major by default, so no transpose.... if (!PyArg_ParseTuple(args, "sO|i:setUniformMatrix3", &uniform, &matrix, &transp)) { - return NULL; + return nullptr; } int loc = GetUniformLocation(uniform); @@ -1390,55 +868,67 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniformMatrix3, if (loc == -1) { PyErr_SetString(PyExc_TypeError, "shader.setUniformMatrix3(...): BL_Shader, first string argument is not a valid uniform value"); - return NULL; + return nullptr; } - MT_Matrix3x3 mat; + mt::mat3 mat; if (!PyMatTo(matrix, mat)) { PyErr_SetString(PyExc_TypeError, "shader.setUniformMatrix3(...): BL_Shader, second argument cannot be converted into a 3x3 matrix"); - return NULL; + return nullptr; } #ifdef SORT_UNIFORMS - mat.getValue3x3(matr); - SetUniformfv(loc, BL_Uniform::UNI_MAT3, matr, (sizeof(float) * 9), (transp != 0)); + float matr[9]; + mat.Pack(matr); + SetUniformfv(loc, RAS_Uniform::UNI_MAT3, matr, (sizeof(float) * 9), 1, (transp != 0)); #else SetUniform(loc, mat, (transp != 0)); #endif Py_RETURN_NONE; } -KX_PYMETHODDEF_DOC(BL_Shader, setAttrib, "setAttrib(enum)") +EXP_PYMETHODDEF_DOC(BL_Shader, setAttrib, "setAttrib(enum)") { - if (mError) { + if (!m_shader) { Py_RETURN_NONE; } int attr = 0; if (!PyArg_ParseTuple(args, "i:setAttrib", &attr)) { - return NULL; + return nullptr; } attr = SHD_TANGENT; // user input is ignored for now, there is only 1 attr - if (mShader == 0) { + if (!m_shader) { PyErr_SetString(PyExc_ValueError, "shader.setAttrib() BL_Shader, invalid shader object"); - return NULL; + return nullptr; + } + + // Avoid redundant attributes reconstruction. + if (attr == m_attr) { + Py_RETURN_NONE; } - mAttr = attr; - glUseProgramObjectARB(mShader); - glBindAttribLocationARB(mShader, mAttr, "Tangent"); + m_attr = (AttribTypes)attr; + + // Can be null in case of filter shaders. + if (m_materialUpdateServer) { + // Notify all clients tracking this shader that attributes are modified. + m_materialUpdateServer->NotifyUpdate(RAS_IMaterial::ATTRIBUTES_MODIFIED); + } + + BindAttribute("Tangent", m_attr); Py_RETURN_NONE; } -KX_PYMETHODDEF_DOC(BL_Shader, setUniformDef, "setUniformDef(name, enum)") +EXP_PYMETHODDEF_DOC(BL_Shader, setUniformDef, "setUniformDef(name, enum)") { - if (mError) { + if (!m_shader) { Py_RETURN_NONE; } @@ -1449,30 +939,26 @@ KX_PYMETHODDEF_DOC(BL_Shader, setUniformDef, "setUniformDef(name, enum)") if (loc != -1) { bool defined = false; - BL_UniformVecDef::iterator it = mPreDef.begin(); - while (it != mPreDef.end()) { - if ((*it)->mLoc == loc) { + for (RAS_DefUniform *defuni : m_preDef) { + if (defuni->m_loc == loc) { defined = true; break; } - it++; } if (defined) { Py_RETURN_NONE; } - BL_DefUniform *uni = new BL_DefUniform(); - uni->mLoc = loc; - uni->mType = nloc; - uni->mFlag = 0; - mPreDef.push_back(uni); + RAS_DefUniform *uni = new RAS_DefUniform(); + uni->m_loc = loc; + uni->m_type = nloc; + uni->m_flag = 0; + m_preDef.push_back(uni); Py_RETURN_NONE; } } - return NULL; + return nullptr; } #endif // WITH_PYTHON - -// eof diff --git a/source/gameengine/Ketsji/BL_Shader.h b/source/gameengine/Ketsji/BL_Shader.h index 5de715d67d4e..9d2d3c4af46d 100644 --- a/source/gameengine/Ketsji/BL_Shader.h +++ b/source/gameengine/Ketsji/BL_Shader.h @@ -6,235 +6,101 @@ #ifndef __BL_SHADER_H__ #define __BL_SHADER_H__ -#include "EXP_PyObjectPlus.h" -#include "BL_Material.h" -#include "BL_Texture.h" -#include "MT_Matrix4x4.h" -#include "MT_Matrix3x3.h" -#include "MT_Tuple2.h" -#include "MT_Tuple3.h" -#include "MT_Tuple4.h" - -/** - * BL_Sampler - * Sampler access - */ -class BL_Sampler -{ -public: - BL_Sampler() - : - mLoc(-1) - { - } +#include "RAS_Shader.h" +#include "RAS_Texture.h" // For RAS_Texture::MaxUnits. +#include "RAS_AttributeArray.h" // For RAS_AttributeArray::AttribList. +#include "RAS_Mesh.h" // For RAS_Mesh::LayersInfo. - int mLoc; // Sampler location +#include "EXP_Value.h" -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_Sampler") -#endif -}; +#include "CM_Update.h" -/** - * BL_Uniform - * uniform storage - */ -class BL_Uniform +class RAS_MeshSlot; +class RAS_IMaterial; + +class BL_Shader : public EXP_Value, public virtual RAS_Shader { -private: - int mLoc; // Uniform location - void *mData; // Memory allocated for variable - bool mDirty; // Caching variable - int mType; // Enum UniformTypes - bool mTranspose; // Transpose matrices - const int mDataLen; // Length of our data + Py_Header public: - BL_Uniform(int data_size); - ~BL_Uniform(); - - enum UniformTypes { - UNI_NONE = 0, - UNI_INT, - UNI_FLOAT, - UNI_INT2, - UNI_FLOAT2, - UNI_INT3, - UNI_FLOAT3, - UNI_INT4, - UNI_FLOAT4, - UNI_MAT3, - UNI_MAT4, - UNI_FLOAT_EYE, - UNI_MAX + enum CallbacksType { + CALLBACKS_BIND = 0, + CALLBACKS_OBJECT, + CALLBACKS_MAX }; - bool Apply(class BL_Shader *shader); - void SetData(int location, int type, bool transpose = false); - int GetLocation() { return mLoc; } - void *getData() { return mData; } - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_Uniform") -#endif -}; - -/** - * BL_DefUniform - * pre defined uniform storage - */ -class BL_DefUniform -{ -public: - BL_DefUniform() - : - mType(0), - mLoc(0), - mFlag(0) - { - } - - int mType; - int mLoc; - unsigned int mFlag; - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_DefUniform") -#endif -}; + enum AttribTypes { + SHD_NONE = 0, + SHD_TANGENT = 1 + }; -/** - * BL_Shader - * shader access - */ -class BL_Shader : public PyObjectPlus -{ - Py_Header private: - typedef std::vector BL_UniformVec; - typedef std::vector BL_UniformVecDef; - - unsigned int mShader; // Shader object - int mPass; // 1.. unused - bool mOk; // Valid and ok - bool mUse; - //BL_Sampler mSampler[MAXTEX]; // Number of samplers - int mAttr; // Tangent attribute - const char *vertProg; // Vertex program string - const char *fragProg; // Fragment program string - bool mError; - bool mDirty; - - // Stored uniform variables - BL_UniformVec mUniforms; - BL_UniformVecDef mPreDef; - - // Compiles and links the shader - bool LinkProgram(); +#ifdef WITH_PYTHON + PyObject *m_callbacks[CALLBACKS_MAX]; +#endif // WITH_PYTHON - // search by location - BL_Uniform *FindUniform(const int location); + AttribTypes m_attr; + CM_UpdateServer *m_materialUpdateServer; - // clears uniform data - void ClearUniforms(); + virtual bool LinkProgram(); public: - BL_Shader(); + BL_Shader(CM_UpdateServer *materialUpdateServer); virtual ~BL_Shader(); - // Unused for now tangent is set as tex coords - enum AttribTypes { - SHD_TANGENT = 1 - }; + virtual std::string GetName(); + virtual std::string GetText(); - enum GenType { - MODELVIEWMATRIX, - MODELVIEWMATRIX_TRANSPOSE, - MODELVIEWMATRIX_INVERSE, - MODELVIEWMATRIX_INVERSETRANSPOSE, - MODELMATRIX, - MODELMATRIX_TRANSPOSE, - MODELMATRIX_INVERSE, - MODELMATRIX_INVERSETRANSPOSE, - VIEWMATRIX, - VIEWMATRIX_TRANSPOSE, - VIEWMATRIX_INVERSE, - VIEWMATRIX_INVERSETRANSPOSE, - CAM_POS, - CONSTANT_TIMER - }; +#ifdef WITH_PYTHON + PyObject *GetCallbacks(CallbacksType type); + void SetCallbacks(CallbacksType type, PyObject *callbacks); +#endif // WITH_PYTHON + + RAS_AttributeArray::AttribList GetAttribs(const RAS_Mesh::LayersInfo& layersInfo, + RAS_Texture *const textures[RAS_Texture::MaxUnits]) const; - const char *GetVertPtr(); - const char *GetFragPtr(); - void SetVertPtr(char *vert); - void SetFragPtr(char *frag); - int getNumPass() { return mPass; } - bool GetError() { return mError; } - - //const BL_Sampler *GetSampler(int i); - void SetSampler(int loc, int unit); - bool Ok() const; - unsigned int GetProg(); - void SetProg(bool enable); - int GetAttribute() { return mAttr; } - - // Apply methods : sets colected uniforms - void ApplyShader(); - void UnloadShader(); - - // Update predefined uniforms each render call - void Update(const class RAS_MeshSlot &ms, class RAS_IRasterizer *rasty); - - // Set sampler units (copied) - //void InitializeSampler(int unit, BL_Texture *texture); - void SetUniformfv(int location, int type, float *param, int size, bool transpose = false); - void SetUniformiv(int location, int type, int *param, int size, bool transpose = false); - int GetAttribLocation(const char *name); - void BindAttribute(const char *attr, int loc); - int GetUniformLocation(const char *name); - void SetUniform(int uniform, const MT_Tuple2 &vec); - void SetUniform(int uniform, const MT_Tuple3 &vec); - void SetUniform(int uniform, const MT_Tuple4 &vec); - void SetUniform(int uniform, const MT_Matrix4x4 &vec, bool transpose = false); - void SetUniform(int uniform, const MT_Matrix3x3 &vec, bool transpose = false); - void SetUniform(int uniform, const float &val); - void SetUniform(int uniform, const float *val, int len); - void SetUniform(int uniform, const int *val, int len); - void SetUniform(int uniform, const unsigned int &val); - void SetUniform(int uniform, const int val); + void BindProg(); + + /** Update the uniform shader for the current rendered mesh user (= object). + * The python callbacks are executed in this function and at the end + * RAS_Shader::Update(rasty, mat) is called. + */ + void Update(RAS_Rasterizer *rasty, RAS_MeshUser *meshUser); // Python interface #ifdef WITH_PYTHON - virtual PyObject *py_repr() - { - return PyUnicode_FromFormat("BL_Shader\n\tvertex shader:%s\n\n\tfragment shader%s\n\n", vertProg, fragProg); - } + + static PyObject *pyattr_get_enabled(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_enabled(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_callbacks(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_callbacks(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); // ----------------------------------- - KX_PYMETHOD_DOC(BL_Shader, setSource); - KX_PYMETHOD_DOC(BL_Shader, delSource); - KX_PYMETHOD_DOC(BL_Shader, getVertexProg); - KX_PYMETHOD_DOC(BL_Shader, getFragmentProg); - KX_PYMETHOD_DOC(BL_Shader, setNumberOfPasses); - KX_PYMETHOD_DOC(BL_Shader, isValid); - KX_PYMETHOD_DOC(BL_Shader, validate); + EXP_PYMETHOD_DOC(BL_Shader, setSource); + EXP_PYMETHOD_DOC(BL_Shader, setSourceList); + EXP_PYMETHOD_DOC(BL_Shader, delSource); + EXP_PYMETHOD_DOC(BL_Shader, getVertexProg); + EXP_PYMETHOD_DOC(BL_Shader, getFragmentProg); + EXP_PYMETHOD_DOC(BL_Shader, setNumberOfPasses); + EXP_PYMETHOD_DOC(BL_Shader, isValid); + EXP_PYMETHOD_DOC(BL_Shader, validate); // ----------------------------------- - KX_PYMETHOD_DOC(BL_Shader, setUniform4f); - KX_PYMETHOD_DOC(BL_Shader, setUniform3f); - KX_PYMETHOD_DOC(BL_Shader, setUniform2f); - KX_PYMETHOD_DOC(BL_Shader, setUniform1f); - KX_PYMETHOD_DOC(BL_Shader, setUniform4i); - KX_PYMETHOD_DOC(BL_Shader, setUniform3i); - KX_PYMETHOD_DOC(BL_Shader, setUniform2i); - KX_PYMETHOD_DOC(BL_Shader, setUniform1i); - KX_PYMETHOD_DOC(BL_Shader, setUniformEyef); - KX_PYMETHOD_DOC(BL_Shader, setUniformfv); - KX_PYMETHOD_DOC(BL_Shader, setUniformiv); - KX_PYMETHOD_DOC(BL_Shader, setUniformMatrix4); - KX_PYMETHOD_DOC(BL_Shader, setUniformMatrix3); - KX_PYMETHOD_DOC(BL_Shader, setUniformDef); - KX_PYMETHOD_DOC(BL_Shader, setAttrib); - KX_PYMETHOD_DOC(BL_Shader, setSampler); + EXP_PYMETHOD_DOC(BL_Shader, setUniform4f); + EXP_PYMETHOD_DOC(BL_Shader, setUniform3f); + EXP_PYMETHOD_DOC(BL_Shader, setUniform2f); + EXP_PYMETHOD_DOC(BL_Shader, setUniform1f); + EXP_PYMETHOD_DOC(BL_Shader, setUniform4i); + EXP_PYMETHOD_DOC(BL_Shader, setUniform3i); + EXP_PYMETHOD_DOC(BL_Shader, setUniform2i); + EXP_PYMETHOD_DOC(BL_Shader, setUniform1i); + EXP_PYMETHOD_DOC(BL_Shader, setUniformEyef); + EXP_PYMETHOD_DOC(BL_Shader, setUniformfv); + EXP_PYMETHOD_DOC(BL_Shader, setUniformiv); + EXP_PYMETHOD_DOC(BL_Shader, setUniformMatrix4); + EXP_PYMETHOD_DOC(BL_Shader, setUniformMatrix3); + EXP_PYMETHOD_DOC(BL_Shader, setUniformDef); + EXP_PYMETHOD_DOC(BL_Shader, setAttrib); + EXP_PYMETHOD_DOC(BL_Shader, setSampler); #endif }; diff --git a/source/gameengine/Ketsji/BL_Texture.cpp b/source/gameengine/Ketsji/BL_Texture.cpp index 75d559a83aa4..280ee933242b 100644 --- a/source/gameengine/Ketsji/BL_Texture.cpp +++ b/source/gameengine/Ketsji/BL_Texture.cpp @@ -22,737 +22,713 @@ * \ingroup ketsji */ -#include "GPU_glew.h" - -#include -#include -#include - -#include "BL_Material.h" #include "BL_Texture.h" -#include "MT_assert.h" +#include "KX_TextureRenderer.h" #include "DNA_texture_types.h" -#include "DNA_image_types.h" -#include "IMB_imbuf_types.h" -#include "BKE_image.h" -#include "BLI_blenlib.h" - -#include "RAS_ICanvas.h" -#include "RAS_Rect.h" -#include "KX_GameObject.h" +#include "GPU_texture.h" +#include "GPU_draw.h" -#define spit(x) std::cout << x << std::endl; +#include "KX_PyMath.h" -#include "MEM_guardedalloc.h" -#include "GPU_draw.h" -#include "GPU_extensions.h" +#include "BLI_math.h" -extern "C" { - // envmaps - #include "IMB_imbuf.h" - void my_envmap_split_ima(EnvMap *env, ImBuf *ibuf); - void my_free_envmapdata(EnvMap *env); +BL_Texture::BL_Texture(MTex *mtex) + :EXP_Value(), + m_isCubeMap(false), + m_mtex(mtex), + m_gpuTex(nullptr) +{ + Tex *tex = m_mtex->tex; + EnvMap *env = tex->env; + m_isCubeMap = (env && tex->type == TEX_ENVMAP && + (env->stype == ENV_LOAD || + (env->stype == ENV_REALT && env->type == ENV_CUBE))); + + Image *ima = tex->ima; + ImageUser& iuser = tex->iuser; + const int gltextarget = m_isCubeMap ? GetCubeMapTextureType() : GetTexture2DType(); + + m_gpuTex = (ima ? GPU_texture_from_blender(ima, &iuser, gltextarget, false, 0.0, true) : nullptr); + + // Initialize saved data. + m_name = std::string(m_mtex->tex->id.name + 2); + m_savedData.colintensfac = m_mtex->difffac; + m_savedData.colfac = m_mtex->colfac; + m_savedData.alphafac = m_mtex->alphafac; + m_savedData.specintensfac = m_mtex->specfac; + m_savedData.speccolorfac = m_mtex->colspecfac; + m_savedData.hardnessfac = m_mtex->hardfac; + m_savedData.emitfac = m_mtex->emitfac; + m_savedData.mirrorfac = m_mtex->mirrfac; + m_savedData.normalfac = m_mtex->norfac; + m_savedData.parallaxbumpfac = m_mtex->parallaxbumpsc; + m_savedData.parallaxstepfac = m_mtex->parallaxsteps; + m_savedData.lodbias = m_mtex->lodbias; + m_savedData.ior = m_mtex->ior; + m_savedData.ratio = m_mtex->refrratio; + m_savedData.uvrot = m_mtex->rot; + copy_v3_v3(m_savedData.uvoffset, m_mtex->ofs); + copy_v3_v3(m_savedData.uvsize, m_mtex->size); + + if (m_gpuTex) { + m_bindCode = GPU_texture_opengl_bindcode(m_gpuTex); + m_savedData.bindcode = m_bindCode; + GPU_texture_ref(m_gpuTex); + } } -// (n&(n-1)) zeros the least significant bit of n -static int is_power_of_2_i(int num) +BL_Texture::~BL_Texture() { - return ((num)&(num-1))==0; + // Restore saved data. + m_mtex->difffac = m_savedData.colintensfac; + m_mtex->colfac = m_savedData.colfac; + m_mtex->alphafac = m_savedData.alphafac; + m_mtex->specfac = m_savedData.specintensfac; + m_mtex->colspecfac = m_savedData.speccolorfac; + m_mtex->hardfac = m_savedData.hardnessfac; + m_mtex->emitfac = m_savedData.emitfac; + m_mtex->mirrfac = m_savedData.mirrorfac; + m_mtex->norfac = m_savedData.normalfac; + m_mtex->parallaxbumpsc = m_savedData.parallaxbumpfac; + m_mtex->parallaxsteps = m_savedData.parallaxstepfac; + m_mtex->lodbias = m_savedData.lodbias; + m_mtex->ior = m_savedData.ior; + m_mtex->refrratio = m_savedData.ratio; + m_mtex->rot = m_savedData.uvrot; + copy_v3_v3(m_mtex->ofs, m_savedData.uvoffset); + copy_v3_v3(m_mtex->size, m_savedData.uvsize); + + if (m_gpuTex) { + GPU_texture_set_opengl_bindcode(m_gpuTex, m_savedData.bindcode); + GPU_texture_free(m_gpuTex); + } } -static int power_of_2_min_i(int num) + +void BL_Texture::CheckValidTexture() { - while (!is_power_of_2_i(num)) - num= num&(num-1); - return num; + if (!m_gpuTex) { + return; + } + + /* Test if the gpu texture is the same in the image which own it, if it's not + * the case then it means that no materials use it anymore and that we have to + * get a pointer of the updated gpu texture used by materials. + * The gpu texture in the image can be nullptr or an already different loaded + * gpu texture. In both cases we call GPU_texture_from_blender. + */ + int target = m_isCubeMap ? TEXTARGET_TEXTURE_CUBE_MAP : TEXTARGET_TEXTURE_2D; + if (m_gpuTex != m_mtex->tex->ima->gputexture[target]) { + Tex *tex = m_mtex->tex; + Image *ima = tex->ima; + ImageUser& iuser = tex->iuser; + + const int gltextarget = m_isCubeMap ? GetCubeMapTextureType() : GetTexture2DType(); + + // Restore gpu texture original bind cdoe to make sure we will delete the right opengl texture. + GPU_texture_set_opengl_bindcode(m_gpuTex, m_savedData.bindcode); + GPU_texture_free(m_gpuTex); + + m_gpuTex = (ima ? GPU_texture_from_blender(ima, &iuser, gltextarget, false, 0.0, true) : nullptr); + + if (m_gpuTex) { + int bindCode = GPU_texture_opengl_bindcode(m_gpuTex); + // If our bind code was the same as the previous gpu texture bind code, then we update it to the new bind code. + if (m_bindCode == m_savedData.bindcode) { + m_bindCode = bindCode; + } + m_savedData.bindcode = bindCode; + GPU_texture_ref(m_gpuTex); + } + } } -// Place holder for a full texture manager -class BL_TextureObject +bool BL_Texture::Ok() const { -public: - unsigned int gl_texture; - void* ref_buffer; -}; - -typedef std::map BL_TextureMap; -static BL_TextureMap g_textureManager; -static GLint g_max_units = -1; + return (m_gpuTex != nullptr); +} +bool BL_Texture::IsCubeMap() const +{ + return m_isCubeMap; +} -BL_Texture::BL_Texture() -: mTexture(0), - mOk(0), - mNeedsDeleted(0), - mType(0), - mUnit(0), - mEnvState(0) +MTex *BL_Texture::GetMTex() const { - // -- + return m_mtex; } -BL_Texture::~BL_Texture() +Tex *BL_Texture::GetTex() const { - // -- + return m_mtex->tex; } -void BL_Texture::DeleteTex() +Image *BL_Texture::GetImage() const { - if ( mNeedsDeleted ) { - glDeleteTextures(1, (GLuint*)&mTexture); - mNeedsDeleted = 0; - mOk = 0; - } + return m_mtex->tex->ima; +} - if (mEnvState) { - glDeleteLists((GLuint)mEnvState, 1); - mEnvState =0; - } +GPUTexture *BL_Texture::GetGPUTexture() const +{ + return m_gpuTex; +} - if (mDisableState) { - glDeleteLists((GLuint)mDisableState, 1); - mDisableState =0; - } - g_textureManager.clear(); +unsigned int BL_Texture::GetTextureType() +{ + return GPU_texture_target(m_gpuTex); } +void BL_Texture::ActivateTexture(int unit) +{ + /* Since GPUTexture can be shared between material textures (MTex), + * we should reapply the bindcode in case of VideoTexture owned texture. + * Without that every material that use this GPUTexture will then use + * the VideoTexture texture, it's not wanted. */ + GPU_texture_set_opengl_bindcode(m_gpuTex, m_bindCode); + GPU_texture_bind(m_gpuTex, unit); +} -bool BL_Texture::InitFromImage(int unit, Image *img, bool mipmap) +void BL_Texture::DisableTexture() { + GPU_texture_unbind(m_gpuTex); +} - ImBuf *ibuf; - if (!img || img->ok==0) - { - mOk = false; - return mOk; - } +// stuff for cvalue related things +std::string BL_Texture::GetName() +{ + return RAS_Texture::GetName(); +} - ibuf= BKE_image_acquire_ibuf(img, NULL, NULL); - if (ibuf==NULL) - { - img->ok = 0; - mOk = false; - return mOk; - } +#ifdef WITH_PYTHON + +PyTypeObject BL_Texture::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "BL_Texture", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &EXP_Value::Type, + 0, 0, 0, 0, 0, 0, + py_base_new +}; - mipmap = mipmap && GPU_get_mipmap(); +PyMethodDef BL_Texture::Methods[] = { + { nullptr, nullptr } //Sentinel +}; - mTexture = img->bindcode[TEXTARGET_TEXTURE_2D]; - mType = GL_TEXTURE_2D; - mUnit = unit; +PyAttributeDef BL_Texture::Attributes[] = { + EXP_PYATTRIBUTE_RW_FUNCTION("diffuseIntensity", BL_Texture, pyattr_get_diffuse_intensity, pyattr_set_diffuse_intensity), + EXP_PYATTRIBUTE_RW_FUNCTION("diffuseFactor", BL_Texture, pyattr_get_diffuse_factor, pyattr_set_diffuse_factor), + EXP_PYATTRIBUTE_RW_FUNCTION("alpha", BL_Texture, pyattr_get_alpha, pyattr_set_alpha), + EXP_PYATTRIBUTE_RW_FUNCTION("specularIntensity", BL_Texture, pyattr_get_specular_intensity, pyattr_set_specular_intensity), + EXP_PYATTRIBUTE_RW_FUNCTION("specularFactor", BL_Texture, pyattr_get_specular_factor, pyattr_set_specular_factor), + EXP_PYATTRIBUTE_RW_FUNCTION("hardness", BL_Texture, pyattr_get_hardness, pyattr_set_hardness), + EXP_PYATTRIBUTE_RW_FUNCTION("emit", BL_Texture, pyattr_get_emit, pyattr_set_emit), + EXP_PYATTRIBUTE_RW_FUNCTION("mirror", BL_Texture, pyattr_get_mirror, pyattr_set_mirror), + EXP_PYATTRIBUTE_RW_FUNCTION("normal", BL_Texture, pyattr_get_normal, pyattr_set_normal), + EXP_PYATTRIBUTE_RW_FUNCTION("parallaxBump", BL_Texture, pyattr_get_parallax_bump, pyattr_set_parallax_bump), + EXP_PYATTRIBUTE_RW_FUNCTION("parallaxStep", BL_Texture, pyattr_get_parallax_step, pyattr_set_parallax_step), + EXP_PYATTRIBUTE_RW_FUNCTION("lodBias", BL_Texture, pyattr_get_lod_bias, pyattr_set_lod_bias), + EXP_PYATTRIBUTE_RW_FUNCTION("bindCode", BL_Texture, pyattr_get_bind_code, pyattr_set_bind_code), + EXP_PYATTRIBUTE_RO_FUNCTION("renderer", BL_Texture, pyattr_get_renderer), + EXP_PYATTRIBUTE_RW_FUNCTION("ior", BL_Texture, pyattr_get_ior, pyattr_set_ior), + EXP_PYATTRIBUTE_RW_FUNCTION("refractionRatio", BL_Texture, pyattr_get_refraction_ratio, pyattr_set_refraction_ratio), + EXP_PYATTRIBUTE_RW_FUNCTION("uvRotation", BL_Texture, pyattr_get_uv_rotation, pyattr_set_uv_rotation), + EXP_PYATTRIBUTE_RW_FUNCTION("uvOffset", BL_Texture, pyattr_get_uv_offset, pyattr_set_uv_offset), + EXP_PYATTRIBUTE_RW_FUNCTION("uvSize", BL_Texture, pyattr_get_uv_size, pyattr_set_uv_size), + EXP_PYATTRIBUTE_NULL //Sentinel +}; - ActivateUnit(mUnit); +PyObject *BL_Texture::pyattr_get_diffuse_intensity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + BL_Texture *self = static_cast(self_v); + return PyFloat_FromDouble(self->GetMTex()->difffac); +} - if (mTexture != 0) { - glBindTexture(GL_TEXTURE_2D, mTexture ); - Validate(); - BKE_image_release_ibuf(img, ibuf, NULL); - return mOk; - } +int BL_Texture::pyattr_set_diffuse_intensity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_Texture *self = static_cast(self_v); + float val = PyFloat_AsDouble(value); - // look for an existing gl image - BL_TextureMap::iterator mapLook = g_textureManager.find(img->id.name); - if (mapLook != g_textureManager.end()) - { - if (mapLook->second.gl_texture != 0) - { - mTexture = mapLook->second.gl_texture; - glBindTexture(GL_TEXTURE_2D, mTexture); - mOk = IsValid(); - BKE_image_release_ibuf(img, ibuf, NULL); - return mOk; - } + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "texture.%s = float: BL_Texture, expected a float", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; } - mNeedsDeleted = 1; - glGenTextures(1, (GLuint*)&mTexture); - -#ifdef WITH_DDS - if (ibuf->ftype == IMB_FTYPE_DDS) - InitGLCompressedTex(ibuf, mipmap); - else - InitGLTex(ibuf->rect, ibuf->x, ibuf->y, mipmap); -#else - InitGLTex(ibuf->rect, ibuf->x, ibuf->y, mipmap); -#endif - - // track created units - BL_TextureObject obj; - obj.gl_texture = mTexture; - obj.ref_buffer = img; - g_textureManager.insert(std::pair((char*)img->id.name, obj)); - - - glDisable(GL_TEXTURE_2D); - ActivateUnit(0); - Validate(); - - BKE_image_release_ibuf(img, ibuf, NULL); + self->GetMTex()->difffac = val; + return PY_SET_ATTR_SUCCESS; +} - return mOk; +PyObject *BL_Texture::pyattr_get_diffuse_factor(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + BL_Texture *self = static_cast(self_v); + return PyFloat_FromDouble(self->GetMTex()->colfac); } -void BL_Texture::InitGLTex(unsigned int *pix,int x,int y,bool mipmap) +int BL_Texture::pyattr_set_diffuse_factor(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - if (!GPU_full_non_power_of_two_support() && (!is_power_of_2_i(x) || !is_power_of_2_i(y)) ) { - InitNonPow2Tex(pix, x,y,mipmap); - return; - } + BL_Texture *self = static_cast(self_v); + float val = PyFloat_AsDouble(value); - glBindTexture(GL_TEXTURE_2D, mTexture ); - if ( mipmap ) { - int i; - ImBuf *ibuf; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "texture.%s = float: BL_Texture, expected a float", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; + } - ibuf = IMB_allocFromBuffer(pix, NULL, x, y); + self->GetMTex()->colfac = val; + return PY_SET_ATTR_SUCCESS; +} - IMB_makemipmap(ibuf, true); +PyObject *BL_Texture::pyattr_get_alpha(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + BL_Texture *self = static_cast(self_v); + return PyFloat_FromDouble(self->GetMTex()->alphafac); +} - for (i = 0; i < ibuf->miptot; i++) { - ImBuf *mip = IMB_getmipmap(ibuf, i); +int BL_Texture::pyattr_set_alpha(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_Texture *self = static_cast(self_v); + float val = PyFloat_AsDouble(value); - glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA, mip->x, mip->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip->rect); - } - IMB_freeImBuf(ibuf); - } - else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, pix ); + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "texture.%s = float: BL_Texture, expected a float", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; } - if (GLEW_EXT_texture_filter_anisotropic) - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic()); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + self->GetMTex()->alphafac = val; + return PY_SET_ATTR_SUCCESS; } -void BL_Texture::InitGLCompressedTex(ImBuf *ibuf, bool mipmap) +PyObject *BL_Texture::pyattr_get_specular_intensity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { -#ifndef WITH_DDS - // Fall back to uncompressed if DDS isn't enabled - InitGLTex(ibuf->rect, ibuf->x, ibuf->y, mipmap); - return; -#else - glBindTexture(GL_TEXTURE_2D, mTexture); - - if (GPU_upload_dxt_texture(ibuf) == 0) { - InitGLTex(ibuf->rect, ibuf->x, ibuf->y, mipmap); - return; - } -#endif + BL_Texture *self = static_cast(self_v); + return PyFloat_FromDouble(self->GetMTex()->specfac); } -void BL_Texture::InitNonPow2Tex(unsigned int *pix,int x,int y,bool mipmap) +int BL_Texture::pyattr_set_specular_intensity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - int nx= power_of_2_min_i(x); - int ny= power_of_2_min_i(y); - - ImBuf *ibuf = IMB_allocFromBuffer(pix, NULL, x, y); - IMB_scaleImBuf(ibuf, nx, ny); + BL_Texture *self = static_cast(self_v); + float val = PyFloat_AsDouble(value); - glBindTexture(GL_TEXTURE_2D, mTexture ); + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "texture.%s = float: BL_Texture, expected a float", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; + } - if ( mipmap ) { - int i; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + self->GetMTex()->specfac = val; + return PY_SET_ATTR_SUCCESS; +} - IMB_makemipmap(ibuf, true); +PyObject *BL_Texture::pyattr_get_specular_factor(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + BL_Texture *self = static_cast(self_v); + return PyFloat_FromDouble(self->GetMTex()->colspecfac); +} - for (i = 0; i < ibuf->miptot; i++) { - ImBuf *mip = IMB_getmipmap(ibuf, i); +int BL_Texture::pyattr_set_specular_factor(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_Texture *self = static_cast(self_v); + float val = PyFloat_AsDouble(value); - glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA, mip->x, mip->y, 0, GL_RGBA, GL_UNSIGNED_BYTE, mip->rect); - } - } - else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nx, ny, 0, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect ); + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "texture.%s = float: BL_Texture, expected a float", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; } - if (GLEW_EXT_texture_filter_anisotropic) - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GPU_get_anisotropic()); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - IMB_freeImBuf(ibuf); + self->GetMTex()->colspecfac = val; + return PY_SET_ATTR_SUCCESS; } +PyObject *BL_Texture::pyattr_get_hardness(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + BL_Texture *self = static_cast(self_v); + return PyFloat_FromDouble(self->GetMTex()->hardfac); +} -bool BL_Texture::InitCubeMap(int unit, EnvMap *cubemap) +int BL_Texture::pyattr_set_hardness(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - if (!GLEW_ARB_texture_cube_map) - { - spit("cubemaps not supported"); - mOk = false; - return mOk; - } - else if (!cubemap || cubemap->ima->ok==0) - { - mOk = false; - return mOk; - } + BL_Texture *self = static_cast(self_v); + float val = PyFloat_AsDouble(value); - ImBuf *ibuf= BKE_image_acquire_ibuf(cubemap->ima, NULL, NULL); - if (ibuf==0) - { - cubemap->ima->ok = 0; - mOk = false; - return mOk; + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "texture.%s = float: BL_Texture, expected a float", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; } - mNeedsDeleted = 1; - mType = GL_TEXTURE_CUBE_MAP_ARB; - mTexture = 0; - mUnit = unit; - - ActivateUnit(mUnit); + self->GetMTex()->hardfac = val; + return PY_SET_ATTR_SUCCESS; +} - BL_TextureMap::iterator mapLook = g_textureManager.find(cubemap->ima->id.name); - if (mapLook != g_textureManager.end()) - { - if (mapLook->second.gl_texture != 0 && mapLook->second.ref_buffer == cubemap->ima) - { - mTexture = mapLook->second.gl_texture; - glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mTexture); - mOk = IsValid(); - BKE_image_release_ibuf(cubemap->ima, ibuf, NULL); - return mOk; - } - } +PyObject *BL_Texture::pyattr_get_emit(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + BL_Texture *self = static_cast(self_v); + return PyFloat_FromDouble(self->GetMTex()->emitfac); +} +int BL_Texture::pyattr_set_emit(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_Texture *self = static_cast(self_v); + float val = PyFloat_AsDouble(value); - glGenTextures(1, (GLuint*)&mTexture); - glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mTexture); + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "texture.%s = float: BL_Texture, expected a float", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; + } + self->GetMTex()->emitfac = val; + return PY_SET_ATTR_SUCCESS; +} - // track created units - BL_TextureObject obj; - obj.gl_texture = mTexture; - obj.ref_buffer = cubemap->ima; - g_textureManager.insert(std::pair((char*)cubemap->ima->id.name, obj)); +PyObject *BL_Texture::pyattr_get_mirror(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + BL_Texture *self = static_cast(self_v); + return PyFloat_FromDouble(self->GetMTex()->mirrfac); +} +int BL_Texture::pyattr_set_mirror(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_Texture *self = static_cast(self_v); + float val = PyFloat_AsDouble(value); - bool needs_split = false; - if (!cubemap->cube[0]) - { - needs_split = true; - spit ("Re-Generating texture buffer"); + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "texture.%s = float: BL_Texture, expected a float", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; } - if (needs_split) - my_envmap_split_ima(cubemap, ibuf); + self->GetMTex()->mirrfac = val; + return PY_SET_ATTR_SUCCESS; +} +PyObject *BL_Texture::pyattr_get_normal(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + BL_Texture *self = static_cast(self_v); + return PyFloat_FromDouble(self->GetMTex()->norfac); +} - if (!is_power_of_2_i(cubemap->cube[0]->x) || !is_power_of_2_i(cubemap->cube[0]->y)) - { - spit("invalid envmap size please render with CubeRes @ power of two"); +int BL_Texture::pyattr_set_normal(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_Texture *self = static_cast(self_v); + float val = PyFloat_AsDouble(value); - my_free_envmapdata(cubemap); - mOk = false; - BKE_image_release_ibuf(cubemap->ima, ibuf, NULL); - return mOk; + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "texture.%s = float: BL_Texture, expected a float", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; } + self->GetMTex()->norfac = val; + return PY_SET_ATTR_SUCCESS; +} -#define SetCubeMapFace(face, num) \ - glTexImage2D(face, 0,GL_RGBA, \ - cubemap->cube[num]->x, \ - cubemap->cube[num]->y, \ - 0, GL_RGBA, GL_UNSIGNED_BYTE, \ - cubemap->cube[num]->rect) - - SetCubeMapFace(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, 5); - SetCubeMapFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, 3); - SetCubeMapFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, 0); - SetCubeMapFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, 1); - SetCubeMapFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, 2); - SetCubeMapFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, 4); - - glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - if (GLEW_VERSION_1_2) - glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE ); +PyObject *BL_Texture::pyattr_get_parallax_bump(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + BL_Texture *self = static_cast(self_v); + return PyFloat_FromDouble(self->GetMTex()->parallaxbumpsc); +} - if (needs_split) - my_free_envmapdata(cubemap); +int BL_Texture::pyattr_set_parallax_bump(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_Texture *self = static_cast(self_v); + float val = PyFloat_AsDouble(value); + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "texture.%s = float: BL_Texture, expected a float", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; + } + self->GetMTex()->parallaxbumpsc = val; + return PY_SET_ATTR_SUCCESS; +} - glDisable(GL_TEXTURE_CUBE_MAP_ARB); - ActivateUnit(0); +PyObject *BL_Texture::pyattr_get_parallax_step(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + BL_Texture *self = static_cast(self_v); + return PyFloat_FromDouble(self->GetMTex()->parallaxsteps); +} - mOk = IsValid(); +int BL_Texture::pyattr_set_parallax_step(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_Texture *self = static_cast(self_v); + float val = PyFloat_AsDouble(value); - BKE_image_release_ibuf(cubemap->ima, ibuf, NULL); + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "texture.%s = float: BL_Texture, expected a float", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; + } - return mOk; + self->GetMTex()->parallaxsteps = val; + return PY_SET_ATTR_SUCCESS; } -bool BL_Texture::IsValid() +PyObject *BL_Texture::pyattr_get_lod_bias(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - return (mTexture!= 0)?glIsTexture(mTexture)!=0:false; + BL_Texture *self = static_cast(self_v); + return PyFloat_FromDouble(self->GetMTex()->lodbias); } - -void BL_Texture::Validate() +int BL_Texture::pyattr_set_lod_bias(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - mOk = IsValid(); -} + BL_Texture *self = static_cast(self_v); + float val = PyFloat_AsDouble(value); + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "texture.%s = float: BL_Texture, expected a float", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; + } -bool BL_Texture::Ok() -{ - return (mTexture!= 0); + self->GetMTex()->lodbias = val; + return PY_SET_ATTR_SUCCESS; } - -unsigned int BL_Texture::GetTextureType() const +PyObject *BL_Texture::pyattr_get_bind_code(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - return mType; + BL_Texture *self = static_cast(self_v); + self->CheckValidTexture(); + return PyLong_FromLong(self->m_bindCode); } -int BL_Texture::GetMaxUnits() +int BL_Texture::pyattr_set_bind_code(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - if (g_max_units < 0) { - GLint unit = 0; - glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &unit); - g_max_units = (MAXTEX >= unit) ? unit : MAXTEX; + BL_Texture *self = static_cast(self_v); + int val = PyLong_AsLong(value); + + if (val < 0 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "texture.%s = int: BL_Texture, expected a unsigned int", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; } - return g_max_units; + self->m_bindCode = val; + return PY_SET_ATTR_SUCCESS; } -void BL_Texture::ActivateFirst() +PyObject *BL_Texture::pyattr_get_renderer(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - if (GLEW_ARB_multitexture) - glActiveTextureARB(GL_TEXTURE0_ARB); + BL_Texture *self = static_cast(self_v); + KX_TextureRenderer *renderer = static_cast(self->GetRenderer()); + if (renderer) { + return renderer->GetProxy(); + } + + Py_RETURN_NONE; } -void BL_Texture::ActivateUnit(int unit) +PyObject *BL_Texture::pyattr_get_ior(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - if (GLEW_ARB_multitexture) - if (unit <= MAXTEX) - glActiveTextureARB(GL_TEXTURE0_ARB+unit); + BL_Texture *self = static_cast(self_v); + return PyFloat_FromDouble(self->GetMTex()->ior); } - -void BL_Texture::DisableUnit() +int BL_Texture::pyattr_set_ior(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - if (GLEW_ARB_multitexture) - glActiveTextureARB(GL_TEXTURE0_ARB+mUnit); - - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); + BL_Texture *self = static_cast(self_v); + float val = PyFloat_AsDouble(value); - if (GLEW_ARB_texture_cube_map && glIsEnabled(GL_TEXTURE_CUBE_MAP_ARB)) - glDisable(GL_TEXTURE_CUBE_MAP_ARB); - else - { - if (glIsEnabled(GL_TEXTURE_2D)) - glDisable(GL_TEXTURE_2D); + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "texture.%s = float: BL_Texture, expected a float", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; } - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - glDisable(GL_TEXTURE_GEN_R); - glDisable(GL_TEXTURE_GEN_Q); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + CLAMP(val, 1.0, 50.0); + self->GetMTex()->ior = val; + return PY_SET_ATTR_SUCCESS; } +PyObject *BL_Texture::pyattr_get_refraction_ratio(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + BL_Texture *self = static_cast(self_v); + return PyFloat_FromDouble(self->GetMTex()->refrratio); +} -void BL_Texture::DisableAllTextures() +int BL_Texture::pyattr_set_refraction_ratio(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - for (int i=0; i(self_v); + float val = PyFloat_AsDouble(value); - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glDisable(GL_TEXTURE_2D); - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - glDisable(GL_TEXTURE_GEN_R); - glDisable(GL_TEXTURE_GEN_Q); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "texture.%s = float: BL_Texture, expected a float", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; } - - if (GLEW_ARB_multitexture) - glActiveTextureARB(GL_TEXTURE0_ARB); + CLAMP(val, 0.0, 1.0); + self->GetMTex()->refrratio = val; + return PY_SET_ATTR_SUCCESS; } - -void BL_Texture::ActivateTexture() +PyObject *BL_Texture::pyattr_get_uv_rotation(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - if (GLEW_ARB_multitexture) - glActiveTextureARB(GL_TEXTURE0_ARB+mUnit); + BL_Texture *self = static_cast(self_v); + return PyFloat_FromDouble(self->GetMTex()->rot); +} - if (mType == GL_TEXTURE_CUBE_MAP_ARB && GLEW_ARB_texture_cube_map) - { - glBindTexture( GL_TEXTURE_CUBE_MAP_ARB, mTexture ); - glEnable(GL_TEXTURE_CUBE_MAP_ARB); - } - else { - if (GLEW_ARB_texture_cube_map ) - glDisable(GL_TEXTURE_CUBE_MAP_ARB); +int BL_Texture::pyattr_set_uv_rotation(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_Texture *self = static_cast(self_v); + float val = PyFloat_AsDouble(value); - glBindTexture( GL_TEXTURE_2D, mTexture ); - glEnable(GL_TEXTURE_2D); + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "texture.%s = float: BL_Texture, expected a float", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; } + self->GetMTex()->rot = val; + return PY_SET_ATTR_SUCCESS; } -void BL_Texture::SetMapping(int mode) -{ +#ifdef USE_MATHUTILS - if (!(mode &USEREFL)) { - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - glDisable(GL_TEXTURE_GEN_R); - glDisable(GL_TEXTURE_GEN_Q); - return; - } +#define MATHUTILS_VEC_CB_TEXTURE_UV_OFFSET_VECTOR 1 +#define MATHUTILS_VEC_CB_TEXTURE_UV_SIZE_VECTOR 2 - if ( mType == GL_TEXTURE_CUBE_MAP_ARB && - GLEW_ARB_texture_cube_map && - mode &USEREFL) - { - glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB ); - glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB ); - glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB ); - - glEnable(GL_TEXTURE_GEN_S); - glEnable(GL_TEXTURE_GEN_T); - glEnable(GL_TEXTURE_GEN_R); - glDisable(GL_TEXTURE_GEN_Q); - return; - } - else - { - glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP ); - glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP ); - - glEnable(GL_TEXTURE_GEN_S); - glEnable(GL_TEXTURE_GEN_T); - glDisable(GL_TEXTURE_GEN_R); - glDisable(GL_TEXTURE_GEN_Q); +static unsigned char mathutils_bltexture_cb_index = -1; // Index for our callbacks + +static int mathutils_bltexture_generic_check(BaseMathObject *bmo) +{ + BL_Texture *self = static_castEXP_PROXY_REF(bmo->cb_user); + if (!self) { + return -1; } -} + return 0; +} -void BL_Texture::setTexEnv(BL_Material *mat, bool modulate) +static int mathutils_bltexture_get(BaseMathObject *bmo, int subtype) { - if (modulate || !GLEW_ARB_texture_env_combine) { - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); - return; + BL_Texture *self = static_castEXP_PROXY_REF(bmo->cb_user); + if (!self) { + return -1; } - if (glIsList(mEnvState)) - { - glCallList(mEnvState); - return; - } - if (!mEnvState) - mEnvState = glGenLists(1); - - glNewList(mEnvState, GL_COMPILE_AND_EXECUTE); - - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB ); - - GLfloat blend_operand = GL_SRC_COLOR; - GLfloat blend_operand_prev = GL_SRC_COLOR; - GLfloat alphaOp = GL_SRC_ALPHA; - - GLenum combiner = GL_COMBINE_RGB_ARB; - GLenum source0 = GL_SOURCE0_RGB_ARB; - GLenum source1 = GL_SOURCE1_RGB_ARB; - GLenum source2 = GL_SOURCE2_RGB_ARB; - GLenum op0 = GL_OPERAND0_RGB_ARB; - GLenum op1 = GL_OPERAND1_RGB_ARB; - GLenum op2 = GL_OPERAND2_RGB_ARB; - - // switch to alpha combiners - if ( mat->flag[mUnit] &TEXALPHA ) { - combiner = GL_COMBINE_ALPHA_ARB; - source0 = GL_SOURCE0_ALPHA_ARB; - source1 = GL_SOURCE1_ALPHA_ARB; - source2 = GL_SOURCE2_ALPHA_ARB; - op0 = GL_OPERAND0_ALPHA_ARB; - op1 = GL_OPERAND1_ALPHA_ARB; - op2 = GL_OPERAND2_ALPHA_ARB; - blend_operand = GL_SRC_ALPHA; - blend_operand_prev = GL_SRC_ALPHA; - // invert - if (mat->flag[mUnit] &TEXNEG) { - blend_operand_prev = GL_ONE_MINUS_SRC_ALPHA; - blend_operand = GL_ONE_MINUS_SRC_ALPHA; + switch (subtype) { + case MATHUTILS_VEC_CB_TEXTURE_UV_OFFSET_VECTOR: + { + copy_v3_v3(bmo->data, self->GetMTex()->ofs); + break; } - } - else { - if (mat->flag[mUnit] &TEXNEG) { - blend_operand_prev=GL_ONE_MINUS_SRC_COLOR; - blend_operand = GL_ONE_MINUS_SRC_COLOR; + case MATHUTILS_VEC_CB_TEXTURE_UV_SIZE_VECTOR: + { + copy_v3_v3(bmo->data, self->GetMTex()->size); + break; } } - bool using_alpha = false; - if (mat->flag[mUnit] &USEALPHA) { - alphaOp = GL_ONE_MINUS_SRC_ALPHA; - using_alpha=true; - } - else if (mat->flag[mUnit] &USENEGALPHA) { - alphaOp = GL_SRC_ALPHA; - using_alpha = true; + return 0; +} + +static int mathutils_bltexture_set(BaseMathObject *bmo, int subtype) +{ + BL_Texture *self = static_castEXP_PROXY_REF(bmo->cb_user); + if (!self) { + return -1; } - switch (mat->blend_mode[mUnit]) { - case BLEND_MIX: - { - // ------------------------------ - if (!using_alpha) { - GLfloat base_col[4]; - base_col[0] = base_col[1] = base_col[2] = 0.f; - base_col[3] = 1.f-mat->color_blend[mUnit]; - glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR,base_col ); - } - glTexEnvf( GL_TEXTURE_ENV, combiner, GL_INTERPOLATE_ARB); - glTexEnvf( GL_TEXTURE_ENV, source0, GL_PREVIOUS_ARB); - glTexEnvf( GL_TEXTURE_ENV, op0, blend_operand_prev ); - glTexEnvf( GL_TEXTURE_ENV, source1, GL_TEXTURE ); - glTexEnvf( GL_TEXTURE_ENV, op1, blend_operand); - if (!using_alpha) - glTexEnvf( GL_TEXTURE_ENV, source2, GL_CONSTANT_ARB ); - else - glTexEnvf( GL_TEXTURE_ENV, source2, GL_TEXTURE ); - - glTexEnvf( GL_TEXTURE_ENV, op2, alphaOp); - }break; - case BLEND_MUL: - { - // ------------------------------ - glTexEnvf( GL_TEXTURE_ENV, combiner, GL_MODULATE); - glTexEnvf( GL_TEXTURE_ENV, source0, GL_PREVIOUS_ARB); - glTexEnvf( GL_TEXTURE_ENV, op0, blend_operand_prev); - glTexEnvf( GL_TEXTURE_ENV, source1, GL_TEXTURE ); - if (using_alpha) - glTexEnvf( GL_TEXTURE_ENV, op1, alphaOp); - else - glTexEnvf( GL_TEXTURE_ENV, op1, blend_operand); - }break; - case BLEND_ADD: - { - // ------------------------------ - glTexEnvf( GL_TEXTURE_ENV, combiner, GL_ADD_SIGNED_ARB); - glTexEnvf( GL_TEXTURE_ENV, source0, GL_PREVIOUS_ARB ); - glTexEnvf( GL_TEXTURE_ENV, op0, blend_operand_prev ); - glTexEnvf( GL_TEXTURE_ENV, source1, GL_TEXTURE ); - if (using_alpha) - glTexEnvf( GL_TEXTURE_ENV, op1, alphaOp); - else - glTexEnvf( GL_TEXTURE_ENV, op1, blend_operand); - }break; - case BLEND_SUB: - { - // ------------------------------ - glTexEnvf( GL_TEXTURE_ENV, combiner, GL_SUBTRACT_ARB); - glTexEnvf( GL_TEXTURE_ENV, source0, GL_PREVIOUS_ARB ); - glTexEnvf( GL_TEXTURE_ENV, op0, blend_operand_prev ); - glTexEnvf( GL_TEXTURE_ENV, source1, GL_TEXTURE ); - glTexEnvf( GL_TEXTURE_ENV, op1, blend_operand); - }break; - case BLEND_SCR: - { - // ------------------------------ - glTexEnvf( GL_TEXTURE_ENV, combiner, GL_ADD); - glTexEnvf( GL_TEXTURE_ENV, source0, GL_PREVIOUS_ARB ); - glTexEnvf( GL_TEXTURE_ENV, op0, blend_operand_prev ); - glTexEnvf( GL_TEXTURE_ENV, source1, GL_TEXTURE ); - if (using_alpha) - glTexEnvf( GL_TEXTURE_ENV, op1, alphaOp); - else - glTexEnvf( GL_TEXTURE_ENV, op1, blend_operand); - } break; + switch (subtype) { + case MATHUTILS_VEC_CB_TEXTURE_UV_OFFSET_VECTOR: + { + copy_v3_v3(self->GetMTex()->ofs, bmo->data); + break; + } + case MATHUTILS_VEC_CB_TEXTURE_UV_SIZE_VECTOR: + { + copy_v3_v3(self->GetMTex()->size, bmo->data); + break; + } } - glTexEnvf( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.0f); - glEndList(); + return 0; } -int BL_Texture::GetPow2(int n) +static int mathutils_bltexture_get_index(BaseMathObject *bmo, int subtype, int index) { - if (!is_power_of_2_i(n)) - n = power_of_2_min_i(n); - - return n; + if (mathutils_bltexture_get(bmo, subtype) == -1) { + return -1; + } + return 0; } -void BL_Texture::SplitEnvMap(EnvMap *map) +static int mathutils_bltexture_set_index(BaseMathObject *bmo, int subtype, int index) { - if (!map || !map->ima || (map->ima && !map->ima->ok)) return; - ImBuf *ibuf= BKE_image_acquire_ibuf(map->ima, NULL, NULL); - if (ibuf) { - my_envmap_split_ima(map, ibuf); - BKE_image_release_ibuf(map->ima, ibuf, NULL); + float f = bmo->data[index]; + + if (mathutils_bltexture_get(bmo, subtype) == -1) { + return -1; } + + bmo->data[index] = f; + return mathutils_bltexture_set(bmo, subtype); } -unsigned int BL_Texture::mDisableState = 0; +static Mathutils_Callback mathutils_bltexture_cb = { + mathutils_bltexture_generic_check, + mathutils_bltexture_get, + mathutils_bltexture_set, + mathutils_bltexture_get_index, + mathutils_bltexture_set_index +}; -extern "C" { -void my_envmap_split_ima(EnvMap *env, ImBuf *ibuf) +void BL_Texture_Mathutils_Callback_Init() { - int dx, part; + // Register mathutils callbacks, ok to run more than once. + mathutils_bltexture_cb_index = Mathutils_RegisterCallback(&mathutils_bltexture_cb); +} - my_free_envmapdata(env); +#endif // USE_MATHUTILS - dx= ibuf->y; - dx/= 2; - if (3*dx != ibuf->x) { - printf("Incorrect envmap size\n"); - env->ok= 0; - env->ima->ok= 0; - } - else { - for (part=0; part<6; part++) { - env->cube[part] = IMB_allocImBuf(dx, dx, 24, IB_rect); - } - IMB_rectcpy(env->cube[0], ibuf, - 0, 0, 0, 0, dx, dx); - IMB_rectcpy(env->cube[1], ibuf, - 0, 0, dx, 0, dx, dx); - IMB_rectcpy(env->cube[2], ibuf, - 0, 0, 2*dx, 0, dx, dx); - IMB_rectcpy(env->cube[3], ibuf, - 0, 0, 0, dx, dx, dx); - IMB_rectcpy(env->cube[4], ibuf, - 0, 0, dx, dx, dx, dx); - IMB_rectcpy(env->cube[5], ibuf, - 0, 0, 2*dx, dx, dx, dx); - - env->ok= 2;// ENV_OSA - } +PyObject *BL_Texture::pyattr_get_uv_offset(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ +#ifdef USE_MATHUTILS + return Vector_CreatePyObject_cb(EXP_PROXY_FROM_REF(self_v), 3, mathutils_bltexture_cb_index, MATHUTILS_VEC_CB_TEXTURE_UV_OFFSET_VECTOR); +#else + BL_Texture *self = static_cast(self_v); + + return PyObjectFrom(self->GetMTex()->ofs); +#endif } +int BL_Texture::pyattr_set_uv_offset(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_Texture *self = static_cast(self_v); + mt::vec3 offset; + if (!PyVecTo(value, offset)) { + return PY_SET_ATTR_FAIL; + } -void my_free_envmapdata(EnvMap *env) + offset.Pack(self->GetMTex()->ofs); + + return PY_SET_ATTR_SUCCESS; +} + +PyObject *BL_Texture::pyattr_get_uv_size(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - unsigned int part; +#ifdef USE_MATHUTILS + return Vector_CreatePyObject_cb(EXP_PROXY_FROM_REF(self_v), 3, mathutils_bltexture_cb_index, MATHUTILS_VEC_CB_TEXTURE_UV_SIZE_VECTOR); +#else + BL_Texture *self = static_cast(self_v); - for (part=0; part<6; part++) { - ImBuf *ibuf= env->cube[part]; - if (ibuf) { - IMB_freeImBuf(ibuf); - env->cube[part] = NULL; - } - } - env->ok= 0; + return PyObjectFrom(self->GetMTex()->size); +#endif } +int BL_Texture::pyattr_set_uv_size(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + BL_Texture *self = static_cast(self_v); + mt::vec3 size; + if (!PyVecTo(value, size)) { + return PY_SET_ATTR_FAIL; + } + + size.Pack(self->GetMTex()->size); + + return PY_SET_ATTR_SUCCESS; +} -} // extern C +#endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/BL_Texture.h b/source/gameengine/Ketsji/BL_Texture.h index b2e17522e402..01077cda7ccc 100644 --- a/source/gameengine/Ketsji/BL_Texture.h +++ b/source/gameengine/Ketsji/BL_Texture.h @@ -1,3 +1,22 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ /** \file BL_Texture.h * \ingroup ketsji @@ -6,77 +25,107 @@ #ifndef __BL_TEXTURE_H__ #define __BL_TEXTURE_H__ -// #include -// #include - -#include "MT_Matrix4x4.h" -#include "KX_Camera.h" +#include "RAS_Texture.h" +#include "EXP_Value.h" -// -- -struct Image; -struct EnvMap; -class BL_Material; -class RAS_Rect; -class RAS_ICanvas; -//class RTData; - -#include "STR_String.h" +#ifdef USE_MATHUTILS +/// Setup mathutils callbacks. +void BL_Texture_Mathutils_Callback_Init(); +#endif -class BL_Texture +class BL_Texture : public EXP_Value, public RAS_Texture { + Py_Header private: - unsigned int mTexture; // Bound texture unit data - bool mOk; // ... - bool mNeedsDeleted; // If generated - unsigned int mType; // enum TEXTURE_2D | CUBE_MAP - int mUnit; // Texture unit associated with mTexture - unsigned int mEnvState; // cache textureEnv - static unsigned int mDisableState; // speed up disabling calls - - void InitNonPow2Tex(unsigned int *p,int x,int y,bool mipmap ); - void InitGLTex(unsigned int *p,int x,int y,bool mipmap ); - void InitGLCompressedTex(struct ImBuf *p, bool mipmap); -public: - BL_Texture(); - ~BL_Texture( ); - - bool Ok(); - int GetUnit() {return mUnit;} - void SetUnit(int unit) {mUnit = unit;} - - unsigned int GetTextureType() const; - void DeleteTex(); - - bool InitFromImage(int unit, Image *img, bool mipmap); - bool InitCubeMap(int unit,EnvMap *cubemap ); + bool m_isCubeMap; + MTex *m_mtex; + GPUTexture *m_gpuTex; + + struct { + unsigned int bindcode; + float colintensfac; + float colfac; + float alphafac; + float specintensfac; + float speccolorfac; + float hardnessfac; + float emitfac; + float mirrorfac; + float normalfac; + float parallaxbumpfac; + float parallaxstepfac; + float lodbias; + float ior; + float ratio; + float uvrot; + float uvoffset[3]; + float uvsize[3]; + } m_savedData; - bool IsValid(); - void Validate(); - - static void ActivateFirst(); - static void DisableAllTextures(); - static void ActivateUnit(int unit); - static int GetMaxUnits(); - static int GetPow2(int x); - static void SplitEnvMap(EnvMap *map); - - - void ActivateTexture(); - void SetMapping(int mode); - void DisableUnit(); - void setTexEnv(BL_Material *mat, bool modulate=false); - unsigned int swapTexture (unsigned int newTex) { - // swap texture codes - unsigned int tmp = mTexture; - mTexture = newTex; - // return original texture code - return tmp; - } - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_Texture") -#endif +public: + BL_Texture(MTex *mtex); + virtual ~BL_Texture(); + + // stuff for cvalue related things + virtual std::string GetName(); + + virtual bool Ok() const; + virtual bool IsCubeMap() const; + + virtual MTex *GetMTex() const; + virtual Tex *GetTex() const; + virtual Image *GetImage() const; + virtual GPUTexture *GetGPUTexture() const; + + virtual unsigned int GetTextureType(); + + enum {MaxUnits = 8}; + + virtual void CheckValidTexture(); + virtual void ActivateTexture(int unit); + virtual void DisableTexture(); + +#ifdef WITH_PYTHON + + static PyObject *pyattr_get_diffuse_intensity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_diffuse_intensity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_diffuse_factor(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_diffuse_factor(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_alpha(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_alpha(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_specular_intensity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_specular_intensity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_specular_factor(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_specular_factor(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_hardness(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_hardness(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_emit(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_emit(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_mirror(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_mirror(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_normal(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_normal(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_parallax_bump(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_parallax_bump(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_parallax_step(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_parallax_step(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_lod_bias(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_lod_bias(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_bind_code(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_bind_code(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_renderer(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_ior(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_ior(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_refraction_ratio(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_refraction_ratio(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_uv_rotation(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_uv_rotation(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_uv_offset(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_uv_offset(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_uv_size(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_uv_size(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + +#endif // WITH_PYTHON }; -#endif /* __BL_TEXTURE_H__ */ +#endif // __BL_TEXTURE_H__ diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt index 417f54cc8b9c..41a93b197cc2 100644 --- a/source/gameengine/Ketsji/CMakeLists.txt +++ b/source/gameengine/Ketsji/CMakeLists.txt @@ -27,15 +27,18 @@ set(INC . KXNetwork ../BlenderRoutines + ../Common ../Converter + ../Device ../Expressions ../GameLogic - ../Network - ../Network/LoopBackNetwork - ../Physics/common + ../Launcher + ../Physics/Common ../Rasterizer + ../Rasterizer/Node ../Rasterizer/RAS_OpenGLRasterizer ../SceneGraph + ../VideoTexture ../../blender ../../blender/blenfont ../../blender/blenkernel @@ -48,14 +51,14 @@ set(INC ../../blender/python ../../blender/python/generic ../../blender/python/mathutils - ../../../intern/container + ../../blender/python/intern ../../../intern/glew-mx ../../../intern/guardedalloc - ../../../intern/string ) set(INC_SYS - ../../../intern/moto/include + ../../../intern/debugbreak + ../../../intern/mathfu ../../../extern/recastnavigation/Recast/Include ../../../extern/recastnavigation/Detour/Include ${PTHREADS_INCLUDE_DIRS} @@ -67,82 +70,99 @@ set(SRC BL_Action.cpp BL_ActionManager.cpp BL_BlenderShader.cpp - BL_Material.cpp BL_Shader.cpp BL_Texture.cpp + KX_2DFilter.cpp + KX_2DFilterManager.cpp + KX_2DFilterOffScreen.cpp KX_ArmatureSensor.cpp + KX_BatchGroup.cpp KX_BlenderMaterial.cpp + KX_BoundingBox.cpp KX_Camera.cpp KX_CameraActuator.cpp KX_CameraIpoSGController.cpp KX_CharacterWrapper.cpp + KX_CollisionEventManager.cpp + KX_CollisionSensor.cpp KX_ConstraintActuator.cpp KX_ConstraintWrapper.cpp - KX_Dome.cpp + KX_CubeMap.cpp + KX_CullingHandler.cpp KX_EmptyObject.cpp KX_FontObject.cpp KX_GameActuator.cpp KX_GameObject.cpp - KX_IpoConvert.cpp - KX_IPO_SGController.cpp + KX_Globals.cpp + KX_IpoController.cpp KX_KetsjiEngine.cpp - KX_Light.cpp + KX_LibLoadStatus.cpp + KX_LightObject.cpp KX_LightIpoSGController.cpp + KX_LodLevel.cpp + KX_LodManager.cpp KX_MaterialIpoController.cpp - KX_MeshProxy.cpp + KX_MeshBuilder.cpp + KX_Mesh.cpp KX_MotionState.cpp KX_MouseActuator.cpp KX_MouseFocusSensor.cpp + KX_MovementSensor.cpp KX_NavMeshObject.cpp KX_NearSensor.cpp KX_ObColorIpoSGController.cpp KX_ObjectActuator.cpp KX_ObstacleSimulation.cpp - KX_OrientationInterpolator.cpp KX_ParentActuator.cpp + KX_PlanarMap.cpp KX_PolyProxy.cpp - KX_PositionInterpolator.cpp KX_PyConstraintBinding.cpp KX_PyMath.cpp + KX_PythonComponent.cpp + KX_PythonComponentManager.cpp KX_PythonInit.cpp KX_PythonInitTypes.cpp KX_PythonMain.cpp KX_RadarSensor.cpp KX_RayCast.cpp - KX_RayEventManager.cpp KX_RaySensor.cpp - KX_SCA_AddObjectActuator.cpp - KX_SCA_DynamicActuator.cpp - KX_SCA_EndObjectActuator.cpp - KX_SCA_ReplaceMeshActuator.cpp - KX_SG_BoneParentNodeRelationship.cpp - KX_SG_NodeRelationships.cpp - KX_ScalarInterpolator.cpp - KX_ScalingInterpolator.cpp + KX_AddObjectActuator.cpp + KX_DynamicActuator.cpp + KX_EndObjectActuator.cpp + KX_ReplaceMeshActuator.cpp + KX_BoneParentNodeRelationship.cpp + KX_NodeRelationships.cpp KX_Scene.cpp KX_SceneActuator.cpp + KX_SoftBodyDeformer.cpp KX_SoundActuator.cpp KX_StateActuator.cpp KX_SteeringActuator.cpp + KX_TextMaterial.cpp + KX_TextureRenderer.cpp + KX_TextureRendererManager.cpp KX_TimeCategoryLogger.cpp KX_TimeLogger.cpp - KX_TouchEventManager.cpp - KX_TouchSensor.cpp KX_TrackToActuator.cpp KX_VehicleWrapper.cpp KX_VertexProxy.cpp KX_VisibilityActuator.cpp KX_WorldInfo.cpp KX_WorldIpoController.cpp + KX_CollisionContactPoints.cpp BL_Action.h BL_ActionManager.h BL_BlenderShader.h - BL_Material.h BL_Shader.h BL_Texture.h + KX_2DFilter.h + KX_2DFilterManager.h + KX_2DFilterOffScreen.h KX_ArmatureSensor.h + KX_BatchGroup.h KX_BlenderMaterial.h + KX_BoundingBox.h KX_Camera.h KX_CameraActuator.h KX_CameraIpoSGController.h @@ -150,80 +170,73 @@ set(SRC KX_ClientObjectInfo.h KX_ConstraintActuator.h KX_ConstraintWrapper.h - KX_Dome.h + KX_CubeMap.h + KX_CullingHandler.h KX_EmptyObject.h KX_FontObject.h KX_GameActuator.h KX_GameObject.h - KX_IInterpolator.h - KX_IpoConvert.h - KX_IPOTransform.h - KX_IPO_SGController.h - KX_IScalarInterpolator.h - KX_ISceneConverter.h - KX_ISystem.h + KX_Globals.h + KX_IpoTransform.h + KX_IpoController.h KX_KetsjiEngine.h - KX_Light.h + KX_LibLoadStatus.h + KX_LightObject.h KX_LightIpoSGController.h + KX_LodLevel.h + KX_LodManager.h KX_MaterialIpoController.h - KX_MeshProxy.h + KX_MeshBuilder.h + KX_Mesh.h KX_MotionState.h KX_MouseActuator.h KX_MouseFocusSensor.h + KX_MovementSensor.h KX_NavMeshObject.h KX_NearSensor.h KX_ObColorIpoSGController.h KX_ObjectActuator.h KX_ObstacleSimulation.h - KX_OrientationInterpolator.h KX_ParentActuator.h KX_PhysicsEngineEnums.h + KX_PlanarMap.h KX_PolyProxy.h - KX_PositionInterpolator.h KX_PyConstraintBinding.h KX_PyMath.h + KX_PythonComponent.h + KX_PythonComponentManager.h KX_PythonInit.h KX_PythonInitTypes.h KX_PythonMain.h KX_RadarSensor.h KX_RayCast.h - KX_RayEventManager.h KX_RaySensor.h - KX_SCA_AddObjectActuator.h - KX_SCA_DynamicActuator.h - KX_SCA_EndObjectActuator.h - KX_SCA_ReplaceMeshActuator.h - KX_SG_BoneParentNodeRelationship.h - KX_SG_NodeRelationships.h - KX_ScalarInterpolator.h - KX_ScalingInterpolator.h + KX_AddObjectActuator.h + KX_DynamicActuator.h + KX_EndObjectActuator.h + KX_ReplaceMeshActuator.h + KX_BoneParentNodeRelationship.h + KX_NodeRelationships.h KX_Scene.h KX_SceneActuator.h + KX_SoftBodyDeformer.h KX_SoundActuator.h KX_StateActuator.h KX_SteeringActuator.h + KX_TextMaterial.h + KX_TextureRenderer.h + KX_TextureRendererManager.h KX_TimeCategoryLogger.h KX_TimeLogger.h - KX_TouchEventManager.h - KX_TouchSensor.h + KX_CollisionEventManager.h + KX_CollisionSensor.h KX_TrackToActuator.h KX_VehicleWrapper.h KX_VertexProxy.h KX_VisibilityActuator.h KX_WorldInfo.h KX_WorldIpoController.h - - # orphan headers (not apart of a library) - ../Physics/common/PHY_DynamicTypes.h - ../Physics/common/PHY_ICharacter.h - ../Physics/common/PHY_IController.h - ../Physics/common/PHY_IGraphicController.h - ../Physics/common/PHY_IMotionState.h - ../Physics/common/PHY_IPhysicsController.h - ../Physics/common/PHY_IPhysicsEnvironment.h - ../Physics/common/PHY_IVehicle.h - ../Physics/common/PHY_Pro.h - + KX_CollisionContactPoints.h ) add_definitions(${GL_DEFINITIONS}) diff --git a/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt b/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt index cfc6ded4e650..4d6be76dc15e 100644 --- a/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt +++ b/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt @@ -26,31 +26,28 @@ set(INC . .. + ../../Common ../../Expressions ../../GameLogic - ../../Network ../../SceneGraph ../../../blender/blenlib - ../../../../intern/container - ../../../../intern/string ) set(INC_SYS - ../../../../intern/moto/include + ../../../../intern/debugbreak + ../../../../intern/mathfu ) set(SRC - KX_NetworkEventManager.cpp + KX_NetworkMessageManager.cpp + KX_NetworkMessageScene.cpp KX_NetworkMessageActuator.cpp KX_NetworkMessageSensor.cpp - KX_NetworkObjectActuator.cpp - KX_NetworkObjectSensor.cpp - KX_NetworkEventManager.h + KX_NetworkMessageManager.h + KX_NetworkMessageScene.h KX_NetworkMessageActuator.h KX_NetworkMessageSensor.h - KX_NetworkObjectActuator.h - KX_NetworkObjectSensor.h ) blender_add_lib(ge_logic_network "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp deleted file mode 100644 index 255c327015cc..000000000000 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - * Ketsji Logic Extension: Network Event Manager generic implementation - */ - -/** \file gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.cpp - * \ingroup ketsjinet - */ - - -// Ketsji specific sensor part -#include "SCA_ISensor.h" - -// Ketsji specific network part -#include "KX_NetworkEventManager.h" - -// Network module specific -#include "NG_NetworkDeviceInterface.h" -#include "NG_NetworkMessage.h" -#include "NG_NetworkObject.h" - -KX_NetworkEventManager::KX_NetworkEventManager(class SCA_LogicManager* -logicmgr, class NG_NetworkDeviceInterface *ndi) : -SCA_EventManager(logicmgr, NETWORK_EVENTMGR), m_ndi(ndi) -{ - //printf("KX_NetworkEventManager constructor\n"); -} - -KX_NetworkEventManager::~KX_NetworkEventManager() -{ - //printf("KX_NetworkEventManager destructor\n"); -} - -void KX_NetworkEventManager::NextFrame() -{ -// printf("KX_NetworkEventManager::proceed %.2f - %.2f\n", curtime, deltatime); - // each frame, the logicmanager will call the network - // eventmanager to look for network events, and process it's - // 'network' sensors - SG_DList::iterator it(m_sensors); - for (it.begin();!it.end();++it) - { -// printf("KX_NetworkEventManager::proceed sensor %.2f\n", curtime); - // process queue - (*it)->Activate(m_logicmgr); - } - - // now a list of triggerer sensors has been built -} - -void KX_NetworkEventManager::EndFrame() -{ -} diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp index 2741907bfe6c..29ff6b464693 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.cpp @@ -33,17 +33,16 @@ #include -#include "NG_NetworkScene.h" +#include "KX_NetworkMessageScene.h" #include "KX_NetworkMessageActuator.h" -KX_NetworkMessageActuator::KX_NetworkMessageActuator( - SCA_IObject* gameobj, // the actuator controlling object - NG_NetworkScene* networkscene, // needed for replication - const STR_String &toPropName, - const STR_String &subject, - int bodyType, - const STR_String &body) : - SCA_IActuator(gameobj, KX_ACT_MESSAGE), +KX_NetworkMessageActuator::KX_NetworkMessageActuator(SCA_IObject *gameobj, // the actuator controlling object + KX_NetworkMessageScene *networkscene, // needed for replication + const std::string &toPropName, + const std::string &subject, + int bodyType, + const std::string &body) + :SCA_IActuator(gameobj, KX_ACT_MESSAGE), m_networkscene(networkscene), m_toPropName(toPropName), m_subject(subject), @@ -56,40 +55,37 @@ KX_NetworkMessageActuator::~KX_NetworkMessageActuator() { } -// returns true if the actuators needs to be running over several frames +/// returns true if the actuators needs to be running over several frames bool KX_NetworkMessageActuator::Update() { - //printf("update messageactuator\n"); bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); if (bNegativeEvent) { return false; // do nothing on negative events - //printf("messageactuator false event\n"); } - //printf("messageactuator true event\n"); - if (m_bPropBody) // ACT_MESG_PROP in DNA_actuator_types.h - { + // ACT_MESG_PROP in DNA_actuator_types.h + if (m_bPropBody) { m_networkscene->SendMessage( m_toPropName, - GetParent()->GetName(), + GetParent(), m_subject, GetParent()->GetPropertyText(m_body)); - } else - { + } + else { m_networkscene->SendMessage( m_toPropName, - GetParent()->GetName(), + GetParent(), m_subject, m_body); } return false; } -CValue* KX_NetworkMessageActuator::GetReplica() +EXP_Value *KX_NetworkMessageActuator::GetReplica() { - KX_NetworkMessageActuator* replica = new KX_NetworkMessageActuator(*this); + KX_NetworkMessageActuator *replica = new KX_NetworkMessageActuator(*this); replica->ProcessReplica(); return replica; @@ -103,9 +99,9 @@ CValue* KX_NetworkMessageActuator::GetReplica() /* Integration hooks -------------------------------------------------- */ PyTypeObject KX_NetworkMessageActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_NetworkMessageActuator", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -113,27 +109,27 @@ PyTypeObject KX_NetworkMessageActuator::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IActuator::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_NetworkMessageActuator::Methods[] = { - {NULL,NULL} // Sentinel + {nullptr, nullptr} // Sentinel }; PyAttributeDef KX_NetworkMessageActuator::Attributes[] = { - KX_PYATTRIBUTE_STRING_RW("propName", 0, MAX_PROP_NAME, false, KX_NetworkMessageActuator, m_toPropName), - KX_PYATTRIBUTE_STRING_RW("subject", 0, 100, false, KX_NetworkMessageActuator, m_subject), - KX_PYATTRIBUTE_BOOL_RW("usePropBody", KX_NetworkMessageActuator, m_bPropBody), - KX_PYATTRIBUTE_STRING_RW("body", 0, 16384, false, KX_NetworkMessageActuator, m_body), - { NULL } //Sentinel + EXP_PYATTRIBUTE_STRING_RW("propName", 0, MAX_PROP_NAME, false, KX_NetworkMessageActuator, m_toPropName), + EXP_PYATTRIBUTE_STRING_RW("subject", 0, 100, false, KX_NetworkMessageActuator, m_subject), + EXP_PYATTRIBUTE_BOOL_RW("usePropBody", KX_NetworkMessageActuator, m_bPropBody), + EXP_PYATTRIBUTE_STRING_RW("body", 0, 16384, false, KX_NetworkMessageActuator, m_body), + EXP_PYATTRIBUTE_NULL //Sentinel }; #endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.h index 7b00129257a8..a52562f76aea 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.h +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageActuator.h @@ -33,40 +33,35 @@ #ifndef __KX_NETWORKMESSAGEACTUATOR_H__ #define __KX_NETWORKMESSAGEACTUATOR_H__ -#include "STR_String.h" +#include #include "SCA_IActuator.h" -#include "NG_NetworkMessage.h" class KX_NetworkMessageActuator : public SCA_IActuator { Py_Header bool m_lastEvent; - class NG_NetworkScene* m_networkscene; // needed for replication - STR_String m_toPropName; - STR_String m_subject; + class KX_NetworkMessageScene *m_networkscene; // needed for replication + std::string m_toPropName; + std::string m_subject; bool m_bPropBody; - STR_String m_body; + std::string m_body; + public: KX_NetworkMessageActuator( - SCA_IObject* gameobj, - NG_NetworkScene* networkscene, - const STR_String &toPropName, - const STR_String &subject, - int bodyType, - const STR_String &body); + SCA_IObject *gameobj, + KX_NetworkMessageScene *networkscene, + const std::string &toPropName, + const std::string &subject, + int bodyType, + const std::string &body); virtual ~KX_NetworkMessageActuator(); virtual bool Update(); - virtual CValue* GetReplica(); - virtual void Replace_NetworkScene(NG_NetworkScene *val) + virtual EXP_Value *GetReplica(); + virtual void Replace_NetworkScene(KX_NetworkMessageScene *val) { - m_networkscene= val; + m_networkscene = val; }; - - /* ------------------------------------------------------------ */ - /* Python interface ------------------------------------------- */ - /* ------------------------------------------------------------ */ - }; #endif /* __KX_NETWORKMESSAGEACTUATOR_H__ */ diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageManager.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageManager.cpp new file mode 100644 index 000000000000..0b88242c1713 --- /dev/null +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageManager.cpp @@ -0,0 +1,84 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * Ketsji Logic Extension: Network Message Scene generic implementation + */ + +/** \file gameengine/Ketsji/KXNetwork/KX_NetworkMessageManager.cpp + * \ingroup ketsjinet + */ + +#include "KX_NetworkMessageManager.h" +#include + +KX_NetworkMessageManager::KX_NetworkMessageManager() + :m_currentList(0) +{ +} + +KX_NetworkMessageManager::~KX_NetworkMessageManager() +{ + ClearMessages(); +} + +void KX_NetworkMessageManager::AddMessage(KX_NetworkMessageManager::Message message) +{ + // Put the new message in map for the given receiver and subject. + m_messages[m_currentList][message.to][message.subject].push_back(message); +} + +const std::vector KX_NetworkMessageManager::GetMessages(std::string to, std::string subject) +{ + std::vector messages; + + // look at messages without receiver. + std::map >& messagesNoReceiver = m_messages[1 - m_currentList][""]; + std::map >& messagesReceiver = m_messages[1 - m_currentList][to]; + if (subject.empty()) { + // Add all message without receiver and subject. + for (const auto& pair : messagesNoReceiver) { + messages.insert(messages.end(), pair.second.begin(), pair.second.end()); + } + // Add all message with the given receiver and no subject. + for (const auto& pair : messagesReceiver) { + messages.insert(messages.end(), pair.second.begin(), pair.second.end()); + } + } + else { + std::vector& messagesNoReceiverSubject = messagesNoReceiver[subject]; + messages.insert(messages.end(), messagesNoReceiverSubject.begin(), messagesNoReceiverSubject.end()); + std::vector& messagesReceiverSubject = messagesReceiver[subject]; + messages.insert(messages.end(), messagesReceiverSubject.begin(), messagesReceiverSubject.end()); + } + + return messages; +} + +void KX_NetworkMessageManager::ClearMessages() +{ + // Clear previous list. + m_messages[1 - m_currentList].clear(); + m_currentList = 1 - m_currentList; +} diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageManager.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageManager.h new file mode 100644 index 000000000000..78aaec2c3b4f --- /dev/null +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageManager.h @@ -0,0 +1,89 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file KX_NetworkMessageManager.h + * \ingroup ketsjinet + * \brief Ketsji Logic Extension: Network Message Manager class + */ +#ifndef __KX_NETWORKMESSAGEMANAGER_H__ +#define __KX_NETWORKMESSAGEMANAGER_H__ + +/* undef SendMessage Macro (WinUser.h) to avoid +conflicts with KX_NetworkMessageManager::SendMessage */ +#ifdef WIN32 +# undef SendMessage +#endif + +#include +#include +#include + +class SCA_IObject; + +class KX_NetworkMessageManager +{ +public: + struct Message + { + /// Receiver object(s) name. + std::string to; + /// Sender game object. + SCA_IObject *from; + /// Message subject, used as filter. + std::string subject; + /// Message body. + std::string body; + }; + +private: + /** List of all messages, filtered by receiver object(s) name and subject name. + * We use two lists, one handle sended message in the current frame and the other + * is used for handle message sended in the last frame for sensors. + */ + std::map > > m_messages[2]; + + /** Since we use two list for the current and last frame we have to switch of + * current message list each frame. This value is only 0 or 1. + */ + unsigned short m_currentList; + +public: + KX_NetworkMessageManager(); + virtual ~KX_NetworkMessageManager(); + + /** Add a message in the next message list. + * \param message The given message to add. + */ + void AddMessage(Message message); + /** Get all messages for a given receiver object name and message subject. + * \param to The object(s) name. + * \param subject The message subject/filter. + */ + const std::vector GetMessages(std::string to, std::string subject); + + /// Clear all messages + void ClearMessages(); +}; + +#endif // __KX_NETWORKMESSAGEMANAGER_H__ diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageScene.cpp similarity index 53% rename from source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h rename to source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageScene.cpp index 9a13b6d53e29..9db8c37d923f 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkEventManager.h +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageScene.cpp @@ -23,33 +23,37 @@ * Contributor(s): none yet. * * ***** END GPL LICENSE BLOCK ***** + * Ketsji Logic Extension: Network Message Scene generic implementation */ -/** \file KX_NetworkEventManager.h +/** \file gameengine/Ketsji/KXNetwork/KX_NetworkMessageScene.cpp * \ingroup ketsjinet - * \brief Ketsji Logic Extension: Network Event Manager class */ -#ifndef __KX_NETWORKEVENTMANAGER_H__ -#define __KX_NETWORKEVENTMANAGER_H__ +#include "KX_NetworkMessageScene.h" -#include "SCA_EventManager.h" - -class KX_NetworkEventManager : public SCA_EventManager +KX_NetworkMessageScene::KX_NetworkMessageScene(KX_NetworkMessageManager *messageManager) + :m_messageManager(messageManager) { - class NG_NetworkDeviceInterface* m_ndi; +} -public: - KX_NetworkEventManager(class SCA_LogicManager* logicmgr, - class NG_NetworkDeviceInterface *ndi); - virtual ~KX_NetworkEventManager (); +KX_NetworkMessageScene::~KX_NetworkMessageScene() +{ +} - virtual void NextFrame(); - virtual void EndFrame(); +void KX_NetworkMessageScene::SendMessage(std::string to, SCA_IObject *from, std::string subject, std::string body) +{ + KX_NetworkMessageManager::Message message; + message.to = to; + message.from = from; + message.subject = subject; + message.body = body; - SCA_LogicManager* GetLogicManager() { return m_logicmgr; } - class NG_NetworkDeviceInterface* GetNetworkDevice() { - return m_ndi; } -}; + // Put the new message in map for the given receiver and subject. + m_messageManager->AddMessage(message); +} -#endif /* __KX_NETWORKEVENTMANAGER_H__ */ +const std::vector KX_NetworkMessageScene::FindMessages(std::string to, std::string subject) +{ + return m_messageManager->GetMessages(to, subject); +} diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageScene.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageScene.h new file mode 100644 index 000000000000..cb5e62865dfa --- /dev/null +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageScene.h @@ -0,0 +1,73 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file KX_NetworkMessageScene.h + * \ingroup ketsjinet + * \brief Ketsji Logic Extension: Network Message Scene class + */ +#ifndef __KX_NETWORKMESSAGESCENE_H__ +#define __KX_NETWORKMESSAGESCENE_H__ + +/* undef SendMessage Macro (WinUser.h) to avoid +conflicts with KX_NetworkMessageScene::SendMessage */ +#ifdef WIN32 +# undef SendMessage +#endif + +#include "KX_NetworkMessageManager.h" +#include +#include +#include + +class SCA_IObject; + +class KX_NetworkMessageScene +{ +private: + KX_NetworkMessageManager *m_messageManager; + +public: + KX_NetworkMessageScene(KX_NetworkMessageManager *messageManager); + virtual ~KX_NetworkMessageScene(); + + /** Send A message to an object(s) name. + * \param to The object(s) name, in case of duplicated object all objects + * with the same name will receive the message. + * \param from The sender game object. + * \param subject The message subject, used as filter for receiver object(s). + * \param message The body of the message. + */ + void SendMessage(std::string to, SCA_IObject *from, std::string subject, std::string body); + + /** Get all messages for a given receiver object name and message subject. + * \param to The object(s) name. + * \param subject The message subject/filter. + */ + const std::vector FindMessages(std::string to, std::string subject); +}; + +#endif // __KX_NETWORKMESSAGESCENE_H__ diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp index 1fadd9382e00..c0f28a058bb1 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.cpp @@ -34,10 +34,7 @@ #include #include "KX_NetworkMessageSensor.h" -#include "KX_NetworkEventManager.h" -#include "NG_NetworkMessage.h" -#include "NG_NetworkScene.h" -#include "NG_NetworkObject.h" +#include "KX_NetworkMessageScene.h" #include "SCA_IObject.h" #include "EXP_InputParser.h" #include "EXP_ListValue.h" @@ -47,18 +44,16 @@ #include #endif -KX_NetworkMessageSensor::KX_NetworkMessageSensor( - class KX_NetworkEventManager* eventmgr, // our eventmanager - class NG_NetworkScene *NetworkScene, // our scene - SCA_IObject* gameobj, // the sensor controlling object - const STR_String &subject - ) : - SCA_ISensor(gameobj,eventmgr), - m_NetworkScene(NetworkScene), - m_subject(subject), - m_frame_message_count (0), - m_BodyList(NULL), - m_SubjectList(NULL) +KX_NetworkMessageSensor::KX_NetworkMessageSensor(SCA_EventManager *eventmgr, // our eventmanager + class KX_NetworkMessageScene *NetworkScene, // our scene + SCA_IObject *gameobj, // the sensor controlling object + const std::string &subject) + :SCA_ISensor(gameobj, eventmgr), + m_NetworkScene(NetworkScene), + m_subject(subject), + m_frame_message_count(0), + m_BodyList(nullptr), + m_SubjectList(nullptr) { Init(); } @@ -72,19 +67,21 @@ KX_NetworkMessageSensor::~KX_NetworkMessageSensor() { } -CValue* KX_NetworkMessageSensor::GetReplica() +EXP_Value *KX_NetworkMessageSensor::GetReplica() { // This is the standard sensor implementation of GetReplica // There may be more network message sensor specific stuff to do here. - CValue* replica = new KX_NetworkMessageSensor(*this); + EXP_Value *replica = new KX_NetworkMessageSensor(*this); - if (replica == NULL) return NULL; + if (replica == nullptr) { + return nullptr; + } replica->ProcessReplica(); return replica; } -// Return true only for flank (UP and DOWN) +/// Return true only for flank (UP and DOWN) bool KX_NetworkMessageSensor::Evaluate() { bool result = false; @@ -94,66 +91,61 @@ bool KX_NetworkMessageSensor::Evaluate() if (m_BodyList) { m_BodyList->Release(); - m_BodyList = NULL; + m_BodyList = nullptr; } if (m_SubjectList) { m_SubjectList->Release(); - m_SubjectList = NULL; + m_SubjectList = nullptr; } - STR_String& toname=GetParent()->GetName(); - STR_String& subject = this->m_subject; + std::string toname = GetParent()->GetName(); + std::string& subject = this->m_subject; - vector messages = - m_NetworkScene->FindMessages(toname,"",subject,true); + const std::vector messages = + m_NetworkScene->FindMessages(toname, subject); m_frame_message_count = messages.size(); if (!messages.empty()) { #ifdef NAN_NET_DEBUG - printf("KX_NetworkMessageSensor found one or more messages\n"); + std::cout << "KX_NetworkMessageSensor found one or more messages" << std::endl; #endif m_IsUp = true; - m_BodyList = new CListValue(); - m_SubjectList = new CListValue(); + m_BodyList = new EXP_ListValue(); + m_SubjectList = new EXP_ListValue(); } - vector::iterator mesit; - for (mesit=messages.begin();mesit!=messages.end();mesit++) - { + std::vector::const_iterator mesit; + for (mesit = messages.begin(); mesit != messages.end(); mesit++) { // save the body - const STR_String& body = (*mesit)->GetMessageText(); + const std::string& body = (*mesit).body; // save the subject - const STR_String& messub = (*mesit)->GetSubject(); + const std::string& messub = (*mesit).subject; #ifdef NAN_NET_DEBUG if (body) { cout << "body [" << body << "]\n"; } #endif - m_BodyList->Add(new CStringValue(body,"body")); + m_BodyList->Add(new EXP_StringValue(body, "body")); // Store Subject - m_SubjectList->Add(new CStringValue(messub,"subject")); - - // free the message - (*mesit)->Release(); + m_SubjectList->Add(new EXP_StringValue(messub, "subject")); } - messages.clear(); result = (WasUp != m_IsUp); // Return always true if a message was received otherwise we can loose messages - if (m_IsUp) + if (m_IsUp) { return true; + } // Is it useful to return also true when the first frame without a message?? // This will cause a fast on/off cycle that seems useless! return result; } -// return true for being up (no flank needed) +/// return true for being up (no flank needed) bool KX_NetworkMessageSensor::IsPositiveTrigger() { -// printf("KX_NetworkMessageSensor IsPositiveTrigger\n"); //attempt to fix [ #3809 ] IPO Actuator does not work with some Sensors //a better solution is to properly introduce separate Edge and Level triggering concept @@ -168,9 +160,9 @@ bool KX_NetworkMessageSensor::IsPositiveTrigger() /* Integration hooks --------------------------------------------------- */ PyTypeObject KX_NetworkMessageSensor::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_NetworkMessageSensor", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -178,46 +170,48 @@ PyTypeObject KX_NetworkMessageSensor::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_ISensor::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_NetworkMessageSensor::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_NetworkMessageSensor::Attributes[] = { - KX_PYATTRIBUTE_STRING_RW("subject", 0, 100, false, KX_NetworkMessageSensor, m_subject), - KX_PYATTRIBUTE_INT_RO("frameMessageCount", KX_NetworkMessageSensor, m_frame_message_count), - KX_PYATTRIBUTE_RO_FUNCTION("bodies", KX_NetworkMessageSensor, pyattr_get_bodies), - KX_PYATTRIBUTE_RO_FUNCTION("subjects", KX_NetworkMessageSensor, pyattr_get_subjects), - { NULL } //Sentinel + EXP_PYATTRIBUTE_STRING_RW("subject", 0, 100, false, KX_NetworkMessageSensor, m_subject), + EXP_PYATTRIBUTE_INT_RO("frameMessageCount", KX_NetworkMessageSensor, m_frame_message_count), + EXP_PYATTRIBUTE_RO_FUNCTION("bodies", KX_NetworkMessageSensor, pyattr_get_bodies), + EXP_PYATTRIBUTE_RO_FUNCTION("subjects", KX_NetworkMessageSensor, pyattr_get_subjects), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *KX_NetworkMessageSensor::pyattr_get_bodies(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_NetworkMessageSensor::pyattr_get_bodies(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_NetworkMessageSensor *self = static_cast(self_v); + KX_NetworkMessageSensor *self = static_cast(self_v); if (self->m_BodyList) { return self->m_BodyList->GetProxy(); - } else { - return (new CListValue())->NewProxy(true); + } + else { + return (new EXP_ListValue())->NewProxy(true); } } -PyObject *KX_NetworkMessageSensor::pyattr_get_subjects(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_NetworkMessageSensor::pyattr_get_subjects(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_NetworkMessageSensor *self = static_cast(self_v); + KX_NetworkMessageSensor *self = static_cast(self_v); if (self->m_SubjectList) { return self->m_SubjectList->GetProxy(); - } else { - return (new CListValue())->NewProxy(true); + } + else { + return (new EXP_ListValue())->NewProxy(true); } } diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h index a519ccdab227..1e7fd795608d 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h +++ b/source/gameengine/Ketsji/KXNetwork/KX_NetworkMessageSensor.h @@ -34,43 +34,45 @@ #include "SCA_ISensor.h" -class KX_NetworkEventManager; -class NG_NetworkScene; +class KX_NetworkMessageScene; +class EXP_StringValue; +template +class EXP_ListValue; class KX_NetworkMessageSensor : public SCA_ISensor { // note: Py_Header MUST BE the first listed here Py_Header - NG_NetworkScene *m_NetworkScene; + KX_NetworkMessageScene *m_NetworkScene; // The subject we filter on. - STR_String m_subject; + std::string m_subject; // The number of messages caught since the last frame. int m_frame_message_count; bool m_IsUp; - class CListValue* m_BodyList; - class CListValue* m_SubjectList; + EXP_ListValue *m_BodyList; + EXP_ListValue *m_SubjectList; + public: KX_NetworkMessageSensor( - KX_NetworkEventManager* eventmgr, // our eventmanager - NG_NetworkScene *NetworkScene, // our scene - SCA_IObject* gameobj, // the sensor controlling object - const STR_String &subject - ); + SCA_EventManager *eventmgr, // our eventmanager + KX_NetworkMessageScene *NetworkScene, // our scene + SCA_IObject *gameobj, // the sensor controlling object + const std::string &subject); virtual ~KX_NetworkMessageSensor(); - virtual CValue* GetReplica(); + virtual EXP_Value *GetReplica(); virtual bool Evaluate(); virtual bool IsPositiveTrigger(); virtual void Init(); void EndFrame(); - virtual void Replace_NetworkScene(NG_NetworkScene *val) + virtual void Replace_NetworkScene(KX_NetworkMessageScene *val) { - m_NetworkScene= val; + m_NetworkScene = val; }; #ifdef WITH_PYTHON @@ -80,11 +82,10 @@ class KX_NetworkMessageSensor : public SCA_ISensor /* ------------------------------------------------------------- */ /* attributes */ - static PyObject* pyattr_get_bodies(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_subjects(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_bodies(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_subjects(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); #endif /* WITH_PYTHON */ - }; #endif /* __KX_NETWORKMESSAGESENSOR_H__ */ diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectActuator.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectActuator.cpp deleted file mode 100644 index 99945447beb8..000000000000 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectActuator.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Ketsji/KXNetwork/KX_NetworkObjectActuator.cpp - * \ingroup ketsjinet - */ diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectActuator.h b/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectActuator.h deleted file mode 100644 index b7d45a4a4db1..000000000000 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectActuator.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Ketsji/KXNetwork/KX_NetworkObjectActuator.h - * \ingroup ketsjinet - */ diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectSensor.cpp b/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectSensor.cpp deleted file mode 100644 index 2370b253c082..000000000000 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectSensor.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Ketsji/KXNetwork/KX_NetworkObjectSensor.cpp - * \ingroup ketsjinet - */ diff --git a/source/gameengine/Ketsji/KX_2DFilter.cpp b/source/gameengine/Ketsji/KX_2DFilter.cpp new file mode 100644 index 000000000000..51d6f1c2e843 --- /dev/null +++ b/source/gameengine/Ketsji/KX_2DFilter.cpp @@ -0,0 +1,261 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Ulysse Martin, Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Ketsji/KX_2DFilter.cpp + * \ingroup ketsji + */ + +#include "KX_2DFilter.h" +#include "KX_2DFilterOffScreen.h" +#include "RAS_Texture.h" // for RAS_Texture::MaxUnits + +#include "CM_Message.h" + +KX_2DFilter::KX_2DFilter(RAS_2DFilterData& data) + :RAS_2DFilter(data), + BL_Shader(nullptr) +{ +} + +KX_2DFilter::~KX_2DFilter() +{ +} + +bool KX_2DFilter::LinkProgram() +{ + return RAS_2DFilter::LinkProgram(); +} + +#ifdef WITH_PYTHON + +bool KX_2DFilter::CheckTexture(int index, int bindCode, const std::string& prefix) const +{ + if (!m_shader) { + PyErr_Format(PyExc_ValueError, "%s: KX_2DFilter, No valid shader found", prefix.c_str()); + return false; + } + if (index < 0 || index >= RAS_Texture::MaxUnits) { + PyErr_Format(PyExc_ValueError, "%s: KX_2DFilter, index out of range [0, %i]", prefix.c_str(), (RAS_Texture::MaxUnits - 1)); + return false; + } + if (bindCode < 0) { + PyErr_Format(PyExc_ValueError, "%s: KX_2DFilter, bindCode negative", prefix.c_str()); + return false; + } + + return true; +} + +bool KX_2DFilter::SetTextureUniform(int index, const char *samplerName) +{ + if (samplerName) { + if (GetError()) { + return false; + } + int loc = GetUniformLocation(samplerName); + + if (loc != -1) { +#ifdef SORT_UNIFORMS + SetUniformiv(loc, RAS_Uniform::UNI_INT, &index, (sizeof(int)), 1); +#else + SetUniform(loc, index); +#endif + } + } + + return true; +} + +PyTypeObject KX_2DFilter::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_2DFilter", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &BL_Shader::Type, + 0, 0, 0, 0, 0, 0, + py_base_new +}; + +PyMethodDef KX_2DFilter::Methods[] = { + EXP_PYMETHODTABLE(KX_2DFilter, setTexture), + EXP_PYMETHODTABLE(KX_2DFilter, setCubeMap), + EXP_PYMETHODTABLE_KEYWORDS(KX_2DFilter, addOffScreen), + EXP_PYMETHODTABLE_NOARGS(KX_2DFilter, removeOffScreen), + {nullptr, nullptr} // Sentinel +}; + +PyAttributeDef KX_2DFilter::Attributes[] = { + EXP_PYATTRIBUTE_RW_FUNCTION("mipmap", KX_2DFilter, pyattr_get_mipmap, pyattr_set_mipmap), + EXP_PYATTRIBUTE_RO_FUNCTION("offScreen", KX_2DFilter, pyattr_get_offScreen), + EXP_PYATTRIBUTE_NULL // Sentinel +}; + +PyObject *KX_2DFilter::pyattr_get_mipmap(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_2DFilter *self = static_cast(self_v); + return PyBool_FromLong(self->GetMipmap()); +} + +int KX_2DFilter::pyattr_set_mipmap(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_2DFilter *self = static_cast(self_v); + int param = PyObject_IsTrue(value); + if (param == -1) { + PyErr_SetString(PyExc_AttributeError, "shader.enabled = bool: BL_Shader, expected True or False"); + return PY_SET_ATTR_FAIL; + } + + self->SetMipmap(param); + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_2DFilter::pyattr_get_offScreen(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_2DFilter *self = static_cast(self_v); + RAS_2DFilterOffScreen *offScreen = self->GetOffScreen(); + return offScreen ? static_cast(offScreen)->GetProxy() : Py_None; +} + +EXP_PYMETHODDEF_DOC(KX_2DFilter, setTexture, "setTexture(index, bindCode, samplerName)") +{ + int index = 0; + int bindCode = 0; + char *samplerName = nullptr; + + if (!PyArg_ParseTuple(args, "ii|s:setTexture", &index, &bindCode, &samplerName)) { + return nullptr; + } + + if (!CheckTexture(index, bindCode, "setTexture(index, bindCode, samplerName)")) { + return nullptr; + } + + if (!SetTextureUniform(index, samplerName)) { + return nullptr; + } + + m_textures[index] = {RAS_Texture::GetTexture2DType(), bindCode}; + Py_RETURN_NONE; +} + +EXP_PYMETHODDEF_DOC(KX_2DFilter, setCubeMap, "setCubeMap(index, bindCode, samplerName)") +{ + int index = 0; + int bindCode = 0; + char *samplerName = nullptr; + + if (!PyArg_ParseTuple(args, "ii|s:setCubeMap", &index, &bindCode, &samplerName)) { + return nullptr; + } + + if (!CheckTexture(index, bindCode, "setCubeMap(index, bindCode, samplerName)")) { + return nullptr; + } + + if (!SetTextureUniform(index, samplerName)) { + return nullptr; + } + + m_textures[index] = {RAS_Texture::GetCubeMapTextureType(), bindCode}; + Py_RETURN_NONE; +} + +EXP_PYMETHODDEF_DOC(KX_2DFilter, addOffScreen, " addOffScreen(slots, depth, width, height, hdr, mipmap)") +{ + int slots; + int depth = 0; + int width = -1; + int height = -1; + int hdr = RAS_Rasterizer::RAS_HDR_NONE; + int mipmap = 0; + int flag = 0; + + if (!EXP_ParseTupleArgsAndKeywords(args, kwds, "i|iiiii:addOffScreen", + {"slots", "depth", "width", "height", "hdr", "mipmap", 0}, + &slots, &depth, &width, &height, &hdr, &mipmap)) { + return nullptr; + } + + if (GetOffScreen()) { + PyErr_SetString(PyExc_TypeError, "filter.addOffScreen(...): KX_2DFilter, custom off screen already exists."); + return nullptr; + } + + if (slots < 0 || slots >= 8) { + PyErr_SetString(PyExc_TypeError, "filter.addOffScreen(...): KX_2DFilter, slots must be between 0 and 8 excluded."); + return nullptr; + } + + if (hdr < 0 || hdr > RAS_Rasterizer::RAS_HDR_MAX) { + PyErr_SetString(PyExc_TypeError, "filter.addOffScreen(...): KX_2DFilter, invalid hdr value."); + return nullptr; + } + + if (width < -1 || height < -1 || width == 0 || height == 0) { + PyErr_SetString(PyExc_TypeError, "filter.addOffScreen(...): KX_2DFilter, invalid size values."); + return nullptr; + } + + if (slots == 0 && !depth) { + PyErr_SetString(PyExc_TypeError, "filter.addOffScreen(...): KX_2DFilter, empty off screen, slots must be at least to 1 or depth to True."); + return nullptr; + } + + if (width == -1 || height == -1) { + flag |= RAS_2DFilterOffScreen::RAS_VIEWPORT_SIZE; + } + + if (mipmap) { + flag |= RAS_2DFilterOffScreen::RAS_MIPMAP; + } + + if (depth) { + flag |= RAS_2DFilterOffScreen::RAS_DEPTH; + } + + KX_2DFilterOffScreen *offScreen = new KX_2DFilterOffScreen(slots, (RAS_2DFilterOffScreen::Flag)flag, width, height, + (RAS_Rasterizer::HdrType)hdr); + + SetOffScreen(offScreen); + + return offScreen->GetProxy(); +} + +EXP_PYMETHODDEF_DOC_NOARGS(KX_2DFilter, removeOffScreen, " removeOffScreen()") +{ + SetOffScreen(nullptr); + Py_RETURN_NONE; +} + +#endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_2DFilter.h b/source/gameengine/Ketsji/KX_2DFilter.h new file mode 100644 index 000000000000..8a0c30a0d1db --- /dev/null +++ b/source/gameengine/Ketsji/KX_2DFilter.h @@ -0,0 +1,66 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Ulysse Martin, Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file KX_2DFilter.h +* \ingroup ketsji +*/ + +#ifndef __KX_2DFILTER_H__ +#define __KX_2DFILTER_H__ + +#include "RAS_2DFilter.h" +#include "BL_Shader.h" + +#ifdef _MSC_VER +/* KX_2DFilter uses a diamond inheritance from a virtual pure base class. Only one branch of the diamond + * define these virtual pure functions and come in the final class with dominance. This behaviour is wanted + * but MSVC warn about it, we just disable the warning. + */ +# pragma warning(disable:4250) +#endif + +class KX_2DFilter : public RAS_2DFilter, public BL_Shader +{ + Py_Header +public: + KX_2DFilter(RAS_2DFilterData& data); + virtual ~KX_2DFilter(); + + virtual bool LinkProgram(); + +#ifdef WITH_PYTHON + bool CheckTexture(int index, int bindCode, const std::string& prefix) const; + bool SetTextureUniform(int index, const char *samplerName); + + static PyObject *pyattr_get_mipmap(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_mipmap(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_offScreen(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + + EXP_PYMETHOD_DOC(KX_2DFilter, setTexture); + EXP_PYMETHOD_DOC(KX_2DFilter, setCubeMap); + EXP_PYMETHOD_DOC(KX_2DFilter, addOffScreen); + EXP_PYMETHOD_DOC_NOARGS(KX_2DFilter, removeOffScreen); + +#endif +}; + +#endif // __KX_2DFILTER_H__ diff --git a/source/gameengine/Ketsji/KX_2DFilterManager.cpp b/source/gameengine/Ketsji/KX_2DFilterManager.cpp new file mode 100644 index 000000000000..96107abfe465 --- /dev/null +++ b/source/gameengine/Ketsji/KX_2DFilterManager.cpp @@ -0,0 +1,146 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Ulysse Martin, Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file KX_2DFilterManager.cpp + * \ingroup ketsji + */ + +#include "KX_2DFilterManager.h" +#include "KX_2DFilter.h" +#include "KX_2DFilterOffScreen.h" + +#include "CM_Message.h" + +KX_2DFilterManager::KX_2DFilterManager() +{ +} + +KX_2DFilterManager::~KX_2DFilterManager() +{ +} + +RAS_2DFilter *KX_2DFilterManager::NewFilter(RAS_2DFilterData& filterData) +{ + return new KX_2DFilter(filterData); +} + +#ifdef WITH_PYTHON +PyMethodDef KX_2DFilterManager::Methods[] = { + // creation + EXP_PYMETHODTABLE(KX_2DFilterManager, getFilter), + EXP_PYMETHODTABLE(KX_2DFilterManager, addFilter), + EXP_PYMETHODTABLE(KX_2DFilterManager, removeFilter), + {nullptr, nullptr} //Sentinel +}; + +PyAttributeDef KX_2DFilterManager::Attributes[] = { + EXP_PYATTRIBUTE_NULL //Sentinel +}; + +PyTypeObject KX_2DFilterManager::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_2DFilterManager", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &EXP_PyObjectPlus::Type, + 0, 0, 0, 0, 0, 0, + py_base_new +}; + + +EXP_PYMETHODDEF_DOC(KX_2DFilterManager, getFilter, " getFilter(index)") +{ + int index = 0; + + if (!PyArg_ParseTuple(args, "i:getFilter", &index)) { + return nullptr; + } + + KX_2DFilter *filter = (KX_2DFilter *)GetFilterPass(index); + + if (filter) { + return filter->GetProxy(); + } + + Py_RETURN_NONE; +} + +EXP_PYMETHODDEF_DOC(KX_2DFilterManager, addFilter, " addFilter(index, type, fragmentProgram)") +{ + int index = 0; + int type = 0; + const char *frag = ""; + + if (!PyArg_ParseTuple(args, "ii|s:addFilter", &index, &type, &frag)) { + return nullptr; + } + + if (GetFilterPass(index)) { + PyErr_Format(PyExc_ValueError, "filterManager.addFilter(index, type, fragmentProgram): KX_2DFilterManager, found existing filter in index (%i)", index); + return nullptr; + } + + if (type < FILTER_BLUR || type > FILTER_CUSTOMFILTER) { + PyErr_SetString(PyExc_ValueError, "filterManager.addFilter(index, type, fragmentProgram): KX_2DFilterManager, type invalid"); + return nullptr; + } + + if (strlen(frag) > 0 && type != FILTER_CUSTOMFILTER) { + CM_PythonFunctionWarning("KX_2DFilterManager", "addFilter", "non-empty fragment program with non-custom filter type"); + } + + RAS_2DFilterData data; + data.filterPassIndex = index; + data.filterMode = type; + data.shaderText = std::string(frag); + + KX_2DFilter *filter = static_cast(AddFilter(data)); + + return filter->GetProxy(); +} + +EXP_PYMETHODDEF_DOC(KX_2DFilterManager, removeFilter, " removeFilter(index)") +{ + int index = 0; + + if (!PyArg_ParseTuple(args, "i:removeFilter", &index)) { + return nullptr; + } + + RemoveFilterPass(index); + + Py_RETURN_NONE; +} + +#endif // WITH_PYTHON diff --git a/source/gameengine/Expressions/EXP_HashedPtr.h b/source/gameengine/Ketsji/KX_2DFilterManager.h similarity index 53% rename from source/gameengine/Expressions/EXP_HashedPtr.h rename to source/gameengine/Ketsji/KX_2DFilterManager.h index fbb6762c351e..c4f0ed334716 100644 --- a/source/gameengine/Expressions/EXP_HashedPtr.h +++ b/source/gameengine/Ketsji/KX_2DFilterManager.h @@ -15,45 +15,38 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. + * Contributor(s): Ulysse Martin, Tristan Porteries. * * ***** END GPL LICENSE BLOCK ***** */ -/** \file EXP_HashedPtr.h - * \ingroup expressions - */ +/** \file KX_2DFilterManager.h +* \ingroup ketsji +*/ -#ifndef __EXP_HASHEDPTR_H__ -#define __EXP_HASHEDPTR_H__ +#ifndef __KX_2DFILTER_MANAGER_H__ +#define __KX_2DFILTER_MANAGER_H__ -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif +#include "RAS_2DFilterManager.h" +#include "EXP_PyObjectPlus.h" -class CHashedPtr +class KX_2DFilterManager : public RAS_2DFilterManager, public EXP_PyObjectPlus { - void* m_valptr; - + Py_Header public: - CHashedPtr(void* val); + KX_2DFilterManager(); + virtual ~KX_2DFilterManager(); - unsigned int hash() const; + virtual RAS_2DFilter *NewFilter(RAS_2DFilterData& filterData); - inline friend bool operator ==( const CHashedPtr & rhs,const CHashedPtr & lhs) - { - return rhs.m_valptr == lhs.m_valptr; - } +#ifdef WITH_PYTHON + EXP_PYMETHOD_DOC(KX_2DFilterManager, getFilter); + EXP_PYMETHOD_DOC(KX_2DFilterManager, addFilter); + EXP_PYMETHOD_DOC(KX_2DFilterManager, removeFilter); + EXP_PYMETHOD_DOC(KX_2DFilterManager, createOffScreen); -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:CHashedPtr") -#endif +#endif // WITH_PYTHON }; -#endif /* __EXP_HASHEDPTR_H__ */ +#endif // __KX_2DFILTER_MANAGER_H__ diff --git a/source/gameengine/Ketsji/KX_2DFilterOffScreen.cpp b/source/gameengine/Ketsji/KX_2DFilterOffScreen.cpp new file mode 100644 index 000000000000..b78e163dba23 --- /dev/null +++ b/source/gameengine/Ketsji/KX_2DFilterOffScreen.cpp @@ -0,0 +1,116 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Ketsji/KX_2DFilterOffScreen.cpp + * \ingroup ketsji + */ + +#include "KX_2DFilterOffScreen.h" + +#include "EXP_ListWrapper.h" + +KX_2DFilterOffScreen::KX_2DFilterOffScreen(unsigned short colorSlots, Flag flag, unsigned int width, unsigned int height, + RAS_Rasterizer::HdrType hdr) + :RAS_2DFilterOffScreen(colorSlots, flag, width, height, hdr) +{ +} + +KX_2DFilterOffScreen::~KX_2DFilterOffScreen() +{ +} + +std::string KX_2DFilterOffScreen::GetName() +{ + return "KX_2DFilterOffScreen"; +} + +#ifdef WITH_PYTHON + +PyTypeObject KX_2DFilterOffScreen::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_2DFilterOffScreen", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &EXP_Value::Type, + 0, 0, 0, 0, 0, 0, + py_base_new +}; + +PyMethodDef KX_2DFilterOffScreen::Methods[] = { + {nullptr, nullptr} // Sentinel +}; + +PyAttributeDef KX_2DFilterOffScreen::Attributes[] = { + EXP_PYATTRIBUTE_RO_FUNCTION("width", KX_2DFilterOffScreen, pyattr_get_width), + EXP_PYATTRIBUTE_RO_FUNCTION("height", KX_2DFilterOffScreen, pyattr_get_height), + EXP_PYATTRIBUTE_RO_FUNCTION("colorBindCodes", KX_2DFilterOffScreen, pyattr_get_colorBindCodes), + EXP_PYATTRIBUTE_RO_FUNCTION("depthBindCode", KX_2DFilterOffScreen, pyattr_get_depthBindCode), + EXP_PYATTRIBUTE_NULL // Sentinel +}; + +PyObject *KX_2DFilterOffScreen::pyattr_get_width(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_2DFilterOffScreen *self = static_cast(self_v); + return PyLong_FromLong(self->GetWidth()); +} + +PyObject *KX_2DFilterOffScreen::pyattr_get_height(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_2DFilterOffScreen *self = static_cast(self_v); + return PyLong_FromLong(self->GetHeight()); +} + +unsigned int KX_2DFilterOffScreen::py_get_textures_size() +{ + return RAS_2DFilterOffScreen::NUM_COLOR_SLOTS; +} + +PyObject *KX_2DFilterOffScreen::py_get_textures_item(unsigned int index) +{ + const int bindCode = GetColorBindCode(index); + return PyLong_FromLong(bindCode); +} + +PyObject *KX_2DFilterOffScreen::pyattr_get_colorBindCodes(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + return (new EXP_ListWrapper(self_v))->NewProxy(true); +} + +PyObject *KX_2DFilterOffScreen::pyattr_get_depthBindCode(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_2DFilterOffScreen *self = static_cast(self_v); + return PyLong_FromLong(self->GetDepthBindCode()); +} + +#endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_2DFilterOffScreen.h b/source/gameengine/Ketsji/KX_2DFilterOffScreen.h new file mode 100644 index 000000000000..4afcd0cf3512 --- /dev/null +++ b/source/gameengine/Ketsji/KX_2DFilterOffScreen.h @@ -0,0 +1,55 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file KX_2DFilter.h +* \ingroup ketsji +*/ + +#ifndef __KX_2DFILTER_OFFSCREEN_H__ +#define __KX_2DFILTER_OFFSCREEN_H__ + +#include "RAS_2DFilterOffScreen.h" +#include "EXP_Value.h" + +class KX_2DFilterOffScreen : public EXP_Value, public RAS_2DFilterOffScreen +{ + Py_Header +public: + KX_2DFilterOffScreen(unsigned short colorSlots, Flag flag, unsigned int width, unsigned int height, RAS_Rasterizer::HdrType hdr); + virtual ~KX_2DFilterOffScreen(); + + virtual std::string GetName(); + +#ifdef WITH_PYTHON + + static PyObject *pyattr_get_width(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_height(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_colorBindCodes(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_depthBindCode(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + + unsigned int py_get_textures_size(); + PyObject *py_get_textures_item(unsigned int index); + +#endif +}; + +#endif // __KX_2DFILTER_OFFSCREEN_H__ diff --git a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp b/source/gameengine/Ketsji/KX_AddObjectActuator.cpp similarity index 50% rename from source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp rename to source/gameengine/Ketsji/KX_AddObjectActuator.cpp index 9a94dccdd4e8..45b347fcfdda 100644 --- a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_AddObjectActuator.cpp @@ -25,7 +25,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file gameengine/Ketsji/KX_SCA_AddObjectActuator.cpp +/** \file gameengine/Ketsji/KX_AddObjectActuator.cpp * \ingroup ketsji * * Add an object when this actuator is triggered @@ -35,65 +35,56 @@ * \source\gameengine\GameLogic\SCA_AddObjectActuator.cpp * Please look here for revision history. */ -#include "KX_SCA_AddObjectActuator.h" -#include "SCA_IScene.h" +#include "KX_AddObjectActuator.h" +#include "KX_Scene.h" #include "KX_GameObject.h" -#include "EXP_PyObjectPlus.h" /* ------------------------------------------------------------------------- */ /* Native functions */ /* ------------------------------------------------------------------------- */ -KX_SCA_AddObjectActuator::KX_SCA_AddObjectActuator(SCA_IObject *gameobj, - SCA_IObject *original, - int time, - SCA_IScene* scene, - const float *linvel, - bool linv_local, - const float *angvel, - bool angv_local) - : - SCA_IActuator(gameobj, KX_ACT_ADD_OBJECT), +KX_AddObjectActuator::KX_AddObjectActuator(KX_GameObject *gameobj, KX_GameObject *original, float time, KX_Scene* scene, + const mt::vec3& linvel, bool linv_local, const mt::vec3& angvel, bool angv_local) + :SCA_IActuator(gameobj, KX_ACT_ADD_OBJECT), m_OriginalObject(original), m_scene(scene), - + m_linear_velocity(linvel), m_localLinvFlag(linv_local), + m_angular_velocity(angvel), m_localAngvFlag(angv_local) { - m_linear_velocity[0] = linvel[0]; - m_linear_velocity[1] = linvel[1]; - m_linear_velocity[2] = linvel[2]; - m_angular_velocity[0] = angvel[0]; - m_angular_velocity[1] = angvel[1]; - m_angular_velocity[2] = angvel[2]; - - if (m_OriginalObject) + if (m_OriginalObject) { m_OriginalObject->RegisterActuator(this); + } - m_lastCreatedObject = NULL; + m_lastCreatedObject = nullptr; m_timeProp = time; } -KX_SCA_AddObjectActuator::~KX_SCA_AddObjectActuator() +KX_AddObjectActuator::~KX_AddObjectActuator() { - if (m_OriginalObject) + if (m_OriginalObject) { m_OriginalObject->UnregisterActuator(this); - if (m_lastCreatedObject) + } + if (m_lastCreatedObject) { m_lastCreatedObject->UnregisterActuator(this); + } } -bool KX_SCA_AddObjectActuator::Update() +bool KX_AddObjectActuator::Update() { //bool result = false; /*unused*/ bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); - if (bNegativeEvent) return false; // do nothing on negative events + if (bNegativeEvent) { + return false; // do nothing on negative events + } InstantAddObject(); @@ -103,19 +94,20 @@ bool KX_SCA_AddObjectActuator::Update() -SCA_IObject* KX_SCA_AddObjectActuator::GetLastCreatedObject() const +KX_GameObject *KX_AddObjectActuator::GetLastCreatedObject() const { return m_lastCreatedObject; } -CValue* KX_SCA_AddObjectActuator::GetReplica() +EXP_Value *KX_AddObjectActuator::GetReplica() { - KX_SCA_AddObjectActuator* replica = new KX_SCA_AddObjectActuator(*this); + KX_AddObjectActuator *replica = new KX_AddObjectActuator(*this); - if (replica == NULL) - return NULL; + if (replica == nullptr) { + return nullptr; + } // this will copy properties and so on... replica->ProcessReplica(); @@ -123,38 +115,43 @@ CValue* KX_SCA_AddObjectActuator::GetReplica() return replica; } -void KX_SCA_AddObjectActuator::ProcessReplica() +void KX_AddObjectActuator::ProcessReplica() { - if (m_OriginalObject) + if (m_OriginalObject) { m_OriginalObject->RegisterActuator(this); - m_lastCreatedObject=NULL; + } + m_lastCreatedObject = nullptr; SCA_IActuator::ProcessReplica(); } -bool KX_SCA_AddObjectActuator::UnlinkObject(SCA_IObject* clientobj) +void KX_AddObjectActuator::Replace_IScene(SCA_IScene *val) +{ + m_scene = static_cast(val); +} + +bool KX_AddObjectActuator::UnlinkObject(SCA_IObject *clientobj) { - if (clientobj == m_OriginalObject) - { + if (clientobj == m_OriginalObject) { // this object is being deleted, we cannot continue to track it. - m_OriginalObject = NULL; + m_OriginalObject = nullptr; return true; } - if (clientobj == m_lastCreatedObject) - { + if (clientobj == m_lastCreatedObject) { // this object is being deleted, we cannot continue to track it. - m_lastCreatedObject = NULL; + m_lastCreatedObject = nullptr; return true; } return false; } -void KX_SCA_AddObjectActuator::Relink(CTR_Map *obj_map) +void KX_AddObjectActuator::Relink(std::map& obj_map) { - void **h_obj = (*obj_map)[m_OriginalObject]; - if (h_obj) { - if (m_OriginalObject) + SCA_IObject *obj = obj_map[m_OriginalObject]; + if (obj) { + if (m_OriginalObject) { m_OriginalObject->UnregisterActuator(this); - m_OriginalObject = (SCA_IObject*)(*h_obj); + } + m_OriginalObject = static_cast(obj); m_OriginalObject->RegisterActuator(this); } } @@ -166,10 +163,10 @@ void KX_SCA_AddObjectActuator::Relink(CTR_Map *obj_map) /* ------------------------------------------------------------------------- */ /* Integration hooks ------------------------------------------------------- */ -PyTypeObject KX_SCA_AddObjectActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "KX_SCA_AddObjectActuator", - sizeof(PyObjectPlus_Proxy), +PyTypeObject KX_AddObjectActuator::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_AddObjectActuator", + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -177,69 +174,76 @@ PyTypeObject KX_SCA_AddObjectActuator::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IActuator::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; -PyMethodDef KX_SCA_AddObjectActuator::Methods[] = { - {"instantAddObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyInstantAddObject, METH_NOARGS, NULL}, - {NULL,NULL} //Sentinel +PyMethodDef KX_AddObjectActuator::Methods[] = { + {"instantAddObject", (PyCFunction)KX_AddObjectActuator::sPyInstantAddObject, METH_NOARGS, nullptr}, + {nullptr, nullptr} //Sentinel }; -PyAttributeDef KX_SCA_AddObjectActuator::Attributes[] = { - KX_PYATTRIBUTE_RW_FUNCTION("object",KX_SCA_AddObjectActuator,pyattr_get_object,pyattr_set_object), - KX_PYATTRIBUTE_RO_FUNCTION("objectLastCreated",KX_SCA_AddObjectActuator,pyattr_get_objectLastCreated), - KX_PYATTRIBUTE_INT_RW("time",0,2000,true,KX_SCA_AddObjectActuator,m_timeProp), - KX_PYATTRIBUTE_FLOAT_ARRAY_RW("linearVelocity",-FLT_MAX,FLT_MAX,KX_SCA_AddObjectActuator,m_linear_velocity,3), - KX_PYATTRIBUTE_FLOAT_ARRAY_RW("angularVelocity",-FLT_MAX,FLT_MAX,KX_SCA_AddObjectActuator,m_angular_velocity,3), - { NULL } //Sentinel +PyAttributeDef KX_AddObjectActuator::Attributes[] = { + EXP_PYATTRIBUTE_RW_FUNCTION("object", KX_AddObjectActuator, pyattr_get_object, pyattr_set_object), + EXP_PYATTRIBUTE_RO_FUNCTION("objectLastCreated", KX_AddObjectActuator, pyattr_get_objectLastCreated), + EXP_PYATTRIBUTE_FLOAT_RW("time", 0.0f, FLT_MAX, KX_AddObjectActuator, m_timeProp), + EXP_PYATTRIBUTE_VECTOR_RW("linearVelocity", -FLT_MAX, FLT_MAX, KX_AddObjectActuator, m_linear_velocity, 3), + EXP_PYATTRIBUTE_VECTOR_RW("angularVelocity", -FLT_MAX, FLT_MAX, KX_AddObjectActuator, m_angular_velocity, 3), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *KX_SCA_AddObjectActuator::pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_AddObjectActuator::pyattr_get_object(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - KX_SCA_AddObjectActuator* actuator = static_cast(self); - if (!actuator->m_OriginalObject) + KX_AddObjectActuator *actuator = static_cast(self); + if (!actuator->m_OriginalObject) { Py_RETURN_NONE; - else + } + else { return actuator->m_OriginalObject->GetProxy(); + } } -int KX_SCA_AddObjectActuator::pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_AddObjectActuator::pyattr_set_object(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_SCA_AddObjectActuator* actuator = static_cast(self); + KX_AddObjectActuator *actuator = static_cast(self); KX_GameObject *gameobj; - if (!ConvertPythonToGameObject(actuator->GetLogicManager(), value, &gameobj, true, "actuator.object = value: KX_SCA_AddObjectActuator")) + if (!ConvertPythonToGameObject(actuator->GetLogicManager(), value, &gameobj, true, "actuator.object = value: KX_AddObjectActuator")) { return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error - if (actuator->m_OriginalObject != NULL) + } + if (actuator->m_OriginalObject != nullptr) { actuator->m_OriginalObject->UnregisterActuator(actuator); + } - actuator->m_OriginalObject = (SCA_IObject*)gameobj; + actuator->m_OriginalObject = gameobj; - if (actuator->m_OriginalObject) + if (actuator->m_OriginalObject) { actuator->m_OriginalObject->RegisterActuator(actuator); + } return PY_SET_ATTR_SUCCESS; } -PyObject *KX_SCA_AddObjectActuator::pyattr_get_objectLastCreated(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_AddObjectActuator::pyattr_get_objectLastCreated(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - KX_SCA_AddObjectActuator* actuator = static_cast(self); - if (!actuator->m_lastCreatedObject) + KX_AddObjectActuator *actuator = static_cast(self); + if (!actuator->m_lastCreatedObject) { Py_RETURN_NONE; - else + } + else { return actuator->m_lastCreatedObject->GetProxy(); + } } -PyObject *KX_SCA_AddObjectActuator::PyInstantAddObject() +PyObject *KX_AddObjectActuator::PyInstantAddObject() { InstantAddObject(); @@ -248,21 +252,17 @@ PyObject *KX_SCA_AddObjectActuator::PyInstantAddObject() #endif // WITH_PYTHON -void KX_SCA_AddObjectActuator::InstantAddObject() +void KX_AddObjectActuator::InstantAddObject() { - if (m_OriginalObject) - { + if (m_OriginalObject) { // Add an identical object, with properties inherited from the original object // Now it needs to be added to the current scene. - SCA_IObject* replica = m_scene->AddReplicaObject(m_OriginalObject,GetParent(),m_timeProp ); - KX_GameObject * game_obj = static_cast(replica); - game_obj->setLinearVelocity(m_linear_velocity, m_localLinvFlag); - game_obj->setAngularVelocity(m_angular_velocity,m_localAngvFlag); - game_obj->ResolveCombinedVelocities(m_linear_velocity, m_angular_velocity, m_localLinvFlag, m_localAngvFlag); + KX_GameObject *replica = m_scene->AddReplicaObject(m_OriginalObject, static_cast(GetParent()), m_timeProp); + replica->SetLinearVelocity(m_linear_velocity, m_localLinvFlag); + replica->SetAngularVelocity(m_angular_velocity, m_localAngvFlag); // keep a copy of the last object, to allow python scripters to change it - if (m_lastCreatedObject) - { + if (m_lastCreatedObject) { //Let's not keep a reference to the object: it's bad, if the object is deleted //this will force to keep a "zombie" in the game for no good reason. //m_scene->DelayedReleaseObject(m_lastCreatedObject); @@ -270,7 +270,7 @@ void KX_SCA_AddObjectActuator::InstantAddObject() //Instead we use the registration mechanism m_lastCreatedObject->UnregisterActuator(this); - m_lastCreatedObject = NULL; + m_lastCreatedObject = nullptr; } m_lastCreatedObject = replica; diff --git a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h b/source/gameengine/Ketsji/KX_AddObjectActuator.h similarity index 53% rename from source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h rename to source/gameengine/Ketsji/KX_AddObjectActuator.h index 8ab245b5df30..d0ef6550f37d 100644 --- a/source/gameengine/Ketsji/KX_SCA_AddObjectActuator.h +++ b/source/gameengine/Ketsji/KX_AddObjectActuator.h @@ -25,94 +25,78 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file KX_SCA_AddObjectActuator.h +/** \file KX_AddObjectActuator.h * \ingroup ketsji * \attention Previously existed as: source/gameengine/GameLogic/SCA_AddObjectActuator.h * Please look here for revision history. */ -#ifndef __KX_SCA_ADDOBJECTACTUATOR_H__ -#define __KX_SCA_ADDOBJECTACTUATOR_H__ +#ifndef __KX_ADDOBJECTACTUATOR_H__ +#define __KX_ADDOBJECTACTUATOR_H__ /* Actuator tree */ #include "SCA_IActuator.h" #include "SCA_LogicManager.h" -#include "MT_Vector3.h" +class KX_Scene; +class KX_GameObject; - -class SCA_IScene; - -class KX_SCA_AddObjectActuator : public SCA_IActuator +class KX_AddObjectActuator : public SCA_IActuator { Py_Header /// Time field: lifetime of the new object - int m_timeProp; + float m_timeProp; /// Original object reference (object to replicate) - SCA_IObject* m_OriginalObject; + KX_GameObject *m_OriginalObject; /// Object will be added to the following scene - SCA_IScene* m_scene; + KX_Scene *m_scene; - /// Linear velocity upon creation of the object. - float m_linear_velocity[3]; - /// Apply the velocity locally + /// Linear velocity upon creation of the object. + mt::vec3 m_linear_velocity; + /// Apply the velocity locally bool m_localLinvFlag; - - /// Angular velocity upon creation of the object. - float m_angular_velocity[3]; - /// Apply the velocity locally - bool m_localAngvFlag; - - - - - SCA_IObject* m_lastCreatedObject; - + + /// Angular velocity upon creation of the object. + mt::vec3 m_angular_velocity; + /// Apply the velocity locally + bool m_localAngvFlag; + + KX_GameObject* m_lastCreatedObject; + public: - /** + /** * This class also has the default constructors * available. Use with care! */ - KX_SCA_AddObjectActuator( - SCA_IObject *gameobj, - SCA_IObject *original, - int time, - SCA_IScene* scene, - const float *linvel, - bool linv_local, - const float *angvel, - bool angv_local - ); + KX_AddObjectActuator(KX_GameObject *gameobj, KX_GameObject *original, float time, KX_Scene* scene, + const mt::vec3& linvel, bool linv_local, const mt::vec3& angvel, bool angv_local); - ~KX_SCA_AddObjectActuator(void); + ~KX_AddObjectActuator(void); - CValue* + EXP_Value* GetReplica( ); - virtual void + virtual void ProcessReplica(); - virtual void Replace_IScene(SCA_IScene *val) - { - m_scene= val; - }; + virtual void Replace_IScene(SCA_IScene *val); - virtual bool + virtual bool UnlinkObject(SCA_IObject* clientobj); - virtual void - Relink(CTR_Map *obj_map); + virtual void + Relink(std::map& obj_map); - virtual bool + virtual bool Update(); - SCA_IObject * + KX_GameObject * GetLastCreatedObject( ) const; @@ -120,14 +104,14 @@ class KX_SCA_AddObjectActuator : public SCA_IActuator #ifdef WITH_PYTHON - KX_PYMETHOD_DOC_NOARGS(KX_SCA_AddObjectActuator,InstantAddObject); - - static PyObject *pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject *pyattr_get_objectLastCreated(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + EXP_PYMETHOD_DOC_NOARGS(KX_AddObjectActuator,InstantAddObject); + static PyObject *pyattr_get_object(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_object(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_objectLastCreated(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + #endif /* WITH_PYTHON */ -}; /* end of class KX_SCA_AddObjectActuator : public KX_EditObjectActuator */ +}; /* end of class KX_AddObjectActuator : public KX_EditObjectActuator */ -#endif /* __KX_SCA_ADDOBJECTACTUATOR_H__ */ +#endif /* __KX_ADDOBJECTACTUATOR_H__ */ diff --git a/source/gameengine/Ketsji/KX_ArmatureSensor.cpp b/source/gameengine/Ketsji/KX_ArmatureSensor.cpp index c111a4de0eb7..a2bf2401db77 100644 --- a/source/gameengine/Ketsji/KX_ArmatureSensor.cpp +++ b/source/gameengine/Ketsji/KX_ArmatureSensor.cpp @@ -43,14 +43,14 @@ #include "SCA_EventManager.h" #include "SCA_LogicManager.h" -KX_ArmatureSensor::KX_ArmatureSensor(class SCA_EventManager* eventmgr, - SCA_IObject* gameobj, - const char *posechannel, - const char *constraintname, - int type, - float value) - : SCA_ISensor(gameobj,eventmgr), - m_constraint(NULL), +KX_ArmatureSensor::KX_ArmatureSensor(class SCA_EventManager *eventmgr, + SCA_IObject *gameobj, + const std::string& posechannel, + const std::string& constraintname, + int type, + float value) + :SCA_ISensor(gameobj, eventmgr), + m_constraint(nullptr), m_posechannel(posechannel), m_constraintname(constraintname), m_type(type), @@ -61,30 +61,31 @@ KX_ArmatureSensor::KX_ArmatureSensor(class SCA_EventManager* eventmgr, void KX_ArmatureSensor::Init() { - m_lastresult = m_invert?true:false; + m_lastresult = m_invert ? true : false; m_result = false; m_reset = true; } void KX_ArmatureSensor::FindConstraint() { - m_constraint = NULL; + m_constraint = nullptr; if (m_gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) { - BL_ArmatureObject* armobj = (BL_ArmatureObject*)m_gameobj; + BL_ArmatureObject *armobj = (BL_ArmatureObject *)m_gameobj; // get the persistent pose structure - bPose* pose = armobj->GetOrigPose(); - bPoseChannel* pchan; - bConstraint* pcon; + bPose *pose = armobj->GetPose(); + bPoseChannel *pchan; + bConstraint *pcon; // and locate the constraint - for (pchan = (bPoseChannel*)pose->chanbase.first; pchan; pchan=(bPoseChannel*)pchan->next) { - if (!strcmp(pchan->name, m_posechannel)) { + for (pchan = (bPoseChannel *)pose->chanbase.first; pchan; pchan = (bPoseChannel *)pchan->next) { + if (pchan->name == m_posechannel) { // now locate the constraint for (pcon = (bConstraint *)pchan->constraints.first; pcon; pcon = (bConstraint *)pcon->next) { - if (!strcmp(pcon->name, m_constraintname)) { - if (pcon->flag & CONSTRAINT_DISABLE) + if (pcon->name == m_constraintname) { + if (pcon->flag & CONSTRAINT_DISABLE) { /* this constraint is not valid, can't use it */ break; + } m_constraint = pcon; break; } @@ -96,15 +97,15 @@ void KX_ArmatureSensor::FindConstraint() } -CValue* KX_ArmatureSensor::GetReplica() +EXP_Value *KX_ArmatureSensor::GetReplica() { - KX_ArmatureSensor* replica = new KX_ArmatureSensor(*this); + KX_ArmatureSensor *replica = new KX_ArmatureSensor(*this); // m_range_expr must be recalculated on replica! replica->ProcessReplica(); return replica; } -void KX_ArmatureSensor::ReParent(SCA_IObject* parent) +void KX_ArmatureSensor::ReParent(SCA_IObject *parent) { SCA_ISensor::ReParent(parent); // must remap the constraint @@ -126,27 +127,37 @@ bool KX_ArmatureSensor::Evaluate() bool reset = m_reset && m_level; m_reset = false; - if (!m_constraint) + if (!m_constraint) { return false; + } switch (m_type) { - case SENS_ARM_STATE_CHANGED: - m_result = !(m_constraint->flag & CONSTRAINT_OFF); - break; - case SENS_ARM_LIN_ERROR_BELOW: - m_result = (m_constraint->lin_error < m_value); - break; - case SENS_ARM_LIN_ERROR_ABOVE: - m_result = (m_constraint->lin_error > m_value); - break; - case SENS_ARM_ROT_ERROR_BELOW: - m_result = (m_constraint->rot_error < m_value); - break; - case SENS_ARM_ROT_ERROR_ABOVE: - m_result = (m_constraint->rot_error > m_value); - break; + case SENS_ARM_STATE_CHANGED: + { + m_result = !(m_constraint->flag & CONSTRAINT_OFF); + break; + } + case SENS_ARM_LIN_ERROR_BELOW: + { + m_result = (m_constraint->lin_error < m_value); + break; + } + case SENS_ARM_LIN_ERROR_ABOVE: + { + m_result = (m_constraint->lin_error > m_value); + break; + } + case SENS_ARM_ROT_ERROR_BELOW: + { + m_result = (m_constraint->rot_error < m_value); + break; + } + case SENS_ARM_ROT_ERROR_ABOVE: + { + m_result = (m_constraint->rot_error > m_value); + break; + } } - if (m_lastresult!=m_result) - { + if (m_lastresult != m_result) { m_lastresult = m_result; return true; } @@ -161,9 +172,9 @@ bool KX_ArmatureSensor::Evaluate() /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_ArmatureSensor::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_ArmatureSensor", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -171,36 +182,37 @@ PyTypeObject KX_ArmatureSensor::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_ISensor::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_ArmatureSensor::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_ArmatureSensor::Attributes[] = { - KX_PYATTRIBUTE_RO_FUNCTION("constraint", KX_ArmatureSensor, pyattr_get_constraint), - KX_PYATTRIBUTE_FLOAT_RW("value",-FLT_MAX,FLT_MAX,KX_ArmatureSensor,m_value), - KX_PYATTRIBUTE_INT_RW("type",0,SENS_ARM_MAXTYPE,false,KX_ArmatureSensor,m_type), - { NULL } //Sentinel + EXP_PYATTRIBUTE_RO_FUNCTION("constraint", KX_ArmatureSensor, pyattr_get_constraint), + EXP_PYATTRIBUTE_FLOAT_RW("value", -FLT_MAX, FLT_MAX, KX_ArmatureSensor, m_value), + EXP_PYATTRIBUTE_INT_RW("type", 0, SENS_ARM_MAXTYPE, false, KX_ArmatureSensor, m_type), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *KX_ArmatureSensor::pyattr_get_constraint(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_ArmatureSensor::pyattr_get_constraint(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - KX_ArmatureSensor* sensor = static_cast(self); + KX_ArmatureSensor *sensor = static_cast(self); if (sensor->m_gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) { - BL_ArmatureObject* armobj = (BL_ArmatureObject*)sensor->m_gameobj; - BL_ArmatureConstraint* constraint = armobj->GetConstraint(sensor->m_posechannel, sensor->m_constraintname); - if (constraint) + BL_ArmatureObject *armobj = (BL_ArmatureObject *)sensor->m_gameobj; + BL_ArmatureConstraint *constraint = armobj->GetConstraint(sensor->m_posechannel, sensor->m_constraintname); + if (constraint) { return constraint->GetProxy(); + } } Py_RETURN_NONE; } diff --git a/source/gameengine/Ketsji/KX_ArmatureSensor.h b/source/gameengine/Ketsji/KX_ArmatureSensor.h index 5b90ea4de2a6..5de4c9397e71 100644 --- a/source/gameengine/Ketsji/KX_ArmatureSensor.h +++ b/source/gameengine/Ketsji/KX_ArmatureSensor.h @@ -41,24 +41,24 @@ struct bConstraint; class KX_ArmatureSensor : public SCA_ISensor { Py_Header - //class CExpression* m_rightexpr; + //class EXP_Expression* m_rightexpr; protected: public: KX_ArmatureSensor(class SCA_EventManager* eventmgr, SCA_IObject* gameobj, - const char *posechannel, - const char *constraintname, + const std::string& posechannel, + const std::string& constraintname, int type, float value); - - /** + + /** * For property sensor, it is used to release the pre-calculated expression * so that self references are removed before the sensor itself is released */ virtual ~KX_ArmatureSensor(); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); virtual void ReParent(SCA_IObject* parent); virtual void Init(); virtual bool Evaluate(); @@ -72,14 +72,14 @@ class KX_ArmatureSensor : public SCA_ISensor /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - static PyObject *pyattr_get_constraint(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_constraint(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); #endif /* WITH_PYTHON */ private: struct bConstraint* m_constraint; - STR_String m_posechannel; - STR_String m_constraintname; + std::string m_posechannel; + std::string m_constraintname; int m_type; float m_value; bool m_result; @@ -87,3 +87,4 @@ class KX_ArmatureSensor : public SCA_ISensor }; #endif + diff --git a/source/gameengine/Ketsji/KX_BatchGroup.cpp b/source/gameengine/Ketsji/KX_BatchGroup.cpp new file mode 100644 index 000000000000..7a5815f6ab51 --- /dev/null +++ b/source/gameengine/Ketsji/KX_BatchGroup.cpp @@ -0,0 +1,319 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Ketsji/KX_BatchGroup.cpp + * \ingroup ketsji + */ + +#include "KX_BatchGroup.h" +#include "KX_GameObject.h" +#include "KX_Globals.h" +#include "RAS_MeshUser.h" + +#include "CM_Message.h" + +KX_BatchGroup::KX_BatchGroup() + :m_referenceObject(nullptr) +{ + m_objects = new EXP_ListValue(); + // The objects are not owned by the batching group, so not released on list releasing. + m_objects->SetReleaseOnDestruct(false); +} + +KX_BatchGroup::~KX_BatchGroup() +{ + m_objects->Release(); +} + +std::string KX_BatchGroup::GetName() +{ + return "KX_BatchGroup"; +} + +EXP_ListValue *KX_BatchGroup::GetObjects() const +{ + return m_objects; +} + +KX_GameObject *KX_BatchGroup::GetReferenceObject() const +{ + return m_referenceObject; +} + +bool KX_BatchGroup::SetReferenceObject(KX_GameObject *object) +{ + if (object) { + RAS_MeshUser *meshUser = object->GetMeshUser(); + if (!meshUser) { + CM_Error("object \"" << object->GetName() << "\" doesn't contain a mesh"); + return false; + } + if (meshUser->GetBatchGroup() != this) { + CM_Error("object \"" << object->GetName() << "\" is not a part of this batch group"); + return false; + } + } + + m_referenceObject = object; + SetReferenceMeshUser(object ? object->GetMeshUser() : nullptr); + + return true; +} + +void KX_BatchGroup::MergeObjects(const std::vector& objects) +{ + for (KX_GameObject *gameobj : objects) { + RAS_MeshUser *meshUser = gameobj->GetMeshUser(); + + if (!meshUser) { + CM_Error("object \"" << gameobj->GetName() << "\" doesn't contain a mesh"); + continue; + } + + if (meshUser->GetBatchGroup()) { + CM_Error("object \"" << gameobj->GetName() << "\" already used in a batch group"); + continue; + } + + mt::mat3x4 trans(gameobj->NodeGetWorldOrientation(), gameobj->NodeGetWorldPosition(), gameobj->NodeGetWorldScaling()); + + if (MergeMeshUser(meshUser, mt::mat4::FromAffineTransform(trans))) { + m_objects->Add(gameobj); + } + else { + CM_Error("failed merge object \"" << gameobj->GetName() << "\""); + } + } +} + +void KX_BatchGroup::SplitObjects(const std::vector& objects) +{ + // Add a fake mesh user to avoid free the batch group while running the function. + AddMeshUser(); + + for (KX_GameObject *gameobj : objects) { + RAS_MeshUser *meshUser = gameobj->GetMeshUser(); + + if (!meshUser) { + CM_Error("object \"" << gameobj->GetName() << "\" doesn't contain a mesh"); + continue; + } + + if (SplitMeshUser(meshUser)) { + m_objects->RemoveValue(gameobj); + if (gameobj == m_referenceObject) { + SetReferenceObject(nullptr); + } + } + else { + CM_Error("failed split object \"" << gameobj->GetName() << "\""); + } + } + + // Update the reference mesh user if it was splitted. + if (!m_objects->Empty() && !m_referenceObject) { + // Use the first object as reference for layer and color. + KX_GameObject *firstObject = m_objects->GetFront(); + SetReferenceObject(firstObject); + } + + RemoveMeshUser(); +} + +#ifdef WITH_PYTHON + +static PyObject *py_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *pylist; + + if (!PyArg_ParseTuple(args, "O:KX_BatchGroup", &pylist)) { + return nullptr; + } + + if (!PyList_Check(pylist)) { + PyErr_SetString(PyExc_SystemError, "KX_BatchGroup(objects): expected a list"); + return nullptr; + } + + std::vector objects; + + for (unsigned short i = 0; i < PyList_GET_SIZE(pylist); ++i) { + PyObject *pyobj = PyList_GET_ITEM(pylist, i); + KX_GameObject *gameobj; + + if (!ConvertPythonToGameObject(KX_GetActiveScene()->GetLogicManager(), pyobj, &gameobj, false, "KX_BatchGroup(objects)")) { + return nullptr; + } + + objects.push_back(gameobj); + } + + KX_BatchGroup *batchGroup = new KX_BatchGroup(); + batchGroup->MergeObjects(objects); + + EXP_ListValue *mergedObjects = batchGroup->GetObjects(); + if (mergedObjects->Empty()) { + PyErr_SetString(PyExc_SystemError, "KX_BatchGroup(objects): none objects were merged."); + delete batchGroup; + return nullptr; + } + + // Use the first object as reference for layer and color. + KX_GameObject *firstObject = mergedObjects->GetFront(); + batchGroup->SetReferenceObject(firstObject); + + return batchGroup->GetProxy(); +} + +PyTypeObject KX_BatchGroup::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_BatchGroup", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &EXP_PyObjectPlus::Type, + 0, 0, 0, 0, 0, 0, + py_new +}; + +PyMethodDef KX_BatchGroup::Methods[] = { + EXP_PYMETHODTABLE(KX_BatchGroup, merge), + EXP_PYMETHODTABLE(KX_BatchGroup, split), + EXP_PYMETHODTABLE(KX_BatchGroup, destruct), + {nullptr, nullptr} // Sentinel +}; + +PyAttributeDef KX_BatchGroup::Attributes[] = { + EXP_PYATTRIBUTE_RO_FUNCTION("objects", KX_BatchGroup, pyattr_get_objects), + EXP_PYATTRIBUTE_RW_FUNCTION("referenceObject", KX_BatchGroup, pyattr_get_referenceObject, pyattr_set_referenceObject), + EXP_PYATTRIBUTE_NULL // Sentinel +}; + +PyObject *KX_BatchGroup::pyattr_get_objects(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_BatchGroup *self = static_cast(self_v); + return self->GetObjects()->GetProxy(); +} + +PyObject *KX_BatchGroup::pyattr_get_referenceObject(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_BatchGroup *self = static_cast(self_v); + return self->GetReferenceObject()->GetProxy(); +} + +int KX_BatchGroup::pyattr_set_referenceObject(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_BatchGroup *self = static_cast(self_v); + + KX_GameObject *object; + if (!ConvertPythonToGameObject(KX_GetActiveScene()->GetLogicManager(), + value, &object, false, "KX_BatchGroup.referenceObject")) + { + return PY_SET_ATTR_FAIL; + } + + if (self->SetReferenceObject(object)) { + return PY_SET_ATTR_SUCCESS; + } + + return PY_SET_ATTR_FAIL; +} + +EXP_PYMETHODDEF_DOC(KX_BatchGroup, merge, "merge(objects)") +{ + PyObject *pylist; + if (!PyArg_ParseTuple(args, "O:merge", &pylist)) { + return nullptr; + } + + if (!PyList_Check(pylist)) { + PyErr_SetString(PyExc_SystemError, "batch.merge(objects): expected a list"); + return nullptr; + } + + std::vector objects; + + for (unsigned short i = 0; i < PyList_GET_SIZE(pylist); ++i) { + PyObject *pyobj = PyList_GET_ITEM(pylist, i); + KX_GameObject *gameobj; + + if (!ConvertPythonToGameObject(KX_GetActiveScene()->GetLogicManager(), pyobj, &gameobj, false, "batch.merge(objects)")) { + return nullptr; + } + + objects.push_back(gameobj); + } + + MergeObjects(objects); + + Py_RETURN_NONE; +} + +EXP_PYMETHODDEF_DOC(KX_BatchGroup, split, "split(objects)") +{ + PyObject *pylist; + if (!PyArg_ParseTuple(args, "O:split", &pylist)) { + return nullptr; + } + + if (!PyList_Check(pylist)) { + PyErr_SetString(PyExc_SystemError, "batch.split(objects): expected a list"); + return nullptr; + } + + std::vector objects; + + for (unsigned short i = 0; i < PyList_GET_SIZE(pylist); ++i) { + PyObject *pyobj = PyList_GET_ITEM(pylist, i); + KX_GameObject *gameobj; + + if (!ConvertPythonToGameObject(KX_GetActiveScene()->GetLogicManager(), pyobj, &gameobj, false, "batch.split(objects)")) { + return nullptr; + } + + objects.push_back(gameobj); + } + + SplitObjects(objects); + + Py_RETURN_NONE; +} + +EXP_PYMETHODDEF_DOC(KX_BatchGroup, destruct, "destruct()") +{ + Destruct(); + + Py_RETURN_NONE; +} + +#endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_BatchGroup.h b/source/gameengine/Ketsji/KX_BatchGroup.h new file mode 100644 index 000000000000..ae012625b55b --- /dev/null +++ b/source/gameengine/Ketsji/KX_BatchGroup.h @@ -0,0 +1,81 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file KX_BatchGroup.h +* \ingroup ketsji +*/ + +#ifndef __KX_BATCH_GROUP_H__ +#define __KX_BATCH_GROUP_H__ + +#include "RAS_BatchGroup.h" +#include "EXP_Value.h" + +class KX_GameObject; +template +class EXP_ListValue; + +class KX_BatchGroup : public EXP_Value, public RAS_BatchGroup +{ + Py_Header +private: + /// The objects currently merged in the batch group. + EXP_ListValue *m_objects; + /// Reference object used to retrieve layer and color. + KX_GameObject *m_referenceObject; + +public: + KX_BatchGroup(); + virtual ~KX_BatchGroup(); + + virtual std::string GetName(); + + EXP_ListValue *GetObjects() const; + + KX_GameObject *GetReferenceObject() const; + /// Set reference object with error checking. Return false on error. + bool SetReferenceObject(KX_GameObject *object); + + /** Merge a list of objects using their mesh user and transformation. + * \param objects The list of objects to merge. + */ + void MergeObjects(const std::vector& objects); + + /** Split a list of objects. + * \param objects The object to split, remove. + */ + void SplitObjects(const std::vector& objects); + +#ifdef WITH_PYTHON + + static PyObject *pyattr_get_objects(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_referenceObject(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_referenceObject(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + + EXP_PYMETHOD_DOC(KX_BatchGroup, merge); + EXP_PYMETHOD_DOC(KX_BatchGroup, split); + EXP_PYMETHOD_DOC(KX_BatchGroup, destruct); + +#endif +}; + +#endif // __KX_BATCH_GROUP_H__ diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp index 80ac8d9693f2..81d8fd42ce25 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp @@ -22,843 +22,437 @@ * \ingroup ketsji */ -#include "GPU_glew.h" - #include "KX_BlenderMaterial.h" -#include "BL_Material.h" #include "KX_Scene.h" -#include "KX_Light.h" -#include "KX_GameObject.h" -#include "KX_MeshProxy.h" #include "KX_PyMath.h" -#include "MT_Vector3.h" -#include "MT_Vector4.h" -#include "MT_Matrix4x4.h" +#include "BL_Shader.h" +#include "BL_BlenderShader.h" + +#include "EXP_ListWrapper.h" #include "RAS_BucketManager.h" -#include "RAS_MeshObject.h" -#include "RAS_IRasterizer.h" +#include "RAS_Rasterizer.h" +#include "RAS_MeshUser.h" #include "GPU_draw.h" +#include "GPU_material.h" // for GPU_BLEND_SOLID -#include "STR_HashedString.h" - -// ------------------------------------ -#include "DNA_object_types.h" #include "DNA_material_types.h" -#include "DNA_image_types.h" -#include "DNA_meshdata_types.h" -#include "BKE_mesh.h" -// ------------------------------------ -#include "BLI_utildefines.h" -#include "BLI_math.h" - -#define spit(x) std::cout << x << std::endl; - -BL_Shader *KX_BlenderMaterial::mLastShader = NULL; -BL_BlenderShader *KX_BlenderMaterial::mLastBlenderShader = NULL; - -//static PyObject *gTextureDict = 0; - -KX_BlenderMaterial::KX_BlenderMaterial() -: PyObjectPlus(), - RAS_IPolyMaterial(), - mMaterial(NULL), - mShader(0), - mBlenderShader(0), - mScene(NULL), - mUserDefBlend(0), - mModified(0), - mConstructed(false), - mPass(0) -{ -} - -void KX_BlenderMaterial::Initialize( - KX_Scene *scene, - BL_Material *data, - GameSettings *game, - int lightlayer) -{ - RAS_IPolyMaterial::Initialize( - data->texname[0], - data->matname, - data->materialindex, - data->tile, - data->tilexrep[0], - data->tileyrep[0], - data->alphablend, - ((data->ras_mode &ALPHA)!=0), - ((data->ras_mode &ZSORT)!=0), - ((data->ras_mode &USE_LIGHT)!=0), - ((data->ras_mode &TEX)), - game - ); - Material *ma = data->material; +#include "DNA_scene_types.h" +KX_BlenderMaterial::KX_BlenderMaterial(Material *mat, const std::string& name, KX_Scene *scene) + :RAS_IMaterial(name), + m_material(mat), + m_shader(nullptr), + m_blenderShader(nullptr), + m_scene(scene), + m_userDefBlend(false) +{ // Save material data to restore on exit - mSavedData.r = ma->r; - mSavedData.g = ma->g; - mSavedData.b = ma->b; - mSavedData.a = ma->alpha; - mSavedData.specr = ma->specr; - mSavedData.specg = ma->specg; - mSavedData.specb = ma->specb; - mSavedData.spec = ma->spec; - mSavedData.ref = ma->ref; - mSavedData.hardness = ma->har; - mSavedData.emit = ma->emit; - - mMaterial = data; - mShader = 0; - mBlenderShader = 0; - mScene = scene; - mUserDefBlend = 0; - mModified = 0; - mConstructed = false; - mPass = 0; - mLightLayer = lightlayer; - // -------------------------------- - // RAS_IPolyMaterial variables... - m_flag |= RAS_BLENDERMAT; - m_flag |= (mMaterial->IdMode>=ONETEX)? RAS_MULTITEX: 0; - m_flag |= ((mMaterial->ras_mode & USE_LIGHT)!=0)? RAS_MULTILIGHT: 0; - m_flag |= (mMaterial->glslmat)? RAS_BLENDERGLSL: 0; - m_flag |= ((mMaterial->ras_mode & CAST_SHADOW)!=0)? RAS_CASTSHADOW: 0; - m_flag |= ((mMaterial->ras_mode & ONLY_SHADOW)!=0)? RAS_ONLYSHADOW: 0; - - // test the sum of the various modes for equality - // so we can ether accept or reject this material - // as being equal, this is rather important to - // prevent material bleeding - for (int i=0; iflag[i] + mMaterial->blend_mode[i]); + m_savedData.r = m_material->r; + m_savedData.g = m_material->g; + m_savedData.b = m_material->b; + m_savedData.a = m_material->alpha; + m_savedData.specr = m_material->specr; + m_savedData.specg = m_material->specg; + m_savedData.specb = m_material->specb; + m_savedData.spec = m_material->spec; + m_savedData.ref = m_material->ref; + m_savedData.hardness = m_material->har; + m_savedData.emit = m_material->emit; + m_savedData.ambient = m_material->amb; + m_savedData.specularalpha = m_material->spectra; + + m_alphablend = mat->game.alpha_blend; + + // with ztransp enabled, enforce alpha blending mode + if ((mat->mode & MA_TRANSP) && (mat->mode & MA_ZTRANSP) && (m_alphablend == GEMAT_SOLID)) { + m_alphablend = GEMAT_ALPHA; + } + + m_zoffset = mat->zoffs; + + m_rasMode |= (mat->game.flag & GEMAT_INVISIBLE) ? 0 : RAS_VISIBLE; + m_rasMode |= (mat->game.flag & GEMAT_NOPHYSICS) ? 0 : RAS_COLLIDER; + m_rasMode |= (mat->game.flag & GEMAT_BACKCULL) ? 0 : RAS_TWOSIDED; + m_rasMode |= (mat->material_type == MA_TYPE_WIRE) ? RAS_WIRE : 0; + m_rasMode |= (mat->mode2 & MA_DEPTH_TRANSP) ? RAS_DEPTH_ALPHA : 0; + + if (ELEM(m_alphablend, GEMAT_CLIP, GEMAT_ALPHA_TO_COVERAGE)) { + m_rasMode |= RAS_ALPHA_SHADOW; + } + // always zsort alpha + add + else if (ELEM(m_alphablend, GEMAT_ALPHA, GEMAT_ALPHA_SORT, GEMAT_ADD)) { + m_rasMode |= RAS_ALPHA; + m_rasMode |= (mat && (mat->game.alpha_blend & GEMAT_ALPHA_SORT)) ? RAS_ZSORT : 0; + } + + switch (mat->game.face_orientation) { + case GEMAT_NORMAL: + { + m_drawingMode = RAS_NORMAL; + break; + } + case GEMAT_BILLBOARD: + { + m_drawingMode = RAS_BILLBOARD; + break; + } + case GEMAT_HALO: + { + m_drawingMode = RAS_HALO; + break; + } + case GEMAT_SHADOW: + { + m_drawingMode = RAS_SHADOW; + break; + } } - m_multimode += mMaterial->IdMode+ (mMaterial->ras_mode & ~(USE_LIGHT)); + + m_flag |= ((mat->mode & MA_SHLESS) != 0) ? 0 : RAS_MULTILIGHT; + m_flag |= ((mat->mode2 & MA_CASTSHADOW) != 0) ? RAS_CASTSHADOW : 0; + m_flag |= ((mat->mode & MA_ONLYCAST) != 0) ? RAS_ONLYSHADOW : 0; + + m_passIndex = mat->index; + + m_blendFunc[0] = RAS_Rasterizer::RAS_ZERO; + m_blendFunc[1] = RAS_Rasterizer::RAS_ZERO; } KX_BlenderMaterial::~KX_BlenderMaterial() { - Material *ma = mMaterial->material; // Restore Blender material data - ma->r = mSavedData.r; - ma->g = mSavedData.g; - ma->b = mSavedData.b; - ma->alpha = mSavedData.a; - ma->specr = mSavedData.specr; - ma->specg = mSavedData.specg; - ma->specb = mSavedData.specb; - ma->spec = mSavedData.spec; - ma->ref = mSavedData.ref; - ma->har = mSavedData.hardness; - ma->emit = mSavedData.emit; - - // cleanup work - if (mConstructed) - // clean only if material was actually used - OnExit(); + m_material->r = m_savedData.r; + m_material->g = m_savedData.g; + m_material->b = m_savedData.b; + m_material->alpha = m_savedData.a; + m_material->specr = m_savedData.specr; + m_material->specg = m_savedData.specg; + m_material->specb = m_savedData.specb; + m_material->spec = m_savedData.spec; + m_material->ref = m_savedData.ref; + m_material->har = m_savedData.hardness; + m_material->emit = m_savedData.emit; + m_material->amb = m_savedData.ambient; + m_material->spectra = m_savedData.specularalpha; + + if (m_shader) { + delete m_shader; + m_shader = nullptr; + } + if (m_blenderShader) { + delete m_blenderShader; + m_blenderShader = nullptr; + } + + /* used to call with 'm_material->tface' but this can be a freed array, + * see: [#30493], so just call with nullptr, this is best since it clears + * the 'lastface' pointer in GPU too - campbell */ + GPU_set_tpage(nullptr, 1, m_alphablend); } -MTexPoly *KX_BlenderMaterial::GetMTexPoly() const +const RAS_Rasterizer::BlendFunc *KX_BlenderMaterial::GetBlendFunc() const { - // fonts on polys - return &mMaterial->mtexpoly; + return m_blendFunc; } -unsigned int* KX_BlenderMaterial::GetMCol() const +void KX_BlenderMaterial::GetRGBAColor(unsigned char *rgba) const { - // fonts on polys - return mMaterial->rgb; + if (m_material) { + *rgba++ = (unsigned char)(m_material->r * 255.0f); + *rgba++ = (unsigned char)(m_material->g * 255.0f); + *rgba++ = (unsigned char)(m_material->b * 255.0f); + *rgba++ = (unsigned char)(m_material->alpha * 255.0f); + } + else { + RAS_IMaterial::GetRGBAColor(rgba); + } } -void KX_BlenderMaterial::GetMaterialRGBAColor(unsigned char *rgba) const +const std::string KX_BlenderMaterial::GetTextureName() const { - if (mMaterial) { - *rgba++ = (unsigned char)(mMaterial->matcolor[0] * 255.0f); - *rgba++ = (unsigned char)(mMaterial->matcolor[1] * 255.0f); - *rgba++ = (unsigned char)(mMaterial->matcolor[2] * 255.0f); - *rgba++ = (unsigned char)(mMaterial->matcolor[3] * 255.0f); - } else - RAS_IPolyMaterial::GetMaterialRGBAColor(rgba); + return (m_textures[0] ? m_textures[0]->GetName() : ""); } Material *KX_BlenderMaterial::GetBlenderMaterial() const { - return mMaterial->material; + return m_material; } -Image *KX_BlenderMaterial::GetBlenderImage() const +Scene *KX_BlenderMaterial::GetBlenderScene() const { - return mMaterial->mtexpoly.tpage; + return m_scene->GetBlenderScene(); } -Scene* KX_BlenderMaterial::GetBlenderScene() const +SCA_IScene *KX_BlenderMaterial::GetScene() const { - return mScene->GetBlenderScene(); + return m_scene; } -void KX_BlenderMaterial::ReleaseMaterial() +void KX_BlenderMaterial::ReloadMaterial() { - if (mBlenderShader) - mBlenderShader->ReloadMaterial(); + BLI_assert(m_scene); + + if (m_blenderShader) { + // If shader exists reload it. + m_blenderShader->ReloadMaterial(); + } + else { + // Create shader. + m_blenderShader = new BL_BlenderShader(m_scene, m_material, this); + + if (!m_blenderShader->Ok()) { + delete m_blenderShader; + m_blenderShader = nullptr; + } + } +} + +void KX_BlenderMaterial::ReplaceScene(KX_Scene *scene) +{ + m_scene = scene; } void KX_BlenderMaterial::InitTextures() { // for each unique material... int i; - for (i=0; imapping[i].mapping & USEENV ) { - if (!GLEW_ARB_texture_cube_map) { - spit("CubeMap textures not supported"); - continue; - } - if (!mTextures[i].InitCubeMap(i, mMaterial->cubemap[i] ) ) - spit("unable to initialize image("<matname<< ", image will not be available"); - } - /* If we're using glsl materials, the textures are handled by bf_gpu, so don't load them twice! - * However, if we're using a custom shader, then we still need to load the textures ourselves. */ - else if (!mMaterial->glslmat || mShader) { - if ( mMaterial->img[i] ) { - if ( ! mTextures[i].InitFromImage(i, mMaterial->img[i], (mMaterial->flag[i] &MIPMAP)!=0 )) - spit("unable to initialize image("<matname<< ", image will not be available"); - } + for (i = 0; i < RAS_Texture::MaxUnits; i++) { + MTex *mtex = m_material->mtex[i]; + if (mtex && mtex->tex) { + BL_Texture *texture = new BL_Texture(mtex); + m_textures[i] = texture; } } } -void KX_BlenderMaterial::OnConstruction() +void KX_BlenderMaterial::EndFrame(RAS_Rasterizer *rasty) { - if (mConstructed) - // when material are reused between objects - return; - - if (mMaterial->glslmat) - SetBlenderGLSLShader(); - - InitTextures(); - - mBlendFunc[0] =0; - mBlendFunc[1] =0; - mConstructed = true; + rasty->SetAlphaBlend(GPU_BLEND_SOLID); + RAS_Texture::DesactiveTextures(); } -void KX_BlenderMaterial::EndFrame() +void KX_BlenderMaterial::UpdateTextures() { - if (mLastBlenderShader) { - mLastBlenderShader->SetProg(false); - mLastBlenderShader = NULL; - } - - if (mLastShader) { - mLastShader->SetProg(false); - mLastShader = NULL; + /** We make sure that all gpu textures are the same in material textures here + * than in gpu material. This is dones in a separated loop because the texture + * regeneration can overide opengl bind settings of the previous texture. + */ + for (unsigned short i = 0; i < RAS_Texture::MaxUnits; i++) { + RAS_Texture *tex = m_textures[i]; + if (tex && tex->Ok()) { + tex->CheckValidTexture(); + } } } -void KX_BlenderMaterial::OnExit() +void KX_BlenderMaterial::ApplyTextures() { - if ( mShader ) { - //note, the shader here is allocated, per unique material - //and this function is called per face - if (mShader == mLastShader) { - mShader->SetProg(false); - mLastShader = NULL; - } - - delete mShader; - mShader = 0; - } - - if ( mBlenderShader ) { - if (mBlenderShader == mLastBlenderShader) { - mBlenderShader->SetProg(false); - mLastBlenderShader = NULL; + // for each enabled unit + for (unsigned short i = 0; i < RAS_Texture::MaxUnits; i++) { + if (m_textures[i] && m_textures[i]->Ok()) { + m_textures[i]->ActivateTexture(i); } - - delete mBlenderShader; - mBlenderShader = 0; } - - BL_Texture::ActivateFirst(); - for (int i=0; itface' but this can be a freed array, - * see: [#30493], so just call with NULL, this is best since it clears - * the 'lastface' pointer in GPU too - campbell */ - GPU_set_tpage(NULL, 1, mMaterial->alphablend); } - -void KX_BlenderMaterial::setShaderData( bool enable, RAS_IRasterizer *ras) +void KX_BlenderMaterial::SetShaderData(RAS_Rasterizer *ras) { - MT_assert(GLEW_ARB_shader_objects && mShader); - - int i; - if ( !enable || !mShader->Ok() ) { - // frame cleanup. - if (mShader == mLastShader) { - mShader->SetProg(false); - mLastShader = NULL; - } - - ras->SetAlphaBlend(TF_SOLID); - BL_Texture::DisableAllTextures(); - return; - } - - BL_Texture::DisableAllTextures(); - mShader->SetProg(true); - mLastShader = mShader; - - BL_Texture::ActivateFirst(); + m_shader->BindProg(); - mShader->ApplyShader(); + m_shader->ApplyShader(); - // for each enabled unit - for (i=0; imapping[i].mapping); - } + ApplyTextures(); - if (!mUserDefBlend) { - ras->SetAlphaBlend(mMaterial->alphablend); + if (!m_userDefBlend) { + ras->SetAlphaBlend(m_alphablend); } else { - ras->SetAlphaBlend(TF_SOLID); + ras->SetAlphaBlend(GPU_BLEND_SOLID); ras->SetAlphaBlend(-1); // indicates custom mode // tested to be valid enums - glEnable(GL_BLEND); - glBlendFunc(mBlendFunc[0], mBlendFunc[1]); + ras->Enable(RAS_Rasterizer::RAS_BLEND); + ras->SetBlendFunc(m_blendFunc[0], m_blendFunc[1]); } } -void KX_BlenderMaterial::setBlenderShaderData( bool enable, RAS_IRasterizer *ras) +void KX_BlenderMaterial::SetBlenderShaderData(RAS_Rasterizer *ras) { - if ( !enable || !mBlenderShader->Ok() ) { - ras->SetAlphaBlend(TF_SOLID); - - // frame cleanup. - if (mLastBlenderShader) { - mLastBlenderShader->SetProg(false); - mLastBlenderShader= NULL; - } - else - BL_Texture::DisableAllTextures(); - - return; - } - - if (!mBlenderShader->Equals(mLastBlenderShader)) { - ras->SetAlphaBlend(mMaterial->alphablend); - - if (mLastBlenderShader) - mLastBlenderShader->SetProg(false); - else - BL_Texture::DisableAllTextures(); - - mBlenderShader->SetProg(true, ras->GetTime(), ras); - mLastBlenderShader= mBlenderShader; - } + // Don't set the alpha blend here because ActivateMeshSlot do it. + m_blenderShader->BindProg(ras); } -void KX_BlenderMaterial::setTexData( bool enable, RAS_IRasterizer *ras) +void KX_BlenderMaterial::ActivateShaders(RAS_Rasterizer *rasty) { - BL_Texture::DisableAllTextures(); - - if ( !enable ) { - ras->SetAlphaBlend(TF_SOLID); - return; - } - - BL_Texture::ActivateFirst(); - - if ( mMaterial->IdMode == DEFAULT_BLENDER ) { - ras->SetAlphaBlend(mMaterial->alphablend); - return; - } - - if ( mMaterial->IdMode == TEXFACE ) { - // no material connected to the object - if ( mTextures[0].Ok() ) { - mTextures[0].ActivateTexture(); - mTextures[0].setTexEnv(0, true); - mTextures[0].SetMapping(mMaterial->mapping[0].mapping); - ras->SetAlphaBlend(mMaterial->alphablend); - } - return; - } - - int mode = 0,i=0; - for (i=0; imapping[i].mapping; - - if (mode &USEOBJ) - setObjectMatrixData(i, ras); - else - mTextures[i].SetMapping(mode); - - if (!(mode &USEOBJ)) - setTexMatrixData( i ); - } + SetShaderData(rasty); + ActivateGLMaterials(rasty); +} - if (!mUserDefBlend) { - ras->SetAlphaBlend(mMaterial->alphablend); - } - else { - ras->SetAlphaBlend(TF_SOLID); - ras->SetAlphaBlend(-1); // indicates custom mode +void KX_BlenderMaterial::ActivateBlenderShaders(RAS_Rasterizer *rasty) +{ + SetBlenderShaderData(rasty); +} - glEnable(GL_BLEND); - glBlendFunc(mBlendFunc[0], mBlendFunc[1]); +void KX_BlenderMaterial::Prepare(RAS_Rasterizer *rasty) +{ + UpdateTextures(); + if (m_blenderShader && m_blenderShader->Ok()) { + m_blenderShader->UpdateLights(rasty); } } -void -KX_BlenderMaterial::ActivatShaders( - RAS_IRasterizer* rasty, - TCachingInfo& cachingInfo)const +void KX_BlenderMaterial::Activate(RAS_Rasterizer *rasty) { - KX_BlenderMaterial *tmp = const_cast(this); - - // reset... - if (tmp->mMaterial->IsShared()) - cachingInfo =0; - - if (mLastBlenderShader) { - mLastBlenderShader->SetProg(false); - mLastBlenderShader= NULL; + if (m_shader && m_shader->Ok()) { + ActivateShaders(rasty); } - - if (GetCachingInfo() != cachingInfo) { - - if (!cachingInfo) - tmp->setShaderData(false, rasty); - - cachingInfo = GetCachingInfo(); - - if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) - tmp->setShaderData(true, rasty); - else if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW && mMaterial->alphablend != GEMAT_SOLID && !rasty->GetUsingOverrideShader()) - tmp->setShaderData(true, rasty); - else - tmp->setShaderData(false, rasty); - - if (mMaterial->ras_mode &TWOSIDED) - rasty->SetCullFace(false); - else - rasty->SetCullFace(true); - - if ((mMaterial->ras_mode &WIRE) || - (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME)) - { - if (mMaterial->ras_mode &WIRE) - rasty->SetCullFace(false); - rasty->SetLines(true); - } - else - rasty->SetLines(false); - ActivatGLMaterials(rasty); - ActivateTexGen(rasty); + else if (m_blenderShader && m_blenderShader->Ok()) { + ActivateBlenderShaders(rasty); } - - //ActivatGLMaterials(rasty); - //ActivateTexGen(rasty); } -void -KX_BlenderMaterial::ActivateBlenderShaders( - RAS_IRasterizer* rasty, - TCachingInfo& cachingInfo)const +void KX_BlenderMaterial::Desactivate(RAS_Rasterizer *rasty) { - KX_BlenderMaterial *tmp = const_cast(this); - - if (mLastShader) { - mLastShader->SetProg(false); - mLastShader= NULL; - } - - if (GetCachingInfo() != cachingInfo) { - if (!cachingInfo) - tmp->setBlenderShaderData(false, rasty); - - cachingInfo = GetCachingInfo(); - - if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) - tmp->setBlenderShaderData(true, rasty); - else if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW && mMaterial->alphablend != GEMAT_SOLID && !rasty->GetUsingOverrideShader()) - tmp->setBlenderShaderData(true, rasty); - else - tmp->setBlenderShaderData(false, rasty); - - if (mMaterial->ras_mode &TWOSIDED) - rasty->SetCullFace(false); - else - rasty->SetCullFace(true); - - if ((mMaterial->ras_mode &WIRE) || - (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME)) - { - if (mMaterial->ras_mode &WIRE) - rasty->SetCullFace(false); - rasty->SetLines(true); + if (m_shader && m_shader->Ok()) { + m_shader->UnbindProg(); + for (unsigned short i = 0; i < RAS_Texture::MaxUnits; i++) { + if (m_textures[i] && m_textures[i]->Ok()) { + m_textures[i]->DisableTexture(); + } } - else - rasty->SetLines(false); - - ActivatGLMaterials(rasty); - mBlenderShader->SetAttribs(rasty, mMaterial); + } + else if (m_blenderShader && m_blenderShader->Ok()) { + m_blenderShader->UnbindProg(); } } -void -KX_BlenderMaterial::ActivateMat( - RAS_IRasterizer* rasty, - TCachingInfo& cachingInfo - )const +bool KX_BlenderMaterial::UseInstancing() const { - KX_BlenderMaterial *tmp = const_cast(this); - - if (mLastShader) { - mLastShader->SetProg(false); - mLastShader= NULL; - } - - if (mLastBlenderShader) { - mLastBlenderShader->SetProg(false); - mLastBlenderShader= NULL; + if (m_shader && m_shader->Ok()) { + return false; } - - if (GetCachingInfo() != cachingInfo) { - if (!cachingInfo) - tmp->setTexData( false,rasty ); - - cachingInfo = GetCachingInfo(); - - if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) - tmp->setTexData( true,rasty ); - else if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW && mMaterial->alphablend != GEMAT_SOLID && !rasty->GetUsingOverrideShader()) - tmp->setTexData(true, rasty); - else - tmp->setTexData( false,rasty); - - if (mMaterial->ras_mode &TWOSIDED) - rasty->SetCullFace(false); - else - rasty->SetCullFace(true); - - if ((mMaterial->ras_mode &WIRE) || - (rasty->GetDrawingMode() <= RAS_IRasterizer::KX_WIREFRAME)) - { - if (mMaterial->ras_mode &WIRE) - rasty->SetCullFace(false); - rasty->SetLines(true); - } - else - rasty->SetLines(false); - ActivatGLMaterials(rasty); - ActivateTexGen(rasty); + else if (m_blenderShader) { + return m_blenderShader->UseInstancing(); } - - //ActivatGLMaterials(rasty); - //ActivateTexGen(rasty); + // The material is in conversion, we use the blender material flag then. + return m_material->shade_flag & MA_INSTANCING; } -bool -KX_BlenderMaterial::Activate( - RAS_IRasterizer* rasty, - TCachingInfo& cachingInfo - )const +void KX_BlenderMaterial::ActivateInstancing(RAS_Rasterizer *rasty, RAS_InstancingBuffer *buffer) { - if (GLEW_ARB_shader_objects && (mShader && mShader->Ok())) { - if ((mPass++) < mShader->getNumPass() ) { - ActivatShaders(rasty, cachingInfo); - return true; - } - else { - if (mShader == mLastShader) { - mShader->SetProg(false); - mLastShader = NULL; - } - mPass = 0; - return false; - } - } - else if ( GLEW_ARB_shader_objects && (mBlenderShader && mBlenderShader->Ok() ) ) { - if (mPass++ == 0) { - ActivateBlenderShaders(rasty, cachingInfo); - return true; - } - else { - mPass = 0; - return false; - } - } - else { - if (mPass++ == 0) { - ActivateMat(rasty, cachingInfo); - return true; - } - else { - mPass = 0; - return false; - } + if (m_blenderShader) { + m_blenderShader->ActivateInstancing(buffer); } } -bool KX_BlenderMaterial::UsesLighting(RAS_IRasterizer *rasty) const +bool KX_BlenderMaterial::UsesLighting() const { - if (!RAS_IPolyMaterial::UsesLighting(rasty)) + if (!RAS_IMaterial::UsesLighting()) { return false; + } - if (mShader && mShader->Ok()) + if (m_shader && m_shader->Ok()) { return true; - else if (mBlenderShader && mBlenderShader->Ok()) + } + else if (m_blenderShader && m_blenderShader->Ok()) { return false; - else + } + else { return true; + } } -void KX_BlenderMaterial::ActivateMeshSlot(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty) const +void KX_BlenderMaterial::ActivateMeshUser(RAS_MeshUser *meshUser, RAS_Rasterizer *rasty, const mt::mat3x4& camtrans) { - if (mShader && GLEW_ARB_shader_objects) { - mShader->Update(ms, rasty); + if (m_shader && m_shader->Ok()) { + m_shader->Update(rasty, meshUser); + m_shader->ApplyShader(); + // Update OpenGL lighting builtins. + rasty->ProcessLighting(UsesLighting(), camtrans); } - else if (mBlenderShader && GLEW_ARB_shader_objects) { - int alphablend; - - mBlenderShader->Update(ms, rasty); + else if (m_blenderShader) { + m_blenderShader->Update(meshUser, m_passIndex, rasty); /* we do blend modes here, because they can change per object * with the same material due to obcolor/obalpha */ - alphablend = mBlenderShader->GetAlphaBlend(); - if (ELEM(alphablend, GEMAT_SOLID, GEMAT_ALPHA, GEMAT_ALPHA_SORT) && mMaterial->alphablend != GEMAT_SOLID) - alphablend = mMaterial->alphablend; + int alphablend = m_blenderShader->GetAlphaBlend(); + if (ELEM(alphablend, GEMAT_SOLID, GEMAT_ALPHA, GEMAT_ALPHA_SORT) && m_alphablend != GEMAT_SOLID) { + alphablend = m_alphablend; + } rasty->SetAlphaBlend(alphablend); } } -void KX_BlenderMaterial::ActivatGLMaterials( RAS_IRasterizer* rasty )const +void KX_BlenderMaterial::ActivateGLMaterials(RAS_Rasterizer *rasty) const { - if (mShader || !mBlenderShader) { - rasty->SetSpecularity( - mMaterial->speccolor[0]*mMaterial->spec_f, - mMaterial->speccolor[1]*mMaterial->spec_f, - mMaterial->speccolor[2]*mMaterial->spec_f, - mMaterial->spec_f - ); - - rasty->SetShinyness( mMaterial->hard ); - - rasty->SetDiffuse( - mMaterial->matcolor[0]*mMaterial->ref+mMaterial->emit, - mMaterial->matcolor[1]*mMaterial->ref+mMaterial->emit, - mMaterial->matcolor[2]*mMaterial->ref+mMaterial->emit, - 1.0f); - - rasty->SetEmissive( - mMaterial->matcolor[0]*mMaterial->emit, - mMaterial->matcolor[1]*mMaterial->emit, - mMaterial->matcolor[2]*mMaterial->emit, - 1.0f ); - - rasty->SetAmbient(mMaterial->amb); + if (m_shader || !m_blenderShader) { + rasty->SetSpecularity(m_material->specr * m_material->spec, m_material->specg * m_material->spec, + m_material->specb * m_material->spec, m_material->spec); + rasty->SetShinyness(((float)m_material->har) / 4.0f); + rasty->SetDiffuse(m_material->r * m_material->ref + m_material->emit, m_material->g * m_material->ref + m_material->emit, + m_material->b * m_material->ref + m_material->emit, 1.0f); + rasty->SetEmissive(m_material->r * m_material->emit, m_material->g * m_material->emit, + m_material->b * m_material->emit, 1.0f); + rasty->SetAmbient(m_material->amb); } - - if (mMaterial->material) - rasty->SetPolygonOffset(-mMaterial->material->zoffs, 0.0f); } - -void KX_BlenderMaterial::ActivateTexGen(RAS_IRasterizer *ras) const +void KX_BlenderMaterial::UpdateIPO(const mt::vec4 &rgba, + const mt::vec3 &specrgb, + float hard, + float spec, + float ref, + float emit, + float ambient, + float alpha, + float specalpha) { - if (ras->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED || - (ras->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW && mMaterial->alphablend != GEMAT_SOLID && !ras->GetUsingOverrideShader())) { - ras->SetAttribNum(0); - if (mShader && GLEW_ARB_shader_objects) { - if (mShader->GetAttribute() == BL_Shader::SHD_TANGENT) { - ras->SetAttrib(RAS_IRasterizer::RAS_TEXCO_DISABLE, 0); - ras->SetAttrib(RAS_IRasterizer::RAS_TEXTANGENT, 1); - ras->SetAttribNum(2); - } - } + // only works one deep now - ras->SetTexCoordNum(mMaterial->num_enabled); - - for (int i=0; imapping[i].mapping; - - if ( mode &(USEREFL|USEOBJ)) - ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_GEN, i); - else if (mode &USEORCO) - ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_ORCO, i); - else if (mode &USENORM) - ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_NORM, i); - else if (mode &USEUV) - ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_UV, i); - else if (mode &USETANG) - ras->SetTexCoord(RAS_IRasterizer::RAS_TEXTANGENT, i); - else - ras->SetTexCoord(RAS_IRasterizer::RAS_TEXCO_DISABLE, i); - } - } + // GLSL Input + m_material->specr = (float)(specrgb)[0]; + m_material->specg = (float)(specrgb)[1]; + m_material->specb = (float)(specrgb)[2]; + m_material->r = (float)(rgba[0]); + m_material->g = (float)(rgba[1]); + m_material->b = (float)(rgba[2]); + m_material->alpha = (float)(rgba[3]); + m_material->amb = (float)(ambient); + m_material->har = (float)(hard); + m_material->emit = (float)(emit); + m_material->spec = (float)(spec); + m_material->ref = (float)(ref); + m_material->spectra = (float)specalpha; } -void KX_BlenderMaterial::setTexMatrixData(int i) +const RAS_AttributeArray::AttribList KX_BlenderMaterial::GetAttribs(const RAS_Mesh::LayersInfo& layersInfo) const { - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - - if ( GLEW_ARB_texture_cube_map && - mTextures[i].GetTextureType() == GL_TEXTURE_CUBE_MAP_ARB && - mMaterial->mapping[i].mapping & USEREFL) { - glScalef( - mMaterial->mapping[i].scale[0], - -mMaterial->mapping[i].scale[1], - -mMaterial->mapping[i].scale[2] - ); + if (m_shader && m_shader->Ok()) { + return m_shader->GetAttribs(layersInfo, m_textures); } - else - { - glScalef( - mMaterial->mapping[i].scale[0], - mMaterial->mapping[i].scale[1], - mMaterial->mapping[i].scale[2] - ); + if (m_blenderShader && m_blenderShader->Ok()) { + return m_blenderShader->GetAttribs(layersInfo); } - glTranslatef( - mMaterial->mapping[i].offsets[0], - mMaterial->mapping[i].offsets[1], - mMaterial->mapping[i].offsets[2] - ); - - glMatrixMode(GL_MODELVIEW); - -} - -static void GetProjPlane(BL_Material *mat, int index,int num, float*param) -{ - param[0]=param[1]=param[2]=param[3]=0.f; - if ( mat->mapping[index].projplane[num] == PROJX ) - param[0] = 1.f; - else if ( mat->mapping[index].projplane[num] == PROJY ) - param[1] = 1.f; - else if ( mat->mapping[index].projplane[num] == PROJZ) - param[2] = 1.f; -} - -void KX_BlenderMaterial::setObjectMatrixData(int i, RAS_IRasterizer *ras) -{ - KX_GameObject *obj = - (KX_GameObject*) - mScene->GetObjectList()->FindValue(mMaterial->mapping[i].objconame); - - if (!obj) return; - - glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR ); - glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR ); - glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR ); - - GLenum plane = GL_EYE_PLANE; - - // figure plane gen - float proj[4] = {0.f,0.f,0.f,0.f}; - GetProjPlane(mMaterial, i, 0, proj); - glTexGenfv(GL_S, plane, proj); - - GetProjPlane(mMaterial, i, 1, proj); - glTexGenfv(GL_T, plane, proj); - - GetProjPlane(mMaterial, i, 2, proj); - glTexGenfv(GL_R, plane, proj); - - glEnable(GL_TEXTURE_GEN_S); - glEnable(GL_TEXTURE_GEN_T); - glEnable(GL_TEXTURE_GEN_R); - - const MT_Matrix4x4& mvmat = ras->GetViewMatrix(); - - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glScalef( - mMaterial->mapping[i].scale[0], - mMaterial->mapping[i].scale[1], - mMaterial->mapping[i].scale[2] - ); - - MT_Point3 pos = obj->NodeGetWorldPosition(); - MT_Vector4 matmul = MT_Vector4(pos[0], pos[1], pos[2], 1.f); - MT_Vector4 t = mvmat*matmul; - - glTranslatef( (float)(-t[0]), (float)(-t[1]), (float)(-t[2]) ); - - glMatrixMode(GL_MODELVIEW); + return {}; } -// ------------------------------------ -void KX_BlenderMaterial::UpdateIPO( - MT_Vector4 rgba, - MT_Vector3 specrgb, - MT_Scalar hard, - MT_Scalar spec, - MT_Scalar ref, - MT_Scalar emit, - MT_Scalar alpha - ) +RAS_InstancingBuffer::Attrib KX_BlenderMaterial::GetInstancingAttribs() const { - // only works one deep now - - // GLSL Multitexture Input - mMaterial->material->specr = mMaterial->speccolor[0] = (float)(specrgb)[0]; - mMaterial->material->specg = mMaterial->speccolor[1] = (float)(specrgb)[1]; - mMaterial->material->specb = mMaterial->speccolor[2] = (float)(specrgb)[2]; - mMaterial->material->r = mMaterial->matcolor[0] = (float)(rgba[0]); - mMaterial->material->g = mMaterial->matcolor[1] = (float)(rgba[1]); - mMaterial->material->b = mMaterial->matcolor[2] = (float)(rgba[2]); - mMaterial->material->alpha = mMaterial->alpha = (float)(rgba[3]); - mMaterial->material->har = mMaterial->hard = (float)(hard); - mMaterial->material->emit = mMaterial->emit = (float)(emit); - mMaterial->material->spec = mMaterial->spec_f = (float)(spec); - mMaterial->material->ref = mMaterial->ref = (float)(ref); -} - -void KX_BlenderMaterial::Replace_IScene(SCA_IScene *val) -{ - mScene= static_cast(val); - - OnConstruction(); -} + if (m_blenderShader && m_blenderShader->Ok()) { + return m_blenderShader->GetInstancingAttribs(); + } -BL_Material *KX_BlenderMaterial::GetBLMaterial() -{ - return mMaterial; + return RAS_InstancingBuffer::DEFAULT_ATTRIBS; } -void KX_BlenderMaterial::SetBlenderGLSLShader() +std::string KX_BlenderMaterial::GetName() { - if (!mBlenderShader) - mBlenderShader = new BL_BlenderShader(mScene, mMaterial->material, mLightLayer); - - if (!mBlenderShader->Ok()) { - delete mBlenderShader; - mBlenderShader = 0; - } + return m_name; } #ifdef USE_MATHUTILS @@ -870,28 +464,36 @@ static unsigned char mathutils_kxblendermaterial_color_cb_index = -1; /* index f static int mathutils_kxblendermaterial_generic_check(BaseMathObject *bmo) { - KX_BlenderMaterial *self = static_castBGE_PROXY_REF(bmo->cb_user); - if (!self) + KX_BlenderMaterial *self = static_castEXP_PROXY_REF(bmo->cb_user); + if (!self) { return -1; + } return 0; } static int mathutils_kxblendermaterial_color_get(BaseMathObject *bmo, int subtype) { - KX_BlenderMaterial *self = static_castBGE_PROXY_REF(bmo->cb_user); - if (!self) + KX_BlenderMaterial *self = static_castEXP_PROXY_REF(bmo->cb_user); + if (!self) { return -1; + } + + Material *mat = self->GetBlenderMaterial(); switch (subtype) { case MATHUTILS_COL_CB_MATERIAL_DIFFUSE_COLOR: { - copy_v3_v3(bmo->data, self->GetBLMaterial()->matcolor); + bmo->data[0] = mat->r; + bmo->data[1] = mat->g; + bmo->data[2] = mat->b; break; } case MATHUTILS_COL_CB_MATERIAL_SPECULAR_COLOR: { - copy_v3_v3(bmo->data, self->GetBLMaterial()->speccolor); + bmo->data[0] = mat->specr; + bmo->data[1] = mat->specg; + bmo->data[2] = mat->specb; break; } } @@ -901,27 +503,26 @@ static int mathutils_kxblendermaterial_color_get(BaseMathObject *bmo, int subtyp static int mathutils_kxblendermaterial_color_set(BaseMathObject *bmo, int subtype) { - KX_BlenderMaterial *self = static_castBGE_PROXY_REF(bmo->cb_user); - if (!self) + KX_BlenderMaterial *self = static_castEXP_PROXY_REF(bmo->cb_user); + if (!self) { return -1; + } + + Material *mat = self->GetBlenderMaterial(); switch (subtype) { case MATHUTILS_COL_CB_MATERIAL_DIFFUSE_COLOR: { - BL_Material *mat = self->GetBLMaterial(); - copy_v3_v3(mat->matcolor, bmo->data); - mat->material->r = bmo->data[0]; - mat->material->g = bmo->data[1]; - mat->material->b = bmo->data[2]; + mat->r = bmo->data[0]; + mat->g = bmo->data[1]; + mat->b = bmo->data[2]; break; } case MATHUTILS_COL_CB_MATERIAL_SPECULAR_COLOR: { - BL_Material *mat = self->GetBLMaterial(); - copy_v3_v3(mat->speccolor, bmo->data); - mat->material->specr = bmo->data[0]; - mat->material->specg = bmo->data[1]; - mat->material->specb = bmo->data[2]; + mat->specr = bmo->data[0]; + mat->specg = bmo->data[1]; + mat->specb = bmo->data[2]; break; } } @@ -932,8 +533,9 @@ static int mathutils_kxblendermaterial_color_set(BaseMathObject *bmo, int subtyp static int mathutils_kxblendermaterial_color_get_index(BaseMathObject *bmo, int subtype, int index) { /* lazy, avoid repeteing the case statement */ - if (mathutils_kxblendermaterial_color_get(bmo, subtype) == -1) + if (mathutils_kxblendermaterial_color_get(bmo, subtype) == -1) { return -1; + } return 0; } @@ -942,8 +544,9 @@ static int mathutils_kxblendermaterial_color_set_index(BaseMathObject *bmo, int float f = bmo->data[index]; /* lazy, avoid repeateing the case statement */ - if (mathutils_kxblendermaterial_color_get(bmo, subtype) == -1) + if (mathutils_kxblendermaterial_color_get(bmo, subtype) == -1) { return -1; + } bmo->data[index] = f; return mathutils_kxblendermaterial_color_set(bmo, subtype); @@ -970,32 +573,34 @@ void KX_BlenderMaterial_Mathutils_Callback_Init() PyMethodDef KX_BlenderMaterial::Methods[] = { - KX_PYMETHODTABLE( KX_BlenderMaterial, getShader ), - KX_PYMETHODTABLE( KX_BlenderMaterial, getMaterialIndex ), - KX_PYMETHODTABLE( KX_BlenderMaterial, getTextureBindcode ), - KX_PYMETHODTABLE( KX_BlenderMaterial, setBlending ), - {NULL,NULL} //Sentinel + EXP_PYMETHODTABLE(KX_BlenderMaterial, getShader), + EXP_PYMETHODTABLE(KX_BlenderMaterial, getTextureBindcode), + EXP_PYMETHODTABLE(KX_BlenderMaterial, setBlending), + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_BlenderMaterial::Attributes[] = { - KX_PYATTRIBUTE_RO_FUNCTION("shader", KX_BlenderMaterial, pyattr_get_shader), - KX_PYATTRIBUTE_RO_FUNCTION("material_index", KX_BlenderMaterial, pyattr_get_materialIndex), - KX_PYATTRIBUTE_RW_FUNCTION("blending", KX_BlenderMaterial, pyattr_get_blending, pyattr_set_blending), - KX_PYATTRIBUTE_RW_FUNCTION("alpha", KX_BlenderMaterial, pyattr_get_alpha, pyattr_set_alpha), - KX_PYATTRIBUTE_RW_FUNCTION("hardness", KX_BlenderMaterial, pyattr_get_hardness, pyattr_set_hardness), - KX_PYATTRIBUTE_RW_FUNCTION("specularIntensity", KX_BlenderMaterial, pyattr_get_specular_intensity, pyattr_set_specular_intensity), - KX_PYATTRIBUTE_RW_FUNCTION("specularColor", KX_BlenderMaterial, pyattr_get_specular_color, pyattr_set_specular_color), - KX_PYATTRIBUTE_RW_FUNCTION("diffuseIntensity", KX_BlenderMaterial, pyattr_get_diffuse_intensity, pyattr_set_diffuse_intensity), - KX_PYATTRIBUTE_RW_FUNCTION("diffuseColor", KX_BlenderMaterial, pyattr_get_diffuse_color, pyattr_set_diffuse_color), - KX_PYATTRIBUTE_RW_FUNCTION("emit", KX_BlenderMaterial, pyattr_get_emit, pyattr_set_emit), - - { NULL } //Sentinel + EXP_PYATTRIBUTE_RO_FUNCTION("shader", KX_BlenderMaterial, pyattr_get_shader), + EXP_PYATTRIBUTE_RO_FUNCTION("textures", KX_BlenderMaterial, pyattr_get_textures), + EXP_PYATTRIBUTE_RW_FUNCTION("blending", KX_BlenderMaterial, pyattr_get_blending, pyattr_set_blending), + EXP_PYATTRIBUTE_RW_FUNCTION("alpha", KX_BlenderMaterial, pyattr_get_alpha, pyattr_set_alpha), + EXP_PYATTRIBUTE_RW_FUNCTION("hardness", KX_BlenderMaterial, pyattr_get_hardness, pyattr_set_hardness), + EXP_PYATTRIBUTE_RW_FUNCTION("specularIntensity", KX_BlenderMaterial, pyattr_get_specular_intensity, pyattr_set_specular_intensity), + EXP_PYATTRIBUTE_RW_FUNCTION("specularColor", KX_BlenderMaterial, pyattr_get_specular_color, pyattr_set_specular_color), + EXP_PYATTRIBUTE_RW_FUNCTION("diffuseIntensity", KX_BlenderMaterial, pyattr_get_diffuse_intensity, pyattr_set_diffuse_intensity), + EXP_PYATTRIBUTE_RW_FUNCTION("diffuseColor", KX_BlenderMaterial, pyattr_get_diffuse_color, pyattr_set_diffuse_color), + EXP_PYATTRIBUTE_RW_FUNCTION("emit", KX_BlenderMaterial, pyattr_get_emit, pyattr_set_emit), + EXP_PYATTRIBUTE_RW_FUNCTION("ambient", KX_BlenderMaterial, pyattr_get_ambient, pyattr_set_ambient), + EXP_PYATTRIBUTE_RW_FUNCTION("specularAlpha", KX_BlenderMaterial, pyattr_get_specular_alpha, pyattr_set_specular_alpha), + EXP_PYATTRIBUTE_SHORT_RW("passIndex", 0, SHRT_MAX, false, KX_BlenderMaterial, m_passIndex), + + EXP_PYATTRIBUTE_NULL //Sentinel }; PyTypeObject KX_BlenderMaterial::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_BlenderMaterial", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -1003,343 +608,403 @@ PyTypeObject KX_BlenderMaterial::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, - &PyObjectPlus::Type, - 0,0,0,0,0,0, + &EXP_Value::Type, + 0, 0, 0, 0, 0, 0, py_base_new }; -PyObject *KX_BlenderMaterial::pyattr_get_shader(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_BlenderMaterial::pyattr_get_shader(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_BlenderMaterial *self = static_cast(self_v); + return self->PygetShader(nullptr, nullptr); +} + +unsigned int KX_BlenderMaterial::py_get_textures_size() +{ + return RAS_Texture::MaxUnits; +} + +PyObject *KX_BlenderMaterial::py_get_textures_item(unsigned int index) +{ + BL_Texture *tex = static_cast(m_textures[index]); + PyObject *item = nullptr; + if (tex) { + item = tex->GetProxy(); + } + else { + Py_RETURN_NONE; + } + return item; +} + +std::string KX_BlenderMaterial::py_get_textures_item_name(unsigned int index) { - KX_BlenderMaterial* self = static_cast(self_v); - return self->PygetShader(NULL, NULL); + BL_Texture *tex = static_cast(m_textures[index]); + return (tex ? tex->GetName() : ""); } -PyObject *KX_BlenderMaterial::pyattr_get_materialIndex(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_BlenderMaterial::pyattr_get_textures(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_BlenderMaterial* self = static_cast(self_v); - return PyLong_FromLong(self->GetMaterialIndex()); + return (new EXP_ListWrapper(self_v))->NewProxy(true); } -PyObject *KX_BlenderMaterial::pyattr_get_blending(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_BlenderMaterial::pyattr_get_blending(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_BlenderMaterial* self = static_cast(self_v); - unsigned int* bfunc = self->getBlendFunc(); + KX_BlenderMaterial *self = static_cast(self_v); + const RAS_Rasterizer::BlendFunc *bfunc = self->GetBlendFunc(); return Py_BuildValue("(ll)", (long int)bfunc[0], (long int)bfunc[1]); } -PyObject *KX_BlenderMaterial::pyattr_get_alpha(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_BlenderMaterial::pyattr_get_alpha(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { KX_BlenderMaterial *self = static_cast(self_v); - return PyFloat_FromDouble(self->GetBLMaterial()->alpha); + return PyFloat_FromDouble(self->GetBlenderMaterial()->alpha); } -int KX_BlenderMaterial::pyattr_set_alpha(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_BlenderMaterial::pyattr_set_alpha(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { KX_BlenderMaterial *self = static_cast(self_v); float val = PyFloat_AsDouble(value); if (val == -1 && PyErr_Occurred()) { - PyErr_Format(PyExc_AttributeError, "material.%s = float: KX_BlenderMaterial, expected a float", attrdef->m_name); + PyErr_Format(PyExc_AttributeError, "material.%s = float: KX_BlenderMaterial, expected a float", attrdef->m_name.c_str()); return PY_SET_ATTR_FAIL; } CLAMP(val, 0.0f, 1.0f); - BL_Material *mat = self->GetBLMaterial(); - mat->alpha = mat->material->alpha = val; + self->GetBlenderMaterial()->alpha = val; return PY_SET_ATTR_SUCCESS; } -PyObject *KX_BlenderMaterial::pyattr_get_hardness(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) + +PyObject *KX_BlenderMaterial::pyattr_get_specular_alpha(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { KX_BlenderMaterial *self = static_cast(self_v); - return PyLong_FromLong(self->GetBLMaterial()->hard); + return PyFloat_FromDouble(self->GetBlenderMaterial()->spectra); } -int KX_BlenderMaterial::pyattr_set_hardness(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_BlenderMaterial::pyattr_set_specular_alpha(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_BlenderMaterial *self = static_cast(self_v); + float val = PyFloat_AsDouble(value); + + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "material.%s = float: KX_BlenderMaterial, expected a float", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; + } + + CLAMP(val, 0.0f, 1.0f); + + self->GetBlenderMaterial()->spectra = val; + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_BlenderMaterial::pyattr_get_hardness(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_BlenderMaterial *self = static_cast(self_v); + return PyLong_FromLong(self->GetBlenderMaterial()->har); +} + +int KX_BlenderMaterial::pyattr_set_hardness(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { KX_BlenderMaterial *self = static_cast(self_v); int val = PyLong_AsLong(value); if (val == -1 && PyErr_Occurred()) { - PyErr_Format(PyExc_AttributeError, "material.%s = int: KX_BlenderMaterial, expected a int", attrdef->m_name); + PyErr_Format(PyExc_AttributeError, "material.%s = int: KX_BlenderMaterial, expected a int", attrdef->m_name.c_str()); return PY_SET_ATTR_FAIL; } CLAMP(val, 1, 511); - BL_Material *mat = self->GetBLMaterial(); - mat->hard = mat->material->har = val; + self->GetBlenderMaterial()->har = val; return PY_SET_ATTR_SUCCESS; } -PyObject *KX_BlenderMaterial::pyattr_get_specular_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_BlenderMaterial::pyattr_get_specular_intensity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { KX_BlenderMaterial *self = static_cast(self_v); - return PyFloat_FromDouble(self->GetBLMaterial()->spec_f); + return PyFloat_FromDouble(self->GetBlenderMaterial()->spec); } -int KX_BlenderMaterial::pyattr_set_specular_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_BlenderMaterial::pyattr_set_specular_intensity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { KX_BlenderMaterial *self = static_cast(self_v); float val = PyFloat_AsDouble(value); if (val == -1 && PyErr_Occurred()) { - PyErr_Format(PyExc_AttributeError, "material.%s = float: KX_BlenderMaterial, expected a float", attrdef->m_name); + PyErr_Format(PyExc_AttributeError, "material.%s = float: KX_BlenderMaterial, expected a float", attrdef->m_name.c_str()); return PY_SET_ATTR_FAIL; } CLAMP(val, 0.0f, 1.0f); - BL_Material *mat = self->GetBLMaterial(); - mat->spec_f = mat->material->spec = val; + self->GetBlenderMaterial()->spec = val; return PY_SET_ATTR_SUCCESS; } -PyObject *KX_BlenderMaterial::pyattr_get_specular_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_BlenderMaterial::pyattr_get_specular_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Color_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), mathutils_kxblendermaterial_color_cb_index, MATHUTILS_COL_CB_MATERIAL_SPECULAR_COLOR); + return Color_CreatePyObject_cb(EXP_PROXY_FROM_REF(self_v), mathutils_kxblendermaterial_color_cb_index, MATHUTILS_COL_CB_MATERIAL_SPECULAR_COLOR); #else KX_BlenderMaterial *self = static_cast(self_v); - return PyColorFromVector(MT_Vector3(self->GetBLMaterial()->speccolor)); + Material *mat = self->GetBlenderMaterial(); + return PyColorFromVector(mt::vec3(mat->specr, mat->specg, mat->specb)); #endif } -int KX_BlenderMaterial::pyattr_set_specular_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_BlenderMaterial::pyattr_set_specular_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { KX_BlenderMaterial *self = static_cast(self_v); - MT_Vector3 color; - if (!PyVecTo(value, color)) + mt::vec3 color; + if (!PyVecTo(value, color)) { return PY_SET_ATTR_FAIL; + } - BL_Material *mat = self->GetBLMaterial(); - color.getValue(mat->speccolor); - mat->material->specr = color[0]; - mat->material->specg = color[1]; - mat->material->specb = color[2]; + Material *mat = self->GetBlenderMaterial(); + mat->specr = color[0]; + mat->specg = color[1]; + mat->specb = color[2]; return PY_SET_ATTR_SUCCESS; } -PyObject *KX_BlenderMaterial::pyattr_get_diffuse_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_BlenderMaterial::pyattr_get_diffuse_intensity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { KX_BlenderMaterial *self = static_cast(self_v); - return PyFloat_FromDouble(self->GetBLMaterial()->ref); + return PyFloat_FromDouble(self->GetBlenderMaterial()->ref); } -int KX_BlenderMaterial::pyattr_set_diffuse_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_BlenderMaterial::pyattr_set_diffuse_intensity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { KX_BlenderMaterial *self = static_cast(self_v); float val = PyFloat_AsDouble(value); if (val == -1 && PyErr_Occurred()) { - PyErr_Format(PyExc_AttributeError, "material.%s = float: KX_BlenderMaterial, expected a float", attrdef->m_name); + PyErr_Format(PyExc_AttributeError, "material.%s = float: KX_BlenderMaterial, expected a float", attrdef->m_name.c_str()); return PY_SET_ATTR_FAIL; } CLAMP(val, 0.0f, 1.0f); - BL_Material *mat = self->GetBLMaterial(); - mat->ref = mat->material->ref = val; + self->GetBlenderMaterial()->ref = val; return PY_SET_ATTR_SUCCESS; } -PyObject *KX_BlenderMaterial::pyattr_get_diffuse_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_BlenderMaterial::pyattr_get_diffuse_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS - return Color_CreatePyObject_cb(BGE_PROXY_FROM_REF(self_v), mathutils_kxblendermaterial_color_cb_index, MATHUTILS_COL_CB_MATERIAL_DIFFUSE_COLOR); + return Color_CreatePyObject_cb(EXP_PROXY_FROM_REF(self_v), mathutils_kxblendermaterial_color_cb_index, MATHUTILS_COL_CB_MATERIAL_DIFFUSE_COLOR); #else KX_BlenderMaterial *self = static_cast(self_v); - return PyColorFromVector(MT_Vector3(self->GetBLMaterial()->matcolor)); + Material *mat = self->GetBlenderMaterial(); + return PyColorFromVector(mt::vec3(mat->r, mat->g, mat->b)); #endif } -int KX_BlenderMaterial::pyattr_set_diffuse_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_BlenderMaterial::pyattr_set_diffuse_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { KX_BlenderMaterial *self = static_cast(self_v); - MT_Vector3 color; - if (!PyVecTo(value, color)) + mt::vec3 color; + if (!PyVecTo(value, color)) { return PY_SET_ATTR_FAIL; + } - BL_Material *mat = self->GetBLMaterial(); - color.getValue(mat->matcolor); - mat->material->r = color[0]; - mat->material->g = color[1]; - mat->material->b = color[2]; + Material *mat = self->GetBlenderMaterial(); + mat->r = color[0]; + mat->g = color[1]; + mat->b = color[2]; return PY_SET_ATTR_SUCCESS; } -PyObject *KX_BlenderMaterial::pyattr_get_emit(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_BlenderMaterial::pyattr_get_emit(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { KX_BlenderMaterial *self = static_cast(self_v); - return PyFloat_FromDouble(self->GetBLMaterial()->emit); + return PyFloat_FromDouble(self->GetBlenderMaterial()->emit); } -int KX_BlenderMaterial::pyattr_set_emit(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_BlenderMaterial::pyattr_set_emit(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { KX_BlenderMaterial *self = static_cast(self_v); float val = PyFloat_AsDouble(value); if (val == -1 && PyErr_Occurred()) { - PyErr_Format(PyExc_AttributeError, "material.%s = float: KX_BlenderMaterial, expected a float", attrdef->m_name); + PyErr_Format(PyExc_AttributeError, "material.%s = float: KX_BlenderMaterial, expected a float", attrdef->m_name.c_str()); return PY_SET_ATTR_FAIL; } CLAMP(val, 0.0f, 2.0f); - BL_Material *mat = self->GetBLMaterial(); - mat->emit = mat->material->emit = val; + self->GetBlenderMaterial()->emit = val; return PY_SET_ATTR_SUCCESS; } -int KX_BlenderMaterial::pyattr_set_blending(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +PyObject *KX_BlenderMaterial::pyattr_get_ambient(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_BlenderMaterial* self = static_cast(self_v); - PyObject *obj = self->PysetBlending(value, NULL); - if (obj) - { - Py_DECREF(obj); - return 0; - } - return -1; + KX_BlenderMaterial *self = static_cast(self_v); + return PyFloat_FromDouble(self->GetBlenderMaterial()->amb); } -KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()") +int KX_BlenderMaterial::pyattr_set_ambient(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - if ( !GLEW_ARB_fragment_shader) { - if (!mModified) - spit("Fragment shaders not supported"); - - mModified = true; - Py_RETURN_NONE; - } - - if ( !GLEW_ARB_vertex_shader) { - if (!mModified) - spit("Vertex shaders not supported"); - - mModified = true; - Py_RETURN_NONE; - } + KX_BlenderMaterial *self = static_cast(self_v); + float val = PyFloat_AsDouble(value); - if (!GLEW_ARB_shader_objects) { - if (!mModified) - spit("GLSL not supported"); - mModified = true; - Py_RETURN_NONE; + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "material.%s = float: KX_BlenderMaterial, expected a float", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; } - else { - // returns Py_None on error - // the calling script will need to check - - if (!mShader && !mModified) { - mShader = new BL_Shader(); - mModified = true; - // Using a custom shader, make sure to initialize textures - InitTextures(); - } + CLAMP(val, 0.0f, 1.0f); - if (mShader && !mShader->GetError()) { - m_flag &= ~RAS_BLENDERGLSL; - mMaterial->SetSharedMaterial(true); - mScene->GetBucketManager()->ReleaseDisplayLists(this); - return mShader->GetProxy(); - } - else { - // decref all references to the object - // then delete it! - // We will then go back to fixed functionality - // for this material - if (mShader) { - delete mShader; /* will handle python de-referencing */ - mShader=0; - } - } - Py_RETURN_NONE; - } - PyErr_SetString(PyExc_ValueError, "material.getShader(): KX_BlenderMaterial, GLSL Error"); - return NULL; + self->GetBlenderMaterial()->amb = val; + return PY_SET_ATTR_SUCCESS; } -KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getMaterialIndex, "getMaterialIndex()") +int KX_BlenderMaterial::pyattr_set_blending(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - return PyLong_FromLong(GetMaterialIndex()); + KX_BlenderMaterial *self = static_cast(self_v); + PyObject *obj = self->PysetBlending(value, nullptr); + if (obj) { + Py_DECREF(obj); + return 0; + } + return -1; } -KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getTexture, "getTexture( index )" ) +EXP_PYMETHODDEF_DOC(KX_BlenderMaterial, getShader, "getShader()") { - // TODO: enable python switching - return NULL; -} + // returns Py_None on error + // the calling script will need to check -KX_PYMETHODDEF_DOC( KX_BlenderMaterial, setTexture , "setTexture( index, tex)") -{ - // TODO: enable python switching - return NULL; + if (!m_shader) { + m_shader = new BL_Shader(this); + } + + if (!m_shader->GetError()) { + return m_shader->GetProxy(); + } + // We have a shader but invalid. + else { + // decref all references to the object + // then delete it! + // We will then go back to fixed functionality + // for this material + delete m_shader; /* will handle python de-referencing */ + m_shader = nullptr; + } + Py_RETURN_NONE; } static const unsigned int GL_array[11] = { - GL_ZERO, - GL_ONE, - GL_SRC_COLOR, - GL_ONE_MINUS_SRC_COLOR, - GL_DST_COLOR, - GL_ONE_MINUS_DST_COLOR, - GL_SRC_ALPHA, - GL_ONE_MINUS_SRC_ALPHA, - GL_DST_ALPHA, - GL_ONE_MINUS_DST_ALPHA, - GL_SRC_ALPHA_SATURATE + RAS_Rasterizer::RAS_ZERO, + RAS_Rasterizer::RAS_ONE, + RAS_Rasterizer::RAS_SRC_COLOR, + RAS_Rasterizer::RAS_ONE_MINUS_SRC_COLOR, + RAS_Rasterizer::RAS_DST_COLOR, + RAS_Rasterizer::RAS_ONE_MINUS_DST_COLOR, + RAS_Rasterizer::RAS_SRC_ALPHA, + RAS_Rasterizer::RAS_ONE_MINUS_SRC_ALPHA, + RAS_Rasterizer::RAS_DST_ALPHA, + RAS_Rasterizer::RAS_ONE_MINUS_DST_ALPHA, + RAS_Rasterizer::RAS_SRC_ALPHA_SATURATE }; -KX_PYMETHODDEF_DOC( KX_BlenderMaterial, setBlending , "setBlending( bge.logic.src, bge.logic.dest)") +EXP_PYMETHODDEF_DOC(KX_BlenderMaterial, setBlending, "setBlending(bge.logic.src, bge.logic.dest)") { unsigned int b[2]; - if (PyArg_ParseTuple(args, "ii:setBlending", &b[0], &b[1])) - { + if (PyArg_ParseTuple(args, "ii:setBlending", &b[0], &b[1])) { bool value_found[2] = {false, false}; - for (int i=0; i<11; i++) - { + for (int i = 0; i < 11; i++) { if (b[0] == GL_array[i]) { value_found[0] = true; - mBlendFunc[0] = b[0]; + m_blendFunc[0] = (RAS_Rasterizer::BlendFunc)b[0]; } if (b[1] == GL_array[i]) { value_found[1] = true; - mBlendFunc[1] = b[1]; + m_blendFunc[1] = (RAS_Rasterizer::BlendFunc)b[1]; + } + if (value_found[0] && value_found[1]) { + break; } - if (value_found[0] && value_found[1]) break; } if (!value_found[0] || !value_found[1]) { PyErr_SetString(PyExc_ValueError, "material.setBlending(int, int): KX_BlenderMaterial, invalid enum."); - return NULL; + return nullptr; } - mUserDefBlend = true; + m_userDefBlend = true; Py_RETURN_NONE; } - return NULL; + return nullptr; } -KX_PYMETHODDEF_DOC(KX_BlenderMaterial, getTextureBindcode, "getTextureBindcode(texslot)") +EXP_PYMETHODDEF_DOC(KX_BlenderMaterial, getTextureBindcode, "getTextureBindcode(texslot)") { + EXP_ShowDeprecationWarning("material.getTextureBindcode(texslot)", "material.textures[texslot].bindCode"); unsigned int texslot; if (!PyArg_ParseTuple(args, "i:texslot", &texslot)) { PyErr_SetString(PyExc_ValueError, "material.getTextureBindcode(texslot): KX_BlenderMaterial, expected an int."); - return NULL; + return nullptr; } - Image *ima = getImage(texslot); + Image *ima = GetTexture(texslot)->GetImage(); if (ima) { unsigned int *bindcode = ima->bindcode; return PyLong_FromLong(*bindcode); } PyErr_SetString(PyExc_ValueError, "material.getTextureBindcode(texslot): KX_BlenderMaterial, invalid texture slot."); - return NULL; + return nullptr; +} + +bool ConvertPythonToMaterial(PyObject *value, KX_BlenderMaterial **material, bool py_none_ok, const char *error_prefix) +{ + if (value == nullptr) { + PyErr_Format(PyExc_TypeError, "%s, python pointer nullptr, should never happen", error_prefix); + *material = nullptr; + return false; + } + + if (value == Py_None) { + *material = nullptr; + + if (py_none_ok) { + return true; + } + else { + PyErr_Format(PyExc_TypeError, "%s, expected KX_BlenderMaterial or a KX_BlenderMaterial name, None is invalid", error_prefix); + return false; + } + } + + if (PyObject_TypeCheck(value, &KX_BlenderMaterial::Type)) { + KX_BlenderMaterial *mat = static_castEXP_PROXY_REF(value); + + /* sets the error */ + if (mat == nullptr) { + PyErr_Format(PyExc_SystemError, "%s, " EXP_PROXY_ERROR_MSG, error_prefix); + return false; + } + + *material = mat; + return true; + } + + *material = nullptr; + + if (py_none_ok) { + PyErr_Format(PyExc_TypeError, "%s, expect a KX_BlenderMaterial, a string or None", error_prefix); + } + else { + PyErr_Format(PyExc_TypeError, "%s, expect a KX_BlenderMaterial or a string", error_prefix); + } + + return false; } #endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.h b/source/gameengine/Ketsji/KX_BlenderMaterial.h index 02b60913b91b..922ee9c9b7c3 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.h +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.h @@ -6,155 +6,113 @@ #ifndef __KX_BLENDERMATERIAL_H__ #define __KX_BLENDERMATERIAL_H__ -#include - - -#include "RAS_IPolygonMaterial.h" -#include "BL_Material.h" +#include "RAS_IMaterial.h" #include "BL_Texture.h" -#include "BL_Shader.h" -#include "BL_BlenderShader.h" +#include "BL_Resource.h" -#include "EXP_PyObjectPlus.h" +#include "EXP_Value.h" -#include "MT_Vector3.h" -#include "MT_Vector4.h" - -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -#include "SCA_IScene.h" /* only for Replace_IScene */ -#include "KX_Scene.h" - -struct MTFace; +class SCA_IScene; class KX_Scene; - +class BL_BlenderShader; +class BL_Shader; +struct Material; #ifdef USE_MATHUTILS void KX_BlenderMaterial_Mathutils_Callback_Init(void); #endif -class KX_BlenderMaterial : public PyObjectPlus, public RAS_IPolyMaterial +class KX_BlenderMaterial : public EXP_Value, public BL_Resource, public RAS_IMaterial { Py_Header + public: - // -------------------------------- - KX_BlenderMaterial(); - void Initialize( - class KX_Scene* scene, - BL_Material* mat, - GameSettings* game, - int lightlayer - ); + KX_BlenderMaterial(Material *mat, const std::string& name, KX_Scene *scene); virtual ~KX_BlenderMaterial(); - // -------------------------------- - virtual TCachingInfo GetCachingInfo(void) const { - return (void*) this; - } - - virtual - bool Activate( - RAS_IRasterizer* rasty, - TCachingInfo& cachingInfo - ) const; - - virtual - void ActivateMeshSlot( - const RAS_MeshSlot & ms, - RAS_IRasterizer* rasty - ) const; - - void ActivateMat( - RAS_IRasterizer* rasty, - TCachingInfo& cachingInfo - )const; - - void ActivatShaders( - RAS_IRasterizer* rasty, - TCachingInfo& cachingInfo - )const; - - void ActivateBlenderShaders( - RAS_IRasterizer* rasty, - TCachingInfo& cachingInfo - )const; - - Material* GetBlenderMaterial() const; - Image* GetBlenderImage() const; - MTexPoly *GetMTexPoly() const; - unsigned int* GetMCol() const; - BL_Texture * getTex (unsigned int idx) { - return (idx < MAXTEX) ? mTextures + idx : NULL; - } - Image * getImage (unsigned int idx) { - return (idx < MAXTEX && mMaterial) ? mMaterial->img[idx] : NULL; - } - unsigned int* getBlendFunc() { - return mBlendFunc; - } + virtual void Prepare(RAS_Rasterizer *rasty); + virtual void Activate(RAS_Rasterizer *rasty); + virtual void Desactivate(RAS_Rasterizer *rasty); + virtual void ActivateInstancing(RAS_Rasterizer *rasty, RAS_InstancingBuffer *buffer); + virtual void ActivateMeshUser(RAS_MeshUser *meshUser, RAS_Rasterizer *rasty, const mt::mat3x4& camtrans); + + void UpdateTextures(); + void ApplyTextures(); + void ActivateShaders(RAS_Rasterizer *rasty); + + void ActivateBlenderShaders(RAS_Rasterizer *rasty); + + const RAS_Rasterizer::BlendFunc *GetBlendFunc() const; + virtual bool UseInstancing() const; + virtual const std::string GetTextureName() const; + virtual Material *GetBlenderMaterial() const; + virtual bool UsesLighting() const; + virtual void GetRGBAColor(unsigned char *rgba) const; + virtual Scene *GetBlenderScene() const; + virtual SCA_IScene *GetScene() const; + virtual void ReloadMaterial(); + + void InitTextures(); + + void ReplaceScene(KX_Scene *scene); + + static void EndFrame(RAS_Rasterizer *rasty); + // for ipos - void UpdateIPO( - MT_Vector4 rgba, MT_Vector3 specrgb, - MT_Scalar hard, MT_Scalar spec, - MT_Scalar ref, MT_Scalar emit, MT_Scalar alpha - ); + virtual void UpdateIPO(const mt::vec4 &rgba, const mt::vec3 &specrgb, float hard, float spec, float ref, + float emit, float ambient, float alpha, float specalpha); - virtual void Replace_IScene(SCA_IScene *val); + virtual const RAS_AttributeArray::AttribList GetAttribs(const RAS_Mesh::LayersInfo& layersInfo) const; + virtual RAS_InstancingBuffer::Attrib GetInstancingAttribs() const; - BL_Material *GetBLMaterial(); + // Stuff for cvalue related things. + virtual std::string GetName(); #ifdef WITH_PYTHON - // -------------------------------- - virtual PyObject *py_repr(void) { return PyUnicode_From_STR_String(mMaterial->matname); } - - static PyObject *pyattr_get_shader(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_materialIndex(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_blending(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_blending(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject *pyattr_get_alpha(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_alpha(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject *pyattr_get_hardness(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_hardness(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject *pyattr_get_specular_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_specular_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject *pyattr_get_specular_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_specular_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject *pyattr_get_diffuse_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_diffuse_intensity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject *pyattr_get_diffuse_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_diffuse_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject *pyattr_get_emit(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_emit(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - - KX_PYMETHOD_DOC(KX_BlenderMaterial, getShader); - KX_PYMETHOD_DOC(KX_BlenderMaterial, getMaterialIndex); - KX_PYMETHOD_DOC(KX_BlenderMaterial, getTexture); - KX_PYMETHOD_DOC(KX_BlenderMaterial, setTexture); - KX_PYMETHOD_DOC(KX_BlenderMaterial, getTextureBindcode); - - KX_PYMETHOD_DOC(KX_BlenderMaterial, setBlending); -#endif /* WITH_PYTHON */ - - // -------------------------------- - // pre calculate to avoid pops/lag at startup - virtual void OnConstruction(); - - static void EndFrame(); + + static PyObject *pyattr_get_shader(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_materialIndex(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_blending(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_textures(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_blending(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_alpha(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_alpha(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_hardness(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_hardness(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_specular_intensity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_specular_intensity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_specular_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_specular_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_diffuse_intensity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_diffuse_intensity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_diffuse_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_diffuse_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_emit(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_emit(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_ambient(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_ambient(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_specular_alpha(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_specular_alpha(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + + unsigned int py_get_textures_size(); + PyObject *py_get_textures_item(unsigned int index); + std::string py_get_textures_item_name(unsigned int index); + + EXP_PYMETHOD_DOC(KX_BlenderMaterial, getShader); + EXP_PYMETHOD_DOC(KX_BlenderMaterial, getTextureBindcode); + + EXP_PYMETHOD_DOC(KX_BlenderMaterial, setBlending); + +#endif // WITH_PYTHON private: - BL_Material* mMaterial; - BL_Shader* mShader; - BL_BlenderShader* mBlenderShader; - KX_Scene* mScene; - BL_Texture mTextures[MAXTEX]; // texture array - bool mUserDefBlend; - unsigned int mBlendFunc[2]; - bool mModified; - bool mConstructed; // if false, don't clean on exit - int mLightLayer; + Material *m_material; + BL_Shader *m_shader; + BL_BlenderShader *m_blenderShader; + KX_Scene *m_scene; + bool m_userDefBlend; + RAS_Rasterizer::BlendFunc m_blendFunc[2]; struct { float r, g, b, a; @@ -163,39 +121,18 @@ class KX_BlenderMaterial : public PyObjectPlus, public RAS_IPolyMaterial float ref; float hardness; float emit; - } mSavedData; - - void InitTextures(); - - void SetBlenderGLSLShader(); - - void ActivatGLMaterials( RAS_IRasterizer* rasty )const; - void ActivateTexGen( RAS_IRasterizer *ras ) const; + float ambient; + float specularalpha; + } m_savedData; - bool UsesLighting(RAS_IRasterizer *rasty) const; - void GetMaterialRGBAColor(unsigned char *rgba) const; - Scene* GetBlenderScene() const; - void ReleaseMaterial(); + void ActivateGLMaterials(RAS_Rasterizer *rasty) const; - // message centers - void setTexData( bool enable,RAS_IRasterizer *ras); - void setBlenderShaderData( bool enable, RAS_IRasterizer *ras); - void setShaderData( bool enable, RAS_IRasterizer *ras); - - void setObjectMatrixData(int i, RAS_IRasterizer *ras); - void setTexMatrixData(int i); - - void setLightData(); - - // cleanup stuff - void OnExit(); - - // shader chacing - static BL_BlenderShader *mLastBlenderShader; - static BL_Shader *mLastShader; - - mutable int mPass; + void SetBlenderShaderData(RAS_Rasterizer *ras); + void SetShaderData(RAS_Rasterizer *ras); }; +#ifdef WITH_PYTHON +bool ConvertPythonToMaterial(PyObject *value, KX_BlenderMaterial **material, bool py_none_ok, const char *error_prefix); +#endif // WITH_PYTHON #endif diff --git a/source/gameengine/Ketsji/KX_BoneParentNodeRelationship.cpp b/source/gameengine/Ketsji/KX_BoneParentNodeRelationship.cpp new file mode 100644 index 000000000000..e72a61c7c25f --- /dev/null +++ b/source/gameengine/Ketsji/KX_BoneParentNodeRelationship.cpp @@ -0,0 +1,105 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Ketsji/KX_BoneParentNodeRelationship.cpp + * \ingroup ketsji + */ + +#include "KX_BoneParentNodeRelationship.h" + +#include "BL_ArmatureObject.h" + +#include "mathfu.h" + +#include "BLI_utildefines.h" + +KX_BoneParentRelation::KX_BoneParentRelation(Bone *bone) + :m_bone(bone) +{ +} + +KX_BoneParentRelation::~KX_BoneParentRelation() +{ +} + +bool KX_BoneParentRelation::UpdateChildCoordinates(SG_Node *child, const SG_Node *parent, bool& parentUpdated) +{ + BLI_assert(child != nullptr); + + // We don't know if the armature has been updated or not, assume yes. + parentUpdated = true; + + // The childs world locations which we will update. + bool valid_parent_transform = false; + + if (parent) { + BL_ArmatureObject *armature = (BL_ArmatureObject *)(parent->GetClientObject()); + if (armature) { + mt::mat3x4 bonetrans; + if (armature->GetBoneTransform(m_bone, bonetrans)) { + const mt::vec3& cscale = child->GetLocalScale(); + const mt::vec3& cpos = child->GetLocalPosition(); + const mt::mat3& crot = child->GetLocalOrientation(); + + // The child's world transform is parent * child + const mt::mat3x4 ptrans = parent->GetWorldTransform() * bonetrans; + + // Get the child's transform, and the bone matrix. + const mt::mat3x4 trans = ptrans * + mt::mat3x4(crot, cpos + mt::vec3(0.0f, armature->GetBoneLength(m_bone), 0.0f), cscale); + + // Recompute the child transform components from the transform. + const mt::vec3 scale = trans.ScaleVector3D(); + const mt::vec3 invscale(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z); + const mt::vec3 pos = trans.TranslationVector3D(); + const mt::mat3 rot = trans.RotationMatrix().Scale(invscale); + + child->SetWorldScale(scale); + child->SetWorldPosition(pos); + child->SetWorldOrientation(rot); + + valid_parent_transform = true; + } + } + } + + if (!valid_parent_transform) { + child->SetWorldFromLocalTransform(); + } + + child->ClearModified(); + // This node must always be updated, so reschedule it for next time. + child->ActivateRecheduleUpdateCallback(); + return valid_parent_transform; +} + +SG_ParentRelation *KX_BoneParentRelation::NewCopy() +{ + KX_BoneParentRelation *bone_parent = new KX_BoneParentRelation(m_bone); + return bone_parent; +} + diff --git a/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.h b/source/gameengine/Ketsji/KX_BoneParentNodeRelationship.h similarity index 59% rename from source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.h rename to source/gameengine/Ketsji/KX_BoneParentNodeRelationship.h index 957d514246b4..2caa18fda1e9 100644 --- a/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.h +++ b/source/gameengine/Ketsji/KX_BoneParentNodeRelationship.h @@ -26,38 +26,29 @@ * */ -/** \file KX_SG_BoneParentNodeRelationship.h +/** \file KX_BoneParentNodeRelationship.h * \ingroup ketsji */ -#ifndef __KX_SG_BONEPARENTNODERELATIONSHIP_H__ -#define __KX_SG_BONEPARENTNODERELATIONSHIP_H__ +#ifndef __KX_BONEPARENTNODERELATIONSHIP_H__ +#define __KX_BONEPARENTNODERELATIONSHIP_H__ -#include "SG_Spatial.h" #include "SG_ParentRelation.h" struct Bone; /** - * Bone parent relationship parents a child SG_Spatial frame to a + * Bone parent relationship parents a child SG_Node frame to a * bone in an armature object. */ class KX_BoneParentRelation : public SG_ParentRelation { +private: + Bone *m_bone; -public : - /** - * Allocate and construct a new KX_SG_BoneParentRelation - * on the heap. - * - * bone is the bone id to use. Currently it is a pointer - * to a Blender struct Bone - this should be fixed if - */ - - static - KX_BoneParentRelation * - New(Bone* bone - ); +public: + KX_BoneParentRelation(Bone *bone); + virtual ~KX_BoneParentRelation(); /** * Updates the childs world coordinates relative to the parent's @@ -65,32 +56,10 @@ public : * * Parent should be a BL_ArmatureObject. */ - bool - UpdateChildCoordinates( - SG_Spatial * child, - const SG_Spatial * parent, - bool& parentUpdated - ); - - /** - * Create a copy of this relationship - */ - SG_ParentRelation * - NewCopy( - ); - - ~KX_BoneParentRelation( - ); - -private : - Bone* m_bone; - KX_BoneParentRelation(Bone* bone - ); - + virtual bool UpdateChildCoordinates(SG_Node *child, const SG_Node *parent, bool& parentUpdated); -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_BoneParentRelation") -#endif + /// Create a copy of this relationship. + virtual SG_ParentRelation *NewCopy(); }; -#endif +#endif // __KX_BONEPARENTNODERELATIONSHIP_H__ diff --git a/source/gameengine/Ketsji/KX_BoundingBox.cpp b/source/gameengine/Ketsji/KX_BoundingBox.cpp new file mode 100644 index 000000000000..842131232294 --- /dev/null +++ b/source/gameengine/Ketsji/KX_BoundingBox.cpp @@ -0,0 +1,381 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + + +#include "KX_BoundingBox.h" +#include "KX_GameObject.h" +#include "KX_PyMath.h" + +#include + +#ifdef WITH_PYTHON + +KX_BoundingBox::KX_BoundingBox(KX_GameObject *owner) + :m_owner(owner), + m_proxy(owner->GetProxy()) +{ +} + +KX_BoundingBox::~KX_BoundingBox() +{ +} + +std::string KX_BoundingBox::GetName() +{ + return "KX_BoundingBox"; +} + +std::string KX_BoundingBox::GetText() +{ + if (!IsValidOwner()) { + return "KX_BoundingBox of invalid object"; + } + return (boost::format("KX_BoundingBox of object %1%, min: %2%, max: %3%") % m_owner->GetName() % GetMin() % GetMax()).str(); +} + +bool KX_BoundingBox::IsValidOwner() +{ + if (!EXP_PROXY_REF(m_proxy)) { + PyErr_SetString(PyExc_SystemError, "KX_BoundingBox, " EXP_PROXY_ERROR_MSG); + return false; + } + return true; +} + +const mt::vec3& KX_BoundingBox::GetMax() const +{ + // Update AABB to make sure we have the last one. + m_owner->UpdateBounds(false); + const SG_BBox& box = m_owner->GetCullingNode().GetAabb(); + return box.GetMax(); +} + +const mt::vec3& KX_BoundingBox::GetMin() const +{ + // Update AABB to make sure we have the last one. + m_owner->UpdateBounds(false); + const SG_BBox& box = m_owner->GetCullingNode().GetAabb(); + return box.GetMin(); +} + +const mt::vec3 KX_BoundingBox::GetCenter() const +{ + // Update AABB to make sure we have the last one. + m_owner->UpdateBounds(false); + const SG_BBox& box = m_owner->GetCullingNode().GetAabb(); + return box.GetCenter(); +} + +float KX_BoundingBox::GetRadius() const +{ + // Update AABB to make sure we have the last one. + m_owner->UpdateBounds(false); + const SG_BBox& box = m_owner->GetCullingNode().GetAabb(); + return box.GetRadius(); +} + +bool KX_BoundingBox::SetMax(const mt::vec3 &max) +{ + const mt::vec3& min = GetMin(); + + if (min.x > max.x || min.y > max.y || min.z > max.z) { + return false; + } + + m_owner->SetBoundsAabb(min, max); + return true; +} + +bool KX_BoundingBox::SetMin(const mt::vec3 &min) +{ + const mt::vec3& max = GetMax(); + + if (min.x > max.x || min.y > max.y || min.z > max.z) { + return false; + } + + m_owner->SetBoundsAabb(min, max); + return true; +} + + +#ifdef USE_MATHUTILS + +#define MATHUTILS_VEC_CB_BOX_MIN 1 +#define MATHUTILS_VEC_CB_BOX_MAX 2 + +static unsigned char mathutils_kxboundingbox_vector_cb_index = -1; /* index for our callbacks */ + +static int mathutils_kxboundingbox_generic_check(BaseMathObject *bmo) +{ + KX_BoundingBox *self = static_castEXP_PROXY_REF(bmo->cb_user); + if (!self) { + return -1; + } + + return 0; +} + +static int mathutils_kxboundingbox_vector_get(BaseMathObject *bmo, int subtype) +{ + KX_BoundingBox *self = static_castEXP_PROXY_REF(bmo->cb_user); + if (!self) { + return -1; + } + + switch (subtype) { + case MATHUTILS_VEC_CB_BOX_MIN: + { + self->GetMin().Pack(bmo->data); + break; + } + case MATHUTILS_VEC_CB_BOX_MAX: + { + self->GetMax().Pack(bmo->data); + break; + } + } + + return 0; +} + +static int mathutils_kxboundingbox_vector_set(BaseMathObject *bmo, int subtype) +{ + KX_BoundingBox *self = static_castEXP_PROXY_REF(bmo->cb_user); + if (!self) { + return -1; + } + + switch (subtype) { + case MATHUTILS_VEC_CB_BOX_MIN: + { + if (!self->SetMin(mt::vec3(bmo->data))) { + PyErr_SetString(PyExc_AttributeError, "bounds.min = Vector: KX_BoundingBox, min bigger than max"); + return -1; + } + break; + } + case MATHUTILS_VEC_CB_BOX_MAX: + { + if (!self->SetMax(mt::vec3(bmo->data))) { + PyErr_SetString(PyExc_AttributeError, "bounds.max = Vector: KX_BoundingBox, max smaller than min"); + return -1; + } + break; + } + } + + return 0; +} + +static int mathutils_kxboundingbox_vector_get_index(BaseMathObject *bmo, int subtype, int index) +{ + /* lazy, avoid repeteing the case statement */ + if (mathutils_kxboundingbox_vector_get(bmo, subtype) == -1) { + return -1; + } + return 0; +} + +static int mathutils_kxboundingbox_vector_set_index(BaseMathObject *bmo, int subtype, int index) +{ + float f = bmo->data[index]; + + /* lazy, avoid repeateing the case statement */ + if (mathutils_kxboundingbox_vector_get(bmo, subtype) == -1) { + return -1; + } + + bmo->data[index] = f; + return mathutils_kxboundingbox_vector_set(bmo, subtype); +} + +static Mathutils_Callback mathutils_kxboundingbox_vector_cb = { + mathutils_kxboundingbox_generic_check, + mathutils_kxboundingbox_vector_get, + mathutils_kxboundingbox_vector_set, + mathutils_kxboundingbox_vector_get_index, + mathutils_kxboundingbox_vector_set_index +}; + +void KX_BoundingBox_Mathutils_Callback_Init() +{ + // register mathutils callbacks, ok to run more than once. + mathutils_kxboundingbox_vector_cb_index = Mathutils_RegisterCallback(&mathutils_kxboundingbox_vector_cb); +} + +#endif // USE_MATHUTILS + +PyTypeObject KX_BoundingBox::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_BoundingBox", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &EXP_PyObjectPlus::Type, + 0, 0, 0, 0, 0, 0, + py_base_new +}; + +PyMethodDef KX_BoundingBox::Methods[] = { + {nullptr, nullptr} // Sentinel +}; + +PyAttributeDef KX_BoundingBox::Attributes[] = { + EXP_PYATTRIBUTE_RW_FUNCTION("min", KX_BoundingBox, pyattr_get_min, pyattr_set_min), + EXP_PYATTRIBUTE_RW_FUNCTION("max", KX_BoundingBox, pyattr_get_max, pyattr_set_max), + EXP_PYATTRIBUTE_RO_FUNCTION("center", KX_BoundingBox, pyattr_get_center), + EXP_PYATTRIBUTE_RO_FUNCTION("radius", KX_BoundingBox, pyattr_get_radius), + EXP_PYATTRIBUTE_RW_FUNCTION("autoUpdate", KX_BoundingBox, pyattr_get_auto_update, pyattr_set_auto_update), + EXP_PYATTRIBUTE_NULL // Sentinel +}; + +PyObject *KX_BoundingBox::pyattr_get_min(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_BoundingBox *self = static_cast(self_v); + if (!self->IsValidOwner()) { + return nullptr; + } + +#ifdef USE_MATHUTILS + return Vector_CreatePyObject_cb( + EXP_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxboundingbox_vector_cb_index, MATHUTILS_VEC_CB_BOX_MIN); +#else + return PyObjectFrom(self->GetMin()); +#endif // USE_MATHUTILS +} + +int KX_BoundingBox::pyattr_set_min(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_BoundingBox *self = static_cast(self_v); + if (!self->IsValidOwner()) { + return PY_SET_ATTR_FAIL; + } + + mt::vec3 min; + if (!PyVecTo(value, min)) { + return PY_SET_ATTR_FAIL; + } + if (!self->SetMin(min)) { + PyErr_SetString(PyExc_AttributeError, "bounds.min = Vector: KX_BoundingBox, min bigger than max"); + return PY_SET_ATTR_FAIL; + } + + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_BoundingBox::pyattr_get_max(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_BoundingBox *self = static_cast(self_v); + if (!self->IsValidOwner()) { + return nullptr; + } + +#ifdef USE_MATHUTILS + return Vector_CreatePyObject_cb( + EXP_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxboundingbox_vector_cb_index, MATHUTILS_VEC_CB_BOX_MAX); +#else + return PyObjectFrom(self->GetMax()); +#endif // USE_MATHUTILS +} + +int KX_BoundingBox::pyattr_set_max(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_BoundingBox *self = static_cast(self_v); + if (!self->IsValidOwner()) { + return PY_SET_ATTR_FAIL; + } + + mt::vec3 max; + if (!PyVecTo(value, max)) { + return PY_SET_ATTR_FAIL; + } + if (!self->SetMax(max)) { + PyErr_SetString(PyExc_AttributeError, "bounds.max = Vector: KX_BoundingBox, max smaller than min"); + return PY_SET_ATTR_FAIL; + } + + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_BoundingBox::pyattr_get_center(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_BoundingBox *self = static_cast(self_v); + if (!self->IsValidOwner()) { + return nullptr; + } + + return PyObjectFrom(self->GetCenter()); +} + +PyObject *KX_BoundingBox::pyattr_get_radius(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_BoundingBox *self = static_cast(self_v); + if (!self->IsValidOwner()) { + return nullptr; + } + + return PyFloat_FromDouble(self->GetRadius()); +} + +PyObject *KX_BoundingBox::pyattr_get_auto_update(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_BoundingBox *self = static_cast(self_v); + if (!self->IsValidOwner()) { + return nullptr; + } + + return PyBool_FromLong(self->m_owner->GetAutoUpdateBounds()); +} + +int KX_BoundingBox::pyattr_set_auto_update(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_BoundingBox *self = static_cast(self_v); + if (!self->IsValidOwner()) { + return PY_SET_ATTR_FAIL; + } + + int autoUpdate = PyObject_IsTrue(value); + if (autoUpdate == -1) { + PyErr_SetString(PyExc_AttributeError, "bounds.autoUpdate = bool: KX_BoundingBox, expected True or False"); + return PY_SET_ATTR_FAIL; + } + + self->m_owner->SetAutoUpdateBounds((bool)autoUpdate); + + return PY_SET_ATTR_SUCCESS; +} + +#endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_BoundingBox.h b/source/gameengine/Ketsji/KX_BoundingBox.h new file mode 100644 index 000000000000..b9b14fd65ec3 --- /dev/null +++ b/source/gameengine/Ketsji/KX_BoundingBox.h @@ -0,0 +1,87 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __KX_BOUNDING_BOX_H__ +#define __KX_BOUNDING_BOX_H__ + +#ifdef WITH_PYTHON + +#include "EXP_Value.h" +#include "mathfu.h" + +class KX_GameObject; + +#ifdef USE_MATHUTILS +/// Setup mathutils callbacks. +void KX_BoundingBox_Mathutils_Callback_Init(); +#endif + +/** \brief Temporary python proxy class to alterate the game object + * bounding box/AABB. Any instance of this class is owned by python. + */ +class KX_BoundingBox : public EXP_Value +{ + Py_Header +protected: + /// The game object owner of this bounding box proxy. + KX_GameObject *m_owner; + /// The game object owner python proxy. + PyObject *m_proxy; + +public: + KX_BoundingBox(KX_GameObject *owner); + virtual ~KX_BoundingBox(); + + virtual std::string GetName(); + virtual std::string GetText(); + + /** Return true if the object owner is still valid. + * Else return false and print a python error. + */ + bool IsValidOwner(); + + /// Return AABB max. + const mt::vec3& GetMax() const; + /// Return AABB min. + const mt::vec3& GetMin() const; + /// Return AABB center. + const mt::vec3 GetCenter() const; + /// Return AABB radius. + float GetRadius() const; + /// Set AABB max, return false if the max is lesser than min. + bool SetMax(const mt::vec3 &max); + /// Set AABB min, return true if the max is greater than max. + bool SetMin(const mt::vec3 &min); + + static PyObject *pyattr_get_min(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_min(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_max(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_max(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_center(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_radius(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_auto_update(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_auto_update(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); +}; + +#endif // WITH_PYTHON + +#endif // __KX_BOUNDING_BOX_H__ diff --git a/source/gameengine/Ketsji/KX_Camera.cpp b/source/gameengine/Ketsji/KX_Camera.cpp index 93f1621255d1..0c7076ef4d6b 100644 --- a/source/gameengine/Ketsji/KX_Camera.cpp +++ b/source/gameengine/Ketsji/KX_Camera.cpp @@ -31,51 +31,46 @@ */ -#include "glew-mx.h" #include "KX_Camera.h" #include "KX_Scene.h" -#include "KX_PythonInit.h" -#include "EXP_Python.h" +#include "KX_Globals.h" #include "KX_PyMath.h" +#include "KX_RayCast.h" #include "RAS_ICanvas.h" -KX_Camera::KX_Camera(void* sgReplicationInfo, +#include "GPU_glew.h" + +#include + +KX_Camera::KX_Camera(void *sgReplicationInfo, SG_Callbacks callbacks, const RAS_CameraData& camdata, - bool frustum_culling, - bool delete_node) - : - KX_GameObject(sgReplicationInfo,callbacks), - m_camdata(camdata), - m_dirty(true), - m_normalized(false), - m_frustum_culling(frustum_culling), - m_set_projection_matrix(false), - m_set_frustum_center(false), - m_delete_node(delete_node) + bool frustum_culling) + : + KX_GameObject(sgReplicationInfo, callbacks), + m_camdata(camdata), + m_projection_matrix(mt::mat4::Identity()), + m_modelview_matrix(mt::mat4::Identity()), + m_dirty(true), + m_normalized(false), + m_frustum_culling(frustum_culling), + m_set_projection_matrix(false), + m_lodDistanceFactor(1.0f), + m_activityCulling(false), + m_showDebugCameraFrustum(false) { - // setting a name would be nice... - m_name = "cam"; - m_projection_matrix.setIdentity(); - m_modelview_matrix.setIdentity(); } KX_Camera::~KX_Camera() { - if (m_delete_node && m_pSGNode) - { - // for shadow camera, avoids memleak - delete m_pSGNode; - m_pSGNode = NULL; - } } -CValue* KX_Camera::GetReplica() +EXP_Value *KX_Camera::GetReplica() { - KX_Camera* replica = new KX_Camera(*this); + KX_Camera *replica = new KX_Camera(*this); // this will copy properties and so on... replica->ProcessReplica(); @@ -86,64 +81,28 @@ CValue* KX_Camera::GetReplica() void KX_Camera::ProcessReplica() { KX_GameObject::ProcessReplica(); - // replicated camera are always registered in the scene - m_delete_node = false; } -MT_Transform KX_Camera::GetWorldToCamera() const +mt::mat3x4 KX_Camera::GetWorldToCamera() const { - MT_Transform camtrans; - camtrans.invert(MT_Transform(NodeGetWorldPosition(), NodeGetWorldOrientation())); - - return camtrans; + return GetCameraToWorld().Inverse(); } -MT_Transform KX_Camera::GetCameraToWorld() const +mt::mat3x4 KX_Camera::GetCameraToWorld() const { - return MT_Transform(NodeGetWorldPosition(), NodeGetWorldOrientation()); + return mt::mat3x4(NodeGetWorldOrientation(), NodeGetWorldPosition()); } - - -void KX_Camera::CorrectLookUp(MT_Scalar speed) -{ -} - - - -const MT_Point3 KX_Camera::GetCameraLocation() const -{ - /* this is the camera locatio in cam coords... */ - //return m_trans1.getOrigin(); - //return MT_Point3(0,0,0); <----- - /* .... I want it in world coords */ - //MT_Transform trans; - //trans.setBasis(NodeGetWorldOrientation()); - - return NodeGetWorldPosition(); -} - - - -/* I want the camera orientation as well. */ -const MT_Quaternion KX_Camera::GetCameraOrientation() const -{ - return NodeGetWorldOrientation().getRotation(); -} - - - /** * Sets the projection matrix that is used by the rasterizer. */ -void KX_Camera::SetProjectionMatrix(const MT_Matrix4x4 & mat) +void KX_Camera::SetProjectionMatrix(const mt::mat4 & mat) { m_projection_matrix = mat; m_dirty = true; m_set_projection_matrix = true; - m_set_frustum_center = false; } @@ -151,11 +110,10 @@ void KX_Camera::SetProjectionMatrix(const MT_Matrix4x4 & mat) /** * Sets the modelview matrix that is used by the rasterizer. */ -void KX_Camera::SetModelviewMatrix(const MT_Matrix4x4 & mat) +void KX_Camera::SetModelviewMatrix(const mt::mat4 & mat) { m_modelview_matrix = mat; m_dirty = true; - m_set_frustum_center = false; } @@ -163,7 +121,7 @@ void KX_Camera::SetModelviewMatrix(const MT_Matrix4x4 & mat) /** * Gets the projection matrix that is used by the rasterizer. */ -const MT_Matrix4x4& KX_Camera::GetProjectionMatrix() const +const mt::mat4& KX_Camera::GetProjectionMatrix() const { return m_projection_matrix; } @@ -173,7 +131,7 @@ const MT_Matrix4x4& KX_Camera::GetProjectionMatrix() const /** * Gets the modelview matrix that is used by the rasterizer. */ -const MT_Matrix4x4& KX_Camera::GetModelviewMatrix() const +const mt::mat4& KX_Camera::GetModelviewMatrix() const { return m_modelview_matrix; } @@ -257,219 +215,58 @@ float KX_Camera::GetFocalLength() const return m_camdata.m_focallength; } +float KX_Camera::GetZoom() const +{ + return m_camdata.m_zoom; +} - -RAS_CameraData* KX_Camera::GetCameraData() +RAS_CameraData *KX_Camera::GetCameraData() { return &m_camdata; } -void KX_Camera::ExtractClipPlanes() +void KX_Camera::SetShowCameraFrustum(bool show) { - if (!m_dirty) - return; - - MT_Matrix4x4 m = m_projection_matrix * m_modelview_matrix; - // Left clip plane - m_planes[0] = m[3] + m[0]; - // Right clip plane - m_planes[1] = m[3] - m[0]; - // Top clip plane - m_planes[2] = m[3] - m[1]; - // Bottom clip plane - m_planes[3] = m[3] + m[1]; - // Near clip plane - m_planes[4] = m[3] + m[2]; - // Far clip plane - m_planes[5] = m[3] - m[2]; - - m_dirty = false; - m_normalized = false; + m_showDebugCameraFrustum = show; } -void KX_Camera::NormalizeClipPlanes() +bool KX_Camera::GetShowCameraFrustum() const { - if (m_normalized) - return; - - for (unsigned int p = 0; p < 6; p++) - { - MT_Scalar factor = sqrtf(m_planes[p][0]*m_planes[p][0] + m_planes[p][1]*m_planes[p][1] + m_planes[p][2]*m_planes[p][2]); - if (!MT_fuzzyZero(factor)) - m_planes[p] /= factor; - } - - m_normalized = true; + return m_showDebugCameraFrustum; } -void KX_Camera::ExtractFrustumSphere() +float KX_Camera::GetLodDistanceFactor() const { - if (m_set_frustum_center) - return; - - // compute sphere for the general case and not only symmetric frustum: - // the mirror code in ImageRender can use very asymmetric frustum. - // We will put the sphere center on the line that goes from origin to the center of the far clipping plane - // This is the optimal position if the frustum is symmetric or very asymmetric and probably close - // to optimal for the general case. The sphere center position is computed so that the distance to - // the near and far extreme frustum points are equal. - - // get the transformation matrix from device coordinate to camera coordinate - MT_Matrix4x4 clip_camcs_matrix = m_projection_matrix; - clip_camcs_matrix.invert(); - - if (m_projection_matrix[3][3] == MT_Scalar(0.0f)) - { - // frustum projection - // detect which of the corner of the far clipping plane is the farthest to the origin - MT_Vector4 nfar; // far point in device normalized coordinate - MT_Point3 farpoint; // most extreme far point in camera coordinate - MT_Point3 nearpoint;// most extreme near point in camera coordinate - MT_Point3 farcenter(0.0f, 0.0f, 0.0f);// center of far cliping plane in camera coordinate - MT_Scalar F=-1.0f, N; // square distance of far and near point to origin - MT_Scalar f, n; // distance of far and near point to z axis. f is always > 0 but n can be < 0 - MT_Scalar e, s; // far and near clipping distance (<0) - MT_Scalar c; // slope of center line = distance of far clipping center to z axis / far clipping distance - MT_Scalar z; // projection of sphere center on z axis (<0) - // tmp value - MT_Vector4 npoint(1.0f, 1.0f, 1.0f, 1.0f); - MT_Vector4 hpoint; - MT_Point3 point; - MT_Scalar len; - for (int i=0; i<4; i++) - { - hpoint = clip_camcs_matrix*npoint; - point.setValue(hpoint[0]/hpoint[3], hpoint[1]/hpoint[3], hpoint[2]/hpoint[3]); - len = point.dot(point); - if (len > F) - { - nfar = npoint; - farpoint = point; - F = len; - } - // rotate by 90 degree along the z axis to walk through the 4 extreme points of the far clipping plane - len = npoint[0]; - npoint[0] = -npoint[1]; - npoint[1] = len; - farcenter += point; - } - // the far center is the average of the far clipping points - farcenter *= 0.25f; - // the extreme near point is the opposite point on the near clipping plane - nfar.setValue(-nfar[0], -nfar[1], -1.0f, 1.0f); - nfar = clip_camcs_matrix*nfar; - nearpoint.setValue(nfar[0]/nfar[3], nfar[1]/nfar[3], nfar[2]/nfar[3]); - // this is a frustum projection - N = nearpoint.dot(nearpoint); - e = farpoint[2]; - s = nearpoint[2]; - // projection on XY plane for distance to axis computation - MT_Point2 farxy(farpoint[0], farpoint[1]); - // f is forced positive by construction - f = farxy.length(); - // get corresponding point on the near plane - farxy *= s/e; - // this formula preserve the sign of n - n = f*s/e - MT_Point2(nearpoint[0]-farxy[0], nearpoint[1]-farxy[1]).length(); - c = MT_Point2(farcenter[0], farcenter[1]).length()/e; - // the big formula, it simplifies to (F-N)/(2(e-s)) for the symmetric case - z = (F-N)/(2.0f*(e-s+c*(f-n))); - m_frustum_center = MT_Point3(farcenter[0]*z/e, farcenter[1]*z/e, z); - m_frustum_radius = m_frustum_center.distance(farpoint); - } - else - { - // orthographic projection - // The most extreme points on the near and far plane. (normalized device coords) - MT_Vector4 hnear(1.0f, 1.0f, 1.0f, 1.0f), hfar(-1.0f, -1.0f, -1.0f, 1.0f); - - // Transform to hom camera local space - hnear = clip_camcs_matrix*hnear; - hfar = clip_camcs_matrix*hfar; - - // Tranform to 3d camera local space. - MT_Point3 nearpoint(hnear[0]/hnear[3], hnear[1]/hnear[3], hnear[2]/hnear[3]); - MT_Point3 farpoint(hfar[0]/hfar[3], hfar[1]/hfar[3], hfar[2]/hfar[3]); - - // just use mediant point - m_frustum_center = (farpoint + nearpoint)*0.5f; - m_frustum_radius = m_frustum_center.distance(farpoint); - } - // Transform to world space. - m_frustum_center = GetCameraToWorld()(m_frustum_center); - m_frustum_radius /= fabsf(NodeGetWorldScaling()[NodeGetWorldScaling().closestAxis()]); - - m_set_frustum_center = true; + return m_lodDistanceFactor; } -bool KX_Camera::PointInsideFrustum(const MT_Point3& x) +void KX_Camera::SetLodDistanceFactor(float lodfactor) { - ExtractClipPlanes(); - - for ( unsigned int i = 0; i < 6 ; i++ ) - { - if (m_planes[i][0] * x[0] + m_planes[i][1] * x[1] + m_planes[i][2] * x[2] + m_planes[i][3] < 0.0f) - return false; - } - return true; + m_lodDistanceFactor = lodfactor; } -int KX_Camera::BoxInsideFrustum(const MT_Point3 *box) +bool KX_Camera::GetActivityCulling() const { - ExtractClipPlanes(); - - unsigned int insideCount = 0; - // 6 view frustum planes - for ( unsigned int p = 0; p < 6 ; p++ ) - { - unsigned int behindCount = 0; - // 8 box vertices. - for (unsigned int v = 0; v < 8 ; v++) - { - if (m_planes[p][0] * box[v][0] + m_planes[p][1] * box[v][1] + m_planes[p][2] * box[v][2] + m_planes[p][3] < 0.0f) - behindCount++; - } - - // 8 points behind this plane - if (behindCount == 8) - return OUTSIDE; - - // Every box vertex is on the front side of this plane - if (!behindCount) - insideCount++; - } - - // All box vertices are on the front side of all frustum planes. - if (insideCount == 6) - return INSIDE; - - return INTERSECT; + return m_activityCulling; } -int KX_Camera::SphereInsideFrustum(const MT_Point3& center, const MT_Scalar &radius) +void KX_Camera::SetActivityCulling(bool enable) { - ExtractFrustumSphere(); - if (center.distance2(m_frustum_center) > (radius + m_frustum_radius)*(radius + m_frustum_radius)) - return OUTSIDE; - - unsigned int p; - ExtractClipPlanes(); - NormalizeClipPlanes(); + m_activityCulling = enable; +} - MT_Scalar distance; - int intersect = INSIDE; - // distance: <-------- OUTSIDE -----|----- INTERSECT -----0----- INTERSECT -----|----- INSIDE --------> - // -radius radius - for (p = 0; p < 6; p++) - { - distance = m_planes[p][0]*center[0] + m_planes[p][1]*center[1] + m_planes[p][2]*center[2] + m_planes[p][3]; - if (fabsf(distance) <= radius) - intersect = INTERSECT; - else if (distance < -radius) - return OUTSIDE; +void KX_Camera::ExtractFrustum() +{ + if (m_dirty) { + m_frustum = SG_Frustum(m_projection_matrix * m_modelview_matrix); + m_dirty = false; } +} - return intersect; +const SG_Frustum& KX_Camera::GetFrustum() +{ + ExtractFrustum(); + return m_frustum; } bool KX_Camera::GetFrustumCulling() const @@ -522,51 +319,53 @@ int KX_Camera::GetViewportTop() const PyMethodDef KX_Camera::Methods[] = { - KX_PYMETHODTABLE(KX_Camera, sphereInsideFrustum), - KX_PYMETHODTABLE_O(KX_Camera, boxInsideFrustum), - KX_PYMETHODTABLE_O(KX_Camera, pointInsideFrustum), - KX_PYMETHODTABLE_NOARGS(KX_Camera, getCameraToWorld), - KX_PYMETHODTABLE_NOARGS(KX_Camera, getWorldToCamera), - KX_PYMETHODTABLE(KX_Camera, setViewport), - KX_PYMETHODTABLE_NOARGS(KX_Camera, setOnTop), - KX_PYMETHODTABLE_O(KX_Camera, getScreenPosition), - KX_PYMETHODTABLE(KX_Camera, getScreenVect), - KX_PYMETHODTABLE(KX_Camera, getScreenRay), - {NULL,NULL} //Sentinel + EXP_PYMETHODTABLE(KX_Camera, sphereInsideFrustum), + EXP_PYMETHODTABLE_O(KX_Camera, boxInsideFrustum), + EXP_PYMETHODTABLE_O(KX_Camera, pointInsideFrustum), + EXP_PYMETHODTABLE_NOARGS(KX_Camera, getCameraToWorld), + EXP_PYMETHODTABLE_NOARGS(KX_Camera, getWorldToCamera), + EXP_PYMETHODTABLE(KX_Camera, setViewport), + EXP_PYMETHODTABLE_NOARGS(KX_Camera, setOnTop), + EXP_PYMETHODTABLE_O(KX_Camera, getScreenPosition), + EXP_PYMETHODTABLE(KX_Camera, getScreenVect), + EXP_PYMETHODTABLE(KX_Camera, getScreenRay), + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_Camera::Attributes[] = { - KX_PYATTRIBUTE_BOOL_RW("frustum_culling", KX_Camera, m_frustum_culling), - KX_PYATTRIBUTE_RW_FUNCTION("perspective", KX_Camera, pyattr_get_perspective, pyattr_set_perspective), + EXP_PYATTRIBUTE_BOOL_RW("frustum_culling", KX_Camera, m_frustum_culling), + EXP_PYATTRIBUTE_BOOL_RW("activityCulling", KX_Camera, m_activityCulling), + EXP_PYATTRIBUTE_RW_FUNCTION("perspective", KX_Camera, pyattr_get_perspective, pyattr_set_perspective), - KX_PYATTRIBUTE_RW_FUNCTION("lens", KX_Camera, pyattr_get_lens, pyattr_set_lens), - KX_PYATTRIBUTE_RW_FUNCTION("fov", KX_Camera, pyattr_get_fov, pyattr_set_fov), - KX_PYATTRIBUTE_RW_FUNCTION("ortho_scale", KX_Camera, pyattr_get_ortho_scale, pyattr_set_ortho_scale), - KX_PYATTRIBUTE_RW_FUNCTION("near", KX_Camera, pyattr_get_near, pyattr_set_near), - KX_PYATTRIBUTE_RW_FUNCTION("far", KX_Camera, pyattr_get_far, pyattr_set_far), - KX_PYATTRIBUTE_RW_FUNCTION("shift_x", KX_Camera, pyattr_get_shift_x, pyattr_set_shift_x), - KX_PYATTRIBUTE_RW_FUNCTION("shift_y", KX_Camera, pyattr_get_shift_y, pyattr_set_shift_y), + EXP_PYATTRIBUTE_RW_FUNCTION("lens", KX_Camera, pyattr_get_lens, pyattr_set_lens), + EXP_PYATTRIBUTE_RW_FUNCTION("fov", KX_Camera, pyattr_get_fov, pyattr_set_fov), + EXP_PYATTRIBUTE_RW_FUNCTION("ortho_scale", KX_Camera, pyattr_get_ortho_scale, pyattr_set_ortho_scale), + EXP_PYATTRIBUTE_RW_FUNCTION("near", KX_Camera, pyattr_get_near, pyattr_set_near), + EXP_PYATTRIBUTE_RW_FUNCTION("far", KX_Camera, pyattr_get_far, pyattr_set_far), + EXP_PYATTRIBUTE_RW_FUNCTION("shift_x", KX_Camera, pyattr_get_shift_x, pyattr_set_shift_x), + EXP_PYATTRIBUTE_RW_FUNCTION("shift_y", KX_Camera, pyattr_get_shift_y, pyattr_set_shift_y), + EXP_PYATTRIBUTE_FLOAT_RW("lodDistanceFactor", 0.0f, FLT_MAX, KX_Camera, m_lodDistanceFactor), - KX_PYATTRIBUTE_RW_FUNCTION("useViewport", KX_Camera, pyattr_get_use_viewport, pyattr_set_use_viewport), + EXP_PYATTRIBUTE_RW_FUNCTION("useViewport", KX_Camera, pyattr_get_use_viewport, pyattr_set_use_viewport), - KX_PYATTRIBUTE_RW_FUNCTION("projection_matrix", KX_Camera, pyattr_get_projection_matrix, pyattr_set_projection_matrix), - KX_PYATTRIBUTE_RO_FUNCTION("modelview_matrix", KX_Camera, pyattr_get_modelview_matrix), - KX_PYATTRIBUTE_RO_FUNCTION("camera_to_world", KX_Camera, pyattr_get_camera_to_world), - KX_PYATTRIBUTE_RO_FUNCTION("world_to_camera", KX_Camera, pyattr_get_world_to_camera), + EXP_PYATTRIBUTE_RW_FUNCTION("projection_matrix", KX_Camera, pyattr_get_projection_matrix, pyattr_set_projection_matrix), + EXP_PYATTRIBUTE_RO_FUNCTION("modelview_matrix", KX_Camera, pyattr_get_modelview_matrix), + EXP_PYATTRIBUTE_RO_FUNCTION("camera_to_world", KX_Camera, pyattr_get_camera_to_world), + EXP_PYATTRIBUTE_RO_FUNCTION("world_to_camera", KX_Camera, pyattr_get_world_to_camera), /* Grrr, functions for constants? */ - KX_PYATTRIBUTE_RO_FUNCTION("INSIDE", KX_Camera, pyattr_get_INSIDE), - KX_PYATTRIBUTE_RO_FUNCTION("OUTSIDE", KX_Camera, pyattr_get_OUTSIDE), - KX_PYATTRIBUTE_RO_FUNCTION("INTERSECT", KX_Camera, pyattr_get_INTERSECT), + EXP_PYATTRIBUTE_RO_FUNCTION("INSIDE", KX_Camera, pyattr_get_INSIDE), + EXP_PYATTRIBUTE_RO_FUNCTION("OUTSIDE", KX_Camera, pyattr_get_OUTSIDE), + EXP_PYATTRIBUTE_RO_FUNCTION("INTERSECT", KX_Camera, pyattr_get_INTERSECT), - { NULL } //Sentinel + EXP_PYATTRIBUTE_NULL //Sentinel }; PyTypeObject KX_Camera::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_Camera", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -577,302 +376,298 @@ PyTypeObject KX_Camera::Type = { 0, &KX_GameObject::Sequence, &KX_GameObject::Mapping, - 0,0,0, - NULL, - NULL, + 0, 0, 0, + nullptr, + nullptr, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &KX_GameObject::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; -KX_PYMETHODDEF_DOC_VARARGS(KX_Camera, sphereInsideFrustum, -"sphereInsideFrustum(center, radius) -> Integer\n" -"\treturns INSIDE, OUTSIDE or INTERSECT if the given sphere is\n" -"\tinside/outside/intersects this camera's viewing frustum.\n\n" -"\tcenter = the center of the sphere (in world coordinates.)\n" -"\tradius = the radius of the sphere\n\n" -"\tExample:\n" -"\timport bge.logic\n\n" -"\tco = bge.logic.getCurrentController()\n" -"\tcam = co.GetOwner()\n\n" -"\t# A sphere of radius 4.0 located at [x, y, z] = [1.0, 1.0, 1.0]\n" -"\tif (cam.sphereInsideFrustum([1.0, 1.0, 1.0], 4) != cam.OUTSIDE):\n" -"\t\t# Sphere is inside frustum !\n" -"\t\t# Do something useful !\n" -"\telse:\n" -"\t\t# Sphere is outside frustum\n" -) +EXP_PYMETHODDEF_DOC_VARARGS(KX_Camera, sphereInsideFrustum, + "sphereInsideFrustum(center, radius) -> Integer\n" + "\treturns INSIDE, OUTSIDE or INTERSECT if the given sphere is\n" + "\tinside/outside/intersects this camera's viewing frustum.\n\n" + "\tcenter = the center of the sphere (in world coordinates.)\n" + "\tradius = the radius of the sphere\n\n" + "\tExample:\n" + "\timport bge.logic\n\n" + "\tco = bge.logic.getCurrentController()\n" + "\tcam = co.GetOwner()\n\n" + "\t# A sphere of radius 4.0 located at [x, y, z] = [1.0, 1.0, 1.0]\n" + "\tif (cam.sphereInsideFrustum([1.0, 1.0, 1.0], 4) != cam.OUTSIDE):\n" + "\t\t# Sphere is inside frustum !\n" + "\t\t# Do something useful !\n" + "\telse:\n" + "\t\t# Sphere is outside frustum\n" + ) { PyObject *pycenter; float radius; - if (PyArg_ParseTuple(args, "Of:sphereInsideFrustum", &pycenter, &radius)) - { - MT_Point3 center; - if (PyVecTo(pycenter, center)) - { - return PyLong_FromLong(SphereInsideFrustum(center, radius)); /* new ref */ + if (PyArg_ParseTuple(args, "Of:sphereInsideFrustum", &pycenter, &radius)) { + mt::vec3 center; + if (PyVecTo(pycenter, center)) { + return PyLong_FromLong(GetFrustum().SphereInsideFrustum(center, radius)); /* new ref */ } } PyErr_SetString(PyExc_TypeError, "camera.sphereInsideFrustum(center, radius): KX_Camera, expected arguments: (center, radius)"); - return NULL; -} - -KX_PYMETHODDEF_DOC_O(KX_Camera, boxInsideFrustum, -"boxInsideFrustum(box) -> Integer\n" -"\treturns INSIDE, OUTSIDE or INTERSECT if the given box is\n" -"\tinside/outside/intersects this camera's viewing frustum.\n\n" -"\tbox = a list of the eight (8) corners of the box (in world coordinates.)\n\n" -"\tExample:\n" -"\timport bge.logic\n\n" -"\tco = bge.logic.getCurrentController()\n" -"\tcam = co.GetOwner()\n\n" -"\tbox = []\n" -"\tbox.append([-1.0, -1.0, -1.0])\n" -"\tbox.append([-1.0, -1.0, 1.0])\n" -"\tbox.append([-1.0, 1.0, -1.0])\n" -"\tbox.append([-1.0, 1.0, 1.0])\n" -"\tbox.append([ 1.0, -1.0, -1.0])\n" -"\tbox.append([ 1.0, -1.0, 1.0])\n" -"\tbox.append([ 1.0, 1.0, -1.0])\n" -"\tbox.append([ 1.0, 1.0, 1.0])\n\n" -"\tif (cam.boxInsideFrustum(box) != cam.OUTSIDE):\n" -"\t\t# Box is inside/intersects frustum !\n" -"\t\t# Do something useful !\n" -"\telse:\n" -"\t\t# Box is outside the frustum !\n" -) + return nullptr; +} + +EXP_PYMETHODDEF_DOC_O(KX_Camera, boxInsideFrustum, + "boxInsideFrustum(box) -> Integer\n" + "\treturns INSIDE, OUTSIDE or INTERSECT if the given box is\n" + "\tinside/outside/intersects this camera's viewing frustum.\n\n" + "\tbox = a list of the eight (8) corners of the box (in world coordinates.)\n\n" + "\tExample:\n" + "\timport bge.logic\n\n" + "\tco = bge.logic.getCurrentController()\n" + "\tcam = co.GetOwner()\n\n" + "\tbox = []\n" + "\tbox.append([-1.0, -1.0, -1.0])\n" + "\tbox.append([-1.0, -1.0, 1.0])\n" + "\tbox.append([-1.0, 1.0, -1.0])\n" + "\tbox.append([-1.0, 1.0, 1.0])\n" + "\tbox.append([ 1.0, -1.0, -1.0])\n" + "\tbox.append([ 1.0, -1.0, 1.0])\n" + "\tbox.append([ 1.0, 1.0, -1.0])\n" + "\tbox.append([ 1.0, 1.0, 1.0])\n\n" + "\tif (cam.boxInsideFrustum(box) != cam.OUTSIDE):\n" + "\t\t# Box is inside/intersects frustum !\n" + "\t\t# Do something useful !\n" + "\telse:\n" + "\t\t# Box is outside the frustum !\n" + ) { unsigned int num_points = PySequence_Size(value); - if (num_points != 8) - { + if (num_points != 8) { PyErr_Format(PyExc_TypeError, "camera.boxInsideFrustum(box): KX_Camera, expected eight (8) points, got %d", num_points); - return NULL; + return nullptr; } - MT_Point3 box[8]; - for (unsigned int p = 0; p < 8 ; p++) + std::array box; + for (unsigned int p = 0; p < 8; p++) { PyObject *item = PySequence_GetItem(value, p); /* new ref */ bool error = !PyVecTo(item, box[p]); Py_DECREF(item); - if (error) - return NULL; + if (error) { + return nullptr; + } } - return PyLong_FromLong(BoxInsideFrustum(box)); /* new ref */ -} - -KX_PYMETHODDEF_DOC_O(KX_Camera, pointInsideFrustum, -"pointInsideFrustum(point) -> Bool\n" -"\treturns 1 if the given point is inside this camera's viewing frustum.\n\n" -"\tpoint = The point to test (in world coordinates.)\n\n" -"\tExample:\n" -"\timport bge.logic\n\n" -"\tco = bge.logic.getCurrentController()\n" -"\tcam = co.GetOwner()\n\n" -"\t# Test point [0.0, 0.0, 0.0]" -"\tif (cam.pointInsideFrustum([0.0, 0.0, 0.0])):\n" -"\t\t# Point is inside frustum !\n" -"\t\t# Do something useful !\n" -"\telse:\n" -"\t\t# Box is outside the frustum !\n" -) -{ - MT_Point3 point; - if (PyVecTo(value, point)) - { - return PyLong_FromLong(PointInsideFrustum(point)); /* new ref */ + return PyLong_FromLong(GetFrustum().BoxInsideFrustum(box)); /* new ref */ +} + +EXP_PYMETHODDEF_DOC_O(KX_Camera, pointInsideFrustum, + "pointInsideFrustum(point) -> Bool\n" + "\treturns 1 if the given point is inside this camera's viewing frustum.\n\n" + "\tpoint = The point to test (in world coordinates.)\n\n" + "\tExample:\n" + "\timport bge.logic\n\n" + "\tco = bge.logic.getCurrentController()\n" + "\tcam = co.GetOwner()\n\n" + "\t# Test point [0.0, 0.0, 0.0]" + "\tif (cam.pointInsideFrustum([0.0, 0.0, 0.0])):\n" + "\t\t# Point is inside frustum !\n" + "\t\t# Do something useful !\n" + "\telse:\n" + "\t\t# Box is outside the frustum !\n" + ) +{ + mt::vec3 point; + if (PyVecTo(value, point)) { + return PyLong_FromLong(GetFrustum().PointInsideFrustum(point)); /* new ref */ } PyErr_SetString(PyExc_TypeError, "camera.pointInsideFrustum(point): KX_Camera, expected point argument."); - return NULL; + return nullptr; } -KX_PYMETHODDEF_DOC_NOARGS(KX_Camera, getCameraToWorld, -"getCameraToWorld() -> Matrix4x4\n" -"\treturns the camera to world transformation matrix, as a list of four lists of four values.\n\n" -"\tie: [[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]])\n" -) +EXP_PYMETHODDEF_DOC_NOARGS(KX_Camera, getCameraToWorld, + "getCameraToWorld() -> Matrix4x4\n" + "\treturns the camera to world transformation matrix, as a list of four lists of four values.\n\n" + "\tie: [[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]])\n" + ) { - return PyObjectFrom(GetCameraToWorld()); /* new ref */ + return PyObjectFrom(mt::mat4::FromAffineTransform(GetCameraToWorld())); /* new ref */ } -KX_PYMETHODDEF_DOC_NOARGS(KX_Camera, getWorldToCamera, -"getWorldToCamera() -> Matrix4x4\n" -"\treturns the world to camera transformation matrix, as a list of four lists of four values.\n\n" -"\tie: [[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]])\n" -) +EXP_PYMETHODDEF_DOC_NOARGS(KX_Camera, getWorldToCamera, + "getWorldToCamera() -> Matrix4x4\n" + "\treturns the world to camera transformation matrix, as a list of four lists of four values.\n\n" + "\tie: [[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]])\n" + ) { - return PyObjectFrom(GetWorldToCamera()); /* new ref */ + return PyObjectFrom(mt::mat4::FromAffineTransform(GetWorldToCamera())); /* new ref */ } -KX_PYMETHODDEF_DOC_VARARGS(KX_Camera, setViewport, -"setViewport(left, bottom, right, top)\n" -"Sets this camera's viewport\n") +EXP_PYMETHODDEF_DOC_VARARGS(KX_Camera, setViewport, + "setViewport(left, bottom, right, top)\n" + "Sets this camera's viewport\n") { int left, bottom, right, top; - if (!PyArg_ParseTuple(args,"iiii:setViewport",&left, &bottom, &right, &top)) - return NULL; + if (!PyArg_ParseTuple(args, "iiii:setViewport", &left, &bottom, &right, &top)) { + return nullptr; + } SetViewport(left, bottom, right, top); Py_RETURN_NONE; } -KX_PYMETHODDEF_DOC_NOARGS(KX_Camera, setOnTop, -"setOnTop()\n" -"Sets this camera's viewport on top\n") +EXP_PYMETHODDEF_DOC_NOARGS(KX_Camera, setOnTop, + "setOnTop()\n" + "Sets this camera's viewport on top\n") { - class KX_Scene* scene = KX_GetActiveScene(); - scene->SetCameraOnTop(this); + GetScene()->SetCameraOnTop(this); Py_RETURN_NONE; } -PyObject *KX_Camera::pyattr_get_perspective(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Camera::pyattr_get_perspective(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Camera* self = static_cast(self_v); + KX_Camera *self = static_cast(self_v); return PyBool_FromLong(self->m_camdata.m_perspective); } -int KX_Camera::pyattr_set_perspective(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_Camera::pyattr_set_perspective(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_Camera* self = static_cast(self_v); - int param = PyObject_IsTrue( value ); + KX_Camera *self = static_cast(self_v); + int param = PyObject_IsTrue(value); if (param == -1) { PyErr_SetString(PyExc_AttributeError, "camera.perspective = bool: KX_Camera, expected True/False or 0/1"); return PY_SET_ATTR_FAIL; } - self->m_camdata.m_perspective= param; + self->m_camdata.m_perspective = param; self->InvalidateProjectionMatrix(); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_Camera::pyattr_get_lens(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Camera::pyattr_get_lens(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Camera* self = static_cast(self_v); + KX_Camera *self = static_cast(self_v); return PyFloat_FromDouble(self->m_camdata.m_lens); } -int KX_Camera::pyattr_set_lens(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_Camera::pyattr_set_lens(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_Camera* self = static_cast(self_v); + KX_Camera *self = static_cast(self_v); float param = PyFloat_AsDouble(value); if (param == -1) { PyErr_SetString(PyExc_AttributeError, "camera.lens = float: KX_Camera, expected a float greater than zero"); return PY_SET_ATTR_FAIL; } - self->m_camdata.m_lens= param; + self->m_camdata.m_lens = param; self->m_set_projection_matrix = false; return PY_SET_ATTR_SUCCESS; } -PyObject *KX_Camera::pyattr_get_fov(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Camera::pyattr_get_fov(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Camera* self = static_cast(self_v); + KX_Camera *self = static_cast(self_v); float lens = self->m_camdata.m_lens; float width = self->m_camdata.m_sensor_x; float fov = 2.0f * atanf(0.5f * width / lens); - return PyFloat_FromDouble(fov * MT_DEGS_PER_RAD); + return PyFloat_FromDouble(RAD2DEGF(fov)); } -int KX_Camera::pyattr_set_fov(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_Camera::pyattr_set_fov(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_Camera* self = static_cast(self_v); + KX_Camera *self = static_cast(self_v); float fov = PyFloat_AsDouble(value); if (fov <= 0.0f) { PyErr_SetString(PyExc_AttributeError, "camera.fov = float: KX_Camera, expected a float greater than zero"); return PY_SET_ATTR_FAIL; } - fov *= MT_RADS_PER_DEG; float width = self->m_camdata.m_sensor_x; - float lens = width / (2.0f * tanf(0.5f * fov)); + float lens = width / (2.0f * tanf(0.5f * DEG2RADF(fov))); - self->m_camdata.m_lens= lens; + self->m_camdata.m_lens = lens; self->m_set_projection_matrix = false; return PY_SET_ATTR_SUCCESS; } -PyObject *KX_Camera::pyattr_get_ortho_scale(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Camera::pyattr_get_ortho_scale(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Camera* self = static_cast(self_v); + KX_Camera *self = static_cast(self_v); return PyFloat_FromDouble(self->m_camdata.m_scale); } -int KX_Camera::pyattr_set_ortho_scale(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_Camera::pyattr_set_ortho_scale(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_Camera* self = static_cast(self_v); + KX_Camera *self = static_cast(self_v); float param = PyFloat_AsDouble(value); if (param == -1) { PyErr_SetString(PyExc_AttributeError, "camera.ortho_scale = float: KX_Camera, expected a float greater than zero"); return PY_SET_ATTR_FAIL; } - self->m_camdata.m_scale= param; + self->m_camdata.m_scale = param; self->m_set_projection_matrix = false; return PY_SET_ATTR_SUCCESS; } -PyObject *KX_Camera::pyattr_get_near(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Camera::pyattr_get_near(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Camera* self = static_cast(self_v); + KX_Camera *self = static_cast(self_v); return PyFloat_FromDouble(self->m_camdata.m_clipstart); } -int KX_Camera::pyattr_set_near(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_Camera::pyattr_set_near(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_Camera* self = static_cast(self_v); + KX_Camera *self = static_cast(self_v); float param = PyFloat_AsDouble(value); if (param == -1) { PyErr_SetString(PyExc_AttributeError, "camera.near = float: KX_Camera, expected a float greater than zero"); return PY_SET_ATTR_FAIL; } - self->m_camdata.m_clipstart= param; + self->m_camdata.m_clipstart = param; self->m_set_projection_matrix = false; return PY_SET_ATTR_SUCCESS; } -PyObject *KX_Camera::pyattr_get_far(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Camera::pyattr_get_far(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Camera* self = static_cast(self_v); + KX_Camera *self = static_cast(self_v); return PyFloat_FromDouble(self->m_camdata.m_clipend); } -int KX_Camera::pyattr_set_far(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_Camera::pyattr_set_far(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_Camera* self = static_cast(self_v); + KX_Camera *self = static_cast(self_v); float param = PyFloat_AsDouble(value); if (param == -1) { PyErr_SetString(PyExc_AttributeError, "camera.far = float: KX_Camera, expected a float greater than zero"); return PY_SET_ATTR_FAIL; } - self->m_camdata.m_clipend= param; + self->m_camdata.m_clipend = param; self->m_set_projection_matrix = false; return PY_SET_ATTR_SUCCESS; } -PyObject *KX_Camera::pyattr_get_shift_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Camera::pyattr_get_shift_x(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Camera* self = static_cast(self_v); + KX_Camera *self = static_cast(self_v); return PyFloat_FromDouble(self->m_camdata.m_shift_x); } -int KX_Camera::pyattr_set_shift_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_Camera::pyattr_set_shift_x(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_Camera* self = static_cast(self_v); + KX_Camera *self = static_cast(self_v); float param = PyFloat_AsDouble(value); if (param == -1) { PyErr_SetString(PyExc_AttributeError, "camera.shift_x = float: KX_Camera, expected a float greater than zero"); @@ -884,15 +679,15 @@ int KX_Camera::pyattr_set_shift_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrde return PY_SET_ATTR_SUCCESS; } -PyObject *KX_Camera::pyattr_get_shift_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Camera::pyattr_get_shift_y(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Camera* self = static_cast(self_v); + KX_Camera *self = static_cast(self_v); return PyFloat_FromDouble(self->m_camdata.m_shift_y); } -int KX_Camera::pyattr_set_shift_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_Camera::pyattr_set_shift_y(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_Camera* self = static_cast(self_v); + KX_Camera *self = static_cast(self_v); float param = PyFloat_AsDouble(value); if (param == -1) { PyErr_SetString(PyExc_AttributeError, "camera.shift_y = float: KX_Camera, expected a float greater than zero"); @@ -904,16 +699,16 @@ int KX_Camera::pyattr_set_shift_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrde return PY_SET_ATTR_SUCCESS; } -PyObject *KX_Camera::pyattr_get_use_viewport(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Camera::pyattr_get_use_viewport(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Camera* self = static_cast(self_v); + KX_Camera *self = static_cast(self_v); return PyBool_FromLong(self->GetViewport()); } -int KX_Camera::pyattr_set_use_viewport(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_Camera::pyattr_set_use_viewport(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_Camera* self = static_cast(self_v); - int param = PyObject_IsTrue( value ); + KX_Camera *self = static_cast(self_v); + int param = PyObject_IsTrue(value); if (param == -1) { PyErr_SetString(PyExc_AttributeError, "camera.useViewport = bool: KX_Camera, expected True or False"); return PY_SET_ATTR_FAIL; @@ -922,77 +717,85 @@ int KX_Camera::pyattr_set_use_viewport(void *self_v, const KX_PYATTRIBUTE_DEF *a return PY_SET_ATTR_SUCCESS; } - -PyObject *KX_Camera::pyattr_get_projection_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Camera::pyattr_get_projection_matrix(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Camera* self = static_cast(self_v); + KX_Camera *self = static_cast(self_v); return PyObjectFrom(self->GetProjectionMatrix()); } -int KX_Camera::pyattr_set_projection_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_Camera::pyattr_set_projection_matrix(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_Camera* self = static_cast(self_v); - MT_Matrix4x4 mat; - if (!PyMatTo(value, mat)) + KX_Camera *self = static_cast(self_v); + mt::mat4 mat; + if (!PyMatTo(value, mat)) { return PY_SET_ATTR_FAIL; + } self->SetProjectionMatrix(mat); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_Camera::pyattr_get_modelview_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Camera::pyattr_get_modelview_matrix(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Camera* self = static_cast(self_v); - return PyObjectFrom(self->GetWorldToCamera()); + KX_Camera *self = static_cast(self_v); + return PyObjectFrom(mt::mat4::FromAffineTransform(self->GetWorldToCamera())); } -PyObject *KX_Camera::pyattr_get_camera_to_world(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Camera::pyattr_get_camera_to_world(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Camera* self = static_cast(self_v); - return PyObjectFrom(self->GetCameraToWorld()); + KX_Camera *self = static_cast(self_v); + return PyObjectFrom(mt::mat4::FromAffineTransform(self->GetCameraToWorld())); } -PyObject *KX_Camera::pyattr_get_world_to_camera(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Camera::pyattr_get_world_to_camera(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Camera* self = static_cast(self_v); - return PyObjectFrom(self->GetWorldToCamera()); + KX_Camera *self = static_cast(self_v); + return PyObjectFrom(mt::mat4::FromAffineTransform(self->GetWorldToCamera())); } -PyObject *KX_Camera::pyattr_get_INSIDE(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ return PyLong_FromLong(INSIDE); } -PyObject *KX_Camera::pyattr_get_OUTSIDE(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ return PyLong_FromLong(OUTSIDE); } -PyObject *KX_Camera::pyattr_get_INTERSECT(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ return PyLong_FromLong(INTERSECT); } +PyObject *KX_Camera::pyattr_get_INSIDE(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + return PyLong_FromLong(INSIDE); +} +PyObject *KX_Camera::pyattr_get_OUTSIDE(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + return PyLong_FromLong(OUTSIDE); +} +PyObject *KX_Camera::pyattr_get_INTERSECT(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + return PyLong_FromLong(INTERSECT); +} -bool ConvertPythonToCamera(PyObject *value, KX_Camera **object, bool py_none_ok, const char *error_prefix) +bool ConvertPythonToCamera(KX_Scene *scene, PyObject *value, KX_Camera **object, bool py_none_ok, const char *error_prefix) { - if (value==NULL) { - PyErr_Format(PyExc_TypeError, "%s, python pointer NULL, should never happen", error_prefix); - *object = NULL; + if (value == nullptr) { + PyErr_Format(PyExc_TypeError, "%s, python pointer nullptr, should never happen", error_prefix); + *object = nullptr; return false; } - if (value==Py_None) { - *object = NULL; + if (value == Py_None) { + *object = nullptr; if (py_none_ok) { return true; - } else { + } + else { PyErr_Format(PyExc_TypeError, "%s, expected KX_Camera or a KX_Camera name, None is invalid", error_prefix); return false; } } if (PyUnicode_Check(value)) { - STR_String value_str = _PyUnicode_AsString(value); - *object = KX_GetActiveScene()->FindCamera(value_str); + std::string value_str = _PyUnicode_AsString(value); + *object = scene->GetCameraList()->FindValue(value_str); if (*object) { return true; - } else { + } + else { PyErr_Format(PyExc_ValueError, "%s, requested name \"%s\" did not match any KX_Camera in this scene", error_prefix, _PyUnicode_AsString(value)); @@ -1001,66 +804,66 @@ bool ConvertPythonToCamera(PyObject *value, KX_Camera **object, bool py_none_ok, } if (PyObject_TypeCheck(value, &KX_Camera::Type)) { - *object = static_castBGE_PROXY_REF(value); + *object = static_castEXP_PROXY_REF(value); /* sets the error */ - if (*object==NULL) { - PyErr_Format(PyExc_SystemError, "%s, " BGE_PROXY_ERROR_MSG, error_prefix); + if (*object == nullptr) { + PyErr_Format(PyExc_SystemError, "%s, " EXP_PROXY_ERROR_MSG, error_prefix); return false; } return true; } - *object = NULL; + *object = nullptr; if (py_none_ok) { PyErr_Format(PyExc_TypeError, "%s, expect a KX_Camera, a string or None", error_prefix); - } else { + } + else { PyErr_Format(PyExc_TypeError, "%s, expect a KX_Camera or a string", error_prefix); } return false; } -KX_PYMETHODDEF_DOC_O(KX_Camera, getScreenPosition, -"getScreenPosition()\n" -) +EXP_PYMETHODDEF_DOC_O(KX_Camera, getScreenPosition, + "getScreenPosition()\n" + ) { - MT_Vector3 vect; - KX_GameObject *obj = NULL; + mt::vec3 vect; + KX_GameObject *obj = nullptr; - if (!PyVecTo(value, vect)) - { + if (!PyVecTo(value, vect)) { PyErr_Clear(); - if (ConvertPythonToGameObject(GetScene()->GetLogicManager(), value, &obj, true, "")) - { + if (ConvertPythonToGameObject(GetScene()->GetLogicManager(), value, &obj, false, "")) { PyErr_Clear(); - vect = MT_Vector3(obj->NodeGetWorldPosition()); + vect = mt::vec3(obj->NodeGetWorldPosition()); } - else - { + else { PyErr_SetString(PyExc_TypeError, "Error in getScreenPosition. Expected a Vector3 or a KX_GameObject or a string for a name of a KX_GameObject"); - return NULL; + return nullptr; } } const GLint *viewport; GLdouble win[3]; - GLdouble modelmatrix[16]; - GLdouble projmatrix[16]; + GLdouble dmodelmatrix[16]; + GLdouble dprojmatrix[16]; - MT_Matrix4x4 m_modelmatrix = this->GetWorldToCamera(); - MT_Matrix4x4 m_projmatrix = this->GetProjectionMatrix(); + const mt::mat4 modelmatrix = mt::mat4::FromAffineTransform(GetWorldToCamera()); + const mt::mat4& projmatrix = this->GetProjectionMatrix(); - m_modelmatrix.getValue(modelmatrix); - m_projmatrix.getValue(projmatrix); + for (unsigned short i = 0; i < 16; ++i) { + dmodelmatrix[i] = modelmatrix[i]; + dprojmatrix[i] = projmatrix[i]; + } viewport = KX_GetActiveEngine()->GetCanvas()->GetViewPort(); - gluProject(vect[0], vect[1], vect[2], modelmatrix, projmatrix, viewport, &win[0], &win[1], &win[2]); + gluProject(vect[0], vect[1], vect[2], dmodelmatrix, dprojmatrix, viewport, &win[0], &win[1], &win[2]); vect[0] = (win[0] - viewport[0]) / viewport[2]; vect[1] = (win[1] - viewport[1]) / viewport[3]; @@ -1074,94 +877,87 @@ KX_PYMETHODDEF_DOC_O(KX_Camera, getScreenPosition, return ret; } - return NULL; + return nullptr; } -KX_PYMETHODDEF_DOC_VARARGS(KX_Camera, getScreenVect, -"getScreenVect()\n" -) +EXP_PYMETHODDEF_DOC_VARARGS(KX_Camera, getScreenVect, + "getScreenVect()\n" + ) { - double x,y; - if (!PyArg_ParseTuple(args,"dd:getScreenVect",&x,&y)) - return NULL; + float x, y; + if (!PyArg_ParseTuple(args, "ff:getScreenVect", &x, &y)) { + return nullptr; + } y = 1.0 - y; //to follow Blender window coordinate system (Top-Down) - MT_Vector3 vect; - MT_Point3 campos, screenpos; + const mt::mat4 modelmatrix = mt::mat4::FromAffineTransform(GetWorldToCamera()); - const GLint *viewport; - GLdouble win[3]; - GLdouble modelmatrix[16]; - GLdouble projmatrix[16]; - - MT_Matrix4x4 m_modelmatrix = this->GetWorldToCamera(); - MT_Matrix4x4 m_projmatrix = this->GetProjectionMatrix(); - - m_modelmatrix.getValue(modelmatrix); - m_projmatrix.getValue(projmatrix); - - viewport = KX_GetActiveEngine()->GetCanvas()->GetViewPort(); + RAS_ICanvas *canvas = KX_GetActiveEngine()->GetCanvas(); + const int width = canvas->GetWidth(); + const int height = canvas->GetHeight(); - vect[0] = x * viewport[2]; - vect[1] = y * viewport[3]; + const mt::vec3 vect(x * width, y * height, 0.0f); + const mt::vec3 screenpos = mt::mat4::UnProject(vect, modelmatrix, m_projection_matrix, width, height); + const mt::vec3 ret = (NodeGetLocalPosition() - screenpos).Normalized(); - vect[0] += viewport[0]; - vect[1] += viewport[1]; + return PyObjectFrom(ret); +} - vect[2] = 0.f; +EXP_PYMETHODDEF_DOC_VARARGS(KX_Camera, getScreenRay, + "getScreenRay()\n" + ) +{ + float x, y, dist; + char *propName = nullptr; - gluUnProject(vect[0], vect[1], vect[2], modelmatrix, projmatrix, viewport, &win[0], &win[1], &win[2]); + if (!PyArg_ParseTuple(args, "fff|s:getScreenRay", &x, &y, &dist, &propName)) { + return nullptr; + } - campos = this->GetCameraLocation(); - screenpos = MT_Point3(win[0], win[1], win[2]); - vect = campos-screenpos; + y = 1.0 - y; //to follow Blender window coordinate system (Top-Down) - vect.normalize(); - return PyObjectFrom(vect); -} + const mt::mat4 modelmatrix = mt::mat4::FromAffineTransform(GetWorldToCamera()); -KX_PYMETHODDEF_DOC_VARARGS(KX_Camera, getScreenRay, -"getScreenRay()\n" -) -{ - MT_Vector3 vect; - double x,y,dist; - char *propName = NULL; + RAS_ICanvas *canvas = KX_GetActiveEngine()->GetCanvas(); + const int width = canvas->GetWidth(); + const int height = canvas->GetHeight(); - if (!PyArg_ParseTuple(args,"ddd|s:getScreenRay",&x,&y,&dist,&propName)) - return NULL; + mt::vec3 fromPoint; + mt::vec3 toPoint; - PyObject *argValue = PyTuple_New(2); - PyTuple_SET_ITEM(argValue, 0, PyFloat_FromDouble(x)); - PyTuple_SET_ITEM(argValue, 1, PyFloat_FromDouble(y)); + // Unproject a point in near plane. + const mt::vec3 point(x * width, y * height, 0.0f); + const mt::vec3 screenpos = mt::mat4::UnProject(point, modelmatrix, m_projection_matrix, width, height); - if (!PyVecTo(PygetScreenVect(argValue), vect)) - { - Py_DECREF(argValue); - PyErr_SetString(PyExc_TypeError, - "Error in getScreenRay. Invalid 2D coordinate. " - "Expected a normalized 2D screen coordinate, " - "a distance and an optional property argument"); - return NULL; + // For perpspective the vector is from camera center to unprojected point. + if (m_camdata.m_perspective) { + fromPoint = NodeGetWorldPosition(); + toPoint = screenpos; + } + // For orthographic the vector is the same as the -Z rotation axis but start from unprojected point. + else { + fromPoint = screenpos; + toPoint = fromPoint - NodeGetWorldOrientation().GetColumn(2); } - Py_DECREF(argValue); - dist = -dist; - vect += this->GetCameraLocation(); + if (dist != 0.0f) { + toPoint = fromPoint + dist * (toPoint - fromPoint).SafeNormalized(mt::axisX3); + } - argValue = (propName?PyTuple_New(3):PyTuple_New(2)); - if (argValue) { - PyTuple_SET_ITEM(argValue, 0, PyObjectFrom(vect)); - PyTuple_SET_ITEM(argValue, 1, PyFloat_FromDouble(dist)); - if (propName) - PyTuple_SET_ITEM(argValue, 2, PyUnicode_FromString(propName)); + PHY_IPhysicsEnvironment *pe = GetScene()->GetPhysicsEnvironment(); + PHY_IPhysicsController *spc = m_physicsController.get(); + KX_GameObject *parent = GetParent(); + if (!spc && parent) { + spc = parent->GetPhysicsController(); + } - PyObject *ret= this->PyrayCastTo(argValue,NULL); - Py_DECREF(argValue); - return ret; + RayCastData rayData("", false, (1u << OB_MAX_COL_MASKS) - 1); + KX_RayCast::Callback callback(this, spc, &rayData); + if (KX_RayCast::RayTest(pe, fromPoint, toPoint, callback) && rayData.m_hitObject) { + return rayData.m_hitObject->GetProxy(); } - return NULL; + Py_RETURN_NONE; } #endif diff --git a/source/gameengine/Ketsji/KX_Camera.h b/source/gameengine/Ketsji/KX_Camera.h index 3b96d7d01b8f..e59312612b19 100644 --- a/source/gameengine/Ketsji/KX_Camera.h +++ b/source/gameengine/Ketsji/KX_Camera.h @@ -33,19 +33,15 @@ #ifndef __KX_CAMERA_H__ #define __KX_CAMERA_H__ - -#include "MT_Transform.h" -#include "MT_Matrix3x3.h" -#include "MT_Matrix4x4.h" -#include "MT_Vector3.h" -#include "MT_Point3.h" #include "KX_GameObject.h" -#include "EXP_IntValue.h" + +#include "SG_Frustum.h" + #include "RAS_CameraData.h" #ifdef WITH_PYTHON /* utility conversion function */ -bool ConvertPythonToCamera(PyObject *value, KX_Camera **object, bool py_none_ok, const char *error_prefix); +bool ConvertPythonToCamera(KX_Scene *scene, PyObject *value, KX_Camera **object, bool py_none_ok, const char *error_prefix); #endif class KX_Camera : public KX_GameObject @@ -60,28 +56,15 @@ class KX_Camera : public KX_GameObject * here? It doesn't really have a function here. */ RAS_CameraData m_camdata; - // Never used, I think... -// void MoveTo(const MT_Point3& movevec) -// { -#if 0 - MT_Transform camtrans; - camtrans.invert(m_trans1); - MT_Matrix3x3 camorient = camtrans.getBasis(); - camtrans.translate(camorient.inverse()*movevec); - m_trans1.invert(camtrans); -#endif -// } - /** * Storage for the projection matrix that is passed to the * rasterizer. */ - MT_Matrix4x4 m_projection_matrix; - //MT_Matrix4x4 m_projection_matrix1; + mt::mat4 m_projection_matrix; /** * Storage for the modelview matrix that is passed to the * rasterizer. */ - MT_Matrix4x4 m_modelview_matrix; + mt::mat4 m_modelview_matrix; /** * true if the view frustum (modelview/projection matrix) @@ -93,108 +76,80 @@ class KX_Camera : public KX_GameObject * true if the frustum planes have been normalized. */ bool m_normalized; - + /** * View Frustum clip planes. */ - MT_Vector4 m_planes[6]; - + mt::vec4 m_planes[6]; + /** * This camera is frustum culling. * Some cameras (ie if the game was started from a non camera view should not cull.) */ bool m_frustum_culling; - + /** * true if this camera has a valid projection matrix. */ bool m_set_projection_matrix; - /** - * The center point of the frustum. - */ - MT_Point3 m_frustum_center; - MT_Scalar m_frustum_radius; - bool m_set_frustum_center; + /** Distance factor for level of detail*/ + float m_lodDistanceFactor; - /** - * whether the camera should delete the node itself (only for shadow camera) - */ - bool m_delete_node; + /// Enable object activity culling for this camera. + bool m_activityCulling; /** - * Extracts the camera clip frames from the projection and world-to-camera matrices. + * Show Debug Camera Frustum? */ - void ExtractClipPlanes(); - /** - * Normalize the camera clip frames. - */ - void NormalizeClipPlanes(); - /** - * Extracts the bound sphere of the view frustum. - */ - void ExtractFrustumSphere(); - /** - * return the clip plane - */ - MT_Vector4 *GetNormalizedClipPlanes() - { - ExtractClipPlanes(); - NormalizeClipPlanes(); - return m_planes; - } + bool m_showDebugCameraFrustum; + + SG_Frustum m_frustum; + + void ExtractFrustum(); public: enum { INSIDE, INTERSECT, OUTSIDE }; - KX_Camera(void* sgReplicationInfo,SG_Callbacks callbacks,const RAS_CameraData& camdata, bool frustum_culling = true, bool delete_node = false); + KX_Camera(void* sgReplicationInfo,SG_Callbacks callbacks,const RAS_CameraData& camdata, bool frustum_culling = true); virtual ~KX_Camera(); - /** - * Inherited from CValue -- return a new copy of this - * instance allocated on the heap. Ownership of the new + /** + * Inherited from EXP_Value -- return a new copy of this + * instance allocated on the heap. Ownership of the new * object belongs with the caller. */ - virtual CValue* + virtual EXP_Value* GetReplica( ); virtual void ProcessReplica(); - MT_Transform GetWorldToCamera() const; - MT_Transform GetCameraToWorld() const; - - /** - * Not implemented. - */ - void CorrectLookUp(MT_Scalar speed); - const MT_Point3 GetCameraLocation() const; - - /* I want the camera orientation as well. */ - const MT_Quaternion GetCameraOrientation() const; + mt::mat3x4 GetWorldToCamera() const; + mt::mat3x4 GetCameraToWorld() const; /** Sets the projection matrix that is used by the rasterizer. */ - void SetProjectionMatrix(const MT_Matrix4x4 & mat); + void SetProjectionMatrix(const mt::mat4 & mat); /** Sets the modelview matrix that is used by the rasterizer. */ - void SetModelviewMatrix(const MT_Matrix4x4 & mat); - + void SetModelviewMatrix(const mt::mat4 & mat); + /** Gets the projection matrix that is used by the rasterizer. */ - const MT_Matrix4x4& GetProjectionMatrix() const; - + const mt::mat4& GetProjectionMatrix() const; + /** returns true if this camera has been set a projection matrix. */ bool hasValidProjectionMatrix() const; - + /** Sets the validity of the projection matrix. Call this if you change camera * data (eg lens, near plane, far plane) and require the projection matrix to be * recalculated. */ void InvalidateProjectionMatrix(bool valid = false); - - /** Gets the modelview matrix that is used by the rasterizer. + + /** Gets the modelview matrix that is used by the rasterizer. * \warning If the Camera is a dynamic object then this method may return garbage. Use GetWorldToCamera() instead. */ - const MT_Matrix4x4& GetModelviewMatrix() const; + const mt::mat4& GetModelviewMatrix() const; /** Gets the aperture. */ float GetLens() const; @@ -216,118 +171,112 @@ class KX_Camera : public KX_GameObject float GetCameraFar() const; /** Gets the focal length (only used for stereo rendering) */ float GetFocalLength() const; + float GetZoom() const; /** Gets all camera data. */ RAS_CameraData* GetCameraData(); - /** - * Tests if the given sphere is inside this camera's view frustum. - * - * \param center The center of the sphere, in world coordinates. - * \param radius The radius of the sphere. - * \return INSIDE, INTERSECT, or OUTSIDE depending on the sphere's relation to the frustum. - */ - int SphereInsideFrustum(const MT_Point3& center, const MT_Scalar &radius); - /** - * Tests the given eight corners of a box with the view frustum. - * - * \param box a pointer to eight MT_Point3 representing the world coordinates of the corners of the box. - * \return INSIDE, INTERSECT, or OUTSIDE depending on the box's relation to the frustum. - */ - int BoxInsideFrustum(const MT_Point3 *box); - /** - * Tests the given point against the view frustum. - * \return true if the given point is inside or on the view frustum; false if it is outside. - */ - bool PointInsideFrustum(const MT_Point3& x); + /** Get/Set show camera frustum */ + void SetShowCameraFrustum(bool show); + bool GetShowCameraFrustum() const; + + /** Get level of detail distance factor */ + float GetLodDistanceFactor() const; + /** Set level of detail distance factor */ + void SetLodDistanceFactor(float lodfactor); + + bool GetActivityCulling() const; + void SetActivityCulling(bool enable); + + const SG_Frustum& GetFrustum(); /** * Gets this camera's culling status. */ bool GetFrustumCulling() const; - + /** * Sets this camera's viewport status. */ void EnableViewport(bool viewport); - + /** * Sets this camera's viewport. */ void SetViewport(int left, int bottom, int right, int top); - + /** * Gets this camera's viewport status. */ bool GetViewport() const; - + /** * Gets this camera's viewport left. */ int GetViewportLeft() const; - + /** * Gets this camera's viewport bottom. */ int GetViewportBottom() const; - + /** * Gets this camera's viewport right. */ int GetViewportRight() const; - + /** * Gets this camera's viewport top. */ int GetViewportTop() const; - virtual int GetGameObjectType() { return OBJ_CAMERA; } + virtual int GetGameObjectType() const { return OBJ_CAMERA; } #ifdef WITH_PYTHON - KX_PYMETHOD_DOC_VARARGS(KX_Camera, sphereInsideFrustum); - KX_PYMETHOD_DOC_O(KX_Camera, boxInsideFrustum); - KX_PYMETHOD_DOC_O(KX_Camera, pointInsideFrustum); - - KX_PYMETHOD_DOC_NOARGS(KX_Camera, getCameraToWorld); - KX_PYMETHOD_DOC_NOARGS(KX_Camera, getWorldToCamera); - - KX_PYMETHOD_DOC_VARARGS(KX_Camera, setViewport); - KX_PYMETHOD_DOC_NOARGS(KX_Camera, setOnTop); - - KX_PYMETHOD_DOC_O(KX_Camera, getScreenPosition); - KX_PYMETHOD_DOC_VARARGS(KX_Camera, getScreenVect); - KX_PYMETHOD_DOC_VARARGS(KX_Camera, getScreenRay); - - static PyObject* pyattr_get_perspective(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_perspective(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - - static PyObject* pyattr_get_lens(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_lens(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_fov(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_fov(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_ortho_scale(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_ortho_scale(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_near(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_near(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_far(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_far(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_shift_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_shift_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_shift_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_shift_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - - static PyObject* pyattr_get_use_viewport(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_use_viewport(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - - static PyObject* pyattr_get_projection_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_projection_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - - static PyObject* pyattr_get_modelview_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_camera_to_world(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_world_to_camera(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - - static PyObject* pyattr_get_INSIDE(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_OUTSIDE(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_INTERSECT(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + EXP_PYMETHOD_DOC_VARARGS(KX_Camera, sphereInsideFrustum); + EXP_PYMETHOD_DOC_O(KX_Camera, boxInsideFrustum); + EXP_PYMETHOD_DOC_O(KX_Camera, pointInsideFrustum); + + EXP_PYMETHOD_DOC_NOARGS(KX_Camera, getCameraToWorld); + EXP_PYMETHOD_DOC_NOARGS(KX_Camera, getWorldToCamera); + + EXP_PYMETHOD_DOC_VARARGS(KX_Camera, setViewport); + EXP_PYMETHOD_DOC_NOARGS(KX_Camera, setOnTop); + + EXP_PYMETHOD_DOC_O(KX_Camera, getScreenPosition); + EXP_PYMETHOD_DOC_VARARGS(KX_Camera, getScreenVect); + EXP_PYMETHOD_DOC_VARARGS(KX_Camera, getScreenRay); + + static PyObject* pyattr_get_perspective(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_perspective(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + + static PyObject* pyattr_get_lens(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_lens(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_fov(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_fov(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_ortho_scale(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_ortho_scale(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_near(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_near(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_far(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_far(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_shift_x(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_shift_x(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_shift_y(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_shift_y(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + + static PyObject* pyattr_get_use_viewport(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_use_viewport(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + + static PyObject* pyattr_get_projection_matrix(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_projection_matrix(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + + static PyObject* pyattr_get_modelview_matrix(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_camera_to_world(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_world_to_camera(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + + static PyObject* pyattr_get_INSIDE(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_OUTSIDE(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_INTERSECT(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); #endif }; diff --git a/source/gameengine/Ketsji/KX_CameraActuator.cpp b/source/gameengine/Ketsji/KX_CameraActuator.cpp index f71699da5d80..7da6ee2362b5 100644 --- a/source/gameengine/Ketsji/KX_CameraActuator.cpp +++ b/source/gameengine/Ketsji/KX_CameraActuator.cpp @@ -33,90 +33,82 @@ * \ingroup ketsji */ -#include "BLI_math_vector.h" - #include "KX_CameraActuator.h" -#include -#include #include "KX_GameObject.h" -#include "EXP_PyObjectPlus.h" - /* ------------------------------------------------------------------------- */ /* Native functions */ /* ------------------------------------------------------------------------- */ -KX_CameraActuator::KX_CameraActuator( - SCA_IObject* gameobj, - SCA_IObject *obj, - float hght, - float minhght, - float maxhght, - short axis, - float damping -): +KX_CameraActuator::KX_CameraActuator(SCA_IObject *gameobj, + SCA_IObject *obj, + float hght, + float minhght, + float maxhght, + short axis, + float damping) : SCA_IActuator(gameobj, KX_ACT_CAMERA), - m_ob (obj), - m_height (hght), - m_minHeight (minhght), - m_maxHeight (maxhght), + m_ob(obj), + m_height(hght), + m_minHeight(minhght), + m_maxHeight(maxhght), m_axis(axis), - m_damping (damping) + m_damping(damping) { - if (m_ob) + if (m_ob) { m_ob->RegisterActuator(this); + } } KX_CameraActuator::~KX_CameraActuator() { - if (m_ob) + if (m_ob) { m_ob->UnregisterActuator(this); + } } - CValue* -KX_CameraActuator:: -GetReplica( -) { - KX_CameraActuator* replica = new KX_CameraActuator(*this); +EXP_Value *KX_CameraActuator::GetReplica() +{ + KX_CameraActuator *replica = new KX_CameraActuator(*this); replica->ProcessReplica(); return replica; }; void KX_CameraActuator::ProcessReplica() { - if (m_ob) + if (m_ob) { m_ob->RegisterActuator(this); + } SCA_IActuator::ProcessReplica(); } -bool KX_CameraActuator::UnlinkObject(SCA_IObject* clientobj) +bool KX_CameraActuator::UnlinkObject(SCA_IObject *clientobj) { - if (clientobj == m_ob) - { + if (clientobj == m_ob) { // this object is being deleted, we cannot continue to track it. - m_ob = NULL; + m_ob = nullptr; return true; } return false; } -void KX_CameraActuator::Relink(CTR_Map *obj_map) +void KX_CameraActuator::Relink(std::map& obj_map) { - void **h_obj = (*obj_map)[m_ob]; - if (h_obj) { - if (m_ob) + SCA_IObject *obj = obj_map[m_ob]; + if (obj) { + if (m_ob) { m_ob->UnregisterActuator(this); - m_ob = (SCA_IObject*)(*h_obj); + } + m_ob = obj; m_ob->RegisterActuator(this); } } /* copied from blender BLI_math ... don't know if there's an equivalent */ -static void Kx_VecUpMat3(float vec[3], float mat[3][3], short axis) +static void Kx_VecUpMat3(mt::vec3 &vec, mt::mat3& mat, short axis) { - // Construct a camera matrix s.t. the specified axis // maps to the given vector (*vec). Also defines the rotation @@ -131,75 +123,68 @@ static void Kx_VecUpMat3(float vec[3], float mat[3][3], short axis) * see: VecUpMat3old */ - if (axis==0) { - cox= 0; coy= 1; coz= 2; /* Y up Z tr */ + if (axis == 0) { + cox = 0; coy = 1; coz = 2; /* Y up Z tr */ } - if (axis==1) { - cox= 1; coy= 2; coz= 0; /* Z up X tr */ + if (axis == 1) { + cox = 1; coy = 2; coz = 0; /* Z up X tr */ } - if (axis==2) { - cox= 2; coy= 0; coz= 1; /* X up Y tr */ + if (axis == 2) { + cox = 2; coy = 0; coz = 1; /* X up Y tr */ } - if (axis==3) { - cox= 0; coy= 1; coz= 2; /* Y op -Z tr */ - vec[0] = -vec[0]; - vec[1] = -vec[1]; - vec[2] = -vec[2]; + if (axis == 3) { + cox = 0; coy = 1; coz = 2; /* Y op -Z tr */ + vec = -vec; } - if (axis==4) { - cox= 1; coy= 0; coz= 2; /* */ + if (axis == 4) { + cox = 1; coy = 0; coz = 2; /* */ } - if (axis==5) { - cox= 2; coy= 1; coz= 0; /* Y up X tr */ + if (axis == 5) { + cox = 2; coy = 1; coz = 0; /* Y up X tr */ } - mat[coz][0] = vec[0]; - mat[coz][1] = vec[1]; - mat[coz][2] = vec[2]; - if (normalize_v3((float *)mat[coz]) == 0.f) { + mat.GetColumn(coz) = vec; + if (mat.GetColumn(coz).Normalize() == 0.f) { /* this is a very abnormal situation: the camera has reach the object center exactly * We will choose a completely arbitrary direction */ - mat[coz][0] = 1.0f; - mat[coz][1] = 0.0f; - mat[coz][2] = 0.0f; + mat.GetColumn(coz) = mt::axisX3; } - inp = mat[coz][2]; - mat[coy][0] = - inp * mat[coz][0]; - mat[coy][1] = - inp * mat[coz][1]; - mat[coy][2] = 1.0f - inp * mat[coz][2]; + inp = mat(coz, 2); + mat(0, coy) = -inp *mat(0, coz); + mat(1, coy) = -inp *mat(1, coz); + mat(2, coy) = 1.0f - inp * mat(2, coz); - if (normalize_v3((float *)mat[coy]) == 0.f) { + if (mat.GetColumn(coy).Normalize() == 0.f) { /* the camera is vertical, chose the y axis arbitrary */ - mat[coy][0] = 0.f; - mat[coy][1] = 1.f; - mat[coy][2] = 0.f; + mat.GetColumn(coy) = mt::axisY3; } - cross_v3_v3v3(mat[cox], mat[coy], mat[coz]); + mat.GetColumn(cox) = mt::vec3::CrossProduct(mat.GetColumn(coy), mat.GetColumn(coz)); } -bool KX_CameraActuator::Update(double curtime, bool frame) +bool KX_CameraActuator::Update(double curtime) { /* wondering... is it really necessary/desirable to suppress negative */ /* events here? */ bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); - if (bNegativeEvent || !m_ob) + if (bNegativeEvent || !m_ob) { return false; + } - KX_GameObject *obj = (KX_GameObject*) GetParent(); - MT_Point3 from = obj->NodeGetWorldPosition(); - MT_Matrix3x3 frommat = obj->NodeGetWorldOrientation(); + KX_GameObject *obj = (KX_GameObject *)GetParent(); + mt::vec3 from = obj->NodeGetWorldPosition(); + mt::mat3 frommat = obj->NodeGetWorldOrientation(); /* These casts are _very_ dangerous!!! */ - MT_Point3 lookat = ((KX_GameObject*)m_ob)->NodeGetWorldPosition(); - MT_Matrix3x3 actormat = ((KX_GameObject*)m_ob)->NodeGetWorldOrientation(); + mt::vec3 lookat = ((KX_GameObject *)m_ob)->NodeGetWorldPosition(); + mt::mat3 actormat = ((KX_GameObject *)m_ob)->NodeGetWorldOrientation(); - float fp1[3]={0}, fp2[3]={0}, rc[3]; + mt::vec3 fp1, fp2, rc; float inp, fac; //, factor = 0.0; /* some factor... */ float mindistsq, maxdistsq, distsq; - float mat[3][3]; + mt::mat3 mat; /* The rules: */ /* CONSTRAINT 1: not implemented */ @@ -223,8 +208,8 @@ bool KX_CameraActuator::Update(double curtime, bool frame) /* ... set up some parameters ... */ /* missing here: the 'floorloc' of the actor's shadow */ - mindistsq= m_minHeight*m_minHeight; - maxdistsq= m_maxHeight*m_maxHeight; + mindistsq = m_minHeight * m_minHeight; + maxdistsq = m_maxHeight * m_maxHeight; /* C1: not checked... is a future option */ @@ -237,56 +222,48 @@ bool KX_CameraActuator::Update(double curtime, bool frame) /* C4: camera behind actor */ switch (m_axis) { case OB_POSX: + { /* X */ - fp1[0] = actormat[0][0]; - fp1[1] = actormat[1][0]; - fp1[2] = actormat[2][0]; + fp1 = actormat.GetColumn(0); - fp2[0] = frommat[0][0]; - fp2[1] = frommat[1][0]; - fp2[2] = frommat[2][0]; + fp2 = frommat.GetColumn(0); break; + } case OB_POSY: + { /* Y */ - fp1[0] = actormat[0][1]; - fp1[1] = actormat[1][1]; - fp1[2] = actormat[2][1]; + fp1 = actormat.GetColumn(1); - fp2[0] = frommat[0][1]; - fp2[1] = frommat[1][1]; - fp2[2] = frommat[2][1]; + fp2 = frommat.GetColumn(1); break; + } case OB_NEGX: + { /* -X */ - fp1[0] = -actormat[0][0]; - fp1[1] = -actormat[1][0]; - fp1[2] = -actormat[2][0]; + fp1 = -actormat.GetColumn(0); - fp2[0] = frommat[0][0]; - fp2[1] = frommat[1][0]; - fp2[2] = frommat[2][0]; + fp2 = frommat.GetColumn(0); break; + } case OB_NEGY: + { /* -Y */ - fp1[0] = -actormat[0][1]; - fp1[1] = -actormat[1][1]; - fp1[2] = -actormat[2][1]; + fp1 = -actormat.GetColumn(1); - fp2[0] = frommat[0][1]; - fp2[1] = frommat[1][1]; - fp2[2] = frommat[2][1]; + fp2 = frommat.GetColumn(1); break; + } default: - assert(0); + { + BLI_assert(0); break; + } } - inp = fp1[0]*fp2[0] + fp1[1]*fp2[1] + fp1[2]*fp2[2]; + inp = mt::vec3::DotProduct(fp1, fp2); fac = (-1.0f + inp) * m_damping; - from[0] += fac * fp1[0]; - from[1] += fac * fp1[1]; - from[2] += fac * fp1[2]; + from += fac * fp1; /* only for it lies: cross test and perpendicular bites up */ if (inp < 0.0f) { @@ -306,54 +283,33 @@ bool KX_CameraActuator::Update(double curtime, bool frame) /* CONSTRAINT 5: minimum / maximum distance */ - rc[0] = (lookat[0]-from[0]); - rc[1] = (lookat[1]-from[1]); - rc[2] = (lookat[2]-from[2]); - distsq = rc[0]*rc[0] + rc[1]*rc[1] + rc[2]*rc[2]; + rc = lookat - from; + distsq = rc.LengthSquared(); if (distsq > maxdistsq) { distsq = 0.15f * (distsq - maxdistsq) / distsq; - from[0] += distsq*rc[0]; - from[1] += distsq*rc[1]; - from[2] += distsq*rc[2]; + from += distsq * rc; } else if (distsq < mindistsq) { distsq = 0.15f * (mindistsq - distsq) / mindistsq; - from[0] -= distsq*rc[0]; - from[1] -= distsq*rc[1]; - from[2] -= distsq*rc[2]; + from -= distsq * rc; } - /* CONSTRAINT 7: track to floor below actor */ - rc[0] = (lookat[0]-from[0]); - rc[1] = (lookat[1]-from[1]); - rc[2] = (lookat[2]-from[2]); - Kx_VecUpMat3(rc, mat, 3); /* y up Track -z */ - - - + rc = lookat - from; + Kx_VecUpMat3(rc, mat, 3); /* y up Track -z */ /* now set the camera position and rotation */ obj->NodeSetLocalPosition(from); - actormat[0][0] = mat[0][0]; actormat[0][1] = mat[1][0]; actormat[0][2] = mat[2][0]; - actormat[1][0] = mat[0][1]; actormat[1][1] = mat[1][1]; actormat[1][2] = mat[2][1]; - actormat[2][0] = mat[0][2]; actormat[2][1] = mat[1][2]; actormat[2][2] = mat[2][2]; - obj->NodeSetLocalOrientation(actormat); + obj->NodeSetLocalOrientation(mat); return true; } -CValue *KX_CameraActuator::findObject(const char *obName) -{ - /* hook to object system */ - return NULL; -} - #ifdef WITH_PYTHON /* ------------------------------------------------------------------------- */ @@ -362,9 +318,9 @@ CValue *KX_CameraActuator::findObject(const char *obName) /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_CameraActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_CameraActuator", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -372,53 +328,58 @@ PyTypeObject KX_CameraActuator::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IActuator::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_CameraActuator::Methods[] = { - {NULL, NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_CameraActuator::Attributes[] = { - KX_PYATTRIBUTE_FLOAT_RW("min",-FLT_MAX,FLT_MAX,KX_CameraActuator,m_minHeight), - KX_PYATTRIBUTE_FLOAT_RW("max",-FLT_MAX,FLT_MAX,KX_CameraActuator,m_maxHeight), - KX_PYATTRIBUTE_FLOAT_RW("height",-FLT_MAX,FLT_MAX,KX_CameraActuator,m_height), - KX_PYATTRIBUTE_SHORT_RW("axis", 0, 5, true, KX_CameraActuator, m_axis), - KX_PYATTRIBUTE_RW_FUNCTION("object", KX_CameraActuator, pyattr_get_object, pyattr_set_object), - KX_PYATTRIBUTE_FLOAT_RW("damping",0.f,10.f,KX_CameraActuator,m_damping), - {NULL} + EXP_PYATTRIBUTE_FLOAT_RW("min", -FLT_MAX, FLT_MAX, KX_CameraActuator, m_minHeight), + EXP_PYATTRIBUTE_FLOAT_RW("max", -FLT_MAX, FLT_MAX, KX_CameraActuator, m_maxHeight), + EXP_PYATTRIBUTE_FLOAT_RW("height", -FLT_MAX, FLT_MAX, KX_CameraActuator, m_height), + EXP_PYATTRIBUTE_SHORT_RW("axis", 0, 5, true, KX_CameraActuator, m_axis), + EXP_PYATTRIBUTE_RW_FUNCTION("object", KX_CameraActuator, pyattr_get_object, pyattr_set_object), + EXP_PYATTRIBUTE_FLOAT_RW("damping", 0.f, 10.f, KX_CameraActuator, m_damping), + EXP_PYATTRIBUTE_NULL }; -PyObject *KX_CameraActuator::pyattr_get_object(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_CameraActuator::pyattr_get_object(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_CameraActuator* self = static_cast(self_v); - if (self->m_ob==NULL) + KX_CameraActuator *self = static_cast(self_v); + if (self->m_ob == nullptr) { Py_RETURN_NONE; - else + } + else { return self->m_ob->GetProxy(); + } } -int KX_CameraActuator::pyattr_set_object(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_CameraActuator::pyattr_set_object(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_CameraActuator* self = static_cast(self_v); + KX_CameraActuator *self = static_cast(self_v); KX_GameObject *gameobj; - if (!ConvertPythonToGameObject(self->GetLogicManager(), value, &gameobj, true, "actuator.object = value: KX_CameraActuator")) + if (!ConvertPythonToGameObject(self->GetLogicManager(), value, &gameobj, true, "actuator.object = value: KX_CameraActuator")) { return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error - if (self->m_ob) + } + if (self->m_ob) { self->m_ob->UnregisterActuator(self); + } - if ((self->m_ob = (SCA_IObject*)gameobj)) + if ((self->m_ob = (SCA_IObject *)gameobj)) { self->m_ob->RegisterActuator(self); + } return PY_SET_ATTR_SUCCESS; } diff --git a/source/gameengine/Ketsji/KX_CameraActuator.h b/source/gameengine/Ketsji/KX_CameraActuator.h index 83668d8bf404..7f1afd5ed12e 100644 --- a/source/gameengine/Ketsji/KX_CameraActuator.h +++ b/source/gameengine/Ketsji/KX_CameraActuator.h @@ -36,7 +36,6 @@ #define __KX_CAMERAACTUATOR_H__ #include "SCA_IActuator.h" -#include "MT_Scalar.h" #include "SCA_LogicManager.h" /** @@ -55,44 +54,38 @@ private : SCA_IObject *m_ob; /** height (float), */ - //const MT_Scalar m_height; + //const float m_height; /** min (float), */ - //const MT_Scalar m_minHeight; + //const float m_minHeight; /** max (float), */ - //const MT_Scalar m_maxHeight; - + //const float m_maxHeight; + /** height (float), */ float m_height; - + /** min (float), */ float m_minHeight; - + /** max (float), */ float m_maxHeight; - + /** axis the camera tries to get behind: +x/+y/-x/-y */ short m_axis; - + /** damping (float), */ float m_damping; - /* get the KX_IGameObject with this name */ - CValue *findObject(const char *obName); - - /* parse x or y to a toggle pick */ - bool string2axischoice(const char *axisString); - - public: - static STR_String X_AXIS_STRING; - static STR_String Y_AXIS_STRING; - +public: + static std::string X_AXIS_STRING; + static std::string Y_AXIS_STRING; + /** * Set the bool toggle to true to use x lock, false for y lock */ KX_CameraActuator( SCA_IObject *gameobj, - //const CValue *ob, + //const EXP_Value *ob, SCA_IObject *ob, float hght, float minhght, @@ -106,20 +99,17 @@ private : - /** Methods Inherited from CValue */ - CValue* GetReplica(); + /** Methods Inherited from EXP_Value */ + EXP_Value* GetReplica(); virtual void ProcessReplica(); - + /** Methods inherited from SCA_IActuator */ - virtual bool Update( - double curtime, - bool frame - ); + virtual bool Update(double curtime); virtual bool UnlinkObject(SCA_IObject* clientobj); /** Methods inherited from SCA_ILogicBrick */ - virtual void Relink(CTR_Map *obj_map); + virtual void Relink(std::map& obj_map); #ifdef WITH_PYTHON @@ -128,8 +118,8 @@ private : /* --------------------------------------------------------------------- */ /* set object to look at */ - static PyObject* pyattr_get_object(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_object(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_object(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_object(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); #endif /* WITH_PYTHON */ diff --git a/source/gameengine/Ketsji/KX_CameraIpoSGController.cpp b/source/gameengine/Ketsji/KX_CameraIpoSGController.cpp index 70f5386fbb74..960f4e38b121 100644 --- a/source/gameengine/Ketsji/KX_CameraIpoSGController.cpp +++ b/source/gameengine/Ketsji/KX_CameraIpoSGController.cpp @@ -31,96 +31,33 @@ #include "KX_CameraIpoSGController.h" -#include "KX_ScalarInterpolator.h" #include "KX_Camera.h" #include "RAS_CameraData.h" -#if defined(_WIN64) -typedef unsigned __int64 uint_ptr; -#else -typedef unsigned long uint_ptr; -#endif - -bool KX_CameraIpoSGController::Update(double currentTime) +bool KX_CameraIpoSGController::Update(SG_Node *node) { - if (m_modified) - { - T_InterpolatorList::iterator i; - for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) { - (*i)->Execute(m_ipotime); - } - - SG_Spatial* ob = (SG_Spatial*)m_pObject; - KX_Camera* kxcamera = (KX_Camera*) ob->GetSGClientObject(); - RAS_CameraData* camdata = kxcamera->GetCameraData(); - - if (m_modify_lens) - camdata->m_lens = m_lens; - - if (m_modify_clipstart ) - camdata->m_clipstart = m_clipstart; - - if (m_modify_clipend) - camdata->m_clipend = m_clipend; - - if (m_modify_lens || m_modify_clipstart || m_modify_clipend) - kxcamera->InvalidateProjectionMatrix(); - - m_modified=false; + if (!SG_Controller::Update(node)) { + return false; } - return false; -} - - -void KX_CameraIpoSGController::AddInterpolator(KX_IInterpolator* interp) -{ - this->m_interpolators.push_back(interp); -} -SG_Controller* KX_CameraIpoSGController::GetReplica(class SG_Node* destnode) -{ - KX_CameraIpoSGController* iporeplica = new KX_CameraIpoSGController(*this); - // clear object that ipo acts on - iporeplica->ClearObject(); - - // dirty hack, ask Gino for a better solution in the ipo implementation - // hacken en zagen, in what we call datahiding, not written for replication :( - - T_InterpolatorList oldlist = m_interpolators; - iporeplica->m_interpolators.clear(); + KX_Camera *kxcamera = static_cast(node->GetClientObject()); + RAS_CameraData *camdata = kxcamera->GetCameraData(); - T_InterpolatorList::iterator i; - for (i = oldlist.begin(); !(i == oldlist.end()); ++i) { - KX_ScalarInterpolator* copyipo = new KX_ScalarInterpolator(*((KX_ScalarInterpolator*)*i)); - iporeplica->AddInterpolator(copyipo); - - MT_Scalar* scaal = ((KX_ScalarInterpolator*)*i)->GetTarget(); - uint_ptr orgbase = (uint_ptr)this; - uint_ptr orgloc = (uint_ptr)scaal; - uint_ptr offset = orgloc-orgbase; - uint_ptr newaddrbase = (uint_ptr)iporeplica + offset; - MT_Scalar* blaptr = (MT_Scalar*) newaddrbase; - copyipo->SetNewTarget((MT_Scalar*)blaptr); + if (m_modify_lens) { + camdata->m_lens = m_lens; } - return iporeplica; -} - -KX_CameraIpoSGController::~KX_CameraIpoSGController() -{ - - T_InterpolatorList::iterator i; - for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) { - delete (*i); + if (m_modify_clipstart) { + camdata->m_clipstart = m_clipstart; } -} + if (m_modify_clipend) { + camdata->m_clipend = m_clipend; + } - void -KX_CameraIpoSGController::SetOption( - int option, - int value) -{ - /* Setting options */ + if (m_modify_lens || m_modify_clipstart || m_modify_clipend) { + kxcamera->InvalidateProjectionMatrix(); + } + return true; } diff --git a/source/gameengine/Ketsji/KX_CameraIpoSGController.h b/source/gameengine/Ketsji/KX_CameraIpoSGController.h index 211c1a4e1981..14b121d14eb4 100644 --- a/source/gameengine/Ketsji/KX_CameraIpoSGController.h +++ b/source/gameengine/Ketsji/KX_CameraIpoSGController.h @@ -33,50 +33,34 @@ #define __KX_CAMERAIPOSGCONTROLLER_H__ #include "SG_Controller.h" -#include "SG_Spatial.h" +#include "SG_Node.h" -#include "KX_IInterpolator.h" +#include "SG_Interpolator.h" struct RAS_CameraData; class KX_CameraIpoSGController : public SG_Controller { public: - MT_Scalar m_lens; - MT_Scalar m_clipstart; - MT_Scalar m_clipend; + float m_lens; + float m_clipstart; + float m_clipend; private: - T_InterpolatorList m_interpolators; unsigned short m_modify_lens : 1; unsigned short m_modify_clipstart : 1; unsigned short m_modify_clipend : 1; - bool m_modified; - double m_ipotime; public: - KX_CameraIpoSGController() : + KX_CameraIpoSGController() : m_modify_lens(false), m_modify_clipstart(false), - m_modify_clipend(false), - m_modified(true), - m_ipotime(0.0) + m_modify_clipend(false) {} - ~KX_CameraIpoSGController(); - SG_Controller* GetReplica(class SG_Node* destnode); - bool Update(double time); + virtual ~KX_CameraIpoSGController() = default; + virtual bool Update(SG_Node *node); - void - SetOption( - int option, - int value - ); - - void SetSimulatedTime(double time) { - m_ipotime = time; - m_modified = true; - } void SetModifyLens(bool modify) { m_modify_lens = modify; } @@ -86,12 +70,6 @@ class KX_CameraIpoSGController : public SG_Controller void SetModifyClipStart(bool modify) { m_modify_clipstart = modify; } - void AddInterpolator(KX_IInterpolator* interp); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_CameraIpoSGController") -#endif }; #endif /* __KX_CAMERAIPOSGCONTROLLER_H__ */ diff --git a/source/gameengine/Ketsji/KX_CharacterWrapper.cpp b/source/gameengine/Ketsji/KX_CharacterWrapper.cpp index 44f06a9f1ebe..7f617da4de5d 100644 --- a/source/gameengine/Ketsji/KX_CharacterWrapper.cpp +++ b/source/gameengine/Ketsji/KX_CharacterWrapper.cpp @@ -23,13 +23,15 @@ */ #include "KX_CharacterWrapper.h" -#include "PHY_ICharacter.h" #include "KX_PyMath.h" + +#include "PHY_ICharacter.h" + #include "BLI_utildefines.h" +#include "BLI_math_base.h" -KX_CharacterWrapper::KX_CharacterWrapper(PHY_ICharacter* character) : - PyObjectPlus(), - m_character(character) +KX_CharacterWrapper::KX_CharacterWrapper(PHY_ICharacter *character) : + m_character(character) { } @@ -37,12 +39,17 @@ KX_CharacterWrapper::~KX_CharacterWrapper() { } +std::string KX_CharacterWrapper::GetName() +{ + return "KX_CharacterWrapper"; +} + #ifdef WITH_PYTHON PyTypeObject KX_CharacterWrapper::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_CharacterWrapper", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -50,69 +57,108 @@ PyTypeObject KX_CharacterWrapper::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, - &PyObjectPlus::Type, - 0,0,0,0,0,0, + &EXP_PyObjectPlus::Type, + 0, 0, 0, 0, 0, 0, py_base_new }; PyAttributeDef KX_CharacterWrapper::Attributes[] = { - KX_PYATTRIBUTE_RO_FUNCTION("onGround", KX_CharacterWrapper, pyattr_get_onground), - KX_PYATTRIBUTE_RW_FUNCTION("gravity", KX_CharacterWrapper, pyattr_get_gravity, pyattr_set_gravity), - KX_PYATTRIBUTE_RW_FUNCTION("maxJumps", KX_CharacterWrapper, pyattr_get_max_jumps, pyattr_set_max_jumps), - KX_PYATTRIBUTE_RO_FUNCTION("jumpCount", KX_CharacterWrapper, pyattr_get_jump_count), - KX_PYATTRIBUTE_RW_FUNCTION("walkDirection", KX_CharacterWrapper, pyattr_get_walk_dir, pyattr_set_walk_dir), - { NULL } //Sentinel + EXP_PYATTRIBUTE_RO_FUNCTION("onGround", KX_CharacterWrapper, pyattr_get_onground), + EXP_PYATTRIBUTE_RW_FUNCTION("gravity", KX_CharacterWrapper, pyattr_get_gravity, pyattr_set_gravity), + EXP_PYATTRIBUTE_RW_FUNCTION("fallSpeed", KX_CharacterWrapper, pyattr_get_fallSpeed, pyattr_set_fallSpeed), + EXP_PYATTRIBUTE_RW_FUNCTION("maxJumps", KX_CharacterWrapper, pyattr_get_max_jumps, pyattr_set_max_jumps), + EXP_PYATTRIBUTE_RW_FUNCTION("maxSlope", KX_CharacterWrapper, pyattr_get_maxSlope, pyattr_set_maxSlope), + EXP_PYATTRIBUTE_RO_FUNCTION("jumpCount", KX_CharacterWrapper, pyattr_get_jump_count), + EXP_PYATTRIBUTE_RW_FUNCTION("jumpSpeed", KX_CharacterWrapper, pyattr_get_jumpSpeed, pyattr_set_jumpSpeed), + EXP_PYATTRIBUTE_RW_FUNCTION("walkDirection", KX_CharacterWrapper, pyattr_get_walk_dir, pyattr_set_walk_dir), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *KX_CharacterWrapper::pyattr_get_onground(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_CharacterWrapper::pyattr_get_onground(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_CharacterWrapper* self = static_cast(self_v); + KX_CharacterWrapper *self = static_cast(self_v); return PyBool_FromLong(self->m_character->OnGround()); } -PyObject *KX_CharacterWrapper::pyattr_get_gravity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_CharacterWrapper::pyattr_get_gravity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_CharacterWrapper* self = static_cast(self_v); + KX_CharacterWrapper *self = static_cast(self_v); - return PyFloat_FromDouble(self->m_character->GetGravity()); + return PyObjectFrom(self->m_character->GetGravity()); } -int KX_CharacterWrapper::pyattr_set_gravity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_CharacterWrapper::pyattr_set_gravity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_CharacterWrapper* self = static_cast(self_v); - double param = PyFloat_AsDouble(value); + KX_CharacterWrapper *self = static_cast(self_v); + mt::vec3 gravity; + if (!PyVecTo(value, gravity)) { + return PY_SET_ATTR_FAIL; + } - if (param == -1) - { - PyErr_SetString(PyExc_ValueError, "KX_CharacterWrapper.gravity: expected a float"); + self->m_character->SetGravity(gravity); + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_CharacterWrapper::pyattr_get_fallSpeed(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_CharacterWrapper *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_character->GetFallSpeed()); +} + +int KX_CharacterWrapper::pyattr_set_fallSpeed(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_CharacterWrapper *self = static_cast(self_v); + const float param = PyFloat_AsDouble(value); + + if (param == -1 || param < 0.0f) { + PyErr_SetString(PyExc_ValueError, "KX_CharacterWrapper.fallSpeed: expected a positive float"); + return PY_SET_ATTR_FAIL; + } + + self->m_character->SetFallSpeed(param); + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_CharacterWrapper::pyattr_get_maxSlope(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_CharacterWrapper *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_character->GetMaxSlope()); +} + +int KX_CharacterWrapper::pyattr_set_maxSlope(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_CharacterWrapper *self = static_cast(self_v); + const float param = PyFloat_AsDouble(value); + + if (param == -1 || param < 0.0f || param > M_PI_2) { + PyErr_SetString(PyExc_ValueError, "KX_CharacterWrapper.maxSlope: expected a float between 0 and half pi"); return PY_SET_ATTR_FAIL; } - self->m_character->SetGravity((float)param); + self->m_character->SetMaxSlope(param); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_CharacterWrapper::pyattr_get_max_jumps(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_CharacterWrapper::pyattr_get_max_jumps(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_CharacterWrapper* self = static_cast(self_v); + KX_CharacterWrapper *self = static_cast(self_v); return PyLong_FromLong(self->m_character->GetMaxJumps()); } -int KX_CharacterWrapper::pyattr_set_max_jumps(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_CharacterWrapper::pyattr_set_max_jumps(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_CharacterWrapper* self = static_cast(self_v); + KX_CharacterWrapper *self = static_cast(self_v); long param = PyLong_AsLong(value); - if (param == -1) - { + if (param == -1) { PyErr_SetString(PyExc_ValueError, "KX_CharacterWrapper.maxJumps: expected an integer"); return PY_SET_ATTR_FAIL; } @@ -123,24 +169,44 @@ int KX_CharacterWrapper::pyattr_set_max_jumps(void *self_v, const KX_PYATTRIBUTE return PY_SET_ATTR_SUCCESS; } -PyObject *KX_CharacterWrapper::pyattr_get_jump_count(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_CharacterWrapper::pyattr_get_jump_count(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_CharacterWrapper* self = static_cast(self_v); + KX_CharacterWrapper *self = static_cast(self_v); return PyLong_FromLong(self->m_character->GetJumpCount()); } -PyObject *KX_CharacterWrapper::pyattr_get_walk_dir(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_CharacterWrapper::pyattr_get_jumpSpeed(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_CharacterWrapper *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_character->GetJumpSpeed()); +} + +int KX_CharacterWrapper::pyattr_set_jumpSpeed(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_CharacterWrapper *self = static_cast(self_v); + const float param = PyFloat_AsDouble(value); + + if (param == -1) { + PyErr_SetString(PyExc_ValueError, "KX_CharacterWrapper.gravity: expected a float"); + return PY_SET_ATTR_FAIL; + } + + self->m_character->SetJumpSpeed(param); + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_CharacterWrapper::pyattr_get_walk_dir(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_CharacterWrapper* self = static_cast(self_v); + KX_CharacterWrapper *self = static_cast(self_v); return PyObjectFrom(self->m_character->GetWalkDirection()); } -int KX_CharacterWrapper::pyattr_set_walk_dir(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_CharacterWrapper::pyattr_set_walk_dir(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_CharacterWrapper* self = static_cast(self_v); - MT_Vector3 dir; + KX_CharacterWrapper *self = static_cast(self_v); + mt::vec3 dir; if (!PyVecTo(value, dir)) { PyErr_SetString(PyExc_TypeError, "KX_CharacterWrapper.walkDirection: expected a vector"); return PY_SET_ATTR_FAIL; @@ -151,17 +217,50 @@ int KX_CharacterWrapper::pyattr_set_walk_dir(void *self_v, const KX_PYATTRIBUTE_ } PyMethodDef KX_CharacterWrapper::Methods[] = { - KX_PYMETHODTABLE_NOARGS(KX_CharacterWrapper, jump), - {NULL,NULL} //Sentinel + EXP_PYMETHODTABLE_NOARGS(KX_CharacterWrapper, jump), + EXP_PYMETHODTABLE(KX_CharacterWrapper, setVelocity), + EXP_PYMETHODTABLE_NOARGS(KX_CharacterWrapper, reset), + {nullptr, nullptr} //Sentinel }; -KX_PYMETHODDEF_DOC_NOARGS(KX_CharacterWrapper, jump, - "jump()\n" - "makes the character jump.\n") +EXP_PYMETHODDEF_DOC_NOARGS(KX_CharacterWrapper, jump, + "jump()\n" + "makes the character jump.\n") { m_character->Jump(); Py_RETURN_NONE; } +EXP_PYMETHODDEF_DOC(KX_CharacterWrapper, setVelocity, + "setVelocity(velocity, time, local=False)\n" + "set the character velocity for time period.\n") +{ + PyObject *pyvect; + float time; + int local = 0; + + if (!PyArg_ParseTuple(args, "Of|i:setVelocity", &pyvect, &time, &local)) { + return nullptr; + } + + mt::vec3 velocity; + if (!PyVecTo(pyvect, velocity)) { + return nullptr; + } + + m_character->SetVelocity(velocity, time, local); + + Py_RETURN_NONE; +} + +EXP_PYMETHODDEF_DOC_NOARGS(KX_CharacterWrapper, reset, + "reset()\n" + "reset the character velocity and walk direction.\n") +{ + m_character->Reset(); + + Py_RETURN_NONE; +} + #endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_CharacterWrapper.h b/source/gameengine/Ketsji/KX_CharacterWrapper.h index 262242b251b9..195d875f3274 100644 --- a/source/gameengine/Ketsji/KX_CharacterWrapper.h +++ b/source/gameengine/Ketsji/KX_CharacterWrapper.h @@ -12,25 +12,35 @@ class PHY_ICharacter; ///Python interface to character physics -class KX_CharacterWrapper : public PyObjectPlus +class KX_CharacterWrapper : public EXP_Value { Py_Header public: KX_CharacterWrapper(PHY_ICharacter* character); virtual ~KX_CharacterWrapper(); -#ifdef WITH_PYTHON - KX_PYMETHOD_DOC_NOARGS(KX_CharacterWrapper, jump); - - static PyObject* pyattr_get_onground(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_gravity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_gravity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_max_jumps(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_max_jumps(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_jump_count(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_walk_dir(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_walk_dir(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + virtual std::string GetName(); +#ifdef WITH_PYTHON + EXP_PYMETHOD_DOC_NOARGS(KX_CharacterWrapper, jump); + EXP_PYMETHOD_DOC(KX_CharacterWrapper, setVelocity); + EXP_PYMETHOD_DOC_NOARGS(KX_CharacterWrapper, reset); + + static PyObject* pyattr_get_onground(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + + static PyObject* pyattr_get_gravity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_gravity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_fallSpeed(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_fallSpeed(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_max_jumps(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_max_jumps(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_maxSlope(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_maxSlope(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_jump_count(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_jumpSpeed(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_jumpSpeed(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_walk_dir(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_walk_dir(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); #endif // WITH_PYTHON private: diff --git a/source/gameengine/Ketsji/KX_ClientObjectInfo.h b/source/gameengine/Ketsji/KX_ClientObjectInfo.h index bcbf06b947c1..8db8dff930d1 100644 --- a/source/gameengine/Ketsji/KX_ClientObjectInfo.h +++ b/source/gameengine/Ketsji/KX_ClientObjectInfo.h @@ -58,27 +58,22 @@ struct KX_ClientObjectInfo m_type(type), m_gameobject(gameobject) {} - + KX_ClientObjectInfo(const KX_ClientObjectInfo ©) : m_type(copy.m_type), m_gameobject(copy.m_gameobject) { } - + virtual ~KX_ClientObjectInfo() {} - - virtual bool hasCollisionCallback() + + virtual bool hasCollisionCallback() { return m_sensors.size() != 0; } - + bool isActor() { return m_type <= ACTOR; } bool isSensor() { return m_type >= SENSOR && m_type <= OBACTORSENSOR; } - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_ClientObjectInfo") -#endif }; #endif /* __KX_CLIENTOBJECTINFO_H__ */ diff --git a/source/gameengine/Ketsji/KX_CollisionContactPoints.cpp b/source/gameengine/Ketsji/KX_CollisionContactPoints.cpp new file mode 100644 index 000000000000..cb4d12df8471 --- /dev/null +++ b/source/gameengine/Ketsji/KX_CollisionContactPoints.cpp @@ -0,0 +1,186 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Ketsji/KX_CollisionContactPoints.cpp + * \ingroup ketsji + */ + +#include "KX_CollisionContactPoints.h" +#include "PHY_DynamicTypes.h" +#include "KX_PyMath.h" + +KX_CollisionContactPoint::KX_CollisionContactPoint(const PHY_ICollData *collData, unsigned int index, bool firstObject) + :m_collData(collData), + m_index(index), + m_firstObject(firstObject) +{ +} + +KX_CollisionContactPoint::~KX_CollisionContactPoint() +{ +} + +std::string KX_CollisionContactPoint::GetName() +{ + return "CollisionContactPoint"; +} + +#ifdef WITH_PYTHON + +PyTypeObject KX_CollisionContactPoint::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_CollisionContactPoint", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &EXP_Value::Type, + 0, 0, 0, 0, 0, 0, + py_base_new +}; + +PyMethodDef KX_CollisionContactPoint::Methods[] = { + {nullptr, nullptr} //Sentinel +}; + +PyAttributeDef KX_CollisionContactPoint::Attributes[] = { + EXP_PYATTRIBUTE_RO_FUNCTION("localPointA", KX_CollisionContactPoint, pyattr_get_local_point_a), + EXP_PYATTRIBUTE_RO_FUNCTION("localPointB", KX_CollisionContactPoint, pyattr_get_local_point_b), + EXP_PYATTRIBUTE_RO_FUNCTION("worldPoint", KX_CollisionContactPoint, pyattr_get_world_point), + EXP_PYATTRIBUTE_RO_FUNCTION("normal", KX_CollisionContactPoint, pyattr_get_normal), + EXP_PYATTRIBUTE_RO_FUNCTION("combinedFriction", KX_CollisionContactPoint, pyattr_get_combined_friction), + EXP_PYATTRIBUTE_RO_FUNCTION("combinedRollingFriction", KX_CollisionContactPoint, pyattr_get_combined_rolling_friction), + EXP_PYATTRIBUTE_RO_FUNCTION("combinedRestitution", KX_CollisionContactPoint, pyattr_get_combined_restitution), + EXP_PYATTRIBUTE_RO_FUNCTION("appliedImpulse", KX_CollisionContactPoint, pyattr_get_applied_impulse), + EXP_PYATTRIBUTE_NULL //Sentinel +}; + +PyObject *KX_CollisionContactPoint::pyattr_get_local_point_a(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_CollisionContactPoint *self = static_cast(self_v); + return PyObjectFrom(self->m_collData->GetLocalPointA(self->m_index, self->m_firstObject)); +} + +PyObject *KX_CollisionContactPoint::pyattr_get_local_point_b(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_CollisionContactPoint *self = static_cast(self_v); + return PyObjectFrom(self->m_collData->GetLocalPointB(self->m_index, self->m_firstObject)); +} + +PyObject *KX_CollisionContactPoint::pyattr_get_world_point(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_CollisionContactPoint *self = static_cast(self_v); + return PyObjectFrom(self->m_collData->GetWorldPoint(self->m_index, self->m_firstObject)); +} + +PyObject *KX_CollisionContactPoint::pyattr_get_normal(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_CollisionContactPoint *self = static_cast(self_v); + return PyObjectFrom(self->m_collData->GetNormal(self->m_index, self->m_firstObject)); +} + +PyObject *KX_CollisionContactPoint::pyattr_get_combined_friction(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_CollisionContactPoint *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_collData->GetCombinedFriction(self->m_index, self->m_firstObject)); +} + +PyObject *KX_CollisionContactPoint::pyattr_get_combined_rolling_friction(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_CollisionContactPoint *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_collData->GetCombinedRollingFriction(self->m_index, self->m_firstObject)); +} + +PyObject *KX_CollisionContactPoint::pyattr_get_combined_restitution(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_CollisionContactPoint *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_collData->GetCombinedRestitution(self->m_index, self->m_firstObject)); +} + +PyObject *KX_CollisionContactPoint::pyattr_get_applied_impulse(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_CollisionContactPoint *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_collData->GetAppliedImpulse(self->m_index, self->m_firstObject)); +} + +static unsigned int kx_collision_contact_point_list_get_size_cb(EXP_PyObjectPlus *self_v) +{ + return ((KX_CollisionContactPointList *)self_v)->GetNumCollisionContactPoint(); +} + +static PyObject *kx_collision_contact_point_list_get_item_cb(EXP_PyObjectPlus *self_v, unsigned int index) +{ + return ((KX_CollisionContactPointList *)self_v)->GetCollisionContactPoint(index)->NewProxy(true); +} + +#endif // WITH_PYTHON + +KX_CollisionContactPointList::KX_CollisionContactPointList(const PHY_ICollData *collData, bool firstObject) + : +#ifdef WITH_PYTHON + EXP_BaseListWrapper(this, kx_collision_contact_point_list_get_size_cb, + kx_collision_contact_point_list_get_item_cb, nullptr, nullptr, EXP_BaseListWrapper::FLAG_NO_WEAK_REF), +#endif // WITH_PYTHON + m_collData(collData), + m_firstObject(firstObject) +{ +} + +KX_CollisionContactPointList::~KX_CollisionContactPointList() +{ +} + +std::string KX_CollisionContactPointList::GetName() +{ + return "KX_CollisionContactPointList"; +} + +KX_CollisionContactPoint *KX_CollisionContactPointList::GetCollisionContactPoint(unsigned int index) +{ + // All contact point infos. + return (new KX_CollisionContactPoint(m_collData, index, m_firstObject)); +} + +unsigned int KX_CollisionContactPointList::GetNumCollisionContactPoint() +{ + return m_collData->GetNumContacts(); +} + +const PHY_ICollData *KX_CollisionContactPointList::GetCollData() +{ + return m_collData; +} + +bool KX_CollisionContactPointList::GetFirstObject() +{ + return m_firstObject; +} diff --git a/source/gameengine/Ketsji/KX_CollisionContactPoints.h b/source/gameengine/Ketsji/KX_CollisionContactPoints.h new file mode 100644 index 000000000000..2ae7295101c2 --- /dev/null +++ b/source/gameengine/Ketsji/KX_CollisionContactPoints.h @@ -0,0 +1,88 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file KX_CollisionContactPoints.h + * \ingroup ketsji + */ + +#ifndef __KX_COLLISION_CONTACT_POINTS_H__ +#define __KX_COLLISION_CONTACT_POINTS_H__ + +#include "EXP_Value.h" +#include "EXP_ListWrapper.h" + +class PHY_ICollData; + +class KX_CollisionContactPoint : public EXP_Value +{ + Py_Header +protected: + /// All infos about contact position, normal, friction ect… + const PHY_ICollData *m_collData; + const unsigned int m_index; + const bool m_firstObject; + +public: + KX_CollisionContactPoint(const PHY_ICollData *collData, unsigned int index, bool firstObject); + virtual ~KX_CollisionContactPoint(); + + // stuff for cvalue related things + std::string GetName(); + +#ifdef WITH_PYTHON + + static PyObject *pyattr_get_local_point_a(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_local_point_b(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_world_point(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_normal(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_combined_friction(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_combined_rolling_friction(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_combined_restitution(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_applied_impulse(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + +#endif // WITH_PYTHON +}; + +class KX_CollisionContactPointList +#ifdef WITH_PYTHON + : public EXP_BaseListWrapper +#endif // WITH_PYTHON +{ +private: + /// The list of contact points for a pair of rigid bodies. + const PHY_ICollData *m_collData; + /// The object is the first in the pair or the second ? + bool m_firstObject; + +public: + KX_CollisionContactPointList(const PHY_ICollData *collData, bool firstObject); + virtual ~KX_CollisionContactPointList(); + + virtual std::string GetName(); + + KX_CollisionContactPoint *GetCollisionContactPoint(unsigned int index); + unsigned int GetNumCollisionContactPoint(); + const PHY_ICollData *GetCollData(); + bool GetFirstObject(); +}; + +#endif // __KX_COLLISION_CONTACT_POINTS_H__ diff --git a/source/gameengine/Ketsji/KX_CollisionEventManager.cpp b/source/gameengine/Ketsji/KX_CollisionEventManager.cpp new file mode 100644 index 000000000000..d4ef2aa0327b --- /dev/null +++ b/source/gameengine/Ketsji/KX_CollisionEventManager.cpp @@ -0,0 +1,254 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Ketsji/KX_CollisionEventManager.cpp + * \ingroup ketsji + */ + +#include "KX_CollisionEventManager.h" +#include "SCA_ISensor.h" +#include "KX_CollisionSensor.h" +#include "KX_GameObject.h" +#include "KX_CollisionContactPoints.h" +#include "PHY_IPhysicsEnvironment.h" +#include "PHY_IPhysicsController.h" + +KX_CollisionEventManager::KX_CollisionEventManager(SCA_LogicManager *logicmgr, PHY_IPhysicsEnvironment *physEnv) + :SCA_EventManager(logicmgr, TOUCH_EVENTMGR), + m_physEnv(physEnv) +{ + m_physEnv->AddCollisionCallback(PHY_OBJECT_RESPONSE, KX_CollisionEventManager::newCollisionResponse, this); + m_physEnv->AddCollisionCallback(PHY_SENSOR_RESPONSE, KX_CollisionEventManager::newCollisionResponse, this); + m_physEnv->AddCollisionCallback(PHY_BROADPH_RESPONSE, KX_CollisionEventManager::newBroadphaseResponse, this); +} + +KX_CollisionEventManager::~KX_CollisionEventManager() +{ + RemoveNewCollisions(); +} + +void KX_CollisionEventManager::RemoveNewCollisions() +{ + m_newCollisions.clear(); +} + +bool KX_CollisionEventManager::NewHandleCollision(PHY_IPhysicsController *ctrl1, PHY_IPhysicsController *ctrl2, + const PHY_ICollData *coll_data, bool first) +{ + m_newCollisions.insert(NewCollision(ctrl1, ctrl2, coll_data, first)); + + return false; +} + +bool KX_CollisionEventManager::newCollisionResponse(void *client_data, PHY_IPhysicsController *ctrl1, + PHY_IPhysicsController *ctrl2, const PHY_ICollData *coll_data, bool first) +{ + KX_CollisionEventManager *collisionmgr = (KX_CollisionEventManager *)client_data; + collisionmgr->NewHandleCollision(ctrl1, ctrl2, coll_data, first); + return false; +} + +bool KX_CollisionEventManager::newBroadphaseResponse(void *client_data, PHY_IPhysicsController *ctrl1, + PHY_IPhysicsController *ctrl2, const PHY_ICollData *coll_data, bool first) +{ + KX_ClientObjectInfo *info1 = (ctrl1) ? static_cast(ctrl1->GetNewClientInfo()) : nullptr; + KX_ClientObjectInfo *info2 = (ctrl2) ? static_cast(ctrl2->GetNewClientInfo()) : nullptr; + + // This call back should only be called for controllers of Near and Radar sensor. + if (!info1) { + return true; + } + bool has_py_callbacks = false; + +#ifdef WITH_PYTHON + // Get KX_GameObjects for callbacks. + KX_GameObject *gobj1 = info1->m_gameobject; + KX_GameObject *gobj2 = (info2) ? info2->m_gameobject : nullptr; + + // Consider callbacks for broadphase inclusion if it's a sensor object type. + if (gobj1 && gobj2) { + has_py_callbacks = gobj1->m_collisionCallbacks || gobj2->m_collisionCallbacks; + } +#endif + + switch (info1->m_type) { + case KX_ClientObjectInfo::SENSOR: + { + if (info1->m_sensors.size() == 1) { + // Only one sensor for this type of object. + KX_CollisionSensor *collisionsensor = static_cast(*info1->m_sensors.begin()); + return collisionsensor->BroadPhaseFilterCollision(ctrl1, ctrl2); + } + break; + } + case KX_ClientObjectInfo::OBSENSOR: + case KX_ClientObjectInfo::OBACTORSENSOR: + { + /* This object may have multiple collision sensors, + * check is any of them is interested in this object. */ + for (SCA_ISensor *sensor : info1->m_sensors) { + if (sensor->GetSensorType() == SCA_ISensor::ST_TOUCH) { + KX_CollisionSensor *collisionsensor = static_cast(sensor); + if (collisionsensor->BroadPhaseSensorFilterCollision(ctrl1, ctrl2)) { + return true; + } + } + } + + return has_py_callbacks; + } + case KX_ClientObjectInfo::STATIC: + case KX_ClientObjectInfo::ACTOR: + case KX_ClientObjectInfo::RESERVED1: + { + // Do nothing. + break; + } + } + return true; +} + +bool KX_CollisionEventManager::RegisterSensor(SCA_ISensor *sensor) +{ + if (SCA_EventManager::RegisterSensor(sensor)) { + KX_CollisionSensor *collisionsensor = static_cast(sensor); + // The sensor was effectively inserted, register it. + collisionsensor->RegisterSumo(this); + return true; + } + + return false; +} + +bool KX_CollisionEventManager::RemoveSensor(SCA_ISensor *sensor) +{ + if (SCA_EventManager::RemoveSensor(sensor)) { + KX_CollisionSensor *collisionsensor = static_cast(sensor); + // The sensor was effectively removed, unregister it. + collisionsensor->UnregisterSumo(this); + return true; + } + + return false; +} + +void KX_CollisionEventManager::EndFrame() +{ + for (SCA_ISensor *sensor : m_sensors) { + static_cast(sensor)->EndFrame(); + } +} + +void KX_CollisionEventManager::NextFrame() +{ + for (SCA_ISensor *sensor : m_sensors) { + static_cast(sensor)->SynchronizeTransform(); + } + + for (const NewCollision& collision : m_newCollisions) { + // Controllers + PHY_IPhysicsController *ctrl1 = collision.first; + PHY_IPhysicsController *ctrl2 = collision.second; + // Sensor iterator + std::list::iterator sit; + + // First client info + KX_ClientObjectInfo *client_info = static_cast(ctrl1->GetNewClientInfo()); + // First gameobject + KX_GameObject *kxObj1 = KX_GameObject::GetClientObject(client_info); + // Invoke sensor response for each object + if (client_info) { + for (sit = client_info->m_sensors.begin(); sit != client_info->m_sensors.end(); ++sit) { + static_cast(*sit)->NewHandleCollision(ctrl1, ctrl2, nullptr); + } + } + + // Second client info + client_info = static_cast(ctrl2->GetNewClientInfo()); + // Second gameobject + KX_GameObject *kxObj2 = KX_GameObject::GetClientObject(client_info); + if (client_info) { + for (sit = client_info->m_sensors.begin(); sit != client_info->m_sensors.end(); ++sit) { + static_cast(*sit)->NewHandleCollision(ctrl2, ctrl1, nullptr); + } + } + // Run python callbacks + const PHY_ICollData *colldata = collision.colldata; + KX_CollisionContactPointList contactPointList0 = KX_CollisionContactPointList(colldata, collision.isFirst); + KX_CollisionContactPointList contactPointList1 = KX_CollisionContactPointList(colldata, !collision.isFirst); + kxObj1->RunCollisionCallbacks(kxObj2, contactPointList0); + kxObj2->RunCollisionCallbacks(kxObj1, contactPointList1); + } + + for (SCA_ISensor *sensor : m_sensors) { + sensor->Activate(m_logicmgr); + } + + RemoveNewCollisions(); +} + +SCA_LogicManager *KX_CollisionEventManager::GetLogicManager() +{ + return m_logicmgr; +} + +PHY_IPhysicsEnvironment *KX_CollisionEventManager::GetPhysicsEnvironment() +{ + return m_physEnv; +} + +KX_CollisionEventManager::NewCollision::NewCollision(PHY_IPhysicsController *_first, PHY_IPhysicsController *_second, + const PHY_ICollData *_colldata, bool _isfirst) + :first(_first), + second(_second), + colldata(_colldata), + isFirst(_isfirst) +{ +} + +KX_CollisionEventManager::NewCollision::NewCollision(const NewCollision &to_copy) + :first(to_copy.first), + second(to_copy.second), + colldata(to_copy.colldata), + isFirst(to_copy.isFirst) +{ +} + +bool KX_CollisionEventManager::NewCollision::operator<(const NewCollision &other) const +{ + // See strict weak ordering: https://support.microsoft.com/en-us/kb/949171. + if (first == other.first) { + if (second == other.second) { + if (colldata == other.colldata) { + return isFirst < other.isFirst; + } + return colldata < other.colldata; + } + return second < other.second; + } + return first < other.first; +} diff --git a/source/gameengine/Ketsji/KX_CollisionEventManager.h b/source/gameengine/Ketsji/KX_CollisionEventManager.h new file mode 100644 index 000000000000..19156392ea63 --- /dev/null +++ b/source/gameengine/Ketsji/KX_CollisionEventManager.h @@ -0,0 +1,95 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file KX_CollisionEventManager.h + * \ingroup ketsji + */ + +#ifndef __KX_TOUCHEVENTMANAGER_H__ +#define __KX_TOUCHEVENTMANAGER_H__ + + +#include "SCA_EventManager.h" +#include "KX_CollisionSensor.h" +#include "KX_GameObject.h" + +#include +#include + +class SCA_ISensor; +class PHY_IPhysicsEnvironment; + +class KX_CollisionEventManager : public SCA_EventManager +{ + /** + * Contains two colliding objects and the first contact point. + */ + class NewCollision + { + public: + PHY_IPhysicsController *first; + PHY_IPhysicsController *second; + const PHY_ICollData *colldata; + bool isFirst; + + /** + * Creates a copy of the given PHY_ICollData; freeing that copy should be done by the owner of + * the NewCollision object. + * + * This allows us to efficiently store NewCollision objects in a std::set without creating more + * copies of colldata, as the NewCollision copy constructor reuses the pointer and doesn't clone + * it again. */ + NewCollision(PHY_IPhysicsController *first, PHY_IPhysicsController *second, const PHY_ICollData *colldata, bool isFirst); + NewCollision(const NewCollision &to_copy); + bool operator<(const NewCollision &other) const; + }; + + PHY_IPhysicsEnvironment *m_physEnv; + std::set m_newCollisions; + + static bool newCollisionResponse(void *client_data, PHY_IPhysicsController *ctrl1, PHY_IPhysicsController *ctrl2, + const PHY_ICollData *coll_data, bool first); + static bool newBroadphaseResponse(void *client_data, PHY_IPhysicsController *ctrl1, PHY_IPhysicsController *ctrl2, + const PHY_ICollData *coll_data, bool first); + + bool NewHandleCollision(PHY_IPhysicsController *ctrl1, PHY_IPhysicsController *ctrl2, const PHY_ICollData *coll_data, bool first); + void RemoveNewCollisions(); + +public: + KX_CollisionEventManager(SCA_LogicManager *logicmgr, PHY_IPhysicsEnvironment *physEnv); + virtual ~KX_CollisionEventManager(); + + virtual void NextFrame(); + virtual void EndFrame(); + virtual bool RegisterSensor(SCA_ISensor *sensor); + virtual bool RemoveSensor(SCA_ISensor *sensor); + + SCA_LogicManager *GetLogicManager(); + PHY_IPhysicsEnvironment *GetPhysicsEnvironment(); +}; + +#endif // __KX_TOUCHEVENTMANAGER_H__ diff --git a/source/gameengine/Ketsji/KX_CollisionSensor.cpp b/source/gameengine/Ketsji/KX_CollisionSensor.cpp new file mode 100644 index 000000000000..7c87c178a4e9 --- /dev/null +++ b/source/gameengine/Ketsji/KX_CollisionSensor.cpp @@ -0,0 +1,339 @@ +/* + * Senses touch and collision events + * + * + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Ketsji/KX_CollisionSensor.cpp + * \ingroup ketsji + */ + + +#include "KX_CollisionSensor.h" +#include "SCA_EventManager.h" +#include "SCA_LogicManager.h" +#include "KX_GameObject.h" +#include "KX_CollisionEventManager.h" +#include "KX_Mesh.h" + +#include "PHY_IPhysicsController.h" + +#include +#include "BLI_utildefines.h" +#include "PHY_IPhysicsEnvironment.h" + +/* ------------------------------------------------------------------------- */ +/* Native functions */ +/* ------------------------------------------------------------------------- */ + +void KX_CollisionSensor::SynchronizeTransform() +{ + // the touch sensor does not require any synchronization: it uses + // the same physical object which is already synchronized by Blender +} + +void KX_CollisionSensor::EndFrame() +{ + m_colliders->ReleaseAndRemoveAll(); + m_hitObject = nullptr; + m_bTriggered = false; + m_bColliderHash = 0; +} + +void KX_CollisionSensor::UnregisterToManager() +{ + // before unregistering the sensor, make sure we release all references + EndFrame(); + SCA_ISensor::UnregisterToManager(); +} + +bool KX_CollisionSensor::Evaluate() +{ + bool result = false; + bool reset = m_reset && m_level; + m_reset = false; + if (m_bTriggered != m_bLastTriggered) { + m_bLastTriggered = m_bTriggered; + if (!m_bTriggered) { + m_hitObject = nullptr; + } + result = true; + } + if (reset) { + // force an event + result = true; + } + + if (m_bCollisionPulse) { // pulse on changes to the colliders + int count = m_colliders->GetCount(); + + if (m_bLastCount != count || m_bColliderHash != m_bLastColliderHash) { + m_bLastCount = count; + m_bLastColliderHash = m_bColliderHash; + result = true; + } + } + return result; +} + +KX_CollisionSensor::KX_CollisionSensor(SCA_EventManager *eventmgr, KX_GameObject *gameobj, bool bFindMaterial, bool bCollisionPulse, const std::string& touchedpropname) + :SCA_ISensor(gameobj, eventmgr), + m_touchedpropname(touchedpropname), + m_bFindMaterial(bFindMaterial), + m_bCollisionPulse(bCollisionPulse), + m_hitMaterial("") +{ + m_colliders = new EXP_ListValue(); + + KX_ClientObjectInfo& clientInfo = gameobj->GetClientInfo(); + clientInfo.m_sensors.push_back(this); + + m_physCtrl = gameobj->GetPhysicsController(); + BLI_assert(!gameobj->GetPhysicsController() || m_physCtrl); + Init(); +} + +void KX_CollisionSensor::Init() +{ + m_bCollision = false; + m_bTriggered = false; + m_bLastTriggered = (m_invert) ? true : false; + m_bLastCount = 0; + m_bColliderHash = m_bLastColliderHash = 0; + m_hitObject = nullptr; + m_reset = true; +} + +KX_CollisionSensor::~KX_CollisionSensor() +{ + m_colliders->Release(); +} + +EXP_Value *KX_CollisionSensor::GetReplica() +{ + KX_CollisionSensor *replica = new KX_CollisionSensor(*this); + replica->ProcessReplica(); + return replica; +} + +void KX_CollisionSensor::ProcessReplica() +{ + SCA_ISensor::ProcessReplica(); + m_colliders = new EXP_ListValue(); + Init(); +} + +void KX_CollisionSensor::ReParent(SCA_IObject *parent) +{ + KX_GameObject *gameobj = static_cast(parent); + PHY_IPhysicsController *sphy = ((KX_GameObject *)parent)->GetPhysicsController(); + if (sphy) { + m_physCtrl = sphy; + } + + KX_ClientObjectInfo& clientInfo = gameobj->GetClientInfo(); + + clientInfo.m_sensors.push_back(this); + SCA_ISensor::ReParent(parent); +} + +void KX_CollisionSensor::RegisterSumo(KX_CollisionEventManager *collisionman) +{ + if (m_physCtrl) { + if (collisionman->GetPhysicsEnvironment()->RequestCollisionCallback(m_physCtrl)) { + KX_ClientObjectInfo *client_info = static_cast(m_physCtrl->GetNewClientInfo()); + if (client_info->isSensor()) { + collisionman->GetPhysicsEnvironment()->AddSensor(m_physCtrl); + } + } + } +} +void KX_CollisionSensor::UnregisterSumo(KX_CollisionEventManager *collisionman) +{ + if (m_physCtrl) { + if (collisionman->GetPhysicsEnvironment()->RemoveCollisionCallback(m_physCtrl)) { + // no more sensor on the controller, can remove it if it is a sensor object + KX_ClientObjectInfo *client_info = static_cast(m_physCtrl->GetNewClientInfo()); + if (client_info->isSensor()) { + collisionman->GetPhysicsEnvironment()->RemoveSensor(m_physCtrl); + } + } + } +} + +// this function is called only for sensor objects +// return true if the controller can collide with the object +bool KX_CollisionSensor::BroadPhaseSensorFilterCollision(PHY_IPhysicsController *ctrl1, PHY_IPhysicsController *ctrl2) +{ + BLI_assert(ctrl1 == m_physCtrl && ctrl2); + + KX_GameObject *myobj = (KX_GameObject *)GetParent(); + KX_GameObject *myparent = myobj->GetParent(); + KX_ClientObjectInfo *client_info = static_cast(ctrl2->GetNewClientInfo()); + KX_ClientObjectInfo *my_client_info = static_cast(m_physCtrl->GetNewClientInfo()); + KX_GameObject *otherobj = (client_info ? client_info->m_gameobject : nullptr); + + // we can only check on persistent characteristic: m_link and m_suspended are not + // good candidate because they are transient. That must be handled at another level + if (!otherobj || + otherobj == myparent || // don't interact with our parent + (my_client_info->m_type == KX_ClientObjectInfo::OBACTORSENSOR && + client_info->m_type != KX_ClientObjectInfo::ACTOR)) { // only with actor objects + return false; + } + + bool found = m_touchedpropname.empty(); + if (!found) { + if (m_bFindMaterial) { + for (KX_Mesh *meshObj : otherobj->GetMeshList()) { + found = (meshObj->FindMaterialName(m_touchedpropname) != nullptr); + if (found) { + break; + } + } + } + else { + found = (otherobj->GetProperty(m_touchedpropname) != nullptr); + } + } + return found; +} + +bool KX_CollisionSensor::NewHandleCollision(PHY_IPhysicsController *ctrl1, PHY_IPhysicsController *ctrl2, const PHY_ICollData *colldata) +{ + KX_GameObject *parent = (KX_GameObject *)GetParent(); + + // need the mapping from PHY_IPhysicsController to gameobjects now + + KX_ClientObjectInfo *client_info = static_cast (ctrl1 == m_physCtrl ? + ctrl2->GetNewClientInfo() : ctrl1->GetNewClientInfo()); + + KX_GameObject *gameobj = (client_info ? + client_info->m_gameobject : + nullptr); + + // add the same check as in SCA_ISensor::Activate(), + // we don't want to record collision when the sensor is not active. + if (m_links && !m_suspended && + gameobj && (gameobj != parent) && client_info->isActor()) { + + bool found = m_touchedpropname.empty(); + bool hitMaterial = false; + if (!found) { + if (m_bFindMaterial) { + for (KX_Mesh *meshObj : gameobj->GetMeshList()) { + found = (meshObj->FindMaterialName(m_touchedpropname) != nullptr); + if (found) { + hitMaterial = true; + break; + } + } + } + else { + found = (gameobj->GetProperty(m_touchedpropname) != nullptr); + } + } + if (found) { + if (!m_colliders->SearchValue(gameobj)) { + m_colliders->Add(CM_AddRef(gameobj)); + + if (m_bCollisionPulse) { + m_bColliderHash += (uint_ptr)(static_cast(&gameobj)); + } + } + m_bTriggered = true; + m_hitObject = gameobj; + m_hitMaterial = hitMaterial; + } + + } + return false; +} + +#ifdef WITH_PYTHON + +/* ------------------------------------------------------------------------- */ +/* Python functions */ +/* ------------------------------------------------------------------------- */ +/* Integration hooks ------------------------------------------------------- */ +PyTypeObject KX_CollisionSensor::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_CollisionSensor", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &SCA_ISensor::Type, + 0, 0, 0, 0, 0, 0, + py_base_new +}; + +PyMethodDef KX_CollisionSensor::Methods[] = { + {nullptr, nullptr} //Sentinel +}; + +PyAttributeDef KX_CollisionSensor::Attributes[] = { + EXP_PYATTRIBUTE_STRING_RW("propName", 0, MAX_PROP_NAME, false, KX_CollisionSensor, m_touchedpropname), + EXP_PYATTRIBUTE_BOOL_RW("useMaterial", KX_CollisionSensor, m_bFindMaterial), + EXP_PYATTRIBUTE_BOOL_RW("usePulseCollision", KX_CollisionSensor, m_bCollisionPulse), + EXP_PYATTRIBUTE_STRING_RO("hitMaterial", KX_CollisionSensor, m_hitMaterial), + EXP_PYATTRIBUTE_RO_FUNCTION("hitObject", KX_CollisionSensor, pyattr_get_object_hit), + EXP_PYATTRIBUTE_RO_FUNCTION("hitObjectList", KX_CollisionSensor, pyattr_get_object_hit_list), + EXP_PYATTRIBUTE_NULL //Sentinel +}; + +/* Python API */ + +PyObject *KX_CollisionSensor::pyattr_get_object_hit(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_CollisionSensor *self = static_cast(self_v); + + if (self->m_hitObject) { + return self->m_hitObject->GetProxy(); + } + else { + Py_RETURN_NONE; + } +} + +PyObject *KX_CollisionSensor::pyattr_get_object_hit_list(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_CollisionSensor *self = static_cast(self_v); + return self->m_colliders->GetProxy(); +} + +#endif diff --git a/source/gameengine/Ketsji/KX_TouchSensor.h b/source/gameengine/Ketsji/KX_CollisionSensor.h similarity index 50% rename from source/gameengine/Ketsji/KX_TouchSensor.h rename to source/gameengine/Ketsji/KX_CollisionSensor.h index 68ac6ffcc6d2..7b85096d43af 100644 --- a/source/gameengine/Ketsji/KX_TouchSensor.h +++ b/source/gameengine/Ketsji/KX_CollisionSensor.h @@ -25,7 +25,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file KX_TouchSensor.h +/** \file KX_CollisionSensor.h * \ingroup ketsji * \brief Senses touch and collision events */ @@ -36,7 +36,7 @@ #include "SCA_ISensor.h" #include "EXP_ListValue.h" -struct PHY_CollData; +class PHY_ICollData; #include "KX_ClientObjectInfo.h" @@ -46,9 +46,9 @@ typedef unsigned __int64 uint_ptr; typedef unsigned long uint_ptr; #endif -class KX_TouchEventManager; +class KX_CollisionEventManager; -class KX_TouchSensor : public SCA_ISensor +class KX_CollisionSensor : public SCA_ISensor { protected: Py_Header @@ -56,71 +56,76 @@ class KX_TouchSensor : public SCA_ISensor /** * The sensor should only look for objects with this property. */ - STR_String m_touchedpropname; - bool m_bFindMaterial; - bool m_bTouchPulse; /* changes in the colliding objects trigger pulses */ + std::string m_touchedpropname; + bool m_bFindMaterial; + bool m_bCollisionPulse; /* changes in the colliding objects trigger pulses */ - class PHY_IPhysicsController* m_physCtrl; + class PHY_IPhysicsController * m_physCtrl; - bool m_bCollision; - bool m_bTriggered; - bool m_bLastTriggered; + bool m_bCollision; + bool m_bTriggered; + bool m_bLastTriggered; - // Use with m_bTouchPulse to detect changes - int m_bLastCount; /* size of m_colliders last tick */ - uint_ptr m_bColliderHash; /* hash collision objects pointers to trigger in case one object collides and another takes its place */ - uint_ptr m_bLastColliderHash; + // Use with m_bCollisionPulse to detect changes + int m_bLastCount; /* size of m_colliders last tick */ + uint_ptr m_bColliderHash; /* hash collision objects pointers to trigger in case one object collides and another takes its place */ + uint_ptr m_bLastColliderHash; - SCA_IObject* m_hitObject; - class CListValue* m_colliders; - STR_String m_hitMaterial; + SCA_IObject *m_hitObject; + EXP_ListValue *m_colliders; + std::string m_hitMaterial; public: - KX_TouchSensor(class SCA_EventManager* eventmgr, - class KX_GameObject* gameobj, - bool bFindMaterial, - bool bTouchPulse, - const STR_String& touchedpropname); - virtual ~KX_TouchSensor(); - - virtual CValue* GetReplica(); + KX_CollisionSensor(class SCA_EventManager *eventmgr, + class KX_GameObject *gameobj, + bool bFindMaterial, + bool bCollisionPulse, + const std::string& touchedpropname); + virtual ~KX_CollisionSensor(); + + virtual EXP_Value *GetReplica(); virtual void ProcessReplica(); virtual void SynchronizeTransform(); virtual bool Evaluate(); virtual void Init(); - virtual void ReParent(SCA_IObject* parent); + virtual void ReParent(SCA_IObject *parent); - virtual void RegisterSumo(KX_TouchEventManager* touchman); - virtual void UnregisterSumo(KX_TouchEventManager* touchman); + virtual void RegisterSumo(KX_CollisionEventManager *collisionman); + virtual void UnregisterSumo(KX_CollisionEventManager *collisionman); virtual void UnregisterToManager(); -#if 0 - virtual DT_Bool HandleCollision(void* obj1,void* obj2, - const DT_CollData * coll_data); -#endif - - virtual bool NewHandleCollision(void*obj1,void*obj2,const PHY_CollData* colldata); + virtual bool NewHandleCollision(PHY_IPhysicsController *ctrl1, PHY_IPhysicsController *ctrl2, const PHY_ICollData *colldata); // Allows to do pre-filtering and save computation time // obj1 = sensor physical controller, obj2 = physical controller of second object // return value = true if collision should be checked on pair of object - virtual bool BroadPhaseFilterCollision(void*obj1,void*obj2) { return true; } - virtual bool BroadPhaseSensorFilterCollision(void*obj1,void*obj2); - virtual sensortype GetSensorType() { return ST_TOUCH; } + virtual bool BroadPhaseFilterCollision(PHY_IPhysicsController *ctrl1, PHY_IPhysicsController *ctrl2) + { + return true; + } + virtual bool BroadPhaseSensorFilterCollision(PHY_IPhysicsController *ctrl1, PHY_IPhysicsController *ctrl2); + virtual sensortype GetSensorType() + { + return ST_TOUCH; + } - virtual bool IsPositiveTrigger() { + virtual bool IsPositiveTrigger() + { bool result = m_bTriggered; - if (m_invert) result = !result; + if (m_invert) { + result = !result; + } return result; } virtual void EndFrame(); - class PHY_IPhysicsController* GetPhysicsController() { return m_physCtrl; } - + class PHY_IPhysicsController *GetPhysicsController() + { + return m_physCtrl; + } - // todo: put some info for collision maybe #ifdef WITH_PYTHON @@ -128,8 +133,8 @@ class KX_TouchSensor : public SCA_ISensor /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - static PyObject* pyattr_get_object_hit(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_object_hit_list(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_object_hit(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_object_hit_list(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); #endif diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp index a1ccd9f8bf81..671b75a255c9 100644 --- a/source/gameengine/Ketsji/KX_ConstraintActuator.cpp +++ b/source/gameengine/Ketsji/KX_ConstraintActuator.cpp @@ -36,36 +36,31 @@ #include "SCA_IActuator.h" #include "KX_ConstraintActuator.h" #include "SCA_IObject.h" -#include "MT_Point3.h" -#include "MT_Matrix3x3.h" #include "KX_GameObject.h" #include "KX_RayCast.h" -#include "KX_PythonInit.h" // KX_GetActiveScene -#include "RAS_MeshObject.h" +#include "KX_Globals.h" // KX_GetActiveScene +#include "KX_Mesh.h" -#include +#include "CM_Message.h" /* ------------------------------------------------------------------------- */ /* Native functions */ /* ------------------------------------------------------------------------- */ KX_ConstraintActuator::KX_ConstraintActuator(SCA_IObject *gameobj, - int posDampTime, - int rotDampTime, - float minBound, - float maxBound, - float refDir[3], - int locrotxyz, - int time, - int option, - char *property) : + int posDampTime, + int rotDampTime, + float minBound, + float maxBound, + const mt::vec3& refDir, + int locrotxyz, + int time, + int option, + char *property) : SCA_IActuator(gameobj, KX_ACT_CONSTRAINT), - m_refDirVector(refDir), + m_refDirection(refDir), m_currentTime(0) { - m_refDirection[0] = refDir[0]; - m_refDirection[1] = refDir[1]; - m_refDirection[2] = refDir[2]; m_posDampTime = posDampTime; m_rotDampTime = rotDampTime; m_locrot = locrotxyz; @@ -73,7 +68,8 @@ KX_ConstraintActuator::KX_ConstraintActuator(SCA_IObject *gameobj, m_activeTime = time; if (property) { m_property = property; - } else { + } + else { m_property = ""; } /* The units of bounds are determined by the type of constraint. To */ @@ -81,33 +77,33 @@ KX_ConstraintActuator::KX_ConstraintActuator(SCA_IObject *gameobj, /* I think converting the bounds to the applicable domain makes more */ /* sense. */ switch (m_locrot) { - case KX_ACT_CONSTRAINT_ORIX: - case KX_ACT_CONSTRAINT_ORIY: - case KX_ACT_CONSTRAINT_ORIZ: + case KX_ACT_CONSTRAINT_ORIX: + case KX_ACT_CONSTRAINT_ORIY: + case KX_ACT_CONSTRAINT_ORIZ: { - MT_Scalar len = m_refDirVector.length(); - if (MT_fuzzyZero(len)) { + float len = m_refDirection.Length(); + if (mt::FuzzyZero(len)) { // missing a valid direction - std::cout << "WARNING: Constraint actuator " << GetName() << ": There is no valid reference direction!" << std::endl; + CM_LogicBrickWarning(this, "there is no valid reference direction!"); m_locrot = KX_ACT_CONSTRAINT_NODEF; - } else { - m_refDirection[0] /= len; - m_refDirection[1] /= len; - m_refDirection[2] /= len; - m_refDirVector /= len; + } + else { + m_refDirection /= len; } m_minimumBound = cosf(minBound); m_maximumBound = cosf(maxBound); m_minimumSine = sinf(minBound); m_maximumSine = sinf(maxBound); + break; + } + default: + { + m_minimumBound = minBound; + m_maximumBound = maxBound; + m_minimumSine = 0.f; + m_maximumSine = 0.f; + break; } - break; - default: - m_minimumBound = minBound; - m_maximumBound = maxBound; - m_minimumSine = 0.f; - m_maximumSine = 0.f; - break; } } /* End of constructor */ @@ -124,24 +120,20 @@ bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo *client, KX_RayCast *resu bool bFound = false; - if (m_property.IsEmpty()) - { + if (m_property.empty()) { bFound = true; } - else - { + else { if (m_option & KX_ACT_CONSTRAINT_MATERIAL) { - for (unsigned int i = 0; i < m_hitObject->GetMeshCount(); ++i) { - RAS_MeshObject *meshObj = m_hitObject->GetMesh(i); - for (unsigned int j = 0; j < meshObj->NumMaterials(); ++j) { - bFound = strcmp(m_property.ReadPtr(), meshObj->GetMaterialName(j).ReadPtr() + 2) == 0; - if (bFound) - break; + for (KX_Mesh *meshObj : m_hitObject->GetMeshList()) { + bFound = (meshObj->FindMaterialName(m_property) != nullptr); + if (bFound) { + break; } } } else { - bFound = m_hitObject->GetProperty(m_property) != NULL; + bFound = m_hitObject->GetProperty(m_property) != nullptr; } } // update the hit status @@ -155,18 +147,17 @@ bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo *client, KX_RayCast *resu */ bool KX_ConstraintActuator::NeedRayCast(KX_ClientObjectInfo *client, void *UNUSED(data)) { - if (client->m_type > KX_ClientObjectInfo::ACTOR) - { + if (client->m_type > KX_ClientObjectInfo::ACTOR) { // Unknown type of object, skip it. // Should not occur as the sensor objects are filtered in RayTest() - printf("Invalid client type %d found in ray casting\n", client->m_type); + CM_LogicBrickError(this, "invalid client type " << client->m_type << " found in ray casting"); return false; } // no X-Ray function yet return true; } -bool KX_ConstraintActuator::Update(double curtime, bool frame) +bool KX_ConstraintActuator::Update(double curtime) { bool result = false; @@ -179,388 +170,401 @@ bool KX_ConstraintActuator::Update(double curtime, bool frame) /* Having to retrieve location/rotation and setting it afterwards may not */ /* be efficient enough... Something to look at later. */ - KX_GameObject *obj = (KX_GameObject*) GetParent(); - MT_Point3 position = obj->NodeGetWorldPosition(); - MT_Point3 newposition; - MT_Vector3 normal, direction, refDirection; - MT_Matrix3x3 rotation = obj->NodeGetWorldOrientation(); - MT_Scalar filter, newdistance, cosangle; + KX_GameObject *obj = (KX_GameObject *)GetParent(); + mt::vec3 position = obj->NodeGetWorldPosition(); + mt::vec3 newposition; + mt::vec3 normal, direction, refDirection; + mt::mat3 rotation = obj->NodeGetWorldOrientation(); + float filter, newdistance, cosangle; int axis, sign; if (m_posDampTime) { - filter = m_posDampTime/(1.0f+m_posDampTime); - } else { + filter = m_posDampTime / (1.0f + m_posDampTime); + } + else { filter = 0.0f; } switch (m_locrot) { - case KX_ACT_CONSTRAINT_ORIX: - case KX_ACT_CONSTRAINT_ORIY: - case KX_ACT_CONSTRAINT_ORIZ: - switch (m_locrot) { case KX_ACT_CONSTRAINT_ORIX: - direction[0] = rotation[0][0]; - direction[1] = rotation[1][0]; - direction[2] = rotation[2][0]; - axis = 0; - break; case KX_ACT_CONSTRAINT_ORIY: - direction[0] = rotation[0][1]; - direction[1] = rotation[1][1]; - direction[2] = rotation[2][1]; - axis = 1; - break; - default: - direction[0] = rotation[0][2]; - direction[1] = rotation[1][2]; - direction[2] = rotation[2][2]; - axis = 2; - break; - } - if ((m_maximumBound < (1.0f-FLT_EPSILON)) || (m_minimumBound < (1.0f-FLT_EPSILON))) { - // reference direction needs to be evaluated - // 1. get the cosine between current direction and target - cosangle = direction.dot(m_refDirVector); - if (cosangle >= (m_maximumBound-FLT_EPSILON) && cosangle <= (m_minimumBound+FLT_EPSILON)) { - // no change to do - result = true; - goto CHECK_TIME; + case KX_ACT_CONSTRAINT_ORIZ: + { + switch (m_locrot) { + case KX_ACT_CONSTRAINT_ORIX: + { + direction = rotation.GetColumn(0); + axis = 0; + break; + } + case KX_ACT_CONSTRAINT_ORIY: + { + direction = rotation.GetColumn(1); + axis = 1; + break; + } + default: + { + direction = rotation.GetColumn(2); + axis = 2; + break; + } } - // 2. define a new reference direction - // compute local axis with reference direction as X and - // Y in direction X refDirection plane - MT_Vector3 zaxis = m_refDirVector.cross(direction); - if (MT_fuzzyZero2(zaxis.length2())) { - // direction and refDirection are identical, - // choose any other direction to define plane - if (direction[0] < 0.9999f) - zaxis = m_refDirVector.cross(MT_Vector3(1.0f,0.0f,0.0f)); - else - zaxis = m_refDirVector.cross(MT_Vector3(0.0f,1.0f,0.0f)); + if ((m_maximumBound < (1.0f - FLT_EPSILON)) || (m_minimumBound < (1.0f - FLT_EPSILON))) { + // reference direction needs to be evaluated + // 1. get the cosine between current direction and target + cosangle = mt::dot(direction, m_refDirection); + if (cosangle >= (m_maximumBound - FLT_EPSILON) && cosangle <= (m_minimumBound + FLT_EPSILON)) { + // no change to do + result = true; + goto CHECK_TIME; + } + // 2. define a new reference direction + // compute local axis with reference direction as X and + // Y in direction X refDirection plane + mt::vec3 zaxis = mt::cross(m_refDirection, direction); + if (mt::FuzzyZero(zaxis.LengthSquared())) { + // direction and refDirection are identical, + // choose any other direction to define plane + if (direction[0] < 0.9999f) { + zaxis = mt::cross(m_refDirection, mt::axisX3); + } + else { + zaxis = mt::cross(m_refDirection, mt::axisY3); + } + } + mt::vec3 yaxis = mt::cross(zaxis, m_refDirection); + yaxis.Normalize(); + if (cosangle > m_minimumBound) { + // angle is too close to reference direction, + // choose a new reference that is exactly at minimum angle + refDirection = m_minimumBound * m_refDirection + m_minimumSine * yaxis; + } + else { + // angle is too large, choose new reference direction at maximum angle + refDirection = m_maximumBound * m_refDirection + m_maximumSine * yaxis; + } } - MT_Vector3 yaxis = zaxis.cross(m_refDirVector); - yaxis.normalize(); - if (cosangle > m_minimumBound) { - // angle is too close to reference direction, - // choose a new reference that is exactly at minimum angle - refDirection = m_minimumBound * m_refDirVector + m_minimumSine * yaxis; - } else { - // angle is too large, choose new reference direction at maximum angle - refDirection = m_maximumBound * m_refDirVector + m_maximumSine * yaxis; + else { + refDirection = m_refDirection; } - } else { - refDirection = m_refDirVector; + // apply damping on the direction + direction = filter * direction + (1.0f - filter) * refDirection; + obj->AlignAxisToVect(direction, axis); + result = true; + goto CHECK_TIME; } - // apply damping on the direction - direction = filter*direction + (1.0f-filter)*refDirection; - obj->AlignAxisToVect(direction, axis); - result = true; - goto CHECK_TIME; - case KX_ACT_CONSTRAINT_DIRPX: - case KX_ACT_CONSTRAINT_DIRPY: - case KX_ACT_CONSTRAINT_DIRPZ: - case KX_ACT_CONSTRAINT_DIRNX: - case KX_ACT_CONSTRAINT_DIRNY: - case KX_ACT_CONSTRAINT_DIRNZ: - switch (m_locrot) { case KX_ACT_CONSTRAINT_DIRPX: - normal[0] = rotation[0][0]; - normal[1] = rotation[1][0]; - normal[2] = rotation[2][0]; - axis = 0; // axis according to KX_GameObject::AlignAxisToVect() - sign = 0; // X axis will be parrallel to direction of ray - break; case KX_ACT_CONSTRAINT_DIRPY: - normal[0] = rotation[0][1]; - normal[1] = rotation[1][1]; - normal[2] = rotation[2][1]; - axis = 1; - sign = 0; - break; case KX_ACT_CONSTRAINT_DIRPZ: - normal[0] = rotation[0][2]; - normal[1] = rotation[1][2]; - normal[2] = rotation[2][2]; - axis = 2; - sign = 0; - break; case KX_ACT_CONSTRAINT_DIRNX: - normal[0] = -rotation[0][0]; - normal[1] = -rotation[1][0]; - normal[2] = -rotation[2][0]; - axis = 0; - sign = 1; - break; case KX_ACT_CONSTRAINT_DIRNY: - normal[0] = -rotation[0][1]; - normal[1] = -rotation[1][1]; - normal[2] = -rotation[2][1]; - axis = 1; - sign = 1; - break; case KX_ACT_CONSTRAINT_DIRNZ: - normal[0] = -rotation[0][2]; - normal[1] = -rotation[1][2]; - normal[2] = -rotation[2][2]; - axis = 2; - sign = 1; - break; - } - normal.normalize(); - if (m_option & KX_ACT_CONSTRAINT_LOCAL) { - // direction of the ray is along the local axis - direction = normal; - } else { + { switch (m_locrot) { - case KX_ACT_CONSTRAINT_DIRPX: - direction = MT_Vector3(1.0f,0.0f,0.0f); - break; - case KX_ACT_CONSTRAINT_DIRPY: - direction = MT_Vector3(0.0f,1.0f,0.0f); - break; - case KX_ACT_CONSTRAINT_DIRPZ: - direction = MT_Vector3(0.0f,0.0f,1.0f); - break; - case KX_ACT_CONSTRAINT_DIRNX: - direction = MT_Vector3(-1.0f,0.0f,0.0f); - break; - case KX_ACT_CONSTRAINT_DIRNY: - direction = MT_Vector3(0.0f,-1.0f,0.0f); - break; - case KX_ACT_CONSTRAINT_DIRNZ: - direction = MT_Vector3(0.0f,0.0f,-1.0f); - break; + case KX_ACT_CONSTRAINT_DIRPX: + { + normal = rotation.GetColumn(0); + axis = 0; // axis according to KX_GameObject::AlignAxisToVect() + sign = 0; // X axis will be parrallel to direction of ray + break; + } + case KX_ACT_CONSTRAINT_DIRPY: + { + normal = rotation.GetColumn(1); + axis = 1; + sign = 0; + break; + } + case KX_ACT_CONSTRAINT_DIRPZ: + { + normal = rotation.GetColumn(2); + axis = 2; + sign = 0; + break; + } + case KX_ACT_CONSTRAINT_DIRNX: + { + normal = -rotation.GetColumn(0); + axis = 0; + sign = 1; + break; + } + case KX_ACT_CONSTRAINT_DIRNY: + { + normal = -rotation.GetColumn(1); + axis = 1; + sign = 1; + break; + } + case KX_ACT_CONSTRAINT_DIRNZ: + { + normal = -rotation.GetColumn(2); + axis = 2; + sign = 1; + break; + } } - } - { - MT_Point3 topoint = position + (m_maximumBound) * direction; - PHY_IPhysicsEnvironment* pe = KX_GetActiveScene()->GetPhysicsEnvironment(); - PHY_IPhysicsController *spc = obj->GetPhysicsController(); - - if (!pe) { - std::cout << "WARNING: Constraint actuator " << GetName() << ": There is no physics environment!" << std::endl; - goto CHECK_TIME; + normal.Normalize(); + if (m_option & KX_ACT_CONSTRAINT_LOCAL) { + // direction of the ray is along the local axis + direction = normal; } - if (!spc) { - // the object is not physical, we probably want to avoid hitting its own parent - KX_GameObject *parent = obj->GetParent(); - if (parent) { - spc = parent->GetPhysicsController(); + else { + switch (m_locrot) { + case KX_ACT_CONSTRAINT_DIRPX: + { + direction = mt::axisX3; + break; + } + case KX_ACT_CONSTRAINT_DIRPY: + { + direction = mt::axisY3; + break; + } + case KX_ACT_CONSTRAINT_DIRPZ: + { + direction = mt::axisZ3; + break; + } + case KX_ACT_CONSTRAINT_DIRNX: + { + direction = -mt::axisX3; + break; + } + case KX_ACT_CONSTRAINT_DIRNY: + { + direction = -mt::axisY3; + break; + } + case KX_ACT_CONSTRAINT_DIRNZ: + { + direction = -mt::axisZ3; + break; + } } } - KX_RayCast::Callback callback(this,dynamic_cast(spc)); - result = KX_RayCast::RayTest(pe, position, topoint, callback); - if (result) { - MT_Vector3 newnormal = callback.m_hitNormal; - // compute new position & orientation - if ((m_option & (KX_ACT_CONSTRAINT_NORMAL|KX_ACT_CONSTRAINT_DISTANCE)) == 0) { - // if none option is set, the actuator does nothing but detect ray - // (works like a sensor) + { + mt::vec3 topoint = position + (m_maximumBound) * direction; + PHY_IPhysicsEnvironment *pe = KX_GetActiveScene()->GetPhysicsEnvironment(); + PHY_IPhysicsController *spc = obj->GetPhysicsController(); + + if (!pe) { + CM_LogicBrickWarning(this, "there is no physics environment!"); goto CHECK_TIME; } - if (m_option & KX_ACT_CONSTRAINT_NORMAL) { - MT_Scalar rotFilter; - // apply damping on the direction - if (m_rotDampTime) { - rotFilter = m_rotDampTime/(1.0f+m_rotDampTime); - } else { - rotFilter = filter; - } - newnormal = rotFilter*normal - (1.0f-rotFilter)*newnormal; - obj->AlignAxisToVect((sign)?-newnormal:newnormal, axis); - if (m_option & KX_ACT_CONSTRAINT_LOCAL) { - direction = newnormal; - direction.normalize(); + if (!spc) { + // the object is not physical, we probably want to avoid hitting its own parent + KX_GameObject *parent = obj->GetParent(); + if (parent) { + spc = parent->GetPhysicsController(); } } - if (m_option & KX_ACT_CONSTRAINT_DISTANCE) { - if (m_posDampTime) { - newdistance = filter*(position-callback.m_hitPoint).length()+(1.0f-filter)*m_minimumBound; - } else { - newdistance = m_minimumBound; + KX_RayCast::Callback callback(this, dynamic_cast(spc)); + result = KX_RayCast::RayTest(pe, position, topoint, callback); + if (result) { + mt::vec3 newnormal = callback.m_hitNormal; + // compute new position & orientation + if ((m_option & (KX_ACT_CONSTRAINT_NORMAL | KX_ACT_CONSTRAINT_DISTANCE)) == 0) { + // if none option is set, the actuator does nothing but detect ray + // (works like a sensor) + goto CHECK_TIME; + } + if (m_option & KX_ACT_CONSTRAINT_NORMAL) { + float rotFilter; + // apply damping on the direction + if (m_rotDampTime) { + rotFilter = m_rotDampTime / (1.0f + m_rotDampTime); + } + else { + rotFilter = filter; + } + newnormal = rotFilter * normal - (1.0f - rotFilter) * newnormal; + obj->AlignAxisToVect((sign) ? -newnormal : newnormal, axis); + if (m_option & KX_ACT_CONSTRAINT_LOCAL) { + direction = newnormal; + direction.Normalize(); + } } - // logically we should cancel the speed along the ray direction as we set the - // position along that axis - spc = obj->GetPhysicsController(); - if (spc && spc->IsDynamic()) { - MT_Vector3 linV = spc->GetLinearVelocity(); - // cancel the projection along the ray direction - MT_Scalar fallspeed = linV.dot(direction); - if (!MT_fuzzyZero(fallspeed)) - spc->SetLinearVelocity(linV-fallspeed*direction,false); + if (m_option & KX_ACT_CONSTRAINT_DISTANCE) { + if (m_posDampTime) { + newdistance = filter * (position - callback.m_hitPoint).Length() + (1.0f - filter) * m_minimumBound; + } + else { + newdistance = m_minimumBound; + } + // logically we should cancel the speed along the ray direction as we set the + // position along that axis + spc = obj->GetPhysicsController(); + if (spc && spc->IsDynamic()) { + mt::vec3 linV = spc->GetLinearVelocity(); + // cancel the projection along the ray direction + float fallspeed = mt::dot(linV, direction); + if (!mt::FuzzyZero(fallspeed)) { + spc->SetLinearVelocity(linV - fallspeed * direction, false); + } + } } - } else { - newdistance = (position-callback.m_hitPoint).length(); + else { + newdistance = (position - callback.m_hitPoint).Length(); + } + newposition = callback.m_hitPoint - newdistance * direction; + } + else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) { + // no contact but still keep running + result = true; + goto CHECK_TIME; } - newposition = callback.m_hitPoint-newdistance*direction; - } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) { - // no contact but still keep running - result = true; - goto CHECK_TIME; } + break; } - break; - case KX_ACT_CONSTRAINT_FHPX: - case KX_ACT_CONSTRAINT_FHPY: - case KX_ACT_CONSTRAINT_FHPZ: - case KX_ACT_CONSTRAINT_FHNX: - case KX_ACT_CONSTRAINT_FHNY: - case KX_ACT_CONSTRAINT_FHNZ: - switch (m_locrot) { case KX_ACT_CONSTRAINT_FHPX: - normal[0] = -rotation[0][0]; - normal[1] = -rotation[1][0]; - normal[2] = -rotation[2][0]; - direction = MT_Vector3(1.0f,0.0f,0.0f); - break; case KX_ACT_CONSTRAINT_FHPY: - normal[0] = -rotation[0][1]; - normal[1] = -rotation[1][1]; - normal[2] = -rotation[2][1]; - direction = MT_Vector3(0.0f,1.0f,0.0f); - break; case KX_ACT_CONSTRAINT_FHPZ: - normal[0] = -rotation[0][2]; - normal[1] = -rotation[1][2]; - normal[2] = -rotation[2][2]; - direction = MT_Vector3(0.0f,0.0f,1.0f); - break; case KX_ACT_CONSTRAINT_FHNX: - normal[0] = rotation[0][0]; - normal[1] = rotation[1][0]; - normal[2] = rotation[2][0]; - direction = MT_Vector3(-1.0f,0.0f,0.0f); - break; case KX_ACT_CONSTRAINT_FHNY: - normal[0] = rotation[0][1]; - normal[1] = rotation[1][1]; - normal[2] = rotation[2][1]; - direction = MT_Vector3(0.0f,-1.0f,0.0f); - break; case KX_ACT_CONSTRAINT_FHNZ: - normal[0] = rotation[0][2]; - normal[1] = rotation[1][2]; - normal[2] = rotation[2][2]; - direction = MT_Vector3(0.0f,0.0f,-1.0f); - break; - } - normal.normalize(); { - PHY_IPhysicsEnvironment* pe = KX_GetActiveScene()->GetPhysicsEnvironment(); - PHY_IPhysicsController *spc = obj->GetPhysicsController(); - - if (!pe) { - std::cout << "WARNING: Constraint actuator " << GetName() << ": There is no physics environment!" << std::endl; - goto CHECK_TIME; - } - if (!spc || !spc->IsDynamic()) { - // the object is not dynamic, it won't support setting speed - goto CHECK_TIME; - } - m_hitObject = NULL; - // distance of Fh area is stored in m_minimum - MT_Point3 topoint = position + (m_minimumBound+spc->GetRadius()) * direction; - KX_RayCast::Callback callback(this, spc); - result = KX_RayCast::RayTest(pe, position, topoint, callback); - // we expect a hit object - if (!m_hitObject) - result = false; - if (result) - { - MT_Vector3 newnormal = callback.m_hitNormal; - // compute new position & orientation - MT_Scalar distance = (callback.m_hitPoint-position).length()-spc->GetRadius(); - // estimate the velocity of the hit point - MT_Point3 relativeHitPoint; - relativeHitPoint = (callback.m_hitPoint-m_hitObject->NodeGetWorldPosition()); - MT_Vector3 velocityHitPoint = m_hitObject->GetVelocity(relativeHitPoint); - MT_Vector3 relativeVelocity = spc->GetLinearVelocity() - velocityHitPoint; - MT_Scalar relativeVelocityRay = direction.dot(relativeVelocity); - MT_Scalar springExtent = 1.0f - distance/m_minimumBound; - // Fh force is stored in m_maximum - MT_Scalar springForce = springExtent * m_maximumBound; - // damping is stored in m_refDirection [0] = damping, [1] = rot damping - MT_Scalar springDamp = relativeVelocityRay * m_refDirVector[0]; - MT_Vector3 newVelocity = spc->GetLinearVelocity()-(springForce+springDamp)*direction; - if (m_option & KX_ACT_CONSTRAINT_NORMAL) + switch (m_locrot) { + case KX_ACT_CONSTRAINT_FHPX: + { + normal = -rotation.GetColumn(0); + direction = mt::axisX3; + break; + } + case KX_ACT_CONSTRAINT_FHPY: + { + normal = -rotation.GetColumn(1); + direction = mt::axisY3; + break; + } + case KX_ACT_CONSTRAINT_FHPZ: + { + normal = -rotation.GetColumn(2); + direction = mt::axisZ3; + break; + } + case KX_ACT_CONSTRAINT_FHNX: { - newVelocity+=(springForce+springDamp)*(newnormal-newnormal.dot(direction)*direction); + normal = rotation.GetColumn(0); + direction = -mt::axisX3; + break; + } + case KX_ACT_CONSTRAINT_FHNY: + { + normal = rotation.GetColumn(1); + direction = -mt::axisY3; + break; } - spc->SetLinearVelocity(newVelocity, false); - if (m_option & KX_ACT_CONSTRAINT_DOROTFH) + case KX_ACT_CONSTRAINT_FHNZ: { - MT_Vector3 angSpring = (normal.cross(newnormal))*m_maximumBound; - MT_Vector3 angVelocity = spc->GetAngularVelocity(); - // remove component that is parallel to normal - angVelocity -= angVelocity.dot(newnormal)*newnormal; - MT_Vector3 angDamp = angVelocity * ((m_refDirVector[1]>MT_EPSILON)?m_refDirVector[1]:m_refDirVector[0]); - spc->SetAngularVelocity(spc->GetAngularVelocity()+(angSpring-angDamp), false); - } - } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) { - // no contact but still keep running - result = true; + normal = rotation.GetColumn(2); + direction = -mt::axisZ3; + break; + } } - // don't set the position with this constraint - goto CHECK_TIME; + normal.Normalize(); + { + PHY_IPhysicsEnvironment *pe = KX_GetActiveScene()->GetPhysicsEnvironment(); + PHY_IPhysicsController *spc = obj->GetPhysicsController(); + + if (!pe) { + CM_LogicBrickWarning(this, "there is no physics environment!"); + goto CHECK_TIME; + } + if (!spc || !spc->IsDynamic()) { + // the object is not dynamic, it won't support setting speed + goto CHECK_TIME; + } + m_hitObject = nullptr; + // distance of Fh area is stored in m_minimum + mt::vec3 topoint = position + (m_minimumBound + spc->GetRadius()) * direction; + KX_RayCast::Callback callback(this, spc); + result = KX_RayCast::RayTest(pe, position, topoint, callback); + // we expect a hit object + if (!m_hitObject) { + result = false; + } + if (result) { + mt::vec3 newnormal = callback.m_hitNormal; + // compute new position & orientation + float distance = (callback.m_hitPoint - position).Length() - spc->GetRadius(); + // estimate the velocity of the hit point + mt::vec3 relativeHitPoint; + relativeHitPoint = (callback.m_hitPoint - m_hitObject->NodeGetWorldPosition()); + mt::vec3 velocityHitPoint = m_hitObject->GetVelocity(relativeHitPoint); + mt::vec3 relativeVelocity = spc->GetLinearVelocity() - velocityHitPoint; + float relativeVelocityRay = mt::dot(direction, relativeVelocity); + float springExtent = 1.0f - distance / m_minimumBound; + // Fh force is stored in m_maximum + float springForce = springExtent * m_maximumBound; + // damping is stored in m_refDirection [0] = damping, [1] = rot damping + float springDamp = relativeVelocityRay * m_refDirection[0]; + mt::vec3 newVelocity = spc->GetLinearVelocity() - (springForce + springDamp) * direction; + if (m_option & KX_ACT_CONSTRAINT_NORMAL) { + newVelocity += (springForce + springDamp) * (newnormal - mt::dot(newnormal, direction) * direction); + } + spc->SetLinearVelocity(newVelocity, false); + if (m_option & KX_ACT_CONSTRAINT_DOROTFH) { + mt::vec3 angSpring = (mt::cross(normal, newnormal)) * m_maximumBound; + mt::vec3 angVelocity = spc->GetAngularVelocity(); + // remove component that is parallel to normal + angVelocity -= mt::dot(angVelocity, newnormal) * newnormal; + mt::vec3 angDamp = angVelocity * (mt::FuzzyZero(m_refDirection[1]) ? m_refDirection[0] : m_refDirection[1]); + spc->SetAngularVelocity(spc->GetAngularVelocity() + (angSpring - angDamp), false); + } + } + else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) { + // no contact but still keep running + result = true; + } + // don't set the position with this constraint + goto CHECK_TIME; + } + break; } - break; - case KX_ACT_CONSTRAINT_LOCX: - case KX_ACT_CONSTRAINT_LOCY: - case KX_ACT_CONSTRAINT_LOCZ: - newposition = position = obj->GetSGNode()->GetLocalPosition(); - switch (m_locrot) { case KX_ACT_CONSTRAINT_LOCX: - Clamp(newposition[0], m_minimumBound, m_maximumBound); - break; case KX_ACT_CONSTRAINT_LOCY: - Clamp(newposition[1], m_minimumBound, m_maximumBound); - break; case KX_ACT_CONSTRAINT_LOCZ: - Clamp(newposition[2], m_minimumBound, m_maximumBound); - break; - } - result = true; - if (m_posDampTime) { - newposition = filter*position + (1.0f-filter)*newposition; - } - obj->NodeSetLocalPosition(newposition); - goto CHECK_TIME; + newposition = position = obj->GetNode()->GetLocalPosition(); + switch (m_locrot) { + case KX_ACT_CONSTRAINT_LOCX: + { + CLAMP(newposition[0], m_minimumBound, m_maximumBound); + break; + } + case KX_ACT_CONSTRAINT_LOCY: + { + CLAMP(newposition[1], m_minimumBound, m_maximumBound); + break; + } + case KX_ACT_CONSTRAINT_LOCZ: + { + CLAMP(newposition[2], m_minimumBound, m_maximumBound); + break; + } + } + result = true; + if (m_posDampTime) { + newposition = filter * position + (1.0f - filter) * newposition; + } + obj->NodeSetLocalPosition(newposition); + goto CHECK_TIME; } if (result) { // set the new position but take into account parent if any obj->NodeSetWorldPosition(newposition); } - CHECK_TIME: - if (result && m_activeTime > 0 ) { - if (++m_currentTime >= m_activeTime) +CHECK_TIME: + if (result && m_activeTime > 0) { + if (++m_currentTime >= m_activeTime) { result = false; + } } } if (!result) { m_currentTime = 0; } return result; -} /* end of KX_ConstraintActuator::Update(double curtime,double deltatime) */ - -void KX_ConstraintActuator::Clamp(MT_Scalar &var, - float min, - float max) { - if (var < min) { - var = min; - } else if (var > max) { - var = max; - } -} - - -bool KX_ConstraintActuator::IsValidMode(KX_ConstraintActuator::KX_CONSTRAINTTYPE m) -{ - bool res = false; - - if ( (m > KX_ACT_CONSTRAINT_NODEF) && (m < KX_ACT_CONSTRAINT_MAX)) { - res = true; - } - - return res; } #ifdef WITH_PYTHON @@ -571,9 +575,9 @@ bool KX_ConstraintActuator::IsValidMode(KX_ConstraintActuator::KX_CONSTRAINTTYPE /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_ConstraintActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_ConstraintActuator", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -581,46 +585,46 @@ PyTypeObject KX_ConstraintActuator::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IActuator::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_ConstraintActuator::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_ConstraintActuator::Attributes[] = { - KX_PYATTRIBUTE_INT_RW("damp",0,100,true,KX_ConstraintActuator,m_posDampTime), - KX_PYATTRIBUTE_INT_RW("rotDamp",0,100,true,KX_ConstraintActuator,m_rotDampTime), - KX_PYATTRIBUTE_FLOAT_ARRAY_RW_CHECK("direction",-FLT_MAX,FLT_MAX,KX_ConstraintActuator,m_refDirection,3,pyattr_check_direction), - KX_PYATTRIBUTE_INT_RW("option",0,0xFFFF,false,KX_ConstraintActuator,m_option), - KX_PYATTRIBUTE_INT_RW("time",0,1000,true,KX_ConstraintActuator,m_activeTime), - KX_PYATTRIBUTE_STRING_RW("propName",0,MAX_PROP_NAME,true,KX_ConstraintActuator,m_property), - KX_PYATTRIBUTE_FLOAT_RW("min",-FLT_MAX,FLT_MAX,KX_ConstraintActuator,m_minimumBound), - KX_PYATTRIBUTE_FLOAT_RW("distance",-FLT_MAX,FLT_MAX,KX_ConstraintActuator,m_minimumBound), - KX_PYATTRIBUTE_FLOAT_RW("max",-FLT_MAX,FLT_MAX,KX_ConstraintActuator,m_maximumBound), - KX_PYATTRIBUTE_FLOAT_RW("rayLength",0,2000.f,KX_ConstraintActuator,m_maximumBound), - KX_PYATTRIBUTE_INT_RW("limit",KX_ConstraintActuator::KX_ACT_CONSTRAINT_NODEF+1,KX_ConstraintActuator::KX_ACT_CONSTRAINT_MAX-1,false,KX_ConstraintActuator,m_locrot), - { NULL } //Sentinel + EXP_PYATTRIBUTE_INT_RW("damp", 0, 100, true, KX_ConstraintActuator, m_posDampTime), + EXP_PYATTRIBUTE_INT_RW("rotDamp", 0, 100, true, KX_ConstraintActuator, m_rotDampTime), + EXP_PYATTRIBUTE_FLOAT_ARRAY_RW_CHECK("direction", -FLT_MAX, FLT_MAX, KX_ConstraintActuator, m_refDirection, 3, pyattr_check_direction), + EXP_PYATTRIBUTE_INT_RW("option", 0, 0xFFFF, false, KX_ConstraintActuator, m_option), + EXP_PYATTRIBUTE_INT_RW("time", 0, 1000, true, KX_ConstraintActuator, m_activeTime), + EXP_PYATTRIBUTE_STRING_RW("propName", 0, MAX_PROP_NAME, true, KX_ConstraintActuator, m_property), + EXP_PYATTRIBUTE_FLOAT_RW("min", -FLT_MAX, FLT_MAX, KX_ConstraintActuator, m_minimumBound), + EXP_PYATTRIBUTE_FLOAT_RW("distance", -FLT_MAX, FLT_MAX, KX_ConstraintActuator, m_minimumBound), + EXP_PYATTRIBUTE_FLOAT_RW("max", -FLT_MAX, FLT_MAX, KX_ConstraintActuator, m_maximumBound), + EXP_PYATTRIBUTE_FLOAT_RW("rayLength", 0, 2000.f, KX_ConstraintActuator, m_maximumBound), + EXP_PYATTRIBUTE_INT_RW("limit", KX_ConstraintActuator::KX_ACT_CONSTRAINT_NODEF + 1, KX_ConstraintActuator::KX_ACT_CONSTRAINT_MAX - 1, false, KX_ConstraintActuator, m_locrot), + EXP_PYATTRIBUTE_NULL //Sentinel }; -int KX_ConstraintActuator::pyattr_check_direction(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +int KX_ConstraintActuator::pyattr_check_direction(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - KX_ConstraintActuator* act = static_cast(self); - MT_Vector3 dir(act->m_refDirection); - MT_Scalar len = dir.length(); - if (MT_fuzzyZero(len)) { + KX_ConstraintActuator *act = static_cast(self_v); + mt::vec3 dir(act->m_refDirection); + float len = dir.Length(); + if (mt::FuzzyZero(len)) { PyErr_SetString(PyExc_ValueError, "actuator.direction = vec: KX_ConstraintActuator, invalid direction"); return 1; } - act->m_refDirVector = dir/len; + act->m_refDirection = dir / len; return 0; } diff --git a/source/gameengine/Ketsji/KX_ConstraintActuator.h b/source/gameengine/Ketsji/KX_ConstraintActuator.h index 61f106321dea..c0def0e2068a 100644 --- a/source/gameengine/Ketsji/KX_ConstraintActuator.h +++ b/source/gameengine/Ketsji/KX_ConstraintActuator.h @@ -33,8 +33,7 @@ #define __KX_CONSTRAINTACTUATOR_H__ #include "SCA_IActuator.h" -#include "MT_Scalar.h" -#include "MT_Vector3.h" +#include "mathfu.h" #include "KX_ClientObjectInfo.h" #include "BLI_utildefines.h" @@ -42,14 +41,14 @@ class KX_RayCast; class KX_GameObject; -class KX_ConstraintActuator : public SCA_IActuator +class KX_ConstraintActuator : public SCA_IActuator, public mt::SimdClassAllocator { Py_Header protected: // Damp time (int), int m_posDampTime; int m_rotDampTime; - // min (float) + // min (float) float m_minimumBound; // max (float) float m_maximumBound; @@ -58,8 +57,7 @@ class KX_ConstraintActuator : public SCA_IActuator // sinus of maximum angle float m_maximumSine; // reference direction - float m_refDirection[3]; - MT_Vector3 m_refDirVector; // same as m_refDirection + mt::vec3 m_refDirection; // locrotxyz choice (pick one): only one choice allowed at a time! int m_locrot; // active time of actuator @@ -68,18 +66,11 @@ class KX_ConstraintActuator : public SCA_IActuator // option int m_option; // property to check - STR_String m_property; + std::string m_property; // hit object KX_GameObject* m_hitObject; - /** - * Clamp to , . Borders are included (in as far as - * float comparisons are good for equality...). - */ - void Clamp(MT_Scalar &var, float min, float max); - - - public: +public: // m_locrot enum KX_CONSTRAINTTYPE { KX_ACT_CONSTRAINT_NODEF = 0, @@ -115,7 +106,6 @@ class KX_ConstraintActuator : public SCA_IActuator KX_ACT_CONSTRAINT_LOCAL = 1024, KX_ACT_CONSTRAINT_DOROTFH = 2048 }; - bool IsValidMode(KX_CONSTRAINTTYPE m); /// \see KX_RayCast bool RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void *UNUSED(data)); /// \see KX_RayCast @@ -126,26 +116,26 @@ class KX_ConstraintActuator : public SCA_IActuator int rotDampTime, float min, float max, - float refDir[3], + const mt::vec3& refDir, int locrot, int time, int option, char *property); virtual ~KX_ConstraintActuator(); - virtual CValue* GetReplica() { + virtual EXP_Value* GetReplica() { KX_ConstraintActuator* replica = new KX_ConstraintActuator(*this); replica->ProcessReplica(); return replica; }; - virtual bool Update(double curtime, bool frame); + virtual bool Update(double curtime); /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - static int pyattr_check_direction(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_check_min(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + static int pyattr_check_direction(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_check_min(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef); }; diff --git a/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp b/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp index 9c3ece2fb555..b8eca7f8f268 100644 --- a/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp +++ b/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp @@ -30,29 +30,27 @@ */ -#include "EXP_PyObjectPlus.h" #include "KX_ConstraintWrapper.h" -#include "PHY_IPhysicsEnvironment.h" - -KX_ConstraintWrapper::KX_ConstraintWrapper( - PHY_ConstraintType ctype, - int constraintId, - PHY_IPhysicsEnvironment* physenv) : - PyObjectPlus(), - m_constraintId(constraintId), - m_constraintType(ctype), - m_physenv(physenv) +#include "PHY_IConstraint.h" + +KX_ConstraintWrapper::KX_ConstraintWrapper(PHY_IConstraint *constraint) + :m_constraint(constraint) { } KX_ConstraintWrapper::~KX_ConstraintWrapper() { } +std::string KX_ConstraintWrapper::GetName() +{ + return "KX_ConstraintWrapper"; +} + #ifdef WITH_PYTHON PyObject *KX_ConstraintWrapper::PyGetConstraintId() { - return PyLong_FromLong(m_constraintId); + return PyLong_FromLong(m_constraint->GetIdentifier()); } @@ -61,10 +59,11 @@ PyObject *KX_ConstraintWrapper::PyGetParam(PyObject *args, PyObject *kwds) int dof; float value; - if (!PyArg_ParseTuple(args,"i:getParam",&dof)) - return NULL; + if (!PyArg_ParseTuple(args, "i:getParam", &dof)) { + return nullptr; + } - value = m_physenv->GetConstraintParam(m_constraintId,dof); + value = m_constraint->GetParam(dof); return PyFloat_FromDouble(value); } @@ -72,21 +71,22 @@ PyObject *KX_ConstraintWrapper::PyGetParam(PyObject *args, PyObject *kwds) PyObject *KX_ConstraintWrapper::PySetParam(PyObject *args, PyObject *kwds) { int dof; - float minLimit,maxLimit; + float minLimit, maxLimit; - if (!PyArg_ParseTuple(args,"iff:setParam",&dof,&minLimit,&maxLimit)) - return NULL; + if (!PyArg_ParseTuple(args, "iff:setParam", &dof, &minLimit, &maxLimit)) { + return nullptr; + } - m_physenv->SetConstraintParam(m_constraintId,dof,minLimit,maxLimit); + m_constraint->SetParam(dof, minLimit, maxLimit); Py_RETURN_NONE; } //python specific stuff PyTypeObject KX_ConstraintWrapper::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_ConstraintWrapper", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -94,40 +94,82 @@ PyTypeObject KX_ConstraintWrapper::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, - &PyObjectPlus::Type, - 0,0,0,0,0,0, + &EXP_PyObjectPlus::Type, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_ConstraintWrapper::Methods[] = { - {"getConstraintId",(PyCFunction) KX_ConstraintWrapper::sPyGetConstraintId, METH_NOARGS}, - {"setParam",(PyCFunction) KX_ConstraintWrapper::sPySetParam, METH_VARARGS}, - {"getParam",(PyCFunction) KX_ConstraintWrapper::sPyGetParam, METH_VARARGS}, - {NULL,NULL} //Sentinel + {"getConstraintId", (PyCFunction)KX_ConstraintWrapper::sPyGetConstraintId, METH_NOARGS}, + {"setParam", (PyCFunction)KX_ConstraintWrapper::sPySetParam, METH_VARARGS}, + {"getParam", (PyCFunction)KX_ConstraintWrapper::sPyGetParam, METH_VARARGS}, + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_ConstraintWrapper::Attributes[] = { - KX_PYATTRIBUTE_RO_FUNCTION("constraint_id", KX_ConstraintWrapper, pyattr_get_constraintId), - KX_PYATTRIBUTE_RO_FUNCTION("constraint_type", KX_ConstraintWrapper, pyattr_get_constraintType), - { NULL } //Sentinel + EXP_PYATTRIBUTE_RO_FUNCTION("constraint_id", KX_ConstraintWrapper, pyattr_get_constraintId), + EXP_PYATTRIBUTE_RO_FUNCTION("constraint_type", KX_ConstraintWrapper, pyattr_get_constraintType), + EXP_PYATTRIBUTE_RW_FUNCTION("breakingThreshold", KX_ConstraintWrapper, pyattr_get_breakingThreshold, pyattr_set_breakingThreshold), + EXP_PYATTRIBUTE_RW_FUNCTION("enabled", KX_ConstraintWrapper, pyattr_get_enabled, pyattr_set_enabled), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *KX_ConstraintWrapper::pyattr_get_constraintId(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_ConstraintWrapper::pyattr_get_constraintId(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_ConstraintWrapper *self = static_cast(self_v); + return PyLong_FromLong(self->m_constraint->GetIdentifier()); +} + +PyObject *KX_ConstraintWrapper::pyattr_get_constraintType(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_ConstraintWrapper *self = static_cast(self_v); + return PyLong_FromLong(self->m_constraint->GetType()); +} + +PyObject *KX_ConstraintWrapper::pyattr_get_breakingThreshold(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_ConstraintWrapper* self = static_cast(self_v); - return self->PyGetConstraintId(); + KX_ConstraintWrapper *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_constraint->GetBreakingThreshold()); } -PyObject *KX_ConstraintWrapper::pyattr_get_constraintType(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +int KX_ConstraintWrapper::pyattr_set_breakingThreshold(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_ConstraintWrapper* self = static_cast(self_v); - return PyLong_FromLong(self->m_constraintType); + KX_ConstraintWrapper *self = static_cast(self_v); + float val = PyFloat_AsDouble(value); + + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "constraint.%s = float: KX_ConstraintWrapper, expected a float", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; + } + + self->m_constraint->SetBreakingThreshold(val); + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_ConstraintWrapper::pyattr_get_enabled(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_ConstraintWrapper *self = static_cast(self_v); + return PyBool_FromLong(self->m_constraint->GetEnabled()); +} + +int KX_ConstraintWrapper::pyattr_set_enabled(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_ConstraintWrapper *self = static_cast(self_v); + int val = PyObject_IsTrue(value); + + if (val == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, "constraint.%s = bool: KX_ConstraintWrapper, expected True or False", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; + } + + self->m_constraint->SetEnabled(val); + return PY_SET_ATTR_SUCCESS; } #endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_ConstraintWrapper.h b/source/gameengine/Ketsji/KX_ConstraintWrapper.h index 8c645615fe8b..8051e759a0a3 100644 --- a/source/gameengine/Ketsji/KX_ConstraintWrapper.h +++ b/source/gameengine/Ketsji/KX_ConstraintWrapper.h @@ -33,29 +33,33 @@ #define __KX_CONSTRAINTWRAPPER_H__ #include "EXP_Value.h" -#include "PHY_DynamicTypes.h" -class KX_ConstraintWrapper : public PyObjectPlus +class PHY_IConstraint; + +class KX_ConstraintWrapper : public EXP_Value { Py_Header public: - KX_ConstraintWrapper(PHY_ConstraintType ctype,int constraintId,class PHY_IPhysicsEnvironment* physenv); + KX_ConstraintWrapper(PHY_IConstraint *constraint); virtual ~KX_ConstraintWrapper (); - int getConstraintId() { return m_constraintId; } + virtual std::string GetName(); + #ifdef WITH_PYTHON - KX_PYMETHOD_NOARGS(KX_ConstraintWrapper,GetConstraintId); - KX_PYMETHOD(KX_ConstraintWrapper,SetParam); - KX_PYMETHOD(KX_ConstraintWrapper,GetParam); + EXP_PYMETHOD_NOARGS(KX_ConstraintWrapper,GetConstraintId); + EXP_PYMETHOD(KX_ConstraintWrapper,SetParam); + EXP_PYMETHOD(KX_ConstraintWrapper,GetParam); - static PyObject *pyattr_get_constraintId(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_constraintType(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_constraintId(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_constraintType(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_breakingThreshold(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_breakingThreshold(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_enabled(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_enabled(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); #endif private: - int m_constraintId; - PHY_ConstraintType m_constraintType; - PHY_IPhysicsEnvironment* m_physenv; + PHY_IConstraint *m_constraint; }; #endif /* __KX_CONSTRAINTWRAPPER_H__ */ diff --git a/source/gameengine/Ketsji/KX_CubeMap.cpp b/source/gameengine/Ketsji/KX_CubeMap.cpp new file mode 100644 index 000000000000..2bffef0603f4 --- /dev/null +++ b/source/gameengine/Ketsji/KX_CubeMap.cpp @@ -0,0 +1,155 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Ulysse Martin, Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file KX_CubeMap.cpp + * \ingroup ketsji + */ + +#include "KX_CubeMap.h" +#include "KX_Camera.h" + +#include "RAS_Rasterizer.h" +#include "RAS_Texture.h" + +static const mt::mat3 topFaceViewMat( + 1.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + 0.0f, 0.0f, -1.0f); + +static const mt::mat3 bottomFaceViewMat( + -1.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + 0.0f, 0.0f, 1.0f); + +static const mt::mat3 frontFaceViewMat( + 0.0f, 0.0f, -1.0f, + 0.0f, -1.0f, 0.0f, + -1.0f, 0.0f, 0.0f); + +static const mt::mat3 backFaceViewMat( + 0.0f, 0.0f, 1.0f, + 0.0f, -1.0f, 0.0f, + 1.0f, 0.0f, 0.0f); + +static const mt::mat3 rightFaceViewMat( + 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, + 0.0f, -1.0f, 0.0f); + +static const mt::mat3 leftFaceViewMat( + 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, -1.0f, + 0.0f, 1.0f, 0.0f); + +const mt::mat3 KX_CubeMap::faceViewMatrices3x3[KX_CubeMap::NUM_FACES] = { + topFaceViewMat, + bottomFaceViewMat, + frontFaceViewMat, + backFaceViewMat, + rightFaceViewMat, + leftFaceViewMat +}; + +KX_CubeMap::KX_CubeMap(EnvMap *env, KX_GameObject *viewpoint) + :KX_TextureRenderer(env, viewpoint), + m_invalidProjection(true) +{ + for (int target : RAS_Texture::GetCubeMapTargets()) { + m_faces.emplace_back(target); + } +} + +KX_CubeMap::~KX_CubeMap() +{ +} + +std::string KX_CubeMap::GetName() +{ + return "KX_CubeMap"; +} + +void KX_CubeMap::InvalidateProjectionMatrix() +{ + m_invalidProjection = true; +} + +const mt::mat4& KX_CubeMap::GetProjectionMatrix(RAS_Rasterizer *rasty, KX_Scene *UNUSED(scene), KX_Camera *UNUSED(sceneCamera), + const RAS_Rect& UNUSED(viewport), const RAS_Rect& UNUSED(area)) +{ + if (m_invalidProjection) { + m_projection = rasty->GetFrustumMatrix(-m_clipStart, m_clipStart, -m_clipStart, m_clipStart, m_clipStart, m_clipEnd); + m_invalidProjection = false; + } + + return m_projection; +} + +bool KX_CubeMap::SetupCamera(KX_Camera *sceneCamera, KX_Camera *camera) +{ + KX_GameObject *viewpoint = GetViewpointObject(); + const mt::vec3& position = viewpoint->NodeGetWorldPosition(); + + camera->NodeSetWorldPosition(position); + + return true; +} + +bool KX_CubeMap::SetupCameraFace(KX_Camera *camera, unsigned short index) +{ + camera->NodeSetGlobalOrientation(faceViewMatrices3x3[index]); + + return true; +} + +#ifdef WITH_PYTHON + +PyTypeObject KX_CubeMap::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_CubeMap", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &KX_TextureRenderer::Type, + 0, 0, 0, 0, 0, 0, + py_base_new +}; + +PyMethodDef KX_CubeMap::Methods[] = { + {nullptr, nullptr} // Sentinel +}; + +PyAttributeDef KX_CubeMap::Attributes[] = { + EXP_PYATTRIBUTE_NULL // Sentinel +}; + +#endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_CubeMap.h b/source/gameengine/Ketsji/KX_CubeMap.h new file mode 100644 index 000000000000..37f6d10b70a2 --- /dev/null +++ b/source/gameengine/Ketsji/KX_CubeMap.h @@ -0,0 +1,63 @@ +/* +* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* Contributor(s): Ulysse Martin, Tristan Porteries. +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +/** \file KX_CubeMap.h + * \ingroup ketsji + */ + +#ifndef __KX_CUBEMAP_H__ +#define __KX_CUBEMAP_H__ + +#include "KX_TextureRenderer.h" + +class KX_CubeMap : public KX_TextureRenderer, public mt::SimdClassAllocator +{ + Py_Header + +private: + /// The camera projection matrix depending on clip start/end. + mt::mat4 m_projection; + /// True if the projection matrix is invalid and need to be recomputed. + bool m_invalidProjection; + +public: + enum { + NUM_FACES = 6 + }; + + /// Face view matrices in 3x3 matrices. + static const mt::mat3 faceViewMatrices3x3[NUM_FACES]; + + KX_CubeMap(EnvMap *env, KX_GameObject *viewpoint); + virtual ~KX_CubeMap(); + + virtual std::string GetName(); + + virtual void InvalidateProjectionMatrix(); + virtual const mt::mat4& GetProjectionMatrix(RAS_Rasterizer *rasty, KX_Scene *scene, KX_Camera *sceneCamera, + const RAS_Rect& viewport, const RAS_Rect& area); + + virtual bool SetupCamera(KX_Camera *sceneCamera, KX_Camera *camera); + virtual bool SetupCameraFace(KX_Camera *camera, unsigned short index); +}; + +#endif // __KX_CUBEMAP_H__ diff --git a/source/gameengine/Ketsji/KX_CullingHandler.cpp b/source/gameengine/Ketsji/KX_CullingHandler.cpp new file mode 100644 index 000000000000..8b9a2a81af45 --- /dev/null +++ b/source/gameengine/Ketsji/KX_CullingHandler.cpp @@ -0,0 +1,86 @@ +#include "KX_CullingHandler.h" +#include "KX_GameObject.h" + +#include "SG_Node.h" + +#include "tbb/tbb.h" + +class CullTask +{ +public: + std::vector m_activeObjects; + EXP_ListValue *m_objects; + KX_CullingHandler& m_handler; + int m_layer; + + CullTask(EXP_ListValue *objects, KX_CullingHandler& handler, int layer) + :m_objects(objects), + m_handler(handler), + m_layer(layer) + { + } + + CullTask(const CullTask& other, tbb::split) + :m_objects(other.m_objects), + m_handler(other.m_handler), + m_layer(other.m_layer) + { + } + + void operator()(const tbb::blocked_range& r) + { + for (unsigned int i = r.begin(), end = r.end(); i < end; ++i) { + KX_GameObject *obj = m_objects->GetValue(i); + if (obj->Renderable(m_layer)) { + // Update the object bounding volume box. + obj->UpdateBounds(false); + + SG_CullingNode& node = obj->GetCullingNode(); + const bool culled = m_handler.Test(obj->NodeGetWorldTransform(), obj->NodeGetWorldScaling(), node.GetAabb()); + + node.SetCulled(culled); + if (!culled) { + m_activeObjects.push_back(obj); + } + } + } + } + + void join(const CullTask& other) + { + m_activeObjects.insert(m_activeObjects.end(), other.m_activeObjects.begin(), other.m_activeObjects.end()); + } +}; + +KX_CullingHandler::KX_CullingHandler(EXP_ListValue *objects, const SG_Frustum& frustum, int layer) + :m_objects(objects), + m_frustum(frustum), + m_layer(layer) +{ +} + +bool KX_CullingHandler::Test(const mt::mat3x4& trans, const mt::vec3& scale, const SG_BBox& aabb) const +{ + bool culled = true; + const float maxscale = std::max(std::max(fabs(scale.x), fabs(scale.y)), fabs(scale.z)); + const SG_Frustum::TestType sphereTest = m_frustum.SphereInsideFrustum(trans * aabb.GetCenter(), maxscale * aabb.GetRadius()); + + // First test if the sphere is in the frustum as it is faster to test than box. + if (sphereTest == SG_Frustum::INSIDE) { + culled = false; + } + // If the sphere intersects we made a box test because the box could be not homogeneous. + else if (sphereTest == SG_Frustum::INTERSECT) { + const mt::mat4 mat = mt::mat4::FromAffineTransform(trans); + culled = (m_frustum.AabbInsideFrustum(aabb.GetMin(), aabb.GetMax(), mat) == SG_Frustum::OUTSIDE); + } + + return culled; +} + +std::vector KX_CullingHandler::Process() +{ + CullTask task(m_objects, *this, m_layer); + tbb::parallel_reduce(tbb::blocked_range(0, m_objects->GetCount()), task); + return task.m_activeObjects; +} diff --git a/source/gameengine/Ketsji/KX_CullingHandler.h b/source/gameengine/Ketsji/KX_CullingHandler.h new file mode 100644 index 000000000000..f58775e50e51 --- /dev/null +++ b/source/gameengine/Ketsji/KX_CullingHandler.h @@ -0,0 +1,38 @@ +#ifndef __KX_CULLING_HANDLER_H__ +#define __KX_CULLING_HANDLER_H__ + +#include "SG_Frustum.h" +#include "SG_BBox.h" + +#include "EXP_ListValue.h" + +#ifdef WIN32 +# ifndef NOMINMAX +# define NOMINMAX +# endif +#endif + +class KX_GameObject; + +class KX_CullingHandler +{ +private: + /// List of all objects to test. + EXP_ListValue *m_objects; + /// The camera frustum data. + const SG_Frustum& m_frustum; + /// Layer to ignore some objects. + int m_layer; + + +public: + KX_CullingHandler(EXP_ListValue *objects, const SG_Frustum& frustum, int layer); + ~KX_CullingHandler() = default; + + bool Test(const mt::mat3x4& trans, const mt::vec3& scale, const SG_BBox& aabb) const; + + /// Process the culling of all object and return a list of non-culled objects. + std::vector Process(); +}; + +#endif // __KX_CULLING_HANDLER_H__ diff --git a/source/gameengine/Ketsji/KX_Dome.cpp b/source/gameengine/Ketsji/KX_Dome.cpp deleted file mode 100644 index bfc8b6edf1bf..000000000000 --- a/source/gameengine/Ketsji/KX_Dome.cpp +++ /dev/null @@ -1,2050 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Contributor(s): Dalai Felinto - * - * This code is originally inspired on some of the ideas and codes from Paul Bourke. - * Developed as part of a Research and Development project for - * SAT - La Société des arts technologiques. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Ketsji/KX_Dome.cpp - * \ingroup ketsji - */ - -#include "KX_Dome.h" - -#ifdef WITH_PYTHON -#include -#endif - -#include -#include - -#include "DNA_scene_types.h" -#include "RAS_CameraData.h" -#include "BLI_math.h" - -#include "glew-mx.h" - -// constructor -KX_Dome::KX_Dome ( - RAS_ICanvas* canvas, - /// rasterizer - RAS_IRasterizer* rasterizer, - /// engine - KX_KetsjiEngine* engine, - - short res, //resolution of the mesh - short mode, //mode - fisheye, truncated, warped, panoramic, ... - short angle, - float resbuf, //size adjustment of the buffer - short tilt, - struct Text* warptext - - ): - dlistSupported(false), - canvaswidth(-1), canvasheight(-1), - m_drawingmode(rasterizer->GetDrawingMode()), - m_resolution(res), - m_mode(mode), - m_angle(angle), - m_resbuffer(resbuf), - m_tilt(tilt), - m_canvas(canvas), - m_rasterizer(rasterizer), - m_engine(engine) -{ - warp.usemesh = false; - fboSupported = false; - - if (mode >= DOME_NUM_MODES) - m_mode = DOME_FISHEYE; - - if (warptext) // it there is a text data try to warp it - { - char *buf; - buf = txt_to_buf(warptext); - if (buf) - { - warp.usemesh = ParseWarpMesh(STR_String(buf)); - MEM_freeN(buf); - } - } - - //setting the viewport size - const int *viewport = m_canvas->GetViewPort(); - - SetViewPort(viewport); - - switch (m_mode) { - case DOME_FISHEYE: - if (m_angle <= 180) { - cubetop.resize(1); - cubebottom.resize(1); - cubeleft.resize(2); - cuberight.resize(2); - - CreateMeshDome180(); - m_numfaces = 4; - } - else if (m_angle > 180) { - cubetop.resize(2); - cubebottom.resize(2); - cubeleft.resize(2); - cubefront.resize(2); - cuberight.resize(2); - - CreateMeshDome250(); - m_numfaces = 5; - } break; - case DOME_ENVMAP: - m_angle = 360; - m_numfaces = 6; - break; - case DOME_PANORAM_SPH: - cubeleft.resize(2); - cubeleftback.resize(2); - cuberight.resize(2); - cuberightback.resize(2); - cubetop.resize(2); - cubebottom.resize(2); - - m_angle = 360; - CreateMeshPanorama(); - m_numfaces = 6; - break; - default: //DOME_TRUNCATED_FRONT and DOME_TRUNCATED_REAR - if (m_angle <= 180) { - cubetop.resize(1); - cubebottom.resize(1); - cubeleft.resize(2); - cuberight.resize(2); - - CreateMeshDome180(); - m_numfaces = 4; - } - else if (m_angle > 180) { - cubetop.resize(2); - cubebottom.resize(2); - cubeleft.resize(2); - cubefront.resize(2); - cuberight.resize(2); - - CreateMeshDome250(); - m_numfaces = 5; - } break; - } - - m_numimages =(warp.usemesh?m_numfaces+1:m_numfaces); - - CalculateCameraOrientation(); - - CreateGLImages(); - - if (warp.usemesh) - fboSupported = CreateFBO(); - - dlistSupported = CreateDL(); -} - -// destructor -KX_Dome::~KX_Dome (void) -{ - ClearGLImages(); - - if (fboSupported) - glDeleteFramebuffersEXT(1, &warp.fboId); - - if (dlistSupported) - glDeleteLists(dlistId, (GLsizei) m_numimages); -} - -void KX_Dome::SetViewPort(const int viewport[4]) -{ - if (canvaswidth != m_viewport.GetWidth() || canvasheight != m_viewport.GetHeight()) - { - m_viewport.SetLeft(viewport[0]); - m_viewport.SetBottom(viewport[1]); - m_viewport.SetRight(viewport[2]); - m_viewport.SetTop(viewport[3]); - - CalculateImageSize(); - } -} - -void KX_Dome::CreateGLImages(void) -{ - glGenTextures(m_numimages, (GLuint*)&domefacesId); - - for (int j=0;jGetWidth(); - canvasheight = m_canvas->GetHeight(); - - m_buffersize = (canvaswidth > canvasheight?canvasheight:canvaswidth); - m_buffersize = (int)(m_buffersize*m_resbuffer); //reduce buffer size for better performance - - int i = 0; - while ((1 << i) <= m_buffersize) - i++; - m_imagesize = (1 << i); - - if (warp.usemesh) { - // warp FBO needs to be up to twice as big as m_buffersize to get more resolution - warp.imagesize = m_imagesize; - if (m_buffersize == m_imagesize) - warp.imagesize *= 2; - - //if FBO is not working/supported, we use the canvas dimension as buffer - warp.bufferwidth = canvaswidth; - warp.bufferheight = canvasheight; - } -} - -bool KX_Dome::CreateDL() -{ - dlistId = glGenLists((GLsizei) m_numimages); - if (dlistId != 0) { - if (m_mode == DOME_FISHEYE || m_mode == DOME_TRUNCATED_FRONT || m_mode == DOME_TRUNCATED_REAR) { - glNewList(dlistId, GL_COMPILE); - GLDrawTriangles(cubetop, nfacestop); - glEndList(); - - glNewList(dlistId+1, GL_COMPILE); - GLDrawTriangles(cubebottom, nfacesbottom); - glEndList(); - - glNewList(dlistId+2, GL_COMPILE); - GLDrawTriangles(cubeleft, nfacesleft); - glEndList(); - - glNewList(dlistId+3, GL_COMPILE); - GLDrawTriangles(cuberight, nfacesright); - glEndList(); - - if (m_angle > 180) { - glNewList(dlistId+4, GL_COMPILE); - GLDrawTriangles(cubefront, nfacesfront); - glEndList(); - } - } - else if (m_mode == DOME_PANORAM_SPH) - { - glNewList(dlistId, GL_COMPILE); - GLDrawTriangles(cubetop, nfacestop); - glEndList(); - - glNewList(dlistId+1, GL_COMPILE); - GLDrawTriangles(cubebottom, nfacesbottom); - glEndList(); - - glNewList(dlistId+2, GL_COMPILE); - GLDrawTriangles(cubeleft, nfacesleft); - glEndList(); - - glNewList(dlistId+3, GL_COMPILE); - GLDrawTriangles(cuberight, nfacesright); - glEndList(); - - glNewList(dlistId+4, GL_COMPILE); - GLDrawTriangles(cubeleftback, nfacesleftback); - glEndList(); - - glNewList(dlistId+5, GL_COMPILE); - GLDrawTriangles(cuberightback, nfacesrightback); - glEndList(); - } - - if (warp.usemesh) { - glNewList((dlistId + m_numfaces), GL_COMPILE); - GLDrawWarpQuads(); - glEndList(); - } - - //clearing the vectors - cubetop.clear(); - cubebottom.clear(); - cuberight.clear(); - cubeleft.clear(); - cubefront.clear(); - cubeleftback.clear(); - cuberightback.clear(); - warp.nodes.clear(); - - } else // genList failed - return false; - - return true; -} - -bool KX_Dome::CreateFBO(void) -{ - if (!GLEW_EXT_framebuffer_object) - { - printf("Dome Error: FrameBuffer unsupported. Using low resolution warp image."); - return false; - } - - glGenFramebuffersEXT(1, &warp.fboId); - if (warp.fboId==0) - { - printf("Dome Error: Invalid frame buffer object. Using low resolution warp image."); - return false; - } - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, warp.fboId); - - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, domefacesId[m_numfaces], 0); - - GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - - if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) - { - printf("Dome Error: FrameBuffer settings unsupported. Using low resolution warp image."); - return false; - } - else if (status != GL_FRAMEBUFFER_COMPLETE_EXT) - { - glDeleteFramebuffersEXT(1, &warp.fboId); - return false; - } - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - - //nothing failed: we can use the whole FBO as buffersize - warp.bufferwidth = warp.bufferheight = warp.imagesize; - return true; -} - -void KX_Dome::GLDrawTriangles(vector & face, int nfaces) -{ - int i,j; - glBegin(GL_TRIANGLES); - for (i=0;i columns, lines; - - lines = text.Explode('\n'); - if (lines.size() < 6) { - printf("Dome Error: Warp Mesh File with insufficient data!\n"); - return false; - } - columns = lines[1].Explode(' '); - if (columns.size() == 1) - columns = lines[1].Explode('\t'); - - if (columns.size() !=2) { - printf("Dome Error: Warp Mesh File incorrect. The second line should contain: width height.\n"); - return false; - } - - warp.mode = atoi(lines[0]);// 1 = radial, 2 = fisheye - - warp.n_width = atoi(columns[0]); - warp.n_height = atoi(columns[1]); - - if ((int)lines.size() < 2 + (warp.n_width * warp.n_height)) { - printf("Dome Error: Warp Mesh File with insufficient data!\n"); - return false; - } - else { - warp.nodes = vector > (warp.n_height, vector(warp.n_width)); - - for (i=2; i-2 < (warp.n_width*warp.n_height); i++) { - columns = lines[i].Explode(' '); - if (columns.size() == 1) - columns = lines[i].Explode('\t'); - - if (columns.size() == 5) { - nodeX = (i-2)%warp.n_width; - nodeY = ((i-2) - nodeX) / warp.n_width; - - warp.nodes[nodeY][nodeX].x = atof(columns[0]); - warp.nodes[nodeY][nodeX].y = atof(columns[1]); - warp.nodes[nodeY][nodeX].u = atof(columns[2]); - warp.nodes[nodeY][nodeX].v = atof(columns[3]); - warp.nodes[nodeY][nodeX].i = atof(columns[4]); - } - else { - warp.nodes.clear(); - printf("Dome Error: Warp Mesh File with wrong number of fields. You should use 5: x y u v i.\n"); - return false; - } - } - } - return true; -} - -void KX_Dome::CreateMeshDome180(void) -{ - /* - * 1)- Define the faces of half of a cube - * - each face is made out of 2 triangles - * 2) Subdivide the faces - * - more resolution == more curved lines - * 3) Spherize the cube - * - normalize the verts - * 4) Flatten onto xz plane - * - transform it onto an equidistant spherical projection techniques to transform the sphere onto a dome image - */ - int i,j; - float uv_ratio = (float)(m_buffersize-1) / m_imagesize; - - m_radangle = DEG2RADF(m_angle); //calculates the radians angle, used for flattening - - //creating faces for the env mapcube 180deg Dome - // Top Face - just a triangle - cubetop[0].verts[0][0] = (float)(-M_SQRT2) / 2.0f; - cubetop[0].verts[0][1] = 0.0f; - cubetop[0].verts[0][2] = 0.5f; - cubetop[0].u[0] = 0.0; - cubetop[0].v[0] = uv_ratio; - - cubetop[0].verts[1][0] = 0.0f; - cubetop[0].verts[1][1] = (float)M_SQRT2 / 2.0f; - cubetop[0].verts[1][2] = 0.5f; - cubetop[0].u[1] = 0.0; - cubetop[0].v[1] = 0.0; - - cubetop[0].verts[2][0] = (float)M_SQRT2 / 2.0f; - cubetop[0].verts[2][1] = 0.0f; - cubetop[0].verts[2][2] = 0.5f; - cubetop[0].u[2] = uv_ratio; - cubetop[0].v[2] = 0.0; - - nfacestop = 1; - - /* Bottom face - just a triangle */ - cubebottom[0].verts[0][0] = (float)(-M_SQRT2) / 2.0f; - cubebottom[0].verts[0][1] = 0.0f; - cubebottom[0].verts[0][2] = -0.5f; - cubebottom[0].u[0] = uv_ratio; - cubebottom[0].v[0] = 0.0; - - cubebottom[0].verts[1][0] = (float)M_SQRT2 / 2.0f; - cubebottom[0].verts[1][1] = 0; - cubebottom[0].verts[1][2] = -0.5f; - cubebottom[0].u[1] = 0.0; - cubebottom[0].v[1] = uv_ratio; - - cubebottom[0].verts[2][0] = 0.0f; - cubebottom[0].verts[2][1] = (float)M_SQRT2 / 2.0f; - cubebottom[0].verts[2][2] = -0.5f; - cubebottom[0].u[2] = 0.0; - cubebottom[0].v[2] = 0.0; - - nfacesbottom = 1; - - /* Left face - two triangles */ - - cubeleft[0].verts[0][0] = (float)(-M_SQRT2) / 2.0f; - cubeleft[0].verts[0][1] = 0.0f; - cubeleft[0].verts[0][2] = -0.5f; - cubeleft[0].u[0] = 0.0; - cubeleft[0].v[0] = 0.0; - - cubeleft[0].verts[1][0] = 0.0f; - cubeleft[0].verts[1][1] = (float)M_SQRT2 / 2.0f; - cubeleft[0].verts[1][2] = -0.5f; - cubeleft[0].u[1] = uv_ratio; - cubeleft[0].v[1] = 0.0; - - cubeleft[0].verts[2][0] = (float)(-M_SQRT2) / 2.0f; - cubeleft[0].verts[2][1] = 0.0f; - cubeleft[0].verts[2][2] = 0.5f; - cubeleft[0].u[2] = 0.0; - cubeleft[0].v[2] = uv_ratio; - - //second triangle - cubeleft[1].verts[0][0] = (float)(-M_SQRT2) / 2.0f; - cubeleft[1].verts[0][1] = 0.0f; - cubeleft[1].verts[0][2] = 0.5f; - cubeleft[1].u[0] = 0.0; - cubeleft[1].v[0] = uv_ratio; - - cubeleft[1].verts[1][0] = 0.0f; - cubeleft[1].verts[1][1] = (float)M_SQRT2 / 2.0f; - cubeleft[1].verts[1][2] = -0.5f; - cubeleft[1].u[1] = uv_ratio; - cubeleft[1].v[1] = 0.0; - - cubeleft[1].verts[2][0] = 0.0f; - cubeleft[1].verts[2][1] = (float)M_SQRT2 / 2.0f; - cubeleft[1].verts[2][2] = 0.5f; - cubeleft[1].u[2] = uv_ratio; - cubeleft[1].v[2] = uv_ratio; - - nfacesleft = 2; - - /* Right face - two triangles */ - cuberight[0].verts[0][0] = 0.0f; - cuberight[0].verts[0][1] = (float)M_SQRT2 / 2.0f; - cuberight[0].verts[0][2] = -0.5f; - cuberight[0].u[0] = 0.0; - cuberight[0].v[0] = 0.0; - - cuberight[0].verts[1][0] = (float)M_SQRT2 / 2.0f; - cuberight[0].verts[1][1] = 0.0f; - cuberight[0].verts[1][2] = -0.5f; - cuberight[0].u[1] = uv_ratio; - cuberight[0].v[1] = 0.0; - - cuberight[0].verts[2][0] = (float)M_SQRT2 / 2.0f; - cuberight[0].verts[2][1] = 0.0f; - cuberight[0].verts[2][2] = 0.5f; - cuberight[0].u[2] = uv_ratio; - cuberight[0].v[2] = uv_ratio; - - //second triangle - cuberight[1].verts[0][0] = 0.0f; - cuberight[1].verts[0][1] = (float)M_SQRT2 / 2.0f; - cuberight[1].verts[0][2] = -0.5f; - cuberight[1].u[0] = 0.0; - cuberight[1].v[0] = 0.0; - - cuberight[1].verts[1][0] = (float)M_SQRT2 / 2.0f; - cuberight[1].verts[1][1] = 0.0f; - cuberight[1].verts[1][2] = 0.5f; - cuberight[1].u[1] = uv_ratio; - cuberight[1].v[1] = uv_ratio; - - cuberight[1].verts[2][0] = 0.0f; - cuberight[1].verts[2][1] = (float)M_SQRT2 / 2.0f; - cuberight[1].verts[2][2] = 0.5f; - cuberight[1].u[2] = 0.0; - cuberight[1].v[2] = uv_ratio; - - nfacesright = 2; - - //Refine a triangular mesh by bisecting each edge forms 3 new triangles for each existing triangle on each iteration - //Could be made more efficient for drawing if the triangles were ordered in a fan. Not that important since we are using DisplayLists - - for (i=0;im_radangle / 2.0; - - phi = atan2(verts[i][2], verts[i][0]); - - verts[i][0] = r * cos(phi); - verts[i][1] = 0.0f; - verts[i][2] = r * sin(phi); - - if (r > 1.0) { - //round the border - verts[i][0] = cos(phi); - verts[i][1] = -3.0f; - verts[i][2] = sin(phi); - } - } -} - -void KX_Dome::FlattenPanorama(MT_Vector3 verts[3]) -{ -// it creates a full spherical panoramic (360deg) - int i; - double phi, theta; - bool edge=false; - - for (i=0;i<3;i++) { - phi = atan2(verts[i][1], verts[i][0]); - phi *= -1.0; //flipping - - if (phi == -MT_PI) //It's on the edge - edge=true; - - verts[i][0] = phi / MT_PI; - verts[i][1] = 0.0f; - - theta = asin(verts[i][2]); - verts[i][2] = theta / MT_PI; - } - if (edge) { - bool right=false; - - for (i=0;i<3;i++) { - if (fmodf(verts[i][0],1.0f) > 0.0f) { - right=true; - break; - } - } - if (right) { - for (i=0;i<3;i++) { - if (verts[i][0] < 0.0f) - verts[i][0] *= -1.0f; - } - } - } -} - -void KX_Dome::SplitFace(vector & face, int *nfaces) -{ - int i; - int n1, n2; - - n1 = n2 = *nfaces; - - for (i=0;iGetCameraNear(),cam->GetCameraFar()); -#endif - - RAS_FrameFrustum m_frustum; //90 deg. Frustum - - m_frustum.camnear = cam->GetCameraNear(); - m_frustum.camfar = cam->GetCameraFar(); - -// float top = tan(90.0f*MT_PI/360.0f) * m_frustum.camnear; - float top = m_frustum.camnear; // for deg = 90deg, tan = 1 - - m_frustum.x1 = -top; - m_frustum.x2 = top; - m_frustum.y1 = -top; - m_frustum.y2 = top; - - m_projmat = m_rasterizer->GetFrustumMatrix( - m_frustum.x1, m_frustum.x2, m_frustum.y1, m_frustum.y2, m_frustum.camnear, m_frustum.camfar); -} - -void KX_Dome::CalculateCameraOrientation() -{ -/* - * Uses 4 cameras for angles up to 180deg - * Uses 5 cameras for angles up to 250deg - * Uses 6 cameras for angles up to 360deg - */ - int i; - float deg45 = MT_PI / 4.0f; - MT_Scalar c = cosf(deg45); - MT_Scalar s = sinf(deg45); - - if (m_angle <= 180 && (m_mode == DOME_FISHEYE - || m_mode == DOME_TRUNCATED_FRONT - || m_mode == DOME_TRUNCATED_REAR)) { - - m_locRot[0] = MT_Matrix3x3( // 90deg - Top - c, -s, 0.0f, - 0.0f,0.0f, -1.0f, - s, c, 0.0f); - - m_locRot[1] = MT_Matrix3x3( // 90deg - Bottom - -s, c, 0.0f, - 0.0f,0.0f, 1.0f, - s, c, 0.0f); - - m_locRot[2] = MT_Matrix3x3( // 45deg - Left - c, 0.0f, s, - 0, 1.0f, 0.0f, - -s, 0.0f, c); - - m_locRot[3] = MT_Matrix3x3( // 45deg - Right - c, 0.0f, -s, - 0.0f, 1.0f, 0.0f, - s, 0.0f, c); - - } else if (m_mode == DOME_ENVMAP || (m_angle > 180 && (m_mode == DOME_FISHEYE - || m_mode == DOME_TRUNCATED_FRONT - || m_mode == DOME_TRUNCATED_REAR))) { - - m_locRot[0] = MT_Matrix3x3( // 90deg - Top - 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f,-1.0f, - 0.0f, 1.0f, 0.0f); - - m_locRot[1] = MT_Matrix3x3( // 90deg - Bottom - 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, - 0.0f,-1.0f, 0.0f); - - m_locRot[2] = MT_Matrix3x3( // -90deg - Left - 0.0f, 0.0f, 1.0f, - 0.0f, 1.0f, 0.0f, - -1.0f, 0.0f, 0.0f); - - m_locRot[3] = MT_Matrix3x3( // 90deg - Right - 0.0f, 0.0f,-1.0f, - 0.0f, 1.0f, 0.0f, - 1.0f, 0.0f, 0.0f); - - m_locRot[4] = MT_Matrix3x3( // 0deg - Front - 1.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 1.0f); - - m_locRot[5] = MT_Matrix3x3( // 180deg - Back - USED for ENVMAP only - -1.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f,-1.0f); - - } else if (m_mode == DOME_PANORAM_SPH) { - - m_locRot[0] = MT_Matrix3x3( // Top - c, s, 0.0f, - 0.0f,0.0f, -1.0f, - -s, c, 0.0f); - - m_locRot[1] = MT_Matrix3x3( // Bottom - c, s, 0.0f, - 0.0f, 0.0f, 1.0f, - s, -c, 0.0f); - - m_locRot[2] = MT_Matrix3x3( // 45deg - Left - -s, 0.0f, c, - 0, 1.0f, 0.0f, - -c, 0.0f, -s); - - m_locRot[3] = MT_Matrix3x3( // 45deg - Right - c, 0.0f, s, - 0, 1.0f, 0.0f, - -s, 0.0f, c); - - m_locRot[4] = MT_Matrix3x3( // 135deg - LeftBack - -s, 0.0f, -c, - 0.0f, 1.0f, 0.0f, - c, 0.0f, -s); - - m_locRot[5] = MT_Matrix3x3( // 135deg - RightBack - c, 0.0f, -s, - 0.0f, 1.0f, 0.0f, - s, 0.0f, c); - } - - // rotating the camera in horizontal axis - if (m_tilt) - { - float tiltdeg = ((m_tilt % 360) * 2 * MT_PI) / 360; - c = cosf(tiltdeg); - s = sinf(tiltdeg); - - MT_Matrix3x3 tilt_mat = MT_Matrix3x3( - 1.0f, 0.0f, 0.0f, - 0.0f, c, -s, - 0.0f, s, c - ); - - for (i =0;i<6;i++) - m_locRot[i] = tilt_mat * m_locRot[i]; - } -} - -void KX_Dome::RotateCamera(KX_Camera* cam, int i) -{ -// I'm not using it, I'm doing inline calls for these commands -// but it's nice to have it here in case I need it - - MT_Matrix3x3 camori = cam->GetSGNode()->GetLocalOrientation(); - - cam->NodeSetLocalOrientation(camori*m_locRot[i]); - cam->NodeUpdateGS(0.f); - - MT_Transform camtrans(cam->GetWorldToCamera()); - MT_Matrix4x4 viewmat(camtrans); - m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->NodeGetLocalScaling(), cam->GetCameraData()->m_perspective); - cam->SetModelviewMatrix(viewmat); - - // restore the original orientation - cam->NodeSetLocalOrientation(camori); - cam->NodeUpdateGS(0.f); -} - -void KX_Dome::Draw(void) -{ - - if (fboSupported) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, warp.fboId); - - glViewport(0,0,warp.imagesize, warp.imagesize); - glScissor(0,0,warp.imagesize, warp.imagesize); - } - - switch (m_mode) { - case DOME_FISHEYE: - DrawDomeFisheye(); - break; - case DOME_ENVMAP: - DrawEnvMap(); - break; - case DOME_PANORAM_SPH: - DrawPanorama(); - break; - case DOME_TRUNCATED_FRONT: - DrawDomeFisheye(); - break; - case DOME_TRUNCATED_REAR: - DrawDomeFisheye(); - break; - } - - if (warp.usemesh) - { - if (fboSupported) - { - m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight()); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - } - else - { - glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_viewport.GetLeft(), m_viewport.GetBottom(), warp.bufferwidth, warp.bufferheight); - } - DrawDomeWarped(); - } -} - -void KX_Dome::DrawEnvMap(void) -{ - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - // Making the viewport always square - - int can_width = m_viewport.GetRight(); - int can_height = m_viewport.GetTop(); - - float ortho_width, ortho_height; - - if (warp.usemesh) - glOrtho((-1.0), 1.0, (-0.66), 0.66, 0.0, 0.0); //stretch the image to reduce resolution lost - - else { - if (can_width/3 <= can_height/2) { - ortho_width = 1.0f; - ortho_height = (float)can_height/can_width; - } - else { - ortho_height = 2.0f / 3; - ortho_width = (float)can_width/can_height * ortho_height; - } - - glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -20.0f, 10.0f); - } - - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - gluLookAt(0.0f,0.0f,1.0f, 0.0f,0.0f,0.0f, 0.0f,1.0f,0.0f); - - glPolygonMode(GL_FRONT, GL_FILL); - glShadeModel(GL_SMOOTH); - glDisable(GL_LIGHTING); - glDisable(GL_DEPTH_TEST); - - glEnable(GL_TEXTURE_2D); - glColor3f(1.0f,1.0f,1.0f); - - float uv_ratio = (float)(m_buffersize-1) / m_imagesize; - double onebythree = 1.0f / 3; - - // domefacesId[0] => (top) - glBindTexture(GL_TEXTURE_2D, domefacesId[0]); - glBegin(GL_QUADS); - glTexCoord2f(uv_ratio,uv_ratio); - glVertex3f( onebythree, 0.0f, 3.0f); - glTexCoord2f(0.0f,uv_ratio); - glVertex3f(-onebythree, 0.0f, 3.0f); - glTexCoord2f(0.0f,0.0f); - glVertex3f(-onebythree,-2 * onebythree, 3.0f); - glTexCoord2f(uv_ratio,0.0f); - glVertex3f(onebythree,-2 * onebythree, 3.0f); - glEnd(); - - // domefacesId[1] => (bottom) - glBindTexture(GL_TEXTURE_2D, domefacesId[1]); - glBegin(GL_QUADS); - glTexCoord2f(uv_ratio,uv_ratio); - glVertex3f(-onebythree, 0.0f, 3.0f); - glTexCoord2f(0.0f,uv_ratio); - glVertex3f(-1.0f, 0.0f, 3.0f); - glTexCoord2f(0.0f,0.0f); - glVertex3f(-1.0f,-2 * onebythree, 3.0f); - glTexCoord2f(uv_ratio,0.0f); - glVertex3f(-onebythree,-2 * onebythree, 3.0f); - glEnd(); - - // domefacesId[2] => -90deg (left) - glBindTexture(GL_TEXTURE_2D, domefacesId[2]); - glBegin(GL_QUADS); - glTexCoord2f(uv_ratio,uv_ratio); - glVertex3f(-onebythree, 2 * onebythree, 3.0f); - glTexCoord2f(0.0f,uv_ratio); - glVertex3f(-1.0f, 2 * onebythree, 3.0f); - glTexCoord2f(0.0f,0.0f); - glVertex3f(-1.0f, 0.0f, 3.0f); - glTexCoord2f(uv_ratio,0.0f); - glVertex3f(-onebythree, 0.0f, 3.0f); - glEnd(); - - // domefacesId[3] => 90deg (right) - glBindTexture(GL_TEXTURE_2D, domefacesId[3]); - glBegin(GL_QUADS); - glTexCoord2f(uv_ratio,uv_ratio); - glVertex3f( 1.0f, 2 * onebythree, 3.0f); - glTexCoord2f(0.0f,uv_ratio); - glVertex3f( onebythree, 2 * onebythree, 3.0f); - glTexCoord2f(0.0f,0.0f); - glVertex3f( onebythree, 0.0f, 3.0f); - glTexCoord2f(uv_ratio,0.0f); - glVertex3f(1.0f, 0.0f, 3.0f); - glEnd(); - - // domefacesId[4] => 0deg (front) - glBindTexture(GL_TEXTURE_2D, domefacesId[4]); - glBegin(GL_QUADS); - glTexCoord2f(uv_ratio,uv_ratio); - glVertex3f( 1.0f, 0.0f, 3.0f); - glTexCoord2f(0.0f,uv_ratio); - glVertex3f( onebythree, 0.0f, 3.0f); - glTexCoord2f(0.0f,0.0f); - glVertex3f( onebythree,-2 * onebythree, 3.0f); - glTexCoord2f(uv_ratio,0.0f); - glVertex3f(1.0f, -2 * onebythree, 3.0f); - glEnd(); - - // domefacesId[5] => 180deg (back) - glBindTexture(GL_TEXTURE_2D, domefacesId[5]); - glBegin(GL_QUADS); - glTexCoord2f(uv_ratio,uv_ratio); - glVertex3f( onebythree, 2 * onebythree, 3.0f); - glTexCoord2f(0.0f,uv_ratio); - glVertex3f(-onebythree, 2 * onebythree, 3.0f); - glTexCoord2f(0.0f,0.0f); - glVertex3f(-onebythree, 0.0f, 3.0f); - glTexCoord2f(uv_ratio,0.0f); - glVertex3f(onebythree, 0.0f, 3.0f); - glEnd(); - - glDisable(GL_TEXTURE_2D); - glEnable(GL_DEPTH_TEST); -} - -void KX_Dome::DrawDomeFisheye(void) -{ - int i; - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - // Making the viewport always square - - int can_width = m_viewport.GetRight(); - int can_height = m_viewport.GetTop(); - - float ortho_width, ortho_height; - - if (m_mode == DOME_FISHEYE) { - if (warp.usemesh) - glOrtho((-1.0f), 1.0f, (-1.0f), 1.0f, -20.0f, 10.0f); //stretch the image to reduce resolution lost - - else { - if (can_width < can_height) { - ortho_width = 1.0f; - ortho_height = (float)can_height/can_width; - } - else { - ortho_width = (float)can_width/can_height; - ortho_height = 1.0f; - } - - glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -20.0f, 10.0f); - } - } - else if (m_mode == DOME_TRUNCATED_FRONT) - { - ortho_width = 1.0f; - ortho_height = 2.0f * ((float)can_height / can_width) - 1.0f; - - glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_width, -20.0f, 10.0f); - } - else { //m_mode == DOME_TRUNCATED_REAR - ortho_width = 1.0f; - ortho_height = 2.0f * ((float)can_height / can_width) - 1.0f; - - glOrtho((-ortho_width), ortho_width, (-ortho_width), ortho_height, -20.0f, 10.0f); - } - - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - gluLookAt(0.0f,-1.0f,0.0f, 0.0f,0.0f,0.0f, 0.0f,0.0f,1.0f); - - if (m_drawingmode == RAS_IRasterizer::KX_WIREFRAME) - glPolygonMode(GL_FRONT, GL_LINE); - else - glPolygonMode(GL_FRONT, GL_FILL); - - glShadeModel(GL_SMOOTH); - glDisable(GL_LIGHTING); - glDisable(GL_DEPTH_TEST); - - glEnable(GL_TEXTURE_2D); - glColor3f(1.0f,1.0f,1.0f); - - if (dlistSupported) { - for (i=0;i 180) { - // front triangle - glBindTexture(GL_TEXTURE_2D, domefacesId[4]); - GLDrawTriangles(cubefront, nfacesfront); - } - } - glDisable(GL_TEXTURE_2D); - glEnable(GL_DEPTH_TEST); -} - -void KX_Dome::DrawPanorama(void) -{ - int i; - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - // Making the viewport always square - - int can_width = m_viewport.GetRight(); - int can_height = m_viewport.GetTop(); - - float ortho_height = 1.0f; - float ortho_width = 1.0f; - - if (warp.usemesh) - glOrtho((-1.0f), 1.0f, (-0.5f), 0.5f, -20.0f, 10.0f); //stretch the image to reduce resolution lost - - else { - //using all the screen - if ((can_width / 2) <= (can_height)) { - ortho_width = 1.0f; - ortho_height = (float)can_height/can_width; - } - else { - ortho_width = (float)can_width / can_height * 0.5f; - ortho_height = 0.5f; - } - - glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -20.0f, 10.0f); - } - - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - gluLookAt(0.0f,-1.0f,0.0f, 0.0f,0.0f,0.0f, 0.0f,0.0f,1.0f); - - if (m_drawingmode == RAS_IRasterizer::KX_WIREFRAME) - glPolygonMode(GL_FRONT, GL_LINE); - else - glPolygonMode(GL_FRONT, GL_FILL); - - glShadeModel(GL_SMOOTH); - glDisable(GL_LIGHTING); - glDisable(GL_DEPTH_TEST); - - glEnable(GL_TEXTURE_2D); - glColor3f(1.0f,1.0f,1.0f); - - if (dlistSupported) { - for (i=0;i (top) - glBindTexture(GL_TEXTURE_2D, domefacesId[0]); - GLDrawTriangles(cubetop, nfacestop); - - // domefacesId[5] => (bottom) - glBindTexture(GL_TEXTURE_2D, domefacesId[1]); - GLDrawTriangles(cubebottom, nfacesbottom); - - // domefacesId[1] => -45deg (left) - glBindTexture(GL_TEXTURE_2D, domefacesId[2]); - GLDrawTriangles(cubeleft, nfacesleft); - - // domefacesId[2] => 45deg (right) - glBindTexture(GL_TEXTURE_2D, domefacesId[3]); - GLDrawTriangles(cuberight, nfacesright); - - // domefacesId[0] => -135deg (leftback) - glBindTexture(GL_TEXTURE_2D, domefacesId[4]); - GLDrawTriangles(cubeleftback, nfacesleftback); - - // domefacesId[3] => 135deg (rightback) - glBindTexture(GL_TEXTURE_2D, domefacesId[5]); - GLDrawTriangles(cuberightback, nfacesrightback); - } - glDisable(GL_TEXTURE_2D); - glEnable(GL_DEPTH_TEST); -} - -void KX_Dome::DrawDomeWarped(void) -{ - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - // Making the viewport always square - int can_width = m_viewport.GetRight(); - int can_height = m_viewport.GetTop(); - - double screen_ratio = can_width/ (double) can_height; - - glOrtho(-screen_ratio,screen_ratio,-1.0f,1.0f,-20.0f,10.0f); - - - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - gluLookAt(0.0f, 0.0f, 1.0f, 0.0f,0.0f,0.0f, 0.0f,1.0f,0.0f); - - if (m_drawingmode == RAS_IRasterizer::KX_WIREFRAME) - glPolygonMode(GL_FRONT, GL_LINE); - else - glPolygonMode(GL_FRONT, GL_FILL); - - glShadeModel(GL_SMOOTH); - glDisable(GL_LIGHTING); - glDisable(GL_DEPTH_TEST); - - glEnable(GL_TEXTURE_2D); - glColor3f(1.0f,1.0f,1.0f); - - if (dlistSupported) { - glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]); - glCallList(dlistId + m_numfaces); - } - else { - glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]); - GLDrawWarpQuads(); - } - glDisable(GL_TEXTURE_2D); - glEnable(GL_DEPTH_TEST); -} - -void KX_Dome::BindImages(int i) -{ - glBindTexture(GL_TEXTURE_2D, domefacesId[i]); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_viewport.GetLeft(), m_viewport.GetBottom(), m_buffersize, m_buffersize); -} - -void KX_Dome::RenderDomeFrame(KX_Scene* scene, KX_Camera* cam, int i) -{ - if (!cam) - return; - - m_canvas->SetViewPort(0,0,m_buffersize-1,m_buffersize-1); - -// m_rasterizer->SetAmbient(); - m_rasterizer->DisplayFog(); - - CalculateFrustum(cam); //calculates m_projmat - cam->SetProjectionMatrix(m_projmat); - m_rasterizer->SetProjectionMatrix(cam->GetProjectionMatrix()); -// Dome_RotateCamera(cam,i); - - MT_Matrix3x3 camori = cam->GetSGNode()->GetLocalOrientation(); - - cam->NodeSetLocalOrientation(camori*m_locRot[i]); - cam->NodeUpdateGS(0.f); - - MT_Transform camtrans(cam->GetWorldToCamera()); - MT_Matrix4x4 viewmat(camtrans); - m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->NodeGetLocalScaling(), 1.0f); - cam->SetModelviewMatrix(viewmat); - - // restore the original orientation - cam->NodeSetLocalOrientation(camori); - cam->NodeUpdateGS(0.f); - - scene->CalculateVisibleMeshes(m_rasterizer,cam); - - m_engine->UpdateAnimations(scene); - - scene->RenderBuckets(camtrans, m_rasterizer); -} diff --git a/source/gameengine/Ketsji/KX_Dome.h b/source/gameengine/Ketsji/KX_Dome.h deleted file mode 100644 index 26079a10e1d3..000000000000 --- a/source/gameengine/Ketsji/KX_Dome.h +++ /dev/null @@ -1,197 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Contributor(s): Dalai Felinto - * - * This source uses some of the ideas and code from Paul Bourke. - * Developed as part of a Research and Development project for - * SAT - La Société des arts technologiques. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file KX_Dome.h - * \ingroup ketsji - */ - -#ifndef __KX_DOME_H__ -#define __KX_DOME_H__ - -#include "KX_Scene.h" -#include "KX_Camera.h" -#include "DNA_screen_types.h" -#include "RAS_ICanvas.h" -#include "RAS_IRasterizer.h" -#include "KX_KetsjiEngine.h" - -#include "GPU_glew.h" -#include - -#include "MEM_guardedalloc.h" -#include "BKE_text.h" - -//Dome modes: limit hardcoded in buttons_scene.c -#define DOME_FISHEYE 1 -#define DOME_TRUNCATED_FRONT 2 -#define DOME_TRUNCATED_REAR 3 -#define DOME_ENVMAP 4 -#define DOME_PANORAM_SPH 5 -#define DOME_NUM_MODES 6 - - -/// class for render 3d scene -class KX_Dome -{ -public: - /// constructor - KX_Dome (RAS_ICanvas* m_canvas, - /// rasterizer - RAS_IRasterizer* m_rasterizer, - /// engine - KX_KetsjiEngine* m_engine, - - short res, - short mode, - short angle, - float resbuf, - short tilt, - struct Text* warptext - ); - - /// destructor - virtual ~KX_Dome (void); - - //openGL checks: - bool dlistSupported; - bool fboSupported; - - //openGL names: - GLuint domefacesId[7]; /* ID of the images -- room for 7 images, using only 4 for 180deg x 360deg dome, - * 6 for panoramic and +1 for warp mesh */ - GLuint dlistId; /* ID of the Display Lists of the images (used as an offset) */ - - typedef struct { - double u[3], v[3]; - MT_Vector3 verts[3]; //three verts - } DomeFace; - - //mesh warp functions - typedef struct { - double x, y, u, v, i; - } WarpMeshNode; - - struct { - bool usemesh; - int mode; - int n_width, n_height; //nodes width and height - int imagesize; - int bufferwidth, bufferheight; - GLuint fboId; - vector > nodes; - } warp; - - bool ParseWarpMesh(STR_String text); - - vector cubetop, cubebottom, cuberight, cubeleft, cubefront, cubeback; //for fisheye - vector cubeleftback, cuberightback; //for panorama - - int nfacestop, nfacesbottom, nfacesleft, nfacesright, nfacesfront, nfacesback; - int nfacesleftback, nfacesrightback; - - int GetNumberRenders() { return m_numfaces; } - - void RenderDome(void); - void RenderDomeFrame(KX_Scene* scene, KX_Camera* cam, int i); - void BindImages(int i); - - void SetViewPort(const int viewport[4]); - void CalculateFrustum(KX_Camera* cam); - void RotateCamera(KX_Camera* cam, int i); - - //Mesh creation Functions - void CreateMeshDome180(void); - void CreateMeshDome250(void); - void CreateMeshPanorama(void); - - void SplitFace(vector & face, int *nfaces); - - void FlattenDome(MT_Vector3 verts[3]); - void FlattenPanorama(MT_Vector3 verts[3]); - - //Draw functions - void GLDrawTriangles(vector & face, int nfaces); - void GLDrawWarpQuads(void); - void Draw(void); - void DrawDomeFisheye(void); - void DrawEnvMap(void); - void DrawPanorama(void); - void DrawDomeWarped(void); - - //setting up openGL - void CreateGLImages(void); - void ClearGLImages(void);//called on resize - bool CreateDL(void); //create Display Lists - void ClearDL(void); //remove Display Lists - bool CreateFBO(void);//create FBO (for warp mesh) - void ClearFBO(void); //remove FBO - - void CalculateCameraOrientation(); - void CalculateImageSize(); //set m_imagesize - - int canvaswidth; - int canvasheight; - -protected: - int m_drawingmode; - - int m_imagesize; - int m_buffersize; // canvas small dimension - int m_numfaces; // 4 to 6 depending on the kind of dome image - int m_numimages; //numfaces +1 if we have warp mesh - - short m_resolution; //resolution to tessellate the mesh - short m_mode; // the mode (truncated, warped, panoramic,...) - short m_angle; //the angle of the fisheye - float m_radangle; //the angle of the fisheye in radians - float m_resbuffer; //the resolution of the buffer - short m_tilt; //the dome tilt (camera rotation on horizontal axis) - - RAS_Rect m_viewport; - - MT_Matrix4x4 m_projmat; - - MT_Matrix3x3 m_locRot[6]; // the rotation matrix - - /// rendered scene - KX_Scene * m_scene; - - /// canvas - RAS_ICanvas* m_canvas; - /// rasterizer - RAS_IRasterizer* m_rasterizer; - /// render tools - RAS_IRenderTools* m_rendertools; - /// engine - KX_KetsjiEngine* m_engine; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_Dome") -#endif -}; - -#endif /* __KX_DOME_H__ */ diff --git a/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp b/source/gameengine/Ketsji/KX_DynamicActuator.cpp similarity index 63% rename from source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp rename to source/gameengine/Ketsji/KX_DynamicActuator.cpp index 5593b16cc337..e82fade32d35 100644 --- a/source/gameengine/Ketsji/KX_SCA_DynamicActuator.cpp +++ b/source/gameengine/Ketsji/KX_DynamicActuator.cpp @@ -25,7 +25,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file gameengine/Ketsji/KX_SCA_DynamicActuator.cpp +/** \file gameengine/Ketsji/KX_DynamicActuator.cpp * \ingroup ketsji * Adjust dynamics settings for this object */ @@ -34,7 +34,7 @@ * \source\gameengine\GameLogic\SCA_DynamicActuator.cpp * Please look here for revision history. */ -#include "KX_SCA_DynamicActuator.h" +#include "KX_DynamicActuator.h" #include "PHY_IPhysicsController.h" #ifdef WITH_PYTHON @@ -45,10 +45,10 @@ /* Integration hooks ------------------------------------------------------- */ -PyTypeObject KX_SCA_DynamicActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "KX_SCA_DynamicActuator", - sizeof(PyObjectPlus_Proxy), +PyTypeObject KX_DynamicActuator::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_DynamicActuator", + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -56,25 +56,25 @@ PyTypeObject KX_SCA_DynamicActuator::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IActuator::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; -PyMethodDef KX_SCA_DynamicActuator::Methods[] = { - {NULL,NULL} //Sentinel +PyMethodDef KX_DynamicActuator::Methods[] = { + {nullptr, nullptr} //Sentinel }; -PyAttributeDef KX_SCA_DynamicActuator::Attributes[] = { - KX_PYATTRIBUTE_SHORT_RW("mode",0,4,false,KX_SCA_DynamicActuator,m_dyn_operation), - KX_PYATTRIBUTE_FLOAT_RW("mass",0.0f,FLT_MAX,KX_SCA_DynamicActuator,m_setmass), - { NULL } //Sentinel +PyAttributeDef KX_DynamicActuator::Attributes[] = { + EXP_PYATTRIBUTE_SHORT_RW("mode", 0, 4, false, KX_DynamicActuator, m_dyn_operation), + EXP_PYATTRIBUTE_FLOAT_RW("mass", 0.0f, FLT_MAX, KX_DynamicActuator, m_setmass), + EXP_PYATTRIBUTE_NULL //Sentinel }; #endif // WITH_PYTHON @@ -83,9 +83,9 @@ PyAttributeDef KX_SCA_DynamicActuator::Attributes[] = { /* Native functions */ /* ------------------------------------------------------------------------- */ -KX_SCA_DynamicActuator::KX_SCA_DynamicActuator(SCA_IObject *gameobj, - short dyn_operation, - float setmass) : +KX_DynamicActuator::KX_DynamicActuator(SCA_IObject *gameobj, + short dyn_operation, + float setmass) : SCA_IActuator(gameobj, KX_ACT_DYNAMIC), m_dyn_operation(dyn_operation), @@ -94,49 +94,72 @@ KX_SCA_DynamicActuator::KX_SCA_DynamicActuator(SCA_IObject *gameobj, } /* End of constructor */ -KX_SCA_DynamicActuator::~KX_SCA_DynamicActuator() +KX_DynamicActuator::~KX_DynamicActuator() { // there's nothing to be done here, really.... } /* end of destructor */ -bool KX_SCA_DynamicActuator::Update() +bool KX_DynamicActuator::Update() { // bool result = false; /*unused*/ - KX_GameObject *obj = (KX_GameObject*) GetParent(); + KX_GameObject *obj = (KX_GameObject *)GetParent(); bool bNegativeEvent = IsNegativeEvent(); - PHY_IPhysicsController* controller; + PHY_IPhysicsController *controller; RemoveAllEvents(); - if (bNegativeEvent) + if (bNegativeEvent) { return false; // do nothing on negative events - if (!obj) + } + if (!obj) { return false; // object not accessible, shouldnt happen + } controller = obj->GetPhysicsController(); - if (!controller) - return false; // no physic object + if (!controller) { + return false; // no physic object - switch (m_dyn_operation) - { - case 0: + } + switch (m_dyn_operation) { + case KX_DYN_RESTORE_DYNAMICS: + { // Child objects must be static, so we block changing to dynamic - if (!obj->GetParent()) + if (!obj->GetParent()) { controller->RestoreDynamics(); + } break; - case 1: + } + case KX_DYN_DISABLE_DYNAMICS: + { controller->SuspendDynamics(); break; - case 2: + } + case KX_DYN_ENABLE_RIGID_BODY: + { controller->SetRigidBody(true); break; - case 3: + } + case KX_DYN_DISABLE_RIGID_BODY: + { controller->SetRigidBody(false); break; - case 4: + } + case KX_DYN_SET_MASS: + { controller->SetMass(m_setmass); break; + } + case KX_DYN_RESTORE_PHYSICS: + { + controller->RestorePhysics(); + break; + } + case KX_DYN_DISABLE_PHYSICS: + { + controller->SuspendPhysics(false); + break; + } } return false; @@ -144,13 +167,14 @@ bool KX_SCA_DynamicActuator::Update() -CValue* KX_SCA_DynamicActuator::GetReplica() +EXP_Value *KX_DynamicActuator::GetReplica() { - KX_SCA_DynamicActuator* replica = - new KX_SCA_DynamicActuator(*this); + KX_DynamicActuator *replica = + new KX_DynamicActuator(*this); - if (replica == NULL) - return NULL; + if (replica == nullptr) { + return nullptr; + } replica->ProcessReplica(); return replica; diff --git a/source/gameengine/Ketsji/KX_SCA_DynamicActuator.h b/source/gameengine/Ketsji/KX_DynamicActuator.h similarity index 85% rename from source/gameengine/Ketsji/KX_SCA_DynamicActuator.h rename to source/gameengine/Ketsji/KX_DynamicActuator.h index 6118ebd35590..56d956e13801 100644 --- a/source/gameengine/Ketsji/KX_SCA_DynamicActuator.h +++ b/source/gameengine/Ketsji/KX_DynamicActuator.h @@ -25,13 +25,13 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file KX_SCA_DynamicActuator.h +/** \file KX_DynamicActuator.h * \ingroup ketsji * \brief Add object to the game world on action of this actuator */ -#ifndef __KX_SCA_DYNAMICACTUATOR_H__ -#define __KX_SCA_DYNAMICACTUATOR_H__ +#ifndef __KX_DYNAMICACTUATOR_H__ +#define __KX_DYNAMICACTUATOR_H__ #include "SCA_IActuator.h" #include "SCA_PropertyActuator.h" @@ -39,7 +39,7 @@ #include "KX_GameObject.h" -class KX_SCA_DynamicActuator : public SCA_IActuator +class KX_DynamicActuator : public SCA_IActuator { Py_Header @@ -47,20 +47,20 @@ class KX_SCA_DynamicActuator : public SCA_IActuator short m_dyn_operation; float m_setmass; public: - KX_SCA_DynamicActuator( + KX_DynamicActuator( SCA_IObject* gameobj, short dyn_operation, float setmass ); - ~KX_SCA_DynamicActuator( + ~KX_DynamicActuator( ); - CValue* + EXP_Value* GetReplica( ); - virtual bool + virtual bool Update(); //Python Interface @@ -70,7 +70,9 @@ class KX_SCA_DynamicActuator : public SCA_IActuator KX_DYN_ENABLE_RIGID_BODY, KX_DYN_DISABLE_RIGID_BODY, KX_DYN_SET_MASS, + KX_DYN_RESTORE_PHYSICS, + KX_DYN_DISABLE_PHYSICS }; -}; +}; #endif diff --git a/source/gameengine/Ketsji/KX_EmptyObject.h b/source/gameengine/Ketsji/KX_EmptyObject.h index 80d8620894a3..86f28ad2ef0a 100644 --- a/source/gameengine/Ketsji/KX_EmptyObject.h +++ b/source/gameengine/Ketsji/KX_EmptyObject.h @@ -37,14 +37,9 @@ class KX_EmptyObject : public KX_GameObject { public: KX_EmptyObject(void* sgReplicationInfo,SG_Callbacks callbacks) : - KX_GameObject(sgReplicationInfo,callbacks) + KX_GameObject(sgReplicationInfo,callbacks) {}; virtual ~KX_EmptyObject(); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_EmptyObject") -#endif }; #endif /* __KX_EMPTYOBJECT_H__ */ diff --git a/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp b/source/gameengine/Ketsji/KX_EndObjectActuator.cpp similarity index 63% rename from source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp rename to source/gameengine/Ketsji/KX_EndObjectActuator.cpp index 34d45101a06f..6400f329acf3 100644 --- a/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_EndObjectActuator.cpp @@ -25,7 +25,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file gameengine/Ketsji/KX_SCA_EndObjectActuator.cpp +/** \file gameengine/Ketsji/KX_EndObjectActuator.cpp * \ingroup ketsji */ @@ -38,62 +38,70 @@ // \source\gameengine\GameLogic\SCA_EndObjectActuator.cpp // Please look here for revision history. -#include "SCA_IActuator.h" -#include "KX_SCA_EndObjectActuator.h" -#include "SCA_IScene.h" +#include "KX_EndObjectActuator.h" +#include "KX_Scene.h" +#include "KX_GameObject.h" -KX_SCA_EndObjectActuator::KX_SCA_EndObjectActuator(SCA_IObject *gameobj, - SCA_IScene* scene): - SCA_IActuator(gameobj, KX_ACT_END_OBJECT), - m_scene(scene) +KX_EndObjectActuator::KX_EndObjectActuator(KX_GameObject *gameobj, + KX_Scene *scene) : + SCA_IActuator(gameobj, KX_ACT_END_OBJECT), + m_scene(scene) { // intentionally empty } /* End of constructor */ -KX_SCA_EndObjectActuator::~KX_SCA_EndObjectActuator() +KX_EndObjectActuator::~KX_EndObjectActuator() { // there's nothing to be done here, really.... } /* end of destructor */ -bool KX_SCA_EndObjectActuator::Update() +bool KX_EndObjectActuator::Update() { // bool result = false; /*unused*/ bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); - if (bNegativeEvent) + if (bNegativeEvent) { return false; // do nothing on negative events - m_scene->DelayedRemoveObject(GetParent()); + } + m_scene->DelayedRemoveObject(static_cast(GetParent())); return false; } -CValue* KX_SCA_EndObjectActuator::GetReplica() +EXP_Value *KX_EndObjectActuator::GetReplica() { - KX_SCA_EndObjectActuator* replica = - new KX_SCA_EndObjectActuator(*this); - if (replica == NULL) return NULL; + KX_EndObjectActuator *replica = + new KX_EndObjectActuator(*this); + if (replica == nullptr) { + return nullptr; + } replica->ProcessReplica(); return replica; }; +void KX_EndObjectActuator::Replace_IScene(SCA_IScene *val) +{ + m_scene = static_cast(val); +} + #ifdef WITH_PYTHON /* ------------------------------------------------------------------------- */ /* Python functions : integration hooks */ /* ------------------------------------------------------------------------- */ -PyTypeObject KX_SCA_EndObjectActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "KX_SCA_EndObjectActuator", - sizeof(PyObjectPlus_Proxy), +PyTypeObject KX_EndObjectActuator::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_EndObjectActuator", + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -101,23 +109,23 @@ PyTypeObject KX_SCA_EndObjectActuator::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IActuator::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; -PyMethodDef KX_SCA_EndObjectActuator::Methods[] = { - {NULL,NULL} //Sentinel +PyMethodDef KX_EndObjectActuator::Methods[] = { + {nullptr, nullptr} //Sentinel }; -PyAttributeDef KX_SCA_EndObjectActuator::Attributes[] = { - { NULL } //Sentinel +PyAttributeDef KX_EndObjectActuator::Attributes[] = { + EXP_PYATTRIBUTE_NULL //Sentinel }; #endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.h b/source/gameengine/Ketsji/KX_EndObjectActuator.h similarity index 79% rename from source/gameengine/Ketsji/KX_SCA_EndObjectActuator.h rename to source/gameengine/Ketsji/KX_EndObjectActuator.h index ef7b56f4495f..5f8042696367 100644 --- a/source/gameengine/Ketsji/KX_SCA_EndObjectActuator.h +++ b/source/gameengine/Ketsji/KX_EndObjectActuator.h @@ -25,49 +25,48 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file KX_SCA_EndObjectActuator.h +/** \file KX_EndObjectActuator.h * \ingroup ketsji * \brief Add object to the game world on action of this actuator * \attention Previously existed as: source/gameengine/GameLogic/SCA_EndObjectActuator.h * Please look here for revision history. */ -#ifndef __KX_SCA_ENDOBJECTACTUATOR_H__ -#define __KX_SCA_ENDOBJECTACTUATOR_H__ +#ifndef __KX_ENDOBJECTACTUATOR_H__ +#define __KX_ENDOBJECTACTUATOR_H__ #include "SCA_IActuator.h" -class SCA_IScene; +class KX_Scene; +class KX_GameObject; -class KX_SCA_EndObjectActuator : public SCA_IActuator +class KX_EndObjectActuator : public SCA_IActuator { Py_Header - SCA_IScene* m_scene; + KX_Scene *m_scene; public: - KX_SCA_EndObjectActuator( - SCA_IObject* gameobj, - SCA_IScene* scene + KX_EndObjectActuator( + KX_GameObject *gameobj, + KX_Scene *scene ); - ~KX_SCA_EndObjectActuator(); + ~KX_EndObjectActuator(); - CValue* + EXP_Value* GetReplica( ); - virtual bool + virtual bool Update(); - virtual void Replace_IScene(SCA_IScene *val) - { - m_scene= val; - }; + virtual void Replace_IScene(SCA_IScene *val); /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - + }; /* end of class KX_EditObjectActuator : public SCA_PropertyActuator */ #endif + diff --git a/source/gameengine/Ketsji/KX_FontObject.cpp b/source/gameengine/Ketsji/KX_FontObject.cpp index a597b2981a2a..27a972b34b5f 100644 --- a/source/gameengine/Ketsji/KX_FontObject.cpp +++ b/source/gameengine/Ketsji/KX_FontObject.cpp @@ -33,10 +33,16 @@ #include "DNA_curve_types.h" #include "DNA_vfont_types.h" #include "KX_Scene.h" +#include "KX_Globals.h" #include "KX_PythonInit.h" +#include "KX_PyMath.h" #include "BLI_math.h" #include "EXP_StringValue.h" -#include "RAS_IRasterizer.h" +#include "RAS_Rasterizer.h" +#include "RAS_BucketManager.h" +#include "RAS_MaterialBucket.h" +#include "RAS_BoundingBox.h" +#include "RAS_TextUser.h" /* paths needed for font load */ #include "BLI_blenlib.h" @@ -49,57 +55,53 @@ extern "C" { #include "BLF_api.h" } +#include "CM_Message.h" + #define BGE_FONT_RES 100 /* proptotype */ int GetFontId(VFont *font); -static std::vector split_string(STR_String str) +static std::vector split_string(std::string str) { - std::vector text = std::vector(); - - /* Split the string upon new lines */ - int begin=0, end=0; - while (end < str.Length()) - { - if (str.GetAt(end) == '\n') - { - text.push_back(str.Mid(begin, end-begin)); - begin = end+1; + std::vector text = std::vector(); + + // Split the string upon new lines + int begin = 0, end = 0; + while (end < str.size()) { + if (str[end] == '\n') { + text.push_back(str.substr(begin, end - begin)); + begin = end + 1; } end++; } - //Now grab the last line - text.push_back(str.Mid(begin, end-begin)); + // Now grab the last line + text.push_back(str.substr(begin, end - begin)); return text; } -KX_FontObject::KX_FontObject(void* sgReplicationInfo, +KX_FontObject::KX_FontObject(void *sgReplicationInfo, SG_Callbacks callbacks, - RAS_IRasterizer* rasterizer, - Object *ob, - bool do_color_management): - KX_GameObject(sgReplicationInfo, callbacks), + RAS_Rasterizer *rasterizer, + RAS_BoundingBoxManager *boundingBoxManager, + Object *ob) + :KX_GameObject(sgReplicationInfo, callbacks), m_object(ob), m_dpi(72), - m_resolution(1.f), - m_rasterizer(rasterizer), - m_do_color_management(do_color_management) + m_resolution(1.0f), + m_rasterizer(rasterizer) { Curve *text = static_cast (ob->data); - m_text = split_string(text->str); m_fsize = text->fsize; m_line_spacing = text->linedist; - m_offset = MT_Vector3(text->xof, text->yof, 0); + m_offset = mt::vec3(text->xof, text->yof, 0.0f); m_fontid = GetFontId(text->vfont); - /* initialize the color with the object color and store it in the KX_Object class - * This is a workaround waiting for the fix: - * [#25487] BGE: Object Color only works when it has a keyed frame */ - copy_v4_v4(m_color, (const float*) ob->col); - this->SetObjectColor((const MT_Vector4&) m_color); + m_boundingBox = new RAS_BoundingBox(boundingBoxManager); + + SetText(text->str); } KX_FontObject::~KX_FontObject() @@ -108,9 +110,9 @@ KX_FontObject::~KX_FontObject() //it's handled in KX_Scene::NewRemoveObject } -CValue* KX_FontObject::GetReplica() +EXP_Value *KX_FontObject::GetReplica() { - KX_FontObject* replica = new KX_FontObject(*this); + KX_FontObject *replica = new KX_FontObject(*this); replica->ProcessReplica(); return replica; } @@ -118,102 +120,162 @@ CValue* KX_FontObject::GetReplica() void KX_FontObject::ProcessReplica() { KX_GameObject::ProcessReplica(); + + m_boundingBox = m_boundingBox->GetReplica(); } -int GetFontId(VFont *vfont) +void KX_FontObject::AddMeshUser() { - PackedFile *packedfile=NULL; - int fontid = -1; + m_meshUser = new RAS_TextUser(&m_clientInfo, m_boundingBox); - if (vfont->packedfile) { - packedfile= vfont->packedfile; - fontid= BLF_load_mem(vfont->name, (unsigned char*)packedfile->data, packedfile->size); + RAS_BucketManager *bucketManager = GetScene()->GetBucketManager(); + RAS_DisplayArrayBucket *arrayBucket = bucketManager->GetTextDisplayArrayBucket(); - if (fontid == -1) { - printf("ERROR: packed font \"%s\" could not be loaded.\n", vfont->name); - fontid = BLF_load("default"); - } - return fontid; - } + m_meshUser->SetMatrix(mt::mat4::FromAffineTransform(NodeGetWorldTransform())); + m_meshUser->SetFrontFace(!IsNegativeScaling()); - /* once we have packed working we can load the builtin font */ - const char *filepath = vfont->name; - if (BKE_vfont_is_builtin(vfont)) { - fontid = BLF_load("default"); + m_meshUser->NewMeshSlot(arrayBucket); +} - /* XXX the following code is supposed to work (after you add get_builtin_packedfile to BKE_font.h ) - * unfortunately it's crashing on blf_glyph.c:173 because gc->glyph_width_max is 0 - */ - // packedfile=get_builtin_packedfile(); - // fontid= BLF_load_mem(font->name, (unsigned char*)packedfile->data, packedfile->size); - // return fontid; +void KX_FontObject::UpdateBuckets() +{ + RAS_TextUser *textUser = static_cast(m_meshUser); - return BLF_load("default"); + // Update datas and add mesh slot to be rendered only if the object is not culled. + if (m_sgNode->IsDirty(SG_Node::DIRTY_RENDER)) { + m_meshUser->SetMatrix(mt::mat4::FromAffineTransform(NodeGetWorldTransform())); + m_meshUser->SetFrontFace(!IsNegativeScaling()); + m_sgNode->ClearDirty(SG_Node::DIRTY_RENDER); } - /* convert from absolute to relative */ - char expanded[256]; // font names can be bigger than FILE_MAX (240) - BLI_strncpy(expanded, filepath, 256); - BLI_path_abs(expanded, G.main->name); + // HARDCODED MULTIPLICATION FACTOR - this will affect the render resolution directly + const float RES = BGE_FONT_RES * m_resolution; - fontid = BLF_load(expanded); + const float size = fabs(m_fsize * NodeGetWorldScaling()[0] * RES); + const float aspect = m_fsize / size; - /* fallback */ - if (fontid == -1) - fontid = BLF_load("default"); + // Account for offset + mt::vec3 offset = NodeGetWorldOrientation() * m_offset * NodeGetWorldScaling(); + // Orient the spacing vector + mt::vec3 spacing = NodeGetWorldOrientation() * mt::vec3(0.0f, m_fsize * m_line_spacing, 0.0f) * NodeGetWorldScaling()[1]; + + textUser->SetLayer(m_layer); + textUser->SetColor(m_objectColor); + textUser->SetFontId(m_fontid); + textUser->SetSize(size); + textUser->SetDpi(m_dpi); + textUser->SetAspect(aspect); + textUser->SetOffset(offset); + textUser->SetSpacing(spacing); + textUser->SetTexts(m_texts); + textUser->ActivateMeshSlots(); +} - return fontid; +void KX_FontObject::SetText(const std::string& text) +{ + m_text = text; + m_texts = split_string(text); + + mt::vec2 min; + mt::vec2 max; + GetTextAabb(min, max); + m_boundingBox->SetAabb(mt::vec3(min.x, min.y, 0.0f), mt::vec3(max.x, max.y, 0.0f)); } -void KX_FontObject::DrawFontText() +void KX_FontObject::UpdateTextFromProperty() { - /* Allow for some logic brick control */ - if (this->GetProperty("Text")) - m_text = split_string(this->GetProperty("Text")->GetText()); + // Allow for some logic brick control + EXP_Value *prop = GetProperty("Text"); + if (prop && prop->GetText() != m_text) { + SetText(prop->GetText()); + } +} - /* only draws the text if visible */ - if (this->GetVisible() == 0) return; +const mt::vec2 KX_FontObject::GetTextDimensions() +{ + mt::vec2 min; + mt::vec2 max; + GetTextAabb(min, max); - /* update the animated color */ - this->GetObjectColor().getValue(m_color); + // Scale the width and height by the object's scale + const mt::vec3& scale = NodeGetLocalScaling(); - /* Font Objects don't use the glsl shader, this color management code is copied from gpu_shader_material.glsl */ - float color[4]; - if (m_do_color_management) { - linearrgb_to_srgb_v4(color, m_color); - } - else { - copy_v4_v4(color, m_color); - } + return mt::vec2((max.x - min.x) * fabs(scale.x), (max.y - min.y) * fabs(scale.y)); +} - /* HARDCODED MULTIPLICATION FACTOR - this will affect the render resolution directly */ +void KX_FontObject::GetTextAabb(mt::vec2& min, mt::vec2& max) +{ const float RES = BGE_FONT_RES * m_resolution; - const float size = m_fsize * this->NodeGetWorldScaling()[0] * RES; + const float size = m_fsize * RES; const float aspect = m_fsize / size; + const float lineSpacing = m_line_spacing / aspect; + + BLF_size(m_fontid, size, m_dpi); - /* Get a working copy of the OpenGLMatrix to use */ - float *mat = GetOpenGLMatrix(); - - /* Account for offset */ - MT_Vector3 offset = this->NodeGetWorldOrientation() * m_offset * this->NodeGetWorldScaling(); - mat[12] += offset[0]; mat[13] += offset[1]; mat[14] += offset[2]; - - /* Orient the spacing vector */ - MT_Vector3 spacing = MT_Vector3(0.0f, m_fsize*m_line_spacing, 0.0f); - spacing = this->NodeGetWorldOrientation() * spacing * this->NodeGetWorldScaling()[1]; - - /* Draw each line, taking spacing into consideration */ - for (int i=0; ipackedfile) { + packedfile = vfont->packedfile; + fontid = BLF_load_mem(vfont->name, (unsigned char *)packedfile->data, packedfile->size); + + if (fontid == -1) { + CM_Error("packed font \"" << vfont->name << "\" could not be loaded"); + fontid = BLF_load("default"); } - m_rasterizer->RenderText3D(m_fontid, m_text[i], int(size), m_dpi, color, mat, aspect); + return fontid; + } + + // once we have packed working we can load the builtin font + if (BKE_vfont_is_builtin(vfont)) { + fontid = BLF_load("default"); + return fontid; } + + // convert from relative to absolute + char expanded[FILE_MAX]; + BLI_strncpy(expanded, vfont->name, FILE_MAX); + + char libpath[FILE_MAX]; + // Use library path if available and ensure it is absolute. + if (vfont->id.lib) { + BLI_strncpy(libpath, vfont->id.lib->name, FILE_MAX); + BLI_path_abs(libpath, KX_GetMainPath().c_str()); + } + else { + BLI_strncpy(libpath, KX_GetMainPath().c_str(), FILE_MAX); + } + BLI_path_abs(expanded, libpath); + + fontid = BLF_load(expanded); + + // fallback + if (fontid == -1) { + fontid = BLF_load("default"); + CM_Warning("failed loading font \"" << vfont->name << "\""); + } + + return fontid; } #ifdef WITH_PYTHON @@ -223,9 +285,9 @@ void KX_FontObject::DrawFontText() /* ------------------------------------------------------------------------- */ PyTypeObject KX_FontObject::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_FontObject", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -236,65 +298,65 @@ PyTypeObject KX_FontObject::Type = { 0, &KX_GameObject::Sequence, &KX_GameObject::Mapping, - 0,0,0, - NULL, - NULL, + 0, 0, 0, + nullptr, + nullptr, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &KX_GameObject::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_FontObject::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_FontObject::Attributes[] = { - //KX_PYATTRIBUTE_STRING_RW("text", 0, 280, false, KX_FontObject, m_text[0]), //arbitrary limit. 280 = 140 unicode chars in unicode - KX_PYATTRIBUTE_RW_FUNCTION("text", KX_FontObject, pyattr_get_text, pyattr_set_text), - KX_PYATTRIBUTE_FLOAT_RW("size", 0.0001f, 10000.0f, KX_FontObject, m_fsize), - KX_PYATTRIBUTE_FLOAT_RW("resolution", 0.0001f, 10000.0f, KX_FontObject, m_resolution), - /* KX_PYATTRIBUTE_INT_RW("dpi", 0, 10000, false, KX_FontObject, m_dpi), */// no real need for expose this I think - { NULL } //Sentinel + EXP_PYATTRIBUTE_RW_FUNCTION("text", KX_FontObject, pyattr_get_text, pyattr_set_text), + EXP_PYATTRIBUTE_RO_FUNCTION("dimensions", KX_FontObject, pyattr_get_dimensions), + EXP_PYATTRIBUTE_FLOAT_RW("size", 0.0001f, 40.0f, KX_FontObject, m_fsize), + EXP_PYATTRIBUTE_FLOAT_RW("resolution", 0.1f, 50.0f, KX_FontObject, m_resolution), + /* EXP_PYATTRIBUTE_INT_RW("dpi", 0, 10000, false, KX_FontObject, m_dpi), */// no real need for expose this I think + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *KX_FontObject::pyattr_get_text(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_FontObject::pyattr_get_text(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_FontObject* self = static_cast(self_v); - STR_String str = STR_String(); - for (int i=0; im_text.size(); ++i) - { - if (i!=0) - str += '\n'; - str += self->m_text[i]; - } - return PyUnicode_From_STR_String(str); + KX_FontObject *self = static_cast(self_v); + return PyUnicode_FromStdString(self->m_text); } -int KX_FontObject::pyattr_set_text(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_FontObject::pyattr_set_text(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_FontObject* self = static_cast(self_v); - if (!PyUnicode_Check(value)) + KX_FontObject *self = static_cast(self_v); + if (!PyUnicode_Check(value)) { return PY_SET_ATTR_FAIL; + } const char *chars = _PyUnicode_AsString(value); /* Allow for some logic brick control */ - CValue* tprop = self->GetProperty("Text"); + EXP_Value *tprop = self->GetProperty("Text"); if (tprop) { - CValue *newstringprop = new CStringValue(STR_String(chars), "Text"); + EXP_Value *newstringprop = new EXP_StringValue(std::string(chars), "Text"); self->SetProperty("Text", newstringprop); newstringprop->Release(); } else { - self->m_text = split_string(STR_String(chars)); + self->SetText(std::string(chars)); } return PY_SET_ATTR_SUCCESS; } +PyObject *KX_FontObject::pyattr_get_dimensions(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_FontObject *self = static_cast(self_v); + return PyObjectFrom(self->GetTextDimensions()); +} + #endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_FontObject.h b/source/gameengine/Ketsji/KX_FontObject.h index 27f642f0f9b1..5ac5581589e3 100644 --- a/source/gameengine/Ketsji/KX_FontObject.h +++ b/source/gameengine/Ketsji/KX_FontObject.h @@ -31,51 +31,68 @@ #ifndef __KX_FONTOBJECT_H__ #define __KX_FONTOBJECT_H__ + #include "KX_GameObject.h" +class RAS_BoundingBox; + class KX_FontObject : public KX_GameObject { public: Py_Header - KX_FontObject(void* sgReplicationInfo, + KX_FontObject(void *sgReplicationInfo, SG_Callbacks callbacks, - RAS_IRasterizer* rasterizer, - Object *ob, - bool do_color_management); + RAS_Rasterizer *rasterizer, + RAS_BoundingBoxManager *boundingBoxManager, + Object *ob); virtual ~KX_FontObject(); - void DrawFontText(); + virtual void AddMeshUser(); + virtual void UpdateBuckets(); /** - * Inherited from CValue -- return a new copy of this + * Inherited from EXP_Value -- return a new copy of this * instance allocated on the heap. Ownership of the new * object belongs with the caller. */ - virtual CValue* GetReplica(); + virtual EXP_Value *GetReplica(); virtual void ProcessReplica(); - virtual int GetGameObjectType() { return OBJ_TEXT; } + virtual int GetGameObjectType() const + { + return OBJ_TEXT; + } + + // Update text and bounding box. + void SetText(const std::string& text); + /// Update text from property. + void UpdateTextFromProperty(); + /// Return text dimensions in blender unit. + const mt::vec2 GetTextDimensions(); protected: - std::vector m_text; - Object* m_object; - int m_fontid; - int m_dpi; - float m_fsize; - float m_resolution; - float m_color[4]; - float m_line_spacing; - MT_Vector3 m_offset; + std::string m_text; + std::vector m_texts; + Object *m_object; + int m_fontid; + int m_dpi; + float m_fsize; + float m_resolution; + float m_line_spacing; + mt::vec3 m_offset; - class RAS_IRasterizer* m_rasterizer; //needed for drawing routine + /// Text bounding box for mesh/text user. + RAS_BoundingBox *m_boundingBox; + /// needed for drawing routine + class RAS_Rasterizer *m_rasterizer; - bool m_do_color_management; + void GetTextAabb(mt::vec2& min, mt::vec2& max); #ifdef WITH_PYTHON - static PyObject* pyattr_get_text(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_text(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_text(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_text(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_dimensions(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); #endif - }; #endif /* __KX_FONTOBJECT_H__ */ diff --git a/source/gameengine/Ketsji/KX_GameActuator.cpp b/source/gameengine/Ketsji/KX_GameActuator.cpp index 8bfe69667643..3c189cb1f852 100644 --- a/source/gameengine/Ketsji/KX_GameActuator.cpp +++ b/source/gameengine/Ketsji/KX_GameActuator.cpp @@ -33,8 +33,6 @@ */ -#include - #include "SCA_IActuator.h" #include "KX_GameActuator.h" //#include @@ -43,20 +41,19 @@ #include "KX_PythonInit.h" /* for config load/saving */ #include "RAS_ICanvas.h" -#include -#include +#include "CM_Message.h" /* ------------------------------------------------------------------------- */ /* Native functions */ /* ------------------------------------------------------------------------- */ KX_GameActuator::KX_GameActuator(SCA_IObject *gameobj, - int mode, - const STR_String& filename, - const STR_String& loadinganimationname, - SCA_IScene* scene, - KX_KetsjiEngine* ketsjiengine) - : SCA_IActuator(gameobj, KX_ACT_GAME) + int mode, + const std::string& filename, + const std::string& loadinganimationname, + SCA_IScene *scene, + KX_KetsjiEngine *ketsjiengine) + :SCA_IActuator(gameobj, KX_ACT_GAME) { m_mode = mode; m_filename = filename; @@ -74,9 +71,9 @@ KX_GameActuator::~KX_GameActuator() -CValue* KX_GameActuator::GetReplica() +EXP_Value *KX_GameActuator::GetReplica() { - KX_GameActuator* replica = new KX_GameActuator(*this); + KX_GameActuator *replica = new KX_GameActuator(*this); replica->ProcessReplica(); return replica; @@ -90,117 +87,54 @@ bool KX_GameActuator::Update() bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); - if (bNegativeEvent) + if (bNegativeEvent) { return false; // do nothing on negative events - switch (m_mode) - { - case KX_GAME_LOAD: - case KX_GAME_START: + } + switch (m_mode) { + case KX_GAME_LOAD: + case KX_GAME_START: { - if (m_ketsjiengine) - { - STR_String exitstring = "start other game"; - m_ketsjiengine->RequestExit(KX_EXIT_REQUEST_START_OTHER_GAME); - m_ketsjiengine->SetNameNextGame(m_filename); + if (m_ketsjiengine) { + std::string exitstring = "start other game"; + m_ketsjiengine->RequestExit(KX_ExitInfo::START_OTHER_GAME, m_filename); m_scene->AddDebugProperty((this)->GetParent(), exitstring); } break; } - case KX_GAME_RESTART: + case KX_GAME_RESTART: { - if (m_ketsjiengine) - { - STR_String exitstring = "restarting game"; - m_ketsjiengine->RequestExit(KX_EXIT_REQUEST_RESTART_GAME); - m_ketsjiengine->SetNameNextGame(m_filename); + if (m_ketsjiengine) { + std::string exitstring = "restarting game"; + m_ketsjiengine->RequestExit(KX_ExitInfo::RESTART_GAME, m_filename); m_scene->AddDebugProperty((this)->GetParent(), exitstring); } break; } - case KX_GAME_QUIT: + case KX_GAME_QUIT: { - if (m_ketsjiengine) - { - STR_String exitstring = "quiting game"; - m_ketsjiengine->RequestExit(KX_EXIT_REQUEST_QUIT_GAME); + if (m_ketsjiengine) { + std::string exitstring = "quiting game"; + m_ketsjiengine->RequestExit(KX_ExitInfo::QUIT_GAME); m_scene->AddDebugProperty((this)->GetParent(), exitstring); } break; } - case KX_GAME_SAVECFG: + case KX_GAME_SAVECFG: { #ifdef WITH_PYTHON - if (m_ketsjiengine) - { - char mashal_path[512]; - char *marshal_buffer = NULL; - unsigned int marshal_length; - FILE *fp = NULL; - - pathGamePythonConfig(mashal_path); - marshal_length = saveGamePythonConfig(&marshal_buffer); - - if (marshal_length && marshal_buffer) { - fp = fopen(mashal_path, "wb"); - if (fp) { - if (fwrite(marshal_buffer, 1, marshal_length, fp) != marshal_length) { - printf("Warning: could not write marshal data\n"); - } - fclose(fp); - } else { - printf("Warning: could not open marshal file\n"); - } - } else { - printf("Warning: could not create marshal buffer\n"); - } - if (marshal_buffer) - delete [] marshal_buffer; + if (m_ketsjiengine) { + saveGamePythonConfig(); } break; #endif // WITH_PYTHON } - case KX_GAME_LOADCFG: + case KX_GAME_LOADCFG: { #ifdef WITH_PYTHON - if (m_ketsjiengine) - { - char mashal_path[512]; - char *marshal_buffer; - int marshal_length; - FILE *fp = NULL; - int result; - - pathGamePythonConfig(mashal_path); - - fp = fopen(mashal_path, "rb"); - if (fp) { - // obtain file size: - fseek (fp , 0 , SEEK_END); - marshal_length = ftell(fp); - if (marshal_length == -1) { - printf("warning: could not read position of '%s'\n", mashal_path); - fclose(fp); - break; - } - rewind(fp); - - marshal_buffer = (char*) malloc (sizeof(char)*marshal_length); - - result = fread (marshal_buffer, 1, marshal_length, fp); - - if (result == marshal_length) { - loadGamePythonConfig(marshal_buffer, marshal_length); - } else { - printf("warning: could not read all of '%s'\n", mashal_path); - } - - free(marshal_buffer); - fclose(fp); - } else { - printf("warning: could not open '%s'\n", mashal_path); - } + if (m_ketsjiengine) { + loadGamePythonConfig(); } break; #endif // WITH_PYTHON @@ -212,12 +146,12 @@ bool KX_GameActuator::Update() canvas->MakeScreenShot(m_filename); } else { - printf("KX_GAME_SCREENSHOT error: Rasterizer not available"); + CM_LogicBrickError(this, "KX_GAME_SCREENSHOT Rasterizer not available"); } break; } - default: - ; /* do nothing? this is an internal error !!! */ + default: + ; /* do nothing? this is an internal error !!! */ } return false; @@ -232,9 +166,9 @@ bool KX_GameActuator::Update() /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_GameActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_GameActuator", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -242,26 +176,26 @@ PyTypeObject KX_GameActuator::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IActuator::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_GameActuator::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_GameActuator::Attributes[] = { - KX_PYATTRIBUTE_STRING_RW("fileName",0,100,false,KX_GameActuator,m_filename), - KX_PYATTRIBUTE_INT_RW("mode", KX_GAME_NODEF+1, KX_GAME_MAX-1, true, KX_GameActuator, m_mode), - { NULL } //Sentinel + EXP_PYATTRIBUTE_STRING_RW("fileName", 0, 100, false, KX_GameActuator, m_filename), + EXP_PYATTRIBUTE_INT_RW("mode", KX_GAME_NODEF + 1, KX_GAME_MAX - 1, true, KX_GameActuator, m_mode), + EXP_PYATTRIBUTE_NULL //Sentinel }; #endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_GameActuator.h b/source/gameengine/Ketsji/KX_GameActuator.h index 63170c5b2454..472aff22b9ee 100644 --- a/source/gameengine/Ketsji/KX_GameActuator.h +++ b/source/gameengine/Ketsji/KX_GameActuator.h @@ -44,8 +44,8 @@ class KX_GameActuator : public SCA_IActuator protected: int m_mode; bool m_restart; - STR_String m_filename; - STR_String m_loadinganimationname; + std::string m_filename; + std::string m_loadinganimationname; class SCA_IScene* m_scene; class KX_KetsjiEngine* m_ketsjiengine; @@ -66,16 +66,16 @@ class KX_GameActuator : public SCA_IActuator KX_GameActuator(SCA_IObject* gameobj, int mode, - const STR_String& filename, - const STR_String& loadinganimationname, + const std::string& filename, + const std::string& loadinganimationname, SCA_IScene* scene, KX_KetsjiEngine* ketsjiEngine); virtual ~KX_GameActuator(); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); virtual bool Update(); - + virtual void Replace_IScene(SCA_IScene *val) { m_scene= val; @@ -84,7 +84,8 @@ class KX_GameActuator : public SCA_IActuator /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - + }; /* end of class KX_GameActuator */ #endif + diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index a4dc5f5c4a20..971a3a96398c 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -31,39 +31,50 @@ */ #ifdef _MSC_VER - /* This warning tells us about truncation of __long__ stl-generated names. - * It can occasionally cause DevStudio to have internal compiler warnings. */ +/* 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 -#include "RAS_IPolygonMaterial.h" -#include "KX_BlenderMaterial.h" #include "KX_GameObject.h" +#include "KX_PythonComponent.h" #include "KX_Camera.h" // only for their ::Type -#include "KX_Light.h" // only for their ::Type +#include "KX_LightObject.h" // only for their ::Type #include "KX_FontObject.h" // only for their ::Type -#include "RAS_MeshObject.h" +#include "RAS_Mesh.h" +#include "RAS_MeshUser.h" +#include "RAS_BoundingBoxManager.h" +#include "RAS_Deformer.h" #include "KX_NavMeshObject.h" -#include "KX_MeshProxy.h" +#include "KX_Mesh.h" #include "KX_PolyProxy.h" -#include // printf +#include "KX_BlenderMaterial.h" #include "SG_Controller.h" #include "PHY_IGraphicController.h" #include "SG_Node.h" +#include "SG_Familly.h" #include "KX_ClientObjectInfo.h" #include "RAS_BucketManager.h" #include "KX_RayCast.h" -#include "KX_PythonInit.h" +#include "KX_Globals.h" #include "KX_PyMath.h" #include "SCA_IActuator.h" #include "SCA_ISensor.h" #include "SCA_IController.h" -#include "NG_NetworkScene.h" //Needed for sendMessage() +#include "KX_NetworkMessageScene.h" //Needed for sendMessage() #include "KX_ObstacleSimulation.h" #include "KX_Scene.h" +#include "KX_LodLevel.h" +#include "KX_LodManager.h" +#include "KX_BoundingBox.h" +#include "SG_CullingNode.h" +#include "KX_BatchGroup.h" +#include "KX_CollisionContactPoints.h" #include "BKE_object.h" +#include "BL_BlenderDataConversion.h" // For BL_ConvertDeformer. +#include "BL_ConvertObjectInfo.h" #include "BL_ActionManager.h" #include "BL_Action.h" @@ -76,387 +87,400 @@ # include "python_utildefines.h" #endif +// Component stuff +#include "DNA_python_component_types.h" + // This file defines relationships between parents and children // in the game engine. -#include "KX_SG_NodeRelationships.h" +#include "KX_NodeRelationships.h" #include "BLI_math.h" -static MT_Point3 dummy_point= MT_Point3(0.0f, 0.0f, 0.0f); -static MT_Vector3 dummy_scaling = MT_Vector3(1.0f, 1.0f, 1.0f); -static MT_Matrix3x3 dummy_orientation = MT_Matrix3x3(1.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 1.0f); - -KX_GameObject::KX_GameObject( - void* sgReplicationInfo, - SG_Callbacks callbacks) - : SCA_IObject(), - m_bDyna(false), - m_layer(0), - m_currentLodLevel(0), - m_previousLodLevel(0), - m_pBlenderObject(NULL), - m_pBlenderGroupObject(NULL), - m_bUseObjectColor(false), - m_bIsNegativeScaling(false), - m_objectColor(1.0f, 1.0f, 1.0f, 1.0f), - m_bVisible(true), - m_bCulled(true), - m_bOccluder(false), - m_pPhysicsController(NULL), - m_pGraphicController(NULL), - m_pObstacleSimulation(NULL), - m_pInstanceObjects(NULL), - m_pDupliGroupObject(NULL), - m_actionManager(NULL), - m_bRecordAnimation(false), - m_isDeformable(false) - +#include "CM_Message.h" + +KX_GameObject::ActivityCullingInfo::ActivityCullingInfo() + :m_flags(ACTIVITY_NONE), + m_physicsRadius(0.0f), + m_logicRadius(0.0f) +{ +} + +KX_GameObject::KX_GameObject(void *sgReplicationInfo, + SG_Callbacks callbacks) + :m_clientInfo(this, KX_ClientObjectInfo::ACTOR), + m_layer(0), + m_passIndex(0), + m_lodManager(nullptr), + m_currentLodLevel(0), + m_meshUser(nullptr), + m_convertInfo(nullptr), + m_objectColor(mt::one4), + m_bVisible(true), + m_bOccluder(false), + m_autoUpdateBounds(false), + m_physicsController(nullptr), + m_graphicController(nullptr), + m_sgNode(new SG_Node(this, sgReplicationInfo, callbacks)), + m_components(nullptr), + m_instanceObjects(nullptr), + m_dupliGroupObject(nullptr), + m_actionManager(nullptr) #ifdef WITH_PYTHON - , m_attr_dict(NULL), - m_collisionCallbacks(NULL) + , m_attr_dict(nullptr), + m_collisionCallbacks(nullptr) #endif { - m_ignore_activity_culling = false; - m_pClient_info = new KX_ClientObjectInfo(this, KX_ClientObjectInfo::ACTOR); - m_pSGNode = new SG_Node(this,sgReplicationInfo,callbacks); - // define the relationship between this node and it's parent. + KX_NormalParentRelation *parent_relation = new KX_NormalParentRelation(); + m_sgNode->SetParentRelation(parent_relation); +} + +KX_GameObject::KX_GameObject(const KX_GameObject& other) + :SCA_IObject(other), + m_clientInfo(this, other.m_clientInfo.m_type), + m_name(other.m_name), + m_layer(other.m_layer), + m_passIndex(other.m_passIndex), + m_meshes(other.m_meshes), + m_lodManager(other.m_lodManager), + m_currentLodLevel(0), + m_meshUser(nullptr), + m_convertInfo(other.m_convertInfo), + m_objectColor(other.m_objectColor), + m_bVisible(other.m_bVisible), + m_bOccluder(other.m_bOccluder), + m_activityCullingInfo(other.m_activityCullingInfo), + m_autoUpdateBounds(other.m_autoUpdateBounds), + m_physicsController(nullptr), + m_graphicController(nullptr), + m_sgNode(nullptr), + m_components(nullptr), + m_instanceObjects(nullptr), + m_dupliGroupObject(nullptr), + m_actionManager(nullptr) +#ifdef WITH_PYTHON + , m_attr_dict(other.m_attr_dict), + m_collisionCallbacks(other.m_collisionCallbacks) +#endif // WITH_PYTHON +{ + if (m_lodManager) { + m_lodManager->AddRef(); + } - KX_NormalParentRelation * parent_relation = - KX_NormalParentRelation::New(); - m_pSGNode->SetParentRelation(parent_relation); -}; +#ifdef WITH_PYTHON + if (m_attr_dict) { + m_attr_dict = PyDict_Copy(m_attr_dict); + } + + Py_XINCREF(m_collisionCallbacks); + if (other.m_components) { + m_components = static_cast *>(other.m_components->GetReplica()); + for (KX_PythonComponent *component : m_components) { + component->SetGameObject(this); + } + } +#endif // WITH_PYTHON +} KX_GameObject::~KX_GameObject() { #ifdef WITH_PYTHON if (m_attr_dict) { PyDict_Clear(m_attr_dict); /* in case of circular refs or other weird cases */ - /* Py_CLEAR: Py_DECREF's and NULL's */ + /* Py_CLEAR: Py_DECREF's and nullptr's */ Py_CLEAR(m_attr_dict); } // Unregister collision callbacks - // Do this before we start freeing physics information like m_pClient_info + // Do this before we start freeing physics information like m_clientInfo if (m_collisionCallbacks) { UnregisterCollisionCallbacks(); Py_CLEAR(m_collisionCallbacks); } -#endif // WITH_PYTHON - RemoveMeshes(); - - // is this delete somewhere ? - //if (m_sumoObj) - // delete m_sumoObj; - delete m_pClient_info; - //if (m_pSGNode) - // delete m_pSGNode; - if (m_pSGNode) - { - // must go through controllers and make sure they will not use us anymore - // This is important for KX_BulletPhysicsControllers that unregister themselves - // from the object when they are deleted. - SGControllerList::iterator contit; - SGControllerList& controllers = m_pSGNode->GetSGControllerList(); - for (contit = controllers.begin();contit!=controllers.end();++contit) - { - (*contit)->ClearObject(); - } - m_pSGNode->SetSGClientObject(NULL); - - /* m_pSGNode is freed in KX_Scene::RemoveNodeDestructObject */ - } - if (m_pGraphicController) - { - delete m_pGraphicController; - } - - if (m_pPhysicsController) - { - delete m_pPhysicsController; + if (m_components) { + m_components->Release(); } +#endif // WITH_PYTHON - if (m_pObstacleSimulation) - { - m_pObstacleSimulation->DestroyObstacleForObj(this); - } + RemoveMeshes(); - if (m_actionManager) - { - delete m_actionManager; + if (m_dupliGroupObject) { + m_dupliGroupObject->Release(); } - if (m_pDupliGroupObject) - { - m_pDupliGroupObject->Release(); + if (m_instanceObjects) { + m_instanceObjects->Release(); } - - if (m_pInstanceObjects) - { - m_pInstanceObjects->Release(); + if (m_lodManager) { + m_lodManager->Release(); } } -KX_GameObject* KX_GameObject::GetClientObject(KX_ClientObjectInfo *info) +KX_GameObject *KX_GameObject::GetClientObject(KX_ClientObjectInfo *info) { - if (!info) - return NULL; + if (!info) { + return nullptr; + } return info->m_gameobject; } -CValue* KX_GameObject:: Calc(VALUE_OPERATOR op, CValue *val) +std::string KX_GameObject::GetName() { - return NULL; + return m_name; } - - -CValue* KX_GameObject::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val) +/* Set the name of the value */ +void KX_GameObject::SetName(const std::string& name) { - return NULL; + m_name = name; } - - -const STR_String & KX_GameObject::GetText() +RAS_Deformer *KX_GameObject::GetDeformer() { - return m_text; + return (m_meshUser) ? m_meshUser->GetDeformer() : nullptr; } - - -double KX_GameObject::GetNumber() +PHY_IPhysicsController *KX_GameObject::GetPhysicsController() { - return 0; + return m_physicsController.get(); } - - -STR_String& KX_GameObject::GetName() +void KX_GameObject::SetPhysicsController(PHY_IPhysicsController *physicscontroller) { - return m_name; + m_physicsController.reset(physicscontroller); } - -/* Set the name of the value */ -void KX_GameObject::SetName(const char *name) +PHY_IGraphicController *KX_GameObject::GetGraphicController() { - m_name = name; + return m_graphicController.get(); } -PHY_IPhysicsController* KX_GameObject::GetPhysicsController() +void KX_GameObject::SetGraphicController(PHY_IGraphicController *graphiccontroller) { - return m_pPhysicsController; + m_graphicController.reset(graphiccontroller); } -KX_GameObject* KX_GameObject::GetDupliGroupObject() +KX_GameObject *KX_GameObject::GetDupliGroupObject() { - return m_pDupliGroupObject; + return m_dupliGroupObject; } -CListValue* KX_GameObject::GetInstanceObjects() +EXP_ListValue *KX_GameObject::GetInstanceObjects() { - return m_pInstanceObjects; + return m_instanceObjects; } -void KX_GameObject::AddInstanceObjects(KX_GameObject* obj) +void KX_GameObject::AddInstanceObjects(KX_GameObject *obj) { - if (!m_pInstanceObjects) - m_pInstanceObjects = new CListValue(); + if (!m_instanceObjects) { + m_instanceObjects = new EXP_ListValue(); + } obj->AddRef(); - m_pInstanceObjects->Add(obj); + m_instanceObjects->Add(obj); } -void KX_GameObject::RemoveInstanceObject(KX_GameObject* obj) +void KX_GameObject::RemoveInstanceObject(KX_GameObject *obj) { - assert(m_pInstanceObjects); - m_pInstanceObjects->RemoveValue(obj); + BLI_assert(m_instanceObjects); + m_instanceObjects->RemoveValue(obj); obj->Release(); } void KX_GameObject::RemoveDupliGroupObject() { - if (m_pDupliGroupObject) { - m_pDupliGroupObject->Release(); - m_pDupliGroupObject = NULL; + if (m_dupliGroupObject) { + m_dupliGroupObject->Release(); + m_dupliGroupObject = nullptr; } } -void KX_GameObject::SetDupliGroupObject(KX_GameObject* obj) +void KX_GameObject::SetDupliGroupObject(KX_GameObject *obj) { obj->AddRef(); - m_pDupliGroupObject = obj; + m_dupliGroupObject = obj; } -void KX_GameObject::AddConstraint(bRigidBodyJointConstraint *cons) +const std::vector& KX_GameObject::GetConstraints() { - m_constraints.push_back(cons); + return m_convertInfo->m_constraints; } -std::vector KX_GameObject::GetConstraints() +void KX_GameObject::ReplicateConstraints(PHY_IPhysicsEnvironment *physEnv, const std::vector& constobj) { - return m_constraints; -} + if (!m_physicsController || m_convertInfo->m_constraints.empty()) { + return; + } -void KX_GameObject::ClearConstraints() -{ - m_constraints.clear(); + // Object could have some constraints, iterate over all of theme to ensure that every constraint is recreated. + for (bRigidBodyJointConstraint *dat : m_convertInfo->m_constraints) { + // Try to find the constraint targets in the list of group objects. + for (KX_GameObject *member : constobj) { + // If the group member is the actual target for the constraint. + if ((dat->tar->id.name + 2) == member->GetName() && member->GetPhysicsController()) { + physEnv->SetupObjectConstraints(this, member, dat); + } + } + } } -KX_GameObject* KX_GameObject::GetParent() +KX_GameObject *KX_GameObject::GetParent() { - KX_GameObject* result = NULL; - SG_Node* node = m_pSGNode; + KX_GameObject *result = nullptr; + SG_Node *node = m_sgNode.get(); while (node && !result) { - node = node->GetSGParent(); - if (node) - result = (KX_GameObject*)node->GetSGClientObject(); + node = node->GetParent(); + if (node) { + result = (KX_GameObject *)node->GetClientObject(); + } } return result; - } -void KX_GameObject::SetParent(KX_Scene *scene, KX_GameObject* obj, bool addToCompound, bool ghost) +void KX_GameObject::SetParent(KX_GameObject *obj, bool addToCompound, bool ghost) { // check on valid node in case a python controller holds a reference to a deleted object - if (obj && - GetSGNode() && // object is not zombi - obj->GetSGNode() && // object is not zombi - GetSGNode()->GetSGParent() != obj->GetSGNode() && // not already parented to same object - !GetSGNode()->IsAncessor(obj->GetSGNode()) && // no parenting loop - this != obj) // not the object itself - { - // Make sure the objects have some scale - MT_Vector3 scale1 = NodeGetWorldScaling(); - MT_Vector3 scale2 = obj->NodeGetWorldScaling(); - if (fabs(scale2[0]) < (MT_Scalar)FLT_EPSILON || - fabs(scale2[1]) < (MT_Scalar)FLT_EPSILON || - fabs(scale2[2]) < (MT_Scalar)FLT_EPSILON || - fabs(scale1[0]) < (MT_Scalar)FLT_EPSILON || - fabs(scale1[1]) < (MT_Scalar)FLT_EPSILON || - fabs(scale1[2]) < (MT_Scalar)FLT_EPSILON) { return; } - - // Remove us from our old parent and set our new parent - RemoveParent(scene); - obj->GetSGNode()->AddChild(GetSGNode()); - - if (m_pPhysicsController) - { - m_pPhysicsController->SuspendDynamics(ghost); - } - // Set us to our new scale, position, and orientation - scale2[0] = 1.0f/scale2[0]; - scale2[1] = 1.0f/scale2[1]; - scale2[2] = 1.0f/scale2[2]; - scale1 = scale1 * scale2; - MT_Matrix3x3 invori = obj->NodeGetWorldOrientation().inverse(); - MT_Vector3 newpos = invori*(NodeGetWorldPosition()-obj->NodeGetWorldPosition())*scale2; - - NodeSetLocalScale(scale1); - NodeSetLocalPosition(MT_Point3(newpos[0],newpos[1],newpos[2])); - NodeSetLocalOrientation(invori*NodeGetWorldOrientation()); - NodeUpdateGS(0.f); - // object will now be a child, it must be removed from the parent list - CListValue* rootlist = scene->GetRootParentList(); - if (rootlist->RemoveValue(this)) - // the object was in parent list, decrement ref count as it's now removed - Release(); - // if the new parent is a compound object, add this object shape to the compound shape. - // step 0: verify this object has physical controller - if (m_pPhysicsController && addToCompound) - { - // step 1: find the top parent (not necessarily obj) - KX_GameObject* rootobj = (KX_GameObject*)obj->GetSGNode()->GetRootSGParent()->GetSGClientObject(); - // step 2: verify it has a physical controller and compound shape - if (rootobj != NULL && - rootobj->m_pPhysicsController != NULL && - rootobj->m_pPhysicsController->IsCompound()) - { - rootobj->m_pPhysicsController->AddCompoundChild(m_pPhysicsController); - } + if (!obj) { + return; + } + + SG_Node *parentSgNode = obj->GetNode(); + KX_Scene *scene = GetScene(); + + // Not already parented to same object, no parenting loop, not the object itself + if (m_sgNode->GetParent() == parentSgNode || m_sgNode->IsAncessor(parentSgNode) || this == obj) { + return; + } + + if (!(scene->GetInactiveList()->SearchValue(obj) != scene->GetObjectList()->SearchValue(this))) { + CM_FunctionWarning("child and parent are not in the same game objects list (active or inactive). This operation is forbidden."); + return; + } + + // Make sure the objects have some scale + mt::vec3 scale1 = NodeGetWorldScaling(); + mt::vec3 scale2 = obj->NodeGetWorldScaling(); + if (mt::FuzzyZero(scale1) || mt::FuzzyZero(scale2)) { + return; + } + + // Remove us from our old parent and set our new parent + RemoveParent(); + parentSgNode->AddChild(m_sgNode.get()); + + if (m_physicsController) { + m_physicsController->SuspendDynamics(ghost); + } + + // Set us to our new scale, position, and orientation + scale2[0] = 1.0f / scale2[0]; + scale2[1] = 1.0f / scale2[1]; + scale2[2] = 1.0f / scale2[2]; + scale1 = scale1 * scale2; + + const mt::mat3 invori = obj->NodeGetWorldOrientation().Inverse(); + const mt::vec3 newpos = invori * (NodeGetWorldPosition() - obj->NodeGetWorldPosition()) * scale2; + + NodeSetLocalScale(scale1); + NodeSetLocalPosition(newpos); + NodeSetLocalOrientation(invori * NodeGetWorldOrientation()); + NodeUpdate(); + + // object will now be a child, it must be removed from the parent list + EXP_ListValue *rootlist = scene->GetRootParentList(); + if (rootlist->RemoveValue(this)) { + // the object was in parent list, decrement ref count as it's now removed + Release(); + } + + // if the new parent is a compound object, add this object shape to the compound shape. + // step 0: verify this object has physical controller + if (m_physicsController && addToCompound) { + // step 1: find the top parent (not necessarily obj) + KX_GameObject *rootobj = (KX_GameObject *)parentSgNode->GetRootSGParent()->GetClientObject(); + // step 2: verify it has a physical controller and compound shape + if (rootobj != nullptr && + rootobj->m_physicsController != nullptr && + rootobj->m_physicsController->IsCompound()) { + rootobj->m_physicsController->AddCompoundChild(m_physicsController.get()); } - // graphically, the object hasn't change place, no need to update m_pGraphicController } + // graphically, the object hasn't change place, no need to update m_graphicController } -void KX_GameObject::RemoveParent(KX_Scene *scene) +void KX_GameObject::RemoveParent() { - // check on valid node in case a python controller holds a reference to a deleted object - if (GetSGNode() && GetSGNode()->GetSGParent()) - { - // get the root object to remove us from compound object if needed - KX_GameObject* rootobj = (KX_GameObject*)GetSGNode()->GetRootSGParent()->GetSGClientObject(); - // Set us to the right spot - GetSGNode()->SetLocalScale(GetSGNode()->GetWorldScaling()); - GetSGNode()->SetLocalOrientation(GetSGNode()->GetWorldOrientation()); - GetSGNode()->SetLocalPosition(GetSGNode()->GetWorldPosition()); - - // Remove us from our parent - GetSGNode()->DisconnectFromParent(); - NodeUpdateGS(0.f); - // the object is now a root object, add it to the parentlist - CListValue* rootlist = scene->GetRootParentList(); - if (!rootlist->SearchValue(this)) - // object was not in root list, add it now and increment ref count - rootlist->Add(AddRef()); - if (m_pPhysicsController) - { - // in case this controller was added as a child shape to the parent - if (rootobj != NULL && - rootobj->m_pPhysicsController != NULL && - rootobj->m_pPhysicsController->IsCompound()) - { - rootobj->m_pPhysicsController->RemoveCompoundChild(m_pPhysicsController); - } - m_pPhysicsController->RestoreDynamics(); - if (m_pPhysicsController->IsDynamic() && (rootobj != NULL && rootobj->m_pPhysicsController)) - { - // dynamic object should remember the velocity they had while being parented - MT_Point3 childPoint = GetSGNode()->GetWorldPosition(); - MT_Point3 rootPoint = rootobj->GetSGNode()->GetWorldPosition(); - MT_Point3 relPoint; - relPoint = (childPoint-rootPoint); - MT_Vector3 linVel = rootobj->m_pPhysicsController->GetVelocity(relPoint); - MT_Vector3 angVel = rootobj->m_pPhysicsController->GetAngularVelocity(); - m_pPhysicsController->SetLinearVelocity(linVel, false); - m_pPhysicsController->SetAngularVelocity(angVel, false); - } + if (!m_sgNode->GetParent()) { + return; + } + + // get the root object to remove us from compound object if needed + KX_GameObject *rootobj = (KX_GameObject *)m_sgNode->GetRootSGParent()->GetClientObject(); + // Set us to the right spot + m_sgNode->SetLocalScale(m_sgNode->GetWorldScaling()); + m_sgNode->SetLocalOrientation(m_sgNode->GetWorldOrientation()); + m_sgNode->SetLocalPosition(m_sgNode->GetWorldPosition()); + + // Remove us from our parent + m_sgNode->DisconnectFromParent(); + NodeUpdate(); + + KX_Scene *scene = GetScene(); + // the object is now a root object, add it to the parentlist + EXP_ListValue *rootlist = scene->GetRootParentList(); + if (!rootlist->SearchValue(this)) { + // object was not in root list, add it now and increment ref count + rootlist->Add(CM_AddRef(this)); + } + if (m_physicsController) { + // in case this controller was added as a child shape to the parent + if (rootobj && + rootobj->m_physicsController && + rootobj->m_physicsController->IsCompound()) { + rootobj->m_physicsController->RemoveCompoundChild(m_physicsController.get()); + } + m_physicsController->RestoreDynamics(); + if (m_physicsController->IsDynamic() && (rootobj && rootobj->m_physicsController)) { + // dynamic object should remember the velocity they had while being parented + const mt::vec3 childPoint = m_sgNode->GetWorldPosition(); + const mt::vec3 rootPoint = rootobj->m_sgNode->GetWorldPosition(); + const mt::vec3 relPoint = (childPoint - rootPoint); + const mt::vec3 linVel = rootobj->m_physicsController->GetVelocity(relPoint); + const mt::vec3 angVel = rootobj->m_physicsController->GetAngularVelocity(); + m_physicsController->SetLinearVelocity(linVel, false); + m_physicsController->SetAngularVelocity(angVel, false); } - // graphically, the object hasn't change place, no need to update m_pGraphicController } + // graphically, the object hasn't change place, no need to update m_graphicController } -BL_ActionManager* KX_GameObject::GetActionManager() +BL_ActionManager *KX_GameObject::GetActionManager() { // We only want to create an action manager if we need it - if (!m_actionManager) - { + if (!m_actionManager) { GetScene()->AddAnimatedObject(this); - m_actionManager = new BL_ActionManager(this); + m_actionManager.reset(new BL_ActionManager(this)); } - return m_actionManager; + return m_actionManager.get(); } -bool KX_GameObject::PlayAction(const char* name, - float start, - float end, - short layer, - short priority, - float blendin, - short play_mode, - float layer_weight, - short ipo_flags, - float playback_speed, - short blend_mode) +bool KX_GameObject::PlayAction(const std::string& name, + float start, + float end, + short layer, + short priority, + float blendin, + short play_mode, + float layer_weight, + short ipo_flags, + float playback_speed, + short blend_mode) { return GetActionManager()->PlayAction(name, start, end, layer, priority, blendin, play_mode, layer_weight, ipo_flags, playback_speed, blend_mode); } @@ -466,19 +490,19 @@ void KX_GameObject::StopAction(short layer) GetActionManager()->StopAction(layer); } -void KX_GameObject::RemoveTaggedActions() +bool KX_GameObject::IsActionDone(short layer) { - GetActionManager()->RemoveTaggedActions(); + return GetActionManager()->IsActionDone(layer); } -bool KX_GameObject::IsActionDone(short layer) +bool KX_GameObject::IsActionsSuspended() { - return GetActionManager()->IsActionDone(layer); + return GetActionManager()->IsSuspended(); } -void KX_GameObject::UpdateActionManager(float curtime) +void KX_GameObject::UpdateActionManager(float curtime, bool applyToObject) { - GetActionManager()->Update(curtime); + GetActionManager()->Update(curtime, applyToObject); } float KX_GameObject::GetActionFrame(short layer) @@ -486,7 +510,7 @@ float KX_GameObject::GetActionFrame(short layer) return GetActionManager()->GetActionFrame(layer); } -const char *KX_GameObject::GetActionName(short layer) +const std::string KX_GameObject::GetActionName(short layer) { return GetActionManager()->GetActionName(layer); } @@ -496,9 +520,9 @@ void KX_GameObject::SetActionFrame(short layer, float frame) GetActionManager()->SetActionFrame(layer, frame); } -bAction *KX_GameObject::GetCurrentAction(short layer) +std::string KX_GameObject::GetCurrentActionName(short layer) { - return GetActionManager()->GetCurrentAction(layer); + return GetActionManager()->GetCurrentActionName(layer); } void KX_GameObject::SetPlayMode(short layer, short mode) @@ -506,55 +530,17 @@ void KX_GameObject::SetPlayMode(short layer, short mode) GetActionManager()->SetPlayMode(layer, mode); } -void KX_GameObject::SetTimes(short layer, float start, float end) -{ - GetActionManager()->SetTimes(layer, start, end); -} - -void KX_GameObject::ProcessReplica() -{ - SCA_IObject::ProcessReplica(); - - m_pGraphicController = NULL; - m_pPhysicsController = NULL; - m_pSGNode = NULL; - - /* Dupli group and instance list are set later in replication. - * See KX_Scene::DupliGroupRecurse. */ - m_pDupliGroupObject = NULL; - m_pInstanceObjects = NULL; - m_pClient_info = new KX_ClientObjectInfo(*m_pClient_info); - m_pClient_info->m_gameobject = this; - m_actionManager = NULL; - m_state = 0; - - KX_Scene* scene = KX_GetActiveScene(); - KX_ObstacleSimulation* obssimulation = scene->GetObstacleSimulation(); - struct Object* blenderobject = GetBlenderObject(); - if (obssimulation && (blenderobject->gameflag & OB_HASOBSTACLE)) - { - obssimulation->AddObstacleForObj(this); - } - -#ifdef WITH_PYTHON - if (m_attr_dict) - m_attr_dict= PyDict_Copy(m_attr_dict); -#endif - -} - -static void setGraphicController_recursive(SG_Node* node) +static void setGraphicController_recursive(SG_Node *node) { - NodeList& children = node->GetSGChildren(); + const NodeList& children = node->GetChildren(); - for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) - { - SG_Node* childnode = (*childit); - KX_GameObject *clientgameobj = static_cast( (*childit)->GetSGClientObject()); - if (clientgameobj != NULL) // This is a GameObject + for (SG_Node *childnode : children) { + KX_GameObject *clientgameobj = static_cast(childnode->GetClientObject()); + if (clientgameobj != nullptr) { // This is a GameObject clientgameobj->ActivateGraphicController(false); + } - // if the childobj is NULL then this may be an inverse parent link + // if the childobj is nullptr then this may be an inverse parent link // so a non recursive search should still look down this node. setGraphicController_recursive(childnode); } @@ -563,46 +549,41 @@ static void setGraphicController_recursive(SG_Node* node) void KX_GameObject::ActivateGraphicController(bool recurse) { - if (m_pGraphicController) - { - m_pGraphicController->Activate(m_bVisible); + if (m_graphicController) { + m_graphicController->Activate(m_bVisible || m_bOccluder); } - if (recurse) - { - setGraphicController_recursive(GetSGNode()); + if (recurse) { + setGraphicController_recursive(m_sgNode.get()); } } -void KX_GameObject::SetUserCollisionGroup(unsigned short group) +void KX_GameObject::SetCollisionGroup(unsigned short group) { - m_userCollisionGroup = group; - if (m_pPhysicsController) - m_pPhysicsController->RefreshCollisions(); + if (m_physicsController) { + m_physicsController->SetCollisionGroup(group); + m_physicsController->RefreshCollisions(); + } } -void KX_GameObject::SetUserCollisionMask(unsigned short mask) +void KX_GameObject::SetCollisionMask(unsigned short mask) { - m_userCollisionMask = mask; - if (m_pPhysicsController) - m_pPhysicsController->RefreshCollisions(); + if (m_physicsController) { + m_physicsController->SetCollisionMask(mask); + m_physicsController->RefreshCollisions(); + } } -unsigned short KX_GameObject::GetUserCollisionGroup() +unsigned short KX_GameObject::GetCollisionGroup() const { - return m_userCollisionGroup; + return m_physicsController ? m_physicsController->GetCollisionGroup() : 0; } -unsigned short KX_GameObject::GetUserCollisionMask() +unsigned short KX_GameObject::GetCollisionMask() const { - return m_userCollisionMask; + return m_physicsController ? m_physicsController->GetCollisionMask() : 0; } -bool KX_GameObject::CheckCollision(KX_GameObject* other) +EXP_Value *KX_GameObject::GetReplica() { - return this->m_userCollisionGroup & other->m_userCollisionMask; -} - -CValue* KX_GameObject::GetReplica() -{ - KX_GameObject* replica = new KX_GameObject(*this); + KX_GameObject *replica = new KX_GameObject(*this); // this will copy properties and so on... replica->ProcessReplica(); @@ -610,597 +591,476 @@ CValue* KX_GameObject::GetReplica() return replica; } -bool KX_GameObject::IsDynamicsSuspended() const +void KX_GameObject::RemoveRessources(const BL_Resource::Library& libraryId) { - if (m_pPhysicsController) - return m_pPhysicsController->IsSuspended(); - return false; + // If the object is using actions, try remove actions from this library. + if (m_actionManager) { + m_actionManager->RemoveActions(libraryId); + } + + for (KX_Mesh *mesh : m_meshes) { + // If the mesh comes from this lirbary, remove all meshes. + if (mesh->Belong(libraryId)) { + RemoveMeshes(); + break; + } + else { + // If one of the material used by the mesh comes from this library, remove all meshes too. + for (RAS_MeshMaterial *meshmat : mesh->GetMeshMaterialList()) { + if (static_cast(meshmat->GetBucket()->GetMaterial())->Belong(libraryId)) { + RemoveMeshes(); + break; + } + } + } + } } -float KX_GameObject::getLinearDamping() const +bool KX_GameObject::IsDynamic() const { - if (m_pPhysicsController) - return m_pPhysicsController->GetLinearDamping(); - return 0; + if (m_physicsController) { + return m_physicsController->IsDynamic(); + } + return false; } -float KX_GameObject::getAngularDamping() const +bool KX_GameObject::IsDynamicsSuspended() const { - if (m_pPhysicsController) - return m_pPhysicsController->GetAngularDamping(); - return 0; + if (m_physicsController) { + return m_physicsController->IsDynamicsSuspended(); + } + return false; } -void KX_GameObject::setLinearDamping(float damping) +float KX_GameObject::GetLinearDamping() const { - if (m_pPhysicsController) - m_pPhysicsController->SetLinearDamping(damping); + if (m_physicsController) { + return m_physicsController->GetLinearDamping(); + } + return 0.0f; } - -void KX_GameObject::setAngularDamping(float damping) +float KX_GameObject::GetAngularDamping() const { - if (m_pPhysicsController) - m_pPhysicsController->SetAngularDamping(damping); + if (m_physicsController) { + return m_physicsController->GetAngularDamping(); + } + return 0.0f; } - -void KX_GameObject::setDamping(float linear, float angular) +void KX_GameObject::SetLinearDamping(float damping) { - if (m_pPhysicsController) - m_pPhysicsController->SetDamping(linear, angular); + if (m_physicsController) { + m_physicsController->SetLinearDamping(damping); + } } -void KX_GameObject::ApplyForce(const MT_Vector3& force,bool local) +void KX_GameObject::SetAngularDamping(float damping) { - if (m_pPhysicsController) - m_pPhysicsController->ApplyForce(force,local); + if (m_physicsController) { + m_physicsController->SetAngularDamping(damping); + } } - - -void KX_GameObject::ApplyTorque(const MT_Vector3& torque,bool local) +void KX_GameObject::SetDamping(float linear, float angular) { - if (m_pPhysicsController) - m_pPhysicsController->ApplyTorque(torque,local); + if (m_physicsController) { + m_physicsController->SetDamping(linear, angular); + } } - - -void KX_GameObject::ApplyMovement(const MT_Vector3& dloc,bool local) +void KX_GameObject::ApplyForce(const mt::vec3& force, bool local) { - if (GetSGNode()) - { - if (m_pPhysicsController) // (IsDynamic()) - { - m_pPhysicsController->RelativeTranslate(dloc,local); - } - GetSGNode()->RelativeTranslate(dloc,GetSGNode()->GetSGParent(),local); + if (m_physicsController) { + m_physicsController->ApplyForce(force, local); } } - - -void KX_GameObject::ApplyRotation(const MT_Vector3& drot,bool local) +void KX_GameObject::ApplyTorque(const mt::vec3& torque, bool local) { - MT_Matrix3x3 rotmat(drot); - - if (GetSGNode()) { - GetSGNode()->RelativeRotate(rotmat,local); - - if (m_pPhysicsController) { // (IsDynamic()) - m_pPhysicsController->RelativeRotate(rotmat,local); - } + if (m_physicsController) { + m_physicsController->ApplyTorque(torque, local); } } +void KX_GameObject::ApplyMovement(const mt::vec3& dloc, bool local) +{ + if (m_physicsController) { // (IsDynamic()) + m_physicsController->RelativeTranslate(dloc, local); + } + m_sgNode->RelativeTranslate(dloc, m_sgNode->GetParent(), local); + NodeUpdate(); +} - -/** - * GetOpenGL Matrix, returns an OpenGL 'compatible' matrix - */ -float *KX_GameObject::GetOpenGLMatrix() +void KX_GameObject::ApplyRotation(const mt::vec3& drot, bool local) { - // todo: optimize and only update if necessary - float *fl = m_OpenGL_4x4Matrix.getPointer(); - if (GetSGNode()) { - MT_Transform trans; + mt::mat3 rotmat(drot); - trans.setOrigin(GetSGNode()->GetWorldPosition()); - trans.setBasis(GetSGNode()->GetWorldOrientation()); + m_sgNode->RelativeRotate(rotmat, local); - MT_Vector3 scaling = GetSGNode()->GetWorldScaling(); - m_bIsNegativeScaling = ((scaling[0] < 0.0f) ^ (scaling[1] < 0.0f) ^ (scaling[2] < 0.0f)) ? true : false; - trans.scale(scaling[0], scaling[1], scaling[2]); - trans.getValue(fl); - GetSGNode()->ClearDirty(); + if (m_physicsController) { // (IsDynamic()) + m_physicsController->RelativeRotate(rotmat, local); } - return fl; + NodeUpdate(); } -void KX_GameObject::UpdateBlenderObjectMatrix(Object* blendobj) +void KX_GameObject::UpdateBlenderObjectMatrix(Object *blendobj) { - if (!blendobj) - blendobj = m_pBlenderObject; + if (!blendobj) { + blendobj = m_convertInfo->m_blenderObject; + } if (blendobj) { - const MT_Matrix3x3& rot = NodeGetWorldOrientation(); - const MT_Vector3& scale = NodeGetWorldScaling(); - const MT_Vector3& pos = NodeGetWorldPosition(); - rot.getValue(blendobj->obmat[0]); - pos.getValue(blendobj->obmat[3]); - mul_v3_fl(blendobj->obmat[0], scale[0]); - mul_v3_fl(blendobj->obmat[1], scale[1]); - mul_v3_fl(blendobj->obmat[2], scale[2]); + const mt::mat3x4 trans = NodeGetWorldTransform(); + trans.PackFromAffineTransform(blendobj->obmat); } } void KX_GameObject::AddMeshUser() { - for (size_t i=0;iAddMeshUser(this, &m_meshSlots, GetDeformer()); - } - // set the part of the mesh slot that never change - float *fl = GetOpenGLMatrixPtr()->getPointer(); + for (size_t i = 0; i < m_meshes.size(); ++i) { + RAS_Deformer *deformer = BL_ConvertDeformer(this, m_meshes[i]); + m_meshUser = m_meshes[i]->AddMeshUser(&m_clientInfo, deformer); - SG_QList::iterator mit(m_meshSlots); -// RAS_MeshSlot* ms; - for (mit.begin(); !mit.end(); ++mit) - { - (*mit)->m_OpenGLMatrix = fl; + m_meshUser->SetMatrix(mt::mat4::FromAffineTransform(NodeGetWorldTransform())); + m_meshUser->SetFrontFace(!IsNegativeScaling()); } - UpdateBuckets(false); } -static void UpdateBuckets_recursive(SG_Node* node) +void KX_GameObject::UpdateBuckets() { - NodeList& children = node->GetSGChildren(); - - for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) - { - SG_Node* childnode = (*childit); - KX_GameObject *clientgameobj = static_cast( (*childit)->GetSGClientObject()); - if (clientgameobj != NULL) // This is a GameObject - clientgameobj->UpdateBuckets(0); - - // if the childobj is NULL then this may be an inverse parent link - // so a non recursive search should still look down this node. - UpdateBuckets_recursive(childnode); + // Update datas and add mesh slot to be rendered only if the object is not culled. + if (m_sgNode->IsDirty(SG_Node::DIRTY_RENDER)) { + m_meshUser->SetMatrix(mt::mat4::FromAffineTransform(NodeGetWorldTransform())); + m_meshUser->SetFrontFace(!IsNegativeScaling()); + m_sgNode->ClearDirty(SG_Node::DIRTY_RENDER); } + + m_meshUser->SetPassIndex(m_passIndex); + m_meshUser->SetLayer(m_layer); + m_meshUser->SetColor(m_objectColor); + m_meshUser->ActivateMeshSlots(); } -void KX_GameObject::UpdateBuckets( bool recursive ) +void KX_GameObject::ReplaceMesh(KX_Mesh *mesh, bool use_gfx, bool use_phys) { - if (GetSGNode()) { - RAS_MeshSlot *ms; - - if (GetSGNode()->IsDirty()) - GetOpenGLMatrix(); - - SG_QList::iterator mit(m_meshSlots); - for (mit.begin(); !mit.end(); ++mit) - { - ms = *mit; - ms->m_bObjectColor = m_bUseObjectColor; - ms->m_RGBAcolor = m_objectColor; - ms->m_bVisible = m_bVisible; - ms->m_bCulled = m_bCulled || !m_bVisible; - if (!ms->m_bCulled) - ms->m_bucket->ActivateMesh(ms); - - /* split if necessary */ -#ifdef USE_SPLIT - ms->Split(); -#endif - } + if (use_gfx && mesh) { + RemoveMeshes(); + AddMesh(mesh); + AddMeshUser(); + } - if (recursive) { - UpdateBuckets_recursive(GetSGNode()); + // Update the new assigned mesh with the physics mesh. + if (use_phys) { + if (m_physicsController) { + m_physicsController->ReinstancePhysicsShape(nullptr, use_gfx ? nullptr : mesh); } } + // Always make sure that the bounding box is updated to the new mesh. + UpdateBounds(true); } + void KX_GameObject::RemoveMeshes() { - for (size_t i=0;iRemoveFromBuckets(this); + // Remove all mesh slots. + if (m_meshUser) { + delete m_meshUser; + m_meshUser = nullptr; + } - //note: meshes can be shared, and are deleted by KX_BlenderSceneConverter + //note: meshes can be shared, and are deleted by BL_SceneConverter m_meshes.clear(); } -void KX_GameObject::AddLodMesh(RAS_MeshObject* mesh) +const std::vector& KX_GameObject::GetMeshList() const { - m_lodmeshes.push_back(mesh); + return m_meshes; } +RAS_MeshUser *KX_GameObject::GetMeshUser() const +{ + return m_meshUser; +} -static float calcHysteresis(KX_Scene *kxscene, LodLevel *lod) +bool KX_GameObject::Renderable(int layer) const { - float hystvariance = 0.0f; + return (m_meshUser != nullptr) && m_bVisible && (layer == 0 || m_layer & layer); +} - if (!kxscene->IsActivedLodHysteresis()) - return hystvariance; +void KX_GameObject::SetLodManager(KX_LodManager *lodManager) +{ + // Reset lod level to avoid overflow index in KX_LodManager::GetLevel. + m_currentLodLevel = 0; - short hysteresis = 0; - // if exists, LoD level hysteresis will override scene hysteresis - if (lod->next->flags & OB_LOD_USE_HYST) - hysteresis = lod->next->obhysteresis; - else - hysteresis = kxscene->GetLodHysteresisValue(); + // Restore object original mesh. + if (!lodManager && m_lodManager && m_lodManager->GetLevelCount() > 0) { + KX_Mesh *origmesh = m_lodManager->GetLevel(0).GetMesh(); + ReplaceMesh(origmesh, true, false); + } + + if (m_lodManager) { + m_lodManager->Release(); + } - return hystvariance = MT_abs(lod->next->distance - lod->distance) * hysteresis / 100; + m_lodManager = lodManager; + + if (m_lodManager) { + m_lodManager->AddRef(); + } } -void KX_GameObject::UpdateLod(MT_Vector3 &cam_pos) +KX_LodManager *KX_GameObject::GetLodManager() const { - // Handle dupligroups - if (m_pInstanceObjects) { - KX_GameObject *instob; - int count = m_pInstanceObjects->GetCount(); - for (int i = 0; i < count; i++) { - instob = (KX_GameObject*)m_pInstanceObjects->GetValue(i); - instob->UpdateLod(cam_pos); - } - } + return m_lodManager; +} - if (m_lodmeshes.empty()) +void KX_GameObject::UpdateLod(KX_Scene *scene, const mt::vec3& cam_pos, float lodfactor) +{ + if (!m_lodManager) { return; + } - MT_Vector3 delta = NodeGetWorldPosition() - cam_pos; - float distance2 = delta.length2(); - - int level = 0; - float hystvariance = 0.0f; - Object *bob = GetBlenderObject(); - LodLevel *lod = (LodLevel *)bob->lodlevels.first; - KX_Scene *kxscene = GetScene(); + const float distance2 = (NodeGetWorldPosition() - cam_pos).LengthSquared() * (lodfactor * lodfactor); + const KX_LodLevel& lodLevel = m_lodManager->GetLevel(scene, m_currentLodLevel, distance2); - for (; lod; lod = lod->next, level++) { - if (!lod->source || lod->source->type != OB_MESH) - level--; + KX_Mesh *mesh = lodLevel.GetMesh(); + if (mesh != m_meshes.front()) { + ReplaceMesh(mesh, true, false); + } - if (!lod->next) - break; + m_currentLodLevel = lodLevel.GetLevel(); +} - if (level == m_previousLodLevel || level == (m_previousLodLevel + 1)) { - hystvariance = calcHysteresis(kxscene, lod); - float newdistance = lod->next->distance + hystvariance; - if (newdistance * newdistance > distance2) - break; +void KX_GameObject::UpdateActivity(float distance) +{ + // Manage physics culling. + if (m_activityCullingInfo.m_flags & ActivityCullingInfo::ACTIVITY_PHYSICS) { + if (distance > m_activityCullingInfo.m_physicsRadius) { + SuspendPhysics(false); } - else if (level == (m_previousLodLevel - 1)) { - hystvariance = calcHysteresis(kxscene, lod); - float newdistance = lod->next->distance - hystvariance; - if (newdistance * newdistance > distance2) - break; + else { + RestorePhysics(); } } - RAS_MeshObject *mesh = m_lodmeshes[level]; - m_currentLodLevel = level; - if (mesh != m_meshes[0]) { - m_previousLodLevel = level; - GetScene()->ReplaceMesh(this, mesh, true, false); + // Manage logic culling. + if (m_activityCullingInfo.m_flags & ActivityCullingInfo::ACTIVITY_LOGIC) { + if (distance > m_activityCullingInfo.m_logicRadius) { + SuspendLogic(); + if (m_actionManager) { + m_actionManager->Suspend(); + } + } + else { + ResumeLogic(); + if (m_actionManager) { + m_actionManager->Resume(); + } + } } } void KX_GameObject::UpdateTransform() { // HACK: saves function call for dynamic object, they are handled differently - if (m_pPhysicsController && !m_pPhysicsController->IsDynamic()) - m_pPhysicsController->SetTransform(); - if (m_pGraphicController) + if (m_physicsController && !m_physicsController->IsDynamic()) { + m_physicsController->SetTransform(); + } + if (m_graphicController) { // update the culling tree - m_pGraphicController->SetGraphicTransform(); + m_graphicController->SetGraphicTransform(); + } } -void KX_GameObject::UpdateTransformFunc(SG_IObject* node, void* gameobj, void* scene) +void KX_GameObject::UpdateTransformFunc(SG_Node *node, void *gameobj, void *scene) { - ((KX_GameObject*)gameobj)->UpdateTransform(); + ((KX_GameObject *)gameobj)->UpdateTransform(); } void KX_GameObject::SynchronizeTransform() { // only used for sensor object, do full synchronization as bullet doesn't do it - if (m_pPhysicsController) - m_pPhysicsController->SetTransform(); - if (m_pGraphicController) - m_pGraphicController->SetGraphicTransform(); -} - -void KX_GameObject::SynchronizeTransformFunc(SG_IObject* node, void* gameobj, void* scene) -{ - ((KX_GameObject*)gameobj)->SynchronizeTransform(); -} - - -void KX_GameObject::SetDebugColor(unsigned int bgra) -{ - for (size_t i=0;iDebugColor(bgra); -} - - - -void KX_GameObject::ResetDebugColor() -{ - SetDebugColor(0xff000000); -} - -void KX_GameObject::InitIPO(bool ipo_as_force, - bool ipo_add, - bool ipo_local) -{ - SGControllerList::iterator it = GetSGNode()->GetSGControllerList().begin(); - - while (it != GetSGNode()->GetSGControllerList().end()) { - (*it)->SetOption(SG_Controller::SG_CONTR_IPO_RESET, true); - (*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_AS_FORCE, ipo_as_force); - (*it)->SetOption(SG_Controller::SG_CONTR_IPO_IPO_ADD, ipo_add); - (*it)->SetOption(SG_Controller::SG_CONTR_IPO_LOCAL, ipo_local); - it++; + if (m_physicsController) { + m_physicsController->SetTransform(); + } + if (m_graphicController) { + m_graphicController->SetGraphicTransform(); } } -void KX_GameObject::UpdateIPO(float curframetime, - bool recurse) +void KX_GameObject::SynchronizeTransformFunc(SG_Node *node, void *gameobj, void *scene) { - /* This function shouldn't call BL_Action::Update, not even indirectly, - * as it will cause deadlock due to the lock in BL_Action::Update. */ - - // just the 'normal' update procedure. - GetSGNode()->SetSimulatedTime(curframetime,recurse); - GetSGNode()->UpdateWorldData(curframetime); - UpdateTransform(); + ((KX_GameObject *)gameobj)->SynchronizeTransform(); } -// IPO update -void -KX_GameObject::UpdateMaterialData( - dword matname_hash, - MT_Vector4 rgba, - MT_Vector3 specrgb, - MT_Scalar hard, - MT_Scalar spec, - MT_Scalar ref, - MT_Scalar emit, - MT_Scalar alpha - - ) -{ - int mesh = 0; - if (((unsigned int)mesh < m_meshes.size()) && mesh >= 0) { - list::iterator mit = m_meshes[mesh]->GetFirstMaterial(); - - for (; mit != m_meshes[mesh]->GetLastMaterial(); ++mit) - { - RAS_IPolyMaterial* poly = mit->m_bucket->GetPolyMaterial(); - - if (poly->GetFlag() & RAS_BLENDERMAT ) - { - KX_BlenderMaterial *m = static_cast(poly); - - if (matname_hash == 0) - { - m->UpdateIPO(rgba, specrgb,hard,spec,ref,emit, alpha); - // if mesh has only one material attached to it then use original hack with no need to edit vertices (better performance) - SetObjectColor(rgba); - } - else - { - if (matname_hash == poly->GetMaterialNameHash()) - { - m->UpdateIPO(rgba, specrgb,hard,spec,ref,emit, alpha); - m_meshes[mesh]->SetVertexColor(poly,rgba); - - // no break here, because one blender material can be split into several game engine materials - // (e.g. one uvsphere material is split into one material at poles with ras_mode TRIANGLE and one material for the body - // if here was a break then would miss some vertices if material was split - } - } - } - } - } -} -bool -KX_GameObject::GetVisible( - void - ) +bool KX_GameObject::GetVisible(void) { return m_bVisible; } -static void setVisible_recursive(SG_Node* node, bool v) +static void setVisible_recursive(SG_Node *node, bool v) { - NodeList& children = node->GetSGChildren(); + const NodeList& children = node->GetChildren(); - for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) - { - SG_Node* childnode = (*childit); - KX_GameObject *clientgameobj = static_cast( (*childit)->GetSGClientObject()); - if (clientgameobj != NULL) // This is a GameObject + for (SG_Node *childnode : children) { + KX_GameObject *clientgameobj = static_cast(childnode->GetClientObject()); + if (clientgameobj != nullptr) { // This is a GameObject clientgameobj->SetVisible(v, 0); + } - // if the childobj is NULL then this may be an inverse parent link + // if the childobj is nullptr then this may be an inverse parent link // so a non recursive search should still look down this node. setVisible_recursive(childnode, v); } } -void -KX_GameObject::SetVisible( - bool v, - bool recursive - ) +void KX_GameObject::SetVisible(bool v, + bool recursive) { - if (GetSGNode()) { - m_bVisible = v; - if (m_pGraphicController) - m_pGraphicController->Activate(m_bVisible); - if (recursive) - setVisible_recursive(GetSGNode(), v); + m_bVisible = v; + if (m_graphicController) { + m_graphicController->Activate(m_bVisible || m_bOccluder); + } + if (recursive) { + setVisible_recursive(m_sgNode.get(), v); } } -static void setOccluder_recursive(SG_Node* node, bool v) +static void setOccluder_recursive(SG_Node *node, bool v) { - NodeList& children = node->GetSGChildren(); + const NodeList& children = node->GetChildren(); - for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) - { - SG_Node* childnode = (*childit); - KX_GameObject *clientgameobj = static_cast( (*childit)->GetSGClientObject()); - if (clientgameobj != NULL) // This is a GameObject + for (SG_Node *childnode : children) { + KX_GameObject *clientgameobj = static_cast(childnode->GetClientObject()); + if (clientgameobj != nullptr) { // This is a GameObject clientgameobj->SetOccluder(v, false); + } - // if the childobj is NULL then this may be an inverse parent link + // if the childobj is nullptr then this may be an inverse parent link // so a non recursive search should still look down this node. setOccluder_recursive(childnode, v); } } -void -KX_GameObject::SetOccluder( - bool v, - bool recursive - ) +void KX_GameObject::SetOccluder(bool v, + bool recursive) { - if (GetSGNode()) { - m_bOccluder = v; - if (recursive) - setOccluder_recursive(GetSGNode(), v); + m_bOccluder = v; + if (m_graphicController) { + m_graphicController->Activate(m_bVisible || m_bOccluder); + } + if (recursive) { + setOccluder_recursive(m_sgNode.get(), v); } } -static void setDebug_recursive(SG_Node *node, bool debug) +static void setDebug_recursive(KX_Scene *scene, SG_Node *node, bool debug) { - NodeList& children = node->GetSGChildren(); - KX_Scene *scene = KX_GetActiveScene(); + const NodeList& children = node->GetChildren(); - for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) { - SG_Node *childnode = (*childit); - KX_GameObject *clientgameobj = static_cast( (*childit)->GetSGClientObject()); - if (clientgameobj != NULL) { + for (SG_Node *childnode : children) { + KX_GameObject *clientgameobj = static_cast(childnode->GetClientObject()); + if (clientgameobj != nullptr) { if (debug) { - if (!scene->ObjectInDebugList(clientgameobj)) + if (!scene->ObjectInDebugList(clientgameobj)) { scene->AddObjectDebugProperties(clientgameobj); + } } - else + else { scene->RemoveObjectDebugProperties(clientgameobj); + } } - /* if the childobj is NULL then this may be an inverse parent link + /* if the childobj is nullptr then this may be an inverse parent link * so a non recursive search should still look down this node. */ - setDebug_recursive(childnode, debug); + setDebug_recursive(scene, childnode, debug); } } -void KX_GameObject::SetUseDebugProperties( bool debug, bool recursive ) +void KX_GameObject::SetUseDebugProperties(bool debug, bool recursive) { - KX_Scene *scene = KX_GetActiveScene(); + KX_Scene *scene = GetScene(); if (debug) { - if (!scene->ObjectInDebugList(this)) + if (!scene->ObjectInDebugList(this)) { scene->AddObjectDebugProperties(this); + } } - else + else { scene->RemoveObjectDebugProperties(this); + } - if (recursive) - setDebug_recursive(GetSGNode(), debug); + if (recursive) { + setDebug_recursive(scene, m_sgNode.get(), debug); + } } -void -KX_GameObject::SetLayer( - int l - ) +void KX_GameObject::SetLayer(int l) { m_layer = l; } -int -KX_GameObject::GetLayer( - void - ) +int KX_GameObject::GetLayer(void) { return m_layer; } -void KX_GameObject::addLinearVelocity(const MT_Vector3& lin_vel,bool local) +void KX_GameObject::SetPassIndex(short index) { - if (m_pPhysicsController) - { - MT_Vector3 lv = local ? NodeGetWorldOrientation() * lin_vel : lin_vel; - m_pPhysicsController->SetLinearVelocity(lv + m_pPhysicsController->GetLinearVelocity(), 0); - } + m_passIndex = index; } - - -void KX_GameObject::setLinearVelocity(const MT_Vector3& lin_vel,bool local) +short KX_GameObject::GetPassIndex() const { - if (m_pPhysicsController) - m_pPhysicsController->SetLinearVelocity(lin_vel,local); + return m_passIndex; } - - -void KX_GameObject::setAngularVelocity(const MT_Vector3& ang_vel,bool local) +void KX_GameObject::AddLinearVelocity(const mt::vec3& lin_vel, bool local) { - if (m_pPhysicsController) - m_pPhysicsController->SetAngularVelocity(ang_vel,local); + if (m_physicsController) { + const mt::vec3 lv = local ? NodeGetWorldOrientation() * lin_vel : lin_vel; + m_physicsController->SetLinearVelocity(lv + m_physicsController->GetLinearVelocity(), 0); + } } - -void KX_GameObject::ResolveCombinedVelocities( - const MT_Vector3 & lin_vel, - const MT_Vector3 & ang_vel, - bool lin_vel_local, - bool ang_vel_local -) { - if (m_pPhysicsController) - { - - MT_Vector3 lv = lin_vel_local ? NodeGetWorldOrientation() * lin_vel : lin_vel; - MT_Vector3 av = ang_vel_local ? NodeGetWorldOrientation() * ang_vel : ang_vel; - m_pPhysicsController->ResolveCombinedVelocities( - lv.x(),lv.y(),lv.z(),av.x(),av.y(),av.z()); +void KX_GameObject::SetLinearVelocity(const mt::vec3& lin_vel, bool local) +{ + if (m_physicsController) { + m_physicsController->SetLinearVelocity(lin_vel, local); } } +void KX_GameObject::SetAngularVelocity(const mt::vec3& ang_vel, bool local) +{ + if (m_physicsController) { + m_physicsController->SetAngularVelocity(ang_vel, local); + } +} -void KX_GameObject::SetObjectColor(const MT_Vector4& rgbavec) +void KX_GameObject::SetObjectColor(const mt::vec4& rgbavec) { - m_bUseObjectColor = true; m_objectColor = rgbavec; } -const MT_Vector4& KX_GameObject::GetObjectColor() +const mt::vec4& KX_GameObject::GetObjectColor() { return m_objectColor; } -void KX_GameObject::AlignAxisToVect(const MT_Vector3& dir, int axis, float fac) +void KX_GameObject::AlignAxisToVect(const mt::vec3& dir, int axis, float fac) { - const MT_Scalar eps = 3.0f * MT_EPSILON; - MT_Matrix3x3 orimat; - MT_Vector3 vect,ori,z,x,y; - MT_Scalar len; - - // check on valid node in case a python controller holds a reference to a deleted object - if (!GetSGNode()) - return; + mt::mat3 orimat; + mt::vec3 vect, ori, z, x, y; + float len; vect = dir; - len = vect.length(); - if (MT_fuzzyZero(len)) - { - cout << "alignAxisToVect() Error: Null vector!\n"; + len = vect.Length(); + if (mt::FuzzyZero(len)) { + CM_FunctionError("null vector!"); return; } @@ -1210,113 +1070,120 @@ void KX_GameObject::AlignAxisToVect(const MT_Vector3& dir, int axis, float fac) // normalize vect /= len; - orimat = GetSGNode()->GetWorldOrientation(); - switch (axis) - { + orimat = NodeGetWorldOrientation(); + switch (axis) { case 0: // align x axis of new coord system to vect - ori.setValue(orimat[0][2], orimat[1][2], orimat[2][2]); // pivot axis - if (1.0f - MT_abs(vect.dot(ori)) < eps) { // vect parallel to pivot? - ori.setValue(orimat[0][1], orimat[1][1], orimat[2][1]); // change the pivot! - } - - if (fac == 1.0f) { - x = vect; - } else { - x = (vect * fac) + ((orimat * MT_Vector3(1.0f, 0.0f, 0.0f)) * (1.0f - fac)); - len = x.length(); - if (MT_fuzzyZero(len)) x = vect; - else x /= len; - } - y = ori.cross(x); - z = x.cross(y); - break; + {ori = orimat.GetColumn(2); // pivot axis + if (mt::FuzzyZero(1.0f - std::abs(mt::dot(vect, ori)))) { // vect parallel to pivot? + ori = orimat.GetColumn(1); // change the pivot! + } + + if (fac == 1.0f) { + x = vect; + } + else { + x = (vect * fac) + ((orimat *mt::axisX3)*(1.0f - fac)); + len = x.Length(); + if (mt::FuzzyZero(len)) { + x = vect; + } + else { + x /= len; + } + } + y = mt::cross(ori, x); + z = mt::cross(x, y); + break;} case 1: // y axis - ori.setValue(orimat[0][0], orimat[1][0], orimat[2][0]); - if (1.0f - MT_abs(vect.dot(ori)) < eps) { - ori.setValue(orimat[0][2], orimat[1][2], orimat[2][2]); - } - - if (fac == 1.0f) { - y = vect; - } else { - y = (vect * fac) + ((orimat * MT_Vector3(0.0f, 1.0f, 0.0f)) * (1.0f - fac)); - len = y.length(); - if (MT_fuzzyZero(len)) y = vect; - else y /= len; - } - z = ori.cross(y); - x = y.cross(z); - break; + {ori = orimat.GetColumn(0); + if (mt::FuzzyZero(1.0f - std::abs(mt::dot(vect, ori)))) { + ori = orimat.GetColumn(2); + } + + if (fac == 1.0f) { + y = vect; + } + else { + y = (vect * fac) + ((orimat *mt::axisY3)*(1.0f - fac)); + len = y.Length(); + if (mt::FuzzyZero(len)) { + y = vect; + } + else { + y /= len; + } + } + z = mt::cross(ori, y); + x = mt::cross(y, z); + break;} case 2: // z axis - ori.setValue(orimat[0][1], orimat[1][1], orimat[2][1]); - if (1.0f - MT_abs(vect.dot(ori)) < eps) { - ori.setValue(orimat[0][0], orimat[1][0], orimat[2][0]); - } - - if (fac == 1.0f) { - z = vect; - } else { - z = (vect * fac) + ((orimat * MT_Vector3(0.0f, 0.0f, 1.0f)) * (1.0f - fac)); - len = z.length(); - if (MT_fuzzyZero(len)) z = vect; - else z /= len; - } - x = ori.cross(z); - y = z.cross(x); - break; + {ori = orimat.GetColumn(1); + if (mt::FuzzyZero(1.0f - std::abs(mt::dot(vect, ori)))) { + ori = orimat.GetColumn(0); + } + + if (fac == 1.0f) { + z = vect; + } + else { + z = (vect * fac) + ((orimat *mt::axisZ3)*(1.0f - fac)); + len = z.Length(); + if (mt::FuzzyZero(len)) { + z = vect; + } + else { + z /= len; + } + } + x = mt::cross(ori, z); + y = mt::cross(z, x); + break;} default: // invalid axis specified - cout << "alignAxisToVect(): Invalid axis '" << axis <<"'\n"; + CM_FunctionWarning("invalid axis '" << axis << "'"); return; } - x.normalize(); // normalize the new base vectors - y.normalize(); - z.normalize(); - orimat.setValue(x[0], y[0], z[0], - x[1], y[1], z[1], - x[2], y[2], z[2]); + x.Normalize(); // normalize the new base vectors + y.Normalize(); + z.Normalize(); + orimat = mt::mat3(x, y, z); - if (GetSGNode()->GetSGParent() != NULL) - { + if (m_sgNode->GetParent() != nullptr) { // the object is a child, adapt its local orientation so that // the global orientation is aligned as we want (cancelling out the parent orientation) - MT_Matrix3x3 invori = GetSGNode()->GetSGParent()->GetWorldOrientation().inverse(); - NodeSetLocalOrientation(invori*orimat); + mt::mat3 invori = m_sgNode->GetParent()->GetWorldOrientation().Inverse(); + NodeSetLocalOrientation(invori * orimat); } else { NodeSetLocalOrientation(orimat); } } -MT_Scalar KX_GameObject::GetMass() +float KX_GameObject::GetMass() { - if (m_pPhysicsController) - { - return m_pPhysicsController->GetMass(); + if (m_physicsController) { + return m_physicsController->GetMass(); } return 0.0f; } -MT_Vector3 KX_GameObject::GetLocalInertia() +mt::vec3 KX_GameObject::GetLocalInertia() { - MT_Vector3 local_inertia(0.0f,0.0f,0.0f); - if (m_pPhysicsController) - { - local_inertia = m_pPhysicsController->GetLocalInertia(); + mt::vec3 local_inertia = mt::zero3; + if (m_physicsController) { + local_inertia = m_physicsController->GetLocalInertia(); } return local_inertia; } -MT_Vector3 KX_GameObject::GetLinearVelocity(bool local) +mt::vec3 KX_GameObject::GetLinearVelocity(bool local) { - MT_Vector3 velocity(0.0f,0.0f,0.0f), locvel; - MT_Matrix3x3 ori; - if (m_pPhysicsController) - { - velocity = m_pPhysicsController->GetLinearVelocity(); + mt::vec3 velocity = mt::zero3, locvel; + mt::mat3 ori; + if (m_physicsController) { + velocity = m_physicsController->GetLinearVelocity(); - if (local) - { - ori = GetSGNode()->GetWorldOrientation(); + if (local) { + ori = NodeGetWorldOrientation(); locvel = velocity * ori; return locvel; @@ -1325,17 +1192,15 @@ MT_Vector3 KX_GameObject::GetLinearVelocity(bool local) return velocity; } -MT_Vector3 KX_GameObject::GetAngularVelocity(bool local) +mt::vec3 KX_GameObject::GetAngularVelocity(bool local) { - MT_Vector3 velocity(0.0f,0.0f,0.0f), locvel; - MT_Matrix3x3 ori; - if (m_pPhysicsController) - { - velocity = m_pPhysicsController->GetAngularVelocity(); + mt::vec3 velocity = mt::zero3, locvel; + mt::mat3 ori; + if (m_physicsController) { + velocity = m_physicsController->GetAngularVelocity(); - if (local) - { - ori = GetSGNode()->GetWorldOrientation(); + if (local) { + ori = NodeGetWorldOrientation(); locvel = velocity * ori; return locvel; @@ -1344,367 +1209,451 @@ MT_Vector3 KX_GameObject::GetAngularVelocity(bool local) return velocity; } -MT_Vector3 KX_GameObject::GetVelocity(const MT_Point3& point) +mt::vec3 KX_GameObject::GetGravity() const { - if (m_pPhysicsController) - { - return m_pPhysicsController->GetVelocity(point); + if (!m_physicsController) { + return mt::zero3; } - return MT_Vector3(0.0f,0.0f,0.0f); + + return m_physicsController->GetGravity(); } -// scenegraph node stuff +void KX_GameObject::SetGravity(const mt::vec3 &gravity) +{ + if (m_physicsController) { + m_physicsController->SetGravity(gravity); + } +} -void KX_GameObject::NodeSetLocalPosition(const MT_Point3& trans) +mt::vec3 KX_GameObject::GetVelocity(const mt::vec3& point) { - // check on valid node in case a python controller holds a reference to a deleted object - if (!GetSGNode()) - return; + if (m_physicsController) { + return m_physicsController->GetVelocity(point); + } + return mt::zero3; +} - if (m_pPhysicsController && !GetSGNode()->GetSGParent()) - { +void KX_GameObject::NodeSetLocalPosition(const mt::vec3& trans) +{ + if (m_physicsController && !m_sgNode->GetParent()) { // don't update physic controller if the object is a child: // 1) the transformation will not be right // 2) in this case, the physic controller is necessarily a static object // that is updated from the normal kinematic synchronization - m_pPhysicsController->SetPosition(trans); + m_physicsController->SetPosition(trans); } - GetSGNode()->SetLocalPosition(trans); - + m_sgNode->SetLocalPosition(trans); } - - -void KX_GameObject::NodeSetLocalOrientation(const MT_Matrix3x3& rot) +void KX_GameObject::NodeSetLocalOrientation(const mt::mat3& rot) { - // check on valid node in case a python controller holds a reference to a deleted object - if (!GetSGNode()) - return; - - if (m_pPhysicsController && !GetSGNode()->GetSGParent()) - { + if (m_physicsController && !m_sgNode->GetParent()) { // see note above - m_pPhysicsController->SetOrientation(rot); + m_physicsController->SetOrientation(rot); } - GetSGNode()->SetLocalOrientation(rot); + m_sgNode->SetLocalOrientation(rot); } -void KX_GameObject::NodeSetGlobalOrientation(const MT_Matrix3x3& rot) +void KX_GameObject::NodeSetGlobalOrientation(const mt::mat3& rot) { - // check on valid node in case a python controller holds a reference to a deleted object - if (!GetSGNode()) - return; - - if (GetSGNode()->GetSGParent()) - GetSGNode()->SetLocalOrientation(GetSGNode()->GetSGParent()->GetWorldOrientation().inverse()*rot); - else + SG_Node *parentSgNode = m_sgNode->GetParent(); + if (parentSgNode) { + NodeSetLocalOrientation(parentSgNode->GetWorldOrientation().Inverse() * rot); + } + else { NodeSetLocalOrientation(rot); + } } -void KX_GameObject::NodeSetLocalScale(const MT_Vector3& scale) +void KX_GameObject::NodeSetLocalScale(const mt::vec3& scale) { - // check on valid node in case a python controller holds a reference to a deleted object - if (!GetSGNode()) - return; - - if (m_pPhysicsController && !GetSGNode()->GetSGParent()) - { - // see note above - m_pPhysicsController->SetScaling(scale); + if (m_physicsController && !m_sgNode->GetParent()) { + m_physicsController->SetScaling(scale); } - GetSGNode()->SetLocalScale(scale); + m_sgNode->SetLocalScale(scale); } - - -void KX_GameObject::NodeSetRelativeScale(const MT_Vector3& scale) +void KX_GameObject::NodeSetRelativeScale(const mt::vec3& scale) { - if (GetSGNode()) - { - GetSGNode()->RelativeScale(scale); - if (m_pPhysicsController && (!GetSGNode()->GetSGParent())) - { - // see note above - // we can use the local scale: it's the same thing for a root object - // and the world scale is not yet updated - MT_Vector3 newscale = GetSGNode()->GetLocalScale(); - m_pPhysicsController->SetScaling(newscale); - } + m_sgNode->RelativeScale(scale); + if (m_physicsController && (!m_sgNode->GetParent())) { + // see note above + // we can use the local scale: it's the same thing for a root object + // and the world scale is not yet updated + const mt::vec3& newscale = NodeGetLocalScaling(); + m_physicsController->SetScaling(newscale); } } -void KX_GameObject::NodeSetWorldScale(const MT_Vector3& scale) +void KX_GameObject::NodeSetWorldScale(const mt::vec3& scale) { - if (!GetSGNode()) - return; - SG_Node* parent = GetSGNode()->GetSGParent(); - if (parent != NULL) - { + SG_Node *parent = m_sgNode->GetParent(); + if (parent) { // Make sure the objects have some scale - MT_Vector3 p_scale = parent->GetWorldScaling(); - if (fabs(p_scale[0]) < (MT_Scalar)FLT_EPSILON || - fabs(p_scale[1]) < (MT_Scalar)FLT_EPSILON || - fabs(p_scale[2]) < (MT_Scalar)FLT_EPSILON) - { + mt::vec3 p_scale = parent->GetWorldScaling(); + if (mt::FuzzyZero(p_scale)) { return; } - p_scale[0] = 1/p_scale[0]; - p_scale[1] = 1/p_scale[1]; - p_scale[2] = 1/p_scale[2]; + p_scale[0] = 1.0f / p_scale[0]; + p_scale[1] = 1.0f / p_scale[1]; + p_scale[2] = 1.0f / p_scale[2]; NodeSetLocalScale(scale * p_scale); } - else - { + else { NodeSetLocalScale(scale); } } -void KX_GameObject::NodeSetWorldPosition(const MT_Point3& trans) +void KX_GameObject::NodeSetWorldPosition(const mt::vec3& trans) { - if (!GetSGNode()) - return; - SG_Node* parent = GetSGNode()->GetSGParent(); - if (parent != NULL) - { + SG_Node *parent = m_sgNode->GetParent(); + if (parent != nullptr) { // Make sure the objects have some scale - MT_Vector3 scale = parent->GetWorldScaling(); - if (fabs(scale[0]) < (MT_Scalar)FLT_EPSILON || - fabs(scale[1]) < (MT_Scalar)FLT_EPSILON || - fabs(scale[2]) < (MT_Scalar)FLT_EPSILON) - { + mt::vec3 scale = parent->GetWorldScaling(); + if (mt::FuzzyZero(scale)) { return; } - scale[0] = 1.0f/scale[0]; - scale[1] = 1.0f/scale[1]; - scale[2] = 1.0f/scale[2]; - MT_Matrix3x3 invori = parent->GetWorldOrientation().inverse(); - MT_Vector3 newpos = invori*(trans-parent->GetWorldPosition())*scale; - NodeSetLocalPosition(MT_Point3(newpos[0],newpos[1],newpos[2])); - } - else - { + + scale[0] = 1.0f / scale[0]; + scale[1] = 1.0f / scale[1]; + scale[2] = 1.0f / scale[2]; + + const mt::mat3 invori = parent->GetWorldOrientation().Inverse(); + const mt::vec3 newpos = invori * (trans - parent->GetWorldPosition()) * scale; + NodeSetLocalPosition(newpos); + } + else { NodeSetLocalPosition(trans); } } +void KX_GameObject::NodeUpdate() +{ + m_sgNode->UpdateWorldData(); +} -void KX_GameObject::NodeUpdateGS(double time) +const mt::mat3& KX_GameObject::NodeGetWorldOrientation() const { - if (GetSGNode()) - GetSGNode()->UpdateWorldData(time); + return m_sgNode->GetWorldOrientation(); } +const mt::mat3& KX_GameObject::NodeGetLocalOrientation() const +{ + return m_sgNode->GetLocalOrientation(); +} +const mt::vec3& KX_GameObject::NodeGetWorldScaling() const +{ + return m_sgNode->GetWorldScaling(); +} -const MT_Matrix3x3& KX_GameObject::NodeGetWorldOrientation() const +const mt::vec3& KX_GameObject::NodeGetLocalScaling() const { - // check on valid node in case a python controller holds a reference to a deleted object - if (!GetSGNode()) - return dummy_orientation; - return GetSGNode()->GetWorldOrientation(); + return m_sgNode->GetLocalScale(); } -const MT_Matrix3x3& KX_GameObject::NodeGetLocalOrientation() const +const mt::vec3& KX_GameObject::NodeGetWorldPosition() const { - // check on valid node in case a python controller holds a reference to a deleted object - if (!GetSGNode()) - return dummy_orientation; - return GetSGNode()->GetLocalOrientation(); + return m_sgNode->GetWorldPosition(); } -const MT_Vector3& KX_GameObject::NodeGetWorldScaling() const +const mt::vec3& KX_GameObject::NodeGetLocalPosition() const { - // check on valid node in case a python controller holds a reference to a deleted object - if (!GetSGNode()) - return dummy_scaling; + return m_sgNode->GetLocalPosition(); +} - return GetSGNode()->GetWorldScaling(); +mt::mat3x4 KX_GameObject::NodeGetWorldTransform() const +{ + return m_sgNode->GetWorldTransform(); } -const MT_Vector3& KX_GameObject::NodeGetLocalScaling() const +mt::mat3x4 KX_GameObject::NodeGetLocalTransform() const { - // check on valid node in case a python controller holds a reference to a deleted object - if (!GetSGNode()) - return dummy_scaling; + return m_sgNode->GetLocalTransform(); +} - return GetSGNode()->GetLocalScale(); +Object *KX_GameObject::GetBlenderObject() const +{ + // Non converted objects has default camera doesn't have convert info. + return (m_convertInfo) ? m_convertInfo->m_blenderObject : nullptr; } -const MT_Point3& KX_GameObject::NodeGetWorldPosition() const +BL_ConvertObjectInfo *KX_GameObject::GetConvertObjectInfo() const { - // check on valid node in case a python controller holds a reference to a deleted object - if (GetSGNode()) - return GetSGNode()->GetWorldPosition(); - else - return dummy_point; + return m_convertInfo; } -const MT_Point3& KX_GameObject::NodeGetLocalPosition() const +void KX_GameObject::SetConvertObjectInfo(BL_ConvertObjectInfo *info) { - // check on valid node in case a python controller holds a reference to a deleted object - if (GetSGNode()) - return GetSGNode()->GetLocalPosition(); - else - return dummy_point; + m_convertInfo = info; +} + +void KX_GameObject::SetNode(SG_Node *node) +{ + m_sgNode.reset(node); +} + +void KX_GameObject::UpdateBounds(bool force) +{ + if ((!m_autoUpdateBounds && !force) || !m_meshUser) { + return; + } + + RAS_BoundingBox *boundingBox = m_meshUser->GetBoundingBox(); + if (!boundingBox || (!boundingBox->GetModified() && !force)) { + return; + } + + RAS_Deformer *deformer = GetDeformer(); + if (deformer) { + /** Update all the deformer, not only per material. + * One of the side effect is to clear some flags about AABB calculation. + * like in KX_SoftBodyDeformer. + */ + deformer->UpdateBuckets(); + } + + // AABB Box : min/max. + mt::vec3 aabbMin; + mt::vec3 aabbMax; + + boundingBox->GetAabb(aabbMin, aabbMax); + + SetBoundsAabb(aabbMin, aabbMax); +} + +void KX_GameObject::SetBoundsAabb(const mt::vec3 &aabbMin, const mt::vec3 &aabbMax) +{ + // Set the AABB in culling node box. + m_cullingNode.GetAabb().Set(aabbMin, aabbMax); + + // Synchronize the AABB with the graphic controller. + if (m_graphicController) { + m_graphicController->SetLocalAabb(aabbMin, aabbMax); + } +} + +void KX_GameObject::GetBoundsAabb(mt::vec3 &aabbMin, mt::vec3 &aabbMax) const +{ + // Get the culling node box AABB + m_cullingNode.GetAabb().Get(aabbMin, aabbMax); +} + +SG_CullingNode& KX_GameObject::GetCullingNode() +{ + return m_cullingNode; } +KX_GameObject::ActivityCullingInfo& KX_GameObject::GetActivityCullingInfo() +{ + return m_activityCullingInfo; +} + +void KX_GameObject::SetActivityCullingInfo(const ActivityCullingInfo& cullingInfo) +{ + m_activityCullingInfo = cullingInfo; +} + +void KX_GameObject::SetActivityCulling(ActivityCullingInfo::Flag flag, bool enable) +{ + if (enable) { + m_activityCullingInfo.m_flags = (ActivityCullingInfo::Flag)(m_activityCullingInfo.m_flags | flag); + } + else { + m_activityCullingInfo.m_flags = (ActivityCullingInfo::Flag)(m_activityCullingInfo.m_flags & ~flag); + + // Restore physics or logic when disabling activity culling. + if (flag & ActivityCullingInfo::ACTIVITY_PHYSICS) { + RestorePhysics(); + } + if (flag & ActivityCullingInfo::ACTIVITY_LOGIC) { + ResumeLogic(); + } + } +} + +void KX_GameObject::SuspendPhysics(bool freeConstraints) +{ + if (m_physicsController) { + m_physicsController->SuspendPhysics((bool)freeConstraints); + } +} + +void KX_GameObject::RestorePhysics() +{ + if (m_physicsController) { + m_physicsController->RestorePhysics(); + } +} void KX_GameObject::UnregisterCollisionCallbacks() { - if (!GetPhysicsController()) { - printf("Warning, trying to unregister collision callbacks for object without collisions: %s!\n", GetName().ReadPtr()); + if (!m_physicsController) { + CM_Warning("trying to unregister collision callbacks for object without collisions: " << GetName()); return; } // Unregister from callbacks - KX_Scene* scene = GetScene(); - PHY_IPhysicsEnvironment* pe = scene->GetPhysicsEnvironment(); - PHY_IPhysicsController* spc = GetPhysicsController(); + KX_Scene *scene = GetScene(); + PHY_IPhysicsEnvironment *pe = scene->GetPhysicsEnvironment(); + PHY_IPhysicsController *spc = m_physicsController.get(); // If we are the last to unregister on this physics controller if (pe->RemoveCollisionCallback(spc)) { // If we are a sensor object - if (m_pClient_info->isSensor()) + if (m_clientInfo.isSensor()) { // Remove sensor body from physics world pe->RemoveSensor(spc); + } } } void KX_GameObject::RegisterCollisionCallbacks() { - if (!GetPhysicsController()) { - printf("Warning, trying to register collision callbacks for object without collisions: %s!\n", GetName().ReadPtr()); + if (!m_physicsController) { + CM_Warning("trying to register collision callbacks for object without collisions: " << GetName()); return; } // Register from callbacks - KX_Scene* scene = GetScene(); - PHY_IPhysicsEnvironment* pe = scene->GetPhysicsEnvironment(); - PHY_IPhysicsController* spc = GetPhysicsController(); + KX_Scene *scene = GetScene(); + PHY_IPhysicsEnvironment *pe = scene->GetPhysicsEnvironment(); + PHY_IPhysicsController *spc = m_physicsController.get(); // If we are the first to register on this physics controller if (pe->RequestCollisionCallback(spc)) { // If we are a sensor object - if (m_pClient_info->isSensor()) + if (m_clientInfo.isSensor()) { // Add sensor body to physics world pe->AddSensor(spc); + } } } -void KX_GameObject::RunCollisionCallbacks(KX_GameObject *collider, const MT_Vector3 &point, const MT_Vector3 &normal) +void KX_GameObject::RunCollisionCallbacks(KX_GameObject *collider, KX_CollisionContactPointList& contactPointList) { #ifdef WITH_PYTHON - if (!m_collisionCallbacks || PyList_GET_SIZE(m_collisionCallbacks) == 0) + if (!m_collisionCallbacks || PyList_GET_SIZE(m_collisionCallbacks) == 0) { return; + } + + const PHY_ICollData *collData = contactPointList.GetCollData(); + const bool isFirstObject = contactPointList.GetFirstObject(); - PyObject *args[] = {collider->GetProxy(), PyObjectFrom(point), PyObjectFrom(normal)}; - RunPythonCallBackList(m_collisionCallbacks, args, 1, ARRAY_SIZE(args)); + PyObject *args[] = {collider->GetProxy(), + PyObjectFrom(collData->GetWorldPoint(0, isFirstObject)), + PyObjectFrom(collData->GetNormal(0, isFirstObject)), + contactPointList.GetProxy()}; + EXP_RunPythonCallBackList(m_collisionCallbacks, args, 1, ARRAY_SIZE(args)); for (unsigned int i = 0; i < ARRAY_SIZE(args); ++i) { Py_DECREF(args[i]); } -#endif -} - -/* Suspend/ resume: for the dynamic behavior, there is a simple - * method. For the residual motion, there is not. I wonder what the - * correct solution is for Sumo. Remove from the motion-update tree? - * - * So far, only switch the physics and logic. - * */ - -void KX_GameObject::Resume(void) -{ - if (m_suspended) { - SCA_IObject::Resume(); - // Child objects must be static, so we block changing to dynamic - if (GetPhysicsController() && !GetParent()) - GetPhysicsController()->RestoreDynamics(); - m_suspended = false; - } + // Invalidate the collison contact point to avoid access to it in next frame + contactPointList.InvalidateProxy(); +#endif } -void KX_GameObject::Suspend() +template +static void walk_children(const SG_Node *node, std::vector& list) { - if ((!m_ignore_activity_culling) && (!m_suspended)) { - SCA_IObject::Suspend(); - if (GetPhysicsController()) - GetPhysicsController()->SuspendDynamics(); - m_suspended = true; + if (!node) { + return; } -} -static void walk_children(SG_Node* node, CListValue* list, bool recursive) -{ - if (!node) - return; - NodeList& children = node->GetSGChildren(); + const NodeList& children = node->GetChildren(); - for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) - { - SG_Node* childnode = (*childit); - CValue* childobj = (CValue*)childnode->GetSGClientObject(); - if (childobj != NULL) // This is a GameObject - { - // add to the list - list->Add(childobj->AddRef()); + for (SG_Node *childnode : children) { + KX_GameObject *childobj = static_cast(childnode->GetClientObject()); + if (childobj) { + list.push_back(childobj); } - // if the childobj is NULL then this may be an inverse parent link - // so a non recursive search should still look down this node. - if (recursive || childobj==NULL) { - walk_children(childnode, list, recursive); + /* If the childobj is nullptr then this may be an inverse parent link + * so a non recursive search should still look down this node. */ + if (recursive || !childobj) { + walk_children(childnode, list); } } } -CListValue* KX_GameObject::GetChildren() +std::vector KX_GameObject::GetChildren() const { - CListValue* list = new CListValue(); - walk_children(GetSGNode(), list, 0); /* GetSGNode() is always valid or it would have raised an exception before this */ + std::vector list; + walk_children(m_sgNode.get(), list); return list; } -CListValue* KX_GameObject::GetChildrenRecursive() +std::vector KX_GameObject::GetChildrenRecursive() const { - CListValue* list = new CListValue(); - walk_children(GetSGNode(), list, 1); + std::vector list; + walk_children(m_sgNode.get(), list); return list; } -KX_Scene* KX_GameObject::GetScene() +EXP_ListValue *KX_GameObject::GetComponents() const +{ + return m_components; +} + +void KX_GameObject::SetComponents(EXP_ListValue *components) +{ + m_components = components; +} + +void KX_GameObject::UpdateComponents() { - SG_Node* node = this->GetSGNode(); - if (node == NULL) { - // this happens for object in non active layers, rely on static scene then - return KX_GetActiveScene(); +#ifdef WITH_PYTHON + if (!m_components) { + return; + } + + for (KX_PythonComponent *comp : m_components) { + comp->Update(); } - return static_cast(node->GetSGClientInfo()); + +#endif // WITH_PYTHON +} + +KX_Scene *KX_GameObject::GetScene() +{ + BLI_assert(m_sgNode); + return static_cast(m_sgNode->GetClientInfo()); } /* --------------------------------------------------------------------- * Some stuff taken from the header * --------------------------------------------------------------------- */ -void KX_GameObject::Relink(CTR_Map *map_parameter) +void KX_GameObject::Relink(std::map& map_parameter) { // we will relink the sensors and actuators that use object references // if the object is part of the replicated hierarchy, use the new // object reference instead SCA_SensorList& sensorlist = GetSensors(); SCA_SensorList::iterator sit; - for (sit=sensorlist.begin(); sit != sensorlist.end(); sit++) + for (sit = sensorlist.begin(); sit != sensorlist.end(); sit++) { (*sit)->Relink(map_parameter); } SCA_ActuatorList& actuatorlist = GetActuators(); SCA_ActuatorList::iterator ait; - for (ait=actuatorlist.begin(); ait != actuatorlist.end(); ait++) + for (ait = actuatorlist.begin(); ait != actuatorlist.end(); ait++) { (*ait)->Relink(map_parameter); } } +#ifdef WITH_PYTHON + +#define PYTHON_CHECK_PHYSICS_CONTROLLER(obj, attr, ret) \ + if (!(obj)->GetPhysicsController()) { \ + PyErr_Format(PyExc_AttributeError, "KX_GameObject.%s, is missing a physics controller", (attr)); \ + return (ret); \ + } + +#endif + #ifdef USE_MATHUTILS /* These require an SGNode */ @@ -1718,62 +1667,89 @@ void KX_GameObject::Relink(CTR_Map *map_parameter) #define MATHUTILS_VEC_CB_LINVEL_GLOBAL 8 #define MATHUTILS_VEC_CB_ANGVEL_LOCAL 9 #define MATHUTILS_VEC_CB_ANGVEL_GLOBAL 10 +#define MATHUTILS_VEC_CB_GRAVITY 11 -static unsigned char mathutils_kxgameob_vector_cb_index= -1; /* index for our callbacks */ +static unsigned char mathutils_kxgameob_vector_cb_index = -1; /* index for our callbacks */ static int mathutils_kxgameob_generic_check(BaseMathObject *bmo) { - KX_GameObject* self = static_castBGE_PROXY_REF(bmo->cb_user); - if (self == NULL) + KX_GameObject *self = static_castEXP_PROXY_REF(bmo->cb_user); + if (self == nullptr) { return -1; + } return 0; } static int mathutils_kxgameob_vector_get(BaseMathObject *bmo, int subtype) { - KX_GameObject* self = static_castBGE_PROXY_REF(bmo->cb_user); - if (self == NULL) + KX_GameObject *self = static_castEXP_PROXY_REF(bmo->cb_user); + if (self == nullptr) { return -1; - -#define PHYS_ERR(attr) PyErr_SetString(PyExc_AttributeError, "KX_GameObject." attr ", is missing a physics controller") + } switch (subtype) { case MATHUTILS_VEC_CB_POS_LOCAL: - self->NodeGetLocalPosition().getValue(bmo->data); + { + self->NodeGetLocalPosition().Pack(bmo->data); break; + } case MATHUTILS_VEC_CB_POS_GLOBAL: - self->NodeGetWorldPosition().getValue(bmo->data); + { + self->NodeGetWorldPosition().Pack(bmo->data); break; + } case MATHUTILS_VEC_CB_SCALE_LOCAL: - self->NodeGetLocalScaling().getValue(bmo->data); + { + self->NodeGetLocalScaling().Pack(bmo->data); break; + } case MATHUTILS_VEC_CB_SCALE_GLOBAL: - self->NodeGetWorldScaling().getValue(bmo->data); + { + self->NodeGetWorldScaling().Pack(bmo->data); break; + } case MATHUTILS_VEC_CB_INERTIA_LOCAL: - if (!self->GetPhysicsController()) return PHYS_ERR("localInertia"), -1; - self->GetPhysicsController()->GetLocalInertia().getValue(bmo->data); + { + PYTHON_CHECK_PHYSICS_CONTROLLER(self, "localInertia", -1); + self->GetLocalInertia().Pack(bmo->data); break; + } case MATHUTILS_VEC_CB_OBJECT_COLOR: - self->GetObjectColor().getValue(bmo->data); + { + self->GetObjectColor().Pack(bmo->data); break; + } case MATHUTILS_VEC_CB_LINVEL_LOCAL: - if (!self->GetPhysicsController()) return PHYS_ERR("localLinearVelocity"), -1; - self->GetLinearVelocity(true).getValue(bmo->data); + { + PYTHON_CHECK_PHYSICS_CONTROLLER(self, "localLinearVelocity", -1); + self->GetLinearVelocity(true).Pack(bmo->data); break; + } case MATHUTILS_VEC_CB_LINVEL_GLOBAL: - if (!self->GetPhysicsController()) return PHYS_ERR("worldLinearVelocity"), -1; - self->GetLinearVelocity(false).getValue(bmo->data); + { + PYTHON_CHECK_PHYSICS_CONTROLLER(self, "worldLinearVelocity", -1); + self->GetLinearVelocity(false).Pack(bmo->data); break; + } case MATHUTILS_VEC_CB_ANGVEL_LOCAL: - if (!self->GetPhysicsController()) return PHYS_ERR("localLinearVelocity"), -1; - self->GetAngularVelocity(true).getValue(bmo->data); + { + PYTHON_CHECK_PHYSICS_CONTROLLER(self, "localLinearVelocity", -1); + self->GetAngularVelocity(true).Pack(bmo->data); break; + } case MATHUTILS_VEC_CB_ANGVEL_GLOBAL: - if (!self->GetPhysicsController()) return PHYS_ERR("worldLinearVelocity"), -1; - self->GetAngularVelocity(false).getValue(bmo->data); + { + PYTHON_CHECK_PHYSICS_CONTROLLER(self, "worldLinearVelocity", -1); + self->GetAngularVelocity(false).Pack(bmo->data); + break; + } + case MATHUTILS_VEC_CB_GRAVITY: + { + PYTHON_CHECK_PHYSICS_CONTROLLER(self, "gravity", -1); + self->GetGravity().Pack(bmo->data); break; + } } @@ -1784,44 +1760,71 @@ static int mathutils_kxgameob_vector_get(BaseMathObject *bmo, int subtype) static int mathutils_kxgameob_vector_set(BaseMathObject *bmo, int subtype) { - KX_GameObject* self = static_castBGE_PROXY_REF(bmo->cb_user); - if (self == NULL) + KX_GameObject *self = static_castEXP_PROXY_REF(bmo->cb_user); + if (self == nullptr) { return -1; + } switch (subtype) { case MATHUTILS_VEC_CB_POS_LOCAL: - self->NodeSetLocalPosition(MT_Point3(bmo->data)); - self->NodeUpdateGS(0.f); + { + self->NodeSetLocalPosition(mt::vec3(bmo->data)); + self->NodeUpdate(); break; + } case MATHUTILS_VEC_CB_POS_GLOBAL: - self->NodeSetWorldPosition(MT_Point3(bmo->data)); - self->NodeUpdateGS(0.f); + { + self->NodeSetWorldPosition(mt::vec3(bmo->data)); + self->NodeUpdate(); break; + } case MATHUTILS_VEC_CB_SCALE_LOCAL: - self->NodeSetLocalScale(MT_Point3(bmo->data)); - self->NodeUpdateGS(0.f); + { + self->NodeSetLocalScale(mt::vec3(bmo->data)); + self->NodeUpdate(); break; + } case MATHUTILS_VEC_CB_SCALE_GLOBAL: - PyErr_SetString(PyExc_AttributeError, "KX_GameObject.worldScale is read-only"); - return -1; + { + self->NodeSetWorldScale(mt::vec3(bmo->data)); + self->NodeUpdate(); + break; + } case MATHUTILS_VEC_CB_INERTIA_LOCAL: + { /* read only */ break; + } case MATHUTILS_VEC_CB_OBJECT_COLOR: - self->SetObjectColor(MT_Vector4(bmo->data)); + { + self->SetObjectColor(mt::vec4(bmo->data)); break; + } case MATHUTILS_VEC_CB_LINVEL_LOCAL: - self->setLinearVelocity(MT_Point3(bmo->data),true); + { + self->SetLinearVelocity(mt::vec3(bmo->data), true); break; + } case MATHUTILS_VEC_CB_LINVEL_GLOBAL: - self->setLinearVelocity(MT_Point3(bmo->data),false); + { + self->SetLinearVelocity(mt::vec3(bmo->data), false); break; + } case MATHUTILS_VEC_CB_ANGVEL_LOCAL: - self->setAngularVelocity(MT_Point3(bmo->data),true); + { + self->SetAngularVelocity(mt::vec3(bmo->data), true); break; + } case MATHUTILS_VEC_CB_ANGVEL_GLOBAL: - self->setAngularVelocity(MT_Point3(bmo->data),false); + { + self->SetAngularVelocity(mt::vec3(bmo->data), false); + break; + } + case MATHUTILS_VEC_CB_GRAVITY: + { + self->SetGravity(mt::vec3(bmo->data)); break; + } } return 0; @@ -1830,18 +1833,20 @@ static int mathutils_kxgameob_vector_set(BaseMathObject *bmo, int subtype) static int mathutils_kxgameob_vector_get_index(BaseMathObject *bmo, int subtype, int index) { /* lazy, avoid repeteing the case statement */ - if (mathutils_kxgameob_vector_get(bmo, subtype) == -1) + if (mathutils_kxgameob_vector_get(bmo, subtype) == -1) { return -1; + } return 0; } static int mathutils_kxgameob_vector_set_index(BaseMathObject *bmo, int subtype, int index) { - float f= bmo->data[index]; + float f = bmo->data[index]; /* lazy, avoid repeteing the case statement */ - if (mathutils_kxgameob_vector_get(bmo, subtype) == -1) + if (mathutils_kxgameob_vector_get(bmo, subtype) == -1) { return -1; + } bmo->data[index] = f; return mathutils_kxgameob_vector_set(bmo, subtype); @@ -1859,21 +1864,26 @@ static Mathutils_Callback mathutils_kxgameob_vector_cb = { #define MATHUTILS_MAT_CB_ORI_LOCAL 1 #define MATHUTILS_MAT_CB_ORI_GLOBAL 2 -static unsigned char mathutils_kxgameob_matrix_cb_index= -1; /* index for our callbacks */ +static unsigned char mathutils_kxgameob_matrix_cb_index = -1; /* index for our callbacks */ static int mathutils_kxgameob_matrix_get(BaseMathObject *bmo, int subtype) { - KX_GameObject* self = static_castBGE_PROXY_REF(bmo->cb_user); - if (self == NULL) + KX_GameObject *self = static_castEXP_PROXY_REF(bmo->cb_user); + if (self == nullptr) { return -1; + } switch (subtype) { case MATHUTILS_MAT_CB_ORI_LOCAL: - self->NodeGetLocalOrientation().getValue3x3(bmo->data); + { + self->NodeGetLocalOrientation().Pack(bmo->data); break; + } case MATHUTILS_MAT_CB_ORI_GLOBAL: - self->NodeGetWorldOrientation().getValue3x3(bmo->data); + { + self->NodeGetWorldOrientation().Pack(bmo->data); break; + } } return 0; @@ -1882,22 +1892,27 @@ static int mathutils_kxgameob_matrix_get(BaseMathObject *bmo, int subtype) static int mathutils_kxgameob_matrix_set(BaseMathObject *bmo, int subtype) { - KX_GameObject* self = static_castBGE_PROXY_REF(bmo->cb_user); - if (self == NULL) + KX_GameObject *self = static_castEXP_PROXY_REF(bmo->cb_user); + if (self == nullptr) { return -1; + } - MT_Matrix3x3 mat3x3; + mt::mat3 mat3x3; switch (subtype) { case MATHUTILS_MAT_CB_ORI_LOCAL: - mat3x3.setValue3x3(bmo->data); + { + mat3x3 = mt::mat3(bmo->data); self->NodeSetLocalOrientation(mat3x3); - self->NodeUpdateGS(0.f); + self->NodeUpdate(); break; + } case MATHUTILS_MAT_CB_ORI_GLOBAL: - mat3x3.setValue3x3(bmo->data); + { + mat3x3 = mt::mat3(bmo->data); self->NodeSetLocalOrientation(mat3x3); - self->NodeUpdateGS(0.f); + self->NodeUpdate(); break; + } } return 0; @@ -1907,16 +1922,16 @@ static Mathutils_Callback mathutils_kxgameob_matrix_cb = { mathutils_kxgameob_generic_check, mathutils_kxgameob_matrix_get, mathutils_kxgameob_matrix_set, - NULL, - NULL + nullptr, + nullptr }; void KX_GameObject_Mathutils_Callback_Init(void) { // register mathutils callbacks, ok to run more than once. - mathutils_kxgameob_vector_cb_index= Mathutils_RegisterCallback(&mathutils_kxgameob_vector_cb); - mathutils_kxgameob_matrix_cb_index= Mathutils_RegisterCallback(&mathutils_kxgameob_matrix_cb); + mathutils_kxgameob_vector_cb_index = Mathutils_RegisterCallback(&mathutils_kxgameob_vector_cb); + mathutils_kxgameob_matrix_cb_index = Mathutils_RegisterCallback(&mathutils_kxgameob_matrix_cb); } #endif // USE_MATHUTILS @@ -1924,195 +1939,234 @@ void KX_GameObject_Mathutils_Callback_Init(void) #ifdef WITH_PYTHON /* ------- python stuff ---------------------------------------------------*/ PyMethodDef KX_GameObject::Methods[] = { - {"applyForce", (PyCFunction) KX_GameObject::sPyApplyForce, METH_VARARGS}, - {"applyTorque", (PyCFunction) KX_GameObject::sPyApplyTorque, METH_VARARGS}, - {"applyRotation", (PyCFunction) KX_GameObject::sPyApplyRotation, METH_VARARGS}, - {"applyMovement", (PyCFunction) KX_GameObject::sPyApplyMovement, METH_VARARGS}, - {"getLinearVelocity", (PyCFunction) KX_GameObject::sPyGetLinearVelocity, METH_VARARGS}, - {"setLinearVelocity", (PyCFunction) KX_GameObject::sPySetLinearVelocity, METH_VARARGS}, - {"getAngularVelocity", (PyCFunction) KX_GameObject::sPyGetAngularVelocity, METH_VARARGS}, - {"setAngularVelocity", (PyCFunction) KX_GameObject::sPySetAngularVelocity, METH_VARARGS}, - {"getVelocity", (PyCFunction) KX_GameObject::sPyGetVelocity, METH_VARARGS}, - {"setDamping", (PyCFunction) KX_GameObject::sPySetDamping, METH_VARARGS}, - {"getReactionForce", (PyCFunction) KX_GameObject::sPyGetReactionForce, METH_NOARGS}, - {"alignAxisToVect",(PyCFunction) KX_GameObject::sPyAlignAxisToVect, METH_VARARGS}, - {"getAxisVect",(PyCFunction) KX_GameObject::sPyGetAxisVect, METH_O}, + {"applyForce", (PyCFunction)KX_GameObject::sPyApplyForce, METH_VARARGS}, + {"applyTorque", (PyCFunction)KX_GameObject::sPyApplyTorque, METH_VARARGS}, + {"applyRotation", (PyCFunction)KX_GameObject::sPyApplyRotation, METH_VARARGS}, + {"applyMovement", (PyCFunction)KX_GameObject::sPyApplyMovement, METH_VARARGS}, + {"getLinearVelocity", (PyCFunction)KX_GameObject::sPyGetLinearVelocity, METH_VARARGS}, + {"setLinearVelocity", (PyCFunction)KX_GameObject::sPySetLinearVelocity, METH_VARARGS}, + {"getAngularVelocity", (PyCFunction)KX_GameObject::sPyGetAngularVelocity, METH_VARARGS}, + {"setAngularVelocity", (PyCFunction)KX_GameObject::sPySetAngularVelocity, METH_VARARGS}, + {"getVelocity", (PyCFunction)KX_GameObject::sPyGetVelocity, METH_VARARGS}, + {"setDamping", (PyCFunction)KX_GameObject::sPySetDamping, METH_VARARGS}, + {"getReactionForce", (PyCFunction)KX_GameObject::sPyGetReactionForce, METH_NOARGS}, + {"alignAxisToVect", (PyCFunction)KX_GameObject::sPyAlignAxisToVect, METH_VARARGS | METH_KEYWORDS}, + {"getAxisVect", (PyCFunction)KX_GameObject::sPyGetAxisVect, METH_O}, + {"suspendPhysics", (PyCFunction)KX_GameObject::sPySuspendPhysics, METH_VARARGS}, + {"restorePhysics", (PyCFunction)KX_GameObject::sPyRestorePhysics, METH_NOARGS}, {"suspendDynamics", (PyCFunction)KX_GameObject::sPySuspendDynamics, METH_VARARGS}, - {"restoreDynamics", (PyCFunction)KX_GameObject::sPyRestoreDynamics,METH_NOARGS}, - {"enableRigidBody", (PyCFunction)KX_GameObject::sPyEnableRigidBody,METH_NOARGS}, - {"disableRigidBody", (PyCFunction)KX_GameObject::sPyDisableRigidBody,METH_NOARGS}, - {"applyImpulse", (PyCFunction) KX_GameObject::sPyApplyImpulse, METH_VARARGS}, - {"setCollisionMargin", (PyCFunction) KX_GameObject::sPySetCollisionMargin, METH_O}, - {"setParent", (PyCFunction)KX_GameObject::sPySetParent,METH_VARARGS}, - {"setVisible",(PyCFunction) KX_GameObject::sPySetVisible, METH_VARARGS}, - {"setOcclusion",(PyCFunction) KX_GameObject::sPySetOcclusion, METH_VARARGS}, - {"removeParent", (PyCFunction)KX_GameObject::sPyRemoveParent,METH_NOARGS}, - - - {"getPhysicsId", (PyCFunction)KX_GameObject::sPyGetPhysicsId,METH_NOARGS}, - {"getPropertyNames", (PyCFunction)KX_GameObject::sPyGetPropertyNames,METH_NOARGS}, - {"replaceMesh",(PyCFunction) KX_GameObject::sPyReplaceMesh, METH_VARARGS}, - {"endObject",(PyCFunction) KX_GameObject::sPyEndObject, METH_NOARGS}, - {"reinstancePhysicsMesh", (PyCFunction)KX_GameObject::sPyReinstancePhysicsMesh,METH_VARARGS}, - - KX_PYMETHODTABLE(KX_GameObject, rayCastTo), - KX_PYMETHODTABLE(KX_GameObject, rayCast), - KX_PYMETHODTABLE_O(KX_GameObject, getDistanceTo), - KX_PYMETHODTABLE_O(KX_GameObject, getVectTo), - KX_PYMETHODTABLE(KX_GameObject, sendMessage), - KX_PYMETHODTABLE(KX_GameObject, addDebugProperty), - - KX_PYMETHODTABLE_KEYWORDS(KX_GameObject, playAction), - KX_PYMETHODTABLE(KX_GameObject, stopAction), - KX_PYMETHODTABLE(KX_GameObject, getActionFrame), - KX_PYMETHODTABLE(KX_GameObject, getActionName), - KX_PYMETHODTABLE(KX_GameObject, setActionFrame), - KX_PYMETHODTABLE(KX_GameObject, isPlayingAction), + {"restoreDynamics", (PyCFunction)KX_GameObject::sPyRestoreDynamics, METH_NOARGS}, + {"enableRigidBody", (PyCFunction)KX_GameObject::sPyEnableRigidBody, METH_NOARGS}, + {"disableRigidBody", (PyCFunction)KX_GameObject::sPyDisableRigidBody, METH_NOARGS}, + {"applyImpulse", (PyCFunction)KX_GameObject::sPyApplyImpulse, METH_VARARGS}, + {"setCollisionMargin", (PyCFunction)KX_GameObject::sPySetCollisionMargin, METH_O}, + {"collide", (PyCFunction)KX_GameObject::sPyCollide, METH_O}, + {"setParent", (PyCFunction)KX_GameObject::sPySetParent, METH_VARARGS | METH_KEYWORDS}, + {"setVisible", (PyCFunction)KX_GameObject::sPySetVisible, METH_VARARGS}, + {"setOcclusion", (PyCFunction)KX_GameObject::sPySetOcclusion, METH_VARARGS}, + {"removeParent", (PyCFunction)KX_GameObject::sPyRemoveParent, METH_NOARGS}, + + + {"getPhysicsId", (PyCFunction)KX_GameObject::sPyGetPhysicsId, METH_NOARGS}, + {"getPropertyNames", (PyCFunction)KX_GameObject::sPyGetPropertyNames, METH_NOARGS}, + {"replaceMesh", (PyCFunction)KX_GameObject::sPyReplaceMesh, METH_VARARGS | METH_KEYWORDS}, + {"endObject", (PyCFunction)KX_GameObject::sPyEndObject, METH_NOARGS}, + {"reinstancePhysicsMesh", (PyCFunction)KX_GameObject::sPyReinstancePhysicsMesh, METH_VARARGS | METH_KEYWORDS}, + {"replacePhysicsShape", (PyCFunction)KX_GameObject::sPyReplacePhysicsShape, METH_O}, + + EXP_PYMETHODTABLE_KEYWORDS(KX_GameObject, rayCastTo), + EXP_PYMETHODTABLE_KEYWORDS(KX_GameObject, rayCast), + EXP_PYMETHODTABLE_O(KX_GameObject, getDistanceTo), + EXP_PYMETHODTABLE_O(KX_GameObject, getVectTo), + EXP_PYMETHODTABLE_KEYWORDS(KX_GameObject, sendMessage), + EXP_PYMETHODTABLE(KX_GameObject, addDebugProperty), + + EXP_PYMETHODTABLE_KEYWORDS(KX_GameObject, playAction), + EXP_PYMETHODTABLE(KX_GameObject, stopAction), + EXP_PYMETHODTABLE(KX_GameObject, getActionFrame), + EXP_PYMETHODTABLE(KX_GameObject, getActionName), + EXP_PYMETHODTABLE(KX_GameObject, setActionFrame), + EXP_PYMETHODTABLE(KX_GameObject, isPlayingAction), // dict style access for props - {"get",(PyCFunction) KX_GameObject::sPyget, METH_VARARGS}, + {"get", (PyCFunction)KX_GameObject::sPyget, METH_VARARGS}, - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_GameObject::Attributes[] = { - KX_PYATTRIBUTE_INT_RO("currentLodLevel", KX_GameObject, m_currentLodLevel), - KX_PYATTRIBUTE_RO_FUNCTION("name", KX_GameObject, pyattr_get_name), - KX_PYATTRIBUTE_RO_FUNCTION("parent", KX_GameObject, pyattr_get_parent), - KX_PYATTRIBUTE_RO_FUNCTION("groupMembers", KX_GameObject, pyattr_get_group_members), - KX_PYATTRIBUTE_RO_FUNCTION("groupObject", KX_GameObject, pyattr_get_group_object), - KX_PYATTRIBUTE_RO_FUNCTION("scene", KX_GameObject, pyattr_get_scene), - KX_PYATTRIBUTE_RO_FUNCTION("life", KX_GameObject, pyattr_get_life), - KX_PYATTRIBUTE_RW_FUNCTION("mass", KX_GameObject, pyattr_get_mass, pyattr_set_mass), - KX_PYATTRIBUTE_RO_FUNCTION("isSuspendDynamics", KX_GameObject, pyattr_get_is_suspend_dynamics), - KX_PYATTRIBUTE_RW_FUNCTION("linVelocityMin", KX_GameObject, pyattr_get_lin_vel_min, pyattr_set_lin_vel_min), - KX_PYATTRIBUTE_RW_FUNCTION("linVelocityMax", KX_GameObject, pyattr_get_lin_vel_max, pyattr_set_lin_vel_max), - KX_PYATTRIBUTE_RW_FUNCTION("angularVelocityMin", KX_GameObject, pyattr_get_ang_vel_min, pyattr_set_ang_vel_min), - KX_PYATTRIBUTE_RW_FUNCTION("angularVelocityMax", KX_GameObject, pyattr_get_ang_vel_max, pyattr_set_ang_vel_max), - KX_PYATTRIBUTE_RW_FUNCTION("visible", KX_GameObject, pyattr_get_visible, pyattr_set_visible), - KX_PYATTRIBUTE_RW_FUNCTION("record_animation", KX_GameObject, pyattr_get_record_animation, pyattr_set_record_animation), - KX_PYATTRIBUTE_BOOL_RW ("occlusion", KX_GameObject, m_bOccluder), - KX_PYATTRIBUTE_RW_FUNCTION("position", KX_GameObject, pyattr_get_worldPosition, pyattr_set_localPosition), - KX_PYATTRIBUTE_RO_FUNCTION("localInertia", KX_GameObject, pyattr_get_localInertia), - KX_PYATTRIBUTE_RW_FUNCTION("orientation",KX_GameObject,pyattr_get_worldOrientation,pyattr_set_localOrientation), - KX_PYATTRIBUTE_RW_FUNCTION("scaling", KX_GameObject, pyattr_get_worldScaling, pyattr_set_localScaling), - KX_PYATTRIBUTE_RW_FUNCTION("timeOffset",KX_GameObject, pyattr_get_timeOffset,pyattr_set_timeOffset), - KX_PYATTRIBUTE_RW_FUNCTION("collisionCallbacks", KX_GameObject, pyattr_get_collisionCallbacks, pyattr_set_collisionCallbacks), - KX_PYATTRIBUTE_RW_FUNCTION("collisionGroup", KX_GameObject, pyattr_get_collisionGroup, pyattr_set_collisionGroup), - KX_PYATTRIBUTE_RW_FUNCTION("collisionMask", KX_GameObject, pyattr_get_collisionMask, pyattr_set_collisionMask), - KX_PYATTRIBUTE_RW_FUNCTION("state", KX_GameObject, pyattr_get_state, pyattr_set_state), - KX_PYATTRIBUTE_RO_FUNCTION("meshes", KX_GameObject, pyattr_get_meshes), - KX_PYATTRIBUTE_RW_FUNCTION("localOrientation",KX_GameObject,pyattr_get_localOrientation,pyattr_set_localOrientation), - KX_PYATTRIBUTE_RW_FUNCTION("worldOrientation",KX_GameObject,pyattr_get_worldOrientation,pyattr_set_worldOrientation), - KX_PYATTRIBUTE_RW_FUNCTION("localPosition", KX_GameObject, pyattr_get_localPosition, pyattr_set_localPosition), - KX_PYATTRIBUTE_RW_FUNCTION("worldPosition", KX_GameObject, pyattr_get_worldPosition, pyattr_set_worldPosition), - KX_PYATTRIBUTE_RW_FUNCTION("localScale", KX_GameObject, pyattr_get_localScaling, pyattr_set_localScaling), - KX_PYATTRIBUTE_RW_FUNCTION("worldScale", KX_GameObject, pyattr_get_worldScaling, pyattr_set_worldScaling), - KX_PYATTRIBUTE_RW_FUNCTION("localTransform", KX_GameObject, pyattr_get_localTransform, pyattr_set_localTransform), - KX_PYATTRIBUTE_RW_FUNCTION("worldTransform", KX_GameObject, pyattr_get_worldTransform, pyattr_set_worldTransform), - KX_PYATTRIBUTE_RW_FUNCTION("linearVelocity", KX_GameObject, pyattr_get_localLinearVelocity, pyattr_set_worldLinearVelocity), - KX_PYATTRIBUTE_RW_FUNCTION("localLinearVelocity", KX_GameObject, pyattr_get_localLinearVelocity, pyattr_set_localLinearVelocity), - KX_PYATTRIBUTE_RW_FUNCTION("worldLinearVelocity", KX_GameObject, pyattr_get_worldLinearVelocity, pyattr_set_worldLinearVelocity), - KX_PYATTRIBUTE_RW_FUNCTION("angularVelocity", KX_GameObject, pyattr_get_localAngularVelocity, pyattr_set_worldAngularVelocity), - KX_PYATTRIBUTE_RW_FUNCTION("localAngularVelocity", KX_GameObject, pyattr_get_localAngularVelocity, pyattr_set_localAngularVelocity), - KX_PYATTRIBUTE_RW_FUNCTION("worldAngularVelocity", KX_GameObject, pyattr_get_worldAngularVelocity, pyattr_set_worldAngularVelocity), - KX_PYATTRIBUTE_RW_FUNCTION("linearDamping", KX_GameObject, pyattr_get_linearDamping, pyattr_set_linearDamping), - KX_PYATTRIBUTE_RW_FUNCTION("angularDamping", KX_GameObject, pyattr_get_angularDamping, pyattr_set_angularDamping), - KX_PYATTRIBUTE_RO_FUNCTION("children", KX_GameObject, pyattr_get_children), - KX_PYATTRIBUTE_RO_FUNCTION("childrenRecursive", KX_GameObject, pyattr_get_children_recursive), - KX_PYATTRIBUTE_RO_FUNCTION("attrDict", KX_GameObject, pyattr_get_attrDict), - KX_PYATTRIBUTE_RW_FUNCTION("color", KX_GameObject, pyattr_get_obcolor, pyattr_set_obcolor), - KX_PYATTRIBUTE_RW_FUNCTION("debug", KX_GameObject, pyattr_get_debug, pyattr_set_debug), - KX_PYATTRIBUTE_RW_FUNCTION("debugRecursive", KX_GameObject, pyattr_get_debugRecursive, pyattr_set_debugRecursive), + EXP_PYATTRIBUTE_SHORT_RO("currentLodLevel", KX_GameObject, m_currentLodLevel), + EXP_PYATTRIBUTE_RW_FUNCTION("lodManager", KX_GameObject, pyattr_get_lodManager, pyattr_set_lodManager), + EXP_PYATTRIBUTE_RW_FUNCTION("name", KX_GameObject, pyattr_get_name, pyattr_set_name), + EXP_PYATTRIBUTE_RO_FUNCTION("parent", KX_GameObject, pyattr_get_parent), + EXP_PYATTRIBUTE_RO_FUNCTION("groupMembers", KX_GameObject, pyattr_get_group_members), + EXP_PYATTRIBUTE_RO_FUNCTION("groupObject", KX_GameObject, pyattr_get_group_object), + EXP_PYATTRIBUTE_RO_FUNCTION("scene", KX_GameObject, pyattr_get_scene), + EXP_PYATTRIBUTE_RO_FUNCTION("life", KX_GameObject, pyattr_get_life), + EXP_PYATTRIBUTE_RW_FUNCTION("mass", KX_GameObject, pyattr_get_mass, pyattr_set_mass), + EXP_PYATTRIBUTE_RO_FUNCTION("isSuspendDynamics", KX_GameObject, pyattr_get_is_suspend_dynamics), + EXP_PYATTRIBUTE_RW_FUNCTION("linVelocityMin", KX_GameObject, pyattr_get_lin_vel_min, pyattr_set_lin_vel_min), + EXP_PYATTRIBUTE_RW_FUNCTION("linVelocityMax", KX_GameObject, pyattr_get_lin_vel_max, pyattr_set_lin_vel_max), + EXP_PYATTRIBUTE_RW_FUNCTION("angularVelocityMin", KX_GameObject, pyattr_get_ang_vel_min, pyattr_set_ang_vel_min), + EXP_PYATTRIBUTE_RW_FUNCTION("angularVelocityMax", KX_GameObject, pyattr_get_ang_vel_max, pyattr_set_ang_vel_max), + EXP_PYATTRIBUTE_RW_FUNCTION("layer", KX_GameObject, pyattr_get_layer, pyattr_set_layer), + EXP_PYATTRIBUTE_SHORT_RW("passIndex", 0, SHRT_MAX, false, KX_GameObject, m_passIndex), + EXP_PYATTRIBUTE_RW_FUNCTION("visible", KX_GameObject, pyattr_get_visible, pyattr_set_visible), + EXP_PYATTRIBUTE_RO_FUNCTION("culled", KX_GameObject, pyattr_get_culled), + EXP_PYATTRIBUTE_RO_FUNCTION("cullingBox", KX_GameObject, pyattr_get_cullingBox), + EXP_PYATTRIBUTE_BOOL_RW("occlusion", KX_GameObject, m_bOccluder), + EXP_PYATTRIBUTE_RW_FUNCTION("physicsCullingRadius", KX_GameObject, pyattr_get_physicsCullingRadius, pyattr_set_physicsCullingRadius), + EXP_PYATTRIBUTE_RW_FUNCTION("logicCullingRadius", KX_GameObject, pyattr_get_logicCullingRadius, pyattr_set_logicCullingRadius), + EXP_PYATTRIBUTE_RW_FUNCTION("physicsCulling", KX_GameObject, pyattr_get_physicsCulling, pyattr_set_physicsCulling), + EXP_PYATTRIBUTE_RW_FUNCTION("logicCulling", KX_GameObject, pyattr_get_logicCulling, pyattr_set_logicCulling), + EXP_PYATTRIBUTE_RW_FUNCTION("position", KX_GameObject, pyattr_get_worldPosition, pyattr_set_localPosition), + EXP_PYATTRIBUTE_RO_FUNCTION("localInertia", KX_GameObject, pyattr_get_localInertia), + EXP_PYATTRIBUTE_RW_FUNCTION("orientation", KX_GameObject, pyattr_get_worldOrientation, pyattr_set_localOrientation), + EXP_PYATTRIBUTE_RW_FUNCTION("scaling", KX_GameObject, pyattr_get_worldScaling, pyattr_set_localScaling), + EXP_PYATTRIBUTE_RW_FUNCTION("timeOffset", KX_GameObject, pyattr_get_timeOffset, pyattr_set_timeOffset), + EXP_PYATTRIBUTE_RW_FUNCTION("collisionCallbacks", KX_GameObject, pyattr_get_collisionCallbacks, pyattr_set_collisionCallbacks), + EXP_PYATTRIBUTE_RW_FUNCTION("collisionGroup", KX_GameObject, pyattr_get_collisionGroup, pyattr_set_collisionGroup), + EXP_PYATTRIBUTE_RW_FUNCTION("collisionMask", KX_GameObject, pyattr_get_collisionMask, pyattr_set_collisionMask), + EXP_PYATTRIBUTE_RW_FUNCTION("state", KX_GameObject, pyattr_get_state, pyattr_set_state), + EXP_PYATTRIBUTE_RO_FUNCTION("meshes", KX_GameObject, pyattr_get_meshes), + EXP_PYATTRIBUTE_RO_FUNCTION("batchGroup", KX_GameObject, pyattr_get_batchGroup), + EXP_PYATTRIBUTE_RW_FUNCTION("localOrientation", KX_GameObject, pyattr_get_localOrientation, pyattr_set_localOrientation), + EXP_PYATTRIBUTE_RW_FUNCTION("worldOrientation", KX_GameObject, pyattr_get_worldOrientation, pyattr_set_worldOrientation), + EXP_PYATTRIBUTE_RW_FUNCTION("localPosition", KX_GameObject, pyattr_get_localPosition, pyattr_set_localPosition), + EXP_PYATTRIBUTE_RW_FUNCTION("worldPosition", KX_GameObject, pyattr_get_worldPosition, pyattr_set_worldPosition), + EXP_PYATTRIBUTE_RW_FUNCTION("localScale", KX_GameObject, pyattr_get_localScaling, pyattr_set_localScaling), + EXP_PYATTRIBUTE_RW_FUNCTION("worldScale", KX_GameObject, pyattr_get_worldScaling, pyattr_set_worldScaling), + EXP_PYATTRIBUTE_RW_FUNCTION("localTransform", KX_GameObject, pyattr_get_localTransform, pyattr_set_localTransform), + EXP_PYATTRIBUTE_RW_FUNCTION("worldTransform", KX_GameObject, pyattr_get_worldTransform, pyattr_set_worldTransform), + EXP_PYATTRIBUTE_RW_FUNCTION("linearVelocity", KX_GameObject, pyattr_get_localLinearVelocity, pyattr_set_worldLinearVelocity), + EXP_PYATTRIBUTE_RW_FUNCTION("localLinearVelocity", KX_GameObject, pyattr_get_localLinearVelocity, pyattr_set_localLinearVelocity), + EXP_PYATTRIBUTE_RW_FUNCTION("worldLinearVelocity", KX_GameObject, pyattr_get_worldLinearVelocity, pyattr_set_worldLinearVelocity), + EXP_PYATTRIBUTE_RW_FUNCTION("angularVelocity", KX_GameObject, pyattr_get_localAngularVelocity, pyattr_set_worldAngularVelocity), + EXP_PYATTRIBUTE_RW_FUNCTION("localAngularVelocity", KX_GameObject, pyattr_get_localAngularVelocity, pyattr_set_localAngularVelocity), + EXP_PYATTRIBUTE_RW_FUNCTION("worldAngularVelocity", KX_GameObject, pyattr_get_worldAngularVelocity, pyattr_set_worldAngularVelocity), + EXP_PYATTRIBUTE_RW_FUNCTION("linearDamping", KX_GameObject, pyattr_get_linearDamping, pyattr_set_linearDamping), + EXP_PYATTRIBUTE_RW_FUNCTION("angularDamping", KX_GameObject, pyattr_get_angularDamping, pyattr_set_angularDamping), + EXP_PYATTRIBUTE_RO_FUNCTION("children", KX_GameObject, pyattr_get_children), + EXP_PYATTRIBUTE_RO_FUNCTION("childrenRecursive", KX_GameObject, pyattr_get_children_recursive), + EXP_PYATTRIBUTE_RO_FUNCTION("attrDict", KX_GameObject, pyattr_get_attrDict), + EXP_PYATTRIBUTE_RW_FUNCTION("color", KX_GameObject, pyattr_get_obcolor, pyattr_set_obcolor), + EXP_PYATTRIBUTE_RW_FUNCTION("debug", KX_GameObject, pyattr_get_debug, pyattr_set_debug), + EXP_PYATTRIBUTE_RO_FUNCTION("components", KX_GameObject, pyattr_get_components), + EXP_PYATTRIBUTE_RW_FUNCTION("debugRecursive", KX_GameObject, pyattr_get_debugRecursive, pyattr_set_debugRecursive), + EXP_PYATTRIBUTE_RW_FUNCTION("gravity", KX_GameObject, pyattr_get_gravity, pyattr_set_gravity), /* experimental, don't rely on these yet */ - KX_PYATTRIBUTE_RO_FUNCTION("sensors", KX_GameObject, pyattr_get_sensors), - KX_PYATTRIBUTE_RO_FUNCTION("controllers", KX_GameObject, pyattr_get_controllers), - KX_PYATTRIBUTE_RO_FUNCTION("actuators", KX_GameObject, pyattr_get_actuators), - {NULL} //Sentinel + EXP_PYATTRIBUTE_RO_FUNCTION("sensors", KX_GameObject, pyattr_get_sensors), + EXP_PYATTRIBUTE_RO_FUNCTION("controllers", KX_GameObject, pyattr_get_controllers), + EXP_PYATTRIBUTE_RO_FUNCTION("actuators", KX_GameObject, pyattr_get_actuators), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *KX_GameObject::PyReplaceMesh(PyObject *args) +PyObject *KX_GameObject::PyReplaceMesh(PyObject *args, PyObject *kwds) { - KX_Scene *scene = KX_GetActiveScene(); SCA_LogicManager *logicmgr = GetScene()->GetLogicManager(); PyObject *value; - int use_gfx= 1, use_phys= 0; - RAS_MeshObject *new_mesh; + int use_gfx = 1, use_phys = 0; + KX_Mesh *new_mesh; - if (!PyArg_ParseTuple(args,"O|ii:replaceMesh", &value, &use_gfx, &use_phys)) - return NULL; + if (!EXP_ParseTupleArgsAndKeywords(args, kwds, "O|ii:replaceMesh", + {"mesh", "useDisplayMesh", "usePhysicsMesh", 0}, &value, &use_gfx, &use_phys)) { + return nullptr; + } - if (!ConvertPythonToMesh(logicmgr, value, &new_mesh, false, "gameOb.replaceMesh(value): KX_GameObject")) - return NULL; + if (!ConvertPythonToMesh(logicmgr, value, &new_mesh, false, "gameOb.replaceMesh(value): KX_GameObject")) { + return nullptr; + } - scene->ReplaceMesh(this, new_mesh, (bool)use_gfx, (bool)use_phys); + ReplaceMesh(new_mesh, (bool)use_gfx, (bool)use_phys); Py_RETURN_NONE; } PyObject *KX_GameObject::PyEndObject() { - KX_Scene* scene = GetScene(); - - scene->DelayedRemoveObject(this); + GetScene()->DelayedRemoveObject(this); Py_RETURN_NONE; - } -PyObject *KX_GameObject::PyReinstancePhysicsMesh(PyObject *args) +PyObject *KX_GameObject::PyReinstancePhysicsMesh(PyObject *args, PyObject *kwds) { - KX_GameObject *gameobj= NULL; - RAS_MeshObject *mesh= NULL; + KX_GameObject *gameobj = nullptr; + KX_Mesh *mesh = nullptr; SCA_LogicManager *logicmgr = GetScene()->GetLogicManager(); + int dupli = 0; - PyObject *gameobj_py= NULL; - PyObject *mesh_py= NULL; + PyObject *gameobj_py = nullptr; + PyObject *mesh_py = nullptr; - if ( !PyArg_ParseTuple(args,"|OO:reinstancePhysicsMesh",&gameobj_py, &mesh_py) || - (gameobj_py && !ConvertPythonToGameObject(logicmgr, gameobj_py, &gameobj, true, "gameOb.reinstancePhysicsMesh(obj, mesh): KX_GameObject")) || - (mesh_py && !ConvertPythonToMesh(logicmgr, mesh_py, &mesh, true, "gameOb.reinstancePhysicsMesh(obj, mesh): KX_GameObject")) - ) { - return NULL; + if (!EXP_ParseTupleArgsAndKeywords(args, kwds, "|OOi:reinstancePhysicsMesh", + {"gameObject", "meshObject", "dupli", 0}, &gameobj_py, &mesh_py, &dupli) || + (gameobj_py && !ConvertPythonToGameObject(logicmgr, gameobj_py, &gameobj, true, "gameOb.reinstancePhysicsMesh(obj, mesh, dupli): KX_GameObject")) || + (mesh_py && !ConvertPythonToMesh(logicmgr, mesh_py, &mesh, true, "gameOb.reinstancePhysicsMesh(obj, mesh, dupli): KX_GameObject"))) { + return nullptr; } - /* gameobj and mesh can be NULL */ - if (GetPhysicsController() && GetPhysicsController()->ReinstancePhysicsShape(gameobj, mesh)) + /* gameobj and mesh can be nullptr */ + if (m_physicsController && m_physicsController->ReinstancePhysicsShape(gameobj, mesh, dupli)) { Py_RETURN_TRUE; + } Py_RETURN_FALSE; } +PyObject *KX_GameObject::PyReplacePhysicsShape(PyObject *value) +{ + KX_GameObject *gameobj; + SCA_LogicManager *logicmgr = GetScene()->GetLogicManager(); + + if (!ConvertPythonToGameObject(logicmgr, value, &gameobj, false, "gameOb.replacePhysicsShape(obj): KX_GameObject")) { + return nullptr; + } + + if (!m_physicsController || !gameobj->GetPhysicsController()) { + PyErr_SetString(PyExc_AttributeError, "gameOb.replacePhysicsShape(obj): function only available for objects with collisions enabled"); + return nullptr; + } + + m_physicsController->ReplacePhysicsShape(gameobj->GetPhysicsController()); + Py_RETURN_NONE; +} + static PyObject *Map_GetItem(PyObject *self_v, PyObject *item) { - KX_GameObject* self = static_castBGE_PROXY_REF(self_v); - const char *attr_str= _PyUnicode_AsString(item); - CValue* resultattr; + KX_GameObject *self = static_castEXP_PROXY_REF(self_v); + const char *attr_str = _PyUnicode_AsString(item); + EXP_Value *resultattr; PyObject *pyconvert; - if (self == NULL) { - PyErr_SetString(PyExc_SystemError, "val = gameOb[key]: KX_GameObject, " BGE_PROXY_ERROR_MSG); - return NULL; + if (self == nullptr) { + PyErr_SetString(PyExc_SystemError, "val = gameOb[key]: KX_GameObject, " EXP_PROXY_ERROR_MSG); + return nullptr; } /* first see if the attributes a string and try get the cvalue attribute */ - if (attr_str && (resultattr=self->GetProperty(attr_str))) { + if (attr_str && (resultattr = self->GetProperty(attr_str))) { pyconvert = resultattr->ConvertValueToPython(); - return pyconvert ? pyconvert:resultattr->GetProxy(); + return pyconvert ? pyconvert : resultattr->GetProxy(); } - /* no CValue attribute, try get the python only m_attr_dict attribute */ - else if (self->m_attr_dict && (pyconvert=PyDict_GetItem(self->m_attr_dict, item))) { + /* no EXP_Value attribute, try get the python only m_attr_dict attribute */ + else if (self->m_attr_dict && (pyconvert = PyDict_GetItem(self->m_attr_dict, item))) { - if (attr_str) + if (attr_str) { PyErr_Clear(); + } Py_INCREF(pyconvert); return pyconvert; } else { - if (attr_str) PyErr_Format(PyExc_KeyError, "value = gameOb[key]: KX_GameObject, key \"%s\" does not exist", attr_str); - else PyErr_SetString(PyExc_KeyError, "value = gameOb[key]: KX_GameObject, key does not exist"); - return NULL; + if (attr_str) { + PyErr_Format(PyExc_KeyError, "value = gameOb[key]: KX_GameObject, key \"%s\" does not exist", attr_str); + } + else { + PyErr_SetString(PyExc_KeyError, "value = gameOb[key]: KX_GameObject, key does not exist"); + } + return nullptr; } } @@ -2120,29 +2174,36 @@ static PyObject *Map_GetItem(PyObject *self_v, PyObject *item) static int Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val) { - KX_GameObject* self = static_castBGE_PROXY_REF(self_v); - const char *attr_str= _PyUnicode_AsString(key); - if (attr_str==NULL) + KX_GameObject *self = static_castEXP_PROXY_REF(self_v); + const char *attr_str = _PyUnicode_AsString(key); + if (attr_str == nullptr) { PyErr_Clear(); + } - if (self == NULL) { - PyErr_SetString(PyExc_SystemError, "gameOb[key] = value: KX_GameObject, " BGE_PROXY_ERROR_MSG); + if (self == nullptr) { + PyErr_SetString(PyExc_SystemError, "gameOb[key] = value: KX_GameObject, " EXP_PROXY_ERROR_MSG); return -1; } - if (val==NULL) { /* del ob["key"] */ - int del= 0; + if (val == nullptr) { /* del ob["key"] */ + int del = 0; /* try remove both just in case */ - if (attr_str) - del |= (self->RemoveProperty(attr_str)==true) ? 1:0; + if (attr_str) { + del |= (self->RemoveProperty(attr_str) == true) ? 1 : 0; + } - if (self->m_attr_dict) - del |= (PyDict_DelItem(self->m_attr_dict, key)==0) ? 1:0; + if (self->m_attr_dict) { + del |= (PyDict_DelItem(self->m_attr_dict, key) == 0) ? 1 : 0; + } - if (del==0) { - if (attr_str) PyErr_Format(PyExc_KeyError, "gameOb[key] = value: KX_GameObject, key \"%s\" could not be set", attr_str); - else PyErr_SetString(PyExc_KeyError, "del gameOb[key]: KX_GameObject, key could not be deleted"); + if (del == 0) { + if (attr_str) { + PyErr_Format(PyExc_KeyError, "gameOb[key] = value: KX_GameObject, key \"%s\" could not be set", attr_str); + } + else { + PyErr_SetString(PyExc_KeyError, "del gameOb[key]: KX_GameObject, key could not be deleted"); + } return -1; } else if (self->m_attr_dict) { @@ -2152,26 +2213,28 @@ static int Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val) else { /* ob["key"] = value */ bool set = false; - /* as CValue */ - if (attr_str && PyObject_TypeCheck(val, &PyObjectPlus::Type)==0) /* don't allow GameObjects for eg to be assigned to CValue props */ - { - CValue *vallie = self->ConvertPythonToValue(val, false, "gameOb[key] = value: "); + /* as EXP_Value */ + if (attr_str && PyObject_TypeCheck(val, &EXP_PyObjectPlus::Type) == 0) { /* don't allow GameObjects for eg to be assigned to EXP_Value props */ + EXP_Value *vallie = self->ConvertPythonToValue(val, false, "gameOb[key] = value: "); if (vallie) { - CValue* oldprop = self->GetProperty(attr_str); + EXP_Value *oldprop = self->GetProperty(attr_str); - if (oldprop) + if (oldprop) { oldprop->SetValue(vallie); - else + } + else { self->SetProperty(attr_str, vallie); + } vallie->Release(); set = true; /* try remove dict value to avoid double ups */ if (self->m_attr_dict) { - if (PyDict_DelItem(self->m_attr_dict, key) != 0) + if (PyDict_DelItem(self->m_attr_dict, key) != 0) { PyErr_Clear(); + } } } else if (PyErr_Occurred()) { @@ -2180,19 +2243,24 @@ static int Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val) } if (set == false) { - if (self->m_attr_dict==NULL) /* lazy init */ - self->m_attr_dict= PyDict_New(); + if (self->m_attr_dict == nullptr) { /* lazy init */ + self->m_attr_dict = PyDict_New(); + } - if (PyDict_SetItem(self->m_attr_dict, key, val)==0) - { - if (attr_str) - self->RemoveProperty(attr_str); /* overwrite the CValue if it exists */ + if (PyDict_SetItem(self->m_attr_dict, key, val) == 0) { + if (attr_str) { + self->RemoveProperty(attr_str); /* overwrite the EXP_Value if it exists */ + } set = true; } else { - if (attr_str) PyErr_Format(PyExc_KeyError, "gameOb[key] = value: KX_GameObject, key \"%s\" not be added to internal dictionary", attr_str); - else PyErr_SetString(PyExc_KeyError, "gameOb[key] = value: KX_GameObject, key not be added to internal dictionary"); + if (attr_str) { + PyErr_Format(PyExc_KeyError, "gameOb[key] = value: KX_GameObject, key \"%s\" not be added to internal dictionary", attr_str); + } + else { + PyErr_SetString(PyExc_KeyError, "gameOb[key] = value: KX_GameObject, key not be added to internal dictionary"); + } } } @@ -2207,46 +2275,48 @@ static int Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val) static int Seq_Contains(PyObject *self_v, PyObject *value) { - KX_GameObject* self = static_castBGE_PROXY_REF(self_v); + KX_GameObject *self = static_castEXP_PROXY_REF(self_v); - if (self == NULL) { - PyErr_SetString(PyExc_SystemError, "val in gameOb: KX_GameObject, " BGE_PROXY_ERROR_MSG); + if (self == nullptr) { + PyErr_SetString(PyExc_SystemError, "val in gameOb: KX_GameObject, " EXP_PROXY_ERROR_MSG); return -1; } - if (PyUnicode_Check(value) && self->GetProperty(_PyUnicode_AsString(value))) + if (PyUnicode_Check(value) && self->GetProperty(_PyUnicode_AsString(value))) { return 1; + } - if (self->m_attr_dict && PyDict_GetItem(self->m_attr_dict, value)) + if (self->m_attr_dict && PyDict_GetItem(self->m_attr_dict, value)) { return 1; + } return 0; } PyMappingMethods KX_GameObject::Mapping = { - (lenfunc)NULL , /*inquiry mp_length */ - (binaryfunc)Map_GetItem, /*binaryfunc mp_subscript */ - (objobjargproc)Map_SetItem, /*objobjargproc mp_ass_subscript */ + (lenfunc)nullptr, /*inquiry mp_length */ + (binaryfunc)Map_GetItem, /*binaryfunc mp_subscript */ + (objobjargproc)Map_SetItem, /*objobjargproc mp_ass_subscript */ }; PySequenceMethods KX_GameObject::Sequence = { - NULL, /* Cant set the len otherwise it can evaluate as false */ - NULL, /* sq_concat */ - NULL, /* sq_repeat */ - NULL, /* sq_item */ - NULL, /* sq_slice */ - NULL, /* sq_ass_item */ - NULL, /* sq_ass_slice */ - (objobjproc)Seq_Contains, /* sq_contains */ - (binaryfunc) NULL, /* sq_inplace_concat */ - (ssizeargfunc) NULL, /* sq_inplace_repeat */ + nullptr, /* Cant set the len otherwise it can evaluate as false */ + nullptr, /* sq_concat */ + nullptr, /* sq_repeat */ + nullptr, /* sq_item */ + nullptr, /* sq_slice */ + nullptr, /* sq_ass_item */ + nullptr, /* sq_ass_slice */ + (objobjproc)Seq_Contains, /* sq_contains */ + (binaryfunc)nullptr, /* sq_inplace_concat */ + (ssizeargfunc)nullptr, /* sq_inplace_repeat */ }; PyTypeObject KX_GameObject::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_GameObject", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -2257,86 +2327,113 @@ PyTypeObject KX_GameObject::Type = { 0, &Sequence, &Mapping, - 0,0,0, - NULL, - NULL, + 0, 0, 0, + nullptr, + nullptr, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IObject::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; -PyObject *KX_GameObject::pyattr_get_name(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_name(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject *self = static_cast(self_v); + return PyUnicode_FromStdString(self->GetName()); +} + +int KX_GameObject::pyattr_set_name(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); - return PyUnicode_From_STR_String(self->GetName()); + KX_GameObject *self = static_cast(self_v); + + if (!PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, "gameOb.name = str: KX_GameObject, expected a string"); + return PY_SET_ATTR_FAIL; + } + + std::string newname = std::string(_PyUnicode_AsString(value)); + std::string oldname = self->GetName(); + + SCA_LogicManager *manager = self->GetScene()->GetLogicManager(); + + // If true, it mean that's this game object is not a replica and was added at conversion time. + if (manager->GetGameObjectByName(oldname) == self) { + /* Two non-replica objects can have the same name bacause these objects are register in the + * logic manager and that the result of GetGameObjectByName will be undefined. */ + if (manager->GetGameObjectByName(newname)) { + PyErr_Format(PyExc_TypeError, "gameOb.name = str: name %s is already used by an other non-replica game object", oldname.c_str()); + return PY_SET_ATTR_FAIL; + } + // Unregister the old name. + manager->UnregisterGameObjectName(oldname); + // Register the object under the new name. + manager->RegisterGameObjectName(newname, self); + } + + // Change the name + self->SetName(newname); + + return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_parent(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_parent(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); - KX_GameObject* parent = self->GetParent(); + KX_GameObject *self = static_cast(self_v); + KX_GameObject *parent = self->GetParent(); if (parent) { return parent->GetProxy(); } Py_RETURN_NONE; } -PyObject *KX_GameObject::pyattr_get_group_members(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_group_members(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); - CListValue* instances = self->GetInstanceObjects(); + KX_GameObject *self = static_cast(self_v); + EXP_ListValue *instances = self->GetInstanceObjects(); if (instances) { return instances->GetProxy(); } Py_RETURN_NONE; } -PyObject* KX_GameObject::pyattr_get_collisionCallbacks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_collisionCallbacks(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); // Only objects with a physics controller should have collision callbacks - if (!self->GetPhysicsController()) { - PyErr_SetString(PyExc_AttributeError, "KX_GameObject.collisionCallbacks: attribute only available for objects with collisions enabled"); - return NULL; - } + PYTHON_CHECK_PHYSICS_CONTROLLER(self, "collisionCallbacks", nullptr); // Return the existing callbacks - if (self->m_collisionCallbacks == NULL) - { + if (!self->m_collisionCallbacks) { self->m_collisionCallbacks = PyList_New(0); - // Subscribe to collision update from KX_TouchManager + // Subscribe to collision update from KX_CollisionEventManager self->RegisterCollisionCallbacks(); } Py_INCREF(self->m_collisionCallbacks); return self->m_collisionCallbacks; } -int KX_GameObject::pyattr_set_collisionCallbacks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_collisionCallbacks(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); // Only objects with a physics controller should have collision callbacks - if (!self->GetPhysicsController()) { - PyErr_SetString(PyExc_AttributeError, "KX_GameObject.collisionCallbacks: attribute only available for objects with collisions enabled"); - return PY_SET_ATTR_FAIL; - } + PYTHON_CHECK_PHYSICS_CONTROLLER(self, "collisionCallbacks", PY_SET_ATTR_FAIL); - if (!PyList_CheckExact(value)) - { + if (!PyList_CheckExact(value)) { PyErr_SetString(PyExc_ValueError, "Expected a list"); return PY_SET_ATTR_FAIL; } - if (self->m_collisionCallbacks == NULL) { + if (!self->m_collisionCallbacks) { self->RegisterCollisionCallbacks(); - } else { + } + else { Py_DECREF(self->m_collisionCallbacks); } @@ -2348,15 +2445,15 @@ int KX_GameObject::pyattr_set_collisionCallbacks(void *self_v, const KX_PYATTRIB return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_collisionGroup(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_collisionGroup(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); - return PyLong_FromLong(self->GetUserCollisionGroup()); + KX_GameObject *self = static_cast(self_v); + return PyLong_FromLong(self->GetCollisionGroup()); } -int KX_GameObject::pyattr_set_collisionGroup(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_collisionGroup(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); int val = PyLong_AsLong(value); if (val == -1 && PyErr_Occurred()) { @@ -2369,19 +2466,19 @@ int KX_GameObject::pyattr_set_collisionGroup(void *self_v, const KX_PYATTRIBUTE_ return PY_SET_ATTR_FAIL; } - self->SetUserCollisionGroup(val); + self->SetCollisionGroup(val); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_collisionMask(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_collisionMask(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); - return PyLong_FromLong(self->GetUserCollisionMask()); + KX_GameObject *self = static_cast(self_v); + return PyLong_FromLong(self->GetCollisionMask()); } -int KX_GameObject::pyattr_set_collisionMask(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_collisionMask(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); int val = PyLong_AsLong(value); if (val == -1 && PyErr_Occurred()) { @@ -2394,13 +2491,13 @@ int KX_GameObject::pyattr_set_collisionMask(void *self_v, const KX_PYATTRIBUTE_D return PY_SET_ATTR_FAIL; } - self->SetUserCollisionMask(val); + self->SetCollisionMask(val); return PY_SET_ATTR_SUCCESS; } -PyObject* KX_GameObject::pyattr_get_scene(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_scene(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject *self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); KX_Scene *scene = self->GetScene(); if (scene) { return scene->GetProxy(); @@ -2408,608 +2505,710 @@ PyObject* KX_GameObject::pyattr_get_scene(void *self_v, const KX_PYATTRIBUTE_DEF Py_RETURN_NONE; } -PyObject *KX_GameObject::pyattr_get_group_object(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_group_object(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); - KX_GameObject* pivot = self->GetDupliGroupObject(); + KX_GameObject *self = static_cast(self_v); + KX_GameObject *pivot = self->GetDupliGroupObject(); if (pivot) { return pivot->GetProxy(); } Py_RETURN_NONE; } -PyObject *KX_GameObject::pyattr_get_life(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_life(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); - CValue *life = self->GetProperty("::timebomb"); - if (life) + EXP_Value *life = self->GetProperty("::timebomb"); + if (life) { // this convert the timebomb seconds to frames, hard coded 50.0f (assuming 50fps) // value hardcoded in KX_Scene::AddReplicaObject() return PyFloat_FromDouble(life->GetNumber() * 50.0); - else + } + else { Py_RETURN_NONE; + } } -PyObject *KX_GameObject::pyattr_get_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_mass(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); PHY_IPhysicsController *spc = self->GetPhysicsController(); return PyFloat_FromDouble(spc ? spc->GetMass() : 0.0f); } -int KX_GameObject::pyattr_set_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_mass(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); PHY_IPhysicsController *spc = self->GetPhysicsController(); - MT_Scalar val = PyFloat_AsDouble(value); + float val = PyFloat_AsDouble(value); if (val < 0.0f) { /* also accounts for non float */ PyErr_SetString(PyExc_AttributeError, "gameOb.mass = float: KX_GameObject, expected a float zero or above"); return PY_SET_ATTR_FAIL; } - if (spc) + if (spc) { spc->SetMass(val); + } return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_is_suspend_dynamics(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_is_suspend_dynamics(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); // Only objects with a physics controller can be suspended - if (!self->GetPhysicsController()) { - PyErr_SetString(PyExc_AttributeError, "This object has not Physics Controller"); - return NULL; - } + PYTHON_CHECK_PHYSICS_CONTROLLER(self, attrdef->m_name.c_str(), nullptr); return PyBool_FromLong(self->IsDynamicsSuspended()); } -PyObject *KX_GameObject::pyattr_get_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_lin_vel_min(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); PHY_IPhysicsController *spc = self->GetPhysicsController(); return PyFloat_FromDouble(spc ? spc->GetLinVelocityMin() : 0.0f); } -int KX_GameObject::pyattr_set_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_lin_vel_min(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); PHY_IPhysicsController *spc = self->GetPhysicsController(); - MT_Scalar val = PyFloat_AsDouble(value); + float val = PyFloat_AsDouble(value); if (val < 0.0f) { /* also accounts for non float */ PyErr_SetString(PyExc_AttributeError, "gameOb.linVelocityMin = float: KX_GameObject, expected a float zero or above"); return PY_SET_ATTR_FAIL; } - if (spc) + if (spc) { spc->SetLinVelocityMin(val); + } + + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_GameObject::pyattr_get_lin_vel_max(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject *self = static_cast(self_v); + PHY_IPhysicsController *spc = self->GetPhysicsController(); + return PyFloat_FromDouble(spc ? spc->GetLinVelocityMax() : 0.0f); +} + +int KX_GameObject::pyattr_set_lin_vel_max(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject *self = static_cast(self_v); + PHY_IPhysicsController *spc = self->GetPhysicsController(); + float val = PyFloat_AsDouble(value); + if (val < 0.0f) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, "gameOb.linVelocityMax = float: KX_GameObject, expected a float zero or above"); + return PY_SET_ATTR_FAIL; + } + + if (spc) { + spc->SetLinVelocityMax(val); + } + + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_GameObject::pyattr_get_ang_vel_min(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject *self = static_cast(self_v); + PHY_IPhysicsController *spc = self->GetPhysicsController(); + return PyFloat_FromDouble(spc ? spc->GetAngularVelocityMin() : 0.0f); +} + +int KX_GameObject::pyattr_set_ang_vel_min(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject *self = static_cast(self_v); + PHY_IPhysicsController *spc = self->GetPhysicsController(); + float val = PyFloat_AsDouble(value); + if (val < 0.0f) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, + "gameOb.angularVelocityMin = float: KX_GameObject, expected a nonnegative float"); + return PY_SET_ATTR_FAIL; + } + + if (spc) { + spc->SetAngularVelocityMin(val); + } + + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_GameObject::pyattr_get_ang_vel_max(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject *self = static_cast(self_v); + PHY_IPhysicsController *spc = self->GetPhysicsController(); + return PyFloat_FromDouble(spc ? spc->GetAngularVelocityMax() : 0.0f); +} + +int KX_GameObject::pyattr_set_ang_vel_max(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject *self = static_cast(self_v); + PHY_IPhysicsController *spc = self->GetPhysicsController(); + float val = PyFloat_AsDouble(value); + if (val < 0.0f) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, + "gameOb.angularVelocityMax = float: KX_GameObject, expected a nonnegative float"); + return PY_SET_ATTR_FAIL; + } + + if (spc) { + spc->SetAngularVelocityMax(val); + } + + return PY_SET_ATTR_SUCCESS; +} + + +PyObject *KX_GameObject::pyattr_get_layer(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject *self = static_cast(self_v); + return PyLong_FromLong(self->GetLayer()); +} + +#define MAX_LAYERS ((1 << 20) - 1) +int KX_GameObject::pyattr_set_layer(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject *self = static_cast(self_v); + int layer = PyLong_AsLong(value); + + if (layer == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; + } + + if (layer < 1) { + PyErr_Format(PyExc_TypeError, "expected an integer greater than 1 for attribute \"%s\"", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; + } + else if (layer > MAX_LAYERS) { + PyErr_Format(PyExc_TypeError, "expected an integer less than %i for attribute \"%s\"", MAX_LAYERS, attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; + } + + self->SetLayer(layer); + return PY_SET_ATTR_SUCCESS; +} +#undef MAX_LAYERS + +PyObject *KX_GameObject::pyattr_get_visible(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject *self = static_cast(self_v); + return PyBool_FromLong(self->GetVisible()); +} + +int KX_GameObject::pyattr_set_visible(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject *self = static_cast(self_v); + int param = PyObject_IsTrue(value); + if (param == -1) { + PyErr_SetString(PyExc_AttributeError, "gameOb.visible = bool: KX_GameObject, expected True or False"); + return PY_SET_ATTR_FAIL; + } + self->SetVisible(param, false); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_culled(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); - PHY_IPhysicsController *spc = self->GetPhysicsController(); - return PyFloat_FromDouble(spc ? spc->GetLinVelocityMax() : 0.0f); + KX_GameObject *self = static_cast(self_v); + return PyBool_FromLong(self->GetCullingNode().GetCulled()); } -int KX_GameObject::pyattr_set_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +PyObject *KX_GameObject::pyattr_get_cullingBox(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); - PHY_IPhysicsController *spc = self->GetPhysicsController(); - MT_Scalar val = PyFloat_AsDouble(value); - if (val < 0.0f) { /* also accounts for non float */ - PyErr_SetString(PyExc_AttributeError, "gameOb.linVelocityMax = float: KX_GameObject, expected a float zero or above"); - return PY_SET_ATTR_FAIL; - } - - if (spc) - spc->SetLinVelocityMax(val); - - return PY_SET_ATTR_SUCCESS; + KX_GameObject *self = static_cast(self_v); + return (new KX_BoundingBox(self))->NewProxy(true); } -PyObject *KX_GameObject::pyattr_get_ang_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_physicsCulling(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject *self = static_cast(self_v); - PHY_IPhysicsController *spc = self->GetPhysicsController(); - return PyFloat_FromDouble(spc ? spc->GetAngularVelocityMin() : 0.0f); + KX_GameObject *self = static_cast(self_v); + return PyBool_FromLong(self->GetActivityCullingInfo().m_flags & ActivityCullingInfo::ACTIVITY_PHYSICS); } -int KX_GameObject::pyattr_set_ang_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_physicsCulling(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject *self = static_cast(self_v); - PHY_IPhysicsController *spc = self->GetPhysicsController(); - MT_Scalar val = PyFloat_AsDouble(value); - if (val < 0.0f) { /* also accounts for non float */ - PyErr_SetString(PyExc_AttributeError, - "gameOb.angularVelocityMin = float: KX_GameObject, expected a nonnegative float"); + KX_GameObject *self = static_cast(self_v); + int param = PyObject_IsTrue(value); + if (param == -1) { + PyErr_SetString(PyExc_AttributeError, "gameOb.physicsCulling = bool: KX_GameObject, expected True or False"); return PY_SET_ATTR_FAIL; } - if (spc) - spc->SetAngularVelocityMin(val); - + self->SetActivityCulling(ActivityCullingInfo::ACTIVITY_PHYSICS, param); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_ang_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_logicCulling(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject *self = static_cast(self_v); - PHY_IPhysicsController *spc = self->GetPhysicsController(); - return PyFloat_FromDouble(spc ? spc->GetAngularVelocityMax() : 0.0f); + KX_GameObject *self = static_cast(self_v); + return PyBool_FromLong(self->GetActivityCullingInfo().m_flags & ActivityCullingInfo::ACTIVITY_LOGIC); } -int KX_GameObject::pyattr_set_ang_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_logicCulling(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject *self = static_cast(self_v); - PHY_IPhysicsController *spc = self->GetPhysicsController(); - MT_Scalar val = PyFloat_AsDouble(value); - if (val < 0.0f) { /* also accounts for non float */ - PyErr_SetString(PyExc_AttributeError, - "gameOb.angularVelocityMax = float: KX_GameObject, expected a nonnegative float"); + KX_GameObject *self = static_cast(self_v); + int param = PyObject_IsTrue(value); + if (param == -1) { + PyErr_SetString(PyExc_AttributeError, "gameOb.logicCulling = bool: KX_GameObject, expected True or False"); return PY_SET_ATTR_FAIL; } - if (spc) - spc->SetAngularVelocityMax(val); - + self->SetActivityCulling(ActivityCullingInfo::ACTIVITY_LOGIC, param); return PY_SET_ATTR_SUCCESS; } - -PyObject *KX_GameObject::pyattr_get_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_physicsCullingRadius(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); - return PyBool_FromLong(self->GetVisible()); + KX_GameObject *self = static_cast(self_v); + return PyFloat_FromDouble(std::sqrt(self->GetActivityCullingInfo().m_physicsRadius)); } -int KX_GameObject::pyattr_set_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_physicsCullingRadius(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); - int param = PyObject_IsTrue( value ); - if (param == -1) { - PyErr_SetString(PyExc_AttributeError, "gameOb.visible = bool: KX_GameObject, expected True or False"); + KX_GameObject *self = static_cast(self_v); + const float val = PyFloat_AsDouble(value); + if (val < 0.0f) { // Also accounts for non float. + PyErr_SetString(PyExc_AttributeError, "gameOb.physicsCullingRadius = float: KX_GameObject, expected a float zero or above"); return PY_SET_ATTR_FAIL; } - self->SetVisible(param, false); - self->UpdateBuckets(false); + self->GetActivityCullingInfo().m_physicsRadius = val * val; + return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_record_animation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_logicCullingRadius(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); - return PyBool_FromLong(self->IsRecordAnimation()); + KX_GameObject *self = static_cast(self_v); + return PyFloat_FromDouble(std::sqrt(self->GetActivityCullingInfo().m_logicRadius)); } -int KX_GameObject::pyattr_set_record_animation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_logicCullingRadius(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); - int param = PyObject_IsTrue(value); - if (param == -1) { - PyErr_SetString(PyExc_AttributeError, "gameOb.record_animation = bool: KX_GameObject, expected boolean"); + KX_GameObject *self = static_cast(self_v); + const float val = PyFloat_AsDouble(value); + if (val < 0.0f) { // Also accounts for non float. + PyErr_SetString(PyExc_AttributeError, "gameOb.logicCullingRadius = float: KX_GameObject, expected a float zero or above"); return PY_SET_ATTR_FAIL; } - self->SetRecordAnimation(param); + self->GetActivityCullingInfo().m_logicRadius = val * val; return PY_SET_ATTR_SUCCESS; } - - -PyObject *KX_GameObject::pyattr_get_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_worldPosition(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS return Vector_CreatePyObject_cb( - BGE_PROXY_FROM_REF_BORROW(self_v), 3, - mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_GLOBAL); + EXP_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_GLOBAL); #else - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); return PyObjectFrom(self->NodeGetWorldPosition()); #endif } -int KX_GameObject::pyattr_set_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_worldPosition(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); - MT_Point3 pos; - if (!PyVecTo(value, pos)) + KX_GameObject *self = static_cast(self_v); + mt::vec3 pos; + if (!PyVecTo(value, pos)) { return PY_SET_ATTR_FAIL; + } self->NodeSetWorldPosition(pos); - self->NodeUpdateGS(0.f); + self->NodeUpdate(); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_localPosition(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS return Vector_CreatePyObject_cb( - BGE_PROXY_FROM_REF_BORROW(self_v), 3, - mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_LOCAL); + EXP_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_POS_LOCAL); #else - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); return PyObjectFrom(self->NodeGetLocalPosition()); #endif } -int KX_GameObject::pyattr_set_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_localPosition(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); - MT_Point3 pos; - if (!PyVecTo(value, pos)) + KX_GameObject *self = static_cast(self_v); + mt::vec3 pos; + if (!PyVecTo(value, pos)) { return PY_SET_ATTR_FAIL; + } self->NodeSetLocalPosition(pos); - self->NodeUpdateGS(0.f); + self->NodeUpdate(); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_localInertia(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_localInertia(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS return Vector_CreatePyObject_cb( - BGE_PROXY_FROM_REF_BORROW(self_v), 3, - mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_INERTIA_LOCAL); + EXP_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_INERTIA_LOCAL); #else - KX_GameObject* self = static_cast(self_v); - if (self->GetPhysicsController1()) + KX_GameObject *self = static_cast(self_v); + if (self->GetPhysicsController1()) { return PyObjectFrom(self->GetPhysicsController1()->GetLocalInertia()); - return Py_BuildValue("fff", 0.0f, 0.0f, 0.0f); + } + return PyObjectFrom(mt::zero3); #endif } -PyObject *KX_GameObject::pyattr_get_worldOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_worldOrientation(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS return Matrix_CreatePyObject_cb( - BGE_PROXY_FROM_REF_BORROW(self_v), 3, 3, - mathutils_kxgameob_matrix_cb_index, MATHUTILS_MAT_CB_ORI_GLOBAL); + EXP_PROXY_FROM_REF_BORROW(self_v), 3, 3, + mathutils_kxgameob_matrix_cb_index, MATHUTILS_MAT_CB_ORI_GLOBAL); #else - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); return PyObjectFrom(self->NodeGetWorldOrientation()); #endif } -int KX_GameObject::pyattr_set_worldOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_worldOrientation(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); /* if value is not a sequence PyOrientationTo makes an error */ - MT_Matrix3x3 rot; - if (!PyOrientationTo(value, rot, "gameOb.worldOrientation = sequence: KX_GameObject, ")) + mt::mat3 rot; + if (!PyOrientationTo(value, rot, "gameOb.worldOrientation = sequence: KX_GameObject, ")) { return PY_SET_ATTR_FAIL; + } self->NodeSetGlobalOrientation(rot); - self->NodeUpdateGS(0.f); + self->NodeUpdate(); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_localOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_localOrientation(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS return Matrix_CreatePyObject_cb( - BGE_PROXY_FROM_REF_BORROW(self_v), 3, 3, - mathutils_kxgameob_matrix_cb_index, MATHUTILS_MAT_CB_ORI_LOCAL); + EXP_PROXY_FROM_REF_BORROW(self_v), 3, 3, + mathutils_kxgameob_matrix_cb_index, MATHUTILS_MAT_CB_ORI_LOCAL); #else - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); return PyObjectFrom(self->NodeGetLocalOrientation()); #endif } -int KX_GameObject::pyattr_set_localOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_localOrientation(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); /* if value is not a sequence PyOrientationTo makes an error */ - MT_Matrix3x3 rot; - if (!PyOrientationTo(value, rot, "gameOb.localOrientation = sequence: KX_GameObject, ")) + mt::mat3 rot; + if (!PyOrientationTo(value, rot, "gameOb.localOrientation = sequence: KX_GameObject, ")) { return PY_SET_ATTR_FAIL; + } self->NodeSetLocalOrientation(rot); - self->NodeUpdateGS(0.f); + self->NodeUpdate(); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_worldScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_worldScaling(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS return Vector_CreatePyObject_cb( - BGE_PROXY_FROM_REF_BORROW(self_v), 3, - mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_GLOBAL); + EXP_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_GLOBAL); #else - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); return PyObjectFrom(self->NodeGetWorldScaling()); #endif } -int KX_GameObject::pyattr_set_worldScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_worldScaling(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); - MT_Vector3 scale; - if (!PyVecTo(value, scale)) + KX_GameObject *self = static_cast(self_v); + mt::vec3 scale; + if (!PyVecTo(value, scale)) { return PY_SET_ATTR_FAIL; + } self->NodeSetWorldScale(scale); - self->NodeUpdateGS(0.f); + self->NodeUpdate(); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_localScaling(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS return Vector_CreatePyObject_cb( - BGE_PROXY_FROM_REF_BORROW(self_v), 3, - mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_LOCAL); + EXP_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_SCALE_LOCAL); #else - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); return PyObjectFrom(self->NodeGetLocalScaling()); #endif } -int KX_GameObject::pyattr_set_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_localScaling(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); - MT_Vector3 scale; - if (!PyVecTo(value, scale)) + KX_GameObject *self = static_cast(self_v); + mt::vec3 scale; + if (!PyVecTo(value, scale)) { return PY_SET_ATTR_FAIL; + } self->NodeSetLocalScale(scale); - self->NodeUpdateGS(0.f); + self->NodeUpdate(); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_localTransform(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_localTransform(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); - - float mat[16]; - - MT_Transform trans; + KX_GameObject *self = static_cast(self_v); - trans.setOrigin(self->GetSGNode()->GetLocalPosition()); - trans.setBasis(self->GetSGNode()->GetLocalOrientation()); - - MT_Vector3 scaling = self->GetSGNode()->GetLocalScale(); - trans.scale(scaling[0], scaling[1], scaling[2]); - - trans.getValue(mat); - - return PyObjectFrom(MT_Matrix4x4(mat)); + return PyObjectFrom(mt::mat4::FromAffineTransform(self->NodeGetLocalTransform())); } -int KX_GameObject::pyattr_set_localTransform(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_localTransform(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); - MT_Matrix4x4 temp; - if (!PyMatTo(value, temp)) + KX_GameObject *self = static_cast(self_v); + mt::mat4 temp; + if (!PyMatTo(value, temp)) { return PY_SET_ATTR_FAIL; + } - float transform[4][4]; - float loc[3], size[3]; - float rot[3][3]; - MT_Matrix3x3 orientation; - - temp.getValue(*transform); - mat4_to_loc_rot_size(loc, rot, size, transform); - - self->NodeSetLocalPosition(MT_Point3(loc)); - - //MT_Matrix3x3's constructor expects a 4x4 matrix - orientation = MT_Matrix3x3(); - orientation.setValue3x3(*rot); - self->NodeSetLocalOrientation(orientation); - - self->NodeSetLocalScale(MT_Vector3(size)); + self->NodeSetLocalPosition(temp.TranslationVector3D()); + self->NodeSetLocalOrientation(temp.RotationMatrix()); + self->NodeSetLocalScale(temp.ScaleVector3D()); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_worldTransform(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_worldTransform(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); - return PyObjectFrom(MT_Matrix4x4(self->GetOpenGLMatrix())); + return PyObjectFrom(mt::mat4::FromAffineTransform(self->NodeGetWorldTransform())); } -int KX_GameObject::pyattr_set_worldTransform(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_worldTransform(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); - MT_Matrix4x4 temp; - if (!PyMatTo(value, temp)) + KX_GameObject *self = static_cast(self_v); + mt::mat4 temp; + if (!PyMatTo(value, temp)) { return PY_SET_ATTR_FAIL; + } - float transform[4][4]; - float loc[3], size[3]; - float rot[3][3]; - MT_Matrix3x3 orientation; - - temp.getValue(*transform); - mat4_to_loc_rot_size(loc, rot, size, transform); - - self->NodeSetWorldPosition(MT_Point3(loc)); - - //MT_Matrix3x3's constructor expects a 4x4 matrix - orientation = MT_Matrix3x3(); - orientation.setValue3x3(*rot); - self->NodeSetGlobalOrientation(orientation); - - self->NodeSetWorldScale(MT_Vector3(size)); + self->NodeSetWorldPosition(temp.TranslationVector3D()); + self->NodeSetGlobalOrientation(temp.RotationMatrix()); + self->NodeSetWorldScale(temp.ScaleVector3D()); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_worldLinearVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_worldLinearVelocity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS return Vector_CreatePyObject_cb( - BGE_PROXY_FROM_REF_BORROW(self_v), 3, - mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_LINVEL_GLOBAL); + EXP_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_LINVEL_GLOBAL); #else - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); return PyObjectFrom(GetLinearVelocity(false)); #endif } -int KX_GameObject::pyattr_set_worldLinearVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_worldLinearVelocity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); - MT_Vector3 velocity; - if (!PyVecTo(value, velocity)) + KX_GameObject *self = static_cast(self_v); + mt::vec3 velocity; + if (!PyVecTo(value, velocity)) { return PY_SET_ATTR_FAIL; + } - self->setLinearVelocity(velocity, false); + self->SetLinearVelocity(velocity, false); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_localLinearVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_localLinearVelocity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS return Vector_CreatePyObject_cb( - BGE_PROXY_FROM_REF_BORROW(self_v), 3, - mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_LINVEL_LOCAL); + EXP_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_LINVEL_LOCAL); #else - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); return PyObjectFrom(GetLinearVelocity(true)); #endif } -int KX_GameObject::pyattr_set_localLinearVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_localLinearVelocity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); - MT_Vector3 velocity; - if (!PyVecTo(value, velocity)) + KX_GameObject *self = static_cast(self_v); + mt::vec3 velocity; + if (!PyVecTo(value, velocity)) { return PY_SET_ATTR_FAIL; + } - self->setLinearVelocity(velocity, true); + self->SetLinearVelocity(velocity, true); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_worldAngularVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_worldAngularVelocity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS return Vector_CreatePyObject_cb( - BGE_PROXY_FROM_REF_BORROW(self_v), 3, - mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_ANGVEL_GLOBAL); + EXP_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_ANGVEL_GLOBAL); #else - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); return PyObjectFrom(GetAngularVelocity(false)); #endif } -int KX_GameObject::pyattr_set_worldAngularVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_worldAngularVelocity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); - MT_Vector3 velocity; - if (!PyVecTo(value, velocity)) + KX_GameObject *self = static_cast(self_v); + mt::vec3 velocity; + if (!PyVecTo(value, velocity)) { return PY_SET_ATTR_FAIL; + } - self->setAngularVelocity(velocity, false); + self->SetAngularVelocity(velocity, false); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_localAngularVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_localAngularVelocity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS return Vector_CreatePyObject_cb( - BGE_PROXY_FROM_REF_BORROW(self_v), 3, - mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_ANGVEL_LOCAL); + EXP_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_ANGVEL_LOCAL); #else - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); return PyObjectFrom(GetAngularVelocity(true)); #endif } -int KX_GameObject::pyattr_set_localAngularVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_localAngularVelocity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject *self = static_cast(self_v); + mt::vec3 velocity; + if (!PyVecTo(value, velocity)) { + return PY_SET_ATTR_FAIL; + } + + self->SetAngularVelocity(velocity, true); + + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_GameObject::pyattr_get_gravity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ +#ifdef USE_MATHUTILS + return Vector_CreatePyObject_cb( + EXP_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_GRAVITY); +#else + KX_GameObject *self = static_cast(self_v); + return PyObjectFrom(GetGravity()); +#endif +} + +int KX_GameObject::pyattr_set_gravity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); - MT_Vector3 velocity; - if (!PyVecTo(value, velocity)) + KX_GameObject *self = static_cast(self_v); + mt::vec3 gravity; + if (!PyVecTo(value, gravity)) { return PY_SET_ATTR_FAIL; + } - self->setAngularVelocity(velocity, true); + self->SetGravity(gravity); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_linearDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_linearDamping(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); - return PyFloat_FromDouble(self->getLinearDamping()); + KX_GameObject *self = static_cast(self_v); + return PyFloat_FromDouble(self->GetLinearDamping()); } -int KX_GameObject::pyattr_set_linearDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_linearDamping(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); float val = PyFloat_AsDouble(value); - self->setLinearDamping(val); + self->SetLinearDamping(val); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_angularDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_angularDamping(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); - return PyFloat_FromDouble(self->getAngularDamping()); + KX_GameObject *self = static_cast(self_v); + return PyFloat_FromDouble(self->GetAngularDamping()); } -int KX_GameObject::pyattr_set_angularDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_angularDamping(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); float val = PyFloat_AsDouble(value); - self->setAngularDamping(val); + self->SetAngularDamping(val); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_timeOffset(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_timeOffset(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); - SG_Node* sg_parent; - if (self->GetSGNode() && (sg_parent = self->GetSGNode()->GetSGParent()) != NULL && sg_parent->IsSlowParent()) { + KX_GameObject *self = static_cast(self_v); + SG_Node *sg_parent; + if ((sg_parent = self->m_sgNode->GetParent()) != nullptr && sg_parent->IsSlowParent()) { return PyFloat_FromDouble(static_cast(sg_parent->GetParentRelation())->GetTimeOffset()); - } else { + } + else { return PyFloat_FromDouble(0.0f); } } -int KX_GameObject::pyattr_set_timeOffset(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_timeOffset(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); - if (self->GetSGNode()) { - MT_Scalar val = PyFloat_AsDouble(value); - SG_Node *sg_parent= self->GetSGNode()->GetSGParent(); - if (val < 0.0f) { /* also accounts for non float */ - PyErr_SetString(PyExc_AttributeError, "gameOb.timeOffset = float: KX_GameObject, expected a float zero or above"); - return PY_SET_ATTR_FAIL; - } - if (sg_parent && sg_parent->IsSlowParent()) - static_cast(sg_parent->GetParentRelation())->SetTimeOffset(val); + KX_GameObject *self = static_cast(self_v); + float val = PyFloat_AsDouble(value); + SG_Node *sg_parent = self->m_sgNode->GetParent(); + if (val < 0.0f) { /* also accounts for non float */ + PyErr_SetString(PyExc_AttributeError, "gameOb.timeOffset = float: KX_GameObject, expected a float zero or above"); + return PY_SET_ATTR_FAIL; + } + if (sg_parent && sg_parent->IsSlowParent()) { + static_cast(sg_parent->GetParentRelation())->SetTimeOffset(val); } return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_state(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); int state = 0; state |= self->GetState(); return PyLong_FromLong(state); } -int KX_GameObject::pyattr_set_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_state(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); int state_i = PyLong_AsLong(value); unsigned int state = 0; @@ -3019,7 +3218,7 @@ int KX_GameObject::pyattr_set_state(void *self_v, const KX_PYATTRIBUTE_DEF *attr } state |= state_i; - if ((state & ((1<<30)-1)) == 0) { + if ((state & ((1 << 30) - 1)) == 0) { PyErr_SetString(PyExc_AttributeError, "gameOb.state = int: KX_GameObject, state bitfield was not between 0 and 30 (1<<0 and 1<<29)"); return PY_SET_ATTR_FAIL; } @@ -3027,158 +3226,174 @@ int KX_GameObject::pyattr_set_state(void *self_v, const KX_PYATTRIBUTE_DEF *attr return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_meshes(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_meshes(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); - PyObject *meshes= PyList_New(self->m_meshes.size()); + KX_GameObject *self = static_cast(self_v); + PyObject *meshes = PyList_New(self->m_meshes.size()); int i; - for (i=0; i < (int)self->m_meshes.size(); i++) + for (i = 0; i < (int)self->m_meshes.size(); i++) { - KX_MeshProxy* meshproxy = new KX_MeshProxy(self->m_meshes[i]); - PyList_SET_ITEM(meshes, i, meshproxy->NewProxy(true)); + PyObject *item = self->m_meshes[i]->GetProxy(); + Py_INCREF(item); + PyList_SET_ITEM(meshes, i, item); } return meshes; } -PyObject *KX_GameObject::pyattr_get_obcolor(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_batchGroup(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject *self = static_cast(self_v); + RAS_MeshUser *meshUser = self->GetMeshUser(); + if (!meshUser) { + Py_RETURN_NONE; + } + + KX_BatchGroup *batchGroup = (KX_BatchGroup *)meshUser->GetBatchGroup(); + if (!batchGroup) { + Py_RETURN_NONE; + } + + return batchGroup->GetProxy(); +} + +PyObject *KX_GameObject::pyattr_get_obcolor(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS return Vector_CreatePyObject_cb( - BGE_PROXY_FROM_REF_BORROW(self_v), 4, - mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_OBJECT_COLOR); + EXP_PROXY_FROM_REF_BORROW(self_v), 4, + mathutils_kxgameob_vector_cb_index, MATHUTILS_VEC_CB_OBJECT_COLOR); #else - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); return PyObjectFrom(self->GetObjectColor()); #endif } -int KX_GameObject::pyattr_set_obcolor(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_obcolor(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject* self = static_cast(self_v); - MT_Vector4 obcolor; - if (!PyVecTo(value, obcolor)) + KX_GameObject *self = static_cast(self_v); + mt::vec4 obcolor; + if (!PyVecTo(value, obcolor)) { return PY_SET_ATTR_FAIL; + } self->SetObjectColor(obcolor); return PY_SET_ATTR_SUCCESS; } -static int kx_game_object_get_sensors_size_cb(void *self_v) +PyObject *KX_GameObject::pyattr_get_components(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject *self = static_cast(self_v); + EXP_ListValue *components = self->GetComponents(); + return components ? components->GetProxy() : (new EXP_ListValue())->NewProxy(true); +} + +unsigned int KX_GameObject::py_get_sensors_size() { - return ((KX_GameObject *)self_v)->GetSensors().size(); + return m_sensors.size(); } -static PyObject *kx_game_object_get_sensors_item_cb(void *self_v, int index) +PyObject *KX_GameObject::py_get_sensors_item(unsigned int index) { - return ((KX_GameObject *)self_v)->GetSensors()[index]->GetProxy(); + return m_sensors[index]->GetProxy(); } -static const char *kx_game_object_get_sensors_item_name_cb(void *self_v, int index) +std::string KX_GameObject::py_get_sensors_item_name(unsigned int index) { - return ((KX_GameObject *)self_v)->GetSensors()[index]->GetName().ReadPtr(); + return m_sensors[index]->GetName(); } -/* These are experimental! */ -PyObject *KX_GameObject::pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_sensors(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - return (new CListWrapper(self_v, - ((KX_GameObject *)self_v)->GetProxy(), - NULL, - kx_game_object_get_sensors_size_cb, - kx_game_object_get_sensors_item_cb, - kx_game_object_get_sensors_item_name_cb, - NULL))->NewProxy(true); + return (new EXP_ListWrapper(self_v))->NewProxy(true); } -static int kx_game_object_get_controllers_size_cb(void *self_v) +unsigned int KX_GameObject::py_get_controllers_size() { - return ((KX_GameObject *)self_v)->GetControllers().size(); + return m_controllers.size(); } -static PyObject *kx_game_object_get_controllers_item_cb(void *self_v, int index) +PyObject *KX_GameObject::py_get_controllers_item(unsigned int index) { - return ((KX_GameObject *)self_v)->GetControllers()[index]->GetProxy(); + return m_controllers[index]->GetProxy(); } -static const char *kx_game_object_get_controllers_item_name_cb(void *self_v, int index) +std::string KX_GameObject::py_get_controllers_item_name(unsigned int index) { - return ((KX_GameObject *)self_v)->GetControllers()[index]->GetName().ReadPtr(); + return m_controllers[index]->GetName(); } -PyObject *KX_GameObject::pyattr_get_controllers(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_controllers(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - return (new CListWrapper(self_v, - ((KX_GameObject *)self_v)->GetProxy(), - NULL, - kx_game_object_get_controllers_size_cb, - kx_game_object_get_controllers_item_cb, - kx_game_object_get_controllers_item_name_cb, - NULL))->NewProxy(true); + return (new EXP_ListWrapper(self_v))->NewProxy(true); } -static int kx_game_object_get_actuators_size_cb(void *self_v) +unsigned int KX_GameObject::py_get_actuators_size() { - return ((KX_GameObject *)self_v)->GetActuators().size(); + return m_actuators.size(); } -static PyObject *kx_game_object_get_actuators_item_cb(void *self_v, int index) +PyObject *KX_GameObject::py_get_actuators_item(unsigned int index) { - return ((KX_GameObject *)self_v)->GetActuators()[index]->GetProxy(); + return m_actuators[index]->GetProxy(); } -static const char *kx_game_object_get_actuators_item_name_cb(void *self_v, int index) +std::string KX_GameObject::py_get_actuators_item_name(unsigned int index) { - return ((KX_GameObject *)self_v)->GetActuators()[index]->GetName().ReadPtr(); + return m_actuators[index]->GetName(); } -PyObject *KX_GameObject::pyattr_get_actuators(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_actuators(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - return (new CListWrapper(self_v, - ((KX_GameObject *)self_v)->GetProxy(), - NULL, - kx_game_object_get_actuators_size_cb, - kx_game_object_get_actuators_item_cb, - kx_game_object_get_actuators_item_name_cb, - NULL))->NewProxy(true); + return (new EXP_ListWrapper(self_v))->NewProxy(true); } -/* End experimental */ -PyObject *KX_GameObject::pyattr_get_children(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_children(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); - return self->GetChildren()->NewProxy(true); + KX_GameObject *self = static_cast(self_v); + EXP_ListValue *list = new EXP_ListValue(self->GetChildren()); + /* The list must not own any data because is temporary and we can't + * ensure that it will freed before item's in it (e.g python owner). */ + list->SetReleaseOnDestruct(false); + return list->NewProxy(true); } -PyObject *KX_GameObject::pyattr_get_children_recursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_children_recursive(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); - return self->GetChildrenRecursive()->NewProxy(true); + KX_GameObject *self = static_cast(self_v); + EXP_ListValue *list = new EXP_ListValue(self->GetChildrenRecursive()); + /* The list must not own any data because is temporary and we can't + * ensure that it will freed before item's in it (e.g python owner). */ + list->SetReleaseOnDestruct(false); + return list->NewProxy(true); } -PyObject *KX_GameObject::pyattr_get_attrDict(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_attrDict(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_GameObject* self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); - if (self->m_attr_dict==NULL) - self->m_attr_dict= PyDict_New(); + if (self->m_attr_dict == nullptr) { + self->m_attr_dict = PyDict_New(); + } Py_INCREF(self->m_attr_dict); return self->m_attr_dict; } -PyObject *KX_GameObject::pyattr_get_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_debug(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Scene *scene = KX_GetActiveScene(); - KX_GameObject *self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); - return PyBool_FromLong(scene->ObjectInDebugList(self)); + return PyBool_FromLong(self->GetScene()->ObjectInDebugList(self)); } -int KX_GameObject::pyattr_set_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_debug(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject *self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); int param = PyObject_IsTrue(value); if (param == -1) { @@ -3191,17 +3406,16 @@ int KX_GameObject::pyattr_set_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attr return PY_SET_ATTR_SUCCESS; } -PyObject *KX_GameObject::pyattr_get_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_GameObject::pyattr_get_debugRecursive(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Scene *scene = KX_GetActiveScene(); - KX_GameObject *self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); - return PyBool_FromLong(scene->ObjectInDebugList(self)); + return PyBool_FromLong(self->GetScene()->ObjectInDebugList(self)); } -int KX_GameObject::pyattr_set_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_GameObject::pyattr_set_debugRecursive(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_GameObject *self = static_cast(self_v); + KX_GameObject *self = static_cast(self_v); int param = PyObject_IsTrue(value); if (param == -1) { @@ -3214,19 +3428,40 @@ int KX_GameObject::pyattr_set_debugRecursive(void *self_v, const KX_PYATTRIBUTE_ return PY_SET_ATTR_SUCCESS; } +PyObject *KX_GameObject::pyattr_get_lodManager(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_GameObject *self = static_cast(self_v); + + return (self->m_lodManager) ? self->m_lodManager->GetProxy() : Py_None; +} + +int KX_GameObject::pyattr_set_lodManager(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_GameObject *self = static_cast(self_v); + + KX_LodManager *lodManager = nullptr; + if (!ConvertPythonToLodManager(value, &lodManager, true, "gameobj.lodManager: KX_GameObject")) { + return PY_SET_ATTR_FAIL; + } + + self->SetLodManager(lodManager); + + return PY_SET_ATTR_SUCCESS; +} + PyObject *KX_GameObject::PyApplyForce(PyObject *args) { int local = 0; PyObject *pyvect; if (PyArg_ParseTuple(args, "O|i:applyForce", &pyvect, &local)) { - MT_Vector3 force; + mt::vec3 force; if (PyVecTo(pyvect, force)) { - ApplyForce(force, (local!=0)); + ApplyForce(force, (local != 0)); Py_RETURN_NONE; } } - return NULL; + return nullptr; } PyObject *KX_GameObject::PyApplyTorque(PyObject *args) @@ -3235,13 +3470,13 @@ PyObject *KX_GameObject::PyApplyTorque(PyObject *args) PyObject *pyvect; if (PyArg_ParseTuple(args, "O|i:applyTorque", &pyvect, &local)) { - MT_Vector3 torque; + mt::vec3 torque; if (PyVecTo(pyvect, torque)) { - ApplyTorque(torque, (local!=0)); + ApplyTorque(torque, (local != 0)); Py_RETURN_NONE; } } - return NULL; + return nullptr; } PyObject *KX_GameObject::PyApplyRotation(PyObject *args) @@ -3250,13 +3485,13 @@ PyObject *KX_GameObject::PyApplyRotation(PyObject *args) PyObject *pyvect; if (PyArg_ParseTuple(args, "O|i:applyRotation", &pyvect, &local)) { - MT_Vector3 rotation; + mt::vec3 rotation; if (PyVecTo(pyvect, rotation)) { - ApplyRotation(rotation, (local!=0)); + ApplyRotation(rotation, (local != 0)); Py_RETURN_NONE; } } - return NULL; + return nullptr; } PyObject *KX_GameObject::PyApplyMovement(PyObject *args) @@ -3265,26 +3500,25 @@ PyObject *KX_GameObject::PyApplyMovement(PyObject *args) PyObject *pyvect; if (PyArg_ParseTuple(args, "O|i:applyMovement", &pyvect, &local)) { - MT_Vector3 movement; + mt::vec3 movement; if (PyVecTo(pyvect, movement)) { - ApplyMovement(movement, (local!=0)); + ApplyMovement(movement, (local != 0)); Py_RETURN_NONE; } } - return NULL; + return nullptr; } PyObject *KX_GameObject::PyGetLinearVelocity(PyObject *args) { // only can get the velocity if we have a physics object connected to us... int local = 0; - if (PyArg_ParseTuple(args,"|i:getLinearVelocity",&local)) - { - return PyObjectFrom(GetLinearVelocity((local!=0))); + + if (PyArg_ParseTuple(args, "|i:getLinearVelocity", &local)) { + return PyObjectFrom(GetLinearVelocity((local != 0))); } - else - { - return NULL; + else { + return nullptr; } } @@ -3293,27 +3527,26 @@ PyObject *KX_GameObject::PySetLinearVelocity(PyObject *args) int local = 0; PyObject *pyvect; - if (PyArg_ParseTuple(args,"O|i:setLinearVelocity",&pyvect,&local)) { - MT_Vector3 velocity; + if (PyArg_ParseTuple(args, "O|i:setLinearVelocity", &pyvect, &local)) { + mt::vec3 velocity; if (PyVecTo(pyvect, velocity)) { - setLinearVelocity(velocity, (local!=0)); + SetLinearVelocity(velocity, (local != 0)); Py_RETURN_NONE; } } - return NULL; + return nullptr; } PyObject *KX_GameObject::PyGetAngularVelocity(PyObject *args) { // only can get the velocity if we have a physics object connected to us... int local = 0; - if (PyArg_ParseTuple(args,"|i:getAngularVelocity",&local)) - { - return PyObjectFrom(GetAngularVelocity((local!=0))); + + if (PyArg_ParseTuple(args, "|i:getAngularVelocity", &local)) { + return PyObjectFrom(GetAngularVelocity((local != 0))); } - else - { - return NULL; + else { + return nullptr; } } @@ -3322,14 +3555,14 @@ PyObject *KX_GameObject::PySetAngularVelocity(PyObject *args) int local = 0; PyObject *pyvect; - if (PyArg_ParseTuple(args,"O|i:setAngularVelocity",&pyvect,&local)) { - MT_Vector3 velocity; + if (PyArg_ParseTuple(args, "O|i:setAngularVelocity", &pyvect, &local)) { + mt::vec3 velocity; if (PyVecTo(pyvect, velocity)) { - setAngularVelocity(velocity, (local!=0)); + SetAngularVelocity(velocity, (local != 0)); Py_RETURN_NONE; } } - return NULL; + return nullptr; } PyObject *KX_GameObject::PySetDamping(PyObject *args) @@ -3337,21 +3570,22 @@ PyObject *KX_GameObject::PySetDamping(PyObject *args) float linear; float angular; - if (!PyArg_ParseTuple(args,"ff|i:setDamping", &linear, &angular)) - return NULL; + if (!PyArg_ParseTuple(args, "ff:setDamping", &linear, &angular)) { + return nullptr; + } - setDamping(linear, angular); + SetDamping(linear, angular); Py_RETURN_NONE; } PyObject *KX_GameObject::PySetVisible(PyObject *args) { int visible, recursive = 0; - if (!PyArg_ParseTuple(args,"i|i:setVisible",&visible, &recursive)) - return NULL; + if (!PyArg_ParseTuple(args, "i|i:setVisible", &visible, &recursive)) { + return nullptr; + } - SetVisible(visible ? true:false, recursive ? true:false); - UpdateBuckets(recursive ? true:false); + SetVisible(visible ? true : false, recursive ? true : false); Py_RETURN_NONE; } @@ -3359,21 +3593,24 @@ PyObject *KX_GameObject::PySetVisible(PyObject *args) PyObject *KX_GameObject::PySetOcclusion(PyObject *args) { int occlusion, recursive = 0; - if (!PyArg_ParseTuple(args,"i|i:setOcclusion",&occlusion, &recursive)) - return NULL; - SetOccluder(occlusion ? true:false, recursive ? true:false); + if (!PyArg_ParseTuple(args, "i|i:setOcclusion", &occlusion, &recursive)) { + return nullptr; + } + + SetOccluder(occlusion ? true : false, recursive ? true : false); Py_RETURN_NONE; } PyObject *KX_GameObject::PyGetVelocity(PyObject *args) { // only can get the velocity if we have a physics object connected to us... - MT_Point3 point(0.0f,0.0f,0.0f); - PyObject *pypos = NULL; + mt::vec3 point = mt::zero3; + PyObject *pypos = nullptr; - if (!PyArg_ParseTuple(args, "|O:getVelocity", &pypos) || (pypos && !PyVecTo(pypos, point))) - return NULL; + if (!PyArg_ParseTuple(args, "|O:getVelocity", &pypos) || (pypos && !PyVecTo(pypos, point))) { + return nullptr; + } return PyObjectFrom(GetVelocity(point)); } @@ -3384,21 +3621,22 @@ PyObject *KX_GameObject::PyGetReactionForce() // XXX - Currently not working with bullet intergration, see KX_BulletPhysicsController.cpp's getReactionForce #if 0 - if (GetPhysicsController1()) + if (GetPhysicsController1()) { return PyObjectFrom(GetPhysicsController1()->getReactionForce()); - return PyObjectFrom(dummy_point); + } + return PyObjectFrom(mt::zero3); #endif - return Py_BuildValue("fff", 0.0f, 0.0f, 0.0f); - + return PyObjectFrom(mt::zero3); } PyObject *KX_GameObject::PyEnableRigidBody() { - if (GetPhysicsController()) - GetPhysicsController()->SetRigidBody(true); + if (m_physicsController) { + m_physicsController->SetRigidBody(true); + } Py_RETURN_NONE; } @@ -3407,36 +3645,38 @@ PyObject *KX_GameObject::PyEnableRigidBody() PyObject *KX_GameObject::PyDisableRigidBody() { - if (GetPhysicsController()) - GetPhysicsController()->SetRigidBody(false); + if (m_physicsController) { + m_physicsController->SetRigidBody(false); + } Py_RETURN_NONE; } -PyObject *KX_GameObject::PySetParent(PyObject *args) +PyObject *KX_GameObject::PySetParent(PyObject *args, PyObject *kwds) { - KX_Scene *scene = KX_GetActiveScene(); SCA_LogicManager *logicmgr = GetScene()->GetLogicManager(); PyObject *pyobj; KX_GameObject *obj; - int addToCompound=1, ghost=1; + int addToCompound = 1, ghost = 1; - if (!PyArg_ParseTuple(args,"O|ii:setParent", &pyobj, &addToCompound, &ghost)) { - return NULL; // Python sets a simple error + if (!EXP_ParseTupleArgsAndKeywords(args, kwds, "O|ii:setParent", {"parent", "compound", "ghost", 0}, + &pyobj, &addToCompound, &ghost)) { + return nullptr; // Python sets a simple error + } + if (!ConvertPythonToGameObject(logicmgr, pyobj, &obj, true, "gameOb.setParent(obj): KX_GameObject")) { + return nullptr; + } + + if (obj) { + SetParent(obj, addToCompound, ghost); } - if (!ConvertPythonToGameObject(logicmgr, pyobj, &obj, true, "gameOb.setParent(obj): KX_GameObject")) - return NULL; - if (obj) - this->SetParent(scene, obj, addToCompound, ghost); Py_RETURN_NONE; } PyObject *KX_GameObject::PyRemoveParent() { - KX_Scene *scene = KX_GetActiveScene(); - - this->RemoveParent(scene); + RemoveParent(); Py_RETURN_NONE; } @@ -3445,21 +3685,55 @@ PyObject *KX_GameObject::PySetCollisionMargin(PyObject *value) { float collisionMargin = PyFloat_AsDouble(value); - if (collisionMargin==-1 && PyErr_Occurred()) { + if (collisionMargin == -1 && PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "expected a float"); - return NULL; + return nullptr; } - if (m_pPhysicsController) - { - m_pPhysicsController->SetMargin(collisionMargin); - Py_RETURN_NONE; - } - PyErr_SetString(PyExc_RuntimeError, "This object has no physics controller"); - return NULL; + PYTHON_CHECK_PHYSICS_CONTROLLER(this, "setCollisionMargin", nullptr); + + m_physicsController->SetMargin(collisionMargin); + Py_RETURN_NONE; } +PyObject *KX_GameObject::PyCollide(PyObject *value) +{ + KX_Scene *scene = GetScene(); + KX_GameObject *other; + + if (!ConvertPythonToGameObject(scene->GetLogicManager(), value, &other, false, "gameOb.collide(obj): KX_GameObject")) { + return nullptr; + } + + if (!m_physicsController || !other->GetPhysicsController()) { + PyErr_SetString(PyExc_TypeError, "expected objects with physics controller"); + return nullptr; + } + + PHY_IPhysicsEnvironment *env = scene->GetPhysicsEnvironment(); + PHY_CollisionTestResult testResult = env->CheckCollision(m_physicsController.get(), other->GetPhysicsController()); + + PyObject *result = PyTuple_New(2); + if (!testResult.collide) { + PyTuple_SET_ITEM(result, 0, Py_False); + PyTuple_SET_ITEM(result, 1, Py_None); + } + else { + PyTuple_SET_ITEM(result, 0, Py_True); + + if (testResult.collData) { + KX_CollisionContactPointList *contactPointList = new KX_CollisionContactPointList(testResult.collData, testResult.isFirst); + PyTuple_SET_ITEM(result, 1, contactPointList->NewProxy(true)); + } + else { + PyTuple_SET_ITEM(result, 1, Py_None); + } + } + + return result; +} + PyObject *KX_GameObject::PyApplyImpulse(PyObject *args) { @@ -3467,37 +3741,51 @@ PyObject *KX_GameObject::PyApplyImpulse(PyObject *args) PyObject *pyimpulse; int local = 0; - if (!m_pPhysicsController) { - PyErr_SetString(PyExc_RuntimeError, "This object has no physics controller"); - return NULL; - } - - if (PyArg_ParseTuple(args, "OO|i:applyImpulse", &pyattach, &pyimpulse, &local)) - { - MT_Point3 attach; - MT_Vector3 impulse; - if (PyVecTo(pyattach, attach) && PyVecTo(pyimpulse, impulse)) - { - m_pPhysicsController->ApplyImpulse(attach, impulse, (local!=0)); + PYTHON_CHECK_PHYSICS_CONTROLLER(this, "applyImpulse", nullptr); + if (PyArg_ParseTuple(args, "OO|i:applyImpulse", &pyattach, &pyimpulse, &local)) { + mt::vec3 attach; + mt::vec3 impulse; + if (PyVecTo(pyattach, attach) && PyVecTo(pyimpulse, impulse)) { + m_physicsController->ApplyImpulse(attach, impulse, (local != 0)); Py_RETURN_NONE; } } - return NULL; + return nullptr; +} + +PyObject *KX_GameObject::PySuspendPhysics(PyObject *args) +{ + int freeConstraints = false; + + if (!PyArg_ParseTuple(args, "|i:suspendPhysics", &freeConstraints)) { + return nullptr; + } + + SuspendPhysics(freeConstraints); + + Py_RETURN_NONE; } +PyObject *KX_GameObject::PyRestorePhysics() +{ + RestorePhysics(); + Py_RETURN_NONE; +} PyObject *KX_GameObject::PySuspendDynamics(PyObject *args) { bool ghost = false; - if (!PyArg_ParseTuple(args, "|b", &ghost)) - return NULL; + if (!PyArg_ParseTuple(args, "|b", &ghost)) { + return nullptr; + } - if (GetPhysicsController()) - GetPhysicsController()->SuspendDynamics(ghost); + if (m_physicsController) { + m_physicsController->SuspendDynamics(ghost); + } Py_RETURN_NONE; } @@ -3507,59 +3795,59 @@ PyObject *KX_GameObject::PySuspendDynamics(PyObject *args) PyObject *KX_GameObject::PyRestoreDynamics() { // Child objects must be static, so we block changing to dynamic - if (GetPhysicsController() && !GetParent()) - GetPhysicsController()->RestoreDynamics(); + if (m_physicsController && !GetParent()) { + m_physicsController->RestoreDynamics(); + } Py_RETURN_NONE; } -PyObject *KX_GameObject::PyAlignAxisToVect(PyObject *args) +PyObject *KX_GameObject::PyAlignAxisToVect(PyObject *args, PyObject *kwds) { PyObject *pyvect; int axis = 2; //z axis is the default float fac = 1.0f; - if (PyArg_ParseTuple(args,"O|if:alignAxisToVect",&pyvect,&axis, &fac)) - { - MT_Vector3 vect; + if (EXP_ParseTupleArgsAndKeywords(args, kwds, "O|if:alignAxisToVect", {"vect", "axis", "factor", 0}, + &pyvect, &axis, &fac)) { + mt::vec3 vect; if (PyVecTo(pyvect, vect)) { if (fac > 0.0f) { - if (fac> 1.0f) fac = 1.0f; + if (fac > 1.0f) { + fac = 1.0f; + } AlignAxisToVect(vect, axis, fac); - NodeUpdateGS(0.f); + NodeUpdate(); } Py_RETURN_NONE; } } - return NULL; + return nullptr; } PyObject *KX_GameObject::PyGetAxisVect(PyObject *value) { - MT_Vector3 vect; - if (PyVecTo(value, vect)) - { + mt::vec3 vect; + if (PyVecTo(value, vect)) { return PyObjectFrom(NodeGetWorldOrientation() * vect); } - return NULL; + return nullptr; } PyObject *KX_GameObject::PyGetPhysicsId() { - PHY_IPhysicsController* ctrl = GetPhysicsController(); unsigned long long physid = 0; - if (ctrl) - { - physid = (unsigned long long)ctrl; + if (m_physicsController) { + physid = (unsigned long long)m_physicsController.get(); } return PyLong_FromUnsignedLongLong(physid); } PyObject *KX_GameObject::PyGetPropertyNames() { - PyObject *list= ConvertKeysToPython(); + PyObject *list = ConvertKeysToPython(); if (m_attr_dict) { PyObject *key, *value; @@ -3572,63 +3860,58 @@ PyObject *KX_GameObject::PyGetPropertyNames() return list; } -KX_PYMETHODDEF_DOC_O(KX_GameObject, getDistanceTo, -"getDistanceTo(other): get distance to another point/KX_GameObject") +EXP_PYMETHODDEF_DOC_O(KX_GameObject, getDistanceTo, + "getDistanceTo(other): get distance to another point/KX_GameObject") { - MT_Point3 b; - if (PyVecTo(value, b)) - { - return PyFloat_FromDouble(NodeGetWorldPosition().distance(b)); + mt::vec3 b; + if (PyVecTo(value, b)) { + return PyFloat_FromDouble((NodeGetWorldPosition() - b).Length()); } PyErr_Clear(); SCA_LogicManager *logicmgr = GetScene()->GetLogicManager(); KX_GameObject *other; - if (ConvertPythonToGameObject(logicmgr, value, &other, false, "gameOb.getDistanceTo(value): KX_GameObject")) - { - return PyFloat_FromDouble(NodeGetWorldPosition().distance(other->NodeGetWorldPosition())); + if (ConvertPythonToGameObject(logicmgr, value, &other, false, "gameOb.getDistanceTo(value): KX_GameObject")) { + return PyFloat_FromDouble((NodeGetWorldPosition() - other->NodeGetWorldPosition()).Length()); } - return NULL; + return nullptr; } -KX_PYMETHODDEF_DOC_O(KX_GameObject, getVectTo, -"getVectTo(other): get vector and the distance to another point/KX_GameObject\n" -"Returns a 3-tuple with (distance,worldVector,localVector)\n") +EXP_PYMETHODDEF_DOC_O(KX_GameObject, getVectTo, + "getVectTo(other): get vector and the distance to another point/KX_GameObject\n" + "Returns a 3-tuple with (distance,worldVector,localVector)\n") { - MT_Point3 toPoint, fromPoint; - MT_Vector3 toDir, locToDir; - MT_Scalar distance; + mt::vec3 toPoint, fromPoint; + mt::vec3 toDir, locToDir; + float distance; SCA_LogicManager *logicmgr = GetScene()->GetLogicManager(); PyObject *returnValue; - if (!PyVecTo(value, toPoint)) - { + if (!PyVecTo(value, toPoint)) { PyErr_Clear(); KX_GameObject *other; - if (ConvertPythonToGameObject(logicmgr, value, &other, false, "")) /* error will be overwritten */ - { + if (ConvertPythonToGameObject(logicmgr, value, &other, false, "")) { /* error will be overwritten */ toPoint = other->NodeGetWorldPosition(); - } else - { + } + else { PyErr_SetString(PyExc_TypeError, "gameOb.getVectTo(other): KX_GameObject, expected a 3D Vector or KX_GameObject type"); - return NULL; + return nullptr; } } fromPoint = NodeGetWorldPosition(); - toDir = toPoint-fromPoint; - distance = toDir.length(); + toDir = toPoint - fromPoint; + distance = toDir.Length(); - if (MT_fuzzyZero(distance)) - { - //cout << "getVectTo() Error: Null vector!\n"; - locToDir = toDir = MT_Vector3(0.0f,0.0f,0.0f); + if (mt::FuzzyZero(distance)) { + locToDir = toDir = mt::zero3; distance = 0.0f; - } else { - toDir.normalize(); + } + else { + toDir.Normalize(); locToDir = toDir * NodeGetWorldOrientation(); } @@ -3641,33 +3924,30 @@ KX_PYMETHODDEF_DOC_O(KX_GameObject, getVectTo, return returnValue; } -struct KX_GameObject::RayCastData +KX_GameObject::RayCastData::RayCastData(const std::string& prop, bool xray, unsigned int mask) + :m_prop(prop), + m_xray(xray), + m_mask(mask), + m_hitObject(nullptr) { - RayCastData(STR_String prop, bool xray, short mask) - :m_prop(prop), - m_xray(xray), - m_mask(mask), - m_hitObject(NULL) - { - } +} - STR_String m_prop; - bool m_xray; - unsigned short m_mask; - KX_GameObject *m_hitObject; -}; +static bool CheckRayCastObject(KX_GameObject *obj, KX_GameObject::RayCastData *rayData) +{ + const std::string& prop = rayData->m_prop; + const unsigned int mask = rayData->m_mask; + // Check if the object had a given property (if this one is non empty) and have the correct group mask (if this one is different from 0xFFFF). + return ((prop.empty() || obj->GetProperty(prop)) && (mask == ((1u << OB_MAX_COL_MASKS) - 1) || obj->GetCollisionGroup() & mask)); +} bool KX_GameObject::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, RayCastData *rayData) { - KX_GameObject* hitKXObj = client->m_gameobject; + KX_GameObject *obj = client->m_gameobject; - // if X-ray option is selected, the unwnted objects were not tested, so get here only with true hit + // if X-ray option is selected, the unwanted objects were not tested, so get here only with true hit // if not, all objects were tested and the front one may not be the correct one. - if ((rayData->m_xray || rayData->m_prop.Length() == 0 || hitKXObj->GetProperty(rayData->m_prop) != NULL) && - hitKXObj->GetUserCollisionGroup() & rayData->m_mask) - { - rayData->m_hitObject = hitKXObj; - return true; + if (rayData->m_xray || CheckRayCastObject(obj, rayData)) { + rayData->m_hitObject = obj; } // return true to stop RayCast::RayTest from looping, the above test was decisive // We would want to loop only if we want to get more than one hit point @@ -3679,67 +3959,54 @@ bool KX_GameObject::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, RayC */ bool KX_GameObject::NeedRayCast(KX_ClientObjectInfo *client, RayCastData *rayData) { - KX_GameObject* hitKXObj = client->m_gameobject; - - if (client->m_type > KX_ClientObjectInfo::ACTOR) - { - // Unknown type of object, skip it. - // Should not occur as the sensor objects are filtered in RayTest() - printf("Invalid client type %d found in ray casting\n", client->m_type); - return false; - } + KX_GameObject *obj = client->m_gameobject; // if X-Ray option is selected, skip object that don't match the criteria as we see through them // if not, test all objects because we don't know yet which one will be on front - if ((!rayData->m_xray || rayData->m_prop.Length() == 0 || hitKXObj->GetProperty(rayData->m_prop) != NULL) && - hitKXObj->GetUserCollisionGroup() & rayData->m_mask) - { - return true; - } - // skip the object - return false; + return (!rayData->m_xray || CheckRayCastObject(obj, rayData)); } -KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, -"rayCastTo(other,dist,prop): look towards another point/KX_GameObject and return first object hit within dist that matches prop\n" -" prop = property name that object must have; can be omitted => detect any object\n" -" dist = max distance to look (can be negative => look behind); 0 or omitted => detect up to other\n" -" other = 3-tuple or object reference") +EXP_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, + "rayCastTo(other,dist,prop): look towards another point/KX_GameObject and return first object hit within dist that matches prop\n" + " prop = property name that object must have; can be omitted => detect any object\n" + " dist = max distance to look (can be negative => look behind); 0 or omitted => detect up to other\n" + " other = 3-tuple or object reference") { - MT_Point3 toPoint; + mt::vec3 toPoint; PyObject *pyarg; float dist = 0.0f; - char *propName = NULL; + const char *propName = ""; SCA_LogicManager *logicmgr = GetScene()->GetLogicManager(); - if (!PyArg_ParseTuple(args,"O|fs:rayCastTo", &pyarg, &dist, &propName)) { - return NULL; // python sets simple error + if (!EXP_ParseTupleArgsAndKeywords(args, kwds, "O|fs:rayCastTo", {"other", "dist", "prop", 0}, + &pyarg, &dist, &propName)) { + return nullptr; // python sets simple error } - if (!PyVecTo(pyarg, toPoint)) - { + if (!PyVecTo(pyarg, toPoint)) { KX_GameObject *other; PyErr_Clear(); - if (ConvertPythonToGameObject(logicmgr, pyarg, &other, false, "")) /* error will be overwritten */ - { + if (ConvertPythonToGameObject(logicmgr, pyarg, &other, false, "")) { /* error will be overwritten */ toPoint = other->NodeGetWorldPosition(); - } else - { + } + else { PyErr_SetString(PyExc_TypeError, "gameOb.rayCastTo(other,dist,prop): KX_GameObject, the first argument to rayCastTo must be a vector or a KX_GameObject"); - return NULL; + return nullptr; } } - MT_Point3 fromPoint = NodeGetWorldPosition(); + mt::vec3 fromPoint = NodeGetWorldPosition(); - if (dist != 0.0f) - toPoint = fromPoint + dist * (toPoint-fromPoint).safe_normalized(); + if (dist != 0.0f) { + toPoint = fromPoint + dist * (toPoint - fromPoint).SafeNormalized(mt::axisX3); + } - PHY_IPhysicsEnvironment* pe = GetScene()->GetPhysicsEnvironment(); - PHY_IPhysicsController *spc = GetPhysicsController(); + PHY_IPhysicsEnvironment *pe = GetScene()->GetPhysicsEnvironment(); + PHY_IPhysicsController *spc = m_physicsController.get(); KX_GameObject *parent = GetParent(); - if (!spc && parent) + if (!spc && parent) { spc = parent->GetPhysicsController(); + } RayCastData rayData(propName, false, (1u << OB_MAX_COL_MASKS) - 1); KX_RayCast::Callback callback(this, spc, &rayData); @@ -3753,7 +4020,7 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo, /* faster then Py_BuildValue since some scripts call raycast a lot */ static PyObject *none_tuple_3() { - PyObject *ret= PyTuple_New(3); + PyObject *ret = PyTuple_New(3); PyTuple_SET_ITEM(ret, 0, Py_None); PyTuple_SET_ITEM(ret, 1, Py_None); PyTuple_SET_ITEM(ret, 2, Py_None); @@ -3765,7 +4032,7 @@ static PyObject *none_tuple_3() } static PyObject *none_tuple_4() { - PyObject *ret= PyTuple_New(4); + PyObject *ret = PyTuple_New(4); PyTuple_SET_ITEM(ret, 0, Py_None); PyTuple_SET_ITEM(ret, 1, Py_None); PyTuple_SET_ITEM(ret, 2, Py_None); @@ -3780,7 +4047,7 @@ static PyObject *none_tuple_4() static PyObject *none_tuple_5() { - PyObject *ret= PyTuple_New(5); + PyObject *ret = PyTuple_New(5); PyTuple_SET_ITEM(ret, 0, Py_None); PyTuple_SET_ITEM(ret, 1, Py_None); PyTuple_SET_ITEM(ret, 2, Py_None); @@ -3795,98 +4062,97 @@ static PyObject *none_tuple_5() return ret; } -KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, - "rayCast(to,from,dist,prop,face,xray,poly,mask): cast a ray and return 3-tuple (object,hit,normal) or 4-tuple (object,hit,normal,polygon) or 4-tuple (object,hit,normal,polygon,hituv) of contact point with object within dist that matches prop.\n" - " If no hit, return (None,None,None) or (None,None,None,None) or (None,None,None,None,None).\n" -" to = 3-tuple or object reference for destination of ray (if object, use center of object)\n" -" from = 3-tuple or object reference for origin of ray (if object, use center of object)\n" -" Can be None or omitted => start from self object center\n" -" dist = max distance to look (can be negative => look behind); 0 or omitted => detect up to to\n" -" prop = property name that object must have; can be omitted => detect any object\n" -" face = normal option: 1=>return face normal; 0 or omitted => normal is oriented towards origin\n" -" xray = X-ray option: 1=>skip objects that don't match prop; 0 or omitted => stop on first object\n" -" poly = polygon option: 1=>return value is a 4-tuple and the 4th element is a KX_PolyProxy object\n" -" which can be None if hit object has no mesh or if there is no hit\n" -" 2=>return value is a 5-tuple, the 4th element is the KX_PolyProxy object\n" -" and the 5th element is the vector of UV coordinates at the hit point of the None if there is no UV mapping\n" -" If 0 or omitted, return value is a 3-tuple\n" -" mask = collision mask: the collision mask that ray can hit, 0 < mask < 65536\n" -"Note: The object on which you call this method matters: the ray will ignore it.\n" -" prop and xray option interact as follow:\n" -" prop off, xray off: return closest hit or no hit if there is no object on the full extend of the ray\n" -" prop off, xray on : idem\n" -" prop on, xray off: return closest hit if it matches prop, no hit otherwise\n" -" prop on, xray on : return closest hit matching prop or no hit if there is no object matching prop on the full extend of the ray\n") -{ - MT_Point3 toPoint; - MT_Point3 fromPoint; +EXP_PYMETHODDEF_DOC(KX_GameObject, rayCast, + "rayCast(to,from,dist,prop,face,xray,poly,mask): cast a ray and return 3-tuple (object,hit,normal) or 4-tuple (object,hit,normal,polygon) or 4-tuple (object,hit,normal,polygon,hituv) of contact point with object within dist that matches prop.\n" + " If no hit, return (None,None,None) or (None,None,None,None) or (None,None,None,None,None).\n" + " to = 3-tuple or object reference for destination of ray (if object, use center of object)\n" + " from = 3-tuple or object reference for origin of ray (if object, use center of object)\n" + " Can be None or omitted => start from self object center\n" + " dist = max distance to look (can be negative => look behind); 0 or omitted => detect up to to\n" + " prop = property name that object must have; can be omitted => detect any object\n" + " face = normal option: 1=>return face normal; 0 or omitted => normal is oriented towards origin\n" + " xray = X-ray option: 1=>skip objects that don't match prop; 0 or omitted => stop on first object\n" + " poly = polygon option: 1=>return value is a 4-tuple and the 4th element is a KX_PolyProxy object\n" + " which can be None if hit object has no mesh or if there is no hit\n" + " 2=>return value is a 5-tuple, the 4th element is the KX_PolyProxy object\n" + " and the 5th element is the vector of UV coordinates at the hit point of the None if there is no UV mapping\n" + " If 0 or omitted, return value is a 3-tuple\n" + " mask = collision mask: the collision mask that ray can hit, 0 < mask < 65536\n" + "Note: The object on which you call this method matters: the ray will ignore it.\n" + " prop and xray option interact as follow:\n" + " prop off, xray off: return closest hit or no hit if there is no object on the full extend of the ray\n" + " prop off, xray on : idem\n" + " prop on, xray off: return closest hit if it matches prop, no hit otherwise\n" + " prop on, xray on : return closest hit matching prop or no hit if there is no object matching prop on the full extend of the ray\n") +{ + mt::vec3 toPoint; + mt::vec3 fromPoint; PyObject *pyto; - PyObject *pyfrom = NULL; + PyObject *pyfrom = Py_None; float dist = 0.0f; - char *propName = NULL; + const char *propName = ""; KX_GameObject *other; - int face=0, xray=0, poly=0; + int face = 0, xray = 0, poly = 0; int mask = (1 << OB_MAX_COL_MASKS) - 1; SCA_LogicManager *logicmgr = GetScene()->GetLogicManager(); - if (!PyArg_ParseTuple(args,"O|Ofsiiii:rayCast", &pyto, &pyfrom, &dist, &propName, &face, &xray, &poly, &mask)) { - return NULL; // Python sets a simple error + if (!EXP_ParseTupleArgsAndKeywords(args, kwds, "O|Ofsiiii:rayCast", + {"objto", "objfrom", "dist", "prop", "face", "xray", "poly", "mask", 0}, + &pyto, &pyfrom, &dist, &propName, &face, &xray, &poly, &mask)) { + return nullptr; // Python sets a simple error } - if (!PyVecTo(pyto, toPoint)) - { + if (!PyVecTo(pyto, toPoint)) { PyErr_Clear(); - if (ConvertPythonToGameObject(logicmgr, pyto, &other, false, "")) /* error will be overwritten */ - { + if (ConvertPythonToGameObject(logicmgr, pyto, &other, false, "")) { /* error will be overwritten */ toPoint = other->NodeGetWorldPosition(); - } else - { + } + else { PyErr_SetString(PyExc_TypeError, "the first argument to rayCast must be a vector or a KX_GameObject"); - return NULL; + return nullptr; } } - if (!pyfrom || pyfrom == Py_None) - { + if (pyfrom == Py_None) { fromPoint = NodeGetWorldPosition(); } - else if (!PyVecTo(pyfrom, fromPoint)) - { + else if (!PyVecTo(pyfrom, fromPoint)) { PyErr_Clear(); - if (ConvertPythonToGameObject(logicmgr, pyfrom, &other, false, "")) /* error will be overwritten */ - { + if (ConvertPythonToGameObject(logicmgr, pyfrom, &other, false, "")) { /* error will be overwritten */ fromPoint = other->NodeGetWorldPosition(); - } else - { + } + else { PyErr_SetString(PyExc_TypeError, "gameOb.rayCast(to,from,dist,prop,face,xray,poly,mask): KX_GameObject, the second optional argument to rayCast must be a vector or a KX_GameObject"); - return NULL; + return nullptr; } } if (mask == 0 || mask & ~((1 << OB_MAX_COL_MASKS) - 1)) { PyErr_Format(PyExc_TypeError, "gameOb.rayCast(to,from,dist,prop,face,xray,poly,mask): KX_GameObject, mask argument to rayCast must be a int bitfield, 0 < mask < %i", (1 << OB_MAX_COL_MASKS)); - return NULL; + return nullptr; } if (dist != 0.0f) { - MT_Vector3 toDir = toPoint-fromPoint; - if (MT_fuzzyZero(toDir.length2())) { + mt::vec3 toDir = toPoint - fromPoint; + if (mt::FuzzyZero(toDir)) { //return Py_BuildValue("OOO", Py_None, Py_None, Py_None); return none_tuple_3(); } - toDir.normalize(); + toDir.Normalize(); toPoint = fromPoint + (dist) * toDir; - } else if (MT_fuzzyZero((toPoint-fromPoint).length2())) { + } + else if (mt::FuzzyZero(toPoint - fromPoint)) { //return Py_BuildValue("OOO", Py_None, Py_None, Py_None); return none_tuple_3(); } - PHY_IPhysicsEnvironment* pe = GetScene()->GetPhysicsEnvironment(); - PHY_IPhysicsController *spc = GetPhysicsController(); + PHY_IPhysicsEnvironment *pe = GetScene()->GetPhysicsEnvironment(); + PHY_IPhysicsController *spc = m_physicsController.get(); KX_GameObject *parent = GetParent(); - if (!spc && parent) + if (!spc && parent) { spc = parent->GetPhysicsController(); + } // to get the hit results RayCastData rayData(propName, xray, mask); @@ -3898,30 +4164,27 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, PyTuple_SET_ITEM(returnValue, 0, rayData.m_hitObject->GetProxy()); PyTuple_SET_ITEM(returnValue, 1, PyObjectFrom(callback.m_hitPoint)); PyTuple_SET_ITEM(returnValue, 2, PyObjectFrom(callback.m_hitNormal)); - if (poly) - { - if (callback.m_hitMesh) - { + if (poly) { + if (callback.m_hitMesh) { + KX_Mesh *mesh = static_cast(callback.m_hitMesh); // if this field is set, then we can trust that m_hitPolygon is a valid polygon - RAS_Polygon* polygon = callback.m_hitMesh->GetPolygon(callback.m_hitPolygon); - KX_PolyProxy* polyproxy = new KX_PolyProxy(callback.m_hitMesh, polygon); + const RAS_Mesh::PolygonInfo polygon = mesh->GetPolygon(callback.m_hitPolygon); + KX_PolyProxy *polyproxy = new KX_PolyProxy(mesh, polygon); PyTuple_SET_ITEM(returnValue, 3, polyproxy->NewProxy(true)); - if (poly == 2) - { - if (callback.m_hitUVOK) + if (poly == 2) { + if (callback.m_hitUVOK) { PyTuple_SET_ITEM(returnValue, 4, PyObjectFrom(callback.m_hitUV)); + } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(returnValue, 4, Py_None); } } } - else - { + else { Py_INCREF(Py_None); PyTuple_SET_ITEM(returnValue, 3, Py_None); - if (poly==2) - { + if (poly == 2) { Py_INCREF(Py_None); PyTuple_SET_ITEM(returnValue, 4, Py_None); } @@ -3931,77 +4194,80 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast, return returnValue; } // no hit - if (poly == 2) + if (poly == 2) { return none_tuple_5(); - else if (poly) + } + else if (poly) { return none_tuple_4(); - else + } + else { return none_tuple_3(); + } } -KX_PYMETHODDEF_DOC_VARARGS(KX_GameObject, sendMessage, - "sendMessage(subject, [body, to])\n" -"sends a message in same manner as a message actuator" -"subject = Subject of the message (string)" -"body = Message body (string)" -"to = Name of object to send the message to") +EXP_PYMETHODDEF_DOC(KX_GameObject, sendMessage, + "sendMessage(subject, [body, to])\n" + "sends a message in same manner as a message actuator" + "subject = Subject of the message (string)" + "body = Message body (string)" + "to = Name of object to send the message to") { - KX_Scene *scene = KX_GetActiveScene(); - char* subject; - char* body = (char *)""; - char* to = (char *)""; - const STR_String& from = GetName(); + char *subject; + char *body = (char *)""; + char *to = (char *)""; - if (!PyArg_ParseTuple(args, "s|ss:sendMessage", &subject, &body, &to)) - return NULL; + if (!EXP_ParseTupleArgsAndKeywords(args, kwds, "s|ss:sendMessage", {"subject", "body", "to", 0}, + &subject, &body, &to)) { + return nullptr; + } - scene->GetNetworkScene()->SendMessage(to, from, subject, body); + GetScene()->GetNetworkMessageScene()->SendMessage(to, this, subject, body); Py_RETURN_NONE; } static void layer_check(short &layer, const char *method_name) { - if (layer < 0 || layer >= MAX_ACTION_LAYERS) - { - printf("KX_GameObject.%s(): given layer (%d) is out of range (0 - %d), setting to 0.\n", method_name, layer, MAX_ACTION_LAYERS-1); + if (layer < 0 || layer >= MAX_ACTION_LAYERS) { + CM_PythonFunctionWarning("KX_GameObject", method_name, "given layer (" << layer + << ") is out of range (0 - " << (MAX_ACTION_LAYERS - 1) << "), setting to 0."); layer = 0; } } -KX_PYMETHODDEF_DOC(KX_GameObject, playAction, - "playAction(name, start_frame, end_frame, layer=0, priority=0 blendin=0, play_mode=ACT_MODE_PLAY, layer_weight=0.0, ipo_flags=0, speed=1.0)\n" - "Plays an action\n") +EXP_PYMETHODDEF_DOC(KX_GameObject, playAction, + "playAction(name, start_frame, end_frame, layer=0, priority=0 blendin=0, play_mode=ACT_MODE_PLAY, layer_weight=0.0, ipo_flags=0, speed=1.0)\n" + "Plays an action\n") { - const char* name; - float start, end, blendin=0.f, speed=1.f, layer_weight=0.f; - short layer=0, priority=0; - short ipo_flags=0; - short play_mode=0; - short blend_mode=0; - - static const char *kwlist[] = {"name", "start_frame", "end_frame", "layer", "priority", "blendin", "play_mode", "layer_weight", "ipo_flags", "speed", "blend_mode", NULL}; + const char *name; + float start, end, blendin = 0.f, speed = 1.f, layer_weight = 0.f; + short layer = 0, priority = 0; + short ipo_flags = 0; + short play_mode = 0; + short blend_mode = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "sff|hhfhfhfh:playAction", const_cast(kwlist), - &name, &start, &end, &layer, &priority, &blendin, &play_mode, &layer_weight, &ipo_flags, &speed, &blend_mode)) - return NULL; + if (!EXP_ParseTupleArgsAndKeywords(args, kwds, "sff|hhfhfhfh:playAction", {"name", "start_frame", "end_frame", "layer", + "priority", "blendin", "play_mode", "layer_weight", "ipo_flags", "speed", "blend_mode", 0}, + &name, &start, &end, &layer, &priority, &blendin, &play_mode, &layer_weight, &ipo_flags, &speed, &blend_mode)) { + return nullptr; + } layer_check(layer, "playAction"); - if (play_mode < 0 || play_mode > BL_Action::ACT_MODE_MAX) - { - printf("KX_GameObject.playAction(): given play_mode (%d) is out of range (0 - %d), setting to ACT_MODE_PLAY", play_mode, BL_Action::ACT_MODE_MAX-1); + if (play_mode < 0 || play_mode > BL_Action::ACT_MODE_MAX) { + CM_PythonFunctionWarning("KX_GameObject", "playAction", "given play_mode (" << play_mode << ") is out of range (0 - " + << (BL_Action::ACT_MODE_MAX - 1) << "), setting to ACT_MODE_PLAY"); play_mode = BL_Action::ACT_MODE_PLAY; } - if (blend_mode < 0 || blend_mode > BL_Action::ACT_BLEND_MAX) - { - printf("KX_GameObject.playAction(): given blend_mode (%d) is out of range (0 - %d), setting to ACT_BLEND_BLEND", blend_mode, BL_Action::ACT_BLEND_MAX-1); + if (blend_mode < 0 || blend_mode > BL_Action::ACT_BLEND_MAX) { + CM_PythonFunctionWarning("KX_GameObject", "playAction", "given blend_mode (" << blend_mode << ") is out of range (0 - " + << (BL_Action::ACT_BLEND_MAX - 1) << "), setting to ACT_BLEND_BLEND"); blend_mode = BL_Action::ACT_BLEND_BLEND; } - if (layer_weight < 0.f || layer_weight > 1.f) - { - printf("KX_GameObject.playAction(): given layer_weight (%f) is out of range (0.0 - 1.0), setting to 0.0", layer_weight); + if (layer_weight < 0.f || layer_weight > 1.f) { + CM_PythonFunctionWarning("KX_GameObject", "playAction", "given layer_weight (" << layer_weight + << ") is out of range (0.0 - 1.0), setting to 0.0"); layer_weight = 0.f; } @@ -4010,14 +4276,15 @@ KX_PYMETHODDEF_DOC(KX_GameObject, playAction, Py_RETURN_NONE; } -KX_PYMETHODDEF_DOC(KX_GameObject, stopAction, - "stopAction(layer=0)\n" - "Stop playing the action on the given layer\n") +EXP_PYMETHODDEF_DOC(KX_GameObject, stopAction, + "stopAction(layer=0)\n" + "Stop playing the action on the given layer\n") { short layer = 0; - if (!PyArg_ParseTuple(args, "|h:stopAction", &layer)) - return NULL; + if (!PyArg_ParseTuple(args, "|h:stopAction", &layer)) { + return nullptr; + } layer_check(layer, "stopAction"); @@ -4026,43 +4293,46 @@ KX_PYMETHODDEF_DOC(KX_GameObject, stopAction, Py_RETURN_NONE; } -KX_PYMETHODDEF_DOC(KX_GameObject, getActionFrame, - "getActionFrame(layer=0)\n" - "Gets the current frame of the action playing in the supplied layer\n") +EXP_PYMETHODDEF_DOC(KX_GameObject, getActionFrame, + "getActionFrame(layer=0)\n" + "Gets the current frame of the action playing in the supplied layer\n") { short layer = 0; - if (!PyArg_ParseTuple(args, "|h:getActionFrame", &layer)) - return NULL; + if (!PyArg_ParseTuple(args, "|h:getActionFrame", &layer)) { + return nullptr; + } layer_check(layer, "getActionFrame"); return PyFloat_FromDouble(GetActionFrame(layer)); } -KX_PYMETHODDEF_DOC(KX_GameObject, getActionName, - "getActionName(layer=0)\n" - "Gets the name of the current action playing in the supplied layer\n") +EXP_PYMETHODDEF_DOC(KX_GameObject, getActionName, + "getActionName(layer=0)\n" + "Gets the name of the current action playing in the supplied layer\n") { short layer = 0; - if (!PyArg_ParseTuple(args, "|h:getActionName", &layer)) - return NULL; + if (!PyArg_ParseTuple(args, "|h:getActionName", &layer)) { + return nullptr; + } layer_check(layer, "getActionName"); - return PyUnicode_FromString(GetActionName(layer)); + return PyUnicode_FromStdString(GetActionName(layer)); } -KX_PYMETHODDEF_DOC(KX_GameObject, setActionFrame, - "setActionFrame(frame, layer=0)\n" - "Set the current frame of the action playing in the supplied layer\n") +EXP_PYMETHODDEF_DOC(KX_GameObject, setActionFrame, + "setActionFrame(frame, layer=0)\n" + "Set the current frame of the action playing in the supplied layer\n") { short layer = 0; float frame; - if (!PyArg_ParseTuple(args, "f|h:setActionFrame", &frame, &layer)) - return NULL; + if (!PyArg_ParseTuple(args, "f|h:setActionFrame", &frame, &layer)) { + return nullptr; + } layer_check(layer, "setActionFrame"); @@ -4071,14 +4341,15 @@ KX_PYMETHODDEF_DOC(KX_GameObject, setActionFrame, Py_RETURN_NONE; } -KX_PYMETHODDEF_DOC(KX_GameObject, isPlayingAction, - "isPlayingAction(layer=0)\n" - "Checks to see if there is an action playing in the given layer\n") +EXP_PYMETHODDEF_DOC(KX_GameObject, isPlayingAction, + "isPlayingAction(layer=0)\n" + "Checks to see if there is an action playing in the given layer\n") { short layer = 0; - if (!PyArg_ParseTuple(args, "|h:isPlayingAction", &layer)) - return NULL; + if (!PyArg_ParseTuple(args, "|h:isPlayingAction", &layer)) { + return nullptr; + } layer_check(layer, "isPlayingAction"); @@ -4086,20 +4357,22 @@ KX_PYMETHODDEF_DOC(KX_GameObject, isPlayingAction, } -KX_PYMETHODDEF_DOC(KX_GameObject, addDebugProperty, -"addDebugProperty(name, visible=1)\n" -"Added or remove a debug property to the debug list.\n") +EXP_PYMETHODDEF_DOC(KX_GameObject, addDebugProperty, + "addDebugProperty(name, visible=1)\n" + "Added or remove a debug property to the debug list.\n") { - KX_Scene *scene = KX_GetActiveScene(); + KX_Scene *scene = GetScene(); char *name; int visible = 1; - if (!PyArg_ParseTuple(args,"s|i:debugProperty", &name , &visible)) - return NULL; + if (!PyArg_ParseTuple(args, "s|i:debugProperty", &name, &visible)) { + return nullptr; + } if (visible) { - if (!scene->PropertyInDebugList(this, name)) + if (!scene->PropertyInDebugList(this, name)) { scene->AddDebugProperty(this, name); + } } else { scene->RemoveDebugProperty(this, name); @@ -4119,22 +4392,25 @@ PyObject *KX_GameObject::Pyget(PyObject *args) PyObject *def = Py_None; PyObject *ret; - if (!PyArg_ParseTuple(args, "O|O:get", &key, &def)) - return NULL; + if (!PyArg_ParseTuple(args, "O|O:get", &key, &def)) { + return nullptr; + } if (PyUnicode_Check(key)) { - CValue *item = GetProperty(_PyUnicode_AsString(key)); + EXP_Value *item = GetProperty(_PyUnicode_AsString(key)); if (item) { ret = item->ConvertValueToPython(); - if (ret) + if (ret) { return ret; - else + } + else { return item->GetProxy(); + } } } - if (m_attr_dict && (ret=PyDict_GetItem(m_attr_dict, key))) { + if (m_attr_dict && (ret = PyDict_GetItem(m_attr_dict, key))) { Py_INCREF(ret); return ret; } @@ -4145,56 +4421,58 @@ PyObject *KX_GameObject::Pyget(PyObject *args) bool ConvertPythonToGameObject(SCA_LogicManager *manager, PyObject *value, KX_GameObject **object, bool py_none_ok, const char *error_prefix) { - if (value==NULL) { - PyErr_Format(PyExc_TypeError, "%s, python pointer NULL, should never happen", error_prefix); - *object = NULL; + if (value == nullptr) { + PyErr_Format(PyExc_TypeError, "%s, python pointer nullptr, should never happen", error_prefix); + *object = nullptr; return false; } - if (value==Py_None) { - *object = NULL; + if (value == Py_None) { + *object = nullptr; if (py_none_ok) { return true; - } else { + } + else { PyErr_Format(PyExc_TypeError, "%s, expected KX_GameObject or a KX_GameObject name, None is invalid", error_prefix); return false; } } if (PyUnicode_Check(value)) { - *object = (KX_GameObject*)manager->GetGameObjectByName(STR_String( _PyUnicode_AsString(value) )); + *object = (KX_GameObject *)manager->GetGameObjectByName(std::string(_PyUnicode_AsString(value))); if (*object) { return true; - } else { + } + else { PyErr_Format(PyExc_ValueError, "%s, requested name \"%s\" did not match any KX_GameObject in this scene", error_prefix, _PyUnicode_AsString(value)); return false; } } - if (PyObject_TypeCheck(value, &KX_GameObject::Type) || - PyObject_TypeCheck(value, &KX_LightObject::Type) || - PyObject_TypeCheck(value, &KX_Camera::Type) || + if (PyObject_TypeCheck(value, &KX_GameObject::Type) || + PyObject_TypeCheck(value, &KX_LightObject::Type) || + PyObject_TypeCheck(value, &KX_Camera::Type) || PyObject_TypeCheck(value, &KX_FontObject::Type) || - PyObject_TypeCheck(value, &KX_NavMeshObject::Type)) - { - *object = static_castBGE_PROXY_REF(value); + PyObject_TypeCheck(value, &KX_NavMeshObject::Type)) { + *object = static_castEXP_PROXY_REF(value); /* sets the error */ - if (*object==NULL) { - PyErr_Format(PyExc_SystemError, "%s, " BGE_PROXY_ERROR_MSG, error_prefix); + if (*object == nullptr) { + PyErr_Format(PyExc_SystemError, "%s, " EXP_PROXY_ERROR_MSG, error_prefix); return false; } return true; } - *object = NULL; + *object = nullptr; if (py_none_ok) { PyErr_Format(PyExc_TypeError, "%s, expect a KX_GameObject, a string or None", error_prefix); - } else { + } + else { PyErr_Format(PyExc_TypeError, "%s, expect a KX_GameObject or a string", error_prefix); } diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h index 7a8243eb43d9..ec661afe044c 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -36,33 +36,37 @@ #ifdef _MSC_VER /* get rid of this stupid "warning 'this' used in initialiser list", generated by VC when including Solid/Sumo */ # pragma warning (disable:4355) -#endif +#endif #include #include "EXP_ListValue.h" #include "SCA_IObject.h" #include "SG_Node.h" -#include "MT_Transform.h" -#include "MT_CmMatrix4x4.h" -#include "CTR_Map.h" -#include "CTR_HashedPtr.h" +#include "SG_CullingNode.h" +#include "mathfu.h" #include "KX_Scene.h" #include "KX_KetsjiEngine.h" /* for m_anim_framerate */ +#include "KX_ClientObjectInfo.h" #include "DNA_constraint_types.h" /* for constraint replication */ #include "DNA_object_types.h" #include "SCA_LogicManager.h" /* for ConvertPythonToGameObject to search object names */ +#include "BL_Resource.h" // For BL_Resource::Library. -//Forward declarations. -struct KX_ClientObjectInfo; class KX_RayCast; -class RAS_MeshObject; +class KX_LodManager; +class KX_PythonComponent; +class KX_Mesh; +class RAS_MeshUser; +class RAS_Deformer; class PHY_IGraphicController; class PHY_IPhysicsEnvironment; class PHY_IPhysicsController; class BL_ActionManager; +class BL_ConvertObjectInfo; struct Object; class KX_ObstacleSimulation; +class KX_CollisionContactPointList; struct bAction; #ifdef WITH_PYTHON @@ -77,68 +81,83 @@ void KX_GameObject_Mathutils_Callback_Init(void); /** * KX_GameObject is the main class for dynamic objects. */ -class KX_GameObject : public SCA_IObject +class KX_GameObject : public SCA_IObject, public mt::SimdClassAllocator { Py_Header +public: + struct ActivityCullingInfo + { + ActivityCullingInfo(); + + enum Flag { + ACTIVITY_NONE = 0, + ACTIVITY_PHYSICS = (1 << 0), + ACTIVITY_LOGIC = (1 << 1) + } m_flags; + + /// Squared physics culling radius. + float m_physicsRadius; + /// Squared logic culling radius. + float m_logicRadius; + }; + protected: - bool m_bDyna; - KX_ClientObjectInfo* m_pClient_info; - STR_String m_name; - STR_String m_text; + KX_ClientObjectInfo m_clientInfo; + std::string m_name; int m_layer; - std::vector m_meshes; - std::vector m_lodmeshes; - int m_currentLodLevel; - short m_previousLodLevel; - SG_QList m_meshSlots; // head of mesh slots of this - struct Object* m_pBlenderObject; - struct Object* m_pBlenderGroupObject; - - bool m_bUseObjectColor; - bool m_bIsNegativeScaling; - MT_Vector4 m_objectColor; - - // Bit fields for user control over physics collisions - unsigned short m_userCollisionGroup; - unsigned short m_userCollisionMask; + short m_passIndex; + std::vector m_meshes; + KX_LodManager *m_lodManager; + short m_currentLodLevel; + RAS_MeshUser *m_meshUser; + /// Info about blender object convert from. + BL_ConvertObjectInfo *m_convertInfo; + + mt::vec4 m_objectColor; // visible = user setting // culled = while rendering, depending on camera - bool m_bVisible; - bool m_bCulled; + bool m_bVisible; bool m_bOccluder; - PHY_IPhysicsController* m_pPhysicsController; - PHY_IGraphicController* m_pGraphicController; + /// Object activity culling settings converted from blender objects. + ActivityCullingInfo m_activityCullingInfo; - SG_Node* m_pSGNode; + bool m_autoUpdateBounds; - MT_CmMatrix4x4 m_OpenGL_4x4Matrix; - std::vector m_constraints; + std::unique_ptr m_physicsController; + std::unique_ptr m_graphicController; - KX_ObstacleSimulation* m_pObstacleSimulation; + SG_CullingNode m_cullingNode; + std::unique_ptr m_sgNode; - CListValue* m_pInstanceObjects; - KX_GameObject* m_pDupliGroupObject; + EXP_ListValue *m_components; + + EXP_ListValue *m_instanceObjects; + KX_GameObject* m_dupliGroupObject; // The action manager is used to play/stop/update actions - BL_ActionManager* m_actionManager; + std::unique_ptr m_actionManager; BL_ActionManager* GetActionManager(); - bool m_bRecordAnimation; - public: - bool m_isDeformable; - /** * KX_GameObject custom infos for ray cast, it contains property name, * collision mask, xray flag and hited object. - * This structure is created during ray cast and passed as argument + * This structure is created during ray cast and passed as argument * "data" to functions KX_GameObject::NeedRayCast and KX_GameObject::RayHit. */ - struct RayCastData; + struct RayCastData + { + RayCastData(const std::string& prop, bool xray, unsigned int mask); + + std::string m_prop; + bool m_xray; + unsigned int m_mask; + KX_GameObject *m_hitObject; + }; /** * Helper function for modules that can't include KX_ClientObjectInfo.h @@ -146,20 +165,20 @@ class KX_GameObject : public SCA_IObject static KX_GameObject* GetClientObject(KX_ClientObjectInfo* info); #ifdef WITH_PYTHON - // Python attributes that wont convert into CValue + // Python attributes that wont convert into EXP_Value // - // there are 2 places attributes can be stored, in the CValue, - // where attributes are converted into BGE's CValue types + // there are 2 places attributes can be stored, in the EXP_Value, + // where attributes are converted into BGE's EXP_Value types // these can be used with property actuators // - // For the python API, For types that cannot be converted into CValues (lists, dicts, GameObjects) + // For the python API, For types that cannot be converted into EXP_Values (lists, dicts, GameObjects) // these will be put into "m_attr_dict", logic bricks cannot access them. // // rules for setting attributes. // - // * there should NEVER be a CValue and a m_attr_dict attribute with matching names. get/sets make sure of this. - // * if CValue conversion fails, use a PyObject in "m_attr_dict" - // * when assigning a value, first see if it can be a CValue, if it can remove the "m_attr_dict" and set the CValue + // * there should NEVER be a EXP_Value and a m_attr_dict attribute with matching names. get/sets make sure of this. + // * if EXP_Value conversion fails, use a PyObject in "m_attr_dict" + // * when assigning a value, first see if it can be a EXP_Value, if it can remove the "m_attr_dict" and set the EXP_Value // PyObject* m_attr_dict; PyObject* m_collisionCallbacks; @@ -167,53 +186,32 @@ class KX_GameObject : public SCA_IObject virtual void /* This function should be virtual - derived classed override it */ Relink( - CTR_Map *map + std::map& map ); - /** - * Compute an OpenGl compatible 4x4 matrix. Has the - * side effect of storing the result internally. The - * memory for the matrix remains the property of this class. - */ - float * - GetOpenGLMatrix( - ); - - /** - * Return a pointer to a MT_CmMatrix4x4 storing the - * opengl transformation for this object. This is updated - * by a call to GetOpenGLMatrix(). This class owns the - * memory for the returned matrix. - */ - - MT_CmMatrix4x4 * - GetOpenGLMatrixPtr( - ) { - return &m_OpenGL_4x4Matrix; - }; - /** * Update the blender object obmat field from the object world position - * if blendobj is NULL, update the object pointed by m_pBlenderObject + * if blendobj is nullptr, update the object pointed by m_blenderObject * The user must take action to restore the matrix before leaving the GE. * Used in Armature evaluation */ void - UpdateBlenderObjectMatrix(Object* blendobj=NULL); + UpdateBlenderObjectMatrix(Object* blendobj=nullptr); /** * Used for constraint replication for group instances. * The list of constraints is filled during data conversion. */ - void AddConstraint(bRigidBodyJointConstraint *cons); - std::vector GetConstraints(); - void ClearConstraints(); + const std::vector& GetConstraints(); - /** - * Get a pointer to the game object that is the parent of - * this object. Or NULL if there is no parent. The returned + void ReplicateConstraints(PHY_IPhysicsEnvironment *physEnv, const std::vector& constobj); + + + /** + * Get a pointer to the game object that is the parent of + * this object. Or nullptr if there is no parent. The returned * object is part of a reference counting scheme. Calling - * this function ups the reference count on the returned + * this function ups the reference count on the returned * object. It is the responsibility of the caller to decrement * the reference count when you have finished with it. */ @@ -221,15 +219,15 @@ class KX_GameObject : public SCA_IObject GetParent( ); - /** + /** * Sets the parent of this object to a game object */ - void SetParent(KX_Scene *scene, KX_GameObject *obj, bool addToCompound=true, bool ghost=true); + void SetParent(KX_GameObject *obj, bool addToCompound=true, bool ghost=true); - /** + /** * Removes the parent of this object to a game object */ - void RemoveParent(KX_Scene *scene); + void RemoveParent(); /********************************* * group reference API @@ -239,7 +237,7 @@ class KX_GameObject : public SCA_IObject GetDupliGroupObject( ); - CListValue* + EXP_ListValue* GetInstanceObjects( ); @@ -250,8 +248,8 @@ class KX_GameObject : public SCA_IObject void AddInstanceObjects(KX_GameObject* ); - - void + + void RemoveDupliGroupObject( ); @@ -265,7 +263,7 @@ class KX_GameObject : public SCA_IObject /** * Adds an action to the object's action manager */ - bool PlayAction(const char* name, + bool PlayAction(const std::string& name, float start, float end, short layer=0, @@ -285,7 +283,7 @@ class KX_GameObject : public SCA_IObject /** * Gets the name of the current action */ - const char *GetActionName(short layer); + const std::string GetActionName(short layer); /** * Sets the current frame of an action @@ -295,233 +293,168 @@ class KX_GameObject : public SCA_IObject /** * Gets the currently running action on the given layer */ - bAction *GetCurrentAction(short layer); + std::string GetCurrentActionName(short layer); /** * Sets play mode of the action on the given layer */ void SetPlayMode(short layer, short mode); - /** - * Sets the start and end times of the action on the given layer - */ - void SetTimes(short layer, float start, float end); - /** * Stop playing the action on the given layer */ void StopAction(short layer); - /** - * Remove playing tagged actions. - */ - void RemoveTaggedActions(); - /** * Check if an action has finished playing */ bool IsActionDone(short layer); + bool IsActionsSuspended(); + /** * Kick the object's action manager + * \param curtime The current time used to compute the actions frame. + * \param applyObject Set to true if the actions must transform this object, else it only manages actions' frames. */ - void UpdateActionManager(float curtime); + void UpdateActionManager(float curtime, bool applyObject); /********************************* * End Animation API *********************************/ /** - * Construct a game object. This class also inherits the + * Construct a game object. This class also inherits the * default constructors - use those with care! */ - KX_GameObject( void* sgReplicationInfo, SG_Callbacks callbacks ); - virtual + KX_GameObject(const KX_GameObject& other); + + virtual ~KX_GameObject( ); - /** + /** * \section Stuff which is here due to poor design. - * Inherited from CValue and needs an implementation. + * Inherited from EXP_Value and needs an implementation. * Do not expect these functions do to anything sensible. */ /** - * Inherited from CValue -- does nothing! - */ - CValue* - Calc( - VALUE_OPERATOR op, - CValue *val - ); - - /** - * Inherited from CValue -- does nothing! - */ - CValue* - CalcFinal( - VALUE_DATA_TYPE dtype, - VALUE_OPERATOR op, - CValue *val - ); - - /** - * Inherited from CValue -- does nothing! - */ - const - STR_String & - GetText( - ); - - /** - * Inherited from CValue -- does nothing! - */ - double - GetNumber( - ); - - /** - * \section Inherited from CValue. These are the useful - * part of the CValue interface that this class implements. + * \section Inherited from EXP_Value. These are the useful + * part of the EXP_Value interface that this class implements. */ /** - * Inherited from CValue -- returns the name of this object. + * Inherited from EXP_Value -- returns the name of this object. */ - STR_String& - GetName( - ); + virtual std::string GetName(); /** - * Inherited from CValue -- set the name of this object. + * Inherited from EXP_Value -- set the name of this object. */ - void - SetName( - const char *name - ); + virtual void SetName(const std::string& name); - /** - * Inherited from CValue -- return a new copy of this - * instance allocated on the heap. Ownership of the new + /** + * Inherited from EXP_Value -- return a new copy of this + * instance allocated on the heap. Ownership of the new * object belongs with the caller. */ - virtual CValue* - GetReplica( - ); + virtual EXP_Value *GetReplica(); - /** - * Inherited from CValue -- Makes sure any internal - * data owned by this class is deep copied. Called internally + /** Remove object resource coming from the given library. + * These resource could be actions and meshes. + * \param libraryId The identifier of the library used to recognize the resource. */ - virtual void - ProcessReplica(); - - /** + void RemoveRessources(const BL_Resource::Library& libraryId); + + /** * Return the linear velocity of the game object. */ - MT_Vector3 + mt::vec3 GetLinearVelocity( bool local=false ); - /** + /** * Return the linear velocity of a given point in world coordinate * but relative to center of object ([0,0,0]=center of object) */ - MT_Vector3 + mt::vec3 GetVelocity( - const MT_Point3& position + const mt::vec3& position ); /** * Return the mass of the object */ - MT_Scalar + float GetMass(); /** * Return the local inertia vector of the object */ - MT_Vector3 + mt::vec3 GetLocalInertia(); - /** + /** * Return the angular velocity of the game object. */ - MT_Vector3 + mt::vec3 GetAngularVelocity( bool local=false ); /** + * Return object's physics controller gravity + */ + mt::vec3 GetGravity() const; + + /** + * Set object's physics controller gravity + */ + void SetGravity(const mt::vec3 &gravity); + /** * Align the object to a given normal. */ - void + void AlignAxisToVect( - const MT_Vector3& vect, + const mt::vec3& vect, int axis = 2, float fac = 1.0 ); - /** + /** * Quick'n'dirty obcolor ipo stuff */ void SetObjectColor( - const MT_Vector4& rgbavec + const mt::vec4& rgbavec ); - const MT_Vector4& + const mt::vec4& GetObjectColor(); - - void - ResolveCombinedVelocities( - const MT_Vector3 & lin_vel, - const MT_Vector3 & ang_vel, - bool lin_vel_local, - bool ang_vel_local - ); + RAS_Deformer *GetDeformer(); /** * \return a pointer to the physics controller owned by this class. */ PHY_IPhysicsController* GetPhysicsController(); - - void SetPhysicsController(PHY_IPhysicsController* physicscontroller,bool isDynamic) - { - m_bDyna = isDynamic; - m_pPhysicsController = physicscontroller; - } - - virtual class RAS_Deformer* GetDeformer() - { - return 0; - } - virtual void SetDeformer(class RAS_Deformer* deformer) - { - - } + void SetPhysicsController(PHY_IPhysicsController *physicscontroller); /** - * \return a pointer to the graphic controller owner by this class + * \return a pointer to the graphic controller owner by this class */ - PHY_IGraphicController* GetGraphicController() - { - return m_pGraphicController; - } + PHY_IGraphicController* GetGraphicController(); + void SetGraphicController(PHY_IGraphicController* graphiccontroller); - void SetGraphicController(PHY_IGraphicController* graphiccontroller) - { - m_pGraphicController = graphiccontroller; - } /* * @add/remove the graphic controller to the physic system */ @@ -530,92 +463,69 @@ class KX_GameObject : public SCA_IObject /** Set the object's collison group * \param filter The group bitfield */ - void SetUserCollisionGroup(unsigned short filter); + void SetCollisionGroup(unsigned short filter); /** Set the object's collison mask - * \param filter The mask bitfield + * \param mask The mask bitfield */ - void SetUserCollisionMask(unsigned short mask); - unsigned short GetUserCollisionGroup(); - unsigned short GetUserCollisionMask(); - /** - * Extra broadphase check for user controllable collisions - */ - bool CheckCollision(KX_GameObject *other); + void SetCollisionMask(unsigned short mask); + unsigned short GetCollisionGroup() const; + unsigned short GetCollisionMask() const; /** * \section Coordinate system manipulation functions */ - void NodeSetLocalPosition(const MT_Point3& trans ); + void NodeSetLocalPosition(const mt::vec3& trans ); - void NodeSetLocalOrientation(const MT_Matrix3x3& rot ); - void NodeSetGlobalOrientation(const MT_Matrix3x3& rot ); + void NodeSetLocalOrientation(const mt::mat3& rot ); + void NodeSetGlobalOrientation(const mt::mat3& rot ); - void NodeSetLocalScale( const MT_Vector3& scale ); - void NodeSetWorldScale( const MT_Vector3& scale ); + void NodeSetLocalScale( const mt::vec3& scale ); + void NodeSetWorldScale( const mt::vec3& scale ); - void NodeSetRelativeScale( const MT_Vector3& scale ); + void NodeSetRelativeScale( const mt::vec3& scale ); // adapt local position so that world position is set to desired position - void NodeSetWorldPosition(const MT_Point3& trans); + void NodeSetWorldPosition(const mt::vec3& trans); - void - NodeUpdateGS( - double time - ); + void NodeUpdate(); - const MT_Matrix3x3& NodeGetWorldOrientation( ) const; - const MT_Vector3& NodeGetWorldScaling( ) const; - const MT_Point3& NodeGetWorldPosition( ) const; + const mt::mat3& NodeGetWorldOrientation( ) const; + const mt::vec3& NodeGetWorldScaling( ) const; + const mt::vec3& NodeGetWorldPosition( ) const; + mt::mat3x4 NodeGetWorldTransform() const; - const MT_Matrix3x3& NodeGetLocalOrientation( ) const; - const MT_Vector3& NodeGetLocalScaling( ) const; - const MT_Point3& NodeGetLocalPosition( ) const; + const mt::mat3& NodeGetLocalOrientation( ) const; + const mt::vec3& NodeGetLocalScaling( ) const; + const mt::vec3& NodeGetLocalPosition( ) const; + mt::mat3x4 NodeGetLocalTransform() const; /** * \section scene graph node accessor functions. */ - SG_Node* GetSGNode( ) - { - return m_pSGNode; + SG_Node* GetNode( ) + { + return m_sgNode.get(); } - const SG_Node* GetSGNode( ) const - { - return m_pSGNode; + const SG_Node* GetNode( ) const + { + return m_sgNode.get(); } - /** - * \section blender object accessor functions. - */ + Object *GetBlenderObject() const; - struct Object* GetBlenderObject( ) - { - return m_pBlenderObject; - } - - void SetBlenderObject(struct Object* obj) - { - m_pBlenderObject = obj; - } - - struct Object* GetBlenderGroupObject( ) - { - return m_pBlenderGroupObject; - } - - void SetBlenderGroupObject(struct Object* obj) - { - m_pBlenderGroupObject = obj; - } + BL_ConvertObjectInfo *GetConvertObjectInfo() const; + void SetConvertObjectInfo(BL_ConvertObjectInfo *info); bool IsDupliGroup() - { - return (m_pBlenderObject && - (m_pBlenderObject->transflag & OB_DUPLIGROUP) && - m_pBlenderObject->dup_group != NULL) ? true : false; + { + Object *blenderobj = GetBlenderObject(); + return (blenderobj && + (blenderobj->transflag & OB_DUPLIGROUP) && + blenderobj->dup_group != nullptr) ? true : false; } /** @@ -626,39 +536,19 @@ class KX_GameObject : public SCA_IObject * old node. This class takes ownership of the new * node. */ - void SetSGNode(SG_Node* node ) - { - m_pSGNode = node; - } - - //Is it a dynamic/physics object ? - bool IsDynamic() const - { - return m_bDyna; - } + void SetNode(SG_Node *node); + + /// Is it a dynamic/physics object ? + bool IsDynamic() const; bool IsDynamicsSuspended() const; - /** - * Should we record animation for this object? - */ - - void SetRecordAnimation(bool recordAnimation) - { - m_bRecordAnimation = recordAnimation; - } - - bool IsRecordAnimation() const - { - return m_bRecordAnimation; - } - /** * Check if this object has a vertex parent relationship */ bool IsVertexParent( ) { - return (m_pSGNode && m_pSGNode->GetSGParent() && m_pSGNode->GetSGParent()->IsVertexParent()); + return (m_sgNode && m_sgNode->GetParent() && m_sgNode->GetParent()->IsVertexParent()); } /// \see KX_RayCast @@ -670,7 +560,7 @@ class KX_GameObject : public SCA_IObject /** * \section Physics accessors for this node. * - * All these calls get passed directly to the physics controller + * All these calls get passed directly to the physics controller * owned by this object. * This is real interface bloat. Why not just use the physics controller * directly? I think this is because the python interface is in the wrong @@ -679,50 +569,50 @@ class KX_GameObject : public SCA_IObject void ApplyForce( - const MT_Vector3& force, bool local + const mt::vec3& force, bool local ); void ApplyTorque( - const MT_Vector3& torque, + const mt::vec3& torque, bool local ); void ApplyRotation( - const MT_Vector3& drot, + const mt::vec3& drot, bool local ); void ApplyMovement( - const MT_Vector3& dloc, + const mt::vec3& dloc, bool local ); void - addLinearVelocity( - const MT_Vector3& lin_vel, + AddLinearVelocity( + const mt::vec3& lin_vel, bool local ); void - setLinearVelocity( - const MT_Vector3& lin_vel, + SetLinearVelocity( + const mt::vec3& lin_vel, bool local ); void - setAngularVelocity( - const MT_Vector3& ang_vel, + SetAngularVelocity( + const mt::vec3& ang_vel, bool local ); - virtual float getLinearDamping() const; - virtual float getAngularDamping() const; - virtual void setLinearDamping(float damping); - virtual void setAngularDamping(float damping); - virtual void setDamping(float linear, float angular); + virtual float GetLinearDamping() const; + virtual float GetAngularDamping() const; + virtual void SetLinearDamping(float damping); + virtual void SetAngularDamping(float damping); + virtual void SetDamping(float linear, float angular); /** * Update the physics object transform based upon the current SG_Node @@ -732,47 +622,14 @@ class KX_GameObject : public SCA_IObject UpdateTransform( ); - static void UpdateTransformFunc(SG_IObject* node, void* gameobj, void* scene); + static void UpdateTransformFunc(SG_Node* node, void* gameobj, void* scene); /** * only used for sensor objects */ void SynchronizeTransform(); - static void SynchronizeTransformFunc(SG_IObject* node, void* gameobj, void* scene); - - /** - * Function to set IPO option at start of IPO - */ - void - InitIPO( - bool ipo_as_force, - bool ipo_add, - bool ipo_local - ); - - /** - * Odd function to update an ipo. ??? - */ - void - UpdateIPO( - float curframetime, - bool recurse - ); - /** - * Updates Material Ipo data - */ - void - UpdateMaterialData( - dword matname_hash, - MT_Vector4 rgba, - MT_Vector3 specrgb, - MT_Scalar hard, - MT_Scalar spec, - MT_Scalar ref, - MT_Scalar emit, - MT_Scalar alpha - ); + static void SynchronizeTransformFunc(SG_Node* node, void* gameobj, void* scene); /** * \section Mesh accessor functions. @@ -782,19 +639,16 @@ class KX_GameObject : public SCA_IObject * Update buckets to indicate that there is a new * user of this object's meshes. */ - void + virtual void AddMeshUser( ); - + /** * Update buckets with data about the mesh after * creating or duplicating the object, changing * visibility, object color, .. . */ - void - UpdateBuckets( - bool recursive - ); + virtual void UpdateBuckets(); /** * Clear the meshes associated with this class @@ -813,63 +667,37 @@ class KX_GameObject : public SCA_IObject */ void AddMesh( - RAS_MeshObject* mesh + KX_Mesh* mesh ) { m_meshes.push_back(mesh); } - /** - * Add a level of detail mesh to the object. These should - * be added in order. + void ReplaceMesh(KX_Mesh *mesh, bool use_gfx, bool use_phys); + + /** Set current lod manager, can be nullptr. + * If nullptr the object's mesh backs to the mesh of the previous first lod level. */ - void - AddLodMesh( - RAS_MeshObject* mesh - ); + void SetLodManager(KX_LodManager *lodManager); + /// Get current lod manager. + KX_LodManager *GetLodManager() const; /** * Updates the current lod level based on distance from camera. */ - void - UpdateLod( - MT_Vector3 &cam_pos - ); + void UpdateLod(KX_Scene *scene, const mt::vec3& cam_pos, float lodfactor); - /** - * Pick out a mesh associated with the integer 'num'. + /** Update the activity culling of the object. + * \param distance Squared nearest distance to the cameras of this object. */ - RAS_MeshObject* - GetMesh( - int num - ) const { - return m_meshes[num]; - } + void UpdateActivity(float distance); - /** - * Return the number of meshes currently associated with this - * game object. - */ - int - GetMeshCount( - ) const { - return m_meshes.size(); - } + const std::vector& GetMeshList() const; - /** - * Set the debug color of the meshes associated with this - * class. Does this still work? - */ - void - SetDebugColor( - unsigned int bgra - ); + /// Return the mesh user of this game object. + RAS_MeshUser *GetMeshUser() const; - /** - * Reset the debug color of meshes associated with this class. - */ - void - ResetDebugColor( - ); + /// Return true when the object can be rendered. + bool Renderable(int layer) const; /** * Was this object marked visible? (only for the explicit @@ -889,22 +717,6 @@ class KX_GameObject : public SCA_IObject bool recursive ); - /** - * Was this object culled? - */ - inline bool - GetCulled( - void - ) { return m_bCulled; } - - /** - * Set culled flag of this object - */ - inline void - SetCulled( - bool c - ) { m_bCulled = c; } - /** * Is this object an occluder? */ @@ -921,7 +733,7 @@ class KX_GameObject : public SCA_IObject bool v, bool recursive ); - + /** * Change the layer of the object (when it is added in another layer * than the original layer) @@ -939,13 +751,48 @@ class KX_GameObject : public SCA_IObject void ); + void SetPassIndex(short index); + short GetPassIndex() const; + + /// Allow auto updating bounding volume box. + inline void SetAutoUpdateBounds(bool autoUpdate) + { + m_autoUpdateBounds = autoUpdate; + } + + inline bool GetAutoUpdateBounds() const + { + return m_autoUpdateBounds; + } + + /** Update the game object bounding box (AABB) by using the one existing in the + * mesh or the mesh deformer. + * \param force Force the AABB update even if the object doesn't allow auto update or if the mesh is + * not modified like in the case of mesh replacement or object duplication. + * \warning Should be called when the game object contains a valid scene graph node + * and a valid graphic controller (if it exists). + */ + void UpdateBounds(bool force); + void SetBoundsAabb(const mt::vec3 &aabbMin, const mt::vec3 &aabbMax); + void GetBoundsAabb(mt::vec3 &aabbMin, mt::vec3 &aabbMax) const; + + SG_CullingNode& GetCullingNode(); + + ActivityCullingInfo& GetActivityCullingInfo(); + void SetActivityCullingInfo(const ActivityCullingInfo& cullingInfo); + /// Enable or disable a category of object activity culling. + void SetActivityCulling(ActivityCullingInfo::Flag flag, bool enable); + + void SuspendPhysics(bool freeConstraints); + void RestorePhysics(); + /** * Get the negative scaling state */ bool IsNegativeScaling( void - ) { return m_bIsNegativeScaling; } + ) { return m_sgNode->IsNegativeScaling(); } /** * \section Logic bubbling methods. @@ -953,7 +800,7 @@ class KX_GameObject : public SCA_IObject void RegisterCollisionCallbacks(); void UnregisterCollisionCallbacks(); - void RunCollisionCallbacks(KX_GameObject *collider, const MT_Vector3 &point, const MT_Vector3 &normal); + void RunCollisionCallbacks(KX_GameObject *collider, KX_CollisionContactPointList& contactPointList); /** * Stop making progress */ @@ -964,25 +811,23 @@ class KX_GameObject : public SCA_IObject */ void Resume(void); - void RegisterObstacle(KX_ObstacleSimulation* obstacleSimulation) - { - m_pObstacleSimulation = obstacleSimulation; - } - - void UnregisterObstacle() - { - m_pObstacleSimulation = NULL; - } - /** * add debug object to the debuglist. */ void SetUseDebugProperties(bool debug, bool recursive); - KX_ClientObjectInfo* getClientInfo() { return m_pClient_info; } + KX_ClientObjectInfo& GetClientInfo() { return m_clientInfo; } + + std::vector GetChildren() const; + std::vector GetChildrenRecursive() const; - CListValue* GetChildren(); - CListValue* GetChildrenRecursive(); + /// Returns the component list. + EXP_ListValue *GetComponents() const; + /// Add a components. + void SetComponents(EXP_ListValue *components); + + /// Updates the components. + void UpdateComponents(); KX_Scene* GetScene(); @@ -990,146 +835,174 @@ class KX_GameObject : public SCA_IObject /** * \section Python interface functions. */ - virtual PyObject *py_repr(void) - { - return PyUnicode_From_STR_String(GetName()); - } - - KX_PYMETHOD_O(KX_GameObject,SetWorldPosition); - KX_PYMETHOD_VARARGS(KX_GameObject, ApplyForce); - KX_PYMETHOD_VARARGS(KX_GameObject, ApplyTorque); - KX_PYMETHOD_VARARGS(KX_GameObject, ApplyRotation); - KX_PYMETHOD_VARARGS(KX_GameObject, ApplyMovement); - KX_PYMETHOD_VARARGS(KX_GameObject,GetLinearVelocity); - KX_PYMETHOD_VARARGS(KX_GameObject,SetLinearVelocity); - KX_PYMETHOD_VARARGS(KX_GameObject,GetAngularVelocity); - KX_PYMETHOD_VARARGS(KX_GameObject,SetAngularVelocity); - KX_PYMETHOD_VARARGS(KX_GameObject,GetVelocity); - KX_PYMETHOD_VARARGS(KX_GameObject,SetDamping); - - KX_PYMETHOD_NOARGS(KX_GameObject,GetReactionForce); - - - KX_PYMETHOD_NOARGS(KX_GameObject,GetVisible); - KX_PYMETHOD_VARARGS(KX_GameObject,SetVisible); - KX_PYMETHOD_VARARGS(KX_GameObject,SetOcclusion); - KX_PYMETHOD_NOARGS(KX_GameObject,GetState); - KX_PYMETHOD_O(KX_GameObject,SetState); - KX_PYMETHOD_VARARGS(KX_GameObject,AlignAxisToVect); - KX_PYMETHOD_O(KX_GameObject,GetAxisVect); - KX_PYMETHOD_VARARGS(KX_GameObject,SuspendDynamics); - KX_PYMETHOD_NOARGS(KX_GameObject,RestoreDynamics); - KX_PYMETHOD_NOARGS(KX_GameObject,EnableRigidBody); - KX_PYMETHOD_NOARGS(KX_GameObject,DisableRigidBody); - KX_PYMETHOD_VARARGS(KX_GameObject,ApplyImpulse); - KX_PYMETHOD_O(KX_GameObject,SetCollisionMargin); - KX_PYMETHOD_NOARGS(KX_GameObject,GetParent); - KX_PYMETHOD_VARARGS(KX_GameObject,SetParent); - KX_PYMETHOD_NOARGS(KX_GameObject,RemoveParent); - KX_PYMETHOD_NOARGS(KX_GameObject,GetChildren); - KX_PYMETHOD_NOARGS(KX_GameObject,GetChildrenRecursive); - KX_PYMETHOD_VARARGS(KX_GameObject,GetMesh); - KX_PYMETHOD_NOARGS(KX_GameObject,GetPhysicsId); - KX_PYMETHOD_NOARGS(KX_GameObject,GetPropertyNames); - KX_PYMETHOD_VARARGS(KX_GameObject,ReplaceMesh); - KX_PYMETHOD_NOARGS(KX_GameObject,EndObject); - KX_PYMETHOD_DOC(KX_GameObject,rayCastTo); - KX_PYMETHOD_DOC(KX_GameObject,rayCast); - KX_PYMETHOD_DOC_O(KX_GameObject,getDistanceTo); - KX_PYMETHOD_DOC_O(KX_GameObject,getVectTo); - KX_PYMETHOD_DOC_VARARGS(KX_GameObject, sendMessage); - KX_PYMETHOD_VARARGS(KX_GameObject, ReinstancePhysicsMesh); - KX_PYMETHOD_DOC(KX_GameObject, addDebugProperty); - - KX_PYMETHOD_DOC(KX_GameObject, playAction); - KX_PYMETHOD_DOC(KX_GameObject, stopAction); - KX_PYMETHOD_DOC(KX_GameObject, getActionFrame); - KX_PYMETHOD_DOC(KX_GameObject, getActionName); - KX_PYMETHOD_DOC(KX_GameObject, setActionFrame); - KX_PYMETHOD_DOC(KX_GameObject, isPlayingAction); + EXP_PYMETHOD_O(KX_GameObject,SetWorldPosition); + EXP_PYMETHOD_VARARGS(KX_GameObject, ApplyForce); + EXP_PYMETHOD_VARARGS(KX_GameObject, ApplyTorque); + EXP_PYMETHOD_VARARGS(KX_GameObject, ApplyRotation); + EXP_PYMETHOD_VARARGS(KX_GameObject, ApplyMovement); + EXP_PYMETHOD_VARARGS(KX_GameObject,GetLinearVelocity); + EXP_PYMETHOD_VARARGS(KX_GameObject,SetLinearVelocity); + EXP_PYMETHOD_VARARGS(KX_GameObject,GetAngularVelocity); + EXP_PYMETHOD_VARARGS(KX_GameObject,SetAngularVelocity); + EXP_PYMETHOD_VARARGS(KX_GameObject,GetVelocity); + EXP_PYMETHOD_VARARGS(KX_GameObject,SetDamping); + + EXP_PYMETHOD_NOARGS(KX_GameObject,GetReactionForce); + + + EXP_PYMETHOD_NOARGS(KX_GameObject,GetVisible); + EXP_PYMETHOD_VARARGS(KX_GameObject,SetVisible); + EXP_PYMETHOD_VARARGS(KX_GameObject,SetOcclusion); + EXP_PYMETHOD_NOARGS(KX_GameObject,GetState); + EXP_PYMETHOD_O(KX_GameObject,SetState); + EXP_PYMETHOD(KX_GameObject,AlignAxisToVect); + EXP_PYMETHOD_O(KX_GameObject,GetAxisVect); + EXP_PYMETHOD_VARARGS(KX_GameObject,SuspendPhysics); + EXP_PYMETHOD_NOARGS(KX_GameObject,RestorePhysics); + EXP_PYMETHOD_VARARGS(KX_GameObject,SuspendDynamics); + EXP_PYMETHOD_NOARGS(KX_GameObject,RestoreDynamics); + EXP_PYMETHOD_NOARGS(KX_GameObject,EnableRigidBody); + EXP_PYMETHOD_NOARGS(KX_GameObject,DisableRigidBody); + EXP_PYMETHOD_VARARGS(KX_GameObject,ApplyImpulse); + EXP_PYMETHOD_O(KX_GameObject,SetCollisionMargin); + EXP_PYMETHOD_O(KX_GameObject,Collide); + EXP_PYMETHOD_NOARGS(KX_GameObject,GetParent); + EXP_PYMETHOD(KX_GameObject,SetParent); + EXP_PYMETHOD_NOARGS(KX_GameObject,RemoveParent); + EXP_PYMETHOD_NOARGS(KX_GameObject,GetChildren); + EXP_PYMETHOD_NOARGS(KX_GameObject,GetChildrenRecursive); + EXP_PYMETHOD_VARARGS(KX_GameObject,GetMesh); + EXP_PYMETHOD_NOARGS(KX_GameObject,GetPhysicsId); + EXP_PYMETHOD_NOARGS(KX_GameObject,GetPropertyNames); + EXP_PYMETHOD(KX_GameObject,ReplaceMesh); + EXP_PYMETHOD_NOARGS(KX_GameObject,EndObject); + EXP_PYMETHOD_DOC(KX_GameObject,rayCastTo); + EXP_PYMETHOD_DOC(KX_GameObject,rayCast); + EXP_PYMETHOD_DOC_O(KX_GameObject,getDistanceTo); + EXP_PYMETHOD_DOC_O(KX_GameObject,getVectTo); + EXP_PYMETHOD_DOC(KX_GameObject, sendMessage); + EXP_PYMETHOD(KX_GameObject, ReinstancePhysicsMesh); + EXP_PYMETHOD_O(KX_GameObject, ReplacePhysicsShape); + EXP_PYMETHOD_DOC(KX_GameObject, addDebugProperty); + + EXP_PYMETHOD_DOC(KX_GameObject, playAction); + EXP_PYMETHOD_DOC(KX_GameObject, stopAction); + EXP_PYMETHOD_DOC(KX_GameObject, getActionFrame); + EXP_PYMETHOD_DOC(KX_GameObject, getActionName); + EXP_PYMETHOD_DOC(KX_GameObject, setActionFrame); + EXP_PYMETHOD_DOC(KX_GameObject, isPlayingAction); + /* Dict access */ - KX_PYMETHOD_VARARGS(KX_GameObject,get); - + EXP_PYMETHOD_VARARGS(KX_GameObject,get); + /* attributes */ - static PyObject* pyattr_get_name(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_parent(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - - static PyObject* pyattr_get_group_object(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_group_members(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_scene(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - - static PyObject* pyattr_get_life(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_is_suspend_dynamics(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_ang_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_ang_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_ang_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_ang_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_record_animation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_record_animation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_worldPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_localPosition(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_localInertia(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_localInertia(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_worldOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_worldOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_localOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_localOrientation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_worldScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_worldScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_localScaling(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_localTransform(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_localTransform(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_worldTransform(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_worldTransform(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_worldLinearVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_worldLinearVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_localLinearVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_localLinearVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_worldAngularVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_worldAngularVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_localAngularVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_localAngularVelocity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_timeOffset(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_timeOffset(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_state(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_meshes(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_children(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_children_recursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_attrDict(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_obcolor(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_obcolor(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_collisionCallbacks(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_collisionCallbacks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_collisionGroup(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_collisionGroup(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_collisionMask(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_collisionMask(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_linearDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_linearDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_angularDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_angularDamping(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - - /* Experimental! */ - static PyObject* pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_controllers(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_actuators(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_name(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_name(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_parent(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + + static PyObject* pyattr_get_group_object(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_group_members(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_scene(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + + static PyObject* pyattr_get_life(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_mass(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_mass(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_is_suspend_dynamics(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_lin_vel_min(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_lin_vel_min(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_lin_vel_max(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_lin_vel_max(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_ang_vel_min(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_ang_vel_min(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_ang_vel_max(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_ang_vel_max(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_layer(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_layer(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_visible(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_visible(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_culled(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_cullingBox(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_physicsCulling(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_physicsCulling(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_logicCulling(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_logicCulling(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_physicsCullingRadius(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_physicsCullingRadius(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_logicCullingRadius(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_logicCullingRadius(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_worldPosition(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_worldPosition(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_localPosition(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_localPosition(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_localInertia(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_localInertia(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_worldOrientation(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_worldOrientation(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_localOrientation(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_localOrientation(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_worldScaling(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_worldScaling(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_localScaling(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_localScaling(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_localTransform(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_localTransform(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_worldTransform(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_worldTransform(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_worldLinearVelocity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_worldLinearVelocity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_localLinearVelocity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_localLinearVelocity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_worldAngularVelocity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_worldAngularVelocity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_localAngularVelocity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_localAngularVelocity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_gravity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_gravity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_timeOffset(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_timeOffset(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_state(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_state(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_meshes(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_batchGroup(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_children(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_children_recursive(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_attrDict(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_obcolor(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_obcolor(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_components(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_collisionCallbacks(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_collisionCallbacks(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_collisionGroup(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_collisionGroup(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_collisionMask(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_collisionMask(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_debug(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_debug(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_debugRecursive(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_debugRecursive(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_linearDamping(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_linearDamping(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_angularDamping(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_angularDamping(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_lodManager(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_lodManager(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + + static PyObject* pyattr_get_sensors(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_controllers(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_actuators(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + + unsigned int py_get_sensors_size(); + PyObject *py_get_sensors_item(unsigned int index); + std::string py_get_sensors_item_name(unsigned int index); + + unsigned int py_get_controllers_size(); + PyObject *py_get_controllers_item(unsigned int index); + std::string py_get_controllers_item_name(unsigned int index); + + unsigned int py_get_actuators_size(); + PyObject *py_get_actuators_item(unsigned int index); + std::string py_get_actuators_item_name(unsigned int index); /* getitem/setitem */ static PyMappingMethods Mapping; diff --git a/source/gameengine/Ketsji/KX_Globals.cpp b/source/gameengine/Ketsji/KX_Globals.cpp new file mode 100644 index 000000000000..3af8f9ad54a4 --- /dev/null +++ b/source/gameengine/Ketsji/KX_Globals.cpp @@ -0,0 +1,94 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Ketsji/KX_Globals.cpp + * \ingroup ketsji + */ + +#include "KX_Globals.h" +#include "KX_Scene.h" +#include "RAS_Rasterizer.h" + +extern "C" { +# include "BLI_blenlib.h" +} + +static KX_KetsjiEngine *g_engine = nullptr; +static KX_Scene *g_scene = nullptr; +static std::string g_mainPath = ""; +static std::string g_origPath = ""; + +void KX_SetActiveEngine(KX_KetsjiEngine *engine) +{ + g_engine = engine; +} + +void KX_SetActiveScene(KX_Scene *scene) +{ + g_scene = scene; +} + +void KX_SetMainPath(const std::string& path) +{ + char cpath[FILE_MAX]; + BLI_strncpy(cpath, path.c_str(), sizeof(cpath)); + BLI_cleanup_file(nullptr, cpath); + g_mainPath = std::string(cpath); +} + +void KX_SetOrigPath(const std::string& path) +{ + char cpath[FILE_MAX]; + BLI_strncpy(cpath, path.c_str(), sizeof(cpath)); + BLI_cleanup_file(nullptr, cpath); + g_origPath = std::string(cpath); +} + +KX_KetsjiEngine *KX_GetActiveEngine() +{ + return g_engine; +} + +KX_Scene *KX_GetActiveScene() +{ + return g_scene; +} + +PHY_IPhysicsEnvironment *KX_GetPhysicsEnvironment() +{ + return g_scene->GetPhysicsEnvironment(); +} + +const std::string& KX_GetMainPath() +{ + return g_mainPath; +} + +const std::string& KX_GetOrigPath() +{ + return g_origPath; +} + +void KX_RasterizerDrawDebugLine(const mt::vec3& from, const mt::vec3& to, const mt::vec4& color) +{ + g_scene->GetDebugDraw().DrawLine(from, to, color); +} diff --git a/source/gameengine/Ketsji/KX_RayEventManager.h b/source/gameengine/Ketsji/KX_Globals.h similarity index 53% rename from source/gameengine/Ketsji/KX_RayEventManager.h rename to source/gameengine/Ketsji/KX_Globals.h index 07506b9e32b1..56151ba46196 100644 --- a/source/gameengine/Ketsji/KX_RayEventManager.h +++ b/source/gameengine/Ketsji/KX_Globals.h @@ -14,40 +14,37 @@ * You 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. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. + * + * Contributor(s): Tristan Porteries. * * ***** END GPL LICENSE BLOCK ***** */ -/** \file KX_RayEventManager.h +/** \file KX_Globals.h * \ingroup ketsji - * \brief Manager for ray events */ -#ifndef __KX_RAYEVENTMANAGER_H__ -#define __KX_RAYEVENTMANAGER_H__ -#include "SCA_EventManager.h" -#include -using namespace std; +#ifndef __KX_GLOBALS_H__ +#define __KX_GLOBALS_H__ + +#include "mathfu.h" +#include + +class KX_KetsjiEngine; +class KX_Scene; +class PHY_IPhysicsEnvironment; -class KX_RayEventManager : public SCA_EventManager -{ -public: - KX_RayEventManager(class SCA_LogicManager* logicmgr) - : SCA_EventManager(logicmgr, RAY_EVENTMGR) - {} - virtual void NextFrame(); +void KX_SetActiveEngine(KX_KetsjiEngine *engine); +void KX_SetActiveScene(KX_Scene *scene); +void KX_SetMainPath(const std::string& path); +void KX_SetOrigPath(const std::string& path); +KX_KetsjiEngine *KX_GetActiveEngine(); +KX_Scene *KX_GetActiveScene(); +PHY_IPhysicsEnvironment *KX_GetPhysicsEnvironment(); +const std::string& KX_GetMainPath(); +const std::string& KX_GetOrigPath(); -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_RayEventManager") -#endif -}; +void KX_RasterizerDrawDebugLine(const mt::vec3 &from,const mt::vec3 &to,const mt::vec4 &color); -#endif /* __KX_RAYEVENTMANAGER_H__ */ +#endif // __KX_GLOBALS_H__ diff --git a/source/gameengine/Ketsji/KX_IPOTransform.h b/source/gameengine/Ketsji/KX_IPOTransform.h deleted file mode 100644 index abf8da31e920..000000000000 --- a/source/gameengine/Ketsji/KX_IPOTransform.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file KX_IPOTransform.h - * \ingroup ketsji - * \brief An abstract object you can move around in a 3d world, and has some logic - */ - -#ifndef __KX_IPOTRANSFORM_H__ -#define __KX_IPOTRANSFORM_H__ - -#include "MT_Transform.h" - -class KX_IPOTransform { -public: - KX_IPOTransform() : - m_position(0.0f, 0.0f, 0.0f), - m_eulerAngles(0.0f, 0.0f, 0.0f), - m_scaling(1.0f, 1.0f, 1.0f), - m_deltaPosition(0.0f, 0.0f, 0.0f), - m_deltaEulerAngles(0.0f, 0.0f, 0.0f), - m_deltaScaling(0.0f, 0.0f, 0.0f) - {} - - MT_Transform GetTransform() const { - return MT_Transform(m_position + m_deltaPosition, - MT_Matrix3x3(m_eulerAngles + m_deltaEulerAngles, - m_scaling + m_deltaScaling)); - } - - MT_Point3& GetPosition() { return m_position; } - MT_Vector3& GetEulerAngles() { return m_eulerAngles; } - MT_Vector3& GetScaling() { return m_scaling; } - - const MT_Point3& GetPosition() const { return m_position; } - const MT_Vector3& GetEulerAngles() const { return m_eulerAngles; } - const MT_Vector3& GetScaling() const { return m_scaling; } - - MT_Vector3& GetDeltaPosition() { return m_deltaPosition; } - MT_Vector3& GetDeltaEulerAngles() { return m_deltaEulerAngles; } - MT_Vector3& GetDeltaScaling() { return m_deltaScaling; } - - void SetPosition(const MT_Point3& pos) { m_position = pos; } - void SetEulerAngles(const MT_Vector3& eul) { m_eulerAngles = eul; } - void SetScaling(const MT_Vector3& scaling) { m_scaling = scaling; } - - void ClearDeltaStuff() { - m_deltaPosition.setValue(0.0f, 0.0f, 0.0f); - m_deltaEulerAngles.setValue(0.0f, 0.0f, 0.0f); - m_deltaScaling.setValue(0.0f, 0.0f, 0.0f); - } - -protected: - MT_Point3 m_position; - MT_Vector3 m_eulerAngles; - MT_Vector3 m_scaling; - MT_Vector3 m_deltaPosition; - MT_Vector3 m_deltaEulerAngles; - MT_Vector3 m_deltaScaling; -}; - -#endif diff --git a/source/gameengine/Ketsji/KX_IPO_SGController.cpp b/source/gameengine/Ketsji/KX_IPO_SGController.cpp deleted file mode 100644 index 2258572b563c..000000000000 --- a/source/gameengine/Ketsji/KX_IPO_SGController.cpp +++ /dev/null @@ -1,373 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - * Scenegraph controller for ipos. - */ - -/** \file gameengine/Ketsji/KX_IPO_SGController.cpp - * \ingroup ketsji - */ - - -#if defined(_WIN64) -typedef unsigned __int64 uint_ptr; -#else -typedef unsigned long uint_ptr; -#endif - -#ifdef _MSC_VER - /* 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 - -#include "KX_IPO_SGController.h" -#include "KX_ScalarInterpolator.h" -#include "KX_GameObject.h" -#include "PHY_IPhysicsController.h" -#include "DNA_ipo_types.h" -#include "BLI_math.h" - -// All objects should start on frame 1! Will we ever need an object to -// start on another frame, the 1.0 should change. -KX_IpoSGController::KX_IpoSGController() -: m_ipo_as_force(false), - m_ipo_add(false), - m_ipo_local(false), - m_modified(true), - m_ipotime(1.0), - m_ipo_start_initialized(false), - m_ipo_start_euler(0.0f, 0.0f, 0.0f), - m_ipo_euler_initialized(false) -{ - m_game_object = NULL; - for (int i = 0; i < KX_MAX_IPO_CHANNELS; i++) - m_ipo_channels_active[i] = false; -} - - -void KX_IpoSGController::SetOption(int option, int value) -{ - switch (option) { - case SG_CONTR_IPO_IPO_AS_FORCE: - m_ipo_as_force = (value != 0); - m_modified = true; - break; - case SG_CONTR_IPO_IPO_ADD: - m_ipo_add = (value != 0); - m_modified = true; - break; - case SG_CONTR_IPO_RESET: - if (m_ipo_start_initialized && value) { - m_ipo_start_initialized = false; - m_modified = true; - } - break; - case SG_CONTR_IPO_LOCAL: - if (value/* && ((SG_Node*)m_pObject)->GetSGParent() == NULL*/) { - // only accept local Ipo if the object has no parent - m_ipo_local = true; - } - else { - m_ipo_local = false; - } - m_modified = true; - break; - default: - ; /* just ignore the rest */ - } -} - -void KX_IpoSGController::UpdateSumoReference() -{ - if (m_game_object) { - } -} - -void KX_IpoSGController::SetGameObject(KX_GameObject *go) -{ - m_game_object = go; -} - -bool KX_IpoSGController::Update(double currentTime) -{ - if (m_modified) { - T_InterpolatorList::iterator i; - for (i = m_interpolators.begin(); i != m_interpolators.end(); ++i) { - (*i)->Execute(m_ipotime);//currentTime); - } - - SG_Spatial *ob = (SG_Spatial *)m_pObject; - - //initialization on the first frame of the IPO - if (!m_ipo_start_initialized) { - m_ipo_start_point = ob->GetLocalPosition(); - m_ipo_start_orient = ob->GetLocalOrientation(); - m_ipo_start_scale = ob->GetLocalScale(); - m_ipo_start_initialized = true; - if (!m_ipo_euler_initialized) { - // do it only once to avoid angle discontinuities - m_ipo_start_orient.getEuler(m_ipo_start_euler[0], m_ipo_start_euler[1], m_ipo_start_euler[2]); - m_ipo_euler_initialized = true; - } - } - - //modifies position? - if (m_ipo_channels_active[OB_LOC_X] || m_ipo_channels_active[OB_LOC_Y] || m_ipo_channels_active[OB_LOC_Z] || - m_ipo_channels_active[OB_DLOC_X] || m_ipo_channels_active[OB_DLOC_Y] || m_ipo_channels_active[OB_DLOC_Z]) - { - if (m_ipo_as_force == true) { - if (m_game_object && ob && m_game_object->GetPhysicsController()) { - MT_Vector3 vec = m_ipo_local ? - ob->GetWorldOrientation() * m_ipo_xform.GetPosition() : - m_ipo_xform.GetPosition(); - m_game_object->GetPhysicsController()->ApplyForce(vec, false); - } - } - else { - // Local ipo should be defined with the object position at (0,0,0) - // Local transform is applied to the object based on initial position - MT_Point3 newPosition(0.0f, 0.0f, 0.0f); - - if (!m_ipo_add) - newPosition = ob->GetLocalPosition(); - //apply separate IPO channels if there is any data in them - //Loc and dLoc act by themselves or are additive - //LocX and dLocX - if (m_ipo_channels_active[OB_LOC_X]) { - newPosition[0] = (m_ipo_channels_active[OB_DLOC_X] ? m_ipo_xform.GetPosition()[0] + m_ipo_xform.GetDeltaPosition()[0] : m_ipo_xform.GetPosition()[0]); - } - else if (m_ipo_channels_active[OB_DLOC_X] && m_ipo_start_initialized) { - newPosition[0] = (((!m_ipo_add) ? m_ipo_start_point[0] : 0.0f) + m_ipo_xform.GetDeltaPosition()[0]); - } - //LocY and dLocY - if (m_ipo_channels_active[OB_LOC_Y]) { - newPosition[1] = (m_ipo_channels_active[OB_DLOC_Y] ? m_ipo_xform.GetPosition()[1] + m_ipo_xform.GetDeltaPosition()[1] : m_ipo_xform.GetPosition()[1]); - } - else if (m_ipo_channels_active[OB_DLOC_Y] && m_ipo_start_initialized) { - newPosition[1] = (((!m_ipo_add) ? m_ipo_start_point[1] : 0.0f) + m_ipo_xform.GetDeltaPosition()[1]); - } - //LocZ and dLocZ - if (m_ipo_channels_active[OB_LOC_Z]) { - newPosition[2] = (m_ipo_channels_active[OB_DLOC_Z] ? m_ipo_xform.GetPosition()[2] + m_ipo_xform.GetDeltaPosition()[2] : m_ipo_xform.GetPosition()[2]); - } - else if (m_ipo_channels_active[OB_DLOC_Z] && m_ipo_start_initialized) { - newPosition[2] = (((!m_ipo_add) ? m_ipo_start_point[2] : 0.0f) + m_ipo_xform.GetDeltaPosition()[2]); - } - if (m_ipo_add) { - if (m_ipo_local) - newPosition = m_ipo_start_point + m_ipo_start_scale*(m_ipo_start_orient*newPosition); - else - newPosition = m_ipo_start_point + newPosition; - } - if (m_game_object) - m_game_object->NodeSetLocalPosition(newPosition); - } - } - //modifies orientation? - if (m_ipo_channels_active[OB_ROT_X] || m_ipo_channels_active[OB_ROT_Y] || m_ipo_channels_active[OB_ROT_Z] || - m_ipo_channels_active[OB_DROT_X] || m_ipo_channels_active[OB_DROT_Y] || m_ipo_channels_active[OB_DROT_Z]) - { - if (m_ipo_as_force) { - if (m_game_object && ob) { - m_game_object->ApplyTorque(m_ipo_local ? - ob->GetWorldOrientation() * m_ipo_xform.GetEulerAngles() : - m_ipo_xform.GetEulerAngles(), false); - } - } - else if (m_ipo_add) { - if (m_ipo_start_initialized) { - double yaw = 0.0, pitch = 0.0, roll = 0.0; //delta Euler angles - - //RotX and dRotX - if (m_ipo_channels_active[OB_ROT_X]) - yaw += m_ipo_xform.GetEulerAngles()[0]; - if (m_ipo_channels_active[OB_DROT_X]) - yaw += m_ipo_xform.GetDeltaEulerAngles()[0]; - - //RotY dRotY - if (m_ipo_channels_active[OB_ROT_Y]) - pitch += m_ipo_xform.GetEulerAngles()[1]; - if (m_ipo_channels_active[OB_DROT_Y]) - pitch += m_ipo_xform.GetDeltaEulerAngles()[1]; - - //RotZ and dRotZ - if (m_ipo_channels_active[OB_ROT_Z]) - roll += m_ipo_xform.GetEulerAngles()[2]; - if (m_ipo_channels_active[OB_DROT_Z]) - roll += m_ipo_xform.GetDeltaEulerAngles()[2]; - - MT_Matrix3x3 rotation(MT_Vector3(yaw, pitch, roll)); - if (m_ipo_local) - rotation = m_ipo_start_orient * rotation; - else - rotation = rotation * m_ipo_start_orient; - if (m_game_object) - m_game_object->NodeSetLocalOrientation(rotation); - } - } - else if (m_ipo_channels_active[OB_ROT_X] || m_ipo_channels_active[OB_ROT_Y] || m_ipo_channels_active[OB_ROT_Z]) { - if (m_ipo_euler_initialized) { - // assume all channel absolute - // All 3 channels should be specified but if they are not, we will take - // the value at the start of the game to avoid angle sign reversal - double yaw = m_ipo_start_euler[0], pitch = m_ipo_start_euler[1], roll = m_ipo_start_euler[2]; - - //RotX and dRotX - if (m_ipo_channels_active[OB_ROT_X]) { - yaw = (m_ipo_channels_active[OB_DROT_X] ? (m_ipo_xform.GetEulerAngles()[0] + m_ipo_xform.GetDeltaEulerAngles()[0]) : m_ipo_xform.GetEulerAngles()[0] ); - } - else if (m_ipo_channels_active[OB_DROT_X]) { - yaw += m_ipo_xform.GetDeltaEulerAngles()[0]; - } - - //RotY dRotY - if (m_ipo_channels_active[OB_ROT_Y]) { - pitch = (m_ipo_channels_active[OB_DROT_Y] ? (m_ipo_xform.GetEulerAngles()[1] + m_ipo_xform.GetDeltaEulerAngles()[1]) : m_ipo_xform.GetEulerAngles()[1] ); - } - else if (m_ipo_channels_active[OB_DROT_Y]) { - pitch += m_ipo_xform.GetDeltaEulerAngles()[1]; - } - - //RotZ and dRotZ - if (m_ipo_channels_active[OB_ROT_Z]) { - roll = (m_ipo_channels_active[OB_DROT_Z] ? (m_ipo_xform.GetEulerAngles()[2] + m_ipo_xform.GetDeltaEulerAngles()[2]) : m_ipo_xform.GetEulerAngles()[2] ); - } - else if (m_ipo_channels_active[OB_DROT_Z]) { - roll += m_ipo_xform.GetDeltaEulerAngles()[2]; - } - if (m_game_object) - m_game_object->NodeSetLocalOrientation(MT_Vector3(yaw, pitch, roll)); - } - } - else if (m_ipo_start_initialized) { - // only DROT, treat as Add - double yaw = 0.0, pitch = 0.0, roll = 0.0; //delta Euler angles - - //dRotX - if (m_ipo_channels_active[OB_DROT_X]) - yaw = m_ipo_xform.GetDeltaEulerAngles()[0]; - - //dRotY - if (m_ipo_channels_active[OB_DROT_Y]) - pitch = m_ipo_xform.GetDeltaEulerAngles()[1]; - - //dRotZ - if (m_ipo_channels_active[OB_DROT_Z]) - roll = m_ipo_xform.GetDeltaEulerAngles()[2]; - - // dRot are always local - MT_Matrix3x3 rotation(MT_Vector3(yaw, pitch, roll)); - rotation = m_ipo_start_orient * rotation; - if (m_game_object) - m_game_object->NodeSetLocalOrientation(rotation); - } - } - //modifies scale? - if (m_ipo_channels_active[OB_SIZE_X] || m_ipo_channels_active[OB_SIZE_Y] || m_ipo_channels_active[OB_SIZE_Z] || - m_ipo_channels_active[OB_DSIZE_X] || m_ipo_channels_active[OB_DSIZE_Y] || m_ipo_channels_active[OB_DSIZE_Z]) - { - //default is no scale change - MT_Vector3 newScale(1.0f, 1.0f, 1.0f); - if (!m_ipo_add) - newScale = ob->GetLocalScale(); - - if (m_ipo_channels_active[OB_SIZE_X]) { - newScale[0] = (m_ipo_channels_active[OB_DSIZE_X] ? (m_ipo_xform.GetScaling()[0] + m_ipo_xform.GetDeltaScaling()[0]) : m_ipo_xform.GetScaling()[0]); - } - else if (m_ipo_channels_active[OB_DSIZE_X] && m_ipo_start_initialized) { - newScale[0] = (m_ipo_xform.GetDeltaScaling()[0] + ((!m_ipo_add) ? m_ipo_start_scale[0] : 0.0f)); - } - - //RotY dRotY - if (m_ipo_channels_active[OB_SIZE_Y]) { - newScale[1] = (m_ipo_channels_active[OB_DSIZE_Y] ? (m_ipo_xform.GetScaling()[1] + m_ipo_xform.GetDeltaScaling()[1]): m_ipo_xform.GetScaling()[1]); - } - else if (m_ipo_channels_active[OB_DSIZE_Y] && m_ipo_start_initialized) { - newScale[1] = (m_ipo_xform.GetDeltaScaling()[1] + ((!m_ipo_add)?m_ipo_start_scale[1] : 0.0f)); - } - - //RotZ and dRotZ - if (m_ipo_channels_active[OB_SIZE_Z]) { - newScale[2] = (m_ipo_channels_active[OB_DSIZE_Z] ? (m_ipo_xform.GetScaling()[2] + m_ipo_xform.GetDeltaScaling()[2]) : m_ipo_xform.GetScaling()[2]); - } - else if (m_ipo_channels_active[OB_DSIZE_Z] && m_ipo_start_initialized) { - newScale[2] = (m_ipo_xform.GetDeltaScaling()[2] + ((!m_ipo_add)?m_ipo_start_scale[2] : 1.0f)); - } - - if (m_ipo_add) { - newScale = m_ipo_start_scale * newScale; - } - if (m_game_object) - m_game_object->NodeSetLocalScale(newScale); - } - m_modified = false; - } - return false; -} - -void KX_IpoSGController::AddInterpolator(KX_IInterpolator *interp) -{ - m_interpolators.push_back(interp); -} - -SG_Controller *KX_IpoSGController::GetReplica(SG_Node *destnode) -{ - KX_IpoSGController *iporeplica = new KX_IpoSGController(*this); - // clear object that ipo acts on in the replica. - iporeplica->ClearObject(); - iporeplica->SetGameObject((KX_GameObject *)destnode->GetSGClientObject()); - - // dirty hack, ask Gino for a better solution in the ipo implementation - // hacken en zagen, in what we call datahiding, not written for replication :( - - T_InterpolatorList oldlist = m_interpolators; - iporeplica->m_interpolators.clear(); - - T_InterpolatorList::iterator i; - for (i = oldlist.begin(); i != oldlist.end(); ++i) { - KX_ScalarInterpolator *copyipo = new KX_ScalarInterpolator(*((KX_ScalarInterpolator *)*i)); - iporeplica->AddInterpolator(copyipo); - - MT_Scalar *scaal = ((KX_ScalarInterpolator *)*i)->GetTarget(); - uint_ptr orgbase = (uint_ptr)&m_ipo_xform; - uint_ptr orgloc = (uint_ptr)scaal; - uint_ptr offset = orgloc - orgbase; - uint_ptr newaddrbase = (uint_ptr)&iporeplica->m_ipo_xform; - newaddrbase += offset; - MT_Scalar *blaptr = (MT_Scalar *) newaddrbase; - copyipo->SetNewTarget((MT_Scalar *)blaptr); - } - - return iporeplica; -} - -KX_IpoSGController::~KX_IpoSGController() -{ - T_InterpolatorList::iterator i; - for (i = m_interpolators.begin(); i != m_interpolators.end(); ++i) { - delete (*i); - } -} diff --git a/source/gameengine/Ketsji/KX_ISceneConverter.h b/source/gameengine/Ketsji/KX_ISceneConverter.h deleted file mode 100644 index 11f412ade055..000000000000 --- a/source/gameengine/Ketsji/KX_ISceneConverter.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file KX_ISceneConverter.h - * \ingroup ketsji - */ - -#ifndef __KX_ISCENECONVERTER_H__ -#define __KX_ISCENECONVERTER_H__ - -#include "STR_String.h" -#include "EXP_Python.h" - -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -struct Scene; - -class KX_ISceneConverter -{ - -public: - KX_ISceneConverter() {} - virtual ~KX_ISceneConverter () {} - - /* - * scenename: name of the scene to be converted, - * if the scenename is empty, convert the 'default' scene (whatever this means) - * destinationscene: pass an empty scene, everything goes into this - * dictobj: python dictionary (for pythoncontrollers) - */ - virtual void ConvertScene( - class KX_Scene* destinationscene, - class RAS_IRasterizer* rendertools, - class RAS_ICanvas* canvas, - bool libloading=false)=0; - - virtual void RemoveScene(class KX_Scene *scene)=0; - - // handle any pending merges from asynchronous loads - virtual void MergeAsyncLoads()=0; - virtual void FinalizeAsyncLoads() = 0; - - virtual void SetAlwaysUseExpandFraming(bool to_what) = 0; - - virtual void SetNewFileName(const STR_String& filename) = 0; - virtual bool TryAndLoadNewFile() = 0; - - virtual void ResetPhysicsObjectsAnimationIpo(bool clearIpo) = 0; - - ///this generates ipo curves for position, rotation, allowing to use game physics in animation - virtual void WritePhysicsObjectToAnimationIpo(int frameNumber) = 0; - virtual void TestHandlesPhysicsObjectToAnimationIpo() = 0; - - ///this is for reseting the position,rotation and scale of the gameobjet that is not dynamic - virtual void resetNoneDynamicObjectToIpo()=0; - - // use blender materials - virtual void SetMaterials(bool val) =0; - virtual bool GetMaterials()=0; - - // use blender glsl materials - virtual void SetGLSLMaterials(bool val) =0; - virtual bool GetGLSLMaterials()=0; - - // cache materials during conversion - virtual void SetCacheMaterials(bool val) =0; - virtual bool GetCacheMaterials()=0; - - virtual struct Scene* GetBlenderSceneForName(const STR_String& name)=0; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_ISceneConverter") -#endif -}; - -#endif /* __KX_ISCENECONVERTER_H__ */ diff --git a/source/gameengine/Ketsji/KX_IpoController.cpp b/source/gameengine/Ketsji/KX_IpoController.cpp new file mode 100644 index 000000000000..e073501c37e6 --- /dev/null +++ b/source/gameengine/Ketsji/KX_IpoController.cpp @@ -0,0 +1,252 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * Scenegraph controller for ipos. + */ + +/** \file gameengine/Ketsji/KX_IpoController.cpp + * \ingroup ketsji + */ + +#include "KX_IpoController.h" +#include "KX_GameObject.h" +#include "PHY_IPhysicsController.h" +#include "DNA_ipo_types.h" +#include "BLI_math.h" + +KX_IpoController::KX_IpoController() + :m_ipo_as_force(false), + m_ipo_add(false), + m_ipo_local(false), + m_ipo_start_initialized(false), + m_ipo_start_euler(mt::zero3), + m_ipo_euler_initialized(false) +{ + for (int i = 0; i < KX_MAX_IPO_CHANNELS; i++) { + m_ipo_channels_active[i] = false; + } +} + +void KX_IpoController::SetOption(SG_ControllerOption option, bool value) +{ + m_modified = true; + + switch (option) { + case SG_CONTR_IPO_IPO_AS_FORCE: + { + m_ipo_as_force = value; + break; + } + case SG_CONTR_IPO_IPO_ADD: + { + m_ipo_add = value; + break; + } + case SG_CONTR_IPO_RESET: + { + if (m_ipo_start_initialized && value) { + m_ipo_start_initialized = false; + } + break; + } + case SG_CONTR_IPO_LOCAL: + { + m_ipo_local = true; + break; + } + default: + ; /* just ignore the rest */ + } +} + +bool KX_IpoController::Update(SG_Node *node) +{ + if (!SG_Controller::Update(node)) { + return false; + } + + KX_GameObject *obj = static_cast(node->GetClientObject()); + + //initialization on the first frame of the IPO + if (!m_ipo_start_initialized) { + m_ipo_start_point = node->GetLocalPosition(); + m_ipo_start_orient = node->GetLocalOrientation(); + m_ipo_start_scale = node->GetLocalScale(); + m_ipo_start_initialized = true; + + if (!m_ipo_euler_initialized) { + // do it only once to avoid angle discontinuities + m_ipo_start_euler = m_ipo_start_orient.GetEuler(); + m_ipo_euler_initialized = true; + } + } + + //modifies position? + if (m_ipo_channels_active[OB_LOC_X] || m_ipo_channels_active[OB_LOC_Y] || m_ipo_channels_active[OB_LOC_Z] || + m_ipo_channels_active[OB_DLOC_X] || m_ipo_channels_active[OB_DLOC_Y] || m_ipo_channels_active[OB_DLOC_Z]) { + if (m_ipo_as_force) { + if (obj->GetPhysicsController()) { + const mt::vec3 vec = m_ipo_local ? + node->GetWorldOrientation() * m_ipo_xform.GetPosition() : + m_ipo_xform.GetPosition(); + obj->GetPhysicsController()->ApplyForce(vec, false); + } + } + else { + // Local ipo should be defined with the nodeject position at (0,0,0) + // Local transform is applied to the nodeject based on initial position + mt::vec3 newPosition = mt::zero3; + + if (!m_ipo_add) { + newPosition = node->GetLocalPosition(); + } + //apply separate IPO channels if there is any data in them + //Loc and dLoc act by themselves or are additive + for (unsigned short i = 0; i < 3; ++i) { + const mt::vec3& loc = m_ipo_xform.GetPosition(); + const mt::vec3& dloc = m_ipo_xform.GetDeltaPosition(); + + const bool delta = m_ipo_channels_active[OB_DLOC_X + i]; + + if (m_ipo_channels_active[OB_LOC_X + i]) { + newPosition[i] = (delta ? loc[i] + dloc[i] : loc[i]); + } + else if (delta) { + newPosition[i] = (((!m_ipo_add) ? m_ipo_start_point[i] : 0.0f) + dloc[i]); + } + } + + if (m_ipo_add) { + if (m_ipo_local) { + newPosition = m_ipo_start_point + m_ipo_start_scale * (m_ipo_start_orient * newPosition); + } + else { + newPosition = m_ipo_start_point + newPosition; + } + } + + obj->NodeSetLocalPosition(newPosition); + } + } + //modifies orientation? + if (m_ipo_channels_active[OB_ROT_X] || m_ipo_channels_active[OB_ROT_Y] || m_ipo_channels_active[OB_ROT_Z] || + m_ipo_channels_active[OB_DROT_X] || m_ipo_channels_active[OB_DROT_Y] || m_ipo_channels_active[OB_DROT_Z]) { + if (m_ipo_as_force) { + obj->ApplyTorque(m_ipo_local ? + node->GetWorldOrientation() * m_ipo_xform.GetEulerAngles() : + m_ipo_xform.GetEulerAngles(), false); + } + else if (m_ipo_add) { + // Delta euler angles. + mt::vec3 angles = mt::zero3; + + for (unsigned short i = 0; i < 3; ++i) { + if (m_ipo_channels_active[OB_ROT_X + i]) { + angles[i] += m_ipo_xform.GetEulerAngles()[i]; + } + if (m_ipo_channels_active[OB_DROT_X + i]) { + angles[i] += m_ipo_xform.GetDeltaEulerAngles()[i]; + } + } + + mt::mat3 rotation(angles); + if (m_ipo_local) { + rotation = m_ipo_start_orient * rotation; + } + else { + rotation = rotation * m_ipo_start_orient; + } + + obj->NodeSetLocalOrientation(rotation); + } + else if (m_ipo_channels_active[OB_ROT_X] || m_ipo_channels_active[OB_ROT_Y] || m_ipo_channels_active[OB_ROT_Z]) { + // assume all channel absolute + // All 3 channels should be specified but if they are not, we will take + // the value at the start of the game to avoid angle sign reversal + mt::vec3 angles(m_ipo_start_euler); + + for (unsigned short i = 0; i < 3; ++i) { + const mt::vec3& eul = m_ipo_xform.GetEulerAngles(); + const mt::vec3& deul = m_ipo_xform.GetDeltaEulerAngles(); + + const bool delta = m_ipo_channels_active[OB_DROT_X + i]; + + if (m_ipo_channels_active[OB_ROT_X + i]) { + angles[i] = (delta ? (eul[i] + deul[i]) : eul[i]); + } + else if (delta) { + angles[i] += deul[i]; + } + } + + obj->NodeSetLocalOrientation(mt::mat3(angles)); + } + else { + mt::vec3 angles = mt::zero3; + + for (unsigned short i = 0; i < 3; ++i) { + if (m_ipo_channels_active[OB_DROT_X + i]) { + angles[i] = m_ipo_xform.GetDeltaEulerAngles()[i]; + } + } + + // dRot are always local + const mt::mat3 rotation = m_ipo_start_orient * mt::mat3(angles); + + obj->NodeSetLocalOrientation(rotation); + } + } + //modifies scale? + if (m_ipo_channels_active[OB_SIZE_X] || m_ipo_channels_active[OB_SIZE_Y] || m_ipo_channels_active[OB_SIZE_Z] || + m_ipo_channels_active[OB_DSIZE_X] || m_ipo_channels_active[OB_DSIZE_Y] || m_ipo_channels_active[OB_DSIZE_Z]) { + //default is no scale change + mt::vec3 newScale = mt::one3; + if (!m_ipo_add) { + newScale = node->GetLocalScale(); + } + + for (unsigned short i = 0; i < 3; ++i) { + const mt::vec3& scale = m_ipo_xform.GetScaling(); + const mt::vec3& dscale = m_ipo_xform.GetDeltaScaling(); + + const bool delta = m_ipo_channels_active[OB_DSIZE_X + i]; + + if (m_ipo_channels_active[OB_SIZE_X + i]) { + newScale[i] = (delta ? (scale[i] + dscale[i]) : scale[i]); + } + else if (delta) { + newScale[i] = (dscale[i] + ((!m_ipo_add) ? m_ipo_start_scale[i] : 0.0f)); + } + } + + if (m_ipo_add) { + newScale = m_ipo_start_scale * newScale; + } + + obj->NodeSetLocalScale(newScale); + } + + return true; +} diff --git a/source/gameengine/Ketsji/KX_IPO_SGController.h b/source/gameengine/Ketsji/KX_IpoController.h similarity index 66% rename from source/gameengine/Ketsji/KX_IPO_SGController.h rename to source/gameengine/Ketsji/KX_IpoController.h index 67dd87468d30..d28c78a0a72a 100644 --- a/source/gameengine/Ketsji/KX_IPO_SGController.h +++ b/source/gameengine/Ketsji/KX_IpoController.h @@ -25,7 +25,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file KX_IPO_SGController.h +/** \file KX_IpoController.h * \ingroup ketsji */ @@ -33,17 +33,16 @@ #define __KX_IPO_SGCONTROLLER_H__ #include "SG_Controller.h" -#include "SG_Spatial.h" +#include "SG_Node.h" -#include "KX_IPOTransform.h" -#include "KX_IInterpolator.h" +#include "KX_IpoTransform.h" +#include "SG_Interpolator.h" #define KX_MAX_IPO_CHANNELS 19 //note- [0] is not used -class KX_IpoSGController : public SG_Controller +class KX_IpoController : public SG_Controller, public mt::SimdClassAllocator { - KX_IPOTransform m_ipo_xform; - T_InterpolatorList m_interpolators; + KX_IpoTransform m_ipo_xform; /** Flag for each IPO channel that can be applied to a game object */ bool m_ipo_channels_active[KX_MAX_IPO_CHANNELS]; @@ -57,68 +56,41 @@ class KX_IpoSGController : public SG_Controller /** Ipo must be applied in local coordinate rather than in global coordinates (used for force and Add mode)*/ bool m_ipo_local; - /** Were settings altered since the last update? */ - bool m_modified; - - /** Local time of this ipo.*/ - double m_ipotime; - /** Location of the object when the IPO is first fired (for local transformations) */ - MT_Point3 m_ipo_start_point; + mt::vec3 m_ipo_start_point; /** Orientation of the object when the IPO is first fired (for local transformations) */ - MT_Matrix3x3 m_ipo_start_orient; + mt::mat3 m_ipo_start_orient; /** Scale of the object when the IPO is first fired (for local transformations) */ - MT_Vector3 m_ipo_start_scale; + mt::vec3 m_ipo_start_scale; /** if IPO initial position has been set for local normal IPO */ bool m_ipo_start_initialized; /** Euler angles at the start of the game, needed for incomplete ROT Ipo curves */ - MT_Vector3 m_ipo_start_euler; + mt::vec3 m_ipo_start_euler; /** true is m_ipo_start_euler has been initialized */ bool m_ipo_euler_initialized; - /** A reference to the original game object. */ - class KX_GameObject *m_game_object; - public: - KX_IpoSGController(); - - virtual ~KX_IpoSGController(); - - virtual SG_Controller *GetReplica(class SG_Node *destnode); + KX_IpoController(); + virtual ~KX_IpoController() = default; - void SetOption(int option, int value); - - /** Set sumo data. */ - void UpdateSumoReference(); - /** Set reference to the corresponding game object. */ - void SetGameObject(class KX_GameObject *go); + virtual void SetOption(SG_ControllerOption option, bool value); void SetIPOChannelActive(int index, bool value) { //indexes found in makesdna\DNA_ipo_types.h m_ipo_channels_active[index] = value; } - KX_IPOTransform &GetIPOTransform() + KX_IpoTransform &GetIPOTransform() { return m_ipo_xform; } - void AddInterpolator(KX_IInterpolator *interp); - virtual bool Update(double time); - virtual void SetSimulatedTime(double time) - { - m_ipotime = time; - m_modified = true; - } - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_IpoSGController") -#endif + virtual bool Update(SG_Node *node); }; #endif /* __KX_IPO_SGCONTROLLER_H__ */ diff --git a/source/gameengine/Ketsji/KX_IpoConvert.cpp b/source/gameengine/Ketsji/KX_IpoConvert.cpp deleted file mode 100644 index 8611c57c863e..000000000000 --- a/source/gameengine/Ketsji/KX_IpoConvert.cpp +++ /dev/null @@ -1,441 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Ketsji/KX_IpoConvert.cpp - * \ingroup bgeconv - */ - -#ifdef _MSC_VER - /* don't show stl-warnings */ -# pragma warning (disable:4786) -#endif - -#include "BKE_material.h" /* give_current_material */ - -#include "KX_GameObject.h" -#include "KX_IpoConvert.h" -#include "KX_IInterpolator.h" -#include "KX_ScalarInterpolator.h" - -#include "KX_BlenderScalarInterpolator.h" -#include "KX_BlenderSceneConverter.h" - - -/* This little block needed for linking to Blender... */ -#ifdef WIN32 -#include "BLI_winstuff.h" -#endif - -#include "DNA_object_types.h" -#include "DNA_action_types.h" -#include "DNA_anim_types.h" -#include "DNA_ipo_types.h" -#include "DNA_lamp_types.h" -#include "DNA_world_types.h" -#include "DNA_camera_types.h" -#include "DNA_material_types.h" -/* end of blender include block */ - -#include "KX_IPO_SGController.h" -#include "KX_LightIpoSGController.h" -#include "KX_CameraIpoSGController.h" -#include "KX_WorldIpoController.h" -#include "KX_ObColorIpoSGController.h" -#include "KX_MaterialIpoController.h" - -#include "SG_Node.h" - -#include "STR_HashedString.h" - -static BL_InterpolatorList *GetAdtList(struct bAction *for_act, KX_BlenderSceneConverter *converter) -{ - BL_InterpolatorList *adtList= converter->FindInterpolatorList(for_act); - - if (!adtList) { - adtList = new BL_InterpolatorList(for_act); - converter->RegisterInterpolatorList(adtList, for_act); - } - - return adtList; -} - -SG_Controller *BL_CreateIPO(struct bAction *action, KX_GameObject* gameobj, KX_BlenderSceneConverter *converter) -{ - KX_IpoSGController* ipocontr = new KX_IpoSGController(); - ipocontr->SetGameObject(gameobj); - - Object* blenderobject = gameobj->GetBlenderObject(); - - ipocontr->GetIPOTransform().SetPosition(MT_Point3(blenderobject->loc)); - ipocontr->GetIPOTransform().SetEulerAngles(MT_Vector3(blenderobject->rot)); - ipocontr->GetIPOTransform().SetScaling(MT_Vector3(blenderobject->size)); - - const char *rotmode, *drotmode; - - switch (blenderobject->rotmode) { - case ROT_MODE_AXISANGLE: - rotmode = "rotation_axis_angle"; - drotmode = "delta_rotation_axis_angle"; - break; - case ROT_MODE_QUAT: /* XXX, this isn't working, currently only eulers are supported [#28853] */ - rotmode = "rotation_quaternion"; - drotmode = "delta_rotation_quaternion"; - break; - default: - rotmode = "rotation_euler"; - drotmode = "delta_rotation_euler"; - break; - } - - BL_InterpolatorList *adtList= GetAdtList(action, converter); - - // For each active channel in the adtList add an - // interpolator to the game object. - - KX_IInterpolator *interpolator; - KX_IScalarInterpolator *interp; - - for (int i=0; i<3; i++) { - if ((interp = adtList->GetScalarInterpolator("location", i))) { - interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetPosition()[i]), interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_LOC_X+i, true); - } - } - for (int i=0; i<3; i++) { - if ((interp = adtList->GetScalarInterpolator("delta_location", i))) { - interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetDeltaPosition()[i]), interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_DLOC_X+i, true); - } - } - for (int i=0; i<3; i++) { - if ((interp = adtList->GetScalarInterpolator(rotmode, i))) { - interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetEulerAngles()[i]), interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_ROT_X+i, true); - } - } - for (int i=0; i<3; i++) { - if ((interp = adtList->GetScalarInterpolator(drotmode, i))) { - interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetDeltaEulerAngles()[i]), interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_DROT_X+i, true); - } - } - for (int i=0; i<3; i++) { - if ((interp = adtList->GetScalarInterpolator("scale", i))) { - interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetScaling()[i]), interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_SIZE_X+i, true); - } - } - for (int i=0; i<3; i++) { - if ((interp = adtList->GetScalarInterpolator("delta_scale", i))) { - interpolator= new KX_ScalarInterpolator(&(ipocontr->GetIPOTransform().GetDeltaScaling()[i]), interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetIPOChannelActive(OB_DSIZE_X+i, true); - } - } - - - return ipocontr; -} - - -SG_Controller *BL_CreateObColorIPO(struct bAction *action, KX_GameObject* gameobj, KX_BlenderSceneConverter *converter) -{ - KX_ObColorIpoSGController* ipocontr_obcol=NULL; - KX_IInterpolator *interpolator; - KX_IScalarInterpolator *interp; - BL_InterpolatorList *adtList= GetAdtList(action, converter); - - for (int i=0; i<4; i++) { - if ((interp = adtList->GetScalarInterpolator("color", i))) { - if (!ipocontr_obcol) { - ipocontr_obcol = new KX_ObColorIpoSGController(); - } - interpolator= new KX_ScalarInterpolator(&ipocontr_obcol->m_rgba[i], interp); - ipocontr_obcol->AddInterpolator(interpolator); - } - } - - return ipocontr_obcol; -} - -SG_Controller *BL_CreateLampIPO(struct bAction *action, KX_GameObject* lightobj, KX_BlenderSceneConverter *converter) -{ - KX_LightIpoSGController* ipocontr = new KX_LightIpoSGController(); - - Lamp *blenderlamp = (Lamp*)lightobj->GetBlenderObject()->data; - - ipocontr->m_energy = blenderlamp->energy; - ipocontr->m_col_rgb[0] = blenderlamp->r; - ipocontr->m_col_rgb[1] = blenderlamp->g; - ipocontr->m_col_rgb[2] = blenderlamp->b; - ipocontr->m_dist = blenderlamp->dist; - - BL_InterpolatorList *adtList= GetAdtList(action, converter); - - // For each active channel in the adtList add an - // interpolator to the game object. - - KX_IInterpolator *interpolator; - KX_IScalarInterpolator *interp; - - if ((interp= adtList->GetScalarInterpolator("energy", 0))) { - interpolator= new KX_ScalarInterpolator(&ipocontr->m_energy, interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyEnergy(true); - } - - if ((interp = adtList->GetScalarInterpolator("distance", 0))) { - interpolator= new KX_ScalarInterpolator(&ipocontr->m_dist, interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyDist(true); - } - - for (int i=0; i<3; i++) { - if ((interp = adtList->GetScalarInterpolator("color", i))) { - interpolator= new KX_ScalarInterpolator(&ipocontr->m_col_rgb[i], interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyColor(true); - } - } - - return ipocontr; -} - -SG_Controller *BL_CreateCameraIPO(struct bAction *action, KX_GameObject* cameraobj, KX_BlenderSceneConverter *converter) -{ - KX_CameraIpoSGController* ipocontr = new KX_CameraIpoSGController(); - - Camera *blendercamera = (Camera*)cameraobj->GetBlenderObject()->data; - - ipocontr->m_lens = blendercamera->lens; - ipocontr->m_clipstart = blendercamera->clipsta; - ipocontr->m_clipend = blendercamera->clipend; - - BL_InterpolatorList *adtList= GetAdtList(action, converter); - - // For each active channel in the adtList add an - // interpolator to the game object. - - KX_IInterpolator *interpolator; - KX_IScalarInterpolator *interp; - - if ((interp = adtList->GetScalarInterpolator("lens", 0))) { - interpolator= new KX_ScalarInterpolator(&ipocontr->m_lens, interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyLens(true); - } - - if ((interp = adtList->GetScalarInterpolator("clip_start", 0))) { - interpolator= new KX_ScalarInterpolator(&ipocontr->m_clipstart, interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyClipStart(true); - } - - if ((interp = adtList->GetScalarInterpolator("clip_end", 0))) { - interpolator= new KX_ScalarInterpolator(&ipocontr->m_clipend, interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyClipEnd(true); - } - - return ipocontr; -} - - -SG_Controller * BL_CreateWorldIPO( bAction *action, struct World *blenderworld, KX_BlenderSceneConverter *converter ) -{ - KX_WorldIpoController *ipocontr = NULL; - - if (blenderworld) { - BL_InterpolatorList *adtList = GetAdtList(action, converter); - - // For each active channel in the adtList add an interpolator to the game object. - KX_IInterpolator *interpolator; - KX_IScalarInterpolator *interp; - - for (int i=0; i<3; i++) { - if ((interp = adtList->GetScalarInterpolator("ambient_color", i))) { - if (!ipocontr) { - ipocontr = new KX_WorldIpoController(); - } - interpolator = new KX_ScalarInterpolator(&ipocontr->m_ambi_rgb[i], interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyAmbientColor(true); - } - } - - for (int i=0; i<3; i++) { - if ((interp = adtList->GetScalarInterpolator("horizon_color", i))) { - if (!ipocontr) { - ipocontr = new KX_WorldIpoController(); - } - interpolator = new KX_ScalarInterpolator(&ipocontr->m_hori_rgb[i], interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyHorizonColor(true); - } - } - - if ((interp = adtList->GetScalarInterpolator("mist_settings.start", 0))) { - if (!ipocontr) { - ipocontr = new KX_WorldIpoController(); - } - interpolator = new KX_ScalarInterpolator(&ipocontr->m_mist_start, interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyMistStart(true); - } - - if ((interp = adtList->GetScalarInterpolator("mist_settings.depth", 0))) { - if (!ipocontr) { - ipocontr = new KX_WorldIpoController(); - } - interpolator = new KX_ScalarInterpolator(&ipocontr->m_mist_dist, interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyMistDist(true); - } - - if ((interp = adtList->GetScalarInterpolator("mist_settings.intensity", 0))) { - if (!ipocontr) { - ipocontr = new KX_WorldIpoController(); - } - interpolator = new KX_ScalarInterpolator(&ipocontr->m_mist_intensity, interp); - ipocontr->AddInterpolator(interpolator); - ipocontr->SetModifyMistIntensity(true); - } - - if (ipocontr) { - ipocontr->m_mist_start = blenderworld->miststa; - ipocontr->m_mist_dist = blenderworld->mistdist; - ipocontr->m_mist_intensity = blenderworld->misi; - ipocontr->m_hori_rgb[0] = blenderworld->horr; - ipocontr->m_hori_rgb[1] = blenderworld->horg; - ipocontr->m_hori_rgb[2] = blenderworld->horb; - ipocontr->m_ambi_rgb[0] = blenderworld->ambr; - ipocontr->m_ambi_rgb[1] = blenderworld->ambg; - ipocontr->m_ambi_rgb[2] = blenderworld->ambb; - } - } - return ipocontr; -} - -SG_Controller *BL_CreateMaterialIpo( - struct bAction *action, - Material* blendermaterial, - dword matname_hash, - KX_GameObject* gameobj, - KX_BlenderSceneConverter *converter - ) -{ - KX_MaterialIpoController* ipocontr = NULL; - - BL_InterpolatorList *adtList= GetAdtList(action, converter); - KX_IInterpolator *interpolator; - KX_IScalarInterpolator *sinterp; - - // -- - for (int i=0; i<3; i++) { - if ((sinterp = adtList->GetScalarInterpolator("diffuse_color", i))) { - if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(matname_hash); - } - interpolator= new KX_ScalarInterpolator(&ipocontr->m_rgba[i], sinterp); - ipocontr->AddInterpolator(interpolator); - } - } - - if ((sinterp = adtList->GetScalarInterpolator("alpha", 0))) { - if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(matname_hash); - } - interpolator= new KX_ScalarInterpolator(&ipocontr->m_rgba[3], sinterp); - ipocontr->AddInterpolator(interpolator); - } - - for (int i=0; i<3; i++) { - if ((sinterp = adtList->GetScalarInterpolator("specular_color", i))) { - if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(matname_hash); - } - interpolator= new KX_ScalarInterpolator(&ipocontr->m_specrgb[i], sinterp); - ipocontr->AddInterpolator(interpolator); - } - } - - if ((sinterp = adtList->GetScalarInterpolator("specular_hardness", 0))) { - if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(matname_hash); - } - interpolator= new KX_ScalarInterpolator(&ipocontr->m_hard, sinterp); - ipocontr->AddInterpolator(interpolator); - } - - if ((sinterp = adtList->GetScalarInterpolator("specular_intensity", 0))) { - if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(matname_hash); - } - interpolator= new KX_ScalarInterpolator(&ipocontr->m_spec, sinterp); - ipocontr->AddInterpolator(interpolator); - } - - if ((sinterp = adtList->GetScalarInterpolator("diffuse_intensity", 0))) { - if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(matname_hash); - } - interpolator= new KX_ScalarInterpolator(&ipocontr->m_ref, sinterp); - ipocontr->AddInterpolator(interpolator); - } - - if ((sinterp = adtList->GetScalarInterpolator("emit", 0))) { - if (!ipocontr) { - ipocontr = new KX_MaterialIpoController(matname_hash); - } - interpolator= new KX_ScalarInterpolator(&ipocontr->m_emit, sinterp); - ipocontr->AddInterpolator(interpolator); - } - - if (ipocontr) { - ipocontr->m_rgba[0] = blendermaterial->r; - ipocontr->m_rgba[1] = blendermaterial->g; - ipocontr->m_rgba[2] = blendermaterial->b; - ipocontr->m_rgba[3] = blendermaterial->alpha; - - ipocontr->m_specrgb[0] = blendermaterial->specr; - ipocontr->m_specrgb[1] = blendermaterial->specg; - ipocontr->m_specrgb[2] = blendermaterial->specb; - - ipocontr->m_hard = blendermaterial->har; - ipocontr->m_spec = blendermaterial->spec; - ipocontr->m_ref = blendermaterial->ref; - ipocontr->m_emit = blendermaterial->emit; - ipocontr->m_alpha = blendermaterial->alpha; - } - - return ipocontr; -} diff --git a/source/gameengine/Ketsji/KX_IpoTransform.h b/source/gameengine/Ketsji/KX_IpoTransform.h new file mode 100644 index 000000000000..92ed2f7f285b --- /dev/null +++ b/source/gameengine/Ketsji/KX_IpoTransform.h @@ -0,0 +1,81 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file KX_IpoTransform.h + * \ingroup ketsji + * \brief An abstract object you can move around in a 3d world, and has some logic + */ + +#ifndef __KX_IPOTRANSFORM_H__ +#define __KX_IPOTRANSFORM_H__ + +#include "mathfu.h" + +class KX_IpoTransform { +public: + KX_IpoTransform() : + m_position(mt::zero3), + m_eulerAngles(mt::zero3), + m_scaling(mt::one3), + m_deltaPosition(mt::zero3), + m_deltaEulerAngles(mt::zero3), + m_deltaScaling(mt::zero3) + {} + + mt::vec3& GetPosition() { return m_position; } + mt::vec3& GetEulerAngles() { return m_eulerAngles; } + mt::vec3& GetScaling() { return m_scaling; } + + const mt::vec3& GetPosition() const { return m_position; } + const mt::vec3& GetEulerAngles() const { return m_eulerAngles; } + const mt::vec3& GetScaling() const { return m_scaling; } + + mt::vec3& GetDeltaPosition() { return m_deltaPosition; } + mt::vec3& GetDeltaEulerAngles() { return m_deltaEulerAngles; } + mt::vec3& GetDeltaScaling() { return m_deltaScaling; } + + void SetPosition(const mt::vec3& pos) { m_position = pos; } + void SetEulerAngles(const mt::vec3& eul) { m_eulerAngles = eul; } + void SetScaling(const mt::vec3& scaling) { m_scaling = scaling; } + + void ClearDeltaStuff() { + m_deltaPosition = mt::zero3; + m_deltaEulerAngles = mt::zero3; + m_deltaScaling = mt::zero3; + } + +protected: + mt::vec3 m_position; + mt::vec3 m_eulerAngles; + mt::vec3 m_scaling; + mt::vec3 m_deltaPosition; + mt::vec3 m_deltaEulerAngles; + mt::vec3 m_deltaScaling; +}; + +#endif + diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index 3592a67c8e4b..35432d519e8b 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -34,8 +34,10 @@ # pragma warning (disable:4786) #endif -#include -#include +#include "CM_Message.h" + +#include +#include #include "BLI_task.h" @@ -43,31 +45,31 @@ #include "EXP_ListValue.h" #include "EXP_IntValue.h" -#include "EXP_VectorValue.h" #include "EXP_BoolValue.h" #include "EXP_FloatValue.h" #include "RAS_BucketManager.h" -#include "RAS_Rect.h" -#include "RAS_IRasterizer.h" +#include "RAS_Rasterizer.h" #include "RAS_ICanvas.h" +#include "RAS_OffScreen.h" +#include "RAS_Query.h" #include "RAS_ILightObject.h" -#include "MT_Vector3.h" -#include "MT_Transform.h" #include "SCA_IInputDevice.h" #include "KX_Camera.h" -#include "KX_Dome.h" -#include "KX_Light.h" -#include "KX_PythonInit.h" +#include "KX_LightObject.h" +#include "KX_Globals.h" #include "KX_PyConstraintBinding.h" #include "PHY_IPhysicsEnvironment.h" -#include "NG_NetworkScene.h" -#include "NG_NetworkDeviceInterface.h" +#include "KX_NetworkMessageScene.h" + +#include "DEV_Joystick.h" // for DEV_Joystick::HandleEvents +#include "KX_PythonInit.h" // for updatePythonJoysticks #include "KX_WorldInfo.h" -#include "KX_ISceneConverter.h" -#include "KX_TimeCategoryLogger.h" + +#include "BL_Converter.h" +#include "BL_SceneConverter.h" #include "RAS_FramingManager.h" #include "DNA_world_types.h" @@ -75,499 +77,257 @@ #include "KX_NavMeshObject.h" -#include "BL_Action.h" // For managing action lock. - #define DEFAULT_LOGIC_TIC_RATE 60.0 -//#define DEFAULT_PHYSICS_TIC_RATE 60.0 - -const char KX_KetsjiEngine::m_profileLabels[tc_numCategories][15] = { - "Physics:", // tc_physics - "Logic:", // tc_logic - "Animations:", // tc_animations - "Network:", // tc_network - "Scenegraph:", // tc_scenegraph - "Rasterizer:", // tc_rasterizer - "Services:", // tc_services - "Overhead:", // tc_overhead - "Outside:", // tc_outside - "GPU Latency:" // tc_latency -}; - -double KX_KetsjiEngine::m_ticrate = DEFAULT_LOGIC_TIC_RATE; -int KX_KetsjiEngine::m_maxLogicFrame = 5; -int KX_KetsjiEngine::m_maxPhysicsFrame = 5; -double KX_KetsjiEngine::m_anim_framerate = 25.0; -double KX_KetsjiEngine::m_suspendedtime = 0.0; -double KX_KetsjiEngine::m_suspendeddelta = 0.0; -double KX_KetsjiEngine::m_average_framerate = 0.0; -bool KX_KetsjiEngine::m_restrict_anim_fps = false; -short KX_KetsjiEngine::m_exitkey = 130; // ESC Key -bool KX_KetsjiEngine::m_doRender = true; - -/** - * Constructor of the Ketsji Engine - */ -KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system) - : m_canvas(NULL), - m_rasterizer(NULL), - m_kxsystem(system), - m_sceneconverter(NULL), - m_networkdevice(NULL), -#ifdef WITH_PYTHON - m_pythondictionary(NULL), -#endif - m_keyboarddevice(NULL), - m_mousedevice(NULL), - - m_bInitialized(false), - m_activecam(0), - m_bFixedTime(false), - m_useExternalClock(false), - - m_firstframe(true), - - m_frameTime(0.f), - m_clockTime(0.f), - m_previousClockTime(0.f), - m_previousAnimTime(0.f), - m_timescale(1.0f), - m_previousRealTime(0.0f), - - m_exitcode(KX_EXIT_REQUEST_NO_REQUEST), - m_exitstring(""), - - m_cameraZoom(1.0f), +KX_ExitInfo::KX_ExitInfo() + :m_code(NO_REQUEST) +{ +} - m_overrideCam(false), - m_overrideCamUseOrtho(false), - m_overrideCamNear(0.0f), - m_overrideCamFar(0.0f), - m_overrideCamZoom(1.0f), +KX_KetsjiEngine::CameraRenderData::CameraRenderData(KX_Camera *rendercam, KX_Camera *cullingcam, const RAS_Rect& area, + const RAS_Rect& viewport, RAS_Rasterizer::StereoMode stereoMode, RAS_Rasterizer::StereoEye eye) + :m_renderCamera(rendercam), + m_cullingCamera(cullingcam), + m_area(area), + m_viewport(viewport), + m_stereoMode(stereoMode), + m_eye(eye) +{ + m_renderCamera->AddRef(); +} - m_stereo(false), - m_curreye(0), +KX_KetsjiEngine::CameraRenderData::CameraRenderData(const CameraRenderData& other) + :m_renderCamera(CM_AddRef(other.m_renderCamera)), + m_cullingCamera(other.m_cullingCamera), + m_area(other.m_area), + m_viewport(other.m_viewport), + m_stereoMode(other.m_stereoMode), + m_eye(other.m_eye) +{ +} - m_logger(NULL), +KX_KetsjiEngine::CameraRenderData::~CameraRenderData() +{ + m_renderCamera->Release(); +} - // Set up timing info display variables - m_show_framerate(false), - m_show_profile(false), - m_showProperties(false), - m_showBackground(false), - m_show_debug_properties(false), - m_autoAddDebugProperties(true), +KX_KetsjiEngine::SceneRenderData::SceneRenderData(KX_Scene *scene) + :m_scene(scene) +{ +} - m_animation_record(false), +KX_KetsjiEngine::FrameRenderData::FrameRenderData(RAS_Rasterizer::OffScreenType ofsType) + :m_ofsType(ofsType) +{ +} - // Default behavior is to hide the cursor every frame. - m_hideCursor(false), +KX_KetsjiEngine::RenderData::RenderData(RAS_Rasterizer::StereoMode stereoMode, bool renderPerEye) + :m_stereoMode(stereoMode), + m_renderPerEye(renderPerEye) +{ +} - m_overrideFrameColor(false), - m_overrideFrameColorR(0.0f), - m_overrideFrameColorG(0.0f), - m_overrideFrameColorB(0.0f), - m_overrideFrameColorA(0.0f), - m_usedome(false) -{ - // Initialize the time logger - m_logger = new KX_TimeCategoryLogger (25); +const std::string KX_KetsjiEngine::m_profileLabels[tc_numCategories] = { + "Physics:", // tc_physics + "Logic:", // tc_logic + "Animations:", // tc_animations + "Network:", // tc_network + "Scenegraph:", // tc_scenegraph + "Rasterizer:", // tc_rasterizer + "Services:", // tc_services + "Overhead:", // tc_overhead + "Outside:", // tc_outside + "GPU Latency:" // tc_latency +}; - for (int i = tc_first; i < tc_numCategories; i++) - m_logger->AddCategory((KX_TimeCategory)i); +const std::string KX_KetsjiEngine::m_renderQueriesLabels[QUERY_MAX] = { + "Samples:", // QUERY_SAMPLES + "Primitives:", // QUERY_PRIMITIVES + "Time:" // QUERY_TIME +}; +/** + * Constructor of the Ketsji Engine + */ +KX_KetsjiEngine::KX_KetsjiEngine() + :m_canvas(nullptr), + m_rasterizer(nullptr), + m_converter(nullptr), + m_networkMessageManager(nullptr), #ifdef WITH_PYTHON - m_pyprofiledict = PyDict_New(); + m_pyprofiledict(PyDict_New()), #endif + m_inputDevice(nullptr), + m_scenes(new EXP_ListValue()), + m_bInitialized(false), + m_flags(AUTO_ADD_DEBUG_PROPERTIES), + m_frameTime(0.0f), + m_clockTime(0.0f), + m_timescale(1.0f), + m_previousRealTime(0.0f), + m_maxLogicFrame(5), + m_maxPhysicsFrame(5), + m_ticrate(DEFAULT_LOGIC_TIC_RATE), + m_anim_framerate(25.0), + m_doRender(true), + m_exitKey(SCA_IInputDevice::ENDKEY), + m_logger(KX_TimeCategoryLogger(m_clock, 25)), + m_average_framerate(0.0), + m_showBoundingBox(KX_DebugOption::DISABLE), + m_showArmature(KX_DebugOption::DISABLE), + m_showCameraFrustum(KX_DebugOption::DISABLE), + m_showShadowFrustum(KX_DebugOption::DISABLE), + m_globalsettings({0}), + m_taskscheduler(BLI_task_scheduler_create(TASK_SCHEDULER_AUTO_THREADS)) +{ + for (int i = tc_first; i < tc_numCategories; i++) { + m_logger.AddCategory((KX_TimeCategory)i); + } - m_taskscheduler = BLI_task_scheduler_create(TASK_SCHEDULER_AUTO_THREADS); - - BL_Action::InitLock(); + m_renderQueries.emplace_back(RAS_Query::SAMPLES); + m_renderQueries.emplace_back(RAS_Query::PRIMITIVES); + m_renderQueries.emplace_back(RAS_Query::TIME); } - - /** * Destructor of the Ketsji Engine, release all memory */ KX_KetsjiEngine::~KX_KetsjiEngine() { - delete m_logger; - if (m_usedome) - delete m_dome; - #ifdef WITH_PYTHON Py_CLEAR(m_pyprofiledict); #endif - if (m_taskscheduler) + if (m_taskscheduler) { BLI_task_scheduler_free(m_taskscheduler); + } - BL_Action::EndLock(); -} - - - -void KX_KetsjiEngine::SetKeyboardDevice(SCA_IInputDevice* keyboarddevice) -{ - MT_assert(keyboarddevice); - m_keyboarddevice = keyboarddevice; -} - - - -void KX_KetsjiEngine::SetMouseDevice(SCA_IInputDevice* mousedevice) -{ - MT_assert(mousedevice); - m_mousedevice = mousedevice; + m_scenes->Release(); } - - -void KX_KetsjiEngine::SetNetworkDevice(NG_NetworkDeviceInterface* networkdevice) +void KX_KetsjiEngine::SetInputDevice(SCA_IInputDevice *inputDevice) { - MT_assert(networkdevice); - m_networkdevice = networkdevice; + BLI_assert(inputDevice); + m_inputDevice = inputDevice; } - -void KX_KetsjiEngine::SetCanvas(RAS_ICanvas* canvas) +void KX_KetsjiEngine::SetCanvas(RAS_ICanvas *canvas) { - MT_assert(canvas); + BLI_assert(canvas); m_canvas = canvas; } - - -void KX_KetsjiEngine::SetRasterizer(RAS_IRasterizer* rasterizer) +void KX_KetsjiEngine::SetRasterizer(RAS_Rasterizer *rasterizer) { - MT_assert(rasterizer); + BLI_assert(rasterizer); m_rasterizer = rasterizer; } -#ifdef WITH_PYTHON -/* - * At the moment the bge.logic module is imported into 'pythondictionary' after this function is called. - * if this function ever changes to assign a copy, make sure the game logic module is imported into this dictionary before hand. - */ -void KX_KetsjiEngine::SetPyNamespace(PyObject *pythondictionary) +void KX_KetsjiEngine::SetNetworkMessageManager(KX_NetworkMessageManager *manager) { - MT_assert(pythondictionary); - m_pythondictionary = pythondictionary; + m_networkMessageManager = manager; } -PyObject* KX_KetsjiEngine::GetPyProfileDict() +#ifdef WITH_PYTHON +PyObject *KX_KetsjiEngine::GetPyProfileDict() { Py_INCREF(m_pyprofiledict); return m_pyprofiledict; } #endif - -void KX_KetsjiEngine::SetSceneConverter(KX_ISceneConverter* sceneconverter) -{ - MT_assert(sceneconverter); - m_sceneconverter = sceneconverter; -} - -void KX_KetsjiEngine::InitDome(short res, short mode, short angle, float resbuf, short tilt, struct Text* text) -{ - m_dome = new KX_Dome(m_canvas, m_rasterizer,this, res, mode, angle, resbuf, tilt, text); - m_usedome = true; -} - -void KX_KetsjiEngine::RenderDome() +void KX_KetsjiEngine::SetConverter(BL_Converter *converter) { - const GLint *viewport = m_canvas->GetViewPort(); - - m_dome->SetViewPort(viewport); - - KX_Scene* firstscene = *m_scenes.begin(); - const RAS_FrameSettings &framesettings = firstscene->GetFramingType(); - - m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); - - // hiding mouse cursor each frame - // (came back when going out of focus and then back in again) - if (m_hideCursor) - m_canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE); - - // clear the entire game screen with the border color - // only once per frame - - m_canvas->BeginDraw(); - - // BeginFrame() sets the actual drawing area. You can use a part of the window - if (!BeginFrame()) - return; - - KX_SceneList::iterator sceneit; - KX_Scene* scene = NULL; - - int n_renders=m_dome->GetNumberRenders(); // usually 4 or 6 - for (int i=0;iClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER); - for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++) - // for each scene, call the proceed functions - { - scene = *sceneit; - KX_SetActiveScene(scene); - KX_Camera* cam = scene->GetActiveCamera(); - - // pass the scene's worldsettings to the rasterizer - scene->GetWorldInfo()->UpdateWorldSettings(); - - // shadow buffers - if (i == 0) { - RenderShadowBuffers(scene); - } - // Avoid drawing the scene with the active camera twice when its viewport is enabled - if (cam && !cam->GetViewport()) - { - if (scene->IsClearingZBuffer()) - m_rasterizer->ClearDepthBuffer(); - - m_rasterizer->SetAuxilaryClientInfo(scene); - - // do the rendering - m_dome->RenderDomeFrame(scene,cam, i); - // render all the font objects for this scene - scene->RenderFonts(); - } - - list* cameras = scene->GetCameras(); - - // Draw the scene once for each camera with an enabled viewport - list::iterator it = cameras->begin(); - while (it != cameras->end()) { - if ((*it)->GetViewport()) - { - if (scene->IsClearingZBuffer()) - m_rasterizer->ClearDepthBuffer(); - - m_rasterizer->SetAuxilaryClientInfo(scene); - - // do the rendering - m_dome->RenderDomeFrame(scene, (*it),i); - // render all the font objects for this scene - scene->RenderFonts(); - } - - it++; - } - // Part of PostRenderScene() - m_rasterizer->MotionBlur(); - scene->Render2DFilters(m_canvas); - // no RunDrawingCallBacks - // no FlushDebugLines - } - m_dome->BindImages(i); - } - - m_canvas->EndFrame();//XXX do we really need that? - - m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight()); - - if (m_overrideFrameColor) //XXX why do we want - { - // Do not use the framing bar color set in the Blender scenes - m_canvas->ClearColor( - m_overrideFrameColorR, - m_overrideFrameColorG, - m_overrideFrameColorB, - m_overrideFrameColorA - ); - } - else - { - // Use the framing bar color set in the Blender scenes - m_canvas->ClearColor( - framesettings.BarRed(), - framesettings.BarGreen(), - framesettings.BarBlue(), - 1.0 - ); - } - m_dome->Draw(); - - // Draw Callback for the last scene -#ifdef WITH_PYTHON - PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment()); - scene->RunDrawingCallbacks(scene->GetPostDrawCB()); -#endif - EndFrame(); + BLI_assert(converter); + m_converter = converter; } -/** - * Ketsji Init(), Initializes data-structures and converts data from - * Blender into Ketsji native (realtime) format also sets up the - * graphics context - */ -void KX_KetsjiEngine::StartEngine(bool clearIpo) +void KX_KetsjiEngine::StartEngine() { - m_clockTime = m_kxsystem->GetTimeInSeconds(); - m_frameTime = m_kxsystem->GetTimeInSeconds(); - m_previousClockTime = m_kxsystem->GetTimeInSeconds(); - m_previousRealTime = m_kxsystem->GetTimeInSeconds(); + // Reset the clock to start at 0.0. + m_clock.Reset(); - m_firstframe = true; m_bInitialized = true; - // there is always one scene enabled at startup - Scene* scene = m_scenes[0]->GetBlenderScene(); - if (scene) - { - m_ticrate = scene->gm.ticrate ? scene->gm.ticrate : DEFAULT_LOGIC_TIC_RATE; - m_maxLogicFrame = scene->gm.maxlogicstep ? scene->gm.maxlogicstep : 5; - m_maxPhysicsFrame = scene->gm.maxphystep ? scene->gm.maxlogicstep : 5; - } - else - { - m_ticrate = DEFAULT_LOGIC_TIC_RATE; - m_maxLogicFrame = 5; - m_maxPhysicsFrame = 5; - } - - if (m_animation_record) - { - m_sceneconverter->ResetPhysicsObjectsAnimationIpo(clearIpo); - m_sceneconverter->WritePhysicsObjectToAnimationIpo(m_currentFrame); - } } -void KX_KetsjiEngine::ClearFrame() +void KX_KetsjiEngine::BeginFrame() { - // clear unless we're drawing overlapping stereo - if (m_rasterizer->InterlacedStereo() && - m_rasterizer->GetEye() == RAS_IRasterizer::RAS_STEREO_RIGHTEYE) - return; - - // clear the viewports with the background color of the first scene - bool doclear = false; - KX_SceneList::iterator sceneit; - RAS_Rect clearvp, area, viewport; + if (m_flags & SHOW_RENDER_QUERIES) { + m_logger.StartLog(tc_overhead); - for (sceneit = m_scenes.begin(); sceneit != m_scenes.end(); sceneit++) - { - KX_Scene* scene = *sceneit; - //const RAS_FrameSettings &framesettings = scene->GetFramingType(); - list* cameras = scene->GetCameras(); - - list::iterator it; - for (it = cameras->begin(); it != cameras->end(); it++) - { - GetSceneViewport(scene, (*it), area, viewport); - - if (!doclear) { - clearvp = viewport; - doclear = true; - } - else { - if (viewport.GetLeft() < clearvp.GetLeft()) - clearvp.SetLeft(viewport.GetLeft()); - if (viewport.GetBottom() < clearvp.GetBottom()) - clearvp.SetBottom(viewport.GetBottom()); - if (viewport.GetRight() > clearvp.GetRight()) - clearvp.SetRight(viewport.GetRight()); - if (viewport.GetTop() > clearvp.GetTop()) - clearvp.SetTop(viewport.GetTop()); - - } + for (RAS_Query& query : m_renderQueries) { + query.Begin(); } } - if (doclear) { - KX_Scene* firstscene = *m_scenes.begin(); - firstscene->GetWorldInfo()->UpdateBackGround(); + m_logger.StartLog(tc_rasterizer); - m_canvas->SetViewPort(clearvp.GetLeft(), clearvp.GetBottom(), - clearvp.GetRight(), clearvp.GetTop()); - m_rasterizer->ClearColorBuffer(); - } -} + m_rasterizer->BeginFrame(m_frameTime); -bool KX_KetsjiEngine::BeginFrame() -{ - // set the area used for rendering (stereo can assign only a subset) - m_rasterizer->SetRenderArea(); - - if (m_canvas->BeginDraw()) - { - ClearFrame(); - - m_rasterizer->BeginFrame(m_kxsystem->GetTimeInSeconds()); - - return true; - } - - return false; + m_canvas->BeginDraw(); } - void KX_KetsjiEngine::EndFrame() { m_rasterizer->MotionBlur(); + m_logger.StartLog(tc_overhead); + + if (m_flags & SHOW_RENDER_QUERIES) { + for (RAS_Query& query : m_renderQueries) { + query.End(); + } + } + // Show profiling info - m_logger->StartLog(tc_overhead, m_kxsystem->GetTimeInSeconds(), true); - if (m_show_framerate || m_show_profile || (m_show_debug_properties)) - { + if (m_flags & (SHOW_PROFILE | SHOW_FRAMERATE | SHOW_DEBUG_PROPERTIES | SHOW_RENDER_QUERIES)) { RenderDebugProperties(); } - double tottime = m_logger->GetAverage(); - if (tottime < 1e-6) + double tottime = m_logger.GetAverage(); + if (tottime < 1e-6) { tottime = 1e-6; + } #ifdef WITH_PYTHON for (int i = tc_first; i < tc_numCategories; ++i) { - double time = m_logger->GetAverage((KX_TimeCategory)i); + double time = m_logger.GetAverage((KX_TimeCategory)i); PyObject *val = PyTuple_New(2); - PyTuple_SetItem(val, 0, PyFloat_FromDouble(time*1000.0)); - PyTuple_SetItem(val, 1, PyFloat_FromDouble(time/tottime * 100.0)); + PyTuple_SetItem(val, 0, PyFloat_FromDouble(time * 1000.0)); + PyTuple_SetItem(val, 1, PyFloat_FromDouble(time / tottime * 100.0)); - PyDict_SetItemString(m_pyprofiledict, m_profileLabels[i], val); + PyDict_SetItemString(m_pyprofiledict, m_profileLabels[i].c_str(), val); Py_DECREF(val); } #endif - m_average_framerate = 1.0/tottime; + m_average_framerate = 1.0 / tottime; // Go to next profiling measurement, time spent after this call is shown in the next frame. - m_logger->NextMeasurement(m_kxsystem->GetTimeInSeconds()); + m_logger.NextMeasurement(); - m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); + m_logger.StartLog(tc_rasterizer); m_rasterizer->EndFrame(); + + m_logger.StartLog(tc_logic); + m_canvas->FlushScreenshots(); + // swap backbuffer (drawing into this buffer) <-> front/visible buffer - m_logger->StartLog(tc_latency, m_kxsystem->GetTimeInSeconds(), true); - m_rasterizer->SwapBuffers(); - m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); + m_logger.StartLog(tc_latency); + m_canvas->SwapBuffers(); + m_logger.StartLog(tc_rasterizer); m_canvas->EndDraw(); } -//#include "PIL_time.h" -//#include "LinearMath/btQuickprof.h" - - -bool KX_KetsjiEngine::NextFrame() +KX_KetsjiEngine::FrameTimes KX_KetsjiEngine::GetFrameTimes() { - double timestep = m_timescale / m_ticrate; - double framestep = timestep; - // static hidden::Clock sClock; - - m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(),true); - - //float dt = sClock.getTimeMicroseconds() * 0.000001f; - //sClock.reset(); - /* - * Clock advancement. There is basically three case: - * - m_useExternalClock is true, the user is responsible to advance the time + * Clock advancement. There is basically two case: + * - USE_EXTERNAL_CLOCK is true, the user is responsible to advance the time * manually using setClockTime, so here, we do not do anything. - * - m_useExternalClock is false, m_bFixedTime is true, we advance for one - * timestep, which already handle the time scaling parameter - * - m_useExternalClock is false, m_bFixedTime is false, we consider how much + * - USE_EXTERNAL_CLOCK is false, we consider how much * time has elapsed since last call and we scale this time by the time * scaling parameter. If m_timescale is 1.0 (default value), the clock * corresponds to the computer clock. @@ -579,440 +339,449 @@ bool KX_KetsjiEngine::NextFrame() * - ticrate * - max_physic_frame * - max_logic_frame - * XXX The logic over computation framestep is definitively not clear (and - * I'm not even sure it is correct). If needed frame is strictly greater - * than max_physics_frame, we are doing a jump in game time, but keeping - * framestep = 1 / ticrate, while if frames is greater than - * max_logic_frame, we increase framestep. - * - * XXX render.fps is not considred anywhere. + * - fixed_framerate */ - if (!m_useExternalClock) { - if (m_bFixedTime) { - m_clockTime += timestep; - } - else { - double current_time = m_kxsystem->GetTimeInSeconds(); - double dt = current_time - m_previousRealTime; - m_previousRealTime = current_time; - // m_clockTime += dt; - m_clockTime += dt * m_timescale; - } - } - double deltatime = m_clockTime - m_frameTime; - if (deltatime<0.0) - { - // We got here too quickly, which means there is nothing to do, just return and don't render. - // Not sure if this is the best fix, but it seems to stop the jumping framerate issue (#33088) - return false; + // Update time if the user is not controlling it. + if (!(m_flags & USE_EXTERNAL_CLOCK)) { + m_clockTime = m_clock.GetTimeSecond(); } - // Compute the number of logic frames to do each update (fixed tic bricks) - int frames = int(deltatime * m_ticrate / m_timescale + 1e-6); -// if (frames>1) -// printf("****************************************"); -// printf("dt = %f, deltatime = %f, frames = %d\n",dt, deltatime,frames); + // Get elapsed time. + const double dt = m_clockTime - m_previousRealTime; -// if (!frames) -// PIL_sleep_ms(1); - KX_SceneList::iterator sceneit; + // Time of a frame (without scale). + double timestep; + if (m_flags & FIXED_FRAMERATE) { + // Normal time step for fixed frame. + timestep = 1.0 / m_ticrate; + } + else { + // The frame is the smallest as possible. + timestep = dt; + } - if (frames>m_maxPhysicsFrame) - { + // Number of frames to proceed. + int frames; + if (m_flags & FIXED_FRAMERATE) { + // As many as possible for the elapsed time. + frames = int(dt * m_ticrate); + } + else { + // Proceed always one frame in non-fixed framerate. + frames = 1; + } - // printf("framedOut: %d\n",frames); - m_frameTime+=(frames-m_maxPhysicsFrame)*timestep; + // Fix timestep to not exceed max physics and logic frames. + if (frames > m_maxPhysicsFrame) { + timestep = dt / m_maxPhysicsFrame; frames = m_maxPhysicsFrame; } + if (frames > m_maxLogicFrame) { + timestep = dt / m_maxLogicFrame; + frames = m_maxLogicFrame; + } + // If the number of frame is non-zero, update previous time. + if (frames > 0) { + m_previousRealTime = m_clockTime; + } + // Else in case of fixed framerate, try to sleep until the next frame. + else if (m_flags & FIXED_FRAMERATE) { + const double sleeptime = timestep - dt - 1.0e-3; + /* If the remaining time is greather than 1ms (sleep resolution) sleep this thread. + * The other 1ms will be busy wait. + */ + if (sleeptime > 0.0) { + std::this_thread::sleep_for(std::chrono::nanoseconds((long)(sleeptime * 1.0e9))); + } + } - bool doRender = frames>0; + // Frame time with time scale. + const double framestep = timestep * m_timescale; - if (frames > m_maxLogicFrame) - { - framestep = (frames*timestep)/m_maxLogicFrame; - frames = m_maxLogicFrame; - } + FrameTimes times; + times.frames = frames; + times.timestep = timestep; + times.framestep = framestep; - while (frames) - { + return times; +} +bool KX_KetsjiEngine::NextFrame() +{ + m_logger.StartLog(tc_services); - m_frameTime += framestep; + const FrameTimes times = GetFrameTimes(); - m_sceneconverter->MergeAsyncLoads(); + // Exit if zero frame is sheduled. + if (times.frames == 0) { + // Start logging time spent outside main loop + m_logger.StartLog(tc_outside); - for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit) - // for each scene, call the proceed functions - { - KX_Scene* scene = *sceneit; + return false; + } + + // Fake release events for mouse movements only once. + m_inputDevice->ReleaseMoveEvent(); + + for (unsigned short i = 0; i < times.frames; ++i) { + m_frameTime += times.framestep; + +#ifdef WITH_SDL + // Handle all SDL Joystick events here to share them for all scenes properly. + short addrem[JOYINDEX_MAX] = {0}; + if (DEV_Joystick::HandleEvents(addrem)) { +# ifdef WITH_PYTHON + updatePythonJoysticks(addrem); +# endif // WITH_PYTHON + } +#endif // WITH_SDL + // for each scene, call the proceed functions + for (KX_Scene *scene : m_scenes) { /* Suspension holds the physics and logic processing for an * entire scene. Objects can be suspended individually, and * the settings for that precede the logic and physics * update. */ - m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true); - - m_sceneconverter->resetNoneDynamicObjectToIpo(); // this is for none dynamic objects with ipo + m_logger.StartLog(tc_logic); scene->UpdateObjectActivity(); - if (!scene->IsSuspended()) - { - // if the scene was suspended recalculate the delta tu "curtime" - m_suspendedtime = scene->getSuspendedTime(); - if (scene->getSuspendedTime()!=0.0) - scene->setSuspendedDelta(scene->getSuspendedDelta()+m_clockTime-scene->getSuspendedTime()); - m_suspendeddelta = scene->getSuspendedDelta(); - - - m_logger->StartLog(tc_network, m_kxsystem->GetTimeInSeconds(), true); - SG_SetActiveStage(SG_STAGE_NETWORK); - scene->GetNetworkScene()->proceed(m_frameTime); - - //m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); - //SG_SetActiveStage(SG_STAGE_NETWORK_UPDATE); - //scene->UpdateParents(m_frameTime); - - m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true); - SG_SetActiveStage(SG_STAGE_PHYSICS1); + if (!scene->IsSuspended()) { + m_logger.StartLog(tc_physics); // set Python hooks for each scene -#ifdef WITH_PYTHON - PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment()); -#endif KX_SetActiveScene(scene); - scene->GetPhysicsEnvironment()->EndFrame(); - - // Update scenegraph after physics step. This maps physics calculations - // into node positions. - //m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); - //SG_SetActiveStage(SG_STAGE_PHYSICS1_UPDATE); - //scene->UpdateParents(m_frameTime); - // Process sensors, and controllers - m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true); - SG_SetActiveStage(SG_STAGE_CONTROLLER); - scene->LogicBeginFrame(m_frameTime); + m_logger.StartLog(tc_logic); + scene->LogicBeginFrame(m_frameTime, times.framestep); // Scenegraph needs to be updated again, because Logic Controllers // can affect the local matrices. - m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); - SG_SetActiveStage(SG_STAGE_CONTROLLER_UPDATE); - scene->UpdateParents(m_frameTime); + m_logger.StartLog(tc_scenegraph); + scene->UpdateParents(); // Process actuators // Do some cleanup work for this logic frame - m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true); - SG_SetActiveStage(SG_STAGE_ACTUATOR); - scene->LogicUpdateFrame(m_frameTime, true); + m_logger.StartLog(tc_logic); + scene->LogicUpdateFrame(m_frameTime); scene->LogicEndFrame(); // Actuators can affect the scenegraph - m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); - SG_SetActiveStage(SG_STAGE_ACTUATOR_UPDATE); - scene->UpdateParents(m_frameTime); - - // update levels of detail - scene->UpdateObjectLods(); + m_logger.StartLog(tc_scenegraph); + scene->UpdateParents(); - m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true); - SG_SetActiveStage(SG_STAGE_PHYSICS2); - scene->GetPhysicsEnvironment()->BeginFrame(); + m_logger.StartLog(tc_physics); // Perform physics calculations on the scene. This can involve // many iterations of the physics solver. - scene->GetPhysicsEnvironment()->ProceedDeltaTime(m_frameTime,timestep,framestep);//m_deltatimerealDeltaTime); - - m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); - SG_SetActiveStage(SG_STAGE_PHYSICS2_UPDATE); - scene->UpdateParents(m_frameTime); + scene->GetPhysicsEnvironment()->ProceedDeltaTime(m_frameTime, times.timestep, times.framestep);//m_deltatimerealDeltaTime); + m_logger.StartLog(tc_scenegraph); + scene->UpdateParents(); + } - if (m_animation_record) - { - m_sceneconverter->WritePhysicsObjectToAnimationIpo(++m_currentFrame); - } - - scene->setSuspendedTime(0.0); - } // suspended - else - if (scene->getSuspendedTime()==0.0) - scene->setSuspendedTime(m_clockTime); - - m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true); - - // invalidates the shadow buffer from previous render/ImageRender because the scene has changed - scene->SetShadowDone(false); + m_logger.StartLog(tc_services); } - // update system devices - m_logger->StartLog(tc_logic, m_kxsystem->GetTimeInSeconds(), true); - if (m_keyboarddevice) - m_keyboarddevice->NextFrame(); + m_logger.StartLog(tc_network); + m_networkMessageManager->ClearMessages(); - if (m_mousedevice) - m_mousedevice->NextFrame(); + // update system devices + m_logger.StartLog(tc_logic); + m_inputDevice->ClearInputs(); - if (m_networkdevice) - m_networkdevice->NextFrame(); + m_converter->ProcessScheduledLibraries(); + UpdateSuspendedScenes(times.framestep); // scene management ProcessScheduledScenes(); - - frames--; } // Start logging time spent outside main loop - m_logger->StartLog(tc_outside, m_kxsystem->GetTimeInSeconds(), true); + m_logger.StartLog(tc_outside); - return doRender && m_doRender; + return m_doRender; } - - -void KX_KetsjiEngine::Render() +void KX_KetsjiEngine::UpdateSuspendedScenes(double framestep) { - if (m_usedome) { - RenderDome(); - return; - } - KX_Scene* firstscene = *m_scenes.begin(); - const RAS_FrameSettings &framesettings = firstscene->GetFramingType(); - - m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); - SG_SetActiveStage(SG_STAGE_RENDER); - - // hiding mouse cursor each frame - // (came back when going out of focus and then back in again) - if (m_hideCursor) - m_canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE); - - // clear the entire game screen with the border color - // only once per frame - m_canvas->BeginDraw(); - if (m_rasterizer->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) { - m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight()); - if (m_overrideFrameColor) - { - // Do not use the framing bar color set in the Blender scenes - m_canvas->ClearColor( - m_overrideFrameColorR, - m_overrideFrameColorG, - m_overrideFrameColorB, - m_overrideFrameColorA - ); - } - else - { - // Use the framing bar color set in the Blender scenes - m_canvas->ClearColor( - framesettings.BarRed(), - framesettings.BarGreen(), - framesettings.BarBlue(), - 1.0 - ); + for (KX_Scene *scene : m_scenes) { + if (scene->IsSuspended()) { + scene->SetSuspendedDelta(scene->GetSuspendedDelta() + framestep); } - // clear the -whole- viewport - m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER); } +} - m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_LEFTEYE); - - // BeginFrame() sets the actual drawing area. You can use a part of the window - if (!BeginFrame()) - return; - - KX_SceneList::iterator sceneit; - for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++) - // for each scene, call the proceed functions - { - KX_Scene* scene = *sceneit; - KX_Camera* cam = scene->GetActiveCamera(); - // pass the scene's worldsettings to the rasterizer - scene->GetWorldInfo()->UpdateWorldSettings(); +KX_KetsjiEngine::CameraRenderData KX_KetsjiEngine::GetCameraRenderData(KX_Scene *scene, KX_Camera *camera, KX_Camera *overrideCullingCam, + const RAS_Rect& displayArea, RAS_Rasterizer::StereoMode stereoMode, RAS_Rasterizer::StereoEye eye) +{ + KX_Camera *rendercam; + /* In case of stereo we must copy the camera because it is used twice with different settings + * (modelview matrix). This copy use the same transform settings that the original camera + * and its name is based on with the eye number in addition. + */ + const bool usestereo = (stereoMode != RAS_Rasterizer::RAS_STEREO_NOSTEREO); + if (usestereo) { + rendercam = new KX_Camera(scene, KX_Scene::m_callbacks, *camera->GetCameraData(), true); + rendercam->SetName("__stereo_" + camera->GetName() + "_" + std::to_string(eye) + "__"); + rendercam->NodeSetGlobalOrientation(camera->NodeGetWorldOrientation()); + rendercam->NodeSetWorldPosition(camera->NodeGetWorldPosition()); + rendercam->NodeSetWorldScale(camera->NodeGetWorldScaling()); + rendercam->NodeUpdate(); + } + // Else use the native camera. + else { + rendercam = camera; + } - // this is now done incrementally in KX_Scene::CalculateVisibleMeshes - //scene->UpdateMeshTransformations(); + KX_Camera *cullingcam = (overrideCullingCam) ? overrideCullingCam : rendercam; - // shadow buffers - RenderShadowBuffers(scene); + KX_SetActiveScene(scene); +#ifdef WITH_PYTHON + scene->RunDrawingCallbacks(KX_Scene::PRE_DRAW_SETUP, rendercam); +#endif - // Avoid drawing the scene with the active camera twice when its viewport is enabled - if (cam && !cam->GetViewport()) - { - if (scene->IsClearingZBuffer()) - m_rasterizer->ClearDepthBuffer(); + RAS_Rect area; + RAS_Rect viewport; + // Compute the area and the viewport based on the current display area and the optional camera viewport. + GetSceneViewport(scene, rendercam, displayArea, area, viewport); + // Compute the camera matrices: modelview and projection. + const mt::mat4 viewmat = m_rasterizer->GetViewMatrix(stereoMode, eye, rendercam->GetWorldToCamera(), rendercam->GetCameraData()->m_perspective); + const mt::mat4 projmat = GetCameraProjectionMatrix(scene, rendercam, stereoMode, eye, viewport, area); + rendercam->SetModelviewMatrix(viewmat); + rendercam->SetProjectionMatrix(projmat); + + CameraRenderData cameraData(rendercam, cullingcam, area, viewport, stereoMode, eye); + + if (usestereo) { + rendercam->Release(); + } - m_rasterizer->SetAuxilaryClientInfo(scene); + return cameraData; +} - // do the rendering - RenderFrame(scene, cam); - } +KX_KetsjiEngine::RenderData KX_KetsjiEngine::GetRenderData() +{ + const RAS_Rasterizer::StereoMode stereomode = m_rasterizer->GetStereoMode(); + const bool usestereo = (stereomode != RAS_Rasterizer::RAS_STEREO_NOSTEREO); + // Set to true when each eye needs to be rendered in a separated off screen. + const bool renderpereye = stereomode == RAS_Rasterizer::RAS_STEREO_INTERLACED || + stereomode == RAS_Rasterizer::RAS_STEREO_VINTERLACE || + stereomode == RAS_Rasterizer::RAS_STEREO_ANAGLYPH; - list* cameras = scene->GetCameras(); + RenderData renderData(stereomode, renderpereye); - // Draw the scene once for each camera with an enabled viewport - list::iterator it = cameras->begin(); - while (it != cameras->end()) { - if ((*it)->GetViewport()) - { - if (scene->IsClearingZBuffer()) - m_rasterizer->ClearDepthBuffer(); + // The number of eyes to manage in case of stereo. + const unsigned short numeyes = (usestereo) ? 2 : 1; + // The number of frames in case of stereo, could be multiple for interlaced or anaglyph stereo. + const unsigned short numframes = (renderpereye) ? 2 : 1; - m_rasterizer->SetAuxilaryClientInfo(scene); + // The off screen corresponding to the frame. + static const RAS_Rasterizer::OffScreenType ofsType[] = { + RAS_Rasterizer::RAS_OFFSCREEN_EYE_LEFT0, + RAS_Rasterizer::RAS_OFFSCREEN_EYE_RIGHT0 + }; - // do the rendering - RenderFrame(scene, (*it)); - } + // Pre-compute the display area used for stereo or normal rendering. + std::vector displayAreas; + for (unsigned short eye = 0; eye < numeyes; ++eye) { + displayAreas.push_back(m_rasterizer->GetRenderArea(m_canvas, stereomode, (RAS_Rasterizer::StereoEye)eye)); + } - it++; + // Prepare override culling camera of each scenes, we don't manage stereo currently. + for (KX_Scene *scene : m_scenes) { + KX_Camera *overrideCullingCam = scene->GetOverrideCullingCamera(); + + if (overrideCullingCam) { + RAS_Rect area; + RAS_Rect viewport; + // Compute the area and the viewport based on the current display area and the optional camera viewport. + GetSceneViewport(scene, overrideCullingCam, displayAreas[RAS_Rasterizer::RAS_STEREO_LEFTEYE], area, viewport); + // Compute the camera matrices: modelview and projection. + const mt::mat4 viewmat = m_rasterizer->GetViewMatrix(stereomode, RAS_Rasterizer::RAS_STEREO_LEFTEYE, + overrideCullingCam->GetWorldToCamera(), overrideCullingCam->GetCameraData()->m_perspective); + const mt::mat4 projmat = GetCameraProjectionMatrix(scene, overrideCullingCam, stereomode, + RAS_Rasterizer::RAS_STEREO_LEFTEYE, viewport, area); + overrideCullingCam->SetModelviewMatrix(viewmat); + overrideCullingCam->SetProjectionMatrix(projmat); } - PostRenderScene(scene); } - // only one place that checks for stereo - if (m_rasterizer->Stereo()) - { - m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_RIGHTEYE); - - if (!BeginFrame()) - return; + for (unsigned short frame = 0; frame < numframes; ++frame) { + renderData.m_frameDataList.emplace_back(ofsType[frame]); + FrameRenderData& frameData = renderData.m_frameDataList.back(); + // Get the eyes managed per frame. + std::vector eyes; + // One eye per frame but different. + if (renderpereye) { + eyes = {(RAS_Rasterizer::StereoEye)frame}; + } + // Two eyes for unique frame. + else if (usestereo) { + eyes = {RAS_Rasterizer::RAS_STEREO_LEFTEYE, RAS_Rasterizer::RAS_STEREO_RIGHTEYE}; + } + // Only one eye for unique frame. + else { + eyes = {RAS_Rasterizer::RAS_STEREO_LEFTEYE}; + } - for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++) - // for each scene, call the proceed functions - { - KX_Scene* scene = *sceneit; - KX_Camera* cam = scene->GetActiveCamera(); - - // pass the scene's worldsettings to the rasterizer - scene->GetWorldInfo()->UpdateWorldSettings(); - - if (scene->IsClearingZBuffer()) - m_rasterizer->ClearDepthBuffer(); - - // pass the scene, for picking and raycasting (shadows) - m_rasterizer->SetAuxilaryClientInfo(scene); - - // do the rendering - //RenderFrame(scene); - RenderFrame(scene, cam); - - list* cameras = scene->GetCameras(); - - // Draw the scene once for each camera with an enabled viewport - list::iterator it = cameras->begin(); - while (it != cameras->end()) { - if ((*it)->GetViewport()) - { - if (scene->IsClearingZBuffer()) - m_rasterizer->ClearDepthBuffer(); - - m_rasterizer->SetAuxilaryClientInfo(scene); + for (KX_Scene *scene : m_scenes) { + frameData.m_sceneDataList.emplace_back(scene); + SceneRenderData& sceneFrameData = frameData.m_sceneDataList.back(); - // do the rendering - RenderFrame(scene, (*it)); + KX_Camera *activecam = scene->GetActiveCamera(); + KX_Camera *overrideCullingCam = scene->GetOverrideCullingCamera(); + for (KX_Camera *cam : scene->GetCameraList()) { + if (cam != activecam && !cam->GetViewport()) { + continue; } - it++; + for (RAS_Rasterizer::StereoEye eye : eyes) { + sceneFrameData.m_cameraDataList.push_back(GetCameraRenderData(scene, cam, overrideCullingCam, displayAreas[eye], + stereomode, eye)); + } } - PostRenderScene(scene); } - } // if (m_rasterizer->Stereo()) + } - EndFrame(); + return renderData; } +void KX_KetsjiEngine::Render() +{ + m_logger.StartLog(tc_rasterizer); + BeginFrame(); -void KX_KetsjiEngine::RequestExit(int exitrequestmode) -{ - m_exitcode = exitrequestmode; -} + for (KX_Scene *scene : m_scenes) { + // shadow buffers + RenderShadowBuffers(scene); + // Render only independent texture renderers here. + scene->RenderTextureRenderers(KX_TextureRendererManager::VIEWPORT_INDEPENDENT, m_rasterizer, nullptr, nullptr, RAS_Rect(), RAS_Rect()); + } + RenderData renderData = GetRenderData(); + // Update all off screen to the current canvas size. + m_rasterizer->UpdateOffScreens(m_canvas); -void KX_KetsjiEngine::SetNameNextGame(const STR_String& nextgame) -{ - m_exitstring = nextgame; -} + const int width = m_canvas->GetWidth(); + const int height = m_canvas->GetHeight(); + // clear the entire game screen with the border color + // only once per frame + m_rasterizer->SetViewport(0, 0, width, height); + m_rasterizer->SetScissor(0, 0, width, height); + KX_Scene *firstscene = m_scenes->GetFront(); + const RAS_FrameSettings &framesettings = firstscene->GetFramingType(); + // Use the framing bar color set in the Blender scenes + m_rasterizer->SetClearColor(framesettings.BarRed(), framesettings.BarGreen(), framesettings.BarBlue(), 1.0f); + // Used to detect when a camera is the first rendered an then doesn't request a depth clear. + unsigned short pass = 0; -int KX_KetsjiEngine::GetExitCode() -{ - // if a game actuator has set an exit code or if there are no scenes left - if (!m_exitcode) - { - if (m_scenes.begin() == m_scenes.end()) - m_exitcode = KX_EXIT_REQUEST_NO_SCENES_LEFT; - } + for (FrameRenderData& frameData : renderData.m_frameDataList) { + // Current bound off screen. + RAS_OffScreen *offScreen = m_rasterizer->GetOffScreen(frameData.m_ofsType); + offScreen->Bind(); + + // Clear off screen only before the first scene render. + m_rasterizer->Clear(RAS_Rasterizer::RAS_COLOR_BUFFER_BIT | RAS_Rasterizer::RAS_DEPTH_BUFFER_BIT); + + // for each scene, call the proceed functions + for (unsigned short i = 0, size = frameData.m_sceneDataList.size(); i < size; ++i) { + const SceneRenderData& sceneFrameData = frameData.m_sceneDataList[i]; + KX_Scene *scene = sceneFrameData.m_scene; - // check if the window has been closed. - if (!m_exitcode) - { - //if (!m_canvas->Check()) { - // m_exitcode = KX_EXIT_REQUEST_OUTSIDE; - //} - } + const bool isfirstscene = (i == 0); + const bool islastscene = (i == (size - 1)); - return m_exitcode; -} + // pass the scene's worldsettings to the rasterizer + scene->GetWorldInfo()->UpdateWorldSettings(m_rasterizer); + m_rasterizer->SetAuxilaryClientInfo(scene); + // Draw the scene once for each camera with an enabled viewport or an active camera. + for (const CameraRenderData& cameraFrameData : sceneFrameData.m_cameraDataList) { + // do the rendering + RenderCamera(scene, cameraFrameData, offScreen, pass++, isfirstscene); + } -const STR_String& KX_KetsjiEngine::GetExitString() -{ - return m_exitstring; -} + /* Choose final render off screen target. If the current off screen is using multisamples we + * are sure that it will be copied to a non-multisamples off screen before render the filters. + * In this case the targeted off screen is the same as the current off screen. */ + RAS_Rasterizer::OffScreenType target; + if (offScreen->GetSamples() > 0) { + /* If the last scene is rendered it's useless to specify a multisamples off screen, we use then + * a non-multisamples off screen and avoid an extra off screen blit. */ + if (islastscene) { + target = RAS_Rasterizer::NextRenderOffScreen(frameData.m_ofsType); + } + else { + target = frameData.m_ofsType; + } + } + /* In case of non-multisamples a ping pong per scene render is made between a potentially multisamples + * off screen and a non-multisamples off screen as the both doesn't use multisamples. */ + else { + target = RAS_Rasterizer::NextRenderOffScreen(frameData.m_ofsType); + } -void KX_KetsjiEngine::EnableCameraOverride(const STR_String& forscene) -{ - m_overrideCam = true; - m_overrideSceneName = forscene; -} + // Render filters and get output off screen. + offScreen = PostRenderScene(scene, offScreen, m_rasterizer->GetOffScreen(target)); + frameData.m_ofsType = offScreen->GetType(); + } + } -void KX_KetsjiEngine::SetCameraZoom(float camzoom) -{ - m_cameraZoom = camzoom; -} + m_canvas->SetViewPort(0, 0, width, height); -void KX_KetsjiEngine::SetCameraOverrideUseOrtho(bool useOrtho) -{ - m_overrideCamUseOrtho = useOrtho; -} + // Compositing per eye off screens to screen. + if (renderData.m_renderPerEye) { + RAS_OffScreen *leftofs = m_rasterizer->GetOffScreen(renderData.m_frameDataList[0].m_ofsType); + RAS_OffScreen *rightofs = m_rasterizer->GetOffScreen(renderData.m_frameDataList[1].m_ofsType); + m_rasterizer->DrawStereoOffScreenToScreen(m_canvas, leftofs, rightofs, renderData.m_stereoMode); + } + // Else simply draw the off screen to screen. + else { + m_rasterizer->DrawOffScreenToScreen(m_canvas, m_rasterizer->GetOffScreen(renderData.m_frameDataList[0].m_ofsType)); + } -void KX_KetsjiEngine::SetCameraOverrideProjectionMatrix(const MT_CmMatrix4x4& mat) -{ - m_overrideCamProjMat = mat; + EndFrame(); } -void KX_KetsjiEngine::SetCameraOverrideViewMatrix(const MT_CmMatrix4x4& mat) +void KX_KetsjiEngine::RequestExit(KX_ExitInfo::Code code) { - m_overrideCamViewMat = mat; + RequestExit(code, ""); } -void KX_KetsjiEngine::SetCameraOverrideClipping(float nearfrust, float farfrust) +void KX_KetsjiEngine::RequestExit(KX_ExitInfo::Code code, const std::string& fileName) { - m_overrideCamNear = nearfrust; - m_overrideCamFar = farfrust; + m_exitInfo.m_code = code; + m_exitInfo.m_fileName = fileName; } -void KX_KetsjiEngine::SetCameraOverrideLens(float lens) +const KX_ExitInfo& KX_KetsjiEngine::GetExitInfo() const { - m_overrideCamLens = lens; + return m_exitInfo; } -void KX_KetsjiEngine::SetCameraOverrideZoom(float camzoom) +void KX_KetsjiEngine::EnableCameraOverride(const std::string& forscene, const mt::mat4& projmat, + const mt::mat4& viewmat, const RAS_CameraData& camdata) { - m_overrideCamZoom = camzoom; + SetFlag(CAMERA_OVERRIDE, true); + m_overrideSceneName = forscene; + m_overrideCamProjMat = projmat; + m_overrideCamViewMat = viewmat; + m_overrideCamData = camdata; } -void KX_KetsjiEngine::GetSceneViewport(KX_Scene *scene, KX_Camera* cam, RAS_Rect& area, RAS_Rect& viewport) + +void KX_KetsjiEngine::GetSceneViewport(KX_Scene *scene, KX_Camera *cam, const RAS_Rect& displayArea, RAS_Rect& area, RAS_Rect& viewport) { // In this function we make sure the rasterizer settings are up-to-date. // We compute the viewport so that logic using this information is up-to-date. @@ -1029,32 +798,33 @@ void KX_KetsjiEngine::GetSceneViewport(KX_Scene *scene, KX_Camera* cam, RAS_Rect // Don't do bars on user specified viewport RAS_FrameSettings settings = scene->GetFramingType(); - if (settings.FrameType() == RAS_FrameSettings::e_frame_bars) + if (settings.FrameType() == RAS_FrameSettings::e_frame_bars) { settings.SetFrameType(RAS_FrameSettings::e_frame_extend); + } RAS_FramingManager::ComputeViewport( scene->GetFramingType(), userviewport, viewport - ); + ); area = userviewport; } - else if ( !m_overrideCam || (scene->GetName() != m_overrideSceneName) || m_overrideCamUseOrtho ) { + else if (((m_flags & CAMERA_OVERRIDE) == 0) || (scene->GetName() != m_overrideSceneName) || !m_overrideCamData.m_perspective) { RAS_FramingManager::ComputeViewport( scene->GetFramingType(), - m_canvas->GetDisplayArea(), - viewport - ); + displayArea, + viewport); - area = m_canvas->GetDisplayArea(); - } else { + area = displayArea; + } + else { viewport.SetLeft(0); viewport.SetBottom(0); - viewport.SetRight(int(m_canvas->GetWidth())); - viewport.SetTop(int(m_canvas->GetHeight())); + viewport.SetRight(m_canvas->GetMaxX()); + viewport.SetTop(m_canvas->GetMaxY()); - area = m_canvas->GetDisplayArea(); + area = displayArea; } } @@ -1064,136 +834,75 @@ void KX_KetsjiEngine::UpdateAnimations(KX_Scene *scene) return; } - // Handle the animations independently of the logic time step - if (GetRestrictAnimationFPS()) { - double anim_timestep = 1.0 / KX_GetActiveScene()->GetAnimationFPS(); - if (m_frameTime - m_previousAnimTime > anim_timestep || m_frameTime == m_previousAnimTime) { - // Sanity/debug print to make sure we're actually going at the fps we want (should be close to anim_timestep) - // printf("Anim fps: %f\n", 1.0/(m_frameTime - m_previousAnimTime)); - m_previousAnimTime = m_frameTime; - for (KX_SceneList::iterator sceneit = m_scenes.begin(); sceneit != m_scenes.end(); ++sceneit) - (*sceneit)->UpdateAnimations(m_frameTime); - } - } - else - scene->UpdateAnimations(m_frameTime); + scene->UpdateAnimations(m_frameTime, (m_flags & RESTRICT_ANIMATION) != 0); } void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene) { - CListValue *lightlist = scene->GetLightList(); - int i, drawmode; + EXP_ListValue *lightlist = scene->GetLightList(); m_rasterizer->SetAuxilaryClientInfo(scene); - for (i=0; iGetCount(); i++) { - KX_GameObject *gameobj = (KX_GameObject*)lightlist->GetValue(i); - - KX_LightObject *light = (KX_LightObject*)gameobj; - RAS_ILightObject *raslight = light->GetLightData(); - - raslight->Update(); - - if (light->GetVisible() && m_rasterizer->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED && - raslight->HasShadowBuffer()) - { - /* make temporary camera */ - RAS_CameraData camdata = RAS_CameraData(); - KX_Camera *cam = new KX_Camera(scene, scene->m_callbacks, camdata, true, true); - cam->SetName("__shadow__cam__"); - - MT_Transform camtrans; - - /* switch drawmode for speed */ - drawmode = m_rasterizer->GetDrawingMode(); - m_rasterizer->SetDrawingMode(RAS_IRasterizer::KX_SHADOW); - - /* binds framebuffer object, sets up camera .. */ - raslight->BindShadowBuffer(m_canvas, cam, camtrans); - - /* update scene */ - scene->CalculateVisibleMeshes(m_rasterizer, cam, raslight->GetShadowLayer()); - - m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true); - SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE); - UpdateAnimations(scene); - m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); - SG_SetActiveStage(SG_STAGE_RENDER); - - /* render */ - m_rasterizer->ClearDepthBuffer(); - m_rasterizer->ClearColorBuffer(); - scene->RenderBuckets(camtrans, m_rasterizer); - - /* unbind framebuffer object, restore drawmode, free camera */ - raslight->UnbindShadowBuffer(); - m_rasterizer->SetDrawingMode(drawmode); - cam->Release(); - } + for (KX_LightObject *light : lightlist) { + light->Update(); } - /* remember that we have a valid shadow buffer for that scene */ - scene->SetShadowDone(true); -} -// update graphics -void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) -{ - bool override_camera; - RAS_Rect viewport, area; - float nearfrust, farfrust, focallength; -// KX_Camera* cam = scene->GetActiveCamera(); + if (m_rasterizer->GetDrawingMode() == RAS_Rasterizer::RAS_TEXTURED) { + for (KX_LightObject *light : lightlist) { + RAS_ILightObject *raslight = light->GetLightData(); + if (light->GetVisible() && raslight->HasShadowBuffer() && raslight->NeedShadowUpdate()) { + /* make temporary camera */ + RAS_CameraData camdata = RAS_CameraData(); + KX_Camera *cam = new KX_Camera(scene, KX_Scene::m_callbacks, camdata, true); + cam->SetName("__shadow__cam__"); - if (!cam) - return; + mt::mat3x4 camtrans; - KX_SetActiveScene(scene); + /* binds framebuffer object, sets up camera .. */ + raslight->BindShadowBuffer(m_canvas, cam, camtrans); -#ifdef WITH_PYTHON - scene->RunDrawingCallbacks(scene->GetPreDrawSetupCB()); -#endif + const std::vector objects = scene->CalculateVisibleMeshes(cam, raslight->GetShadowLayer()); - GetSceneViewport(scene, cam, area, viewport); + m_logger.StartLog(tc_animations); + UpdateAnimations(scene); + m_logger.StartLog(tc_rasterizer); - // store the computed viewport in the scene - scene->SetSceneViewport(viewport); + /* render */ + m_rasterizer->Clear(RAS_Rasterizer::RAS_DEPTH_BUFFER_BIT | RAS_Rasterizer::RAS_COLOR_BUFFER_BIT); + // Send a nullptr off screen because the viewport is binding it's using its own private one. + scene->RenderBuckets(objects, RAS_Rasterizer::RAS_SHADOW, camtrans, m_rasterizer, nullptr); - // set the viewport for this frame and scene - m_canvas->SetViewPort(viewport.GetLeft(), viewport.GetBottom(), - viewport.GetRight(), viewport.GetTop()); - - // see KX_BlenderMaterial::Activate - //m_rasterizer->SetAmbient(); - m_rasterizer->DisplayFog(); - - override_camera = m_overrideCam && (scene->GetName() == m_overrideSceneName); - override_camera = override_camera && (cam->GetName() == "__default__cam__"); - - if (override_camera && m_overrideCamUseOrtho) { - m_rasterizer->SetProjectionMatrix(m_overrideCamProjMat); - if (!cam->hasValidProjectionMatrix()) { - // needed to get frustum planes for culling - MT_Matrix4x4 projmat; - projmat.setValue(m_overrideCamProjMat.getPointer()); - cam->SetProjectionMatrix(projmat); + /* unbind framebuffer object, restore drawmode, free camera */ + raslight->UnbindShadowBuffer(); + cam->Release(); + } } - } else if (cam->hasValidProjectionMatrix()) - { - m_rasterizer->SetProjectionMatrix(cam->GetProjectionMatrix()); - } else - { - RAS_FrameFrustum frustum; - bool orthographic = !cam->GetCameraData()->m_perspective; - nearfrust = cam->GetCameraNear(); - farfrust = cam->GetCameraFar(); - focallength = cam->GetFocalLength(); - MT_Matrix4x4 projmat; + } +} - if (override_camera) { - nearfrust = m_overrideCamNear; - farfrust = m_overrideCamFar; - } +mt::mat4 KX_KetsjiEngine::GetCameraProjectionMatrix(KX_Scene *scene, KX_Camera *cam, RAS_Rasterizer::StereoMode stereoMode, + RAS_Rasterizer::StereoEye eye, const RAS_Rect& viewport, const RAS_Rect& area) const +{ + if (cam->hasValidProjectionMatrix()) { + return cam->GetProjectionMatrix(); + } + + const bool override_camera = ((m_flags & CAMERA_OVERRIDE) != 0) && (scene->GetName() == m_overrideSceneName) && + (cam->GetName() == "__default__cam__"); + + mt::mat4 projmat; + if (override_camera && !m_overrideCamData.m_perspective) { + // needed to get frustum planes for culling + projmat = m_overrideCamProjMat; + } + else { + RAS_FrameFrustum frustum{}; + const bool orthographic = !cam->GetCameraData()->m_perspective; + const float nearfrust = cam->GetCameraNear(); + const float farfrust = cam->GetCameraFar(); + const float focallength = cam->GetFocalLength(); - float camzoom = override_camera ? m_overrideCamZoom : m_cameraZoom; + const float camzoom = cam->GetZoom(); if (orthographic) { RAS_FramingManager::ComputeOrtho( @@ -1206,8 +915,8 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) cam->GetSensorFit(), cam->GetShiftHorizontal(), cam->GetShiftVertical(), - frustum - ); + frustum); + if (!cam->GetViewport()) { frustum.x1 *= camzoom; frustum.x2 *= camzoom; @@ -1217,7 +926,8 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) projmat = m_rasterizer->GetOrthoMatrix( frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar); - } else { + } + else { RAS_FramingManager::ComputeFrustum( scene->GetFramingType(), area, @@ -1230,8 +940,7 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) cam->GetShiftVertical(), nearfrust, farfrust, - frustum - ); + frustum); if (!cam->GetViewport()) { frustum.x1 *= camzoom; @@ -1239,95 +948,132 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) frustum.y1 *= camzoom; frustum.y2 *= camzoom; } - projmat = m_rasterizer->GetFrustumMatrix( - frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar, focallength); + projmat = m_rasterizer->GetFrustumMatrix(stereoMode, eye, focallength, + frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar); } - cam->SetProjectionMatrix(projmat); + } - // Otherwise the projection matrix for each eye will be the same... - if (!orthographic && m_rasterizer->Stereo()) - cam->InvalidateProjectionMatrix(); + return projmat; +} + +// update graphics +void KX_KetsjiEngine::RenderCamera(KX_Scene *scene, const CameraRenderData& cameraFrameData, RAS_OffScreen *offScreen, + unsigned short pass, bool isFirstScene) +{ + KX_Camera *rendercam = cameraFrameData.m_renderCamera; + KX_Camera *cullingcam = cameraFrameData.m_cullingCamera; + const RAS_Rect &area = cameraFrameData.m_area; + const RAS_Rect &viewport = cameraFrameData.m_viewport; + + KX_SetActiveScene(scene); + + /* Render texture probes depending of the the current viewport and area, these texture probes are commonly the planar map + * which need to be recomputed by each view in case of multi-viewport or stereo. + */ + scene->RenderTextureRenderers(KX_TextureRendererManager::VIEWPORT_DEPENDENT, m_rasterizer, offScreen, rendercam, viewport, area); + + // set the viewport for this frame and scene + const int left = viewport.GetLeft(); + const int bottom = viewport.GetBottom(); + const int width = viewport.GetWidth(); + const int height = viewport.GetHeight(); + m_rasterizer->SetViewport(left, bottom, width, height); + m_rasterizer->SetScissor(left, bottom, width, height); + + /* Clear the depth after setting the scene viewport/scissor + * if it's not the first render pass. */ + if (pass > 0) { + m_rasterizer->Clear(RAS_Rasterizer::RAS_DEPTH_BUFFER_BIT); } - MT_Transform camtrans(cam->GetWorldToCamera()); - MT_Matrix4x4 viewmat(camtrans); + m_rasterizer->SetEye(cameraFrameData.m_eye); + + m_rasterizer->SetProjectionMatrix(rendercam->GetProjectionMatrix()); + m_rasterizer->SetViewMatrix(rendercam->GetModelviewMatrix(), rendercam->NodeGetWorldScaling()); - m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->NodeGetLocalScaling(), cam->GetCameraData()->m_perspective); - cam->SetModelviewMatrix(viewmat); + if (isFirstScene) { + KX_WorldInfo *worldInfo = scene->GetWorldInfo(); + // Update background and render it. + worldInfo->UpdateBackGround(m_rasterizer); + worldInfo->RenderBackground(m_rasterizer); + } // The following actually reschedules all vertices to be // redrawn. There is a cache between the actual rescheduling // and this call though. Visibility is imparted when this call // runs through the individual objects. - m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true); - SG_SetActiveStage(SG_STAGE_CULLING); + m_logger.StartLog(tc_scenegraph); + + const std::vector objects = scene->CalculateVisibleMeshes(cullingcam, 0); - scene->CalculateVisibleMeshes(m_rasterizer,cam); + // update levels of detail + scene->UpdateObjectLods(cullingcam, objects); - m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true); - SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE); + m_logger.StartLog(tc_animations); UpdateAnimations(scene); - m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true); - SG_SetActiveStage(SG_STAGE_RENDER); + m_logger.StartLog(tc_rasterizer); + + // Draw debug infos like bouding box, armature ect.. if enabled. + scene->DrawDebug(objects, m_showBoundingBox, m_showArmature); + // Draw debug camera frustum. + DrawDebugCameraFrustum(scene, cameraFrameData); + DrawDebugShadowFrustum(scene); #ifdef WITH_PYTHON - PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment()); // Run any pre-drawing python callbacks - scene->RunDrawingCallbacks(scene->GetPreDrawCB()); + scene->RunDrawingCallbacks(KX_Scene::PRE_DRAW, rendercam); #endif - scene->RenderBuckets(camtrans, m_rasterizer); - - // render all the font objects for this scene - scene->RenderFonts(); + scene->RenderBuckets(objects, m_rasterizer->GetDrawingMode(), rendercam->GetWorldToCamera(), m_rasterizer, offScreen); - if (scene->GetPhysicsEnvironment()) + if (scene->GetPhysicsEnvironment()) { scene->GetPhysicsEnvironment()->DebugDrawWorld(); + } } /* * To run once per scene */ -void KX_KetsjiEngine::PostRenderScene(KX_Scene* scene) +RAS_OffScreen *KX_KetsjiEngine::PostRenderScene(KX_Scene *scene, RAS_OffScreen *inputofs, RAS_OffScreen *targetofs) { KX_SetActiveScene(scene); - // We need to first make sure our viewport is correct (enabling multiple viewports can mess this up) - m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight()); + scene->FlushDebugDraw(m_rasterizer, m_canvas); + + // We need to first make sure our viewport is correct (enabling multiple viewports can mess this up), only for filters. + const int width = m_canvas->GetWidth(); + const int height = m_canvas->GetHeight(); + m_rasterizer->SetViewport(0, 0, width, height); + m_rasterizer->SetScissor(0, 0, width, height); - m_rasterizer->FlushDebugShapes(scene); - scene->Render2DFilters(m_canvas); + RAS_OffScreen *offScreen = scene->Render2DFilters(m_rasterizer, m_canvas, inputofs, targetofs); #ifdef WITH_PYTHON - PHY_SetActiveEnvironment(scene->GetPhysicsEnvironment()); - scene->RunDrawingCallbacks(scene->GetPostDrawCB()); + /* We can't deduce what camera should be passed to the python callbacks + * because the post draw callbacks are per scenes and not per cameras. + */ + scene->RunDrawingCallbacks(KX_Scene::POST_DRAW, nullptr); // Python draw callback can also call debug draw functions, so we have to clear debug shapes. - m_rasterizer->FlushDebugShapes(scene); + scene->FlushDebugDraw(m_rasterizer, m_canvas); #endif + + return offScreen; } void KX_KetsjiEngine::StopEngine() { - if (m_bInitialized) - { - m_sceneconverter->FinalizeAsyncLoads(); + if (m_bInitialized) { + m_converter->FinalizeAsyncLoads(); - if (m_animation_record) - { -// printf("TestHandlesPhysicsObjectToAnimationIpo\n"); - m_sceneconverter->TestHandlesPhysicsObjectToAnimationIpo(); - } - - KX_SceneList::iterator sceneit; - for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++) - { - KX_Scene* scene = *sceneit; - m_sceneconverter->RemoveScene(scene); + while (m_scenes->GetCount() > 0) { + KX_Scene *scene = m_scenes->GetFront(); + DestructScene(scene); + // WARNING: here the scene is a dangling pointer. + m_scenes->Remove(0); } - m_scenes.clear(); // cleanup all the stuff m_rasterizer->Exit(); @@ -1336,70 +1082,53 @@ void KX_KetsjiEngine::StopEngine() // Scene Management is able to switch between scenes // and have several scenes running in parallel -void KX_KetsjiEngine::AddScene(KX_Scene* scene) +void KX_KetsjiEngine::AddScene(KX_Scene *scene) { - m_scenes.push_back(scene); + m_scenes->Add(CM_AddRef(scene)); PostProcessScene(scene); } - - -void KX_KetsjiEngine::PostProcessScene(KX_Scene* scene) +void KX_KetsjiEngine::PostProcessScene(KX_Scene *scene) { - bool override_camera = (m_overrideCam && (scene->GetName() == m_overrideSceneName)); - - SG_SetActiveStage(SG_STAGE_SCENE); + bool override_camera = (((m_flags & CAMERA_OVERRIDE) != 0) && (scene->GetName() == m_overrideSceneName)); // if there is no activecamera, or the camera is being // overridden we need to construct a temporary camera - if (!scene->GetActiveCamera() || override_camera) - { - KX_Camera* activecam = NULL; - - RAS_CameraData camdata = RAS_CameraData(); - if (override_camera) - { - camdata.m_lens = m_overrideCamLens; - camdata.m_clipstart = m_overrideCamNear; - camdata.m_clipend = m_overrideCamFar; + if (!scene->GetActiveCamera() || override_camera) { + KX_Camera *activecam = nullptr; - camdata.m_perspective= !m_overrideCamUseOrtho; - } - activecam = new KX_Camera(scene,KX_Scene::m_callbacks,camdata); + activecam = new KX_Camera(scene, KX_Scene::m_callbacks, override_camera ? m_overrideCamData : RAS_CameraData()); activecam->SetName("__default__cam__"); // set transformation if (override_camera) { - const MT_CmMatrix4x4& cammatdata = m_overrideCamViewMat; - MT_Transform trans = MT_Transform(cammatdata.getPointer()); - MT_Transform camtrans; - camtrans.invert(trans); - - activecam->NodeSetLocalPosition(camtrans.getOrigin()); - activecam->NodeSetLocalOrientation(camtrans.getBasis()); - activecam->NodeUpdateGS(0); - } else { - activecam->NodeSetLocalPosition(MT_Point3(0.0f, 0.0f, 0.0f)); - activecam->NodeSetLocalOrientation(MT_Vector3(0.0f, 0.0f, 0.0f)); - activecam->NodeUpdateGS(0); + const mt::mat3x4 trans = mt::mat3x4::ToAffineTransform(m_overrideCamViewMat); + const mt::mat3x4 camtrans = trans.Inverse(); + + activecam->NodeSetLocalPosition(camtrans.TranslationVector3D()); + activecam->NodeSetLocalOrientation(camtrans.RotationMatrix()); + } + else { + activecam->NodeSetLocalPosition(mt::zero3); + activecam->NodeSetLocalOrientation(mt::mat3::Identity()); } - scene->AddCamera(activecam); + activecam->NodeUpdate(); + + scene->GetCameraList()->Add(CM_AddRef(activecam)); scene->SetActiveCamera(activecam); - scene->GetObjectList()->Add(activecam->AddRef()); - scene->GetRootParentList()->Add(activecam->AddRef()); + scene->GetObjectList()->Add(CM_AddRef(activecam)); + scene->GetRootParentList()->Add(CM_AddRef(activecam)); // done with activecam activecam->Release(); } - scene->UpdateParents(0.0); + scene->UpdateParents(); } - - void KX_KetsjiEngine::RenderDebugProperties() { - STR_String debugtxt; + std::string debugtxt; int title_xmargin = -7; int title_y_top_margin = 4; int title_y_bottom_margin = 2; @@ -1407,28 +1136,22 @@ void KX_KetsjiEngine::RenderDebugProperties() int const_xindent = 4; int const_ysize = 14; - int xcoord = 12; // mmmm, these constants were taken from blender source - int ycoord = 17; // to 'mimic' behavior + int xcoord = 12; // mmmm, these constants were taken from blender source + int ycoord = 17; // to 'mimic' behavior int profile_indent = 72; - float tottime = m_logger->GetAverage(); + float tottime = m_logger.GetAverage(); if (tottime < 1e-6f) { tottime = 1e-6f; } - // Set viewport to entire canvas - RAS_Rect viewport; - m_canvas->SetViewPort(0, 0, int(m_canvas->GetWidth()), int(m_canvas->GetHeight())); + static const mt::vec4 white(1.0f, 1.0f, 1.0f, 1.0f); - if (m_show_framerate || m_show_profile) { - /* Title for profiling("Profile") */ - m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, - "Profile", - xcoord + const_xindent + title_xmargin, // Adds the constant x indent (0 for now) to the title x margin - ycoord, - m_canvas->GetWidth() /* RdV, TODO ?? */, - m_canvas->GetHeight() /* RdV, TODO ?? */); + if (m_flags & (SHOW_FRAMERATE | SHOW_PROFILE)) { + // Title for profiling("Profile") + // Adds the constant x indent (0 for now) to the title x margin + m_debugDraw.RenderText2d("Profile", mt::vec2(xcoord + const_xindent + title_xmargin, ycoord), white); // Increase the indent by default increase ycoord += const_ysize; @@ -1436,62 +1159,61 @@ void KX_KetsjiEngine::RenderDebugProperties() ycoord += title_y_bottom_margin; } - /* Framerate display */ - if (m_show_framerate) { - m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, - "Frametime :", - xcoord + const_xindent, - ycoord, - m_canvas->GetWidth() /* RdV, TODO ?? */, - m_canvas->GetHeight() /* RdV, TODO ?? */); - - debugtxt.Format("%5.1fms (%.1ffps)", tottime * 1000.0f, 1.0f/tottime); - m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, - debugtxt.ReadPtr(), - xcoord + const_xindent + profile_indent, - ycoord, - m_canvas->GetWidth() /* RdV, TODO ?? */, - m_canvas->GetHeight() /* RdV, TODO ?? */); + // Framerate display + if (m_flags & SHOW_FRAMERATE) { + m_debugDraw.RenderText2d("Frametime :", + mt::vec2(xcoord + const_xindent, + ycoord), white); + + debugtxt = (boost::format("%5.2fms (%.1ffps)") % (tottime * 1000.0f) % (1.0f / tottime)).str(); + m_debugDraw.RenderText2d(debugtxt, mt::vec2(xcoord + const_xindent + profile_indent, ycoord), white); // Increase the indent by default increase ycoord += const_ysize; } - /* Profile display */ - if (m_show_profile) { + // Profile display + if (m_flags & SHOW_PROFILE) { for (int j = tc_first; j < tc_numCategories; j++) { - m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, - m_profileLabels[j], - xcoord + const_xindent, - ycoord, - m_canvas->GetWidth(), - m_canvas->GetHeight()); - - double time = m_logger->GetAverage((KX_TimeCategory)j); - - debugtxt.Format("%5.2fms | %d%%", (float)time*1000.f, (int)((float)time/tottime * 100.f)); - m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, - debugtxt.ReadPtr(), - xcoord + const_xindent + profile_indent, ycoord, - m_canvas->GetWidth(), - m_canvas->GetHeight()); - - m_rasterizer->RenderBox2D(xcoord + (int)(2.2f * profile_indent), ycoord, m_canvas->GetWidth(), m_canvas->GetHeight(), (float)time/tottime); + m_debugDraw.RenderText2d(m_profileLabels[j], mt::vec2(xcoord + const_xindent, ycoord), white); + + double time = m_logger.GetAverage((KX_TimeCategory)j); + + debugtxt = (boost::format("%5.2fms | %d%%") % (time * 1000.f) % (int)(time / tottime * 100.f)).str(); + m_debugDraw.RenderText2d(debugtxt, mt::vec2(xcoord + const_xindent + profile_indent, ycoord), white); + + const mt::vec2 boxSize(50 * (time / tottime), 9); + m_debugDraw.RenderBox2d(mt::vec2(xcoord + (int)(2.2 * profile_indent), ycoord), boxSize, white); + ycoord += const_ysize; + } + } + + if (m_flags & SHOW_RENDER_QUERIES) { + m_debugDraw.RenderText2d("Render Queries :", mt::vec2(xcoord + const_xindent + title_xmargin, ycoord), white); + ycoord += const_ysize; + + for (unsigned short i = 0; i < QUERY_MAX; ++i) { + m_debugDraw.RenderText2d(m_renderQueriesLabels[i], mt::vec2(xcoord + const_xindent, ycoord), white); + + if (i == QUERY_TIME) { + debugtxt = (boost::format("%.2fms") % (((float)m_renderQueries[i].Result()) / 1e6)).str(); + } + else { + debugtxt = (boost::format("%i") % m_renderQueries[i].Result()).str(); + } + + m_debugDraw.RenderText2d(debugtxt, mt::vec2(xcoord + const_xindent + profile_indent, ycoord), white); ycoord += const_ysize; } } + // Add the ymargin for titles below the other section of debug info ycoord += title_y_top_margin; /* Property display */ - if (m_show_debug_properties) { - - /* Title for debugging("Debug properties") */ - m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, - "Debug Properties", - xcoord + const_xindent + title_xmargin, // Adds the constant x indent (0 for now) to the title x margin - ycoord, - m_canvas->GetWidth() /* RdV, TODO ?? */, - m_canvas->GetHeight() /* RdV, TODO ?? */); + if (m_flags & SHOW_DEBUG_PROPERTIES) { + // Title for debugging("Debug properties") + // Adds the constant x indent (0 for now) to the title x margin + m_debugDraw.RenderText2d("Debug Properties", mt::vec2(xcoord + const_xindent + title_xmargin, ycoord), white); // Increase the indent by default increase ycoord += const_ysize; @@ -1499,95 +1221,67 @@ void KX_KetsjiEngine::RenderDebugProperties() ycoord += title_y_bottom_margin; /* Calculate amount of properties that can displayed. */ - unsigned propsAct = 0; - unsigned propsMax = (m_canvas->GetHeight() - ycoord) / const_ysize; - - KX_SceneList::iterator sceneit; - for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++) { - KX_Scene* scene = *sceneit; - /* the 'normal' debug props */ - vector& debugproplist = scene->GetDebugProperties(); - - for (unsigned i=0; i < debugproplist.size() && propsAct < propsMax; i++) - { - CValue *propobj = debugproplist[i]->m_obj; - STR_String objname = propobj->GetName(); - STR_String propname = debugproplist[i]->m_name; - propsAct++; - if (propname == "__state__") { - // reserve name for object state - KX_GameObject* gameobj = static_cast(propobj); - unsigned int state = gameobj->GetState(); - debugtxt = objname + "." + propname + " = "; - bool first = true; - for (int statenum=1;state;state >>= 1, statenum++) - { - if (state & 1) - { - if (!first) - { - debugtxt += ","; - } - debugtxt += STR_String(statenum); - first = false; - } - } - m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, - debugtxt.ReadPtr(), - xcoord + const_xindent, - ycoord, - m_canvas->GetWidth(), - m_canvas->GetHeight()); - ycoord += const_ysize; - } - else { - CValue *propval = propobj->GetProperty(propname); - if (propval) { - STR_String text = propval->GetText(); - debugtxt = objname + ": '" + propname + "' = " + text; - m_rasterizer->RenderText2D(RAS_IRasterizer::RAS_TEXT_PADDED, - debugtxt.ReadPtr(), - xcoord + const_xindent, - ycoord, - m_canvas->GetWidth(), - m_canvas->GetHeight()); - ycoord += const_ysize; - } - } - } + const unsigned short propsMax = (m_canvas->GetHeight() - ycoord) / const_ysize; + + for (KX_Scene *scene : m_scenes) { + scene->RenderDebugProperties(m_debugDraw, const_xindent, const_ysize, xcoord, ycoord, propsMax); } } -} - -KX_SceneList* KX_KetsjiEngine::CurrentScenes() -{ - return &m_scenes; + m_debugDraw.Flush(m_rasterizer, m_canvas); } +void KX_KetsjiEngine::DrawDebugCameraFrustum(KX_Scene *scene, const CameraRenderData& cameraFrameData) +{ + if (m_showCameraFrustum == KX_DebugOption::DISABLE) { + return; + } + RAS_DebugDraw& debugDraw = scene->GetDebugDraw(); + for (KX_Camera *cam : scene->GetCameraList()) { + if (cam != cameraFrameData.m_renderCamera && (m_showCameraFrustum == KX_DebugOption::FORCE || cam->GetShowCameraFrustum())) { + const mt::mat4 viewmat = m_rasterizer->GetViewMatrix(cameraFrameData.m_stereoMode, cameraFrameData.m_eye, + cam->GetWorldToCamera(), cam->GetCameraData()->m_perspective); + const mt::mat4 projmat = GetCameraProjectionMatrix(scene, cam, cameraFrameData.m_stereoMode, cameraFrameData.m_eye, + cameraFrameData.m_viewport, cameraFrameData.m_area); + debugDraw.DrawCameraFrustum(projmat * viewmat); + } + } +} -KX_Scene* KX_KetsjiEngine::FindScene(const STR_String& scenename) +void KX_KetsjiEngine::DrawDebugShadowFrustum(KX_Scene *scene) { - KX_SceneList::iterator sceneit = m_scenes.begin(); - - // bit risky :) better to split the second clause - while ( (sceneit != m_scenes.end()) - && ((*sceneit)->GetName() != scenename)) - { - sceneit++; + if (m_showShadowFrustum == KX_DebugOption::DISABLE) { + return; } - return ((sceneit == m_scenes.end()) ? NULL : *sceneit); + RAS_DebugDraw& debugDraw = scene->GetDebugDraw(); + for (KX_LightObject *light : scene->GetLightList()) { + RAS_ILightObject *raslight = light->GetLightData(); + if (m_showShadowFrustum == KX_DebugOption::FORCE || light->GetShowShadowFrustum()) { + const mt::mat4 projmat(raslight->GetWinMat()); + const mt::mat4 viewmat(raslight->GetViewMat()); + + debugDraw.DrawCameraFrustum(projmat * viewmat); + } + } } +EXP_ListValue *KX_KetsjiEngine::CurrentScenes() +{ + return m_scenes; +} +KX_Scene *KX_KetsjiEngine::FindScene(const std::string& scenename) +{ + return m_scenes->FindValue(scenename); +} -void KX_KetsjiEngine::ConvertAndAddScene(const STR_String& scenename,bool overlay) +void KX_KetsjiEngine::ConvertAndAddScene(const std::string& scenename, bool overlay) { // only add scene when it doesn't exist! if (FindScene(scenename)) { - printf("warning: scene %s already exists, not added!\n",scenename.ReadPtr()); + CM_Warning("scene " << scenename << " already exists, not added!"); } else { if (overlay) { @@ -1599,118 +1293,92 @@ void KX_KetsjiEngine::ConvertAndAddScene(const STR_String& scenename,bool overla } } - - - -void KX_KetsjiEngine::RemoveScene(const STR_String& scenename) +void KX_KetsjiEngine::RemoveScene(const std::string& scenename) { - if (FindScene(scenename)) - { + if (FindScene(scenename)) { m_removingScenes.push_back(scenename); } - else - { -// STR_String tmpname = scenename; - std::cout << "warning: scene " << scenename << " does not exist, not removed!" << std::endl; + else { + CM_Warning("scene " << scenename << " does not exist, not removed!"); } } - - void KX_KetsjiEngine::RemoveScheduledScenes() { - if (m_removingScenes.size()) - { - vector::iterator scenenameit; - for (scenenameit=m_removingScenes.begin();scenenameit != m_removingScenes.end();scenenameit++) - { - STR_String scenename = *scenenameit; - - KX_SceneList::iterator sceneit; - for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++) - { - KX_Scene* scene = *sceneit; - if (scene->GetName()==scenename) - { - m_sceneconverter->RemoveScene(scene); - m_scenes.erase(sceneit); - break; - } + if (!m_removingScenes.empty()) { + std::vector::iterator scenenameit; + for (scenenameit = m_removingScenes.begin(); scenenameit != m_removingScenes.end(); scenenameit++) { + std::string scenename = *scenenameit; + + KX_Scene *scene = FindScene(scenename); + if (scene) { + DestructScene(scene); + m_scenes->RemoveValue(scene); } } m_removingScenes.clear(); } } -KX_Scene* KX_KetsjiEngine::CreateScene(Scene *scene, bool libloading) +KX_Scene *KX_KetsjiEngine::CreateScene(Scene *scene) { - KX_Scene* tmpscene = new KX_Scene(m_keyboarddevice, - m_mousedevice, - m_networkdevice, - scene->id.name+2, - scene, - m_canvas); - - m_sceneconverter->ConvertScene(tmpscene, - m_rasterizer, - m_canvas, - libloading); + KX_Scene *tmpscene = new KX_Scene(m_inputDevice, + scene->id.name + 2, + scene, + m_canvas, + m_networkMessageManager); return tmpscene; } -KX_Scene* KX_KetsjiEngine::CreateScene(const STR_String& scenename) +KX_Scene *KX_KetsjiEngine::CreateScene(const std::string& scenename) { - Scene *scene = m_sceneconverter->GetBlenderSceneForName(scenename); - if (!scene) - return NULL; + Scene *scene = m_converter->GetBlenderSceneForName(scenename); + if (!scene) { + return nullptr; + } + return CreateScene(scene); } void KX_KetsjiEngine::AddScheduledScenes() { - vector::iterator scenenameit; + if (!m_addingOverlayScenes.empty()) { + for (const std::string& scenename : m_addingOverlayScenes) { + KX_Scene *tmpscene = CreateScene(scenename); - if (m_addingOverlayScenes.size()) - { - for (scenenameit = m_addingOverlayScenes.begin(); - scenenameit != m_addingOverlayScenes.end(); - scenenameit++) - { - STR_String scenename = *scenenameit; - KX_Scene* tmpscene = CreateScene(scenename); if (tmpscene) { - m_scenes.push_back(tmpscene); + m_converter->ConvertScene(tmpscene); + m_scenes->Add(CM_AddRef(tmpscene)); PostProcessScene(tmpscene); - } else { - printf("warning: scene %s could not be found, not added!\n",scenename.ReadPtr()); + tmpscene->Release(); + } + else { + CM_Warning("scene " << scenename << " could not be found, not added!"); } } m_addingOverlayScenes.clear(); } - if (m_addingBackgroundScenes.size()) - { - for (scenenameit = m_addingBackgroundScenes.begin(); - scenenameit != m_addingBackgroundScenes.end(); - scenenameit++) - { - STR_String scenename = *scenenameit; - KX_Scene* tmpscene = CreateScene(scenename); + if (!m_addingBackgroundScenes.empty()) { + for (const std::string& scenename : m_addingBackgroundScenes) { + KX_Scene *tmpscene = CreateScene(scenename); + if (tmpscene) { - m_scenes.insert(m_scenes.begin(),tmpscene); + m_converter->ConvertScene(tmpscene); + m_scenes->Insert(0, CM_AddRef(tmpscene)); PostProcessScene(tmpscene); - } else { - printf("warning: scene %s could not be found, not added!\n",scenename.ReadPtr()); + tmpscene->Release(); + } + else { + CM_Warning("scene " << scenename << " could not be found, not added!"); } } m_addingBackgroundScenes.clear(); } } - - -bool KX_KetsjiEngine::ReplaceScene(const STR_String& oldscene,const STR_String& newscene) +bool KX_KetsjiEngine::ReplaceScene(const std::string& oldscene, const std::string& newscene) { // Don't allow replacement if the new scene doesn't exist. // Allows smarter game design (used to have no check here). @@ -1718,10 +1386,11 @@ bool KX_KetsjiEngine::ReplaceScene(const STR_String& oldscene,const STR_String& // for a game that did a replace followed by a lib load with the // new scene in the lib => it won't work anymore, the lib // must be loaded before doing the replace. - if (m_sceneconverter->GetBlenderSceneForName(newscene) != NULL) { - m_replace_scenes.push_back(std::make_pair(oldscene,newscene)); + if (m_converter->GetBlenderSceneForName(newscene)) { + m_replace_scenes.emplace_back(oldscene, newscene); return true; } + return false; } @@ -1731,103 +1400,61 @@ bool KX_KetsjiEngine::ReplaceScene(const STR_String& oldscene,const STR_String& // stupid to rely on the mem allocation order... void KX_KetsjiEngine::ReplaceScheduledScenes() { - if (m_replace_scenes.size()) - { - vector >::iterator scenenameit; + if (!m_replace_scenes.empty()) { + std::vector >::iterator scenenameit; for (scenenameit = m_replace_scenes.begin(); - scenenameit != m_replace_scenes.end(); - scenenameit++) + scenenameit != m_replace_scenes.end(); + scenenameit++) { - STR_String oldscenename = (*scenenameit).first; - STR_String newscenename = (*scenenameit).second; - int i=0; + std::string oldscenename = (*scenenameit).first; + std::string newscenename = (*scenenameit).second; /* Scenes are not supposed to be included twice... I think */ - KX_SceneList::iterator sceneit; - for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++) { - KX_Scene* scene = *sceneit; + for (unsigned int sce_idx = 0; sce_idx < m_scenes->GetCount(); ++sce_idx) { + KX_Scene *scene = m_scenes->GetValue(sce_idx); if (scene->GetName() == oldscenename) { // avoid crash if the new scene doesn't exist, just do nothing - Scene *blScene = m_sceneconverter->GetBlenderSceneForName(newscenename); + Scene *blScene = m_converter->GetBlenderSceneForName(newscenename); if (blScene) { - m_sceneconverter->RemoveScene(scene); - KX_Scene* tmpscene = CreateScene(blScene); - m_scenes[i]=tmpscene; + DestructScene(scene); + + KX_Scene *tmpscene = CreateScene(blScene); + m_converter->ConvertScene(tmpscene); + + m_scenes->SetValue(sce_idx, CM_AddRef(tmpscene)); PostProcessScene(tmpscene); + tmpscene->Release(); } else { - printf("warning: scene %s could not be found, not replaced!\n",newscenename.ReadPtr()); + CM_Warning("scene " << newscenename << " could not be found, not replaced!"); } } - i++; } } m_replace_scenes.clear(); } } - - -void KX_KetsjiEngine::SuspendScene(const STR_String& scenename) -{ - KX_Scene* scene = FindScene(scenename); - if (scene) scene->Suspend(); -} - - - -void KX_KetsjiEngine::ResumeScene(const STR_String& scenename) -{ - KX_Scene* scene = FindScene(scenename); - if (scene) scene->Resume(); -} - - - -void KX_KetsjiEngine::SetUseFixedTime(bool bUseFixedTime) -{ - m_bFixedTime = bUseFixedTime; -} - -void KX_KetsjiEngine::SetUseExternalClock(bool useExternalClock) +void KX_KetsjiEngine::SuspendScene(const std::string& scenename) { - m_useExternalClock = useExternalClock; -} - -void KX_KetsjiEngine::SetAnimRecordMode(bool animation_record, int startFrame) -{ - m_animation_record = animation_record; - if (animation_record) - { - // when recording physics keyframes, run at a variable (capped) frame rate (fixed time == full speed) - m_bFixedTime = false; + KX_Scene *scene = FindScene(scenename); + if (scene) { + scene->Suspend(); } - m_currentFrame = startFrame; -} - -int KX_KetsjiEngine::getAnimRecordFrame() const -{ - return m_currentFrame; -} - -void KX_KetsjiEngine::setAnimRecordFrame(int framenr) -{ - m_currentFrame = framenr; -} - -bool KX_KetsjiEngine::GetUseFixedTime(void) const -{ - return m_bFixedTime; } -bool KX_KetsjiEngine::GetUseExternalClock(void) const +void KX_KetsjiEngine::ResumeScene(const std::string& scenename) { - return m_useExternalClock; + KX_Scene *scene = FindScene(scenename); + if (scene) { + scene->Resume(); + } } -double KX_KetsjiEngine::GetSuspendedDelta() +void KX_KetsjiEngine::DestructScene(KX_Scene *scene) { - return m_suspendeddelta; + scene->RunOnRemoveCallbacks(); + m_converter->RemoveScene(scene); } double KX_KetsjiEngine::GetTicRate() @@ -1845,9 +1472,9 @@ double KX_KetsjiEngine::GetTimeScale() const return m_timescale; } -void KX_KetsjiEngine::SetTimeScale(double timescale) +void KX_KetsjiEngine::SetTimeScale(double timeScale) { - m_timescale = timescale; + m_timescale = timeScale; } int KX_KetsjiEngine::GetMaxLogicFrame() @@ -1870,22 +1497,27 @@ void KX_KetsjiEngine::SetMaxPhysicsFrame(int frame) m_maxPhysicsFrame = frame; } -bool KX_KetsjiEngine::GetRestrictAnimationFPS() +double KX_KetsjiEngine::GetAnimFrameRate() { - return m_restrict_anim_fps; + return m_anim_framerate; } -void KX_KetsjiEngine::SetRestrictAnimationFPS(bool bRestrictAnimFPS) +bool KX_KetsjiEngine::GetFlag(FlagType flag) const { - m_restrict_anim_fps = bRestrictAnimFPS; + return (m_flags & flag) != 0; } -double KX_KetsjiEngine::GetAnimFrameRate() +void KX_KetsjiEngine::SetFlag(FlagType flag, bool enable) { - return m_anim_framerate; + if (enable) { + m_flags = (FlagType)(m_flags | flag); + } + else { + m_flags = (FlagType)(m_flags & ~flag); + } } -double KX_KetsjiEngine::GetClockTime(void) const +double KX_KetsjiEngine::GetClockTime() const { return m_clockTime; } @@ -1895,14 +1527,14 @@ void KX_KetsjiEngine::SetClockTime(double externalClockTime) m_clockTime = externalClockTime; } -double KX_KetsjiEngine::GetFrameTime(void) const +double KX_KetsjiEngine::GetFrameTime() const { return m_frameTime; } -double KX_KetsjiEngine::GetRealTime(void) const +double KX_KetsjiEngine::GetRealTime() const { - return m_kxsystem->GetTimeInSeconds(); + return m_clock.GetTimeSecond(); } void KX_KetsjiEngine::SetAnimFrameRate(double framerate) @@ -1915,14 +1547,14 @@ double KX_KetsjiEngine::GetAverageFrameRate() return m_average_framerate; } -void KX_KetsjiEngine::SetExitKey(short key) +void KX_KetsjiEngine::SetExitKey(SCA_IInputDevice::SCA_EnumInputs key) { - m_exitkey = key; + m_exitKey = key; } -short KX_KetsjiEngine::GetExitKey() +SCA_IInputDevice::SCA_EnumInputs KX_KetsjiEngine::GetExitKey() const { - return m_exitkey; + return m_exitKey; } void KX_KetsjiEngine::SetRender(bool render) @@ -1935,146 +1567,82 @@ bool KX_KetsjiEngine::GetRender() return m_doRender; } -void KX_KetsjiEngine::SetShowFramerate(bool frameRate) -{ - m_show_framerate = frameRate; -} - -bool KX_KetsjiEngine::GetShowFramerate() -{ - return m_show_framerate; -} - -void KX_KetsjiEngine::SetShowProfile(bool profile) -{ - m_show_profile = profile; -} - -bool KX_KetsjiEngine::GetShowProfile() -{ - return m_show_profile; -} - -void KX_KetsjiEngine::SetShowProperties(bool properties) -{ - m_show_debug_properties = properties; -} - -bool KX_KetsjiEngine::GetShowProperties() -{ - return m_show_debug_properties; -} - -void KX_KetsjiEngine::SetAutoAddDebugProperties(bool add) -{ - m_autoAddDebugProperties = add; -} - -bool KX_KetsjiEngine::GetAutoAddDebugProperties() -{ - return m_autoAddDebugProperties; -} - -void KX_KetsjiEngine::SetTimingDisplay(bool frameRate, bool profile, bool properties) -{ - m_show_framerate = frameRate; - m_show_profile = profile; - m_show_debug_properties = properties; -} - - - -void KX_KetsjiEngine::GetTimingDisplay(bool& frameRate, bool& profile, bool& properties) const -{ - frameRate = m_show_framerate; - profile = m_show_profile; - properties = m_show_debug_properties; -} - - - -void KX_KetsjiEngine::ProcessScheduledScenes(void) +void KX_KetsjiEngine::ProcessScheduledScenes() { // Check whether there will be changes to the list of scenes - if (m_addingOverlayScenes.size() || - m_addingBackgroundScenes.size() || - m_replace_scenes.size() || - m_removingScenes.size()) { - + if (!(m_addingOverlayScenes.empty() && m_addingBackgroundScenes.empty() && + m_replace_scenes.empty() && m_removingScenes.empty())) { // Change the scene list ReplaceScheduledScenes(); RemoveScheduledScenes(); AddScheduledScenes(); } -} + if (m_scenes->Empty()) { + RequestExit(KX_ExitInfo::NO_SCENES_LEFT); + } +} -void KX_KetsjiEngine::SetHideCursor(bool hideCursor) +void KX_KetsjiEngine::SetShowBoundingBox(KX_DebugOption mode) { - m_hideCursor = hideCursor; + m_showBoundingBox = mode; } - -bool KX_KetsjiEngine::GetHideCursor(void) const +KX_DebugOption KX_KetsjiEngine::GetShowBoundingBox() const { - return m_hideCursor; + return m_showBoundingBox; } - -void KX_KetsjiEngine::SetUseOverrideFrameColor(bool overrideFrameColor) +void KX_KetsjiEngine::SetShowArmatures(KX_DebugOption mode) { - m_overrideFrameColor = overrideFrameColor; + m_showArmature = mode; } - -bool KX_KetsjiEngine::GetUseOverrideFrameColor(void) const +KX_DebugOption KX_KetsjiEngine::GetShowArmatures() const { - return m_overrideFrameColor; + return m_showArmature; } - -void KX_KetsjiEngine::SetOverrideFrameColor(float r, float g, float b, float a) +void KX_KetsjiEngine::SetShowCameraFrustum(KX_DebugOption mode) { - m_overrideFrameColorR = r; - m_overrideFrameColorG = g; - m_overrideFrameColorB = b; - m_overrideFrameColorA = a; + m_showCameraFrustum = mode; } +KX_DebugOption KX_KetsjiEngine::GetShowCameraFrustum() const +{ + return m_showCameraFrustum; +} -void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b, float& a) const +void KX_KetsjiEngine::SetShowShadowFrustum(KX_DebugOption mode) { - r = m_overrideFrameColorR; - g = m_overrideFrameColorG; - b = m_overrideFrameColorB; - a = m_overrideFrameColorA; + m_showShadowFrustum = mode; } +KX_DebugOption KX_KetsjiEngine::GetShowShadowFrustum() const +{ + return m_showShadowFrustum; +} void KX_KetsjiEngine::Resize() { - KX_SceneList::iterator sceneit; - /* extended mode needs to recalculate camera frusta when */ - KX_Scene* firstscene = *m_scenes.begin(); + KX_Scene *firstscene = m_scenes->GetFront(); const RAS_FrameSettings &framesettings = firstscene->GetFramingType(); if (framesettings.FrameType() == RAS_FrameSettings::e_frame_extend) { - for (sceneit = m_scenes.begin(); sceneit != m_scenes.end(); sceneit++) { - KX_Camera* cam = ((KX_Scene *)*sceneit)->GetActiveCamera(); + for (KX_Scene *scene : m_scenes) { + KX_Camera *cam = scene->GetActiveCamera(); cam->InvalidateProjectionMatrix(); } } } - -void KX_KetsjiEngine::SetGlobalSettings(GlobalSettings* gs) +void KX_KetsjiEngine::SetGlobalSettings(GlobalSettings *gs) { - m_globalsettings.matmode = gs->matmode; m_globalsettings.glslflag = gs->glslflag; } -GlobalSettings* KX_KetsjiEngine::GetGlobalSettings(void) +GlobalSettings *KX_KetsjiEngine::GetGlobalSettings() { return &m_globalsettings; } diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h index ab3a3d013b48..eb6aea7a8400 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.h +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h @@ -33,125 +33,202 @@ #ifndef __KX_KETSJIENGINE_H__ #define __KX_KETSJIENGINE_H__ -#include "MT_CmMatrix4x4.h" -#include "MT_Matrix4x4.h" -#include "STR_String.h" -#include "KX_ISystem.h" -#include "KX_Scene.h" +#include +#include "KX_TimeCategoryLogger.h" #include "EXP_Python.h" #include "KX_WorldInfo.h" +#include "RAS_CameraData.h" +#include "RAS_Rasterizer.h" +#include "RAS_DebugDraw.h" +#include "SCA_IInputDevice.h" // For SCA_IInputDevice::SCA_EnumInputs. +#include "CM_Clock.h" #include struct TaskScheduler; -class KX_TimeCategoryLogger; - -#define LEFT_EYE 1 -#define RIGHT_EYE 2 +class KX_Scene; +class KX_Camera; +class BL_Converter; +class KX_NetworkMessageManager; +class RAS_ICanvas; +class RAS_OffScreen; +class RAS_Query; +class SCA_IInputDevice; +template +class EXP_ListValue; + +struct KX_ExitInfo +{ + enum Code { + NO_REQUEST = 0, + QUIT_GAME, + RESTART_GAME, + START_OTHER_GAME, + NO_SCENES_LEFT, + BLENDER_ESC, + OUTSIDE, + MAX + }; + + Code m_code; + + /// Extra information on behaviour after exit (e.g starting an other game) + std::string m_fileName; + + KX_ExitInfo(); +}; -enum KX_ExitRequestMode +enum class KX_DebugOption { - KX_EXIT_REQUEST_NO_REQUEST = 0, - KX_EXIT_REQUEST_QUIT_GAME, - KX_EXIT_REQUEST_RESTART_GAME, - KX_EXIT_REQUEST_START_OTHER_GAME, - KX_EXIT_REQUEST_NO_SCENES_LEFT, - KX_EXIT_REQUEST_BLENDER_ESC, - KX_EXIT_REQUEST_OUTSIDE, - KX_EXIT_REQUEST_MAX + DISABLE = 0, + FORCE, + ALLOW }; typedef struct { - short matmode; short glslflag; -} GlobalSettings; +} GlobalSettings; /** * KX_KetsjiEngine is the core game engine class. */ -class KX_KetsjiEngine +class KX_KetsjiEngine : public mt::SimdClassAllocator { +public: + enum FlagType + { + FLAG_NONE = 0, + /// Show profiling info on the game display? + SHOW_PROFILE = (1 << 0), + /// Show the framerate on the game display? + SHOW_FRAMERATE = (1 << 1), + /// Process and show render queries? + SHOW_RENDER_QUERIES = (1 << 2), + /// Show debug properties on the game display. + SHOW_DEBUG_PROPERTIES = (1 << 3), + /// Whether or not to lock animation updates to the animation framerate? + RESTRICT_ANIMATION = (1 << 4), + /// Display of fixed frames? + FIXED_FRAMERATE = (1 << 5), + /// BGE relies on a external clock or its own internal clock? + USE_EXTERNAL_CLOCK = (1 << 6), + /// Automatic add debug properties to the debug list. + AUTO_ADD_DEBUG_PROPERTIES = (1 << 7), + /// Use override camera? + CAMERA_OVERRIDE = (1 << 8) + }; private: - class RAS_ICanvas* m_canvas; // 2D Canvas (2D Rendering Device Context) - class RAS_IRasterizer* m_rasterizer; // 3D Rasterizer (3D Rendering) - class KX_ISystem* m_kxsystem; - class KX_ISceneConverter* m_sceneconverter; - class NG_NetworkDeviceInterface* m_networkdevice; + struct CameraRenderData + { + CameraRenderData(KX_Camera *rendercam, KX_Camera *cullingcam, const RAS_Rect& area, const RAS_Rect& viewport, + RAS_Rasterizer::StereoMode stereoMode, RAS_Rasterizer::StereoEye eye); + CameraRenderData(const CameraRenderData& other); + ~CameraRenderData(); + + /// Rendered camera, could be a temporary camera in case of stereo. + KX_Camera *m_renderCamera; + KX_Camera *m_cullingCamera; + RAS_Rect m_area; + RAS_Rect m_viewport; + RAS_Rasterizer::StereoMode m_stereoMode; + RAS_Rasterizer::StereoEye m_eye; + }; + + struct SceneRenderData + { + SceneRenderData(KX_Scene *scene); + + KX_Scene *m_scene; + std::vector m_cameraDataList; + }; + + /// Data used to render a frame. + struct FrameRenderData + { + FrameRenderData(RAS_Rasterizer::OffScreenType ofsType); + + RAS_Rasterizer::OffScreenType m_ofsType; + std::vector m_sceneDataList; + }; + + struct RenderData + { + RenderData(RAS_Rasterizer::StereoMode stereoMode, bool renderPerEye); + + RAS_Rasterizer::StereoMode m_stereoMode; + bool m_renderPerEye; + std::vector m_frameDataList; + }; + + struct FrameTimes + { + // Number of frames to proceed. + int frames; + // Real duration of a frame. + double timestep; + // Scaled duration of a frame. + double framestep; + }; + + CM_Clock m_clock; + /// 2D Canvas (2D Rendering Device Context) + RAS_ICanvas *m_canvas; + /// 3D Rasterizer (3D Rendering) + RAS_Rasterizer *m_rasterizer; + /// Global debug draw, mainly used for profiling texts. + RAS_DebugDraw m_debugDraw; + BL_Converter *m_converter; + KX_NetworkMessageManager *m_networkMessageManager; #ifdef WITH_PYTHON - /* borrowed from sys.modules["__main__"], don't manage ref's */ - PyObject* m_pythondictionary; - PyObject* m_pyprofiledict; + PyObject *m_pyprofiledict; #endif - class SCA_IInputDevice* m_keyboarddevice; - class SCA_IInputDevice* m_mousedevice; - class KX_Dome* m_dome; // dome stereo mode - - /** Lists of scenes scheduled to be removed at the end of the frame. */ - std::vector m_removingScenes; - /** Lists of overley scenes scheduled to be added at the end of the frame. */ - std::vector m_addingOverlayScenes; - /** Lists of background scenes scheduled to be added at the end of the frame. */ - std::vector m_addingBackgroundScenes; - /** Lists of scenes scheduled to be replaced at the end of the frame. */ - std::vector > m_replace_scenes; - - /* The current list of scenes. */ - KX_SceneList m_scenes; - /* State variable recording the presence of object debug info in the current scene list. */ - bool m_propertiesPresent; - - bool m_bInitialized; - int m_activecam; - bool m_bFixedTime; - bool m_useExternalClock; - + SCA_IInputDevice *m_inputDevice; - bool m_firstframe; - int m_currentFrame; + /// Lists of scenes scheduled to be removed at the end of the frame. + std::vector m_removingScenes; + /// Lists of overley scenes scheduled to be added at the end of the frame. + std::vector m_addingOverlayScenes; + /// Lists of background scenes scheduled to be added at the end of the frame. + std::vector m_addingBackgroundScenes; + /// Lists of scenes scheduled to be replaced at the end of the frame. + std::vector > m_replace_scenes; - double m_frameTime; // current logic game time - double m_clockTime; // game time for the next rendering step - double m_previousClockTime; // game time of the previous rendering step - double m_previousAnimTime; //game time when the animations were last updated - double m_remainingTime; - double m_timescale; // time scaling parameter. if > 1.0, time goes faster than real-time. If < 1.0, times goes slower than real-time. - double m_previousRealTime; + /// The current list of scenes. + EXP_ListValue *m_scenes; - static int m_maxLogicFrame; /* maximum number of consecutive logic frame */ - static int m_maxPhysicsFrame; /* maximum number of consecutive physics frame */ - static double m_ticrate; - static double m_anim_framerate; /* for animation playback only - ipo and action */ + bool m_bInitialized; - static bool m_restrict_anim_fps; + FlagType m_flags; - static double m_suspendedtime; - static double m_suspendeddelta; + /// current logic game time + double m_frameTime; + /// game time for the next rendering step + double m_clockTime; + /// time scaling parameter. if > 1.0, time goes faster than real-time. If < 1.0, times goes slower than real-time. + double m_timescale; + double m_previousRealTime; - static short m_exitkey; /* Key used to exit the BGE */ + /// maximum number of consecutive logic frame + int m_maxLogicFrame; + /// maximum number of consecutive physics frame + int m_maxPhysicsFrame; + double m_ticrate; + /// for animation playback only - ipo and action + double m_anim_framerate; - static bool m_doRender; /* whether or not the scene should be rendered after the logic frame */ + bool m_doRender; /* whether or not the scene should be rendered after the logic frame */ - int m_exitcode; - STR_String m_exitstring; + /// Key used to exit the BGE + SCA_IInputDevice::SCA_EnumInputs m_exitKey; - float m_cameraZoom; + KX_ExitInfo m_exitInfo; - bool m_overrideCam; - STR_String m_overrideSceneName; + std::string m_overrideSceneName; + RAS_CameraData m_overrideCamData; + mt::mat4 m_overrideCamProjMat; + mt::mat4 m_overrideCamViewMat; - bool m_overrideCamUseOrtho; - MT_CmMatrix4x4 m_overrideCamProjMat; - MT_CmMatrix4x4 m_overrideCamViewMat; - float m_overrideCamNear; - float m_overrideCamFar; - float m_overrideCamLens; - /// Default camera zoom. - float m_overrideCamZoom; - - bool m_stereo; - int m_curreye; - - /** Categories for profiling display. */ + /// Categories for profiling display. typedef enum { tc_first = 0, tc_physics = 0, @@ -160,161 +237,172 @@ class KX_KetsjiEngine tc_network, tc_scenegraph, tc_rasterizer, - tc_services, // time spent in miscelaneous activities - tc_overhead, // profile info drawing overhead - tc_outside, // time spent outside main loop - tc_latency, // time spent waiting on the gpu + tc_services, // time spent in miscelaneous activities + tc_overhead, // profile info drawing overhead + tc_outside, // time spent outside main loop + tc_latency, // time spent waiting on the gpu tc_numCategories } KX_TimeCategory; - /** Time logger. */ - KX_TimeCategoryLogger* m_logger; - - /** Labels for profiling display. */ - static const char m_profileLabels[tc_numCategories][15]; - /** Last estimated framerate */ - static double m_average_framerate; - /** Show the framerate on the game display? */ - bool m_show_framerate; - /** Show profiling info on the game display? */ - bool m_show_profile; - /** Show any debug (scene) object properties on the game display? */ - bool m_showProperties; - /** Show background behind text for readability? */ - bool m_showBackground; - /** Show debug properties on the game display*/ - bool m_show_debug_properties; - /** Automatic add debug properties to the debug list*/ - bool m_autoAddDebugProperties; - - /** record physics into keyframes */ - bool m_animation_record; - - /** Hide cursor every frame? */ - bool m_hideCursor; - - /** Override framing bars color? */ - bool m_overrideFrameColor; - /** Red component of framing bar color. */ - float m_overrideFrameColorR; - /** Green component of framing bar color. */ - float m_overrideFrameColorG; - /** Blue component of framing bar color. */ - float m_overrideFrameColorB; - /** alpha component of framing bar color. */ - float m_overrideFrameColorA; - - /** Settings that doesn't go away with Game Actuator */ + /// Time logger. + KX_TimeCategoryLogger m_logger; + /// Labels for profiling display. + static const std::string m_profileLabels[tc_numCategories]; + + enum QueryCategory { + QUERY_SAMPLES = 0, + QUERY_PRIMITIVES, + QUERY_TIME, + QUERY_MAX + }; + + std::vector m_renderQueries; + static const std::string m_renderQueriesLabels[QUERY_MAX]; + + /// Last estimated framerate + double m_average_framerate; + + /// Enable debug draw of culling bounding boxes. + KX_DebugOption m_showBoundingBox; + /// Enable debug draw armatures. + KX_DebugOption m_showArmature; + /// Enable debug draw of camera frustum. + KX_DebugOption m_showCameraFrustum; + /// Enable debug light shadow frustum. + KX_DebugOption m_showShadowFrustum; + + /// Settings that doesn't go away with Game Actuator GlobalSettings m_globalsettings; - /** Task scheduler for multi-threading */ - TaskScheduler* m_taskscheduler; + /// Task scheduler for multi-threading + TaskScheduler *m_taskscheduler; + + /** Set scene's total pause duration for animations process. + * This is done in a separate loop to get the proper state of each scenes. + * eg: There's 2 scenes, the first is suspended and the second is active. + * If the second scene resume the first, the first scene will be not proceed + * in 'NextFrame' for one frame, but set as active. + * The render functions, called after and which update animations, + * will see the first scene as active and will proceed to it, + * but it will cause some negative current frame on actions because of the + * total pause duration not set. + */ + void UpdateSuspendedScenes(double framestep); + + /// Update and return the projection matrix of a camera depending on the viewport. + mt::mat4 GetCameraProjectionMatrix(KX_Scene *scene, KX_Camera *cam, RAS_Rasterizer::StereoMode stereoMode, + RAS_Rasterizer::StereoEye eye, const RAS_Rect& viewport, const RAS_Rect& area) const; + CameraRenderData GetCameraRenderData(KX_Scene *scene, KX_Camera *camera, KX_Camera *overrideCullingCam, const RAS_Rect& displayArea, + RAS_Rasterizer::StereoMode stereoMode, RAS_Rasterizer::StereoEye eye); + /// Compute frame render data per eyes (in case of stereo), scenes and camera. + RenderData GetRenderData(); + + void RenderCamera(KX_Scene *scene, const CameraRenderData& cameraFrameData, RAS_OffScreen *offScreen, unsigned short pass, bool isFirstScene); + RAS_OffScreen *PostRenderScene(KX_Scene *scene, RAS_OffScreen *inputofs, RAS_OffScreen *targetofs); + void RenderDebugProperties(); + /// Debug draw cameras frustum of a scene. + void DrawDebugCameraFrustum(KX_Scene *scene, const CameraRenderData& cameraFrameData); + /// Debug draw lights shadow frustum of a scene. + void DrawDebugShadowFrustum(KX_Scene *scene); + + /** + * Processes all scheduled scene activity. + * At the end, if the scene lists have changed, + * SceneListsChanged(void) is called. + * \see SceneListsChanged(void). + */ + void ProcessScheduledScenes(void); + + /** + * This method is invoked when the scene lists have changed. + */ + void RemoveScheduledScenes(void); + void AddScheduledScenes(void); + void ReplaceScheduledScenes(void); + void PostProcessScene(KX_Scene *scene); + + void BeginFrame(); + void EndFrame(); - void RenderFrame(KX_Scene* scene, KX_Camera* cam); - void PostRenderScene(KX_Scene* scene); - void RenderDebugProperties(); + FrameTimes GetFrameTimes(); public: - KX_KetsjiEngine(class KX_ISystem* system); + KX_KetsjiEngine(); virtual ~KX_KetsjiEngine(); - // set the devices and stuff. the client must take care of creating these - void SetKeyboardDevice(SCA_IInputDevice* keyboarddevice); - void SetMouseDevice(SCA_IInputDevice* mousedevice); - void SetNetworkDevice(NG_NetworkDeviceInterface* networkdevice); - void SetCanvas(RAS_ICanvas* canvas); - void SetRasterizer(RAS_IRasterizer* rasterizer); + /// set the devices and stuff. the client must take care of creating these + void SetInputDevice(SCA_IInputDevice *inputDevice); + void SetCanvas(RAS_ICanvas *canvas); + void SetRasterizer(RAS_Rasterizer *rasterizer); + void SetNetworkMessageManager(KX_NetworkMessageManager *manager); #ifdef WITH_PYTHON - void SetPyNamespace(PyObject *pythondictionary); - PyObject* GetPyNamespace() { return m_pythondictionary; } - PyObject* GetPyProfileDict(); + PyObject *GetPyProfileDict(); #endif - void SetSceneConverter(KX_ISceneConverter* sceneconverter); - KX_ISceneConverter* GetSceneConverter() { return m_sceneconverter; } - void SetAnimRecordMode(bool animation_record, int startFrame); - - int getAnimRecordFrame() const; - void setAnimRecordFrame(int framenr); - - RAS_IRasterizer* GetRasterizer() { return m_rasterizer; } - RAS_ICanvas* GetCanvas() { return m_canvas; } - SCA_IInputDevice* GetKeyboardDevice() { return m_keyboarddevice; } - SCA_IInputDevice* GetMouseDevice() { return m_mousedevice; } - - TaskScheduler* GetTaskScheduler() { return m_taskscheduler; } - - /// Dome functions - void InitDome(short res, short mode, short angle, float resbuf, short tilt, struct Text* text); - void EndDome(); - void RenderDome(); - bool m_usedome; - - ///returns true if an update happened to indicate -> Render - bool NextFrame(); - void Render(); - void RenderShadowBuffers(KX_Scene *scene); - - void StartEngine(bool clearIpo); - void StopEngine(); - void Export(const STR_String& filename); - - void RequestExit(int exitrequestmode); - void SetNameNextGame(const STR_String& nextgame); - int GetExitCode(); - const STR_String& GetExitString(); - - KX_SceneList* CurrentScenes(); - KX_Scene* FindScene(const STR_String& scenename); - void AddScene(class KX_Scene* scene); - void ConvertAndAddScene(const STR_String& scenename,bool overlay); - - void RemoveScene(const STR_String& scenename); - bool ReplaceScene(const STR_String& oldscene,const STR_String& newscene); - void SuspendScene(const STR_String& scenename); - void ResumeScene(const STR_String& scenename); - - void GetSceneViewport(KX_Scene* scene, KX_Camera* cam, RAS_Rect& area, RAS_Rect& viewport); - - /// Sets zoom for camera objects, useful only with extend and scale framing mode. - void SetCameraZoom(float camzoom); - - void EnableCameraOverride(const STR_String& forscene); - - void SetCameraOverrideUseOrtho(bool useOrtho); - void SetCameraOverrideProjectionMatrix(const MT_CmMatrix4x4& mat); - void SetCameraOverrideViewMatrix(const MT_CmMatrix4x4& mat); - void SetCameraOverrideClipping(float near, float far); - void SetCameraOverrideLens(float lens); - /// Sets zoom for default camera, = 2 in embedded mode. - void SetCameraOverrideZoom(float camzoom); + void SetConverter(BL_Converter *converter); + BL_Converter *GetConverter() + { + return m_converter; + } + + RAS_Rasterizer *GetRasterizer() + { + return m_rasterizer; + } + RAS_ICanvas *GetCanvas() + { + return m_canvas; + } + SCA_IInputDevice *GetInputDevice() + { + return m_inputDevice; + } + KX_NetworkMessageManager *GetNetworkMessageManager() const + { + return m_networkMessageManager; + } + + TaskScheduler *GetTaskScheduler() + { + return m_taskscheduler; + } + + /// returns true if an update happened to indicate -> Render + bool NextFrame(); + void Render(); + void RenderShadowBuffers(KX_Scene *scene); + + void StartEngine(); + void StopEngine(); + void Export(const std::string& filename); + + void RequestExit(KX_ExitInfo::Code code); + void RequestExit(KX_ExitInfo::Code code, const std::string& fileName); + + const KX_ExitInfo& GetExitInfo() const; + + EXP_ListValue *CurrentScenes(); + KX_Scene *FindScene(const std::string& scenename); + void AddScene(KX_Scene *scene); + void DestructScene(KX_Scene *scene); + void ConvertAndAddScene(const std::string& scenename, bool overlay); + + void RemoveScene(const std::string& scenename); + bool ReplaceScene(const std::string& oldscene, const std::string& newscene); + void SuspendScene(const std::string& scenename); + void ResumeScene(const std::string& scenename); + + void GetSceneViewport(KX_Scene *scene, KX_Camera *cam, const RAS_Rect& displayArea, RAS_Rect& area, RAS_Rect& viewport); + + void EnableCameraOverride(const std::string& forscene, const mt::mat4& projmat, const mt::mat4& viewmat, const RAS_CameraData& camdata); // Update animations for object in this scene void UpdateAnimations(KX_Scene *scene); - /** - * Sets display of all frames. - * \param bUseFixedTime New setting for display all frames. - */ - void SetUseFixedTime(bool bUseFixedTime); + bool GetFlag(FlagType flag) const; + /// Enable or disable a set of flags. + void SetFlag(FlagType flag, bool enable); - /** - * Returns display of all frames. - * \return Current setting for display all frames. - */ - bool GetUseFixedTime(void) const; - - /** - * Sets if the BGE relies on a external clock or its own internal clock - */ - void SetUseExternalClock(bool bUseExternalClock); - - /** - * Returns if we rely on an external clock - * \return Current setting - */ - bool GetUseExternalClock(void) const; - - /** + /* * Returns next render frame game time */ double GetClockTime(void) const; @@ -335,60 +423,44 @@ class KX_KetsjiEngine */ double GetRealTime(void) const; - /** - * Returns the difference between the local time of the scene (when it - * was running and not suspended) and the "curtime" - */ - static double GetSuspendedDelta(); - /** * Gets the number of logic updates per second. */ - static double GetTicRate(); + double GetTicRate(); /** * Sets the number of logic updates per second. */ - static void SetTicRate(double ticrate); + void SetTicRate(double ticrate); /** * Gets the maximum number of logic frame before render frame */ - static int GetMaxLogicFrame(); + int GetMaxLogicFrame(); /** * Sets the maximum number of logic frame before render frame */ - static void SetMaxLogicFrame(int frame); + void SetMaxLogicFrame(int frame); /** * Gets the maximum number of physics frame before render frame */ - static int GetMaxPhysicsFrame(); + int GetMaxPhysicsFrame(); /** * Sets the maximum number of physics frame before render frame */ - static void SetMaxPhysicsFrame(int frame); - - /** - * Gets whether or not to lock animation updates to the animframerate - */ - static bool GetRestrictAnimationFPS(); - - /** - * Sets whether or not to lock animation updates to the animframerate - */ - static void SetRestrictAnimationFPS(bool bRestrictAnimFPS); + void SetMaxPhysicsFrame(int frame); /** * Gets the framerate for playing animations. (actions and ipos) */ - static double GetAnimFrameRate(); + double GetAnimFrameRate(); /** * Sets the framerate for playing animations. (actions and ipos) */ - static void SetAnimFrameRate(double framerate); + void SetAnimFrameRate(double framerate); /** * Gets the last estimated average framerate */ - static double GetAverageFrameRate(); + double GetAverageFrameRate(); /** * Gets the time scale multiplier @@ -398,156 +470,53 @@ class KX_KetsjiEngine /** * Sets the time scale multiplier */ - void SetTimeScale(double scale); + void SetTimeScale(double timeScale); - static void SetExitKey(short key); - - static short GetExitKey(); + void SetExitKey(SCA_IInputDevice::SCA_EnumInputs key); + SCA_IInputDevice::SCA_EnumInputs GetExitKey() const; /** * Activate or deactivates the render of the scene after the logic frame * \param render true (render) or false (do not render) */ - static void SetRender(bool render); + void SetRender(bool render); /** * Get the current render flag value */ - static bool GetRender(); + bool GetRender(); - /** - * \Sets the display for frame rate on or off. - */ - void SetShowFramerate(bool frameRate); + /// Allow debug bounding box debug. + void SetShowBoundingBox(KX_DebugOption mode); + /// Returns the current setting for bounding box debug. + KX_DebugOption GetShowBoundingBox() const; - /** - * \Gets the display for frame rate on or off. - */ - bool GetShowFramerate(); - - /** - * \Sets the display for individual components on or off. - */ - void SetShowProfile(bool profile); - - /** - * \Gets the display for individual components on or off. - */ - bool GetShowProfile(); - - /** - * \Sets the display of scene object debug properties on or off. - */ - void SetShowProperties(bool properties); - - /** - * \Gets the display of scene object debug properties on or off. - */ - bool GetShowProperties(); - - /** - * \Sets if the auto adding of scene object debug properties on or off. - */ - bool GetAutoAddDebugProperties(); - - /** - * \Sets the auto adding of scene object debug properties on or off. - */ - void SetAutoAddDebugProperties(bool add); - - /** - * Activates or deactivates timing information display. - * \param frameRate Display for frame rate on or off. - * \param profile Display for individual components on or off. - * \param properties Display of scene object debug properties on or off. - */ - void SetTimingDisplay(bool frameRate, bool profile, bool properties); - - /** - * Returns status of timing information display. - * \param frameRate Display for frame rate on or off. - * \param profile Display for individual components on or off. - * \param properties Display of scene object debug properties on or off. - */ - void GetTimingDisplay(bool& frameRate, bool& profile, bool& properties) const; - - /** - * Sets cursor hiding on every frame. - * \param hideCursor Turns hiding on or off. - */ - void SetHideCursor(bool hideCursor); + /// Allow debug armatures. + void SetShowArmatures(KX_DebugOption mode); + /// Returns the current setting for armatures debug. + KX_DebugOption GetShowArmatures() const; - /** - * Returns the current setting for cursor hiding. - * \return The current setting for cursor hiding. - */ - bool GetHideCursor(void) const; + /// Allow debug camera frustum. + void SetShowCameraFrustum(KX_DebugOption mode); + /// Returns the current setting for camera frustum debug. + KX_DebugOption GetShowCameraFrustum() const; - /** - * Enables/disables the use of the framing bar color of the Blender file's scenes. - * \param overrideFrameColor The new setting. - */ - void SetUseOverrideFrameColor(bool overrideFrameColor); + /// Allow debug light shadow frustum. + void SetShowShadowFrustum(KX_DebugOption mode); + /// Returns the current setting for light shadow frustum debug. + KX_DebugOption GetShowShadowFrustum() const; - /** - * Check if the frame color is being overridden. - */ - bool GetUseOverrideFrameColor(void) const; + KX_Scene *CreateScene(const std::string& scenename); + KX_Scene *CreateScene(Scene *scene); - /** - * Set the color used for framing bar color instead of the one in the Blender file's scenes. - * \param r Red component of the override color. - * \param g Green component of the override color. - * \param b Blue component of the override color. - */ - void SetOverrideFrameColor(float r, float g, float b, float a); - - /** - * Returns the color used for framing bar color instead of the one in the Blender file's scenes. - * \param r Red component of the override color. - * \param g Green component of the override color. - * \param b Blue component of the override color. - */ - void GetOverrideFrameColor(float& r, float& g, float& b, float& a) const; - - KX_Scene* CreateScene(const STR_String& scenename); - KX_Scene* CreateScene(Scene *scene, bool libloading=false); - - GlobalSettings* GetGlobalSettings(void); - void SetGlobalSettings(GlobalSettings* gs); + GlobalSettings *GetGlobalSettings(void); + void SetGlobalSettings(GlobalSettings *gs); /** * Invalidate all the camera matrices and handle other * needed changes when resized. * It's only called from Blenderplayer. */ - void Resize(); - -protected: - /** - * Processes all scheduled scene activity. - * At the end, if the scene lists have changed, - * SceneListsChanged(void) is called. - * \see SceneListsChanged(void). - */ - void ProcessScheduledScenes(void); - - /** - * This method is invoked when the scene lists have changed. - */ - - void RemoveScheduledScenes(void); - void AddScheduledScenes(void); - void ReplaceScheduledScenes(void); - void PostProcessScene(class KX_Scene* scene); - - bool BeginFrame(); - void ClearFrame(); - void EndFrame(); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_KetsjiEngine") -#endif + void Resize(); }; #endif /* __KX_KETSJIENGINE_H__ */ diff --git a/source/gameengine/Ketsji/KX_LibLoadStatus.cpp b/source/gameengine/Ketsji/KX_LibLoadStatus.cpp new file mode 100644 index 000000000000..dca8f19ff905 --- /dev/null +++ b/source/gameengine/Ketsji/KX_LibLoadStatus.cpp @@ -0,0 +1,231 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Mitchell Stokes + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file KX_LibLoadStatus.cpp + * \ingroup bgeconv + */ + +#include "KX_LibLoadStatus.h" + +#include "EXP_PythonCallBack.h" + +#include "PIL_time.h" + +KX_LibLoadStatus::KX_LibLoadStatus(BL_Converter *converter, KX_KetsjiEngine *engine, KX_Scene *merge_scene, const std::string& path) + :m_converter(converter), + m_engine(engine), + m_mergescene(merge_scene), + m_libname(path), + m_progress(0.0f), + m_finished(false) +#ifdef WITH_PYTHON + , + m_finish_cb(nullptr), + m_progress_cb(nullptr) +#endif +{ + m_endtime = m_starttime = PIL_check_seconds_timer(); +} + +void KX_LibLoadStatus::Finish() +{ + m_finished = true; + m_progress = 1.f; + m_endtime = PIL_check_seconds_timer(); + + RunFinishCallback(); + RunProgressCallback(); +} + +void KX_LibLoadStatus::RunFinishCallback() +{ +#ifdef WITH_PYTHON + if (m_finish_cb) { + PyObject *args[] = {GetProxy()}; + + EXP_RunPythonCallback(m_finish_cb, args, 0, 1); + + Py_DECREF(args[0]); + } +#endif +} + +void KX_LibLoadStatus::RunProgressCallback() +{ +} + +BL_Converter *KX_LibLoadStatus::GetConverter() const +{ + return m_converter; +} + +KX_KetsjiEngine *KX_LibLoadStatus::GetEngine() const +{ + return m_engine; +} + +KX_Scene *KX_LibLoadStatus::GetMergeScene() const +{ + return m_mergescene; +} + +std::vector& KX_LibLoadStatus::GetSceneConverters() +{ + return m_sceneConvertes; +} + +void KX_LibLoadStatus::AddSceneConverter(KX_Scene *scene, const BL_Resource::Library& libraryId) +{ + m_sceneConvertes.emplace_back(scene, libraryId); +} + +bool KX_LibLoadStatus::IsFinished() const +{ + return m_finished; +} + +void KX_LibLoadStatus::SetProgress(float progress) +{ + m_progress = progress; + RunProgressCallback(); +} + +float KX_LibLoadStatus::GetProgress() const +{ + return m_progress; +} + +void KX_LibLoadStatus::AddProgress(float progress) +{ + m_progress += progress; + RunProgressCallback(); +} + +#ifdef WITH_PYTHON + +PyMethodDef KX_LibLoadStatus::Methods[] = { + {nullptr, nullptr} // Sentinel +}; + +PyAttributeDef KX_LibLoadStatus::Attributes[] = { + EXP_PYATTRIBUTE_RW_FUNCTION("onFinish", KX_LibLoadStatus, pyattr_get_onfinish, pyattr_set_onfinish), + // EXP_PYATTRIBUTE_RW_FUNCTION("onProgress", KX_LibLoadStatus, pyattr_get_onprogress, pyattr_set_onprogress), + EXP_PYATTRIBUTE_FLOAT_RO("progress", KX_LibLoadStatus, m_progress), + EXP_PYATTRIBUTE_STRING_RO("libraryName", KX_LibLoadStatus, m_libname), + EXP_PYATTRIBUTE_RO_FUNCTION("timeTaken", KX_LibLoadStatus, pyattr_get_timetaken), + EXP_PYATTRIBUTE_BOOL_RO("finished", KX_LibLoadStatus, m_finished), + EXP_PYATTRIBUTE_NULL // Sentinel +}; + +PyTypeObject KX_LibLoadStatus::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_LibLoadStatus", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &EXP_PyObjectPlus::Type, + 0, 0, 0, 0, 0, 0, + py_base_new +}; + + +PyObject *KX_LibLoadStatus::pyattr_get_onfinish(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LibLoadStatus *self = static_cast(self_v); + + if (self->m_finish_cb) { + Py_INCREF(self->m_finish_cb); + return self->m_finish_cb; + } + + Py_RETURN_NONE; +} + +int KX_LibLoadStatus::pyattr_set_onfinish(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_LibLoadStatus *self = static_cast(self_v); + + if (!PyCallable_Check(value)) { + PyErr_SetString(PyExc_TypeError, "KX_LibLoadStatus.onFinished requires a callable object"); + return PY_SET_ATTR_FAIL; + } + + if (self->m_finish_cb) { + Py_DECREF(self->m_finish_cb); + } + + Py_INCREF(value); + self->m_finish_cb = value; + + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_LibLoadStatus::pyattr_get_onprogress(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LibLoadStatus *self = static_cast(self_v); + + if (self->m_progress_cb) { + Py_INCREF(self->m_progress_cb); + return self->m_progress_cb; + } + + Py_RETURN_NONE; +} + +int KX_LibLoadStatus::pyattr_set_onprogress(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_LibLoadStatus *self = static_cast(self_v); + + if (!PyCallable_Check(value)) { + PyErr_SetString(PyExc_TypeError, "KX_LibLoadStatus.onProgress requires a callable object"); + return PY_SET_ATTR_FAIL; + } + + if (self->m_progress_cb) { + Py_DECREF(self->m_progress_cb); + } + + Py_INCREF(value); + self->m_progress_cb = value; + + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_LibLoadStatus::pyattr_get_timetaken(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LibLoadStatus *self = static_cast(self_v); + + return PyFloat_FromDouble(self->m_endtime - self->m_starttime); +} + +#endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_LibLoadStatus.h b/source/gameengine/Ketsji/KX_LibLoadStatus.h new file mode 100644 index 000000000000..ac2528ee30e9 --- /dev/null +++ b/source/gameengine/Ketsji/KX_LibLoadStatus.h @@ -0,0 +1,90 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Mitchell Stokes + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file KX_LibLoadStatus.h + * \ingroup bgeconv + */ + +#ifndef __KX_LIBLOADSTATUS_H__ +#define __KX_LIBLOADSTATUS_H__ + +#include "EXP_PyObjectPlus.h" +#include "BL_SceneConverter.h" + +class BL_Converter; +class KX_KetsjiEngine; +class KX_Scene; + +class KX_LibLoadStatus : public EXP_PyObjectPlus +{ + Py_Header +private: + BL_Converter *m_converter; + KX_KetsjiEngine *m_engine; + KX_Scene *m_mergescene; + std::vector m_sceneConvertes; + std::string m_libname; + + float m_progress; + double m_starttime; + double m_endtime; + + /// The current status of this libload, used by the scene converter. + bool m_finished; + +#ifdef WITH_PYTHON + PyObject *m_finish_cb; + PyObject *m_progress_cb; +#endif + +public: + KX_LibLoadStatus(BL_Converter *converter, KX_KetsjiEngine *engine, KX_Scene *merge_scene, const std::string& path); + + /// Called when the libload is done. + void Finish(); + void RunFinishCallback(); + void RunProgressCallback(); + + BL_Converter *GetConverter() const; + KX_KetsjiEngine *GetEngine() const; + KX_Scene *GetMergeScene() const; + + std::vector& GetSceneConverters(); + void AddSceneConverter(KX_Scene *scene, const BL_Resource::Library& libraryId); + + bool IsFinished() const; + + void SetProgress(float progress); + float GetProgress() const; + void AddProgress(float progress); + +#ifdef WITH_PYTHON + static PyObject *pyattr_get_onfinish(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_onfinish(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_onprogress(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_onprogress(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + + static PyObject *pyattr_get_timetaken(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); +#endif +}; + +#endif // __KX_LIBLOADSTATUS_H__ diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp deleted file mode 100644 index cdef0f458d76..000000000000 --- a/source/gameengine/Ketsji/KX_Light.cpp +++ /dev/null @@ -1,488 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Ketsji/KX_Light.cpp - * \ingroup ketsji - */ - -#ifdef _MSC_VER -# pragma warning (disable:4786) -#endif - -#include - -#include "KX_Light.h" -#include "KX_Camera.h" -#include "RAS_IRasterizer.h" -#include "RAS_ICanvas.h" -#include "RAS_ILightObject.h" - -#include "KX_PyMath.h" - -#include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_lamp_types.h" - -#include "BKE_scene.h" -#include "MEM_guardedalloc.h" - -#include "BLI_math.h" - -KX_LightObject::KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks, - RAS_IRasterizer* rasterizer, - RAS_ILightObject* lightobj, - bool glsl) - : KX_GameObject(sgReplicationInfo,callbacks), - m_rasterizer(rasterizer) -{ - m_lightobj = lightobj; - m_lightobj->m_scene = sgReplicationInfo; - m_lightobj->m_light = this; - m_rasterizer->AddLight(m_lightobj); - m_lightobj->m_glsl = glsl; - m_blenderscene = ((KX_Scene*)sgReplicationInfo)->GetBlenderScene(); - m_base = NULL; -}; - - -KX_LightObject::~KX_LightObject() -{ - if (m_lightobj) { - m_rasterizer->RemoveLight(m_lightobj); - delete(m_lightobj); - } - - if (m_base) { - BKE_scene_base_unlink(m_blenderscene, m_base); - MEM_freeN(m_base); - } -} - - -CValue* KX_LightObject::GetReplica() -{ - - KX_LightObject* replica = new KX_LightObject(*this); - - replica->ProcessReplica(); - - replica->m_lightobj = m_lightobj->Clone(); - replica->m_lightobj->m_light = replica; - m_rasterizer->AddLight(replica->m_lightobj); - if (m_base) - m_base = NULL; - - return replica; -} - -void KX_LightObject::UpdateScene(KX_Scene *kxscene) -{ - m_lightobj->m_scene = (void*)kxscene; - m_blenderscene = kxscene->GetBlenderScene(); - m_base = BKE_scene_base_add(m_blenderscene, GetBlenderObject()); -} - -void KX_LightObject::SetLayer(int layer) -{ - KX_GameObject::SetLayer(layer); - m_lightobj->m_layer = layer; -} - -#ifdef WITH_PYTHON -/* ------------------------------------------------------------------------- */ -/* Python Integration Hooks */ -/* ------------------------------------------------------------------------- */ - -PyTypeObject KX_LightObject::Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "KX_LightObject", - sizeof(PyObjectPlus_Proxy), - 0, - py_base_dealloc, - 0, - 0, - 0, - 0, - py_base_repr, - 0, - &KX_GameObject::Sequence, - &KX_GameObject::Mapping, - 0,0,0, - NULL, - NULL, - 0, - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, - Methods, - 0, - 0, - &KX_GameObject::Type, - 0,0,0,0,0,0, - py_base_new -}; - -PyMethodDef KX_LightObject::Methods[] = { - {NULL,NULL} //Sentinel -}; - -PyAttributeDef KX_LightObject::Attributes[] = { - KX_PYATTRIBUTE_RW_FUNCTION("layer", KX_LightObject, pyattr_get_layer, pyattr_set_layer), - KX_PYATTRIBUTE_RW_FUNCTION("energy", KX_LightObject, pyattr_get_energy, pyattr_set_energy), - KX_PYATTRIBUTE_RW_FUNCTION("distance", KX_LightObject, pyattr_get_distance, pyattr_set_distance), - KX_PYATTRIBUTE_RW_FUNCTION("color", KX_LightObject, pyattr_get_color, pyattr_set_color), - KX_PYATTRIBUTE_RW_FUNCTION("lin_attenuation", KX_LightObject, pyattr_get_lin_attenuation, pyattr_set_lin_attenuation), - KX_PYATTRIBUTE_RW_FUNCTION("quad_attenuation", KX_LightObject, pyattr_get_quad_attenuation, pyattr_set_quad_attenuation), - KX_PYATTRIBUTE_RW_FUNCTION("spotsize", KX_LightObject, pyattr_get_spotsize, pyattr_set_spotsize), - KX_PYATTRIBUTE_RW_FUNCTION("spotblend", KX_LightObject, pyattr_get_spotblend, pyattr_set_spotblend), - KX_PYATTRIBUTE_RO_FUNCTION("shadowClipStart", KX_LightObject, pyattr_get_shadow_clip_start), - KX_PYATTRIBUTE_RO_FUNCTION("shadowClipEnd", KX_LightObject, pyattr_get_shadow_clip_end), - KX_PYATTRIBUTE_RO_FUNCTION("shadowFrustumSize", KX_LightObject, pyattr_get_shadow_frustum_size), - KX_PYATTRIBUTE_RO_FUNCTION("shadowBias", KX_LightObject, pyattr_get_shadow_bias), - KX_PYATTRIBUTE_RO_FUNCTION("shadowBleedBias", KX_LightObject, pyattr_get_shadow_bleed_bias), - KX_PYATTRIBUTE_RO_FUNCTION("shadowBindId", KX_LightObject, pyattr_get_shadow_bind_code), - KX_PYATTRIBUTE_RO_FUNCTION("shadowMapType", KX_LightObject, pyattr_get_shadow_map_type), - KX_PYATTRIBUTE_RO_FUNCTION("shadowColor", KX_LightObject, pyattr_get_shadow_color), - KX_PYATTRIBUTE_RO_FUNCTION("useShadow", KX_LightObject, pyattr_get_shadow_active), - KX_PYATTRIBUTE_RO_FUNCTION("shadowMatrix", KX_LightObject, pyattr_get_shadow_matrix), - KX_PYATTRIBUTE_RO_FUNCTION("SPOT", KX_LightObject, pyattr_get_typeconst), - KX_PYATTRIBUTE_RO_FUNCTION("SUN", KX_LightObject, pyattr_get_typeconst), - KX_PYATTRIBUTE_RO_FUNCTION("NORMAL", KX_LightObject, pyattr_get_typeconst), - KX_PYATTRIBUTE_RW_FUNCTION("type", KX_LightObject, pyattr_get_type, pyattr_set_type), - { NULL } //Sentinel -}; - -PyObject *KX_LightObject::pyattr_get_layer(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LightObject *self = static_cast(self_v); - return PyLong_FromLong(self->m_lightobj->m_layer); -} - -int KX_LightObject::pyattr_set_layer(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) -{ - KX_LightObject *self = static_cast(self_v); - int layer = PyLong_AsLong(value); - - if (layer == -1 && PyErr_Occurred()) { - PyErr_Format(PyExc_TypeError, "expected an integer for attribute \"%s\"", attrdef->m_name); - return PY_SET_ATTR_FAIL; - } - - if (layer < 1) { - PyErr_Format(PyExc_TypeError, "expected an integer greater than 1 for attribute \"%s\"", attrdef->m_name); - return PY_SET_ATTR_FAIL; - } - else if (layer > MAX_LIGHT_LAYERS) { - PyErr_Format(PyExc_TypeError, "expected an integer less than %i for attribute \"%s\"", MAX_LIGHT_LAYERS, attrdef->m_name); - return PY_SET_ATTR_FAIL; - } - - self->SetLayer(layer); - return PY_SET_ATTR_SUCCESS; -} - -PyObject *KX_LightObject::pyattr_get_energy(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LightObject* self = static_cast(self_v); - return PyFloat_FromDouble(self->m_lightobj->m_energy); -} - -int KX_LightObject::pyattr_set_energy(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) -{ - KX_LightObject* self = static_cast(self_v); - - if (PyFloat_Check(value)) { - float val = PyFloat_AsDouble(value); - if (val < 0) - val = 0; - else if (val > 10) - val = 10; - - self->m_lightobj->m_energy = val; - return PY_SET_ATTR_SUCCESS; - } - - PyErr_Format(PyExc_TypeError, "expected float value for attribute \"%s\"", attrdef->m_name); - return PY_SET_ATTR_FAIL; -} - -PyObject *KX_LightObject::pyattr_get_shadow_clip_start(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LightObject *self = static_cast(self_v); - return PyFloat_FromDouble(self->m_lightobj->m_shadowclipstart); -} - -PyObject *KX_LightObject::pyattr_get_shadow_clip_end(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LightObject *self = static_cast(self_v); - return PyFloat_FromDouble(self->m_lightobj->m_shadowclipend); -} - -PyObject *KX_LightObject::pyattr_get_shadow_frustum_size(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LightObject *self = static_cast(self_v); - return PyFloat_FromDouble(self->m_lightobj->m_shadowfrustumsize); -} - -PyObject *KX_LightObject::pyattr_get_shadow_bind_code(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LightObject *self = static_cast(self_v); - return PyLong_FromLong(self->m_lightobj->GetShadowBindCode()); -} - -PyObject *KX_LightObject::pyattr_get_shadow_bias(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LightObject *self = static_cast(self_v); - return PyFloat_FromDouble(self->m_lightobj->m_shadowbias); -} - -PyObject *KX_LightObject::pyattr_get_shadow_bleed_bias(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LightObject *self = static_cast(self_v); - return PyFloat_FromDouble(self->m_lightobj->m_shadowbleedbias); -} - -PyObject *KX_LightObject::pyattr_get_shadow_map_type(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LightObject *self = static_cast(self_v); - return PyLong_FromLong(self->m_lightobj->m_shadowmaptype); -} - -PyObject *KX_LightObject::pyattr_get_shadow_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LightObject *self = static_cast(self_v); - return PyObjectFrom(self->m_lightobj->GetShadowMatrix()); -} - -PyObject *KX_LightObject::pyattr_get_shadow_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LightObject *self = static_cast(self_v); - return PyColorFromVector(MT_Vector3(self->m_lightobj->m_shadowcolor)); -} - -PyObject *KX_LightObject::pyattr_get_shadow_active(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LightObject *self = static_cast(self_v); - return PyBool_FromLong(self->m_lightobj->HasShadowBuffer()); -} - -PyObject *KX_LightObject::pyattr_get_distance(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LightObject* self = static_cast(self_v); - return PyFloat_FromDouble(self->m_lightobj->m_distance); -} - -int KX_LightObject::pyattr_set_distance(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) -{ - KX_LightObject* self = static_cast(self_v); - - if (PyFloat_Check(value)) { - float val = PyFloat_AsDouble(value); - if (val < 0.01f) - val = 0.01f; - else if (val > 5000.f) - val = 5000.f; - - self->m_lightobj->m_distance = val; - return PY_SET_ATTR_SUCCESS; - } - - PyErr_Format(PyExc_TypeError, "expected float value for attribute \"%s\"", attrdef->m_name); - return PY_SET_ATTR_FAIL; -} - -PyObject *KX_LightObject::pyattr_get_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LightObject* self = static_cast(self_v); - return Py_BuildValue("[fff]", self->m_lightobj->m_color[0], self->m_lightobj->m_color[1], self->m_lightobj->m_color[2]); -} - -int KX_LightObject::pyattr_set_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) -{ - KX_LightObject* self = static_cast(self_v); - - MT_Vector3 color; - if (PyVecTo(value, color)) - { - self->m_lightobj->m_color[0] = color[0]; - self->m_lightobj->m_color[1] = color[1]; - self->m_lightobj->m_color[2] = color[2]; - return PY_SET_ATTR_SUCCESS; - } - return PY_SET_ATTR_FAIL; -} - -PyObject *KX_LightObject::pyattr_get_lin_attenuation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LightObject* self = static_cast(self_v); - return PyFloat_FromDouble(self->m_lightobj->m_att1); -} - -int KX_LightObject::pyattr_set_lin_attenuation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) -{ - KX_LightObject* self = static_cast(self_v); - - if (PyFloat_Check(value)) { - float val = PyFloat_AsDouble(value); - if (val < 0.f) - val = 0.f; - else if (val > 1.f) - val = 1.f; - - self->m_lightobj->m_att1 = val; - return PY_SET_ATTR_SUCCESS; - } - - PyErr_Format(PyExc_TypeError, "expected float value for attribute \"%s\"", attrdef->m_name); - return PY_SET_ATTR_FAIL; -} - -PyObject *KX_LightObject::pyattr_get_quad_attenuation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LightObject* self = static_cast(self_v); - return PyFloat_FromDouble(self->m_lightobj->m_att2); -} - -int KX_LightObject::pyattr_set_quad_attenuation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) -{ - KX_LightObject* self = static_cast(self_v); - - if (PyFloat_Check(value)) { - float val = PyFloat_AsDouble(value); - if (val < 0.f) - val = 0.f; - else if (val > 1.f) - val = 1.f; - - self->m_lightobj->m_att2 = val; - return PY_SET_ATTR_SUCCESS; - } - - PyErr_Format(PyExc_TypeError, "expected float value for attribute \"%s\"", attrdef->m_name); - return PY_SET_ATTR_FAIL; -} - -PyObject *KX_LightObject::pyattr_get_spotsize(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LightObject* self = static_cast(self_v); - return PyFloat_FromDouble(RAD2DEG(self->m_lightobj->m_spotsize)); -} - -int KX_LightObject::pyattr_set_spotsize(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) -{ - KX_LightObject* self = static_cast(self_v); - - if (PyFloat_Check(value)) { - double val = PyFloat_AsDouble(value); - if (val < 0.0) - val = 0.0; - else if (val > 180.0) - val = 180.0; - - self->m_lightobj->m_spotsize = (float)DEG2RAD(val); - return PY_SET_ATTR_SUCCESS; - } - - PyErr_Format(PyExc_TypeError, "expected float value for attribute \"%s\"", attrdef->m_name); - return PY_SET_ATTR_FAIL; -} -PyObject *KX_LightObject::pyattr_get_spotblend(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LightObject* self = static_cast(self_v); - return PyFloat_FromDouble(self->m_lightobj->m_spotblend); -} - -int KX_LightObject::pyattr_set_spotblend(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) -{ - KX_LightObject* self = static_cast(self_v); - - if (PyFloat_Check(value)) { - float val = (float)PyFloat_AsDouble(value); - if (val < 0.f) - val = 0.f; - else if (val > 1.f) - val = 1.f; - - self->m_lightobj->m_spotblend = val; - return PY_SET_ATTR_SUCCESS; - } - - PyErr_Format(PyExc_TypeError, "expected float value for attribute \"%s\"", attrdef->m_name); - return PY_SET_ATTR_FAIL; -} - -PyObject *KX_LightObject::pyattr_get_typeconst(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - PyObject *retvalue; - - const char* type = attrdef->m_name; - - if (!strcmp(type, "SPOT")) { - retvalue = PyLong_FromLong(RAS_ILightObject::LIGHT_SPOT); - } else if (!strcmp(type, "SUN")) { - retvalue = PyLong_FromLong(RAS_ILightObject::LIGHT_SUN); - } else if (!strcmp(type, "NORMAL")) { - retvalue = PyLong_FromLong(RAS_ILightObject::LIGHT_NORMAL); - } - else { - /* should never happen */ - PyErr_SetString(PyExc_TypeError, "light.type: internal error, invalid light type"); - retvalue = NULL; - } - - return retvalue; -} - -PyObject *KX_LightObject::pyattr_get_type(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_LightObject* self = static_cast(self_v); - return PyLong_FromLong(self->m_lightobj->m_type); -} - -int KX_LightObject::pyattr_set_type(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) -{ - KX_LightObject* self = static_cast(self_v); - const int val = PyLong_AsLong(value); - if ((val==-1 && PyErr_Occurred()) || val<0 || val>2) { - PyErr_SetString(PyExc_ValueError, "light.type= val: KX_LightObject, expected an int between 0 and 2"); - return PY_SET_ATTR_FAIL; - } - - switch (val) { - case 0: - self->m_lightobj->m_type = self->m_lightobj->LIGHT_SPOT; - break; - case 1: - self->m_lightobj->m_type = self->m_lightobj->LIGHT_SUN; - break; - case 2: - self->m_lightobj->m_type = self->m_lightobj->LIGHT_NORMAL; - break; - } - - return PY_SET_ATTR_SUCCESS; -} -#endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_Light.h b/source/gameengine/Ketsji/KX_Light.h deleted file mode 100644 index 21c68cb93175..000000000000 --- a/source/gameengine/Ketsji/KX_Light.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file KX_Light.h - * \ingroup ketsji - */ - -#ifndef __KX_LIGHT_H__ -#define __KX_LIGHT_H__ - -#include "KX_GameObject.h" - -#define MAX_LIGHT_LAYERS ((1 << 20) - 1) - -struct GPULamp; -struct Scene; -struct Base; -class KX_Camera; -class RAS_IRasterizer; -class RAS_ILightObject; -class MT_Transform; - -class KX_LightObject : public KX_GameObject -{ - Py_Header -protected: - RAS_ILightObject* m_lightobj; - class RAS_IRasterizer* m_rasterizer; //needed for registering and replication of lightobj - Scene* m_blenderscene; - Base* m_base; - -public: - KX_LightObject(void* sgReplicationInfo,SG_Callbacks callbacks,RAS_IRasterizer* rasterizer,RAS_ILightObject* lightobj, bool glsl); - virtual ~KX_LightObject(); - virtual CValue* GetReplica(); - RAS_ILightObject* GetLightData() { return m_lightobj;} - - void UpdateScene(class KX_Scene *kxscene); - virtual void SetLayer(int layer); - - virtual int GetGameObjectType() { return OBJ_LIGHT; } - -#ifdef WITH_PYTHON - /* attributes */ - static PyObject* pyattr_get_layer(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_layer(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_energy(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_energy(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject *pyattr_get_shadow_clip_start(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_shadow_clip_end(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_shadow_frustum_size(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_shadow_bind_code(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_shadow_bias(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_shadow_bleed_bias(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_shadow_map_type(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_shadow_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_shadow_active(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_shadow_matrix(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_distance(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_distance(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_color(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_color(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_lin_attenuation(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_lin_attenuation(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_quad_attenuation(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_quad_attenuation(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_spotsize(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_spotsize(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_spotblend(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_spotblend(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_typeconst(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_type(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_type(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); -#endif -}; - -#endif /* __KX_LIGHT_H__ */ diff --git a/source/gameengine/Ketsji/KX_LightIpoSGController.cpp b/source/gameengine/Ketsji/KX_LightIpoSGController.cpp index 70efa9b50c1a..bf0496abcf40 100644 --- a/source/gameengine/Ketsji/KX_LightIpoSGController.cpp +++ b/source/gameengine/Ketsji/KX_LightIpoSGController.cpp @@ -31,92 +31,29 @@ #include "KX_LightIpoSGController.h" -#include "KX_ScalarInterpolator.h" -#include "KX_Light.h" +#include "KX_LightObject.h" #include "RAS_ILightObject.h" -#if defined(_WIN64) -typedef unsigned __int64 uint_ptr; -#else -typedef unsigned long uint_ptr; -#endif - -bool KX_LightIpoSGController::Update(double currentTime) +bool KX_LightIpoSGController::Update(SG_Node *node) { - if (m_modified) - { - T_InterpolatorList::iterator i; - for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) { - (*i)->Execute(m_ipotime);//currentTime); - } - - RAS_ILightObject *lightobj; - - SG_Spatial* ob = (SG_Spatial*)m_pObject; - KX_LightObject* kxlight = (KX_LightObject*) ob->GetSGClientObject(); - lightobj = kxlight->GetLightData(); - //lightobj = (KX_Light*) - - if (m_modify_energy) { - lightobj->m_energy = m_energy; - } - - if (m_modify_color) { - lightobj->m_color[0] = m_col_rgb[0]; - lightobj->m_color[1] = m_col_rgb[1]; - lightobj->m_color[2] = m_col_rgb[2]; - } - - if (m_modify_dist) { - lightobj->m_distance = m_dist; - } - - m_modified=false; + if (!SG_Controller::Update(node)) { + return false; } - return false; -} - - -void KX_LightIpoSGController::AddInterpolator(KX_IInterpolator* interp) -{ - this->m_interpolators.push_back(interp); -} - -SG_Controller* KX_LightIpoSGController::GetReplica(class SG_Node* destnode) -{ - KX_LightIpoSGController* iporeplica = new KX_LightIpoSGController(*this); - // clear object that ipo acts on - iporeplica->ClearObject(); - - // dirty hack, ask Gino for a better solution in the ipo implementation - // hacken en zagen, in what we call datahiding, not written for replication :( - T_InterpolatorList oldlist = m_interpolators; - iporeplica->m_interpolators.clear(); + KX_LightObject *kxlight = static_cast(node->GetClientObject()); + RAS_ILightObject *lightobj = kxlight->GetLightData(); - T_InterpolatorList::iterator i; - for (i = oldlist.begin(); !(i == oldlist.end()); ++i) { - KX_ScalarInterpolator* copyipo = new KX_ScalarInterpolator(*((KX_ScalarInterpolator*)*i)); - iporeplica->AddInterpolator(copyipo); - - MT_Scalar* scaal = ((KX_ScalarInterpolator*)*i)->GetTarget(); - uint_ptr orgbase = (uint_ptr)this; - uint_ptr orgloc = (uint_ptr)scaal; - uint_ptr offset = orgloc-orgbase; - uint_ptr newaddrbase = (uint_ptr)iporeplica + offset; - MT_Scalar* blaptr = (MT_Scalar*) newaddrbase; - copyipo->SetNewTarget((MT_Scalar*)blaptr); + if (m_modify_energy) { + lightobj->m_energy = m_energy; } - return iporeplica; -} - -KX_LightIpoSGController::~KX_LightIpoSGController() -{ + if (m_modify_color) { + lightobj->m_color = m_col_rgb; + } - T_InterpolatorList::iterator i; - for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) { - delete (*i); + if (m_modify_dist) { + lightobj->m_distance = m_dist; } + return true; } diff --git a/source/gameengine/Ketsji/KX_LightIpoSGController.h b/source/gameengine/Ketsji/KX_LightIpoSGController.h index 151dfcd5abd9..1cba294f9e1a 100644 --- a/source/gameengine/Ketsji/KX_LightIpoSGController.h +++ b/source/gameengine/Ketsji/KX_LightIpoSGController.h @@ -33,46 +33,34 @@ #define __KX_LIGHTIPOSGCONTROLLER_H__ #include "SG_Controller.h" -#include "SG_Spatial.h" +#include "SG_Node.h" -#include "KX_IInterpolator.h" +#include "SG_Interpolator.h" class RAS_ILightObject; class KX_LightIpoSGController : public SG_Controller { public: - MT_Scalar m_energy; - MT_Scalar m_col_rgb[3]; - MT_Scalar m_dist; + float m_energy; + mt::vec3 m_col_rgb; + float m_dist; private: - T_InterpolatorList m_interpolators; unsigned short m_modify_energy : 1; unsigned short m_modify_color : 1; unsigned short m_modify_dist : 1; - bool m_modified; - double m_ipotime; public: - KX_LightIpoSGController() : + KX_LightIpoSGController() : m_modify_energy(false), m_modify_color(false), - m_modify_dist(false), - m_modified(true), - m_ipotime(0.0) + m_modify_dist(false) {} - virtual ~KX_LightIpoSGController(); + virtual ~KX_LightIpoSGController() = default; - virtual SG_Controller* GetReplica(class SG_Node* destnode); - - virtual bool Update(double time); - - virtual void SetSimulatedTime(double time) { - m_ipotime = time; - m_modified = true; - } + virtual bool Update(SG_Node *node); void SetModifyEnergy(bool modify) { m_modify_energy = modify; @@ -85,21 +73,6 @@ class KX_LightIpoSGController : public SG_Controller void SetModifyDist(bool modify) { m_modify_dist = modify; } - - void - SetOption( - int option, - int value - ) { - // intentionally empty - }; - - void AddInterpolator(KX_IInterpolator* interp); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_LightIpoSGController") -#endif }; #endif /* __KX_LIGHTIPOSGCONTROLLER_H__ */ diff --git a/source/gameengine/Ketsji/KX_LightObject.cpp b/source/gameengine/Ketsji/KX_LightObject.cpp new file mode 100644 index 000000000000..1c6bca4b3f09 --- /dev/null +++ b/source/gameengine/Ketsji/KX_LightObject.cpp @@ -0,0 +1,523 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Ketsji/KX_LightObject.cpp + * \ingroup ketsji + */ + +#ifdef _MSC_VER +# pragma warning (disable:4786) +#endif + +#include + +#include "KX_LightObject.h" +#include "KX_Camera.h" +#include "RAS_Rasterizer.h" +#include "RAS_ICanvas.h" +#include "RAS_ILightObject.h" + +#include "KX_PyMath.h" + +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_lamp_types.h" + +#include "BKE_scene.h" +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" + +KX_LightObject::KX_LightObject(void *sgReplicationInfo, SG_Callbacks callbacks, + RAS_Rasterizer *rasterizer, + RAS_ILightObject *lightobj) + :KX_GameObject(sgReplicationInfo, callbacks), + m_rasterizer(rasterizer), + m_showShadowFrustum(false) +{ + m_lightobj = lightobj; + m_lightobj->m_scene = sgReplicationInfo; + m_lightobj->m_light = this; + m_rasterizer->AddLight(m_lightobj); + m_blenderscene = ((KX_Scene *)sgReplicationInfo)->GetBlenderScene(); + m_base = nullptr; +} + +KX_LightObject::~KX_LightObject() +{ + if (m_lightobj) { + m_rasterizer->RemoveLight(m_lightobj); + delete(m_lightobj); + } + + if (m_base) { + BKE_scene_base_unlink(m_blenderscene, m_base); + MEM_freeN(m_base); + } +} + +EXP_Value *KX_LightObject::GetReplica() +{ + KX_LightObject *replica = new KX_LightObject(*this); + + replica->ProcessReplica(); + + replica->m_lightobj = m_lightobj->Clone(); + replica->m_lightobj->m_light = replica; + m_rasterizer->AddLight(replica->m_lightobj); + if (m_base) { + m_base = nullptr; + } + + return replica; +} + +bool KX_LightObject::GetShowShadowFrustum() const +{ + return m_showShadowFrustum; +} + +void KX_LightObject::SetShowShadowFrustum(bool show) +{ + m_showShadowFrustum = show; +} + +void KX_LightObject::Update() +{ + m_lightobj->Update(NodeGetWorldTransform(), !m_bVisible); +} + +void KX_LightObject::UpdateScene(KX_Scene *kxscene) +{ + m_lightobj->m_scene = (void *)kxscene; + m_blenderscene = kxscene->GetBlenderScene(); + m_base = BKE_scene_base_add(m_blenderscene, GetBlenderObject()); +} + +void KX_LightObject::SetLayer(int layer) +{ + KX_GameObject::SetLayer(layer); + m_lightobj->m_layer = layer; +} + +#ifdef WITH_PYTHON +/* ------------------------------------------------------------------------- */ +/* Python Integration Hooks */ +/* ------------------------------------------------------------------------- */ + +PyTypeObject KX_LightObject::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_LightObject", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, + &KX_GameObject::Sequence, + &KX_GameObject::Mapping, + 0, 0, 0, + nullptr, + nullptr, + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &KX_GameObject::Type, + 0, 0, 0, 0, 0, 0, + py_base_new +}; + +PyMethodDef KX_LightObject::Methods[] = { + EXP_PYMETHODTABLE_NOARGS(KX_LightObject, updateShadow), + {nullptr, nullptr} // Sentinel +}; + +PyAttributeDef KX_LightObject::Attributes[] = { + EXP_PYATTRIBUTE_RW_FUNCTION("energy", KX_LightObject, pyattr_get_energy, pyattr_set_energy), + EXP_PYATTRIBUTE_RW_FUNCTION("distance", KX_LightObject, pyattr_get_distance, pyattr_set_distance), + EXP_PYATTRIBUTE_RW_FUNCTION("color", KX_LightObject, pyattr_get_color, pyattr_set_color), + EXP_PYATTRIBUTE_RW_FUNCTION("lin_attenuation", KX_LightObject, pyattr_get_lin_attenuation, pyattr_set_lin_attenuation), + EXP_PYATTRIBUTE_RW_FUNCTION("quad_attenuation", KX_LightObject, pyattr_get_quad_attenuation, pyattr_set_quad_attenuation), + EXP_PYATTRIBUTE_RW_FUNCTION("spotsize", KX_LightObject, pyattr_get_spotsize, pyattr_set_spotsize), + EXP_PYATTRIBUTE_RW_FUNCTION("spotblend", KX_LightObject, pyattr_get_spotblend, pyattr_set_spotblend), + EXP_PYATTRIBUTE_RO_FUNCTION("shadowClipStart", KX_LightObject, pyattr_get_shadow_clip_start), + EXP_PYATTRIBUTE_RO_FUNCTION("shadowClipEnd", KX_LightObject, pyattr_get_shadow_clip_end), + EXP_PYATTRIBUTE_RO_FUNCTION("shadowFrustumSize", KX_LightObject, pyattr_get_shadow_frustum_size), + EXP_PYATTRIBUTE_RO_FUNCTION("shadowBias", KX_LightObject, pyattr_get_shadow_bias), + EXP_PYATTRIBUTE_RO_FUNCTION("shadowBleedBias", KX_LightObject, pyattr_get_shadow_bleed_bias), + EXP_PYATTRIBUTE_RO_FUNCTION("shadowBindId", KX_LightObject, pyattr_get_shadow_bind_code), + EXP_PYATTRIBUTE_RO_FUNCTION("shadowMapType", KX_LightObject, pyattr_get_shadow_map_type), + EXP_PYATTRIBUTE_RO_FUNCTION("shadowColor", KX_LightObject, pyattr_get_shadow_color), + EXP_PYATTRIBUTE_RO_FUNCTION("useShadow", KX_LightObject, pyattr_get_shadow_active), + EXP_PYATTRIBUTE_RO_FUNCTION("shadowMatrix", KX_LightObject, pyattr_get_shadow_matrix), + EXP_PYATTRIBUTE_RO_FUNCTION("SPOT", KX_LightObject, pyattr_get_typeconst), + EXP_PYATTRIBUTE_RO_FUNCTION("SUN", KX_LightObject, pyattr_get_typeconst), + EXP_PYATTRIBUTE_RO_FUNCTION("NORMAL", KX_LightObject, pyattr_get_typeconst), + EXP_PYATTRIBUTE_RO_FUNCTION("HEMI", KX_LightObject, pyattr_get_typeconst), + EXP_PYATTRIBUTE_RW_FUNCTION("type", KX_LightObject, pyattr_get_type, pyattr_set_type), + EXP_PYATTRIBUTE_RW_FUNCTION("staticShadow", KX_LightObject, pyattr_get_static_shadow, pyattr_set_static_shadow), + EXP_PYATTRIBUTE_NULL // Sentinel +}; + +EXP_PYMETHODDEF_DOC_NOARGS(KX_LightObject, updateShadow, "updateShadow(): Set the shadow to be updated next frame if the lamp uses a static shadow.\n") +{ + m_lightobj->m_requestShadowUpdate = true; + Py_RETURN_NONE; +} + +PyObject *KX_LightObject::pyattr_get_energy(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_lightobj->m_energy); +} + +int KX_LightObject::pyattr_set_energy(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_LightObject *self = static_cast(self_v); + + if (PyFloat_Check(value)) { + float val = PyFloat_AsDouble(value); + if (val < 0) { + val = 0; + } + else if (val > 10) { + val = 10; + } + + self->m_lightobj->m_energy = val; + return PY_SET_ATTR_SUCCESS; + } + + PyErr_Format(PyExc_TypeError, "expected float value for attribute \"%s\"", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; +} + +PyObject *KX_LightObject::pyattr_get_shadow_clip_start(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_lightobj->m_shadowclipstart); +} + +PyObject *KX_LightObject::pyattr_get_shadow_clip_end(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_lightobj->m_shadowclipend); +} + +PyObject *KX_LightObject::pyattr_get_shadow_frustum_size(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_lightobj->m_shadowfrustumsize); +} + +PyObject *KX_LightObject::pyattr_get_shadow_bind_code(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject *self = static_cast(self_v); + return PyLong_FromLong(self->m_lightobj->GetShadowBindCode()); +} + +PyObject *KX_LightObject::pyattr_get_shadow_bias(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_lightobj->m_shadowbias); +} + +PyObject *KX_LightObject::pyattr_get_shadow_bleed_bias(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_lightobj->m_shadowbleedbias); +} + +PyObject *KX_LightObject::pyattr_get_shadow_map_type(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject *self = static_cast(self_v); + return PyLong_FromLong(self->m_lightobj->m_shadowmaptype); +} + +PyObject *KX_LightObject::pyattr_get_shadow_matrix(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject *self = static_cast(self_v); + return PyObjectFrom(self->m_lightobj->GetShadowMatrix()); +} + +PyObject *KX_LightObject::pyattr_get_shadow_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject *self = static_cast(self_v); + return PyColorFromVector(self->m_lightobj->m_shadowcolor); +} + +PyObject *KX_LightObject::pyattr_get_shadow_active(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject *self = static_cast(self_v); + return PyBool_FromLong(self->m_lightobj->HasShadowBuffer()); +} + +PyObject *KX_LightObject::pyattr_get_distance(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_lightobj->m_distance); +} + +int KX_LightObject::pyattr_set_distance(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_LightObject *self = static_cast(self_v); + + if (PyFloat_Check(value)) { + float val = PyFloat_AsDouble(value); + if (val < 0.01f) { + val = 0.01f; + } + else if (val > 5000.f) { + val = 5000.f; + } + + self->m_lightobj->m_distance = val; + return PY_SET_ATTR_SUCCESS; + } + + PyErr_Format(PyExc_TypeError, "expected float value for attribute \"%s\"", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; +} + +PyObject *KX_LightObject::pyattr_get_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject *self = static_cast(self_v); + return PyColorFromVector(self->m_lightobj->m_color); +} + +int KX_LightObject::pyattr_set_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_LightObject *self = static_cast(self_v); + + mt::vec3 color; + if (PyVecTo(value, color)) { + self->m_lightobj->m_color = color; + return PY_SET_ATTR_SUCCESS; + } + return PY_SET_ATTR_FAIL; +} + +PyObject *KX_LightObject::pyattr_get_lin_attenuation(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_lightobj->m_att1); +} + +int KX_LightObject::pyattr_set_lin_attenuation(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_LightObject *self = static_cast(self_v); + + if (PyFloat_Check(value)) { + float val = PyFloat_AsDouble(value); + if (val < 0.f) { + val = 0.f; + } + else if (val > 1.f) { + val = 1.f; + } + + self->m_lightobj->m_att1 = val; + return PY_SET_ATTR_SUCCESS; + } + + PyErr_Format(PyExc_TypeError, "expected float value for attribute \"%s\"", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; +} + +PyObject *KX_LightObject::pyattr_get_quad_attenuation(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_lightobj->m_att2); +} + +int KX_LightObject::pyattr_set_quad_attenuation(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_LightObject *self = static_cast(self_v); + + if (PyFloat_Check(value)) { + float val = PyFloat_AsDouble(value); + if (val < 0.f) { + val = 0.f; + } + else if (val > 1.f) { + val = 1.f; + } + + self->m_lightobj->m_att2 = val; + return PY_SET_ATTR_SUCCESS; + } + + PyErr_Format(PyExc_TypeError, "expected float value for attribute \"%s\"", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; +} + +PyObject *KX_LightObject::pyattr_get_spotsize(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject *self = static_cast(self_v); + return PyFloat_FromDouble(RAD2DEG(self->m_lightobj->m_spotsize)); +} + +int KX_LightObject::pyattr_set_spotsize(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_LightObject *self = static_cast(self_v); + + if (PyFloat_Check(value)) { + double val = PyFloat_AsDouble(value); + if (val < 0.0) { + val = 0.0; + } + else if (val > 180.0) { + val = 180.0; + } + + self->m_lightobj->m_spotsize = (float)DEG2RAD(val); + return PY_SET_ATTR_SUCCESS; + } + + PyErr_Format(PyExc_TypeError, "expected float value for attribute \"%s\"", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; +} +PyObject *KX_LightObject::pyattr_get_spotblend(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_lightobj->m_spotblend); +} + +int KX_LightObject::pyattr_set_spotblend(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_LightObject *self = static_cast(self_v); + + if (PyFloat_Check(value)) { + float val = (float)PyFloat_AsDouble(value); + if (val < 0.f) { + val = 0.f; + } + else if (val > 1.f) { + val = 1.f; + } + + self->m_lightobj->m_spotblend = val; + return PY_SET_ATTR_SUCCESS; + } + + PyErr_Format(PyExc_TypeError, "expected float value for attribute \"%s\"", attrdef->m_name.c_str()); + return PY_SET_ATTR_FAIL; +} + +PyObject *KX_LightObject::pyattr_get_typeconst(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + PyObject *retvalue; + + const std::string& type = attrdef->m_name; + + if (type == "SPOT") { + retvalue = PyLong_FromLong(RAS_ILightObject::LIGHT_SPOT); + } + else if (type == "SUN") { + retvalue = PyLong_FromLong(RAS_ILightObject::LIGHT_SUN); + } + else if (type == "NORMAL") { + retvalue = PyLong_FromLong(RAS_ILightObject::LIGHT_NORMAL); + } + else if (type == "HEMI") { + retvalue = PyLong_FromLong(RAS_ILightObject::LIGHT_HEMI); + } + else { + /* should never happen */ + PyErr_SetString(PyExc_TypeError, "light.type: internal error, invalid light type"); + retvalue = nullptr; + } + + return retvalue; +} + +PyObject *KX_LightObject::pyattr_get_type(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject *self = static_cast(self_v); + return PyLong_FromLong(self->m_lightobj->m_type); +} + +int KX_LightObject::pyattr_set_type(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_LightObject *self = static_cast(self_v); + const int val = PyLong_AsLong(value); + if ((val == -1 && PyErr_Occurred()) || val < 0 || val > 3) { + PyErr_SetString(PyExc_ValueError, "light.type= val: KX_LightObject, expected an int between 0 and 2"); + return PY_SET_ATTR_FAIL; + } + + switch (val) { + case 0: + { + self->m_lightobj->m_type = self->m_lightobj->LIGHT_SPOT; + break; + } + case 1: + { + self->m_lightobj->m_type = self->m_lightobj->LIGHT_SUN; + break; + } + case 2: + { + self->m_lightobj->m_type = self->m_lightobj->LIGHT_NORMAL; + break; + } + case 3: + { + self->m_lightobj->m_type = self->m_lightobj->LIGHT_HEMI; + break; + } + } + + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_LightObject::pyattr_get_static_shadow(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LightObject *self = static_cast(self_v); + return PyBool_FromLong(self->m_lightobj->m_staticShadow); +} + +int KX_LightObject::pyattr_set_static_shadow(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_LightObject *self = static_cast(self_v); + int param = PyObject_IsTrue(value); + if (param == -1) { + PyErr_SetString(PyExc_AttributeError, "light.staticShadow = val: KX_LightObject, expected True or False"); + return PY_SET_ATTR_FAIL; + } + + self->m_lightobj->m_staticShadow = param; + return PY_SET_ATTR_SUCCESS; +} +#endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_LightObject.h b/source/gameengine/Ketsji/KX_LightObject.h new file mode 100644 index 000000000000..8b54e9bc7407 --- /dev/null +++ b/source/gameengine/Ketsji/KX_LightObject.h @@ -0,0 +1,118 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file KX_LightObject.h + * \ingroup ketsji + */ + +#ifndef __KX_LIGHT_H__ +#define __KX_LIGHT_H__ + +#include "KX_GameObject.h" + +struct GPULamp; +struct Scene; +struct Base; +class KX_Scene; +class KX_Camera; +class RAS_Rasterizer; +class RAS_ILightObject; + +class KX_LightObject : public KX_GameObject +{ + Py_Header +protected: + RAS_ILightObject *m_lightobj; + /// Needed for registering and replication of lightobj. + RAS_Rasterizer *m_rasterizer; + Scene *m_blenderscene; + Base *m_base; + + bool m_showShadowFrustum; + +public: + KX_LightObject(void *sgReplicationInfo, SG_Callbacks callbacks, RAS_Rasterizer *rasterizer, RAS_ILightObject *lightobj); + virtual ~KX_LightObject(); + + virtual EXP_Value *GetReplica(); + RAS_ILightObject *GetLightData() + { + return m_lightobj; + } + + bool GetShowShadowFrustum() const; + void SetShowShadowFrustum(bool show); + + // Update rasterizer light settings. + void Update(); + + void UpdateScene(KX_Scene *kxscene); + virtual void SetLayer(int layer); + + virtual int GetGameObjectType() const + { + return OBJ_LIGHT; + } + +#ifdef WITH_PYTHON + // functions + EXP_PYMETHOD_DOC_NOARGS(KX_LightObject, updateShadow); + + // attributes + static PyObject *pyattr_get_energy(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_energy(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_shadow_clip_start(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_shadow_clip_end(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_shadow_frustum_size(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_shadow_bind_code(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_shadow_bias(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_shadow_bleed_bias(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_shadow_map_type(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_shadow_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_shadow_active(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_shadow_matrix(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_distance(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_distance(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_lin_attenuation(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_lin_attenuation(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_quad_attenuation(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_quad_attenuation(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_spotsize(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_spotsize(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_spotblend(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_spotblend(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_typeconst(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_type(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_type(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_static_shadow(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_static_shadow(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); +#endif +}; + +#endif // __KX_LIGHT_H__ diff --git a/source/gameengine/Ketsji/KX_LodLevel.cpp b/source/gameengine/Ketsji/KX_LodLevel.cpp new file mode 100644 index 000000000000..c51a0b8be902 --- /dev/null +++ b/source/gameengine/Ketsji/KX_LodLevel.cpp @@ -0,0 +1,136 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Ulysse Martin, Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Ketsji/KX_LodLevel.cpp + * \ingroup ketsji + */ + +#include "KX_LodLevel.h" +#include "KX_Mesh.h" + +KX_LodLevel::KX_LodLevel(float distance, float hysteresis, unsigned short level, KX_Mesh *mesh, unsigned short flag) + :m_distance(distance), + m_hysteresis(hysteresis), + m_level(level), + m_flags(flag), + m_mesh(mesh) +{ +} + +KX_LodLevel::~KX_LodLevel() +{ +} + +std::string KX_LodLevel::GetName() +{ + return m_mesh->GetName(); +} + +float KX_LodLevel::GetDistance() const +{ + return m_distance; +} + +float KX_LodLevel::GetHysteresis() const +{ + return m_hysteresis; +} + +unsigned short KX_LodLevel::GetLevel() const +{ + return m_level; +} + +unsigned short KX_LodLevel::GetFlag() const +{ + return m_flags; +} + +KX_Mesh *KX_LodLevel::GetMesh() const +{ + return m_mesh; +} + +#ifdef WITH_PYTHON + +PyTypeObject KX_LodLevel::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_LodLevel", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &EXP_Value::Type, + 0, 0, 0, 0, 0, 0, + py_base_new +}; + +PyMethodDef KX_LodLevel::Methods[] = { + {nullptr, nullptr} // Sentinel +}; + +PyAttributeDef KX_LodLevel::Attributes[] = { + EXP_PYATTRIBUTE_RO_FUNCTION("mesh", KX_LodLevel, pyattr_get_mesh), + EXP_PYATTRIBUTE_SHORT_RO("level", KX_LodLevel, m_level), + EXP_PYATTRIBUTE_FLOAT_RO("distance", KX_LodLevel, m_distance), + EXP_PYATTRIBUTE_FLOAT_RO("hysteresis", KX_LodLevel, m_hysteresis), + EXP_PYATTRIBUTE_RO_FUNCTION("useHysteresis", KX_LodLevel, pyattr_get_use_hysteresis), + EXP_PYATTRIBUTE_RO_FUNCTION("useMesh", KX_LodLevel, pyattr_get_use_mesh), + EXP_PYATTRIBUTE_RO_FUNCTION("useMaterial", KX_LodLevel, pyattr_get_use_material), + EXP_PYATTRIBUTE_NULL // Sentinel +}; + +PyObject *KX_LodLevel::pyattr_get_mesh(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LodLevel *self = static_cast(self_v); + return self->GetMesh()->GetProxy(); +} + +PyObject *KX_LodLevel::pyattr_get_use_hysteresis(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LodLevel *self = static_cast(self_v); + return PyBool_FromLong(self->GetFlag() & KX_LodLevel::USE_HYSTERESIS); +} + +PyObject *KX_LodLevel::pyattr_get_use_mesh(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LodLevel *self = static_cast(self_v); + return PyBool_FromLong(self->GetFlag() & KX_LodLevel::USE_MESH); +} + +PyObject *KX_LodLevel::pyattr_get_use_material(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_LodLevel *self = static_cast(self_v); + return PyBool_FromLong(self->GetFlag() & KX_LodLevel::USE_MATERIAL); +} + +#endif //WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_LodLevel.h b/source/gameengine/Ketsji/KX_LodLevel.h new file mode 100644 index 000000000000..d60d861768b1 --- /dev/null +++ b/source/gameengine/Ketsji/KX_LodLevel.h @@ -0,0 +1,76 @@ +/* +* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* Contributor(s): Ulysse Martin, Tristan Porteries. +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +/** \file KX_LodLevel.h + * \ingroup ketsji + */ + +#ifndef __KX_LOD_LEVEL_H__ +#define __KX_LOD_LEVEL_H__ + +#include "EXP_Value.h" + +class KX_Mesh; + +class KX_LodLevel : public EXP_Value +{ + Py_Header +private: + float m_distance; + float m_hysteresis; + short m_level; + unsigned short m_flags; + KX_Mesh *m_mesh; + +public: + KX_LodLevel(float distance, float hysteresis, unsigned short level, KX_Mesh *mesh, unsigned short flag); + virtual ~KX_LodLevel(); + + virtual std::string GetName(); + + float GetDistance() const; + float GetHysteresis() const; + unsigned short GetLevel() const; + unsigned short GetFlag() const; + KX_Mesh *GetMesh() const; + + enum { + /// Use custom hysteresis for this level. + USE_HYSTERESIS = (1 << 0), + /// Use a different mesh than original. + USE_MESH = (1 << 1), + /// Use a different material than original mesh. + USE_MATERIAL = (1 << 2) + }; + +#ifdef WITH_PYTHON + + static PyObject *pyattr_get_mesh(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_use_hysteresis(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_use_mesh(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_use_material(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + +#endif // WITH_PYTHON + +}; + +#endif // __KX_LOD_LEVEL_H__ diff --git a/source/gameengine/Ketsji/KX_LodManager.cpp b/source/gameengine/Ketsji/KX_LodManager.cpp new file mode 100644 index 000000000000..b21bd8d5efb0 --- /dev/null +++ b/source/gameengine/Ketsji/KX_LodManager.cpp @@ -0,0 +1,266 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Ulysse Martin, Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Ketsji/KX_LodManager.cpp + * \ingroup ketsji + */ + +#include "KX_LodManager.h" +#include "KX_LodLevel.h" +#include "KX_Scene.h" + +#include "EXP_ListWrapper.h" + +#include "BL_BlenderDataConversion.h" +#include "DNA_object_types.h" +#include "BLI_listbase.h" + +KX_LodManager::LodLevelIterator::LodLevelIterator(const std::vector& levels, unsigned short index, KX_Scene *scene) + :m_levels(levels), + m_index(index), + m_scene(scene) +{ +} + +inline float KX_LodManager::LodLevelIterator::GetHysteresis(unsigned short level) const +{ + if (level < 1 || !m_scene->IsActivedLodHysteresis()) { + return 0.0f; + } + + const KX_LodLevel& lod = m_levels[level]; + const KX_LodLevel& prelod = m_levels[level - 1]; + + float hysteresis = 0.0f; + // if exists, LoD level hysteresis will override scene hysteresis + if (lod.GetFlag() & KX_LodLevel::USE_HYSTERESIS) { + hysteresis = lod.GetHysteresis() / 100.0f; + } + else { + hysteresis = m_scene->GetLodHysteresisValue() / 100.0f; + } + + return std::abs(prelod.GetDistance() - lod.GetDistance()) * hysteresis; +} + +inline int KX_LodManager::LodLevelIterator::operator++() +{ + return m_index++; +} + +inline int KX_LodManager::LodLevelIterator::operator--() +{ + return m_index--; +} + +inline short KX_LodManager::LodLevelIterator::operator*() const +{ + return m_index; +} + +inline bool KX_LodManager::LodLevelIterator::operator<=(float distance2) const +{ + // The last level doesn't have a next level, then the maximum distance is infinite and should always return false. + if (m_index == (m_levels.size() - 1)) { + return false; + } + + return SQUARE(m_levels[m_index + 1].GetDistance() + GetHysteresis(m_index + 1)) <= distance2; +} + +inline bool KX_LodManager::LodLevelIterator::operator>(float distance2) const +{ + return SQUARE(m_levels[m_index].GetDistance() - GetHysteresis(m_index)) > distance2; +} + +KX_LodManager::KX_LodManager(Object *ob, KX_Scene *scene, BL_SceneConverter& converter) + :m_refcount(1), + m_distanceFactor(ob->lodfactor) +{ + Mesh *lodmesh = (Mesh *)ob->data; + Object *lodmatob = ob; + unsigned short level = 0; + + for (LodLevel *lod = (LodLevel *)ob->lodlevels.first; lod; lod = lod->next) { + if (!lod->source || lod->source->type != OB_MESH) { + continue; + } + unsigned short flag = 0; + if (lod->flags & OB_LOD_USE_HYST) { + flag |= KX_LodLevel::USE_HYSTERESIS; + } + + if (lod->flags & OB_LOD_USE_MESH) { + lodmesh = (Mesh *)lod->source->data; + flag |= KX_LodLevel::USE_MESH; + } + + if (lod->flags & OB_LOD_USE_MAT) { + lodmatob = lod->source; + flag |= KX_LodLevel::USE_MATERIAL; + } + + m_levels.emplace_back(lod->distance, lod->obhysteresis, level++, + BL_ConvertMesh(lodmesh, lodmatob, scene, converter), flag); + } +} + +KX_LodManager::~KX_LodManager() +{ +} + +std::string KX_LodManager::GetName() +{ + return "KX_LodManager"; +} + +unsigned int KX_LodManager::GetLevelCount() const +{ + return m_levels.size(); +} + +const KX_LodLevel& KX_LodManager::GetLevel(unsigned int index) const +{ + return m_levels[index]; +} + +KX_LodLevel& KX_LodManager::GetLevel(unsigned int index) +{ + return m_levels[index]; +} + +const KX_LodLevel& KX_LodManager::GetLevel(KX_Scene *scene, short previouslod, float distance2) +{ + distance2 *= (m_distanceFactor * m_distanceFactor); + + LodLevelIterator it(m_levels, previouslod, scene); + + while (true) { + if (it <= distance2) { + ++it; + } + else if (it > distance2) { + --it; + } + else { + break; + } + } + + const unsigned short level = *it; + return m_levels[level]; +} + +#ifdef WITH_PYTHON + +PyTypeObject KX_LodManager::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_LodManager", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &EXP_Value::Type, + 0, 0, 0, 0, 0, 0, + py_base_new +}; + +PyMethodDef KX_LodManager::Methods[] = { + {nullptr, nullptr} // Sentinel +}; + +PyAttributeDef KX_LodManager::Attributes[] = { + EXP_PYATTRIBUTE_RO_FUNCTION("levels", KX_LodManager, pyattr_get_levels), + EXP_PYATTRIBUTE_FLOAT_RW("distanceFactor", 0.0f, FLT_MAX, KX_LodManager, m_distanceFactor), + EXP_PYATTRIBUTE_NULL +}; + +unsigned int KX_LodManager::py_get_levels_size() +{ + return m_levels.size(); +} + +PyObject *KX_LodManager::py_get_levels_item(unsigned int index) +{ + return m_levels[index].GetProxy(); +} + +PyObject *KX_LodManager::pyattr_get_levels(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + return (new EXP_ListWrapper(self_v))->NewProxy(true); +} + +bool ConvertPythonToLodManager(PyObject *value, KX_LodManager **object, bool py_none_ok, const char *error_prefix) +{ + if (value == nullptr) { + PyErr_Format(PyExc_TypeError, "%s, python pointer nullptr, should never happen", error_prefix); + *object = nullptr; + return false; + } + + if (value == Py_None) { + *object = nullptr; + + if (py_none_ok) { + return true; + } + else { + PyErr_Format(PyExc_TypeError, "%s, expected KX_LodManager, None is invalid", error_prefix); + return false; + } + } + + if (PyObject_TypeCheck(value, &KX_LodManager::Type)) { + *object = static_castEXP_PROXY_REF(value); + + /* sets the error */ + if (*object == nullptr) { + PyErr_Format(PyExc_SystemError, "%s, " EXP_PROXY_ERROR_MSG, error_prefix); + return false; + } + + return true; + } + + *object = nullptr; + + if (py_none_ok) { + PyErr_Format(PyExc_TypeError, "%s, expect a KX_LodManager or None", error_prefix); + } + else { + PyErr_Format(PyExc_TypeError, "%s, expect a KX_LodManager", error_prefix); + } + + return false; +} + +#endif //WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_LodManager.h b/source/gameengine/Ketsji/KX_LodManager.h new file mode 100644 index 000000000000..d87a85fd2776 --- /dev/null +++ b/source/gameengine/Ketsji/KX_LodManager.h @@ -0,0 +1,120 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Ulysse Martin, Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file KX_LodManager.h + * \ingroup ketsji + */ + +#ifndef __KX_LOD_MANAGER_H__ +#define __KX_LOD_MANAGER_H__ + +#include "EXP_Value.h" +#include + +class KX_Scene; +class BL_SceneConverter; +class KX_LodLevel; +struct Object; + +class KX_LodManager : public EXP_Value +{ + Py_Header + +private: + /** This class helps to compare the object distance to camera with the list of lod levels. + * It represent the gap between two levels, when you compare it with a distance it compare + * with the a N level distance and a N+1 level distance including hysteresis. + */ + class LodLevelIterator + { + private: + const std::vector& m_levels; + short m_index; + KX_Scene *m_scene; + float GetHysteresis(unsigned short level) const; + + public: + LodLevelIterator(const std::vector& levels, unsigned short index, KX_Scene *scene); + + int operator++(); + int operator--(); + short operator*() const; + /// Compare next level distance more hysteresis with current distance. + bool operator<=(float distance2) const; + /// Compare the current lod level distance less hysteresis with current distance. + bool operator>(float distance2) const; + }; + + std::vector m_levels; + + /** Get the hysteresis from the level or the scene. + * \param scene Scene used to get default hysteresis. + * \param level Level index used to get hysteresis. + */ + float GetHysteresis(KX_Scene *scene, unsigned short level); + + int m_refcount; + + /// Factor applied to the distance from the camera to the object. + float m_distanceFactor; + +public: + KX_LodManager(Object *ob, KX_Scene *scene, BL_SceneConverter& converter); + virtual ~KX_LodManager(); + + virtual std::string GetName(); + + /// Return number of lod levels. + unsigned int GetLevelCount() const; + + /** Get lod level by index. + * \param index The lod level index. + */ + const KX_LodLevel& GetLevel(unsigned int index) const; + KX_LodLevel& GetLevel(unsigned int index); + + /** Get lod level cooresponding to distance and previous level. + * \param scene Scene used to get default hysteresis. + * \param previouslod Previous lod computed by this function before. + * Use -1 to disable the hysteresis when the lod manager has changed. + * \param distance2 Squared distance object to the camera. + */ + const KX_LodLevel& GetLevel(KX_Scene *scene, short previouslod, float distance); + +#ifdef WITH_PYTHON + + static PyObject *pyattr_get_levels(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + + unsigned int py_get_levels_size(); + PyObject *py_get_levels_item(unsigned int index); + +#endif //WITH_PYTHON +}; + +#ifdef WITH_PYTHON + +/// Utility python conversion function. +bool ConvertPythonToLodManager(PyObject *value, KX_LodManager **object, bool py_none_ok, const char *error_prefix); + +#endif // WITH_PYTHON + +#endif // __KX_LOD_MANAGER_H__ diff --git a/source/gameengine/Ketsji/KX_MaterialIpoController.cpp b/source/gameengine/Ketsji/KX_MaterialIpoController.cpp index 71d4eea0ed91..8d3f90688eef 100644 --- a/source/gameengine/Ketsji/KX_MaterialIpoController.cpp +++ b/source/gameengine/Ketsji/KX_MaterialIpoController.cpp @@ -23,82 +23,17 @@ */ #include "KX_MaterialIpoController.h" -#include "KX_ScalarInterpolator.h" #include "KX_GameObject.h" -#include "BLI_sys_types.h" // for intptr_t support +#include "RAS_IMaterial.h" -bool KX_MaterialIpoController::Update(double currentTime) +bool KX_MaterialIpoController::Update(SG_Node *node) { - if (m_modified) - { - T_InterpolatorList::iterator i; - for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) { - (*i)->Execute(m_ipotime); - } - - - SG_Spatial* ob = (SG_Spatial*)m_pObject; - KX_GameObject* kxgameobj= (KX_GameObject*) ob->GetSGClientObject(); - - //kxgameobj->SetObjectColor(m_rgba); - kxgameobj->UpdateMaterialData( - m_matname_hash, - m_rgba, - m_specrgb, - m_hard, - m_spec, - m_ref, - m_emit, - m_alpha - ); - - m_modified=false; + if (!SG_Controller::Update(node)) { + return false; } - return false; -} - - -void KX_MaterialIpoController::AddInterpolator(KX_IInterpolator* interp) -{ - this->m_interpolators.push_back(interp); -} - -SG_Controller* KX_MaterialIpoController::GetReplica(class SG_Node* destnode) -{ - KX_MaterialIpoController* iporeplica = new KX_MaterialIpoController(*this); - // clear object that ipo acts on - iporeplica->ClearObject(); - // dirty hack, ask Gino for a better solution in the ipo implementation - // hacken en zagen, in what we call datahiding, not written for replication :( - - T_InterpolatorList oldlist = m_interpolators; - iporeplica->m_interpolators.clear(); - - T_InterpolatorList::iterator i; - for (i = oldlist.begin(); !(i == oldlist.end()); ++i) { - KX_ScalarInterpolator* copyipo = new KX_ScalarInterpolator(*((KX_ScalarInterpolator*)*i)); - iporeplica->AddInterpolator(copyipo); - - MT_Scalar* scaal = ((KX_ScalarInterpolator*)*i)->GetTarget(); - intptr_t orgbase = (intptr_t)this; - intptr_t orgloc = (intptr_t)scaal; - intptr_t offset = orgloc-orgbase; - intptr_t newaddrbase = (intptr_t)iporeplica + offset; - MT_Scalar* blaptr = (MT_Scalar*) newaddrbase; - copyipo->SetNewTarget((MT_Scalar*)blaptr); - } - - return iporeplica; -} - -KX_MaterialIpoController::~KX_MaterialIpoController() -{ - - T_InterpolatorList::iterator i; - for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) { - delete (*i); - } + m_material->UpdateIPO(m_rgba, m_specrgb, m_hard, m_spec, m_ref, m_emit, m_ambient, m_alpha, m_specAlpha); + return true; } diff --git a/source/gameengine/Ketsji/KX_MaterialIpoController.h b/source/gameengine/Ketsji/KX_MaterialIpoController.h index ca5d1040da2b..e88a1c2cd92f 100644 --- a/source/gameengine/Ketsji/KX_MaterialIpoController.h +++ b/source/gameengine/Ketsji/KX_MaterialIpoController.h @@ -9,57 +9,34 @@ #include "SG_Controller.h" -#include "SG_Spatial.h" -#include "KX_IInterpolator.h" +#include "SG_Node.h" +#include "SG_Interpolator.h" +#include "mathfu.h" -#include "STR_String.h" //typedef dword +class RAS_IMaterial; -class KX_MaterialIpoController : public SG_Controller +class KX_MaterialIpoController : public SG_Controller, public mt::SimdClassAllocator { public: - MT_Vector4 m_rgba; - MT_Vector3 m_specrgb; - MT_Scalar m_hard; - MT_Scalar m_spec; - MT_Scalar m_ref; - MT_Scalar m_emit; - MT_Scalar m_alpha; + mt::vec4 m_rgba; + mt::vec3 m_specrgb; + float m_hard; + float m_spec; + float m_ref; + float m_emit; + float m_ambient; + float m_alpha; + float m_specAlpha; private: - T_InterpolatorList m_interpolators; - bool m_modified; + RAS_IMaterial *m_material; - double m_ipotime; - dword m_matname_hash; public: - KX_MaterialIpoController(dword matname_hash) : - m_modified(true), - m_ipotime(0.0), - m_matname_hash(matname_hash) + KX_MaterialIpoController(RAS_IMaterial *mat) : + m_material(mat) {} - virtual ~KX_MaterialIpoController(); - virtual SG_Controller* GetReplica(class SG_Node* destnode); - virtual bool Update(double time); - virtual void SetSimulatedTime(double time) { - m_ipotime = time; - m_modified = true; - } - - void - SetOption( - int option, - int value - ) { - // intentionally empty - }; - - - void AddInterpolator(KX_IInterpolator* interp); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_MaterialIpoController") -#endif + virtual ~KX_MaterialIpoController() = default; + virtual bool Update(SG_Node *node); }; #endif /* __KX_MATERIALIPOCONTROLLER_H__ */ diff --git a/source/gameengine/Ketsji/KX_Mesh.cpp b/source/gameengine/Ketsji/KX_Mesh.cpp new file mode 100644 index 000000000000..722f1dc88b18 --- /dev/null +++ b/source/gameengine/Ketsji/KX_Mesh.cpp @@ -0,0 +1,603 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Ketsji/KX_Mesh.cpp + * \ingroup ketsji + */ + +#include "KX_Mesh.h" +#include "KX_Scene.h" +#include "KX_Globals.h" +#include "KX_KetsjiEngine.h" + +#include "BL_Converter.h" + +#include "RAS_IMaterial.h" +#include "RAS_DisplayArray.h" +#include "RAS_BucketManager.h" +#include "SCA_LogicManager.h" + +#include "KX_VertexProxy.h" +#include "KX_PolyProxy.h" + +#include "KX_BlenderMaterial.h" + +#include "KX_PyMath.h" + +#include "SCA_LogicManager.h" + +#include "EXP_PyObjectPlus.h" +#include "EXP_ListWrapper.h" + +#include "BLI_kdopbvh.h" +#include "BLI_compiler_compat.h" // For MSVC __func__ + +#include "MEM_guardedalloc.h" + +extern "C" { +# include "mathutils_bvhtree.h" +} + +KX_Mesh::KX_Mesh(KX_Scene *scene, Mesh *mesh, const RAS_Mesh::LayersInfo& layersInfo) + :RAS_Mesh(mesh, layersInfo), + m_scene(scene) +{ +} + +KX_Mesh::KX_Mesh(KX_Scene *scene, const std::string& name, const RAS_Mesh::LayersInfo& layersInfo) + :RAS_Mesh(name, layersInfo), + m_scene(scene) +{ +} + +KX_Mesh::KX_Mesh(const KX_Mesh& other) + :RAS_Mesh(other), + m_scene(other.m_scene) +{ +} + +KX_Mesh::~KX_Mesh() +{ +} + +KX_Scene *KX_Mesh::GetScene() const +{ + return m_scene; +} + +void KX_Mesh::ReplaceScene(KX_Scene *scene) +{ + m_scene = scene; +} + +#ifdef WITH_PYTHON + +PyTypeObject KX_Mesh::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_Mesh", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &EXP_Value::Type, + 0, 0, 0, 0, 0, 0, + py_base_new +}; + +PyMethodDef KX_Mesh::Methods[] = { + {"getMaterialName", (PyCFunction)KX_Mesh::sPyGetMaterialName, METH_VARARGS}, + {"getTextureName", (PyCFunction)KX_Mesh::sPyGetTextureName, METH_VARARGS}, + {"getVertexArrayLength", (PyCFunction)KX_Mesh::sPyGetVertexArrayLength, METH_VARARGS}, + {"getVertex", (PyCFunction)KX_Mesh::sPyGetVertex, METH_VARARGS}, + {"getPolygon", (PyCFunction)KX_Mesh::sPyGetPolygon, METH_VARARGS}, + {"transform", (PyCFunction)KX_Mesh::sPyTransform, METH_VARARGS}, + {"transformUV", (PyCFunction)KX_Mesh::sPyTransformUV, METH_VARARGS}, + {"replaceMaterial", (PyCFunction)KX_Mesh::sPyReplaceMaterial, METH_VARARGS}, + {"copy", (PyCFunction)KX_Mesh::sPyCopy, METH_NOARGS}, + {"constructBvh", (PyCFunction)KX_Mesh::sPyConstructBvh, METH_VARARGS | METH_KEYWORDS}, + {"destruct", (PyCFunction) KX_Mesh::sPyDestruct, METH_NOARGS}, + {nullptr, nullptr} //Sentinel +}; + +PyAttributeDef KX_Mesh::Attributes[] = { + EXP_PYATTRIBUTE_RO_FUNCTION("materials", KX_Mesh, pyattr_get_materials), + EXP_PYATTRIBUTE_RO_FUNCTION("numPolygons", KX_Mesh, pyattr_get_numPolygons), + EXP_PYATTRIBUTE_RO_FUNCTION("numMaterials", KX_Mesh, pyattr_get_numMaterials), + EXP_PYATTRIBUTE_RO_FUNCTION("polygons", KX_Mesh, pyattr_get_polygons), + + EXP_PYATTRIBUTE_NULL //Sentinel +}; + +std::string KX_Mesh::GetName() +{ + return RAS_Mesh::GetName(); +} + +PyObject *KX_Mesh::PyGetMaterialName(PyObject *args, PyObject *kwds) +{ + int matid = 1; + std::string matname; + + if (PyArg_ParseTuple(args, "i:getMaterialName", &matid)) { + matname = GetMaterialName(matid); + } + else { + return nullptr; + } + + return PyUnicode_FromStdString(matname); +} + +PyObject *KX_Mesh::PyGetTextureName(PyObject *args, PyObject *kwds) +{ + int matid = 1; + std::string matname; + + if (PyArg_ParseTuple(args, "i:getTextureName", &matid)) { + matname = GetTextureName(matid); + } + else { + return nullptr; + } + + return PyUnicode_FromStdString(matname); +} + +PyObject *KX_Mesh::PyGetVertexArrayLength(PyObject *args, PyObject *kwds) +{ + int matid = 0; + int length = 0; + + if (!PyArg_ParseTuple(args, "i:getVertexArrayLength", &matid)) { + return nullptr; + } + + RAS_DisplayArray *array = GetDisplayArray(matid); + if (array) { + length = array->GetVertexCount(); + } + + return PyLong_FromLong(length); +} + +PyObject *KX_Mesh::PyGetVertex(PyObject *args, PyObject *kwds) +{ + int vertexindex; + int matindex; + + if (!PyArg_ParseTuple(args, "ii:getVertex", &matindex, &vertexindex)) { + return nullptr; + } + + RAS_DisplayArray *array = GetDisplayArray(matindex); + if (vertexindex < 0 || vertexindex >= array->GetVertexCount()) { + PyErr_SetString(PyExc_ValueError, "mesh.getVertex(mat_idx, vert_idx): KX_Mesh, could not get a vertex at the given indices"); + return nullptr; + } + + return (new KX_VertexProxy(array, vertexindex))->NewProxy(true); +} + +PyObject *KX_Mesh::PyGetPolygon(PyObject *args, PyObject *kwds) +{ + int polyindex = 1; + + if (!PyArg_ParseTuple(args, "i:getPolygon", &polyindex)) { + return nullptr; + } + + if (polyindex < 0 || polyindex >= m_numPolygons) { + PyErr_SetString(PyExc_AttributeError, "mesh.getPolygon(int): KX_Mesh, invalid polygon index"); + return nullptr; + } + + const RAS_Mesh::PolygonInfo polygon = GetPolygon(polyindex); + KX_PolyProxy *polyProxy = new KX_PolyProxy(this, polygon); + return polyProxy->NewProxy(true); +} + +PyObject *KX_Mesh::PyTransform(PyObject *args, PyObject *kwds) +{ + int matindex; + PyObject *pymat; + bool ok = false; + + mt::mat4 transform; + + if (!PyArg_ParseTuple(args, "iO:transform", &matindex, &pymat) || + !PyMatTo(pymat, transform)) { + return nullptr; + } + + mt::mat4 ntransform = transform; + ntransform(0, 3) = ntransform(1, 3) = ntransform(2, 3) = 0.0f; + + /* transform mesh verts */ + for (unsigned short i = 0, num = m_materials.size(); i < num; ++i) { + if (matindex == -1) { + /* always transform */ + } + else if (matindex == i) { + /* we found the right index! */ + } + else { + continue; + } + + RAS_DisplayArray *array = m_materials[i]->GetDisplayArray(); + ok = true; + + const unsigned int vertexCount = array->GetVertexCount(); + for (unsigned int j = 0; j < vertexCount; ++j) { + array->SetPosition(j, transform * mt::vec3(array->GetPosition(j))); + array->SetNormal(j, ntransform * mt::vec3(array->GetNormal(j))); + array->SetTangent(j, ntransform * mt::vec4(array->GetTangent(j))); + } + + array->NotifyUpdate(RAS_DisplayArray::POSITION_MODIFIED | + RAS_DisplayArray::NORMAL_MODIFIED | + RAS_DisplayArray::TANGENT_MODIFIED); + + /* if we set a material index, quit when done */ + if (matindex != -1) { + break; + } + } + + if (ok == false) { + PyErr_Format(PyExc_ValueError, + "mesh.transform(...): invalid material index %d", matindex); + return nullptr; + } + + Py_RETURN_NONE; +} + +PyObject *KX_Mesh::PyTransformUV(PyObject *args, PyObject *kwds) +{ + int matindex; + PyObject *pymat; + int uvindex = -1; + int uvindex_from = -1; + bool ok = false; + + mt::mat4 transform; + + if (!PyArg_ParseTuple(args, "iO|iii:transformUV", &matindex, &pymat, &uvindex, &uvindex_from) || + !PyMatTo(pymat, transform)) { + return nullptr; + } + + if (uvindex < -1 || uvindex > RAS_Texture::MaxUnits) { + PyErr_Format(PyExc_ValueError, + "mesh.transformUV(...): invalid uv_index %d", uvindex); + return nullptr; + } + if (uvindex_from < -1 || uvindex_from > RAS_Texture::MaxUnits) { + PyErr_Format(PyExc_ValueError, + "mesh.transformUV(...): invalid uv_index_from %d", uvindex); + return nullptr; + } + if (uvindex_from == uvindex) { + uvindex_from = -1; + } + + /* transform mesh verts */ + for (unsigned short i = 0, num = m_materials.size(); i < num; ++i) { + if (matindex == -1) { + /* always transform */ + } + else if (matindex == i) { + /* we found the right index! */ + } + else { + continue; + } + + RAS_DisplayArray *array = m_materials[i]->GetDisplayArray(); + const RAS_DisplayArray::Format& format = array->GetFormat(); + ok = true; + + for (unsigned int j = 0, size = array->GetVertexCount(); j < size; ++j) { + if (uvindex_from != -1) { + array->SetUv(j, uvindex, array->GetUv(j, uvindex_from)); + } + + if (0 <= uvindex && uvindex < format.uvSize) { + const mt::vec2_packed& uv = array->GetUv(j, uvindex); + array->SetUv(j, uvindex, (transform * mt::vec3(uv.x, uv.y, 0.0f)).xy()); + } + else if (uvindex == -1) { + for (unsigned short k = 0; k < format.uvSize; ++k) { + const mt::vec2_packed& uv = array->GetUv(j, k); + array->SetUv(j, k, (transform * mt::vec3(uv.x, uv.y, 0.0f)).xy()); + } + } + } + + array->NotifyUpdate(RAS_DisplayArray::UVS_MODIFIED); + + /* if we set a material index, quit when done */ + if (matindex != -1) { + break; + } + } + + if (ok == false) { + PyErr_Format(PyExc_ValueError, + "mesh.transformUV(...): invalid material index %d", matindex); + return nullptr; + } + + Py_RETURN_NONE; +} + +PyObject *KX_Mesh::PyReplaceMaterial(PyObject *args, PyObject *kwds) +{ + unsigned short matindex; + PyObject *pymat; + KX_BlenderMaterial *mat; + + if (!PyArg_ParseTuple(args, "hO:replaceMaterial", &matindex, &pymat) || + !ConvertPythonToMaterial(pymat, &mat, false, "mesh.replaceMaterial(...): invalid material")) { + return nullptr; + } + + + RAS_MeshMaterial *meshmat = GetMeshMaterial(matindex); + if (!meshmat) { + PyErr_Format(PyExc_ValueError, "Invalid material index %d", matindex); + return nullptr; + } + + KX_Scene *scene = (KX_Scene *)meshmat->GetBucket()->GetMaterial()->GetScene(); + if (scene != mat->GetScene()) { + PyErr_Format(PyExc_ValueError, "Mesh successor scene doesn't match current mesh scene"); + return nullptr; + } + + RAS_BucketManager *bucketmgr = scene->GetBucketManager(); + bool created = false; + RAS_MaterialBucket *bucket = bucketmgr->FindBucket(mat, created); + + // Must never create the material bucket. + BLI_assert(created == false); + + meshmat->ReplaceMaterial(bucket); + + Py_RETURN_NONE; +} + +PyObject *KX_Mesh::PyCopy() +{ + KX_Mesh *dupli = new KX_Mesh(*this); + // Create bounding box. + dupli->EndConversion(m_scene->GetBoundingBoxManager()); + + // Transfer ownership to converter. + KX_GetActiveEngine()->GetConverter()->RegisterMesh(m_scene, dupli); + + return dupli->GetProxy(); +} + +PyObject *KX_Mesh::PyDestruct() +{ + // Transfer ownership to converter. + KX_GetActiveEngine()->GetConverter()->UnregisterMesh(m_scene, this); + + // Here the mesh is freed. + + Py_RETURN_NONE; +} + +PyObject *KX_Mesh::PyConstructBvh(PyObject *args, PyObject *kwds) +{ + float epsilon = 0.0f; + PyObject *pymat = nullptr; + + if (!EXP_ParseTupleArgsAndKeywords(args, kwds, "|Of:constructBvh", {"transform", "epsilon", 0}, &pymat, &epsilon)) { + return nullptr; + } + + mt::mat4 mat = mt::mat4::Identity(); + if (pymat && !PyMatTo(pymat, mat)) { + return nullptr; + } + + BVHTree *tree = BLI_bvhtree_new(m_numPolygons, epsilon, 4, 6); + + unsigned int numVert = 0; + // Compute the totale number of vertices. + for (const PolygonRangeInfo& range : m_polygonRanges) { + numVert += range.array->GetVertexCount(); + } + + const char *function_macro = __func__; //Workaround for MSVC2015 + float (*coords)[3] = (float (*)[3])MEM_mallocN(sizeof(float[3]) * numVert, function_macro); + // Convert the vertices. + { + unsigned vertBase = 0; + for (const PolygonRangeInfo& range : m_polygonRanges) { + RAS_DisplayArray *array = range.array; + for (unsigned int i = 0, size = array->GetVertexCount(); i < size; ++i) { + const mt::vec3 pos = mat * mt::vec3(array->GetPosition(i)); + pos.Pack(coords[vertBase + i]); + } + vertBase += array->GetVertexCount(); + } + } + + unsigned int *tris = (unsigned int *)MEM_mallocN(sizeof(unsigned int) * 3 * m_numPolygons, __func__); + // Convert the indices. + { + unsigned int index = 0; + unsigned int vertBase = 0; + for (const PolygonRangeInfo& range : m_polygonRanges) { + // Iterate by triangle (3 indices). + for (; index < range.endIndex; index += 3) { + // Get the relative triangle base index. + const unsigned int triBase = index - range.startIndex; + float co[3][3]; + + for (unsigned short i = 0; i < 3; ++i) { + // Get the absolute the vertex index. + const unsigned int vertIndex = vertBase + range.array->GetTriangleIndex(triBase + i); + + tris[index + i] = vertIndex; + copy_v3_v3(co[i], coords[vertIndex]); + } + + BLI_bvhtree_insert(tree, index / 3, co[0], 3); + } + vertBase += range.array->GetVertexCount(); + } + } + + BLI_bvhtree_balance(tree); + + return bvhtree_CreatePyObject( + tree, epsilon, + coords, numVert, + (unsigned int (*)[3])tris, m_numPolygons * 3, + nullptr, nullptr); +} + +PyObject *KX_Mesh::pyattr_get_materials(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_Mesh *self = static_cast(self_v); + + const unsigned short tot = self->m_materials.size(); + + PyObject *materials = PyList_New(tot); + + for (unsigned short i = 0; i < tot; ++i) { + RAS_MeshMaterial *mmat = self->m_materials[i]; + KX_BlenderMaterial *mat = static_cast(mmat->GetBucket()->GetMaterial()); + PyList_SET_ITEM(materials, i, mat->GetProxy()); + } + return materials; +} + +PyObject *KX_Mesh::pyattr_get_numMaterials(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_Mesh *self = static_cast (self_v); + return PyLong_FromLong(self->m_materials.size()); +} + +PyObject *KX_Mesh::pyattr_get_numPolygons(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_Mesh *self = static_cast (self_v); + return PyLong_FromLong(self->m_numPolygons); +} + +unsigned int KX_Mesh::py_get_polygons_size() +{ + return m_numPolygons; +} + +PyObject *KX_Mesh::py_get_polygons_item(unsigned int index) +{ + const RAS_Mesh::PolygonInfo polygon = GetPolygon(index); + + KX_PolyProxy *polyProxy = new KX_PolyProxy(this, polygon); + return polyProxy->NewProxy(true); +} + +PyObject *KX_Mesh::pyattr_get_polygons(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + return (new EXP_ListWrapper(self_v))->NewProxy(true); +} + +/* a close copy of ConvertPythonToGameObject but for meshes */ +bool ConvertPythonToMesh(SCA_LogicManager *logicmgr, PyObject *value, KX_Mesh **object, bool py_none_ok, const char *error_prefix) +{ + if (value == nullptr) { + PyErr_Format(PyExc_TypeError, "%s, python pointer nullptr, should never happen", error_prefix); + *object = nullptr; + return false; + } + + if (value == Py_None) { + *object = nullptr; + + if (py_none_ok) { + return true; + } + else { + PyErr_Format(PyExc_TypeError, "%s, expected KX_Mesh or a KX_Mesh name, None is invalid", error_prefix); + return false; + } + } + + if (PyUnicode_Check(value)) { + *object = (KX_Mesh *)logicmgr->GetMeshByName(std::string(_PyUnicode_AsString(value))); + + if (*object) { + return true; + } + else { + PyErr_Format(PyExc_ValueError, "%s, requested name \"%s\" did not match any KX_Mesh in this scene", error_prefix, _PyUnicode_AsString(value)); + return false; + } + } + + if (PyObject_TypeCheck(value, &KX_Mesh::Type)) { + KX_Mesh *kx_mesh = static_castEXP_PROXY_REF(value); + + /* sets the error */ + if (kx_mesh == nullptr) { + PyErr_Format(PyExc_SystemError, "%s, " EXP_PROXY_ERROR_MSG, error_prefix); + return false; + } + + *object = kx_mesh; + return true; + } + + *object = nullptr; + + if (py_none_ok) { + PyErr_Format(PyExc_TypeError, "%s, expect a KX_Mesh, a string or None", error_prefix); + } + else { + PyErr_Format(PyExc_TypeError, "%s, expect a KX_Mesh or a string", error_prefix); + } + + return false; +} + +#endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_Mesh.h b/source/gameengine/Ketsji/KX_Mesh.h new file mode 100644 index 000000000000..ea4a2b9bde1f --- /dev/null +++ b/source/gameengine/Ketsji/KX_Mesh.h @@ -0,0 +1,97 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file KX_Mesh.h + * \ingroup ketsji + */ + +#ifndef __KX_MESH_H__ +#define __KX_MESH_H__ + +#include "RAS_Mesh.h" + +#include "BL_Resource.h" + +#include "EXP_Value.h" + +class KX_Mesh; +class SCA_LogicManager; +class KX_Scene; + +#ifdef WITH_PYTHON +// utility conversion function +bool ConvertPythonToMesh(SCA_LogicManager *logicmgr, PyObject *value, KX_Mesh **object, bool py_none_ok, const char *error_prefix); + +#endif // WITH_PYTHON + +class KX_Mesh : public EXP_Value, public BL_Resource, public RAS_Mesh +{ + Py_Header + +private: + KX_Scene *m_scene; + +public: + KX_Mesh(KX_Scene *scene, Mesh *mesh, const LayersInfo& layersInfo); + KX_Mesh(KX_Scene *scene, const std::string& name, const LayersInfo& layersInfo); + KX_Mesh(const KX_Mesh& other); + virtual ~KX_Mesh(); + + // stuff for cvalue related things + virtual std::string GetName(); + + KX_Scene *GetScene() const; + void ReplaceScene(KX_Scene *scene); + +#ifdef WITH_PYTHON + + EXP_PYMETHOD(KX_Mesh, GetMaterialName); + EXP_PYMETHOD(KX_Mesh, GetTextureName); + + // both take materialid (int) + EXP_PYMETHOD(KX_Mesh, GetVertexArrayLength); + EXP_PYMETHOD(KX_Mesh, GetVertex); + EXP_PYMETHOD(KX_Mesh, GetPolygon); + EXP_PYMETHOD(KX_Mesh, Transform); + EXP_PYMETHOD(KX_Mesh, TransformUV); + EXP_PYMETHOD(KX_Mesh, ReplaceMaterial); + EXP_PYMETHOD_NOARGS(KX_Mesh, Copy); + EXP_PYMETHOD(KX_Mesh, ConstructBvh); + EXP_PYMETHOD_NOARGS(KX_Mesh, Destruct); + + static PyObject *pyattr_get_materials(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_numMaterials(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_numPolygons(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_polygons(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + + unsigned int py_get_polygons_size(); + PyObject *py_get_polygons_item(unsigned int index); + +#endif // WITH_PYTHON +}; + +#endif // __KX_MESH_H__ diff --git a/source/gameengine/Ketsji/KX_MeshBuilder.cpp b/source/gameengine/Ketsji/KX_MeshBuilder.cpp new file mode 100644 index 000000000000..0c7c97ddef71 --- /dev/null +++ b/source/gameengine/Ketsji/KX_MeshBuilder.cpp @@ -0,0 +1,644 @@ +#include "KX_MeshBuilder.h" +#include "KX_VertexProxy.h" +#include "KX_BlenderMaterial.h" +#include "KX_Scene.h" +#include "KX_KetsjiEngine.h" +#include "KX_Globals.h" +#include "KX_PyMath.h" + +#include "EXP_ListWrapper.h" + +#include "BL_Converter.h" + +#include "RAS_BucketManager.h" + +#include "BLI_math_vector.h" +#include "BLI_math_geom.h" + +KX_MeshBuilderSlot::KX_MeshBuilderSlot(KX_BlenderMaterial *material, RAS_DisplayArray::PrimitiveType primitiveType, + const RAS_DisplayArray::Format& format, unsigned int& origIndexCounter) + :m_material(material), + m_array(new RAS_DisplayArray(primitiveType, format)), + m_origIndexCounter(origIndexCounter) +{ +} + +KX_MeshBuilderSlot::KX_MeshBuilderSlot(RAS_MeshMaterial *meshmat, const RAS_DisplayArray::Format& format, + unsigned int& origIndexCounter) + :m_origIndexCounter(origIndexCounter) +{ + RAS_MaterialBucket *bucket = meshmat->GetBucket(); + m_material = static_cast(bucket->GetMaterial()); + + RAS_DisplayArray *array = meshmat->GetDisplayArray(); + BLI_assert(array->GetType() == RAS_DisplayArray::NORMAL); + m_array = new RAS_DisplayArray(*array); + + // Compute the maximum original index from the arrays. + m_origIndexCounter = std::max(m_origIndexCounter, m_array->GetMaxOrigIndex()); +} + +KX_MeshBuilderSlot::~KX_MeshBuilderSlot() +{ +} + +std::string KX_MeshBuilderSlot::GetName() +{ + return m_material->GetName().substr(2); +} + +KX_BlenderMaterial *KX_MeshBuilderSlot::GetMaterial() const +{ + return m_material; +} + +void KX_MeshBuilderSlot::SetMaterial(KX_BlenderMaterial *material) +{ + m_material = material; +} + +bool KX_MeshBuilderSlot::Invalid() const +{ + // WARNING: Always respect the order from RAS_DisplayArray::PrimitiveType. + static const unsigned short itemsCount[] = { + 3, // TRIANGLES + 2 // LINES + }; + + const unsigned short count = itemsCount[m_array->GetPrimitiveType()]; + return ((m_array->GetPrimitiveIndexCount() % count) != 0 || (m_array->GetTriangleIndexCount() % count) != 0); +} + +RAS_DisplayArray *KX_MeshBuilderSlot::GetDisplayArray() const +{ + return m_array; +} + +PyTypeObject KX_MeshBuilderSlot::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_MeshBuilderSlot", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &EXP_Value::Type, + 0, 0, 0, 0, 0, 0, + py_base_new +}; + +PyMethodDef KX_MeshBuilderSlot::Methods[] = { + {"addVertex", (PyCFunction)KX_MeshBuilderSlot::sPyAddVertex, METH_VARARGS | METH_KEYWORDS}, + {"addIndex", (PyCFunction)KX_MeshBuilderSlot::sPyAddIndex, METH_O}, + {"removeVertex", (PyCFunction)KX_MeshBuilderSlot::sPyRemoveVertex, METH_VARARGS}, + {"addPrimitiveIndex", (PyCFunction)KX_MeshBuilderSlot::sPyAddPrimitiveIndex, METH_O}, + {"removePrimitiveIndex", (PyCFunction)KX_MeshBuilderSlot::sPyRemovePrimitiveIndex, METH_VARARGS}, + {"addTriangleIndex", (PyCFunction)KX_MeshBuilderSlot::sPyAddTriangleIndex, METH_O}, + {"removeTriangleIndex", (PyCFunction)KX_MeshBuilderSlot::sPyRemoveTriangleIndex, METH_VARARGS}, + {"recalculateNormals", (PyCFunction)KX_MeshBuilderSlot::sPyRecalculateNormals, METH_NOARGS}, + {nullptr, nullptr} // Sentinel +}; + +PyAttributeDef KX_MeshBuilderSlot::Attributes[] = { + EXP_PYATTRIBUTE_RO_FUNCTION("vertices", KX_MeshBuilderSlot, pyattr_get_vertices), + EXP_PYATTRIBUTE_RO_FUNCTION("indices", KX_MeshBuilderSlot, pyattr_get_indices), + EXP_PYATTRIBUTE_RO_FUNCTION("triangleIndices", KX_MeshBuilderSlot, pyattr_get_triangleIndices), + EXP_PYATTRIBUTE_RW_FUNCTION("material", KX_MeshBuilderSlot, pyattr_get_material, pyattr_set_material), + EXP_PYATTRIBUTE_RO_FUNCTION("uvCount", KX_MeshBuilderSlot, pyattr_get_uvCount), + EXP_PYATTRIBUTE_RO_FUNCTION("colorCount", KX_MeshBuilderSlot, pyattr_get_colorCount), + EXP_PYATTRIBUTE_RO_FUNCTION("primitive", KX_MeshBuilderSlot, pyattr_get_primitive), + EXP_PYATTRIBUTE_NULL // Sentinel +}; + +template +unsigned int KX_MeshBuilderSlot::get_size_cb() +{ + return (m_array->*Func)(); +} + +PyObject *KX_MeshBuilderSlot::get_item_vertices_cb(unsigned int index) +{ + KX_VertexProxy *vert = new KX_VertexProxy(m_array, index); + + return vert->NewProxy(true); +} + +template +PyObject *KX_MeshBuilderSlot::get_item_indices_cb(unsigned int index) +{ + return PyLong_FromLong((m_array->*Func)(index)); +} + +PyObject *KX_MeshBuilderSlot::pyattr_get_vertices(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + return (new EXP_ListWrapper, + &KX_MeshBuilderSlot::get_item_vertices_cb> + (self_v))->NewProxy(true); +} + +PyObject *KX_MeshBuilderSlot::pyattr_get_indices(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + return (new EXP_ListWrapper, + &KX_MeshBuilderSlot::get_item_indices_cb<&RAS_DisplayArray::GetPrimitiveIndex>> + (self_v))->NewProxy(true); +} + +PyObject *KX_MeshBuilderSlot::pyattr_get_triangleIndices(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + return (new EXP_ListWrapper, + &KX_MeshBuilderSlot::get_item_indices_cb<&RAS_DisplayArray::GetTriangleIndex>> + (self_v))->NewProxy(true); +} + +PyObject *KX_MeshBuilderSlot::pyattr_get_material(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_MeshBuilderSlot *self = static_cast(self_v); + return self->GetMaterial()->GetProxy(); +} + +int KX_MeshBuilderSlot::pyattr_set_material(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_MeshBuilderSlot *self = static_cast(self_v); + KX_BlenderMaterial *mat; + if (ConvertPythonToMaterial(value, &mat, false, "slot.material = material; KX_MeshBuilderSlot excepted a KX_BlenderMaterial.")) { + return PY_SET_ATTR_FAIL; + } + + self->SetMaterial(mat); + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_MeshBuilderSlot::pyattr_get_uvCount(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_MeshBuilderSlot *self = static_cast(self_v); + return PyBool_FromLong(self->GetDisplayArray()->GetFormat().uvSize); +} + +PyObject *KX_MeshBuilderSlot::pyattr_get_colorCount(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_MeshBuilderSlot *self = static_cast(self_v); + return PyBool_FromLong(self->GetDisplayArray()->GetFormat().colorSize); +} + +PyObject *KX_MeshBuilderSlot::pyattr_get_primitive(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_MeshBuilderSlot *self = static_cast(self_v); + return PyBool_FromLong(self->GetDisplayArray()->GetPrimitiveType()); +} + +PyObject *KX_MeshBuilderSlot::PyAddVertex(PyObject *args, PyObject *kwds) +{ + PyObject *pypos; + PyObject *pynormal = nullptr; + PyObject *pytangent = nullptr; + PyObject *pyuvs = nullptr; + PyObject *pycolors = nullptr; + + if (!EXP_ParseTupleArgsAndKeywords(args, kwds, "O|OOOO:addVertex", + {"position", "normal", "tangent", "uvs", "colors", 0}, + &pypos, &pynormal, &pytangent, &pyuvs, &pycolors)) + { + return nullptr; + } + + mt::vec3_packed pos; + if (!PyVecTo(pypos, pos)) { + return nullptr; + } + + mt::vec3_packed normal = mt::vec3_packed(mt::axisZ3); + if (pynormal && !PyVecTo(pynormal, normal)) { + return nullptr; + } + + mt::vec4_packed tangent = mt::vec4_packed(mt::one4); + if (pytangent && !PyVecTo(pytangent, tangent)) { + return nullptr; + } + + const RAS_DisplayArray::Format& format = m_array->GetFormat(); + + mt::vec2_packed uvs[RAS_Texture::MaxUnits] = {mt::vec2_packed(mt::zero2)}; + if (pyuvs) { + if (!PySequence_Check(pyuvs)) { + return nullptr; + } + + const unsigned short size = max_ii(format.uvSize, PySequence_Size(pyuvs)); + for (unsigned short i = 0; i < size; ++i) { + if (!PyVecTo(PySequence_GetItem(pyuvs, i), uvs[i])) { + return nullptr; + } + } + } + + unsigned int colors[RAS_Texture::MaxUnits] = {0xFFFFFFFF}; + if (pycolors) { + if (!PySequence_Check(pycolors)) { + return nullptr; + } + + const unsigned short size = max_ii(format.colorSize, PySequence_Size(pycolors)); + for (unsigned short i = 0; i < size; ++i) { + mt::vec4 color; + if (!PyVecTo(PySequence_GetItem(pycolors, i), color)) { + return nullptr; + } + rgba_float_to_uchar(reinterpret_cast(colors[i]), color.Data()); + } + } + + const unsigned index = m_array->AddVertex(pos, normal, tangent, uvs, colors, m_origIndexCounter++, 0); + + return PyLong_FromLong(index); +} + +PyObject *KX_MeshBuilderSlot::PyAddIndex(PyObject *value) +{ + if (!PySequence_Check(value)) { + PyErr_Format(PyExc_TypeError, "expected a list"); + return nullptr; + } + + const bool isTriangle = (m_array->GetPrimitiveType() == RAS_DisplayArray::TRIANGLES); + + for (unsigned int i = 0, size = PySequence_Size(value); i < size; ++i) { + const int val = PyLong_AsLong(PySequence_GetItem(value, i)); + + if (val < 0 && PyErr_Occurred()) { + PyErr_Format(PyExc_TypeError, "expected a list of positive integer"); + return nullptr; + } + + m_array->AddPrimitiveIndex(val); + if (isTriangle) { + m_array->AddTriangleIndex(val); + } + } + + Py_RETURN_NONE; +} + +PyObject *KX_MeshBuilderSlot::PyAddPrimitiveIndex(PyObject *value) +{ + if (!PySequence_Check(value)) { + PyErr_Format(PyExc_TypeError, "expected a list"); + return nullptr; + } + + for (unsigned int i = 0, size = PySequence_Size(value); i < size; ++i) { + const int val = PyLong_AsLong(PySequence_GetItem(value, i)); + + if (val < 0 && PyErr_Occurred()) { + PyErr_Format(PyExc_TypeError, "expected a list of positive integer"); + return nullptr; + } + + m_array->AddPrimitiveIndex(val); + } + + Py_RETURN_NONE; +} + +PyObject *KX_MeshBuilderSlot::PyAddTriangleIndex(PyObject *value) +{ + if (!PySequence_Check(value)) { + PyErr_Format(PyExc_TypeError, "expected a list"); + return nullptr; + } + + for (unsigned int i = 0, size = PySequence_Size(value); i < size; ++i) { + const int val = PyLong_AsLong(PySequence_GetItem(value, i)); + + if (val < 0 && PyErr_Occurred()) { + PyErr_Format(PyExc_TypeError, "expected a list of positive integer"); + return nullptr; + } + + m_array->AddTriangleIndex(val); + } + + Py_RETURN_NONE; +} + +static bool removeDataCheck(int start, int end, unsigned int size, const std::string& errmsg) +{ + if (start < 0 || start >= size || (end != -1 && (end > size || end <= start))) { + PyErr_Format(PyExc_TypeError, "%s: range invalid or empty, must be included in [0, %i[", errmsg.c_str(), size); + return false; + } + + return true; +} + +PyObject *KX_MeshBuilderSlot::PyRemoveVertex(PyObject *args) +{ + int start; + int end = -1; + + if (!PyArg_ParseTuple(args, "i|i:removeVertex", &start, &end)) { + return nullptr; + } + + if (!removeDataCheck(start, end, m_array->GetVertexCount(), "slot.removeVertex(start, end)")) { + return nullptr; + } + + m_array->RemoveVertex(start, end); + + Py_RETURN_NONE; +} + +PyObject *KX_MeshBuilderSlot::PyRemovePrimitiveIndex(PyObject *args) +{ + int start; + int end = -1; + + if (!PyArg_ParseTuple(args, "i|i:removePrimitiveIndex", &start, &end)) { + return nullptr; + } + + if (!removeDataCheck(start, end, m_array->GetPrimitiveIndexCount(), "slot.removePrimitiveIndex(start, end)")) { + return nullptr; + } + + m_array->RemovePrimitiveIndex(start, end); + + Py_RETURN_NONE; +} + +PyObject *KX_MeshBuilderSlot::PyRemoveTriangleIndex(PyObject *args) +{ + int start; + int end = -1; + + if (!PyArg_ParseTuple(args, "i|i:removeTriangleIndex", &start, &end)) { + return nullptr; + } + + if (!removeDataCheck(start, end, m_array->GetTriangleIndexCount(), "slot.removeTriangleIndex(start, end)")) { + return nullptr; + } + + m_array->RemoveTriangleIndex(start, end); + + Py_RETURN_NONE; +} + +PyObject *KX_MeshBuilderSlot::PyRecalculateNormals() +{ + if (Invalid()) { + PyErr_SetString(PyExc_TypeError, "slot.recalculateNormals(): slot has an invalid number of indices"); + return nullptr; + } + + std::vector > normals(m_array->GetVertexCount(), mt::zero3); + + for (unsigned int i = 0, size = m_array->GetPrimitiveIndexCount(); i < size; i += 3) { + float normal[3]; + normal_tri_v3(normal, + m_array->GetPosition(m_array->GetPrimitiveIndex(i)).data, + m_array->GetPosition(m_array->GetPrimitiveIndex(i + 1)).data, + m_array->GetPosition(m_array->GetPrimitiveIndex(i + 2)).data); + + const mt::vec3 vnormal(normal); + for (unsigned short j = 0; j < 3; ++j) { + normals[m_array->GetPrimitiveIndex(i + j)] += vnormal; + } + } + + for (unsigned int i = 0, size = normals.size(); i < size; ++i) { + m_array->SetNormal(i, normals[i].SafeNormalized(mt::zero3)); + } + + Py_RETURN_NONE; +} + +KX_MeshBuilder::KX_MeshBuilder(const std::string& name, KX_Scene *scene, const RAS_Mesh::LayersInfo& layersInfo, + const RAS_DisplayArray::Format& format) + :m_name(name), + m_layersInfo(layersInfo), + m_format(format), + m_scene(scene), + m_origIndexCounter(0) +{ +} + +KX_MeshBuilder::KX_MeshBuilder(const std::string& name, KX_Mesh *mesh) + :m_name(name), + m_layersInfo(mesh->GetLayersInfo()), + m_scene(mesh->GetScene()) +{ + m_format = {(uint8_t)max_ii(m_layersInfo.uvLayers.size(), 1), (uint8_t)max_ii(m_layersInfo.colorLayers.size(), 1)}; + + for (RAS_MeshMaterial *meshmat : mesh->GetMeshMaterialList()) { + KX_MeshBuilderSlot *slot = new KX_MeshBuilderSlot(meshmat, m_format, m_origIndexCounter); + m_slots.Add(slot); + } +} + +KX_MeshBuilder::~KX_MeshBuilder() +{ +} + +std::string KX_MeshBuilder::GetName() +{ + return m_name; +} + +EXP_ListValue& KX_MeshBuilder::GetSlots() +{ + return m_slots; +} + +static bool convertPythonListToLayers(PyObject *list, KX_Mesh::LayerList& layers, const std::string& errmsg) +{ + if (list == Py_None) { + return true; + } + + if (!PySequence_Check(list)) { + PyErr_Format(PyExc_TypeError, "%s expected a list", errmsg.c_str()); + return false; + } + + const unsigned short size = PySequence_Size(list); + if (size > RAS_Texture::MaxUnits) { + PyErr_Format(PyExc_TypeError, "%s excepted a list of maximum %i items", errmsg.c_str(), RAS_Texture::MaxUnits); + return false; + } + + for (unsigned short i = 0; i < size; ++i) { + PyObject *value = PySequence_GetItem(list, i); + + if (!PyUnicode_Check(value)) { + PyErr_Format(PyExc_TypeError, "%s excepted a list of string", errmsg.c_str()); + } + + const std::string name = std::string(_PyUnicode_AsString(value)); + layers.push_back({i, name}); + } + + return true; +} + +static PyObject *py_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + const char *name; + PyObject *pyscene; + PyObject *pyuvs = Py_None; + PyObject *pycolors = Py_None; + + if (!EXP_ParseTupleArgsAndKeywords(args, kwds, "sO|OO:KX_MeshBuilder", + {"name", "scene", "uvs", "colors", 0}, &name, &pyscene, &pyuvs, &pycolors)) + { + return nullptr; + } + + KX_Scene *scene; + if (!ConvertPythonToScene(pyscene, &scene, false, "KX_MeshBuilder(name, scene, uvs, colors): scene must be KX_Scene")) { + return nullptr; + } + + KX_Mesh::LayersInfo layersInfo; + if (!convertPythonListToLayers(pyuvs, layersInfo.uvLayers, "KX_MeshBuilder(name, scene, uvs, colors): uvs:") || + !convertPythonListToLayers(pycolors, layersInfo.colorLayers, "KX_MeshBuilder(name, scene, uvs, colors): colors:")) + { + return nullptr; + } + + RAS_DisplayArray::Format format{(uint8_t)max_ii(layersInfo.uvLayers.size(), 1), (uint8_t)max_ii(layersInfo.colorLayers.size(), 1)}; + + KX_MeshBuilder *builder = new KX_MeshBuilder(name, scene, layersInfo, format); + + return builder->NewProxy(true); +} + +static PyObject *py_new_from_mesh(PyObject *UNUSED(self), PyObject *args) +{ + PyObject *pymesh; + const char *name; + + if (!PyArg_ParseTuple(args, "sO:FromMesh", &name, &pymesh)) { + return nullptr; + } + + KX_Mesh *mesh; + if (!ConvertPythonToMesh(KX_GetActiveScene()->GetLogicManager(), pymesh, &mesh, false, "KX_MeshBuilder.FromMesh")) { + return nullptr; + } + + KX_MeshBuilder *builder = new KX_MeshBuilder(name, mesh); + + return builder->NewProxy(true); +} + +PyTypeObject KX_MeshBuilder::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_MeshBuilder", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &EXP_Value::Type, + 0, 0, 0, 0, 0, 0, + py_new +}; + +PyMethodDef KX_MeshBuilder::Methods[] = { + {"FromMesh", (PyCFunction)py_new_from_mesh, METH_STATIC | METH_VARARGS}, + {"addSlot", (PyCFunction)KX_MeshBuilder::sPyAddSlot, METH_VARARGS | METH_KEYWORDS}, + {"finish", (PyCFunction)KX_MeshBuilder::sPyFinish, METH_NOARGS}, + {nullptr, nullptr} // Sentinel +}; + +PyAttributeDef KX_MeshBuilder::Attributes[] = { + EXP_PYATTRIBUTE_RO_FUNCTION("slots", KX_MeshBuilder, pyattr_get_slots), + EXP_PYATTRIBUTE_NULL // Sentinel +}; + +PyObject *KX_MeshBuilder::pyattr_get_slots(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_MeshBuilder *self = static_cast(self_v); + return self->GetSlots().GetProxy(); +} + +PyObject *KX_MeshBuilder::PyAddSlot(PyObject *args, PyObject *kwds) +{ + PyObject *pymat; + int primitive; + + if (!EXP_ParseTupleArgsAndKeywords(args, kwds, "O|i:addSlot", {"material", "primitive", 0}, &pymat, &primitive)) { + return nullptr; + } + + KX_BlenderMaterial *material; + if (!ConvertPythonToMaterial(pymat, &material, false, "meshBuilder.addSlot(...): material must be a KX_BlenderMaterial")) { + return nullptr; + } + + if (!ELEM(primitive, RAS_DisplayArray::LINES, RAS_DisplayArray::TRIANGLES)) { + PyErr_SetString(PyExc_TypeError, "meshBuilder.addSlot(...): primitive value invalid"); + return nullptr; + } + + KX_MeshBuilderSlot *slot = new KX_MeshBuilderSlot(material, (RAS_DisplayArray::PrimitiveType)primitive, m_format, m_origIndexCounter); + m_slots.Add(slot); + + return slot->GetProxy(); +} + +PyObject *KX_MeshBuilder::PyFinish() +{ + if (m_slots.GetCount() == 0) { + PyErr_SetString(PyExc_TypeError, "meshBuilder.finish(): no mesh data found"); + return nullptr; + } + + for (KX_MeshBuilderSlot *slot : m_slots) { + if (slot->Invalid()) { + PyErr_Format(PyExc_TypeError, "meshBuilder.finish(): slot (%s) has an invalid number of indices", + slot->GetName().c_str()); + return nullptr; + } + } + + KX_Mesh *mesh = new KX_Mesh(m_scene, m_name, m_layersInfo); + + RAS_BucketManager *bucketManager = m_scene->GetBucketManager(); + for (unsigned short i = 0, size = m_slots.GetCount(); i < size; ++i) { + KX_MeshBuilderSlot *slot = m_slots.GetValue(i); + bool created; + RAS_MaterialBucket *bucket = bucketManager->FindBucket(slot->GetMaterial(), created); + mesh->AddMaterial(bucket, i, slot->GetDisplayArray()); + } + + mesh->EndConversion(m_scene->GetBoundingBoxManager()); + + KX_GetActiveEngine()->GetConverter()->RegisterMesh(m_scene, mesh); + + return mesh->GetProxy(); +} + diff --git a/source/gameengine/Ketsji/KX_MeshBuilder.h b/source/gameengine/Ketsji/KX_MeshBuilder.h new file mode 100644 index 000000000000..0bb4ab88727b --- /dev/null +++ b/source/gameengine/Ketsji/KX_MeshBuilder.h @@ -0,0 +1,117 @@ +#ifndef __KX_MESH_BUILDER_H__ +#define __KX_MESH_BUILDER_H__ + +#include "KX_Mesh.h" +#include "RAS_DisplayArray.h" + +#include "EXP_ListValue.h" + +class KX_BlenderMaterial; + +/** \brief Helper python class used to register vertices and indices + * along a material into a mesh. + */ +class KX_MeshBuilderSlot : public EXP_Value +{ + Py_Header + +private: + /// The material used by this slot. + KX_BlenderMaterial *m_material; + /// Array owning vertices and indices data. + RAS_DisplayArray *m_array; + /// Counter used to compute the original index of new added vertices. + unsigned int& m_origIndexCounter; + +public: + KX_MeshBuilderSlot(KX_BlenderMaterial *material, RAS_DisplayArray::PrimitiveType primitiveType, + const RAS_DisplayArray::Format& format, unsigned int& origIndexCounter); + KX_MeshBuilderSlot(RAS_MeshMaterial *meshmat, const RAS_DisplayArray::Format& format, unsigned int& origIndexCounter); + ~KX_MeshBuilderSlot(); + + virtual std::string GetName(); + + KX_BlenderMaterial *GetMaterial() const; + void SetMaterial(KX_BlenderMaterial *material); + + /// Return true if the number of indices doesn't match the primitive type used. + bool Invalid() const; + + RAS_DisplayArray *GetDisplayArray() const; + +#ifdef WITH_PYTHON + + using GetSizeFunc = unsigned int (RAS_DisplayArray::*)() const; + using GetIndexFunc = unsigned int (RAS_DisplayArray::*)(const unsigned int) const; + + template + unsigned int get_size_cb(); + PyObject *get_item_vertices_cb(unsigned int index); + template + PyObject *get_item_indices_cb(unsigned int index); + + static PyObject *pyattr_get_vertices(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_indices(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_triangleIndices(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_material(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_material(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_uvCount(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_colorCount(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_primitive(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + + EXP_PYMETHOD(KX_MeshBuilderSlot, AddVertex); + EXP_PYMETHOD_VARARGS(KX_MeshBuilderSlot, RemoveVertex); + EXP_PYMETHOD_O(KX_MeshBuilderSlot, AddIndex); + EXP_PYMETHOD_O(KX_MeshBuilderSlot, AddPrimitiveIndex); + EXP_PYMETHOD_VARARGS(KX_MeshBuilderSlot, RemovePrimitiveIndex); + EXP_PYMETHOD_O(KX_MeshBuilderSlot, AddTriangleIndex); + EXP_PYMETHOD_VARARGS(KX_MeshBuilderSlot, RemoveTriangleIndex); + EXP_PYMETHOD_NOARGS(KX_MeshBuilderSlot, RecalculateNormals); + +#endif // WITH_PYTHON +}; + +/** \brief Helper python class used to construct meshes. + * The user instantiate it, add data and call conversion to mesh at the end. + */ +class KX_MeshBuilder : public EXP_Value +{ + Py_Header + +private: + std::string m_name; + + /// Mesh data partitioned per slot/material. + EXP_ListValue m_slots; + /// The uv and color layers used by the mesh, should match with the one used in the materials. + RAS_Mesh::LayersInfo m_layersInfo; + /// Vertex format, deduced from the layers info. + RAS_DisplayArray::Format m_format; + + /// The scene to register along the new mesh. + KX_Scene *m_scene; + + /// Counter shared by all the slots to compute the original index of a new added vertex. + unsigned int m_origIndexCounter; + +public: + KX_MeshBuilder(const std::string& name, KX_Scene *scene, const RAS_Mesh::LayersInfo& layersInfo, + const RAS_DisplayArray::Format& format); + KX_MeshBuilder(const std::string& name, KX_Mesh *mesh); + ~KX_MeshBuilder(); + + virtual std::string GetName(); + + EXP_ListValue& GetSlots(); + +#ifdef WITH_PYTHON + + static PyObject *pyattr_get_slots(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + + EXP_PYMETHOD(KX_MeshBuilder, AddSlot); + EXP_PYMETHOD_NOARGS(KX_MeshBuilder, Finish); + +#endif // WITH_PYTHON +}; + +#endif // __KX_MESH_BUILDER_H__ diff --git a/source/gameengine/Ketsji/KX_MeshProxy.cpp b/source/gameengine/Ketsji/KX_MeshProxy.cpp deleted file mode 100644 index ceec7fbb07a4..000000000000 --- a/source/gameengine/Ketsji/KX_MeshProxy.cpp +++ /dev/null @@ -1,464 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Ketsji/KX_MeshProxy.cpp - * \ingroup ketsji - */ - - -#ifdef WITH_PYTHON - -#include "KX_MeshProxy.h" -#include "RAS_IPolygonMaterial.h" -#include "RAS_MeshObject.h" - -#include "KX_VertexProxy.h" -#include "KX_PolyProxy.h" - -#include "KX_BlenderMaterial.h" - -#include "KX_PyMath.h" - -#include "SCA_LogicManager.h" - -#include "EXP_PyObjectPlus.h" - -PyTypeObject KX_MeshProxy::Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "KX_MeshProxy", - sizeof(PyObjectPlus_Proxy), - 0, - py_base_dealloc, - 0, - 0, - 0, - 0, - py_base_repr, - 0,0,0,0,0,0,0,0,0, - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, - Methods, - 0, - 0, - &CValue::Type, - 0,0,0,0,0,0, - py_base_new -}; - -PyMethodDef KX_MeshProxy::Methods[] = { - {"getMaterialName", (PyCFunction)KX_MeshProxy::sPyGetMaterialName,METH_VARARGS}, - {"getTextureName", (PyCFunction)KX_MeshProxy::sPyGetTextureName,METH_VARARGS}, - {"getVertexArrayLength", (PyCFunction)KX_MeshProxy::sPyGetVertexArrayLength,METH_VARARGS}, - {"getVertex", (PyCFunction)KX_MeshProxy::sPyGetVertex,METH_VARARGS}, - {"getPolygon", (PyCFunction)KX_MeshProxy::sPyGetPolygon,METH_VARARGS}, - {"transform", (PyCFunction)KX_MeshProxy::sPyTransform,METH_VARARGS}, - {"transformUV", (PyCFunction)KX_MeshProxy::sPyTransformUV,METH_VARARGS}, - //{"getIndexArrayLength", (PyCFunction)KX_MeshProxy::sPyGetIndexArrayLength,METH_VARARGS}, - {NULL,NULL} //Sentinel -}; - -PyAttributeDef KX_MeshProxy::Attributes[] = { - KX_PYATTRIBUTE_RO_FUNCTION("materials", KX_MeshProxy, pyattr_get_materials), - KX_PYATTRIBUTE_RO_FUNCTION("numPolygons", KX_MeshProxy, pyattr_get_numPolygons), - KX_PYATTRIBUTE_RO_FUNCTION("numMaterials", KX_MeshProxy, pyattr_get_numMaterials), - - { NULL } //Sentinel -}; - -void KX_MeshProxy::SetMeshModified(bool v) -{ - m_meshobj->SetMeshModified(v); -} - -KX_MeshProxy::KX_MeshProxy(RAS_MeshObject* mesh) - : CValue(), m_meshobj(mesh) -{ -} - -KX_MeshProxy::~KX_MeshProxy() -{ -} - - - -// stuff for cvalue related things -CValue* KX_MeshProxy::Calc(VALUE_OPERATOR op, CValue *val) { return NULL;} -CValue* KX_MeshProxy::CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val) { return NULL;} - -const STR_String & KX_MeshProxy::GetText() {return m_meshobj->GetName();}; -double KX_MeshProxy::GetNumber() { return -1;} -STR_String& KX_MeshProxy::GetName() { return m_meshobj->GetName();} -void KX_MeshProxy::SetName(const char *name) { }; -CValue* KX_MeshProxy::GetReplica() { return NULL;} - - -// stuff for python integration - -PyObject *KX_MeshProxy::PyGetMaterialName(PyObject *args, PyObject *kwds) -{ - int matid= 1; - STR_String matname; - - if (PyArg_ParseTuple(args,"i:getMaterialName",&matid)) - { - matname = m_meshobj->GetMaterialName(matid); - } - else { - return NULL; - } - - return PyUnicode_From_STR_String(matname); - -} - - -PyObject *KX_MeshProxy::PyGetTextureName(PyObject *args, PyObject *kwds) -{ - int matid= 1; - STR_String matname; - - if (PyArg_ParseTuple(args,"i:getTextureName",&matid)) - { - matname = m_meshobj->GetTextureName(matid); - } - else { - return NULL; - } - - return PyUnicode_From_STR_String(matname); - -} - -PyObject *KX_MeshProxy::PyGetVertexArrayLength(PyObject *args, PyObject *kwds) -{ - int matid= 0; - int length = 0; - - - if (!PyArg_ParseTuple(args,"i:getVertexArrayLength",&matid)) - return NULL; - - - RAS_MeshMaterial *mmat = m_meshobj->GetMeshMaterial(matid); /* can be NULL*/ - - if (mmat) - { - RAS_IPolyMaterial* mat = mmat->m_bucket->GetPolyMaterial(); - if (mat) - length = m_meshobj->NumVertices(mat); - } - - return PyLong_FromLong(length); -} - - -PyObject *KX_MeshProxy::PyGetVertex(PyObject *args, PyObject *kwds) -{ - int vertexindex; - int matindex; - - if (!PyArg_ParseTuple(args,"ii:getVertex",&matindex,&vertexindex)) - return NULL; - - RAS_TexVert* vertex = m_meshobj->GetVertex(matindex,vertexindex); - - if (vertex==NULL) { - PyErr_SetString(PyExc_ValueError, "mesh.getVertex(mat_idx, vert_idx): KX_MeshProxy, could not get a vertex at the given indices"); - return NULL; - } - - return (new KX_VertexProxy(this, vertex))->NewProxy(true); -} - -PyObject *KX_MeshProxy::PyGetPolygon(PyObject *args, PyObject *kwds) -{ - int polyindex= 1; - PyObject *polyob = NULL; - - if (!PyArg_ParseTuple(args,"i:getPolygon",&polyindex)) - return NULL; - - if (polyindex<0 || polyindex >= m_meshobj->NumPolygons()) - { - PyErr_SetString(PyExc_AttributeError, "mesh.getPolygon(int): KX_MeshProxy, invalid polygon index"); - return NULL; - } - - - RAS_Polygon* polygon = m_meshobj->GetPolygon(polyindex); - if (polygon) - { - polyob = (new KX_PolyProxy(m_meshobj, polygon))->NewProxy(true); - } - else { - PyErr_SetString(PyExc_AttributeError, "mesh.getPolygon(int): KX_MeshProxy, polygon is NULL, unknown reason"); - } - return polyob; -} - -PyObject *KX_MeshProxy::PyTransform(PyObject *args, PyObject *kwds) -{ - int matindex; - PyObject *pymat; - bool ok = false; - - MT_Matrix4x4 transform; - - if (!PyArg_ParseTuple(args,"iO:transform", &matindex, &pymat) || - !PyMatTo(pymat, transform)) - { - return NULL; - } - - MT_Matrix4x4 ntransform = transform.inverse().transposed(); - ntransform[0][3] = ntransform[1][3] = ntransform[2][3] = 0.0f; - - /* transform mesh verts */ - unsigned int mit_index = 0; - for (list::iterator mit = m_meshobj->GetFirstMaterial(); - (mit != m_meshobj->GetLastMaterial()); - ++mit, ++mit_index) - { - if (matindex == -1) { - /* always transform */ - } - else if (matindex == mit_index) { - /* we found the right index! */ - } - else { - continue; - } - - RAS_MeshSlot *slot = mit->m_baseslot; - RAS_MeshSlot::iterator it; - ok = true; - - for (slot->begin(it); !slot->end(it); slot->next(it)) { - size_t i; - for (i = it.startvertex; i < it.endvertex; i++) { - RAS_TexVert *vert = &it.vertex[i]; - vert->Transform(transform, ntransform); - } - } - - /* if we set a material index, quit when done */ - if (matindex == mit_index) { - break; - } - } - - if (ok == false) { - PyErr_Format(PyExc_ValueError, - "mesh.transform(...): invalid material index %d", matindex); - return NULL; - } - - m_meshobj->SetMeshModified(true); - - Py_RETURN_NONE; -} - -PyObject *KX_MeshProxy::PyTransformUV(PyObject *args, PyObject *kwds) -{ - int matindex; - PyObject *pymat; - int uvindex = -1; - int uvindex_from = -1; - bool ok = false; - - MT_Matrix4x4 transform; - - if (!PyArg_ParseTuple(args,"iO|iii:transformUV", &matindex, &pymat, &uvindex, &uvindex_from) || - !PyMatTo(pymat, transform)) - { - return NULL; - } - - if (uvindex < -1 || uvindex > 1) { - PyErr_Format(PyExc_ValueError, - "mesh.transformUV(...): invalid uv_index %d", uvindex); - return NULL; - } - if (uvindex_from < -1 || uvindex_from > 1) { - PyErr_Format(PyExc_ValueError, - "mesh.transformUV(...): invalid uv_index_from %d", uvindex); - return NULL; - } - if (uvindex_from == uvindex) { - uvindex_from = -1; - } - - /* transform mesh verts */ - unsigned int mit_index = 0; - for (list::iterator mit = m_meshobj->GetFirstMaterial(); - (mit != m_meshobj->GetLastMaterial()); - ++mit, ++mit_index) - { - if (matindex == -1) { - /* always transform */ - } - else if (matindex == mit_index) { - /* we found the right index! */ - } - else { - continue; - } - - RAS_MeshSlot *slot = mit->m_baseslot; - RAS_MeshSlot::iterator it; - ok = true; - - for (slot->begin(it); !slot->end(it); slot->next(it)) { - size_t i; - - for (i = it.startvertex; i < it.endvertex; i++) { - RAS_TexVert *vert = &it.vertex[i]; - if (uvindex_from != -1) { - if (uvindex_from == 0) vert->SetUV(1, vert->getUV(0)); - else vert->SetUV(0, vert->getUV(1)); - } - - switch (uvindex) { - case 0: - vert->TransformUV(0, transform); - break; - case 1: - vert->TransformUV(1, transform); - break; - case -1: - vert->TransformUV(0, transform); - vert->TransformUV(1, transform); - break; - } - } - } - - /* if we set a material index, quit when done */ - if (matindex == mit_index) { - break; - } - } - - if (ok == false) { - PyErr_Format(PyExc_ValueError, - "mesh.transformUV(...): invalid material index %d", matindex); - return NULL; - } - - m_meshobj->SetMeshModified(true); - - Py_RETURN_NONE; -} - -PyObject *KX_MeshProxy::pyattr_get_materials(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_MeshProxy* self = static_cast(self_v); - - int tot= self->m_meshobj->NumMaterials(); - int i; - - PyObject *materials = PyList_New( tot ); - - list::iterator mit= self->m_meshobj->GetFirstMaterial(); - - - for (i=0; im_bucket->GetPolyMaterial(); - KX_BlenderMaterial *mat = static_cast(polymat); - PyList_SET_ITEM(materials, i, mat->GetProxy()); - } - return materials; -} - -PyObject *KX_MeshProxy::pyattr_get_numMaterials(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_MeshProxy * self = static_cast (self_v); - return PyLong_FromLong(self->m_meshobj->NumMaterials()); -} - -PyObject *KX_MeshProxy::pyattr_get_numPolygons(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_MeshProxy * self = static_cast (self_v); - return PyLong_FromLong(self->m_meshobj->NumPolygons()); -} - -/* a close copy of ConvertPythonToGameObject but for meshes */ -bool ConvertPythonToMesh(SCA_LogicManager *logicmgr, PyObject *value, RAS_MeshObject **object, bool py_none_ok, const char *error_prefix) -{ - if (value==NULL) { - PyErr_Format(PyExc_TypeError, "%s, python pointer NULL, should never happen", error_prefix); - *object = NULL; - return false; - } - - if (value==Py_None) { - *object = NULL; - - if (py_none_ok) { - return true; - } else { - PyErr_Format(PyExc_TypeError, "%s, expected KX_MeshProxy or a KX_MeshProxy name, None is invalid", error_prefix); - return false; - } - } - - if (PyUnicode_Check(value)) { - *object = (RAS_MeshObject*)logicmgr->GetMeshByName(STR_String( _PyUnicode_AsString(value) )); - - if (*object) { - return true; - } else { - PyErr_Format(PyExc_ValueError, "%s, requested name \"%s\" did not match any KX_MeshProxy in this scene", error_prefix, _PyUnicode_AsString(value)); - return false; - } - } - - if (PyObject_TypeCheck(value, &KX_MeshProxy::Type)) { - KX_MeshProxy *kx_mesh = static_castBGE_PROXY_REF(value); - - /* sets the error */ - if (kx_mesh==NULL) { - PyErr_Format(PyExc_SystemError, "%s, " BGE_PROXY_ERROR_MSG, error_prefix); - return false; - } - - *object = kx_mesh->GetMesh(); - return true; - } - - *object = NULL; - - if (py_none_ok) { - PyErr_Format(PyExc_TypeError, "%s, expect a KX_MeshProxy, a string or None", error_prefix); - } else { - PyErr_Format(PyExc_TypeError, "%s, expect a KX_MeshProxy or a string", error_prefix); - } - - return false; -} - -#endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_MeshProxy.h b/source/gameengine/Ketsji/KX_MeshProxy.h deleted file mode 100644 index f634834a2b6a..000000000000 --- a/source/gameengine/Ketsji/KX_MeshProxy.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file KX_MeshProxy.h - * \ingroup ketsji - */ - -#ifndef __KX_MESHPROXY_H__ -#define __KX_MESHPROXY_H__ - -#ifdef WITH_PYTHON - -#include "SCA_IObject.h" - -class SCA_LogicManager; -/* utility conversion function */ -bool ConvertPythonToMesh(SCA_LogicManager *logicmgr, PyObject *value, class RAS_MeshObject **object, bool py_none_ok, const char *error_prefix); - -class KX_MeshProxy : public CValue -{ - Py_Header - - class RAS_MeshObject* m_meshobj; -public: - KX_MeshProxy(class RAS_MeshObject* mesh); - virtual ~KX_MeshProxy(); - - void SetMeshModified(bool v); - - // stuff for cvalue related things - virtual CValue* Calc(VALUE_OPERATOR op, CValue *val); - virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); - virtual const STR_String & GetText(); - virtual double GetNumber(); - virtual RAS_MeshObject* GetMesh() { return m_meshobj; } - virtual STR_String& GetName(); - virtual void SetName(const char *name); // Set the name of the value - virtual CValue* GetReplica(); - -// stuff for python integration - - KX_PYMETHOD(KX_MeshProxy,GetNumMaterials); // Deprecated - KX_PYMETHOD(KX_MeshProxy,GetMaterialName); - KX_PYMETHOD(KX_MeshProxy,GetTextureName); - KX_PYMETHOD_NOARGS(KX_MeshProxy,GetNumPolygons); // Deprecated - - // both take materialid (int) - KX_PYMETHOD(KX_MeshProxy,GetVertexArrayLength); - KX_PYMETHOD(KX_MeshProxy,GetVertex); - KX_PYMETHOD(KX_MeshProxy,GetPolygon); - KX_PYMETHOD(KX_MeshProxy,Transform); - KX_PYMETHOD(KX_MeshProxy,TransformUV); - - static PyObject *pyattr_get_materials(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_numMaterials(void *self, const KX_PYATTRIBUTE_DEF * attrdef); - static PyObject *pyattr_get_numPolygons(void *self, const KX_PYATTRIBUTE_DEF * attrdef); -}; - -#endif /* WITH_PYTHON */ - -#endif /* __KX_MESHPROXY_H__ */ diff --git a/source/gameengine/Ketsji/KX_MotionState.cpp b/source/gameengine/Ketsji/KX_MotionState.cpp index 922643cb13d4..d555a0c2e849 100644 --- a/source/gameengine/Ketsji/KX_MotionState.cpp +++ b/source/gameengine/Ketsji/KX_MotionState.cpp @@ -30,75 +30,52 @@ */ #include "KX_MotionState.h" -#include "SG_Spatial.h" +#include "SG_Node.h" -KX_MotionState::KX_MotionState(SG_Spatial* node) : m_node(node) +KX_MotionState::KX_MotionState(SG_Node *node) + :m_node(node) { - } KX_MotionState::~KX_MotionState() { } -void KX_MotionState::GetWorldPosition(float& posX,float& posY,float& posZ) -{ - const MT_Point3& pos = m_node->GetWorldPosition(); - posX = pos[0]; - posY = pos[1]; - posZ = pos[2]; -} - -void KX_MotionState::GetWorldScaling(float& scaleX,float& scaleY,float& scaleZ) +mt::vec3 KX_MotionState::GetWorldPosition() const { - const MT_Vector3& scale = m_node->GetWorldScaling(); - scaleX = scale[0]; - scaleY = scale[1]; - scaleZ = scale[2]; + return m_node->GetWorldPosition(); } -void KX_MotionState::GetWorldOrientation(float& quatIma0,float& quatIma1,float& quatIma2,float& quatReal) +mt::vec3 KX_MotionState::GetWorldScaling() const { - MT_Quaternion orn = m_node->GetWorldOrientation().getRotation(); - quatIma0 = orn[0]; - quatIma1 = orn[1]; - quatIma2 = orn[2]; - quatReal = orn[3]; + return m_node->GetWorldScaling(); } -void KX_MotionState::GetWorldOrientation(float* ori) +mt::mat3 KX_MotionState::GetWorldOrientation() const { - const MT_Matrix3x3& mat = m_node->GetWorldOrientation(); - mat.getValue(ori); + return m_node->GetWorldOrientation(); } -void KX_MotionState::SetWorldOrientation(const float* ori) +void KX_MotionState::SetWorldOrientation(const mt::mat3& ori) { m_node->SetLocalOrientation(ori); } -void KX_MotionState::SetWorldPosition(float posX,float posY,float posZ) +void KX_MotionState::SetWorldPosition(const mt::vec3& pos) { - m_node->SetLocalPosition(MT_Point3(posX,posY,posZ)); - //m_node->SetWorldPosition(MT_Point3(posX,posY,posZ)); + m_node->SetLocalPosition(pos); } -void KX_MotionState::SetWorldOrientation(float quatIma0,float quatIma1,float quatIma2,float quatReal) +void KX_MotionState::SetWorldOrientation(const mt::quat& quat) { - MT_Quaternion orn; - orn[0] = quatIma0; - orn[1] = quatIma1; - orn[2] = quatIma2; - orn[3] = quatReal; - - m_node->SetLocalOrientation(orn); - //m_node->SetWorldOrientation(orn); - + m_node->SetLocalOrientation(quat.ToMatrix()); } -void KX_MotionState::CalculateWorldTransformations() +void KX_MotionState::CalculateWorldTransformations() { //Not needed, will be done in KX_Scene::UpdateParents() after the physics simulation //bool parentUpdated = false; - //m_node->ComputeWorldTransforms(NULL, parentUpdated); + //m_node->ComputeWorldTransforms(nullptr, parentUpdated); } + + diff --git a/source/gameengine/Ketsji/KX_MotionState.h b/source/gameengine/Ketsji/KX_MotionState.h index 38046fe4ff93..1f7adc7ae150 100644 --- a/source/gameengine/Ketsji/KX_MotionState.h +++ b/source/gameengine/Ketsji/KX_MotionState.h @@ -34,32 +34,25 @@ #include "PHY_IMotionState.h" -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif +class SG_Node; class KX_MotionState : public PHY_IMotionState { - class SG_Spatial* m_node; + SG_Node *m_node; public: - KX_MotionState(class SG_Spatial* spatial); + KX_MotionState(SG_Node *spatial); virtual ~KX_MotionState(); - virtual void GetWorldPosition(float& posX,float& posY,float& posZ); - virtual void GetWorldScaling(float& scaleX,float& scaleY,float& scaleZ); - virtual void GetWorldOrientation(float& quatIma0,float& quatIma1,float& quatIma2,float& quatReal); - virtual void SetWorldPosition(float posX,float posY,float posZ); - virtual void SetWorldOrientation(float quatIma0,float quatIma1,float quatIma2,float quatReal); - virtual void GetWorldOrientation(float* ori); - virtual void SetWorldOrientation(const float* ori); + virtual mt::vec3 GetWorldPosition() const; + virtual mt::vec3 GetWorldScaling() const; + virtual mt::mat3 GetWorldOrientation() const; - virtual void CalculateWorldTransformations(); + virtual void SetWorldPosition(const mt::vec3& pos); + virtual void SetWorldOrientation(const mt::mat3& ori); + virtual void SetWorldOrientation(const mt::quat& quat); - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_MotionState") -#endif + virtual void CalculateWorldTransformations(); }; -#endif /* __KX_MOTIONSTATE_H__ */ +#endif // __KX_MOTIONSTATE_H__ diff --git a/source/gameengine/Ketsji/KX_MouseActuator.cpp b/source/gameengine/Ketsji/KX_MouseActuator.cpp index 6aa0d588b506..dea9ab9bfae1 100644 --- a/source/gameengine/Ketsji/KX_MouseActuator.cpp +++ b/source/gameengine/Ketsji/KX_MouseActuator.cpp @@ -22,13 +22,13 @@ #include "KX_MouseActuator.h" #include "KX_KetsjiEngine.h" +#include "KX_PyMath.h" #include "SCA_MouseManager.h" #include "SCA_IInputDevice.h" #include "RAS_ICanvas.h" #include "KX_GameObject.h" -#include "MT_Vector3.h" -#include "MT_Scalar.h" -#include "MT_assert.h" +#include "KX_PyMath.h" +#include "BLI_utildefines.h" #include "limits.h" #include "BLI_math.h" @@ -41,48 +41,29 @@ /* Native functions */ /* ------------------------------------------------------------------------- */ -KX_MouseActuator::KX_MouseActuator( - SCA_IObject* gameobj, - - KX_KetsjiEngine* ketsjiEngine, - SCA_MouseManager* eventmgr, - int acttype, - bool visible, - bool* use_axis, - float* threshold, - bool* reset, - int* object_axis, - bool* local, - float* sensitivity, - float* limit_x, - float* limit_y -): - SCA_IActuator(gameobj, KX_ACT_MOUSE), +KX_MouseActuator::KX_MouseActuator(SCA_IObject* gameobj, KX_KetsjiEngine* ketsjiEngine, SCA_MouseManager* eventmgr, + int acttype, bool visible, const bool use_axis[2], const mt::vec2& threshold, const bool reset[2], + const int object_axis[2], const bool local[2], const mt::vec2& sensitivity, const mt::vec2 limit[2]) + :SCA_IActuator(gameobj, KX_ACT_MOUSE), m_ketsji(ketsjiEngine), m_eventmgr(eventmgr), m_type(acttype), m_visible(visible), - m_use_axis_x(use_axis[0]), - m_use_axis_y(use_axis[1]), - m_reset_x(reset[0]), - m_reset_y(reset[1]), - m_local_x(local[0]), - m_local_y(local[1]) + m_threshold(threshold), + m_sensitivity(sensitivity), + m_initialSkipping(true), + m_oldPosition(mt::zero2), + m_angle(mt::zero2) { + for (unsigned short i = 0; i < 2; ++i) { + m_use_axis[i] = use_axis[i]; + m_reset[i] = reset[i]; + m_object_axis[i] = object_axis[i]; + m_local[i] = local[i]; + m_limit[i] = limit[i]; + } + m_canvas = m_ketsji->GetCanvas(); - m_oldposition[0] = m_oldposition[1] = -1.f; - m_limit_x[0] = limit_x[0]; - m_limit_x[1] = limit_x[1]; - m_limit_y[0] = limit_y[0]; - m_limit_y[1] = limit_y[1]; - m_threshold[0] = threshold[0]; - m_threshold[1] = threshold[1]; - m_object_axis[0] = object_axis[0]; - m_object_axis[1] = object_axis[1]; - m_sensitivity[0] = sensitivity[0]; - m_sensitivity[1] = sensitivity[1]; - m_angle[0] = 0.f; - m_angle[1] = 0.f; } KX_MouseActuator::~KX_MouseActuator() @@ -91,13 +72,14 @@ KX_MouseActuator::~KX_MouseActuator() bool KX_MouseActuator::Update() { - bool result = false; - bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); - if (bNegativeEvent) - return false; // do nothing on negative events + if (bNegativeEvent) { + // Reset initial skipping check on negative events. + m_initialSkipping = true; + return false; + } KX_GameObject *parent = static_cast(GetParent()); @@ -122,191 +104,113 @@ bool KX_MouseActuator::Update() { if (m_mouse) { - float position[2]; - float movement[2]; - MT_Vector3 rotation; - float setposition[2] = {0.0f}; - float center_x = 0.5f, center_y = 0.5f; - - getMousePosition(position); - - movement[0] = position[0]; - movement[1] = position[1]; + const mt::vec2 position = GetMousePosition(); + mt::vec2 movement = position; + mt::vec3 rotation; + mt::vec2 setposition = mt::zero2; + + mt::vec2 center(0.5f, 0.5f); //preventing undesired drifting when resolution is odd - if ((m_canvas->GetWidth() % 2) != 0) { - center_x = ((m_canvas->GetWidth() - 1.0f) / 2.0f) / (m_canvas->GetWidth()); + if ((m_canvas->GetWidth() % 2) == 0) { + center.x = float(m_canvas->GetMaxX() / 2) / m_canvas->GetMaxX(); } - if ((m_canvas->GetHeight() % 2) != 0) { - center_y = ((m_canvas->GetHeight() - 1.0f) / 2.0f) / (m_canvas->GetHeight()); + if ((m_canvas->GetHeight() % 2) == 0) { + center.y = float(m_canvas->GetMaxY() / 2) / m_canvas->GetMaxY(); } //preventing initial skipping. - if ((m_oldposition[0] <= -0.9f) && (m_oldposition[1] <= -0.9f)) { - - if (m_reset_x) { - m_oldposition[0] = center_x; - } - else { - m_oldposition[0] = position[0]; + if (m_initialSkipping) { + for (unsigned short i = 0; i < 2; ++i) { + if (m_reset[i]) { + m_oldPosition[i] = center[i]; + } + else { + m_oldPosition[i] = position[i]; + } } - if (m_reset_y) { - m_oldposition[1] = center_y; - } - else { - m_oldposition[1] = position[1]; - } - setMousePosition(m_oldposition[0], m_oldposition[1]); + SetMousePosition(m_oldPosition); + m_initialSkipping = false; break; } - //Calculating X axis. - if (m_use_axis_x) { - - if (m_reset_x) { - setposition[0] = center_x; - movement[0] -= center_x; - } - else { - setposition[0] = position[0]; - movement[0] -= m_oldposition[0]; - } - - movement[0] *= -1.0f; - - /* Don't apply the rotation when we are under a certain threshold for mouse - movement */ - - if (((movement[0] > (m_threshold[0] / 10.0f)) || - ((movement[0] * (-1.0f)) > (m_threshold[0] / 10.0f)))) { - - movement[0] *= m_sensitivity[0]; - - if ((m_limit_x[0] != 0.0f) && ((m_angle[0] + movement[0]) <= m_limit_x[0])) { - movement[0] = m_limit_x[0] - m_angle[0]; - } - - if ((m_limit_x[1] != 0.0f) && ((m_angle[0] + movement[0]) >= m_limit_x[1])) { - movement[0] = m_limit_x[1] - m_angle[0]; + for (unsigned short i = 0; i < 2; ++i) { + if (m_use_axis[i]) { + if (m_reset[i]) { + setposition[i] = center[i]; + movement[i] -= center[i]; } - - m_angle[0] += movement[0]; - - switch (m_object_axis[0]) { - case KX_ACT_MOUSE_OBJECT_AXIS_X: - { - rotation = MT_Vector3(movement[0], 0.0f, 0.0f); - break; - } - case KX_ACT_MOUSE_OBJECT_AXIS_Y: - { - rotation = MT_Vector3(0.0f, movement[0], 0.0f); - break; - } - case KX_ACT_MOUSE_OBJECT_AXIS_Z: - { - rotation = MT_Vector3(0.0f, 0.0f, movement[0]); - break; - } - default: - break; + else { + setposition[i] = position[i]; + movement[i] -= m_oldPosition[i]; } - parent->ApplyRotation(rotation, m_local_x); - } - } - else { - setposition[0] = center_x; - } - - //Calculating Y axis. - if (m_use_axis_y) { - if (m_reset_y) { - setposition[1] = center_y; - movement[1] -= center_y; - } - else { - setposition[1] = position[1]; - movement[1] -= m_oldposition[1]; - } - - movement[1] *= -1.0f; + movement[i] *= -1.0f; - /* Don't apply the rotation when we are under a certain threshold for mouse - movement */ + // Don't apply the rotation when we are under a certain threshold for mouse movement. + if (((movement[i] > (m_threshold[i] / 10.0f)) || + ((movement[i] * (-1.0f)) > (m_threshold[i] / 10.0f)))) { - if (((movement[1] > (m_threshold[1] / 10.0f)) || - ((movement[1] * (-1.0f)) > (m_threshold[1] / 10.0f)))) { - - movement[1] *= m_sensitivity[1]; - - if ((m_limit_y[0] != 0.0f) && ((m_angle[1] + movement[1]) <= m_limit_y[0])) { - movement[1] = m_limit_y[0] - m_angle[1]; - } + movement[i] *= m_sensitivity[i]; - if ((m_limit_y[1] != 0.0f) && ((m_angle[1] + movement[1]) >= m_limit_y[1])) { - movement[1] = m_limit_y[1] - m_angle[1]; - } - - m_angle[1] += movement[1]; - - switch (m_object_axis[1]) - { - case KX_ACT_MOUSE_OBJECT_AXIS_X: - { - rotation = MT_Vector3(movement[1], 0.0f, 0.0f); - break; + if ((m_limit[i][0] != 0.0f) && ((m_angle[i] + movement[i]) <= m_limit[i][0])) { + movement[i] = m_limit[i][0] - m_angle[i]; } - case KX_ACT_MOUSE_OBJECT_AXIS_Y: - { - rotation = MT_Vector3(0.0f, movement[1], 0.0f); - break; + + if ((m_limit[i][1] != 0.0f) && ((m_angle[i] + movement[i]) >= m_limit[i][1])) { + movement[i] = m_limit[i][1] - m_angle[i]; } - case KX_ACT_MOUSE_OBJECT_AXIS_Z: - { - rotation = MT_Vector3(0.0f, 0.0f, movement[1]); - break; + + m_angle[i] += movement[i]; + + switch (m_object_axis[i]) { + case KX_ACT_MOUSE_OBJECT_AXIS_X: + { + rotation = mt::vec3(movement[i], 0.0f, 0.0f); + break; + } + case KX_ACT_MOUSE_OBJECT_AXIS_Y: + { + rotation = mt::vec3(0.0f, movement[i], 0.0f); + break; + } + case KX_ACT_MOUSE_OBJECT_AXIS_Z: + { + rotation = mt::vec3(0.0f, 0.0f, movement[i]); + break; + } + default: + break; } - default: - break; + parent->ApplyRotation(rotation, m_local[i]); } - parent->ApplyRotation(rotation, m_local_y); } - } - else { - setposition[1] = center_y; + else { + setposition[i] = center[i]; + } } // only trigger mouse event when it is necessary - if (m_oldposition[0] != position[0] || m_oldposition[1] != position[1]) { - setMousePosition(setposition[0], setposition[1]); + if (m_oldPosition != position) { + SetMousePosition(setposition); } - m_oldposition[0] = position[0]; - m_oldposition[1] = position[1]; - - } - else { - //printf("\nNo input device detected for mouse actuator\n"); + m_oldPosition = position; } break; } default: + { break; } - return result; -} - -bool KX_MouseActuator::isValid(KX_MouseActuator::KX_ACT_MOUSE_MODE mode) -{ - return ((mode > KX_ACT_MOUSE_NODEF) && (mode < KX_ACT_MOUSE_MAX)); + } + return true; } - -CValue* KX_MouseActuator::GetReplica() +EXP_Value *KX_MouseActuator::GetReplica() { - KX_MouseActuator* replica = new KX_MouseActuator(*this); + KX_MouseActuator *replica = new KX_MouseActuator(*this); replica->ProcessReplica(); return replica; @@ -317,22 +221,32 @@ void KX_MouseActuator::ProcessReplica() SCA_IActuator::ProcessReplica(); } -void KX_MouseActuator::getMousePosition(float* pos) +void KX_MouseActuator::Replace_IScene(SCA_IScene *scene) +{ + /* Changes the event manager when the scene changes in case of lib loading. + * Using an event manager in an actuator is not a regular behaviour which is + * to avoid if it is possible. + */ + SCA_LogicManager *logicmgr = ((KX_Scene *)scene)->GetLogicManager(); + m_eventmgr = (SCA_MouseManager *)logicmgr->FindEventManager(m_eventmgr->GetType()); +} + +mt::vec2 KX_MouseActuator::GetMousePosition() const { - MT_assert(m_mouse); - const SCA_InputEvent & xevent = m_mouse->GetEventValue(SCA_IInputDevice::KX_MOUSEX); - const SCA_InputEvent & yevent = m_mouse->GetEventValue(SCA_IInputDevice::KX_MOUSEY); + BLI_assert(m_mouse); + const SCA_InputEvent & xevent = m_mouse->GetInput(SCA_IInputDevice::MOUSEX); + const SCA_InputEvent & yevent = m_mouse->GetInput(SCA_IInputDevice::MOUSEY); - pos[0] = m_canvas->GetMouseNormalizedX(xevent.m_eventval); - pos[1] = m_canvas->GetMouseNormalizedY(yevent.m_eventval); + return mt::vec2(m_canvas->GetMouseNormalizedX(xevent.m_values[xevent.m_values.size() - 1]), + m_canvas->GetMouseNormalizedY(yevent.m_values[yevent.m_values.size() - 1])); } -void KX_MouseActuator::setMousePosition(float fx, float fy) +void KX_MouseActuator::SetMousePosition(const mt::vec2& pos) { int x, y; - x = (int)(fx * m_canvas->GetWidth()); - y = (int)(fy * m_canvas->GetHeight()); + x = (int)(pos.x * m_canvas->GetMaxX()); + y = (int)(pos.y * m_canvas->GetMaxY()); m_canvas->SetMousePosition(x, y); } @@ -345,9 +259,9 @@ void KX_MouseActuator::setMousePosition(float fx, float fy) /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_MouseActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_MouseActuator", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -355,183 +269,130 @@ PyTypeObject KX_MouseActuator::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IActuator::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_MouseActuator::Methods[] = { - {"reset", (PyCFunction) KX_MouseActuator::sPyReset, METH_NOARGS,"reset() : undo rotation caused by actuator\n"}, - {NULL,NULL} //Sentinel + {"reset", (PyCFunction)KX_MouseActuator::sPyReset, METH_NOARGS, "reset() : undo rotation caused by actuator\n"}, + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_MouseActuator::Attributes[] = { - KX_PYATTRIBUTE_BOOL_RW("visible", KX_MouseActuator, m_visible), - KX_PYATTRIBUTE_BOOL_RW("use_axis_x", KX_MouseActuator, m_use_axis_x), - KX_PYATTRIBUTE_BOOL_RW("use_axis_y", KX_MouseActuator, m_use_axis_y), - KX_PYATTRIBUTE_FLOAT_ARRAY_RW("threshold", 0.0f, 0.5f, KX_MouseActuator, m_threshold, 2), - KX_PYATTRIBUTE_BOOL_RW("reset_x", KX_MouseActuator, m_reset_x), - KX_PYATTRIBUTE_BOOL_RW("reset_y", KX_MouseActuator, m_reset_y), - KX_PYATTRIBUTE_INT_ARRAY_RW("object_axis", 0, 2, 1, KX_MouseActuator, m_object_axis, 2), - KX_PYATTRIBUTE_BOOL_RW("local_x", KX_MouseActuator, m_local_x), - KX_PYATTRIBUTE_BOOL_RW("local_y", KX_MouseActuator, m_local_y), - KX_PYATTRIBUTE_FLOAT_ARRAY_RW("sensitivity", -FLT_MAX, FLT_MAX, KX_MouseActuator, m_sensitivity, 2), - KX_PYATTRIBUTE_RW_FUNCTION("limit_x", KX_MouseActuator, pyattr_get_limit_x, pyattr_set_limit_x), - KX_PYATTRIBUTE_RW_FUNCTION("limit_y", KX_MouseActuator, pyattr_get_limit_y, pyattr_set_limit_y), - KX_PYATTRIBUTE_RW_FUNCTION("angle", KX_MouseActuator, pyattr_get_angle, pyattr_set_angle), - { NULL } //Sentinel + EXP_PYATTRIBUTE_BOOL_RW("visible", KX_MouseActuator, m_visible), + EXP_PYATTRIBUTE_BOOL_RW("use_axis_x", KX_MouseActuator, m_use_axis[0]), + EXP_PYATTRIBUTE_BOOL_RW("use_axis_y", KX_MouseActuator, m_use_axis[1]), + EXP_PYATTRIBUTE_VECTOR_RW("threshold", 0.0f, 0.5f, KX_MouseActuator, m_threshold, 2), + EXP_PYATTRIBUTE_BOOL_RW("reset_x", KX_MouseActuator, m_reset[0]), + EXP_PYATTRIBUTE_BOOL_RW("reset_y", KX_MouseActuator, m_reset[1]), + EXP_PYATTRIBUTE_INT_ARRAY_RW("object_axis", 0, 2, 1, KX_MouseActuator, m_object_axis, 2), + EXP_PYATTRIBUTE_BOOL_RW("local_x", KX_MouseActuator, m_local[0]), + EXP_PYATTRIBUTE_BOOL_RW("local_y", KX_MouseActuator, m_local[1]), + EXP_PYATTRIBUTE_VECTOR_RW("sensitivity", -FLT_MAX, FLT_MAX, KX_MouseActuator, m_sensitivity, 2), + EXP_PYATTRIBUTE_RW_FUNCTION("limit_x", KX_MouseActuator, pyattr_get_limit_x, pyattr_set_limit_x), + EXP_PYATTRIBUTE_RW_FUNCTION("limit_y", KX_MouseActuator, pyattr_get_limit_y, pyattr_set_limit_y), + EXP_PYATTRIBUTE_RW_FUNCTION("angle", KX_MouseActuator, pyattr_get_angle, pyattr_set_angle), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject* KX_MouseActuator::pyattr_get_limit_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_MouseActuator::pyattr_get_limit_x(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_MouseActuator* self= static_cast(self_v); - return Py_BuildValue("[f,f]", (self->m_limit_x[0] / (float)M_PI * 180.0f), (self->m_limit_x[1] / (float)M_PI * 180.0f)); + KX_MouseActuator *self = static_cast(self_v); + return PyObjectFrom(mt::vec2(self->m_limit[0]) / (float)M_PI * 180.0f); } -int KX_MouseActuator::pyattr_set_limit_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_MouseActuator::pyattr_set_limit_x(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - PyObject *item1, *item2; - KX_MouseActuator* self= static_cast(self_v); + KX_MouseActuator *self = static_cast(self_v); - if (!PyList_Check(value)) + mt::vec2 vec; + if (!PyVecTo(value, vec)) { return PY_SET_ATTR_FAIL; - - if (PyList_Size(value) != 2) - return PY_SET_ATTR_FAIL; - - item1 = PyList_GET_ITEM(value, 0); - item2 = PyList_GET_ITEM(value, 1); - - if (!(PyFloat_Check(item1)) || !(PyFloat_Check(item2))) { - return PY_SET_ATTR_FAIL; - } - else { - self->m_limit_x[0] = (float)((PyFloat_AsDouble(item1) * M_PI) / 180.0f); - self->m_limit_x[1] = (float)((PyFloat_AsDouble(item2) * M_PI) / 180.0f); } + self->m_limit[0] = vec * ((float)M_PI / 180.0f); + return PY_SET_ATTR_SUCCESS; } -PyObject* KX_MouseActuator::pyattr_get_limit_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_MouseActuator::pyattr_get_limit_y(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_MouseActuator* self= static_cast(self_v); - return Py_BuildValue("[f,f]", (self->m_limit_y[0] / (float)M_PI * 180.0f), (self->m_limit_y[1] / (float)M_PI * 180.0f)); + KX_MouseActuator *self = static_cast(self_v); + return PyObjectFrom(mt::vec2(self->m_limit[1]) / (float)M_PI * 180.0f); } -int KX_MouseActuator::pyattr_set_limit_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_MouseActuator::pyattr_set_limit_y(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - PyObject *item1, *item2; - KX_MouseActuator* self= static_cast(self_v); + KX_MouseActuator *self = static_cast(self_v); - if (!PyList_Check(value)) + mt::vec2 vec; + if (!PyVecTo(value, vec)) { return PY_SET_ATTR_FAIL; - - if (PyList_Size(value) != 2) - return PY_SET_ATTR_FAIL; - - item1 = PyList_GET_ITEM(value, 0); - item2 = PyList_GET_ITEM(value, 1); - - if (!(PyFloat_Check(item1)) || !(PyFloat_Check(item2))) { - return PY_SET_ATTR_FAIL; - } - else { - self->m_limit_y[0] = (float)((PyFloat_AsDouble(item1) * M_PI) / 180.0f); - self->m_limit_y[1] = (float)((PyFloat_AsDouble(item2) * M_PI) / 180.0f); } + self->m_limit[1] = vec * ((float)M_PI / 180.0f); + return PY_SET_ATTR_SUCCESS; } -PyObject* KX_MouseActuator::pyattr_get_angle(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_MouseActuator::pyattr_get_angle(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_MouseActuator* self= static_cast(self_v); - return Py_BuildValue("[f,f]", (self->m_angle[0] / (float)M_PI * 180.0f), (self->m_angle[1] / (float)M_PI * 180.0f)); + KX_MouseActuator *self = static_cast(self_v); + return PyObjectFrom(mt::vec2(self->m_angle) / (float)M_PI * 180.0f); } -int KX_MouseActuator::pyattr_set_angle(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_MouseActuator::pyattr_set_angle(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - PyObject *item1, *item2; - KX_MouseActuator* self= static_cast(self_v); + KX_MouseActuator *self = static_cast(self_v); - if (!PyList_Check(value)) + mt::vec2 vec; + if (!PyVecTo(value, vec)) { return PY_SET_ATTR_FAIL; - - if (PyList_Size(value) != 2) - return PY_SET_ATTR_FAIL; - - item1 = PyList_GET_ITEM(value, 0); - item2 = PyList_GET_ITEM(value, 1); - - if (!(PyFloat_Check(item1)) || !(PyFloat_Check(item2))) { - return PY_SET_ATTR_FAIL; - } - else { - self->m_angle[0] = ((float)(PyFloat_AsDouble(item1) * M_PI) / 180.0f); - self->m_angle[1] = ((float)(PyFloat_AsDouble(item2) * M_PI) / 180.0f); } + self->m_angle = vec * ((float)M_PI / 180.0f); + return PY_SET_ATTR_SUCCESS; } -PyObject* KX_MouseActuator::PyReset() +PyObject *KX_MouseActuator::PyReset() { - MT_Vector3 rotation; + mt::vec3 rotation; KX_GameObject *parent = static_cast(GetParent()); - switch (m_object_axis[0]) { - case KX_ACT_MOUSE_OBJECT_AXIS_X: - { - rotation = MT_Vector3(-1.0f * m_angle[0], 0.0f, 0.0f); - break; - } - case KX_ACT_MOUSE_OBJECT_AXIS_Y: - { - rotation = MT_Vector3(0.0f, -1.0f * m_angle[0], 0.0f); - break; - } - case KX_ACT_MOUSE_OBJECT_AXIS_Z: - { - rotation = MT_Vector3(0.0f, 0.0f, -1.0f * m_angle[0]); - break; - } - default: - break; - } - parent->ApplyRotation(rotation, m_local_x); - - switch (m_object_axis[1]) { - case KX_ACT_MOUSE_OBJECT_AXIS_X: - { - rotation = MT_Vector3(-1.0f * m_angle[1], 0.0f, 0.0f); - break; - } - case KX_ACT_MOUSE_OBJECT_AXIS_Y: - { - rotation = MT_Vector3(0.0f, -1.0f * m_angle[1], 0.0f); - break; - } - case KX_ACT_MOUSE_OBJECT_AXIS_Z: - { - rotation = MT_Vector3(0.0f, 0.0f, -1.0f * m_angle[1]); - break; + for (unsigned short i = 0; i < 2; ++i) { + switch (m_object_axis[i]) { + case KX_ACT_MOUSE_OBJECT_AXIS_X: + { + rotation = mt::vec3(-1.0f * m_angle[i], 0.0f, 0.0f); + break; + } + case KX_ACT_MOUSE_OBJECT_AXIS_Y: + { + rotation = mt::vec3(0.0f, -1.0f * m_angle[i], 0.0f); + break; + } + case KX_ACT_MOUSE_OBJECT_AXIS_Z: + { + rotation = mt::vec3(0.0f, 0.0f, -1.0f * m_angle[i]); + break; + } + default: + break; } - default: - break; + parent->ApplyRotation(rotation, m_local[i]); } - parent->ApplyRotation(rotation, m_local_y); - m_angle[0] = 0.0f; - m_angle[1] = 0.0f; + m_angle = mt::zero2; Py_RETURN_NONE; } diff --git a/source/gameengine/Ketsji/KX_MouseActuator.h b/source/gameengine/Ketsji/KX_MouseActuator.h index e244e2714280..aa5476671883 100644 --- a/source/gameengine/Ketsji/KX_MouseActuator.h +++ b/source/gameengine/Ketsji/KX_MouseActuator.h @@ -41,23 +41,20 @@ class KX_MouseActuator : public SCA_IActuator SCA_IInputDevice* m_mouse; RAS_ICanvas* m_canvas; int m_type; + bool m_initialSkipping; bool m_visible; - bool m_use_axis_x; /* 0 for calculate axis, 1 for ignore axis */ - bool m_use_axis_y; - float m_threshold[2]; - bool m_reset_x; /* 0=reset, 1=free */ - bool m_reset_y; + bool m_use_axis[2]; /* 0 for calculate axis, 1 for ignore axis */ + mt::vec2 m_threshold; + bool m_reset[2]; /* 0=reset, 1=free */ int m_object_axis[2]; /* 0=x, 1=y, 2=z */ - bool m_local_x; /* 0=local, 1=global*/ - bool m_local_y; - float m_sensitivity[2]; - float m_limit_x[2]; - float m_limit_y[2]; + bool m_local[2]; /* 0=local, 1=global*/ + mt::vec2 m_sensitivity; + mt::vec2 m_limit[2]; - float m_oldposition[2]; - float m_angle[2]; + mt::vec2 m_oldPosition; + mt::vec2 m_angle; public: @@ -74,35 +71,21 @@ class KX_MouseActuator : public SCA_IActuator KX_ACT_MOUSE_MAX }; - KX_MouseActuator( - SCA_IObject* gameobj, - KX_KetsjiEngine* ketsjiEngine, - SCA_MouseManager* eventmgr, - int acttype, - bool visible, - bool* use_axis, - float* threshold, - bool* reset, - int* object_axis, - bool* local, - float* sensitivity, - float* limit_x, - float* limit_y - ); - + KX_MouseActuator(SCA_IObject* gameobj, KX_KetsjiEngine* ketsjiEngine, SCA_MouseManager* eventmgr, + int acttype, bool visible, const bool use_axis[2], const mt::vec2& threshold, const bool reset[2], + const int object_axis[2], const bool local[2], const mt::vec2& sensitivity, const mt::vec2 limit[2]); ~KX_MouseActuator(); - CValue* GetReplica(); + EXP_Value* GetReplica(); virtual void ProcessReplica(); - virtual bool Update(); + virtual void Replace_IScene(SCA_IScene *scene); - /* check whether this value is valid */ - bool isValid(KX_ACT_MOUSE_MODE mode); + virtual bool Update(); - virtual void getMousePosition(float*); - virtual void setMousePosition(float, float); + mt::vec2 GetMousePosition() const; + void SetMousePosition(const mt::vec2& pos); #ifdef WITH_PYTHON @@ -113,18 +96,18 @@ class KX_MouseActuator : public SCA_IActuator /* Methods */ - KX_PYMETHOD_DOC_NOARGS(KX_MouseActuator,Reset); + EXP_PYMETHOD_DOC_NOARGS(KX_MouseActuator,Reset); /* Attributes */ - static PyObject* pyattr_get_limit_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_limit_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_limit_x(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_limit_x(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_limit_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_limit_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_limit_y(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_limit_y(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_angle(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_angle(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject* pyattr_get_angle(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_angle(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); #endif /* WITH_PYTHON */ }; diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp index 6dc85b599353..4e184ebc667b 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp @@ -31,21 +31,18 @@ */ #ifdef _MSC_VER - /* This warning tells us about truncation of __long__ stl-generated names. - * It can occasionally cause DevStudio to have internal compiler warnings. */ +/* 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 -#include - -#include "MT_Point3.h" #include "RAS_FramingManager.h" #include "RAS_ICanvas.h" -#include "RAS_IRasterizer.h" -#include "RAS_MeshObject.h" +#include "RAS_Rasterizer.h" #include "SCA_IScene.h" #include "KX_Scene.h" #include "KX_Camera.h" +#include "KX_Mesh.h" #include "KX_MouseFocusSensor.h" #include "KX_PyMath.h" @@ -53,49 +50,52 @@ #include "PHY_IPhysicsController.h" #include "PHY_IPhysicsEnvironment.h" - #include "KX_ClientObjectInfo.h" +#include "CM_Message.h" + /* ------------------------------------------------------------------------- */ /* Native functions */ /* ------------------------------------------------------------------------- */ -KX_MouseFocusSensor::KX_MouseFocusSensor(SCA_MouseManager* eventmgr, +KX_MouseFocusSensor::KX_MouseFocusSensor(SCA_MouseManager *eventmgr, int startx, int starty, - short int mousemode, - int focusmode, - bool bTouchPulse, - const STR_String& propname, - bool bFindMaterial, - bool bXRay, - KX_Scene* kxscene, - KX_KetsjiEngine *kxengine, - SCA_IObject* gameobj) - : SCA_MouseSensor(eventmgr, startx, starty, mousemode, gameobj), - m_focusmode(focusmode), - m_bTouchPulse(bTouchPulse), - m_bXRay(bXRay), - m_bFindMaterial(bFindMaterial), - m_propertyname(propname), - m_kxscene(kxscene), - m_kxengine(kxengine) + short int mousemode, + int focusmode, + bool bCollisionPulse, + const std::string& propname, + bool bFindMaterial, + bool bXRay, + int mask, + KX_Scene *kxscene, + KX_KetsjiEngine *kxengine, + SCA_IObject *gameobj) + :SCA_MouseSensor(eventmgr, startx, starty, mousemode, gameobj), + m_focusmode(focusmode), + m_bCollisionPulse(bCollisionPulse), + m_bXRay(bXRay), + m_mask(mask), + m_bFindMaterial(bFindMaterial), + m_propertyname(propname), + m_kxscene(kxscene), + m_kxengine(kxengine) { Init(); } void KX_MouseFocusSensor::Init() { - m_mouse_over_in_previous_frame = (m_invert)?true:false; + m_mouse_over_in_previous_frame = (m_invert) ? true : false; m_positive_event = false; m_hitObject = 0; - m_hitObject_Last = NULL; + m_hitObject_Last = nullptr; m_reset = true; - m_hitPosition.setValue(0,0,0); - m_prevTargetPoint.setValue(0,0,0); - m_prevSourcePoint.setValue(0,0,0); - m_hitNormal.setValue(0,0,1); + m_hitPosition = mt::zero3; + m_prevTargetPoint = mt::zero3; + m_prevSourcePoint = mt::zero3; + m_hitNormal = mt::zero3; } bool KX_MouseFocusSensor::Evaluate() @@ -104,7 +104,6 @@ bool KX_MouseFocusSensor::Evaluate() bool obHasFocus = false; bool reset = m_reset && m_level; -// cout << "evaluate focus mouse sensor "<m_gameobject; + KX_GameObject *hitKXObj = client_info->m_gameobject; /* Is this me? In the ray test, there are a lot of extra checks * for aliasing artifacts from self-hits. That doesn't happen @@ -154,35 +155,29 @@ bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo *client_info, KX_RayCast *r * self-hits? (No, and the raysensor shouldn't do it either, since * self-hits are excluded by setting the correct ignore-object.) * Hitspots now become valid. */ - KX_GameObject* thisObj = (KX_GameObject*) GetParent(); + KX_GameObject *thisObj = (KX_GameObject *)GetParent(); bool bFound = false; - if ((m_focusmode == 2) || hitKXObj == thisObj) - { - if (m_propertyname.Length() == 0) - { + if ((m_focusmode == 2) || hitKXObj == thisObj) { + if (m_propertyname.empty()) { bFound = true; } - else - { + else { if (m_bFindMaterial) { - for (unsigned int i = 0; i < hitKXObj->GetMeshCount(); ++i) { - RAS_MeshObject *meshObj = hitKXObj->GetMesh(i); - for (unsigned int j = 0; j < meshObj->NumMaterials(); ++j) { - bFound = strcmp(m_propertyname.ReadPtr(), meshObj->GetMaterialName(j).ReadPtr() + 2) == 0; - if (bFound) - break; + for (RAS_Mesh *meshObj : hitKXObj->GetMeshList()) { + bFound = (meshObj->FindMaterialName(m_propertyname) != nullptr); + if (bFound) { + break; } } } else { - bFound = hitKXObj->GetProperty(m_propertyname) != NULL; + bFound = hitKXObj->GetProperty(m_propertyname) != nullptr; } } - if (bFound) - { + if (bFound) { m_hitObject = hitKXObj; m_hitPosition = result->m_hitPoint; m_hitNormal = result->m_hitNormal; @@ -202,33 +197,35 @@ bool KX_MouseFocusSensor::NeedRayCast(KX_ClientObjectInfo *client, void *UNUSED( { KX_GameObject *hitKXObj = client->m_gameobject; - if (client->m_type > KX_ClientObjectInfo::ACTOR) - { + if (client->m_type > KX_ClientObjectInfo::ACTOR) { // Unknown type of object, skip it. // Should not occur as the sensor objects are filtered in RayTest() - printf("Invalid client type %d found ray casting\n", client->m_type); + CM_Error("invalid client type " << client->m_type << " found ray casting"); return false; } - if (m_bXRay && m_propertyname.Length() != 0) - { - if (m_bFindMaterial) - { + + // The current object is not in the proper layer. + if (!(hitKXObj->GetCollisionGroup() & m_mask)) { + return false; + } + + if (m_bXRay && m_propertyname.size() != 0) { + if (m_bFindMaterial) { bool found = false; - for (unsigned int i = 0; i < hitKXObj->GetMeshCount(); ++i) { - RAS_MeshObject *meshObj = hitKXObj->GetMesh(i); - for (unsigned int j = 0; j < meshObj->NumMaterials(); ++j) { - found = strcmp(m_propertyname.ReadPtr(), meshObj->GetMaterialName(j).ReadPtr() + 2) == 0; - if (found) - break; + for (KX_Mesh *meshObj : hitKXObj->GetMeshList()) { + found = (meshObj->FindMaterialName(m_propertyname) != nullptr); + if (found) { + break; } } - if (!found) + if (!found) { return false; + } } - else - { - if (hitKXObj->GetProperty(m_propertyname) == NULL) + else { + if (hitKXObj->GetProperty(m_propertyname) == nullptr) { return false; + } } } return true; @@ -278,30 +275,29 @@ bool KX_MouseFocusSensor::ParentObjectHasFocusCamera(KX_Camera *cam) * division by 0.0...*/ RAS_Rect area, viewport; - short m_y_inv = m_kxengine->GetCanvas()->GetHeight()-m_y; + RAS_ICanvas *canvas = m_kxengine->GetCanvas(); + short m_y_inv = canvas->GetHeight() - m_y; - m_kxengine->GetSceneViewport(m_kxscene, cam, area, viewport); + RAS_Rasterizer *rasty = m_kxengine->GetRasterizer(); + const RAS_Rect displayArea = rasty->GetRenderArea(canvas, rasty->GetStereoMode(), RAS_Rasterizer::RAS_STEREO_LEFTEYE); + m_kxengine->GetSceneViewport(m_kxscene, cam, displayArea, area, viewport); /* Check if the mouse is in the viewport */ - if (( m_x < viewport.m_x2 && // less than right - m_x > viewport.m_x1 && // more than then left - m_y_inv < viewport.m_y2 && // below top - m_y_inv > viewport.m_y1) == 0) // above bottom - { + if ((m_x < viewport.GetRight() && // less than right + m_x > viewport.GetLeft() && // more than then left + m_y_inv < viewport.GetTop() && // below top + m_y_inv > viewport.GetBottom()) == 0) { // above bottom return false; } - float height = float(viewport.m_y2 - viewport.m_y1 + 1); - float width = float(viewport.m_x2 - viewport.m_x1 + 1); + float maxy = float(viewport.GetMaxY()); + float maxx = float(viewport.GetMaxX()); - float x_lb = float(viewport.m_x1); - float y_lb = float(viewport.m_y1); - - MT_Vector4 frompoint; - MT_Vector4 topoint; + float x_lb = float(viewport.GetLeft()); + float y_lb = float(viewport.GetBottom()); /* m_y_inv - inverting for a bounds check is only part of it, now make relative to view bounds */ - m_y_inv = (viewport.m_y2 - m_y_inv) + viewport.m_y1; + m_y_inv = (viewport.GetTop() - m_y_inv) + viewport.GetBottom(); /* There's some strangeness I don't fully get here... These values @@ -314,23 +310,15 @@ bool KX_MouseFocusSensor::ParentObjectHasFocusCamera(KX_Camera *cam) * The actual z coordinates used don't have to be exact just infront and * behind of the near and far clip planes. */ - frompoint.setValue( (2 * (m_x-x_lb) / width) - 1.0f, - 1.0f - (2 * (m_y_inv - y_lb) / height), - -1.0f, - 1.0f ); - - topoint.setValue( (2 * (m_x-x_lb) / width) - 1.0f, - 1.0f - (2 * (m_y_inv-y_lb) / height), - 1.0f, - 1.0f ); + mt::vec3 frompoint((2 * (m_x - x_lb) / maxx) - 1.0f, 1.0f - (2 * (m_y_inv - y_lb) / maxy), -1.0f); + mt::vec3 topoint((2 * (m_x - x_lb) / maxx) - 1.0f, 1.0f - (2 * (m_y_inv - y_lb) / maxy), 1.0f); /* camera to world */ - MT_Matrix4x4 camcs_wcs_matrix = MT_Matrix4x4(cam->GetCameraToWorld()); + mt::mat4 camcs_wcs_matrix = mt::mat4::FromAffineTransform(cam->GetCameraToWorld()); /* badly defined, the first time round.... I wonder why... I might * want to guard against floating point errors here.*/ - MT_Matrix4x4 clip_camcs_matrix = MT_Matrix4x4(cam->GetProjectionMatrix()); - clip_camcs_matrix.invert(); + mt::mat4 clip_camcs_matrix = cam->GetProjectionMatrix().Inverse(); /* shoot-points: clip to cam to wcs . win to clip was already done.*/ frompoint = clip_camcs_matrix * frompoint; @@ -341,27 +329,23 @@ bool KX_MouseFocusSensor::ParentObjectHasFocusCamera(KX_Camera *cam) topoint = camcs_wcs_matrix * topoint; /* from hom wcs to 3d wcs: */ - m_prevSourcePoint.setValue( frompoint[0]/frompoint[3], - frompoint[1]/frompoint[3], - frompoint[2]/frompoint[3]); - - m_prevTargetPoint.setValue( topoint[0]/topoint[3], - topoint[1]/topoint[3], - topoint[2]/topoint[3]); + m_prevSourcePoint = frompoint; + m_prevTargetPoint = topoint; /* 2. Get the object from PhysicsEnvironment */ /* Shoot! Beware that the first argument here is an * ignore-object. We don't ignore anything... */ - PHY_IPhysicsController* physics_controller = cam->GetPhysicsController(); - PHY_IPhysicsEnvironment* physics_environment = m_kxscene->GetPhysicsEnvironment(); + PHY_IPhysicsController *physics_controller = cam->GetPhysicsController(); + PHY_IPhysicsEnvironment *physics_environment = m_kxscene->GetPhysicsEnvironment(); // get UV mapping - KX_RayCast::Callback callback(this,physics_controller,NULL,false,true); + KX_RayCast::Callback callback(this, physics_controller, nullptr, false, true); KX_RayCast::RayTest(physics_environment, m_prevSourcePoint, m_prevTargetPoint, callback); - if (m_hitObject) + if (m_hitObject) { return true; + } return false; } @@ -369,49 +353,48 @@ bool KX_MouseFocusSensor::ParentObjectHasFocusCamera(KX_Camera *cam) bool KX_MouseFocusSensor::ParentObjectHasFocus() { m_hitObject = 0; - m_hitPosition.setValue(0,0,0); - m_hitNormal.setValue(1,0,0); + m_hitPosition = mt::zero3; + m_hitNormal = mt::axisZ3; - KX_Camera *cam= m_kxscene->GetActiveCamera(); + KX_Camera *activecam = m_kxscene->GetActiveCamera(); - if (ParentObjectHasFocusCamera(cam)) + if (ParentObjectHasFocusCamera(activecam)) { return true; + } - list* cameras = m_kxscene->GetCameras(); - list::iterator it = cameras->begin(); - - while (it != cameras->end()) { - if (((*it) != cam) && (*it)->GetViewport()) - if (ParentObjectHasFocusCamera(*it)) + EXP_ListValue *cameras = m_kxscene->GetCameraList(); + for (KX_Camera *cam : cameras) { + if ((cam != activecam) && cam->GetViewport()) { + if (ParentObjectHasFocusCamera(cam)) { return true; - - it++; + } + } } return false; } -const MT_Point3& KX_MouseFocusSensor::RaySource() const +const mt::vec3& KX_MouseFocusSensor::RaySource() const { return m_prevSourcePoint; } -const MT_Point3& KX_MouseFocusSensor::RayTarget() const +const mt::vec3& KX_MouseFocusSensor::RayTarget() const { return m_prevTargetPoint; } -const MT_Point3& KX_MouseFocusSensor::HitPosition() const +const mt::vec3& KX_MouseFocusSensor::HitPosition() const { return m_hitPosition; } -const MT_Vector3& KX_MouseFocusSensor::HitNormal() const +const mt::vec3& KX_MouseFocusSensor::HitNormal() const { return m_hitNormal; } -const MT_Vector2& KX_MouseFocusSensor::HitUV() const +const mt::vec2& KX_MouseFocusSensor::HitUV() const { return m_hitUV; } @@ -424,9 +407,9 @@ const MT_Vector2& KX_MouseFocusSensor::HitUV() const /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_MouseFocusSensor::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_MouseFocusSensor", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -434,86 +417,93 @@ PyTypeObject KX_MouseFocusSensor::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_MouseSensor::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_MouseFocusSensor::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_MouseFocusSensor::Attributes[] = { - KX_PYATTRIBUTE_RO_FUNCTION("raySource", KX_MouseFocusSensor, pyattr_get_ray_source), - KX_PYATTRIBUTE_RO_FUNCTION("rayTarget", KX_MouseFocusSensor, pyattr_get_ray_target), - KX_PYATTRIBUTE_RO_FUNCTION("rayDirection", KX_MouseFocusSensor, pyattr_get_ray_direction), - KX_PYATTRIBUTE_RO_FUNCTION("hitObject", KX_MouseFocusSensor, pyattr_get_hit_object), - KX_PYATTRIBUTE_RO_FUNCTION("hitPosition", KX_MouseFocusSensor, pyattr_get_hit_position), - KX_PYATTRIBUTE_RO_FUNCTION("hitNormal", KX_MouseFocusSensor, pyattr_get_hit_normal), - KX_PYATTRIBUTE_RO_FUNCTION("hitUV", KX_MouseFocusSensor, pyattr_get_hit_uv), - KX_PYATTRIBUTE_BOOL_RW("usePulseFocus", KX_MouseFocusSensor, m_bTouchPulse), - KX_PYATTRIBUTE_BOOL_RW("useXRay", KX_MouseFocusSensor, m_bXRay), - KX_PYATTRIBUTE_BOOL_RW("useMaterial", KX_MouseFocusSensor, m_bFindMaterial), - KX_PYATTRIBUTE_STRING_RW("propName", 0, MAX_PROP_NAME, false, KX_MouseFocusSensor, m_propertyname), - { NULL } //Sentinel + EXP_PYATTRIBUTE_RO_FUNCTION("raySource", KX_MouseFocusSensor, pyattr_get_ray_source), + EXP_PYATTRIBUTE_RO_FUNCTION("rayTarget", KX_MouseFocusSensor, pyattr_get_ray_target), + EXP_PYATTRIBUTE_RO_FUNCTION("rayDirection", KX_MouseFocusSensor, pyattr_get_ray_direction), + EXP_PYATTRIBUTE_RO_FUNCTION("hitObject", KX_MouseFocusSensor, pyattr_get_hit_object), + EXP_PYATTRIBUTE_RO_FUNCTION("hitPosition", KX_MouseFocusSensor, pyattr_get_hit_position), + EXP_PYATTRIBUTE_RO_FUNCTION("hitNormal", KX_MouseFocusSensor, pyattr_get_hit_normal), + EXP_PYATTRIBUTE_RO_FUNCTION("hitUV", KX_MouseFocusSensor, pyattr_get_hit_uv), + EXP_PYATTRIBUTE_BOOL_RW("usePulseFocus", KX_MouseFocusSensor, m_bCollisionPulse), + EXP_PYATTRIBUTE_BOOL_RW("useXRay", KX_MouseFocusSensor, m_bXRay), + EXP_PYATTRIBUTE_INT_RW("mask", 1, (1 << OB_MAX_COL_MASKS) - 1, true, KX_MouseFocusSensor, m_mask), + EXP_PYATTRIBUTE_BOOL_RW("useMaterial", KX_MouseFocusSensor, m_bFindMaterial), + EXP_PYATTRIBUTE_STRING_RW("propName", 0, MAX_PROP_NAME, false, KX_MouseFocusSensor, m_propertyname), + EXP_PYATTRIBUTE_NULL //Sentinel }; /* Attributes */ -PyObject *KX_MouseFocusSensor::pyattr_get_ray_source(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_MouseFocusSensor::pyattr_get_ray_source(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_MouseFocusSensor* self = static_cast(self_v); + KX_MouseFocusSensor *self = static_cast(self_v); return PyObjectFrom(self->RaySource()); } -PyObject *KX_MouseFocusSensor::pyattr_get_ray_target(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_MouseFocusSensor::pyattr_get_ray_target(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_MouseFocusSensor* self = static_cast(self_v); + KX_MouseFocusSensor *self = static_cast(self_v); return PyObjectFrom(self->RayTarget()); } -PyObject *KX_MouseFocusSensor::pyattr_get_ray_direction(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_MouseFocusSensor::pyattr_get_ray_direction(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_MouseFocusSensor* self = static_cast(self_v); - MT_Vector3 dir = self->RayTarget() - self->RaySource(); - if (MT_fuzzyZero(dir)) dir.setValue(0,0,0); - else dir.normalize(); + KX_MouseFocusSensor *self = static_cast(self_v); + mt::vec3 dir = self->RayTarget() - self->RaySource(); + if (mt::FuzzyZero(dir)) { + dir = mt::zero3; + } + else { + dir.Normalize(); + } return PyObjectFrom(dir); } -PyObject *KX_MouseFocusSensor::pyattr_get_hit_object(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_MouseFocusSensor::pyattr_get_hit_object(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_MouseFocusSensor* self = static_cast(self_v); + KX_MouseFocusSensor *self = static_cast(self_v); - if (self->m_hitObject) + if (self->m_hitObject) { return self->m_hitObject->GetProxy(); + } Py_RETURN_NONE; } -PyObject *KX_MouseFocusSensor::pyattr_get_hit_position(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_MouseFocusSensor::pyattr_get_hit_position(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_MouseFocusSensor* self = static_cast(self_v); + KX_MouseFocusSensor *self = static_cast(self_v); return PyObjectFrom(self->HitPosition()); } -PyObject *KX_MouseFocusSensor::pyattr_get_hit_normal(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_MouseFocusSensor::pyattr_get_hit_normal(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_MouseFocusSensor* self = static_cast(self_v); + KX_MouseFocusSensor *self = static_cast(self_v); return PyObjectFrom(self->HitNormal()); } -PyObject *KX_MouseFocusSensor::pyattr_get_hit_uv(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_MouseFocusSensor::pyattr_get_hit_uv(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_MouseFocusSensor* self = static_cast(self_v); + KX_MouseFocusSensor *self = static_cast(self_v); return PyObjectFrom(self->HitUV()); } #endif // WITH_PYTHON /* eof */ + diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.h b/source/gameengine/Ketsji/KX_MouseFocusSensor.h index 9437a0f3432d..5137b06fb55d 100644 --- a/source/gameengine/Ketsji/KX_MouseFocusSensor.h +++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.h @@ -46,29 +46,29 @@ class KX_RayCast; * * - extend the valid modes? * - */ -class KX_MouseFocusSensor : public SCA_MouseSensor +class KX_MouseFocusSensor : public SCA_MouseSensor, public mt::SimdClassAllocator { Py_Header - - public: - + +public: KX_MouseFocusSensor(class SCA_MouseManager* eventmgr, int startx, int starty, short int mousemode, int focusmode, - bool bTouchPulse, - const STR_String& propname, + bool bCollisionPulse, + const std::string& propname, bool bFindMaterial, bool bXRay, + int mask, KX_Scene* kxscene, KX_KetsjiEngine* kxengine, SCA_IObject* gameobj); virtual ~KX_MouseFocusSensor() { } - virtual CValue* GetReplica() { - CValue* replica = new KX_MouseFocusSensor(*this); + virtual EXP_Value* GetReplica() { + EXP_Value* replica = new KX_MouseFocusSensor(*this); // this will copy properties and so on... replica->ProcessReplica(); return replica; @@ -81,7 +81,7 @@ class KX_MouseFocusSensor : public SCA_MouseSensor /** - * \attention Overrides default evaluate. + * \attention Overrides default evaluate. */ virtual bool Evaluate(); virtual void Init(); @@ -96,13 +96,13 @@ class KX_MouseFocusSensor : public SCA_MouseSensor bool RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void *UNUSED(data)); /// \see KX_RayCast bool NeedRayCast(KX_ClientObjectInfo *client, void *UNUSED(data)); - - const MT_Point3& RaySource() const; - const MT_Point3& RayTarget() const; - const MT_Point3& HitPosition() const; - const MT_Vector3& HitNormal() const; - const MT_Vector2& HitUV() const; - + + const mt::vec3& RaySource() const; + const mt::vec3& RayTarget() const; + const mt::vec3& HitPosition() const; + const mt::vec3& HitNormal() const; + const mt::vec2& HitUV() const; + #ifdef WITH_PYTHON /* --------------------------------------------------------------------- */ @@ -110,14 +110,14 @@ class KX_MouseFocusSensor : public SCA_MouseSensor /* --------------------------------------------------------------------- */ /* attributes */ - static PyObject* pyattr_get_ray_source(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_ray_target(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_ray_direction(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_hit_object(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_hit_position(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_hit_normal(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_hit_uv(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - + static PyObject* pyattr_get_ray_source(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_ray_target(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_ray_direction(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_hit_object(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_hit_position(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_hit_normal(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_hit_uv(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + #endif /* WITH_PYTHON */ /* --------------------------------------------------------------------- */ @@ -138,13 +138,15 @@ class KX_MouseFocusSensor : public SCA_MouseSensor /** * Flags whether changes in hit object should trigger a pulse */ - bool m_bTouchPulse; - + bool m_bCollisionPulse; + /** * Flags get through other objects */ bool m_bXRay; + int m_mask; + /** * Flags material */ @@ -153,7 +155,7 @@ class KX_MouseFocusSensor : public SCA_MouseSensor /** * Property or material name */ - STR_String m_propertyname; + std::string m_propertyname; /** * Flags whether the previous test evaluated positive. @@ -164,7 +166,7 @@ class KX_MouseFocusSensor : public SCA_MouseSensor * Tests whether the object is in mouse focus for this camera */ bool ParentObjectHasFocusCamera(KX_Camera *cam); - + /** * Tests whether the object is in mouse focus in this scene. */ @@ -173,27 +175,27 @@ class KX_MouseFocusSensor : public SCA_MouseSensor /** * (in game world coordinates) the place where the object was hit. */ - MT_Point3 m_hitPosition; + mt::vec3 m_hitPosition; /** * (in game world coordinates) the position to which to shoot the ray. */ - MT_Point3 m_prevTargetPoint; + mt::vec3 m_prevTargetPoint; /** * (in game world coordinates) the position from which to shoot the ray. */ - MT_Point3 m_prevSourcePoint; + mt::vec3 m_prevSourcePoint; /** * (in game world coordinates) the face normal of the vertex where * the object was hit. */ - MT_Vector3 m_hitNormal; + mt::vec3 m_hitNormal; /** * UV texture coordinate of the hit point if any, (0,0) otherwise */ - MT_Vector2 m_hitUV; + mt::vec2 m_hitUV; /** * The KX scene that holds the camera. The camera position diff --git a/source/gameengine/Ketsji/KX_MovementSensor.cpp b/source/gameengine/Ketsji/KX_MovementSensor.cpp new file mode 100644 index 000000000000..8aa6b369514d --- /dev/null +++ b/source/gameengine/Ketsji/KX_MovementSensor.cpp @@ -0,0 +1,225 @@ +/* + * Detects if an object has moved + * + * + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Ketsji/KX_MovementSensor.cpp + * \ingroup ketsji + */ + + +#include "KX_MovementSensor.h" +#include "SCA_EventManager.h" +#include "SCA_LogicManager.h" +#include "SCA_IObject.h" +#include "KX_GameObject.h" +#include "DNA_sensor_types.h" + +#include + + +KX_MovementSensor::KX_MovementSensor(SCA_EventManager *eventmgr, + SCA_IObject *gameobj, + int axis, bool localflag, + float threshold) + :SCA_ISensor(gameobj, eventmgr), + m_localflag(localflag), + m_axis(axis), + m_threshold(threshold) +{ + Init(); +} + +void KX_MovementSensor::Init() +{ + m_previousPosition = GetOwnerPosition(m_localflag); + m_positionHasChanged = false; + m_triggered = (m_invert) ? true : false; +} + +KX_MovementSensor::~KX_MovementSensor() +{ +} + +mt::vec3 KX_MovementSensor::GetOwnerPosition(bool local) +{ + KX_GameObject *owner = (KX_GameObject *)GetParent(); + if (!local) { + return owner->NodeGetWorldPosition(); + } + return owner->NodeGetLocalOrientation().Inverse() * owner->NodeGetLocalPosition(); +} + +EXP_Value *KX_MovementSensor::GetReplica() +{ + KX_MovementSensor *replica = new KX_MovementSensor(*this); + replica->ProcessReplica(); + replica->Init(); + + return replica; +} + +bool KX_MovementSensor::IsPositiveTrigger() +{ + bool result = m_positionHasChanged; + + if (m_invert) { + result = !result; + } + + return result; +} + +bool KX_MovementSensor::Evaluate() +{ + mt::vec3 currentposition; + + bool result = false; + bool reset = m_reset && m_level; + + currentposition = GetOwnerPosition(m_localflag); + + m_positionHasChanged = false; + + switch (m_axis) { + case SENS_MOVEMENT_X_AXIS: // X + { + m_positionHasChanged = ((currentposition.x - m_previousPosition.x) > m_threshold); + break; + } + case SENS_MOVEMENT_Y_AXIS: // Y + { + m_positionHasChanged = ((currentposition.y - m_previousPosition.y) > m_threshold); + break; + } + case SENS_MOVEMENT_Z_AXIS: // Z + { + m_positionHasChanged = ((currentposition.z - m_previousPosition.z) > m_threshold); + break; + } + case SENS_MOVEMENT_NEG_X_AXIS: // -X + { + m_positionHasChanged = ((currentposition.x - m_previousPosition.x) < -m_threshold); + break; + } + case SENS_MOVEMENT_NEG_Y_AXIS: // -Y + { + m_positionHasChanged = ((currentposition.y - m_previousPosition.y) < -m_threshold); + break; + } + case SENS_MOVEMENT_NEG_Z_AXIS: // -Z + { + m_positionHasChanged = ((currentposition.z - m_previousPosition.z) < -m_threshold); + break; + } + case SENS_MOVEMENT_ALL_AXIS: // ALL + { + if ((fabs(currentposition.x - m_previousPosition.x) > m_threshold) || + (fabs(currentposition.y - m_previousPosition.y) > m_threshold) || + (fabs(currentposition.z - m_previousPosition.z) > m_threshold)) { + m_positionHasChanged = true; + } + break; + } + } + + m_previousPosition = currentposition; + + /* now pass this result*/ + + if (m_positionHasChanged) { + if (!m_triggered) { + // notify logicsystem that movement sensor is just activated + result = true; + m_triggered = true; + } + else { + // notify logicsystem that movement sensor is STILL active ... + result = false; + } + } + else { + if (m_triggered) { + m_triggered = false; + // notify logicsystem that movement is just deactivated + result = true; + } + else { + result = false; + } + + } + if (reset) { + // force an event + result = true; + } + + return result; +} + +#ifdef WITH_PYTHON + +/* ------------------------------------------------------------------------- */ +/* Python functions */ +/* ------------------------------------------------------------------------- */ + +/* Integration hooks ------------------------------------------------------- */ +PyTypeObject KX_MovementSensor::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_MovementSensor", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &SCA_ISensor::Type, + 0, 0, 0, 0, 0, 0, + py_base_new +}; + +PyMethodDef KX_MovementSensor::Methods[] = { + {nullptr, nullptr} // Sentinel +}; + +PyAttributeDef KX_MovementSensor::Attributes[] = { + EXP_PYATTRIBUTE_FLOAT_RW("threshold", 0.001f, 10000.0f, KX_MovementSensor, m_threshold), + EXP_PYATTRIBUTE_INT_RW("axis", 0, 6, true, KX_MovementSensor, m_axis), + EXP_PYATTRIBUTE_NULL // Sentinel +}; + +#endif + diff --git a/source/gameengine/Ketsji/KX_MovementSensor.h b/source/gameengine/Ketsji/KX_MovementSensor.h new file mode 100644 index 000000000000..b8fb7caec6d9 --- /dev/null +++ b/source/gameengine/Ketsji/KX_MovementSensor.h @@ -0,0 +1,89 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file KX_MovementSensor.h + * \ingroup ketsji + * \brief Check if object has moved + */ + +#ifndef __KX_MOVEMENT_H__ +#define __KX_MOVEMENT_H__ + +#include "SCA_ISensor.h" +#include "mathfu.h" + + +class KX_MovementSensor : public SCA_ISensor, public mt::SimdClassAllocator +{ + Py_Header + +public: + enum MovementAxis { + KX_MOVEMENT_AXIS_POS_X = 1, + KX_MOVEMENT_AXIS_POS_Y = 0, + KX_MOVEMENT_AXIS_POS_Z = 2, + KX_MOVEMENT_AXIS_NEG_X = 3, + KX_MOVEMENT_AXIS_NEG_Y = 4, + KX_MOVEMENT_AXIS_NEG_Z = 5, + KX_MOVEMENT_ALL_AXIS = 6, + }; + +private: + /// True if the position is taken in world space or object space(local). + bool m_localflag; + /// The axis to detect mouvement, can be all axis. + int m_axis; + /// The previous object position. + mt::vec3 m_previousPosition; + /** True if the position is not the same (depends of a treshold value) + * between two logic frame. + */ + bool m_positionHasChanged; + /// Threshold below which the movement is not detected + float m_threshold; + bool m_triggered; + +public: + KX_MovementSensor(SCA_EventManager *eventmgr, + SCA_IObject *gameobj, + int axis, bool localflag, + float threshold); + virtual ~KX_MovementSensor(); + virtual EXP_Value *GetReplica(); + mt::vec3 GetOwnerPosition(bool local); + + virtual bool Evaluate(); + virtual bool IsPositiveTrigger(); + virtual void Init(); + +#ifdef WITH_PYTHON + +#endif // WITH_PYTHON + +}; + +#endif // __KX_MOVEMENT_H__ diff --git a/source/gameengine/Ketsji/KX_NavMeshObject.cpp b/source/gameengine/Ketsji/KX_NavMeshObject.cpp index a5feb95b00bc..ee860cc2f2ad 100644 --- a/source/gameengine/Ketsji/KX_NavMeshObject.cpp +++ b/source/gameengine/Ketsji/KX_NavMeshObject.cpp @@ -29,67 +29,88 @@ #include "BLI_math_vector.h" #include "KX_NavMeshObject.h" -#include "RAS_MeshObject.h" -#include "RAS_Polygon.h" +#include "KX_Mesh.h" +#include "RAS_DisplayArray.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" extern "C" { -#include "BKE_scene.h" -#include "BKE_customdata.h" -#include "BKE_cdderivedmesh.h" -#include "BKE_DerivedMesh.h" -#include "BKE_navmesh_conversion.h" +# include "BKE_scene.h" +# include "BKE_customdata.h" +# include "BKE_cdderivedmesh.h" +# include "BKE_DerivedMesh.h" +# include "BKE_navmesh_conversion.h" + +# include "BLI_alloca.h" } -#include "KX_PythonInit.h" +#include "KX_Globals.h" #include "KX_PyMath.h" #include "EXP_Value.h" #include "Recast.h" #include "DetourStatNavMeshBuilder.h" #include "KX_ObstacleSimulation.h" +#include "CM_Message.h" + #define MAX_PATH_LEN 256 static const float polyPickExt[3] = {2, 4, 2}; -static void calcMeshBounds(const float* vert, int nverts, float* bmin, float* bmax) +static void calcMeshBounds(const float *vert, int nverts, float *bmin, float *bmax) { bmin[0] = bmax[0] = vert[0]; bmin[1] = bmax[1] = vert[1]; bmin[2] = bmax[2] = vert[2]; - for (int i=1; ivert[3*i+0]) bmin[0] = vert[3*i+0]; - if (bmin[1]>vert[3*i+1]) bmin[1] = vert[3*i+1]; - if (bmin[2]>vert[3*i+2]) bmin[2] = vert[3*i+2]; + for (int i = 1; i < nverts; i++) { + if (bmin[0] > vert[3 * i + 0]) { + bmin[0] = vert[3 * i + 0]; + } + if (bmin[1] > vert[3 * i + 1]) { + bmin[1] = vert[3 * i + 1]; + } + if (bmin[2] > vert[3 * i + 2]) { + bmin[2] = vert[3 * i + 2]; + } - if (bmax[0]ProcessReplica(); return replica; } @@ -97,215 +118,238 @@ CValue* KX_NavMeshObject::GetReplica() void KX_NavMeshObject::ProcessReplica() { KX_GameObject::ProcessReplica(); - m_navMesh = NULL; /* without this, building frees the navmesh we copied from */ - if (!BuildNavMesh()) { - std::cout << "Error in " << __func__ << ": unable to build navigation mesh" << std::endl; - return; - } - KX_Scene* scene = KX_GetActiveScene(); - KX_ObstacleSimulation* obssimulation = scene->GetObstacleSimulation(); - if (obssimulation) - obssimulation->AddObstaclesForNavMesh(this); + m_navMesh = nullptr; } -bool KX_NavMeshObject::BuildVertIndArrays(float *&vertices, int& nverts, - unsigned short* &polys, int& npolys, unsigned short *&dmeshes, - float *&dvertices, int &ndvertsuniq, unsigned short *&dtris, - int& ndtris, int &vertsPerPoly) +int KX_NavMeshObject::GetGameObjectType() const { - DerivedMesh* dm = mesh_create_derived_no_virtual(GetScene()->GetBlenderScene(), GetBlenderObject(), - NULL, CD_MASK_MESH); + return OBJ_NAVMESH; +} + +bool KX_NavMeshObject::BuildFromDerivedMesh(float *&vertices, int& nverts, + unsigned short * &polys, int& npolys, unsigned short *&dmeshes, + float *&dvertices, int &ndvertsuniq, unsigned short *&dtris, + int& ndtris, int &vertsPerPoly) +{ + KX_Mesh *meshobj = m_meshes.front(); + if (!meshobj->GetMesh()) { + return false; + } + + DerivedMesh *dm = CDDM_from_mesh(meshobj->GetMesh()); CustomData *pdata = dm->getPolyDataLayout(dm); - int* recastData = (int*) CustomData_get_layer(pdata, CD_RECAST); - if (recastData) - { - int *dtrisToPolysMap=NULL, *dtrisToTrisMap=NULL, *trisToFacesMap=NULL; - int nAllVerts = 0; - float *allVerts = NULL; - buildNavMeshDataByDerivedMesh(dm, &vertsPerPoly, &nAllVerts, &allVerts, &ndtris, &dtris, - &npolys, &dmeshes, &polys, &dtrisToPolysMap, &dtrisToTrisMap, &trisToFacesMap); - - MEM_SAFE_FREE(dtrisToPolysMap); - MEM_SAFE_FREE(dtrisToTrisMap); - MEM_SAFE_FREE(trisToFacesMap); - - unsigned short *verticesMap = (unsigned short *)MEM_mallocN(sizeof(*verticesMap) * nAllVerts, __func__); - memset(verticesMap, 0xff, sizeof(*verticesMap) * nAllVerts); - int curIdx = 0; - //vertices - mesh verts - //iterate over all polys and create map for their vertices first... - for (int polyidx=0; polyidxrelease(dm); + return false; + } + + int *dtrisToPolysMap = nullptr, *dtrisToTrisMap = nullptr, *trisToFacesMap = nullptr; + int nAllVerts = 0; + float *allVerts = nullptr; + buildNavMeshDataByDerivedMesh(dm, &vertsPerPoly, &nAllVerts, &allVerts, &ndtris, &dtris, + &npolys, &dmeshes, &polys, &dtrisToPolysMap, &dtrisToTrisMap, &trisToFacesMap); + + MEM_SAFE_FREE(dtrisToPolysMap); + MEM_SAFE_FREE(dtrisToTrisMap); + MEM_SAFE_FREE(trisToFacesMap); + + unsigned short *verticesMap = (unsigned short *)MEM_mallocN(sizeof(*verticesMap) * nAllVerts, __func__); + memset(verticesMap, 0xff, sizeof(*verticesMap) * nAllVerts); + int curIdx = 0; + //vertices - mesh verts + //iterate over all polys and create map for their vertices first... + for (int polyidx = 0; polyidx < npolys; polyidx++) { + unsigned short *poly = &polys[polyidx * vertsPerPoly * 2]; + for (int i = 0; i < vertsPerPoly; i++) { + unsigned short idx = poly[i]; + if (idx == 0xffff) { + break; + } + if (verticesMap[idx] == 0xffff) { + verticesMap[idx] = curIdx++; } + poly[i] = verticesMap[idx]; } - nverts = curIdx; - //...then iterate over detailed meshes - //transform indices to local ones (for each navigation polygon) - for (int polyidx=0; polyidx0) - { - dvertices = new float[ndvertsuniq*3]; - } - for (int vi=0; vi 0) { + dvertices = new float[ndvertsuniq * 3]; + } + for (int vi = 0; vi < nAllVerts; vi++) { + int newIdx = verticesMap[vi]; + if (newIdx != 0xffff) { + if (newIdx < nverts) { + //navigation mesh vertex + memcpy(vertices + 3 * newIdx, allVerts + 3 * vi, 3 * sizeof(float)); + } + else { + //detailed mesh vertex + memcpy(dvertices + 3 * (newIdx - nverts), allVerts + 3 * vi, 3 * sizeof(float)); } } + } - MEM_SAFE_FREE(allVerts); - - MEM_freeN(verticesMap); - } - else - { - //create from RAS_MeshObject (detailed mesh is fake) - RAS_MeshObject* meshobj = GetMesh(0); - vertsPerPoly = 3; - nverts = meshobj->m_sharedvertex_map.size(); - if (nverts >= 0xffff) - return false; - //calculate count of tris - int nmeshpolys = meshobj->NumPolygons(); - npolys = nmeshpolys; - for (int p=0; pGetPolygon(p)->VertexCount(); - npolys+=vertcount-3; - } + MEM_SAFE_FREE(allVerts); + MEM_freeN(verticesMap); + dm->release(dm); - //create verts - vertices = new float[nverts*3]; - float* vert = vertices; - for (int vi=0; vim_sharedvertex_map[vi].empty() ? meshobj->GetVertexLocation(vi) : NULL; - if (pos) - copy_v3_v3(vert, pos); - else - { - memset(vert, 0, 3*sizeof(float)); //vertex isn't in any poly, set dummy zero coordinates + return true; +} + +bool KX_NavMeshObject::BuildFromMesh(float *&vertices, int& nverts, + unsigned short * &polys, int& npolys, unsigned short *&dmeshes, + float *&dvertices, int &ndvertsuniq, unsigned short *&dtris, + int& ndtris, int &vertsPerPoly) +{ + KX_Mesh *meshobj = m_meshes.front(); + vertsPerPoly = 3; + + // Indices count. + unsigned int numindices = 0; + // Original (without split of normal or UV) vertex count. + unsigned int numvertices = 0; + + for (RAS_MeshMaterial *meshmat : meshobj->GetMeshMaterialList()) { + RAS_DisplayArray *array = meshmat->GetDisplayArray(); + + numindices += array->GetTriangleIndexCount(); + numvertices = std::max(numvertices, array->GetMaxOrigIndex() + 1); + } + + // Detour can't manage more than 65536 vertices. + if (numvertices > 0xffff) { + return false; + } + + vertices = new float[numvertices * 3]; + // Detour supports 6 indices per polygons natively, 0xffff is the discard value. + polys = (unsigned short *)MEM_callocN(sizeof(unsigned short) * numindices * 2, "BuildVertIndArrays polys"); + memset(polys, 0xff, sizeof(unsigned short) * numindices * 2); + + /// Map from original vertex index to m_vertexArray vertex index. + std::vector vertRemap(numvertices, -1); + + // Current vertex written. + unsigned int curvert = 0; + // Current index written. + unsigned int curind = 0; + for (RAS_MeshMaterial *meshmat : meshobj->GetMeshMaterialList()) { + RAS_DisplayArray *array = meshmat->GetDisplayArray(); + // Convert location of all vertices and remap if vertices weren't already converted. + for (unsigned int j = 0, numvert = array->GetVertexCount(); j < numvert; ++j) { + const RAS_VertexInfo& info = array->GetVertexInfo(j); + const unsigned int origIndex = info.GetOrigIndex(); + /* Avoid double conversion of two unique vertices using the same base: + * using the same original vertex and so the same position. + */ + if (vertRemap[origIndex] != -1) { + continue; } - vert+=3; + + copy_v3_v3(&vertices[curvert * 3], array->GetPosition(j).data); + + // Register the vertex index where the position was converted in m_vertexArray. + vertRemap[origIndex] = curvert++; } - //create tris - polys = (unsigned short *)MEM_callocN(sizeof(unsigned short)*3*2*npolys, "BuildVertIndArrays polys"); - memset(polys, 0xff, sizeof(unsigned short)*3*2*npolys); - unsigned short *poly = polys; - RAS_Polygon* raspoly; - for (int p=0; pGetPolygon(p); - for (int v=0; vVertexCount()-2; v++) - { - poly[0] = raspoly->GetVertex(0)->getOrigIndex(); - for (size_t i=1; i<3; i++) - { - poly[i] = raspoly->GetVertex(v+i)->getOrigIndex(); - } - poly += 6; + for (unsigned int j = 0, numtris = array->GetTriangleIndexCount() / 3; j < numtris; ++j) { + for (unsigned short k = 0; k < 3; ++k) { + const unsigned int index = array->GetTriangleIndex(j * 3 + k); + const RAS_VertexInfo& info = array->GetVertexInfo(index); + const unsigned int origIndex = info.GetOrigIndex(); + polys[curind + k] = vertRemap[origIndex]; } + curind += 6; } - dmeshes = NULL; - dvertices = NULL; - ndvertsuniq = 0; - dtris = NULL; - ndtris = npolys; } - dm->release(dm); + + nverts = numvertices; + npolys = numindices / vertsPerPoly; + dmeshes = nullptr; + dvertices = nullptr; + ndvertsuniq = 0; + dtris = nullptr; + ndtris = npolys; return true; } +bool KX_NavMeshObject::BuildVertIndArrays(float *&vertices, int& nverts, + unsigned short * &polys, int& npolys, unsigned short *&dmeshes, + float *&dvertices, int &ndvertsuniq, unsigned short *&dtris, + int& ndtris, int &vertsPerPoly) +{ + if (BuildFromDerivedMesh(vertices, nverts, polys, npolys, dmeshes, dvertices, ndvertsuniq, dtris, ndtris, vertsPerPoly)) { + return true; + } + + return BuildFromMesh(vertices, nverts, polys, npolys, dmeshes, dvertices, ndvertsuniq, dtris, ndtris, vertsPerPoly); +} bool KX_NavMeshObject::BuildNavMesh() { - if (m_navMesh) - { + KX_ObstacleSimulation *obssimulation = GetScene()->GetObstacleSimulation(); + + if (obssimulation) { + obssimulation->DestroyObstacleForObj(this); + } + + if (m_navMesh) { delete m_navMesh; - m_navMesh = NULL; + m_navMesh = nullptr; } - if (GetMeshCount()==0) - { - printf("Can't find mesh for navmesh object: %s\n", m_name.ReadPtr()); + if (m_meshes.empty()) { + CM_Error("can't find mesh for navmesh object: " << m_name); return false; } - float *vertices = NULL, *dvertices = NULL; - unsigned short *polys = NULL, *dtris = NULL, *dmeshes = NULL; + float *vertices = nullptr, *dvertices = nullptr; + unsigned short *polys = nullptr, *dtris = nullptr, *dmeshes = nullptr; int nverts = 0, npolys = 0, ndvertsuniq = 0, ndtris = 0; int vertsPerPoly = 0; - if (!BuildVertIndArrays(vertices, nverts, polys, npolys, - dmeshes, dvertices, ndvertsuniq, dtris, ndtris, vertsPerPoly ) - || vertsPerPoly<3) - { - printf("Can't build navigation mesh data for object:%s\n", m_name.ReadPtr()); + if (!BuildVertIndArrays(vertices, nverts, polys, npolys, dmeshes, dvertices, ndvertsuniq, dtris, ndtris, vertsPerPoly) || + vertsPerPoly < 3) { + CM_Error("can't build navigation mesh data for object: " << m_name); if (vertices) { delete[] vertices; } @@ -315,69 +359,66 @@ bool KX_NavMeshObject::BuildNavMesh() return false; } - MT_Point3 pos; - if (dmeshes==NULL) - { - for (int i=0; i((vertices[3*i+0]-bmin[0])*ics); - vertsi[3*i+1] = static_cast((vertices[3*i+1]-bmin[1])*ics); - vertsi[3*i+2] = static_cast((vertices[3*i+2]-bmin[2])*ics); + unsigned short *vertsi = new unsigned short[3 * nverts]; + float ics = 1.f / cs; + for (int i = 0; i < nverts; i++) { + vertsi[3 * i + 0] = static_cast((vertices[3 * i + 0] - bmin[0]) * ics); + vertsi[3 * i + 1] = static_cast((vertices[3 * i + 1] - bmin[1]) * ics); + vertsi[3 * i + 2] = static_cast((vertices[3 * i + 2] - bmin[2]) * ics); } // Calculate data size const int headerSize = sizeof(dtStatNavMeshHeader); - const int vertsSize = sizeof(float)*3*nverts; - const int polysSize = sizeof(dtStatPoly)*npolys; - const int nodesSize = sizeof(dtStatBVNode)*npolys*2; - const int detailMeshesSize = sizeof(dtStatPolyDetail)*npolys; - const int detailVertsSize = sizeof(float)*3*ndvertsuniq; - const int detailTrisSize = sizeof(unsigned char)*4*ndtris; + const int vertsSize = sizeof(float) * 3 * nverts; + const int polysSize = sizeof(dtStatPoly) * npolys; + const int nodesSize = sizeof(dtStatBVNode) * npolys * 2; + const int detailMeshesSize = sizeof(dtStatPolyDetail) * npolys; + const int detailVertsSize = sizeof(float) * 3 * ndvertsuniq; + const int detailTrisSize = sizeof(unsigned char) * 4 * ndtris; const int dataSize = headerSize + vertsSize + polysSize + nodesSize + - detailMeshesSize + detailVertsSize + detailTrisSize; - unsigned char* data = new unsigned char[dataSize]; - if (!data) - return false; + detailMeshesSize + detailVertsSize + detailTrisSize; + unsigned char *data = new unsigned char[dataSize]; + memset(data, 0, dataSize); - unsigned char* d = data; - dtStatNavMeshHeader* header = (dtStatNavMeshHeader*)d; d += headerSize; - float* navVerts = (float*)d; d += vertsSize; - dtStatPoly* navPolys = (dtStatPoly*)d; d += polysSize; - dtStatBVNode* navNodes = (dtStatBVNode*)d; d += nodesSize; - dtStatPolyDetail* navDMeshes = (dtStatPolyDetail*)d; d += detailMeshesSize; - float* navDVerts = (float*)d; d += detailVertsSize; - unsigned char* navDTris = (unsigned char*)d; d += detailTrisSize; + unsigned char *d = data; + dtStatNavMeshHeader *header = (dtStatNavMeshHeader *)d; d += headerSize; + float *navVerts = (float *)d; d += vertsSize; + dtStatPoly *navPolys = (dtStatPoly *)d; d += polysSize; + dtStatBVNode *navNodes = (dtStatBVNode *)d; d += nodesSize; + dtStatPolyDetail *navDMeshes = (dtStatPolyDetail *)d; d += detailMeshesSize; + float *navDVerts = (float *)d; d += detailVertsSize; + unsigned char *navDTris = (unsigned char *)d; d += detailTrisSize; // Store header header->magic = DT_STAT_NAVMESH_MAGIC; @@ -396,260 +437,251 @@ bool KX_NavMeshObject::BuildNavMesh() header->ndtris = ndtris; // Store vertices - for (int i = 0; i < nverts; ++i) - { - const unsigned short* iv = &vertsi[i*3]; - float* v = &navVerts[i*3]; + for (int i = 0; i < nverts; ++i) { + const unsigned short *iv = &vertsi[i * 3]; + float *v = &navVerts[i * 3]; v[0] = bmin[0] + iv[0] * cs; v[1] = bmin[1] + iv[1] * cs; v[2] = bmin[2] + iv[2] * cs; } - //memcpy(navVerts, vertices, nverts*3*sizeof(float)); - // Store polygons - const unsigned short* src = polys; - for (int i = 0; i < npolys; ++i) - { - dtStatPoly* p = &navPolys[i]; + // Store polygons. + const unsigned short *src = polys; + for (int i = 0; i < npolys; ++i) { + dtStatPoly *p = &navPolys[i]; p->nv = 0; - for (int j = 0; j < vertsPerPoly; ++j) - { - if (src[j] == 0xffff) break; + for (int j = 0; j < vertsPerPoly; ++j) { + if (src[j] == 0xffff) { + break; + } p->v[j] = src[j]; - p->n[j] = src[vertsPerPoly+j]+1; + p->n[j] = src[vertsPerPoly + j] + 1; p->nv++; } - src += vertsPerPoly*2; + src += vertsPerPoly * 2; } - header->nnodes = createBVTree(vertsi, nverts, polys, npolys, vertsPerPoly, - cs, cs, npolys*2, navNodes); + header->nnodes = createBVTree(vertsi, nverts, polys, npolys, vertsPerPoly, cs, cs, npolys * 2, navNodes); - - if (dmeshes==NULL) - { - //create fake detail meshes - for (int i = 0; i < npolys; ++i) - { + if (!dmeshes) { + // Create fake detail meshes. + for (int i = 0; i < npolys; ++i) { dtStatPolyDetail& dtl = navDMeshes[i]; dtl.vbase = 0; dtl.nverts = 0; dtl.tbase = i; dtl.ntris = 1; } - // setup triangles. - unsigned char* tri = navDTris; - for (size_t i=0; iinit(data, dataSize, true); - delete [] vertices; + delete[] vertices; - /* navmesh conversion is using C guarded alloc for memory allocaitons */ + // Navmesh conversion is using C guarded alloc for memory allocaitons. MEM_freeN(polys); - if (dmeshes) MEM_freeN(dmeshes); - if (dtris) MEM_freeN(dtris); + if (dmeshes) { + MEM_freeN(dmeshes); + } + if (dtris) { + MEM_freeN(dtris); + } - if (dvertices) - delete [] dvertices; + if (dvertices) { + delete[] dvertices; + } - if (vertsi) - delete [] vertsi; + if (vertsi) { + delete[] vertsi; + } + + if (obssimulation) { + obssimulation->AddObstaclesForNavMesh(this); + } return true; } -dtStatNavMesh* KX_NavMeshObject::GetNavMesh() +dtStatNavMesh *KX_NavMeshObject::GetNavMesh() const { return m_navMesh; } -void KX_NavMeshObject::DrawNavMesh(NavMeshRenderMode renderMode) +void KX_NavMeshObject::DrawNavMesh(NavMeshRenderMode renderMode) const { - if (!m_navMesh) + if (!m_navMesh) { return; - MT_Vector3 color(0.f, 0.f, 0.f); + } + + const mt::vec4 color(0.0f, 0.0f, 0.0f, 1.0f); - switch (renderMode) - { - case RM_POLYS : - case RM_WALLS : - for (int pi=0; pigetPolyCount(); pi++) + switch (renderMode) { + case RM_POLYS: + case RM_WALLS: { - const dtStatPoly* poly = m_navMesh->getPoly(pi); - - for (int i = 0, j = (int)poly->nv-1; i < (int)poly->nv; j = i++) - { - if (poly->n[j] && renderMode==RM_WALLS) - continue; - const float* vif = m_navMesh->getVertex(poly->v[i]); - const float* vjf = m_navMesh->getVertex(poly->v[j]); - MT_Point3 vi(vif[0], vif[2], vif[1]); - MT_Point3 vj(vjf[0], vjf[2], vjf[1]); - vi = TransformToWorldCoords(vi); - vj = TransformToWorldCoords(vj); - KX_RasterizerDrawDebugLine(vi, vj, color); + for (int pi = 0; pi < m_navMesh->getPolyCount(); pi++) { + const dtStatPoly *poly = m_navMesh->getPoly(pi); + + for (int i = 0, j = (int)poly->nv - 1; i < (int)poly->nv; j = i++) { + if (poly->n[j] && renderMode == RM_WALLS) { + continue; + } + const float *vif = m_navMesh->getVertex(poly->v[i]); + const float *vjf = m_navMesh->getVertex(poly->v[j]); + mt::vec3 vi(vif[0], vif[2], vif[1]); + mt::vec3 vj(vjf[0], vjf[2], vjf[1]); + vi = TransformToWorldCoords(vi); + vj = TransformToWorldCoords(vj); + KX_RasterizerDrawDebugLine(vi, vj, color); + } } + break; } - break; - case RM_TRIS : - for (int i = 0; i < m_navMesh->getPolyDetailCount(); ++i) + case RM_TRIS: { - const dtStatPoly* p = m_navMesh->getPoly(i); - const dtStatPolyDetail* pd = m_navMesh->getPolyDetail(i); - - for (int j = 0; j < pd->ntris; ++j) - { - const unsigned char* t = m_navMesh->getDetailTri(pd->tbase+j); - MT_Point3 tri[3]; - for (int k = 0; k < 3; ++k) - { - const float* v; - if (t[k] < p->nv) - v = m_navMesh->getVertex(p->v[t[k]]); - else - v = m_navMesh->getDetailVertex(pd->vbase+(t[k]-p->nv)); - float pos[3]; - rcVcopy(pos, v); - flipAxes(pos); - tri[k].setValue(pos); - } + for (int i = 0; i < m_navMesh->getPolyDetailCount(); ++i) { + const dtStatPoly *p = m_navMesh->getPoly(i); + const dtStatPolyDetail *pd = m_navMesh->getPolyDetail(i); + + for (int j = 0; j < pd->ntris; ++j) { + const unsigned char *t = m_navMesh->getDetailTri(pd->tbase + j); + mt::vec3 tri[3]; + for (int k = 0; k < 3; ++k) { + const float *v; + if (t[k] < p->nv) { + v = m_navMesh->getVertex(p->v[t[k]]); + } + else { + v = m_navMesh->getDetailVertex(pd->vbase + (t[k] - p->nv)); + } + float pos[3]; + rcVcopy(pos, v); + flipAxes(pos); + tri[k] = mt::vec3(pos); + } - for (int k=0; k<3; k++) - tri[k] = TransformToWorldCoords(tri[k]); + for (int k = 0; k < 3; k++) { + tri[k] = TransformToWorldCoords(tri[k]); + } - for (int k=0; k<3; k++) - KX_RasterizerDrawDebugLine(tri[k], tri[(k+1)%3], color); + for (int k = 0; k < 3; k++) { + KX_RasterizerDrawDebugLine(tri[k], tri[(k + 1) % 3], color); + } + } } + break; + } + default: + { + break; } - break; - default: - /* pass */ - break; } } -MT_Point3 KX_NavMeshObject::TransformToLocalCoords(const MT_Point3& wpos) +mt::vec3 KX_NavMeshObject::TransformToLocalCoords(const mt::vec3& wpos) const { - MT_Matrix3x3 orientation = NodeGetWorldOrientation(); - const MT_Vector3& scaling = NodeGetWorldScaling(); - orientation.scale(scaling[0], scaling[1], scaling[2]); - MT_Transform worldtr(NodeGetWorldPosition(), orientation); - MT_Transform invworldtr; - invworldtr.invert(worldtr); - MT_Point3 lpos = invworldtr(wpos); - return lpos; + return (NodeGetWorldTransform().Inverse() * wpos); } -MT_Point3 KX_NavMeshObject::TransformToWorldCoords(const MT_Point3& lpos) +mt::vec3 KX_NavMeshObject::TransformToWorldCoords(const mt::vec3& lpos) const { - MT_Matrix3x3 orientation = NodeGetWorldOrientation(); - const MT_Vector3& scaling = NodeGetWorldScaling(); - orientation.scale(scaling[0], scaling[1], scaling[2]); - MT_Transform worldtr(NodeGetWorldPosition(), orientation); - MT_Point3 wpos = worldtr(lpos); - return wpos; + return (NodeGetWorldTransform() * lpos); } -int KX_NavMeshObject::FindPath(const MT_Point3& from, const MT_Point3& to, float* path, int maxPathLen) +KX_NavMeshObject::PathType KX_NavMeshObject::FindPath(const mt::vec3& from, const mt::vec3& to, unsigned int maxPathLen) const { - if (!m_navMesh) - return 0; - MT_Point3 localfrom = TransformToLocalCoords(from); - MT_Point3 localto = TransformToLocalCoords(to); - float spos[3], epos[3]; - localfrom.getValue(spos); flipAxes(spos); - localto.getValue(epos); flipAxes(epos); - dtStatPolyRef sPolyRef = m_navMesh->findNearestPoly(spos, polyPickExt); - dtStatPolyRef ePolyRef = m_navMesh->findNearestPoly(epos, polyPickExt); - - int pathLen = 0; - if (sPolyRef && ePolyRef) - { - dtStatPolyRef* polys = new dtStatPolyRef[maxPathLen]; - int npolys; - npolys = m_navMesh->findPath(sPolyRef, ePolyRef, spos, epos, polys, maxPathLen); - if (npolys) - { - pathLen = m_navMesh->findStraightPath(spos, epos, polys, npolys, path, maxPathLen); - for (int i=0; ifindNearestPoly(localfrom.Data(), polyPickExt); + dtStatPolyRef ePolyRef = m_navMesh->findNearestPoly(localto.Data(), polyPickExt); + + if (sPolyRef && ePolyRef) { + dtStatPolyRef *polys = (dtStatPolyRef *)BLI_array_alloca(polys, maxPathLen); + const unsigned int npolys = m_navMesh->findPath(sPolyRef, ePolyRef, localfrom.Data(), localto.Data(), polys, maxPathLen); + if (npolys > 0) { + float(*points)[3] = (float(*)[3])BLI_array_alloca(points, maxPathLen); + const unsigned int pathLen = m_navMesh->findStraightPath(localfrom.Data(), localto.Data(), polys, npolys, + &points[0][0], maxPathLen); + + path.resize(pathLen); + for (unsigned int i = 0; i < pathLen; ++i) { + mt::vec3 waypoint(points[i]); + flipAxes(waypoint); + path[i] = TransformToWorldCoords(waypoint); } } - - delete[] polys; } - return pathLen; + return path; } -float KX_NavMeshObject::Raycast(const MT_Point3& from, const MT_Point3& to) +float KX_NavMeshObject::Raycast(const mt::vec3& from, const mt::vec3& to) const { - if (!m_navMesh) + if (!m_navMesh) { return 0.f; - MT_Point3 localfrom = TransformToLocalCoords(from); - MT_Point3 localto = TransformToLocalCoords(to); - float spos[3], epos[3]; - localfrom.getValue(spos); flipAxes(spos); - localto.getValue(epos); flipAxes(epos); - dtStatPolyRef sPolyRef = m_navMesh->findNearestPoly(spos, polyPickExt); - float t=0; + } + + mt::vec3 localfrom = TransformToLocalCoords(from); + mt::vec3 localto = TransformToLocalCoords(to); + flipAxes(localfrom); + flipAxes(localto); + + dtStatPolyRef sPolyRef = m_navMesh->findNearestPoly(localfrom.Data(), polyPickExt); + + float t = 0.0f; static dtStatPolyRef polys[MAX_PATH_LEN]; - m_navMesh->raycast(sPolyRef, spos, epos, t, polys, MAX_PATH_LEN); + m_navMesh->raycast(sPolyRef, localfrom.Data(), localto.Data(), t, polys, MAX_PATH_LEN); return t; } -void KX_NavMeshObject::DrawPath(const float *path, int pathLen, const MT_Vector3& color) +void KX_NavMeshObject::DrawPath(const PathType& path, const mt::vec4& color) const { - MT_Vector3 a,b; - for (int i=0; i=0 && arg= 0 && arg < RM_MAX) { renderMode = (NavMeshRenderMode)arg; + } DrawNavMesh(renderMode); Py_RETURN_NONE; } -KX_PYMETHODDEF_DOC_NOARGS(KX_NavMeshObject, rebuild, - "rebuild(): rebuild navigation mesh\n") +EXP_PYMETHODDEF_DOC_NOARGS(KX_NavMeshObject, rebuild, + "rebuild(): rebuild navigation mesh\n") { BuildNavMesh(); Py_RETURN_NONE; } -#endif // WITH_PYTHON +#endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_NavMeshObject.h b/source/gameengine/Ketsji/KX_NavMeshObject.h index 0f0bf8008d05..d82cb4d2ba9b 100644 --- a/source/gameengine/Ketsji/KX_NavMeshObject.h +++ b/source/gameengine/Ketsji/KX_NavMeshObject.h @@ -24,57 +24,73 @@ * * ***** END GPL LICENSE BLOCK ***** */ + #ifndef __KX_NAVMESHOBJECT_H__ #define __KX_NAVMESHOBJECT_H__ + #include "DetourStatNavMesh.h" #include "KX_GameObject.h" -#include "EXP_PyObjectPlus.h" -#include - -class RAS_MeshObject; -class MT_Transform; -class KX_NavMeshObject: public KX_GameObject +class KX_NavMeshObject : public KX_GameObject { Py_Header protected: - dtStatNavMesh* m_navMesh; + dtStatNavMesh *m_navMesh; + + bool BuildFromDerivedMesh(float *&vertices, int& nverts, + unsigned short * &polys, int& npolys, unsigned short *&dmeshes, + float *&dvertices, int &ndvertsuniq, unsigned short * &dtris, + int& ndtris, int &vertsPerPoly); + + bool BuildFromMesh(float *&vertices, int& nverts, + unsigned short * &polys, int& npolys, unsigned short *&dmeshes, + float *&dvertices, int &ndvertsuniq, unsigned short * &dtris, + int& ndtris, int &vertsPerPoly); bool BuildVertIndArrays(float *&vertices, int& nverts, - unsigned short* &polys, int& npolys, unsigned short *&dmeshes, - float *&dvertices, int &ndvertsuniq, unsigned short* &dtris, - int& ndtris, int &vertsPerPoly); + unsigned short * &polys, int& npolys, unsigned short *&dmeshes, + float *&dvertices, int &ndvertsuniq, unsigned short * &dtris, + int& ndtris, int &vertsPerPoly); public: - KX_NavMeshObject(void* sgReplicationInfo, SG_Callbacks callbacks); - ~KX_NavMeshObject(); + using PathType = std::vector >; - virtual CValue* GetReplica(); - virtual void ProcessReplica(); + enum NavMeshRenderMode + { + RM_WALLS, + RM_POLYS, + RM_TRIS, + RM_MAX + }; + KX_NavMeshObject(void *sgReplicationInfo, SG_Callbacks callbacks); + virtual ~KX_NavMeshObject(); + + virtual EXP_Value *GetReplica(); + virtual void ProcessReplica(); + virtual int GetGameObjectType() const; bool BuildNavMesh(); - dtStatNavMesh* GetNavMesh(); - int FindPath(const MT_Point3& from, const MT_Point3& to, float* path, int maxPathLen); - float Raycast(const MT_Point3& from, const MT_Point3& to); + dtStatNavMesh *GetNavMesh() const; + + PathType FindPath(const mt::vec3& from, const mt::vec3& to, unsigned int maxPathLen) const; + float Raycast(const mt::vec3& from, const mt::vec3& to) const; + + void DrawNavMesh(NavMeshRenderMode mode) const; + void DrawPath(const PathType& path, const mt::vec4& color) const; - enum NavMeshRenderMode {RM_WALLS, RM_POLYS, RM_TRIS, RM_MAX}; - void DrawNavMesh(NavMeshRenderMode mode); - void DrawPath(const float *path, int pathLen, const MT_Vector3& color); + mt::vec3 TransformToLocalCoords(const mt::vec3& wpos) const; + mt::vec3 TransformToWorldCoords(const mt::vec3& lpos) const; - MT_Point3 TransformToLocalCoords(const MT_Point3& wpos); - MT_Point3 TransformToWorldCoords(const MT_Point3& lpos); #ifdef WITH_PYTHON - /* --------------------------------------------------------------------- */ - /* Python interface ---------------------------------------------------- */ - /* --------------------------------------------------------------------- */ - - KX_PYMETHOD_DOC(KX_NavMeshObject, findPath); - KX_PYMETHOD_DOC(KX_NavMeshObject, raycast); - KX_PYMETHOD_DOC(KX_NavMeshObject, draw); - KX_PYMETHOD_DOC_NOARGS(KX_NavMeshObject, rebuild); -#endif /* WITH_PYTHON */ + + EXP_PYMETHOD_DOC(KX_NavMeshObject, findPath); + EXP_PYMETHOD_DOC(KX_NavMeshObject, raycast); + EXP_PYMETHOD_DOC(KX_NavMeshObject, draw); + EXP_PYMETHOD_DOC_NOARGS(KX_NavMeshObject, rebuild); + +#endif // WITH_PYTHON }; -#endif /* __KX_NAVMESHOBJECT_H__ */ +#endif // __KX_NAVMESHOBJECT_H__ diff --git a/source/gameengine/Ketsji/KX_NearSensor.cpp b/source/gameengine/Ketsji/KX_NearSensor.cpp index c436c77c32b1..f29748d351c7 100644 --- a/source/gameengine/Ketsji/KX_NearSensor.cpp +++ b/source/gameengine/Ketsji/KX_NearSensor.cpp @@ -36,37 +36,36 @@ #include "KX_NearSensor.h" #include "SCA_LogicManager.h" #include "KX_GameObject.h" -#include "KX_TouchEventManager.h" +#include "KX_CollisionEventManager.h" #include "KX_Scene.h" // needed to create a replica #include "PHY_IPhysicsEnvironment.h" #include "PHY_IPhysicsController.h" #include "PHY_IMotionState.h" -KX_NearSensor::KX_NearSensor(SCA_EventManager* eventmgr, - KX_GameObject* gameobj, - float margin, - float resetmargin, - bool bFindMaterial, - const STR_String& touchedpropname, - PHY_IPhysicsController* ctrl) - :KX_TouchSensor(eventmgr, - gameobj, - bFindMaterial, - false, - touchedpropname), - m_Margin(margin), - m_ResetMargin(resetmargin) +KX_NearSensor::KX_NearSensor(SCA_EventManager *eventmgr, + KX_GameObject *gameobj, + float margin, + float resetmargin, + bool bFindMaterial, + const std::string& touchedpropname, + PHY_IPhysicsController *ctrl) + :KX_CollisionSensor(eventmgr, + gameobj, + bFindMaterial, + false, + touchedpropname), + m_Margin(margin), + m_ResetMargin(resetmargin) { - gameobj->getClientInfo()->m_sensors.remove(this); + gameobj->GetClientInfo().m_sensors.remove(this); m_client_info = new KX_ClientObjectInfo(gameobj, KX_ClientObjectInfo::SENSOR); m_client_info->m_sensors.push_back(this); //DT_ShapeHandle shape = (DT_ShapeHandle) vshape; m_physCtrl = ctrl; - if (m_physCtrl) - { + if (m_physCtrl) { m_physCtrl->SetMargin(m_Margin); m_physCtrl->SetNewClientInfo(m_client_info); } @@ -77,38 +76,32 @@ void KX_NearSensor::SynchronizeTransform() { // The near and radar sensors are using a different physical object which is // not linked to the parent object, must synchronize it. - if (m_physCtrl) - { - PHY_IMotionState* motionState = m_physCtrl->GetMotionState(); - KX_GameObject* parent = ((KX_GameObject*)GetParent()); - const MT_Point3& pos = parent->NodeGetWorldPosition(); - float ori[12]; - parent->NodeGetWorldOrientation().getValue(ori); - motionState->SetWorldPosition(pos[0], pos[1], pos[2]); - motionState->SetWorldOrientation(ori); + if (m_physCtrl) { + PHY_IMotionState *motionState = m_physCtrl->GetMotionState(); + KX_GameObject *parent = ((KX_GameObject *)GetParent()); + motionState->SetWorldPosition(parent->NodeGetWorldPosition()); + motionState->SetWorldOrientation(parent->NodeGetWorldOrientation()); m_physCtrl->WriteMotionStateToDynamics(true); } } -CValue* KX_NearSensor::GetReplica() +EXP_Value *KX_NearSensor::GetReplica() { - KX_NearSensor* replica = new KX_NearSensor(*this); + KX_NearSensor *replica = new KX_NearSensor(*this); replica->ProcessReplica(); return replica; } void KX_NearSensor::ProcessReplica() { - KX_TouchSensor::ProcessReplica(); + KX_CollisionSensor::ProcessReplica(); m_client_info = new KX_ClientObjectInfo(m_client_info->m_gameobject, KX_ClientObjectInfo::SENSOR); - if (m_physCtrl) - { + if (m_physCtrl) { m_physCtrl = m_physCtrl->GetReplicaForSensors(); - if (m_physCtrl) - { - //static_cast(m_eventmgr)->GetPhysicsEnvironment()->addSensor(replica->m_physCtrl); + if (m_physCtrl) { + //static_cast(m_eventmgr)->GetPhysicsEnvironment()->addSensor(replica->m_physCtrl); m_physCtrl->SetMargin(m_Margin); m_physCtrl->SetNewClientInfo(m_client_info); } @@ -116,10 +109,10 @@ void KX_NearSensor::ProcessReplica() } } -void KX_NearSensor::ReParent(SCA_IObject* parent) +void KX_NearSensor::ReParent(SCA_IObject *parent) { SCA_ISensor::ReParent(parent); - m_client_info->m_gameobject = static_cast(parent); + m_client_info->m_gameobject = static_cast(parent); m_client_info->m_sensors.push_back(this); //Synchronize here with the actual parent. SynchronizeTransform(); @@ -130,31 +123,28 @@ void KX_NearSensor::ReParent(SCA_IObject* parent) KX_NearSensor::~KX_NearSensor() { // for nearsensor, the sensor is the 'owner' of sumoobj - // for touchsensor, it's the parent - if (m_physCtrl) - { - //static_cast(m_eventmgr)->GetPhysicsEnvironment()->removeSensor(m_physCtrl); + // for collisionsensor, it's the parent + if (m_physCtrl) { + //static_cast(m_eventmgr)->GetPhysicsEnvironment()->removeSensor(m_physCtrl); delete m_physCtrl; - m_physCtrl = NULL; + m_physCtrl = nullptr; } - if (m_client_info) + if (m_client_info) { delete m_client_info; + } } void KX_NearSensor::SetPhysCtrlRadius() { - if (m_bTriggered) - { - if (m_physCtrl) - { + if (m_bTriggered) { + if (m_physCtrl) { m_physCtrl->SetRadius(m_ResetMargin); } - } else - { - if (m_physCtrl) - { + } + else { + if (m_physCtrl) { m_physCtrl->SetRadius(m_Margin); } } @@ -165,8 +155,7 @@ bool KX_NearSensor::Evaluate() bool result = false; // KX_GameObject* parent = static_cast(GetParent()); - if (m_bTriggered != m_bLastTriggered) - { + if (m_bTriggered != m_bLastTriggered) { m_bLastTriggered = m_bTriggered; SetPhysCtrlRadius(); @@ -180,26 +169,23 @@ bool KX_NearSensor::Evaluate() // this function is called at broad phase stage to check if the two controller // need to interact at all. It is used for Near/Radar sensor that don't need to // check collision with object not included in filter -bool KX_NearSensor::BroadPhaseFilterCollision(void*obj1,void*obj2) +bool KX_NearSensor::BroadPhaseFilterCollision(PHY_IPhysicsController *ctrl1, PHY_IPhysicsController *ctrl2) { - KX_GameObject* parent = static_cast(GetParent()); + KX_GameObject *parent = static_cast(GetParent()); // need the mapping from PHY_IPhysicsController to gameobjects now - assert(obj1==m_physCtrl && obj2); - KX_ClientObjectInfo *client_info = static_cast((static_cast(obj2))->GetNewClientInfo()); + BLI_assert(ctrl1 == m_physCtrl && ctrl2); + KX_ClientObjectInfo *client_info = static_cast(ctrl2->GetNewClientInfo()); - KX_GameObject* gameobj = ( client_info ? - client_info->m_gameobject : - NULL); + KX_GameObject *gameobj = (client_info ? + client_info->m_gameobject : + nullptr); - if (gameobj && (gameobj != parent)) - { + if (gameobj && (gameobj != parent)) { // only take valid colliders - if (client_info->m_type == KX_ClientObjectInfo::ACTOR) - { - if ((m_touchedpropname.Length() == 0) || - (gameobj->GetProperty(m_touchedpropname))) - { + if (client_info->m_type == KX_ClientObjectInfo::ACTOR) { + if ((m_touchedpropname.empty()) || + (gameobj->GetProperty(m_touchedpropname))) { return true; } } @@ -208,37 +194,36 @@ bool KX_NearSensor::BroadPhaseFilterCollision(void*obj1,void*obj2) return false; } -bool KX_NearSensor::NewHandleCollision(void *obj1, void *obj2, const PHY_CollData *coll_data) +bool KX_NearSensor::NewHandleCollision(PHY_IPhysicsController *ctrl1, PHY_IPhysicsController *ctrl2, const PHY_ICollData *coll_data) { -// KX_TouchEventManager* toucheventmgr = static_cast(m_eventmgr); +// KX_CollisionEventManager* toucheventmgr = static_cast(m_eventmgr); // KX_GameObject* parent = static_cast(GetParent()); // need the mapping from PHY_IPhysicsController to gameobjects now - KX_ClientObjectInfo *client_info = static_cast (obj1 == m_physCtrl? - ((PHY_IPhysicsController*)obj2)->GetNewClientInfo() : - ((PHY_IPhysicsController*)obj1)->GetNewClientInfo()); + KX_ClientObjectInfo *client_info = static_cast ((ctrl1 == m_physCtrl) ? + ctrl2->GetNewClientInfo() : ctrl1->GetNewClientInfo()); - KX_GameObject* gameobj = ( client_info ? - client_info->m_gameobject : - NULL); + KX_GameObject *gameobj = (client_info ? + client_info->m_gameobject : + nullptr); // Add the same check as in SCA_ISensor::Activate(), // we don't want to record collision when the sensor is not active. if (m_links && !m_suspended && - gameobj /* done in BroadPhaseFilterCollision() && (gameobj != parent)*/) - { - if (!m_colliders->SearchValue(gameobj)) - m_colliders->Add(gameobj->AddRef()); + gameobj /* done in BroadPhaseFilterCollision() && (gameobj != parent)*/) { + if (!m_colliders->SearchValue(gameobj)) { + m_colliders->Add(CM_AddRef(gameobj)); + } // only take valid colliders // These checks are done already in BroadPhaseFilterCollision() //if (client_info->m_type == KX_ClientObjectInfo::ACTOR) //{ - // if ((m_touchedpropname.Length() == 0) || + // if ((m_touchedpropname.empty()) || // (gameobj->GetProperty(m_touchedpropname))) // { - m_bTriggered = true; - m_hitObject = gameobj; + m_bTriggered = true; + m_hitObject = gameobj; // } //} } @@ -257,9 +242,9 @@ bool KX_NearSensor::NewHandleCollision(void *obj1, void *obj2, const PHY_CollDat /* ------------------------------------------------------------------------- */ PyTypeObject KX_NearSensor::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_NearSensor", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -267,26 +252,26 @@ PyTypeObject KX_NearSensor::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, - &KX_TouchSensor::Type, - 0,0,0,0,0,0, + &KX_CollisionSensor::Type, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_NearSensor::Methods[] = { //No methods - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_NearSensor::Attributes[] = { - KX_PYATTRIBUTE_FLOAT_RW_CHECK("distance", 0, 10000, KX_NearSensor, m_Margin, CheckResetDistance), - KX_PYATTRIBUTE_FLOAT_RW_CHECK("resetDistance", 0, 10000, KX_NearSensor, m_ResetMargin, CheckResetDistance), - {NULL} //Sentinel + EXP_PYATTRIBUTE_FLOAT_RW_CHECK("distance", 0, 10000, KX_NearSensor, m_Margin, CheckResetDistance), + EXP_PYATTRIBUTE_FLOAT_RW_CHECK("resetDistance", 0, 10000, KX_NearSensor, m_ResetMargin, CheckResetDistance), + EXP_PYATTRIBUTE_NULL //Sentinel }; #endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_NearSensor.h b/source/gameengine/Ketsji/KX_NearSensor.h index e323357434a7..52a7689488c2 100644 --- a/source/gameengine/Ketsji/KX_NearSensor.h +++ b/source/gameengine/Ketsji/KX_NearSensor.h @@ -33,13 +33,13 @@ #ifndef __KX_NEARSENSOR_H__ #define __KX_NEARSENSOR_H__ -#include "KX_TouchSensor.h" +#include "KX_CollisionSensor.h" #include "KX_ClientObjectInfo.h" class KX_Scene; -struct PHY_CollData; +class PHY_ICollData; -class KX_NearSensor : public KX_TouchSensor +class KX_NearSensor : public KX_CollisionSensor { Py_Header protected: @@ -53,7 +53,7 @@ class KX_NearSensor : public KX_TouchSensor float margin, float resetmargin, bool bFindMaterial, - const STR_String& touchedpropname, + const std::string& touchedpropname, PHY_IPhysicsController* ctrl); #if 0 public: @@ -62,21 +62,25 @@ class KX_NearSensor : public KX_TouchSensor double margin, double resetmargin, bool bFindMaterial, - const STR_String& touchedpropname, + const std::string& touchedpropname, class KX_Scene* scene); #endif - virtual ~KX_NearSensor(); + virtual ~KX_NearSensor(); virtual void SynchronizeTransform(); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); virtual void ProcessReplica(); virtual void SetPhysCtrlRadius(); virtual bool Evaluate(); virtual void ReParent(SCA_IObject* parent); - virtual bool NewHandleCollision(void* obj1,void* obj2, - const PHY_CollData * coll_data); - virtual bool BroadPhaseFilterCollision(void*obj1,void*obj2); - virtual bool BroadPhaseSensorFilterCollision(void* obj1,void* obj2) { return false; } + + virtual bool NewHandleCollision(PHY_IPhysicsController *ctrl1, PHY_IPhysicsController *ctrl2, const PHY_ICollData *colldata); + virtual bool BroadPhaseFilterCollision(PHY_IPhysicsController *ctrl1, PHY_IPhysicsController *ctrl2); + virtual bool BroadPhaseSensorFilterCollision(PHY_IPhysicsController *ctrl1, PHY_IPhysicsController *ctrl2) + { + return false; + } + virtual sensortype GetSensorType() { return ST_NEAR; } #ifdef WITH_PYTHON @@ -88,7 +92,7 @@ class KX_NearSensor : public KX_TouchSensor //No methods //This method is used to make sure the distance does not exceed the reset distance - static int CheckResetDistance(void *self, const PyAttributeDef*) + static int CheckResetDistance(EXP_PyObjectPlus *self, const PyAttributeDef*) { KX_NearSensor* sensor = reinterpret_cast(self); @@ -96,7 +100,7 @@ class KX_NearSensor : public KX_TouchSensor sensor->m_ResetMargin = sensor->m_Margin; sensor->SetPhysCtrlRadius(); - + return 0; } diff --git a/source/gameengine/Ketsji/KX_NodeRelationships.cpp b/source/gameengine/Ketsji/KX_NodeRelationships.cpp new file mode 100644 index 000000000000..bb3b94ef1cf3 --- /dev/null +++ b/source/gameengine/Ketsji/KX_NodeRelationships.cpp @@ -0,0 +1,205 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Ketsji/KX_NodeRelationships.cpp + * \ingroup ketsji + */ + +#include "KX_NodeRelationships.h" + +#include "SG_Node.h" + +#include "BLI_utildefines.h" + +KX_NormalParentRelation::~KX_NormalParentRelation() +{ +} + +KX_NormalParentRelation::KX_NormalParentRelation() +{ +} + +bool KX_NormalParentRelation::UpdateChildCoordinates(SG_Node *child, const SG_Node *parent, bool& parentUpdated) +{ + BLI_assert(child != nullptr); + + if (!parentUpdated && !child->IsModified()) { + return false; + } + + parentUpdated = true; + + if (parent) { + const mt::mat3x4 trans = parent->GetWorldTransform() * child->GetLocalTransform(); + const mt::vec3 scale = trans.ScaleVector3D(); + const mt::vec3 invscale(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z); + const mt::vec3 pos = trans.TranslationVector3D(); + const mt::mat3 rot = trans.RotationMatrix().Scale(invscale); + + child->SetWorldScale(scale); + child->SetWorldPosition(pos); + child->SetWorldOrientation(rot); + + } + else { + child->SetWorldFromLocalTransform(); + } + + child->ClearModified(); + + return true; +} + +SG_ParentRelation *KX_NormalParentRelation::NewCopy() +{ + return new KX_NormalParentRelation(); +} + +KX_VertexParentRelation::~KX_VertexParentRelation() +{ +} + +KX_VertexParentRelation::KX_VertexParentRelation() +{ +} + +bool KX_VertexParentRelation::UpdateChildCoordinates(SG_Node *child, const SG_Node *parent, bool& parentUpdated) +{ + BLI_assert(child != nullptr); + + if (!parentUpdated && !child->IsModified()) { + return false; + } + + child->SetWorldScale(child->GetLocalScale()); + + if (parent) { + child->SetWorldPosition(child->GetLocalPosition() + parent->GetWorldPosition()); + } + else { + child->SetWorldPosition(child->GetLocalPosition()); + } + + child->SetWorldOrientation(child->GetLocalOrientation()); + child->ClearModified(); + + return true; +} + +SG_ParentRelation *KX_VertexParentRelation::NewCopy() +{ + return new KX_VertexParentRelation(); +} + +bool KX_VertexParentRelation::IsVertexRelation() +{ + return true; +} + +KX_SlowParentRelation::KX_SlowParentRelation(float relaxation) + :m_relax(relaxation), + m_initialized(false) +{ +} + +KX_SlowParentRelation::~KX_SlowParentRelation() +{ +} + +bool KX_SlowParentRelation::UpdateChildCoordinates(SG_Node *child, const SG_Node *parent, bool& parentUpdated) +{ + BLI_assert(child != nullptr); + + // The child will move even if the parent is not. + parentUpdated = true; + + if (parent) { + /* This is a slow parent relation + * first compute the normal child world coordinates. */ + const mt::mat3x4 ntrans = parent->GetWorldTransform() * child->GetLocalTransform(); + const mt::vec3 nscale = ntrans.ScaleVector3D(); + const mt::vec3 ninvscale(1.0f / nscale.x, 1.0f / nscale.y, 1.0f / nscale.z); + const mt::vec3 npos = ntrans.TranslationVector3D(); + const mt::mat3 nrot = ntrans.RotationMatrix().Scale(ninvscale); + + if (m_initialized) { + // Get the current world transform. + const mt::vec3& cscale = child->GetWorldScaling(); + const mt::vec3& cpos = child->GetWorldPosition(); + const mt::mat3& crot = child->GetWorldOrientation(); + + /* Now 'interpolate' the normal coordinates with the last + * world coordinates to get the new world coordinates. */ + const float weight = 1.0f / (m_relax + 1.0f); + const mt::vec3 scale = (m_relax * cscale + nscale) * weight; + const mt::vec3 pos = (m_relax * cpos + npos) * weight; + + // For rotation we must go through quaternion. + const mt::quat cquat = mt::quat::FromMatrix(crot).Normalized(); + const mt::quat nquat = mt::quat::FromMatrix(nrot).Normalized(); + const mt::mat3 rot = mt::quat::Slerp(cquat, nquat, weight).ToMatrix(); + + child->SetWorldScale(scale); + child->SetWorldPosition(pos); + child->SetWorldOrientation(rot); + } + else { + child->SetWorldFromLocalTransform(); + m_initialized = true; + } + } + else { + child->SetWorldFromLocalTransform(); + } + + child->ClearModified(); + // This node must always be updated, so reschedule it for next time. + child->ActivateRecheduleUpdateCallback(); + + return true; +} + +SG_ParentRelation *KX_SlowParentRelation::NewCopy() +{ + return new KX_SlowParentRelation(m_relax); +} + +float KX_SlowParentRelation::GetTimeOffset() +{ + return m_relax; +} + +void KX_SlowParentRelation::SetTimeOffset(float relaxation) +{ + m_relax = relaxation; +} + + +bool KX_SlowParentRelation::IsSlowRelation() +{ + return true; +} diff --git a/source/gameengine/Ketsji/KX_NodeRelationships.h b/source/gameengine/Ketsji/KX_NodeRelationships.h new file mode 100644 index 000000000000..fb00852d139b --- /dev/null +++ b/source/gameengine/Ketsji/KX_NodeRelationships.h @@ -0,0 +1,107 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file KX_NodeRelationships.h + * \ingroup ketsji + * \section KX_NodeRelationships + * This file provides common concrete implementations of + * SG_ParentRelation used by the game engine. These are + * KX_SlowParentRelation a slow parent relationship. + * KX_NormalParentRelation a normal parent relationship where + * orientation and position are inherited from the parent by + * the child. + * KX_VertexParentRelation only location information is + * inherited by the child. + */ + +#ifndef __KX_NODERELATIONSHIPS_H__ +#define __KX_NODERELATIONSHIPS_H__ + +#include "SG_ParentRelation.h" + +class KX_NormalParentRelation : public SG_ParentRelation +{ +public: + KX_NormalParentRelation(); + virtual ~KX_NormalParentRelation(); + + /// Method inherited from KX_ParentRelation. + virtual bool UpdateChildCoordinates(SG_Node *child, const SG_Node *parent, bool& parentUpdated); + + /// Method inherited from KX_ParentRelation. + virtual SG_ParentRelation *NewCopy(); +}; + +class KX_VertexParentRelation : public SG_ParentRelation +{ +public: + KX_VertexParentRelation(); + virtual ~KX_VertexParentRelation(); + + /// Method inherited from KX_ParentRelation. + virtual bool UpdateChildCoordinates(SG_Node *child, const SG_Node *parent, bool& parentUpdated); + + /// Method inherited from KX_ParentRelation. + virtual SG_ParentRelation *NewCopy(); + + virtual bool IsVertexRelation(); +}; + +class KX_SlowParentRelation : public SG_ParentRelation +{ +private: + /// The relaxation coefficient. + float m_relax; + + /** + * Looks like a hack flag to me. + * We need to compute valid world coordinates the first + * time we update spatial data of the child. This is done + * by just doing a normal parent relation the first time + * UpdateChildCoordinates is called and then doing the + * slow parent relation + */ + bool m_initialized; + +public: + KX_SlowParentRelation(float relaxation); + virtual ~KX_SlowParentRelation(); + + /// Method inherited from KX_ParentRelation. + virtual bool UpdateChildCoordinates(SG_Node *child, const SG_Node *parent, bool& parentUpdated); + + /// Method inherited from KX_ParentRelation. + virtual SG_ParentRelation *NewCopy(); + + float GetTimeOffset(); + void SetTimeOffset(float relaxation); + + virtual bool IsSlowRelation(); +}; + +#endif // __KX_NODERELATIONSHIPS_H__ diff --git a/source/gameengine/Ketsji/KX_ObColorIpoSGController.cpp b/source/gameengine/Ketsji/KX_ObColorIpoSGController.cpp index 6777afd03c9f..3d2956762a41 100644 --- a/source/gameengine/Ketsji/KX_ObColorIpoSGController.cpp +++ b/source/gameengine/Ketsji/KX_ObColorIpoSGController.cpp @@ -31,80 +31,17 @@ #include "KX_ObColorIpoSGController.h" -#include "KX_ScalarInterpolator.h" #include "KX_GameObject.h" -#if defined(_WIN64) -typedef unsigned __int64 uint_ptr; -#else -typedef unsigned long uint_ptr; -#endif - - -bool KX_ObColorIpoSGController::Update(double currentTime) -{ - if (m_modified) - { - SG_Spatial* ob = (SG_Spatial*)m_pObject; - KX_GameObject* kxgameobj= (KX_GameObject*) ob->GetSGClientObject(); - - m_rgba = kxgameobj->GetObjectColor(); - - T_InterpolatorList::iterator i; - for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) { - (*i)->Execute(m_ipotime); - } - - - kxgameobj->SetObjectColor(m_rgba); - - - m_modified=false; - } - return false; -} - - -void KX_ObColorIpoSGController::AddInterpolator(KX_IInterpolator* interp) -{ - this->m_interpolators.push_back(interp); -} - -SG_Controller* KX_ObColorIpoSGController::GetReplica(class SG_Node* destnode) +bool KX_ObColorIpoSGController::Update(SG_Node *node) { - KX_ObColorIpoSGController* iporeplica = new KX_ObColorIpoSGController(*this); - // clear object that ipo acts on - iporeplica->ClearObject(); - - // dirty hack, ask Gino for a better solution in the ipo implementation - // hacken en zagen, in what we call datahiding, not written for replication :( - - T_InterpolatorList oldlist = m_interpolators; - iporeplica->m_interpolators.clear(); - - T_InterpolatorList::iterator i; - for (i = oldlist.begin(); !(i == oldlist.end()); ++i) { - KX_ScalarInterpolator* copyipo = new KX_ScalarInterpolator(*((KX_ScalarInterpolator*)*i)); - iporeplica->AddInterpolator(copyipo); - - MT_Scalar* scaal = ((KX_ScalarInterpolator*)*i)->GetTarget(); - uint_ptr orgbase = (uint_ptr)this; - uint_ptr orgloc = (uint_ptr)scaal; - uint_ptr offset = orgloc-orgbase; - uint_ptr newaddrbase = (uint_ptr)iporeplica + offset; - MT_Scalar* blaptr = (MT_Scalar*) newaddrbase; - copyipo->SetNewTarget((MT_Scalar*)blaptr); + if (!SG_Controller::Update(node)) { + return false; } - return iporeplica; -} - -KX_ObColorIpoSGController::~KX_ObColorIpoSGController() -{ + KX_GameObject *kxgameobj = static_cast(node->GetClientObject()); - T_InterpolatorList::iterator i; - for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) { - delete (*i); - } + kxgameobj->SetObjectColor(m_rgba); + return true; } diff --git a/source/gameengine/Ketsji/KX_ObColorIpoSGController.h b/source/gameengine/Ketsji/KX_ObColorIpoSGController.h index e482e66fad33..dcf96c716017 100644 --- a/source/gameengine/Ketsji/KX_ObColorIpoSGController.h +++ b/source/gameengine/Ketsji/KX_ObColorIpoSGController.h @@ -33,48 +33,19 @@ #define __KX_OBCOLORIPOSGCONTROLLER_H__ #include "SG_Controller.h" -#include "SG_Spatial.h" -#include "KX_IInterpolator.h" +#include "SG_Node.h" +#include "SG_Interpolator.h" +#include "mathfu.h" -class KX_ObColorIpoSGController : public SG_Controller +class KX_ObColorIpoSGController : public SG_Controller, public mt::SimdClassAllocator { public: - MT_Vector4 m_rgba; + mt::vec4 m_rgba; - -private: - T_InterpolatorList m_interpolators; - bool m_modified; - - double m_ipotime; public: - KX_ObColorIpoSGController() : - m_modified(true), - m_ipotime(0.0) - {} - virtual ~KX_ObColorIpoSGController(); - virtual SG_Controller* GetReplica(class SG_Node* destnode); - virtual bool Update(double time); - virtual void SetSimulatedTime(double time) { - m_ipotime = time; - m_modified = true; - } - - void - SetOption( - int option, - int value - ) { - // intentionally empty - }; - - - void AddInterpolator(KX_IInterpolator* interp); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_ObColorIpoSGController") -#endif + KX_ObColorIpoSGController() = default; + virtual ~KX_ObColorIpoSGController() = default; + virtual bool Update(SG_Node *node); }; #endif /* __KX_OBCOLORIPOSGCONTROLLER_H__ */ diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.cpp b/source/gameengine/Ketsji/KX_ObjectActuator.cpp index d957fe8f31ab..0f43ce6e9606 100644 --- a/source/gameengine/Ketsji/KX_ObjectActuator.cpp +++ b/source/gameengine/Ketsji/KX_ObjectActuator.cpp @@ -32,33 +32,26 @@ * \ingroup ketsji */ -#include - #include "KX_ObjectActuator.h" #include "KX_GameObject.h" -#include "KX_PyMath.h" // For PyVecTo - should this include be put in PyObjectPlus? +#include "KX_PyMath.h" // For PyVecTo. #include "PHY_IPhysicsController.h" #include "PHY_ICharacter.h" #include "PHY_IPhysicsEnvironment.h" -/* ------------------------------------------------------------------------- */ -/* Native functions */ -/* ------------------------------------------------------------------------- */ - -KX_ObjectActuator:: -KX_ObjectActuator( - SCA_IObject* gameobj, - KX_GameObject* refobj, - const MT_Vector3& force, - const MT_Vector3& torque, - const MT_Vector3& dloc, - const MT_Vector3& drot, - const MT_Vector3& linV, - const MT_Vector3& angV, - const short damping, - const KX_LocalFlags& flag -) : - SCA_IActuator(gameobj, KX_ACT_OBJECT), +#include "CM_Message.h" + +KX_ObjectActuator::KX_ObjectActuator(SCA_IObject *gameobj, + KX_GameObject *refobj, + const mt::vec3& force, + const mt::vec3& torque, + const mt::vec3& dloc, + const mt::vec3& drot, + const mt::vec3& linV, + const mt::vec3& angV, + const short damping, + const KX_LocalFlags& flag) + :SCA_IActuator(gameobj, KX_ACT_OBJECT), m_force(force), m_torque(torque), m_dloc(dloc), @@ -69,47 +62,56 @@ KX_ObjectActuator( m_current_linear_factor(0.0f), m_current_angular_factor(0.0f), m_damping(damping), - m_previous_error(0.0f,0.0f,0.0f), - m_error_accumulator(0.0f,0.0f,0.0f), - m_bitLocalFlag (flag), + m_previous_error(0.0f, 0.0f, 0.0f), + m_error_accumulator(0.0f, 0.0f, 0.0f), + m_bitLocalFlag(flag), m_reference(refobj), - m_active_combined_velocity (false), m_linear_damping_active(false), m_angular_damping_active(false), m_jumping(false) { - if (m_bitLocalFlag.ServoControl) - { + if (m_bitLocalFlag.ServoControl) { // in servo motion, the force is local if the target velocity is local m_bitLocalFlag.Force = m_bitLocalFlag.LinearVelocity; m_pid = m_torque; } - if (m_bitLocalFlag.CharacterMotion) - { + if (m_bitLocalFlag.CharacterMotion) { KX_GameObject *parent = static_cast(GetParent()); PHY_ICharacter *character = parent->GetScene()->GetPhysicsEnvironment()->GetCharacterController(parent); - if (!character) - { - printf("Character motion enabled on non-character object (%s), falling back to simple motion.\n", parent->GetName().Ptr()); + if (!character) { + CM_LogicBrickWarning(this, "character motion enabled on non-character object, falling back to simple motion."); m_bitLocalFlag.CharacterMotion = false; } } - if (m_reference) + if (m_reference) { m_reference->RegisterActuator(this); + } UpdateFuzzyFlags(); } KX_ObjectActuator::~KX_ObjectActuator() { - if (m_reference) + if (m_reference) { m_reference->UnregisterActuator(this); + } } -bool KX_ObjectActuator::Update() +void KX_ObjectActuator::UpdateFuzzyFlags() { + m_bitLocalFlag.ZeroForce = mt::FuzzyZero(m_force); + m_bitLocalFlag.ZeroTorque = mt::FuzzyZero(m_torque); + m_bitLocalFlag.ZeroDLoc = mt::FuzzyZero(m_dloc); + m_bitLocalFlag.ZeroDRot = mt::FuzzyZero(m_drot); + m_bitLocalFlag.ZeroLinearVelocity = mt::FuzzyZero(m_linear_velocity); + m_linear_length2 = (m_bitLocalFlag.ZeroLinearVelocity) ? 0.0f : m_linear_velocity.LengthSquared(); + m_bitLocalFlag.ZeroAngularVelocity = mt::FuzzyZero(m_angular_velocity); + m_angular_length2 = (m_bitLocalFlag.ZeroAngularVelocity) ? 0.0f : m_angular_velocity.LengthSquared(); +} +bool KX_ObjectActuator::Update() +{ bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); @@ -117,37 +119,20 @@ bool KX_ObjectActuator::Update() PHY_ICharacter *character = parent->GetScene()->GetPhysicsEnvironment()->GetCharacterController(parent); if (bNegativeEvent) { - // If we previously set the linear velocity we now have to inform - // the physics controller that we no longer wish to apply it and that - // it should reconcile the externally set velocity with it's - // own velocity. - if (m_active_combined_velocity) { - if (parent) - parent->ResolveCombinedVelocities( - m_linear_velocity, - m_angular_velocity, - (m_bitLocalFlag.LinearVelocity) != 0, - (m_bitLocalFlag.AngularVelocity) != 0 - ); - m_active_combined_velocity = false; - } - // Explicitly stop the movement if we're using character motion if (m_bitLocalFlag.CharacterMotion) { - character->SetWalkDirection(MT_Vector3 (0.0f, 0.0f, 0.0f)); + character->SetWalkDirection(mt::zero3); } m_linear_damping_active = false; m_angular_damping_active = false; - m_error_accumulator.setValue(0.0f,0.0f,0.0f); - m_previous_error.setValue(0.0f,0.0f,0.0f); + m_error_accumulator = mt::zero3; + m_previous_error = mt::zero3; m_jumping = false; return false; - - } else if (parent) - { - if (m_bitLocalFlag.ServoControl) - { + } + else if (parent) { + if (m_bitLocalFlag.ServoControl) { // In this mode, we try to reach a target speed using force // As we don't know the friction, we must implement a generic // servo control to achieve the speed in a configurable @@ -159,95 +144,113 @@ bool KX_ObjectActuator::Update() // dv = e(t) - e(t-1) // KP, KD, KI : coefficient // F = KP*e+KI*I+KD*dv - MT_Scalar mass = parent->GetMass(); - if (mass < MT_EPSILON) + float mass = parent->GetMass(); + if (mt::FuzzyZero(mass)) { return false; - MT_Vector3 v = parent->GetLinearVelocity(m_bitLocalFlag.LinearVelocity); - if (m_reference) - { - const MT_Point3& mypos = parent->NodeGetWorldPosition(); - const MT_Point3& refpos = m_reference->NodeGetWorldPosition(); - MT_Point3 relpos; - relpos = (mypos-refpos); - MT_Vector3 vel= m_reference->GetVelocity(relpos); - if (m_bitLocalFlag.LinearVelocity) - // must convert in local space - vel = parent->NodeGetWorldOrientation().transposed()*vel; - v -= vel; } - MT_Vector3 e = m_linear_velocity - v; - MT_Vector3 dv = e - m_previous_error; - MT_Vector3 I = m_error_accumulator + e; - - m_force = m_pid.x()*e+m_pid.y()*I+m_pid.z()*dv; - // to automatically adapt the PID coefficient to mass; - m_force *= mass; - if (m_bitLocalFlag.Torque) - { - if (m_force[0] > m_dloc[0]) - { - m_force[0] = m_dloc[0]; - I[0] = m_error_accumulator[0]; - } else if (m_force[0] < m_drot[0]) - { - m_force[0] = m_drot[0]; - I[0] = m_error_accumulator[0]; - } + + mt::vec3 v; + if (m_bitLocalFlag.ServoControlAngular) { + v = parent->GetAngularVelocity(m_bitLocalFlag.AngularVelocity); } - if (m_bitLocalFlag.DLoc) - { - if (m_force[1] > m_dloc[1]) - { - m_force[1] = m_dloc[1]; - I[1] = m_error_accumulator[1]; - } else if (m_force[1] < m_drot[1]) - { - m_force[1] = m_drot[1]; - I[1] = m_error_accumulator[1]; + else { + v = parent->GetLinearVelocity(m_bitLocalFlag.LinearVelocity); + } + + if (m_reference) { + if (m_bitLocalFlag.ServoControlAngular) { + const mt::vec3 vel = m_reference->GetAngularVelocity(m_bitLocalFlag.AngularVelocity); + v -= vel; + } + else { + const mt::vec3& mypos = parent->NodeGetWorldPosition(); + const mt::vec3& refpos = m_reference->NodeGetWorldPosition(); + const mt::vec3 relpos = (mypos - refpos); + mt::vec3 vel = m_reference->GetVelocity(relpos); + if (m_bitLocalFlag.LinearVelocity) { + // must convert in local space + vel = parent->NodeGetWorldOrientation().Transpose() * vel; + } + v -= vel; } } - if (m_bitLocalFlag.DRot) - { - if (m_force[2] > m_dloc[2]) - { - m_force[2] = m_dloc[2]; - I[2] = m_error_accumulator[2]; - } else if (m_force[2] < m_drot[2]) - { - m_force[2] = m_drot[2]; - I[2] = m_error_accumulator[2]; + + mt::vec3 e; + if (m_bitLocalFlag.ServoControlAngular) { + e = m_angular_velocity - v; + } + else { + e = m_linear_velocity - v; + } + + mt::vec3 dv = e - m_previous_error; + mt::vec3 I = m_error_accumulator + e; + + mt::vec3& f = (m_bitLocalFlag.ServoControlAngular) ? m_torque : m_force; + f = m_pid.x * e + m_pid.y * I + m_pid.z * dv; + + /* Make sure velocity is correct depending on how body react to force/torque. + * See btRigidBody::integrateVelocities */ + if (m_bitLocalFlag.ServoControlAngular) { + f *= parent->GetLocalInertia(); + } + else { + f *= mass; + } + + const bool limits[3] = {m_bitLocalFlag.Torque, m_bitLocalFlag.DLoc, m_bitLocalFlag.DRot}; + + for (unsigned short i = 0; i < 3; ++i) { + if (!limits[i]) { + continue; + } + + if (f[i] > m_dloc[i]) { + f[i] = m_dloc[i]; + I[i] = m_error_accumulator[i]; + } + else if (f[i] < m_drot[i]) { + f[i] = m_drot[i]; + I[i] = m_error_accumulator[i]; } } + m_previous_error = e; m_error_accumulator = I; - parent->ApplyForce(m_force,(m_bitLocalFlag.LinearVelocity) != 0); + + if (m_bitLocalFlag.ServoControlAngular) { + parent->ApplyTorque(f, m_bitLocalFlag.AngularVelocity); + } + else { + parent->ApplyForce(f, m_bitLocalFlag.LinearVelocity); + } } else if (m_bitLocalFlag.CharacterMotion) { - MT_Vector3 dir = m_dloc; + mt::vec3 dir = m_dloc; if (m_bitLocalFlag.DLoc) { - MT_Matrix3x3 basis = parent->GetPhysicsController()->GetOrientation(); + mt::mat3 basis = parent->GetPhysicsController()->GetOrientation(); dir = basis * dir; } if (m_bitLocalFlag.AddOrSetCharLoc) { - MT_Vector3 old_dir = character->GetWalkDirection(); + mt::vec3 old_dir = character->GetWalkDirection(); - if (!old_dir.fuzzyZero()) { - MT_Scalar mag = old_dir.length(); + if (!mt::FuzzyZero(old_dir)) { + float mag = old_dir.Length(); dir = dir + old_dir; - if (!dir.fuzzyZero()) - dir = dir.normalized() * mag; + if (!mt::FuzzyZero(dir)) { + dir = dir.Normalized() * mag; + } } } // We always want to set the walk direction since a walk direction of (0, 0, 0) should stop the character - character->SetWalkDirection(dir/parent->GetScene()->GetPhysicsEnvironment()->GetNumTimeSubSteps()); + character->SetWalkDirection(dir / parent->GetScene()->GetPhysicsEnvironment()->GetNumTimeSubSteps()); - if (!m_bitLocalFlag.ZeroDRot) - { - parent->ApplyRotation(m_drot,(m_bitLocalFlag.DRot) != 0); + if (!m_bitLocalFlag.ZeroDRot) { + parent->ApplyRotation(m_drot, (m_bitLocalFlag.DRot) != 0); } if (m_bitLocalFlag.CharacterJump) { @@ -255,73 +258,73 @@ bool KX_ObjectActuator::Update() character->Jump(); m_jumping = true; } - else if (character->OnGround()) + else if (character->OnGround()) { m_jumping = false; + } } } else { - if (!m_bitLocalFlag.ZeroForce) - { - parent->ApplyForce(m_force,(m_bitLocalFlag.Force) != 0); + if (!m_bitLocalFlag.ZeroForce) { + parent->ApplyForce(m_force, (m_bitLocalFlag.Force) != 0); } - if (!m_bitLocalFlag.ZeroTorque) - { - parent->ApplyTorque(m_torque,(m_bitLocalFlag.Torque) != 0); + if (!m_bitLocalFlag.ZeroTorque) { + parent->ApplyTorque(m_torque, (m_bitLocalFlag.Torque) != 0); } - if (!m_bitLocalFlag.ZeroDLoc) - { - parent->ApplyMovement(m_dloc,(m_bitLocalFlag.DLoc) != 0); + if (!m_bitLocalFlag.ZeroDLoc) { + parent->ApplyMovement(m_dloc, (m_bitLocalFlag.DLoc) != 0); } - if (!m_bitLocalFlag.ZeroDRot) - { - parent->ApplyRotation(m_drot,(m_bitLocalFlag.DRot) != 0); + if (!m_bitLocalFlag.ZeroDRot) { + parent->ApplyRotation(m_drot, (m_bitLocalFlag.DRot) != 0); } - if (!m_bitLocalFlag.ZeroLinearVelocity) - { + if (!m_bitLocalFlag.ZeroLinearVelocity) { if (m_bitLocalFlag.AddOrSetLinV) { - parent->addLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0); - } else { - m_active_combined_velocity = true; + parent->AddLinearVelocity(m_linear_velocity, (m_bitLocalFlag.LinearVelocity) != 0); + } + else { if (m_damping > 0) { - MT_Vector3 linV; + mt::vec3 linV; if (!m_linear_damping_active) { // delta and the start speed (depends on the existing speed in that direction) linV = parent->GetLinearVelocity(m_bitLocalFlag.LinearVelocity); // keep only the projection along the desired direction - m_current_linear_factor = linV.dot(m_linear_velocity)/m_linear_length2; + m_current_linear_factor = mt::dot(linV, m_linear_velocity) / m_linear_length2; m_linear_damping_active = true; } - if (m_current_linear_factor < 1.0f) - m_current_linear_factor += 1.0f/m_damping; - if (m_current_linear_factor > 1.0f) + if (m_current_linear_factor < 1.0f) { + m_current_linear_factor += 1.0f / m_damping; + } + if (m_current_linear_factor > 1.0f) { m_current_linear_factor = 1.0f; + } linV = m_current_linear_factor * m_linear_velocity; - parent->setLinearVelocity(linV,(m_bitLocalFlag.LinearVelocity) != 0); - } else { - parent->setLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0); + parent->SetLinearVelocity(linV, (m_bitLocalFlag.LinearVelocity) != 0); + } + else { + parent->SetLinearVelocity(m_linear_velocity, (m_bitLocalFlag.LinearVelocity) != 0); } } } - if (!m_bitLocalFlag.ZeroAngularVelocity) - { - m_active_combined_velocity = true; + if (!m_bitLocalFlag.ZeroAngularVelocity) { if (m_damping > 0) { - MT_Vector3 angV; + mt::vec3 angV; if (!m_angular_damping_active) { // delta and the start speed (depends on the existing speed in that direction) angV = parent->GetAngularVelocity(m_bitLocalFlag.AngularVelocity); // keep only the projection along the desired direction - m_current_angular_factor = angV.dot(m_angular_velocity)/m_angular_length2; + m_current_angular_factor = mt::dot(angV, m_angular_velocity) / m_angular_length2; m_angular_damping_active = true; } - if (m_current_angular_factor < 1.0f) - m_current_angular_factor += 1.0f/m_damping; - if (m_current_angular_factor > 1.0f) - m_current_angular_factor = 1.0f; + if (m_current_angular_factor < 1.0) { + m_current_angular_factor += 1.0 / m_damping; + } + if (m_current_angular_factor > 1.0) { + m_current_angular_factor = 1.0; + } angV = m_current_angular_factor * m_angular_velocity; - parent->setAngularVelocity(angV,(m_bitLocalFlag.AngularVelocity) != 0); - } else { - parent->setAngularVelocity(m_angular_velocity,(m_bitLocalFlag.AngularVelocity) != 0); + parent->SetAngularVelocity(angV, (m_bitLocalFlag.AngularVelocity) != 0); + } + else { + parent->SetAngularVelocity(m_angular_velocity, (m_bitLocalFlag.AngularVelocity) != 0); } } } @@ -330,11 +333,9 @@ bool KX_ObjectActuator::Update() return true; } - - -CValue* KX_ObjectActuator::GetReplica() +EXP_Value *KX_ObjectActuator::GetReplica() { - KX_ObjectActuator* replica = new KX_ObjectActuator(*this);//m_float,GetName()); + KX_ObjectActuator *replica = new KX_ObjectActuator(*this); replica->ProcessReplica(); return replica; @@ -343,40 +344,33 @@ CValue* KX_ObjectActuator::GetReplica() void KX_ObjectActuator::ProcessReplica() { SCA_IActuator::ProcessReplica(); - if (m_reference) + if (m_reference) { m_reference->RegisterActuator(this); + } } -bool KX_ObjectActuator::UnlinkObject(SCA_IObject* clientobj) +bool KX_ObjectActuator::UnlinkObject(SCA_IObject *clientobj) { - if (clientobj == (SCA_IObject*)m_reference) - { + if (clientobj == m_reference) { // this object is being deleted, we cannot continue to use it as reference. - m_reference = NULL; + m_reference = nullptr; return true; } return false; } -void KX_ObjectActuator::Relink(CTR_Map *obj_map) +void KX_ObjectActuator::Relink(std::map& obj_map) { - void **h_obj = (*obj_map)[m_reference]; - if (h_obj) { - if (m_reference) + KX_GameObject *obj = static_cast(obj_map[m_reference]); + if (obj) { + if (m_reference) { m_reference->UnregisterActuator(this); - m_reference = (KX_GameObject*)(*h_obj); + } + m_reference = obj; m_reference->RegisterActuator(this); } } -/* some 'standard' utilities... */ -bool KX_ObjectActuator::isValid(KX_ObjectActuator::KX_OBJECT_ACT_VEC_TYPE type) -{ - bool res = false; - res = (type > KX_OBJECT_ACT_NODEF) && (type < KX_OBJECT_ACT_MAX); - return res; -} - #ifdef WITH_PYTHON /* ------------------------------------------------------------------------- */ @@ -385,9 +379,9 @@ bool KX_ObjectActuator::isValid(KX_ObjectActuator::KX_OBJECT_ACT_VEC_TYPE type) /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_ObjectActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_ObjectActuator", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -395,46 +389,46 @@ PyTypeObject KX_ObjectActuator::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IActuator::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_ObjectActuator::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_ObjectActuator::Attributes[] = { - KX_PYATTRIBUTE_VECTOR_RW_CHECK("force", -1000, 1000, false, KX_ObjectActuator, m_force, PyUpdateFuzzyFlags), - KX_PYATTRIBUTE_BOOL_RW("useLocalForce", KX_ObjectActuator, m_bitLocalFlag.Force), - KX_PYATTRIBUTE_VECTOR_RW_CHECK("torque", -1000, 1000, false, KX_ObjectActuator, m_torque, PyUpdateFuzzyFlags), - KX_PYATTRIBUTE_BOOL_RW("useLocalTorque", KX_ObjectActuator, m_bitLocalFlag.Torque), - KX_PYATTRIBUTE_VECTOR_RW_CHECK("dLoc", -1000, 1000, false, KX_ObjectActuator, m_dloc, PyUpdateFuzzyFlags), - KX_PYATTRIBUTE_BOOL_RW("useLocalDLoc", KX_ObjectActuator, m_bitLocalFlag.DLoc), - KX_PYATTRIBUTE_VECTOR_RW_CHECK("dRot", -1000, 1000, false, KX_ObjectActuator, m_drot, PyUpdateFuzzyFlags), - KX_PYATTRIBUTE_BOOL_RW("useLocalDRot", KX_ObjectActuator, m_bitLocalFlag.DRot), + EXP_PYATTRIBUTE_VECTOR_RW_CHECK("force", -1000, 1000, false, KX_ObjectActuator, m_force, 3, PyUpdateFuzzyFlags), + EXP_PYATTRIBUTE_BOOL_RW("useLocalForce", KX_ObjectActuator, m_bitLocalFlag.Force), + EXP_PYATTRIBUTE_VECTOR_RW_CHECK("torque", -1000, 1000, false, KX_ObjectActuator, m_torque, 3, PyUpdateFuzzyFlags), + EXP_PYATTRIBUTE_BOOL_RW("useLocalTorque", KX_ObjectActuator, m_bitLocalFlag.Torque), + EXP_PYATTRIBUTE_VECTOR_RW_CHECK("dLoc", -1000, 1000, false, KX_ObjectActuator, m_dloc, 3, PyUpdateFuzzyFlags), + EXP_PYATTRIBUTE_BOOL_RW("useLocalDLoc", KX_ObjectActuator, m_bitLocalFlag.DLoc), + EXP_PYATTRIBUTE_VECTOR_RW_CHECK("dRot", -1000, 1000, false, KX_ObjectActuator, m_drot, 3, PyUpdateFuzzyFlags), + EXP_PYATTRIBUTE_BOOL_RW("useLocalDRot", KX_ObjectActuator, m_bitLocalFlag.DRot), #ifdef USE_MATHUTILS - KX_PYATTRIBUTE_RW_FUNCTION("linV", KX_ObjectActuator, pyattr_get_linV, pyattr_set_linV), - KX_PYATTRIBUTE_RW_FUNCTION("angV", KX_ObjectActuator, pyattr_get_angV, pyattr_set_angV), + EXP_PYATTRIBUTE_RW_FUNCTION("linV", KX_ObjectActuator, pyattr_get_linV, pyattr_set_linV), + EXP_PYATTRIBUTE_RW_FUNCTION("angV", KX_ObjectActuator, pyattr_get_angV, pyattr_set_angV), #else - KX_PYATTRIBUTE_VECTOR_RW_CHECK("linV", -1000, 1000, false, KX_ObjectActuator, m_linear_velocity, PyUpdateFuzzyFlags), - KX_PYATTRIBUTE_VECTOR_RW_CHECK("angV", -1000, 1000, false, KX_ObjectActuator, m_angular_velocity, PyUpdateFuzzyFlags), + EXP_PYATTRIBUTE_VECTOR_RW_CHECK("linV", -1000, 1000, false, KX_ObjectActuator, m_linear_velocity, 3, PyUpdateFuzzyFlags), + EXP_PYATTRIBUTE_VECTOR_RW_CHECK("angV", -1000, 1000, false, KX_ObjectActuator, m_angular_velocity, 3, PyUpdateFuzzyFlags), #endif - KX_PYATTRIBUTE_BOOL_RW("useLocalLinV", KX_ObjectActuator, m_bitLocalFlag.LinearVelocity), - KX_PYATTRIBUTE_BOOL_RW("useLocalAngV", KX_ObjectActuator, m_bitLocalFlag.AngularVelocity), - KX_PYATTRIBUTE_SHORT_RW("damping", 0, 1000, false, KX_ObjectActuator, m_damping), - KX_PYATTRIBUTE_RW_FUNCTION("forceLimitX", KX_ObjectActuator, pyattr_get_forceLimitX, pyattr_set_forceLimitX), - KX_PYATTRIBUTE_RW_FUNCTION("forceLimitY", KX_ObjectActuator, pyattr_get_forceLimitY, pyattr_set_forceLimitY), - KX_PYATTRIBUTE_RW_FUNCTION("forceLimitZ", KX_ObjectActuator, pyattr_get_forceLimitZ, pyattr_set_forceLimitZ), - KX_PYATTRIBUTE_VECTOR_RW_CHECK("pid", -100, 200, true, KX_ObjectActuator, m_pid, PyCheckPid), - KX_PYATTRIBUTE_RW_FUNCTION("reference", KX_ObjectActuator,pyattr_get_reference,pyattr_set_reference), - { NULL } //Sentinel + EXP_PYATTRIBUTE_BOOL_RW("useLocalLinV", KX_ObjectActuator, m_bitLocalFlag.LinearVelocity), + EXP_PYATTRIBUTE_BOOL_RW("useLocalAngV", KX_ObjectActuator, m_bitLocalFlag.AngularVelocity), + EXP_PYATTRIBUTE_SHORT_RW("damping", 0, 1000, false, KX_ObjectActuator, m_damping), + EXP_PYATTRIBUTE_RW_FUNCTION("forceLimitX", KX_ObjectActuator, pyattr_get_forceLimitX, pyattr_set_forceLimitX), + EXP_PYATTRIBUTE_RW_FUNCTION("forceLimitY", KX_ObjectActuator, pyattr_get_forceLimitY, pyattr_set_forceLimitY), + EXP_PYATTRIBUTE_RW_FUNCTION("forceLimitZ", KX_ObjectActuator, pyattr_get_forceLimitZ, pyattr_set_forceLimitZ), + EXP_PYATTRIBUTE_VECTOR_RW_CHECK("pid", -100, 200, true, KX_ObjectActuator, m_pid, 3, PyCheckPid), + EXP_PYATTRIBUTE_RW_FUNCTION("reference", KX_ObjectActuator, pyattr_get_reference, pyattr_set_reference), + EXP_PYATTRIBUTE_NULL //Sentinel }; /* Attribute get/set functions */ @@ -449,26 +443,32 @@ static unsigned char mathutils_kxobactu_vector_cb_index = -1; /* index for our c static int mathutils_obactu_generic_check(BaseMathObject *bmo) { - KX_ObjectActuator* self = static_castBGE_PROXY_REF(bmo->cb_user); - if (self == NULL) + KX_ObjectActuator *self = static_castEXP_PROXY_REF(bmo->cb_user); + if (self == nullptr) { return -1; + } return 0; } static int mathutils_obactu_vector_get(BaseMathObject *bmo, int subtype) { - KX_ObjectActuator* self = static_castBGE_PROXY_REF(bmo->cb_user); - if (self == NULL) + KX_ObjectActuator *self = static_castEXP_PROXY_REF(bmo->cb_user); + if (self == nullptr) { return -1; + } switch (subtype) { case MATHUTILS_VEC_CB_LINV: - self->m_linear_velocity.getValue(bmo->data); + { + self->m_linear_velocity.Pack(bmo->data); break; + } case MATHUTILS_VEC_CB_ANGV: - self->m_angular_velocity.getValue(bmo->data); + { + self->m_angular_velocity.Pack(bmo->data); break; + } } return 0; @@ -476,17 +476,22 @@ static int mathutils_obactu_vector_get(BaseMathObject *bmo, int subtype) static int mathutils_obactu_vector_set(BaseMathObject *bmo, int subtype) { - KX_ObjectActuator* self = static_castBGE_PROXY_REF(bmo->cb_user); - if (self == NULL) + KX_ObjectActuator *self = static_castEXP_PROXY_REF(bmo->cb_user); + if (self == nullptr) { return -1; + } switch (subtype) { case MATHUTILS_VEC_CB_LINV: - self->m_linear_velocity.setValue(bmo->data); + { + self->m_linear_velocity = mt::vec3(bmo->data); break; + } case MATHUTILS_VEC_CB_ANGV: - self->m_angular_velocity.setValue(bmo->data); + { + self->m_angular_velocity = mt::vec3(bmo->data); break; + } } return 0; @@ -495,8 +500,9 @@ static int mathutils_obactu_vector_set(BaseMathObject *bmo, int subtype) static int mathutils_obactu_vector_get_index(BaseMathObject *bmo, int subtype, int index) { /* lazy, avoid repeteing the case statement */ - if (mathutils_obactu_vector_get(bmo, subtype) == -1) + if (mathutils_obactu_vector_get(bmo, subtype) == -1) { return -1; + } return 0; } @@ -505,8 +511,9 @@ static int mathutils_obactu_vector_set_index(BaseMathObject *bmo, int subtype, i float f = bmo->data[index]; /* lazy, avoid repeteing the case statement */ - if (mathutils_obactu_vector_get(bmo, subtype) == -1) + if (mathutils_obactu_vector_get(bmo, subtype) == -1) { return -1; + } bmo->data[index] = f; return mathutils_obactu_vector_set(bmo, subtype); @@ -520,43 +527,44 @@ static Mathutils_Callback mathutils_obactu_vector_cb = { mathutils_obactu_vector_set_index }; -PyObject *KX_ObjectActuator::pyattr_get_linV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_ObjectActuator::pyattr_get_linV(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { return Vector_CreatePyObject_cb( - BGE_PROXY_FROM_REF_BORROW(self_v), 3, - mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_LINV); + EXP_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_LINV); } -int KX_ObjectActuator::pyattr_set_linV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_ObjectActuator::pyattr_set_linV(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_ObjectActuator* self = static_cast(self_v); - if (!PyVecTo(value, self->m_linear_velocity)) + KX_ObjectActuator *self = static_cast(self_v); + if (!PyVecTo(value, self->m_linear_velocity)) { return PY_SET_ATTR_FAIL; + } self->UpdateFuzzyFlags(); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_ObjectActuator::pyattr_get_angV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_ObjectActuator::pyattr_get_angV(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { return Vector_CreatePyObject_cb( - BGE_PROXY_FROM_REF_BORROW(self_v), 3, - mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_ANGV); + EXP_PROXY_FROM_REF_BORROW(self_v), 3, + mathutils_kxobactu_vector_cb_index, MATHUTILS_VEC_CB_ANGV); } -int KX_ObjectActuator::pyattr_set_angV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_ObjectActuator::pyattr_set_angV(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_ObjectActuator* self = static_cast(self_v); - if (!PyVecTo(value, self->m_angular_velocity)) + KX_ObjectActuator *self = static_cast(self_v); + if (!PyVecTo(value, self->m_angular_velocity)) { return PY_SET_ATTR_FAIL; + } self->UpdateFuzzyFlags(); return PY_SET_ATTR_SUCCESS; } - void KX_ObjectActuator_Mathutils_Callback_Init(void) { // register mathutils callbacks, ok to run more than once. @@ -565,9 +573,9 @@ void KX_ObjectActuator_Mathutils_Callback_Init(void) #endif // USE_MATHUTILS -PyObject *KX_ObjectActuator::pyattr_get_forceLimitX(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_ObjectActuator::pyattr_get_forceLimitX(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_ObjectActuator* self = reinterpret_cast(self_v); + KX_ObjectActuator *self = reinterpret_cast(self_v); PyObject *retVal = PyList_New(3); PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(self->m_drot[0])); @@ -577,19 +585,17 @@ PyObject *KX_ObjectActuator::pyattr_get_forceLimitX(void *self_v, const KX_PYATT return retVal; } -int KX_ObjectActuator::pyattr_set_forceLimitX(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_ObjectActuator::pyattr_set_forceLimitX(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_ObjectActuator* self = reinterpret_cast(self_v); + KX_ObjectActuator *self = reinterpret_cast(self_v); PyObject *seq = PySequence_Fast(value, ""); - if (seq && PySequence_Fast_GET_SIZE(seq) == 3) - { + if (seq && PySequence_Fast_GET_SIZE(seq) == 3) { self->m_drot[0] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 0)); self->m_dloc[0] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 1)); self->m_bitLocalFlag.Torque = (PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 2)) != 0); - if (!PyErr_Occurred()) - { + if (!PyErr_Occurred()) { Py_DECREF(seq); return PY_SET_ATTR_SUCCESS; } @@ -601,9 +607,9 @@ int KX_ObjectActuator::pyattr_set_forceLimitX(void *self_v, const KX_PYATTRIBUTE return PY_SET_ATTR_FAIL; } -PyObject *KX_ObjectActuator::pyattr_get_forceLimitY(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_ObjectActuator::pyattr_get_forceLimitY(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_ObjectActuator* self = reinterpret_cast(self_v); + KX_ObjectActuator *self = reinterpret_cast(self_v); PyObject *retVal = PyList_New(3); PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(self->m_drot[1])); @@ -613,19 +619,17 @@ PyObject *KX_ObjectActuator::pyattr_get_forceLimitY(void *self_v, const KX_PYATT return retVal; } -int KX_ObjectActuator::pyattr_set_forceLimitY(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_ObjectActuator::pyattr_set_forceLimitY(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_ObjectActuator* self = reinterpret_cast(self_v); + KX_ObjectActuator *self = reinterpret_cast(self_v); PyObject *seq = PySequence_Fast(value, ""); - if (seq && PySequence_Fast_GET_SIZE(seq) == 3) - { + if (seq && PySequence_Fast_GET_SIZE(seq) == 3) { self->m_drot[1] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 0)); self->m_dloc[1] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 1)); self->m_bitLocalFlag.DLoc = (PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 2)) != 0); - if (!PyErr_Occurred()) - { + if (!PyErr_Occurred()) { Py_DECREF(seq); return PY_SET_ATTR_SUCCESS; } @@ -637,9 +641,9 @@ int KX_ObjectActuator::pyattr_set_forceLimitY(void *self_v, const KX_PYATTRIBUTE return PY_SET_ATTR_FAIL; } -PyObject *KX_ObjectActuator::pyattr_get_forceLimitZ(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_ObjectActuator::pyattr_get_forceLimitZ(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_ObjectActuator* self = reinterpret_cast(self_v); + KX_ObjectActuator *self = reinterpret_cast(self_v); PyObject *retVal = PyList_New(3); PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(self->m_drot[2])); @@ -649,19 +653,17 @@ PyObject *KX_ObjectActuator::pyattr_get_forceLimitZ(void *self_v, const KX_PYATT return retVal; } -int KX_ObjectActuator::pyattr_set_forceLimitZ(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_ObjectActuator::pyattr_set_forceLimitZ(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_ObjectActuator* self = reinterpret_cast(self_v); + KX_ObjectActuator *self = reinterpret_cast(self_v); PyObject *seq = PySequence_Fast(value, ""); - if (seq && PySequence_Fast_GET_SIZE(seq) == 3) - { + if (seq && PySequence_Fast_GET_SIZE(seq) == 3) { self->m_drot[2] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 0)); self->m_dloc[2] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value, 1)); self->m_bitLocalFlag.DRot = (PyLong_AsLong(PySequence_Fast_GET_ITEM(value, 2)) != 0); - if (!PyErr_Occurred()) - { + if (!PyErr_Occurred()) { Py_DECREF(seq); return PY_SET_ATTR_SUCCESS; } @@ -673,28 +675,31 @@ int KX_ObjectActuator::pyattr_set_forceLimitZ(void *self_v, const KX_PYATTRIBUTE return PY_SET_ATTR_FAIL; } -PyObject *KX_ObjectActuator::pyattr_get_reference(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_ObjectActuator::pyattr_get_reference(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - KX_ObjectActuator* actuator = static_cast(self); - if (!actuator->m_reference) + KX_ObjectActuator *actuator = static_cast(self); + if (!actuator->m_reference) { Py_RETURN_NONE; + } return actuator->m_reference->GetProxy(); } -int KX_ObjectActuator::pyattr_set_reference(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_ObjectActuator::pyattr_set_reference(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_ObjectActuator* actuator = static_cast(self); + KX_ObjectActuator *actuator = static_cast(self); KX_GameObject *refOb; - if (!ConvertPythonToGameObject(actuator->GetLogicManager(), value, &refOb, true, "actu.reference = value: KX_ObjectActuator")) + if (!ConvertPythonToGameObject(actuator->GetLogicManager(), value, &refOb, true, "actu.reference = value: KX_ObjectActuator")) { return PY_SET_ATTR_FAIL; + } - if (actuator->m_reference) + if (actuator->m_reference) { actuator->m_reference->UnregisterActuator(actuator); + } - if (refOb==NULL) { - actuator->m_reference= NULL; + if (refOb == nullptr) { + actuator->m_reference = nullptr; } else { actuator->m_reference = refOb; @@ -704,6 +709,44 @@ int KX_ObjectActuator::pyattr_set_reference(void *self, const struct KX_PYATTRIB return PY_SET_ATTR_SUCCESS; } -#endif // WITH_PYTHON +// This lets the attribute macros use UpdateFuzzyFlags() +int KX_ObjectActuator::PyUpdateFuzzyFlags(EXP_PyObjectPlus *self, const PyAttributeDef *attrdef) +{ + KX_ObjectActuator *act = reinterpret_cast(self); + act->UpdateFuzzyFlags(); + return 0; +} + +// This is the keep the PID values in check after they are assigned with Python +int KX_ObjectActuator::PyCheckPid(EXP_PyObjectPlus *self, const PyAttributeDef *attrdef) +{ + KX_ObjectActuator *act = reinterpret_cast(self); + + // P 0 to 200 + if (act->m_pid[0] < 0) { + act->m_pid[0] = 0; + } + else if (act->m_pid[0] > 200) { + act->m_pid[0] = 200; + } + + // I 0 to 3 + if (act->m_pid[1] < 0) { + act->m_pid[1] = 0; + } + else if (act->m_pid[1] > 3) { + act->m_pid[1] = 3; + } + + // D -100 to 100 + if (act->m_pid[2] < -100) { + act->m_pid[2] = -100; + } + else if (act->m_pid[2] > 100) { + act->m_pid[2] = 100; + } + + return 0; +} -/* eof */ +#endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.h b/source/gameengine/Ketsji/KX_ObjectActuator.h index 7b34c0cbec23..f5ed71baf306 100644 --- a/source/gameengine/Ketsji/KX_ObjectActuator.h +++ b/source/gameengine/Ketsji/KX_ObjectActuator.h @@ -34,7 +34,7 @@ #define __KX_OBJECTACTUATOR_H__ #include "SCA_IActuator.h" -#include "MT_Vector3.h" +#include "mathfu.h" #ifdef USE_MATHUTILS void KX_ObjectActuator_Mathutils_Callback_Init(void); @@ -42,12 +42,9 @@ void KX_ObjectActuator_Mathutils_Callback_Init(void); class KX_GameObject; -// -// Stores the flags for each CValue derived class -// struct KX_LocalFlags { - KX_LocalFlags() : - Force(false), + KX_LocalFlags() + :Force(false), Torque(false), DRot(false), DLoc(false), @@ -84,151 +81,83 @@ struct KX_LocalFlags { bool ZeroDLoc; bool ZeroLinearVelocity; bool ZeroAngularVelocity; + bool ServoControlAngular; }; -class KX_ObjectActuator : public SCA_IActuator +class KX_ObjectActuator : public SCA_IActuator, public mt::SimdClassAllocator { Py_Header - MT_Vector3 m_force; - MT_Vector3 m_torque; - MT_Vector3 m_dloc; - MT_Vector3 m_drot; - MT_Vector3 m_linear_velocity; - MT_Vector3 m_angular_velocity; - MT_Vector3 m_pid; - MT_Scalar m_linear_length2; - MT_Scalar m_angular_length2; + mt::vec3 m_force; + mt::vec3 m_torque; + mt::vec3 m_dloc; + mt::vec3 m_drot; + mt::vec3 m_linear_velocity; + mt::vec3 m_angular_velocity; + mt::vec3 m_pid; + float m_linear_length2; + float m_angular_length2; // used in damping - MT_Scalar m_current_linear_factor; - MT_Scalar m_current_angular_factor; - short m_damping; + float m_current_linear_factor; + float m_current_angular_factor; + short m_damping; // used in servo control - MT_Vector3 m_previous_error; - MT_Vector3 m_error_accumulator; - KX_LocalFlags m_bitLocalFlag; - KX_GameObject* m_reference; - // A hack bool -- oh no sorry everyone - // This bool is used to check if we have informed - // the physics object that we are no longer - // setting linear velocity. - - bool m_active_combined_velocity; + mt::vec3 m_previous_error; + mt::vec3 m_error_accumulator; + KX_LocalFlags m_bitLocalFlag; + KX_GameObject *m_reference; + bool m_linear_damping_active; bool m_angular_damping_active; bool m_jumping; public: - enum KX_OBJECT_ACT_VEC_TYPE { - KX_OBJECT_ACT_NODEF = 0, - KX_OBJECT_ACT_FORCE, - KX_OBJECT_ACT_TORQUE, - KX_OBJECT_ACT_DLOC, - KX_OBJECT_ACT_DROT, - KX_OBJECT_ACT_LINEAR_VELOCITY, - KX_OBJECT_ACT_ANGULAR_VELOCITY, - KX_OBJECT_ACT_MAX - }; - - /** - * Check whether this is a valid vector mode - */ - bool isValid(KX_OBJECT_ACT_VEC_TYPE type); - - KX_ObjectActuator( - SCA_IObject* gameobj, - KX_GameObject* refobj, - const MT_Vector3& force, - const MT_Vector3& torque, - const MT_Vector3& dloc, - const MT_Vector3& drot, - const MT_Vector3& linV, - const MT_Vector3& angV, - const short damping, - const KX_LocalFlags& flag - ); - ~KX_ObjectActuator(); - CValue* GetReplica(); - void ProcessReplica(); - bool UnlinkObject(SCA_IObject* clientobj); - void Relink(CTR_Map *obj_map); - - void SetForceLoc(const double force[3]) { /*m_force=force;*/ } - void UpdateFuzzyFlags() - { - m_bitLocalFlag.ZeroForce = MT_fuzzyZero(m_force); - m_bitLocalFlag.ZeroTorque = MT_fuzzyZero(m_torque); - m_bitLocalFlag.ZeroDLoc = MT_fuzzyZero(m_dloc); - m_bitLocalFlag.ZeroDRot = MT_fuzzyZero(m_drot); - m_bitLocalFlag.ZeroLinearVelocity = MT_fuzzyZero(m_linear_velocity); - m_linear_length2 = (m_bitLocalFlag.ZeroLinearVelocity) ? 0.0f : m_linear_velocity.length2(); - m_bitLocalFlag.ZeroAngularVelocity = MT_fuzzyZero(m_angular_velocity); - m_angular_length2 = (m_bitLocalFlag.ZeroAngularVelocity) ? 0.0f : m_angular_velocity.length2(); - } + KX_ObjectActuator(SCA_IObject *gameobj, + KX_GameObject *refobj, + const mt::vec3& force, + const mt::vec3& torque, + const mt::vec3& dloc, + const mt::vec3& drot, + const mt::vec3& linV, + const mt::vec3& angV, + const short damping, + const KX_LocalFlags& flag); + virtual ~KX_ObjectActuator(); + + virtual EXP_Value *GetReplica(); + virtual void ProcessReplica(); + virtual bool UnlinkObject(SCA_IObject *clientobj); + virtual void Relink(std::map& obj_map); + + void UpdateFuzzyFlags(); + virtual bool Update(); #ifdef WITH_PYTHON - /* --------------------------------------------------------------------- */ - /* Python interface ---------------------------------------------------- */ - /* --------------------------------------------------------------------- */ - - /* Attributes */ - static PyObject* pyattr_get_forceLimitX(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_forceLimitX(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_forceLimitY(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_forceLimitY(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_forceLimitZ(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_forceLimitZ(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_reference(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_reference(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_forceLimitX(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_forceLimitX(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_forceLimitY(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_forceLimitY(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_forceLimitZ(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_forceLimitZ(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_reference(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_reference(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); #ifdef USE_MATHUTILS - static PyObject* pyattr_get_linV(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_linV(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_angV(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_angV(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_linV(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_linV(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_angV(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_angV(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); #endif - // This lets the attribute macros use UpdateFuzzyFlags() - static int PyUpdateFuzzyFlags(void *self, const PyAttributeDef *attrdef) - { - KX_ObjectActuator* act = reinterpret_cast(self); - act->UpdateFuzzyFlags(); - return 0; - } - - // This is the keep the PID values in check after they are assigned with Python - static int PyCheckPid(void *self, const PyAttributeDef *attrdef) - { - KX_ObjectActuator* act = reinterpret_cast(self); - - //P 0 to 200 - if (act->m_pid[0] < 0) { - act->m_pid[0] = 0; - } else if (act->m_pid[0] > 200) { - act->m_pid[0] = 200; - } - - //I 0 to 3 - if (act->m_pid[1] < 0) { - act->m_pid[1] = 0; - } else if (act->m_pid[1] > 3) { - act->m_pid[1] = 3; - } - - //D -100 to 100 - if (act->m_pid[2] < -100) { - act->m_pid[2] = -100; - } else if (act->m_pid[2] > 100) { - act->m_pid[2] = 100; - } - - return 0; - } + /// This lets the attribute macros use UpdateFuzzyFlags(). + static int PyUpdateFuzzyFlags(EXP_PyObjectPlus *self, const PyAttributeDef *attrdef); + /// This is the keep the PID values in check after they are assigned with Python. + static int PyCheckPid(EXP_PyObjectPlus *self, const PyAttributeDef *attrdef); -#endif /* WITH_PYTHON */ +#endif // WITH_PYTHON }; -#endif /* __KX_OBJECTACTUATOR_H__ */ +#endif // __KX_OBJECTACTUATOR_H__ diff --git a/source/gameengine/Ketsji/KX_ObstacleSimulation.cpp b/source/gameengine/Ketsji/KX_ObstacleSimulation.cpp index 20d4a5175522..221c62dbb3c1 100644 --- a/source/gameengine/Ketsji/KX_ObstacleSimulation.cpp +++ b/source/gameengine/Ketsji/KX_ObstacleSimulation.cpp @@ -28,70 +28,81 @@ #include "KX_ObstacleSimulation.h" #include "KX_NavMeshObject.h" -#include "KX_PythonInit.h" +#include "KX_Globals.h" #include "DNA_object_types.h" #include "BLI_math.h" namespace { - inline float perp(const MT_Vector2& a, const MT_Vector2& b) { return a.x()*b.y() - a.y()*b.x(); } - - inline float sqr(float x) { return x * x; } - inline float lerp(float a, float b, float t) { return a + (b - a) * t; } - inline float clamp(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); } - inline void vset(float v[2], float x, float y) { v[0] = x; v[1] = y; } +inline float perp(const mt::vec2& a, const mt::vec2& b) +{ + return a.x * b.y - a.y * b.x; } -/* grr, seems moto provides no nice way to do this */ -#define MT_3D_AS_2D(v) MT_Vector2((v)[0], (v)[1]) +inline float sqr(float x) +{ + return x * x; +} +inline float lerp(float a, float b, float t) +{ + return a + (b - a) * t; +} +inline float clamp(float a, float mn, float mx) +{ + return a < mn ? mn : (a > mx ? mx : a); +} +} -static int sweepCircleCircle( - const MT_Vector2 &pos0, const MT_Scalar r0, const MT_Vector2 &v, - const MT_Vector2 &pos1, const MT_Scalar r1, - float& tmin, float& tmax) +static int sweepCircleCircle(const mt::vec2 &pos0, const float r0, const mt::vec2 &v, + const mt::vec2 &pos1, const float r1, + float& tmin, float& tmax) { static const float EPS = 0.0001f; - MT_Vector2 c0(pos0.x(), pos0.y()); - MT_Vector2 c1(pos1.x(), pos1.y()); - MT_Vector2 s = c1 - c0; - MT_Scalar r = r0+r1; - float c = s.length2() - r*r; - float a = v.length2(); - if (a < EPS) return 0; // not moving + mt::vec2 c0(pos0.x, pos0.y); + mt::vec2 c1(pos1.x, pos1.y); + mt::vec2 s = c1 - c0; + float r = r0 + r1; + float c = s.LengthSquared() - r * r; + float a = v.LengthSquared(); + if (a < EPS) { + return 0; // not moving + } // Overlap, calc time to exit. - float b = MT_dot(v,s); - float d = b*b - a*c; - if (d < 0.0f) return 0; // no intersection. + float b = mt::dot(v, s); + float d = b * b - a * c; + if (d < 0.0f) { + return 0; // no intersection. + } tmin = (b - sqrtf(d)) / a; tmax = (b + sqrtf(d)) / a; return 1; } -static int sweepCircleSegment( - const MT_Vector2 &pos0, const MT_Scalar r0, const MT_Vector2 &v, - const MT_Vector2& pa, const MT_Vector2 &pb, const MT_Scalar sr, - float& tmin, float &tmax) +static int sweepCircleSegment(const mt::vec2 &pos0, const float r0, const mt::vec2 &v, + const mt::vec2& pa, const mt::vec2 &pb, const float sr, + float& tmin, float &tmax) { // equation parameters - MT_Vector2 c0(pos0.x(), pos0.y()); - MT_Vector2 sa(pa.x(), pa.y()); - MT_Vector2 sb(pb.x(), pb.y()); - MT_Vector2 L = sb-sa; - MT_Vector2 H = c0-sa; - MT_Scalar radius = r0+sr; - float l2 = L.length2(); + mt::vec2 c0(pos0.x, pos0.y); + mt::vec2 sa(pa.x, pa.y); + mt::vec2 sb(pb.x, pb.y); + mt::vec2 L = sb - sa; + mt::vec2 H = c0 - sa; + float radius = r0 + sr; + float l2 = L.LengthSquared(); float r2 = radius * radius; float dl = perp(v, L); float hl = perp(H, L); float a = dl * dl; float b = 2.0f * hl * dl; float c = hl * hl - (r2 * l2); - float d = (b*b) - (4.0f * a * c); + float d = (b * b) - (4.0f * a * c); // infinite line missed by infinite ray. - if (d < 0.0f) + if (d < 0.0f) { return 0; + } d = sqrtf(d); tmin = (-b - d) / (2.0f * a); @@ -99,45 +110,43 @@ static int sweepCircleSegment( // line missed by ray range. /* if (tmax < 0.0f || tmin > 1.0f) - return 0;*/ + return 0;*/ // find what part of the ray was collided. - MT_Vector2 Pedge; - Pedge = c0+v*tmin; + mt::vec2 Pedge; + Pedge = c0 + v * tmin; H = Pedge - sa; - float e0 = MT_dot(H, L) / l2; - Pedge = c0 + v*tmax; + float e0 = mt::dot(H, L) / l2; + Pedge = c0 + v * tmax; H = Pedge - sa; - float e1 = MT_dot(H, L) / l2; + float e1 = mt::dot(H, L) / l2; - if (e0 < 0.0f || e1 < 0.0f) - { + if (e0 < 0.0f || e1 < 0.0f) { float ctmin, ctmax; - if (sweepCircleCircle(pos0, r0, v, pa, sr, ctmin, ctmax)) - { - if (e0 < 0.0f && ctmin > tmin) + if (sweepCircleCircle(pos0, r0, v, pa, sr, ctmin, ctmax)) { + if (e0 < 0.0f && ctmin > tmin) { tmin = ctmin; - if (e1 < 0.0f && ctmax < tmax) + } + if (e1 < 0.0f && ctmax < tmax) { tmax = ctmax; + } } - else - { + else { return 0; } } - if (e0 > 1.0f || e1 > 1.0f) - { + if (e0 > 1.0f || e1 > 1.0f) { float ctmin, ctmax; - if (sweepCircleCircle(pos0, r0, v, pb, sr, ctmin, ctmax)) - { - if (e0 > 1.0f && ctmin > tmin) + if (sweepCircleCircle(pos0, r0, v, pb, sr, ctmin, ctmax)) { + if (e0 > 1.0f && ctmin > tmin) { tmin = ctmin; - if (e1 > 1.0f && ctmax < tmax) + } + if (e1 > 1.0f && ctmax < tmax) { tmax = ctmax; + } } - else - { + else { return 0; } } @@ -147,231 +156,242 @@ static int sweepCircleSegment( static bool inBetweenAngle(float a, float amin, float amax, float& t) { - if (amax < amin) amax += (float)M_PI*2; - if (a < amin-(float)M_PI) a += (float)M_PI*2; - if (a > amin+(float)M_PI) a -= (float)M_PI*2; - if (a >= amin && a < amax) - { - t = (a-amin) / (amax-amin); + if (amax < amin) { + amax += (float)M_PI * 2; + } + if (a < amin - (float)M_PI) { + a += (float)M_PI * 2; + } + if (a > amin + (float)M_PI) { + a -= (float)M_PI * 2; + } + if (a >= amin && a < amax) { + t = (a - amin) / (amax - amin); return true; } return false; } -static float interpolateToi(float a, const float* dir, const float* toi, const int ntoi) +static float interpolateToi(float a, const float *dir, const float *toi, const int ntoi) { for (int i = 0; i < ntoi; ++i) { - int next = (i+1) % ntoi; + int next = (i + 1) % ntoi; float t; - if (inBetweenAngle(a, dir[i], dir[next], t)) - { + if (inBetweenAngle(a, dir[i], dir[next], t)) { return lerp(toi[i], toi[next], t); } } return 0; } -KX_ObstacleSimulation::KX_ObstacleSimulation(MT_Scalar levelHeight, bool enableVisualization) -: m_levelHeight(levelHeight) -, m_enableVisualization(enableVisualization) +KX_ObstacleSimulation::KX_ObstacleSimulation(float levelHeight, bool enableVisualization) + :m_levelHeight(levelHeight) + , m_enableVisualization(enableVisualization) { } KX_ObstacleSimulation::~KX_ObstacleSimulation() { - for (size_t i=0; im_gameObj = gameobj; - vset(obstacle->vel, 0,0); - vset(obstacle->pvel, 0,0); - vset(obstacle->dvel, 0,0); - vset(obstacle->nvel, 0,0); - for (int i = 0; i < VEL_HIST_SIZE; ++i) - vset(&obstacle->hvel[i*2], 0,0); + obstacle->vel = mt::zero2; + obstacle->pvel = mt::zero2; + obstacle->dvel = mt::zero2; + obstacle->nvel = mt::zero2; + for (int i = 0; i < VEL_HIST_SIZE; ++i) { + obstacle->hvel[i] = mt::zero2; + } obstacle->hhead = 0; - gameobj->RegisterObstacle(this); m_obstacles.push_back(obstacle); return obstacle; } -void KX_ObstacleSimulation::AddObstacleForObj(KX_GameObject* gameobj) +void KX_ObstacleSimulation::AddObstacleForObj(KX_GameObject *gameobj) { - KX_Obstacle* obstacle = CreateObstacle(gameobj); - struct Object* blenderobject = gameobj->GetBlenderObject(); + KX_Obstacle *obstacle = CreateObstacle(gameobj); + struct Object *blenderobject = gameobj->GetBlenderObject(); obstacle->m_type = KX_OBSTACLE_OBJ; obstacle->m_shape = KX_OBSTACLE_CIRCLE; obstacle->m_rad = blenderobject->obstacleRad; } -void KX_ObstacleSimulation::AddObstaclesForNavMesh(KX_NavMeshObject* navmeshobj) +void KX_ObstacleSimulation::AddObstaclesForNavMesh(KX_NavMeshObject *navmeshobj) { - dtStatNavMesh* navmesh = navmeshobj->GetNavMesh(); - if (navmesh) - { + dtStatNavMesh *navmesh = navmeshobj->GetNavMesh(); + if (navmesh) { int npoly = navmesh->getPolyCount(); - for (int pi=0; pigetPoly(pi); + const dtStatPoly *poly = navmesh->getPoly(pi); - for (int i = 0, j = (int)poly->nv-1; i < (int)poly->nv; j = i++) + for (int i = 0, j = (int)poly->nv - 1; i < (int)poly->nv; j = i++) { - if (poly->n[j]) continue; - const float* vj = navmesh->getVertex(poly->v[j]); - const float* vi = navmesh->getVertex(poly->v[i]); + if (poly->n[j]) { + continue; + } + const float *vj = navmesh->getVertex(poly->v[j]); + const float *vi = navmesh->getVertex(poly->v[i]); - KX_Obstacle* obstacle = CreateObstacle(navmeshobj); + KX_Obstacle *obstacle = CreateObstacle(navmeshobj); obstacle->m_type = KX_OBSTACLE_NAV_MESH; obstacle->m_shape = KX_OBSTACLE_SEGMENT; - obstacle->m_pos = MT_Point3(vj[0], vj[2], vj[1]); - obstacle->m_pos2 = MT_Point3(vi[0], vi[2], vi[1]); + obstacle->m_pos = mt::vec3(vj[0], vj[2], vj[1]); + obstacle->m_pos2 = mt::vec3(vi[0], vi[2], vi[1]); obstacle->m_rad = 0; } } } } -void KX_ObstacleSimulation::DestroyObstacleForObj(KX_GameObject* gameobj) +void KX_ObstacleSimulation::DestroyObstacleForObj(KX_GameObject *gameobj) { - for (size_t i=0; im_gameObj == gameobj) - { - KX_Obstacle* obstacle = m_obstacles[i]; - obstacle->m_gameObj->UnregisterObstacle(); + if (m_obstacles[i]->m_gameObj == gameobj) { + KX_Obstacle *obstacle = m_obstacles[i]; m_obstacles[i] = m_obstacles.back(); m_obstacles.pop_back(); delete obstacle; } - else + else { i++; + } } } void KX_ObstacleSimulation::UpdateObstacles() { - for (size_t i=0; im_type==KX_OBSTACLE_NAV_MESH || m_obstacles[i]->m_shape==KX_OBSTACLE_SEGMENT) + if (m_obstacles[i]->m_type == KX_OBSTACLE_NAV_MESH || m_obstacles[i]->m_shape == KX_OBSTACLE_SEGMENT) { continue; + } - KX_Obstacle* obs = m_obstacles[i]; + KX_Obstacle *obs = m_obstacles[i]; obs->m_pos = obs->m_gameObj->NodeGetWorldPosition(); - obs->vel[0] = obs->m_gameObj->GetLinearVelocity().x(); - obs->vel[1] = obs->m_gameObj->GetLinearVelocity().y(); + obs->vel = obs->m_gameObj->GetLinearVelocity().xy(); // Update velocity history and calculate perceived (average) velocity. - copy_v2_v2(&obs->hvel[obs->hhead * 2], obs->vel); - obs->hhead = (obs->hhead+1) % VEL_HIST_SIZE; - vset(obs->pvel,0,0); - for (int j = 0; j < VEL_HIST_SIZE; ++j) - add_v2_v2v2(obs->pvel, obs->pvel, &obs->hvel[j * 2]); - mul_v2_fl(obs->pvel, 1.0f / VEL_HIST_SIZE); + obs->hvel[obs->hhead] = obs->vel; + obs->hhead = (obs->hhead + 1) % VEL_HIST_SIZE; + obs->pvel = mt::zero2; + for (int j = 0; j < VEL_HIST_SIZE; ++j) { + obs->pvel += obs->hvel[j]; + } + obs->pvel *= 1.0f / VEL_HIST_SIZE; } } -KX_Obstacle* KX_ObstacleSimulation::GetObstacle(KX_GameObject* gameobj) +KX_Obstacle *KX_ObstacleSimulation::GetObstacle(KX_GameObject *gameobj) { - for (size_t i=0; im_gameObj == gameobj) + if (m_obstacles[i]->m_gameObj == gameobj) { return m_obstacles[i]; + } } - return NULL; + return nullptr; } -void KX_ObstacleSimulation::AdjustObstacleVelocity(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, - MT_Vector3& velocity, MT_Scalar maxDeltaSpeed,MT_Scalar maxDeltaAngle) +void KX_ObstacleSimulation::AdjustObstacleVelocity(KX_Obstacle *activeObst, KX_NavMeshObject *activeNavMeshObj, + mt::vec3& velocity, float maxDeltaSpeed, float maxDeltaAngle) { } void KX_ObstacleSimulation::DrawObstacles() { - if (!m_enableVisualization) + if (!m_enableVisualization) { return; - static const MT_Vector3 bluecolor(0,0,1); - static const MT_Vector3 normal(0.0f, 0.0f, 1.0f); + } + static const mt::vec4 bluecolor(0.0f, 0.0f, 1.0f, 1.0f); static const int SECTORS_NUM = 32; - for (size_t i=0; im_shape==KX_OBSTACLE_SEGMENT) - { - MT_Point3 p1 = m_obstacles[i]->m_pos; - MT_Point3 p2 = m_obstacles[i]->m_pos2; + if (m_obstacles[i]->m_shape == KX_OBSTACLE_SEGMENT) { + mt::vec3 p1 = m_obstacles[i]->m_pos; + mt::vec3 p2 = m_obstacles[i]->m_pos2; //apply world transform - if (m_obstacles[i]->m_type == KX_OBSTACLE_NAV_MESH) - { - KX_NavMeshObject* navmeshobj = static_cast(m_obstacles[i]->m_gameObj); + if (m_obstacles[i]->m_type == KX_OBSTACLE_NAV_MESH) { + KX_NavMeshObject *navmeshobj = static_cast(m_obstacles[i]->m_gameObj); p1 = navmeshobj->TransformToWorldCoords(p1); p2 = navmeshobj->TransformToWorldCoords(p2); } KX_RasterizerDrawDebugLine(p1, p2, bluecolor); } - else if (m_obstacles[i]->m_shape==KX_OBSTACLE_CIRCLE) - { - KX_RasterizerDrawDebugCircle(m_obstacles[i]->m_pos, m_obstacles[i]->m_rad, bluecolor, - normal, SECTORS_NUM); + else if (m_obstacles[i]->m_shape == KX_OBSTACLE_CIRCLE) { + const float radius = m_obstacles[i]->m_rad; + const mt::vec3& pos = m_obstacles[i]->m_pos; + const float delta = M_PI * 2.0f / SECTORS_NUM; + for (unsigned short i = 0; i < SECTORS_NUM; ++i) { + const float t1 = delta * i; + const float t2 = delta * (i + 1); + const mt::vec3 p1 = mt::vec3(cosf(t1), sinf(t1), 0.0f) * radius + pos; + const mt::vec3 p2 = mt::vec3(cosf(t2), sinf(t2), 0.0f) * radius + pos; + KX_RasterizerDrawDebugLine(p1, p2, bluecolor); + } } } } -static MT_Point3 nearestPointToObstacle(MT_Point3& pos ,KX_Obstacle* obstacle) +static mt::vec3 nearestPointToObstacle(mt::vec3& pos, KX_Obstacle *obstacle) { - switch (obstacle->m_shape) - { - case KX_OBSTACLE_SEGMENT : - { - MT_Vector3 ab = obstacle->m_pos2 - obstacle->m_pos; - if (!ab.fuzzyZero()) + switch (obstacle->m_shape) { + case KX_OBSTACLE_SEGMENT: { - const MT_Scalar dist = ab.length(); - MT_Vector3 abdir = ab.normalized(); - MT_Vector3 v = pos - obstacle->m_pos; - MT_Scalar proj = abdir.dot(v); - CLAMP(proj, 0, dist); - MT_Point3 res = obstacle->m_pos + abdir*proj; - return res; + mt::vec3 ab = obstacle->m_pos2 - obstacle->m_pos; + if (!mt::FuzzyZero(ab)) { + const float dist = ab.Length(); + mt::vec3 abdir = ab.Normalized(); + mt::vec3 v = pos - obstacle->m_pos; + float proj = mt::dot(abdir, v); + CLAMP(proj, 0, dist); + mt::vec3 res = obstacle->m_pos + abdir * proj; + return res; + } + ATTR_FALLTHROUGH; } - ATTR_FALLTHROUGH; - } - case KX_OBSTACLE_CIRCLE : - default: - return obstacle->m_pos; + case KX_OBSTACLE_CIRCLE: + default: + return obstacle->m_pos; } } -static bool filterObstacle(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, KX_Obstacle* otherObst, - float levelHeight) +static bool filterObstacle(KX_Obstacle *activeObst, KX_NavMeshObject *activeNavMeshObj, KX_Obstacle *otherObst, + float levelHeight) { //filter obstacles by type - if ( (otherObst == activeObst) || - (otherObst->m_type==KX_OBSTACLE_NAV_MESH && otherObst->m_gameObj!=activeNavMeshObj) ) + if ((otherObst == activeObst) || + (otherObst->m_type == KX_OBSTACLE_NAV_MESH && otherObst->m_gameObj != activeNavMeshObj)) { return false; + } //filter obstacles by position - MT_Point3 p = nearestPointToObstacle(activeObst->m_pos, otherObst); - if ( fabsf(activeObst->m_pos.z() - p.z()) > levelHeight) + mt::vec3 p = nearestPointToObstacle(activeObst->m_pos, otherObst); + if (fabsf(activeObst->m_pos.z - p.z) > levelHeight) { return false; + } return true; } ///////////*********TOI_rays**********///////////////// -KX_ObstacleSimulationTOI::KX_ObstacleSimulationTOI(MT_Scalar levelHeight, bool enableVisualization) -: KX_ObstacleSimulation(levelHeight, enableVisualization), +KX_ObstacleSimulationTOI::KX_ObstacleSimulationTOI(float levelHeight, bool enableVisualization) + :KX_ObstacleSimulation(levelHeight, enableVisualization), m_maxSamples(32), m_minToi(0.0f), m_maxToi(0.0f), @@ -383,45 +403,46 @@ KX_ObstacleSimulationTOI::KX_ObstacleSimulationTOI(MT_Scalar levelHeight, bool e } -void KX_ObstacleSimulationTOI::AdjustObstacleVelocity(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, - MT_Vector3& velocity, MT_Scalar maxDeltaSpeed, MT_Scalar maxDeltaAngle) +void KX_ObstacleSimulationTOI::AdjustObstacleVelocity(KX_Obstacle *activeObst, KX_NavMeshObject *activeNavMeshObj, + mt::vec3& velocity, float maxDeltaSpeed, float maxDeltaAngle) { int nobs = m_obstacles.size(); int obstidx = std::find(m_obstacles.begin(), m_obstacles.end(), activeObst) - m_obstacles.begin(); - if (obstidx == nobs) + if (obstidx == nobs) { return; + } - vset(activeObst->dvel, velocity.x(), velocity.y()); + activeObst->dvel = velocity.xy(); //apply RVO sampleRVO(activeObst, activeNavMeshObj, maxDeltaAngle); // Fake dynamic constraint. - float dv[2]; - float vel[2]; - sub_v2_v2v2(dv, activeObst->nvel, activeObst->vel); - float ds = len_v2(dv); - if (ds > maxDeltaSpeed || ds<-maxDeltaSpeed) - mul_v2_fl(dv, fabs(maxDeltaSpeed / ds)); - add_v2_v2v2(vel, activeObst->vel, dv); - - velocity.x() = vel[0]; - velocity.y() = vel[1]; + mt::vec2 dv = activeObst->nvel - activeObst->vel; + const float ds = dv.Length(); + if (ds > maxDeltaSpeed || ds < -maxDeltaSpeed) { + dv *= fabsf(maxDeltaSpeed / ds); + } + const mt::vec2 vel = activeObst->vel + dv; + + velocity.x = vel.x; + velocity.y = vel.y; } ///////////*********TOI_rays**********///////////////// static const int AVOID_MAX_STEPS = 128; -struct TOICircle -{ - TOICircle() : n(0), minToi(0), maxToi(1) {} - float toi[AVOID_MAX_STEPS]; // Time of impact (seconds) - float toie[AVOID_MAX_STEPS]; // Time of exit (seconds) - float dir[AVOID_MAX_STEPS]; // Direction (radians) - int n; // Number of samples - float minToi, maxToi; // Min/max TOI (seconds) +struct TOICircle { + TOICircle() :n(0), minToi(0), maxToi(1) + { + } + float toi[AVOID_MAX_STEPS]; // Time of impact (seconds) + float toie[AVOID_MAX_STEPS]; // Time of exit (seconds) + float dir[AVOID_MAX_STEPS]; // Direction (radians) + int n; // Number of samples + float minToi, maxToi; // Min/max TOI (seconds) }; -KX_ObstacleSimulationTOI_rays::KX_ObstacleSimulationTOI_rays(MT_Scalar levelHeight, bool enableVisualization): +KX_ObstacleSimulationTOI_rays::KX_ObstacleSimulationTOI_rays(float levelHeight, bool enableVisualization) : KX_ObstacleSimulationTOI(levelHeight, enableVisualization) { m_maxSamples = 32; @@ -433,15 +454,15 @@ KX_ObstacleSimulationTOI_rays::KX_ObstacleSimulationTOI_rays(MT_Scalar levelHeig } -void KX_ObstacleSimulationTOI_rays::sampleRVO(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, - const float maxDeltaAngle) +void KX_ObstacleSimulationTOI_rays::sampleRVO(KX_Obstacle *activeObst, KX_NavMeshObject *activeNavMeshObj, + const float maxDeltaAngle) { - MT_Vector2 vel(activeObst->dvel[0], activeObst->dvel[1]); - float vmax = (float) vel.length(); - float odir = (float) atan2(vel.y(), vel.x()); + mt::vec2 vel = activeObst->dvel; + float vmax = (float)vel.Length(); + float odir = (float)atan2(vel.y, vel.x); - MT_Vector2 ddir = vel; - ddir.normalize(); + mt::vec2 ddir = vel; + ddir.Normalize(); float bestScore = FLT_MAX; float bestDir = odir; @@ -452,65 +473,60 @@ void KX_ObstacleSimulationTOI_rays::sampleRVO(KX_Obstacle* activeObst, KX_NavMes tc.minToi = m_minToi; tc.maxToi = m_maxToi; - const int iforw = m_maxSamples/2; + const int iforw = m_maxSamples / 2; const float aoff = (float)iforw / (float)m_maxSamples; size_t nobs = m_obstacles.size(); for (int iter = 0; iter < m_maxSamples; ++iter) { // Calculate sample velocity - const float ndir = ((float)iter/(float)m_maxSamples) - aoff; - const float dir = odir+ndir*(float)M_PI*2.0f; - MT_Vector2 svel; - svel.x() = cosf(dir) * vmax; - svel.y() = sinf(dir) * vmax; + const float ndir = ((float)iter / (float)m_maxSamples) - aoff; + const float dir = odir + ndir * (float)M_PI * 2.0f; + mt::vec2 svel; + svel.x = cosf(dir) * vmax; + svel.y = sinf(dir) * vmax; // Find min time of impact and exit amongst all obstacles. float tmin = m_maxToi; float tmine = 0.0f; for (int i = 0; i < nobs; ++i) { - KX_Obstacle* ob = m_obstacles[i]; + KX_Obstacle *ob = m_obstacles[i]; bool res = filterObstacle(activeObst, activeNavMeshObj, ob, m_levelHeight); - if (!res) + if (!res) { continue; + } - float htmin,htmax; + float htmin, htmax; - if (ob->m_shape == KX_OBSTACLE_CIRCLE) - { - MT_Vector2 vab; - if (len_v2(ob->vel) < 0.01f * 0.01f) { + if (ob->m_shape == KX_OBSTACLE_CIRCLE) { + mt::vec2 vab; + if (ob->vel.Length() < 0.01f * 0.01f) { // Stationary, use VO vab = svel; } - else - { + else { // Moving, use RVO - vab = 2*svel - vel - ob->vel; + vab = (2.0f * svel) - vel - mt::vec2(ob->vel); } - if (!sweepCircleCircle(MT_3D_AS_2D(activeObst->m_pos), activeObst->m_rad, - vab, MT_3D_AS_2D(ob->m_pos), ob->m_rad, htmin, htmax)) - { + if (!sweepCircleCircle(activeObst->m_pos.xy(), activeObst->m_rad, + vab, ob->m_pos.xy(), ob->m_rad, htmin, htmax)) { continue; } } - else if (ob->m_shape == KX_OBSTACLE_SEGMENT) - { - MT_Point3 p1 = ob->m_pos; - MT_Point3 p2 = ob->m_pos2; + else if (ob->m_shape == KX_OBSTACLE_SEGMENT) { + mt::vec3 p1 = ob->m_pos; + mt::vec3 p2 = ob->m_pos2; //apply world transform - if (ob->m_type == KX_OBSTACLE_NAV_MESH) - { - KX_NavMeshObject* navmeshobj = static_cast(ob->m_gameObj); + if (ob->m_type == KX_OBSTACLE_NAV_MESH) { + KX_NavMeshObject *navmeshobj = static_cast(ob->m_gameObj); p1 = navmeshobj->TransformToWorldCoords(p1); p2 = navmeshobj->TransformToWorldCoords(p2); } - if (!sweepCircleSegment(MT_3D_AS_2D(activeObst->m_pos), activeObst->m_rad, svel, - MT_3D_AS_2D(p1), MT_3D_AS_2D(p2), ob->m_rad, htmin, htmax)) - { + if (!sweepCircleSegment(activeObst->m_pos.xy(), activeObst->m_rad, svel, + p1.xy(), p2.xy(), ob->m_rad, htmin, htmax)) { continue; } } @@ -518,29 +534,28 @@ void KX_ObstacleSimulationTOI_rays::sampleRVO(KX_Obstacle* activeObst, KX_NavMes continue; } - if (htmin > 0.0f) - { + if (htmin > 0.0f) { // The closest obstacle is somewhere ahead of us, keep track of nearest obstacle. - if (htmin < tmin) + if (htmin < tmin) { tmin = htmin; + } } - else if (htmax > 0.0f) - { + else if (htmax > 0.0f) { // The agent overlaps the obstacle, keep track of first safe exit. - if (htmax > tmine) + if (htmax > tmine) { tmine = htmax; + } } } // Calculate sample penalties and final score. const float apen = m_velWeight * fabsf(ndir); - const float tpen = m_toiWeight * (1.0f/(0.0001f+tmin/m_maxToi)); - const float cpen = m_collisionWeight * (tmine/m_minToi)*(tmine/m_minToi); + const float tpen = m_toiWeight * (1.0f / (0.0001f + tmin / m_maxToi)); + const float cpen = m_collisionWeight * (tmine / m_minToi) * (tmine / m_minToi); const float score = apen + tpen + cpen; // Update best score. - if (score < bestScore) - { + if (score < bestScore) { bestDir = dir; bestToi = tmin; bestScore = score; @@ -551,60 +566,54 @@ void KX_ObstacleSimulationTOI_rays::sampleRVO(KX_Obstacle* activeObst, KX_NavMes tc.toie[iter] = tmine; } - if (len_v2(activeObst->vel) > 0.1f) { + if (activeObst->vel.Length() > 0.1f) { // Constrain max turn rate. - float cura = atan2(activeObst->vel[1],activeObst->vel[0]); + float cura = atan2(activeObst->vel.x, activeObst->vel.y); float da = bestDir - cura; - if (da < -M_PI) da += (float)M_PI*2; - if (da > M_PI) da -= (float)M_PI*2; - if (da < -maxDeltaAngle) - { + if (da < -M_PI) { + da += (float)M_PI * 2; + } + if (da > M_PI) { + da -= (float)M_PI * 2; + } + if (da < -maxDeltaAngle) { bestDir = cura - maxDeltaAngle; - bestToi = min(bestToi, interpolateToi(bestDir, tc.dir, tc.toi, tc.n)); + bestToi = std::min(bestToi, interpolateToi(bestDir, tc.dir, tc.toi, tc.n)); } - else if (da > maxDeltaAngle) - { + else if (da > maxDeltaAngle) { bestDir = cura + maxDeltaAngle; - bestToi = min(bestToi, interpolateToi(bestDir, tc.dir, tc.toi, tc.n)); + bestToi = std::min(bestToi, interpolateToi(bestDir, tc.dir, tc.toi, tc.n)); } } // Adjust speed when time of impact is less than min TOI. - if (bestToi < m_minToi) - vmax *= bestToi/m_minToi; + if (bestToi < m_minToi) { + vmax *= bestToi / m_minToi; + } // New steering velocity. - activeObst->nvel[0] = cosf(bestDir) * vmax; - activeObst->nvel[1] = sinf(bestDir) * vmax; + activeObst->nvel.x = cosf(bestDir) * vmax; + activeObst->nvel.y = sinf(bestDir) * vmax; } ///////////********* TOI_cells**********///////////////// -static void processSamples(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, +static void processSamples(KX_Obstacle *activeObst, KX_NavMeshObject *activeNavMeshObj, KX_Obstacles& obstacles, float levelHeight, const float vmax, - const float* spos, const float cs, const int nspos, float* res, + mt::vec2 *spos, const float cs, const int nspos, mt::vec2& res, float maxToi, float velWeight, float curVelWeight, float sideWeight, float toiWeight) { - vset(res, 0,0); + res = mt::zero2; const float ivmax = 1.0f / vmax; - - float adir[2] /*, adist */; - if (normalize_v2_v2(adir, activeObst->pvel) <= 0.01f) { - zero_v2(adir); - } - - float activeObstPos[2]; - vset(activeObstPos, activeObst->m_pos.x(), activeObst->m_pos.y()); - /* adist = vdot(adir, activeObstPos); */ + const mt::vec2 activeObstPos = activeObst->m_pos.xy(); float minPenalty = FLT_MAX; for (int n = 0; n < nspos; ++n) { - float vcand[2]; - copy_v2_v2(vcand, &spos[n * 2]); + const mt::vec2& vcand = spos[n]; // Find min time of impact and exit amongst all obstacles. float tmin = maxToi; @@ -613,36 +622,29 @@ static void processSamples(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavM for (int i = 0; i < obstacles.size(); ++i) { - KX_Obstacle* ob = obstacles[i]; - bool res = filterObstacle(activeObst, activeNavMeshObj, ob, levelHeight); - if (!res) + KX_Obstacle *ob = obstacles[i]; + bool found = filterObstacle(activeObst, activeNavMeshObj, ob, levelHeight); + if (!found) { continue; + } float htmin, htmax; - if (ob->m_shape==KX_OBSTACLE_CIRCLE) - { - float vab[2]; - + if (ob->m_shape == KX_OBSTACLE_CIRCLE) { // Moving, use RVO - mul_v2_v2fl(vab, vcand, 2); - sub_v2_v2v2(vab, vab, activeObst->vel); - sub_v2_v2v2(vab, vab, ob->vel); + const mt::vec2 vab = vcand * 2.0f - activeObst->vel - ob->vel; // Side // NOTE: dp, and dv are constant over the whole calculation, // they can be precomputed per object. - const float* pa = activeObstPos; - float pb[2]; - vset(pb, ob->m_pos.x(), ob->m_pos.y()); + const mt::vec2 pb = ob->m_pos.xy(); const float orig[2] = {0, 0}; - float dp[2], dv[2], np[2]; - sub_v2_v2v2(dp, pb, pa); - normalize_v2(dp); - sub_v2_v2v2(dv, ob->dvel, activeObst->dvel); + const mt::vec2 dp = (pb - activeObstPos).Normalized(); + const mt::vec2 dv = ob->dvel - activeObst->dvel; + mt::vec2 np; /* TODO: use line_point_side_v2 */ - if (area_tri_signed_v2(orig, dp, dv) < 0.01f) { + if (area_tri_signed_v2(orig, dp.Data(), dv.Data()) < 0.01f) { np[0] = -dp[1]; np[1] = dp[0]; } @@ -651,59 +653,54 @@ static void processSamples(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavM np[1] = -dp[0]; } - side += clamp(min(dot_v2v2(dp, vab), - dot_v2v2(np, vab)) * 2.0f, 0.0f, 1.0f); + side += clamp(std::min(mt::dot(dp, vab), + mt::dot(np, vab)) * 2.0f, 0.0f, 1.0f); nside++; - if (!sweepCircleCircle(MT_3D_AS_2D(activeObst->m_pos), activeObst->m_rad, - vab, MT_3D_AS_2D(ob->m_pos), ob->m_rad, htmin, htmax)) - { + if (!sweepCircleCircle(activeObst->m_pos.xy(), activeObst->m_rad, + mt::vec2(vab), ob->m_pos.xy(), ob->m_rad, htmin, htmax)) { continue; } // Handle overlapping obstacles. - if (htmin < 0.0f && htmax > 0.0f) - { + if (htmin < 0.0f && htmax > 0.0f) { // Avoid more when overlapped. htmin = -htmin * 0.5f; } } - else if (ob->m_shape == KX_OBSTACLE_SEGMENT) - { - MT_Point3 p1 = ob->m_pos; - MT_Point3 p2 = ob->m_pos2; + else if (ob->m_shape == KX_OBSTACLE_SEGMENT) { + mt::vec3 p1 = ob->m_pos; + mt::vec3 p2 = ob->m_pos2; //apply world transform - if (ob->m_type == KX_OBSTACLE_NAV_MESH) - { - KX_NavMeshObject* navmeshobj = static_cast(ob->m_gameObj); + if (ob->m_type == KX_OBSTACLE_NAV_MESH) { + KX_NavMeshObject *navmeshobj = static_cast(ob->m_gameObj); p1 = navmeshobj->TransformToWorldCoords(p1); p2 = navmeshobj->TransformToWorldCoords(p2); } - float p[2], q[2]; - vset(p, p1.x(), p1.y()); - vset(q, p2.x(), p2.y()); + const mt::vec2 p = p1.xy(); + const mt::vec2 q = p2.xy(); // NOTE: the segments are assumed to come from a navmesh which is shrunken by // the agent radius, hence the use of really small radius. // This can be handle more efficiently by using seg-seg test instead. // If the whole segment is to be treated as obstacle, use agent->rad instead of 0.01f! const float r = 0.01f; // agent->rad - if (dist_squared_to_line_segment_v2(activeObstPos, p, q) < sqr(r + ob->m_rad)) { - float sdir[2], snorm[2]; - sub_v2_v2v2(sdir, q, p); - snorm[0] = sdir[1]; - snorm[1] = -sdir[0]; + if (dist_squared_to_line_segment_v2(activeObstPos.Data(), p.Data(), q.Data()) < sqr(r + ob->m_rad)) { + const mt::vec2 sdir = q - p; + const mt::vec2 snorm(sdir.y, -sdir.x); // If the velocity is pointing towards the segment, no collision. - if (dot_v2v2(snorm, vcand) < 0.0f) + if (mt::dot(snorm, vcand) < 0.0f) { continue; + } // Else immediate collision. htmin = 0.0f; htmax = 10.0f; } - else - { - if (!sweepCircleSegment(activeObstPos, r, vcand, p, q, ob->m_rad, htmin, htmax)) + else { + if (!sweepCircleSegment(mt::vec2(activeObstPos), r, mt::vec2(vcand), + mt::vec2(p), mt::vec2(q), ob->m_rad, htmin, htmax)) { continue; + } } // Avoid less when facing walls. @@ -713,117 +710,107 @@ static void processSamples(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavM continue; } - if (htmin >= 0.0f) - { + if (htmin >= 0.0f) { // The closest obstacle is somewhere ahead of us, keep track of nearest obstacle. - if (htmin < tmin) + if (htmin < tmin) { tmin = htmin; + } } } // Normalize side bias, to prevent it dominating too much. - if (nside) + if (nside) { side /= nside; + } - const float vpen = velWeight * (len_v2v2(vcand, activeObst->dvel) * ivmax); - const float vcpen = curVelWeight * (len_v2v2(vcand, activeObst->vel) * ivmax); + const float vpen = velWeight * (vcand - activeObst->dvel).Length() * ivmax; + const float vcpen = curVelWeight * (vcand - activeObst->vel).Length() * ivmax; const float spen = sideWeight * side; - const float tpen = toiWeight * (1.0f/(0.1f+tmin/maxToi)); + const float tpen = toiWeight * (1.0f / (0.1f + tmin / maxToi)); const float penalty = vpen + vcpen + spen + tpen; if (penalty < minPenalty) { minPenalty = penalty; - copy_v2_v2(res, vcand); + res = vcand; } } } -void KX_ObstacleSimulationTOI_cells::sampleRVO(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, - const float maxDeltaAngle) +void KX_ObstacleSimulationTOI_cells::sampleRVO(KX_Obstacle *activeObst, KX_NavMeshObject *activeNavMeshObj, + const float maxDeltaAngle) { - vset(activeObst->nvel, 0.f, 0.f); - float vmax = len_v2(activeObst->dvel); + activeObst->nvel = mt::zero2; + const float vmax = activeObst->dvel.Length(); - float* spos = new float[2*m_maxSamples]; + mt::vec2 *spos = new mt::vec2[m_maxSamples]; int nspos = 0; - if (!m_adaptive) - { - const float cvx = activeObst->dvel[0]*m_bias; - const float cvy = activeObst->dvel[1]*m_bias; - float vmax = len_v2(activeObst->dvel); - const float vrange = vmax*(1-m_bias); - const float cs = 1.0f / (float)m_sampleRadius*vrange; + if (!m_adaptive) { + const mt::vec2 cv = activeObst->dvel * m_bias; + const float vrange = vmax * (1 - m_bias); + const float cs = 1.0f / (float)m_sampleRadius * vrange; for (int y = -m_sampleRadius; y <= m_sampleRadius; ++y) { for (int x = -m_sampleRadius; x <= m_sampleRadius; ++x) { - if (nspos < m_maxSamples) - { - const float vx = cvx + (float)(x+0.5f)*cs; - const float vy = cvy + (float)(y+0.5f)*cs; - if (vx*vx+vy*vy > sqr(vmax+cs/2)) continue; - spos[nspos*2+0] = vx; - spos[nspos*2+1] = vy; + if (nspos < m_maxSamples) { + const mt::vec2 v = cv + (float)(x + 0.5f) * cs; + if (v.LengthSquared() > sqr(vmax + cs / 2)) { + continue; + } + spos[nspos] = v; nspos++; } } } - processSamples(activeObst, activeNavMeshObj, m_obstacles, m_levelHeight, vmax, spos, cs/2, - nspos, activeObst->nvel, m_maxToi, m_velWeight, m_curVelWeight, m_collisionWeight, m_toiWeight); + processSamples(activeObst, activeNavMeshObj, m_obstacles, m_levelHeight, vmax, spos, cs / 2, + nspos, activeObst->nvel, m_maxToi, m_velWeight, m_curVelWeight, m_collisionWeight, m_toiWeight); } - else - { - int rad; - float res[2]; - float cs; + else { + const int rad = 4; // First sample location. - rad = 4; - res[0] = activeObst->dvel[0]*m_bias; - res[1] = activeObst->dvel[1]*m_bias; - cs = vmax*(2-m_bias*2) / (float)(rad-1); + mt::vec2 res = activeObst->dvel * m_bias; + float cs = vmax * (2 - m_bias * 2) / (float)(rad - 1); for (int k = 0; k < 5; ++k) { - const float half = (rad-1)*cs*0.5f; + const float half = (rad - 1) * cs * 0.5f; nspos = 0; for (int y = 0; y < rad; ++y) { for (int x = 0; x < rad; ++x) { - const float v_xy[2] = { - res[0] + x * cs - half, - res[1] + y * cs - half}; - - if (len_squared_v2(v_xy) > sqr(vmax + cs / 2)) + const mt::vec2 v_xy = res + mt::vec2(x, y) * cs - half; + if (v_xy.LengthSquared() > sqr(vmax + cs / 2)) { continue; + } - copy_v2_v2(&spos[nspos * 2 + 0], v_xy); + spos[nspos] = v_xy; nspos++; } } - processSamples(activeObst, activeNavMeshObj, m_obstacles, m_levelHeight, vmax, spos, cs/2, + processSamples(activeObst, activeNavMeshObj, m_obstacles, m_levelHeight, vmax, spos, cs / 2, nspos, res, m_maxToi, m_velWeight, m_curVelWeight, m_collisionWeight, m_toiWeight); cs *= 0.5f; } - copy_v2_v2(activeObst->nvel, res); + activeObst->nvel = res; } - delete [] spos; + delete[] spos; } -KX_ObstacleSimulationTOI_cells::KX_ObstacleSimulationTOI_cells(MT_Scalar levelHeight, bool enableVisualization) -: KX_ObstacleSimulationTOI(levelHeight, enableVisualization) -, m_bias(0.4f) -, m_adaptive(true) -, m_sampleRadius(15) +KX_ObstacleSimulationTOI_cells::KX_ObstacleSimulationTOI_cells(float levelHeight, bool enableVisualization) + :KX_ObstacleSimulationTOI(levelHeight, enableVisualization) + , m_bias(0.4f) + , m_adaptive(true) + , m_sampleRadius(15) { - m_maxSamples = (m_sampleRadius*2+1)*(m_sampleRadius*2+1) + 100; + m_maxSamples = (m_sampleRadius * 2 + 1) * (m_sampleRadius * 2 + 1) + 100; m_maxToi = 1.5f; m_velWeight = 2.0f; m_curVelWeight = 0.75f; diff --git a/source/gameengine/Ketsji/KX_ObstacleSimulation.h b/source/gameengine/Ketsji/KX_ObstacleSimulation.h index a49911e9fb8b..9bb11c3977ce 100644 --- a/source/gameengine/Ketsji/KX_ObstacleSimulation.h +++ b/source/gameengine/Ketsji/KX_ObstacleSimulation.h @@ -1,5 +1,5 @@ /* - * Simulation for obstacle avoidance behavior + * Simulation for obstacle avoidance behavior * (based on Cane Project - http://code.google.com/p/cane by Mikko Mononen (c) 2009) * * ***** BEGIN GPL LICENSE BLOCK ***** @@ -27,41 +27,39 @@ #define __KX_OBSTACLESIMULATION_H__ #include -#include "MT_Point2.h" -#include "MT_Point3.h" +#include "mathfu.h" class KX_GameObject; class KX_NavMeshObject; enum KX_OBSTACLE_TYPE { - KX_OBSTACLE_OBJ, + KX_OBSTACLE_OBJ, KX_OBSTACLE_NAV_MESH, }; enum KX_OBSTACLE_SHAPE { - KX_OBSTACLE_CIRCLE, + KX_OBSTACLE_CIRCLE, KX_OBSTACLE_SEGMENT, }; #define VEL_HIST_SIZE 6 -struct KX_Obstacle +struct KX_Obstacle : mt::SimdClassAllocator { KX_OBSTACLE_TYPE m_type; KX_OBSTACLE_SHAPE m_shape; - MT_Point3 m_pos; - MT_Point3 m_pos2; - MT_Scalar m_rad; - - float vel[2]; - float pvel[2]; - float dvel[2]; - float nvel[2]; - float hvel[VEL_HIST_SIZE*2]; + mt::vec3 m_pos; + mt::vec3 m_pos2; + float m_rad; + + mt::vec2 vel; + mt::vec2 pvel; + mt::vec2 dvel; + mt::vec2 nvel; + mt::vec2 hvel[VEL_HIST_SIZE]; int hhead; - KX_GameObject* m_gameObj; }; typedef std::vector KX_Obstacles; @@ -71,12 +69,12 @@ class KX_ObstacleSimulation protected: KX_Obstacles m_obstacles; - MT_Scalar m_levelHeight; + float m_levelHeight; bool m_enableVisualization; KX_Obstacle* CreateObstacle(KX_GameObject* gameobj); public: - KX_ObstacleSimulation(MT_Scalar levelHeight, bool enableVisualization); + KX_ObstacleSimulation(float levelHeight, bool enableVisualization); virtual ~KX_ObstacleSimulation(); void DrawObstacles(); @@ -87,8 +85,8 @@ class KX_ObstacleSimulation void AddObstaclesForNavMesh(KX_NavMeshObject* navmesh); KX_Obstacle* GetObstacle(KX_GameObject* gameobj); void UpdateObstacles(); - virtual void AdjustObstacleVelocity(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, - MT_Vector3& velocity, MT_Scalar maxDeltaSpeed,MT_Scalar maxDeltaAngle); + virtual void AdjustObstacleVelocity(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, + mt::vec3& velocity, float maxDeltaSpeed,float maxDeltaAngle); }; class KX_ObstacleSimulationTOI: public KX_ObstacleSimulation @@ -102,21 +100,21 @@ class KX_ObstacleSimulationTOI: public KX_ObstacleSimulation float m_toiWeight; // Sample selection TOI weight float m_collisionWeight; // Sample selection collision weight - virtual void sampleRVO(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, + virtual void sampleRVO(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, const float maxDeltaAngle) = 0; public: - KX_ObstacleSimulationTOI(MT_Scalar levelHeight, bool enableVisualization); - virtual void AdjustObstacleVelocity(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, - MT_Vector3& velocity, MT_Scalar maxDeltaSpeed,MT_Scalar maxDeltaAngle); + KX_ObstacleSimulationTOI(float levelHeight, bool enableVisualization); + virtual void AdjustObstacleVelocity(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, + mt::vec3& velocity, float maxDeltaSpeed,float maxDeltaAngle); }; class KX_ObstacleSimulationTOI_rays: public KX_ObstacleSimulationTOI { protected: - virtual void sampleRVO(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, + virtual void sampleRVO(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, const float maxDeltaAngle); public: - KX_ObstacleSimulationTOI_rays(MT_Scalar levelHeight, bool enableVisualization); + KX_ObstacleSimulationTOI_rays(float levelHeight, bool enableVisualization); }; class KX_ObstacleSimulationTOI_cells: public KX_ObstacleSimulationTOI @@ -125,10 +123,10 @@ class KX_ObstacleSimulationTOI_cells: public KX_ObstacleSimulationTOI float m_bias; bool m_adaptive; int m_sampleRadius; - virtual void sampleRVO(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, + virtual void sampleRVO(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, const float maxDeltaAngle); public: - KX_ObstacleSimulationTOI_cells(MT_Scalar levelHeight, bool enableVisualization); + KX_ObstacleSimulationTOI_cells(float levelHeight, bool enableVisualization); }; #endif diff --git a/source/gameengine/Ketsji/KX_OrientationInterpolator.cpp b/source/gameengine/Ketsji/KX_OrientationInterpolator.cpp deleted file mode 100644 index 16a9441acc76..000000000000 --- a/source/gameengine/Ketsji/KX_OrientationInterpolator.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Ketsji/KX_OrientationInterpolator.cpp - * \ingroup ketsji - */ - - -#include "KX_OrientationInterpolator.h" -#include "MT_Matrix3x3.h" -#include "KX_IScalarInterpolator.h" - -void KX_OrientationInterpolator::Execute(float currentTime) const -{ - MT_Vector3 eul(m_ipos[0]->GetValue(currentTime), - m_ipos[1]->GetValue(currentTime), - m_ipos[2]->GetValue(currentTime)); - MT_Scalar ci = cosf(eul[0]); - MT_Scalar cj = cosf(eul[1]); - MT_Scalar ch = cosf(eul[2]); - MT_Scalar si = sinf(eul[0]); - MT_Scalar sj = sinf(eul[1]); - MT_Scalar sh = sinf(eul[2]); - MT_Scalar cc = ci*ch; - MT_Scalar cs = ci*sh; - MT_Scalar sc = si*ch; - MT_Scalar ss = si*sh; - - m_target.setValue(cj*ch, sj*sc-cs, sj*cc+ss, - cj*sh, sj*ss+cc, sj*cs-sc, - -sj, cj*si, cj*ci); -} diff --git a/source/gameengine/Ketsji/KX_OrientationInterpolator.h b/source/gameengine/Ketsji/KX_OrientationInterpolator.h deleted file mode 100644 index d6fa0f797bfd..000000000000 --- a/source/gameengine/Ketsji/KX_OrientationInterpolator.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file KX_OrientationInterpolator.h - * \ingroup ketsji - */ - -#ifndef __KX_ORIENTATIONINTERPOLATOR_H__ -#define __KX_ORIENTATIONINTERPOLATOR_H__ - -#include "KX_IInterpolator.h" - -class MT_Matrix3x3; -class KX_IScalarInterpolator; - -class KX_OrientationInterpolator : public KX_IInterpolator { -public: - KX_OrientationInterpolator(MT_Matrix3x3& target, - KX_IScalarInterpolator **ipos) - : m_target(target) - { - m_ipos[0] = ipos[0]; - m_ipos[1] = ipos[1]; - m_ipos[2] = ipos[2]; - } - - virtual void Execute(float currentTime) const; - -private: - MT_Matrix3x3& m_target; - KX_IScalarInterpolator *m_ipos[3]; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_OrientationInterpolator") -#endif -}; - -#endif diff --git a/source/gameengine/Ketsji/KX_ParentActuator.cpp b/source/gameengine/Ketsji/KX_ParentActuator.cpp index fd4ef89aa85f..0b03e6400c88 100644 --- a/source/gameengine/Ketsji/KX_ParentActuator.cpp +++ b/source/gameengine/Ketsji/KX_ParentActuator.cpp @@ -35,7 +35,7 @@ #include "KX_ParentActuator.h" #include "KX_GameObject.h" -#include "KX_PythonInit.h" +#include "KX_Globals.h" #include "EXP_PyObjectPlus.h" @@ -44,33 +44,35 @@ /* ------------------------------------------------------------------------- */ KX_ParentActuator::KX_ParentActuator(SCA_IObject *gameobj, - int mode, - bool addToCompound, - bool ghost, - SCA_IObject *ob) - : SCA_IActuator(gameobj, KX_ACT_PARENT), - m_mode(mode), - m_addToCompound(addToCompound), - m_ghost(ghost), - m_ob(ob) + int mode, + bool addToCompound, + bool ghost, + SCA_IObject *ob) + :SCA_IActuator(gameobj, KX_ACT_PARENT), + m_mode(mode), + m_addToCompound(addToCompound), + m_ghost(ghost), + m_ob(ob) { - if (m_ob) + if (m_ob) { m_ob->RegisterActuator(this); + } } KX_ParentActuator::~KX_ParentActuator() { - if (m_ob) + if (m_ob) { m_ob->UnregisterActuator(this); + } } -CValue* KX_ParentActuator::GetReplica() +EXP_Value *KX_ParentActuator::GetReplica() { - KX_ParentActuator* replica = new KX_ParentActuator(*this); + KX_ParentActuator *replica = new KX_ParentActuator(*this); // replication just copy the m_base pointer => common random generator replica->ProcessReplica(); return replica; @@ -78,30 +80,31 @@ CValue* KX_ParentActuator::GetReplica() void KX_ParentActuator::ProcessReplica() { - if (m_ob) + if (m_ob) { m_ob->RegisterActuator(this); + } SCA_IActuator::ProcessReplica(); } -bool KX_ParentActuator::UnlinkObject(SCA_IObject* clientobj) +bool KX_ParentActuator::UnlinkObject(SCA_IObject *clientobj) { - if (clientobj == m_ob) - { + if (clientobj == m_ob) { // this object is being deleted, we cannot continue to track it. - m_ob = NULL; + m_ob = nullptr; return true; } return false; } -void KX_ParentActuator::Relink(CTR_Map *obj_map) +void KX_ParentActuator::Relink(std::map& obj_map) { - void **h_obj = (*obj_map)[m_ob]; - if (h_obj) { - if (m_ob) + SCA_IObject *obj = obj_map[m_ob]; + if (obj) { + if (m_ob) { m_ob->UnregisterActuator(this); - m_ob = (SCA_IObject*)(*h_obj); + } + m_ob = obj; m_ob->RegisterActuator(this); } } @@ -113,20 +116,26 @@ bool KX_ParentActuator::Update() bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); - if (bNegativeEvent) + if (bNegativeEvent) { return false; // do nothing on negative events - KX_GameObject *obj = (KX_GameObject*) GetParent(); - KX_Scene *scene = KX_GetActiveScene(); + } + KX_GameObject *obj = (KX_GameObject *)GetParent(); switch (m_mode) { case KX_PARENT_SET: - if (m_ob) - obj->SetParent(scene, (KX_GameObject*)m_ob, m_addToCompound, m_ghost); + { + if (m_ob) { + obj->SetParent((KX_GameObject *)m_ob, m_addToCompound, m_ghost); + } break; + } case KX_PARENT_REMOVE: - obj->RemoveParent(scene); + { + obj->RemoveParent(); break; - }; + } + } + ; return false; } @@ -139,9 +148,9 @@ bool KX_ParentActuator::Update() /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_ParentActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_ParentActuator", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -149,53 +158,58 @@ PyTypeObject KX_ParentActuator::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IActuator::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_ParentActuator::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_ParentActuator::Attributes[] = { - KX_PYATTRIBUTE_RW_FUNCTION("object", KX_ParentActuator, pyattr_get_object, pyattr_set_object), - KX_PYATTRIBUTE_INT_RW("mode", KX_PARENT_NODEF+1, KX_PARENT_MAX-1, true, KX_ParentActuator, m_mode), - KX_PYATTRIBUTE_BOOL_RW("compound", KX_ParentActuator, m_addToCompound), - KX_PYATTRIBUTE_BOOL_RW("ghost", KX_ParentActuator, m_ghost), - { NULL } //Sentinel + EXP_PYATTRIBUTE_RW_FUNCTION("object", KX_ParentActuator, pyattr_get_object, pyattr_set_object), + EXP_PYATTRIBUTE_INT_RW("mode", KX_PARENT_NODEF + 1, KX_PARENT_MAX - 1, true, KX_ParentActuator, m_mode), + EXP_PYATTRIBUTE_BOOL_RW("compound", KX_ParentActuator, m_addToCompound), + EXP_PYATTRIBUTE_BOOL_RW("ghost", KX_ParentActuator, m_ghost), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *KX_ParentActuator::pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_ParentActuator::pyattr_get_object(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - KX_ParentActuator* actuator = static_cast(self); - if (!actuator->m_ob) + KX_ParentActuator *actuator = static_cast(self); + if (!actuator->m_ob) { Py_RETURN_NONE; - else + } + else { return actuator->m_ob->GetProxy(); + } } -int KX_ParentActuator::pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_ParentActuator::pyattr_set_object(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_ParentActuator* actuator = static_cast(self); + KX_ParentActuator *actuator = static_cast(self); KX_GameObject *gameobj; - if (!ConvertPythonToGameObject(actuator->GetLogicManager(), value, &gameobj, true, "actuator.object = value: KX_ParentActuator")) + if (!ConvertPythonToGameObject(actuator->GetLogicManager(), value, &gameobj, true, "actuator.object = value: KX_ParentActuator")) { return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error - if (actuator->m_ob != NULL) + } + if (actuator->m_ob != nullptr) { actuator->m_ob->UnregisterActuator(actuator); + } - actuator->m_ob = (SCA_IObject*) gameobj; + actuator->m_ob = (SCA_IObject *)gameobj; - if (actuator->m_ob) + if (actuator->m_ob) { actuator->m_ob->RegisterActuator(actuator); + } return PY_SET_ATTR_SUCCESS; } diff --git a/source/gameengine/Ketsji/KX_ParentActuator.h b/source/gameengine/Ketsji/KX_ParentActuator.h index ebb7ab594608..5db999aafa17 100644 --- a/source/gameengine/Ketsji/KX_ParentActuator.h +++ b/source/gameengine/Ketsji/KX_ParentActuator.h @@ -39,17 +39,17 @@ class KX_ParentActuator : public SCA_IActuator { Py_Header - + /** Mode */ int m_mode; - + /** option */ bool m_addToCompound; bool m_ghost; /** Object to set as parent */ SCA_IObject *m_ob; - - + + public: enum KX_PARENTACT_MODE @@ -68,12 +68,12 @@ class KX_ParentActuator : public SCA_IActuator SCA_IObject *ob); virtual ~KX_ParentActuator(); virtual bool Update(); - - virtual CValue* GetReplica(); + + virtual EXP_Value* GetReplica(); virtual void ProcessReplica(); - virtual void Relink(CTR_Map *obj_map); + virtual void Relink(std::map& obj_map); virtual bool UnlinkObject(SCA_IObject* clientobj); - + #ifdef WITH_PYTHON /* --------------------------------------------------------------------- */ @@ -81,9 +81,9 @@ class KX_ParentActuator : public SCA_IActuator /* --------------------------------------------------------------------- */ /* These are used to get and set m_ob */ - static PyObject *pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - + static PyObject *pyattr_get_object(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_object(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + #endif /* WITH_PYTHON */ }; /* end of class KX_ParentActuator : public SCA_PropertyActuator */ diff --git a/source/gameengine/Ketsji/KX_PlanarMap.cpp b/source/gameengine/Ketsji/KX_PlanarMap.cpp new file mode 100644 index 000000000000..623111191d4d --- /dev/null +++ b/source/gameengine/Ketsji/KX_PlanarMap.cpp @@ -0,0 +1,278 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Ulysse Martin, Tristan Porteries, Martins Upitis. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file KX_PlanarMap.cpp + * \ingroup ketsji + */ + +#include "KX_PlanarMap.h" +#include "KX_Camera.h" +#include "KX_PyMath.h" + +#include "RAS_Rasterizer.h" +#include "RAS_Texture.h" + +KX_PlanarMap::KX_PlanarMap(EnvMap *env, KX_GameObject *viewpoint) + :KX_TextureRenderer(env, viewpoint), + m_normal(mt::axisZ3) +{ + m_faces.emplace_back(RAS_Texture::GetTexture2DType()); + + switch (env->mode) { + case ENVMAP_REFLECTION: + { + m_type = REFLECTION; + break; + } + case ENVMAP_REFRACTION: + { + m_type = REFRACTION; + break; + } + } +} + +KX_PlanarMap::~KX_PlanarMap() +{ +} + +std::string KX_PlanarMap::GetName() +{ + return "KX_PlanarMap"; +} + +void KX_PlanarMap::ComputeClipPlane(const mt::vec3& mirrorObjWorldPos, const mt::mat3& mirrorObjWorldOri) +{ + const mt::vec3 normal = mirrorObjWorldOri * m_normal; + + m_clipPlane.x = normal.x; + m_clipPlane.y = normal.y; + m_clipPlane.z = normal.z; + m_clipPlane.w = -(m_clipPlane.x * mirrorObjWorldPos.x + + m_clipPlane.y * mirrorObjWorldPos.y + + m_clipPlane.z * mirrorObjWorldPos.z); +} + +void KX_PlanarMap::InvalidateProjectionMatrix() +{ + m_projections.clear(); +} + +const mt::mat4& KX_PlanarMap::GetProjectionMatrix(RAS_Rasterizer *rasty, KX_Scene *scene, KX_Camera *sceneCamera, + const RAS_Rect& viewport, const RAS_Rect& area) +{ + std::unordered_map::const_iterator projectionit = m_projections.find(sceneCamera); + if (projectionit != m_projections.end()) { + return projectionit->second; + } + + mt::mat4& projection = m_projections[sceneCamera]; + + RAS_FrameFrustum frustum; + const bool orthographic = !sceneCamera->GetCameraData()->m_perspective; + + if (orthographic) { + RAS_FramingManager::ComputeOrtho( + scene->GetFramingType(), + area, + viewport, + sceneCamera->GetScale(), + m_clipStart, + m_clipEnd, + sceneCamera->GetSensorFit(), + sceneCamera->GetShiftHorizontal(), + sceneCamera->GetShiftVertical(), + frustum); + } + else { + RAS_FramingManager::ComputeFrustum( + scene->GetFramingType(), + area, + viewport, + sceneCamera->GetLens(), + sceneCamera->GetSensorWidth(), + sceneCamera->GetSensorHeight(), + sceneCamera->GetSensorFit(), + sceneCamera->GetShiftHorizontal(), + sceneCamera->GetShiftVertical(), + m_clipStart, + m_clipEnd, + frustum); + } + + if (!sceneCamera->GetViewport()) { + const float camzoom = sceneCamera->GetZoom(); + frustum.x1 *= camzoom; + frustum.x2 *= camzoom; + frustum.y1 *= camzoom; + frustum.y2 *= camzoom; + } + + if (orthographic) { + projection = rasty->GetOrthoMatrix( + frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar); + } + else { + projection = rasty->GetFrustumMatrix(frustum.x1, frustum.x2, frustum.y1, frustum.y2, frustum.camnear, frustum.camfar); + } + + return projection; +} + +void KX_PlanarMap::BeginRenderFace(RAS_Rasterizer *rasty) +{ + KX_TextureRenderer::BeginRenderFace(rasty); + + if (m_type == REFLECTION) { + rasty->SetInvertFrontFace(true); + rasty->EnableClipPlane(0, m_clipPlane); + } + else { + rasty->EnableClipPlane(0, -m_clipPlane); + } +} + +void KX_PlanarMap::EndRenderFace(RAS_Rasterizer *rasty) +{ + if (m_type == REFLECTION) { + rasty->SetInvertFrontFace(false); + } + rasty->DisableClipPlane(0); + + KX_TextureRenderer::EndRenderFace(rasty); +} + +const mt::vec3& KX_PlanarMap::GetNormal() const +{ + return m_normal; +} + +void KX_PlanarMap::SetNormal(const mt::vec3& normal) +{ + m_normal = normal.Normalized(); +} + +bool KX_PlanarMap::SetupCamera(KX_Camera *sceneCamera, KX_Camera *camera) +{ + KX_GameObject *mirror = GetViewpointObject(); + + // Compute camera position and orientation. + const mt::mat3& mirrorObjWorldOri = mirror->NodeGetWorldOrientation(); + const mt::vec3& mirrorObjWorldPos = mirror->NodeGetWorldPosition(); + + mt::vec3 cameraWorldPos = sceneCamera->NodeGetWorldPosition(); + + // Update clip plane to possible new normal or viewpoint object. + ComputeClipPlane(mirrorObjWorldPos, mirrorObjWorldOri); + + const float d = m_clipPlane.x * cameraWorldPos.x + + m_clipPlane.y * cameraWorldPos.y + + m_clipPlane.z * cameraWorldPos.z + + m_clipPlane.w; + + // Check if the scene camera is in the right plane side. + if (d < 0.0) { + return false; + } + + const mt::mat3 mirrorObjWorldOriInverse = mirrorObjWorldOri.Inverse(); + mt::mat3 cameraWorldOri = sceneCamera->NodeGetWorldOrientation(); + + static const mt::mat3 unmir(1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, -1.0f); + + if (m_type == REFLECTION) { + // Get vector from mirror to camera in mirror space. + cameraWorldPos = (cameraWorldPos - mirrorObjWorldPos) * mirrorObjWorldOri; + + cameraWorldPos = mirrorObjWorldPos + cameraWorldPos * unmir * mirrorObjWorldOriInverse; + cameraWorldOri = cameraWorldOri.Transpose() * mirrorObjWorldOri * unmir * mirrorObjWorldOriInverse; + cameraWorldOri = cameraWorldOri.Transpose(); + } + + // Set render camera position and orientation. + camera->NodeSetWorldPosition(cameraWorldPos); + camera->NodeSetGlobalOrientation(cameraWorldOri); + + return true; +} + +bool KX_PlanarMap::SetupCameraFace(KX_Camera *camera, unsigned short index) +{ + return true; +} + +#ifdef WITH_PYTHON + +PyTypeObject KX_PlanarMap::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_PlanarMap", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &KX_TextureRenderer::Type, + 0, 0, 0, 0, 0, 0, + py_base_new +}; + +PyMethodDef KX_PlanarMap::Methods[] = { + {nullptr, nullptr} // Sentinel +}; + +PyAttributeDef KX_PlanarMap::Attributes[] = { + EXP_PYATTRIBUTE_RW_FUNCTION("normal", KX_PlanarMap, pyattr_get_normal, pyattr_set_normal), + EXP_PYATTRIBUTE_NULL // Sentinel +}; + +PyObject *KX_PlanarMap::pyattr_get_normal(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_PlanarMap *self = static_cast(self_v); + return PyObjectFrom(self->GetNormal()); +} + +int KX_PlanarMap::pyattr_set_normal(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_PlanarMap *self = static_cast(self_v); + + mt::vec3 normal; + if (!PyVecTo(value, normal)) { + return PY_SET_ATTR_FAIL; + } + + self->SetNormal(normal); + + return PY_SET_ATTR_SUCCESS; +} + +#endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_PlanarMap.h b/source/gameengine/Ketsji/KX_PlanarMap.h new file mode 100644 index 000000000000..19df7cbbd43a --- /dev/null +++ b/source/gameengine/Ketsji/KX_PlanarMap.h @@ -0,0 +1,78 @@ +/* +* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* Contributor(s): Ulysse Martin, Tristan Porteries, Martins Upitis. +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +/** \file KX_PlanarMap.h +* \ingroup ketsji +*/ + +#ifndef __KX_PLANAR_H__ +#define __KX_PLANAR_H__ + +#include "KX_TextureRenderer.h" + +#include + +class KX_PlanarMap : public KX_TextureRenderer, public mt::SimdClassAllocator +{ + Py_Header + +private: + /// Mirror normal vector. + mt::vec3 m_normal; + /// Clip plane equation values. + mt::vec4 m_clipPlane; + + std::unordered_map m_projections; + + enum Type { + REFLECTION, + REFRACTION + } m_type; + +public: + KX_PlanarMap(EnvMap *env, KX_GameObject *viewpoint); + virtual ~KX_PlanarMap(); + + virtual std::string GetName(); + + void ComputeClipPlane(const mt::vec3& mirrorObjWorldPos, const mt::mat3& mirrorObjWorldOri); + + virtual void InvalidateProjectionMatrix(); + virtual const mt::mat4& GetProjectionMatrix(RAS_Rasterizer *rasty, KX_Scene *scene, KX_Camera *sceneCamera, + const RAS_Rect& viewport, const RAS_Rect& area); + + virtual void BeginRenderFace(RAS_Rasterizer *rasty) override; + virtual void EndRenderFace(RAS_Rasterizer *rasty) override; + + const mt::vec3& GetNormal() const; + void SetNormal(const mt::vec3& normal); + + virtual bool SetupCamera(KX_Camera *sceneCamera, KX_Camera *camera); + virtual bool SetupCameraFace(KX_Camera *camera, unsigned short index); + +#ifdef WITH_PYTHON + static PyObject *pyattr_get_normal(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_normal(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); +#endif // WITH_PYTHON +}; + +#endif // __KX_PLANAR_H__ diff --git a/source/gameengine/Ketsji/KX_PolyProxy.cpp b/source/gameengine/Ketsji/KX_PolyProxy.cpp index 4454543161b3..a46bfb40a56e 100644 --- a/source/gameengine/Ketsji/KX_PolyProxy.cpp +++ b/source/gameengine/Ketsji/KX_PolyProxy.cpp @@ -33,17 +33,20 @@ #ifdef WITH_PYTHON #include "KX_PolyProxy.h" -#include "KX_MeshProxy.h" -#include "RAS_MeshObject.h" -#include "RAS_Polygon.h" +#include "KX_Mesh.h" +#include "RAS_Mesh.h" +#include "RAS_MaterialBucket.h" +#include "RAS_DisplayArray.h" +#include "KX_VertexProxy.h" #include "KX_BlenderMaterial.h" +#include "EXP_ListWrapper.h" #include "KX_PyMath.h" PyTypeObject KX_PolyProxy::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_PolyProxy", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -51,47 +54,48 @@ PyTypeObject KX_PolyProxy::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, - &CValue::Type, - 0,0,0,0,0,0, + &EXP_Value::Type, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_PolyProxy::Methods[] = { - KX_PYMETHODTABLE_NOARGS(KX_PolyProxy,getMaterialIndex), - KX_PYMETHODTABLE_NOARGS(KX_PolyProxy,getNumVertex), - KX_PYMETHODTABLE_NOARGS(KX_PolyProxy,isVisible), - KX_PYMETHODTABLE_NOARGS(KX_PolyProxy,isCollider), - KX_PYMETHODTABLE_NOARGS(KX_PolyProxy,getMaterialName), - KX_PYMETHODTABLE_NOARGS(KX_PolyProxy,getTextureName), - KX_PYMETHODTABLE(KX_PolyProxy,getVertexIndex), - KX_PYMETHODTABLE_NOARGS(KX_PolyProxy,getMesh), - KX_PYMETHODTABLE_NOARGS(KX_PolyProxy,getMaterial), - {NULL,NULL} //Sentinel + EXP_PYMETHODTABLE_NOARGS(KX_PolyProxy, getMaterialIndex), + EXP_PYMETHODTABLE_NOARGS(KX_PolyProxy, getNumVertex), + EXP_PYMETHODTABLE_NOARGS(KX_PolyProxy, isVisible), + EXP_PYMETHODTABLE_NOARGS(KX_PolyProxy, isCollider), + EXP_PYMETHODTABLE_NOARGS(KX_PolyProxy, getMaterialName), + EXP_PYMETHODTABLE_NOARGS(KX_PolyProxy, getTextureName), + EXP_PYMETHODTABLE(KX_PolyProxy, getVertexIndex), + EXP_PYMETHODTABLE_NOARGS(KX_PolyProxy, getMesh), + EXP_PYMETHODTABLE_NOARGS(KX_PolyProxy, getMaterial), + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_PolyProxy::Attributes[] = { - KX_PYATTRIBUTE_RO_FUNCTION("material_name", KX_PolyProxy, pyattr_get_material_name), - KX_PYATTRIBUTE_RO_FUNCTION("texture_name", KX_PolyProxy, pyattr_get_texture_name), - KX_PYATTRIBUTE_RO_FUNCTION("material", KX_PolyProxy, pyattr_get_material), - KX_PYATTRIBUTE_RO_FUNCTION("material_id", KX_PolyProxy, pyattr_get_material_id), - KX_PYATTRIBUTE_RO_FUNCTION("v1", KX_PolyProxy, pyattr_get_v1), - KX_PYATTRIBUTE_RO_FUNCTION("v2", KX_PolyProxy, pyattr_get_v2), - KX_PYATTRIBUTE_RO_FUNCTION("v3", KX_PolyProxy, pyattr_get_v3), - KX_PYATTRIBUTE_RO_FUNCTION("v4", KX_PolyProxy, pyattr_get_v4), - KX_PYATTRIBUTE_RO_FUNCTION("visible", KX_PolyProxy, pyattr_get_visible), - KX_PYATTRIBUTE_RO_FUNCTION("collide", KX_PolyProxy, pyattr_get_collide), - { NULL } //Sentinel + EXP_PYATTRIBUTE_RO_FUNCTION("material_name", KX_PolyProxy, pyattr_get_material_name), + EXP_PYATTRIBUTE_RO_FUNCTION("texture_name", KX_PolyProxy, pyattr_get_texture_name), + EXP_PYATTRIBUTE_RO_FUNCTION("material", KX_PolyProxy, pyattr_get_material), + EXP_PYATTRIBUTE_RO_FUNCTION("material_id", KX_PolyProxy, pyattr_get_material_id), + EXP_PYATTRIBUTE_RO_FUNCTION("v1", KX_PolyProxy, pyattr_get_v1), + EXP_PYATTRIBUTE_RO_FUNCTION("v2", KX_PolyProxy, pyattr_get_v2), + EXP_PYATTRIBUTE_RO_FUNCTION("v3", KX_PolyProxy, pyattr_get_v3), + EXP_PYATTRIBUTE_RO_FUNCTION("v4", KX_PolyProxy, pyattr_get_v4), + EXP_PYATTRIBUTE_RO_FUNCTION("visible", KX_PolyProxy, pyattr_get_visible), + EXP_PYATTRIBUTE_RO_FUNCTION("collide", KX_PolyProxy, pyattr_get_collide), + EXP_PYATTRIBUTE_RO_FUNCTION("vertices", KX_PolyProxy, pyattr_get_vertices), + EXP_PYATTRIBUTE_NULL //Sentinel }; -KX_PolyProxy::KX_PolyProxy(const RAS_MeshObject*mesh, RAS_Polygon* polygon) -: m_polygon(polygon), - m_mesh((RAS_MeshObject*)mesh) +KX_PolyProxy::KX_PolyProxy(KX_Mesh *mesh, const RAS_Mesh::PolygonInfo& polygon) + :m_mesh(mesh), + m_polygon(polygon) { } @@ -101,165 +105,163 @@ KX_PolyProxy::~KX_PolyProxy() // stuff for cvalue related things -CValue* KX_PolyProxy::Calc(VALUE_OPERATOR, CValue *) { return NULL;} -CValue* KX_PolyProxy::CalcFinal(VALUE_DATA_TYPE, VALUE_OPERATOR, CValue *) { return NULL;} -static STR_String sPolyName = "polygone"; -const STR_String & KX_PolyProxy::GetText() {return sPolyName;}; -double KX_PolyProxy::GetNumber() { return -1;} -STR_String& KX_PolyProxy::GetName() { return sPolyName;} -void KX_PolyProxy::SetName(const char *) { }; -CValue* KX_PolyProxy::GetReplica() { return NULL;} +std::string KX_PolyProxy::GetName() +{ + return "polygone"; +} + +const RAS_Mesh::PolygonInfo& KX_PolyProxy::GetPolygon() const +{ + return m_polygon; +} // stuff for python integration -PyObject *KX_PolyProxy::pyattr_get_material_name(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_PolyProxy::pyattr_get_material_name(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_PolyProxy* self = static_cast(self_v); + KX_PolyProxy *self = static_cast(self_v); return self->PygetMaterialName(); } -PyObject *KX_PolyProxy::pyattr_get_texture_name(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_PolyProxy::pyattr_get_texture_name(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_PolyProxy* self = static_cast(self_v); + KX_PolyProxy *self = static_cast(self_v); return self->PygetTextureName(); } -PyObject *KX_PolyProxy::pyattr_get_material(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_PolyProxy::pyattr_get_material(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_PolyProxy* self = static_cast(self_v); + KX_PolyProxy *self = static_cast(self_v); return self->PygetMaterial(); } -PyObject *KX_PolyProxy::pyattr_get_material_id(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_PolyProxy::pyattr_get_material_id(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_PolyProxy* self = static_cast(self_v); + KX_PolyProxy *self = static_cast(self_v); return self->PygetMaterialIndex(); } -PyObject *KX_PolyProxy::pyattr_get_v1(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_PolyProxy::pyattr_get_v1(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_PolyProxy* self = static_cast(self_v); + KX_PolyProxy *self = static_cast(self_v); - return PyLong_FromLong(self->m_polygon->GetVertexOffsetAbsolute(0)); + return PyLong_FromLong(self->m_polygon.indices[0]); } -PyObject *KX_PolyProxy::pyattr_get_v2(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_PolyProxy::pyattr_get_v2(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_PolyProxy* self = static_cast(self_v); + KX_PolyProxy *self = static_cast(self_v); - return PyLong_FromLong(self->m_polygon->GetVertexOffsetAbsolute(1)); + return PyLong_FromLong(self->m_polygon.indices[1]); } -PyObject *KX_PolyProxy::pyattr_get_v3(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_PolyProxy::pyattr_get_v3(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_PolyProxy* self = static_cast(self_v); + KX_PolyProxy *self = static_cast(self_v); - return PyLong_FromLong(self->m_polygon->GetVertexOffsetAbsolute(2)); + return PyLong_FromLong(self->m_polygon.indices[2]); } -PyObject *KX_PolyProxy::pyattr_get_v4(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_PolyProxy::pyattr_get_v4(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_PolyProxy* self = static_cast(self_v); - - if (3 < self->m_polygon->VertexCount()) - { - return PyLong_FromLong(self->m_polygon->GetVertexOffsetAbsolute(3)); - } return PyLong_FromLong(0); } -PyObject *KX_PolyProxy::pyattr_get_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_PolyProxy::pyattr_get_visible(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_PolyProxy* self = static_cast(self_v); + KX_PolyProxy *self = static_cast(self_v); return self->PyisVisible(); } -PyObject *KX_PolyProxy::pyattr_get_collide(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_PolyProxy::pyattr_get_collide(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_PolyProxy* self = static_cast(self_v); + KX_PolyProxy *self = static_cast(self_v); return self->PyisCollider(); } -KX_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, getMaterialIndex, -"getMaterialIndex() : return the material index of the polygon in the mesh\n") +unsigned int KX_PolyProxy::py_get_vertices_size() { - RAS_MaterialBucket* polyBucket = m_polygon->GetMaterial(); - unsigned int matid; - for (matid=0; matid<(unsigned int)m_mesh->NumMaterials(); matid++) - { - RAS_MeshMaterial* meshMat = m_mesh->GetMeshMaterial(matid); - if (meshMat->m_bucket == polyBucket) - // found it - break; - } - return PyLong_FromLong(matid); + return 3; +} + +PyObject *KX_PolyProxy::py_get_vertices_item(unsigned int index) +{ + KX_VertexProxy *vert = new KX_VertexProxy(m_polygon.array, m_polygon.indices[index]); + + return vert->NewProxy(true); +} + +PyObject *KX_PolyProxy::pyattr_get_vertices(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + return (new EXP_ListWrapper(self_v))->NewProxy(true); +} + +EXP_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, getMaterialIndex, + "getMaterialIndex() : return the material index of the polygon in the mesh\n") +{ + return PyLong_FromLong(m_polygon.matId); } -KX_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, getNumVertex, -"getNumVertex() : returns the number of vertex of the polygon, 3 or 4\n") +EXP_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, getNumVertex, + "getNumVertex() : returns the number of vertex of the polygon\n") { - return PyLong_FromLong(m_polygon->VertexCount()); + return PyLong_FromLong(3); } -KX_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, isVisible, -"isVisible() : returns whether the polygon is visible or not\n") +EXP_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, isVisible, + "isVisible() : returns whether the polygon is visible or not\n") { - return PyLong_FromLong(m_polygon->IsVisible()); + return PyLong_FromLong(m_polygon.flags & RAS_Mesh::PolygonInfo::VISIBLE); } -KX_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, isCollider, -"isCollider() : returns whether the polygon is receives collision or not\n") +EXP_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, isCollider, + "isCollider() : returns whether the polygon is receives collision or not\n") { - return PyLong_FromLong(m_polygon->IsCollider()); + return PyLong_FromLong(m_polygon.flags & RAS_Mesh::PolygonInfo::COLLIDER); } -KX_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, getMaterialName, -"getMaterialName() : returns the polygon material name, \"NoMaterial\" if no material\n") +EXP_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, getMaterialName, + "getMaterialName() : returns the polygon material name, \"\" if no material\n") { - return PyUnicode_From_STR_String(m_polygon->GetMaterial()->GetPolyMaterial()->GetMaterialName()); + return PyUnicode_FromStdString(m_mesh->GetMaterialName(m_polygon.matId)); } -KX_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, getTextureName, -"getTexturelName() : returns the polygon texture name, \"NULL\" if no texture\n") +EXP_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, getTextureName, + "getTexturelName() : returns the polygon texture name, \"\" if no texture\n") { - return PyUnicode_From_STR_String(m_polygon->GetMaterial()->GetPolyMaterial()->GetTextureName()); + return PyUnicode_FromStdString(m_mesh->GetTextureName(m_polygon.matId)); } -KX_PYMETHODDEF_DOC(KX_PolyProxy, getVertexIndex, -"getVertexIndex(vertex) : returns the mesh vertex index of a polygon vertex\n" -"vertex: index of the vertex in the polygon: 0->3\n" -"return value can be used to retrieve the vertex details through mesh proxy\n" -"Note: getVertexIndex(3) on a triangle polygon returns 0\n") +EXP_PYMETHODDEF_DOC(KX_PolyProxy, getVertexIndex, + "getVertexIndex(vertex) : returns the mesh vertex index of a polygon vertex\n" + "vertex: index of the vertex in the polygon: 0->2\n" + "return value can be used to retrieve the vertex details through mesh proxy\n") { int index; - if (!PyArg_ParseTuple(args,"i:getVertexIndex",&index)) - { - return NULL; + if (!PyArg_ParseTuple(args, "i:getVertexIndex", &index)) { + return nullptr; } - if (index < 0 || index > 3) - { - PyErr_SetString(PyExc_AttributeError, "poly.getVertexIndex(int): KX_PolyProxy, expected an index between 0-3"); - return NULL; + if (index < 0 || index > 3) { + PyErr_SetString(PyExc_AttributeError, "poly.getVertexIndex(int): KX_PolyProxy, expected an index between 0-2"); + return nullptr; } - if (index < m_polygon->VertexCount()) - { - return PyLong_FromLong(m_polygon->GetVertexOffsetAbsolute(index)); + if (index < 3) { + return PyLong_FromLong(m_polygon.indices[index]); } return PyLong_FromLong(0); } -KX_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, getMesh, -"getMesh() : returns a mesh proxy\n") +EXP_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, getMesh, + "getMesh() : returns a mesh proxy\n") { - KX_MeshProxy* meshproxy = new KX_MeshProxy((RAS_MeshObject*)m_mesh); - return meshproxy->NewProxy(true); + return m_mesh->GetProxy(); } -KX_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, getMaterial, -"getMaterial() : returns a material\n") +EXP_PYMETHODDEF_DOC_NOARGS(KX_PolyProxy, getMaterial, + "getMaterial() : returns a material\n") { - RAS_IPolyMaterial *polymat = m_polygon->GetMaterial()->GetPolyMaterial(); - KX_BlenderMaterial* mat = static_cast(polymat); + RAS_MeshMaterial *meshmat = m_mesh->GetMeshMaterial(m_polygon.matId); + KX_BlenderMaterial *mat = static_cast(meshmat->GetBucket()->GetMaterial()); return mat->GetProxy(); } diff --git a/source/gameengine/Ketsji/KX_PolyProxy.h b/source/gameengine/Ketsji/KX_PolyProxy.h index 837e7f8354c0..685a7dff5702 100644 --- a/source/gameengine/Ketsji/KX_PolyProxy.h +++ b/source/gameengine/Ketsji/KX_PolyProxy.h @@ -34,49 +34,52 @@ #ifdef WITH_PYTHON -#include "SCA_IObject.h" +#include "EXP_Value.h" +#include "RAS_Mesh.h" -class KX_PolyProxy : public CValue +class KX_Mesh; + +class KX_PolyProxy : public EXP_Value { Py_Header protected: - class RAS_Polygon* m_polygon; - class RAS_MeshObject* m_mesh; + KX_Mesh *m_mesh; + RAS_Mesh::PolygonInfo m_polygon; + public: - KX_PolyProxy(const class RAS_MeshObject*mesh, class RAS_Polygon* polygon); + KX_PolyProxy(KX_Mesh *mesh, const RAS_Mesh::PolygonInfo& polygon); virtual ~KX_PolyProxy(); // stuff for cvalue related things - CValue* Calc(VALUE_OPERATOR op, CValue *val); - CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); - const STR_String & GetText(); - double GetNumber(); - STR_String& GetName(); - void SetName(const char *name); // Set the name of the value - CValue* GetReplica(); + virtual std::string GetName(); + + const RAS_Mesh::PolygonInfo& GetPolygon() const; + // stuff for python integration + static PyObject *pyattr_get_material_name(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_texture_name(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_material(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_material_id(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_v1(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_v2(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_v3(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_v4(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_visible(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_collide(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_vertices(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); -// stuff for python integration - static PyObject *pyattr_get_material_name(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_texture_name(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_material(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_material_id(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_v1(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_v2(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_v3(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_v4(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_collide(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + unsigned int py_get_vertices_size(); + PyObject *py_get_vertices_item(unsigned int index); - KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMaterialIndex) - KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getNumVertex) - KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,isVisible) - KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,isCollider) - KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMaterialName) - KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getTextureName) - KX_PYMETHOD_DOC(KX_PolyProxy,getVertexIndex) - KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMesh) - KX_PYMETHOD_DOC_NOARGS(KX_PolyProxy,getMaterial) + EXP_PYMETHOD_DOC_NOARGS(KX_PolyProxy, getMaterialIndex) + EXP_PYMETHOD_DOC_NOARGS(KX_PolyProxy, getNumVertex) + EXP_PYMETHOD_DOC_NOARGS(KX_PolyProxy, isVisible) + EXP_PYMETHOD_DOC_NOARGS(KX_PolyProxy, isCollider) + EXP_PYMETHOD_DOC_NOARGS(KX_PolyProxy, getMaterialName) + EXP_PYMETHOD_DOC_NOARGS(KX_PolyProxy, getTextureName) + EXP_PYMETHOD_DOC(KX_PolyProxy, getVertexIndex) + EXP_PYMETHOD_DOC_NOARGS(KX_PolyProxy, getMesh) + EXP_PYMETHOD_DOC_NOARGS(KX_PolyProxy, getMaterial) }; diff --git a/source/gameengine/Ketsji/KX_PositionInterpolator.cpp b/source/gameengine/Ketsji/KX_PositionInterpolator.cpp deleted file mode 100644 index 1e217ecf6163..000000000000 --- a/source/gameengine/Ketsji/KX_PositionInterpolator.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Ketsji/KX_PositionInterpolator.cpp - * \ingroup ketsji - */ - - -#include "KX_PositionInterpolator.h" -#include "MT_Point3.h" -#include "KX_IScalarInterpolator.h" - -void KX_PositionInterpolator::Execute(float currentTime) const -{ - m_target.setValue(m_ipos[0]->GetValue(currentTime), - m_ipos[1]->GetValue(currentTime), - m_ipos[2]->GetValue(currentTime)); -} diff --git a/source/gameengine/Ketsji/KX_PositionInterpolator.h b/source/gameengine/Ketsji/KX_PositionInterpolator.h deleted file mode 100644 index 86601ab3d4b0..000000000000 --- a/source/gameengine/Ketsji/KX_PositionInterpolator.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file KX_PositionInterpolator.h - * \ingroup ketsji - */ - -#ifndef __KX_POSITIONINTERPOLATOR_H__ -#define __KX_POSITIONINTERPOLATOR_H__ - -#include "KX_IInterpolator.h" - -class MT_Point3; -class KX_IScalarInterpolator; - -class KX_PositionInterpolator : public KX_IInterpolator { -public: - KX_PositionInterpolator(MT_Point3& target, - KX_IScalarInterpolator *ipos[]) : - m_target(target) - { - m_ipos[0] = ipos[0]; - m_ipos[1] = ipos[1]; - m_ipos[2] = ipos[2]; - } - - virtual void Execute(float currentTime) const; - -private: - MT_Point3& m_target; - KX_IScalarInterpolator *m_ipos[3]; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_PositionInterpolator") -#endif -}; - -#endif diff --git a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp index 25ffa3fe8b07..a0a78475583e 100644 --- a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp +++ b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp @@ -37,10 +37,9 @@ #include "PHY_IPhysicsController.h" #include "PHY_IVehicle.h" #include "PHY_DynamicTypes.h" -#include "MT_Matrix3x3.h" #include "KX_GameObject.h" // ConvertPythonToGameObject() -#include "KX_PythonInit.h" +#include "KX_Globals.h" #include "EXP_PyObjectPlus.h" @@ -51,101 +50,101 @@ #ifdef WITH_PYTHON // macro copied from KX_PythonInit.cpp -#define KX_MACRO_addTypesToDict(dict, name, name2) PyDict_SetItemString(dict, #name, item=PyLong_FromLong(name2)); Py_DECREF(item) - -// nasty glob variable to connect scripting language -// if there is a better way (without global), please do so! -static PHY_IPhysicsEnvironment* g_CurrentActivePhysicsEnvironment = NULL; +#define KX_MACRO_addTypesToDict(dict, name, name2) PyDict_SetItemString(dict, #name, item = PyLong_FromLong(name2)); Py_DECREF(item) PyDoc_STRVAR(PhysicsConstraints_module_documentation, -"This is the Python API for the Physics Constraints" -); + "This is the Python API for the Physics Constraints" + ); PyDoc_STRVAR(gPySetGravity__doc__, -"setGravity(float x,float y,float z)\n" -"" -); + "setGravity(float x,float y,float z)\n" + "" + ); PyDoc_STRVAR(gPySetDebugMode__doc__, -"setDebugMode(int mode)\n" -"" -); + "setDebugMode(int mode)\n" + "" + ); PyDoc_STRVAR(gPySetNumIterations__doc__, -"setNumIterations(int numiter)\n" -"This sets the number of iterations for an iterative constraint solver" -); + "setNumIterations(int numiter)\n" + "This sets the number of iterations for an iterative constraint solver" + ); PyDoc_STRVAR(gPySetNumTimeSubSteps__doc__, -"setNumTimeSubSteps(int numsubstep)\n" -"This sets the number of substeps for each physics proceed. Tradeoff quality for performance." -); + "setNumTimeSubSteps(int numsubstep)\n" + "This sets the number of substeps for each physics proceed. Tradeoff quality for performance." + ); PyDoc_STRVAR(gPySetDeactivationTime__doc__, -"setDeactivationTime(float time)\n" -"This sets the time after which a resting rigidbody gets deactived" -); + "setDeactivationTime(float time)\n" + "This sets the time after which a resting rigidbody gets deactived" + ); PyDoc_STRVAR(gPySetDeactivationLinearTreshold__doc__, -"setDeactivationLinearTreshold(float linearTreshold)\n" -"" -); + "setDeactivationLinearTreshold(float linearTreshold)\n" + "" + ); PyDoc_STRVAR(gPySetDeactivationAngularTreshold__doc__, -"setDeactivationAngularTreshold(float angularTreshold)\n" -"" -); + "setDeactivationAngularTreshold(float angularTreshold)\n" + "" + ); PyDoc_STRVAR(gPySetContactBreakingTreshold__doc__, -"setContactBreakingTreshold(float breakingTreshold)\n" -"Reasonable default is 0.02 (if units are meters)" -); + "setContactBreakingTreshold(float breakingTreshold)\n" + "Reasonable default is 0.02 (if units are meters)" + ); PyDoc_STRVAR(gPySetCcdMode__doc__, -"setCcdMode(int ccdMode)\n" -"Very experimental, not recommended" -); + "setCcdMode(int ccdMode)\n" + "Very experimental, not recommended" + ); PyDoc_STRVAR(gPySetSorConstant__doc__, -"setSorConstant(float sor)\n" -"Very experimental, not recommended" -); + "setSorConstant(float sor)\n" + "Very experimental, not recommended" + ); PyDoc_STRVAR(gPySetSolverTau__doc__, -"setTau(float tau)\n" -"Very experimental, not recommended" -); + "setTau(float tau)\n" + "Very experimental, not recommended" + ); PyDoc_STRVAR(gPySetSolverDamping__doc__, -"setDamping(float damping)\n" -"Very experimental, not recommended" -); + "setDamping(float damping)\n" + "Very experimental, not recommended" + ); PyDoc_STRVAR(gPySetLinearAirDamping__doc__, -"setLinearAirDamping(float damping)\n" -"Very experimental, not recommended" -); + "setLinearAirDamping(float damping)\n" + "Very experimental, not recommended" + ); PyDoc_STRVAR(gPySetUseEpa__doc__, -"setUseEpa(int epa)\n" -"Very experimental, not recommended" -); + "setUseEpa(int epa)\n" + "Very experimental, not recommended" + ); PyDoc_STRVAR(gPySetSolverType__doc__, -"setSolverType(int solverType)\n" -"Very experimental, not recommended" -); + "setSolverType(int solverType)\n" + "Very experimental, not recommended" + ); PyDoc_STRVAR(gPyCreateConstraint__doc__, -"createConstraint(ob1,ob2,float restLength,float restitution,float damping)\n" -"" -); + "createConstraint(ob1,ob2,float restLength,float restitution,float damping)\n" + "" + ); +PyDoc_STRVAR(gPyCreateVehicle__doc__, + "createVehicle(chassis)\n" + "" + ); PyDoc_STRVAR(gPyGetVehicleConstraint__doc__, -"getVehicleConstraint(int constraintId)\n" -"" -); + "getVehicleConstraint(int constraintId)\n" + "" + ); PyDoc_STRVAR(gPyGetCharacter__doc__, -"getCharacter(KX_GameObject obj)\n" -"" -); + "getCharacter(KX_GameObject obj)\n" + "" + ); PyDoc_STRVAR(gPyRemoveConstraint__doc__, -"removeConstraint(int constraintId)\n" -"" -); + "removeConstraint(int constraintId)\n" + "" + ); PyDoc_STRVAR(gPyGetAppliedImpulse__doc__, -"getAppliedImpulse(int constraintId)\n" -"" -); + "getAppliedImpulse(int constraintId)\n" + "" + ); @@ -154,14 +153,14 @@ static PyObject *gPySetGravity(PyObject *self, PyObject *args, PyObject *kwds) { - float x,y,z; - if (PyArg_ParseTuple(args,"fff",&x,&y,&z)) - { - if (PHY_GetActiveEnvironment()) - PHY_GetActiveEnvironment()->SetGravity(x,y,z); + float x, y, z; + if (PyArg_ParseTuple(args, "fff", &x, &y, &z)) { + if (KX_GetPhysicsEnvironment()) { + KX_GetPhysicsEnvironment()->SetGravity(x, y, z); + } } else { - return NULL; + return nullptr; } Py_RETURN_NONE; @@ -172,17 +171,15 @@ static PyObject *gPySetDebugMode(PyObject *self, PyObject *kwds) { int mode; - if (PyArg_ParseTuple(args,"i",&mode)) - { - if (PHY_GetActiveEnvironment()) - { - PHY_GetActiveEnvironment()->SetDebugMode(mode); + if (PyArg_ParseTuple(args, "i", &mode)) { + if (KX_GetPhysicsEnvironment()) { + KX_GetPhysicsEnvironment()->SetDebugMode(mode); } } else { - return NULL; + return nullptr; } Py_RETURN_NONE; @@ -195,15 +192,13 @@ static PyObject *gPySetNumTimeSubSteps(PyObject *self, PyObject *kwds) { int substep; - if (PyArg_ParseTuple(args,"i",&substep)) - { - if (PHY_GetActiveEnvironment()) - { - PHY_GetActiveEnvironment()->SetNumTimeSubSteps(substep); + if (PyArg_ParseTuple(args, "i", &substep)) { + if (KX_GetPhysicsEnvironment()) { + KX_GetPhysicsEnvironment()->SetNumTimeSubSteps(substep); } } else { - return NULL; + return nullptr; } Py_RETURN_NONE; } @@ -214,15 +209,13 @@ static PyObject *gPySetNumIterations(PyObject *self, PyObject *kwds) { int iter; - if (PyArg_ParseTuple(args,"i",&iter)) - { - if (PHY_GetActiveEnvironment()) - { - PHY_GetActiveEnvironment()->SetNumIterations(iter); + if (PyArg_ParseTuple(args, "i", &iter)) { + if (KX_GetPhysicsEnvironment()) { + KX_GetPhysicsEnvironment()->SetNumIterations(iter); } } else { - return NULL; + return nullptr; } Py_RETURN_NONE; } @@ -233,15 +226,13 @@ static PyObject *gPySetDeactivationTime(PyObject *self, PyObject *kwds) { float deactive_time; - if (PyArg_ParseTuple(args,"f",&deactive_time)) - { - if (PHY_GetActiveEnvironment()) - { - PHY_GetActiveEnvironment()->SetDeactivationTime(deactive_time); + if (PyArg_ParseTuple(args, "f", &deactive_time)) { + if (KX_GetPhysicsEnvironment()) { + KX_GetPhysicsEnvironment()->SetDeactivationTime(deactive_time); } } else { - return NULL; + return nullptr; } Py_RETURN_NONE; } @@ -252,15 +243,13 @@ static PyObject *gPySetDeactivationLinearTreshold(PyObject *self, PyObject *kwds) { float linearDeactivationTreshold; - if (PyArg_ParseTuple(args,"f",&linearDeactivationTreshold)) - { - if (PHY_GetActiveEnvironment()) - { - PHY_GetActiveEnvironment()->SetDeactivationLinearTreshold( linearDeactivationTreshold); + if (PyArg_ParseTuple(args, "f", &linearDeactivationTreshold)) { + if (KX_GetPhysicsEnvironment()) { + KX_GetPhysicsEnvironment()->SetDeactivationLinearTreshold(linearDeactivationTreshold); } } else { - return NULL; + return nullptr; } Py_RETURN_NONE; } @@ -271,15 +260,13 @@ static PyObject *gPySetDeactivationAngularTreshold(PyObject *self, PyObject *kwds) { float angularDeactivationTreshold; - if (PyArg_ParseTuple(args,"f",&angularDeactivationTreshold)) - { - if (PHY_GetActiveEnvironment()) - { - PHY_GetActiveEnvironment()->SetDeactivationAngularTreshold( angularDeactivationTreshold); + if (PyArg_ParseTuple(args, "f", &angularDeactivationTreshold)) { + if (KX_GetPhysicsEnvironment()) { + KX_GetPhysicsEnvironment()->SetDeactivationAngularTreshold(angularDeactivationTreshold); } } else { - return NULL; + return nullptr; } Py_RETURN_NONE; } @@ -289,15 +276,13 @@ static PyObject *gPySetContactBreakingTreshold(PyObject *self, PyObject *kwds) { float contactBreakingTreshold; - if (PyArg_ParseTuple(args,"f",&contactBreakingTreshold)) - { - if (PHY_GetActiveEnvironment()) - { - PHY_GetActiveEnvironment()->SetContactBreakingTreshold( contactBreakingTreshold); + if (PyArg_ParseTuple(args, "f", &contactBreakingTreshold)) { + if (KX_GetPhysicsEnvironment()) { + KX_GetPhysicsEnvironment()->SetContactBreakingTreshold(contactBreakingTreshold); } } else { - return NULL; + return nullptr; } Py_RETURN_NONE; } @@ -308,15 +293,13 @@ static PyObject *gPySetCcdMode(PyObject *self, PyObject *kwds) { float ccdMode; - if (PyArg_ParseTuple(args,"f",&ccdMode)) - { - if (PHY_GetActiveEnvironment()) - { - PHY_GetActiveEnvironment()->SetCcdMode( ccdMode); + if (PyArg_ParseTuple(args, "f", &ccdMode)) { + if (KX_GetPhysicsEnvironment()) { + KX_GetPhysicsEnvironment()->SetCcdMode(ccdMode); } } else { - return NULL; + return nullptr; } Py_RETURN_NONE; } @@ -326,15 +309,13 @@ static PyObject *gPySetSorConstant(PyObject *self, PyObject *kwds) { float sor; - if (PyArg_ParseTuple(args,"f",&sor)) - { - if (PHY_GetActiveEnvironment()) - { - PHY_GetActiveEnvironment()->SetSolverSorConstant( sor); + if (PyArg_ParseTuple(args, "f", &sor)) { + if (KX_GetPhysicsEnvironment()) { + KX_GetPhysicsEnvironment()->SetSolverSorConstant(sor); } } else { - return NULL; + return nullptr; } Py_RETURN_NONE; } @@ -344,15 +325,13 @@ static PyObject *gPySetSolverTau(PyObject *self, PyObject *kwds) { float tau; - if (PyArg_ParseTuple(args,"f",&tau)) - { - if (PHY_GetActiveEnvironment()) - { - PHY_GetActiveEnvironment()->SetSolverTau( tau); + if (PyArg_ParseTuple(args, "f", &tau)) { + if (KX_GetPhysicsEnvironment()) { + KX_GetPhysicsEnvironment()->SetSolverTau(tau); } } else { - return NULL; + return nullptr; } Py_RETURN_NONE; } @@ -363,15 +342,13 @@ static PyObject *gPySetSolverDamping(PyObject *self, PyObject *kwds) { float damping; - if (PyArg_ParseTuple(args,"f",&damping)) - { - if (PHY_GetActiveEnvironment()) - { - PHY_GetActiveEnvironment()->SetSolverDamping( damping); + if (PyArg_ParseTuple(args, "f", &damping)) { + if (KX_GetPhysicsEnvironment()) { + KX_GetPhysicsEnvironment()->SetSolverDamping(damping); } } else { - return NULL; + return nullptr; } Py_RETURN_NONE; } @@ -381,15 +358,13 @@ static PyObject *gPySetLinearAirDamping(PyObject *self, PyObject *kwds) { float damping; - if (PyArg_ParseTuple(args,"f",&damping)) - { - if (PHY_GetActiveEnvironment()) - { - PHY_GetActiveEnvironment()->SetLinearAirDamping( damping); + if (PyArg_ParseTuple(args, "f", &damping)) { + if (KX_GetPhysicsEnvironment()) { + KX_GetPhysicsEnvironment()->SetLinearAirDamping(damping); } } else { - return NULL; + return nullptr; } Py_RETURN_NONE; } @@ -399,16 +374,14 @@ static PyObject *gPySetUseEpa(PyObject *self, PyObject *args, PyObject *kwds) { - int epa; - if (PyArg_ParseTuple(args,"i",&epa)) - { - if (PHY_GetActiveEnvironment()) - { - PHY_GetActiveEnvironment()->SetUseEpa(epa); + int epa; + if (PyArg_ParseTuple(args, "i", &epa)) { + if (KX_GetPhysicsEnvironment()) { + KX_GetPhysicsEnvironment()->SetUseEpa(epa); } } else { - return NULL; + return nullptr; } Py_RETURN_NONE; } @@ -416,16 +389,14 @@ static PyObject *gPySetSolverType(PyObject *self, PyObject *args, PyObject *kwds) { - int solverType; - if (PyArg_ParseTuple(args,"i",&solverType)) - { - if (PHY_GetActiveEnvironment()) - { - PHY_GetActiveEnvironment()->SetSolverType(solverType); + int solverType; + if (PyArg_ParseTuple(args, "i", &solverType)) { + if (KX_GetPhysicsEnvironment()) { + KX_GetPhysicsEnvironment()->SetSolverType((PHY_SolverType)solverType); } } else { - return NULL; + return nullptr; } Py_RETURN_NONE; } @@ -438,51 +409,49 @@ static PyObject *gPyGetVehicleConstraint(PyObject *self, { #if defined(_WIN64) __int64 constraintid; - if (PyArg_ParseTuple(args,"L",&constraintid)) + if (PyArg_ParseTuple(args, "L", &constraintid)) #else long constraintid; - if (PyArg_ParseTuple(args,"l",&constraintid)) + if (PyArg_ParseTuple(args, "l", &constraintid)) #endif { - if (PHY_GetActiveEnvironment()) - { + if (KX_GetPhysicsEnvironment()) { - PHY_IVehicle* vehicle = PHY_GetActiveEnvironment()->GetVehicleConstraint(constraintid); - if (vehicle) - { - KX_VehicleWrapper* pyWrapper = new KX_VehicleWrapper(vehicle,PHY_GetActiveEnvironment()); + PHY_IVehicle *vehicle = KX_GetPhysicsEnvironment()->GetVehicleConstraint(constraintid); + if (vehicle) { + KX_VehicleWrapper *pyWrapper = new KX_VehicleWrapper(vehicle); return pyWrapper->NewProxy(true); } } } else { - return NULL; + return nullptr; } Py_RETURN_NONE; } -static PyObject* gPyGetCharacter(PyObject* self, - PyObject* args, - PyObject* kwds) +static PyObject *gPyGetCharacter(PyObject *self, + PyObject *args, + PyObject *kwds) { - PyObject* pyob; + PyObject *pyob; KX_GameObject *ob; - if (!PyArg_ParseTuple(args,"O", &pyob)) - return NULL; + if (!PyArg_ParseTuple(args, "O", &pyob)) { + return nullptr; + } - if (!ConvertPythonToGameObject(KX_GetActiveScene()->GetLogicManager(), pyob, &ob, false, "bge.constraints.getCharacter(value)")) - return NULL; + if (!ConvertPythonToGameObject(KX_GetActiveScene()->GetLogicManager(), pyob, &ob, false, "bge.constraints.getCharacter(value)")) { + return nullptr; + } - if (PHY_GetActiveEnvironment()) - { + if (KX_GetPhysicsEnvironment()) { - PHY_ICharacter* character= PHY_GetActiveEnvironment()->GetCharacterController(ob); - if (character) - { - KX_CharacterWrapper* pyWrapper = new KX_CharacterWrapper(character); + PHY_ICharacter *character = KX_GetPhysicsEnvironment()->GetCharacterController(ob); + if (character) { + KX_CharacterWrapper *pyWrapper = new KX_CharacterWrapper(character); return pyWrapper->NewProxy(true); } @@ -501,38 +470,45 @@ static PyObject *gPyCreateConstraint(PyObject *self, int flag = 0; float pivotX = 0.0f, pivotY = 0.0f, pivotZ = 0.0f, axisX = 0.0f, axisY = 0.0f, axisZ = 0.0f; - static const char *kwlist[] = {"physicsid_1", "physicsid_2", "constraint_type", "pivot_x", "pivot_y", "pivot_z", - "axis_x", "axis_y", "axis_z", "flag", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "KKi|ffffffi:createConstraint", (char **)kwlist, - &physicsid, &physicsid2, &constrainttype, - &pivotX, &pivotY, &pivotZ, &axisX, &axisY, &axisZ, &flag)) - { - return NULL; + if (!EXP_ParseTupleArgsAndKeywords(args, kwds, "KKi|ffffffi:createConstraint", {"physicsid_1", "physicsid_2", + "constraint_type", "pivot_x", "pivot_y", "pivot_z", "axis_x", "axis_y", "axis_z", "flag", 0}, + &physicsid, &physicsid2, &constrainttype, &pivotX, &pivotY, &pivotZ, &axisX, &axisY, &axisZ, &flag)) { + return nullptr; } - if (PHY_GetActiveEnvironment()) { - PHY_IPhysicsController *physctrl = (PHY_IPhysicsController*)physicsid; - PHY_IPhysicsController *physctrl2 = (PHY_IPhysicsController*)physicsid2; + if (KX_GetPhysicsEnvironment()) { + PHY_IPhysicsController *physctrl = (PHY_IPhysicsController *)physicsid; + PHY_IPhysicsController *physctrl2 = (PHY_IPhysicsController *)physicsid2; if (physctrl) { //TODO:check for existence of this pointer! + if (constrainttype == PHY_VEHICLE_CONSTRAINT) { + EXP_ShowDeprecationWarning("bge.constraints.createConstraint(...)", "bge.constraints.createVehicle(chassis)"); + PHY_IVehicle *vehicle = KX_GetPhysicsEnvironment()->CreateVehicle(physctrl); + + KX_VehicleWrapper *wrap = new KX_VehicleWrapper(vehicle); + + return wrap->NewProxy(true); + } //convert from euler angle into axis const float deg2rad = 0.017453292f; //we need to pass a full constraint frame, not just axis //localConstraintFrameBasis - MT_Matrix3x3 localCFrame(MT_Vector3(deg2rad*axisX, deg2rad*axisY, deg2rad*axisZ)); - MT_Vector3 axis0 = localCFrame.getColumn(0); - MT_Vector3 axis1 = localCFrame.getColumn(1); - MT_Vector3 axis2 = localCFrame.getColumn(2); - - int constraintid = PHY_GetActiveEnvironment()->CreateConstraint( - physctrl, physctrl2, (enum PHY_ConstraintType)constrainttype, pivotX, pivotY, pivotZ, - (float)axis0.x(), (float)axis0.y(), (float)axis0.z(), - (float)axis1.x(), (float)axis1.y(), (float)axis1.z(), - (float)axis2.x(), (float)axis2.y(), (float)axis2.z(), flag); + mt::mat3 localCFrame(mt::vec3(deg2rad *axisX, deg2rad *axisY, deg2rad *axisZ)); + mt::vec3 axis0 = localCFrame.GetColumn(0); + mt::vec3 axis1 = localCFrame.GetColumn(1); + mt::vec3 axis2 = localCFrame.GetColumn(2); + + PHY_IConstraint *constraint = KX_GetPhysicsEnvironment()->CreateConstraint( + physctrl, physctrl2, (enum PHY_ConstraintType)constrainttype, pivotX, pivotY, pivotZ, + (float)axis0.x, (float)axis0.y, (float)axis0.z, + (float)axis1.x, (float)axis1.y, (float)axis1.z, + (float)axis2.x, (float)axis2.y, (float)axis2.z, flag); + + if (!constraint) { + return nullptr; + } - KX_ConstraintWrapper *wrap = new KX_ConstraintWrapper( - (enum PHY_ConstraintType)constrainttype, constraintid, PHY_GetActiveEnvironment()); + KX_ConstraintWrapper *wrap = new KX_ConstraintWrapper(constraint); return wrap->NewProxy(true); } @@ -540,30 +516,54 @@ static PyObject *gPyCreateConstraint(PyObject *self, Py_RETURN_NONE; } +static PyObject *gPyCreateVehicle(PyObject *self, PyObject *args) +{ + /* FIXME - physicsid is a long being cast to a pointer, should at least use PyCapsule */ + unsigned long long physicsid = 0; + if (!PyArg_ParseTuple(args, "K:createVehicle", &physicsid)) { + return nullptr; + } + + if (!KX_GetPhysicsEnvironment()) { + Py_RETURN_NONE; + } + PHY_IPhysicsController *physctrl = (PHY_IPhysicsController *)physicsid; + if (!physctrl) { //TODO:check for existence of this pointer! + return nullptr; + } + + PHY_IVehicle *vehicle = KX_GetPhysicsEnvironment()->CreateVehicle(physctrl); + if (!vehicle) { + return nullptr; + } + + KX_VehicleWrapper *wrap = new KX_VehicleWrapper(vehicle); + + return wrap->NewProxy(true); +} static PyObject *gPyGetAppliedImpulse(PyObject *self, PyObject *args, PyObject *kwds) { - float appliedImpulse = 0.f; + float appliedImpulse = 0.f; #if defined(_WIN64) __int64 constraintid; - if (PyArg_ParseTuple(args,"L",&constraintid)) + if (PyArg_ParseTuple(args, "L", &constraintid)) #else long constraintid; - if (PyArg_ParseTuple(args,"l",&constraintid)) + if (PyArg_ParseTuple(args, "l", &constraintid)) #endif { - if (PHY_GetActiveEnvironment()) - { - appliedImpulse = PHY_GetActiveEnvironment()->GetAppliedImpulse(constraintid); + if (KX_GetPhysicsEnvironment()) { + appliedImpulse = KX_GetPhysicsEnvironment()->GetAppliedImpulse(constraintid); } } else { - return NULL; + return nullptr; } return PyFloat_FromDouble(appliedImpulse); @@ -576,19 +576,18 @@ static PyObject *gPyRemoveConstraint(PyObject *self, { #if defined(_WIN64) __int64 constraintid; - if (PyArg_ParseTuple(args,"L",&constraintid)) + if (PyArg_ParseTuple(args, "L", &constraintid)) #else long constraintid; - if (PyArg_ParseTuple(args,"l",&constraintid)) + if (PyArg_ParseTuple(args, "l", &constraintid)) #endif { - if (PHY_GetActiveEnvironment()) - { - PHY_GetActiveEnvironment()->RemoveConstraintById(constraintid); + if (KX_GetPhysicsEnvironment()) { + KX_GetPhysicsEnvironment()->RemoveConstraintById(constraintid, true); } } else { - return NULL; + return nullptr; } Py_RETURN_NONE; @@ -596,76 +595,78 @@ static PyObject *gPyRemoveConstraint(PyObject *self, static PyObject *gPyExportBulletFile(PyObject *, PyObject *args) { - char* filename; - if (!PyArg_ParseTuple(args,"s:exportBulletFile",&filename)) - return NULL; + char *filename; + if (!PyArg_ParseTuple(args, "s:exportBulletFile", &filename)) { + return nullptr; + } - if (PHY_GetActiveEnvironment()) - { - PHY_GetActiveEnvironment()->ExportFile(filename); + if (KX_GetPhysicsEnvironment()) { + KX_GetPhysicsEnvironment()->ExportFile(filename); } Py_RETURN_NONE; } static struct PyMethodDef physicsconstraints_methods[] = { - {"setGravity",(PyCFunction) gPySetGravity, - METH_VARARGS, (const char*)gPySetGravity__doc__}, - {"setDebugMode",(PyCFunction) gPySetDebugMode, + {"setGravity", (PyCFunction)gPySetGravity, + METH_VARARGS, (const char *)gPySetGravity__doc__}, + {"setDebugMode", (PyCFunction)gPySetDebugMode, METH_VARARGS, (const char *)gPySetDebugMode__doc__}, /// settings that influence quality of the rigidbody dynamics - {"setNumIterations",(PyCFunction) gPySetNumIterations, + {"setNumIterations", (PyCFunction)gPySetNumIterations, METH_VARARGS, (const char *)gPySetNumIterations__doc__}, - {"setNumTimeSubSteps",(PyCFunction) gPySetNumTimeSubSteps, + {"setNumTimeSubSteps", (PyCFunction)gPySetNumTimeSubSteps, METH_VARARGS, (const char *)gPySetNumTimeSubSteps__doc__}, - {"setDeactivationTime",(PyCFunction) gPySetDeactivationTime, + {"setDeactivationTime", (PyCFunction)gPySetDeactivationTime, METH_VARARGS, (const char *)gPySetDeactivationTime__doc__}, - {"setDeactivationLinearTreshold",(PyCFunction) gPySetDeactivationLinearTreshold, + {"setDeactivationLinearTreshold", (PyCFunction)gPySetDeactivationLinearTreshold, METH_VARARGS, (const char *)gPySetDeactivationLinearTreshold__doc__}, - {"setDeactivationAngularTreshold",(PyCFunction) gPySetDeactivationAngularTreshold, + {"setDeactivationAngularTreshold", (PyCFunction)gPySetDeactivationAngularTreshold, METH_VARARGS, (const char *)gPySetDeactivationAngularTreshold__doc__}, - {"setContactBreakingTreshold",(PyCFunction) gPySetContactBreakingTreshold, + {"setContactBreakingTreshold", (PyCFunction)gPySetContactBreakingTreshold, METH_VARARGS, (const char *)gPySetContactBreakingTreshold__doc__}, - {"setCcdMode",(PyCFunction) gPySetCcdMode, + {"setCcdMode", (PyCFunction)gPySetCcdMode, METH_VARARGS, (const char *)gPySetCcdMode__doc__}, - {"setSorConstant",(PyCFunction) gPySetSorConstant, + {"setSorConstant", (PyCFunction)gPySetSorConstant, METH_VARARGS, (const char *)gPySetSorConstant__doc__}, - {"setSolverTau",(PyCFunction) gPySetSolverTau, + {"setSolverTau", (PyCFunction)gPySetSolverTau, METH_VARARGS, (const char *)gPySetSolverTau__doc__}, - {"setSolverDamping",(PyCFunction) gPySetSolverDamping, + {"setSolverDamping", (PyCFunction)gPySetSolverDamping, METH_VARARGS, (const char *)gPySetSolverDamping__doc__}, - {"setLinearAirDamping",(PyCFunction) gPySetLinearAirDamping, + {"setLinearAirDamping", (PyCFunction)gPySetLinearAirDamping, METH_VARARGS, (const char *)gPySetLinearAirDamping__doc__}, - {"setUseEpa",(PyCFunction) gPySetUseEpa, + {"setUseEpa", (PyCFunction)gPySetUseEpa, METH_VARARGS, (const char *)gPySetUseEpa__doc__}, - {"setSolverType",(PyCFunction) gPySetSolverType, + {"setSolverType", (PyCFunction)gPySetSolverType, METH_VARARGS, (const char *)gPySetSolverType__doc__}, - {"createConstraint",(PyCFunction) gPyCreateConstraint, - METH_VARARGS|METH_KEYWORDS, (const char *)gPyCreateConstraint__doc__}, - {"getVehicleConstraint",(PyCFunction) gPyGetVehicleConstraint, + {"createConstraint", (PyCFunction)gPyCreateConstraint, + METH_VARARGS | METH_KEYWORDS, (const char *)gPyCreateConstraint__doc__}, + {"createVehicle", (PyCFunction)gPyCreateVehicle, + METH_VARARGS, (const char *)gPyCreateVehicle__doc__}, + {"getVehicleConstraint", (PyCFunction)gPyGetVehicleConstraint, METH_VARARGS, (const char *)gPyGetVehicleConstraint__doc__}, - {"getCharacter",(PyCFunction) gPyGetCharacter, + {"getCharacter", (PyCFunction)gPyGetCharacter, METH_VARARGS, (const char *)gPyGetCharacter__doc__}, - {"removeConstraint",(PyCFunction) gPyRemoveConstraint, + {"removeConstraint", (PyCFunction)gPyRemoveConstraint, METH_VARARGS, (const char *)gPyRemoveConstraint__doc__}, - {"getAppliedImpulse",(PyCFunction) gPyGetAppliedImpulse, + {"getAppliedImpulse", (PyCFunction)gPyGetAppliedImpulse, METH_VARARGS, (const char *)gPyGetAppliedImpulse__doc__}, - {"exportBulletFile",(PyCFunction)gPyExportBulletFile, + {"exportBulletFile", (PyCFunction)gPyExportBulletFile, METH_VARARGS, "export a .bullet file"}, //sentinel - { NULL, (PyCFunction) NULL, 0, NULL } + { nullptr, (PyCFunction)nullptr, 0, nullptr } }; static struct PyModuleDef PhysicsConstraints_module_def = { @@ -731,20 +732,5 @@ PyMODINIT_FUNC initConstraintPythonBinding() return m; } -#if 0 -static void KX_RemovePythonConstraintBinding() -{ -} -#endif - -void PHY_SetActiveEnvironment(class PHY_IPhysicsEnvironment* env) -{ - g_CurrentActivePhysicsEnvironment = env; -} - -PHY_IPhysicsEnvironment* PHY_GetActiveEnvironment() -{ - return g_CurrentActivePhysicsEnvironment; -} - #endif // WITH_PYTHON + diff --git a/source/gameengine/Ketsji/KX_PyConstraintBinding.h b/source/gameengine/Ketsji/KX_PyConstraintBinding.h index 2bf9f7e197d0..397cb2396f2f 100644 --- a/source/gameengine/Ketsji/KX_PyConstraintBinding.h +++ b/source/gameengine/Ketsji/KX_PyConstraintBinding.h @@ -38,8 +38,6 @@ PyMODINIT_FUNC initConstraintPythonBinding(); -void PHY_SetActiveEnvironment(class PHY_IPhysicsEnvironment* env); -PHY_IPhysicsEnvironment* PHY_GetActiveEnvironment(); #endif /* WITH_PYTHON */ #endif /* __KX_PYCONSTRAINTBINDING_H__ */ diff --git a/source/gameengine/Ketsji/KX_PyMath.cpp b/source/gameengine/Ketsji/KX_PyMath.cpp index 2620eed4287a..7d4649d64020 100644 --- a/source/gameengine/Ketsji/KX_PyMath.cpp +++ b/source/gameengine/Ketsji/KX_PyMath.cpp @@ -37,41 +37,31 @@ #ifdef WITH_PYTHON -#include "MT_Vector3.h" -#include "MT_Vector4.h" -#include "MT_Matrix4x4.h" -#include "MT_Point2.h" - #include "EXP_ListValue.h" -#include "EXP_Python.h" #include "KX_PyMath.h" -bool PyOrientationTo(PyObject *pyval, MT_Matrix3x3 &rot, const char *error_prefix) +bool PyOrientationTo(PyObject *pyval, mt::mat3 &rot, const char *error_prefix) { - int size= PySequence_Size(pyval); - - if (size == 4) - { - MT_Quaternion qrot; - if (PyQuatTo(pyval, qrot)) - { - rot.setRotation(qrot); + int size = PySequence_Size(pyval); + + if (size == 4) { + mt::quat qrot; + if (PyQuatTo(pyval, qrot)) { + rot = qrot.ToMatrix(); return true; } } else if (size == 3) { /* 3x3 matrix or euler */ - MT_Vector3 erot; - if (PyVecTo(pyval, erot)) - { - rot.setEuler(erot); + mt::vec3 erot; + if (PyVecTo(pyval, erot)) { + rot = mt::mat3(erot); return true; } PyErr_Clear(); - if (PyMatTo(pyval, rot)) - { + if (PyMatTo(pyval, rot)) { return true; } } @@ -80,13 +70,14 @@ bool PyOrientationTo(PyObject *pyval, MT_Matrix3x3 &rot, const char *error_prefi return false; } -bool PyQuatTo(PyObject *pyval, MT_Quaternion &qrot) +bool PyQuatTo(PyObject *pyval, mt::quat &qrot) { - if (!PyVecTo(pyval, qrot)) + if (!PyVecTo(pyval, qrot)) { return false; + } /* annoying!, Blender/Mathutils have the W axis first! */ - MT_Scalar w = qrot[0]; /* from python, this is actually the W */ + float w = qrot[0]; /* from python, this is actually the W */ qrot[0] = qrot[1]; qrot[1] = qrot[2]; qrot[2] = qrot[3]; @@ -95,120 +86,21 @@ bool PyQuatTo(PyObject *pyval, MT_Quaternion &qrot) return true; } -PyObject *PyObjectFrom(const MT_Matrix4x4 &mat) -{ -#ifdef USE_MATHUTILS - float fmat[16]; - mat.getValue(fmat); - return Matrix_CreatePyObject(fmat, 4, 4, NULL); -#else - PyObject *collist = PyList_New(4); - PyObject *col; - int i; - - for (i=0; i < 4; i++) { - col = PyList_New(4); - PyList_SET_ITEM(col, 0, PyFloat_FromDouble(mat[0][i])); - PyList_SET_ITEM(col, 1, PyFloat_FromDouble(mat[1][i])); - PyList_SET_ITEM(col, 2, PyFloat_FromDouble(mat[2][i])); - PyList_SET_ITEM(col, 3, PyFloat_FromDouble(mat[3][i])); - PyList_SET_ITEM(collist, i, col); - } - - return collist; -#endif -} - -PyObject *PyObjectFrom(const MT_Matrix3x3 &mat) -{ -#ifdef USE_MATHUTILS - float fmat[9]; - mat.getValue3x3(fmat); - return Matrix_CreatePyObject(fmat, 3, 3, NULL); -#else - PyObject *collist = PyList_New(3); - PyObject *col; - int i; - - for (i=0; i < 3; i++) { - col = PyList_New(3); - PyList_SET_ITEM(col, 0, PyFloat_FromDouble(mat[0][i])); - PyList_SET_ITEM(col, 1, PyFloat_FromDouble(mat[1][i])); - PyList_SET_ITEM(col, 2, PyFloat_FromDouble(mat[2][i])); - PyList_SET_ITEM(collist, i, col); - } - - return collist; -#endif -} - #ifdef USE_MATHUTILS -PyObject *PyObjectFrom(const MT_Quaternion &qrot) +PyObject *PyObjectFrom(const mt::quat &qrot) { - /* NOTE, were re-ordering here for Mathutils compat */ - float fvec[4]; - qrot.getValue(fvec); - return Quaternion_CreatePyObject(fvec, NULL); + float data[4]; + qrot.Pack(data); + return Quaternion_CreatePyObject(data, nullptr); } #endif -PyObject *PyObjectFrom(const MT_Tuple4 &vec) -{ -#ifdef USE_MATHUTILS - float fvec[4]; - vec.getValue(fvec); - return Vector_CreatePyObject(fvec, 4, NULL); -#else - PyObject *list = PyList_New(4); - PyList_SET_ITEM(list, 0, PyFloat_FromDouble(vec[0])); - PyList_SET_ITEM(list, 1, PyFloat_FromDouble(vec[1])); - PyList_SET_ITEM(list, 2, PyFloat_FromDouble(vec[2])); - PyList_SET_ITEM(list, 3, PyFloat_FromDouble(vec[3])); - return list; -#endif -} - -PyObject *PyObjectFrom(const MT_Tuple3 &vec) -{ -#ifdef USE_MATHUTILS - float fvec[3]; - vec.getValue(fvec); - return Vector_CreatePyObject(fvec, 3, NULL); -#else - PyObject *list = PyList_New(3); - PyList_SET_ITEM(list, 0, PyFloat_FromDouble(vec[0])); - PyList_SET_ITEM(list, 1, PyFloat_FromDouble(vec[1])); - PyList_SET_ITEM(list, 2, PyFloat_FromDouble(vec[2])); - return list; -#endif -} - -PyObject *PyObjectFrom(const MT_Tuple2 &vec) -{ -#ifdef USE_MATHUTILS - float fvec[2]; - vec.getValue(fvec); - return Vector_CreatePyObject(fvec, 2, NULL); -#else - PyObject *list = PyList_New(2); - PyList_SET_ITEM(list, 0, PyFloat_FromDouble(vec[0])); - PyList_SET_ITEM(list, 1, PyFloat_FromDouble(vec[1])); - return list; -#endif -} - -PyObject *PyColorFromVector(const MT_Vector3 &vec) +PyObject *PyColorFromVector(const mt::vec3 &vec) { #ifdef USE_MATHUTILS - float fvec[3]; - vec.getValue(fvec); - return Color_CreatePyObject(fvec, NULL); + return Color_CreatePyObject(vec.Data(), nullptr); #else - PyObject *list = PyList_New(3); - PyList_SET_ITEM(list, 0, PyFloat_FromDouble(vec[0])); - PyList_SET_ITEM(list, 1, PyFloat_FromDouble(vec[1])); - PyList_SET_ITEM(list, 2, PyFloat_FromDouble(vec[2])); - return list; + return PyObjectFrom(vec); #endif } diff --git a/source/gameengine/Ketsji/KX_PyMath.h b/source/gameengine/Ketsji/KX_PyMath.h index c9059da8913a..1644c3f65bd4 100644 --- a/source/gameengine/Ketsji/KX_PyMath.h +++ b/source/gameengine/Ketsji/KX_PyMath.h @@ -33,13 +33,7 @@ #ifndef __KX_PYMATH_H__ #define __KX_PYMATH_H__ -#include "MT_Point2.h" -#include "MT_Point3.h" -#include "MT_Vector2.h" -#include "MT_Vector3.h" -#include "MT_Vector4.h" -#include "MT_Matrix3x3.h" -#include "MT_Matrix4x4.h" +#include "mathfu.h" #include "EXP_Python.h" #include "EXP_PyObjectPlus.h" @@ -51,11 +45,15 @@ extern "C" { } #endif -inline unsigned int Size(const MT_Matrix4x4&) { return 4; } -inline unsigned int Size(const MT_Matrix3x3&) { return 3; } -inline unsigned int Size(const MT_Tuple2&) { return 2; } -inline unsigned int Size(const MT_Tuple3&) { return 3; } -inline unsigned int Size(const MT_Tuple4&) { return 4; } +inline unsigned int Size(const mt::mat4&) { return 4; } +inline unsigned int Size(const mt::mat3&) { return 3; } +inline unsigned int Size(const mt::vec2&) { return 2; } +inline unsigned int Size(const mt::vec3&) { return 3; } +inline unsigned int Size(const mt::vec4&) { return 4; } +inline unsigned int Size(const mt::quat&) { return 4; } +inline unsigned int Size(const mt::vec2_packed&) { return 2; } +inline unsigned int Size(const mt::vec3_packed&) { return 3; } +inline unsigned int Size(const mt::vec4_packed&) { return 4; } /** * Converts the given python matrix (column-major) to an MT class (row-major). @@ -64,8 +62,6 @@ template bool PyMatTo(PyObject *pymat, T& mat) { bool noerror = true; - mat.setIdentity(); - #ifdef USE_MATHUTILS @@ -83,7 +79,7 @@ bool PyMatTo(PyObject *pymat, T& mat) { for (unsigned int col = 0; col < Size(mat); col++) { - mat[row][col] = *(pymatrix->matrix + col * pymatrix->num_row + row); + mat(row, col) = *(pymatrix->matrix + col * pymatrix->num_row + row); } } } @@ -97,7 +93,7 @@ bool PyMatTo(PyObject *pymat, T& mat) unsigned int rows = PySequence_Size(pymat); if (rows != Size(mat)) return false; - + for (unsigned int row = 0; noerror && row < rows; row++) { PyObject *pyrow = PySequence_GetItem(pymat, row); /* new ref */ @@ -110,7 +106,7 @@ bool PyMatTo(PyObject *pymat, T& mat) else { for (unsigned int col = 0; col < cols; col++) { PyObject *item = PySequence_GetItem(pyrow, col); /* new ref */ - mat[row][col] = PyFloat_AsDouble(item); + mat(row, col) = PyFloat_AsDouble(item); Py_DECREF(item); } } @@ -120,12 +116,12 @@ bool PyMatTo(PyObject *pymat, T& mat) } Py_DECREF(pyrow); } - } else + } else noerror = false; - + if (noerror==false) PyErr_SetString(PyExc_TypeError, "could not be converted to a matrix (sequence of sequences)"); - + return noerror; } @@ -137,7 +133,7 @@ bool PyVecTo(PyObject *pyval, T& vec) { #ifdef USE_MATHUTILS /* no need for BaseMath_ReadCallback() here, reading the sequences will do this */ - + if (VectorObject_Check(pyval)) { VectorObject *pyvec= (VectorObject *)pyval; if (BaseMath_ReadCallback(pyvec) == -1) { @@ -147,7 +143,7 @@ bool PyVecTo(PyObject *pyval, T& vec) PyErr_Format(PyExc_AttributeError, "error setting vector, %d args, should be %d", pyvec->size, Size(vec)); return false; } - vec.setValue((float *) pyvec->vec); + vec = T(pyvec->vec); return true; } else if (QuaternionObject_Check(pyval)) { @@ -160,7 +156,7 @@ bool PyVecTo(PyObject *pyval, T& vec) return false; } /* xyzw -> wxyz reordering is done by PyQuatTo */ - vec.setValue((float *) pyquat->quat); + vec = T(pyquat->quat); return true; } else if (EulerObject_Check(pyval)) { @@ -172,7 +168,7 @@ bool PyVecTo(PyObject *pyval, T& vec) PyErr_Format(PyExc_AttributeError, "error setting vector, %d args, should be %d", 3, Size(vec)); return false; } - vec.setValue((float *) pyeul->eul); + vec = T(pyeul->eul); return true; } else @@ -183,26 +179,26 @@ bool PyVecTo(PyObject *pyval, T& vec) PyErr_Format(PyExc_AttributeError, "error setting vector, %d args, should be %d", numitems, Size(vec)); return false; } - + for (unsigned int x = 0; x < numitems; x++) vec[x] = PyFloat_AsDouble(PyTuple_GET_ITEM(pyval, x)); /* borrow ref */ - + if (PyErr_Occurred()) { PyErr_SetString(PyExc_AttributeError, "one or more of the items in the sequence was not a float"); return false; } - + return true; } - else if (PyObject_TypeCheck(pyval, (PyTypeObject *)&PyObjectPlus::Type)) { + else if (PyObject_TypeCheck(pyval, (PyTypeObject *)&EXP_PyObjectPlus::Type)) { /* note, include this check because PySequence_Check does too much introspection * on the PyObject (like getting its __class__, on a BGE type this means searching up * the parent list each time only to discover its not a sequence. * GameObjects are often used as an alternative to vectors so this is a common case * better to do a quick check for it, likely the error below will be ignored. - * - * This is not 'correct' since we have proxy type CListValues's which could - * contain floats/ints but there no cases of CValueLists being this way + * + * This is not 'correct' since we have proxy type EXP_ListValues's which could + * contain floats/ints but there no cases of EXP_ValueLists being this way */ PyErr_Format(PyExc_AttributeError, "expected a sequence type"); return false; @@ -213,69 +209,108 @@ bool PyVecTo(PyObject *pyval, T& vec) PyErr_Format(PyExc_AttributeError, "error setting vector, %d args, should be %d", numitems, Size(vec)); return false; } - + for (unsigned int x = 0; x < numitems; x++) { PyObject *item = PySequence_GetItem(pyval, x); /* new ref */ vec[x] = PyFloat_AsDouble(item); Py_DECREF(item); } - + if (PyErr_Occurred()) { PyErr_SetString(PyExc_AttributeError, "one or more of the items in the sequence was not a float"); return false; } - + return true; } else { PyErr_Format(PyExc_AttributeError, "not a sequence type, expected a sequence of numbers size %d", Size(vec)); } - + return false; } -bool PyQuatTo(PyObject *pyval, MT_Quaternion &qrot); +bool PyQuatTo(PyObject *pyval, mt::quat &qrot); -bool PyOrientationTo(PyObject *pyval, MT_Matrix3x3 &mat, const char *error_prefix); +bool PyOrientationTo(PyObject *pyval, mt::mat3 &mat, const char *error_prefix); -/** - * Converts an MT_Matrix4x4 to a python object. - */ -PyObject *PyObjectFrom(const MT_Matrix4x4 &mat); +/// Converts an mt::matX to a python object. +template +PyObject *PyObjectFrom(const mt::Matrix &mat) +{ +#ifdef USE_MATHUTILS + float fmat[Rows * Cols]; + mat.Pack(fmat); + return Matrix_CreatePyObject(fmat, Rows, Cols, nullptr); +#else + PyObject *list = PyList_New(Rows); + + for (unsigned short i = 0; i < Rows; ++i) { + PyObject *row = PyList_New(Cols); + for (unsigned short j = 0; j < Cols; ++j) { + PyList_SET_ITEM(row, j, PyFloat_FromDouble(mat[i][j])); + } + PyList_SET_ITEM(list, i, row); + } -/** - * Converts an MT_Matrix3x3 to a python object. - */ -PyObject *PyObjectFrom(const MT_Matrix3x3 &mat); + return list; +#endif +} -/** - * Converts an MT_Tuple2 to a python object. - */ -PyObject *PyObjectFrom(const MT_Tuple2 &vec); +#ifdef USE_MATHUTILS +/// Converts an mt::quat to a python object. +PyObject *PyObjectFrom(const mt::quat &qrot); +#endif -/** - * Converts an MT_Tuple3 to a python object - */ -PyObject *PyObjectFrom(const MT_Tuple3 &vec); +/// Converts an mt::vecX to a python object. +template +PyObject *PyObjectFrom(const mt::Vector &vec) +{ +#ifdef USE_MATHUTILS + return Vector_CreatePyObject(vec.Data(), Size, nullptr); +#else + PyObject *list = PyList_New(Size); + for (unsigned short i = 0; i < Size; ++i) { + PyList_SET_ITEM(list, i, PyFloat_FromDouble(vec[i])); + } + return list; +#endif +} +/// Converts an mt::vecX_packed to a python object. +template +PyObject *PyObjectFrom(const mt::VectorPacked &vec) +{ #ifdef USE_MATHUTILS -/** - * Converts an MT_Quaternion to a python object. - */ -PyObject *PyObjectFrom(const MT_Quaternion &qrot); + return Vector_CreatePyObject(vec.data, Size, nullptr); +#else + PyObject *list = PyList_New(Size); + for (unsigned short i = 0; i < Size; ++i) { + PyList_SET_ITEM(list, i, PyFloat_FromDouble(vec.data[i])); + } + return list; #endif +} -/** - * Converts an MT_Tuple4 to a python object. - */ -PyObject *PyObjectFrom(const MT_Tuple4 &pos); +/// Converts an mt::vec3 to a python color object. +PyObject *PyColorFromVector(const mt::vec3 &vec); +/// Convert a float array to a python object. +template +PyObject *PyObjectFrom(const float (&vec)[Size]) +{ +#ifdef USE_MATHUTILS + return Vector_CreatePyObject(vec, Size, nullptr); +#else + PyObject *list = PyList_New(Size); + for (unsigned short i = 0; i < Size; ++i) { + PyList_SET_ITEM(list, i, PyFloat_FromDouble(vec[i])); + } + return list; #endif +} -/** - * Converts an MT_Vector3 to a python color object. - */ -PyObject *PyColorFromVector(const MT_Vector3 &vec); +#endif // WITH_PYTHON -#endif /* WITH_PYTHON */ +#endif // __KX_PYMATH_H__ diff --git a/source/gameengine/Ketsji/KX_PythonComponent.cpp b/source/gameengine/Ketsji/KX_PythonComponent.cpp new file mode 100644 index 000000000000..ae9fe78863b4 --- /dev/null +++ b/source/gameengine/Ketsji/KX_PythonComponent.cpp @@ -0,0 +1,172 @@ +/** + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Mitchell Stokes, Diego Lopes, Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifdef WITH_PYTHON + +#include "KX_PythonComponent.h" +#include "KX_GameObject.h" + +#include "CM_Message.h" + +#include "DNA_python_component_types.h" + +#include "BKE_python_component.h" + +KX_PythonComponent::KX_PythonComponent(const std::string& name) + :m_pc(nullptr), + m_gameobj(nullptr), + m_name(name), + m_init(false) +{ +} + +KX_PythonComponent::~KX_PythonComponent() +{ +} + +std::string KX_PythonComponent::GetName() +{ + return m_name; +} + +EXP_Value *KX_PythonComponent::GetReplica() +{ + KX_PythonComponent *replica = new KX_PythonComponent(*this); + replica->ProcessReplica(); + + // Subclass the python component. + PyTypeObject *type = Py_TYPE(GetProxy()); + if (!py_base_new(type, PyTuple_Pack(1, replica->GetProxy()), nullptr)) { + CM_Error("failed replicate component: \"" << m_name << "\""); + delete replica; + return nullptr; + } + + return replica; +} + +void KX_PythonComponent::ProcessReplica() +{ + EXP_Value::ProcessReplica(); + m_gameobj = nullptr; + m_init = false; +} + +KX_GameObject *KX_PythonComponent::GetGameObject() const +{ + return m_gameobj; +} + +void KX_PythonComponent::SetGameObject(KX_GameObject *gameobj) +{ + m_gameobj = gameobj; +} + +void KX_PythonComponent::SetBlenderPythonComponent(PythonComponent *pc) +{ + m_pc = pc; +} + +void KX_PythonComponent::Start() +{ + PyObject *arg_dict = (PyObject *)BKE_python_component_argument_dict_new(m_pc); + + PyObject *ret = PyObject_CallMethod(GetProxy(), "start", "O", arg_dict); + + if (PyErr_Occurred()) { + PyErr_Print(); + } + + Py_XDECREF(arg_dict); + Py_XDECREF(ret); +} + +void KX_PythonComponent::Update() +{ + if (!m_init) { + Start(); + m_init = true; + } + + PyObject *pycomp = GetProxy(); + if (!PyObject_CallMethod(pycomp, "update", "")) { + PyErr_Print(); + } +} + +PyObject *KX_PythonComponent::py_component_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + KX_PythonComponent *comp = new KX_PythonComponent(type->tp_name); + + PyObject *proxy = py_base_new(type, PyTuple_Pack(1, comp->GetProxy()), kwds); + if (!proxy) { + delete comp; + return nullptr; + } + + return proxy; +} + +PyTypeObject KX_PythonComponent::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_PythonComponent", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &EXP_PyObjectPlus::Type, + 0, 0, 0, 0, 0, 0, + py_component_new +}; + +PyMethodDef KX_PythonComponent::Methods[] = { + {nullptr, nullptr} // Sentinel +}; + +PyAttributeDef KX_PythonComponent::Attributes[] = { + EXP_PYATTRIBUTE_RO_FUNCTION("object", KX_PythonComponent, pyattr_get_object), + EXP_PYATTRIBUTE_NULL // Sentinel +}; + +PyObject *KX_PythonComponent::pyattr_get_object(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_PythonComponent *self = static_cast(self_v); + KX_GameObject *gameobj = self->GetGameObject(); + + if (gameobj) { + return gameobj->GetProxy(); + } + else { + Py_RETURN_NONE; + } +} +#endif diff --git a/source/gameengine/Ketsji/KX_PythonComponent.h b/source/gameengine/Ketsji/KX_PythonComponent.h new file mode 100644 index 000000000000..117210b9d46f --- /dev/null +++ b/source/gameengine/Ketsji/KX_PythonComponent.h @@ -0,0 +1,69 @@ +/** + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __KX_PYCOMPONENT_H__ +#define __KX_PYCOMPONENT_H__ + +#ifdef WITH_PYTHON + +#include "EXP_Value.h" + +class KX_GameObject; +struct PythonComponent; + +class KX_PythonComponent : public EXP_Value +{ + Py_Header + +private: + PythonComponent *m_pc; + KX_GameObject *m_gameobj; + std::string m_name; + bool m_init; + +public: + KX_PythonComponent(const std::string& name); + virtual ~KX_PythonComponent(); + + // stuff for cvalue related things + virtual std::string GetName(); + virtual EXP_Value *GetReplica(); + + void ProcessReplica(); + + KX_GameObject *GetGameObject() const; + void SetGameObject(KX_GameObject *gameobj); + + void SetBlenderPythonComponent(PythonComponent *pc); + + void Start(); + void Update(); + + static PyObject *py_component_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + + // Attributes + static PyObject *pyattr_get_object(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); +}; + +#endif // WITH_PYTHON + +#endif // __KX_PYCOMPONENT_H__ diff --git a/source/gameengine/Ketsji/KX_PythonComponentManager.cpp b/source/gameengine/Ketsji/KX_PythonComponentManager.cpp new file mode 100644 index 000000000000..7fbb006e244f --- /dev/null +++ b/source/gameengine/Ketsji/KX_PythonComponentManager.cpp @@ -0,0 +1,42 @@ +#include "KX_PythonComponentManager.h" +#include "KX_PythonComponent.h" +#include "KX_GameObject.h" + +#include "CM_List.h" + +KX_PythonComponentManager::KX_PythonComponentManager() +{ +} + +KX_PythonComponentManager::~KX_PythonComponentManager() +{ +} + +void KX_PythonComponentManager::RegisterObject(KX_GameObject *gameobj) +{ + // Always register only once an object. + m_objects.push_back(gameobj); +} + +void KX_PythonComponentManager::UnregisterObject(KX_GameObject *gameobj) +{ + CM_ListRemoveIfFound(m_objects, gameobj); +} + +void KX_PythonComponentManager::UpdateComponents() +{ + /* Update object components, we copy the object pointer in a second list to make + * sure that we iterate on a list which will not be modified, indeed components + * can add objects in theirs update. + */ + const std::vector objects = m_objects; + for (KX_GameObject *gameobj : objects) { + gameobj->UpdateComponents(); + } +} + +void KX_PythonComponentManager::Merge(KX_PythonComponentManager& other) +{ + m_objects.insert(m_objects.end(), other.m_objects.begin(), other.m_objects.end()); + other.m_objects.clear(); +} diff --git a/source/gameengine/Ketsji/KX_PythonComponentManager.h b/source/gameengine/Ketsji/KX_PythonComponentManager.h new file mode 100644 index 000000000000..41b2faee70bf --- /dev/null +++ b/source/gameengine/Ketsji/KX_PythonComponentManager.h @@ -0,0 +1,25 @@ +#ifndef __KX_PYTHON_COMPONENT_H__ +#define __KX_PYTHON_COMPONENT_H__ + +#include + +class KX_GameObject; + +class KX_PythonComponentManager +{ +private: + std::vector m_objects; + +public: + KX_PythonComponentManager(); + ~KX_PythonComponentManager(); + + void RegisterObject(KX_GameObject *gameobj); + void UnregisterObject(KX_GameObject *gameobj); + + void UpdateComponents(); + + void Merge(KX_PythonComponentManager& other); +}; + +#endif // __KX_PYTHON_COMPONENT_H__ diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index 251273cf7a84..0cf09d9b597e 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -30,8 +30,6 @@ * \ingroup ketsji */ -#include "GPU_glew.h" - #ifdef _MSC_VER # pragma warning (disable:4786) #endif @@ -49,11 +47,15 @@ extern "C" { # include "py_capi_utils.h" # include "mathutils.h" // 'mathutils' module copied here so the blenderlayer can use. # include "bgl.h" + # include "bpy.h" // for bpy_sys_module_backup # include "blf_py_api.h" # include "marshal.h" /* python header for loading/saving dicts */ } -#include "../../../../intern/audaspace/intern/AUD_PyInit.h" + +#ifdef WITH_AUDASPACE +# include "../../../../intern/audaspace/intern/AUD_PyInit.h" +#endif // WITH_AUDASPACE #endif /* WITH_PYTHON */ @@ -74,11 +76,12 @@ extern "C" { #include "KX_KetsjiEngine.h" #include "KX_RadarSensor.h" #include "KX_RaySensor.h" +#include "KX_MovementSensor.h" #include "KX_ArmatureSensor.h" #include "KX_SceneActuator.h" #include "KX_GameActuator.h" #include "KX_ParentActuator.h" -#include "KX_SCA_DynamicActuator.h" +#include "KX_DynamicActuator.h" #include "KX_SteeringActuator.h" #include "KX_NavMeshObject.h" #include "KX_MouseActuator.h" @@ -87,28 +90,26 @@ extern "C" { #include "SCA_IInputDevice.h" #include "SCA_PropertySensor.h" #include "SCA_RandomActuator.h" -#include "SCA_KeyboardSensor.h" /* IsPrintable, ToCharacter */ #include "SCA_JoystickManager.h" /* JOYINDEX_MAX */ #include "SCA_PythonJoystick.h" #include "SCA_PythonKeyboard.h" #include "SCA_PythonMouse.h" +#include "SCA_2DFilterActuator.h" #include "KX_ConstraintActuator.h" #include "KX_SoundActuator.h" #include "KX_StateActuator.h" #include "BL_ActionActuator.h" #include "BL_ArmatureObject.h" -#include "RAS_IRasterizer.h" +#include "RAS_Rasterizer.h" #include "RAS_ICanvas.h" -#include "RAS_IOffScreen.h" #include "RAS_BucketManager.h" #include "RAS_2DFilterManager.h" -#include "MT_Vector3.h" -#include "MT_Point3.h" #include "EXP_ListValue.h" #include "EXP_InputParser.h" #include "KX_Scene.h" +#include "KX_Globals.h" -#include "NG_NetworkScene.h" //Needed for sendMessage() +#include "KX_NetworkMessageScene.h" //Needed for sendMessage() #include "BL_Shader.h" #include "BL_Action.h" @@ -119,6 +120,8 @@ extern "C" { #include "KX_PythonInitTypes.h" +#include "CM_Message.h" + /* we only need this to get a list of libraries from the main struct */ #include "DNA_ID.h" #include "DNA_scene_types.h" @@ -137,9 +140,9 @@ extern "C" { } /* for converting new scenes */ -#include "KX_BlenderSceneConverter.h" +#include "BL_Converter.h" #include "KX_LibLoadStatus.h" -#include "KX_MeshProxy.h" /* for creating a new library of mesh objects */ +#include "KX_Mesh.h" /* for creating a new library of mesh objects */ extern "C" { #include "BKE_idcode.h" } @@ -148,60 +151,18 @@ extern "C" { #ifdef WITH_PYTHON -static RAS_ICanvas* gp_Canvas = NULL; -static char gp_GamePythonPath[FILE_MAX] = ""; -static char gp_GamePythonPathOrig[FILE_MAX] = ""; // not super happy about this, but we need to remember the first loaded file for the global/dict load save - -static SCA_PythonKeyboard* gp_PythonKeyboard = NULL; -static SCA_PythonMouse* gp_PythonMouse = NULL; -static SCA_PythonJoystick* gp_PythonJoysticks[JOYINDEX_MAX] = {NULL}; -#endif // WITH_PYTHON - -static KX_Scene* gp_KetsjiScene = NULL; -static KX_KetsjiEngine* gp_KetsjiEngine = NULL; -static RAS_IRasterizer* gp_Rasterizer = NULL; - - -void KX_SetActiveScene(class KX_Scene* scene) -{ - gp_KetsjiScene = scene; -} - -class KX_Scene* KX_GetActiveScene() -{ - return gp_KetsjiScene; -} - -class KX_KetsjiEngine* KX_GetActiveEngine() -{ - return gp_KetsjiEngine; -} - -/* why is this in python? */ -void KX_RasterizerDrawDebugLine(const MT_Vector3& from,const MT_Vector3& to,const MT_Vector3& color) -{ - if (gp_Rasterizer) - gp_Rasterizer->DrawDebugLine(gp_KetsjiScene, from, to, color); -} - -void KX_RasterizerDrawDebugCircle(const MT_Vector3& center, const MT_Scalar radius, const MT_Vector3& color, - const MT_Vector3& normal, int nsector) -{ - if (gp_Rasterizer) - gp_Rasterizer->DrawDebugCircle(gp_KetsjiScene, center, radius, color, normal, nsector); -} - -#ifdef WITH_PYTHON - +static std::unique_ptr gp_PythonKeyboard; +static std::unique_ptr gp_PythonMouse; +static std::unique_ptr gp_PythonJoysticks[JOYINDEX_MAX]; static struct { PyObject *path; PyObject *meta_path; PyObject *modules; -} gp_sys_backup = {NULL}; +} gp_sys_backup = {nullptr}; /* Macro for building the keyboard translation */ -//#define KX_MACRO_addToDict(dict, name) PyDict_SetItemString(dict, #name, PyLong_FromLong(SCA_IInputDevice::KX_##name)) +//#define KX_MACRO_addToDict(dict, name) PyDict_SetItemString(dict, #name, PyLong_FromLong(SCA_IInputDevice::##name)) //#define KX_MACRO_addToDict(dict, name) PyDict_SetItemString(dict, #name, item=PyLong_FromLong(name)); Py_DECREF(item) /* For the defines for types from logic bricks, we do stuff explicitly... */ #define KX_MACRO_addTypesToDict(dict, name, value) KX_MACRO_addTypesToDict_fn(dict, #name, value) @@ -224,201 +185,148 @@ static void KX_MACRO_addTypesToDict_fn(PyObject *dict, const char *name, long va static PyObject *ErrorObject; PyDoc_STRVAR(gPyGetRandomFloat_doc, -"getRandomFloat()\n" -"returns a random floating point value in the range [0..1]" -); + "getRandomFloat()\n" + "returns a random floating point value in the range [0..1]" + ); static PyObject *gPyGetRandomFloat(PyObject *) { - return PyFloat_FromDouble(MT_random()); + return PyFloat_FromDouble(mt::Random()); } static PyObject *gPySetGravity(PyObject *, PyObject *value) { - MT_Vector3 vec; - if (!PyVecTo(value, vec)) - return NULL; + mt::vec3 vec; + if (!PyVecTo(value, vec)) { + return nullptr; + } - if (gp_KetsjiScene) - gp_KetsjiScene->SetGravity(vec); + KX_Scene *scene = KX_GetActiveScene(); + if (scene) { + scene->SetGravity(vec); + } Py_RETURN_NONE; } PyDoc_STRVAR(gPyExpandPath_doc, -"expandPath(path)\n" -"Converts a blender internal path into a proper file system path.\n" -" path - the string path to convert.\n" -"Use / as directory separator in path\n" -"You can use '//' at the start of the string to define a relative path." -"Blender replaces that string by the directory of the current .blend or runtime file to make a full path name.\n" -"The function also converts the directory separator to the local file system format." -); + "expandPath(path)\n" + "Converts a blender internal path into a proper file system path.\n" + " path - the string path to convert.\n" + "Use / as directory separator in path\n" + "You can use '//' at the start of the string to define a relative path." + "Blender replaces that string by the directory of the current .blend or runtime file to make a full path name.\n" + "The function also converts the directory separator to the local file system format." + ); static PyObject *gPyExpandPath(PyObject *, PyObject *args) { char expanded[FILE_MAX]; - char* filename; + char *filename; - if (!PyArg_ParseTuple(args,"s:ExpandPath",&filename)) - return NULL; + if (!PyArg_ParseTuple(args, "s:ExpandPath", &filename)) { + return nullptr; + } BLI_strncpy(expanded, filename, FILE_MAX); - BLI_path_abs(expanded, gp_GamePythonPath); + BLI_path_abs(expanded, KX_GetMainPath().c_str()); return PyC_UnicodeFromByte(expanded); } PyDoc_STRVAR(gPyStartGame_doc, -"startGame(blend)\n" -"Loads the blend file" -); + "startGame(blend)\n" + "Loads the blend file" + ); static PyObject *gPyStartGame(PyObject *, PyObject *args) { - char* blendfile; + char *blendfile; - if (!PyArg_ParseTuple(args, "s:startGame", &blendfile)) - return NULL; + if (!PyArg_ParseTuple(args, "s:startGame", &blendfile)) { + return nullptr; + } - gp_KetsjiEngine->RequestExit(KX_EXIT_REQUEST_START_OTHER_GAME); - gp_KetsjiEngine->SetNameNextGame(blendfile); + KX_GetActiveEngine()->RequestExit(KX_ExitInfo::START_OTHER_GAME, blendfile); Py_RETURN_NONE; } PyDoc_STRVAR(gPyEndGame_doc, -"endGame()\n" -"Ends the current game" -); + "endGame()\n" + "Ends the current game" + ); static PyObject *gPyEndGame(PyObject *) { - gp_KetsjiEngine->RequestExit(KX_EXIT_REQUEST_QUIT_GAME); - - //printf("%s\n", gp_GamePythonPath); + KX_GetActiveEngine()->RequestExit(KX_ExitInfo::QUIT_GAME); Py_RETURN_NONE; } PyDoc_STRVAR(gPyRestartGame_doc, -"restartGame()\n" -"Restarts the current game by reloading the .blend file" -); + "restartGame()\n" + "Restarts the current game by reloading the .blend file" + ); static PyObject *gPyRestartGame(PyObject *) { - gp_KetsjiEngine->RequestExit(KX_EXIT_REQUEST_RESTART_GAME); - gp_KetsjiEngine->SetNameNextGame(gp_GamePythonPath); + KX_GetActiveEngine()->RequestExit(KX_ExitInfo::RESTART_GAME, KX_GetMainPath()); Py_RETURN_NONE; } PyDoc_STRVAR(gPySaveGlobalDict_doc, -"saveGlobalDict()\n" -"Saves bge.logic.globalDict to a file" -); + "saveGlobalDict()\n" + "Saves bge.logic.globalDict to a file" + ); static PyObject *gPySaveGlobalDict(PyObject *) { - char marshal_path[512]; - char *marshal_buffer = NULL; - unsigned int marshal_length; - FILE *fp = NULL; - - pathGamePythonConfig(marshal_path); - marshal_length = saveGamePythonConfig(&marshal_buffer); - - if (marshal_length && marshal_buffer) - { - fp = fopen(marshal_path, "wb"); - - if (fp) - { - if (fwrite(marshal_buffer, 1, marshal_length, fp) != marshal_length) - printf("Warning: could not write marshal data\n"); - - fclose(fp); - } else { - printf("Warning: could not open marshal file\n"); - } - } else { - printf("Warning: could not create marshal buffer\n"); - } - - if (marshal_buffer) - delete [] marshal_buffer; + saveGamePythonConfig(); Py_RETURN_NONE; } PyDoc_STRVAR(gPyLoadGlobalDict_doc, -"LoadGlobalDict()\n" -"Loads bge.logic.globalDict from a file" -); + "LoadGlobalDict()\n" + "Loads bge.logic.globalDict from a file" + ); static PyObject *gPyLoadGlobalDict(PyObject *) { - char marshal_path[512]; - char *marshal_buffer = NULL; - int marshal_length; - FILE *fp = NULL; - int result; - - pathGamePythonConfig(marshal_path); - - fp = fopen(marshal_path, "rb"); - - if (fp) { - // obtain file size: - fseek (fp, 0, SEEK_END); - marshal_length = ftell(fp); - if (marshal_length == -1) { - printf("Warning: could not read position of '%s'\n", marshal_path); - fclose(fp); - Py_RETURN_NONE; - } - rewind(fp); - - marshal_buffer = (char*)malloc (sizeof(char)*marshal_length); - - result = fread(marshal_buffer, 1, marshal_length, fp); - - if (result == marshal_length) { - loadGamePythonConfig(marshal_buffer, marshal_length); - } else { - printf("Warning: could not read all of '%s'\n", marshal_path); - } - - free(marshal_buffer); - fclose(fp); - } else { - printf("Warning: could not open '%s'\n", marshal_path); - } + loadGamePythonConfig(); Py_RETURN_NONE; } PyDoc_STRVAR(gPyGetProfileInfo_doc, -"getProfileInfo()\n" -"returns a dictionary with profiling information" -); + "getProfileInfo()\n" + "returns a dictionary with profiling information" + ); static PyObject *gPyGetProfileInfo(PyObject *) { - return gp_KetsjiEngine->GetPyProfileDict(); + return KX_GetActiveEngine()->GetPyProfileDict(); } PyDoc_STRVAR(gPySendMessage_doc, -"sendMessage(subject, [body, to, from])\n" -"sends a message in same manner as a message actuator" -" subject = Subject of the message" -" body = Message body" -" to = Name of object to send the message to" -" from = Name of object to send the string from" -); + "sendMessage(subject, [body, to, from])\n" + "sends a message in same manner as a message actuator" + " subject = Subject of the message" + " body = Message body" + " to = Name of object to send the message to" + " from = Name of object to send the string from" + ); static PyObject *gPySendMessage(PyObject *, PyObject *args) { - char* subject; - char* body = (char *)""; - char* to = (char *)""; - char* from = (char *)""; + char *subject; + char *body = (char *)""; + char *to = (char *)""; + PyObject *pyfrom = Py_None; + KX_GameObject *from = nullptr; + KX_Scene *scene = KX_GetActiveScene(); + + if (!PyArg_ParseTuple(args, "s|ssO:sendMessage", &subject, &body, &to, &pyfrom)) { + return nullptr; + } - if (!PyArg_ParseTuple(args, "s|sss:sendMessage", &subject, &body, &to, &from)) - return NULL; + if (!ConvertPythonToGameObject(scene->GetLogicManager(), pyfrom, &from, true, "sendMessage(subject, [body, to, from]): \"from\" argument")) { + return nullptr; + } - gp_KetsjiScene->GetNetworkScene()->SendMessage(to, from, subject, body); + scene->GetNetworkMessageScene()->SendMessage(to, from, subject, body); Py_RETURN_NONE; } @@ -439,94 +347,101 @@ static PyObject *gPyGetSpectrum(PyObject *) static PyObject *gPySetLogicTicRate(PyObject *, PyObject *args) { float ticrate; - if (!PyArg_ParseTuple(args, "f:setLogicTicRate", &ticrate)) - return NULL; + if (!PyArg_ParseTuple(args, "f:setLogicTicRate", &ticrate)) { + return nullptr; + } - KX_KetsjiEngine::SetTicRate(ticrate); + KX_GetActiveEngine()->SetTicRate(ticrate); Py_RETURN_NONE; } static PyObject *gPyGetLogicTicRate(PyObject *) { - return PyFloat_FromDouble(KX_KetsjiEngine::GetTicRate()); + return PyFloat_FromDouble(KX_GetActiveEngine()->GetTicRate()); } static PyObject *gPySetExitKey(PyObject *, PyObject *args) { short exitkey; - if (!PyArg_ParseTuple(args, "h:setExitKey", &exitkey)) - return NULL; - KX_KetsjiEngine::SetExitKey(exitkey); + if (!PyArg_ParseTuple(args, "h:setExitKey", &exitkey)) { + return nullptr; + } + KX_GetActiveEngine()->SetExitKey((SCA_IInputDevice::SCA_EnumInputs)exitkey); Py_RETURN_NONE; } static PyObject *gPyGetExitKey(PyObject *) { - return PyLong_FromLong(KX_KetsjiEngine::GetExitKey()); + return PyLong_FromLong(KX_GetActiveEngine()->GetExitKey()); } static PyObject *gPySetRender(PyObject *, PyObject *args) { int render; - if (!PyArg_ParseTuple(args, "i:setRender", &render)) - return NULL; - KX_KetsjiEngine::SetRender(render); + if (!PyArg_ParseTuple(args, "i:setRender", &render)) { + return nullptr; + } + KX_GetActiveEngine()->SetRender(render); Py_RETURN_NONE; } static PyObject *gPyGetRender(PyObject *) { - return PyBool_FromLong(KX_KetsjiEngine::GetRender()); + return PyBool_FromLong(KX_GetActiveEngine()->GetRender()); } static PyObject *gPySetMaxLogicFrame(PyObject *, PyObject *args) { int frame; - if (!PyArg_ParseTuple(args, "i:setMaxLogicFrame", &frame)) - return NULL; + if (!PyArg_ParseTuple(args, "i:setMaxLogicFrame", &frame)) { + return nullptr; + } - KX_KetsjiEngine::SetMaxLogicFrame(frame); + KX_GetActiveEngine()->SetMaxLogicFrame(frame); Py_RETURN_NONE; } static PyObject *gPyGetMaxLogicFrame(PyObject *) { - return PyLong_FromLong(KX_KetsjiEngine::GetMaxLogicFrame()); + return PyLong_FromLong(KX_GetActiveEngine()->GetMaxLogicFrame()); } static PyObject *gPySetMaxPhysicsFrame(PyObject *, PyObject *args) { int frame; - if (!PyArg_ParseTuple(args, "i:setMaxPhysicsFrame", &frame)) - return NULL; + if (!PyArg_ParseTuple(args, "i:setMaxPhysicsFrame", &frame)) { + return nullptr; + } - KX_KetsjiEngine::SetMaxPhysicsFrame(frame); + KX_GetActiveEngine()->SetMaxPhysicsFrame(frame); Py_RETURN_NONE; } static PyObject *gPyGetMaxPhysicsFrame(PyObject *) { - return PyLong_FromLong(KX_KetsjiEngine::GetMaxPhysicsFrame()); + return PyLong_FromLong(KX_GetActiveEngine()->GetMaxPhysicsFrame()); } static PyObject *gPySetPhysicsTicRate(PyObject *, PyObject *args) { float ticrate; - if (!PyArg_ParseTuple(args, "f:setPhysicsTicRate", &ticrate)) - return NULL; + if (!PyArg_ParseTuple(args, "f:setPhysicsTicRate", &ticrate)) { + return nullptr; + } - PHY_GetActiveEnvironment()->SetFixedTimeStep(true,ticrate); + KX_GetPhysicsEnvironment()->SetFixedTimeStep(true, ticrate); Py_RETURN_NONE; } #if 0 // unused static PyObject *gPySetPhysicsDebug(PyObject *, PyObject *args) { int debugMode; - if (!PyArg_ParseTuple(args, "i:setPhysicsDebug", &debugMode)) - return NULL; + if (!PyArg_ParseTuple(args, "i:setPhysicsDebug", &debugMode)) { + return nullptr; + } - PHY_GetActiveEnvironment()->setDebugMode(debugMode); + KX_GetPhysicsEnvironment()->setDebugMode(debugMode); Py_RETURN_NONE; } #endif @@ -534,122 +449,106 @@ static PyObject *gPySetPhysicsDebug(PyObject *, PyObject *args) static PyObject *gPyGetPhysicsTicRate(PyObject *) { - return PyFloat_FromDouble(PHY_GetActiveEnvironment()->GetFixedTimeStep()); -} - -static PyObject *gPySetAnimRecordFrame(PyObject *, PyObject *args) -{ - int anim_record_frame; - - if (!PyArg_ParseTuple(args, "i:setAnimRecordFrame", &anim_record_frame)) - return NULL; - - if (anim_record_frame < 0 && (U.flag & USER_NONEGFRAMES)) { - PyErr_Format(PyExc_ValueError, "Frame number must be non-negative (was %i).", anim_record_frame); - return NULL; - } - - gp_KetsjiEngine->setAnimRecordFrame(anim_record_frame); - Py_RETURN_NONE; -} - -static PyObject *gPyGetAnimRecordFrame(PyObject *) -{ - return PyLong_FromLong(gp_KetsjiEngine->getAnimRecordFrame()); + return PyFloat_FromDouble(KX_GetPhysicsEnvironment()->GetFixedTimeStep()); } static PyObject *gPyGetAverageFrameRate(PyObject *) { - return PyFloat_FromDouble(KX_KetsjiEngine::GetAverageFrameRate()); + return PyFloat_FromDouble(KX_GetActiveEngine()->GetAverageFrameRate()); } static PyObject *gPyGetUseExternalClock(PyObject *) { - return PyBool_FromLong(gp_KetsjiEngine->GetUseExternalClock()); + return PyBool_FromLong(KX_GetActiveEngine()->GetFlag(KX_KetsjiEngine::USE_EXTERNAL_CLOCK)); } static PyObject *gPySetUseExternalClock(PyObject *, PyObject *args) { - bool bUseExternalClock; + int bUseExternalClock; - if (!PyArg_ParseTuple(args, "p:setUseExternalClock", &bUseExternalClock)) - return NULL; + if (!PyArg_ParseTuple(args, "p:setUseExternalClock", &bUseExternalClock)) { + return nullptr; + } - gp_KetsjiEngine->SetUseExternalClock(bUseExternalClock); + KX_GetActiveEngine()->SetFlag(KX_KetsjiEngine::USE_EXTERNAL_CLOCK, (bool)bUseExternalClock); Py_RETURN_NONE; } static PyObject *gPyGetClockTime(PyObject *) { - return PyFloat_FromDouble(gp_KetsjiEngine->GetClockTime()); + return PyFloat_FromDouble(KX_GetActiveEngine()->GetClockTime()); } static PyObject *gPySetClockTime(PyObject *, PyObject *args) { double externalClockTime; - if (!PyArg_ParseTuple(args, "d:setClockTime", &externalClockTime)) - return NULL; + if (!PyArg_ParseTuple(args, "d:setClockTime", &externalClockTime)) { + return nullptr; + } - gp_KetsjiEngine->SetClockTime(externalClockTime); + KX_GetActiveEngine()->SetClockTime(externalClockTime); Py_RETURN_NONE; } static PyObject *gPyGetFrameTime(PyObject *) { - return PyFloat_FromDouble(gp_KetsjiEngine->GetFrameTime()); + return PyFloat_FromDouble(KX_GetActiveEngine()->GetFrameTime()); } static PyObject *gPyGetRealTime(PyObject *) { - return PyFloat_FromDouble(gp_KetsjiEngine->GetRealTime()); + return PyFloat_FromDouble(KX_GetActiveEngine()->GetRealTime()); } static PyObject *gPyGetTimeScale(PyObject *) { - return PyFloat_FromDouble(gp_KetsjiEngine->GetTimeScale()); + return PyFloat_FromDouble(KX_GetActiveEngine()->GetTimeScale()); } static PyObject *gPySetTimeScale(PyObject *, PyObject *args) { double time_scale; - if (!PyArg_ParseTuple(args, "d:setTimeScale", &time_scale)) - return NULL; + if (!PyArg_ParseTuple(args, "d:setTimeScale", &time_scale)) { + return nullptr; + } - gp_KetsjiEngine->SetTimeScale(time_scale); + KX_GetActiveEngine()->SetTimeScale(time_scale); Py_RETURN_NONE; } static PyObject *gPyGetBlendFileList(PyObject *, PyObject *args) { - char cpath[sizeof(gp_GamePythonPath)]; - char *searchpath = NULL; + char cpath[FILE_MAX]; + char *searchpath = nullptr; PyObject *list, *value; DIR *dp; struct dirent *dirp; - if (!PyArg_ParseTuple(args, "|s:getBlendFileList", &searchpath)) - return NULL; + if (!PyArg_ParseTuple(args, "|s:getBlendFileList", &searchpath)) { + return nullptr; + } list = PyList_New(0); if (searchpath) { BLI_strncpy(cpath, searchpath, FILE_MAX); - BLI_path_abs(cpath, gp_GamePythonPath); - } else { + BLI_path_abs(cpath, KX_GetMainPath().c_str()); + } + else { /* Get the dir only */ - BLI_split_dir_part(gp_GamePythonPath, cpath, sizeof(cpath)); + BLI_split_dir_part(KX_GetMainPath().c_str(), cpath, sizeof(cpath)); } - if ((dp = opendir(cpath)) == NULL) { + if ((dp = opendir(cpath)) == nullptr) { /* todo, show the errno, this shouldnt happen anyway if the blendfile is readable */ - fprintf(stderr, "Could not read directory (%s) failed, code %d (%s)\n", cpath, errno, strerror(errno)); + CM_Error("could not read directory (" << cpath << ") failed, code " << errno << " (" << strerror(errno) << ")"); return list; } - while ((dirp = readdir(dp)) != NULL) { + while ((dirp = readdir(dp)) != nullptr) { if (BLI_path_extension_check(dirp->d_name, ".blend")) { value = PyC_UnicodeFromByte(dirp->d_name); PyList_Append(list, value); @@ -662,116 +561,131 @@ static PyObject *gPyGetBlendFileList(PyObject *, PyObject *args) } PyDoc_STRVAR(gPyAddScene_doc, -"addScene(name, [overlay])\n" -"Adds a scene to the game engine.\n" -" name = Name of the scene\n" -" overlay = Overlay or underlay" -); + "addScene(name, [overlay])\n" + "Adds a scene to the game engine.\n" + " name = Name of the scene\n" + " overlay = Overlay or underlay" + ); static PyObject *gPyAddScene(PyObject *, PyObject *args) { - char* name; + char *name; int overlay = 1; - if (!PyArg_ParseTuple(args, "s|i:addScene", &name , &overlay)) - return NULL; + if (!PyArg_ParseTuple(args, "s|i:addScene", &name, &overlay)) { + return nullptr; + } - gp_KetsjiEngine->ConvertAndAddScene(name, (overlay != 0)); + KX_GetActiveEngine()->ConvertAndAddScene(name, (overlay != 0)); Py_RETURN_NONE; } PyDoc_STRVAR(gPyGetCurrentScene_doc, -"getCurrentScene()\n" -"Gets a reference to the current scene." -); + "getCurrentScene()\n" + "Gets a reference to the current scene." + ); static PyObject *gPyGetCurrentScene(PyObject *self) { - return gp_KetsjiScene->GetProxy(); + return KX_GetActiveScene()->GetProxy(); } PyDoc_STRVAR(gPyGetSceneList_doc, -"getSceneList()\n" -"Return a list of converted scenes." -); + "getSceneList()\n" + "Return a list of converted scenes." + ); static PyObject *gPyGetSceneList(PyObject *self) { - KX_KetsjiEngine* m_engine = KX_GetActiveEngine(); - PyObject *list; - KX_SceneList* scenes = m_engine->CurrentScenes(); - int numScenes = scenes->size(); - int i; - - list = PyList_New(numScenes); + return KX_GetActiveEngine()->CurrentScenes()->GetProxy(); +} - for (i=0;iat(i); - PyList_SET_ITEM(list, i, scene->GetProxy()); - } +PyDoc_STRVAR(gPyGetInactiveSceneNames_doc, + "getInactiveSceneNames()\n" + "Get all inactive scenes names" + ); +static PyObject *gPyGetInactiveSceneNames(PyObject *self) +{ + EXP_ListValue *list = KX_GetActiveEngine()->GetConverter()->GetInactiveSceneNames(); - return list; + return list->NewProxy(true); } -static PyObject *pyPrintStats(PyObject *,PyObject *,PyObject *) + + +static PyObject *pyPrintStats(PyObject *, PyObject *, PyObject *) { - gp_KetsjiScene->GetSceneConverter()->PrintStats(); + KX_GetActiveEngine()->GetConverter()->PrintStats(); Py_RETURN_NONE; } -static PyObject *pyPrintExt(PyObject *,PyObject *,PyObject *) +static PyObject *pyPrintExt(PyObject *, PyObject *, PyObject *) { - if (gp_Rasterizer) - gp_Rasterizer->PrintHardwareInfo(); - else - printf("Warning: no rasterizer detected for PrintGLInfo!\n"); + RAS_Rasterizer *rasterizer = KX_GetActiveEngine()->GetRasterizer(); + if (rasterizer) { + rasterizer->PrintHardwareInfo(); + } + else { + CM_Error("no rasterizer detected for PrintGLInfo!"); + } Py_RETURN_NONE; } static PyObject *gLibLoad(PyObject *, PyObject *args, PyObject *kwds) { - KX_Scene *kx_scene= gp_KetsjiScene; + KX_Scene *kx_scene = nullptr; + PyObject *pyscene = Py_None; char *path; char *group; Py_buffer py_buffer; - py_buffer.buf = NULL; - char *err_str= NULL; - KX_LibLoadStatus *status = NULL; + py_buffer.buf = nullptr; + char *err_str = nullptr; + KX_LibLoadStatus *status = nullptr; - short options=0; - int load_actions=0, verbose=0, load_scripts=1, async=0; + short options = 0; + int load_actions = 0, verbose = 0, load_scripts = 1, asynchronous = 0; - static const char *kwlist[] = {"path", "group", "buffer", "load_actions", "verbose", "load_scripts", "async", NULL}; + if (!EXP_ParseTupleArgsAndKeywords(args, kwds, "ss|y*iiIiO:LibLoad", + {"path", "group", "buffer", "load_actions", "verbose", "load_scripts", "asynchronous", "scene", 0}, + &path, &group, &py_buffer, &load_actions, &verbose, &load_scripts, &asynchronous, &pyscene)) { + return nullptr; + } - if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss|y*iiIi:LibLoad", const_cast(kwlist), - &path, &group, &py_buffer, &load_actions, &verbose, &load_scripts, &async)) - return NULL; + if (!ConvertPythonToScene(pyscene, &kx_scene, true, "invalid scene")) { + return nullptr; + } + if (!kx_scene) { + kx_scene = KX_GetActiveScene(); + } /* setup options */ - if (load_actions != 0) - options |= KX_BlenderSceneConverter::LIB_LOAD_LOAD_ACTIONS; - if (verbose != 0) - options |= KX_BlenderSceneConverter::LIB_LOAD_VERBOSE; - if (load_scripts != 0) - options |= KX_BlenderSceneConverter::LIB_LOAD_LOAD_SCRIPTS; - if (async != 0) - options |= KX_BlenderSceneConverter::LIB_LOAD_ASYNC; - - if (!py_buffer.buf) - { + if (load_actions != 0) { + options |= BL_Converter::LIB_LOAD_LOAD_ACTIONS; + } + if (verbose != 0) { + options |= BL_Converter::LIB_LOAD_VERBOSE; + } + if (load_scripts != 0) { + options |= BL_Converter::LIB_LOAD_LOAD_SCRIPTS; + } + if (asynchronous != 0) { + options |= BL_Converter::LIB_LOAD_ASYNC; + } + + BL_Converter *converter = KX_GetActiveEngine()->GetConverter(); + + if (!py_buffer.buf) { char abs_path[FILE_MAX]; // Make the path absolute BLI_strncpy(abs_path, path, sizeof(abs_path)); - BLI_path_abs(abs_path, gp_GamePythonPath); + BLI_path_abs(abs_path, KX_GetMainPath().c_str()); - if ((status=kx_scene->GetSceneConverter()->LinkBlendFilePath(abs_path, group, kx_scene, &err_str, options))) { + if ((status = converter->LinkBlendFilePath(abs_path, group, kx_scene, &err_str, options))) { return status->GetProxy(); } } - else - { + else { - if ((status=kx_scene->GetSceneConverter()->LinkBlendFileMemory(py_buffer.buf, py_buffer.len, path, group, kx_scene, &err_str, options))) { + if ((status = converter->LinkBlendFileMemory(py_buffer.buf, py_buffer.len, path, group, kx_scene, &err_str, options))) { PyBuffer_Release(&py_buffer); return status->GetProxy(); } @@ -781,7 +695,7 @@ static PyObject *gLibLoad(PyObject *, PyObject *args, PyObject *kwds) if (err_str) { PyErr_SetString(PyExc_ValueError, err_str); - return NULL; + return nullptr; } Py_RETURN_FALSE; @@ -789,45 +703,41 @@ static PyObject *gLibLoad(PyObject *, PyObject *args, PyObject *kwds) static PyObject *gLibNew(PyObject *, PyObject *args) { - KX_Scene *kx_scene= gp_KetsjiScene; + KX_Scene *kx_scene = KX_GetActiveScene(); char *path; char *group; const char *name; PyObject *names; int idcode; - if (!PyArg_ParseTuple(args,"ssO!:LibNew",&path, &group, &PyList_Type, &names)) - return NULL; + if (!PyArg_ParseTuple(args, "ssO!:LibNew", &path, &group, &PyList_Type, &names)) { + return nullptr; + } - if (kx_scene->GetSceneConverter()->GetMainDynamicPath(path)) - { + BL_Converter *converter = KX_GetActiveEngine()->GetConverter(); + + if (converter->ExistLibrary(path)) { PyErr_SetString(PyExc_KeyError, "the name of the path given exists"); - return NULL; + return nullptr; } - idcode= BKE_idcode_from_name(group); - if (idcode==0) { + idcode = BKE_idcode_from_name(group); + if (idcode == 0) { PyErr_Format(PyExc_ValueError, "invalid group given \"%s\"", group); - return NULL; + return nullptr; } - Main *maggie=BKE_main_new(); - kx_scene->GetSceneConverter()->GetMainDynamic().push_back(maggie); - strncpy(maggie->name, path, sizeof(maggie->name)-1); + Main *maggie = converter->CreateLibrary(path); /* Copy the object into main */ - if (idcode==ID_ME) { - PyObject *ret= PyList_New(0); - PyObject *item; - for (Py_ssize_t i= 0; i < PyList_GET_SIZE(names); i++) { - name= _PyUnicode_AsString(PyList_GET_ITEM(names, i)); + if (idcode == ID_ME) { + PyObject *ret = PyList_New(0); + for (Py_ssize_t i = 0; i < PyList_GET_SIZE(names); i++) { + name = _PyUnicode_AsString(PyList_GET_ITEM(names, i)); if (name) { - RAS_MeshObject *meshobj= kx_scene->GetSceneConverter()->ConvertMeshSpecial(kx_scene, maggie, name); - if (meshobj) { - KX_MeshProxy* meshproxy = new KX_MeshProxy(meshobj); - item= meshproxy->NewProxy(true); - PyList_Append(ret, item); - Py_DECREF(item); + KX_Mesh *mesh = converter->ConvertMeshSpecial(kx_scene, maggie, name); + if (mesh) { + PyList_Append(ret, mesh->GetProxy()); } } else { @@ -839,7 +749,7 @@ static PyObject *gLibNew(PyObject *, PyObject *args) } else { PyErr_Format(PyExc_ValueError, "only \"Mesh\" group currently supported"); - return NULL; + return nullptr; } Py_RETURN_NONE; @@ -847,14 +757,13 @@ static PyObject *gLibNew(PyObject *, PyObject *args) static PyObject *gLibFree(PyObject *, PyObject *args) { - KX_Scene *kx_scene= gp_KetsjiScene; char *path; - if (!PyArg_ParseTuple(args,"s:LibFree",&path)) - return NULL; + if (!PyArg_ParseTuple(args, "s:LibFree", &path)) { + return nullptr; + } - if (kx_scene->GetSceneConverter()->FreeBlendFile(path)) - { + if (KX_GetActiveEngine()->GetConverter()->FreeBlendFile(path)) { Py_RETURN_TRUE; } else { @@ -864,13 +773,11 @@ static PyObject *gLibFree(PyObject *, PyObject *args) static PyObject *gLibList(PyObject *, PyObject *args) { - vector &dynMaggie = gp_KetsjiScene->GetSceneConverter()->GetMainDynamic(); - int i= 0; - PyObject *list= PyList_New(dynMaggie.size()); + const std::vector names = KX_GetActiveEngine()->GetConverter()->GetLibraryNames(); + PyObject *list = PyList_New(names.size()); - for (vector::iterator it=dynMaggie.begin(); !(it==dynMaggie.end()); it++) - { - PyList_SET_ITEM(list, i++, PyUnicode_FromString( (*it)->name) ); + for (unsigned short i = 0, size = names.size(); i < size; ++i) { + PyList_SET_ITEM(list, i, PyUnicode_FromStdString(names[i])); } return list; @@ -879,15 +786,17 @@ static PyObject *gLibList(PyObject *, PyObject *args) struct PyNextFrameState pynextframestate; static PyObject *gPyNextFrame(PyObject *) { - if (pynextframestate.func == NULL) Py_RETURN_NONE; - if (pynextframestate.state == NULL) Py_RETURN_NONE; //should never happen; raise exception instead? + if (pynextframestate.func == nullptr) { + Py_RETURN_NONE; + } + if (pynextframestate.state == nullptr) { + Py_RETURN_NONE; //should never happen; raise exception instead? - if (pynextframestate.func(pynextframestate.state)) //nonzero = stop - { + } + if (pynextframestate.func(pynextframestate.state)) { //nonzero = stop Py_RETURN_TRUE; } - else // 0 = go on - { + else { // 0 = go on Py_RETURN_FALSE; } } @@ -901,78 +810,93 @@ static struct PyMethodDef game_methods[] = { {"saveGlobalDict", (PyCFunction)gPySaveGlobalDict, METH_NOARGS, (const char *)gPySaveGlobalDict_doc}, {"loadGlobalDict", (PyCFunction)gPyLoadGlobalDict, METH_NOARGS, (const char *)gPyLoadGlobalDict_doc}, {"sendMessage", (PyCFunction)gPySendMessage, METH_VARARGS, (const char *)gPySendMessage_doc}, - {"getCurrentController", (PyCFunction) SCA_PythonController::sPyGetCurrentController, METH_NOARGS, SCA_PythonController::sPyGetCurrentController__doc__}, - {"getCurrentScene", (PyCFunction) gPyGetCurrentScene, METH_NOARGS, gPyGetCurrentScene_doc}, - {"getSceneList", (PyCFunction) gPyGetSceneList, METH_NOARGS, (const char *)gPyGetSceneList_doc}, + {"getCurrentController", (PyCFunction)SCA_PythonController::sPyGetCurrentController, METH_NOARGS, SCA_PythonController::sPyGetCurrentController__doc__}, + {"getCurrentScene", (PyCFunction)gPyGetCurrentScene, METH_NOARGS, gPyGetCurrentScene_doc}, + {"getInactiveSceneNames", (PyCFunction)gPyGetInactiveSceneNames, METH_NOARGS, (const char *)gPyGetInactiveSceneNames_doc}, + {"getSceneList", (PyCFunction)gPyGetSceneList, METH_NOARGS, (const char *)gPyGetSceneList_doc}, {"addScene", (PyCFunction)gPyAddScene, METH_VARARGS, (const char *)gPyAddScene_doc}, - {"getRandomFloat",(PyCFunction) gPyGetRandomFloat, METH_NOARGS, (const char *)gPyGetRandomFloat_doc}, - {"setGravity",(PyCFunction) gPySetGravity, METH_O, (const char *)"set Gravitation"}, - {"getSpectrum",(PyCFunction) gPyGetSpectrum, METH_NOARGS, (const char *)"get audio spectrum"}, - {"getMaxLogicFrame", (PyCFunction) gPyGetMaxLogicFrame, METH_NOARGS, (const char *)"Gets the max number of logic frame per render frame"}, - {"setMaxLogicFrame", (PyCFunction) gPySetMaxLogicFrame, METH_VARARGS, (const char *)"Sets the max number of logic frame per render frame"}, - {"getMaxPhysicsFrame", (PyCFunction) gPyGetMaxPhysicsFrame, METH_NOARGS, (const char *)"Gets the max number of physics frame per render frame"}, - {"setMaxPhysicsFrame", (PyCFunction) gPySetMaxPhysicsFrame, METH_VARARGS, (const char *)"Sets the max number of physics farme per render frame"}, - {"getLogicTicRate", (PyCFunction) gPyGetLogicTicRate, METH_NOARGS, (const char *)"Gets the logic tic rate"}, - {"setLogicTicRate", (PyCFunction) gPySetLogicTicRate, METH_VARARGS, (const char *)"Sets the logic tic rate"}, - {"getPhysicsTicRate", (PyCFunction) gPyGetPhysicsTicRate, METH_NOARGS, (const char *)"Gets the physics tic rate"}, - {"setPhysicsTicRate", (PyCFunction) gPySetPhysicsTicRate, METH_VARARGS, (const char *)"Sets the physics tic rate"}, - {"getAnimRecordFrame", (PyCFunction) gPyGetAnimRecordFrame, METH_NOARGS, (const char *)"Gets the current frame number used for animation recording"}, - {"setAnimRecordFrame", (PyCFunction) gPySetAnimRecordFrame, METH_VARARGS, (const char *)"Sets the current frame number used for animation recording"}, - {"getExitKey", (PyCFunction) gPyGetExitKey, METH_NOARGS, (const char *)"Gets the key used to exit the game engine"}, - {"setExitKey", (PyCFunction) gPySetExitKey, METH_VARARGS, (const char *)"Sets the key used to exit the game engine"}, - {"setRender", (PyCFunction) gPySetRender, METH_VARARGS, (const char *)"Set the global render flag"}, - {"getRender", (PyCFunction) gPyGetRender, METH_NOARGS, (const char *)"get the global render flag value"}, - {"getUseExternalClock", (PyCFunction) gPyGetUseExternalClock, METH_NOARGS, (const char *)"Get if we use the time provided by an external clock"}, - {"setUseExternalClock", (PyCFunction) gPySetUseExternalClock, METH_VARARGS, (const char *)"Set if we use the time provided by an external clock"}, - {"getClockTime", (PyCFunction) gPyGetClockTime, METH_NOARGS, (const char *)"Get the last BGE render time. " - "The BGE render time is the simulated time corresponding to the next scene that will be renderered"}, - {"setClockTime", (PyCFunction) gPySetClockTime, METH_VARARGS, (const char *)"Set the BGE render time. " - "The BGE render time is the simulated time corresponding to the next scene that will be rendered"}, - {"getFrameTime", (PyCFunction) gPyGetFrameTime, METH_NOARGS, (const char *)"Get the BGE last frametime. " - "The BGE frame time is the simulated time corresponding to the last call of the logic system"}, - {"getRealTime", (PyCFunction) gPyGetRealTime, METH_NOARGS, (const char *)"Get the real system time. " - "The real-time corresponds to the system time" }, - {"getAverageFrameRate", (PyCFunction) gPyGetAverageFrameRate, METH_NOARGS, (const char *)"Gets the estimated average frame rate"}, - {"getTimeScale", (PyCFunction) gPyGetTimeScale, METH_NOARGS, (const char *)"Get the time multiplier"}, - {"setTimeScale", (PyCFunction) gPySetTimeScale, METH_VARARGS, (const char *)"Set the time multiplier"}, + {"getRandomFloat", (PyCFunction)gPyGetRandomFloat, METH_NOARGS, (const char *)gPyGetRandomFloat_doc}, + {"setGravity", (PyCFunction)gPySetGravity, METH_O, (const char *)"set Gravitation"}, + {"getSpectrum", (PyCFunction)gPyGetSpectrum, METH_NOARGS, (const char *)"get audio spectrum"}, + {"getMaxLogicFrame", (PyCFunction)gPyGetMaxLogicFrame, METH_NOARGS, (const char *)"Gets the max number of logic frame per render frame"}, + {"setMaxLogicFrame", (PyCFunction)gPySetMaxLogicFrame, METH_VARARGS, (const char *)"Sets the max number of logic frame per render frame"}, + {"getMaxPhysicsFrame", (PyCFunction)gPyGetMaxPhysicsFrame, METH_NOARGS, (const char *)"Gets the max number of physics frame per render frame"}, + {"setMaxPhysicsFrame", (PyCFunction)gPySetMaxPhysicsFrame, METH_VARARGS, (const char *)"Sets the max number of physics farme per render frame"}, + {"getLogicTicRate", (PyCFunction)gPyGetLogicTicRate, METH_NOARGS, (const char *)"Gets the logic tic rate"}, + {"setLogicTicRate", (PyCFunction)gPySetLogicTicRate, METH_VARARGS, (const char *)"Sets the logic tic rate"}, + {"getPhysicsTicRate", (PyCFunction)gPyGetPhysicsTicRate, METH_NOARGS, (const char *)"Gets the physics tic rate"}, + {"setPhysicsTicRate", (PyCFunction)gPySetPhysicsTicRate, METH_VARARGS, (const char *)"Sets the physics tic rate"}, + {"getExitKey", (PyCFunction)gPyGetExitKey, METH_NOARGS, (const char *)"Gets the key used to exit the game engine"}, + {"setExitKey", (PyCFunction)gPySetExitKey, METH_VARARGS, (const char *)"Sets the key used to exit the game engine"}, + {"setRender", (PyCFunction)gPySetRender, METH_VARARGS, (const char *)"Set the global render flag"}, + {"getRender", (PyCFunction)gPyGetRender, METH_NOARGS, (const char *)"get the global render flag value"}, + {"getUseExternalClock", (PyCFunction)gPyGetUseExternalClock, METH_NOARGS, (const char *)"Get if we use the time provided by an external clock"}, + {"setUseExternalClock", (PyCFunction)gPySetUseExternalClock, METH_VARARGS, (const char *)"Set if we use the time provided by an external clock"}, + {"getClockTime", (PyCFunction)gPyGetClockTime, METH_NOARGS, (const char *)"Get the last BGE render time. " + "The BGE render time is the simulated time corresponding to the next scene that will be renderered"}, + {"setClockTime", (PyCFunction)gPySetClockTime, METH_VARARGS, (const char *)"Set the BGE render time. " + "The BGE render time is the simulated time corresponding to the next scene that will be rendered"}, + {"getFrameTime", (PyCFunction)gPyGetFrameTime, METH_NOARGS, (const char *)"Get the BGE last frametime. " + "The BGE frame time is the simulated time corresponding to the last call of the logic system"}, + {"getRealTime", (PyCFunction)gPyGetRealTime, METH_NOARGS, (const char *)"Get the real system time. " + "The real-time corresponds to the system time" }, + {"getAverageFrameRate", (PyCFunction)gPyGetAverageFrameRate, METH_NOARGS, (const char *)"Gets the estimated average frame rate"}, + {"getTimeScale", (PyCFunction)gPyGetTimeScale, METH_NOARGS, (const char *)"Get the time multiplier"}, + {"setTimeScale", (PyCFunction)gPySetTimeScale, METH_VARARGS, (const char *)"Set the time multiplier"}, {"getBlendFileList", (PyCFunction)gPyGetBlendFileList, METH_VARARGS, (const char *)"Gets a list of blend files in the same directory as the current blend file"}, {"PrintGLInfo", (PyCFunction)pyPrintExt, METH_NOARGS, (const char *)"Prints GL Extension Info"}, {"PrintMemInfo", (PyCFunction)pyPrintStats, METH_NOARGS, (const char *)"Print engine statistics"}, {"NextFrame", (PyCFunction)gPyNextFrame, METH_NOARGS, (const char *)"Render next frame (if Python has control)"}, {"getProfileInfo", (PyCFunction)gPyGetProfileInfo, METH_NOARGS, gPyGetProfileInfo_doc}, /* library functions */ - {"LibLoad", (PyCFunction)gLibLoad, METH_VARARGS|METH_KEYWORDS, (const char *)""}, + {"LibLoad", (PyCFunction)gLibLoad, METH_VARARGS | METH_KEYWORDS, (const char *)""}, {"LibNew", (PyCFunction)gLibNew, METH_VARARGS, (const char *)""}, {"LibFree", (PyCFunction)gLibFree, METH_VARARGS, (const char *)""}, {"LibList", (PyCFunction)gLibList, METH_VARARGS, (const char *)""}, - {NULL, (PyCFunction) NULL, 0, NULL } + {nullptr, (PyCFunction)nullptr, 0, nullptr } }; static PyObject *gPyGetWindowHeight(PyObject *, PyObject *args) { - return PyLong_FromLong((gp_Canvas ? gp_Canvas->GetHeight() : 0)); + RAS_ICanvas *canvas = KX_GetActiveEngine()->GetCanvas(); + return PyLong_FromLong((canvas ? canvas->GetHeight() : 0)); } static PyObject *gPyGetWindowWidth(PyObject *, PyObject *args) { - return PyLong_FromLong((gp_Canvas ? gp_Canvas->GetWidth() : 0)); + RAS_ICanvas *canvas = KX_GetActiveEngine()->GetCanvas(); + return PyLong_FromLong((canvas ? canvas->GetWidth() : 0)); } +static PyObject *gPySetBackgroundColor(PyObject *, PyObject *value) +{ + mt::vec4 vec; + if (!PyVecTo(value, vec)) { + return nullptr; + } - -// temporarility visibility thing, will be moved to rasterizer/renderer later -bool gUseVisibilityTemp = false; + KX_WorldInfo *wi = KX_GetActiveScene()->GetWorldInfo(); + if (!wi->hasWorld()) { + PyErr_SetString(PyExc_RuntimeError, "bge.render.SetBackgroundColor(color), World not available"); + return nullptr; + } + EXP_ShowDeprecationWarning("setBackgroundColor()", "KX_WorldInfo.horizonColor/zenithColor"); + wi->setHorizonColor(vec); + wi->setZenithColor(vec); + Py_RETURN_NONE; +} static PyObject *gPyEnableVisibility(PyObject *, PyObject *args) { int visible; - if (!PyArg_ParseTuple(args,"i:enableVisibility",&visible)) - return NULL; + if (!PyArg_ParseTuple(args, "i:enableVisibility", &visible)) { + return nullptr; + } - gUseVisibilityTemp = (visible != 0); + // TODO Py_RETURN_NONE; } @@ -981,17 +905,21 @@ static PyObject *gPyEnableVisibility(PyObject *, PyObject *args) static PyObject *gPyShowMouse(PyObject *, PyObject *args) { int visible; - if (!PyArg_ParseTuple(args,"i:showMouse",&visible)) - return NULL; + if (!PyArg_ParseTuple(args, "i:showMouse", &visible)) { + return nullptr; + } - if (visible) - { - if (gp_Canvas) - gp_Canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL); - } else - { - if (gp_Canvas) - gp_Canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE); + RAS_ICanvas *canvas = KX_GetActiveEngine()->GetCanvas(); + + if (visible) { + if (canvas) { + canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL); + } + } + else { + if (canvas) { + canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE); + } } Py_RETURN_NONE; @@ -1001,12 +929,16 @@ static PyObject *gPyShowMouse(PyObject *, PyObject *args) static PyObject *gPySetMousePosition(PyObject *, PyObject *args) { - int x,y; - if (!PyArg_ParseTuple(args,"ii:setMousePosition",&x,&y)) - return NULL; + int x, y; + if (!PyArg_ParseTuple(args, "ii:setMousePosition", &x, &y)) { + return nullptr; + } - if (gp_Canvas) - gp_Canvas->SetMousePosition(x,y); + RAS_ICanvas *canvas = KX_GetActiveEngine()->GetCanvas(); + + if (canvas) { + canvas->SetMousePosition(x, y); + } Py_RETURN_NONE; } @@ -1014,99 +946,84 @@ static PyObject *gPySetMousePosition(PyObject *, PyObject *args) static PyObject *gPySetEyeSeparation(PyObject *, PyObject *args) { float sep; - if (!PyArg_ParseTuple(args, "f:setEyeSeparation", &sep)) - return NULL; + if (!PyArg_ParseTuple(args, "f:setEyeSeparation", &sep)) { + return nullptr; + } - if (!gp_Rasterizer) { + if (!KX_GetActiveEngine()->GetRasterizer()) { PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setEyeSeparation(float), Rasterizer not available"); - return NULL; + return nullptr; } - gp_Rasterizer->SetEyeSeparation(sep); + KX_GetActiveEngine()->GetRasterizer()->SetEyeSeparation(sep); Py_RETURN_NONE; } static PyObject *gPyGetEyeSeparation(PyObject *) { - if (!gp_Rasterizer) { + if (!KX_GetActiveEngine()->GetRasterizer()) { PyErr_SetString(PyExc_RuntimeError, "Rasterizer.getEyeSeparation(), Rasterizer not available"); - return NULL; + return nullptr; } - return PyFloat_FromDouble(gp_Rasterizer->GetEyeSeparation()); + return PyFloat_FromDouble(KX_GetActiveEngine()->GetRasterizer()->GetEyeSeparation()); } static PyObject *gPySetFocalLength(PyObject *, PyObject *args) { float focus; - if (!PyArg_ParseTuple(args, "f:setFocalLength", &focus)) - return NULL; + if (!PyArg_ParseTuple(args, "f:setFocalLength", &focus)) { + return nullptr; + } - if (!gp_Rasterizer) { + if (!KX_GetActiveEngine()->GetRasterizer()) { PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setFocalLength(float), Rasterizer not available"); - return NULL; + return nullptr; } - gp_Rasterizer->SetFocalLength(focus); + KX_GetActiveEngine()->GetRasterizer()->SetFocalLength(focus); Py_RETURN_NONE; } static PyObject *gPyGetFocalLength(PyObject *, PyObject *, PyObject *) { - if (!gp_Rasterizer) { + if (!KX_GetActiveEngine()->GetRasterizer()) { PyErr_SetString(PyExc_RuntimeError, "Rasterizer.getFocalLength(), Rasterizer not available"); - return NULL; + return nullptr; } - return PyFloat_FromDouble(gp_Rasterizer->GetFocalLength()); + return PyFloat_FromDouble(KX_GetActiveEngine()->GetRasterizer()->GetFocalLength()); Py_RETURN_NONE; } static PyObject *gPyGetStereoEye(PyObject *, PyObject *, PyObject *) { - int flag = RAS_IRasterizer::RAS_STEREO_LEFTEYE; + RAS_Rasterizer *rasterizer = KX_GetActiveEngine()->GetRasterizer(); - if (!gp_Rasterizer) { + if (!rasterizer) { PyErr_SetString(PyExc_RuntimeError, "Rasterizer.getStereoEye(), Rasterizer not available"); - return NULL; + return nullptr; } - if (gp_Rasterizer->Stereo()) - flag = gp_Rasterizer->GetEye(); + int flag = rasterizer->GetEye(); return PyLong_FromLong(flag); } -static PyObject *gPySetBackgroundColor(PyObject *, PyObject *value) +static PyObject *gPyMakeScreenshot(PyObject *, PyObject *args) { - MT_Vector4 vec; - if (!PyVecTo(value, vec)) - return NULL; - - KX_WorldInfo *wi = gp_KetsjiScene->GetWorldInfo(); - if (!wi->hasWorld()) { - PyErr_SetString(PyExc_RuntimeError, "bge.render.SetBackgroundColor(color), World not available"); - return NULL; + char *filename; + if (!PyArg_ParseTuple(args, "s:makeScreenshot", &filename)) { + return nullptr; } - ShowDeprecationWarning("setBackgroundColor()", "KX_WorldInfo.background_color"); - wi->setBackColor((float)vec[0], (float)vec[1], (float)vec[2]); - - Py_RETURN_NONE; -} - -static PyObject *gPyMakeScreenshot(PyObject *, PyObject *args) -{ - char* filename; - if (!PyArg_ParseTuple(args,"s:makeScreenshot",&filename)) - return NULL; + RAS_ICanvas *canvas = KX_GetActiveEngine()->GetCanvas(); - if (gp_Canvas) - { - gp_Canvas->MakeScreenShot(filename); + if (canvas) { + canvas->MakeScreenShot(filename); } Py_RETURN_NONE; @@ -1115,87 +1032,100 @@ static PyObject *gPyMakeScreenshot(PyObject *, PyObject *args) static PyObject *gPyEnableMotionBlur(PyObject *, PyObject *args) { float motionblurvalue; - if (!PyArg_ParseTuple(args,"f:enableMotionBlur",&motionblurvalue)) - return NULL; + if (!PyArg_ParseTuple(args, "f:enableMotionBlur", &motionblurvalue)) { + return nullptr; + } - if (!gp_Rasterizer) { + if (!KX_GetActiveEngine()->GetRasterizer()) { PyErr_SetString(PyExc_RuntimeError, "Rasterizer.enableMotionBlur(float), Rasterizer not available"); - return NULL; + return nullptr; } - gp_Rasterizer->EnableMotionBlur(motionblurvalue); + KX_GetActiveEngine()->GetRasterizer()->EnableMotionBlur(motionblurvalue); Py_RETURN_NONE; } static PyObject *gPyDisableMotionBlur(PyObject *) { - if (!gp_Rasterizer) { + if (!KX_GetActiveEngine()->GetRasterizer()) { PyErr_SetString(PyExc_RuntimeError, "Rasterizer.disableMotionBlur(), Rasterizer not available"); - return NULL; + return nullptr; } - gp_Rasterizer->DisableMotionBlur(); + KX_GetActiveEngine()->GetRasterizer()->DisableMotionBlur(); Py_RETURN_NONE; } -static int getGLSLSettingFlag(const char *setting) +static int getGLSLSettingFlag(const std::string& setting) { - if (strcmp(setting, "lights") == 0) + if (setting == "lights") { return GAME_GLSL_NO_LIGHTS; - else if (strcmp(setting, "shaders") == 0) + } + else if (setting == "shaders") { return GAME_GLSL_NO_SHADERS; - else if (strcmp(setting, "shadows") == 0) + } + else if (setting == "shadows") { return GAME_GLSL_NO_SHADOWS; - else if (strcmp(setting, "ramps") == 0) + } + else if (setting == "ramps") { return GAME_GLSL_NO_RAMPS; - else if (strcmp(setting, "nodes") == 0) + } + else if (setting == "nodes") { return GAME_GLSL_NO_NODES; - else if (strcmp(setting, "extra_textures") == 0) + } + else if (setting == "extra_textures") { return GAME_GLSL_NO_EXTRA_TEX; - else + } + else { return -1; + } } static PyObject *gPySetGLSLMaterialSetting(PyObject *, PyObject *args, PyObject *) { - GlobalSettings *gs= gp_KetsjiEngine->GetGlobalSettings(); + GlobalSettings *gs = KX_GetActiveEngine()->GetGlobalSettings(); char *setting; int enable, flag, sceneflag; - if (!PyArg_ParseTuple(args,"si:setGLSLMaterialSetting",&setting,&enable)) - return NULL; + if (!PyArg_ParseTuple(args, "si:setGLSLMaterialSetting", &setting, &enable)) { + return nullptr; + } flag = getGLSLSettingFlag(setting); if (flag == -1) { PyErr_SetString(PyExc_ValueError, "Rasterizer.setGLSLMaterialSetting(string): glsl setting is not known"); - return NULL; + return nullptr; } - sceneflag= gs->glslflag; + sceneflag = gs->glslflag; - if (enable) + if (enable) { gs->glslflag &= ~flag; - else + } + else { gs->glslflag |= flag; + } /* display lists and GLSL materials need to be remade */ if (sceneflag != gs->glslflag) { - GPU_materials_free(G_MAIN); - if (gp_KetsjiEngine) { - KX_SceneList *scenes = gp_KetsjiEngine->CurrentScenes(); - KX_SceneList::iterator it; + GPU_materials_free(G.main); + if (KX_GetActiveEngine()) { + EXP_ListValue *scenes = KX_GetActiveEngine()->CurrentScenes(); - for (it=scenes->begin(); it!=scenes->end(); it++) { + for (KX_Scene *scene : scenes) { // temporarily store the glsl settings in the scene for the GLSL materials - (*it)->GetBlenderScene()->gm.flag = gs->glslflag; - if ((*it)->GetBucketManager()) { - (*it)->GetBucketManager()->ReleaseDisplayLists(); - (*it)->GetBucketManager()->ReleaseMaterials(); + scene->GetBlenderScene()->gm.flag = gs->glslflag; + if (scene->GetBucketManager()) { + scene->GetBucketManager()->ReloadMaterials(); + } + KX_WorldInfo *world = scene->GetWorldInfo(); + if (world) { + world->ReloadMaterial(); } } } @@ -1208,82 +1138,65 @@ static PyObject *gPyGetGLSLMaterialSetting(PyObject *, PyObject *args, PyObject *) { - GlobalSettings *gs= gp_KetsjiEngine->GetGlobalSettings(); + GlobalSettings *gs = KX_GetActiveEngine()->GetGlobalSettings(); char *setting; int enabled = 0, flag; - if (!PyArg_ParseTuple(args,"s:getGLSLMaterialSetting",&setting)) - return NULL; + if (!PyArg_ParseTuple(args, "s:getGLSLMaterialSetting", &setting)) { + return nullptr; + } flag = getGLSLSettingFlag(setting); if (flag == -1) { PyErr_SetString(PyExc_ValueError, "Rasterizer.getGLSLMaterialSetting(string): glsl setting is not known"); - return NULL; + return nullptr; } enabled = ((gs->glslflag & flag) != 0); return PyLong_FromLong(enabled); } -#define KX_BLENDER_MULTITEX_MATERIAL 1 -#define KX_BLENDER_GLSL_MATERIAL 2 +#define KX_BLENDER_MULTITEX_MATERIAL 1 +#define KX_BLENDER_GLSL_MATERIAL 2 static PyObject *gPySetMaterialType(PyObject *, PyObject *args, PyObject *) { - GlobalSettings *gs= gp_KetsjiEngine->GetGlobalSettings(); - int type; - - if (!PyArg_ParseTuple(args,"i:setMaterialType",&type)) - return NULL; - - if (type == KX_BLENDER_GLSL_MATERIAL) - gs->matmode= GAME_MAT_GLSL; - else if (type == KX_BLENDER_MULTITEX_MATERIAL) - gs->matmode= GAME_MAT_MULTITEX; - else { - PyErr_SetString(PyExc_ValueError, "Rasterizer.setMaterialType(int): material type is not known"); - return NULL; - } + EXP_ShowDeprecationWarning("setMaterialMode(mode)", "nothing"); Py_RETURN_NONE; } static PyObject *gPyGetMaterialType(PyObject *) { - GlobalSettings *gs= gp_KetsjiEngine->GetGlobalSettings(); - int flag; - - if (gs->matmode == GAME_MAT_GLSL) - flag = KX_BLENDER_GLSL_MATERIAL; - else - flag = KX_BLENDER_MULTITEX_MATERIAL; + EXP_ShowDeprecationWarning("getMaterialMode()", "nothing"); - return PyLong_FromLong(flag); + return PyLong_FromLong(0); } static PyObject *gPySetAnisotropicFiltering(PyObject *, PyObject *args) { short level; - if (!PyArg_ParseTuple(args, "h:setAnisotropicFiltering", &level)) - return NULL; + if (!PyArg_ParseTuple(args, "h:setAnisotropicFiltering", &level)) { + return nullptr; + } if (level != 1 && level != 2 && level != 4 && level != 8 && level != 16) { PyErr_SetString(PyExc_ValueError, "Rasterizer.setAnisotropicFiltering(level): Expected value of 1, 2, 4, 8, or 16 for value"); - return NULL; + return nullptr; } - gp_Rasterizer->SetAnisotropicFiltering(level); + KX_GetActiveEngine()->GetRasterizer()->SetAnisotropicFiltering(level); Py_RETURN_NONE; } static PyObject *gPyGetAnisotropicFiltering(PyObject *, PyObject *args) { - return PyLong_FromLong(gp_Rasterizer->GetAnisotropicFiltering()); + return PyLong_FromLong(KX_GetActiveEngine()->GetRasterizer()->GetAnisotropicFiltering()); } static PyObject *gPyDrawLine(PyObject *, PyObject *args) @@ -1292,165 +1205,169 @@ static PyObject *gPyDrawLine(PyObject *, PyObject *args) PyObject *ob_to; PyObject *ob_color; - if (!gp_Rasterizer) { + if (!KX_GetActiveEngine()->GetRasterizer()) { PyErr_SetString(PyExc_RuntimeError, "Rasterizer.drawLine(obFrom, obTo, color): Rasterizer not available"); - return NULL; + return nullptr; } - if (!PyArg_ParseTuple(args,"OOO:drawLine",&ob_from,&ob_to,&ob_color)) - return NULL; + if (!PyArg_ParseTuple(args, "OOO:drawLine", &ob_from, &ob_to, &ob_color)) { + return nullptr; + } - MT_Vector3 from; - MT_Vector3 to; - MT_Vector3 color; - if (!PyVecTo(ob_from, from)) - return NULL; - if (!PyVecTo(ob_to, to)) - return NULL; - if (!PyVecTo(ob_color, color)) - return NULL; + mt::vec3 from; + mt::vec3 to; + mt::vec3 color3; + mt::vec4 color4; - gp_Rasterizer->DrawDebugLine(gp_KetsjiScene, from, to, color); + if (!PyVecTo(ob_from, from)) { + return nullptr; + } + if (!PyVecTo(ob_to, to)) { + return nullptr; + } - Py_RETURN_NONE; + // Allow conversion from vector 3d. + if (PyVecTo(ob_color, color3)) { + KX_RasterizerDrawDebugLine(from, to, mt::vec4(color3.x, color3.y, color3.z, 1.0f)); + Py_RETURN_NONE; + } + else { + // Clear error message of the conversion from vector3d. + PyErr_Clear(); + if (PyVecTo(ob_color, color4)) { + KX_RasterizerDrawDebugLine(from, to, color4); + } + Py_RETURN_NONE; + } + + return nullptr; } static PyObject *gPySetWindowSize(PyObject *, PyObject *args) { int width, height; - if (!PyArg_ParseTuple(args, "ii:resize", &width, &height)) - return NULL; + if (!PyArg_ParseTuple(args, "ii:resize", &width, &height)) { + return nullptr; + } - gp_Canvas->ResizeWindow(width, height); + KX_GetActiveEngine()->GetCanvas()->ResizeWindow(width, height); Py_RETURN_NONE; } static PyObject *gPySetFullScreen(PyObject *, PyObject *value) { - gp_Canvas->SetFullScreen(PyObject_IsTrue(value)); + KX_GetActiveEngine()->GetCanvas()->SetFullScreen(PyObject_IsTrue(value)); Py_RETURN_NONE; } static PyObject *gPyGetFullScreen(PyObject *) { - return PyBool_FromLong(gp_Canvas->GetFullScreen()); + return PyBool_FromLong(KX_GetActiveEngine()->GetCanvas()->GetFullScreen()); } static PyObject *gPySetMipmapping(PyObject *, PyObject *args) { int val = 0; - if (!PyArg_ParseTuple(args, "i:setMipmapping", &val)) - return NULL; + if (!PyArg_ParseTuple(args, "i:setMipmapping", &val)) { + return nullptr; + } - if (val < 0 || val > RAS_IRasterizer::RAS_MIPMAP_MAX) { + if (val < 0 || val > RAS_Rasterizer::RAS_MIPMAP_MAX) { PyErr_SetString(PyExc_ValueError, "Rasterizer.setMipmapping(val): invalid mipmaping option"); - return NULL; + return nullptr; } - if (!gp_Rasterizer) { + if (!KX_GetActiveEngine()->GetRasterizer()) { PyErr_SetString(PyExc_RuntimeError, "Rasterizer.setMipmapping(val): Rasterizer not available"); - return NULL; + return nullptr; } - gp_Rasterizer->SetMipmapping((RAS_IRasterizer::MipmapOption)val); + KX_GetActiveEngine()->GetRasterizer()->SetMipmapping((RAS_Rasterizer::MipmapOption)val); Py_RETURN_NONE; } static PyObject *gPyGetMipmapping(PyObject *) { - if (!gp_Rasterizer) { + if (!KX_GetActiveEngine()->GetRasterizer()) { PyErr_SetString(PyExc_RuntimeError, "Rasterizer.getMipmapping(): Rasterizer not available"); - return NULL; + return nullptr; } - return PyLong_FromLong(gp_Rasterizer->GetMipmapping()); + return PyLong_FromLong(KX_GetActiveEngine()->GetRasterizer()->GetMipmapping()); } static PyObject *gPySetVsync(PyObject *, PyObject *args) { - int interval; + int control; - if (!PyArg_ParseTuple(args, "i:setVsync", &interval)) - return NULL; + if (!PyArg_ParseTuple(args, "i:setVsync", &control)) { + return nullptr; + } - if (interval < 0 || interval > VSYNC_ADAPTIVE) { + if (control < 0 || control >= RAS_ICanvas::SWAP_CONTROL_MAX) { PyErr_SetString(PyExc_ValueError, "Rasterizer.setVsync(value): value must be VSYNC_OFF, VSYNC_ON, or VSYNC_ADAPTIVE"); - return NULL; + return nullptr; } - if (interval == VSYNC_ADAPTIVE) - interval = -1; - gp_Canvas->SetSwapInterval((interval == VSYNC_ON) ? 1 : 0); + KX_GetActiveEngine()->GetCanvas()->SetSwapControl((RAS_ICanvas::SwapControl)control); Py_RETURN_NONE; } static PyObject *gPyGetVsync(PyObject *) { - int interval = 0; - gp_Canvas->GetSwapInterval(interval); - return PyLong_FromLong(interval); + return PyLong_FromLong(KX_GetActiveEngine()->GetCanvas()->GetSwapControl()); } static PyObject *gPyShowFramerate(PyObject *, PyObject *args) { int visible; - if (!PyArg_ParseTuple(args,"i:showFramerate",&visible)) - return NULL; - - if (visible && gp_KetsjiEngine) - gp_KetsjiEngine->SetShowFramerate(true); - else - gp_KetsjiEngine->SetShowFramerate(false); + if (!PyArg_ParseTuple(args, "i:showFramerate", &visible)) { + return nullptr; + } + KX_GetActiveEngine()->SetFlag(KX_KetsjiEngine::SHOW_FRAMERATE, visible); Py_RETURN_NONE; } static PyObject *gPyShowProfile(PyObject *, PyObject *args) { int visible; - if (!PyArg_ParseTuple(args,"i:showProfile",&visible)) - return NULL; - - if (visible && gp_KetsjiEngine) - gp_KetsjiEngine->SetShowProfile(true); - else - gp_KetsjiEngine->SetShowProfile(false); + if (!PyArg_ParseTuple(args, "i:showProfile", &visible)) { + return nullptr; + } + KX_GetActiveEngine()->SetFlag(KX_KetsjiEngine::SHOW_PROFILE, visible); Py_RETURN_NONE; } static PyObject *gPyShowProperties(PyObject *, PyObject *args) { int visible; - if (!PyArg_ParseTuple(args,"i:showProperties",&visible)) - return NULL; - - if (visible && gp_KetsjiEngine) - gp_KetsjiEngine->SetShowProperties(true); - else - gp_KetsjiEngine->SetShowProperties(false); + if (!PyArg_ParseTuple(args, "i:showProperties", &visible)) { + return nullptr; + } + KX_GetActiveEngine()->SetFlag(KX_KetsjiEngine::SHOW_DEBUG_PROPERTIES, visible); Py_RETURN_NONE; } static PyObject *gPyAutoDebugList(PyObject *, PyObject *args) { int add; - if (!PyArg_ParseTuple(args,"i:autoAddProperties",&add)) - return NULL; - - if (add && gp_KetsjiEngine) - gp_KetsjiEngine->SetAutoAddDebugProperties(true); - else - gp_KetsjiEngine->SetAutoAddDebugProperties(false); + if (!PyArg_ParseTuple(args, "i:autoAddProperties", &add)) { + return nullptr; + } + KX_GetActiveEngine()->SetFlag(KX_KetsjiEngine::AUTO_ADD_DEBUG_PROPERTIES, add); Py_RETURN_NONE; } static PyObject *gPyClearDebugList(PyObject *) { - if (gp_KetsjiScene) - gp_KetsjiScene->RemoveAllDebugProperties(); + KX_Scene *scene = KX_GetActiveScene(); + if (scene) { + scene->RemoveAllDebugProperties(); + } Py_RETURN_NONE; } @@ -1460,231 +1377,78 @@ static PyObject *gPyGetDisplayDimensions(PyObject *) PyObject *result; int width, height; - gp_Canvas->GetDisplayDimensions(width, height); + KX_GetActiveEngine()->GetCanvas()->GetDisplayDimensions(width, height); result = PyTuple_New(2); PyTuple_SET_ITEMS(result, - PyLong_FromLong(width), - PyLong_FromLong(height)); + PyLong_FromLong(width), + PyLong_FromLong(height)); return result; } - -/* python wrapper around RAS_IOffScreen - * Should eventually gets its own file - */ - -static void PyRASOffScreen__tp_dealloc(PyRASOffScreen *self) -{ - if (self->ofs) - delete self->ofs; - Py_TYPE(self)->tp_free((PyObject *)self); -} - -PyDoc_STRVAR(py_RASOffScreen_doc, -"RASOffscreen(width, height) -> new GPU Offscreen object" -"initialized to hold a framebuffer object of ``width`` x ``height``.\n" -"" -); - -PyDoc_STRVAR(RASOffScreen_width_doc, "Offscreen buffer width.\n\n:type: integer"); -static PyObject *RASOffScreen_width_get(PyRASOffScreen *self, void *UNUSED(type)) -{ - return PyLong_FromLong(self->ofs->GetWidth()); -} - -PyDoc_STRVAR(RASOffScreen_height_doc, "Offscreen buffer height.\n\n:type: GLsizei"); -static PyObject *RASOffScreen_height_get(PyRASOffScreen *self, void *UNUSED(type)) -{ - return PyLong_FromLong(self->ofs->GetHeight()); -} - -PyDoc_STRVAR(RASOffScreen_color_doc, "Offscreen buffer texture object (if target is RAS_OFS_RENDER_TEXTURE).\n\n:type: GLuint"); -static PyObject *RASOffScreen_color_get(PyRASOffScreen *self, void *UNUSED(type)) -{ - return PyLong_FromLong(self->ofs->GetColor()); -} - -static PyGetSetDef RASOffScreen_getseters[] = { - {(char *)"width", (getter)RASOffScreen_width_get, (setter)NULL, RASOffScreen_width_doc, NULL}, - {(char *)"height", (getter)RASOffScreen_height_get, (setter)NULL, RASOffScreen_height_doc, NULL}, - {(char *)"color", (getter)RASOffScreen_color_get, (setter)NULL, RASOffScreen_color_doc, NULL}, - {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ -}; - -static int PyRASOffScreen__tp_init(PyRASOffScreen *self, PyObject *args, PyObject *kwargs) -{ - int width, height, samples, target; - const char *keywords[] = {"width", "height", "samples", "target", NULL}; - - samples = 0; - target = RAS_IOffScreen::RAS_OFS_RENDER_BUFFER; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|ii:RASOffscreen", (char **)keywords, &width, &height, &samples, &target)) { - return -1; - } - - if (width <= 0) { - PyErr_SetString(PyExc_ValueError, "negative 'width' given"); - return -1; - } - - if (height <= 0) { - PyErr_SetString(PyExc_ValueError, "negative 'height' given"); - return -1; - } - - if (samples < 0) { - PyErr_SetString(PyExc_ValueError, "negative 'samples' given"); - return -1; - } - - if (target != RAS_IOffScreen::RAS_OFS_RENDER_BUFFER && target != RAS_IOffScreen::RAS_OFS_RENDER_TEXTURE) - { - PyErr_SetString(PyExc_ValueError, "invalid 'target' given, can only be RAS_OFS_RENDER_BUFFER or RAS_OFS_RENDER_TEXTURE"); - return -1; - } - if (!gp_Rasterizer) - { - PyErr_SetString(PyExc_SystemError, "no rasterizer"); - return -1; - } - self->ofs = gp_Rasterizer->CreateOffScreen(width, height, samples, target); - if (!self->ofs) { - PyErr_SetString(PyExc_SystemError, "creation failed"); - return -1; - } - return 0; -} - -PyTypeObject PyRASOffScreen_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "RASOffScreen", /* tp_name */ - sizeof(PyRASOffScreen), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)PyRASOffScreen__tp_dealloc, /* tp_dealloc */ - NULL, /* tp_print */ - NULL, /* tp_getattr */ - NULL, /* tp_setattr */ - NULL, /* tp_compare */ - NULL, /* tp_repr */ - NULL, /* tp_as_number */ - NULL, /* tp_as_sequence */ - NULL, /* tp_as_mapping */ - NULL, /* tp_hash */ - NULL, /* tp_call */ - NULL, /* tp_str */ - NULL, /* tp_getattro */ - NULL, /* tp_setattro */ - NULL, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - py_RASOffScreen_doc, /* Documentation string */ - NULL, /* tp_traverse */ - NULL, /* tp_clear */ - NULL, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - NULL, /* tp_iter */ - NULL, /* tp_iternext */ - NULL, /* tp_methods */ - NULL, /* tp_members */ - RASOffScreen_getseters, /* tp_getset */ - NULL, /* tp_base */ - NULL, /* tp_dict */ - NULL, /* tp_descr_get */ - NULL, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)PyRASOffScreen__tp_init, /* tp_init */ - (allocfunc)PyType_GenericAlloc, /* tp_alloc */ - (newfunc)PyType_GenericNew, /* tp_new */ - (freefunc)0, /* tp_free */ - NULL, /* tp_is_gc */ - NULL, /* tp_bases */ - NULL, /* tp_mro */ - NULL, /* tp_cache */ - NULL, /* tp_subclasses */ - NULL, /* tp_weaklist */ - (destructor) NULL /* tp_del */ -}; - - -static PyObject *gPyOffScreenCreate(PyObject *UNUSED(self), PyObject *args) -{ - int width; - int height; - int samples; - int target; - - samples = 0; - if (!PyArg_ParseTuple(args, "ii|ii:offScreenCreate", &width, &height, &samples, &target)) - return NULL; - - return PyObject_CallObject((PyObject *) &PyRASOffScreen_Type, args); -} - PyDoc_STRVAR(Rasterizer_module_documentation, -"This is the Python API for the game engine of Rasterizer" -); + "This is the Python API for the game engine of Rasterizer" + ); static struct PyMethodDef rasterizer_methods[] = { - {"getWindowWidth",(PyCFunction) gPyGetWindowWidth, + {"getWindowWidth", (PyCFunction)gPyGetWindowWidth, METH_VARARGS, "getWindowWidth doc"}, - {"getWindowHeight",(PyCFunction) gPyGetWindowHeight, + {"getWindowHeight", (PyCFunction)gPyGetWindowHeight, METH_VARARGS, "getWindowHeight doc"}, - {"makeScreenshot",(PyCFunction)gPyMakeScreenshot, + {"makeScreenshot", (PyCFunction)gPyMakeScreenshot, METH_VARARGS, "make Screenshot doc"}, - {"enableVisibility",(PyCFunction) gPyEnableVisibility, + {"enableVisibility", (PyCFunction)gPyEnableVisibility, METH_VARARGS, "enableVisibility doc"}, - {"showMouse",(PyCFunction) gPyShowMouse, + {"showMouse", (PyCFunction)gPyShowMouse, METH_VARARGS, "showMouse(bool visible)"}, - {"setMousePosition",(PyCFunction) gPySetMousePosition, + {"setMousePosition", (PyCFunction)gPySetMousePosition, METH_VARARGS, "setMousePosition(int x,int y)"}, - {"setBackgroundColor",(PyCFunction)gPySetBackgroundColor,METH_O,"set Background Color (rgb)"}, - {"enableMotionBlur",(PyCFunction)gPyEnableMotionBlur,METH_VARARGS,"enable motion blur"}, - {"disableMotionBlur",(PyCFunction)gPyDisableMotionBlur,METH_NOARGS,"disable motion blur"}, - - {"setEyeSeparation", (PyCFunction) gPySetEyeSeparation, METH_VARARGS, "set the eye separation for stereo mode"}, - {"getEyeSeparation", (PyCFunction) gPyGetEyeSeparation, METH_NOARGS, "get the eye separation for stereo mode"}, - {"setFocalLength", (PyCFunction) gPySetFocalLength, METH_VARARGS, "set the focal length for stereo mode"}, - {"getFocalLength", (PyCFunction) gPyGetFocalLength, METH_VARARGS, "get the focal length for stereo mode"}, - {"getStereoEye", (PyCFunction) gPyGetStereoEye, METH_VARARGS, "get the current stereoscopy eye being rendered"}, - {"setMaterialMode",(PyCFunction) gPySetMaterialType, + {"setBackgroundColor", (PyCFunction)gPySetBackgroundColor, METH_O, "set Background Color (rgb)"}, + {"enableMotionBlur", (PyCFunction)gPyEnableMotionBlur, METH_VARARGS, "enable motion blur"}, + {"disableMotionBlur", (PyCFunction)gPyDisableMotionBlur, METH_NOARGS, "disable motion blur"}, + + {"setEyeSeparation", (PyCFunction)gPySetEyeSeparation, METH_VARARGS, "set the eye separation for stereo mode"}, + {"getEyeSeparation", (PyCFunction)gPyGetEyeSeparation, METH_NOARGS, "get the eye separation for stereo mode"}, + {"setFocalLength", (PyCFunction)gPySetFocalLength, METH_VARARGS, "set the focal length for stereo mode"}, + {"getFocalLength", (PyCFunction)gPyGetFocalLength, METH_VARARGS, "get the focal length for stereo mode"}, + {"getStereoEye", (PyCFunction)gPyGetStereoEye, METH_VARARGS, "get the current stereoscopy eye being rendered"}, + {"setMaterialMode", (PyCFunction)gPySetMaterialType, METH_VARARGS, "set the material mode to use for OpenGL rendering"}, - {"getMaterialMode",(PyCFunction) gPyGetMaterialType, + {"getMaterialMode", (PyCFunction)gPyGetMaterialType, METH_NOARGS, "get the material mode being used for OpenGL rendering"}, - {"setGLSLMaterialSetting",(PyCFunction) gPySetGLSLMaterialSetting, + {"setGLSLMaterialSetting", (PyCFunction)gPySetGLSLMaterialSetting, METH_VARARGS, "set the state of a GLSL material setting"}, - {"getGLSLMaterialSetting",(PyCFunction) gPyGetGLSLMaterialSetting, + {"getGLSLMaterialSetting", (PyCFunction)gPyGetGLSLMaterialSetting, METH_VARARGS, "get the state of a GLSL material setting"}, - {"setAnisotropicFiltering", (PyCFunction) gPySetAnisotropicFiltering, + {"setAnisotropicFiltering", (PyCFunction)gPySetAnisotropicFiltering, METH_VARARGS, "set the anisotropic filtering level (must be one of 1, 2, 4, 8, 16)"}, - {"getAnisotropicFiltering", (PyCFunction) gPyGetAnisotropicFiltering, + {"getAnisotropicFiltering", (PyCFunction)gPyGetAnisotropicFiltering, METH_VARARGS, "get the anisotropic filtering level"}, - {"drawLine", (PyCFunction) gPyDrawLine, + {"drawLine", (PyCFunction)gPyDrawLine, METH_VARARGS, "draw a line on the screen"}, - {"setWindowSize", (PyCFunction) gPySetWindowSize, METH_VARARGS, ""}, - {"setFullScreen", (PyCFunction) gPySetFullScreen, METH_O, ""}, - {"getFullScreen", (PyCFunction) gPyGetFullScreen, METH_NOARGS, ""}, - {"getDisplayDimensions", (PyCFunction) gPyGetDisplayDimensions, METH_NOARGS, + {"setWindowSize", (PyCFunction)gPySetWindowSize, METH_VARARGS, ""}, + {"setFullScreen", (PyCFunction)gPySetFullScreen, METH_O, ""}, + {"getFullScreen", (PyCFunction)gPyGetFullScreen, METH_NOARGS, ""}, + {"getDisplayDimensions", (PyCFunction)gPyGetDisplayDimensions, METH_NOARGS, "Get the actual dimensions, in pixels, of the physical display (e.g., the monitor)."}, - {"setMipmapping", (PyCFunction) gPySetMipmapping, METH_VARARGS, ""}, - {"getMipmapping", (PyCFunction) gPyGetMipmapping, METH_NOARGS, ""}, - {"setVsync", (PyCFunction) gPySetVsync, METH_VARARGS, ""}, - {"getVsync", (PyCFunction) gPyGetVsync, METH_NOARGS, ""}, - {"showFramerate",(PyCFunction) gPyShowFramerate, METH_VARARGS, "show or hide the framerate"}, - {"showProfile",(PyCFunction) gPyShowProfile, METH_VARARGS, "show or hide the profile"}, - {"showProperties",(PyCFunction) gPyShowProperties, METH_VARARGS, "show or hide the debug properties"}, - {"autoDebugList",(PyCFunction) gPyAutoDebugList, METH_VARARGS, "enable or disable auto adding debug properties to the debug list"}, - {"clearDebugList",(PyCFunction) gPyClearDebugList, METH_NOARGS, "clears the debug property list"}, - {"offScreenCreate", (PyCFunction) gPyOffScreenCreate, METH_VARARGS, "create an offscreen buffer object, arguments are width and height in pixels"}, - { NULL, (PyCFunction) NULL, 0, NULL } + {"setMipmapping", (PyCFunction)gPySetMipmapping, METH_VARARGS, ""}, + {"getMipmapping", (PyCFunction)gPyGetMipmapping, METH_NOARGS, ""}, + {"setVsync", (PyCFunction)gPySetVsync, METH_VARARGS, ""}, + {"getVsync", (PyCFunction)gPyGetVsync, METH_NOARGS, ""}, + {"showFramerate", (PyCFunction)gPyShowFramerate, METH_VARARGS, "show or hide the framerate"}, + {"showProfile", (PyCFunction)gPyShowProfile, METH_VARARGS, "show or hide the profile"}, + {"showProperties", (PyCFunction)gPyShowProperties, METH_VARARGS, "show or hide the debug properties"}, + {"autoDebugList", (PyCFunction)gPyAutoDebugList, METH_VARARGS, "enable or disable auto adding debug properties to the debug list"}, + {"clearDebugList", (PyCFunction)gPyClearDebugList, METH_NOARGS, "clears the debug property list"}, + { nullptr, (PyCFunction)nullptr, 0, nullptr } }; PyDoc_STRVAR(GameLogic_module_documentation, -"This is the Python API for the game engine of bge.logic" -); + "This is the Python API for the game engine of bge.logic" + ); static struct PyModuleDef GameLogic_module_def = { {}, /* m_base */ @@ -1704,9 +1468,7 @@ PyMODINIT_FUNC initGameLogicPythonBinding() PyObject *d; PyObject *item; /* temp PyObject *storage */ - gUseVisibilityTemp=false; - - PyObjectPlus::ClearDeprecationWarning(); /* Not that nice to call here but makes sure warnings are reset between loading scenes */ + EXP_PyObjectPlus::ClearDeprecationWarning(); /* Not that nice to call here but makes sure warnings are reset between loading scenes */ m = PyModule_Create(&GameLogic_module_def); PyDict_SetItemString(PySys_GetObject("modules"), GameLogic_module_def.m_name, m); @@ -1718,37 +1480,25 @@ PyMODINIT_FUNC initGameLogicPythonBinding() // can be overwritten later for gameEngine instances that can load new blend files and re-initialize this module // for now its safe to make sure it exists for other areas such as the web plugin - PyDict_SetItemString(d, "globalDict", item=PyDict_New()); Py_DECREF(item); - - // Add keyboard and mouse attributes to this module - MT_assert(!gp_PythonKeyboard); - gp_PythonKeyboard = new SCA_PythonKeyboard(gp_KetsjiEngine->GetKeyboardDevice()); - PyDict_SetItemString(d, "keyboard", gp_PythonKeyboard->NewProxy(true)); + PyDict_SetItemString(d, "globalDict", item = PyDict_New()); Py_DECREF(item); - MT_assert(!gp_PythonMouse); - gp_PythonMouse = new SCA_PythonMouse(gp_KetsjiEngine->GetMouseDevice(), gp_Canvas); - PyDict_SetItemString(d, "mouse", gp_PythonMouse->NewProxy(true)); + KX_KetsjiEngine *engine = KX_GetActiveEngine(); - PyObject* joylist = PyList_New(JOYINDEX_MAX); - for (int i=0; iGetInputDevice())); + PyDict_SetItemString(d, "keyboard", gp_PythonKeyboard->GetProxy()); - if (joy && joy->Connected()) { - gp_PythonJoysticks[i] = new SCA_PythonJoystick(joy); - item = gp_PythonJoysticks[i]->NewProxy(true); - } - else { - if (joy) { - joy->ReleaseInstance(); - } - item = Py_None; - } + BLI_assert(!gp_PythonMouse); + gp_PythonMouse.reset(new SCA_PythonMouse(engine->GetInputDevice(), engine->GetCanvas())); + PyDict_SetItemString(d, "mouse", gp_PythonMouse->GetProxy()); - Py_INCREF(item); - PyList_SET_ITEM(joylist, i, item); + PyObject *joylist = PyList_New(JOYINDEX_MAX); + for (unsigned short i = 0; i < JOYINDEX_MAX; ++i) { + PyList_SET_ITEM(joylist, i, Py_None); } PyDict_SetItemString(d, "joysticks", joylist); + Py_DECREF(joylist); ErrorObject = PyUnicode_FromString("GameLogic.error"); PyDict_SetItemString(d, "error", ErrorObject); @@ -1829,67 +1579,68 @@ PyMODINIT_FUNC initGameLogicPythonBinding() KX_MACRO_addTypesToDict(d, KX_ACTIONACT_PROPERTY, ACT_ACTION_FROM_PROP); /* 7. GL_BlendFunc */ - KX_MACRO_addTypesToDict(d, BL_ZERO, GL_ZERO); - KX_MACRO_addTypesToDict(d, BL_ONE, GL_ONE); - KX_MACRO_addTypesToDict(d, BL_SRC_COLOR, GL_SRC_COLOR); - KX_MACRO_addTypesToDict(d, BL_ONE_MINUS_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR); - KX_MACRO_addTypesToDict(d, BL_DST_COLOR, GL_DST_COLOR); - KX_MACRO_addTypesToDict(d, BL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_DST_COLOR); - KX_MACRO_addTypesToDict(d, BL_SRC_ALPHA, GL_SRC_ALPHA); - KX_MACRO_addTypesToDict(d, BL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - KX_MACRO_addTypesToDict(d, BL_DST_ALPHA, GL_DST_ALPHA); - KX_MACRO_addTypesToDict(d, BL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA); - KX_MACRO_addTypesToDict(d, BL_SRC_ALPHA_SATURATE, GL_SRC_ALPHA_SATURATE); + KX_MACRO_addTypesToDict(d, BL_ZERO, RAS_Rasterizer::RAS_ZERO); + KX_MACRO_addTypesToDict(d, BL_ONE, RAS_Rasterizer::RAS_ONE); + KX_MACRO_addTypesToDict(d, BL_SRC_COLOR, RAS_Rasterizer::RAS_SRC_COLOR); + KX_MACRO_addTypesToDict(d, BL_ONE_MINUS_SRC_COLOR, RAS_Rasterizer::RAS_ONE_MINUS_SRC_COLOR); + KX_MACRO_addTypesToDict(d, BL_DST_COLOR, RAS_Rasterizer::RAS_DST_COLOR); + KX_MACRO_addTypesToDict(d, BL_ONE_MINUS_DST_COLOR, RAS_Rasterizer::RAS_ONE_MINUS_DST_COLOR); + KX_MACRO_addTypesToDict(d, BL_SRC_ALPHA, RAS_Rasterizer::RAS_SRC_ALPHA); + KX_MACRO_addTypesToDict(d, BL_ONE_MINUS_SRC_ALPHA, RAS_Rasterizer::RAS_ONE_MINUS_SRC_ALPHA); + KX_MACRO_addTypesToDict(d, BL_DST_ALPHA, RAS_Rasterizer::RAS_DST_ALPHA); + KX_MACRO_addTypesToDict(d, BL_ONE_MINUS_DST_ALPHA, RAS_Rasterizer::RAS_ONE_MINUS_DST_ALPHA); + KX_MACRO_addTypesToDict(d, BL_SRC_ALPHA_SATURATE, RAS_Rasterizer::RAS_SRC_ALPHA_SATURATE); /* 8. UniformTypes */ KX_MACRO_addTypesToDict(d, SHD_TANGENT, BL_Shader::SHD_TANGENT); - KX_MACRO_addTypesToDict(d, MODELVIEWMATRIX, BL_Shader::MODELVIEWMATRIX); - KX_MACRO_addTypesToDict(d, MODELVIEWMATRIX_TRANSPOSE, BL_Shader::MODELVIEWMATRIX_TRANSPOSE); - KX_MACRO_addTypesToDict(d, MODELVIEWMATRIX_INVERSE, BL_Shader::MODELVIEWMATRIX_INVERSE); - KX_MACRO_addTypesToDict(d, MODELVIEWMATRIX_INVERSETRANSPOSE, BL_Shader::MODELVIEWMATRIX_INVERSETRANSPOSE); - KX_MACRO_addTypesToDict(d, MODELMATRIX, BL_Shader::MODELMATRIX); - KX_MACRO_addTypesToDict(d, MODELMATRIX_TRANSPOSE, BL_Shader::MODELMATRIX_TRANSPOSE); - KX_MACRO_addTypesToDict(d, MODELMATRIX_INVERSE, BL_Shader::MODELMATRIX_INVERSE); - KX_MACRO_addTypesToDict(d, MODELMATRIX_INVERSETRANSPOSE, BL_Shader::MODELMATRIX_INVERSETRANSPOSE); - KX_MACRO_addTypesToDict(d, VIEWMATRIX, BL_Shader::VIEWMATRIX); - KX_MACRO_addTypesToDict(d, VIEWMATRIX_TRANSPOSE, BL_Shader::VIEWMATRIX_TRANSPOSE); - KX_MACRO_addTypesToDict(d, VIEWMATRIX_INVERSE, BL_Shader::VIEWMATRIX_INVERSE); - KX_MACRO_addTypesToDict(d, VIEWMATRIX_INVERSETRANSPOSE, BL_Shader::VIEWMATRIX_INVERSETRANSPOSE); - KX_MACRO_addTypesToDict(d, CAM_POS, BL_Shader::CAM_POS); - KX_MACRO_addTypesToDict(d, CONSTANT_TIMER, BL_Shader::CONSTANT_TIMER); + KX_MACRO_addTypesToDict(d, MODELVIEWMATRIX, RAS_Shader::MODELVIEWMATRIX); + KX_MACRO_addTypesToDict(d, MODELVIEWMATRIX_TRANSPOSE, RAS_Shader::MODELVIEWMATRIX_TRANSPOSE); + KX_MACRO_addTypesToDict(d, MODELVIEWMATRIX_INVERSE, RAS_Shader::MODELVIEWMATRIX_INVERSE); + KX_MACRO_addTypesToDict(d, MODELVIEWMATRIX_INVERSETRANSPOSE, RAS_Shader::MODELVIEWMATRIX_INVERSETRANSPOSE); + KX_MACRO_addTypesToDict(d, MODELMATRIX, RAS_Shader::MODELMATRIX); + KX_MACRO_addTypesToDict(d, MODELMATRIX_TRANSPOSE, RAS_Shader::MODELMATRIX_TRANSPOSE); + KX_MACRO_addTypesToDict(d, MODELMATRIX_INVERSE, RAS_Shader::MODELMATRIX_INVERSE); + KX_MACRO_addTypesToDict(d, MODELMATRIX_INVERSETRANSPOSE, RAS_Shader::MODELMATRIX_INVERSETRANSPOSE); + KX_MACRO_addTypesToDict(d, VIEWMATRIX, RAS_Shader::VIEWMATRIX); + KX_MACRO_addTypesToDict(d, VIEWMATRIX_TRANSPOSE, RAS_Shader::VIEWMATRIX_TRANSPOSE); + KX_MACRO_addTypesToDict(d, VIEWMATRIX_INVERSE, RAS_Shader::VIEWMATRIX_INVERSE); + KX_MACRO_addTypesToDict(d, VIEWMATRIX_INVERSETRANSPOSE, RAS_Shader::VIEWMATRIX_INVERSETRANSPOSE); + KX_MACRO_addTypesToDict(d, CAM_POS, RAS_Shader::CAM_POS); + KX_MACRO_addTypesToDict(d, CONSTANT_TIMER, RAS_Shader::CONSTANT_TIMER); + KX_MACRO_addTypesToDict(d, EYE, RAS_Shader::EYE); /* 9. state actuator */ - KX_MACRO_addTypesToDict(d, KX_STATE1, (1<<0)); - KX_MACRO_addTypesToDict(d, KX_STATE2, (1<<1)); - KX_MACRO_addTypesToDict(d, KX_STATE3, (1<<2)); - KX_MACRO_addTypesToDict(d, KX_STATE4, (1<<3)); - KX_MACRO_addTypesToDict(d, KX_STATE5, (1<<4)); - KX_MACRO_addTypesToDict(d, KX_STATE6, (1<<5)); - KX_MACRO_addTypesToDict(d, KX_STATE7, (1<<6)); - KX_MACRO_addTypesToDict(d, KX_STATE8, (1<<7)); - KX_MACRO_addTypesToDict(d, KX_STATE9, (1<<8)); - KX_MACRO_addTypesToDict(d, KX_STATE10, (1<<9)); - KX_MACRO_addTypesToDict(d, KX_STATE11, (1<<10)); - KX_MACRO_addTypesToDict(d, KX_STATE12, (1<<11)); - KX_MACRO_addTypesToDict(d, KX_STATE13, (1<<12)); - KX_MACRO_addTypesToDict(d, KX_STATE14, (1<<13)); - KX_MACRO_addTypesToDict(d, KX_STATE15, (1<<14)); - KX_MACRO_addTypesToDict(d, KX_STATE16, (1<<15)); - KX_MACRO_addTypesToDict(d, KX_STATE17, (1<<16)); - KX_MACRO_addTypesToDict(d, KX_STATE18, (1<<17)); - KX_MACRO_addTypesToDict(d, KX_STATE19, (1<<18)); - KX_MACRO_addTypesToDict(d, KX_STATE20, (1<<19)); - KX_MACRO_addTypesToDict(d, KX_STATE21, (1<<20)); - KX_MACRO_addTypesToDict(d, KX_STATE22, (1<<21)); - KX_MACRO_addTypesToDict(d, KX_STATE23, (1<<22)); - KX_MACRO_addTypesToDict(d, KX_STATE24, (1<<23)); - KX_MACRO_addTypesToDict(d, KX_STATE25, (1<<24)); - KX_MACRO_addTypesToDict(d, KX_STATE26, (1<<25)); - KX_MACRO_addTypesToDict(d, KX_STATE27, (1<<26)); - KX_MACRO_addTypesToDict(d, KX_STATE28, (1<<27)); - KX_MACRO_addTypesToDict(d, KX_STATE29, (1<<28)); - KX_MACRO_addTypesToDict(d, KX_STATE30, (1<<29)); + KX_MACRO_addTypesToDict(d, KX_STATE1, (1 << 0)); + KX_MACRO_addTypesToDict(d, KX_STATE2, (1 << 1)); + KX_MACRO_addTypesToDict(d, KX_STATE3, (1 << 2)); + KX_MACRO_addTypesToDict(d, KX_STATE4, (1 << 3)); + KX_MACRO_addTypesToDict(d, KX_STATE5, (1 << 4)); + KX_MACRO_addTypesToDict(d, KX_STATE6, (1 << 5)); + KX_MACRO_addTypesToDict(d, KX_STATE7, (1 << 6)); + KX_MACRO_addTypesToDict(d, KX_STATE8, (1 << 7)); + KX_MACRO_addTypesToDict(d, KX_STATE9, (1 << 8)); + KX_MACRO_addTypesToDict(d, KX_STATE10, (1 << 9)); + KX_MACRO_addTypesToDict(d, KX_STATE11, (1 << 10)); + KX_MACRO_addTypesToDict(d, KX_STATE12, (1 << 11)); + KX_MACRO_addTypesToDict(d, KX_STATE13, (1 << 12)); + KX_MACRO_addTypesToDict(d, KX_STATE14, (1 << 13)); + KX_MACRO_addTypesToDict(d, KX_STATE15, (1 << 14)); + KX_MACRO_addTypesToDict(d, KX_STATE16, (1 << 15)); + KX_MACRO_addTypesToDict(d, KX_STATE17, (1 << 16)); + KX_MACRO_addTypesToDict(d, KX_STATE18, (1 << 17)); + KX_MACRO_addTypesToDict(d, KX_STATE19, (1 << 18)); + KX_MACRO_addTypesToDict(d, KX_STATE20, (1 << 19)); + KX_MACRO_addTypesToDict(d, KX_STATE21, (1 << 20)); + KX_MACRO_addTypesToDict(d, KX_STATE22, (1 << 21)); + KX_MACRO_addTypesToDict(d, KX_STATE23, (1 << 22)); + KX_MACRO_addTypesToDict(d, KX_STATE24, (1 << 23)); + KX_MACRO_addTypesToDict(d, KX_STATE25, (1 << 24)); + KX_MACRO_addTypesToDict(d, KX_STATE26, (1 << 25)); + KX_MACRO_addTypesToDict(d, KX_STATE27, (1 << 26)); + KX_MACRO_addTypesToDict(d, KX_STATE28, (1 << 27)); + KX_MACRO_addTypesToDict(d, KX_STATE29, (1 << 28)); + KX_MACRO_addTypesToDict(d, KX_STATE30, (1 << 29)); /* All Sensors */ KX_MACRO_addTypesToDict(d, KX_SENSOR_JUST_ACTIVATED, SCA_ISensor::KX_SENSOR_JUST_ACTIVATED); @@ -1913,6 +1664,15 @@ PyMODINIT_FUNC initGameLogicPythonBinding() KX_MACRO_addTypesToDict(d, KX_RAY_AXIS_NEG_Y, KX_RaySensor::KX_RAY_AXIS_NEG_Y); KX_MACRO_addTypesToDict(d, KX_RAY_AXIS_NEG_Z, KX_RaySensor::KX_RAY_AXIS_NEG_Z); + /* Movement Sensor */ + KX_MACRO_addTypesToDict(d, KX_MOVEMENT_AXIS_POS_X, KX_MovementSensor::KX_MOVEMENT_AXIS_POS_X); + KX_MACRO_addTypesToDict(d, KX_MOVEMENT_AXIS_POS_Y, KX_MovementSensor::KX_MOVEMENT_AXIS_POS_Y); + KX_MACRO_addTypesToDict(d, KX_MOVEMENT_AXIS_POS_Z, KX_MovementSensor::KX_MOVEMENT_AXIS_POS_Z); + KX_MACRO_addTypesToDict(d, KX_MOVEMENT_AXIS_NEG_X, KX_MovementSensor::KX_MOVEMENT_AXIS_NEG_X); + KX_MACRO_addTypesToDict(d, KX_MOVEMENT_AXIS_NEG_Y, KX_MovementSensor::KX_MOVEMENT_AXIS_NEG_Y); + KX_MACRO_addTypesToDict(d, KX_MOVEMENT_AXIS_NEG_Z, KX_MovementSensor::KX_MOVEMENT_AXIS_NEG_Z); + KX_MACRO_addTypesToDict(d, KX_MOVEMENT_ALL_AXIS, KX_MovementSensor::KX_MOVEMENT_ALL_AXIS); + /* TrackTo Actuator */ KX_MACRO_addTypesToDict(d, KX_TRACK_UPAXIS_POS_X, KX_TrackToActuator::KX_TRACK_UPAXIS_POS_X); KX_MACRO_addTypesToDict(d, KX_TRACK_UPAXIS_POS_Y, KX_TrackToActuator::KX_TRACK_UPAXIS_POS_Y); @@ -1925,38 +1685,38 @@ PyMODINIT_FUNC initGameLogicPythonBinding() KX_MACRO_addTypesToDict(d, KX_TRACK_TRAXIS_NEG_Z, KX_TrackToActuator::KX_TRACK_TRAXIS_NEG_Z); /* Dynamic actuator */ - KX_MACRO_addTypesToDict(d, KX_DYN_RESTORE_DYNAMICS, KX_SCA_DynamicActuator::KX_DYN_RESTORE_DYNAMICS); - KX_MACRO_addTypesToDict(d, KX_DYN_DISABLE_DYNAMICS, KX_SCA_DynamicActuator::KX_DYN_DISABLE_DYNAMICS); - KX_MACRO_addTypesToDict(d, KX_DYN_ENABLE_RIGID_BODY, KX_SCA_DynamicActuator::KX_DYN_ENABLE_RIGID_BODY); - KX_MACRO_addTypesToDict(d, KX_DYN_DISABLE_RIGID_BODY, KX_SCA_DynamicActuator::KX_DYN_DISABLE_RIGID_BODY); - KX_MACRO_addTypesToDict(d, KX_DYN_SET_MASS, KX_SCA_DynamicActuator::KX_DYN_SET_MASS); + KX_MACRO_addTypesToDict(d, KX_DYN_RESTORE_DYNAMICS, KX_DynamicActuator::KX_DYN_RESTORE_DYNAMICS); + KX_MACRO_addTypesToDict(d, KX_DYN_DISABLE_DYNAMICS, KX_DynamicActuator::KX_DYN_DISABLE_DYNAMICS); + KX_MACRO_addTypesToDict(d, KX_DYN_ENABLE_RIGID_BODY, KX_DynamicActuator::KX_DYN_ENABLE_RIGID_BODY); + KX_MACRO_addTypesToDict(d, KX_DYN_DISABLE_RIGID_BODY, KX_DynamicActuator::KX_DYN_DISABLE_RIGID_BODY); + KX_MACRO_addTypesToDict(d, KX_DYN_SET_MASS, KX_DynamicActuator::KX_DYN_SET_MASS); /* Input & Mouse Sensor */ - KX_MACRO_addTypesToDict(d, KX_INPUT_NONE, SCA_InputEvent::KX_NO_INPUTSTATUS); - KX_MACRO_addTypesToDict(d, KX_INPUT_JUST_ACTIVATED, SCA_InputEvent::KX_JUSTACTIVATED); - KX_MACRO_addTypesToDict(d, KX_INPUT_ACTIVE, SCA_InputEvent::KX_ACTIVE); - KX_MACRO_addTypesToDict(d, KX_INPUT_JUST_RELEASED, SCA_InputEvent::KX_JUSTRELEASED); + KX_MACRO_addTypesToDict(d, KX_INPUT_NONE, SCA_InputEvent::NONE); + KX_MACRO_addTypesToDict(d, KX_INPUT_JUST_ACTIVATED, SCA_InputEvent::JUSTACTIVATED); + KX_MACRO_addTypesToDict(d, KX_INPUT_ACTIVE, SCA_InputEvent::ACTIVE); + KX_MACRO_addTypesToDict(d, KX_INPUT_JUST_RELEASED, SCA_InputEvent::JUSTRELEASED); - KX_MACRO_addTypesToDict(d, KX_MOUSE_BUT_LEFT, SCA_IInputDevice::KX_LEFTMOUSE); - KX_MACRO_addTypesToDict(d, KX_MOUSE_BUT_MIDDLE, SCA_IInputDevice::KX_MIDDLEMOUSE); - KX_MACRO_addTypesToDict(d, KX_MOUSE_BUT_RIGHT, SCA_IInputDevice::KX_RIGHTMOUSE); + KX_MACRO_addTypesToDict(d, KX_MOUSE_BUT_LEFT, SCA_IInputDevice::LEFTMOUSE); + KX_MACRO_addTypesToDict(d, KX_MOUSE_BUT_MIDDLE, SCA_IInputDevice::MIDDLEMOUSE); + KX_MACRO_addTypesToDict(d, KX_MOUSE_BUT_RIGHT, SCA_IInputDevice::RIGHTMOUSE); /* 2D Filter Actuator */ - KX_MACRO_addTypesToDict(d, RAS_2DFILTER_ENABLED, RAS_2DFilterManager::RAS_2DFILTER_ENABLED); - KX_MACRO_addTypesToDict(d, RAS_2DFILTER_DISABLED, RAS_2DFilterManager::RAS_2DFILTER_DISABLED); - KX_MACRO_addTypesToDict(d, RAS_2DFILTER_NOFILTER, RAS_2DFilterManager::RAS_2DFILTER_NOFILTER); - KX_MACRO_addTypesToDict(d, RAS_2DFILTER_MOTIONBLUR, RAS_2DFilterManager::RAS_2DFILTER_MOTIONBLUR); - KX_MACRO_addTypesToDict(d, RAS_2DFILTER_BLUR, RAS_2DFilterManager::RAS_2DFILTER_BLUR); - KX_MACRO_addTypesToDict(d, RAS_2DFILTER_SHARPEN, RAS_2DFilterManager::RAS_2DFILTER_SHARPEN); - KX_MACRO_addTypesToDict(d, RAS_2DFILTER_DILATION, RAS_2DFilterManager::RAS_2DFILTER_DILATION); - KX_MACRO_addTypesToDict(d, RAS_2DFILTER_EROSION, RAS_2DFilterManager::RAS_2DFILTER_EROSION); - KX_MACRO_addTypesToDict(d, RAS_2DFILTER_LAPLACIAN, RAS_2DFilterManager::RAS_2DFILTER_LAPLACIAN); - KX_MACRO_addTypesToDict(d, RAS_2DFILTER_SOBEL, RAS_2DFilterManager::RAS_2DFILTER_SOBEL); - KX_MACRO_addTypesToDict(d, RAS_2DFILTER_PREWITT, RAS_2DFilterManager::RAS_2DFILTER_PREWITT); - KX_MACRO_addTypesToDict(d, RAS_2DFILTER_GRAYSCALE, RAS_2DFilterManager::RAS_2DFILTER_GRAYSCALE); - KX_MACRO_addTypesToDict(d, RAS_2DFILTER_SEPIA, RAS_2DFilterManager::RAS_2DFILTER_SEPIA); - KX_MACRO_addTypesToDict(d, RAS_2DFILTER_INVERT, RAS_2DFilterManager::RAS_2DFILTER_INVERT); - KX_MACRO_addTypesToDict(d, RAS_2DFILTER_CUSTOMFILTER, RAS_2DFilterManager::RAS_2DFILTER_CUSTOMFILTER); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_ENABLED, RAS_2DFilterManager::FILTER_ENABLED); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_DISABLED, RAS_2DFilterManager::FILTER_DISABLED); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_NOFILTER, RAS_2DFilterManager::FILTER_NOFILTER); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_MOTIONBLUR, RAS_2DFilterManager::FILTER_MOTIONBLUR); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_BLUR, RAS_2DFilterManager::FILTER_BLUR); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_SHARPEN, RAS_2DFilterManager::FILTER_SHARPEN); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_DILATION, RAS_2DFilterManager::FILTER_DILATION); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_EROSION, RAS_2DFilterManager::FILTER_EROSION); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_LAPLACIAN, RAS_2DFilterManager::FILTER_LAPLACIAN); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_SOBEL, RAS_2DFilterManager::FILTER_SOBEL); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_PREWITT, RAS_2DFilterManager::FILTER_PREWITT); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_GRAYSCALE, RAS_2DFilterManager::FILTER_GRAYSCALE); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_SEPIA, RAS_2DFilterManager::FILTER_SEPIA); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_INVERT, RAS_2DFilterManager::FILTER_INVERT); + KX_MACRO_addTypesToDict(d, RAS_2DFILTER_CUSTOMFILTER, RAS_2DFilterManager::FILTER_CUSTOMFILTER); /* Sound Actuator */ KX_MACRO_addTypesToDict(d, KX_SOUNDACT_PLAYSTOP, KX_SoundActuator::KX_SOUNDACT_PLAYSTOP); @@ -2069,8 +1829,7 @@ PyMODINIT_FUNC initGameLogicPythonBinding() // Check for errors - if (PyErr_Occurred()) - { + if (PyErr_Occurred()) { Py_FatalError("can't initialize module bge.logic"); } @@ -2115,6 +1874,11 @@ static void backupPySysObjects(void) Py_XDECREF(gp_sys_backup.modules); /* just in case its set */ gp_sys_backup.modules = PyDict_Copy(sys_mods); /* copy the dict */ + if (bpy_sys_module_backup) { + PyDict_Clear(sys_mods); + // Load a clean generated modules dict from the blender begining. + PyDict_Update(sys_mods, bpy_sys_module_backup); + } } /* for initPySysObjects only, @@ -2128,12 +1892,10 @@ static void initPySysObjects__append(PyObject *sys_path, const char *filename) char expanded[FILE_MAX]; BLI_split_dir_part(filename, expanded, sizeof(expanded)); /* get the dir part of filename only */ - BLI_path_abs(expanded, gp_GamePythonPath); /* filename from lib->filename is (always?) absolute, so this may not be needed but it wont hurt */ - BLI_cleanup_file(gp_GamePythonPath, expanded); /* Don't use BLI_cleanup_dir because it adds a slash - BREAKS WIN32 ONLY */ + BLI_path_abs(expanded, KX_GetMainPath().c_str()); /* filename from lib->filename is (always?) absolute, so this may not be needed but it wont hurt */ + BLI_cleanup_file(KX_GetMainPath().c_str(), expanded); /* Don't use BLI_cleanup_dir because it adds a slash - BREAKS WIN32 ONLY */ item = PyC_UnicodeFromByte(expanded); -// printf("SysPath - '%s', '%s', '%s'\n", expanded, filename, gp_GamePythonPath); - if (PySequence_Index(sys_path, item) == -1) { PyErr_Clear(); /* PySequence_Index sets a ValueError */ PyList_Insert(sys_path, 0, item); @@ -2141,12 +1903,13 @@ static void initPySysObjects__append(PyObject *sys_path, const char *filename) Py_DECREF(item); } + static void initPySysObjects(Main *maggie) { PyObject *sys_path = PySys_GetObject("path"); PyObject *sys_meta_path = PySys_GetObject("meta_path"); - if (gp_sys_backup.path == NULL) { + if (gp_sys_backup.path == nullptr) { /* backup */ backupPySysObjects(); } @@ -2156,24 +1919,21 @@ static void initPySysObjects(Main *maggie) PyList_SetSlice(sys_meta_path, 0, INT_MAX, gp_sys_backup.meta_path); } - Library *lib= (Library *)maggie->library.first; + Library *lib = (Library *)maggie->library.first; while (lib) { /* lib->name wont work in some cases (on win32), - * even when expanding with gp_GamePythonPath, using lib->filename is less trouble */ + * even when expanding with KX_GetMainPath(), using lib->filename is less trouble */ initPySysObjects__append(sys_path, lib->filepath); - lib= (Library *)lib->id.next; + lib = (Library *)lib->id.next; } - initPySysObjects__append(sys_path, gp_GamePythonPath); - -// fprintf(stderr, "\nNew Path: %d ", PyList_GET_SIZE(sys_path)); -// PyObject_Print(sys_path, stderr, 0); + initPySysObjects__append(sys_path, KX_GetMainPath().c_str()); } static void restorePySysObjects(void) { - if (gp_sys_backup.path == NULL) { + if (gp_sys_backup.path == nullptr) { return; } @@ -2185,22 +1945,24 @@ static void restorePySysObjects(void) /* paths */ PyList_SetSlice(sys_path, 0, INT_MAX, gp_sys_backup.path); Py_DECREF(gp_sys_backup.path); - gp_sys_backup.path = NULL; + gp_sys_backup.path = nullptr; /* meta_path */ PyList_SetSlice(sys_meta_path, 0, INT_MAX, gp_sys_backup.meta_path); Py_DECREF(gp_sys_backup.meta_path); - gp_sys_backup.meta_path = NULL; + gp_sys_backup.meta_path = nullptr; /* modules */ PyDict_Clear(sys_mods); PyDict_Update(sys_mods, gp_sys_backup.modules); Py_DECREF(gp_sys_backup.modules); - gp_sys_backup.modules = NULL; - + gp_sys_backup.modules = nullptr; +} -// fprintf(stderr, "\nRestore Path: %d ", PyList_GET_SIZE(sys_path)); -// PyObject_Print(sys_path, stderr, 0); +void appendPythonPath(const std::string& path) +{ + PyObject *sys_path = PySys_GetObject("path"); + initPySysObjects__append(sys_path, path.c_str()); } void addImportMain(struct Main *maggie) @@ -2215,69 +1977,42 @@ void removeImportMain(struct Main *maggie) PyDoc_STRVAR(BGE_module_documentation, - "This module contains submodules for the Blender Game Engine.\n" -); + "This module contains submodules for the Blender Game Engine.\n" + ); static struct PyModuleDef BGE_module_def = { PyModuleDef_HEAD_INIT, "bge", /* m_name */ BGE_module_documentation, /* m_doc */ 0, /* m_size */ - NULL, /* m_methods */ - NULL, /* m_reload */ - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL, /* m_free */ + nullptr, /* m_methods */ + nullptr, /* m_reload */ + nullptr, /* m_traverse */ + nullptr, /* m_clear */ + nullptr, /* m_free */ }; -PyMODINIT_FUNC initBGE(void) +static void addSubModule(PyObject *modules, PyObject *mod, PyObject *submod, const std::string& modname) { - PyObject *mod; - PyObject *submodule; - PyObject *sys_modules = PyThreadState_GET()->interp->modules; - const char *mod_full; - - mod = PyModule_Create(&BGE_module_def); - - /* skip "bge." */ -#define SUBMOD (mod_full + 4) - - mod_full = "bge.app"; - PyModule_AddObject(mod, SUBMOD, (submodule = initApplicationPythonBinding())); - PyDict_SetItemString(sys_modules, mod_full, submodule); - Py_INCREF(submodule); - - mod_full = "bge.constraints"; - PyModule_AddObject(mod, SUBMOD, (submodule = initConstraintPythonBinding())); - PyDict_SetItemString(sys_modules, mod_full, submodule); - Py_INCREF(submodule); - - mod_full = "bge.events"; - PyModule_AddObject(mod, SUBMOD, (submodule = initGameKeysPythonBinding())); - PyDict_SetItemString(sys_modules, mod_full, submodule); - Py_INCREF(submodule); - - mod_full = "bge.logic"; - PyModule_AddObject(mod, SUBMOD, (submodule = initGameLogicPythonBinding())); - PyDict_SetItemString(sys_modules, mod_full, submodule); - Py_INCREF(submodule); - - mod_full = "bge.render"; - PyModule_AddObject(mod, SUBMOD, (submodule = initRasterizerPythonBinding())); - PyDict_SetItemString(sys_modules, mod_full, submodule); - Py_INCREF(submodule); + /* PyModule_AddObject doesn't incref the sub module but PyDict_SetItemString increfs + * the item set. So no incref and decref are needed here. */ + PyModule_AddObject(mod, modname.substr(4).c_str(), submod); + PyDict_SetItemString(modules, modname.c_str(), submod); +} - mod_full = "bge.texture"; - PyModule_AddObject(mod, SUBMOD, (submodule = initVideoTexturePythonBinding())); - PyDict_SetItemString(sys_modules, mod_full, submodule); - Py_INCREF(submodule); +PyMODINIT_FUNC initBGE() +{ + PyObject *modules = PyThreadState_GET()->interp->modules; - mod_full = "bge.types"; - PyModule_AddObject(mod, SUBMOD, (submodule = initGameTypesPythonBinding())); - PyDict_SetItemString(sys_modules, mod_full, submodule); - Py_INCREF(submodule); + PyObject *mod = PyModule_Create(&BGE_module_def); -#undef SUBMOD + addSubModule(modules, mod, initApplicationPythonBinding(), "bge.app"); + addSubModule(modules, mod, initConstraintPythonBinding(), "bge.constraints"); + addSubModule(modules, mod, initGameKeysPythonBinding(), "bge.events"); + addSubModule(modules, mod, initGameLogicPythonBinding(), "bge.logic"); + addSubModule(modules, mod, initRasterizerPythonBinding(), "bge.render"); + addSubModule(modules, mod, initGameTypesPythonBinding(), "bge.types"); + addSubModule(modules, mod, initVideoTexturePythonBinding(), "bge.texture"); return mod; } @@ -2288,195 +2023,147 @@ static struct _inittab bge_internal_modules[] = { {"mathutils", PyInit_mathutils}, {"bgl", BPyInit_bgl}, {"blf", BPyInit_blf}, +#ifdef WITH_AUDASPACE {"aud", AUD_initPython}, - {NULL, NULL} +#endif // WITH_AUDASPACE + {nullptr, nullptr} }; /** * Python is not initialized. * see bpy_interface.c's BPY_python_start() which shares the same functionality in blender. */ -PyObject *initGamePlayerPythonScripting(Main *maggie, int argc, char** argv) -{ - /* Yet another gotcha in the py api - * Cant run PySys_SetArgv more than once because this adds the - * binary dir to the sys.path each time. - * Id have thought python being totally restarted would make this ok but - * somehow it remembers the sys.path - Campbell - */ - static bool first_time = true; - const char * const py_path_bundle = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON, NULL); - - /* not essential but nice to set our name */ - static wchar_t program_path_wchar[FILE_MAX]; /* python holds a reference */ +void initPlayerPython(int argc, char **argv) +{ + const char *const py_path_bundle = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON, nullptr); + + // Not essential but nice to set our name, not that python holds a reference to program path string. + static wchar_t program_path_wchar[FILE_MAX]; BLI_strncpy_wchar_from_utf8(program_path_wchar, BKE_appdir_program_path(), ARRAY_SIZE(program_path_wchar)); Py_SetProgramName(program_path_wchar); - /* Update, Py3.3 resolves attempting to parse non-existing header */ -#if 0 - /* Python 3.2 now looks for '2.xx/python/include/python3.2d/pyconfig.h' to - * parse from the 'sysconfig' module which is used by 'site', - * so for now disable site. alternatively we could copy the file. */ - if (py_path_bundle != NULL) { - Py_NoSiteFlag = 1; /* inhibits the automatic importing of 'site' */ - } -#endif - Py_FrozenFlag = 1; - /* must run before python initializes */ + // Must run before python initializes. PyImport_ExtendInittab(bge_internal_modules); - /* find local python installation */ + // Find local python installation. PyC_SetHomePath(py_path_bundle); - Py_Initialize(); - - if (argv && first_time) { /* browser plugins don't currently set this */ - // Until python support ascii again, we use our own. - // PySys_SetArgv(argc, argv); - int i; - PyObject *py_argv= PyList_New(argc); + /* without this the sys.stdout may be set to 'ascii' + * (it is on my system at least), where printing unicode values will raise + * an error, this is highly annoying, another stumbling block for devs, + * so use a more relaxed error handler and enforce utf-8 since the rest of + * blender is utf-8 too - campbell */ + Py_SetStandardStreamEncoding("utf-8", "surrogateescape"); - for (i=0; iGetCanvas(); - gp_Rasterizer = ketsjiengine->GetRasterizer(); - gp_KetsjiEngine = ketsjiengine; - gp_KetsjiScene = startscene; +void updatePythonJoysticks(short(&addrem)[JOYINDEX_MAX]) +{ + PyObject *gameLogic = PyImport_ImportModule("GameLogic"); + PyObject *pythonJoyList = PyDict_GetItemString(PyModule_GetDict(gameLogic), "joysticks"); - if (argv) /* player only */ - dictionaryobject= initGamePlayerPythonScripting(blenderdata, argc, argv); - else - dictionaryobject= initGamePythonScripting(blenderdata); + for (unsigned short i = 0; i < JOYINDEX_MAX; ++i) { + if (addrem[i] == 0) { + continue; + } - ketsjiengine->SetPyNamespace(dictionaryobject); + PyObject *item = Py_None; - modules = PyImport_GetModuleDict(); + if (addrem[i] == 1) { + DEV_Joystick *joy = DEV_Joystick::GetInstance(i); + if (joy && joy->Connected()) { + gp_PythonJoysticks[i].reset(new SCA_PythonJoystick(joy, i)); + item = gp_PythonJoysticks[i]->GetProxy(); + } + } + else if (addrem[i] == 2) { + gp_PythonJoysticks[i].reset(nullptr); + } - *gameLogic = PyDict_GetItemString(modules, "GameLogic"); - /* is set in initGameLogicPythonBinding so only set here if we want it to persist between scenes */ - if (pyGlobalDict) - PyDict_SetItemString(PyModule_GetDict(*gameLogic), "globalDict", pyGlobalDict); // Same as importing the module. + PyList_SetItem(pythonJoyList, i, item); + } - *gameLogic_keys = PyDict_Keys(PyModule_GetDict(*gameLogic)); + Py_DECREF(gameLogic); } static struct PyModuleDef Rasterizer_module_def = { @@ -2496,8 +2183,6 @@ PyMODINIT_FUNC initRasterizerPythonBinding() PyObject *m; PyObject *d; - PyType_Ready(&PyRASOffScreen_Type); - m = PyModule_Create(&Rasterizer_module_def); PyDict_SetItemString(PySys_GetObject("modules"), Rasterizer_module_def.m_name, m); @@ -2512,29 +2197,28 @@ PyMODINIT_FUNC initRasterizerPythonBinding() KX_MACRO_addTypesToDict(d, KX_BLENDER_MULTITEX_MATERIAL, KX_BLENDER_MULTITEX_MATERIAL); KX_MACRO_addTypesToDict(d, KX_BLENDER_GLSL_MATERIAL, KX_BLENDER_GLSL_MATERIAL); - KX_MACRO_addTypesToDict(d, RAS_MIPMAP_NONE, RAS_IRasterizer::RAS_MIPMAP_NONE); - KX_MACRO_addTypesToDict(d, RAS_MIPMAP_NEAREST, RAS_IRasterizer::RAS_MIPMAP_NEAREST); - KX_MACRO_addTypesToDict(d, RAS_MIPMAP_LINEAR, RAS_IRasterizer::RAS_MIPMAP_LINEAR); + KX_MACRO_addTypesToDict(d, RAS_MIPMAP_NONE, RAS_Rasterizer::RAS_MIPMAP_NONE); + KX_MACRO_addTypesToDict(d, RAS_MIPMAP_NEAREST, RAS_Rasterizer::RAS_MIPMAP_NEAREST); + KX_MACRO_addTypesToDict(d, RAS_MIPMAP_LINEAR, RAS_Rasterizer::RAS_MIPMAP_LINEAR); /* for get/setVsync */ - KX_MACRO_addTypesToDict(d, VSYNC_OFF, VSYNC_OFF); - KX_MACRO_addTypesToDict(d, VSYNC_ON, VSYNC_ON); - KX_MACRO_addTypesToDict(d, VSYNC_ADAPTIVE, VSYNC_ADAPTIVE); + KX_MACRO_addTypesToDict(d, VSYNC_OFF, RAS_ICanvas::VSYNC_OFF); + KX_MACRO_addTypesToDict(d, VSYNC_ON, RAS_ICanvas::VSYNC_ON); + KX_MACRO_addTypesToDict(d, VSYNC_ADAPTIVE, RAS_ICanvas::VSYNC_ADAPTIVE); /* stereoscopy */ - KX_MACRO_addTypesToDict(d, LEFT_EYE, RAS_IRasterizer::RAS_STEREO_LEFTEYE); - KX_MACRO_addTypesToDict(d, RIGHT_EYE, RAS_IRasterizer::RAS_STEREO_RIGHTEYE); - - /* offscreen render */ - KX_MACRO_addTypesToDict(d, RAS_OFS_RENDER_BUFFER, RAS_IOffScreen::RAS_OFS_RENDER_BUFFER); - KX_MACRO_addTypesToDict(d, RAS_OFS_RENDER_TEXTURE, RAS_IOffScreen::RAS_OFS_RENDER_TEXTURE); + KX_MACRO_addTypesToDict(d, LEFT_EYE, RAS_Rasterizer::RAS_STEREO_LEFTEYE); + KX_MACRO_addTypesToDict(d, RIGHT_EYE, RAS_Rasterizer::RAS_STEREO_RIGHTEYE); + // HDR + KX_MACRO_addTypesToDict(d, HDR_NONE, RAS_Rasterizer::RAS_HDR_NONE); + KX_MACRO_addTypesToDict(d, HDR_HALF_FLOAT, RAS_Rasterizer::RAS_HDR_HALF_FLOAT); + KX_MACRO_addTypesToDict(d, HDR_FULL_FLOAT, RAS_Rasterizer::RAS_HDR_FULL_FLOAT); // XXXX Add constants here // Check for errors - if (PyErr_Occurred()) - { + if (PyErr_Occurred()) { Py_FatalError("can't initialize module Rasterizer"); } @@ -2548,22 +2232,23 @@ PyMODINIT_FUNC initRasterizerPythonBinding() /* ------------------------------------------------------------------------- */ PyDoc_STRVAR(GameKeys_module_documentation, -"This modules provides defines for key-codes" -); + "This modules provides defines for key-codes" + ); PyDoc_STRVAR(gPyEventToString_doc, -"EventToString(event)\n" -"Take a valid event from the GameKeys module or Keyboard Sensor and return a name" -); + "EventToString(event)\n" + "Take a valid event from the GameKeys module or Keyboard Sensor and return a name" + ); static PyObject *gPyEventToString(PyObject *, PyObject *value) { - PyObject *mod, *dict, *key, *val, *ret = NULL; + PyObject *mod, *dict, *key, *val, *ret = nullptr; Py_ssize_t pos = 0; - mod = PyImport_ImportModule( "GameKeys" ); - if (!mod) - return NULL; + mod = PyImport_ImportModule("GameKeys"); + if (!mod) { + return nullptr; + } dict = PyModule_GetDict(mod); @@ -2576,39 +2261,38 @@ static PyObject *gPyEventToString(PyObject *, PyObject *value) PyErr_Clear(); // in case there was an error clearing Py_DECREF(mod); - if (!ret) PyErr_SetString(PyExc_ValueError, "GameKeys.EventToString(int): expected a valid int keyboard event"); - else Py_INCREF(ret); + if (!ret) { + PyErr_SetString(PyExc_ValueError, "GameKeys.EventToString(int): expected a valid int keyboard event"); + } + else { + Py_INCREF(ret); + } return ret; } PyDoc_STRVAR(gPyEventToCharacter_doc, -"EventToCharacter(event, is_shift)\n" -"Take a valid event from the GameKeys module or Keyboard Sensor and return a character" -); + "EventToCharacter(event, is_shift)\n" + "Take a valid event from the GameKeys module or Keyboard Sensor and return a character" + ); static PyObject *gPyEventToCharacter(PyObject *, PyObject *args) { int event, shift; - if (!PyArg_ParseTuple(args,"ii:EventToCharacter", &event, &shift)) - return NULL; - - if (IsPrintable(event)) { - char ch[2] = {'\0', '\0'}; - ch[0] = ToCharacter(event, (bool)shift); - return PyUnicode_FromString(ch); - } - else { - return PyUnicode_FromString(""); + if (!PyArg_ParseTuple(args, "ii:EventToCharacter", &event, &shift)) { + return nullptr; } + + char character[2] = {SCA_IInputDevice::ConvertKeyToChar((SCA_IInputDevice::SCA_EnumInputs)event, (bool)shift), '\0'}; + return PyUnicode_FromString(character); } static struct PyMethodDef gamekeys_methods[] = { {"EventToCharacter", (PyCFunction)gPyEventToCharacter, METH_VARARGS, (const char *)gPyEventToCharacter_doc}, {"EventToString", (PyCFunction)gPyEventToString, METH_O, (const char *)gPyEventToString_doc}, - { NULL, (PyCFunction) NULL, 0, NULL } + { nullptr, (PyCFunction)nullptr, 0, nullptr } }; static struct PyModuleDef GameKeys_module_def = { @@ -2636,141 +2320,140 @@ PyMODINIT_FUNC initGameKeysPythonBinding() // XXXX Add constants here - KX_MACRO_addTypesToDict(d, AKEY, SCA_IInputDevice::KX_AKEY); - KX_MACRO_addTypesToDict(d, BKEY, SCA_IInputDevice::KX_BKEY); - KX_MACRO_addTypesToDict(d, CKEY, SCA_IInputDevice::KX_CKEY); - KX_MACRO_addTypesToDict(d, DKEY, SCA_IInputDevice::KX_DKEY); - KX_MACRO_addTypesToDict(d, EKEY, SCA_IInputDevice::KX_EKEY); - KX_MACRO_addTypesToDict(d, FKEY, SCA_IInputDevice::KX_FKEY); - KX_MACRO_addTypesToDict(d, GKEY, SCA_IInputDevice::KX_GKEY); - KX_MACRO_addTypesToDict(d, HKEY, SCA_IInputDevice::KX_HKEY); - KX_MACRO_addTypesToDict(d, IKEY, SCA_IInputDevice::KX_IKEY); - KX_MACRO_addTypesToDict(d, JKEY, SCA_IInputDevice::KX_JKEY); - KX_MACRO_addTypesToDict(d, KKEY, SCA_IInputDevice::KX_KKEY); - KX_MACRO_addTypesToDict(d, LKEY, SCA_IInputDevice::KX_LKEY); - KX_MACRO_addTypesToDict(d, MKEY, SCA_IInputDevice::KX_MKEY); - KX_MACRO_addTypesToDict(d, NKEY, SCA_IInputDevice::KX_NKEY); - KX_MACRO_addTypesToDict(d, OKEY, SCA_IInputDevice::KX_OKEY); - KX_MACRO_addTypesToDict(d, PKEY, SCA_IInputDevice::KX_PKEY); - KX_MACRO_addTypesToDict(d, QKEY, SCA_IInputDevice::KX_QKEY); - KX_MACRO_addTypesToDict(d, RKEY, SCA_IInputDevice::KX_RKEY); - KX_MACRO_addTypesToDict(d, SKEY, SCA_IInputDevice::KX_SKEY); - KX_MACRO_addTypesToDict(d, TKEY, SCA_IInputDevice::KX_TKEY); - KX_MACRO_addTypesToDict(d, UKEY, SCA_IInputDevice::KX_UKEY); - KX_MACRO_addTypesToDict(d, VKEY, SCA_IInputDevice::KX_VKEY); - KX_MACRO_addTypesToDict(d, WKEY, SCA_IInputDevice::KX_WKEY); - KX_MACRO_addTypesToDict(d, XKEY, SCA_IInputDevice::KX_XKEY); - KX_MACRO_addTypesToDict(d, YKEY, SCA_IInputDevice::KX_YKEY); - KX_MACRO_addTypesToDict(d, ZKEY, SCA_IInputDevice::KX_ZKEY); - - KX_MACRO_addTypesToDict(d, ZEROKEY, SCA_IInputDevice::KX_ZEROKEY); - KX_MACRO_addTypesToDict(d, ONEKEY, SCA_IInputDevice::KX_ONEKEY); - KX_MACRO_addTypesToDict(d, TWOKEY, SCA_IInputDevice::KX_TWOKEY); - KX_MACRO_addTypesToDict(d, THREEKEY, SCA_IInputDevice::KX_THREEKEY); - KX_MACRO_addTypesToDict(d, FOURKEY, SCA_IInputDevice::KX_FOURKEY); - KX_MACRO_addTypesToDict(d, FIVEKEY, SCA_IInputDevice::KX_FIVEKEY); - KX_MACRO_addTypesToDict(d, SIXKEY, SCA_IInputDevice::KX_SIXKEY); - KX_MACRO_addTypesToDict(d, SEVENKEY, SCA_IInputDevice::KX_SEVENKEY); - KX_MACRO_addTypesToDict(d, EIGHTKEY, SCA_IInputDevice::KX_EIGHTKEY); - KX_MACRO_addTypesToDict(d, NINEKEY, SCA_IInputDevice::KX_NINEKEY); - - KX_MACRO_addTypesToDict(d, CAPSLOCKKEY, SCA_IInputDevice::KX_CAPSLOCKKEY); - - KX_MACRO_addTypesToDict(d, LEFTCTRLKEY, SCA_IInputDevice::KX_LEFTCTRLKEY); - KX_MACRO_addTypesToDict(d, LEFTALTKEY, SCA_IInputDevice::KX_LEFTALTKEY); - KX_MACRO_addTypesToDict(d, RIGHTALTKEY, SCA_IInputDevice::KX_RIGHTALTKEY); - KX_MACRO_addTypesToDict(d, RIGHTCTRLKEY, SCA_IInputDevice::KX_RIGHTCTRLKEY); - KX_MACRO_addTypesToDict(d, RIGHTSHIFTKEY, SCA_IInputDevice::KX_RIGHTSHIFTKEY); - KX_MACRO_addTypesToDict(d, LEFTSHIFTKEY, SCA_IInputDevice::KX_LEFTSHIFTKEY); - - KX_MACRO_addTypesToDict(d, ESCKEY, SCA_IInputDevice::KX_ESCKEY); - KX_MACRO_addTypesToDict(d, TABKEY, SCA_IInputDevice::KX_TABKEY); - KX_MACRO_addTypesToDict(d, RETKEY, SCA_IInputDevice::KX_RETKEY); - KX_MACRO_addTypesToDict(d, ENTERKEY, SCA_IInputDevice::KX_RETKEY); - KX_MACRO_addTypesToDict(d, SPACEKEY, SCA_IInputDevice::KX_SPACEKEY); - KX_MACRO_addTypesToDict(d, LINEFEEDKEY, SCA_IInputDevice::KX_LINEFEEDKEY); - KX_MACRO_addTypesToDict(d, BACKSPACEKEY, SCA_IInputDevice::KX_BACKSPACEKEY); - KX_MACRO_addTypesToDict(d, DELKEY, SCA_IInputDevice::KX_DELKEY); - KX_MACRO_addTypesToDict(d, SEMICOLONKEY, SCA_IInputDevice::KX_SEMICOLONKEY); - KX_MACRO_addTypesToDict(d, PERIODKEY, SCA_IInputDevice::KX_PERIODKEY); - KX_MACRO_addTypesToDict(d, COMMAKEY, SCA_IInputDevice::KX_COMMAKEY); - KX_MACRO_addTypesToDict(d, QUOTEKEY, SCA_IInputDevice::KX_QUOTEKEY); - KX_MACRO_addTypesToDict(d, ACCENTGRAVEKEY, SCA_IInputDevice::KX_ACCENTGRAVEKEY); - KX_MACRO_addTypesToDict(d, MINUSKEY, SCA_IInputDevice::KX_MINUSKEY); - KX_MACRO_addTypesToDict(d, SLASHKEY, SCA_IInputDevice::KX_SLASHKEY); - KX_MACRO_addTypesToDict(d, BACKSLASHKEY, SCA_IInputDevice::KX_BACKSLASHKEY); - KX_MACRO_addTypesToDict(d, EQUALKEY, SCA_IInputDevice::KX_EQUALKEY); - KX_MACRO_addTypesToDict(d, LEFTBRACKETKEY, SCA_IInputDevice::KX_LEFTBRACKETKEY); - KX_MACRO_addTypesToDict(d, RIGHTBRACKETKEY, SCA_IInputDevice::KX_RIGHTBRACKETKEY); - - KX_MACRO_addTypesToDict(d, LEFTARROWKEY, SCA_IInputDevice::KX_LEFTARROWKEY); - KX_MACRO_addTypesToDict(d, DOWNARROWKEY, SCA_IInputDevice::KX_DOWNARROWKEY); - KX_MACRO_addTypesToDict(d, RIGHTARROWKEY, SCA_IInputDevice::KX_RIGHTARROWKEY); - KX_MACRO_addTypesToDict(d, UPARROWKEY, SCA_IInputDevice::KX_UPARROWKEY); - - KX_MACRO_addTypesToDict(d, PAD2 , SCA_IInputDevice::KX_PAD2); - KX_MACRO_addTypesToDict(d, PAD4 , SCA_IInputDevice::KX_PAD4); - KX_MACRO_addTypesToDict(d, PAD6 , SCA_IInputDevice::KX_PAD6); - KX_MACRO_addTypesToDict(d, PAD8 , SCA_IInputDevice::KX_PAD8); - - KX_MACRO_addTypesToDict(d, PAD1 , SCA_IInputDevice::KX_PAD1); - KX_MACRO_addTypesToDict(d, PAD3 , SCA_IInputDevice::KX_PAD3); - KX_MACRO_addTypesToDict(d, PAD5 , SCA_IInputDevice::KX_PAD5); - KX_MACRO_addTypesToDict(d, PAD7 , SCA_IInputDevice::KX_PAD7); - KX_MACRO_addTypesToDict(d, PAD9 , SCA_IInputDevice::KX_PAD9); - - KX_MACRO_addTypesToDict(d, PADPERIOD, SCA_IInputDevice::KX_PADPERIOD); - KX_MACRO_addTypesToDict(d, PADSLASHKEY, SCA_IInputDevice::KX_PADSLASHKEY); - KX_MACRO_addTypesToDict(d, PADASTERKEY, SCA_IInputDevice::KX_PADASTERKEY); - - - KX_MACRO_addTypesToDict(d, PAD0, SCA_IInputDevice::KX_PAD0); - KX_MACRO_addTypesToDict(d, PADMINUS, SCA_IInputDevice::KX_PADMINUS); - KX_MACRO_addTypesToDict(d, PADENTER, SCA_IInputDevice::KX_PADENTER); - KX_MACRO_addTypesToDict(d, PADPLUSKEY, SCA_IInputDevice::KX_PADPLUSKEY); - - - KX_MACRO_addTypesToDict(d, F1KEY, SCA_IInputDevice::KX_F1KEY); - KX_MACRO_addTypesToDict(d, F2KEY, SCA_IInputDevice::KX_F2KEY); - KX_MACRO_addTypesToDict(d, F3KEY, SCA_IInputDevice::KX_F3KEY); - KX_MACRO_addTypesToDict(d, F4KEY, SCA_IInputDevice::KX_F4KEY); - KX_MACRO_addTypesToDict(d, F5KEY, SCA_IInputDevice::KX_F5KEY); - KX_MACRO_addTypesToDict(d, F6KEY, SCA_IInputDevice::KX_F6KEY); - KX_MACRO_addTypesToDict(d, F7KEY, SCA_IInputDevice::KX_F7KEY); - KX_MACRO_addTypesToDict(d, F8KEY, SCA_IInputDevice::KX_F8KEY); - KX_MACRO_addTypesToDict(d, F9KEY, SCA_IInputDevice::KX_F9KEY); - KX_MACRO_addTypesToDict(d, F10KEY, SCA_IInputDevice::KX_F10KEY); - KX_MACRO_addTypesToDict(d, F11KEY, SCA_IInputDevice::KX_F11KEY); - KX_MACRO_addTypesToDict(d, F12KEY, SCA_IInputDevice::KX_F12KEY); - KX_MACRO_addTypesToDict(d, F13KEY, SCA_IInputDevice::KX_F13KEY); - KX_MACRO_addTypesToDict(d, F14KEY, SCA_IInputDevice::KX_F14KEY); - KX_MACRO_addTypesToDict(d, F15KEY, SCA_IInputDevice::KX_F15KEY); - KX_MACRO_addTypesToDict(d, F16KEY, SCA_IInputDevice::KX_F16KEY); - KX_MACRO_addTypesToDict(d, F17KEY, SCA_IInputDevice::KX_F17KEY); - KX_MACRO_addTypesToDict(d, F18KEY, SCA_IInputDevice::KX_F18KEY); - KX_MACRO_addTypesToDict(d, F19KEY, SCA_IInputDevice::KX_F19KEY); - - KX_MACRO_addTypesToDict(d, OSKEY, SCA_IInputDevice::KX_OSKEY); - - KX_MACRO_addTypesToDict(d, PAUSEKEY, SCA_IInputDevice::KX_PAUSEKEY); - KX_MACRO_addTypesToDict(d, INSERTKEY, SCA_IInputDevice::KX_INSERTKEY); - KX_MACRO_addTypesToDict(d, HOMEKEY, SCA_IInputDevice::KX_HOMEKEY); - KX_MACRO_addTypesToDict(d, PAGEUPKEY, SCA_IInputDevice::KX_PAGEUPKEY); - KX_MACRO_addTypesToDict(d, PAGEDOWNKEY, SCA_IInputDevice::KX_PAGEDOWNKEY); - KX_MACRO_addTypesToDict(d, ENDKEY, SCA_IInputDevice::KX_ENDKEY); + KX_MACRO_addTypesToDict(d, AKEY, SCA_IInputDevice::AKEY); + KX_MACRO_addTypesToDict(d, BKEY, SCA_IInputDevice::BKEY); + KX_MACRO_addTypesToDict(d, CKEY, SCA_IInputDevice::CKEY); + KX_MACRO_addTypesToDict(d, DKEY, SCA_IInputDevice::DKEY); + KX_MACRO_addTypesToDict(d, EKEY, SCA_IInputDevice::EKEY); + KX_MACRO_addTypesToDict(d, FKEY, SCA_IInputDevice::FKEY); + KX_MACRO_addTypesToDict(d, GKEY, SCA_IInputDevice::GKEY); + KX_MACRO_addTypesToDict(d, HKEY, SCA_IInputDevice::HKEY_); + KX_MACRO_addTypesToDict(d, IKEY, SCA_IInputDevice::IKEY); + KX_MACRO_addTypesToDict(d, JKEY, SCA_IInputDevice::JKEY); + KX_MACRO_addTypesToDict(d, KKEY, SCA_IInputDevice::KKEY); + KX_MACRO_addTypesToDict(d, LKEY, SCA_IInputDevice::LKEY); + KX_MACRO_addTypesToDict(d, MKEY, SCA_IInputDevice::MKEY); + KX_MACRO_addTypesToDict(d, NKEY, SCA_IInputDevice::NKEY); + KX_MACRO_addTypesToDict(d, OKEY, SCA_IInputDevice::OKEY); + KX_MACRO_addTypesToDict(d, PKEY, SCA_IInputDevice::PKEY); + KX_MACRO_addTypesToDict(d, QKEY, SCA_IInputDevice::QKEY); + KX_MACRO_addTypesToDict(d, RKEY, SCA_IInputDevice::RKEY); + KX_MACRO_addTypesToDict(d, SKEY, SCA_IInputDevice::SKEY); + KX_MACRO_addTypesToDict(d, TKEY, SCA_IInputDevice::TKEY); + KX_MACRO_addTypesToDict(d, UKEY, SCA_IInputDevice::UKEY); + KX_MACRO_addTypesToDict(d, VKEY, SCA_IInputDevice::VKEY); + KX_MACRO_addTypesToDict(d, WKEY, SCA_IInputDevice::WKEY); + KX_MACRO_addTypesToDict(d, XKEY, SCA_IInputDevice::XKEY); + KX_MACRO_addTypesToDict(d, YKEY, SCA_IInputDevice::YKEY); + KX_MACRO_addTypesToDict(d, ZKEY, SCA_IInputDevice::ZKEY); + + KX_MACRO_addTypesToDict(d, ZEROKEY, SCA_IInputDevice::ZEROKEY); + KX_MACRO_addTypesToDict(d, ONEKEY, SCA_IInputDevice::ONEKEY); + KX_MACRO_addTypesToDict(d, TWOKEY, SCA_IInputDevice::TWOKEY); + KX_MACRO_addTypesToDict(d, THREEKEY, SCA_IInputDevice::THREEKEY); + KX_MACRO_addTypesToDict(d, FOURKEY, SCA_IInputDevice::FOURKEY); + KX_MACRO_addTypesToDict(d, FIVEKEY, SCA_IInputDevice::FIVEKEY); + KX_MACRO_addTypesToDict(d, SIXKEY, SCA_IInputDevice::SIXKEY); + KX_MACRO_addTypesToDict(d, SEVENKEY, SCA_IInputDevice::SEVENKEY); + KX_MACRO_addTypesToDict(d, EIGHTKEY, SCA_IInputDevice::EIGHTKEY); + KX_MACRO_addTypesToDict(d, NINEKEY, SCA_IInputDevice::NINEKEY); + + KX_MACRO_addTypesToDict(d, CAPSLOCKKEY, SCA_IInputDevice::CAPSLOCKKEY); + + KX_MACRO_addTypesToDict(d, LEFTCTRLKEY, SCA_IInputDevice::LEFTCTRLKEY); + KX_MACRO_addTypesToDict(d, LEFTALTKEY, SCA_IInputDevice::LEFTALTKEY); + KX_MACRO_addTypesToDict(d, RIGHTALTKEY, SCA_IInputDevice::RIGHTALTKEY); + KX_MACRO_addTypesToDict(d, RIGHTCTRLKEY, SCA_IInputDevice::RIGHTCTRLKEY); + KX_MACRO_addTypesToDict(d, RIGHTSHIFTKEY, SCA_IInputDevice::RIGHTSHIFTKEY); + KX_MACRO_addTypesToDict(d, LEFTSHIFTKEY, SCA_IInputDevice::LEFTSHIFTKEY); + + KX_MACRO_addTypesToDict(d, ESCKEY, SCA_IInputDevice::ESCKEY); + KX_MACRO_addTypesToDict(d, TABKEY, SCA_IInputDevice::TABKEY); + KX_MACRO_addTypesToDict(d, RETKEY, SCA_IInputDevice::RETKEY); + KX_MACRO_addTypesToDict(d, ENTERKEY, SCA_IInputDevice::RETKEY); + KX_MACRO_addTypesToDict(d, SPACEKEY, SCA_IInputDevice::SPACEKEY); + KX_MACRO_addTypesToDict(d, LINEFEEDKEY, SCA_IInputDevice::LINEFEEDKEY); + KX_MACRO_addTypesToDict(d, BACKSPACEKEY, SCA_IInputDevice::BACKSPACEKEY); + KX_MACRO_addTypesToDict(d, DELKEY, SCA_IInputDevice::DELKEY); + KX_MACRO_addTypesToDict(d, SEMICOLONKEY, SCA_IInputDevice::SEMICOLONKEY); + KX_MACRO_addTypesToDict(d, PERIODKEY, SCA_IInputDevice::PERIODKEY); + KX_MACRO_addTypesToDict(d, COMMAKEY, SCA_IInputDevice::COMMAKEY); + KX_MACRO_addTypesToDict(d, QUOTEKEY, SCA_IInputDevice::QUOTEKEY); + KX_MACRO_addTypesToDict(d, ACCENTGRAVEKEY, SCA_IInputDevice::ACCENTGRAVEKEY); + KX_MACRO_addTypesToDict(d, MINUSKEY, SCA_IInputDevice::MINUSKEY); + KX_MACRO_addTypesToDict(d, SLASHKEY, SCA_IInputDevice::SLASHKEY); + KX_MACRO_addTypesToDict(d, BACKSLASHKEY, SCA_IInputDevice::BACKSLASHKEY); + KX_MACRO_addTypesToDict(d, EQUALKEY, SCA_IInputDevice::EQUALKEY); + KX_MACRO_addTypesToDict(d, LEFTBRACKETKEY, SCA_IInputDevice::LEFTBRACKETKEY); + KX_MACRO_addTypesToDict(d, RIGHTBRACKETKEY, SCA_IInputDevice::RIGHTBRACKETKEY); + + KX_MACRO_addTypesToDict(d, LEFTARROWKEY, SCA_IInputDevice::LEFTARROWKEY); + KX_MACRO_addTypesToDict(d, DOWNARROWKEY, SCA_IInputDevice::DOWNARROWKEY); + KX_MACRO_addTypesToDict(d, RIGHTARROWKEY, SCA_IInputDevice::RIGHTARROWKEY); + KX_MACRO_addTypesToDict(d, UPARROWKEY, SCA_IInputDevice::UPARROWKEY); + + KX_MACRO_addTypesToDict(d, PAD2, SCA_IInputDevice::PAD2); + KX_MACRO_addTypesToDict(d, PAD4, SCA_IInputDevice::PAD4); + KX_MACRO_addTypesToDict(d, PAD6, SCA_IInputDevice::PAD6); + KX_MACRO_addTypesToDict(d, PAD8, SCA_IInputDevice::PAD8); + + KX_MACRO_addTypesToDict(d, PAD1, SCA_IInputDevice::PAD1); + KX_MACRO_addTypesToDict(d, PAD3, SCA_IInputDevice::PAD3); + KX_MACRO_addTypesToDict(d, PAD5, SCA_IInputDevice::PAD5); + KX_MACRO_addTypesToDict(d, PAD7, SCA_IInputDevice::PAD7); + KX_MACRO_addTypesToDict(d, PAD9, SCA_IInputDevice::PAD9); + + KX_MACRO_addTypesToDict(d, PADPERIOD, SCA_IInputDevice::PADPERIOD); + KX_MACRO_addTypesToDict(d, PADSLASHKEY, SCA_IInputDevice::PADSLASHKEY); + KX_MACRO_addTypesToDict(d, PADASTERKEY, SCA_IInputDevice::PADASTERKEY); + + + KX_MACRO_addTypesToDict(d, PAD0, SCA_IInputDevice::PAD0); + KX_MACRO_addTypesToDict(d, PADMINUS, SCA_IInputDevice::PADMINUS); + KX_MACRO_addTypesToDict(d, PADENTER, SCA_IInputDevice::PADENTER); + KX_MACRO_addTypesToDict(d, PADPLUSKEY, SCA_IInputDevice::PADPLUSKEY); + + + KX_MACRO_addTypesToDict(d, F1KEY, SCA_IInputDevice::F1KEY); + KX_MACRO_addTypesToDict(d, F2KEY, SCA_IInputDevice::F2KEY); + KX_MACRO_addTypesToDict(d, F3KEY, SCA_IInputDevice::F3KEY); + KX_MACRO_addTypesToDict(d, F4KEY, SCA_IInputDevice::F4KEY); + KX_MACRO_addTypesToDict(d, F5KEY, SCA_IInputDevice::F5KEY); + KX_MACRO_addTypesToDict(d, F6KEY, SCA_IInputDevice::F6KEY); + KX_MACRO_addTypesToDict(d, F7KEY, SCA_IInputDevice::F7KEY); + KX_MACRO_addTypesToDict(d, F8KEY, SCA_IInputDevice::F8KEY); + KX_MACRO_addTypesToDict(d, F9KEY, SCA_IInputDevice::F9KEY); + KX_MACRO_addTypesToDict(d, F10KEY, SCA_IInputDevice::F10KEY); + KX_MACRO_addTypesToDict(d, F11KEY, SCA_IInputDevice::F11KEY); + KX_MACRO_addTypesToDict(d, F12KEY, SCA_IInputDevice::F12KEY); + KX_MACRO_addTypesToDict(d, F13KEY, SCA_IInputDevice::F13KEY); + KX_MACRO_addTypesToDict(d, F14KEY, SCA_IInputDevice::F14KEY); + KX_MACRO_addTypesToDict(d, F15KEY, SCA_IInputDevice::F15KEY); + KX_MACRO_addTypesToDict(d, F16KEY, SCA_IInputDevice::F16KEY); + KX_MACRO_addTypesToDict(d, F17KEY, SCA_IInputDevice::F17KEY); + KX_MACRO_addTypesToDict(d, F18KEY, SCA_IInputDevice::F18KEY); + KX_MACRO_addTypesToDict(d, F19KEY, SCA_IInputDevice::F19KEY); + + KX_MACRO_addTypesToDict(d, OSKEY, SCA_IInputDevice::OSKEY); + + KX_MACRO_addTypesToDict(d, PAUSEKEY, SCA_IInputDevice::PAUSEKEY); + KX_MACRO_addTypesToDict(d, INSERTKEY, SCA_IInputDevice::INSERTKEY); + KX_MACRO_addTypesToDict(d, HOMEKEY, SCA_IInputDevice::HOMEKEY); + KX_MACRO_addTypesToDict(d, PAGEUPKEY, SCA_IInputDevice::PAGEUPKEY); + KX_MACRO_addTypesToDict(d, PAGEDOWNKEY, SCA_IInputDevice::PAGEDOWNKEY); + KX_MACRO_addTypesToDict(d, ENDKEY, SCA_IInputDevice::ENDKEY); // MOUSE - KX_MACRO_addTypesToDict(d, LEFTMOUSE, SCA_IInputDevice::KX_LEFTMOUSE); - KX_MACRO_addTypesToDict(d, MIDDLEMOUSE, SCA_IInputDevice::KX_MIDDLEMOUSE); - KX_MACRO_addTypesToDict(d, RIGHTMOUSE, SCA_IInputDevice::KX_RIGHTMOUSE); - KX_MACRO_addTypesToDict(d, WHEELUPMOUSE, SCA_IInputDevice::KX_WHEELUPMOUSE); - KX_MACRO_addTypesToDict(d, WHEELDOWNMOUSE, SCA_IInputDevice::KX_WHEELDOWNMOUSE); - KX_MACRO_addTypesToDict(d, MOUSEX, SCA_IInputDevice::KX_MOUSEX); - KX_MACRO_addTypesToDict(d, MOUSEY, SCA_IInputDevice::KX_MOUSEY); + KX_MACRO_addTypesToDict(d, LEFTMOUSE, SCA_IInputDevice::LEFTMOUSE); + KX_MACRO_addTypesToDict(d, MIDDLEMOUSE, SCA_IInputDevice::MIDDLEMOUSE); + KX_MACRO_addTypesToDict(d, RIGHTMOUSE, SCA_IInputDevice::RIGHTMOUSE); + KX_MACRO_addTypesToDict(d, WHEELUPMOUSE, SCA_IInputDevice::WHEELUPMOUSE); + KX_MACRO_addTypesToDict(d, WHEELDOWNMOUSE, SCA_IInputDevice::WHEELDOWNMOUSE); + KX_MACRO_addTypesToDict(d, MOUSEX, SCA_IInputDevice::MOUSEX); + KX_MACRO_addTypesToDict(d, MOUSEY, SCA_IInputDevice::MOUSEY); // Check for errors - if (PyErr_Occurred()) - { + if (PyErr_Occurred()) { Py_FatalError("can't initialize module GameKeys"); } @@ -2784,15 +2467,15 @@ PyMODINIT_FUNC initGameKeysPythonBinding() /* ------------------------------------------------------------------------- */ PyDoc_STRVAR(Application_module_documentation, - "This module contains application values that remain unchanged during runtime." - ); + "This module contains application values that remain unchanged during runtime." + ); static struct PyModuleDef Application_module_def = { PyModuleDef_HEAD_INIT, "bge.app", /* m_name */ Application_module_documentation, /* m_doc */ 0, /* m_size */ - NULL, /* m_methods */ + nullptr, /* m_methods */ 0, /* m_reload */ 0, /* m_traverse */ 0, /* m_clear */ @@ -2810,33 +2493,37 @@ PyMODINIT_FUNC initApplicationPythonBinding() d = PyModule_GetDict(m); PyDict_SetItemString(d, "version", Py_BuildValue("(iii)", - BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION)); + BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION)); PyDict_SetItemString(d, "version_string", PyUnicode_FromFormat("%d.%02d (sub %d)", - BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION)); + BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION)); PyDict_SetItemString(d, "version_char", PyUnicode_FromString( - STRINGIFY(BLENDER_VERSION_CHAR))); + STRINGIFY(BLENDER_VERSION_CHAR))); + PyDict_SetItemString(d, "upbge_version", Py_BuildValue("(iii)", + UPBGE_VERSION / 100, UPBGE_VERSION % 100, UPBGE_SUBVERSION)); + PyDict_SetItemString(d, "upbge_version_string", PyUnicode_FromFormat("%d.%d (sub %d)", + UPBGE_VERSION / 100, UPBGE_VERSION % 100, UPBGE_SUBVERSION)); PyDict_SetItemString(d, "has_texture_ffmpeg", #ifdef WITH_FFMPEG - Py_True + Py_True #else - Py_False + Py_False #endif - ); + ); PyDict_SetItemString(d, "has_joystick", #ifdef WITH_SDL - Py_True + Py_True #else - Py_False + Py_False #endif - ); + ); PyDict_SetItemString(d, "has_physics", #ifdef WITH_BULLET - Py_True + Py_True #else - Py_False + Py_False #endif - ); + ); // Check for errors if (PyErr_Occurred()) { @@ -2849,17 +2536,18 @@ PyMODINIT_FUNC initApplicationPythonBinding() // utility function for loading and saving the globalDict -int saveGamePythonConfig( char **marshal_buffer) +void saveGamePythonConfig() { + char *marshal_buffer = nullptr; int marshal_length = 0; PyObject *gameLogic = PyImport_ImportModule("GameLogic"); if (gameLogic) { PyObject *pyGlobalDict = PyDict_GetItemString(PyModule_GetDict(gameLogic), "globalDict"); // Same as importing the module if (pyGlobalDict) { #ifdef Py_MARSHAL_VERSION - PyObject *pyGlobalDictMarshal = PyMarshal_WriteObjectToString( pyGlobalDict, 2); // Py_MARSHAL_VERSION == 2 as of Py2.5 + PyObject *pyGlobalDictMarshal = PyMarshal_WriteObjectToString(pyGlobalDict, 2); // Py_MARSHAL_VERSION == 2 as of Py2.5 #else - PyObject *pyGlobalDictMarshal = PyMarshal_WriteObjectToString( pyGlobalDict ); + PyObject *pyGlobalDictMarshal = PyMarshal_WriteObjectToString(pyGlobalDict); #endif if (pyGlobalDictMarshal) { // for testing only @@ -2867,87 +2555,127 @@ int saveGamePythonConfig( char **marshal_buffer) char *marshal_cstring; marshal_cstring = PyBytes_AsString(pyGlobalDictMarshal); // py3 uses byte arrays - marshal_length= PyBytes_Size(pyGlobalDictMarshal); - *marshal_buffer = new char[marshal_length + 1]; - memcpy(*marshal_buffer, marshal_cstring, marshal_length); + marshal_length = PyBytes_Size(pyGlobalDictMarshal); + marshal_buffer = new char[marshal_length + 1]; + memcpy(marshal_buffer, marshal_cstring, marshal_length); Py_DECREF(pyGlobalDictMarshal); - } else { - printf("Error, bge.logic.globalDict could not be marshal'd\n"); } - } else { - printf("Error, bge.logic.globalDict was removed\n"); + else { + CM_Error("bge.logic.globalDict could not be marshal'd"); + } + } + else { + CM_Error("bge.logic.globalDict was removed"); } Py_DECREF(gameLogic); - } else { + } + else { PyErr_Clear(); - printf("Error, bge.logic failed to import bge.logic.globalDict will be lost\n"); + CM_Error("bge.logic failed to import bge.logic.globalDict will be lost"); } - return marshal_length; -} -int loadGamePythonConfig(char *marshal_buffer, int marshal_length) -{ - /* Restore the dict */ - if (marshal_buffer) { - PyObject *gameLogic = PyImport_ImportModule("GameLogic"); - - if (gameLogic) { - PyObject *pyGlobalDict = PyMarshal_ReadObjectFromString(marshal_buffer, marshal_length); - if (pyGlobalDict) { - PyObject *pyGlobalDict_orig = PyDict_GetItemString(PyModule_GetDict(gameLogic), "globalDict"); // Same as importing the module. - if (pyGlobalDict_orig) { - PyDict_Clear(pyGlobalDict_orig); - PyDict_Update(pyGlobalDict_orig, pyGlobalDict); - } else { - /* this should not happen, but cant find the original globalDict, just assign it then */ - PyDict_SetItemString(PyModule_GetDict(gameLogic), "globalDict", pyGlobalDict); // Same as importing the module. - } - Py_DECREF(gameLogic); - Py_DECREF(pyGlobalDict); - return 1; - } else { - Py_DECREF(gameLogic); - PyErr_Clear(); - printf("Error could not marshall string\n"); + std::string marshal_path = pathGamePythonConfig(); + + if (marshal_length && marshal_buffer) { + FILE *fp = fopen(marshal_path.c_str(), "wb"); + + if (fp) { + if (fwrite(marshal_buffer, 1, marshal_length, fp) != marshal_length) { + CM_Error("could not write marshal data"); } + + fclose(fp); } else { - PyErr_Clear(); - printf("Error, bge.logic failed to import bge.logic.globalDict will be lost\n"); + CM_Error("could not open marshal file"); } } - return 0; + else { + CM_Error("could not create marshal buffer"); + } + + if (marshal_buffer) { + delete[] marshal_buffer; + } } -void pathGamePythonConfig(char *path) +void loadGamePythonConfig() { - int len = strlen(gp_GamePythonPathOrig); // Always use the first loaded blend filename + std::string marshal_path = pathGamePythonConfig(); - BLI_strncpy(path, gp_GamePythonPathOrig, sizeof(gp_GamePythonPathOrig)); + FILE *fp = fopen(marshal_path.c_str(), "rb"); - /* replace extension */ - if (BLI_path_extension_check(path, ".blend")) { - strcpy(path+(len-6), ".bgeconf"); - } else { - strcpy(path+len, ".bgeconf"); + if (fp) { + // obtain file size: + fseek(fp, 0, SEEK_END); + size_t marshal_length = ftell(fp); + if (marshal_length == -1) { + CM_Error("could not read position of '" << marshal_path << "'"); + fclose(fp); + return; + } + rewind(fp); + + char *marshal_buffer = (char *)malloc(sizeof(char) * marshal_length); + + int result = fread(marshal_buffer, 1, marshal_length, fp); + + if (result == marshal_length) { + /* Restore the dict */ + PyObject *gameLogic = PyImport_ImportModule("GameLogic"); + + if (gameLogic) { + PyObject *pyGlobalDict = PyMarshal_ReadObjectFromString(marshal_buffer, marshal_length); + if (pyGlobalDict) { + PyObject *pyGlobalDict_orig = PyDict_GetItemString(PyModule_GetDict(gameLogic), "globalDict"); // Same as importing the module. + if (pyGlobalDict_orig) { + PyDict_Clear(pyGlobalDict_orig); + PyDict_Update(pyGlobalDict_orig, pyGlobalDict); + } + else { + /* this should not happen, but cant find the original globalDict, just assign it then */ + PyDict_SetItemString(PyModule_GetDict(gameLogic), "globalDict", pyGlobalDict); // Same as importing the module. + } + Py_DECREF(gameLogic); + Py_DECREF(pyGlobalDict); + } + else { + Py_DECREF(gameLogic); + PyErr_Clear(); + CM_Error("could not marshall string"); + } + } + else { + PyErr_Clear(); + CM_Error("bge.logic failed to import bge.logic.globalDict will be lost"); + } + } + else { + CM_Error("could not read all of '" << marshal_path << "'"); + } + + free(marshal_buffer); + fclose(fp); + } + else { + CM_Error("could not open '" << marshal_path << "'"); } } -void setGamePythonPath(const char *path) +std::string pathGamePythonConfig() { - BLI_strncpy(gp_GamePythonPath, path, sizeof(gp_GamePythonPath)); - BLI_cleanup_file(NULL, gp_GamePythonPath); /* not absolutely needed but makes resolving path problems less confusing later */ + std::string path = KX_GetOrigPath(); + int len = path.size(); - if (gp_GamePythonPathOrig[0] == '\0') - BLI_strncpy(gp_GamePythonPathOrig, path, sizeof(gp_GamePythonPathOrig)); -} + /* replace extension */ + if (BLI_path_extension_check(path.c_str(), ".blend")) { + path = path.substr(0, len - 6) + std::string(".bgeconf"); + } + else { + path += std::string(".bgeconf"); + } -// we need this so while blender is open (not blenderplayer) -// loading new blendfiles will reset this on starting the -// engine but loading blend files within the BGE wont overwrite gp_GamePythonPathOrig -void resetGamePythonPath() -{ - gp_GamePythonPathOrig[0] = '\0'; + return path; } #endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_PythonInit.h b/source/gameengine/Ketsji/KX_PythonInit.h index 6550934a9166..a43dc784f5f1 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.h +++ b/source/gameengine/Ketsji/KX_PythonInit.h @@ -33,18 +33,12 @@ #define __KX_PYTHONINIT_H__ #include "EXP_Python.h" -#include "STR_String.h" -#include "MT_Vector3.h" +#include -class KX_KetsjiEngine; -class KX_Scene; - -typedef enum { - psl_Lowest = 0, - psl_Highest, -} TPythonSecurityLevel; +#include "DEV_JoystickDefines.h" // For JOYINDEX_MAX -extern bool gUseVisibilityTemp; +class KX_KetsjiEngine; +struct Main; #ifdef WITH_PYTHON PyMODINIT_FUNC initBGE(void); @@ -53,43 +47,38 @@ PyMODINIT_FUNC initGameLogicPythonBinding(void); PyMODINIT_FUNC initGameKeysPythonBinding(void); PyMODINIT_FUNC initRasterizerPythonBinding(void); PyMODINIT_FUNC initVideoTexturePythonBinding(void); -PyObject *initGamePlayerPythonScripting(struct Main *maggie, int argc, char **argv); -PyObject *initGamePythonScripting(struct Main *maggie); - -void exitGamePlayerPythonScripting(); -void exitGamePythonScripting(); -void setupGamePython(KX_KetsjiEngine *ketsjiengine, KX_Scene *startscene, Main *blenderdata, - PyObject *pyGlobalDict, PyObject **gameLogic, PyObject **gameLogic_keys, int argc, char **argv); -void setGamePythonPath(const char *path); -void resetGamePythonPath(); -void pathGamePythonConfig(char *path); -int saveGamePythonConfig(char **marshal_buffer); -int loadGamePythonConfig(char *marshal_buffer, int marshal_length); -#endif -void addImportMain(struct Main *maggie); -void removeImportMain(struct Main *maggie); +// Add a python include path. +void appendPythonPath(const std::string& path); -class KX_KetsjiEngine; -class KX_Scene; +void initPlayerPython(int argc, char **argv); +void exitPlayerPython(); + +void initGamePython(Main *main, PyObject *pyGlobalDict); +void exitGamePython(); -void KX_SetActiveScene(KX_Scene *scene); -KX_Scene *KX_GetActiveScene(); -KX_KetsjiEngine *KX_GetActiveEngine(); +std::string pathGamePythonConfig(); +void saveGamePythonConfig(); +void loadGamePythonConfig(); + +/// Create a python interpreter and stop the engine until the interpreter is active. +void createPythonConsole(); + +// Update Python Joysticks +void updatePythonJoysticks(short (&addrem)[JOYINDEX_MAX]); +#endif + +void addImportMain(Main *maggie); +void removeImportMain(Main *maggie); typedef int (*PyNextFrameFunc)(void *); struct PyNextFrameState { - /** can be either a GPG_NextFrameState or a BL_KetsjiNextFrameState */ + /// Launcher currently used (LA_Launcher). void *state; - /** can be either GPG_PyNextFrame or BL_KetsjiPyNextFrame */ + /// Launcher python frame function (LA_Launcher::PythonEngineNextFrame). PyNextFrameFunc func; }; extern struct PyNextFrameState pynextframestate; -void KX_RasterizerDrawDebugLine(const MT_Vector3 &from,const MT_Vector3 &to,const MT_Vector3 &color); -void KX_RasterizerDrawDebugCircle(const MT_Vector3 ¢er, const MT_Scalar radius, const MT_Vector3 &color, - const MT_Vector3 &normal, int nsector); - - #endif /* __KX_PYTHONINIT_H__ */ diff --git a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp index a9c90b33cdab..ac45e56480c0 100644 --- a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp +++ b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp @@ -35,32 +35,46 @@ /* Only for Class::Parents */ #include "BL_BlenderShader.h" -#include "BL_ShapeActionActuator.h" +#include "BL_Shader.h" +#include "BL_ActionActuator.h" #include "BL_ArmatureActuator.h" #include "BL_ArmatureConstraint.h" #include "BL_ArmatureObject.h" #include "BL_ArmatureChannel.h" +#include "BL_Texture.h" +#include "KX_2DFilter.h" +#include "KX_2DFilterManager.h" +#include "KX_2DFilterOffScreen.h" #include "KX_WorldInfo.h" #include "KX_ArmatureSensor.h" +#include "KX_BatchGroup.h" #include "KX_BlenderMaterial.h" +#include "KX_BoundingBox.h" +#include "KX_Camera.h" #include "KX_CameraActuator.h" #include "KX_CharacterWrapper.h" #include "KX_ConstraintActuator.h" #include "KX_ConstraintWrapper.h" +#include "KX_CubeMap.h" #include "KX_GameActuator.h" #include "KX_LibLoadStatus.h" -#include "KX_Light.h" +#include "KX_LightObject.h" +#include "KX_LodLevel.h" +#include "KX_LodManager.h" #include "KX_FontObject.h" -#include "KX_MeshProxy.h" +#include "KX_MeshBuilder.h" +#include "KX_Mesh.h" #include "KX_MouseFocusSensor.h" #include "KX_NetworkMessageActuator.h" #include "KX_NetworkMessageSensor.h" #include "KX_ObjectActuator.h" #include "KX_ParentActuator.h" +#include "KX_PlanarMap.h" #include "KX_PolyProxy.h" -#include "KX_SCA_AddObjectActuator.h" -#include "KX_SCA_EndObjectActuator.h" -#include "KX_SCA_ReplaceMeshActuator.h" +#include "KX_PythonComponent.h" +#include "KX_AddObjectActuator.h" +#include "KX_EndObjectActuator.h" +#include "KX_ReplaceMeshActuator.h" #include "KX_SceneActuator.h" #include "KX_StateActuator.h" #include "KX_SteeringActuator.h" @@ -72,6 +86,7 @@ #include "SCA_ActuatorSensor.h" #include "SCA_AlwaysSensor.h" #include "SCA_DelaySensor.h" +#include "SCA_InputEvent.h" #include "SCA_JoystickSensor.h" #include "SCA_KeyboardSensor.h" #include "SCA_MouseSensor.h" @@ -87,31 +102,37 @@ #include "KX_NearSensor.h" #include "KX_RadarSensor.h" #include "KX_RaySensor.h" -#include "KX_SCA_DynamicActuator.h" +#include "KX_MovementSensor.h" +#include "KX_DynamicActuator.h" #include "KX_SoundActuator.h" -#include "KX_TouchSensor.h" +#include "KX_CollisionSensor.h" #include "KX_VisibilityActuator.h" #include "SCA_PropertySensor.h" #include "SCA_PythonController.h" #include "SCA_RandomActuator.h" +#include "SCA_VibrationActuator.h" #include "SCA_IController.h" #include "KX_NavMeshObject.h" #include "KX_MouseActuator.h" +#include "KX_CollisionContactPoints.h" #include "EXP_ListWrapper.h" +#include "Texture.h" static void PyType_Attr_Set(PyGetSetDef *attr_getset, PyAttributeDef *attr) { - attr_getset->name= (char *)attr->m_name; - attr_getset->doc= NULL; + attr_getset->name = (char *)attr->m_name.c_str(); + attr_getset->doc = nullptr; - attr_getset->get= reinterpret_cast(PyObjectPlus::py_get_attrdef); + attr_getset->get = reinterpret_cast(EXP_PyObjectPlus::py_get_attrdef); - if (attr->m_access==KX_PYATTRIBUTE_RO) - attr_getset->set= NULL; - else - attr_getset->set= reinterpret_cast(PyObjectPlus::py_set_attrdef); + if (attr->m_access == EXP_PYATTRIBUTE_RO) { + attr_getset->set = nullptr; + } + else { + attr_getset->set = reinterpret_cast(EXP_PyObjectPlus::py_set_attrdef); + } - attr_getset->closure= reinterpret_cast(attr); + attr_getset->closure = reinterpret_cast(attr); } static void PyType_Ready_ADD(PyObject *dict, PyTypeObject *tp, PyAttributeDef *attributes, PyAttributeDef *attributesPtr, int init_getset) @@ -122,37 +143,37 @@ static void PyType_Ready_ADD(PyObject *dict, PyTypeObject *tp, PyAttributeDef *a /* we need to do this for all types before calling PyType_Ready * since they will call the parents PyType_Ready and those might not have initialized vars yet */ - //if (tp->tp_base==NULL) - // printf("Debug: No Parents - '%s'\n" , tp->tp_name); - - if (tp->tp_getset==NULL && ((attributes && attributes->m_name) || (attributesPtr && attributesPtr->m_name))) { + if (tp->tp_getset == nullptr && ((attributes && !attributes->m_name.empty()) || (attributesPtr && !attributesPtr->m_name.empty()))) { PyGetSetDef *attr_getset; - int attr_tot= 0; + int attr_tot = 0; if (attributes) { - for (attr= attributes; attr->m_name; attr++, attr_tot++) + for (attr = attributes; !attr->m_name.empty(); attr++, attr_tot++) { attr->m_usePtr = false; + } } if (attributesPtr) { - for (attr= attributesPtr; attr->m_name; attr++, attr_tot++) + for (attr = attributesPtr; !attr->m_name.empty(); attr++, attr_tot++) { attr->m_usePtr = true; + } } - tp->tp_getset = attr_getset = reinterpret_cast(PyMem_Malloc((attr_tot+1) * sizeof(PyGetSetDef))); // XXX - Todo, free + tp->tp_getset = attr_getset = reinterpret_cast(PyMem_Malloc((attr_tot + 1) * sizeof(PyGetSetDef))); // XXX - Todo, free if (attributes) { - for (attr= attributes; attr->m_name; attr++, attr_getset++) { + for (attr = attributes; !attr->m_name.empty(); attr++, attr_getset++) { PyType_Attr_Set(attr_getset, attr); } } if (attributesPtr) { - for (attr= attributesPtr; attr->m_name; attr++, attr_getset++) { + for (attr = attributesPtr; !attr->m_name.empty(); attr++, attr_getset++) { PyType_Attr_Set(attr_getset, attr); } } memset(attr_getset, 0, sizeof(PyGetSetDef)); } - } else { + } + else { PyType_Ready(tp); PyDict_SetItemString(dict, tp->tp_name, reinterpret_cast(tp)); } @@ -160,24 +181,24 @@ static void PyType_Ready_ADD(PyObject *dict, PyTypeObject *tp, PyAttributeDef *a } -#define PyType_Ready_Attr(d, n, i) PyType_Ready_ADD(d, &n::Type, n::Attributes, NULL, i) +#define PyType_Ready_Attr(d, n, i) PyType_Ready_ADD(d, &n::Type, n::Attributes, nullptr, i) #define PyType_Ready_AttrPtr(d, n, i) PyType_Ready_ADD(d, &n::Type, n::Attributes, n::AttributesPtr, i) PyDoc_STRVAR(GameTypes_module_documentation, -"This module provides access to the game engine data types." -); + "This module provides access to the game engine data types." + ); static struct PyModuleDef GameTypes_module_def = { PyModuleDef_HEAD_INIT, "GameTypes", /* m_name */ GameTypes_module_documentation, /* m_doc */ 0, /* m_size */ - NULL, /* m_methods */ - NULL, /* m_reload */ - NULL, /* m_traverse */ - NULL, /* m_clear */ - NULL, /* m_free */ + nullptr, /* m_methods */ + nullptr, /* m_reload */ + nullptr, /* m_traverse */ + nullptr, /* m_clear */ + nullptr, /* m_free */ }; @@ -191,45 +212,58 @@ PyMODINIT_FUNC initGameTypesPythonBinding(void) dict = PyModule_GetDict(m); - for (int init_getset= 1; init_getset > -1; init_getset--) { /* run twice, once to init the getsets another to run PyType_Ready */ + for (int init_getset = 1; init_getset > -1; init_getset--) { /* run twice, once to init the getsets another to run PyType_Ready */ PyType_Ready_Attr(dict, BL_ActionActuator, init_getset); PyType_Ready_Attr(dict, BL_Shader, init_getset); - PyType_Ready_Attr(dict, BL_ShapeActionActuator, init_getset); PyType_Ready_Attr(dict, BL_ArmatureObject, init_getset); PyType_Ready_Attr(dict, BL_ArmatureActuator, init_getset); PyType_Ready_Attr(dict, BL_ArmatureConstraint, init_getset); PyType_Ready_AttrPtr(dict, BL_ArmatureBone, init_getset); PyType_Ready_AttrPtr(dict, BL_ArmatureChannel, init_getset); - // PyType_Ready_Attr(dict, CPropValue, init_getset); // doesn't use Py_Header - PyType_Ready_Attr(dict, CListValue, init_getset); - PyType_Ready_Attr(dict, CListWrapper, init_getset); - PyType_Ready_Attr(dict, CValue, init_getset); + PyType_Ready_Attr(dict, BL_Texture, init_getset); + // PyType_Ready_Attr(dict, EXP_PropValue, init_getset); // doesn't use Py_Header + PyType_Ready_Attr(dict, EXP_BaseListValue, init_getset); + PyType_Ready_Attr(dict, EXP_BaseListWrapper, init_getset); + PyType_Ready_Attr(dict, EXP_Value, init_getset); + PyType_Ready_Attr(dict, KX_2DFilter, init_getset); + PyType_Ready_Attr(dict, KX_2DFilterManager, init_getset); + PyType_Ready_Attr(dict, KX_2DFilterOffScreen, init_getset); PyType_Ready_Attr(dict, KX_ArmatureSensor, init_getset); + PyType_Ready_Attr(dict, KX_BatchGroup, init_getset); PyType_Ready_Attr(dict, KX_BlenderMaterial, init_getset); + PyType_Ready_Attr(dict, KX_BoundingBox, init_getset); PyType_Ready_Attr(dict, KX_Camera, init_getset); PyType_Ready_Attr(dict, KX_CameraActuator, init_getset); PyType_Ready_Attr(dict, KX_CharacterWrapper, init_getset); PyType_Ready_Attr(dict, KX_ConstraintActuator, init_getset); PyType_Ready_Attr(dict, KX_ConstraintWrapper, init_getset); + PyType_Ready_Attr(dict, KX_CubeMap, init_getset); PyType_Ready_Attr(dict, KX_GameActuator, init_getset); PyType_Ready_Attr(dict, KX_GameObject, init_getset); PyType_Ready_Attr(dict, KX_LibLoadStatus, init_getset); PyType_Ready_Attr(dict, KX_LightObject, init_getset); + PyType_Ready_Attr(dict, KX_LodLevel, init_getset); + PyType_Ready_Attr(dict, KX_LodManager, init_getset); PyType_Ready_Attr(dict, KX_FontObject, init_getset); - PyType_Ready_Attr(dict, KX_MeshProxy, init_getset); + PyType_Ready_Attr(dict, KX_MeshBuilder, init_getset); + PyType_Ready_Attr(dict, KX_MeshBuilderSlot, init_getset); + PyType_Ready_Attr(dict, KX_Mesh, init_getset); PyType_Ready_Attr(dict, KX_MouseFocusSensor, init_getset); + PyType_Ready_Attr(dict, KX_MovementSensor, init_getset); PyType_Ready_Attr(dict, KX_NearSensor, init_getset); PyType_Ready_Attr(dict, KX_NetworkMessageActuator, init_getset); PyType_Ready_Attr(dict, KX_NetworkMessageSensor, init_getset); PyType_Ready_Attr(dict, KX_ObjectActuator, init_getset); PyType_Ready_Attr(dict, KX_ParentActuator, init_getset); + PyType_Ready_Attr(dict, KX_PlanarMap, init_getset); PyType_Ready_Attr(dict, KX_PolyProxy, init_getset); + PyType_Ready_Attr(dict, KX_PythonComponent, init_getset); PyType_Ready_Attr(dict, KX_RadarSensor, init_getset); PyType_Ready_Attr(dict, KX_RaySensor, init_getset); - PyType_Ready_Attr(dict, KX_SCA_AddObjectActuator, init_getset); - PyType_Ready_Attr(dict, KX_SCA_DynamicActuator, init_getset); - PyType_Ready_Attr(dict, KX_SCA_EndObjectActuator, init_getset); - PyType_Ready_Attr(dict, KX_SCA_ReplaceMeshActuator, init_getset); + PyType_Ready_Attr(dict, KX_AddObjectActuator, init_getset); + PyType_Ready_Attr(dict, KX_DynamicActuator, init_getset); + PyType_Ready_Attr(dict, KX_EndObjectActuator, init_getset); + PyType_Ready_Attr(dict, KX_ReplaceMeshActuator, init_getset); PyType_Ready_Attr(dict, KX_Scene, init_getset); PyType_Ready_Attr(dict, KX_WorldInfo, init_getset); PyType_Ready_Attr(dict, KX_NavMeshObject, init_getset); @@ -237,13 +271,15 @@ PyMODINIT_FUNC initGameTypesPythonBinding(void) PyType_Ready_Attr(dict, KX_SoundActuator, init_getset); PyType_Ready_Attr(dict, KX_StateActuator, init_getset); PyType_Ready_Attr(dict, KX_SteeringActuator, init_getset); - PyType_Ready_Attr(dict, KX_TouchSensor, init_getset); + PyType_Ready_Attr(dict, KX_CollisionSensor, init_getset); + PyType_Ready_Attr(dict, KX_TextureRenderer, init_getset); PyType_Ready_Attr(dict, KX_TrackToActuator, init_getset); PyType_Ready_Attr(dict, KX_VehicleWrapper, init_getset); PyType_Ready_Attr(dict, KX_VertexProxy, init_getset); PyType_Ready_Attr(dict, KX_VisibilityActuator, init_getset); PyType_Ready_Attr(dict, KX_MouseActuator, init_getset); - PyType_Ready_Attr(dict, PyObjectPlus, init_getset); + PyType_Ready_Attr(dict, KX_CollisionContactPoint, init_getset); + PyType_Ready_Attr(dict, EXP_PyObjectPlus, init_getset); PyType_Ready_Attr(dict, SCA_2DFilterActuator, init_getset); PyType_Ready_Attr(dict, SCA_ANDController, init_getset); // PyType_Ready_Attr(dict, SCA_Actuator, init_getset); // doesn't use Py_Header @@ -251,6 +287,7 @@ PyMODINIT_FUNC initGameTypesPythonBinding(void) PyType_Ready_Attr(dict, SCA_AlwaysSensor, init_getset); PyType_Ready_Attr(dict, SCA_DelaySensor, init_getset); PyType_Ready_Attr(dict, SCA_ILogicBrick, init_getset); + PyType_Ready_Attr(dict, SCA_InputEvent, init_getset); PyType_Ready_Attr(dict, SCA_IObject, init_getset); PyType_Ready_Attr(dict, SCA_ISensor, init_getset); PyType_Ready_Attr(dict, SCA_JoystickSensor, init_getset); @@ -264,12 +301,14 @@ PyMODINIT_FUNC initGameTypesPythonBinding(void) PyType_Ready_Attr(dict, SCA_PythonController, init_getset); PyType_Ready_Attr(dict, SCA_RandomActuator, init_getset); PyType_Ready_Attr(dict, SCA_RandomSensor, init_getset); + PyType_Ready_Attr(dict, SCA_VibrationActuator, init_getset); PyType_Ready_Attr(dict, SCA_XNORController, init_getset); PyType_Ready_Attr(dict, SCA_XORController, init_getset); PyType_Ready_Attr(dict, SCA_IController, init_getset); PyType_Ready_Attr(dict, SCA_PythonJoystick, init_getset); PyType_Ready_Attr(dict, SCA_PythonKeyboard, init_getset); PyType_Ready_Attr(dict, SCA_PythonMouse, init_getset); + PyType_Ready_Attr(dict, Texture, init_getset); } #ifdef USE_MATHUTILS @@ -278,6 +317,8 @@ PyMODINIT_FUNC initGameTypesPythonBinding(void) KX_ObjectActuator_Mathutils_Callback_Init(); KX_WorldInfo_Mathutils_Callback_Init(); KX_BlenderMaterial_Mathutils_Callback_Init(); + KX_BoundingBox_Mathutils_Callback_Init(); + BL_Texture_Mathutils_Callback_Init(); #endif return m; diff --git a/source/gameengine/Ketsji/KX_PythonMain.cpp b/source/gameengine/Ketsji/KX_PythonMain.cpp index 740bb102fd95..6c59f47f0228 100644 --- a/source/gameengine/Ketsji/KX_PythonMain.cpp +++ b/source/gameengine/Ketsji/KX_PythonMain.cpp @@ -26,46 +26,35 @@ #include "KX_PythonMain.h" -#ifdef __cplusplus extern "C" { -#endif +# include "BLI_listbase.h" -#include +# include "BKE_text.h" +# include "BKE_idprop.h" +# include "BKE_main.h" -#include "MEM_guardedalloc.h" - -#include "BLI_string.h" -#include "BLI_listbase.h" - -#include "BKE_text.h" -#include "BKE_main.h" -#include "BKE_idprop.h" - - -#ifdef __cplusplus +# include "DNA_scene_types.h" } -#endif -extern "C" char *KX_GetPythonMain(struct Scene *scene) +std::string KX_GetPythonMain(Scene *scene) { - /* examine custom scene properties */ + // Examine custom scene properties. if (scene->id.properties) { IDProperty *item = IDP_GetPropertyTypeFromGroup(scene->id.properties, "__main__", IDP_STRING); if (item) { - return BLI_strdup(IDP_String(item)); + return IDP_String(item); } } - return NULL; + return ""; } -extern "C" char *KX_GetPythonCode(Main *bmain, char *python_main) +std::string KX_GetPythonCode(Main *bmain, const std::string& python_main) { - Text *text; - - if ((text = (Text *)BLI_findstring(&bmain->text, python_main, offsetof(ID, name) + 2))) { + Text *text = (Text *)BLI_findstring(&bmain->text, python_main.c_str(), offsetof(ID, name) + 2); + if (text) { return txt_to_buf(text); } - return NULL; + return ""; } diff --git a/source/gameengine/Ketsji/KX_PythonMain.h b/source/gameengine/Ketsji/KX_PythonMain.h index c627a4a147a8..2cf22db6e8bf 100644 --- a/source/gameengine/Ketsji/KX_PythonMain.h +++ b/source/gameengine/Ketsji/KX_PythonMain.h @@ -32,10 +32,12 @@ #ifndef __KX_PYTHON_MAIN__ #define __KX_PYTHON_MAIN__ -#include "BLI_sys_types.h" -#include "BKE_main.h" -#include "DNA_scene_types.h" -extern "C" char *KX_GetPythonMain(struct Scene* scene); -extern "C" char *KX_GetPythonCode(struct Main *main, char *python_main); +#include + +struct Scene; +struct Main; + +std::string KX_GetPythonMain(Scene* scene); +std::string KX_GetPythonCode(Main *main, const std::string& python_main); #endif /* __KX_PYTHON_MAIN__ */ diff --git a/source/gameengine/Ketsji/KX_RadarSensor.cpp b/source/gameengine/Ketsji/KX_RadarSensor.cpp index 4f7a0e330112..cb1d25531338 100644 --- a/source/gameengine/Ketsji/KX_RadarSensor.cpp +++ b/source/gameengine/Ketsji/KX_RadarSensor.cpp @@ -37,37 +37,39 @@ #include "PHY_IMotionState.h" #include "DNA_sensor_types.h" +#include "BLI_math_rotation.h" + /** - * RadarSensor constructor. Creates a near-sensor derived class, with a cone collision shape. + * RadarSensor constructor. Creates a near-sensor derived class, with a cone collision shape. */ -KX_RadarSensor::KX_RadarSensor(SCA_EventManager* eventmgr, - KX_GameObject* gameobj, - PHY_IPhysicsController* physCtrl, - double coneradius, - double coneheight, - int axis, - double margin, - double resetmargin, - bool bFindMaterial, - const STR_String& touchedpropname) - - : KX_NearSensor( - eventmgr, - gameobj, - //DT_NewCone(coneradius,coneheight), - margin, - resetmargin, - bFindMaterial, - touchedpropname, - physCtrl), - - m_coneradius(coneradius), - m_coneheight(coneheight), - m_axis(axis) +KX_RadarSensor::KX_RadarSensor(SCA_EventManager *eventmgr, + KX_GameObject *gameobj, + PHY_IPhysicsController *physCtrl, + double coneradius, + double coneheight, + int axis, + double margin, + double resetmargin, + bool bFindMaterial, + const std::string& touchedpropname) + + :KX_NearSensor( + eventmgr, + gameobj, + //DT_NewCone(coneradius,coneheight), + margin, + resetmargin, + bFindMaterial, + touchedpropname, + physCtrl), + + m_coneradius(coneradius), + m_coneheight(coneheight), + m_axis(axis) { m_client_info->m_type = KX_ClientObjectInfo::SENSOR; //m_client_info->m_clientobject = gameobj; - //m_client_info->m_auxilary_info = NULL; + //m_client_info->m_auxilary_info = nullptr; //sumoObj->setClientObject(&m_client_info); } @@ -76,9 +78,9 @@ KX_RadarSensor::~KX_RadarSensor() } -CValue* KX_RadarSensor::GetReplica() +EXP_Value *KX_RadarSensor::GetReplica() { - KX_RadarSensor* replica = new KX_RadarSensor(*this); + KX_RadarSensor *replica = new KX_RadarSensor(*this); replica->ProcessReplica(); return replica; } @@ -88,86 +90,59 @@ CValue* KX_RadarSensor::GetReplica() * for usage. */ void KX_RadarSensor::SynchronizeTransform() { - // Getting the parent location was commented out. Why? - MT_Transform trans; - trans.setOrigin(((KX_GameObject*)GetParent())->NodeGetWorldPosition()); - trans.setBasis(((KX_GameObject*)GetParent())->NodeGetWorldOrientation()); + KX_GameObject *obj = static_cast(GetParent()); + mt::mat3 rot = obj->NodeGetWorldOrientation(); + const mt::vec3& pos = obj->NodeGetWorldPosition(); // What is the default orientation? pointing in the -y direction? // is the geometry correctly converted? // a collision cone is oriented // center the cone correctly // depends on the radar 'axis' - switch (m_axis) - { - case SENS_RADAR_X_AXIS: // +X Axis + switch (m_axis) { + case SENS_RADAR_X_AXIS: // +X Axis { - MT_Quaternion rotquatje(MT_Vector3(0,0,1),MT_radians(90)); - trans.rotate(rotquatje); - trans.translate(MT_Vector3 (0, -m_coneheight/2.0f, 0)); + rot *= mt::mat3(0.0f, 0.0f, M_PI / 2.0f); break; }; - case SENS_RADAR_Y_AXIS: // +Y Axis + case SENS_RADAR_Y_AXIS: // +Y Axis { - MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(-180)); - trans.rotate(rotquatje); - trans.translate(MT_Vector3 (0, -m_coneheight/2.0f, 0)); + rot *= mt::mat3(-M_PI, 0.0f, 0.0f); break; }; - case SENS_RADAR_Z_AXIS: // +Z Axis + case SENS_RADAR_Z_AXIS: // +Z Axis { - MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(-90)); - trans.rotate(rotquatje); - trans.translate(MT_Vector3 (0, -m_coneheight/2.0f, 0)); + rot *= mt::mat3(-M_PI / 2.0f, 0.0f, 0.0f); break; }; - case SENS_RADAR_NEG_X_AXIS: // -X Axis + case SENS_RADAR_NEG_X_AXIS: // -X Axis { - MT_Quaternion rotquatje(MT_Vector3(0,0,1),MT_radians(-90)); - trans.rotate(rotquatje); - trans.translate(MT_Vector3 (0, -m_coneheight/2.0f, 0)); + rot *= mt::mat3(0.0f, 0.0f, -M_PI / 2.0f); break; }; - case SENS_RADAR_NEG_Y_AXIS: // -Y Axis + case SENS_RADAR_NEG_Y_AXIS: // -Y Axis { - //MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(-180)); - //trans.rotate(rotquatje); - trans.translate(MT_Vector3 (0, -m_coneheight/2.0f, 0)); break; }; - case SENS_RADAR_NEG_Z_AXIS: // -Z Axis + case SENS_RADAR_NEG_Z_AXIS: // -Z Axis { - MT_Quaternion rotquatje(MT_Vector3(1,0,0),MT_radians(90)); - trans.rotate(rotquatje); - trans.translate(MT_Vector3 (0, -m_coneheight/2.0f, 0)); + rot *= mt::mat3(M_PI / 2.0f, 0.0f, 0.0f); break; }; - default: + default: { } } - //Using a temp variable to translate MT_Point3 to float[3]. - //float[3] works better for the Python interface. - MT_Point3 temp = trans.getOrigin(); - m_cone_origin[0] = temp[0]; - m_cone_origin[1] = temp[1]; - m_cone_origin[2] = temp[2]; - - temp = trans(MT_Point3(0, -m_coneheight/2.0f, 0)); - m_cone_target[0] = temp[0]; - m_cone_target[1] = temp[1]; - m_cone_target[2] = temp[2]; - - - if (m_physCtrl) - { - PHY_IMotionState* motionState = m_physCtrl->GetMotionState(); - const MT_Point3& pos = trans.getOrigin(); - float ori[12]; - trans.getBasis().getValue(ori); - motionState->SetWorldPosition(pos[0], pos[1], pos[2]); - motionState->SetWorldOrientation(ori); + mt::mat3x4 trans(rot, pos + rot * mt::vec3(0, -m_coneheight / 2.0f, 0)); + + m_cone_origin = trans.TranslationVector3D(); + m_cone_target = trans * mt::vec3(0, -m_coneheight/2.0f, 0); + + if (m_physCtrl) { + PHY_IMotionState *motionState = m_physCtrl->GetMotionState(); + motionState->SetWorldPosition(trans.TranslationVector3D()); + motionState->SetWorldOrientation(trans.RotationMatrix()); m_physCtrl->WriteMotionStateToDynamics(true); } @@ -183,9 +158,9 @@ void KX_RadarSensor::SynchronizeTransform() /* Python Integration Hooks */ /* ------------------------------------------------------------------------- */ PyTypeObject KX_RadarSensor::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_RadarSensor", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -193,37 +168,37 @@ PyTypeObject KX_RadarSensor::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &KX_NearSensor::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_RadarSensor::Methods[] = { - {NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_RadarSensor::Attributes[] = { - KX_PYATTRIBUTE_FLOAT_ARRAY_RO("coneOrigin", KX_RadarSensor, m_cone_origin, 3), - KX_PYATTRIBUTE_FLOAT_ARRAY_RO("coneTarget", KX_RadarSensor, m_cone_target, 3), - KX_PYATTRIBUTE_FLOAT_RO("distance", KX_RadarSensor, m_coneheight), - KX_PYATTRIBUTE_RO_FUNCTION("angle", KX_RadarSensor, pyattr_get_angle), - KX_PYATTRIBUTE_INT_RW("axis", 0, 5, true, KX_RadarSensor, m_axis), - {NULL} //Sentinel + EXP_PYATTRIBUTE_VECTOR_RO("coneOrigin", KX_RadarSensor, m_cone_origin, 3), + EXP_PYATTRIBUTE_VECTOR_RO("coneTarget", KX_RadarSensor, m_cone_target, 3), + EXP_PYATTRIBUTE_FLOAT_RO("distance", KX_RadarSensor, m_coneheight), + EXP_PYATTRIBUTE_RO_FUNCTION("angle", KX_RadarSensor, pyattr_get_angle), + EXP_PYATTRIBUTE_INT_RW("axis", 0, 5, true, KX_RadarSensor, m_axis), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *KX_RadarSensor::pyattr_get_angle(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_RadarSensor::pyattr_get_angle(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_RadarSensor* self = static_cast(self_v); + KX_RadarSensor *self = static_cast(self_v); // The original angle from the gui was converted, so we recalculate the value here to maintain // consistency between Python and the gui - return PyFloat_FromDouble(MT_degrees(atan(self->m_coneradius / self->m_coneheight)) * 2); + return PyFloat_FromDouble(RAD2DEGF(atan(self->m_coneradius / self->m_coneheight)) * 2); } diff --git a/source/gameengine/Ketsji/KX_RadarSensor.h b/source/gameengine/Ketsji/KX_RadarSensor.h index c0cb7bc65d59..dbf58485f596 100644 --- a/source/gameengine/Ketsji/KX_RadarSensor.h +++ b/source/gameengine/Ketsji/KX_RadarSensor.h @@ -33,7 +33,6 @@ #define __KX_RADARSENSOR_H__ #include "KX_NearSensor.h" -#include "MT_Point3.h" /** * Radar 'cone' sensor. Very similar to a near-sensor, but instead of a sphere, a cone is used. @@ -42,7 +41,7 @@ class KX_RadarSensor : public KX_NearSensor { protected: Py_Header - + float m_coneradius; /** @@ -54,13 +53,13 @@ class KX_RadarSensor : public KX_NearSensor /** * The previous position of the origin of the cone. */ - float m_cone_origin[3]; + mt::vec3 m_cone_origin; /** * The previous direction of the cone (origin to bottom plane). */ - float m_cone_target[3]; - + mt::vec3 m_cone_target; + public: KX_RadarSensor(SCA_EventManager* eventmgr, @@ -72,11 +71,11 @@ class KX_RadarSensor : public KX_NearSensor double margin, double resetmargin, bool bFindMaterial, - const STR_String& touchedpropname); + const std::string& touchedpropname); KX_RadarSensor(); virtual ~KX_RadarSensor(); virtual void SynchronizeTransform(); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ @@ -93,7 +92,7 @@ class KX_RadarSensor : public KX_NearSensor virtual sensortype GetSensorType() { return ST_RADAR; } /* python */ #ifdef WITH_PYTHON - static PyObject* pyattr_get_angle(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); + static PyObject* pyattr_get_angle(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); #endif }; diff --git a/source/gameengine/Ketsji/KX_RayCast.cpp b/source/gameengine/Ketsji/KX_RayCast.cpp index ad021bbc871b..ea74e35dd723 100644 --- a/source/gameengine/Ketsji/KX_RayCast.cpp +++ b/source/gameengine/Ketsji/KX_RayCast.cpp @@ -31,37 +31,35 @@ */ -#include -#include - #include "KX_RayCast.h" -#include "MT_Point3.h" -#include "MT_Vector3.h" - #include "PHY_IPhysicsEnvironment.h" #include "PHY_IPhysicsController.h" -KX_RayCast::KX_RayCast(PHY_IPhysicsController* ignoreController, bool faceNormal, bool faceUV) +#include "CM_Message.h" + +KX_RayCast::KX_RayCast(PHY_IPhysicsController *ignoreController, bool faceNormal, bool faceUV) :PHY_IRayCastFilterCallback(ignoreController, faceNormal, faceUV) { } -void KX_RayCast::reportHit(PHY_RayCastResult* result) +void KX_RayCast::reportHit(PHY_RayCastResult *result) { m_hitFound = true; - m_hitPoint = MT_Vector3(result->m_hitPoint); - m_hitNormal = MT_Vector3(result->m_hitNormal); + m_hitPoint = mt::vec3(result->m_hitPoint); + m_hitNormal = mt::vec3(result->m_hitNormal); m_hitUVOK = result->m_hitUVOK; - m_hitUV = MT_Vector2(result->m_hitUV); + m_hitUV = mt::vec2(result->m_hitUV); m_hitMesh = result->m_meshObject; m_hitPolygon = result->m_polygon; } -bool KX_RayCast::RayTest(PHY_IPhysicsEnvironment* physics_environment, const MT_Point3& _frompoint, const MT_Point3& topoint, KX_RayCast& callback) +bool KX_RayCast::RayTest(PHY_IPhysicsEnvironment *physics_environment, const mt::vec3& _frompoint, const mt::vec3& topoint, KX_RayCast& callback) { - if (physics_environment==NULL) return false; /* prevents crashing in some cases */ + if (physics_environment == nullptr) { + return false; /* prevents crashing in some cases */ + } // Loops over all physics objects between frompoint and topoint, // calling callback.RayHit for each one. // @@ -69,52 +67,56 @@ bool KX_RayCast::RayTest(PHY_IPhysicsEnvironment* physics_environment, const MT_ // // returns true if an object was found, false if not. - MT_Point3 frompoint(_frompoint); - const MT_Vector3 todir( (topoint - frompoint).safe_normalized() ); - MT_Point3 prevpoint(_frompoint+todir*(-1.f)); + mt::vec3 frompoint(_frompoint); + const mt::vec3 todir((topoint - frompoint).SafeNormalized(mt::axisX3)); + mt::vec3 prevpoint(_frompoint + todir * (-1.f)); - PHY_IPhysicsController* hit_controller; + PHY_IPhysicsController *hit_controller; while ((hit_controller = physics_environment->RayTest(callback, - frompoint.x(),frompoint.y(),frompoint.z(), - topoint.x(),topoint.y(),topoint.z())) != NULL) + frompoint.x, frompoint.y, frompoint.z, + topoint.x, topoint.y, topoint.z)) != nullptr) { - KX_ClientObjectInfo *info = static_cast(hit_controller->GetNewClientInfo()); + KX_ClientObjectInfo *info = static_cast(hit_controller->GetNewClientInfo()); - if (!info) - { - printf("no info!\n"); - MT_assert(info && "Physics controller with no client object info"); + if (!info) { + CM_Error("no info!"); + BLI_assert(info && "Physics controller with no client object info"); break; } // The biggest danger to endless loop, prevent this by checking that the // hit point always progresses along the ray direction.. prevpoint -= callback.m_hitPoint; - if (prevpoint.length2() < MT_EPSILON) + if (mt::FuzzyZero(prevpoint.LengthSquared())) { break; + } - if (callback.RayHit(info)) + if (callback.RayHit(info)) { // caller may decide to stop the loop and still cancel the hit return callback.m_hitFound; + } // Skip past the object and keep tracing. // Note that retrieving in a single shot multiple hit points would be possible // but it would require some change in Bullet. prevpoint = callback.m_hitPoint; /* We add 0.001 of fudge, so that if the margin && radius == 0.0, we don't endless loop. */ - MT_Scalar marg = 0.001f + hit_controller->GetMargin(); + float marg = 0.001f + hit_controller->GetMargin(); marg *= 2.f; /* Calculate the other side of this object */ - MT_Scalar h = MT_abs(todir.dot(callback.m_hitNormal)); - if (h <= 0.01f) + float h = std::abs(mt::dot(todir, callback.m_hitNormal)); + if (h <= 0.01f) { // the normal is almost orthogonal to the ray direction, cannot compute the other side break; + } marg /= h; frompoint = callback.m_hitPoint + marg * todir; // verify that we are not passed the to point - if ((topoint - frompoint).dot(todir) < 0.f) + if (mt::dot((topoint - frompoint), todir) < 0.f) { break; + } } return false; } + diff --git a/source/gameengine/Ketsji/KX_RayCast.h b/source/gameengine/Ketsji/KX_RayCast.h index 32531735de36..5aae4c14c492 100644 --- a/source/gameengine/Ketsji/KX_RayCast.h +++ b/source/gameengine/Ketsji/KX_RayCast.h @@ -32,13 +32,13 @@ #ifndef __KX_RAYCAST_H__ #define __KX_RAYCAST_H__ +#include "BLI_utildefines.h" + #include "PHY_IPhysicsEnvironment.h" #include "PHY_IPhysicsController.h" -#include "MT_Vector2.h" -#include "MT_Point3.h" -#include "MT_Vector3.h" +#include "mathfu.h" -class RAS_MeshObject; +class RAS_Mesh; struct KX_ClientObjectInfo; /** @@ -60,12 +60,12 @@ class KX_RayCast : public PHY_IRayCastFilterCallback { public: bool m_hitFound; - MT_Point3 m_hitPoint; - MT_Vector3 m_hitNormal; - const RAS_MeshObject* m_hitMesh; + mt::vec3 m_hitPoint; + mt::vec3 m_hitNormal; + RAS_Mesh *m_hitMesh; int m_hitPolygon; int m_hitUVOK; // !=0 if UV coordinate in m_hitUV is valid - MT_Vector2 m_hitUV; + mt::vec2 m_hitUV; KX_RayCast(PHY_IPhysicsController* ignoreController, bool faceNormal, bool faceUV); virtual ~KX_RayCast() {} @@ -80,26 +80,21 @@ class KX_RayCast : public PHY_IRayCastFilterCallback */ virtual bool RayHit(KX_ClientObjectInfo* client) = 0; - /** + /** * Callback wrapper. * * Construct with KX_RayCast::Callback(this, data) * and pass to KX_RayCast::RayTest */ template class Callback; - + /// Public interface. /// Implement bool RayHit in your class to receive ray callbacks. static bool RayTest( - PHY_IPhysicsEnvironment* physics_environment, - const MT_Point3& frompoint, - const MT_Point3& topoint, + PHY_IPhysicsEnvironment* physics_environment, + const mt::vec3& frompoint, + const mt::vec3& topoint, KX_RayCast& callback); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_RayCast") -#endif }; template @@ -113,13 +108,13 @@ class KX_RayCast::Callback : public KX_RayCast */ dataT *data; public: - Callback(T *_self, PHY_IPhysicsController *controller = NULL, dataT *_data = NULL, bool faceNormal = false, bool faceUV = false) + Callback(T *_self, PHY_IPhysicsController *controller = nullptr, dataT *_data = nullptr, bool faceNormal = false, bool faceUV = false) : KX_RayCast(controller, faceNormal, faceUV), self(_self), data(_data) { } - + ~Callback() {} virtual bool RayHit(KX_ClientObjectInfo* client) @@ -130,20 +125,15 @@ class KX_RayCast::Callback : public KX_RayCast virtual bool needBroadphaseRayCast(PHY_IPhysicsController* controller) { KX_ClientObjectInfo* info = static_cast(controller->GetNewClientInfo()); - + if (!info) { - MT_assert(info && "Physics controller with no client object info"); + BLI_assert(info && "Physics controller with no client object info"); return false; } return self->NeedRayCast(info, data); } - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_RayCast::Callback") -#endif }; - + #endif diff --git a/source/gameengine/Ketsji/KX_RaySensor.cpp b/source/gameengine/Ketsji/KX_RaySensor.cpp index 5e22bc9661f8..52473bb6f16a 100644 --- a/source/gameengine/Ketsji/KX_RaySensor.cpp +++ b/source/gameengine/Ketsji/KX_RaySensor.cpp @@ -35,7 +35,6 @@ #include "KX_RaySensor.h" #include "SCA_EventManager.h" -#include "SCA_RandomEventManager.h" #include "SCA_LogicManager.h" #include "SCA_IObject.h" #include "KX_ClientObjectInfo.h" @@ -43,39 +42,40 @@ #include "KX_Scene.h" #include "KX_RayCast.h" #include "KX_PyMath.h" +#include "KX_Mesh.h" #include "PHY_IPhysicsEnvironment.h" #include "PHY_IPhysicsController.h" #include "DNA_sensor_types.h" -#include "RAS_MeshObject.h" - -#include - - -KX_RaySensor::KX_RaySensor(class SCA_EventManager* eventmgr, - SCA_IObject* gameobj, - const STR_String& propname, - bool bFindMaterial, - bool bXRay, - double distance, - int axis, - KX_Scene* ketsjiScene) - : SCA_ISensor(gameobj,eventmgr), - m_propertyname(propname), - m_bFindMaterial(bFindMaterial), - m_bXRay(bXRay), - m_distance(distance), - m_scene(ketsjiScene), - m_axis(axis), - m_hitMaterial("") + +#include "CM_Message.h" + +KX_RaySensor::KX_RaySensor(class SCA_EventManager *eventmgr, + SCA_IObject *gameobj, + const std::string& propname, + bool bFindMaterial, + bool bXRay, + double distance, + int axis, + int mask, + KX_Scene *ketsjiScene) + :SCA_ISensor(gameobj, eventmgr), + m_propertyname(propname), + m_bFindMaterial(bFindMaterial), + m_bXRay(bXRay), + m_distance(distance), + m_scene(ketsjiScene), + m_axis(axis), + m_mask(mask), + m_hitMaterial("") { Init(); } void KX_RaySensor::Init() { - m_bTriggered = (m_invert)?true:false; + m_bTriggered = (m_invert) ? true : false; m_rayHit = false; - m_hitObject = NULL; + m_hitObject = nullptr; m_reset = true; } @@ -86,9 +86,9 @@ KX_RaySensor::~KX_RaySensor() -CValue* KX_RaySensor::GetReplica() +EXP_Value *KX_RaySensor::GetReplica() { - KX_RaySensor* replica = new KX_RaySensor(*this); + KX_RaySensor *replica = new KX_RaySensor(*this); replica->ProcessReplica(); replica->Init(); @@ -101,8 +101,9 @@ bool KX_RaySensor::IsPositiveTrigger() { bool result = m_rayHit; - if (m_invert) + if (m_invert) { result = !result; + } return result; } @@ -110,45 +111,33 @@ bool KX_RaySensor::IsPositiveTrigger() bool KX_RaySensor::RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, void *UNUSED(data)) { - KX_GameObject* hitKXObj = client->m_gameobject; + KX_GameObject *hitKXObj = client->m_gameobject; bool bFound = false; bool hitMaterial = false; - if (m_propertyname.Length() == 0) - { + if (m_propertyname.empty()) { bFound = true; } - else - { + else { if (m_bFindMaterial) { - for (unsigned int i = 0; i < hitKXObj->GetMeshCount(); ++i) { - RAS_MeshObject *meshObj = hitKXObj->GetMesh(i); - for (unsigned int j = 0; j < meshObj->NumMaterials(); ++j) { - bFound = strcmp(m_propertyname.ReadPtr(), meshObj->GetMaterialName(j).ReadPtr() + 2) == 0; - if (bFound) { - hitMaterial = true; - break; - } + for (RAS_Mesh *meshObj : hitKXObj->GetMeshList()) { + bFound = (meshObj->FindMaterialName(m_propertyname) != nullptr); + if (bFound) { + hitMaterial = true; + break; } } } else { - bFound = hitKXObj->GetProperty(m_propertyname) != NULL; + bFound = hitKXObj->GetProperty(m_propertyname) != nullptr; } } - if (bFound) - { + if (bFound) { m_rayHit = true; m_hitObject = hitKXObj; - m_hitPosition[0] = result->m_hitPoint[0]; - m_hitPosition[1] = result->m_hitPoint[1]; - m_hitPosition[2] = result->m_hitPoint[2]; - - m_hitNormal[0] = result->m_hitNormal[0]; - m_hitNormal[1] = result->m_hitNormal[1]; - m_hitNormal[2] = result->m_hitNormal[2]; - + m_hitPosition = result->m_hitPoint; + m_hitNormal = result->m_hitNormal; m_hitMaterial = hitMaterial; } // no multi-hit search yet @@ -162,31 +151,35 @@ bool KX_RaySensor::NeedRayCast(KX_ClientObjectInfo *client, void *UNUSED(data)) { KX_GameObject *hitKXObj = client->m_gameobject; - if (client->m_type > KX_ClientObjectInfo::ACTOR) - { + if (client->m_type > KX_ClientObjectInfo::ACTOR) { // Unknown type of object, skip it. // Should not occur as the sensor objects are filtered in RayTest() - printf("Invalid client type %d found ray casting\n", client->m_type); + CM_Error("invalid client type " << client->m_type << " found ray casting"); + return false; + } + + // The current object is not in the proper layer. + if (!(hitKXObj->GetCollisionGroup() & m_mask)) { return false; } - if (m_bXRay && m_propertyname.Length() != 0) - { + + if (m_bXRay && m_propertyname.size() != 0) { if (m_bFindMaterial) { bool found = false; - for (unsigned int i = 0; i < hitKXObj->GetMeshCount(); ++i) { - RAS_MeshObject *meshObj = hitKXObj->GetMesh(i); - for (unsigned int j = 0; j < meshObj->NumMaterials(); ++j) { - found = strcmp(m_propertyname.ReadPtr(), meshObj->GetMaterialName(j).ReadPtr() + 2) == 0; - if (found) - break; + for (KX_Mesh *meshObj : hitKXObj->GetMeshList()) { + found = (meshObj->FindMaterialName(m_propertyname) != nullptr); + if (found) { + break; } } - if (!found) + if (!found) { return false; + } } else { - if (hitKXObj->GetProperty(m_propertyname) == NULL) + if (hitKXObj->GetProperty(m_propertyname) == nullptr) { return false; + } } } return true; @@ -197,89 +190,67 @@ bool KX_RaySensor::Evaluate() bool result = false; bool reset = m_reset && m_level; m_rayHit = false; - m_hitObject = NULL; - m_hitPosition[0] = 0; - m_hitPosition[1] = 0; - m_hitPosition[2] = 0; - - m_hitNormal[0] = 1; - m_hitNormal[1] = 0; - m_hitNormal[2] = 0; + m_hitObject = nullptr; + m_hitPosition = mt::zero3; + m_hitNormal = mt::axisX3; - KX_GameObject* obj = (KX_GameObject*)GetParent(); - MT_Point3 frompoint = obj->NodeGetWorldPosition(); - MT_Matrix3x3 matje = obj->NodeGetWorldOrientation(); - MT_Matrix3x3 invmat = matje.inverse(); + KX_GameObject *obj = (KX_GameObject *)GetParent(); + mt::vec3 frompoint = obj->NodeGetWorldPosition(); + mt::mat3 mat = obj->NodeGetWorldOrientation(); - MT_Vector3 todir; + mt::vec3 todir; m_reset = false; - switch (m_axis) - { - case SENS_RAY_X_AXIS: // X + switch (m_axis) { + case SENS_RAY_X_AXIS: // X { - todir[0] = invmat[0][0]; - todir[1] = invmat[0][1]; - todir[2] = invmat[0][2]; + todir = mat.GetColumn(0); break; } - case SENS_RAY_Y_AXIS: // Y + case SENS_RAY_Y_AXIS: // Y { - todir[0] = invmat[1][0]; - todir[1] = invmat[1][1]; - todir[2] = invmat[1][2]; + todir = mat.GetColumn(1); break; } - case SENS_RAY_Z_AXIS: // Z + case SENS_RAY_Z_AXIS: // Z { - todir[0] = invmat[2][0]; - todir[1] = invmat[2][1]; - todir[2] = invmat[2][2]; + todir = mat.GetColumn(2); break; } - case SENS_RAY_NEG_X_AXIS: // -X + case SENS_RAY_NEG_X_AXIS: // -X { - todir[0] = -invmat[0][0]; - todir[1] = -invmat[0][1]; - todir[2] = -invmat[0][2]; + todir = -mat.GetColumn(0); break; } - case SENS_RAY_NEG_Y_AXIS: // -Y + case SENS_RAY_NEG_Y_AXIS: // -Y { - todir[0] = -invmat[1][0]; - todir[1] = -invmat[1][1]; - todir[2] = -invmat[1][2]; + todir = -mat.GetColumn(1); break; } - case SENS_RAY_NEG_Z_AXIS: // -Z + case SENS_RAY_NEG_Z_AXIS: // -Z { - todir[0] = -invmat[2][0]; - todir[1] = -invmat[2][1]; - todir[2] = -invmat[2][2]; + todir = -mat.GetColumn(2); break; } } - todir.normalize(); - m_rayDirection[0] = todir[0]; - m_rayDirection[1] = todir[1]; - m_rayDirection[2] = todir[2]; - - MT_Point3 topoint = frompoint + (m_distance) * todir; - PHY_IPhysicsEnvironment* pe = m_scene->GetPhysicsEnvironment(); - - if (!pe) - { - std::cout << "WARNING: Ray sensor " << GetName() << ": There is no physics environment!" << std::endl; - std::cout << " Check universe for malfunction." << std::endl; + todir.Normalize(); + m_rayDirection = todir; + + mt::vec3 topoint = frompoint + (m_distance) * todir; + PHY_IPhysicsEnvironment *pe = m_scene->GetPhysicsEnvironment(); + + if (!pe) { + CM_LogicBrickWarning(this, "there is no physics environment! Check universe for malfunction."); return false; } PHY_IPhysicsController *spc = obj->GetPhysicsController(); KX_GameObject *parent = obj->GetParent(); - if (!spc && parent) + if (!spc && parent) { spc = parent->GetPhysicsController(); + } - PHY_IPhysicsEnvironment* physics_environment = this->m_scene->GetPhysicsEnvironment(); + PHY_IPhysicsEnvironment *physics_environment = this->m_scene->GetPhysicsEnvironment(); KX_RayCast::Callback callback(this, spc); @@ -287,38 +258,33 @@ bool KX_RaySensor::Evaluate() /* now pass this result to some controller */ - if (m_rayHit) - { - if (!m_bTriggered) - { + if (m_rayHit) { + if (!m_bTriggered) { // notify logicsystem that ray is now hitting result = true; m_bTriggered = true; } - else - { + else { // notify logicsystem that ray is STILL hitting ... result = false; } } - else - { - if (m_bTriggered) - { + else { + if (m_bTriggered) { m_bTriggered = false; // notify logicsystem that ray JUST left the Object result = true; } - else - { + else { result = false; } } - if (reset) + if (reset) { // force an event result = true; + } return result; } @@ -331,9 +297,9 @@ bool KX_RaySensor::Evaluate() /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_RaySensor::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_RaySensor", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -341,41 +307,43 @@ PyTypeObject KX_RaySensor::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_ISensor::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_RaySensor::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_RaySensor::Attributes[] = { - KX_PYATTRIBUTE_BOOL_RW("useMaterial", KX_RaySensor, m_bFindMaterial), - KX_PYATTRIBUTE_BOOL_RW("useXRay", KX_RaySensor, m_bXRay), - KX_PYATTRIBUTE_FLOAT_RW("range", 0, 10000, KX_RaySensor, m_distance), - KX_PYATTRIBUTE_STRING_RW("propName", 0, MAX_PROP_NAME, false, KX_RaySensor, m_propertyname), - KX_PYATTRIBUTE_INT_RW("axis", 0, 5, true, KX_RaySensor, m_axis), - KX_PYATTRIBUTE_FLOAT_ARRAY_RO("hitPosition", KX_RaySensor, m_hitPosition, 3), - KX_PYATTRIBUTE_FLOAT_ARRAY_RO("rayDirection", KX_RaySensor, m_rayDirection, 3), - KX_PYATTRIBUTE_FLOAT_ARRAY_RO("hitNormal", KX_RaySensor, m_hitNormal, 3), - KX_PYATTRIBUTE_STRING_RO("hitMaterial", KX_RaySensor, m_hitMaterial), - KX_PYATTRIBUTE_RO_FUNCTION("hitObject", KX_RaySensor, pyattr_get_hitobject), - { NULL } //Sentinel + EXP_PYATTRIBUTE_BOOL_RW("useMaterial", KX_RaySensor, m_bFindMaterial), + EXP_PYATTRIBUTE_BOOL_RW("useXRay", KX_RaySensor, m_bXRay), + EXP_PYATTRIBUTE_FLOAT_RW("range", 0, 10000, KX_RaySensor, m_distance), + EXP_PYATTRIBUTE_STRING_RW("propName", 0, MAX_PROP_NAME, false, KX_RaySensor, m_propertyname), + EXP_PYATTRIBUTE_INT_RW("axis", 0, 5, true, KX_RaySensor, m_axis), + EXP_PYATTRIBUTE_INT_RW("mask", 1, (1 << OB_MAX_COL_MASKS) - 1, true, KX_RaySensor, m_mask), + EXP_PYATTRIBUTE_VECTOR_RO("hitPosition", KX_RaySensor, m_hitPosition, 3), + EXP_PYATTRIBUTE_VECTOR_RO("rayDirection", KX_RaySensor, m_rayDirection, 3), + EXP_PYATTRIBUTE_VECTOR_RO("hitNormal", KX_RaySensor, m_hitNormal, 3), + EXP_PYATTRIBUTE_STRING_RO("hitMaterial", KX_RaySensor, m_hitMaterial), + EXP_PYATTRIBUTE_RO_FUNCTION("hitObject", KX_RaySensor, pyattr_get_hitobject), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *KX_RaySensor::pyattr_get_hitobject(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_RaySensor::pyattr_get_hitobject(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_RaySensor* self = static_cast(self_v); - if (self->m_hitObject) + KX_RaySensor *self = static_cast(self_v); + if (self->m_hitObject) { return self->m_hitObject->GetProxy(); + } Py_RETURN_NONE; } diff --git a/source/gameengine/Ketsji/KX_RaySensor.h b/source/gameengine/Ketsji/KX_RaySensor.h index e84f29f38acd..e03d42b8aa54 100644 --- a/source/gameengine/Ketsji/KX_RaySensor.h +++ b/source/gameengine/Ketsji/KX_RaySensor.h @@ -34,7 +34,6 @@ #define __KX_RAYSENSOR_H__ #include "SCA_ISensor.h" -#include "MT_Point3.h" #include "SCA_IScene.h" /* only for scene replace */ #include "KX_Scene.h" /* only for scene replace */ @@ -46,31 +45,33 @@ class KX_RayCast; class KX_RaySensor : public SCA_ISensor { Py_Header - STR_String m_propertyname; + std::string m_propertyname; bool m_bFindMaterial; bool m_bXRay; float m_distance; class KX_Scene* m_scene; bool m_bTriggered; int m_axis; + int m_mask; bool m_rayHit; - float m_hitPosition[3]; + mt::vec3 m_hitPosition; SCA_IObject* m_hitObject; - float m_hitNormal[3]; - float m_rayDirection[3]; - STR_String m_hitMaterial; + mt::vec3 m_hitNormal; + mt::vec3 m_rayDirection; + std::string m_hitMaterial; public: KX_RaySensor(class SCA_EventManager* eventmgr, SCA_IObject* gameobj, - const STR_String& propname, + const std::string& propname, bool bFindMaterial, bool bXRay, double distance, int axis, + int mask, class KX_Scene* ketsjiScene); virtual ~KX_RaySensor(); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); virtual bool Evaluate(); virtual bool IsPositiveTrigger(); @@ -81,9 +82,9 @@ class KX_RaySensor : public SCA_ISensor /// \see KX_RayCast bool NeedRayCast(KX_ClientObjectInfo *client, void *UNUSED(data)); - virtual void Replace_IScene(SCA_IScene *val) - { - m_scene= static_cast(val); + virtual void Replace_IScene(SCA_IScene *val) + { + m_scene= static_cast(val); } //Python Interface @@ -96,12 +97,12 @@ class KX_RaySensor : public SCA_ISensor KX_RAY_AXIS_NEG_Y = 4, KX_RAY_AXIS_NEG_Z = 5, }; - + #ifdef WITH_PYTHON /* Attributes */ - static PyObject *pyattr_get_hitobject(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - + static PyObject *pyattr_get_hitobject(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + #endif /* WITH_PYTHON */ }; diff --git a/source/gameengine/Ketsji/KX_RenderData.cpp b/source/gameengine/Ketsji/KX_RenderData.cpp new file mode 100644 index 000000000000..abd1408f590e --- /dev/null +++ b/source/gameengine/Ketsji/KX_RenderData.cpp @@ -0,0 +1,48 @@ +#include "KX_RenderData.h" +#include "KX_Camera.h" + +KX_CameraRenderData::KX_CameraRenderData(KX_Camera *rendercam, KX_Camera *cullingcam, const RAS_Rect& area, + const RAS_Rect& viewport, RAS_Rasterizer::StereoMode stereoMode, RAS_Rasterizer::StereoEye eye, unsigned short index) + :m_renderCamera(rendercam), + m_cullingCamera(cullingcam), + m_area(area), + m_viewport(viewport), + m_stereoMode(stereoMode), + m_eye(eye), + m_index(index) +{ + m_renderCamera->AddRef(); +} + +KX_CameraRenderData::KX_CameraRenderData(const KX_CameraRenderData& other) + :m_renderCamera(CM_AddRef(other.m_renderCamera)), + m_cullingCamera(other.m_cullingCamera), + m_area(other.m_area), + m_viewport(other.m_viewport), + m_stereoMode(other.m_stereoMode), + m_eye(other.m_eye), + m_index(other.m_index) +{ +} + +KX_CameraRenderData::~KX_CameraRenderData() +{ + m_renderCamera->Release(); +} + +KX_SceneRenderData::KX_SceneRenderData(KX_Scene *scene) + :m_scene(scene) +{ +} + +KX_FrameRenderData::KX_FrameRenderData(RAS_Rasterizer::OffScreenType ofsType, const std::vector& eyes) + :m_ofsType(ofsType), + m_eyes(eyes) +{ +} + +KX_RenderData::KX_RenderData(RAS_Rasterizer::StereoMode stereoMode, bool renderPerEye) + :m_stereoMode(stereoMode), + m_renderPerEye(renderPerEye) +{ +} diff --git a/source/gameengine/Ketsji/KX_RenderData.h b/source/gameengine/Ketsji/KX_RenderData.h new file mode 100644 index 000000000000..be3708551a6a --- /dev/null +++ b/source/gameengine/Ketsji/KX_RenderData.h @@ -0,0 +1,60 @@ +#ifndef __KX_RENDER_DATA_H__ +#define __KX_RENDER_DATA_H__ + +#include "RAS_Rasterizer.h" + +class KX_Scene; +class KX_Camera; + +/** \brief This file contains all the data describing the rendering proceeded in a frame. + * KX_RenderData is the main data which for each eye (in case of stereo) contains a frame + * and each of these frame contains the scenes data and cameras data. + */ + +struct KX_CameraRenderData +{ + KX_CameraRenderData(KX_Camera *rendercam, KX_Camera *cullingcam, const RAS_Rect& area, const RAS_Rect& viewport, + RAS_Rasterizer::StereoMode stereoMode, RAS_Rasterizer::StereoEye eye, unsigned short index); + KX_CameraRenderData(const KX_CameraRenderData& other); + ~KX_CameraRenderData(); + + /// Rendered camera, could be a temporary camera in case of stereo. + KX_Camera *m_renderCamera; + KX_Camera *m_cullingCamera; + RAS_Rect m_area; + RAS_Rect m_viewport; + RAS_Rasterizer::StereoMode m_stereoMode; + RAS_Rasterizer::StereoEye m_eye; + // Index of the camera in all the scene's cameras rendered. + unsigned short m_index; +}; + +struct KX_SceneRenderData +{ + KX_SceneRenderData(KX_Scene *scene); + + KX_Scene *m_scene; + // Use multiple list of cameras in case of per eye stereo. + std::vector m_cameraDataList[RAS_Rasterizer::RAS_STEREO_MAXEYE]; +}; + +/// Data used to render a frame. +struct KX_FrameRenderData +{ + KX_FrameRenderData(RAS_Rasterizer::OffScreenType ofsType, const std::vector& eyes); + + RAS_Rasterizer::OffScreenType m_ofsType; + std::vector m_eyes; +}; + +struct KX_RenderData +{ + KX_RenderData(RAS_Rasterizer::StereoMode stereoMode, bool renderPerEye); + + RAS_Rasterizer::StereoMode m_stereoMode; + bool m_renderPerEye; + std::vector m_sceneDataList; + std::vector m_frameDataList; +}; + +#endif // __KX_RENDER_DATA_H__ diff --git a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp b/source/gameengine/Ketsji/KX_ReplaceMeshActuator.cpp similarity index 52% rename from source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp rename to source/gameengine/Ketsji/KX_ReplaceMeshActuator.cpp index 2a071c221e4f..db5ae5f2bfe0 100644 --- a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp +++ b/source/gameengine/Ketsji/KX_ReplaceMeshActuator.cpp @@ -25,7 +25,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.cpp +/** \file gameengine/Ketsji/KX_ReplaceMeshActuator.cpp * \ingroup ketsji * * Replace the mesh for this actuator's parent @@ -38,12 +38,10 @@ // Please look here for revision history. -#include - -#include "KX_SCA_ReplaceMeshActuator.h" -#include "KX_MeshProxy.h" - -#include "EXP_PyObjectPlus.h" +#include "KX_ReplaceMeshActuator.h" +#include "KX_Scene.h" +#include "KX_GameObject.h" +#include "KX_Mesh.h" #ifdef WITH_PYTHON @@ -53,10 +51,10 @@ /* Integration hooks ------------------------------------------------------- */ -PyTypeObject KX_SCA_ReplaceMeshActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "KX_SCA_ReplaceMeshActuator", - sizeof(PyObjectPlus_Proxy), +PyTypeObject KX_ReplaceMeshActuator::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_ReplaceMeshActuator", + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -64,52 +62,53 @@ PyTypeObject KX_SCA_ReplaceMeshActuator::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IActuator::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; -PyMethodDef KX_SCA_ReplaceMeshActuator::Methods[] = { - KX_PYMETHODTABLE(KX_SCA_ReplaceMeshActuator, instantReplaceMesh), - {NULL,NULL} //Sentinel +PyMethodDef KX_ReplaceMeshActuator::Methods[] = { + EXP_PYMETHODTABLE(KX_ReplaceMeshActuator, instantReplaceMesh), + {nullptr, nullptr} //Sentinel }; -PyAttributeDef KX_SCA_ReplaceMeshActuator::Attributes[] = { - KX_PYATTRIBUTE_RW_FUNCTION("mesh", KX_SCA_ReplaceMeshActuator, pyattr_get_mesh, pyattr_set_mesh), - KX_PYATTRIBUTE_BOOL_RW ("useDisplayMesh", KX_SCA_ReplaceMeshActuator, m_use_gfx), - KX_PYATTRIBUTE_BOOL_RW ("usePhysicsMesh", KX_SCA_ReplaceMeshActuator, m_use_phys), - { NULL } //Sentinel +PyAttributeDef KX_ReplaceMeshActuator::Attributes[] = { + EXP_PYATTRIBUTE_RW_FUNCTION("mesh", KX_ReplaceMeshActuator, pyattr_get_mesh, pyattr_set_mesh), + EXP_PYATTRIBUTE_BOOL_RW("useDisplayMesh", KX_ReplaceMeshActuator, m_use_gfx), + EXP_PYATTRIBUTE_BOOL_RW("usePhysicsMesh", KX_ReplaceMeshActuator, m_use_phys), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *KX_SCA_ReplaceMeshActuator::pyattr_get_mesh(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_ReplaceMeshActuator::pyattr_get_mesh(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - KX_SCA_ReplaceMeshActuator* actuator = static_cast(self); - if (!actuator->m_mesh) + KX_ReplaceMeshActuator *actuator = static_cast(self); + if (!actuator->m_mesh) { Py_RETURN_NONE; - KX_MeshProxy* meshproxy = new KX_MeshProxy(actuator->m_mesh); - return meshproxy->NewProxy(true); + } + return actuator->m_mesh->GetProxy(); } -int KX_SCA_ReplaceMeshActuator::pyattr_set_mesh(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_ReplaceMeshActuator::pyattr_set_mesh(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_SCA_ReplaceMeshActuator* actuator = static_cast(self); - RAS_MeshObject* new_mesh; + KX_ReplaceMeshActuator *actuator = static_cast(self); + KX_Mesh *new_mesh; - if (!ConvertPythonToMesh(actuator->GetLogicManager(), value, &new_mesh, true, "actuator.mesh = value: KX_SCA_ReplaceMeshActuator")) + if (!ConvertPythonToMesh(actuator->GetLogicManager(), value, &new_mesh, true, "actuator.mesh = value: KX_ReplaceMeshActuator")) { return PY_SET_ATTR_FAIL; + } actuator->m_mesh = new_mesh; return PY_SET_ATTR_SUCCESS; } -KX_PYMETHODDEF_DOC(KX_SCA_ReplaceMeshActuator, instantReplaceMesh, -"instantReplaceMesh() : immediately replace mesh without delay\n") +EXP_PYMETHODDEF_DOC(KX_ReplaceMeshActuator, instantReplaceMesh, + "instantReplaceMesh() : immediately replace mesh without delay\n") { InstantReplaceMesh(); Py_RETURN_NONE; @@ -121,15 +120,13 @@ KX_PYMETHODDEF_DOC(KX_SCA_ReplaceMeshActuator, instantReplaceMesh, /* Native functions */ /* ------------------------------------------------------------------------- */ -KX_SCA_ReplaceMeshActuator::KX_SCA_ReplaceMeshActuator(SCA_IObject *gameobj, - class RAS_MeshObject *mesh, - SCA_IScene* scene, - bool use_gfx, - bool use_phys) : +KX_ReplaceMeshActuator::KX_ReplaceMeshActuator(KX_GameObject *gameobj, + KX_Mesh *mesh, + bool use_gfx, + bool use_phys) : SCA_IActuator(gameobj, KX_ACT_REPLACE_MESH), m_mesh(mesh), - m_scene(scene), m_use_gfx(use_gfx), m_use_phys(use_phys) { @@ -137,46 +134,48 @@ KX_SCA_ReplaceMeshActuator::KX_SCA_ReplaceMeshActuator(SCA_IObject *gameobj, -KX_SCA_ReplaceMeshActuator::~KX_SCA_ReplaceMeshActuator() +KX_ReplaceMeshActuator::~KX_ReplaceMeshActuator() { // there's nothing to be done here, really.... } /* end of destructor */ -bool KX_SCA_ReplaceMeshActuator::Update() +bool KX_ReplaceMeshActuator::Update() { // bool result = false; /*unused*/ bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); - if (bNegativeEvent) + if (bNegativeEvent) { return false; // do nothing on negative events - if (m_mesh || m_use_phys) /* NULL mesh is ok if were updating physics */ - m_scene->ReplaceMesh(GetParent(),m_mesh, m_use_gfx, m_use_phys); + } + InstantReplaceMesh(); return false; } -CValue* KX_SCA_ReplaceMeshActuator::GetReplica() +EXP_Value *KX_ReplaceMeshActuator::GetReplica() { - KX_SCA_ReplaceMeshActuator* replica = - new KX_SCA_ReplaceMeshActuator(*this); + KX_ReplaceMeshActuator *replica = + new KX_ReplaceMeshActuator(*this); - if (replica == NULL) - return NULL; + if (replica == nullptr) { + return nullptr; + } replica->ProcessReplica(); return replica; }; -void KX_SCA_ReplaceMeshActuator::InstantReplaceMesh() +void KX_ReplaceMeshActuator::InstantReplaceMesh() { - if (m_mesh) m_scene->ReplaceMesh(GetParent(),m_mesh, m_use_gfx, m_use_phys); + if (m_mesh || m_use_phys) { + KX_GameObject *gameobj = static_cast(GetParent()); + gameobj->ReplaceMesh(m_mesh, m_use_gfx, m_use_phys); + } } - -/* eof */ diff --git a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h b/source/gameengine/Ketsji/KX_ReplaceMeshActuator.h similarity index 68% rename from source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h rename to source/gameengine/Ketsji/KX_ReplaceMeshActuator.h index 52884d692c66..57d5c01884a8 100644 --- a/source/gameengine/Ketsji/KX_SCA_ReplaceMeshActuator.h +++ b/source/gameengine/Ketsji/KX_ReplaceMeshActuator.h @@ -25,50 +25,48 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file KX_SCA_ReplaceMeshActuator.h +/** \file KX_ReplaceMeshActuator.h * \ingroup ketsji * \brief Add object to the game world on action of this actuator * \attention Previously existed as: source/gameengine/GameLogic/SCA_ReplaceMeshActuator.h * Please look here for revision history. */ -#ifndef __KX_SCA_REPLACEMESHACTUATOR_H__ -#define __KX_SCA_REPLACEMESHACTUATOR_H__ +#ifndef __KX_REPLACEMESHACTUATOR_H__ +#define __KX_REPLACEMESHACTUATOR_H__ #include "SCA_IActuator.h" #include "SCA_PropertyActuator.h" #include "SCA_LogicManager.h" -#include "SCA_IScene.h" -#include "RAS_MeshObject.h" +class KX_Mesh; +class KX_GameObject; -class KX_SCA_ReplaceMeshActuator : public SCA_IActuator +class KX_ReplaceMeshActuator : public SCA_IActuator { Py_Header // mesh reference (mesh to replace) - RAS_MeshObject* m_mesh; - SCA_IScene* m_scene; - bool m_use_gfx; + KX_Mesh *m_mesh; + bool m_use_gfx; bool m_use_phys; public: - KX_SCA_ReplaceMeshActuator( - SCA_IObject* gameobj, - RAS_MeshObject *mesh, - SCA_IScene* scene, + KX_ReplaceMeshActuator( + KX_GameObject *gameobj, + KX_Mesh *mesh, bool use_gfx, bool use_phys ); - ~KX_SCA_ReplaceMeshActuator( + ~KX_ReplaceMeshActuator( ); - CValue* + EXP_Value* GetReplica( ); - virtual bool + virtual bool Update(); void InstantReplaceMesh(); @@ -79,18 +77,13 @@ class KX_SCA_ReplaceMeshActuator : public SCA_IActuator /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - virtual void Replace_IScene(SCA_IScene *val) - { - m_scene= val; - }; + static PyObject *pyattr_get_mesh(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_mesh(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject *pyattr_get_mesh(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_mesh(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - - KX_PYMETHOD_DOC(KX_SCA_ReplaceMeshActuator,instantReplaceMesh); + EXP_PYMETHOD_DOC(KX_ReplaceMeshActuator,instantReplaceMesh); #endif /* WITH_PYTHON */ -}; +}; -#endif /* __KX_SCA_REPLACEMESHACTUATOR_H__ */ +#endif /* __KX_REPLACEMESHACTUATOR_H__ */ diff --git a/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp b/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp deleted file mode 100644 index 038de1ead105..000000000000 --- a/source/gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Ketsji/KX_SG_BoneParentNodeRelationship.cpp - * \ingroup ketsji - */ - - -#include - -#include "KX_SG_BoneParentNodeRelationship.h" - -#include "MT_Matrix4x4.h" -#include "BL_ArmatureObject.h" - - -/** - * Implementation of classes defined in KX_SG_BoneParentNodeRelationship.h - */ - -/** - * first of all KX_SG_BoneParentRelation - */ - - KX_BoneParentRelation * -KX_BoneParentRelation:: -New(Bone* bone -) { - return new KX_BoneParentRelation(bone); -} - - bool -KX_BoneParentRelation:: -UpdateChildCoordinates( - SG_Spatial * child, - const SG_Spatial * parent, - bool& parentUpdated -) { - MT_assert(child != NULL); - - // This way of accessing child coordinates is a bit cumbersome - // be nice to have non constant reference access to these values. - - const MT_Vector3 & child_scale = child->GetLocalScale(); - const MT_Point3 & child_pos = child->GetLocalPosition(); - const MT_Matrix3x3 & child_rotation = child->GetLocalOrientation(); - // we don't know if the armature has been updated or not, assume yes - parentUpdated = true; - - // the childs world locations which we will update. - - MT_Vector3 child_w_scale; - MT_Point3 child_w_pos; - MT_Matrix3x3 child_w_rotation; - - bool valid_parent_transform = false; - - if (parent) - { - BL_ArmatureObject *armature = (BL_ArmatureObject*)(parent->GetSGClientObject()); - if (armature) - { - MT_Matrix4x4 parent_matrix; - if (armature->GetBoneMatrix(m_bone, parent_matrix)) - { - // Get the child's transform, and the bone matrix. - MT_Matrix4x4 child_transform ( - MT_Transform(child_pos + MT_Vector3(0.0f, armature->GetBoneLength(m_bone), 0.0f), - child_rotation.scaled( - child_scale[0], - child_scale[1], - child_scale[2]))); - - // The child's world transform is parent * child - parent_matrix = parent->GetWorldTransform() * parent_matrix; - child_transform = parent_matrix * child_transform; - - // Recompute the child transform components from the transform. - child_w_scale.setValue( - MT_Vector3(child_transform[0][0], child_transform[0][1], child_transform[0][2]).length(), - MT_Vector3(child_transform[1][0], child_transform[1][1], child_transform[1][2]).length(), - MT_Vector3(child_transform[2][0], child_transform[2][1], child_transform[2][2]).length()); - child_w_rotation.setValue(child_transform[0][0], child_transform[0][1], child_transform[0][2], - child_transform[1][0], child_transform[1][1], child_transform[1][2], - child_transform[2][0], child_transform[2][1], child_transform[2][2]); - child_w_rotation.scale(1.0f/child_w_scale[0], 1.0f/child_w_scale[1], 1.0f/child_w_scale[2]); - - child_w_pos = MT_Point3(child_transform[0][3], child_transform[1][3], child_transform[2][3]); - - valid_parent_transform = true; - } - } - } - - if (valid_parent_transform) - { - child->SetWorldScale(child_w_scale); - child->SetWorldPosition(child_w_pos); - child->SetWorldOrientation(child_w_rotation); - } - else { - child->SetWorldFromLocalTransform(); - } - child->ClearModified(); - // this node must always be updated, so reschedule it for next time - child->ActivateRecheduleUpdateCallback(); - return valid_parent_transform; -} - - SG_ParentRelation * -KX_BoneParentRelation:: -NewCopy( -) { - KX_BoneParentRelation* bone_parent = new KX_BoneParentRelation(m_bone); - return bone_parent; -} - -KX_BoneParentRelation:: -~KX_BoneParentRelation( -) { - //nothing to do -} - - -KX_BoneParentRelation:: -KX_BoneParentRelation(Bone* bone -) -: m_bone(bone) -{ - // nothing to do -} diff --git a/source/gameengine/Ketsji/KX_SG_NodeRelationships.cpp b/source/gameengine/Ketsji/KX_SG_NodeRelationships.cpp deleted file mode 100644 index c1855f881d09..000000000000 --- a/source/gameengine/Ketsji/KX_SG_NodeRelationships.cpp +++ /dev/null @@ -1,294 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Ketsji/KX_SG_NodeRelationships.cpp - * \ingroup ketsji - */ - - -#include "KX_SG_NodeRelationships.h" - -/** - * Implementation of classes defined in KX_SG_NodeRelationships.h - */ - -/** - * first of all KX_NormalParentRelation - */ - - KX_NormalParentRelation * -KX_NormalParentRelation:: -New( -) { - return new KX_NormalParentRelation(); -} - - bool -KX_NormalParentRelation:: -UpdateChildCoordinates( - SG_Spatial * child, - const SG_Spatial * parent, - bool& parentUpdated -) { - MT_assert(child != NULL); - - if (!parentUpdated && !child->IsModified()) - return false; - - parentUpdated = true; - - if (parent==NULL) { /* Simple case */ - child->SetWorldFromLocalTransform(); - child->ClearModified(); - return true; //false; - } - else { - // the childs world locations which we will update. - const MT_Vector3 & p_world_scale = parent->GetWorldScaling(); - const MT_Point3 & p_world_pos = parent->GetWorldPosition(); - const MT_Matrix3x3 & p_world_rotation = parent->GetWorldOrientation(); - - child->SetWorldScale(p_world_scale * child->GetLocalScale()); - child->SetWorldOrientation(p_world_rotation * child->GetLocalOrientation()); - child->SetWorldPosition(p_world_pos + p_world_scale * (p_world_rotation * child->GetLocalPosition())); - child->ClearModified(); - return true; - } -} - - SG_ParentRelation * -KX_NormalParentRelation:: -NewCopy( -) { - return new KX_NormalParentRelation(); -} - -KX_NormalParentRelation:: -~KX_NormalParentRelation( -) { - //nothing to do -} - - -KX_NormalParentRelation:: -KX_NormalParentRelation( -) { - // nothing to do -} - -/** - * Next KX_VertexParentRelation - */ - - - KX_VertexParentRelation * -KX_VertexParentRelation:: -New( -) { - return new KX_VertexParentRelation(); -} - -/** - * Method inherited from KX_ParentRelation - */ - - bool -KX_VertexParentRelation:: -UpdateChildCoordinates( - SG_Spatial * child, - const SG_Spatial * parent, - bool& parentUpdated -) { - - MT_assert(child != NULL); - - if (!parentUpdated && !child->IsModified()) - return false; - - child->SetWorldScale(child->GetLocalScale()); - - if (parent) - child->SetWorldPosition(child->GetLocalPosition()+parent->GetWorldPosition()); - else - child->SetWorldPosition(child->GetLocalPosition()); - - child->SetWorldOrientation(child->GetLocalOrientation()); - child->ClearModified(); - return true; //parent != NULL; -} - -/** - * Method inherited from KX_ParentRelation - */ - - SG_ParentRelation * -KX_VertexParentRelation:: -NewCopy( -) { - return new KX_VertexParentRelation(); -}; - -KX_VertexParentRelation:: -~KX_VertexParentRelation( -) { - //nothing to do -} - - -KX_VertexParentRelation:: -KX_VertexParentRelation( -) { - //nothing to do -} - - -/** - * Slow parent relationship - */ - - KX_SlowParentRelation * -KX_SlowParentRelation:: -New( - MT_Scalar relaxation -) { - return new KX_SlowParentRelation(relaxation); -} - -/** - * Method inherited from KX_ParentRelation - */ - - bool -KX_SlowParentRelation:: -UpdateChildCoordinates( - SG_Spatial * child, - const SG_Spatial * parent, - bool& parentUpdated -) { - MT_assert(child != NULL); - - // the child will move even if the parent is not - parentUpdated = true; - - const MT_Vector3 & child_scale = child->GetLocalScale(); - const MT_Point3 & child_pos = child->GetLocalPosition(); - const MT_Matrix3x3 & child_rotation = child->GetLocalOrientation(); - - // the childs world locations which we will update. - - MT_Vector3 child_w_scale; - MT_Point3 child_w_pos; - MT_Matrix3x3 child_w_rotation; - - if (parent) { - - // This is a slow parent relation - // first compute the normal child world coordinates. - - MT_Vector3 child_n_scale; - MT_Point3 child_n_pos; - MT_Matrix3x3 child_n_rotation; - - const MT_Vector3 & p_world_scale = parent->GetWorldScaling(); - const MT_Point3 & p_world_pos = parent->GetWorldPosition(); - const MT_Matrix3x3 & p_world_rotation = parent->GetWorldOrientation(); - - child_n_scale = p_world_scale * child_scale; - child_n_rotation = p_world_rotation * child_rotation; - - child_n_pos = p_world_pos + p_world_scale * - (p_world_rotation * child_pos); - - - if (m_initialized) { - - // get the current world positions - - child_w_scale = child->GetWorldScaling(); - child_w_pos = child->GetWorldPosition(); - child_w_rotation = child->GetWorldOrientation(); - - // now 'interpolate' the normal coordinates with the last - // world coordinates to get the new world coordinates. - - MT_Scalar weight = MT_Scalar(1)/(m_relax + 1); - child_w_scale = (m_relax * child_w_scale + child_n_scale) * weight; - child_w_pos = (m_relax * child_w_pos + child_n_pos) * weight; - // for rotation we must go through quaternion - MT_Quaternion child_w_quat = child_w_rotation.getRotation().slerp(child_n_rotation.getRotation(), weight); - child_w_rotation.setRotation(child_w_quat); - //FIXME: update physics controller. - } else { - child_w_scale = child_n_scale; - child_w_pos = child_n_pos; - child_w_rotation = child_n_rotation; - m_initialized = true; - } - - } else { - - child_w_scale = child_scale; - child_w_pos = child_pos; - child_w_rotation = child_rotation; - } - - child->SetWorldScale(child_w_scale); - child->SetWorldPosition(child_w_pos); - child->SetWorldOrientation(child_w_rotation); - child->ClearModified(); - // this node must always be updated, so reschedule it for next time - child->ActivateRecheduleUpdateCallback(); - - return true; //parent != NULL; -} - -/** - * Method inherited from KX_ParentRelation - */ - - SG_ParentRelation * -KX_SlowParentRelation:: -NewCopy( -) { - return new KX_SlowParentRelation(m_relax); -} - -KX_SlowParentRelation:: -KX_SlowParentRelation( - MT_Scalar relaxation -): - m_relax(relaxation), - m_initialized(false) -{ - //nothing to do -} - -KX_SlowParentRelation:: -~KX_SlowParentRelation( -) { - //nothing to do -} diff --git a/source/gameengine/Ketsji/KX_SG_NodeRelationships.h b/source/gameengine/Ketsji/KX_SG_NodeRelationships.h deleted file mode 100644 index 3b2fdf0272bd..000000000000 --- a/source/gameengine/Ketsji/KX_SG_NodeRelationships.h +++ /dev/null @@ -1,231 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - * - */ - -/** \file KX_SG_NodeRelationships.h - * \ingroup ketsji - * \section KX_SG_NodeRelationships - * This file provides common concrete implementations of - * SG_ParentRelation used by the game engine. These are - * KX_SlowParentRelation a slow parent relationship. - * KX_NormalParentRelation a normal parent relationship where - * orientation and position are inherited from the parent by - * the child. - * KX_VertexParentRelation only location information is - * inherited by the child. - */ - -#ifndef __KX_SG_NODERELATIONSHIPS_H__ -#define __KX_SG_NODERELATIONSHIPS_H__ - -#include "SG_Spatial.h" -#include "SG_ParentRelation.h" - -class KX_NormalParentRelation : public SG_ParentRelation -{ - -public : - /** - * Allocate and construct a new KX_NormalParentRelation - * on the heap. - */ - - static - KX_NormalParentRelation * - New( - ); - - /** - * Method inherited from KX_ParentRelation - */ - - bool - UpdateChildCoordinates( - SG_Spatial * child, - const SG_Spatial * parent, - bool& parentUpdated - ); - - /** - * Method inherited from KX_ParentRelation - */ - - SG_ParentRelation * - NewCopy( - ); - - ~KX_NormalParentRelation( - ); - -private : - - KX_NormalParentRelation( - ); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_NormalParentRelation") -#endif -}; - - -class KX_VertexParentRelation : public SG_ParentRelation -{ - -public : - - /** - * Allocate and construct a new KX_VertexParentRelation - * on the heap. - */ - - static - KX_VertexParentRelation * - New( - ); - - /** - * Method inherited from KX_ParentRelation - */ - - bool - UpdateChildCoordinates( - SG_Spatial * child, - const SG_Spatial * parent, - bool& parentUpdated - ); - - /** - * Method inherited from KX_ParentRelation - */ - - SG_ParentRelation * - NewCopy( - ); - - ~KX_VertexParentRelation( - ); - - bool - IsVertexRelation( - ) { - return true; - } - -private : - - KX_VertexParentRelation( - ); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_VertexParentRelation") -#endif -}; - - -class KX_SlowParentRelation : public SG_ParentRelation -{ - -public : - - /** - * Allocate and construct a new KX_VertexParentRelation - * on the heap. - */ - - static - KX_SlowParentRelation * - New( - MT_Scalar relaxation - ); - - /** - * Method inherited from KX_ParentRelation - */ - - bool - UpdateChildCoordinates( - SG_Spatial * child, - const SG_Spatial * parent, - bool& parentUpdated - ); - - /** - * Method inherited from KX_ParentRelation - */ - - SG_ParentRelation * - NewCopy( - ); - - MT_Scalar - GetTimeOffset( - ) { return m_relax; } - - void - SetTimeOffset( - MT_Scalar relaxation - ) { m_relax = relaxation; } - - ~KX_SlowParentRelation( - ); - - bool - IsSlowRelation( - ) { - return true; - } - -private : - - KX_SlowParentRelation( - MT_Scalar relaxation - ); - - // the relaxation coefficient. - - MT_Scalar m_relax; - - /** - * Looks like a hack flag to me. - * We need to compute valid world coordinates the first - * time we update spatial data of the child. This is done - * by just doing a normal parent relation the first time - * UpdateChildCoordinates is called and then doing the - * slow parent relation - */ - - bool m_initialized; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_SlowParentRelation") -#endif -}; - -#endif diff --git a/source/gameengine/Ketsji/KX_ScalarInterpolator.h b/source/gameengine/Ketsji/KX_ScalarInterpolator.h deleted file mode 100644 index 69d2d4229e3b..000000000000 --- a/source/gameengine/Ketsji/KX_ScalarInterpolator.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file KX_ScalarInterpolator.h - * \ingroup ketsji - */ - -#ifndef __KX_SCALARINTERPOLATOR_H__ -#define __KX_SCALARINTERPOLATOR_H__ - -#include "MT_Scalar.h" -#include "KX_IInterpolator.h" - -class KX_IScalarInterpolator; - -class KX_ScalarInterpolator : public KX_IInterpolator { -public: - KX_ScalarInterpolator(MT_Scalar* target, - KX_IScalarInterpolator *ipo) : - m_target(target), - m_ipo(ipo) - {} - - virtual ~KX_ScalarInterpolator() {} - virtual void Execute(float currentTime) const; - void SetNewTarget(MT_Scalar* newtarget) - { - m_target=newtarget; - } - MT_Scalar* GetTarget() - { - return m_target; - } -private: - MT_Scalar* m_target; - KX_IScalarInterpolator *m_ipo; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_ScalarInterpolator") -#endif -}; - -#endif diff --git a/source/gameengine/Ketsji/KX_ScalingInterpolator.cpp b/source/gameengine/Ketsji/KX_ScalingInterpolator.cpp deleted file mode 100644 index dd40cbd22fda..000000000000 --- a/source/gameengine/Ketsji/KX_ScalingInterpolator.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Ketsji/KX_ScalingInterpolator.cpp - * \ingroup ketsji - */ - - -#include "KX_ScalingInterpolator.h" -#include "MT_Vector3.h" -#include "KX_IScalarInterpolator.h" - -void KX_ScalingInterpolator::Execute(float currentTime) const -{ - m_target.setValue(m_ipos[0]->GetValue(currentTime), - m_ipos[1]->GetValue(currentTime), - m_ipos[2]->GetValue(currentTime)); -} diff --git a/source/gameengine/Ketsji/KX_ScalingInterpolator.h b/source/gameengine/Ketsji/KX_ScalingInterpolator.h deleted file mode 100644 index ca7b3177e521..000000000000 --- a/source/gameengine/Ketsji/KX_ScalingInterpolator.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file KX_ScalingInterpolator.h - * \ingroup ketsji - */ - -#ifndef __KX_SCALINGINTERPOLATOR_H__ -#define __KX_SCALINGINTERPOLATOR_H__ - -#include "KX_IInterpolator.h" - -class MT_Vector3; -class KX_IScalarInterpolator; - -class KX_ScalingInterpolator : public KX_IInterpolator { -public: - KX_ScalingInterpolator(MT_Vector3& target, - KX_IScalarInterpolator *ipos[]) - : m_target(target) - { - m_ipos[0] = ipos[0]; - m_ipos[1] = ipos[1]; - m_ipos[2] = ipos[2]; - } - - virtual void Execute(float currentTime) const; - -private: - MT_Vector3& m_target; - KX_IScalarInterpolator *m_ipos[3]; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_ScalingInterpolator") -#endif -}; - -#endif diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index ef5d1580181b..a1391200b393 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -35,103 +35,99 @@ # pragma warning (disable:4786) #endif -#include - #include "KX_Scene.h" -#include "KX_PythonInit.h" -#include "MT_assert.h" +#include "KX_Globals.h" +#include "BLI_utildefines.h" #include "KX_KetsjiEngine.h" #include "KX_BlenderMaterial.h" +#include "KX_TextMaterial.h" #include "KX_FontObject.h" -#include "RAS_IPolygonMaterial.h" +#include "RAS_IMaterial.h" #include "EXP_ListValue.h" #include "SCA_LogicManager.h" #include "SCA_TimeEventManager.h" -//#include "SCA_AlwaysEventManager.h" -//#include "SCA_RandomEventManager.h" -//#include "KX_RayEventManager.h" #include "SCA_2DFilterActuator.h" #include "SCA_PythonController.h" -#include "KX_TouchEventManager.h" +#include "KX_CollisionEventManager.h" #include "SCA_KeyboardManager.h" #include "SCA_MouseManager.h" -//#include "SCA_PropertyEventManager.h" #include "SCA_ActuatorEventManager.h" #include "SCA_BasicEventManager.h" #include "KX_Camera.h" +#include "KX_NavMeshObject.h" #include "SCA_JoystickManager.h" #include "KX_PyMath.h" -#include "RAS_MeshObject.h" +#include "KX_Mesh.h" #include "SCA_IScene.h" +#include "KX_LodManager.h" +#include "KX_CullingHandler.h" -#include "RAS_IRasterizer.h" +#include "RAS_Rasterizer.h" #include "RAS_ICanvas.h" +#include "RAS_2DFilterData.h" +#include "KX_2DFilterManager.h" +#include "RAS_BoundingBoxManager.h" #include "RAS_BucketManager.h" +#include "RAS_Deformer.h" #include "EXP_FloatValue.h" #include "SCA_IController.h" #include "SCA_IActuator.h" #include "SG_Node.h" -#include "BL_System.h" #include "SG_Controller.h" -#include "SG_IObject.h" -#include "SG_Tree.h" +#include "SG_Node.h" #include "DNA_group_types.h" #include "DNA_scene_types.h" #include "DNA_property_types.h" -#include "KX_SG_NodeRelationships.h" +#include "KX_NodeRelationships.h" -#include "KX_NetworkEventManager.h" -#include "NG_NetworkScene.h" +#include "KX_NetworkMessageScene.h" #include "PHY_IPhysicsEnvironment.h" #include "PHY_IGraphicController.h" #include "PHY_IPhysicsController.h" -#include "KX_BlenderSceneConverter.h" +#include "BL_Converter.h" +#include "BL_ArmatureObject.h" #include "KX_MotionState.h" - -#include "BL_ModifierDeformer.h" -#include "BL_ShapeDeformer.h" -#include "BL_DeformableGameObject.h" #include "KX_ObstacleSimulation.h" -#ifdef WITH_BULLET -# include "KX_SoftBodyDeformer.h" -#endif - #ifdef WITH_PYTHON # include "EXP_PythonCallBack.h" #endif -#include "KX_Light.h" +#include "KX_LightObject.h" #include "BLI_task.h" -static void *KX_SceneReplicationFunc(SG_IObject* node,void* gameobj,void* scene) +#include "CM_Message.h" +#include "CM_List.h" + +static void *KX_SceneReplicationFunc(SG_Node *node, void *gameobj, void *scene) { - KX_GameObject* replica = ((KX_Scene*)scene)->AddNodeReplicaObject(node,(KX_GameObject*)gameobj); + KX_GameObject *replica = ((KX_Scene *)scene)->AddNodeReplicaObject(node, (KX_GameObject *)gameobj); - if (replica) + if (replica) { replica->Release(); + } - return (void*)replica; + return (void *)replica; } -static void *KX_SceneDestructionFunc(SG_IObject* node,void* gameobj,void* scene) +static void *KX_SceneDestructionFunc(SG_Node *node, void *gameobj, void *scene) { - ((KX_Scene*)scene)->RemoveNodeDestructObject(node,(KX_GameObject*)gameobj); + ((KX_Scene *)scene)->RemoveNodeDestructObject((KX_GameObject *)gameobj); - return NULL; -}; + return nullptr; +} -bool KX_Scene::KX_ScenegraphUpdateFunc(SG_IObject* node,void* gameobj,void* scene) +bool KX_Scene::KX_ScenegraphUpdateFunc(SG_Node *node, void *gameobj, void *scene) { - return ((SG_Node*)node)->Schedule(((KX_Scene*)scene)->m_sghead); + return node->Schedule(((KX_Scene *)scene)->m_sghead); } -bool KX_Scene::KX_ScenegraphRescheduleFunc(SG_IObject* node,void* gameobj,void* scene) +bool KX_Scene::KX_ScenegraphRescheduleFunc(SG_Node *node, void *gameobj, void *scene) { - return ((SG_Node*)node)->Reschedule(((KX_Scene*)scene)->m_sghead); + return node->Reschedule(((KX_Scene *)scene)->m_sghead); } SG_Callbacks KX_Scene::m_callbacks = SG_Callbacks( @@ -141,284 +137,254 @@ SG_Callbacks KX_Scene::m_callbacks = SG_Callbacks( KX_Scene::KX_ScenegraphUpdateFunc, KX_Scene::KX_ScenegraphRescheduleFunc); -// temporarily var until there is a button in the userinterface -// (defined in KX_PythonInit.cpp) -extern bool gUseVisibilityTemp; - -KX_Scene::KX_Scene(class SCA_IInputDevice* keyboarddevice, - class SCA_IInputDevice* mousedevice, - class NG_NetworkDeviceInterface *ndi, - const STR_String& sceneName, - Scene *scene, - class RAS_ICanvas* canvas): - PyObjectPlus(), - m_keyboardmgr(NULL), - m_mousemgr(NULL), - m_sceneConverter(NULL), +KX_Scene::KX_Scene(SCA_IInputDevice *inputDevice, + const std::string& sceneName, + Scene *scene, + RAS_ICanvas *canvas, + KX_NetworkMessageManager *messageManager) : + m_keyboardmgr(nullptr), + m_mousemgr(nullptr), m_physicsEnvironment(0), m_sceneName(sceneName), - m_networkDeviceInterface(ndi), - m_active_camera(NULL), + m_activeCamera(nullptr), + m_overrideCullingCamera(nullptr), m_ueberExecutionPriority(0), + m_suspend(false), + m_suspendedDelta(0.0), + m_activityCulling(false), + m_dbvtCulling(false), + m_dbvtOcclusionRes(0), m_blenderScene(scene), + m_previousAnimTime(0.0f), m_isActivedHysteresis(false), m_lodHysteresisValue(0) { - m_suspendedtime = 0.0; - m_suspendeddelta = 0.0; - m_dbvt_culling = false; - m_dbvt_occlusion_res = 0; - m_activity_culling = false; - m_suspend = false; - m_isclearingZbuffer = true; - m_isShadowDone = false; - m_tempObjectList = new CListValue(); - m_objectlist = new CListValue(); - m_parentlist = new CListValue(); - m_lightlist= new CListValue(); - m_inactivelist = new CListValue(); - m_euthanasyobjects = new CListValue(); - m_animatedlist = new CListValue(); + m_objectlist = new EXP_ListValue(); + m_parentlist = new EXP_ListValue(); + m_lightlist = new EXP_ListValue(); + m_inactivelist = new EXP_ListValue(); + m_cameralist = new EXP_ListValue(); + m_fontlist = new EXP_ListValue(); + m_filterManager = new KX_2DFilterManager(); m_logicmgr = new SCA_LogicManager(); m_timemgr = new SCA_TimeEventManager(m_logicmgr); - m_keyboardmgr = new SCA_KeyboardManager(m_logicmgr,keyboarddevice); - m_mousemgr = new SCA_MouseManager(m_logicmgr,mousedevice, canvas); - - //SCA_AlwaysEventManager* alwaysmgr = new SCA_AlwaysEventManager(m_logicmgr); - //SCA_PropertyEventManager* propmgr = new SCA_PropertyEventManager(m_logicmgr); - SCA_ActuatorEventManager* actmgr = new SCA_ActuatorEventManager(m_logicmgr); - //SCA_RandomEventManager* rndmgr = new SCA_RandomEventManager(m_logicmgr); - SCA_BasicEventManager* basicmgr = new SCA_BasicEventManager(m_logicmgr); - //KX_RayEventManager* raymgr = new KX_RayEventManager(m_logicmgr); - - KX_NetworkEventManager* netmgr = new KX_NetworkEventManager(m_logicmgr, ndi); - + m_keyboardmgr = new SCA_KeyboardManager(m_logicmgr, inputDevice); + m_mousemgr = new SCA_MouseManager(m_logicmgr, inputDevice); + SCA_ActuatorEventManager *actmgr = new SCA_ActuatorEventManager(m_logicmgr); + SCA_BasicEventManager *basicmgr = new SCA_BasicEventManager(m_logicmgr); - //m_logicmgr->RegisterEventManager(alwaysmgr); - //m_logicmgr->RegisterEventManager(propmgr); m_logicmgr->RegisterEventManager(actmgr); m_logicmgr->RegisterEventManager(m_keyboardmgr); m_logicmgr->RegisterEventManager(m_mousemgr); m_logicmgr->RegisterEventManager(m_timemgr); - //m_logicmgr->RegisterEventManager(rndmgr); - //m_logicmgr->RegisterEventManager(raymgr); - m_logicmgr->RegisterEventManager(netmgr); m_logicmgr->RegisterEventManager(basicmgr); + SCA_JoystickManager *joymgr = new SCA_JoystickManager(m_logicmgr); + m_logicmgr->RegisterEventManager(joymgr); - SYS_SystemHandle hSystem = SYS_GetSystem(); - bool nojoystick= SYS_GetCommandLineInt(hSystem,"nojoystick",0); - if (!nojoystick) - { - SCA_JoystickManager *joymgr = new SCA_JoystickManager(m_logicmgr); - m_logicmgr->RegisterEventManager(joymgr); - } + m_networkScene = new KX_NetworkMessageScene(messageManager); - MT_assert (m_networkDeviceInterface != NULL); - m_networkScene = new NG_NetworkScene(m_networkDeviceInterface); + m_rendererManager = new KX_TextureRendererManager(this); + m_bucketmanager = new RAS_BucketManager(KX_TextMaterial::GetSingleton()); + m_boundingBoxManager = new RAS_BoundingBoxManager(); - m_rootnode = NULL; + m_animationPool = BLI_task_pool_create(KX_GetActiveEngine()->GetTaskScheduler(), &m_animationPoolData); - m_bucketmanager=new RAS_BucketManager(); +#ifdef WITH_PYTHON + m_attrDict = nullptr; + m_removeCallbacks = nullptr; - bool showObstacleSimulation = (scene->gm.flag & GAME_SHOW_OBSTACLE_SIMULATION) != 0; - switch (scene->gm.obstacleSimulation) - { - case OBSTSIMULATION_TOI_rays: - m_obstacleSimulation = new KX_ObstacleSimulationTOI_rays((MT_Scalar)scene->gm.levelHeight, showObstacleSimulation); - break; - case OBSTSIMULATION_TOI_cells: - m_obstacleSimulation = new KX_ObstacleSimulationTOI_cells((MT_Scalar)scene->gm.levelHeight, showObstacleSimulation); - break; - default: - m_obstacleSimulation = NULL; + for (unsigned short i = 0; i < MAX_DRAW_CALLBACK; ++i) { + m_drawCallbacks[i] = nullptr; } - -#ifdef WITH_PYTHON - m_attr_dict = NULL; - m_draw_call_pre = NULL; - m_draw_call_post = NULL; - m_draw_setup_call_pre = NULL; #endif } - - KX_Scene::~KX_Scene() { - // The release of debug properties used to be in SCA_IScene::~SCA_IScene - // It's still there but we remove all properties here otherwise some - // reference might be hanging and causing late release of objects + /* The release of debug properties used to be in SCA_IScene::~SCA_IScene + * It's still there but we remove all properties here otherwise some + * reference might be hanging and causing late release of objects + */ RemoveAllDebugProperties(); - while (GetRootParentList()->GetCount() > 0) - { - KX_GameObject* parentobj = (KX_GameObject*) GetRootParentList()->GetValue(0); + while (GetRootParentList()->GetCount() > 0) { + KX_GameObject *parentobj = GetRootParentList()->GetValue(0); this->RemoveObject(parentobj); } - if (m_obstacleSimulation) + if (m_obstacleSimulation) { delete m_obstacleSimulation; + } - if (m_objectlist) + if (m_animationPool) { + BLI_task_pool_free(m_animationPool); + } + + if (m_objectlist) { m_objectlist->Release(); + } - if (m_parentlist) + if (m_parentlist) { m_parentlist->Release(); + } - if (m_inactivelist) + if (m_inactivelist) { m_inactivelist->Release(); + } - if (m_lightlist) + if (m_lightlist) { m_lightlist->Release(); + } - if (m_tempObjectList) - m_tempObjectList->Release(); + if (m_cameralist) { + m_cameralist->Release(); + } - if (m_euthanasyobjects) - m_euthanasyobjects->Release(); + if (m_fontlist) { + m_fontlist->Release(); + } - if (m_animatedlist) - m_animatedlist->Release(); + if (m_filterManager) { + delete m_filterManager; + } - if (m_logicmgr) + if (m_logicmgr) { delete m_logicmgr; + } - if (m_physicsEnvironment) + if (m_physicsEnvironment) { delete m_physicsEnvironment; + } - if (m_networkScene) + if (m_networkScene) { delete m_networkScene; + } - if (m_bucketmanager) - { + if (m_rendererManager) { + delete m_rendererManager; + } + + if (m_bucketmanager) { delete m_bucketmanager; } + if (m_boundingBoxManager) { + delete m_boundingBoxManager; + } + + if (m_worldinfo) { + delete m_worldinfo; + } + #ifdef WITH_PYTHON - if (m_attr_dict) { - PyDict_Clear(m_attr_dict); - /* Py_CLEAR: Py_DECREF's and NULL's */ - Py_CLEAR(m_attr_dict); + if (m_attrDict) { + PyDict_Clear(m_attrDict); + Py_CLEAR(m_attrDict); } - /* these may be NULL but the macro checks */ - Py_CLEAR(m_draw_call_pre); - Py_CLEAR(m_draw_call_post); + // These may be nullptr but the macro checks. + Py_CLEAR(m_removeCallbacks); + for (unsigned short i = 0; i < MAX_DRAW_CALLBACK; ++i) { + Py_CLEAR(m_drawCallbacks[i]); + } #endif } -RAS_BucketManager* KX_Scene::GetBucketManager() +std::string KX_Scene::GetName() +{ + return m_sceneName; +} + +void KX_Scene::SetName(const std::string& name) +{ + m_sceneName = name; +} + +RAS_BucketManager *KX_Scene::GetBucketManager() const { return m_bucketmanager; } +KX_TextureRendererManager *KX_Scene::GetTextureRendererManager() const +{ + return m_rendererManager; +} -CListValue* KX_Scene::GetTempObjectList() +RAS_BoundingBoxManager *KX_Scene::GetBoundingBoxManager() const { - return m_tempObjectList; + return m_boundingBoxManager; } -CListValue* KX_Scene::GetObjectList() +EXP_ListValue *KX_Scene::GetObjectList() const { return m_objectlist; } - -CListValue* KX_Scene::GetRootParentList() +EXP_ListValue *KX_Scene::GetRootParentList() const { return m_parentlist; } -CListValue* KX_Scene::GetInactiveList() +EXP_ListValue *KX_Scene::GetInactiveList() const { return m_inactivelist; } - - -CListValue* KX_Scene::GetLightList() +EXP_ListValue *KX_Scene::GetLightList() const { return m_lightlist; } -SCA_LogicManager* KX_Scene::GetLogicManager() +EXP_ListValue *KX_Scene::GetCameraList() const { - return m_logicmgr; + return m_cameralist; } -SCA_TimeEventManager* KX_Scene::GetTimeEventManager() +EXP_ListValue *KX_Scene::GetFontList() const { - return m_timemgr; + return m_fontlist; } - - - -list* KX_Scene::GetCameras() +SCA_LogicManager *KX_Scene::GetLogicManager() const { - return &m_cameras; + return m_logicmgr; } -void KX_Scene::SetFramingType(RAS_FrameSettings & frame_settings) +SCA_TimeEventManager *KX_Scene::GetTimeEventManager() const { - m_frame_settings = frame_settings; -}; + return m_timemgr; +} -/** - * Return a const reference to the framing - * type set by the above call. - * The contents are not guaranteed to be sensible - * if you don't call the above function. - */ -const RAS_FrameSettings& KX_Scene::GetFramingType() const +KX_PythonComponentManager& KX_Scene::GetPythonComponentManager() { - return m_frame_settings; -}; - - + return m_componentManager; +} -/** - * Store the current scene's viewport on the - * game engine canvas. - */ -void KX_Scene::SetSceneViewport(const RAS_Rect &viewport) +void KX_Scene::SetFramingType(const RAS_FrameSettings& frameSettings) { - m_viewport = viewport; + m_frameSettings = frameSettings; } - - -const RAS_Rect& KX_Scene::GetSceneViewport() const +const RAS_FrameSettings& KX_Scene::GetFramingType() const { - return m_viewport; + return m_frameSettings; } - - -void KX_Scene::SetWorldInfo(class KX_WorldInfo* worldinfo) +void KX_Scene::SetWorldInfo(KX_WorldInfo *worldinfo) { m_worldinfo = worldinfo; } - - -class KX_WorldInfo* KX_Scene::GetWorldInfo() +KX_WorldInfo *KX_Scene::GetWorldInfo() const { return m_worldinfo; } - -const STR_String& KX_Scene::GetName() -{ - return m_sceneName; -} - - void KX_Scene::Suspend() { m_suspend = true; @@ -431,1363 +397,1042 @@ void KX_Scene::Resume() void KX_Scene::SetActivityCulling(bool b) { - m_activity_culling = b; + m_activityCulling = b; } -bool KX_Scene::IsSuspended() +bool KX_Scene::IsSuspended() const { return m_suspend; } -bool KX_Scene::IsClearingZBuffer() +void KX_Scene::SetDbvtCulling(bool b) { - return m_isclearingZbuffer; + m_dbvtCulling = b; } -void KX_Scene::EnableZBufferClearing(bool isclearingZbuffer) +bool KX_Scene::GetDbvtCulling() const { - m_isclearingZbuffer = isclearingZbuffer; + return m_dbvtCulling; } -void KX_Scene::AddObjectDebugProperties(class KX_GameObject* gameobj) +void KX_Scene::SetDbvtOcclusionRes(int i) { - Object* blenderobject = gameobj->GetBlenderObject(); - bProperty* prop = (bProperty*)blenderobject->prop.first; - - while (prop) { - if (prop->flag & PROP_DEBUG) - AddDebugProperty(gameobj,STR_String(prop->name)); - prop = prop->next; - } + m_dbvtOcclusionRes = i; +} - if (blenderobject->scaflag & OB_DEBUGSTATE) - AddDebugProperty(gameobj,STR_String("__state__")); +int KX_Scene::GetDbvtOcclusionRes() const +{ + return m_dbvtOcclusionRes; } -void KX_Scene::RemoveNodeDestructObject(class SG_IObject* node,class CValue* gameobj) +void KX_Scene::AddObjectDebugProperties(KX_GameObject *gameobj) { - KX_GameObject* orgobj = (KX_GameObject*)gameobj; - if (NewRemoveObject(orgobj) != 0) - { - // object is not yet deleted because a reference is hanging somewhere. - // This should not happen anymore since we use proxy object for Python - // confident enough to put an assert? - //assert(false); - printf("Zombie object! name=%s\n", orgobj->GetName().ReadPtr()); - orgobj->SetSGNode(NULL); - PHY_IGraphicController* ctrl = orgobj->GetGraphicController(); - if (ctrl) - { - // a graphic controller is set, we must delete it as the node will be deleted - delete ctrl; - orgobj->SetGraphicController(NULL); + Object *blenderobject = gameobj->GetBlenderObject(); + if (!blenderobject) { + return; + } + + for (bProperty *prop = (bProperty *)blenderobject->prop.first; prop; prop = prop->next) { + if (prop->flag & PROP_DEBUG) { + AddDebugProperty(gameobj, prop->name); } } - if (node) - delete node; + + if (blenderobject->scaflag & OB_DEBUGSTATE) { + AddDebugProperty(gameobj, "__state__"); + } } -KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CValue* gameobj) +void KX_Scene::RemoveNodeDestructObject(KX_GameObject *gameobj) { - // for group duplication, limit the duplication of the hierarchy to the - // objects that are part of the group. - if (!IsObjectInGroup(gameobj)) - return NULL; + if (NewRemoveObject(gameobj)) { + /* Object is not yet deleted because a reference is hanging somewhere. + * This should not happen anymore since we use proxy object for Python. */ + CM_Error("zombie object! name=" << gameobj->GetName()); + BLI_assert(false); + } +} - KX_GameObject* orgobj = (KX_GameObject*)gameobj; - KX_GameObject* newobj = (KX_GameObject*)orgobj->GetReplica(); - m_map_gameobject_to_replica.insert(orgobj, newobj); +KX_GameObject *KX_Scene::AddNodeReplicaObject(SG_Node *node, KX_GameObject *gameobj) +{ + /* For group duplication, limit the duplication of the hierarchy to the + * objects that are part of the group. */ + if (!IsObjectInGroup(gameobj)) { + return nullptr; + } - // also register 'timers' (time properties) of the replica - int numprops = newobj->GetPropertyCount(); + KX_GameObject *newobj = static_cast(gameobj->GetReplica()); + m_map_gameobject_to_replica[gameobj] = newobj; - for (int i = 0; i < numprops; i++) - { - CValue* prop = newobj->GetProperty(i); + // Also register 'timers' (time properties) of the replica. + for (unsigned short i = 0, numprops = newobj->GetPropertyCount(); i < numprops; ++i) { + EXP_Value *prop = newobj->GetProperty(i); - if (prop->GetProperty("timer")) - this->m_timemgr->AddTimeProperty(prop); + if (prop->GetProperty("timer")) { + m_timemgr->AddTimeProperty(prop); + } } - if (node) - { - newobj->SetSGNode((SG_Node*)node); + if (node) { + newobj->SetNode(node); } - else - { - m_rootnode = new SG_Node(newobj,this,KX_Scene::m_callbacks); + else { + SG_Node *rootnode = new SG_Node(newobj, this, KX_Scene::m_callbacks); + + // This fixes part of the scaling-added object bug. + SG_Node *orgnode = gameobj->GetNode(); + rootnode->SetLocalScale(orgnode->GetLocalScale()); + rootnode->SetLocalPosition(orgnode->GetLocalPosition()); + rootnode->SetLocalOrientation(orgnode->GetLocalOrientation()); + + // Define the relationship between this node and it's parent. + KX_NormalParentRelation *parent_relation = new KX_NormalParentRelation(); + rootnode->SetParentRelation(parent_relation); - // this fixes part of the scaling-added object bug - SG_Node* orgnode = orgobj->GetSGNode(); - m_rootnode->SetLocalScale(orgnode->GetLocalScale()); - m_rootnode->SetLocalPosition(orgnode->GetLocalPosition()); - m_rootnode->SetLocalOrientation(orgnode->GetLocalOrientation()); + newobj->SetNode(rootnode); + } - // define the relationship between this node and it's parent. - KX_NormalParentRelation * parent_relation = - KX_NormalParentRelation::New(); - m_rootnode->SetParentRelation(parent_relation); + SG_Node *replicanode = newobj->GetNode(); - newobj->SetSGNode(m_rootnode); + // Add the object in the obstacle simulation if needed. + if (m_obstacleSimulation && gameobj->GetBlenderObject()->gameflag & OB_HASOBSTACLE) { + m_obstacleSimulation->AddObstacleForObj(newobj); + } + // Reconstruct nav mesh. + if (gameobj->GetGameObjectType() == SCA_IObject::OBJ_NAVMESH) { + static_cast(gameobj)->BuildNavMesh(); } - SG_IObject* replicanode = newobj->GetSGNode(); -// SG_Node* rootnode = (replicanode == m_rootnode ? NULL : m_rootnode); + // Register object for component update. + if (gameobj->GetComponents()) { + m_componentManager.RegisterObject(newobj); + } - replicanode->SetSGClientObject(newobj); + replicanode->SetClientObject(newobj); - // this is the list of object that are send to the graphics pipeline - m_objectlist->Add(newobj->AddRef()); - if (newobj->GetGameObjectType()==SCA_IObject::OBJ_LIGHT) - m_lightlist->Add(newobj->AddRef()); - else if (newobj->GetGameObjectType()==SCA_IObject::OBJ_TEXT) - AddFont((KX_FontObject*)newobj); - newobj->AddMeshUser(); + // This is the list of object that are send to the graphics pipeline. + m_objectlist->Add(CM_AddRef(newobj)); - // logic cannot be replicated, until the whole hierarchy is replicated. - m_logicHierarchicalGameObjects.push_back(newobj); - //replicate controllers of this node - SGControllerList scenegraphcontrollers = orgobj->GetSGNode()->GetSGControllerList(); - replicanode->RemoveAllControllers(); - SGControllerList::iterator cit; - //int numcont = scenegraphcontrollers.size(); - - for (cit = scenegraphcontrollers.begin();!(cit==scenegraphcontrollers.end());++cit) - { - // controller replication is quite complicated - // only replicate ipo controller for now - - SG_Controller* replicacontroller = (*cit)->GetReplica((SG_Node*) replicanode); - if (replicacontroller) + switch (newobj->GetGameObjectType()) { + case SCA_IObject::OBJ_LIGHT: + { + m_lightlist->Add(CM_AddRef(static_cast(newobj))); + break; + } + case SCA_IObject::OBJ_TEXT: { - replicacontroller->SetObject(replicanode); - replicanode->AddSGController(replicacontroller); + m_fontlist->Add(CM_AddRef(static_cast(newobj))); + break; + } + case SCA_IObject::OBJ_CAMERA: + { + m_cameralist->Add(CM_AddRef(static_cast(newobj))); + break; + } + case SCA_IObject::OBJ_ARMATURE: + { + AddAnimatedObject(newobj); + break; } } - // replicate graphic controller - if (orgobj->GetGraphicController()) - { - PHY_IMotionState* motionstate = new KX_MotionState(newobj->GetSGNode()); - PHY_IGraphicController* newctrl = orgobj->GetGraphicController()->GetReplica(motionstate); - newctrl->SetNewClientInfo(newobj->getClientInfo()); + + // Logic cannot be replicated, until the whole hierarchy is replicated. + m_logicHierarchicalGameObjects.push_back(newobj); + + // Replicate graphic controller. + if (gameobj->GetGraphicController()) { + PHY_IMotionState *motionstate = new KX_MotionState(newobj->GetNode()); + PHY_IGraphicController *newctrl = gameobj->GetGraphicController()->GetReplica(motionstate); + newctrl->SetNewClientInfo(&newobj->GetClientInfo()); newobj->SetGraphicController(newctrl); } - // replicate physics controller - if (orgobj->GetPhysicsController()) - { - PHY_IMotionState* motionstate = new KX_MotionState(newobj->GetSGNode()); - PHY_IPhysicsController* newctrl = orgobj->GetPhysicsController()->GetReplica(); + // Replicate physics controller. + if (gameobj->GetPhysicsController()) { + PHY_IMotionState *motionstate = new KX_MotionState(newobj->GetNode()); + PHY_IPhysicsController *newctrl = gameobj->GetPhysicsController()->GetReplica(); KX_GameObject *parent = newobj->GetParent(); - PHY_IPhysicsController* parentctrl = (parent) ? parent->GetPhysicsController() : NULL; + PHY_IPhysicsController *parentctrl = (parent) ? parent->GetPhysicsController() : nullptr; - newctrl->SetNewClientInfo(newobj->getClientInfo()); - newobj->SetPhysicsController(newctrl, newobj->IsDynamic()); + newctrl->SetNewClientInfo(&newobj->GetClientInfo()); + newobj->SetPhysicsController(newctrl); newctrl->PostProcessReplica(motionstate, parentctrl); - // Child objects must be static - if (parent) + // Child objects must be static. + if (parent) { newctrl->SuspendDynamics(); + } } return newobj; } - - -// before calling this method KX_Scene::ReplicateLogic(), make sure to -// have called 'GameObject::ReParentLogic' for each object this -// hierarchy that's because first ALL bricks must exist in the new -// replica of the hierarchy in order to make cross-links work properly -// ! -// It is VERY important that the order of sensors and actuators in -// the replicated object is preserved: it is used to reconnect the logic. -// This method is more robust then using the bricks name in case of complex -// group replication. The replication of logic bricks is done in -// SCA_IObject::ReParentLogic(), make sure it preserves the order of the bricks. -void KX_Scene::ReplicateLogic(KX_GameObject* newobj) +/* + * Before calling this method KX_Scene::ReplicateLogic(), make sure to + * have called 'GameObject::ReParentLogic' for each object this + * hierarchy that's because first ALL bricks must exist in the new + * replica of the hierarchy in order to make cross-links work properly. + * + * It is VERY important that the order of sensors and actuators in + * the replicated object is preserved: it is used to reconnect the logic. + * This method is more robust then using the bricks name in case of complex + * group replication. The replication of logic bricks is done in + * SCA_IObject::ReParentLogic(), make sure it preserves the order of the bricks. + */ +void KX_Scene::ReplicateLogic(KX_GameObject *newobj) { - /* add properties to debug list, for added objects and DupliGroups */ - if (KX_GetActiveEngine()->GetAutoAddDebugProperties()) { + // Add properties to debug list, for added objects and DupliGroups. + if (KX_GetActiveEngine()->GetFlag(KX_KetsjiEngine::AUTO_ADD_DEBUG_PROPERTIES)) { AddObjectDebugProperties(newobj); } - // also relink the controller to sensors/actuators - SCA_ControllerList& controllers = newobj->GetControllers(); - //SCA_SensorList& sensors = newobj->GetSensors(); - //SCA_ActuatorList& actuators = newobj->GetActuators(); + // Also relink the controller to sensors/actuators. + const SCA_ControllerList controllers = newobj->GetControllers(); - for (SCA_ControllerList::iterator itc = controllers.begin(); !(itc==controllers.end());itc++) - { - SCA_IController* cont = (*itc); + for (SCA_IController *cont : controllers) { cont->SetUeberExecutePriority(m_ueberExecutionPriority); - vector linkedsensors = cont->GetLinkedSensors(); - vector linkedactuators = cont->GetLinkedActuators(); + const SCA_SensorList linkedsensors = cont->GetLinkedSensors(); + const SCA_ActuatorList linkedactuators = cont->GetLinkedActuators(); - // disconnect the sensors and actuators - // do it directly on the list at this controller is not connected to anything at this stage + /* Disconnect the sensors and actuators + * do it directly on the list at this controller is not connected to anything at this stage. */ cont->GetLinkedSensors().clear(); cont->GetLinkedActuators().clear(); - // now relink each sensor - for (vector::iterator its = linkedsensors.begin();!(its==linkedsensors.end());its++) - { - SCA_ISensor* oldsensor = (*its); - SCA_IObject* oldsensorobj = oldsensor->GetParent(); - SCA_IObject* newsensorobj = NULL; - - // the original owner of the sensor has been replicated? - void **h_obj = m_map_gameobject_to_replica[oldsensorobj]; - if (h_obj) - newsensorobj = (SCA_IObject*)(*h_obj); - if (!newsensorobj) - { - // no, then the sensor points outside the hierarchy, keep it the same - if (m_objectlist->SearchValue(oldsensorobj)) - // only replicate links that points to active objects - m_logicmgr->RegisterToSensor(cont,oldsensor); + // Now relink each sensor. + for (SCA_ISensor *oldsensor : linkedsensors) { + SCA_IObject *oldsensorobj = oldsensor->GetParent(); + // The original owner of the sensor has been replicated? + SCA_IObject *newsensorobj = m_map_gameobject_to_replica[oldsensorobj]; + + if (!newsensorobj) { + // No, then the sensor points outside the hierarchy, keep it the same. + if (m_objectlist->SearchValue(static_cast(oldsensorobj))) { + // Only replicate links that points to active objects. + m_logicmgr->RegisterToSensor(cont, oldsensor); + } } - else - { - // yes, then the new sensor has the same position + else { + // Yes, then the new sensor has the same position. SCA_SensorList& sensorlist = oldsensorobj->GetSensors(); SCA_SensorList::iterator sit; - SCA_ISensor* newsensor = NULL; + SCA_ISensor *newsensor = nullptr; int sensorpos; - for (sensorpos=0, sit=sensorlist.begin(); sit!=sensorlist.end(); sit++, sensorpos++) - { - if ((*sit) == oldsensor) - { + for (sensorpos = 0, sit = sensorlist.begin(); sit != sensorlist.end(); sit++, sensorpos++) { + if ((*sit) == oldsensor) { newsensor = newsensorobj->GetSensors().at(sensorpos); break; } } - assert(newsensor != NULL); - m_logicmgr->RegisterToSensor(cont,newsensor); + + BLI_assert(newsensor != nullptr); + m_logicmgr->RegisterToSensor(cont, newsensor); } } - // now relink each actuator - for (vector::iterator ita = linkedactuators.begin();!(ita==linkedactuators.end());ita++) - { - SCA_IActuator* oldactuator = (*ita); - SCA_IObject* oldactuatorobj = oldactuator->GetParent(); - SCA_IObject* newactuatorobj = NULL; - - // the original owner of the sensor has been replicated? - void **h_obj = m_map_gameobject_to_replica[oldactuatorobj]; - if (h_obj) - newactuatorobj = (SCA_IObject*)(*h_obj); - - if (!newactuatorobj) - { - // no, then the sensor points outside the hierarchy, keep it the same - if (m_objectlist->SearchValue(oldactuatorobj)) - // only replicate links that points to active objects - m_logicmgr->RegisterToActuator(cont,oldactuator); + // Now relink each actuator. + for (SCA_IActuator *oldactuator : linkedactuators) { + SCA_IObject *oldactuatorobj = oldactuator->GetParent(); + SCA_IObject *newactuatorobj = m_map_gameobject_to_replica[oldactuatorobj]; + + if (!newactuatorobj) { + // No, then the sensor points outside the hierarchy, keep it the same. + if (m_objectlist->SearchValue(static_cast(oldactuatorobj))) { + // Only replicate links that points to active objects + m_logicmgr->RegisterToActuator(cont, oldactuator); + } } - else - { - // yes, then the new sensor has the same position + else { + // Yes, then the new sensor has the same position SCA_ActuatorList& actuatorlist = oldactuatorobj->GetActuators(); SCA_ActuatorList::iterator ait; - SCA_IActuator* newactuator = NULL; + SCA_IActuator *newactuator = nullptr; int actuatorpos; - for (actuatorpos=0, ait=actuatorlist.begin(); ait!=actuatorlist.end(); ait++, actuatorpos++) - { - if ((*ait) == oldactuator) - { + for (actuatorpos = 0, ait = actuatorlist.begin(); ait != actuatorlist.end(); ait++, actuatorpos++) { + if ((*ait) == oldactuator) { newactuator = newactuatorobj->GetActuators().at(actuatorpos); break; } } - assert(newactuator != NULL); - m_logicmgr->RegisterToActuator(cont,newactuator); + BLI_assert(newactuator != nullptr); + m_logicmgr->RegisterToActuator(cont, newactuator); newactuator->SetUeberExecutePriority(m_ueberExecutionPriority); } } } - // ready to set initial state + // Ready to set initial state. newobj->ResetState(); } -void KX_Scene::DupliGroupRecurse(CValue* obj, int level) +void KX_Scene::DupliGroupRecurse(KX_GameObject *groupobj, int level) { - KX_GameObject* groupobj = (KX_GameObject*) obj; - KX_GameObject* replica; - KX_GameObject* gameobj; - Object* blgroupobj = groupobj->GetBlenderObject(); - Group* group; - GroupObject *go; - vector duplilist; + Object *blgroupobj = groupobj->GetBlenderObject(); + std::vector duplilist; - if (!groupobj->GetSGNode() || - !groupobj->IsDupliGroup() || - level>MAX_DUPLI_RECUR) + if (!groupobj->GetNode() || !groupobj->IsDupliGroup() || level > MAX_DUPLI_RECUR) { return; + } - // we will add one group at a time + // We will add one group at a time. m_logicHierarchicalGameObjects.clear(); m_map_gameobject_to_replica.clear(); m_ueberExecutionPriority++; - // for groups will do something special: - // we will force the creation of objects to those in the group only - // Again, this is match what Blender is doing (it doesn't care of parent relationship) + + /* For groups will do something special: + * we will force the creation of objects to those in the group only + * Again, this is match what Blender is doing (it doesn't care of parent relationship) + */ m_groupGameObjects.clear(); - group = blgroupobj->dup_group; - for (go=(GroupObject*)group->gobject.first; go; go=(GroupObject*)go->next) - { - Object* blenderobj = go->ob; - if (blgroupobj == blenderobj) - // this check is also in group_duplilist() + Group *group = blgroupobj->dup_group; + for (GroupObject *go = (GroupObject *)group->gobject.first; go; go = (GroupObject *)go->next) { + Object *blenderobj = go->ob; + if (blgroupobj == blenderobj) { + // This check is also in group_duplilist(). continue; + } - gameobj = (KX_GameObject*)m_logicmgr->FindGameObjByBlendObj(blenderobj); - if (gameobj == NULL) - { - // this object has not been converted!!! - // Should not happen as dupli group are created automatically + KX_GameObject *gameobj = (KX_GameObject *)m_logicmgr->FindGameObjByBlendObj(blenderobj); + if (gameobj == nullptr) { + /* This object has not been converted. + * Should not happen as dupli group are created automatically */ continue; } - gameobj->SetBlenderGroupObject(blgroupobj); - - if ((blenderobj->lay & group->layer)==0) - { - // object is not visible in the 3D view, will not be instantiated + if ((blenderobj->lay & group->layer) == 0) { + // Object is not visible in the 3D view, will not be instantiated. continue; } m_groupGameObjects.insert(gameobj); } - set::iterator oit; - for (oit=m_groupGameObjects.begin(); oit != m_groupGameObjects.end(); oit++) - { - gameobj = (KX_GameObject*)(*oit); - + for (KX_GameObject *gameobj : m_groupGameObjects) { KX_GameObject *parent = gameobj->GetParent(); - if (parent != NULL) - { - // this object is not a top parent. Either it is the child of another - // object in the group and it will be added automatically when the parent - // is added. Or it is the child of an object outside the group and the group - // is inconsistent, skip it anyway + if (parent != nullptr) { + /* This object is not a top parent. Either it is the child of another + * object in the group and it will be added automatically when the parent + * is added. Or it is the child of an object outside the group and the group + * is inconsistent, skip it anyway. + */ continue; } - replica = (KX_GameObject*) AddNodeReplicaObject(NULL,gameobj); - // add to 'rootparent' list (this is the list of top hierarchy objects, updated each frame) - m_parentlist->Add(replica->AddRef()); - - // recurse replication into children nodes - NodeList& children = gameobj->GetSGNode()->GetSGChildren(); - - replica->GetSGNode()->ClearSGChildren(); - for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) - { - SG_Node* orgnode = (*childit); - SG_Node* childreplicanode = orgnode->GetSGReplica(); - if (childreplicanode) - replica->GetSGNode()->AddChild(childreplicanode); + KX_GameObject *replica = AddNodeReplicaObject(nullptr, gameobj); + // Add to 'rootparent' list (this is the list of top hierarchy objects, updated each frame). + m_parentlist->Add(CM_AddRef(replica)); + + // Recurse replication into children nodes. + const NodeList& children = gameobj->GetNode()->GetChildren(); + + replica->GetNode()->ClearSGChildren(); + for (SG_Node *orgnode : children) { + SG_Node *childreplicanode = orgnode->GetReplica(); + if (childreplicanode) { + replica->GetNode()->AddChild(childreplicanode); + } } - // don't replicate logic now: we assume that the objects in the group can have - // logic relationship, even outside parent relationship - // In order to match 3D view, the position of groupobj is used as a - // transformation matrix instead of the new position. This means that - // the group reference point is 0,0,0 - - // get the rootnode's scale - MT_Vector3 newscale = groupobj->NodeGetWorldScaling(); - // set the replica's relative scale with the rootnode's scale + /* Don't replicate logic now: we assume that the objects in the group can have + * logic relationship, even outside parent relationship + * In order to match 3D view, the position of groupobj is used as a + * transformation matrix instead of the new position. This means that + * the group reference point is 0,0,0. + */ + + // Get the rootnode's scale. + const mt::vec3& newscale = groupobj->NodeGetWorldScaling(); + // Set the replica's relative scale with the rootnode's scale. replica->NodeSetRelativeScale(newscale); - MT_Point3 offset(group->dupli_ofs); - MT_Point3 newpos = groupobj->NodeGetWorldPosition() + - newscale*(groupobj->NodeGetWorldOrientation() * (gameobj->NodeGetWorldPosition()-offset)); + const mt::vec3 offset(group->dupli_ofs); + const mt::vec3 newpos = groupobj->NodeGetWorldPosition() + + newscale * (groupobj->NodeGetWorldOrientation() * (gameobj->NodeGetWorldPosition() - offset)); replica->NodeSetLocalPosition(newpos); - // set the orientation after position for softbody! - MT_Matrix3x3 newori = groupobj->NodeGetWorldOrientation() * gameobj->NodeGetWorldOrientation(); + // Set the orientation after position for softbody. + const mt::mat3 newori = groupobj->NodeGetWorldOrientation() * gameobj->NodeGetWorldOrientation(); replica->NodeSetLocalOrientation(newori); - // update scenegraph for entire tree of children - replica->GetSGNode()->UpdateWorldData(0); - replica->GetSGNode()->SetBBox(gameobj->GetSGNode()->BBox()); - replica->GetSGNode()->SetRadius(gameobj->GetSGNode()->Radius()); - // we can now add the graphic controller to the physic engine + // Update scenegraph for entire tree of children. + replica->GetNode()->UpdateWorldData(); + // We can now add the graphic controller to the physic engine. replica->ActivateGraphicController(true); - // done with replica + // Done with replica. replica->Release(); } - // the logic must be replicated first because we need - // the new logic bricks before relinking - vector::iterator git; - for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) - { - (*git)->ReParentLogic(); + // Do the linking of member objects to group object for every objects. + for (KX_GameObject *gameobj : m_logicHierarchicalGameObjects) { + /* Set references for dupli-group + * groupobj holds a list of all objects, that belongs to this group. */ + groupobj->AddInstanceObjects(gameobj); + // Every object gets the reference to its dupli-group object. + gameobj->SetDupliGroupObject(groupobj); } - // relink any pointers as necessary, sort of a temporary solution - for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) - { - // this will also relink the actuator to objects within the hierarchy - (*git)->Relink(&m_map_gameobject_to_replica); - // add the object in the layer of the parent - (*git)->SetLayer(groupobj->GetLayer()); + /* The logic must be replicated first because we need + * the new logic bricks before relinking. */ + for (KX_GameObject *gameobj : m_logicHierarchicalGameObjects) { + gameobj->ReParentLogic(); } - // replicate crosslinks etc. between logic bricks - for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) - { - ReplicateLogic((*git)); + // Relink any pointers as necessary, sort of a temporary solution. + for (KX_GameObject *gameobj : m_logicHierarchicalGameObjects) { + // This will also relink the actuator to objects within the hierarchy. + gameobj->Relink(m_map_gameobject_to_replica); + gameobj->AddMeshUser(); + // Always make sure that the bounding box is valid. + gameobj->UpdateBounds(true); + // Add the object in the layer of the parent. + gameobj->SetLayer(groupobj->GetLayer()); } - // now look if object in the hierarchy have dupli group and recurse - for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) - { - /* Replicate all constraints. */ - if ((*git)->GetPhysicsController()) { - (*git)->GetPhysicsController()->ReplicateConstraints((*git), m_logicHierarchicalGameObjects); - (*git)->ClearConstraints(); - } - - if ((*git) != groupobj && (*git)->IsDupliGroup()) - // can't instantiate group immediately as it destroys m_logicHierarchicalGameObjects - duplilist.push_back((*git)); + // Replicate crosslinks etc. between logic bricks. + for (KX_GameObject *gameobj : m_logicHierarchicalGameObjects) { + ReplicateLogic(gameobj); + } - if ((*git)->GetBlenderGroupObject() == blgroupobj) { - // set references for dupli-group - // groupobj holds a list of all objects, that belongs to this group - groupobj->AddInstanceObjects((*git)); + // Now look if object in the hierarchy have dupli group and recurse. + for (KX_GameObject *gameobj : m_logicHierarchicalGameObjects) { + // Replicate all constraints. + gameobj->ReplicateConstraints(m_physicsEnvironment, m_logicHierarchicalGameObjects); - // every object gets the reference to its dupli-group object - (*git)->SetDupliGroupObject(groupobj); + if (gameobj != groupobj && gameobj->IsDupliGroup()) { + // Can't instantiate group immediately as it destroys m_logicHierarchicalGameObjects. + duplilist.push_back(gameobj); } } - for (git = duplilist.begin(); !(git == duplilist.end()); ++git) - { - DupliGroupRecurse((*git), level+1); + for (KX_GameObject *gameobj : duplilist) { + DupliGroupRecurse(gameobj, level + 1); } } - -SCA_IObject* KX_Scene::AddReplicaObject(class CValue* originalobject, - class CValue* referenceobject, - int lifespan) +bool KX_Scene::IsObjectInGroup(KX_GameObject *gameobj) const { + return (m_groupGameObjects.empty() || m_groupGameObjects.find(gameobj) != m_groupGameObjects.end()); +} +KX_GameObject *KX_Scene::AddReplicaObject(KX_GameObject *originalobj, KX_GameObject *referenceobj, float lifespan) +{ m_logicHierarchicalGameObjects.clear(); m_map_gameobject_to_replica.clear(); m_groupGameObjects.clear(); - KX_GameObject* originalobj = (KX_GameObject*) originalobject; - KX_GameObject* referenceobj = (KX_GameObject*) referenceobject; - m_ueberExecutionPriority++; - // lets create a replica - KX_GameObject* replica = (KX_GameObject*) AddNodeReplicaObject(NULL,originalobj); - - // add a timebomb to this object - // lifespan of zero means 'this object lives forever' - if (lifespan > 0) - { - // for now, convert between so called frames and realtime - m_tempObjectList->Add(replica->AddRef()); - // this convert the life from frames to sort-of seconds, hard coded 0.02 that assumes we have 50 frames per second - // if you change this value, make sure you change it in KX_GameObject::pyattr_get_life property too - CValue *fval = new CFloatValue(lifespan*0.02f); - replica->SetProperty("::timebomb",fval); + // Lets create a replica. + KX_GameObject *replica = AddNodeReplicaObject(nullptr, originalobj); + + /* Add a timebomb to this object + * lifespan of zero means 'this object lives forever'. */ + if (lifespan > 0.0f) { + // For now, convert between so called frames and realtime. + m_tempObjectList.push_back(replica); + /* This convert the life from frames to sort-of seconds, hard coded 0.02 that assumes we have 50 frames per second + * if you change this value, make sure you change it in KX_GameObject::pyattr_get_life property too. */ + EXP_Value *fval = new EXP_FloatValue(lifespan * 0.02f); + replica->SetProperty("::timebomb", fval); fval->Release(); } - // add to 'rootparent' list (this is the list of top hierarchy objects, updated each frame) - m_parentlist->Add(replica->AddRef()); + // Add to 'rootparent' list (this is the list of top hierarchy objects, updated each frame). + m_parentlist->Add(CM_AddRef(replica)); - // recurse replication into children nodes + // Recurse replication into children nodes. - NodeList& children = originalobj->GetSGNode()->GetSGChildren(); + const NodeList& children = originalobj->GetNode()->GetChildren(); - replica->GetSGNode()->ClearSGChildren(); - for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) - { - SG_Node* orgnode = (*childit); - SG_Node* childreplicanode = orgnode->GetSGReplica(); - if (childreplicanode) - replica->GetSGNode()->AddChild(childreplicanode); + replica->GetNode()->ClearSGChildren(); + for (SG_Node *orgnode : children) { + SG_Node *childreplicanode = orgnode->GetReplica(); + if (childreplicanode) { + replica->GetNode()->AddChild(childreplicanode); + } } if (referenceobj) { - // At this stage all the objects in the hierarchy have been duplicated, - // we can update the scenegraph, we need it for the duplication of logic - MT_Point3 newpos = referenceobj->NodeGetWorldPosition(); + /* At this stage all the objects in the hierarchy have been duplicated, + * we can update the scenegraph, we need it for the duplication of logic. */ + const mt::vec3& newpos = referenceobj->NodeGetWorldPosition(); replica->NodeSetLocalPosition(newpos); - MT_Matrix3x3 newori = referenceobj->NodeGetWorldOrientation(); + const mt::mat3& newori = referenceobj->NodeGetWorldOrientation(); replica->NodeSetLocalOrientation(newori); - // get the rootnode's scale - MT_Vector3 newscale = referenceobj->GetSGNode()->GetRootSGParent()->GetLocalScale(); - // set the replica's relative scale with the rootnode's scale + // Get the rootnode's scale. + const mt::vec3& newscale = referenceobj->GetNode()->GetRootSGParent()->GetLocalScale(); + // Set the replica's relative scale with the rootnode's scale. replica->NodeSetRelativeScale(newscale); } - replica->GetSGNode()->UpdateWorldData(0); - replica->GetSGNode()->SetBBox(originalobj->GetSGNode()->BBox()); - replica->GetSGNode()->SetRadius(originalobj->GetSGNode()->Radius()); - // the size is correct, we can add the graphic controller to the physic engine + replica->GetNode()->UpdateWorldData(); + // The size is correct, we can add the graphic controller to the physic engine. replica->ActivateGraphicController(true); - // now replicate logic - vector::iterator git; - for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) - { - (*git)->ReParentLogic(); + // Now replicate logic. + for (KX_GameObject *gameobj : m_logicHierarchicalGameObjects) { + gameobj->ReParentLogic(); } - // relink any pointers as necessary, sort of a temporary solution - for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) - { - // this will also relink the actuators in the hierarchy - (*git)->Relink(&m_map_gameobject_to_replica); + // Relink any pointers as necessary, sort of a temporary solution. + for (KX_GameObject *gameobj : m_logicHierarchicalGameObjects) { + // This will also relink the actuators in the hierarchy. + gameobj->Relink(m_map_gameobject_to_replica); + gameobj->AddMeshUser(); + // Always make sure that the bounding box is valid. + gameobj->UpdateBounds(true); + if (referenceobj) { - // add the object in the layer of the reference object - (*git)->SetLayer(referenceobj->GetLayer()); + // Add the object in the layer of the reference object. + gameobj->SetLayer(referenceobj->GetLayer()); } else { // We don't know what layer set, so we set all visible layers in the blender scene. - (*git)->SetLayer(m_blenderScene->lay); + gameobj->SetLayer(m_blenderScene->lay); } } - // replicate crosslinks etc. between logic bricks - for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) - { - ReplicateLogic((*git)); + // Replicate crosslinks etc. between logic bricks. + for (KX_GameObject *gameobj : m_logicHierarchicalGameObjects) { + ReplicateLogic(gameobj); } - // check if there are objects with dupligroup in the hierarchy - vector duplilist; - for (git = m_logicHierarchicalGameObjects.begin();!(git==m_logicHierarchicalGameObjects.end());++git) - { - if ((*git)->IsDupliGroup()) - { - // separate list as m_logicHierarchicalGameObjects is also used by DupliGroupRecurse() - duplilist.push_back(*git); + // Check if there are objects with dupligroup in the hierarchy. + std::vector duplilist; + for (KX_GameObject *gameobj : m_logicHierarchicalGameObjects) { + if (gameobj->IsDupliGroup()) { + // Separate list as m_logicHierarchicalGameObjects is also used by DupliGroupRecurse(). + duplilist.push_back(gameobj); } } - for (git = duplilist.begin();!(git==duplilist.end());++git) - { - DupliGroupRecurse(*git, 0); + for (KX_GameObject *gameobj : duplilist) { + DupliGroupRecurse(gameobj, 0); } - // don't release replica here because we are returning it, not done with it... + + // Don't release replica here because we are returning it, not done with it... return replica; } - - -void KX_Scene::RemoveObject(class CValue* gameobj) +void KX_Scene::RemoveObject(KX_GameObject *gameobj) { - KX_GameObject* newobj = (KX_GameObject*) gameobj; + // Disconnect child from parent. + SG_Node *node = gameobj->GetNode(); - // disconnect child from parent - SG_Node* node = newobj->GetSGNode(); - - if (node) - { + if (node) { node->DisconnectFromParent(); - // recursively destruct + // Recursively destruct. node->Destruct(); } - //no need to do that: the object is destroyed and memory released - //newobj->SetSGNode(0); } -void KX_Scene::RemoveDupliGroup(class CValue *gameobj) +void KX_Scene::RemoveDupliGroup(KX_GameObject *gameobj) { - KX_GameObject *newobj = (KX_GameObject *) gameobj; - - if (newobj->IsDupliGroup()) { - for (int i = 0; i < newobj->GetInstanceObjects()->GetCount(); i++) { - CValue *obj = newobj->GetInstanceObjects()->GetValue(i); - DelayedRemoveObject(obj); + if (gameobj->GetInstanceObjects()) { + for (KX_GameObject *instance : gameobj->GetInstanceObjects()) { + DelayedRemoveObject(instance); } } } -void KX_Scene::DelayedRemoveObject(class CValue* gameobj) +void KX_Scene::DelayedRemoveObject(KX_GameObject *gameobj) { RemoveDupliGroup(gameobj); - if (!m_euthanasyobjects->SearchValue(gameobj)) - { - m_euthanasyobjects->Add(gameobj->AddRef()); - } + CM_ListAddIfNotFound(m_euthanasyobjects, gameobj); } -int KX_Scene::NewRemoveObject(class CValue* gameobj) +void KX_Scene::RemoveEuthanasyObjects() { - int ret; - KX_GameObject* newobj = (KX_GameObject*) gameobj; + /* Don't remove the objects from the euthanasy list here as the child objects of a deleted + * parent object are destructed directly from the sgnode in the same time the parent + * object is destructed. These child objects must be removed automatically from the + * euthanasy list to avoid double deletion in case the user ask to delete the child object + * explicitly. NewRemoveObject is the place to do it. + */ + while (!m_euthanasyobjects.empty()) { + RemoveObject(m_euthanasyobjects.front()); + } +} - /* remove property from debug list */ - RemoveObjectDebugProperties(newobj); +bool KX_Scene::NewRemoveObject(KX_GameObject *gameobj) +{ + // Remove property from debug list. + RemoveObjectDebugProperties(gameobj); /* Invalidate the python reference, since the object may exist in script lists * its possible that it wont be automatically invalidated, so do it manually here, * * if for some reason the object is added back into the scene python can always get a new Proxy */ - newobj->InvalidateProxy(); - - // keep the blender->game object association up to date - // note that all the replicas of an object will have the same - // blender object, that's why we need to check the game object - // as only the deletion of the original object must be recorded - m_logicmgr->UnregisterGameObj(newobj->GetBlenderObject(), gameobj); + gameobj->InvalidateProxy(); - //todo: look at this - //GetPhysicsEnvironment()->RemovePhysicsController(gameobj->getPhysicsController()); + /* Keep the blender->game object association up to date + * note that all the replicas of an object will have the same + * blender object, that's why we need to check the game object + * as only the deletion of the original object must be recorded. + */ + if (gameobj->GetBlenderObject()) { + // In some case the game object can contains a nullptr blender object e.g default camera. + m_logicmgr->UnregisterGameObj(gameobj->GetBlenderObject(), gameobj); + } - // remove all sensors/controllers/actuators from logicsystem... + // Remove all sensors/controllers/actuators from logicsystem. - SCA_SensorList& sensors = newobj->GetSensors(); - for (SCA_SensorList::iterator its = sensors.begin(); - !(its==sensors.end());its++) - { - m_logicmgr->RemoveSensor(*its); + SCA_SensorList& sensors = gameobj->GetSensors(); + for (SCA_ISensor *sensor : sensors) { + m_logicmgr->RemoveSensor(sensor); } - SCA_ControllerList& controllers = newobj->GetControllers(); - for (SCA_ControllerList::iterator itc = controllers.begin(); - !(itc==controllers.end());itc++) - { - m_logicmgr->RemoveController(*itc); - (*itc)->ReParent(NULL); + SCA_ControllerList& controllers = gameobj->GetControllers(); + for (SCA_IController *controller : controllers) { + m_logicmgr->RemoveController(controller); + controller->ReParent(nullptr); } - SCA_ActuatorList& actuators = newobj->GetActuators(); - for (SCA_ActuatorList::iterator ita = actuators.begin(); - !(ita==actuators.end());ita++) - { - m_logicmgr->RemoveActuator(*ita); + SCA_ActuatorList& actuators = gameobj->GetActuators(); + for (SCA_IActuator *actuator : actuators) { + m_logicmgr->RemoveActuator(actuator); } - // the sensors/controllers/actuators must also be released, this is done in ~SCA_IObject - - // now remove the timer properties from the time manager - int numprops = newobj->GetPropertyCount(); + // The sensors/controllers/actuators must also be released, this is done in ~SCA_IObject. - for (int i = 0; i < numprops; i++) - { - CValue* propval = newobj->GetProperty(i); - if (propval->GetProperty("timer")) - { + // Now remove the timer properties from the time manager. + for (unsigned short i = 0, numprops = gameobj->GetPropertyCount(); i < numprops; ++i) { + EXP_Value *propval = gameobj->GetProperty(i); + if (propval->GetProperty("timer")) { m_timemgr->RemoveTimeProperty(propval); } } - // if the object is the dupligroup proxy, you have to cleanup all m_pDupliGroupObject's in all - // instances refering to this group - if (newobj->GetInstanceObjects()) { - for (int i = 0; i < newobj->GetInstanceObjects()->GetCount(); i++) { - KX_GameObject* instance = (KX_GameObject*)newobj->GetInstanceObjects()->GetValue(i); + /* If the object is the dupligroup proxy, you have to cleanup all m_dupliGroupObject's in all + * instances refering to this group. */ + if (gameobj->GetInstanceObjects()) { + for (KX_GameObject *instance : gameobj->GetInstanceObjects()) { instance->RemoveDupliGroupObject(); } } - // if this object was part of a group, make sure to remove it from that group's instance list - KX_GameObject* group = newobj->GetDupliGroupObject(); - if (group) - group->RemoveInstanceObject(newobj); - - newobj->RemoveMeshes(); - - switch (newobj->GetGameObjectType()) { - case SCA_IObject::OBJ_CAMERA: - m_cameras.remove((KX_Camera *)newobj); - break; - case SCA_IObject::OBJ_TEXT: - m_fonts.remove((KX_FontObject *)newobj); - break; + // If this object was part of a group, make sure to remove it from that group's instance list. + KX_GameObject *group = gameobj->GetDupliGroupObject(); + if (group) { + group->RemoveInstanceObject(gameobj); } - ret = 1; - if (newobj->GetGameObjectType()==SCA_IObject::OBJ_LIGHT && m_lightlist->RemoveValue(newobj)) - ret = newobj->Release(); - if (m_objectlist->RemoveValue(newobj)) - ret = newobj->Release(); - if (m_tempObjectList->RemoveValue(newobj)) - ret = newobj->Release(); - if (m_parentlist->RemoveValue(newobj)) - ret = newobj->Release(); - if (m_inactivelist->RemoveValue(newobj)) - ret = newobj->Release(); - if (m_euthanasyobjects->RemoveValue(newobj)) - ret = newobj->Release(); - if (m_animatedlist->RemoveValue(newobj)) - ret = newobj->Release(); - - /* Warning 'newobj' maye be freed now, only compare, don't access */ - - - if (newobj == m_active_camera) - { - //no AddRef done on m_active_camera so no Release - //m_active_camera->Release(); - m_active_camera = NULL; - } - - /* currently does nothing, keep in case we need to Unregister something */ -#if 0 - if (m_sceneConverter) - m_sceneConverter->UnregisterGameObject(newobj); -#endif - - // return value will be 0 if the object is actually deleted (all reference gone) - - return ret; -} - - - -void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj, bool use_gfx, bool use_phys) -{ - KX_GameObject* gameobj = static_cast(obj); - RAS_MeshObject* mesh = static_cast(meshobj); - - if (!gameobj) { - std::cout << "KX_Scene::ReplaceMesh Warning: invalid object, doing nothing" << std::endl; - return; + if (m_obstacleSimulation) { + m_obstacleSimulation->DestroyObstacleForObj(gameobj); } - if (use_gfx && mesh != NULL) - { - gameobj->RemoveMeshes(); - gameobj->AddMesh(mesh); + m_componentManager.UnregisterObject(gameobj); - if (gameobj->m_isDeformable) - { - BL_DeformableGameObject* newobj = static_cast( gameobj ); + gameobj->RemoveMeshes(); - if (newobj->GetDeformer()) - { - delete newobj->GetDeformer(); - newobj->SetDeformer(NULL); - } + m_rendererManager->InvalidateViewpoint(gameobj); - if (mesh->GetMesh()) - { - // we must create a new deformer but which one? - KX_GameObject* parentobj = newobj->GetParent(); - // this always return the original game object (also for replicate) - Object* blendobj = newobj->GetBlenderObject(); - // object that owns the new mesh - Object* oldblendobj = static_cast(m_logicmgr->FindBlendObjByGameMeshName(mesh->GetName())); - Mesh* blendmesh = mesh->GetMesh(); - - bool bHasModifier = BL_ModifierDeformer::HasCompatibleDeformer(blendobj); - bool bHasShapeKey = blendmesh->key != NULL && blendmesh->key->type==KEY_RELATIVE; - bool bHasDvert = blendmesh->dvert != NULL; - bool bHasArmature = - BL_ModifierDeformer::HasArmatureDeformer(blendobj) && - parentobj && // current parent is armature - parentobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE && - oldblendobj && // needed for mesh deform - blendobj->parent && // original object had armature (not sure this test is needed) - blendobj->parent->type == OB_ARMATURE && - blendmesh->dvert!=NULL; // mesh has vertex group -#ifdef WITH_BULLET - bool bHasSoftBody = (!parentobj && (blendobj->gameflag & OB_SOFT_BODY)); -#endif + bool ret = true; + if (m_lightlist->RemoveValue(gameobj)) { + ret = (gameobj->Release() != nullptr); + } + if (m_objectlist->RemoveValue(gameobj)) { + ret = (gameobj->Release() != nullptr); + } + if (m_parentlist->RemoveValue(gameobj)) { + ret = (gameobj->Release() != nullptr); + } + if (m_inactivelist->RemoveValue(gameobj)) { + ret = (gameobj->Release() != nullptr); + } + if (m_fontlist->RemoveValue(gameobj)) { + ret = (gameobj->Release() != nullptr); + } + if (m_cameralist->RemoveValue(gameobj)) { + ret = (gameobj->Release() != nullptr); + } - if (oldblendobj==NULL) { - if (bHasModifier || bHasShapeKey || bHasDvert || bHasArmature) { - std::cout << "warning: ReplaceMesh() new mesh is not used in an object from the current scene, you will get incorrect behavior" << std::endl; - bHasShapeKey= bHasDvert= bHasArmature=bHasModifier= false; - } - } + // WARNING: 'gameobj' maybe be freed now, only compare, don't access. + CM_ListRemoveIfFound(m_animatedlist, gameobj); + CM_ListRemoveIfFound(m_euthanasyobjects, gameobj); + CM_ListRemoveIfFound(m_tempObjectList, gameobj); - if (bHasModifier) - { - BL_ModifierDeformer* modifierDeformer; - if (bHasShapeKey || bHasArmature) - { - modifierDeformer = new BL_ModifierDeformer( - newobj, - m_blenderScene, - oldblendobj, blendobj, - mesh, - true, - static_cast( parentobj->AddRef() ) - ); - modifierDeformer->LoadShapeDrivers(parentobj); - } - else - { - modifierDeformer = new BL_ModifierDeformer( - newobj, - m_blenderScene, - oldblendobj, blendobj, - mesh, - false, - NULL - ); - } - newobj->SetDeformer(modifierDeformer); - } - else if (bHasShapeKey) { - BL_ShapeDeformer* shapeDeformer; - if (bHasArmature) - { - shapeDeformer = new BL_ShapeDeformer( - newobj, - oldblendobj, blendobj, - mesh, - true, - true, - static_cast( parentobj->AddRef() ) - ); - shapeDeformer->LoadShapeDrivers(parentobj); - } - else - { - shapeDeformer = new BL_ShapeDeformer( - newobj, - oldblendobj, blendobj, - mesh, - false, - true, - NULL - ); - } - newobj->SetDeformer( shapeDeformer); - } - else if (bHasArmature) - { - BL_SkinDeformer* skinDeformer = new BL_SkinDeformer( - newobj, - oldblendobj, blendobj, - mesh, - true, - true, - static_cast( parentobj->AddRef() ) - ); - newobj->SetDeformer(skinDeformer); - } - else if (bHasDvert) - { - BL_MeshDeformer* meshdeformer = new BL_MeshDeformer( - newobj, oldblendobj, mesh - ); - newobj->SetDeformer(meshdeformer); - } -#ifdef WITH_BULLET - else if (bHasSoftBody) - { - KX_SoftBodyDeformer *softdeformer = new KX_SoftBodyDeformer(mesh, newobj); - newobj->SetDeformer(softdeformer); - } -#endif - } + if (gameobj == m_activeCamera) { + m_activeCamera = nullptr; } - gameobj->AddMeshUser(); + if (gameobj == m_overrideCullingCamera) { + m_overrideCullingCamera = nullptr; } - if (use_phys) { /* update the new assigned mesh with the physics mesh */ - if (gameobj->GetPhysicsController()) - gameobj->GetPhysicsController()->ReinstancePhysicsShape(NULL, use_gfx?NULL:mesh); - } + // Return value will be nullptr if the object is actually deleted (all reference gone) + return ret; } -/* Font Object routines */ -void KX_Scene::AddFont(KX_FontObject* font) +KX_Camera *KX_Scene::GetActiveCamera() { - if (!FindFont(font)) - m_fonts.push_back(font); + // nullptr if not defined. + return m_activeCamera; } -KX_FontObject* KX_Scene::FindFont(KX_FontObject* font) +void KX_Scene::SetActiveCamera(KX_Camera *cam) { - list::iterator it = m_fonts.begin(); - - while ((it != m_fonts.end()) && ((*it) != font)) - { - ++it; - } - - return ((it == m_fonts.end()) ? NULL : (*it)); + m_activeCamera = cam; } - -/* Camera Object routines */ -KX_Camera* KX_Scene::FindCamera(KX_Camera* cam) +KX_Camera *KX_Scene::GetOverrideCullingCamera() const { - list::iterator it = m_cameras.begin(); - - while ((it != m_cameras.end()) && ((*it) != cam)) { - it++; - } - - return ((it == m_cameras.end()) ? NULL : (*it)); + return m_overrideCullingCamera; } - -KX_Camera* KX_Scene::FindCamera(STR_String& name) +void KX_Scene::SetOverrideCullingCamera(KX_Camera *cam) { - list::iterator it = m_cameras.begin(); - - while ((it != m_cameras.end()) && ((*it)->GetName() != name)) { - it++; - } - - return ((it == m_cameras.end()) ? NULL : (*it)); + m_overrideCullingCamera = cam; } -void KX_Scene::AddCamera(KX_Camera* cam) +void KX_Scene::SetCameraOnTop(KX_Camera *cam) { - if (!FindCamera(cam)) - m_cameras.push_back(cam); + // No release and addref just change camera place. + m_cameralist->RemoveValue(cam); + m_cameralist->Add(cam); } - -KX_Camera* KX_Scene::GetActiveCamera() +void KX_Scene::PhysicsCullingCallback(KX_ClientObjectInfo *objectInfo, void *cullingInfo) { - // NULL if not defined - return m_active_camera; -} + CullingInfo *info = static_cast(cullingInfo); + KX_GameObject *gameobj = objectInfo->m_gameobject; - -void KX_Scene::SetActiveCamera(KX_Camera* cam) -{ - // only set if the cam is in the active list? Or add it otherwise? - if (!FindCamera(cam)) { - AddCamera(cam); - if (cam) std::cout << "Added cam " << cam->GetName() << std::endl; + if (!gameobj->Renderable(info->m_layer)) { + return; } - m_active_camera = cam; + // Make object visible. + gameobj->GetCullingNode().SetCulled(false); + info->m_objects.push_back(gameobj); } -void KX_Scene::SetCameraOnTop(KX_Camera* cam) +std::vector KX_Scene::CalculateVisibleMeshes(KX_Camera *cam, int layer) { - if (!FindCamera(cam)) { - // adding is always done at the back, so that's all that needs to be done - AddCamera(cam); - if (cam) std::cout << "Added cam " << cam->GetName() << std::endl; - } else { - m_cameras.remove(cam); - m_cameras.push_back(cam); + std::vector objects; + if (!cam->GetFrustumCulling()) { + for (KX_GameObject *gameobj : m_objectlist) { + gameobj->GetCullingNode().SetCulled(false); + objects.push_back(gameobj); + } + return objects; } + + return CalculateVisibleMeshes(cam->GetFrustum(), layer); } -void KX_Scene::MarkVisible(SG_Tree *node, RAS_IRasterizer* rasty, KX_Camera* cam, int layer) +std::vector KX_Scene::CalculateVisibleMeshes(const SG_Frustum& frustum, int layer) { - int intersect = KX_Camera::INTERSECT; - KX_GameObject *gameobj = node->Client()?(KX_GameObject*) node->Client()->GetSGClientObject():NULL; - bool visible = (gameobj && gameobj->GetVisible() && (!layer || (gameobj->GetLayer() & layer))); - bool dotest = visible || node->Left() || node->Right(); + std::vector objects; + m_boundingBoxManager->Update(false); - /* If the camera is inside the box, assume intersect. */ - if (dotest && !node->inside( cam->NodeGetWorldPosition())) - { - MT_Scalar radius = node->Radius(); - MT_Point3 center = node->Center(); + bool dbvt_culling = false; + if (m_dbvtCulling) { + for (KX_GameObject *gameobj : m_objectlist) { + /* Reset KX_GameObject m_culled to true before doing culling + * since DBVT culling will only set it to false. + */ + gameobj->GetCullingNode().SetCulled(true); + // Update the object bounding volume box. + gameobj->UpdateBounds(false); + } - intersect = cam->SphereInsideFrustum(center, radius); + // Test culling through Bullet, get the clip planes. + const std::array& planes = frustum.GetPlanes(); + const mt::mat4& matrix = frustum.GetMatrix(); + const int *viewport = KX_GetActiveEngine()->GetCanvas()->GetViewPort(); + CullingInfo info(layer, objects); - if (intersect == KX_Camera::INTERSECT) - { - MT_Point3 box[8]; - node->get(box); - intersect = cam->BoxInsideFrustum(box); - } + dbvt_culling = m_physicsEnvironment->CullingTest(PhysicsCullingCallback, &info, planes, m_dbvtOcclusionRes, viewport, matrix); } - switch (intersect) - { - case KX_Camera::OUTSIDE: - MarkSubTreeVisible(node, rasty, false, cam); - break; - case KX_Camera::INTERSECT: - if (gameobj) - MarkVisible(rasty, gameobj, cam, layer); - if (node->Left()) - MarkVisible(node->Left(), rasty, cam, layer); - if (node->Right()) - MarkVisible(node->Right(), rasty, cam, layer); - break; - case KX_Camera::INSIDE: - MarkSubTreeVisible(node, rasty, true, cam, layer); - break; + if (!dbvt_culling) { + KX_CullingHandler handler(m_objectlist, frustum, layer); + objects = handler.Process(); } -} - -void KX_Scene::MarkSubTreeVisible(SG_Tree *node, RAS_IRasterizer* rasty, bool visible, KX_Camera* cam, int layer) -{ - if (node->Client()) - { - KX_GameObject *gameobj = (KX_GameObject*) node->Client()->GetSGClientObject(); - if (gameobj->GetVisible()) - { - if (visible) - { - int nummeshes = gameobj->GetMeshCount(); - // this adds the vertices to the display list - for (int m=0;mGetMesh(m))->SchedulePolygons(rasty->GetDrawingMode()); - } + m_boundingBoxManager->ClearModified(); - gameobj->SetCulled(!visible); - gameobj->UpdateBuckets(false); - } - } - if (node->Left()) - MarkSubTreeVisible(node->Left(), rasty, visible, cam, layer); - if (node->Right()) - MarkSubTreeVisible(node->Right(), rasty, visible, cam, layer); + return objects; } -void KX_Scene::MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj,KX_Camera* cam,int layer) +RAS_DebugDraw& KX_Scene::GetDebugDraw() { - // User (Python/Actuator) has forced object invisible... - if (!gameobj->GetSGNode() || !gameobj->GetVisible()) - return; - - // Shadow lamp layers - if (layer && !(gameobj->GetLayer() & layer)) { - gameobj->SetCulled(true); - gameobj->UpdateBuckets(false); - return; - } + return m_debugDraw; +} - // If Frustum culling is off, the object is always visible. - bool vis = !cam->GetFrustumCulling(); +void KX_Scene::DrawDebug(const std::vector& objects, + KX_DebugOption showBoundingBox, KX_DebugOption showArmatures) +{ + if (showBoundingBox != KX_DebugOption::DISABLE) { + for (KX_GameObject *gameobj : objects) { + const mt::vec3& scale = gameobj->NodeGetWorldScaling(); + const mt::vec3& position = gameobj->NodeGetWorldPosition(); + const mt::mat3& orientation = gameobj->NodeGetWorldOrientation(); + const SG_BBox& box = gameobj->GetCullingNode().GetAabb(); + const mt::vec3& center = box.GetCenter(); - // If the camera is inside this node, then the object is visible. - if (!vis) - { - vis = gameobj->GetSGNode()->inside( cam->GetCameraLocation() ); - } + m_debugDraw.DrawAabb(position, orientation, box.GetMin() * scale, box.GetMax() * scale, + mt::vec4(1.0f, 0.0f, 1.0f, 1.0f)); - // Test the object's bound sphere against the view frustum. - if (!vis) - { - MT_Vector3 scale = gameobj->GetSGNode()->GetWorldScaling(); - MT_Scalar radius = fabs(scale[scale.closestAxis()] * gameobj->GetSGNode()->Radius()); - switch (cam->SphereInsideFrustum(gameobj->NodeGetWorldPosition(), radius)) - { - case KX_Camera::INSIDE: - vis = true; - break; - case KX_Camera::OUTSIDE: - vis = false; - break; - case KX_Camera::INTERSECT: - // Test the object's bound box against the view frustum. - MT_Point3 box[8]; - gameobj->GetSGNode()->getBBox(box); - vis = cam->BoxInsideFrustum(box) != KX_Camera::OUTSIDE; - break; + static const mt::vec3 axes[] = {mt::axisX3, mt::axisY3, mt::axisZ3}; + static const mt::vec4 colors[] = {mt::vec4(1.0f, 0.0f, 0.0f, 1.0f), mt::vec4(0.0f, 1.0f, 0.0f, 1.0f), mt::vec4(0.0f, 0.0f, 1.0f, 1.0f)}; + // Render center in red, green and blue. + for (unsigned short i = 0; i < 3; ++i) { + m_debugDraw.DrawLine(orientation * (center * scale) + position, + orientation * ((center + axes[i]) * scale) + position, colors[i]); + } } } - if (vis) - { - int nummeshes = gameobj->GetMeshCount(); - - for (int m=0;mGetMesh(m))->SchedulePolygons(rasty->GetDrawingMode()); + if (showArmatures != KX_DebugOption::DISABLE) { + // The side effect of a armature is that it was added in the animated object list. + for (KX_GameObject *gameobj : m_animatedlist) { + if (gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) { + BL_ArmatureObject *armature = static_cast(gameobj); + if (showArmatures == KX_DebugOption::FORCE || armature->GetDrawDebug()) { + armature->DrawDebug(m_debugDraw); + } + } } - // Visibility/ non-visibility are marked - // elsewhere now. - gameobj->SetCulled(false); - gameobj->UpdateBuckets(false); - } else { - gameobj->SetCulled(true); - gameobj->UpdateBuckets(false); } } -void KX_Scene::PhysicsCullingCallback(KX_ClientObjectInfo *objectInfo, void* cullingInfo) +void KX_Scene::RenderDebugProperties(RAS_DebugDraw& debugDraw, int xindent, int ysize, int& xcoord, int& ycoord, unsigned short propsMax) { - KX_GameObject* gameobj = objectInfo->m_gameobject; - if (!gameobj->GetVisible()) - // ideally, invisible objects should be removed from the culling tree temporarily - return; - if (((CullingInfo*)cullingInfo)->m_layer && !(gameobj->GetLayer() & ((CullingInfo*)cullingInfo)->m_layer)) - // used for shadow: object is not in shadow layer - return; - - // make object visible - gameobj->SetCulled(false); - gameobj->UpdateBuckets(false); -} + static const mt::vec4 white(1.0f, 1.0f, 1.0f, 1.0f); -void KX_Scene::CalculateVisibleMeshes(RAS_IRasterizer* rasty,KX_Camera* cam, int layer) -{ - bool dbvt_culling = false; - if (m_dbvt_culling) - { - /* Reset KX_GameObject m_bCulled to true before doing culling - * since DBVT culling will only set it to false. - * This is similar to what RAS_BucketManager does for RAS_MeshSlot culling. - */ - for (int i = 0; i < m_objectlist->GetCount(); i++) { - KX_GameObject *gameobj = static_cast(m_objectlist->GetValue(i)); - gameobj->SetCulled(true); - } + // The 'normal' debug props. + const std::vector& debugproplist = GetDebugProperties(); - // test culling through Bullet - MT_Vector4 planes[6]; - // get the clip planes - MT_Vector4* cplanes = cam->GetNormalizedClipPlanes(); - // and convert - planes[0].setValue(cplanes[4].getValue()); // near - planes[1].setValue(cplanes[5].getValue()); // far - planes[2].setValue(cplanes[0].getValue()); // left - planes[3].setValue(cplanes[1].getValue()); // right - planes[4].setValue(cplanes[2].getValue()); // top - planes[5].setValue(cplanes[3].getValue()); // bottom - CullingInfo info(layer); - - float mvmat[16] = {0}; - cam->GetModelviewMatrix().getValue(mvmat); - float pmat[16] = {0}; - cam->GetProjectionMatrix().getValue(pmat); - - dbvt_culling = m_physicsEnvironment->CullingTest(PhysicsCullingCallback,&info,planes,5,m_dbvt_occlusion_res, - KX_GetActiveEngine()->GetCanvas()->GetViewPort(), - mvmat, pmat); + unsigned short numprop = debugproplist.size(); + if (numprop > propsMax) { + numprop = propsMax; } - if (!dbvt_culling) { - // the physics engine couldn't help us, do it the hard way - for (int i = 0; i < m_objectlist->GetCount(); i++) - { - MarkVisible(rasty, static_cast(m_objectlist->GetValue(i)), cam, layer); + + for (unsigned short i = 0; i < numprop; ++i) { + const SCA_DebugProp& debugProp = debugproplist[i]; + SCA_IObject *gameobj = debugProp.m_obj; + const std::string objname = gameobj->GetName(); + const std::string& propname = debugProp.m_name; + if (propname == "__state__") { + // reserve name for object state + unsigned int state = gameobj->GetState(); + std::string debugtxt = objname + "." + propname + " = "; + bool first = true; + for (int statenum = 1; state; state >>= 1, statenum++) { + if (state & 1) { + if (!first) { + debugtxt += ","; + } + debugtxt += std::to_string(statenum); + first = false; + } + } + debugDraw.RenderText2d(debugtxt, mt::vec2(xcoord + xindent, ycoord), white); + ycoord += ysize; + } + else { + EXP_Value *propval = gameobj->GetProperty(propname); + if (propval) { + const std::string text = propval->GetText(); + const std::string debugtxt = objname + ": '" + propname + "' = " + text; + debugDraw.RenderText2d(debugtxt, mt::vec2(xcoord + xindent, ycoord), white); + ycoord += ysize; + } } } } -// logic stuff -void KX_Scene::LogicBeginFrame(double curtime) +void KX_Scene::FlushDebugDraw(RAS_Rasterizer *rasty, RAS_ICanvas *canvas) { - // have a look at temp objects ... - int lastobj = m_tempObjectList->GetCount() - 1; + m_debugDraw.Flush(rasty, canvas); +} - for (int i = lastobj; i >= 0; i--) - { - CValue* objval = m_tempObjectList->GetValue(i); - CFloatValue* propval = (CFloatValue*) objval->GetProperty("::timebomb"); +void KX_Scene::LogicBeginFrame(double curtime, double framestep) +{ + // Have a look at temp objects. + for (KX_GameObject *gameobj : m_tempObjectList) { + EXP_FloatValue *propval = static_cast(gameobj->GetProperty("::timebomb")); - if (propval) - { - float timeleft = (float)(propval->GetNumber() - 1.0/KX_KetsjiEngine::GetTicRate()); + if (propval) { + const float timeleft = propval->GetNumber() - framestep; - if (timeleft > 0) - { + if (timeleft > 0) { propval->SetFloat(timeleft); } - else - { - DelayedRemoveObject(objval); - // remove obj + else { + // Remove obj, remove the object from tempObjectList in NewRemoveObject only. + DelayedRemoveObject(gameobj); } } - else - { - // all object is the tempObjectList should have a clock + else { + // All object is the tempObjectList should have a clock. + BLI_assert(false); } } - m_logicmgr->BeginFrame(curtime, 1.0/KX_KetsjiEngine::GetTicRate()); + m_logicmgr->BeginFrame(curtime, framestep); } -void KX_Scene::AddAnimatedObject(CValue* gameobj) +void KX_Scene::AddAnimatedObject(KX_GameObject *gameobj) { - gameobj->AddRef(); - m_animatedlist->Add(gameobj); + CM_ListAddIfNotFound(m_animatedlist, gameobj); } static void update_anim_thread_func(TaskPool *pool, void *taskdata, int UNUSED(threadid)) { - KX_GameObject *gameobj, *child, *parent; - CListValue *children; - bool needs_update; - double curtime = *(double*)BLI_task_pool_userdata(pool); + KX_Scene::AnimationPoolData *data = (KX_Scene::AnimationPoolData *)BLI_task_pool_userdata(pool); + double curtime = data->curtime; - gameobj = (KX_GameObject*)taskdata; + KX_GameObject *gameobj = (KX_GameObject *)taskdata; // Non-armature updates are fast enough, so just update them - needs_update = gameobj->GetGameObjectType() != SCA_IObject::OBJ_ARMATURE; + bool needs_update = gameobj->GetGameObjectType() != SCA_IObject::OBJ_ARMATURE; if (!needs_update) { // If we got here, we're looking to update an armature, so check its children meshes // to see if we need to bother with a more expensive pose update - children = gameobj->GetChildren(); + const std::vector children = gameobj->GetChildren(); bool has_mesh = false, has_non_mesh = false; // Check for meshes that haven't been culled - for (int j=0; jGetCount(); ++j) { - child = (KX_GameObject*)children->GetValue(j); - - if (!child->GetCulled()) { + for (KX_GameObject *child : children) { + if (!child->GetCullingNode().GetCulled()) { needs_update = true; break; } - if (child->GetMeshCount() == 0) + if (child->GetMeshList().empty()) { has_non_mesh = true; - else + } + else { has_mesh = true; + } } // If we didn't find a non-culled mesh, check to see // if we even have any meshes, and update if this // armature has only non-mesh children. - if (!needs_update && !has_mesh && has_non_mesh) + if (!needs_update && !has_mesh && has_non_mesh) { needs_update = true; - - children->Release(); + } } + // If the object is a culled armature, then we manage only the animation time and end of its animations. + gameobj->UpdateActionManager(curtime, needs_update); + if (needs_update) { - gameobj->UpdateActionManager(curtime); - children = gameobj->GetChildren(); - parent = gameobj->GetParent(); + const std::vector children = gameobj->GetChildren(); + KX_GameObject *parent = gameobj->GetParent(); // Only do deformers here if they are not parented to an armature, otherwise the armature will // handle updating its children - if (gameobj->GetDeformer() && (!parent || parent->GetGameObjectType() != SCA_IObject::OBJ_ARMATURE)) + if (gameobj->GetDeformer() && (!parent || parent->GetGameObjectType() != SCA_IObject::OBJ_ARMATURE)) { gameobj->GetDeformer()->Update(); + } - for (int j=0; jGetCount(); ++j) { - child = (KX_GameObject*)children->GetValue(j); - + for (KX_GameObject *child : children) { if (child->GetDeformer()) { child->GetDeformer()->Update(); } } - - children->Release(); } } -void KX_Scene::UpdateAnimations(double curtime) +void KX_Scene::UpdateAnimations(double curtime, bool restrict) { - TaskPool *pool = BLI_task_pool_create(KX_GetActiveEngine()->GetTaskScheduler(), &curtime); + if (restrict) { + const double animTimeStep = 1.0 / m_blenderScene->r.frs_sec; + + /* Don't update if the time step is too small and if we are not asking for redundant + * updates like for different culling passes. */ + if ((curtime - m_previousAnimTime) < animTimeStep && curtime != m_previousAnimTime) { + return; + } - for (int i=0; iGetCount(); ++i) { - BLI_task_pool_push(pool, update_anim_thread_func, m_animatedlist->GetValue(i), false, TASK_PRIORITY_LOW); + // Sanity/debug print to make sure we're actually going at the fps we want (should be close to animTimeStep) + // CM_Debug("Anim fps: " << 1.0 / (curtime - m_previousAnimTime)); + m_previousAnimTime = curtime; } - BLI_task_pool_work_and_wait(pool); - BLI_task_pool_free(pool); -} + m_animationPoolData.curtime = curtime; -void KX_Scene::LogicUpdateFrame(double curtime, bool frame) -{ - m_logicmgr->UpdateFrame(curtime, frame); + for (KX_GameObject *gameobj : m_animatedlist) { + if (!gameobj->IsActionsSuspended()) { + BLI_task_pool_push(m_animationPool, update_anim_thread_func, gameobj, false, TASK_PRIORITY_LOW); + } + } + + BLI_task_pool_work_and_wait(m_animationPool); } +void KX_Scene::LogicUpdateFrame(double curtime) +{ + m_componentManager.UpdateComponents(); + m_logicmgr->UpdateFrame(curtime); +} void KX_Scene::LogicEndFrame() { m_logicmgr->EndFrame(); - int numobj; - KX_GameObject* obj; - - while ((numobj = m_euthanasyobjects->GetCount()) > 0) - { - // remove the object from this list to make sure we will not hit it again - obj = (KX_GameObject*)m_euthanasyobjects->GetValue(numobj-1); - m_euthanasyobjects->Remove(numobj-1); - obj->Release(); - RemoveObject(obj); - } + RemoveEuthanasyObjects(); //prepare obstacle simulation for new frame - if (m_obstacleSimulation) + if (m_obstacleSimulation) { m_obstacleSimulation->UpdateObstacles(); -} - + } + for (KX_FontObject *font : m_fontlist) { + font->UpdateTextFromProperty(); + } +} -/** - * UpdateParents: SceneGraph transformation update. - */ -void KX_Scene::UpdateParents(double curtime) +void KX_Scene::UpdateParents() { - // we use the SG dynamic list - SG_Node* node; + // We use the SG dynamic list + SG_Node *node; - while ((node = SG_Node::GetNextScheduled(m_sghead)) != NULL) - { - node->UpdateWorldData(curtime); + while ((node = SG_Node::GetNextScheduled(m_sghead))) { + node->UpdateWorldData(); } - //for (int i=0; iGetCount(); i++) - //{ - // KX_GameObject* parentobj = (KX_GameObject*)GetRootParentList()->GetValue(i); - // parentobj->NodeUpdateGS(curtime); - //} - - // the list must be empty here - assert(m_sghead.Empty()); - // some nodes may be ready for reschedule, move them to schedule list for next time - while ((node = SG_Node::GetNextRescheduled(m_sghead)) != NULL) - { + // The list must be empty here + BLI_assert(m_sghead.Empty()); + // Some nodes may be ready for reschedule, move them to schedule list for next time. + while ((node = SG_Node::GetNextRescheduled(m_sghead))) { node->Schedule(m_sghead); } } - -RAS_MaterialBucket* KX_Scene::FindBucket(class RAS_IPolyMaterial* polymat, bool &bucketCreated) +void KX_Scene::RenderBuckets(const std::vector& objects, RAS_Rasterizer::DrawType drawingMode, const mt::mat3x4& cameratransform, + RAS_Rasterizer *rasty, RAS_OffScreen *offScreen) { - return m_bucketmanager->FindBucket(polymat, bucketCreated); -} - - + for (KX_GameObject *gameobj : objects) { + /* This function update all mesh slot info (e.g culling, color, matrix) from the game object. + * It's done just before the render to be sure of the object color and visibility. */ + gameobj->UpdateBuckets(); + } -void KX_Scene::RenderBuckets(const MT_Transform & cameratransform, - class RAS_IRasterizer* rasty) -{ - m_bucketmanager->Renderbuckets(cameratransform,rasty); - KX_BlenderMaterial::EndFrame(); + m_bucketmanager->Renderbuckets(drawingMode, cameratransform, rasty, offScreen); + KX_BlenderMaterial::EndFrame(rasty); } -void KX_Scene::RenderFonts() +void KX_Scene::RenderTextureRenderers(KX_TextureRendererManager::RendererCategory category, RAS_Rasterizer *rasty, + RAS_OffScreen *offScreen, KX_Camera *camera, const RAS_Rect& viewport, const RAS_Rect& area) { - list::iterator it = m_fonts.begin(); - while (it != m_fonts.end()) { - (*it)->DrawFontText(); - ++it; - } + m_rendererManager->Render(category, rasty, offScreen, camera, viewport, area); } -void KX_Scene::UpdateObjectLods(void) +void KX_Scene::UpdateObjectLods(KX_Camera *cam, const std::vector& objects) { - KX_GameObject* gameobj; - - if (!this->m_active_camera) - return; + const mt::vec3& cam_pos = cam->NodeGetWorldPosition(); + const float lodfactor = cam->GetLodDistanceFactor(); - MT_Vector3 cam_pos = this->m_active_camera->NodeGetWorldPosition(); - - for (int i = 0; i < this->GetObjectList()->GetCount(); i++) { - gameobj = (KX_GameObject*) GetObjectList()->GetValue(i); - if (!gameobj->GetCulled()) { - gameobj->UpdateLod(cam_pos); - } + for (KX_GameObject *gameobj : objects) { + gameobj->UpdateLod(this, cam_pos, lodfactor); } } @@ -1796,7 +1441,7 @@ void KX_Scene::SetLodHysteresis(bool active) m_isActivedHysteresis = active; } -bool KX_Scene::IsActivedLodHysteresis(void) +bool KX_Scene::IsActivedLodHysteresis() const { return m_isActivedHysteresis; } @@ -1806,230 +1451,188 @@ void KX_Scene::SetLodHysteresisValue(int hysteresisvalue) m_lodHysteresisValue = hysteresisvalue; } -int KX_Scene::GetLodHysteresisValue(void) +int KX_Scene::GetLodHysteresisValue() const { return m_lodHysteresisValue; } -void KX_Scene::UpdateObjectActivity(void) +void KX_Scene::UpdateObjectActivity() { - if (m_activity_culling) { - /* determine the activity criterium and set objects accordingly */ - int i=0; + if (!m_activityCulling) { + return; + } - MT_Point3 camloc = GetActiveCamera()->NodeGetWorldPosition(); //GetCameraLocation(); + std::vector > camPositions; - for (i=0;iGetCount();i++) - { - KX_GameObject* ob = (KX_GameObject*) GetObjectList()->GetValue(i); - - if (!ob->GetIgnoreActivityCulling()) { - /* Simple test: more than 10 away from the camera, count - * Manhattan distance. */ - MT_Point3 obpos = ob->NodeGetWorldPosition(); - - if ((fabsf(camloc[0] - obpos[0]) > m_activity_box_radius) || - (fabsf(camloc[1] - obpos[1]) > m_activity_box_radius) || - (fabsf(camloc[2] - obpos[2]) > m_activity_box_radius) ) - { - ob->Suspend(); - } - else { - ob->Resume(); - } - } + for (KX_Camera *cam : m_cameralist) { + if (cam->GetActivityCulling()) { + camPositions.push_back(cam->NodeGetWorldPosition()); } } -} - -void KX_Scene::SetActivityCullingRadius(float f) -{ - if (f < 0.5f) - f = 0.5f; - m_activity_box_radius = f; -} -NG_NetworkDeviceInterface* KX_Scene::GetNetworkDeviceInterface() -{ - return m_networkDeviceInterface; -} - -NG_NetworkScene* KX_Scene::GetNetworkScene() -{ - return m_networkScene; -} + // None cameras are using object activity culling? + if (camPositions.size() == 0) { + return; + } -void KX_Scene::SetNetworkDeviceInterface(NG_NetworkDeviceInterface* newInterface) -{ - m_networkDeviceInterface = newInterface; -} + for (KX_GameObject *gameobj : m_objectlist) { + // If the object doesn't manage activity culling we don't compute distance. + if (gameobj->GetActivityCullingInfo().m_flags == KX_GameObject::ActivityCullingInfo::ACTIVITY_NONE) { + continue; + } -void KX_Scene::SetNetworkScene(NG_NetworkScene *newScene) -{ - m_networkScene = newScene; + // For each camera compute the distance to objects and keep the minimum distance. + const mt::vec3& obpos = gameobj->NodeGetWorldPosition(); + float dist = FLT_MAX; + for (const mt::vec3& campos : camPositions) { + // Keep the minimum distance. + dist = std::min((obpos - campos).LengthSquared(), dist); + } + gameobj->UpdateActivity(dist); + } } - -void KX_Scene::SetGravity(const MT_Vector3& gravity) +KX_NetworkMessageScene *KX_Scene::GetNetworkMessageScene() const { - GetPhysicsEnvironment()->SetGravity(gravity[0],gravity[1],gravity[2]); + return m_networkScene; } -MT_Vector3 KX_Scene::GetGravity() +void KX_Scene::SetNetworkMessageScene(KX_NetworkMessageScene *netScene) { - MT_Vector3 gravity; - - GetPhysicsEnvironment()->GetGravity(gravity); - - return gravity; + m_networkScene = netScene; } -void KX_Scene::SetSceneConverter(class KX_BlenderSceneConverter* sceneConverter) +PHY_IPhysicsEnvironment *KX_Scene::GetPhysicsEnvironment() const { - m_sceneConverter = sceneConverter; + return m_physicsEnvironment; } -void KX_Scene::SetPhysicsEnvironment(class PHY_IPhysicsEnvironment* physEnv) +void KX_Scene::SetPhysicsEnvironment(PHY_IPhysicsEnvironment *physEnv) { m_physicsEnvironment = physEnv; if (m_physicsEnvironment) { - KX_TouchEventManager* touchmgr = new KX_TouchEventManager(m_logicmgr, physEnv); - m_logicmgr->RegisterEventManager(touchmgr); + KX_CollisionEventManager *collisionmgr = new KX_CollisionEventManager(m_logicmgr, physEnv); + m_logicmgr->RegisterEventManager(collisionmgr); } } -void KX_Scene::setSuspendedTime(double suspendedtime) +void KX_Scene::SetGravity(const mt::vec3& gravity) { - m_suspendedtime = suspendedtime; + m_physicsEnvironment->SetGravity(gravity[0], gravity[1], gravity[2]); } -double KX_Scene::getSuspendedTime() + +mt::vec3 KX_Scene::GetGravity() const { - return m_suspendedtime; + return m_physicsEnvironment->GetGravity(); } -void KX_Scene::setSuspendedDelta(double suspendeddelta) + +void KX_Scene::SetSuspendedDelta(double suspendeddelta) { - m_suspendeddelta = suspendeddelta; + m_suspendedDelta = suspendeddelta; } -double KX_Scene::getSuspendedDelta() + +double KX_Scene::GetSuspendedDelta() const { - return m_suspendeddelta; + return m_suspendedDelta; } -short KX_Scene::GetAnimationFPS() +Scene *KX_Scene::GetBlenderScene() const { - return m_blenderScene->r.frs_sec; + return m_blenderScene; } -static void MergeScene_LogicBrick(SCA_ILogicBrick* brick, KX_Scene *from, KX_Scene *to) +static void MergeScene_LogicBrick(SCA_ILogicBrick *brick, KX_Scene *from, KX_Scene *to) { - SCA_LogicManager *logicmgr= to->GetLogicManager(); + SCA_LogicManager *logicmgr = to->GetLogicManager(); brick->Replace_IScene(to); - brick->Replace_NetworkScene(to->GetNetworkScene()); + brick->Replace_NetworkScene(to->GetNetworkMessageScene()); brick->SetLogicManager(to->GetLogicManager()); - // If we end up replacing a KX_TouchEventManager, we need to make sure - // physics controllers are properly in place. In other words, do this - // after merging physics controllers! - SCA_ISensor *sensor= dynamic_cast(brick); + /* If we end up replacing a KX_CollisionEventManager, we need to make sure + * physics controllers are properly in place. In other words, do this + * after merging physics controllers. + */ + SCA_ISensor *sensor = dynamic_cast(brick); if (sensor) { sensor->Replace_EventManager(logicmgr); } - SCA_2DFilterActuator *filter_actuator = dynamic_cast(brick); + SCA_2DFilterActuator *filter_actuator = dynamic_cast(brick); if (filter_actuator) { - filter_actuator->SetScene(to); - } - -#ifdef WITH_PYTHON - // Python must be called from the main thread unless we want to deal - // with GIL issues. So, this is delayed until here in case of async - // libload (originally in KX_ConvertControllers) - SCA_PythonController *pyctrl = dynamic_cast(brick); - if (pyctrl) { - pyctrl->SetNamespace(KX_GetActiveEngine()->GetPyNamespace()); - - if (pyctrl->m_mode==SCA_PythonController::SCA_PYEXEC_SCRIPT) - pyctrl->Compile(); + filter_actuator->SetScene(to, to->Get2DFilterManager()); } -#endif } -static void MergeScene_GameObject(KX_GameObject* gameobj, KX_Scene *to, KX_Scene *from) +static void MergeScene_GameObject(KX_GameObject *gameobj, KX_Scene *to, KX_Scene *from) { - { - SCA_ActuatorList& actuators= gameobj->GetActuators(); - SCA_ActuatorList::iterator ita; - - for (ita = actuators.begin(); !(ita==actuators.end()); ++ita) - { - MergeScene_LogicBrick(*ita, from, to); - } + const SCA_ActuatorList& actuators = gameobj->GetActuators(); + for (SCA_IActuator *actuator : actuators) { + MergeScene_LogicBrick(actuator, from, to); } - - { - SCA_SensorList& sensors= gameobj->GetSensors(); - SCA_SensorList::iterator its; - - for (its = sensors.begin(); !(its==sensors.end()); ++its) - { - MergeScene_LogicBrick(*its, from, to); - } + const SCA_SensorList& sensors = gameobj->GetSensors(); + for (SCA_ISensor *sensor : sensors) { + MergeScene_LogicBrick(sensor, from, to); } - { - SCA_ControllerList& controllers= gameobj->GetControllers(); - SCA_ControllerList::iterator itc; - - for (itc = controllers.begin(); !(itc==controllers.end()); ++itc) - { - SCA_IController *cont= *itc; - MergeScene_LogicBrick(cont, from, to); - } + const SCA_ControllerList& controllers = gameobj->GetControllers(); + for (SCA_IController *controller : controllers) { + MergeScene_LogicBrick(controller, from, to); } - /* graphics controller */ - PHY_IController *ctrl = gameobj->GetGraphicController(); - if (ctrl) { - /* SHOULD update the m_cullingTree */ - ctrl->SetPhysicsEnvironment(to->GetPhysicsEnvironment()); + // Graphics controller. + PHY_IGraphicController *graphicCtrl = gameobj->GetGraphicController(); + if (graphicCtrl) { + // Should update the m_cullingTree. + graphicCtrl->SetPhysicsEnvironment(to->GetPhysicsEnvironment()); } - ctrl = gameobj->GetPhysicsController(); - if (ctrl) { - ctrl->SetPhysicsEnvironment(to->GetPhysicsEnvironment()); + PHY_IPhysicsController *physicsCtrl = gameobj->GetPhysicsController(); + if (physicsCtrl) { + physicsCtrl->SetPhysicsEnvironment(to->GetPhysicsEnvironment()); } - /* SG_Node can hold a scene reference */ - SG_Node *sg= gameobj->GetSGNode(); + // SG_Node can hold a scene reference. + SG_Node *sg = gameobj->GetNode(); if (sg) { - if (sg->GetSGClientInfo() == from) { - sg->SetSGClientInfo(to); + if (sg->GetClientInfo() == from) { + sg->SetClientInfo(to); - /* Make sure to grab the children too since they might not be tied to a game object */ - NodeList children = sg->GetSGChildren(); - for (int i=0; iSetSGClientInfo(to); + // Make sure to grab the children too since they might not be tied to a game object. + const NodeList& children = sg->GetChildren(); + for (SG_Node *child : children) { + child->SetClientInfo(to); + } + } + } + switch (gameobj->GetGameObjectType()) { + // If the object is a light, update it's scene. + case SCA_IObject::OBJ_LIGHT: + { + static_cast(gameobj)->UpdateScene(to); + break; + } + // All armatures should be in the animated object list to be umpdated. + case SCA_IObject::OBJ_ARMATURE: + { + to->AddAnimatedObject(gameobj); + break; + } + // Force recreation of text users to link them to the merged scene text material. + case SCA_IObject::OBJ_TEXT: + { + gameobj->RemoveMeshes(); + gameobj->AddMeshUser(); + break; } } - /* If the object is a light, update it's scene */ - if (gameobj->GetGameObjectType() == SCA_IObject::OBJ_LIGHT) - ((KX_LightObject*)gameobj)->UpdateScene(to); - - if (gameobj->GetGameObjectType() == SCA_IObject::OBJ_CAMERA) - to->AddCamera((KX_Camera*)gameobj); - - // All armatures should be in the animated object list to be umpdated. - if (gameobj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE) - to->AddAnimatedObject(gameobj); - /* Add the object to the scene's logic manager */ + // Add the object to the scene's logic manager. to->GetLogicManager()->RegisterGameObjectName(gameobj->GetName(), gameobj); to->GetLogicManager()->RegisterGameObj(gameobj->GetBlenderObject(), gameobj); - for (int i = 0; i < gameobj->GetMeshCount(); ++i) { - RAS_MeshObject *meshobj = gameobj->GetMesh(i); + for (KX_Mesh *meshobj : gameobj->GetMeshList()) { // Register the mesh object by name and blender object. to->GetLogicManager()->RegisterGameMeshName(meshobj->GetName(), gameobj->GetBlenderObject()); to->GetLogicManager()->RegisterMeshName(meshobj->GetName(), meshobj); @@ -2041,144 +1644,130 @@ bool KX_Scene::MergeScene(KX_Scene *other) PHY_IPhysicsEnvironment *env = this->GetPhysicsEnvironment(); PHY_IPhysicsEnvironment *env_other = other->GetPhysicsEnvironment(); - if ((env==NULL) != (env_other==NULL)) /* TODO - even when both scenes have NONE physics, the other is loaded with bullet enabled, ??? */ - { - printf("KX_Scene::MergeScene: physics scenes type differ, aborting\n"); - printf("\tsource %d, terget %d\n", (int)(env!=NULL), (int)(env_other!=NULL)); + if ((env == nullptr) != (env_other == nullptr)) { + // TODO - even when both scenes have NONE physics, the other is loaded with bullet enabled, ??? + CM_FunctionError("physics scenes type differ, aborting\n\tsource " << (int)(env != nullptr) << ", target " << (int)(env_other != nullptr)); return false; } - if (GetSceneConverter() != other->GetSceneConverter()) { - printf("KX_Scene::MergeScene: converters differ, aborting\n"); - return false; - } - - - GetBucketManager()->MergeBucketManager(other->GetBucketManager(), this); + m_bucketmanager->Merge(other->GetBucketManager(), this); + m_boundingBoxManager->Merge(other->GetBoundingBoxManager()); + m_rendererManager->Merge(other->GetTextureRendererManager()); + m_componentManager.Merge(other->GetPythonComponentManager()); - - /* active + inactive == all ??? - lets hope so */ - for (int i = 0; i < other->GetObjectList()->GetCount(); i++) - { - KX_GameObject* gameobj = (KX_GameObject*)other->GetObjectList()->GetValue(i); + for (KX_GameObject *gameobj : *other->GetObjectList()) { MergeScene_GameObject(gameobj, this, other); - /* add properties to debug list for LibLoad objects */ - if (KX_GetActiveEngine()->GetAutoAddDebugProperties()) { + // Add properties to debug list for LibLoad objects. + if (KX_GetActiveEngine()->GetFlag(KX_KetsjiEngine::AUTO_ADD_DEBUG_PROPERTIES)) { AddObjectDebugProperties(gameobj); } - - gameobj->UpdateBuckets(false); /* only for active objects */ } - for (int i = 0; i < other->GetInactiveList()->GetCount(); i++) - { - KX_GameObject* gameobj = (KX_GameObject*)other->GetInactiveList()->GetValue(i); + for (KX_GameObject *gameobj : *other->GetInactiveList()) { MergeScene_GameObject(gameobj, this, other); } if (env) { env->MergeEnvironment(env_other); - CListValue *otherObjects = other->GetObjectList(); + EXP_ListValue *otherObjects = other->GetObjectList(); // List of all physics objects to merge (needed by ReplicateConstraints). std::vector physicsObjects; - for (unsigned int i = 0; i < otherObjects->GetCount(); ++i) { - KX_GameObject *gameobj = (KX_GameObject *)otherObjects->GetValue(i); + for (KX_GameObject *gameobj : otherObjects) { if (gameobj->GetPhysicsController()) { physicsObjects.push_back(gameobj); } } - for (unsigned int i = 0; i < physicsObjects.size(); ++i) { - KX_GameObject *gameobj = physicsObjects[i]; + for (KX_GameObject *gameobj : physicsObjects) { // Replicate all constraints in the right physics environment. - gameobj->GetPhysicsController()->ReplicateConstraints(gameobj, physicsObjects); - gameobj->ClearConstraints(); + gameobj->ReplicateConstraints(m_physicsEnvironment, physicsObjects); } } - - GetTempObjectList()->MergeList(other->GetTempObjectList()); - other->GetTempObjectList()->ReleaseAndRemoveAll(); - - GetObjectList()->MergeList(other->GetObjectList()); + m_objectlist->MergeList(other->GetObjectList()); other->GetObjectList()->ReleaseAndRemoveAll(); - GetInactiveList()->MergeList(other->GetInactiveList()); + m_inactivelist->MergeList(other->GetInactiveList()); other->GetInactiveList()->ReleaseAndRemoveAll(); - GetRootParentList()->MergeList(other->GetRootParentList()); + m_parentlist->MergeList(other->GetRootParentList()); other->GetRootParentList()->ReleaseAndRemoveAll(); - GetLightList()->MergeList(other->GetLightList()); + m_lightlist->MergeList(other->GetLightList()); other->GetLightList()->ReleaseAndRemoveAll(); - /* move materials across, assume they both use the same scene-converters - * Do this after lights are merged so materials can use the lights in shaders - */ - GetSceneConverter()->MergeScene(this, other); - - /* merge logic */ - { - SCA_LogicManager *logicmgr= GetLogicManager(); - SCA_LogicManager *logicmgr_other= other->GetLogicManager(); - - vectorevtmgrs= logicmgr->GetEventManagers(); - //vectorevtmgrs_others= logicmgr_other->GetEventManagers(); - - //SCA_EventManager *evtmgr; - SCA_EventManager *evtmgr_other; + m_cameralist->MergeList(other->GetCameraList()); + other->GetCameraList()->ReleaseAndRemoveAll(); - for (unsigned int i= 0; i < evtmgrs.size(); i++) { - evtmgr_other= logicmgr_other->FindEventManager(evtmgrs[i]->GetType()); + m_fontlist->MergeList(other->GetFontList()); + other->GetFontList()->ReleaseAndRemoveAll(); - if (evtmgr_other) /* unlikely but possible one scene has a joystick and not the other */ - evtmgr_other->Replace_LogicManager(logicmgr); + // Grab any timer properties from the other scene. + SCA_TimeEventManager *timemgr_other = other->GetTimeEventManager(); + std::vector times = timemgr_other->GetTimeValues(); - /* when merging objects sensors are moved across into the new manager, don't need to do this here */ - } + for (EXP_Value *time : times) { + m_timemgr->AddTimeProperty(time); + } - /* grab any timer properties from the other scene */ - SCA_TimeEventManager *timemgr= GetTimeEventManager(); - SCA_TimeEventManager *timemgr_other= other->GetTimeEventManager(); - vector times = timemgr_other->GetTimeValues(); + return true; +} - for (unsigned int i= 0; i < times.size(); i++) { - timemgr->AddTimeProperty(times[i]); - } +KX_2DFilterManager *KX_Scene::Get2DFilterManager() const +{ + return m_filterManager; +} - } - return true; +RAS_OffScreen *KX_Scene::Render2DFilters(RAS_Rasterizer *rasty, RAS_ICanvas *canvas, RAS_OffScreen *inputofs, RAS_OffScreen *targetofs) +{ + return m_filterManager->RenderFilters(rasty, canvas, inputofs, targetofs); } -void KX_Scene::Update2DFilter(vector& propNames, void* gameObj, RAS_2DFilterManager::RAS_2DFILTER_MODE filtermode, int pass, STR_String& text) +KX_ObstacleSimulation *KX_Scene::GetObstacleSimulation() { - m_filtermanager.EnableFilter(propNames, gameObj, filtermode, pass, text); + return m_obstacleSimulation; } -void KX_Scene::Render2DFilters(RAS_ICanvas* canvas) +void KX_Scene::SetObstacleSimulation(KX_ObstacleSimulation *obstacleSimulation) { - m_filtermanager.RenderFilters(canvas); + m_obstacleSimulation = obstacleSimulation; } #ifdef WITH_PYTHON -void KX_Scene::RunDrawingCallbacks(PyObject *cb_list) +void KX_Scene::RunDrawingCallbacks(DrawingCallbackType callbackType, KX_Camera *camera) { - if (!cb_list || PyList_GET_SIZE(cb_list) == 0) + PyObject *list = m_drawCallbacks[callbackType]; + if (!list || PyList_GET_SIZE(list) == 0) { return; + } - RunPythonCallBackList(cb_list, NULL, 0, 0); + if (camera) { + PyObject *args[1] = {camera->GetProxy()}; + EXP_RunPythonCallBackList(list, args, 0, 1); + } + else { + EXP_RunPythonCallBackList(list, nullptr, 0, 0); + } } -//---------------------------------------------------------------------------- -//Python +void KX_Scene::RunOnRemoveCallbacks() +{ + PyObject *list = m_removeCallbacks; + if (!list || PyList_GET_SIZE(list) == 0) { + return; + } + + PyObject *args[1] = { GetProxy() }; + EXP_RunPythonCallBackList(list, args, 0, 1); +} PyTypeObject KX_Scene::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_Scene", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -2189,379 +1778,422 @@ PyTypeObject KX_Scene::Type = { 0, &Sequence, &Mapping, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, - &CValue::Type, - 0,0,0,0,0,0, + &EXP_Value::Type, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_Scene::Methods[] = { - KX_PYMETHODTABLE(KX_Scene, addObject), - KX_PYMETHODTABLE(KX_Scene, end), - KX_PYMETHODTABLE(KX_Scene, restart), - KX_PYMETHODTABLE(KX_Scene, replace), - KX_PYMETHODTABLE(KX_Scene, suspend), - KX_PYMETHODTABLE(KX_Scene, resume), - KX_PYMETHODTABLE(KX_Scene, drawObstacleSimulation), - - - /* dict style access */ - KX_PYMETHODTABLE(KX_Scene, get), - - {NULL,NULL} //Sentinel + EXP_PYMETHODTABLE(KX_Scene, addObject), + EXP_PYMETHODTABLE(KX_Scene, end), + EXP_PYMETHODTABLE(KX_Scene, restart), + EXP_PYMETHODTABLE(KX_Scene, replace), + EXP_PYMETHODTABLE(KX_Scene, suspend), + EXP_PYMETHODTABLE(KX_Scene, resume), + EXP_PYMETHODTABLE(KX_Scene, drawObstacleSimulation), + + // Sict style access. + EXP_PYMETHODTABLE(KX_Scene, get), + + {nullptr, nullptr} // Sentinel }; static PyObject *Map_GetItem(PyObject *self_v, PyObject *item) { - KX_Scene* self = static_castBGE_PROXY_REF(self_v); - const char *attr_str= _PyUnicode_AsString(item); + KX_Scene *self = static_castEXP_PROXY_REF(self_v); + const char *attr_str = _PyUnicode_AsString(item); PyObject *pyconvert; - if (self == NULL) { - PyErr_SetString(PyExc_SystemError, "val = scene[key]: KX_Scene, " BGE_PROXY_ERROR_MSG); - return NULL; + if (!self) { + PyErr_SetString(PyExc_SystemError, "val = scene[key]: KX_Scene, " EXP_PROXY_ERROR_MSG); + return nullptr; } - if (!self->m_attr_dict) - self->m_attr_dict = PyDict_New(); + if (!self->m_attrDict) { + self->m_attrDict = PyDict_New(); + } - if (self->m_attr_dict && (pyconvert=PyDict_GetItem(self->m_attr_dict, item))) { + if (self->m_attrDict && (pyconvert = PyDict_GetItem(self->m_attrDict, item))) { - if (attr_str) + if (attr_str) { PyErr_Clear(); + } Py_INCREF(pyconvert); return pyconvert; } else { - if (attr_str) PyErr_Format(PyExc_KeyError, "value = scene[key]: KX_Scene, key \"%s\" does not exist", attr_str); - else PyErr_SetString(PyExc_KeyError, "value = scene[key]: KX_Scene, key does not exist"); - return NULL; + if (attr_str) { + PyErr_Format(PyExc_KeyError, "value = scene[key]: KX_Scene, key \"%s\" does not exist", attr_str); + } + else { + PyErr_SetString(PyExc_KeyError, "value = scene[key]: KX_Scene, key does not exist"); + } + return nullptr; } } static int Map_SetItem(PyObject *self_v, PyObject *key, PyObject *val) { - KX_Scene* self = static_castBGE_PROXY_REF(self_v); - const char *attr_str= _PyUnicode_AsString(key); - if (attr_str==NULL) + KX_Scene *self = static_castEXP_PROXY_REF(self_v); + const char *attr_str = _PyUnicode_AsString(key); + if (!attr_str) { PyErr_Clear(); + } - if (self == NULL) { - PyErr_SetString(PyExc_SystemError, "scene[key] = value: KX_Scene, " BGE_PROXY_ERROR_MSG); + if (!self) { + PyErr_SetString(PyExc_SystemError, "scene[key] = value: KX_Scene, " EXP_PROXY_ERROR_MSG); return -1; } - if (!self->m_attr_dict) - self->m_attr_dict = PyDict_New(); + if (!self->m_attrDict) { + self->m_attrDict = PyDict_New(); + } - if (val==NULL) { /* del ob["key"] */ - int del= 0; + if (!val) { + // del ob["key"] + int del = 0; - if (self->m_attr_dict) - del |= (PyDict_DelItem(self->m_attr_dict, key)==0) ? 1:0; + if (self->m_attrDict) { + del |= (PyDict_DelItem(self->m_attrDict, key) == 0) ? 1 : 0; + } - if (del==0) { - if (attr_str) PyErr_Format(PyExc_KeyError, "scene[key] = value: KX_Scene, key \"%s\" could not be set", attr_str); - else PyErr_SetString(PyExc_KeyError, "del scene[key]: KX_Scene, key could not be deleted"); + if (del == 0) { + if (attr_str) { + PyErr_Format(PyExc_KeyError, "scene[key] = value: KX_Scene, key \"%s\" could not be set", attr_str); + } + else { + PyErr_SetString(PyExc_KeyError, "del scene[key]: KX_Scene, key could not be deleted"); + } return -1; } - else if (self->m_attr_dict) { - PyErr_Clear(); /* PyDict_DelItem sets an error when it fails */ + else if (self->m_attrDict) { + // PyDict_DelItem sets an error when it fails. + PyErr_Clear(); } } - else { /* ob["key"] = value */ + else { + // ob["key"] = value int set = 0; - if (self->m_attr_dict==NULL) /* lazy init */ - self->m_attr_dict= PyDict_New(); - + // Lazy init. + if (!self->m_attrDict) { + self->m_attrDict = PyDict_New(); + } - if (PyDict_SetItem(self->m_attr_dict, key, val)==0) - set= 1; - else + if (PyDict_SetItem(self->m_attrDict, key, val) == 0) { + set = 1; + } + else { PyErr_SetString(PyExc_KeyError, "scene[key] = value: KX_Scene, key not be added to internal dictionary"); + } - if (set==0) - return -1; /* pythons error value */ + if (set == 0) { + // Pythons error value. + return -1; + } } - return 0; /* success */ + // Success. + return 0; } static int Seq_Contains(PyObject *self_v, PyObject *value) { - KX_Scene* self = static_castBGE_PROXY_REF(self_v); + KX_Scene *self = static_castEXP_PROXY_REF(self_v); - if (self == NULL) { - PyErr_SetString(PyExc_SystemError, "val in scene: KX_Scene, " BGE_PROXY_ERROR_MSG); + if (!self) { + PyErr_SetString(PyExc_SystemError, "val in scene: KX_Scene, " EXP_PROXY_ERROR_MSG); return -1; } - if (!self->m_attr_dict) - self->m_attr_dict = PyDict_New(); + if (!self->m_attrDict) { + self->m_attrDict = PyDict_New(); + } - if (self->m_attr_dict && PyDict_GetItem(self->m_attr_dict, value)) + if (self->m_attrDict && PyDict_GetItem(self->m_attrDict, value)) { return 1; + } return 0; } PyMappingMethods KX_Scene::Mapping = { - (lenfunc)NULL, /* inquiry mp_length */ - (binaryfunc)Map_GetItem, /* binaryfunc mp_subscript */ - (objobjargproc)Map_SetItem, /* objobjargproc mp_ass_subscript */ + (lenfunc)nullptr, // inquiry mp_length + (binaryfunc)Map_GetItem, // binaryfunc mp_subscript + (objobjargproc)Map_SetItem, // objobjargproc mp_ass_subscript }; PySequenceMethods KX_Scene::Sequence = { - NULL, /* Cant set the len otherwise it can evaluate as false */ - NULL, /* sq_concat */ - NULL, /* sq_repeat */ - NULL, /* sq_item */ - NULL, /* sq_slice */ - NULL, /* sq_ass_item */ - NULL, /* sq_ass_slice */ - (objobjproc)Seq_Contains, /* sq_contains */ - (binaryfunc) NULL, /* sq_inplace_concat */ - (ssizeargfunc) NULL, /* sq_inplace_repeat */ + nullptr, // Cant set the len otherwise it can evaluate as false. + nullptr, // sq_concat + nullptr, // sq_repeat + nullptr, // sq_item + nullptr, // sq_slice + nullptr, // sq_ass_item + nullptr, // sq_ass_slice + (objobjproc)Seq_Contains, // sq_contains + (binaryfunc)nullptr, // sq_inplace_concat + (ssizeargfunc)nullptr, // sq_inplace_repeat }; -PyObject *KX_Scene::pyattr_get_name(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Scene::pyattr_get_name(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Scene* self = static_cast(self_v); - return PyUnicode_From_STR_String(self->GetName()); + KX_Scene *self = static_cast(self_v); + return PyUnicode_FromStdString(self->GetName()); } -PyObject *KX_Scene::pyattr_get_objects(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Scene::pyattr_get_objects(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Scene* self = static_cast(self_v); + KX_Scene *self = static_cast(self_v); return self->GetObjectList()->GetProxy(); } -PyObject *KX_Scene::pyattr_get_objects_inactive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Scene::pyattr_get_objects_inactive(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Scene* self = static_cast(self_v); + KX_Scene *self = static_cast(self_v); return self->GetInactiveList()->GetProxy(); } -PyObject *KX_Scene::pyattr_get_lights(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Scene::pyattr_get_lights(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Scene* self = static_cast(self_v); + KX_Scene *self = static_cast(self_v); return self->GetLightList()->GetProxy(); } -PyObject *KX_Scene::pyattr_get_world(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Scene::pyattr_get_filter_manager(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_Scene *self = static_cast(self_v); + KX_2DFilterManager *filterManager = self->Get2DFilterManager(); + + return filterManager->GetProxy(); +} + +PyObject *KX_Scene::pyattr_get_world(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Scene* self = static_cast(self_v); + KX_Scene *self = static_cast(self_v); KX_WorldInfo *world = self->GetWorldInfo(); - if (world->GetName() != "") { - return world->GetProxy(); + if (world->GetName().empty()) { + Py_RETURN_NONE; } else { - Py_RETURN_NONE; + return world->GetProxy(); } } -PyObject *KX_Scene::pyattr_get_cameras(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Scene::pyattr_get_texts(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - /* With refcounts in this case... - * the new CListValue is owned by python, so its possible python holds onto it longer then the BGE - * however this is the same with "scene.objects + []", when you make a copy by adding lists. - */ - - KX_Scene* self = static_cast(self_v); - CListValue* clist = new CListValue(); - - /* return self->GetCameras()->GetProxy(); */ - - list::iterator it = self->GetCameras()->begin(); - while (it != self->GetCameras()->end()) { - clist->Add((*it)->AddRef()); - it++; - } + KX_Scene *self = static_cast(self_v); + return self->GetFontList()->GetProxy(); +} - return clist->NewProxy(true); +PyObject *KX_Scene::pyattr_get_cameras(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_Scene *self = static_cast(self_v); + return self->GetCameraList()->GetProxy(); } -PyObject *KX_Scene::pyattr_get_active_camera(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Scene::pyattr_get_active_camera(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Scene* self = static_cast(self_v); - KX_Camera* cam= self->GetActiveCamera(); - if (cam) - return self->GetActiveCamera()->GetProxy(); - else + KX_Scene *self = static_cast(self_v); + KX_Camera *cam = self->GetActiveCamera(); + if (cam) { + return cam->GetProxy(); + } + else { Py_RETURN_NONE; + } } - -int KX_Scene::pyattr_set_active_camera(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_Scene::pyattr_set_active_camera(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_Scene* self = static_cast(self_v); + KX_Scene *self = static_cast(self_v); KX_Camera *camOb; - if (!ConvertPythonToCamera(value, &camOb, false, "scene.active_camera = value: KX_Scene")) + if (!ConvertPythonToCamera(self, value, &camOb, false, "scene.active_camera = value: KX_Scene")) { return PY_SET_ATTR_FAIL; + } self->SetActiveCamera(camOb); return PY_SET_ATTR_SUCCESS; } -PyObject *KX_Scene::pyattr_get_drawing_callback_pre(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Scene::pyattr_get_overrideCullingCamera(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Scene* self = static_cast(self_v); - - if (self->m_draw_call_pre==NULL) - self->m_draw_call_pre= PyList_New(0); - Py_INCREF(self->m_draw_call_pre); - return self->m_draw_call_pre; + KX_Scene *self = static_cast(self_v); + KX_Camera *cam = self->GetOverrideCullingCamera(); + if (cam) { + return cam->GetProxy(); + } + else { + Py_RETURN_NONE; + } } -PyObject *KX_Scene::pyattr_get_drawing_callback_post(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +int KX_Scene::pyattr_set_overrideCullingCamera(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_Scene* self = static_cast(self_v); + KX_Scene *self = static_cast(self_v); + KX_Camera *cam; + + if (!ConvertPythonToCamera(self, value, &cam, true, "scene.active_camera = value: KX_Scene")) { + return PY_SET_ATTR_FAIL; + } - if (self->m_draw_call_post==NULL) - self->m_draw_call_post= PyList_New(0); - Py_INCREF(self->m_draw_call_post); - return self->m_draw_call_post; + self->SetOverrideCullingCamera(cam); + return PY_SET_ATTR_SUCCESS; } -PyObject *KX_Scene::pyattr_get_drawing_setup_callback_pre(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +static std::map callbacksTable = { + {"pre_draw", KX_Scene::PRE_DRAW}, + {"pre_draw_setup", KX_Scene::PRE_DRAW_SETUP}, + {"post_draw", KX_Scene::POST_DRAW} +}; + +PyObject *KX_Scene::pyattr_get_drawing_callback(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Scene* self = static_cast(self_v); + KX_Scene *self = static_cast(self_v); + + const DrawingCallbackType type = callbacksTable[attrdef->m_name]; + if (!self->m_drawCallbacks[type]) { + self->m_drawCallbacks[type] = PyList_New(0); + } - if (self->m_draw_setup_call_pre == NULL) - self->m_draw_setup_call_pre = PyList_New(0); + Py_INCREF(self->m_drawCallbacks[type]); - Py_INCREF(self->m_draw_setup_call_pre); - return self->m_draw_setup_call_pre; + return self->m_drawCallbacks[type]; } -int KX_Scene::pyattr_set_drawing_callback_pre(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_Scene::pyattr_set_drawing_callback(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_Scene* self = static_cast(self_v); + KX_Scene *self = static_cast(self_v); - if (!PyList_CheckExact(value)) - { + if (!PyList_CheckExact(value)) { PyErr_SetString(PyExc_ValueError, "Expected a list"); return PY_SET_ATTR_FAIL; } - Py_XDECREF(self->m_draw_call_pre); + + const DrawingCallbackType type = callbacksTable[attrdef->m_name]; + + Py_XDECREF(self->m_drawCallbacks[type]); Py_INCREF(value); - self->m_draw_call_pre = value; + self->m_drawCallbacks[type] = value; return PY_SET_ATTR_SUCCESS; } -int KX_Scene::pyattr_set_drawing_callback_post(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +PyObject *KX_Scene::pyattr_get_remove_callback(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Scene* self = static_cast(self_v); + KX_Scene *self = static_cast(self_v); - if (!PyList_CheckExact(value)) - { - PyErr_SetString(PyExc_ValueError, "Expected a list"); - return PY_SET_ATTR_FAIL; + if (!self->m_removeCallbacks) { + self->m_removeCallbacks = PyList_New(0); } - Py_XDECREF(self->m_draw_call_post); - Py_INCREF(value); - self->m_draw_call_post = value; + Py_INCREF(self->m_removeCallbacks); - return PY_SET_ATTR_SUCCESS; + return self->m_removeCallbacks; } -int KX_Scene::pyattr_set_drawing_setup_callback_pre(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_Scene::pyattr_set_remove_callback(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_Scene* self = static_cast(self_v); + KX_Scene *self = static_cast(self_v); if (!PyList_CheckExact(value)) { PyErr_SetString(PyExc_ValueError, "Expected a list"); return PY_SET_ATTR_FAIL; } - Py_XDECREF(self->m_draw_setup_call_pre); + Py_XDECREF(self->m_removeCallbacks); + Py_INCREF(value); + self->m_removeCallbacks = value; - self->m_draw_setup_call_pre = value; return PY_SET_ATTR_SUCCESS; } -PyObject *KX_Scene::pyattr_get_gravity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_Scene::pyattr_get_gravity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_Scene* self = static_cast(self_v); + KX_Scene *self = static_cast(self_v); return PyObjectFrom(self->GetGravity()); } -int KX_Scene::pyattr_set_gravity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_Scene::pyattr_set_gravity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_Scene* self = static_cast(self_v); + KX_Scene *self = static_cast(self_v); - MT_Vector3 vec; - if (!PyVecTo(value, vec)) + mt::vec3 vec; + if (!PyVecTo(value, vec)) { return PY_SET_ATTR_FAIL; + } self->SetGravity(vec); return PY_SET_ATTR_SUCCESS; } PyAttributeDef KX_Scene::Attributes[] = { - KX_PYATTRIBUTE_RO_FUNCTION("name", KX_Scene, pyattr_get_name), - KX_PYATTRIBUTE_RO_FUNCTION("objects", KX_Scene, pyattr_get_objects), - KX_PYATTRIBUTE_RO_FUNCTION("objectsInactive", KX_Scene, pyattr_get_objects_inactive), - KX_PYATTRIBUTE_RO_FUNCTION("lights", KX_Scene, pyattr_get_lights), - KX_PYATTRIBUTE_RO_FUNCTION("cameras", KX_Scene, pyattr_get_cameras), - KX_PYATTRIBUTE_RO_FUNCTION("world", KX_Scene, pyattr_get_world), - KX_PYATTRIBUTE_RW_FUNCTION("active_camera", KX_Scene, pyattr_get_active_camera, pyattr_set_active_camera), - KX_PYATTRIBUTE_RW_FUNCTION("pre_draw", KX_Scene, pyattr_get_drawing_callback_pre, pyattr_set_drawing_callback_pre), - KX_PYATTRIBUTE_RW_FUNCTION("post_draw", KX_Scene, pyattr_get_drawing_callback_post, pyattr_set_drawing_callback_post), - KX_PYATTRIBUTE_RW_FUNCTION("pre_draw_setup", KX_Scene, pyattr_get_drawing_setup_callback_pre, pyattr_set_drawing_setup_callback_pre), - KX_PYATTRIBUTE_RW_FUNCTION("gravity", KX_Scene, pyattr_get_gravity, pyattr_set_gravity), - KX_PYATTRIBUTE_BOOL_RO("suspended", KX_Scene, m_suspend), - KX_PYATTRIBUTE_BOOL_RO("activity_culling", KX_Scene, m_activity_culling), - KX_PYATTRIBUTE_FLOAT_RW("activity_culling_radius", 0.5f, FLT_MAX, KX_Scene, m_activity_box_radius), - KX_PYATTRIBUTE_BOOL_RO("dbvt_culling", KX_Scene, m_dbvt_culling), - { NULL } //Sentinel + EXP_PYATTRIBUTE_RO_FUNCTION("name", KX_Scene, pyattr_get_name), + EXP_PYATTRIBUTE_RO_FUNCTION("objects", KX_Scene, pyattr_get_objects), + EXP_PYATTRIBUTE_RO_FUNCTION("objectsInactive", KX_Scene, pyattr_get_objects_inactive), + EXP_PYATTRIBUTE_RO_FUNCTION("lights", KX_Scene, pyattr_get_lights), + EXP_PYATTRIBUTE_RO_FUNCTION("texts", KX_Scene, pyattr_get_texts), + EXP_PYATTRIBUTE_RO_FUNCTION("cameras", KX_Scene, pyattr_get_cameras), + EXP_PYATTRIBUTE_RO_FUNCTION("filterManager", KX_Scene, pyattr_get_filter_manager), + EXP_PYATTRIBUTE_RO_FUNCTION("world", KX_Scene, pyattr_get_world), + EXP_PYATTRIBUTE_RW_FUNCTION("active_camera", KX_Scene, pyattr_get_active_camera, pyattr_set_active_camera), + EXP_PYATTRIBUTE_RW_FUNCTION("overrideCullingCamera", KX_Scene, pyattr_get_overrideCullingCamera, pyattr_set_overrideCullingCamera), + EXP_PYATTRIBUTE_RW_FUNCTION("pre_draw", KX_Scene, pyattr_get_drawing_callback, pyattr_set_drawing_callback), + EXP_PYATTRIBUTE_RW_FUNCTION("post_draw", KX_Scene, pyattr_get_drawing_callback, pyattr_set_drawing_callback), + EXP_PYATTRIBUTE_RW_FUNCTION("pre_draw_setup", KX_Scene, pyattr_get_drawing_callback, pyattr_set_drawing_callback), + EXP_PYATTRIBUTE_RW_FUNCTION("onRemove", KX_Scene, pyattr_get_remove_callback, pyattr_set_remove_callback), + EXP_PYATTRIBUTE_RW_FUNCTION("gravity", KX_Scene, pyattr_get_gravity, pyattr_set_gravity), + EXP_PYATTRIBUTE_BOOL_RO("suspended", KX_Scene, m_suspend), + EXP_PYATTRIBUTE_BOOL_RO("activityCulling", KX_Scene, m_activityCulling), + EXP_PYATTRIBUTE_BOOL_RO("dbvt_culling", KX_Scene, m_dbvtCulling), + EXP_PYATTRIBUTE_NULL // Sentinel }; -KX_PYMETHODDEF_DOC(KX_Scene, addObject, -"addObject(object, other, time=0)\n" -"Returns the added object.\n") +EXP_PYMETHODDEF_DOC(KX_Scene, addObject, + "addObject(object, other, time=0)\n" + "Returns the added object.\n") { PyObject *pyob, *pyreference = Py_None; KX_GameObject *ob, *reference; - int time = 0; + float time = 0.0f; - if (!PyArg_ParseTuple(args, "O|Oi:addObject", &pyob, &pyreference, &time)) - return NULL; + if (!PyArg_ParseTuple(args, "O|Of:addObject", &pyob, &pyreference, &time)) { + return nullptr; + } if (!ConvertPythonToGameObject(m_logicmgr, pyob, &ob, false, "scene.addObject(object, reference, time): KX_Scene (first argument)") || - !ConvertPythonToGameObject(m_logicmgr, pyreference, &reference, true, "scene.addObject(object, reference, time): KX_Scene (second argument)")) - return NULL; + !ConvertPythonToGameObject(m_logicmgr, pyreference, &reference, true, "scene.addObject(object, reference, time): KX_Scene (second argument)")) { + return nullptr; + } if (!m_inactivelist->SearchValue(ob)) { PyErr_Format(PyExc_ValueError, "scene.addObject(object, reference, time): KX_Scene (first argument): object must be in an inactive layer"); - return NULL; + return nullptr; } - SCA_IObject *replica = AddReplicaObject((SCA_IObject*)ob, reference, time); + KX_GameObject *replica = AddReplicaObject(ob, reference, time); - // release here because AddReplicaObject AddRef's - // the object is added to the scene so we don't want python to own a reference + /* Release here because AddReplicaObject AddRef's + * the object is added to the scene so we don't want python to own a reference. */ replica->Release(); return replica->GetProxy(); } -KX_PYMETHODDEF_DOC(KX_Scene, end, -"end()\n" -"Removes this scene from the game.\n") +EXP_PYMETHODDEF_DOC(KX_Scene, end, + "end()\n" + "Removes this scene from the game.\n") { KX_GetActiveEngine()->RemoveScene(m_sceneName); @@ -2569,70 +2201,73 @@ KX_PYMETHODDEF_DOC(KX_Scene, end, Py_RETURN_NONE; } -KX_PYMETHODDEF_DOC(KX_Scene, restart, - "restart()\n" - "Restarts this scene.\n") +EXP_PYMETHODDEF_DOC(KX_Scene, restart, + "restart()\n" + "Restarts this scene.\n") { KX_GetActiveEngine()->ReplaceScene(m_sceneName, m_sceneName); Py_RETURN_NONE; } -KX_PYMETHODDEF_DOC(KX_Scene, replace, - "replace(newScene)\n" - "Replaces this scene with another one.\n" - "Return True if the new scene exists and scheduled for replacement, False otherwise.\n") +EXP_PYMETHODDEF_DOC(KX_Scene, replace, + "replace(newScene)\n" + "Replaces this scene with another one.\n" + "Return True if the new scene exists and scheduled for replacement, False otherwise.\n") { - char* name; + char *name; - if (!PyArg_ParseTuple(args, "s:replace", &name)) - return NULL; + if (!PyArg_ParseTuple(args, "s:replace", &name)) { + return nullptr; + } - if (KX_GetActiveEngine()->ReplaceScene(m_sceneName, name)) - Py_RETURN_TRUE; + if (KX_GetActiveEngine()->ReplaceScene(m_sceneName, name)) { + Py_RETURN_TRUE; + } - Py_RETURN_FALSE; + Py_RETURN_FALSE; } -KX_PYMETHODDEF_DOC(KX_Scene, suspend, - "suspend()\n" - "Suspends this scene.\n") +EXP_PYMETHODDEF_DOC(KX_Scene, suspend, + "suspend()\n" + "Suspends this scene.\n") { Suspend(); Py_RETURN_NONE; } -KX_PYMETHODDEF_DOC(KX_Scene, resume, - "resume()\n" - "Resumes this scene.\n") +EXP_PYMETHODDEF_DOC(KX_Scene, resume, + "resume()\n" + "Resumes this scene.\n") { Resume(); Py_RETURN_NONE; } -KX_PYMETHODDEF_DOC(KX_Scene, drawObstacleSimulation, - "drawObstacleSimulation()\n" - "Draw debug visualization of obstacle simulation.\n") +EXP_PYMETHODDEF_DOC(KX_Scene, drawObstacleSimulation, + "drawObstacleSimulation()\n" + "Draw debug visualization of obstacle simulation.\n") { - if (GetObstacleSimulation()) + if (GetObstacleSimulation()) { GetObstacleSimulation()->DrawObstacles(); + } Py_RETURN_NONE; } -/* Matches python dict.get(key, [default]) */ -KX_PYMETHODDEF_DOC(KX_Scene, get, "") +EXP_PYMETHODDEF_DOC(KX_Scene, get, "") { PyObject *key; PyObject *def = Py_None; PyObject *ret; - if (!PyArg_ParseTuple(args, "O|O:get", &key, &def)) - return NULL; + if (!PyArg_ParseTuple(args, "O|O:get", &key, &def)) { + return nullptr; + } - if (m_attr_dict && (ret=PyDict_GetItem(m_attr_dict, key))) { + if (m_attrDict && (ret = PyDict_GetItem(m_attrDict, key))) { Py_INCREF(ret); return ret; } @@ -2641,4 +2276,60 @@ KX_PYMETHODDEF_DOC(KX_Scene, get, "") return def; } -#endif // WITH_PYTHON +bool ConvertPythonToScene(PyObject *value, KX_Scene **scene, bool py_none_ok, const char *error_prefix) +{ + if (value == nullptr) { + PyErr_Format(PyExc_TypeError, "%s, python pointer nullptr, should never happen", error_prefix); + *scene = nullptr; + return false; + } + + if (value == Py_None) { + *scene = nullptr; + + if (py_none_ok) { + return true; + } + else { + PyErr_Format(PyExc_TypeError, "%s, expected KX_Scene or a KX_Scene name, None is invalid", error_prefix); + return false; + } + } + + if (PyUnicode_Check(value)) { + *scene = KX_GetActiveEngine()->CurrentScenes()->FindValue(std::string(_PyUnicode_AsString(value))); + + if (*scene) { + return true; + } + else { + PyErr_Format(PyExc_ValueError, "%s, requested name \"%s\" did not match any in game", error_prefix, _PyUnicode_AsString(value)); + return false; + } + } + + if (PyObject_TypeCheck(value, &KX_Scene::Type)) { + *scene = static_castEXP_PROXY_REF(value); + + // Sets the error. + if (*scene == nullptr) { + PyErr_Format(PyExc_SystemError, "%s, " EXP_PROXY_ERROR_MSG, error_prefix); + return false; + } + + return true; + } + + *scene = nullptr; + + if (py_none_ok) { + PyErr_Format(PyExc_TypeError, "%s, expect a KX_Scene, a string or None", error_prefix); + } + else { + PyErr_Format(PyExc_TypeError, "%s, expect a KX_Scene or a string", error_prefix); + } + + return false; +} + +#endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h index d548d1e48925..a8269500eab1 100644 --- a/source/gameengine/Ketsji/KX_Scene.h +++ b/source/gameengine/Ketsji/KX_Scene.h @@ -34,186 +34,164 @@ #include "KX_PhysicsEngineEnums.h" +#include "KX_TextureRendererManager.h" // For KX_TextureRendererManager::RendererCategory. +#include "KX_PythonComponentManager.h" +#include "KX_KetsjiEngine.h" // For KX_DebugOption. -#include -#include -#include - -#include "CTR_Map.h" -#include "CTR_HashedPtr.h" -#include "SG_IObject.h" +#include "SG_Node.h" +#include "SG_Frustum.h" #include "SCA_IScene.h" -#include "MT_Transform.h" +#include "RAS_Rasterizer.h" // For RAS_Rasterizer::DrawType. +#include "RAS_DebugDraw.h" #include "RAS_FramingManager.h" #include "RAS_Rect.h" - #include "EXP_PyObjectPlus.h" -#include "RAS_2DFilterManager.h" +#include "EXP_Value.h" -/** - * \section Forward declarations - */ -struct SM_MaterialProps; -struct SM_ShapeProps; -struct Scene; +#include -class CTR_HashedPtr; -class CListValue; -class CValue; +template +class EXP_ListValue; +class EXP_Value; class SCA_LogicManager; class SCA_KeyboardManager; class SCA_TimeEventManager; class SCA_MouseManager; -class SCA_ISystem; class SCA_IInputDevice; -class NG_NetworkDeviceInterface; -class NG_NetworkScene; -class SG_IObject; -class SG_Node; -class SG_Tree; +class SCA_JoystickManager; +class KX_NetworkMessageScene; +class KX_NetworkMessageManager; +class KX_2DFilterManager; +class KX_ObstacleSimulation; class KX_WorldInfo; class KX_Camera; +class KX_FontObject; class KX_GameObject; class KX_LightObject; +struct KX_ClientObjectInfo; +class BL_SceneConverter; +class SG_Node; +class PHY_IPhysicsEnvironment; +class RAS_Mesh; +class RAS_BoundingBoxManager; class RAS_BucketManager; class RAS_MaterialBucket; -class RAS_IPolyMaterial; -class RAS_IRasterizer; -class RAS_IRenderTools; -class SCA_JoystickManager; -class btCollisionShape; -class KX_BlenderSceneConverter; -struct KX_ClientObjectInfo; -class KX_ObstacleSimulation; +class RAS_IMaterial; +class RAS_Rasterizer; +class RAS_OffScreen; +class RAS_2DFilterManager; -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -/* for ID freeing */ -#define IS_TAGGED(_id) ((_id) && (((ID *)_id)->tag & LIB_TAG_DOIT)) +struct Scene; +struct TaskPool; -/** - * The KX_Scene holds all data for an independent scene. It relates - * KX_Objects to the specific objects in the modules. - * */ -class KX_Scene : public PyObjectPlus, public SCA_IScene +class KX_Scene : public EXP_Value, public SCA_IScene { +public: + enum DrawingCallbackType { + PRE_DRAW = 0, + POST_DRAW, + PRE_DRAW_SETUP, + MAX_DRAW_CALLBACK + }; + + struct AnimationPoolData + { + double curtime; + }; + + static SG_Callbacks m_callbacks; + +private: Py_Header #ifdef WITH_PYTHON - PyObject* m_attr_dict; - PyObject* m_draw_call_pre; - PyObject* m_draw_call_post; - PyObject* m_draw_setup_call_pre; + PyObject *m_attrDict; + PyObject *m_removeCallbacks; + PyObject *m_drawCallbacks[MAX_DRAW_CALLBACK]; #endif - struct CullingInfo { + struct CullingInfo + { int m_layer; - CullingInfo(int layer) : m_layer(layer) {} + std::vector& m_objects; + + CullingInfo(int layer, std::vector& objects) + :m_layer(layer), + m_objects(objects) + { + } }; -protected: - RAS_BucketManager* m_bucketmanager; - CListValue* m_tempObjectList; + KX_TextureRendererManager *m_rendererManager; + RAS_BucketManager *m_bucketmanager; + + /// Manager used to update all the mesh bounding box. + RAS_BoundingBoxManager *m_boundingBoxManager; + + std::vector m_tempObjectList; /** * The list of objects which have been removed during the * course of one frame. They are actually destroyed in * LogicEndFrame() via a call to RemoveObject(). */ - CListValue* m_euthanasyobjects; - - CListValue* m_objectlist; - CListValue* m_parentlist; // all 'root' parents - CListValue* m_lightlist; - CListValue* m_inactivelist; // all objects that are not in the active layer - CListValue* m_animatedlist; // all animated objects + std::vector m_euthanasyobjects; - SG_QList m_sghead; // list of nodes that needs scenegraph update - // the Dlist is not object that must be updated - // the Qlist is for objects that needs to be rescheduled - // for updates after udpate is over (slow parent, bone parent) + EXP_ListValue *m_objectlist; + /// All 'root' parents. + EXP_ListValue *m_parentlist; + EXP_ListValue *m_lightlist; + /// All objects that are not in the active layer. + EXP_ListValue *m_inactivelist; + /// All animated objects, no need of EXP_ListValue because the list isn't exposed in python. + std::vector m_animatedlist; + /// The list of cameras for this scene. + EXP_ListValue *m_cameralist; + /// The list of fonts for this scene. + EXP_ListValue *m_fontlist; /** - * The set of cameras for this scene + * List of nodes that needs scenegraph update + * the Dlist is not object that must be updated + * the Qlist is for objects that needs to be rescheduled + * for updates after udpate is over (slow parent, bone parent). */ - std::list m_cameras; + SG_QList m_sghead; - /** - * The set of fonts for this scene - */ - std::list m_fonts; + /// Various SCA managers used by the scene + SCA_LogicManager *m_logicmgr; + SCA_KeyboardManager *m_keyboardmgr; + SCA_MouseManager *m_mousemgr; + SCA_TimeEventManager *m_timemgr; + KX_PythonComponentManager m_componentManager; - /** - * Various SCA managers used by the scene - */ - SCA_LogicManager* m_logicmgr; - SCA_KeyboardManager* m_keyboardmgr; - SCA_MouseManager* m_mousemgr; - SCA_TimeEventManager* m_timemgr; - - // Scene converter where many scene entities are registered - // Used to deregister objects that are deleted - class KX_BlenderSceneConverter* m_sceneConverter; - /** - * physics engine abstraction - */ - //e_PhysicsEngine m_physicsEngine; //who needs this ? - class PHY_IPhysicsEnvironment* m_physicsEnvironment; + /// Physics engine abstraction. + PHY_IPhysicsEnvironment *m_physicsEnvironment; - /** - * Does this scene clear the z-buffer? - */ - bool m_isclearingZbuffer; - - /** - * Does the shadow buffer needs calculing - */ - bool m_isShadowDone; - - /** - * The name of the scene - */ - STR_String m_sceneName; - - /** - * stores the world-settings for a scene - */ - KX_WorldInfo* m_worldinfo; + /// The name of the scene. + std::string m_sceneName; - /** - * \section Different scenes, linked to ketsji scene - */ + /// Stores the world-settings for a scene. + KX_WorldInfo *m_worldinfo; - /** - * Network scene. - */ - NG_NetworkDeviceInterface* m_networkDeviceInterface; - NG_NetworkScene* m_networkScene; + /// Network scene. + KX_NetworkMessageScene *m_networkScene; - /** - * A temporary variable used to parent objects together on - * replication. Don't get confused by the name it is not - * the scene's root node! - */ - SG_Node* m_rootnode; - - /** - * The active camera for the scene - */ - KX_Camera* m_active_camera; + /// The active camera for the scene. + KX_Camera *m_activeCamera; + /// The active camera for scene culling. + KX_Camera *m_overrideCullingCamera; /** * Another temporary variable outstaying its welcome * used in AddReplicaObject to map game objects to their * replicas so pointers can be updated. */ - CTR_Map m_map_gameobject_to_replica; + std::map m_map_gameobject_to_replica; /** * Another temporary variable outstaying its welcome @@ -221,7 +199,7 @@ class KX_Scene : public PyObjectPlus, public SCA_IScene * objects. Logic can only be updated when all objects * have been updated. This stores a list of the new objects. */ - std::vector m_logicHierarchicalGameObjects; + std::vector m_logicHierarchicalGameObjects; /** * This temporary variable will contain the list of @@ -231,52 +209,29 @@ class KX_Scene : public PyObjectPlus, public SCA_IScene * Used in AddReplicaObject. If the list is empty, it * means don't care. */ - std::set m_groupGameObjects; + std::set m_groupGameObjects; - /** - * Pointer to system variable passed in in constructor - * only used in constructor so we do not need to keep it - * around in this class. - */ - - SCA_ISystem* m_kxsystem; - - /** - * The execution priority of replicated object actuators? - */ - int m_ueberExecutionPriority; + /// The execution priority of replicated object actuators. + int m_ueberExecutionPriority; /** * Activity 'bubble' settings : * Suspend (freeze) the entire scene. */ bool m_suspend; + double m_suspendedDelta; - /** - * Radius in Manhattan distance of the box for activity culling. - */ - float m_activity_box_radius; + /// Toggle to enable or disable object activity culling. + bool m_activityCulling; - /** - * Toggle to enable or disable activity culling. - */ - bool m_activity_culling; + /// Toggle to enable or disable culling via DBVT broadphase of Bullet. + bool m_dbvtCulling; - /** - * Toggle to enable or disable culling via DBVT broadphase of Bullet. - */ - bool m_dbvt_culling; + /// Occlusion culling resolution. + int m_dbvtOcclusionRes; - /** - * Occlusion culling resolution - */ - int m_dbvt_occlusion_res; - - /** - * The framing settings used by this scene - */ - - RAS_FrameSettings m_frame_settings; + /// The framing settings used by this scene + RAS_FrameSettings m_frameSettings; /** * This scenes viewport into the game engine @@ -284,225 +239,107 @@ class KX_Scene : public PyObjectPlus, public SCA_IScene */ RAS_Rect m_viewport; - /** - * Visibility testing functions. - */ - void MarkVisible(SG_Tree *node, RAS_IRasterizer* rasty, KX_Camera*cam,int layer=0); - void MarkSubTreeVisible(SG_Tree *node, RAS_IRasterizer* rasty, bool visible, KX_Camera*cam,int layer=0); - void MarkVisible(RAS_IRasterizer* rasty, KX_GameObject* gameobj, KX_Camera*cam, int layer=0); - static void PhysicsCullingCallback(KX_ClientObjectInfo* objectInfo, void* cullingInfo); + /// Debug drawing registering. + RAS_DebugDraw m_debugDraw; - double m_suspendedtime; - double m_suspendeddelta; + /// Visibility testing functions. + static void PhysicsCullingCallback(KX_ClientObjectInfo *objectInfo, void *cullingInfo); - struct Scene* m_blenderScene; + Scene *m_blenderScene; - RAS_2DFilterManager m_filtermanager; + KX_2DFilterManager *m_filterManager; - KX_ObstacleSimulation* m_obstacleSimulation; + KX_ObstacleSimulation *m_obstacleSimulation; - /** - * LOD Hysteresis settings - */ + AnimationPoolData m_animationPoolData; + TaskPool *m_animationPool; + double m_previousAnimTime; + + /// LOD Hysteresis settings. bool m_isActivedHysteresis; int m_lodHysteresisValue; -public: - KX_Scene(class SCA_IInputDevice* keyboarddevice, - class SCA_IInputDevice* mousedevice, - class NG_NetworkDeviceInterface* ndi, - const STR_String& scenename, - struct Scene* scene, - class RAS_ICanvas* canvas); - - virtual - ~KX_Scene(); + void RemoveNodeDestructObject(KX_GameObject *gameobj); + void RemoveObject(KX_GameObject *gameobj); + void RemoveDupliGroup(KX_GameObject *gameobj); + bool NewRemoveObject(KX_GameObject *gameobj); - RAS_BucketManager* GetBucketManager(); - RAS_MaterialBucket* FindBucket(RAS_IPolyMaterial* polymat, bool &bucketCreated); - void RenderBuckets(const MT_Transform& cameratransform, - RAS_IRasterizer* rasty); - - /** - * Update all transforms according to the scenegraph. - */ - static bool KX_ScenegraphUpdateFunc(SG_IObject* node,void* gameobj,void* scene); - static bool KX_ScenegraphRescheduleFunc(SG_IObject* node,void* gameobj,void* scene); - void UpdateParents(double curtime); - void DupliGroupRecurse(CValue* gameobj, int level); - bool IsObjectInGroup(CValue* gameobj) - { - return (m_groupGameObjects.empty() || - m_groupGameObjects.find(gameobj) != m_groupGameObjects.end()); - } - void AddObjectDebugProperties(class KX_GameObject* gameobj); - SCA_IObject* AddReplicaObject(CValue* gameobj, - CValue* locationobj, - int lifespan=0); - KX_GameObject* AddNodeReplicaObject(SG_IObject* node, - CValue* gameobj); - void RemoveNodeDestructObject(SG_IObject* node, - CValue* gameobj); - void RemoveObject(CValue* gameobj); - void RemoveDupliGroup(CValue *gameobj); - void DelayedRemoveObject(CValue* gameobj); - - int NewRemoveObject(CValue* gameobj); - void ReplaceMesh(CValue* gameobj, - void* meshob, bool use_gfx, bool use_phys); - - void AddAnimatedObject(CValue* gameobj); +public: + KX_Scene(SCA_IInputDevice *inputDevice, + const std::string& scenename, + Scene *scene, + RAS_ICanvas *canvas, + KX_NetworkMessageManager *messageManager); + virtual ~KX_Scene(); + + RAS_BucketManager *GetBucketManager() const; + KX_TextureRendererManager *GetTextureRendererManager() const; + RAS_BoundingBoxManager *GetBoundingBoxManager() const; + void RenderBuckets(const std::vector& objects, RAS_Rasterizer::DrawType drawingMode, + const mt::mat3x4& cameratransform, RAS_Rasterizer *rasty, RAS_OffScreen *offScreen); + void RenderTextureRenderers(KX_TextureRendererManager::RendererCategory category, RAS_Rasterizer *rasty, RAS_OffScreen *offScreen, + KX_Camera *sceneCamera, const RAS_Rect& viewport, const RAS_Rect& area); + + /// Update all transforms according to the scenegraph. + static bool KX_ScenegraphUpdateFunc(SG_Node *node, void *gameobj, void *scene); + static bool KX_ScenegraphRescheduleFunc(SG_Node *node, void *gameobj, void *scene); + /// SceneGraph transformation update. + void UpdateParents(); + + void DupliGroupRecurse(KX_GameObject *groupobj, int level); + bool IsObjectInGroup(KX_GameObject *gameobj) const; + void AddObjectDebugProperties(KX_GameObject *gameobj); + KX_GameObject *AddReplicaObject(KX_GameObject *gameobj, KX_GameObject *locationobj, float lifespan = 0.0f); + KX_GameObject *AddNodeReplicaObject(SG_Node *node, KX_GameObject *gameobj); + + /// Add an object to remove. + void DelayedRemoveObject(KX_GameObject *gameobj); + /// Effectivly remove object added with DelayedRemoveObject + void RemoveEuthanasyObjects(); + + void AddAnimatedObject(KX_GameObject *gameobj); /** * \section Logic stuff * Initiate an update of the logic system. */ - void LogicBeginFrame(double curtime); - void LogicUpdateFrame(double curtime, bool frame); - void UpdateAnimations(double curtime); - - void - LogicEndFrame( - ); - - CListValue* - GetTempObjectList( - ); - - CListValue* - GetObjectList( - ); - - CListValue* - GetInactiveList( - ); - - CListValue* - GetRootParentList( - ); - - CListValue* - GetLightList( - ); - - SCA_LogicManager * - GetLogicManager( - ); - - SCA_TimeEventManager * - GetTimeEventManager( - ); - - /** Font Routines */ - - /** Find a font in the scene by pointer. */ - KX_FontObject* - FindFont( - KX_FontObject* - ); - - /** Add a camera to this scene. */ - void - AddFont( - KX_FontObject* - ); - - /** Render the fonts in this scene. */ - void - RenderFonts( - ); - - /** Camera Routines */ - - std::list* - GetCameras( - ); - - - /** Find a camera in the scene by pointer. */ - KX_Camera* - FindCamera( - KX_Camera* - ); - - /** Find a scene in the scene by name. */ - KX_Camera* - FindCamera( - STR_String& - ); - - /** Add a camera to this scene. */ - void - AddCamera( - KX_Camera* - ); - - /** Find the currently active camera. */ - KX_Camera* - GetActiveCamera( - ); + void LogicBeginFrame(double curtime, double framestep); + void LogicUpdateFrame(double curtime); + void UpdateAnimations(double curtime, bool restrict); + + void LogicEndFrame(); + + EXP_ListValue *GetObjectList() const; + EXP_ListValue *GetInactiveList() const; + EXP_ListValue *GetRootParentList() const; + EXP_ListValue *GetLightList() const; + EXP_ListValue *GetCameraList() const; + EXP_ListValue *GetFontList() const; + + SCA_LogicManager *GetLogicManager() const; + SCA_TimeEventManager *GetTimeEventManager() const; + KX_PythonComponentManager& GetPythonComponentManager(); + + /// Return the currently active camera. + KX_Camera *GetActiveCamera(); /** * Set this camera to be the active camera in the scene. If the * camera is not present in the camera list, it will be added */ + void SetActiveCamera(KX_Camera *camera); - void - SetActiveCamera( - class KX_Camera* - ); + KX_Camera *GetOverrideCullingCamera() const; + void SetOverrideCullingCamera(KX_Camera *cam); /** * Move this camera to the end of the list so that it is rendered last. * If the camera is not on the list, it will be added */ - void - SetCameraOnTop( - class KX_Camera* - ); + void SetCameraOnTop(KX_Camera *camera); - /** - * Activates new desired canvas width set at design time. - * \param width The new desired width. - */ - void - SetCanvasDesignWidth( - unsigned int width - ); - /** - * Activates new desired canvas height set at design time. - * \param width The new desired height. - */ - void - SetCanvasDesignHeight( - unsigned int height - ); - /** - * Returns the current desired canvas width set at design time. - * \return The desired width. - */ - unsigned int - GetCanvasDesignWidth( - void - ) const; - - /** - * Returns the current desired canvas height set at design time. - * \return The desired height. - */ - unsigned int - GetCanvasDesignHeight( - void - ) const; - - /** - * Set the framing options for this scene - */ - - void - SetFramingType( - RAS_FrameSettings & frame_settings - ); + /// Set the framing options for this scene. + void SetFramingType(const RAS_FrameSettings& frameSettings); /** * Return a const reference to the framing @@ -510,46 +347,29 @@ class KX_Scene : public PyObjectPlus, public SCA_IScene * The contents are not guaranteed to be sensible * if you don't call the above function. */ - - const - RAS_FrameSettings & - GetFramingType( - ) const; - - /** - * Store the current scene's viewport on the - * game engine canvas. - */ - void SetSceneViewport(const RAS_Rect &viewport); - - /** - * Get the current scene's viewport on the - * game engine canvas. This maintained - * externally in KX_GameEngine - */ - const RAS_Rect& GetSceneViewport() const; + const RAS_FrameSettings &GetFramingType() const; /** * \section Accessors to different scenes of this scene */ - void SetNetworkDeviceInterface(NG_NetworkDeviceInterface* newInterface); - void SetNetworkScene(NG_NetworkScene *newScene); - void SetWorldInfo(class KX_WorldInfo* wi); - KX_WorldInfo* GetWorldInfo(); - void CalculateVisibleMeshes(RAS_IRasterizer* rasty, KX_Camera *cam, int layer=0); - KX_Camera* GetpCamera(); - NG_NetworkDeviceInterface* GetNetworkDeviceInterface(); - NG_NetworkScene* GetNetworkScene(); - KX_BlenderSceneConverter *GetSceneConverter() { return m_sceneConverter; } + void SetNetworkMessageScene(KX_NetworkMessageScene *netScene); + KX_NetworkMessageScene *GetNetworkMessageScene() const; - /** - * Replicate the logic bricks associated to this object. - */ + void SetWorldInfo(KX_WorldInfo *wi); + KX_WorldInfo *GetWorldInfo() const; - void ReplicateLogic(class KX_GameObject* newobj); - static SG_Callbacks m_callbacks; + std::vector CalculateVisibleMeshes(KX_Camera *cam, int layer); + std::vector CalculateVisibleMeshes(const SG_Frustum& frustum, int layer); - const STR_String& GetName(); + RAS_DebugDraw& GetDebugDraw(); + /// \section Debug draw. + void DrawDebug(const std::vector& objects, + KX_DebugOption showBoundingBox, KX_DebugOption showArmatures); + void RenderDebugProperties(RAS_DebugDraw& debugDraw, int xindent, int ysize, int& xcoord, int& ycoord, unsigned short propsMax); + void FlushDebugDraw(RAS_Rasterizer *rasty, RAS_ICanvas *canvas); + + /// Replicate the logic bricks associated to this object. + void ReplicateLogic(KX_GameObject *newobj); // Suspend the entire scene. void Suspend(); @@ -557,141 +377,107 @@ class KX_Scene : public PyObjectPlus, public SCA_IScene // Resume a suspended scene. void Resume(); - // Update the mesh for objects based on level of detail settings - void UpdateObjectLods(void); + /// Update the mesh for objects based on level of detail settings + void UpdateObjectLods(KX_Camera *cam, const std::vector& objects); // LoD Hysteresis functions void SetLodHysteresis(bool active); - bool IsActivedLodHysteresis(); + bool IsActivedLodHysteresis() const; void SetLodHysteresisValue(int hysteresisvalue); - int GetLodHysteresisValue(); - - // Update the activity box settings for objects in this scene, if needed. - void UpdateObjectActivity(void); + int GetLodHysteresisValue() const; - // Enable/disable activity culling. + /// Update the activity culling of objects in this scene, if needed. + void UpdateObjectActivity(); + /// Enable/disable activity culling. void SetActivityCulling(bool b); - // Set the radius of the activity culling box. - void SetActivityCullingRadius(float f); - bool IsSuspended(); - bool IsClearingZBuffer(); - void EnableZBufferClearing(bool isclearingZbuffer); - bool IsShadowDone() { return m_isShadowDone; } - void SetShadowDone(bool b) { m_isShadowDone = b; } - // use of DBVT tree for camera culling - void SetDbvtCulling(bool b) { m_dbvt_culling = b; } - bool GetDbvtCulling() { return m_dbvt_culling; } - void SetDbvtOcclusionRes(int i) { m_dbvt_occlusion_res = i; } - int GetDbvtOcclusionRes() { return m_dbvt_occlusion_res; } - - void SetSceneConverter(class KX_BlenderSceneConverter* sceneConverter); - - class PHY_IPhysicsEnvironment* GetPhysicsEnvironment() - { - return m_physicsEnvironment; - } - - void SetPhysicsEnvironment(class PHY_IPhysicsEnvironment* physEnv); + bool IsSuspended() const; - void SetGravity(const MT_Vector3& gravity); - MT_Vector3 GetGravity(); + /// Use of DBVT tree for camera culling + void SetDbvtCulling(bool b); + bool GetDbvtCulling() const; + void SetDbvtOcclusionRes(int i); + int GetDbvtOcclusionRes() const; - short GetAnimationFPS(); + void SetSceneConverter(BL_SceneConverter *sceneConverter); - /** - * Sets the node tree for this scene. - */ - void SetNodeTree(SG_Tree* root); - - /** - * 2D Filters - */ - void Update2DFilter(std::vector& propNames, void* gameObj, RAS_2DFilterManager::RAS_2DFILTER_MODE filtermode, int pass, STR_String& text); - void Render2DFilters(RAS_ICanvas* canvas); + PHY_IPhysicsEnvironment *GetPhysicsEnvironment() const; + void SetPhysicsEnvironment(PHY_IPhysicsEnvironment *physEnv); - KX_ObstacleSimulation* GetObstacleSimulation() { return m_obstacleSimulation; } - -#ifdef WITH_PYTHON - /* --------------------------------------------------------------------- */ - /* Python interface ---------------------------------------------------- */ - /* --------------------------------------------------------------------- */ - - KX_PYMETHOD_DOC(KX_Scene, addObject); - KX_PYMETHOD_DOC(KX_Scene, end); - KX_PYMETHOD_DOC(KX_Scene, restart); - KX_PYMETHOD_DOC(KX_Scene, replace); - KX_PYMETHOD_DOC(KX_Scene, suspend); - KX_PYMETHOD_DOC(KX_Scene, resume); - KX_PYMETHOD_DOC(KX_Scene, get); - KX_PYMETHOD_DOC(KX_Scene, drawObstacleSimulation); - - - /* attributes */ - static PyObject* pyattr_get_name(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_objects(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_objects_inactive(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_lights(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_cameras(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_world(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject* pyattr_get_active_camera(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_active_camera(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_drawing_callback_pre(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_drawing_callback_pre(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_drawing_callback_post(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_drawing_callback_post(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_drawing_setup_callback_pre(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_drawing_setup_callback_pre(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject* pyattr_get_gravity(void* self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_gravity(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - - virtual PyObject *py_repr(void) { return PyUnicode_From_STR_String(GetName()); } - - /* getitem/setitem */ - static PyMappingMethods Mapping; - static PySequenceMethods Sequence; + void SetGravity(const mt::vec3& gravity); + mt::vec3 GetGravity() const; - /** - * Run the registered python drawing functions. - */ - void RunDrawingCallbacks(PyObject *cb_list); - - PyObject *GetPreDrawCB() { return m_draw_call_pre; } - PyObject *GetPostDrawCB() { return m_draw_call_post; } - PyObject *GetPreDrawSetupCB() { return m_draw_setup_call_pre; } -#endif - - /** - * Sets the time the scene was suspended - */ - void setSuspendedTime(double suspendedtime); - /** - * Returns the "curtime" the scene was suspended - */ - double getSuspendedTime(); /** * Sets the difference between the local time of the scene (when it * was running and not suspended) and the "curtime" */ - void setSuspendedDelta(double suspendeddelta); + void SetSuspendedDelta(double suspendeddelta); /** * Returns the difference between the local time of the scene (when it * was running and not suspended) and the "curtime" */ - double getSuspendedDelta(); - /** - * Returns the Blender scene this was made from - */ - struct Scene *GetBlenderScene() { return m_blenderScene; } + double GetSuspendedDelta() const; + + /// Returns the Blender scene this was made from. + Scene *GetBlenderScene() const; bool MergeScene(KX_Scene *other); + /// 2D Filters. + KX_2DFilterManager *Get2DFilterManager() const; + RAS_OffScreen *Render2DFilters(RAS_Rasterizer *rasty, RAS_ICanvas *canvas, RAS_OffScreen *inputofs, RAS_OffScreen *targetofs); + + KX_ObstacleSimulation *GetObstacleSimulation(); + void SetObstacleSimulation(KX_ObstacleSimulation *obstacleSimulation); + + virtual std::string GetName(); + virtual void SetName(const std::string& name); + +#ifdef WITH_PYTHON - //void PrintStats(int verbose_level) { - // m_bucketmanager->PrintStats(verbose_level) - //} + EXP_PYMETHOD_DOC(KX_Scene, addObject); + EXP_PYMETHOD_DOC(KX_Scene, end); + EXP_PYMETHOD_DOC(KX_Scene, restart); + EXP_PYMETHOD_DOC(KX_Scene, replace); + EXP_PYMETHOD_DOC(KX_Scene, suspend); + EXP_PYMETHOD_DOC(KX_Scene, resume); + EXP_PYMETHOD_DOC(KX_Scene, get); + EXP_PYMETHOD_DOC(KX_Scene, drawObstacleSimulation); + + // Attributes. + static PyObject *pyattr_get_name(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_objects(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_objects_inactive(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_lights(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_texts(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_cameras(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_filter_manager(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_world(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_active_camera(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_active_camera(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_overrideCullingCamera(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_overrideCullingCamera(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_drawing_callback(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_drawing_callback(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_remove_callback(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_remove_callback(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_gravity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_gravity(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + + // getitem/setitem + static PyMappingMethods Mapping; + static PySequenceMethods Sequence; + + /// Run the registered python drawing functions. + void RunDrawingCallbacks(DrawingCallbackType callbackType, KX_Camera *camera); + + // Run the registered python callbacks when the scene is removed. + void RunOnRemoveCallbacks(); +#endif }; -typedef std::vector KX_SceneList; +#ifdef WITH_PYTHON +bool ConvertPythonToScene(PyObject *value, KX_Scene **scene, bool py_none_ok, const char *error_prefix); +#endif -#endif /* __KX_SCENE_H__ */ +#endif // __KX_SCENE_H__ diff --git a/source/gameengine/Ketsji/KX_SceneActuator.cpp b/source/gameengine/Ketsji/KX_SceneActuator.cpp index 2bef9237bb40..65e3073e4106 100644 --- a/source/gameengine/Ketsji/KX_SceneActuator.cpp +++ b/source/gameengine/Ketsji/KX_SceneActuator.cpp @@ -39,70 +39,74 @@ #include "KX_Scene.h" #include "KX_Camera.h" #include "KX_KetsjiEngine.h" +#include "KX_Globals.h" /* ------------------------------------------------------------------------- */ /* Native functions */ /* ------------------------------------------------------------------------- */ KX_SceneActuator::KX_SceneActuator(SCA_IObject *gameobj, - int mode, - KX_Scene *scene, - KX_KetsjiEngine* ketsjiEngine, - const STR_String& nextSceneName, - KX_Camera* camera) - : SCA_IActuator(gameobj, KX_ACT_SCENE) + int mode, + KX_Scene *scene, + KX_KetsjiEngine *ketsjiEngine, + const std::string& nextSceneName, + KX_Camera *camera) + :SCA_IActuator(gameobj, KX_ACT_SCENE) { m_mode = mode; m_scene = scene; - m_KetsjiEngine=ketsjiEngine; + m_KetsjiEngine = ketsjiEngine; m_camera = camera; m_nextSceneName = nextSceneName; - if (m_camera) + if (m_camera) { m_camera->RegisterActuator(this); + } } /* End of constructor */ KX_SceneActuator::~KX_SceneActuator() { - if (m_camera) + if (m_camera) { m_camera->UnregisterActuator(this); + } } /* end of destructor */ -CValue* KX_SceneActuator::GetReplica() +EXP_Value *KX_SceneActuator::GetReplica() { - KX_SceneActuator* replica = new KX_SceneActuator(*this); + KX_SceneActuator *replica = new KX_SceneActuator(*this); replica->ProcessReplica(); return replica; } void KX_SceneActuator::ProcessReplica() { - if (m_camera) + if (m_camera) { m_camera->RegisterActuator(this); + } SCA_IActuator::ProcessReplica(); } -bool KX_SceneActuator::UnlinkObject(SCA_IObject* clientobj) +bool KX_SceneActuator::UnlinkObject(SCA_IObject *clientobj) { - if (clientobj == (SCA_IObject*)m_camera) - { + if (clientobj == (SCA_IObject *)m_camera) { // this object is being deleted, we cannot continue to track it. - m_camera = NULL; + m_camera = nullptr; return true; } return false; } -void KX_SceneActuator::Relink(CTR_Map *obj_map) +void KX_SceneActuator::Relink(std::map& obj_map) { - void **h_obj = (*obj_map)[m_camera]; - if (h_obj) { - if (m_camera) + KX_Camera *obj = static_cast(obj_map[m_camera]); + if (obj) { + if (m_camera) { m_camera->UnregisterActuator(this); - m_camera = (KX_Camera*)(*h_obj); + } + m_camera = obj; m_camera->RegisterActuator(this); } } @@ -114,106 +118,81 @@ bool KX_SceneActuator::Update() bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); - if (bNegativeEvent) + if (bNegativeEvent) { return false; // do nothing on negative events - switch (m_mode) - { - case KX_SCENE_RESTART: + } + switch (m_mode) { + case KX_SCENE_RESTART: { - m_KetsjiEngine->ReplaceScene(m_scene->GetName(),m_scene->GetName()); + m_KetsjiEngine->ReplaceScene(m_scene->GetName(), m_scene->GetName()); break; } - case KX_SCENE_SET_CAMERA: - if (m_camera) + case KX_SCENE_SET_CAMERA: { - m_scene->SetActiveCamera(m_camera); + if (m_camera) { + m_scene->SetActiveCamera(m_camera); + } + else { + // if no camera is set and the parent object is a camera, use it as the camera + SCA_IObject *parent = GetParent(); + if (parent->GetGameObjectType() == SCA_IObject::OBJ_CAMERA) { + m_scene->SetActiveCamera((KX_Camera *)parent); + } + } + break; } - else + default: { - // if no camera is set and the parent object is a camera, use it as the camera - SCA_IObject* parent = GetParent(); - if (parent->GetGameObjectType()==SCA_IObject::OBJ_CAMERA) - { - m_scene->SetActiveCamera((KX_Camera*)parent); - } + break; } - break; - default: - break; } - if (!m_nextSceneName.Length()) + if (!m_nextSceneName.size()) { return false; + } - switch (m_mode) - { - case KX_SCENE_SET_SCENE: + switch (m_mode) { + case KX_SCENE_SET_SCENE: { - m_KetsjiEngine->ReplaceScene(m_scene->GetName(),m_nextSceneName); + m_KetsjiEngine->ReplaceScene(m_scene->GetName(), m_nextSceneName); break; } - case KX_SCENE_ADD_FRONT_SCENE: + case KX_SCENE_ADD_FRONT_SCENE: { - bool overlay=true; - m_KetsjiEngine->ConvertAndAddScene(m_nextSceneName,overlay); + bool overlay = true; + m_KetsjiEngine->ConvertAndAddScene(m_nextSceneName, overlay); break; } - case KX_SCENE_ADD_BACK_SCENE: + case KX_SCENE_ADD_BACK_SCENE: { - bool overlay=false; - m_KetsjiEngine->ConvertAndAddScene(m_nextSceneName,overlay); + bool overlay = false; + m_KetsjiEngine->ConvertAndAddScene(m_nextSceneName, overlay); break; } - case KX_SCENE_REMOVE_SCENE: + case KX_SCENE_REMOVE_SCENE: { m_KetsjiEngine->RemoveScene(m_nextSceneName); break; } - case KX_SCENE_SUSPEND: + case KX_SCENE_SUSPEND: { m_KetsjiEngine->SuspendScene(m_nextSceneName); break; } - case KX_SCENE_RESUME: + case KX_SCENE_RESUME: { m_KetsjiEngine->ResumeScene(m_nextSceneName); break; } - default: - ; /* do nothing? this is an internal error !!! */ + default: + ; /* do nothing? this is an internal error !!! */ } return false; } - -/* returns a camera if the name is valid */ -KX_Camera* KX_SceneActuator::FindCamera(const char *camName) -{ - KX_SceneList* sl = m_KetsjiEngine->CurrentScenes(); - STR_String name = STR_String(camName); - KX_SceneList::iterator it = sl->begin(); - KX_Camera* cam = NULL; - - while ((it != sl->end()) && (!cam)) - { - cam = (*it)->FindCamera(name); - it++; - } - - return cam; -} - - - -KX_Scene* KX_SceneActuator::FindScene(const char *sceneName) -{ - return m_KetsjiEngine->FindScene(sceneName); -} - - #ifdef WITH_PYTHON /* ------------------------------------------------------------------------- */ @@ -222,9 +201,9 @@ KX_Scene* KX_SceneActuator::FindScene(const char *sceneName) /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_SceneActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_SceneActuator", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -232,52 +211,55 @@ PyTypeObject KX_SceneActuator::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IActuator::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_SceneActuator::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_SceneActuator::Attributes[] = { - KX_PYATTRIBUTE_STRING_RW("scene",0,MAX_ID_NAME-2,true,KX_SceneActuator,m_nextSceneName), - KX_PYATTRIBUTE_RW_FUNCTION("camera",KX_SceneActuator,pyattr_get_camera,pyattr_set_camera), - KX_PYATTRIBUTE_BOOL_RW("useRestart", KX_SceneActuator, m_restart), - KX_PYATTRIBUTE_INT_RW("mode", KX_SCENE_NODEF+1, KX_SCENE_MAX-1, true, KX_SceneActuator, m_mode), - { NULL } //Sentinel + EXP_PYATTRIBUTE_STRING_RW("scene", 0, MAX_ID_NAME - 2, true, KX_SceneActuator, m_nextSceneName), + EXP_PYATTRIBUTE_RW_FUNCTION("camera", KX_SceneActuator, pyattr_get_camera, pyattr_set_camera), + EXP_PYATTRIBUTE_BOOL_RW("useRestart", KX_SceneActuator, m_restart), + EXP_PYATTRIBUTE_INT_RW("mode", KX_SCENE_NODEF + 1, KX_SCENE_MAX - 1, true, KX_SceneActuator, m_mode), + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *KX_SceneActuator::pyattr_get_camera(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_SceneActuator::pyattr_get_camera(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - KX_SceneActuator* actuator = static_cast(self); - if (!actuator->m_camera) + KX_SceneActuator *actuator = static_cast(self); + if (!actuator->m_camera) { Py_RETURN_NONE; + } return actuator->m_camera->GetProxy(); } -int KX_SceneActuator::pyattr_set_camera(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_SceneActuator::pyattr_set_camera(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_SceneActuator* actuator = static_cast(self); + KX_SceneActuator *actuator = static_cast(self); KX_Camera *camOb; - if (!ConvertPythonToCamera(value, &camOb, true, "actu.camera = value: KX_SceneActuator")) + if (!ConvertPythonToCamera(KX_GetActiveScene(), value, &camOb, true, "actu.camera = value: KX_SceneActuator")) { return PY_SET_ATTR_FAIL; + } - if (actuator->m_camera) + if (actuator->m_camera) { actuator->m_camera->UnregisterActuator(actuator); + } - if (camOb==NULL) { - actuator->m_camera= NULL; + if (camOb == nullptr) { + actuator->m_camera = nullptr; } else { actuator->m_camera = camOb; diff --git a/source/gameengine/Ketsji/KX_SceneActuator.h b/source/gameengine/Ketsji/KX_SceneActuator.h index c83a0a3a11c5..92ab3c083267 100644 --- a/source/gameengine/Ketsji/KX_SceneActuator.h +++ b/source/gameengine/Ketsji/KX_SceneActuator.h @@ -39,7 +39,7 @@ class KX_SceneActuator : public SCA_IActuator { Py_Header - + int m_mode; // (restart) has become a toggle internally... not in the interface though bool m_restart; @@ -48,16 +48,11 @@ class KX_SceneActuator : public SCA_IActuator class KX_Scene* m_scene; class KX_KetsjiEngine* m_KetsjiEngine; /** The scene to switch to. */ - STR_String m_nextSceneName; - + std::string m_nextSceneName; + // (Set Camera) Object class KX_Camera* m_camera; - /** Is this a valid scene? */ - class KX_Scene* FindScene(const char* sceneName); - /** Is this a valid camera? */ - class KX_Camera* FindCamera(const char* cameraName); - public: enum SCA_SceneActuatorMode { @@ -72,22 +67,22 @@ class KX_SceneActuator : public SCA_IActuator KX_SCENE_RESUME, KX_SCENE_MAX }; - + KX_SceneActuator(SCA_IObject* gameobj, int mode, KX_Scene* scene, KX_KetsjiEngine* ketsjiEngine, - const STR_String& nextSceneName, + const std::string& nextSceneName, KX_Camera* camera); virtual ~KX_SceneActuator(); - virtual CValue* GetReplica(); + virtual EXP_Value* GetReplica(); virtual void ProcessReplica(); virtual bool UnlinkObject(SCA_IObject* clientobj); - virtual void Relink(CTR_Map *obj_map); + virtual void Relink(std::map& obj_map); virtual bool Update(); - + #ifdef WITH_PYTHON virtual void Replace_IScene(SCA_IScene *val) @@ -98,9 +93,9 @@ class KX_SceneActuator : public SCA_IActuator /* --------------------------------------------------------------------- */ /* Python interface ---------------------------------------------------- */ /* --------------------------------------------------------------------- */ - - static PyObject *pyattr_get_camera(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_camera(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); + + static PyObject *pyattr_get_camera(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_camera(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); #endif /* WITH_PYTHON */ diff --git a/source/gameengine/Ketsji/KX_SoftBodyDeformer.cpp b/source/gameengine/Ketsji/KX_SoftBodyDeformer.cpp new file mode 100644 index 000000000000..ae4282e6ee50 --- /dev/null +++ b/source/gameengine/Ketsji/KX_SoftBodyDeformer.cpp @@ -0,0 +1,136 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Converter/KX_SoftBodyDeformer.cpp + * \ingroup bgeconv + */ + + +#ifdef _MSC_VER +# pragma warning (disable:4786) +#endif //WIN32 + +#include "BLI_utildefines.h" + +#include "KX_SoftBodyDeformer.h" +#include "KX_Mesh.h" +#include "KX_GameObject.h" + +#include "RAS_DisplayArray.h" +#include "RAS_BoundingBoxManager.h" + +#ifdef WITH_BULLET + +#include "CcdPhysicsEnvironment.h" +#include "CcdPhysicsController.h" +#include "BulletSoftBody/btSoftBody.h" + +#include "btBulletDynamicsCommon.h" + +KX_SoftBodyDeformer::KX_SoftBodyDeformer(RAS_Mesh *pMeshObject, KX_GameObject *gameobj) + :RAS_Deformer(pMeshObject), + m_gameobj(gameobj), + m_needUpdateAabb(true) +{ + KX_Scene *scene = m_gameobj->GetScene(); + RAS_BoundingBoxManager *boundingBoxManager = scene->GetBoundingBoxManager(); + m_boundingBox = boundingBoxManager->CreateBoundingBox(); + // Set AABB default to mesh bounding box AABB. + m_boundingBox->CopyAabb(m_mesh->GetBoundingBox()); +} + +KX_SoftBodyDeformer::~KX_SoftBodyDeformer() +{ +} + +void KX_SoftBodyDeformer::Apply(RAS_DisplayArray *array) +{ + CcdPhysicsController *ctrl = (CcdPhysicsController *)m_gameobj->GetPhysicsController(); + if (!ctrl) { + return; + } + + btSoftBody *softBody = ctrl->GetSoftBody(); + if (!softBody) { + return; + } + + // update the vertex in m_transverts + Update(); + + btSoftBody::tNodeArray& nodes(softBody->m_nodes); + const std::vector& indices = ctrl->GetSoftBodyIndices(); + + // AABB Box : min/max. + mt::vec3 aabbMin(FLT_MAX); + mt::vec3 aabbMax(-FLT_MAX); + + if (m_needUpdateAabb) { + m_boundingBox->SetAabb(aabbMin, aabbMax); + m_needUpdateAabb = false; + } + + const mt::mat3x4 invtrans = m_gameobj->NodeGetWorldTransform().Inverse(); + const bool autoUpdate = m_gameobj->GetAutoUpdateBounds(); + + for (unsigned int i = 0, size = array->GetVertexCount(); i < size; ++i) { + const RAS_VertexInfo& vinfo = array->GetVertexInfo(i); + + const unsigned int index = indices[vinfo.GetOrigIndex()]; + const mt::vec3 pos = ToMt(nodes[index].m_x); + + array->SetPosition(i, pos); + array->SetNormal(i, ToMt(nodes[index].m_n)); + + if (autoUpdate) { + // Extract object transform from the vertex position. + const mt::vec3 ptWorld = invtrans * pos; + aabbMin = mt::vec3::Min(aabbMin, ptWorld); + aabbMax = mt::vec3::Max(aabbMax, ptWorld); + } + } + + for (DisplayArraySlot& slot : m_slots) { + if (slot.m_displayArray == array) { + const short modifiedFlag = slot.m_arrayUpdateClient.GetInvalidAndClear(); + if (modifiedFlag != RAS_DisplayArray::NONE_MODIFIED) { + /// Update vertex data from the original mesh. + array->UpdateFrom(slot.m_origDisplayArray, modifiedFlag); + } + + break; + } + } + + array->NotifyUpdate(RAS_DisplayArray::POSITION_MODIFIED | RAS_DisplayArray::NORMAL_MODIFIED); + + if (autoUpdate) { + m_boundingBox->ExtendAabb(aabbMin, aabbMax); + } +} + +#endif diff --git a/source/gameengine/Converter/KX_SoftBodyDeformer.h b/source/gameengine/Ketsji/KX_SoftBodyDeformer.h similarity index 59% rename from source/gameengine/Converter/KX_SoftBodyDeformer.h rename to source/gameengine/Ketsji/KX_SoftBodyDeformer.h index d70a736e8b2e..7107b4dbb966 100644 --- a/source/gameengine/Converter/KX_SoftBodyDeformer.h +++ b/source/gameengine/Ketsji/KX_SoftBodyDeformer.h @@ -37,65 +37,40 @@ #endif #include "RAS_Deformer.h" -#include "BL_DeformableGameObject.h" -#include +class KX_GameObject; class KX_SoftBodyDeformer : public RAS_Deformer { - class RAS_MeshObject* m_pMeshObject; - class BL_DeformableGameObject* m_gameobj; + KX_GameObject *m_gameobj; + /** Set to true to request an AABB update in Apply(mat). + * Used to compute a fully AABB and not for only one material. + */ + bool m_needUpdateAabb; public: - KX_SoftBodyDeformer(RAS_MeshObject* pMeshObject,BL_DeformableGameObject* gameobj) - :m_pMeshObject(pMeshObject), - m_gameobj(gameobj) - { - //printf("KX_SoftBodyDeformer\n"); - }; + KX_SoftBodyDeformer(RAS_Mesh *pMeshObject, KX_GameObject *gameobj); + virtual ~KX_SoftBodyDeformer(); - virtual ~KX_SoftBodyDeformer() - { - //printf("~KX_SoftBodyDeformer\n"); - }; - virtual void Relink(CTR_Map*map); - virtual bool Apply(class RAS_IPolyMaterial *polymat); - virtual bool Update(void) + virtual void Apply(RAS_DisplayArray *array); + virtual bool Update() { - //printf("update\n"); m_bDynamic = true; - return true;//?? + return true; } - virtual bool UpdateBuckets(void) + virtual void UpdateBuckets() { + // invalidate the AABB for each read acces. + m_needUpdateAabb = true; // this is to update the mesh slots outside the rasterizer, // no need to do it for this deformer, it's done in any case in Apply() - return false; } - virtual RAS_Deformer *GetReplica() - { - KX_SoftBodyDeformer* deformer = new KX_SoftBodyDeformer(*this); - deformer->ProcessReplica(); - return deformer; - } - virtual void ProcessReplica() - { - // we have two pointers to deal with but we cannot do it now, will be done in Relink - m_bDynamic = false; - } virtual bool SkipVertexTransform() { return true; } - -protected: - //class RAS_MeshObject *m_pMesh; - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_ShapeDeformer") -#endif }; - #endif + diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp index 13549148993c..b6b3107058af 100644 --- a/source/gameengine/Ketsji/KX_SoundActuator.cpp +++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp @@ -49,24 +49,28 @@ typedef float sample_t; #include "KX_GameObject.h" #include "KX_PyMath.h" // needed for PyObjectFrom() -#include "KX_PythonInit.h" +#include "KX_Globals.h" #include "KX_Camera.h" #include /* ------------------------------------------------------------------------- */ /* Native functions */ /* ------------------------------------------------------------------------- */ -KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj, - AUD_Sound* sound, - float volume, - float pitch, - bool is3d, - KX_3DSoundSettings settings, - KX_SOUNDACT_TYPE type)//, - : SCA_IActuator(gameobj, KX_ACT_SOUND) +KX_SoundActuator::KX_SoundActuator(SCA_IObject *gameobj, +#ifdef WITH_AUDASPACE + AUD_Sound *sound, +#endif // WITH_AUDASPACE + float volume, + float pitch, + bool is3d, + KX_3DSoundSettings settings, + KX_SOUNDACT_TYPE type)//, + :SCA_IActuator(gameobj, KX_ACT_SOUND) { - m_sound = sound ? AUD_Sound_copy(sound) : NULL; - m_handle = NULL; +#ifdef WITH_AUDASPACE + m_sound = sound ? AUD_Sound_copy(sound) : nullptr; + m_handle = nullptr; +#endif // WITH_AUDASPACE m_volume = volume; m_pitch = pitch; m_is3d = is3d; @@ -79,6 +83,7 @@ KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj, KX_SoundActuator::~KX_SoundActuator() { +#ifdef WITH_AUDASPACE if (m_handle) { AUD_Handle_stop(m_handle); } @@ -86,48 +91,57 @@ KX_SoundActuator::~KX_SoundActuator() if (m_sound) { AUD_Sound_free(m_sound); } +#endif // WITH_AUDASPACE } void KX_SoundActuator::play() { +#ifdef WITH_AUDASPACE if (m_handle) { AUD_Handle_stop(m_handle); - m_handle = NULL; + m_handle = nullptr; } - if (!m_sound) + if (!m_sound) { return; + } // this is the sound that will be played and not deleted afterwards - AUD_Sound* sound = m_sound; + AUD_Sound *sound = m_sound; bool loop = false; - switch (m_type) - { - case KX_SOUNDACT_LOOPBIDIRECTIONAL: - case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP: - sound = AUD_Sound_pingpong(sound); - ATTR_FALLTHROUGH; - case KX_SOUNDACT_LOOPEND: - case KX_SOUNDACT_LOOPSTOP: - loop = true; - break; - case KX_SOUNDACT_PLAYSTOP: - case KX_SOUNDACT_PLAYEND: - default: - break; - } - - AUD_Device* device = AUD_Device_getCurrent(); + switch (m_type) { + case KX_SOUNDACT_LOOPBIDIRECTIONAL: + case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP: + { + sound = AUD_Sound_pingpong(sound); + ATTR_FALLTHROUGH; + } + case KX_SOUNDACT_LOOPEND: + case KX_SOUNDACT_LOOPSTOP: + { + loop = true; + break; + } + case KX_SOUNDACT_PLAYSTOP: + case KX_SOUNDACT_PLAYEND: + default: + { + break; + } + } + + AUD_Device *device = AUD_Device_getCurrent(); m_handle = AUD_Device_play(device, sound, false); AUD_Device_free(device); // in case of pingpong, we have to free the sound - if (sound != m_sound) + if (sound != m_sound) { AUD_Sound_free(sound); + } - if (m_handle != NULL) { + if (m_handle != nullptr) { if (m_is3d) { AUD_Handle_setRelative(m_handle, true); AUD_Handle_setVolumeMaximum(m_handle, m_3d.max_gain); @@ -140,18 +154,20 @@ void KX_SoundActuator::play() AUD_Handle_setConeVolumeOuter(m_handle, m_3d.cone_outer_gain); } - if (loop) + if (loop) { AUD_Handle_setLoopCount(m_handle, -1); + } AUD_Handle_setPitch(m_handle, m_pitch); AUD_Handle_setVolume(m_handle, m_volume); } m_isplaying = true; +#endif // WITH_AUDASPACE } -CValue* KX_SoundActuator::GetReplica() +EXP_Value *KX_SoundActuator::GetReplica() { - KX_SoundActuator* replica = new KX_SoundActuator(*this); + KX_SoundActuator *replica = new KX_SoundActuator(*this); replica->ProcessReplica(); return replica; } @@ -159,63 +175,66 @@ CValue* KX_SoundActuator::GetReplica() void KX_SoundActuator::ProcessReplica() { SCA_IActuator::ProcessReplica(); - m_handle = NULL; +#ifdef WITH_AUDASPACE + m_handle = nullptr; m_sound = AUD_Sound_copy(m_sound); +#endif // WITH_AUDASPACE } -bool KX_SoundActuator::Update(double curtime, bool frame) +bool KX_SoundActuator::Update(double curtime) { - if (!frame) - return true; bool result = false; +#ifdef WITH_AUDASPACE // do nothing on negative events, otherwise sounds are played twice! bool bNegativeEvent = IsNegativeEvent(); bool bPositiveEvent = m_posevent; +#endif // WITH_AUDASPACE RemoveAllEvents(); - if (!m_sound) +#ifdef WITH_AUDASPACE + if (!m_sound) { return false; + } // actual audio device playing state bool isplaying = m_handle ? (AUD_Handle_getStatus(m_handle) == AUD_STATUS_PLAYING) : false; - if (bNegativeEvent) - { + if (bNegativeEvent) { // here must be a check if it is still playing - if (m_isplaying && isplaying) - { - switch (m_type) - { - case KX_SOUNDACT_PLAYSTOP: - case KX_SOUNDACT_LOOPSTOP: - case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP: + if (m_isplaying && isplaying) { + switch (m_type) { + case KX_SOUNDACT_PLAYSTOP: + case KX_SOUNDACT_LOOPSTOP: + case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP: { // stop immediately - if (m_handle) - { + if (m_handle) { AUD_Handle_stop(m_handle); - m_handle = NULL; + m_handle = nullptr; } break; } - case KX_SOUNDACT_PLAYEND: + case KX_SOUNDACT_PLAYEND: { // do nothing, sound will stop anyway when it's finished break; } - case KX_SOUNDACT_LOOPEND: - case KX_SOUNDACT_LOOPBIDIRECTIONAL: + case KX_SOUNDACT_LOOPEND: + case KX_SOUNDACT_LOOPBIDIRECTIONAL: { // stop the looping so that the sound stops when it finished - if (m_handle) + if (m_handle) { AUD_Handle_setLoopCount(m_handle, 0); + } + break; + } + default: + { + // implement me !! break; } - default: - // implement me !! - break; } } // remember that we tried to stop the actuator @@ -229,48 +248,47 @@ bool KX_SoundActuator::Update(double curtime, bool frame) // check that we actually have a positive event so as not to play sounds when being disabled. else if (bPositiveEvent) /* <- added since 2.49 */ #else - else // <- works in most cases except a loop-end sound will never stop unless - // the negative pulse is done continuesly + else // <- works in most cases except a loop-end sound will never stop unless + // the negative pulse is done continuesly #endif { - if (!m_isplaying) + if (!m_isplaying) { play(); + } } // verify that the sound is still playing isplaying = m_handle ? (AUD_Handle_getStatus(m_handle) == AUD_STATUS_PLAYING) : false; - if (isplaying) - { - if (m_is3d) - { - KX_Camera* cam = KX_GetActiveScene()->GetActiveCamera(); - if (cam) - { - KX_GameObject* obj = (KX_GameObject*)this->GetParent(); - MT_Point3 p; - MT_Matrix3x3 Mo; + if (isplaying) { + if (m_is3d) { + KX_Camera *cam = KX_GetActiveScene()->GetActiveCamera(); + if (cam) { + KX_GameObject *obj = (KX_GameObject *)this->GetParent(); + mt::vec3 p; + mt::mat3 Mo; float data[4]; - Mo = cam->NodeGetWorldOrientation().inverse(); + Mo = cam->NodeGetWorldOrientation().Inverse(); p = (obj->NodeGetWorldPosition() - cam->NodeGetWorldPosition()); p = Mo * p; - p.getValue(data); + p.Pack(data); AUD_Handle_setLocation(m_handle, data); p = (obj->GetLinearVelocity() - cam->GetLinearVelocity()); p = Mo * p; - p.getValue(data); + p.Pack(data); AUD_Handle_setVelocity(m_handle, data); - (Mo * obj->NodeGetWorldOrientation()).getRotation().getValue(data); + mt::quat::FromMatrix(Mo * obj->NodeGetWorldOrientation()).Pack(data); AUD_Handle_setOrientation(m_handle, data); } } result = true; } - else - { + else { m_isplaying = false; result = false; } +#endif // WITH_AUDASPACE + return result; } @@ -284,9 +302,9 @@ bool KX_SoundActuator::Update(double curtime, bool frame) /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_SoundActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_SoundActuator", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -294,113 +312,126 @@ PyTypeObject KX_SoundActuator::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IActuator::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_SoundActuator::Methods[] = { - KX_PYMETHODTABLE_NOARGS(KX_SoundActuator, startSound), - KX_PYMETHODTABLE_NOARGS(KX_SoundActuator, pauseSound), - KX_PYMETHODTABLE_NOARGS(KX_SoundActuator, stopSound), - {NULL, NULL} //Sentinel + EXP_PYMETHODTABLE_NOARGS(KX_SoundActuator, startSound), + EXP_PYMETHODTABLE_NOARGS(KX_SoundActuator, pauseSound), + EXP_PYMETHODTABLE_NOARGS(KX_SoundActuator, stopSound), + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_SoundActuator::Attributes[] = { - KX_PYATTRIBUTE_BOOL_RO("is3D", KX_SoundActuator, m_is3d), - KX_PYATTRIBUTE_RW_FUNCTION("volume_maximum", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), - KX_PYATTRIBUTE_RW_FUNCTION("volume_minimum", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), - KX_PYATTRIBUTE_RW_FUNCTION("distance_reference", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), - KX_PYATTRIBUTE_RW_FUNCTION("distance_maximum", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), - KX_PYATTRIBUTE_RW_FUNCTION("attenuation", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), - KX_PYATTRIBUTE_RW_FUNCTION("cone_angle_inner", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), - KX_PYATTRIBUTE_RW_FUNCTION("cone_angle_outer", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), - KX_PYATTRIBUTE_RW_FUNCTION("cone_volume_outer", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), - KX_PYATTRIBUTE_RW_FUNCTION("sound", KX_SoundActuator, pyattr_get_sound, pyattr_set_sound), - - KX_PYATTRIBUTE_RW_FUNCTION("time", KX_SoundActuator, pyattr_get_audposition, pyattr_set_audposition), - KX_PYATTRIBUTE_RW_FUNCTION("volume", KX_SoundActuator, pyattr_get_gain, pyattr_set_gain), - KX_PYATTRIBUTE_RW_FUNCTION("pitch", KX_SoundActuator, pyattr_get_pitch, pyattr_set_pitch), - KX_PYATTRIBUTE_ENUM_RW("mode",KX_SoundActuator::KX_SOUNDACT_NODEF+1,KX_SoundActuator::KX_SOUNDACT_MAX-1,false,KX_SoundActuator,m_type), - { NULL } //Sentinel + EXP_PYATTRIBUTE_BOOL_RO("is3D", KX_SoundActuator, m_is3d), + EXP_PYATTRIBUTE_RW_FUNCTION("volume_maximum", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), + EXP_PYATTRIBUTE_RW_FUNCTION("volume_minimum", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), + EXP_PYATTRIBUTE_RW_FUNCTION("distance_reference", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), + EXP_PYATTRIBUTE_RW_FUNCTION("distance_maximum", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), + EXP_PYATTRIBUTE_RW_FUNCTION("attenuation", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), + EXP_PYATTRIBUTE_RW_FUNCTION("cone_angle_inner", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), + EXP_PYATTRIBUTE_RW_FUNCTION("cone_angle_outer", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), + EXP_PYATTRIBUTE_RW_FUNCTION("cone_volume_outer", KX_SoundActuator, pyattr_get_3d_property, pyattr_set_3d_property), + EXP_PYATTRIBUTE_RW_FUNCTION("sound", KX_SoundActuator, pyattr_get_sound, pyattr_set_sound), + + EXP_PYATTRIBUTE_RW_FUNCTION("time", KX_SoundActuator, pyattr_get_audposition, pyattr_set_audposition), + EXP_PYATTRIBUTE_RW_FUNCTION("volume", KX_SoundActuator, pyattr_get_gain, pyattr_set_gain), + EXP_PYATTRIBUTE_RW_FUNCTION("pitch", KX_SoundActuator, pyattr_get_pitch, pyattr_set_pitch), + EXP_PYATTRIBUTE_ENUM_RW("mode", KX_SoundActuator::KX_SOUNDACT_NODEF + 1, KX_SoundActuator::KX_SOUNDACT_MAX - 1, false, KX_SoundActuator, m_type), + EXP_PYATTRIBUTE_NULL //Sentinel }; /* Methods ----------------------------------------------------------------- */ -KX_PYMETHODDEF_DOC_NOARGS(KX_SoundActuator, startSound, -"startSound()\n" -"\tStarts the sound.\n") +EXP_PYMETHODDEF_DOC_NOARGS(KX_SoundActuator, startSound, + "startSound()\n" + "\tStarts the sound.\n") { +#ifdef WITH_AUDASPACE switch (m_handle ? AUD_Handle_getStatus(m_handle) : AUD_STATUS_INVALID) { case AUD_STATUS_PLAYING: + { break; + } case AUD_STATUS_PAUSED: + { AUD_Handle_resume(m_handle); break; + } default: play(); } +#endif // WITH_AUDASPACE + Py_RETURN_NONE; } -KX_PYMETHODDEF_DOC_NOARGS(KX_SoundActuator, pauseSound, -"pauseSound()\n" -"\tPauses the sound.\n") +EXP_PYMETHODDEF_DOC_NOARGS(KX_SoundActuator, pauseSound, + "pauseSound()\n" + "\tPauses the sound.\n") { - if (m_handle) +#ifdef WITH_AUDASPACE + if (m_handle) { AUD_Handle_pause(m_handle); + } +#endif // WITH_AUDASPACE + Py_RETURN_NONE; } -KX_PYMETHODDEF_DOC_NOARGS(KX_SoundActuator, stopSound, -"stopSound()\n" -"\tStops the sound.\n") +EXP_PYMETHODDEF_DOC_NOARGS(KX_SoundActuator, stopSound, + "stopSound()\n" + "\tStops the sound.\n") { - if (m_handle) - { +#ifdef WITH_AUDASPACE + if (m_handle) { AUD_Handle_stop(m_handle); - m_handle = NULL; + m_handle = nullptr; } +#endif // WITH_AUDASPACE + Py_RETURN_NONE; } /* Atribute setting and getting -------------------------------------------- */ -PyObject *KX_SoundActuator::pyattr_get_3d_property(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_SoundActuator::pyattr_get_3d_property(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - KX_SoundActuator * actuator = static_cast (self); - const char* prop = attrdef->m_name; + KX_SoundActuator *actuator = static_cast (self); + const std::string& prop = attrdef->m_name; float result_value = 0.0f; - if (!strcmp(prop, "volume_maximum")) { + if (prop == "volume_maximum") { result_value = actuator->m_3d.max_gain; - - } else if (!strcmp(prop, "volume_minimum")) { + } + else if (prop == "volume_minimum") { result_value = actuator->m_3d.min_gain; - - } else if (!strcmp(prop, "distance_reference")) { + } + else if (prop == "distance_reference") { result_value = actuator->m_3d.reference_distance; - - } else if (!strcmp(prop, "distance_maximum")) { + } + else if (prop == "distance_maximum") { result_value = actuator->m_3d.max_distance; - - } else if (!strcmp(prop, "attenuation")) { + } + else if (prop == "attenuation") { result_value = actuator->m_3d.rolloff_factor; - - } else if (!strcmp(prop, "cone_angle_inner")) { + } + else if (prop == "cone_angle_inner") { result_value = actuator->m_3d.cone_inner_angle; - - } else if (!strcmp(prop, "cone_angle_outer")) { + } + else if (prop == "cone_angle_outer") { result_value = actuator->m_3d.cone_outer_angle; - - } else if (!strcmp(prop, "cone_volume_outer")) { + } + else if (prop == "cone_volume_outer") { result_value = actuator->m_3d.cone_outer_gain; - - } else { + } + else { Py_RETURN_NONE; } @@ -408,22 +439,26 @@ PyObject *KX_SoundActuator::pyattr_get_3d_property(void *self, const struct KX_P return result; } -PyObject *KX_SoundActuator::pyattr_get_audposition(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_SoundActuator::pyattr_get_audposition(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - KX_SoundActuator * actuator = static_cast (self); float position = 0.0f; - if (actuator->m_handle) +#ifdef WITH_AUDASPACE + KX_SoundActuator *actuator = static_cast (self); + + if (actuator->m_handle) { position = AUD_Handle_getPosition(actuator->m_handle); + } +#endif // WITH_AUDASPACE PyObject *result = PyFloat_FromDouble(position); return result; } -PyObject *KX_SoundActuator::pyattr_get_gain(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_SoundActuator::pyattr_get_gain(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - KX_SoundActuator * actuator = static_cast (self); + KX_SoundActuator *actuator = static_cast (self); float gain = actuator->m_volume; PyObject *result = PyFloat_FromDouble(gain); @@ -431,9 +466,9 @@ PyObject *KX_SoundActuator::pyattr_get_gain(void *self, const struct KX_PYATTRIB return result; } -PyObject *KX_SoundActuator::pyattr_get_pitch(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_SoundActuator::pyattr_get_pitch(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - KX_SoundActuator * actuator = static_cast (self); + KX_SoundActuator *actuator = static_cast (self); float pitch = actuator->m_pitch; PyObject *result = PyFloat_FromDouble(pitch); @@ -441,133 +476,191 @@ PyObject *KX_SoundActuator::pyattr_get_pitch(void *self, const struct KX_PYATTRI return result; } -PyObject *KX_SoundActuator::pyattr_get_sound(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_SoundActuator::pyattr_get_sound(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - KX_SoundActuator * actuator = static_cast (self); - if (actuator->m_sound) +#ifdef WITH_AUDASPACE + KX_SoundActuator *actuator = static_cast (self); + + if (actuator->m_sound) { return (PyObject *)AUD_getPythonSound(actuator->m_sound); - else - Py_RETURN_NONE; + } +#endif // WITH_AUDASPACE + + Py_RETURN_NONE; + } -int KX_SoundActuator::pyattr_set_3d_property(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_SoundActuator::pyattr_set_3d_property(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_SoundActuator * actuator = static_cast (self); - const char* prop = attrdef->m_name; + KX_SoundActuator *actuator = static_cast (self); + const std::string& prop = attrdef->m_name; float prop_value = 0.0f; - if (!PyArg_Parse(value, "f", &prop_value)) + if (!PyArg_Parse(value, "f", &prop_value)) { return PY_SET_ATTR_FAIL; + } // if sound is working and 3D, set the new setting - if (!actuator->m_is3d) + if (!actuator->m_is3d) { return PY_SET_ATTR_FAIL; + } - if (!strcmp(prop, "volume_maximum")) { + if (prop == "volume_maximum") { actuator->m_3d.max_gain = prop_value; - if (actuator->m_handle) +#ifdef WITH_AUDASPACE + if (actuator->m_handle) { AUD_Handle_setVolumeMaximum(actuator->m_handle, prop_value); + } +#endif // WITH_AUDASPACE - } else if (!strcmp(prop, "volume_minimum")) { + } + else if (prop == "volume_minimum") { actuator->m_3d.min_gain = prop_value; - if (actuator->m_handle) +#ifdef WITH_AUDASPACE + if (actuator->m_handle) { AUD_Handle_setVolumeMinimum(actuator->m_handle, prop_value); + } +#endif // WITH_AUDASPACE - } else if (!strcmp(prop, "distance_reference")) { + } + else if (prop == "distance_reference") { actuator->m_3d.reference_distance = prop_value; - if (actuator->m_handle) +#ifdef WITH_AUDASPACE + if (actuator->m_handle) { AUD_Handle_setDistanceReference(actuator->m_handle, prop_value); + } +#endif // WITH_AUDASPACE - } else if (!strcmp(prop, "distance_maximum")) { + } + else if (prop == "distance_maximum") { actuator->m_3d.max_distance = prop_value; - if (actuator->m_handle) +#ifdef WITH_AUDASPACE + if (actuator->m_handle) { AUD_Handle_setDistanceMaximum(actuator->m_handle, prop_value); + } +#endif // WITH_AUDASPACE - } else if (!strcmp(prop, "attenuation")) { + } + else if (prop == "attenuation") { actuator->m_3d.rolloff_factor = prop_value; - if (actuator->m_handle) +#ifdef WITH_AUDASPACE + if (actuator->m_handle) { AUD_Handle_setAttenuation(actuator->m_handle, prop_value); + } +#endif // WITH_AUDASPACE - } else if (!strcmp(prop, "cone_angle_inner")) { + } + else if (prop == "cone_angle_inner") { actuator->m_3d.cone_inner_angle = prop_value; - if (actuator->m_handle) +#ifdef WITH_AUDASPACE + if (actuator->m_handle) { AUD_Handle_setConeAngleInner(actuator->m_handle, prop_value); + } +#endif // WITH_AUDASPACE - } else if (!strcmp(prop, "cone_angle_outer")) { + } + else if (prop == "cone_angle_outer") { actuator->m_3d.cone_outer_angle = prop_value; - if (actuator->m_handle) +#ifdef WITH_AUDASPACE + if (actuator->m_handle) { AUD_Handle_setConeAngleOuter(actuator->m_handle, prop_value); + } +#endif // WITH_AUDASPACE - } else if (!strcmp(prop, "cone_volume_outer")) { + } + else if (prop == "cone_volume_outer") { actuator->m_3d.cone_outer_gain = prop_value; - if (actuator->m_handle) +#ifdef WITH_AUDASPACE + if (actuator->m_handle) { AUD_Handle_setConeVolumeOuter(actuator->m_handle, prop_value); + } +#endif // WITH_AUDASPACE - } else { + } + else { return PY_SET_ATTR_FAIL; } return PY_SET_ATTR_SUCCESS; } -int KX_SoundActuator::pyattr_set_audposition(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_SoundActuator::pyattr_set_audposition(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_SoundActuator * actuator = static_cast (self); - float position = 1.0f; - if (!PyArg_Parse(value, "f", &position)) + if (!PyArg_Parse(value, "f", &position)) { return PY_SET_ATTR_FAIL; + } - if (actuator->m_handle) +#ifdef WITH_AUDASPACE + KX_SoundActuator *actuator = static_cast (self); + + if (actuator->m_handle) { AUD_Handle_setPosition(actuator->m_handle, position); + } +#endif // WITH_AUDASPACE + return PY_SET_ATTR_SUCCESS; } -int KX_SoundActuator::pyattr_set_gain(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_SoundActuator::pyattr_set_gain(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { float gain = 1.0f; - KX_SoundActuator * actuator = static_cast (self); - if (!PyArg_Parse(value, "f", &gain)) + KX_SoundActuator *actuator = static_cast (self); + if (!PyArg_Parse(value, "f", &gain)) { return PY_SET_ATTR_FAIL; + } actuator->m_volume = gain; - if (actuator->m_handle) + +#ifdef WITH_AUDASPACE + if (actuator->m_handle) { AUD_Handle_setVolume(actuator->m_handle, gain); + } +#endif // WITH_AUDASPACE return PY_SET_ATTR_SUCCESS; } -int KX_SoundActuator::pyattr_set_pitch(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_SoundActuator::pyattr_set_pitch(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { float pitch = 1.0f; - KX_SoundActuator * actuator = static_cast (self); - if (!PyArg_Parse(value, "f", &pitch)) + KX_SoundActuator *actuator = static_cast (self); + if (!PyArg_Parse(value, "f", &pitch)) { return PY_SET_ATTR_FAIL; + } actuator->m_pitch = pitch; - if (actuator->m_handle) + +#ifdef WITH_AUDASPACE + if (actuator->m_handle) { AUD_Handle_setPitch(actuator->m_handle, pitch); + } +#endif // WITH_AUDASPACE return PY_SET_ATTR_SUCCESS; } -int KX_SoundActuator::pyattr_set_sound(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_SoundActuator::pyattr_set_sound(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - PyObject *sound = NULL; - KX_SoundActuator * actuator = static_cast (self); - if (!PyArg_Parse(value, "O", &sound)) + PyObject *sound = nullptr; + if (!PyArg_Parse(value, "O", &sound)) { return PY_SET_ATTR_FAIL; + } + +#ifdef WITH_AUDASPACE + KX_SoundActuator *actuator = static_cast (self); AUD_Sound *snd = AUD_getSoundFromPython(sound); - if (snd) - { - AUD_Sound_free(actuator->m_sound); - actuator->m_sound = snd; - return PY_SET_ATTR_SUCCESS; + if (!snd) { + return PY_SET_ATTR_FAIL; } - return PY_SET_ATTR_FAIL; + AUD_Sound_free(actuator->m_sound); + actuator->m_sound = snd; +#endif // WITH_AUDASPACE + + return PY_SET_ATTR_SUCCESS; } #endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_SoundActuator.h b/source/gameengine/Ketsji/KX_SoundActuator.h index 5ec2fda722ff..a7b683bc4e84 100644 --- a/source/gameengine/Ketsji/KX_SoundActuator.h +++ b/source/gameengine/Ketsji/KX_SoundActuator.h @@ -56,12 +56,14 @@ class KX_SoundActuator : public SCA_IActuator { Py_Header bool m_isplaying; +#ifdef WITH_AUDASPACE AUD_Sound* m_sound; + AUD_Handle* m_handle; +#endif // WITH_AUDASPACE float m_volume; float m_pitch; bool m_is3d; KX_3DSoundSettings m_3d; - AUD_Handle* m_handle; void play(); @@ -82,7 +84,9 @@ class KX_SoundActuator : public SCA_IActuator KX_SOUNDACT_TYPE m_type; KX_SoundActuator(SCA_IObject* gameobj, +#ifdef WITH_AUDASPACE AUD_Sound *sound, +#endif // WITH_AUDASPACE float volume, float pitch, bool is3d, @@ -91,9 +95,9 @@ class KX_SoundActuator : public SCA_IActuator ~KX_SoundActuator(); - virtual bool Update(double curtime, bool frame); + virtual bool Update(double curtime); - CValue* GetReplica(); + EXP_Value* GetReplica(); void ProcessReplica(); #ifdef WITH_PYTHON @@ -102,23 +106,23 @@ class KX_SoundActuator : public SCA_IActuator /* Python interface --------------------------------------------------- */ /* -------------------------------------------------------------------- */ - KX_PYMETHOD_DOC_NOARGS(KX_SoundActuator, startSound); - KX_PYMETHOD_DOC_NOARGS(KX_SoundActuator, pauseSound); - KX_PYMETHOD_DOC_NOARGS(KX_SoundActuator, stopSound); - - static int pyattr_set_3d_property(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_set_audposition(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_set_gain(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_set_pitch(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_set_type(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_set_sound(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - - static PyObject *pyattr_get_3d_property(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_audposition(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_gain(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_pitch(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_type(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_sound(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); + EXP_PYMETHOD_DOC_NOARGS(KX_SoundActuator, startSound); + EXP_PYMETHOD_DOC_NOARGS(KX_SoundActuator, pauseSound); + EXP_PYMETHOD_DOC_NOARGS(KX_SoundActuator, stopSound); + + static int pyattr_set_3d_property(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_audposition(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_gain(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_pitch(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_type(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_sound(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + + static PyObject *pyattr_get_3d_property(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_audposition(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_gain(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_pitch(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_type(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_sound(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); #endif /* WITH_PYTHON */ diff --git a/source/gameengine/Ketsji/KX_StateActuator.cpp b/source/gameengine/Ketsji/KX_StateActuator.cpp index 870540669c91..0c05cc4acf0d 100644 --- a/source/gameengine/Ketsji/KX_StateActuator.cpp +++ b/source/gameengine/Ketsji/KX_StateActuator.cpp @@ -34,21 +34,17 @@ #include "KX_StateActuator.h" #include "KX_GameObject.h" -KX_StateActuator::KX_StateActuator( - SCA_IObject* gameobj, - int operation, - unsigned int mask - ) - : SCA_IActuator(gameobj, KX_ACT_STATE), - m_operation(operation), - m_mask(mask) +KX_StateActuator::KX_StateActuator(SCA_IObject *gameobj, + int operation, + unsigned int mask) + :SCA_IActuator(gameobj, KX_ACT_STATE), + m_operation(operation), + m_mask(mask) { // intentionally empty } -KX_StateActuator::~KX_StateActuator( - void - ) +KX_StateActuator::~KX_StateActuator(void) { // intentionally empty } @@ -56,48 +52,53 @@ KX_StateActuator::~KX_StateActuator( // used to put state actuator to be executed before any other actuators SG_QList KX_StateActuator::m_stateActuatorHead; -CValue* -KX_StateActuator::GetReplica( - void - ) +EXP_Value *KX_StateActuator::GetReplica(void) { - KX_StateActuator* replica = new KX_StateActuator(*this); + KX_StateActuator *replica = new KX_StateActuator(*this); replica->ProcessReplica(); return replica; } -bool -KX_StateActuator::Update() +bool KX_StateActuator::Update() { bool bNegativeEvent = IsNegativeEvent(); unsigned int objMask; // execution of state actuator means that we are in the execution phase, reset this pointer // because all the active actuator of this object will be removed for sure. - m_gameobj->m_firstState = NULL; + m_gameobj->SetFirstState(nullptr); RemoveAllEvents(); - if (bNegativeEvent) return false; + if (bNegativeEvent) { + return false; + } - KX_GameObject *obj = (KX_GameObject*) GetParent(); + KX_GameObject *obj = (KX_GameObject *)GetParent(); objMask = obj->GetState(); - switch (m_operation) - { - case OP_CPY: - objMask = m_mask; - break; - case OP_SET: - objMask |= m_mask; - break; - case OP_CLR: - objMask &= ~m_mask; - break; - case OP_NEG: - objMask ^= m_mask; - break; - default: - // unsupported operation, no nothing - return false; + switch (m_operation) { + case OP_CPY: + { + objMask = m_mask; + break; + } + case OP_SET: + { + objMask |= m_mask; + break; + } + case OP_CLR: + { + objMask &= ~m_mask; + break; + } + case OP_NEG: + { + objMask ^= m_mask; + break; + } + default: + // unsupported operation, no nothing + return false; } obj->SetState(objMask); return false; @@ -107,21 +108,20 @@ KX_StateActuator::Update() // e.g. when an object is deleted. void KX_StateActuator::Deactivate() { - if (QDelink()) - { + if (QDelink()) { // the actuator was in the active list - if (m_stateActuatorHead.QEmpty()) + if (m_stateActuatorHead.QEmpty()) { // no more state object active m_stateActuatorHead.Delink(); + } } } void KX_StateActuator::Activate(SG_DList& head) { // sort the state actuators per object on the global list - if (QEmpty()) - { - InsertSelfActiveQList(m_stateActuatorHead, &m_gameobj->m_firstState); + if (QEmpty()) { + InsertSelfActiveQList(m_stateActuatorHead, m_gameobj->GetFirstState()); // add front to make sure it runs before other actuators head.AddFront(&m_stateActuatorHead); } @@ -137,9 +137,9 @@ void KX_StateActuator::Activate(SG_DList& head) /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_StateActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_StateActuator", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -147,25 +147,25 @@ PyTypeObject KX_StateActuator::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IActuator::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_StateActuator::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_StateActuator::Attributes[] = { - KX_PYATTRIBUTE_INT_RW("operation",KX_StateActuator::OP_NOP+1,KX_StateActuator::OP_COUNT-1,false,KX_StateActuator,m_operation), - KX_PYATTRIBUTE_INT_RW("mask",0,0x3FFFFFFF,false,KX_StateActuator,m_mask), - { NULL } //Sentinel + EXP_PYATTRIBUTE_INT_RW("operation", KX_StateActuator::OP_NOP + 1, KX_StateActuator::OP_COUNT - 1, false, KX_StateActuator, m_operation), + EXP_PYATTRIBUTE_INT_RW("mask", 0, 0x3FFFFFFF, false, KX_StateActuator, m_mask), + EXP_PYATTRIBUTE_NULL //Sentinel }; #endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_StateActuator.h b/source/gameengine/Ketsji/KX_StateActuator.h index e53c26e7cf75..22c9572c2f41 100644 --- a/source/gameengine/Ketsji/KX_StateActuator.h +++ b/source/gameengine/Ketsji/KX_StateActuator.h @@ -39,7 +39,7 @@ /* * Use of SG_DList : element of actuator being deactivated * Head: SCA_LogicManager::m_removedActuators - * Use of SG_QList : element of global activated state actuator list + * Use of SG_QList : element of global activated state actuator list * Head: KX_StateActuator::m_stateActuatorHead */ class KX_StateActuator : public SCA_IActuator @@ -64,7 +64,7 @@ class KX_StateActuator : public SCA_IActuator int m_mask; public: - + KX_StateActuator( SCA_IObject* gameobj, int operation, @@ -76,7 +76,7 @@ class KX_StateActuator : public SCA_IActuator void ); - virtual CValue* + virtual EXP_Value* GetReplica( void ); @@ -94,3 +94,4 @@ class KX_StateActuator : public SCA_IActuator }; #endif + diff --git a/source/gameengine/Ketsji/KX_SteeringActuator.cpp b/source/gameengine/Ketsji/KX_SteeringActuator.cpp index fd45706b1e30..19483be19fbe 100644 --- a/source/gameengine/Ketsji/KX_SteeringActuator.cpp +++ b/source/gameengine/Ketsji/KX_SteeringActuator.cpp @@ -33,310 +33,297 @@ #include "KX_GameObject.h" #include "KX_NavMeshObject.h" #include "KX_ObstacleSimulation.h" -#include "KX_PythonInit.h" +#include "KX_Globals.h" #include "KX_PyMath.h" #include "Recast.h" -/* ------------------------------------------------------------------------- */ -/* Native functions */ -/* ------------------------------------------------------------------------- */ - -KX_SteeringActuator::KX_SteeringActuator(SCA_IObject *gameobj, - int mode, - KX_GameObject *target, - KX_GameObject *navmesh, - float distance, - float velocity, - float acceleration, - float turnspeed, - bool isSelfTerminated, - int pathUpdatePeriod, - KX_ObstacleSimulation* simulation, - short facingmode, - bool normalup, - bool enableVisualization, - bool lockzvel) - : SCA_IActuator(gameobj, KX_ACT_STEERING), - m_target(target), - m_mode(mode), - m_distance(distance), - m_velocity(velocity), - m_acceleration(acceleration), - m_turnspeed(turnspeed), - m_simulation(simulation), - m_updateTime(0), - m_obstacle(NULL), - m_isActive(false), - m_isSelfTerminated(isSelfTerminated), - m_enableVisualization(enableVisualization), - m_facingMode(facingmode), - m_normalUp(normalup), - m_pathLen(0), - m_pathUpdatePeriod(pathUpdatePeriod), - m_lockzvel(lockzvel), - m_wayPointIdx(-1), - m_steerVec(MT_Vector3(0, 0, 0)) +#include "EXP_ListWrapper.h" + +KX_SteeringActuator::KX_SteeringActuator(SCA_IObject *gameobj, int mode, KX_GameObject *target, KX_GameObject *navmesh, + float distance, float velocity, float acceleration, float turnspeed, bool isSelfTerminated, int pathUpdatePeriod, + KX_ObstacleSimulation *simulation, short facingmode, bool normalup, bool enableVisualization, bool lockzvel) + :SCA_IActuator(gameobj, KX_ACT_STEERING), + m_target(target), + m_mode(mode), + m_distance(distance), + m_velocity(velocity), + m_acceleration(acceleration), + m_turnspeed(turnspeed), + m_simulation(simulation), + m_updateTime(0.0), + m_obstacle(nullptr), + m_isActive(false), + m_isSelfTerminated(isSelfTerminated), + m_enableVisualization(enableVisualization), + m_facingMode(facingmode), + m_normalUp(normalup), + m_pathUpdatePeriod(pathUpdatePeriod), + m_lockzvel(lockzvel), + m_wayPointIdx(-1), + m_steerVec(mt::zero3) { - m_navmesh = static_cast(navmesh); - if (m_navmesh) + m_navmesh = static_cast(navmesh); + if (m_navmesh) { m_navmesh->RegisterActuator(this); - if (m_target) + } + if (m_target) { m_target->RegisterActuator(this); + } + + if (m_simulation) { + m_obstacle = m_simulation->GetObstacle(static_cast(gameobj)); + } - if (m_simulation) - m_obstacle = m_simulation->GetObstacle((KX_GameObject*)gameobj); - KX_GameObject* parent = ((KX_GameObject*)gameobj)->GetParent(); - if (m_facingMode>0 && parent) - { - m_parentlocalmat = parent->GetSGNode()->GetLocalOrientation(); + KX_GameObject *parent = static_cast(gameobj)->GetParent(); + if (m_facingMode > 0 && parent) { + m_parentlocalmat = parent->NodeGetLocalOrientation(); + } + else { + m_parentlocalmat = mt::mat3::Identity(); } - else - m_parentlocalmat.setIdentity(); } KX_SteeringActuator::~KX_SteeringActuator() { - if (m_navmesh) + if (m_navmesh) { m_navmesh->UnregisterActuator(this); - if (m_target) + } + if (m_target) { m_target->UnregisterActuator(this); + } } -CValue* KX_SteeringActuator::GetReplica() +EXP_Value *KX_SteeringActuator::GetReplica() { - KX_SteeringActuator* replica = new KX_SteeringActuator(*this); - // replication just copy the m_base pointer => common random generator + KX_SteeringActuator *replica = new KX_SteeringActuator(*this); replica->ProcessReplica(); return replica; } void KX_SteeringActuator::ProcessReplica() { - if (m_target) + if (m_target) { m_target->RegisterActuator(this); - if (m_navmesh) + } + if (m_navmesh) { m_navmesh->RegisterActuator(this); + } SCA_IActuator::ProcessReplica(); } -void KX_SteeringActuator::ReParent(SCA_IObject* parent) +void KX_SteeringActuator::ReParent(SCA_IObject *parent) { SCA_IActuator::ReParent(parent); - if (m_simulation) - m_obstacle = m_simulation->GetObstacle((KX_GameObject*)m_gameobj); + if (m_simulation) { + m_obstacle = m_simulation->GetObstacle(static_cast(m_gameobj)); + } } -bool KX_SteeringActuator::UnlinkObject(SCA_IObject* clientobj) +bool KX_SteeringActuator::UnlinkObject(SCA_IObject *clientobj) { - if (clientobj == m_target) - { - m_target = NULL; + if (clientobj == m_target) { + m_target = nullptr; return true; } - else if (clientobj == m_navmesh) - { - m_navmesh = NULL; + else if (clientobj == m_navmesh) { + m_navmesh = nullptr; return true; } return false; } -void KX_SteeringActuator::Relink(CTR_Map *obj_map) +void KX_SteeringActuator::Relink(std::map& obj_map) { - void **h_obj = (*obj_map)[m_target]; - if (h_obj) { - if (m_target) + KX_GameObject *obj = static_cast(obj_map[m_target]); + if (obj) { + if (m_target) { m_target->UnregisterActuator(this); - m_target = (KX_GameObject*)(*h_obj); + } + m_target = obj; m_target->RegisterActuator(this); } - h_obj = (*obj_map)[m_navmesh]; - if (h_obj) { - if (m_navmesh) + KX_NavMeshObject *navobj = static_cast(obj_map[m_navmesh]); + if (navobj) { + if (m_navmesh) { m_navmesh->UnregisterActuator(this); - m_navmesh = (KX_NavMeshObject*)(*h_obj); + } + m_navmesh = navobj; m_navmesh->RegisterActuator(this); } } -bool KX_SteeringActuator::Update(double curtime, bool frame) +bool KX_SteeringActuator::Update(double curtime) { - if (frame) - { - double delta = curtime - m_updateTime; + double delta = curtime - m_updateTime; + m_updateTime = curtime; + + if (m_posevent && !m_isActive) { + delta = 0.0; + m_pathUpdateTime = -1.0; m_updateTime = curtime; + m_isActive = true; + } + bool bNegativeEvent = IsNegativeEvent(); + if (bNegativeEvent) { + m_isActive = false; + } + + RemoveAllEvents(); - if (m_posevent && !m_isActive) + if (!delta) { + return true; + } + + if (bNegativeEvent || !m_target) { + // Do nothing on negative events. + return false; + } + + KX_GameObject *obj = static_cast(GetParent()); + const mt::vec3& mypos = obj->NodeGetWorldPosition(); + const mt::vec3& targpos = m_target->NodeGetWorldPosition(); + const mt::vec3 vectotarg = targpos - mypos; + const mt::vec2 vectotarg2d = vectotarg.xy(); + m_steerVec = mt::zero3; + bool apply_steerforce = false; + bool terminate = true; + + switch (m_mode) { + case KX_STEERING_SEEK: { - delta = 0.0; - m_pathUpdateTime = -1.0; - m_updateTime = curtime; - m_isActive = true; + if (vectotarg2d.LengthSquared() > m_distance * m_distance) { + terminate = false; + m_steerVec = vectotarg; + m_steerVec.Normalize(); + apply_steerforce = true; + } + break; } - bool bNegativeEvent = IsNegativeEvent(); - if (bNegativeEvent) - m_isActive = false; - - RemoveAllEvents(); - - if (!delta) - return true; - - if (bNegativeEvent || !m_target) - return false; // do nothing on negative events - - KX_GameObject *obj = (KX_GameObject*) GetParent(); - const MT_Point3& mypos = obj->NodeGetWorldPosition(); - const MT_Point3& targpos = m_target->NodeGetWorldPosition(); - MT_Vector3 vectotarg = targpos - mypos; - MT_Vector3 vectotarg2d = vectotarg; - vectotarg2d.z() = 0.0f; - m_steerVec = MT_Vector3(0.0f, 0.0f, 0.0f); - bool apply_steerforce = false; - bool terminate = true; - - switch (m_mode) { - case KX_STEERING_SEEK: - if (vectotarg2d.length2()>m_distance*m_distance) - { - terminate = false; - m_steerVec = vectotarg; - m_steerVec.normalize(); - apply_steerforce = true; - } - break; - case KX_STEERING_FLEE: - if (vectotarg2d.length2()m_distance*m_distance) - { - terminate = false; - - static const MT_Scalar WAYPOINT_RADIUS(0.25f); - - if (m_pathUpdateTime<0 || (m_pathUpdatePeriod>=0 && - curtime - m_pathUpdateTime>((double)m_pathUpdatePeriod/1000.0))) - { - m_pathUpdateTime = curtime; - m_pathLen = m_navmesh->FindPath(mypos, targpos, m_path, MAX_PATH_LENGTH); - m_wayPointIdx = m_pathLen > 1 ? 1 : -1; - } - - if (m_wayPointIdx>0) - { - MT_Vector3 waypoint(&m_path[3*m_wayPointIdx]); - if ((waypoint-mypos).length2()=m_pathLen) - { - m_wayPointIdx = -1; - terminate = true; - } - else - waypoint.setValue(&m_path[3*m_wayPointIdx]); - } + case KX_STEERING_FLEE: + { + if (vectotarg2d.LengthSquared() < m_distance * m_distance) { + terminate = false; + m_steerVec = -vectotarg; + m_steerVec.Normalize(); + apply_steerforce = true; + } + break; + } + case KX_STEERING_PATHFOLLOWING: + { + if (m_navmesh && vectotarg.LengthSquared() > m_distance * m_distance) { + terminate = false; - m_steerVec = waypoint - mypos; - apply_steerforce = true; + static const float WAYPOINT_RADIUS(0.25f); + if (m_pathUpdateTime < 0 || (m_pathUpdatePeriod >= 0 && + curtime - m_pathUpdateTime > ((double)m_pathUpdatePeriod / 1000.0))) { + m_pathUpdateTime = curtime; + m_path = m_navmesh->FindPath(mypos, targpos, MAX_PATH_LENGTH); + m_wayPointIdx = m_path.size() > 1 ? 1 : -1; + } - if (m_enableVisualization) - { - //debug draw - static const MT_Vector3 PATH_COLOR(1.0f,0.0f,0.0f); - m_navmesh->DrawPath(m_path, m_pathLen, PATH_COLOR); + if (m_wayPointIdx > 0) { + mt::vec3 waypoint = m_path[m_wayPointIdx]; + if ((waypoint - mypos).LengthSquared() < WAYPOINT_RADIUS * WAYPOINT_RADIUS) { + m_wayPointIdx++; + if (m_wayPointIdx >= m_path.size()) { + m_wayPointIdx = -1; + terminate = true; + } + else { + waypoint = m_path[m_wayPointIdx]; } } - } - break; - } + m_steerVec = waypoint - mypos; + apply_steerforce = true; - if (apply_steerforce) - { - bool isdyna = obj->IsDynamic(); - if (isdyna) - m_steerVec.z() = 0; - if (!m_steerVec.fuzzyZero()) - m_steerVec.normalize(); - MT_Vector3 newvel = m_velocity * m_steerVec; - - //adjust velocity to avoid obstacles - if (m_simulation && m_obstacle /*&& !newvel.fuzzyZero()*/) - { - if (m_enableVisualization) - KX_RasterizerDrawDebugLine(mypos, mypos + newvel, MT_Vector3(1.0f, 0.0f, 0.0f)); - m_simulation->AdjustObstacleVelocity(m_obstacle, m_mode!=KX_STEERING_PATHFOLLOWING ? m_navmesh : NULL, - newvel, m_acceleration*(float)delta, m_turnspeed/(180.0f*(float)(M_PI*delta))); - if (m_enableVisualization) - KX_RasterizerDrawDebugLine(mypos, mypos + newvel, MT_Vector3(0.0f, 1.0f, 0.0f)); + if (m_enableVisualization) { + // Debug draw. + static const mt::vec4 PATH_COLOR(1.0f, 0.0f, 0.0f, 1.0f); + m_navmesh->DrawPath(m_path, PATH_COLOR); + } + } } + break; + } + } - HandleActorFace(newvel); - if (isdyna) - { - //temporary solution: set 2D steering velocity directly to obj - //correct way is to apply physical force - MT_Vector3 curvel = obj->GetLinearVelocity(); - - if (m_lockzvel) - newvel.z() = 0.0f; - else - newvel.z() = curvel.z(); + if (apply_steerforce) { + bool isdyna = obj->IsDynamic(); + if (isdyna) { + m_steerVec.z = 0.0f; + } + m_steerVec.SafeNormalize(); + mt::vec3 newvel = m_velocity * m_steerVec; - obj->setLinearVelocity(newvel, false); + // Adjust velocity to avoid obstacles. + if (m_simulation && m_obstacle) { + if (m_enableVisualization) { + KX_RasterizerDrawDebugLine(mypos, mypos + newvel, mt::vec4(1.0f, 0.0f, 0.0f, 1.0f)); } - else - { - MT_Vector3 movement = delta*newvel; - obj->ApplyMovement(movement, false); + m_simulation->AdjustObstacleVelocity(m_obstacle, m_mode != KX_STEERING_PATHFOLLOWING ? m_navmesh : nullptr, + newvel, m_acceleration * (float)delta, m_turnspeed / (180.0f * (float)(M_PI * delta))); + if (m_enableVisualization) { + KX_RasterizerDrawDebugLine(mypos, mypos + newvel, mt::vec4(0.0f, 1.0f, 0.0f, 1.0f)); } } - else - { - if (m_simulation && m_obstacle) - { - m_obstacle->dvel[0] = 0.f; - m_obstacle->dvel[1] = 0.f; + + HandleActorFace(newvel); + if (isdyna) { + // Temporary solution: set 2D steering velocity directly to obj correct way is to apply physical force. + const mt::vec3 curvel = obj->GetLinearVelocity(); + + if (m_lockzvel) { + newvel.z = 0.0f; + } + else { + newvel.z = curvel.z; } + obj->SetLinearVelocity(newvel, false); } + else { + const mt::vec3 movement = ((float)delta) * newvel; + obj->ApplyMovement(movement, false); + } + } + else { + if (m_simulation && m_obstacle) { + m_obstacle->dvel[0] = 0.f; + m_obstacle->dvel[1] = 0.f; + } + } - if (terminate && m_isSelfTerminated) - return false; + if (terminate && m_isSelfTerminated) { + return false; } return true; } -const MT_Vector3& KX_SteeringActuator::GetSteeringVec() +const mt::vec3& KX_SteeringActuator::GetSteeringVec() const { - static MT_Vector3 ZERO_VECTOR(0, 0, 0); - if (m_isActive) + if (m_isActive) { return m_steerVec; - else - return ZERO_VECTOR; + } + else { + return mt::zero3; + } } -inline float vdot2(const float* a, const float* b) +inline float vdot2(const float *a, const float *b) { - return a[0]*b[0] + a[2]*b[2]; + return a[0] * b[0] + a[2] * b[2]; } -static bool barDistSqPointToTri(const float* p, const float* a, const float* b, const float* c) +static bool barDistSqPointToTri(const float *p, const float *a, const float *b, const float *c) { float v0[3], v1[3], v2[3]; - rcVsub(v0, c,a); - rcVsub(v1, b,a); - rcVsub(v2, p,a); + rcVsub(v0, c, a); + rcVsub(v1, b, a); + rcVsub(v2, p, a); const float dot00 = vdot2(v0, v0); const float dot01 = vdot2(v0, v1); @@ -344,188 +331,177 @@ static bool barDistSqPointToTri(const float* p, const float* a, const float* b, const float dot11 = vdot2(v1, v1); const float dot12 = vdot2(v1, v2); - // Compute barycentric coordinates + // Compute barycentric coordinates. float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01); float u = (dot11 * dot02 - dot01 * dot12) * invDenom; float v = (dot00 * dot12 - dot01 * dot02) * invDenom; - float ud = u<0.f ? -u : (u>1.f ? u-1.f : 0.f); - float vd = v<0.f ? -v : (v>1.f ? v-1.f : 0.f); + float ud = u < 0.0f ? -u : (u > 1.0f ? u - 1.0f : 0.0f); + float vd = v < 0.0f ? -v : (v > 1.0f ? v - 1.0f : 0.0f); return ud * ud + vd * vd; } -inline void flipAxes(float* vec) +inline void flipAxes(mt::vec3& vec) { - std::swap(vec[1],vec[2]); + std::swap(vec.y, vec.z); } -static bool getNavmeshNormal(dtStatNavMesh* navmesh, const MT_Vector3& pos, MT_Vector3& normal) +inline void flipAxes(float vec[3]) +{ + std::swap(vec[1], vec[2]); +} + +static bool getNavmeshNormal(dtStatNavMesh *navmesh, const mt::vec3& pos, mt::vec3& normal) { static const float polyPickExt[3] = {2, 4, 2}; - float spos[3]; - pos.getValue(spos); + mt::vec3 spos = pos; flipAxes(spos); - dtStatPolyRef sPolyRef = navmesh->findNearestPoly(spos, polyPickExt); - if (sPolyRef == 0) + dtStatPolyRef sPolyRef = navmesh->findNearestPoly(spos.Data(), polyPickExt); + if (sPolyRef == 0) { return false; - const dtStatPoly* p = navmesh->getPoly(sPolyRef-1); - const dtStatPolyDetail* pd = navmesh->getPolyDetail(sPolyRef-1); + } + + const dtStatPoly *p = navmesh->getPoly(sPolyRef - 1); + const dtStatPolyDetail *pd = navmesh->getPolyDetail(sPolyRef - 1); float distMin = FLT_MAX; int idxMin = -1; - for (int i = 0; i < pd->ntris; ++i) - { - const unsigned char* t = navmesh->getDetailTri(pd->tbase+i); - const float* v[3]; - for (int j = 0; j < 3; ++j) - { - if (t[j] < p->nv) + for (int i = 0; i < pd->ntris; ++i) { + const unsigned char *t = navmesh->getDetailTri(pd->tbase + i); + const float *v[3]; + for (int j = 0; j < 3; ++j) { + if (t[j] < p->nv) { v[j] = navmesh->getVertex(p->v[t[j]]); - else - v[j] = navmesh->getDetailVertex(pd->vbase+(t[j]-p->nv)); + } + else { + v[j] = navmesh->getDetailVertex(pd->vbase + (t[j] - p->nv)); + } } - float dist = barDistSqPointToTri(spos, v[0], v[1], v[2]); - if (dist=0) - { - const unsigned char* t = navmesh->getDetailTri(pd->tbase+idxMin); - const float* v[3]; - for (int j = 0; j < 3; ++j) - { - if (t[j] < p->nv) + if (idxMin >= 0) { + const unsigned char *t = navmesh->getDetailTri(pd->tbase + idxMin); + const float *v[3]; + for (int j = 0; j < 3; ++j) { + if (t[j] < p->nv) { v[j] = navmesh->getVertex(p->v[t[j]]); - else - v[j] = navmesh->getDetailVertex(pd->vbase+(t[j]-p->nv)); + } + else { + v[j] = navmesh->getDetailVertex(pd->vbase + (t[j] - p->nv)); + } } - MT_Vector3 tri[3]; - for (size_t j=0; j<3; j++) - tri[j].setValue(v[j][0],v[j][2],v[j][1]); - MT_Vector3 a,b; - a = tri[1]-tri[0]; - b = tri[2]-tri[0]; - normal = b.cross(a).safe_normalized(); + + mt::vec3 tri[3]; + for (size_t j = 0; j < 3; j++) { + tri[j] = mt::vec3(v[j]); + } + + const mt::vec3 a = tri[1] - tri[0]; + const mt::vec3 b = tri[2] - tri[0]; + normal = mt::cross(b, a).SafeNormalized(mt::axisX3); return true; } return false; } -void KX_SteeringActuator::HandleActorFace(MT_Vector3& velocity) +void KX_SteeringActuator::HandleActorFace(const mt::vec3& velocity) { - if (m_facingMode==0 && (!m_navmesh || !m_normalUp)) - return; - KX_GameObject* curobj = (KX_GameObject*) GetParent(); - MT_Vector3 dir = m_facingMode==0 ? curobj->NodeGetLocalOrientation().getColumn(1) : velocity; - if (dir.fuzzyZero()) + if (m_facingMode == 0 && (!m_navmesh || !m_normalUp)) { return; - dir.normalize(); - MT_Vector3 up(0,0,1); - MT_Vector3 left; - MT_Matrix3x3 mat; - - if (m_navmesh && m_normalUp) - { - dtStatNavMesh* navmesh = m_navmesh->GetNavMesh(); - MT_Vector3 normal; - MT_Vector3 trpos = m_navmesh->TransformToLocalCoords(curobj->NodeGetWorldPosition()); - if (getNavmeshNormal(navmesh, trpos, normal)) - { + } - left = (dir.cross(up)).safe_normalized(); - dir = (-left.cross(normal)).safe_normalized(); + KX_GameObject *curobj = static_cast(GetParent()); + mt::vec3 dir = (m_facingMode == 0) ? curobj->NodeGetLocalOrientation().GetColumn(1) : velocity; + if (mt::FuzzyZero(dir)) { + return; + } + dir.Normalize(); + mt::vec3 up = mt::axisZ3; + mt::vec3 left; + mt::mat3 mat; + + if (m_navmesh && m_normalUp) { + dtStatNavMesh *navmesh = m_navmesh->GetNavMesh(); + mt::vec3 normal; + mt::vec3 trpos = m_navmesh->TransformToLocalCoords(curobj->NodeGetWorldPosition()); + if (getNavmeshNormal(navmesh, trpos, normal)) { + left = (mt::cross(dir, up)).SafeNormalized(mt::axisX3); + dir = (-mt::cross(left, normal)).SafeNormalized(mt::axisX3); up = normal; } } - switch (m_facingMode) - { - case 1: // TRACK X + switch (m_facingMode) { + case 1: // TRACK X { - left = dir.safe_normalized(); - dir = -(left.cross(up)).safe_normalized(); + left = dir.SafeNormalized(mt::axisX3); + dir = -(mt::cross(left, up)).SafeNormalized(mt::axisX3); break; }; - case 2: // TRACK Y + case 2: // TRACK Y { - left = (dir.cross(up)).safe_normalized(); + left = (mt::cross(dir, up)).SafeNormalized(mt::axisX3); break; } - case 3: // track Z + case 3: // track Z { - left = up.safe_normalized(); - up = dir.safe_normalized(); + left = up.SafeNormalized(mt::axisX3); + up = dir.SafeNormalized(mt::axisX3); dir = left; - left = (dir.cross(up)).safe_normalized(); + left = (mt::cross(dir, up)).SafeNormalized(mt::axisX3); break; } - case 4: // TRACK -X + case 4: // TRACK -X { - left = -dir.safe_normalized(); - dir = -(left.cross(up)).safe_normalized(); + left = -dir.SafeNormalized(mt::axisX3); + dir = -(mt::cross(left, up)).SafeNormalized(mt::axisX3); break; }; - case 5: // TRACK -Y + case 5: // TRACK -Y { - left = (-dir.cross(up)).safe_normalized(); + left = (-mt::cross(dir, up)).SafeNormalized(mt::axisX3); dir = -dir; break; } - case 6: // track -Z + case 6: // track -Z { - left = up.safe_normalized(); - up = -dir.safe_normalized(); + left = up.SafeNormalized(mt::axisX3); + up = -dir.SafeNormalized(mt::axisX3); dir = left; - left = (dir.cross(up)).safe_normalized(); + left = (mt::cross(dir, up)).SafeNormalized(mt::axisX3); break; } } - mat.setValue ( - left[0], dir[0],up[0], - left[1], dir[1],up[1], - left[2], dir[2],up[2] - ); - + mat = mt::mat3(left, dir, up); - - KX_GameObject* parentObject = curobj->GetParent(); - if (parentObject) - { - MT_Point3 localpos; - localpos = curobj->GetSGNode()->GetLocalPosition(); - MT_Matrix3x3 parentmatinv; - parentmatinv = parentObject->NodeGetWorldOrientation ().inverse (); - mat = parentmatinv * mat; - mat = m_parentlocalmat * mat; + KX_GameObject *parentObject = curobj->GetParent(); + if (parentObject) { + mt::vec3 localpos = curobj->NodeGetLocalPosition(); + mt::mat3 parentmatinv = parentObject->NodeGetWorldOrientation().Inverse(); + mat = m_parentlocalmat * parentmatinv * mat; curobj->NodeSetLocalOrientation(mat); curobj->NodeSetLocalPosition(localpos); } - else - { + else { curobj->NodeSetLocalOrientation(mat); } - } #ifdef WITH_PYTHON -/* ------------------------------------------------------------------------- */ -/* Python functions */ -/* ------------------------------------------------------------------------- */ - -/* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_SteeringActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_SteeringActuator", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -533,106 +509,129 @@ PyTypeObject KX_SteeringActuator::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IActuator::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_SteeringActuator::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} // Sentinel. }; PyAttributeDef KX_SteeringActuator::Attributes[] = { - KX_PYATTRIBUTE_INT_RW("behavior", KX_STEERING_NODEF+1, KX_STEERING_MAX-1, true, KX_SteeringActuator, m_mode), - KX_PYATTRIBUTE_RW_FUNCTION("target", KX_SteeringActuator, pyattr_get_target, pyattr_set_target), - KX_PYATTRIBUTE_RW_FUNCTION("navmesh", KX_SteeringActuator, pyattr_get_navmesh, pyattr_set_navmesh), - KX_PYATTRIBUTE_FLOAT_RW("distance", 0.0f, 1000.0f, KX_SteeringActuator, m_distance), - KX_PYATTRIBUTE_FLOAT_RW("velocity", 0.0f, 1000.0f, KX_SteeringActuator, m_velocity), - KX_PYATTRIBUTE_FLOAT_RW("acceleration", 0.0f, 1000.0f, KX_SteeringActuator, m_acceleration), - KX_PYATTRIBUTE_FLOAT_RW("turnspeed", 0.0f, 720.0f, KX_SteeringActuator, m_turnspeed), - KX_PYATTRIBUTE_BOOL_RW("selfterminated", KX_SteeringActuator, m_isSelfTerminated), - KX_PYATTRIBUTE_BOOL_RW("enableVisualization", KX_SteeringActuator, m_enableVisualization), - KX_PYATTRIBUTE_RO_FUNCTION("steeringVec", KX_SteeringActuator, pyattr_get_steeringVec), - KX_PYATTRIBUTE_SHORT_RW("facingMode", 0, 6, true, KX_SteeringActuator, m_facingMode), - KX_PYATTRIBUTE_INT_RW("pathUpdatePeriod", -1, 100000, true, KX_SteeringActuator, m_pathUpdatePeriod), - KX_PYATTRIBUTE_BOOL_RW("lockZVelocity", KX_SteeringActuator, m_lockzvel), - { NULL } //Sentinel + EXP_PYATTRIBUTE_INT_RW("behavior", KX_STEERING_NODEF + 1, KX_STEERING_MAX - 1, true, KX_SteeringActuator, m_mode), + EXP_PYATTRIBUTE_RW_FUNCTION("target", KX_SteeringActuator, pyattr_get_target, pyattr_set_target), + EXP_PYATTRIBUTE_RW_FUNCTION("navmesh", KX_SteeringActuator, pyattr_get_navmesh, pyattr_set_navmesh), + EXP_PYATTRIBUTE_FLOAT_RW("distance", 0.0f, 1000.0f, KX_SteeringActuator, m_distance), + EXP_PYATTRIBUTE_FLOAT_RW("velocity", 0.0f, 1000.0f, KX_SteeringActuator, m_velocity), + EXP_PYATTRIBUTE_FLOAT_RW("acceleration", 0.0f, 1000.0f, KX_SteeringActuator, m_acceleration), + EXP_PYATTRIBUTE_FLOAT_RW("turnspeed", 0.0f, 720.0f, KX_SteeringActuator, m_turnspeed), + EXP_PYATTRIBUTE_BOOL_RW("selfterminated", KX_SteeringActuator, m_isSelfTerminated), + EXP_PYATTRIBUTE_BOOL_RW("enableVisualization", KX_SteeringActuator, m_enableVisualization), + EXP_PYATTRIBUTE_RO_FUNCTION("steeringVec", KX_SteeringActuator, pyattr_get_steeringVec), + EXP_PYATTRIBUTE_SHORT_RW("facingMode", 0, 6, true, KX_SteeringActuator, m_facingMode), + EXP_PYATTRIBUTE_INT_RW("pathUpdatePeriod", -1, 100000, true, KX_SteeringActuator, m_pathUpdatePeriod), + EXP_PYATTRIBUTE_BOOL_RW("lockZVelocity", KX_SteeringActuator, m_lockzvel), + EXP_PYATTRIBUTE_RO_FUNCTION("path", KX_SteeringActuator, pyattr_get_path), + EXP_PYATTRIBUTE_NULL // Sentinel. }; -PyObject *KX_SteeringActuator::pyattr_get_target(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_SteeringActuator::pyattr_get_target(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - KX_SteeringActuator* actuator = static_cast(self); - if (!actuator->m_target) + KX_SteeringActuator *actuator = static_cast(self); + if (!actuator->m_target) { Py_RETURN_NONE; - else + } + else { return actuator->m_target->GetProxy(); + } } -int KX_SteeringActuator::pyattr_set_target(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_SteeringActuator::pyattr_set_target(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_SteeringActuator* actuator = static_cast(self); + KX_SteeringActuator *actuator = static_cast(self); KX_GameObject *gameobj; - if (!ConvertPythonToGameObject(actuator->GetLogicManager(), value, &gameobj, true, "actuator.object = value: KX_SteeringActuator")) - return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error - - if (actuator->m_target != NULL) + if (!ConvertPythonToGameObject(actuator->GetLogicManager(), value, &gameobj, true, "actuator.object = value: KX_SteeringActuator")) { + return PY_SET_ATTR_FAIL; + } + if (actuator->m_target) { actuator->m_target->UnregisterActuator(actuator); + } - actuator->m_target = (KX_GameObject*) gameobj; + actuator->m_target = gameobj; - if (actuator->m_target) + if (actuator->m_target) { actuator->m_target->RegisterActuator(actuator); + } return PY_SET_ATTR_SUCCESS; } -PyObject *KX_SteeringActuator::pyattr_get_navmesh(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_SteeringActuator::pyattr_get_navmesh(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - KX_SteeringActuator* actuator = static_cast(self); - if (!actuator->m_navmesh) + KX_SteeringActuator *actuator = static_cast(self); + if (!actuator->m_navmesh) { Py_RETURN_NONE; - else + } + else { return actuator->m_navmesh->GetProxy(); + } } -int KX_SteeringActuator::pyattr_set_navmesh(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_SteeringActuator::pyattr_set_navmesh(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_SteeringActuator* actuator = static_cast(self); + KX_SteeringActuator *actuator = static_cast(self); KX_GameObject *gameobj; - if (!ConvertPythonToGameObject(actuator->GetLogicManager(), value, &gameobj, true, "actuator.object = value: KX_SteeringActuator")) - return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error + if (!ConvertPythonToGameObject(actuator->GetLogicManager(), value, &gameobj, true, "actuator.object = value: KX_SteeringActuator")) { + return PY_SET_ATTR_FAIL; - if (dynamic_cast(gameobj) == NULL) { + } + if (gameobj->GetGameObjectType() != SCA_IObject::OBJ_NAVMESH) { PyErr_Format(PyExc_TypeError, "KX_NavMeshObject is expected"); return PY_SET_ATTR_FAIL; } - if (actuator->m_navmesh != NULL) + if (actuator->m_navmesh) { actuator->m_navmesh->UnregisterActuator(actuator); + } - actuator->m_navmesh = static_cast(gameobj); + actuator->m_navmesh = static_cast(gameobj); - if (actuator->m_navmesh) + if (actuator->m_navmesh) { actuator->m_navmesh->RegisterActuator(actuator); + } return PY_SET_ATTR_SUCCESS; } -PyObject *KX_SteeringActuator::pyattr_get_steeringVec(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_SteeringActuator::pyattr_get_steeringVec(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - KX_SteeringActuator* actuator = static_cast(self); - const MT_Vector3& steeringVec = actuator->GetSteeringVec(); + KX_SteeringActuator *actuator = static_cast(self); + const mt::vec3& steeringVec = actuator->GetSteeringVec(); return PyObjectFrom(steeringVec); } -#endif // WITH_PYTHON +unsigned int KX_SteeringActuator::py_get_path_size() +{ + return m_path.size(); +} + +PyObject *KX_SteeringActuator::py_get_path_item(unsigned int index) +{ + return PyObjectFrom(m_path[index]); +} + +PyObject *KX_SteeringActuator::pyattr_get_path(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) +{ + return (new EXP_ListWrapper(self))->NewProxy(true); +} -/* eof */ +#endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_SteeringActuator.h b/source/gameengine/Ketsji/KX_SteeringActuator.h index 4cdf5777da94..0cf1538ab7ef 100644 --- a/source/gameengine/Ketsji/KX_SteeringActuator.h +++ b/source/gameengine/Ketsji/KX_SteeringActuator.h @@ -29,44 +29,46 @@ #include "SCA_IActuator.h" #include "SCA_LogicManager.h" -#include "MT_Matrix3x3.h" + +#include "KX_NavMeshObject.h" + +#include "mathfu.h" class KX_GameObject; -class KX_NavMeshObject; struct KX_Obstacle; class KX_ObstacleSimulation; const int MAX_PATH_LENGTH = 128; -class KX_SteeringActuator : public SCA_IActuator +class KX_SteeringActuator : public SCA_IActuator, public mt::SimdClassAllocator { Py_Header - /** Target object */ KX_GameObject *m_target; KX_NavMeshObject *m_navmesh; - int m_mode; + int m_mode; float m_distance; float m_velocity; float m_acceleration; float m_turnspeed; - KX_ObstacleSimulation* m_simulation; + KX_ObstacleSimulation *m_simulation; double m_updateTime; - KX_Obstacle* m_obstacle; + KX_Obstacle *m_obstacle; bool m_isActive; bool m_isSelfTerminated; bool m_enableVisualization; short m_facingMode; bool m_normalUp; - float m_path[MAX_PATH_LENGTH*3]; - int m_pathLen; + KX_NavMeshObject::PathType m_path; int m_pathUpdatePeriod; double m_pathUpdateTime; bool m_lockzvel; int m_wayPointIdx; - MT_Matrix3x3 m_parentlocalmat; - MT_Vector3 m_steerVec; - void HandleActorFace(MT_Vector3& velocity); + mt::mat3 m_parentlocalmat; + mt::vec3 m_steerVec; + + void HandleActorFace(const mt::vec3& velocity); + public: enum KX_STEERINGACT_MODE { @@ -77,47 +79,33 @@ class KX_SteeringActuator : public SCA_IActuator KX_STEERING_MAX }; - KX_SteeringActuator(class SCA_IObject* gameobj, - int mode, - KX_GameObject *target, - KX_GameObject *navmesh, - float distance, - float velocity, - float acceleration, - float turnspeed, - bool isSelfTerminated, - int pathUpdatePeriod, - KX_ObstacleSimulation* simulation, - short facingmode, - bool normalup, - bool enableVisualization, - bool lockzvel); + KX_SteeringActuator(SCA_IObject *gameobj, int mode, KX_GameObject *target, KX_GameObject *navmesh, float distance, + float velocity, float acceleration, float turnspeed, bool isSelfTerminated, int pathUpdatePeriod, + KX_ObstacleSimulation *simulation, short facingmode, bool normalup, bool enableVisualization, bool lockzvel); virtual ~KX_SteeringActuator(); - virtual bool Update(double curtime, bool frame); - virtual CValue* GetReplica(); + virtual bool Update(double curtime); + + virtual EXP_Value *GetReplica(); virtual void ProcessReplica(); - virtual void ReParent(SCA_IObject* parent); - virtual void Relink(CTR_Map *obj_map); - virtual bool UnlinkObject(SCA_IObject* clientobj); - const MT_Vector3& GetSteeringVec(); + virtual void ReParent(SCA_IObject *parent); + virtual void Relink(std::map& obj_map); + virtual bool UnlinkObject(SCA_IObject *clientobj); + const mt::vec3& GetSteeringVec() const; #ifdef WITH_PYTHON - /* --------------------------------------------------------------------- */ - /* Python interface ---------------------------------------------------- */ - /* --------------------------------------------------------------------- */ - - /* These are used to get and set m_target */ - static PyObject *pyattr_get_target(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_target(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject *pyattr_get_navmesh(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_navmesh(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject *pyattr_get_steeringVec(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - + static PyObject *pyattr_get_target(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_target(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_navmesh(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_navmesh(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_steeringVec(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_path(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); -#endif /* WITH_PYTHON */ + unsigned int py_get_path_size(); + PyObject *py_get_path_item(unsigned int index); -}; /* end of class KX_SteeringActuator : public SCA_PropertyActuator */ +#endif // WITH_PYTHON +}; -#endif /* __KX_STEERINGACTUATOR_H__ */ +#endif // __KX_STEERINGACTUATOR_H__ diff --git a/source/gameengine/Ketsji/KX_TextMaterial.cpp b/source/gameengine/Ketsji/KX_TextMaterial.cpp new file mode 100644 index 000000000000..229a2fb18f76 --- /dev/null +++ b/source/gameengine/Ketsji/KX_TextMaterial.cpp @@ -0,0 +1,115 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Ketsji/KX_TextMaterial.cpp + * \ingroup ketsji + */ + +#include "KX_TextMaterial.h" + +#include "DNA_material_types.h" + +KX_TextMaterial::KX_TextMaterial() + :RAS_IMaterial("__TextMaterial__") +{ + m_rasMode |= (RAS_ALPHA | RAS_TEXT); + m_alphablend = GEMAT_ALPHA; +} + +KX_TextMaterial::~KX_TextMaterial() +{ +} + +void KX_TextMaterial::Prepare(RAS_Rasterizer *rasty) +{ +} + +void KX_TextMaterial::Activate(RAS_Rasterizer *rasty) +{ +} + +void KX_TextMaterial::Desactivate(RAS_Rasterizer *rasty) +{ +} + +void KX_TextMaterial::ActivateInstancing(RAS_Rasterizer *rasty, RAS_InstancingBuffer *buffer) +{ +} + +void KX_TextMaterial::DesactivateInstancing() +{ +} + +void KX_TextMaterial::ActivateMeshUser(RAS_MeshUser *meshUser, RAS_Rasterizer *rasty, const mt::mat3x4& camtrans) +{ +} + +const std::string KX_TextMaterial::GetTextureName() const +{ + return ""; +} + +Material *KX_TextMaterial::GetBlenderMaterial() const +{ + return nullptr; +} + +Scene *KX_TextMaterial::GetBlenderScene() const +{ + return nullptr; +} + +SCA_IScene *KX_TextMaterial::GetScene() const +{ + return nullptr; +} + +bool KX_TextMaterial::UseInstancing() const +{ + return false; +} + +void KX_TextMaterial::ReloadMaterial() +{ +} + +void KX_TextMaterial::UpdateIPO(const mt::vec4 &rgba, const mt::vec3 &specrgb, float hard, float spec, float ref, + float emit, float ambient, float alpha, float specalpha) +{ +} + +const RAS_AttributeArray::AttribList KX_TextMaterial::GetAttribs(const RAS_Mesh::LayersInfo& layersInfo) const +{ + return {}; +} + +RAS_InstancingBuffer::Attrib KX_TextMaterial::GetInstancingAttribs() const +{ + return RAS_InstancingBuffer::DEFAULT_ATTRIBS; +} + +KX_TextMaterial *KX_TextMaterial::GetSingleton() +{ + static KX_TextMaterial singleton; + return &singleton; +} + diff --git a/source/gameengine/Ketsji/KX_TextMaterial.h b/source/gameengine/Ketsji/KX_TextMaterial.h new file mode 100644 index 000000000000..2432eb82694b --- /dev/null +++ b/source/gameengine/Ketsji/KX_TextMaterial.h @@ -0,0 +1,62 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file KX_TextMaterial.h + * \ingroup ketsji + * \brief Fake material used for all text objects. + */ + +#ifndef __KX_TEXTMATERIAL_H__ +#define __KX_TEXTMATERIAL_H__ + +#include "RAS_IMaterial.h" + +class KX_TextMaterial : public RAS_IMaterial +{ +public: + KX_TextMaterial(); + virtual ~KX_TextMaterial(); + + virtual void Prepare(RAS_Rasterizer *rasty); + virtual void Activate(RAS_Rasterizer *rasty); + virtual void Desactivate(RAS_Rasterizer *rasty); + virtual void ActivateInstancing(RAS_Rasterizer *rasty, RAS_InstancingBuffer *buffer); + virtual void DesactivateInstancing(); + virtual void ActivateMeshUser(RAS_MeshUser *meshUser, RAS_Rasterizer *rasty, const mt::mat3x4& camtrans); + + virtual const std::string GetTextureName() const; + virtual Material *GetBlenderMaterial() const; + virtual Scene *GetBlenderScene() const; + virtual SCA_IScene *GetScene() const; + virtual bool UseInstancing() const; + virtual void ReloadMaterial(); + + virtual void UpdateIPO(const mt::vec4 &rgba, const mt::vec3 &specrgb, float hard, float spec, float ref, + float emit, float ambient, float alpha, float specalpha); + + virtual const RAS_AttributeArray::AttribList GetAttribs(const RAS_Mesh::LayersInfo& layersInfo) const; + virtual RAS_InstancingBuffer::Attrib GetInstancingAttribs() const; + + static KX_TextMaterial *GetSingleton(); +}; + +#endif // __KX_TEXTMATERIAL_H__ diff --git a/source/gameengine/Ketsji/KX_TextureRenderer.cpp b/source/gameengine/Ketsji/KX_TextureRenderer.cpp new file mode 100644 index 000000000000..b692e199b4cc --- /dev/null +++ b/source/gameengine/Ketsji/KX_TextureRenderer.cpp @@ -0,0 +1,231 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Ulysse Martin, Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file KX_TextureRenderer.cpp + * \ingroup ketsji + */ + +#include "KX_TextureRenderer.h" +#include "KX_GameObject.h" +#include "KX_Globals.h" + +#include "DNA_texture_types.h" + +KX_TextureRenderer::KX_TextureRenderer(EnvMap *env, KX_GameObject *viewpoint) + :m_clipStart(env->clipsta), + m_clipEnd(env->clipend), + m_viewpointObject(viewpoint), + m_enabled(true), + m_ignoreLayers(env->notlay), + m_lodDistanceFactor(env->lodfactor), + m_forceUpdate(true) +{ + m_autoUpdate = (env->flag & ENVMAP_AUTO_UPDATE) != 0; +} + +KX_TextureRenderer::~KX_TextureRenderer() +{ +} + +std::string KX_TextureRenderer::GetName() +{ + return "KX_TextureRenderer"; +} + +KX_GameObject *KX_TextureRenderer::GetViewpointObject() const +{ + return m_viewpointObject; +} + +void KX_TextureRenderer::SetViewpointObject(KX_GameObject *gameobj) +{ + m_viewpointObject = gameobj; +} + +bool KX_TextureRenderer::GetEnabled() const +{ + return m_enabled; +} + +int KX_TextureRenderer::GetIgnoreLayers() const +{ + return m_ignoreLayers; +} + +float KX_TextureRenderer::GetClipStart() const +{ + return m_clipStart; +} + +float KX_TextureRenderer::GetClipEnd() const +{ + return m_clipEnd; +} + +void KX_TextureRenderer::SetClipStart(float start) +{ + m_clipStart = start; +} + +void KX_TextureRenderer::SetClipEnd(float end) +{ + m_clipEnd = end; +} + +float KX_TextureRenderer::GetLodDistanceFactor() const +{ + return m_lodDistanceFactor; +} + +void KX_TextureRenderer::SetLodDistanceFactor(float lodfactor) +{ + m_lodDistanceFactor = lodfactor; +} + +bool KX_TextureRenderer::NeedUpdate() +{ + bool result = m_autoUpdate || m_forceUpdate; + // Disable the force update for the next render. + m_forceUpdate = false; + + return result; +} + +#ifdef WITH_PYTHON + +PyTypeObject KX_TextureRenderer::Type = { + PyVarObject_HEAD_INIT(nullptr, 0) + "KX_TextureRenderer", + sizeof(EXP_PyObjectPlus_Proxy), + 0, + py_base_dealloc, + 0, + 0, + 0, + 0, + py_base_repr, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + 0, 0, 0, 0, 0, 0, 0, + Methods, + 0, + 0, + &EXP_Value::Type, + 0, 0, 0, 0, 0, 0, + py_base_new +}; + +PyMethodDef KX_TextureRenderer::Methods[] = { + EXP_PYMETHODTABLE_NOARGS(KX_TextureRenderer, update), + {nullptr, nullptr} // Sentinel +}; + +PyAttributeDef KX_TextureRenderer::Attributes[] = { + EXP_PYATTRIBUTE_RW_FUNCTION("viewpointObject", KX_TextureRenderer, pyattr_get_viewpoint_object, pyattr_set_viewpoint_object), + EXP_PYATTRIBUTE_BOOL_RW("autoUpdate", KX_TextureRenderer, m_autoUpdate), + EXP_PYATTRIBUTE_BOOL_RW("enabled", KX_TextureRenderer, m_enabled), + EXP_PYATTRIBUTE_INT_RW("ignoreLayers", 0, (1 << 20) - 1, true, KX_TextureRenderer, m_ignoreLayers), + EXP_PYATTRIBUTE_RW_FUNCTION("clipStart", KX_TextureRenderer, pyattr_get_clip_start, pyattr_set_clip_start), + EXP_PYATTRIBUTE_RW_FUNCTION("clipEnd", KX_TextureRenderer, pyattr_get_clip_end, pyattr_set_clip_end), + EXP_PYATTRIBUTE_FLOAT_RW("lodDistanceFactor", 0.0f, FLT_MAX, KX_TextureRenderer, m_lodDistanceFactor), + EXP_PYATTRIBUTE_NULL // Sentinel +}; + +EXP_PYMETHODDEF_DOC_NOARGS(KX_TextureRenderer, update, "update(): Set the texture rendered to be updated next frame.\n") +{ + m_forceUpdate = true; + Py_RETURN_NONE; +} + +PyObject *KX_TextureRenderer::pyattr_get_viewpoint_object(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_TextureRenderer *self = static_cast(self_v); + KX_GameObject *gameobj = self->GetViewpointObject(); + if (gameobj) { + return gameobj->GetProxy(); + } + Py_RETURN_NONE; +} + +int KX_TextureRenderer::pyattr_set_viewpoint_object(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_TextureRenderer *self = static_cast(self_v); + KX_GameObject *gameobj = nullptr; + + SCA_LogicManager *logicmgr = KX_GetActiveScene()->GetLogicManager(); + + if (!ConvertPythonToGameObject(logicmgr, value, &gameobj, true, "renderer.object = value: KX_TextureRenderer")) { + return PY_SET_ATTR_FAIL; + } + + self->SetViewpointObject(gameobj); + return PY_SET_ATTR_SUCCESS; +} + + +PyObject *KX_TextureRenderer::pyattr_get_clip_start(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_TextureRenderer *self = static_cast(self_v); + return PyFloat_FromDouble(self->GetClipStart()); +} + +int KX_TextureRenderer::pyattr_set_clip_start(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_TextureRenderer *self = static_cast(self_v); + + const float val = PyFloat_AsDouble(value); + + if (val <= 0.0f) { + PyErr_SetString(PyExc_AttributeError, "cubeMap.clipStart = float: KX_TextureRenderer, expected a float grater than zero"); + return PY_SET_ATTR_FAIL; + } + + self->SetClipStart(val); + self->InvalidateProjectionMatrix(); + + return PY_SET_ATTR_SUCCESS; +} + +PyObject *KX_TextureRenderer::pyattr_get_clip_end(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_TextureRenderer *self = static_cast(self_v); + return PyFloat_FromDouble(self->GetClipEnd()); +} + +int KX_TextureRenderer::pyattr_set_clip_end(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_TextureRenderer *self = static_cast(self_v); + + const float val = PyFloat_AsDouble(value); + + if (val <= 0.0f) { + PyErr_SetString(PyExc_AttributeError, "cubeMap.clipEnd = float: KX_TextureRenderer, expected a float grater than zero"); + return PY_SET_ATTR_FAIL; + } + + self->SetClipEnd(val); + self->InvalidateProjectionMatrix(); + + return PY_SET_ATTR_SUCCESS; +} + +#endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_TextureRenderer.h b/source/gameengine/Ketsji/KX_TextureRenderer.h new file mode 100644 index 000000000000..34e7d1832547 --- /dev/null +++ b/source/gameengine/Ketsji/KX_TextureRenderer.h @@ -0,0 +1,115 @@ +/* +* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* Contributor(s): Ulysse Martin, Tristan Porteries. +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +/** \file KX_TextureRenderer.h + * \ingroup ketsji + */ + +#ifndef __KX_TEXTURE_RENDERER_H__ +#define __KX_TEXTURE_RENDERER_H__ + +#include "EXP_Value.h" +#include "RAS_TextureRenderer.h" + +class KX_GameObject; +class KX_Camera; +class KX_Scene; +class RAS_Rect; + +struct EnvMap; + +class KX_TextureRenderer : public EXP_Value, public RAS_TextureRenderer +{ + Py_Header + +protected: + /// View clip start. + float m_clipStart; + /// View clip end. + float m_clipEnd; + +private: + /// The object used to render from its position. + KX_GameObject *m_viewpointObject; + + /// The texture renderer is enabled for render. + bool m_enabled; + /// Layers to ignore during render. + int m_ignoreLayers; + + + /// Distance factor for level of detail. + float m_lodDistanceFactor; + + /// True if the renderer is updated every frame. + bool m_autoUpdate; + /** True if the renderer need to be updated for the next frame. + * Generally used when m_autoUpdate is to false. + */ + bool m_forceUpdate; + +public: + KX_TextureRenderer(EnvMap *env, KX_GameObject *viewpoint); + virtual ~KX_TextureRenderer(); + + virtual std::string GetName(); + + KX_GameObject *GetViewpointObject() const; + void SetViewpointObject(KX_GameObject *gameobj); + + virtual void InvalidateProjectionMatrix() = 0; + + float GetLodDistanceFactor() const; + void SetLodDistanceFactor(float lodfactor); + + virtual const mt::mat4& GetProjectionMatrix(RAS_Rasterizer *rasty, KX_Scene *scene, KX_Camera *sceneCamera, + const RAS_Rect& viewport, const RAS_Rect& area) = 0; + + bool GetEnabled() const; + int GetIgnoreLayers() const; + + float GetClipStart() const; + float GetClipEnd() const; + void SetClipStart(float start); + void SetClipEnd(float end); + + // Return true when the texture renderer need to be updated. + bool NeedUpdate(); + + /// Setup camera position and orientation shared by all the faces, returns true when the render will be made. + virtual bool SetupCamera(KX_Camera *sceneCamera, KX_Camera *camera) = 0; + /// Setup camera position and orientation unique per faces, returns true when the render will be made. + virtual bool SetupCameraFace(KX_Camera *camera, unsigned short index) = 0; + +#ifdef WITH_PYTHON + EXP_PYMETHOD_DOC_NOARGS(KX_TextureRenderer, update); + + static PyObject *pyattr_get_viewpoint_object(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_viewpoint_object(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_clip_start(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_clip_start(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_clip_end(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_clip_end(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); +#endif +}; + +#endif // __KX_TEXTURE_RENDERER_H__ diff --git a/source/gameengine/Ketsji/KX_TextureRendererManager.cpp b/source/gameengine/Ketsji/KX_TextureRendererManager.cpp new file mode 100644 index 000000000000..cb6859cd8899 --- /dev/null +++ b/source/gameengine/Ketsji/KX_TextureRendererManager.cpp @@ -0,0 +1,221 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Ulysse Martin, Tristan Porteries, Martins Upitis. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Ketsji/KX_TextureRendererManager.cpp + * \ingroup ketsji + */ + +#include "KX_TextureRendererManager.h" +#include "KX_Camera.h" +#include "KX_Scene.h" +#include "KX_Globals.h" +#include "KX_CubeMap.h" +#include "KX_PlanarMap.h" + +#include "RAS_Rasterizer.h" +#include "RAS_OffScreen.h" +#include "RAS_Texture.h" + +#include "DNA_texture_types.h" + +#include "CM_Message.h" + +KX_TextureRendererManager::KX_TextureRendererManager(KX_Scene *scene) + :m_scene(scene) +{ + const RAS_CameraData& camdata = RAS_CameraData(); + m_camera = new KX_Camera(m_scene, KX_Scene::m_callbacks, camdata, true); + m_camera->SetName("__renderer_cam__"); +} + +KX_TextureRendererManager::~KX_TextureRendererManager() +{ + for (unsigned short i = 0; i < CATEGORY_MAX; ++i) { + for (KX_TextureRenderer *renderer : m_renderers[i]) { + delete renderer; + } + } + + m_camera->Release(); +} + +void KX_TextureRendererManager::InvalidateViewpoint(KX_GameObject *gameobj) +{ + for (unsigned short i = 0; i < CATEGORY_MAX; ++i) { + for (KX_TextureRenderer *renderer : m_renderers[i]) { + if (renderer->GetViewpointObject() == gameobj) { + renderer->SetViewpointObject(nullptr); + } + } + } +} + +void KX_TextureRendererManager::AddRenderer(RendererType type, RAS_Texture *texture, KX_GameObject *viewpoint) +{ + /* Don't Add renderer several times for the same texture. If the texture is shared by several objects, + * we just add a "textureUser" to signal that the renderer texture will be shared by several objects. + */ + for (unsigned short i = 0; i < CATEGORY_MAX; ++i) { + for (KX_TextureRenderer *renderer : m_renderers[i]) { + if (renderer->EqualTextureUser(texture)) { + renderer->AddTextureUser(texture); + + KX_GameObject *origviewpoint = renderer->GetViewpointObject(); + if (viewpoint != origviewpoint) { + CM_Warning("texture renderer (" << texture->GetName() << ") uses different viewpoint objects (" << + (origviewpoint ? origviewpoint->GetName() : "") << " and " << viewpoint->GetName() << ")."); + } + return; + } + } + } + + EnvMap *env = texture->GetTex()->env; + KX_TextureRenderer *renderer; + switch (type) { + case CUBE: + { + renderer = new KX_CubeMap(env, viewpoint); + m_renderers[VIEWPORT_INDEPENDENT].push_back(renderer); + break; + } + case PLANAR: + { + renderer = new KX_PlanarMap(env, viewpoint); + m_renderers[VIEWPORT_DEPENDENT].push_back(renderer); + break; + } + } + + renderer->AddTextureUser(texture); +} + +bool KX_TextureRendererManager::RenderRenderer(RAS_Rasterizer *rasty, KX_TextureRenderer *renderer, + KX_Camera *sceneCamera, const RAS_Rect& viewport, const RAS_Rect& area) +{ + KX_GameObject *viewpoint = renderer->GetViewpointObject(); + // Doesn't need (or can) update. + if (!renderer->NeedUpdate() || !renderer->GetEnabled() || !viewpoint) { + return false; + } + + // Set camera setting shared by all the renderer's faces. + if (!renderer->SetupCamera(sceneCamera, m_camera)) { + return false; + } + + const bool visible = viewpoint->GetVisible(); + /* We hide the viewpoint object in the case backface culling is disabled -> we can't see through + * the object faces if the camera is inside the gameobject. + */ + viewpoint->SetVisible(false, false); + + // Set camera lod distance factor from renderer value. + m_camera->SetLodDistanceFactor(renderer->GetLodDistanceFactor()); + + /* When we update clipstart or clipend values, + * or if the projection matrix is not computed yet, + * we have to compute projection matrix. + */ + const mt::mat4& projmat = renderer->GetProjectionMatrix(rasty, m_scene, sceneCamera, viewport, area); + m_camera->SetProjectionMatrix(projmat); + rasty->SetProjectionMatrix(projmat); + + // Begin rendering stuff + renderer->BeginRender(rasty); + + for (unsigned short i = 0; i < renderer->GetNumFaces(); ++i) { + // Set camera settings unique per faces. + if (!renderer->SetupCameraFace(m_camera, i)) { + continue; + } + + m_camera->NodeUpdate(); + + renderer->BindFace(i); + + const mt::mat3x4 camtrans(m_camera->GetWorldToCamera()); + const mt::mat4 viewmat = mt::mat4::FromAffineTransform(camtrans); + + rasty->SetViewMatrix(viewmat); + m_camera->SetModelviewMatrix(viewmat); + + const std::vector objects = m_scene->CalculateVisibleMeshes(m_camera, ~renderer->GetIgnoreLayers()); + + /* Updating the lod per face is normally not expensive because a cube map normally show every objects + * but here we update only visible object of a face including the clip end and start. + */ + m_scene->UpdateObjectLods(m_camera, objects); + + /* Update animations to use the culling of each faces, BL_ActionManager avoid redundants + * updates internally. */ + KX_GetActiveEngine()->UpdateAnimations(m_scene); + + renderer->BeginRenderFace(rasty); + + // Now the objects are culled and we can render the scene. + m_scene->GetWorldInfo()->RenderBackground(rasty); + // Send a nullptr off screen because we use a set of FBO with shared textures, not an off screen. + m_scene->RenderBuckets(objects, RAS_Rasterizer::RAS_RENDERER, camtrans, rasty, nullptr); + + renderer->EndRenderFace(rasty); + } + + viewpoint->SetVisible(visible, false); + + renderer->EndRender(rasty); + + return true; +} + +void KX_TextureRendererManager::Render(RendererCategory category, RAS_Rasterizer *rasty, RAS_OffScreen *offScreen, + KX_Camera *sceneCamera, const RAS_Rect& viewport, const RAS_Rect& area) +{ + const std::vector& renderers = m_renderers[category]; + if (renderers.empty() || rasty->GetDrawingMode() != RAS_Rasterizer::RAS_TEXTURED) { + return; + } + + // Disable scissor to not bother with scissor box. + rasty->Disable(RAS_Rasterizer::RAS_SCISSOR_TEST); + + // Check if at least one renderer was rendered. + bool rendered = false; + for (KX_TextureRenderer *renderer : renderers) { + rendered |= RenderRenderer(rasty, renderer, sceneCamera, viewport, area); + } + + rasty->Enable(RAS_Rasterizer::RAS_SCISSOR_TEST); + + if (offScreen && rendered) { + // Restore the off screen bound before rendering the texture renderers. + offScreen->Bind(); + } +} + +void KX_TextureRendererManager::Merge(KX_TextureRendererManager *other) +{ + for (unsigned short i = 0; i < CATEGORY_MAX; ++i) { + m_renderers[i].insert(m_renderers[i].end(), other->m_renderers[i].begin(), other->m_renderers[i].end()); + other->m_renderers[i].clear(); + } +} diff --git a/source/gameengine/Ketsji/KX_TextureRendererManager.h b/source/gameengine/Ketsji/KX_TextureRendererManager.h new file mode 100644 index 000000000000..c69748b0092c --- /dev/null +++ b/source/gameengine/Ketsji/KX_TextureRendererManager.h @@ -0,0 +1,95 @@ +/* +* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* Contributor(s): Ulysse Martin, Tristan Porteries, Martins Upitis. +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +/** \file KX_TextureRendererManager.h +* \ingroup ketsji +*/ + +#ifndef __KX_TEXTURE_RENDERER_MANAGER_H__ +#define __KX_TEXTURE_RENDERER_MANAGER_H__ + +#include + +class KX_GameObject; +class KX_Camera; +class KX_Scene; +class KX_TextureRenderer; + +class RAS_Rasterizer; +class RAS_OffScreen; +class RAS_Texture; +class RAS_Rect; + +class KX_TextureRendererManager +{ +public: + enum RendererCategory { + VIEWPORT_DEPENDENT = 0, + VIEWPORT_INDEPENDENT, + CATEGORY_MAX + }; + +private: + /// All existing renderers of this scene by categories. + std::vector m_renderers[CATEGORY_MAX]; + /// The camera used for renderers render, it's own by the renderer manager. + KX_Camera *m_camera; + /// The scene we are rendering for. + KX_Scene *m_scene; + + /// Render a texture renderer, return true if the render was proceeded. + bool RenderRenderer(RAS_Rasterizer *rasty, KX_TextureRenderer *renderer, + KX_Camera *sceneCamera, const RAS_Rect& viewport, const RAS_Rect& area); + +public: + enum RendererType { + CUBE, + PLANAR + }; + + KX_TextureRendererManager(KX_Scene *scene); + virtual ~KX_TextureRendererManager(); + + /// Invalidate renderers using the given game object as viewpoint object. + void InvalidateViewpoint(KX_GameObject *gameobj); + + /** Add and create a renderer if none existing renderer was using the same + * texture containing in the material texture passed. + */ + void AddRenderer(RendererType type, RAS_Texture *texture, KX_GameObject *viewpoint); + + /** Execute all the texture renderer. + * \param category The category of renderers to render. + * \param offScreen The off screen bound before rendering the texture renderers. + * \param sceneCamera The scene camera currently rendering the scene, used only in case of + * VIEWPORT_DEPENDENT category. + * \param viewport The viewport render area. + * \param area The windows render area. + */ + void Render(RendererCategory category, RAS_Rasterizer *rasty, RAS_OffScreen *offScreen, + KX_Camera *sceneCamera, const RAS_Rect& viewport, const RAS_Rect& area); + + /// Merge the content of an other renderer manager, used during lib loading. + void Merge(KX_TextureRendererManager *other); +}; + +#endif // __KX_TEXTURE_RENDERER_MANAGER_H__ diff --git a/source/gameengine/Ketsji/KX_TimeCategoryLogger.cpp b/source/gameengine/Ketsji/KX_TimeCategoryLogger.cpp index 7c83a6eb350f..7e7db34282a4 100644 --- a/source/gameengine/Ketsji/KX_TimeCategoryLogger.cpp +++ b/source/gameengine/Ketsji/KX_TimeCategoryLogger.cpp @@ -32,109 +32,81 @@ #include "KX_TimeCategoryLogger.h" -KX_TimeCategoryLogger::KX_TimeCategoryLogger(unsigned int maxNumMeasurements) -: m_maxNumMeasurements(maxNumMeasurements) +KX_TimeCategoryLogger::KX_TimeCategoryLogger(const CM_Clock& clock, unsigned int maxNumMeasurements) + :m_clock(clock), + m_maxNumMeasurements(maxNumMeasurements), + m_lastCategory(-1) { } - -KX_TimeCategoryLogger::~KX_TimeCategoryLogger(void) +KX_TimeCategoryLogger::~KX_TimeCategoryLogger() { - DisposeLoggers(); } - void KX_TimeCategoryLogger::SetMaxNumMeasurements(unsigned int maxNumMeasurements) { - KX_TimeLoggerMap::iterator it; - for (it = m_loggers.begin(); it != m_loggers.end(); it++) { - it->second->SetMaxNumMeasurements(maxNumMeasurements); + for (TimeLoggerMap::value_type& pair : m_loggers) { + pair.second.SetMaxNumMeasurements(maxNumMeasurements); } m_maxNumMeasurements = maxNumMeasurements; } - -unsigned int KX_TimeCategoryLogger::GetMaxNumMeasurements(void) const +unsigned int KX_TimeCategoryLogger::GetMaxNumMeasurements() const { return m_maxNumMeasurements; } - void KX_TimeCategoryLogger::AddCategory(TimeCategory tc) { // Only add if not already present if (m_loggers.find(tc) == m_loggers.end()) { - KX_TimeLogger* logger = new KX_TimeLogger(m_maxNumMeasurements); - //assert(logger); - m_loggers.insert(KX_TimeLoggerMap::value_type(tc, logger)); + m_loggers.emplace(TimeLoggerMap::value_type(tc, KX_TimeLogger(m_maxNumMeasurements))); } } - -void KX_TimeCategoryLogger::StartLog(TimeCategory tc, double now, bool endOtherCategories) +void KX_TimeCategoryLogger::StartLog(TimeCategory tc) { - if (endOtherCategories) { - KX_TimeLoggerMap::iterator it; - for (it = m_loggers.begin(); it != m_loggers.end(); it++) { - if (it->first != tc) { - it->second->EndLog(now); - } - } + const double now = m_clock.GetTimeSecond(); + if (m_lastCategory != -1) { + m_loggers[m_lastCategory].EndLog(now); } - //assert(m_loggers[tc] != m_loggers.end()); - m_loggers[tc]->StartLog(now); + m_loggers[tc].StartLog(now); + m_lastCategory = tc; } - -void KX_TimeCategoryLogger::EndLog(TimeCategory tc, double now) +void KX_TimeCategoryLogger::EndLog(TimeCategory tc) { - //assert(m_loggers[tc] != m_loggers.end()); - m_loggers[tc]->EndLog(now); + const double now = m_clock.GetTimeSecond(); + m_loggers[tc].EndLog(now); } - -void KX_TimeCategoryLogger::EndLog(double now) +void KX_TimeCategoryLogger::EndLog() { - KX_TimeLoggerMap::iterator it; - for (it = m_loggers.begin(); it != m_loggers.end(); it++) { - it->second->EndLog(now); - } + const double now = m_clock.GetTimeSecond(); + m_loggers[m_lastCategory].EndLog(now); + m_lastCategory = -1; } - -void KX_TimeCategoryLogger::NextMeasurement(double now) +void KX_TimeCategoryLogger::NextMeasurement() { - KX_TimeLoggerMap::iterator it; - for (it = m_loggers.begin(); it != m_loggers.end(); it++) { - it->second->NextMeasurement(now); + const double now = m_clock.GetTimeSecond(); + for (TimeLoggerMap::value_type& pair : m_loggers) { + pair.second.NextMeasurement(now); } } - double KX_TimeCategoryLogger::GetAverage(TimeCategory tc) { - //assert(m_loggers[tc] != m_loggers.end()); - return m_loggers[tc]->GetAverage(); + return m_loggers[tc].GetAverage(); } - -double KX_TimeCategoryLogger::GetAverage(void) +double KX_TimeCategoryLogger::GetAverage() { double time = 0.0; - KX_TimeLoggerMap::iterator it; - for (it = m_loggers.begin(); it != m_loggers.end(); it++) { - time += it->second->GetAverage(); + for (TimeLoggerMap::value_type& pair : m_loggers) { + time += pair.second.GetAverage(); } return time; } - - -void KX_TimeCategoryLogger::DisposeLoggers(void) -{ - KX_TimeLoggerMap::iterator it; - for (it = m_loggers.begin(); it != m_loggers.end(); it++) { - delete it->second; - } -} diff --git a/source/gameengine/Ketsji/KX_TimeCategoryLogger.h b/source/gameengine/Ketsji/KX_TimeCategoryLogger.h index d27cd42c2556..00b70d62488f 100644 --- a/source/gameengine/Ketsji/KX_TimeCategoryLogger.h +++ b/source/gameengine/Ketsji/KX_TimeCategoryLogger.h @@ -39,6 +39,7 @@ #include #include "KX_TimeLogger.h" +#include "CM_Clock.h" /** * Stores and manages time measurements by category. @@ -46,91 +47,80 @@ * Average measurements can be established for each separate category * or for all categories together. */ -class KX_TimeCategoryLogger { +class KX_TimeCategoryLogger +{ public: typedef int TimeCategory; + typedef std::map TimeLoggerMap; /** * Constructor. * \param maxNumMesasurements Maximum number of measurements stored (> 1). */ - KX_TimeCategoryLogger(unsigned int maxNumMeasurements = 10); + KX_TimeCategoryLogger(const CM_Clock& clock, unsigned int maxNumMeasurements = 10); /** * Destructor. */ - virtual ~KX_TimeCategoryLogger(void); + ~KX_TimeCategoryLogger(); /** * Changes the maximum number of measurements that can be stored. */ - virtual void SetMaxNumMeasurements(unsigned int maxNumMeasurements); + void SetMaxNumMeasurements(unsigned int maxNumMeasurements); /** * Changes the maximum number of measurements that can be stored. */ - virtual unsigned int GetMaxNumMeasurements(void) const; + unsigned int GetMaxNumMeasurements() const; /** * Adds a category. * \param category The new category. */ - virtual void AddCategory(TimeCategory tc); + void AddCategory(TimeCategory tc); /** * Starts logging in current measurement for the given category. * \param tc The category to log to. - * \param now The current time. - * \param endOtherCategories Whether to stop logging to other categories. */ - virtual void StartLog(TimeCategory tc, double now, bool endOtherCategories = true); + void StartLog(TimeCategory tc); /** * End logging in current measurement for the given category. * \param tc The category to log to. - * \param now The current time. */ - virtual void EndLog(TimeCategory tc, double now); + void EndLog(TimeCategory tc); /** * End logging in current measurement for all categories. - * \param now The current time. */ - virtual void EndLog(double now); + void EndLog(); /** * Logs time in next measurement. - * \param now The current time. */ - virtual void NextMeasurement(double now); + void NextMeasurement(); /** * Returns average of all but the current measurement time. * \return The average of all but the current measurement. */ - virtual double GetAverage(TimeCategory tc); + double GetAverage(TimeCategory tc); /** * Returns average for grand total. */ - virtual double GetAverage(void); + double GetAverage(); protected: - /** - * Disposes loggers. - */ - virtual void DisposeLoggers(void); - - /** Storage for the loggers. */ - typedef std::map KX_TimeLoggerMap; - KX_TimeLoggerMap m_loggers; - /** Maximum number of measurements. */ + const CM_Clock& m_clock; + /// Storage for the loggers. + TimeLoggerMap m_loggers; + /// Maximum number of measurements. unsigned int m_maxNumMeasurements; - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_TimeCategoryLogger") -#endif + TimeCategory m_lastCategory; }; #endif /* __KX_TIMECATEGORYLOGGER_H__ */ diff --git a/source/gameengine/Ketsji/KX_TimeLogger.cpp b/source/gameengine/Ketsji/KX_TimeLogger.cpp index 03c95846984b..9be7a741e274 100644 --- a/source/gameengine/Ketsji/KX_TimeLogger.cpp +++ b/source/gameengine/Ketsji/KX_TimeLogger.cpp @@ -32,19 +32,17 @@ #include "KX_TimeLogger.h" -KX_TimeLogger::KX_TimeLogger(unsigned int maxNumMeasurements) : - m_maxNumMeasurements(maxNumMeasurements), +KX_TimeLogger::KX_TimeLogger(unsigned int maxNumMeasurements) + :m_maxNumMeasurements(maxNumMeasurements), m_logStart(0), m_logging(false) { } - -KX_TimeLogger::~KX_TimeLogger(void) +KX_TimeLogger::~KX_TimeLogger() { } - void KX_TimeLogger::SetMaxNumMeasurements(unsigned int maxNumMeasurements) { if ((m_maxNumMeasurements != maxNumMeasurements) && maxNumMeasurements) { @@ -53,13 +51,11 @@ void KX_TimeLogger::SetMaxNumMeasurements(unsigned int maxNumMeasurements) } } - -unsigned int KX_TimeLogger::GetMaxNumMeasurements(void) const +unsigned int KX_TimeLogger::GetMaxNumMeasurements() const { return m_maxNumMeasurements; } - void KX_TimeLogger::StartLog(double now) { if (!m_logging) { @@ -68,19 +64,17 @@ void KX_TimeLogger::StartLog(double now) } } - void KX_TimeLogger::EndLog(double now) { if (m_logging) { m_logging = false; double time = now - m_logStart; - if (m_measurements.size() > 0) { + if (!m_measurements.empty()) { m_measurements[0] += time; } } } - void KX_TimeLogger::NextMeasurement(double now) { // End logging to current measurement @@ -98,13 +92,11 @@ void KX_TimeLogger::NextMeasurement(double now) } } - - -double KX_TimeLogger::GetAverage(void) const +double KX_TimeLogger::GetAverage() const { double avg = 0.0; - unsigned int numMeasurements = m_measurements.size(); + const unsigned int numMeasurements = m_measurements.size(); if (numMeasurements > 1) { for (unsigned int i = 1; i < numMeasurements; i++) { avg += m_measurements[i]; diff --git a/source/gameengine/Ketsji/KX_TimeLogger.h b/source/gameengine/Ketsji/KX_TimeLogger.h index 59d7bdc84e33..215664aa0e2c 100644 --- a/source/gameengine/Ketsji/KX_TimeLogger.h +++ b/source/gameengine/Ketsji/KX_TimeLogger.h @@ -38,14 +38,11 @@ #include -#ifdef WITH_CXX_GUARDEDALLOC -# include "MEM_guardedalloc.h" -#endif - /** * Stores and manages time measurements. */ -class KX_TimeLogger { +class KX_TimeLogger +{ public: /** * Constructor. @@ -56,59 +53,54 @@ class KX_TimeLogger { /** * Destructor. */ - virtual ~KX_TimeLogger(void); + ~KX_TimeLogger(); /** * Changes the maximum number of measurements that can be stored. */ - virtual void SetMaxNumMeasurements(unsigned int maxNumMeasurements); + void SetMaxNumMeasurements(unsigned int maxNumMeasurements); /** * Changes the maximum number of measurements that can be stored. */ - virtual unsigned int GetMaxNumMeasurements(void) const; + unsigned int GetMaxNumMeasurements() const; /** * Starts logging in current measurement. * \param now The current time. */ - virtual void StartLog(double now); + void StartLog(double now); /** * End logging in current measurement. * \param now The current time. */ - virtual void EndLog(double now); + void EndLog(double now); /** * Logs time in next measurement. * \param now The current time. */ - virtual void NextMeasurement(double now); + void NextMeasurement(double now); /** * Returns average of all but the current measurement. * \return The average of all but the current measurement. */ - virtual double GetAverage(void) const; + double GetAverage() const; protected: - /** Storage for the measurements. */ + /// Storage for the measurements. std::deque m_measurements; - /** Maximum number of measurements. */ + /// Maximum number of measurements. unsigned int m_maxNumMeasurements; - /** Time at start of logging. */ + /// Time at start of logging. double m_logStart; - /** State of logging. */ + /// State of logging. bool m_logging; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_TimeLogger") -#endif }; -#endif /* __KX_TIMELOGGER_H__ */ +#endif // __KX_TIMELOGGER_H__ diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.cpp b/source/gameengine/Ketsji/KX_TouchEventManager.cpp deleted file mode 100644 index ecaceb9c0edc..000000000000 --- a/source/gameengine/Ketsji/KX_TouchEventManager.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Ketsji/KX_TouchEventManager.cpp - * \ingroup ketsji - */ - - -#include "KX_TouchEventManager.h" -#include "SCA_ISensor.h" -#include "KX_TouchSensor.h" -#include "KX_GameObject.h" -#include "PHY_IPhysicsEnvironment.h" -#include "PHY_IPhysicsController.h" - - -KX_TouchEventManager::KX_TouchEventManager(class SCA_LogicManager* logicmgr, - PHY_IPhysicsEnvironment* physEnv) - : SCA_EventManager(logicmgr, TOUCH_EVENTMGR), - m_physEnv(physEnv) -{ - //notm_scene->addTouchCallback(STATIC_RESPONSE, KX_TouchEventManager::collisionResponse, this); - - //m_scene->addTouchCallback(OBJECT_RESPONSE, KX_TouchEventManager::collisionResponse, this); - //m_scene->addTouchCallback(SENSOR_RESPONSE, KX_TouchEventManager::collisionResponse, this); - - m_physEnv->AddTouchCallback(PHY_OBJECT_RESPONSE, KX_TouchEventManager::newCollisionResponse, this); - m_physEnv->AddTouchCallback(PHY_SENSOR_RESPONSE, KX_TouchEventManager::newCollisionResponse, this); - m_physEnv->AddTouchCallback(PHY_BROADPH_RESPONSE, KX_TouchEventManager::newBroadphaseResponse, this); - -} - -bool KX_TouchEventManager::NewHandleCollision(void* object1, void* object2, const PHY_CollData *coll_data) -{ - - PHY_IPhysicsController* obj1 = static_cast(object1); - PHY_IPhysicsController* obj2 = static_cast(object2); - - m_newCollisions.insert(NewCollision(obj1, obj2, coll_data)); - - return false; -} - - -bool KX_TouchEventManager::newCollisionResponse(void *client_data, - void *object1, - void *object2, - const PHY_CollData *coll_data) -{ - KX_TouchEventManager *touchmgr = (KX_TouchEventManager *) client_data; - touchmgr->NewHandleCollision(object1, object2, coll_data); - return false; -} - -bool KX_TouchEventManager::newBroadphaseResponse(void *client_data, - void *object1, - void *object2, - const PHY_CollData *coll_data) -{ - PHY_IPhysicsController* ctrl1 = static_cast(object1); - PHY_IPhysicsController* ctrl2 = static_cast(object2); - - KX_ClientObjectInfo *info1 = (ctrl1) ? static_cast(ctrl1->GetNewClientInfo()) : NULL; - KX_ClientObjectInfo *info2 = (ctrl2) ? static_cast(ctrl2->GetNewClientInfo()) : NULL; - - // This call back should only be called for controllers of Near and Radar sensor - if (!info1) - return true; - - // Get KX_GameObjects for callbacks - KX_GameObject* gobj1 = info1->m_gameobject; - KX_GameObject* gobj2 = (info2) ? info2->m_gameobject : NULL; - - bool has_py_callbacks = false; - -#ifdef WITH_PYTHON - // Consider callbacks for broadphase inclusion if it's a sensor object type - if (gobj1 && gobj2) - has_py_callbacks = gobj1->m_collisionCallbacks || gobj2->m_collisionCallbacks; -#else - (void)gobj1; - (void)gobj2; -#endif - - switch (info1->m_type) - { - case KX_ClientObjectInfo::SENSOR: - if (info1->m_sensors.size() == 1) - { - // only one sensor for this type of object - KX_TouchSensor* touchsensor = static_cast(*info1->m_sensors.begin()); - return touchsensor->BroadPhaseFilterCollision(object1, object2); - } - break; - case KX_ClientObjectInfo::OBSENSOR: - case KX_ClientObjectInfo::OBACTORSENSOR: - // this object may have multiple collision sensors, - // check is any of them is interested in this object - for (std::list::iterator it = info1->m_sensors.begin(); - it != info1->m_sensors.end(); - ++it) - { - if ((*it)->GetSensorType() == SCA_ISensor::ST_TOUCH) - { - KX_TouchSensor* touchsensor = static_cast(*it); - if (touchsensor->BroadPhaseSensorFilterCollision(object1, object2)) - return true; - } - } - - return has_py_callbacks; - - // quiet the compiler - case KX_ClientObjectInfo::STATIC: - case KX_ClientObjectInfo::ACTOR: - case KX_ClientObjectInfo::RESERVED1: - /* do nothing*/ - break; - } - return true; -} - -void KX_TouchEventManager::RegisterSensor(SCA_ISensor* sensor) -{ - KX_TouchSensor* touchsensor = static_cast(sensor); - if (m_sensors.AddBack(touchsensor)) - // the sensor was effectively inserted, register it - touchsensor->RegisterSumo(this); -} - -void KX_TouchEventManager::RemoveSensor(SCA_ISensor* sensor) -{ - KX_TouchSensor* touchsensor = static_cast(sensor); - if (touchsensor->Delink()) - // the sensor was effectively removed, unregister it - touchsensor->UnregisterSumo(this); -} - - - -void KX_TouchEventManager::EndFrame() -{ - SG_DList::iterator it(m_sensors); - for (it.begin();!it.end();++it) - { - (*it)->EndFrame(); - } -} - - - -void KX_TouchEventManager::NextFrame() -{ - SG_DList::iterator it(m_sensors); - for (it.begin();!it.end();++it) - (*it)->SynchronizeTransform(); - - for (std::set::iterator cit = m_newCollisions.begin(); cit != m_newCollisions.end(); ++cit) - { - // Controllers - PHY_IPhysicsController* ctrl1 = (*cit).first; - PHY_IPhysicsController* ctrl2 = (*cit).second; - - // Sensor iterator - list::iterator sit; - - // First client info - KX_ClientObjectInfo *client_info = static_cast(ctrl1->GetNewClientInfo()); - // First gameobject - KX_GameObject *kxObj1 = KX_GameObject::GetClientObject(client_info); - // Invoke sensor response for each object - if (client_info) { - for ( sit = client_info->m_sensors.begin(); sit != client_info->m_sensors.end(); ++sit) { - static_cast(*sit)->NewHandleCollision(ctrl1, ctrl2, NULL); - } - } - - // Second client info - client_info = static_cast(ctrl2->GetNewClientInfo()); - // Second gameobject - KX_GameObject *kxObj2 = KX_GameObject::GetClientObject(client_info); - if (client_info) { - for ( sit = client_info->m_sensors.begin(); sit != client_info->m_sensors.end(); ++sit) { - static_cast(*sit)->NewHandleCollision(ctrl2, ctrl1, NULL); - } - } - // Run python callbacks - PHY_CollData *colldata = cit->colldata; - kxObj1->RunCollisionCallbacks(kxObj2, colldata->m_point1, colldata->m_normal); - kxObj2->RunCollisionCallbacks(kxObj1, colldata->m_point2, -colldata->m_normal); - - delete cit->colldata; - } - - m_newCollisions.clear(); - - for (it.begin();!it.end();++it) - (*it)->Activate(m_logicmgr); - } - - -KX_TouchEventManager::NewCollision::NewCollision(PHY_IPhysicsController *first, - PHY_IPhysicsController *second, - const PHY_CollData *colldata) - : first(first), second(second), colldata(new PHY_CollData(*colldata)) -{} - -KX_TouchEventManager::NewCollision::NewCollision(const NewCollision &to_copy) - : first(to_copy.first), second(to_copy.second), colldata(to_copy.colldata) -{} - -bool KX_TouchEventManager::NewCollision::operator<(const NewCollision &other) const -{ - //see strict weak ordering: https://support.microsoft.com/en-us/kb/949171 - if (first == other.first) { - if (second == other.second) { - return colldata < other.colldata; - } - return second < other.second; - } - return first < other.first; -} diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.h b/source/gameengine/Ketsji/KX_TouchEventManager.h deleted file mode 100644 index 916a55ba3c9a..000000000000 --- a/source/gameengine/Ketsji/KX_TouchEventManager.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file KX_TouchEventManager.h - * \ingroup ketsji - */ - -#ifndef __KX_TOUCHEVENTMANAGER_H__ -#define __KX_TOUCHEVENTMANAGER_H__ - - -#include "SCA_EventManager.h" -#include "KX_TouchSensor.h" -#include "KX_GameObject.h" - -#include -#include - -class SCA_ISensor; -class PHY_IPhysicsEnvironment; - -class KX_TouchEventManager : public SCA_EventManager -{ - /** - * Contains two colliding objects and the first contact point. - */ - class NewCollision { - public: - PHY_IPhysicsController *first; - PHY_IPhysicsController *second; - PHY_CollData *colldata; - - /** - * Creates a copy of the given PHY_CollData; freeing that copy should be done by the owner of - * the NewCollision object. - * - * This allows us to efficiently store NewCollision objects in a std::set without creating more - * copies of colldata, as the NewCollision copy constructor reuses the pointer and doesn't clone - * it again. */ - NewCollision(PHY_IPhysicsController *first, - PHY_IPhysicsController *second, - const PHY_CollData *colldata); - NewCollision(const NewCollision &to_copy); - bool operator<(const NewCollision &other) const; - }; - - PHY_IPhysicsEnvironment* m_physEnv; - - std::set m_newCollisions; - - - static bool newCollisionResponse(void *client_data, - void *object1, - void *object2, - const PHY_CollData *coll_data); - - static bool newBroadphaseResponse(void *client_data, - void *object1, - void *object2, - const PHY_CollData *coll_data); - - virtual bool NewHandleCollision(void* obj1,void* obj2, - const PHY_CollData * coll_data); - - - - - -public: - KX_TouchEventManager(class SCA_LogicManager* logicmgr, - PHY_IPhysicsEnvironment* physEnv); - virtual void NextFrame(); - virtual void EndFrame(); - virtual void RegisterSensor(SCA_ISensor* sensor); - virtual void RemoveSensor(SCA_ISensor* sensor); - SCA_LogicManager* GetLogicManager() { return m_logicmgr;} - PHY_IPhysicsEnvironment *GetPhysicsEnvironment() { return m_physEnv; } - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_TouchEventManager") -#endif -}; - -#endif /* __KX_TOUCHEVENTMANAGER_H__ */ diff --git a/source/gameengine/Ketsji/KX_TouchSensor.cpp b/source/gameengine/Ketsji/KX_TouchSensor.cpp deleted file mode 100644 index d5598164eb0a..000000000000 --- a/source/gameengine/Ketsji/KX_TouchSensor.cpp +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Senses touch and collision events - * - * - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Ketsji/KX_TouchSensor.cpp - * \ingroup ketsji - */ - - -#include "KX_TouchSensor.h" -#include "SCA_EventManager.h" -#include "SCA_LogicManager.h" -#include "KX_GameObject.h" -#include "KX_TouchEventManager.h" - -#include "PHY_IPhysicsController.h" - -#include "RAS_MeshObject.h" - -#include -#include "PHY_IPhysicsEnvironment.h" - -/* ------------------------------------------------------------------------- */ -/* Native functions */ -/* ------------------------------------------------------------------------- */ - -void KX_TouchSensor::SynchronizeTransform() -{ - // the touch sensor does not require any synchronization: it uses - // the same physical object which is already synchronized by Blender -} - - -void KX_TouchSensor::EndFrame() -{ - m_colliders->ReleaseAndRemoveAll(); - m_hitObject = NULL; - m_bTriggered = false; - m_bColliderHash = 0; -} - -void KX_TouchSensor::UnregisterToManager() -{ - // before unregistering the sensor, make sure we release all references - EndFrame(); - SCA_ISensor::UnregisterToManager(); -} - -bool KX_TouchSensor::Evaluate() -{ - bool result = false; - bool reset = m_reset && m_level; - m_reset = false; - if (m_bTriggered != m_bLastTriggered) - { - m_bLastTriggered = m_bTriggered; - if (!m_bTriggered) - m_hitObject = NULL; - result = true; - } - if (reset) - // force an event - result = true; - - if (m_bTouchPulse) { /* pulse on changes to the colliders */ - int count = m_colliders->GetCount(); - - if (m_bLastCount!=count || m_bColliderHash!=m_bLastColliderHash) { - m_bLastCount = count; - m_bLastColliderHash= m_bColliderHash; - result = true; - } - } - return result; -} - -KX_TouchSensor::KX_TouchSensor(SCA_EventManager* eventmgr,KX_GameObject* gameobj,bool bFindMaterial,bool bTouchPulse,const STR_String& touchedpropname) -:SCA_ISensor(gameobj,eventmgr), -m_touchedpropname(touchedpropname), -m_bFindMaterial(bFindMaterial), -m_bTouchPulse(bTouchPulse), -m_hitMaterial("") -/*m_sumoObj(sumoObj),*/ -{ -// KX_TouchEventManager* touchmgr = (KX_TouchEventManager*) eventmgr; -// m_resptable = touchmgr->GetResponseTable(); - -// m_solidHandle = m_sumoObj->getObjectHandle(); - - m_colliders = new CListValue(); - - KX_ClientObjectInfo *client_info = gameobj->getClientInfo(); - //client_info->m_gameobject = gameobj; - //client_info->m_auxilary_info = NULL; - client_info->m_sensors.push_back(this); - - m_physCtrl = gameobj->GetPhysicsController(); - MT_assert( !gameobj->GetPhysicsController() || m_physCtrl ); - Init(); -} - -void KX_TouchSensor::Init() -{ - m_bCollision = false; - m_bTriggered = false; - m_bLastTriggered = (m_invert)?true:false; - m_bLastCount = 0; - m_bColliderHash = m_bLastColliderHash = 0; - m_hitObject = NULL; - m_reset = true; -} - -KX_TouchSensor::~KX_TouchSensor() -{ - //DT_ClearObjectResponse(m_resptable,m_solidHandle); - m_colliders->Release(); -} - -CValue* KX_TouchSensor::GetReplica() -{ - KX_TouchSensor* replica = new KX_TouchSensor(*this); - replica->ProcessReplica(); - return replica; -} - -void KX_TouchSensor::ProcessReplica() -{ - SCA_ISensor::ProcessReplica(); - m_colliders = new CListValue(); - Init(); -} - -void KX_TouchSensor::ReParent(SCA_IObject* parent) -{ - KX_GameObject *gameobj = static_cast(parent); - PHY_IPhysicsController *sphy = ((KX_GameObject*)parent)->GetPhysicsController(); - if (sphy) - m_physCtrl = sphy; - -// m_solidHandle = m_sumoObj->getObjectHandle(); - KX_ClientObjectInfo *client_info = gameobj->getClientInfo(); - //client_info->m_gameobject = gameobj; - //client_info->m_auxilary_info = NULL; - - client_info->m_sensors.push_back(this); - SCA_ISensor::ReParent(parent); -} - -void KX_TouchSensor::RegisterSumo(KX_TouchEventManager *touchman) -{ - if (m_physCtrl) - { - if (touchman->GetPhysicsEnvironment()->RequestCollisionCallback(m_physCtrl)) - { - KX_ClientObjectInfo *client_info = static_cast(m_physCtrl->GetNewClientInfo()); - if (client_info->isSensor()) - touchman->GetPhysicsEnvironment()->AddSensor(m_physCtrl); - } - } -} -void KX_TouchSensor::UnregisterSumo(KX_TouchEventManager* touchman) -{ - if (m_physCtrl) - { - if (touchman->GetPhysicsEnvironment()->RemoveCollisionCallback(m_physCtrl)) - { - // no more sensor on the controller, can remove it if it is a sensor object - KX_ClientObjectInfo *client_info = static_cast(m_physCtrl->GetNewClientInfo()); - if (client_info->isSensor()) - touchman->GetPhysicsEnvironment()->RemoveSensor(m_physCtrl); - } - } -} - -// this function is called only for sensor objects -// return true if the controller can collide with the object -bool KX_TouchSensor::BroadPhaseSensorFilterCollision(void*obj1,void*obj2) -{ - assert(obj1==m_physCtrl && obj2); - - KX_GameObject* myobj = (KX_GameObject*)GetParent(); - KX_GameObject* myparent = myobj->GetParent(); - KX_ClientObjectInfo *client_info = static_cast(((PHY_IPhysicsController*)obj2)->GetNewClientInfo()); - KX_ClientObjectInfo *my_client_info = static_cast(m_physCtrl->GetNewClientInfo()); - KX_GameObject* otherobj = ( client_info ? client_info->m_gameobject : NULL); - - // we can only check on persistent characteristic: m_link and m_suspended are not - // good candidate because they are transient. That must be handled at another level - if (!otherobj || - otherobj == myparent || // don't interact with our parent - (my_client_info->m_type == KX_ClientObjectInfo::OBACTORSENSOR && - client_info->m_type != KX_ClientObjectInfo::ACTOR)) // only with actor objects - return false; - - bool found = m_touchedpropname.IsEmpty(); - if (!found) - { - if (m_bFindMaterial) { - for (unsigned int i = 0; i < otherobj->GetMeshCount(); ++i) { - RAS_MeshObject *meshObj = otherobj->GetMesh(i); - for (unsigned int j = 0; j < meshObj->NumMaterials(); ++j) { - found = strcmp(m_touchedpropname.ReadPtr(), meshObj->GetMaterialName(j).ReadPtr() + 2) == 0; - if (found) - break; - } - } - } - else { - found = (otherobj->GetProperty(m_touchedpropname) != NULL); - } - } - return found; -} - -bool KX_TouchSensor::NewHandleCollision(void*object1,void*object2,const PHY_CollData* colldata) -{ -// KX_TouchEventManager* toucheventmgr = (KX_TouchEventManager*)m_eventmgr; - KX_GameObject* parent = (KX_GameObject*)GetParent(); - - // need the mapping from PHY_IPhysicsController to gameobjects now - - KX_ClientObjectInfo *client_info = static_cast (object1 == m_physCtrl? - ((PHY_IPhysicsController*)object2)->GetNewClientInfo(): - ((PHY_IPhysicsController*)object1)->GetNewClientInfo()); - - KX_GameObject* gameobj = ( client_info ? - client_info->m_gameobject : - NULL); - - // add the same check as in SCA_ISensor::Activate(), - // we don't want to record collision when the sensor is not active. - if (m_links && !m_suspended && - gameobj && (gameobj != parent) && client_info->isActor()) - { - - bool found = m_touchedpropname.IsEmpty(); - bool hitMaterial = false; - if (!found) - { - if (m_bFindMaterial) { - for (unsigned int i = 0; i < gameobj->GetMeshCount(); ++i) { - RAS_MeshObject *meshObj = gameobj->GetMesh(i); - for (unsigned int j = 0; j < meshObj->NumMaterials(); ++j) { - found = strcmp(m_touchedpropname.ReadPtr(), meshObj->GetMaterialName(j).ReadPtr() + 2) == 0; - if (found) { - hitMaterial = true; - break; - } - } - } - } - else { - found = (gameobj->GetProperty(m_touchedpropname) != NULL); - } - } - if (found) - { - if (!m_colliders->SearchValue(gameobj)) { - m_colliders->Add(gameobj->AddRef()); - - if (m_bTouchPulse) - m_bColliderHash += (uint_ptr)(static_cast(&gameobj)); - } - m_bTriggered = true; - m_hitObject = gameobj; - m_hitMaterial = hitMaterial; - //printf("KX_TouchSensor::HandleCollision\n"); - } - - } - return false; // was DT_CONTINUE but this was defined in sumo as false. -} - -#ifdef WITH_PYTHON - -/* ------------------------------------------------------------------------- */ -/* Python functions */ -/* ------------------------------------------------------------------------- */ -/* Integration hooks ------------------------------------------------------- */ -PyTypeObject KX_TouchSensor::Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "KX_TouchSensor", - sizeof(PyObjectPlus_Proxy), - 0, - py_base_dealloc, - 0, - 0, - 0, - 0, - py_base_repr, - 0,0,0,0,0,0,0,0,0, - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, - Methods, - 0, - 0, - &SCA_ISensor::Type, - 0,0,0,0,0,0, - py_base_new -}; - -PyMethodDef KX_TouchSensor::Methods[] = { - {NULL,NULL} //Sentinel -}; - -PyAttributeDef KX_TouchSensor::Attributes[] = { - KX_PYATTRIBUTE_STRING_RW("propName",0,MAX_PROP_NAME,false,KX_TouchSensor,m_touchedpropname), - KX_PYATTRIBUTE_BOOL_RW("useMaterial",KX_TouchSensor,m_bFindMaterial), - KX_PYATTRIBUTE_BOOL_RW("usePulseCollision",KX_TouchSensor,m_bTouchPulse), - KX_PYATTRIBUTE_STRING_RO("hitMaterial", KX_TouchSensor, m_hitMaterial), - KX_PYATTRIBUTE_RO_FUNCTION("hitObject", KX_TouchSensor, pyattr_get_object_hit), - KX_PYATTRIBUTE_RO_FUNCTION("hitObjectList", KX_TouchSensor, pyattr_get_object_hit_list), - { NULL } //Sentinel -}; - -/* Python API */ - -PyObject *KX_TouchSensor::pyattr_get_object_hit(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_TouchSensor* self = static_cast(self_v); - - if (self->m_hitObject) - return self->m_hitObject->GetProxy(); - else - Py_RETURN_NONE; -} - -PyObject *KX_TouchSensor::pyattr_get_object_hit_list(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) -{ - KX_TouchSensor* self = static_cast(self_v); - return self->m_colliders->GetProxy(); -} - -#endif - -/* eof */ diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.cpp b/source/gameengine/Ketsji/KX_TrackToActuator.cpp index e720af06acb5..9a942a0d0196 100644 --- a/source/gameengine/Ketsji/KX_TrackToActuator.cpp +++ b/source/gameengine/Ketsji/KX_TrackToActuator.cpp @@ -35,7 +35,6 @@ * m_upflag for the up direction * normal situation is +y for forward, +z for up */ -#include "MT_Scalar.h" #include "SCA_IActuator.h" #include "KX_TrackToActuator.h" #include "SCA_IScene.h" @@ -56,7 +55,7 @@ KX_TrackToActuator::KX_TrackToActuator(SCA_IObject *gameobj, bool allow3D, int trackflag, int upflag) - : SCA_IActuator(gameobj, KX_ACT_TRACKTO) + :SCA_IActuator(gameobj, KX_ACT_TRACKTO) { m_time = time; m_allow3D = allow3D; @@ -65,17 +64,18 @@ KX_TrackToActuator::KX_TrackToActuator(SCA_IObject *gameobj, m_upflag = upflag; m_parentobj = 0; - if (m_object) + if (m_object) { m_object->RegisterActuator(this); + } { // if the object is vertex parented, don't check parent orientation as the link is broken - if (!((KX_GameObject*)gameobj)->IsVertexParent()) { - m_parentobj = ((KX_GameObject*)gameobj)->GetParent(); // check if the object is parented + if (!((KX_GameObject *)gameobj)->IsVertexParent()) { + m_parentobj = ((KX_GameObject *)gameobj)->GetParent(); // check if the object is parented if (m_parentobj) { // if so, store the initial local rotation // this is needed to revert the effect of the parent inverse node (TBC) - m_parentlocalmat = m_parentobj->GetSGNode()->GetLocalOrientation(); + m_parentlocalmat = m_parentobj->GetNode()->GetLocalOrientation(); // use registration mechanism rather than AddRef, it creates zombie objects m_parentobj->RegisterActuator(this); } @@ -87,9 +87,9 @@ KX_TrackToActuator::KX_TrackToActuator(SCA_IObject *gameobj, /* old function from Blender */ -static MT_Matrix3x3 EulToMat3(float eul[3]) +static mt::mat3 EulToMat3(float eul[3]) { - MT_Matrix3x3 mat; + mt::mat3 mat; float ci, cj, ch, si, sj, sh, cc, cs, sc, ss; ci = cosf(eul[0]); @@ -98,20 +98,20 @@ static MT_Matrix3x3 EulToMat3(float eul[3]) si = sinf(eul[0]); sj = sinf(eul[1]); sh = sinf(eul[2]); - cc = ci*ch; - cs = ci*sh; - sc = si*ch; - ss = si*sh; - - mat[0][0] = cj*ch; - mat[1][0] = sj*sc-cs; - mat[2][0] = sj*cc+ss; - mat[0][1] = cj*sh; - mat[1][1] = sj*ss+cc; - mat[2][1] = sj*cs-sc; - mat[0][2] = -sj; - mat[1][2] = cj*si; - mat[2][2] = cj*ci; + cc = ci * ch; + cs = ci * sh; + sc = si * ch; + ss = si * sh; + + mat(0, 0) = cj * ch; + mat(0, 1) = sj * sc - cs; + mat(0, 2) = sj * cc + ss; + mat(1, 0) = cj * sh; + mat(1, 1) = sj * ss + cc; + mat(1, 2) = sj * cs - sc; + mat(2, 0) = -sj; + mat(2, 1) = cj * si; + mat(2, 2) = cj * ci; return mat; } @@ -119,18 +119,18 @@ static MT_Matrix3x3 EulToMat3(float eul[3]) /* old function from Blender */ -static void Mat3ToEulOld(MT_Matrix3x3 mat, float eul[3]) +static void Mat3ToEulOld(const mt::mat3 &mat, float eul[3]) { - const float cy = sqrtf(mat[0][0] * mat[0][0] + mat[0][1] * mat[0][1]); + const float cy = sqrtf(mat(0, 0) * mat(0, 0) + mat(1, 0) * mat(1, 0)); if (cy > (float)(16.0f * FLT_EPSILON)) { - eul[0] = atan2f( mat[1][2], mat[2][2]); - eul[1] = atan2f(-mat[0][2], cy); - eul[2] = atan2f( mat[0][1], mat[0][0]); + eul[0] = atan2f(mat(2, 1), mat(2, 2)); + eul[1] = atan2f(-mat(2, 0), cy); + eul[2] = atan2f(mat(1, 0), mat(0, 0)); } else { - eul[0] = atan2f(-mat[2][1], mat[1][1]); - eul[1] = atan2f(-mat[0][2], cy); + eul[0] = atan2f(-mat(1, 2), mat(1, 1)); + eul[1] = atan2f(-mat(2, 0), cy); eul[2] = 0.0f; } } @@ -148,20 +148,35 @@ static void compatible_eulFast(float *eul, float *oldrot) dy = eul[1] - oldrot[1]; dz = eul[2] - oldrot[2]; - if (fabsf(dx) > (float)MT_PI) { - if (dx > 0.0f) eul[0] -= (float)MT_2_PI; else eul[0] += (float)MT_2_PI; + if (fabsf(dx) > (float)M_PI) { + if (dx > 0.0f) { + eul[0] -= (float)(M_PI * 2.0f); + } + else { + eul[0] += (float)(M_PI * 2.0f); + } } - if (fabsf(dy) > (float)MT_PI) { - if (dy > 0.0f) eul[1] -= (float)MT_2_PI; else eul[1] += (float)MT_2_PI; + if (fabsf(dy) > (float)M_PI) { + if (dy > 0.0f) { + eul[1] -= (float)(M_PI * 2.0f); + } + else { + eul[1] += (float)(M_PI * 2.0f); + } } - if (fabsf(dz) > (float)MT_PI) { - if (dz > 0.0f) eul[2] -= (float)MT_2_PI; else eul[2] += (float)MT_2_PI; + if (fabsf(dz) > (float)M_PI) { + if (dz > 0.0f) { + eul[2] -= (float)(M_PI * 2.0f); + } + else { + eul[2] += (float)(M_PI * 2.0f); + } } } -static MT_Matrix3x3 matrix3x3_interpol(MT_Matrix3x3 oldmat, MT_Matrix3x3 mat, int m_time) +static mt::mat3 matrix3x3_interpol(const mt::mat3 &oldmat, const mt::mat3 &mat, int m_time) { float eul[3], oldeul[3]; @@ -181,68 +196,72 @@ static float basis_cross(int n, int m) switch (n - m) { case 1: case -2: + { return 1.0f; + } case -1: case 2: + { return -1.0f; + } default: return 0.0f; } } /* vectomat function obtained from constrain.c and modified to work with MOTO library */ -static MT_Matrix3x3 vectomat(MT_Vector3 vec, short axis, short upflag, short threedimup) +static mt::mat3 vectomat(const mt::vec3 &dir, short axis, short upflag, short threedimup) { - MT_Matrix3x3 mat; - MT_Vector3 y(MT_Scalar(0.0f), MT_Scalar(1.0f), MT_Scalar(0.0f)); - MT_Vector3 z(MT_Scalar(0.0f), MT_Scalar(0.0f), MT_Scalar(1.0f)); /* world Z axis is the global up axis */ - MT_Vector3 proj; - MT_Vector3 right; - MT_Scalar mul; + mt::mat3 mat; + mt::vec3 proj; + mt::vec3 right; + float mul; int right_index; /* Normalized Vec vector*/ - vec = vec.safe_normalized_vec(z); + mt::vec3 vec = dir.SafeNormalized(mt::axisZ3); /* if 2D doesn't move the up vector */ if (!threedimup) { - vec.setValue(MT_Scalar(vec[0]), MT_Scalar(vec[1]), MT_Scalar(0.0f)); - vec = (vec - z.dot(vec)*z).safe_normalized_vec(z); + vec.z = 0.0f; + vec = (vec - mt::dot(mt::axisZ3, vec) * mt::axisZ3).SafeNormalized(mt::axisZ3); } - if (axis > 2) + if (axis > 2) { axis -= 3; - else + } + else { vec = -vec; + } /* project the up vector onto the plane specified by vec */ /* first z onto vec... */ - mul = z.dot(vec) / vec.dot(vec); + mul = mt::dot(mt::axisZ3, vec) / mt::dot(vec, vec); proj = vec * mul; /* then onto the plane */ - proj = z - proj; + proj = mt::axisZ3 - proj; /* proj specifies the transformation of the up axis */ - proj = proj.safe_normalized_vec(y); + proj = proj.SafeNormalized(mt::axisY3); /* Normalized cross product of vec and proj specifies transformation of the right axis */ - right = proj.cross(vec); - right.normalize(); + right = mt::cross(proj, vec); + right.Normalize(); if (axis != upflag) { right_index = 3 - axis - upflag; /* account for up direction, track direction */ right = right * basis_cross(axis, upflag); - mat.setRow(right_index, right); - mat.setRow(upflag, proj); - mat.setRow(axis, vec); - mat = mat.inverse(); + + mat.GetColumn(right_index) = right; + mat.GetColumn(upflag) = proj; + mat.GetColumn(axis) = vec; } /* identity matrix - don't do anything if the two axes are the same */ else { - mat.setIdentity(); + mat = mt::mat3::Identity(); } return mat; @@ -250,75 +269,77 @@ static MT_Matrix3x3 vectomat(MT_Vector3 vec, short axis, short upflag, short thr KX_TrackToActuator::~KX_TrackToActuator() { - if (m_object) + if (m_object) { m_object->UnregisterActuator(this); - if (m_parentobj) + } + if (m_parentobj) { m_parentobj->UnregisterActuator(this); + } } /* end of destructor */ void KX_TrackToActuator::ProcessReplica() { // the replica is tracking the same object => register it - if (m_object) + if (m_object) { m_object->RegisterActuator(this); - if (m_parentobj) + } + if (m_parentobj) { m_parentobj->RegisterActuator(this); + } SCA_IActuator::ProcessReplica(); } -bool KX_TrackToActuator::UnlinkObject(SCA_IObject* clientobj) +bool KX_TrackToActuator::UnlinkObject(SCA_IObject *clientobj) { - if (clientobj == m_object) - { + if (clientobj == m_object) { // this object is being deleted, we cannot continue to track it. - m_object = NULL; + m_object = nullptr; return true; } - if (clientobj == m_parentobj) - { - m_parentobj = NULL; + if (clientobj == m_parentobj) { + m_parentobj = nullptr; return true; } return false; } -void KX_TrackToActuator::Relink(CTR_Map *obj_map) +void KX_TrackToActuator::Relink(std::map& obj_map) { - void **h_obj = (*obj_map)[m_object]; - if (h_obj) { - if (m_object) + SCA_IObject *obj = obj_map[m_object]; + if (obj) { + if (m_object) { m_object->UnregisterActuator(this); - m_object = (SCA_IObject*)(*h_obj); + } + m_object = obj; m_object->RegisterActuator(this); } - void **h_parobj = (*obj_map)[m_parentobj]; - if (h_parobj) { - if (m_parentobj) + KX_GameObject *parobj = static_cast(obj_map[m_parentobj]); + if (parobj) { + if (m_parentobj) { m_parentobj->UnregisterActuator(this); - m_parentobj= (KX_GameObject*)(*h_parobj); + } + m_parentobj = parobj; m_parentobj->RegisterActuator(this); } } -bool KX_TrackToActuator::Update(double curtime, bool frame) +bool KX_TrackToActuator::Update(double curtime) { bool result = false; bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); - if (bNegativeEvent) - { + if (bNegativeEvent) { // do nothing on negative events } - else if (m_object) - { - KX_GameObject* curobj = (KX_GameObject*) GetParent(); - MT_Vector3 dir = curobj->NodeGetWorldPosition() - ((KX_GameObject*)m_object)->NodeGetWorldPosition(); - MT_Matrix3x3 mat; - MT_Matrix3x3 oldmat; + else if (m_object) { + KX_GameObject *curobj = (KX_GameObject *)GetParent(); + mt::vec3 dir = curobj->NodeGetWorldPosition() - ((KX_GameObject *)m_object)->NodeGetWorldPosition(); + mt::mat3 mat; + mt::mat3 oldmat; mat = vectomat(dir, m_trackflag, m_upflag, m_allow3D); oldmat = curobj->NodeGetWorldOrientation(); @@ -329,11 +350,11 @@ bool KX_TrackToActuator::Update(double curtime, bool frame) /* check if the model is parented and calculate the child transform */ if (m_parentobj) { - MT_Point3 localpos; - localpos = curobj->GetSGNode()->GetLocalPosition(); + mt::vec3 localpos; + localpos = curobj->GetNode()->GetLocalPosition(); // Get the inverse of the parent matrix - MT_Matrix3x3 parentmatinv; - parentmatinv = m_parentobj->NodeGetWorldOrientation().inverse(); + mt::mat3 parentmatinv; + parentmatinv = m_parentobj->NodeGetWorldOrientation().Inverse(); // transform the local coordinate system into the parents system mat = parentmatinv * mat; // append the initial parent local rotation matrix @@ -362,9 +383,9 @@ bool KX_TrackToActuator::Update(double curtime, bool frame) /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_TrackToActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_TrackToActuator", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -372,55 +393,60 @@ PyTypeObject KX_TrackToActuator::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IActuator::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_TrackToActuator::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_TrackToActuator::Attributes[] = { - KX_PYATTRIBUTE_INT_RW("time",0,1000,true,KX_TrackToActuator,m_time), - KX_PYATTRIBUTE_BOOL_RW("use3D",KX_TrackToActuator,m_allow3D), - KX_PYATTRIBUTE_INT_RW("upAxis", 0, 2, true, KX_TrackToActuator,m_upflag), - KX_PYATTRIBUTE_INT_RW("trackAxis", 0, 5, true, KX_TrackToActuator,m_trackflag), - KX_PYATTRIBUTE_RW_FUNCTION("object", KX_TrackToActuator, pyattr_get_object, pyattr_set_object), + EXP_PYATTRIBUTE_INT_RW("time", 0, 1000, true, KX_TrackToActuator, m_time), + EXP_PYATTRIBUTE_BOOL_RW("use3D", KX_TrackToActuator, m_allow3D), + EXP_PYATTRIBUTE_INT_RW("upAxis", 0, 2, true, KX_TrackToActuator, m_upflag), + EXP_PYATTRIBUTE_INT_RW("trackAxis", 0, 5, true, KX_TrackToActuator, m_trackflag), + EXP_PYATTRIBUTE_RW_FUNCTION("object", KX_TrackToActuator, pyattr_get_object, pyattr_set_object), - { NULL } //Sentinel + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *KX_TrackToActuator::pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_TrackToActuator::pyattr_get_object(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) { - KX_TrackToActuator* actuator = static_cast(self); - if (!actuator->m_object) + KX_TrackToActuator *actuator = static_cast(self); + if (!actuator->m_object) { Py_RETURN_NONE; - else + } + else { return actuator->m_object->GetProxy(); + } } -int KX_TrackToActuator::pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_TrackToActuator::pyattr_set_object(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_TrackToActuator* actuator = static_cast(self); + KX_TrackToActuator *actuator = static_cast(self); KX_GameObject *gameobj; - if (!ConvertPythonToGameObject(actuator->GetLogicManager(), value, &gameobj, true, "actuator.object = value: KX_TrackToActuator")) + if (!ConvertPythonToGameObject(actuator->GetLogicManager(), value, &gameobj, true, "actuator.object = value: KX_TrackToActuator")) { return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error - if (actuator->m_object != NULL) + } + if (actuator->m_object != nullptr) { actuator->m_object->UnregisterActuator(actuator); + } - actuator->m_object = (SCA_IObject*) gameobj; + actuator->m_object = (SCA_IObject *)gameobj; - if (actuator->m_object) + if (actuator->m_object) { actuator->m_object->RegisterActuator(actuator); + } return PY_SET_ATTR_SUCCESS; } diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.h b/source/gameengine/Ketsji/KX_TrackToActuator.h index 697785c4f594..91fceaae55c8 100644 --- a/source/gameengine/Ketsji/KX_TrackToActuator.h +++ b/source/gameengine/Ketsji/KX_TrackToActuator.h @@ -34,11 +34,11 @@ #include "SCA_IActuator.h" #include "SCA_IObject.h" -#include "MT_Matrix3x3.h" +#include "mathfu.h" #include "KX_GameObject.h" -class KX_TrackToActuator : public SCA_IActuator +class KX_TrackToActuator : public SCA_IActuator, public mt::SimdClassAllocator { Py_Header // Object reference. Actually, we use the object's 'life' @@ -49,15 +49,16 @@ class KX_TrackToActuator : public SCA_IActuator int m_time; int m_trackflag; int m_upflag; - - MT_Matrix3x3 m_parentlocalmat; + + mt::mat3 m_parentlocalmat; KX_GameObject* m_parentobj; - public: +public: + KX_TrackToActuator(SCA_IObject* gameobj, SCA_IObject *ob, int time, bool threedee,int trackflag,int upflag); virtual ~KX_TrackToActuator(); - virtual CValue* GetReplica() { + virtual EXP_Value* GetReplica() { KX_TrackToActuator* replica = new KX_TrackToActuator(*this); replica->ProcessReplica(); return replica; @@ -65,8 +66,8 @@ class KX_TrackToActuator : public SCA_IActuator virtual void ProcessReplica(); virtual bool UnlinkObject(SCA_IObject* clientobj); - virtual void Relink(CTR_Map *obj_map); - virtual bool Update(double curtime, bool frame); + virtual void Relink(std::map& obj_map); + virtual bool Update(double curtime); //Python Interface enum UpAxis { @@ -88,9 +89,9 @@ class KX_TrackToActuator : public SCA_IActuator /* Python part */ /* These are used to get and set m_ob */ - static PyObject *pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - + static PyObject *pyattr_get_object(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_object(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + #endif /* WITH_PYTHON */ }; /* end of class KX_TrackToActuator : public KX_EditObjectActuator */ diff --git a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp index 27ad8c6f685f..4f0b43aa16e1 100644 --- a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp +++ b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp @@ -22,34 +22,27 @@ * \ingroup ketsji */ -#include "EXP_PyObjectPlus.h" - #include "KX_VehicleWrapper.h" -#include "PHY_IPhysicsEnvironment.h" #include "PHY_IVehicle.h" #include "KX_PyMath.h" #include "KX_GameObject.h" #include "KX_MotionState.h" -#include "KX_PythonInit.h" - -KX_VehicleWrapper::KX_VehicleWrapper( - PHY_IVehicle* vehicle, - PHY_IPhysicsEnvironment* physenv) : - PyObjectPlus(), - m_vehicle(vehicle), - m_physenv(physenv) +#include "KX_Globals.h" + +#include "DNA_object_types.h" // for OB_MAX_COL_MASKS + +KX_VehicleWrapper::KX_VehicleWrapper(PHY_IVehicle *vehicle) + :m_vehicle(vehicle) { } KX_VehicleWrapper::~KX_VehicleWrapper() { - int numMotion = m_motionStates.size(); - for (int i=0;iGetLogicManager(), wheelGameObject, &gameOb, false, "vehicle.addWheel(...): KX_VehicleWrapper (first argument)")) - return NULL; + if (!ConvertPythonToGameObject(KX_GetActiveScene()->GetLogicManager(), wheelGameObject, &gameOb, false, "vehicle.addWheel(...): KX_VehicleWrapper (first argument)")) { + return nullptr; + } - if (gameOb->GetSGNode()) - { - MT_Vector3 attachPos,attachDir,attachAxle; - if (!PyVecTo(pylistPos,attachPos)) { + if (gameOb->GetNode()) { + mt::vec3 attachPos, attachDir, attachAxle; + if (!PyVecTo(pylistPos, attachPos)) { PyErr_SetString(PyExc_AttributeError, "addWheel(...) Unable to add wheel. attachPos must be a vector with 3 elements."); - return NULL; + return nullptr; } - if (!PyVecTo(pylistDir,attachDir)) { + if (!PyVecTo(pylistDir, attachDir)) { PyErr_SetString(PyExc_AttributeError, "addWheel(...) Unable to add wheel. downDir must be a vector with 3 elements."); - return NULL; + return nullptr; } - if (!PyVecTo(pylistAxleDir,attachAxle)) { + if (!PyVecTo(pylistAxleDir, attachAxle)) { PyErr_SetString(PyExc_AttributeError, "addWheel(...) Unable to add wheel. axleDir must be a vector with 3 elements."); - return NULL; + return nullptr; } //someone reverse some conventions inside Bullet (axle winding) @@ -111,15 +103,16 @@ PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args) if (wheelRadius <= 0) { PyErr_SetString(PyExc_AttributeError, "addWheel(...) Unable to add wheel. wheelRadius must be positive."); - return NULL; + return nullptr; } - PHY_IMotionState *motionState = new KX_MotionState(gameOb->GetSGNode()); - m_vehicle->AddWheel(motionState,attachPos,attachDir,attachAxle,suspensionRestLength,wheelRadius,hasSteering); + PHY_IMotionState *motionState = new KX_MotionState(gameOb->GetNode()); + m_vehicle->AddWheel(motionState, attachPos, attachDir, attachAxle, suspensionRestLength, wheelRadius, hasSteering); } - } else { - return NULL; + } + else { + return nullptr; } Py_RETURN_NONE; } @@ -130,44 +123,36 @@ PyObject *KX_VehicleWrapper::PyGetWheelPosition(PyObject *args) int wheelIndex; - if (PyArg_ParseTuple(args,"i:getWheelPosition",&wheelIndex)) - { - float position[3]; + if (PyArg_ParseTuple(args, "i:getWheelPosition", &wheelIndex)) { WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "getWheelPosition"); - m_vehicle->GetWheelPosition(wheelIndex,position[0],position[1],position[2]); - MT_Vector3 pos(position[0],position[1],position[2]); - return PyObjectFrom(pos); + return PyObjectFrom(m_vehicle->GetWheelPosition(wheelIndex)); } - return NULL; + return nullptr; } PyObject *KX_VehicleWrapper::PyGetWheelRotation(PyObject *args) { int wheelIndex; - if (PyArg_ParseTuple(args,"i:getWheelRotation",&wheelIndex)) - { + if (PyArg_ParseTuple(args, "i:getWheelRotation", &wheelIndex)) { WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "getWheelRotation"); return PyFloat_FromDouble(m_vehicle->GetWheelRotation(wheelIndex)); } - return NULL; + return nullptr; } PyObject *KX_VehicleWrapper::PyGetWheelOrientationQuaternion(PyObject *args) { int wheelIndex; - if (PyArg_ParseTuple(args,"i:getWheelOrientationQuaternion",&wheelIndex)) - { - float orn[4]; + if (PyArg_ParseTuple(args, "i:getWheelOrientationQuaternion", &wheelIndex)) { WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "getWheelOrientationQuaternion"); - m_vehicle->GetWheelOrientationQuaternion(wheelIndex,orn[0],orn[1],orn[2],orn[3]); - MT_Quaternion quatorn(orn[0],orn[1],orn[2],orn[3]); - MT_Matrix3x3 ornmat(quatorn); + const mt::quat quat = m_vehicle->GetWheelOrientationQuaternion(wheelIndex); + const mt::mat3 ornmat = quat.ToMatrix(); return PyObjectFrom(ornmat); } - return NULL; + return nullptr; } @@ -189,15 +174,14 @@ PyObject *KX_VehicleWrapper::PyApplyEngineForce(PyObject *args) float force; int wheelIndex; - if (PyArg_ParseTuple(args,"fi:applyEngineForce",&force,&wheelIndex)) - { + if (PyArg_ParseTuple(args, "fi:applyEngineForce", &force, &wheelIndex)) { WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "applyEngineForce"); force *= -1.f;//someone reverse some conventions inside Bullet (axle winding) - m_vehicle->ApplyEngineForce(force,wheelIndex); + m_vehicle->ApplyEngineForce(force, wheelIndex); } else { - return NULL; + return nullptr; } Py_RETURN_NONE; } @@ -207,14 +191,13 @@ PyObject *KX_VehicleWrapper::PySetTyreFriction(PyObject *args) float wheelFriction; int wheelIndex; - if (PyArg_ParseTuple(args,"fi:setTyreFriction",&wheelFriction,&wheelIndex)) - { + if (PyArg_ParseTuple(args, "fi:setTyreFriction", &wheelFriction, &wheelIndex)) { WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "setTyreFriction"); - m_vehicle->SetWheelFriction(wheelFriction,wheelIndex); + m_vehicle->SetWheelFriction(wheelFriction, wheelIndex); } else { - return NULL; + return nullptr; } Py_RETURN_NONE; } @@ -224,14 +207,13 @@ PyObject *KX_VehicleWrapper::PySetSuspensionStiffness(PyObject *args) float suspensionStiffness; int wheelIndex; - if (PyArg_ParseTuple(args,"fi:setSuspensionStiffness",&suspensionStiffness,&wheelIndex)) - { + if (PyArg_ParseTuple(args, "fi:setSuspensionStiffness", &suspensionStiffness, &wheelIndex)) { WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "setSuspensionStiffness"); - m_vehicle->SetSuspensionStiffness(suspensionStiffness,wheelIndex); + m_vehicle->SetSuspensionStiffness(suspensionStiffness, wheelIndex); } else { - return NULL; + return nullptr; } Py_RETURN_NONE; } @@ -241,13 +223,13 @@ PyObject *KX_VehicleWrapper::PySetSuspensionDamping(PyObject *args) float suspensionDamping; int wheelIndex; - if (PyArg_ParseTuple(args,"fi:setSuspensionDamping",&suspensionDamping,&wheelIndex)) - { + if (PyArg_ParseTuple(args, "fi:setSuspensionDamping", &suspensionDamping, &wheelIndex)) { WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "setSuspensionDamping"); - m_vehicle->SetSuspensionDamping(suspensionDamping,wheelIndex); - } else { - return NULL; + m_vehicle->SetSuspensionDamping(suspensionDamping, wheelIndex); + } + else { + return nullptr; } Py_RETURN_NONE; } @@ -257,13 +239,13 @@ PyObject *KX_VehicleWrapper::PySetSuspensionCompression(PyObject *args) float suspensionCompression; int wheelIndex; - if (PyArg_ParseTuple(args,"fi:setSuspensionCompression",&suspensionCompression,&wheelIndex)) - { + if (PyArg_ParseTuple(args, "fi:setSuspensionCompression", &suspensionCompression, &wheelIndex)) { WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "setSuspensionCompression"); - m_vehicle->SetSuspensionCompression(suspensionCompression,wheelIndex); - } else { - return NULL; + m_vehicle->SetSuspensionCompression(suspensionCompression, wheelIndex); + } + else { + return nullptr; } Py_RETURN_NONE; } @@ -273,14 +255,13 @@ PyObject *KX_VehicleWrapper::PySetRollInfluence(PyObject *args) float rollInfluence; int wheelIndex; - if (PyArg_ParseTuple(args,"fi:setRollInfluence",&rollInfluence,&wheelIndex)) - { + if (PyArg_ParseTuple(args, "fi:setRollInfluence", &rollInfluence, &wheelIndex)) { WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "setRollInfluence"); - m_vehicle->SetRollInfluence(rollInfluence,wheelIndex); + m_vehicle->SetRollInfluence(rollInfluence, wheelIndex); } else { - return NULL; + return nullptr; } Py_RETURN_NONE; } @@ -291,14 +272,13 @@ PyObject *KX_VehicleWrapper::PyApplyBraking(PyObject *args) float braking; int wheelIndex; - if (PyArg_ParseTuple(args,"fi:applyBraking",&braking,&wheelIndex)) - { + if (PyArg_ParseTuple(args, "fi:applyBraking", &braking, &wheelIndex)) { WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "applyBraking"); - m_vehicle->ApplyBraking(braking,wheelIndex); + m_vehicle->ApplyBraking(braking, wheelIndex); } else { - return NULL; + return nullptr; } Py_RETURN_NONE; } @@ -309,14 +289,13 @@ PyObject *KX_VehicleWrapper::PySetSteeringValue(PyObject *args) float steeringValue; int wheelIndex; - if (PyArg_ParseTuple(args,"fi:setSteeringValue",&steeringValue,&wheelIndex)) - { + if (PyArg_ParseTuple(args, "fi:setSteeringValue", &steeringValue, &wheelIndex)) { WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "setSteeringValue"); - m_vehicle->SetSteeringValue(steeringValue,wheelIndex); + m_vehicle->SetSteeringValue(steeringValue, wheelIndex); } else { - return NULL; + return nullptr; } Py_RETURN_NONE; } @@ -333,9 +312,9 @@ PyObject *KX_VehicleWrapper::PyGetConstraintType(PyObject *args) //python specific stuff PyTypeObject KX_VehicleWrapper::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_VehicleWrapper", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -343,38 +322,79 @@ PyTypeObject KX_VehicleWrapper::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, - &PyObjectPlus::Type, - 0,0,0,0,0,0, + &EXP_PyObjectPlus::Type, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_VehicleWrapper::Methods[] = { - {"addWheel",(PyCFunction) KX_VehicleWrapper::sPyAddWheel, METH_VARARGS}, - {"getNumWheels",(PyCFunction) KX_VehicleWrapper::sPyGetNumWheels, METH_VARARGS}, - {"getWheelOrientationQuaternion",(PyCFunction) KX_VehicleWrapper::sPyGetWheelOrientationQuaternion, METH_VARARGS}, - {"getWheelRotation",(PyCFunction) KX_VehicleWrapper::sPyGetWheelRotation, METH_VARARGS}, - {"getWheelPosition",(PyCFunction) KX_VehicleWrapper::sPyGetWheelPosition, METH_VARARGS}, - {"getConstraintId",(PyCFunction) KX_VehicleWrapper::sPyGetConstraintId, METH_VARARGS}, - {"getConstraintType",(PyCFunction) KX_VehicleWrapper::sPyGetConstraintType, METH_VARARGS}, - {"setSteeringValue",(PyCFunction) KX_VehicleWrapper::sPySetSteeringValue, METH_VARARGS}, - {"applyEngineForce",(PyCFunction) KX_VehicleWrapper::sPyApplyEngineForce, METH_VARARGS}, - {"applyBraking",(PyCFunction) KX_VehicleWrapper::sPyApplyBraking, METH_VARARGS}, - {"setTyreFriction",(PyCFunction) KX_VehicleWrapper::sPySetTyreFriction, METH_VARARGS}, - {"setSuspensionStiffness",(PyCFunction) KX_VehicleWrapper::sPySetSuspensionStiffness, METH_VARARGS}, - {"setSuspensionDamping",(PyCFunction) KX_VehicleWrapper::sPySetSuspensionDamping, METH_VARARGS}, - {"setSuspensionCompression",(PyCFunction) KX_VehicleWrapper::sPySetSuspensionCompression, METH_VARARGS}, - {"setRollInfluence",(PyCFunction) KX_VehicleWrapper::sPySetRollInfluence, METH_VARARGS}, - {NULL,NULL} //Sentinel + {"addWheel", (PyCFunction)KX_VehicleWrapper::sPyAddWheel, METH_VARARGS}, + {"getNumWheels", (PyCFunction)KX_VehicleWrapper::sPyGetNumWheels, METH_VARARGS}, + {"getWheelOrientationQuaternion", (PyCFunction)KX_VehicleWrapper::sPyGetWheelOrientationQuaternion, METH_VARARGS}, + {"getWheelRotation", (PyCFunction)KX_VehicleWrapper::sPyGetWheelRotation, METH_VARARGS}, + {"getWheelPosition", (PyCFunction)KX_VehicleWrapper::sPyGetWheelPosition, METH_VARARGS}, + {"getConstraintId", (PyCFunction)KX_VehicleWrapper::sPyGetConstraintId, METH_VARARGS}, + {"getConstraintType", (PyCFunction)KX_VehicleWrapper::sPyGetConstraintType, METH_VARARGS}, + {"setSteeringValue", (PyCFunction)KX_VehicleWrapper::sPySetSteeringValue, METH_VARARGS}, + {"applyEngineForce", (PyCFunction)KX_VehicleWrapper::sPyApplyEngineForce, METH_VARARGS}, + {"applyBraking", (PyCFunction)KX_VehicleWrapper::sPyApplyBraking, METH_VARARGS}, + {"setTyreFriction", (PyCFunction)KX_VehicleWrapper::sPySetTyreFriction, METH_VARARGS}, + {"setSuspensionStiffness", (PyCFunction)KX_VehicleWrapper::sPySetSuspensionStiffness, METH_VARARGS}, + {"setSuspensionDamping", (PyCFunction)KX_VehicleWrapper::sPySetSuspensionDamping, METH_VARARGS}, + {"setSuspensionCompression", (PyCFunction)KX_VehicleWrapper::sPySetSuspensionCompression, METH_VARARGS}, + {"setRollInfluence", (PyCFunction)KX_VehicleWrapper::sPySetRollInfluence, METH_VARARGS}, + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_VehicleWrapper::Attributes[] = { - { NULL } //Sentinel + EXP_PYATTRIBUTE_RW_FUNCTION("rayMask", KX_VehicleWrapper, pyattr_get_ray_mask, pyattr_set_ray_mask), + EXP_PYATTRIBUTE_RO_FUNCTION("constraint_id", KX_VehicleWrapper, pyattr_get_constraintId), + EXP_PYATTRIBUTE_RO_FUNCTION("constraint_type", KX_VehicleWrapper, pyattr_get_constraintType), + EXP_PYATTRIBUTE_NULL //Sentinel }; +PyObject *KX_VehicleWrapper::pyattr_get_constraintId(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_VehicleWrapper *self = static_cast(self_v); + return PyLong_FromLong(self->m_vehicle->GetUserConstraintId()); +} + +PyObject *KX_VehicleWrapper::pyattr_get_constraintType(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + return PyLong_FromLong(PHY_VEHICLE_CONSTRAINT); +} + +PyObject *KX_VehicleWrapper::pyattr_get_ray_mask(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_VehicleWrapper *wrapper = static_cast(self); + return PyLong_FromLong(wrapper->m_vehicle->GetRayCastMask()); +} + +int KX_VehicleWrapper::pyattr_set_ray_mask(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_VehicleWrapper *wrapper = static_cast(self); + + int mask = PyLong_AsLong(value); + + if (mask == -1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "rayMask = int: KX_VehicleWrapper, expected an int bit field"); + return PY_SET_ATTR_FAIL; + } + + if (mask == 0 || mask & ~((1 << OB_MAX_COL_MASKS) - 1)) { + PyErr_Format(PyExc_AttributeError, "rayMask = int: KX_VehicleWrapper, expected a int bit field, 0 < rayMask < %i", (1 << OB_MAX_COL_MASKS)); + return PY_SET_ATTR_FAIL; + } + + wrapper->m_vehicle->SetRayCastMask(mask); + + return PY_SET_ATTR_SUCCESS; +} + #endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_VehicleWrapper.h b/source/gameengine/Ketsji/KX_VehicleWrapper.h index 259ca7cc1ba3..98a31be2eaa6 100644 --- a/source/gameengine/Ketsji/KX_VehicleWrapper.h +++ b/source/gameengine/Ketsji/KX_VehicleWrapper.h @@ -8,54 +8,55 @@ #include "EXP_Value.h" class PHY_IVehicle; -class PHY_IMotionState; - -#include ///Python interface to physics vehicles (primarily 4-wheel cars and 2wheel bikes) -class KX_VehicleWrapper : public PyObjectPlus +class KX_VehicleWrapper : public EXP_Value { Py_Header - std::vector m_motionStates; - public: - KX_VehicleWrapper(PHY_IVehicle* vehicle,class PHY_IPhysicsEnvironment* physenv); + KX_VehicleWrapper(PHY_IVehicle* vehicle); virtual ~KX_VehicleWrapper (); - int getConstraintId(); - -#ifdef WITH_PYTHON - - KX_PYMETHOD_VARARGS(KX_VehicleWrapper,AddWheel); - KX_PYMETHOD_VARARGS(KX_VehicleWrapper,GetNumWheels); - KX_PYMETHOD_VARARGS(KX_VehicleWrapper,GetWheelOrientationQuaternion); - KX_PYMETHOD_VARARGS(KX_VehicleWrapper,GetWheelRotation); - - KX_PYMETHOD_VARARGS(KX_VehicleWrapper,GetWheelPosition); - - KX_PYMETHOD_VARARGS(KX_VehicleWrapper,GetConstraintId); - KX_PYMETHOD_VARARGS(KX_VehicleWrapper,GetConstraintType); - KX_PYMETHOD_VARARGS(KX_VehicleWrapper,SetSteeringValue); + virtual std::string GetName(); - KX_PYMETHOD_VARARGS(KX_VehicleWrapper,ApplyEngineForce); - - KX_PYMETHOD_VARARGS(KX_VehicleWrapper,ApplyBraking); - - KX_PYMETHOD_VARARGS(KX_VehicleWrapper,SetTyreFriction); - - KX_PYMETHOD_VARARGS(KX_VehicleWrapper,SetSuspensionStiffness); - - KX_PYMETHOD_VARARGS(KX_VehicleWrapper,SetSuspensionDamping); - - KX_PYMETHOD_VARARGS(KX_VehicleWrapper,SetSuspensionCompression); +#ifdef WITH_PYTHON + + EXP_PYMETHOD_VARARGS(KX_VehicleWrapper,AddWheel); + EXP_PYMETHOD_VARARGS(KX_VehicleWrapper,GetNumWheels); + EXP_PYMETHOD_VARARGS(KX_VehicleWrapper,GetWheelOrientationQuaternion); + EXP_PYMETHOD_VARARGS(KX_VehicleWrapper,GetWheelRotation); + + EXP_PYMETHOD_VARARGS(KX_VehicleWrapper,GetWheelPosition); + + EXP_PYMETHOD_VARARGS(KX_VehicleWrapper,GetConstraintId); + EXP_PYMETHOD_VARARGS(KX_VehicleWrapper,GetConstraintType); + + EXP_PYMETHOD_VARARGS(KX_VehicleWrapper,SetSteeringValue); + + EXP_PYMETHOD_VARARGS(KX_VehicleWrapper,ApplyEngineForce); + + EXP_PYMETHOD_VARARGS(KX_VehicleWrapper,ApplyBraking); + + EXP_PYMETHOD_VARARGS(KX_VehicleWrapper,SetTyreFriction); + + EXP_PYMETHOD_VARARGS(KX_VehicleWrapper,SetSuspensionStiffness); + + EXP_PYMETHOD_VARARGS(KX_VehicleWrapper,SetSuspensionDamping); + + EXP_PYMETHOD_VARARGS(KX_VehicleWrapper,SetSuspensionCompression); + + EXP_PYMETHOD_VARARGS(KX_VehicleWrapper,SetRollInfluence); + + static PyObject *pyattr_get_ray_mask(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_ray_mask(EXP_PyObjectPlus *self, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_constraintId(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_constraintType(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); - KX_PYMETHOD_VARARGS(KX_VehicleWrapper,SetRollInfluence); #endif /* WITH_PYTHON */ private: PHY_IVehicle* m_vehicle; - PHY_IPhysicsEnvironment* m_physenv; }; #endif /* __KX_VEHICLEWRAPPER_H__ */ diff --git a/source/gameengine/Ketsji/KX_VertexProxy.cpp b/source/gameengine/Ketsji/KX_VertexProxy.cpp index 2733f774663a..469ab8fdeb69 100644 --- a/source/gameengine/Ketsji/KX_VertexProxy.cpp +++ b/source/gameengine/Ketsji/KX_VertexProxy.cpp @@ -29,19 +29,23 @@ * \ingroup ketsji */ - #ifdef WITH_PYTHON #include "KX_VertexProxy.h" -#include "KX_MeshProxy.h" -#include "RAS_TexVert.h" +#include "KX_Mesh.h" + +#include "RAS_DisplayArray.h" #include "KX_PyMath.h" +#include "EXP_ListWrapper.h" + +#include + PyTypeObject KX_VertexProxy::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_VertexProxy", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -49,546 +53,561 @@ PyTypeObject KX_VertexProxy::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, - &CValue::Type, - 0,0,0,0,0,0, + &EXP_Value::Type, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_VertexProxy::Methods[] = { - {"getXYZ", (PyCFunction)KX_VertexProxy::sPyGetXYZ,METH_NOARGS}, - {"setXYZ", (PyCFunction)KX_VertexProxy::sPySetXYZ,METH_O}, + {"getXYZ", (PyCFunction)KX_VertexProxy::sPyGetXYZ, METH_NOARGS}, + {"setXYZ", (PyCFunction)KX_VertexProxy::sPySetXYZ, METH_O}, {"getUV", (PyCFunction)KX_VertexProxy::sPyGetUV1, METH_NOARGS}, {"setUV", (PyCFunction)KX_VertexProxy::sPySetUV1, METH_O}, - {"getUV2", (PyCFunction)KX_VertexProxy::sPyGetUV2,METH_NOARGS}, - {"setUV2", (PyCFunction)KX_VertexProxy::sPySetUV2,METH_VARARGS}, + {"getUV2", (PyCFunction)KX_VertexProxy::sPyGetUV2, METH_NOARGS}, + {"setUV2", (PyCFunction)KX_VertexProxy::sPySetUV2, METH_VARARGS}, - {"getRGBA", (PyCFunction)KX_VertexProxy::sPyGetRGBA,METH_NOARGS}, - {"setRGBA", (PyCFunction)KX_VertexProxy::sPySetRGBA,METH_O}, - {"getNormal", (PyCFunction)KX_VertexProxy::sPyGetNormal,METH_NOARGS}, - {"setNormal", (PyCFunction)KX_VertexProxy::sPySetNormal,METH_O}, - {NULL,NULL} //Sentinel + {"getRGBA", (PyCFunction)KX_VertexProxy::sPyGetRGBA, METH_NOARGS}, + {"setRGBA", (PyCFunction)KX_VertexProxy::sPySetRGBA, METH_O}, + {"getNormal", (PyCFunction)KX_VertexProxy::sPyGetNormal, METH_NOARGS}, + {"setNormal", (PyCFunction)KX_VertexProxy::sPySetNormal, METH_O}, + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_VertexProxy::Attributes[] = { - KX_PYATTRIBUTE_RW_FUNCTION("x", KX_VertexProxy, pyattr_get_x, pyattr_set_x), - KX_PYATTRIBUTE_RW_FUNCTION("y", KX_VertexProxy, pyattr_get_y, pyattr_set_y), - KX_PYATTRIBUTE_RW_FUNCTION("z", KX_VertexProxy, pyattr_get_z, pyattr_set_z), + EXP_PYATTRIBUTE_RW_FUNCTION("x", KX_VertexProxy, pyattr_get_x, pyattr_set_x), + EXP_PYATTRIBUTE_RW_FUNCTION("y", KX_VertexProxy, pyattr_get_y, pyattr_set_y), + EXP_PYATTRIBUTE_RW_FUNCTION("z", KX_VertexProxy, pyattr_get_z, pyattr_set_z), - KX_PYATTRIBUTE_RW_FUNCTION("r", KX_VertexProxy, pyattr_get_r, pyattr_set_r), - KX_PYATTRIBUTE_RW_FUNCTION("g", KX_VertexProxy, pyattr_get_g, pyattr_set_g), - KX_PYATTRIBUTE_RW_FUNCTION("b", KX_VertexProxy, pyattr_get_b, pyattr_set_b), - KX_PYATTRIBUTE_RW_FUNCTION("a", KX_VertexProxy, pyattr_get_a, pyattr_set_a), + EXP_PYATTRIBUTE_RW_FUNCTION("r", KX_VertexProxy, pyattr_get_r, pyattr_set_r), + EXP_PYATTRIBUTE_RW_FUNCTION("g", KX_VertexProxy, pyattr_get_g, pyattr_set_g), + EXP_PYATTRIBUTE_RW_FUNCTION("b", KX_VertexProxy, pyattr_get_b, pyattr_set_b), + EXP_PYATTRIBUTE_RW_FUNCTION("a", KX_VertexProxy, pyattr_get_a, pyattr_set_a), - KX_PYATTRIBUTE_RW_FUNCTION("u", KX_VertexProxy, pyattr_get_u, pyattr_set_u), - KX_PYATTRIBUTE_RW_FUNCTION("v", KX_VertexProxy, pyattr_get_v, pyattr_set_v), + EXP_PYATTRIBUTE_RW_FUNCTION("u", KX_VertexProxy, pyattr_get_u, pyattr_set_u), + EXP_PYATTRIBUTE_RW_FUNCTION("v", KX_VertexProxy, pyattr_get_v, pyattr_set_v), - KX_PYATTRIBUTE_RW_FUNCTION("u2", KX_VertexProxy, pyattr_get_u2, pyattr_set_u2), - KX_PYATTRIBUTE_RW_FUNCTION("v2", KX_VertexProxy, pyattr_get_v2, pyattr_set_v2), + EXP_PYATTRIBUTE_RW_FUNCTION("u2", KX_VertexProxy, pyattr_get_u2, pyattr_set_u2), + EXP_PYATTRIBUTE_RW_FUNCTION("v2", KX_VertexProxy, pyattr_get_v2, pyattr_set_v2), - KX_PYATTRIBUTE_RW_FUNCTION("XYZ", KX_VertexProxy, pyattr_get_XYZ, pyattr_set_XYZ), - KX_PYATTRIBUTE_RW_FUNCTION("UV", KX_VertexProxy, pyattr_get_UV, pyattr_set_UV), - KX_PYATTRIBUTE_RW_FUNCTION("uvs", KX_VertexProxy, pyattr_get_uvs, pyattr_set_uvs), + EXP_PYATTRIBUTE_RW_FUNCTION("XYZ", KX_VertexProxy, pyattr_get_XYZ, pyattr_set_XYZ), + EXP_PYATTRIBUTE_RW_FUNCTION("UV", KX_VertexProxy, pyattr_get_UV, pyattr_set_UV), + EXP_PYATTRIBUTE_RW_FUNCTION("uvs", KX_VertexProxy, pyattr_get_uvs, pyattr_set_uvs), - KX_PYATTRIBUTE_RW_FUNCTION("color", KX_VertexProxy, pyattr_get_color, pyattr_set_color), - KX_PYATTRIBUTE_RW_FUNCTION("normal", KX_VertexProxy, pyattr_get_normal, pyattr_set_normal), + EXP_PYATTRIBUTE_RW_FUNCTION("color", KX_VertexProxy, pyattr_get_color, pyattr_set_color), + EXP_PYATTRIBUTE_RW_FUNCTION("colors", KX_VertexProxy, pyattr_get_colors, pyattr_set_colors), + EXP_PYATTRIBUTE_RW_FUNCTION("normal", KX_VertexProxy, pyattr_get_normal, pyattr_set_normal), - { NULL } //Sentinel + EXP_PYATTRIBUTE_NULL //Sentinel }; -PyObject *KX_VertexProxy::pyattr_get_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_VertexProxy::pyattr_get_x(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_VertexProxy *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_array->GetPosition(self->m_vertexIndex).x); +} + +PyObject *KX_VertexProxy::pyattr_get_y(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_VertexProxy *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_array->GetPosition(self->m_vertexIndex).y); +} + +PyObject *KX_VertexProxy::pyattr_get_z(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_VertexProxy *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_array->GetPosition(self->m_vertexIndex).z); +} + +PyObject *KX_VertexProxy::pyattr_get_r(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_VertexProxy *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_array->GetColor(self->m_vertexIndex, 0)[0] / 255.0); +} + +PyObject *KX_VertexProxy::pyattr_get_g(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + KX_VertexProxy *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_array->GetColor(self->m_vertexIndex, 0)[1] / 255.0); +} + +PyObject *KX_VertexProxy::pyattr_get_b(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_VertexProxy* self = static_cast(self_v); - return PyFloat_FromDouble(self->m_vertex->getXYZ()[0]); + KX_VertexProxy *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_array->GetColor(self->m_vertexIndex, 0)[2] / 255.0); } -PyObject *KX_VertexProxy::pyattr_get_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_VertexProxy::pyattr_get_a(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_VertexProxy* self = static_cast(self_v); - return PyFloat_FromDouble(self->m_vertex->getXYZ()[1]); + KX_VertexProxy *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_array->GetColor(self->m_vertexIndex, 0)[3] / 255.0); } -PyObject *KX_VertexProxy::pyattr_get_z(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_VertexProxy::pyattr_get_u(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_VertexProxy* self = static_cast(self_v); - return PyFloat_FromDouble(self->m_vertex->getXYZ()[2]); + KX_VertexProxy *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_array->GetUv(self->m_vertexIndex, 0).x); } -PyObject *KX_VertexProxy::pyattr_get_r(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_VertexProxy::pyattr_get_v(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_VertexProxy* self = static_cast(self_v); - return PyFloat_FromDouble(self->m_vertex->getRGBA()[0]/255.0); + KX_VertexProxy *self = static_cast(self_v); + return PyFloat_FromDouble(self->m_array->GetUv(self->m_vertexIndex, 0).y); } -PyObject *KX_VertexProxy::pyattr_get_g(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_VertexProxy::pyattr_get_u2(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_VertexProxy* self = static_cast(self_v); - return PyFloat_FromDouble(self->m_vertex->getRGBA()[1]/255.0); + KX_VertexProxy *self = static_cast(self_v); + return (self->m_array->GetFormat().uvSize > 1) ? PyFloat_FromDouble(self->m_array->GetUv(self->m_vertexIndex, 1).x) : PyFloat_FromDouble(0.0f); } -PyObject *KX_VertexProxy::pyattr_get_b(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_VertexProxy::pyattr_get_v2(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_VertexProxy* self = static_cast(self_v); - return PyFloat_FromDouble(self->m_vertex->getRGBA()[2]/255.0); + KX_VertexProxy *self = static_cast(self_v); + return (self->m_array->GetFormat().uvSize > 1) ? PyFloat_FromDouble(self->m_array->GetUv(self->m_vertexIndex, 1).y) : PyFloat_FromDouble(0.0f); } -PyObject *KX_VertexProxy::pyattr_get_a(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_VertexProxy::pyattr_get_XYZ(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_VertexProxy* self = static_cast(self_v); - return PyFloat_FromDouble(self->m_vertex->getRGBA()[3]/255.0); + KX_VertexProxy *self = static_cast(self_v); + return PyObjectFrom(self->m_array->GetPosition(self->m_vertexIndex)); } -PyObject *KX_VertexProxy::pyattr_get_u(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_VertexProxy::pyattr_get_UV(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_VertexProxy* self = static_cast(self_v); - return PyFloat_FromDouble(self->m_vertex->getUV(0)[0]); + KX_VertexProxy *self = static_cast(self_v); + return PyObjectFrom(self->m_array->GetUv(self->m_vertexIndex, 0)); } -PyObject *KX_VertexProxy::pyattr_get_v(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +unsigned int KX_VertexProxy::py_get_uvs_size() { - KX_VertexProxy* self = static_cast(self_v); - return PyFloat_FromDouble(self->m_vertex->getUV(0)[1]); + return m_array->GetFormat().uvSize; } -PyObject *KX_VertexProxy::pyattr_get_u2(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_VertexProxy::py_get_uvs_item(unsigned int index) { - KX_VertexProxy* self = static_cast(self_v); - return PyFloat_FromDouble(self->m_vertex->getUV(1)[0]); + return PyObjectFrom(m_array->GetUv(m_vertexIndex, index)); } -PyObject *KX_VertexProxy::pyattr_get_v2(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +bool KX_VertexProxy::py_set_uvs_item(unsigned int index, PyObject *item) { - KX_VertexProxy* self = static_cast(self_v); - return PyFloat_FromDouble(self->m_vertex->getUV(1)[1]); + mt::vec2_packed uv; + if (!PyVecTo(item, uv)) { + return false; + } + + m_array->SetUv(m_vertexIndex, index, uv); + m_array->NotifyUpdate(RAS_DisplayArray::UVS_MODIFIED); + + return true; } -PyObject *KX_VertexProxy::pyattr_get_XYZ(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_VertexProxy::pyattr_get_uvs(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_VertexProxy* self = static_cast(self_v); - return PyObjectFrom(MT_Vector3(self->m_vertex->getXYZ())); + return (new EXP_ListWrapper(self_v))->NewProxy(true); } -PyObject *KX_VertexProxy::pyattr_get_UV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +unsigned int KX_VertexProxy::py_get_colors_size() { - KX_VertexProxy* self = static_cast(self_v); - return PyObjectFrom(MT_Point2(self->m_vertex->getUV(0))); + return m_array->GetFormat().colorSize; } -PyObject *KX_VertexProxy::pyattr_get_uvs(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_VertexProxy::py_get_colors_item(unsigned int index) { - KX_VertexProxy* self= static_cast(self_v); + const unsigned char *rgba = m_array->GetColor(m_vertexIndex, index); + mt::vec4 color(rgba[0], rgba[1], rgba[2], rgba[3]); + color /= 255.0f; + return PyObjectFrom(color); +} - PyObject* uvlist = PyList_New(RAS_TexVert::MAX_UNIT); - for (int i=0; im_vertex->getUV(i)))); +bool KX_VertexProxy::py_set_colors_item(unsigned int index, PyObject *item) +{ + mt::vec4 color; + if (!PyVecTo(item, color)) { + return false; } - return uvlist; + m_array->SetColor(m_vertexIndex, index, color); + m_array->NotifyUpdate(RAS_DisplayArray::COLORS_MODIFIED); + + return true; +} + +PyObject *KX_VertexProxy::pyattr_get_colors(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + return (new EXP_ListWrapper(self_v))->NewProxy(true); } -PyObject *KX_VertexProxy::pyattr_get_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_VertexProxy::pyattr_get_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_VertexProxy* self = static_cast(self_v); - const unsigned char *colp = self->m_vertex->getRGBA(); - MT_Vector4 color(colp[0], colp[1], colp[2], colp[3]); + KX_VertexProxy *self = static_cast(self_v); + const unsigned char *colp = self->m_array->GetColor(self->m_vertexIndex, 0); + mt::vec4 color(colp[0], colp[1], colp[2], colp[3]); color /= 255.0f; return PyObjectFrom(color); } -PyObject *KX_VertexProxy::pyattr_get_normal(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_VertexProxy::pyattr_get_normal(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { - KX_VertexProxy* self = static_cast(self_v); - return PyObjectFrom(MT_Vector3(self->m_vertex->getNormal())); + KX_VertexProxy *self = static_cast(self_v); + return PyObjectFrom(self->m_array->GetNormal(self->m_vertexIndex)); } -int KX_VertexProxy::pyattr_set_x(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_VertexProxy::pyattr_set_x(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_VertexProxy* self = static_cast(self_v); - if (PyFloat_Check(value)) - { + KX_VertexProxy *self = static_cast(self_v); + if (PyFloat_Check(value)) { float val = PyFloat_AsDouble(value); - MT_Point3 pos(self->m_vertex->getXYZ()); - pos.x() = val; - self->m_vertex->SetXYZ(pos); - self->m_mesh->SetMeshModified(true); + self->m_array->GetPosition(self->m_vertexIndex).x = val; + self->m_array->NotifyUpdate(RAS_DisplayArray::POSITION_MODIFIED); return PY_SET_ATTR_SUCCESS; } return PY_SET_ATTR_FAIL; } -int KX_VertexProxy::pyattr_set_y(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_VertexProxy::pyattr_set_y(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_VertexProxy* self = static_cast(self_v); - if (PyFloat_Check(value)) - { + KX_VertexProxy *self = static_cast(self_v); + if (PyFloat_Check(value)) { float val = PyFloat_AsDouble(value); - MT_Point3 pos(self->m_vertex->getXYZ()); - pos.y() = val; - self->m_vertex->SetXYZ(pos); - self->m_mesh->SetMeshModified(true); + self->m_array->GetPosition(self->m_vertexIndex).y = val; + self->m_array->NotifyUpdate(RAS_DisplayArray::POSITION_MODIFIED); return PY_SET_ATTR_SUCCESS; } return PY_SET_ATTR_FAIL; } -int KX_VertexProxy::pyattr_set_z(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_VertexProxy::pyattr_set_z(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_VertexProxy* self = static_cast(self_v); - if (PyFloat_Check(value)) - { + KX_VertexProxy *self = static_cast(self_v); + if (PyFloat_Check(value)) { float val = PyFloat_AsDouble(value); - MT_Point3 pos(self->m_vertex->getXYZ()); - pos.z() = val; - self->m_vertex->SetXYZ(pos); - self->m_mesh->SetMeshModified(true); + self->m_array->GetPosition(self->m_vertexIndex).z = val; + self->m_array->NotifyUpdate(RAS_DisplayArray::POSITION_MODIFIED); return PY_SET_ATTR_SUCCESS; } return PY_SET_ATTR_FAIL; } -int KX_VertexProxy::pyattr_set_u(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_VertexProxy::pyattr_set_u(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_VertexProxy* self = static_cast(self_v); - if (PyFloat_Check(value)) - { + KX_VertexProxy *self = static_cast(self_v); + if (PyFloat_Check(value)) { float val = PyFloat_AsDouble(value); - MT_Point2 uv = self->m_vertex->getUV(0); - uv[0] = val; - self->m_vertex->SetUV(0, uv); - self->m_mesh->SetMeshModified(true); + self->m_array->GetUv(self->m_vertexIndex, 0).x = val; + self->m_array->NotifyUpdate(RAS_DisplayArray::UVS_MODIFIED); return PY_SET_ATTR_SUCCESS; } return PY_SET_ATTR_FAIL; } -int KX_VertexProxy::pyattr_set_v(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_VertexProxy::pyattr_set_v(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_VertexProxy* self = static_cast(self_v); - if (PyFloat_Check(value)) - { + KX_VertexProxy *self = static_cast(self_v); + if (PyFloat_Check(value)) { float val = PyFloat_AsDouble(value); - MT_Point2 uv = self->m_vertex->getUV(0); - uv[1] = val; - self->m_vertex->SetUV(0, uv); - self->m_mesh->SetMeshModified(true); + self->m_array->GetUv(self->m_vertexIndex, 0).y = val; + self->m_array->NotifyUpdate(RAS_DisplayArray::UVS_MODIFIED); return PY_SET_ATTR_SUCCESS; } return PY_SET_ATTR_FAIL; } -int KX_VertexProxy::pyattr_set_u2(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_VertexProxy::pyattr_set_u2(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_VertexProxy* self = static_cast(self_v); - if (PyFloat_Check(value)) - { - float val = PyFloat_AsDouble(value); - MT_Point2 uv = self->m_vertex->getUV(1); - uv[0] = val; - self->m_vertex->SetUV(1, uv); - self->m_mesh->SetMeshModified(true); + KX_VertexProxy *self = static_cast(self_v); + if (PyFloat_Check(value)) { + if (self->m_array->GetFormat().uvSize > 1) { + float val = PyFloat_AsDouble(value); + self->m_array->GetUv(self->m_vertexIndex, 1).x = val; + self->m_array->NotifyUpdate(RAS_DisplayArray::UVS_MODIFIED); + } return PY_SET_ATTR_SUCCESS; } return PY_SET_ATTR_FAIL; } -int KX_VertexProxy::pyattr_set_v2(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_VertexProxy::pyattr_set_v2(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_VertexProxy* self = static_cast(self_v); - if (PyFloat_Check(value)) - { - float val = PyFloat_AsDouble(value); - MT_Point2 uv = self->m_vertex->getUV(1); - uv[1] = val; - self->m_vertex->SetUV(1, uv); - self->m_mesh->SetMeshModified(true); + KX_VertexProxy *self = static_cast(self_v); + if (PyFloat_Check(value)) { + if (self->m_array->GetFormat().uvSize > 1) { + float val = PyFloat_AsDouble(value); + self->m_array->GetUv(self->m_vertexIndex, 1).y = val; + self->m_array->NotifyUpdate(RAS_DisplayArray::UVS_MODIFIED); + } return PY_SET_ATTR_SUCCESS; } return PY_SET_ATTR_FAIL; } -int KX_VertexProxy::pyattr_set_r(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_VertexProxy::pyattr_set_r(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_VertexProxy* self = static_cast(self_v); - if (PyFloat_Check(value)) - { + KX_VertexProxy *self = static_cast(self_v); + if (PyFloat_Check(value)) { float val = PyFloat_AsDouble(value); - unsigned int icol = *((const unsigned int *)self->m_vertex->getRGBA()); - unsigned char *cp = (unsigned char*) &icol; - val *= 255.0f; - cp[0] = (unsigned char) val; - self->m_vertex->SetRGBA(icol); - self->m_mesh->SetMeshModified(true); + self->m_array->GetColor(self->m_vertexIndex, 0)[0] = (unsigned char)(val * 255.0f); + self->m_array->NotifyUpdate(RAS_DisplayArray::COLORS_MODIFIED); return PY_SET_ATTR_SUCCESS; } return PY_SET_ATTR_FAIL; } -int KX_VertexProxy::pyattr_set_g(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_VertexProxy::pyattr_set_g(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_VertexProxy* self = static_cast(self_v); - if (PyFloat_Check(value)) - { + KX_VertexProxy *self = static_cast(self_v); + if (PyFloat_Check(value)) { float val = PyFloat_AsDouble(value); - unsigned int icol = *((const unsigned int *)self->m_vertex->getRGBA()); - unsigned char *cp = (unsigned char*) &icol; - val *= 255.0f; - cp[1] = (unsigned char) val; - self->m_vertex->SetRGBA(icol); - self->m_mesh->SetMeshModified(true); + self->m_array->GetColor(self->m_vertexIndex, 0)[1] = (unsigned char)(val * 255.0f); + self->m_array->NotifyUpdate(RAS_DisplayArray::COLORS_MODIFIED); return PY_SET_ATTR_SUCCESS; } return PY_SET_ATTR_FAIL; } -int KX_VertexProxy::pyattr_set_b(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_VertexProxy::pyattr_set_b(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_VertexProxy* self = static_cast(self_v); - if (PyFloat_Check(value)) - { + KX_VertexProxy *self = static_cast(self_v); + if (PyFloat_Check(value)) { float val = PyFloat_AsDouble(value); - unsigned int icol = *((const unsigned int *)self->m_vertex->getRGBA()); - unsigned char *cp = (unsigned char*) &icol; - val *= 255.0f; - cp[2] = (unsigned char) val; - self->m_vertex->SetRGBA(icol); - self->m_mesh->SetMeshModified(true); + self->m_array->GetColor(self->m_vertexIndex, 0)[2] = (unsigned char)(val * 255.0f); + self->m_array->NotifyUpdate(RAS_DisplayArray::COLORS_MODIFIED); return PY_SET_ATTR_SUCCESS; } return PY_SET_ATTR_FAIL; } -int KX_VertexProxy::pyattr_set_a(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_VertexProxy::pyattr_set_a(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_VertexProxy* self = static_cast(self_v); - if (PyFloat_Check(value)) - { + KX_VertexProxy *self = static_cast(self_v); + if (PyFloat_Check(value)) { float val = PyFloat_AsDouble(value); - unsigned int icol = *((const unsigned int *)self->m_vertex->getRGBA()); - unsigned char *cp = (unsigned char*) &icol; - val *= 255.0f; - cp[3] = (unsigned char) val; - self->m_vertex->SetRGBA(icol); - self->m_mesh->SetMeshModified(true); + self->m_array->GetColor(self->m_vertexIndex, 0)[3] = (unsigned char)(val * 255.0f); + self->m_array->NotifyUpdate(RAS_DisplayArray::COLORS_MODIFIED); return PY_SET_ATTR_SUCCESS; } return PY_SET_ATTR_FAIL; } -int KX_VertexProxy::pyattr_set_XYZ(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_VertexProxy::pyattr_set_XYZ(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_VertexProxy* self = static_cast(self_v); - if (PySequence_Check(value)) - { - MT_Point3 vec; - if (PyVecTo(value, vec)) - { - self->m_vertex->SetXYZ(vec); - self->m_mesh->SetMeshModified(true); - return PY_SET_ATTR_SUCCESS; - } + KX_VertexProxy *self = static_cast(self_v); + mt::vec3_packed vec; + if (PyVecTo(value, vec)) { + self->m_array->SetPosition(self->m_vertexIndex, vec); + self->m_array->NotifyUpdate(RAS_DisplayArray::POSITION_MODIFIED); + return PY_SET_ATTR_SUCCESS; } return PY_SET_ATTR_FAIL; } -int KX_VertexProxy::pyattr_set_UV(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_VertexProxy::pyattr_set_UV(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_VertexProxy* self = static_cast(self_v); - if (PySequence_Check(value)) - { - MT_Point2 vec; - if (PyVecTo(value, vec)) { - self->m_vertex->SetUV(0, vec); - self->m_mesh->SetMeshModified(true); - return PY_SET_ATTR_SUCCESS; - } + KX_VertexProxy *self = static_cast(self_v); + mt::vec2_packed vec; + if (PyVecTo(value, vec)) { + self->m_array->SetUv(self->m_vertexIndex, 0, vec); + self->m_array->NotifyUpdate(RAS_DisplayArray::UVS_MODIFIED); + return PY_SET_ATTR_SUCCESS; } return PY_SET_ATTR_FAIL; } -int KX_VertexProxy::pyattr_set_uvs(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_VertexProxy::pyattr_set_uvs(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_VertexProxy* self= static_cast(self_v); - if (PySequence_Check(value)) - { - MT_Point2 vec; - for (int i=0; im_vertex->SetUV(i, vec); - self->m_mesh->SetMeshModified(true); + KX_VertexProxy *self = static_cast(self_v); + if (PySequence_Check(value)) { + mt::vec2_packed vec; + for (int i = 0; i < PySequence_Size(value) && i < self->m_array->GetFormat().uvSize; ++i) { + if (PyVecTo(PySequence_GetItem(value, i), vec)) { + self->m_array->SetUv(self->m_vertexIndex, i, vec); } - else - { - PyErr_SetString(PyExc_AttributeError, STR_String().Format("list[%d] was not a vector", i).ReadPtr()); + else { + PyErr_SetString(PyExc_AttributeError, ((boost::format("list[%d] was not a vector") % i).str().c_str())); return PY_SET_ATTR_FAIL; } } - self->m_mesh->SetMeshModified(true); + self->m_array->NotifyUpdate(RAS_DisplayArray::UVS_MODIFIED); return PY_SET_ATTR_SUCCESS; } return PY_SET_ATTR_FAIL; } -int KX_VertexProxy::pyattr_set_color(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_VertexProxy::pyattr_set_color(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_VertexProxy* self = static_cast(self_v); - if (PySequence_Check(value)) - { - MT_Vector4 vec; - if (PyVecTo(value, vec)) - { - self->m_vertex->SetRGBA(vec); - self->m_mesh->SetMeshModified(true); - return PY_SET_ATTR_SUCCESS; - } + KX_VertexProxy *self = static_cast(self_v); + mt::vec4 vec; + if (PyVecTo(value, vec)) { + self->m_array->SetColor(self->m_vertexIndex, 0, vec); + self->m_array->NotifyUpdate(RAS_DisplayArray::COLORS_MODIFIED); + return PY_SET_ATTR_SUCCESS; } return PY_SET_ATTR_FAIL; } -int KX_VertexProxy::pyattr_set_normal(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_VertexProxy::pyattr_set_colors(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_VertexProxy* self = static_cast(self_v); - if (PySequence_Check(value)) - { - MT_Vector3 vec; - if (PyVecTo(value, vec)) - { - self->m_vertex->SetNormal(vec); - self->m_mesh->SetMeshModified(true); - return PY_SET_ATTR_SUCCESS; + KX_VertexProxy *self = static_cast(self_v); + if (PySequence_Check(value)) { + mt::vec4 vec; + for (int i = 0; i < PySequence_Size(value) && i < self->m_array->GetFormat().colorSize; ++i) { + if (PyVecTo(PySequence_GetItem(value, i), vec)) { + self->m_array->SetColor(self->m_vertexIndex, i, vec); + } + else { + PyErr_SetString(PyExc_AttributeError, ((boost::format("list[%d] was not a vector") % i).str().c_str())); + return PY_SET_ATTR_FAIL; + } } + + self->m_array->NotifyUpdate(RAS_DisplayArray::COLORS_MODIFIED); + return PY_SET_ATTR_SUCCESS; } return PY_SET_ATTR_FAIL; } -KX_VertexProxy::KX_VertexProxy(KX_MeshProxy*mesh, RAS_TexVert* vertex) -: m_vertex(vertex), - m_mesh(mesh) +int KX_VertexProxy::pyattr_set_normal(EXP_PyObjectPlus *self_v, const struct EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_VertexProxy *self = static_cast(self_v); + mt::vec3_packed vec; + if (PyVecTo(value, vec)) { + self->m_array->SetNormal(self->m_vertexIndex, vec); + self->m_array->NotifyUpdate(RAS_DisplayArray::NORMAL_MODIFIED); + return PY_SET_ATTR_SUCCESS; + } + return PY_SET_ATTR_FAIL; +} + +KX_VertexProxy::KX_VertexProxy(RAS_DisplayArray *array, unsigned int vertexIndex) + :m_vertexIndex(vertexIndex), + m_array(array) { - /* see bug [#27071] */ - Py_INCREF(m_mesh->GetProxy()); } KX_VertexProxy::~KX_VertexProxy() { - /* see bug [#27071] */ - Py_DECREF(m_mesh->GetProxy()); } +unsigned int KX_VertexProxy::GetVertexIndex() const +{ + return m_vertexIndex; +} +RAS_DisplayArray *KX_VertexProxy::GetDisplayArray() const +{ + return m_array; +} // stuff for cvalue related things -CValue* KX_VertexProxy::Calc(VALUE_OPERATOR, CValue *) { return NULL;} -CValue* KX_VertexProxy::CalcFinal(VALUE_DATA_TYPE, VALUE_OPERATOR, CValue *) { return NULL;} -static STR_String sVertexName = "vertex"; -const STR_String & KX_VertexProxy::GetText() {return sVertexName;}; -double KX_VertexProxy::GetNumber() { return -1;} -STR_String& KX_VertexProxy::GetName() { return sVertexName;} -void KX_VertexProxy::SetName(const char *) { }; -CValue* KX_VertexProxy::GetReplica() { return NULL;} +std::string KX_VertexProxy::GetName() +{ + return "vertex"; +} // stuff for python integration - PyObject *KX_VertexProxy::PyGetXYZ() { - return PyObjectFrom(MT_Point3(m_vertex->getXYZ())); + return PyObjectFrom(m_array->GetPosition(m_vertexIndex)); } PyObject *KX_VertexProxy::PySetXYZ(PyObject *value) { - MT_Point3 vec; - if (!PyVecTo(value, vec)) - return NULL; + mt::vec3_packed vec; + if (!PyVecTo(value, vec)) { + return nullptr; + } - m_vertex->SetXYZ(vec); - m_mesh->SetMeshModified(true); + m_array->SetPosition(m_vertexIndex, vec); + m_array->NotifyUpdate(RAS_DisplayArray::POSITION_MODIFIED); Py_RETURN_NONE; } PyObject *KX_VertexProxy::PyGetNormal() { - return PyObjectFrom(MT_Vector3(m_vertex->getNormal())); + return PyObjectFrom(m_array->GetNormal(m_vertexIndex)); } PyObject *KX_VertexProxy::PySetNormal(PyObject *value) { - MT_Vector3 vec; - if (!PyVecTo(value, vec)) - return NULL; + mt::vec3_packed vec; + if (!PyVecTo(value, vec)) { + return nullptr; + } - m_vertex->SetNormal(vec); - m_mesh->SetMeshModified(true); + m_array->SetNormal(m_vertexIndex, vec); + m_array->NotifyUpdate(RAS_DisplayArray::NORMAL_MODIFIED); Py_RETURN_NONE; } - PyObject *KX_VertexProxy::PyGetRGBA() { - int *rgba = (int *) m_vertex->getRGBA(); - return PyLong_FromLong(*rgba); + const unsigned int rgba = m_array->GetRawColor(m_vertexIndex, 0); + return PyLong_FromLong(rgba); } PyObject *KX_VertexProxy::PySetRGBA(PyObject *value) { if (PyLong_Check(value)) { int rgba = PyLong_AsLong(value); - m_vertex->SetRGBA(rgba); - m_mesh->SetMeshModified(true); + m_array->SetColor(m_vertexIndex, 0, rgba); + m_array->NotifyUpdate(true); Py_RETURN_NONE; } else { - MT_Vector4 vec; - if (PyVecTo(value, vec)) - { - m_vertex->SetRGBA(vec); - m_mesh->SetMeshModified(true); + mt::vec4 vec; + if (PyVecTo(value, vec)) { + m_array->SetColor(m_vertexIndex, 0, vec); + m_array->NotifyUpdate(RAS_DisplayArray::COLORS_MODIFIED); Py_RETURN_NONE; } } PyErr_SetString(PyExc_TypeError, "vert.setRGBA(value): KX_VertexProxy, expected a 4D vector or an int"); - return NULL; + return nullptr; } - PyObject *KX_VertexProxy::PyGetUV1() { - return PyObjectFrom(MT_Vector2(m_vertex->getUV(0))); + return PyObjectFrom(m_array->GetUv(m_vertexIndex, 0)); } PyObject *KX_VertexProxy::PySetUV1(PyObject *value) { - MT_Point2 vec; - if (!PyVecTo(value, vec)) - return NULL; + mt::vec2_packed vec; + if (!PyVecTo(value, vec)) { + return nullptr; + } - m_vertex->SetUV(0, vec); - m_mesh->SetMeshModified(true); + m_array->SetUv(m_vertexIndex, 0, vec); + m_array->NotifyUpdate(RAS_DisplayArray::UVS_MODIFIED); Py_RETURN_NONE; } PyObject *KX_VertexProxy::PyGetUV2() { - return PyObjectFrom(MT_Vector2(m_vertex->getUV(1))); + return (m_array->GetFormat().uvSize > 1) ? PyObjectFrom(m_array->GetUv(m_vertexIndex, 1)) : PyObjectFrom(mt::zero2); } PyObject *KX_VertexProxy::PySetUV2(PyObject *args) { - MT_Point2 vec; - if (!PyVecTo(args, vec)) - return NULL; + mt::vec2_packed vec; + if (!PyVecTo(args, vec)) { + return nullptr; + } - m_vertex->SetUV(1, vec); - m_mesh->SetMeshModified(true); + if (m_array->GetFormat().uvSize > 1) { + m_array->SetUv(m_vertexIndex, 1, vec); + m_array->NotifyUpdate(RAS_DisplayArray::UVS_MODIFIED); + } Py_RETURN_NONE; } diff --git a/source/gameengine/Ketsji/KX_VertexProxy.h b/source/gameengine/Ketsji/KX_VertexProxy.h index ce4cb1f83430..483dadc5f6b1 100644 --- a/source/gameengine/Ketsji/KX_VertexProxy.h +++ b/source/gameengine/Ketsji/KX_VertexProxy.h @@ -34,79 +34,84 @@ #ifdef WITH_PYTHON -#include "SCA_IObject.h" +#include "EXP_Value.h" -class KX_VertexProxy : public CValue +class RAS_DisplayArray; + +class KX_VertexProxy : public EXP_Value { Py_Header + protected: + unsigned int m_vertexIndex; + RAS_DisplayArray *m_array; - class RAS_TexVert* m_vertex; - class KX_MeshProxy* m_mesh; public: - KX_VertexProxy(class KX_MeshProxy*mesh, class RAS_TexVert* vertex); + KX_VertexProxy(RAS_DisplayArray *array, unsigned int vertexIndex); virtual ~KX_VertexProxy(); - // stuff for cvalue related things - CValue* Calc(VALUE_OPERATOR op, CValue *val); - CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val); - const STR_String & GetText(); - double GetNumber(); - STR_String& GetName(); - void SetName(const char *name); // Set the name of the value - CValue* GetReplica(); - - -// stuff for python integration - - static PyObject *pyattr_get_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_z(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_r(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_g(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_b(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_a(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_u(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_v(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_u2(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_v2(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_XYZ(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_UV(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_normal(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_uvs(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_x(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_set_y(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_set_z(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_set_u(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_set_v(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_set_u2(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_set_v2(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_set_r(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_set_g(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_set_b(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_set_a(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_set_XYZ(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_set_UV(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_set_color(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_set_normal(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static int pyattr_set_uvs(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - - KX_PYMETHOD_NOARGS(KX_VertexProxy,GetXYZ); - KX_PYMETHOD_O(KX_VertexProxy,SetXYZ); - KX_PYMETHOD_NOARGS(KX_VertexProxy,GetUV1); - KX_PYMETHOD_O(KX_VertexProxy,SetUV1); - - KX_PYMETHOD_NOARGS(KX_VertexProxy,GetUV2); - KX_PYMETHOD_VARARGS(KX_VertexProxy,SetUV2); - - KX_PYMETHOD_NOARGS(KX_VertexProxy,GetRGBA); - KX_PYMETHOD_O(KX_VertexProxy,SetRGBA); - KX_PYMETHOD_NOARGS(KX_VertexProxy,GetNormal); - KX_PYMETHOD_O(KX_VertexProxy,SetNormal); + unsigned int GetVertexIndex() const; + RAS_DisplayArray *GetDisplayArray() const; + // stuff for cvalue related things + std::string GetName(); + + static PyObject *pyattr_get_x(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_y(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_z(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_r(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_g(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_b(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_a(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_u(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_v(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_u2(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_v2(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_XYZ(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_UV(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_colors(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_normal(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_uvs(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_x(EXP_PyObjectPlus *self, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_y(EXP_PyObjectPlus *self, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_z(EXP_PyObjectPlus *self, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_u(EXP_PyObjectPlus *self, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_v(EXP_PyObjectPlus *self, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_u2(EXP_PyObjectPlus *self, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_v2(EXP_PyObjectPlus *self, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_r(EXP_PyObjectPlus *self, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_g(EXP_PyObjectPlus *self, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_b(EXP_PyObjectPlus *self, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_a(EXP_PyObjectPlus *self, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_XYZ(EXP_PyObjectPlus *self, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_UV(EXP_PyObjectPlus *self, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_color(EXP_PyObjectPlus *self, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_colors(EXP_PyObjectPlus *self, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_normal(EXP_PyObjectPlus *self, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static int pyattr_set_uvs(EXP_PyObjectPlus *self, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + + unsigned int py_get_uvs_size(); + PyObject *py_get_uvs_item(unsigned int index); + bool py_set_uvs_item(unsigned int index, PyObject *item); + unsigned int py_get_colors_size(); + PyObject *py_get_colors_item(unsigned int index); + bool py_set_colors_item(unsigned int index, PyObject *item); + + EXP_PYMETHOD_NOARGS(KX_VertexProxy, GetXYZ); + EXP_PYMETHOD_O(KX_VertexProxy, SetXYZ); + EXP_PYMETHOD_NOARGS(KX_VertexProxy, GetUV1); + EXP_PYMETHOD_O(KX_VertexProxy, SetUV1); + + EXP_PYMETHOD_NOARGS(KX_VertexProxy, GetUV2); + EXP_PYMETHOD_VARARGS(KX_VertexProxy, SetUV2); + + EXP_PYMETHOD_NOARGS(KX_VertexProxy, GetRGBA); + EXP_PYMETHOD_O(KX_VertexProxy, SetRGBA); + EXP_PYMETHOD_NOARGS(KX_VertexProxy, GetNormal); + EXP_PYMETHOD_O(KX_VertexProxy, SetNormal); }; -#endif /* WITH_PYTHON */ +#endif // WITH_PYTHON -#endif /* __KX_VERTEXPROXY_H__ */ +#endif // __KX_VERTEXPROXY_H__ diff --git a/source/gameengine/Ketsji/KX_VisibilityActuator.cpp b/source/gameengine/Ketsji/KX_VisibilityActuator.cpp index 1136dea041ba..62503188374a 100644 --- a/source/gameengine/Ketsji/KX_VisibilityActuator.cpp +++ b/source/gameengine/Ketsji/KX_VisibilityActuator.cpp @@ -34,50 +34,43 @@ #include "KX_VisibilityActuator.h" #include "KX_GameObject.h" -KX_VisibilityActuator::KX_VisibilityActuator( - SCA_IObject* gameobj, - bool visible, - bool occlusion, - bool recursive - ) - : SCA_IActuator(gameobj, KX_ACT_VISIBILITY), - m_visible(visible), - m_occlusion(occlusion), - m_recursive(recursive) +KX_VisibilityActuator::KX_VisibilityActuator(SCA_IObject *gameobj, + bool visible, + bool occlusion, + bool recursive) + :SCA_IActuator(gameobj, KX_ACT_VISIBILITY), + m_visible(visible), + m_occlusion(occlusion), + m_recursive(recursive) { // intentionally empty } -KX_VisibilityActuator::~KX_VisibilityActuator( - void - ) +KX_VisibilityActuator::~KX_VisibilityActuator(void) { // intentionally empty } -CValue* -KX_VisibilityActuator::GetReplica( - void - ) +EXP_Value *KX_VisibilityActuator::GetReplica(void) { - KX_VisibilityActuator* replica = new KX_VisibilityActuator(*this); + KX_VisibilityActuator *replica = new KX_VisibilityActuator(*this); replica->ProcessReplica(); return replica; } -bool -KX_VisibilityActuator::Update() +bool KX_VisibilityActuator::Update() { bool bNegativeEvent = IsNegativeEvent(); RemoveAllEvents(); - if (bNegativeEvent) return false; + if (bNegativeEvent) { + return false; + } - KX_GameObject *obj = (KX_GameObject*) GetParent(); + KX_GameObject *obj = (KX_GameObject *)GetParent(); obj->SetVisible(m_visible, m_recursive); obj->SetOccluder(m_occlusion, m_recursive); - obj->UpdateBuckets(m_recursive); return false; } @@ -92,9 +85,9 @@ KX_VisibilityActuator::Update() /* Integration hooks ------------------------------------------------------- */ PyTypeObject KX_VisibilityActuator::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_VisibilityActuator", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -102,26 +95,26 @@ PyTypeObject KX_VisibilityActuator::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, &SCA_IActuator::Type, - 0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_VisibilityActuator::Methods[] = { - {NULL,NULL} //Sentinel + {nullptr, nullptr} //Sentinel }; PyAttributeDef KX_VisibilityActuator::Attributes[] = { - KX_PYATTRIBUTE_BOOL_RW("visibility", KX_VisibilityActuator, m_visible), - KX_PYATTRIBUTE_BOOL_RW("useOcclusion", KX_VisibilityActuator, m_occlusion), - KX_PYATTRIBUTE_BOOL_RW("useRecursion", KX_VisibilityActuator, m_recursive), - { NULL } //Sentinel + EXP_PYATTRIBUTE_BOOL_RW("visibility", KX_VisibilityActuator, m_visible), + EXP_PYATTRIBUTE_BOOL_RW("useOcclusion", KX_VisibilityActuator, m_occlusion), + EXP_PYATTRIBUTE_BOOL_RW("useRecursion", KX_VisibilityActuator, m_recursive), + EXP_PYATTRIBUTE_NULL //Sentinel }; #endif // WITH_PYTHON diff --git a/source/gameengine/Ketsji/KX_VisibilityActuator.h b/source/gameengine/Ketsji/KX_VisibilityActuator.h index 228161403f92..c73fc1e0eb24 100644 --- a/source/gameengine/Ketsji/KX_VisibilityActuator.h +++ b/source/gameengine/Ketsji/KX_VisibilityActuator.h @@ -45,7 +45,7 @@ class KX_VisibilityActuator : public SCA_IActuator bool m_recursive; public: - + KX_VisibilityActuator( SCA_IObject* gameobj, bool visible, @@ -57,7 +57,7 @@ class KX_VisibilityActuator : public SCA_IActuator void ); - virtual CValue* + virtual EXP_Value* GetReplica( void ); @@ -72,3 +72,4 @@ class KX_VisibilityActuator : public SCA_IActuator }; #endif + diff --git a/source/gameengine/Ketsji/KX_WorldInfo.cpp b/source/gameengine/Ketsji/KX_WorldInfo.cpp index d8b9dabe5f3d..b7c8228c12c9 100644 --- a/source/gameengine/Ketsji/KX_WorldInfo.cpp +++ b/source/gameengine/Ketsji/KX_WorldInfo.cpp @@ -31,9 +31,8 @@ #include "KX_WorldInfo.h" -#include "KX_PythonInit.h" #include "KX_PyMath.h" -#include "RAS_IRasterizer.h" +#include "RAS_Rasterizer.h" #include "GPU_material.h" /* This little block needed for linking to Blender... */ @@ -47,25 +46,35 @@ #include "BLI_math.h" -#include "BKE_global.h" #include "BKE_scene.h" /* end of blender include block */ - KX_WorldInfo::KX_WorldInfo(Scene *blenderscene, World *blenderworld) + :m_scene(blenderscene) { if (blenderworld) { m_name = blenderworld->id.name + 2; - m_do_color_management = BKE_scene_check_color_management_enabled(blenderscene); m_hasworld = true; m_hasmist = ((blenderworld->mode) & WO_MIST ? true : false); + m_hasEnvLight = ((blenderworld->mode) & WO_ENV_LIGHT ? true : false); + m_savedData.horizonColor[0] = blenderworld->horr; + m_savedData.horizonColor[1] = blenderworld->horg; + m_savedData.horizonColor[2] = blenderworld->horb; + m_savedData.zenithColor[0] = blenderworld->zenr; + m_savedData.zenithColor[1] = blenderworld->zeng; + m_savedData.zenithColor[2] = blenderworld->zenb; + m_envLightEnergy = blenderworld->ao_env_energy; + m_envLightColor = blenderworld->aocolor; m_misttype = blenderworld->mistype; m_miststart = blenderworld->miststa; m_mistdistance = blenderworld->mistdist; m_mistintensity = blenderworld->misi; - setMistColor(blenderworld->horr, blenderworld->horg, blenderworld->horb); - setBackColor(blenderworld->horr, blenderworld->horg, blenderworld->horb); - setAmbientColor(blenderworld->ambr, blenderworld->ambg, blenderworld->ambb); + setMistColor(mt::vec3(blenderworld->horr, blenderworld->horg, blenderworld->horb)); + setHorizonColor(mt::vec4(blenderworld->horr, blenderworld->horg, blenderworld->horb, 1.0f)); + setZenithColor(mt::vec4(blenderworld->zenr, blenderworld->zeng, blenderworld->zenb, 1.0f)); + setAmbientColor(mt::vec3(blenderworld->ambr, blenderworld->ambg, blenderworld->ambb)); + setExposure(blenderworld->exp); + setRange(blenderworld->range); } else { m_hasworld = false; @@ -74,45 +83,45 @@ KX_WorldInfo::KX_WorldInfo(Scene *blenderscene, World *blenderworld) KX_WorldInfo::~KX_WorldInfo() { + // Restore saved horizon and zenith colors + if (m_hasworld) { + m_scene->world->horr = m_savedData.horizonColor[0]; + m_scene->world->horg = m_savedData.horizonColor[1]; + m_scene->world->horb = m_savedData.horizonColor[2]; + m_scene->world->zenr = m_savedData.zenithColor[0]; + m_scene->world->zeng = m_savedData.zenithColor[1]; + m_scene->world->zenb = m_savedData.zenithColor[2]; + } } -const STR_String& KX_WorldInfo::GetName() +std::string KX_WorldInfo::GetName() { return m_name; } -bool KX_WorldInfo::hasWorld() -{ - return m_hasworld; -} - -void KX_WorldInfo::setBackColor(float r, float g, float b) +void KX_WorldInfo::ReloadMaterial() { - m_backgroundcolor[0] = r; - m_backgroundcolor[1] = g; - m_backgroundcolor[2] = b; - - if (m_do_color_management) { - linearrgb_to_srgb_v3_v3(m_con_backgroundcolor, m_backgroundcolor); + if (m_hasworld && m_scene->world->skytype & (WO_SKYBLEND | WO_SKYPAPER | WO_SKYREAL)) { + m_gpuMat = GPU_material_world(m_scene, m_scene->world, GPU_MATERIAL_NO_COLOR_MANAGEMENT); } else { - copy_v3_v3(m_con_backgroundcolor, m_backgroundcolor); + m_gpuMat = nullptr; } } -const float *KX_WorldInfo::getBackColorConverted() const +bool KX_WorldInfo::hasWorld() { - return m_con_backgroundcolor; + return m_hasworld; } -void KX_WorldInfo::setMistType(short type) +void KX_WorldInfo::setHorizonColor(const mt::vec4& horizoncolor) { - m_misttype = type; + m_horizoncolor = horizoncolor; } -void KX_WorldInfo::setUseMist(bool enable) +void KX_WorldInfo::setZenithColor(const mt::vec4& zenithcolor) { - m_hasmist = enable; + m_zenithcolor = zenithcolor; } void KX_WorldInfo::setMistStart(float d) @@ -129,67 +138,94 @@ void KX_WorldInfo::setMistIntensity(float intensity) { m_mistintensity = intensity; } -void KX_WorldInfo::setMistColor(float r, float g, float b) + +void KX_WorldInfo::setExposure(float exposure) { - m_mistcolor[0] = r; - m_mistcolor[1] = g; - m_mistcolor[2] = b; + m_exposure = exposure; +} - if (m_do_color_management) { - linearrgb_to_srgb_v3_v3(m_con_mistcolor, m_mistcolor); - } - else { - copy_v3_v3(m_con_mistcolor, m_mistcolor); - } +void KX_WorldInfo::setRange(float range) +{ + m_range = range; } -void KX_WorldInfo::setAmbientColor(float r, float g, float b) +void KX_WorldInfo::setMistColor(const mt::vec3& mistcolor) { - m_ambientcolor[0] = r; - m_ambientcolor[1] = g; - m_ambientcolor[2] = b; + m_mistcolor = mistcolor; +} - if (m_do_color_management) { - linearrgb_to_srgb_v3_v3(m_con_ambientcolor, m_ambientcolor); - } - else { - copy_v3_v3(m_con_ambientcolor, m_ambientcolor); - } +void KX_WorldInfo::setAmbientColor(const mt::vec3& ambientcolor) +{ + m_ambientcolor = ambientcolor; } -void KX_WorldInfo::UpdateBackGround() +void KX_WorldInfo::UpdateBackGround(RAS_Rasterizer *rasty) { if (m_hasworld) { - RAS_IRasterizer *m_rasterizer = KX_GetActiveEngine()->GetRasterizer(); + // Update World values for world material created in GPU_material_world/GPU_material_old_world. + m_scene->world->zenr = m_zenithcolor[0]; + m_scene->world->zeng = m_zenithcolor[1]; + m_scene->world->zenb = m_zenithcolor[2]; + m_scene->world->horr = m_horizoncolor[0]; + m_scene->world->horg = m_horizoncolor[1]; + m_scene->world->horb = m_horizoncolor[2]; + + // Update GPUWorld values for regular materials. + GPU_horizon_update_color(m_horizoncolor.Data()); + GPU_zenith_update_color(m_zenithcolor.Data()); + } +} - if (m_rasterizer->GetDrawingMode() >= RAS_IRasterizer::KX_SOLID) { - m_rasterizer->SetBackColor(m_con_backgroundcolor); - GPU_horizon_update_color(m_backgroundcolor); +void KX_WorldInfo::UpdateWorldSettings(RAS_Rasterizer *rasty) +{ + if (m_hasworld) { + rasty->SetAmbientColor(m_ambientcolor); + GPU_ambient_update_color(m_ambientcolor.Data()); + GPU_update_exposure_range(m_exposure, m_range); + GPU_update_envlight_energy(m_envLightEnergy); + + if (m_hasmist) { + rasty->SetFog(m_misttype, m_miststart, m_mistdistance, m_mistintensity, m_mistcolor); + GPU_mist_update_values(m_misttype, m_miststart, m_mistdistance, m_mistintensity, m_mistcolor.Data()); + GPU_mist_update_enable(true); + } + else { + GPU_mist_update_enable(false); } } } -void KX_WorldInfo::UpdateWorldSettings() +void KX_WorldInfo::RenderBackground(RAS_Rasterizer *rasty) { if (m_hasworld) { - RAS_IRasterizer *m_rasterizer = KX_GetActiveEngine()->GetRasterizer(); - - if (m_rasterizer->GetDrawingMode() >= RAS_IRasterizer::KX_SOLID) { - m_rasterizer->SetAmbientColor(m_con_ambientcolor); - GPU_ambient_update_color(m_ambientcolor); - - if (m_hasmist) { - m_rasterizer->SetFog(m_misttype, m_miststart, m_mistdistance, m_mistintensity, m_con_mistcolor); - GPU_mist_update_values(m_misttype, m_miststart, m_mistdistance, m_mistintensity, m_mistcolor); - m_rasterizer->EnableFog(true); - GPU_mist_update_enable(true); - } - else { - m_rasterizer->EnableFog(false); - GPU_mist_update_enable(false); - } + if (m_gpuMat) { + static float texcofac[4] = { 0.0f, 0.0f, 1.0f, 1.0f }; + GPU_material_bind(m_gpuMat, m_scene->lay, 1.0f, false, rasty->GetViewMatrix().Data(), + rasty->GetViewInvMatrix().Data(), texcofac, false); + + /* Disable cull face instead of setting front face as it could be + * inversed in planar rendering. + */ + rasty->SetCullFace(false); + rasty->Enable(RAS_Rasterizer::RAS_DEPTH_TEST); + rasty->SetDepthFunc(RAS_Rasterizer::RAS_ALWAYS); + + rasty->DrawOverlayPlane(); + + rasty->SetDepthFunc(RAS_Rasterizer::RAS_LEQUAL); + + GPU_material_unbind(m_gpuMat); + } + else { + rasty->SetClearColor(m_horizoncolor[0], m_horizoncolor[1], m_horizoncolor[2], m_horizoncolor[3]); + rasty->Clear(RAS_Rasterizer::RAS_COLOR_BUFFER_BIT); } } + // Else render a dummy gray background. + else { + rasty->SetClearColor(0.05f, 0.05f, 0.05f, 1.0f); + rasty->Clear(RAS_Rasterizer::RAS_COLOR_BUFFER_BIT); + } } #ifdef WITH_PYTHON @@ -197,18 +233,14 @@ void KX_WorldInfo::UpdateWorldSettings() /* ------------------------------------------------------------------------- * Python functions * ------------------------------------------------------------------------- */ -PyObject *KX_WorldInfo::py_repr(void) -{ - return PyUnicode_From_STR_String(GetName()); -} /* ------------------------------------------------------------------------- * Python Integration Hooks * ------------------------------------------------------------------------- */ PyTypeObject KX_WorldInfo::Type = { - PyVarObject_HEAD_INIT(NULL, 0) + PyVarObject_HEAD_INIT(nullptr, 0) "KX_WorldInfo", - sizeof(PyObjectPlus_Proxy), + sizeof(EXP_PyObjectPlus_Proxy), 0, py_base_dealloc, 0, @@ -216,34 +248,41 @@ PyTypeObject KX_WorldInfo::Type = { 0, 0, py_base_repr, - 0,0,0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - 0,0,0,0,0,0,0, + 0, 0, 0, 0, 0, 0, 0, Methods, 0, 0, - &PyObjectPlus::Type, - 0,0,0,0,0,0, + &EXP_PyObjectPlus::Type, + 0, 0, 0, 0, 0, 0, py_base_new }; PyMethodDef KX_WorldInfo::Methods[] = { - {NULL,NULL} /* Sentinel */ + {nullptr, nullptr} /* Sentinel */ }; PyAttributeDef KX_WorldInfo::Attributes[] = { - KX_PYATTRIBUTE_BOOL_RW("mistEnable", KX_WorldInfo, m_hasmist), - KX_PYATTRIBUTE_FLOAT_RW("mistStart", 0.0f, 10000.0f, KX_WorldInfo, m_miststart), - KX_PYATTRIBUTE_FLOAT_RW("mistDistance", 0.001f, 10000.0f, KX_WorldInfo, m_mistdistance), - KX_PYATTRIBUTE_FLOAT_RW("mistIntensity", 0.0f, 1.0f, KX_WorldInfo, m_mistintensity), - KX_PYATTRIBUTE_SHORT_RW("mistType", 0, 2, true, KX_WorldInfo, m_misttype), - KX_PYATTRIBUTE_RO_FUNCTION("KX_MIST_QUADRATIC", KX_WorldInfo, pyattr_get_mist_typeconst), - KX_PYATTRIBUTE_RO_FUNCTION("KX_MIST_LINEAR", KX_WorldInfo, pyattr_get_mist_typeconst), - KX_PYATTRIBUTE_RO_FUNCTION("KX_MIST_INV_QUADRATIC", KX_WorldInfo, pyattr_get_mist_typeconst), - KX_PYATTRIBUTE_RW_FUNCTION("mistColor", KX_WorldInfo, pyattr_get_mist_color, pyattr_set_mist_color), - KX_PYATTRIBUTE_RW_FUNCTION("backgroundColor", KX_WorldInfo, pyattr_get_back_color, pyattr_set_back_color), - KX_PYATTRIBUTE_RW_FUNCTION("ambientColor", KX_WorldInfo, pyattr_get_ambient_color, pyattr_set_ambient_color), - { NULL } /* Sentinel */ + EXP_PYATTRIBUTE_BOOL_RW("mistEnable", KX_WorldInfo, m_hasmist), + EXP_PYATTRIBUTE_FLOAT_RW("mistStart", 0.0f, 10000.0f, KX_WorldInfo, m_miststart), + EXP_PYATTRIBUTE_FLOAT_RW("mistDistance", 0.001f, 10000.0f, KX_WorldInfo, m_mistdistance), + EXP_PYATTRIBUTE_FLOAT_RW("mistIntensity", 0.0f, 1.0f, KX_WorldInfo, m_mistintensity), + EXP_PYATTRIBUTE_SHORT_RW("mistType", 0, 2, true, KX_WorldInfo, m_misttype), + EXP_PYATTRIBUTE_RO_FUNCTION("KX_MIST_QUADRATIC", KX_WorldInfo, pyattr_get_mist_typeconst), + EXP_PYATTRIBUTE_RO_FUNCTION("KX_MIST_LINEAR", KX_WorldInfo, pyattr_get_mist_typeconst), + EXP_PYATTRIBUTE_RO_FUNCTION("KX_MIST_INV_QUADRATIC", KX_WorldInfo, pyattr_get_mist_typeconst), + EXP_PYATTRIBUTE_RW_FUNCTION("mistColor", KX_WorldInfo, pyattr_get_mist_color, pyattr_set_mist_color), + EXP_PYATTRIBUTE_RW_FUNCTION("horizonColor", KX_WorldInfo, pyattr_get_horizon_color, pyattr_set_horizon_color), + EXP_PYATTRIBUTE_RW_FUNCTION("backgroundColor", KX_WorldInfo, pyattr_get_background_color, pyattr_set_background_color), + EXP_PYATTRIBUTE_RW_FUNCTION("zenithColor", KX_WorldInfo, pyattr_get_zenith_color, pyattr_set_zenith_color), + EXP_PYATTRIBUTE_RW_FUNCTION("ambientColor", KX_WorldInfo, pyattr_get_ambient_color, pyattr_set_ambient_color), + EXP_PYATTRIBUTE_FLOAT_RW("exposure", 0.0f, 1.0f, KX_WorldInfo, m_exposure), + EXP_PYATTRIBUTE_FLOAT_RW("range", 0.2f, 5.0f, KX_WorldInfo, m_range), + EXP_PYATTRIBUTE_FLOAT_RW("envLightEnergy", 0.0f, FLT_MAX, KX_WorldInfo, m_envLightEnergy), + EXP_PYATTRIBUTE_BOOL_RO("envLightEnabled", KX_WorldInfo, m_hasEnvLight), + EXP_PYATTRIBUTE_SHORT_RO("envLightColor", KX_WorldInfo, m_envLightColor), + EXP_PYATTRIBUTE_NULL /* Sentinel */ }; /* Attribute get/set functions */ @@ -254,123 +293,182 @@ PyAttributeDef KX_WorldInfo::Attributes[] = { /* subtype */ #define MATHUTILS_COL_CB_MIST_COLOR 1 -#define MATHUTILS_COL_CB_BACK_COLOR 2 -#define MATHUTILS_COL_CB_AMBIENT_COLOR 3 +#define MATHUTILS_COL_CB_HOR_COLOR 2 +#define MATHUTILS_COL_CB_BACK_COLOR 3 +#define MATHUTILS_COL_CB_AMBIENT_COLOR 4 +#define MATHUTILS_COL_CB_ZEN_COLOR 5 static unsigned char mathutils_world_color_cb_index = -1; /* index for our callbacks */ static int mathutils_world_generic_check(BaseMathObject *bmo) { - KX_WorldInfo *self = static_castBGE_PROXY_REF(bmo->cb_user); - if (self == NULL) + KX_WorldInfo *self = static_castEXP_PROXY_REF(bmo->cb_user); + if (self == nullptr) { return -1; + } return 0; } static int mathutils_world_color_get(BaseMathObject *bmo, int subtype) { - KX_WorldInfo *self = static_castBGE_PROXY_REF(bmo->cb_user); - if (self == NULL) + KX_WorldInfo *self = static_castEXP_PROXY_REF(bmo->cb_user); + if (self == nullptr) { return -1; + } switch (subtype) { case MATHUTILS_COL_CB_MIST_COLOR: - copy_v3_v3(bmo->data, self->m_mistcolor); + { + self->m_mistcolor.Pack(bmo->data); break; + } + case MATHUTILS_COL_CB_HOR_COLOR: case MATHUTILS_COL_CB_BACK_COLOR: - copy_v3_v3(bmo->data, self->m_backgroundcolor); + { + self->m_horizoncolor.Pack(bmo->data); + break; + } + case MATHUTILS_COL_CB_ZEN_COLOR: + { + self->m_zenithcolor.Pack(bmo->data); break; + } case MATHUTILS_COL_CB_AMBIENT_COLOR: - copy_v3_v3(bmo->data, self->m_ambientcolor); + { + self->m_ambientcolor.Pack(bmo->data); break; - default: - return -1; + } + default: + return -1; } return 0; } static int mathutils_world_color_set(BaseMathObject *bmo, int subtype) { - KX_WorldInfo *self = static_castBGE_PROXY_REF(bmo->cb_user); + KX_WorldInfo *self = static_castEXP_PROXY_REF(bmo->cb_user); - if (self == NULL) + if (self == nullptr) { return -1; + } switch (subtype) { case MATHUTILS_COL_CB_MIST_COLOR: - self->setMistColor(bmo->data[0], bmo->data[1], bmo->data[2]); + { + self->setMistColor(mt::vec3(bmo->data)); + break; + } + case MATHUTILS_COL_CB_HOR_COLOR: + { + self->setHorizonColor(mt::vec4(bmo->data)); break; + } case MATHUTILS_COL_CB_BACK_COLOR: - self->setBackColor(bmo->data[0], bmo->data[1], bmo->data[2]); + { + self->setHorizonColor(mt::vec4(bmo->data[0], bmo->data[1], bmo->data[2], 1.0f)); break; + } + case MATHUTILS_COL_CB_ZEN_COLOR: + { + self->setZenithColor(mt::vec4(bmo->data)); + break; + } case MATHUTILS_COL_CB_AMBIENT_COLOR: - self->setAmbientColor(bmo->data[0], bmo->data[1], bmo->data[2]); + { + self->setAmbientColor(mt::vec3(bmo->data)); break; - default: - return -1; + } + default: + return -1; } return 0; } static int mathutils_world_color_get_index(BaseMathObject *bmo, int subtype, int index) { - KX_WorldInfo *self = static_castBGE_PROXY_REF(bmo->cb_user); + KX_WorldInfo *self = static_castEXP_PROXY_REF(bmo->cb_user); - if (self == NULL) + if (self == nullptr) { return -1; + } switch (subtype) { case MATHUTILS_COL_CB_MIST_COLOR: { - const float *color = self->m_mistcolor; - bmo->data[index] = color[index]; + bmo->data[index] = self->m_mistcolor[index]; + break; } - break; + case MATHUTILS_COL_CB_HOR_COLOR: case MATHUTILS_COL_CB_BACK_COLOR: { - const float *color = self->m_backgroundcolor; - bmo->data[index] = color[index]; + bmo->data[index] = self->m_horizoncolor[index]; + break; } + case MATHUTILS_COL_CB_ZEN_COLOR: + { + bmo->data[index] = self->m_zenithcolor[index]; break; + } case MATHUTILS_COL_CB_AMBIENT_COLOR: { - const float *color = self->m_ambientcolor; - bmo->data[index] = color[index]; + bmo->data[index] = self->m_ambientcolor[index]; + break; } - break; - default: - return -1; + default: + return -1; } return 0; } static int mathutils_world_color_set_index(BaseMathObject *bmo, int subtype, int index) { - KX_WorldInfo *self = static_castBGE_PROXY_REF(bmo->cb_user); + KX_WorldInfo *self = static_castEXP_PROXY_REF(bmo->cb_user); - if (self == NULL) + if (self == nullptr) { return -1; + } - float color[4]; switch (subtype) { case MATHUTILS_COL_CB_MIST_COLOR: - copy_v3_v3(color, self->m_mistcolor); + { + mt::vec3 color = self->m_mistcolor; color[index] = bmo->data[index]; - self->setMistColor(color[0], color[1], color[2]); - break; + self->setMistColor(color); + break; + } + case MATHUTILS_COL_CB_HOR_COLOR: case MATHUTILS_COL_CB_BACK_COLOR: - copy_v3_v3(color, self->m_backgroundcolor); + { + mt::vec4 color = self->m_horizoncolor; + color[index] = bmo->data[index]; + CLAMP(color[0], 0.0f, 1.0f); + CLAMP(color[1], 0.0f, 1.0f); + CLAMP(color[2], 0.0f, 1.0f); + CLAMP(color[3], 0.0f, 1.0f); + self->setHorizonColor(color); + break; + } + case MATHUTILS_COL_CB_ZEN_COLOR: + { + mt::vec4 color = self->m_zenithcolor; color[index] = bmo->data[index]; - self->setBackColor(color[0], color[1], color[2]); - break; + CLAMP(color[0], 0.0f, 1.0f); + CLAMP(color[1], 0.0f, 1.0f); + CLAMP(color[2], 0.0f, 1.0f); + CLAMP(color[3], 0.0f, 1.0f); + self->setZenithColor(color); + break; + } case MATHUTILS_COL_CB_AMBIENT_COLOR: - copy_v3_v3(color, self->m_ambientcolor); + { + mt::vec3 color = self->m_ambientcolor; color[index] = bmo->data[index]; - self->setAmbientColor(color[0], color[1], color[2]); + self->setAmbientColor(color); break; - default: - return -1; + } + default: + return -1; } return 0; } @@ -390,102 +488,147 @@ void KX_WorldInfo_Mathutils_Callback_Init() } #endif // USE_MATHUTILS - -PyObject *KX_WorldInfo::pyattr_get_mist_typeconst(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_WorldInfo::pyattr_get_mist_typeconst(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { PyObject *retvalue; - const char* type = attrdef->m_name; + const std::string& type = attrdef->m_name; - if (!strcmp(type, "KX_MIST_QUADRATIC")) { + if (type == "KX_MIST_QUADRATIC") { retvalue = PyLong_FromLong(KX_MIST_QUADRATIC); } - else if (!strcmp(type, "KX_MIST_LINEAR")) { + else if (type == "KX_MIST_LINEAR") { retvalue = PyLong_FromLong(KX_MIST_LINEAR); } - else if (!strcmp(type, "KX_MIST_INV_QUADRATIC")) { + else if (type == "KX_MIST_INV_QUADRATIC") { retvalue = PyLong_FromLong(KX_MIST_INV_QUADRATIC); } else { /* should never happen */ PyErr_SetString(PyExc_TypeError, "invalid mist type"); - retvalue = NULL; + retvalue = nullptr; } return retvalue; } -PyObject *KX_WorldInfo::pyattr_get_mist_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_WorldInfo::pyattr_get_mist_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS return Color_CreatePyObject_cb( - BGE_PROXY_FROM_REF_BORROW(self_v), - mathutils_world_color_cb_index, MATHUTILS_COL_CB_MIST_COLOR); + EXP_PROXY_FROM_REF_BORROW(self_v), + mathutils_world_color_cb_index, MATHUTILS_COL_CB_MIST_COLOR); #else - KX_WorldInfo *self = static_cast(self_v); - return PyObjectFrom(MT_Vector3(self->m_mistcolor)); + KX_WorldInfo *self = static_cast(self_v); + return PyObjectFrom(self->m_mistcolor); #endif } -int KX_WorldInfo::pyattr_set_mist_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_WorldInfo::pyattr_set_mist_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_WorldInfo *self = static_cast(self_v); + KX_WorldInfo *self = static_cast(self_v); - MT_Vector3 color; - if (PyVecTo(value, color)) - { - self->setMistColor(color[0], color[1], color[2]); + mt::vec3 color; + if (PyVecTo(value, color)) { + self->setMistColor(color); return PY_SET_ATTR_SUCCESS; } return PY_SET_ATTR_FAIL; } -PyObject *KX_WorldInfo::pyattr_get_back_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_WorldInfo::pyattr_get_horizon_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { +#ifdef USE_MATHUTILS + return Vector_CreatePyObject_cb( + EXP_PROXY_FROM_REF_BORROW(self_v), 4, + mathutils_world_color_cb_index, MATHUTILS_COL_CB_HOR_COLOR); +#else + KX_WorldInfo *self = static_cast(self_v); + return PyObjectFrom(self->m_horizoncolor); +#endif +} + +int KX_WorldInfo::pyattr_set_horizon_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_WorldInfo *self = static_cast(self_v); + + mt::vec4 color; + if (PyVecTo(value, color)) { + self->setHorizonColor(color); + return PY_SET_ATTR_SUCCESS; + } + return PY_SET_ATTR_FAIL; +} + +PyObject *KX_WorldInfo::pyattr_get_background_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ #ifdef USE_MATHUTILS return Color_CreatePyObject_cb( - BGE_PROXY_FROM_REF_BORROW(self_v), - mathutils_world_color_cb_index, MATHUTILS_COL_CB_BACK_COLOR); + EXP_PROXY_FROM_REF_BORROW(self_v), + mathutils_world_color_cb_index, MATHUTILS_COL_CB_BACK_COLOR); +#else + KX_WorldInfo *self = static_cast(self_v); + return PyObjectFrom(self->m_horizoncolor.xyz()); +#endif +} + +int KX_WorldInfo::pyattr_set_background_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) +{ + KX_WorldInfo *self = static_cast(self_v); + + mt::vec3 color; + if (PyVecTo(value, color)) { + self->setHorizonColor(mt::vec4(color[0], color[1], color[2], 1.0f)); + return PY_SET_ATTR_SUCCESS; + } + return PY_SET_ATTR_FAIL; +} + +PyObject *KX_WorldInfo::pyattr_get_zenith_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) +{ + +#ifdef USE_MATHUTILS + return Vector_CreatePyObject_cb( + EXP_PROXY_FROM_REF_BORROW(self_v), 4, + mathutils_world_color_cb_index, MATHUTILS_COL_CB_ZEN_COLOR); #else - KX_WorldInfo *self = static_cast(self_v); - return PyObjectFrom(MT_Vector3(self->m_backgroundcolor)); + KX_WorldInfo *self = static_cast(self_v); + return PyObjectFrom(self->m_zenithcolor); #endif } -int KX_WorldInfo::pyattr_set_back_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_WorldInfo::pyattr_set_zenith_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_WorldInfo *self = static_cast(self_v); + KX_WorldInfo *self = static_cast(self_v); - MT_Vector3 color; - if (PyVecTo(value, color)) - { - self->setBackColor(color[0], color[1], color[2]); + mt::vec4 color; + if (PyVecTo(value, color)) { + self->setZenithColor(color); return PY_SET_ATTR_SUCCESS; } return PY_SET_ATTR_FAIL; } -PyObject *KX_WorldInfo::pyattr_get_ambient_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) +PyObject *KX_WorldInfo::pyattr_get_ambient_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef) { #ifdef USE_MATHUTILS return Color_CreatePyObject_cb( - BGE_PROXY_FROM_REF_BORROW(self_v), - mathutils_world_color_cb_index, MATHUTILS_COL_CB_AMBIENT_COLOR); + EXP_PROXY_FROM_REF_BORROW(self_v), + mathutils_world_color_cb_index, MATHUTILS_COL_CB_AMBIENT_COLOR); #else - KX_WorldInfo *self = static_cast(self_v); - return PyObjectFrom(MT_Vector3(self->m_ambientcolor)); + KX_WorldInfo *self = static_cast(self_v); + return PyObjectFrom(self->m_ambientcolor); #endif } -int KX_WorldInfo::pyattr_set_ambient_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) +int KX_WorldInfo::pyattr_set_ambient_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value) { - KX_WorldInfo *self = static_cast(self_v); + KX_WorldInfo *self = static_cast(self_v); - MT_Vector3 color; - if (PyVecTo(value, color)) - { - self->setAmbientColor(color[0], color[1], color[2]); + mt::vec3 color; + if (PyVecTo(value, color)) { + self->setAmbientColor(color); return PY_SET_ATTR_SUCCESS; } return PY_SET_ATTR_FAIL; diff --git a/source/gameengine/Ketsji/KX_WorldInfo.h b/source/gameengine/Ketsji/KX_WorldInfo.h index b155faf28372..7f58b22c34e0 100644 --- a/source/gameengine/Ketsji/KX_WorldInfo.h +++ b/source/gameengine/Ketsji/KX_WorldInfo.h @@ -32,35 +32,45 @@ #ifndef __KX_WORLDINFO_H__ #define __KX_WORLDINFO_H__ -#include "MT_Scalar.h" -#include "KX_KetsjiEngine.h" -#include "EXP_PyObjectPlus.h" +#include "mathfu.h" +#include "EXP_Value.h" #ifdef USE_MATHUTILS void KX_WorldInfo_Mathutils_Callback_Init(void); #endif +class RAS_Rasterizer; +struct GPUMaterial; struct Scene; struct World; -class KX_WorldInfo : public PyObjectPlus +class KX_WorldInfo : public EXP_Value, public mt::SimdClassAllocator { Py_Header - STR_String m_name; - bool m_do_color_management; + std::string m_name; + Scene *m_scene; + GPUMaterial *m_gpuMat; bool m_hasworld; bool m_hasmist; + bool m_hasEnvLight; short m_misttype; + short m_envLightColor; float m_miststart; float m_mistdistance; float m_mistintensity; - float m_mistcolor[3]; - float m_backgroundcolor[3]; - float m_ambientcolor[3]; - float m_con_mistcolor[3]; - float m_con_backgroundcolor[3]; - float m_con_ambientcolor[3]; + float m_range; + float m_exposure; + float m_envLightEnergy; + mt::vec3 m_mistcolor; + mt::vec4 m_horizoncolor; + mt::vec4 m_zenithcolor; + mt::vec3 m_ambientcolor; + + struct { + mt::vec3 horizonColor; + mt::vec3 zenithColor; + } m_savedData; public: /** @@ -75,30 +85,36 @@ class KX_WorldInfo : public PyObjectPlus KX_WorldInfo(Scene *blenderscene, World *blenderworld); ~KX_WorldInfo(); - const STR_String &GetName(); + virtual std::string GetName(); + + void ReloadMaterial(); bool hasWorld(); - void setUseMist(bool enable); - void setMistType(short type); void setMistStart(float d); void setMistDistance(float d); void setMistIntensity(float intensity); - void setMistColor(float r, float g, float b); - void setBackColor(float r, float g, float b); - const float *getBackColorConverted() const; - void setAmbientColor(float r, float g, float b); - void UpdateBackGround(); - void UpdateWorldSettings(); + void setExposure(float exposure); + void setRange(float range); + void setMistColor(const mt::vec3& mistcolor); + void setHorizonColor(const mt::vec4& horizoncolor); + void setZenithColor(const mt::vec4& zenithcolor); + void setAmbientColor(const mt::vec3& ambientcolor); + void UpdateBackGround(RAS_Rasterizer *rasty); + void UpdateWorldSettings(RAS_Rasterizer *rasty); + void RenderBackground(RAS_Rasterizer *rasty); #ifdef WITH_PYTHON /* attributes */ - static PyObject *pyattr_get_mist_typeconst(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static PyObject *pyattr_get_mist_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_mist_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject *pyattr_get_back_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_back_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - static PyObject *pyattr_get_ambient_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef); - static int pyattr_set_ambient_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value); - virtual PyObject *py_repr(void); + static PyObject *pyattr_get_mist_typeconst(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static PyObject *pyattr_get_mist_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_mist_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_horizon_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_horizon_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_background_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_background_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_zenith_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_zenith_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); + static PyObject *pyattr_get_ambient_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef); + static int pyattr_set_ambient_color(EXP_PyObjectPlus *self_v, const EXP_PYATTRIBUTE_DEF *attrdef, PyObject *value); #endif }; diff --git a/source/gameengine/Ketsji/KX_WorldIpoController.cpp b/source/gameengine/Ketsji/KX_WorldIpoController.cpp index ea7e78455d3d..9ccecf03d348 100644 --- a/source/gameengine/Ketsji/KX_WorldIpoController.cpp +++ b/source/gameengine/Ketsji/KX_WorldIpoController.cpp @@ -31,95 +31,42 @@ #include "KX_WorldIpoController.h" -#include "KX_ScalarInterpolator.h" #include "KX_WorldInfo.h" -#include "KX_PythonInit.h" +#include "KX_Globals.h" #include "KX_Scene.h" -#if defined(_WIN64) -typedef unsigned __int64 uint_ptr; -#else -typedef unsigned long uint_ptr; -#endif - -bool KX_WorldIpoController::Update(double currentTime) +bool KX_WorldIpoController::Update(SG_Node *node) { - if (m_modified) { - T_InterpolatorList::iterator i; - for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) { - (*i)->Execute(m_ipotime); - } - - KX_WorldInfo *world = KX_GetActiveScene()->GetWorldInfo(); - - if (m_modify_mist_start) { - world->setMistStart(m_mist_start); - } - - if (m_modify_mist_dist) { - world->setMistDistance(m_mist_dist); - } - - if (m_modify_mist_intensity) { - world->setMistIntensity(m_mist_intensity); - } - - if (m_modify_horizon_color) { - world->setBackColor(m_hori_rgb[0], m_hori_rgb[1], m_hori_rgb[2]); - world->setMistColor(m_hori_rgb[0], m_hori_rgb[1], m_hori_rgb[2]); - } - - if (m_modify_ambient_color) { - world->setAmbientColor(m_ambi_rgb[0], m_ambi_rgb[1], m_ambi_rgb[2]); - } - - m_modified = false; + if (!SG_Controller::Update(node)) { + return false; } - return false; -} - - -void KX_WorldIpoController::AddInterpolator(KX_IInterpolator* interp) -{ - this->m_interpolators.push_back(interp); -} - -SG_Controller* KX_WorldIpoController::GetReplica(class SG_Node* destnode) -{ - KX_WorldIpoController* iporeplica = new KX_WorldIpoController(*this); - // clear object that ipo acts on - iporeplica->ClearObject(); - - // dirty hack, ask Gino for a better solution in the ipo implementation - // hacken en zagen, in what we call datahiding, not written for replication :( + KX_WorldInfo *world = KX_GetActiveScene()->GetWorldInfo(); - T_InterpolatorList oldlist = m_interpolators; - iporeplica->m_interpolators.clear(); + if (m_modify_mist_start) { + world->setMistStart(m_mist_start); + } - T_InterpolatorList::iterator i; - for (i = oldlist.begin(); !(i == oldlist.end()); ++i) { - KX_ScalarInterpolator* copyipo = new KX_ScalarInterpolator(*((KX_ScalarInterpolator*)*i)); - iporeplica->AddInterpolator(copyipo); + if (m_modify_mist_dist) { + world->setMistDistance(m_mist_dist); + } - MT_Scalar* scaal = ((KX_ScalarInterpolator*)*i)->GetTarget(); - uint_ptr orgbase = (uint_ptr)this; - uint_ptr orgloc = (uint_ptr)scaal; - uint_ptr offset = orgloc-orgbase; - uint_ptr newaddrbase = (uint_ptr)iporeplica + offset; - MT_Scalar* blaptr = (MT_Scalar*) newaddrbase; - copyipo->SetNewTarget((MT_Scalar*)blaptr); + if (m_modify_mist_intensity) { + world->setMistIntensity(m_mist_intensity); } - return iporeplica; -} + if (m_modify_horizon_color) { + world->setHorizonColor(mt::vec4(m_hori_rgb[0], m_hori_rgb[1], m_hori_rgb[2], 1.0f)); + world->setMistColor(m_hori_rgb); + } -KX_WorldIpoController::~KX_WorldIpoController() -{ + if (m_modify_zenith_color) { + world->setZenithColor(mt::vec4(m_zeni_rgb[0], m_zeni_rgb[1], m_zeni_rgb[2], 1.0f)); + } - T_InterpolatorList::iterator i; - for (i = m_interpolators.begin(); !(i == m_interpolators.end()); ++i) { - delete (*i); + if (m_modify_ambient_color) { + world->setAmbientColor(m_ambi_rgb); } + return true; } diff --git a/source/gameengine/Ketsji/KX_WorldIpoController.h b/source/gameengine/Ketsji/KX_WorldIpoController.h index 0e4b408323de..3ac06de260f7 100644 --- a/source/gameengine/Ketsji/KX_WorldIpoController.h +++ b/source/gameengine/Ketsji/KX_WorldIpoController.h @@ -33,50 +33,40 @@ #define __KX_WORLDIPOCONTROLLER_H__ #include "SG_Controller.h" -#include "SG_Spatial.h" -#include "KX_IInterpolator.h" +#include "SG_Node.h" +#include "SG_Interpolator.h" -class KX_WorldIpoController : public SG_Controller +class KX_WorldIpoController : public SG_Controller, public mt::SimdClassAllocator { public: - MT_Scalar m_mist_start; - MT_Scalar m_mist_dist; - MT_Scalar m_mist_intensity; - MT_Scalar m_hori_rgb[3]; - MT_Scalar m_ambi_rgb[3]; + float m_mist_start; + float m_mist_dist; + float m_mist_intensity; + mt::vec3 m_hori_rgb; + mt::vec3 m_zeni_rgb; + mt::vec3 m_ambi_rgb; private: - T_InterpolatorList m_interpolators; unsigned short m_modify_mist_start : 1; unsigned short m_modify_mist_dist : 1; unsigned short m_modify_mist_intensity : 1; unsigned short m_modify_horizon_color : 1; + unsigned short m_modify_zenith_color : 1; unsigned short m_modify_ambient_color : 1; - bool m_modified; - - double m_ipotime; public: - KX_WorldIpoController() : + KX_WorldIpoController() : m_modify_mist_start(false), m_modify_mist_dist(false), m_modify_mist_intensity(false), m_modify_horizon_color(false), - m_modify_ambient_color(false), - m_modified(true), - m_ipotime(0.0) + m_modify_zenith_color(false), + m_modify_ambient_color(false) {} - virtual ~KX_WorldIpoController(); - - virtual SG_Controller* GetReplica(class SG_Node* destnode); + virtual ~KX_WorldIpoController() = default; - virtual bool Update(double time); - - virtual void SetSimulatedTime(double time) { - m_ipotime = time; - m_modified = true; - } + virtual bool Update(SG_Node *node); void SetModifyMistStart(bool modify) { m_modify_mist_start = modify; @@ -94,24 +84,13 @@ class KX_WorldIpoController : public SG_Controller m_modify_horizon_color = modify; } + void SetModifyZenithColor(bool modify) { + m_modify_zenith_color = modify; + } + void SetModifyAmbientColor(bool modify) { m_modify_ambient_color = modify; } - - void - SetOption( - int option, - int value - ) { - // intentionally empty - }; - - void AddInterpolator(KX_IInterpolator* interp); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_WorldIpoController") -#endif }; #endif /* __KX_WORLDIPOCONTROLLER_H__ */ diff --git a/source/gameengine/Launcher/CMakeLists.txt b/source/gameengine/Launcher/CMakeLists.txt new file mode 100644 index 000000000000..6d6b94f1d653 --- /dev/null +++ b/source/gameengine/Launcher/CMakeLists.txt @@ -0,0 +1,83 @@ +# ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The Original Code is Copyright (C) 2006, Blender Foundation +# All rights reserved. +# +# The Original Code is: all of this file. +# +# Contributor(s): Tristan Porteries. +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + ../BlenderRoutines + ../Common + ../Converter + ../Device + ../Expressions + ../GameLogic + ../GamePlayer + ../Ketsji + ../Ketsji/KXNetwork + ../Rasterizer + ../Rasterizer/Node + ../SceneGraph + ../VideoTexture + ../../blender/blenkernel + ../../blender/blenlib + ../../blender/gpu + ../../blender/makesdna + ../../blender/makesrna + ../../blender/windowmanager + ../../../intern/guardedalloc + ../../../intern/ghost + ../../../intern/string + ../../../intern/termcolor +) + +set(INC_SYS + ../../../intern/debugbreak + ../../../intern/mathfu + ${BOOST_INCLUDE_DIR} +) + +set(SRC + LA_BlenderLauncher.cpp + LA_Launcher.cpp + LA_PlayerLauncher.cpp + LA_SystemCommandLine.cpp + + LA_BlenderLauncher.h + LA_Launcher.h + LA_PlayerLauncher.h + LA_SystemCommandLine.h +) + +if(WITH_GAMEENGINE_SECURITY) + add_definitions(-DWITH_GAMEENGINE_SECURITY) +endif() + +if(WITH_AUDASPACE) + add_definitions(${AUDASPACE_DEFINITIONS}) + + list(APPEND INC_SYS + ${AUDASPACE_C_INCLUDE_DIRS} + ) +endif() + +blender_add_lib(ge_launcher "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/gameengine/Launcher/LA_BlenderLauncher.cpp b/source/gameengine/Launcher/LA_BlenderLauncher.cpp new file mode 100644 index 000000000000..e713a95759ec --- /dev/null +++ b/source/gameengine/Launcher/LA_BlenderLauncher.cpp @@ -0,0 +1,181 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Launcher/LA_BlenderLauncher.cpp + * \ingroup launcher + */ + +#include "LA_BlenderLauncher.h" + +#include "KX_BlenderCanvas.h" + +#include "KX_PythonInit.h" + +extern "C" { +# include "BKE_context.h" + +// avoid c++ conflict with 'new' +# define new _new +# include "BKE_screen.h" +# undef new + +# include "DNA_scene_types.h" +# include "DNA_screen_types.h" +# include "DNA_object_types.h" +# include "DNA_view3d_types.h" + +# include "WM_types.h" +# include "WM_api.h" +# include "wm_event_system.h" +# include "wm_window.h" + +# include "BLI_rect.h" +} + +LA_BlenderLauncher::LA_BlenderLauncher(GHOST_ISystem *system, Main *maggie, Scene *scene, GlobalSettings *gs, RAS_Rasterizer::StereoMode stereoMode, + int argc, char **argv, bContext *context, rcti *camframe, ARegion *ar, int alwaysUseExpandFraming) + :LA_Launcher(system, maggie, scene, gs, stereoMode, scene->gm.aasamples, alwaysUseExpandFraming, argc, argv), + m_context(context), + m_ar(ar), + m_camFrame(camframe), + m_drawLetterBox(false) +{ + m_windowManager = CTX_wm_manager(m_context); + m_window = CTX_wm_window(m_context); + m_view3d = CTX_wm_view3d(m_context); + + m_areaRect.SetLeft(m_camFrame->xmin); + m_areaRect.SetBottom(m_camFrame->ymin); + m_areaRect.SetRight(m_camFrame->xmax); + m_areaRect.SetTop(m_camFrame->ymax); +} + +LA_BlenderLauncher::~LA_BlenderLauncher() +{ +} + +RAS_ICanvas *LA_BlenderLauncher::CreateCanvas(RAS_Rasterizer *rasty) +{ + return (new KX_BlenderCanvas(rasty, m_windowManager, m_window, m_areaRect)); +} + +RAS_Rasterizer::DrawType LA_BlenderLauncher::GetRasterizerDrawMode() +{ + View3D *v3d = CTX_wm_view3d(m_context); + + RAS_Rasterizer::DrawType drawmode = RAS_Rasterizer::RAS_TEXTURED; + switch (v3d->drawtype) { + case OB_BOUNDBOX: + case OB_WIRE: + { + drawmode = RAS_Rasterizer::RAS_WIREFRAME; + break; + } + case OB_MATERIAL: + { + drawmode = RAS_Rasterizer::RAS_TEXTURED; + break; + } + } + return drawmode; +} + +void LA_BlenderLauncher::InitCamera() +{ + RegionView3D *rv3d = CTX_wm_region_view3d(m_context); + if (rv3d->persp == RV3D_CAMOB) { + if (m_startScene->gm.framing.type == SCE_GAMEFRAMING_BARS) { /* Letterbox */ + m_drawLetterBox = true; + } + else { + m_camZoom = 1.0f / BKE_screen_view3d_zoom_to_fac(rv3d->camzoom); + } + } + + if (rv3d->persp != RV3D_CAMOB) { + RAS_CameraData camdata = RAS_CameraData(); + camdata.m_lens = m_view3d->lens; + camdata.m_clipstart = m_view3d->near; + camdata.m_clipend = m_view3d->far; + camdata.m_perspective = (rv3d->persp != RV3D_ORTHO); + camdata.m_zoom = 2.0f; + + m_ketsjiEngine->EnableCameraOverride(m_startSceneName, mt::mat4(rv3d->winmat), mt::mat4(rv3d->viewmat), camdata); + } +} + +void LA_BlenderLauncher::SetWindowOrder(short order) +{ + wm_window_set_order(m_window, order); +} + +void LA_BlenderLauncher::InitEngine() +{ + // Lock frame and camera enabled - storing global values. + m_savedBlenderData.sceneLayer = m_startScene->lay; + m_savedBlenderData.camera = m_startScene->camera; + + if (m_view3d->scenelock == 0) { + m_startScene->lay = m_view3d->lay; + m_startScene->camera = m_view3d->camera; + } + + LA_Launcher::InitEngine(); +} + +void LA_BlenderLauncher::ExitEngine() +{ + LA_Launcher::ExitEngine(); + + // Lock frame and camera enabled - restoring global values. + if (m_view3d->scenelock == 0) { + m_startScene->lay = m_savedBlenderData.sceneLayer; + m_startScene->camera = m_savedBlenderData.camera; + } + + // Free all window manager events unused. + wm_event_free_all(m_window); +} + +void LA_BlenderLauncher::RenderEngine() +{ + if (m_drawLetterBox) { + // Clear screen to border color + // We do this here since we set the canvas to be within the frames. This means the engine + // itself is unaware of the extra space, so we clear the whole region for it. + m_rasterizer->SetClearColor(m_startScene->gm.framing.col[0], m_startScene->gm.framing.col[1], m_startScene->gm.framing.col[2]); + m_rasterizer->SetViewport(m_ar->winrct.xmin, m_ar->winrct.ymin, + BLI_rcti_size_x(&m_ar->winrct) + 1, BLI_rcti_size_y(&m_ar->winrct) + 1); + m_rasterizer->SetScissor(m_ar->winrct.xmin, m_ar->winrct.ymin, + BLI_rcti_size_x(&m_ar->winrct) + 1, BLI_rcti_size_y(&m_ar->winrct) + 1); + m_rasterizer->Clear(RAS_Rasterizer::RAS_COLOR_BUFFER_BIT); + } + LA_Launcher::RenderEngine(); +} + +KX_ExitInfo LA_BlenderLauncher::EngineNextFrame() +{ + // Free all window manager events unused. + wm_event_free_all(m_window); + + return LA_Launcher::EngineNextFrame(); +} diff --git a/source/gameengine/Launcher/LA_BlenderLauncher.h b/source/gameengine/Launcher/LA_BlenderLauncher.h new file mode 100644 index 000000000000..05845969eb37 --- /dev/null +++ b/source/gameengine/Launcher/LA_BlenderLauncher.h @@ -0,0 +1,75 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file LA_BlenderLauncher.h + * \ingroup launcher + */ + +#include "LA_Launcher.h" + +#include "RAS_Rect.h" + +struct Object; +struct bContext; +struct ARegion; +struct View3D; +struct rcti; +struct wmWindowManager; +struct wmWindow; + +class LA_BlenderLauncher : public LA_Launcher +{ +protected: + bContext *m_context; + ARegion *m_ar; + rcti *m_camFrame; + View3D *m_view3d; + wmWindowManager *m_windowManager; + wmWindow *m_window; + int m_alwaysUseExpandFraming; + bool m_drawLetterBox; + RAS_Rect m_areaRect; + + /// Saved blender data to restore at the game end as m_savedData from LA_Launcher. + struct SavedBlenderData { + int sceneLayer; + Object *camera; + } m_savedBlenderData; + + virtual void RenderEngine(); + + virtual RAS_ICanvas *CreateCanvas(RAS_Rasterizer *rasty); + virtual RAS_Rasterizer::DrawType GetRasterizerDrawMode(); + virtual void InitCamera(); + + virtual void SetWindowOrder(short order); + +public: + LA_BlenderLauncher(GHOST_ISystem *system, Main *maggie, Scene *scene, GlobalSettings *gs, RAS_Rasterizer::StereoMode stereoMode, + int argc, char **argv, bContext *context, rcti *camframe, ARegion *ar, int alwaysUseExpandFraming); + virtual ~LA_BlenderLauncher(); + + virtual void InitEngine(); + virtual void ExitEngine(); + + virtual KX_ExitInfo EngineNextFrame(); +}; diff --git a/source/gameengine/Launcher/LA_Launcher.cpp b/source/gameengine/Launcher/LA_Launcher.cpp new file mode 100644 index 000000000000..7f1b2e4629a1 --- /dev/null +++ b/source/gameengine/Launcher/LA_Launcher.cpp @@ -0,0 +1,525 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Launcher/LA_Launcher.cpp + * \ingroup launcher + */ + +#ifdef WIN32 +# include +#endif + +#include "LA_Launcher.h" +#include "LA_SystemCommandLine.h" + +#include "RAS_ICanvas.h" + +#include "GPG_Canvas.h" + +#include "KX_KetsjiEngine.h" +#include "KX_Scene.h" +#include "KX_Globals.h" +#include "KX_PythonInit.h" +#include "KX_PythonMain.h" +#include "KX_PyConstraintBinding.h" + +#include "BL_Converter.h" +#include "BL_SceneConverter.h" +#include "BL_BlenderDataConversion.h" + +#include "KX_NetworkMessageManager.h" + +#ifdef WITH_PYTHON +# include "Texture.h" // For FreeAllTextures. +#endif // WITH_PYTHON + +#include "GHOST_ISystem.h" +#include "GHOST_IWindow.h" + +#include "DEV_EventConsumer.h" +#include "DEV_InputDevice.h" + +#include "DEV_Joystick.h" + +#include "CM_Message.h" + +extern "C" { +# include "GPU_extensions.h" + +# include "BKE_sound.h" +# include "BKE_main.h" + +# include "DNA_scene_types.h" +# include "DNA_material_types.h" + +# include "wm_event_types.h" +} + +#ifdef WITH_AUDASPACE +# include AUD_DEVICE_H +#endif + +#ifdef WITH_PYTHON + +struct PythonMainLoopState +{ + KX_ExitInfo m_exitInfo; + LA_Launcher *m_launcher; +}; + +#endif + +LA_Launcher::LA_Launcher(GHOST_ISystem *system, Main *maggie, Scene *scene, GlobalSettings *gs, + RAS_Rasterizer::StereoMode stereoMode, int samples, bool alwaysUseExpandFraming, int argc, char **argv) + :m_startSceneName(scene->id.name + 2), + m_startScene(scene), + m_maggie(maggie), + m_kxStartScene(nullptr), + m_globalSettings(gs), + m_system(system), + m_ketsjiEngine(nullptr), + m_inputDevice(nullptr), + m_eventConsumer(nullptr), + m_canvas(nullptr), + m_rasterizer(nullptr), + m_converter(nullptr), +#ifdef WITH_PYTHON + m_globalDict(nullptr), +#endif // WITH_PYTHON + m_alwaysUseExpandFraming(alwaysUseExpandFraming), + m_camZoom(1.0f), + m_samples(samples), + m_stereoMode(stereoMode), + m_argc(argc), + m_argv(argv) +{ + m_pythonConsole.use = false; +} + +LA_Launcher::~LA_Launcher() +{ +} + +#ifdef WITH_PYTHON +void LA_Launcher::SetPythonGlobalDict(PyObject *globalDict) +{ + m_globalDict = globalDict; +} +#endif // WITH_PYTHON + +GlobalSettings *LA_Launcher::GetGlobalSettings() +{ + return m_ketsjiEngine->GetGlobalSettings(); +} + +void LA_Launcher::InitEngine() +{ + // Get and set the preferences. + SYS_SystemHandle syshandle = SYS_GetSystem(); + + const GameData& gm = m_startScene->gm; + bool properties = (SYS_GetCommandLineInt(syshandle, "show_properties", 0) != 0); + bool profile = (SYS_GetCommandLineInt(syshandle, "show_profile", 0) != 0); + + bool showPhysics = (gm.flag & GAME_SHOW_PHYSICS); + SYS_WriteCommandLineInt(syshandle, "show_physics", showPhysics); + + // WARNING: Fixed time is the opposite of fixed framerate. + bool fixed_framerate = (SYS_GetCommandLineInt(syshandle, "fixedtime", (gm.flag & GAME_ENABLE_ALL_FRAMES)) == 0); + bool frameRate = (SYS_GetCommandLineInt(syshandle, "show_framerate", 0) != 0); + bool renderQueries = (SYS_GetCommandLineInt(syshandle, "show_render_queries", 0) != 0); + short showBoundingBox = SYS_GetCommandLineInt(syshandle, "show_bounding_box", gm.showBoundingBox); + short showArmatures = SYS_GetCommandLineInt(syshandle, "show_armatures", gm.showArmatures); + short showCameraFrustum = SYS_GetCommandLineInt(syshandle, "show_camera_frustum", gm.showCameraFrustum); + short showShadowFrustum = SYS_GetCommandLineInt(syshandle, "show_shadow_frustum", gm.showShadowFrustum); + bool nodepwarnings = (SYS_GetCommandLineInt(syshandle, "ignore_deprecation_warnings", 1) != 0); + bool restrictAnimFPS = (gm.flag & GAME_RESTRICT_ANIM_UPDATES) != 0; + + const KX_KetsjiEngine::FlagType flags = (KX_KetsjiEngine::FlagType) + ((fixed_framerate ? KX_KetsjiEngine::FIXED_FRAMERATE : 0) | + (frameRate ? KX_KetsjiEngine::SHOW_FRAMERATE : 0) | + (renderQueries ? KX_KetsjiEngine::SHOW_RENDER_QUERIES : 0) | + (restrictAnimFPS ? KX_KetsjiEngine::RESTRICT_ANIMATION : 0) | + (properties ? KX_KetsjiEngine::SHOW_DEBUG_PROPERTIES : 0) | + (profile ? KX_KetsjiEngine::SHOW_PROFILE : 0)); + + // Setup python console keys used as shortcut. + for (unsigned short i = 0; i < 4; ++i) { + if (gm.pythonkeys[i] != EVENT_NONE) { + m_pythonConsole.keys.push_back(BL_ConvertKeyCode(gm.pythonkeys[i])); + } + } + m_pythonConsole.use = (gm.flag & GAME_PYTHON_CONSOLE); + + m_rasterizer = new RAS_Rasterizer(); + + // Stereo parameters - Eye Separation from the UI - stereomode from the command-line/UI + static const RAS_Rasterizer::ColorManagement colorManagementTable[] = { + RAS_Rasterizer::RAS_COLOR_MANAGEMENT_LINEAR, // GAME_COLOR_MANAGEMENT_LINEAR + RAS_Rasterizer::RAS_COLOR_MANAGEMENT_SRGB // GAME_COLOR_MANAGEMENT_SRGB + }; + m_rasterizer->SetColorManagment(colorManagementTable[gm.colorManagement]); + m_rasterizer->SetStereoMode(m_stereoMode); + m_rasterizer->SetEyeSeparation(m_startScene->gm.eyeseparation); + m_rasterizer->SetDrawingMode(GetRasterizerDrawMode()); + + // Copy current anisotropic level to restore it at the game end. + m_savedData.anisotropic = m_rasterizer->GetAnisotropicFiltering(); + // Copy current mipmap mode to restore at the game end. + m_savedData.mipmap = m_rasterizer->GetMipmapping(); + + // Create the canvas, rasterizer and rendertools. + m_canvas = CreateCanvas(m_rasterizer); + + static const RAS_ICanvas::SwapControl swapControlTable[] = { + RAS_ICanvas::VSYNC_ON, // VSYNC_ON + RAS_ICanvas::VSYNC_OFF, // VSYNC_OFF + RAS_ICanvas::VSYNC_ADAPTIVE // VSYNC_ADAPTIVE + }; + + m_canvas->SetSwapControl(swapControlTable[gm.vsync]); + + // Set canvas multisamples. + m_canvas->SetSamples(m_samples); + + RAS_Rasterizer::HdrType hdrtype = RAS_Rasterizer::RAS_HDR_NONE; + switch (gm.hdr) { + case GAME_HDR_NONE: + { + hdrtype = RAS_Rasterizer::RAS_HDR_NONE; + break; + } + case GAME_HDR_HALF_FLOAT: + { + hdrtype = RAS_Rasterizer::RAS_HDR_HALF_FLOAT; + break; + } + case GAME_HDR_FULL_FLOAT: + { + hdrtype = RAS_Rasterizer::RAS_HDR_FULL_FLOAT; + break; + } + } + m_canvas->SetHdrType(hdrtype); + + m_canvas->Init(); + if (gm.flag & GAME_SHOW_MOUSE) { + m_canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL); + } + else { + m_canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE); + } + + // Create the inputdevices. + m_inputDevice = new DEV_InputDevice(); + m_eventConsumer = new DEV_EventConsumer(m_system, m_inputDevice, m_canvas); + m_system->addEventConsumer(m_eventConsumer); + + m_networkMessageManager = new KX_NetworkMessageManager(); + + // Create the ketsjiengine. + m_ketsjiEngine = new KX_KetsjiEngine(); + KX_SetActiveEngine(m_ketsjiEngine); + + // Set the devices. + m_ketsjiEngine->SetInputDevice(m_inputDevice); + m_ketsjiEngine->SetCanvas(m_canvas); + m_ketsjiEngine->SetRasterizer(m_rasterizer); + m_ketsjiEngine->SetNetworkMessageManager(m_networkMessageManager); + + DEV_Joystick::Init(); + + m_ketsjiEngine->SetExitKey(BL_ConvertKeyCode(gm.exitkey)); +#ifdef WITH_PYTHON + EXP_Value::SetDeprecationWarnings(nodepwarnings); +#else + (void)nodepwarnings; +#endif + + m_ketsjiEngine->SetFlag(flags, true); + m_ketsjiEngine->SetRender(true); + m_ketsjiEngine->SetShowBoundingBox((KX_DebugOption)showBoundingBox); + m_ketsjiEngine->SetShowArmatures((KX_DebugOption)showArmatures); + m_ketsjiEngine->SetShowCameraFrustum((KX_DebugOption)showCameraFrustum); + m_ketsjiEngine->SetShowShadowFrustum((KX_DebugOption)showShadowFrustum); + + m_ketsjiEngine->SetTicRate(gm.ticrate); + m_ketsjiEngine->SetMaxLogicFrame(gm.maxlogicstep); + m_ketsjiEngine->SetMaxPhysicsFrame(gm.maxphystep); + m_ketsjiEngine->SetTimeScale(gm.timeScale); + + // Set the global settings (carried over if restart/load new files). + m_ketsjiEngine->SetGlobalSettings(m_globalSettings); + + InitCamera(); + +#ifdef WITH_PYTHON + KX_SetMainPath(std::string(m_maggie->name)); + // Some python things. + initGamePython(m_maggie, m_globalDict); +#endif // WITH_PYTHON + + // Create a scene converter, create and convert the stratingscene. + m_converter = new BL_Converter(m_maggie, m_ketsjiEngine, m_alwaysUseExpandFraming, m_camZoom); + m_ketsjiEngine->SetConverter(m_converter); + + m_kxStartScene = m_ketsjiEngine->CreateScene(m_startScene); + + KX_SetActiveScene(m_kxStartScene); + + +#ifdef WITH_AUDASPACE + // Initialize 3D Audio Settings. + AUD_Device *device = BKE_sound_get_device(); + AUD_Device_setSpeedOfSound(device, m_startScene->audio.speed_of_sound); + AUD_Device_setDopplerFactor(device, m_startScene->audio.doppler_factor); + AUD_Device_setDistanceModel(device, AUD_DistanceModel(m_startScene->audio.distance_model)); +#endif // WITH_AUDASPACE + + // Convert scene data. + m_converter->ConvertScene(m_kxStartScene); + + m_ketsjiEngine->AddScene(m_kxStartScene); + m_kxStartScene->Release(); + + m_rasterizer->Init(); + m_ketsjiEngine->StartEngine(); + + /* Set the animation playback rate for ipo's and actions the + * framerate below should patch with FPS macro defined in blendef.h + * Could be in StartEngine set the framerate, we need the scene to do this. + */ + Scene *scene = m_kxStartScene->GetBlenderScene(); // needed for macro + m_ketsjiEngine->SetAnimFrameRate(FPS); +} + + +void LA_Launcher::ExitEngine() +{ +#ifdef WITH_PYTHON + Texture::FreeAllTextures(nullptr); +#endif // WITH_PYTHON + + DEV_Joystick::Close(); + m_ketsjiEngine->StopEngine(); + + // Set anisotropic settign back to its original value. + m_rasterizer->SetAnisotropicFiltering(m_savedData.anisotropic); + // Set mipmap setting back to its original value. + m_rasterizer->SetMipmapping(m_savedData.mipmap); + + if (m_converter) { + delete m_converter; + m_converter = nullptr; + } + if (m_ketsjiEngine) { + delete m_ketsjiEngine; + m_ketsjiEngine = nullptr; + } + if (m_inputDevice) { + delete m_inputDevice; + m_inputDevice = nullptr; + } + if (m_eventConsumer) { + m_system->removeEventConsumer(m_eventConsumer); + delete m_eventConsumer; + } + if (m_rasterizer) { + delete m_rasterizer; + m_rasterizer = nullptr; + } + if (m_canvas) { + delete m_canvas; + m_canvas = nullptr; + } + if (m_networkMessageManager) { + delete m_networkMessageManager; + m_networkMessageManager = nullptr; + } + + // Call this after we're sure nothing needs Python anymore (e.g., destructors). + exitGamePython(); + +#ifdef WITH_AUDASPACE + // Stop all remaining playing sounds. + AUD_Device_stopAll(BKE_sound_get_device()); +#endif // WITH_AUDASPACE +} + +#ifdef WITH_PYTHON + +void LA_Launcher::HandlePythonConsole() +{ +#ifndef WITH_GAMEENGINE_SECURITY + if (!m_pythonConsole.use) { + return; + } + + for (unsigned short i = 0, size = m_pythonConsole.keys.size(); i < size; ++i) { + if (!m_inputDevice->GetInput(m_pythonConsole.keys[i]).Find(SCA_InputEvent::ACTIVE)) { + return; + } + } + +#ifdef WIN32 // We Use this function to avoid Blender window freeze when we launch python console from Windows. + DisableProcessWindowsGhosting(); +#endif + + // Pop the console window for windows. + m_system->toggleConsole(1); + + createPythonConsole(); + + // Hide the console window for windows. + m_system->toggleConsole(0); + + // Set the game engine windows on top of all other and active. + SetWindowOrder(1); + + + /* As we show the console, the release events of the shortcut keys can be not handled by the engine. + * We simulate they them. + */ + for (unsigned short i = 0, size = m_pythonConsole.keys.size(); i < size; ++i) { + m_inputDevice->ConvertEvent(m_pythonConsole.keys[i], 0, 0); + } +#endif +} + +int LA_Launcher::PythonEngineNextFrame(void *state) +{ + PythonMainLoopState *pstate = (PythonMainLoopState *)state; + pstate->m_exitInfo = pstate->m_launcher->EngineNextFrame(); + if (pstate->m_exitInfo.m_code == KX_ExitInfo::NO_REQUEST) { + return 0; + } + else { + CM_Error("Exit code " << (int)pstate->m_exitInfo.m_code << ": " << pstate->m_exitInfo.m_fileName); + return 1; + } +} + +#endif + +void LA_Launcher::RenderEngine() +{ + // Render the frame. + m_ketsjiEngine->Render(); +} + +#ifdef WITH_PYTHON + +bool LA_Launcher::GetPythonMainLoopCode(std::string& pythonCode, std::string& pythonFileName) +{ + pythonFileName = KX_GetPythonMain(m_startScene); + if (pythonFileName.empty()) { + return false; + } + + pythonCode = KX_GetPythonCode(m_maggie, pythonFileName); + if (pythonCode.empty()) { + CM_Error("cannot yield control to Python: no Python text data block named '" << pythonFileName << "'"); + return false; + } + return true; +} + +void LA_Launcher::RunPythonMainLoop(const std::string& pythonCode) +{ + PyRun_SimpleString(pythonCode.c_str()); +} + +#endif // WITH_PYTHON + +KX_ExitInfo LA_Launcher::EngineNextFrame() +{ +#ifdef WITH_PYTHON + // Check if we can create a python console debugging. + HandlePythonConsole(); +#endif + // Kick the engine. + bool renderFrame = m_ketsjiEngine->NextFrame(); + + // First check if we want to exit. + KX_ExitInfo exitInfo = m_ketsjiEngine->GetExitInfo(); + + if (exitInfo.m_code == KX_ExitInfo::NO_REQUEST) { + if (renderFrame) { + RenderEngine(); + } + } + + m_system->processEvents(false); + m_system->dispatchEvents(); + + SCA_IInputDevice::SCA_EnumInputs exitKey = m_ketsjiEngine->GetExitKey(); + if (m_inputDevice->GetInput(exitKey).Find(SCA_InputEvent::ACTIVE) && + !m_inputDevice->GetHookExitKey()) { + m_inputDevice->ConvertEvent(exitKey, 0, 0); + exitInfo.m_code = KX_ExitInfo::BLENDER_ESC; + } + else if (m_inputDevice->GetInput(SCA_IInputDevice::WINCLOSE).Find(SCA_InputEvent::ACTIVE) || + m_inputDevice->GetInput(SCA_IInputDevice::WINQUIT).Find(SCA_InputEvent::ACTIVE)) { + m_inputDevice->ConvertEvent(SCA_IInputDevice::WINCLOSE, 0, 0); + m_inputDevice->ConvertEvent(SCA_IInputDevice::WINQUIT, 0, 0); + exitInfo.m_code = KX_ExitInfo::OUTSIDE; + } + + return exitInfo; +} + +KX_ExitInfo LA_Launcher::EngineMainLoop() +{ +#ifdef WITH_PYTHON + std::string pythonCode; + std::string pythonFileName; + if (GetPythonMainLoopCode(pythonCode, pythonFileName)) { + // Set python environement variable. + KX_SetActiveScene(m_kxStartScene); + + PythonMainLoopState state; + state.m_launcher = this; + pynextframestate.state = &state; + pynextframestate.func = &PythonEngineNextFrame; + + CM_Debug("Yielding control to Python script '" << pythonFileName << "'..."); + RunPythonMainLoop(pythonCode); + CM_Debug("Exit Python script '" << pythonFileName << "'"); + + return state.m_exitInfo; + } + else { + pynextframestate.state = nullptr; + pynextframestate.func = nullptr; +#endif // WITH_PYTHON + + KX_ExitInfo exitInfo; + while (exitInfo.m_code == KX_ExitInfo::NO_REQUEST) { + exitInfo = EngineNextFrame(); + } + + return exitInfo; + +#ifdef WITH_PYTHON +} +#endif +} diff --git a/source/gameengine/Launcher/LA_Launcher.h b/source/gameengine/Launcher/LA_Launcher.h new file mode 100644 index 000000000000..53f60676a5ee --- /dev/null +++ b/source/gameengine/Launcher/LA_Launcher.h @@ -0,0 +1,159 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file LA_Launcher.h + * \ingroup launcher + */ + +#ifndef __LA_LAUNCHER_H__ +#define __LA_LAUNCHER_H__ + +#include "KX_KetsjiEngine.h" + +#include "RAS_Rasterizer.h" + +#include "SCA_IInputDevice.h" + +#include + +class KX_Scene; +class BL_Converter; +class KX_NetworkMessageManager; +class RAS_ICanvas; +class DEV_EventConsumer; +class DEV_InputDevice; +class GHOST_ISystem; +struct Scene; +struct Main; + +class LA_Launcher +{ +protected: + /// \section The game data. + std::string m_startSceneName; + Scene *m_startScene; + Main *m_maggie; + KX_Scene *m_kxStartScene; + + GlobalSettings *m_globalSettings; + + /// GHOST system abstraction. + GHOST_ISystem *m_system; + + /// The gameengine itself. + KX_KetsjiEngine* m_ketsjiEngine; + /// The game engine's input device abstraction. + DEV_InputDevice *m_inputDevice; + DEV_EventConsumer *m_eventConsumer; + /// The game engine's canvas abstraction. + RAS_ICanvas *m_canvas; + /// The rasterizer. + RAS_Rasterizer *m_rasterizer; + /// Converts Blender data files. + BL_Converter *m_converter; + /// Manage messages. + KX_NetworkMessageManager *m_networkMessageManager; + +#ifdef WITH_PYTHON + PyObject *m_globalDict; +#endif // WITH_PYTHON + + bool m_alwaysUseExpandFraming; + float m_camZoom; + + /// The number of render samples. + int m_samples; + + /// The render stereo mode passed in constructor. + RAS_Rasterizer::StereoMode m_stereoMode; + + /// argc and argv need to be passed on to python + int m_argc; + char **m_argv; + + /// Saved data to restore at the game end. + struct SavedData { + RAS_Rasterizer::MipmapOption mipmap; + int anisotropic; + } m_savedData; + + struct PythonConsole { + bool use; + std::vector keys; + } m_pythonConsole; + +#ifdef WITH_PYTHON + void HandlePythonConsole(); +#endif // WITH_PYTHON + + /// Execute engine render, overrided to render background. + virtual void RenderEngine(); + +#ifdef WITH_PYTHON + /** Return true if the user use a valid python script for main loop and copy the python code + * to pythonCode and file name to pythonFileName. Else return false. + * This function print itself error messages for invalid script name and only pythonCode + * value must be freed. + */ + virtual bool GetPythonMainLoopCode(std::string& pythonCode, std::string& pythonFileName); + virtual void RunPythonMainLoop(const std::string& pythonCode); +#endif // WITH_PYTHON + + virtual RAS_ICanvas *CreateCanvas(RAS_Rasterizer *rasty) = 0; + virtual RAS_Rasterizer::DrawType GetRasterizerDrawMode() = 0; + virtual void InitCamera() = 0; + + virtual void SetWindowOrder(short order) = 0; + +public: + LA_Launcher(GHOST_ISystem *system, Main *maggie, Scene *scene, GlobalSettings *gs, + RAS_Rasterizer::StereoMode stereoMode, int samples, bool alwaysUseExpandFraming, int argc, char **argv); + virtual ~LA_Launcher(); + +#ifdef WITH_PYTHON + /// Setup python global dictionnary, used outside constructor to compile without python. + void SetPythonGlobalDict(PyObject *globalDict); +#endif // WITH_PYTHON + + GlobalSettings *GetGlobalSettings(); + + inline KX_Scene *GetStartScene() const + { + return m_kxStartScene; + } + + /// Initializes the game engine. + virtual void InitEngine(); + /// Shuts the game engine down. + virtual void ExitEngine(); + + /// Compute next frame. + virtual KX_ExitInfo EngineNextFrame(); + /// Execute the loop of the engine, return when receive a exit request from the engine. + KX_ExitInfo EngineMainLoop(); + +#ifdef WITH_PYTHON + static int PythonEngineNextFrame(void *state); +#endif // WITH_PYTHON +}; + +#endif // __LA_LAUNCHER_H__ diff --git a/source/gameengine/Launcher/LA_PlayerLauncher.cpp b/source/gameengine/Launcher/LA_PlayerLauncher.cpp new file mode 100644 index 000000000000..bf1012cf7c93 --- /dev/null +++ b/source/gameengine/Launcher/LA_PlayerLauncher.cpp @@ -0,0 +1,157 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Launcher/LA_PlayerLauncher.cpp + * \ingroup launcher + */ + + +#ifdef WIN32 +# pragma warning (disable:4786) // suppress stl-MSVC debug info warning +# include +#endif + +#include "LA_PlayerLauncher.h" +#include "LA_SystemCommandLine.h" + +extern "C" { +# include "BKE_sound.h" + +# include "BLI_fileops.h" + +# include "MEM_guardedalloc.h" +} + +#include "KX_PythonInit.h" + +#include "GPG_Canvas.h" + +#include "GHOST_ISystem.h" + +#include "DEV_InputDevice.h" + +#include "CM_Message.h" + +LA_PlayerLauncher::LA_PlayerLauncher(GHOST_ISystem *system, GHOST_IWindow *window, Main *maggie, Scene *scene, GlobalSettings *gs, + RAS_Rasterizer::StereoMode stereoMode, int samples, int argc, char **argv, const std::string& pythonMainLoop) + :LA_Launcher(system, maggie, scene, gs, stereoMode, samples, false, argc, argv), + m_mainWindow(window), + m_pythonMainLoop(pythonMainLoop) +{ +} + +LA_PlayerLauncher::~LA_PlayerLauncher() +{ +} + +#ifdef WITH_PYTHON + +bool LA_PlayerLauncher::GetPythonMainLoopCode(std::string& pythonCode, std::string& pythonFileName) +{ +#ifndef WITH_GAMEENGINE_SECURITY + if (!m_pythonMainLoop.empty()) { + if (BLI_is_file(m_pythonMainLoop.c_str())) { + size_t filesize = 0; + char *filecontent = (char *)BLI_file_read_text_as_mem(m_pythonMainLoop.c_str(), 0, &filesize); + pythonCode = std::string(filecontent, filesize); + MEM_freeN(filecontent); + pythonFileName = m_pythonMainLoop; + return true; + } + else { + CM_Error("cannot yield control to Python: no file named '" << m_pythonMainLoop << "'"); + return false; + } + } +#endif + return LA_Launcher::GetPythonMainLoopCode(pythonCode, pythonFileName); +} + +void LA_PlayerLauncher::RunPythonMainLoop(const std::string& pythonCode) +{ + /* If a valid python main loop file exists is that we are running it. + * Then we put its path in the python include paths. */ + if (!m_pythonMainLoop.empty()) { + appendPythonPath(m_pythonMainLoop); + } + LA_Launcher::RunPythonMainLoop(pythonCode); +} + +#endif // WITH_PYTHON + +RAS_Rasterizer::DrawType LA_PlayerLauncher::GetRasterizerDrawMode() +{ + const SYS_SystemHandle& syshandle = SYS_GetSystem(); + const bool wireframe = SYS_GetCommandLineInt(syshandle, "wireframe", 0); + + if (wireframe) { + return RAS_Rasterizer::RAS_WIREFRAME; + } + + return RAS_Rasterizer::RAS_TEXTURED; +} + +void LA_PlayerLauncher::InitCamera() +{ +} + +void LA_PlayerLauncher::SetWindowOrder(short order) +{ + m_mainWindow->setOrder((order == 0) ? GHOST_kWindowOrderBottom : GHOST_kWindowOrderTop); +} + +void LA_PlayerLauncher::InitEngine() +{ + BKE_sound_init(m_maggie); + LA_Launcher::InitEngine(); + + m_rasterizer->PrintHardwareInfo(); +} + +void LA_PlayerLauncher::ExitEngine() +{ + LA_Launcher::ExitEngine(); + BKE_sound_exit(); +} + +KX_ExitInfo LA_PlayerLauncher::EngineNextFrame() +{ + if (m_inputDevice->GetInput(SCA_IInputDevice::WINRESIZE).Find(SCA_InputEvent::ACTIVE)) { + GHOST_Rect bnds; + m_mainWindow->getClientBounds(bnds); + m_canvas->Resize(bnds.getWidth(), bnds.getHeight()); + m_ketsjiEngine->Resize(); + m_inputDevice->ConvertEvent(SCA_IInputDevice::WINRESIZE, 0, 0); + } + + return LA_Launcher::EngineNextFrame(); +} + +RAS_ICanvas *LA_PlayerLauncher::CreateCanvas(RAS_Rasterizer *rasty) +{ + return (new GPG_Canvas(rasty, m_mainWindow)); +} diff --git a/source/gameengine/Launcher/LA_PlayerLauncher.h b/source/gameengine/Launcher/LA_PlayerLauncher.h new file mode 100644 index 000000000000..f7a5a4dec9bd --- /dev/null +++ b/source/gameengine/Launcher/LA_PlayerLauncher.h @@ -0,0 +1,71 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file LA_PlayerLauncher.h + * \ingroup launcher + */ + +#ifdef WIN32 +#include +#endif + +#include "LA_Launcher.h" + +#include "GHOST_Types.h" + +class GHOST_IWindow; + +class LA_PlayerLauncher : public LA_Launcher +{ +protected: + /// Main window. + GHOST_IWindow *m_mainWindow; + + /// Override python script main loop file name. + std::string m_pythonMainLoop; + +#ifdef WITH_PYTHON + virtual bool GetPythonMainLoopCode(std::string& pythonCode, std::string& pythonFileName); + virtual void RunPythonMainLoop(const std::string& pythonCode); +#endif // WITH_PYTHON + + virtual RAS_ICanvas *CreateCanvas(RAS_Rasterizer *rasty); + virtual RAS_Rasterizer::DrawType GetRasterizerDrawMode(); + virtual void InitCamera(); + + virtual void SetWindowOrder(short order); + +public: + LA_PlayerLauncher(GHOST_ISystem *system, GHOST_IWindow *window, Main *maggie, Scene *scene, GlobalSettings *gs, + RAS_Rasterizer::StereoMode stereoMode, int samples, int argc, char **argv, const std::string& pythonMainLoop); + virtual ~LA_PlayerLauncher(); + + virtual void InitEngine(); + virtual void ExitEngine(); + + virtual KX_ExitInfo EngineNextFrame(); +}; diff --git a/source/gameengine/BlenderRoutines/BL_System.cpp b/source/gameengine/Launcher/LA_SystemCommandLine.cpp similarity index 62% rename from source/gameengine/BlenderRoutines/BL_System.cpp rename to source/gameengine/Launcher/LA_SystemCommandLine.cpp index 5560ea121651..900fb0cb40de 100644 --- a/source/gameengine/BlenderRoutines/BL_System.cpp +++ b/source/gameengine/Launcher/LA_SystemCommandLine.cpp @@ -15,37 +15,35 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL LICENSE BLOCK ***** - * Interface to the commandline arguments */ -/** \file gameengine/BlenderRoutines/BL_System.cpp +/** \file gameengine/BlenderRoutines/LA_SystemCommandLine.cpp * \ingroup blroutines */ -#include "CTR_Map.h" -#include "STR_HashedString.h" -#include "BL_System.h" +#include +#include "LA_SystemCommandLine.h" + +#include struct SingletonSystem { - CTR_Map int_params; - CTR_Map float_params; - CTR_Map string_params; + std::map int_params; + std::map float_params; + std::map string_params; }; -static SingletonSystem *_system_instance = NULL; +static SingletonSystem *_system_instance = nullptr; SYS_SystemHandle SYS_GetSystem() { - if (!_system_instance) + if (!_system_instance) { _system_instance = new SingletonSystem(); + } return (SYS_SystemHandle)_system_instance; } @@ -54,48 +52,52 @@ void SYS_DeleteSystem(SYS_SystemHandle sys) { if (_system_instance) { delete _system_instance; - _system_instance = NULL; + _system_instance = nullptr; } } int SYS_GetCommandLineInt(SYS_SystemHandle sys, const char *paramname, int defaultvalue) { - int *result = ((SingletonSystem *)sys)->int_params[paramname]; - if (result) - return *result; + std::map::iterator it = ((SingletonSystem *)sys)->int_params.find(paramname); + if (it != ((SingletonSystem *)sys)->int_params.end()) { + return it->second; + } return defaultvalue; } float SYS_GetCommandLineFloat(SYS_SystemHandle sys, const char *paramname, float defaultvalue) { - float *result = ((SingletonSystem *)sys)->float_params[paramname]; - if (result) - return *result; + std::map::iterator it = ((SingletonSystem *)sys)->float_params.find(paramname); + if (it != ((SingletonSystem *)sys)->float_params.end()) { + return it->second; + } return defaultvalue; } const char *SYS_GetCommandLineString(SYS_SystemHandle sys, const char *paramname, const char *defaultvalue) { - STR_String *result = ((SingletonSystem *)sys)->string_params[paramname]; - if (result) - return *result; + std::map::iterator it = ((SingletonSystem *)sys)->string_params.find(paramname); + if (it != ((SingletonSystem *)sys)->string_params.end()) { + return it->second.c_str(); + } return defaultvalue; } void SYS_WriteCommandLineInt(SYS_SystemHandle sys, const char *paramname, int value) { - ((SingletonSystem *)sys)->int_params.insert(paramname, value); + ((SingletonSystem *)sys)->int_params[paramname] = value; } void SYS_WriteCommandLineFloat(SYS_SystemHandle sys, const char *paramname, float value) { - ((SingletonSystem *)sys)->float_params.insert(paramname, value); + ((SingletonSystem *)sys)->float_params[paramname] = value; } void SYS_WriteCommandLineString(SYS_SystemHandle sys, const char *paramname, const char *value) { - ((SingletonSystem *)sys)->string_params.insert(paramname, value); + ((SingletonSystem *)sys)->string_params[paramname] = value; } + diff --git a/source/gameengine/BlenderRoutines/BL_System.h b/source/gameengine/Launcher/LA_SystemCommandLine.h similarity index 90% rename from source/gameengine/BlenderRoutines/BL_System.h rename to source/gameengine/Launcher/LA_SystemCommandLine.h index 9fc53c053c04..48de9666e0f9 100644 --- a/source/gameengine/BlenderRoutines/BL_System.h +++ b/source/gameengine/Launcher/LA_SystemCommandLine.h @@ -15,19 +15,14 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL LICENSE BLOCK ***** - * System specific information / access. - * Interface to the commandline arguments */ -/** \file gameengine/BlenderRoutines/BL_System.h +/** \file gameengine/BlenderRoutines/LA_SystemCommandLine.h * \ingroup blroutines */ @@ -67,3 +62,4 @@ extern void StartKetsjiShell(struct bContext *C, struct ARegion *ar, #endif #endif /* __BL_SYSTEM_H__ */ + diff --git a/source/gameengine/Network/LoopBackNetwork/NG_LoopBackNetworkDeviceInterface.cpp b/source/gameengine/Network/LoopBackNetwork/NG_LoopBackNetworkDeviceInterface.cpp deleted file mode 100644 index 753977d3a122..000000000000 --- a/source/gameengine/Network/LoopBackNetwork/NG_LoopBackNetworkDeviceInterface.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - * LoopbackNetworkDeviceInterface derived from NG_NetworkDeviceInterface - */ - -/** \file gameengine/Network/LoopBackNetwork/NG_LoopBackNetworkDeviceInterface.cpp - * \ingroup bgenetlb - */ - - -#include "NG_LoopBackNetworkDeviceInterface.h" -#include "NG_NetworkMessage.h" - -using namespace std; - -// temporary debugging printf's -#ifdef NAN_NET_DEBUG - #include -#endif - -NG_LoopBackNetworkDeviceInterface::NG_LoopBackNetworkDeviceInterface() -{ - m_currentQueue=0; - Online(); // LoopBackdevices are 'online' immediately -} - -NG_LoopBackNetworkDeviceInterface::~NG_LoopBackNetworkDeviceInterface() -{ -} - -// perhaps this should go to the shared/common implementation too -void NG_LoopBackNetworkDeviceInterface::NextFrame() -{ - // Release reference to the messages while emptying the queue - while (m_messages[m_currentQueue].size() > 0) { -#ifdef NAN_NET_DEBUG - printf("NG_LBNDI::NextFrame %d '%s'\n", m_currentQueue, m_messages[m_currentQueue][0]->GetSubject().ReadPtr()); -#endif - // Should do assert(m_events[0]); - m_messages[m_currentQueue][0]->Release(); - m_messages[m_currentQueue].pop_front(); - } - //m_messages[m_currentQueue].clear(); - - m_currentQueue=1-m_currentQueue; -} - -void NG_LoopBackNetworkDeviceInterface::SendNetworkMessage(NG_NetworkMessage* nwmsg) -{ -#ifdef NAN_NET_DEBUG - printf("NG_LBNDI::SendNetworkMessage %d, '%s'->'%s' '%s' '%s'\n", - 1-m_currentQueue, - nwmsg->GetDestinationName().ReadPtr(), - nwmsg->GetSenderName().ReadPtr(), - nwmsg->GetSubject().ReadPtr(), - nwmsg->GetMessageText().ReadPtr()); -#endif - int backqueue = 1-m_currentQueue; - - nwmsg->AddRef(); - m_messages[backqueue].push_back(nwmsg); -} - -vector NG_LoopBackNetworkDeviceInterface::RetrieveNetworkMessages() -{ - vector messages; - - std::deque::iterator mesit=m_messages[m_currentQueue].begin(); - for (; !(mesit == m_messages[m_currentQueue].end()); ++mesit) - { - - // We don't increase the reference count for these messages. We - // are passing a vector of messages in the interface and not - // explicitily storing the messgaes for long term usage - - messages.push_back(*mesit); - -#ifdef NAN_NET_DEBUG - printf("NG_LBNDI::RetrieveNetworkMessages %d '%s'->'%s' '%s' '%s'\n", - m_currentQueue, - (*mesit)->GetDestinationName().ReadPtr(), - (*mesit)->GetSenderName().ReadPtr(), - (*mesit)->GetSubject().ReadPtr(), - (*mesit)->GetMessageText().ReadPtr()); -#endif - } - return messages; -} diff --git a/source/gameengine/Network/LoopBackNetwork/NG_LoopBackNetworkDeviceInterface.h b/source/gameengine/Network/LoopBackNetwork/NG_LoopBackNetworkDeviceInterface.h deleted file mode 100644 index 8bbb1e91e356..000000000000 --- a/source/gameengine/Network/LoopBackNetwork/NG_LoopBackNetworkDeviceInterface.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file NG_LoopBackNetworkDeviceInterface.h - * \ingroup bgenetlb - * \brief LoopbackNetworkDeviceInterface derived from NG_NetworkDeviceInterface - */ -#ifndef __NG_LOOPBACKNETWORKDEVICEINTERFACE_H__ -#define __NG_LOOPBACKNETWORKDEVICEINTERFACE_H__ - -#include -#include "NG_NetworkDeviceInterface.h" - -class NG_LoopBackNetworkDeviceInterface : public NG_NetworkDeviceInterface -{ - std::deque m_messages[2]; - int m_currentQueue; - -public: - NG_LoopBackNetworkDeviceInterface(); - virtual ~NG_LoopBackNetworkDeviceInterface(); - - /** - * Clear message buffer - */ - virtual void NextFrame(); - - bool Connect(char *address, unsigned int port, char *password, - unsigned int localport, unsigned int timeout) - { - return true; - } - bool Disconnect(void) {return true;} - - virtual void SendNetworkMessage(class NG_NetworkMessage* msg); - virtual std::vector RetrieveNetworkMessages(); -}; - -#endif /* __NG_LOOPBACKNETWORKDEVICEINTERFACE_H__ */ diff --git a/source/gameengine/Network/NG_NetworkDeviceInterface.h b/source/gameengine/Network/NG_NetworkDeviceInterface.h deleted file mode 100644 index 95450db3d46c..000000000000 --- a/source/gameengine/Network/NG_NetworkDeviceInterface.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file NG_NetworkDeviceInterface.h - * \ingroup bgenet - * \brief Functions like (de)initialize network, get library version - * To be derived by loopback and network libraries - */ - -#ifndef __NG_NETWORKDEVICEINTERFACE_H__ -#define __NG_NETWORKDEVICEINTERFACE_H__ - -#include "NG_NetworkMessage.h" -#include - -class NG_NetworkDeviceInterface -{ -private: - // candidates for shared/common implementation class - bool m_online; -public: - NG_NetworkDeviceInterface() {} - virtual ~NG_NetworkDeviceInterface() {} - - virtual void NextFrame()=0; - - /** - * Mark network connection online - */ - void Online(void) { m_online = true; } - /** - * Mark network connection offline - */ - void Offline(void) { m_online = false; } - /** - * Is the network connection established ? - */ - bool IsOnline(void) { return m_online; } - - virtual bool Connect(char *address, unsigned int port, char *password, - unsigned int localport, unsigned int timeout)=0; - virtual bool Disconnect(void)=0; - - virtual void SendNetworkMessage(NG_NetworkMessage* msg)=0; - /** - * read NG_NetworkMessage from library buffer, may be - * irrelevant for loopbackdevices - */ - - virtual std::vector RetrieveNetworkMessages()=0; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:NG_NetworkDeviceInterface") -#endif -}; - -#endif /* __NG_NETWORKDEVICEINTERFACE_H__ */ diff --git a/source/gameengine/Network/NG_NetworkMessage.cpp b/source/gameengine/Network/NG_NetworkMessage.cpp deleted file mode 100644 index 23ae2529b7a7..000000000000 --- a/source/gameengine/Network/NG_NetworkMessage.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - * generic Network Message implementation - */ - -/** \file gameengine/Network/NG_NetworkMessage.cpp - * \ingroup bgenet - */ - -#include "NG_NetworkMessage.h" -#include - -int NG_NetworkMessage::s_nextID = 3; // just some number to start with - -NG_NetworkMessage::NG_NetworkMessage( - const STR_String& to, - const STR_String& from, - const STR_String& subject, - const STR_String& body) : - m_uniqueMessageID(s_nextID++), - m_refcount(1), - m_to(to), - m_from(from), - m_subject(subject), - m_message(body) -{ -} - -NG_NetworkMessage::~NG_NetworkMessage() -{ - assert(m_refcount==0); -} diff --git a/source/gameengine/Network/NG_NetworkMessage.h b/source/gameengine/Network/NG_NetworkMessage.h deleted file mode 100644 index 6c96dbd8f1ca..000000000000 --- a/source/gameengine/Network/NG_NetworkMessage.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file NG_NetworkMessage.h - * \ingroup bgenet - * \brief generic Network Message class - */ -#ifndef __NG_NETWORKMESSAGE_H__ -#define __NG_NETWORKMESSAGE_H__ - -#include "STR_HashedString.h" - -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -class NG_NetworkMessage -{ - static int s_nextID; - int m_uniqueMessageID; // intern counting MessageID - unsigned int m_ClientId; - int m_refcount; - - STR_String m_to; // receiver - STR_String m_from; // sender - STR_String m_subject; // empty or propName - STR_String m_message; // message or propValue - -protected: - ~NG_NetworkMessage(); - -public: - NG_NetworkMessage( - const STR_String& to, - const STR_String& from, - const STR_String& subject, - const STR_String& body); - - void AddRef() { - m_refcount++; - } - - // This is not nice code you should'nt need to resort to - // delete this. - void Release() - { - if (! --m_refcount) - { - delete this; - } - } - - /** - * set the content of this message - */ - void SetMessageText(const STR_String& msgtext) { - m_message = msgtext; - } - - /** - * get the (read-only) To part of this message - */ - const STR_String& GetDestinationName() { return m_to; } - - /** - * get the (read-only) From part of this message - */ - const STR_String& GetSenderName() { return m_from; } - - /** - * get the (read-only) Subject part of this message - */ - const STR_String& GetSubject() { return m_subject; } - - /** - * get the (read-only) Body part of this message - */ - const STR_String& GetMessageText() { -//cout << "GetMessageText " << m_message << "\n"; - return m_message; - } - const STR_String& GetMessageText() const { -//cout << "GetMessageText " << m_message << "\n"; - return m_message; - } - - /** - * Set the NetworkMessage sender identifier - */ - void SetSender(unsigned int ClientId) { - m_ClientId = ClientId; - } - - /** - * Get the NetworkMessage sender identifier - */ - unsigned int GetSender(void) { - return m_ClientId; - } - - /** - * get the unique Network Message ID - */ - int GetMessageID() { - return m_uniqueMessageID; - } - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:NG_NetworkMessage") -#endif -}; - -#endif /* __NG_NETWORKMESSAGE_H__ */ diff --git a/source/gameengine/Network/NG_NetworkObject.h b/source/gameengine/Network/NG_NetworkObject.h deleted file mode 100644 index 54459cad55d5..000000000000 --- a/source/gameengine/Network/NG_NetworkObject.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file NG_NetworkObject.h - * \ingroup bgenet - * \brief generic Network Object class - */ -#ifndef __NG_NETWORKOBJECT_H__ -#define __NG_NETWORKOBJECT_H__ - -#include "STR_String.h" - -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -class NG_NetworkObject -{ - STR_String m_name; -public: - NG_NetworkObject(); - ~NG_NetworkObject(); - const STR_String& GetName(); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:NG_NetworkObject") -#endif -}; - -#endif /* __NG_NETWORKOBJECT_H__ */ diff --git a/source/gameengine/Network/NG_NetworkScene.cpp b/source/gameengine/Network/NG_NetworkScene.cpp deleted file mode 100644 index 8e89db4b1295..000000000000 --- a/source/gameengine/Network/NG_NetworkScene.cpp +++ /dev/null @@ -1,271 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - * NetworkSceneManagement generic implementation - */ - -/** \file gameengine/Network/NG_NetworkScene.cpp - * \ingroup bgenet - */ - -#include -#include -#include - -#include "NG_NetworkScene.h" -#include "NG_NetworkDeviceInterface.h" -#include "NG_NetworkMessage.h" -#include "NG_NetworkObject.h" - -NG_NetworkScene::NG_NetworkScene(NG_NetworkDeviceInterface* nic) -{ - m_networkdevice = nic; -} - -NG_NetworkScene::~NG_NetworkScene() -{ - ClearAllMessageMaps(); -} - -/** - * progress one frame, handle all network traffic - */ -void NG_NetworkScene::proceed(double curtime) -{ - if (!m_networkdevice) return; - if (!m_networkdevice->IsOnline()) return; - - ClearAllMessageMaps(); - - // read all NetworkMessages from the device - vector messages = - m_networkdevice->RetrieveNetworkMessages(); - - vector::iterator mesit = messages.begin(); - for (; !(mesit == messages.end()); mesit++) { - NG_NetworkMessage* message = (*mesit); - vector* tmplist=NULL; - - vector** tmplistptr = - m_messagesByDestinationName[message->GetDestinationName()]; - // if there is already a vector of messages, append, else create - // a new vector and insert into map - if (!tmplistptr) { - tmplist = new vector; - m_messagesByDestinationName.insert(message->GetDestinationName(), - tmplist); - } else { - tmplist = *tmplistptr; - } - message->AddRef(); - tmplist->push_back(message); - tmplist = NULL; - - tmplistptr = m_messagesBySenderName[message->GetSenderName()]; - // if there is already a vector of messages, append, else create - // a new vector and insert into map - if (!tmplistptr) { - tmplist = new vector; - m_messagesBySenderName.insert(message->GetSenderName(), tmplist); - } else { - tmplist = *tmplistptr; - } - message->AddRef(); - tmplist->push_back(message); - tmplist = NULL; - - tmplistptr = m_messagesBySubject[message->GetSubject()]; - // if there is already a vector of messages, append, else create - // a new vector and insert into map - if (!tmplistptr) { - tmplist = new vector; - m_messagesBySubject.insert(message->GetSubject(), tmplist); - } else { - tmplist = *tmplistptr; - } - message->AddRef(); - tmplist->push_back(message); - tmplist = NULL; - } -} - -/** - * add a network object to the network scene - */ -void NG_NetworkScene::AddObject(NG_NetworkObject* object) -{ - if (! m_networkdevice->IsOnline()) return; - - const STR_String& name = object->GetName(); - m_networkObjects.insert(name, object); -} - -/** - * remove a network object from the network scene - */ -void NG_NetworkScene::RemoveObject(NG_NetworkObject* object) -{ - if (! m_networkdevice->IsOnline()) return; - - const STR_String& name = object->GetName(); - m_networkObjects.remove(name); -} - -/** - * remove all network scene objects at once - */ -void NG_NetworkScene::RemoveAllObjects() -{ - m_networkObjects.clear(); -} - -/** - * get a single network object given its name - */ -NG_NetworkObject* NG_NetworkScene::FindNetworkObject(const STR_String& objname) -{ - NG_NetworkObject *nwobj = NULL; - if (! m_networkdevice->IsOnline()) return nwobj; - - NG_NetworkObject **nwobjptr = m_networkObjects[objname]; - if (nwobjptr) { - nwobj = *nwobjptr; - } - - return nwobj; -} - -bool NG_NetworkScene::ConstraintsAreValid( - const STR_String& from, - const STR_String& subject, - NG_NetworkMessage* message) -{ - vector** fromlistptr = m_messagesBySenderName[from]; - vector** subjectlistptr = m_messagesBySubject[subject]; - - vector* fromlist = (fromlistptr ? *fromlistptr : NULL); - vector* subjectlist = (subjectlistptr ? *subjectlistptr : NULL); - - return ( - ( from.IsEmpty() || (!fromlist ? false : (!(std::find(fromlist->begin(), fromlist->end(), message) == fromlist->end()))) - ) && - ( subject.IsEmpty() || (!subjectlist ? false : (!(std::find(subjectlist->begin(), subjectlist->end(), message) == subjectlist->end()))) - )); -} - -vector NG_NetworkScene::FindMessages( - const STR_String& to, - const STR_String& from, - const STR_String& subject, - bool spamallowed) -{ - vector foundmessages; - bool notfound = false; - - // broad phase - notfound = ((to.IsEmpty() || spamallowed) ? notfound : m_messagesByDestinationName[to] == NULL); - if (!notfound) - notfound = (from.IsEmpty() ? notfound : m_messagesBySenderName[from] == NULL); - if (!notfound) - notfound = (subject.IsEmpty() ? notfound : m_messagesBySubject[subject] == NULL); - if (notfound) { - // it's definitely NOT in the scene, so stop looking - } else { // narrow phase - // possibly it's there, but maybe not (false hit) - if (to.IsEmpty()) { - // take all messages, and check other fields - MT_assert(!"objectnames that are empty are not valid, so make it a hobby project :)\n"); - } else { - //todo: find intersection of messages (that are in other 2 maps) - vector** tolistptr = m_messagesByDestinationName[to]; - if (tolistptr) { - vector* tolist = *tolistptr; - vector::iterator listit; - for (listit=tolist->begin();!(listit==tolist->end());listit++) { - NG_NetworkMessage* message = *listit; - if (ConstraintsAreValid(from, subject, message)) { - message->AddRef(); - foundmessages.push_back(message); - } - } - } - // TODO find intersection of messages (that are in other 2 maps) - if (spamallowed) { - tolistptr = m_messagesByDestinationName[""]; - if (tolistptr) { - vector* tolist = *tolistptr; - vector::iterator listit; - for (listit=tolist->begin();!(listit==tolist->end());listit++) { - NG_NetworkMessage* message = *listit; - if (ConstraintsAreValid(from, subject, message)) { - message->AddRef(); - foundmessages.push_back(message); - } - } - } - } - } - } - return foundmessages; -} - -void NG_NetworkScene::SendMessage( - const STR_String& to, - const STR_String& from, - const STR_String& subject, - const STR_String& message) -{ - NG_NetworkMessage* msg = new NG_NetworkMessage(to, from, subject, message); - m_networkdevice->SendNetworkMessage(msg); - msg->Release(); -} - -void NG_NetworkScene::ClearAllMessageMaps(void) -{ - ClearMessageMap(m_messagesByDestinationName); - ClearMessageMap(m_messagesBySenderName); - ClearMessageMap(m_messagesBySubject); -} - -void NG_NetworkScene::ClearMessageMap(TMessageMap& map) -{ - // Release the messages in the map - for (int i = 0; i < map.size(); i++) { - vector* msglist; - msglist = *(map.at(i)); - - // Iterate through the current vector and release all it's messages - vector::iterator msgit; - for (msgit = msglist->begin(); msgit != msglist->end(); msgit++) { - (*msgit)->Release(); - } - - // Delete the actual vector - delete (msglist); - } - - // Empty the map - map.clear(); -} diff --git a/source/gameengine/Network/NG_NetworkScene.h b/source/gameengine/Network/NG_NetworkScene.h deleted file mode 100644 index e6233852ee25..000000000000 --- a/source/gameengine/Network/NG_NetworkScene.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file NG_NetworkScene.h - * \ingroup bgenet - * \brief NetworkSceneManagement generic class - */ -#ifndef __NG_NETWORKSCENE_H__ -#define __NG_NETWORKSCENE_H__ - -#include "CTR_Map.h" -#include "STR_HashedString.h" -#include - -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -//MSVC defines SendMessage as a win api function, even though we aren't using it -#ifdef SendMessage -# undef SendMessage -#endif - -using namespace std; - -class NG_NetworkDeviceInterface; - -class NG_NetworkScene -{ - class NG_NetworkDeviceInterface *m_networkdevice; - CTR_Map m_networkObjects; - - // CTR_Maps used as a 'Bloom' filter - typedef CTR_Map* > TMessageMap; - TMessageMap m_messagesByDestinationName; - TMessageMap m_messagesBySenderName; - TMessageMap m_messagesBySubject; - -public: - NG_NetworkScene(NG_NetworkDeviceInterface *nic); - ~NG_NetworkScene(); - - /** - * progress one frame, handle all network traffic - */ - void proceed(double curtime); - - /** - * add a networkobject to the scene - */ - void AddObject(NG_NetworkObject* object); - - /** - * remove a networkobject to the scene - */ - void RemoveObject(NG_NetworkObject* object); - - /** - * remove all objects at once - */ - void RemoveAllObjects(); - - /** - * send a message (ascii text) over the network - */ - void SendMessage(const STR_String& to,const STR_String& from,const STR_String& subject,const STR_String& message); - - /** - * find an object by name - */ - NG_NetworkObject* FindNetworkObject(const STR_String& objname); - - bool ConstraintsAreValid(const STR_String& from,const STR_String& subject,class NG_NetworkMessage* message); - vector FindMessages(const STR_String& to,const STR_String& from,const STR_String& subject,bool spamallowed); - -protected: - /** - * Releases messages in message map members. - */ - void ClearAllMessageMaps(void); - - /** - * Releases messages for the given message map. - * \param map Message map with messages. - */ - void ClearMessageMap(TMessageMap& map); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:NG_NetworkScene") -#endif -}; - -#endif /* __NG_NETWORKSCENE_H__ */ diff --git a/source/gameengine/Physics/Bullet/CMakeLists.txt b/source/gameengine/Physics/Bullet/CMakeLists.txt index 8b00f1b47fa4..d40f48275f3b 100644 --- a/source/gameengine/Physics/Bullet/CMakeLists.txt +++ b/source/gameengine/Physics/Bullet/CMakeLists.txt @@ -28,34 +28,37 @@ remove_strict_flags() set(INC . - ../common + ../Common + ../../Common ../../Converter ../../Expressions ../../GameLogic ../../Ketsji ../../Rasterizer + ../../Rasterizer/Node ../../SceneGraph ../../../blender/blenkernel ../../../blender/blenlib ../../../blender/gpu ../../../blender/makesdna - ../../../../intern/container ../../../../intern/guardedalloc - ../../../../intern/glew-mx - ../../../../intern/string ) set(INC_SYS - ../../../../intern/moto/include - ${GLEW_INCLUDE_PATH} + ../../../../intern/debugbreak + ../../../../intern/mathfu ${PYTHON_INCLUDE_DIRS} + ${BOOST_INCLUDE_DIR} ) set(SRC + CcdConstraint.cpp CcdPhysicsEnvironment.cpp CcdPhysicsController.cpp CcdGraphicController.cpp + CcdConstraint.h + CcdMathUtils.h CcdGraphicController.h CcdPhysicsController.h CcdPhysicsEnvironment.h diff --git a/source/gameengine/Physics/Bullet/CcdConstraint.cpp b/source/gameengine/Physics/Bullet/CcdConstraint.cpp new file mode 100644 index 000000000000..d77f3fcb284a --- /dev/null +++ b/source/gameengine/Physics/Bullet/CcdConstraint.cpp @@ -0,0 +1,207 @@ +#include "CcdConstraint.h" + +#include "BLI_utildefines.h" + +#include "btBulletDynamicsCommon.h" + +CcdConstraint::CcdConstraint(btTypedConstraint *constraint, bool disableCollision) + :m_constraint(constraint), + m_disableCollision(disableCollision), + m_active(true) +{ + BLI_assert(m_constraint); +} + +CcdConstraint::~CcdConstraint() +{ +} + +bool CcdConstraint::GetDisableCollision() const +{ + return m_disableCollision; +} + +bool CcdConstraint::GetActive() const +{ + return m_active; +} + +void CcdConstraint::SetActive(bool active) +{ + m_active = active; +} + +bool CcdConstraint::GetEnabled() const +{ + return m_constraint->isEnabled(); +} + +void CcdConstraint::SetEnabled(bool enabled) +{ + m_constraint->setEnabled(enabled); + + // Unsleep objects to enable constraint influence. + if (enabled) { + m_constraint->getRigidBodyA().activate(true); + m_constraint->getRigidBodyB().activate(true); + } +} + +void CcdConstraint::SetParam(int param, float value0, float value1) +{ + switch (m_constraint->getUserConstraintType()) { + case PHY_GENERIC_6DOF_CONSTRAINT: + { + switch (param) { + case 0: case 1: case 2: case 3: case 4: case 5: + { + //param = 0..5 are constraint limits, with low/high limit value + btGeneric6DofConstraint *genCons = (btGeneric6DofConstraint *)m_constraint; + genCons->setLimit(param, value0, value1); + break; + } + case 6: case 7: case 8: + { + //param = 6,7,8 are translational motors, with value0=target velocity, value1 = max motor force + btGeneric6DofConstraint *genCons = (btGeneric6DofConstraint *)m_constraint; + int transMotorIndex = param - 6; + btTranslationalLimitMotor *transMotor = genCons->getTranslationalLimitMotor(); + transMotor->m_targetVelocity[transMotorIndex] = value0; + transMotor->m_maxMotorForce[transMotorIndex] = value1; + transMotor->m_enableMotor[transMotorIndex] = (value1 > 0.0f); + break; + } + case 9: case 10: case 11: + { + //param = 9,10,11 are rotational motors, with value0=target velocity, value1 = max motor force + btGeneric6DofConstraint *genCons = (btGeneric6DofConstraint *)m_constraint; + int angMotorIndex = param - 9; + btRotationalLimitMotor *rotMotor = genCons->getRotationalLimitMotor(angMotorIndex); + rotMotor->m_enableMotor = (value1 > 0.0f); + rotMotor->m_targetVelocity = value0; + rotMotor->m_maxMotorForce = value1; + break; + } + + case 12: case 13: case 14: case 15: case 16: case 17: + { + //param 12-17 are for motorized springs on each of the degrees of freedom + btGeneric6DofSpringConstraint *genCons = (btGeneric6DofSpringConstraint *)m_constraint; + int springIndex = param - 12; + if (value0 != 0.0f) { + bool springEnabled = true; + genCons->setStiffness(springIndex, value0); + genCons->setDamping(springIndex, value1); + genCons->enableSpring(springIndex, springEnabled); + genCons->setEquilibriumPoint(springIndex); + } + else { + bool springEnabled = false; + genCons->enableSpring(springIndex, springEnabled); + } + break; + } + + default: + { + } + } + ; + break; + }; + case PHY_CONE_TWIST_CONSTRAINT: + { + switch (param) { + case 3: case 4: case 5: + { + //param = 3,4,5 are constraint limits, high limit values + btConeTwistConstraint *coneTwist = (btConeTwistConstraint *)m_constraint; + coneTwist->setLimit(param, value1); + break; + } + default: + { + } + } + ; + break; + }; + case PHY_ANGULAR_CONSTRAINT: + case PHY_LINEHINGE_CONSTRAINT: + { + switch (param) { + case 3: + { + //param = 3 is a constraint limit, with low/high limit value + btHingeConstraint *hingeCons = (btHingeConstraint *)m_constraint; + hingeCons->setLimit(value0, value1); + break; + } + default: + { + } + } + break; + }; + default: + { + }; + } + ; +} + +float CcdConstraint::GetParam(int param) +{ + switch (m_constraint->getUserConstraintType()) { + case PHY_GENERIC_6DOF_CONSTRAINT: + { + switch (param) { + case 0: case 1: case 2: + { + //param = 0..2 are linear constraint values + btGeneric6DofConstraint *genCons = (btGeneric6DofConstraint *)m_constraint; + genCons->calculateTransforms(); + return genCons->getRelativePivotPosition(param); + break; + } + case 3: case 4: case 5: + { + //param = 3..5 are relative constraint (Euler) angles + btGeneric6DofConstraint *genCons = (btGeneric6DofConstraint *)m_constraint; + genCons->calculateTransforms(); + return genCons->getAngle(param - 3); + break; + } + default: + { + } + } + break; + }; + default: + { + }; + } + ; + return 0.0f; +} + +float CcdConstraint::GetBreakingThreshold() const +{ + return m_constraint->getBreakingImpulseThreshold(); +} + +void CcdConstraint::SetBreakingThreshold(float threshold) +{ + m_constraint->setBreakingImpulseThreshold(threshold); +} + +int CcdConstraint::GetIdentifier() const +{ + return m_constraint->getUserConstraintId(); +} + +PHY_ConstraintType CcdConstraint::GetType() const +{ + return (PHY_ConstraintType)m_constraint->getUserConstraintType(); +} diff --git a/source/gameengine/Physics/Bullet/CcdConstraint.h b/source/gameengine/Physics/Bullet/CcdConstraint.h new file mode 100644 index 000000000000..84a7e32cff47 --- /dev/null +++ b/source/gameengine/Physics/Bullet/CcdConstraint.h @@ -0,0 +1,39 @@ +#ifndef __CCD_CONSTRAINT_H__ +#define __CCD_CONSTRAINT_H__ + +#include "PHY_IConstraint.h" + +class btTypedConstraint; + +class CcdConstraint : public PHY_IConstraint +{ +private: + btTypedConstraint *m_constraint; + + /// Disable collision between constrained objects? + bool m_disableCollision; + /// The constraint is added in dynamic world? + bool m_active; + +public: + CcdConstraint(btTypedConstraint *constraint, bool disableCollision); + virtual ~CcdConstraint(); + + bool GetDisableCollision() const; + bool GetActive() const; + void SetActive(bool active); + + virtual bool GetEnabled() const; + virtual void SetEnabled(bool enabled); + + virtual void SetParam(int param, float value0, float value1); + virtual float GetParam(int param); + + virtual float GetBreakingThreshold() const; + virtual void SetBreakingThreshold(float threshold); + + virtual int GetIdentifier() const; + virtual PHY_ConstraintType GetType() const; +}; + +#endif // __CCD_CONSTRAINT_H__ diff --git a/source/gameengine/Physics/Bullet/CcdGraphicController.cpp b/source/gameengine/Physics/Bullet/CcdGraphicController.cpp index 8ddd4cbdada4..0a7c339ec2a0 100644 --- a/source/gameengine/Physics/Bullet/CcdGraphicController.cpp +++ b/source/gameengine/Physics/Bullet/CcdGraphicController.cpp @@ -2,84 +2,64 @@ * \ingroup physbullet */ /* -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. -*/ + 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 "CcdPhysicsEnvironment.h" #include "CcdGraphicController.h" #include "btBulletDynamicsCommon.h" -#include "MT_Point3.h" - -CcdGraphicController::CcdGraphicController (CcdPhysicsEnvironment* phyEnv, PHY_IMotionState* motionState) : - m_localAabbMin(0.f, 0.f, 0.f), - m_localAabbMax(0.f, 0.f, 0.f), +CcdGraphicController::CcdGraphicController(CcdPhysicsEnvironment *phyEnv, PHY_IMotionState *motionState) + :m_localAabbMin(0.0f, 0.0f, 0.0f), + m_localAabbMax(0.0f, 0.0f, 0.0f), m_motionState(motionState), m_phyEnv(phyEnv), - m_handle(NULL), - m_newClientInfo(NULL) + m_handle(nullptr), + m_newClientInfo(nullptr) { } CcdGraphicController::~CcdGraphicController() { - if (m_phyEnv) + if (m_phyEnv) { m_phyEnv->RemoveCcdGraphicController(this); + } - if (m_motionState) + if (m_motionState) { delete m_motionState; + } } -void CcdGraphicController::SetLocalAabb(const btVector3& aabbMin,const btVector3& aabbMax) +void CcdGraphicController::SetLocalAabb(const btVector3& aabbMin, const btVector3& aabbMax) { m_localAabbMin = aabbMin; m_localAabbMax = aabbMax; SetGraphicTransform(); } -void CcdGraphicController::SetLocalAabb(const MT_Point3& aabbMin,const MT_Point3& aabbMax) -{ - m_localAabbMin.setValue(aabbMin[0],aabbMin[1],aabbMin[2]); - m_localAabbMax.setValue(aabbMax[0],aabbMax[1],aabbMax[2]); - SetGraphicTransform(); -} - -void CcdGraphicController::SetLocalAabb(const MT_Vector3& aabbMin,const MT_Vector3& aabbMax) +void CcdGraphicController::SetLocalAabb(const mt::vec3& aabbMin, const mt::vec3& aabbMax) { - m_localAabbMin.setValue(aabbMin[0],aabbMin[1],aabbMin[2]); - m_localAabbMax.setValue(aabbMax[0],aabbMax[1],aabbMax[2]); - SetGraphicTransform(); -} - -void CcdGraphicController::SetLocalAabb(const float* aabbMin,const float* aabbMax) -{ - m_localAabbMin.setValue(aabbMin[0],aabbMin[1],aabbMin[2]); - m_localAabbMax.setValue(aabbMax[0],aabbMax[1],aabbMax[2]); + m_localAabbMin = ToBullet(aabbMin); + m_localAabbMax = ToBullet(aabbMax); SetGraphicTransform(); } void CcdGraphicController::GetAabb(btVector3& aabbMin, btVector3& aabbMax) { - btVector3 pos; - btVector3 scale; - float ori[12]; - m_motionState->GetWorldPosition(pos.m_floats[0],pos.m_floats[1],pos.m_floats[2]); - m_motionState->GetWorldScaling(scale.m_floats[0],scale.m_floats[1],scale.m_floats[2]); - m_motionState->GetWorldOrientation(ori); - btMatrix3x3 rot(ori[0], ori[4], ori[8], - ori[1], ori[5], ori[9], - ori[2], ori[6], ori[10]); + const btVector3 pos = ToBullet(m_motionState->GetWorldPosition()); + const btVector3 scale = ToBullet(m_motionState->GetWorldScaling()); + const btMatrix3x3 rot = ToBullet(m_motionState->GetWorldOrientation()); btVector3 localAabbMin = m_localAabbMin; btVector3 localAabbMax = m_localAabbMax; @@ -93,60 +73,62 @@ void CcdGraphicController::GetAabb(btVector3& aabbMin, btVector3& aabbMax) localAabbMax[1] = (scale.getY() <= 0.0f) ? tmpAabbMin[1] : tmpAabbMax[1]; localAabbMax[2] = (scale.getZ() <= 0.0f) ? tmpAabbMin[2] : tmpAabbMax[2]; - btVector3 localHalfExtents = btScalar(0.5f)*(localAabbMax-localAabbMin); - btVector3 localCenter = btScalar(0.5f)*(localAabbMax+localAabbMin); + btVector3 localHalfExtents = btScalar(0.5f) * (localAabbMax - localAabbMin); + btVector3 localCenter = btScalar(0.5f) * (localAabbMax + localAabbMin); btMatrix3x3 abs_b = rot.absolute(); - btVector3 center = rot*localCenter + pos; - btVector3 extent = abs_b*localHalfExtents; + btVector3 center = rot * localCenter + pos; + btVector3 extent = abs_b * localHalfExtents; aabbMin = center - extent; aabbMax = center + extent; } bool CcdGraphicController::SetGraphicTransform() { - if (!m_handle) + if (!m_handle) { return false; + } btVector3 aabbMin; btVector3 aabbMax; GetAabb(aabbMin, aabbMax); // update Aabb in broadphase - m_phyEnv->GetCullingTree()->setAabb(m_handle,aabbMin,aabbMax,NULL); + m_phyEnv->GetCullingTree()->setAabb(m_handle, aabbMin, aabbMax, nullptr); return true; } -PHY_IGraphicController* CcdGraphicController::GetReplica(class PHY_IMotionState* motionState) +PHY_IGraphicController *CcdGraphicController::GetReplica(class PHY_IMotionState *motionState) { - CcdGraphicController* replica = new CcdGraphicController(*this); + CcdGraphicController *replica = new CcdGraphicController(*this); replica->m_motionState = motionState; - replica->m_newClientInfo = NULL; - replica->m_handle = NULL; + replica->m_newClientInfo = nullptr; + replica->m_handle = nullptr; // don't add the graphic controller now: work around a bug in Bullet with rescaling, // (the scale of the controller is not yet defined). //m_phyEnv->addCcdGraphicController(replica); return replica; } -void CcdGraphicController::SetPhysicsEnvironment(class PHY_IPhysicsEnvironment* env) +void CcdGraphicController::SetPhysicsEnvironment(class PHY_IPhysicsEnvironment *env) { - CcdPhysicsEnvironment* phyEnv = static_cast(env); - /* Updates the m_phyEnv's m_cullingTree & m_cullingCache */ + CcdPhysicsEnvironment *phyEnv = static_cast(env); + // Updates the m_phyEnv's m_cullingTree & m_cullingCache if (GetBroadphaseHandle()) { - /* insert into the new physics scene */ + // insert into the new physics scene Activate(false); - m_phyEnv= phyEnv; + m_phyEnv = phyEnv; Activate(true); } else { - m_phyEnv= phyEnv; + m_phyEnv = phyEnv; } } void CcdGraphicController::Activate(bool active) { - if (active) + if (active) { m_phyEnv->AddCcdGraphicController(this); - else + } + else { m_phyEnv->RemoveCcdGraphicController(this); - + } } diff --git a/source/gameengine/Physics/Bullet/CcdGraphicController.h b/source/gameengine/Physics/Bullet/CcdGraphicController.h index d1ce61ca6727..a67549d522e9 100644 --- a/source/gameengine/Physics/Bullet/CcdGraphicController.h +++ b/source/gameengine/Physics/Bullet/CcdGraphicController.h @@ -1,17 +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. -*/ + 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. + */ /** \file CcdGraphicController.h * \ingroup physbullet @@ -27,31 +27,37 @@ subject to the following restrictions: #include "LinearMath/btTransform.h" #include "PHY_IMotionState.h" -#include "MT_Point3.h" class CcdPhysicsEnvironment; class btCollisionObject; ///CcdGraphicController is a graphic object that supports view frustrum culling and occlusion -class CcdGraphicController : public PHY_IGraphicController +class CcdGraphicController : public PHY_IGraphicController, public mt::SimdClassAllocator { public: - CcdGraphicController(CcdPhysicsEnvironment* phyEnv, PHY_IMotionState* motionState); + CcdGraphicController(CcdPhysicsEnvironment *phyEnv, PHY_IMotionState *motionState); virtual ~CcdGraphicController(); - void SetLocalAabb(const btVector3& aabbMin,const btVector3& aabbMax); - void SetLocalAabb(const MT_Point3& aabbMin,const MT_Point3& aabbMax); - virtual void SetLocalAabb(const MT_Vector3& aabbMin,const MT_Vector3& aabbMax); - virtual void SetLocalAabb(const float aabbMin[3],const float aabbMax[3]); + void SetLocalAabb(const btVector3& aabbMin, const btVector3& aabbMax); + virtual void SetLocalAabb(const mt::vec3& aabbMin, const mt::vec3& aabbMax); - PHY_IMotionState* GetMotionState() { return m_motionState; } + PHY_IMotionState *GetMotionState() + { + return m_motionState; + } void GetAabb(btVector3& aabbMin, btVector3& aabbMax); - virtual void SetBroadphaseHandle(btBroadphaseProxy* handle) { m_handle = handle; } - virtual btBroadphaseProxy* GetBroadphaseHandle() { return m_handle; } + virtual void SetBroadphaseHandle(btBroadphaseProxy *handle) + { + m_handle = handle; + } + virtual btBroadphaseProxy *GetBroadphaseHandle() + { + return m_handle; + } - virtual void SetPhysicsEnvironment(class PHY_IPhysicsEnvironment* env); + virtual void SetPhysicsEnvironment(class PHY_IPhysicsEnvironment *env); //////////////////////////////////// // PHY_IGraphicController interface @@ -67,24 +73,25 @@ class CcdGraphicController : public PHY_IGraphicController virtual void Activate(bool active); // client info for culling - virtual void* GetNewClientInfo() { return m_newClientInfo; } - virtual void SetNewClientInfo(void* clientinfo) { m_newClientInfo = clientinfo; } - virtual PHY_IGraphicController* GetReplica(class PHY_IMotionState* motionstate); + virtual void *GetNewClientInfo() + { + return m_newClientInfo; + } + virtual void SetNewClientInfo(void *clientinfo) + { + m_newClientInfo = clientinfo; + } + virtual PHY_IGraphicController *GetReplica(class PHY_IMotionState *motionstate); private: // unscaled aabb corner btVector3 m_localAabbMin; btVector3 m_localAabbMax; - PHY_IMotionState* m_motionState; - CcdPhysicsEnvironment* m_phyEnv; - btBroadphaseProxy* m_handle; - void* m_newClientInfo; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:CcdGraphicController") -#endif + PHY_IMotionState *m_motionState; + CcdPhysicsEnvironment *m_phyEnv; + btBroadphaseProxy *m_handle; + void *m_newClientInfo; }; #endif /* BULLET2_PHYSICSCONTROLLER_H */ diff --git a/source/gameengine/Physics/Bullet/CcdMathUtils.h b/source/gameengine/Physics/Bullet/CcdMathUtils.h new file mode 100644 index 000000000000..96351b5255b8 --- /dev/null +++ b/source/gameengine/Physics/Bullet/CcdMathUtils.h @@ -0,0 +1,54 @@ +#ifndef __CCD_MATH_UTILS__ +#define __CCD_MATH_UTILS__ + +#include "mathfu.h" + +#include "LinearMath/btVector3.h" +#include "LinearMath/btQuaternion.h" +#include "LinearMath/btMatrix3x3.h" + +inline mt::vec3 ToMt(const btVector3& vec) +{ + return mt::vec3(vec.x(), vec.y(), vec.z()); +} + +inline mt::vec4 ToMt(const btVector4& vec) +{ + return mt::vec4(vec.x(), vec.y(), vec.z(), vec.w()); +} + +inline mt::mat3 ToMt(const btMatrix3x3& mat) +{ + return mt::mat3(mat[0][0], mat[1][0], mat[2][0], + mat[0][1], mat[1][1], mat[2][1], + mat[0][2], mat[1][2], mat[2][2]); +} + +inline mt::quat ToMt(const btQuaternion& quat) +{ + return mt::quat(quat.w(), quat.x(), quat.y(), quat.z()); +} + +inline btVector3 ToBullet(const mt::vec3& vec) +{ + return btVector3(vec.x, vec.y, vec.z); +} + +inline btVector4 ToBullet(const mt::vec4& vec) +{ + return btVector4(vec.x, vec.y, vec.z, vec.w); +} + +inline btMatrix3x3 ToBullet(const mt::mat3& mat) +{ + return btMatrix3x3(mat(0, 0), mat(0, 1), mat(0, 2), + mat(1, 0), mat(1, 1), mat(1, 2), + mat(2, 0), mat(2, 1), mat(2, 2)); +} + +inline btQuaternion ToBullet(const mt::quat& quat) +{ + return btQuaternion(quat.x, quat.y, quat.z, quat.w); +} + +#endif // __CCD_MATH_UTILS__ diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp index e54a533ac95f..20602b56a138 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp @@ -2,24 +2,26 @@ * \ingroup physbullet */ /* -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. -*/ + 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 WIN32 #include #endif +#include "CM_Message.h" + #include "CcdPhysicsController.h" #include "btBulletDynamicsCommon.h" #include "BulletCollision/CollisionDispatch/btGhostObject.h" @@ -28,10 +30,13 @@ subject to the following restrictions: #include "PHY_IMotionState.h" #include "CcdPhysicsEnvironment.h" -#include "RAS_MeshObject.h" -#include "RAS_Polygon.h" + #include "RAS_Deformer.h" +#include "RAS_IMaterial.h" +#include "RAS_MaterialBucket.h" + #include "KX_GameObject.h" +#include "KX_Mesh.h" #include "BulletSoftBody/btSoftBody.h" #include "BulletSoftBody/btSoftBodyInternals.h" @@ -39,118 +44,164 @@ subject to the following restrictions: #include "LinearMath/btConvexHull.h" #include "BulletCollision/Gimpact/btGImpactShape.h" -#include "BulletSoftBody/btSoftRigidDynamicsWorld.h" - -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" - -extern "C"{ - #include "BLI_utildefines.h" - #include "BKE_cdderivedmesh.h" -} - +#include "BulletSoftBody/btSoftRigidDynamicsWorldMt.h" -class BP_Proxy; +#include "BLI_utildefines.h" -///todo: fill all the empty CcdPhysicsController methods, hook them up to the btRigidBody class +/// todo: fill all the empty CcdPhysicsController methods, hook them up to the btRigidBody class //'temporarily' global variables -//float gDeactivationTime = 2.f; -//bool gDisableDeactivation = false; extern float gDeactivationTime; extern bool gDisableDeactivation; - float gLinearSleepingTreshold; float gAngularSleepingTreshold; -BlenderBulletCharacterController::BlenderBulletCharacterController(btMotionState *motionState, btPairCachingGhostObject *ghost, btConvexShape* shape, float stepHeight) - : btKinematicCharacterController(ghost,shape,stepHeight,2), - m_motionState(motionState), - m_jumps(0), - m_maxJumps(1) +CcdCharacter::CcdCharacter(CcdPhysicsController *ctrl, btMotionState *motionState, + btGhostObject *ghost, btConvexShape *shape, float stepHeight) + :btKinematicCharacterController(ghost, shape, stepHeight, btVector3(0.0f, 0.0f, 1.0f)), + m_ctrl(ctrl), + m_motionState(motionState), + m_jumps(0), + m_maxJumps(1) { } -void BlenderBulletCharacterController::updateAction(btCollisionWorld *collisionWorld, btScalar dt) +void CcdCharacter::updateAction(btCollisionWorld *collisionWorld, btScalar dt) { - if (onGround()) + if (onGround()) { m_jumps = 0; + } - btKinematicCharacterController::updateAction(collisionWorld,dt); + btKinematicCharacterController::updateAction(collisionWorld, dt); m_motionState->setWorldTransform(getGhostObject()->getWorldTransform()); } -unsigned char BlenderBulletCharacterController::getMaxJumps() const +unsigned char CcdCharacter::getMaxJumps() const { return m_maxJumps; } -void BlenderBulletCharacterController::setMaxJumps(unsigned char maxJumps) +void CcdCharacter::setMaxJumps(unsigned char maxJumps) { m_maxJumps = maxJumps; } -unsigned char BlenderBulletCharacterController::getJumpCount() const +unsigned char CcdCharacter::getJumpCount() const { return m_jumps; } -bool BlenderBulletCharacterController::canJump() const +bool CcdCharacter::canJump() const { return (onGround() && m_maxJumps > 0) || m_jumps < m_maxJumps; } -void BlenderBulletCharacterController::jump() +void CcdCharacter::jump() { - if (!canJump()) + if (!canJump()) { return; + } m_verticalVelocity = m_jumpSpeed; m_wasJumping = true; m_jumps++; } -const btVector3& BlenderBulletCharacterController::getWalkDirection() +const btVector3& CcdCharacter::getWalkDirection() { return m_walkDirection; } +float CcdCharacter::GetFallSpeed() const +{ + return m_fallSpeed; +} + +void CcdCharacter::SetFallSpeed(float fallSpeed) +{ + setFallSpeed(fallSpeed); +} + +float CcdCharacter::GetMaxSlope() const +{ + return m_maxSlopeRadians; +} + +void CcdCharacter::SetMaxSlope(float maxSlope) +{ + setMaxSlope(maxSlope); +} + +float CcdCharacter::GetJumpSpeed() const +{ + return m_jumpSpeed; +} + +void CcdCharacter::SetJumpSpeed(float jumpSpeed) +{ + setJumpSpeed(jumpSpeed); +} + +void CcdCharacter::SetVelocity(const btVector3& vel, float time, bool local) +{ + btVector3 v = vel; + if (local) { + const btTransform xform = getGhostObject()->getWorldTransform(); + v = xform.getBasis() * v; + } + + // Avoid changing velocity and keeping previous time interval. + m_velocityTimeInterval = 0.0f; + + setVelocityForTimeInterval(v, time); +} + +void CcdCharacter::SetVelocity(const mt::vec3& vel, float time, bool local) +{ + SetVelocity(ToBullet(vel), time, local); +} + +void CcdCharacter::Reset() +{ + btCollisionWorld *world = m_ctrl->GetPhysicsEnvironment()->GetDynamicsWorld(); + reset(world); +} + bool CleanPairCallback::processOverlap(btBroadphasePair &pair) { if ((pair.m_pProxy0 == m_cleanProxy) || (pair.m_pProxy1 == m_cleanProxy)) { m_pairCache->cleanOverlappingPair(pair, m_dispatcher); - CcdPhysicsController *ctrl0 = (CcdPhysicsController*)(((btCollisionObject*)pair.m_pProxy0->m_clientObject)->getUserPointer()); - CcdPhysicsController *ctrl1 = (CcdPhysicsController*)(((btCollisionObject*)pair.m_pProxy1->m_clientObject)->getUserPointer()); + CcdPhysicsController *ctrl0 = (CcdPhysicsController *)(((btCollisionObject *)pair.m_pProxy0->m_clientObject)->getUserPointer()); + CcdPhysicsController *ctrl1 = (CcdPhysicsController *)(((btCollisionObject *)pair.m_pProxy1->m_clientObject)->getUserPointer()); ctrl0->GetCollisionObject()->activate(false); ctrl1->GetCollisionObject()->activate(false); } return false; } -CcdPhysicsController::CcdPhysicsController (const CcdConstructionInfo& ci) -:m_cci(ci) +CcdPhysicsController::CcdPhysicsController(const CcdConstructionInfo& ci) + :m_cci(ci) { - m_prototypeTransformInitialized = false; - m_softbodyMappingDone = false; - m_collisionDelay = 0; m_newClientInfo = 0; m_registerCount = 0; m_softBodyTransformInitialized = false; - m_parentCtrl = 0; + m_parentRoot = nullptr; // copy pointers locally to allow smart release m_MotionState = ci.m_MotionState; m_collisionShape = ci.m_collisionShape; // apply scaling before creating rigid body m_collisionShape->setLocalScaling(m_cci.m_scaling); - if (m_cci.m_mass) + if (m_cci.m_mass) { m_collisionShape->calculateLocalInertia(m_cci.m_mass, m_cci.m_localInertiaTensor); + } // shape info is shared, increment ref count m_shapeInfo = ci.m_shapeInfo; - if (m_shapeInfo) + if (m_shapeInfo) { m_shapeInfo->AddRef(); + } - m_bulletChildShape = NULL; + m_bulletChildShape = nullptr; m_bulletMotionState = 0; m_characterController = 0; @@ -164,19 +215,20 @@ CcdPhysicsController::CcdPhysicsController (const CcdConstructionInfo& ci) CreateRigidbody(); } -void CcdPhysicsController::addCcdConstraintRef(btTypedConstraint* c) +void CcdPhysicsController::addCcdConstraintRef(btTypedConstraint *c) { int index = m_ccdConstraintRefs.findLinearSearch(c); - if (index == m_ccdConstraintRefs.size()) + if (index == m_ccdConstraintRefs.size()) { m_ccdConstraintRefs.push_back(c); + } } -void CcdPhysicsController::removeCcdConstraintRef(btTypedConstraint* c) +void CcdPhysicsController::removeCcdConstraintRef(btTypedConstraint *c) { m_ccdConstraintRefs.remove(c); } -btTypedConstraint* CcdPhysicsController::getCcdConstraintRef(int index) +btTypedConstraint *CcdPhysicsController::getCcdConstraintRef(int index) { return m_ccdConstraintRefs[index]; } @@ -186,80 +238,68 @@ int CcdPhysicsController::getNumCcdConstraintRefs() const return m_ccdConstraintRefs.size(); } -btTransform& CcdPhysicsController::GetTransformFromMotionState(PHY_IMotionState* motionState) +btTransform CcdPhysicsController::GetTransformFromMotionState(PHY_IMotionState *motionState) { - static btTransform trans; - btVector3 tmp; - motionState->GetWorldPosition(tmp.m_floats[0], tmp.m_floats[1], tmp.m_floats[2]); - trans.setOrigin(tmp); - - float ori[12]; - motionState->GetWorldOrientation(ori); - trans.getBasis().setFromOpenGLSubMatrix(ori); - //btQuaternion orn; - //motionState->getWorldOrientation(orn[0],orn[1],orn[2],orn[3]); - //trans.setRotation(orn); - return trans; + const mt::vec3 pos = motionState->GetWorldPosition(); + const mt::mat3 mat = motionState->GetWorldOrientation(); + return btTransform(ToBullet(mat), ToBullet(pos)); } -class BlenderBulletMotionState : public btMotionState +class BlenderBulletMotionState : public btMotionState { - PHY_IMotionState* m_blenderMotionState; + PHY_IMotionState *m_blenderMotionState; public: - - BlenderBulletMotionState(PHY_IMotionState* bms) + BlenderBulletMotionState(PHY_IMotionState *bms) :m_blenderMotionState(bms) { - } - void getWorldTransform(btTransform& worldTrans ) const + void getWorldTransform(btTransform& worldTrans) const { - btVector3 pos; - float ori[12]; - - m_blenderMotionState->GetWorldPosition(pos.m_floats[0],pos.m_floats[1],pos.m_floats[2]); - m_blenderMotionState->GetWorldOrientation(ori); - worldTrans.setOrigin(pos); - worldTrans.getBasis().setFromOpenGLSubMatrix(ori); + const mt::vec3 pos = m_blenderMotionState->GetWorldPosition(); + const mt::mat3 mat = m_blenderMotionState->GetWorldOrientation(); + worldTrans.setOrigin(ToBullet(pos)); + worldTrans.setBasis(ToBullet(mat)); } - void setWorldTransform(const btTransform& worldTrans) + void setWorldTransform(const btTransform& worldTrans) { - m_blenderMotionState->SetWorldPosition(worldTrans.getOrigin().getX(),worldTrans.getOrigin().getY(),worldTrans.getOrigin().getZ()); - btQuaternion rotQuat = worldTrans.getRotation(); - m_blenderMotionState->SetWorldOrientation(rotQuat[0],rotQuat[1],rotQuat[2],rotQuat[3]); + m_blenderMotionState->SetWorldPosition(ToMt(worldTrans.getOrigin())); + m_blenderMotionState->SetWorldOrientation(ToMt(worldTrans.getBasis())); m_blenderMotionState->CalculateWorldTransformations(); } - }; -btRigidBody* CcdPhysicsController::GetRigidBody() +btRigidBody *CcdPhysicsController::GetRigidBody() { return btRigidBody::upcast(m_object); } -const btRigidBody* CcdPhysicsController::GetRigidBody() const +const btRigidBody *CcdPhysicsController::GetRigidBody() const { return btRigidBody::upcast(m_object); } -btCollisionObject* CcdPhysicsController::GetCollisionObject() +btCollisionObject *CcdPhysicsController::GetCollisionObject() { return m_object; } -btSoftBody* CcdPhysicsController::GetSoftBody() +btSoftBody *CcdPhysicsController::GetSoftBody() { return btSoftBody::upcast(m_object); } -btKinematicCharacterController* CcdPhysicsController::GetCharacterController() +btKinematicCharacterController *CcdPhysicsController::GetCharacterController() { return m_characterController; } -#include "BulletSoftBody/btSoftBodyHelpers.h" +const std::vector& CcdPhysicsController::GetSoftBodyIndices() const +{ + return m_softBodyIndices; +} +#include "BulletSoftBody/btSoftBodyHelpers.h" bool CcdPhysicsController::CreateSoftbody() { @@ -267,45 +307,42 @@ bool CcdPhysicsController::CreateSoftbody() //disable soft body until first sneak preview is ready if (!m_cci.m_bSoft || !m_cci.m_collisionShape || - ((shapeType != CONVEX_HULL_SHAPE_PROXYTYPE)&& - (shapeType != TRIANGLE_MESH_SHAPE_PROXYTYPE) && - (shapeType != SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE))) - { + ((shapeType != CONVEX_HULL_SHAPE_PROXYTYPE) && + (shapeType != TRIANGLE_MESH_SHAPE_PROXYTYPE) && + (shapeType != SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE))) { return false; } - btRigidBody::btRigidBodyConstructionInfo rbci(m_cci.m_mass,m_bulletMotionState,m_collisionShape,m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor); - rbci.m_linearDamping = m_cci.m_linearDamping; - rbci.m_angularDamping = m_cci.m_angularDamping; - rbci.m_friction = m_cci.m_friction; - rbci.m_restitution = m_cci.m_restitution; - - btVector3 p(0.0f,0.0f,0.0f);// = getOrigin(); - //btSoftBody* psb=btSoftBodyHelpers::CreateRope(worldInfo, btVector3(-10,0,i*0.25),btVector3(10,0,i*0.25), 16,1+2); - btSoftBody* psb = 0; + btSoftBody *psb = nullptr; btSoftBodyWorldInfo& worldInfo = m_cci.m_physicsEnv->GetDynamicsWorld()->getWorldInfo(); if (m_cci.m_collisionShape->getShapeType() == CONVEX_HULL_SHAPE_PROXYTYPE) { - btConvexHullShape* convexHull = (btConvexHullShape* )m_cci.m_collisionShape; + btConvexHullShape *convexHull = (btConvexHullShape *)m_cci.m_collisionShape; { int nvertices = convexHull->getNumPoints(); - const btVector3* vertices = convexHull->getPoints(); + const btVector3 *vertices = convexHull->getPoints(); - HullDesc hdsc(QF_TRIANGLES,nvertices,vertices); - HullResult hres; - HullLibrary hlib; /*??*/ - hdsc.mMaxVertices=nvertices; - hlib.CreateConvexHull(hdsc,hres); + HullDesc hdsc(QF_TRIANGLES, nvertices, vertices); + HullResult hres; + HullLibrary hlib; + hdsc.mMaxVertices = nvertices; + hlib.CreateConvexHull(hdsc, hres); psb = new btSoftBody(&worldInfo, (int)hres.mNumOutputVertices, &hres.m_OutputVertices[0], 0); for (int i = 0; i < (int)hres.mNumFaces; ++i) { const unsigned int idx[3] = {hres.m_Indices[i * 3 + 0], - hres.m_Indices[i * 3 + 1], - hres.m_Indices[i * 3 + 2]}; - if (idx[0] < idx[1]) psb->appendLink(idx[0], idx[1]); - if (idx[1] < idx[2]) psb->appendLink(idx[1], idx[2]); - if (idx[2] < idx[0]) psb->appendLink(idx[2], idx[0]); + hres.m_Indices[i * 3 + 1], + hres.m_Indices[i * 3 + 2]}; + if (idx[0] < idx[1]) { + psb->appendLink(idx[0], idx[1]); + } + if (idx[1] < idx[2]) { + psb->appendLink(idx[1], idx[2]); + } + if (idx[2] < idx[0]) { + psb->appendLink(idx[2], idx[0]); + } psb->appendFace(idx[0], idx[1], idx[2]); } hlib.ReleaseResult(hres); @@ -313,119 +350,108 @@ bool CcdPhysicsController::CreateSoftbody() } else { int numtris = 0; - if (m_cci.m_collisionShape->getShapeType() ==SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE) - { - btScaledBvhTriangleMeshShape* scaledtrimeshshape = (btScaledBvhTriangleMeshShape*) m_cci.m_collisionShape; - btBvhTriangleMeshShape* trimeshshape = scaledtrimeshshape->getChildShape(); + if (m_cci.m_collisionShape->getShapeType() == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE) { + btScaledBvhTriangleMeshShape *scaledtrimeshshape = (btScaledBvhTriangleMeshShape *)m_cci.m_collisionShape; + btBvhTriangleMeshShape *trimeshshape = scaledtrimeshshape->getChildShape(); ///only deal with meshes that have 1 sub part/component, for now - if (trimeshshape->getMeshInterface()->getNumSubParts()==1) - { - unsigned char* vertexBase; - btScalar* scaledVertexBase; + if (trimeshshape->getMeshInterface()->getNumSubParts() == 1) { + unsigned char *vertexBase; + btScalar *scaledVertexBase; btVector3 localScaling; PHY_ScalarType vertexType; int numverts; int vertexstride; - unsigned char* indexbase; + unsigned char *indexbase; int indexstride; PHY_ScalarType indexType; - trimeshshape->getMeshInterface()->getLockedVertexIndexBase(&vertexBase,numverts,vertexType,vertexstride,&indexbase,indexstride,numtris,indexType); + trimeshshape->getMeshInterface()->getLockedVertexIndexBase(&vertexBase, numverts, vertexType, vertexstride, &indexbase, indexstride, numtris, indexType); localScaling = scaledtrimeshshape->getLocalScaling(); - scaledVertexBase = new btScalar[numverts*3]; - for (int i=0; igetMeshInterface()->getNumSubParts()==1) - { - unsigned char* vertexBase; + if (trimeshshape->getMeshInterface()->getNumSubParts() == 1) { + unsigned char *vertexBase; PHY_ScalarType vertexType; int numverts; int vertexstride; - unsigned char* indexbase; + unsigned char *indexbase; int indexstride; PHY_ScalarType indexType; - trimeshshape->getMeshInterface()->getLockedVertexIndexBase(&vertexBase,numverts,vertexType,vertexstride,&indexbase,indexstride,numtris,indexType); + trimeshshape->getMeshInterface()->getLockedVertexIndexBase(&vertexBase, numverts, vertexType, vertexstride, &indexbase, indexstride, numtris, indexType); - psb = btSoftBodyHelpers::CreateFromTriMesh(worldInfo,(const btScalar*)vertexBase,(const int*)indexbase,numtris,false); + psb = btSoftBodyHelpers::CreateFromTriMesh(worldInfo, (const btScalar *)vertexBase, (const int *)indexbase, numtris, false); } } // store face tag so that we can find our original face when doing ray casting - btSoftBody::Face* ft; + btSoftBody::Face *ft; int i; - for (i=0, ft=&psb->m_faces[0]; im_faces[0]; i < numtris; ++i, ++ft) { // Hack!! use m_tag to store the face number, normally it is a pointer // add 1 to make sure it is never 0 - ft->m_tag = (void*)((uintptr_t)(i+1)); + ft->m_tag = (void *)((uintptr_t)(i + 1)); } } - if (m_cci.m_margin > 0.f) - { + if (m_cci.m_margin > 0.0f) { psb->getCollisionShape()->setMargin(m_cci.m_margin); psb->updateBounds(); } m_object = psb; - //btSoftBody::Material* pm=psb->appendMaterial(); - btSoftBody::Material* pm=psb->m_materials[0]; - pm->m_kLST = m_cci.m_soft_linStiff; - pm->m_kAST = m_cci.m_soft_angStiff; - pm->m_kVST = m_cci.m_soft_volume; + btSoftBody::Material *pm = psb->m_materials[0]; + pm->m_kLST = m_cci.m_soft_linStiff; + pm->m_kAST = m_cci.m_soft_angStiff; + pm->m_kVST = m_cci.m_soft_volume; psb->m_cfg.collisions = 0; - if (m_cci.m_soft_collisionflags & CCD_BSB_COL_CL_RS) - { - psb->m_cfg.collisions += btSoftBody::fCollision::CL_RS; - } else - { - psb->m_cfg.collisions += btSoftBody::fCollision::SDF_RS; + if (m_cci.m_soft_collisionflags & CCD_BSB_COL_CL_RS) { + psb->m_cfg.collisions += btSoftBody::fCollision::CL_RS; } - if (m_cci.m_soft_collisionflags & CCD_BSB_COL_CL_SS) - { + else { + psb->m_cfg.collisions += btSoftBody::fCollision::SDF_RS; + } + if (m_cci.m_soft_collisionflags & CCD_BSB_COL_CL_SS) { psb->m_cfg.collisions += btSoftBody::fCollision::CL_SS; - } else - { + } + else { psb->m_cfg.collisions += btSoftBody::fCollision::VF_SS; } + psb->m_cfg.kSRHR_CL = m_cci.m_soft_kSRHR_CL; // Soft vs rigid hardness [0,1] (cluster only) + psb->m_cfg.kSKHR_CL = m_cci.m_soft_kSKHR_CL; // Soft vs kinetic hardness [0,1] (cluster only) + psb->m_cfg.kSSHR_CL = m_cci.m_soft_kSSHR_CL; // Soft vs soft hardness [0,1] (cluster only) + psb->m_cfg.kSR_SPLT_CL = m_cci.m_soft_kSR_SPLT_CL; // Soft vs rigid impulse split [0,1] (cluster only) - psb->m_cfg.kSRHR_CL = m_cci.m_soft_kSRHR_CL; /* Soft vs rigid hardness [0,1] (cluster only) */ - psb->m_cfg.kSKHR_CL = m_cci.m_soft_kSKHR_CL; /* Soft vs kinetic hardness [0,1] (cluster only) */ - psb->m_cfg.kSSHR_CL = m_cci.m_soft_kSSHR_CL; /* Soft vs soft hardness [0,1] (cluster only) */ - psb->m_cfg.kSR_SPLT_CL = m_cci.m_soft_kSR_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ - - psb->m_cfg.kSK_SPLT_CL = m_cci.m_soft_kSK_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ - psb->m_cfg.kSS_SPLT_CL = m_cci.m_soft_kSS_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ - psb->m_cfg.kVCF = m_cci.m_soft_kVCF; /* Velocities correction factor (Baumgarte) */ - psb->m_cfg.kDP = m_cci.m_soft_kDP; /* Damping coefficient [0,1] */ + psb->m_cfg.kSK_SPLT_CL = m_cci.m_soft_kSK_SPLT_CL; // Soft vs rigid impulse split [0,1] (cluster only) + psb->m_cfg.kSS_SPLT_CL = m_cci.m_soft_kSS_SPLT_CL; // Soft vs rigid impulse split [0,1] (cluster only) + psb->m_cfg.kVCF = m_cci.m_soft_kVCF; // Velocities correction factor (Baumgarte) + psb->m_cfg.kDP = m_cci.m_soft_kDP; // Damping coefficient [0,1] - psb->m_cfg.kDG = m_cci.m_soft_kDG; /* Drag coefficient [0,+inf] */ - psb->m_cfg.kLF = m_cci.m_soft_kLF; /* Lift coefficient [0,+inf] */ - psb->m_cfg.kPR = m_cci.m_soft_kPR; /* Pressure coefficient [-inf,+inf] */ - psb->m_cfg.kVC = m_cci.m_soft_kVC; /* Volume conversation coefficient [0,+inf] */ + psb->m_cfg.kDG = m_cci.m_soft_kDG; // Drag coefficient [0,+inf] + psb->m_cfg.kLF = m_cci.m_soft_kLF; // Lift coefficient [0,+inf] + psb->m_cfg.kPR = m_cci.m_soft_kPR; // Pressure coefficient [-inf,+inf] + psb->m_cfg.kVC = m_cci.m_soft_kVC; // Volume conversation coefficient [0,+inf] - psb->m_cfg.kDF = m_cci.m_soft_kDF; /* Dynamic friction coefficient [0,1] */ - psb->m_cfg.kMT = m_cci.m_soft_kMT; /* Pose matching coefficient [0,1] */ - psb->m_cfg.kCHR = m_cci.m_soft_kCHR; /* Rigid contacts hardness [0,1] */ - psb->m_cfg.kKHR = m_cci.m_soft_kKHR; /* Kinetic contacts hardness [0,1] */ + psb->m_cfg.kDF = m_cci.m_soft_kDF; // Dynamic friction coefficient [0,1] + psb->m_cfg.kMT = m_cci.m_soft_kMT; // Pose matching coefficient [0,1] + psb->m_cfg.kCHR = m_cci.m_soft_kCHR; // Rigid contacts hardness [0,1] + psb->m_cfg.kKHR = m_cci.m_soft_kKHR; // Kinetic contacts hardness [0,1] - psb->m_cfg.kSHR = m_cci.m_soft_kSHR; /* Soft contacts hardness [0,1] */ - psb->m_cfg.kAHR = m_cci.m_soft_kAHR; /* Anchors hardness [0,1] */ + psb->m_cfg.kSHR = m_cci.m_soft_kSHR; // Soft contacts hardness [0,1] + psb->m_cfg.kAHR = m_cci.m_soft_kAHR; // Anchors hardness [0,1] - if (m_cci.m_gamesoftFlag & CCD_BSB_BENDING_CONSTRAINTS)//OB_SB_GOAL) - { - psb->generateBendingConstraints(2,pm); + if (m_cci.m_gamesoftFlag & CCD_BSB_BENDING_CONSTRAINTS) { + psb->generateBendingConstraints(m_cci.m_softBendingDistance, pm); } psb->m_cfg.piterations = m_cci.m_soft_piterations; @@ -433,95 +459,58 @@ bool CcdPhysicsController::CreateSoftbody() psb->m_cfg.diterations = m_cci.m_soft_diterations; psb->m_cfg.citerations = m_cci.m_soft_citerations; - if (m_cci.m_gamesoftFlag & CCD_BSB_SHAPE_MATCHING)//OB_SB_GOAL) - { - psb->setPose(false,true);// - } else - { - psb->setPose(true,false); + if (m_cci.m_gamesoftFlag & CCD_BSB_SHAPE_MATCHING) { + psb->setPose(false, true); + } + else { + psb->setPose(true, false); } psb->randomizeConstraints(); + psb->setTotalMass(m_cci.m_mass); - if (m_cci.m_soft_collisionflags & (CCD_BSB_COL_CL_RS+CCD_BSB_COL_CL_SS)) - { + if (m_cci.m_soft_collisionflags & (CCD_BSB_COL_CL_RS + CCD_BSB_COL_CL_SS)) { psb->generateClusters(m_cci.m_soft_numclusteriterations); } - psb->setTotalMass(m_cci.m_mass); psb->setCollisionFlags(0); - ///create a mapping between graphics mesh vertices and soft body vertices - { - RAS_MeshObject* rasMesh= GetShapeInfo()->GetMesh(); - - if (rasMesh && !m_softbodyMappingDone) - { - //printf("apply\n"); - RAS_MeshSlot::iterator it; - RAS_MeshMaterial *mmat; - RAS_MeshSlot *slot; - size_t i; - - //for each material - for (int m=0;mNumMaterials();m++) - { - mmat = rasMesh->GetMeshMaterial(m); - - slot = mmat->m_baseslot; - for (slot->begin(it); !slot->end(it); slot->next(it)) - { - int index = 0; - for (i=it.startvertex; isetSoftBodyIndex(0); - btScalar maxDistSqr = 1e30; - btSoftBody::tNodeArray& nodes(psb->m_nodes); - btVector3 xyz = btVector3(vertex->getXYZ()[0],vertex->getXYZ()[1],vertex->getXYZ()[2]); - for (int n=0;nsetSoftBodyIndex(n); - } - } - } - } - } + const unsigned int numVertices = m_shapeInfo->m_vertexRemap.size(); + m_softBodyIndices.resize(numVertices); + for (unsigned int i = 0; i < numVertices; ++i) { + const unsigned int index = m_shapeInfo->m_vertexRemap[i]; + if (index == -1) { + m_softBodyIndices[i] = 0; + continue; } + const float *co = &m_shapeInfo->m_vertexArray[index * 3]; + m_softBodyIndices[i] = Ccd_FindClosestNode(psb, btVector3(co[0], co[1], co[2])); } - m_softbodyMappingDone = true; btTransform startTrans; - rbci.m_motionState->getWorldTransform(startTrans); + m_bulletMotionState->getWorldTransform(startTrans); - m_MotionState->SetWorldPosition(startTrans.getOrigin().getX(),startTrans.getOrigin().getY(),startTrans.getOrigin().getZ()); - m_MotionState->SetWorldOrientation(0,0,0,1); + m_MotionState->SetWorldPosition(ToMt(startTrans.getOrigin())); + m_MotionState->SetWorldOrientation(mt::mat3::Identity()); + + psb->transform(startTrans); - if (!m_prototypeTransformInitialized) - { - m_prototypeTransformInitialized = true; - m_softBodyTransformInitialized = true; - psb->transform(startTrans); - } m_object->setCollisionFlags(m_object->getCollisionFlags() | m_cci.m_collisionFlags); - if (m_cci.m_do_anisotropic) + if (m_cci.m_do_anisotropic) { m_object->setAnisotropicFriction(m_cci.m_anisotropicFriction); + } + return true; } bool CcdPhysicsController::CreateCharacterController() { - if (!m_cci.m_bCharacter) + if (!m_cci.m_bCharacter) { return false; + } - m_object = new btPairCachingGhostObject(); + m_object = new btGhostObject(); m_object->setCollisionShape(m_collisionShape); m_object->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); @@ -529,31 +518,34 @@ bool CcdPhysicsController::CreateCharacterController() m_bulletMotionState->getWorldTransform(trans); m_object->setWorldTransform(trans); - m_characterController = new BlenderBulletCharacterController(m_bulletMotionState,(btPairCachingGhostObject*)m_object,(btConvexShape*)m_collisionShape,m_cci.m_stepHeight); + m_characterController = new CcdCharacter(this, m_bulletMotionState, (btGhostObject *)m_object, + (btConvexShape *)m_collisionShape, m_cci.m_stepHeight); m_characterController->setJumpSpeed(m_cci.m_jumpSpeed); m_characterController->setFallSpeed(m_cci.m_fallSpeed); m_characterController->setMaxJumps(m_cci.m_maxJumps); + m_characterController->setMaxSlope(m_cci.m_maxSlope); return true; } void CcdPhysicsController::CreateRigidbody() { - //btTransform trans = GetTransformFromMotionState(m_MotionState); m_bulletMotionState = new BlenderBulletMotionState(m_MotionState); ///either create a btCollisionObject, btRigidBody or btSoftBody - if (CreateSoftbody() || CreateCharacterController()) + if (CreateSoftbody() || CreateCharacterController()) { // soft body created, done return; + } //create a rgid collision object - btRigidBody::btRigidBodyConstructionInfo rbci(m_cci.m_mass,m_bulletMotionState,m_collisionShape,m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor); + btRigidBody::btRigidBodyConstructionInfo rbci(m_cci.m_mass, m_bulletMotionState, m_collisionShape, m_cci.m_localInertiaTensor *m_cci.m_inertiaFactor); rbci.m_linearDamping = m_cci.m_linearDamping; rbci.m_angularDamping = m_cci.m_angularDamping; rbci.m_friction = m_cci.m_friction; + rbci.m_rollingFriction = m_cci.m_rollingFriction; rbci.m_restitution = m_cci.m_restitution; m_object = new btRigidBody(rbci); @@ -565,24 +557,21 @@ void CcdPhysicsController::CreateRigidbody() //convert collision flags! //special case: a near/radar sensor controller should not be defined static or it will //generate loads of static-static collision messages on the console - if (m_cci.m_bSensor) - { + if (m_cci.m_bSensor) { // reset the flags that have been set so far - GetCollisionObject()->setCollisionFlags(0); + m_object->setCollisionFlags(0); // sensor must never go to sleep: they need to detect continously - GetCollisionObject()->setActivationState(DISABLE_DEACTIVATION); + m_object->setActivationState(DISABLE_DEACTIVATION); } - GetCollisionObject()->setCollisionFlags(m_object->getCollisionFlags() | m_cci.m_collisionFlags); - btRigidBody* body = GetRigidBody(); + m_object->setCollisionFlags(m_object->getCollisionFlags() | m_cci.m_collisionFlags); + btRigidBody *body = GetRigidBody(); - if (body) - { - body->setGravity( m_cci.m_gravity); + if (body) { + body->setGravity(m_cci.m_gravity); body->setDamping(m_cci.m_linearDamping, m_cci.m_angularDamping); - if (!m_cci.m_bRigid) - { - body->setAngularFactor(0.f); + if (!m_cci.m_bRigid) { + body->setAngularFactor(0.0f); } // use bullet's default contact processing theshold, blender's old default of 1 is too small here. // if there's really a need to change this, it should be exposed in the ui first. @@ -590,41 +579,54 @@ void CcdPhysicsController::CreateRigidbody() body->setSleepingThresholds(gLinearSleepingTreshold, gAngularSleepingTreshold); } - if (m_object && m_cci.m_do_anisotropic) - { + if (m_object && m_cci.m_do_anisotropic) { m_object->setAnisotropicFriction(m_cci.m_anisotropicFriction); } +} + +mt::vec3 CcdPhysicsController::GetGravity() +{ + btRigidBody *body = GetRigidBody(); + if (body) { + return ToMt(body->getGravity()); + } + return mt::zero3; +} +void CcdPhysicsController::SetGravity(const mt::vec3 &gravity) +{ + btRigidBody *body = GetRigidBody(); + if (body) { + body->setGravity(ToBullet(gravity)); + } } -static void DeleteBulletShape(btCollisionShape* shape, bool free) +static void DeleteBulletShape(btCollisionShape *shape, bool free) { if (shape->getShapeType() == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE) { /* If we use Bullet scaled shape (btScaledBvhTriangleMeshShape) we have to * free the child of the unscaled shape (btTriangleMeshShape) here. */ btTriangleMeshShape *meshShape = ((btScaledBvhTriangleMeshShape *)shape)->getChildShape(); - if (meshShape) + if (meshShape) { delete meshShape; + } } if (free) { delete shape; } } -bool CcdPhysicsController::DeleteControllerShape( ) +bool CcdPhysicsController::DeleteControllerShape() { - if (m_collisionShape) - { + if (m_collisionShape) { // collision shape is always unique to the controller, can delete it here - if (m_collisionShape->isCompound()) - { + if (m_collisionShape->isCompound()) { // bullet does not delete the child shape, must do it here - btCompoundShape* compoundShape = (btCompoundShape*)m_collisionShape; + btCompoundShape *compoundShape = (btCompoundShape *)m_collisionShape; int numChild = compoundShape->getNumChildShapes(); - for (int i=numChild-1 ; i >= 0; i--) - { - btCollisionShape* childShape = compoundShape->getChildShape(i); + for (int i = numChild - 1; i >= 0; i--) { + btCollisionShape *childShape = compoundShape->getChildShape(i); DeleteBulletShape(childShape, true); } } @@ -638,12 +640,14 @@ bool CcdPhysicsController::DeleteControllerShape( ) bool CcdPhysicsController::ReplaceControllerShape(btCollisionShape *newShape) { - if (m_collisionShape) + if (m_collisionShape) { DeleteControllerShape(); + } - // If newShape is NULL it means to create a new Bullet shape. - if (!newShape) + // If newShape is nullptr it means to create a new Bullet shape. + if (!newShape) { newShape = m_shapeInfo->CreateBulletShape(m_cci.m_margin, m_cci.m_bGimpact, !m_cci.m_bSoft); + } m_object->setCollisionShape(newShape); m_collisionShape = newShape; @@ -651,20 +655,18 @@ bool CcdPhysicsController::ReplaceControllerShape(btCollisionShape *newShape) btSoftBody *softBody = GetSoftBody(); if (softBody) { - btSoftRigidDynamicsWorld *world = GetPhysicsEnvironment()->GetDynamicsWorld(); + btSoftRigidDynamicsWorldMt *world = m_cci.m_physicsEnv->GetDynamicsWorld(); // remove the old softBody world->removeSoftBody(softBody); // soft body must be recreated delete m_object; - m_object = NULL; + m_object = nullptr; // force complete reinitialization - m_softbodyMappingDone = false; - m_prototypeTransformInitialized = false; m_softBodyTransformInitialized = false; CreateSoftbody(); - assert(m_object); + BLI_assert(m_object); btSoftBody *newSoftBody = GetSoftBody(); // set the user @@ -679,21 +681,24 @@ bool CcdPhysicsController::ReplaceControllerShape(btCollisionShape *newShape) CcdPhysicsController::~CcdPhysicsController() { //will be reference counted, due to sharing - if (m_cci.m_physicsEnv) - m_cci.m_physicsEnv->RemoveCcdPhysicsController(this); + if (m_cci.m_physicsEnv) { + m_cci.m_physicsEnv->RemoveCcdPhysicsController(this, true); + } - if (m_MotionState) + if (m_MotionState) { delete m_MotionState; - if (m_bulletMotionState) + } + if (m_bulletMotionState) { delete m_bulletMotionState; - if (m_characterController) + } + if (m_characterController) { delete m_characterController; + } delete m_object; DeleteControllerShape(); - if (m_shapeInfo) - { + if (m_shapeInfo) { m_shapeInfo->Release(); } } @@ -701,18 +706,21 @@ CcdPhysicsController::~CcdPhysicsController() void CcdPhysicsController::SimulationTick(float timestep) { btRigidBody *body = GetRigidBody(); - if (!body || body->isStaticObject()) + if (!body || body->isStaticObject()) { return; + } // Clamp linear velocity if (m_cci.m_clamp_vel_max > 0.0f || m_cci.m_clamp_vel_min > 0.0f) { const btVector3 &linvel = body->getLinearVelocity(); btScalar len = linvel.length(); - if (m_cci.m_clamp_vel_max > 0.0f && len > m_cci.m_clamp_vel_max) + if (m_cci.m_clamp_vel_max > 0.0f && len > m_cci.m_clamp_vel_max) { body->setLinearVelocity(linvel * (m_cci.m_clamp_vel_max / len)); - else if (m_cci.m_clamp_vel_min > 0.0f && !btFuzzyZero(len) && len < m_cci.m_clamp_vel_min) + } + else if (m_cci.m_clamp_vel_min > 0.0f && !btFuzzyZero(len) && len < m_cci.m_clamp_vel_min) { body->setLinearVelocity(linvel * (m_cci.m_clamp_vel_min / len)); + } } // Clamp angular velocity @@ -720,197 +728,160 @@ void CcdPhysicsController::SimulationTick(float timestep) const btVector3 &angvel = body->getAngularVelocity(); btScalar len = angvel.length(); - if (m_cci.m_clamp_angvel_max > 0.0f && len > m_cci.m_clamp_angvel_max) + if (m_cci.m_clamp_angvel_max > 0.0f && len > m_cci.m_clamp_angvel_max) { body->setAngularVelocity(angvel * (m_cci.m_clamp_angvel_max / len)); - else if (m_cci.m_clamp_angvel_min > 0.0f && !btFuzzyZero(len) && len < m_cci.m_clamp_angvel_min) + } + else if (m_cci.m_clamp_angvel_min > 0.0f && !btFuzzyZero(len) && len < m_cci.m_clamp_angvel_min) { body->setAngularVelocity(angvel * (m_cci.m_clamp_angvel_min / len)); + } } } - /** * SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding') */ -bool CcdPhysicsController::SynchronizeMotionStates(float time) +bool CcdPhysicsController::SynchronizeMotionStates(float time) { //sync non-static to motionstate, and static from motionstate (todo: add kinematic etc.) - btSoftBody* sb = GetSoftBody(); - if (sb) - { - if (sb->m_pose.m_bframe) - { + btSoftBody *sb = GetSoftBody(); + if (sb) { + if (sb->m_pose.m_bframe) { btVector3 worldPos = sb->m_pose.m_com; btQuaternion worldquat; - btMatrix3x3 trs = sb->m_pose.m_rot*sb->m_pose.m_scl; + btMatrix3x3 trs = sb->m_pose.m_rot * sb->m_pose.m_scl; trs.getRotation(worldquat); - m_MotionState->SetWorldPosition(worldPos[0],worldPos[1],worldPos[2]); - m_MotionState->SetWorldOrientation(worldquat[0],worldquat[1],worldquat[2],worldquat[3]); + m_MotionState->SetWorldPosition(ToMt(worldPos)); + m_MotionState->SetWorldOrientation(ToMt(worldquat)); } - else - { - btVector3 aabbMin,aabbMax; - sb->getAabb(aabbMin,aabbMax); - btVector3 worldPos = (aabbMax+aabbMin)*0.5f; - m_MotionState->SetWorldPosition(worldPos[0],worldPos[1],worldPos[2]); + else { + btVector3 aabbMin, aabbMax; + sb->getAabb(aabbMin, aabbMax); + btVector3 worldPos = (aabbMax + aabbMin) * 0.5f; + m_MotionState->SetWorldPosition(ToMt(worldPos)); } m_MotionState->CalculateWorldTransformations(); return true; } - btRigidBody* body = GetRigidBody(); + btRigidBody *body = GetRigidBody(); - if (body && !body->isStaticObject()) - { + if (body && !body->isStaticObject()) { const btTransform& xform = body->getCenterOfMassTransform(); const btMatrix3x3& worldOri = xform.getBasis(); const btVector3& worldPos = xform.getOrigin(); - float ori[12]; - worldOri.getOpenGLSubMatrix(ori); - m_MotionState->SetWorldOrientation(ori); - m_MotionState->SetWorldPosition(worldPos[0],worldPos[1],worldPos[2]); + m_MotionState->SetWorldOrientation(ToMt(worldOri)); + m_MotionState->SetWorldPosition(ToMt(worldPos)); m_MotionState->CalculateWorldTransformations(); + } - float scale[3]; - m_MotionState->GetWorldScaling(scale[0],scale[1],scale[2]); - btVector3 scaling(scale[0],scale[1],scale[2]); - GetCollisionShape()->setLocalScaling(scaling); - } else - { - btVector3 worldPos; - btQuaternion worldquat; - -/* m_MotionState->getWorldPosition(worldPos[0],worldPos[1],worldPos[2]); - m_MotionState->getWorldOrientation(worldquat[0],worldquat[1],worldquat[2],worldquat[3]); - btTransform oldTrans = m_body->getCenterOfMassTransform(); - btTransform newTrans(worldquat,worldPos); - - SetCenterOfMassTransform(newTrans); - //need to keep track of previous position for friction effects... + const mt::vec3& scale = m_MotionState->GetWorldScaling(); + GetCollisionShape()->setLocalScaling(ToBullet(scale)); - m_MotionState->calculateWorldTransformations(); -*/ - float scale[3]; - m_MotionState->GetWorldScaling(scale[0],scale[1],scale[2]); - btVector3 scaling(scale[0],scale[1],scale[2]); - GetCollisionShape()->setLocalScaling(scaling); - } return true; - } - /** - * WriteMotionStateToDynamics synchronizes dynas, kinematic and deformable entities (and do 'late binding') - */ +/** + * WriteMotionStateToDynamics synchronizes dynas, kinematic and deformable entities (and do 'late binding') + */ -void CcdPhysicsController::WriteMotionStateToDynamics(bool nondynaonly) +void CcdPhysicsController::WriteMotionStateToDynamics(bool nondynaonly) { - btTransform& xform = CcdPhysicsController::GetTransformFromMotionState(m_MotionState); + btTransform xform = CcdPhysicsController::GetTransformFromMotionState(m_MotionState); SetCenterOfMassTransform(xform); } -void CcdPhysicsController::WriteDynamicsToMotionState() +void CcdPhysicsController::WriteDynamicsToMotionState() { } - // controller replication -void CcdPhysicsController::PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl) +// controller replication +void CcdPhysicsController::PostProcessReplica(class PHY_IMotionState *motionstate, class PHY_IPhysicsController *parentctrl) { - SetParentCtrl((CcdPhysicsController*)parentctrl); - m_softBodyTransformInitialized=false; + SetParentRoot((CcdPhysicsController *)parentctrl); + m_softBodyTransformInitialized = false; m_MotionState = motionstate; m_registerCount = 0; - m_collisionShape = NULL; + m_collisionShape = nullptr; // Clear all old constraints. m_ccdConstraintRefs.clear(); // always create a new shape to avoid scaling bug - if (m_shapeInfo) - { + if (m_shapeInfo) { m_shapeInfo->AddRef(); m_collisionShape = m_shapeInfo->CreateBulletShape(m_cci.m_margin, m_cci.m_bGimpact, !m_cci.m_bSoft); - if (m_collisionShape) - { + if (m_collisionShape) { // new shape has no scaling, apply initial scaling //m_collisionShape->setMargin(m_cci.m_margin); m_collisionShape->setLocalScaling(m_cci.m_scaling); - if (m_cci.m_mass) + if (m_cci.m_mass) { m_collisionShape->calculateLocalInertia(m_cci.m_mass, m_cci.m_localInertiaTensor); + } } } // load some characterists that are not - btRigidBody* oldbody = GetRigidBody(); - m_object = 0; + btRigidBody *oldbody = GetRigidBody(); + m_object = nullptr; CreateRigidbody(); - btRigidBody* body = GetRigidBody(); - if (body) - { - if (m_cci.m_mass) - { + btRigidBody *body = GetRigidBody(); + if (body) { + if (m_cci.m_mass) { body->setMassProps(m_cci.m_mass, m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor); } - if (oldbody) - { + if (oldbody) { body->setLinearFactor(oldbody->getLinearFactor()); body->setAngularFactor(oldbody->getAngularFactor()); - if (oldbody->getActivationState() == DISABLE_DEACTIVATION) + if (oldbody->getActivationState() == DISABLE_DEACTIVATION) { body->setActivationState(DISABLE_DEACTIVATION); + } } } // sensor object are added when needed - if (!m_cci.m_bSensor) + if (!m_cci.m_bSensor) { m_cci.m_physicsEnv->AddCcdPhysicsController(this); - - + } } -void CcdPhysicsController::SetPhysicsEnvironment(class PHY_IPhysicsEnvironment *env) +void CcdPhysicsController::SetPhysicsEnvironment(class PHY_IPhysicsEnvironment *env) { // can safely assume CCD environment - CcdPhysicsEnvironment *physicsEnv = static_cast(env); + CcdPhysicsEnvironment *physicsEnv = static_cast(env); - if (m_cci.m_physicsEnv != physicsEnv) - { + if (m_cci.m_physicsEnv != physicsEnv) { // since the environment is changing, we must also move the controler to the // new environment. Note that we don't handle sensor explicitly: this // function can be called on sensor but only when they are not registered - if (m_cci.m_physicsEnv->RemoveCcdPhysicsController(this)) - { + if (m_cci.m_physicsEnv->RemoveCcdPhysicsController(this, true)) { physicsEnv->AddCcdPhysicsController(this); // Set the object to be active so it can at least by evaluated once. // This fixes issues with static objects not having their physics meshes // in the right spot when lib loading. - this->GetCollisionObject()->setActivationState(ACTIVE_TAG); + m_object->setActivationState(ACTIVE_TAG); } m_cci.m_physicsEnv = physicsEnv; } } -void CcdPhysicsController::SetCenterOfMassTransform(btTransform& xform) +void CcdPhysicsController::SetCenterOfMassTransform(btTransform& xform) { - btRigidBody* body = GetRigidBody(); - if (body) - { + btRigidBody *body = GetRigidBody(); + if (body) { body->setCenterOfMassTransform(xform); - } else - { + } + else { //either collision object or soft body? - if (GetSoftBody()) - { - - } else - { - - if (m_object->isStaticOrKinematicObject()) - { + if (GetSoftBody()) { + } + else { + if (m_object->isStaticOrKinematicObject()) { m_object->setInterpolationWorldTransform(m_object->getWorldTransform()); - } else - { + } + else { m_object->setInterpolationWorldTransform(xform); } m_object->setWorldTransform(xform); @@ -918,157 +889,132 @@ void CcdPhysicsController::SetCenterOfMassTransform(btTransform& xform) } } - // kinematic methods -void CcdPhysicsController::RelativeTranslate(const MT_Vector3& dlocin,bool local) +// kinematic methods +void CcdPhysicsController::RelativeTranslate(const mt::vec3& dlocin, bool local) { - if (m_object) - { + if (m_object) { m_object->activate(true); - if (m_object->isStaticObject()) - { - if (!m_cci.m_bSensor) + if (m_object->isStaticObject()) { + if (!m_cci.m_bSensor) { m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + } // kinematic object should not set the transform, it disturbs the velocity interpolation return; } - btVector3 dloc(dlocin.x(), dlocin.y(), dlocin.z()); + btVector3 dloc = ToBullet(dlocin); btTransform xform = m_object->getWorldTransform(); - if (local) - dloc = xform.getBasis()*dloc; + if (local) { + dloc = xform.getBasis() * dloc; + } xform.setOrigin(xform.getOrigin() + dloc); SetCenterOfMassTransform(xform); } - } -void CcdPhysicsController::RelativeRotate(const MT_Matrix3x3& rotval,bool local) +void CcdPhysicsController::RelativeRotate(const mt::mat3& rotval, bool local) { - if (m_object) - { + if (m_object) { m_object->activate(true); - if (m_object->isStaticObject()) - { - if (!m_cci.m_bSensor) + if (m_object->isStaticObject()) { + if (!m_cci.m_bSensor) { m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + } // kinematic object should not set the transform, it disturbs the velocity interpolation return; } - btMatrix3x3 drotmat(rotval[0].x(), rotval[0].y(), rotval[0].z(), - rotval[1].x(), rotval[1].y(), rotval[1].z(), - rotval[2].x(), rotval[2].y(), rotval[2].z()); - - + btMatrix3x3 drotmat = ToBullet(rotval); btMatrix3x3 currentOrn; GetWorldOrientation(currentOrn); btTransform xform = m_object->getWorldTransform(); - xform.setBasis(xform.getBasis()*(local ? - drotmat : (currentOrn.inverse() * drotmat * currentOrn))); + xform.setBasis(xform.getBasis() * (local ? + drotmat : (currentOrn.inverse() * drotmat * currentOrn))); SetCenterOfMassTransform(xform); } } - void CcdPhysicsController::GetWorldOrientation(btMatrix3x3& mat) { - float ori[12]; - m_MotionState->GetWorldOrientation(ori); - mat.setFromOpenGLSubMatrix(ori); + const mt::mat3 ori = m_MotionState->GetWorldOrientation(); + mat = ToBullet(ori); } -MT_Matrix3x3 CcdPhysicsController::GetOrientation() +mt::mat3 CcdPhysicsController::GetOrientation() { - btMatrix3x3 orn = m_object->getWorldTransform().getBasis(); - return MT_Matrix3x3(orn[0][0], orn[0][1], orn[0][2], orn[1][0], orn[1][1], orn[1][2], orn[2][0], orn[2][1], orn[2][2]); + const btMatrix3x3 orn = m_object->getWorldTransform().getBasis(); + return ToMt(orn); } -void CcdPhysicsController::SetOrientation(const MT_Matrix3x3& orn) +void CcdPhysicsController::SetOrientation(const mt::mat3& orn) { - btMatrix3x3 btmat(orn[0][0], orn[0][1], orn[0][2], orn[1][0], orn[1][1], orn[1][2], orn[2][0], orn[2][1], orn[2][2]); - SetWorldOrientation(btmat); + SetWorldOrientation(ToBullet(orn)); } void CcdPhysicsController::SetWorldOrientation(const btMatrix3x3& orn) { - if (m_object) - { + if (m_object) { m_object->activate(true); - if (m_object->isStaticObject() && !m_cci.m_bSensor) - { + if (m_object->isStaticObject() && !m_cci.m_bSensor) { m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); } - // not required - //m_MotionState->setWorldOrientation(quatImag0,quatImag1,quatImag2,quatReal); btTransform xform = m_object->getWorldTransform(); xform.setBasis(orn); SetCenterOfMassTransform(xform); - // not required - //m_bulletMotionState->setWorldTransform(xform); + //only once! - if (!m_softBodyTransformInitialized && GetSoftBody()) - { + if (!m_softBodyTransformInitialized && GetSoftBody()) { m_softbodyStartTrans.setBasis(orn); xform.setOrigin(m_softbodyStartTrans.getOrigin()); GetSoftBody()->transform(xform); m_softBodyTransformInitialized = true; } - } - } -void CcdPhysicsController::SetPosition(const MT_Vector3& pos) +void CcdPhysicsController::SetPosition(const mt::vec3& pos) { - if (m_object) - { + if (m_object) { m_object->activate(true); - if (m_object->isStaticObject()) - { - if (!m_cci.m_bSensor) + if (m_object->isStaticObject()) { + if (!m_cci.m_bSensor) { m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + } // kinematic object should not set the transform, it disturbs the velocity interpolation return; } - // not required, this function is only used to update the physic controller - //m_MotionState->setWorldPosition(posX,posY,posZ); + btTransform xform = m_object->getWorldTransform(); - xform.setOrigin(btVector3(pos.x(), pos.y(), pos.z())); + xform.setOrigin(ToBullet(pos)); SetCenterOfMassTransform(xform); - if (!m_softBodyTransformInitialized) + if (!m_softBodyTransformInitialized) { m_softbodyStartTrans.setOrigin(xform.getOrigin()); - // not required - //m_bulletMotionState->setWorldTransform(xform); + } } } void CcdPhysicsController::ForceWorldTransform(const btMatrix3x3& mat, const btVector3& pos) { - if (m_object) - { + if (m_object) { btTransform& xform = m_object->getWorldTransform(); xform.setBasis(mat); xform.setOrigin(pos); } } - -void CcdPhysicsController::ResolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ) -{ -} - void CcdPhysicsController::RefreshCollisions() { // the object is in an inactive layer so it's useless to update it and can cause problems - if (!GetPhysicsEnvironment()->IsActiveCcdPhysicsController(this)) + if (IsPhysicsSuspended()) { return; + } - btSoftRigidDynamicsWorld *dw = GetPhysicsEnvironment()->GetDynamicsWorld(); + btDynamicsWorld *dw = m_cci.m_physicsEnv->GetDynamicsWorld(); btBroadphaseProxy *proxy = m_object->getBroadphaseHandle(); btDispatcher *dispatcher = dw->getDispatcher(); btOverlappingPairCache *pairCache = dw->getPairCache(); @@ -1077,16 +1023,25 @@ void CcdPhysicsController::RefreshCollisions() pairCache->processAllOverlappingPairs(&cleanPairs, dispatcher); // Forcibly recreate the physics object - btBroadphaseProxy* handle = m_object->getBroadphaseHandle(); - GetPhysicsEnvironment()->UpdateCcdPhysicsController(this, GetMass(), m_object->getCollisionFlags(), handle->m_collisionFilterGroup, handle->m_collisionFilterMask); + btBroadphaseProxy *handle = m_object->getBroadphaseHandle(); + m_cci.m_physicsEnv->UpdateCcdPhysicsController(this, GetMass(), m_object->getCollisionFlags(), handle->m_collisionFilterGroup, handle->m_collisionFilterMask); +} + +void CcdPhysicsController::SuspendPhysics(bool freeConstraints) +{ + m_cci.m_physicsEnv->RemoveCcdPhysicsController(this, freeConstraints); } -void CcdPhysicsController::SuspendDynamics(bool ghost) +void CcdPhysicsController::RestorePhysics() +{ + m_cci.m_physicsEnv->AddCcdPhysicsController(this); +} + +void CcdPhysicsController::SuspendDynamics(bool ghost) { btRigidBody *body = GetRigidBody(); - if (body && !m_suspended && !GetConstructionInfo().m_bSensor && GetPhysicsEnvironment()->IsActiveCcdPhysicsController(this)) - { - btBroadphaseProxy* handle = body->getBroadphaseHandle(); + if (body && !m_suspended && !m_cci.m_bSensor && !IsPhysicsSuspended()) { + btBroadphaseProxy *handle = body->getBroadphaseHandle(); m_savedCollisionFlags = body->getCollisionFlags(); m_savedMass = GetMass(); @@ -1094,148 +1049,132 @@ void CcdPhysicsController::SuspendDynamics(bool ghost) m_savedCollisionFilterGroup = handle->m_collisionFilterGroup; m_savedCollisionFilterMask = handle->m_collisionFilterMask; m_suspended = true; - GetPhysicsEnvironment()->UpdateCcdPhysicsController(this, - 0.0f, - btCollisionObject::CF_STATIC_OBJECT|((ghost)?btCollisionObject::CF_NO_CONTACT_RESPONSE:(m_savedCollisionFlags&btCollisionObject::CF_NO_CONTACT_RESPONSE)), - btBroadphaseProxy::StaticFilter, - btBroadphaseProxy::AllFilter ^ btBroadphaseProxy::StaticFilter); + m_cci.m_physicsEnv->UpdateCcdPhysicsController(this, + 0.0f, + btCollisionObject::CF_STATIC_OBJECT | ((ghost) ? btCollisionObject::CF_NO_CONTACT_RESPONSE : (m_savedCollisionFlags & btCollisionObject::CF_NO_CONTACT_RESPONSE)), + btBroadphaseProxy::StaticFilter, + btBroadphaseProxy::AllFilter ^ btBroadphaseProxy::StaticFilter); m_cci.m_bDyna = false; } } -void CcdPhysicsController::RestoreDynamics() +void CcdPhysicsController::RestoreDynamics() { btRigidBody *body = GetRigidBody(); - if (body && m_suspended && GetPhysicsEnvironment()->IsActiveCcdPhysicsController(this)) - { + if (body && m_suspended && !IsPhysicsSuspended()) { // before make sure any position change that was done in this logic frame are accounted for SetTransform(); - GetPhysicsEnvironment()->UpdateCcdPhysicsController(this, - m_savedMass, - m_savedCollisionFlags, - m_savedCollisionFilterGroup, - m_savedCollisionFilterMask); + m_cci.m_physicsEnv->UpdateCcdPhysicsController(this, + m_savedMass, + m_savedCollisionFlags, + m_savedCollisionFilterGroup, + m_savedCollisionFilterMask); body->activate(); m_cci.m_bDyna = m_savedDyna; m_suspended = false; } } -void CcdPhysicsController::GetPosition(MT_Vector3& pos) const +mt::vec3 CcdPhysicsController::GetPosition() const { - const btTransform& xform = m_object->getWorldTransform(); - pos[0] = xform.getOrigin().x(); - pos[1] = xform.getOrigin().y(); - pos[2] = xform.getOrigin().z(); + return ToMt(m_object->getWorldTransform().getOrigin()); } -void CcdPhysicsController::SetScaling(const MT_Vector3& scale) +void CcdPhysicsController::SetScaling(const mt::vec3& scale) { - if (!btFuzzyZero(m_cci.m_scaling.x()-scale.x()) || - !btFuzzyZero(m_cci.m_scaling.y()-scale.y()) || - !btFuzzyZero(m_cci.m_scaling.z()-scale.z())) - { - m_cci.m_scaling = btVector3(scale.x(),scale.y(),scale.z()); + if (!btFuzzyZero(m_cci.m_scaling.x() - scale.x) || + !btFuzzyZero(m_cci.m_scaling.y() - scale.y) || + !btFuzzyZero(m_cci.m_scaling.z() - scale.z)) { + m_cci.m_scaling = ToBullet(scale); - if (m_object && m_object->getCollisionShape()) - { + if (m_object && m_object->getCollisionShape()) { m_object->activate(true); // without this, sleeping objects scale wont be applied in bullet if python changes the scale - Campbell. m_object->getCollisionShape()->setLocalScaling(m_cci.m_scaling); - //printf("no inertia recalc for fixed objects with mass=0\n"); - btRigidBody* body = GetRigidBody(); - if (body && m_cci.m_mass) - { + btRigidBody *body = GetRigidBody(); + if (body && m_cci.m_mass) { body->getCollisionShape()->calculateLocalInertia(m_cci.m_mass, m_cci.m_localInertiaTensor); body->setMassProps(m_cci.m_mass, m_cci.m_localInertiaTensor * m_cci.m_inertiaFactor); } - } } } void CcdPhysicsController::SetTransform() { - btVector3 pos; - btVector3 scale; - float ori[12]; - m_MotionState->GetWorldPosition(pos.m_floats[0],pos.m_floats[1],pos.m_floats[2]); - m_MotionState->GetWorldScaling(scale.m_floats[0],scale.m_floats[1],scale.m_floats[2]); - m_MotionState->GetWorldOrientation(ori); - btMatrix3x3 rot(ori[0], ori[4], ori[8], - ori[1], ori[5], ori[9], - ori[2], ori[6], ori[10]); - ForceWorldTransform(rot, pos); - - if (!IsDynamic() && !GetConstructionInfo().m_bSensor && !GetCharacterController()) - { - btCollisionObject* object = GetRigidBody(); + const mt::vec3 pos = m_MotionState->GetWorldPosition(); + const mt::mat3 rot = m_MotionState->GetWorldOrientation(); + ForceWorldTransform(ToBullet(rot), ToBullet(pos)); + + if (!IsDynamic() && !GetConstructionInfo().m_bSensor && !m_characterController) { + btCollisionObject *object = GetRigidBody(); object->setActivationState(ACTIVE_TAG); object->setCollisionFlags(object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); } } -MT_Scalar CcdPhysicsController::GetMass() +float CcdPhysicsController::GetMass() { - if (GetSoftBody()) + if (GetSoftBody()) { return GetSoftBody()->getTotalMass(); + } - MT_Scalar invmass = 0.f; - if (GetRigidBody()) + float invmass = 0.0f; + if (GetRigidBody()) { invmass = GetRigidBody()->getInvMass(); - if (invmass) - return 1.f/invmass; - return 0.f; - + } + if (invmass) { + return 1.0f / invmass; + } + return 0.0f; } -void CcdPhysicsController::SetMass(MT_Scalar newmass) +void CcdPhysicsController::SetMass(float newmass) { btRigidBody *body = GetRigidBody(); - if (body && !m_suspended && newmass>MT_EPSILON && GetMass()>MT_EPSILON) - { - btBroadphaseProxy* handle = body->getBroadphaseHandle(); - GetPhysicsEnvironment()->UpdateCcdPhysicsController(this, - newmass, - body->getCollisionFlags(), - handle->m_collisionFilterGroup, - handle->m_collisionFilterMask); + if (body && !m_suspended && !IsPhysicsSuspended() && (!mt::FuzzyZero(newmass) && !mt::FuzzyZero(GetMass()))) { + btBroadphaseProxy *handle = body->getBroadphaseHandle(); + m_cci.m_physicsEnv->UpdateCcdPhysicsController(this, + newmass, + body->getCollisionFlags(), + handle->m_collisionFilterGroup, + handle->m_collisionFilterMask); } } - // physics methods -void CcdPhysicsController::ApplyTorque(const MT_Vector3& torquein,bool local) +float CcdPhysicsController::GetInertiaFactor() const +{ + return m_cci.m_inertiaFactor; +} + +// physics methods +void CcdPhysicsController::ApplyTorque(const mt::vec3& torquein, bool local) { - btVector3 torque(torquein.x(),torquein.y(),torquein.z()); + btVector3 torque = ToBullet(torquein); btTransform xform = m_object->getWorldTransform(); - if (m_object && torque.length2() > (SIMD_EPSILON*SIMD_EPSILON)) - { - btRigidBody* body = GetRigidBody(); + if (m_object && torque.length2() > (SIMD_EPSILON * SIMD_EPSILON)) { + btRigidBody *body = GetRigidBody(); m_object->activate(); - if (m_object->isStaticObject()) - { - if (!m_cci.m_bSensor) + if (m_object->isStaticObject()) { + if (!m_cci.m_bSensor) { m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + } return; } - if (local) - { - torque = xform.getBasis()*torque; + if (local) { + torque = xform.getBasis() * torque; } - if (body) - { - if (m_cci.m_bRigid) - { + if (body) { + if (m_cci.m_bRigid) { body->applyTorque(torque); } - else - { + else { //workaround for incompatibility between 'DYNAMIC' game object, and angular factor //a DYNAMIC object has some inconsistency: it has no angular effect due to collisions, but still has torque const btVector3 angFac = body->getAngularFactor(); - btVector3 tmpFac(1,1,1); + btVector3 tmpFac(1.0f, 1.0f, 1.0f); body->setAngularFactor(tmpFac); body->applyTorque(torque); body->setAngularFactor(angFac); @@ -1244,290 +1183,301 @@ void CcdPhysicsController::ApplyTorque(const MT_Vector3& torquein,bool local) } } -void CcdPhysicsController::ApplyForce(const MT_Vector3& forcein,bool local) +void CcdPhysicsController::ApplyForce(const mt::vec3& forcein, bool local) { - btVector3 force(forcein.x(),forcein.y(),forcein.z()); - + btVector3 force = ToBullet(forcein); - if (m_object && force.length2() > (SIMD_EPSILON*SIMD_EPSILON)) - { + if (m_object && force.length2() > (SIMD_EPSILON * SIMD_EPSILON)) { m_object->activate(); - if (m_object->isStaticObject()) - { - if (!m_cci.m_bSensor) + if (m_object->isStaticObject()) { + if (!m_cci.m_bSensor) { m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + } return; } btTransform xform = m_object->getWorldTransform(); - if (local) - { - force = xform.getBasis()*force; + if (local) { + force = xform.getBasis() * force; } - btRigidBody* body = GetRigidBody(); - if (body) + btRigidBody *body = GetRigidBody(); + if (body) { body->applyCentralForce(force); - btSoftBody* soft = GetSoftBody(); - if (soft) - { + } + btSoftBody *soft = GetSoftBody(); + if (soft) { // the force is applied on each node, must reduce it in the same extend - if (soft->m_nodes.size() > 0) + if (soft->m_nodes.size() > 0) { force /= soft->m_nodes.size(); + } soft->addForce(force); } } } -void CcdPhysicsController::SetAngularVelocity(const MT_Vector3& ang_vel,bool local) +void CcdPhysicsController::SetAngularVelocity(const mt::vec3& ang_vel, bool local) { - btVector3 angvel(ang_vel.x(),ang_vel.y(),ang_vel.z()); + btVector3 angvel = ToBullet(ang_vel); /* Refuse tiny tiny velocities, as they might cause instabilities. */ float vel_squared = angvel.length2(); - if (vel_squared > 0 && vel_squared <= (SIMD_EPSILON*SIMD_EPSILON)) - angvel = btVector3(0, 0, 0); + if (vel_squared > 0.0f && vel_squared <= (SIMD_EPSILON * SIMD_EPSILON)) { + angvel = btVector3(0.0f, 0.0f, 0.0f); + } - if (m_object) - { + if (m_object) { m_object->activate(true); - if (m_object->isStaticObject()) - { - if (!m_cci.m_bSensor) + if (m_object->isStaticObject()) { + if (!m_cci.m_bSensor) { m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + } return; } btTransform xform = m_object->getWorldTransform(); - if (local) - { - angvel = xform.getBasis()*angvel; + if (local) { + angvel = xform.getBasis() * angvel; } - btRigidBody* body = GetRigidBody(); - if (body) + btRigidBody *body = GetRigidBody(); + if (body) { body->setAngularVelocity(angvel); + } } - } -void CcdPhysicsController::SetLinearVelocity(const MT_Vector3& lin_vel,bool local) +void CcdPhysicsController::SetLinearVelocity(const mt::vec3& lin_vel, bool local) { - btVector3 linVel(lin_vel.x(),lin_vel.y(),lin_vel.z()); + btVector3 linVel = ToBullet(lin_vel); /* Refuse tiny tiny velocities, as they might cause instabilities. */ - float vel_squared = linVel.length2(); - if (vel_squared > 0 && vel_squared <= (SIMD_EPSILON*SIMD_EPSILON)) - linVel = btVector3(0, 0, 0); + const float vel_squared = linVel.length2(); + if (vel_squared > 0.0f && vel_squared <= (SIMD_EPSILON * SIMD_EPSILON)) { + linVel = btVector3(0.0f, 0.0f, 0.0f); + } - if (m_object) - { + if (m_object) { m_object->activate(true); - if (m_object->isStaticObject()) - { - if (!m_cci.m_bSensor) + if (m_object->isStaticObject()) { + if (!m_cci.m_bSensor) { m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + } return; } - btSoftBody* soft = GetSoftBody(); - if (soft) - { - if (local) - { - linVel = m_softbodyStartTrans.getBasis()*linVel; + btSoftBody *soft = GetSoftBody(); + if (soft) { + if (local) { + linVel = m_softbodyStartTrans.getBasis() * linVel; } soft->setVelocity(linVel); - } else - { + } + else { btTransform xform = m_object->getWorldTransform(); - if (local) - { - linVel = xform.getBasis()*linVel; + if (local) { + linVel = xform.getBasis() * linVel; } - btRigidBody* body = GetRigidBody(); - if (body) + btRigidBody *body = GetRigidBody(); + if (body) { body->setLinearVelocity(linVel); + } } } } -void CcdPhysicsController::ApplyImpulse(const MT_Point3& attach, const MT_Vector3& impulsein, bool local) +void CcdPhysicsController::ApplyImpulse(const mt::vec3& attach, const mt::vec3& impulsein, bool local) { - btVector3 pos; - btVector3 impulse(impulsein.x(), impulsein.y(), impulsein.z()); + btVector3 impulse = ToBullet(impulsein); - if (m_object && impulse.length2() > (SIMD_EPSILON*SIMD_EPSILON)) - { + if (m_object && impulse.length2() > (SIMD_EPSILON * SIMD_EPSILON)) { m_object->activate(); - if (m_object->isStaticObject()) - { - if (!m_cci.m_bSensor) + if (m_object->isStaticObject()) { + if (!m_cci.m_bSensor) { m_object->setCollisionFlags(m_object->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + } return; } - btTransform xform = m_object->getWorldTransform(); + const btTransform xform = m_object->getWorldTransform(); + btVector3 pos; - if (local) - { - pos = btVector3(attach.x(), attach.y(), attach.z()); + if (local) { + pos = ToBullet(attach); impulse = xform.getBasis() * impulse; } else { /* If the point of impulse application is not equal to the object position * then an angular momentum is generated in the object*/ - pos = btVector3(attach.x()-xform.getOrigin().x(), attach.y()-xform.getOrigin().y(), attach.z()-xform.getOrigin().z()); + pos = ToBullet(attach) - xform.getOrigin(); } - btRigidBody* body = GetRigidBody(); - if (body) - body->applyImpulse(impulse,pos); - + btRigidBody *body = GetRigidBody(); + if (body) { + body->applyImpulse(impulse, pos); + } } } -void CcdPhysicsController::Jump() +void CcdPhysicsController::Jump() { - if (m_object && m_characterController) + if (m_object && m_characterController) { m_characterController->jump(); + } +} + +void CcdPhysicsController::SetActive(bool active) +{ } -void CcdPhysicsController::SetActive(bool active) +unsigned short CcdPhysicsController::GetCollisionGroup() const { + return m_cci.m_collisionGroup; } -float CcdPhysicsController::GetLinearDamping() const +unsigned short CcdPhysicsController::GetCollisionMask() const { - const btRigidBody* body = GetRigidBody(); - if (body) + return m_cci.m_collisionMask; +} + +void CcdPhysicsController::SetCollisionGroup(unsigned short group) +{ + m_cci.m_collisionGroup = group; +} + +void CcdPhysicsController::SetCollisionMask(unsigned short mask) +{ + m_cci.m_collisionMask = mask; +} + +float CcdPhysicsController::GetLinearDamping() const +{ + const btRigidBody *body = GetRigidBody(); + if (body) { return body->getLinearDamping(); - return 0; + } + return 0.0f; } -float CcdPhysicsController::GetAngularDamping() const +float CcdPhysicsController::GetAngularDamping() const { - const btRigidBody* body = GetRigidBody(); - if (body) + const btRigidBody *body = GetRigidBody(); + if (body) { return body->getAngularDamping(); - return 0; + } + return 0.0f; } -void CcdPhysicsController::SetLinearDamping(float damping) +void CcdPhysicsController::SetLinearDamping(float damping) { SetDamping(damping, GetAngularDamping()); } -void CcdPhysicsController::SetAngularDamping(float damping) +void CcdPhysicsController::SetAngularDamping(float damping) { SetDamping(GetLinearDamping(), damping); } -void CcdPhysicsController::SetDamping(float linear, float angular) +void CcdPhysicsController::SetDamping(float linear, float angular) { - btRigidBody* body = GetRigidBody(); - if (!body) return; + btRigidBody *body = GetRigidBody(); + if (!body) { + return; + } body->setDamping(linear, angular); } - - // reading out information from physics -MT_Vector3 CcdPhysicsController::GetLinearVelocity() +// reading out information from physics +mt::vec3 CcdPhysicsController::GetLinearVelocity() { - btRigidBody* body = GetRigidBody(); - if (body) - { + btRigidBody *body = GetRigidBody(); + if (body) { const btVector3& linvel = body->getLinearVelocity(); - return MT_Vector3(linvel.x(), linvel.y(), linvel.z()); + return ToMt(linvel); } - return MT_Vector3(0.f, 0.f, 0.f); + return mt::zero3; } -MT_Vector3 CcdPhysicsController::GetAngularVelocity() +mt::vec3 CcdPhysicsController::GetAngularVelocity() { - btRigidBody* body = GetRigidBody(); - if (body) - { - const btVector3& angvel= body->getAngularVelocity(); - return MT_Vector3(angvel.x(), angvel.y(), angvel.z()); + btRigidBody *body = GetRigidBody(); + if (body) { + const btVector3& angvel = body->getAngularVelocity(); + return ToMt(angvel); } - return MT_Vector3(0.f, 0.f, 0.f); + return mt::zero3; } -MT_Vector3 CcdPhysicsController::GetVelocity(const MT_Point3 &posin) +mt::vec3 CcdPhysicsController::GetVelocity(const mt::vec3 &posin) { - btVector3 pos(posin.x(), posin.y(), posin.z()); - btRigidBody* body = GetRigidBody(); - if (body) - { - btVector3 linvel = body->getVelocityInLocalPoint(pos); - return MT_Vector3(linvel.x(), linvel.y(), linvel.z()); + btRigidBody *body = GetRigidBody(); + if (body) { + btVector3 linvel = body->getVelocityInLocalPoint(ToBullet(posin)); + return ToMt(linvel); } - return MT_Vector3(0.f, 0.f, 0.f); + return mt::zero3; } -MT_Vector3 CcdPhysicsController::GetLocalInertia() +mt::vec3 CcdPhysicsController::GetLocalInertia() { - MT_Vector3 inertia(0.f, 0.f, 0.f); - btVector3 inv_inertia; - if (GetRigidBody()) { - inv_inertia = GetRigidBody()->getInvInertiaDiagLocal(); + btRigidBody *body = GetRigidBody(); + mt::vec3 inertia = mt::zero3; + if (body) { + const btVector3 inv_inertia = body->getInvInertiaDiagLocal(); if (!btFuzzyZero(inv_inertia.getX()) && - !btFuzzyZero(inv_inertia.getY()) && - !btFuzzyZero(inv_inertia.getZ())) - inertia = MT_Vector3(1.f/inv_inertia.getX(), 1.f/inv_inertia.getY(), 1.f/inv_inertia.getZ()); + !btFuzzyZero(inv_inertia.getY()) && + !btFuzzyZero(inv_inertia.getZ())) { + inertia = mt::vec3(1.0f / inv_inertia.getX(), 1.0f / inv_inertia.getY(), 1.0f / inv_inertia.getZ()); + } } return inertia; } - // dyna's that are rigidbody are free in orientation, dyna's with non-rigidbody are restricted -void CcdPhysicsController::SetRigidBody(bool rigid) +// dyna's that are rigidbody are free in orientation, dyna's with non-rigidbody are restricted +void CcdPhysicsController::SetRigidBody(bool rigid) { - btRigidBody* body = GetRigidBody(); - if (body) - { + btRigidBody *body = GetRigidBody(); + if (body) { m_cci.m_bRigid = rigid; if (!rigid) { - body->setAngularFactor(0.f); - body->setAngularVelocity(btVector3(0.f, 0.f, 0.f)); + body->setAngularFactor(0.0f); + body->setAngularVelocity(btVector3(0.0f, 0.0f, 0.0f)); } - else + else { body->setAngularFactor(m_cci.m_angularFactor); + } } } - // clientinfo for raycasts for example -void* CcdPhysicsController::GetNewClientInfo() +// clientinfo for raycasts for example +void *CcdPhysicsController::GetNewClientInfo() { return m_newClientInfo; } -void CcdPhysicsController::SetNewClientInfo(void* clientinfo) + +void CcdPhysicsController::SetNewClientInfo(void *clientinfo) { m_newClientInfo = clientinfo; - if (m_cci.m_bSensor) - { + if (m_cci.m_bSensor) { // use a different callback function for sensor object, // bullet will not synchronize, we must do it explicitly - SG_Callbacks& callbacks = KX_GameObject::GetClientObject((KX_ClientObjectInfo*)clientinfo)->GetSGNode()->GetCallBackFunctions(); + SG_Callbacks& callbacks = KX_GameObject::GetClientObject((KX_ClientObjectInfo *)clientinfo)->GetNode()->GetCallBackFunctions(); callbacks.m_updatefunc = KX_GameObject::SynchronizeTransformFunc; } } - -void CcdPhysicsController::UpdateDeactivation(float timeStep) +void CcdPhysicsController::UpdateDeactivation(float timeStep) { - btRigidBody* body = GetRigidBody(); - if (body) - { - body->updateDeactivation( timeStep); + btRigidBody *body = GetRigidBody(); + if (body) { + body->updateDeactivation(timeStep); } } bool CcdPhysicsController::WantsSleeping() { - btRigidBody* body = GetRigidBody(); - if (body) - { + btRigidBody *body = GetRigidBody(); + if (body) { return body->wantsSleeping(); } //check it out @@ -1537,168 +1487,167 @@ bool CcdPhysicsController::WantsSleeping() * the current controller shape provided it is a compound shape. * The idea is that dynamic parenting on a compound object will dynamically extend the shape */ -void CcdPhysicsController::AddCompoundChild(PHY_IPhysicsController* child) +void CcdPhysicsController::AddCompoundChild(PHY_IPhysicsController *child) { - if (child == NULL || !IsCompound()) + if (child == nullptr || !IsCompound()) { return; + } // other controller must be a bullet controller too // verify that body and shape exist and match - CcdPhysicsController* childCtrl = dynamic_cast(child); - btRigidBody* rootBody = GetRigidBody(); - btRigidBody* childBody = childCtrl->GetRigidBody(); - if (!rootBody || !childBody) + CcdPhysicsController *childCtrl = static_cast(child); + btRigidBody *rootBody = GetRigidBody(); + btRigidBody *childBody = childCtrl->GetRigidBody(); + if (!rootBody || !childBody) { return; - const btCollisionShape* rootShape = rootBody->getCollisionShape(); - const btCollisionShape* childShape = childBody->getCollisionShape(); + } + const btCollisionShape *rootShape = rootBody->getCollisionShape(); + const btCollisionShape *childShape = childBody->getCollisionShape(); if (!rootShape || - !childShape || - rootShape->getShapeType() != COMPOUND_SHAPE_PROXYTYPE) + !childShape || + rootShape->getShapeType() != COMPOUND_SHAPE_PROXYTYPE) { return; - btCompoundShape* compoundShape = (btCompoundShape*)rootShape; + } + btCompoundShape *compoundShape = (btCompoundShape *)rootShape; + // compute relative transformation between parent and child btTransform rootTrans; btTransform childTrans; rootBody->getMotionState()->getWorldTransform(rootTrans); childBody->getMotionState()->getWorldTransform(childTrans); btVector3 rootScale = rootShape->getLocalScaling(); - rootScale[0] = 1.0f/rootScale[0]; - rootScale[1] = 1.0f/rootScale[1]; - rootScale[2] = 1.0f/rootScale[2]; + rootScale[0] = 1.0 / rootScale[0]; + rootScale[1] = 1.0 / rootScale[1]; + rootScale[2] = 1.0 / rootScale[2]; // relative scale = child_scale/parent_scale - btVector3 relativeScale = childShape->getLocalScaling()*rootScale; - btMatrix3x3 rootRotInverse = rootTrans.getBasis().transpose(); + const btVector3 relativeScale = childShape->getLocalScaling() * rootScale; + const btMatrix3x3 rootRotInverse = rootTrans.getBasis().transpose(); // relative pos = parent_rot^-1 * ((parent_pos-child_pos)/parent_scale) - btVector3 relativePos = rootRotInverse*((childTrans.getOrigin()-rootTrans.getOrigin())*rootScale); + const btVector3 relativePos = rootRotInverse * ((childTrans.getOrigin() - rootTrans.getOrigin()) * rootScale); // relative rot = parent_rot^-1 * child_rot - btMatrix3x3 relativeRot = rootRotInverse*childTrans.getBasis(); + const btMatrix3x3 relativeRot = rootRotInverse * childTrans.getBasis(); + // create a proxy shape info to store the transformation - CcdShapeConstructionInfo* proxyShapeInfo = new CcdShapeConstructionInfo(); + CcdShapeConstructionInfo *proxyShapeInfo = new CcdShapeConstructionInfo(); // store the transformation to this object shapeinfo proxyShapeInfo->m_childTrans.setOrigin(relativePos); proxyShapeInfo->m_childTrans.setBasis(relativeRot); - proxyShapeInfo->m_childScale.setValue(relativeScale[0], relativeScale[1], relativeScale[2]); + proxyShapeInfo->m_childScale = relativeScale; // we will need this to make sure that we remove the right proxy later when unparenting proxyShapeInfo->m_userData = childCtrl; proxyShapeInfo->SetProxy(childCtrl->GetShapeInfo()->AddRef()); // add to parent compound shapeinfo (increments ref count) GetShapeInfo()->AddShape(proxyShapeInfo); // create new bullet collision shape from the object shapeinfo and set scaling - btCollisionShape* newChildShape = proxyShapeInfo->CreateBulletShape(childCtrl->GetMargin(), childCtrl->GetConstructionInfo().m_bGimpact, true); + btCollisionShape *newChildShape = proxyShapeInfo->CreateBulletShape(childCtrl->GetMargin(), childCtrl->GetConstructionInfo().m_bGimpact, true); newChildShape->setLocalScaling(relativeScale); // add bullet collision shape to parent compound collision shape - compoundShape->addChildShape(proxyShapeInfo->m_childTrans,newChildShape); + compoundShape->addChildShape(proxyShapeInfo->m_childTrans, newChildShape); // proxyShapeInfo is not needed anymore, release it proxyShapeInfo->Release(); // remember we created this shape childCtrl->m_bulletChildShape = newChildShape; - // recompute inertia of parent - if (!rootBody->isStaticOrKinematicObject()) - { + + // Recalculate inertia for object owning compound shape. + if (!rootBody->isStaticOrKinematicObject()) { btVector3 localInertia; - float mass = 1.f/rootBody->getInvMass(); - compoundShape->calculateLocalInertia(mass,localInertia); - rootBody->setMassProps(mass,localInertia); + const float mass = 1.0f / rootBody->getInvMass(); + compoundShape->calculateLocalInertia(mass, localInertia); + rootBody->setMassProps(mass, localInertia * m_cci.m_inertiaFactor); } // must update the broadphase cache, - GetPhysicsEnvironment()->RefreshCcdPhysicsController(this); + m_cci.m_physicsEnv->RefreshCcdPhysicsController(this); // remove the children - GetPhysicsEnvironment()->RemoveCcdPhysicsController(childCtrl); + m_cci.m_physicsEnv->RemoveCcdPhysicsController(childCtrl, true); } /* Reverse function of the above, it will remove a shape from a compound shape * provided that the former was added to the later using AddCompoundChild() */ -void CcdPhysicsController::RemoveCompoundChild(PHY_IPhysicsController* child) +void CcdPhysicsController::RemoveCompoundChild(PHY_IPhysicsController *child) { - if (child == NULL || !IsCompound()) + if (!child || !IsCompound()) { return; + } // other controller must be a bullet controller too // verify that body and shape exist and match - CcdPhysicsController* childCtrl = dynamic_cast(child); - btRigidBody* rootBody = GetRigidBody(); - btRigidBody* childBody = childCtrl->GetRigidBody(); - if (!rootBody || !childBody) + CcdPhysicsController *childCtrl = static_cast(child); + btRigidBody *rootBody = GetRigidBody(); + btRigidBody *childBody = childCtrl->GetRigidBody(); + if (!rootBody || !childBody) { return; - const btCollisionShape* rootShape = rootBody->getCollisionShape(); + } + const btCollisionShape *rootShape = rootBody->getCollisionShape(); if (!rootShape || - rootShape->getShapeType() != COMPOUND_SHAPE_PROXYTYPE) + rootShape->getShapeType() != COMPOUND_SHAPE_PROXYTYPE) { return; - btCompoundShape* compoundShape = (btCompoundShape*)rootShape; + } + btCompoundShape *compoundShape = (btCompoundShape *)rootShape; // retrieve the shapeInfo - CcdShapeConstructionInfo* childShapeInfo = childCtrl->GetShapeInfo(); - CcdShapeConstructionInfo* rootShapeInfo = GetShapeInfo(); + CcdShapeConstructionInfo *childShapeInfo = childCtrl->GetShapeInfo(); + CcdShapeConstructionInfo *rootShapeInfo = GetShapeInfo(); // and verify that the child is part of the parent int i = rootShapeInfo->FindChildShape(childShapeInfo, childCtrl); - if (i < 0) + if (i < 0) { return; + } rootShapeInfo->RemoveChildShape(i); - if (childCtrl->m_bulletChildShape) - { + if (childCtrl->m_bulletChildShape) { int numChildren = compoundShape->getNumChildShapes(); - for (i=0; igetChildShape(i) == childCtrl->m_bulletChildShape) - { + for (i = 0; i < numChildren; i++) { + if (compoundShape->getChildShape(i) == childCtrl->m_bulletChildShape) { compoundShape->removeChildShapeByIndex(i); compoundShape->recalculateLocalAabb(); break; } } delete childCtrl->m_bulletChildShape; - childCtrl->m_bulletChildShape = NULL; + childCtrl->m_bulletChildShape = nullptr; } // recompute inertia of parent - if (!rootBody->isStaticOrKinematicObject()) - { + if (!rootBody->isStaticOrKinematicObject()) { btVector3 localInertia; - float mass = 1.f/rootBody->getInvMass(); - compoundShape->calculateLocalInertia(mass,localInertia); - rootBody->setMassProps(mass,localInertia); + float mass = 1.f / rootBody->getInvMass(); + compoundShape->calculateLocalInertia(mass, localInertia); + rootBody->setMassProps(mass, localInertia * m_cci.m_inertiaFactor); } // must update the broadphase cache, - GetPhysicsEnvironment()->RefreshCcdPhysicsController(this); + m_cci.m_physicsEnv->RefreshCcdPhysicsController(this); // reactivate the children - GetPhysicsEnvironment()->AddCcdPhysicsController(childCtrl); + m_cci.m_physicsEnv->AddCcdPhysicsController(childCtrl); } -PHY_IPhysicsController* CcdPhysicsController::GetReplica() +PHY_IPhysicsController *CcdPhysicsController::GetReplica() { - CcdPhysicsController* replica = new CcdPhysicsController(*this); + CcdPhysicsController *replica = new CcdPhysicsController(*this); return replica; } // Keeping this separate for now, maybe we can combine it with GetReplica()... -PHY_IPhysicsController* CcdPhysicsController::GetReplicaForSensors() +PHY_IPhysicsController *CcdPhysicsController::GetReplicaForSensors() { // This is used only to replicate Near and Radar sensor controllers // The replication of object physics controller is done in KX_BulletPhysicsController::GetReplica() CcdConstructionInfo cinfo = m_cci; - if (m_shapeInfo) - { - // This situation does not normally happen - cinfo.m_collisionShape = m_shapeInfo->CreateBulletShape(m_cci.m_margin, m_cci.m_bGimpact, !m_cci.m_bSoft); - } - else if (m_collisionShape) - { - switch (m_collisionShape->getShapeType()) - { - case SPHERE_SHAPE_PROXYTYPE: + + if (m_collisionShape) { + switch (m_collisionShape->getShapeType()) { + case SPHERE_SHAPE_PROXYTYPE: { - btSphereShape* orgShape = (btSphereShape*)m_collisionShape; + btSphereShape *orgShape = (btSphereShape *)m_collisionShape; cinfo.m_collisionShape = new btSphereShape(*orgShape); break; } - case CONE_SHAPE_PROXYTYPE: + case CONE_SHAPE_PROXYTYPE: { - btConeShape* orgShape = (btConeShape*)m_collisionShape; + btConeShape *orgShape = (btConeShape *)m_collisionShape; cinfo.m_collisionShape = new btConeShape(*orgShape); break; } - default: + default: { - return 0; + return nullptr; } } } @@ -1706,60 +1655,62 @@ PHY_IPhysicsController* CcdPhysicsController::GetReplicaForSensors() cinfo.m_MotionState = new DefaultMotionState(); cinfo.m_shapeInfo = m_shapeInfo; - CcdPhysicsController* replica = new CcdPhysicsController(cinfo); + CcdPhysicsController *replica = new CcdPhysicsController(cinfo); return replica; } +bool CcdPhysicsController::IsPhysicsSuspended() +{ + return !GetPhysicsEnvironment()->IsActiveCcdPhysicsController(this); +} + /* Refresh the physics object from either an object or a mesh. - * from_gameobj and from_meshobj can be NULL + * from_gameobj and from_meshobj can be nullptr * * when setting the mesh, the following vars get priority - * 1) from_meshobj - creates the phys mesh from RAS_MeshObject - * 2) from_gameobj - creates the phys mesh from the DerivedMesh where possible, else the RAS_MeshObject - * 3) this - update the phys mesh from DerivedMesh or RAS_MeshObject + * 1) from_meshobj - creates the phys mesh from RAS_Mesh + * 2) from_gameobj - creates the phys mesh from the DerivedMesh where possible, else the RAS_Mesh + * 3) this - update the phys mesh from DerivedMesh or RAS_Mesh * * Most of the logic behind this is in m_shapeInfo->UpdateMesh(...) */ -bool CcdPhysicsController::ReinstancePhysicsShape(KX_GameObject *from_gameobj, RAS_MeshObject *from_meshobj) +bool CcdPhysicsController::ReinstancePhysicsShape(KX_GameObject *from_gameobj, RAS_Mesh *from_meshobj, bool dupli) { - if (m_shapeInfo->m_shapeType != PHY_SHAPE_MESH) + if (m_shapeInfo->m_shapeType != PHY_SHAPE_MESH) { return false; + } - if (!from_gameobj && !from_meshobj) - from_gameobj = KX_GameObject::GetClientObject((KX_ClientObjectInfo*)GetNewClientInfo()); + if (!from_gameobj && !from_meshobj) { + from_gameobj = KX_GameObject::GetClientObject((KX_ClientObjectInfo *)GetNewClientInfo()); + } + + if (dupli && (m_shapeInfo->GetRefCount() > 1)) { + CcdShapeConstructionInfo *newShapeInfo = m_shapeInfo->GetReplica(); + m_shapeInfo->Release(); + m_shapeInfo = newShapeInfo; + } /* updates the arrays used for making the new bullet mesh */ m_shapeInfo->UpdateMesh(from_gameobj, from_meshobj); /* create the new bullet mesh */ - GetPhysicsEnvironment()->UpdateCcdPhysicsControllerShape(m_shapeInfo); + m_cci.m_physicsEnv->UpdateCcdPhysicsControllerShape(m_shapeInfo); return true; } -void CcdPhysicsController::ReplicateConstraints(KX_GameObject *replica, std::vector constobj) +void CcdPhysicsController::ReplacePhysicsShape(PHY_IPhysicsController *phyctrl) { - if (replica->GetConstraints().size() == 0 || !replica->GetPhysicsController()) - return; - - PHY_IPhysicsEnvironment *physEnv = GetPhysicsEnvironment(); + CcdShapeConstructionInfo *shapeInfo = ((CcdPhysicsController *)phyctrl)->GetShapeInfo(); - vector constraints = replica->GetConstraints(); - vector::iterator consit; - - /* Object could have some constraints, iterate over all of theme to ensure that every constraint is recreated. */ - for (consit = constraints.begin(); consit != constraints.end(); ++consit) { - /* Try to find the constraint targets in the list of group objects. */ - bRigidBodyJointConstraint *dat = (*consit); - vector::iterator memit; - for (memit = constobj.begin(); memit != constobj.end(); ++memit) { - KX_GameObject *member = (*memit); - /* If the group member is the actual target for the constraint. */ - if (dat->tar->id.name + 2 == member->GetName() && member->GetPhysicsController()) - physEnv->SetupObjectConstraints(replica, member, dat); - } - } + // switch shape info + m_shapeInfo->Release(); + m_shapeInfo = shapeInfo->AddRef(); + // recreate Bullet shape only for this physics controller + ReplaceControllerShape(nullptr); + // refresh to remove collision pair + m_cci.m_physicsEnv->RefreshCcdPhysicsController(this); } /////////////////////////////////////////////////////////// @@ -1770,866 +1721,431 @@ void CcdPhysicsController::ReplicateConstraints(KX_GameObject *replica, std::vec DefaultMotionState::DefaultMotionState() { m_worldTransform.setIdentity(); - m_localScaling.setValue(1.f,1.f,1.f); + m_localScaling.setValue(1.0f, 1.0f, 1.0f); } - DefaultMotionState::~DefaultMotionState() { - } -void DefaultMotionState::GetWorldPosition(float& posX,float& posY,float& posZ) +mt::vec3 DefaultMotionState::GetWorldPosition() const { - posX = m_worldTransform.getOrigin().x(); - posY = m_worldTransform.getOrigin().y(); - posZ = m_worldTransform.getOrigin().z(); + return ToMt(m_worldTransform.getOrigin()); } -void DefaultMotionState::GetWorldScaling(float& scaleX,float& scaleY,float& scaleZ) +mt::vec3 DefaultMotionState::GetWorldScaling() const { - scaleX = m_localScaling.getX(); - scaleY = m_localScaling.getY(); - scaleZ = m_localScaling.getZ(); + return ToMt(m_localScaling); } -void DefaultMotionState::GetWorldOrientation(float& quatIma0,float& quatIma1,float& quatIma2,float& quatReal) +mt::mat3 DefaultMotionState::GetWorldOrientation() const { - btQuaternion quat = m_worldTransform.getRotation(); - quatIma0 = quat.x(); - quatIma1 = quat.y(); - quatIma2 = quat.z(); - quatReal = quat[3]; + return ToMt(m_worldTransform.getBasis()); } -void DefaultMotionState::GetWorldOrientation(float* ori) +void DefaultMotionState::SetWorldOrientation(const mt::mat3& ori) { - m_worldTransform.getBasis().getOpenGLSubMatrix(ori); + m_worldTransform.setBasis(ToBullet(ori)); } - -void DefaultMotionState::SetWorldOrientation(const float* ori) -{ - m_worldTransform.getBasis().setFromOpenGLSubMatrix(ori); -} -void DefaultMotionState::SetWorldPosition(float posX,float posY,float posZ) +void DefaultMotionState::SetWorldPosition(const mt::vec3& pos) { - btVector3 pos(posX,posY,posZ); - m_worldTransform.setOrigin( pos ); + m_worldTransform.setOrigin(ToBullet(pos)); } -void DefaultMotionState::SetWorldOrientation(float quatIma0,float quatIma1,float quatIma2,float quatReal) +void DefaultMotionState::SetWorldOrientation(const mt::quat& quat) { - btQuaternion orn(quatIma0,quatIma1,quatIma2,quatReal); - m_worldTransform.setRotation( orn ); + m_worldTransform.setRotation(ToBullet(quat)); } -void DefaultMotionState::CalculateWorldTransformations() +void DefaultMotionState::CalculateWorldTransformations() { - } // Shape constructor -std::map CcdShapeConstructionInfo::m_meshShapeMap; +CcdShapeConstructionInfo::MeshShapeMap CcdShapeConstructionInfo::m_meshShapeMap; -CcdShapeConstructionInfo* CcdShapeConstructionInfo::FindMesh(RAS_MeshObject* mesh, struct DerivedMesh* dm, bool polytope) +CcdShapeConstructionInfo *CcdShapeConstructionInfo::FindMesh(RAS_Mesh *mesh, RAS_Deformer *deformer, PHY_ShapeType shapeType) { - if (polytope || dm) - // not yet supported - return NULL; - - std::map::const_iterator mit = m_meshShapeMap.find(mesh); - if (mit != m_meshShapeMap.end()) + MeshShapeMap::const_iterator mit = m_meshShapeMap.find(MeshShapeKey(mesh, deformer, shapeType)); + if (mit != m_meshShapeMap.end()) { return mit->second; - return NULL; + } + return nullptr; } -bool CcdShapeConstructionInfo::SetMesh(RAS_MeshObject *meshobj, DerivedMesh *dm, bool polytope) +CcdShapeConstructionInfo *CcdShapeConstructionInfo::GetReplica() { - int numpolys, numverts; - - // assume no shape information - // no support for dynamic change of shape yet - assert(IsUnused()); - m_shapeType = PHY_SHAPE_NONE; - m_meshObject = NULL; - bool free_dm = false; - - // No mesh object or mesh has no polys - if (!meshobj || !meshobj->HasColliderPolygon()) { - m_vertexArray.clear(); - m_polygonIndexArray.clear(); - m_triFaceArray.clear(); - m_triFaceUVcoArray.clear(); - return false; - } - - if (!dm) { - free_dm = true; - dm = CDDM_from_mesh(meshobj->GetMesh()); - } - - // Some meshes with modifiers returns 0 polys, call DM_ensure_tessface avoid this. - DM_ensure_tessface(dm); - - MVert *mvert = dm->getVertArray(dm); - MFace *mface = dm->getTessFaceArray(dm); - numpolys = dm->getNumTessFaces(dm); - numverts = dm->getNumVerts(dm); - MTFace *tface = (MTFace *)dm->getTessFaceDataArray(dm, CD_MTFACE); - - /* double lookup */ - const int *index_mf_to_mpoly = (const int *)dm->getTessFaceDataArray(dm, CD_ORIGINDEX); - const int *index_mp_to_orig = (const int *)dm->getPolyDataArray(dm, CD_ORIGINDEX); - if (!index_mf_to_mpoly) { - index_mp_to_orig = NULL; - } - - m_shapeType = (polytope) ? PHY_SHAPE_POLYTOPE : PHY_SHAPE_MESH; - - /* Convert blender geometry into bullet mesh, need these vars for mapping */ - std::vector vert_tag_array(numverts, false); - unsigned int tot_bt_verts = 0; - - if (polytope) { - // Tag verts we're using - for (int p2 = 0; p2 < numpolys; p2++) { - MFace *mf = &mface[p2]; - const int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, p2) : p2; - RAS_Polygon *poly = (origi != ORIGINDEX_NONE) ? meshobj->GetPolygon(origi) : NULL; - - // only add polygons that have the collision flag set - if (poly && poly->IsCollider()) { - if (!vert_tag_array[mf->v1]) { - vert_tag_array[mf->v1] = true; - tot_bt_verts++; - } - if (!vert_tag_array[mf->v2]) { - vert_tag_array[mf->v2] = true; - tot_bt_verts++; - } - if (!vert_tag_array[mf->v3]) { - vert_tag_array[mf->v3] = true; - tot_bt_verts++; - } - if (mf->v4 && !vert_tag_array[mf->v4]) { - vert_tag_array[mf->v4] = true; - tot_bt_verts++; - } - } - } - - /* Can happen with ngons */ - if (!tot_bt_verts) { - goto cleanup_empty_mesh; - } - - m_vertexArray.resize(tot_bt_verts * 3); - - btScalar *bt = &m_vertexArray[0]; - - for (int p2 = 0; p2 < numpolys; p2++) { - MFace *mf = &mface[p2]; - const int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, p2) : p2; - RAS_Polygon *poly = (origi != ORIGINDEX_NONE) ? meshobj->GetPolygon(origi) : NULL; - - // only add polygons that have the collisionflag set - if (poly->IsCollider()) { - if (vert_tag_array[mf->v1]) { - const float *vtx = mvert[mf->v1].co; - vert_tag_array[mf->v1] = false; - *bt++ = vtx[0]; - *bt++ = vtx[1]; - *bt++ = vtx[2]; - } - if (vert_tag_array[mf->v2]) { - const float *vtx = mvert[mf->v2].co; - vert_tag_array[mf->v2] = false; - *bt++ = vtx[0]; - *bt++ = vtx[1]; - *bt++ = vtx[2]; - } - if (vert_tag_array[mf->v3]) { - const float *vtx = mvert[mf->v3].co; - vert_tag_array[mf->v3] = false; - *bt++ = vtx[0]; - *bt++ = vtx[1]; - *bt++ = vtx[2]; - } - if (mf->v4 && vert_tag_array[mf->v4]) { - const float *vtx = mvert[mf->v4].co; - vert_tag_array[mf->v4] = false; - *bt++ = vtx[0]; - *bt++ = vtx[1]; - *bt++ = vtx[2]; - } - } - } - } - else { - unsigned int tot_bt_tris = 0; - std::vector vert_remap_array(numverts, 0); - - // Tag verts we're using - for (int p2 = 0; p2 < numpolys; p2++) { - MFace *mf = &mface[p2]; - const int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, p2) : p2; - RAS_Polygon *poly = (origi != ORIGINDEX_NONE) ? meshobj->GetPolygon(origi) : NULL; - - // only add polygons that have the collision flag set - if (poly && poly->IsCollider()) { - if (!vert_tag_array[mf->v1]) { - vert_tag_array[mf->v1] = true; - vert_remap_array[mf->v1] = tot_bt_verts; - tot_bt_verts++; - } - if (!vert_tag_array[mf->v2]) { - vert_tag_array[mf->v2] = true; - vert_remap_array[mf->v2] = tot_bt_verts; - tot_bt_verts++; - } - if (!vert_tag_array[mf->v3]) { - vert_tag_array[mf->v3] = true; - vert_remap_array[mf->v3] = tot_bt_verts; - tot_bt_verts++; - } - if (mf->v4 && !vert_tag_array[mf->v4]) { - vert_tag_array[mf->v4] = true; - vert_remap_array[mf->v4] = tot_bt_verts; - tot_bt_verts++; - } - tot_bt_tris += (mf->v4 ? 2 : 1); /* a quad or a tri */ - } - } - - /* Can happen with ngons */ - if (!tot_bt_verts) { - goto cleanup_empty_mesh; - } - - m_vertexArray.resize(tot_bt_verts * 3); - m_polygonIndexArray.resize(tot_bt_tris); - m_triFaceArray.resize(tot_bt_tris * 3); - btScalar *bt = &m_vertexArray[0]; - int *poly_index_pt = &m_polygonIndexArray[0]; - int *tri_pt = &m_triFaceArray[0]; - - UVco *uv_pt = NULL; - if (tface) { - m_triFaceUVcoArray.resize(tot_bt_tris * 3); - uv_pt = &m_triFaceUVcoArray[0]; - } - else - m_triFaceUVcoArray.clear(); - - for (int p2 = 0; p2 < numpolys; p2++) { - MFace *mf = &mface[p2]; - MTFace *tf = (tface) ? &tface[p2] : NULL; - const int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, p2) : p2; - RAS_Polygon *poly = (origi != ORIGINDEX_NONE) ? meshobj->GetPolygon(origi) : NULL; - - // only add polygons that have the collisionflag set - if (poly && poly->IsCollider()) { - MVert *v1 = &mvert[mf->v1]; - MVert *v2 = &mvert[mf->v2]; - MVert *v3 = &mvert[mf->v3]; - - // the face indices - tri_pt[0] = vert_remap_array[mf->v1]; - tri_pt[1] = vert_remap_array[mf->v2]; - tri_pt[2] = vert_remap_array[mf->v3]; - tri_pt = tri_pt + 3; - if (tf) { - uv_pt[0].uv[0] = tf->uv[0][0]; - uv_pt[0].uv[1] = tf->uv[0][1]; - uv_pt[1].uv[0] = tf->uv[1][0]; - uv_pt[1].uv[1] = tf->uv[1][1]; - uv_pt[2].uv[0] = tf->uv[2][0]; - uv_pt[2].uv[1] = tf->uv[2][1]; - uv_pt += 3; - } - - // m_polygonIndexArray - *poly_index_pt = origi; - poly_index_pt++; - - // the vertex location - if (vert_tag_array[mf->v1]) { /* *** v1 *** */ - vert_tag_array[mf->v1] = false; - *bt++ = v1->co[0]; - *bt++ = v1->co[1]; - *bt++ = v1->co[2]; - } - if (vert_tag_array[mf->v2]) { /* *** v2 *** */ - vert_tag_array[mf->v2] = false; - *bt++ = v2->co[0]; - *bt++ = v2->co[1]; - *bt++ = v2->co[2]; - } - if (vert_tag_array[mf->v3]) { /* *** v3 *** */ - vert_tag_array[mf->v3] = false; - *bt++ = v3->co[0]; - *bt++ = v3->co[1]; - *bt++ = v3->co[2]; - } - - if (mf->v4) - { - MVert *v4 = &mvert[mf->v4]; - - tri_pt[0] = vert_remap_array[mf->v1]; - tri_pt[1] = vert_remap_array[mf->v3]; - tri_pt[2] = vert_remap_array[mf->v4]; - tri_pt = tri_pt + 3; - if (tf) - { - uv_pt[0].uv[0] = tf->uv[0][0]; - uv_pt[0].uv[1] = tf->uv[0][1]; - uv_pt[1].uv[0] = tf->uv[2][0]; - uv_pt[1].uv[1] = tf->uv[2][1]; - uv_pt[2].uv[0] = tf->uv[3][0]; - uv_pt[2].uv[1] = tf->uv[3][1]; - uv_pt += 3; - } - - // m_polygonIndexArray - *poly_index_pt = origi; - poly_index_pt++; - - // the vertex location - if (vert_tag_array[mf->v4]) { /* *** v4 *** */ - vert_tag_array[mf->v4] = false; - *bt++ = v4->co[0]; - *bt++ = v4->co[1]; - *bt++ = v4->co[2]; - } - } - } - } - - - /* If this ever gets confusing, print out an OBJ file for debugging */ -#if 0 - printf("# vert count %d\n", m_vertexArray.size()); - for (i = 0; i < m_vertexArray.size(); i += 1) { - printf("v %.6f %.6f %.6f\n", m_vertexArray[i].x(), m_vertexArray[i].y(), m_vertexArray[i].z()); - } - - printf("# face count %d\n", m_triFaceArray.size()); - for (i = 0; i < m_triFaceArray.size(); i += 3) { - printf("f %d %d %d\n", m_triFaceArray[i] + 1, m_triFaceArray[i + 1] + 1, m_triFaceArray[i + 2] + 1); - } -#endif - - } - -#if 0 - if (validpolys == false) - { - // should not happen - m_shapeType = PHY_SHAPE_NONE; - return false; - } -#endif - - m_meshObject = meshobj; - if (free_dm) { - dm->release(dm); - dm = NULL; - } - - // sharing only on static mesh at present, if you change that, you must also change in FindMesh - if (!polytope && !dm) { - // triangle shape can be shared, store the mesh object in the map - m_meshShapeMap.insert(std::pair(meshobj, this)); - } - return true; - + CcdShapeConstructionInfo *replica = new CcdShapeConstructionInfo(*this); + replica->ProcessReplica(); + return replica; +} -cleanup_empty_mesh: - m_shapeType = PHY_SHAPE_NONE; - m_meshObject = NULL; +void CcdShapeConstructionInfo::ProcessReplica() +{ + m_userData = nullptr; + m_mesh = nullptr; + m_triangleIndexVertexArray = nullptr; + m_forceReInstance = false; + m_shapeProxy = nullptr; m_vertexArray.clear(); m_polygonIndexArray.clear(); m_triFaceArray.clear(); m_triFaceUVcoArray.clear(); - if (free_dm) { - dm->release(dm); - } - return false; + m_shapeArray.clear(); } -#include - /* Updates the arrays used by CreateBulletShape(), * take care that recalcLocalAabb() runs after CreateBulletShape is called. * */ -bool CcdShapeConstructionInfo::UpdateMesh(class KX_GameObject *gameobj, class RAS_MeshObject *meshobj) +bool CcdShapeConstructionInfo::UpdateMesh(KX_GameObject *gameobj, RAS_Mesh *meshobj) { - int numpolys; - int numverts; - - unsigned int tot_bt_tris = 0; - unsigned int tot_bt_verts = 0; - - int i, j; - int v_orig; - - /* Use for looping over verts in a face as a try or 2 tris */ - const int quad_verts[7] = {0, 1, 2, 0, 2, 3, -1}; - const int tri_verts[4] = {0, 1, 2, -1}; - const int *fv_pt; - - if (!gameobj && !meshobj) + if (!gameobj && !meshobj) { return false; + } - if (m_shapeType != PHY_SHAPE_MESH) + if (!ELEM(m_shapeType, PHY_SHAPE_MESH, PHY_SHAPE_POLYTOPE)) { return false; + } - RAS_Deformer *deformer = gameobj ? gameobj->GetDeformer() : NULL; - DerivedMesh *dm = NULL; - - if (deformer) - dm = deformer->GetPhysicsMesh(); + RAS_Deformer *deformer = nullptr; - /* get the mesh from the object if not defined */ + // Specified mesh object is the highest priority. if (!meshobj) { - /* modifier mesh */ - if (dm) - meshobj = deformer->GetRasMesh(); - - /* game object first mesh */ - if (!meshobj) { - if (gameobj->GetMeshCount() > 0) { - meshobj = gameobj->GetMesh(0); + // Object deformer is second priority. + deformer = gameobj ? gameobj->GetDeformer() : nullptr; + if (deformer) { + meshobj = deformer->GetMesh(); + } + else { + // Object mesh is last priority. + const std::vector& meshes = gameobj->GetMeshList(); + if (!meshes.empty()) { + meshobj = meshes.front(); } } } - if (dm && deformer->GetRasMesh() == meshobj) { - /* - * Derived Mesh Update - * - * */ - - MVert *mvert = dm->getVertArray(dm); - MFace *mface = dm->getTessFaceArray(dm); - numpolys = dm->getNumTessFaces(dm); - numverts = dm->getNumVerts(dm); - - /* double lookup */ - const int *index_mf_to_mpoly = (const int *)dm->getTessFaceDataArray(dm, CD_ORIGINDEX); - const int *index_mp_to_orig = (const int *)dm->getPolyDataArray(dm, CD_ORIGINDEX); - if (!index_mf_to_mpoly) { - index_mp_to_orig = NULL; - } - - MFace *mf; - MVert *mv; - - if (CustomData_has_layer(&dm->faceData, CD_MTFACE)) { - MTFace *tface = (MTFace *)dm->getTessFaceDataArray(dm, CD_MTFACE); - MTFace *tf; - - std::vector vert_tag_array(numverts, false); - std::vector vert_remap_array(numverts, 0); - - for (mf = mface, tf = tface, i = 0; i < numpolys; mf++, tf++, i++) { - if (tf->mode & TF_DYNAMIC) { - int flen; - - if (mf->v4) { - tot_bt_tris += 2; - flen = 4; - } - else { - tot_bt_tris++; - flen = 3; - } - - for (j = 0; j < flen; j++) { - v_orig = (*(&mf->v1 + j)); - - if (!vert_tag_array[v_orig]) { - vert_tag_array[v_orig] = true; - vert_remap_array[v_orig] = tot_bt_verts; - tot_bt_verts++; - } - } - } - } + // Can't find the mesh object. + if (!meshobj) { + return false; + } - m_vertexArray.resize(tot_bt_verts * 3); - btScalar *bt = &m_vertexArray[0]; + RAS_DisplayArrayList displayArrays; - m_triFaceArray.resize(tot_bt_tris * 3); - int *tri_pt = &m_triFaceArray[0]; + // Indices count. + unsigned int numIndices = 0; + // Original (without split of normal or UV) vertex count. + unsigned int numVertices = 0; - m_triFaceUVcoArray.resize(tot_bt_tris * 3); - UVco *uv_pt = &m_triFaceUVcoArray[0]; + /// Absolute polygon start index for each used display arrays. + std::vector polygonStartIndices; + unsigned int curPolygonStartIndex = 0; - m_polygonIndexArray.resize(tot_bt_tris); - int *poly_index_pt = &m_polygonIndexArray[0]; + // Compute indices count and maximum vertex count. + for (unsigned int i = 0, numMat = meshobj->GetNumMaterials(); i < numMat; ++i) { + RAS_MeshMaterial *meshmat = meshobj->GetMeshMaterial(i); + RAS_IMaterial *mat = meshmat->GetBucket()->GetMaterial(); - for (mf = mface, tf = tface, i = 0; i < numpolys; mf++, tf++, i++) { - if (tf->mode & TF_DYNAMIC) { - int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, i) : i; + RAS_DisplayArray *array = (deformer) ? deformer->GetDisplayArray(i) : meshmat->GetDisplayArray(); + const unsigned int indicesCount = array->GetTriangleIndexCount(); - if (mf->v4) { - fv_pt = quad_verts; - *poly_index_pt++ = origi; - *poly_index_pt++ = origi; - } - else { - fv_pt = tri_verts; - *poly_index_pt++ = origi; - } - - for (; *fv_pt > -1; fv_pt++) { - v_orig = (*(&mf->v1 + (*fv_pt))); - - if (vert_tag_array[v_orig]) - { - mv = mvert + v_orig; - *bt++ = mv->co[0]; - *bt++ = mv->co[1]; - *bt++ = mv->co[2]; - - vert_tag_array[v_orig] = false; - } - *tri_pt++ = vert_remap_array[v_orig]; - uv_pt->uv[0] = tf->uv[*fv_pt][0]; - uv_pt->uv[1] = tf->uv[*fv_pt][1]; - uv_pt++; - } - } - } + // If collisions are disabled: do nothing. + if (mat->IsCollider()) { + numIndices += indicesCount; + numVertices = std::max(numVertices, array->GetMaxOrigIndex() + 1); + // Add valid display arrays. + displayArrays.push_back(array); + polygonStartIndices.push_back(curPolygonStartIndex); } - else { - /* no need for a vertex mapping. simple/fast */ - tot_bt_verts = numverts; - - for (mf = mface, i = 0; i < numpolys; mf++, i++) { - tot_bt_tris += (mf->v4 ? 2 : 1); - } - - m_vertexArray.resize(tot_bt_verts * 3); - btScalar *bt = &m_vertexArray[0]; - - m_triFaceArray.resize(tot_bt_tris * 3); - int *tri_pt = &m_triFaceArray[0]; - - m_polygonIndexArray.resize(tot_bt_tris); - int *poly_index_pt = &m_polygonIndexArray[0]; + curPolygonStartIndex += indicesCount / 3; + } - m_triFaceUVcoArray.clear(); + // Detect mesh without triangles. + if (numIndices == 0 && m_shapeType == PHY_SHAPE_MESH) { + return false; + } - for (mv = mvert, i = 0; i < numverts; mv++, i++) { - *bt++ = mv->co[0]; *bt++ = mv->co[1]; *bt++ = mv->co[2]; + m_vertexArray.resize(numVertices * 3); + m_vertexRemap.resize(numVertices); + // resize() doesn't initialize all values if the vector wasn't empty before. Prefer fill explicitly. + std::fill(m_vertexRemap.begin(), m_vertexRemap.end(), -1); + + // Current vertex written. + unsigned int curVert = 0; + + for (RAS_DisplayArray *array : displayArrays) { + // Convert location of all vertices and remap if vertices weren't already converted. + for (unsigned int j = 0, numvert = array->GetVertexCount(); j < numvert; ++j) { + const RAS_VertexInfo& info = array->GetVertexInfo(j); + const unsigned int origIndex = info.GetOrigIndex(); + /* Avoid double conversion of two unique vertices using the same base: + * using the same original vertex and so the same position. + */ + if (m_vertexRemap[origIndex] != -1) { + continue; } - for (mf = mface, i = 0; i < numpolys; mf++, i++) { - int origi = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, i) : i; + const mt::vec3_packed& pos = array->GetPosition(j); + m_vertexArray[curVert * 3] = pos.x; + m_vertexArray[curVert * 3 + 1] = pos.y; + m_vertexArray[curVert * 3 + 2] = pos.z; - if (mf->v4) { - fv_pt = quad_verts; - *poly_index_pt++ = origi; - *poly_index_pt++ = origi; - } - else { - fv_pt = tri_verts; - *poly_index_pt++ = origi; - } - - for (; *fv_pt > -1; fv_pt++) - *tri_pt++ = (*(&mf->v1 + (*fv_pt))); - } + // Register the vertex index where the position was converted in m_vertexArray. + m_vertexRemap[origIndex] = curVert++; } } - else { /* - * RAS Mesh Update - * - * */ - /* Note!, gameobj can be NULL here */ - /* transverts are only used for deformed RAS_Meshes, the RAS_TexVert data - * is too hard to get at, see below for details */ - float(*transverts)[3] = NULL; - int transverts_tot = 0; /* with deformed meshes - should always be greater than the max orginal index, or we get crashes */ + // Convex shapes don't need indices. + if (m_shapeType == PHY_SHAPE_MESH) { + m_triFaceArray.resize(numIndices); + m_triFaceUVcoArray.resize(numIndices); + m_polygonIndexArray.resize(numIndices / 3); - if (deformer) { - /* map locations from the deformed array - * - * Could call deformer->Update(); but rely on redraw updating. - * */ - transverts = deformer->GetTransVerts(&transverts_tot); - } - - // Tag verts we're using - numpolys = meshobj->NumPolygons(); - numverts = meshobj->m_sharedvertex_map.size(); - const float *xyz; - - - std::vector vert_tag_array(numverts, false); - std::vector vert_remap_array(numverts, 0); - - for (int p = 0; p < numpolys; p++) { - RAS_Polygon *poly = meshobj->GetPolygon(p); - if (poly->IsCollider()) { - for (i = 0; i < poly->VertexCount(); i++) { - v_orig = poly->GetVertex(i)->getOrigIndex(); - if (!vert_tag_array[v_orig]) { - vert_tag_array[v_orig] = true; - vert_remap_array[v_orig] = tot_bt_verts; - tot_bt_verts++; - } - } - tot_bt_tris += (poly->VertexCount() == 4 ? 2 : 1); - } - } + // Current triangle written. + unsigned int curTri = 0; - // This case happens when none of the polys are colliders - if (tot_bt_tris == 0 || tot_bt_verts == 0) - return false; + for (unsigned short i = 0, numArray = displayArrays.size(); i < numArray; ++i) { + RAS_DisplayArray *array = displayArrays[i]; + const unsigned int polygonStartIndex = polygonStartIndices[i]; - m_vertexArray.resize(tot_bt_verts * 3); - btScalar *bt = &m_vertexArray[0]; + // Convert triangles using remaped vertices index. + for (unsigned int j = 0, numind = array->GetTriangleIndexCount(); j < numind; j += 3) { + // Should match polygon access index with RAS_Mesh::GetPolygon. + m_polygonIndexArray[curTri] = polygonStartIndex + j / 3; - m_triFaceArray.resize(tot_bt_tris * 3); - int *tri_pt = &m_triFaceArray[0]; + for (unsigned short k = 0; k < 3; ++k) { + const unsigned int index = array->GetTriangleIndex(j + k); + const unsigned int curInd = curTri * 3 + k; - /* cant be used for anything useful in this case, since we don't rely on the original mesh - * will just be an array like pythons range(tot_bt_tris) */ - m_polygonIndexArray.resize(tot_bt_tris); + // Convert UV for raycast UV computation. + const mt::vec2_packed& uv = array->GetUv(index, 0); + m_triFaceUVcoArray[curInd] = {{uv.x, uv.y}}; - - int p = 0; - int t = 0; - while (t < tot_bt_tris) { - RAS_Polygon *poly = meshobj->GetPolygon(p); - - if (poly->IsCollider()) { - /* quad or tri loop */ - fv_pt = (poly->VertexCount() == 3 ? tri_verts : quad_verts); - - for (; *fv_pt > -1; fv_pt++) { - v_orig = poly->GetVertex(*fv_pt)->getOrigIndex(); - if (vert_tag_array[v_orig]) { - if (transverts) { - /* deformed mesh, using RAS_TexVert locations would be too troublesome - * because they are use the gameob as a hash in the material slot */ - *bt++ = transverts[v_orig][0]; - *bt++ = transverts[v_orig][1]; - *bt++ = transverts[v_orig][2]; - } - else { - /* static mesh python may have modified */ - xyz = meshobj->GetVertexLocation(v_orig); - *bt++ = xyz[0]; - *bt++ = xyz[1]; - *bt++ = xyz[2]; - } - vert_tag_array[v_orig] = false; - } - *tri_pt++ = vert_remap_array[v_orig]; + // Get vertex index from original index to m_vertexArray vertex index. + const RAS_VertexInfo& info = array->GetVertexInfo(index); + const unsigned int origIndex = info.GetOrigIndex(); + m_triFaceArray[curInd] = m_vertexRemap[origIndex]; } + ++curTri; } - // first triangle - m_polygonIndexArray[t] = p; - - // if the poly is a quad we transform it in two triangles - if (poly->VertexCount() == 4) { - t++; - // second triangle - m_polygonIndexArray[t] = p; - } - t++; - p++; } } #if 0 - /* needs #include */ - printf("# vert count %d\n", m_vertexArray.size()); + CM_Debug("# vert count " << m_vertexArray.size()); for (int i = 0; i < m_vertexArray.size(); i += 3) { - printf("v %.6f %.6f %.6f\n", m_vertexArray[i], m_vertexArray[i + 1], m_vertexArray[i + 2]); + CM_Debug("v " << m_vertexArray[i] << " " << m_vertexArray[i + 1] << " " << m_vertexArray[i + 2]); } - printf("# face count %d\n", m_triFaceArray.size()); + CM_Debug("# face count " << m_triFaceArray.size()); for (int i = 0; i < m_triFaceArray.size(); i += 3) { - printf("f %d %d %d\n", m_triFaceArray[i] + 1, m_triFaceArray[i + 1] + 1, m_triFaceArray[i + 2] + 1); + CM_Debug("f " << m_triFaceArray[i] + 1 << " " << m_triFaceArray[i + 1] + 1 << " " << m_triFaceArray[i + 2] + 1); } #endif - /* force recreation of the m_triangleIndexVertexArray. - * If this has multiple users we cant delete */ + // Force recreation of the m_triangleIndexVertexArray. if (m_triangleIndexVertexArray) { m_forceReInstance = true; } - // Make sure to also replace the mesh in the shape map! Otherwise we leave dangling references when we free. - // Note, this whole business could cause issues with shared meshes. If we update one mesh, do we replace - // them all? - std::map::iterator mit = m_meshShapeMap.find(m_meshObject); - if (mit != m_meshShapeMap.end()) { - m_meshShapeMap.erase(mit); - m_meshShapeMap[meshobj] = this; + /* Make sure to also replace the mesh in the shape map! Otherwise we leave dangling references when we free. + * Note, this whole business could cause issues with shared meshes. + */ + for (MeshShapeMap::iterator it = m_meshShapeMap.begin(); it != m_meshShapeMap.end(); ) { + if (it->second == this) { + it = m_meshShapeMap.erase(it); + } + else { + ++it; + } } - m_meshObject = meshobj; + // Register mesh object to shape. + m_meshShapeMap[MeshShapeKey(meshobj, deformer, m_shapeType)] = this; + + m_mesh = meshobj; - if (dm) { - dm->needsFree = 1; - dm->release(dm); - } return true; } -bool CcdShapeConstructionInfo::SetProxy(CcdShapeConstructionInfo* shapeInfo) +bool CcdShapeConstructionInfo::SetProxy(CcdShapeConstructionInfo *shapeInfo) { - if (shapeInfo == NULL) + if (!shapeInfo) { return false; - // no support for dynamic change - assert(IsUnused()); + } + m_shapeType = PHY_SHAPE_PROXY; m_shapeProxy = shapeInfo; return true; } -btCollisionShape* CcdShapeConstructionInfo::CreateBulletShape(btScalar margin, bool useGimpact, bool useBvh) +RAS_Mesh *CcdShapeConstructionInfo::GetMesh() const { - btCollisionShape* collisionShape = 0; - btCompoundShape* compoundShape = 0; + return m_mesh; +} - if (m_shapeType == PHY_SHAPE_PROXY && m_shapeProxy != NULL) - return m_shapeProxy->CreateBulletShape(margin, useGimpact, useBvh); +btCollisionShape *CcdShapeConstructionInfo::CreateBulletShape(btScalar margin, bool useGimpact, bool useBvh) +{ + btCollisionShape *collisionShape = nullptr; - switch (m_shapeType) - { - default: - break; - - case PHY_SHAPE_BOX: - collisionShape = new btBoxShape(m_halfExtend); - collisionShape->setMargin(margin); - break; - - case PHY_SHAPE_SPHERE: - collisionShape = new btSphereShape(m_radius); - collisionShape->setMargin(margin); - break; - - case PHY_SHAPE_CYLINDER: - collisionShape = new btCylinderShapeZ(m_halfExtend); - collisionShape->setMargin(margin); - break; - - case PHY_SHAPE_CONE: - collisionShape = new btConeShapeZ(m_radius, m_height); - collisionShape->setMargin(margin); - break; - - case PHY_SHAPE_POLYTOPE: - collisionShape = new btConvexHullShape(&m_vertexArray[0], m_vertexArray.size()/3, 3*sizeof(btScalar)); - collisionShape->setMargin(margin); - break; - - case PHY_SHAPE_CAPSULE: - collisionShape = new btCapsuleShapeZ(m_radius, m_height); - collisionShape->setMargin(margin); - break; - - case PHY_SHAPE_MESH: - // Let's use the latest btScaledBvhTriangleMeshShape: it allows true sharing of - // triangle mesh information between duplicates => drastic performance increase when - // duplicating complex mesh objects. - // BUT it causes a small performance decrease when sharing is not required: - // 9 multiplications/additions and one function call for each triangle that passes the mid phase filtering - // One possible optimization is to use directly the btBvhTriangleMeshShape when the scale is 1,1,1 - // and btScaledBvhTriangleMeshShape otherwise. - if (useGimpact) { - if (!m_triangleIndexVertexArray || m_forceReInstance) { - if (m_triangleIndexVertexArray) - delete m_triangleIndexVertexArray; - - m_triangleIndexVertexArray = new btTriangleIndexVertexArray( - m_polygonIndexArray.size(), + switch (m_shapeType) { + case PHY_SHAPE_PROXY: + { + if (m_shapeProxy) { + collisionShape = m_shapeProxy->CreateBulletShape(margin, useGimpact, useBvh); + } + break; + } + case PHY_SHAPE_BOX: + { + collisionShape = new btBoxShape(m_halfExtend); + collisionShape->setMargin(margin); + break; + } + case PHY_SHAPE_SPHERE: + { + collisionShape = new btSphereShape(m_radius); + collisionShape->setMargin(margin); + break; + } + case PHY_SHAPE_CYLINDER: + { + collisionShape = new btCylinderShapeZ(m_halfExtend); + collisionShape->setMargin(margin); + break; + } + case PHY_SHAPE_CONE: + { + collisionShape = new btConeShapeZ(m_radius, m_height); + collisionShape->setMargin(margin); + break; + } + case PHY_SHAPE_CAPSULE: + { + collisionShape = new btCapsuleShapeZ(m_radius, m_height); + collisionShape->setMargin(margin); + break; + } + case PHY_SHAPE_POLYTOPE: + { + if (m_vertexArray.size() == 0) { + break; + } + + collisionShape = new btConvexHullShape(&m_vertexArray[0], m_vertexArray.size() / 3, 3 * sizeof(btScalar)); + collisionShape->setMargin(margin); + break; + } + case PHY_SHAPE_MESH: + { + if (m_vertexArray.size() == 0) { + break; + } + + // Let's use the latest btScaledBvhTriangleMeshShape: it allows true sharing of + // triangle mesh information between duplicates => drastic performance increase when + // duplicating complex mesh objects. + // BUT it causes a small performance decrease when sharing is not required: + // 9 multiplications/additions and one function call for each triangle that passes the mid phase filtering + // One possible optimization is to use directly the btBvhTriangleMeshShape when the scale is 1,1,1 + // and btScaledBvhTriangleMeshShape otherwise. + if (useGimpact) { + if (!m_triangleIndexVertexArray || m_forceReInstance) { + if (m_triangleIndexVertexArray) { + delete m_triangleIndexVertexArray; + } + + m_triangleIndexVertexArray = new btTriangleIndexVertexArray( + m_triFaceArray.size() / 3, m_triFaceArray.data(), 3 * sizeof(int), m_vertexArray.size() / 3, &m_vertexArray[0], 3 * sizeof(btScalar)); - m_forceReInstance = false; - } + m_forceReInstance = false; + } - btGImpactMeshShape *gimpactShape = new btGImpactMeshShape(m_triangleIndexVertexArray); - gimpactShape->setMargin(margin); - gimpactShape->updateBound(); - collisionShape = gimpactShape; - } - else { - if (!m_triangleIndexVertexArray || m_forceReInstance) { - ///enable welding, only for the objects that need it (such as soft bodies) - if (0.0f != m_weldingThreshold1) { - btTriangleMesh *collisionMeshData = new btTriangleMesh(true, false); - collisionMeshData->m_weldingThreshold = m_weldingThreshold1; - bool removeDuplicateVertices = true; - // m_vertexArray not in multiple of 3 anymore, use m_triFaceArray - for (unsigned int i = 0; i < m_triFaceArray.size(); i += 3) { - btScalar *bt = &m_vertexArray[3 * m_triFaceArray[i]]; - btVector3 v1(bt[0], bt[1], bt[2]); - bt = &m_vertexArray[3 * m_triFaceArray[i + 1]]; - btVector3 v2(bt[0], bt[1], bt[2]); - bt = &m_vertexArray[3 * m_triFaceArray[i + 2]]; - btVector3 v3(bt[0], bt[1], bt[2]); - collisionMeshData->addTriangle(v1, v2, v3, removeDuplicateVertices); + btGImpactMeshShape *gimpactShape = new btGImpactMeshShape(m_triangleIndexVertexArray); + gimpactShape->setMargin(margin); + gimpactShape->updateBound(); + collisionShape = gimpactShape; + } + else { + if (!m_triangleIndexVertexArray || m_forceReInstance) { + ///enable welding, only for the objects that need it (such as soft bodies) + if (0.0f != m_weldingThreshold1) { + btTriangleMesh *collisionMeshData = new btTriangleMesh(true, false); + collisionMeshData->m_weldingThreshold = m_weldingThreshold1; + bool removeDuplicateVertices = true; + // m_vertexArray not in multiple of 3 anymore, use m_triFaceArray + for (unsigned int i = 0; i < m_triFaceArray.size(); i += 3) { + btScalar *bt = &m_vertexArray[3 * m_triFaceArray[i]]; + btVector3 v1(bt[0], bt[1], bt[2]); + bt = &m_vertexArray[3 * m_triFaceArray[i + 1]]; + btVector3 v2(bt[0], bt[1], bt[2]); + bt = &m_vertexArray[3 * m_triFaceArray[i + 2]]; + btVector3 v3(bt[0], bt[1], bt[2]); + collisionMeshData->addTriangle(v1, v2, v3, removeDuplicateVertices); + } + m_triangleIndexVertexArray = collisionMeshData; } - m_triangleIndexVertexArray = collisionMeshData; - } - else { - m_triangleIndexVertexArray = new btTriangleIndexVertexArray( - m_polygonIndexArray.size(), + else { + if (m_triangleIndexVertexArray) { + delete m_triangleIndexVertexArray; + } + m_triangleIndexVertexArray = new btTriangleIndexVertexArray( + m_triFaceArray.size() / 3, m_triFaceArray.data(), 3 * sizeof(int), m_vertexArray.size() / 3, &m_vertexArray[0], 3 * sizeof(btScalar)); + } + + m_forceReInstance = false; } - m_forceReInstance = false; + btBvhTriangleMeshShape *unscaledShape = new btBvhTriangleMeshShape(m_triangleIndexVertexArray, true, useBvh); + unscaledShape->setMargin(margin); + collisionShape = new btScaledBvhTriangleMeshShape(unscaledShape, btVector3(1.0f, 1.0f, 1.0f)); + collisionShape->setMargin(margin); } - - btBvhTriangleMeshShape *unscaledShape = new btBvhTriangleMeshShape(m_triangleIndexVertexArray, true, useBvh); - unscaledShape->setMargin(margin); - collisionShape = new btScaledBvhTriangleMeshShape(unscaledShape, btVector3(1.0f, 1.0f, 1.0f)); - collisionShape->setMargin(margin); + break; } - break; - - case PHY_SHAPE_COMPOUND: - if (m_shapeArray.size() > 0) + case PHY_SHAPE_COMPOUND: { - compoundShape = new btCompoundShape(); - for (std::vector::iterator sit = m_shapeArray.begin(); - sit != m_shapeArray.end(); - sit++) - { - collisionShape = (*sit)->CreateBulletShape(margin, useGimpact, useBvh); - if (collisionShape) - { - collisionShape->setLocalScaling((*sit)->m_childScale); - compoundShape->addChildShape((*sit)->m_childTrans, collisionShape); + if (m_shapeArray.empty()) { + break; + } + + btCompoundShape *compoundShape = new btCompoundShape(); + for (CcdShapeConstructionInfo *childShape : m_shapeArray) { + btCollisionShape *childCollisionShape = childShape->CreateBulletShape(margin, useGimpact, useBvh); + if (childCollisionShape) { + childCollisionShape->setLocalScaling(childShape->m_childScale); + compoundShape->addChildShape(childShape->m_childTrans, childCollisionShape); } } + collisionShape = compoundShape; + break; + } + case PHY_SHAPE_EMPTY: + { + collisionShape = new btEmptyShape(); + collisionShape->setMargin(margin); + break; + } + default: + { + BLI_assert(false); } - break; } return collisionShape; } -void CcdShapeConstructionInfo::AddShape(CcdShapeConstructionInfo* shapeInfo) +void CcdShapeConstructionInfo::AddShape(CcdShapeConstructionInfo *shapeInfo) { m_shapeArray.push_back(shapeInfo); shapeInfo->AddRef(); @@ -2637,27 +2153,27 @@ void CcdShapeConstructionInfo::AddShape(CcdShapeConstructionInfo* shapeInfo) CcdShapeConstructionInfo::~CcdShapeConstructionInfo() { - for (std::vector::iterator sit = m_shapeArray.begin(); - sit != m_shapeArray.end(); - sit++) - { - (*sit)->Release(); + for (CcdShapeConstructionInfo *shapeInfo : m_shapeArray) { + shapeInfo->Release(); } m_shapeArray.clear(); - if (m_triangleIndexVertexArray) + if (m_triangleIndexVertexArray) { delete m_triangleIndexVertexArray; + } m_vertexArray.clear(); - if (m_shapeType == PHY_SHAPE_MESH && m_meshObject != NULL) - { - std::map::iterator mit = m_meshShapeMap.find(m_meshObject); - if (mit != m_meshShapeMap.end() && mit->second == this) - { - m_meshShapeMap.erase(mit); + + for (MeshShapeMap::iterator it = m_meshShapeMap.begin(); it != m_meshShapeMap.end(); ) { + if (it->second == this) { + it = m_meshShapeMap.erase(it); + } + else { + ++it; } } - if (m_shapeType == PHY_SHAPE_PROXY && m_shapeProxy != NULL) - { + + if (m_shapeType == PHY_SHAPE_PROXY && m_shapeProxy) { m_shapeProxy->Release(); } } + diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h index d69feda38e5d..a2a7541e4669 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h @@ -1,17 +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. -*/ + 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. + */ /** \file CcdPhysicsController.h * \ingroup physbullet @@ -21,11 +21,15 @@ subject to the following restrictions: #ifndef __CCDPHYSICSCONTROLLER_H__ #define __CCDPHYSICSCONTROLLER_H__ +#include "CM_RefCount.h" + #include #include #include "PHY_IPhysicsController.h" +#include "CcdMathUtils.h" + /// PHY_IPhysicsController is the abstract simplified Interface to a physical object. /// It contains the IMotionState and IDeformableMesh Interfaces. #include "btBulletDynamicsCommon.h" @@ -40,100 +44,81 @@ extern float gLinearSleepingTreshold; extern float gAngularSleepingTreshold; extern bool gDisableDeactivation; class CcdPhysicsEnvironment; +class CcdPhysicsController; class btMotionState; -class RAS_MeshObject; -struct DerivedMesh; +class RAS_Mesh; +class RAS_Deformer; class btCollisionShape; - -#define CCD_BSB_SHAPE_MATCHING 2 +#define CCD_BSB_SHAPE_MATCHING 2 #define CCD_BSB_BENDING_CONSTRAINTS 8 #define CCD_BSB_AERO_VPOINT 16 /* aero model, Vertex normals are oriented toward velocity*/ #define CCD_BSB_AERO_VTWOSIDE 32 /* aero model, Vertex normals are flipped to match velocity */ /* BulletSoftBody.collisionflags */ -#define CCD_BSB_COL_SDF_RS 2 /* SDF based rigid vs soft */ -#define CCD_BSB_COL_CL_RS 4 /* Cluster based rigid vs soft */ -#define CCD_BSB_COL_CL_SS 8 /* Cluster based soft vs soft */ -#define CCD_BSB_COL_VF_SS 16 /* Vertex/Face based soft vs soft */ - +#define CCD_BSB_COL_SDF_RS 2 /* SDF based rigid vs soft */ +#define CCD_BSB_COL_CL_RS 4 /* Cluster based rigid vs soft */ +#define CCD_BSB_COL_CL_SS 8 /* Cluster based soft vs soft */ +#define CCD_BSB_COL_VF_SS 16 /* Vertex/Face based soft vs soft */ // Shape contructor // It contains all the information needed to create a simple bullet shape at runtime -class CcdShapeConstructionInfo +class CcdShapeConstructionInfo : public CM_RefCount, public mt::SimdClassAllocator { public: + struct UVco { float uv[2]; }; - static CcdShapeConstructionInfo* FindMesh(class RAS_MeshObject* mesh, struct DerivedMesh* dm, bool polytope); + static CcdShapeConstructionInfo *FindMesh(RAS_Mesh *mesh, RAS_Deformer *deformer, PHY_ShapeType shapeType); - CcdShapeConstructionInfo() : - m_shapeType(PHY_SHAPE_NONE), + CcdShapeConstructionInfo() + :m_shapeType(PHY_SHAPE_NONE), m_radius(1.0f), m_height(1.0f), - m_halfExtend(0.f,0.f,0.f), - m_childScale(1.0f,1.0f,1.0f), - m_userData(NULL), - m_refCount(1), - m_meshObject(NULL), - m_triangleIndexVertexArray(NULL), + m_halfExtend(0.0f, 0.0f, 0.0f), + m_childScale(1.0f, 1.0f, 1.0f), + m_userData(nullptr), + m_mesh(nullptr), + m_triangleIndexVertexArray(nullptr), m_forceReInstance(false), - m_weldingThreshold1(0.f), - m_shapeProxy(NULL) + m_weldingThreshold1(0.0f), + m_shapeProxy(nullptr) { m_childTrans.setIdentity(); } ~CcdShapeConstructionInfo(); - CcdShapeConstructionInfo* AddRef() - { - m_refCount++; - return this; - } - - int Release() - { - if (--m_refCount > 0) - return m_refCount; - delete this; - return 0; - } - - bool IsUnused(void) - { - return (m_meshObject==NULL && m_shapeArray.size() == 0 && m_shapeProxy == NULL); - } - - void AddShape(CcdShapeConstructionInfo* shapeInfo); + void AddShape(CcdShapeConstructionInfo *shapeInfo); btStridingMeshInterface *GetMeshInterface() { return m_triangleIndexVertexArray; } - CcdShapeConstructionInfo* GetChildShape(int i) + CcdShapeConstructionInfo *GetChildShape(int i) { if (i < 0 || i >= (int)m_shapeArray.size()) - return NULL; + return nullptr; return m_shapeArray.at(i); } - int FindChildShape(CcdShapeConstructionInfo* shapeInfo, void* userData) + int FindChildShape(CcdShapeConstructionInfo *shapeInfo, void *userData) { - if (shapeInfo == NULL) + if (shapeInfo == nullptr) return -1; - for (int i=0; i<(int)m_shapeArray.size(); i++) - { - CcdShapeConstructionInfo* childInfo = m_shapeArray.at(i); - if ((userData == NULL || userData == childInfo->m_userData) && - (childInfo == shapeInfo || - (childInfo->m_shapeType == PHY_SHAPE_PROXY && - childInfo->m_shapeProxy == shapeInfo))) + for (int i = 0; i < (int)m_shapeArray.size(); i++) { + CcdShapeConstructionInfo *childInfo = m_shapeArray.at(i); + if ((userData == nullptr || userData == childInfo->m_userData) && + (childInfo == shapeInfo || + (childInfo->m_shapeType == PHY_SHAPE_PROXY && + childInfo->m_shapeProxy == shapeInfo))) + { return i; + } } return -1; } @@ -143,126 +128,133 @@ class CcdShapeConstructionInfo if (i < 0 || i >= (int)m_shapeArray.size()) return false; m_shapeArray.at(i)->Release(); - if (i < (int)m_shapeArray.size()-1) + if (i < (int)m_shapeArray.size() - 1) m_shapeArray[i] = m_shapeArray.back(); m_shapeArray.pop_back(); return true; } - bool SetMesh(class RAS_MeshObject* mesh, struct DerivedMesh* dm, bool polytope); - RAS_MeshObject* GetMesh(void) - { - return m_meshObject; - } + bool UpdateMesh(class KX_GameObject *gameobj, class RAS_Mesh *mesh); - bool UpdateMesh(class KX_GameObject* gameobj, class RAS_MeshObject* mesh); + CcdShapeConstructionInfo *GetReplica(); + void ProcessReplica(); - bool SetProxy(CcdShapeConstructionInfo* shapeInfo); - CcdShapeConstructionInfo* GetProxy(void) + bool SetProxy(CcdShapeConstructionInfo *shapeInfo); + CcdShapeConstructionInfo *GetProxy(void) { return m_shapeProxy; } - btCollisionShape* CreateBulletShape(btScalar margin, bool useGimpact=false, bool useBvh=true); + RAS_Mesh *GetMesh() const; + + btCollisionShape *CreateBulletShape(btScalar margin, bool useGimpact = false, bool useBvh = true); // member variables - PHY_ShapeType m_shapeType; - btScalar m_radius; - btScalar m_height; - btVector3 m_halfExtend; - btTransform m_childTrans; - btVector3 m_childScale; - void* m_userData; - btAlignedObjectArray m_vertexArray; // Contains both vertex array for polytope shape and - // triangle array for concave mesh shape. Each vertex is 3 consecutive values - // In this case a triangle is made of 3 consecutive points - std::vector m_polygonIndexArray; // Contains the array of polygon index in the - // original mesh that correspond to shape triangles. - // only set for concave mesh shape. - - std::vector m_triFaceArray; // Contains an array of triplets of face indices - // quads turn into 2 tris - - std::vector m_triFaceUVcoArray; // Contains an array of pair of UV coordinate for each vertex of faces - // quads turn into 2 tris - - void setVertexWeldingThreshold1(float threshold) - { - m_weldingThreshold1 = threshold*threshold; + PHY_ShapeType m_shapeType; + btScalar m_radius; + btScalar m_height; + btVector3 m_halfExtend; + btTransform m_childTrans; + btVector3 m_childScale; + void *m_userData; + + /** Vertex mapping from original vertex index to shape vertex index. */ + std::vector m_vertexRemap; + + /** Contains both vertex array for polytope shape and triangle array for concave mesh shape. + * Each vertex is 3 consecutive values. In this case a triangle is made of 3 consecutive points + */ + btAlignedObjectArray m_vertexArray; + /** Contains the array of polygon index in the original mesh that correspond to shape triangles. + * only set for concave mesh shape. + */ + std::vector m_polygonIndexArray; + + /// Contains an array of triplets of face indices quads turn into 2 tris + std::vector m_triFaceArray; + + /// Contains an array of pair of UV coordinate for each vertex of faces quads turn into 2 tris + std::vector m_triFaceUVcoArray; + + void setVertexWeldingThreshold1(float threshold) + { + m_weldingThreshold1 = threshold * threshold; } protected: - static std::map m_meshShapeMap; - int m_refCount; // this class is shared between replicas - // keep track of users so that we can release it - RAS_MeshObject* m_meshObject; // Keep a pointer to the original mesh - // The list of vertexes and indexes for the triangle mesh, shared between Bullet shape. - btTriangleIndexVertexArray *m_triangleIndexVertexArray; - std::vector m_shapeArray; // for compound shapes - bool m_forceReInstance; //use gimpact for concave dynamic/moving collision detection - float m_weldingThreshold1; //welding closeby vertices together can improve softbody stability etc. - CcdShapeConstructionInfo* m_shapeProxy; // only used for PHY_SHAPE_PROXY, pointer to actual shape info + using MeshShapeKey = std::tuple; + using MeshShapeMap = std::map; - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:CcdShapeConstructionInfo") -#endif + static MeshShapeMap m_meshShapeMap; + /// Converted original mesh. + RAS_Mesh *m_mesh; + /// The list of vertexes and indexes for the triangle mesh, shared between Bullet shape. + btTriangleIndexVertexArray *m_triangleIndexVertexArray; + /// for compound shapes + std::vector m_shapeArray; + ///use gimpact for concave dynamic/moving collision detection + bool m_forceReInstance; + ///welding closeby vertices together can improve softbody stability etc. + float m_weldingThreshold1; + /// only used for PHY_SHAPE_PROXY, pointer to actual shape info + CcdShapeConstructionInfo *m_shapeProxy; }; -struct CcdConstructionInfo -{ +struct CcdConstructionInfo { - ///CollisionFilterGroups provides some optional usage of basic collision filtering - ///this is done during broadphase, so very early in the pipeline - ///more advanced collision filtering should be done in btCollisionDispatcher::NeedsCollision + /** CollisionFilterGroups provides some optional usage of basic collision filtering + * this is done during broadphase, so very early in the pipeline + * more advanced collision filtering should be done in btCollisionDispatcher::NeedsCollision + */ enum CollisionFilterGroups { - DefaultFilter = 1, + DynamicFilter = 1, StaticFilter = 2, KinematicFilter = 4, DebrisFilter = 8, SensorFilter = 16, CharacterFilter = 32, - AllFilter = DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter | SensorFilter | CharacterFilter, + AllFilter = DynamicFilter | StaticFilter | KinematicFilter | DebrisFilter | SensorFilter | CharacterFilter, }; - CcdConstructionInfo() - :m_localInertiaTensor(1.f, 1.f, 1.f), - m_gravity(0,0,0), - m_scaling(1.f,1.f,1.f), - m_linearFactor(0.f, 0.f, 0.f), - m_angularFactor(0.f, 0.f, 0.f), - m_mass(0.f), - m_clamp_vel_min(-1.f), - m_clamp_vel_max(-1.f), - m_clamp_angvel_min(0.0f), - m_clamp_angvel_max(0.0f), + :m_localInertiaTensor(1.0f, 1.0f, 1.0f), + m_gravity(0.0f, 0.0f, 0.0f), + m_scaling(1.0f, 1.0f, 1.0f), + m_linearFactor(0.0f, 0.0f, 0.0f), + m_angularFactor(0.0f, 0.0f, 0.0f), + m_mass(0.0f), + m_clamp_vel_min(-1.0f), + m_clamp_vel_max(-1.0f), + m_clamp_angvel_min(0.0f), + m_clamp_angvel_max(0.0f), m_restitution(0.1f), m_friction(0.5f), + m_rollingFriction(0.0f), m_linearDamping(0.1f), m_angularDamping(0.1f), m_margin(0.06f), m_gamesoftFlag(0), - m_soft_linStiff(1.f), - m_soft_angStiff(1.f), - m_soft_volume(1.f), + m_softBendingDistance(2), + m_soft_linStiff(1.0f), + m_soft_angStiff(1.0f), + m_soft_volume(1.0f), m_soft_viterations(0), m_soft_piterations(1), m_soft_diterations(0), m_soft_citerations(4), m_soft_kSRHR_CL(0.1f), - m_soft_kSKHR_CL(1.f), + m_soft_kSKHR_CL(1.0f), m_soft_kSSHR_CL(0.5f), m_soft_kSR_SPLT_CL(0.5f), m_soft_kSK_SPLT_CL(0.5f), m_soft_kSS_SPLT_CL(0.5f), - m_soft_kVCF(1.f), - m_soft_kDP(0.f), - m_soft_kDG(0.f), - m_soft_kLF(0.f), - m_soft_kPR(0.f), - m_soft_kVC(0.f), + m_soft_kVCF(1.0f), + m_soft_kDP(0.0f), + m_soft_kDG(0.0f), + m_soft_kLF(0.0f), + m_soft_kPR(0.0f), + m_soft_kVC(0.0f), m_soft_kDF(0.2f), m_soft_kMT(0), m_soft_kCHR(1.0f), @@ -270,149 +262,194 @@ struct CcdConstructionInfo m_soft_kSHR(1.0f), m_soft_kAHR(0.7f), m_collisionFlags(0), - m_bDyna(false), + m_bDyna(false), m_bRigid(false), m_bSoft(false), m_bSensor(false), m_bCharacter(false), m_bGimpact(false), - m_collisionFilterGroup(DefaultFilter), + m_collisionFilterGroup(DynamicFilter), m_collisionFilterMask(AllFilter), - m_collisionShape(0), - m_MotionState(0), - m_shapeInfo(0), - m_physicsEnv(0), - m_inertiaFactor(1.f), + m_collisionGroup(0xFFFF), + m_collisionMask(0xFFFF), + m_collisionShape(nullptr), + m_MotionState(nullptr), + m_shapeInfo(nullptr), + m_physicsEnv(nullptr), + m_inertiaFactor(1.0f), m_do_anisotropic(false), - m_anisotropicFriction(1.f,1.f,1.f), + m_anisotropicFriction(1.0f, 1.0f, 1.0f), m_do_fh(false), m_do_rot_fh(false), - m_fh_spring(0.f), - m_fh_damping(0.f), - m_fh_distance(1.f), + m_fh_spring(0.0f), + m_fh_damping(0.0f), + m_fh_distance(1.0f), m_fh_normal(false) // m_contactProcessingThreshold(1e10f) { - } - btVector3 m_localInertiaTensor; - btVector3 m_gravity; - btVector3 m_scaling; - btVector3 m_linearFactor; - btVector3 m_angularFactor; - btScalar m_mass; - btScalar m_clamp_vel_min; - btScalar m_clamp_vel_max; - btScalar m_clamp_angvel_min; // Minimum angular velocity, in radians/sec. - btScalar m_clamp_angvel_max; // Maximum angular velocity, in radians/sec. - btScalar m_restitution; - btScalar m_friction; - btScalar m_linearDamping; - btScalar m_angularDamping; - btScalar m_margin; - - //////////////////// - float m_stepHeight; - float m_jumpSpeed; - float m_fallSpeed; + btVector3 m_localInertiaTensor; + btVector3 m_gravity; + btVector3 m_scaling; + btVector3 m_linearFactor; + btVector3 m_angularFactor; + btScalar m_mass; + btScalar m_clamp_vel_min; + btScalar m_clamp_vel_max; + /// Minimum angular velocity, in radians/sec. + btScalar m_clamp_angvel_min; + /// Maximum angular velocity, in radians/sec. + btScalar m_clamp_angvel_max; + btScalar m_restitution; + btScalar m_friction; + btScalar m_rollingFriction; + btScalar m_linearDamping; + btScalar m_angularDamping; + btScalar m_margin; + + float m_stepHeight; + float m_jumpSpeed; + float m_fallSpeed; + float m_maxSlope; unsigned char m_maxJumps; - int m_gamesoftFlag; - float m_soft_linStiff; /* linear stiffness 0..1 */ - float m_soft_angStiff; /* angular stiffness 0..1 */ - float m_soft_volume; /* volume preservation 0..1 */ - - int m_soft_viterations; /* Velocities solver iterations */ - int m_soft_piterations; /* Positions solver iterations */ - int m_soft_diterations; /* Drift solver iterations */ - int m_soft_citerations; /* Cluster solver iterations */ - - float m_soft_kSRHR_CL; /* Soft vs rigid hardness [0,1] (cluster only) */ - float m_soft_kSKHR_CL; /* Soft vs kinetic hardness [0,1] (cluster only) */ - float m_soft_kSSHR_CL; /* Soft vs soft hardness [0,1] (cluster only) */ - float m_soft_kSR_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ - - float m_soft_kSK_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ - float m_soft_kSS_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ - float m_soft_kVCF; /* Velocities correction factor (Baumgarte) */ - float m_soft_kDP; /* Damping coefficient [0,1] */ - - float m_soft_kDG; /* Drag coefficient [0,+inf] */ - float m_soft_kLF; /* Lift coefficient [0,+inf] */ - float m_soft_kPR; /* Pressure coefficient [-inf,+inf] */ - float m_soft_kVC; /* Volume conversation coefficient [0,+inf] */ - - float m_soft_kDF; /* Dynamic friction coefficient [0,1] */ - float m_soft_kMT; /* Pose matching coefficient [0,1] */ - float m_soft_kCHR; /* Rigid contacts hardness [0,1] */ - float m_soft_kKHR; /* Kinetic contacts hardness [0,1] */ - - float m_soft_kSHR; /* Soft contacts hardness [0,1] */ - float m_soft_kAHR; /* Anchors hardness [0,1] */ - int m_soft_collisionflags; /* Vertex/Face or Signed Distance Field(SDF) or Clusters, Soft versus Soft or Rigid */ - int m_soft_numclusteriterations; /* number of iterations to refine collision clusters*/ -/////////////////// - - - - int m_collisionFlags; - bool m_bDyna; - bool m_bRigid; - bool m_bSoft; - bool m_bSensor; - bool m_bCharacter; - bool m_bGimpact; // use Gimpact for mesh body - - ///optional use of collision group/mask: - ///only collision with object goups that match the collision mask. - ///this is very basic early out. advanced collision filtering should be - ///done in the btCollisionDispatcher::NeedsCollision and NeedsResponse - ///both values default to 1 - short int m_collisionFilterGroup; - short int m_collisionFilterMask; - - ///these pointers are used as argument passing for the CcdPhysicsController constructor - ///and not anymore after that - class btCollisionShape* m_collisionShape; - class PHY_IMotionState* m_MotionState; - class CcdShapeConstructionInfo* m_shapeInfo; - - CcdPhysicsEnvironment* m_physicsEnv; //needed for self-replication - float m_inertiaFactor;//tweak the inertia (hooked up to Blender 'formfactor' - bool m_do_anisotropic; + int m_gamesoftFlag; + unsigned short m_softBendingDistance; + /// linear stiffness 0..1 + float m_soft_linStiff; + /// angular stiffness 0..1 + float m_soft_angStiff; + /// volume preservation 0..1 + float m_soft_volume; + + /// Velocities solver iterations + int m_soft_viterations; + /// Positions solver iterations + int m_soft_piterations; + /// Drift solver iterations + int m_soft_diterations; + /// Cluster solver iterations + int m_soft_citerations; + + /// Soft vs rigid hardness [0,1] (cluster only) + float m_soft_kSRHR_CL; + /// Soft vs kinetic hardness [0,1] (cluster only) + float m_soft_kSKHR_CL; + /// Soft vs soft hardness [0,1] (cluster only) + float m_soft_kSSHR_CL; + /// Soft vs rigid impulse split [0,1] (cluster only) + float m_soft_kSR_SPLT_CL; + /// Soft vs rigid impulse split [0,1] (cluster only) + float m_soft_kSK_SPLT_CL; + /// Soft vs rigid impulse split [0,1] (cluster only) + float m_soft_kSS_SPLT_CL; + /// Velocities correction factor (Baumgarte) + float m_soft_kVCF; + /// Damping coefficient [0,1] + float m_soft_kDP; + + /// Drag coefficient [0,+inf] + float m_soft_kDG; + /// Lift coefficient [0,+inf] + float m_soft_kLF; + /// Pressure coefficient [-inf,+inf] + float m_soft_kPR; + /// Volume conversation coefficient [0,+inf] + float m_soft_kVC; + + /// Dynamic friction coefficient [0,1] + float m_soft_kDF; + /// Pose matching coefficient [0,1] + float m_soft_kMT; + /// Rigid contacts hardness [0,1] + float m_soft_kCHR; + /// Kinetic contacts hardness [0,1] + float m_soft_kKHR; + + /// Soft contacts hardness [0,1] + float m_soft_kSHR; + /// Anchors hardness [0,1] + float m_soft_kAHR; + /// Vertex/Face or Signed Distance Field(SDF) or Clusters, Soft versus Soft or Rigid + int m_soft_collisionflags; + /// number of iterations to refine collision clusters + int m_soft_numclusteriterations; + + int m_collisionFlags; + bool m_bDyna; + bool m_bRigid; + bool m_bSoft; + bool m_bSensor; + bool m_bCharacter; + /// use Gimpact for mesh body + bool m_bGimpact; + + /** optional use of collision group/mask: + * only collision with object goups that match the collision mask. + * this is very basic early out. advanced collision filtering should be + * done in the btCollisionDispatcher::NeedsCollision and NeedsResponse + * both values default to 1 + */ + short int m_collisionFilterGroup; + short int m_collisionFilterMask; + + unsigned short m_collisionGroup; + unsigned short m_collisionMask; + + /** these pointers are used as argument passing for the CcdPhysicsController constructor + * and not anymore after that + */ + class btCollisionShape *m_collisionShape; + class PHY_IMotionState *m_MotionState; + class CcdShapeConstructionInfo *m_shapeInfo; + + /// needed for self-replication + CcdPhysicsEnvironment *m_physicsEnv; + /// tweak the inertia (hooked up to Blender 'formfactor' + float m_inertiaFactor; + bool m_do_anisotropic; btVector3 m_anisotropicFriction; - bool m_do_fh; ///< Should the object have a linear Fh spring? - bool m_do_rot_fh; ///< Should the object have an angular Fh spring? - btScalar m_fh_spring; ///< Spring constant (both linear and angular) - btScalar m_fh_damping; ///< Damping factor (linear and angular) in range [0, 1] - btScalar m_fh_distance; ///< The range above the surface where Fh is active. - bool m_fh_normal; ///< Should the object slide off slopes? - float m_radius;//for fh backwards compatibility - - ///m_contactProcessingThreshold allows to process contact points with positive distance - ///normally only contacts with negative distance (penetration) are solved - ///however, rigid body stacking is more stable when positive contacts are still passed into the constraint solver - ///this might sometimes lead to collisions with 'internal edges' such as a sliding character controller - ///so disable/set m_contactProcessingThreshold to zero for sliding characters etc. + /// Should the object have a linear Fh spring? + bool m_do_fh; + /// Should the object have an angular Fh spring? + bool m_do_rot_fh; + /// Spring constant (both linear and angular) + btScalar m_fh_spring; + /// Damping factor (linear and angular) in range [0, 1] + btScalar m_fh_damping; + /// The range above the surface where Fh is active. + btScalar m_fh_distance; + /// Should the object slide off slopes? + bool m_fh_normal; + /// for fh backwards compatibility + float m_radius; + + /** m_contactProcessingThreshold allows to process contact points with positive distance + * normally only contacts with negative distance (penetration) are solved + * however, rigid body stacking is more stable when positive contacts are still passed into the constraint solver + * this might sometimes lead to collisions with 'internal edges' such as a sliding character controller + * so disable/set m_contactProcessingThreshold to zero for sliding characters etc. + */ // float m_contactProcessingThreshold;///< Process contacts with positive distance in range [0..INF] }; class btRigidBody; class btCollisionObject; class btSoftBody; -class btPairCachingGhostObject; +class btGhostObject; -class BlenderBulletCharacterController : public btKinematicCharacterController, public PHY_ICharacter +class CcdCharacter : public btKinematicCharacterController, public PHY_ICharacter { private: - btMotionState* m_motionState; + CcdPhysicsController *m_ctrl; + btMotionState *m_motionState; unsigned char m_jumps; unsigned char m_maxJumps; public: - BlenderBulletCharacterController(btMotionState *motionState, btPairCachingGhostObject *ghost, btConvexShape* shape, float stepHeight); + CcdCharacter(CcdPhysicsController *ctrl, btMotionState *motionState, btGhostObject *ghost, btConvexShape *shape, float stepHeight); virtual void updateAction(btCollisionWorld *collisionWorld, btScalar dt); @@ -428,29 +465,59 @@ class BlenderBulletCharacterController : public btKinematicCharacterController, const btVector3& getWalkDirection(); + void SetVelocity(const btVector3& vel, float time, bool local); + // PHY_ICharacter interface - virtual void Jump() { jump(); } - virtual bool OnGround() { return onGround(); } - virtual float GetGravity() { return getGravity(); } - virtual void SetGravity(float gravity) { setGravity(gravity); } - virtual unsigned char GetMaxJumps() { return getMaxJumps(); } - virtual void SetMaxJumps(unsigned char maxJumps) { setMaxJumps(maxJumps); } - virtual unsigned char GetJumpCount() { return getJumpCount(); } - virtual void SetWalkDirection(const MT_Vector3& dir) + virtual void Jump() + { + jump(); + } + virtual bool OnGround() + { + return onGround(); + } + virtual mt::vec3 GetGravity() + { + return ToMt(getGravity()); + } + virtual void SetGravity(const mt::vec3& gravity) + { + setGravity(ToBullet(gravity)); + } + virtual unsigned char GetMaxJumps() + { + return getMaxJumps(); + } + virtual void SetMaxJumps(unsigned char maxJumps) + { + setMaxJumps(maxJumps); + } + virtual unsigned char GetJumpCount() { - btVector3 vec = btVector3(dir[0], dir[1], dir[2]); - setWalkDirection(vec); + return getJumpCount(); } - virtual MT_Vector3 GetWalkDirection() + virtual void SetWalkDirection(const mt::vec3& dir) { - btVector3 vec = getWalkDirection(); - return MT_Vector3(vec[0], vec[1], vec[2]); + setWalkDirection(ToBullet(dir)); } -#ifdef WITH_CXX_GUARDEDALLOC - using PHY_ICharacter::operator new; - using PHY_ICharacter::operator delete; -#endif + virtual mt::vec3 GetWalkDirection() + { + return ToMt(getWalkDirection()); + } + + virtual float GetFallSpeed() const; + virtual void SetFallSpeed(float fallSpeed); + + virtual float GetMaxSlope() const; + virtual void SetMaxSlope(float maxSlope); + + virtual float GetJumpSpeed() const; + virtual void SetJumpSpeed(float jumpSpeed); + + virtual void SetVelocity(const mt::vec3& vel, float time, bool local); + + virtual void Reset(); }; class CleanPairCallback : public btOverlapCallback @@ -470,55 +537,57 @@ class CleanPairCallback : public btOverlapCallback virtual bool processOverlap(btBroadphasePair &pair); }; -///CcdPhysicsController is a physics object that supports continuous collision detection and time of impact based physics resolution. -class CcdPhysicsController : public PHY_IPhysicsController +/// CcdPhysicsController is a physics object that supports continuous collision detection and time of impact based physics resolution. +class CcdPhysicsController : public PHY_IPhysicsController, public mt::SimdClassAllocator { protected: - btCollisionObject* m_object; - BlenderBulletCharacterController* m_characterController; - + btCollisionObject *m_object; + CcdCharacter *m_characterController; - class PHY_IMotionState* m_MotionState; - btMotionState* m_bulletMotionState; - class btCollisionShape* m_collisionShape; - class CcdShapeConstructionInfo* m_shapeInfo; - btCollisionShape* m_bulletChildShape; + class PHY_IMotionState *m_MotionState; + btMotionState *m_bulletMotionState; + class btCollisionShape *m_collisionShape; + class CcdShapeConstructionInfo *m_shapeInfo; + btCollisionShape *m_bulletChildShape; - btAlignedObjectArray m_ccdConstraintRefs; // keep track of typed constraints referencing this rigid body - friend class CcdPhysicsEnvironment; // needed when updating the controller + /// keep track of typed constraints referencing this rigid body + btAlignedObjectArray m_ccdConstraintRefs; + /// needed when updating the controller + friend class CcdPhysicsEnvironment; //some book keeping for replication - bool m_softbodyMappingDone; - bool m_softBodyTransformInitialized; - bool m_prototypeTransformInitialized; - btTransform m_softbodyStartTrans; + bool m_softBodyTransformInitialized; + btTransform m_softbodyStartTrans; + /// Soft body indices for all original vertices. + std::vector m_softBodyIndices; - void* m_newClientInfo; - int m_registerCount; // needed when multiple sensors use the same controller - CcdConstructionInfo m_cci;//needed for replication + void *m_newClientInfo; + int m_registerCount; // needed when multiple sensors use the same controller + CcdConstructionInfo m_cci;//needed for replication - CcdPhysicsController* m_parentCtrl; + CcdPhysicsController *m_parentRoot; int m_savedCollisionFlags; short m_savedCollisionFilterGroup; short m_savedCollisionFilterMask; - MT_Scalar m_savedMass; + float m_savedMass; bool m_savedDyna; bool m_suspended; - void GetWorldOrientation(btMatrix3x3& mat); void CreateRigidbody(); bool CreateSoftbody(); bool CreateCharacterController(); - bool Register() { - return (m_registerCount++ == 0) ? true : false; + bool Register() + { + return (m_registerCount++ == 0); } - bool Unregister() { - return (--m_registerCount == 0) ? true : false; + bool Unregister() + { + return (--m_registerCount == 0); } bool Registered() const @@ -526,307 +595,291 @@ class CcdPhysicsController : public PHY_IPhysicsController return (m_registerCount != 0); } - void addCcdConstraintRef(btTypedConstraint* c); - void removeCcdConstraintRef(btTypedConstraint* c); - btTypedConstraint* getCcdConstraintRef(int index); + void addCcdConstraintRef(btTypedConstraint *c); + void removeCcdConstraintRef(btTypedConstraint *c); + btTypedConstraint *getCcdConstraintRef(int index); int getNumCcdConstraintRefs() const; void SetWorldOrientation(const btMatrix3x3& mat); void ForceWorldTransform(const btMatrix3x3& mat, const btVector3& pos); - public: - - int m_collisionDelay; - - - CcdPhysicsController (const CcdConstructionInfo& ci); +public: - /** - * Delete the current Bullet shape used in the rigid body. - */ - bool DeleteControllerShape(); + CcdPhysicsController(const CcdConstructionInfo& ci); - /** - * Delete the old Bullet shape and set the new Bullet shape : newShape - * \param newShape The new Bullet shape to set, if is NULL we create a new Bullet shape - */ - bool ReplaceControllerShape(btCollisionShape *newShape); + /** + * Delete the current Bullet shape used in the rigid body. + */ + bool DeleteControllerShape(); - virtual ~CcdPhysicsController(); + /** + * Delete the old Bullet shape and set the new Bullet shape : newShape + * \param newShape The new Bullet shape to set, if is nullptr we create a new Bullet shape + */ + bool ReplaceControllerShape(btCollisionShape *newShape); - CcdConstructionInfo& GetConstructionInfo() - { - return m_cci; - } - const CcdConstructionInfo& GetConstructionInfo() const - { - return m_cci; - } + virtual ~CcdPhysicsController(); + CcdConstructionInfo& GetConstructionInfo() + { + return m_cci; + } + const CcdConstructionInfo& GetConstructionInfo() const + { + return m_cci; + } - btRigidBody* GetRigidBody(); - const btRigidBody* GetRigidBody() const; - btCollisionObject* GetCollisionObject(); - btSoftBody* GetSoftBody(); - btKinematicCharacterController* GetCharacterController(); - - CcdShapeConstructionInfo* GetShapeInfo() { return m_shapeInfo; } + btRigidBody *GetRigidBody(); + const btRigidBody *GetRigidBody() const; + btCollisionObject *GetCollisionObject(); + btSoftBody *GetSoftBody(); + btKinematicCharacterController *GetCharacterController(); - btCollisionShape* GetCollisionShape() { - return m_object->getCollisionShape(); - } - //////////////////////////////////// - // PHY_IPhysicsController interface - //////////////////////////////////// - - - /** - * SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding') - */ - virtual bool SynchronizeMotionStates(float time); - - /** - * Called for every physics simulation step. Use this method for - * things like limiting linear and angular velocity. - */ - void SimulationTick(float timestep); - - /** - * WriteMotionStateToDynamics ynchronizes dynas, kinematic and deformable entities (and do 'late binding') - */ - - virtual void WriteMotionStateToDynamics(bool nondynaonly); - virtual void WriteDynamicsToMotionState(); - - // controller replication - virtual void PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl); - virtual void SetPhysicsEnvironment(class PHY_IPhysicsEnvironment *env); - - // kinematic methods - virtual void RelativeTranslate(const MT_Vector3& dloc,bool local); - virtual void RelativeRotate(const MT_Matrix3x3&rotval, bool local); - virtual MT_Matrix3x3 GetOrientation(); - virtual void SetOrientation(const MT_Matrix3x3& orn); - virtual void SetPosition(const MT_Vector3& pos); - virtual void GetPosition(MT_Vector3& pos) const; - virtual void SetScaling(const MT_Vector3& scale); - virtual void SetTransform(); - - virtual MT_Scalar GetMass(); - virtual void SetMass(MT_Scalar newmass); - - // physics methods - virtual void ApplyImpulse(const MT_Point3& attach, const MT_Vector3& impulsein, bool local); - virtual void ApplyTorque(const MT_Vector3& torque,bool local); - virtual void ApplyForce(const MT_Vector3& force,bool local); - virtual void SetAngularVelocity(const MT_Vector3& ang_vel,bool local); - virtual void SetLinearVelocity(const MT_Vector3& lin_vel,bool local); - virtual void Jump(); - virtual void SetActive(bool active); - - virtual float GetLinearDamping() const; - virtual float GetAngularDamping() const; - virtual void SetLinearDamping(float damping); - virtual void SetAngularDamping(float damping); - virtual void SetDamping(float linear, float angular); - - // reading out information from physics - virtual MT_Vector3 GetLinearVelocity(); - virtual MT_Vector3 GetAngularVelocity(); - virtual MT_Vector3 GetVelocity(const MT_Point3& posin); - virtual MT_Vector3 GetLocalInertia(); - - // dyna's that are rigidbody are free in orientation, dyna's with non-rigidbody are restricted - virtual void SetRigidBody(bool rigid); - - - virtual void ResolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ); - virtual void RefreshCollisions(); - virtual void SuspendDynamics(bool ghost); - virtual void RestoreDynamics(); - - // Shape control - virtual void AddCompoundChild(PHY_IPhysicsController* child); - virtual void RemoveCompoundChild(PHY_IPhysicsController* child); - - // clientinfo for raycasts for example - virtual void* GetNewClientInfo(); - virtual void SetNewClientInfo(void* clientinfo); - virtual PHY_IPhysicsController* GetReplica(); - virtual PHY_IPhysicsController* GetReplicaForSensors(); - - ///There should be no 'SetCollisionFilterGroup' method, as changing this during run-time is will result in errors - short int GetCollisionFilterGroup() const - { - return m_cci.m_collisionFilterGroup; - } - ///There should be no 'SetCollisionFilterGroup' method, as changing this during run-time is will result in errors - short int GetCollisionFilterMask() const - { - return m_cci.m_collisionFilterMask; - } + CcdShapeConstructionInfo *GetShapeInfo() + { + return m_shapeInfo; + } - virtual void CalcXform() {} - virtual void SetMargin(float margin) - { - if (m_collisionShape) { - m_collisionShape->setMargin(margin); - // if the shape use a unscaled shape we have also to set the correct margin in it - if (m_collisionShape->getShapeType() == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE) - ((btScaledBvhTriangleMeshShape *)m_collisionShape)->getChildShape()->setMargin(margin); - } - } - virtual float GetMargin() const - { - return (m_collisionShape) ? m_collisionShape->getMargin() : 0.f; - } - virtual float GetRadius() const - { - // this is not the actual shape radius, it's only used for Fh support - return m_cci.m_radius; - } - virtual void SetRadius(float margin) - { - if (m_collisionShape && m_collisionShape->getShapeType() == SPHERE_SHAPE_PROXYTYPE) - { - btSphereShape* sphereShape = static_cast(m_collisionShape); - sphereShape->setUnscaledRadius(margin); - } - m_cci.m_radius = margin; - } + btCollisionShape *GetCollisionShape() + { + return m_object->getCollisionShape(); + } - // velocity clamping - virtual void SetLinVelocityMin(float val) - { - m_cci.m_clamp_vel_min= val; - } - virtual float GetLinVelocityMin() const - { - return m_cci.m_clamp_vel_min; - } - virtual void SetLinVelocityMax(float val) - { - m_cci.m_clamp_vel_max= val; - } - virtual float GetLinVelocityMax() const - { - return m_cci.m_clamp_vel_max; - } + const std::vector& GetSoftBodyIndices() const; + //////////////////////////////////// + // PHY_IPhysicsController interface + //////////////////////////////////// + + /** + * SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding') + */ + virtual bool SynchronizeMotionStates(float time); + + /** + * Called for every physics simulation step. Use this method for + * things like limiting linear and angular velocity. + */ + void SimulationTick(float timestep); + + /** + * WriteMotionStateToDynamics ynchronizes dynas, kinematic and deformable entities (and do 'late binding') + */ + virtual void WriteMotionStateToDynamics(bool nondynaonly); + virtual void WriteDynamicsToMotionState(); + + // controller replication + virtual void PostProcessReplica(class PHY_IMotionState *motionstate, class PHY_IPhysicsController *parentctrl); + virtual void SetPhysicsEnvironment(class PHY_IPhysicsEnvironment *env); + + // kinematic methods + virtual void RelativeTranslate(const mt::vec3& dloc, bool local); + virtual void RelativeRotate(const mt::mat3&rotval, bool local); + virtual mt::mat3 GetOrientation(); + virtual void SetOrientation(const mt::mat3& orn); + virtual void SetPosition(const mt::vec3& pos); + virtual mt::vec3 GetPosition() const; + virtual void SetScaling(const mt::vec3& scale); + virtual void SetTransform(); + + virtual float GetMass(); + virtual void SetMass(float newmass); + + float GetInertiaFactor() const; + + // physics methods + virtual void ApplyImpulse(const mt::vec3& attach, const mt::vec3& impulsein, bool local); + virtual void ApplyTorque(const mt::vec3& torque, bool local); + virtual void ApplyForce(const mt::vec3& force, bool local); + virtual void SetAngularVelocity(const mt::vec3& ang_vel, bool local); + virtual void SetLinearVelocity(const mt::vec3& lin_vel, bool local); + virtual void Jump(); + virtual void SetActive(bool active); + + virtual unsigned short GetCollisionGroup() const; + virtual unsigned short GetCollisionMask() const; + virtual void SetCollisionGroup(unsigned short group); + virtual void SetCollisionMask(unsigned short mask); + + virtual float GetLinearDamping() const; + virtual float GetAngularDamping() const; + virtual void SetLinearDamping(float damping); + virtual void SetAngularDamping(float damping); + virtual void SetDamping(float linear, float angular); + virtual void SetGravity(const mt::vec3 &gravity); + + // reading out information from physics + virtual mt::vec3 GetLinearVelocity(); + virtual mt::vec3 GetAngularVelocity(); + virtual mt::vec3 GetVelocity(const mt::vec3& posin); + virtual mt::vec3 GetLocalInertia(); + virtual mt::vec3 GetGravity(); + + // dyna's that are rigidbody are free in orientation, dyna's with non-rigidbody are restricted + virtual void SetRigidBody(bool rigid); + + virtual void RefreshCollisions(); + virtual void SuspendPhysics(bool freeConstraints); + virtual void RestorePhysics(); + virtual void SuspendDynamics(bool ghost); + virtual void RestoreDynamics(); + + // Shape control + virtual void AddCompoundChild(PHY_IPhysicsController *child); + virtual void RemoveCompoundChild(PHY_IPhysicsController *child); + + // clientinfo for raycasts for example + virtual void *GetNewClientInfo(); + virtual void SetNewClientInfo(void *clientinfo); + virtual PHY_IPhysicsController *GetReplica(); + virtual PHY_IPhysicsController *GetReplicaForSensors(); + + ///There should be no 'SetCollisionFilterGroup' method, as changing this during run-time is will result in errors + short int GetCollisionFilterGroup() const + { + return m_cci.m_collisionFilterGroup; + } + ///There should be no 'SetCollisionFilterGroup' method, as changing this during run-time is will result in errors + short int GetCollisionFilterMask() const + { + return m_cci.m_collisionFilterMask; + } - virtual void SetAngularVelocityMin(float val) - { - m_cci.m_clamp_angvel_min = val; - } - virtual float GetAngularVelocityMin() const - { - return m_cci.m_clamp_angvel_min; - } - virtual void SetAngularVelocityMax(float val) - { - m_cci.m_clamp_angvel_max = val; + virtual void SetMargin(float margin) + { + if (m_collisionShape) { + m_collisionShape->setMargin(margin); + // if the shape use a unscaled shape we have also to set the correct margin in it + if (m_collisionShape->getShapeType() == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE) + ((btScaledBvhTriangleMeshShape *)m_collisionShape)->getChildShape()->setMargin(margin); } - virtual float GetAngularVelocityMax() const - { - return m_cci.m_clamp_angvel_max; + } + virtual float GetMargin() const + { + return (m_collisionShape) ? m_collisionShape->getMargin() : 0.0f; + } + virtual float GetRadius() const + { + // this is not the actual shape radius, it's only used for Fh support + return m_cci.m_radius; + } + virtual void SetRadius(float margin) + { + if (m_collisionShape && m_collisionShape->getShapeType() == SPHERE_SHAPE_PROXYTYPE) { + btSphereShape *sphereShape = static_cast(m_collisionShape); + sphereShape->setUnscaledRadius(margin); } + m_cci.m_radius = margin; + } - bool WantsSleeping(); - - void UpdateDeactivation(float timeStep); - - void SetCenterOfMassTransform(btTransform& xform); + /// velocity clamping + virtual void SetLinVelocityMin(float val) + { + m_cci.m_clamp_vel_min = val; + } + virtual float GetLinVelocityMin() const + { + return m_cci.m_clamp_vel_min; + } + virtual void SetLinVelocityMax(float val) + { + m_cci.m_clamp_vel_max = val; + } + virtual float GetLinVelocityMax() const + { + return m_cci.m_clamp_vel_max; + } - static btTransform& GetTransformFromMotionState(PHY_IMotionState* motionState); + virtual void SetAngularVelocityMin(float val) + { + m_cci.m_clamp_angvel_min = val; + } + virtual float GetAngularVelocityMin() const + { + return m_cci.m_clamp_angvel_min; + } + virtual void SetAngularVelocityMax(float val) + { + m_cci.m_clamp_angvel_max = val; + } + virtual float GetAngularVelocityMax() const + { + return m_cci.m_clamp_angvel_max; + } - void setAabb(const btVector3& aabbMin,const btVector3& aabbMax); + bool WantsSleeping(); + void UpdateDeactivation(float timeStep); - class PHY_IMotionState* GetMotionState() - { - return m_MotionState; - } + void SetCenterOfMassTransform(btTransform& xform); - const class PHY_IMotionState* GetMotionState() const - { - return m_MotionState; - } + static btTransform GetTransformFromMotionState(PHY_IMotionState *motionState); - class CcdPhysicsEnvironment* GetPhysicsEnvironment() - { - return m_cci.m_physicsEnv; - } + class PHY_IMotionState *GetMotionState() + { + return m_MotionState; + } - void SetParentCtrl(CcdPhysicsController* parentCtrl) - { - m_parentCtrl = parentCtrl; - } + const class PHY_IMotionState *GetMotionState() const + { + return m_MotionState; + } - CcdPhysicsController* GetParentCtrl() - { - return m_parentCtrl; - } + class CcdPhysicsEnvironment *GetPhysicsEnvironment() + { + return m_cci.m_physicsEnv; + } - const CcdPhysicsController* GetParentCtrl() const - { - return m_parentCtrl; - } + void SetParentRoot(CcdPhysicsController *parentCtrl) + { + m_parentRoot = parentCtrl; + } - virtual bool IsDynamic() - { - return GetConstructionInfo().m_bDyna; - } + CcdPhysicsController *GetParentRoot() const + { + return m_parentRoot; + } - virtual bool IsSuspended() const - { - return m_suspended; - } + virtual bool IsDynamic() + { + return GetConstructionInfo().m_bDyna; + } - virtual bool IsCompound() - { - return GetConstructionInfo().m_shapeInfo->m_shapeType == PHY_SHAPE_COMPOUND; - } + virtual bool IsDynamicsSuspended() const + { + return m_suspended; + } - virtual bool ReinstancePhysicsShape(KX_GameObject *from_gameobj, RAS_MeshObject* from_meshobj); + virtual bool IsPhysicsSuspended(); - /* Method to replicate rigid body joint contraints for group instances. */ - virtual void ReplicateConstraints(KX_GameObject *gameobj, std::vector constobj); + virtual bool IsCompound() + { + return GetConstructionInfo().m_shapeInfo->m_shapeType == PHY_SHAPE_COMPOUND; + } -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:CcdPhysicsController") -#endif + virtual bool ReinstancePhysicsShape(KX_GameObject *from_gameobj, RAS_Mesh *from_meshobj, bool dupli = false); + virtual void ReplacePhysicsShape(PHY_IPhysicsController *phyctrl); }; - - - -///DefaultMotionState implements standard motionstate, using btTransform -class DefaultMotionState : public PHY_IMotionState - +/// DefaultMotionState implements standard motionstate, using btTransform +class DefaultMotionState : public PHY_IMotionState, public mt::SimdClassAllocator { - public: - DefaultMotionState(); - - virtual ~DefaultMotionState(); - - virtual void GetWorldPosition(float& posX,float& posY,float& posZ); - virtual void GetWorldScaling(float& scaleX,float& scaleY,float& scaleZ); - virtual void GetWorldOrientation(float& quatIma0,float& quatIma1,float& quatIma2,float& quatReal); +public: + DefaultMotionState(); - virtual void SetWorldPosition(float posX,float posY,float posZ); - virtual void SetWorldOrientation(float quatIma0,float quatIma1,float quatIma2,float quatReal); - virtual void GetWorldOrientation(float* ori); - virtual void SetWorldOrientation(const float* ori); + virtual ~DefaultMotionState(); - virtual void CalculateWorldTransformations(); + virtual mt::vec3 GetWorldPosition() const; + virtual mt::vec3 GetWorldScaling() const; + virtual mt::mat3 GetWorldOrientation() const; - btTransform m_worldTransform; - btVector3 m_localScaling; + virtual void SetWorldPosition(const mt::vec3& pos); + virtual void SetWorldOrientation(const mt::mat3& ori); + virtual void SetWorldOrientation(const mt::quat& quat); + virtual void CalculateWorldTransformations(); -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:DefaultMotionState") -#endif + btTransform m_worldTransform; + btVector3 m_localScaling; }; - #endif /* __CCDPHYSICSCONTROLLER_H__ */ diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp index 910b3a7dc84a..f291f252e96d 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp @@ -2,36 +2,41 @@ * \ingroup physbullet */ /* -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. -*/ - - - + 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 "CcdPhysicsEnvironment.h" #include "CcdPhysicsController.h" #include "CcdGraphicController.h" +#include "CcdConstraint.h" +#include "CcdMathUtils.h" #include #include "btBulletDynamicsCommon.h" #include "LinearMath/btIDebugDraw.h" #include "BulletCollision/CollisionDispatch/btGhostObject.h" #include "BulletCollision/CollisionDispatch/btSimulationIslandManager.h" -#include "BulletSoftBody/btSoftRigidDynamicsWorld.h" +#include "BulletCollision/CollisionDispatch/btCollisionDispatcherMt.h" +#include "BulletSoftBody/btSoftRigidDynamicsWorldMt.h" #include "BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h" #include "BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h" #include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h" +#include "BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.h" +#include "BulletDynamics/MLCPSolvers/btMLCPSolver.h" +#include "BulletDynamics/MLCPSolvers/btDantzigSolver.h" +#include "BulletDynamics/MLCPSolvers/btLemkeSolver.h" +#include "BulletDynamics/MLCPSolvers/btPATHSolver.h" //profiling/timings #include "LinearMath/btQuickprof.h" @@ -39,16 +44,17 @@ subject to the following restrictions: #include "PHY_IMotionState.h" #include "PHY_ICharacter.h" -#include "PHY_Pro.h" #include "KX_GameObject.h" -#include "KX_PythonInit.h" // for KX_RasterizerDrawDebugLine -#include "KX_BlenderSceneConverter.h" -#include "RAS_MeshObject.h" -#include "RAS_Polygon.h" -#include "RAS_TexVert.h" +#include "KX_Globals.h" // for KX_RasterizerDrawDebugLine +#include "KX_Mesh.h" +#include "BL_SceneConverter.h" +#include "RAS_DisplayArray.h" +#include "RAS_MaterialBucket.h" +#include "RAS_IMaterial.h" #include "DNA_scene_types.h" #include "DNA_world_types.h" +#include "DNA_object_types.h" // for OB_MAX_COL_MASKS #include "DNA_object_force_types.h" extern "C" { @@ -58,29 +64,23 @@ extern "C" { #define CCD_CONSTRAINT_DISABLE_LINKED_COLLISION 0x80 -#ifdef NEW_BULLET_VEHICLE_SUPPORT #include "BulletDynamics/Vehicle/btRaycastVehicle.h" #include "BulletDynamics/Vehicle/btVehicleRaycaster.h" #include "BulletDynamics/Vehicle/btWheelInfo.h" #include "PHY_IVehicle.h" -static btRaycastVehicle::btVehicleTuning gTuning; +static btRaycastVehicle::btVehicleTuning gTuning; -#endif //NEW_BULLET_VEHICLE_SUPPORT #include "LinearMath/btAabbUtil2.h" -#include "MT_Matrix4x4.h" -#include "MT_Vector3.h" -#include "MT_MinMax.h" #ifdef WIN32 -void DrawRasterizerLine(const float* from,const float* to,int color); +void DrawRasterizerLine(const float *from, const float *to, int color); #endif #include "BulletDynamics/ConstraintSolver/btContactConstraint.h" - -#include -#include // for memset +#include "CM_Message.h" +#include "CM_List.h" // This was copied from the old KX_ConvertPhysicsObjects #ifdef WIN32 @@ -97,112 +97,181 @@ void DrawRasterizerLine(const float* from,const float* to,int color); #endif //_MSC_VER #endif //WIN32 -#ifdef NEW_BULLET_VEHICLE_SUPPORT -class WrapperVehicle : public PHY_IVehicle +class VehicleClosestRayResultCallback : public btCollisionWorld::ClosestRayResultCallback { +private: + const btCollisionShape *m_hitTriangleShape; + unsigned short m_mask; + +public: + VehicleClosestRayResultCallback(const btVector3& rayFrom, const btVector3& rayTo, unsigned short mask) + :btCollisionWorld::ClosestRayResultCallback(rayFrom, rayTo), + m_mask(mask) + { + } + + virtual ~VehicleClosestRayResultCallback() + { + } - btRaycastVehicle* m_vehicle; - PHY_IPhysicsController* m_chassis; + virtual bool needsCollision(btBroadphaseProxy *proxy0) const + { + if (!btCollisionWorld::ClosestRayResultCallback::needsCollision(proxy0)) { + return false; + } + + btCollisionObject *object = (btCollisionObject *)proxy0->m_clientObject; + CcdPhysicsController *phyCtrl = static_cast(object->getUserPointer()); + + if (phyCtrl->GetCollisionGroup() & m_mask) { + return true; + } + + return false; + } +}; + +class BlenderVehicleRaycaster : public btDefaultVehicleRaycaster +{ +private: + btDynamicsWorld *m_dynamicsWorld; + unsigned short m_mask; public: + BlenderVehicleRaycaster(btDynamicsWorld *world) + :btDefaultVehicleRaycaster(world), + m_dynamicsWorld(world), + m_mask((1 << OB_MAX_COL_MASKS) - 1) + { + } - WrapperVehicle(btRaycastVehicle* vehicle,PHY_IPhysicsController* chassis) + virtual void *castRay(const btVector3& from, const btVector3& to, btVehicleRaycasterResult& result) + { + // RayResultCallback& resultCallback; + + VehicleClosestRayResultCallback rayCallback(from, to, m_mask); + + // We override btDefaultVehicleRaycaster so we can set this flag, otherwise our + // vehicles go crazy (http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=9662) + rayCallback.m_flags |= btTriangleRaycastCallback::kF_UseSubSimplexConvexCastRaytest; + + m_dynamicsWorld->rayTest(from, to, rayCallback); + + if (rayCallback.hasHit()) { + const btRigidBody *body = btRigidBody::upcast(rayCallback.m_collisionObject); + if (body && body->hasContactResponse()) { + result.m_hitPointInWorld = rayCallback.m_hitPointWorld; + result.m_hitNormalInWorld = rayCallback.m_hitNormalWorld; + result.m_hitNormalInWorld.normalize(); + result.m_distFraction = rayCallback.m_closestHitFraction; + return (void *)body; + } + } + return nullptr; + } + + unsigned short GetRayCastMask() const + { + return m_mask; + } + + void SetRayCastMask(unsigned short mask) + { + m_mask = mask; + } +}; + +class WrapperVehicle : public PHY_IVehicle +{ + btRaycastVehicle *m_vehicle; + BlenderVehicleRaycaster *m_raycaster; + PHY_IPhysicsController *m_chassis; + +public: + WrapperVehicle(btRaycastVehicle *vehicle, BlenderVehicleRaycaster *raycaster, PHY_IPhysicsController *chassis) :m_vehicle(vehicle), + m_raycaster(raycaster), m_chassis(chassis) { } ~WrapperVehicle() { + for (unsigned short i = 0, numWheels = GetNumWheels(); i < numWheels; ++i) { + btWheelInfo& info = m_vehicle->getWheelInfo(i); + PHY_IMotionState *motionState = (PHY_IMotionState *)info.m_clientInfo; + delete motionState; + } + delete m_vehicle; + delete m_raycaster; } - btRaycastVehicle* GetVehicle() + btRaycastVehicle *GetVehicle() { return m_vehicle; } - PHY_IPhysicsController* GetChassis() + PHY_IPhysicsController *GetChassis() { return m_chassis; } - virtual void AddWheel( - PHY_IMotionState* motionState, - MT_Vector3 connectionPoint, - MT_Vector3 downDirection, - MT_Vector3 axleDirection, - float suspensionRestLength, - float wheelRadius, - bool hasSteering - ) + virtual void AddWheel(PHY_IMotionState *motionState, + const mt::vec3 &connectionPoint, + const mt::vec3 &downDirection, + const mt::vec3 &axleDirection, + float suspensionRestLength, + float wheelRadius, + bool hasSteering) { - btVector3 connectionPointCS0(connectionPoint[0],connectionPoint[1],connectionPoint[2]); - btVector3 wheelDirectionCS0(downDirection[0],downDirection[1],downDirection[2]); - btVector3 wheelAxle(axleDirection[0],axleDirection[1],axleDirection[2]); - - - btWheelInfo& info = m_vehicle->addWheel(connectionPointCS0,wheelDirectionCS0,wheelAxle, - suspensionRestLength,wheelRadius,gTuning,hasSteering); + btWheelInfo& info = m_vehicle->addWheel(ToBullet(connectionPoint), ToBullet(downDirection.Normalized()), + ToBullet(axleDirection.Normalized()), suspensionRestLength, wheelRadius, gTuning, hasSteering); info.m_clientInfo = motionState; - } - void SyncWheels() + void SyncWheels() { int numWheels = GetNumWheels(); int i; - for (i=0;igetWheelInfo(i); - PHY_IMotionState* motionState = (PHY_IMotionState*)info.m_clientInfo; - // m_vehicle->updateWheelTransformsWS(info,false); - m_vehicle->updateWheelTransform(i,false); - btTransform trans = m_vehicle->getWheelInfo(i).m_worldTransform; - btQuaternion orn = trans.getRotation(); - const btVector3& pos = trans.getOrigin(); - motionState->SetWorldOrientation(orn.x(),orn.y(),orn.z(),orn[3]); - motionState->SetWorldPosition(pos.x(),pos.y(),pos.z()); - + PHY_IMotionState *motionState = (PHY_IMotionState *)info.m_clientInfo; + m_vehicle->updateWheelTransform(i, false); + const btTransform trans = m_vehicle->getWheelInfo(i).m_worldTransform; + motionState->SetWorldOrientation(ToMt(trans.getBasis())); + motionState->SetWorldPosition(ToMt(trans.getOrigin())); } } - virtual int GetNumWheels() const + virtual int GetNumWheels() const { return m_vehicle->getNumWheels(); } - virtual void GetWheelPosition(int wheelIndex,float& posX,float& posY,float& posZ) const + virtual mt::vec3 GetWheelPosition(int wheelIndex) const { - if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels())) - { - btVector3 origin = m_vehicle->getWheelTransformWS(wheelIndex).getOrigin(); - - posX = origin.x(); - posY = origin.y(); - posZ = origin.z(); + if ((wheelIndex >= 0) && (wheelIndex < m_vehicle->getNumWheels())) { + const btVector3 origin = m_vehicle->getWheelTransformWS(wheelIndex).getOrigin(); + return ToMt(origin); } + return mt::zero3; } - virtual void GetWheelOrientationQuaternion(int wheelIndex,float& quatX,float& quatY,float& quatZ,float& quatW) const + virtual mt::quat GetWheelOrientationQuaternion(int wheelIndex) const { - if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels())) - { - btQuaternion quat = m_vehicle->getWheelTransformWS(wheelIndex).getRotation(); - - quatX = quat.x(); - quatY = quat.y(); - quatZ = quat.z(); - quatW = quat.w(); + if ((wheelIndex >= 0) && (wheelIndex < m_vehicle->getNumWheels())) { + const btQuaternion quat = m_vehicle->getWheelTransformWS(wheelIndex).getRotation(); + return ToMt(quat); } + return mt::quat(0.0f, 0.0f, 0.0f, 0.0f); } - virtual float GetWheelRotation(int wheelIndex) const + virtual float GetWheelRotation(int wheelIndex) const { - float rotation = 0.f; + float rotation = 0.0f; - if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels())) - { + if ((wheelIndex >= 0) && (wheelIndex < m_vehicle->getNumWheels())) { btWheelInfo& info = m_vehicle->getWheelInfo(wheelIndex); rotation = info.m_rotation; } @@ -210,329 +279,333 @@ class WrapperVehicle : public PHY_IVehicle return rotation; } - - - virtual int GetUserConstraintId() const + virtual int GetUserConstraintId() const { return m_vehicle->getUserConstraintId(); } - virtual int GetUserConstraintType() const + virtual int GetUserConstraintType() const { return m_vehicle->getUserConstraintType(); } - virtual void SetSteeringValue(float steering,int wheelIndex) + virtual void SetSteeringValue(float steering, int wheelIndex) { - if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels())) { - m_vehicle->setSteeringValue(steering,wheelIndex); + if ((wheelIndex >= 0) && (wheelIndex < m_vehicle->getNumWheels())) { + m_vehicle->setSteeringValue(steering, wheelIndex); } } - virtual void ApplyEngineForce(float force,int wheelIndex) + virtual void ApplyEngineForce(float force, int wheelIndex) { - if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels())) { - m_vehicle->applyEngineForce(force,wheelIndex); + if ((wheelIndex >= 0) && (wheelIndex < m_vehicle->getNumWheels())) { + m_vehicle->applyEngineForce(force, wheelIndex); } } - virtual void ApplyBraking(float braking,int wheelIndex) + virtual void ApplyBraking(float braking, int wheelIndex) { - if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels())) - { + if ((wheelIndex >= 0) && (wheelIndex < m_vehicle->getNumWheels())) { btWheelInfo& info = m_vehicle->getWheelInfo(wheelIndex); info.m_brake = braking; } } - virtual void SetWheelFriction(float friction,int wheelIndex) + virtual void SetWheelFriction(float friction, int wheelIndex) { - if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels())) - { + if ((wheelIndex >= 0) && (wheelIndex < m_vehicle->getNumWheels())) { btWheelInfo& info = m_vehicle->getWheelInfo(wheelIndex); info.m_frictionSlip = friction; } - } - virtual void SetSuspensionStiffness(float suspensionStiffness,int wheelIndex) + virtual void SetSuspensionStiffness(float suspensionStiffness, int wheelIndex) { - if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels())) - { + if ((wheelIndex >= 0) && (wheelIndex < m_vehicle->getNumWheels())) { btWheelInfo& info = m_vehicle->getWheelInfo(wheelIndex); info.m_suspensionStiffness = suspensionStiffness; - } } - virtual void SetSuspensionDamping(float suspensionDamping,int wheelIndex) + virtual void SetSuspensionDamping(float suspensionDamping, int wheelIndex) { - if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels())) - { + if ((wheelIndex >= 0) && (wheelIndex < m_vehicle->getNumWheels())) { btWheelInfo& info = m_vehicle->getWheelInfo(wheelIndex); info.m_wheelsDampingRelaxation = suspensionDamping; } } - virtual void SetSuspensionCompression(float suspensionCompression,int wheelIndex) + virtual void SetSuspensionCompression(float suspensionCompression, int wheelIndex) { - if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels())) - { + if ((wheelIndex >= 0) && (wheelIndex < m_vehicle->getNumWheels())) { btWheelInfo& info = m_vehicle->getWheelInfo(wheelIndex); info.m_wheelsDampingCompression = suspensionCompression; } } - - - virtual void SetRollInfluence(float rollInfluence,int wheelIndex) + virtual void SetRollInfluence(float rollInfluence, int wheelIndex) { - if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels())) - { + if ((wheelIndex >= 0) && (wheelIndex < m_vehicle->getNumWheels())) { btWheelInfo& info = m_vehicle->getWheelInfo(wheelIndex); info.m_rollInfluence = rollInfluence; } } - virtual void SetCoordinateSystem(int rightIndex,int upIndex,int forwardIndex) + virtual void SetCoordinateSystem(int rightIndex, int upIndex, int forwardIndex) { - m_vehicle->setCoordinateSystem(rightIndex,upIndex,forwardIndex); + m_vehicle->setCoordinateSystem(rightIndex, upIndex, forwardIndex); } - - -}; - -class BlenderVehicleRaycaster: public btDefaultVehicleRaycaster -{ - btDynamicsWorld* m_dynamicsWorld; -public: - BlenderVehicleRaycaster(btDynamicsWorld* world) - :btDefaultVehicleRaycaster(world), m_dynamicsWorld(world) + virtual void SetRayCastMask(short mask) { + m_raycaster->SetRayCastMask(mask); } - - virtual void* castRay(const btVector3& from,const btVector3& to, btVehicleRaycasterResult& result) + virtual short GetRayCastMask() const { - // RayResultCallback& resultCallback; - - btCollisionWorld::ClosestRayResultCallback rayCallback(from,to); - - // We override btDefaultVehicleRaycaster so we can set this flag, otherwise our - // vehicles go crazy (http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=9662) - rayCallback.m_flags |= btTriangleRaycastCallback::kF_UseSubSimplexConvexCastRaytest; - - m_dynamicsWorld->rayTest(from, to, rayCallback); - - if (rayCallback.hasHit()) - { - - const btRigidBody* body = btRigidBody::upcast(rayCallback.m_collisionObject); - if (body && body->hasContactResponse()) - { - result.m_hitPointInWorld = rayCallback.m_hitPointWorld; - result.m_hitNormalInWorld = rayCallback.m_hitNormalWorld; - result.m_hitNormalInWorld.normalize(); - result.m_distFraction = rayCallback.m_closestHitFraction; - return (void*)body; - } - } - return 0; + return m_raycaster->GetRayCastMask(); } }; -#endif //NEW_BULLET_VEHICLE_SUPPORT class CcdOverlapFilterCallBack : public btOverlapFilterCallback { private: - class CcdPhysicsEnvironment* m_physEnv; + class CcdPhysicsEnvironment *m_physEnv; public: - CcdOverlapFilterCallBack(CcdPhysicsEnvironment* env) : + CcdOverlapFilterCallBack(CcdPhysicsEnvironment *env) : m_physEnv(env) { } virtual ~CcdOverlapFilterCallBack() { } - // return true when pairs need collision - virtual bool needBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const; + /// return true when pairs need collision + virtual bool needBroadphaseCollision(btBroadphaseProxy *proxy0, btBroadphaseProxy *proxy1) const; }; - -void CcdPhysicsEnvironment::SetDebugDrawer(btIDebugDraw* debugDrawer) +CcdDebugDraw::CcdDebugDraw() + :m_debugMode(0) { - if (debugDrawer && m_dynamicsWorld) - m_dynamicsWorld->setDebugDrawer(debugDrawer); - m_debugDrawer = debugDrawer; } - -#if 0 -static void DrawAabb(btIDebugDraw* debugDrawer,const btVector3& from,const btVector3& to,const btVector3& color) +void CcdDebugDraw::drawLine(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; - - debugDrawer->drawLine(pa,pb,color); - } - edgecoord = btVector3(-1.f,-1.f,-1.f); - if (i<3) - edgecoord[i]*=-1.f; + if (m_debugMode > 0) { + KX_RasterizerDrawDebugLine(ToMt(from), ToMt(to), mt::vec4(color.x(), color.y(), color.z(), 1.0f)); } } -#endif +void CcdDebugDraw::reportErrorWarning(const char *warningString) +{ +} +void CcdDebugDraw::drawContactPoint(const btVector3& PointOnB, const btVector3& normalOnB, float distance, int lifeTime, const btVector3& color) +{ + drawLine(PointOnB, PointOnB + normalOnB, color); + drawSphere(PointOnB, 0.1f, color); +} +void CcdDebugDraw::setDebugMode(int debugMode) +{ + m_debugMode = debugMode; +} +int CcdDebugDraw::getDebugMode() const +{ + return m_debugMode; +} -CcdPhysicsEnvironment::CcdPhysicsEnvironment(bool useDbvtCulling,btDispatcher* dispatcher,btOverlappingPairCache* pairCache) -:m_cullingCache(NULL), -m_cullingTree(NULL), -m_numIterations(10), -m_numTimeSubSteps(1), -m_ccdMode(0), -m_solverType(-1), -m_profileTimings(0), -m_enableSatCollisionDetection(false), -m_deactivationTime(2.0f), -m_linearDeactivationThreshold(0.8f), -m_angularDeactivationThreshold(1.0f), -m_contactBreakingThreshold(0.02f), -m_solver(NULL), -m_ownPairCache(NULL), -m_filterCallback(NULL), -m_ghostPairCallback(NULL), -m_ownDispatcher(NULL), -m_scalingPropagated(false) +void CcdDebugDraw::draw3dText(const btVector3& location, const char *textString) { +} - for (int i=0;igetMaxNumThreads(); + if (btGetTaskScheduler() != scheduler) { + scheduler->setNumThreads(numThread); + btSetTaskScheduler(scheduler); } -// m_collisionConfiguration = new btDefaultCollisionConfiguration(); - m_collisionConfiguration = new btSoftBodyRigidBodyCollisionConfiguration(); - //m_collisionConfiguration->setConvexConvexMultipointIterations(); - - if (!dispatcher) - { - btCollisionDispatcher* disp = new btCollisionDispatcher(m_collisionConfiguration); - dispatcher = disp; - btGImpactCollisionAlgorithm::registerAlgorithm(disp); - m_ownDispatcher = dispatcher; + for (int i = 0; i < PHY_NUM_RESPONSE; i++) { + m_triggerCallbacks[i] = nullptr; } - //m_broadphase = new btAxisSweep3(btVector3(-1000,-1000,-1000),btVector3(1000,1000,1000)); - //m_broadphase = new btSimpleBroadphase(); - m_broadphase = new btDbvtBroadphase(); + btGImpactCollisionAlgorithm::registerAlgorithm(m_dispatcher.get()); + // avoid any collision in the culling tree if (useDbvtCulling) { - m_cullingCache = new btNullPairCache(); - m_cullingTree = new btDbvtBroadphase(m_cullingCache); + m_cullingCache.reset(new btNullPairCache()); + m_cullingTree.reset(new btDbvtBroadphase(m_cullingCache.get())); } - m_filterCallback = new CcdOverlapFilterCallBack(this); - m_ghostPairCallback = new btGhostPairCallback(); - m_broadphase->getOverlappingPairCache()->setOverlapFilterCallback(m_filterCallback); - m_broadphase->getOverlappingPairCache()->setInternalGhostPairCallback(m_ghostPairCallback); + m_broadphase->getOverlappingPairCache()->setOverlapFilterCallback(m_filterCallback.get()); + m_broadphase->getOverlappingPairCache()->setInternalGhostPairCallback(m_ghostPairCallback.get()); - SetSolverType(1);//issues with quickstep and memory allocations -// m_dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,m_broadphase,m_solver,m_collisionConfiguration); - m_dynamicsWorld = new btSoftRigidDynamicsWorld(dispatcher,m_broadphase,m_solver,m_collisionConfiguration); + m_solvers.resize(numThread); + SetSolverType(solverType); + + m_solverPool.reset(new btConstraintSolverPoolMt(m_solvers.data(), numThread)); + m_dynamicsWorld.reset(new btSoftRigidDynamicsWorldMt(m_dispatcher.get(), m_broadphase.get(), m_solverPool.get(), m_collisionConfiguration.get())); m_dynamicsWorld->setInternalTickCallback(&CcdPhysicsEnvironment::StaticSimulationSubtickCallback, this); - //m_dynamicsWorld->getSolverInfo().m_linearSlop = 0.01f; - //m_dynamicsWorld->getSolverInfo().m_solverMode= SOLVER_USE_WARMSTARTING + SOLVER_USE_2_FRICTION_DIRECTIONS + SOLVER_RANDMIZE_ORDER + SOLVER_USE_FRICTION_WARMSTARTING; - m_debugDrawer = 0; - SetGravity(0.f,0.f,-9.81f); + m_dynamicsWorld->setDebugDrawer(&m_debugDrawer); + + SetGravity(0.0f, 0.0f, -9.81f); } -void CcdPhysicsEnvironment::AddCcdPhysicsController(CcdPhysicsController* ctrl) +void CcdPhysicsEnvironment::AddCcdPhysicsController(CcdPhysicsController *ctrl) { // the controller is already added we do nothing if (!m_controllers.insert(ctrl).second) { return; } - btRigidBody* body = ctrl->GetRigidBody(); - btCollisionObject* obj = ctrl->GetCollisionObject(); + btRigidBody *body = ctrl->GetRigidBody(); + btCollisionObject *obj = ctrl->GetCollisionObject(); //this m_userPointer is just used for triggers, see CallbackTriggers obj->setUserPointer(ctrl); if (body) { body->setGravity(m_gravity); body->setSleepingThresholds(m_linearDeactivationThreshold, m_angularDeactivationThreshold); - } - - if (body) - { //use explicit group/filter for finer control over collision in bullet => near/radar sensor m_dynamicsWorld->addRigidBody(body, ctrl->GetCollisionFilterGroup(), ctrl->GetCollisionFilterMask()); - } else - { - if (ctrl->GetSoftBody()) - { - btSoftBody* softBody = ctrl->GetSoftBody(); + + // Restore constraints in case of physics restore. + for (unsigned short i = 0, size = ctrl->getNumCcdConstraintRefs(); i < size; ++i) { + btTypedConstraint *con = ctrl->getCcdConstraintRef(i); + RestoreConstraint(ctrl, con); + } + + // Handle potential vehicle constraints + for (WrapperVehicle *wrapperVehicle : m_wrapperVehicles) { + if (wrapperVehicle->GetChassis() == ctrl) { + btRaycastVehicle *vehicle = wrapperVehicle->GetVehicle(); + m_dynamicsWorld->addVehicle(vehicle); + } + } + } + else { + if (ctrl->GetSoftBody()) { + btSoftBody *softBody = ctrl->GetSoftBody(); m_dynamicsWorld->addSoftBody(softBody); - } else - { - if (obj->getCollisionShape()) - { + } + else { + if (obj->getCollisionShape()) { m_dynamicsWorld->addCollisionObject(obj, ctrl->GetCollisionFilterGroup(), ctrl->GetCollisionFilterMask()); } - if (ctrl->GetCharacterController()) - { + if (ctrl->GetCharacterController()) { m_dynamicsWorld->addAction(ctrl->GetCharacterController()); } } } - if (obj->isStaticOrKinematicObject()) - { + if (obj->isStaticOrKinematicObject()) { obj->setActivationState(ISLAND_SLEEPING); } - assert(obj->getBroadphaseHandle()); + BLI_assert(obj->getBroadphaseHandle()); } -void CcdPhysicsEnvironment::RemoveConstraint(btTypedConstraint *con) +void CcdPhysicsEnvironment::RemoveConstraint(btTypedConstraint *con, bool free) { + CcdConstraint *userData = (CcdConstraint *)con->getUserConstraintPtr(); + if (!userData->GetActive()) { + return; + } + btRigidBody &rbA = con->getRigidBodyA(); btRigidBody &rbB = con->getRigidBodyB(); rbA.activate(); rbB.activate(); + + userData->SetActive(false); m_dynamicsWorld->removeConstraint(con); - if (rbA.getUserPointer()) { - ((CcdPhysicsController *)rbA.getUserPointer())->removeCcdConstraintRef(con); + if (free) { + if (rbA.getUserPointer()) { + ((CcdPhysicsController *)rbA.getUserPointer())->removeCcdConstraintRef(con); + } + + if (rbB.getUserPointer()) { + ((CcdPhysicsController *)rbB.getUserPointer())->removeCcdConstraintRef(con); + } + + /* Since we remove the constraint in the onwer and the target, we can delete it, + * KX_ConstraintWrapper keep the constraint id not the pointer, so no problems. */ + delete userData; + delete con; } +} + +void CcdPhysicsEnvironment::RemoveVehicle(WrapperVehicle *vehicle, bool free) +{ + m_dynamicsWorld->removeVehicle(vehicle->GetVehicle()); + if (free) { + CM_ListRemoveIfFound(m_wrapperVehicles, vehicle); + delete vehicle; + } +} + +void CcdPhysicsEnvironment::RemoveVehicle(CcdPhysicsController *ctrl, bool free) +{ + for (std::vector::iterator it = m_wrapperVehicles.begin(); it != m_wrapperVehicles.end(); ) { + WrapperVehicle *vehicle = *it; + if (vehicle->GetChassis() == ctrl) { + m_dynamicsWorld->removeVehicle(vehicle->GetVehicle()); + if (free) { + it = m_wrapperVehicles.erase(it); + delete vehicle; + continue; + } + } + ++it; + } +} + +void CcdPhysicsEnvironment::RestoreConstraint(CcdPhysicsController *ctrl, btTypedConstraint *con) +{ + CcdConstraint *userData = (CcdConstraint *)con->getUserConstraintPtr(); + if (userData->GetActive()) { + return; + } + + btRigidBody &rbA = con->getRigidBodyA(); + btRigidBody &rbB = con->getRigidBodyB(); - if (rbB.getUserPointer()) { - ((CcdPhysicsController *)rbB.getUserPointer())->removeCcdConstraintRef(con); + CcdPhysicsController *other = nullptr; + + if (rbA.getUserPointer() && rbB.getUserPointer()) { + CcdPhysicsController *ctrl0 = (CcdPhysicsController *)rbA.getUserPointer(); + CcdPhysicsController *ctrl1 = (CcdPhysicsController *)rbB.getUserPointer(); + other = (ctrl0 != ctrl) ? ctrl0 : ctrl1; } - /* Since we remove the constraint in the onwer and the target, we can delete it, - * KX_ConstraintWrapper keep the constraint id not the pointer, so no problems. */ - delete con; + BLI_assert(other != nullptr); + + // Avoid add constraint if one of the objects are not available. + if (IsActiveCcdPhysicsController(other)) { + userData->SetActive(true); + m_dynamicsWorld->addConstraint(con, userData->GetDisableCollision()); + } } -bool CcdPhysicsEnvironment::RemoveCcdPhysicsController(CcdPhysicsController* ctrl) +bool CcdPhysicsEnvironment::RemoveCcdPhysicsController(CcdPhysicsController *ctrl, bool freeConstraints) { // if the physics controller is already removed we do nothing if (!m_controllers.erase(ctrl)) { @@ -540,9 +613,8 @@ bool CcdPhysicsEnvironment::RemoveCcdPhysicsController(CcdPhysicsController* ctr } //also remove constraint - btRigidBody* body = ctrl->GetRigidBody(); - if (body) - { + btRigidBody *body = ctrl->GetRigidBody(); + if (body) { btBroadphaseProxy *proxy = ctrl->GetCollisionObject()->getBroadphaseHandle(); btDispatcher *dispatcher = m_dynamicsWorld->getDispatcher(); btOverlappingPairCache *pairCache = m_dynamicsWorld->getPairCache(); @@ -550,37 +622,24 @@ bool CcdPhysicsEnvironment::RemoveCcdPhysicsController(CcdPhysicsController* ctr CleanPairCallback cleanPairs(proxy, pairCache, dispatcher); pairCache->processAllOverlappingPairs(&cleanPairs, dispatcher); - for (int i = ctrl->getNumCcdConstraintRefs() - 1; i >= 0; i--) - { - btTypedConstraint* con = ctrl->getCcdConstraintRef(i); - RemoveConstraint(con); + for (int i = ctrl->getNumCcdConstraintRefs() - 1; i >= 0; i--) { + btTypedConstraint *con = ctrl->getCcdConstraintRef(i); + RemoveConstraint(con, freeConstraints); } m_dynamicsWorld->removeRigidBody(ctrl->GetRigidBody()); // Handle potential vehicle constraints - int numVehicles = m_wrapperVehicles.size(); - int vehicle_constraint = 0; - for (int i=0;iGetChassis() == ctrl) - vehicle_constraint = wrapperVehicle->GetVehicle()->getUserConstraintId(); - } - - if (vehicle_constraint > 0) - RemoveConstraintById(vehicle_constraint); - } else - { + RemoveVehicle(ctrl, freeConstraints); + } + else { //if a softbody - if (ctrl->GetSoftBody()) - { + if (ctrl->GetSoftBody()) { m_dynamicsWorld->removeSoftBody(ctrl->GetSoftBody()); - } else - { + } + else { m_dynamicsWorld->removeCollisionObject(ctrl->GetCollisionObject()); - if (ctrl->GetCharacterController()) - { + if (ctrl->GetCharacterController()) { m_dynamicsWorld->removeAction(ctrl->GetCharacterController()); } } @@ -589,23 +648,22 @@ bool CcdPhysicsEnvironment::RemoveCcdPhysicsController(CcdPhysicsController* ctr return true; } -void CcdPhysicsEnvironment::UpdateCcdPhysicsController(CcdPhysicsController* ctrl, btScalar newMass, int newCollisionFlags, short int newCollisionGroup, short int newCollisionMask) +void CcdPhysicsEnvironment::UpdateCcdPhysicsController(CcdPhysicsController *ctrl, btScalar newMass, int newCollisionFlags, short int newCollisionGroup, short int newCollisionMask) { // this function is used when the collisionning group of a controller is changed // remove and add the collistioning object - btRigidBody* body = ctrl->GetRigidBody(); + btRigidBody *body = ctrl->GetRigidBody(); btSoftBody *softBody = ctrl->GetSoftBody(); - btCollisionObject* obj = ctrl->GetCollisionObject(); - if (obj) - { - btVector3 inertia(0.0f,0.0f,0.0f); + btCollisionObject *obj = ctrl->GetCollisionObject(); + if (obj) { + btVector3 inertia(0.0, 0.0, 0.0); m_dynamicsWorld->removeCollisionObject(obj); obj->setCollisionFlags(newCollisionFlags); - if (body) - { - if (newMass) + if (body) { + if (newMass) { body->getCollisionShape()->calculateLocalInertia(newMass, inertia); - body->setMassProps(newMass, inertia); + } + body->setMassProps(newMass, inertia * ctrl->GetInertiaFactor()); m_dynamicsWorld->addRigidBody(body, newCollisionGroup, newCollisionMask); } else if (softBody) { @@ -622,15 +680,13 @@ void CcdPhysicsEnvironment::UpdateCcdPhysicsController(CcdPhysicsController* ctr ctrl->m_cci.m_collisionFlags = newCollisionFlags; } -void CcdPhysicsEnvironment::RefreshCcdPhysicsController(CcdPhysicsController* ctrl) +void CcdPhysicsEnvironment::RefreshCcdPhysicsController(CcdPhysicsController *ctrl) { - btCollisionObject* obj = ctrl->GetCollisionObject(); - if (obj) - { - btBroadphaseProxy* proxy = obj->getBroadphaseHandle(); - if (proxy) - { - m_dynamicsWorld->getPairCache()->cleanProxyFromPairs(proxy,m_dynamicsWorld->getDispatcher()); + btCollisionObject *obj = ctrl->GetCollisionObject(); + if (obj) { + btBroadphaseProxy *proxy = obj->getBroadphaseHandle(); + if (proxy) { + m_dynamicsWorld->getPairCache()->cleanProxyFromPairs(proxy, m_dynamicsWorld->getDispatcher()); } } } @@ -640,119 +696,100 @@ bool CcdPhysicsEnvironment::IsActiveCcdPhysicsController(CcdPhysicsController *c return (m_controllers.find(ctrl) != m_controllers.end()); } -void CcdPhysicsEnvironment::AddCcdGraphicController(CcdGraphicController* ctrl) +void CcdPhysicsEnvironment::AddCcdGraphicController(CcdGraphicController *ctrl) { - if (m_cullingTree && !ctrl->GetBroadphaseHandle()) - { - btVector3 minAabb; - btVector3 maxAabb; + if (m_cullingTree && !ctrl->GetBroadphaseHandle()) { + btVector3 minAabb; + btVector3 maxAabb; ctrl->GetAabb(minAabb, maxAabb); ctrl->SetBroadphaseHandle(m_cullingTree->createProxy( - minAabb, - maxAabb, - INVALID_SHAPE_PROXYTYPE, // this parameter is not used - ctrl, - 0, // this object does not collision with anything - 0, - NULL, // dispatcher => this parameter is not used - 0)); + minAabb, + maxAabb, + INVALID_SHAPE_PROXYTYPE, // this parameter is not used + ctrl, + 0, // this object does not collision with anything + 0, + nullptr // dispatcher => this parameter is not used + )); - assert(ctrl->GetBroadphaseHandle()); + BLI_assert(ctrl->GetBroadphaseHandle()); } } -void CcdPhysicsEnvironment::RemoveCcdGraphicController(CcdGraphicController* ctrl) +void CcdPhysicsEnvironment::RemoveCcdGraphicController(CcdGraphicController *ctrl) { - if (m_cullingTree) - { - btBroadphaseProxy* bp = ctrl->GetBroadphaseHandle(); - if (bp) - { - m_cullingTree->destroyProxy(bp,NULL); - ctrl->SetBroadphaseHandle(0); + if (m_cullingTree) { + btBroadphaseProxy *bp = ctrl->GetBroadphaseHandle(); + if (bp) { + m_cullingTree->destroyProxy(bp, nullptr); + ctrl->SetBroadphaseHandle(nullptr); } } } void CcdPhysicsEnvironment::UpdateCcdPhysicsControllerShape(CcdShapeConstructionInfo *shapeInfo) { - for (std::set::iterator it = m_controllers.begin(); it != m_controllers.end(); ++it) { - CcdPhysicsController *ctrl = *it; - - if (ctrl->GetShapeInfo() != shapeInfo) + for (CcdPhysicsController *ctrl : m_controllers) { + if (ctrl->GetShapeInfo() != shapeInfo) { continue; + } - ctrl->ReplaceControllerShape(NULL); + ctrl->ReplaceControllerShape(nullptr); RefreshCcdPhysicsController(ctrl); } } -void CcdPhysicsEnvironment::BeginFrame() -{ - -} - void CcdPhysicsEnvironment::DebugDrawWorld() { - if (m_dynamicsWorld->getDebugDrawer() && m_dynamicsWorld->getDebugDrawer()->getDebugMode() >0) - m_dynamicsWorld->debugDrawWorld(); + m_dynamicsWorld->debugDrawWorld(); } void CcdPhysicsEnvironment::StaticSimulationSubtickCallback(btDynamicsWorld *world, btScalar timeStep) { // Get the pointer to the CcdPhysicsEnvironment associated with this Bullet world. - CcdPhysicsEnvironment *this_ = static_cast(world->getWorldUserInfo()); + CcdPhysicsEnvironment *this_ = static_cast(world->getWorldUserInfo()); this_->SimulationSubtickCallback(timeStep); } void CcdPhysicsEnvironment::SimulationSubtickCallback(btScalar timeStep) { - std::set::iterator it; + std::set::iterator it; for (it = m_controllers.begin(); it != m_controllers.end(); it++) { (*it)->SimulationTick(timeStep); } } -bool CcdPhysicsEnvironment::ProceedDeltaTime(double curTime,float timeStep,float interval) +bool CcdPhysicsEnvironment::ProceedDeltaTime(double curTime, float timeStep, float interval) { - std::set::iterator it; + std::set::iterator it; int i; // Update Bullet global variables. gDeactivationTime = m_deactivationTime; gContactBreakingThreshold = m_contactBreakingThreshold; - for (it=m_controllers.begin(); it!=m_controllers.end(); it++) - { + for (it = m_controllers.begin(); it != m_controllers.end(); it++) { (*it)->SynchronizeMotionStates(timeStep); } float subStep = timeStep / float(m_numTimeSubSteps); - i = m_dynamicsWorld->stepSimulation(interval,25,subStep);//perform always a full simulation step + i = m_dynamicsWorld->stepSimulation(interval, 25, subStep);//perform always a full simulation step //uncomment next line to see where Bullet spend its time (printf in console) //CProfileManager::dumpAll(); - ProcessFhSprings(curTime,i*subStep); + ProcessFhSprings(curTime, i * subStep); - for (it=m_controllers.begin(); it!=m_controllers.end(); it++) - { + for (it = m_controllers.begin(); it != m_controllers.end(); it++) { (*it)->SynchronizeMotionStates(timeStep); } - //for (it=m_controllers.begin(); it!=m_controllers.end(); it++) - //{ - // (*it)->SynchronizeMotionStates(timeStep); - //} - - for (i=0;iSyncWheels(); } - CallbackTriggers(); return true; @@ -760,161 +797,149 @@ bool CcdPhysicsEnvironment::ProceedDeltaTime(double curTime,float timeStep,float class ClosestRayResultCallbackNotMe : public btCollisionWorld::ClosestRayResultCallback { - btCollisionObject* m_owner; - btCollisionObject* m_parent; + btCollisionObject *m_owner; + btCollisionObject *m_parent; public: - ClosestRayResultCallbackNotMe(const btVector3& rayFromWorld,const btVector3& rayToWorld,btCollisionObject* owner,btCollisionObject* parent) - :btCollisionWorld::ClosestRayResultCallback(rayFromWorld,rayToWorld), + ClosestRayResultCallbackNotMe(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionObject *owner, btCollisionObject *parent) + :btCollisionWorld::ClosestRayResultCallback(rayFromWorld, rayToWorld), m_owner(owner), m_parent(parent) { - } - virtual bool needsCollision(btBroadphaseProxy* proxy0) const + virtual bool needsCollision(btBroadphaseProxy *proxy0) const { //don't collide with self - if (proxy0->m_clientObject == m_owner) + if (proxy0->m_clientObject == m_owner) { return false; + } - if (proxy0->m_clientObject == m_parent) + if (proxy0->m_clientObject == m_parent) { return false; + } return btCollisionWorld::ClosestRayResultCallback::needsCollision(proxy0); } - }; -void CcdPhysicsEnvironment::ProcessFhSprings(double curTime,float interval) +void CcdPhysicsEnvironment::ProcessFhSprings(double curTime, float interval) { - std::set::iterator it; - // Add epsilon to the tick rate for numerical stability - int numIter = (int)(interval*(KX_KetsjiEngine::GetTicRate() + 0.001f)); + std::set::iterator it; - for (it=m_controllers.begin(); it!=m_controllers.end(); it++) - { - CcdPhysicsController* ctrl = (*it); - btRigidBody* body = ctrl->GetRigidBody(); + const float step = interval * KX_GetActiveEngine()->GetTicRate(); - if (body && (ctrl->GetConstructionInfo().m_do_fh || ctrl->GetConstructionInfo().m_do_rot_fh)) - { - //printf("has Fh or RotFh\n"); + for (it = m_controllers.begin(); it != m_controllers.end(); it++) { + CcdPhysicsController *ctrl = (*it); + btRigidBody *body = ctrl->GetRigidBody(); + + if (body && (ctrl->GetConstructionInfo().m_do_fh || ctrl->GetConstructionInfo().m_do_rot_fh)) { //re-implement SM_FhObject.cpp using btCollisionWorld::rayTest and info from ctrl->getConstructionInfo() //send a ray from {0.0, 0.0, 0.0} towards {0.0, 0.0, -10.0}, in local coordinates - CcdPhysicsController* parentCtrl = ctrl->GetParentCtrl(); - btRigidBody* parentBody = parentCtrl?parentCtrl->GetRigidBody() : 0; - btRigidBody* cl_object = parentBody ? parentBody : body; + CcdPhysicsController *parentCtrl = ctrl->GetParentRoot(); + btRigidBody *parentBody = parentCtrl ? parentCtrl->GetRigidBody() : nullptr; + btRigidBody *cl_object = parentBody ? parentBody : body; - if (body->isStaticOrKinematicObject()) + if (body->isStaticOrKinematicObject()) { continue; + } - btVector3 rayDirLocal(0,0,-10); + btVector3 rayDirLocal(0.0f, 0.0f, -10.0f); //m_dynamicsWorld //ctrl->GetRigidBody(); btVector3 rayFromWorld = body->getCenterOfMassPosition(); //btVector3 rayToWorld = rayFromWorld + body->getCenterOfMassTransform().getBasis() * rayDirLocal; //ray always points down the z axis in world space... - btVector3 rayToWorld = rayFromWorld + rayDirLocal; + btVector3 rayToWorld = rayFromWorld + rayDirLocal; - ClosestRayResultCallbackNotMe resultCallback(rayFromWorld,rayToWorld,body,parentBody); + ClosestRayResultCallbackNotMe resultCallback(rayFromWorld, rayToWorld, body, parentBody); - m_dynamicsWorld->rayTest(rayFromWorld,rayToWorld,resultCallback); - if (resultCallback.hasHit()) - { + m_dynamicsWorld->rayTest(rayFromWorld, rayToWorld, resultCallback); + if (resultCallback.hasHit()) { //we hit this one: resultCallback.m_collisionObject; - CcdPhysicsController* controller = static_cast(resultCallback.m_collisionObject->getUserPointer()); + CcdPhysicsController *controller = static_cast(resultCallback.m_collisionObject->getUserPointer()); - if (controller) - { - if (controller->GetConstructionInfo().m_fh_distance < SIMD_EPSILON) + if (controller) { + if (controller->GetConstructionInfo().m_fh_distance < SIMD_EPSILON) { continue; + } - btRigidBody* hit_object = controller->GetRigidBody(); - if (!hit_object) + btRigidBody *hit_object = controller->GetRigidBody(); + if (!hit_object) { continue; + } CcdConstructionInfo& hitObjShapeProps = controller->GetConstructionInfo(); - float distance = resultCallback.m_closestHitFraction*rayDirLocal.length()-ctrl->GetConstructionInfo().m_radius; - if (distance >= hitObjShapeProps.m_fh_distance) + float distance = resultCallback.m_closestHitFraction * rayDirLocal.length() - ctrl->GetConstructionInfo().m_radius; + if (distance >= hitObjShapeProps.m_fh_distance) { continue; + } - - - //btVector3 ray_dir = cl_object->getCenterOfMassTransform().getBasis()* rayDirLocal.normalized(); + //btVector3 ray_dir = cl_object->getCenterOfMassTransform().getBasis()* rayDirLocal.Normalized(); btVector3 ray_dir = rayDirLocal.normalized(); btVector3 normal = resultCallback.m_hitNormalWorld; normal.normalize(); - for (int i=0; iGetConstructionInfo().m_do_fh) - { - btVector3 lspot = cl_object->getCenterOfMassPosition() + - rayDirLocal * resultCallback.m_closestHitFraction; - - - + if (ctrl->GetConstructionInfo().m_do_fh) { + btVector3 lspot = cl_object->getCenterOfMassPosition() + + rayDirLocal * resultCallback.m_closestHitFraction; - lspot -= hit_object->getCenterOfMassPosition(); - btVector3 rel_vel = cl_object->getLinearVelocity() - hit_object->getVelocityInLocalPoint(lspot); - btScalar rel_vel_ray = ray_dir.dot(rel_vel); - btScalar spring_extent = 1.0f - distance / hitObjShapeProps.m_fh_distance; + lspot -= hit_object->getCenterOfMassPosition(); + btVector3 rel_vel = cl_object->getLinearVelocity() - hit_object->getVelocityInLocalPoint(lspot); + btScalar rel_vel_ray = ray_dir.dot(rel_vel); + btScalar spring_extent = 1.0f - distance / hitObjShapeProps.m_fh_distance; - btScalar i_spring = spring_extent * hitObjShapeProps.m_fh_spring; - btScalar i_damp = rel_vel_ray * hitObjShapeProps.m_fh_damping; + btScalar i_spring = spring_extent * hitObjShapeProps.m_fh_spring; + btScalar i_damp = rel_vel_ray * hitObjShapeProps.m_fh_damping; - cl_object->setLinearVelocity(cl_object->getLinearVelocity() + (-(i_spring + i_damp) * ray_dir)); - if (hitObjShapeProps.m_fh_normal) - { - cl_object->setLinearVelocity(cl_object->getLinearVelocity()+(i_spring + i_damp) *(normal - normal.dot(ray_dir) * ray_dir)); - } - - btVector3 lateral = rel_vel - rel_vel_ray * ray_dir; + cl_object->setLinearVelocity(cl_object->getLinearVelocity() + (-(i_spring + i_damp) * ray_dir) * step); + if (hitObjShapeProps.m_fh_normal) { + cl_object->setLinearVelocity(cl_object->getLinearVelocity() + (i_spring + i_damp) * (normal - normal.dot(ray_dir) * ray_dir) * step); + } + btVector3 lateral = rel_vel - rel_vel_ray * ray_dir; - if (ctrl->GetConstructionInfo().m_do_anisotropic) { - //Bullet basis contains no scaling/shear etc. - const btMatrix3x3& lcs = cl_object->getCenterOfMassTransform().getBasis(); - btVector3 loc_lateral = lateral * lcs; - const btVector3& friction_scaling = cl_object->getAnisotropicFriction(); - loc_lateral *= friction_scaling; - lateral = lcs * loc_lateral; - } + if (ctrl->GetConstructionInfo().m_do_anisotropic) { + //Bullet basis contains no scaling/shear etc. + const btMatrix3x3& lcs = cl_object->getCenterOfMassTransform().getBasis(); + btVector3 loc_lateral = lateral * lcs; + const btVector3& friction_scaling = cl_object->getAnisotropicFriction(); + loc_lateral *= friction_scaling; + lateral = lcs * loc_lateral; + } - btScalar rel_vel_lateral = lateral.length(); + btScalar rel_vel_lateral = lateral.length(); - if (rel_vel_lateral > SIMD_EPSILON) { - btScalar friction_factor = hit_object->getFriction();//cl_object->getFriction(); + if (rel_vel_lateral > SIMD_EPSILON) { + btScalar friction_factor = hit_object->getFriction();//cl_object->getFriction(); - btScalar max_friction = friction_factor * btMax(btScalar(0.0f), i_spring); + btScalar max_friction = friction_factor * btMax(btScalar(0.0), i_spring); - btScalar rel_mom_lateral = rel_vel_lateral / cl_object->getInvMass(); + btScalar rel_mom_lateral = rel_vel_lateral / cl_object->getInvMass(); - btVector3 friction = (rel_mom_lateral > max_friction) ? - -lateral * (max_friction / rel_vel_lateral) : - -lateral; + btVector3 friction = (rel_mom_lateral > max_friction) ? + -lateral * (max_friction / rel_vel_lateral) : + -lateral; - cl_object->applyCentralImpulse(friction); - } + cl_object->applyCentralImpulse(friction * step); } + } - if (ctrl->GetConstructionInfo().m_do_rot_fh) { - btVector3 up2 = cl_object->getWorldTransform().getBasis().getColumn(2); + if (ctrl->GetConstructionInfo().m_do_rot_fh) { + btVector3 up2 = cl_object->getWorldTransform().getBasis().getColumn(2); - btVector3 t_spring = up2.cross(normal) * hitObjShapeProps.m_fh_spring; - btVector3 ang_vel = cl_object->getAngularVelocity(); + btVector3 t_spring = up2.cross(normal) * hitObjShapeProps.m_fh_spring; + btVector3 ang_vel = cl_object->getAngularVelocity(); - // only rotations that tilt relative to the normal are damped - ang_vel -= ang_vel.dot(normal) * normal; + // only rotations that tilt relative to the normal are damped + ang_vel -= ang_vel.dot(normal) * normal; - btVector3 t_damp = ang_vel * hitObjShapeProps.m_fh_damping; + btVector3 t_damp = ang_vel * hitObjShapeProps.m_fh_damping; - cl_object->setAngularVelocity(cl_object->getAngularVelocity() + (t_spring - t_damp)); - } + cl_object->setAngularVelocity(cl_object->getAngularVelocity() + (t_spring - t_damp) * step); } } } @@ -922,237 +947,165 @@ void CcdPhysicsEnvironment::ProcessFhSprings(double curTime,float interval) } } -int CcdPhysicsEnvironment::GetDebugMode() const +int CcdPhysicsEnvironment::GetDebugMode() const { - if (m_debugDrawer) { - return m_debugDrawer->getDebugMode(); - } - return 0; + return m_debugDrawer.getDebugMode(); } -void CcdPhysicsEnvironment::SetDebugMode(int debugMode) +void CcdPhysicsEnvironment::SetDebugMode(int debugMode) { - if (m_debugDrawer) { - m_debugDrawer->setDebugMode(debugMode); - } + m_debugDrawer.setDebugMode(debugMode); } -void CcdPhysicsEnvironment::SetNumIterations(int numIter) +void CcdPhysicsEnvironment::SetNumIterations(int numIter) { m_numIterations = numIter; } -void CcdPhysicsEnvironment::SetDeactivationTime(float dTime) +void CcdPhysicsEnvironment::SetDeactivationTime(float dTime) { m_deactivationTime = dTime; } -void CcdPhysicsEnvironment::SetDeactivationLinearTreshold(float linTresh) +void CcdPhysicsEnvironment::SetDeactivationLinearTreshold(float linTresh) { m_linearDeactivationThreshold = linTresh; // Update from all controllers. - for (std::set::iterator it = m_controllers.begin(); it != m_controllers.end(); it++) { - if ((*it)->GetRigidBody()) - (*it)->GetRigidBody()->setSleepingThresholds(m_linearDeactivationThreshold, m_angularDeactivationThreshold); + for (CcdPhysicsController *ctrl : m_controllers) { + if (ctrl->GetRigidBody()) { + ctrl->GetRigidBody()->setSleepingThresholds(m_linearDeactivationThreshold, m_angularDeactivationThreshold); + } } } -void CcdPhysicsEnvironment::SetDeactivationAngularTreshold(float angTresh) +void CcdPhysicsEnvironment::SetDeactivationAngularTreshold(float angTresh) { m_angularDeactivationThreshold = angTresh; // Update from all controllers. - for (std::set::iterator it = m_controllers.begin(); it != m_controllers.end(); it++) { - if ((*it)->GetRigidBody()) + for (std::set::iterator it = m_controllers.begin(); it != m_controllers.end(); it++) { + if ((*it)->GetRigidBody()) { (*it)->GetRigidBody()->setSleepingThresholds(m_linearDeactivationThreshold, m_angularDeactivationThreshold); + } } } -void CcdPhysicsEnvironment::SetContactBreakingTreshold(float contactBreakingTreshold) +void CcdPhysicsEnvironment::SetContactBreakingTreshold(float contactBreakingTreshold) { m_contactBreakingThreshold = contactBreakingTreshold; } - -void CcdPhysicsEnvironment::SetCcdMode(int ccdMode) +void CcdPhysicsEnvironment::SetCcdMode(int ccdMode) { m_ccdMode = ccdMode; } - -void CcdPhysicsEnvironment::SetSolverSorConstant(float sor) +void CcdPhysicsEnvironment::SetSolverSorConstant(float sor) { m_dynamicsWorld->getSolverInfo().m_sor = sor; } -void CcdPhysicsEnvironment::SetSolverTau(float tau) +void CcdPhysicsEnvironment::SetSolverTau(float tau) { m_dynamicsWorld->getSolverInfo().m_tau = tau; } -void CcdPhysicsEnvironment::SetSolverDamping(float damping) +void CcdPhysicsEnvironment::SetSolverDamping(float damping) { m_dynamicsWorld->getSolverInfo().m_damping = damping; } - -void CcdPhysicsEnvironment::SetLinearAirDamping(float damping) +void CcdPhysicsEnvironment::SetLinearAirDamping(float damping) { //gLinearAirDamping = damping; } -void CcdPhysicsEnvironment::SetUseEpa(bool epa) +void CcdPhysicsEnvironment::SetUseEpa(bool epa) { //gUseEpa = epa; } -void CcdPhysicsEnvironment::SetSolverType(int solverType) +void CcdPhysicsEnvironment::SetSolverType(PHY_SolverType solverType) { + if (m_solverType == solverType) { + return; + } - switch (solverType) - { - case 1: - { - if (m_solverType != solverType) + for (unsigned short i = 0, size = m_solvers.size(); i < size; ++i) { + switch (solverType) { + case PHY_SOLVER_SEQUENTIAL: { - - m_solver = new btSequentialImpulseConstraintSolver(); - - + m_solvers[i] = new btSequentialImpulseConstraintSolver(); break; } + case PHY_SOLVER_NNCG: + { + m_solvers[i] = new btNNCGConstraintSolver(); + break; + } + case PHY_SOLVER_MLCP_DANTZIG: + { + m_solvers[i] = new btMLCPSolver(new btDantzigSolver()); + break; + } + case PHY_SOLVER_MLCP_LEMKE: + { + m_solvers[i] = new btMLCPSolver(new btLemkeSolver()); + break; + } + default: + { + BLI_assert(false); + } } - - case 0: - default: - if (m_solverType != solverType) - { -// m_solver = new OdeConstraintSolver(); - - break; - } - - }; + } m_solverType = solverType; } - - -void CcdPhysicsEnvironment::GetGravity(MT_Vector3& grav) +mt::vec3 CcdPhysicsEnvironment::GetGravity() const { - const btVector3& gravity = m_dynamicsWorld->getGravity(); - grav[0] = gravity.getX(); - grav[1] = gravity.getY(); - grav[2] = gravity.getZ(); + return ToMt(m_dynamicsWorld->getGravity()); } - -void CcdPhysicsEnvironment::SetGravity(float x,float y,float z) +void CcdPhysicsEnvironment::SetGravity(float x, float y, float z) { - m_gravity = btVector3(x,y,z); + m_gravity = btVector3(x, y, z); m_dynamicsWorld->setGravity(m_gravity); - m_dynamicsWorld->getWorldInfo().m_gravity.setValue(x,y,z); + m_dynamicsWorld->getWorldInfo().m_gravity.setValue(x, y, z); } - - - static int gConstraintUid = 1; -//Following the COLLADA physics specification for constraints -int CcdPhysicsEnvironment::CreateUniversalD6Constraint( - class PHY_IPhysicsController* ctrlRef,class PHY_IPhysicsController* ctrlOther, - btTransform& frameInA, - btTransform& frameInB, - const btVector3& linearMinLimits, - const btVector3& linearMaxLimits, - const btVector3& angularMinLimits, - const btVector3& angularMaxLimits,int flags -) -{ - - bool disableCollisionBetweenLinkedBodies = (0!=(flags & CCD_CONSTRAINT_DISABLE_LINKED_COLLISION)); - - //we could either add some logic to recognize ball-socket and hinge, or let that up to the user - //perhaps some warning or hint that hinge/ball-socket is more efficient? - - - btGeneric6DofConstraint* genericConstraint = 0; - CcdPhysicsController* ctrl0 = (CcdPhysicsController*) ctrlRef; - CcdPhysicsController* ctrl1 = (CcdPhysicsController*) ctrlOther; - - btRigidBody* rb0 = ctrl0->GetRigidBody(); - btRigidBody* rb1 = ctrl1->GetRigidBody(); - - if (rb1) - { - - - bool useReferenceFrameA = true; - genericConstraint = new btGeneric6DofSpringConstraint( - *rb0,*rb1, - frameInA,frameInB,useReferenceFrameA); - genericConstraint->setLinearLowerLimit(linearMinLimits); - genericConstraint->setLinearUpperLimit(linearMaxLimits); - genericConstraint->setAngularLowerLimit(angularMinLimits); - genericConstraint->setAngularUpperLimit(angularMaxLimits); - } else - { - // TODO: Implement single body case... - //No, we can use a fixed rigidbody in above code, rather than unnecessary duplation of code - - } - - if (genericConstraint) - { - // m_constraints.push_back(genericConstraint); - m_dynamicsWorld->addConstraint(genericConstraint,disableCollisionBetweenLinkedBodies); - - genericConstraint->setUserConstraintId(gConstraintUid++); - genericConstraint->setUserConstraintType(PHY_GENERIC_6DOF_CONSTRAINT); - //64 bit systems can't cast pointer to int. could use size_t instead. - return genericConstraint->getUserConstraintId(); - } - return 0; -} - -void CcdPhysicsEnvironment::RemoveConstraintById(int constraintId) +void CcdPhysicsEnvironment::RemoveConstraintById(int constraintId, bool free) { // For soft body constraints - if (constraintId == 0) + if (constraintId == 0) { return; + } int i; int numConstraints = m_dynamicsWorld->getNumConstraints(); - for (i=0;igetConstraint(i); - if (constraint->getUserConstraintId() == constraintId) - { - RemoveConstraint(constraint); + for (i = 0; i < numConstraints; i++) { + btTypedConstraint *constraint = m_dynamicsWorld->getConstraint(i); + if (constraint->getUserConstraintId() == constraintId) { + RemoveConstraint(constraint, free); break; } } - WrapperVehicle *vehicle; - if ((vehicle = (WrapperVehicle*)GetVehicleConstraint(constraintId))) - { - m_dynamicsWorld->removeVehicle(vehicle->GetVehicle()); - m_wrapperVehicles.erase(std::remove(m_wrapperVehicles.begin(), m_wrapperVehicles.end(), vehicle)); - delete vehicle; + WrapperVehicle *vehicle = static_cast(GetVehicleConstraint(constraintId)); + if (vehicle) { + RemoveVehicle(vehicle, free); } } +struct FilterClosestRayResultCallback : public btCollisionWorld::ClosestRayResultCallback { + PHY_IRayCastFilterCallback& m_phyRayFilter; + const btCollisionShape *m_hitTriangleShape; + int m_hitTriangleIndex; -struct FilterClosestRayResultCallback : public btCollisionWorld::ClosestRayResultCallback -{ - PHY_IRayCastFilterCallback& m_phyRayFilter; - const btCollisionShape* m_hitTriangleShape; - int m_hitTriangleIndex; - - - FilterClosestRayResultCallback (PHY_IRayCastFilterCallback& phyRayFilter,const btVector3& rayFrom,const btVector3& rayTo) - : btCollisionWorld::ClosestRayResultCallback(rayFrom,rayTo), + FilterClosestRayResultCallback(PHY_IRayCastFilterCallback& phyRayFilter, const btVector3& rayFrom, const btVector3& rayTo) + :btCollisionWorld::ClosestRayResultCallback(rayFrom, rayTo), m_phyRayFilter(phyRayFilter), - m_hitTriangleShape(NULL), + m_hitTriangleShape(nullptr), m_hitTriangleIndex(0) { } @@ -1161,38 +1114,39 @@ struct FilterClosestRayResultCallback : public btCollisionWorld::ClosestRayResul { } - virtual bool needsCollision(btBroadphaseProxy* proxy0) const + virtual bool needsCollision(btBroadphaseProxy *proxy0) const { - if (!(proxy0->m_collisionFilterGroup & m_collisionFilterMask)) + if (!(proxy0->m_collisionFilterGroup & m_collisionFilterMask)) { return false; - if (!(m_collisionFilterGroup & proxy0->m_collisionFilterMask)) + } + if (!(m_collisionFilterGroup & proxy0->m_collisionFilterMask)) { return false; - btCollisionObject* object = (btCollisionObject*)proxy0->m_clientObject; - CcdPhysicsController* phyCtrl = static_cast(object->getUserPointer()); - if (phyCtrl == m_phyRayFilter.m_ignoreController) + } + btCollisionObject *object = (btCollisionObject *)proxy0->m_clientObject; + CcdPhysicsController *phyCtrl = static_cast(object->getUserPointer()); + if (phyCtrl == m_phyRayFilter.m_ignoreController) { return false; + } return m_phyRayFilter.needBroadphaseRayCast(phyCtrl); } - virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) + virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace) { //CcdPhysicsController* curHit = static_cast(rayResult.m_collisionObject->getUserPointer()); // save shape information as ClosestRayResultCallback::AddSingleResult() does not do it - if (rayResult.m_localShapeInfo) - { + if (rayResult.m_localShapeInfo) { m_hitTriangleShape = rayResult.m_collisionObject->getCollisionShape(); m_hitTriangleIndex = rayResult.m_localShapeInfo->m_triangleIndex; - } else - { - m_hitTriangleShape = NULL; + } + else { + m_hitTriangleShape = nullptr; m_hitTriangleIndex = 0; } - return ClosestRayResultCallback::addSingleResult(rayResult,normalInWorldSpace); + return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace); } - }; -static bool GetHitTriangle(btCollisionShape* shape, CcdShapeConstructionInfo* shapeInfo, int hitTriangleIndex, btVector3 triangle[]) +static bool GetHitTriangle(btCollisionShape *shape, CcdShapeConstructionInfo *shapeInfo, int hitTriangleIndex, btVector3 triangle[]) { // this code is copied from Bullet const unsigned char *vertexbase; @@ -1203,10 +1157,11 @@ static bool GetHitTriangle(btCollisionShape* shape, CcdShapeConstructionInfo* sh int indexstride; int numfaces; PHY_ScalarType indicestype; - btStridingMeshInterface* meshInterface = shapeInfo->GetMeshInterface(); + btStridingMeshInterface *meshInterface = shapeInfo->GetMeshInterface(); - if (!meshInterface) + if (!meshInterface) { return false; + } meshInterface->getLockedReadOnlyVertexIndexBase( &vertexbase, @@ -1219,35 +1174,32 @@ static bool GetHitTriangle(btCollisionShape* shape, CcdShapeConstructionInfo* sh indicestype, 0); - unsigned int* gfxbase = (unsigned int*)(indexbase+hitTriangleIndex*indexstride); + unsigned int *gfxbase = (unsigned int *)(indexbase + hitTriangleIndex * indexstride); const btVector3& meshScaling = shape->getLocalScaling(); - for (int j=2;j>=0;j--) - { + for (int j = 2; j >= 0; j--) { int graphicsindex = (indicestype == PHY_SHORT) ? ((unsigned short *)gfxbase)[j] : gfxbase[j]; - btScalar* graphicsbase = (btScalar*)(vertexbase+graphicsindex*stride); + btScalar *graphicsbase = (btScalar *)(vertexbase + graphicsindex * stride); - triangle[j] = btVector3(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),graphicsbase[2]*meshScaling.getZ()); + triangle[j] = btVector3(graphicsbase[0] * meshScaling.getX(), graphicsbase[1] * meshScaling.getY(), graphicsbase[2] * meshScaling.getZ()); } meshInterface->unLockReadOnlyVertexBase(0); return true; } -PHY_IPhysicsController* CcdPhysicsEnvironment::RayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ) +PHY_IPhysicsController *CcdPhysicsEnvironment::RayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX, float fromY, float fromZ, float toX, float toY, float toZ) { - btVector3 rayFrom(fromX,fromY,fromZ); - btVector3 rayTo(toX,toY,toZ); + btVector3 rayFrom(fromX, fromY, fromZ); + btVector3 rayTo(toX, toY, toZ); - btVector3 hitPointWorld,normalWorld; + btVector3 hitPointWorld, normalWorld; //Either Ray Cast with or without filtering //btCollisionWorld::ClosestRayResultCallback rayCallback(rayFrom,rayTo); - FilterClosestRayResultCallback rayCallback(filterCallback,rayFrom,rayTo); - + FilterClosestRayResultCallback rayCallback(filterCallback, rayFrom, rayTo); PHY_RayCastResult result; - memset(&result, 0, sizeof(result)); // don't collision with sensor object rayCallback.m_collisionFilterMask = CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::SensorFilter; @@ -1255,139 +1207,128 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::RayTest(PHY_IRayCastFilterCallbac rayCallback.m_flags |= btTriangleRaycastCallback::kF_UseSubSimplexConvexCastRaytest; //, ,filterCallback.m_faceNormal); - m_dynamicsWorld->rayTest(rayFrom,rayTo,rayCallback); - if (rayCallback.hasHit()) - { - CcdPhysicsController* controller = static_cast(rayCallback.m_collisionObject->getUserPointer()); + m_dynamicsWorld->rayTest(rayFrom, rayTo, rayCallback); + if (rayCallback.hasHit()) { + CcdPhysicsController *controller = static_cast(rayCallback.m_collisionObject->getUserPointer()); result.m_controller = controller; result.m_hitPoint[0] = rayCallback.m_hitPointWorld.getX(); result.m_hitPoint[1] = rayCallback.m_hitPointWorld.getY(); result.m_hitPoint[2] = rayCallback.m_hitPointWorld.getZ(); - if (rayCallback.m_hitTriangleShape != NULL) - { + if (rayCallback.m_hitTriangleShape != nullptr) { // identify the mesh polygon - CcdShapeConstructionInfo* shapeInfo = controller->m_shapeInfo; - if (shapeInfo) - { - btCollisionShape* shape = controller->GetCollisionObject()->getCollisionShape(); - if (shape->isCompound()) - { - btCompoundShape* compoundShape = (btCompoundShape*)shape; - CcdShapeConstructionInfo* compoundShapeInfo = shapeInfo; + CcdShapeConstructionInfo *shapeInfo = controller->m_shapeInfo; + if (shapeInfo) { + btCollisionShape *shape = controller->GetCollisionObject()->getCollisionShape(); + if (shape->isCompound()) { + btCompoundShape *compoundShape = (btCompoundShape *)shape; + CcdShapeConstructionInfo *compoundShapeInfo = shapeInfo; // need to search which sub-shape has been hit - for (int i=0; igetNumChildShapes(); i++) - { + for (int i = 0; i < compoundShape->getNumChildShapes(); i++) { shapeInfo = compoundShapeInfo->GetChildShape(i); - shape=compoundShape->getChildShape(i); - if (shape == rayCallback.m_hitTriangleShape) + shape = compoundShape->getChildShape(i); + if (shape == rayCallback.m_hitTriangleShape) { break; + } } } if (shape == rayCallback.m_hitTriangleShape && - rayCallback.m_hitTriangleIndex < shapeInfo->m_polygonIndexArray.size()) - { + rayCallback.m_hitTriangleIndex < shapeInfo->m_polygonIndexArray.size()) { // save original collision shape triangle for soft body int hitTriangleIndex = rayCallback.m_hitTriangleIndex; result.m_meshObject = shapeInfo->GetMesh(); - if (shape->isSoftBody()) - { + if (shape->isSoftBody()) { // soft body using different face numbering because of randomization // hopefully we have stored the original face number in m_tag - const btSoftBody* softBody = static_cast(rayCallback.m_collisionObject); - if (softBody->m_faces[hitTriangleIndex].m_tag != 0) - { - rayCallback.m_hitTriangleIndex = (int)((uintptr_t)(softBody->m_faces[hitTriangleIndex].m_tag)-1); + const btSoftBody *softBody = static_cast(rayCallback.m_collisionObject); + if (softBody->m_faces[hitTriangleIndex].m_tag != 0) { + rayCallback.m_hitTriangleIndex = (int)((uintptr_t)(softBody->m_faces[hitTriangleIndex].m_tag) - 1); } } // retrieve the original mesh polygon (in case of quad->tri conversion) - result.m_polygon = shapeInfo->m_polygonIndexArray.at(rayCallback.m_hitTriangleIndex); + result.m_polygon = shapeInfo->m_polygonIndexArray[rayCallback.m_hitTriangleIndex]; // hit triangle in world coordinate, for face normal and UV coordinate btVector3 triangle[3]; bool triangleOK = false; - if (filterCallback.m_faceUV && (3*rayCallback.m_hitTriangleIndex) < shapeInfo->m_triFaceUVcoArray.size()) - { + if (filterCallback.m_faceUV && (3 * rayCallback.m_hitTriangleIndex) < shapeInfo->m_triFaceUVcoArray.size()) { // interpolate the UV coordinate of the hit point - CcdShapeConstructionInfo::UVco* uvCo = &shapeInfo->m_triFaceUVcoArray[3*rayCallback.m_hitTriangleIndex]; + CcdShapeConstructionInfo::UVco *uvCo = &shapeInfo->m_triFaceUVcoArray[3 * rayCallback.m_hitTriangleIndex]; // 1. get the 3 coordinate of the triangle in world space btVector3 v1, v2, v3; - if (shape->isSoftBody()) - { + if (shape->isSoftBody()) { // soft body give points directly in world coordinate - const btSoftBody* softBody = static_cast(rayCallback.m_collisionObject); + const btSoftBody *softBody = static_cast(rayCallback.m_collisionObject); v1 = softBody->m_faces[hitTriangleIndex].m_n[0]->m_x; v2 = softBody->m_faces[hitTriangleIndex].m_n[1]->m_x; v3 = softBody->m_faces[hitTriangleIndex].m_n[2]->m_x; - } else - { + } + else { // for rigid body we must apply the world transform triangleOK = GetHitTriangle(shape, shapeInfo, hitTriangleIndex, triangle); - if (!triangleOK) + if (!triangleOK) { // if we cannot get the triangle, no use to continue goto SKIP_UV_NORMAL; + } v1 = rayCallback.m_collisionObject->getWorldTransform()(triangle[0]); v2 = rayCallback.m_collisionObject->getWorldTransform()(triangle[1]); v3 = rayCallback.m_collisionObject->getWorldTransform()(triangle[2]); } // 2. compute barycentric coordinate of the hit point - btVector3 v = v2-v1; - btVector3 w = v3-v1; + btVector3 v = v2 - v1; + btVector3 w = v3 - v1; btVector3 u = v.cross(w); btScalar A = u.length(); - v = v2-rayCallback.m_hitPointWorld; - w = v3-rayCallback.m_hitPointWorld; + v = v2 - rayCallback.m_hitPointWorld; + w = v3 - rayCallback.m_hitPointWorld; u = v.cross(w); btScalar A1 = u.length(); - v = rayCallback.m_hitPointWorld-v1; - w = v3-v1; + v = rayCallback.m_hitPointWorld - v1; + w = v3 - v1; u = v.cross(w); btScalar A2 = u.length(); btVector3 baryCo; - baryCo.setX(A1/A); - baryCo.setY(A2/A); - baryCo.setZ(1.0f-baryCo.getX()-baryCo.getY()); + baryCo.setX(A1 / A); + baryCo.setY(A2 / A); + baryCo.setZ(1.0f - baryCo.getX() - baryCo.getY()); // 3. compute UV coordinate - result.m_hitUV[0] = baryCo.getX()*uvCo[0].uv[0] + baryCo.getY()*uvCo[1].uv[0] + baryCo.getZ()*uvCo[2].uv[0]; - result.m_hitUV[1] = baryCo.getX()*uvCo[0].uv[1] + baryCo.getY()*uvCo[1].uv[1] + baryCo.getZ()*uvCo[2].uv[1]; + result.m_hitUV[0] = baryCo.getX() * uvCo[0].uv[0] + baryCo.getY() * uvCo[1].uv[0] + baryCo.getZ() * uvCo[2].uv[0]; + result.m_hitUV[1] = baryCo.getX() * uvCo[0].uv[1] + baryCo.getY() * uvCo[1].uv[1] + baryCo.getZ() * uvCo[2].uv[1]; result.m_hitUVOK = 1; } // Bullet returns the normal from "outside". // If the user requests the real normal, compute it now - if (filterCallback.m_faceNormal) - { - if (shape->isSoftBody()) - { + if (filterCallback.m_faceNormal) { + if (shape->isSoftBody()) { // we can get the real normal directly from the body - const btSoftBody* softBody = static_cast(rayCallback.m_collisionObject); + const btSoftBody *softBody = static_cast(rayCallback.m_collisionObject); rayCallback.m_hitNormalWorld = softBody->m_faces[hitTriangleIndex].m_normal; - } else - { - if (!triangleOK) + } + else { + if (!triangleOK) { triangleOK = GetHitTriangle(shape, shapeInfo, hitTriangleIndex, triangle); - if (triangleOK) - { + } + if (triangleOK) { btVector3 triangleNormal; - triangleNormal = (triangle[1]-triangle[0]).cross(triangle[2]-triangle[0]); - rayCallback.m_hitNormalWorld = rayCallback.m_collisionObject->getWorldTransform().getBasis()*triangleNormal; + triangleNormal = (triangle[1] - triangle[0]).cross(triangle[2] - triangle[0]); + rayCallback.m_hitNormalWorld = rayCallback.m_collisionObject->getWorldTransform().getBasis() * triangleNormal; } } } - SKIP_UV_NORMAL: +SKIP_UV_NORMAL: ; } } } - if (rayCallback.m_hitNormalWorld.length2() > (SIMD_EPSILON*SIMD_EPSILON)) - { + if (rayCallback.m_hitNormalWorld.length2() > (SIMD_EPSILON * SIMD_EPSILON)) { rayCallback.m_hitNormalWorld.normalize(); - } else - { - rayCallback.m_hitNormalWorld.setValue(1,0,0); + } + else { + rayCallback.m_hitNormalWorld.setValue(1.0f, 0.0f, 0.0f); } result.m_hitNormal[0] = rayCallback.m_hitNormalWorld.getX(); result.m_hitNormal[1] = rayCallback.m_hitNormalWorld.getY(); @@ -1395,16 +1336,13 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::RayTest(PHY_IRayCastFilterCallbac filterCallback.reportHit(&result); } - return result.m_controller; } // Handles occlusion culling. // The implementation is based on the CDTestFramework -struct OcclusionBuffer -{ - struct WriteOCL - { +struct OcclusionBuffer { + struct WriteOCL { static inline bool Process(btScalar &q, btScalar v) { if (q < v) { @@ -1418,8 +1356,7 @@ struct OcclusionBuffer } }; - struct QueryOCL - { + struct QueryOCL { static inline bool Process(btScalar &q, btScalar v) { return (q <= v); @@ -1444,7 +1381,7 @@ struct OcclusionBuffer { m_initialized = false; m_occlusion = false; - m_buffer = NULL; + m_buffer = nullptr; m_bufferSize = 0; } // multiplication of column major matrices: m = m1 * m2 @@ -1472,13 +1409,13 @@ struct OcclusionBuffer m[15] = btScalar(m1[3] * m2[12] + m1[7] * m2[13] + m1[11] * m2[14] + m1[15] * m2[15]); } - void setup(int size, const int *view, float modelview[16], float projection[16]) + void setup(int size, const int *view, float mat[16]) { m_initialized = false; m_occlusion = false; // compute the size of the buffer int maxsize = (view[2] > view[3]) ? view[2] : view[3]; - assert(maxsize > 0); + BLI_assert(maxsize > 0); double ratio = 1.0 / (2 * maxsize); // ensure even number m_sizes[0] = 2 * ((int)(size * view[2] * ratio + 0.5)); @@ -1491,7 +1428,9 @@ struct OcclusionBuffer // at this time of the rendering, the modelview matrix is the // world to camera transformation and the projection matrix is // camera to clip transformation. combine both so that - CMmat4mul(m_wtc, projection, modelview); + for (unsigned short i = 0; i < 16; i++) { + m_wtc[i] = btScalar(mat[i]); + } } void initialize() @@ -1501,7 +1440,7 @@ struct OcclusionBuffer // see if we can reuse if (newsize > m_bufferSize) { free(m_buffer); - m_buffer = NULL; + m_buffer = nullptr; m_bufferSize = 0; } } @@ -1514,14 +1453,14 @@ struct OcclusionBuffer memset(m_buffer, 0, newsize); } // memory allocate must succeed - assert(m_buffer != NULL); + BLI_assert(m_buffer != nullptr); m_initialized = true; m_occlusion = false; } void SetModelMatrix(float *fl) { - CMmat4mul(m_mtc,m_wtc,fl); + CMmat4mul(m_mtc, m_wtc, fl); if (!m_initialized) { initialize(); } @@ -1606,7 +1545,7 @@ struct OcclusionBuffer return 0; } if (m != 0) { - for (i = ni - 1, j = 0, n = 0;j < ni; i = j++) { + for (i = ni - 1, j = 0, n = 0; j < ni; i = j++) { const btVector4 &a = pi[i]; const btVector4 &b = pi[j]; const btScalar t = s[i] / (a[2] - a[3] - b[2] + b[3]); @@ -1631,10 +1570,10 @@ struct OcclusionBuffer // write or check a triangle to buffer. a,b,c in device coordinates (-1,+1) template inline bool draw(const btVector4 &a, - const btVector4 &b, - const btVector4 &c, - const float face, - const btScalar minarea) + const btVector4 &b, + const btVector4 &c, + const float face, + const btScalar minarea) { const btScalar a2 = btCross(b - a, c - a)[2]; if ((face * a2) < 0.0f || btFabs(a2) < minarea) { @@ -1717,15 +1656,15 @@ struct OcclusionBuffer z[1] = ztmp; } int dy[] = {y[0] - y[1], - y[1] - y[2], - y[2] - y[0]}; + y[1] - y[2], + y[2] - y[0]}; btScalar dzy[3]; dzy[0] = (dy[0]) ? (z[0] - z[1]) / dy[0] : btScalar(0.0f); dzy[1] = (dy[1]) ? (z[1] - z[2]) / dy[1] : btScalar(0.0f); dzy[2] = (dy[2]) ? (z[2] - z[0]) / dy[2] : btScalar(0.0f); btScalar v[3] = {dzy[0] * (miy - y[0]) + z[0], - dzy[1] * (miy - y[1]) + z[1], - dzy[2] * (miy - y[2]) + z[2]}; + dzy[1] * (miy - y[1]) + z[1], + dzy[2] * (miy - y[2]) + z[2]}; dy[0] = y[1] - y[0]; dy[1] = y[0] - y[1]; dy[2] = y[2] - y[0]; @@ -1781,15 +1720,15 @@ struct OcclusionBuffer z[1] = ztmp; } int dx[] = {x[0] - x[1], - x[1] - x[2], - x[2] - x[0]}; + x[1] - x[2], + x[2] - x[0]}; btScalar dzx[3]; - dzx[0] = (dx[0]) ? (z[0]-z[1]) / dx[0] : btScalar(0.0f); - dzx[1] = (dx[1]) ? (z[1]-z[2]) / dx[1] : btScalar(0.0f); - dzx[2] = (dx[2]) ? (z[2]-z[0]) / dx[2] : btScalar(0.0f); + dzx[0] = (dx[0]) ? (z[0] - z[1]) / dx[0] : btScalar(0.0f); + dzx[1] = (dx[1]) ? (z[1] - z[2]) / dx[1] : btScalar(0.0f); + dzx[2] = (dx[2]) ? (z[2] - z[0]) / dx[2] : btScalar(0.0f); btScalar v[3] = {dzx[0] * (mix - x[0]) + z[0], - dzx[1] * (mix - x[1]) + z[1], - dzx[2] * (mix - x[2]) + z[2]}; + dzx[1] * (mix - x[1]) + z[1], + dzx[2] * (mix - x[2]) + z[2]}; dx[0] = x[1] - x[0]; dx[1] = x[0] - x[1]; dx[2] = x[2] - x[0]; @@ -1816,18 +1755,18 @@ struct OcclusionBuffer else { // general case const int dx[] = {y[0] - y[1], - y[1] - y[2], - y[2] - y[0]}; + y[1] - y[2], + y[2] - y[0]}; const int dy[] = {x[1] - x[0] - dx[0] * width, - x[2] - x[1] - dx[1] * width, - x[0] - x[2] - dx[2] * width}; + x[2] - x[1] - dx[1] * width, + x[0] - x[2] - dx[2] * width}; const int a = x[2] * y[0] + x[0] * y[1] - x[2] * y[1] - x[0] * y[2] + x[1] * y[2] - x[1] * y[0]; const btScalar ia = 1 / (btScalar)a; const btScalar dzx = ia * (y[2] * (z[1] - z[0]) + y[1] * (z[0] - z[2]) + y[0] * (z[2] - z[1])); const btScalar dzy = ia * (x[2] * (z[0] - z[1]) + x[0] * (z[1] - z[2]) + x[1] * (z[2] - z[0])) - (dzx * width); - int c[] = {miy * x[1] + mix * y[0] - x[1] * y[0] - mix * y[1] + x[0] * y[1] - miy * x[0], - miy * x[2] + mix * y[1] - x[2] * y[1] - mix * y[2] + x[1] * y[2] - miy * x[1], - miy * x[0] + mix * y[2] - x[0] * y[2] - mix * y[0] + x[2] * y[0] - miy * x[2]}; + int c[] = {miy *x[1] + mix * y[0] - x[1] * y[0] - mix * y[1] + x[0] * y[1] - miy * x[0], + miy *x[2] + mix * y[1] - x[2] * y[1] - mix * y[2] + x[1] * y[2] - miy * x[1], + miy *x[0] + mix * y[2] - x[0] * y[2] - mix * y[0] + x[2] * y[0] - miy * x[2]}; btScalar v = ia * ((z[2] * c[0]) + (z[0] * c[1]) + (z[1] * c[2])); btScalar *scan = &m_buffer[miy * m_sizes[0]]; @@ -1849,8 +1788,8 @@ struct OcclusionBuffer // clip than write or check a polygon template inline bool clipDraw(const btVector4 *p, - const float face, - btScalar minarea) + const float face, + btScalar minarea) { btVector4 o[NP * 2]; int n = clip(p, o); @@ -1868,9 +1807,9 @@ struct OcclusionBuffer // = 1.f if face is single sided and scale is positive // = -1.f if face is single sided and scale is negative void appendOccluderM(const float *a, - const float *b, - const float *c, - const float face) + const float *b, + const float *c, + const float face) { btVector4 p[3]; transformM(a, p[0]); @@ -1878,23 +1817,10 @@ struct OcclusionBuffer transformM(c, p[2]); clipDraw<3, WriteOCL>(p, face, btScalar(0.0f)); } - // add a quad (in model coordinate) - void appendOccluderM(const float *a, - const float *b, - const float *c, - const float *d, - const float face) - { - btVector4 p[4]; - transformM(a, p[0]); - transformM(b, p[1]); - transformM(c, p[2]); - transformM(d, p[3]); - clipDraw<4, WriteOCL>(p, face, btScalar(0.0f)); - } + // query occluder for a box (c=center, e=extend) in world coordinate inline bool queryOccluderW(const btVector3 &c, - const btVector3 &e) + const btVector3 &e) { if (!m_occlusion) { // no occlusion yet, no need to check @@ -1917,16 +1843,16 @@ struct OcclusionBuffer } } static const int d[] = {1, 0, 3, 2, - 4, 5, 6, 7, - 4, 7, 3, 0, - 6, 5, 1, 2, - 7, 6, 2, 3, - 5, 4, 0, 1}; - for (unsigned int i = 0; i < (sizeof(d) / sizeof(d[0]));) { + 4, 5, 6, 7, + 4, 7, 3, 0, + 6, 5, 1, 2, + 7, 6, 2, 3, + 5, 4, 0, 1}; + for (unsigned int i = 0; i < (sizeof(d) / sizeof(d[0])); ) { const btVector4 p[] = {x[d[i + 0]], - x[d[i + 1]], - x[d[i + 2]], - x[d[i + 3]]}; + x[d[i + 1]], + x[d[i + 2]], + x[d[i + 3]]}; i += 4; if (clipDraw<4, QueryOCL>(p, 1.0f, 0.0f)) { return true; @@ -1937,636 +1863,359 @@ struct OcclusionBuffer }; -struct DbvtCullingCallback : btDbvt::ICollide -{ +struct DbvtCullingCallback : btDbvt::ICollide { PHY_CullingCallback m_clientCallback; - void* m_userData; + void *m_userData; OcclusionBuffer *m_ocb; - DbvtCullingCallback(PHY_CullingCallback clientCallback, void* userData) + DbvtCullingCallback(PHY_CullingCallback clientCallback, void *userData) { m_clientCallback = clientCallback; m_userData = userData; - m_ocb = NULL; + m_ocb = nullptr; } - bool Descent(const btDbvtNode* node) + bool Descent(const btDbvtNode *node) { - return(m_ocb->queryOccluderW(node->volume.Center(),node->volume.Extents())); + return (m_ocb->queryOccluderW(node->volume.Center(), node->volume.Extents())); } - void Process(const btDbvtNode* node,btScalar depth) + void Process(const btDbvtNode *node, btScalar depth) { Process(node); } - void Process(const btDbvtNode* leaf) + void Process(const btDbvtNode *leaf) { - btBroadphaseProxy* proxy=(btBroadphaseProxy*)leaf->data; + btBroadphaseProxy *proxy = (btBroadphaseProxy *)leaf->data; // the client object is a graphic controller - CcdGraphicController* ctrl = static_cast(proxy->m_clientObject); - KX_ClientObjectInfo *info = (KX_ClientObjectInfo*)ctrl->GetNewClientInfo(); - if (m_ocb) - { + CcdGraphicController *ctrl = static_cast(proxy->m_clientObject); + KX_ClientObjectInfo *info = (KX_ClientObjectInfo *)ctrl->GetNewClientInfo(); + if (m_ocb) { // means we are doing occlusion culling. Check if this object is an occluders - KX_GameObject* gameobj = KX_GameObject::GetClientObject(info); - if (gameobj && gameobj->GetOccluder()) - { - float *fl = gameobj->GetOpenGLMatrixPtr()->getPointer(); + KX_GameObject *gameobj = KX_GameObject::GetClientObject(info); + if (gameobj && gameobj->GetOccluder()) { + float fl[16]; + gameobj->NodeGetWorldTransform().PackFromAffineTransform(fl); + // this will create the occlusion buffer if not already done // and compute the transformation from model local space to clip space m_ocb->SetModelMatrix(fl); - float face = (gameobj->IsNegativeScaling()) ? -1.0f : 1.0f; + const float negative = gameobj->IsNegativeScaling(); // walk through the meshes and for each add to buffer - for (int i=0; iGetMeshCount(); i++) - { - RAS_MeshObject* meshobj = gameobj->GetMesh(i); - const float *v1, *v2, *v3, *v4; - - int polycount = meshobj->NumPolygons(); - for (int j=0; jGetPolygon(j); - switch (poly->VertexCount()) - { - case 3: - v1 = poly->GetVertex(0)->getXYZ(); - v2 = poly->GetVertex(1)->getXYZ(); - v3 = poly->GetVertex(2)->getXYZ(); - m_ocb->appendOccluderM(v1,v2,v3,((poly->IsTwoside())?0.f:face)); - break; - case 4: - v1 = poly->GetVertex(0)->getXYZ(); - v2 = poly->GetVertex(1)->getXYZ(); - v3 = poly->GetVertex(2)->getXYZ(); - v4 = poly->GetVertex(3)->getXYZ(); - m_ocb->appendOccluderM(v1,v2,v3,v4,((poly->IsTwoside())?0.f:face)); - break; + for (KX_Mesh *meshobj : gameobj->GetMeshList()) { + for (RAS_MeshMaterial *meshmat : meshobj->GetMeshMaterialList()) { + RAS_DisplayArray *array = meshmat->GetDisplayArray(); + const bool twoside = meshmat->GetBucket()->GetMaterial()->IsTwoSided(); + const float face = (twoside) ? 0.0f : ((negative) ? -1.0f : 1.0f); + + for (unsigned int j = 0, size = array->GetTriangleIndexCount(); j < size; j += 3) { + m_ocb->appendOccluderM(array->GetPosition(array->GetTriangleIndex(j)).data, + array->GetPosition(array->GetTriangleIndex(j + 1)).data, + array->GetPosition(array->GetTriangleIndex(j + 2)).data, + face); } } } } } - if (info) + if (info) { (*m_clientCallback)(info, m_userData); + } } }; static OcclusionBuffer gOcb; -bool CcdPhysicsEnvironment::CullingTest(PHY_CullingCallback callback, void* userData, MT_Vector4 *planes, int nplanes, int occlusionRes, const int *viewport, float modelview[16], float projection[16]) +bool CcdPhysicsEnvironment::CullingTest(PHY_CullingCallback callback, void *userData, const std::array& planes, + int occlusionRes, const int *viewport, const mt::mat4& matrix) { - if (!m_cullingTree) + if (!m_cullingTree) { return false; + } DbvtCullingCallback dispatcher(callback, userData); btVector3 planes_n[6]; btScalar planes_o[6]; - if (nplanes > 6) - nplanes = 6; - for (int i=0; i occlusion culling - if (occlusionRes) - { - gOcb.setup(occlusionRes, viewport, modelview, projection); + if (occlusionRes) { + gOcb.setup(occlusionRes, viewport, (float *)matrix.Data()); dispatcher.m_ocb = &gOcb; // occlusion culling, the direction of the view is taken from the first plan which MUST be the near plane - btDbvt::collideOCL(m_cullingTree->m_sets[1].m_root,planes_n,planes_o,planes_n[0],nplanes,dispatcher); - btDbvt::collideOCL(m_cullingTree->m_sets[0].m_root,planes_n,planes_o,planes_n[0],nplanes,dispatcher); + btDbvt::collideOCL(m_cullingTree->m_sets[1].m_root, planes_n, planes_o, planes_n[0], 6, dispatcher); + btDbvt::collideOCL(m_cullingTree->m_sets[0].m_root, planes_n, planes_o, planes_n[0], 6, dispatcher); } else { - btDbvt::collideKDOP(m_cullingTree->m_sets[1].m_root,planes_n,planes_o,nplanes,dispatcher); - btDbvt::collideKDOP(m_cullingTree->m_sets[0].m_root,planes_n,planes_o,nplanes,dispatcher); + btDbvt::collideKDOP(m_cullingTree->m_sets[1].m_root, planes_n, planes_o, 6, dispatcher); + btDbvt::collideKDOP(m_cullingTree->m_sets[0].m_root, planes_n, planes_o, 6, dispatcher); } return true; } -int CcdPhysicsEnvironment::GetNumContactPoints() +int CcdPhysicsEnvironment::GetNumContactPoints() { return 0; } -void CcdPhysicsEnvironment::GetContactPoint(int i,float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ) +void CcdPhysicsEnvironment::GetContactPoint(int i, float& hitX, float& hitY, float& hitZ, float& normalX, float& normalY, float& normalZ) { - } - - - -btBroadphaseInterface* CcdPhysicsEnvironment::GetBroadphase() +btBroadphaseInterface *CcdPhysicsEnvironment::GetBroadphase() { return m_dynamicsWorld->getBroadphase(); } -btDispatcher* CcdPhysicsEnvironment::GetDispatcher() +btDispatcher *CcdPhysicsEnvironment::GetDispatcher() { return m_dynamicsWorld->getDispatcher(); } void CcdPhysicsEnvironment::MergeEnvironment(PHY_IPhysicsEnvironment *other_env) { - CcdPhysicsEnvironment *other = dynamic_cast(other_env); - if (other == NULL) { - printf("KX_Scene::MergeScene: Other scene is not using Bullet physics, not merging physics.\n"); + CcdPhysicsEnvironment *other = static_cast(other_env); + if (other == nullptr) { + CM_Error("other scene is not using Bullet physics, not merging physics."); return; } - std::set::iterator it; + std::set::iterator it; - while (other->m_controllers.begin() != other->m_controllers.end()) - { - it= other->m_controllers.begin(); - CcdPhysicsController* ctrl= (*it); + while (other->m_controllers.begin() != other->m_controllers.end()) { + it = other->m_controllers.begin(); + CcdPhysicsController *ctrl = (*it); - other->RemoveCcdPhysicsController(ctrl); + other->RemoveCcdPhysicsController(ctrl, true); this->AddCcdPhysicsController(ctrl); } } CcdPhysicsEnvironment::~CcdPhysicsEnvironment() { - -#ifdef NEW_BULLET_VEHICLE_SUPPORT m_wrapperVehicles.clear(); -#endif //NEW_BULLET_VEHICLE_SUPPORT - - //m_broadphase->DestroyScene(); - //delete broadphase ? release reference on broadphase ? - - //first delete scene, then dispatcher, because pairs have to release manifolds on the dispatcher - //delete m_dispatcher; - delete m_dynamicsWorld; - - - if (NULL != m_ownPairCache) - delete m_ownPairCache; - - if (NULL != m_ownDispatcher) - delete m_ownDispatcher; - - if (NULL != m_solver) - delete m_solver; - - if (NULL != m_debugDrawer) - delete m_debugDrawer; - - if (NULL != m_filterCallback) - delete m_filterCallback; - - if (NULL != m_ghostPairCallback) - delete m_ghostPairCallback; - - if (NULL != m_collisionConfiguration) - delete m_collisionConfiguration; - - if (NULL != m_broadphase) - delete m_broadphase; - - if (NULL != m_cullingTree) - delete m_cullingTree; - - if (NULL != m_cullingCache) - delete m_cullingCache; - -} - - -float CcdPhysicsEnvironment::GetConstraintParam(int constraintId,int param) -{ - btTypedConstraint* typedConstraint = GetConstraintById(constraintId); - if (!typedConstraint) - return 0.0f; - switch (typedConstraint->getUserConstraintType()) - { - case PHY_GENERIC_6DOF_CONSTRAINT: - { - - switch (param) - { - case 0: case 1: case 2: - { - //param = 0..2 are linear constraint values - btGeneric6DofConstraint* genCons = (btGeneric6DofConstraint*)typedConstraint; - genCons->calculateTransforms(); - return genCons->getRelativePivotPosition(param); - break; - } - case 3: case 4: case 5: - { - //param = 3..5 are relative constraint (Euler) angles - btGeneric6DofConstraint* genCons = (btGeneric6DofConstraint*)typedConstraint; - genCons->calculateTransforms(); - return genCons->getAngle(param-3); - break; - } - default: - { - } - } - break; - }; - default: - { - }; - }; - return 0.f; -} - -void CcdPhysicsEnvironment::SetConstraintParam(int constraintId,int param,float value0,float value1) -{ - btTypedConstraint* typedConstraint = GetConstraintById(constraintId); - if (!typedConstraint) - return; - - switch (typedConstraint->getUserConstraintType()) - { - case PHY_GENERIC_6DOF_CONSTRAINT: - { - - switch (param) - { - case 0: case 1: case 2: case 3: case 4: case 5: - { - //param = 0..5 are constraint limits, with low/high limit value - btGeneric6DofConstraint* genCons = (btGeneric6DofConstraint*)typedConstraint; - genCons->setLimit(param,value0,value1); - break; - } - case 6: case 7: case 8: - { - //param = 6,7,8 are translational motors, with value0=target velocity, value1 = max motor force - btGeneric6DofConstraint* genCons = (btGeneric6DofConstraint*)typedConstraint; - int transMotorIndex = param-6; - btTranslationalLimitMotor* transMotor = genCons->getTranslationalLimitMotor(); - transMotor->m_targetVelocity[transMotorIndex] = value0; - transMotor->m_maxMotorForce[transMotorIndex] = value1; - transMotor->m_enableMotor[transMotorIndex] = (value1>0.f); - break; - } - case 9: case 10: case 11: - { - //param = 9,10,11 are rotational motors, with value0=target velocity, value1 = max motor force - btGeneric6DofConstraint* genCons = (btGeneric6DofConstraint*)typedConstraint; - int angMotorIndex = param-9; - btRotationalLimitMotor* rotMotor = genCons->getRotationalLimitMotor(angMotorIndex); - rotMotor->m_enableMotor = (value1 > 0.f); - rotMotor->m_targetVelocity = value0; - rotMotor->m_maxMotorForce = value1; - break; - } - - case 12: case 13: case 14: case 15: case 16: case 17: - { - //param 12-17 are for motorized springs on each of the degrees of freedom - btGeneric6DofSpringConstraint* genCons = (btGeneric6DofSpringConstraint*)typedConstraint; - int springIndex = param-12; - if (value0!=0.f) - { - bool springEnabled = true; - genCons->setStiffness(springIndex,value0); - genCons->setDamping(springIndex,value1); - genCons->enableSpring(springIndex,springEnabled); - genCons->setEquilibriumPoint(springIndex); - } else - { - bool springEnabled = false; - genCons->enableSpring(springIndex,springEnabled); - } - break; - } - - default: - { - } - }; - break; - }; - case PHY_CONE_TWIST_CONSTRAINT: - { - switch (param) - { - case 3: case 4: case 5: - { - //param = 3,4,5 are constraint limits, high limit values - btConeTwistConstraint* coneTwist = (btConeTwistConstraint*)typedConstraint; - if (value1<0.0f) - coneTwist->setLimit(param,btScalar(BT_LARGE_FLOAT)); - else - coneTwist->setLimit(param,value1); - break; - } - default: - { - } - }; - break; - }; - case PHY_ANGULAR_CONSTRAINT: - case PHY_LINEHINGE_CONSTRAINT: - { - switch (param) - { - case 3: - { - //param = 3 is a constraint limit, with low/high limit value - btHingeConstraint* hingeCons = (btHingeConstraint*)typedConstraint; - hingeCons->setLimit(value0,value1); - break; - } - default: - { - } - } - break; - }; - default: - { - }; - }; + // First delete scene, then dispatcher, because pairs have to release manifolds on the dispatcher. + m_dynamicsWorld.reset(nullptr); } -btTypedConstraint* CcdPhysicsEnvironment::GetConstraintById(int constraintId) +btTypedConstraint *CcdPhysicsEnvironment::GetConstraintById(int constraintId) { // For soft body constraints - if (constraintId == 0) - return NULL; + if (constraintId == 0) { + return nullptr; + } int numConstraints = m_dynamicsWorld->getNumConstraints(); int i; - for (i=0;igetConstraint(i); - if (constraint->getUserConstraintId()==constraintId) - { + for (i = 0; i < numConstraints; i++) { + btTypedConstraint *constraint = m_dynamicsWorld->getConstraint(i); + if (constraint->getUserConstraintId() == constraintId) { return constraint; } } - return 0; + return nullptr; } - -void CcdPhysicsEnvironment::AddSensor(PHY_IPhysicsController* ctrl) +void CcdPhysicsEnvironment::AddSensor(PHY_IPhysicsController *ctrl) { - CcdPhysicsController* ctrl1 = (CcdPhysicsController* )ctrl; + CcdPhysicsController *ctrl1 = (CcdPhysicsController *)ctrl; AddCcdPhysicsController(ctrl1); } -bool CcdPhysicsEnvironment::RemoveCollisionCallback(PHY_IPhysicsController* ctrl) +bool CcdPhysicsEnvironment::RemoveCollisionCallback(PHY_IPhysicsController *ctrl) { - CcdPhysicsController* ccdCtrl = (CcdPhysicsController*)ctrl; + CcdPhysicsController *ccdCtrl = (CcdPhysicsController *)ctrl; return ccdCtrl->Unregister(); } - -void CcdPhysicsEnvironment::RemoveSensor(PHY_IPhysicsController* ctrl) +void CcdPhysicsEnvironment::RemoveSensor(PHY_IPhysicsController *ctrl) { - RemoveCcdPhysicsController((CcdPhysicsController*)ctrl); + RemoveCcdPhysicsController((CcdPhysicsController *)ctrl, true); } -void CcdPhysicsEnvironment::AddTouchCallback(int response_class, PHY_ResponseCallback callback, void *user) +void CcdPhysicsEnvironment::AddCollisionCallback(int response_class, PHY_ResponseCallback callback, void *user) { - /* printf("addTouchCallback\n(response class = %i)\n",response_class); - - //map PHY_ convention into SM_ convention - switch (response_class) - { - case PHY_FH_RESPONSE: - printf("PHY_FH_RESPONSE\n"); - break; - case PHY_SENSOR_RESPONSE: - printf("PHY_SENSOR_RESPONSE\n"); - break; - case PHY_CAMERA_RESPONSE: - printf("PHY_CAMERA_RESPONSE\n"); - break; - case PHY_OBJECT_RESPONSE: - printf("PHY_OBJECT_RESPONSE\n"); - break; - case PHY_STATIC_RESPONSE: - printf("PHY_STATIC_RESPONSE\n"); - break; - default: - assert(0); - return; - } - */ - m_triggerCallbacks[response_class] = callback; m_triggerCallbacksUserPtrs[response_class] = user; - } -bool CcdPhysicsEnvironment::RequestCollisionCallback(PHY_IPhysicsController* ctrl) +bool CcdPhysicsEnvironment::RequestCollisionCallback(PHY_IPhysicsController *ctrl) { - CcdPhysicsController* ccdCtrl = static_cast(ctrl); + CcdPhysicsController *ccdCtrl = static_cast(ctrl); return ccdCtrl->Register(); } -void CcdPhysicsEnvironment::CallbackTriggers() +void CcdPhysicsEnvironment::CallbackTriggers() { - bool draw_contact_points = m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawContactPoints); - - if (!m_triggerCallbacks[PHY_OBJECT_RESPONSE] && !draw_contact_points) + if (!m_triggerCallbacks[PHY_OBJECT_RESPONSE]) { return; + } - //walk over all overlapping pairs, and if one of the involved bodies is registered for trigger callback, perform callback - btDispatcher* dispatcher = m_dynamicsWorld->getDispatcher(); - int numManifolds = dispatcher->getNumManifolds(); - for (int i=0;igetManifoldByIndexInternal(i); - int numContacts = manifold->getNumContacts(); - if (!numContacts) continue; - - const btRigidBody* rb0 = static_cast(manifold->getBody0()); - const btRigidBody* rb1 = static_cast(manifold->getBody1()); - if (draw_contact_points) - { - for (int j=0;jgetContactPoint(j); - m_debugDrawer->drawContactPoint(cp.m_positionWorldOnB, - cp.m_normalWorldOnB, - cp.getDistance(), - cp.getLifeTime(), - color); - } + // Walk over all overlapping pairs, and if one of the involved bodies is registered for trigger callback, perform callback. + btDispatcher *dispatcher = m_dynamicsWorld->getDispatcher(); + for (unsigned int i = 0, numManifolds = dispatcher->getNumManifolds(); i < numManifolds; i++) { + btPersistentManifold *manifold = dispatcher->getManifoldByIndexInternal(i); + if (manifold->getNumContacts() == 0) { + continue; } - //m_internalOwner is set in 'addPhysicsController' - CcdPhysicsController* ctrl0 = static_cast(rb0->getUserPointer()); - CcdPhysicsController* ctrl1 = static_cast(rb1->getUserPointer()); - bool usecallback = false; + const btCollisionObject *col0 = manifold->getBody0(); + const btCollisionObject *col1 = manifold->getBody1(); + CcdPhysicsController *ctrl0 = static_cast(col0->getUserPointer()); + CcdPhysicsController *ctrl1 = static_cast(col1->getUserPointer()); + + bool first; // Test if one of the controller is registered and use collision callback. - if (ctrl0->Registered()) - usecallback = true; + if (ctrl0->Registered()) { + first = true; + } else if (ctrl1->Registered()) { - colliding_ctrl0 = false; - usecallback = true; + first = false; + } + else { + // No controllers registered for collision callbacks. + continue; } - if (usecallback) { - static PHY_CollData coll_data; - const btManifoldPoint &cp = manifold->getContactPoint(0); + const CcdCollData *coll_data = new CcdCollData(manifold); + m_triggerCallbacks[PHY_OBJECT_RESPONSE](m_triggerCallbacksUserPtrs[PHY_OBJECT_RESPONSE], ctrl0, ctrl1, coll_data, first); + } +} + +PHY_CollisionTestResult CcdPhysicsEnvironment::CheckCollision(PHY_IPhysicsController *ctrl0, PHY_IPhysicsController *ctrl1) +{ + PHY_CollisionTestResult result{false, false, nullptr}; - /* Make sure that "point1" is always on the object we report on, and - * "point2" on the other object. Also ensure the normal is oriented - * correctly. */ - btVector3 point1 = colliding_ctrl0 ? cp.m_positionWorldOnA : cp.m_positionWorldOnB; - btVector3 point2 = colliding_ctrl0 ? cp.m_positionWorldOnB : cp.m_positionWorldOnA; - btVector3 normal = colliding_ctrl0 ? -cp.m_normalWorldOnB : cp.m_normalWorldOnB; + btCollisionObject *col0 = static_cast(ctrl0)->GetCollisionObject(); + btCollisionObject *col1 = static_cast(ctrl1)->GetCollisionObject(); - coll_data.m_point1 = MT_Vector3(point1.m_floats); - coll_data.m_point2 = MT_Vector3(point2.m_floats); - coll_data.m_normal = MT_Vector3(normal.m_floats); + if (!col0 || !col1) { + return result; + } - m_triggerCallbacks[PHY_OBJECT_RESPONSE](m_triggerCallbacksUserPtrs[PHY_OBJECT_RESPONSE], - ctrl0, ctrl1, &coll_data); - } - // Bullet does not refresh the manifold contact point for object without contact response - // may need to remove this when a newer Bullet version is integrated - if (!dispatcher->needsResponse(rb0, rb1)) - { - // Refresh algorithm fails sometimes when there is penetration - // (usuall the case with ghost and sensor objects) - // Let's just clear the manifold, in any case, it is recomputed on each frame. - manifold->clearManifold(); //refreshContactPoints(rb0->getCenterOfMassTransform(),rb1->getCenterOfMassTransform()); - } + btBroadphaseProxy *proxy0 = col0->getBroadphaseHandle(); + btBroadphaseProxy *proxy1 = col1->getBroadphaseHandle(); + + btBroadphasePair *pair = m_dynamicsWorld->getPairCache()->findPair(proxy0, proxy1); + + if (!pair) { + return result; + } + + result.collide = true; + + if (pair->m_algorithm) { + btManifoldArray manifoldArray; + pair->m_algorithm->getAllContactManifolds(manifoldArray); + btPersistentManifold *manifold = manifoldArray[0]; + + result.isFirst = (col0 == manifold->getBody0()); + result.collData = new CcdCollData(manifold); } + + return result; } // This call back is called before a pair is added in the cache // Handy to remove objects that must be ignored by sensors -bool CcdOverlapFilterCallBack::needBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const +bool CcdOverlapFilterCallBack::needBroadphaseCollision(btBroadphaseProxy *proxy0, btBroadphaseProxy *proxy1) const { - btCollisionObject *colObj0, *colObj1; - CcdPhysicsController *sensorCtrl, *objCtrl; + btCollisionObject *colObj0 = (btCollisionObject *)proxy0->m_clientObject; + btCollisionObject *colObj1 = (btCollisionObject *)proxy1->m_clientObject; + + if (!colObj0 || !colObj1) { + return false; + } - KX_GameObject *kxObj0 = KX_GameObject::GetClientObject( - (KX_ClientObjectInfo*) - ((CcdPhysicsController*) - (((btCollisionObject*)proxy0->m_clientObject)->getUserPointer())) - ->GetNewClientInfo()); - KX_GameObject *kxObj1 = KX_GameObject::GetClientObject( - (KX_ClientObjectInfo*) - ((CcdPhysicsController*) - (((btCollisionObject*)proxy1->m_clientObject)->getUserPointer())) - ->GetNewClientInfo()); - - // First check the filters. Note that this is called during scene - // conversion, so we can't assume the KX_GameObject instances exist. This - // may make some objects erroneously collide on the first frame, but the - // alternative is to have them erroneously miss. - bool collides; - collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0; - collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask); - if (kxObj0 && kxObj1) { - collides = collides && kxObj0->CheckCollision(kxObj1); - collides = collides && kxObj1->CheckCollision(kxObj0); - } - if (!collides) + CcdPhysicsController *ctrl0 = static_cast(colObj0->getUserPointer()); + CcdPhysicsController *ctrl1 = static_cast(colObj1->getUserPointer()); + + if (!((proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) && + (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask) && + (ctrl0->GetCollisionGroup() & ctrl1->GetCollisionMask()) && + (ctrl1->GetCollisionGroup() & ctrl0->GetCollisionMask()))) { return false; + } + CcdPhysicsController *sensorCtrl, *objCtrl; // additional check for sensor object - if (proxy0->m_collisionFilterGroup & btBroadphaseProxy::SensorTrigger) - { + if (proxy0->m_collisionFilterGroup & btBroadphaseProxy::SensorTrigger) { // this is a sensor object, the other one can't be a sensor object because // they exclude each other in the above test - assert(!(proxy1->m_collisionFilterGroup & btBroadphaseProxy::SensorTrigger)); - colObj0 = (btCollisionObject*)proxy0->m_clientObject; - colObj1 = (btCollisionObject*)proxy1->m_clientObject; + BLI_assert(!(proxy1->m_collisionFilterGroup & btBroadphaseProxy::SensorTrigger)); + sensorCtrl = ctrl0; + objCtrl = ctrl1; } - else if (proxy1->m_collisionFilterGroup & btBroadphaseProxy::SensorTrigger) - { - colObj0 = (btCollisionObject*)proxy1->m_clientObject; - colObj1 = (btCollisionObject*)proxy0->m_clientObject; + else if (proxy1->m_collisionFilterGroup & btBroadphaseProxy::SensorTrigger) { + sensorCtrl = ctrl1; + objCtrl = ctrl0; } - else - { + else { return true; } - if (!colObj0 || !colObj1) - return false; - sensorCtrl = static_cast(colObj0->getUserPointer()); - objCtrl = static_cast(colObj1->getUserPointer()); - if (m_physEnv->m_triggerCallbacks[PHY_BROADPH_RESPONSE]) - { - return m_physEnv->m_triggerCallbacks[PHY_BROADPH_RESPONSE](m_physEnv->m_triggerCallbacksUserPtrs[PHY_BROADPH_RESPONSE], sensorCtrl, objCtrl, 0); + + if (m_physEnv->m_triggerCallbacks[PHY_BROADPH_RESPONSE]) { + return m_physEnv->m_triggerCallbacks[PHY_BROADPH_RESPONSE](m_physEnv->m_triggerCallbacksUserPtrs[PHY_BROADPH_RESPONSE], sensorCtrl, objCtrl, nullptr, false); } return true; } - -#ifdef NEW_BULLET_VEHICLE_SUPPORT - //complex constraint for vehicles -PHY_IVehicle* CcdPhysicsEnvironment::GetVehicleConstraint(int constraintId) +PHY_IVehicle *CcdPhysicsEnvironment::GetVehicleConstraint(int constraintId) { int i; int numVehicles = m_wrapperVehicles.size(); - for (i=0;iGetVehicle()->getUserConstraintId() == constraintId) + for (i = 0; i < numVehicles; i++) { + WrapperVehicle *wrapperVehicle = m_wrapperVehicles[i]; + if (wrapperVehicle->GetVehicle()->getUserConstraintId() == constraintId) { return wrapperVehicle; + } } - return 0; + return nullptr; } -#endif //NEW_BULLET_VEHICLE_SUPPORT - - -PHY_ICharacter* CcdPhysicsEnvironment::GetCharacterController(KX_GameObject *ob) +PHY_ICharacter *CcdPhysicsEnvironment::GetCharacterController(KX_GameObject *ob) { - CcdPhysicsController* controller = (CcdPhysicsController*)ob->GetPhysicsController(); - return (controller) ? dynamic_cast(controller->GetCharacterController()) : NULL; + CcdPhysicsController *controller = (CcdPhysicsController *)ob->GetPhysicsController(); + return (controller) ? static_cast(controller->GetCharacterController()) : nullptr; } -PHY_IPhysicsController* CcdPhysicsEnvironment::CreateSphereController(float radius,const MT_Vector3& position) +PHY_IPhysicsController *CcdPhysicsEnvironment::CreateSphereController(float radius, const mt::vec3& position) { - - CcdConstructionInfo cinfo; - memset(&cinfo, 0, sizeof(cinfo)); /* avoid uninitialized values */ + CcdConstructionInfo cinfo; cinfo.m_collisionShape = new btSphereShape(radius); // memory leak! The shape is not deleted by Bullet and we cannot add it to the KX_Scene.m_shapes list - cinfo.m_MotionState = 0; + cinfo.m_MotionState = nullptr; cinfo.m_physicsEnv = this; // declare this object as Dyamic rather than static!! // The reason as it is designed to detect all type of object, including static object // It would cause static-static message to be printed on the console otherwise cinfo.m_collisionFlags |= btCollisionObject::CF_NO_CONTACT_RESPONSE | btCollisionObject::CF_STATIC_OBJECT; - DefaultMotionState* motionState = new DefaultMotionState(); + DefaultMotionState *motionState = new DefaultMotionState(); cinfo.m_MotionState = motionState; // we will add later the possibility to select the filter from option cinfo.m_collisionFilterMask = CcdConstructionInfo::AllFilter ^ CcdConstructionInfo::SensorFilter; cinfo.m_collisionFilterGroup = CcdConstructionInfo::SensorFilter; cinfo.m_bSensor = true; motionState->m_worldTransform.setIdentity(); - motionState->m_worldTransform.setOrigin(btVector3(position[0],position[1],position[2])); + motionState->m_worldTransform.setOrigin(ToBullet(position)); - CcdPhysicsController* sphereController = new CcdPhysicsController(cinfo); + CcdPhysicsController *sphereController = new CcdPhysicsController(cinfo); return sphereController; } -int findClosestNode(btSoftBody* sb,const btVector3& worldPoint); -int findClosestNode(btSoftBody* sb,const btVector3& worldPoint) +int Ccd_FindClosestNode(btSoftBody *sb, const btVector3& worldPoint) { int node = -1; btSoftBody::tNodeArray& nodes(sb->m_nodes); float maxDistSqr = 1e30f; - for (int n=0;nGetRigidBody() : 0; - btRigidBody* rb1 = c1 ? c1->GetRigidBody() : 0; - - + CcdPhysicsController *c0 = (CcdPhysicsController *)ctrl0; + CcdPhysicsController *c1 = (CcdPhysicsController *)ctrl1; + btRigidBody *rb0 = c0 ? c0->GetRigidBody() : nullptr; + btRigidBody *rb1 = c1 ? c1->GetRigidBody() : nullptr; bool rb0static = rb0 ? rb0->isStaticOrKinematicObject() : true; bool rb1static = rb1 ? rb1->isStaticOrKinematicObject() : true; - btCollisionObject* colObj0 = c0->GetCollisionObject(); - if (!colObj0) - { - return 0; + btCollisionObject *colObj0 = c0->GetCollisionObject(); + if (!colObj0) { + return nullptr; } - btVector3 pivotInA(pivotX,pivotY,pivotZ); - - + btVector3 pivotInA(pivotX, pivotY, pivotZ); //it might be a soft body, let's try - btSoftBody* sb0 = c0 ? c0->GetSoftBody() : 0; - btSoftBody* sb1 = c1 ? c1->GetSoftBody() : 0; - if (sb0 && sb1) - { + btSoftBody *sb0 = c0 ? c0->GetSoftBody() : nullptr; + btSoftBody *sb1 = c1 ? c1->GetSoftBody() : nullptr; + if (sb0 && sb1) { //not between two soft bodies? - return 0; + return nullptr; } - if (sb0) - { + if (sb0) { //either cluster or node attach, let's find closest node first //the soft body doesn't have a 'real' world transform, so get its initial world transform for now btVector3 pivotPointSoftWorld = sb0->m_initialWorldTransform(pivotInA); - int node=findClosestNode(sb0,pivotPointSoftWorld); - if (node >=0) - { - bool clusterconstaint = false; -/* - switch (type) - { - case PHY_LINEHINGE_CONSTRAINT: - { - if (sb0->clusterCount() && rb1) - { - btSoftBody::LJoint::Specs ls; - ls.erp=0.5f; - ls.position=sb0->clusterCom(0); - sb0->appendLinearJoint(ls,rb1); - clusterconstaint = true; - break; - } - } - case PHY_GENERIC_6DOF_CONSTRAINT: - { - if (sb0->clusterCount() && rb1) - { - btSoftBody::AJoint::Specs as; - as.erp = 1; - as.cfm = 1; - as.axis.setValue(axisX,axisY,axisZ); - sb0->appendAngularJoint(as,rb1); - clusterconstaint = true; - break; - } - - break; - } - default: - { - - } - }; - */ - - if (!clusterconstaint) - { - if (rb1) - { - sb0->appendAnchor(node,rb1,disableCollisionBetweenLinkedBodies); - } else - { - sb0->setMass(node,0.f); - } + int node = Ccd_FindClosestNode(sb0, pivotPointSoftWorld); + if (node >= 0) { + if (rb1) { + sb0->appendAnchor(node, rb1, disableCollisionBetweenLinkedBodies); + } + else { + sb0->setMass(node, 0.0f); } - - } - return 0;//can't remove soft body anchors yet + return nullptr;//can't remove soft body anchors yet } - if (sb1) - { + if (sb1) { btVector3 pivotPointAWorld = colObj0->getWorldTransform()(pivotInA); - int node=findClosestNode(sb1,pivotPointAWorld); - if (node >=0) - { - bool clusterconstaint = false; - - /* - switch (type) - { - case PHY_LINEHINGE_CONSTRAINT: - { - if (sb1->clusterCount() && rb0) - { - btSoftBody::LJoint::Specs ls; - ls.erp=0.5f; - ls.position=sb1->clusterCom(0); - sb1->appendLinearJoint(ls,rb0); - clusterconstaint = true; - break; - } - } - case PHY_GENERIC_6DOF_CONSTRAINT: - { - if (sb1->clusterCount() && rb0) - { - btSoftBody::AJoint::Specs as; - as.erp = 1; - as.cfm = 1; - as.axis.setValue(axisX,axisY,axisZ); - sb1->appendAngularJoint(as,rb0); - clusterconstaint = true; - break; - } - - break; - } - default: - { - - - } - };*/ - - - if (!clusterconstaint) - { - if (rb0) - { - sb1->appendAnchor(node,rb0,disableCollisionBetweenLinkedBodies); - } else - { - sb1->setMass(node,0.f); - } + int node = Ccd_FindClosestNode(sb1, pivotPointAWorld); + if (node >= 0) { + if (rb0) { + sb1->appendAnchor(node, rb0, disableCollisionBetweenLinkedBodies); + } + else { + sb1->setMass(node, 0.0f); } - - } - return 0;//can't remove soft body anchors yet + return nullptr;//can't remove soft body anchors yet } - if (rb0static && rb1static) - { + if (rb0static && rb1static) { + return nullptr; + } - return 0; + + if (!rb0) { + return nullptr; } + // If either of the controllers is missing, we can't do anything. + if (!c0 || !c1) { + return nullptr; + } - if (!rb0) - return 0; + btTypedConstraint *con = nullptr; btVector3 pivotInB = rb1 ? rb1->getCenterOfMassTransform().inverse()(rb0->getCenterOfMassTransform()(pivotInA)) : - rb0->getCenterOfMassTransform() * pivotInA; - btVector3 axisInA(axisX,axisY,axisZ); + rb0->getCenterOfMassTransform() * pivotInA; + btVector3 axisInA(axisX, axisY, axisZ); bool angularOnly = false; - switch (type) - { - case PHY_POINT2POINT_CONSTRAINT: + switch (type) { + case PHY_POINT2POINT_CONSTRAINT: { - // If either of the controllers is missing, we can't do anything. - if (!c0 || !c1) return 0; - - btPoint2PointConstraint* p2p = 0; + btPoint2PointConstraint *p2p = nullptr; - if (rb1) - { - p2p = new btPoint2PointConstraint(*rb0, - *rb1,pivotInA,pivotInB); - } else - { - p2p = new btPoint2PointConstraint(*rb0, - pivotInA); + if (rb1) { + p2p = new btPoint2PointConstraint(*rb0, *rb1, pivotInA, pivotInB); + } + else { + p2p = new btPoint2PointConstraint(*rb0, pivotInA); } - c0->addCcdConstraintRef(p2p); - c1->addCcdConstraintRef(p2p); - m_dynamicsWorld->addConstraint(p2p,disableCollisionBetweenLinkedBodies); -// m_constraints.push_back(p2p); - - p2p->setUserConstraintId(gConstraintUid++); - p2p->setUserConstraintType(type); - //64 bit systems can't cast pointer to int. could use size_t instead. - return p2p->getUserConstraintId(); + con = p2p; break; } - case PHY_GENERIC_6DOF_CONSTRAINT: + case PHY_GENERIC_6DOF_CONSTRAINT: { - // If either of the controllers is missing, we can't do anything. - if (!c0 || !c1) return 0; + btGeneric6DofConstraint *genericConstraint = nullptr; - btGeneric6DofConstraint* genericConstraint = 0; - - if (rb1) - { + if (rb1) { btTransform frameInA; btTransform frameInB; - btVector3 axis1(axis1X,axis1Y,axis1Z), axis2(axis2X,axis2Y,axis2Z); - if (axis1.length() == 0.0f) - { - btPlaneSpace1( axisInA, axis1, axis2 ); + btVector3 axis1(axis1X, axis1Y, axis1Z), axis2(axis2X, axis2Y, axis2Z); + if (axis1.length() == 0.0) { + btPlaneSpace1(axisInA, axis1, axis2); } - frameInA.getBasis().setValue( axisInA.x(), axis1.x(), axis2.x(), - axisInA.y(), axis1.y(), axis2.y(), - axisInA.z(), axis1.z(), axis2.z() ); - frameInA.setOrigin( pivotInA ); + frameInA.getBasis().setValue(axisInA.x(), axis1.x(), axis2.x(), + axisInA.y(), axis1.y(), axis2.y(), + axisInA.z(), axis1.z(), axis2.z()); + frameInA.setOrigin(pivotInA); btTransform inv = rb1->getCenterOfMassTransform().inverse(); btTransform globalFrameA = rb0->getCenterOfMassTransform() * frameInA; - frameInB = inv * globalFrameA; + frameInB = inv * globalFrameA; bool useReferenceFrameA = true; genericConstraint = new btGeneric6DofSpringConstraint( - *rb0,*rb1, - frameInA,frameInB,useReferenceFrameA); - - - } else - { - static btRigidBody s_fixedObject2( 0,0,0); + *rb0, *rb1, + frameInA, frameInB, useReferenceFrameA); + } + else { + static btRigidBody s_fixedObject2(0.0f, nullptr, nullptr); btTransform frameInA; btTransform frameInB; btVector3 axis1, axis2; - btPlaneSpace1( axisInA, axis1, axis2 ); + btPlaneSpace1(axisInA, axis1, axis2); - frameInA.getBasis().setValue( axisInA.x(), axis1.x(), axis2.x(), - axisInA.y(), axis1.y(), axis2.y(), - axisInA.z(), axis1.z(), axis2.z() ); + frameInA.getBasis().setValue(axisInA.x(), axis1.x(), axis2.x(), + axisInA.y(), axis1.y(), axis2.y(), + axisInA.z(), axis1.z(), axis2.z()); - frameInA.setOrigin( pivotInA ); + frameInA.setOrigin(pivotInA); ///frameInB in worldspace frameInB = rb0->getCenterOfMassTransform() * frameInA; bool useReferenceFrameA = true; genericConstraint = new btGeneric6DofSpringConstraint( - *rb0,s_fixedObject2, - frameInA,frameInB,useReferenceFrameA); + *rb0, s_fixedObject2, + frameInA, frameInB, useReferenceFrameA); } - if (genericConstraint) - { - //m_constraints.push_back(genericConstraint); - c0->addCcdConstraintRef(genericConstraint); - c1->addCcdConstraintRef(genericConstraint); - m_dynamicsWorld->addConstraint(genericConstraint,disableCollisionBetweenLinkedBodies); - genericConstraint->setUserConstraintId(gConstraintUid++); - genericConstraint->setUserConstraintType(type); - //64 bit systems can't cast pointer to int. could use size_t instead. - return genericConstraint->getUserConstraintId(); - } + con = genericConstraint; break; } - case PHY_CONE_TWIST_CONSTRAINT: + case PHY_CONE_TWIST_CONSTRAINT: { - // If either of the controllers is missing, we can't do anything. - if (!c0 || !c1) return 0; - - btConeTwistConstraint* coneTwistContraint = 0; - + btConeTwistConstraint *coneTwistContraint = nullptr; - if (rb1) - { + if (rb1) { btTransform frameInA; btTransform frameInB; - btVector3 axis1(axis1X,axis1Y,axis1Z), axis2(axis2X,axis2Y,axis2Z); - if (axis1.length() == 0.0f) - { - btPlaneSpace1( axisInA, axis1, axis2 ); + btVector3 axis1(axis1X, axis1Y, axis1Z), axis2(axis2X, axis2Y, axis2Z); + if (axis1.length() == 0.0) { + btPlaneSpace1(axisInA, axis1, axis2); } - frameInA.getBasis().setValue( axisInA.x(), axis1.x(), axis2.x(), - axisInA.y(), axis1.y(), axis2.y(), - axisInA.z(), axis1.z(), axis2.z() ); - frameInA.setOrigin( pivotInA ); + frameInA.getBasis().setValue(axisInA.x(), axis1.x(), axis2.x(), + axisInA.y(), axis1.y(), axis2.y(), + axisInA.z(), axis1.z(), axis2.z()); + frameInA.setOrigin(pivotInA); btTransform inv = rb1->getCenterOfMassTransform().inverse(); btTransform globalFrameA = rb0->getCenterOfMassTransform() * frameInA; - frameInB = inv * globalFrameA; - - coneTwistContraint = new btConeTwistConstraint( *rb0,*rb1, - frameInA,frameInB); - + frameInB = inv * globalFrameA; - } else - { - static btRigidBody s_fixedObject2( 0,0,0); + coneTwistContraint = new btConeTwistConstraint(*rb0, *rb1, + frameInA, frameInB); + } + else { + static btRigidBody s_fixedObject2(0.0f, nullptr, nullptr); btTransform frameInA; btTransform frameInB; btVector3 axis1, axis2; - btPlaneSpace1( axisInA, axis1, axis2 ); + btPlaneSpace1(axisInA, axis1, axis2); - frameInA.getBasis().setValue( axisInA.x(), axis1.x(), axis2.x(), - axisInA.y(), axis1.y(), axis2.y(), - axisInA.z(), axis1.z(), axis2.z() ); + frameInA.getBasis().setValue(axisInA.x(), axis1.x(), axis2.x(), + axisInA.y(), axis1.y(), axis2.y(), + axisInA.z(), axis1.z(), axis2.z()); - frameInA.setOrigin( pivotInA ); + frameInA.setOrigin(pivotInA); ///frameInB in worldspace frameInB = rb0->getCenterOfMassTransform() * frameInA; coneTwistContraint = new btConeTwistConstraint( - *rb0,s_fixedObject2, - frameInA,frameInB); - } - - if (coneTwistContraint) - { - //m_constraints.push_back(genericConstraint); - c0->addCcdConstraintRef(coneTwistContraint); - c1->addCcdConstraintRef(coneTwistContraint); - m_dynamicsWorld->addConstraint(coneTwistContraint,disableCollisionBetweenLinkedBodies); - coneTwistContraint->setUserConstraintId(gConstraintUid++); - coneTwistContraint->setUserConstraintType(type); - //64 bit systems can't cast pointer to int. could use size_t instead. - return coneTwistContraint->getUserConstraintId(); + *rb0, s_fixedObject2, + frameInA, frameInB); } - + con = coneTwistContraint; break; } - case PHY_ANGULAR_CONSTRAINT: - angularOnly = true; - - - case PHY_LINEHINGE_CONSTRAINT: + case PHY_ANGULAR_CONSTRAINT: { - // If either of the controllers is missing, we can't do anything. - if (!c0 || !c1) return 0; + angularOnly = true; - btHingeConstraint* hinge = 0; + } + case PHY_LINEHINGE_CONSTRAINT: + { + btHingeConstraint *hinge = nullptr; - if (rb1) - { + if (rb1) { // We know the orientations so we should use them instead of // having btHingeConstraint fill in the blanks any way it wants to. btTransform frameInA; btTransform frameInB; - btVector3 axis1(axis1X,axis1Y,axis1Z), axis2(axis2X,axis2Y,axis2Z); - if (axis1.length() == 0.0f) - { - btPlaneSpace1( axisInA, axis1, axis2 ); + btVector3 axis1(axis1X, axis1Y, axis1Z), axis2(axis2X, axis2Y, axis2Z); + if (axis1.length() == 0.0f) { + btPlaneSpace1(axisInA, axis1, axis2); } // Internally btHingeConstraint's hinge-axis is z - frameInA.getBasis().setValue( axis1.x(), axis2.x(), axisInA.x(), - axis1.y(), axis2.y(), axisInA.y(), - axis1.z(), axis2.z(), axisInA.z() ); + frameInA.getBasis().setValue(axis1.x(), axis2.x(), axisInA.x(), + axis1.y(), axis2.y(), axisInA.y(), + axis1.z(), axis2.z(), axisInA.z()); - frameInA.setOrigin( pivotInA ); + frameInA.setOrigin(pivotInA); btTransform inv = rb1->getCenterOfMassTransform().inverse(); @@ -2973,87 +2467,82 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl frameInB = inv * globalFrameA; - hinge = new btHingeConstraint(*rb0,*rb1,frameInA,frameInB); - - - } else - { - static btRigidBody s_fixedObject2( 0,0,0); + hinge = new btHingeConstraint(*rb0, *rb1, frameInA, frameInB); + } + else { + static btRigidBody s_fixedObject2(0.0f, nullptr, nullptr); btTransform frameInA; btTransform frameInB; - btVector3 axis1(axis1X,axis1Y,axis1Z), axis2(axis2X,axis2Y,axis2Z); - if (axis1.length() == 0.0f) - { - btPlaneSpace1( axisInA, axis1, axis2 ); + btVector3 axis1(axis1X, axis1Y, axis1Z), axis2(axis2X, axis2Y, axis2Z); + if (axis1.length() == 0.0f) { + btPlaneSpace1(axisInA, axis1, axis2); } // Internally btHingeConstraint's hinge-axis is z - frameInA.getBasis().setValue( axis1.x(), axis2.x(), axisInA.x(), - axis1.y(), axis2.y(), axisInA.y(), - axis1.z(), axis2.z(), axisInA.z() ); - frameInA.setOrigin( pivotInA ); + frameInA.getBasis().setValue(axis1.x(), axis2.x(), axisInA.x(), + axis1.y(), axis2.y(), axisInA.y(), + axis1.z(), axis2.z(), axisInA.z()); + frameInA.setOrigin(pivotInA); frameInB = rb0->getCenterOfMassTransform() * frameInA; hinge = new btHingeConstraint(*rb0, s_fixedObject2, frameInA, frameInB); } hinge->setAngularOnly(angularOnly); - //m_constraints.push_back(hinge); - c0->addCcdConstraintRef(hinge); - c1->addCcdConstraintRef(hinge); - m_dynamicsWorld->addConstraint(hinge,disableCollisionBetweenLinkedBodies); - hinge->setUserConstraintId(gConstraintUid++); - hinge->setUserConstraintType(type); - //64 bit systems can't cast pointer to int. could use size_t instead. - return hinge->getUserConstraintId(); - break; - } -#ifdef NEW_BULLET_VEHICLE_SUPPORT - - case PHY_VEHICLE_CONSTRAINT: - { - btRaycastVehicle::btVehicleTuning* tuning = new btRaycastVehicle::btVehicleTuning(); - btRigidBody* chassis = rb0; - btDefaultVehicleRaycaster* raycaster = new BlenderVehicleRaycaster(m_dynamicsWorld); - btRaycastVehicle* vehicle = new btRaycastVehicle(*tuning,chassis,raycaster); - WrapperVehicle* wrapperVehicle = new WrapperVehicle(vehicle,ctrl0); - m_wrapperVehicles.push_back(wrapperVehicle); - m_dynamicsWorld->addVehicle(vehicle); - vehicle->setUserConstraintId(gConstraintUid++); - vehicle->setUserConstraintType(type); - return vehicle->getUserConstraintId(); + con = hinge; break; - }; -#endif //NEW_BULLET_VEHICLE_SUPPORT - - default: + } + default: { } - }; + } + ; - //btRigidBody& rbA,btRigidBody& rbB, const btVector3& pivotInA,const btVector3& pivotInB + if (!con) { + return nullptr; + } - return 0; + c0->addCcdConstraintRef(con); + c1->addCcdConstraintRef(con); + con->setUserConstraintId(gConstraintUid++); + con->setUserConstraintType(type); + CcdConstraint *constraintData = new CcdConstraint(con, disableCollisionBetweenLinkedBodies); + con->setUserConstraintPtr(constraintData); + m_dynamicsWorld->addConstraint(con, disableCollisionBetweenLinkedBodies); + return constraintData; } +PHY_IVehicle *CcdPhysicsEnvironment::CreateVehicle(PHY_IPhysicsController *ctrl) +{ + const btRaycastVehicle::btVehicleTuning tuning = btRaycastVehicle::btVehicleTuning(); + BlenderVehicleRaycaster *raycaster = new BlenderVehicleRaycaster(m_dynamicsWorld.get()); + btRaycastVehicle *vehicle = new btRaycastVehicle(tuning, ((CcdPhysicsController *)ctrl)->GetRigidBody(), raycaster); + WrapperVehicle *wrapperVehicle = new WrapperVehicle(vehicle, raycaster, ctrl); + m_wrapperVehicles.push_back(wrapperVehicle); + + m_dynamicsWorld->addVehicle(vehicle); + + vehicle->setUserConstraintId(gConstraintUid++); + vehicle->setUserConstraintType(PHY_VEHICLE_CONSTRAINT); + return wrapperVehicle; +} -PHY_IPhysicsController* CcdPhysicsEnvironment::CreateConeController(float coneradius,float coneheight) +PHY_IPhysicsController *CcdPhysicsEnvironment::CreateConeController(float coneradius, float coneheight) { - CcdConstructionInfo cinfo; -//don't memset cinfo: this is C++ and values should be set in the constructor! + CcdConstructionInfo cinfo; // we don't need a CcdShapeConstructionInfo for this shape: // it is simple enough for the standard copy constructor (see CcdPhysicsController::GetReplica) - cinfo.m_collisionShape = new btConeShape(coneradius,coneheight); - cinfo.m_MotionState = 0; + cinfo.m_collisionShape = new btConeShape(coneradius, coneheight); + cinfo.m_MotionState = nullptr; cinfo.m_physicsEnv = this; cinfo.m_collisionFlags |= btCollisionObject::CF_NO_CONTACT_RESPONSE | btCollisionObject::CF_STATIC_OBJECT; - DefaultMotionState* motionState = new DefaultMotionState(); + DefaultMotionState *motionState = new DefaultMotionState(); cinfo.m_MotionState = motionState; // we will add later the possibility to select the filter from option @@ -3063,128 +2552,84 @@ PHY_IPhysicsController* CcdPhysicsEnvironment::CreateConeController(float conera motionState->m_worldTransform.setIdentity(); // motionState->m_worldTransform.setOrigin(btVector3(position[0],position[1],position[2])); - CcdPhysicsController* sphereController = new CcdPhysicsController(cinfo); - + CcdPhysicsController *sphereController = new CcdPhysicsController(cinfo); return sphereController; } -float CcdPhysicsEnvironment::getAppliedImpulse(int constraintid) +float CcdPhysicsEnvironment::getAppliedImpulse(int constraintid) { // For soft body constraints - if (constraintid == 0) + if (constraintid == 0) { return 0.0f; + } int i; int numConstraints = m_dynamicsWorld->getNumConstraints(); - for (i=0;igetConstraint(i); - if (constraint->getUserConstraintId() == constraintid) - { + for (i = 0; i < numConstraints; i++) { + btTypedConstraint *constraint = m_dynamicsWorld->getConstraint(i); + if (constraint->getUserConstraintId() == constraintid) { return constraint->getAppliedImpulse(); } } - return 0.f; + return 0.0f; } -void CcdPhysicsEnvironment::ExportFile(const char* filename) +void CcdPhysicsEnvironment::ExportFile(const std::string& filename) { - btDefaultSerializer* serializer = new btDefaultSerializer(); + btDefaultSerializer *serializer = new btDefaultSerializer(); + for (int i = 0; i < m_dynamicsWorld->getNumCollisionObjects(); i++) { + btCollisionObject *colObj = m_dynamicsWorld->getCollisionObjectArray()[i]; - for (int i=0;igetNumCollisionObjects();i++) - { - - btCollisionObject* colObj = m_dynamicsWorld->getCollisionObjectArray()[i]; - - CcdPhysicsController* controller = static_cast(colObj->getUserPointer()); - if (controller) - { - const char* name = KX_GameObject::GetClientObject((KX_ClientObjectInfo*)controller->GetNewClientInfo())->GetName(); - if (name) - { - serializer->registerNameForPointer(colObj,name); + CcdPhysicsController *controller = static_cast(colObj->getUserPointer()); + if (controller) { + const std::string name = KX_GameObject::GetClientObject((KX_ClientObjectInfo *)controller->GetNewClientInfo())->GetName(); + if (!name.empty()) { + serializer->registerNameForPointer(colObj, name.c_str()); } } } m_dynamicsWorld->serialize(serializer); - FILE* file = fopen(filename,"wb"); - if (file) - { - fwrite(serializer->getBufferPointer(),serializer->getCurrentBufferSize(),1, file); + FILE *file = fopen(filename.c_str(), "wb"); + if (file) { + fwrite(serializer->getBufferPointer(), serializer->getCurrentBufferSize(), 1, file); fclose(file); } } -struct BlenderDebugDraw : public btIDebugDraw +CcdPhysicsEnvironment *CcdPhysicsEnvironment::Create(Scene *blenderscene, bool visualizePhysics) { - BlenderDebugDraw () : - m_debugMode(0) - { - } - - int m_debugMode; - - virtual void drawLine(const btVector3& from,const btVector3& to,const btVector3& color) - { - if (m_debugMode >0) - { - MT_Vector3 kxfrom(from[0],from[1],from[2]); - MT_Vector3 kxto(to[0],to[1],to[2]); - MT_Vector3 kxcolor(color[0],color[1],color[2]); - - KX_RasterizerDrawDebugLine(kxfrom,kxto,kxcolor); - } - } - - virtual void reportErrorWarning(const char* warningString) - { - - } - - virtual void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,float distance,int lifeTime,const btVector3& color) - { - drawLine(PointOnB, PointOnB + normalOnB, color); - drawSphere(PointOnB, 0.1f, color); - } - - virtual void setDebugMode(int debugMode) - { - m_debugMode = debugMode; - } - virtual int getDebugMode() const - { - return m_debugMode; - } - ///todo: find out if Blender can do this - virtual void draw3dText(const btVector3& location,const char* textString) - { - - } + static const PHY_SolverType solverTypeTable[] = { + PHY_SOLVER_SEQUENTIAL, // GAME_SOLVER_SEQUENTIAL + PHY_SOLVER_NNCG, // GAME_SOLVER_NNGC + PHY_SOLVER_MLCP_DANTZIG, // GAME_SOLVER_MLCP_DANTZIG + PHY_SOLVER_MLCP_LEMKE // GAME_SOLVER_MLCP_LEMKE + }; -}; + CcdPhysicsEnvironment *ccdPhysEnv = new CcdPhysicsEnvironment(solverTypeTable[blenderscene->gm.solverType], + (blenderscene->gm.mode & WO_DBVT_CULLING) != 0); -CcdPhysicsEnvironment *CcdPhysicsEnvironment::Create(Scene *blenderscene, bool visualizePhysics) -{ - CcdPhysicsEnvironment* ccdPhysEnv = new CcdPhysicsEnvironment((blenderscene->gm.mode & WO_DBVT_CULLING) != 0); - ccdPhysEnv->SetDebugDrawer(new BlenderDebugDraw()); ccdPhysEnv->SetDeactivationLinearTreshold(blenderscene->gm.lineardeactthreshold); ccdPhysEnv->SetDeactivationAngularTreshold(blenderscene->gm.angulardeactthreshold); ccdPhysEnv->SetDeactivationTime(blenderscene->gm.deactivationtime); - if (visualizePhysics) - ccdPhysEnv->SetDebugMode(btIDebugDraw::DBG_DrawWireframe|btIDebugDraw::DBG_DrawAabb|btIDebugDraw::DBG_DrawContactPoints|btIDebugDraw::DBG_DrawText|btIDebugDraw::DBG_DrawConstraintLimits|btIDebugDraw::DBG_DrawConstraints); + if (visualizePhysics) { + ccdPhysEnv->SetDebugMode(btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawAabb | btIDebugDraw::DBG_DrawContactPoints | + btIDebugDraw::DBG_DrawText | btIDebugDraw::DBG_DrawConstraintLimits | btIDebugDraw::DBG_DrawConstraints); + } return ccdPhysEnv; } -void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject *meshobj, DerivedMesh *dm, KX_Scene *kxscene, PHY_ShapeProps *shapeprops, PHY_MaterialProps *smmaterial, PHY_IMotionState *motionstate, int activeLayerBitInfo, bool isCompoundChild, bool hasCompoundChildren) +void CcdPhysicsEnvironment::ConvertObject(BL_SceneConverter& converter, KX_GameObject *gameobj, RAS_Mesh *meshobj, + KX_Scene *kxscene, PHY_IMotionState *motionstate, + int activeLayerBitInfo, bool isCompoundChild, bool hasCompoundChildren) { - Object* blenderobject = gameobj->GetBlenderObject(); + Object *blenderobject = gameobj->GetBlenderObject(); bool isbulletdyna = (blenderobject->gameflag & OB_DYNAMIC) != 0; bool isbulletsensor = (blenderobject->gameflag & OB_SENSOR) != 0; @@ -3195,103 +2640,122 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject CcdConstructionInfo ci; class CcdShapeConstructionInfo *shapeInfo = new CcdShapeConstructionInfo(); - // get Root Parent of blenderobject - Object *blenderparent = blenderobject->parent; - while (blenderparent && blenderparent->parent) { - blenderparent = blenderparent->parent; + Object *blenderRoot = blenderobject->parent; + Object *blenderCompoundRoot = nullptr; + // Iterate over all parents in the object tree. + { + Object *parentit = blenderobject->parent; + while (parentit) { + // If the parent is valid for compound parent shape, update blenderCompoundRoot. + if ((parentit->gameflag & OB_CHILD) && (blenderobject->gameflag & (OB_COLLISION | OB_DYNAMIC | OB_RIGID_BODY)) && + !(blenderobject->gameflag & OB_SOFT_BODY)) { + blenderCompoundRoot = parentit; + } + // Continue looking for root parent. + blenderRoot = parentit; + + parentit = parentit->parent; + } } - KX_GameObject *parent = NULL; - if (blenderparent) - { - KX_BlenderSceneConverter *converter = (KX_BlenderSceneConverter*)KX_GetActiveEngine()->GetSceneConverter(); - parent = converter->FindGameObject(blenderparent); + KX_GameObject *compoundParent = nullptr; + if (blenderCompoundRoot) { + compoundParent = converter.FindGameObject(blenderCompoundRoot); isbulletsoftbody = false; } - if (!isbulletdyna) - { + KX_GameObject *parentRoot = nullptr; + if (blenderRoot) { + parentRoot = converter.FindGameObject(blenderRoot); + isbulletsoftbody = false; + } + + if (!isbulletdyna) { ci.m_collisionFlags |= btCollisionObject::CF_STATIC_OBJECT; } - if ((blenderobject->gameflag & (OB_GHOST | OB_SENSOR | OB_CHARACTER)) != 0) - { + if ((blenderobject->gameflag & (OB_GHOST | OB_SENSOR | OB_CHARACTER)) != 0) { ci.m_collisionFlags |= btCollisionObject::CF_NO_CONTACT_RESPONSE; } + ci.m_collisionGroup = blenderobject->col_group; + ci.m_collisionMask = blenderobject->col_mask; + ci.m_MotionState = motionstate; - ci.m_gravity = btVector3(0,0,0); - ci.m_linearFactor = btVector3(((blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_X_AXIS) !=0)? 0 : 1, - ((blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_Y_AXIS) !=0)? 0 : 1, - ((blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_Z_AXIS) !=0)? 0 : 1); - ci.m_angularFactor = btVector3(((blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_X_ROT_AXIS) !=0)? 0 : 1, - ((blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_Y_ROT_AXIS) !=0)? 0 : 1, - ((blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_Z_ROT_AXIS) !=0)? 0 : 1); - ci.m_localInertiaTensor =btVector3(0,0,0); - ci.m_mass = isbulletdyna ? shapeprops->m_mass : 0.f; - ci.m_clamp_vel_min = shapeprops->m_clamp_vel_min; - ci.m_clamp_vel_max = shapeprops->m_clamp_vel_max; - ci.m_clamp_angvel_min = shapeprops->m_clamp_angvel_min; - ci.m_clamp_angvel_max = shapeprops->m_clamp_angvel_max; - ci.m_stepHeight = isbulletchar ? shapeprops->m_step_height : 0.f; - ci.m_jumpSpeed = isbulletchar ? shapeprops->m_jump_speed : 0.f; - ci.m_fallSpeed = isbulletchar ? shapeprops->m_fall_speed : 0.f; - ci.m_maxJumps = isbulletchar ? shapeprops->m_max_jumps : 0; + ci.m_gravity = btVector3(0.0f, 0.0f, 0.0f); + ci.m_linearFactor = btVector3(((blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_X_AXIS) != 0) ? 0.0f : 1.0f, + ((blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_Y_AXIS) != 0) ? 0.0f : 1.0f, + ((blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_Z_AXIS) != 0) ? 0.0f : 1.0f); + ci.m_angularFactor = btVector3(((blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_X_ROT_AXIS) != 0) ? 0.0f : 1.0f, + ((blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_Y_ROT_AXIS) != 0) ? 0.0f : 1.0f, + ((blenderobject->gameflag2 & OB_LOCK_RIGID_BODY_Z_ROT_AXIS) != 0) ? 0.0f : 1.0f); + ci.m_localInertiaTensor = btVector3(0.0f, 0.0f, 0.0f); + ci.m_mass = isbulletdyna ? blenderobject->mass : 0.0f; + ci.m_clamp_vel_min = blenderobject->min_vel; + ci.m_clamp_vel_max = blenderobject->max_vel; + ci.m_clamp_angvel_min = blenderobject->min_angvel; + ci.m_clamp_angvel_max = blenderobject->max_angvel; + ci.m_stepHeight = isbulletchar ? blenderobject->step_height : 0.0f; + ci.m_jumpSpeed = isbulletchar ? blenderobject->jump_speed : 0.0f; + ci.m_fallSpeed = isbulletchar ? blenderobject->fall_speed : 0.0f; + ci.m_maxSlope = isbulletchar ? blenderobject->max_slope : 0.0f; + ci.m_maxJumps = isbulletchar ? blenderobject->max_jumps : 0; //mmm, for now, take this for the size of the dynamicobject // Blender uses inertia for radius of dynamic object shapeInfo->m_radius = ci.m_radius = blenderobject->inertia; useGimpact = ((isbulletdyna || isbulletsensor) && !isbulletsoftbody); - if (isbulletsoftbody) - { - if (blenderobject->bsoft) - { + if (isbulletsoftbody) { + if (blenderobject->bsoft) { ci.m_margin = blenderobject->bsoft->margin; ci.m_gamesoftFlag = blenderobject->bsoft->flag; + ci.m_softBendingDistance = blenderobject->bsoft->bending_dist; + ci.m_soft_linStiff = blenderobject->bsoft->linStiff; - ci.m_soft_angStiff = blenderobject->bsoft->angStiff; /* angular stiffness 0..1 */ - ci.m_soft_volume = blenderobject->bsoft->volume; /* volume preservation 0..1 */ + ci.m_soft_angStiff = blenderobject->bsoft->angStiff; // angular stiffness 0..1 + ci.m_soft_volume = blenderobject->bsoft->volume; // volume preservation 0..1 - ci.m_soft_viterations = blenderobject->bsoft->viterations; /* Velocities solver iterations */ - ci.m_soft_piterations = blenderobject->bsoft->piterations; /* Positions solver iterations */ - ci.m_soft_diterations = blenderobject->bsoft->diterations; /* Drift solver iterations */ - ci.m_soft_citerations = blenderobject->bsoft->citerations; /* Cluster solver iterations */ + ci.m_soft_viterations = blenderobject->bsoft->viterations; // Velocities solver iterations + ci.m_soft_piterations = blenderobject->bsoft->piterations; // Positions solver iterations + ci.m_soft_diterations = blenderobject->bsoft->diterations; // Drift solver iterations + ci.m_soft_citerations = blenderobject->bsoft->citerations; // Cluster solver iterations - ci.m_soft_kSRHR_CL = blenderobject->bsoft->kSRHR_CL; /* Soft vs rigid hardness [0,1] (cluster only) */ - ci.m_soft_kSKHR_CL = blenderobject->bsoft->kSKHR_CL; /* Soft vs kinetic hardness [0,1] (cluster only) */ - ci.m_soft_kSSHR_CL = blenderobject->bsoft->kSSHR_CL; /* Soft vs soft hardness [0,1] (cluster only) */ - ci.m_soft_kSR_SPLT_CL = blenderobject->bsoft->kSR_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ + ci.m_soft_kSRHR_CL = blenderobject->bsoft->kSRHR_CL; // Soft vs rigid hardness [0,1] (cluster only) + ci.m_soft_kSKHR_CL = blenderobject->bsoft->kSKHR_CL; // Soft vs kinetic hardness [0,1] (cluster only) + ci.m_soft_kSSHR_CL = blenderobject->bsoft->kSSHR_CL; // Soft vs soft hardness [0,1] (cluster only) + ci.m_soft_kSR_SPLT_CL = blenderobject->bsoft->kSR_SPLT_CL; // Soft vs rigid impulse split [0,1] (cluster only) - ci.m_soft_kSK_SPLT_CL = blenderobject->bsoft->kSK_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ - ci.m_soft_kSS_SPLT_CL = blenderobject->bsoft->kSS_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */ - ci.m_soft_kVCF = blenderobject->bsoft->kVCF; /* Velocities correction factor (Baumgarte) */ - ci.m_soft_kDP = blenderobject->bsoft->kDP; /* Damping coefficient [0,1] */ + ci.m_soft_kSK_SPLT_CL = blenderobject->bsoft->kSK_SPLT_CL; // Soft vs rigid impulse split [0,1] (cluster only) + ci.m_soft_kSS_SPLT_CL = blenderobject->bsoft->kSS_SPLT_CL; // Soft vs rigid impulse split [0,1] (cluster only) + ci.m_soft_kVCF = blenderobject->bsoft->kVCF; // Velocities correction factor (Baumgarte) + ci.m_soft_kDP = blenderobject->bsoft->kDP; // Damping coefficient [0,1] - ci.m_soft_kDG = blenderobject->bsoft->kDG; /* Drag coefficient [0,+inf] */ - ci.m_soft_kLF = blenderobject->bsoft->kLF; /* Lift coefficient [0,+inf] */ - ci.m_soft_kPR = blenderobject->bsoft->kPR; /* Pressure coefficient [-inf,+inf] */ - ci.m_soft_kVC = blenderobject->bsoft->kVC; /* Volume conversation coefficient [0,+inf] */ + ci.m_soft_kDG = blenderobject->bsoft->kDG; // Drag coefficient [0,+inf] + ci.m_soft_kLF = blenderobject->bsoft->kLF; // Lift coefficient [0,+inf] + ci.m_soft_kPR = blenderobject->bsoft->kPR; // Pressure coefficient [-inf,+inf] + ci.m_soft_kVC = blenderobject->bsoft->kVC; // Volume conversation coefficient [0,+inf] - ci.m_soft_kDF = blenderobject->bsoft->kDF; /* Dynamic friction coefficient [0,1] */ - ci.m_soft_kMT = blenderobject->bsoft->kMT; /* Pose matching coefficient [0,1] */ - ci.m_soft_kCHR = blenderobject->bsoft->kCHR; /* Rigid contacts hardness [0,1] */ - ci.m_soft_kKHR = blenderobject->bsoft->kKHR; /* Kinetic contacts hardness [0,1] */ + ci.m_soft_kDF = blenderobject->bsoft->kDF; // Dynamic friction coefficient [0,1] + ci.m_soft_kMT = blenderobject->bsoft->kMT; // Pose matching coefficient [0,1] + ci.m_soft_kCHR = blenderobject->bsoft->kCHR; // Rigid contacts hardness [0,1] + ci.m_soft_kKHR = blenderobject->bsoft->kKHR; // Kinetic contacts hardness [0,1] - ci.m_soft_kSHR = blenderobject->bsoft->kSHR; /* Soft contacts hardness [0,1] */ - ci.m_soft_kAHR = blenderobject->bsoft->kAHR; /* Anchors hardness [0,1] */ - ci.m_soft_collisionflags = blenderobject->bsoft->collisionflags; /* Vertex/Face or Signed Distance Field(SDF) or Clusters, Soft versus Soft or Rigid */ - ci.m_soft_numclusteriterations = blenderobject->bsoft->numclusteriterations; /* number of iterations to refine collision clusters*/ + ci.m_soft_kSHR = blenderobject->bsoft->kSHR; // Soft contacts hardness [0,1] + ci.m_soft_kAHR = blenderobject->bsoft->kAHR; // Anchors hardness [0,1] + ci.m_soft_collisionflags = blenderobject->bsoft->collisionflags; // Vertex/Face or Signed Distance Field(SDF) or Clusters, Soft versus Soft or Rigid + ci.m_soft_numclusteriterations = blenderobject->bsoft->numclusteriterations; // number of iterations to refine collision clusters } - else - { - ci.m_margin = 0.f; + else { + ci.m_margin = 0.0f; ci.m_gamesoftFlag = OB_BSB_BENDING_CONSTRAINTS | OB_BSB_SHAPE_MATCHING | OB_BSB_AERO_VPOINT; + ci.m_softBendingDistance = 2; + ci.m_soft_linStiff = 0.5f; - ci.m_soft_angStiff = 1.f; /* angular stiffness 0..1 */ - ci.m_soft_volume = 1.f; /* volume preservation 0..1 */ + ci.m_soft_angStiff = 1.0f; // angular stiffness 0..1 + ci.m_soft_volume = 1.0f; // volume preservation 0..1 ci.m_soft_viterations = 0; ci.m_soft_piterations = 1; @@ -3299,7 +2763,7 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject ci.m_soft_citerations = 4; ci.m_soft_kSRHR_CL = 0.1f; - ci.m_soft_kSKHR_CL = 1.f; + ci.m_soft_kSKHR_CL = 1.0f; ci.m_soft_kSSHR_CL = 0.5f; ci.m_soft_kSR_SPLT_CL = 0.5f; @@ -3318,51 +2782,48 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject ci.m_soft_kCHR = 1.0f; ci.m_soft_kKHR = 0.1f; - ci.m_soft_kSHR = 1.f; + ci.m_soft_kSHR = 1.0f; ci.m_soft_kAHR = 0.7f; ci.m_soft_collisionflags = OB_BSB_COL_SDF_RS + OB_BSB_COL_VF_SS; ci.m_soft_numclusteriterations = 16; } } - else - { + else { ci.m_margin = blenderobject->margin; } - ci.m_localInertiaTensor = btVector3(ci.m_mass/3.f,ci.m_mass/3.f,ci.m_mass/3.f); + ci.m_localInertiaTensor = btVector3(ci.m_mass / 3.0f, ci.m_mass / 3.0f, ci.m_mass / 3.0f); - btCollisionShape* bm = 0; + btCollisionShape *bm = nullptr; char bounds = isbulletdyna ? OB_BOUND_SPHERE : OB_BOUND_TRIANGLE_MESH; - if (!(blenderobject->gameflag & OB_BOUNDS)) - { - if (blenderobject->gameflag & OB_SOFT_BODY) + if (!(blenderobject->gameflag & OB_BOUNDS)) { + if (blenderobject->gameflag & OB_SOFT_BODY) { bounds = OB_BOUND_TRIANGLE_MESH; - else if (blenderobject->gameflag & OB_CHARACTER) + } + else if (blenderobject->gameflag & OB_CHARACTER) { bounds = OB_BOUND_SPHERE; + } } - else - { + else { if (ELEM(blenderobject->collision_boundtype, OB_BOUND_CONVEX_HULL, OB_BOUND_TRIANGLE_MESH) - && blenderobject->type != OB_MESH) - { + && blenderobject->type != OB_MESH) { // Can't use triangle mesh or convex hull on a non-mesh object, fall-back to sphere bounds = OB_BOUND_SPHERE; } - else + else { bounds = blenderobject->collision_boundtype; + } } // Get bounds information float bounds_center[3], bounds_extends[3]; - BoundBox *bb= BKE_object_boundbox_get(blenderobject); - if (bb==NULL) - { + BoundBox *bb = BKE_object_boundbox_get(blenderobject); + if (bb == nullptr) { bounds_center[0] = bounds_center[1] = bounds_center[2] = 0.0f; bounds_extends[0] = bounds_extends[1] = bounds_extends[2] = 1.0f; } - else - { + else { bounds_extends[0] = 0.5f * fabsf(bb->vec[0][0] - bb->vec[4][0]); bounds_extends[1] = 0.5f * fabsf(bb->vec[0][1] - bb->vec[2][1]); bounds_extends[2] = 0.5f * fabsf(bb->vec[0][2] - bb->vec[1][2]); @@ -3372,95 +2833,96 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject bounds_center[2] = 0.5f * (bb->vec[0][2] + bb->vec[1][2]); } - switch (bounds) - { - case OB_BOUND_SPHERE: + switch (bounds) { + case OB_BOUND_SPHERE: { - //float radius = objprop->m_radius; - //btVector3 inertiaHalfExtents ( - // radius, - // radius, - // radius); - - //blender doesn't support multisphere, but for testing: - - //bm = new MultiSphereShape(inertiaHalfExtents,,&trans.getOrigin(),&radius,1); shapeInfo->m_shapeType = PHY_SHAPE_SPHERE; - // XXX We calculated the radius but didn't use it? - // objprop.m_boundobject.c.m_radius = MT_max(bb.m_extends[0], MT_max(bb.m_extends[1], bb.m_extends[2])); bm = shapeInfo->CreateBulletShape(ci.m_margin); break; - }; - case OB_BOUND_BOX: + } + case OB_BOUND_BOX: { shapeInfo->m_halfExtend.setValue( - 2.f * bounds_extends[0], - 2.f * bounds_extends[1], - 2.f * bounds_extends[2]); + 2.0f * bounds_extends[0], + 2.0f * bounds_extends[1], + 2.0f * bounds_extends[2]); shapeInfo->m_halfExtend /= 2.0f; shapeInfo->m_halfExtend = shapeInfo->m_halfExtend.absolute(); shapeInfo->m_shapeType = PHY_SHAPE_BOX; bm = shapeInfo->CreateBulletShape(ci.m_margin); break; - }; - case OB_BOUND_CYLINDER: + } + case OB_BOUND_CYLINDER: { - float radius = MT_max(bounds_extends[0], bounds_extends[1]); + float radius = std::max(bounds_extends[0], bounds_extends[1]); shapeInfo->m_halfExtend.setValue( radius, radius, bounds_extends[2] - ); + ); shapeInfo->m_shapeType = PHY_SHAPE_CYLINDER; bm = shapeInfo->CreateBulletShape(ci.m_margin); break; } - case OB_BOUND_CONE: + case OB_BOUND_CONE: { - shapeInfo->m_radius = MT_max(bounds_extends[0], bounds_extends[1]); - shapeInfo->m_height = 2.f * bounds_extends[2]; + shapeInfo->m_radius = std::max(bounds_extends[0], bounds_extends[1]); + shapeInfo->m_height = 2.0f * bounds_extends[2]; shapeInfo->m_shapeType = PHY_SHAPE_CONE; bm = shapeInfo->CreateBulletShape(ci.m_margin); break; } - case OB_BOUND_CONVEX_HULL: + case OB_BOUND_CONVEX_HULL: { - shapeInfo->SetMesh(meshobj, dm,true); + // Convex shapes can be shared, check first if we already have a shape on that mesh. + CcdShapeConstructionInfo *sharedShapeInfo = CcdShapeConstructionInfo::FindMesh(meshobj, gameobj->GetDeformer(), PHY_SHAPE_POLYTOPE); + if (sharedShapeInfo) { + shapeInfo->Release(); + shapeInfo = sharedShapeInfo; + shapeInfo->AddRef(); + } + else { + shapeInfo->m_shapeType = PHY_SHAPE_POLYTOPE; + // Update from deformer or mesh. + shapeInfo->UpdateMesh(gameobj, nullptr); + } + bm = shapeInfo->CreateBulletShape(ci.m_margin); break; } - case OB_BOUND_CAPSULE: + case OB_BOUND_CAPSULE: { - shapeInfo->m_radius = MT_max(bounds_extends[0], bounds_extends[1]); - shapeInfo->m_height = 2.f * (bounds_extends[2] - shapeInfo->m_radius); - if (shapeInfo->m_height < 0.f) - shapeInfo->m_height = 0.f; + shapeInfo->m_radius = std::max(bounds_extends[0], bounds_extends[1]); + shapeInfo->m_height = 2.0f * (bounds_extends[2] - shapeInfo->m_radius); + if (shapeInfo->m_height < 0.0f) { + shapeInfo->m_height = 0.0f; + } shapeInfo->m_shapeType = PHY_SHAPE_CAPSULE; bm = shapeInfo->CreateBulletShape(ci.m_margin); break; } - case OB_BOUND_TRIANGLE_MESH: + case OB_BOUND_TRIANGLE_MESH: { - // mesh shapes can be shared, check first if we already have a shape on that mesh - class CcdShapeConstructionInfo *sharedShapeInfo = CcdShapeConstructionInfo::FindMesh(meshobj, dm, false); - if (sharedShapeInfo != NULL) - { + // Mesh shapes can be shared, check first if we already have a shape on that mesh. + CcdShapeConstructionInfo *sharedShapeInfo = CcdShapeConstructionInfo::FindMesh(meshobj, gameobj->GetDeformer(), PHY_SHAPE_MESH); + if (sharedShapeInfo) { shapeInfo->Release(); shapeInfo = sharedShapeInfo; shapeInfo->AddRef(); - } else - { - shapeInfo->SetMesh(meshobj, dm, false); + } + else { + shapeInfo->m_shapeType = PHY_SHAPE_MESH; + // Update from deformer or mesh. + shapeInfo->UpdateMesh(gameobj, nullptr); } // Soft bodies can benefit from welding, don't do it on non-soft bodies - if (isbulletsoftbody) - { + if (isbulletsoftbody) { // disable welding: it doesn't bring any additional stability and it breaks the relation between soft body collision shape and graphic mesh // shapeInfo->setVertexWeldingThreshold1((blenderobject->bsoft) ? blenderobject->bsoft->welding ? 0.f); - shapeInfo->setVertexWeldingThreshold1(0.f); //todo: expose this to the UI + shapeInfo->setVertexWeldingThreshold1(0.0f); //todo: expose this to the UI } bm = shapeInfo->CreateBulletShape(ci.m_margin, useGimpact, !isbulletsoftbody); @@ -3469,148 +2931,134 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject break; } + case OB_BOUND_EMPTY: + { + shapeInfo->m_shapeType = PHY_SHAPE_EMPTY; + bm = shapeInfo->CreateBulletShape(ci.m_margin); + break; + } } - -// ci.m_localInertiaTensor.setValue(0.1f,0.1f,0.1f); - - if (!bm) - { + if (!bm) { delete motionstate; shapeInfo->Release(); return; } - //bm->setMargin(ci.m_margin); - - - if (isCompoundChild) - { - //find parent, compound shape and add to it - //take relative transform into account! - CcdPhysicsController* parentCtrl = (CcdPhysicsController*)parent->GetPhysicsController(); - assert(parentCtrl); - - // only makes compound shape if parent has a physics controller (i.e not an empty, etc) - if (parentCtrl) { - CcdShapeConstructionInfo* parentShapeInfo = parentCtrl->GetShapeInfo(); - btRigidBody* rigidbody = parentCtrl->GetRigidBody(); - btCollisionShape* colShape = rigidbody->getCollisionShape(); - assert(colShape->isCompound()); - btCompoundShape* compoundShape = (btCompoundShape*)colShape; - - // compute the local transform from parent, this may include several node in the chain - SG_Node* gameNode = gameobj->GetSGNode(); - SG_Node* parentNode = parent->GetSGNode(); - // relative transform - MT_Vector3 parentScale = parentNode->GetWorldScaling(); - parentScale[0] = MT_Scalar(1.0f)/parentScale[0]; - parentScale[1] = MT_Scalar(1.0f)/parentScale[1]; - parentScale[2] = MT_Scalar(1.0f)/parentScale[2]; - MT_Vector3 relativeScale = gameNode->GetWorldScaling() * parentScale; - MT_Matrix3x3 parentInvRot = parentNode->GetWorldOrientation().transposed(); - MT_Vector3 relativePos = parentInvRot*((gameNode->GetWorldPosition()-parentNode->GetWorldPosition())*parentScale); - MT_Matrix3x3 relativeRot = parentInvRot*gameNode->GetWorldOrientation(); - - shapeInfo->m_childScale.setValue(relativeScale[0],relativeScale[1],relativeScale[2]); - bm->setLocalScaling(shapeInfo->m_childScale); - shapeInfo->m_childTrans.getOrigin().setValue(relativePos[0],relativePos[1],relativePos[2]); - float rot[12]; - relativeRot.getValue(rot); - shapeInfo->m_childTrans.getBasis().setFromOpenGLSubMatrix(rot); - - parentShapeInfo->AddShape(shapeInfo); - compoundShape->addChildShape(shapeInfo->m_childTrans,bm); - //do some recalc? - //recalc inertia for rigidbody - if (!rigidbody->isStaticOrKinematicObject()) - { - btVector3 localInertia; - float mass = 1.f/rigidbody->getInvMass(); - compoundShape->calculateLocalInertia(mass,localInertia); - rigidbody->setMassProps(mass,localInertia); - } - shapeInfo->Release(); - // delete motionstate as it's not used - delete motionstate; + if (isCompoundChild) { + //find parent, compound shape and add to it + //take relative transform into account! + CcdPhysicsController *parentCtrl = (CcdPhysicsController *)compoundParent->GetPhysicsController(); + BLI_assert(parentCtrl); + + // only makes compound shape if parent has a physics controller (i.e not an empty, etc) + if (parentCtrl) { + CcdShapeConstructionInfo *parentShapeInfo = parentCtrl->GetShapeInfo(); + btRigidBody *rigidbody = parentCtrl->GetRigidBody(); + btCollisionShape *colShape = rigidbody->getCollisionShape(); + BLI_assert(colShape->isCompound()); + btCompoundShape *compoundShape = (btCompoundShape *)colShape; + + // compute the local transform from parent, this may include several node in the chain + SG_Node *gameNode = gameobj->GetNode(); + SG_Node *parentNode = compoundParent->GetNode(); + // relative transform + mt::vec3 parentScale = parentNode->GetWorldScaling(); + parentScale[0] = 1.0f / parentScale[0]; + parentScale[1] = 1.0f / parentScale[1]; + parentScale[2] = 1.0f / parentScale[2]; + mt::vec3 relativeScale = gameNode->GetWorldScaling() * parentScale; + mt::mat3 parentInvRot = parentNode->GetWorldOrientation().Transpose(); + mt::vec3 relativePos = parentInvRot * ((gameNode->GetWorldPosition() - parentNode->GetWorldPosition()) * parentScale); + mt::mat3 relativeRot = parentInvRot * gameNode->GetWorldOrientation(); + + shapeInfo->m_childScale = ToBullet(relativeScale); + bm->setLocalScaling(shapeInfo->m_childScale); + shapeInfo->m_childTrans.setOrigin(ToBullet(relativePos)); + shapeInfo->m_childTrans.setBasis(ToBullet(relativeRot)); + + parentShapeInfo->AddShape(shapeInfo); + compoundShape->addChildShape(shapeInfo->m_childTrans, bm); + + // Recalculate inertia for object owning compound shape. + if (!rigidbody->isStaticOrKinematicObject()) { + btVector3 localInertia; + const float mass = 1.0f / rigidbody->getInvMass(); + compoundShape->calculateLocalInertia(mass, localInertia); + rigidbody->setMassProps(mass, localInertia * parentCtrl->GetInertiaFactor()); } - return; - } - - if (hasCompoundChildren) - { - // create a compound shape info - CcdShapeConstructionInfo *compoundShapeInfo = new CcdShapeConstructionInfo(); - compoundShapeInfo->m_shapeType = PHY_SHAPE_COMPOUND; - compoundShapeInfo->AddShape(shapeInfo); - // create the compound shape manually as we already have the child shape - btCompoundShape* compoundShape = new btCompoundShape(); - compoundShape->addChildShape(shapeInfo->m_childTrans,bm); - // now replace the shape - bm = compoundShape; shapeInfo->Release(); - shapeInfo = compoundShapeInfo; + // delete motionstate as it's not used + delete motionstate; } + return; + } - - - - + if (hasCompoundChildren) { + // create a compound shape info + CcdShapeConstructionInfo *compoundShapeInfo = new CcdShapeConstructionInfo(); + compoundShapeInfo->m_shapeType = PHY_SHAPE_COMPOUND; + compoundShapeInfo->AddShape(shapeInfo); + // create the compound shape manually as we already have the child shape + btCompoundShape *compoundShape = new btCompoundShape(); + compoundShape->addChildShape(shapeInfo->m_childTrans, bm); + // now replace the shape + bm = compoundShape; + shapeInfo->Release(); + shapeInfo = compoundShapeInfo; + } #ifdef TEST_SIMD_HULL - if (bm->IsPolyhedral()) - { - PolyhedralConvexShape* polyhedron = static_cast(bm); - if (!polyhedron->m_optionalHull) - { + if (bm->IsPolyhedral()) { + PolyhedralConvexShape *polyhedron = static_cast(bm); + if (!polyhedron->m_optionalHull) { //first convert vertices in 'Point3' format int numPoints = polyhedron->GetNumVertices(); - Point3* points = new Point3[numPoints+1]; + Point3 *points = new Point3[numPoints + 1]; //first 4 points should not be co-planar, so add central point to satisfy MakeHull - points[0] = Point3(0.f,0.f,0.f); + points[0] = Point3(0.0f, 0.0f, 0.0f); btVector3 vertex; - for (int p=0;pGetVertex(p,vertex); - points[p+1] = Point3(vertex.getX(),vertex.getY(),vertex.getZ()); + for (int p = 0; p < numPoints; p++) { + polyhedron->GetVertex(p, vertex); + points[p + 1] = Point3(vertex.getX(), vertex.getY(), vertex.getZ()); } - Hull* hull = Hull::MakeHull(numPoints+1,points); + Hull *hull = Hull::MakeHull(numPoints + 1, points); polyhedron->m_optionalHull = hull; } - } #endif //TEST_SIMD_HULL ci.m_collisionShape = bm; ci.m_shapeInfo = shapeInfo; - ci.m_friction = smmaterial->m_friction;//tweak the friction a bit, so the default 0.5 works nice - ci.m_restitution = smmaterial->m_restitution; + ci.m_friction = blenderobject->friction; + ci.m_rollingFriction = blenderobject->rolling_friction; + ci.m_restitution = blenderobject->reflect; ci.m_physicsEnv = this; - // drag / damping is inverted - ci.m_linearDamping = 1.f - shapeprops->m_lin_drag; - ci.m_angularDamping = 1.f - shapeprops->m_ang_drag; + ci.m_linearDamping = blenderobject->damping; + ci.m_angularDamping = blenderobject->rdamping; //need a bit of damping, else system doesn't behave well - ci.m_inertiaFactor = shapeprops->m_inertia/0.4f;//defaults to 0.4, don't want to change behavior - - ci.m_do_anisotropic = shapeprops->m_do_anisotropic; - ci.m_anisotropicFriction.setValue(shapeprops->m_friction_scaling[0],shapeprops->m_friction_scaling[1],shapeprops->m_friction_scaling[2]); + ci.m_inertiaFactor = blenderobject->formfactor / 0.4f;//defaults to 0.4, don't want to change behavior + ci.m_do_anisotropic = (blenderobject->gameflag & OB_ANISOTROPIC_FRICTION); + ci.m_anisotropicFriction = btVector3( + blenderobject->anisotropicFriction[0], + blenderobject->anisotropicFriction[1], + blenderobject->anisotropicFriction[2]); -////////// //do Fh, do Rot Fh - ci.m_do_fh = shapeprops->m_do_fh; - ci.m_do_rot_fh = shapeprops->m_do_rot_fh; - ci.m_fh_damping = smmaterial->m_fh_damping; - ci.m_fh_distance = smmaterial->m_fh_distance; - ci.m_fh_normal = smmaterial->m_fh_normal; - ci.m_fh_spring = smmaterial->m_fh_spring; + ci.m_do_fh = (blenderobject->gameflag & OB_DO_FH); + ci.m_do_rot_fh = (blenderobject->gameflag & OB_ROT_FH); + ci.m_fh_damping = blenderobject->xyfrict; + ci.m_fh_distance = blenderobject->fhdist; + ci.m_fh_normal = (blenderobject->dynamode & OB_FH_NOR); + ci.m_fh_spring = blenderobject->fh; ci.m_collisionFilterGroup = (isbulletsensor) ? short(CcdConstructionInfo::SensorFilter) : - (isbulletdyna) ? short(CcdConstructionInfo::DefaultFilter) : + (isbulletdyna) ? short(CcdConstructionInfo::DynamicFilter) : (isbulletchar) ? short(CcdConstructionInfo::CharacterFilter) : short(CcdConstructionInfo::StaticFilter); ci.m_collisionFilterMask = @@ -3624,124 +3072,70 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject ci.m_bSensor = isbulletsensor; ci.m_bCharacter = isbulletchar; ci.m_bGimpact = useGimpact; - MT_Vector3 scaling = gameobj->NodeGetWorldScaling(); + mt::vec3 scaling = gameobj->NodeGetWorldScaling(); ci.m_scaling.setValue(scaling[0], scaling[1], scaling[2]); - CcdPhysicsController* physicscontroller = new CcdPhysicsController(ci); + CcdPhysicsController *physicscontroller = new CcdPhysicsController(ci); // shapeInfo is reference counted, decrement now as we don't use it anymore - if (shapeInfo) + if (shapeInfo) { shapeInfo->Release(); + } - gameobj->SetPhysicsController(physicscontroller,isbulletdyna); - - // record animation for dynamic objects - if (isbulletdyna) - gameobj->SetRecordAnimation(true); + gameobj->SetPhysicsController(physicscontroller); - physicscontroller->SetNewClientInfo(gameobj->getClientInfo()); + physicscontroller->SetNewClientInfo(&gameobj->GetClientInfo()); // don't add automatically sensor object, they are added when a collision sensor is registered - if (!isbulletsensor && (blenderobject->lay & activeLayerBitInfo) != 0) - { - this->AddCcdPhysicsController( physicscontroller); + if (!isbulletsensor && (blenderobject->lay & activeLayerBitInfo) != 0) { + this->AddCcdPhysicsController(physicscontroller); } { - btRigidBody* rbody = physicscontroller->GetRigidBody(); + btRigidBody *rbody = physicscontroller->GetRigidBody(); - if (rbody) - { + if (rbody) { rbody->setLinearFactor(ci.m_linearFactor); - if (isbulletrigidbody) - { + if (isbulletrigidbody) { rbody->setAngularFactor(ci.m_angularFactor); } - if (rbody && (blenderobject->gameflag & OB_COLLISION_RESPONSE) != 0) - { + if (rbody && (blenderobject->gameflag & OB_COLLISION_RESPONSE) != 0) { rbody->setActivationState(DISABLE_DEACTIVATION); } } } - if (parent) + if (parentRoot) { physicscontroller->SuspendDynamics(false); - - CcdPhysicsController* parentCtrl = parent ? (CcdPhysicsController*)parent->GetPhysicsController() : 0; - physicscontroller->SetParentCtrl(parentCtrl); - - - //Now done directly in ci.m_collisionFlags so that it propagates to replica - //if (objprop->m_ghost) - //{ - // rbody->setCollisionFlags(rbody->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE); - //} - - if (isbulletdyna && !isbulletrigidbody) - { -#if 0 - //setting the inertia could achieve similar results to constraint the up - //but it is prone to instability, so use special 'Angular' constraint - btVector3 inertia = physicscontroller->GetRigidBody()->getInvInertiaDiagLocal(); - inertia.setX(0.f); - inertia.setZ(0.f); - - physicscontroller->GetRigidBody()->setInvInertiaDiagLocal(inertia); - physicscontroller->GetRigidBody()->updateInertiaTensor(); -#endif - - //this->createConstraint(physicscontroller,0,PHY_ANGULAR_CONSTRAINT,0,0,0,0,0,1); - - //Now done directly in ci.m_bRigid so that it propagates to replica - //physicscontroller->GetRigidBody()->setAngularFactor(0.f); - ; } - - STR_String materialname; - if (meshobj) - materialname = meshobj->GetMaterialName(0); - - -#if 0 - ///test for soft bodies - if (objprop->m_softbody && physicscontroller) - { - btSoftBody* softBody = physicscontroller->GetSoftBody(); - if (softBody && gameobj->GetMesh(0))//only the first mesh, if any - { - //should be a mesh then, so add a soft body deformer - KX_SoftBodyDeformer* softbodyDeformer = new KX_SoftBodyDeformer( gameobj->GetMesh(0),(BL_DeformableGameObject*)gameobj); - gameobj->SetDeformer(softbodyDeformer); - } - } -#endif + CcdPhysicsController *parentCtrl = parentRoot ? static_cast(parentRoot->GetPhysicsController()) : nullptr; + physicscontroller->SetParentRoot(parentCtrl); } - void CcdPhysicsEnvironment::SetupObjectConstraints(KX_GameObject *obj_src, KX_GameObject *obj_dest, - bRigidBodyJointConstraint *dat) + bRigidBodyJointConstraint *dat) { PHY_IPhysicsController *phy_src = obj_src->GetPhysicsController(); PHY_IPhysicsController *phy_dest = obj_dest->GetPhysicsController(); PHY_IPhysicsEnvironment *phys_env = obj_src->GetScene()->GetPhysicsEnvironment(); /* We need to pass a full constraint frame, not just axis. */ - MT_Matrix3x3 localCFrame(MT_Vector3(dat->axX,dat->axY,dat->axZ)); - MT_Vector3 axis0 = localCFrame.getColumn(0); - MT_Vector3 axis1 = localCFrame.getColumn(1); - MT_Vector3 axis2 = localCFrame.getColumn(2); - MT_Vector3 scale = obj_src->NodeGetWorldScaling(); + mt::mat3 localCFrame(mt::vec3(dat->axX, dat->axY, dat->axZ)); + mt::vec3 axis0 = localCFrame.GetColumn(0); + mt::vec3 axis1 = localCFrame.GetColumn(1); + mt::vec3 axis2 = localCFrame.GetColumn(2); + mt::vec3 scale = obj_src->NodeGetWorldScaling(); /* Apply not only the pivot and axis values, but also take scale into count * this is not working well, if only one or two axis are scaled, but works ok on * homogeneous scaling. */ - int constraintId = phys_env->CreateConstraint( + PHY_IConstraint *constraint = phys_env->CreateConstraint( phy_src, phy_dest, (PHY_ConstraintType)dat->type, - (float)(dat->pivX * scale.x()), (float)(dat->pivY * scale.y()), (float)(dat->pivZ * scale.z()), - (float)(axis0.x() * scale.x()), (float)(axis0.y() * scale.y()), (float)(axis0.z() * scale.z()), - (float)(axis1.x() * scale.x()), (float)(axis1.y() * scale.y()), (float)(axis1.z() * scale.z()), - (float)(axis2.x() * scale.x()), (float)(axis2.y() * scale.y()), (float)(axis2.z() * scale.z()), + (float)(dat->pivX * scale.x), (float)(dat->pivY * scale.y), (float)(dat->pivZ * scale.z), + (float)(axis0.x * scale.x), (float)(axis0.y * scale.y), (float)(axis0.z * scale.z), + (float)(axis1.x * scale.x), (float)(axis1.y * scale.y), (float)(axis1.z * scale.z), + (float)(axis2.x * scale.x), (float)(axis2.y * scale.y), (float)(axis2.z * scale.z), dat->flag); /* PHY_POINT2POINT_CONSTRAINT = 1, @@ -3751,8 +3145,9 @@ void CcdPhysicsEnvironment::SetupObjectConstraints(KX_GameObject *obj_src, KX_Ga * PHY_VEHICLE_CONSTRAINT = 11, * PHY_GENERIC_6DOF_CONSTRAINT = 12 */ - if (!constraintId) + if (!constraint) { return; + } int dof = 0; int dof_max = 0; @@ -3761,35 +3156,108 @@ void CcdPhysicsEnvironment::SetupObjectConstraints(KX_GameObject *obj_src, KX_Ga switch (dat->type) { /* Set all the limits for generic 6DOF constraint. */ case PHY_GENERIC_6DOF_CONSTRAINT: + { dof_max = 6; dofbit = 1; break; + } /* Set XYZ angular limits for cone twist constraint. */ case PHY_CONE_TWIST_CONSTRAINT: + { dof = 3; dof_max = 6; dofbit = 1 << 3; break; + } /* Set only X angular limits for line hinge and angular constraint. */ case PHY_LINEHINGE_CONSTRAINT: case PHY_ANGULAR_CONSTRAINT: + { dof = 3; dof_max = 4; dofbit = 1 << 3; break; + } default: + { break; + } } for (; dof < dof_max; dof++) { if (dat->flag & dofbit) { - phys_env->SetConstraintParam(constraintId, dof, dat->minLimit[dof], dat->maxLimit[dof]); + constraint->SetParam(dof, dat->minLimit[dof], dat->maxLimit[dof]); } else { /* minLimit > maxLimit means free (no limit) for this degree of freedom. */ - phys_env->SetConstraintParam(constraintId, dof, 1.0f, -1.0f); + constraint->SetParam(dof, 1.0f, -1.0f); } dofbit <<= 1; } + if (dat->flag & CONSTRAINT_USE_BREAKING) { + constraint->SetBreakingThreshold(dat->breaking); + } +} + +CcdCollData::CcdCollData(const btPersistentManifold *manifoldPoint) + :m_manifoldPoint(manifoldPoint) +{ +} + +CcdCollData::~CcdCollData() +{ +} + +unsigned int CcdCollData::GetNumContacts() const +{ + return m_manifoldPoint->getNumContacts(); +} + +mt::vec3 CcdCollData::GetLocalPointA(unsigned int index, bool first) const +{ + const btManifoldPoint& point = m_manifoldPoint->getContactPoint(index); + return ToMt(first ? point.m_localPointA : point.m_localPointB); +} + +mt::vec3 CcdCollData::GetLocalPointB(unsigned int index, bool first) const +{ + const btManifoldPoint& point = m_manifoldPoint->getContactPoint(index); + return ToMt(first ? point.m_localPointB : point.m_localPointA); +} + +mt::vec3 CcdCollData::GetWorldPoint(unsigned int index, bool first) const +{ + const btManifoldPoint& point = m_manifoldPoint->getContactPoint(index); + return ToMt(point.m_positionWorldOnB); +} + +mt::vec3 CcdCollData::GetNormal(unsigned int index, bool first) const +{ + const btManifoldPoint& point = m_manifoldPoint->getContactPoint(index); + return ToMt(first ? -point.m_normalWorldOnB : point.m_normalWorldOnB); +} + +float CcdCollData::GetCombinedFriction(unsigned int index, bool first) const +{ + const btManifoldPoint& point = m_manifoldPoint->getContactPoint(index); + return point.m_combinedFriction; +} + +float CcdCollData::GetCombinedRollingFriction(unsigned int index, bool first) const +{ + const btManifoldPoint& point = m_manifoldPoint->getContactPoint(index); + return point.m_combinedRollingFriction; +} + +float CcdCollData::GetCombinedRestitution(unsigned int index, bool first) const +{ + const btManifoldPoint& point = m_manifoldPoint->getContactPoint(index); + return point.m_combinedRestitution; +} + +float CcdCollData::GetAppliedImpulse(unsigned int index, bool first) const +{ + const btManifoldPoint& point = m_manifoldPoint->getContactPoint(index); + return point.m_appliedImpulse; } diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h index 2c7b009a1f84..66084d156093 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h @@ -1,17 +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. -*/ + 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. + */ /** \file CcdPhysicsEnvironment.h * \ingroup physbullet @@ -23,323 +23,310 @@ subject to the following restrictions: #include "PHY_IPhysicsEnvironment.h" #include "KX_KetsjiEngine.h" +#include "KX_Globals.h" + +#include "CcdPhysicsController.h" #include #include #include -class CcdPhysicsController; -class CcdGraphicController; #include "LinearMath/btVector3.h" #include "LinearMath/btTransform.h" +#include "BulletDynamics/ConstraintSolver/btContactSolverInfo.h" - - +class PHY_IVehicle; +class CcdGraphicController; +class WrapperVehicle; +class CcdOverlapFilterCallBack; +class CcdShapeConstructionInfo; class btTypedConstraint; class btSimulationIslandManager; class btCollisionDispatcher; class btDispatcher; -//#include "btBroadphaseInterface.h" - -//switch on/off new vehicle support -#define NEW_BULLET_VEHICLE_SUPPORT 1 - -#include "BulletDynamics/ConstraintSolver/btContactSolverInfo.h" - -class WrapperVehicle; +class btDefaultCollisionConfiguration; class btPersistentManifold; class btBroadphaseInterface; struct btDbvtBroadphase; +class btGhostPairCallback; class btOverlappingPairCache; class btIDebugDraw; class btDynamicsWorld; -class PHY_IVehicle; -class CcdOverlapFilterCallBack; -class CcdShapeConstructionInfo; +class btSoftRigidDynamicsWorldMt; +class btConstraintSolver; +class btConstraintSolverPoolMt; + +/// Find the id of the closest node to a point in a soft body. +int Ccd_FindClosestNode(btSoftBody *sb, const btVector3& worldPoint); + +class CcdDebugDraw : public btIDebugDraw +{ +private: + int m_debugMode; + +public: + CcdDebugDraw(); + + virtual void drawLine(const btVector3& from, const btVector3& to, const btVector3& color); + virtual void reportErrorWarning(const char *warningString); + virtual void drawContactPoint(const btVector3& PointOnB, const btVector3& normalOnB, float distance, int lifeTime, const btVector3& color); + virtual void setDebugMode(int debugMode); + virtual int getDebugMode() const; + virtual void draw3dText(const btVector3& location, const char *textString); +}; /** CcdPhysicsEnvironment is an experimental mainloop for physics simulation using optional continuous collision detection. * Physics Environment takes care of stepping the simulation and is a container for physics entities. * It stores rigidbodies,constraints, materials etc. * A derived class may be able to 'construct' entities by loading and/or converting */ -class CcdPhysicsEnvironment : public PHY_IPhysicsEnvironment +class CcdPhysicsEnvironment : public PHY_IPhysicsEnvironment, public mt::SimdClassAllocator { friend class CcdOverlapFilterCallBack; - btVector3 m_gravity; - // Removes the constraint and his references from the owner and the target. - void RemoveConstraint(btTypedConstraint *con); + /// Removes the constraint and his references from the owner and the target. + void RemoveConstraint(btTypedConstraint *con, bool free); + /// Remove a vehicle wrapper. + void RemoveVehicle(WrapperVehicle *vehicle, bool free); + /// Remove vehicle wrapper used by a physics controller used as chassis. + void RemoveVehicle(CcdPhysicsController *ctrl, bool free); + /// Restore the constraint if the owner and target are presents. + void RestoreConstraint(CcdPhysicsController *ctrl, btTypedConstraint *con); protected: - btIDebugDraw* m_debugDrawer; - - class btDefaultCollisionConfiguration* m_collisionConfiguration; - class btBroadphaseInterface* m_broadphase; // broadphase for dynamic world - // for culling only - btOverlappingPairCache* m_cullingCache; - struct btDbvtBroadphase* m_cullingTree; // broadphase for culling - - //solver iterations - int m_numIterations; - - //timestep subdivisions - int m_numTimeSubSteps; - - - int m_ccdMode; - int m_solverType; - int m_profileTimings; - bool m_enableSatCollisionDetection; - - float m_deactivationTime; - float m_linearDeactivationThreshold; - float m_angularDeactivationThreshold; - float m_contactBreakingThreshold; - - void ProcessFhSprings(double curTime,float timeStep); - - public: - CcdPhysicsEnvironment(bool useDbvtCulling, btDispatcher* dispatcher=0, btOverlappingPairCache* pairCache=0); - - virtual ~CcdPhysicsEnvironment(); - - ///////////////////////////////////// - //PHY_IPhysicsEnvironment interface - ///////////////////////////////////// - - /// Perform an integration step of duration 'timeStep'. - - virtual void SetDebugDrawer(btIDebugDraw* debugDrawer); - - virtual void SetNumIterations(int numIter); - virtual void SetNumTimeSubSteps(int numTimeSubSteps) - { - m_numTimeSubSteps = numTimeSubSteps; - } - virtual void SetDeactivationTime(float dTime); - virtual void SetDeactivationLinearTreshold(float linTresh); - virtual void SetDeactivationAngularTreshold(float angTresh); - virtual void SetContactBreakingTreshold(float contactBreakingTreshold); - virtual void SetCcdMode(int ccdMode); - virtual void SetSolverType(int solverType); - virtual void SetSolverSorConstant(float sor); - virtual void SetSolverTau(float tau); - virtual void SetSolverDamping(float damping); - virtual void SetLinearAirDamping(float damping); - virtual void SetUseEpa(bool epa); - - virtual int GetNumTimeSubSteps() - { - return m_numTimeSubSteps; - } - - virtual void BeginFrame(); - virtual void EndFrame() {} - /// Perform an integration step of duration 'timeStep'. - virtual bool ProceedDeltaTime(double curTime,float timeStep,float interval); - - /** - * Called by Bullet for every physical simulation (sub)tick. - * Our constructor registers this callback to Bullet, which stores a pointer to 'this' in - * the btDynamicsWorld::getWorldUserInfo() pointer. - */ - static void StaticSimulationSubtickCallback(btDynamicsWorld *world, btScalar timeStep); - void SimulationSubtickCallback(btScalar timeStep); - - virtual void DebugDrawWorld(); -// virtual bool proceedDeltaTimeOneStep(float timeStep); - - virtual void SetFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep) - { - SetNumTimeSubSteps((int)(fixedTimeStep / KX_KetsjiEngine::GetTicRate())); - } - //returns 0.f if no fixed timestep is used - - virtual float GetFixedTimeStep() { return 0.f; } - - virtual void SetDebugMode(int debugMode); - virtual int GetDebugMode()const; - - virtual void SetGravity(float x,float y,float z); - virtual void GetGravity(MT_Vector3& grav); - - - virtual int CreateConstraint(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsController* ctrl2,PHY_ConstraintType type, - float pivotX,float pivotY,float pivotZ, - float axisX,float axisY,float axisZ, - float axis1X=0,float axis1Y=0,float axis1Z=0, - float axis2X=0,float axis2Y=0,float axis2Z=0,int flag=0 - ); - - - //Following the COLLADA physics specification for constraints - virtual int CreateUniversalD6Constraint( - class PHY_IPhysicsController* ctrlRef,class PHY_IPhysicsController* ctrlOther, - btTransform& localAttachmentFrameRef, - btTransform& localAttachmentOther, - const btVector3& linearMinLimits, - const btVector3& linearMaxLimits, - const btVector3& angularMinLimits, - const btVector3& angularMaxLimits,int flags - ); - - - virtual void SetConstraintParam(int constraintId,int param,float value,float value1); - - virtual float GetConstraintParam(int constraintId,int param); - - virtual void RemoveConstraintById(int constraintid); + btVector3 m_gravity; - virtual float getAppliedImpulse(int constraintid); + CcdDebugDraw m_debugDrawer; + std::unique_ptr m_collisionConfiguration; + /// broadphase for dynamic world + std::unique_ptr m_broadphase; + /// for culling only + std::unique_ptr m_cullingCache; + /// broadphase for culling + std::unique_ptr m_cullingTree; - virtual void CallbackTriggers(); + /** use explicit btSoftRigidDynamicsWorld/btDiscreteDynamicsWorld* so that we have access to + * btDiscreteDynamicsWorld::addRigidBody(body,filter,group) + * so that we can set the body collision filter/group at the time of creation + * and not afterwards (breaks the collision system for radar/near sensor) + * Ideally we would like to have access to this function from the btDynamicsWorld interface + */ + std::unique_ptr m_dynamicsWorld; + std::unique_ptr m_solverPool; + std::vector m_solvers; -#ifdef NEW_BULLET_VEHICLE_SUPPORT - //complex constraint for vehicles - virtual PHY_IVehicle* GetVehicleConstraint(int constraintId); -#else - virtual class PHY_IVehicle* GetVehicleConstraint(int constraintId) - { - return 0; - } -#endif /* NEW_BULLET_VEHICLE_SUPPORT */ - // Character physics wrapper - virtual PHY_ICharacter* GetCharacterController(class KX_GameObject* ob); + std::unique_ptr m_filterCallback; - btTypedConstraint* GetConstraintById(int constraintId); + std::unique_ptr m_ghostPairCallback; - virtual PHY_IPhysicsController* RayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ); - virtual bool CullingTest(PHY_CullingCallback callback, void* userData, MT_Vector4* planes, int nplanes, int occlusionRes, const int *viewport, float modelview[16], float projection[16]); + std::unique_ptr m_dispatcher; + std::set m_controllers; + std::vector m_wrapperVehicles; - //Methods for gamelogic collision/physics callbacks - virtual void AddSensor(PHY_IPhysicsController* ctrl); - virtual void RemoveSensor(PHY_IPhysicsController* ctrl); - virtual void AddTouchCallback(int response_class, PHY_ResponseCallback callback, void *user); - virtual bool RequestCollisionCallback(PHY_IPhysicsController* ctrl); - virtual bool RemoveCollisionCallback(PHY_IPhysicsController* ctrl); - //These two methods are used *solely* to create controllers for Near/Radar sensor! Don't use for anything else - virtual PHY_IPhysicsController* CreateSphereController(float radius,const MT_Vector3& position); - virtual PHY_IPhysicsController* CreateConeController(float coneradius,float coneheight); + PHY_ResponseCallback m_triggerCallbacks[PHY_NUM_RESPONSE]; + void *m_triggerCallbacksUserPtrs[PHY_NUM_RESPONSE]; + /// solver iterations + int m_numIterations; - virtual int GetNumContactPoints(); + /// timestep subdivisions + int m_numTimeSubSteps; - virtual void GetContactPoint(int i,float& hitX,float& hitY,float& hitZ,float& normalX,float& normalY,float& normalZ); + int m_ccdMode; + PHY_SolverType m_solverType; - ////////////////////// - //CcdPhysicsEnvironment interface - //////////////////////// + float m_deactivationTime; + float m_linearDeactivationThreshold; + float m_angularDeactivationThreshold; + float m_contactBreakingThreshold; - void AddCcdPhysicsController(CcdPhysicsController* ctrl); + void ProcessFhSprings(double curTime, float timeStep); + virtual void ExportFile(const std::string& filename); + +public: + CcdPhysicsEnvironment(PHY_SolverType solverType, bool useDbvtCulling); + + virtual ~CcdPhysicsEnvironment(); + + ///////////////////////////////////// + //PHY_IPhysicsEnvironment interface + ///////////////////////////////////// + + /// Perform an integration step of duration 'timeStep'. - bool RemoveCcdPhysicsController(CcdPhysicsController* ctrl); + virtual void SetNumIterations(int numIter); + virtual void SetNumTimeSubSteps(int numTimeSubSteps) + { + m_numTimeSubSteps = numTimeSubSteps; + } + virtual void SetDeactivationTime(float dTime); + virtual void SetDeactivationLinearTreshold(float linTresh); + virtual void SetDeactivationAngularTreshold(float angTresh); + virtual void SetContactBreakingTreshold(float contactBreakingTreshold); + virtual void SetCcdMode(int ccdMode); + virtual void SetSolverType(PHY_SolverType solverType); + virtual void SetSolverSorConstant(float sor); + virtual void SetSolverTau(float tau); + virtual void SetSolverDamping(float damping); + virtual void SetLinearAirDamping(float damping); + virtual void SetUseEpa(bool epa); - void UpdateCcdPhysicsController(CcdPhysicsController* ctrl, btScalar newMass, int newCollisionFlags, short int newCollisionGroup, short int newCollisionMask); + virtual int GetNumTimeSubSteps() + { + return m_numTimeSubSteps; + } + /// Perform an integration step of duration 'timeStep'. + virtual bool ProceedDeltaTime(double curTime, float timeStep, float interval); - void RefreshCcdPhysicsController(CcdPhysicsController* ctrl); + /** + * Called by Bullet for every physical simulation (sub)tick. + * Our constructor registers this callback to Bullet, which stores a pointer to 'this' in + * the btDynamicsWorld::getWorldUserInfo() pointer. + */ + static void StaticSimulationSubtickCallback(btDynamicsWorld *world, btScalar timeStep); + void SimulationSubtickCallback(btScalar timeStep); - bool IsActiveCcdPhysicsController(CcdPhysicsController *ctrl); + virtual void DebugDrawWorld(); - void AddCcdGraphicController(CcdGraphicController* ctrl); + virtual void SetFixedTimeStep(bool useFixedTimeStep, float fixedTimeStep) + { + SetNumTimeSubSteps((int)(fixedTimeStep / KX_GetActiveEngine()->GetTicRate())); + } + /// returns 0.f if no fixed timestep is used + virtual float GetFixedTimeStep() + { + return 0.f; + } - void RemoveCcdGraphicController(CcdGraphicController* ctrl); + virtual void SetDebugMode(int debugMode); + virtual int GetDebugMode() const; - /** - * Update all physics controllers shape which use the same shape construction info. - * Call RecreateControllerShape on controllers which use the same shape - * construction info that argument shapeInfo. - * You need to call this function when the shape construction info changed. - */ - void UpdateCcdPhysicsControllerShape(CcdShapeConstructionInfo *shapeInfo); + virtual void SetGravity(float x, float y, float z); + virtual mt::vec3 GetGravity() const; - btBroadphaseInterface* GetBroadphase(); - btDbvtBroadphase* GetCullingTree() { return m_cullingTree; } - btDispatcher* GetDispatcher(); + virtual PHY_IConstraint *CreateConstraint(class PHY_IPhysicsController *ctrl, class PHY_IPhysicsController *ctrl2, PHY_ConstraintType type, + float pivotX, float pivotY, float pivotZ, + float axisX, float axisY, float axisZ, + float axis1X = 0, float axis1Y = 0, float axis1Z = 0, + float axis2X = 0, float axis2Y = 0, float axis2Z = 0, int flag = 0); + virtual PHY_IVehicle *CreateVehicle(PHY_IPhysicsController *ctrl); + virtual void RemoveConstraintById(int constraintid, bool free); - bool IsSatCollisionDetectionEnabled() const - { - return m_enableSatCollisionDetection; - } + virtual float getAppliedImpulse(int constraintid); - void EnableSatCollisionDetection(bool enableSat) - { - m_enableSatCollisionDetection = enableSat; - } + virtual void CallbackTriggers(); + //complex constraint for vehicles + virtual PHY_IVehicle *GetVehicleConstraint(int constraintId); + // Character physics wrapper + virtual PHY_ICharacter *GetCharacterController(class KX_GameObject *ob); - const btPersistentManifold* GetManifold(int index) const; + btTypedConstraint *GetConstraintById(int constraintId); + virtual PHY_IPhysicsController *RayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX, float fromY, float fromZ, float toX, float toY, float toZ); + virtual bool CullingTest(PHY_CullingCallback callback, void *userData, const std::array& planes, + int occlusionRes, const int *viewport, const mt::mat4& matrix); - void SyncMotionStates(float timeStep); - class btSoftRigidDynamicsWorld* GetDynamicsWorld() - { - return m_dynamicsWorld; - } + //Methods for gamelogic collision/physics callbacks + virtual void AddSensor(PHY_IPhysicsController *ctrl); + virtual void RemoveSensor(PHY_IPhysicsController *ctrl); + virtual void AddCollisionCallback(int response_class, PHY_ResponseCallback callback, void *user); + virtual bool RequestCollisionCallback(PHY_IPhysicsController *ctrl); + virtual bool RemoveCollisionCallback(PHY_IPhysicsController *ctrl); + virtual PHY_CollisionTestResult CheckCollision(PHY_IPhysicsController *ctrl0, PHY_IPhysicsController *ctrl1); + //These two methods are used *solely* to create controllers for Near/Radar sensor! Don't use for anything else + virtual PHY_IPhysicsController *CreateSphereController(float radius, const mt::vec3& position); + virtual PHY_IPhysicsController *CreateConeController(float coneradius, float coneheight); - class btConstraintSolver* GetConstraintSolver(); + virtual int GetNumContactPoints(); - void MergeEnvironment(PHY_IPhysicsEnvironment *other_env); + virtual void GetContactPoint(int i, float& hitX, float& hitY, float& hitZ, float& normalX, float& normalY, float& normalZ); - static CcdPhysicsEnvironment *Create(struct Scene *blenderscene, bool visualizePhysics); + ////////////////////// + //CcdPhysicsEnvironment interface + //////////////////////// - virtual void ConvertObject(KX_GameObject* gameobj, - RAS_MeshObject* meshobj, - DerivedMesh* dm, - KX_Scene* kxscene, - PHY_ShapeProps* shapeprops, - PHY_MaterialProps* smmaterial, - PHY_IMotionState *motionstate, - int activeLayerBitInfo, - bool isCompoundChild, - bool hasCompoundChildren); + void AddCcdPhysicsController(CcdPhysicsController *ctrl); - /* Set the rigid body joints constraints values for converted objects and replicated group instances. */ - virtual void SetupObjectConstraints(KX_GameObject *obj_src, KX_GameObject *obj_dest, - bRigidBodyJointConstraint *dat); + bool RemoveCcdPhysicsController(CcdPhysicsController *ctrl, bool freeConstraints); - protected: + void UpdateCcdPhysicsController(CcdPhysicsController *ctrl, btScalar newMass, int newCollisionFlags, short int newCollisionGroup, short int newCollisionMask); + + void RefreshCcdPhysicsController(CcdPhysicsController *ctrl); + bool IsActiveCcdPhysicsController(CcdPhysicsController *ctrl); + void AddCcdGraphicController(CcdGraphicController *ctrl); - std::set m_controllers; + void RemoveCcdGraphicController(CcdGraphicController *ctrl); - PHY_ResponseCallback m_triggerCallbacks[PHY_NUM_RESPONSE]; - void* m_triggerCallbacksUserPtrs[PHY_NUM_RESPONSE]; + /** + * Update all physics controllers shape which use the same shape construction info. + * Call RecreateControllerShape on controllers which use the same shape + * construction info that argument shapeInfo. + * You need to call this function when the shape construction info changed. + */ + void UpdateCcdPhysicsControllerShape(CcdShapeConstructionInfo *shapeInfo); - std::vector m_wrapperVehicles; + btBroadphaseInterface *GetBroadphase(); + btDbvtBroadphase *GetCullingTree() + { + return m_cullingTree.get(); + } - //use explicit btSoftRigidDynamicsWorld/btDiscreteDynamicsWorld* so that we have access to - //btDiscreteDynamicsWorld::addRigidBody(body,filter,group) - //so that we can set the body collision filter/group at the time of creation - //and not afterwards (breaks the collision system for radar/near sensor) - //Ideally we would like to have access to this function from the btDynamicsWorld interface - //class btDynamicsWorld* m_dynamicsWorld; - class btSoftRigidDynamicsWorld* m_dynamicsWorld; + btDispatcher *GetDispatcher(); - class btConstraintSolver* m_solver; + const btPersistentManifold *GetManifold(int index) const; - class btOverlappingPairCache* m_ownPairCache; + void SyncMotionStates(float timeStep); - class CcdOverlapFilterCallBack* m_filterCallback; + btSoftRigidDynamicsWorldMt *GetDynamicsWorld() + { + return m_dynamicsWorld.get(); + } - class btGhostPairCallback* m_ghostPairCallback; + btConstraintSolver *GetConstraintSolver(); - class btDispatcher* m_ownDispatcher; + void MergeEnvironment(PHY_IPhysicsEnvironment *other_env); - bool m_scalingPropagated; + static CcdPhysicsEnvironment *Create(struct Scene *blenderscene, bool visualizePhysics); - virtual void ExportFile(const char* filename); + virtual void ConvertObject(BL_SceneConverter& converter, + KX_GameObject *gameobj, + RAS_Mesh *meshobj, + KX_Scene *kxscene, + PHY_IMotionState *motionstate, + int activeLayerBitInfo, + bool isCompoundChild, + bool hasCompoundChildren); + /* Set the rigid body joints constraints values for converted objects and replicated group instances. */ + virtual void SetupObjectConstraints(KX_GameObject *obj_src, KX_GameObject *obj_dest, + bRigidBodyJointConstraint *dat); +}; -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:CcdPhysicsEnvironment") -#endif +class CcdCollData : public PHY_ICollData +{ + const btPersistentManifold *m_manifoldPoint; +public: + CcdCollData(const btPersistentManifold *manifoldPoint); + virtual ~CcdCollData(); + + virtual unsigned int GetNumContacts() const; + virtual mt::vec3 GetLocalPointA(unsigned int index, bool first) const; + virtual mt::vec3 GetLocalPointB(unsigned int index, bool first) const; + virtual mt::vec3 GetWorldPoint(unsigned int index, bool first) const; + virtual mt::vec3 GetNormal(unsigned int index, bool first) const; + virtual float GetCombinedFriction(unsigned int index, bool first) const; + virtual float GetCombinedRollingFriction(unsigned int index, bool first) const; + virtual float GetCombinedRestitution(unsigned int index, bool first) const; + virtual float GetAppliedImpulse(unsigned int index, bool first) const; }; #endif /* __CCDPHYSICSENVIRONMENT_H__ */ diff --git a/source/gameengine/Network/LoopBackNetwork/CMakeLists.txt b/source/gameengine/Physics/Common/CMakeLists.txt similarity index 77% rename from source/gameengine/Network/LoopBackNetwork/CMakeLists.txt rename to source/gameengine/Physics/Common/CMakeLists.txt index 75877575614b..7ec8b3451d0f 100644 --- a/source/gameengine/Network/LoopBackNetwork/CMakeLists.txt +++ b/source/gameengine/Physics/Common/CMakeLists.txt @@ -25,19 +25,22 @@ set(INC . - .. - ../../../../intern/container - ../../../../intern/string ) set(INC_SYS - + ../../../../intern/moto/include ) set(SRC - NG_LoopBackNetworkDeviceInterface.cpp - - NG_LoopBackNetworkDeviceInterface.h + PHY_IConstraint.h + PHY_DynamicTypes.h + PHY_ICharacter.h + PHY_IController.h + PHY_IGraphicController.h + PHY_IMotionState.h + PHY_IPhysicsController.h + PHY_IPhysicsEnvironment.h + PHY_IVehicle.h ) -blender_add_lib(ge_logic_loopbacknetwork "${SRC}" "${INC}" "${INC_SYS}") +blender_add_lib(ge_phys_dummy "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/gameengine/Physics/Common/PHY_DynamicTypes.h b/source/gameengine/Physics/Common/PHY_DynamicTypes.h new file mode 100644 index 000000000000..70411af2a538 --- /dev/null +++ b/source/gameengine/Physics/Common/PHY_DynamicTypes.h @@ -0,0 +1,106 @@ +/* + 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. + */ + +/** \file PHY_DynamicTypes.h + * \ingroup phys + */ + +#ifndef __PHY_DYNAMICTYPES_H__ +#define __PHY_DYNAMICTYPES_H__ + +#include "mathfu.h" + +struct KX_ClientObjectInfo; +class PHY_IPhysicsController; + +enum +{ + PHY_FH_RESPONSE, + PHY_SENSOR_RESPONSE, // Touch Sensors + PHY_CAMERA_RESPONSE, // Visibility Culling + PHY_OBJECT_RESPONSE, // Object Dynamic Geometry Response + PHY_STATIC_RESPONSE, // Static Geometry Response + PHY_BROADPH_RESPONSE, // broadphase Response + + PHY_NUM_RESPONSE +}; + +class PHY_ICollData +{ +public: + PHY_ICollData() + { + } + + virtual ~PHY_ICollData() + { + } + + virtual unsigned int GetNumContacts() const = 0; + virtual mt::vec3 GetLocalPointA(unsigned int index, bool first) const = 0; + virtual mt::vec3 GetLocalPointB(unsigned int index, bool first) const = 0; + virtual mt::vec3 GetWorldPoint(unsigned int index, bool first) const = 0; + virtual mt::vec3 GetNormal(unsigned int index, bool first) const = 0; + virtual float GetCombinedFriction(unsigned int index, bool first) const = 0; + virtual float GetCombinedRollingFriction(unsigned int index, bool first) const = 0; + virtual float GetCombinedRestitution(unsigned int index, bool first) const = 0; + virtual float GetAppliedImpulse(unsigned int index, bool first) const = 0; +}; + +struct PHY_CollisionTestResult +{ + bool collide; + bool isFirst; + PHY_ICollData *collData; +}; + +using PHY_ResponseCallback = bool (*)(void *client_data, PHY_IPhysicsController *ctrl1, PHY_IPhysicsController *ctrl2, + const PHY_ICollData *coll_data, bool first); +using PHY_CullingCallback = void (*)(KX_ClientObjectInfo *info, void *param); + +/// PHY_ConstraintType enumerates all supported Constraint Types +typedef enum PHY_ConstraintType { + PHY_POINT2POINT_CONSTRAINT = 1, + PHY_LINEHINGE_CONSTRAINT = 2, + PHY_ANGULAR_CONSTRAINT = 3, //hinge without ball socket + PHY_CONE_TWIST_CONSTRAINT = 4, + PHY_VEHICLE_CONSTRAINT = 11, //complex 'constraint' that turns a rigidbody into a vehicle + PHY_GENERIC_6DOF_CONSTRAINT = 12, //can leave any of the 6 degree of freedom 'free' or 'locked' + +} PHY_ConstraintType; + +typedef enum PHY_ShapeType { + PHY_SHAPE_NONE, + PHY_SHAPE_BOX, + PHY_SHAPE_SPHERE, + PHY_SHAPE_CYLINDER, + PHY_SHAPE_CONE, + PHY_SHAPE_CAPSULE, + PHY_SHAPE_MESH, + PHY_SHAPE_POLYTOPE, + PHY_SHAPE_COMPOUND, + PHY_SHAPE_EMPTY, + PHY_SHAPE_PROXY +} PHY_ShapeType; + +typedef enum PHY_SolverType { + PHY_SOLVER_NONE, + PHY_SOLVER_SEQUENTIAL, + PHY_SOLVER_NNCG, + PHY_SOLVER_MLCP_DANTZIG, + PHY_SOLVER_MLCP_LEMKE +} PHY_SolverType; + +#endif /* __PHY_DYNAMICTYPES_H__ */ diff --git a/source/gameengine/Physics/Common/PHY_ICharacter.h b/source/gameengine/Physics/Common/PHY_ICharacter.h new file mode 100644 index 000000000000..9a87acd466f6 --- /dev/null +++ b/source/gameengine/Physics/Common/PHY_ICharacter.h @@ -0,0 +1,46 @@ + +/** \file PHY_ICharacter.h + * \ingroup phys + */ + +#ifndef __PHY_ICHARACTER_H__ +#define __PHY_ICHARACTER_H__ + +//PHY_ICharacter provides a generic interface for "character" controllers + +class PHY_ICharacter +{ +public: + virtual ~PHY_ICharacter() + { + } + + virtual void Jump() = 0; + virtual bool OnGround() = 0; + + virtual mt::vec3 GetGravity() = 0; + virtual void SetGravity(const mt::vec3& gravity) = 0; + + virtual unsigned char GetMaxJumps() = 0; + virtual void SetMaxJumps(unsigned char maxJumps) = 0; + + virtual unsigned char GetJumpCount() = 0; + + virtual void SetWalkDirection(const mt::vec3& dir) = 0; + virtual mt::vec3 GetWalkDirection() = 0; + + virtual float GetFallSpeed() const = 0; + virtual void SetFallSpeed(float fallSpeed) = 0; + + virtual float GetMaxSlope() const = 0; + virtual void SetMaxSlope(float maxSlope) = 0; + + virtual float GetJumpSpeed() const = 0; + virtual void SetJumpSpeed(float jumpSpeed) = 0; + + virtual void SetVelocity(const mt::vec3& vel, float time, bool local) = 0; + + virtual void Reset() = 0; +}; + +#endif //__PHY_ICHARACTER_H__ diff --git a/source/gameengine/Physics/Common/PHY_IConstraint.h b/source/gameengine/Physics/Common/PHY_IConstraint.h new file mode 100644 index 000000000000..573eae662032 --- /dev/null +++ b/source/gameengine/Physics/Common/PHY_IConstraint.h @@ -0,0 +1,25 @@ +#ifndef __PHY_ICONSTRAINT_H__ +#define __PHY_ICONSTRAINT_H__ + +#include "PHY_DynamicTypes.h" // For PHY_ConstraintType. + +class PHY_IConstraint +{ +public: + PHY_IConstraint() = default; + virtual ~PHY_IConstraint() = default; + + virtual bool GetEnabled() const = 0; + virtual void SetEnabled(bool enabled) = 0; + + virtual void SetParam(int param, float value, float value1) = 0; + virtual float GetParam(int param) = 0; + + virtual float GetBreakingThreshold() const = 0; + virtual void SetBreakingThreshold(float threshold) = 0; + + virtual int GetIdentifier() const = 0; + virtual PHY_ConstraintType GetType() const = 0; +}; + +#endif // __PHY_ICONSTRAINT_H__ diff --git a/source/gameengine/Physics/common/PHY_IController.h b/source/gameengine/Physics/Common/PHY_IController.h similarity index 78% rename from source/gameengine/Physics/common/PHY_IController.h rename to source/gameengine/Physics/Common/PHY_IController.h index 239749596180..f0dc4e2999c8 100644 --- a/source/gameengine/Physics/common/PHY_IController.h +++ b/source/gameengine/Physics/Common/PHY_IController.h @@ -36,10 +36,6 @@ class PHY_IPhysicsEnvironment; -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - /** * PHY_IController is the abstract simplified Interface to objects * controlled by the physics engine. This includes the physics objects @@ -47,17 +43,14 @@ class PHY_IPhysicsEnvironment; */ class PHY_IController { - public: - virtual ~PHY_IController() {}; - // clientinfo for raycasts for example - virtual void* GetNewClientInfo()=0; - virtual void SetNewClientInfo(void* clientinfo)=0; - virtual void SetPhysicsEnvironment(class PHY_IPhysicsEnvironment *env)=0; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:PHY_IController") -#endif +public: + virtual ~PHY_IController() + { + } + // clientinfo for raycasts for example + virtual void *GetNewClientInfo() = 0; + virtual void SetNewClientInfo(void *clientinfo) = 0; + virtual void SetPhysicsEnvironment(class PHY_IPhysicsEnvironment *env) = 0; }; #endif /* __PHY_ICONTROLLER_H__ */ diff --git a/source/gameengine/Physics/common/PHY_IGraphicController.h b/source/gameengine/Physics/Common/PHY_IGraphicController.h similarity index 71% rename from source/gameengine/Physics/common/PHY_IGraphicController.h rename to source/gameengine/Physics/Common/PHY_IGraphicController.h index b047edd93ebb..a5b5cfb8bf44 100644 --- a/source/gameengine/Physics/common/PHY_IGraphicController.h +++ b/source/gameengine/Physics/Common/PHY_IGraphicController.h @@ -34,6 +34,7 @@ #include "PHY_IController.h" +class PHY_IMotionState; /** * PHY_IPhysicsController is the abstract simplified Interface to a physical object. @@ -41,20 +42,18 @@ */ class PHY_IGraphicController : public PHY_IController { - public: - /** - * SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding') - */ - virtual bool SetGraphicTransform()=0; - virtual void Activate(bool active=true)=0; - virtual void SetLocalAabb(const class MT_Vector3& aabbMin,const class MT_Vector3& aabbMax)=0; - virtual void SetLocalAabb(const float* aabbMin,const float* aabbMax)=0; - - virtual PHY_IGraphicController* GetReplica(class PHY_IMotionState* motionstate) {return 0;} - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:PHY_IController") -#endif +public: + /** + * SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding') + */ + virtual bool SetGraphicTransform() = 0; + virtual void Activate(bool active = true) = 0; + virtual void SetLocalAabb(const mt::vec3& aabbMin, const mt::vec3& aabbMax) = 0; + + virtual PHY_IGraphicController *GetReplica(PHY_IMotionState *motionstate) + { + return nullptr; + } }; #endif /* __PHY_IGRAPHICCONTROLLER_H__ */ diff --git a/source/gameengine/Physics/common/PHY_IMotionState.h b/source/gameengine/Physics/Common/PHY_IMotionState.h similarity index 59% rename from source/gameengine/Physics/common/PHY_IMotionState.h rename to source/gameengine/Physics/Common/PHY_IMotionState.h index 0474d9abc729..273a9b541bc8 100644 --- a/source/gameengine/Physics/common/PHY_IMotionState.h +++ b/source/gameengine/Physics/Common/PHY_IMotionState.h @@ -32,37 +32,28 @@ #ifndef __PHY_IMOTIONSTATE_H__ #define __PHY_IMOTIONSTATE_H__ -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif +#include "mathfu.h" /** * PHY_IMotionState is the Interface to explicitly synchronize the world transformation. * Default implementations for mayor graphics libraries like OpenGL and DirectX can be provided. */ -class PHY_IMotionState - +class PHY_IMotionState { - public: - virtual ~PHY_IMotionState() {}; - - virtual void GetWorldPosition(float& posX,float& posY,float& posZ)=0; - virtual void GetWorldScaling(float& scaleX,float& scaleY,float& scaleZ)=0; - virtual void GetWorldOrientation(float& quatIma0,float& quatIma1,float& quatIma2,float& quatReal)=0; - // ori = array 12 floats, [0..3] = first column + 0, [4..7] = second column, [8..11] = third column - virtual void GetWorldOrientation(float* ori)=0; - virtual void SetWorldOrientation(const float* ori)=0; - - virtual void SetWorldPosition(float posX,float posY,float posZ)=0; - virtual void SetWorldOrientation(float quatIma0,float quatIma1,float quatIma2,float quatReal)=0; - +public: + virtual ~PHY_IMotionState() + { + } - virtual void CalculateWorldTransformations()=0; + virtual mt::vec3 GetWorldPosition() const = 0; + virtual mt::vec3 GetWorldScaling() const = 0; + virtual mt::mat3 GetWorldOrientation() const = 0; + virtual void SetWorldPosition(const mt::vec3& pos) = 0; + virtual void SetWorldOrientation(const mt::mat3& ori) = 0; + virtual void SetWorldOrientation(const mt::quat& quat) = 0; -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:PHY_IMotionState") -#endif + virtual void CalculateWorldTransformations() = 0; }; #endif /* __PHY_IMOTIONSTATE_H__ */ diff --git a/source/gameengine/Physics/Common/PHY_IPhysicsController.h b/source/gameengine/Physics/Common/PHY_IPhysicsController.h new file mode 100644 index 000000000000..d79f924318a2 --- /dev/null +++ b/source/gameengine/Physics/Common/PHY_IPhysicsController.h @@ -0,0 +1,157 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file PHY_IPhysicsController.h + * \ingroup phys + */ + +#ifndef __PHY_IPHYSICSCONTROLLER_H__ +#define __PHY_IPHYSICSCONTROLLER_H__ + +#include + +#include "PHY_IController.h" + +class PHY_IMotionState; +class PHY_IPhysicsEnvironment; + +class KX_GameObject; +class RAS_Mesh; + +/** + * PHY_IPhysicsController is the abstract simplified Interface to a physical object. + * It contains the IMotionState and IDeformableMesh Interfaces. + */ +class PHY_IPhysicsController : public PHY_IController +{ +public: + virtual ~PHY_IPhysicsController() + { + } + /** + * SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding') + */ + virtual bool SynchronizeMotionStates(float time) = 0; + /** + * WriteMotionStateToDynamics ynchronizes dynas, kinematic and deformable entities (and do 'late binding') + */ + + virtual void WriteMotionStateToDynamics(bool nondynaonly) = 0; + virtual void WriteDynamicsToMotionState() = 0; + virtual class PHY_IMotionState *GetMotionState() = 0; + // controller replication + virtual void PostProcessReplica(class PHY_IMotionState *motionstate, class PHY_IPhysicsController *parentctrl) = 0; + virtual void SetPhysicsEnvironment(class PHY_IPhysicsEnvironment *env) = 0; + + // kinematic methods + virtual void RelativeTranslate(const mt::vec3& dloc, bool local) = 0; + virtual void RelativeRotate(const mt::mat3 &, bool local) = 0; + virtual mt::mat3 GetOrientation() = 0; + virtual void SetOrientation(const mt::mat3& orn) = 0; + virtual void SetPosition(const mt::vec3& pos) = 0; + virtual mt::vec3 GetPosition() const = 0; + virtual void SetScaling(const mt::vec3& scale) = 0; + virtual void SetTransform() = 0; + + virtual float GetMass() = 0; + virtual void SetMass(float newmass) = 0; + + // physics methods + virtual void ApplyImpulse(const mt::vec3& attach, const mt::vec3& impulse, bool local) = 0; + virtual void ApplyTorque(const mt::vec3& torque, bool local) = 0; + virtual void ApplyForce(const mt::vec3& force, bool local) = 0; + virtual void SetAngularVelocity(const mt::vec3& ang_vel, bool local) = 0; + virtual void SetLinearVelocity(const mt::vec3& lin_vel, bool local) = 0; + + virtual float GetLinearDamping() const = 0; + virtual float GetAngularDamping() const = 0; + virtual void SetLinearDamping(float damping) = 0; + virtual void SetAngularDamping(float damping) = 0; + virtual void SetDamping(float linear, float angular) = 0; + virtual void SetGravity(const mt::vec3 &gravity) = 0; + + virtual void RefreshCollisions() = 0; + virtual void SuspendPhysics(bool freeConstraints) = 0; + virtual void RestorePhysics() = 0; + virtual void SuspendDynamics(bool ghost = false) = 0; + virtual void RestoreDynamics() = 0; + + virtual void SetActive(bool active) = 0; + + virtual unsigned short GetCollisionGroup() const = 0; + virtual unsigned short GetCollisionMask() const = 0; + virtual void SetCollisionGroup(unsigned short group) = 0; + virtual void SetCollisionMask(unsigned short mask) = 0; + + // reading out information from physics + virtual mt::vec3 GetLinearVelocity() = 0; + virtual mt::vec3 GetAngularVelocity() = 0; + virtual mt::vec3 GetVelocity(const mt::vec3& pos) = 0; + virtual mt::vec3 GetLocalInertia() = 0; + virtual mt::vec3 GetGravity() = 0; + + // dyna's that are rigidbody are free in orientation, dyna's with non-rigidbody are restricted + virtual void SetRigidBody(bool rigid) = 0; + + virtual PHY_IPhysicsController *GetReplica() + { + return nullptr; + } + virtual PHY_IPhysicsController *GetReplicaForSensors() + { + return nullptr; + } + + virtual void SetMargin(float margin) = 0; + virtual float GetMargin() const = 0; + virtual float GetRadius() const = 0; + virtual void SetRadius(float margin) = 0; + + virtual float GetLinVelocityMin() const = 0; + virtual void SetLinVelocityMin(float val) = 0; + virtual float GetLinVelocityMax() const = 0; + virtual void SetLinVelocityMax(float val) = 0; + + virtual void SetAngularVelocityMin(float val) = 0; + virtual float GetAngularVelocityMin() const = 0; + virtual void SetAngularVelocityMax(float val) = 0; + virtual float GetAngularVelocityMax() const = 0; + + // Shape control + virtual void AddCompoundChild(PHY_IPhysicsController *child) = 0; + virtual void RemoveCompoundChild(PHY_IPhysicsController *child) = 0; + + virtual bool IsDynamic() = 0; + virtual bool IsCompound() = 0; + virtual bool IsDynamicsSuspended() const = 0; + virtual bool IsPhysicsSuspended() = 0; + + virtual bool ReinstancePhysicsShape(KX_GameObject *from_gameobj, RAS_Mesh *from_meshobj, bool dupli = false) = 0; + virtual void ReplacePhysicsShape(PHY_IPhysicsController *phyctrl) = 0; +}; + +#endif /* __PHY_IPHYSICSCONTROLLER_H__ */ diff --git a/source/gameengine/Physics/Common/PHY_IPhysicsEnvironment.h b/source/gameengine/Physics/Common/PHY_IPhysicsEnvironment.h new file mode 100644 index 000000000000..ddfcbd5e68e0 --- /dev/null +++ b/source/gameengine/Physics/Common/PHY_IPhysicsEnvironment.h @@ -0,0 +1,253 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file PHY_IPhysicsEnvironment.h + * \ingroup phys + */ + +#ifndef __PHY_IPHYSICSENVIRONMENT_H__ +#define __PHY_IPHYSICSENVIRONMENT_H__ + +#include "PHY_DynamicTypes.h" + +#include + +class PHY_IConstraint; +class PHY_IVehicle; +class PHY_ICharacter; +class RAS_Mesh; +class PHY_IPhysicsController; + +class RAS_Mesh; +class KX_GameObject; +class KX_Scene; +class BL_SceneConverter; + +class PHY_IMotionState; +struct bRigidBodyJointConstraint; + +/** + * pass back information from rayTest + */ +struct PHY_RayCastResult { + PHY_IPhysicsController *m_controller; + mt::vec3 m_hitPoint; + mt::vec3 m_hitNormal; + RAS_Mesh *m_meshObject; // !=nullptr for mesh object (only for Bullet controllers) + int m_polygon; // index of the polygon hit by the ray, only if m_meshObject != nullptr + int m_hitUVOK; // !=0 if UV coordinate in m_hitUV is valid + mt::vec2 m_hitUV; // UV coordinates of hit point + + PHY_RayCastResult() + :m_controller(nullptr), + m_hitPoint(mt::zero3), + m_hitNormal(mt::zero3), + m_meshObject(nullptr), + m_polygon(0), + m_hitUVOK(0), + m_hitUV(mt::zero2) + { + } +}; + +/** + * This class replaces the ignoreController parameter of rayTest function. + * It allows more sophisticated filtering on the physics controller before computing the ray intersection to save CPU. + * It is only used to its full extend by the Ccd physics environment (Bullet). + */ +class PHY_IRayCastFilterCallback +{ +public: + PHY_IPhysicsController *m_ignoreController; + bool m_faceNormal; + bool m_faceUV; + + virtual ~PHY_IRayCastFilterCallback() + { + } + + virtual bool needBroadphaseRayCast(PHY_IPhysicsController *controller) + { + return true; + } + + virtual void reportHit(PHY_RayCastResult *result) = 0; + + PHY_IRayCastFilterCallback(PHY_IPhysicsController *ignoreController, bool faceNormal = false, bool faceUV = false) + : m_ignoreController(ignoreController), + m_faceNormal(faceNormal), + m_faceUV(faceUV) + { + } +}; + +/** + * Physics Environment takes care of stepping the simulation and is a container for physics entities + * (rigidbodies,constraints, materials etc.) + * A derived class may be able to 'construct' entities by loading and/or converting + */ +class PHY_IPhysicsEnvironment +{ +public: + virtual ~PHY_IPhysicsEnvironment() + { + } + /// Perform an integration step of duration 'timeStep'. + virtual bool ProceedDeltaTime(double curTime, float timeStep, float interval) = 0; + /// draw debug lines (make sure to call this during the render phase, otherwise lines are not drawn properly) + virtual void DebugDrawWorld() + { + } + virtual void SetFixedTimeStep(bool useFixedTimeStep, float fixedTimeStep) = 0; + // returns 0.f if no fixed timestep is used + virtual float GetFixedTimeStep() = 0; + + /// getDebugMode return the actual debug visualization state + virtual int GetDebugMode() const = 0; + /// setDebugMode is used to support several ways of debug lines, contact point visualization + virtual void SetDebugMode(int debugMode) + { + } + /// setNumIterations set the number of iterations for iterative solvers + virtual void SetNumIterations(int numIter) + { + } + /// setNumTimeSubSteps set the number of divisions of the timestep. Tradeoff quality versus performance. + virtual void SetNumTimeSubSteps(int numTimeSubSteps) + { + } + virtual int GetNumTimeSubSteps() + { + return 0; + } + /// setDeactivationTime sets the minimum time that an objects has to stay within the velocity tresholds until it gets fully deactivated + virtual void SetDeactivationTime(float dTime) + { + } + /// setDeactivationLinearTreshold sets the linear velocity treshold, see setDeactivationTime + virtual void SetDeactivationLinearTreshold(float linTresh) + { + } + /// setDeactivationAngularTreshold sets the angular velocity treshold, see setDeactivationTime + virtual void SetDeactivationAngularTreshold(float angTresh) + { + } + /// setContactBreakingTreshold sets tresholds to do with contact point management + virtual void SetContactBreakingTreshold(float contactBreakingTreshold) + { + } + /// continuous collision detection mode, very experimental for Bullet + virtual void SetCcdMode(int ccdMode) + { + } + /// successive overrelaxation constant, in case PSOR is used, values in between 1 and 2 guarantee converging behavior + virtual void SetSolverSorConstant(float sor) + { + } + /// setSolverType, internal setting, chooses solvertype, PSOR, Dantzig, impulse based, penalty based + virtual void SetSolverType(PHY_SolverType solverType) + { + } + /// setTau sets the spring constant of a penalty based solver + virtual void SetSolverTau(float tau) + { + } + /// setDamping sets the damper constant of a penalty based solver + virtual void SetSolverDamping(float damping) + { + } + /// linear air damping for rigidbodies + virtual void SetLinearAirDamping(float damping) + { + } + /// penetrationdepth setting + virtual void SetUseEpa(bool epa) + { + } + + virtual void SetGravity(float x, float y, float z) = 0; + virtual mt::vec3 GetGravity() const = 0; + + virtual PHY_IConstraint *CreateConstraint(class PHY_IPhysicsController *ctrl, class PHY_IPhysicsController *ctrl2, PHY_ConstraintType type, + float pivotX, float pivotY, float pivotZ, + float axis0X, float axis0Y, float axis0Z, + float axis1X = 0, float axis1Y = 0, float axis1Z = 0, + float axis2X = 0, float axis2Y = 0, float axis2Z = 0, int flag = 0) = 0; + virtual PHY_IVehicle *CreateVehicle(PHY_IPhysicsController *ctrl) = 0; + virtual void RemoveConstraintById(int constraintid, bool free) = 0; + virtual float GetAppliedImpulse(int constraintid) + { + return 0.0f; + } + + // complex constraint for vehicles + virtual PHY_IVehicle *GetVehicleConstraint(int constraintId) = 0; + // Character physics wrapper + virtual PHY_ICharacter *GetCharacterController(class KX_GameObject *ob) = 0; + + virtual PHY_IPhysicsController *RayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX, float fromY, float fromZ, float toX, float toY, float toZ) = 0; + + // culling based on physical broad phase + // the plane number must be set as follow: near, far, left, right, top, botton + // the near plane must be the first one and must always be present, it is used to get the direction of the view + virtual bool CullingTest(PHY_CullingCallback callback, void *userData, const std::array& planes, + int occlusionRes, const int *viewport, const mt::mat4& matrix) = 0; + + // Methods for gamelogic collision/physics callbacks + virtual void AddSensor(PHY_IPhysicsController *ctrl) = 0; + virtual void RemoveSensor(PHY_IPhysicsController *ctrl) = 0; + virtual void AddCollisionCallback(int response_class, PHY_ResponseCallback callback, void *user) = 0; + virtual bool RequestCollisionCallback(PHY_IPhysicsController *ctrl) = 0; + virtual bool RemoveCollisionCallback(PHY_IPhysicsController *ctrl) = 0; + virtual PHY_CollisionTestResult CheckCollision(PHY_IPhysicsController *ctrl0, PHY_IPhysicsController *ctrl1) = 0; + //These two methods are *solely* used to create controllers for sensor! Don't use for anything else + virtual PHY_IPhysicsController *CreateSphereController(float radius, const mt::vec3& position) = 0; + virtual PHY_IPhysicsController *CreateConeController(float coneradius, float coneheight) = 0; + + virtual void ExportFile(const std::string& filename) + { + }; + + virtual void MergeEnvironment(PHY_IPhysicsEnvironment *other_env) = 0; + + virtual void ConvertObject(BL_SceneConverter& converter, + KX_GameObject *gameobj, + RAS_Mesh *meshobj, + KX_Scene *kxscene, + PHY_IMotionState *motionstate, + int activeLayerBitInfo, + bool isCompoundChild, + bool hasCompoundChildren) = 0; + + /* Set the rigid body joints constraints values for converted objects and replicated group instances. */ + virtual void SetupObjectConstraints(KX_GameObject *obj_src, KX_GameObject *obj_dest, + bRigidBodyJointConstraint *dat) + { + } +}; + +#endif /* __PHY_IPHYSICSENVIRONMENT_H__ */ diff --git a/source/gameengine/Physics/Common/PHY_IVehicle.h b/source/gameengine/Physics/Common/PHY_IVehicle.h new file mode 100644 index 000000000000..017bd16bc05b --- /dev/null +++ b/source/gameengine/Physics/Common/PHY_IVehicle.h @@ -0,0 +1,64 @@ + +/** \file PHY_IVehicle.h + * \ingroup phys + */ + +#ifndef __PHY_IVEHICLE_H__ +#define __PHY_IVEHICLE_H__ + +//PHY_IVehicle provides a generic interface for (raycast based) vehicles. Mostly targetting 4 wheel cars and 2 wheel motorbikes. + +#include "PHY_DynamicTypes.h" + +class PHY_IMotionState; + +class PHY_IVehicle +{ +public: + virtual ~PHY_IVehicle() + { + }; + + virtual void AddWheel( + PHY_IMotionState *motionState, + const mt::vec3 &connectionPoint, + const mt::vec3 &downDirection, + const mt::vec3 &axleDirection, + float suspensionRestLength, + float wheelRadius, + bool hasSteering) = 0; + + virtual int GetNumWheels() const = 0; + + virtual mt::vec3 GetWheelPosition(int wheelIndex) const = 0; + virtual mt::quat GetWheelOrientationQuaternion(int wheelIndex) const = 0; + virtual float GetWheelRotation(int wheelIndex) const = 0; + + virtual int GetUserConstraintId() const = 0; + virtual int GetUserConstraintType() const = 0; + + // some basic steering/braking/tuning/balancing (bikes) + + virtual void SetSteeringValue(float steering, int wheelIndex) = 0; + + virtual void ApplyEngineForce(float force, int wheelIndex) = 0; + + virtual void ApplyBraking(float braking, int wheelIndex) = 0; + + virtual void SetWheelFriction(float friction, int wheelIndex) = 0; + + virtual void SetSuspensionStiffness(float suspensionStiffness, int wheelIndex) = 0; + + virtual void SetSuspensionDamping(float suspensionStiffness, int wheelIndex) = 0; + + virtual void SetSuspensionCompression(float suspensionStiffness, int wheelIndex) = 0; + + virtual void SetRollInfluence(float rollInfluence, int wheelIndex) = 0; + + virtual void SetCoordinateSystem(int rightIndex, int upIndex, int forwardIndex) = 0; + + virtual void SetRayCastMask(short mask) = 0; + virtual short GetRayCastMask() const = 0; +}; + +#endif /* __PHY_IVEHICLE_H__ */ diff --git a/source/gameengine/Physics/Dummy/CMakeLists.txt b/source/gameengine/Physics/Dummy/CMakeLists.txt index 692331f1ce47..133742736fba 100644 --- a/source/gameengine/Physics/Dummy/CMakeLists.txt +++ b/source/gameengine/Physics/Dummy/CMakeLists.txt @@ -25,11 +25,12 @@ set(INC . - ../common + ../Common + ../../../blender/blenlib ) set(INC_SYS - ../../../../intern/moto/include + ../../../../intern/mathfu ) set(SRC diff --git a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp index 817bcb3e72c3..a05a8a50006c 100644 --- a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp @@ -40,26 +40,12 @@ DummyPhysicsEnvironment::DummyPhysicsEnvironment() // create physicsengine data } - - DummyPhysicsEnvironment::~DummyPhysicsEnvironment() { //destroy physicsengine data } -void DummyPhysicsEnvironment::BeginFrame() -{ - // beginning of logic frame: apply forces -} - -void DummyPhysicsEnvironment::EndFrame() -{ - // end of logic frame: clear forces -} - - - -bool DummyPhysicsEnvironment::ProceedDeltaTime(double curTime,float timeStep,float interval) +bool DummyPhysicsEnvironment::ProceedDeltaTime(double curTime, float timeStep, float interval) { //step physics simulation, typically perform @@ -69,13 +55,14 @@ bool DummyPhysicsEnvironment::ProceedDeltaTime(double curTime,float timeStep,f // return true if an update was done. return true; } -void DummyPhysicsEnvironment::SetFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep) + +void DummyPhysicsEnvironment::SetFixedTimeStep(bool useFixedTimeStep, float fixedTimeStep) { } -float DummyPhysicsEnvironment::GetFixedTimeStep() +float DummyPhysicsEnvironment::GetFixedTimeStep() { - return 0.f; + return 0.0f; } int DummyPhysicsEnvironment::GetDebugMode() const @@ -83,38 +70,37 @@ int DummyPhysicsEnvironment::GetDebugMode() const return 0; } -void DummyPhysicsEnvironment::SetGravity(float x,float y,float z) +void DummyPhysicsEnvironment::SetGravity(float x, float y, float z) { } -void DummyPhysicsEnvironment::GetGravity(class MT_Vector3& grav) +mt::vec3 DummyPhysicsEnvironment::GetGravity() const { + return mt::zero3; } - - - -int DummyPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsController* ctrl2,PHY_ConstraintType type, - float pivotX,float pivotY,float pivotZ,float axisX,float axisY,float axisZ, - float axis1X,float axis1Y,float axis1Z, - float axis2X,float axis2Y,float axis2Z,int flag - ) +PHY_IConstraint *DummyPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController *ctrl, class PHY_IPhysicsController *ctrl2, PHY_ConstraintType type, + float pivotX, float pivotY, float pivotZ, float axisX, float axisY, float axisZ, + float axis1X, float axis1Y, float axis1Z, + float axis2X, float axis2Y, float axis2Z, int flag) { + return nullptr; +} - int constraintid = 0; - return constraintid; - +PHY_IVehicle *DummyPhysicsEnvironment::CreateVehicle(PHY_IPhysicsController *ctrl) +{ + return nullptr; } -void DummyPhysicsEnvironment::RemoveConstraintById(int constraintid) +void DummyPhysicsEnvironment::RemoveConstraintById(int constraintid, bool free) { - if (constraintid) - { + if (constraintid) { } } -PHY_IPhysicsController* DummyPhysicsEnvironment::RayTest(PHY_IRayCastFilterCallback &filterCallback,float fromX,float fromY,float fromZ, float toX,float toY,float toZ) +PHY_IPhysicsController *DummyPhysicsEnvironment::RayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX, float fromY, float fromZ, float toX, float toY, float toZ) { //collision detection / raytesting - return NULL; + return nullptr; } + diff --git a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h index dd6f7f448032..66f4fef5b4d5 100644 --- a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h +++ b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h @@ -43,92 +43,97 @@ * * A derived class may be able to 'construct' entities by loading and/or converting */ -class DummyPhysicsEnvironment : public PHY_IPhysicsEnvironment +class DummyPhysicsEnvironment : public PHY_IPhysicsEnvironment { - public: DummyPhysicsEnvironment (); - virtual ~DummyPhysicsEnvironment (); - virtual void BeginFrame(); - virtual void EndFrame(); + virtual ~DummyPhysicsEnvironment (); // Perform an integration step of duration 'timeStep'. - virtual bool ProceedDeltaTime(double curTime,float timeStep,float interval); - virtual void SetFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep); - virtual float GetFixedTimeStep(); + virtual bool ProceedDeltaTime(double curTime, float timeStep, float interval); + virtual void SetFixedTimeStep(bool useFixedTimeStep, float fixedTimeStep); + virtual float GetFixedTimeStep(); - virtual int GetDebugMode() const; + virtual int GetDebugMode() const; - virtual void SetGravity(float x,float y,float z); - virtual void GetGravity(class MT_Vector3& grav); + virtual void SetGravity(float x, float y, float z); + virtual mt::vec3 GetGravity() const; - virtual int CreateConstraint(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsController* ctrl2,PHY_ConstraintType type, - float pivotX,float pivotY,float pivotZ, - float axisX,float axisY,float axisZ, - float axis1X=0,float axis1Y=0,float axis1Z=0, - float axis2X=0,float axis2Y=0,float axis2Z=0,int flag=0 - ); + virtual PHY_IConstraint *CreateConstraint(class PHY_IPhysicsController *ctrl, class PHY_IPhysicsController *ctrl2, PHY_ConstraintType type, + float pivotX, float pivotY, float pivotZ, + float axisX, float axisY, float axisZ, + float axis1X = 0, float axis1Y = 0, float axis1Z = 0, + float axis2X = 0, float axis2Y = 0, float axis2Z = 0, int flag = 0); + virtual PHY_IVehicle *CreateVehicle(PHY_IPhysicsController *ctrl); - virtual void RemoveConstraintById(int constraintid); + virtual void RemoveConstraintById(int constraintid, bool free); - //complex constraint for vehicles - virtual PHY_IVehicle* GetVehicleConstraint(int constraintId) + //complex constraint for vehicles + virtual PHY_IVehicle *GetVehicleConstraint(int constraintId) { - return 0; + return nullptr; } - // Character physics wrapper - virtual PHY_ICharacter* GetCharacterController(class KX_GameObject* ob) + // Character physics wrapper + virtual PHY_ICharacter *GetCharacterController(class KX_GameObject *ob) { - return 0; + return nullptr; } - virtual PHY_IPhysicsController* RayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ); - virtual bool CullingTest(PHY_CullingCallback callback, void* userData, class MT_Vector4* planes, int nplanes, int occlusionRes, const int *viewport, float modelview[16], float projection[16]) { return false; } - + virtual PHY_IPhysicsController *RayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX, float fromY, float fromZ, float toX, float toY, float toZ); + virtual bool CullingTest(PHY_CullingCallback callback, void *userData, const std::array& planes, + int occlusionRes, const int *viewport, const mt::mat4& matrix) + { + return false; + } //gamelogic callbacks - virtual void AddSensor(PHY_IPhysicsController* ctrl) {} - virtual void RemoveSensor(PHY_IPhysicsController* ctrl) {} - virtual void AddTouchCallback(int response_class, PHY_ResponseCallback callback, void *user) - { - } - virtual bool RequestCollisionCallback(PHY_IPhysicsController* ctrl) { return false; } - virtual bool RemoveCollisionCallback(PHY_IPhysicsController* ctrl) { return false;} - virtual PHY_IPhysicsController* CreateSphereController(float radius,const class MT_Vector3& position) {return 0;} - virtual PHY_IPhysicsController* CreateConeController(float coneradius,float coneheight) { return 0;} - - virtual void SetConstraintParam(int constraintId,int param,float value,float value1) - { - } - - virtual float GetConstraintParam(int constraintId,int param) - { - return 0.f; - } + virtual void AddSensor(PHY_IPhysicsController *ctrl) + { + } + virtual void RemoveSensor(PHY_IPhysicsController *ctrl) + { + } + virtual void AddCollisionCallback(int response_class, PHY_ResponseCallback callback, void *user) + { + } + virtual bool RequestCollisionCallback(PHY_IPhysicsController *ctrl) + { + return false; + } + virtual bool RemoveCollisionCallback(PHY_IPhysicsController *ctrl) + { + return false; + } + virtual PHY_CollisionTestResult CheckCollision(PHY_IPhysicsController *ctrl0, PHY_IPhysicsController *ctrl1) + { + return {false, false, nullptr}; + } + virtual PHY_IPhysicsController *CreateSphereController(float radius, const mt::vec3& position) + { + return nullptr; + } + virtual PHY_IPhysicsController *CreateConeController(float coneradius, float coneheight) + { + return nullptr; + } virtual void MergeEnvironment(PHY_IPhysicsEnvironment *other_env) { // Dummy, nothing to do here } - virtual void ConvertObject(KX_GameObject* gameobj, - RAS_MeshObject* meshobj, - DerivedMesh* dm, - KX_Scene* kxscene, - PHY_ShapeProps* shapeprops, - PHY_MaterialProps* smmaterial, - PHY_IMotionState *motionstate, - int activeLayerBitInfo, - bool isCompoundChild, - bool hasCompoundChildren) + virtual void ConvertObject(BL_SceneConverter& converter, + KX_GameObject *gameobj, + RAS_Mesh *meshobj, + KX_Scene *kxscene, + PHY_IMotionState *motionstate, + int activeLayerBitInfo, + bool isCompoundChild, + bool hasCompoundChildren) { // All we need to do is handle the motionstate (we're supposed to own it) delete motionstate; } - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:DummyPhysicsEnvironment") -#endif }; #endif /* __DUMMYPHYSICSENVIRONMENT_H__ */ diff --git a/source/gameengine/Physics/common/PHY_DynamicTypes.h b/source/gameengine/Physics/common/PHY_DynamicTypes.h deleted file mode 100644 index a92a950b26f2..000000000000 --- a/source/gameengine/Physics/common/PHY_DynamicTypes.h +++ /dev/null @@ -1,91 +0,0 @@ -/* -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. -*/ - -/** \file PHY_DynamicTypes.h - * \ingroup phys - */ - -#ifndef __PHY_DYNAMICTYPES_H__ -#define __PHY_DYNAMICTYPES_H__ - -#include "MT_Vector3.h" - -struct KX_ClientObjectInfo; - -enum -{ - PHY_FH_RESPONSE, - PHY_SENSOR_RESPONSE, /* Touch Sensors */ - PHY_CAMERA_RESPONSE, /* Visibility Culling */ - PHY_OBJECT_RESPONSE, /* Object Dynamic Geometry Response */ - PHY_STATIC_RESPONSE, /* Static Geometry Response */ - PHY_BROADPH_RESPONSE, /* broadphase Response */ - - PHY_NUM_RESPONSE -}; - -typedef struct PHY_CollData { - MT_Vector3 m_point1; /* Point in object1 in world coordinates */ - MT_Vector3 m_point2; /* Point in object2 in world coordinates */ - MT_Vector3 m_normal; /* point2 - point1 */ -} PHY_CollData; - - -typedef bool (*PHY_ResponseCallback)(void *client_data, - void *client_object1, - void *client_object2, - const PHY_CollData *coll_data); -typedef void (*PHY_CullingCallback)(KX_ClientObjectInfo* info, void* param); - - -/// PHY_PhysicsType enumerates all possible Physics Entities. -/// It is mainly used to create/add Physics Objects - -typedef enum PHY_PhysicsType { - PHY_CONVEX_RIGIDBODY=16386, - PHY_CONCAVE_RIGIDBODY=16399, - PHY_CONVEX_FIXEDBODY=16388,//'collision object' - PHY_CONCAVE_FIXEDBODY=16401, - PHY_CONVEX_KINEMATICBODY=16387,// - PHY_CONCAVE_KINEMATICBODY=16400, - PHY_CONVEX_PHANTOMBODY=16398, - PHY_CONCAVE_PHANTOMBODY=16402 -} PHY_PhysicsType; - -/// PHY_ConstraintType enumerates all supported Constraint Types -typedef enum PHY_ConstraintType { - PHY_POINT2POINT_CONSTRAINT=1, - PHY_LINEHINGE_CONSTRAINT=2, - PHY_ANGULAR_CONSTRAINT = 3,//hinge without ball socket - PHY_CONE_TWIST_CONSTRAINT = 4, - PHY_VEHICLE_CONSTRAINT=11,//complex 'constraint' that turns a rigidbody into a vehicle - PHY_GENERIC_6DOF_CONSTRAINT=12,//can leave any of the 6 degree of freedom 'free' or 'locked' - -} PHY_ConstraintType; - -typedef enum PHY_ShapeType { - PHY_SHAPE_NONE, - PHY_SHAPE_BOX, - PHY_SHAPE_SPHERE, - PHY_SHAPE_CYLINDER, - PHY_SHAPE_CONE, - PHY_SHAPE_CAPSULE, - PHY_SHAPE_MESH, - PHY_SHAPE_POLYTOPE, - PHY_SHAPE_COMPOUND, - PHY_SHAPE_PROXY -} PHY_ShapeType; - -#endif /* __PHY_DYNAMICTYPES_H__ */ diff --git a/source/gameengine/Physics/common/PHY_ICharacter.h b/source/gameengine/Physics/common/PHY_ICharacter.h deleted file mode 100644 index 9c27e1fe2b89..000000000000 --- a/source/gameengine/Physics/common/PHY_ICharacter.h +++ /dev/null @@ -1,39 +0,0 @@ - -/** \file PHY_ICharacter.h - * \ingroup phys - */ - -#ifndef __PHY_ICHARACTER_H__ -#define __PHY_ICHARACTER_H__ - -//PHY_ICharacter provides a generic interface for "character" controllers - -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -class PHY_ICharacter -{ -public: - virtual ~PHY_ICharacter() {}; - - virtual void Jump()= 0; - virtual bool OnGround()= 0; - - virtual float GetGravity()= 0; - virtual void SetGravity(float gravity)= 0; - - virtual unsigned char GetMaxJumps() = 0; - virtual void SetMaxJumps(unsigned char maxJumps) = 0; - - virtual unsigned char GetJumpCount() = 0; - - virtual void SetWalkDirection(const class MT_Vector3& dir)=0; - virtual MT_Vector3 GetWalkDirection()=0; - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:PHY_ICharacter") -#endif -}; - -#endif //__PHY_ICHARACTER_H__ diff --git a/source/gameengine/Physics/common/PHY_IPhysicsController.h b/source/gameengine/Physics/common/PHY_IPhysicsController.h deleted file mode 100644 index 195f4ccee4b0..000000000000 --- a/source/gameengine/Physics/common/PHY_IPhysicsController.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file PHY_IPhysicsController.h - * \ingroup phys - */ - -#ifndef __PHY_IPHYSICSCONTROLLER_H__ -#define __PHY_IPHYSICSCONTROLLER_H__ - -#include -#include "PHY_IController.h" - -class PHY_IMotionState; -class PHY_IPhysicsEnvironment; - -class MT_Vector3; -class MT_Point3; -class MT_Matrix3x3; - -class KX_GameObject; -class RAS_MeshObject; - -/** - * PHY_IPhysicsController is the abstract simplified Interface to a physical object. - * It contains the IMotionState and IDeformableMesh Interfaces. - */ -class PHY_IPhysicsController : public PHY_IController -{ - - public: - virtual ~PHY_IPhysicsController() {}; - /** - * SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding') - */ - virtual bool SynchronizeMotionStates(float time)=0; - /** - * WriteMotionStateToDynamics ynchronizes dynas, kinematic and deformable entities (and do 'late binding') - */ - - virtual void WriteMotionStateToDynamics(bool nondynaonly)=0; - virtual void WriteDynamicsToMotionState()=0; - virtual class PHY_IMotionState* GetMotionState() = 0; - // controller replication - virtual void PostProcessReplica(class PHY_IMotionState* motionstate,class PHY_IPhysicsController* parentctrl)=0; - virtual void SetPhysicsEnvironment(class PHY_IPhysicsEnvironment *env)=0; - - // kinematic methods - virtual void RelativeTranslate(const MT_Vector3& dloc,bool local)=0; - virtual void RelativeRotate(const MT_Matrix3x3&,bool local)=0; - virtual MT_Matrix3x3 GetOrientation()=0; - virtual void SetOrientation(const MT_Matrix3x3& orn)=0; - virtual void SetPosition(const MT_Vector3& pos)=0; - virtual void GetPosition(MT_Vector3& pos) const=0; - virtual void SetScaling(const MT_Vector3& scale)=0; - virtual void SetTransform()=0; - - virtual MT_Scalar GetMass()=0; - virtual void SetMass(MT_Scalar newmass)=0; - - // physics methods - virtual void ApplyImpulse(const MT_Point3& attach, const MT_Vector3& impulse,bool local)=0; - virtual void ApplyTorque(const MT_Vector3& torque,bool local)=0; - virtual void ApplyForce(const MT_Vector3& force,bool local)=0; - virtual void SetAngularVelocity(const MT_Vector3& ang_vel,bool local)=0; - virtual void SetLinearVelocity(const MT_Vector3& lin_vel,bool local)=0; - virtual void ResolveCombinedVelocities(float linvelX,float linvelY,float linvelZ,float angVelX,float angVelY,float angVelZ) = 0; - - virtual float GetLinearDamping() const=0; - virtual float GetAngularDamping() const=0; - virtual void SetLinearDamping(float damping)=0; - virtual void SetAngularDamping(float damping)=0; - virtual void SetDamping(float linear, float angular)=0; - - virtual void RefreshCollisions() = 0; - virtual void SuspendDynamics(bool ghost=false)=0; - virtual void RestoreDynamics()=0; - - virtual void SetActive(bool active)=0; - - // reading out information from physics - virtual MT_Vector3 GetLinearVelocity()=0; - virtual MT_Vector3 GetAngularVelocity()=0; - virtual MT_Vector3 GetVelocity(const MT_Point3& pos)=0; - virtual MT_Vector3 GetLocalInertia()=0; - - // dyna's that are rigidbody are free in orientation, dyna's with non-rigidbody are restricted - virtual void SetRigidBody(bool rigid)=0; - - virtual PHY_IPhysicsController* GetReplica() {return 0;} - virtual PHY_IPhysicsController* GetReplicaForSensors() {return 0;} - - virtual void CalcXform() =0; - virtual void SetMargin(float margin) =0; - virtual float GetMargin() const=0; - virtual float GetRadius() const=0; - virtual void SetRadius(float margin) = 0; - - virtual float GetLinVelocityMin() const=0; - virtual void SetLinVelocityMin(float val) = 0; - virtual float GetLinVelocityMax() const=0; - virtual void SetLinVelocityMax(float val) = 0; - - virtual void SetAngularVelocityMin(float val) = 0; - virtual float GetAngularVelocityMin() const = 0; - virtual void SetAngularVelocityMax(float val) = 0; - virtual float GetAngularVelocityMax() const = 0; - - MT_Vector3 GetWorldPosition(MT_Vector3& localpos); - - // Shape control - virtual void AddCompoundChild(PHY_IPhysicsController* child) = 0; - virtual void RemoveCompoundChild(PHY_IPhysicsController* child) = 0; - - - virtual bool IsDynamic() = 0; - virtual bool IsCompound() = 0; - virtual bool IsSuspended() const = 0; - - virtual bool ReinstancePhysicsShape(KX_GameObject *from_gameobj, RAS_MeshObject* from_meshobj) = 0; - - /* Method to replicate rigid body joint contraints for group instances. */ - virtual void ReplicateConstraints(KX_GameObject *gameobj, std::vector constobj) = 0; - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:PHY_IPhysicsController") -#endif -}; - -#endif /* __PHY_IPHYSICSCONTROLLER_H__ */ diff --git a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h deleted file mode 100644 index 59612b10b574..000000000000 --- a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file PHY_IPhysicsEnvironment.h - * \ingroup phys - */ - -#ifndef __PHY_IPHYSICSENVIRONMENT_H__ -#define __PHY_IPHYSICSENVIRONMENT_H__ - -#include "PHY_DynamicTypes.h" -#include "MT_Vector2.h" -#include "MT_Vector3.h" -#include "MT_Vector4.h" - -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -class PHY_IVehicle; -class PHY_ICharacter; -class RAS_MeshObject; -class PHY_IPhysicsController; - - -class RAS_MeshObject; -struct DerivedMesh; -class KX_GameObject; -class KX_Scene; - -struct PHY_ShapeProps; -struct PHY_MaterialProps; -class PHY_IMotionState; -struct bRigidBodyJointConstraint; - -/** - * pass back information from rayTest - */ -struct PHY_RayCastResult -{ - PHY_IPhysicsController* m_controller; - MT_Vector3 m_hitPoint; - MT_Vector3 m_hitNormal; - const RAS_MeshObject* m_meshObject; // !=NULL for mesh object (only for Bullet controllers) - int m_polygon; // index of the polygon hit by the ray, - // only if m_meshObject != NULL - int m_hitUVOK; // !=0 if UV coordinate in m_hitUV is valid - MT_Vector2 m_hitUV; // UV coordinates of hit point -}; - -/** - * This class replaces the ignoreController parameter of rayTest function. - * It allows more sophisticated filtering on the physics controller before computing the ray intersection to save CPU. - * It is only used to its full extend by the Ccd physics environment (Bullet). - */ -class PHY_IRayCastFilterCallback -{ -public: - PHY_IPhysicsController* m_ignoreController; - bool m_faceNormal; - bool m_faceUV; - - virtual ~PHY_IRayCastFilterCallback() - { - } - - virtual bool needBroadphaseRayCast(PHY_IPhysicsController* controller) - { - return true; - } - - virtual void reportHit(PHY_RayCastResult* result) = 0; - - PHY_IRayCastFilterCallback(PHY_IPhysicsController* ignoreController, bool faceNormal=false, bool faceUV=false) - :m_ignoreController(ignoreController), - m_faceNormal(faceNormal), - m_faceUV(faceUV) - { - } - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:PHY_IRayCastFilterCallback") -#endif -}; - -/** - * Physics Environment takes care of stepping the simulation and is a container for physics entities - * (rigidbodies,constraints, materials etc.) - * A derived class may be able to 'construct' entities by loading and/or converting - */ -class PHY_IPhysicsEnvironment -{ - public: - virtual ~PHY_IPhysicsEnvironment() {} - virtual void BeginFrame() = 0; - virtual void EndFrame() = 0; - /// Perform an integration step of duration 'timeStep'. - virtual bool ProceedDeltaTime(double curTime,float timeStep,float interval)=0; - ///draw debug lines (make sure to call this during the render phase, otherwise lines are not drawn properly) - virtual void DebugDrawWorld() {} - virtual void SetFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep)=0; - //returns 0.f if no fixed timestep is used - virtual float GetFixedTimeStep()=0; - - ///getDebugMode return the actual debug visualization state - virtual int GetDebugMode()const=0; - ///setDebugMode is used to support several ways of debug lines, contact point visualization - virtual void SetDebugMode(int debugMode) {} - ///setNumIterations set the number of iterations for iterative solvers - virtual void SetNumIterations(int numIter) {} - ///setNumTimeSubSteps set the number of divisions of the timestep. Tradeoff quality versus performance. - virtual void SetNumTimeSubSteps(int numTimeSubSteps) {} - virtual int GetNumTimeSubSteps() {return 0; } - ///setDeactivationTime sets the minimum time that an objects has to stay within the velocity tresholds until it gets fully deactivated - virtual void SetDeactivationTime(float dTime) {} - ///setDeactivationLinearTreshold sets the linear velocity treshold, see setDeactivationTime - virtual void SetDeactivationLinearTreshold(float linTresh) {} - ///setDeactivationAngularTreshold sets the angular velocity treshold, see setDeactivationTime - virtual void SetDeactivationAngularTreshold(float angTresh) {} - ///setContactBreakingTreshold sets tresholds to do with contact point management - virtual void SetContactBreakingTreshold(float contactBreakingTreshold) {} - ///continuous collision detection mode, very experimental for Bullet - virtual void SetCcdMode(int ccdMode) {} - ///successive overrelaxation constant, in case PSOR is used, values in between 1 and 2 guarantee converging behavior - virtual void SetSolverSorConstant(float sor) {} - ///setSolverType, internal setting, chooses solvertype, PSOR, Dantzig, impulse based, penalty based - virtual void SetSolverType(int solverType) {} - ///setTau sets the spring constant of a penalty based solver - virtual void SetSolverTau(float tau) {} - ///setDamping sets the damper constant of a penalty based solver - virtual void SetSolverDamping(float damping) {} - ///linear air damping for rigidbodies - virtual void SetLinearAirDamping(float damping) {} - /// penetrationdepth setting - virtual void SetUseEpa(bool epa) {} - - virtual void SetGravity(float x,float y,float z)=0; - virtual void GetGravity(MT_Vector3& grav) = 0; - - virtual int CreateConstraint(class PHY_IPhysicsController* ctrl,class PHY_IPhysicsController* ctrl2,PHY_ConstraintType type, - float pivotX,float pivotY,float pivotZ, - float axis0X,float axis0Y,float axis0Z, - float axis1X=0,float axis1Y=0,float axis1Z=0, - float axis2X=0,float axis2Y=0,float axis2Z=0,int flag=0 - )=0; - virtual void RemoveConstraintById(int constraintid) = 0; - virtual float GetAppliedImpulse(int constraintid) { return 0.0f; } - - - //complex constraint for vehicles - virtual PHY_IVehicle* GetVehicleConstraint(int constraintId) =0; - - // Character physics wrapper - virtual PHY_ICharacter* GetCharacterController(class KX_GameObject* ob) =0; - - virtual PHY_IPhysicsController* RayTest(PHY_IRayCastFilterCallback &filterCallback, float fromX,float fromY,float fromZ, float toX,float toY,float toZ)=0; - - //culling based on physical broad phase - // the plane number must be set as follow: near, far, left, right, top, botton - // the near plane must be the first one and must always be present, it is used to get the direction of the view - virtual bool CullingTest(PHY_CullingCallback callback, void *userData, MT_Vector4* planeNormals, int planeNumber, int occlusionRes, const int *viewport, float modelview[16], float projection[16]) = 0; - - //Methods for gamelogic collision/physics callbacks - //todo: - virtual void AddSensor(PHY_IPhysicsController* ctrl)=0; - virtual void RemoveSensor(PHY_IPhysicsController* ctrl)=0; - virtual void AddTouchCallback(int response_class, PHY_ResponseCallback callback, void *user)=0; - virtual bool RequestCollisionCallback(PHY_IPhysicsController* ctrl)=0; - virtual bool RemoveCollisionCallback(PHY_IPhysicsController* ctrl)=0; - //These two methods are *solely* used to create controllers for sensor! Don't use for anything else - virtual PHY_IPhysicsController* CreateSphereController(float radius,const MT_Vector3& position) =0; - virtual PHY_IPhysicsController* CreateConeController(float coneradius,float coneheight)=0; - - virtual void SetConstraintParam(int constraintId,int param,float value,float value1) = 0; - virtual float GetConstraintParam(int constraintId,int param) = 0; - - virtual void ExportFile(const char* filename) {}; - - virtual void MergeEnvironment(PHY_IPhysicsEnvironment *other_env) = 0; - - virtual void ConvertObject(KX_GameObject* gameobj, - RAS_MeshObject* meshobj, - DerivedMesh* dm, - KX_Scene* kxscene, - PHY_ShapeProps* shapeprops, - PHY_MaterialProps* smmaterial, - PHY_IMotionState *motionstate, - int activeLayerBitInfo, - bool isCompoundChild, - bool hasCompoundChildren) = 0; - - /* Set the rigid body joints constraints values for converted objects and replicated group instances. */ - virtual void SetupObjectConstraints(KX_GameObject *obj_src, KX_GameObject *obj_dest, - bRigidBodyJointConstraint *dat) {} - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:PHY_IPhysicsEnvironment") -#endif -}; - -#endif /* __PHY_IPHYSICSENVIRONMENT_H__ */ diff --git a/source/gameengine/Physics/common/PHY_IVehicle.h b/source/gameengine/Physics/common/PHY_IVehicle.h deleted file mode 100644 index 94676807be9c..000000000000 --- a/source/gameengine/Physics/common/PHY_IVehicle.h +++ /dev/null @@ -1,69 +0,0 @@ - -/** \file PHY_IVehicle.h - * \ingroup phys - */ - -#ifndef __PHY_IVEHICLE_H__ -#define __PHY_IVEHICLE_H__ - -//PHY_IVehicle provides a generic interface for (raycast based) vehicles. Mostly targetting 4 wheel cars and 2 wheel motorbikes. - -class PHY_IMotionState; -#include "PHY_DynamicTypes.h" - -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -class PHY_IVehicle -{ -public: - virtual ~PHY_IVehicle() {}; - - virtual void AddWheel( - PHY_IMotionState* motionState, - MT_Vector3 connectionPoint, - MT_Vector3 downDirection, - MT_Vector3 axleDirection, - float suspensionRestLength, - float wheelRadius, - bool hasSteering - ) = 0; - - - virtual int GetNumWheels() const = 0; - - virtual void GetWheelPosition(int wheelIndex,float& posX,float& posY,float& posZ) const = 0; - virtual void GetWheelOrientationQuaternion(int wheelIndex,float& quatX,float& quatY,float& quatZ,float& quatW) const = 0; - virtual float GetWheelRotation(int wheelIndex) const = 0; - - virtual int GetUserConstraintId() const =0; - virtual int GetUserConstraintType() const =0; - - //some basic steering/braking/tuning/balancing (bikes) - - virtual void SetSteeringValue(float steering,int wheelIndex) = 0; - - virtual void ApplyEngineForce(float force,int wheelIndex) = 0; - - virtual void ApplyBraking(float braking,int wheelIndex) = 0; - - virtual void SetWheelFriction(float friction,int wheelIndex) = 0; - - virtual void SetSuspensionStiffness(float suspensionStiffness,int wheelIndex) = 0; - - virtual void SetSuspensionDamping(float suspensionStiffness,int wheelIndex) = 0; - - virtual void SetSuspensionCompression(float suspensionStiffness,int wheelIndex) = 0; - - virtual void SetRollInfluence(float rollInfluence,int wheelIndex) = 0; - - virtual void SetCoordinateSystem(int rightIndex,int upIndex,int forwardIndex) =0; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:PHY_IVehicle") -#endif -}; - -#endif /* __PHY_IVEHICLE_H__ */ diff --git a/source/gameengine/Physics/common/PHY_Pro.h b/source/gameengine/Physics/common/PHY_Pro.h deleted file mode 100644 index 632cd9bb9fb9..000000000000 --- a/source/gameengine/Physics/common/PHY_Pro.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file PHY_Pro.h - * \ingroup phys - */ - -#ifndef __PHY_PRO_H__ -#define __PHY_PRO_H__ - -#include - -// Properties of dynamic objects -struct PHY_ShapeProps { - MT_Scalar m_mass; // Total mass - MT_Scalar m_inertia; // Inertia, should be a tensor some time - MT_Scalar m_lin_drag; // Linear drag (air, water) 0 = concrete, 1 = vacuum, inverted and called dampening in blenders UI - MT_Scalar m_ang_drag; // Angular drag, inverted and called dampening in blenders UI - MT_Scalar m_friction_scaling[3]; // Scaling for anisotropic friction. Component in range [0, 1] - MT_Scalar m_clamp_vel_min; // Clamp the minimum velocity, this ensures an object moves at a minimum speed unless its stationary - MT_Scalar m_clamp_vel_max; // Clamp max velocity - MT_Scalar m_clamp_angvel_min; // Clamp the minimum angular velocity. - MT_Scalar m_clamp_angvel_max; // Clamp the maximum angular velocity. - bool m_do_anisotropic; // Should I do anisotropic friction? - bool m_do_fh; // Should the object have a linear Fh spring? - bool m_do_rot_fh; // Should the object have an angular Fh spring? - MT_Scalar m_step_height; // Max height of climbable steps (Character) - MT_Scalar m_jump_speed; // Velocity of jumps (Character) - MT_Scalar m_fall_speed; // Max velocity of falling (Character) - unsigned char m_max_jumps; // Max ammount of jumps (Character) -}; - - -// Properties of collidable objects (non-ghost objects) -struct PHY_MaterialProps { - MT_Scalar m_restitution; // restitution of energie after a collision 0 = inelastic, 1 = elastic - MT_Scalar m_friction; // Coulomb friction (= ratio between the normal en maximum friction force) - MT_Scalar m_fh_spring; // Spring constant (both linear and angular) - MT_Scalar m_fh_damping; // Damping factor (linear and angular) in range [0, 1] - MT_Scalar m_fh_distance; // The range above the surface where Fh is active. - bool m_fh_normal; // Should the object slide off slopes? -}; - -#endif /* __PHY_PRO_H__ */ diff --git a/source/gameengine/Rasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/CMakeLists.txt index fc7dc90e03b4..ec563a37cbac 100644 --- a/source/gameengine/Rasterizer/CMakeLists.txt +++ b/source/gameengine/Rasterizer/CMakeLists.txt @@ -25,68 +25,126 @@ set(INC . + Node + RAS_OpenGLRasterizer + ../Common + ../Converter ../Expressions ../Ketsji + ../Physics/Common ../SceneGraph + ../GameLogic ../../blender/makesdna + ../../blender/blenfont ../../blender/blenlib ../../blender/blenkernel ../../blender/gpu ../../blender/imbuf - ../../../intern/container ../../../intern/glew-mx ../../../intern/guardedalloc - ../../../intern/string + ../../../intern/termcolor ) set(INC_SYS - ../../../intern/moto/include + ../../../intern/debugbreak + ../../../intern/mathfu ${GLEW_INCLUDE_PATH} ${PYTHON_INCLUDE_DIRS} + ${BOOST_INCLUDE_DIR} ) set(SRC + RAS_2DFilter.cpp + RAS_2DFilterData.cpp RAS_2DFilterManager.cpp + RAS_2DFilterOffScreen.cpp + RAS_AttributeArray.cpp + RAS_AttributeArrayStorage.cpp + RAS_BatchDisplayArray.cpp + RAS_BatchGroup.cpp + RAS_BoundingBox.cpp + RAS_BoundingBoxManager.cpp RAS_BucketManager.cpp + RAS_DebugDraw.cpp + RAS_Deformer.cpp + RAS_DisplayArray.cpp + RAS_DisplayArrayBucket.cpp + RAS_DisplayArrayStorage.cpp RAS_FramingManager.cpp - RAS_IPolygonMaterial.cpp - RAS_MaterialBucket.cpp - RAS_MeshObject.cpp - RAS_Polygon.cpp - RAS_TexVert.cpp - RAS_texmatrix.cpp RAS_ICanvas.cpp + RAS_InstancingBuffer.cpp + RAS_IMaterial.cpp + RAS_Rasterizer.cpp + RAS_MaterialBucket.cpp + RAS_MeshMaterial.cpp + RAS_Mesh.cpp + RAS_MeshSlot.cpp + RAS_MeshUser.cpp + RAS_OffScreen.cpp + RAS_Query.cpp + RAS_Shader.cpp + RAS_Texture.cpp + RAS_TextureRenderer.cpp + RAS_TextUser.cpp + RAS_VertexInfo.cpp + RAS_2DFilterData.h + RAS_2DFilter.h RAS_2DFilterManager.h + RAS_2DFilterOffScreen.h + RAS_AttributeArray.h + RAS_AttributeArrayStorage.h + RAS_BatchDisplayArray.h + RAS_BatchGroup.h + RAS_BoundingBox.h + RAS_BoundingBoxManager.h RAS_BucketManager.h RAS_CameraData.h + RAS_DebugDraw.h RAS_Deformer.h + RAS_DisplayArray.h + RAS_DisplayArrayBucket.h + RAS_DisplayArrayStorage.h RAS_FramingManager.h RAS_ICanvas.h - RAS_IPolygonMaterial.h - RAS_IRasterizer.h + RAS_IMaterial.h + RAS_Rasterizer.h RAS_ILightObject.h - RAS_IOffScreen.h + RAS_InstancingBuffer.h RAS_ISync.h RAS_MaterialBucket.h - RAS_MeshObject.h - RAS_ObjectColor.h - RAS_Polygon.h + RAS_MeshMaterial.h + RAS_Mesh.h + RAS_MeshSlot.h + RAS_MeshUser.h + RAS_OffScreen.h + RAS_Query.h RAS_Rect.h - RAS_TexMatrix.h - RAS_TexVert.h - RAS_OpenGLFilters/RAS_Blur2DFilter.h - RAS_OpenGLFilters/RAS_Dilation2DFilter.h - RAS_OpenGLFilters/RAS_Erosion2DFilter.h - RAS_OpenGLFilters/RAS_GrayScale2DFilter.h - RAS_OpenGLFilters/RAS_Invert2DFilter.h - RAS_OpenGLFilters/RAS_Laplacian2DFilter.h - RAS_OpenGLFilters/RAS_Prewitt2DFilter.h - RAS_OpenGLFilters/RAS_Sepia2DFilter.h - RAS_OpenGLFilters/RAS_Sharpen2DFilter.h - RAS_OpenGLFilters/RAS_Sobel2DFilter.h + RAS_Shader.h + RAS_Texture.h + RAS_TextureRenderer.h + RAS_TextUser.h + RAS_VertexInfo.h ) +data_to_c_simple(RAS_OpenGLFilters/RAS_Blur2DFilter.glsl SRC) +data_to_c_simple(RAS_OpenGLFilters/RAS_Dilation2DFilter.glsl SRC) +data_to_c_simple(RAS_OpenGLFilters/RAS_Erosion2DFilter.glsl SRC) +data_to_c_simple(RAS_OpenGLFilters/RAS_GrayScale2DFilter.glsl SRC) +data_to_c_simple(RAS_OpenGLFilters/RAS_Invert2DFilter.glsl SRC) +data_to_c_simple(RAS_OpenGLFilters/RAS_Laplacian2DFilter.glsl SRC) +data_to_c_simple(RAS_OpenGLFilters/RAS_Prewitt2DFilter.glsl SRC) +data_to_c_simple(RAS_OpenGLFilters/RAS_Sepia2DFilter.glsl SRC) +data_to_c_simple(RAS_OpenGLFilters/RAS_Sharpen2DFilter.glsl SRC) +data_to_c_simple(RAS_OpenGLFilters/RAS_Sobel2DFilter.glsl SRC) +data_to_c_simple(RAS_OpenGLFilters/RAS_VertexShader2DFilter.glsl SRC) + add_definitions(${GL_DEFINITIONS}) +# ---------------------------------------------------------------------------------------------------------------- +# workaround to increase the number of sections for object file format in MSVC 2015 compiler when we DEBUG +if(MSVC14) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj /Zi /Od /Ob0") +endif() + blender_add_lib(ge_rasterizer "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/gameengine/Rasterizer/Node/CMakeLists.txt b/source/gameengine/Rasterizer/Node/CMakeLists.txt new file mode 100644 index 000000000000..628c26d4c4bd --- /dev/null +++ b/source/gameengine/Rasterizer/Node/CMakeLists.txt @@ -0,0 +1,19 @@ +# ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# Contributor(s): Tristan Porteries. +# +# ***** END GPL LICENSE BLOCK ***** diff --git a/source/gameengine/Rasterizer/Node/RAS_BaseNode.h b/source/gameengine/Rasterizer/Node/RAS_BaseNode.h new file mode 100644 index 000000000000..15433242b724 --- /dev/null +++ b/source/gameengine/Rasterizer/Node/RAS_BaseNode.h @@ -0,0 +1,92 @@ +/* +* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* Contributor(s): Porteries Tristan. +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +#ifndef __RAS_BASIC_NODE__ +#define __RAS_BASIC_NODE__ + +/** RAS_BaseNode is a class wrapping a rendering class by simulating it with a + * binding and unbinding function. + * \param NodeInfo The node information. + */ +template +class RAS_BaseNode +{ +public: + using OwnerType = typename NodeInfo::OwnerType; + using TupleType = typename NodeInfo::TupleType; + using DataType = typename NodeInfo::DataType; + using Leaf = typename NodeInfo::Leaf; + + /** The type of function to call for binding and unbinding. + * It takes as arguments the tuple containing the data of the parent nodes. + */ + using Function = void (OwnerType::*)(const TupleType&); + +protected: + /// An instance of the wrapped class. + OwnerType *m_owner; + DataType *m_data; + + Function m_bind; + Function m_unbind; + +public: + RAS_BaseNode(OwnerType *owner, DataType *data, Function bind, Function unbind) + :m_owner(owner), + m_data(data), + m_bind(bind), + m_unbind(unbind) + { + } + + RAS_BaseNode() = default; + + ~RAS_BaseNode() + { + } + + inline OwnerType *GetOwner() const + { + return m_owner; + } + + inline DataType *GetData() const + { + return m_data; + } + + inline void Bind(const TupleType& tuple) + { + if (m_bind) { + (m_owner->*m_bind)(tuple); + } + } + + inline void Unbind(const TupleType& tuple) + { + if (m_unbind) { + (m_owner->*m_unbind)(tuple); + } + } +}; + +#endif // __RAS_BASIC_NODE__ diff --git a/source/gameengine/Rasterizer/Node/RAS_DownwardNode.h b/source/gameengine/Rasterizer/Node/RAS_DownwardNode.h new file mode 100644 index 000000000000..517f7f3bd549 --- /dev/null +++ b/source/gameengine/Rasterizer/Node/RAS_DownwardNode.h @@ -0,0 +1,149 @@ +/* +* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* Contributor(s): Porteries Tristan. +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +#ifndef __RAS_DOWNWARD_NODE_H__ +#define __RAS_DOWNWARD_NODE_H__ + +#include "RAS_BaseNode.h" +#include "RAS_DummyNode.h" + +#include + +#ifdef DEBUG +# include +# include +#endif // DEBUG + +/** RAS_DownwardNode is a node which store its children nodes. + * + * A downward node is using for unsorted render when the bind and unbind call can be proceed + * by iterating from the top of the tree to the bottom. + * Each downward node in render process call its bind function then render all its children + * nodes and finally call its unbind function. + * + * \param _ChildType The children node type. + */ +template +class RAS_DownwardNode : public RAS_BaseNode +{ +public: + using typename RAS_BaseNode::OwnerType; + using typename RAS_BaseNode::DataType; + using typename RAS_BaseNode::TupleType; + using typename RAS_BaseNode::Leaf; + using typename RAS_BaseNode::Function; + typedef _ChildType ChildType; + typedef std::vector ChildTypeList; + +private: + ChildTypeList m_children; + +public: + RAS_DownwardNode(OwnerType *owner, DataType *data, Function bind, Function unbind) + :RAS_BaseNode(owner, data, bind, unbind) + { + } + + RAS_DownwardNode() = default; + + ~RAS_DownwardNode() + { + } + + /** Returning true when a node is valid. A node is valid if it is always final or + * if it has at least one children. + */ + inline bool GetValid() const + { + if (!Leaf()) { + return !m_children.empty(); + } + return true; + } + + /// Add a child node if it is valid. + inline void AddChild(ChildType *child) + { + if (child->GetValid()) { + m_children.push_back(child); + } + } + + inline void Clear() + { + if (!Leaf()) { + m_children.clear(); + } + } + + /** Recursive function calling the bind function, call itsefl in children nodes + * and calling unbind function. + * \param tuple The function tuple argument to use for binding and unbinding. + */ + template + inline typename std::enable_if::value, void>::type + Execute(const TupleType& tuple) + { + this->Bind(tuple); + + typename ChildType::TupleType childTuple(tuple, this->m_data); + for (ChildType *child : m_children) { + child->Execute(childTuple); + } + + this->Unbind(tuple); + + // In the same time we can remove the children nodes. + Clear(); + } + + /// Function override to avoid try creating a RAS_DummyNodeTuple with arguments. + template + inline typename std::enable_if::value, void>::type + Execute(const TupleType& tuple) + { + this->Bind(tuple); + + this->Unbind(tuple); + + // No need to clear as dummy node are never instanced. + } + +#ifdef DEBUG + void Print(unsigned short level, bool recursive) const + { + for (unsigned short i = 0; i < level; ++i) { + std::cout << "\t"; + } + + std::cout << boost::typeindex::type_id().pretty_name() << "(" << this->m_owner << ") "<< std::endl; + + if (recursive) { + for (ChildType *child : m_children) { + child->Print(level + 1, recursive); + } + } + } +#endif // DEBUG +}; + +#endif // __RAS_DOWNWARD_NODE_H__ diff --git a/source/gameengine/Rasterizer/Node/RAS_DummyNode.h b/source/gameengine/Rasterizer/Node/RAS_DummyNode.h new file mode 100644 index 000000000000..e69c6948aa5d --- /dev/null +++ b/source/gameengine/Rasterizer/Node/RAS_DummyNode.h @@ -0,0 +1,46 @@ +/* +* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* Contributor(s): Porteries Tristan. +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +#ifndef __RAS_DUMMY_NODE_H__ +#define __RAS_DUMMY_NODE_H__ + +struct RAS_DummyNodeData +{ +}; + +struct RAS_DummyNodeTuple +{ +}; + +class RAS_DummyNode +{ +public: + using DataType = RAS_DummyNodeData; + using TupleType = RAS_DummyNodeTuple; + typedef RAS_DummyNode ParentType; + + void Print(unsigned short level, bool recursive) + { + } +}; + +#endif // __RAS_DUMMY_NODE_H__ diff --git a/source/gameengine/Rasterizer/Node/RAS_RenderNode.h b/source/gameengine/Rasterizer/Node/RAS_RenderNode.h new file mode 100644 index 000000000000..59e6a1692055 --- /dev/null +++ b/source/gameengine/Rasterizer/Node/RAS_RenderNode.h @@ -0,0 +1,253 @@ +/* +* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* Contributor(s): Porteries Tristan. +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +#ifndef __RAS_RENDER_NODE__ +#define __RAS_RENDER_NODE__ + +#include "RAS_DownwardNode.h" +#include "RAS_UpwardNode.h" +#include "RAS_UpwardNodeIterator.h" +#include "RAS_Rasterizer.h" + +#include + +class RAS_BucketManager; +class RAS_MaterialBucket; +class RAS_DisplayArray; +class RAS_DisplayArrayBucket; +class RAS_MeshSlot; +class RAS_IMaterial; +class RAS_Rasterizer; +class RAS_DisplayArrayStorage; +class RAS_AttributeArrayStorage; + +class RAS_MaterialDownwardNode; +class RAS_ManagerDownwardNode; +class RAS_DisplayArrayDownwardNode; + +class RAS_MaterialUpwardNode; +class RAS_ManagerUpwardNode; +class RAS_DisplayArrayUpwardNode; +class RAS_MeshSlotUpwardNode; + +struct RAS_ManagerNodeData +{ + mt::mat3x4 m_trans; + RAS_Rasterizer *m_rasty; + RAS_Rasterizer::DrawType m_drawingMode; + bool m_sort; + bool m_shaderOverride; +}; + +struct RAS_MaterialNodeData +{ + RAS_IMaterial *m_material; + int m_drawingMode; + bool m_cullFace; + bool m_zsort; + bool m_text; + float m_zoffset; +}; + +struct RAS_DisplayArrayNodeData +{ + RAS_DisplayArray *m_array; + RAS_AttributeArrayStorage *m_attribStorage; + RAS_DisplayArrayStorage *m_arrayStorage; + bool m_applyMatrix; + RAS_InstancingBuffer *m_instancingBuffer; +}; + +struct RAS_MeshSlotNodeData +{ +}; + +/// Data passed to material node. +struct RAS_MaterialNodeTuple +{ + RAS_ManagerNodeData *m_managerData; + + RAS_MaterialNodeTuple(const RAS_DummyNodeTuple& dummyTuple, RAS_ManagerNodeData *managerData) + :m_managerData(managerData) + { + } +}; + +/// Data passed to display array node. +struct RAS_DisplayArrayNodeTuple : RAS_MaterialNodeTuple +{ + RAS_MaterialNodeData *m_materialData; + + RAS_DisplayArrayNodeTuple(const RAS_MaterialNodeTuple& materialTuple, RAS_MaterialNodeData *materialData) + :RAS_MaterialNodeTuple(materialTuple), + m_materialData(materialData) + { + } +}; + +/// Data passed to mesh slot node. +struct RAS_MeshSlotNodeTuple : RAS_DisplayArrayNodeTuple +{ + RAS_DisplayArrayNodeData *m_displayArrayData; + + RAS_MeshSlotNodeTuple(const RAS_DisplayArrayNodeTuple& displayArrayTuple, RAS_DisplayArrayNodeData *displayArrayData) + :RAS_DisplayArrayNodeTuple(displayArrayTuple), + m_displayArrayData(displayArrayData) + { + } +}; + +struct RAS_ManagerNodeInfo +{ + /// Wrapped type owning the node. + using OwnerType = RAS_BucketManager; + /// Data the node will pass to the sub node. + using DataType = RAS_ManagerNodeData; + /// Data tuple used in bind/unbind functions. + using TupleType = RAS_DummyNodeTuple; + /// True if the node is a leaf/final. + using Leaf = std::false_type; +}; + +struct RAS_MaterialNodeInfo +{ + using OwnerType = RAS_MaterialBucket; + using DataType = RAS_MaterialNodeData; + using TupleType = RAS_MaterialNodeTuple; + using Leaf = std::false_type; +}; + +/// Node info for display array for the downward tree, this node is a leaf. +struct RAS_DisplayArrayDownwardNodeInfo +{ + using OwnerType = RAS_DisplayArrayBucket; + using DataType = RAS_DisplayArrayNodeData; + using TupleType = RAS_DisplayArrayNodeTuple; + using Leaf = std::true_type; +}; + +/// Node info for display array for the upward tree, this node is not a leaf. +struct RAS_DisplayArrayUpwardNodeInfo +{ + using OwnerType = RAS_DisplayArrayBucket; + using DataType = RAS_DisplayArrayNodeData; + using TupleType = RAS_DisplayArrayNodeTuple; + using Leaf = std::false_type; +}; + +struct RAS_MeshSlotNodeInfo +{ + using OwnerType = RAS_MeshSlot; + using DataType = RAS_DummyNodeData; + using TupleType = RAS_MeshSlotNodeTuple; + using Leaf = std::true_type; +}; + +class RAS_ManagerDownwardNode : public RAS_DownwardNode +{ +public: + RAS_ManagerDownwardNode(OwnerType *owner, DataType *data, Function bind, Function unbind) + :RAS_DownwardNode::RAS_DownwardNode(owner, data, bind, unbind) + { + } + + RAS_ManagerDownwardNode() = default; +}; + +class RAS_MaterialDownwardNode : public RAS_DownwardNode +{ +public: + RAS_MaterialDownwardNode(OwnerType *owner, DataType *data, Function bind, Function unbind) + :RAS_DownwardNode::RAS_DownwardNode(owner, data, bind, unbind) + { + } + + RAS_MaterialDownwardNode() = default; +}; + +class RAS_DisplayArrayDownwardNode : public RAS_DownwardNode +{ +public: + RAS_DisplayArrayDownwardNode(OwnerType *owner, DataType *data, Function bind, Function unbind) + :RAS_DownwardNode::RAS_DownwardNode(owner, data, bind, unbind) + { + } + + RAS_DisplayArrayDownwardNode() = default; +}; + +class RAS_ManagerUpwardNode : public RAS_UpwardNode +{ +public: + RAS_ManagerUpwardNode(OwnerType *owner, DataType *data, Function bind, Function unbind) + :RAS_UpwardNode::RAS_UpwardNode(owner, data, bind, unbind) + { + } + + RAS_ManagerUpwardNode() = default; +}; + +class RAS_MaterialUpwardNode : public RAS_UpwardNode +{ +public: + RAS_MaterialUpwardNode(OwnerType *owner, DataType *data, Function bind, Function unbind) + :RAS_UpwardNode::RAS_UpwardNode(owner, data, bind, unbind) + { + } + + RAS_MaterialUpwardNode() = default; +}; + +class RAS_DisplayArrayUpwardNode : public RAS_UpwardNode +{ +public: + RAS_DisplayArrayUpwardNode(OwnerType *owner, DataType *data, Function bind, Function unbind) + :RAS_UpwardNode::RAS_UpwardNode(owner, data, bind, unbind) + { + } + + RAS_DisplayArrayUpwardNode() = default; +}; + +class RAS_MeshSlotUpwardNode : public RAS_UpwardNode +{ +public: + RAS_MeshSlotUpwardNode(OwnerType *owner, DataType *data, Function bind, Function unbind) + :RAS_UpwardNode::RAS_UpwardNode(owner, data, bind, unbind) + { + } + + RAS_MeshSlotUpwardNode() = default; +}; + +typedef std::vector RAS_UpwardTreeLeafs; + +class RAS_MeshSlotUpwardNodeIterator : public RAS_UpwardNodeIterator +{ +public: + RAS_MeshSlotUpwardNodeIterator(NodeType *node) + :RAS_UpwardNodeIterator(node) + { + } +}; + +#endif // __RAS_RENDER_NODE__ diff --git a/source/gameengine/Rasterizer/Node/RAS_UpwardNode.h b/source/gameengine/Rasterizer/Node/RAS_UpwardNode.h new file mode 100644 index 000000000000..7ff1f917c7b5 --- /dev/null +++ b/source/gameengine/Rasterizer/Node/RAS_UpwardNode.h @@ -0,0 +1,92 @@ +/* +* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* Contributor(s): Porteries Tristan. +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +#ifndef __RAS_UPWARD_NODE_H__ +#define __RAS_UPWARD_NODE_H__ + +#include "RAS_BaseNode.h" + +#ifdef DEBUG +# include +# include +#endif // DEBUG + +/** RAS_UpwardNode is a node storing its parent node. + * + * A upward node is using for sorted render were two non-consecutive nodes could share + * the same parent node. In this case the render can be proceed from top to bottom, but + * from the bottom (leafs) to the bottom. This process is external in RAS_UpwardNodeIterator. + * + * \param _ParentType The parent node type. + */ +template +class RAS_UpwardNode : public RAS_BaseNode +{ +public: + using typename RAS_BaseNode::OwnerType; + using typename RAS_BaseNode::DataType; + using typename RAS_BaseNode::Function; + typedef _ParentType ParentType; + +private: + ParentType *m_parent; + +public: + RAS_UpwardNode(OwnerType *owner, DataType *data, Function bind, Function unbind) + :RAS_BaseNode(owner, data, bind, unbind), + m_parent(nullptr) + { + } + + RAS_UpwardNode() = default; + + ~RAS_UpwardNode() + { + } + + inline ParentType *GetParent() const + { + return m_parent; + } + + inline void SetParent(ParentType *parent) + { + m_parent = parent; + } + +#ifdef DEBUG + void Print(unsigned short level, bool recursive) + { + for (unsigned short i = 0; i < level; ++i) { + std::cout << "\t"; + } + + std::cout << boost::typeindex::type_id().pretty_name() << "(" << this->m_owner << ") "<< std::endl; + + if (recursive) { + m_parent->Print(level + 1, recursive); + } + } +#endif // DEBUG +}; + +#endif // __RAS_UPWARD_NODE_H__ diff --git a/source/gameengine/Rasterizer/Node/RAS_UpwardNodeIterator.h b/source/gameengine/Rasterizer/Node/RAS_UpwardNodeIterator.h new file mode 100644 index 000000000000..7ffa2c97a60d --- /dev/null +++ b/source/gameengine/Rasterizer/Node/RAS_UpwardNodeIterator.h @@ -0,0 +1,135 @@ +#ifndef __RAS_UPWARD_NODE_VISITOR_H__ +#define __RAS_UPWARD_NODE_VISITOR_H__ + +#include "RAS_BaseNode.h" +#include "RAS_DummyNode.h" + +#include + +/** This class is a dummy node iterator doing none iteration. + * The node wrapped has the property to have also a dummy tuple. + */ +template +class RAS_DummyUpwardNodeIterator +{ +public: + using DataType = typename NodeType::DataType; + +private: + NodeType *m_node; + RAS_DummyNodeTuple m_tuple; + +public: + RAS_DummyUpwardNodeIterator(NodeType *node) + :m_node(node) + { + m_node->Bind(m_tuple); + } + + ~RAS_DummyUpwardNodeIterator() + { + m_node->Unbind(m_tuple); + } + + inline const RAS_DummyNodeTuple& GetTuple() const + { + return m_tuple; + } + + inline DataType *GetData() const + { + return m_node->GetData(); + } + + inline bool NextNode(NodeType *node) + { + return false; + } + + inline void Finish() + { + m_node->Unbind(m_tuple); + } +}; + +/** RAS_UpwardNodeIterator is class using to proceed the sorted render using RAS_UpwardNode. + * + * A sorted render is proceed comparing the parent node of the current node with the parent + * node of the previous node. If the both parent nodes are not the same, then the previous + * parent node is calling its unbinding function and the current parent node is calling its + * binding function. + * The same operation is done recursively for parent node of parent node. + * + * \param NodeType The upward node type. + */ +template +class RAS_UpwardNodeIterator +{ +public: + using NodeType = _NodeType; + using DataType = typename NodeType::DataType; + using ParentNodeType = typename NodeType::ParentType; + using TupleType = typename NodeType::TupleType; + using ParentTupleType = typename ParentNodeType::TupleType; + using ParentType = typename std::conditional< + std::is_same::value, + RAS_DummyUpwardNodeIterator, + RAS_UpwardNodeIterator >::type; + +private: + NodeType *m_node; + ParentType m_parent; + TupleType m_tuple; + +public: + RAS_UpwardNodeIterator(NodeType *node) + :m_node(node), + m_parent(node->GetParent()), + m_tuple(m_parent.GetTuple(), m_parent.GetData()) + { + m_node->Bind(m_tuple); + } + + ~RAS_UpwardNodeIterator() + { + m_node->Unbind(m_tuple); + } + + inline const TupleType& GetTuple() const + { + return m_tuple; + } + + inline DataType *GetData() const + { + return m_node->GetData(); + } + + inline bool NextNode(NodeType *node) + { + // If the parent node is unchanged, nothing is done. + if (node == m_node) { + return false; + } + + // The node must be bound before to have a valid m_tuple. + m_node->Unbind(m_tuple); + + /* Nodes request to be unbind or bind when their parent are kept bound. + * The nodes are then unbind before their parent and bind after their parent. + * This is proceeded by doing the recursive call between unbind and bind, unbind + * at recursion construction (upward), bind at recursion destruction (downward). + */ + if (m_parent.NextNode(node->GetParent())) { + // We regenerate tuple only when the parent node changed. + m_tuple = TupleType(m_parent.GetTuple(), m_parent.GetData()); + } + + m_node = node; + m_node->Bind(m_tuple); + + return true; + } +}; + +#endif // __RAS_UPWARD_NODE_VISITOR_H__ diff --git a/source/gameengine/Rasterizer/RAS_2DFilter.cpp b/source/gameengine/Rasterizer/RAS_2DFilter.cpp new file mode 100644 index 000000000000..90b4e8fbf504 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_2DFilter.cpp @@ -0,0 +1,293 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Pierluigi Grassi, Porteries Tristan. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "RAS_2DFilter.h" +#include "RAS_2DFilterManager.h" +#include "RAS_2DFilterOffScreen.h" +#include "RAS_Rasterizer.h" +#include "RAS_ICanvas.h" +#include "RAS_OffScreen.h" +#include "RAS_Rect.h" + +#include "EXP_Value.h" + +#include "GPU_glew.h" + +extern "C" { +extern char datatoc_RAS_VertexShader2DFilter_glsl[]; +} + +static std::string predefinedUniformsName[RAS_2DFilter::MAX_PREDEFINED_UNIFORM_TYPE] = { + "bgl_RenderedTexture", // RENDERED_TEXTURE_UNIFORM + "bgl_DepthTexture", // DEPTH_TEXTURE_UNIFORM + "bgl_RenderedTextureWidth", // RENDERED_TEXTURE_WIDTH_UNIFORM + "bgl_RenderedTextureHeight", // RENDERED_TEXTURE_HEIGHT_UNIFORM + "bgl_TextureCoordinateOffset" // TEXTURE_COORDINATE_OFFSETS_UNIFORM +}; + +RAS_2DFilter::RAS_2DFilter(RAS_2DFilterData& data) + :m_properties(data.propertyNames), + m_gameObject(data.gameObject), + m_uniformInitialized(false), + m_mipmap(data.mipmap) +{ + for (unsigned int i = 0; i < TEXTURE_OFFSETS_SIZE; i++) { + m_textureOffsets[i] = 0; + } + + for (unsigned int i = 0; i < MAX_PREDEFINED_UNIFORM_TYPE; ++i) { + m_predefinedUniforms[i] = -1; + } + + if (!data.shaderText.empty()) { + m_progs[VERTEX_PROGRAM] = std::string(datatoc_RAS_VertexShader2DFilter_glsl); + m_progs[FRAGMENT_PROGRAM] = data.shaderText; + + LinkProgram(); + } +} + +RAS_2DFilter::~RAS_2DFilter() +{ +} + +bool RAS_2DFilter::GetMipmap() const +{ + return m_mipmap; +} + +void RAS_2DFilter::SetMipmap(bool mipmap) +{ + m_mipmap = mipmap; +} + +RAS_2DFilterOffScreen *RAS_2DFilter::GetOffScreen() const +{ + return m_offScreen.get(); +} + +void RAS_2DFilter::SetOffScreen(RAS_2DFilterOffScreen *offScreen) +{ + m_offScreen.reset(offScreen); +} + +void RAS_2DFilter::Initialize(RAS_ICanvas *canvas) +{ + /* The shader must be initialized at the first frame when the canvas is accesible. + * to solve this we initialize filter at the frist render frame. */ + if (!m_uniformInitialized) { + ParseShaderProgram(); + ComputeTextureOffsets(canvas); + m_uniformInitialized = true; + } +} + +RAS_OffScreen *RAS_2DFilter::Render(RAS_Rasterizer *rasty, RAS_ICanvas *canvas, RAS_OffScreen *depthofs, + RAS_OffScreen *colorofs, RAS_OffScreen *targetofs) +{ + /* The off screen the filter rendered to. If the filter is invalid or uses a custom + * off screen the output off screen is the same as the input off screen. */ + RAS_OffScreen *outputofs = colorofs; + if (!Ok()) { + return outputofs; + } + + /* The target off screen must be not the color input off screen, it can be the same as depth input + * screen because depth is unchanged. */ + BLI_assert(targetofs != colorofs); + + if (m_offScreen) { + if (!m_offScreen->Update(canvas)) { + return outputofs; + } + + m_offScreen->Bind(rasty); + } + else { + targetofs->Bind(); + outputofs = targetofs; + } + + Initialize(canvas); + + BindProg(); + + BindTextures(depthofs, colorofs); + BindUniforms(canvas); + + Update(rasty, mt::mat4::Identity()); + + ApplyShader(); + + rasty->DrawOverlayPlane(); + + UnbindTextures(depthofs, colorofs); + + if (m_offScreen) { + m_offScreen->Unbind(rasty, canvas); + } + + UnbindProg(); + + return outputofs; +} + +bool RAS_2DFilter::LinkProgram() +{ + if (!RAS_Shader::LinkProgram()) { + return false; + } + + m_uniformInitialized = false; + + return true; +} + +void RAS_2DFilter::ParseShaderProgram() +{ + // Parse shader to found used uniforms. + for (unsigned int i = 0; i < MAX_PREDEFINED_UNIFORM_TYPE; ++i) { + m_predefinedUniforms[i] = GetUniformLocation(predefinedUniformsName[i], false); + } + + if (m_gameObject) { + std::vector foundProperties; + for (const std::string& prop : m_properties) { + const unsigned int loc = GetUniformLocation(prop, false); + if (loc != -1) { + m_propertiesLoc.push_back(loc); + foundProperties.push_back(prop); + } + } + m_properties = foundProperties; + } +} + +/* Fill the textureOffsets array with values used by the shaders to get texture samples + of nearby fragments. Or vertices or whatever.*/ +void RAS_2DFilter::ComputeTextureOffsets(RAS_ICanvas *canvas) +{ + const GLfloat texturewidth = (GLfloat)canvas->GetWidth(); + const GLfloat textureheight = (GLfloat)canvas->GetHeight(); + const GLfloat xInc = 1.0f / texturewidth; + const GLfloat yInc = 1.0f / textureheight; + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + m_textureOffsets[(((i * 3) + j) * 2) + 0] = (-1.0f * xInc) + ((GLfloat)i * xInc); + m_textureOffsets[(((i * 3) + j) * 2) + 1] = (-1.0f * yInc) + ((GLfloat)j * yInc); + } + } +} + +void RAS_2DFilter::BindTextures(RAS_OffScreen *depthofs, RAS_OffScreen *colorofs) +{ + if (m_predefinedUniforms[RENDERED_TEXTURE_UNIFORM] != -1) { + colorofs->BindColorTexture(8); + if (m_mipmap) { + colorofs->MipmapTexture(); + } + } + if (m_predefinedUniforms[DEPTH_TEXTURE_UNIFORM] != -1) { + depthofs->BindDepthTexture(9); + } + + // Bind custom textures. + for (const auto& pair : m_textures) { + glActiveTexture(GL_TEXTURE0 + pair.first); + glBindTexture(pair.second.first, pair.second.second); + } +} + +void RAS_2DFilter::UnbindTextures(RAS_OffScreen *depthofs, RAS_OffScreen *colorofs) +{ + if (m_predefinedUniforms[RENDERED_TEXTURE_UNIFORM] != -1) { + colorofs->UnbindColorTexture(); + if (m_mipmap) { + colorofs->UnmipmapTexture(); + } + } + if (m_predefinedUniforms[DEPTH_TEXTURE_UNIFORM] != -1) { + depthofs->UnbindDepthTexture(); + } + + // Unbind custom textures. + for (const auto& pair : m_textures) { + glActiveTexture(GL_TEXTURE0 + pair.first); + glBindTexture(pair.second.first, 0); + } + + glActiveTextureARB(GL_TEXTURE0); +} + +void RAS_2DFilter::BindUniforms(RAS_ICanvas *canvas) +{ + if (m_predefinedUniforms[RENDERED_TEXTURE_UNIFORM] != -1) { + SetUniform(m_predefinedUniforms[RENDERED_TEXTURE_UNIFORM], 8); + } + if (m_predefinedUniforms[DEPTH_TEXTURE_UNIFORM] != -1) { + SetUniform(m_predefinedUniforms[DEPTH_TEXTURE_UNIFORM], 9); + } + if (m_predefinedUniforms[RENDERED_TEXTURE_WIDTH_UNIFORM] != -1) { + // Bind rendered texture width. + const unsigned int texturewidth = canvas->GetWidth(); + SetUniform(m_predefinedUniforms[RENDERED_TEXTURE_WIDTH_UNIFORM], (float)texturewidth); + } + if (m_predefinedUniforms[RENDERED_TEXTURE_HEIGHT_UNIFORM] != -1) { + // Bind rendered texture height. + const unsigned int textureheight = canvas->GetHeight(); + SetUniform(m_predefinedUniforms[RENDERED_TEXTURE_HEIGHT_UNIFORM], (float)textureheight); + } + if (m_predefinedUniforms[TEXTURE_COORDINATE_OFFSETS_UNIFORM] != -1) { + // Bind texture offsets. + SetUniformfv(m_predefinedUniforms[TEXTURE_COORDINATE_OFFSETS_UNIFORM], RAS_Uniform::UNI_FLOAT2, m_textureOffsets, + sizeof(float) * TEXTURE_OFFSETS_SIZE, TEXTURE_OFFSETS_SIZE / 2); + } + + for (unsigned int i = 0, size = m_properties.size(); i < size; ++i) { + const std::string& prop = m_properties[i]; + unsigned int uniformLoc = m_propertiesLoc[i]; + + EXP_Value *property = m_gameObject->GetProperty(prop); + + if (!property) { + continue; + } + + switch (property->GetValueType()) { + case VALUE_INT_TYPE: + { + SetUniform(uniformLoc, (int)property->GetNumber()); + break; + } + case VALUE_FLOAT_TYPE: + { + SetUniform(uniformLoc, (float)property->GetNumber()); + break; + } + default: + { + break; + } + } + } +} diff --git a/source/gameengine/Rasterizer/RAS_2DFilter.h b/source/gameengine/Rasterizer/RAS_2DFilter.h new file mode 100644 index 000000000000..61b84eb267d1 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_2DFilter.h @@ -0,0 +1,107 @@ +/* +* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* Contributor(s): Pierluigi Grassi, Porteries Tristan. +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +#ifndef __RAS_2DFILTER_H__ +#define __RAS_2DFILTER_H__ + +#include "RAS_2DFilterData.h" +#include "RAS_Shader.h" + +#include +#include + +class RAS_2DFilterManager; +class RAS_Rasterizer; +class RAS_ICanvas; +class RAS_OffScreen; +class RAS_2DFilterOffScreen; +class EXP_Value; + +class RAS_2DFilter : public virtual RAS_Shader +{ +public: + enum PredefinedUniformType { + RENDERED_TEXTURE_UNIFORM = 0, + DEPTH_TEXTURE_UNIFORM, + RENDERED_TEXTURE_WIDTH_UNIFORM, + RENDERED_TEXTURE_HEIGHT_UNIFORM, + TEXTURE_COORDINATE_OFFSETS_UNIFORM, + MAX_PREDEFINED_UNIFORM_TYPE + }; + +protected: + int m_predefinedUniforms[MAX_PREDEFINED_UNIFORM_TYPE]; + + std::vector m_properties; + std::vector m_propertiesLoc; + EXP_Value *m_gameObject; + + /// True if the uniform locations are updated with the current shader program/script. + bool m_uniformInitialized; + /// True if generate mipmap of input color texture. + bool m_mipmap; + + /** A set of vec2 coordinates that the shaders use to sample nearby pixels from incoming textures. + The computation should be left to the glsl shader, I keep it for backward compatibility. */ + static const int TEXTURE_OFFSETS_SIZE = 18; //9 vec2 entries + float m_textureOffsets[TEXTURE_OFFSETS_SIZE]; + + std::unordered_map > m_textures; + + /// Custom off screen for special datas. + std::unique_ptr m_offScreen; + + virtual bool LinkProgram(); + void ParseShaderProgram(); + void BindUniforms(RAS_ICanvas *canvas); + void BindTextures(RAS_OffScreen *detphofs, RAS_OffScreen *colorofs); + void UnbindTextures(RAS_OffScreen *detphofs, RAS_OffScreen *colorofs); + void ComputeTextureOffsets(RAS_ICanvas *canvas); + +public: + RAS_2DFilter(RAS_2DFilterData& data); + virtual ~RAS_2DFilter(); + + bool GetMipmap() const; + void SetMipmap(bool mipmap); + + RAS_2DFilterOffScreen *GetOffScreen() const; + void SetOffScreen(RAS_2DFilterOffScreen *offScreen); + + /// Called by the filter manager when it has informations like the display size, a gl context... + void Initialize(RAS_ICanvas *canvas); + + /** Render the filter. + * \param rasty The used rasterizer to call draw commands. + * \param canvas The canvas containing screen viewport. + * \param detphofs The off screen used only for the depth texture input, + * the same for all filters of a scene. + * \param colorofs The off screen used only for the color texture input, unique per filters. + * \param targetofs The off screen used to draw the filter to. + * \return The off screen to use as input for the next filter. + */ + RAS_OffScreen *Render(RAS_Rasterizer *rasty, RAS_ICanvas *canvas, RAS_OffScreen *detphofs, + RAS_OffScreen *colorofs, RAS_OffScreen *targetofs); +}; + +#endif // __RAS_2DFILTER_H__ + diff --git a/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectSensor.h b/source/gameengine/Rasterizer/RAS_2DFilterData.cpp similarity index 78% rename from source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectSensor.h rename to source/gameengine/Rasterizer/RAS_2DFilterData.cpp index 5ae05ad8b36c..3ac21df18b18 100644 --- a/source/gameengine/Ketsji/KXNetwork/KX_NetworkObjectSensor.h +++ b/source/gameengine/Rasterizer/RAS_2DFilterData.cpp @@ -15,16 +15,21 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * * Contributor(s): none yet. * * ***** END GPL LICENSE BLOCK ***** */ +#include "RAS_2DFilterData.h" +#include -/** \file gameengine/Ketsji/KXNetwork/KX_NetworkObjectSensor.h - * \ingroup ketsjinet - */ +RAS_2DFilterData::RAS_2DFilterData() + :gameObject(nullptr), + mipmap(false), + filterMode(-1), + filterPassIndex(-1) +{ +} + +RAS_2DFilterData::~RAS_2DFilterData() +{ +} diff --git a/source/gameengine/Rasterizer/RAS_2DFilterData.h b/source/gameengine/Rasterizer/RAS_2DFilterData.h new file mode 100644 index 000000000000..484dd9859aa3 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_2DFilterData.h @@ -0,0 +1,56 @@ +/* +* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* Contributor(s): Pierluigi Grassi, Porteries Tristan. +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +#ifndef __RAS_2DFILTERDATA__ +#define __RAS_2DFILTERDATA__ + +#include +#include + +class EXP_Value; + +/** This type is used to pack data received from a 2D Filter actuator and send it to +the RAS_2DFilterManager::AddFilter method, because the number of parameters needed by +a custom filter may become quite large and a function with a thousands paramters doesn't look +very good. So it's purely for readability. +*/ +class RAS_2DFilterData +{ +public: + RAS_2DFilterData(); + virtual ~RAS_2DFilterData(); + + /// The names of the properties of the game object that the shader may want to use as uniforms. + std::vector propertyNames; + /// The KX_GameObject (or something else?) that provides the values for the uniforms named above. + EXP_Value *gameObject; + /// Enable/Disable mipmap in for rendered texture. + bool mipmap; + /// Should be a SCA_2DFilterActuator.FILTER_MODE value. + int filterMode; + /// In the original design this was bot the pass index and the unique identifier of the filter in the filter manager. + unsigned int filterPassIndex; + /// This is the shader program source code IF the filter is not a predefined one. + std::string shaderText; +}; + +#endif // __RAS_2DFILTERDATA__ diff --git a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp index 2749752bc6c5..10ac4f580beb 100644 --- a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp +++ b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp @@ -15,7 +15,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * Contributor(s): none yet. + * Contributor(s): Pierluigi Grassi, Porteries Tristan. * * ***** END GPL LICENSE BLOCK ***** */ @@ -24,539 +24,203 @@ * \ingroup bgerast */ -#include "BLI_utildefines.h" - -#include "RAS_OpenGLFilters/RAS_Blur2DFilter.h" -#include "RAS_OpenGLFilters/RAS_Sharpen2DFilter.h" -#include "RAS_OpenGLFilters/RAS_Dilation2DFilter.h" -#include "RAS_OpenGLFilters/RAS_Erosion2DFilter.h" -#include "RAS_OpenGLFilters/RAS_Laplacian2DFilter.h" -#include "RAS_OpenGLFilters/RAS_Sobel2DFilter.h" -#include "RAS_OpenGLFilters/RAS_Prewitt2DFilter.h" -#include "RAS_OpenGLFilters/RAS_GrayScale2DFilter.h" -#include "RAS_OpenGLFilters/RAS_Sepia2DFilter.h" -#include "RAS_OpenGLFilters/RAS_Invert2DFilter.h" - -#include "STR_String.h" #include "RAS_ICanvas.h" -#include "RAS_Rect.h" +#include "RAS_Rasterizer.h" +#include "RAS_OffScreen.h" #include "RAS_2DFilterManager.h" -#include +#include "RAS_2DFilter.h" -#include "GPU_glew.h" +#include "CM_Message.h" -#include +#include "GPU_glew.h" -#include "EXP_Value.h" +extern "C" { +extern char datatoc_RAS_Blur2DFilter_glsl[]; +extern char datatoc_RAS_Sharpen2DFilter_glsl[]; +extern char datatoc_RAS_Dilation2DFilter_glsl[]; +extern char datatoc_RAS_Erosion2DFilter_glsl[]; +extern char datatoc_RAS_Laplacian2DFilter_glsl[]; +extern char datatoc_RAS_Sobel2DFilter_glsl[]; +extern char datatoc_RAS_Prewitt2DFilter_glsl[]; +extern char datatoc_RAS_GrayScale2DFilter_glsl[]; +extern char datatoc_RAS_Sepia2DFilter_glsl[]; +extern char datatoc_RAS_Invert2DFilter_glsl[]; +} -RAS_2DFilterManager::RAS_2DFilterManager(): -texturewidth(-1), textureheight(-1), -/* numberoffilters(0), */ /* UNUSED */ need_tex_update(true) +RAS_2DFilterManager::RAS_2DFilterManager() { - isshadersupported = GLEW_ARB_shader_objects && - GLEW_ARB_fragment_shader && GLEW_ARB_multitexture; - - /* used to return before 2.49 but need to initialize values so don't */ - if (!isshadersupported) - std::cout<<"shaders not supported!" << std::endl; - - int passindex; - for (passindex =0; passindexSetEnabled(true); - printf("2D Filter GLSL Shader: %s error:\n", task); - - c = code; - while ((c < end) && (pos = strchr(c, '\n'))) { - printf("%2d ", line); - fwrite(c, (pos+1)-c, 1, stdout); - c = pos+1; - line++; - } - - puts(c); - puts(log); - puts("\n"); + return filter; } -unsigned int RAS_2DFilterManager::CreateShaderProgram(const char* shadersource) +void RAS_2DFilterManager::RemoveFilterPass(unsigned int passIndex) { - GLuint program = 0; - GLuint fShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER); - GLint success; + m_filters.erase(passIndex); +} - glShaderSourceARB(fShader, 1, (const char**)&shadersource, NULL); +RAS_2DFilter *RAS_2DFilterManager::GetFilterPass(unsigned int passIndex) +{ + RAS_PassTo2DFilter::iterator it = m_filters.find(passIndex); + return (it != m_filters.end()) ? it->second : nullptr; +} - glCompileShaderARB(fShader); +RAS_OffScreen *RAS_2DFilterManager::RenderFilters(RAS_Rasterizer *rasty, RAS_ICanvas *canvas, RAS_OffScreen *inputofs, RAS_OffScreen *targetofs) +{ + if (m_filters.empty()) { + // No filters, discard. + return inputofs; + } + rasty->Disable(RAS_Rasterizer::RAS_DEPTH_TEST); + rasty->SetDepthMask(RAS_Rasterizer::RAS_DEPTHMASK_DISABLED); + rasty->Disable(RAS_Rasterizer::RAS_BLEND); + rasty->Disable(RAS_Rasterizer::RAS_ALPHA_TEST); - glGetObjectParameterivARB(fShader, GL_COMPILE_STATUS, &success); - if (!success) { - /*Shader Comile Error*/ - PrintShaderErrors(fShader, "compile", shadersource); - goto fail; - } + rasty->SetLines(false); - program = glCreateProgramObjectARB(); - glAttachObjectARB(program, fShader); + RAS_OffScreen *previousofs = inputofs; - glLinkProgramARB(program); - glGetObjectParameterivARB(program, GL_LINK_STATUS, &success); - if (!success) { - /*Program Link Error*/ - PrintShaderErrors(fShader, "link", shadersource); - goto fail; + /* Set source off screen to RAS_OFFSCREEN_FILTER0 in case of multisample and blit, + * else keep the original source off screen. */ + if (inputofs->GetSamples()) { + previousofs = rasty->GetOffScreen(RAS_Rasterizer::RAS_OFFSCREEN_FILTER0); + // No need to bind previousofs because a blit is proceeded. + rasty->DrawOffScreen(inputofs, previousofs); } - glValidateProgramARB(program); - glGetObjectParameterivARB(program, GL_VALIDATE_STATUS, &success); - if (!success) { - /*Program Validation Error*/ - PrintShaderErrors(fShader, "validate", shadersource); - goto fail; - } + // The filter color input off screen, changed for each filters. + RAS_OffScreen *colorofs; + // The filter depth input off scree, unchanged for each filters. + RAS_OffScreen *depthofs = previousofs; - /* owned by 'program' */ - if (fShader) { - glDeleteObjectARB(fShader); - } + // Used to know if a filter is the last of the container. + RAS_PassTo2DFilter::const_iterator pend = std::prev(m_filters.end()); - return program; + for (RAS_PassTo2DFilter::iterator begin = m_filters.begin(), it = begin, end = m_filters.end(); it != end; ++it) { + RAS_2DFilter *filter = it->second; + /* Assign the previous off screen to the input off screen. At the first render it's the + * input off screen sent to RenderFilters. */ + colorofs = previousofs; -fail: - if (fShader) { - glDeleteObjectARB(fShader); - } + RAS_OffScreen *ftargetofs; + // Computing the filter targeted off screen. + if (it == pend) { + // Render to the targeted off screen for the last filter. + ftargetofs = targetofs; + } + else { + // Else render to the next off screen compared to the input off screen. + ftargetofs = rasty->GetOffScreen(RAS_Rasterizer::NextFilterOffScreen(colorofs->GetType())); + } - if (program) { - glDeleteObjectARB(program); + /* Get the output off screen of the filter, could be the same as the input off screen + * if no modifications were made or the targeted off screen. + * This output off screen is used for the next filter as input off screen */ + previousofs = filter->Render(rasty, canvas, depthofs, colorofs, ftargetofs); } - return 0; -} -unsigned int RAS_2DFilterManager::CreateShaderProgram(int filtermode) -{ - switch (filtermode) { - case RAS_2DFILTER_BLUR: - return CreateShaderProgram(BlurFragmentShader); - case RAS_2DFILTER_SHARPEN: - return CreateShaderProgram(SharpenFragmentShader); - case RAS_2DFILTER_DILATION: - return CreateShaderProgram(DilationFragmentShader); - case RAS_2DFILTER_EROSION: - return CreateShaderProgram(ErosionFragmentShader); - case RAS_2DFILTER_LAPLACIAN: - return CreateShaderProgram(LaplacionFragmentShader); - case RAS_2DFILTER_SOBEL: - return CreateShaderProgram(SobelFragmentShader); - case RAS_2DFILTER_PREWITT: - return CreateShaderProgram(PrewittFragmentShader); - case RAS_2DFILTER_GRAYSCALE: - return CreateShaderProgram(GrayScaleFragmentShader); - case RAS_2DFILTER_SEPIA: - return CreateShaderProgram(SepiaFragmentShader); - case RAS_2DFILTER_INVERT: - return CreateShaderProgram(InvertFragmentShader); + // The last filter doesn't use its own off screen and didn't render to the targeted off screen ? + if (previousofs != targetofs) { + // Render manually to the targeted off screen as the last filter didn't do it for us. + targetofs->Bind(); + rasty->DrawOffScreen(previousofs, targetofs); } - return 0; -} -void RAS_2DFilterManager::AnalyseShader(int passindex, vector& propNames) -{ - texflag[passindex] = 0; - if (glGetUniformLocationARB(m_filters[passindex], "bgl_DepthTexture") != -1) - { - if (GLEW_ARB_depth_texture) - texflag[passindex] |= 0x1; - } - if (glGetUniformLocationARB(m_filters[passindex], "bgl_LuminanceTexture") != -1) - { - texflag[passindex] |= 0x2; - } + rasty->Enable(RAS_Rasterizer::RAS_DEPTH_TEST); + rasty->SetDepthMask(RAS_Rasterizer::RAS_DEPTHMASK_ENABLED); - if (m_gameObjects[passindex]) - { - int objProperties = propNames.size(); - int i; - for (i=0; iGetProperty(m_properties[passindex][i]); - - if (!property) - continue; - - switch (property->GetValueType()) { - case VALUE_INT_TYPE: - glUniform1iARB(uniformLoc, property->GetNumber()); - break; - case VALUE_FLOAT_TYPE: - glUniform1fARB(uniformLoc, property->GetNumber()); - break; - default: - break; + case RAS_2DFilterManager::FILTER_SHARPEN: + { + shaderSource = datatoc_RAS_Sharpen2DFilter_glsl; + break; } - } -} - -void RAS_2DFilterManager::EndShaderProgram() -{ - glUseProgramObjectARB(0); -} - -void RAS_2DFilterManager::FreeTextures() -{ - if (texname[0]!=(unsigned int)-1) - glDeleteTextures(1, (GLuint*)&texname[0]); - if (texname[1]!=(unsigned int)-1) - glDeleteTextures(1, (GLuint*)&texname[1]); - if (texname[2]!=(unsigned int)-1) - glDeleteTextures(1, (GLuint*)&texname[2]); -} - -void RAS_2DFilterManager::SetupTextures(bool depth, bool luminance) -{ - FreeTextures(); - - glGenTextures(1, (GLuint*)&texname[0]); - glBindTexture(GL_TEXTURE_2D, texname[0]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texturewidth, textureheight, 0, GL_RGBA, - GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - - if (depth) { - glGenTextures(1, (GLuint*)&texname[1]); - glBindTexture(GL_TEXTURE_2D, texname[1]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, texturewidth,textureheight, - 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE,NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, - GL_NONE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - } - - if (luminance) { - glGenTextures(1, (GLuint*)&texname[2]); - glBindTexture(GL_TEXTURE_2D, texname[2]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE16, texturewidth, textureheight, - 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - } -} - -void RAS_2DFilterManager::UpdateOffsetMatrix(RAS_ICanvas* canvas) -{ - /* RAS_Rect canvas_rect = canvas->GetWindowArea(); */ /* UNUSED */ - texturewidth = canvas->GetWidth()+1; - textureheight = canvas->GetHeight()+1; - GLint i,j; - - if (!GL_ARB_texture_non_power_of_two) - { - i = 0; - while ((1 << i) <= texturewidth) - i++; - texturewidth = (1 << (i)); - - // Now for height - i = 0; - while ((1 << i) <= textureheight) - i++; - textureheight = (1 << (i)); - } - - GLfloat xInc = 1.0f / (GLfloat)texturewidth; - GLfloat yInc = 1.0f / (GLfloat)textureheight; - - for (i = 0; i < 3; i++) - { - for (j = 0; j < 3; j++) + case RAS_2DFilterManager::FILTER_DILATION: { - textureoffsets[(((i*3)+j)*2)+0] = (-1.0f * xInc) + ((GLfloat)i * xInc); - textureoffsets[(((i*3)+j)*2)+1] = (-1.0f * yInc) + ((GLfloat)j * yInc); + shaderSource = datatoc_RAS_Dilation2DFilter_glsl; + break; } - } -} - -void RAS_2DFilterManager::UpdateCanvasTextureCoord(const int viewport[4]) -{ - /* - * This function update canvascoord[]. - * These parameters are used to create texcoord[1] - * That way we can access the texcoord relative to the canvas: - * (0.0,0.0) bottom left, (1.0,1.0) top right, (0.5,0.5) center - */ - canvascoord[0] = (GLfloat) viewport[0] / -viewport[2]; - canvascoord[1] = (GLfloat) (texturewidth - viewport[0]) / viewport[2]; - - canvascoord[2] = (GLfloat) viewport[1] / -viewport[3]; - canvascoord[3] = (GLfloat)(textureheight - viewport[1]) / viewport[3]; -} - -void RAS_2DFilterManager::RenderFilters(RAS_ICanvas* canvas) -{ - bool need_depth=false; - bool need_luminance=false; - int num_filters = 0; - - int passindex; - - if (!isshadersupported) - return; - - for (passindex =0; passindexGetViewPort(); - - if (texturewidth != viewport[2] || textureheight != viewport[3]) - { - UpdateOffsetMatrix(canvas); - UpdateCanvasTextureCoord(viewport); - need_tex_update = true; - } - - if (need_tex_update) - { - SetupTextures(need_depth, need_luminance); - need_tex_update = false; - } - - if (need_depth) { - glActiveTextureARB(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, texname[1]); - glCopyTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT, viewport[0], viewport[1], viewport[2], viewport[3], 0); - } - - if (need_luminance) { - glActiveTextureARB(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, texname[2]); - glCopyTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE16, viewport[0], viewport[1], viewport[2], viewport[3], 0); - } - - // reverting to texunit 0, without this we get bug [#28462] - glActiveTextureARB(GL_TEXTURE0); - - // We do this to make side-by-side stereo rendering work correctly with 2D filters. It would probably be nicer to just set the viewport, - // but it can be easier for writing shaders to have the coordinates for the whole screen instead of just part of the screen. - RAS_Rect scissor_rect = canvas->GetDisplayArea(); - - glScissor(scissor_rect.GetLeft() + viewport[0], - scissor_rect.GetBottom() + viewport[1], - scissor_rect.GetWidth() + 1, - scissor_rect.GetHeight() + 1); - - glDisable(GL_DEPTH_TEST); - // in case the previous material was wire - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - // if the last rendered face had alpha add it would messes with the color of the plane we apply 2DFilter to - glDisable(GL_BLEND); - // fix for [#34523] alpha buffer is now available for all OSs - glDisable(GL_ALPHA_TEST); - - glPushMatrix(); //GL_MODELVIEW - glLoadIdentity(); // GL_MODELVIEW - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - - for (passindex =0; passindex& propNames, void* gameObj, RAS_2DFILTER_MODE mode, int pass, STR_String& text) -{ - if (!isshadersupported) - return; - if (pass<0 || pass>=MAX_RENDER_PASS) - return; - need_tex_update = true; - if (mode == RAS_2DFILTER_DISABLED) - { - m_enabled[pass] = 0; - return; - } - - if (mode == RAS_2DFILTER_ENABLED) - { - m_enabled[pass] = 1; - return; - } - - if (mode == RAS_2DFILTER_NOFILTER) - { - if (m_filters[pass]) - glDeleteObjectARB(m_filters[pass]); - m_enabled[pass] = 0; - m_filters[pass] = 0; - m_gameObjects[pass] = NULL; - m_properties[pass].clear(); - texflag[pass] = 0; - return; + if (shaderSource.empty()) { + if (filterData.filterMode == RAS_2DFilterManager::FILTER_CUSTOMFILTER) { + result = NewFilter(filterData); + } + else { + CM_Error("cannot create filter for mode: " << filterData.filterMode << "."); + } } - - if (mode == RAS_2DFILTER_CUSTOMFILTER) - { - if (m_filters[pass]) - glDeleteObjectARB(m_filters[pass]); - m_filters[pass] = CreateShaderProgram(text.Ptr()); - m_gameObjects[pass] = gameObj; - AnalyseShader(pass, propNames); - m_enabled[pass] = 1; - return; + else { + filterData.shaderText = shaderSource; + result = NewFilter(filterData); } - - // We've checked all other cases, which means we must be dealing with a builtin filter - if (m_filters[pass]) - glDeleteObjectARB(m_filters[pass]); - m_filters[pass] = CreateShaderProgram(mode); - m_gameObjects[pass] = NULL; - AnalyseShader(pass, propNames); - m_enabled[pass] = 1; + return result; } diff --git a/source/gameengine/Rasterizer/RAS_2DFilterManager.h b/source/gameengine/Rasterizer/RAS_2DFilterManager.h index a57acc633c9f..333df55dca02 100644 --- a/source/gameengine/Rasterizer/RAS_2DFilterManager.h +++ b/source/gameengine/Rasterizer/RAS_2DFilterManager.h @@ -15,12 +15,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. + * Contributor(s): Pierluigi Grassi, Porteries Tristan. * * ***** END GPL LICENSE BLOCK ***** */ @@ -32,83 +27,69 @@ #ifndef __RAS_2DFILTERMANAGER_H__ #define __RAS_2DFILTERMANAGER_H__ -#define MAX_RENDER_PASS 100 - -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif +#include "RAS_2DFilterData.h" +#include class RAS_ICanvas; +class RAS_Rasterizer; +class RAS_OffScreen; +class RAS_2DFilter; + +typedef std::map RAS_PassTo2DFilter; class RAS_2DFilterManager { -private: - unsigned int CreateShaderProgram(const char* shadersource); - unsigned int CreateShaderProgram(int filtermode); - void AnalyseShader(int passindex, std::vector& propNames); - void StartShaderProgram(int passindex); - void EndShaderProgram(); - void PrintShaderErrors(unsigned int shader, const char *task, const char *code); - - void SetupTextures(bool depth, bool luminance); - void FreeTextures(); - - void UpdateOffsetMatrix(RAS_ICanvas* canvas); - void UpdateCanvasTextureCoord(const int viewport[4]); - - float canvascoord[4]; - float textureoffsets[18]; - /* float view[4]; */ /* UNUSED */ - /* texname[0] contains render to texture, texname[1] contains depth texture, texname[2] contains luminance texture*/ - unsigned int texname[3]; - int texturewidth; - int textureheight; - /* int numberoffilters; */ /* UNUSED */ - /* bit 0: enable/disable depth texture - * bit 1: enable/disable luminance texture*/ - short texflag[MAX_RENDER_PASS]; - - bool isshadersupported; - bool errorprinted; - bool need_tex_update; - - unsigned int m_filters[MAX_RENDER_PASS]; - short m_enabled[MAX_RENDER_PASS]; - - // stores object properties to send to shaders in each pass - std::vector m_properties[MAX_RENDER_PASS]; - void* m_gameObjects[MAX_RENDER_PASS]; public: - enum RAS_2DFILTER_MODE { - RAS_2DFILTER_ENABLED = -2, - RAS_2DFILTER_DISABLED = -1, - RAS_2DFILTER_NOFILTER = 0, - RAS_2DFILTER_MOTIONBLUR, - RAS_2DFILTER_BLUR, - RAS_2DFILTER_SHARPEN, - RAS_2DFILTER_DILATION, - RAS_2DFILTER_EROSION, - RAS_2DFILTER_LAPLACIAN, - RAS_2DFILTER_SOBEL, - RAS_2DFILTER_PREWITT, - RAS_2DFILTER_GRAYSCALE, - RAS_2DFILTER_SEPIA, - RAS_2DFILTER_INVERT, - RAS_2DFILTER_CUSTOMFILTER, - RAS_2DFILTER_NUMBER_OF_FILTERS + enum FILTER_MODE { + FILTER_ENABLED = -2, + FILTER_DISABLED = -1, + FILTER_NOFILTER = 0, + FILTER_MOTIONBLUR, + FILTER_BLUR, + FILTER_SHARPEN, + FILTER_DILATION, + FILTER_EROSION, + FILTER_LAPLACIAN, + FILTER_SOBEL, + FILTER_PREWITT, + FILTER_GRAYSCALE, + FILTER_SEPIA, + FILTER_INVERT, + FILTER_CUSTOMFILTER, + FILTER_NUMBER_OF_FILTERS }; RAS_2DFilterManager(); + virtual ~RAS_2DFilterManager(); - ~RAS_2DFilterManager(); + /** Applies the filters to the scene. + * \param rasty The rasterizer used for draw commands. + * \param canvas The canvas containing the screen viewport. + * \param inputofs The off screen used as input of the first filter. + * \param targetofs The off screen used as output of the last filter. + * \return The last used off screen, if none filters were rendered it's the + * same off screen than inputofs. + */ + RAS_OffScreen *RenderFilters(RAS_Rasterizer *rasty, RAS_ICanvas *canvas, RAS_OffScreen *inputofs, RAS_OffScreen *targetofs); - void RenderFilters(RAS_ICanvas* canvas); + /// Add a filter to the stack of filters managed by this object. + RAS_2DFilter *AddFilter(RAS_2DFilterData& filterData); - void EnableFilter(std::vector& propNames, void* gameObj, RAS_2DFILTER_MODE mode, int pass, STR_String& text); + /// Removes the filters at a given pass index. + void RemoveFilterPass(unsigned int passIndex); + /// Get the existing filter for the given pass index. + RAS_2DFilter *GetFilterPass(unsigned int passIndex); -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_2DFilterManager") -#endif +private: + RAS_PassTo2DFilter m_filters; + + /** Creates a filter matching the given filter data. Returns nullptr if no + * filter can be created with such information. + */ + RAS_2DFilter *CreateFilter(RAS_2DFilterData& filterData); + /// Only return a new instanced filter. + virtual RAS_2DFilter *NewFilter(RAS_2DFilterData& filterData) = 0; }; -#endif + +#endif // __RAS_2DFILTERMANAGER_H__ diff --git a/source/gameengine/Rasterizer/RAS_2DFilterOffScreen.cpp b/source/gameengine/Rasterizer/RAS_2DFilterOffScreen.cpp new file mode 100644 index 000000000000..4476fb7c51a2 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_2DFilterOffScreen.cpp @@ -0,0 +1,187 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Rasterizer/RAS_2DFilterOffScreen.cpp + * \ingroup bgerast + */ + +#include "RAS_2DFilterOffScreen.h" +#include "RAS_ICanvas.h" + +#include "GPU_framebuffer.h" +#include "GPU_texture.h" + +RAS_2DFilterOffScreen::RAS_2DFilterOffScreen(unsigned short colorSlots, Flag flag, unsigned int width, unsigned int height, + RAS_Rasterizer::HdrType hdr) + :m_flag(flag), + m_colorSlots(colorSlots), + m_hdr(hdr), + m_width(width), + m_height(height), + m_frameBuffer(GPU_framebuffer_create()), + m_depthTexture(nullptr) +{ + for (unsigned short i = 0; i < NUM_COLOR_SLOTS; ++i) { + m_colorTextures[i] = nullptr; + } + + if (!(m_flag & RAS_VIEWPORT_SIZE)) { + Construct(); + } +} + +RAS_2DFilterOffScreen::~RAS_2DFilterOffScreen() +{ + GPU_framebuffer_free(m_frameBuffer); + for (unsigned short i = 0; i < NUM_COLOR_SLOTS; ++i) { + GPUTexture *texture = m_colorTextures[i]; + if (texture) { + GPU_texture_free(texture); + } + } + if (m_depthTexture) { + GPU_texture_free(m_depthTexture); + } +} + +void RAS_2DFilterOffScreen::Construct() +{ + for (unsigned short i = 0; i < m_colorSlots; ++i) { + GPUTexture *texture = m_colorTextures[i]; + if (texture) { + GPU_framebuffer_texture_detach(texture); + GPU_texture_free(texture); + } + + // WARNING: Always respect the order from RAS_Rasterizer::HdrType. + static const GPUHDRType hdrEnums[] = { + GPU_HDR_NONE, // RAS_HDR_NONE + GPU_HDR_HALF_FLOAT, // RAS_HDR_HALF_FLOAT + GPU_HDR_FULL_FLOAT // RAS_HDR_FULL_FLOAT + }; + + texture = GPU_texture_create_2D(m_width, m_height, nullptr, hdrEnums[m_hdr], nullptr); + if (!GPU_framebuffer_texture_attach(m_frameBuffer, texture, i, nullptr)) { + GPU_texture_free(texture); + texture = nullptr; + } + m_colorTextures[i] = texture; + } + + if (m_flag & RAS_DEPTH) { + if (m_depthTexture) { + GPU_framebuffer_texture_detach(m_depthTexture); + GPU_texture_free(m_depthTexture); + } + + GPUTexture *texture = GPU_texture_create_depth(m_width, m_height, false, nullptr); + if (!GPU_framebuffer_texture_attach(m_frameBuffer, texture, 0, nullptr)) { + GPU_texture_free(texture); + texture = nullptr; + } + m_depthTexture = texture; + } +} + +void RAS_2DFilterOffScreen::MipmapTexture() +{ + for (unsigned short i = 0; i < m_colorSlots; ++i) { + GPUTexture *texture = m_colorTextures[i]; + GPU_texture_bind(texture, 0); + GPU_texture_filter_mode(texture, false, true, true); + GPU_texture_generate_mipmap(texture); + GPU_texture_unbind(texture); + } +} + +bool RAS_2DFilterOffScreen::Update(RAS_ICanvas *canvas) +{ + if (m_flag & RAS_VIEWPORT_SIZE) { + const unsigned int width = canvas->GetWidth(); + const unsigned int height = canvas->GetHeight(); + if (m_width != width || m_height != height) { + m_width = width; + m_height = height; + + Construct(); + } + } + + return GetValid(); +} + +void RAS_2DFilterOffScreen::Bind(RAS_Rasterizer *rasty) +{ + GPU_framebuffer_bind_all_attachments(m_frameBuffer); + + if (!(m_flag & RAS_VIEWPORT_SIZE)) { + rasty->SetViewport(0, 0, m_width, m_height); + rasty->SetScissor(0, 0, m_width, m_height); + } +} + +void RAS_2DFilterOffScreen::Unbind(RAS_Rasterizer *rasty, RAS_ICanvas *canvas) +{ + if (m_flag & RAS_MIPMAP) { + MipmapTexture(); + } + + if (!(m_flag & RAS_VIEWPORT_SIZE)) { + const int width = canvas->GetWidth(); + const int height = canvas->GetHeight(); + rasty->SetViewport(0, 0, width, height); + rasty->SetScissor(0, 0, width, height); + } +} + +bool RAS_2DFilterOffScreen::GetValid() const +{ + return GPU_framebuffer_check_valid(m_frameBuffer, nullptr); +} + +int RAS_2DFilterOffScreen::GetColorBindCode(unsigned short index) const +{ + if (!m_colorTextures[index]) { + return -1; + } + + return GPU_texture_opengl_bindcode(m_colorTextures[index]); +} + +int RAS_2DFilterOffScreen::GetDepthBindCode() const +{ + if (!m_depthTexture) { + return -1; + } + + return GPU_texture_opengl_bindcode(m_depthTexture); +} + +unsigned int RAS_2DFilterOffScreen::GetWidth() const +{ + return m_width; +} + +unsigned int RAS_2DFilterOffScreen::GetHeight() const +{ + return m_height; +} diff --git a/source/gameengine/Rasterizer/RAS_2DFilterOffScreen.h b/source/gameengine/Rasterizer/RAS_2DFilterOffScreen.h new file mode 100644 index 000000000000..eab30afe4f19 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_2DFilterOffScreen.h @@ -0,0 +1,96 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_2DFilterOffScreen.h + * \ingroup bgerast + */ + +#ifndef __RAS_2DFILTER_OFFSCREEN_H__ +#define __RAS_2DFILTER_OFFSCREEN_H__ + +#include "RAS_Rasterizer.h" + +#include + +class RAS_ICanvas; +struct GPUFrameBuffer; +struct GPUTexture; + +/** \brief This class manages an off screen with more than one color textures (sample-able) + * and an optional depth texture (sample-able), contrary to RAS_OffScreen. + * This class is created, owned and unique per RAS_2DFilter to avoid implicit invalidation + * of filter when the off screen is deleted or using an off screen in multiple filter or + * different scenes. + */ +class RAS_2DFilterOffScreen +{ +public: + enum Flag { + RAS_VIEWPORT_SIZE = (1 << 0), + RAS_DEPTH = (1 << 1), + RAS_MIPMAP = (1 << 2) + }; + + enum { + NUM_COLOR_SLOTS = 8 + }; + +private: + const Flag m_flag; + const unsigned short m_colorSlots; + const RAS_Rasterizer::HdrType m_hdr; + + unsigned int m_width; + unsigned int m_height; + + GPUFrameBuffer *m_frameBuffer; + GPUTexture *m_colorTextures[NUM_COLOR_SLOTS]; + GPUTexture *m_depthTexture; + + /// Construct the frame buffer and the textures with the current settings. + void Construct(); + /// Generate mipmap levels for color textures of the off screen. + void MipmapTexture(); + +public: + RAS_2DFilterOffScreen(unsigned short colorSlots, Flag flag, unsigned int width, unsigned int height, RAS_Rasterizer::HdrType hdr); + virtual ~RAS_2DFilterOffScreen(); + + /** Update the off screen to the new canvas dimensions if allowed. + * \return True if the off screen is valid. + */ + bool Update(RAS_ICanvas *canvas); + /// Bind the off screen and set the viewport before rendering to it. + void Bind(RAS_Rasterizer *rasty); + /// Restore the off screen and mipmap textures. + void Unbind(RAS_Rasterizer *rasty, RAS_ICanvas *canvas); + /// Return true of the off screen is valid from the OpenGL rules for frame buffers. + bool GetValid() const; + + int GetColorBindCode(unsigned short index) const; + int GetDepthBindCode() const; + + unsigned int GetWidth() const; + unsigned int GetHeight() const; +}; + +#endif // __RAS_2DFILTER_OFFSCREEN_H__ diff --git a/source/gameengine/Rasterizer/RAS_AttributeArray.cpp b/source/gameengine/Rasterizer/RAS_AttributeArray.cpp new file mode 100644 index 000000000000..5b7b8492aaa9 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_AttributeArray.cpp @@ -0,0 +1,73 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Rasterizer/RAS_AttributeArray.cpp + * \ingroup bgerast + */ + +#include "RAS_AttributeArray.h" +#include "RAS_AttributeArrayStorage.h" +#include "RAS_DisplayArray.h" + +RAS_AttributeArray::RAS_AttributeArray(RAS_DisplayArray *array) + :m_array(array) +{ +} + +RAS_AttributeArray::RAS_AttributeArray(const AttribList& attribs, RAS_DisplayArray *array) + :m_attribs(attribs), + m_array(array) +{ +} + +RAS_AttributeArray::~RAS_AttributeArray() +{ +} + +RAS_AttributeArray& RAS_AttributeArray::operator=(RAS_AttributeArray&& other) +{ + m_array = other.m_array; + m_attribs = std::move(other.m_attribs); + + for (std::unique_ptr& storage : m_storages) { + storage.reset(nullptr); + } + + return *this; +} + +RAS_AttributeArrayStorage *RAS_AttributeArray::GetStorage(RAS_Rasterizer::DrawType drawingMode) +{ + std::unique_ptr& storage = m_storages[drawingMode]; + if (!storage) { + storage.reset(new RAS_AttributeArrayStorage(m_array->GetLayout(), &m_array->GetStorage(), m_attribs)); + } + + return storage.get(); +} + +void RAS_AttributeArray::Clear() +{ + for (std::unique_ptr &storage : m_storages) { + storage.reset(nullptr); + } +} diff --git a/source/gameengine/Rasterizer/RAS_AttributeArray.h b/source/gameengine/Rasterizer/RAS_AttributeArray.h new file mode 100644 index 000000000000..b1b0de37fd25 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_AttributeArray.h @@ -0,0 +1,80 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_AttributeArray.h + * \ingroup bgerast + */ + +#ifndef __RAS_ATTRIBUTE_ARRAY_H__ +#define __RAS_ATTRIBUTE_ARRAY_H__ + +#include "RAS_Rasterizer.h" + +#include + +class RAS_DisplayArray; +class RAS_AttributeArrayStorage; +class RAS_DisplayArrayStorage; + +class RAS_AttributeArray +{ +public: + enum AttribType { + RAS_ATTRIB_POS, // Vertex coordinates. + RAS_ATTRIB_UV, // UV coordinates. + RAS_ATTRIB_NORM, // Normal coordinates. + RAS_ATTRIB_TANGENT, // Tangent coordinates. + RAS_ATTRIB_COLOR, // Vertex color. + RAS_ATTRIB_MAX + }; + + struct Attrib + { + unsigned short m_loc; + AttribType m_type; + bool m_texco; + unsigned short m_layer; + }; + + /* Attribute list of the following format: + * hashed name: (attrib type, texco, layer(optional)). + */ + using AttribList = std::vector; + +private: + std::array, RAS_Rasterizer::RAS_DRAW_MAX> m_storages; + AttribList m_attribs; + RAS_DisplayArray *m_array; + +public: + RAS_AttributeArray(RAS_DisplayArray *array); + RAS_AttributeArray(const AttribList& attribs, RAS_DisplayArray *array); + ~RAS_AttributeArray(); + + RAS_AttributeArray& operator=(RAS_AttributeArray&& other); + + RAS_AttributeArrayStorage *GetStorage(RAS_Rasterizer::DrawType drawingMode); + /// Used to invalidate all attribute array in case of array storage resizing. + void Clear(); +}; + +#endif // __RAS_ATTRIBUTE_ARRAY_H__ diff --git a/source/gameengine/Rasterizer/RAS_AttributeArrayStorage.cpp b/source/gameengine/Rasterizer/RAS_AttributeArrayStorage.cpp new file mode 100644 index 000000000000..a79aee5c55f2 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_AttributeArrayStorage.cpp @@ -0,0 +1,24 @@ +#include "RAS_AttributeArrayStorage.h" +#include "RAS_StorageVao.h" + +RAS_AttributeArrayStorage::RAS_AttributeArrayStorage(const RAS_DisplayArrayLayout& layout, RAS_DisplayArrayStorage *arrayStorage, + const RAS_AttributeArray::AttribList& attribList) + :m_vao(new RAS_StorageVao(layout, arrayStorage, attribList)) +{ +} + +RAS_AttributeArrayStorage::~RAS_AttributeArrayStorage() +{ +} + +void RAS_AttributeArrayStorage::BindPrimitives() +{ + m_vao->BindPrimitives(); +} + +void RAS_AttributeArrayStorage::UnbindPrimitives() +{ + m_vao->UnbindPrimitives(); +} + + diff --git a/source/gameengine/Rasterizer/RAS_AttributeArrayStorage.h b/source/gameengine/Rasterizer/RAS_AttributeArrayStorage.h new file mode 100644 index 000000000000..5241d6975c4b --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_AttributeArrayStorage.h @@ -0,0 +1,23 @@ +#ifndef __RAS_ATTRIBUTE_ARRAY_STORAGE_H__ +#define __RAS_ATTRIBUTE_ARRAY_STORAGE_H__ + +#include "RAS_AttributeArray.h" + +class RAS_StorageVao; +struct RAS_DisplayArrayLayout; + +class RAS_AttributeArrayStorage +{ +private: + std::unique_ptr m_vao; + +public: + RAS_AttributeArrayStorage(const RAS_DisplayArrayLayout& layout, RAS_DisplayArrayStorage *arrayStorage, + const RAS_AttributeArray::AttribList& attribList); + ~RAS_AttributeArrayStorage(); + + void BindPrimitives(); + void UnbindPrimitives(); +}; + +#endif // __RAS_ATTRIBUTE_ARRAY_STORAGE_H__ diff --git a/source/gameengine/Rasterizer/RAS_BatchDisplayArray.cpp b/source/gameengine/Rasterizer/RAS_BatchDisplayArray.cpp new file mode 100644 index 000000000000..92822ad29c90 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_BatchDisplayArray.cpp @@ -0,0 +1,166 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_BatchDisplayArray.cpp + * \ingroup bgerast + */ + +#include "RAS_BatchDisplayArray.h" +#ifdef DEBUG +# include "CM_Message.h" +#endif + +RAS_BatchDisplayArray::RAS_BatchDisplayArray(PrimitiveType type, const Format &format) + :RAS_DisplayArray(type, format) +{ +} + +RAS_BatchDisplayArray::~RAS_BatchDisplayArray() +{ +} + +unsigned int RAS_BatchDisplayArray::Merge(RAS_DisplayArray *array, const mt::mat4& mat) +{ + const unsigned int vertexcount = array->GetVertexCount(); + const unsigned int indexcount = array->GetPrimitiveIndexCount(); + + const unsigned int startvertex = GetVertexCount(); + const unsigned int startindex = m_primitiveIndices.size(); + + // Add the part info. + Part part; + part.m_startVertex = startvertex; + part.m_vertexCount = vertexcount; + part.m_startIndex = startindex; + part.m_indexCount = indexcount; + part.m_indexOffset = part.m_startIndex * sizeof(unsigned int); + m_parts.push_back(part); + + // Pre-allocate vertex list and index list. + const unsigned int totalVertexCount = startvertex + vertexcount; + m_vertexData.positions.resize(totalVertexCount); + m_vertexData.normals.resize(totalVertexCount); + m_vertexData.tangents.resize(totalVertexCount); + // Uv and color are not resized here as they are just merged later. + + m_primitiveIndices.resize(startindex + indexcount); + +#ifdef DEBUG + CM_Debug("Add part : " << (m_parts.size() - 1) << ", start index: " << startindex << ", index count: " << indexcount << ", start vertex: " << startvertex << ", vertex count: " << vertexcount); +#endif // DEBUG + + // Normal and tangent matrix. + mt::mat4 nmat = mat; + nmat(0, 3) = nmat(1, 3) = nmat(2, 3) = 0.0f; + + // Copy the vertices and transform. + for (unsigned int i = 0; i < vertexcount; ++i) { + m_vertexData.positions[startvertex + i] = mat * mt::vec3(array->GetPosition(i)); + } + + for (unsigned int i = 0; i < vertexcount; ++i) { + m_vertexData.normals[startvertex + i] = nmat * mt::vec3(array->GetNormal(i)); + } + + for (unsigned int i = 0; i < vertexcount; ++i) { + m_vertexData.tangents[startvertex + i] = nmat * mt::vec4(array->GetTangent(i)); + } + + for (unsigned short i = 0; i < m_format.uvSize; ++i) { + m_vertexData.uvs[i].insert(m_vertexData.uvs[i].end(), array->m_vertexData.uvs[i].begin(), array->m_vertexData.uvs[i].end()); + } + + for (unsigned short i = 0; i < m_format.colorSize; ++i) { + m_vertexData.colors[i].insert(m_vertexData.colors[i].end(), array->m_vertexData.colors[i].begin(), array->m_vertexData.colors[i].end()); + } + + // Copy the indices of the merged array with as gap the first vertex index. + for (unsigned int i = 0; i < indexcount; ++i) { + m_primitiveIndices[startindex + i] = (array->m_primitiveIndices[i] + startvertex); + } + + // Request storage update. + NotifyUpdate(SIZE_MODIFIED); + + return (m_parts.size() - 1); +} + +void RAS_BatchDisplayArray::Split(unsigned int partIndex) +{ + const Part &part = m_parts[partIndex]; + + const unsigned int startindex = part.m_startIndex; + const unsigned int startvertex = part.m_startVertex; + + const unsigned int indexcount = part.m_indexCount; + const unsigned int vertexcount = part.m_vertexCount; + + const unsigned int endvertex = startvertex + vertexcount; + +#ifdef DEBUG + CM_Debug("Move indices from " << startindex << " to " << m_primitiveIndices.size() - indexcount << ", shift of " << indexcount); +#endif // DEBUG + + // Move the indices after the part to remove before of vertexcount places. + for (unsigned int i = startindex, size = m_primitiveIndices.size() - indexcount; i < size; ++i) { + m_primitiveIndices[i] = m_primitiveIndices[i + indexcount] - vertexcount; + } + + // Erase the end of the index. + m_primitiveIndices.erase(m_primitiveIndices.end() - indexcount, m_primitiveIndices.end()); + +#ifdef DEBUG + CM_Debug("Remove vertexes : start vertex: " << startvertex << ", end vertex: " << endvertex); +#endif // DEBUG + + // Erase vertices of the part to remove. + m_vertexData.positions.erase(m_vertexData.positions.begin() + startvertex, m_vertexData.positions.begin() + endvertex); + m_vertexData.normals.erase(m_vertexData.normals.begin() + startvertex, m_vertexData.normals.begin() + endvertex); + m_vertexData.tangents.erase(m_vertexData.tangents.begin() + startvertex, m_vertexData.tangents.begin() + endvertex); + + for (unsigned short i = 0; i < m_format.uvSize; ++i) { + m_vertexData.uvs[i].erase(m_vertexData.uvs[i].begin() + startvertex, m_vertexData.uvs[i].begin() + endvertex); + } + + for (unsigned short i = 0; i < m_format.colorSize; ++i) { + m_vertexData.colors[i].erase(m_vertexData.colors[i].begin() + startvertex, m_vertexData.colors[i].begin() + endvertex); + } + + // Reduce start vertex and start index of the part after the removed part. + for (unsigned i = partIndex + 1, size = m_parts.size(); i < size; ++i) { + Part& nextPart = m_parts[i]; + nextPart.m_startVertex -= vertexcount; + nextPart.m_startIndex -= indexcount; + nextPart.m_indexOffset = (nextPart.m_startIndex * sizeof(unsigned int)); + } + + // Remove the part info. + m_parts.erase(m_parts.begin() + partIndex); + + // Request storage update. + NotifyUpdate(SIZE_MODIFIED); +} + +RAS_DisplayArray::Type RAS_BatchDisplayArray::GetType() const +{ + return BATCHING; +} diff --git a/source/gameengine/Rasterizer/RAS_BatchDisplayArray.h b/source/gameengine/Rasterizer/RAS_BatchDisplayArray.h new file mode 100644 index 000000000000..38eb816643ed --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_BatchDisplayArray.h @@ -0,0 +1,80 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_BatchDisplayArray.h + * \ingroup bgerast + */ + +#ifndef __RAS_IDISPLAY_ARRAY_BATCHING_H__ +#define __RAS_IDISPLAY_ARRAY_BATCHING_H__ + +#include "RAS_DisplayArray.h" + +class RAS_BatchDisplayArray : public RAS_DisplayArray +{ +protected: + /// This struct is dedicated to store all the info of a part. + struct Part + { + /// Relative pointer to the start index, used for VBO. + intptr_t m_indexOffset; + + unsigned int m_startVertex; + unsigned int m_vertexCount; + + unsigned int m_startIndex; + unsigned int m_indexCount; + }; + + /// The part's info. + std::vector m_parts; + +public: + RAS_BatchDisplayArray(PrimitiveType type, const Format &format); + virtual ~RAS_BatchDisplayArray(); + + inline intptr_t GetPartIndexOffset(const unsigned short index) + { + return m_parts[index].m_indexOffset; + } + + inline unsigned int GetPartIndexCount(const unsigned short index) + { + return m_parts[index].m_indexCount; + } + + /** Merge a display array with a transform matrix. + * \param array The display array to merge. + * \param mat The matrix applied on all the vertices. + * \return The index of the part just added. + */ + unsigned int Merge(RAS_DisplayArray *array, const mt::mat4& mat); + + /** Split a part. + * \param partIndex The index of the part to remove. + */ + void Split(unsigned int partIndex); + + virtual Type GetType() const; +}; + +#endif // __RAS_IDISPLAY_ARRAY_BATCHING_H__ diff --git a/source/gameengine/Rasterizer/RAS_BatchGroup.cpp b/source/gameengine/Rasterizer/RAS_BatchGroup.cpp new file mode 100644 index 000000000000..86e692096604 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_BatchGroup.cpp @@ -0,0 +1,219 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Rasterizer/RAS_BatchGroup.cpp + * \ingroup bgerast + */ + +#include "RAS_BatchGroup.h" +#include "RAS_BatchDisplayArray.h" +#include "RAS_IMaterial.h" +#include "RAS_MaterialBucket.h" +#include "RAS_MeshUser.h" +#include "RAS_MeshSlot.h" + +#include "CM_Message.h" + +#include + +RAS_BatchGroup::Batch::Batch() + :m_displayArrayBucket(nullptr), + m_displayArray(nullptr) +{ +} + +RAS_BatchGroup::RAS_BatchGroup() + :m_users(0), + m_referenceMeshUser(nullptr) +{ +} + +RAS_BatchGroup::~RAS_BatchGroup() +{ + for (const auto& pair : m_batchs) { + const Batch& batch = pair.second; + delete batch.m_displayArrayBucket; + } +} + +RAS_BatchGroup *RAS_BatchGroup::AddMeshUser() +{ + ++m_users; + return this; +} + +RAS_BatchGroup *RAS_BatchGroup::RemoveMeshUser() +{ + --m_users; + if (m_users == 0) { + delete this; + return nullptr; + } + return this; +} + +RAS_MeshUser *RAS_BatchGroup::GetReferenceMeshUser() const +{ + return m_referenceMeshUser; +} + +void RAS_BatchGroup::SetReferenceMeshUser(RAS_MeshUser *meshUser) +{ + m_referenceMeshUser = meshUser; +} + +bool RAS_BatchGroup::MergeMeshSlot(RAS_BatchGroup::Batch& batch, RAS_MeshSlot& slot, const mt::mat4& mat) +{ + RAS_DisplayArrayBucket *origArrayBucket = slot.m_displayArrayBucket; + RAS_DisplayArray *origArray = origArrayBucket->GetDisplayArray(); + RAS_DisplayArrayBucket *arrayBucket = batch.m_displayArrayBucket; + RAS_BatchDisplayArray *array = batch.m_displayArray; + + if (batch.m_originalDisplayArrayBucketList.find(&slot) != batch.m_originalDisplayArrayBucketList.end()) { + CM_Error("could not merge twice a mesh"); + return false; + } + + // Don't merge if the vertex format or pimitive type is not the same. + if (origArray->GetFormat() != array->GetFormat() || origArray->GetPrimitiveType() != array->GetPrimitiveType()) { + CM_Error("could not merge incompatible vertex format or primitive type") + return false; + } + + // Store original display array bucket. + batch.m_originalDisplayArrayBucketList[&slot] = origArrayBucket; + batch.m_meshSlots.push_back(&slot); + + // Merge display array. + const unsigned int index = array->Merge(origArray, mat); + slot.m_batchPartIndex = index; + + slot.SetDisplayArrayBucket(arrayBucket); + + return true; +} + +bool RAS_BatchGroup::SplitMeshSlot(RAS_MeshSlot& slot) +{ + RAS_MaterialBucket *bucket = slot.m_displayArrayBucket->GetBucket(); + RAS_IMaterial *material = bucket->GetMaterial(); + + std::map::iterator bit = m_batchs.find(material); + if (bit == m_batchs.end()) { + CM_Error("could not found corresponding material \"" << material->GetName() << "\""); + return false; + } + + Batch& batch = bit->second; + + RAS_DisplayArrayBucket *origArrayBucket = batch.m_originalDisplayArrayBucketList[&slot]; + + if (!origArrayBucket) { + CM_Error("could not restore mesh"); + return false; + } + + slot.SetDisplayArrayBucket(origArrayBucket); + + batch.m_displayArray->Split(slot.m_batchPartIndex); + + batch.m_originalDisplayArrayBucketList.erase(&slot); + + slot.m_batchPartIndex = -1; + + // One part is removed and then all the part after must use an index smaller of one. + RAS_MeshSlotList::iterator mit = batch.m_meshSlots.erase(std::find(batch.m_meshSlots.begin(), batch.m_meshSlots.end(), &slot)); + for (RAS_MeshSlotList::iterator it = mit, end = batch.m_meshSlots.end(); it != end; ++it) { + RAS_MeshSlot *meshSlot = *it; + --meshSlot->m_batchPartIndex; + } + + return true; +} + +bool RAS_BatchGroup::MergeMeshUser(RAS_MeshUser *meshUser, const mt::mat4& mat) +{ + for (RAS_MeshSlot& meshSlot : meshUser->GetMeshSlots()) { + RAS_DisplayArrayBucket *arrayBucket = meshSlot.m_displayArrayBucket; + RAS_MaterialBucket *bucket = arrayBucket->GetBucket(); + RAS_IMaterial *material = bucket->GetMaterial(); + + Batch& batch = m_batchs[material]; + // Create the batch if it is empty. + if (!batch.m_displayArray && !batch.m_displayArrayBucket) { + RAS_DisplayArray *origarray = arrayBucket->GetDisplayArray(); + batch.m_displayArray = new RAS_BatchDisplayArray(origarray->GetPrimitiveType(), origarray->GetFormat()); + batch.m_displayArrayBucket = new RAS_DisplayArrayBucket(bucket, batch.m_displayArray, arrayBucket->GetMesh(), + arrayBucket->GetMeshMaterial(), nullptr); + } + + if (!MergeMeshSlot(batch, meshSlot, mat)) { + return false; + } + } + + meshUser->SetBatchGroup(this); + + return true; +} + +bool RAS_BatchGroup::SplitMeshUser(RAS_MeshUser *meshUser) +{ + for (RAS_MeshSlot& meshSlot : meshUser->GetMeshSlots()) { + if (!SplitMeshSlot(meshSlot)) { + return false; + } + } + + // Deference batch groups by setting it to nullptr. + meshUser->SetBatchGroup(nullptr); + + return true; +} + +void RAS_BatchGroup::Destruct() +{ + /* Add an user to be sure the batch group will not be deleted. Indeed all + * the mesh user will deference the batch group and then in the last iteration + * the batch will be deleted before leave the function. This caused to break + * the loop which needs to access m_batchs end iterator. + */ + AddMeshUser(); + + for (auto& pair : m_batchs) { + Batch& batch = pair.second; + for (RAS_MeshSlot *slot : batch.m_meshSlots) { + RAS_DisplayArrayBucket *origArrayBucket = batch.m_originalDisplayArrayBucketList[slot]; + + slot->SetDisplayArrayBucket(origArrayBucket); + + slot->m_meshUser->SetBatchGroup(nullptr); + + slot->m_batchPartIndex = -1; + } + } + + m_batchs.clear(); + + // Release here and destruct the batch group. + RemoveMeshUser(); +} diff --git a/source/gameengine/Rasterizer/RAS_BatchGroup.h b/source/gameengine/Rasterizer/RAS_BatchGroup.h new file mode 100644 index 000000000000..d74d8238f81c --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_BatchGroup.h @@ -0,0 +1,111 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_BatchGroup.h + * \ingroup bgerast + */ + +#ifndef __RAS_BATCH_GROUP_H__ +#define __RAS_BATCH_GROUP_H__ + +#include "RAS_DisplayArrayBucket.h" + +class RAS_IMaterial; +class RAS_BatchDisplayArray; + +class RAS_BatchGroup +{ +private: + /// The reference counter. + short m_users; + /// Reference object used to retrieve layer and color. + RAS_MeshUser *m_referenceMeshUser; + + /// A batch contained the merged display array for all the display array used for a given material. + class Batch + { + public: + Batch(); + + /// The display array bucket owning the merged display array. + RAS_DisplayArrayBucket *m_displayArrayBucket; + /// The merged display array. + RAS_BatchDisplayArray *m_displayArray; + + /// The original display array bucket per mesh slots. + std::map m_originalDisplayArrayBucketList; + /// All the mesh slots sorted by batch index. + RAS_MeshSlotList m_meshSlots; + }; + + /// The batch per material. + std::map m_batchs; + + /** Merge the display array of the passed mesh slot. + * \param slot The mesh slot using the display array to merge. + * \param mat The transform matrix to apply to vertices during merging. + * \return false on failure. + */ + bool MergeMeshSlot(Batch& batch, RAS_MeshSlot& slot, const mt::mat4& mat); + + /** Split the part representing the display array containing in the passed mesh slot. + * \param slot The mesh slot using the display array to split. + * \return false on failure. + */ + bool SplitMeshSlot(RAS_MeshSlot& slot); + +public: + RAS_BatchGroup(); + virtual ~RAS_BatchGroup(); + + /// Notice the batch group that it is used by one more mesh user. + RAS_BatchGroup *AddMeshUser(); + /// Notice the batch group that it is unused by one less mesh user. + RAS_BatchGroup *RemoveMeshUser(); + + RAS_MeshUser *GetReferenceMeshUser() const; + /// Change reference mesh user without error check. + void SetReferenceMeshUser(RAS_MeshUser *meshUser); + + /** Merge the display array of the mesh slots contained in the mesh user. + * \param meshUser The mesh user to merge mesh slots from. + * \param mat The object matrix to use in display array merging. It's not the matrix from + * the mesh user because this one can be not updated. + * \return false on failure. + */ + bool MergeMeshUser(RAS_MeshUser *meshUser, const mt::mat4& mat); + + /** Split the display array of the mesh slots contained in the mesh user. + * \param meshUser THe mesh user to merge mesh slots from. + * \return false on failure. + */ + bool SplitMeshUser(RAS_MeshUser *meshUser); + + /** Restore the display array (bucket) of all the mesh slots using this batch group. + * The side effect is to make the batch group unused and then deleted from reference + * counting. + */ + void Destruct(); +}; + + +#endif // __RAS_BATCH_GROUP_H__ diff --git a/source/gameengine/Rasterizer/RAS_BoundingBox.cpp b/source/gameengine/Rasterizer/RAS_BoundingBox.cpp new file mode 100644 index 000000000000..8bd12ff39087 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_BoundingBox.cpp @@ -0,0 +1,191 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_BoundingBox.cpp + * \ingroup bgerast + */ + +#include "RAS_BoundingBox.h" +#include "RAS_BoundingBoxManager.h" + +#include "CM_List.h" + +RAS_BoundingBox::RAS_BoundingBox(RAS_BoundingBoxManager *manager) + :m_modified(false), + m_aabbMin(mt::zero3), + m_aabbMax(mt::zero3), + m_users(0), + m_manager(manager) +{ + BLI_assert(m_manager); + m_manager->m_boundingBoxList.push_back(this); +} + +RAS_BoundingBox::~RAS_BoundingBox() +{ +} + +RAS_BoundingBox *RAS_BoundingBox::GetReplica() +{ + RAS_BoundingBox *boundingBox = new RAS_BoundingBox(*this); + boundingBox->ProcessReplica(); + return boundingBox; +} + +void RAS_BoundingBox::ProcessReplica() +{ + m_users = 0; + m_manager->m_boundingBoxList.push_back(this); +} + +void RAS_BoundingBox::AddUser() +{ + ++m_users; + /* No one was using this bounding box previously. Then add it to the active + * bounding box list in the manager.*/ + if (m_users == 1) { + m_manager->m_activeBoundingBoxList.push_back(this); + } +} + +void RAS_BoundingBox::RemoveUser() +{ + --m_users; + BLI_assert(m_users >= 0); + + /* Some one was using this bounding box previously. Then remove it from the + * active bounding box list. */ + if (m_users == 0) { + CM_ListRemoveIfFound(m_manager->m_activeBoundingBoxList, this); + } +} + +void RAS_BoundingBox::SetManager(RAS_BoundingBoxManager *manager) +{ + BLI_assert(m_manager); + m_manager = manager; +} + +bool RAS_BoundingBox::GetModified() const +{ + return m_modified; +} + +void RAS_BoundingBox::ClearModified() +{ + m_modified = false; +} + +void RAS_BoundingBox::GetAabb(mt::vec3& aabbMin, mt::vec3& aabbMax) const +{ + aabbMin = m_aabbMin; + aabbMax = m_aabbMax; +} + +void RAS_BoundingBox::SetAabb(const mt::vec3& aabbMin, const mt::vec3& aabbMax) +{ + m_aabbMin = aabbMin; + m_aabbMax = aabbMax; + m_modified = true; +} + +void RAS_BoundingBox::ExtendAabb(const mt::vec3& aabbMin, const mt::vec3& aabbMax) +{ + m_aabbMin = mt::vec3::Min(m_aabbMin, aabbMin); + m_aabbMax = mt::vec3::Max(m_aabbMax, aabbMax); + m_modified = true; +} + +void RAS_BoundingBox::CopyAabb(RAS_BoundingBox *other) +{ + other->GetAabb(m_aabbMin, m_aabbMax); + m_modified = true; +} + +void RAS_BoundingBox::Update(bool force) +{ +} + +RAS_MeshBoundingBox::RAS_MeshBoundingBox(RAS_BoundingBoxManager *manager, const RAS_DisplayArrayList& displayArrayList) + :RAS_BoundingBox(manager) +{ + for (RAS_DisplayArray *array : displayArrayList) { + m_slots.push_back({array, {RAS_DisplayArray::POSITION_MODIFIED, RAS_DisplayArray::NONE_MODIFIED}, + mt::zero3, mt::zero3}); + } + + for (DisplayArraySlot& slot : m_slots) { + slot.m_displayArray->AddUpdateClient(&slot.m_arrayUpdateClient); + } +} + +RAS_MeshBoundingBox::~RAS_MeshBoundingBox() +{ +} + +RAS_BoundingBox *RAS_MeshBoundingBox::GetReplica() +{ + RAS_MeshBoundingBox *boundingBox = new RAS_MeshBoundingBox(*this); + + boundingBox->m_users = 0; + for (DisplayArraySlot& slot : boundingBox->m_slots) { + slot.m_displayArray->AddUpdateClient(&slot.m_arrayUpdateClient); + } + + return boundingBox; +} + +void RAS_MeshBoundingBox::Update(bool force) +{ + bool modified = false; + for (DisplayArraySlot& slot : m_slots) { + RAS_DisplayArray *array = slot.m_displayArray; + // Select modified display array or all if the update is forced. + if (!slot.m_arrayUpdateClient.GetInvalidAndClear() && !force) { + continue; + } + modified = true; + + slot.m_aabbMin = mt::vec3(FLT_MAX); + slot.m_aabbMax = mt::vec3(-FLT_MAX); + + // For each vertex. + for (unsigned int i = 0, size = array->GetVertexCount(); i < size; ++i) { + const mt::vec3 vertPos(array->GetPosition(i)); + + slot.m_aabbMin = mt::vec3::Min(slot.m_aabbMin, vertPos); + slot.m_aabbMax = mt::vec3::Max(slot.m_aabbMax, vertPos); + } + } + + if (modified) { + m_aabbMin = mt::vec3(FLT_MAX); + m_aabbMax = mt::vec3(-FLT_MAX); + + for (const DisplayArraySlot& slot : m_slots) { + m_aabbMin = mt::vec3::Min(m_aabbMin, slot.m_aabbMin); + m_aabbMax = mt::vec3::Max(m_aabbMax, slot.m_aabbMax); + } + } + + m_modified = true; +} diff --git a/source/gameengine/Rasterizer/RAS_BoundingBox.h b/source/gameengine/Rasterizer/RAS_BoundingBox.h new file mode 100644 index 000000000000..b503df734f01 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_BoundingBox.h @@ -0,0 +1,114 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_BoundingBox.h + * \ingroup bgerast + */ + +#ifndef __RAS_BOUNDING_BOX_H__ +#define __RAS_BOUNDING_BOX_H__ + +#include "RAS_DisplayArray.h" + +class RAS_BoundingBoxManager; + +class RAS_BoundingBox : public mt::SimdClassAllocator +{ +protected: + /// True when the bounding box is modified. + bool m_modified; + + /// The AABB minimum. + mt::vec3 m_aabbMin; + /// The AABB maximum. + mt::vec3 m_aabbMax; + + /// The number of mesh user using this bounding box. + int m_users; + /// The manager of all the bounding boxes of a scene. + RAS_BoundingBoxManager *m_manager; + +public: + RAS_BoundingBox(RAS_BoundingBoxManager *manager); + virtual ~RAS_BoundingBox(); + + virtual RAS_BoundingBox *GetReplica(); + void ProcessReplica(); + + /// Notice that the bounding box is used by one more mesh user. + void AddUser(); + /// Notice that the bounding box is left by one mesh user. + void RemoveUser(); + + /// Change the bounding box manager. Used only for the libloading scene merge. + void SetManager(RAS_BoundingBoxManager *manager); + + /** Return true when the bounding box AABB was set or when the display + * array were modified in case of RAS_MeshBoundingBox instance. + */ + bool GetModified() const; + /// Set the bounding box unmodified. + void ClearModified(); + + void GetAabb(mt::vec3& aabbMin, mt::vec3& aabbMax) const; + void SetAabb(const mt::vec3& aabbMin, const mt::vec3& aabbMax); + /// Compute the AABB of the bounding box AABB mixed with the passed AABB. + void ExtendAabb(const mt::vec3& aabbMin, const mt::vec3& aabbMax); + + void CopyAabb(RAS_BoundingBox *other); + + virtual void Update(bool force); +}; + +class RAS_MeshBoundingBox : public RAS_BoundingBox +{ +private: + /// Display arrays used to compute the AABB. + struct DisplayArraySlot + { + RAS_DisplayArray *m_displayArray; + CM_UpdateClient m_arrayUpdateClient; + /// AABB minimum of only this display array. + mt::vec3 m_aabbMin; + /// AABB maximum of only this display array. + mt::vec3 m_aabbMax; + }; + + /// The sub AABB per display array. + // Use aligned allocator because DisplayArraySlot use aligned members. + std::vector > m_slots; + +public: + RAS_MeshBoundingBox(RAS_BoundingBoxManager *manager, const RAS_DisplayArrayList& displayArrayList); + virtual ~RAS_MeshBoundingBox(); + + virtual RAS_BoundingBox *GetReplica(); + + /** Check if one of the display array was modified, and then recompute the AABB. + * \param force Force the AABB computation even if none display arrays are modified. + */ + virtual void Update(bool force); +}; + +typedef std::vector RAS_BoundingBoxList; + +#endif // __RAS_BOUNDING_BOX_H__ diff --git a/source/gameengine/Rasterizer/RAS_BoundingBoxManager.cpp b/source/gameengine/Rasterizer/RAS_BoundingBoxManager.cpp new file mode 100644 index 000000000000..53433604f11c --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_BoundingBoxManager.cpp @@ -0,0 +1,81 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_BoundingBoxManager.cpp + * \ingroup bgerast + */ + +#include "RAS_BoundingBoxManager.h" + +#include + +RAS_BoundingBoxManager::RAS_BoundingBoxManager() +{ +} + +RAS_BoundingBoxManager::~RAS_BoundingBoxManager() +{ + for (RAS_BoundingBox *boundingBox : m_boundingBoxList) { + delete boundingBox; + } + + BLI_assert(m_activeBoundingBoxList.empty()); +} + +RAS_BoundingBox *RAS_BoundingBoxManager::CreateBoundingBox() +{ + RAS_BoundingBox *boundingBox = new RAS_BoundingBox(this); + return boundingBox; +} + +RAS_BoundingBox *RAS_BoundingBoxManager::CreateMeshBoundingBox(const RAS_DisplayArrayList& arrayList) +{ + RAS_BoundingBox *boundingBox = new RAS_MeshBoundingBox(this, arrayList); + + return boundingBox; +} + +void RAS_BoundingBoxManager::Update(bool force) +{ + for (RAS_BoundingBox *boundingBox : m_activeBoundingBoxList) { + boundingBox->Update(force); + } +} + +void RAS_BoundingBoxManager::ClearModified() +{ + for (RAS_BoundingBox *boundingBox : m_activeBoundingBoxList) { + boundingBox->ClearModified(); + } +} + +void RAS_BoundingBoxManager::Merge(RAS_BoundingBoxManager *other) +{ + for (RAS_BoundingBox *boundingBox : other->m_boundingBoxList) { + boundingBox->SetManager(this); + m_boundingBoxList.push_back(boundingBox); + } + other->m_boundingBoxList.clear(); + + m_activeBoundingBoxList.insert(m_activeBoundingBoxList.begin(), other->m_activeBoundingBoxList.begin(), other->m_activeBoundingBoxList.end()); + other->m_activeBoundingBoxList.clear(); +} diff --git a/source/gameengine/Rasterizer/RAS_BoundingBoxManager.h b/source/gameengine/Rasterizer/RAS_BoundingBoxManager.h new file mode 100644 index 000000000000..a5ae435e58da --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_BoundingBoxManager.h @@ -0,0 +1,72 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_BoundingBoxManager.h + * \ingroup bgerast + */ + +#ifndef __RAS_BOUNDING_BOX_MANAGER_H__ +#define __RAS_BOUNDING_BOX_MANAGER_H__ + +#include "RAS_BoundingBox.h" + +class RAS_BoundingBoxManager +{ + // To manage the insert remove in m_boundingBoxList and m_activeBoundingBoxList. + friend RAS_BoundingBox; +private: + /// All the existing bounding boxes for this manager. + RAS_BoundingBoxList m_boundingBoxList; + /** All the bounding boxes used by at least one mesh user. + * These bounding boxes will be updated each frames. + */ + RAS_BoundingBoxList m_activeBoundingBoxList; + +public: + RAS_BoundingBoxManager(); + ~RAS_BoundingBoxManager(); + + /** Create the bounding box from the bounding box manager. The reason to + * do that is that the scene owning the bounding box manager will be freed + * before the deformers and meshes. + */ + RAS_BoundingBox *CreateBoundingBox(); + /** Create mesh bounding box. + * \param arrayList The display arrays composing the mesh. + * \see CreateBoundingBox. + */ + RAS_BoundingBox *CreateMeshBoundingBox(const RAS_DisplayArrayList& arrayList); + + /** Update all the active bounding boxes. + * \param force Force updating bounding box even if the display arrays are not modified. + */ + void Update(bool force); + /// Set all the active bounding box unmodified. + void ClearModified(); + + /** Merge an other bounding box manager. + * \param other The bounding box manager to merge data from. This manager is empty after the merge. + */ + void Merge(RAS_BoundingBoxManager *other); +}; + +#endif // __RAS_MESH_BOUNDING_BOX_MANAGER_H__ diff --git a/source/gameengine/Rasterizer/RAS_BucketManager.cpp b/source/gameengine/Rasterizer/RAS_BucketManager.cpp index ec5e3402de5d..e467595f4526 100644 --- a/source/gameengine/Rasterizer/RAS_BucketManager.cpp +++ b/source/gameengine/Rasterizer/RAS_BucketManager.cpp @@ -30,350 +30,383 @@ */ #ifdef _MSC_VER - /* don't show these anoying STL warnings */ +/* don't show these anoying STL warnings */ # pragma warning (disable:4786) #endif #include "RAS_MaterialBucket.h" -#include "RAS_MeshObject.h" -#include "RAS_Polygon.h" -#include "RAS_IPolygonMaterial.h" -#include "RAS_IRasterizer.h" +#include "RAS_Mesh.h" +#include "RAS_MeshUser.h" +#include "RAS_IMaterial.h" +#include "RAS_Rasterizer.h" #include "RAS_BucketManager.h" #include /* sorting */ -struct RAS_BucketManager::sortedmeshslot +RAS_BucketManager::SortedMeshSlot::SortedMeshSlot(RAS_MeshSlot *ms, const mt::vec3& pnorm) + :m_ms(ms) { -public: - MT_Scalar m_z; /* depth */ - RAS_MeshSlot *m_ms; /* mesh slot */ - RAS_MaterialBucket *m_bucket; /* buck mesh slot came from */ + // would be good to use the actual bounding box center instead + const mt::vec3 pos = m_ms->m_meshUser->GetMatrix().TranslationVector3D(); - sortedmeshslot() {} + m_z = mt::dot(pnorm, pos); +} - void set(RAS_MeshSlot *ms, RAS_MaterialBucket *bucket, const MT_Vector3& pnorm) - { - // would be good to use the actual bounding box center instead - MT_Point3 pos(ms->m_OpenGLMatrix[12], ms->m_OpenGLMatrix[13], ms->m_OpenGLMatrix[14]); +RAS_BucketManager::SortedMeshSlot::SortedMeshSlot(RAS_MeshSlotUpwardNode *node, const mt::vec3& pnorm) + :m_node(node) +{ + RAS_MeshSlot *ms = m_node->GetOwner(); + // would be good to use the actual bounding box center instead + const mt::vec3 pos = ms->m_meshUser->GetMatrix().TranslationVector3D(); - m_z = MT_dot(pnorm, pos); - m_ms = ms; - m_bucket = bucket; - } -}; + m_z = mt::dot(pnorm, pos); +} -struct RAS_BucketManager::backtofront +bool RAS_BucketManager::backtofront::operator()(const SortedMeshSlot &a, const SortedMeshSlot &b) { - bool operator()(const sortedmeshslot &a, const sortedmeshslot &b) - { - return (a.m_z < b.m_z) || (a.m_z == b.m_z && a.m_ms < b.m_ms); - } -}; + return (a.m_z < b.m_z) || (a.m_z == b.m_z && a.m_ms < b.m_ms); +} -struct RAS_BucketManager::fronttoback +bool RAS_BucketManager::fronttoback::operator()(const SortedMeshSlot &a, const SortedMeshSlot &b) { - bool operator()(const sortedmeshslot &a, const sortedmeshslot &b) - { - return (a.m_z > b.m_z) || (a.m_z == b.m_z && a.m_ms > b.m_ms); - } -}; - -/* bucket manager */ + return (a.m_z > b.m_z) || (a.m_z == b.m_z && a.m_ms > b.m_ms); +} -RAS_BucketManager::RAS_BucketManager() +RAS_BucketManager::RAS_BucketManager(RAS_IMaterial *textMaterial) + :m_downwardNode(this, &m_nodeData, nullptr, nullptr), + m_upwardNode(this, &m_nodeData, nullptr, nullptr) { - + bool created; + m_text.m_bucket = FindBucket(textMaterial, created); + m_text.m_arrayBucket = new RAS_DisplayArrayBucket(m_text.m_bucket, nullptr, nullptr, nullptr, nullptr); } RAS_BucketManager::~RAS_BucketManager() { - BucketList::iterator it; + delete m_text.m_arrayBucket; - for (it = m_SolidBuckets.begin(); it != m_SolidBuckets.end(); it++) - delete (*it); + for (RAS_MaterialBucket *bucket : m_buckets[ALL_BUCKET]) { + delete bucket; + } +} - for (it = m_AlphaBuckets.begin(); it != m_AlphaBuckets.end(); it++) - delete(*it); +void RAS_BucketManager::PrepareBuckets(RAS_Rasterizer *rasty, RAS_BucketManager::BucketType bucketType) +{ + if (m_nodeData.m_shaderOverride) { + return; + } - m_SolidBuckets.clear(); - m_AlphaBuckets.clear(); + for (RAS_MaterialBucket *bucket : m_buckets[bucketType]) { + RAS_IMaterial *mat = bucket->GetMaterial(); + mat->Prepare(rasty); + } } -void RAS_BucketManager::OrderBuckets(const MT_Transform& cameratrans, BucketList& buckets, vector& slots, bool alpha) +void RAS_BucketManager::RenderSortedBuckets(RAS_Rasterizer *rasty, RAS_BucketManager::BucketType bucketType) { - BucketList::iterator bit; - list::iterator mit; - size_t size = 0, i = 0; - - /* Camera's near plane equation: pnorm.dot(point) + pval, - * but we leave out pval since it's constant anyway */ - const MT_Vector3 pnorm(cameratrans.getBasis()[2]); - - for (bit = buckets.begin(); bit != buckets.end(); ++bit) - { - SG_DList::iterator mit((*bit)->GetActiveMeshSlots()); - for (mit.begin(); !mit.end(); ++mit) - size++; + PrepareBuckets(rasty, bucketType); + + BucketList& solidBuckets = m_buckets[bucketType]; + RAS_UpwardTreeLeafs leafs; + for (RAS_MaterialBucket *bucket : solidBuckets) { + bucket->GenerateTree(m_downwardNode, m_upwardNode, leafs, m_nodeData.m_drawingMode, true); } - slots.resize(size); + m_nodeData.m_sort = true; - for (bit = buckets.begin(); bit != buckets.end(); ++bit) - { - RAS_MaterialBucket* bucket = *bit; - RAS_MeshSlot* ms; - // remove the mesh slot from the list, it culls them automatically for next frame - while ((ms = bucket->GetNextActiveMeshSlot())) { - slots[i++].set(ms, bucket, pnorm); + if (m_downwardNode.GetValid()) { + m_downwardNode.Execute(RAS_DummyNodeTuple()); + } + if (!leafs.empty()) { + /* Camera's near plane equation: pnorm.dot(point) + pval, + * but we leave out pval since it's constant anyway */ + const mt::mat3x4& trans = m_nodeData.m_trans; + const mt::vec3 pnorm(trans[2], trans[5], trans[8]); + std::vector sortedSlots(leafs.size()); + // Generate all SortedMeshSlot corresponding to all the leafs nodes. + std::transform(leafs.begin(), leafs.end(), sortedSlots.begin(), + [&pnorm](RAS_MeshSlotUpwardNode *node) { + return SortedMeshSlot(node, pnorm); + }); + + std::sort(sortedSlots.begin(), sortedSlots.end(), backtofront()); + + std::vector::const_iterator it = sortedSlots.begin(); + RAS_MeshSlotUpwardNodeIterator iterator((it++)->m_node); + for (std::vector::const_iterator end = sortedSlots.end(); it != end; ++it) { + iterator.NextNode(it->m_node); } } +} - if (alpha) - sort(slots.begin(), slots.end(), backtofront()); - else - sort(slots.begin(), slots.end(), fronttoback()); +void RAS_BucketManager::RenderBasicBuckets(RAS_Rasterizer *rasty, RAS_BucketManager::BucketType bucketType) +{ + PrepareBuckets(rasty, bucketType); + + RAS_UpwardTreeLeafs leafs; + for (RAS_MaterialBucket *bucket : m_buckets[bucketType]) { + bucket->GenerateTree(m_downwardNode, m_upwardNode, leafs, m_nodeData.m_drawingMode, false); + } + + if (m_downwardNode.GetValid()) { + m_nodeData.m_sort = false; + m_downwardNode.Execute(RAS_DummyNodeTuple()); + } } -void RAS_BucketManager::RenderAlphaBuckets(const MT_Transform& cameratrans, RAS_IRasterizer* rasty) +void RAS_BucketManager::Renderbuckets(RAS_Rasterizer::DrawType drawingMode, const mt::mat3x4& cameratrans, RAS_Rasterizer *rasty, + RAS_OffScreen *offScreen) { - vector slots; - vector::iterator sit; + m_nodeData.m_rasty = rasty; + m_nodeData.m_trans = cameratrans; + m_nodeData.m_drawingMode = drawingMode; + + switch (drawingMode) { + case RAS_Rasterizer::RAS_SHADOW: + { + const bool isVarianceShadow = rasty->GetShadowMode() == RAS_Rasterizer::RAS_SHADOW_VARIANCE; + + rasty->SetDepthMask(RAS_Rasterizer::RAS_DEPTHMASK_ENABLED); + + /* Rendering solid regular materials with an override shader for + * variance shadow or an empty shader. + */ + + m_nodeData.m_shaderOverride = true; + if (!m_buckets[SOLID_SHADOW_BUCKET].empty()) { + rasty->SetOverrideShader(isVarianceShadow ? + RAS_Rasterizer::RAS_OVERRIDE_SHADER_SHADOW_VARIANCE : + RAS_Rasterizer::RAS_OVERRIDE_SHADER_BLACK); + } + RenderBasicBuckets(rasty, SOLID_SHADOW_BUCKET); - // Having depth masks disabled/enabled gives different artifacts in - // case no sorting is done or is done inexact. For compatibility, we - // disable it. - if (rasty->GetDrawingMode() != RAS_IRasterizer::KX_SHADOW) - rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_DISABLED); + /* Rendering solid instancing materials with a different override + * shader for variance and simple shadow. + */ - OrderBuckets(cameratrans, m_AlphaBuckets, slots, true); + if (!m_buckets[SOLID_SHADOW_INSTANCING_BUCKET].empty()) { + rasty->SetOverrideShader(isVarianceShadow ? + RAS_Rasterizer::RAS_OVERRIDE_SHADER_SHADOW_VARIANCE_INSTANCING : + RAS_Rasterizer::RAS_OVERRIDE_SHADER_BLACK_INSTANCING); + } + RenderBasicBuckets(rasty, SOLID_SHADOW_INSTANCING_BUCKET); - for (sit=slots.begin(); sit!=slots.end(); ++sit) { - rasty->SetClientObject(sit->m_ms->m_clientObj); + if (isVarianceShadow) { + /* Rendering alpha shadow instancing materials with an override + * shader for variance shadow. + */ - while (sit->m_bucket->ActivateMaterial(cameratrans, rasty)) - sit->m_bucket->RenderMeshSlot(cameratrans, rasty, *(sit->m_ms)); + if (!m_buckets[ALPHA_SHADOW_INSTANCING_BUCKET].empty()) { + rasty->SetOverrideShader(RAS_Rasterizer::RAS_OVERRIDE_SHADER_SHADOW_VARIANCE_INSTANCING); + } + RenderBasicBuckets(rasty, ALPHA_SHADOW_INSTANCING_BUCKET); - // make this mesh slot culled automatically for next frame - // it will be culled out by frustum culling - sit->m_ms->SetCulled(true); - } + /* Rendering alpha shadow regular materials with an override + * shader for variance shadow and ordering. + */ - rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_ENABLED); -} + if (!m_buckets[ALPHA_SHADOW_BUCKET].empty()) { + rasty->SetOverrideShader(RAS_Rasterizer::RAS_OVERRIDE_SHADER_SHADOW_VARIANCE); + } + RenderBasicBuckets(rasty, ALPHA_SHADOW_BUCKET); -void RAS_BucketManager::RenderSolidBuckets(const MT_Transform& cameratrans, RAS_IRasterizer* rasty) -{ - BucketList::iterator bit; - - rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_ENABLED); - - for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) { -#if 1 - RAS_MaterialBucket* bucket = *bit; - RAS_MeshSlot* ms; - // remove the mesh slot from the list, it culls them automatically for next frame - while ((ms = bucket->GetNextActiveMeshSlot())) { - rasty->SetClientObject(ms->m_clientObj); - while (bucket->ActivateMaterial(cameratrans, rasty)) - bucket->RenderMeshSlot(cameratrans, rasty, *ms); - - // make this mesh slot culled automatically for next frame - // it will be culled out by frustum culling - ms->SetCulled(true); - } -#else - list::iterator mit; - for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) { - if (mit->IsCulled()) - continue; + rasty->SetOverrideShader(RAS_Rasterizer::RAS_OVERRIDE_SHADER_NONE); + } + else { + // Rendering alpha shadow materials (including instancing) with their shaders. - rasty->SetClientObject(rasty, mit->m_clientObj); + rasty->SetOverrideShader(RAS_Rasterizer::RAS_OVERRIDE_SHADER_NONE); + m_nodeData.m_shaderOverride = false; - while ((*bit)->ActivateMaterial(cameratrans, rasty)) - (*bit)->RenderMeshSlot(cameratrans, rasty, *mit); + RenderBasicBuckets(rasty, ALPHA_SHADOW_INSTANCING_BUCKET); + // Render alpha shadow regular materials with ordering. + RenderBasicBuckets(rasty, ALPHA_SHADOW_BUCKET); + } - // make this mesh slot culled automatically for next frame - // it will be culled out by frustum culling - mit->SetCulled(true); + break; } -#endif - } - - /* this code draws meshes order front-to-back instead to reduce overdraw. - * it turned out slower due to much material state switching, a more clever - * algorithm might do better. */ -#if 0 - vector slots; - vector::iterator sit; + case RAS_Rasterizer::RAS_WIREFRAME: + { + m_nodeData.m_shaderOverride = true; + rasty->SetLines(true); + rasty->SetDepthMask(RAS_Rasterizer::RAS_DEPTHMASK_ENABLED); - OrderBuckets(cameratrans, m_SolidBuckets, slots, false); + // Rendering solid regular materials with an empty override shader. - for (sit=slots.begin(); sit!=slots.end(); ++sit) { - rendertools->SetClientObject(rasty, sit->m_ms->m_clientObj); + if (!m_buckets[SOLID_BUCKET].empty()) { + rasty->SetOverrideShader(RAS_Rasterizer::RAS_OVERRIDE_SHADER_BLACK); + } + RenderBasicBuckets(rasty, SOLID_BUCKET); - while (sit->m_bucket->ActivateMaterial(cameratrans, rasty)) - sit->m_bucket->RenderMeshSlot(cameratrans, rasty, *(sit->m_ms)); - } -#endif -} + /* Rendering solid, alpha and alpha depth instancing materials + * with an override shader. + */ -void RAS_BucketManager::Renderbuckets(const MT_Transform& cameratrans, RAS_IRasterizer* rasty) -{ - /* beginning each frame, clear (texture/material) caching information */ - rasty->ClearCachingInfo(); - - RenderSolidBuckets(cameratrans, rasty); - RenderAlphaBuckets(cameratrans, rasty); - - /* If we're drawing shadows and bucket wasn't rendered (outside of the lamp frustum or doesn't cast shadows) - * then the mesh is still modified, so we don't want to set MeshModified to false yet (it will mess up - * updating display lists). Just leave this step for the main render pass. - */ - if (rasty->GetDrawingMode() != RAS_IRasterizer::KX_SHADOW) { - /* All meshes should be up to date now */ - /* Don't do this while processing buckets because some meshes are split between buckets */ - BucketList::iterator bit; - list::iterator mit; - for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) { - for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) { - mit->m_mesh->SetMeshModified(false); + if ((m_buckets[SOLID_INSTANCING_BUCKET].size() + m_buckets[ALPHA_INSTANCING_BUCKET].size()) > 0) { + rasty->SetOverrideShader(RAS_Rasterizer::RAS_OVERRIDE_SHADER_BLACK_INSTANCING); } - } - for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit) { - for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) { - mit->m_mesh->SetMeshModified(false); + RenderBasicBuckets(rasty, SOLID_INSTANCING_BUCKET); + RenderSortedBuckets(rasty, ALPHA_INSTANCING_BUCKET); + + /* Rendering alpha and alpha depth regular materials with + * an empty shader and ordering. + */ + + if (!m_buckets[ALPHA_BUCKET].empty()) { + rasty->SetOverrideShader(RAS_Rasterizer::RAS_OVERRIDE_SHADER_BLACK); } - } - } + RenderSortedBuckets(rasty, ALPHA_BUCKET); + rasty->SetOverrideShader(RAS_Rasterizer::RAS_OVERRIDE_SHADER_NONE); - rasty->SetClientObject(NULL); -} + rasty->SetLines(false); + break; + } + case RAS_Rasterizer::RAS_TEXTURED: + { + /* Rendering solid and alpha (regular and instancing) materials + * with their shaders. + */ -RAS_MaterialBucket *RAS_BucketManager::FindBucket(RAS_IPolyMaterial *material, bool &bucketCreated) -{ - BucketList::iterator it; + m_nodeData.m_shaderOverride = false; + rasty->SetDepthMask(RAS_Rasterizer::RAS_DEPTHMASK_ENABLED); - bucketCreated = false; + RenderBasicBuckets(rasty, SOLID_BUCKET); + RenderBasicBuckets(rasty, SOLID_INSTANCING_BUCKET); - for (it = m_SolidBuckets.begin(); it != m_SolidBuckets.end(); it++) - if (*(*it)->GetPolyMaterial() == *material) - return *it; + rasty->SetDepthMask(RAS_Rasterizer::RAS_DEPTHMASK_DISABLED); - for (it = m_AlphaBuckets.begin(); it != m_AlphaBuckets.end(); it++) - if (*(*it)->GetPolyMaterial() == *material) - return *it; + // Update depth transparency depth texture after rendering all solid materials. + if ((m_buckets[ALPHA_DEPTH_BUCKET].size() + m_buckets[ALPHA_DEPTH_INSTANCING_BUCKET].size()) > 0) { + rasty->UpdateGlobalDepthTexture(offScreen); + } + RenderBasicBuckets(rasty, ALPHA_INSTANCING_BUCKET); + RenderSortedBuckets(rasty, ALPHA_BUCKET); - RAS_MaterialBucket *bucket = new RAS_MaterialBucket(material); - bucketCreated = true; - if (bucket->IsAlpha()) - m_AlphaBuckets.push_back(bucket); - else - m_SolidBuckets.push_back(bucket); + rasty->SetDepthMask(RAS_Rasterizer::RAS_DEPTHMASK_ENABLED); + break; + } + case RAS_Rasterizer::RAS_RENDERER: + { + /* Rendering solid and alpha (regular and instancing) materials + * with their shaders. + */ - return bucket; -} + m_nodeData.m_shaderOverride = false; + rasty->SetDepthMask(RAS_Rasterizer::RAS_DEPTHMASK_ENABLED); -void RAS_BucketManager::OptimizeBuckets(MT_Scalar distance) -{ - BucketList::iterator bit; + RenderBasicBuckets(rasty, SOLID_BUCKET); + RenderBasicBuckets(rasty, SOLID_INSTANCING_BUCKET); - distance = 10.0f; + rasty->SetDepthMask(RAS_Rasterizer::RAS_DEPTHMASK_DISABLED); - for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) - (*bit)->Optimize(distance); - for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit) - (*bit)->Optimize(distance); -} + // Don't use depth transparency because the renderer could not offer a depth texture. + rasty->ResetGlobalDepthTexture(); -void RAS_BucketManager::ReleaseDisplayLists(RAS_IPolyMaterial *mat) -{ - BucketList::iterator bit; - list::iterator mit; - - for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) { - if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) { - for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) { - if (mit->m_DisplayList) { - mit->m_DisplayList->Release(); - mit->m_DisplayList = NULL; - } - } + RenderBasicBuckets(rasty, ALPHA_INSTANCING_BUCKET); + RenderSortedBuckets(rasty, ALPHA_BUCKET); + + rasty->SetDepthMask(RAS_Rasterizer::RAS_DEPTHMASK_ENABLED); + break; + } + default: + { + break; } } - for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit) { - if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) { - for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) { - if (mit->m_DisplayList) { - mit->m_DisplayList->Release(); - mit->m_DisplayList = NULL; - } - } - } + for (RAS_MaterialBucket *bucket : m_buckets[ALL_BUCKET]) { + bucket->RemoveActiveMeshSlots(); } + + rasty->SetClientObject(nullptr); } -void RAS_BucketManager::ReleaseMaterials(RAS_IPolyMaterial * mat) +RAS_MaterialBucket *RAS_BucketManager::FindBucket(RAS_IMaterial *material, bool &bucketCreated) { - BucketList::iterator bit; - list::iterator mit; + bucketCreated = false; - for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) { - if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) { - (*bit)->GetPolyMaterial()->ReleaseMaterial(); + for (RAS_MaterialBucket *bucket : m_buckets[ALL_BUCKET]) { + if (bucket->GetMaterial() == material) { + return bucket; } } - for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit) { - if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) { - (*bit)->GetPolyMaterial()->ReleaseMaterial(); + RAS_MaterialBucket *bucket = new RAS_MaterialBucket(material); + bucketCreated = true; + + const bool useinstancing = material->UseInstancing(); + if (!material->OnlyShadow()) { + if (material->IsAlpha()) { + m_buckets[useinstancing ? ALPHA_INSTANCING_BUCKET : ALPHA_BUCKET].push_back(bucket); + if (material->IsAlphaDepth()) { + m_buckets[useinstancing ? ALPHA_DEPTH_INSTANCING_BUCKET : ALPHA_DEPTH_BUCKET].push_back(bucket); + } + } + else { + m_buckets[useinstancing ? SOLID_INSTANCING_BUCKET : SOLID_BUCKET].push_back(bucket); } } + if (material->CastsShadows()) { + if (material->IsAlphaShadow()) { + m_buckets[useinstancing ? ALPHA_SHADOW_INSTANCING_BUCKET : ALPHA_SHADOW_BUCKET].push_back(bucket); + } + else { + m_buckets[useinstancing ? SOLID_SHADOW_INSTANCING_BUCKET : SOLID_SHADOW_BUCKET].push_back(bucket); + } + } + + // Used to free the bucket. + m_buckets[ALL_BUCKET].push_back(bucket); + return bucket; } -/* frees the bucket, only used when freeing scenes */ -void RAS_BucketManager::RemoveMaterial(RAS_IPolyMaterial * mat) +RAS_DisplayArrayBucket *RAS_BucketManager::GetTextDisplayArrayBucket() const { - BucketList::iterator bit, bitp; - list::iterator mit; - int i; - + return m_text.m_arrayBucket; +} - for (i=0; iGetPolyMaterial()) { - m_SolidBuckets.erase(m_SolidBuckets.begin()+i); - delete bucket; - i--; +void RAS_BucketManager::ReloadMaterials(RAS_IMaterial *mat) +{ + for (RAS_MaterialBucket *bucket : m_buckets[ALL_BUCKET]) { + if (mat == nullptr || (mat == bucket->GetMaterial())) { + bucket->GetMaterial()->ReloadMaterial(); } } +} - for (int i=0; iGetPolyMaterial()) { - m_AlphaBuckets.erase(m_AlphaBuckets.begin()+i); +void RAS_BucketManager::RemoveMaterial(RAS_IMaterial *mat) +{ + BucketList& allBuckets = m_buckets[ALL_BUCKET]; + for (BucketList::iterator it = allBuckets.begin(); it != allBuckets.end();) { + RAS_MaterialBucket *bucket = *it; + // Find the bucket in ALL_BUCKET list. + if (mat == bucket->GetMaterial()) { + // Iterate over all bucket list excepted ALL_BUCKET and remove the bucket. + for (unsigned short i = 0; i < ALL_BUCKET; ++i) { + CM_ListRemoveIfFound(m_buckets[i], bucket); + } + // Remove the bucket from ALL_BUCKET and destruct it. + it = allBuckets.erase(it); delete bucket; - i--; + } + else { + ++it; } } } -//#include - -void RAS_BucketManager::MergeBucketManager(RAS_BucketManager *other, SCA_IScene *scene) +void RAS_BucketManager::Merge(RAS_BucketManager *other, SCA_IScene *scene) { - /* concatenate lists */ - // printf("BEFORE %d %d\n", GetSolidBuckets().size(), GetAlphaBuckets().size()); + for (unsigned short i = 0; i < NUM_BUCKET_TYPE; ++i) { + BucketList& buckets = m_buckets[i]; + BucketList& otherbuckets = other->m_buckets[i]; - GetSolidBuckets().insert( GetSolidBuckets().end(), other->GetSolidBuckets().begin(), other->GetSolidBuckets().end() ); - other->GetSolidBuckets().clear(); - - GetAlphaBuckets().insert( GetAlphaBuckets().end(), other->GetAlphaBuckets().begin(), other->GetAlphaBuckets().end() ); - other->GetAlphaBuckets().clear(); - //printf("AFTER %d %d\n", GetSolidBuckets().size(), GetAlphaBuckets().size()); + // Skip the text bucket. + std::remove_copy(otherbuckets.begin(), otherbuckets.end(), std::back_inserter(buckets), other->m_text.m_bucket); + otherbuckets.clear(); + } } diff --git a/source/gameengine/Rasterizer/RAS_BucketManager.h b/source/gameengine/Rasterizer/RAS_BucketManager.h index dead4c619bd3..5e2894225e96 100644 --- a/source/gameengine/Rasterizer/RAS_BucketManager.h +++ b/source/gameengine/Rasterizer/RAS_BucketManager.h @@ -32,62 +32,96 @@ #ifndef __RAS_BUCKETMANAGER_H__ #define __RAS_BUCKETMANAGER_H__ -#include "MT_Transform.h" #include "RAS_MaterialBucket.h" #include -class RAS_BucketManager +class RAS_OffScreen; +class SCA_IScene; + +class RAS_BucketManager : public mt::SimdClassAllocator { public: - typedef std::vector BucketList; -private: - BucketList m_SolidBuckets; - BucketList m_AlphaBuckets; - - struct sortedmeshslot; - struct backtofront; - struct fronttoback; + typedef std::vector BucketList; + class SortedMeshSlot + { + public: + /// depth + float m_z; + + union { + RAS_MeshSlot *m_ms; + RAS_MeshSlotUpwardNode *m_node; + }; + + SortedMeshSlot() = default; + SortedMeshSlot(RAS_MeshSlot *ms, const mt::vec3& pnorm); + SortedMeshSlot(RAS_MeshSlotUpwardNode *node, const mt::vec3& pnorm); + }; + + struct backtofront + { + bool operator()(const SortedMeshSlot &a, const SortedMeshSlot &b); + }; + struct fronttoback + { + bool operator()(const SortedMeshSlot &a, const SortedMeshSlot &b); + }; + +protected: + enum BucketType { + SOLID_BUCKET = 0, + ALPHA_BUCKET, + SOLID_INSTANCING_BUCKET, + ALPHA_INSTANCING_BUCKET, + ALPHA_DEPTH_BUCKET, + ALPHA_DEPTH_INSTANCING_BUCKET, + SOLID_SHADOW_BUCKET, + ALPHA_SHADOW_BUCKET, + SOLID_SHADOW_INSTANCING_BUCKET, + ALPHA_SHADOW_INSTANCING_BUCKET, + ALL_BUCKET, + NUM_BUCKET_TYPE, + }; + + BucketList m_buckets[NUM_BUCKET_TYPE]; + + RAS_ManagerNodeData m_nodeData; + RAS_ManagerDownwardNode m_downwardNode; + RAS_ManagerUpwardNode m_upwardNode; + + struct TextData + { + RAS_MaterialBucket *m_bucket; + RAS_DisplayArrayBucket *m_arrayBucket; + } m_text; public: - RAS_BucketManager(); - virtual ~RAS_BucketManager(); - - void Renderbuckets(const MT_Transform & cameratrans, RAS_IRasterizer* rasty); - RAS_MaterialBucket* FindBucket(RAS_IPolyMaterial *material, bool &bucketCreated); - void OptimizeBuckets(MT_Scalar distance); + /** Initialize bucket manager and create material bucket for the text material. + * \param textMaterial The material used to render texts. + */ + RAS_BucketManager(RAS_IMaterial *textMaterial); + virtual ~RAS_BucketManager(); - void ReleaseDisplayLists(RAS_IPolyMaterial *material = NULL); - void ReleaseMaterials(RAS_IPolyMaterial *material = NULL); + void Renderbuckets(RAS_Rasterizer::DrawType drawingMode, const mt::mat3x4& cameratrans, RAS_Rasterizer *rasty, + RAS_OffScreen *offScreen); - void RemoveMaterial(RAS_IPolyMaterial *mat); // freeing scenes only + RAS_MaterialBucket *FindBucket(RAS_IMaterial *material, bool &bucketCreated); + RAS_DisplayArrayBucket *GetTextDisplayArrayBucket() const; - /* for merging */ - void MergeBucketManager(RAS_BucketManager *other, SCA_IScene *scene); - BucketList & GetSolidBuckets() {return m_SolidBuckets;} - BucketList & GetAlphaBuckets() {return m_AlphaBuckets;} + void ReloadMaterials(RAS_IMaterial *material = nullptr); - /*void PrintStats(int verbose_level) { - printf("\nMappings...\n"); - printf("\t m_SolidBuckets: %d\n", m_SolidBuckets.size()); - printf("\t\t m_SolidBuckets: %d\n", m_SolidBuckets.size()); - printf("\t m_AlphaBuckets: %d\n", m_AlphaBuckets.size()); - }*/ + // freeing scenes only + void RemoveMaterial(RAS_IMaterial *mat); + // for merging + void Merge(RAS_BucketManager *other, SCA_IScene *scene); private: - void OrderBuckets(const MT_Transform& cameratrans, BucketList& buckets, vector& slots, bool alpha); - - void RenderSolidBuckets(const MT_Transform& cameratrans, - RAS_IRasterizer* rasty); - void RenderAlphaBuckets(const MT_Transform& cameratrans, - RAS_IRasterizer* rasty); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_BucketManager") -#endif + void PrepareBuckets(RAS_Rasterizer *rasty, BucketType bucketType); + void RenderBasicBuckets(RAS_Rasterizer *rasty, BucketType bucketType); + void RenderSortedBuckets(RAS_Rasterizer *rasty, BucketType bucketType); }; -#endif /* __RAS_BUCKETMANAGER_H__ */ +#endif // __RAS_BUCKETMANAGER_H__ diff --git a/source/gameengine/Rasterizer/RAS_CameraData.h b/source/gameengine/Rasterizer/RAS_CameraData.h index bc8433afd055..b5e938ed7ea8 100644 --- a/source/gameengine/Rasterizer/RAS_CameraData.h +++ b/source/gameengine/Rasterizer/RAS_CameraData.h @@ -50,11 +50,12 @@ struct RAS_CameraData int m_viewportright; int m_viewporttop; float m_focallength; + float m_zoom; RAS_CameraData(float lens = 35.0f, float scale = 6.0f, float sensor_x = 32.0f, float sensor_y = 18.0f, short sensor_fit = 0, float shift_x = 0.0f, float shift_y = 0.0f, float clipstart = 0.1f, float clipend = 5000.0f, bool perspective = true, - float focallength = 3.0f, bool viewport = false, int viewportleft = 0, int viewportbottom = 0, + float focallength = 3.0f, float zoom = 1.0f, bool viewport = false, int viewportleft = 0, int viewportbottom = 0, int viewportright = 0, int viewporttop = 0) : m_lens(lens), m_scale(scale), @@ -71,7 +72,8 @@ struct RAS_CameraData m_viewportbottom(viewportbottom), m_viewportright(viewportright), m_viewporttop(viewporttop), - m_focallength(focallength) + m_focallength(focallength), + m_zoom(zoom) { } }; diff --git a/source/gameengine/Rasterizer/RAS_DebugDraw.cpp b/source/gameengine/Rasterizer/RAS_DebugDraw.cpp new file mode 100644 index 000000000000..6be88db9fbc8 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_DebugDraw.cpp @@ -0,0 +1,124 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Rasterizer/RAS_DebugDraw.cpp + * \ingroup bgerastogl + */ + +#include "RAS_DebugDraw.h" +#include "RAS_Rasterizer.h" + +RAS_DebugDraw::Shape::Shape(const mt::vec4& color) +{ + color.Pack(m_color); +} + +RAS_DebugDraw::Line::Line(const mt::vec3& from, const mt::vec3& to, const mt::vec4& color) +{ + color.Pack(m_color); + color.Pack(m_color2); + from.Pack(m_from); + to.Pack(m_to); +} + +RAS_DebugDraw::Aabb::Aabb(const mt::vec3& pos, const mt::mat3& rot, const mt::vec3& min, const mt::vec3& max, const mt::vec4& color) + :Shape(color) +{ + const mt::vec3 diag = (max - min) * 0.5f; + const mt::vec3 center = (min + max) * 0.5f; + + const mt::mat3x4 trans(rot, rot *center + pos, diag); + trans.PackFromAffineTransform(m_mat); +} + +RAS_DebugDraw::Frustum::Frustum(const mt::mat4& persmat, const mt::vec4& insideColor, const mt::vec4& outsideColor, + const mt::vec4& wireColor) +{ + persmat.Pack(m_persMat); + insideColor.Pack(m_insideColor); + outsideColor.Pack(m_outsideColor); + wireColor.Pack(m_wireColor); +} + +RAS_DebugDraw::Text2d::Text2d(const std::string& text, const mt::vec2& pos, const mt::vec4& color) + :Shape(color), + m_text(text) +{ + pos.Pack(m_pos); +} + +RAS_DebugDraw::Box2d::Box2d(const mt::vec2& pos, const mt::vec2& size, const mt::vec4& color) + :Shape(color) +{ + pos.Pack(m_pos); + + m_size[0] = size.x + 1; + m_size[1] = -size.y; +} + +RAS_DebugDraw::RAS_DebugDraw() +{ +} + +RAS_DebugDraw::~RAS_DebugDraw() = default; + +void RAS_DebugDraw::DrawLine(const mt::vec3 &from, const mt::vec3 &to, const mt::vec4 &color) +{ + m_lines.emplace_back(from, to, color); +} + +void RAS_DebugDraw::DrawAabb(const mt::vec3& pos, const mt::mat3& rot, + const mt::vec3& min, const mt::vec3& max, const mt::vec4& color) +{ + m_aabbs.emplace_back(pos, rot, min, max, color); +} + +void RAS_DebugDraw::DrawCameraFrustum(const mt::mat4& persmat) +{ + m_frustums.emplace_back(persmat.Inverse(), mt::vec4(0.4f, 0.4f, 0.4f, 0.4f), mt::vec4(0.0f, 0.0f, 0.0f, 0.4f), + mt::vec4(0.8f, 0.5f, 0.0f, 1.0f)); +} + +void RAS_DebugDraw::RenderBox2d(const mt::vec2& pos, const mt::vec2& size, const mt::vec4& color) +{ + m_boxes2d.emplace_back(pos, size, color); +} + +void RAS_DebugDraw::RenderText2d(const std::string& text, const mt::vec2& size, const mt::vec4& color) +{ + m_texts2d.emplace_back(text, size, color); +} + +void RAS_DebugDraw::Flush(RAS_Rasterizer *rasty, RAS_ICanvas *canvas) +{ + if ((m_lines.size() + m_aabbs.size() + m_frustums.size() + m_texts2d.size() + m_boxes2d.size()) == 0) { + return; + } + + rasty->FlushDebug(canvas, this); + + m_lines.clear(); + m_aabbs.clear(); + m_frustums.clear(); + m_texts2d.clear(); + m_boxes2d.clear(); +} diff --git a/source/gameengine/Rasterizer/RAS_DebugDraw.h b/source/gameengine/Rasterizer/RAS_DebugDraw.h new file mode 100644 index 000000000000..3862063e32ec --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_DebugDraw.h @@ -0,0 +1,126 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_DebugDraw.h + * \ingroup bgerast + */ + +#ifndef __RAS_DEBUG_DRAW_H__ +#define __RAS_DEBUG_DRAW_H__ + +#include "mathfu.h" + +#include +#include +#include +#include + +class RAS_Rasterizer; +class RAS_ICanvas; + +class RAS_DebugDraw +{ + friend class RAS_OpenGLDebugDraw; + +private: + struct Shape + { + Shape(const mt::vec4& color); + float m_color[4]; + }; + + struct Line + { + Line(const mt::vec3& from, const mt::vec3& to, const mt::vec4& color); + float m_color[4]; + float m_from[3]; + float m_color2[4]; + float m_to[3]; + }; + + struct Aabb : Shape + { + Aabb(const mt::vec3& pos, const mt::mat3& rot, const mt::vec3& min, const mt::vec3& max, const mt::vec4& color); + float m_mat[16]; + }; + + struct Frustum + { + Frustum(const mt::mat4& persmat, const mt::vec4& insideColor, const mt::vec4& outsideColor, const mt::vec4& wireColor); + float m_persMat[16]; + float m_wireColor[4]; + float m_insideColor[4]; + float m_outsideColor[4]; + }; + + struct Text2d : Shape + { + Text2d(const std::string& text, const mt::vec2& pos, const mt::vec4& color); + std::string m_text; + float m_pos[2]; + }; + + struct Box2d : Shape + { + Box2d(const mt::vec2& pos, const mt::vec2& size, const mt::vec4& color); + union { + struct { + float m_pos[2]; + float m_size[2]; + }; + float m_trans[4]; + }; + }; + + std::vector m_lines; + std::vector m_aabbs; + std::vector m_frustums; + std::vector m_texts2d; + std::vector m_boxes2d; + +public: + RAS_DebugDraw(); + ~RAS_DebugDraw(); + + void DrawLine(const mt::vec3 &from, const mt::vec3 &to, const mt::vec4& color); + /** Draw a box depends on minimal and maximal corner. + * \param pos The box's position. + * \param rot The box's orientation. + * \param min The box's minimal corner. + * \param max The box's maximal corner. + * \param color The box's color. + */ + void DrawAabb(const mt::vec3& pos, const mt::mat3& rot, + const mt::vec3& min, const mt::vec3& max, const mt::vec4& color); + /** Draw a box representing a camera frustum volume. + * \param projmat The camera perspective matrix. + */ + void DrawCameraFrustum(const mt::mat4& persmat); + + void RenderBox2d(const mt::vec2& pos, const mt::vec2& size, const mt::vec4& color); + + void RenderText2d(const std::string& text, const mt::vec2& pos, const mt::vec4& color); + + void Flush(RAS_Rasterizer *rasty, RAS_ICanvas *canvas); +}; + +#endif // __RAS_DEBUG_DRAW_H__ diff --git a/source/gameengine/Rasterizer/RAS_Deformer.cpp b/source/gameengine/Rasterizer/RAS_Deformer.cpp new file mode 100644 index 000000000000..f18d4cd29297 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_Deformer.cpp @@ -0,0 +1,76 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "RAS_Deformer.h" +#include "RAS_Mesh.h" + +RAS_Deformer::RAS_Deformer(RAS_Mesh *mesh) + :m_mesh(mesh), + m_bDynamic(false), + m_boundingBox(nullptr) +{ +} + +RAS_Deformer::~RAS_Deformer() +{ + for (const DisplayArraySlot& slot : m_slots) { + delete slot.m_displayArray; + delete slot.m_displayArrayBucket; + } +} + +void RAS_Deformer::InitializeDisplayArrays() +{ + for (RAS_MeshMaterial *meshmat : m_mesh->GetMeshMaterialList()) { + RAS_DisplayArray *origArray = meshmat->GetDisplayArray(); + /* Duplicate the display array bucket and the display array if needed to store + * the mesh slot on a unique list (= display array bucket) and use an unique vertex + * array (=display array). */ + RAS_DisplayArray *array = new RAS_DisplayArray(*origArray); + + RAS_DisplayArrayBucket *arrayBucket = new RAS_DisplayArrayBucket(meshmat->GetBucket(), array, m_mesh, meshmat, this); + + m_slots.push_back( + {array, origArray, meshmat, arrayBucket, + {RAS_DisplayArray::TANGENT_MODIFIED | RAS_DisplayArray::UVS_MODIFIED | RAS_DisplayArray::COLORS_MODIFIED, + RAS_DisplayArray::NONE_MODIFIED}}); + } + + for (DisplayArraySlot& slot : m_slots) { + slot.m_origDisplayArray->AddUpdateClient(&slot.m_arrayUpdateClient); + } +} + +RAS_Mesh *RAS_Deformer::GetMesh() const +{ + return m_mesh; +} + +RAS_DisplayArray *RAS_Deformer::GetDisplayArray(unsigned short index) const +{ + return m_slots[index].m_displayArray; +} + +RAS_DisplayArrayBucket *RAS_Deformer::GetDisplayArrayBucket(unsigned short index) const +{ + return m_slots[index].m_displayArrayBucket; +} diff --git a/source/gameengine/Rasterizer/RAS_Deformer.h b/source/gameengine/Rasterizer/RAS_Deformer.h index 5a2197ed81d1..2e4d53455284 100644 --- a/source/gameengine/Rasterizer/RAS_Deformer.h +++ b/source/gameengine/Rasterizer/RAS_Deformer.h @@ -36,67 +36,72 @@ # pragma warning (disable:4786) /* get rid of stupid stl-visual compiler debug warning */ #endif -#include -#include "CTR_Map.h" +#include "RAS_BoundingBox.h" +#include "RAS_DisplayArray.h" // For RAS_DisplayArrayList. +#include "RAS_DisplayArrayBucket.h" // For RAS_DisplayArrayBucketList. -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif +#include -struct DerivedMesh; -class RAS_MeshObject; +class RAS_Mesh; +class SCA_IObject; class RAS_Deformer { public: - RAS_Deformer() : m_pMesh(NULL), m_bDynamic(false) {} - virtual ~RAS_Deformer() {} - virtual void Relink(CTR_Map*map)=0; - virtual bool Apply(class RAS_IPolyMaterial *polymat)=0; + RAS_Deformer(RAS_Mesh *mesh); + virtual ~RAS_Deformer(); + + void InitializeDisplayArrays(); + + virtual void Apply(RAS_DisplayArray *array) = 0; virtual bool Update(void)=0; - virtual bool UpdateBuckets(void)=0; - virtual RAS_Deformer *GetReplica()=0; - virtual void ProcessReplica()=0; - virtual bool SkipVertexTransform() - { - return false; - } - virtual bool ShareVertexArray() - { - return true; - } - virtual bool UseVertexArray() - { - return true; - } + virtual void UpdateBuckets(void)=0; + // true when deformer produces varying vertex (shape or armature) bool IsDynamic() { return m_bDynamic; } - virtual struct DerivedMesh* GetFinalMesh() - { - return NULL; - } - virtual struct DerivedMesh* GetPhysicsMesh() + + virtual bool SkipVertexTransform() { - return NULL; + return false; } - virtual class RAS_MeshObject* GetRasMesh() + + RAS_BoundingBox *GetBoundingBox() const { - /* m_pMesh does not seem to be being used?? */ - return NULL; + return m_boundingBox; } - virtual float (* GetTransVerts(int *tot))[3] { *tot= 0; return NULL; } + + RAS_Mesh *GetMesh() const; + + RAS_DisplayArray *GetDisplayArray(unsigned short index) const; + RAS_DisplayArrayBucket *GetDisplayArrayBucket(unsigned short index) const; protected: - class RAS_MeshObject *m_pMesh; - bool m_bDynamic; + /// Struct wrapping display arrays owned/used by the deformer. + struct DisplayArraySlot + { + /// The unique display array owned by the deformer. + RAS_DisplayArray *m_displayArray; + /// The original display array used by the deformer to duplicate data. + RAS_DisplayArray *m_origDisplayArray; + /// The mesh material of the owning the original display array. + RAS_MeshMaterial *m_meshMaterial; + /// The unique display array bucket using the display array of this deformer. + RAS_DisplayArrayBucket *m_displayArrayBucket; + /// Update client of the orignal display array. + CM_UpdateClient m_arrayUpdateClient; + }; + std::vector m_slots; -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_Deformer") -#endif + RAS_Mesh *m_mesh; + bool m_bDynamic; + + /// Deformer bounding box. + RAS_BoundingBox *m_boundingBox; }; #endif + diff --git a/source/gameengine/Rasterizer/RAS_DisplayArray.cpp b/source/gameengine/Rasterizer/RAS_DisplayArray.cpp new file mode 100644 index 000000000000..dcf9a46e471d --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_DisplayArray.cpp @@ -0,0 +1,302 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_DisplayArray.cpp + * \ingroup bgerast + */ + +#include "RAS_DisplayArray.h" +#include "RAS_DisplayArrayStorage.h" +#include "RAS_Mesh.h" + +#include "GPU_glew.h" + +#include + +struct PolygonSort { + /// Distance from polygon center to camera near plane. + float m_z; + /// Index of the first vertex in the polygon. + unsigned int m_first; + + PolygonSort() = default; + + void Init(unsigned int first, const mt::vec3& center, const mt::vec3& pnorm) + { + m_first = first; + m_z = mt::dot(pnorm, center); + } + + struct BackToFront { + bool operator()(const PolygonSort &a, const PolygonSort &b) const + { + return a.m_z < b.m_z; + } + }; +}; + +RAS_DisplayArray::RAS_DisplayArray(PrimitiveType type, const RAS_DisplayArray::Format& format) + :m_type(type), + m_format(format), + m_maxOrigIndex(0) +{ +} + +RAS_DisplayArray::RAS_DisplayArray(const RAS_DisplayArray& other) + :m_type(other.m_type), + m_format(other.m_format), + m_vertexData(other.m_vertexData), + m_vertexInfos(other.m_vertexInfos), + m_primitiveIndices(other.m_primitiveIndices), + m_triangleIndices(other.m_triangleIndices), + m_maxOrigIndex(other.m_maxOrigIndex), + m_polygonCenters(other.m_polygonCenters) +{ +} + +RAS_DisplayArray::~RAS_DisplayArray() +{ +} + +unsigned int RAS_DisplayArray::AddVertex(const mt::vec3_packed& pos, const mt::vec3_packed& nor, const mt::vec4_packed& tan, + mt::vec2_packed uvs[RAS_Texture::MaxUnits], unsigned int colors[RAS_Texture::MaxUnits], unsigned int origIndex, uint8_t flag) +{ + m_vertexData.positions.push_back(pos); + m_vertexData.normals.push_back(nor); + m_vertexData.tangents.push_back(tan); + + for (unsigned short i = 0; i < m_format.uvSize; ++i) { + m_vertexData.uvs[i].push_back(uvs[i]); + } + + for (unsigned short i = 0; i < m_format.colorSize; ++i) { + m_vertexData.colors[i].push_back({colors[i]}); + } + + m_maxOrigIndex = std::max(m_maxOrigIndex, origIndex); + m_vertexInfos.emplace_back(origIndex, flag); + + return m_vertexInfos.size() - 1; +} + +template +void removeRange(List& list, unsigned int start, unsigned int end) +{ + if (end == -1) { + list.erase(list.begin() + start); + } + else { + list.erase(list.begin() + start, list.begin() + end); + } +} + +void RAS_DisplayArray::RemoveVertex(unsigned int start, unsigned int end) +{ + removeRange(m_vertexData.positions, start, end); + removeRange(m_vertexData.normals, start, end); + removeRange(m_vertexData.tangents, start, end); + + for (unsigned short i = 0; i < m_format.uvSize; ++i) { + removeRange(m_vertexData.uvs[i], start, end); + } + + for (unsigned short i = 0; i < m_format.colorSize; ++i) { + removeRange(m_vertexData.colors[i], start, end); + } + + removeRange(m_vertexInfos, start, end); +} + +void RAS_DisplayArray::RemovePrimitiveIndex(unsigned int start, unsigned int end) +{ + removeRange(m_primitiveIndices, start, end); +} + +void RAS_DisplayArray::RemoveTriangleIndex(unsigned int start, unsigned int end) +{ + removeRange(m_triangleIndices, start, end); +} + +void RAS_DisplayArray::Clear() +{ + m_vertexData.positions.clear(); + m_vertexData.normals.clear(); + m_vertexData.tangents.clear(); + + for (unsigned short i = 0; i < m_format.uvSize; ++i) { + m_vertexData.uvs[i].clear(); + } + + for (unsigned short i = 0; i < m_format.colorSize; ++i) { + m_vertexData.colors[i].clear(); + } + + m_vertexInfos.clear(); + m_primitiveIndices.clear(); + m_triangleIndices.clear(); + m_maxOrigIndex = 0; +} + +void RAS_DisplayArray::SortPolygons(const mt::mat3x4& transform, unsigned int *indexmap) +{ + const unsigned int totpoly = GetPrimitiveIndexCount() / 3; + + if (totpoly <= 1 || m_type == LINES) { + return; + } + + // Extract camera Z plane. + const mt::vec3 pnorm(transform[2], transform[5], transform[8]); + + if (m_polygonCenters.size() != totpoly) { + m_polygonCenters.resize(totpoly, mt::zero3); + for (unsigned int i = 0; i < totpoly; ++i) { + // Compute polygon center. + mt::vec3& center = m_polygonCenters[i]; + for (unsigned short j = 0; j < 3; ++j) { + /* Note that we don't divide by 3 as it is not needed + * to compare polygons. */ + center += mt::vec3(m_vertexData.positions[m_primitiveIndices[i * 3 + j]]); + } + } + } + + std::vector sortedPoly(totpoly); + // Get indices and polygon distance into temporary array. + for (unsigned int i = 0; i < totpoly; ++i) { + sortedPoly[i].Init(i * 3, pnorm, m_polygonCenters[i]); + } + + std::sort(sortedPoly.begin(), sortedPoly.end(), PolygonSort::BackToFront()); + + // Get indices from temporary array. + for (unsigned int i = 0; i < totpoly; ++i) { + const unsigned int first = sortedPoly[i].m_first; + for (unsigned short j = 0; j < 3; ++j) { + indexmap[i * 3 + j] = m_primitiveIndices[first + j]; + } + } +} + +void RAS_DisplayArray::InvalidatePolygonCenters() +{ + m_polygonCenters.clear(); +} + +RAS_DisplayArray::PrimitiveType RAS_DisplayArray::GetPrimitiveType() const +{ + return m_type; +} + +int RAS_DisplayArray::GetOpenGLPrimitiveType() const +{ + switch (m_type) { + case LINES: + { + return GL_LINES; + } + case TRIANGLES: + { + return GL_TRIANGLES; + } + } + return 0; +} + +void RAS_DisplayArray::UpdateFrom(RAS_DisplayArray *other, int flag) +{ + BLI_assert(m_format == other->GetFormat()); + + if (flag & POSITION_MODIFIED) { + m_vertexData.positions = other->m_vertexData.positions; + } + if (flag & NORMAL_MODIFIED) { + m_vertexData.normals = other->m_vertexData.normals; + } + if (flag & TANGENT_MODIFIED) { + m_vertexData.tangents = other->m_vertexData.tangents; + } + if (flag & UVS_MODIFIED) { + for (unsigned short i = 0; i < m_format.uvSize; ++i) { + m_vertexData.uvs[i] = other->m_vertexData.uvs[i]; + } + } + if (flag & COLORS_MODIFIED) { + for (unsigned short i = 0; i < m_format.colorSize; ++i) { + m_vertexData.colors[i] = other->m_vertexData.colors[i]; + } + } + + NotifyUpdate(flag); +} + +const RAS_DisplayArray::Format& RAS_DisplayArray::GetFormat() const +{ + return m_format; +} + +RAS_DisplayArrayLayout RAS_DisplayArray::GetLayout() const +{ + RAS_DisplayArrayLayout layout; + intptr_t offset = 0; + + const unsigned int size = GetVertexCount(); + + layout.position = offset; + offset += sizeof(mt::vec3_packed) * size; + + layout.normal = offset; + offset += sizeof(mt::vec3_packed) * size; + + layout.tangent = offset; + offset += sizeof(mt::vec4_packed) * size; + + for (unsigned short i = 0; i < m_format.uvSize; ++i) { + layout.uvs[i] = offset; + offset += sizeof(mt::vec2_packed) * size; + } + + for (unsigned short i = 0; i < m_format.colorSize; ++i) { + layout.colors[i] = offset; + offset += sizeof(unsigned int) * size; + } + + layout.size = offset; + + return layout; +} + +RAS_DisplayArray::Type RAS_DisplayArray::GetType() const +{ + return NORMAL; +} + +RAS_DisplayArrayStorage& RAS_DisplayArray::GetStorage() +{ + return m_storage; +} + +void RAS_DisplayArray::ConstructStorage() +{ + m_storage.Construct(this); + m_storage.UpdateSize(); +} diff --git a/source/gameengine/Rasterizer/RAS_DisplayArray.h b/source/gameengine/Rasterizer/RAS_DisplayArray.h new file mode 100644 index 000000000000..ec9076c54d63 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_DisplayArray.h @@ -0,0 +1,322 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_DisplayArray.h + * \ingroup bgerast + */ + +#ifndef __RAS_IDISPLAY_ARRAY_H__ +#define __RAS_IDISPLAY_ARRAY_H__ + +#include "RAS_DisplayArrayStorage.h" +#include "RAS_DisplayArrayLayout.h" +#include "RAS_VertexInfo.h" + +#include "CM_Update.h" + +#include "BLI_math_vector.h" + +#include "mathfu.h" + +#include +#include +#include + +class RAS_BatchDisplayArray; +class RAS_StorageVbo; + +class RAS_DisplayArray : public CM_UpdateServer +{ + friend RAS_BatchDisplayArray; + friend RAS_StorageVbo; + +public: + enum PrimitiveType { + TRIANGLES, + LINES, + }; + + enum Type { + NORMAL, + BATCHING + }; + + /// Modification categories. + enum { + NONE_MODIFIED = 0, + POSITION_MODIFIED = 1 << 0, // Vertex position modified. + NORMAL_MODIFIED = 1 << 1, // Vertex normal modified. + UVS_MODIFIED = 1 << 2, // Vertex UVs modified. + COLORS_MODIFIED = 1 << 3, // Vertex colors modified. + TANGENT_MODIFIED = 1 << 4, // Vertex tangent modified. + SIZE_MODIFIED = 1 << 5, // Vertex and index array changed of size. + STORAGE_INVALID = 1 << 6, // Storage not yet created. + AABB_MODIFIED = POSITION_MODIFIED, + MESH_MODIFIED = POSITION_MODIFIED | NORMAL_MODIFIED | UVS_MODIFIED | + COLORS_MODIFIED | TANGENT_MODIFIED, + ANY_MODIFIED = MESH_MODIFIED | SIZE_MODIFIED | STORAGE_INVALID + }; + + /// Struct used to pass the vertex format to functions. + struct Format + { + uint8_t uvSize; + uint8_t colorSize; + + Format() = default; + + /// Operators used to compare the contents (uv size, color size, ...) of two vertex formats. + inline bool operator== (const Format& other) const + { + return (uvSize == other.uvSize && colorSize == other.colorSize); + } + + inline bool operator!= (const Format& other) const + { + return !(*this == other); + } + }; + +protected: + /// The display array primitive type. + PrimitiveType m_type; + /// The vertex format used. + Format m_format; + + struct VertexData + { + std::vector positions; + std::vector normals; + std::vector tangents; + std::vector uvs[RAS_Texture::MaxUnits]; + + union Color + { + unsigned int m_flat; + unsigned char m_array[4]; + }; + + std::vector colors[RAS_Texture::MaxUnits]; + } m_vertexData; + + /// The vertex infos unused for rendering, e.g original or soft body index, flag. + std::vector m_vertexInfos; + /// The indices used for rendering. + std::vector m_primitiveIndices; + /// The indices of the original triangle independently of the primitive type. + std::vector m_triangleIndices; + + /// Maximum original vertex index. + unsigned int m_maxOrigIndex; + + /** Polygon centers cache used to sort polygons depending on depth. + * This list is stored here because we sort per array not per entire mesh. + */ + std::vector > m_polygonCenters; + + /// The OpenGL data storage used for rendering. + RAS_DisplayArrayStorage m_storage; + +public: + RAS_DisplayArray(PrimitiveType type, const Format& format); + RAS_DisplayArray(const RAS_DisplayArray& other); + ~RAS_DisplayArray(); + + inline mt::vec3_packed& GetPosition(const unsigned int index) + { + return m_vertexData.positions[index]; + } + + inline mt::vec3_packed& GetNormal(const unsigned int index) + { + return m_vertexData.normals[index]; + } + + inline mt::vec4_packed& GetTangent(const unsigned int index) + { + return m_vertexData.tangents[index]; + } + + inline mt::vec2_packed& GetUv(const unsigned int index, const unsigned short layer) + { + return m_vertexData.uvs[layer][index]; + } + + inline unsigned char(&GetColor(const unsigned int index, const unsigned short layer))[4] + { + return m_vertexData.colors[layer][index].m_array; + } + + inline unsigned int& GetRawColor(const unsigned int index, const unsigned short layer) + { + return m_vertexData.colors[layer][index].m_flat; + } + + inline void SetPosition(const unsigned int index, const mt::vec3_packed& value) + { + m_vertexData.positions[index] = value; + } + + inline void SetPosition(const unsigned int index, const mt::vec3& value) + { + m_vertexData.positions[index] = value; + } + + inline void SetNormal(const unsigned int index, const mt::vec3_packed& value) + { + m_vertexData.normals[index] = value; + } + + inline void SetNormal(const unsigned int index, const mt::vec3& value) + { + m_vertexData.normals[index] = value; + } + + inline void SetTangent(const unsigned int index, const mt::vec4_packed& value) + { + m_vertexData.tangents[index] = value; + } + + inline void SetTangent(const unsigned int index, const mt::vec4& value) + { + m_vertexData.tangents[index] = value; + } + + inline void SetUv(const unsigned int index, const unsigned short layer, const mt::vec2_packed& value) + { + m_vertexData.uvs[layer][index] = value; + } + + inline void SetUv(const unsigned int index, const unsigned short layer, const mt::vec2& value) + { + m_vertexData.uvs[layer][index] = value; + } + + inline void SetColor(const unsigned int index, const unsigned short layer, const unsigned char value[4]) + { + VertexData::Color color; + copy_v4_v4_uchar(color.m_array, value); + m_vertexData.colors[layer][index] = color; + } + + inline void SetColor(const unsigned int index, const unsigned short layer, const unsigned int value) + { + m_vertexData.colors[layer][index].m_flat = value; + } + + inline void SetColor(const unsigned int index, const unsigned short layer, const mt::vec4& col) + { + VertexData::Color& color = m_vertexData.colors[layer][index]; + for (unsigned short i = 0; i < 4; ++i) { + color.m_array[i] = (unsigned char)(col[i] * 255.0f); + } + } + + inline unsigned int GetPrimitiveIndex(const unsigned int index) const + { + return m_primitiveIndices[index]; + } + + inline unsigned int GetTriangleIndex(const unsigned int index) const + { + return m_triangleIndices[index]; + } + + inline const RAS_VertexInfo& GetVertexInfo(const unsigned int index) const + { + return m_vertexInfos[index]; + } + + inline RAS_VertexInfo& GetVertexInfo(const unsigned int index) + { + return m_vertexInfos[index]; + } + + unsigned int AddVertex(const mt::vec3_packed& pos, const mt::vec3_packed& nor, const mt::vec4_packed& tan, + mt::vec2_packed uvs[RAS_Texture::MaxUnits], unsigned int colors[RAS_Texture::MaxUnits], unsigned int origIndex, uint8_t flag); + + inline void AddPrimitiveIndex(const unsigned int index) + { + m_primitiveIndices.push_back(index); + } + + inline void AddTriangleIndex(const unsigned int origIndex) + { + m_triangleIndices.push_back(origIndex); + } + + void RemoveVertex(unsigned int start, unsigned int end); + void RemovePrimitiveIndex(unsigned int start, unsigned int end); + void RemoveTriangleIndex(unsigned int start, unsigned int end); + + void Clear(); + + inline unsigned int GetVertexCount() const + { + return m_vertexData.positions.size(); + } + + inline unsigned int GetPrimitiveIndexCount() const + { + return m_primitiveIndices.size(); + } + + inline unsigned int GetTriangleIndexCount() const + { + return m_triangleIndices.size(); + } + + inline unsigned int GetMaxOrigIndex() const + { + return m_maxOrigIndex; + } + + void SortPolygons(const mt::mat3x4& transform, unsigned int *indexmap); + void InvalidatePolygonCenters(); + + /** Copy vertex data from an other display array. Different vertex type is allowed. + * \param other The other display array to copy from. + * \param flag The flag coresponding to datas to copy. + */ + void UpdateFrom(RAS_DisplayArray *other, int flag); + + /// Return the primitive type used for indices. + PrimitiveType GetPrimitiveType() const; + /// Return the primitive type used for indices in OpenGL value. + int GetOpenGLPrimitiveType() const; + + /// Return the vertex format used. + const Format& GetFormat() const; + + /// Return the vertex memory format used. + RAS_DisplayArrayLayout GetLayout() const; + + /// Return the type of the display array. + virtual Type GetType() const; + + RAS_DisplayArrayStorage& GetStorage(); + void ConstructStorage(); +}; + +using RAS_DisplayArrayList = std::vector; + +#endif // __RAS_IDISPLAY_ARRAY_H__ diff --git a/source/gameengine/Rasterizer/RAS_DisplayArrayBucket.cpp b/source/gameengine/Rasterizer/RAS_DisplayArrayBucket.cpp new file mode 100644 index 000000000000..c8d1b549b525 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_DisplayArrayBucket.cpp @@ -0,0 +1,401 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Rasterizer/RAS_DisplayArrayBucket.cpp + * \ingroup bgerast + */ + +#include "RAS_DisplayArrayBucket.h" +#include "RAS_BatchDisplayArray.h" +#include "RAS_DisplayArrayStorage.h" +#include "RAS_AttributeArrayStorage.h" +#include "RAS_MaterialBucket.h" +#include "RAS_IMaterial.h" +#include "RAS_Mesh.h" +#include "RAS_MeshUser.h" +#include "RAS_Deformer.h" +#include "RAS_BatchGroup.h" +#include "RAS_Rasterizer.h" +#include "RAS_InstancingBuffer.h" +#include "RAS_BucketManager.h" + +#include + +#ifdef _MSC_VER +# pragma warning (disable:4786) +#endif + +#ifdef WIN32 +# include +#endif // WIN32 + +RAS_DisplayArrayBucket::RAS_DisplayArrayBucket(RAS_MaterialBucket *bucket, RAS_DisplayArray *array, + RAS_Mesh *mesh, RAS_MeshMaterial *meshmat, RAS_Deformer *deformer) + :m_bucket(bucket), + m_displayArray(array), + m_mesh(mesh), // TODO remove + m_meshMaterial(meshmat), + m_deformer(deformer), + m_arrayStorage(nullptr), + m_attribArray(m_displayArray), + m_materialUpdateClient(RAS_IMaterial::ATTRIBUTES_MODIFIED, RAS_IMaterial::ATTRIBUTES_MODIFIED), + m_arrayUpdateClient(RAS_DisplayArray::ANY_MODIFIED, RAS_DisplayArray::STORAGE_INVALID), + m_instancingNode(this, &m_nodeData, &RAS_DisplayArrayBucket::RunInstancingNode, nullptr), + m_batchingNode(this, &m_nodeData, &RAS_DisplayArrayBucket::RunBatchingNode, nullptr) +{ + m_bucket->AddDisplayArrayBucket(this); + + // Display array can be null in case of text. + if (m_displayArray) { + m_downwardNode = RAS_DisplayArrayDownwardNode(this, &m_nodeData, &RAS_DisplayArrayBucket::RunDownwardNode, nullptr); + m_upwardNode = RAS_DisplayArrayUpwardNode(this, &m_nodeData, &RAS_DisplayArrayBucket::BindUpwardNode, + &RAS_DisplayArrayBucket::UnbindUpwardNode); + + m_arrayStorage = &m_displayArray->GetStorage(); + m_displayArray->AddUpdateClient(&m_arrayUpdateClient); + } + else { + // If there's no display array then we draw using text, in this case the display array bind/unbind should be avoid. + m_downwardNode = RAS_DisplayArrayDownwardNode(this, &m_nodeData, &RAS_DisplayArrayBucket::RunDownwardNodeNoArray, nullptr); + m_upwardNode = RAS_DisplayArrayUpwardNode(this, &m_nodeData, nullptr, nullptr); + } + + // Initialize node arguments. + m_nodeData.m_array = m_displayArray; + m_nodeData.m_arrayStorage = m_arrayStorage; + m_nodeData.m_attribStorage = nullptr; + m_nodeData.m_applyMatrix = (!m_deformer || !m_deformer->SkipVertexTransform()); + + RAS_IMaterial *material = bucket->GetMaterial(); + material->AddUpdateClient(&m_materialUpdateClient); +} + +RAS_DisplayArrayBucket::~RAS_DisplayArrayBucket() +{ + m_bucket->RemoveDisplayArrayBucket(this); +} + +RAS_MaterialBucket *RAS_DisplayArrayBucket::GetBucket() const +{ + return m_bucket; +} + +RAS_DisplayArray *RAS_DisplayArrayBucket::GetDisplayArray() const +{ + return m_displayArray; +} + +RAS_Mesh *RAS_DisplayArrayBucket::GetMesh() const +{ + return m_mesh; +} + +RAS_MeshMaterial *RAS_DisplayArrayBucket::GetMeshMaterial() const +{ + return m_meshMaterial; +} + +void RAS_DisplayArrayBucket::ActivateMesh(RAS_MeshSlot *slot) +{ + m_activeMeshSlots.push_back(slot); +} + +void RAS_DisplayArrayBucket::RemoveActiveMeshSlots() +{ + m_activeMeshSlots.clear(); +} + +bool RAS_DisplayArrayBucket::UseBatching() const +{ + return (m_displayArray && m_displayArray->GetType() == RAS_DisplayArray::BATCHING); +} + +void RAS_DisplayArrayBucket::UpdateActiveMeshSlots(RAS_Rasterizer::DrawType drawingMode, bool instancing) +{ + if (m_deformer) { + m_deformer->Apply(m_displayArray); + } + + if (m_displayArray) { + const unsigned int modifiedFlag = m_arrayUpdateClient.GetInvalidAndClear(); + if (modifiedFlag != RAS_DisplayArray::NONE_MODIFIED) { + if (modifiedFlag & RAS_DisplayArray::STORAGE_INVALID) { + m_displayArray->ConstructStorage(); + } + else if (modifiedFlag & RAS_DisplayArray::SIZE_MODIFIED) { + m_arrayStorage->UpdateSize(); + // Invalidate all existing attribute storages. + m_attribArray.Clear(); + } + // Set the display array storage modified if the mesh is modified. + else if (modifiedFlag & RAS_DisplayArray::MESH_MODIFIED) { + m_arrayStorage->UpdateVertexData(modifiedFlag); + } + + if (modifiedFlag & RAS_DisplayArray::POSITION_MODIFIED) { + // Reset polygons center cache to ask update. + m_displayArray->InvalidatePolygonCenters(); + } + } + + if (m_materialUpdateClient.GetInvalidAndClear()) { + RAS_IMaterial *mat = m_bucket->GetMaterial(); + const RAS_Mesh::LayersInfo& layersInfo = m_mesh->GetLayersInfo(); + const RAS_AttributeArray::AttribList attribList = mat->GetAttribs(layersInfo); + + m_attribArray = RAS_AttributeArray(attribList, m_displayArray); + } + + m_nodeData.m_attribStorage = m_attribArray.GetStorage(drawingMode); + } + + if (instancing) { + // Create the instancing buffer only if needed. + if (!m_instancingBuffer[drawingMode]) { + RAS_IMaterial *mat = m_bucket->GetMaterial(); + m_instancingBuffer[drawingMode].reset(new RAS_InstancingBuffer(mat->GetInstancingAttribs())); + } + + m_nodeData.m_instancingBuffer = m_instancingBuffer[drawingMode].get(); + } +} + +void RAS_DisplayArrayBucket::GenerateTree(RAS_MaterialDownwardNode& downwardRoot, RAS_MaterialUpwardNode& upwardRoot, + RAS_UpwardTreeLeafs& upwardLeafs, RAS_Rasterizer::DrawType drawingMode, bool sort, bool instancing) +{ + if (m_activeMeshSlots.empty()) { + return; + } + + // Update deformer and render settings. + UpdateActiveMeshSlots(drawingMode, instancing); + + if (instancing) { + downwardRoot.AddChild(&m_instancingNode); + } + else if (UseBatching()) { + downwardRoot.AddChild(&m_batchingNode); + } + else if (sort) { + for (RAS_MeshSlot *slot : m_activeMeshSlots) { + slot->GenerateTree(m_upwardNode, upwardLeafs); + } + + m_upwardNode.SetParent(&upwardRoot); + } + else { + downwardRoot.AddChild(&m_downwardNode); + } +} + +void RAS_DisplayArrayBucket::BindUpwardNode(const RAS_DisplayArrayNodeTuple& tuple) +{ + m_nodeData.m_attribStorage->BindPrimitives(); +} + +void RAS_DisplayArrayBucket::UnbindUpwardNode(const RAS_DisplayArrayNodeTuple& tuple) +{ + m_nodeData.m_attribStorage->UnbindPrimitives(); +} + +void RAS_DisplayArrayBucket::RunDownwardNode(const RAS_DisplayArrayNodeTuple& tuple) +{ + RAS_AttributeArrayStorage *attribStorage = m_nodeData.m_attribStorage; + attribStorage->BindPrimitives(); + + const RAS_MeshSlotNodeTuple msTuple(tuple, &m_nodeData); + for (RAS_MeshSlot *ms : m_activeMeshSlots) { + // Reuse the node function without spend time storing RAS_MeshSlot under nodes. + ms->RunNode(msTuple); + } + + attribStorage->UnbindPrimitives(); +} + +void RAS_DisplayArrayBucket::RunDownwardNodeNoArray(const RAS_DisplayArrayNodeTuple& tuple) +{ + const RAS_MeshSlotNodeTuple msTuple(tuple, &m_nodeData); + for (RAS_MeshSlot *ms : m_activeMeshSlots) { + // Reuse the node function without spend time storing RAS_MeshSlot under nodes. + ms->RunNode(msTuple); + } +} + +void RAS_DisplayArrayBucket::RunInstancingNode(const RAS_DisplayArrayNodeTuple& tuple) +{ + RAS_ManagerNodeData *managerData = tuple.m_managerData; + RAS_MaterialNodeData *materialData = tuple.m_materialData; + RAS_Rasterizer *rasty = managerData->m_rasty; + + const unsigned int nummeshslots = m_activeMeshSlots.size(); + + RAS_IMaterial *material = materialData->m_material; + RAS_InstancingBuffer *buffer = m_nodeData.m_instancingBuffer; + + const short matPasIndex = material->GetPassIndex(); + + // Bind the instancing buffer to work on it. + buffer->Realloc(nummeshslots); + + /* If the material use the transparency we must sort all mesh slots depending on the distance. + * This code share the code used in RAS_BucketManager to do the sort. + */ + if (managerData->m_sort) { + std::vector sortedMeshSlots(nummeshslots); + + const mt::mat3x4& trans = managerData->m_trans; + const mt::vec3 pnorm(trans[2], trans[5], trans[8]); + std::transform(m_activeMeshSlots.begin(), m_activeMeshSlots.end(), sortedMeshSlots.begin(), + [&pnorm](RAS_MeshSlot *slot) { + return RAS_BucketManager::SortedMeshSlot(slot, pnorm); + }); + + std::sort(sortedMeshSlots.begin(), sortedMeshSlots.end(), RAS_BucketManager::backtofront()); + RAS_MeshSlotList meshSlots(nummeshslots); + for (unsigned int i = 0; i < nummeshslots; ++i) { + meshSlots[i] = sortedMeshSlots[i].m_ms; + } + + // Fill the buffer with the sorted mesh slots. + buffer->Update(rasty, materialData->m_drawingMode, matPasIndex, meshSlots); + } + else { + // Fill the buffer with the original mesh slots. + buffer->Update(rasty, materialData->m_drawingMode, matPasIndex, m_activeMeshSlots); + } + + RAS_AttributeArrayStorage *attribStorage = m_nodeData.m_attribStorage; + // Make sure to bind the VAO before instancing attributes to not clear them. + attribStorage->BindPrimitives(); + + buffer->Bind(); + + // Bind all vertex attributs for the used material and the given buffer offset. + if (managerData->m_shaderOverride) { + rasty->ActivateOverrideShaderInstancing(buffer); + } + else { + material->ActivateInstancing(rasty, buffer); + } + + /* Because the geometry instancing use setting for all instances we use the original alpha blend. + * This requierd that the user use "alpha blend" mode if he will mutate object color alpha. + */ + rasty->SetAlphaBlend(material->GetAlphaBlend()); + + /* It's a major issue of the geometry instancing : we can't manage face wise. + * To be sure we don't use the old face wise we force it to true. */ + rasty->SetFrontFace(true); + + // Unbind the buffer to avoid conflict with the render after. + buffer->Unbind(); + + m_arrayStorage->IndexPrimitivesInstancing(nummeshslots); + + // Unbind attributes, both array attributes and instancing attributes. + attribStorage->UnbindPrimitives(); +} + +void RAS_DisplayArrayBucket::RunBatchingNode(const RAS_DisplayArrayNodeTuple& tuple) +{ + RAS_ManagerNodeData *managerData = tuple.m_managerData; + RAS_MaterialNodeData *materialData = tuple.m_materialData; + + RAS_IMaterial *material = materialData->m_material; + const unsigned int nummeshslots = m_activeMeshSlots.size(); + + // We must use a int instead of unsigned size to match GLsizei type. + std::vector counts(nummeshslots); + std::vector indices(nummeshslots); + + RAS_BatchDisplayArray *batchArray = static_cast(m_displayArray); + + /* If the material use the transparency we must sort all mesh slots depending on the distance. + * This code share the code used in RAS_BucketManager to do the sort. + */ + if (managerData->m_sort) { + std::vector sortedMeshSlots(nummeshslots); + + const mt::mat3x4& trans = managerData->m_trans; + const mt::vec3 pnorm(trans[2], trans[5], trans[8]); + std::transform(m_activeMeshSlots.begin(), m_activeMeshSlots.end(), sortedMeshSlots.begin(), + [&pnorm](RAS_MeshSlot *slot) { + return RAS_BucketManager::SortedMeshSlot(slot, pnorm); + }); + + std::sort(sortedMeshSlots.begin(), sortedMeshSlots.end(), RAS_BucketManager::backtofront()); + for (unsigned int i = 0; i < nummeshslots; ++i) { + const short index = sortedMeshSlots[i].m_ms->m_batchPartIndex; + indices[i] = batchArray->GetPartIndexOffset(index); + counts[i] = batchArray->GetPartIndexCount(index); + } + } + else { + for (unsigned int i = 0; i < nummeshslots; ++i) { + const short index = m_activeMeshSlots[i]->m_batchPartIndex; + indices[i] = batchArray->GetPartIndexOffset(index); + counts[i] = batchArray->GetPartIndexCount(index); + } + } + + RAS_Rasterizer *rasty = managerData->m_rasty; + + /* Because the batching use setting for all instances we use the original alpha blend. + * This requierd that the user use "alpha blend" mode if he will mutate object color alpha. + */ + rasty->SetAlphaBlend(materialData->m_material->GetAlphaBlend()); + + /* It's a major issue of the batching : we can't manage face wise per object. + * To be sure we don't use the old face wise we force it to true. */ + rasty->SetFrontFace(true); + + // Retrieve batch group from first active mesh slot. + RAS_BatchGroup *group = m_activeMeshSlots.front()->m_meshUser->GetBatchGroup(); + // Use batch group reference mesh user for layer and object color. + material->ActivateMeshUser(group->GetReferenceMeshUser(), rasty, managerData->m_trans); + + RAS_AttributeArrayStorage *attribStorage = m_nodeData.m_attribStorage; + attribStorage->BindPrimitives(); + + m_arrayStorage->IndexPrimitivesBatching(indices, counts); + + attribStorage->UnbindPrimitives(); +} + +void RAS_DisplayArrayBucket::ChangeMaterialBucket(RAS_MaterialBucket *bucket) +{ + m_bucket = bucket; + + // Change of material update looking. + RAS_IMaterial *material = bucket->GetMaterial(); + material->MoveUpdateClient(&m_materialUpdateClient, RAS_IMaterial::ATTRIBUTES_MODIFIED); + + // Instancing buffers are linked to material attributes, invalid them. + for (unsigned short i = 0; i < RAS_Rasterizer::RAS_DRAW_MAX; ++i) { + m_instancingBuffer[i].reset(nullptr); + } +} diff --git a/source/gameengine/Rasterizer/RAS_DisplayArrayBucket.h b/source/gameengine/Rasterizer/RAS_DisplayArrayBucket.h new file mode 100644 index 000000000000..376c9e48ae60 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_DisplayArrayBucket.h @@ -0,0 +1,120 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_DisplayArrayBucket.h + * \ingroup bgerast + */ + +#ifndef __RAS_DISPLAY_MATERIAL_BUCKET_H__ +#define __RAS_DISPLAY_MATERIAL_BUCKET_H__ + +#include "CM_Update.h" + +#include "RAS_MeshSlot.h" +#include "RAS_AttributeArray.h" + +#include + +class RAS_MaterialBucket; +class RAS_DisplayArray; +class RAS_Mesh; +class RAS_MeshMaterial; +class RAS_Deformer; +class RAS_IStorageInfo; +class RAS_InstancingBuffer; + +class RAS_DisplayArrayBucket +{ +private: + /// The parent bucket. + RAS_MaterialBucket *m_bucket; + /// The display array = list of vertexes and indexes. + RAS_DisplayArray *m_displayArray; + /// The parent mesh object, it can be nullptr for text objects. + RAS_Mesh *m_mesh; + /// The material mesh. + RAS_MeshMaterial *m_meshMaterial; + /// The list of all visible mesh slots to render this frame. + RAS_MeshSlotList m_activeMeshSlots; + /// The deformer using this display array. + RAS_Deformer *m_deformer; + + RAS_DisplayArrayStorage *m_arrayStorage; + /// Attribute array used for each different render categories. + RAS_AttributeArray m_attribArray; + + /// The vertex buffer object containing all the data used for the instancing rendering for each drawing category. + std::unique_ptr m_instancingBuffer[RAS_Rasterizer::RAS_DRAW_MAX]; + + CM_UpdateClient m_materialUpdateClient; + CM_UpdateClient m_arrayUpdateClient; + + RAS_DisplayArrayNodeData m_nodeData; + RAS_DisplayArrayDownwardNode m_downwardNode; + RAS_DisplayArrayUpwardNode m_upwardNode; + + RAS_DisplayArrayDownwardNode m_instancingNode; + RAS_DisplayArrayDownwardNode m_batchingNode; + +public: + RAS_DisplayArrayBucket(RAS_MaterialBucket *bucket, RAS_DisplayArray *array, + RAS_Mesh *mesh, RAS_MeshMaterial *meshmat, RAS_Deformer *deformer); + ~RAS_DisplayArrayBucket(); + + /// \section Accesor + RAS_MaterialBucket *GetBucket() const; + RAS_DisplayArray *GetDisplayArray() const; + RAS_Mesh *GetMesh() const; + RAS_MeshMaterial *GetMeshMaterial() const; + + /// \section Active Mesh Slots Management. + void ActivateMesh(RAS_MeshSlot *slot); + /// Remove all mesh slots from the list. + void RemoveActiveMeshSlots(); + + /// \section Render Infos + bool UseBatching() const; + + /// Update render infos. + void UpdateActiveMeshSlots(RAS_Rasterizer::DrawType drawingMode, bool instancing); + + void GenerateTree(RAS_MaterialDownwardNode& downwardRoot, RAS_MaterialUpwardNode& upwardRoot, + RAS_UpwardTreeLeafs& upwardLeafs, RAS_Rasterizer::DrawType drawingMode, bool sort, bool instancing); + void BindUpwardNode(const RAS_DisplayArrayNodeTuple& tuple); + void UnbindUpwardNode(const RAS_DisplayArrayNodeTuple& tuple); + void RunDownwardNode(const RAS_DisplayArrayNodeTuple& tuple); + void RunDownwardNodeNoArray(const RAS_DisplayArrayNodeTuple& tuple); + void RunInstancingNode(const RAS_DisplayArrayNodeTuple& tuple); + void RunBatchingNode(const RAS_DisplayArrayNodeTuple& tuple); + + /// Replace the material bucket of this display array bucket by the one given. + void ChangeMaterialBucket(RAS_MaterialBucket *bucket); +}; + +typedef std::vector RAS_DisplayArrayBucketList; + +#endif // __RAS_DISPLAY_MATERIAL_BUCKET_H__ diff --git a/source/gameengine/Rasterizer/RAS_DisplayArrayLayout.h b/source/gameengine/Rasterizer/RAS_DisplayArrayLayout.h new file mode 100644 index 000000000000..3887976bbc07 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_DisplayArrayLayout.h @@ -0,0 +1,16 @@ +#ifndef __RAS_DISPLAY_ARRAY_LAYOUT_H__ +#define __RAS_DISPLAY_ARRAY_LAYOUT_H__ + +#include "RAS_Texture.h" // For RAS_Texture::MaxUnits + +struct RAS_DisplayArrayLayout +{ + intptr_t position; + intptr_t normal; + intptr_t tangent; + intptr_t uvs[RAS_Texture::MaxUnits]; + intptr_t colors[RAS_Texture::MaxUnits]; + intptr_t size; +}; + +#endif // __RAS_DISPLAY_ARRAY_LAYOUT_H__ diff --git a/source/gameengine/Rasterizer/RAS_DisplayArrayStorage.cpp b/source/gameengine/Rasterizer/RAS_DisplayArrayStorage.cpp new file mode 100644 index 000000000000..917c793c3f12 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_DisplayArrayStorage.cpp @@ -0,0 +1,55 @@ +#include "RAS_DisplayArrayStorage.h" +#include "RAS_StorageVbo.h" + +RAS_DisplayArrayStorage::RAS_DisplayArrayStorage() +{ +} + +RAS_DisplayArrayStorage::~RAS_DisplayArrayStorage() +{ +} + +void RAS_DisplayArrayStorage::Construct(RAS_DisplayArray *array) +{ + m_vbo.reset(new RAS_StorageVbo(array)); +} + +RAS_StorageVbo *RAS_DisplayArrayStorage::GetVbo() const +{ + return m_vbo.get(); +} + +void RAS_DisplayArrayStorage::UpdateVertexData(unsigned int modifiedFlag) +{ + m_vbo->UpdateVertexData(modifiedFlag); +} + +void RAS_DisplayArrayStorage::UpdateSize() +{ + m_vbo->UpdateSize(); +} + +unsigned int *RAS_DisplayArrayStorage::GetIndexMap() +{ + return m_vbo->GetIndexMap(); +} + +void RAS_DisplayArrayStorage::FlushIndexMap() +{ + m_vbo->FlushIndexMap(); +} + +void RAS_DisplayArrayStorage::IndexPrimitives() +{ + m_vbo->IndexPrimitives(); +} + +void RAS_DisplayArrayStorage::IndexPrimitivesInstancing(unsigned int numslots) +{ + m_vbo->IndexPrimitivesInstancing(numslots); +} + +void RAS_DisplayArrayStorage::IndexPrimitivesBatching(const std::vector& indices, const std::vector& counts) +{ + m_vbo->IndexPrimitivesBatching(indices, counts); +} diff --git a/source/gameengine/Rasterizer/RAS_DisplayArrayStorage.h b/source/gameengine/Rasterizer/RAS_DisplayArrayStorage.h new file mode 100644 index 000000000000..db6f5637ccc1 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_DisplayArrayStorage.h @@ -0,0 +1,47 @@ +#ifndef __RAS_DISPLAY_ARRAY_STORAGE_H__ +#define __RAS_DISPLAY_ARRAY_STORAGE_H__ + +#include +#include + +class RAS_DisplayArray; +class RAS_StorageVbo; +class RAS_StorageVao; + +class RAS_DisplayArrayStorage +{ + friend RAS_StorageVao; + +private: + std::unique_ptr m_vbo; + + RAS_StorageVbo *GetVbo() const; + +public: + RAS_DisplayArrayStorage(); + ~RAS_DisplayArrayStorage(); + + // Construct manually to take care that the OpenGL context is current (case of asynchronous libloading). + void Construct(RAS_DisplayArray *array); + + void UpdateVertexData(unsigned int modifiedFlag); + void UpdateSize(); + /// Map the index data and return its pointer. + unsigned int *GetIndexMap(); + /// Flush the index data map. + void FlushIndexMap(); + + /// Render the display array. + void IndexPrimitives(); + /** Render the display array using instancing. + * \param numslots The number of instance to render. + */ + void IndexPrimitivesInstancing(unsigned int numslots); + /** Render the display array using indirect indices array. + * \param indices The list of indices pointers to read. + * \param counts The number of indices associated to the indices pointers. + */ + void IndexPrimitivesBatching(const std::vector& indices, const std::vector& counts); +}; + +#endif // __RAS_DISPLAY_ARRAY_STORAGE_H__ diff --git a/source/gameengine/Rasterizer/RAS_FramingManager.cpp b/source/gameengine/Rasterizer/RAS_FramingManager.cpp index b2148b94d090..5dd936d5e21b 100644 --- a/source/gameengine/Rasterizer/RAS_FramingManager.cpp +++ b/source/gameengine/Rasterizer/RAS_FramingManager.cpp @@ -33,19 +33,16 @@ #include "RAS_FramingManager.h" #include "RAS_Rect.h" - void -RAS_FramingManager:: -ComputeDefaultFrustum( - const float camnear, - const float camfar, - const float lens, - const float sensor_x, const float sensor_y, - const short sensor_fit, - const float shift_x, - const float shift_y, - const float design_aspect_ratio, - RAS_FrameFrustum & frustum -) { +void RAS_FramingManager::ComputeDefaultFrustum(const float camnear, + const float camfar, + const float lens, + const float sensor_x, const float sensor_y, + const short sensor_fit, + const float shift_x, + const float shift_y, + const float design_aspect_ratio, + RAS_FrameFrustum & frustum) +{ float size; float halfSize; float sizeX; @@ -53,25 +50,26 @@ ComputeDefaultFrustum( float offsetX; float offsetY; - if (sensor_fit==RAS_SENSORFIT_AUTO) { + if (sensor_fit == RAS_SENSORFIT_AUTO) { size = sensor_x * camnear / lens; halfSize = size * 0.5f; if (design_aspect_ratio > 1.f) { // halfsize defines the width sizeX = halfSize; - sizeY = halfSize/design_aspect_ratio; - } else { + sizeY = halfSize / design_aspect_ratio; + } + else { // halfsize defines the height sizeX = halfSize * design_aspect_ratio; sizeY = halfSize; } } - else if (sensor_fit==RAS_SENSORFIT_HOR) { + else if (sensor_fit == RAS_SENSORFIT_HOR) { size = sensor_x * camnear / lens; halfSize = size * 0.5f; sizeX = halfSize; - sizeY = halfSize/design_aspect_ratio; + sizeY = halfSize / design_aspect_ratio; } else { size = sensor_y * camnear / lens; @@ -91,39 +89,36 @@ ComputeDefaultFrustum( frustum.camfar = camfar; } - void -RAS_FramingManager:: -ComputeDefaultOrtho( - const float camnear, - const float camfar, - const float scale, - const float design_aspect_ratio, - const short sensor_fit, - const float shift_x, - const float shift_y, - RAS_FrameFrustum & frustum -) +void RAS_FramingManager::ComputeDefaultOrtho(const float camnear, + const float camfar, + const float scale, + const float design_aspect_ratio, + const short sensor_fit, + const float shift_x, + const float shift_y, + RAS_FrameFrustum & frustum) { - float halfSize = scale*0.5f; + float halfSize = scale * 0.5f; float sizeX; float sizeY; float offsetX; float offsetY; - if (sensor_fit==RAS_SENSORFIT_AUTO) { + if (sensor_fit == RAS_SENSORFIT_AUTO) { if (design_aspect_ratio > 1.f) { // halfsize defines the width sizeX = halfSize; - sizeY = halfSize/design_aspect_ratio; - } else { + sizeY = halfSize / design_aspect_ratio; + } + else { // halfsize defines the height sizeX = halfSize * design_aspect_ratio; sizeY = halfSize; } } - else if (sensor_fit==RAS_SENSORFIT_HOR) { + else if (sensor_fit == RAS_SENSORFIT_HOR) { sizeX = halfSize; - sizeY = halfSize/design_aspect_ratio; + sizeY = halfSize / design_aspect_ratio; } else { sizeX = halfSize * design_aspect_ratio; @@ -142,20 +137,17 @@ ComputeDefaultOrtho( } - void -RAS_FramingManager:: -ComputeBestFitViewRect( - const RAS_Rect &availableViewport, - const float design_aspect_ratio, - RAS_Rect &viewport -) { +void RAS_FramingManager::ComputeBestFitViewRect(const RAS_Rect &availableViewport, + const float design_aspect_ratio, + RAS_Rect &viewport) +{ // try and honour the aspect ratio when setting the // drawable area. If we don't do this we are liable // to get a lot of distortion in the rendered image. int width = availableViewport.GetWidth(); int height = availableViewport.GetHeight(); - float window_aspect = float(width)/float(height); + float window_aspect = float(width) / float(height); if (window_aspect < design_aspect_ratio) { int v_height = (int)(width / design_aspect_ratio); @@ -166,7 +158,8 @@ ComputeBestFitViewRect( viewport.SetRight(availableViewport.GetLeft() + width); viewport.SetTop(availableViewport.GetBottom() + left_over + v_height); - } else { + } + else { int v_width = (int)(height * design_aspect_ratio); int left_over = (width - v_width) / 2; @@ -177,14 +170,10 @@ ComputeBestFitViewRect( } } - void -RAS_FramingManager:: -ComputeViewport( - const RAS_FrameSettings &settings, - const RAS_Rect &availableViewport, - RAS_Rect &viewport -) { - +void RAS_FramingManager::ComputeViewport(const RAS_FrameSettings &settings, + const RAS_Rect &availableViewport, + RAS_Rect &viewport) +{ RAS_FrameSettings::RAS_FrameType type = settings.FrameType(); const int winx = availableViewport.GetWidth(); const int winy = availableViewport.GetHeight(); @@ -199,13 +188,13 @@ ComputeViewport( // lets just scale the thing type = RAS_FrameSettings::e_frame_scale; - } else { - design_aspect_ratio = design_width/design_height; + } + else { + design_aspect_ratio = design_width / design_height; } switch (type) { - - case RAS_FrameSettings::e_frame_scale : + case RAS_FrameSettings::e_frame_scale: case RAS_FrameSettings::e_frame_extend: { viewport.SetLeft(availableViewport.GetLeft()); @@ -222,30 +211,28 @@ ComputeViewport( availableViewport, design_aspect_ratio, viewport - ); + ); break; } - default : + default: + { break; + } } } - void -RAS_FramingManager:: -ComputeFrustum( - const RAS_FrameSettings &settings, - const RAS_Rect &availableViewport, - const RAS_Rect &viewport, - const float lens, - const float sensor_x, const float sensor_y, const short sensor_fit, - const float shift_x, - const float shift_y, - const float camnear, - const float camfar, - RAS_FrameFrustum &frustum -) { - +void RAS_FramingManager::ComputeFrustum(const RAS_FrameSettings &settings, + const RAS_Rect &availableViewport, + const RAS_Rect &viewport, + const float lens, + const float sensor_x, const float sensor_y, const short sensor_fit, + const float shift_x, + const float shift_y, + const float camnear, + const float camfar, + RAS_FrameFrustum &frustum) +{ RAS_FrameSettings::RAS_FrameType type = settings.FrameType(); const float design_width = float(settings.DesignAspectWidth()); @@ -258,8 +245,9 @@ ComputeFrustum( // lets just scale the thing type = RAS_FrameSettings::e_frame_scale; - } else { - design_aspect_ratio = design_width/design_height; + } + else { + design_aspect_ratio = design_width / design_height; } ComputeDefaultFrustum( @@ -273,10 +261,9 @@ ComputeFrustum( shift_y, design_aspect_ratio, frustum - ); + ); switch (type) { - case RAS_FrameSettings::e_frame_extend: { float x_scale, y_scale; @@ -301,14 +288,14 @@ ComputeFrustum( availableViewport, design_aspect_ratio, vt - ); + ); // now scale the calculated frustum by the difference // between vt and the viewport in each axis. // These are always > 1 - x_scale = float(viewport.GetWidth())/float(vt.GetWidth()); - y_scale = float(viewport.GetHeight())/float(vt.GetHeight()); + x_scale = float(viewport.GetWidth()) / float(vt.GetWidth()); + y_scale = float(viewport.GetHeight()) / float(vt.GetHeight()); break; } } @@ -320,27 +307,25 @@ ComputeFrustum( break; } - case RAS_FrameSettings::e_frame_scale : + case RAS_FrameSettings::e_frame_scale: case RAS_FrameSettings::e_frame_bars: - default : + default: + { break; + } } } - void -RAS_FramingManager:: - ComputeOrtho( - const RAS_FrameSettings &settings, - const RAS_Rect &availableViewport, - const RAS_Rect &viewport, - const float scale, - const float camnear, - const float camfar, - const short sensor_fit, - const float shift_x, - const float shift_y, - RAS_FrameFrustum &frustum - ) +void RAS_FramingManager::ComputeOrtho(const RAS_FrameSettings &settings, + const RAS_Rect &availableViewport, + const RAS_Rect &viewport, + const float scale, + const float camnear, + const float camfar, + const short sensor_fit, + const float shift_x, + const float shift_y, + RAS_FrameFrustum &frustum) { RAS_FrameSettings::RAS_FrameType type = settings.FrameType(); @@ -353,8 +338,9 @@ RAS_FramingManager:: // well this is ill defined // lets just scale the thing type = RAS_FrameSettings::e_frame_scale; - } else { - design_aspect_ratio = design_width/design_height; + } + else { + design_aspect_ratio = design_width / design_height; } @@ -367,10 +353,9 @@ RAS_FramingManager:: shift_x, shift_y, frustum - ); + ); switch (type) { - case RAS_FrameSettings::e_frame_extend: { float x_scale, y_scale; @@ -401,8 +386,8 @@ RAS_FramingManager:: // between vt and the viewport in each axis. // These are always > 1 - x_scale = float(viewport.GetWidth())/float(vt.GetWidth()); - y_scale = float(viewport.GetHeight())/float(vt.GetHeight()); + x_scale = float(viewport.GetWidth()) / float(vt.GetWidth()); + y_scale = float(viewport.GetHeight()) / float(vt.GetHeight()); break; } } @@ -414,10 +399,11 @@ RAS_FramingManager:: break; } - case RAS_FrameSettings::e_frame_scale : + case RAS_FrameSettings::e_frame_scale: case RAS_FrameSettings::e_frame_bars: - default : + default: + { break; + } } - } diff --git a/source/gameengine/Rasterizer/RAS_FramingManager.h b/source/gameengine/Rasterizer/RAS_FramingManager.h index 3fb488a5af6c..a6e8c0311319 100644 --- a/source/gameengine/Rasterizer/RAS_FramingManager.h +++ b/source/gameengine/Rasterizer/RAS_FramingManager.h @@ -32,10 +32,6 @@ #ifndef __RAS_FRAMINGMANAGER_H__ #define __RAS_FRAMINGMANAGER_H__ -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - class RAS_Rect; /** @@ -61,7 +57,7 @@ class RAS_Rect; class RAS_FrameSettings { -public : +public: /** * enum defining the policy to use * in each axis. @@ -82,96 +78,79 @@ public : float bar_g, float bar_b, unsigned int design_aspect_width, - unsigned int design_aspect_height - ): - m_frame_type(frame_type), + unsigned int design_aspect_height) + :m_frame_type(frame_type), m_bar_r(bar_r), m_bar_g(bar_g), m_bar_b(bar_b), m_design_aspect_width(design_aspect_width), m_design_aspect_height(design_aspect_height) { - }; + } - RAS_FrameSettings( - ): - m_frame_type(e_frame_scale), + RAS_FrameSettings() + :m_frame_type(e_frame_scale), m_bar_r(0), m_bar_g(0), m_bar_b(0), m_design_aspect_width(1), m_design_aspect_height(1) { - }; + } /** * Accessors */ - const - RAS_FrameType & - FrameType( - ) const { + const RAS_FrameType &FrameType() const + { return m_frame_type; - }; + } - void - SetFrameType( - RAS_FrameType type - ) { + void SetFrameType(RAS_FrameType type) + { m_frame_type = type; - }; + } - float - BarRed( - ) const { + float BarRed() const + { return m_bar_r; - }; + } - float - BarGreen( - ) const { + float BarGreen() const + { return m_bar_g; - }; + } - float - BarBlue( - ) const { + float BarBlue() const + { return m_bar_b; - }; + } - unsigned int - DesignAspectWidth( - ) const { + unsigned int DesignAspectWidth() const + { return m_design_aspect_width; - }; + } - unsigned int - DesignAspectHeight( - ) const { + unsigned int DesignAspectHeight() const + { return m_design_aspect_height; - }; - -private : + } +private: RAS_FrameType m_frame_type; float m_bar_r; float m_bar_g; float m_bar_b; unsigned int m_design_aspect_width; unsigned int m_design_aspect_height; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_FrameSettings") -#endif }; struct RAS_FrameFrustum { - float camnear,camfar; - float x1,y1; - float x2,y2; + float camnear, camfar; + float x1, y1; + float x2, y2; }; /* must match R_CULLING_... from DNA_scene_types.h */ @@ -203,22 +182,17 @@ enum RAS_SensorFit class RAS_FramingManager { -public : - +public: /** * Compute a viewport given * a RAS_FrameSettings and a description of the * canvas. */ - static - void - ComputeViewport( + static void ComputeViewport( const RAS_FrameSettings &settings, const RAS_Rect &availableViewport, - RAS_Rect &viewport - ); - + RAS_Rect &viewport); /** * compute a frustum given a valid viewport, @@ -226,9 +200,7 @@ public : * and camera description */ - static - void - ComputeOrtho( + static void ComputeOrtho( const RAS_FrameSettings &settings, const RAS_Rect &availableViewport, const RAS_Rect &viewport, @@ -238,12 +210,9 @@ public : const short sensor_fit, const float shift_x, const float shift_y, - RAS_FrameFrustum &frustum - ); + RAS_FrameFrustum &frustum); - static - void - ComputeFrustum( + static void ComputeFrustum( const RAS_FrameSettings &settings, const RAS_Rect &availableViewport, const RAS_Rect &viewport, @@ -253,12 +222,9 @@ public : const float shift_y, const float camnear, const float camfar, - RAS_FrameFrustum &frustum - ); + RAS_FrameFrustum &frustum); - static - void - ComputeDefaultFrustum( + static void ComputeDefaultFrustum( const float camnear, const float camfar, const float lens, @@ -267,12 +233,9 @@ public : const float shift_x, const float shift_y, const float design_aspect_ratio, - RAS_FrameFrustum & frustum - ); + RAS_FrameFrustum & frustum); - static - void - ComputeDefaultOrtho( + static void ComputeDefaultOrtho( const float camnear, const float camfar, const float scale, @@ -280,37 +243,22 @@ public : const short sensor_fit, const float shift_x, const float shift_y, - RAS_FrameFrustum & frustum - ); - -private : + RAS_FrameFrustum & frustum); - static - void - ComputeBestFitViewRect( +private: + static void ComputeBestFitViewRect( const RAS_Rect &availableViewport, const float design_aspect_ratio, - RAS_Rect &viewport - ); - - + RAS_Rect &viewport); /** * Private constructor - this class is not meant * for instantiation. */ - RAS_FramingManager( - ); + RAS_FramingManager(); - RAS_FramingManager( - const RAS_FramingManager & - ); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_FramingManager") -#endif + RAS_FramingManager(const RAS_FramingManager &); }; #endif diff --git a/source/gameengine/Rasterizer/RAS_ICanvas.cpp b/source/gameengine/Rasterizer/RAS_ICanvas.cpp index 808d257f8f0c..47c872dc76f2 100644 --- a/source/gameengine/Rasterizer/RAS_ICanvas.cpp +++ b/source/gameengine/Rasterizer/RAS_ICanvas.cpp @@ -36,18 +36,20 @@ #include "MEM_guardedalloc.h" extern "C" { -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" +# include "IMB_imbuf.h" +# include "IMB_imbuf_types.h" } +#include "CM_Message.h" + +#include // for free() // Task data for saving screenshots in a different thread. -struct ScreenshotTaskData -{ +struct ScreenshotTaskData { unsigned int *dumprect; int dumpsx; int dumpsy; - char *path; + char path[FILE_MAX]; ImageFormatData *im_format; }; @@ -60,11 +62,21 @@ struct ScreenshotTaskData */ void save_screenshot_thread_func(TaskPool *__restrict pool, void *taskdata, int threadid); +const int RAS_ICanvas::swapInterval[RAS_ICanvas::SWAP_CONTROL_MAX] = { + 0, // VSYNC_OFF + 1, // VSYNC_ON + -1 // VSYNC_ADAPTIVE +}; -RAS_ICanvas::RAS_ICanvas() +RAS_ICanvas::RAS_ICanvas(RAS_Rasterizer *rasty) + :m_samples(0), + m_hdrType(RAS_Rasterizer::RAS_HDR_NONE), + m_swapControl(VSYNC_OFF), + m_frame(1) { m_taskscheduler = BLI_task_scheduler_create(TASK_SCHEDULER_AUTO_THREADS); - m_taskpool = BLI_task_pool_create(m_taskscheduler, NULL); + m_taskpool = BLI_task_pool_create(m_taskscheduler, nullptr); + m_rasterizer = rasty; } RAS_ICanvas::~RAS_ICanvas() @@ -72,15 +84,66 @@ RAS_ICanvas::~RAS_ICanvas() if (m_taskpool) { BLI_task_pool_work_and_wait(m_taskpool); BLI_task_pool_free(m_taskpool); - m_taskpool = NULL; + m_taskpool = nullptr; } if (m_taskscheduler) { BLI_task_scheduler_free(m_taskscheduler); - m_taskscheduler = NULL; + m_taskscheduler = nullptr; + } +} + +void RAS_ICanvas::SetSwapControl(SwapControl control) +{ + m_swapControl = control; +} + +RAS_ICanvas::SwapControl RAS_ICanvas::GetSwapControl() const +{ + return m_swapControl; +} + +void RAS_ICanvas::SetSamples(int samples) +{ + m_samples = samples; +} + +int RAS_ICanvas::GetSamples() const +{ + return m_samples; +} + +void RAS_ICanvas::SetHdrType(RAS_Rasterizer::HdrType type) +{ + m_hdrType = type; +} + +RAS_Rasterizer::HdrType RAS_ICanvas::GetHdrType() const +{ + return m_hdrType; +} + +void RAS_ICanvas::FlushScreenshots() +{ + for (const Screenshot& screenshot : m_screenshots) { + SaveScreeshot(screenshot); } + + m_screenshots.clear(); } +void RAS_ICanvas::AddScreenshot(const std::string& path, int x, int y, int width, int height, ImageFormatData *format) +{ + Screenshot screenshot; + screenshot.path = path; + screenshot.x = x; + screenshot.y = y; + screenshot.width = width; + screenshot.height = height; + screenshot.format = format; + + m_screenshots.push_back(screenshot); +} void save_screenshot_thread_func(TaskPool *__restrict UNUSED(pool), void *taskdata, int UNUSED(threadid)) { @@ -92,33 +155,34 @@ void save_screenshot_thread_func(TaskPool *__restrict UNUSED(pool), void *taskda BKE_imbuf_write_as(ibuf, task->path, task->im_format, false); - ibuf->rect = NULL; + ibuf->rect = nullptr; IMB_freeImBuf(ibuf); - MEM_freeN(task->dumprect); - MEM_freeN(task->path); + // Dumprect is allocated in RAS_OpenGLRasterizer::MakeScreenShot with malloc(), we must use free() then. + free(task->dumprect); MEM_freeN(task->im_format); } -void RAS_ICanvas::save_screenshot(const char *filename, int dumpsx, int dumpsy, unsigned int *dumprect, - ImageFormatData * im_format) +void RAS_ICanvas::SaveScreeshot(const Screenshot& screenshot) { - /* create file path */ - char *path = (char *)MEM_mallocN(FILE_MAX, "screenshot-path"); - BLI_strncpy(path, filename, FILE_MAX); - BLI_path_abs(path, G.main->name); - BLI_path_frame(path, m_frame, 0); - m_frame++; - BKE_image_path_ensure_ext_from_imtype(path, im_format->imtype); + unsigned int *pixels = m_rasterizer->MakeScreenshot(screenshot.x, screenshot.y, screenshot.width, screenshot.height); + if (!pixels) { + CM_Error("cannot allocate pixels array"); + return; + } /* Save the actual file in a different thread, so that the * game engine can keep running at full speed. */ ScreenshotTaskData *task = (ScreenshotTaskData *)MEM_mallocN(sizeof(ScreenshotTaskData), "screenshot-data"); - task->dumprect = dumprect; - task->dumpsx = dumpsx; - task->dumpsy = dumpsy; - task->path = path; - task->im_format = im_format; + task->dumprect = pixels; + task->dumpsx = screenshot.width; + task->dumpsy = screenshot.height; + task->im_format = screenshot.format; + + BLI_strncpy(task->path, screenshot.path.c_str(), FILE_MAX); + BLI_path_frame(task->path, m_frame, 0); + m_frame++; + BKE_image_path_ensure_ext_from_imtype(task->path, task->im_format->imtype); BLI_task_pool_push(m_taskpool, save_screenshot_thread_func, diff --git a/source/gameengine/Rasterizer/RAS_ICanvas.h b/source/gameengine/Rasterizer/RAS_ICanvas.h index 2c67f454df1e..7869892e8486 100644 --- a/source/gameengine/Rasterizer/RAS_ICanvas.h +++ b/source/gameengine/Rasterizer/RAS_ICanvas.h @@ -32,9 +32,7 @@ #ifndef __RAS_ICANVAS_H__ #define __RAS_ICANVAS_H__ -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif +#include "RAS_Rasterizer.h" // for RAS_Rasterizer::HdrType class RAS_Rect; struct TaskScheduler; @@ -47,35 +45,28 @@ struct ImageFormatData; class RAS_ICanvas { public: - enum BufferType { - COLOR_BUFFER=1, - DEPTH_BUFFER=2 - }; - enum RAS_MouseState { - MOUSE_INVISIBLE=1, + MOUSE_INVISIBLE = 1, MOUSE_WAIT, MOUSE_NORMAL }; - RAS_ICanvas(); - virtual ~RAS_ICanvas(); + enum SwapControl + { + VSYNC_OFF = 0, + VSYNC_ON, + VSYNC_ADAPTIVE, + SWAP_CONTROL_MAX + }; - virtual - void - Init( - ) = 0; + RAS_ICanvas(RAS_Rasterizer *rasty); + virtual ~RAS_ICanvas(); - virtual - void - BeginFrame( - )=0; + virtual void Init() = 0; - virtual - void - EndFrame( - )=0; + virtual void BeginFrame() = 0; + virtual void EndFrame() = 0; /** * Initializes the canvas for drawing. Drawing to the canvas is @@ -85,203 +76,126 @@ class RAS_ICanvas * \retval true Acquiring the canvas succeeded. * */ - - virtual - bool - BeginDraw( - )=0; + virtual void BeginDraw() = 0; /** * Unitializes the canvas for drawing. */ - - virtual - void - EndDraw( - )=0; - + virtual void EndDraw() = 0; /// probably needs some arguments for PS2 in future - virtual - void - SwapBuffers( - )=0; - - virtual - void - SetSwapInterval( - int interval - )=0; - - virtual - bool - GetSwapInterval( - int& intervalOut - )=0; - - virtual - void - ClearBuffer( - int type - )=0; - - virtual - void - ClearColor( - float r, - float g, - float b, - float a - )=0; - - virtual - int - GetWidth( - ) const = 0; - - virtual - int - GetHeight( - ) const = 0; - - virtual - int - GetMouseX(int x - )=0; - - virtual - int - GetMouseY(int y - )= 0; - - virtual - float - GetMouseNormalizedX(int x - )=0; - - virtual - float - GetMouseNormalizedY(int y - )= 0; - - virtual - const RAS_Rect & - GetDisplayArea( - ) const = 0; - - virtual - void - SetDisplayArea(RAS_Rect *rect - ) = 0; + virtual void SwapBuffers() = 0; + virtual void SetSwapControl(SwapControl control); + SwapControl GetSwapControl() const; + + void SetSamples(int samples); + int GetSamples() const; + + void SetHdrType(RAS_Rasterizer::HdrType type); + RAS_Rasterizer::HdrType GetHdrType() const; + + virtual int GetWidth() const = 0; + virtual int GetHeight() const = 0; + virtual int GetMaxX() const = 0; + virtual int GetMaxY() const = 0; + + /** Convert mouse coordinates from screen or client window to render area coordinates. + * \param x The input X coordinate. + * \param y The input Y coordinate. + * \param r_x The mouse render area X coordinate. + * \param r_y The mouse render area Y coordinate. + * \param screen Set to true when the input coordinates come from the screen and not the client window. + */ + virtual void ConvertMousePosition(int x, int y, int &r_x, int &r_y, bool screen) = 0; + + virtual float GetMouseNormalizedX(int x) = 0; + virtual float GetMouseNormalizedY(int y) = 0; /** * Used to get canvas area within blender. */ - virtual - RAS_Rect & - GetWindowArea( - ) = 0; + virtual RAS_Rect &GetWindowArea() = 0; /** * Set the visible view-port */ - - virtual - void - SetViewPort( - int x1, int y1, - int x2, int y2 - ) = 0; + virtual void SetViewPort(int x, int y, int width, int height) = 0; /** * Update the Canvas' viewport (used when the viewport changes without using SetViewPort() * eg: Shadow buffers and FBOs */ - - virtual - void - UpdateViewPort( - int x1, int y1, - int x2, int y2 - ) = 0; + virtual void UpdateViewPort(int x, int y, int width, int height) = 0; /** * Get the visible viewport */ - virtual - const int* - GetViewPort() = 0; - - virtual - void - SetMouseState( - RAS_MouseState mousestate - )=0; - - virtual - void - SetMousePosition( - int x, - int y - )=0; - - virtual - RAS_MouseState - GetMouseState() + virtual const int *GetViewPort() = 0; + + virtual void SetMouseState(RAS_MouseState mousestate) = 0; + virtual void SetMousePosition(int x, int y) = 0; + + virtual RAS_MouseState GetMouseState() { return m_mousestate; } - virtual - void - MakeScreenShot( - const char* filename - )=0; + virtual void MakeScreenShot(const std::string& filename) = 0; + /// Proceed the actual screenshot at the frame end. + void FlushScreenshots(); virtual void GetDisplayDimensions(int &width, int &height) = 0; - virtual - void - ResizeWindow( - int width, - int height - )=0; - - virtual - void - SetFullScreen( - bool enable - )=0; + virtual void ResizeWindow(int width, int height) = 0; - virtual - bool - GetFullScreen()=0; + /// Resize the canvas without resizing the window. + virtual void Resize(int width, int height) = 0; + virtual void SetFullScreen(bool enable) = 0; + virtual bool GetFullScreen() = 0; + RAS_Rasterizer *GetRasterizer() + { + return m_rasterizer; + } protected: + /// Swap interval value of each swap control mode. + static const int swapInterval[SWAP_CONTROL_MAX]; + + struct Screenshot + { + std::string path; + int x; + int y; + int width; + int height; + ImageFormatData *format; + }; + + std::vector m_screenshots; + + int m_samples; + RAS_Rasterizer::HdrType m_hdrType; + + SwapControl m_swapControl; RAS_MouseState m_mousestate; - int m_frame; /// frame number for screenshots. + /// frame number for screenshots. + int m_frame; TaskScheduler *m_taskscheduler; TaskPool *m_taskpool; + RAS_Rasterizer *m_rasterizer; + + /** Delay the screenshot to the frame end to use a valid buffer and avoid copy from an invalid buffer + * at the frame begin after the buffer swap. The screenshot are proceeded in \see FlushScreenshots. + */ + void AddScreenshot(const std::string& path, int x, int y, int width, int height, ImageFormatData *format); /** * Saves screenshot data to a file. The actual compression and disk I/O is performed in * a separate thread. - * - * @param filename name of the file, can contain "###" for sequential numbering. A copy of the string - * is made, so the pointer can be freed by the caller. - * @param dumpsx width in pixels. - * @param dumpsy height in pixels. - * @param dumprect pixel data; ownership is passed to this function, which also frees the data. - * @param im_format image format for the file; ownership is passed to this function, which also frees the data. */ - void save_screenshot(const char *filename, int dumpsx, int dumpsy, unsigned int *dumprect, - ImageFormatData * im_format); - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_ICanvas") -#endif + void SaveScreeshot(const Screenshot& screenshot); }; -#endif /* __RAS_ICANVAS_H__ */ +#endif // __RAS_ICANVAS_H__ diff --git a/source/gameengine/Rasterizer/RAS_ILightObject.h b/source/gameengine/Rasterizer/RAS_ILightObject.h index 2ff4ec7da015..d7ce092ef6da 100644 --- a/source/gameengine/Rasterizer/RAS_ILightObject.h +++ b/source/gameengine/Rasterizer/RAS_ILightObject.h @@ -32,13 +32,11 @@ #ifndef __RAS_LIGHTOBJECT_H__ #define __RAS_LIGHTOBJECT_H__ +#include "mathfu.h" + class RAS_ICanvas; class KX_Camera; -class KX_Scene; - -class MT_Transform; -class MT_Matrix4x4; struct Image; @@ -48,8 +46,10 @@ class RAS_ILightObject enum LightType { LIGHT_SPOT, LIGHT_SUN, - LIGHT_NORMAL + LIGHT_NORMAL, + LIGHT_HEMI }; + bool m_modified; int m_layer; void *m_scene; @@ -63,9 +63,9 @@ class RAS_ILightObject float m_shadowbias; float m_shadowbleedbias; short m_shadowmaptype; - float m_shadowcolor[3]; + mt::vec3 m_shadowcolor; - float m_color[3]; + mt::vec3 m_color; float m_att1; float m_att2; @@ -74,22 +74,27 @@ class RAS_ILightObject float m_spotblend; LightType m_type; - + bool m_nodiffuse; bool m_nospecular; - bool m_glsl; - virtual ~RAS_ILightObject() {} + bool m_staticShadow; + bool m_requestShadowUpdate; + + virtual ~RAS_ILightObject() = default; virtual RAS_ILightObject* Clone() = 0; virtual bool HasShadowBuffer() = 0; + virtual bool NeedShadowUpdate() = 0; virtual int GetShadowBindCode() = 0; - virtual MT_Matrix4x4 GetShadowMatrix() = 0; + virtual mt::mat4 GetShadowMatrix() = 0; + virtual mt::mat4 GetViewMat() = 0; + virtual mt::mat4 GetWinMat() = 0; virtual int GetShadowLayer() = 0; - virtual void BindShadowBuffer(RAS_ICanvas *canvas, KX_Camera *cam, MT_Transform& camtrans) = 0; + virtual void BindShadowBuffer(RAS_ICanvas *canvas, KX_Camera *cam, mt::mat3x4& camtrans) = 0; virtual void UnbindShadowBuffer() = 0; virtual Image *GetTextureImage(short texslot) = 0; - virtual void Update() = 0; + virtual void Update(const mt::mat3x4& trans, bool hide) = 0; }; #endif /* __RAS_LIGHTOBJECT_H__ */ diff --git a/source/gameengine/Rasterizer/RAS_IMaterial.cpp b/source/gameengine/Rasterizer/RAS_IMaterial.cpp new file mode 100644 index 000000000000..1d23793d7356 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_IMaterial.cpp @@ -0,0 +1,165 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Rasterizer/RAS_IMaterial.cpp + * \ingroup bgerast + */ + + +#include "RAS_IMaterial.h" + +RAS_IMaterial::RAS_IMaterial(const std::string& name) + :m_name(name), + m_drawingMode(0), + m_alphablend(0), + m_zoffset(0.0f), + m_rasMode(0), + m_flag(0), + m_passIndex(0) +{ + for (unsigned short i = 0; i < RAS_Texture::MaxUnits; ++i) { + m_textures[i] = nullptr; + } +} + +RAS_IMaterial::~RAS_IMaterial() +{ + for (unsigned short i = 0; i < RAS_Texture::MaxUnits; ++i) { + if (m_textures[i]) { + delete m_textures[i]; + } + } +} + +bool RAS_IMaterial::IsAlphaShadow() const +{ + return (m_rasMode & RAS_ALPHA_SHADOW); +} + +bool RAS_IMaterial::IsWire() const +{ + return (m_rasMode & RAS_WIRE); +} + +bool RAS_IMaterial::IsText() const +{ + return (m_rasMode & RAS_TEXT); +} + +bool RAS_IMaterial::IsCullFace() const +{ + return !(m_rasMode & (RAS_TWOSIDED | RAS_WIRE)); +} + +bool RAS_IMaterial::IsTwoSided() const +{ + return (m_rasMode & RAS_TWOSIDED); +} + +bool RAS_IMaterial::IsVisible() const +{ + return (m_rasMode & RAS_VISIBLE); +} + +bool RAS_IMaterial::IsCollider() const +{ + return (m_rasMode & RAS_COLLIDER); +} + +void RAS_IMaterial::GetRGBAColor(unsigned char *rgba) const +{ + *rgba++ = 0xFF; + *rgba++ = 0xFF; + *rgba++ = 0xFF; + *rgba++ = 0xFF; +} + +bool RAS_IMaterial::IsAlpha() const +{ + return (m_rasMode & (RAS_ALPHA | RAS_ZSORT)); +} + +bool RAS_IMaterial::IsAlphaDepth() const +{ + return (m_rasMode & RAS_DEPTH_ALPHA); +} + +bool RAS_IMaterial::IsZSort() const +{ + return (m_rasMode & RAS_ZSORT); +} + +int RAS_IMaterial::GetDrawingMode() const +{ + return m_drawingMode; +} + +int RAS_IMaterial::GetAlphaBlend() const +{ + return m_alphablend; +} + +float RAS_IMaterial::GetZOffset() const +{ + return m_zoffset; +} + +std::string RAS_IMaterial::GetName() +{ + return m_name; +} + +unsigned int RAS_IMaterial::GetFlag() const +{ + return m_flag; +} + +bool RAS_IMaterial::UsesLighting() const +{ + // Return false only if material is shadeless. + return (m_flag & RAS_MULTILIGHT); +} + +bool RAS_IMaterial::CastsShadows() const +{ + return (m_flag & RAS_CASTSHADOW) != 0; +} + +bool RAS_IMaterial::OnlyShadow() const +{ + return (m_flag & RAS_ONLYSHADOW) != 0; +} + +short RAS_IMaterial::GetPassIndex() const +{ + return m_passIndex; +} + +RAS_Texture *RAS_IMaterial::GetTexture(unsigned int index) +{ + return m_textures[index]; +} diff --git a/source/gameengine/Rasterizer/RAS_IMaterial.h b/source/gameengine/Rasterizer/RAS_IMaterial.h new file mode 100644 index 000000000000..b848e6d50625 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_IMaterial.h @@ -0,0 +1,156 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_IMaterial.h + * \ingroup bgerast + */ + +#ifndef __RAS_IPOLYGONMATERIAL_H__ +#define __RAS_IPOLYGONMATERIAL_H__ + +#include "RAS_Texture.h" +#include "RAS_Mesh.h" +#include "RAS_AttributeArray.h" +#include "RAS_InstancingBuffer.h" + +#include "CM_Update.h" + +#include +#include + +class RAS_Rasterizer; +class SCA_IScene; +struct Material; +struct Scene; +struct GameSettings; + +/** + * Polygon Material on which the material buckets are sorted + */ +class RAS_IMaterial : public CM_UpdateServer +{ +public: + enum Props + { + RAS_MULTILIGHT = (1 << 1), + RAS_CASTSHADOW = (1 << 4), + RAS_ONLYSHADOW = (1 << 5), + }; + + enum RasterizerModes + { + RAS_ZSORT = (1 << 0), + RAS_ALPHA = (1 << 1), + RAS_DEPTH_ALPHA = (1 << 2), + RAS_ALPHA_SHADOW = (1 << 3), + RAS_WIRE = (1 << 4), + RAS_TEXT = (1 << 5), + RAS_TWOSIDED = (1 << 6), + RAS_VISIBLE = (1 << 7), + RAS_COLLIDER = (1 << 8) + }; + + enum DrawingModes + { + RAS_NORMAL, + RAS_BILLBOARD, + RAS_HALO, + RAS_SHADOW + }; + + enum UpdateFlags + { + ATTRIBUTES_MODIFIED = (1 << 0), + SHADER_MODIFIED = (1 << 1) + }; + +protected: + std::string m_name; // also needed for collisionsensor + int m_drawingMode; + int m_alphablend; + float m_zoffset; + int m_rasMode; + unsigned int m_flag; + short m_passIndex; + + RAS_Texture *m_textures[RAS_Texture::MaxUnits]; + +public: + RAS_IMaterial(const std::string& name); + + virtual ~RAS_IMaterial(); + + /// Prepare the material data for rendering. + virtual void Prepare(RAS_Rasterizer *rasty) = 0; + virtual void Activate(RAS_Rasterizer *rasty) = 0; + virtual void Desactivate(RAS_Rasterizer *rasty) = 0; + virtual void ActivateInstancing(RAS_Rasterizer *rasty, RAS_InstancingBuffer *buffer) = 0; + virtual void ActivateMeshUser(RAS_MeshUser *meshUser, RAS_Rasterizer *rasty, const mt::mat3x4& camtrans) = 0; + + bool IsAlpha() const; + bool IsAlphaDepth() const; + bool IsZSort() const; + bool IsWire() const; + bool IsText() const; + bool IsCullFace() const; + bool IsTwoSided() const; + bool IsVisible() const; + bool IsCollider() const; + int GetDrawingMode() const; + int GetAlphaBlend() const; + float GetZOffset() const; + virtual std::string GetName(); + unsigned int GetFlag() const; + bool IsAlphaShadow() const; + bool CastsShadows() const; + bool OnlyShadow() const; + short GetPassIndex() const; + RAS_Texture *GetTexture(unsigned int index); + + virtual const std::string GetTextureName() const = 0; + virtual Material *GetBlenderMaterial() const = 0; + virtual Scene *GetBlenderScene() const = 0; + virtual SCA_IScene *GetScene() const = 0; + virtual bool UseInstancing() const = 0; + virtual void ReloadMaterial() = 0; + virtual void GetRGBAColor(unsigned char *rgba) const; + virtual bool UsesLighting() const; + + virtual void UpdateIPO(const mt::vec4 &rgba, const mt::vec3 &specrgb, float hard, float spec, float ref, + float emit, float ambient, float alpha, float specalpha) = 0; + + virtual const RAS_AttributeArray::AttribList GetAttribs(const RAS_Mesh::LayersInfo& layersInfo) const = 0; + /// Return attributes category used for instancing, this value tell what attributes must be updated. + virtual RAS_InstancingBuffer::Attrib GetInstancingAttribs() const = 0; + + /** + * \return the equivalent drawing mode for the material settings (equivalent to old TexFace tface->mode). + */ + int ConvertFaceMode(struct GameSettings *game) const; +}; + +#endif /* __RAS_IPOLYGONMATERIAL_H__ */ diff --git a/source/gameengine/Rasterizer/RAS_IOffScreen.h b/source/gameengine/Rasterizer/RAS_IOffScreen.h deleted file mode 100644 index d61a31504b8f..000000000000 --- a/source/gameengine/Rasterizer/RAS_IOffScreen.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2015, Blender Foundation - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): Blender Foundation. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file RAS_IOffScreen.h - * \ingroup bgerast - */ - -#ifndef __RAS_OFFSCREEN_H__ -#define __RAS_OFFSCREEN_H__ - -#include "EXP_Python.h" - -class RAS_ICanvas; - -class MT_Transform; - -struct Image; - -class RAS_IOffScreen -{ -public: - enum RAS_OFS_BIND_MODE { - RAS_OFS_BIND_RENDER = 0, - RAS_OFS_BIND_READ, - }; - enum RAS_OFS_RENDER_TARGET { - RAS_OFS_RENDER_BUFFER = 0, // use render buffer as render target - RAS_OFS_RENDER_TEXTURE, // use texture as render target - }; - - int m_width; - int m_height; - int m_samples; - int m_color; // if used, holds the texture object, 0 if not used - - virtual ~RAS_IOffScreen() {} - - virtual bool Create(int width, int height, int samples, RAS_OFS_RENDER_TARGET target) = 0; - virtual void Destroy() = 0; - virtual void Bind(RAS_OFS_BIND_MODE mode) = 0; - virtual void Blit() = 0; - virtual void Unbind() = 0; - virtual void MipMap() = 0; - - virtual int GetWidth() { return m_width; } - virtual int GetHeight() { return m_height; } - virtual int GetSamples() { return m_samples; } - virtual int GetColor() { return m_color; } -}; - -#ifdef WITH_PYTHON -typedef struct { - PyObject_HEAD - RAS_IOffScreen *ofs; -} PyRASOffScreen; - -extern PyTypeObject PyRASOffScreen_Type; -#endif - -#endif /* __RAS_OFFSCREEN_H__ */ diff --git a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp deleted file mode 100644 index 8ad4a9c8d424..000000000000 --- a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp +++ /dev/null @@ -1,295 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Rasterizer/RAS_IPolygonMaterial.cpp - * \ingroup bgerast - */ - - -#include "RAS_IPolygonMaterial.h" -#include "RAS_IRasterizer.h" - -#include "DNA_material_types.h" - -void RAS_IPolyMaterial::Initialize( - const STR_String& texname, - const STR_String& matname, - int materialindex, - int tile, - int tilexrep, - int tileyrep, - int alphablend, - bool alpha, - bool zsort, - bool light, - bool image, - struct GameSettings* game) -{ - m_texturename = texname; - m_materialname = matname; - m_materialindex = materialindex; - m_tile = tile; - m_tilexrep = tilexrep; - m_tileyrep = tileyrep; - m_alphablend = alphablend; - m_alpha = alpha; - m_zsort = zsort; - m_light = light; - m_polymatid = m_newpolymatid++; - m_flag = 0; - m_multimode = 0; - m_shininess = 35.0f; - m_specular.setValue(0.5f,0.5f,0.5f); - m_specularity = 1.0f; - m_diffuse.setValue(0.5f,0.5f,0.5f); - m_drawingmode = ConvertFaceMode(game, image); -} - -RAS_IPolyMaterial::RAS_IPolyMaterial() - : m_texturename("__Dummy_Texture_Name__"), - m_materialname("__Dummy_Material_Name__"), - m_tile(0), - m_tilexrep(0), - m_tileyrep(0), - m_drawingmode (0), - m_alphablend(0), - m_alpha(false), - m_zsort(false), - m_light(false), - m_materialindex(0), - m_polymatid(0), - m_flag(0), - m_multimode(0) -{ - m_shininess = 35.0f; - m_specular = MT_Vector3(0.5f,0.5f,0.5f); - m_specularity = 1.0f; - m_diffuse = MT_Vector3(0.5f,0.5f,0.5f); -} - -RAS_IPolyMaterial::RAS_IPolyMaterial(const STR_String& texname, - const STR_String& matname, - int materialindex, - int tile, - int tilexrep, - int tileyrep, - int alphablend, - bool alpha, - bool zsort) - : m_texturename(texname), - m_materialname(matname), - m_tile(tile), - m_tilexrep(tilexrep), - m_tileyrep(tileyrep), - m_alphablend(alphablend), - m_alpha(alpha), - m_zsort(zsort), - m_materialindex(materialindex), - m_polymatid(m_newpolymatid++), - m_flag(0), - m_multimode(0) -{ - m_shininess = 35.0f; - m_specular = MT_Vector3(0.5f,0.5f,0.5f); - m_specularity = 1.0f; - m_diffuse = MT_Vector3(0.5f,0.5f,0.5f); -} - - -bool RAS_IPolyMaterial::Equals(const RAS_IPolyMaterial& lhs) const -{ - if (m_flag &RAS_BLENDERMAT) - { - bool test = ( - this->m_multimode == lhs.m_multimode && - this->m_flag == lhs.m_flag && - this->m_drawingmode == lhs.m_drawingmode && - this->m_alphablend == lhs.m_alphablend && - this->m_texturename.hash() == lhs.m_texturename.hash() && - this->m_materialname.hash() == lhs.m_materialname.hash() - ); - - return test; - } - else - { - return ( - this->m_tile == lhs.m_tile && - this->m_tilexrep == lhs.m_tilexrep && - this->m_tileyrep == lhs.m_tileyrep && - this->m_alphablend == lhs.m_alphablend && - this->m_alpha == lhs.m_alpha && - this->m_zsort == lhs.m_zsort && - this->m_light == lhs.m_light && - this->m_drawingmode == lhs.m_drawingmode && - this->m_texturename.hash() == lhs.m_texturename.hash() && - this->m_materialname.hash() == lhs.m_materialname.hash() - ); - } -} - -int RAS_IPolyMaterial::ConvertFaceMode(struct GameSettings *game, bool image) const -{ - if (!game) return (image?GEMAT_TEX:0); - - int modefinal = 0; - - int orimode = game->face_orientation; - int alpha_blend = game->alpha_blend; - int flags = game->flag & (GEMAT_TEXT | GEMAT_BACKCULL); - - modefinal = orimode | alpha_blend | flags; - modefinal |= (image ? GEMAT_TEX : 0); - - return modefinal; -} - -void RAS_IPolyMaterial::GetMaterialRGBAColor(unsigned char *rgba) const -{ - *rgba++ = 0xFF; - *rgba++ = 0xFF; - *rgba++ = 0xFF; - *rgba++ = 0xFF; -} - -bool RAS_IPolyMaterial::Less(const RAS_IPolyMaterial& rhs) const -{ - if (Equals(rhs)) - return false; - - return m_polymatid < rhs.m_polymatid; -} - -bool RAS_IPolyMaterial::IsAlpha() const -{ - return m_alpha || m_zsort; -} - -bool RAS_IPolyMaterial::IsZSort() const -{ - return m_zsort; -} - -unsigned int RAS_IPolyMaterial::hash() const -{ - return m_texturename.hash(); -} - -int RAS_IPolyMaterial::GetDrawingMode() const -{ - return m_drawingmode; -} - -const STR_String& RAS_IPolyMaterial::GetMaterialName() const -{ - return m_materialname; -} - -dword RAS_IPolyMaterial::GetMaterialNameHash() const -{ - return m_materialname.hash(); -} - -const STR_String& RAS_IPolyMaterial::GetTextureName() const -{ - return m_texturename; -} - -int RAS_IPolyMaterial::GetMaterialIndex() const -{ - return m_materialindex; -} - -Material *RAS_IPolyMaterial::GetBlenderMaterial() const -{ - return NULL; -} - -Image *RAS_IPolyMaterial::GetBlenderImage() const -{ - return NULL; -} -MTexPoly *RAS_IPolyMaterial::GetMTexPoly() const -{ - return NULL; -} - -unsigned int *RAS_IPolyMaterial::GetMCol() const -{ - return NULL; -} - -Scene* RAS_IPolyMaterial::GetBlenderScene() const -{ - return NULL; -} - -void RAS_IPolyMaterial::ReleaseMaterial() -{ -} - -unsigned int RAS_IPolyMaterial::GetFlag() const -{ - return m_flag; -} - -bool RAS_IPolyMaterial::UsesLighting(RAS_IRasterizer *rasty) const -{ - bool dolights = false; - - if (m_flag & RAS_BLENDERMAT) { - dolights = (m_flag & RAS_MULTILIGHT) != 0; - } - else if (rasty->GetDrawingMode() < RAS_IRasterizer::KX_SOLID) { - /* pass */ - } - else if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW) { - /* pass */ - } - else { - dolights = m_light; - } - - return dolights; -} - -bool RAS_IPolyMaterial::CastsShadows() const -{ - return (m_flag & RAS_CASTSHADOW) != 0; -} - -bool RAS_IPolyMaterial::OnlyShadow() const -{ - return (m_flag & RAS_ONLYSHADOW) != 0; -} - -bool RAS_IPolyMaterial::UsesObjectColor() const -{ - return !(m_flag & RAS_BLENDERGLSL); -} - -unsigned int RAS_IPolyMaterial::m_newpolymatid = 0; diff --git a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h deleted file mode 100644 index 70d48fce48cd..000000000000 --- a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file RAS_IPolygonMaterial.h - * \ingroup bgerast - */ - -#ifndef __RAS_IPOLYGONMATERIAL_H__ -#define __RAS_IPOLYGONMATERIAL_H__ - -#include "STR_HashedString.h" - -#include "MT_Vector3.h" - -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -class RAS_IRasterizer; -struct MTexPoly; -struct Material; -struct Image; -struct Scene; -class SCA_IScene; -struct GameSettings; - -enum MaterialProps -{ - RAS_ZSORT =1, - RAS_TRANSPARENT =2, - RAS_TRIANGLE =4, - RAS_MULTITEX =8, - RAS_MULTILIGHT =16, - RAS_BLENDERMAT =32, - RAS_GLSHADER =64, - RAS_AUTOGEN =128, - RAS_NORMAL =256, - RAS_DEFMULTI =512, - RAS_BLENDERGLSL =1024, - RAS_CASTSHADOW =2048, - RAS_ONLYSHADOW =4096, -}; - -/** - * Polygon Material on which the material buckets are sorted - * - */ -class RAS_IPolyMaterial -{ - //todo: remove these variables from this interface/protocol class -protected: - STR_HashedString m_texturename; - STR_HashedString m_materialname; //also needed for touchsensor - int m_tile; - int m_tilexrep,m_tileyrep; - int m_drawingmode; - int m_alphablend; - bool m_alpha; - bool m_zsort; - bool m_light; - int m_materialindex; - - unsigned int m_polymatid; - static unsigned int m_newpolymatid; - - // will move... - unsigned int m_flag;//MaterialProps - int m_multimode; // sum of values -public: - MT_Vector3 m_diffuse; - float m_shininess; - MT_Vector3 m_specular; - float m_specularity; - - /** Used to store caching information for materials. */ - typedef void* TCachingInfo; - - // care! these are taken from blender polygonflags, see file DNA_mesh_types.h for #define TF_BILLBOARD etc. - enum MaterialFlags - { - BILLBOARD_SCREENALIGNED = 512, /* GEMAT_HALO */ - BILLBOARD_AXISALIGNED = 1024, /* GEMAT_BILLBOARD */ - SHADOW =2048 /* GEMAT_SHADOW */ - }; - - RAS_IPolyMaterial(); - RAS_IPolyMaterial(const STR_String& texname, - const STR_String& matname, - int materialindex, - int tile, - int tilexrep, - int tileyrep, - int transp, - bool alpha, - bool zsort); - void Initialize(const STR_String& texname, - const STR_String& matname, - int materialindex, - int tile, - int tilexrep, - int tileyrep, - int transp, - bool alpha, - bool zsort, - bool light, - bool image, - struct GameSettings* game); - - virtual ~RAS_IPolyMaterial() {} - - /** - * Returns the caching information for this material, - * This can be used to speed up the rasterizing process. - * \return The caching information. - */ - virtual TCachingInfo GetCachingInfo(void) const { return 0; } - - /** - * Activates the material in the rasterizer. - * On entry, the cachingInfo contains info about the last activated material. - * On exit, the cachingInfo should contain updated info about this material. - * \param rasty The rasterizer in which the material should be active. - * \param cachingInfo The information about the material used to speed up rasterizing. - */ - virtual bool Activate(RAS_IRasterizer* rasty, TCachingInfo& cachingInfo) const - { - return false; - } - virtual void ActivateMeshSlot(const class RAS_MeshSlot & ms, RAS_IRasterizer* rasty) const {} - - virtual bool Equals(const RAS_IPolyMaterial& lhs) const; - bool Less(const RAS_IPolyMaterial& rhs) const; - //int GetLightLayer() const; - bool IsAlpha() const; - bool IsZSort() const; - unsigned int hash() const; - int GetDrawingMode() const; - const STR_String& GetMaterialName() const; - dword GetMaterialNameHash() const; - const STR_String& GetTextureName() const; - unsigned int GetFlag() const; - int GetMaterialIndex() const; - - virtual Material* GetBlenderMaterial() const; - virtual Image* GetBlenderImage() const; - virtual MTexPoly* GetMTexPoly() const; - virtual unsigned int* GetMCol() const; - virtual Scene* GetBlenderScene() const; - virtual void ReleaseMaterial(); - virtual void GetMaterialRGBAColor(unsigned char *rgba) const; - virtual bool UsesLighting(RAS_IRasterizer *rasty) const; - virtual bool UsesObjectColor() const; - virtual bool CastsShadows() const; - virtual bool OnlyShadow() const; - - virtual void Replace_IScene(SCA_IScene *val) {} /* overridden by KX_BlenderMaterial */ - - /** - * \return the equivalent drawing mode for the material settings (equivalent to old TexFace tface->mode). - */ - int ConvertFaceMode(struct GameSettings *game, bool image) const; - - /* - * PreCalculate texture gen - */ - virtual void OnConstruction() {} - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_IPolyMaterial") -#endif -}; - -inline bool operator ==( const RAS_IPolyMaterial & rhs,const RAS_IPolyMaterial & lhs) -{ - return ( rhs.Equals(lhs)); -} - -inline bool operator < ( const RAS_IPolyMaterial & lhs, const RAS_IPolyMaterial & rhs) -{ - return lhs.Less(rhs); -} - -#endif /* __RAS_IPOLYGONMATERIAL_H__ */ diff --git a/source/gameengine/Rasterizer/RAS_IRasterizer.h b/source/gameengine/Rasterizer/RAS_IRasterizer.h deleted file mode 100644 index 783c216e3c50..000000000000 --- a/source/gameengine/Rasterizer/RAS_IRasterizer.h +++ /dev/null @@ -1,506 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file RAS_IRasterizer.h - * \ingroup bgerast - */ - -#ifndef __RAS_IRASTERIZER_H__ -#define __RAS_IRASTERIZER_H__ - -#ifdef _MSC_VER -# pragma warning (disable:4786) -#endif - -#include "STR_HashedString.h" - -#include "MT_CmMatrix4x4.h" -#include "MT_Matrix4x4.h" - -#include "RAS_TexVert.h" - -#include -using namespace std; - -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -class RAS_ICanvas; -class RAS_IPolyMaterial; -class RAS_MeshSlot; -class RAS_ILightObject; -class SCA_IScene; -class RAS_IOffScreen; -class RAS_ISync; - -typedef vector KX_IndexArray; -typedef vector KX_VertexArray; -typedef vector vecVertexArray; -typedef vector vecIndexArrays; - -/** - * 3D rendering device context interface. - */ -class RAS_IRasterizer -{ -public: - enum RAS_TEXT_RENDER_MODE { - RAS_TEXT_RENDER_NODEF = 0, - RAS_TEXT_NORMAL, - RAS_TEXT_PADDED, - RAS_TEXT_MAX, - }; - - RAS_IRasterizer(RAS_ICanvas* canv) {}; - virtual ~RAS_IRasterizer() {}; - - /** - * Drawing types - */ - enum DrawType { - KX_BOUNDINGBOX = 1, - KX_WIREFRAME, - KX_SOLID, - KX_SHADED, - KX_TEXTURED, - KX_SHADOW, - }; - - /** - * Drawing modes - */ - - enum DrawMode { - KX_MODE_LINES = 1, - KX_MODE_TRIANGLES, - KX_MODE_QUADS, - }; - - /** - * Valid SetDepthMask parameters - */ - enum DepthMask { - KX_DEPTHMASK_ENABLED = 1, - KX_DEPTHMASK_DISABLED, - }; - - /** - */ - enum { - RAS_RENDER_3DPOLYGON_TEXT = 64, /* GEMAT_TEXT */ - KX_BACKCULL = 16, /* GEMAT_BACKCULL */ - KX_TEX = 4096, /* GEMAT_TEX */ - KX_LINES = 32768, - }; - - /** - * Stereo mode types - */ - enum StereoMode { - RAS_STEREO_NOSTEREO = 1, - RAS_STEREO_QUADBUFFERED, - RAS_STEREO_ABOVEBELOW, - RAS_STEREO_INTERLACED, - RAS_STEREO_ANAGLYPH, - RAS_STEREO_SIDEBYSIDE, - RAS_STEREO_VINTERLACE, - RAS_STEREO_DOME, - RAS_STEREO_3DTVTOPBOTTOM, - - RAS_STEREO_MAXSTEREO - }; - - /** - * Texture gen modes. - */ - enum TexCoGen { - RAS_TEXCO_GEN, /* < GPU will generate texture coordinates */ - RAS_TEXCO_ORCO, /* < Vertex coordinates (object space) */ - RAS_TEXCO_GLOB, /* < Vertex coordinates (world space) */ - RAS_TEXCO_UV, /* < UV coordinates */ - RAS_TEXCO_OBJECT, /* < Use another object's position as coordinates */ - RAS_TEXCO_LAVECTOR, /* < Light vector as coordinates */ - RAS_TEXCO_VIEW, /* < View vector as coordinates */ - RAS_TEXCO_STICKY, /* < Sticky coordinates */ - RAS_TEXCO_WINDOW, /* < Window coordinates */ - RAS_TEXCO_NORM, /* < Normal coordinates */ - RAS_TEXTANGENT, /* < */ - RAS_TEXCO_VCOL, /* < Vertex Color */ - RAS_TEXCO_DISABLE, /* < Disable this texture unit (cached) */ - }; - - /** - * Render pass identifiers for stereo. - */ - enum StereoEye { - RAS_STEREO_LEFTEYE = 1, - RAS_STEREO_RIGHTEYE, - }; - - /** - * Mipmap options - */ - enum MipmapOption { - RAS_MIPMAP_NONE, - RAS_MIPMAP_NEAREST, - RAS_MIPMAP_LINEAR, - - RAS_MIPMAP_MAX, /* Should always be last */ - }; - - /** - * SetDepthMask enables or disables writing a fragment's depth value - * to the Z buffer. - */ - virtual void SetDepthMask(DepthMask depthmask) = 0; - - /** - * SetMaterial sets the material settings for subsequent primitives - * to be rendered with. - * The material will be cached. - */ - virtual bool SetMaterial(const RAS_IPolyMaterial &mat) = 0; - - /** - * Init initializes the renderer. - */ - virtual bool Init() = 0; - - /** - * Exit cleans up the renderer. - */ - virtual void Exit() = 0; - - /** - * BeginFrame is called at the start of each frame. - */ - virtual bool BeginFrame(double time) = 0; - - /** - * ClearColorBuffer clears the color buffer. - */ - virtual void ClearColorBuffer() = 0; - - /** - * ClearDepthBuffer clears the depth buffer. - */ - virtual void ClearDepthBuffer() = 0; - - /** - * ClearCachingInfo clears the currently cached material. - */ - virtual void ClearCachingInfo(void) = 0; - - /** - * EndFrame is called at the end of each frame. - */ - virtual void EndFrame() = 0; - - /** - * SetRenderArea sets the render area from the 2d canvas. - * Returns true if only of subset of the canvas is used. - */ - virtual void SetRenderArea() = 0; - - // Stereo Functions - /** - * SetStereoMode will set the stereo mode - */ - virtual void SetStereoMode(const StereoMode stereomode) = 0; - - /** - * Stereo can be used to query if the rasterizer is in stereo mode. - * \return true if stereo mode is enabled. - */ - virtual bool Stereo() = 0; - virtual StereoMode GetStereoMode() = 0; - virtual bool InterlacedStereo() = 0; - - /** - * Sets which eye buffer subsequent primitives will be rendered to. - */ - virtual void SetEye(const StereoEye eye) = 0; - virtual StereoEye GetEye() = 0; - - /** - * Sets the distance between eyes for stereo mode. - */ - virtual void SetEyeSeparation(const float eyeseparation) = 0; - virtual float GetEyeSeparation() = 0; - - /** - * Sets the focal length for stereo mode. - */ - virtual void SetFocalLength(const float focallength) = 0; - virtual float GetFocalLength() = 0; - - /** - * Create an offscreen render buffer that can be used as target for render. - * For the time being, it is only used in VideoTexture for custom render. - */ - virtual RAS_IOffScreen *CreateOffScreen(int width, int height, int samples, int target) = 0; - - /** - * Create a sync object - * For use with offscreen render - */ - virtual RAS_ISync *CreateSync(int type) = 0; - - /** - * SwapBuffers swaps the back buffer with the front buffer. - */ - virtual void SwapBuffers() = 0; - - // Drawing Functions - /** - * IndexPrimitives: Renders primitives from mesh slot. - */ - virtual void IndexPrimitives(class RAS_MeshSlot &ms) = 0; - - /** - * IndexPrimitives_3DText will render text into the polygons. - */ - virtual void IndexPrimitives_3DText(class RAS_MeshSlot &ms, class RAS_IPolyMaterial *polymat) = 0; - - virtual void SetProjectionMatrix(MT_CmMatrix4x4 &mat) = 0; - - /* This one should become our final version, methinks. */ - /** - * Set the projection matrix for the rasterizer. This projects - * from camera coordinates to window coordinates. - * \param mat The projection matrix. - */ - virtual void SetProjectionMatrix(const MT_Matrix4x4 &mat) = 0; - - /** - * Sets the modelview matrix. - */ - virtual void SetViewMatrix(const MT_Matrix4x4 &mat, const MT_Matrix3x3 &ori, - const MT_Point3 &pos, const MT_Vector3 &scale, bool perspective) = 0; - - /** - */ - virtual const MT_Point3& GetCameraPosition() = 0; - virtual bool GetCameraOrtho() = 0; - - /** - * Fog - */ - virtual void SetFog(short type, float start, float dist, float intensity, float color[3]) = 0; - virtual void DisplayFog() = 0; - virtual void EnableFog(bool enable) = 0; - - virtual void SetBackColor(float color[3]) = 0; - - /** - * \param drawingmode = KX_BOUNDINGBOX, KX_WIREFRAME, KX_SOLID, KX_SHADED or KX_TEXTURED. - */ - virtual void SetDrawingMode(int drawingmode) = 0; - - /** - * \return the current drawing mode: KX_BOUNDINGBOX, KX_WIREFRAME, KX_SOLID, KX_SHADED or KX_TEXTURED. - */ - virtual int GetDrawingMode() = 0; - - /** - * Sets face culling - */ - virtual void SetCullFace(bool enable) = 0; - - /** - * Sets wireframe mode. - */ - virtual void SetLines(bool enable) = 0; - - /** - */ - virtual double GetTime() = 0; - - /** - * Generates a projection matrix from the specified frustum. - * \param left the left clipping plane - * \param right the right clipping plane - * \param bottom the bottom clipping plane - * \param top the top clipping plane - * \param frustnear the near clipping plane - * \param frustfar the far clipping plane - * \return a 4x4 matrix representing the projection transform. - */ - virtual MT_Matrix4x4 GetFrustumMatrix( - float left, float right, float bottom, float top, - float frustnear, float frustfar, - float focallength = 0.0f, bool perspective = true) = 0; - - /** - * Generates a orthographic projection matrix from the specified frustum. - * \param left the left clipping plane - * \param right the right clipping plane - * \param bottom the bottom clipping plane - * \param top the top clipping plane - * \param frustnear the near clipping plane - * \param frustfar the far clipping plane - * \return a 4x4 matrix representing the projection transform. - */ - virtual MT_Matrix4x4 GetOrthoMatrix( - float left, float right, float bottom, float top, - float frustnear, float frustfar) = 0; - - /** - * Sets the specular color component of the lighting equation. - */ - virtual void SetSpecularity(float specX, float specY, float specZ, float specval) = 0; - - /** - * Sets the specular exponent component of the lighting equation. - */ - virtual void SetShinyness(float shiny) = 0; - - /** - * Sets the diffuse color component of the lighting equation. - */ - virtual void SetDiffuse(float difX,float difY, float difZ, float diffuse) = 0; - - /** - * Sets the emissive color component of the lighting equation. - */ - virtual void SetEmissive(float eX, float eY, float eZ, float e) = 0; - - virtual void SetAmbientColor(float color[3]) = 0; - virtual void SetAmbient(float factor) = 0; - - /** - * Sets a polygon offset. z depth will be: z1 = mult*z0 + add - */ - virtual void SetPolygonOffset(float mult, float add) = 0; - - virtual void DrawDebugLine(SCA_IScene *scene, const MT_Vector3 &from, const MT_Vector3 &to, const MT_Vector3& color) = 0; - virtual void DrawDebugCircle(SCA_IScene *scene, const MT_Vector3 ¢er, const MT_Scalar radius, - const MT_Vector3 &color, const MT_Vector3 &normal, int nsector) = 0; - virtual void FlushDebugShapes(SCA_IScene *scene) = 0; - - virtual void SetTexCoordNum(int num) = 0; - virtual void SetAttribNum(int num) = 0; - virtual void SetTexCoord(TexCoGen coords, int unit) = 0; - virtual void SetAttrib(TexCoGen coords, int unit, int layer = 0) = 0; - - virtual const MT_Matrix4x4 &GetViewMatrix() const = 0; - virtual const MT_Matrix4x4 &GetViewInvMatrix() const = 0; - - virtual bool QueryLists() { return false; } - virtual bool QueryArrays() { return false; } - - virtual void EnableMotionBlur(float motionblurvalue) = 0; - virtual void DisableMotionBlur() = 0; - - virtual float GetMotionBlurValue() = 0; - virtual int GetMotionBlurState() = 0; - virtual void SetMotionBlurState(int newstate) = 0; - - virtual void SetAlphaBlend(int alphablend) = 0; - virtual void SetFrontFace(bool ccw) = 0; - - virtual void SetAnisotropicFiltering(short level) = 0; - virtual short GetAnisotropicFiltering() = 0; - - virtual void SetMipmapping(MipmapOption val) = 0; - virtual MipmapOption GetMipmapping() = 0; - - virtual void SetUsingOverrideShader(bool val) = 0; - virtual bool GetUsingOverrideShader() = 0; - - /** - * Render Tools - */ - virtual void applyTransform(float *oglmatrix, int drawingmode) = 0; - - /** - * Renders 2D boxes. - * \param xco Position on the screen (origin in lower left corner). - * \param yco Position on the screen (origin in lower left corner). - * \param width Width of the canvas to draw to. - * \param height Height of the canvas to draw to. - * \param percentage Percentage of bar. - */ - virtual void RenderBox2D(int xco, int yco, int width, int height, float percentage) = 0; - - /** - * Renders 3D text string using BFL. - * \param fontid The id of the font. - * \param text The string to render. - * \param size The size of the text. - * \param dpi The resolution of the text. - * \param color The color of the object. - * \param mat The Matrix of the text object. - * \param aspect A scaling factor to compensate for the size. - */ - virtual void RenderText3D( - int fontid, const char *text, int size, int dpi, - const float color[4], const float mat[16], float aspect) = 0; - - /** - * Renders 2D text string. - * \param mode The type of text - * \param text The string to render. - * \param xco Position on the screen (origin in lower left corner). - * \param yco Position on the screen (origin in lower left corner). - * \param width Width of the canvas to draw to. - * \param height Height of the canvas to draw to. - */ - virtual void RenderText2D( - RAS_TEXT_RENDER_MODE mode, const char *text, - int xco, int yco, int width, int height) = 0; - - virtual void ProcessLighting(bool uselights, const MT_Transform &trans) = 0; - - virtual void PushMatrix() = 0; - - virtual void PopMatrix() = 0; - - virtual RAS_ILightObject *CreateLight() = 0; - - virtual void AddLight(RAS_ILightObject *lightobject) = 0; - - virtual void RemoveLight(RAS_ILightObject *lightobject) = 0; - - virtual void MotionBlur() = 0; - - virtual void SetClientObject(void *obj) = 0; - - virtual void SetAuxilaryClientInfo(void *inf) = 0; - - /** - * Prints information about what the hardware supports. - */ - virtual void PrintHardwareInfo() = 0; - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_IRasterizer") -#endif -}; - -#endif /* __RAS_IRASTERIZER_H__ */ diff --git a/source/gameengine/Rasterizer/RAS_InstancingBuffer.cpp b/source/gameengine/Rasterizer/RAS_InstancingBuffer.cpp new file mode 100644 index 000000000000..428bf1ffe330 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_InstancingBuffer.cpp @@ -0,0 +1,158 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is: all of this file. + * + * Contributor(s): Porteries Tristan. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Rasterizer/RAS_InstancingBuffer.cpp + * \ingroup bgerast + */ + +#include "RAS_InstancingBuffer.h" +#include "RAS_Rasterizer.h" +#include "RAS_MeshUser.h" + +extern "C" { +// To avoid include BKE_DerivedMesh.h. +typedef int (*DMSetMaterial)(int mat_nr, void *attribs); + #include "GPU_buffers.h" +} + +RAS_InstancingBuffer::RAS_InstancingBuffer(Attrib attribs) + :m_vbo(nullptr), + m_attribs(attribs) +{ +} + +RAS_InstancingBuffer::~RAS_InstancingBuffer() +{ + if (m_vbo) { + GPU_buffer_free(m_vbo); + } +} + +void RAS_InstancingBuffer::Realloc(unsigned int size) +{ + // Offset of next memory block. + uintptr_t offset = 0; + + // Compute memory block offsets. + + m_matrixOffset = offset; + offset += MATRIX_MEMORY_SIZE * size; + + m_positionOffset = offset; + offset += POSITION_MEMORY_SIZE * size; + + if (m_attribs & COLOR_ATTRIB) { + m_colorOffset = offset; + offset += COLOR_MEMORY_SIZE * size; + } + if (m_attribs & LAYER_ATTRIB) { + m_layerOffset = offset; + offset += LAYER_MEMORY_SIZE * size; + } + if (m_attribs & INFO_ATTRIB) { + m_infoOffset = offset; + offset += INFO_MEMORY_SIZE * size; + } + + if (m_vbo) { + GPU_buffer_free(m_vbo); + } + // Use next offset as memory size. + m_vbo = GPU_buffer_alloc(offset); +} + +void RAS_InstancingBuffer::Bind() +{ + GPU_buffer_bind(m_vbo, GPU_BINDING_ARRAY); +} + +void RAS_InstancingBuffer::Unbind() +{ + GPU_buffer_unbind(m_vbo, GPU_BINDING_ARRAY); +} + +void RAS_InstancingBuffer::Update(RAS_Rasterizer *rasty, int drawingmode, short matPassIndex, const RAS_MeshSlotList &meshSlots) +{ + const intptr_t buffer = (intptr_t)GPU_buffer_lock_stream(m_vbo, GPU_BINDING_ARRAY); + const unsigned int count = meshSlots.size(); + + // Pack matrix and position. + for (unsigned int i = 0; i < count; ++i) { + RAS_MeshSlot *ms = meshSlots[i]; + float mat[16]; + rasty->SetClientObject(ms->m_meshUser->GetClientObject()); + rasty->GetTransform(ms->m_meshUser->GetMatrix(), drawingmode, mat); + + float (&matrixData)[9] = *(float (*)[9])(buffer + m_matrixOffset + MATRIX_MEMORY_SIZE * i); + matrixData[0] = mat[0]; + matrixData[1] = mat[4]; + matrixData[2] = mat[8]; + matrixData[3] = mat[1]; + matrixData[4] = mat[5]; + matrixData[5] = mat[9]; + matrixData[6] = mat[2]; + matrixData[7] = mat[6]; + matrixData[8] = mat[10]; + + float (&positionData)[3] = *(float (*)[3])(buffer + m_positionOffset + POSITION_MEMORY_SIZE * i); + positionData[0] = mat[12]; + positionData[1] = mat[13]; + positionData[2] = mat[14]; + } + + // Pack color. + if (m_attribs & COLOR_ATTRIB) { + for (unsigned int i = 0; i < count; ++i) { + RAS_MeshSlot *ms = meshSlots[i]; + + float (&colorData)[4] = *(float (*)[4])(buffer + m_colorOffset + COLOR_MEMORY_SIZE * i); + ms->m_meshUser->GetColor().Pack(colorData); + } + } + + // Pack layer. + if (m_attribs & LAYER_ATTRIB) { + for (unsigned int i = 0; i < count; ++i) { + RAS_MeshSlot *ms = meshSlots[i]; + + unsigned int &layerData = *(unsigned int *)(buffer + m_layerOffset + LAYER_MEMORY_SIZE * i); + layerData = ms->m_meshUser->GetLayer(); + } + } + + // Pack info. + if (m_attribs & INFO_ATTRIB) { + for (unsigned int i = 0; i < count; ++i) { + RAS_MeshSlot *ms = meshSlots[i]; + RAS_MeshUser *meshUser = ms->m_meshUser; + + float (&infoData)[3] = *(float (*)[3])(buffer + m_infoOffset + INFO_MEMORY_SIZE * i); + infoData[0] = float(meshUser->GetPassIndex()); + infoData[1] = float(matPassIndex); + infoData[2] = meshUser->GetRandom(); + } + } + + GPU_buffer_unlock(m_vbo, GPU_BINDING_ARRAY); +} diff --git a/source/gameengine/Rasterizer/RAS_InstancingBuffer.h b/source/gameengine/Rasterizer/RAS_InstancingBuffer.h new file mode 100644 index 000000000000..aec08bcf3550 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_InstancingBuffer.h @@ -0,0 +1,124 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is: all of this file. + * + * Contributor(s): Porteries Tristan. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_InstancingBuffer.h + * \ingroup bgerast + */ + +#ifndef __RAS_INSTANCING_BUFFER_H__ +#define __RAS_INSTANCING_BUFFER_H__ + +#include "RAS_MeshSlot.h" + +class RAS_Rasterizer; + +struct GPUBuffer; + +class RAS_InstancingBuffer +{ +public: + /// Item to pack. + enum Attrib + { + /// Pack matrix and positions, needed for all shaders. + DEFAULT_ATTRIBS = 0, + /// Pack object color. + COLOR_ATTRIB = (1 << 0), + /// Pack object layer. + LAYER_ATTRIB = (1 << 1), + /// Pack object info. + INFO_ATTRIB = (1 << 2) + }; + +private: + /// Memory size of packed items. + enum MemorySize + { + MATRIX_MEMORY_SIZE = sizeof(float[9]), + POSITION_MEMORY_SIZE = sizeof(float[3]), + COLOR_MEMORY_SIZE = sizeof(float[4]), + LAYER_MEMORY_SIZE = sizeof(int), + INFO_MEMORY_SIZE = sizeof(float[3]) + }; + + /// The OpenGL VBO. + GPUBuffer *m_vbo; + /// The matrix offset in the VBO. + intptr_t m_matrixOffset; + /// The position offset in the VBO. + intptr_t m_positionOffset; + /// The color offset in the VBO. + intptr_t m_colorOffset; + /// The layer offset in the VBO. + intptr_t m_layerOffset; + /// The info offset in the VBO. + intptr_t m_infoOffset; + + /// Attributes to update. + Attrib m_attribs; + +public: + RAS_InstancingBuffer(Attrib attribs); + ~RAS_InstancingBuffer(); + + /// Realloc the VBO. + void Realloc(unsigned int size); + /// Bind the VBO before work on it. + void Bind(); + /// Unbind the VBO after work on it. + void Unbind(); + + /** Allocate the VBO and fill it with a InstancingObject per mesh slots. + * \param rasty Rasterizer used to compute the mesh slot matrix, useful for billboard material. + * \param drawingmode The material drawing mode used to detect a billboard/halo/shadow material. + * \param meshSlots The list of all non-culled and visible mesh slots (= game object). + */ + void Update(RAS_Rasterizer *rasty, int drawingmode, short matPassIndex, const RAS_MeshSlotList &meshSlots); + + inline intptr_t GetMatrixOffset() const + { + return m_matrixOffset; + } + inline intptr_t GetPositionOffset() const + { + return m_positionOffset; + } + inline intptr_t GetColorOffset() const + { + return m_colorOffset; + } + + inline intptr_t GetLayerOffset() const + { + return m_layerOffset; + } + + inline intptr_t GetInfoOffset() const + { + return m_infoOffset; + } +}; + +#endif // __RAS_INSTANCING_BUFFER_H__ + diff --git a/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp b/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp index 10542c985ff8..4f32b5dbb135 100644 --- a/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp +++ b/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp @@ -29,650 +29,148 @@ * \ingroup bgerast */ - #include "RAS_MaterialBucket.h" +#include "RAS_IMaterial.h" +#include "RAS_Rasterizer.h" +#include "RAS_Mesh.h" +#include "RAS_MeshUser.h" +#include "RAS_Deformer.h" + +#include "CM_List.h" #ifdef _MSC_VER # pragma warning (disable:4786) #endif #ifdef WIN32 -#include +# include #endif // WIN32 -#include "RAS_IPolygonMaterial.h" -#include "RAS_TexVert.h" -#include "RAS_IRasterizer.h" -#include "RAS_MeshObject.h" -#include "RAS_Deformer.h" // __NLA - -/* mesh slot */ - -RAS_MeshSlot::RAS_MeshSlot() : SG_QList() -{ - m_clientObj = NULL; - m_pDeformer = NULL; - m_OpenGLMatrix = NULL; - m_mesh = NULL; - m_bucket = NULL; - m_bVisible = false; - m_bCulled = true; - m_bObjectColor = false; - m_RGBAcolor = MT_Vector4(0.0f, 0.0f, 0.0f, 0.0f); - m_DisplayList = NULL; - m_bDisplayList = true; - m_joinSlot = NULL; - m_pDerivedMesh = NULL; -} - -RAS_MeshSlot::~RAS_MeshSlot() +RAS_MaterialBucket::RAS_MaterialBucket(RAS_IMaterial *mat) + :m_material(mat), + m_downwardNode(this, &m_nodeData, &RAS_MaterialBucket::BindNode, &RAS_MaterialBucket::UnbindNode), + m_upwardNode(this, &m_nodeData, &RAS_MaterialBucket::BindNode, &RAS_MaterialBucket::UnbindNode) { - RAS_DisplayArrayList::iterator it; - -#ifdef USE_SPLIT - Split(true); - - while (m_joinedSlots.size()) - m_joinedSlots.front()->Split(true); -#endif - - for (it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) { - (*it)->m_users--; - if ((*it)->m_users == 0) - delete *it; - } - - if (m_DisplayList) { - m_DisplayList->Release(); - m_DisplayList = NULL; - } + m_nodeData.m_material = m_material; + m_nodeData.m_drawingMode = m_material->GetDrawingMode(); + m_nodeData.m_cullFace = m_material->IsCullFace(); + m_nodeData.m_zsort = m_material->IsZSort(); + m_nodeData.m_text = m_material->IsText(); + m_nodeData.m_zoffset = m_material->GetZOffset(); } -RAS_MeshSlot::RAS_MeshSlot(const RAS_MeshSlot& slot) : SG_QList() +RAS_MaterialBucket::~RAS_MaterialBucket() { - RAS_DisplayArrayList::iterator it; - - m_clientObj = NULL; - m_pDeformer = NULL; - m_pDerivedMesh = NULL; - m_OpenGLMatrix = NULL; - m_mesh = slot.m_mesh; - m_bucket = slot.m_bucket; - m_bVisible = slot.m_bVisible; - m_bCulled = slot.m_bCulled; - m_bObjectColor = slot.m_bObjectColor; - m_RGBAcolor = slot.m_RGBAcolor; - m_DisplayList = NULL; - m_bDisplayList = slot.m_bDisplayList; - m_joinSlot = NULL; - m_currentArray = slot.m_currentArray; - m_displayArrays = slot.m_displayArrays; - m_joinedSlots = slot.m_joinedSlots; - - m_startarray = slot.m_startarray; - m_startvertex = slot.m_startvertex; - m_startindex = slot.m_startindex; - m_endarray = slot.m_endarray; - m_endvertex = slot.m_endvertex; - m_endindex = slot.m_endindex; - - for (it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) { - // don't copy display arrays for now because it breaks python - // access to vertices, but we'll need a solution if we want to - // join display arrays for reducing draw calls. - //*it = new RAS_DisplayArray(**it); - //(*it)->m_users = 1; - - (*it)->m_users++; - } } -void RAS_MeshSlot::init(RAS_MaterialBucket *bucket, int numverts) +RAS_IMaterial *RAS_MaterialBucket::GetMaterial() const { - m_bucket = bucket; - - SetDisplayArray(numverts); - - m_startarray = 0; - m_startvertex = 0; - m_startindex = 0; - m_endarray = 0; - m_endvertex = 0; - m_endindex = 0; + return m_material; } -void RAS_MeshSlot::begin(RAS_MeshSlot::iterator& it) +bool RAS_MaterialBucket::IsAlpha() const { - int startvertex, endvertex; - int startindex, endindex; - - it.array = m_displayArrays.empty() ? NULL : m_displayArrays[m_startarray]; - - if (it.array == NULL || it.array->m_index.size() == 0 || it.array->m_vertex.size() == 0) { - it.array = NULL; - it.vertex = NULL; - it.index = NULL; - it.startvertex = 0; - it.endvertex = 0; - it.totindex = 0; - } - else { - startvertex = m_startvertex; - endvertex = (m_startarray == m_endarray)? m_endvertex: it.array->m_vertex.size(); - startindex = m_startindex; - endindex = (m_startarray == m_endarray)? m_endindex: it.array->m_index.size(); - - it.vertex = &it.array->m_vertex[0]; - it.index = &it.array->m_index[startindex]; - it.startvertex = startvertex; - it.endvertex = endvertex; - it.totindex = endindex-startindex; - it.arraynum = m_startarray; - } + return (m_material->IsAlpha()); } -void RAS_MeshSlot::next(RAS_MeshSlot::iterator& it) +bool RAS_MaterialBucket::IsZSort() const { - int startvertex, endvertex; - int startindex, endindex; - - if (it.arraynum == (size_t)m_endarray) { - it.array = NULL; - it.vertex = NULL; - it.index = NULL; - it.startvertex = 0; - it.endvertex = 0; - it.totindex = 0; - } - else { - it.arraynum++; - it.array = m_displayArrays[it.arraynum]; - - startindex = 0; - endindex = (it.arraynum == (size_t)m_endarray)? m_endindex: it.array->m_index.size(); - startvertex = 0; - endvertex = (it.arraynum == (size_t)m_endarray)? m_endvertex: it.array->m_vertex.size(); - - it.vertex = &it.array->m_vertex[0]; - it.index = &it.array->m_index[startindex]; - it.startvertex = startvertex; - it.endvertex = endvertex; - it.totindex = endindex-startindex; - } + return (m_material->IsZSort()); } -bool RAS_MeshSlot::end(RAS_MeshSlot::iterator& it) +bool RAS_MaterialBucket::IsWire() const { - return (it.array == NULL); + return (m_material->IsWire()); } -RAS_DisplayArray *RAS_MeshSlot::CurrentDisplayArray() +bool RAS_MaterialBucket::UseInstancing() const { - return m_currentArray; + return (m_material->UseInstancing()); } -void RAS_MeshSlot::SetDisplayArray(int numverts) +void RAS_MaterialBucket::RemoveActiveMeshSlots() { - RAS_DisplayArrayList::iterator it; - RAS_DisplayArray *darray = NULL; - - for (it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) { - darray = *it; - - if (darray->m_type == numverts) { - if (darray->m_index.size()+numverts >= RAS_DisplayArray::BUCKET_MAX_INDEX) - darray = NULL; - else if (darray->m_vertex.size()+numverts >= RAS_DisplayArray::BUCKET_MAX_VERTEX) - darray = NULL; - else - break; - } - else - darray = NULL; + for (RAS_DisplayArrayBucket *arrayBucket : m_displayArrayBucketList) { + arrayBucket->RemoveActiveMeshSlots(); } - - if (!darray) { - darray = new RAS_DisplayArray(); - darray->m_users = 1; - - if (numverts == 2) darray->m_type = RAS_DisplayArray::LINE; - else if (numverts == 3) darray->m_type = RAS_DisplayArray::TRIANGLE; - else darray->m_type = RAS_DisplayArray::QUAD; - - m_displayArrays.push_back(darray); - - if (numverts == 2) - darray->m_type = RAS_DisplayArray::LINE; - else if (numverts == 3) - darray->m_type = RAS_DisplayArray::TRIANGLE; - else if (numverts == 4) - darray->m_type = RAS_DisplayArray::QUAD; - - m_endarray = m_displayArrays.size()-1; - m_endvertex = 0; - m_endindex = 0; - } - - m_currentArray = darray; -} - -void RAS_MeshSlot::AddPolygon(int numverts) -{ - SetDisplayArray(numverts); } -int RAS_MeshSlot::AddVertex(const RAS_TexVert& tv) +void RAS_MaterialBucket::ActivateMaterial(RAS_Rasterizer *rasty) { - RAS_DisplayArray *darray; - int offset; - - darray = m_currentArray; - darray->m_vertex.push_back(tv); - offset = darray->m_vertex.size()-1; - - if (darray == m_displayArrays[m_endarray]) - m_endvertex++; - - return offset; + m_material->Activate(rasty); } -void RAS_MeshSlot::AddPolygonVertex(int offset) +void RAS_MaterialBucket::DesactivateMaterial(RAS_Rasterizer *rasty) { - RAS_DisplayArray *darray; - - darray = m_currentArray; - darray->m_index.push_back(offset); - - if (darray == m_displayArrays[m_endarray]) - m_endindex++; + m_material->Desactivate(rasty); } -void RAS_MeshSlot::UpdateDisplayArraysOffset() +void RAS_MaterialBucket::GenerateTree(RAS_ManagerDownwardNode& downwardRoot, RAS_ManagerUpwardNode& upwardRoot, + RAS_UpwardTreeLeafs& upwardLeafs, RAS_Rasterizer::DrawType drawingMode, bool sort) { - unsigned int offset = 0; - for (unsigned short i = 0; i < m_displayArrays.size(); ++i) { - RAS_DisplayArray *darray = m_displayArrays[i]; - darray->m_offset = offset; - offset += darray->m_vertex.size(); + if (m_displayArrayBucketList.empty()) { + return; } -} -void RAS_MeshSlot::SetDeformer(RAS_Deformer* deformer) -{ - if (deformer && m_pDeformer != deformer) { - RAS_DisplayArrayList::iterator it; - if (deformer->ShareVertexArray()) { - // this deformer uses the base vertex array, first release the current ones - for (it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) { - (*it)->m_users--; - if ((*it)->m_users == 0) - delete *it; - } - m_displayArrays.clear(); - // then hook to the base ones - RAS_MeshMaterial *mmat = m_mesh->GetMeshMaterial(m_bucket->GetPolyMaterial()); - if (mmat && mmat->m_baseslot) { - m_displayArrays = mmat->m_baseslot->m_displayArrays; - for (it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) { - (*it)->m_users++; - } - } - } - else { - // no sharing - // we create local copy of RAS_DisplayArray when we have a deformer: - // this way we can avoid conflict between the vertex cache of duplicates - for (it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) { - if (deformer->UseVertexArray()) { - // the deformer makes use of vertex array, make sure we have our local copy - if ((*it)->m_users > 1) { - // only need to copy if there are other users - // note that this is the usual case as vertex arrays are held by the material base slot - RAS_DisplayArray *newarray = new RAS_DisplayArray(*(*it)); - newarray->m_users = 1; - (*it)->m_users--; - *it = newarray; - } - } else { - // the deformer is not using vertex array (Modifier), release them - (*it)->m_users--; - if ((*it)->m_users == 0) - delete *it; - } - } - if (!deformer->UseVertexArray()) { - m_displayArrays.clear(); - m_startarray = 0; - m_startvertex = 0; - m_startindex = 0; - m_endarray = 0; - m_endvertex = 0; - m_endindex = 0; - } - } + const bool instancing = UseInstancing(); + for (RAS_DisplayArrayBucket *displayArrayBucket : m_displayArrayBucketList) { + displayArrayBucket->GenerateTree(m_downwardNode, m_upwardNode, upwardLeafs, drawingMode, sort, instancing); } - m_pDeformer = deformer; -} -bool RAS_MeshSlot::Equals(RAS_MeshSlot *target) -{ - if (!m_OpenGLMatrix || !target->m_OpenGLMatrix) - return false; - if (m_pDeformer || target->m_pDeformer) - return false; - if (m_bVisible != target->m_bVisible) - return false; - if (m_bObjectColor != target->m_bObjectColor) - return false; - if (m_bObjectColor && !(m_RGBAcolor == target->m_RGBAcolor)) - return false; - - return true; -} - -bool RAS_MeshSlot::Join(RAS_MeshSlot *target, MT_Scalar distance) -{ - RAS_DisplayArrayList::iterator it; - iterator mit; - size_t i; - - // verify if we can join - if (m_joinSlot || (m_joinedSlots.empty() == false) || target->m_joinSlot) - return false; - - if (!Equals(target)) - return false; - - MT_Vector3 co(&m_OpenGLMatrix[12]); - MT_Vector3 targetco(&target->m_OpenGLMatrix[12]); - - if ((co - targetco).length() > distance) - return false; - - MT_Matrix4x4 mat(m_OpenGLMatrix); - MT_Matrix4x4 targetmat(target->m_OpenGLMatrix); - targetmat.invert(); + downwardRoot.AddChild(&m_downwardNode); - MT_Matrix4x4 transform = targetmat*mat; - - // m_mesh, clientobj - m_joinSlot = target; - m_joinInvTransform = transform; - m_joinInvTransform.invert(); - target->m_joinedSlots.push_back(this); - - MT_Matrix4x4 ntransform = m_joinInvTransform.transposed(); - ntransform[0][3] = ntransform[1][3] = ntransform[2][3] = 0.0f; - - for (begin(mit); !end(mit); next(mit)) - for (i=mit.startvertex; im_displayArrays.reserve(target->m_displayArrays.size() + m_displayArrays.size()); - - for (it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) { - target->m_displayArrays.push_back(*it); - target->m_endarray++; - target->m_endvertex = target->m_displayArrays.back()->m_vertex.size(); - target->m_endindex = target->m_displayArrays.back()->m_index.size(); + if (sort) { + m_upwardNode.SetParent(&upwardRoot); } - - if (m_DisplayList) { - m_DisplayList->Release(); - m_DisplayList = NULL; - } - if (target->m_DisplayList) { - target->m_DisplayList->Release(); - target->m_DisplayList = NULL; - } - - return true; -#if 0 - return false; -#endif } -bool RAS_MeshSlot::Split(bool force) +void RAS_MaterialBucket::BindNode(const RAS_MaterialNodeTuple& tuple) { - list::iterator jit; - RAS_MeshSlot *target = m_joinSlot; - RAS_DisplayArrayList::iterator it, jt; - iterator mit; - size_t i, found0 = 0, found1 = 0; - - if (target && (force || !Equals(target))) { - m_joinSlot = NULL; - - for (jit=target->m_joinedSlots.begin(); jit!=target->m_joinedSlots.end(); jit++) { - if (*jit == this) { - target->m_joinedSlots.erase(jit); - found0 = 1; - break; - } - } - - if (!found0) - abort(); - - for (it=m_displayArrays.begin(); it!=m_displayArrays.end(); it++) { - found1 = 0; - for (jt=target->m_displayArrays.begin(); jt!=target->m_displayArrays.end(); jt++) { - if (*jt == *it) { - target->m_displayArrays.erase(jt); - target->m_endarray--; - found1 = 1; - break; - } - } - - if (!found1) - abort(); - } - - if (target->m_displayArrays.empty() == false) { - target->m_endvertex = target->m_displayArrays.back()->m_vertex.size(); - target->m_endindex = target->m_displayArrays.back()->m_index.size(); - } - else { - target->m_endvertex = 0; - target->m_endindex = 0; - } - - MT_Matrix4x4 ntransform = m_joinInvTransform.inverse().transposed(); - ntransform[0][3] = ntransform[1][3] = ntransform[2][3] = 0.0f; - - for (begin(mit); !end(mit); next(mit)) - for (i=mit.startvertex; im_DisplayList) { - target->m_DisplayList->Release(); - target->m_DisplayList = NULL; - } + RAS_ManagerNodeData *managerData = tuple.m_managerData; + RAS_Rasterizer *rasty = managerData->m_rasty; + rasty->SetCullFace(m_nodeData.m_cullFace); + rasty->SetPolygonOffset(managerData->m_drawingMode, -m_nodeData.m_zoffset, 0.0f); - return true; + if (!managerData->m_shaderOverride) { + ActivateMaterial(managerData->m_rasty); } - - return false; } - -#ifdef USE_SPLIT -bool RAS_MeshSlot::IsCulled() +void RAS_MaterialBucket::UnbindNode(const RAS_MaterialNodeTuple& tuple) { - if (m_joinSlot) - return true; - if (!m_bCulled) - return false; - list::iterator it; - for (it=m_joinedSlots.begin(); it!=m_joinedSlots.end(); it++) - if (!(*it)->m_bCulled) - return false; - return true; -} -#endif - -/* material bucket sorting */ - -struct RAS_MaterialBucket::less -{ - bool operator()(const RAS_MaterialBucket* x, const RAS_MaterialBucket* y) const - { - return *x->GetPolyMaterial() < *y->GetPolyMaterial(); + RAS_ManagerNodeData *managerData = tuple.m_managerData; + if (!managerData->m_shaderOverride) { + DesactivateMaterial(managerData->m_rasty); } -}; - -/* material bucket */ - -RAS_MaterialBucket::RAS_MaterialBucket(RAS_IPolyMaterial* mat) -{ - m_material = mat; } -RAS_MaterialBucket::~RAS_MaterialBucket() -{ -} - -RAS_IPolyMaterial* RAS_MaterialBucket::GetPolyMaterial() const -{ - return m_material; -} - -bool RAS_MaterialBucket::IsAlpha() const -{ - return (m_material->IsAlpha()); -} - -bool RAS_MaterialBucket::IsZSort() const +void RAS_MaterialBucket::AddDisplayArrayBucket(RAS_DisplayArrayBucket *bucket) { - return (m_material->IsZSort()); + m_displayArrayBucketList.push_back(bucket); } -RAS_MeshSlot* RAS_MaterialBucket::AddMesh(int numverts) +void RAS_MaterialBucket::RemoveDisplayArrayBucket(RAS_DisplayArrayBucket *bucket) { - RAS_MeshSlot *ms; - - m_meshSlots.push_back(RAS_MeshSlot()); - - ms = &m_meshSlots.back(); - ms->init(this, numverts); - - return ms; + CM_ListRemoveIfFound(m_displayArrayBucketList, bucket); } -RAS_MeshSlot* RAS_MaterialBucket::CopyMesh(RAS_MeshSlot *ms) +RAS_DisplayArrayBucketList& RAS_MaterialBucket::GetDisplayArrayBucketList() { - m_meshSlots.push_back(RAS_MeshSlot(*ms)); - - return &m_meshSlots.back(); + return m_displayArrayBucketList; } -void RAS_MaterialBucket::RemoveMesh(RAS_MeshSlot* ms) +void RAS_MaterialBucket::MoveDisplayArrayBucket(RAS_MeshMaterial *meshmat, RAS_MaterialBucket *bucket) { - list::iterator it; - - for (it=m_meshSlots.begin(); it!=m_meshSlots.end(); it++) { - if (&*it == ms) { - m_meshSlots.erase(it); - return; + for (RAS_DisplayArrayBucketList::iterator dit = m_displayArrayBucketList.begin(); dit != m_displayArrayBucketList.end(); ) { + // In case of deformers, multiple display array bucket can use the same mesh and material. + RAS_DisplayArrayBucket *displayArrayBucket = *dit; + if (displayArrayBucket->GetMeshMaterial() != meshmat) { + ++dit; + continue; } - } -} - -list::iterator RAS_MaterialBucket::msBegin() -{ - return m_meshSlots.begin(); -} - -list::iterator RAS_MaterialBucket::msEnd() -{ - return m_meshSlots.end(); -} - -bool RAS_MaterialBucket::ActivateMaterial(const MT_Transform& cameratrans, RAS_IRasterizer* rasty) -{ - bool uselights; - - if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW && !m_material->CastsShadows()) - return false; - - if (rasty->GetDrawingMode() != RAS_IRasterizer::KX_SHADOW && m_material->OnlyShadow()) - return false; - - if (!rasty->SetMaterial(*m_material)) - return false; - - uselights= m_material->UsesLighting(rasty); - rasty->ProcessLighting(uselights, cameratrans); - return true; -} - -void RAS_MaterialBucket::RenderMeshSlot(const MT_Transform& cameratrans, RAS_IRasterizer* rasty, RAS_MeshSlot &ms) -{ - m_material->ActivateMeshSlot(ms, rasty); - - if (ms.m_pDeformer) - { - if (ms.m_pDeformer->Apply(m_material)) - ms.m_mesh->SetMeshModified(true); - // KX_ReInstanceShapeFromMesh(ms.m_mesh); // Recompute the physics mesh. (Can't call KX_* from RAS_) - } - - if (IsZSort() && rasty->GetDrawingMode() >= RAS_IRasterizer::KX_SOLID) - ms.m_mesh->SortPolygons(ms, cameratrans*MT_Transform(ms.m_OpenGLMatrix)); - - rasty->PushMatrix(); - if (!ms.m_pDeformer || !ms.m_pDeformer->SkipVertexTransform()) - { - rasty->applyTransform(ms.m_OpenGLMatrix,m_material->GetDrawingMode()); + displayArrayBucket->ChangeMaterialBucket(bucket); + bucket->AddDisplayArrayBucket(displayArrayBucket); + dit = m_displayArrayBucketList.erase(dit); } - - if (rasty->QueryLists()) - if (ms.m_DisplayList) - ms.m_DisplayList->SetModified(ms.m_mesh->MeshModified()); - - // verify if we can use display list, not for deformed object, and - // also don't create a new display list when drawing shadow buffers, - // then it won't have texture coordinates for actual drawing. also - // for zsort we can't make a display list, since the polygon order - // changes all the time. - if (ms.m_pDeformer && ms.m_pDeformer->IsDynamic()) - ms.m_bDisplayList = false; - else if (!ms.m_DisplayList && rasty->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW) - ms.m_bDisplayList = false; - else if (IsZSort()) - ms.m_bDisplayList = false; - else if (m_material->UsesObjectColor() && ms.m_bObjectColor) - ms.m_bDisplayList = false; - else - ms.m_bDisplayList = true; - - if (m_material->GetDrawingMode() & RAS_IRasterizer::RAS_RENDER_3DPOLYGON_TEXT) { - // for text drawing using faces - rasty->IndexPrimitives_3DText(ms, m_material); - } - else { - rasty->IndexPrimitives(ms); - } - - rasty->PopMatrix(); -} - -void RAS_MaterialBucket::Optimize(MT_Scalar distance) -{ - /* TODO: still have to check before this works correct: - * - lightlayer, frontface, text, billboard - * - make it work with physics */ - -#if 0 - list::iterator it; - list::iterator jt; - - // greed joining on all following buckets - for (it=m_meshSlots.begin(); it!=m_meshSlots.end(); it++) - for (jt=it, jt++; jt!=m_meshSlots.end(); jt++) - jt->Join(&*it, distance); -#endif } diff --git a/source/gameengine/Rasterizer/RAS_MaterialBucket.h b/source/gameengine/Rasterizer/RAS_MaterialBucket.h index 8ea80d883cf1..5509fd8a5220 100644 --- a/source/gameengine/Rasterizer/RAS_MaterialBucket.h +++ b/source/gameengine/Rasterizer/RAS_MaterialBucket.h @@ -29,185 +29,13 @@ * \ingroup bgerast */ -#ifndef __RAS_MATERIALBUCKET_H__ -#define __RAS_MATERIALBUCKET_H__ +#ifndef __RAS_MATERIAL_BUCKET_H__ +#define __RAS_MATERIAL_BUCKET_H__ -#include "RAS_TexVert.h" -#include "CTR_Map.h" -#include "SG_QList.h" +#include "RAS_DisplayArrayBucket.h" -#include "MT_Transform.h" -#include "MT_Matrix4x4.h" - -#include -#include -#include - -class RAS_MaterialBucket; -struct DerivedMesh; -class CTR_HashedPtr; -class RAS_Deformer; -class RAS_IPolyMaterial; -class RAS_IRasterizer; -class RAS_MeshObject; - -using namespace std; - -/* Display List Slot */ - -class KX_ListSlot -{ -protected: - int m_refcount; -public: - KX_ListSlot() { m_refcount = 1; } - virtual ~KX_ListSlot() {} - virtual int Release() { - if (--m_refcount > 0) - return m_refcount; - delete this; - return 0; - } - virtual KX_ListSlot* AddRef() { - m_refcount++; - return this; - } - virtual void SetModified(bool mod)=0; -}; - -/* An array with data used for OpenGL drawing */ - -class RAS_DisplayArray -{ -public: - /** The offset relation to the previous RAS_DisplayArray. - * For the user vertex are one big list but in C++ source - * it's two different lists if we use quads and triangles. - * So to fix that we add an offset. - * This value is set in UpdateDisplayArraysOffset(). - */ - unsigned int m_offset; - vector m_vertex; - vector m_index; - /* LINE currently isn't used */ - enum { LINE = 2, TRIANGLE = 3, QUAD = 4 } m_type; - //RAS_MeshSlot *m_origSlot; - - /* Number of RAS_MeshSlot using this array */ - int m_users; - - enum { BUCKET_MAX_INDEX = 65535 }; - enum { BUCKET_MAX_VERTEX = 65535 }; -}; - -/* Entry of a RAS_MeshObject into RAS_MaterialBucket */ -typedef std::vector RAS_DisplayArrayList; - -// The QList is used to link the mesh slots to the object -// The DList is used to link the visible mesh slots to the material bucket -class RAS_MeshSlot : public SG_QList -{ - friend class RAS_ListRasterizer; -private: - // indices into display arrays - int m_startarray; - int m_endarray; - int m_startindex; - int m_endindex; - int m_startvertex; - int m_endvertex; - RAS_DisplayArrayList m_displayArrays; - - // for construction only - RAS_DisplayArray* m_currentArray; - -public: - // for rendering - RAS_MaterialBucket* m_bucket; - RAS_MeshObject* m_mesh; - void* m_clientObj; - RAS_Deformer* m_pDeformer; - DerivedMesh* m_pDerivedMesh; - float* m_OpenGLMatrix; - // visibility - bool m_bVisible; - bool m_bCulled; - // object color - bool m_bObjectColor; - MT_Vector4 m_RGBAcolor; - // display lists - KX_ListSlot* m_DisplayList; - bool m_bDisplayList; - // joined mesh slots - RAS_MeshSlot* m_joinSlot; - MT_Matrix4x4 m_joinInvTransform; - list m_joinedSlots; - - RAS_MeshSlot(); - RAS_MeshSlot(const RAS_MeshSlot& slot); - virtual ~RAS_MeshSlot(); - - void init(RAS_MaterialBucket *bucket, int numverts); - - struct iterator { - RAS_DisplayArray *array; - RAS_TexVert *vertex; - unsigned short *index; - size_t startvertex; - size_t endvertex; - size_t totindex; - size_t arraynum; - }; - - void begin(iterator& it); - void next(iterator& it); - bool end(iterator& it); - - /* used during construction */ - void SetDisplayArray(int numverts); - RAS_DisplayArray *CurrentDisplayArray(); - void SetDeformer(RAS_Deformer* deformer); - - void AddPolygon(int numverts); - int AddVertex(const RAS_TexVert& tv); - void AddPolygonVertex(int offset); - - /// Update offset of each display array - void UpdateDisplayArraysOffset(); - - /* optimization */ - bool Split(bool force=false); - bool Join(RAS_MeshSlot *target, MT_Scalar distance); - bool Equals(RAS_MeshSlot *target); -#ifdef USE_SPLIT - bool IsCulled(); -#else - bool IsCulled() { return m_bCulled; } -#endif - void SetCulled(bool culled) { m_bCulled = culled; } - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_MeshSlot") -#endif -}; - -/* Used by RAS_MeshObject, to point to it's slots in a bucket */ - -class RAS_MeshMaterial -{ -public: - RAS_MeshSlot *m_baseslot; - class RAS_MaterialBucket *m_bucket; - - /* the KX_GameObject is used as a key here */ - CTR_Map m_slots; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_MeshMaterial") -#endif -}; +class RAS_IMaterial; +class RAS_Rasterizer; /* Contains a list of display arrays with the same material, * and a mesh slot for each mesh that uses display arrays in @@ -216,52 +44,42 @@ class RAS_MeshMaterial class RAS_MaterialBucket { public: - RAS_MaterialBucket(RAS_IPolyMaterial* mat); + RAS_MaterialBucket(RAS_IMaterial *mat); virtual ~RAS_MaterialBucket(); - /* Bucket Sorting */ - struct less; - typedef set Set; + // Material Properties + RAS_IMaterial *GetMaterial() const; + bool IsAlpha() const; + bool IsZSort() const; + bool IsWire() const; + bool UseInstancing() const; - /* Material Properties */ - RAS_IPolyMaterial* GetPolyMaterial() const; - bool IsAlpha() const; - bool IsZSort() const; + // Rendering + void ActivateMaterial(RAS_Rasterizer *rasty); + void DesactivateMaterial(RAS_Rasterizer *rasty); - /* Rendering */ - bool ActivateMaterial(const MT_Transform& cameratrans, RAS_IRasterizer* rasty); - void RenderMeshSlot(const MT_Transform& cameratrans, RAS_IRasterizer* rasty, RAS_MeshSlot &ms); + // Render nodes. + void GenerateTree(RAS_ManagerDownwardNode& downwardRoot, RAS_ManagerUpwardNode& upwardRoot, + RAS_UpwardTreeLeafs& upwardLeafs, RAS_Rasterizer::DrawType drawingMode, bool sort); + void BindNode(const RAS_MaterialNodeTuple& tuple); + void UnbindNode(const RAS_MaterialNodeTuple& tuple); - /* Mesh Slot Access */ - list::iterator msBegin(); - list::iterator msEnd(); + void RemoveActiveMeshSlots(); - class RAS_MeshSlot* AddMesh(int numverts); - class RAS_MeshSlot* CopyMesh(class RAS_MeshSlot *ms); - void RemoveMesh(class RAS_MeshSlot* ms); - void Optimize(MT_Scalar distance); - void ActivateMesh(RAS_MeshSlot* slot) - { - m_activeMeshSlotsHead.AddBack(slot); - } - SG_DList& GetActiveMeshSlots() - { - return m_activeMeshSlotsHead; - } - RAS_MeshSlot* GetNextActiveMeshSlot() - { - return (RAS_MeshSlot*)m_activeMeshSlotsHead.Remove(); - } + void AddDisplayArrayBucket(RAS_DisplayArrayBucket *bucket); + void RemoveDisplayArrayBucket(RAS_DisplayArrayBucket *bucket); -private: - list m_meshSlots; // all the mesh slots - RAS_IPolyMaterial* m_material; - SG_DList m_activeMeshSlotsHead; // only those which must be rendered + RAS_DisplayArrayBucketList& GetDisplayArrayBucketList(); + void MoveDisplayArrayBucket(RAS_MeshMaterial *meshmat, RAS_MaterialBucket *bucket); + +private: + RAS_IMaterial *m_material; + RAS_DisplayArrayBucketList m_displayArrayBucketList; -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_MaterialBucket") -#endif + RAS_MaterialNodeData m_nodeData; + RAS_MaterialDownwardNode m_downwardNode; + RAS_MaterialUpwardNode m_upwardNode; }; -#endif /* __RAS_MATERIAL_BUCKET */ +#endif // __RAS_MATERIAL_BUCKET_H__ diff --git a/source/gameengine/Rasterizer/RAS_Mesh.cpp b/source/gameengine/Rasterizer/RAS_Mesh.cpp new file mode 100644 index 000000000000..a1651dee75a1 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_Mesh.cpp @@ -0,0 +1,307 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Rasterizer/RAS_Mesh.cpp + * \ingroup bgerast + */ + +#include "DNA_mesh_types.h" + +#include "RAS_Mesh.h" +#include "RAS_MeshUser.h" +#include "RAS_BoundingBoxManager.h" +#include "RAS_IMaterial.h" +#include "RAS_BucketManager.h" +#include "RAS_DisplayArray.h" +#include "RAS_Deformer.h" + +#include "SCA_IScene.h" + +#include "CM_Message.h" + +RAS_Mesh::RAS_Mesh(Mesh *mesh, const LayersInfo& layersInfo) + :m_name(mesh->id.name + 2), + m_layersInfo(layersInfo), + m_boundingBox(nullptr), + m_mesh(mesh) +{ +} + +RAS_Mesh::RAS_Mesh(const std::string& name, const LayersInfo& layersInfo) + :m_name(name), + m_layersInfo(layersInfo), + m_boundingBox(nullptr), + m_mesh(nullptr) +{ +} + +RAS_Mesh::RAS_Mesh(const RAS_Mesh& other) + :m_name(other.m_name), + m_layersInfo(other.m_layersInfo), + m_boundingBox(nullptr), + m_mesh(other.m_mesh) +{ + for (RAS_MeshMaterial *meshmat : other.m_materials) { + RAS_MeshMaterial *newmeshmat = new RAS_MeshMaterial(*meshmat, this); + m_materials.push_back(newmeshmat); + } +} + +RAS_Mesh::~RAS_Mesh() +{ + for (RAS_MeshMaterial *meshmat : m_materials) { + delete meshmat; + } + m_materials.clear(); +} + +const RAS_MeshMaterialList& RAS_Mesh::GetMeshMaterialList() const +{ + return m_materials; +} + +unsigned short RAS_Mesh::GetNumMaterials() const +{ + return m_materials.size(); +} + +std::string RAS_Mesh::GetMaterialName(unsigned int matid) const +{ + RAS_MeshMaterial *mmat = GetMeshMaterial(matid); + + if (mmat) { + return mmat->GetBucket()->GetMaterial()->GetName(); + } + + return ""; +} + +RAS_MeshMaterial *RAS_Mesh::GetMeshMaterial(unsigned int matid) const +{ + if (m_materials.size() > matid) { + return m_materials[matid]; + } + + return nullptr; +} + +RAS_MeshMaterial *RAS_Mesh::GetMeshMaterialBlenderIndex(unsigned int index) const +{ + for (RAS_MeshMaterial *meshmat : m_materials) { + if (meshmat->GetIndex() == index) { + return meshmat; + } + } + + return nullptr; +} + +RAS_MeshMaterial *RAS_Mesh::FindMaterialName(const std::string& name) const +{ + for (RAS_MeshMaterial *meshmat : m_materials) { + // Check without the MA prefix. + if (name == std::string(meshmat->GetBucket()->GetMaterial()->GetName(), 2)) { + return meshmat; + } + } + + return nullptr; +} + +unsigned int RAS_Mesh::GetNumPolygons() const +{ + return m_numPolygons; +} + +RAS_Mesh::PolygonInfo RAS_Mesh::GetPolygon(unsigned int index) const +{ + // Convert triangle index to triangle vertex index. + index *= 3; + + for (const PolygonRangeInfo& range : m_polygonRanges) { + if (index >= range.startIndex && index < range.endIndex) { + + // Convert to relative index. + index -= range.startIndex; + + RAS_DisplayArray *array = range.array; + PolygonInfo polyInfo{ + array, + {array->GetTriangleIndex(index), + array->GetTriangleIndex(index + 1), + array->GetTriangleIndex(index + 2)}, + range.flags, range.matId + }; + + return polyInfo; + } + } + + BLI_assert(false); + + return PolygonInfo(); +} + +const std::string& RAS_Mesh::GetName() const +{ + return m_name; +} + +std::string RAS_Mesh::GetTextureName(unsigned int matid) const +{ + RAS_MeshMaterial *mmat = GetMeshMaterial(matid); + + if (mmat) { + return mmat->GetBucket()->GetMaterial()->GetTextureName(); + } + + return ""; +} + +RAS_MeshMaterial *RAS_Mesh::AddMaterial(RAS_MaterialBucket *bucket, unsigned int index, const RAS_DisplayArray::Format& format) +{ + RAS_MeshMaterial *meshmat = GetMeshMaterialBlenderIndex(index); + + // None found, create a new one. + if (!meshmat) { + meshmat = new RAS_MeshMaterial(this, bucket, index, format); + m_materials.push_back(meshmat); + } + + return meshmat; +} + +RAS_MeshMaterial *RAS_Mesh::AddMaterial(RAS_MaterialBucket *bucket, unsigned int index, RAS_DisplayArray *array) +{ + RAS_MeshMaterial *meshmat = GetMeshMaterialBlenderIndex(index); + + // None found, create a new one. + if (!meshmat) { + meshmat = new RAS_MeshMaterial(this, bucket, index, array); + m_materials.push_back(meshmat); + } + + return meshmat; +} + +RAS_DisplayArray *RAS_Mesh::GetDisplayArray(unsigned int matid) const +{ + RAS_MeshMaterial *mmat = GetMeshMaterial(matid); + + if (!mmat) { + return nullptr; + } + + RAS_DisplayArray *array = mmat->GetDisplayArray(); + + return array; +} + +RAS_BoundingBox *RAS_Mesh::GetBoundingBox() const +{ + return m_boundingBox; +} + +RAS_MeshUser *RAS_Mesh::AddMeshUser(void *clientobj, RAS_Deformer *deformer) +{ + RAS_BoundingBox *boundingBox = (deformer) ? deformer->GetBoundingBox() : m_boundingBox; + RAS_MeshUser *meshUser = new RAS_MeshUser(clientobj, boundingBox, deformer); + + for (unsigned short i = 0, nummat = m_materials.size(); i < nummat; ++i) { + RAS_DisplayArrayBucket *arrayBucket = (deformer) ? + deformer->GetDisplayArrayBucket(i) : m_materials[i]->GetDisplayArrayBucket(); + meshUser->NewMeshSlot(arrayBucket); + } + return meshUser; +} + +void RAS_Mesh::EndConversion(RAS_BoundingBoxManager *boundingBoxManager) +{ + RAS_DisplayArrayList arrayList; + + // Construct a list of all the display arrays used by this mesh. + for (RAS_MeshMaterial *meshmat : m_materials) { + RAS_DisplayArray *array = meshmat->GetDisplayArray(); + + const std::string materialname = meshmat->GetBucket()->GetMaterial()->GetName(); + if (array->GetVertexCount() == 0) { + CM_Warning("mesh \"" << m_name << "\" has no vertices for material \"" << materialname + << "\". It introduces performance decrease for empty render."); + } + else { + // Generate bounding box only for non-empty display arrays. + arrayList.push_back(array); + } + + if (array->GetPrimitiveIndexCount() == 0) { + CM_Warning("mesh \"" << m_name << "\" has no primitives for material \"" << materialname + << "\". It introduces performance decrease for empty render."); + } + } + + if (arrayList.empty()) { + // Use a dummy bounding box if there's no valid display arrays. + m_boundingBox = boundingBoxManager->CreateBoundingBox(); + } + else { + // Construct the bounding box of this mesh without deformers. + m_boundingBox = boundingBoxManager->CreateMeshBoundingBox(arrayList); + } + m_boundingBox->Update(true); + + // Construct polygon range info. + unsigned int startIndex = 0; + for (unsigned short i = 0, size = m_materials.size(); i < size; ++i) { + RAS_MeshMaterial *meshmat = m_materials[i]; + RAS_DisplayArray *array = meshmat->GetDisplayArray(); + const unsigned indexCount = array->GetTriangleIndexCount(); + if (indexCount == 0) { + continue; + } + + // Compute absolute array end index. + const unsigned int endIndex = startIndex + indexCount - 1; + + RAS_IMaterial *mat = meshmat->GetBucket()->GetMaterial(); + PolygonInfo::Flags flags = + ((mat->IsVisible()) ? PolygonInfo::VISIBLE : PolygonInfo::NONE | + (mat->IsCollider()) ? PolygonInfo::COLLIDER : PolygonInfo::NONE | + (mat->IsTwoSided()) ? PolygonInfo::TWOSIDE : PolygonInfo::NONE); + + m_polygonRanges.push_back({array, startIndex, endIndex, flags, i}); + + // Update absolute start array index for the next array. + startIndex += indexCount; + } + + m_numPolygons = startIndex / 3; +} + +const RAS_Mesh::LayersInfo& RAS_Mesh::GetLayersInfo() const +{ + return m_layersInfo; +} diff --git a/source/gameengine/Rasterizer/RAS_Mesh.h b/source/gameengine/Rasterizer/RAS_Mesh.h new file mode 100644 index 000000000000..9fd1f21297d1 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_Mesh.h @@ -0,0 +1,187 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_Mesh.h + * \ingroup bgerast + */ + +#ifndef __RAS_MESH_H__ +#define __RAS_MESH_H__ + +#ifdef _MSC_VER +/* disable the STL warnings ("debug information length > 255") */ +# pragma warning (disable:4786) +#endif + +#include +#include +#include + +#include "RAS_MeshMaterial.h" + +class RAS_MaterialBucket; +class RAS_MeshUser; +class RAS_Deformer; +class RAS_BoundingBox; +class RAS_BoundingBoxManager; +struct Mesh; + +/* RAS_Mesh is a mesh used for rendering. It stores polygons, + * but the actual vertices and index arrays are stored in material + * buckets, referenced by the list of RAS_MeshMaterials. */ + +class RAS_Mesh +{ +public: + /** Additionals data stored in mesh layers. These datas can be the colors layer or the + * UV map layers. They are used to find attribute's layers index by looking for similar + * attribute's names in shader and names of the mesh layers here. + */ + struct Layer { + /// The index of the color or uv layer in the vertices. + unsigned short index; + /// The name of the color or uv layer used to find corresponding material attributes. + std::string name; + }; + + typedef std::vector LayerList; + + struct LayersInfo { + /// UV layers info. + LayerList uvLayers; + /// Color layers info. + LayerList colorLayers; + /// The active color layer index as default. + unsigned short activeColor; + /// The active uv layer index as default. + unsigned short activeUv; + }; + + /** Polygon info generate when getting a polygon through + * RAS_Mesh::GetPolygon. */ + struct PolygonInfo { + enum Flags { + NONE = 0, + VISIBLE = (1 << 0), + COLLIDER = (1 << 1), + TWOSIDE = (1 << 2) + }; + + /// Display array owning the polygon, used to get vertices. + RAS_DisplayArray *array; + /// Polygon vertices indices in the display array. + unsigned int indices[3]; + /// Polygon flags depending on material using this display array. + Flags flags; + /// Material index owning the display array of this polygon. + unsigned short matId; + }; + +protected: + /** Polygon info per range depending of display array stored to generate + * the individual polygon info. */ + struct PolygonRangeInfo { + /// Display array owning polygons for this index range. + RAS_DisplayArray *array; + /// Start absolute vertex index of the range. + unsigned int startIndex; + /// End absolute vertex index of the range. + unsigned int endIndex; + /// Polygon flags depending on material using this display array. + PolygonInfo::Flags flags; + /// Material index owning the display array of this polygon range. + unsigned short matId; + }; + + std::vector m_polygonRanges; + unsigned int m_numPolygons; + + std::string m_name; + + LayersInfo m_layersInfo; + + /// The mesh bounding box. + RAS_BoundingBox *m_boundingBox; + + RAS_MeshMaterialList m_materials; + Mesh *m_mesh; + +public: + RAS_Mesh(Mesh *mesh, const LayersInfo& layersInfo); + RAS_Mesh(const std::string& name, const LayersInfo& layersInfo); + RAS_Mesh(const RAS_Mesh& other); + virtual ~RAS_Mesh(); + + // materials + unsigned short GetNumMaterials() const; + std::string GetMaterialName(unsigned int matid) const; + std::string GetTextureName(unsigned int matid) const; + + const RAS_MeshMaterialList& GetMeshMaterialList() const; + RAS_MeshMaterial *GetMeshMaterial(unsigned int matid) const; + RAS_MeshMaterial *GetMeshMaterialBlenderIndex(unsigned int index) const; + RAS_MeshMaterial *FindMaterialName(const std::string& name) const; + + // name + const std::string& GetName() const; + + // original blender mesh + Mesh *GetMesh() + { + return m_mesh; + } + + /** Add a material with empty display array along given vertex format. + * \param bucket Material bucket used to draw this mesh part. + * \param index The blender material index in mesh. + * \param format The vertex format used to initialize the display array. + */ + RAS_MeshMaterial *AddMaterial(RAS_MaterialBucket *bucket, unsigned int index, const RAS_DisplayArray::Format& format); + + /** Add a material with an already constructed display array. + * \param bucket Material bucket used to draw this mesh part. + * \param index The blender material index in mesh. + * \param array The display array. + */ + RAS_MeshMaterial *AddMaterial(RAS_MaterialBucket *bucket, unsigned int index, RAS_DisplayArray *array); + + RAS_DisplayArray *GetDisplayArray(unsigned int matid) const; + + unsigned int GetNumPolygons() const; + PolygonInfo GetPolygon(unsigned int index) const; + + RAS_BoundingBox *GetBoundingBox() const; + // buckets + RAS_MeshUser *AddMeshUser(void *clientobj, RAS_Deformer *deformer); + + void EndConversion(RAS_BoundingBoxManager *boundingBoxManager); + + /// Return the list of blender's layers. + const LayersInfo& GetLayersInfo() const; +}; + +#endif // __RAS_MESH_H__ diff --git a/source/gameengine/Rasterizer/RAS_MeshMaterial.cpp b/source/gameengine/Rasterizer/RAS_MeshMaterial.cpp new file mode 100644 index 000000000000..48636751d7be --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_MeshMaterial.cpp @@ -0,0 +1,87 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "RAS_MeshMaterial.h" +#include "RAS_MaterialBucket.h" +#include "RAS_DisplayArray.h" +#include "RAS_DisplayArrayBucket.h" + +RAS_MeshMaterial::RAS_MeshMaterial(RAS_Mesh *mesh, RAS_MaterialBucket *bucket, unsigned int index, const RAS_DisplayArray::Format& format) + :m_bucket(bucket), + m_index(index) +{ + RAS_DisplayArray::PrimitiveType type = (bucket->IsWire()) ? RAS_DisplayArray::LINES : RAS_DisplayArray::TRIANGLES; + m_displayArray = new RAS_DisplayArray(type, format); + + m_displayArrayBucket = new RAS_DisplayArrayBucket(bucket, m_displayArray, mesh, this, nullptr); +} + +RAS_MeshMaterial::RAS_MeshMaterial(RAS_Mesh *mesh, RAS_MaterialBucket *bucket, unsigned int index, RAS_DisplayArray *array) + :m_bucket(bucket), + m_index(index), + m_displayArray(array) +{ + m_displayArrayBucket = new RAS_DisplayArrayBucket(bucket, m_displayArray, mesh, this, nullptr); +} + +RAS_MeshMaterial::RAS_MeshMaterial(const RAS_MeshMaterial& other, RAS_Mesh *mesh) + :m_bucket(other.m_bucket), + m_index(other.m_index) +{ + m_displayArray = new RAS_DisplayArray(*other.m_displayArray); + m_displayArrayBucket = new RAS_DisplayArrayBucket(m_bucket, m_displayArray, mesh, this, nullptr); +} + +RAS_MeshMaterial::~RAS_MeshMaterial() +{ + delete m_displayArrayBucket; + delete m_displayArray; +} + +unsigned int RAS_MeshMaterial::GetIndex() const +{ + return m_index; +} + +RAS_MaterialBucket *RAS_MeshMaterial::GetBucket() const +{ + return m_bucket; +} + +RAS_DisplayArray *RAS_MeshMaterial::GetDisplayArray() const +{ + return m_displayArray; +} + +RAS_DisplayArrayBucket *RAS_MeshMaterial::GetDisplayArrayBucket() const +{ + return m_displayArrayBucket; +} + +void RAS_MeshMaterial::ReplaceMaterial(RAS_MaterialBucket *bucket) +{ + // Avoid replacing the by the same material bucket. + if (m_bucket != bucket) { + m_bucket->MoveDisplayArrayBucket(this, bucket); + m_bucket = bucket; + } +} diff --git a/source/gameengine/Rasterizer/RAS_MeshMaterial.h b/source/gameengine/Rasterizer/RAS_MeshMaterial.h new file mode 100644 index 000000000000..aef4c74c5b25 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_MeshMaterial.h @@ -0,0 +1,77 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_MeshMaterial.h + * \ingroup bgerast + */ + +#ifndef __RAS_MESH_MATERIAL_H__ +#define __RAS_MESH_MATERIAL_H__ + +#include "RAS_DisplayArray.h" + +#include + +class RAS_Mesh; +class RAS_DisplayArrayBucket; +class RAS_MaterialBucket; + +/** \brief Node between material and mesh. + * Own the display array and the display array bucket used to draw the part of the mesh + * with the bucket material. + */ +class RAS_MeshMaterial +{ +private: + RAS_MaterialBucket *m_bucket; + /// The blender material index position in the mesh. + unsigned int m_index; + + RAS_DisplayArray *m_displayArray; + RAS_DisplayArrayBucket *m_displayArrayBucket; + +public: + RAS_MeshMaterial(RAS_Mesh *mesh, RAS_MaterialBucket *bucket, unsigned int index, const RAS_DisplayArray::Format& format); + /** Copy mesh material for a given mesh object. + * \param mesh Owner of copied mesh material. + */ + RAS_MeshMaterial(const RAS_MeshMaterial& other, RAS_Mesh *mesh); + RAS_MeshMaterial(RAS_Mesh *mesh, RAS_MaterialBucket *bucket, unsigned int index, RAS_DisplayArray *array); + ~RAS_MeshMaterial(); + + + unsigned int GetIndex() const; + RAS_MaterialBucket *GetBucket() const; + RAS_DisplayArray *GetDisplayArray() const; + RAS_DisplayArrayBucket *GetDisplayArrayBucket() const; + + void ReplaceMaterial(RAS_MaterialBucket *bucket); +}; + +using RAS_MeshMaterialList = std::vector; + +#endif // __RAS_MESH_MATERIAL_H__ diff --git a/source/gameengine/Rasterizer/RAS_MeshObject.cpp b/source/gameengine/Rasterizer/RAS_MeshObject.cpp deleted file mode 100644 index f39af70cf71a..000000000000 --- a/source/gameengine/Rasterizer/RAS_MeshObject.cpp +++ /dev/null @@ -1,573 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Rasterizer/RAS_MeshObject.cpp - * \ingroup bgerast - */ - -#include "DNA_key_types.h" -#include "DNA_mesh_types.h" - -#include "CTR_HashedPtr.h" - -#include "RAS_MeshObject.h" -#include "RAS_Polygon.h" -#include "RAS_IPolygonMaterial.h" -#include "RAS_Deformer.h" -#include "MT_Point3.h" - -#include - - -/* polygon sorting */ - -struct RAS_MeshObject::polygonSlot -{ - float m_z; - int m_index[4]; - - polygonSlot() {} - - /* pnorm is the normal from the plane equation that the distance from is - * used to sort again. */ - void get(const RAS_TexVert *vertexarray, const unsigned short *indexarray, - int offset, int nvert, const MT_Vector3& pnorm) - { - MT_Vector3 center(0, 0, 0); - int i; - - for (i=0; i b.m_z; - } -}; - -/* mesh object */ - -STR_String RAS_MeshObject::s_emptyname = ""; - -RAS_MeshObject::RAS_MeshObject(Mesh* mesh) - : m_bModified(true), - m_bMeshModified(true), - m_mesh(mesh) -{ - if (m_mesh && m_mesh->key) - { - KeyBlock *kb; - int count=0; - // initialize weight cache for shape objects - // count how many keys in this mesh - for (kb= (KeyBlock *)m_mesh->key->block.first; kb; kb= (KeyBlock *)kb->next) - count++; - m_cacheWeightIndex.resize(count,-1); - } -} - -RAS_MeshObject::~RAS_MeshObject() -{ - vector::iterator it; - - for (it=m_Polygons.begin(); it!=m_Polygons.end(); it++) - delete (*it); - - m_sharedvertex_map.clear(); - m_Polygons.clear(); - m_materials.clear(); -} - -bool RAS_MeshObject::MeshModified() -{ - return m_bMeshModified; -} - -//unsigned int RAS_MeshObject::GetLightLayer() -//{ -// return m_lightlayer; -//} - - - -int RAS_MeshObject::NumMaterials() -{ - return m_materials.size(); -} - -const STR_String& RAS_MeshObject::GetMaterialName(unsigned int matid) -{ - RAS_MeshMaterial* mmat = GetMeshMaterial(matid); - - if (mmat) - return mmat->m_bucket->GetPolyMaterial()->GetMaterialName(); - - return s_emptyname; -} - -RAS_MeshMaterial* RAS_MeshObject::GetMeshMaterial(unsigned int matid) -{ - if ((m_materials.empty() == false) && (matid < m_materials.size())) - { - list::iterator it = m_materials.begin(); - while (matid--) ++it; - return &*it; - } - - return NULL; -} - - - -int RAS_MeshObject::NumPolygons() -{ - return m_Polygons.size(); -} - - - -RAS_Polygon* RAS_MeshObject::GetPolygon(int num) const -{ - return m_Polygons[num]; -} - - - - - list::iterator GetFirstMaterial(); - list::iterator GetLastMaterial(); -list::iterator RAS_MeshObject::GetFirstMaterial() -{ - return m_materials.begin(); -} - - - -list::iterator RAS_MeshObject::GetLastMaterial() -{ - return m_materials.end(); -} - - - -void RAS_MeshObject::SetName(const char *name) -{ - m_name = name; -} - - - -STR_String& RAS_MeshObject::GetName() -{ - return m_name; -} - - - -const STR_String& RAS_MeshObject::GetTextureName(unsigned int matid) -{ - RAS_MeshMaterial* mmat = GetMeshMaterial(matid); - - if (mmat) - return mmat->m_bucket->GetPolyMaterial()->GetTextureName(); - - return s_emptyname; -} - -RAS_MeshMaterial *RAS_MeshObject::GetMeshMaterial(RAS_IPolyMaterial *mat) -{ - list::iterator mit; - - /* find a mesh material */ - for (mit = m_materials.begin(); mit != m_materials.end(); mit++) - if (mit->m_bucket->GetPolyMaterial() == mat) - return &*mit; - - return NULL; -} - -int RAS_MeshObject::GetMaterialId(RAS_IPolyMaterial *mat) -{ - list::iterator mit; - int imat; - - /* find a mesh material */ - for (imat=0, mit = m_materials.begin(); mit != m_materials.end(); mit++, imat++) - if (mit->m_bucket->GetPolyMaterial() == mat) - return imat; - - return -1; -} - -RAS_Polygon* RAS_MeshObject::AddPolygon(RAS_MaterialBucket *bucket, int numverts) -{ - RAS_MeshMaterial *mmat; - RAS_Polygon *poly; - RAS_MeshSlot *slot; - - /* find a mesh material */ - mmat = GetMeshMaterial(bucket->GetPolyMaterial()); - - /* none found, create a new one */ - if (!mmat) { - RAS_MeshMaterial meshmat; - meshmat.m_bucket = bucket; - meshmat.m_baseslot = meshmat.m_bucket->AddMesh(numverts); - meshmat.m_baseslot->m_mesh = this; - m_materials.push_back(meshmat); - mmat = &m_materials.back(); - } - - /* add it to the bucket, this also adds new display arrays */ - slot = mmat->m_baseslot; - slot->AddPolygon(numverts); - - /* create a new polygon */ - RAS_DisplayArray *darray = slot->CurrentDisplayArray(); - poly = new RAS_Polygon(bucket, darray, numverts); - m_Polygons.push_back(poly); - - return poly; -} - -void RAS_MeshObject::DebugColor(unsigned int abgr) -{ - /*int numpolys = NumPolygons(); - - for (int i=0;iVertexCount();v++) - RAS_TexVert* vtx = poly->GetVertex(v)->setDebugRGBA(abgr); - } - */ - - /* m_debugcolor = abgr; */ -} - -void RAS_MeshObject::SetVertexColor(RAS_IPolyMaterial* mat,MT_Vector4 rgba) -{ - RAS_MeshMaterial *mmat = GetMeshMaterial(mat); - RAS_MeshSlot *slot = mmat->m_baseslot; - RAS_MeshSlot::iterator it; - size_t i; - - for (slot->begin(it); !slot->end(it); slot->next(it)) - for (i=it.startvertex; iGetMaterial()->GetPolyMaterial()); - slot = mmat->m_baseslot; - darray = slot->CurrentDisplayArray(); - - { /* Shared Vertex! */ - /* find vertices shared between faces, with the restriction - * that they exist in the same display array, and have the - * same uv coordinate etc */ - vector& sharedmap = m_sharedvertex_map[origindex]; - vector::iterator it; - - for (it = sharedmap.begin(); it != sharedmap.end(); it++) - { - if (it->m_darray != darray) - continue; - if (!it->m_darray->m_vertex[it->m_offset].closeTo(&texvert)) - continue; - - /* found one, add it and we're done */ - if (poly->IsVisible()) - slot->AddPolygonVertex(it->m_offset); - poly->SetVertexOffset(i, it->m_offset); - return; - } - } - - /* no shared vertex found, add a new one */ - offset = slot->AddVertex(texvert); - if (poly->IsVisible()) - slot->AddPolygonVertex(offset); - poly->SetVertexOffset(i, offset); - - { /* Shared Vertex! */ - SharedVertex shared; - shared.m_darray = darray; - shared.m_offset = offset; - m_sharedvertex_map[origindex].push_back(shared); - } -} - -int RAS_MeshObject::NumVertices(RAS_IPolyMaterial* mat) -{ - RAS_MeshMaterial *mmat; - RAS_MeshSlot *slot; - RAS_MeshSlot::iterator it; - size_t len = 0; - - mmat = GetMeshMaterial(mat); - slot = mmat->m_baseslot; - for (slot->begin(it); !slot->end(it); slot->next(it)) - len += it.endvertex - it.startvertex; - - return len; -} - - -RAS_TexVert* RAS_MeshObject::GetVertex(unsigned int matid, - unsigned int index) -{ - RAS_MeshMaterial *mmat; - RAS_MeshSlot *slot; - RAS_MeshSlot::iterator it; - size_t len; - - mmat = GetMeshMaterial(matid); - - if (!mmat) - return NULL; - - slot = mmat->m_baseslot; - len = 0; - for (slot->begin(it); !slot->end(it); slot->next(it)) { - if (index >= len + it.endvertex - it.startvertex) - len += it.endvertex - it.startvertex; - else - return &it.vertex[index - len]; - } - - return NULL; -} - -const float* RAS_MeshObject::GetVertexLocation(unsigned int orig_index) -{ - vector& sharedmap = m_sharedvertex_map[orig_index]; - vector::iterator it= sharedmap.begin(); - return it->m_darray->m_vertex[it->m_offset].getXYZ(); -} - -void RAS_MeshObject::AddMeshUser(void *clientobj, SG_QList *head, RAS_Deformer* deformer) -{ - list::iterator it; - list::iterator mit; - - for (it = m_materials.begin();it!=m_materials.end();++it) { - /* always copy from the base slot, which is never removed - * since new objects can be created with the same mesh data */ - if (deformer && !deformer->UseVertexArray()) - { - // HACK! - // this deformer doesn't use vertex array => derive mesh - // we must keep only the mesh slots that have unique material id - // this is to match the derived mesh drawing function - // Need a better solution in the future: scan the derive mesh and create vertex array - RAS_IPolyMaterial* curmat = it->m_bucket->GetPolyMaterial(); - if (curmat->GetFlag() & RAS_BLENDERGLSL) - { - for (mit = m_materials.begin(); mit != it; ++mit) - { - RAS_IPolyMaterial* mat = mit->m_bucket->GetPolyMaterial(); - if ((mat->GetFlag() & RAS_BLENDERGLSL) && - mat->GetMaterialIndex() == curmat->GetMaterialIndex()) - // no need to convert current mesh slot - break; - } - if (mit != it) - continue; - } - } - RAS_MeshSlot *ms = it->m_bucket->CopyMesh(it->m_baseslot); - ms->m_clientObj = clientobj; - ms->SetDeformer(deformer); - it->m_slots.insert(clientobj, ms); - head->QAddBack(ms); - } -} - -void RAS_MeshObject::RemoveFromBuckets(void *clientobj) -{ - list::iterator it; - - for (it = m_materials.begin();it!=m_materials.end();++it) { - RAS_MeshSlot **msp = it->m_slots[clientobj]; - - if (!msp) - continue; - - RAS_MeshSlot *ms = *msp; - - it->m_bucket->RemoveMesh(ms); - it->m_slots.remove(clientobj); - } -} - -void RAS_MeshObject::EndConversion() -{ -#if 0 - m_sharedvertex_map.clear(); // SharedVertex - vector > shared_null(0); - shared_null.swap( m_sharedvertex_map ); /* really free the memory */ -#endif - - for (std::list::iterator it = m_materials.begin(); - it != m_materials.end(); - ++it) - { - RAS_MeshSlot *ms = it->m_baseslot; - ms->UpdateDisplayArraysOffset(); - } -} - -//void RAS_MeshObject::Transform(const MT_Transform& trans) -//{ - //m_trans.translate(MT_Vector3(0,0,1));//.operator *=(trans); - -// for (int i=0;iTransform(trans); -// } -//} - - -/* -void RAS_MeshObject::RelativeTransform(const MT_Vector3& vec) -{ - for (int i=0;iRelativeTransform(vec); - } -} -*/ - -void RAS_MeshObject::SortPolygons(RAS_MeshSlot& ms, const MT_Transform &transform) -{ - // Limitations: sorting is quite simple, and handles many - // cases wrong, partially due to polygons being sorted per - // bucket. - // - // a) mixed triangles/quads are sorted wrong - // b) mixed materials are sorted wrong - // c) more than 65k faces are sorted wrong - // d) intersecting objects are sorted wrong - // e) intersecting polygons are sorted wrong - // - // a) can be solved by making all faces either triangles or quads - // if they need to be z-sorted. c) could be solved by allowing - // larger buckets, b) and d) cannot be solved easily if we want - // to avoid excessive state changes while drawing. e) would - // require splitting polygons. - - RAS_MeshSlot::iterator it; - size_t j; - - for (ms.begin(it); !ms.end(it); ms.next(it)) { - unsigned int nvert = (int)it.array->m_type; - unsigned int totpoly = it.totindex/nvert; - - if (totpoly <= 1) - continue; - if (it.array->m_type == RAS_DisplayArray::LINE) - continue; - - // Extract camera Z plane... - const MT_Vector3 pnorm(transform.getBasis()[2]); - // unneeded: const MT_Scalar pval = transform.getOrigin()[2]; - - vector poly_slots(totpoly); - - /* get indices and z into temporary array */ - for (j=0; jIsCollider()) - return true; - - return false; -} - -void RAS_MeshObject::SchedulePolygons(int drawingmode) -{ - if (m_bModified) - { - m_bModified = false; - m_bMeshModified = true; - } -} diff --git a/source/gameengine/Rasterizer/RAS_MeshObject.h b/source/gameengine/Rasterizer/RAS_MeshObject.h deleted file mode 100644 index ac643f52f06b..000000000000 --- a/source/gameengine/Rasterizer/RAS_MeshObject.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file RAS_MeshObject.h - * \ingroup bgerast - */ - -#ifndef __RAS_MESHOBJECT_H__ -#define __RAS_MESHOBJECT_H__ - -#ifdef _MSC_VER - /* disable the STL warnings ("debug information length > 255") */ -# pragma warning (disable:4786) -#endif - -#include -#include - -#include "RAS_MaterialBucket.h" -#include "MT_Transform.h" -#include "STR_String.h" - -struct Mesh; -class RAS_Deformer; -class RAS_Polygon; - -/* RAS_MeshObject is a mesh used for rendering. It stores polygons, - * but the actual vertices and index arrays are stored in material - * buckets, referenced by the list of RAS_MeshMaterials. */ - -class RAS_MeshObject -{ -private: - /* unsigned int m_debugcolor; */ /* UNUSED */ - - bool m_bModified; - bool m_bMeshModified; - - STR_String m_name; - static STR_String s_emptyname; - - vector m_Polygons; - - /* polygon sorting */ - struct polygonSlot; - struct backtofront; - struct fronttoback; - -protected: - vector m_cacheWeightIndex; - list m_materials; - Mesh* m_mesh; - -public: - // for now, meshes need to be in a certain layer (to avoid sorting on lights in realtime) - RAS_MeshObject(Mesh* mesh); - virtual ~RAS_MeshObject(); - - - /* materials */ - int NumMaterials(); - const STR_String& GetMaterialName(unsigned int matid); - const STR_String& GetTextureName(unsigned int matid); - - RAS_MeshMaterial* GetMeshMaterial(unsigned int matid); - RAS_MeshMaterial* GetMeshMaterial(RAS_IPolyMaterial *mat); - int GetMaterialId(RAS_IPolyMaterial *mat); - - list::iterator GetFirstMaterial(); - list::iterator GetLastMaterial(); - - //unsigned int GetLightLayer(); - - /* name */ - void SetName(const char *name); - STR_String& GetName(); - - /* modification state */ - bool MeshModified(); - void SetMeshModified(bool v) { m_bMeshModified = v; } - - /* original blender mesh */ - Mesh* GetMesh() { return m_mesh; } - - /* mesh construction */ - - virtual RAS_Polygon* AddPolygon(RAS_MaterialBucket *bucket, int numverts); - virtual void AddVertex(RAS_Polygon *poly, int i, - const MT_Point3& xyz, - const MT_Point2 uvs[RAS_TexVert::MAX_UNIT], - const MT_Vector4& tangent, - const unsigned int rgbacolor, - const MT_Vector3& normal, - bool flat, - int origindex); - - void SchedulePolygons(int drawingmode); - - /* vertex and polygon acces */ - int NumVertices(RAS_IPolyMaterial* mat); - RAS_TexVert* GetVertex(unsigned int matid, unsigned int index); - const float* GetVertexLocation(unsigned int orig_index); - - int NumPolygons(); - RAS_Polygon* GetPolygon(int num) const; - - /* buckets */ - virtual void AddMeshUser(void *clientobj, SG_QList *head, RAS_Deformer* deformer); - - void RemoveFromBuckets(void *clientobj); - void EndConversion(); - - /* colors */ - void DebugColor(unsigned int abgr); - void SetVertexColor(RAS_IPolyMaterial* mat,MT_Vector4 rgba); - - /* polygon sorting by Z for alpha */ - void SortPolygons(RAS_MeshSlot& ms, const MT_Transform &transform); - - - bool HasColliderPolygon(); - - /* for construction to find shared vertices */ - struct SharedVertex { - RAS_DisplayArray *m_darray; - int m_offset; - }; - - vector > m_sharedvertex_map; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_MeshObject") -#endif -}; - -#endif /* __RAS_MESHOBJECT_H__ */ diff --git a/source/gameengine/Rasterizer/RAS_MeshSlot.cpp b/source/gameengine/Rasterizer/RAS_MeshSlot.cpp new file mode 100644 index 000000000000..c0962f2c2b9a --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_MeshSlot.cpp @@ -0,0 +1,116 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Rasterizer/RAS_MeshSlot.cpp + * \ingroup bgerast + */ + +#include "RAS_MeshSlot.h" +#include "RAS_MeshUser.h" +#include "RAS_IMaterial.h" +#include "RAS_DisplayArray.h" +#include "RAS_DisplayArrayStorage.h" +#include "RAS_Mesh.h" + +#ifdef _MSC_VER +# pragma warning (disable:4786) +#endif + +#ifdef WIN32 +# include +#endif // WIN32 + +static RAS_DummyNodeData dummyNodeData; + +// mesh slot +RAS_MeshSlot::RAS_MeshSlot(RAS_MeshUser *meshUser, RAS_DisplayArrayBucket *arrayBucket) + :m_node(this, &dummyNodeData, &RAS_MeshSlot::RunNode, nullptr), + m_displayArrayBucket(arrayBucket), + m_meshUser(meshUser), + m_batchPartIndex(-1) +{ +} + +RAS_MeshSlot::~RAS_MeshSlot() +{ +} + +RAS_MeshSlot::RAS_MeshSlot(const RAS_MeshSlot& other) + :m_node(this, &dummyNodeData, &RAS_MeshSlot::RunNode, nullptr), + m_displayArrayBucket(other.m_displayArrayBucket), + m_meshUser(other.m_meshUser), + m_batchPartIndex(other.m_batchPartIndex) +{ +} + +void RAS_MeshSlot::SetDisplayArrayBucket(RAS_DisplayArrayBucket *arrayBucket) +{ + m_displayArrayBucket = arrayBucket; +} + +void RAS_MeshSlot::GenerateTree(RAS_DisplayArrayUpwardNode& root, RAS_UpwardTreeLeafs& leafs) +{ + m_node.SetParent(&root); + leafs.push_back(&m_node); +} + +void RAS_MeshSlot::RunNode(const RAS_MeshSlotNodeTuple& tuple) +{ + RAS_ManagerNodeData *managerData = tuple.m_managerData; + RAS_MaterialNodeData *materialData = tuple.m_materialData; + RAS_DisplayArrayNodeData *displayArrayData = tuple.m_displayArrayData; + RAS_Rasterizer *rasty = managerData->m_rasty; + rasty->SetClientObject(m_meshUser->GetClientObject()); + rasty->SetFrontFace(m_meshUser->GetFrontFace()); + + RAS_DisplayArrayStorage *storage = displayArrayData->m_arrayStorage; + + if (!managerData->m_shaderOverride) { + materialData->m_material->ActivateMeshUser(m_meshUser, rasty, managerData->m_trans); + + if (materialData->m_zsort && storage) { + displayArrayData->m_array->SortPolygons( + managerData->m_trans * mt::mat4::ToAffineTransform(m_meshUser->GetMatrix()), storage->GetIndexMap()); + storage->FlushIndexMap(); + } + } + + rasty->PushMatrix(); + + if (materialData->m_text) { + rasty->IndexPrimitivesText(this); + } + else { + if (displayArrayData->m_applyMatrix) { + float mat[16]; + rasty->GetTransform(m_meshUser->GetMatrix(), materialData->m_drawingMode, mat); + rasty->MultMatrix(mat); + } + storage->IndexPrimitives(); + } + rasty->PopMatrix(); +} diff --git a/source/gameengine/GameLogic/SCA_PropertyEventManager.h b/source/gameengine/Rasterizer/RAS_MeshSlot.h similarity index 55% rename from source/gameengine/GameLogic/SCA_PropertyEventManager.h rename to source/gameengine/Rasterizer/RAS_MeshSlot.h index 554fe686df20..5bfe5c8ced0f 100644 --- a/source/gameengine/GameLogic/SCA_PropertyEventManager.h +++ b/source/gameengine/Rasterizer/RAS_MeshSlot.h @@ -25,31 +25,43 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file SCA_PropertyEventManager.h - * \ingroup gamelogic +/** \file RAS_MeshSlot.h + * \ingroup bgerast */ -#ifndef __SCA_PROPERTYEVENTMANAGER_H__ -#define __SCA_PROPERTYEVENTMANAGER_H__ +#ifndef __RAS_MESH_SLOT_H__ +#define __RAS_MESH_SLOT_H__ -#include "SCA_EventManager.h" +#include "RAS_RenderNode.h" #include -using namespace std; +class RAS_DisplayArrayBucket; +class RAS_MeshUser; -class SCA_PropertyEventManager : public SCA_EventManager +class RAS_MeshSlot { +private: + RAS_MeshSlotUpwardNode m_node; + public: - SCA_PropertyEventManager(class SCA_LogicManager* logicmgr); - virtual ~SCA_PropertyEventManager(); - virtual void NextFrame(); - //SCA_LogicManager* GetLogicManager() { return m_logicmgr;} + // for rendering + RAS_DisplayArrayBucket *m_displayArrayBucket; + RAS_MeshUser *m_meshUser; + + /// Batch index used for batching render. + short m_batchPartIndex; + RAS_MeshSlot(RAS_MeshUser *meshUser, RAS_DisplayArrayBucket *arrayBucket); + RAS_MeshSlot(const RAS_MeshSlot& other); + virtual ~RAS_MeshSlot(); -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:SCA_PropertyEventManager") -#endif + void SetDisplayArrayBucket(RAS_DisplayArrayBucket *arrayBucket); + + void GenerateTree(RAS_DisplayArrayUpwardNode& root, RAS_UpwardTreeLeafs& leafs); + void RunNode(const RAS_MeshSlotNodeTuple& tuple); }; -#endif /* __SCA_PROPERTYEVENTMANAGER_H__ */ +typedef std::vector RAS_MeshSlotList; + +#endif // __RAS_MESH_SLOT_H__ diff --git a/source/gameengine/Rasterizer/RAS_MeshUser.cpp b/source/gameengine/Rasterizer/RAS_MeshUser.cpp new file mode 100644 index 000000000000..e763d890abc8 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_MeshUser.cpp @@ -0,0 +1,167 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is: all of this file. + * + * Contributor(s): Porteries Tristan. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_MeshUser.cpp + * \ingroup bgerast + */ + +#include "RAS_MeshUser.h" +#include "RAS_DisplayArrayBucket.h" +#include "RAS_BoundingBox.h" +#include "RAS_BatchGroup.h" +#include "RAS_Deformer.h" + +#include "BLI_hash.h" + +RAS_MeshUser::RAS_MeshUser(void *clientobj, RAS_BoundingBox *boundingBox, RAS_Deformer *deformer) + :m_layer((1 << 20) - 1), + m_passIndex(0), + m_random(BLI_hash_int_2d((uintptr_t)clientobj, 0) / ((float)0xFFFFFFFF)), + m_frontFace(true), + m_color(mt::zero4), + m_boundingBox(boundingBox), + m_clientObject(clientobj), + m_batchGroup(nullptr), + m_deformer(deformer) +{ + BLI_assert(m_boundingBox); + m_boundingBox->AddUser(); +} + +RAS_MeshUser::~RAS_MeshUser() +{ + m_meshSlots.clear(); + + m_boundingBox->RemoveUser(); + + if (m_batchGroup) { + // Has the side effect to deference the batch group. + m_batchGroup->SplitMeshUser(this); + } +} + +void RAS_MeshUser::NewMeshSlot(RAS_DisplayArrayBucket *arrayBucket) +{ + m_meshSlots.emplace_back(this, arrayBucket); +} + +unsigned int RAS_MeshUser::GetLayer() const +{ + return m_layer; +} + +short RAS_MeshUser::GetPassIndex() const +{ + return m_passIndex; +} + +float RAS_MeshUser::GetRandom() const +{ + return m_random; +} + +bool RAS_MeshUser::GetFrontFace() const +{ + return m_frontFace; +} + +const mt::vec4& RAS_MeshUser::GetColor() const +{ + return m_color; +} + +const mt::mat4& RAS_MeshUser::GetMatrix() const +{ + return m_matrix; +} + +RAS_BoundingBox *RAS_MeshUser::GetBoundingBox() const +{ + return m_boundingBox; +} + +void *RAS_MeshUser::GetClientObject() const +{ + return m_clientObject; +} + +std::vector& RAS_MeshUser::GetMeshSlots() +{ + return m_meshSlots; +} + +RAS_BatchGroup *RAS_MeshUser::GetBatchGroup() const +{ + return m_batchGroup; +} + +RAS_Deformer *RAS_MeshUser::GetDeformer() +{ + return m_deformer.get(); +} + +void RAS_MeshUser::SetLayer(unsigned int layer) +{ + m_layer = layer; +} + +void RAS_MeshUser::SetPassIndex(short index) +{ + m_passIndex = index; +} + +void RAS_MeshUser::SetFrontFace(bool frontFace) +{ + m_frontFace = frontFace; +} + +void RAS_MeshUser::SetColor(const mt::vec4& color) +{ + m_color = color; +} + +void RAS_MeshUser::SetMatrix(const mt::mat4& matrix) +{ + m_matrix = matrix; +} + +void RAS_MeshUser::SetBatchGroup(RAS_BatchGroup *batchGroup) +{ + if (m_batchGroup) { + m_batchGroup->RemoveMeshUser(); + } + + m_batchGroup = batchGroup; + + if (m_batchGroup) { + m_batchGroup->AddMeshUser(); + } +} + +void RAS_MeshUser::ActivateMeshSlots() +{ + for (RAS_MeshSlot& ms : m_meshSlots) { + ms.m_displayArrayBucket->ActivateMesh(&ms); + } +} diff --git a/source/gameengine/Rasterizer/RAS_MeshUser.h b/source/gameengine/Rasterizer/RAS_MeshUser.h new file mode 100644 index 000000000000..8ed1edbe1b99 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_MeshUser.h @@ -0,0 +1,93 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is: all of this file. + * + * Contributor(s): Porteries Tristan. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_MeshUser.h + * \ingroup bgerast + */ + +#ifndef __RAS_MESH_USER_H__ +#define __RAS_MESH_USER_H__ + +#include "RAS_MeshSlot.h" + +#include + +class RAS_BoundingBox; +class RAS_BatchGroup; +class RAS_Deformer; + +class RAS_MeshUser : public mt::SimdClassAllocator +{ +private: + /// Lamp layer. + unsigned int m_layer; + /// Object pass index. + short m_passIndex; + /// Random value of this user. + float m_random; + /// OpenGL face wise. + bool m_frontFace; + /// Object color. + mt::vec4 m_color; + /// Object transformation matrix. + mt::mat4 m_matrix; + /// Bounding box corresponding to a mesh or deformer. + RAS_BoundingBox *m_boundingBox; + /// Client object owner of this mesh user. + void *m_clientObject; + /// Unique mesh slots used for render of this object. + std::vector m_meshSlots; + /// Possible batching groups shared between mesh users. + RAS_BatchGroup *m_batchGroup; + /// Deformer of this mesh user modifying the display array of the mesh slots. + std::unique_ptr m_deformer; + +public: + RAS_MeshUser(void *clientobj, RAS_BoundingBox *boundingBox, RAS_Deformer *deformer); + virtual ~RAS_MeshUser(); + + void NewMeshSlot(RAS_DisplayArrayBucket *arrayBucket); + unsigned int GetLayer() const; + short GetPassIndex() const; + float GetRandom() const; + bool GetFrontFace() const; + const mt::vec4& GetColor() const; + const mt::mat4& GetMatrix() const; + RAS_BoundingBox *GetBoundingBox() const; + void *GetClientObject() const; + std::vector& GetMeshSlots(); + RAS_BatchGroup *GetBatchGroup() const; + RAS_Deformer *GetDeformer(); + + void SetLayer(unsigned int layer); + void SetPassIndex(short index); + void SetFrontFace(bool frontFace); + void SetColor(const mt::vec4& color); + void SetMatrix(const mt::mat4& matrix); + void SetBatchGroup(RAS_BatchGroup *batchGroup); + + void ActivateMeshSlots(); +}; + +#endif // __RAS_MESH_USER_H__ diff --git a/source/gameengine/Rasterizer/RAS_OffScreen.cpp b/source/gameengine/Rasterizer/RAS_OffScreen.cpp new file mode 100644 index 000000000000..e533acae64d3 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OffScreen.cpp @@ -0,0 +1,134 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Rasterizer/RAS_OffScreen.cpp + * \ingroup bgerast + */ + +#include "RAS_OffScreen.h" + +RAS_OffScreen *RAS_OffScreen::lastOffScreen = nullptr; + +RAS_OffScreen::RAS_OffScreen(unsigned int width, unsigned int height, int samples, GPUHDRType hdrType, GPUOffScreenMode mode, char errOut[256], + RAS_Rasterizer::OffScreenType type) + :m_offScreen(GPU_offscreen_create(width, height, samples, hdrType, mode, errOut)), + m_type(type) +{ +} + +RAS_OffScreen::~RAS_OffScreen() +{ + if (GetValid()) { + GPU_offscreen_free(m_offScreen); + } +} + +bool RAS_OffScreen::GetValid() const +{ + return (m_offScreen != nullptr); +} + +void RAS_OffScreen::Bind() +{ + GPU_offscreen_bind_simple(m_offScreen); + lastOffScreen = this; +} + +RAS_OffScreen *RAS_OffScreen::Blit(RAS_OffScreen *dstOffScreen, bool color, bool depth) +{ + GPU_offscreen_blit(m_offScreen, dstOffScreen->m_offScreen, color, depth); + + return dstOffScreen; +} + +void RAS_OffScreen::BindColorTexture(unsigned short slot) +{ + GPU_texture_bind(GPU_offscreen_texture(m_offScreen), slot); +} + +void RAS_OffScreen::BindDepthTexture(unsigned short slot) +{ + GPU_texture_bind(GPU_offscreen_depth_texture(m_offScreen), slot); +} + +void RAS_OffScreen::UnbindColorTexture() +{ + GPU_texture_unbind(GPU_offscreen_texture(m_offScreen)); +} + +void RAS_OffScreen::UnbindDepthTexture() +{ + GPU_texture_unbind(GPU_offscreen_depth_texture(m_offScreen)); +} + +void RAS_OffScreen::MipmapTexture() +{ + GPUTexture *tex = GPU_offscreen_texture(m_offScreen); + GPU_texture_filter_mode(tex, false, true, true); + GPU_texture_generate_mipmap(tex); +} + +void RAS_OffScreen::UnmipmapTexture() +{ + GPU_texture_filter_mode(GPU_offscreen_texture(m_offScreen), false, true, false); +} + +int RAS_OffScreen::GetColorBindCode() const +{ + return GPU_offscreen_color_texture(m_offScreen); +} + +int RAS_OffScreen::GetSamples() const +{ + return GPU_offscreen_samples(m_offScreen); +} + +unsigned int RAS_OffScreen::GetWidth() const +{ + return GPU_offscreen_width(m_offScreen); +} + +unsigned int RAS_OffScreen::GetHeight() const +{ + return GPU_offscreen_height(m_offScreen); +} + +RAS_Rasterizer::OffScreenType RAS_OffScreen::GetType() const +{ + return m_type; +} + +GPUTexture *RAS_OffScreen::GetDepthTexture() +{ + return GPU_offscreen_depth_texture(m_offScreen); +} + +RAS_OffScreen *RAS_OffScreen::GetLastOffScreen() +{ + return lastOffScreen; +} + +void RAS_OffScreen::RestoreScreen() +{ + GPU_framebuffer_restore(); + lastOffScreen = nullptr; +} diff --git a/source/gameengine/Rasterizer/RAS_OffScreen.h b/source/gameengine/Rasterizer/RAS_OffScreen.h new file mode 100644 index 000000000000..40f3ee23d7d3 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OffScreen.h @@ -0,0 +1,80 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_OffScreen.h + * \ingroup bgerast + */ + +#ifndef __RAS_OFFSCREEN_H__ +#define __RAS_OFFSCREEN_H__ + +#include "RAS_Rasterizer.h" + +#include "GPU_framebuffer.h" + +struct GPUOffScreen; +struct GPUTexture; + +class RAS_OffScreen +{ +private: + /// All the off screens used. + GPUOffScreen *m_offScreen; + /// The off screen type, render, final, filter ect... + RAS_Rasterizer::OffScreenType m_type; + + /// The last bound off screen, set to nullptr in RestoreScreen(). + static RAS_OffScreen *lastOffScreen; + +public: + RAS_OffScreen(unsigned int width, unsigned int height, int samples, GPUHDRType hdrType, GPUOffScreenMode mode, char errOut[256], + RAS_Rasterizer::OffScreenType type); + ~RAS_OffScreen(); + + bool GetValid() const; + + void Bind(); + /// NOTE: This function has the side effect to leave the destination off screen bound. + RAS_OffScreen *Blit(RAS_OffScreen *dstOffScreen, bool color, bool depth); + + void BindColorTexture(unsigned short slot); + void BindDepthTexture(unsigned short slot); + void UnbindColorTexture(); + void UnbindDepthTexture(); + + void MipmapTexture(); + void UnmipmapTexture(); + + int GetColorBindCode() const; + + int GetSamples() const; + unsigned GetWidth() const; + unsigned GetHeight() const; + RAS_Rasterizer::OffScreenType GetType() const; + + GPUTexture *GetDepthTexture(); + + static RAS_OffScreen *GetLastOffScreen(); + static void RestoreScreen(); +}; + +#endif // __RAS_OFFSCREEN_H__ diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Blur2DFilter.glsl b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Blur2DFilter.glsl new file mode 100644 index 000000000000..fd9da7b07681 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Blur2DFilter.glsl @@ -0,0 +1,18 @@ +uniform sampler2D bgl_RenderedTexture; +uniform vec2 bgl_TextureCoordinateOffset[9]; + +void main(void) +{ + vec4 samples[9]; + + for (int i = 0; i < 9; i++) + { + samples[i] = texture2D(bgl_RenderedTexture, + gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); + } + + gl_FragColor = (samples[0] + (2.0*samples[1]) + samples[2] + + (2.0*samples[3]) + samples[4] + (2.0*samples[5]) + + samples[6] + (2.0*samples[7]) + samples[8]) / 13.0; +} + diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Blur2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Blur2DFilter.h deleted file mode 100644 index 295244e3e949..000000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Blur2DFilter.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file RAS_Blur2DFilter.h - * \ingroup bgerastoglfilters - */ - -#ifndef __RAS_BLUR2DFILTER_H__ -#define __RAS_BLUR2DFILTER_H__ - -static const char *BlurFragmentShader = STRINGIFY( -uniform sampler2D bgl_RenderedTexture; -uniform vec2 bgl_TextureCoordinateOffset[9]; - -void main(void) -{ - vec4 sample[9]; - - for (int i = 0; i < 9; i++) - { - sample[i] = texture2D(bgl_RenderedTexture, - gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); - } - - gl_FragColor = (sample[0] + (2.0*sample[1]) + sample[2] + - (2.0*sample[3]) + sample[4] + (2.0*sample[5]) + - sample[6] + (2.0*sample[7]) + sample[8]) / 13.0; -} -); -#endif diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Dilation2DFilter.glsl b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Dilation2DFilter.glsl new file mode 100644 index 000000000000..f1fa303254dd --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Dilation2DFilter.glsl @@ -0,0 +1,18 @@ +uniform sampler2D bgl_RenderedTexture; +uniform vec2 bgl_TextureCoordinateOffset[9]; + +void main(void) +{ + vec4 samples[9]; + vec4 maxValue = vec4(0.0); + + for (int i = 0; i < 9; i++) + { + samples[i] = texture2D(bgl_RenderedTexture, + gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); + maxValue = max(samples[i], maxValue); + } + + gl_FragColor = maxValue; +} + diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Dilation2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Dilation2DFilter.h deleted file mode 100644 index 80fb313fb3c5..000000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Dilation2DFilter.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file RAS_Dilation2DFilter.h - * \ingroup bgerastoglfilters - */ - -#ifndef __RAS_DILATION2DFILTER_H__ -#define __RAS_DILATION2DFILTER_H__ - -static const char *DilationFragmentShader = STRINGIFY( -uniform sampler2D bgl_RenderedTexture; -uniform vec2 bgl_TextureCoordinateOffset[9]; - -void main(void) -{ - vec4 sample[9]; - vec4 maxValue = vec4(0.0); - - for (int i = 0; i < 9; i++) - { - sample[i] = texture2D(bgl_RenderedTexture, - gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); - maxValue = max(sample[i], maxValue); - } - - gl_FragColor = maxValue; -} -); -#endif diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Erosion2DFilter.glsl b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Erosion2DFilter.glsl new file mode 100644 index 000000000000..45eeb697fb84 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Erosion2DFilter.glsl @@ -0,0 +1,17 @@ +uniform sampler2D bgl_RenderedTexture; +uniform vec2 bgl_TextureCoordinateOffset[9]; + +void main(void) +{ + vec4 samples[9]; + vec4 minValue = vec4(1.0); + + for (int i = 0; i < 9; i++) + { + samples[i] = texture2D(bgl_RenderedTexture, + gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); + minValue = min(samples[i], minValue); + } + + gl_FragColor = minValue; +} diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Erosion2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Erosion2DFilter.h deleted file mode 100644 index 56e2c22fe2e7..000000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Erosion2DFilter.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file RAS_Erosion2DFilter.h - * \ingroup bgerastoglfilters - */ - -#ifndef __RAS_EROSION2DFILTER_H__ -#define __RAS_EROSION2DFILTER_H__ - -static const char *ErosionFragmentShader = STRINGIFY( -uniform sampler2D bgl_RenderedTexture; -uniform vec2 bgl_TextureCoordinateOffset[9]; - -void main(void) -{ - vec4 sample[9]; - vec4 minValue = vec4(1.0); - - for (int i = 0; i < 9; i++) - { - sample[i] = texture2D(bgl_RenderedTexture, - gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); - minValue = min(sample[i], minValue); - } - - gl_FragColor = minValue; -} -); -#endif diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_GrayScale2DFilter.glsl b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_GrayScale2DFilter.glsl new file mode 100644 index 000000000000..2eba31c96c9d --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_GrayScale2DFilter.glsl @@ -0,0 +1,8 @@ +uniform sampler2D bgl_RenderedTexture; + +void main(void) +{ + vec4 texcolor = texture2D(bgl_RenderedTexture, gl_TexCoord[0].st); + float gray = dot(texcolor.rgb, vec3(0.299, 0.587, 0.114)); + gl_FragColor = vec4(gray, gray, gray, texcolor.a); +} diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_GrayScale2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_GrayScale2DFilter.h deleted file mode 100644 index b2ac1008de11..000000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_GrayScale2DFilter.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file RAS_GrayScale2DFilter.h - * \ingroup bgerastoglfilters - */ - -#ifndef __RAS_GRAYSCALE2DFILTER_H__ -#define __RAS_GRAYSCALE2DFILTER_H__ - -static const char *GrayScaleFragmentShader = STRINGIFY( -uniform sampler2D bgl_RenderedTexture; - -void main(void) -{ - vec4 texcolor = texture2D(bgl_RenderedTexture, gl_TexCoord[0].st); - float gray = dot(texcolor.rgb, vec3(0.299, 0.587, 0.114)); - gl_FragColor = vec4(gray, gray, gray, texcolor.a); -} -); -#endif diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Invert2DFilter.glsl b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Invert2DFilter.glsl new file mode 100644 index 000000000000..2cd8e7dd9b86 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Invert2DFilter.glsl @@ -0,0 +1,8 @@ +uniform sampler2D bgl_RenderedTexture; + +void main(void) +{ + vec4 texcolor = texture2D(bgl_RenderedTexture, gl_TexCoord[0].st); + gl_FragColor.rgb = 1.0 - texcolor.rgb; + gl_FragColor.a = texcolor.a; +} diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Invert2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Invert2DFilter.h deleted file mode 100644 index dce303916ea2..000000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Invert2DFilter.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file RAS_Invert2DFilter.h - * \ingroup bgerastoglfilters - */ - -#ifndef __RAS_INVERT2DFILTER_H__ -#define __RAS_INVERT2DFILTER_H__ - -static const char *InvertFragmentShader = STRINGIFY( -uniform sampler2D bgl_RenderedTexture; - -void main(void) -{ - vec4 texcolor = texture2D(bgl_RenderedTexture, gl_TexCoord[0].st); - gl_FragColor.rgb = 1.0 - texcolor.rgb; - gl_FragColor.a = texcolor.a; -} -); -#endif diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Laplacian2DFilter.glsl b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Laplacian2DFilter.glsl new file mode 100644 index 000000000000..6dbc3fbb7097 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Laplacian2DFilter.glsl @@ -0,0 +1,20 @@ +uniform sampler2D bgl_RenderedTexture; +uniform vec2 bgl_TextureCoordinateOffset[9]; + +void main(void) +{ + vec4 samples[9]; + + for (int i = 0; i < 9; i++) + { + samples[i] = texture2D(bgl_RenderedTexture, + gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); + } + + gl_FragColor = (samples[4] * 8.0) - + (samples[0] + samples[1] + samples[2] + + samples[3] + samples[5] + + samples[6] + samples[7] + samples[8]); + gl_FragColor = vec4(gl_FragColor.rgb, 1.0); +} + diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Laplacian2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Laplacian2DFilter.h deleted file mode 100644 index 84aa2ceb2668..000000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Laplacian2DFilter.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file RAS_Laplacian2DFilter.h - * \ingroup bgerastoglfilters - */ - -#ifndef __RAS_LAPLACIAN2DFILTER_H__ -#define __RAS_LAPLACIAN2DFILTER_H__ - -static const char *LaplacionFragmentShader = STRINGIFY( -uniform sampler2D bgl_RenderedTexture; -uniform vec2 bgl_TextureCoordinateOffset[9]; - -void main(void) -{ - vec4 sample[9]; - - for (int i = 0; i < 9; i++) - { - sample[i] = texture2D(bgl_RenderedTexture, - gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); - } - - gl_FragColor = (sample[4] * 8.0) - - (sample[0] + sample[1] + sample[2] + - sample[3] + sample[5] + - sample[6] + sample[7] + sample[8]); - gl_FragColor = vec4(gl_FragColor.rgb, 1.0); -} -); -#endif diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Prewitt2DFilter.glsl b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Prewitt2DFilter.glsl new file mode 100644 index 000000000000..5fd2f52ef8ef --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Prewitt2DFilter.glsl @@ -0,0 +1,24 @@ +uniform sampler2D bgl_RenderedTexture; +uniform vec2 bgl_TextureCoordinateOffset[9]; + +void main(void) +{ + vec4 samples[9]; + + for (int i = 0; i < 9; i++) + { + samples[i] = texture2D(bgl_RenderedTexture, + gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); + } + + vec4 horizEdge = samples[2] + samples[5] + samples[8] - + (samples[0] + samples[3] + samples[6]); + + vec4 vertEdge = samples[0] + samples[1] + samples[2] - + (samples[6] + samples[7] + samples[8]); + + gl_FragColor.rgb = sqrt((horizEdge.rgb * horizEdge.rgb) + + (vertEdge.rgb * vertEdge.rgb)); + gl_FragColor.a = 1.0; +} + diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Prewitt2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Prewitt2DFilter.h deleted file mode 100644 index 10bb2796240d..000000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Prewitt2DFilter.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file RAS_Prewitt2DFilter.h - * \ingroup bgerastoglfilters - */ - -#ifndef __RAS_PREWITT2DFILTER_H__ -#define __RAS_PREWITT2DFILTER_H__ - -static const char *PrewittFragmentShader = STRINGIFY( -uniform sampler2D bgl_RenderedTexture; -uniform vec2 bgl_TextureCoordinateOffset[9]; - -void main(void) -{ - vec4 sample[9]; - - for (int i = 0; i < 9; i++) - { - sample[i] = texture2D(bgl_RenderedTexture, - gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); - } - - vec4 horizEdge = sample[2] + sample[5] + sample[8] - - (sample[0] + sample[3] + sample[6]); - - vec4 vertEdge = sample[0] + sample[1] + sample[2] - - (sample[6] + sample[7] + sample[8]); - - gl_FragColor.rgb = sqrt((horizEdge.rgb * horizEdge.rgb) + - (vertEdge.rgb * vertEdge.rgb)); - gl_FragColor.a = 1.0; -} - -); -#endif diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sepia2DFilter.glsl b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sepia2DFilter.glsl new file mode 100644 index 000000000000..0ded834855b2 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sepia2DFilter.glsl @@ -0,0 +1,8 @@ +uniform sampler2D bgl_RenderedTexture; + +void main(void) +{ + vec4 texcolor = texture2D(bgl_RenderedTexture, gl_TexCoord[0].st); + float gray = dot(texcolor.rgb, vec3(0.299, 0.587, 0.114)); + gl_FragColor = vec4(gray * vec3(1.2, 1.0, 0.8), texcolor.a); +} diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sepia2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sepia2DFilter.h deleted file mode 100644 index 1aad0ddea6b3..000000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sepia2DFilter.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file RAS_Sepia2DFilter.h - * \ingroup bgerastoglfilters - */ - -#ifndef __RAS_SEPIA2DFILTER_H__ -#define __RAS_SEPIA2DFILTER_H__ - -static const char *SepiaFragmentShader = STRINGIFY( -uniform sampler2D bgl_RenderedTexture; - -void main(void) -{ - vec4 texcolor = texture2D(bgl_RenderedTexture, gl_TexCoord[0].st); - float gray = dot(texcolor.rgb, vec3(0.299, 0.587, 0.114)); - gl_FragColor = vec4(gray * vec3(1.2, 1.0, 0.8), texcolor.a); -} -); -#endif diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sharpen2DFilter.glsl b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sharpen2DFilter.glsl new file mode 100644 index 000000000000..22bd56fdc371 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sharpen2DFilter.glsl @@ -0,0 +1,18 @@ +uniform sampler2D bgl_RenderedTexture; +uniform vec2 bgl_TextureCoordinateOffset[9]; + +void main(void) +{ + vec4 samples[9]; + + for (int i = 0; i < 9; i++) + { + samples[i] = texture2D(bgl_RenderedTexture, + gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); + } + + gl_FragColor = (samples[4] * 9.0) - + (samples[0] + samples[1] + samples[2] + + samples[3] + samples[5] + + samples[6] + samples[7] + samples[8]); +} diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sharpen2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sharpen2DFilter.h deleted file mode 100644 index 7512393815b0..000000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sharpen2DFilter.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file RAS_Sharpen2DFilter.h - * \ingroup bgerastoglfilters - */ - -#ifndef __RAS_SHARPEN2DFILTER_H__ -#define __RAS_SHARPEN2DFILTER_H__ - -static const char *SharpenFragmentShader = STRINGIFY( -uniform sampler2D bgl_RenderedTexture; -uniform vec2 bgl_TextureCoordinateOffset[9]; - -void main(void) -{ - vec4 sample[9]; - - for (int i = 0; i < 9; i++) - { - sample[i] = texture2D(bgl_RenderedTexture, - gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); - } - - gl_FragColor = (sample[4] * 9.0) - - (sample[0] + sample[1] + sample[2] + - sample[3] + sample[5] + - sample[6] + sample[7] + sample[8]); -} -); -#endif diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sobel2DFilter.glsl b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sobel2DFilter.glsl new file mode 100644 index 000000000000..5520ef4f97ff --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sobel2DFilter.glsl @@ -0,0 +1,24 @@ +uniform sampler2D bgl_RenderedTexture; +uniform vec2 bgl_TextureCoordinateOffset[9]; + +void main(void) +{ + vec4 samples[9]; + + for (int i = 0; i < 9; i++) + { + samples[i] = texture2D(bgl_RenderedTexture, + gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); + } + + vec4 horizEdge = samples[2] + (2.0*samples[5]) + samples[8] - + (samples[0] + (2.0*samples[3]) + samples[6]); + + vec4 vertEdge = samples[0] + (2.0*samples[1]) + samples[2] - + (samples[6] + (2.0*samples[7]) + samples[8]); + + gl_FragColor.rgb = sqrt((horizEdge.rgb * horizEdge.rgb) + + (vertEdge.rgb * vertEdge.rgb)); + gl_FragColor.a = 1.0; +} + diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sobel2DFilter.h b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sobel2DFilter.h deleted file mode 100644 index ca35b9454883..000000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_Sobel2DFilter.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file RAS_Sobel2DFilter.h - * \ingroup bgerastoglfilters - */ - -#ifndef __RAS_SOBEL2DFILTER_H__ -#define __RAS_SOBEL2DFILTER_H__ - -static const char *SobelFragmentShader = STRINGIFY( -uniform sampler2D bgl_RenderedTexture; -uniform vec2 bgl_TextureCoordinateOffset[9]; - -void main(void) -{ - vec4 sample[9]; - - for (int i = 0; i < 9; i++) - { - sample[i] = texture2D(bgl_RenderedTexture, - gl_TexCoord[0].st + bgl_TextureCoordinateOffset[i]); - } - - vec4 horizEdge = sample[2] + (2.0*sample[5]) + sample[8] - - (sample[0] + (2.0*sample[3]) + sample[6]); - - vec4 vertEdge = sample[0] + (2.0*sample[1]) + sample[2] - - (sample[6] + (2.0*sample[7]) + sample[8]); - - gl_FragColor.rgb = sqrt((horizEdge.rgb * horizEdge.rgb) + - (vertEdge.rgb * vertEdge.rgb)); - gl_FragColor.a = 1.0; -} -); -#endif diff --git a/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_VertexShader2DFilter.glsl b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_VertexShader2DFilter.glsl new file mode 100644 index 000000000000..0305b63cd377 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OpenGLFilters/RAS_VertexShader2DFilter.glsl @@ -0,0 +1,6 @@ +void main(void) +{ + gl_Position = gl_Vertex; + gl_TexCoord[0] = gl_MultiTexCoord0; +} + diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt index 89e31b62b414..017cfb07eca7 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt @@ -25,12 +25,15 @@ set(INC .. + ../Node # XXX Remove these <<< ../../BlenderRoutines + ../../Common + ../../Converter ../../Expressions ../../GameLogic ../../Ketsji - ../../Physics/common + ../../Physics/Common # >>> ../../SceneGraph ../../../blender/blenfont @@ -38,33 +41,33 @@ set(INC ../../../blender/blenlib ../../../blender/gpu ../../../blender/makesdna - ../../../../intern/container ../../../../intern/glew-mx - ../../../../intern/string + ../../../../intern/guardedalloc ) set(INC_SYS - ../../../../intern/moto/include + ../../../intern/debugbreak + ../../../../intern/mathfu ${GLEW_INCLUDE_PATH} + ${BOOST_INCLUDE_DIR} ) set(SRC - RAS_ListRasterizer.cpp + RAS_OpenGLDebugDraw.cpp RAS_OpenGLLight.cpp - RAS_OpenGLOffScreen.cpp + RAS_OpenGLQuery.cpp RAS_OpenGLSync.cpp RAS_OpenGLRasterizer.cpp - RAS_StorageVA.cpp - RAS_StorageVBO.cpp + RAS_StorageVao.cpp + RAS_StorageVbo.cpp - RAS_IStorage.h - RAS_ListRasterizer.h + RAS_OpenGLDebugDraw.h RAS_OpenGLLight.h - RAS_OpenGLOffScreen.h + RAS_OpenGLQuery.h RAS_OpenGLSync.h RAS_OpenGLRasterizer.h - RAS_StorageVA.h - RAS_StorageVBO.h + RAS_StorageVao.h + RAS_StorageVbo.h ) add_definitions(${GL_DEFINITIONS}) diff --git a/source/gameengine/Ketsji/KX_ScalarInterpolator.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.h similarity index 72% rename from source/gameengine/Ketsji/KX_ScalarInterpolator.cpp rename to source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.h index e234a9621b80..918b84ab4a64 100644 --- a/source/gameengine/Ketsji/KX_ScalarInterpolator.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.h @@ -25,15 +25,19 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file gameengine/Ketsji/KX_ScalarInterpolator.cpp - * \ingroup ketsji +/** \file RAS_GLExtensionManager.h + * \ingroup bgerastogl */ +#ifndef __RAS_GLEXTENSIONMANAGER_H__ +#define __RAS_GLEXTENSIONMANAGER_H__ -#include "KX_ScalarInterpolator.h" -#include "KX_IScalarInterpolator.h" +/** Note: this used to have a lot more code, but now extension handling + * is done by GLEW, so it does mostly debug stuff */ -void KX_ScalarInterpolator::Execute(float currentTime) const +namespace bgl { - *m_target = m_ipo->GetValue(currentTime); -} + void InitExtensions(bool debug); +} // namespace bgl + +#endif /* __RAS_GLEXTENSIONMANAGER_H__ */ diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_IStorage.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_IStorage.h deleted file mode 100644 index ae0cdcd84afb..000000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_IStorage.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef __KX_STORAGE -#define __KX_STORAGE - -#ifdef WITH_CXX_GUARDEDALLOC - #include "MEM_guardedalloc.h" -#endif - -class RAS_MeshSlot; - -class RAS_IStorage -{ - -public: - virtual ~RAS_IStorage() {}; - - virtual bool Init()=0; - virtual void Exit()=0; - - virtual void IndexPrimitives(RAS_MeshSlot& ms)=0; - - virtual void SetDrawingMode(int drawingmode)=0; - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_IStorage") -#endif -}; - -#endif //__KX_STORAGE diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp deleted file mode 100644 index 3afb94413bcc..000000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp +++ /dev/null @@ -1,278 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp - * \ingroup bgerastogl - */ - -#include - -#include "RAS_ListRasterizer.h" - -#ifdef WIN32 -#include -#endif // WIN32 - -#include "GPU_glew.h" - -#include "RAS_MaterialBucket.h" -#include "RAS_TexVert.h" -#include "MT_assert.h" - -//#if defined(DEBUG) -//#ifdef WIN32 -//#define spit(x) std::cout << x << std::endl; -//#endif //WIN32 -//#else -#define spit(x) -//#endif - -RAS_ListSlot::RAS_ListSlot(RAS_ListRasterizer* rasty) -: KX_ListSlot(), - m_list(0), - m_flag(LIST_MODIFY|LIST_CREATE), - m_matnr(0), - m_rasty(rasty) -{ -} - -int RAS_ListSlot::Release() -{ - if (--m_refcount > 0) - return m_refcount; - m_rasty->RemoveListSlot(this); - delete this; - return 0; -} - -RAS_ListSlot::~RAS_ListSlot() -{ - RemoveList(); -} - - -void RAS_ListSlot::RemoveList() -{ - if (m_list != 0) { - spit("Releasing display list (" << m_list << ")"); - glDeleteLists((GLuint)m_list, 1); - m_list =0; - } -} - -void RAS_ListSlot::DrawList() -{ - if (m_flag &LIST_MODIFY) { - if (m_flag &LIST_CREATE) { - if (m_list == 0) { - m_list = (unsigned int)glGenLists(1); - m_flag = m_flag &~ LIST_CREATE; - spit("Created display list (" << m_list << ")"); - } - } - if (m_list != 0) - glNewList((GLuint)m_list, GL_COMPILE); - - m_flag |= LIST_BEGIN; - return; - } - glCallList(m_list); -} - -void RAS_ListSlot::EndList() -{ - if (m_flag & LIST_BEGIN) { - glEndList(); - m_flag = m_flag &~(LIST_BEGIN|LIST_MODIFY); - m_flag |= LIST_END; - glCallList(m_list); - } -} - -void RAS_ListSlot::SetModified(bool mod) -{ - if (mod && !(m_flag & LIST_MODIFY)) { - spit("Modifying list (" << m_list << ")"); - m_flag = m_flag &~ LIST_END; - m_flag |= LIST_MODIFY; - } -} - -bool RAS_ListSlot::End() -{ - return (m_flag &LIST_END)!=0; -} - - - -RAS_ListRasterizer::RAS_ListRasterizer(RAS_ICanvas* canvas, bool lock, RAS_STORAGE_TYPE storage) -: RAS_OpenGLRasterizer(canvas, storage) -{ -} - -RAS_ListRasterizer::~RAS_ListRasterizer() -{ - ReleaseAlloc(); -} - -void RAS_ListRasterizer::RemoveListSlot(RAS_ListSlot* list) -{ - if (list->m_flag & LIST_DERIVEDMESH) { - RAS_DerivedMeshLists::iterator it = mDerivedMeshLists.begin(); - while (it != mDerivedMeshLists.end()) { - RAS_ListSlots *slots = it->second; - if (slots->size() > list->m_matnr && slots->at(list->m_matnr) == list) { - (*slots)[list->m_matnr] = NULL; - // check if all slots are NULL and if yes, delete the entry - int i; - for (i=slots->size(); i-- > 0; ) { - if (slots->at(i) != NULL) - break; - } - if (i < 0) { - slots->clear(); - delete slots; - mDerivedMeshLists.erase(it); - } - break; - } - ++it; - } - } else { - RAS_ArrayLists::iterator it = mArrayLists.begin(); - while (it != mArrayLists.end()) { - if (it->second == list) { - mArrayLists.erase(it); - break; - } - it++; - } - } -} - -RAS_ListSlot* RAS_ListRasterizer::FindOrAdd(RAS_MeshSlot& ms) -{ - /* - * Keep a copy of constant lists submitted for rendering, - * this guards against (replicated)new...delete every frame, - * and we can reuse lists! - * :: sorted by mesh slot - */ - RAS_ListSlot* localSlot = (RAS_ListSlot*)ms.m_DisplayList; - if (!localSlot) { - if (ms.m_pDerivedMesh) { - // that means that we draw based on derived mesh, a display list is possible - // Note that we come here only for static derived mesh - int matnr = ms.m_bucket->GetPolyMaterial()->GetMaterialIndex(); - RAS_ListSlot* nullSlot = NULL; - RAS_ListSlots *listVector; - RAS_DerivedMeshLists::iterator it = mDerivedMeshLists.find(ms.m_pDerivedMesh); - if (it == mDerivedMeshLists.end()) { - listVector = new RAS_ListSlots(matnr+4, nullSlot); - localSlot = new RAS_ListSlot(this); - localSlot->m_flag |= LIST_DERIVEDMESH; - localSlot->m_matnr = matnr; - listVector->at(matnr) = localSlot; - mDerivedMeshLists.insert(std::pair(ms.m_pDerivedMesh, listVector)); - } else { - listVector = it->second; - if (listVector->size() <= matnr) - listVector->resize(matnr+4, nullSlot); - if ((localSlot = listVector->at(matnr)) == NULL) { - localSlot = new RAS_ListSlot(this); - localSlot->m_flag |= LIST_DERIVEDMESH; - localSlot->m_matnr = matnr; - listVector->at(matnr) = localSlot; - } else { - localSlot->AddRef(); - } - } - } else { - RAS_ArrayLists::iterator it = mArrayLists.find(ms.m_displayArrays); - if (it == mArrayLists.end()) { - localSlot = new RAS_ListSlot(this); - mArrayLists.insert(std::pair(ms.m_displayArrays, localSlot)); - } else { - localSlot = static_cast(it->second->AddRef()); - } - } - } - MT_assert(localSlot); - return localSlot; -} - -void RAS_ListRasterizer::ReleaseAlloc() -{ - for (RAS_ArrayLists::iterator it = mArrayLists.begin();it != mArrayLists.end();++it) - delete it->second; - mArrayLists.clear(); - for (RAS_DerivedMeshLists::iterator it = mDerivedMeshLists.begin();it != mDerivedMeshLists.end();++it) { - RAS_ListSlots* slots = it->second; - for (int i=slots->size(); i-- > 0; ) { - RAS_ListSlot* slot = slots->at(i); - if (slot) - delete slot; - } - slots->clear(); - delete slots; - } - mDerivedMeshLists.clear(); -} - -void RAS_ListRasterizer::IndexPrimitives(RAS_MeshSlot& ms) -{ - RAS_ListSlot* localSlot =0; - - if (ms.m_bDisplayList) { - localSlot = FindOrAdd(ms); - localSlot->DrawList(); - - if (localSlot->End()) { - // save slot here too, needed for replicas and object using same mesh - // => they have the same vertexarray but different mesh slot - ms.m_DisplayList = localSlot; - return; - } - } - - RAS_OpenGLRasterizer::IndexPrimitives(ms); - - if (ms.m_bDisplayList) { - localSlot->EndList(); - ms.m_DisplayList = localSlot; - } -} - -bool RAS_ListRasterizer::Init(void) -{ - return RAS_OpenGLRasterizer::Init(); -} - -void RAS_ListRasterizer::SetDrawingMode(int drawingmode) -{ - RAS_OpenGLRasterizer::SetDrawingMode(drawingmode); -} - -void RAS_ListRasterizer::Exit() -{ - RAS_OpenGLRasterizer::Exit(); -} - -// eof diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h deleted file mode 100644 index e3e6931311b6..000000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.h +++ /dev/null @@ -1,77 +0,0 @@ - -/** \file RAS_ListRasterizer.h - * \ingroup bgerastogl - */ - -#ifndef __RAS_LISTRASTERIZER_H__ -#define __RAS_LISTRASTERIZER_H__ - -#include "RAS_MaterialBucket.h" -#include "RAS_OpenGLRasterizer.h" -#include -#include - -class RAS_ListRasterizer; -class RAS_ListSlot : public KX_ListSlot -{ - friend class RAS_ListRasterizer; - unsigned int m_list; - unsigned int m_flag; - unsigned int m_matnr; - RAS_ListRasterizer* m_rasty; -public: - RAS_ListSlot(RAS_ListRasterizer* rasty); - virtual ~RAS_ListSlot(); - virtual void SetModified(bool mod); - virtual int Release(); - - void RemoveList(); - void DrawList(); - void EndList(); - bool End(); - -}; - -enum RAS_ListSlotFlags { - LIST_CREATE =1, - LIST_MODIFY =2, - LIST_BEGIN =4, - LIST_END =8, - LIST_DERIVEDMESH=16, -}; - -struct DerivedMesh; - -typedef std::map RAS_ArrayLists; -typedef std::vector RAS_ListSlots; // indexed by material slot number -typedef std::map RAS_DerivedMeshLists; - -class RAS_ListRasterizer : public RAS_OpenGLRasterizer -{ - RAS_ArrayLists mArrayLists; - RAS_DerivedMeshLists mDerivedMeshLists; - - RAS_ListSlot* FindOrAdd(class RAS_MeshSlot& ms); - void ReleaseAlloc(); - -public: - void RemoveListSlot(RAS_ListSlot* list); - RAS_ListRasterizer(RAS_ICanvas* canvas, bool lock, RAS_STORAGE_TYPE storage); - virtual ~RAS_ListRasterizer(); - - virtual void IndexPrimitives(class RAS_MeshSlot& ms); - - virtual bool Init(); - virtual void Exit(); - - virtual void SetDrawingMode(int drawingmode); - - virtual bool QueryLists() {return true;} - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_ListRasterizer") -#endif -}; - -#endif diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLDebugDraw.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLDebugDraw.cpp new file mode 100644 index 000000000000..f5a609410539 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLDebugDraw.cpp @@ -0,0 +1,296 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLDebugDraw.cpp + * \ingroup bgerastogl + */ + +#include "RAS_OpenGLDebugDraw.h" +#include "RAS_Rasterizer.h" +#include "RAS_ICanvas.h" +#include "RAS_DebugDraw.h" + +#include "GPU_material.h" +#include "GPU_glew.h" +#include "GPU_shader.h" + +extern "C" { +# include "BLF_api.h" +} + +template +inline static void updateVbo(unsigned int vbo, const std::vector& data) +{ + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(Item) * data.size(), data.data(), GL_STATIC_DRAW); +} + +inline static void attribVector(unsigned short loc, unsigned short stride, intptr_t offset, unsigned short size, unsigned short divisor) +{ + glEnableVertexAttribArray(loc); + glVertexAttribPointer(loc, size, GL_FLOAT, false, stride, (const void *)offset); + glVertexAttribDivisorARB(loc, divisor); +} + +inline static void attribMatrix(unsigned short loc, unsigned short stride, intptr_t offset, unsigned short size, unsigned short divisor) +{ + for (unsigned short i = 0; i < size; ++i) { + glEnableVertexAttribArray(loc + i); + glVertexAttribPointer(loc + i, size, GL_FLOAT, false, stride, (const void *)(offset + size * i * sizeof(float))); + glVertexAttribDivisorARB(loc + i, divisor); + } +} + +RAS_OpenGLDebugDraw::RAS_OpenGLDebugDraw() +{ + static const GLubyte boxIndices[] = { + 0, 1, 1, 2, 2, 3, 3, 0, 0, 4, 4, 5, 5, 6, 6, 7, 7, 4, 1, 5, 2, 6, 3, 7, // Wire (24). + 0, 1, 2, 2, 3, 0, 1, 5, 6, 6, 2, 1, 7, 6, 5, 5, 4, 7, 4, 0, 3, 3, 7, 4, 4, 5, 1, 1, 0, 4, 3, 2, 6, 6, 7, 3 // Solid (36). + }; + + static const float unitBoxVertices[24] = { + -1.0f, -1.0f, -1.0f, + 1.0f, -1.0f, -1.0f, + 1.0f, 1.0f, -1.0f, + -1.0f, 1.0f, -1.0f, + -1.0f, -1.0f, 1.0f, + 1.0f, -1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 1.0f + }; + + static const float unitBox2DVertices[8] = { + 0.0f, 0.0f, + 1.0f, 0.0f, + 1.0f, 1.0f, + 0.0f, 1.0f + }; + + glGenBuffers(MAX_IBO, m_ibos); + glGenBuffers(MAX_VBO, m_vbos); + + // Initialize static IBOs and VBOs. + glBindBuffer(GL_ARRAY_BUFFER, m_ibos[BOX_IBO]); + glBufferData(GL_ARRAY_BUFFER, sizeof(boxIndices), (void *)boxIndices, GL_STATIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, m_vbos[BOX_UNIT_VBO]); + glBufferData(GL_ARRAY_BUFFER, sizeof(unitBoxVertices), (void *)unitBoxVertices, GL_STATIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, m_vbos[BOX_2D_UNIT_VBO]); + glBufferData(GL_ARRAY_BUFFER, sizeof(unitBox2DVertices), (void *)unitBox2DVertices, GL_STATIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + + m_colorShader = GPU_shader_get_builtin_shader(GPU_SHADER_FLAT_COLOR); + m_frustumLineShader = GPU_shader_get_builtin_shader(GPU_SHADER_FRUSTUM_LINE); + m_frustumSolidShader = GPU_shader_get_builtin_shader(GPU_SHADER_FRUSTUM_SOLID); + m_box2dShader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_BOX); + + glGenVertexArrays(MAX_VAO, m_vaos); + + glBindVertexArray(m_vaos[LINES_VAO]); + { + static const unsigned short stride = sizeof(RAS_DebugDraw::Line) / 2; + const unsigned int pos = GPU_shader_get_attribute(m_colorShader, "pos"); + const unsigned int color = GPU_shader_get_attribute(m_colorShader, "color"); + + glBindBuffer(GL_ARRAY_BUFFER, m_vbos[LINES_VBO]); + attribVector(pos, stride, offsetof(RAS_DebugDraw::Line, m_from), 3, 0); + attribVector(color, stride, offsetof(RAS_DebugDraw::Line, m_color), 4, 0); + } + + static const unsigned short frustumStride = sizeof(RAS_DebugDraw::Frustum); + + glBindVertexArray(m_vaos[FRUSTUMS_LINE_VAO]); + { + const unsigned short pos = GPU_shader_get_attribute(m_frustumLineShader, "pos"); + const unsigned short mat = GPU_shader_get_attribute(m_frustumLineShader, "mat"); + const unsigned short color = GPU_shader_get_attribute(m_frustumLineShader, "color"); + + glBindBuffer(GL_ARRAY_BUFFER, m_vbos[BOX_UNIT_VBO]); + attribVector(pos, 0, 0, 3, 0); + + glBindBuffer(GL_ARRAY_BUFFER, m_vbos[FRUSTUMS_VBO]); + attribVector(color, frustumStride, offsetof(RAS_DebugDraw::Frustum, m_wireColor), 4, 1); + attribMatrix(mat, frustumStride, offsetof(RAS_DebugDraw::Frustum, m_persMat), 4, 1); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibos[BOX_IBO]); + } + + glBindVertexArray(m_vaos[FRUSTUMS_SOLID_VAO]); + { + const unsigned short pos = GPU_shader_get_attribute(m_frustumSolidShader, "pos"); + const unsigned short mat = GPU_shader_get_attribute(m_frustumSolidShader, "mat"); + const unsigned short insideColor = GPU_shader_get_attribute(m_frustumSolidShader, "insideColor"); + const unsigned short outsideColor = GPU_shader_get_attribute(m_frustumSolidShader, "outsideColor"); + + glBindBuffer(GL_ARRAY_BUFFER, m_vbos[BOX_UNIT_VBO]); + attribVector(pos, 0, 0, 3, 0); + + glBindBuffer(GL_ARRAY_BUFFER, m_vbos[FRUSTUMS_VBO]); + attribVector(insideColor, frustumStride, offsetof(RAS_DebugDraw::Frustum, m_insideColor), 4, 1); + attribVector(outsideColor, frustumStride, offsetof(RAS_DebugDraw::Frustum, m_outsideColor), 4, 1); + attribMatrix(mat, frustumStride, offsetof(RAS_DebugDraw::Frustum, m_persMat), 4, 1); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibos[BOX_IBO]); + } + + glBindVertexArray(m_vaos[AABB_VAO]); + { + static const unsigned short stride = sizeof(RAS_DebugDraw::Aabb); + const unsigned short pos = GPU_shader_get_attribute(m_frustumLineShader, "pos"); + const unsigned short mat = GPU_shader_get_attribute(m_frustumLineShader, "mat"); + const unsigned short color = GPU_shader_get_attribute(m_frustumLineShader, "color"); + + glBindBuffer(GL_ARRAY_BUFFER, m_vbos[BOX_UNIT_VBO]); + attribVector(pos, 0, 0, 3, 0); + + glBindBuffer(GL_ARRAY_BUFFER, m_vbos[AABB_VBO]); + attribVector(color, stride, offsetof(RAS_DebugDraw::Aabb, m_color), 4, 1); + attribMatrix(mat, stride, offsetof(RAS_DebugDraw::Aabb, m_mat), 4, 1); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibos[BOX_IBO]); + } + + glBindVertexArray(m_vaos[BOX_2D_VAO]); + { + static const unsigned short stride = sizeof(RAS_DebugDraw::Box2d); + const unsigned short pos = GPU_shader_get_attribute(m_box2dShader, "pos"); + const unsigned short trans = GPU_shader_get_attribute(m_box2dShader, "trans"); + const unsigned short color = GPU_shader_get_attribute(m_box2dShader, "color"); + + glBindBuffer(GL_ARRAY_BUFFER, m_vbos[BOX_2D_UNIT_VBO]); + attribVector(pos, 0, 0, 2, 0); + + glBindBuffer(GL_ARRAY_BUFFER, m_vbos[BOX_2D_VBO]); + attribVector(color, stride, offsetof(RAS_DebugDraw::Box2d, m_color), 4, 1); + attribVector(trans, stride, offsetof(RAS_DebugDraw::Box2d, m_trans), 4, 1); + } + + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +RAS_OpenGLDebugDraw::~RAS_OpenGLDebugDraw() +{ + glDeleteBuffers(MAX_IBO, m_ibos); + glDeleteBuffers(MAX_VBO, m_vbos); + glDeleteVertexArrays(MAX_VAO, m_vaos); +} + +void RAS_OpenGLDebugDraw::Flush(RAS_Rasterizer *rasty, RAS_ICanvas *canvas, RAS_DebugDraw *debugDraw) +{ + rasty->SetFrontFace(true); + rasty->SetAlphaBlend(GPU_BLEND_ALPHA); + rasty->DisableLights(); + + // draw lines + const std::vector& lines = debugDraw->m_lines; + const unsigned int numlines = lines.size(); + if (numlines > 0) { + updateVbo(m_vbos[LINES_VBO], lines); + + glBindVertexArray(m_vaos[LINES_VAO]); + GPU_shader_bind(m_colorShader); + glDrawArrays(GL_LINES, 0, numlines * 2); + } + + const std::vector& frustums = debugDraw->m_frustums; + const unsigned int numfrustums = frustums.size(); + if (numfrustums > 0) { + updateVbo(m_vbos[FRUSTUMS_VBO], frustums); + + glBindVertexArray(m_vaos[FRUSTUMS_LINE_VAO]); + GPU_shader_bind(m_frustumLineShader); + glDrawElementsInstancedARB(GL_LINES, 24, GL_UNSIGNED_BYTE, nullptr, numfrustums); + + glBindVertexArray(m_vaos[FRUSTUMS_SOLID_VAO]); + GPU_shader_bind(m_frustumSolidShader); + glDrawElementsInstancedARB(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, (const void *)(sizeof(GLubyte) * 24), numfrustums); + } + + const std::vector& aabbs = debugDraw->m_aabbs; + const unsigned int numaabbs = aabbs.size(); + if (numaabbs > 0) { + updateVbo(m_vbos[AABB_VBO], aabbs); + + glBindVertexArray(m_vaos[AABB_VAO]); + GPU_shader_bind(m_frustumLineShader); + glDrawElementsInstancedARB(GL_LINES, 24, GL_UNSIGNED_BYTE, nullptr, numaabbs); + } + + const unsigned int width = canvas->GetWidth(); + const unsigned int height = canvas->GetHeight(); + + rasty->Disable(RAS_Rasterizer::RAS_DEPTH_TEST); + rasty->DisableForText(); + + rasty->PushMatrix(); + rasty->LoadIdentity(); + + rasty->SetMatrixMode(RAS_Rasterizer::RAS_PROJECTION); + rasty->PushMatrix(); + rasty->LoadIdentity(); + + glOrtho(0, width, height, 0, -100, 100); + + const std::vector& boxes2d = debugDraw->m_boxes2d; + const unsigned int numboxes = boxes2d.size(); + if (numboxes > 0) { + updateVbo(m_vbos[BOX_2D_VBO], boxes2d); + + glBindVertexArray(m_vaos[BOX_2D_VAO]); + GPU_shader_bind(m_box2dShader); + glDrawArraysInstancedARB(GL_TRIANGLE_FAN, 0, 4, numboxes); + } + + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + GPU_shader_unbind(); + + rasty->LoadIdentity(); + + glOrtho(0, width, 0, height, -100, 100); + + BLF_size(blf_mono_font, 11, 72); + + BLF_enable(blf_mono_font, BLF_SHADOW); + static float black[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + BLF_shadow(blf_mono_font, 1, black); + BLF_shadow_offset(blf_mono_font, 1, 1); + + for (const RAS_DebugDraw::Text2d& text2d : debugDraw->m_texts2d) { + const std::string& text = text2d.m_text; + const float xco = text2d.m_pos[0]; + const float yco = height - text2d.m_pos[1]; + + glColor4fv(text2d.m_color); + BLF_position(blf_mono_font, xco, yco, 0.0f); + BLF_draw(blf_mono_font, text.c_str(), text.size()); + } + BLF_disable(blf_mono_font, BLF_SHADOW); + + rasty->PopMatrix(); + rasty->SetMatrixMode(RAS_Rasterizer::RAS_MODELVIEW); + + rasty->PopMatrix(); +} diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLDebugDraw.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLDebugDraw.h new file mode 100644 index 000000000000..0d1e3f869f35 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLDebugDraw.h @@ -0,0 +1,79 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_OpenGLDebugDraw.h + * \ingroup bgerastogl + */ + +#ifndef __RAS_OPEN_GL_DEBUG_DRAW_H__ +#define __RAS_OPEN_GL_DEBUG_DRAW_H__ + +class RAS_Rasterizer; +class RAS_ICanvas; +class RAS_DebugDraw; +struct GPUShader; + +class RAS_OpenGLDebugDraw +{ +private: + enum IboType { + BOX_IBO = 0, + MAX_IBO + }; + + enum VboType { + BOX_UNIT_VBO = 0, + BOX_2D_UNIT_VBO, + LINES_VBO, + BOX_VBO, + BOX_2D_VBO, + AABB_VBO, + FRUSTUMS_VBO, + MAX_VBO + }; + + enum VaoType { + LINES_VAO = 0, + FRUSTUMS_LINE_VAO, + FRUSTUMS_SOLID_VAO, + AABB_VAO, + BOX_2D_VAO, + MAX_VAO + }; + + unsigned int m_ibos[MAX_IBO]; + unsigned int m_vbos[MAX_VBO]; + unsigned int m_vaos[MAX_VAO]; + + GPUShader *m_colorShader; + GPUShader *m_frustumLineShader; + GPUShader *m_frustumSolidShader; + GPUShader *m_box2dShader; + +public: + RAS_OpenGLDebugDraw(); + ~RAS_OpenGLDebugDraw(); + + void Flush(RAS_Rasterizer *rasty, RAS_ICanvas *canvas, RAS_DebugDraw *debugDraw); +}; + +#endif // __RAS_OPEN_GL_DEBUG_DRAW_H__ diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp index cc343916b90d..c6dd5e201e85 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp @@ -31,13 +31,11 @@ #include "RAS_OpenGLLight.h" -#include "RAS_OpenGLRasterizer.h" +#include "RAS_Rasterizer.h" #include "RAS_ICanvas.h" -#include "MT_CmMatrix4x4.h" - #include "KX_Camera.h" -#include "KX_Light.h" +#include "KX_LightObject.h" #include "KX_Scene.h" #include "DNA_lamp_types.h" @@ -45,16 +43,16 @@ #include "GPU_material.h" -RAS_OpenGLLight::RAS_OpenGLLight(RAS_OpenGLRasterizer *ras) - :m_rasterizer(ras) +RAS_OpenGLLight::RAS_OpenGLLight(RAS_Rasterizer *ras) + :m_rasterizer(ras) { } RAS_OpenGLLight::~RAS_OpenGLLight() { GPULamp *lamp; - KX_LightObject* kxlight = (KX_LightObject*)m_light; - Lamp *la = (Lamp*)kxlight->GetBlenderObject()->data; + KX_LightObject *kxlight = (KX_LightObject *)m_light; + Lamp *la = (Lamp *)kxlight->GetBlenderObject()->data; if ((lamp = GetGPULamp())) { float obmat[4][4] = {{0}}; @@ -66,65 +64,65 @@ RAS_OpenGLLight::~RAS_OpenGLLight() bool RAS_OpenGLLight::ApplyFixedFunctionLighting(KX_Scene *kxscene, int oblayer, int slot) { - KX_Scene* lightscene = (KX_Scene*)m_scene; - KX_LightObject* kxlight = (KX_LightObject*)m_light; + KX_Scene *lightscene = (KX_Scene *)m_scene; + KX_LightObject *kxlight = (KX_LightObject *)m_light; float vec[4]; int scenelayer = ~0; - if (kxscene && kxscene->GetBlenderScene()) + if (kxscene && kxscene->GetBlenderScene()) { scenelayer = kxscene->GetBlenderScene()->lay; + } /* only use lights in the same layer as the object */ - if (!(m_layer & oblayer)) + if (!(m_layer & oblayer)) { return false; + } /* only use lights in the same scene, and in a visible layer */ - if (kxscene != lightscene || !(m_layer & scenelayer)) + if (kxscene != lightscene || !(m_layer & scenelayer)) { return false; + } - // lights don't get their openGL matrix updated, do it now - if (kxlight->GetSGNode()->IsDirty()) - kxlight->GetOpenGLMatrix(); + const mt::mat4 worldmatrix = mt::mat4::FromAffineTransform(kxlight->NodeGetWorldTransform()); - MT_CmMatrix4x4& worldmatrix= *kxlight->GetOpenGLMatrixPtr(); - vec[0] = worldmatrix(0,3); - vec[1] = worldmatrix(1,3); - vec[2] = worldmatrix(2,3); + vec[0] = worldmatrix(0, 3); + vec[1] = worldmatrix(1, 3); + vec[2] = worldmatrix(2, 3); vec[3] = 1.0f; - if (m_type==RAS_ILightObject::LIGHT_SUN) { + if (m_type == RAS_ILightObject::LIGHT_SUN) { - vec[0] = worldmatrix(0,2); - vec[1] = worldmatrix(1,2); - vec[2] = worldmatrix(2,2); + vec[0] = worldmatrix(0, 2); + vec[1] = worldmatrix(1, 2); + vec[2] = worldmatrix(2, 2); //vec[0] = base->object->obmat[2][0]; //vec[1] = base->object->obmat[2][1]; //vec[2] = base->object->obmat[2][2]; vec[3] = 0.0f; - glLightfv((GLenum)(GL_LIGHT0+slot), GL_POSITION, vec); + glLightfv((GLenum)(GL_LIGHT0 + slot), GL_POSITION, vec); } else { - //vec[3] = 1.0f; - glLightfv((GLenum)(GL_LIGHT0+slot), GL_POSITION, vec); - glLightf((GLenum)(GL_LIGHT0+slot), GL_CONSTANT_ATTENUATION, 1.0f); - glLightf((GLenum)(GL_LIGHT0+slot), GL_LINEAR_ATTENUATION, m_att1/m_distance); + //vec[3] = 1.0; + glLightfv((GLenum)(GL_LIGHT0 + slot), GL_POSITION, vec); + glLightf((GLenum)(GL_LIGHT0 + slot), GL_CONSTANT_ATTENUATION, 1.0f); + glLightf((GLenum)(GL_LIGHT0 + slot), GL_LINEAR_ATTENUATION, m_att1 / m_distance); // without this next line it looks backward compatible. //attennuation still is acceptable - glLightf((GLenum)(GL_LIGHT0+slot), GL_QUADRATIC_ATTENUATION, m_att2/(m_distance*m_distance)); + glLightf((GLenum)(GL_LIGHT0 + slot), GL_QUADRATIC_ATTENUATION, m_att2 / (m_distance * m_distance)); - if (m_type==RAS_ILightObject::LIGHT_SPOT) { - vec[0] = -worldmatrix(0,2); - vec[1] = -worldmatrix(1,2); - vec[2] = -worldmatrix(2,2); + if (m_type == RAS_ILightObject::LIGHT_SPOT) { + vec[0] = -worldmatrix(0, 2); + vec[1] = -worldmatrix(1, 2); + vec[2] = -worldmatrix(2, 2); //vec[0] = -base->object->obmat[2][0]; //vec[1] = -base->object->obmat[2][1]; //vec[2] = -base->object->obmat[2][2]; - glLightfv((GLenum)(GL_LIGHT0+slot), GL_SPOT_DIRECTION, vec); - glLightf((GLenum)(GL_LIGHT0+slot), GL_SPOT_CUTOFF, m_spotsize / 2.0f); - glLightf((GLenum)(GL_LIGHT0+slot), GL_SPOT_EXPONENT, 128.0f * m_spotblend); + glLightfv((GLenum)(GL_LIGHT0 + slot), GL_SPOT_DIRECTION, vec); + glLightf((GLenum)(GL_LIGHT0 + slot), GL_SPOT_CUTOFF, m_spotsize / 2.0f); + glLightf((GLenum)(GL_LIGHT0 + slot), GL_SPOT_EXPONENT, 128.0f * m_spotblend); } else { - glLightf((GLenum)(GL_LIGHT0+slot), GL_SPOT_CUTOFF, 180.0f); + glLightf((GLenum)(GL_LIGHT0 + slot), GL_SPOT_CUTOFF, 180.0f); } } @@ -132,82 +130,111 @@ bool RAS_OpenGLLight::ApplyFixedFunctionLighting(KX_Scene *kxscene, int oblayer, vec[0] = vec[1] = vec[2] = vec[3] = 0.0f; } else { - vec[0] = m_energy*m_color[0]; - vec[1] = m_energy*m_color[1]; - vec[2] = m_energy*m_color[2]; + vec[0] = m_energy * m_color[0]; + vec[1] = m_energy * m_color[1]; + vec[2] = m_energy * m_color[2]; vec[3] = 1.0f; } - glLightfv((GLenum)(GL_LIGHT0+slot), GL_DIFFUSE, vec); - if (m_nospecular) - { + glLightfv((GLenum)(GL_LIGHT0 + slot), GL_DIFFUSE, vec); + if (m_nospecular) { vec[0] = vec[1] = vec[2] = vec[3] = 0.0f; } else if (m_nodiffuse) { - vec[0] = m_energy*m_color[0]; - vec[1] = m_energy*m_color[1]; - vec[2] = m_energy*m_color[2]; + vec[0] = m_energy * m_color[0]; + vec[1] = m_energy * m_color[1]; + vec[2] = m_energy * m_color[2]; vec[3] = 1.0f; } - glLightfv((GLenum)(GL_LIGHT0+slot), GL_SPECULAR, vec); - glEnable((GLenum)(GL_LIGHT0+slot)); + glLightfv((GLenum)(GL_LIGHT0 + slot), GL_SPECULAR, vec); + glEnable((GLenum)(GL_LIGHT0 + slot)); return true; } GPULamp *RAS_OpenGLLight::GetGPULamp() { - KX_LightObject* kxlight = (KX_LightObject*)m_light; + KX_LightObject *kxlight = (KX_LightObject *)m_light; - if (m_glsl) - return GPU_lamp_from_blender(kxlight->GetScene()->GetBlenderScene(), kxlight->GetBlenderObject(), kxlight->GetBlenderGroupObject()); - else - return NULL; + KX_GameObject *groupObj = kxlight->GetDupliGroupObject(); + Object *blenderGroup = groupObj ? groupObj->GetBlenderObject() : nullptr; + return GPU_lamp_from_blender(kxlight->GetScene()->GetBlenderScene(), kxlight->GetBlenderObject(), blenderGroup); } - bool RAS_OpenGLLight::HasShadowBuffer() { GPULamp *lamp; - if ((lamp = GetGPULamp())) + if ((lamp = GetGPULamp())) { return GPU_lamp_has_shadow_buffer(lamp); - else + } + else { return false; + } +} + + +bool RAS_OpenGLLight::NeedShadowUpdate() +{ + if (!m_staticShadow) { + return true; + } + return m_requestShadowUpdate; } int RAS_OpenGLLight::GetShadowBindCode() { GPULamp *lamp; - if ((lamp = GetGPULamp())) + if ((lamp = GetGPULamp())) { return GPU_lamp_shadow_bind_code(lamp); + } return -1; } -MT_Matrix4x4 RAS_OpenGLLight::GetShadowMatrix() +mt::mat4 RAS_OpenGLLight::GetViewMat() +{ + GPULamp *lamp = GetGPULamp(); + if (lamp) { + return mt::mat4(GPU_lamp_get_viewmat(lamp)); + } + return mt::mat4::Identity(); +} + +mt::mat4 RAS_OpenGLLight::GetWinMat() +{ + GPULamp *lamp = GetGPULamp(); + if (lamp) { + return mt::mat4(GPU_lamp_get_winmat(lamp)); + } + return mt::mat4::Identity(); +} + +mt::mat4 RAS_OpenGLLight::GetShadowMatrix() { GPULamp *lamp; - if ((lamp = GetGPULamp())) - return MT_Matrix4x4(GPU_lamp_dynpersmat(lamp)); - MT_Matrix4x4 mat; - mat.setIdentity(); - return mat; + if ((lamp = GetGPULamp())) { + return mt::mat4(GPU_lamp_dynpersmat(lamp)); + } + + return mt::mat4::Identity(); } int RAS_OpenGLLight::GetShadowLayer() { GPULamp *lamp; - if ((lamp = GetGPULamp())) + if ((lamp = GetGPULamp())) { return GPU_lamp_shadow_layer(lamp); - else + } + else { return 0; + } } -void RAS_OpenGLLight::BindShadowBuffer(RAS_ICanvas *canvas, KX_Camera *cam, MT_Transform& camtrans) +void RAS_OpenGLLight::BindShadowBuffer(RAS_ICanvas *canvas, KX_Camera *cam, mt::mat3x4& camtrans) { GPULamp *lamp; float viewmat[4][4], winmat[4][4]; @@ -217,33 +244,33 @@ void RAS_OpenGLLight::BindShadowBuffer(RAS_ICanvas *canvas, KX_Camera *cam, MT_T lamp = GetGPULamp(); GPU_lamp_shadow_buffer_bind(lamp, viewmat, &winsize, winmat); - if (GPU_lamp_shadow_buffer_type(lamp) == LA_SHADMAP_VARIANCE) - m_rasterizer->SetUsingOverrideShader(true); + if (GPU_lamp_shadow_buffer_type(lamp) == LA_SHADMAP_VARIANCE) { + m_rasterizer->SetShadowMode(RAS_Rasterizer::RAS_SHADOW_VARIANCE); + } + else { + m_rasterizer->SetShadowMode(RAS_Rasterizer::RAS_SHADOW_SIMPLE); + } /* GPU_lamp_shadow_buffer_bind() changes the viewport, so update the canvas */ canvas->UpdateViewPort(0, 0, winsize, winsize); /* setup camera transformation */ - MT_Matrix4x4 modelviewmat((float*)viewmat); - MT_Matrix4x4 projectionmat((float*)winmat); + mt::mat4 modelviewmat((float *)viewmat); + mt::mat4 projectionmat((float *)winmat); - MT_Transform trans = MT_Transform((float*)viewmat); - camtrans.invert(trans); + const mt::mat3x4 trans = mt::mat3x4((float *)viewmat); + camtrans = trans.Inverse(); cam->SetModelviewMatrix(modelviewmat); cam->SetProjectionMatrix(projectionmat); - cam->NodeSetLocalPosition(camtrans.getOrigin()); - cam->NodeSetLocalOrientation(camtrans.getBasis()); - cam->NodeUpdateGS(0); + cam->NodeSetLocalPosition(camtrans.TranslationVector3D()); + cam->NodeSetLocalOrientation(camtrans.RotationMatrix()); + cam->NodeUpdate(); /* setup rasterizer transformations */ - /* SetViewMatrix may use stereomode which we temporarily disable here */ - RAS_IRasterizer::StereoMode stereomode = m_rasterizer->GetStereoMode(); - m_rasterizer->SetStereoMode(RAS_IRasterizer::RAS_STEREO_NOSTEREO); m_rasterizer->SetProjectionMatrix(projectionmat); - m_rasterizer->SetViewMatrix(modelviewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->NodeGetLocalScaling(), cam->GetCameraData()->m_perspective); - m_rasterizer->SetStereoMode(stereomode); + m_rasterizer->SetViewMatrix(modelviewmat); } void RAS_OpenGLLight::UnbindShadowBuffer() @@ -251,47 +278,41 @@ void RAS_OpenGLLight::UnbindShadowBuffer() GPULamp *lamp = GetGPULamp(); GPU_lamp_shadow_buffer_unbind(lamp); - if (GPU_lamp_shadow_buffer_type(lamp) == LA_SHADMAP_VARIANCE) - m_rasterizer->SetUsingOverrideShader(false); + m_rasterizer->SetShadowMode(RAS_Rasterizer::RAS_SHADOW_NONE); + + m_requestShadowUpdate = false; } Image *RAS_OpenGLLight::GetTextureImage(short texslot) { - KX_LightObject* kxlight = (KX_LightObject*)m_light; - Lamp *la = (Lamp*)kxlight->GetBlenderObject()->data; + KX_LightObject *kxlight = (KX_LightObject *)m_light; + Lamp *la = (Lamp *)kxlight->GetBlenderObject()->data; - if (texslot >= MAX_MTEX || texslot < 0) - { - printf("KX_LightObject::GetTextureImage(): texslot exceeds slot bounds (0-%d)\n", MAX_MTEX-1); - return NULL; + if (texslot >= MAX_MTEX || texslot < 0) { + printf("KX_LightObject::GetTextureImage(): texslot exceeds slot bounds (0-%d)\n", MAX_MTEX - 1); + return nullptr; } - if (la->mtex[texslot]) + if (la->mtex[texslot]) { return la->mtex[texslot]->tex->ima; + } - return NULL; + return nullptr; } -void RAS_OpenGLLight::Update() +void RAS_OpenGLLight::Update(const mt::mat3x4& trans, bool hide) { - GPULamp *lamp; - KX_LightObject* kxlight = (KX_LightObject*)m_light; + GPULamp *lamp = GetGPULamp(); - if ((lamp = GetGPULamp()) != NULL && kxlight->GetSGNode()) { + if (lamp) { float obmat[4][4]; - // lights don't get their openGL matrix updated, do it now - if (kxlight->GetSGNode()->IsDirty()) - kxlight->GetOpenGLMatrix(); - float *dobmat = kxlight->GetOpenGLMatrixPtr()->getPointer(); - - for (int i=0; i<4; i++) - for (int j=0; j<4; j++, dobmat++) - obmat[i][j] = (float)*dobmat; - int hide = kxlight->GetVisible() ? 0 : 1; + trans.PackFromAffineTransform(obmat); + GPU_lamp_update(lamp, m_layer, hide, obmat); GPU_lamp_update_colors(lamp, m_color[0], m_color[1], - m_color[2], m_energy); + m_color[2], m_energy); GPU_lamp_update_distance(lamp, m_distance, m_att1, m_att2, m_coeff_const, m_coeff_lin, m_coeff_quad); GPU_lamp_update_spot(lamp, m_spotsize, m_spotblend); } } + diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.h index a520b18c434a..076fdc4e906e 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.h @@ -27,30 +27,39 @@ #include "RAS_ILightObject.h" -class RAS_OpenGLRasterizer; +class RAS_Rasterizer; +class KX_Scene; struct GPULamp; struct Image; class RAS_OpenGLLight : public RAS_ILightObject { - RAS_OpenGLRasterizer *m_rasterizer; + RAS_Rasterizer *m_rasterizer; GPULamp *GetGPULamp(); + public: - RAS_OpenGLLight(RAS_OpenGLRasterizer *ras); + RAS_OpenGLLight(RAS_Rasterizer *ras); ~RAS_OpenGLLight(); bool ApplyFixedFunctionLighting(KX_Scene *kxscene, int oblayer, int slot); - RAS_OpenGLLight* Clone() { return new RAS_OpenGLLight(*this); } + RAS_OpenGLLight *Clone() + { + return new RAS_OpenGLLight(*this); + } bool HasShadowBuffer(); + bool NeedShadowUpdate(); int GetShadowBindCode(); - MT_Matrix4x4 GetShadowMatrix(); + mt::mat4 GetViewMat(); + mt::mat4 GetWinMat(); + mt::mat4 GetShadowMatrix(); int GetShadowLayer(); - void BindShadowBuffer(RAS_ICanvas *canvas, KX_Camera *cam, MT_Transform& camtrans); + void BindShadowBuffer(RAS_ICanvas *canvas, KX_Camera *cam, mt::mat3x4& camtrans); void UnbindShadowBuffer(); Image *GetTextureImage(short texslot); - void Update(); + void Update(const mt::mat3x4& trans, bool hide); + void SetShadowUpdateState(short state); }; diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp deleted file mode 100644 index 58b3c61bd058..000000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp +++ /dev/null @@ -1,347 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2015, Blender Foundation - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): Blender Foundation. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "GPU_glew.h" - -#include - -#include "RAS_OpenGLOffScreen.h" -#include "RAS_ICanvas.h" - -RAS_OpenGLOffScreen::RAS_OpenGLOffScreen(RAS_ICanvas *canvas) - :m_canvas(canvas), m_depthrb(0), m_colorrb(0), m_depthtx(0), m_colortx(0), - m_fbo(0), m_blitfbo(0), m_blitrbo(0), m_blittex(0), m_target(RAS_OFS_RENDER_BUFFER), m_bound(false) -{ - m_width = 0; - m_height = 0; - m_samples = 0; - m_color = 0; -} - -RAS_OpenGLOffScreen::~RAS_OpenGLOffScreen() -{ - Destroy(); -} - -bool RAS_OpenGLOffScreen::Create(int width, int height, int samples, RAS_OFS_RENDER_TARGET target) -{ - GLenum status; - GLuint glo[2], fbo; - GLint max_samples; - GLenum textarget; - - if (m_fbo) { - printf("RAS_OpenGLOffScreen::Create(): buffer exists already, destroy first\n"); - return false; - } - if (target != RAS_IOffScreen::RAS_OFS_RENDER_BUFFER && - target != RAS_IOffScreen::RAS_OFS_RENDER_TEXTURE) - { - printf("RAS_OpenGLOffScreen::Create(): invalid offscren target\n"); - return false; - } - if (!GLEW_EXT_framebuffer_object) { - printf("RAS_OpenGLOffScreen::Create(): frame buffer not supported\n"); - return false; - } - if (samples) { - if (!GLEW_EXT_framebuffer_multisample || - !GLEW_EXT_framebuffer_blit) - { - samples = 0; - } - } - if (samples && target == RAS_OFS_RENDER_TEXTURE) { - // we need this in addition if we use multisample textures - if (!GLEW_ARB_texture_multisample || - !GLEW_EXT_framebuffer_multisample_blit_scaled) - { - samples = 0; - } - } - if (samples) { - max_samples = 0; - glGetIntegerv(GL_MAX_SAMPLES_EXT , &max_samples); - if (samples > max_samples) - samples = max_samples; - } - m_target = target; - fbo = 0; - glGenFramebuffersEXT(1, &fbo); - if (fbo == 0) { - printf("RAS_OpenGLOffScreen::Create(): frame buffer creation failed: %d\n", (int)glGetError()); - return false; - } - m_fbo = fbo; - glo[0] = glo[1] = 0; - if (target == RAS_OFS_RENDER_TEXTURE) { - glGenTextures(2, glo); - if (glo[0] == 0 || glo[1] == 0) { - printf("RAS_OpenGLOffScreen::Create(): texture creation failed: %d\n", (int)glGetError()); - goto L_ERROR; - } - m_depthtx = glo[0]; - m_color = m_colortx = glo[1]; - if (samples) { - textarget = GL_TEXTURE_2D_MULTISAMPLE; - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_depthtx); - glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_DEPTH_COMPONENT, width, height, true); - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, m_colortx); - glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGBA8, width, height, true); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); - } - else { - textarget = GL_TEXTURE_2D; - glBindTexture(GL_TEXTURE_2D, m_depthtx); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); - glBindTexture(GL_TEXTURE_2D, m_colortx); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glBindTexture(GL_TEXTURE_2D, 0); - } - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, textarget, m_depthtx, 0); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, textarget, m_colortx, 0); - } - else { - glGenRenderbuffersEXT(2, glo); - if (glo[0] == 0 || glo[1] == 0) { - printf("RAS_OpenGLOffScreen::Create(): render buffer creation failed: %d\n", (int)glGetError()); - goto L_ERROR; - } - m_depthrb = glo[0]; - m_colorrb = glo[1]; - glBindRenderbufferEXT(GL_RENDERBUFFER, m_depthrb); - glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, GL_DEPTH_COMPONENT, width, height); - glBindRenderbufferEXT(GL_RENDERBUFFER, m_colorrb); - glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, GL_RGBA8, width, height); - glBindRenderbufferEXT(GL_RENDERBUFFER, 0); - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER, m_depthrb); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER, m_colorrb); - } - status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { - printf("RAS_OpenGLOffScreen::Create(): frame buffer incomplete: %d\n", (int)status); - goto L_ERROR; - } - m_width = width; - m_height = height; - - if (samples > 0) { - GLuint blit_tex; - GLuint blit_fbo; - // create a secondary FBO to blit to before the pixel can be read - - /* write into new single-sample buffer */ - glGenFramebuffersEXT(1, &blit_fbo); - if (!blit_fbo) { - printf("RAS_OpenGLOffScreen::Create(): failed creating a FBO for multi-sample offscreen buffer\n"); - goto L_ERROR; - } - m_blitfbo = blit_fbo; - blit_tex = 0; - if (target == RAS_OFS_RENDER_TEXTURE) { - glGenTextures(1, &blit_tex); - if (!blit_tex) { - printf("RAS_OpenGLOffScreen::Create(): failed creating a texture for multi-sample offscreen buffer\n"); - goto L_ERROR; - } - // m_color is the texture where the final render goes, the blit texture in this case - m_color = m_blittex = blit_tex; - glBindTexture(GL_TEXTURE_2D, m_blittex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_blitfbo); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_blittex, 0); - } - else { - /* create render buffer for new 'fbo_blit' */ - glGenRenderbuffersEXT(1, &blit_tex); - if (!blit_tex) { - printf("RAS_OpenGLOffScreen::Create(): failed creating a render buffer for multi-sample offscreen buffer\n"); - goto L_ERROR; - } - m_blitrbo = blit_tex; - glBindRenderbufferEXT(GL_RENDERBUFFER, m_blitrbo); - glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 0, GL_RGBA8, width, height); - glBindRenderbufferEXT(GL_RENDERBUFFER, 0); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_blitfbo); - glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER, m_blitrbo); - } - status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER_EXT); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0); - if (status != GL_FRAMEBUFFER_COMPLETE) { - printf("RAS_OpenGLOffScreen::Create(): frame buffer for multi-sample offscreen buffer incomplete: %d\n", (int)status); - goto L_ERROR; - } - // remember that multisample is enabled - m_samples = 1; - } - return true; - -L_ERROR: - Destroy(); - return false; -} - -void RAS_OpenGLOffScreen::Destroy() -{ - GLuint globj; - Unbind(); - if (m_fbo) { - globj = m_fbo; - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); - if (m_target == RAS_OFS_RENDER_TEXTURE) { - GLenum textarget = (m_samples) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, textarget, 0, 0); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, textarget, 0, 0); - } - else { - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, 0); - } - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - glDeleteFramebuffersEXT(1, &globj); - m_fbo = 0; - } - if (m_depthrb) { - globj = m_depthrb; - glDeleteRenderbuffers(1, &globj); - m_depthrb = 0; - } - if (m_colorrb) { - globj = m_colorrb; - glDeleteRenderbuffers(1, &globj); - m_colorrb = 0; - } - if (m_depthtx) { - globj = m_depthtx; - glDeleteTextures(1, &globj); - m_depthtx = 0; - } - if (m_colortx) { - globj = m_colortx; - glDeleteTextures(1, &globj); - m_colortx = 0; - } - if (m_blitfbo) { - globj = m_blitfbo; - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_blitfbo); - if (m_target == RAS_OFS_RENDER_TEXTURE) { - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0); - } - else { - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, 0); - } - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - glDeleteFramebuffersEXT(1, &globj); - m_blitfbo = 0; - } - if (m_blitrbo) { - globj = m_blitrbo; - glDeleteRenderbuffers(1, &globj); - m_blitrbo = 0; - } - if (m_blittex) { - globj = m_blittex; - glDeleteTextures(1, &globj); - m_blittex = 0; - } - m_width = 0; - m_height = 0; - m_samples = 0; - m_color = 0; - m_target = RAS_OFS_RENDER_BUFFER; -} - -void RAS_OpenGLOffScreen::Bind(RAS_OFS_BIND_MODE mode) -{ - if (m_fbo) { - if (mode == RAS_OFS_BIND_RENDER) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); - glViewport(0, 0, m_width, m_height); - glDisable(GL_SCISSOR_TEST); - } - else if (!m_blitfbo) { - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); - } - else { - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_blitfbo); - glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); - } - m_bound = true; - } -} - -void RAS_OpenGLOffScreen::Unbind() -{ - if (!m_bound) - return; - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - glEnable(GL_SCISSOR_TEST); - glReadBuffer(GL_BACK); - glDrawBuffer(GL_BACK); - m_bound = false; -} - -void RAS_OpenGLOffScreen::MipMap() -{ - if (m_color) { - glBindTexture(GL_TEXTURE_2D, m_color); - glGenerateMipmap(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); - } -} - -void RAS_OpenGLOffScreen::Blit() -{ - if (m_bound && m_blitfbo) { - // set the draw target to the secondary FBO, the read target is still the multisample FBO - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, m_blitfbo); - - // sample the primary - glBlitFramebufferEXT(0, 0, m_width, m_height, 0, 0, m_width, m_height, GL_COLOR_BUFFER_BIT, GL_NEAREST); - - // make sure the next glReadPixels will read from the secondary buffer - glBindFramebufferEXT(GL_READ_FRAMEBUFFER, m_blitfbo); - } -} diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h deleted file mode 100644 index 15c7744c13a7..000000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2015, Blender Foundation - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): Blender Foundation. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef __RAS_OPENGLOFFSCREEN__ -#define __RAS_OPENGLOFFSCREEN__ - -#include "RAS_IOffScreen.h" -#include "GPU_extensions.h" - -class RAS_ICanvas; - -class RAS_OpenGLOffScreen : public RAS_IOffScreen -{ - RAS_ICanvas *m_canvas; - // these are GL objects - unsigned int m_depthrb; - unsigned int m_colorrb; - unsigned int m_depthtx; - unsigned int m_colortx; - unsigned int m_fbo; - unsigned int m_blitfbo; - unsigned int m_blitrbo; - unsigned int m_blittex; - RAS_OFS_RENDER_TARGET m_target; - bool m_bound; - - -public: - RAS_OpenGLOffScreen(RAS_ICanvas *canvas); - ~RAS_OpenGLOffScreen(); - - bool Create(int width, int height, int samples, RAS_OFS_RENDER_TARGET target); - void Destroy(); - void Bind(RAS_OFS_BIND_MODE mode); - void Blit(); - void Unbind(); - void MipMap(); -}; - -#endif /* __RAS_OPENGLOFFSCREEN__ */ diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLQuery.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLQuery.cpp new file mode 100644 index 000000000000..e942eecf90a4 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLQuery.cpp @@ -0,0 +1,78 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLQuery.cpp + * \ingroup bgerastogl + */ + +#include "RAS_OpenGLQuery.h" + +RAS_OpenGLQuery::RAS_OpenGLQuery(RAS_Query::QueryType type) +{ + static const GLenum targetTable[] = { + GL_SAMPLES_PASSED, // SAMPLES + GL_ANY_SAMPLES_PASSED, // ANY_SAMPLES + GL_ANY_SAMPLES_PASSED_CONSERVATIVE, // ANY_SAMPLES_CONSERVATIVE + GL_PRIMITIVES_GENERATED, // PRIMITIVES + GL_TIME_ELAPSED // TIME + }; + + m_target = targetTable[type]; + + glGenQueries(1, &m_id); +} + +RAS_OpenGLQuery::~RAS_OpenGLQuery() +{ + glDeleteQueries(1, &m_id); +} + +void RAS_OpenGLQuery::Begin() +{ + glBeginQuery(m_target, m_id); +} + +void RAS_OpenGLQuery::End() +{ + glEndQuery(m_target); +} + +bool RAS_OpenGLQuery::Available() +{ + GLint result; + glGetQueryObjectiv(m_id, GL_QUERY_RESULT_AVAILABLE, &result); + return result; +} + +int RAS_OpenGLQuery::ResultNoWait() +{ + GLint result; + glGetQueryObjectiv(m_id, GL_QUERY_RESULT_NO_WAIT, &result); + return result; +} + +int RAS_OpenGLQuery::Result() +{ + GLint result; + glGetQueryObjectiv(m_id, GL_QUERY_RESULT, &result); + return result; +} diff --git a/source/gameengine/Rasterizer/RAS_TexMatrix.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLQuery.h similarity index 67% rename from source/gameengine/Rasterizer/RAS_TexMatrix.h rename to source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLQuery.h index a2dd291d0165..962f78e45197 100644 --- a/source/gameengine/Rasterizer/RAS_TexMatrix.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLQuery.h @@ -15,28 +15,40 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): Tristan Porteries. * * ***** END GPL LICENSE BLOCK ***** */ -/** \file RAS_TexMatrix.h +/** \file RAS_OpenGLQuery.h * \ingroup bgerast */ -#ifndef __RAS_TEXMATRIX_H__ -#define __RAS_TEXMATRIX_H__ +#ifndef __RAS_OPENGLQUERY_H__ +#define __RAS_OPENGLQUERY_H__ + +#include "RAS_Query.h" + +#include "GPU_glew.h" + +class RAS_OpenGLQuery +{ +private: + GLuint m_id; + GLenum m_target; + +public: + RAS_OpenGLQuery(RAS_Query::QueryType type); + ~RAS_OpenGLQuery(); -#include "MT_Matrix3x3.h" -#include "MT_Point3.h" -#include "MT_Point2.h" -#include "RAS_TexVert.h" + void Begin(); + void End(); -void RAS_CalcTexMatrix(RAS_TexVert p[3],MT_Point3& origin,MT_Vector3& udir,MT_Vector3& vdir); + bool Available(); + int ResultNoWait(); + int Result(); +}; -#endif /* __RAS_TEXMATRIX_H__ */ +#endif // __RAS_OPENGLQUERY_H__ diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp index 9472ff9b70e1..8b7545b52346 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp @@ -29,1529 +29,391 @@ * \ingroup bgerastogl */ - -#include -#include - #include "RAS_OpenGLRasterizer.h" +#include "RAS_IMaterial.h" #include "GPU_glew.h" -#include "RAS_ICanvas.h" -#include "RAS_Rect.h" -#include "RAS_TexVert.h" -#include "RAS_MeshObject.h" -#include "RAS_Polygon.h" -#include "RAS_ILightObject.h" -#include "MT_CmMatrix4x4.h" - -#include "RAS_OpenGLLight.h" -#include "RAS_OpenGLOffScreen.h" -#include "RAS_OpenGLSync.h" - -#include "RAS_StorageVA.h" -#include "RAS_StorageVBO.h" +#include "RAS_MeshUser.h" #include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_material.h" #include "GPU_shader.h" -extern "C"{ - #include "BLF_api.h" - #include "BKE_DerivedMesh.h" - #include "BKE_global.h" -} - - -// XXX Clean these up <<< -#include "EXP_Value.h" -#include "KX_Scene.h" -#include "KX_RayCast.h" -#include "KX_GameObject.h" -// >>> - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -/** - * 32x32 bit masks for vinterlace stereo mode - */ -static GLuint left_eye_vinterlace_mask[32]; -static GLuint right_eye_vinterlace_mask[32]; - -/** - * 32x32 bit masks for hinterlace stereo mode. - * Left eye = &hinterlace_mask[0] - * Right eye = &hinterlace_mask[1] - */ -static GLuint hinterlace_mask[33]; - -RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas, RAS_STORAGE_TYPE storage) - :RAS_IRasterizer(canvas), - m_2DCanvas(canvas), - m_fogenabled(false), - m_time(0.0f), - m_campos(0.0f, 0.0f, 0.0f), - m_camortho(false), - m_camnegscale(false), - m_stereomode(RAS_STEREO_NOSTEREO), - m_curreye(RAS_STEREO_LEFTEYE), - m_eyeseparation(0.0f), - m_focallength(0.0f), - m_setfocallength(false), - m_noOfScanlines(32), - m_motionblur(0), - m_motionblurvalue(-1.0f), - m_usingoverrideshader(false), - m_clientobject(NULL), - m_auxilaryClientInfo(NULL), - m_drawingmode(KX_TEXTURED), - m_texco_num(0), - m_attrib_num(0), - //m_last_alphablend(GPU_BLEND_SOLID), - m_last_frontface(true), - m_materialCachingInfo(0), - m_storage_type(storage) +extern "C" { +# include "BLF_api.h" +} + +#include "MEM_guardedalloc.h" + +#include "CM_Message.h" + +#include // For memcpy. + +// WARNING: Always respect the order from RAS_Rasterizer::EnableBit. +static const int openGLEnableBitEnums[] = { + GL_DEPTH_TEST, // RAS_DEPTH_TEST + GL_ALPHA_TEST, // RAS_ALPHA_TEST + GL_SCISSOR_TEST, // RAS_SCISSOR_TEST + GL_TEXTURE_2D, // RAS_TEXTURE_2D + GL_TEXTURE_CUBE_MAP_ARB, // RAS_TEXTURE_CUBE_MAP + GL_BLEND, // RAS_BLEND + GL_COLOR_MATERIAL, // RAS_COLOR_MATERIAL + GL_CULL_FACE, // RAS_CULL_FACE + GL_LIGHTING, // RAS_LIGHTING + GL_MULTISAMPLE_ARB, // RAS_MULTISAMPLE + GL_POLYGON_STIPPLE, // RAS_POLYGON_STIPPLE + GL_POLYGON_OFFSET_FILL, // RAS_POLYGON_OFFSET_FILL + GL_POLYGON_OFFSET_LINE, // RAS_POLYGON_OFFSET_LINE + GL_TEXTURE_GEN_S, // RAS_TEXTURE_GEN_S + GL_TEXTURE_GEN_T, // RAS_TEXTURE_GEN_T + GL_TEXTURE_GEN_R, // RAS_TEXTURE_GEN_R + GL_TEXTURE_GEN_Q // RAS_TEXTURE_GEN_Q +}; + +// WARNING: Always respect the order from RAS_Rasterizer::DepthFunc. +static const int openGLDepthFuncEnums[] = { + GL_NEVER, // RAS_NEVER + GL_LEQUAL, // RAS_LEQUAL + GL_LESS, // RAS_LESS + GL_ALWAYS, // RAS_ALWAYS + GL_GEQUAL, // RAS_GEQUAL + GL_GREATER, // RAS_GREATER + GL_NOTEQUAL, // RAS_NOTEQUAL + GL_EQUAL // RAS_EQUAL +}; + +// WARNING: Always respect the order from RAS_Rasterizer::MatrixMode. +static const int openGLMatrixModeEnums[] = { + GL_PROJECTION, // RAS_PROJECTION + GL_MODELVIEW, // RAS_MODELVIEW + GL_TEXTURE // RAS_TEXTURE +}; + +// WARNING: Always respect the order from RAS_Rasterizer::BlendFunc. +static const int openGLBlendFuncEnums[] = { + GL_ZERO, // RAS_ZERO, + GL_ONE, // RAS_ONE, + GL_SRC_COLOR, // RAS_SRC_COLOR, + GL_ONE_MINUS_SRC_COLOR, // RAS_ONE_MINUS_SRC_COLOR, + GL_DST_COLOR, // RAS_DST_COLOR, + GL_ONE_MINUS_DST_COLOR, // RAS_ONE_MINUS_DST_COLOR, + GL_SRC_ALPHA, // RAS_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA, // RAS_ONE_MINUS_SRC_ALPHA, + GL_DST_ALPHA, // RAS_DST_ALPHA, + GL_ONE_MINUS_DST_ALPHA, // RAS_ONE_MINUS_DST_ALPHA, + GL_SRC_ALPHA_SATURATE // RAS_SRC_ALPHA_SATURATE +}; + +RAS_OpenGLRasterizer::ScreenPlane::ScreenPlane() +{ + // Generate the VBO and IBO for screen overlay plane. + glGenBuffers(1, &m_vbo); + glGenBuffers(1, &m_ibo); + glGenVertexArrays(1, &m_vao); + + // Vertexes for screen plane, it contains the vertex position (3 floats) and the vertex uv after (2 floats, total size = 5 floats). + static const float vertices[] = { + // 3f position | 2f UV + -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, + -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, -1.0f, 1.0f, 1.0f, 0.0f + }; + // Indices for screen plane. + static const GLubyte indices[] = {3, 2, 1, 0}; + + glBindVertexArray(m_vao); + + // Send indices in the sreen plane IBO. + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); + + // Send vertexes in the screen plane VBO. + glBindBuffer(GL_ARRAY_BUFFER, m_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + // Enable vertex/uv pointer. + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + // Bind vertex/uv pointer with VBO offset. (position = 0, uv = 3 * float, stride = 5 * float). + glVertexPointer(3, GL_FLOAT, sizeof(float) * 5, 0); + glTexCoordPointer(2, GL_FLOAT, sizeof(float) * 5, ((char *)nullptr) + sizeof(float) * 3); + + // Unbind VBO + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glBindVertexArray(0); +} + +RAS_OpenGLRasterizer::ScreenPlane::~ScreenPlane() +{ + // Delete screen overlay plane VBO/IBO/VAO + glDeleteVertexArrays(1, &m_vao); + glDeleteBuffers(1, &m_vbo); + glDeleteBuffers(1, &m_ibo); +} + +inline void RAS_OpenGLRasterizer::ScreenPlane::Render() +{ + glBindVertexArray(m_vao); + // Draw in triangle fan mode to reduce IBO size. + glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_BYTE, 0); + + glBindVertexArray(0); +} + +RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_Rasterizer *rasterizer) + :m_rasterizer(rasterizer) { - m_viewmatrix.setIdentity(); - m_viewinvmatrix.setIdentity(); - - for (int i = 0; i < 32; i++) - { - left_eye_vinterlace_mask[i] = 0x55555555; - right_eye_vinterlace_mask[i] = 0xAAAAAAAA; - hinterlace_mask[i] = (i&1)*0xFFFFFFFF; - } - hinterlace_mask[32] = 0; - - m_prevafvalue = GPU_get_anisotropic(); - - if (m_storage_type == RAS_VBO /*|| m_storage_type == RAS_AUTO_STORAGE && GLEW_ARB_vertex_buffer_object*/) { - m_storage = new RAS_StorageVBO(&m_texco_num, m_texco, &m_attrib_num, m_attrib, m_attrib_layer); - } - else if ((m_storage_type == RAS_VA) || (m_storage_type == RAS_AUTO_STORAGE)) { - m_storage = new RAS_StorageVA(&m_texco_num, m_texco, &m_attrib_num, m_attrib, m_attrib_layer); - } - else { - printf("Unknown rasterizer storage type, falling back to vertex arrays\n"); - m_storage = new RAS_StorageVA(&m_texco_num, m_texco, &m_attrib_num, m_attrib, m_attrib_layer); - } - - glGetIntegerv(GL_MAX_LIGHTS, (GLint *) &m_numgllights); - if (m_numgllights < 8) - m_numgllights = 8; } - - RAS_OpenGLRasterizer::~RAS_OpenGLRasterizer() { - // Restore the previous AF value - GPU_set_anisotropic(G_MAIN, m_prevafvalue); - - if (m_storage) - delete m_storage; } -bool RAS_OpenGLRasterizer::Init() +unsigned short RAS_OpenGLRasterizer::GetNumLights() const { - bool storage_init; - GPU_state_init(); - + int numlights = 0; + glGetIntegerv(GL_MAX_LIGHTS, (GLint *)&numlights); - m_ambr = 0.0f; - m_ambg = 0.0f; - m_ambb = 0.0f; - - glDisable(GL_BLEND); - glDisable(GL_ALPHA_TEST); - //m_last_alphablend = GPU_BLEND_SOLID; - GPU_set_material_alpha_blend(GPU_BLEND_SOLID); - - glFrontFace(GL_CCW); - m_last_frontface = true; - - m_redback = 0.4375f; - m_greenback = 0.4375f; - m_blueback = 0.4375f; - m_alphaback = 0.0f; - - glClearColor(m_redback,m_greenback,m_blueback,m_alphaback); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - - glShadeModel(GL_SMOOTH); - - storage_init = m_storage->Init(); - - return true && storage_init; -} - - -void RAS_OpenGLRasterizer::SetAmbientColor(float color[3]) -{ - m_ambr = color[0]; - m_ambg = color[1]; - m_ambb = color[2]; -} - -void RAS_OpenGLRasterizer::SetAmbient(float factor) -{ - float ambient[] = {m_ambr * factor, m_ambg * factor, m_ambb * factor, 1.0f}; - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); -} - -void RAS_OpenGLRasterizer::SetBackColor(float color[3]) -{ - m_redback = color[0]; - m_greenback = color[1]; - m_blueback = color[2]; - m_alphaback = 0.0f; -} - -void RAS_OpenGLRasterizer::SetFog(short type, float start, float dist, float intensity, float color[3]) -{ - float params[4] = {color[0], color[1], color[2], 1.0f}; - glFogi(GL_FOG_MODE, GL_LINEAR); - glFogf(GL_FOG_DENSITY, intensity / 10.0f); - glFogf(GL_FOG_START, start); - glFogf(GL_FOG_END, start + dist); - glFogfv(GL_FOG_COLOR, params); -} - -void RAS_OpenGLRasterizer::EnableFog(bool enable) -{ - m_fogenabled = enable; -} - -void RAS_OpenGLRasterizer::DisplayFog() -{ - if ((m_drawingmode >= KX_SOLID) && m_fogenabled) { - glEnable(GL_FOG); - } - else { - glDisable(GL_FOG); - } -} - -bool RAS_OpenGLRasterizer::SetMaterial(const RAS_IPolyMaterial& mat) -{ - return mat.Activate(this, m_materialCachingInfo); -} - - - -void RAS_OpenGLRasterizer::Exit() -{ - m_storage->Exit(); - - glEnable(GL_CULL_FACE); - glEnable(GL_DEPTH_TEST); - glClearDepth(1.0f); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glClearColor(m_redback, m_greenback, m_blueback, m_alphaback); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glDepthMask (GL_TRUE); - glDepthFunc(GL_LEQUAL); - glBlendFunc(GL_ONE, GL_ZERO); - - glDisable(GL_POLYGON_STIPPLE); - - glDisable(GL_LIGHTING); - if (GLEW_EXT_separate_specular_color || GLEW_VERSION_1_2) - glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR); - - EndFrame(); -} - -bool RAS_OpenGLRasterizer::BeginFrame(double time) -{ - m_time = time; - - // Blender camera routine destroys the settings - if (m_drawingmode < KX_SOLID) - { - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - } - else - { - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); + if (numlights > 8) { + return 8; } - - glDisable(GL_BLEND); - glDisable(GL_ALPHA_TEST); - //m_last_alphablend = GPU_BLEND_SOLID; - GPU_set_material_alpha_blend(GPU_BLEND_SOLID); - - glFrontFace(GL_CCW); - m_last_frontface = true; - - glShadeModel(GL_SMOOTH); - - glEnable(GL_MULTISAMPLE_ARB); - - m_2DCanvas->BeginFrame(); - - // Render Tools - m_clientobject = NULL; - m_lastlightlayer = -1; - m_lastauxinfo = NULL; - m_lastlighting = true; /* force disable in DisableOpenGLLights() */ - DisableOpenGLLights(); - - return true; -} - - - -void RAS_OpenGLRasterizer::SetDrawingMode(int drawingmode) -{ - m_drawingmode = drawingmode; - - if (m_drawingmode == KX_WIREFRAME) - glDisable(GL_CULL_FACE); - - m_storage->SetDrawingMode(drawingmode); + return numlights; } -int RAS_OpenGLRasterizer::GetDrawingMode() +void RAS_OpenGLRasterizer::Enable(RAS_Rasterizer::EnableBit bit) { - return m_drawingmode; + glEnable(openGLEnableBitEnums[bit]); } - -void RAS_OpenGLRasterizer::SetDepthMask(DepthMask depthmask) -{ - glDepthMask(depthmask == KX_DEPTHMASK_DISABLED ? GL_FALSE : GL_TRUE); -} - - -void RAS_OpenGLRasterizer::ClearColorBuffer() -{ - m_2DCanvas->ClearColor(m_redback,m_greenback,m_blueback,m_alphaback); - m_2DCanvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER); -} - - -void RAS_OpenGLRasterizer::ClearDepthBuffer() -{ - m_2DCanvas->ClearBuffer(RAS_ICanvas::DEPTH_BUFFER); -} - - -void RAS_OpenGLRasterizer::ClearCachingInfo(void) +void RAS_OpenGLRasterizer::Disable(RAS_Rasterizer::EnableBit bit) { - m_materialCachingInfo = 0; + glDisable(openGLEnableBitEnums[bit]); } -void RAS_OpenGLRasterizer::FlushDebugShapes(SCA_IScene *scene) +void RAS_OpenGLRasterizer::EnableLight(unsigned short count) { - std::vector &debugShapes = m_debugShapes[scene]; - if (debugShapes.empty()) - return; - - // DrawDebugLines - GLboolean light, tex; - - light= glIsEnabled(GL_LIGHTING); - tex= glIsEnabled(GL_TEXTURE_2D); - - if (light) glDisable(GL_LIGHTING); - if (tex) glDisable(GL_TEXTURE_2D); - - // draw lines - glBegin(GL_LINES); - for (unsigned int i = 0; i < debugShapes.size(); i++) { - if (debugShapes[i].m_type != OglDebugShape::LINE) - continue; - glColor4f(debugShapes[i].m_color[0], debugShapes[i].m_color[1], debugShapes[i].m_color[2], 1.0f); - const MT_Scalar *fromPtr = &debugShapes[i].m_pos.x(); - const MT_Scalar *toPtr= &debugShapes[i].m_param.x(); - glVertex3fv(fromPtr); - glVertex3fv(toPtr); - } - glEnd(); - - // draw circles - for (unsigned int i = 0; i < debugShapes.size(); i++) { - if (debugShapes[i].m_type != OglDebugShape::CIRCLE) - continue; - glBegin(GL_LINE_LOOP); - glColor4f(debugShapes[i].m_color[0], debugShapes[i].m_color[1], debugShapes[i].m_color[2], 1.0f); - - static const MT_Vector3 worldUp(0.0f, 0.0f, 1.0f); - MT_Vector3 norm = debugShapes[i].m_param; - MT_Matrix3x3 tr; - if (norm.fuzzyZero() || norm == worldUp) - { - tr.setIdentity(); - } - else - { - MT_Vector3 xaxis, yaxis; - xaxis = MT_cross(norm, worldUp); - yaxis = MT_cross(xaxis, norm); - tr.setValue(xaxis.x(), xaxis.y(), xaxis.z(), - yaxis.x(), yaxis.y(), yaxis.z(), - norm.x(), norm.y(), norm.z()); - } - MT_Scalar rad = debugShapes[i].m_param2.x(); - int n = (int)debugShapes[i].m_param2.y(); - for (int j = 0; jEndFrame(); + glDisable((GLenum)(GL_LIGHT0 + count)); } -void RAS_OpenGLRasterizer::SetRenderArea() +void RAS_OpenGLRasterizer::SetDepthFunc(RAS_Rasterizer::DepthFunc func) { - RAS_Rect area; - // only above/below stereo method needs viewport adjustment - switch (m_stereomode) - { - case RAS_STEREO_ABOVEBELOW: - switch (m_curreye) { - case RAS_STEREO_LEFTEYE: - // upper half of window - area.SetLeft(0); - area.SetBottom(m_2DCanvas->GetHeight() - - int(m_2DCanvas->GetHeight() - m_noOfScanlines) / 2); - - area.SetRight(int(m_2DCanvas->GetWidth())); - area.SetTop(int(m_2DCanvas->GetHeight())); - m_2DCanvas->SetDisplayArea(&area); - break; - case RAS_STEREO_RIGHTEYE: - // lower half of window - area.SetLeft(0); - area.SetBottom(0); - area.SetRight(int(m_2DCanvas->GetWidth())); - area.SetTop(int(m_2DCanvas->GetHeight() - m_noOfScanlines) / 2); - m_2DCanvas->SetDisplayArea(&area); - break; - } - break; - case RAS_STEREO_3DTVTOPBOTTOM: - switch (m_curreye) { - case RAS_STEREO_LEFTEYE: - // upper half of window - area.SetLeft(0); - area.SetBottom(m_2DCanvas->GetHeight() - - m_2DCanvas->GetHeight() / 2); - - area.SetRight(m_2DCanvas->GetWidth()); - area.SetTop(m_2DCanvas->GetHeight()); - m_2DCanvas->SetDisplayArea(&area); - break; - case RAS_STEREO_RIGHTEYE: - // lower half of window - area.SetLeft(0); - area.SetBottom(0); - area.SetRight(m_2DCanvas->GetWidth()); - area.SetTop(m_2DCanvas->GetHeight() / 2); - m_2DCanvas->SetDisplayArea(&area); - break; - } - break; - case RAS_STEREO_SIDEBYSIDE: - switch (m_curreye) - { - case RAS_STEREO_LEFTEYE: - // Left half of window - area.SetLeft(0); - area.SetBottom(0); - area.SetRight(m_2DCanvas->GetWidth()/2); - area.SetTop(m_2DCanvas->GetHeight()); - m_2DCanvas->SetDisplayArea(&area); - break; - case RAS_STEREO_RIGHTEYE: - // Right half of window - area.SetLeft(m_2DCanvas->GetWidth()/2); - area.SetBottom(0); - area.SetRight(m_2DCanvas->GetWidth()); - area.SetTop(m_2DCanvas->GetHeight()); - m_2DCanvas->SetDisplayArea(&area); - break; - } - break; - default: - // every available pixel - area.SetLeft(0); - area.SetBottom(0); - area.SetRight(int(m_2DCanvas->GetWidth())); - area.SetTop(int(m_2DCanvas->GetHeight())); - m_2DCanvas->SetDisplayArea(&area); - break; - } + glDepthFunc(openGLDepthFuncEnums[func]); } -void RAS_OpenGLRasterizer::SetStereoMode(const StereoMode stereomode) +void RAS_OpenGLRasterizer::SetBlendFunc(RAS_Rasterizer::BlendFunc src, RAS_Rasterizer::BlendFunc dst) { - m_stereomode = stereomode; + glBlendFunc(openGLBlendFuncEnums[src], openGLBlendFuncEnums[dst]); } -RAS_IRasterizer::StereoMode RAS_OpenGLRasterizer::GetStereoMode() +void RAS_OpenGLRasterizer::Init() { - return m_stereomode; + glShadeModel(GL_SMOOTH); } -bool RAS_OpenGLRasterizer::Stereo() +void RAS_OpenGLRasterizer::SetAmbient(const mt::vec3& amb, float factor) { - if (m_stereomode > RAS_STEREO_NOSTEREO) // > 0 - return true; - else - return false; + float ambient[] = {amb.x * factor, amb.y * factor, amb.z * factor, 1.0f}; + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); } -bool RAS_OpenGLRasterizer::InterlacedStereo() +void RAS_OpenGLRasterizer::SetFog(short type, float start, float dist, float intensity, const mt::vec3& color) { - return m_stereomode == RAS_STEREO_VINTERLACE || m_stereomode == RAS_STEREO_INTERLACED; + float params[4] = {color[0], color[1], color[2], 1.0f}; + glFogi(GL_FOG_MODE, GL_LINEAR); + glFogf(GL_FOG_DENSITY, intensity / 10.0f); + glFogf(GL_FOG_START, start); + glFogf(GL_FOG_END, start + dist); + glFogfv(GL_FOG_COLOR, params); } -void RAS_OpenGLRasterizer::SetEye(const StereoEye eye) +void RAS_OpenGLRasterizer::Exit() { - m_curreye = eye; - switch (m_stereomode) - { - case RAS_STEREO_QUADBUFFERED: - glDrawBuffer(m_curreye == RAS_STEREO_LEFTEYE ? GL_BACK_LEFT : GL_BACK_RIGHT); - break; - case RAS_STEREO_ANAGLYPH: - if (m_curreye == RAS_STEREO_LEFTEYE) { - glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE); - } - else { - //glAccum(GL_LOAD, 1.0f); - glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_FALSE); - ClearDepthBuffer(); - } - break; - case RAS_STEREO_VINTERLACE: - { - // OpenGL stippling is deprecated, it is no longer possible to affect all shaders - // this way, offscreen rendering and then compositing may be the better solution - glEnable(GL_POLYGON_STIPPLE); - glPolygonStipple((const GLubyte*) ((m_curreye == RAS_STEREO_LEFTEYE) ? left_eye_vinterlace_mask : right_eye_vinterlace_mask)); - if (m_curreye == RAS_STEREO_RIGHTEYE) - ClearDepthBuffer(); - break; - } - case RAS_STEREO_INTERLACED: - { - glEnable(GL_POLYGON_STIPPLE); - glPolygonStipple((const GLubyte*) &hinterlace_mask[m_curreye == RAS_STEREO_LEFTEYE?0:1]); - if (m_curreye == RAS_STEREO_RIGHTEYE) - ClearDepthBuffer(); - break; - } - default: - break; + if (GLEW_EXT_separate_specular_color || GLEW_VERSION_1_2) { + glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR); } } -RAS_IRasterizer::StereoEye RAS_OpenGLRasterizer::GetEye() +void RAS_OpenGLRasterizer::BeginFrame() { - return m_curreye; -} - - -void RAS_OpenGLRasterizer::SetEyeSeparation(const float eyeseparation) -{ - m_eyeseparation = eyeseparation; -} - -float RAS_OpenGLRasterizer::GetEyeSeparation() -{ - return m_eyeseparation; -} - -void RAS_OpenGLRasterizer::SetFocalLength(const float focallength) -{ - m_focallength = focallength; - m_setfocallength = true; -} - -float RAS_OpenGLRasterizer::GetFocalLength() -{ - return m_focallength; + glShadeModel(GL_SMOOTH); } -RAS_IOffScreen *RAS_OpenGLRasterizer::CreateOffScreen(int width, int height, int samples, int target) +void RAS_OpenGLRasterizer::SetDepthMask(RAS_Rasterizer::DepthMask depthmask) { - RAS_IOffScreen *ofs; - - ofs = new RAS_OpenGLOffScreen(m_2DCanvas); - - if (!ofs->Create(width, height, samples, (RAS_IOffScreen::RAS_OFS_RENDER_TARGET)target)) { - delete ofs; - return NULL; - } - return ofs; + glDepthMask(depthmask == RAS_Rasterizer::RAS_DEPTHMASK_DISABLED ? GL_FALSE : GL_TRUE); } -RAS_ISync *RAS_OpenGLRasterizer::CreateSync(int type) +unsigned int *RAS_OpenGLRasterizer::MakeScreenshot(int x, int y, int width, int height) { - RAS_ISync *sync; - - sync = new RAS_OpenGLSync(); + unsigned int *pixeldata = nullptr; - if (!sync->Create((RAS_ISync::RAS_SYNC_TYPE)type)) { - delete sync; - return NULL; + if (width && height) { + pixeldata = (unsigned int *)malloc(sizeof(unsigned int) * width * height); + glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixeldata); } - return sync; -} -void RAS_OpenGLRasterizer::SwapBuffers() -{ - m_2DCanvas->SwapBuffers(); + return pixeldata; } - - -const MT_Matrix4x4& RAS_OpenGLRasterizer::GetViewMatrix() const +void RAS_OpenGLRasterizer::Clear(int clearbit) { - return m_viewmatrix; -} + GLbitfield glclearbit = 0; -const MT_Matrix4x4& RAS_OpenGLRasterizer::GetViewInvMatrix() const -{ - return m_viewinvmatrix; -} - -void RAS_OpenGLRasterizer::IndexPrimitives_3DText(RAS_MeshSlot& ms, - class RAS_IPolyMaterial* polymat) -{ - bool obcolor = ms.m_bObjectColor; - MT_Vector4& rgba = ms.m_RGBAcolor; - RAS_MeshSlot::iterator it; - - const STR_String& mytext = ((CValue*)m_clientobject)->GetPropertyText("Text"); - - // handle object color - if (obcolor) { - glDisableClientState(GL_COLOR_ARRAY); - glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]); + if (clearbit & RAS_Rasterizer::RAS_COLOR_BUFFER_BIT) { + glclearbit |= GL_COLOR_BUFFER_BIT; } - else - glEnableClientState(GL_COLOR_ARRAY); - - for (ms.begin(it); !ms.end(it); ms.next(it)) { - RAS_TexVert *vertex; - size_t i, j, numvert; - - numvert = it.array->m_type; - - if (it.array->m_type == RAS_DisplayArray::LINE) { - // line drawing, no text - glBegin(GL_LINES); - - for (i=0; igetXYZ()); - - vertex = &it.vertex[it.index[i+1]]; - glVertex3fv(vertex->getXYZ()); - } - - glEnd(); - } - else { - // triangle and quad text drawing - for (i=0; igetXYZ()[0]; - v[j][1] = vertex->getXYZ()[1]; - v[j][2] = vertex->getXYZ()[2]; - v_ptr[j] = v[j]; - - uv_ptr[j] = vertex->getUV(0); - } - - // find the right opengl attribute - glattrib = -1; - if (GLEW_ARB_vertex_program) - for (unit=0; unitGetMTexPoly(), polymat->GetDrawingMode(), mytext, mytext.Length(), polymat->GetMCol(), - v_ptr, uv_ptr, glattrib); - - ClearCachingInfo(); - } - } + if (clearbit & RAS_Rasterizer::RAS_DEPTH_BUFFER_BIT) { + glclearbit |= GL_DEPTH_BUFFER_BIT; } - - glDisableClientState(GL_COLOR_ARRAY); -} - -void RAS_OpenGLRasterizer::SetTexCoordNum(int num) -{ - m_texco_num = num; - if (m_texco_num > RAS_MAX_TEXCO) - m_texco_num = RAS_MAX_TEXCO; -} - -void RAS_OpenGLRasterizer::SetAttribNum(int num) -{ - m_attrib_num = num; - if (m_attrib_num > RAS_MAX_ATTRIB) - m_attrib_num = RAS_MAX_ATTRIB; -} - -void RAS_OpenGLRasterizer::SetTexCoord(TexCoGen coords, int unit) -{ - // this changes from material to material - if (unit < RAS_MAX_TEXCO) - m_texco[unit] = coords; -} - -void RAS_OpenGLRasterizer::SetAttrib(TexCoGen coords, int unit, int layer) -{ - // this changes from material to material - if (unit < RAS_MAX_ATTRIB) { - m_attrib[unit] = coords; - m_attrib_layer[unit] = layer; + if (clearbit & RAS_Rasterizer::RAS_STENCIL_BUFFER_BIT) { + glclearbit |= GL_STENCIL_BUFFER_BIT; } -} - -void RAS_OpenGLRasterizer::IndexPrimitives(RAS_MeshSlot& ms) -{ - if (ms.m_pDerivedMesh) - DrawDerivedMesh(ms); - else - m_storage->IndexPrimitives(ms); -} - -// Code for hooking into Blender's mesh drawing for derived meshes. -// If/when we use more of Blender's drawing code, we may be able to -// clean this up -static bool current_wireframe; -static RAS_MaterialBucket *current_bucket; -static RAS_IPolyMaterial *current_polymat; -static RAS_MeshSlot *current_ms; -static RAS_MeshObject *current_mesh; -static int current_blmat_nr; -static GPUVertexAttribs current_gpu_attribs; -static Image *current_image; -static int CheckMaterialDM(int matnr, void *attribs) -{ - // only draw the current material - if (matnr != current_blmat_nr) - return 0; - GPUVertexAttribs *gattribs = (GPUVertexAttribs *)attribs; - if (gattribs) - memcpy(gattribs, ¤t_gpu_attribs, sizeof(GPUVertexAttribs)); - return 1; -} - -static DMDrawOption CheckTexDM(MTexPoly *mtexpoly, const bool has_mcol, int matnr) -{ - // index is the original face index, retrieve the polygon - if (matnr == current_blmat_nr && - (mtexpoly == NULL || mtexpoly->tpage == current_image)) { - // must handle color. - if (current_wireframe) - return DM_DRAW_OPTION_NO_MCOL; - if (current_ms->m_bObjectColor) { - MT_Vector4& rgba = current_ms->m_RGBAcolor; - glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]); - // don't use mcol - return DM_DRAW_OPTION_NO_MCOL; - } - if (!has_mcol) { - // we have to set the color from the material - unsigned char rgba[4]; - current_polymat->GetMaterialRGBAColor(rgba); - glColor4ubv((const GLubyte *)rgba); - return DM_DRAW_OPTION_NORMAL; - } - return DM_DRAW_OPTION_NORMAL; - } - return DM_DRAW_OPTION_SKIP; + glClear(glclearbit); } -void RAS_OpenGLRasterizer::DrawDerivedMesh(class RAS_MeshSlot &ms) +void RAS_OpenGLRasterizer::SetClearColor(float r, float g, float b, float a) { - // mesh data is in derived mesh - current_bucket = ms.m_bucket; - current_polymat = current_bucket->GetPolyMaterial(); - current_ms = &ms; - current_mesh = ms.m_mesh; - current_wireframe = m_drawingmode <= RAS_IRasterizer::KX_WIREFRAME; - // MCol *mcol = (MCol*)ms.m_pDerivedMesh->getFaceDataArray(ms.m_pDerivedMesh, CD_MCOL); /* UNUSED */ - - // handle two-side - if (current_polymat->GetDrawingMode() & RAS_IRasterizer::KX_BACKCULL) - this->SetCullFace(true); - else - this->SetCullFace(false); - - if (current_polymat->GetFlag() & RAS_BLENDERGLSL) { - // GetMaterialIndex return the original mface material index, - // increment by 1 to match what derived mesh is doing - current_blmat_nr = current_polymat->GetMaterialIndex()+1; - // For GLSL we need to retrieve the GPU material attribute - Material* blmat = current_polymat->GetBlenderMaterial(); - Scene* blscene = current_polymat->GetBlenderScene(); - if (!current_wireframe && blscene && blmat) - GPU_material_vertex_attributes(GPU_material_from_blender(blscene, blmat, false), ¤t_gpu_attribs); - else - memset(¤t_gpu_attribs, 0, sizeof(current_gpu_attribs)); - // DM draw can mess up blending mode, restore at the end - int current_blend_mode = GPU_get_material_alpha_blend(); - ms.m_pDerivedMesh->drawFacesGLSL(ms.m_pDerivedMesh, CheckMaterialDM); - GPU_set_material_alpha_blend(current_blend_mode); - } else { - //ms.m_pDerivedMesh->drawMappedFacesTex(ms.m_pDerivedMesh, CheckTexfaceDM, mcol); - current_blmat_nr = current_polymat->GetMaterialIndex(); - current_image = current_polymat->GetBlenderImage(); - ms.m_pDerivedMesh->drawFacesTex(ms.m_pDerivedMesh, CheckTexDM, NULL, NULL, DM_DRAW_USE_ACTIVE_UV); - } + glClearColor(r, g, b, a); } -void RAS_OpenGLRasterizer::SetProjectionMatrix(MT_CmMatrix4x4 &mat) +void RAS_OpenGLRasterizer::SetClearDepth(float d) { - glMatrixMode(GL_PROJECTION); - float* matrix = &mat(0, 0); - glLoadMatrixf(matrix); - - m_camortho = (mat(3, 3) != 0.0f); + glClearDepth(d); } -void RAS_OpenGLRasterizer::SetProjectionMatrix(const MT_Matrix4x4 & mat) +void RAS_OpenGLRasterizer::SetColorMask(bool r, bool g, bool b, bool a) { - glMatrixMode(GL_PROJECTION); - float matrix[16]; - /* Get into argument. Looks a bit dodgy, but it's ok. */ - mat.getValue(matrix); - glLoadMatrixf(matrix); - - m_camortho = (mat[3][3] != 0.0f); -} - -MT_Matrix4x4 RAS_OpenGLRasterizer::GetFrustumMatrix( - float left, - float right, - float bottom, - float top, - float frustnear, - float frustfar, - float focallength, - bool -) { - MT_Matrix4x4 result; - float mat[16]; - - // correction for stereo - if (Stereo()) - { - float near_div_focallength; - float offset; - - // if Rasterizer.setFocalLength is not called we use the camera focallength - if (!m_setfocallength) - // if focallength is null we use a value known to be reasonable - m_focallength = (focallength == 0.f) ? m_eyeseparation * 30.0f - : focallength; - - near_div_focallength = frustnear / m_focallength; - offset = 0.5f * m_eyeseparation * near_div_focallength; - switch (m_curreye) { - case RAS_STEREO_LEFTEYE: - left += offset; - right += offset; - break; - case RAS_STEREO_RIGHTEYE: - left -= offset; - right -= offset; - break; - } - // leave bottom and top untouched - if (m_stereomode == RAS_STEREO_3DTVTOPBOTTOM) { - // restore the vertical frustum because the 3DTV will - // expand the top and bottom part to the full size of the screen - bottom *= 2.0f; - top *= 2.0f; - } - } - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glFrustum(left, right, bottom, top, frustnear, frustfar); - - glGetFloatv(GL_PROJECTION_MATRIX, mat); - result.setValue(mat); - - return result; -} - -MT_Matrix4x4 RAS_OpenGLRasterizer::GetOrthoMatrix( - float left, - float right, - float bottom, - float top, - float frustnear, - float frustfar -) { - MT_Matrix4x4 result; - float mat[16]; - - // stereo is meaningless for orthographic, disable it - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(left, right, bottom, top, frustnear, frustfar); - - glGetFloatv(GL_PROJECTION_MATRIX, mat); - result.setValue(mat); - - return result; + glColorMask(r ? GL_TRUE : GL_FALSE, g ? GL_TRUE : GL_FALSE, b ? GL_TRUE : GL_FALSE, a ? GL_TRUE : GL_FALSE); } - -// next arguments probably contain redundant info, for later... -void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat, - const MT_Matrix3x3 & camOrientMat3x3, - const MT_Point3 & pos, - const MT_Vector3 &scale, - bool perspective) +void RAS_OpenGLRasterizer::DrawOverlayPlane() { - m_viewmatrix = mat; - - // correction for stereo - if (Stereo() && perspective) - { - MT_Vector3 unitViewDir(0.0f, -1.0f, 0.0f); // minus y direction, Blender convention - MT_Vector3 unitViewupVec(0.0f, 0.0f, 1.0f); - MT_Vector3 viewDir, viewupVec; - MT_Vector3 eyeline; - - // actual viewDir - viewDir = camOrientMat3x3 * unitViewDir; // this is the moto convention, vector on right hand side - // actual viewup vec - viewupVec = camOrientMat3x3 * unitViewupVec; - - // vector between eyes - eyeline = viewDir.cross(viewupVec); - - switch (m_curreye) { - case RAS_STEREO_LEFTEYE: - { - // translate to left by half the eye distance - MT_Transform transform; - transform.setIdentity(); - transform.translate(-(eyeline * m_eyeseparation / 2.0f)); - m_viewmatrix *= transform; - } - break; - case RAS_STEREO_RIGHTEYE: - { - // translate to right by half the eye distance - MT_Transform transform; - transform.setIdentity(); - transform.translate(eyeline * m_eyeseparation / 2.0f); - m_viewmatrix *= transform; - } - break; - } - } - - bool negX = (scale[0] < 0.0f); - bool negY = (scale[1] < 0.0f); - bool negZ = (scale[2] < 0.0f); - if (negX || negY || negZ) { - m_viewmatrix.tscale((negX)?-1.0f:1.0f, (negY)?-1.0f:1.0f, (negZ)?-1.0f:1.0f, 1.0); - } - m_viewinvmatrix = m_viewmatrix; - m_viewinvmatrix.invert(); - - // note: getValue gives back column major as needed by OpenGL - MT_Scalar glviewmat[16]; - m_viewmatrix.getValue(glviewmat); - - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(glviewmat); - m_campos = pos; - m_camnegscale = negX ^ negY ^ negZ; + m_screenPlane.Render(); } - -const MT_Point3& RAS_OpenGLRasterizer::GetCameraPosition() +void RAS_OpenGLRasterizer::SetViewport(int x, int y, int width, int height) { - return m_campos; + glViewport(x, y, width, height); } -bool RAS_OpenGLRasterizer::GetCameraOrtho() +void RAS_OpenGLRasterizer::GetViewport(int *rect) { - return m_camortho; + glGetIntegerv(GL_VIEWPORT, rect); } -void RAS_OpenGLRasterizer::SetCullFace(bool enable) +void RAS_OpenGLRasterizer::SetScissor(int x, int y, int width, int height) { - if (enable) - glEnable(GL_CULL_FACE); - else - glDisable(GL_CULL_FACE); + glScissor(x, y, width, height); } void RAS_OpenGLRasterizer::SetLines(bool enable) { - if (enable) + if (enable) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - else + } + else { glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } } void RAS_OpenGLRasterizer::SetSpecularity(float specX, - float specY, - float specZ, - float specval) + float specY, + float specZ, + float specval) { GLfloat mat_specular[] = {specX, specY, specZ, specval}; glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular); } - - void RAS_OpenGLRasterizer::SetShinyness(float shiny) { - GLfloat mat_shininess[] = { shiny }; + GLfloat mat_shininess[] = { shiny }; glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess); } - - -void RAS_OpenGLRasterizer::SetDiffuse(float difX,float difY,float difZ,float diffuse) +void RAS_OpenGLRasterizer::SetDiffuse(float difX, float difY, float difZ, float diffuse) { - GLfloat mat_diffuse [] = {difX, difY,difZ, diffuse}; + GLfloat mat_diffuse[] = {difX, difY, difZ, diffuse}; glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse); } void RAS_OpenGLRasterizer::SetEmissive(float eX, float eY, float eZ, float e) { - GLfloat mat_emit [] = {eX,eY,eZ,e}; + GLfloat mat_emit[] = {eX, eY, eZ, e}; glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mat_emit); } - -double RAS_OpenGLRasterizer::GetTime() -{ - return m_time; -} - void RAS_OpenGLRasterizer::SetPolygonOffset(float mult, float add) { glPolygonOffset(mult, add); - GLint mode = GL_POLYGON_OFFSET_FILL; - if (m_drawingmode < KX_SHADED) - mode = GL_POLYGON_OFFSET_LINE; - if (mult != 0.0f || add != 0.0f) - glEnable(mode); - else - glDisable(mode); } -void RAS_OpenGLRasterizer::EnableMotionBlur(float motionblurvalue) +void RAS_OpenGLRasterizer::EnableClipPlane(unsigned short index, const mt::vec4& plane) { - /* don't just set m_motionblur to 1, but check if it is 0 so - * we don't reset a motion blur that is already enabled */ - if (m_motionblur == 0) - m_motionblur = 1; - m_motionblurvalue = motionblurvalue; + double planev[4] = {plane.x, plane.y, plane.z, plane.w}; + glClipPlane(GL_CLIP_PLANE0 + index, planev); + glEnable(GL_CLIP_PLANE0 + index); } -void RAS_OpenGLRasterizer::DisableMotionBlur() +void RAS_OpenGLRasterizer::DisableClipPlane(unsigned short index) { - m_motionblur = 0; - m_motionblurvalue = -1.0f; -} - -void RAS_OpenGLRasterizer::SetAlphaBlend(int alphablend) -{ - /* Variance shadow maps don't handle alpha well, best to not allow it for now */ - if (m_drawingmode == KX_SHADOW && m_usingoverrideshader) - GPU_set_material_alpha_blend(GPU_BLEND_SOLID); - else - GPU_set_material_alpha_blend(alphablend); -/* - if (alphablend == m_last_alphablend) - return; - - if (alphablend == GPU_BLEND_SOLID) { - glDisable(GL_BLEND); - glDisable(GL_ALPHA_TEST); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - else if (alphablend == GPU_BLEND_ADD) { - glBlendFunc(GL_ONE, GL_ONE); - glEnable(GL_BLEND); - glDisable(GL_ALPHA_TEST); - } - else if (alphablend == GPU_BLEND_ALPHA) { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, 0.0f); - } - else if (alphablend == GPU_BLEND_CLIP) { - glDisable(GL_BLEND); - glEnable(GL_ALPHA_TEST); - glAlphaFunc(GL_GREATER, 0.5f); - } - - m_last_alphablend = alphablend; -*/ + glDisable(GL_CLIP_PLANE0 + index); } void RAS_OpenGLRasterizer::SetFrontFace(bool ccw) { - if (m_camnegscale) - ccw = !ccw; - - if (m_last_frontface == ccw) - return; - - if (ccw) + if (ccw) { glFrontFace(GL_CCW); - else - glFrontFace(GL_CW); - - m_last_frontface = ccw; -} - -void RAS_OpenGLRasterizer::SetAnisotropicFiltering(short level) -{ - GPU_set_anisotropic(G_MAIN, (float)level); -} - -short RAS_OpenGLRasterizer::GetAnisotropicFiltering() -{ - return (short)GPU_get_anisotropic(); -} - -void RAS_OpenGLRasterizer::SetMipmapping(MipmapOption val) -{ - if (val == RAS_IRasterizer::RAS_MIPMAP_LINEAR) - { - GPU_set_linear_mipmap(1); - GPU_set_mipmap(G_MAIN, 1); - } - else if (val == RAS_IRasterizer::RAS_MIPMAP_NEAREST) - { - GPU_set_linear_mipmap(0); - GPU_set_mipmap(G_MAIN, 1); - } - else - { - GPU_set_linear_mipmap(0); - GPU_set_mipmap(G_MAIN, 0); - } -} - -RAS_IRasterizer::MipmapOption RAS_OpenGLRasterizer::GetMipmapping() -{ - if (GPU_get_mipmap()) { - if (GPU_get_linear_mipmap()) { - return RAS_IRasterizer::RAS_MIPMAP_LINEAR; - } - else { - return RAS_IRasterizer::RAS_MIPMAP_NEAREST; - } } else { - return RAS_IRasterizer::RAS_MIPMAP_NONE; - } -} - -void RAS_OpenGLRasterizer::SetUsingOverrideShader(bool val) -{ - m_usingoverrideshader = val; -} - -bool RAS_OpenGLRasterizer::GetUsingOverrideShader() -{ - return m_usingoverrideshader; -} - -/** - * Render Tools - */ - -/* ProcessLighting performs lighting on objects. the layer is a bitfield that - * contains layer information. There are 20 'official' layers in blender. A - * light is applied on an object only when they are in the same layer. OpenGL - * has a maximum of 8 lights (simultaneous), so 20 * 8 lights are possible in - * a scene. */ - -void RAS_OpenGLRasterizer::ProcessLighting(bool uselights, const MT_Transform& viewmat) -{ - bool enable = false; - int layer= -1; - - /* find the layer */ - if (uselights) { - if (m_clientobject) - layer = static_cast(m_clientobject)->GetLayer(); - } - - /* avoid state switching */ - if (m_lastlightlayer == layer && m_lastauxinfo == m_auxilaryClientInfo) - return; - - m_lastlightlayer = layer; - m_lastauxinfo = m_auxilaryClientInfo; - - /* enable/disable lights as needed */ - if (layer >= 0) { - //enable = ApplyLights(layer, viewmat); - // taken from blender source, incompatibility between Blender Object / GameObject - KX_Scene* kxscene = (KX_Scene*)m_auxilaryClientInfo; - float glviewmat[16]; - unsigned int count; - std::vector::iterator lit = m_lights.begin(); - - for (count=0; countApplyFixedFunctionLighting(kxscene, layer, count)) - count++; - } - glPopMatrix(); - - enable = count > 0; + glFrontFace(GL_CW); } - - if (enable) - EnableOpenGLLights(); - else - DisableOpenGLLights(); } -void RAS_OpenGLRasterizer::EnableOpenGLLights() +void RAS_OpenGLRasterizer::EnableLights() { - if (m_lastlighting == true) - return; - - glEnable(GL_LIGHTING); - glEnable(GL_COLOR_MATERIAL); - glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); - glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, (GetCameraOrtho())? GL_FALSE: GL_TRUE); - if (GLEW_EXT_separate_specular_color || GLEW_VERSION_1_2) - glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); - - m_lastlighting = true; -} - -void RAS_OpenGLRasterizer::DisableOpenGLLights() -{ - if (m_lastlighting == false) - return; - - glDisable(GL_LIGHTING); - glDisable(GL_COLOR_MATERIAL); - - m_lastlighting = false; -} - -RAS_ILightObject *RAS_OpenGLRasterizer::CreateLight() -{ - return new RAS_OpenGLLight(this); -} - -void RAS_OpenGLRasterizer::AddLight(RAS_ILightObject* lightobject) -{ - RAS_OpenGLLight* gllight = dynamic_cast(lightobject); - assert(gllight); - m_lights.push_back(gllight); + glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, (m_rasterizer->GetCameraOrtho()) ? GL_FALSE : GL_TRUE); } -void RAS_OpenGLRasterizer::RemoveLight(RAS_ILightObject* lightobject) +void RAS_OpenGLRasterizer::DisableForText() { - RAS_OpenGLLight* gllight = dynamic_cast(lightobject); - assert(gllight); - - std::vector::iterator lit = - std::find(m_lights.begin(),m_lights.end(),gllight); - - if (!(lit==m_lights.end())) - m_lights.erase(lit); -} + for (int i = 0; i < RAS_Texture::MaxUnits; i++) { + glActiveTextureARB(GL_TEXTURE0_ARB + i); -bool RAS_OpenGLRasterizer::RayHit(struct KX_ClientObjectInfo *client, KX_RayCast *result, float *oglmatrix) -{ - if (result->m_hitMesh) { - - RAS_Polygon* poly = result->m_hitMesh->GetPolygon(result->m_hitPolygon); - if (!poly->IsVisible()) - return false; - - MT_Vector3 resultnormal(result->m_hitNormal); - MT_Vector3 left(oglmatrix[0],oglmatrix[1],oglmatrix[2]); - MT_Vector3 dir = -(left.cross(resultnormal)).safe_normalized(); - left = (dir.cross(resultnormal)).safe_normalized(); - // for the up vector, we take the 'resultnormal' returned by the physics - - float maat[16] = {left[0], left[1], left[2], 0, - dir[0], dir[1], dir[2], 0, - resultnormal[0], resultnormal[1], resultnormal[2], 0, - 0, 0, 0, 1}; - - glTranslatef(oglmatrix[12],oglmatrix[13],oglmatrix[14]); - //glMultMatrixd(oglmatrix); - glMultMatrixf(maat); - return true; - } - else { - return false; - } -} - -void RAS_OpenGLRasterizer::applyTransform(float* oglmatrix,int objectdrawmode ) -{ - /* FIXME: - blender: intern/moto/include/MT_Vector3.inl:42: MT_Vector3 operator/(const - MT_Vector3&, double): Assertion `!MT_fuzzyZero(s)' failed. - - Program received signal SIGABRT, Aborted. - [Switching to Thread 16384 (LWP 1519)] - 0x40477571 in kill () from /lib/libc.so.6 - (gdb) bt - #7 0x08334368 in MT_Vector3::normalized() const () - #8 0x0833e6ec in RAS_OpenGLRasterizer::applyTransform(RAS_IRasterizer*, double*, int) () - */ - - if (objectdrawmode & RAS_IPolyMaterial::BILLBOARD_SCREENALIGNED || - objectdrawmode & RAS_IPolyMaterial::BILLBOARD_AXISALIGNED) - { - // rotate the billboard/halo - //page 360/361 3D Game Engine Design, David Eberly for a discussion - // on screen aligned and axis aligned billboards - // assumed is that the preprocessor transformed all billboard polygons - // so that their normal points into the positive x direction (1.0f, 0.0f, 0.0f) - // when new parenting for objects is done, this rotation - // will be moved into the object - - MT_Point3 objpos (oglmatrix[12],oglmatrix[13],oglmatrix[14]); - MT_Point3 campos = GetCameraPosition(); - MT_Vector3 dir = (campos - objpos).safe_normalized(); - MT_Vector3 up(0,0,1.0f); - - KX_GameObject* gameobj = (KX_GameObject*)m_clientobject; - // get scaling of halo object - MT_Vector3 size = gameobj->GetSGNode()->GetWorldScaling(); - - bool screenaligned = (objectdrawmode & RAS_IPolyMaterial::BILLBOARD_SCREENALIGNED)!=0;//false; //either screen or axisaligned - if (screenaligned) - { - up = (up - up.dot(dir) * dir).safe_normalized(); - } else - { - dir = (dir - up.dot(dir)*up).safe_normalized(); - } - - MT_Vector3 left = dir.normalized(); - dir = (up.cross(left)).normalized(); - - // we have calculated the row vectors, now we keep - // local scaling into account: - - left *= size[0]; - dir *= size[1]; - up *= size[2]; - - float maat[16] = {left[0], left[1], left[2], 0, - dir[0], dir[1], dir[2], 0, - up[0], up[1], up[2], 0, - 0, 0, 0, 1}; - - glTranslatef(objpos[0],objpos[1],objpos[2]); - glMultMatrixf(maat); - - } - else { - if (objectdrawmode & RAS_IPolyMaterial::SHADOW) - { - // shadow must be cast to the ground, physics system needed here! - MT_Point3 frompoint(oglmatrix[12],oglmatrix[13],oglmatrix[14]); - KX_GameObject *gameobj = (KX_GameObject*)m_clientobject; - MT_Vector3 direction = MT_Vector3(0,0,-1); - - direction.normalize(); - direction *= 100000; - - MT_Point3 topoint = frompoint + direction; - - KX_Scene* kxscene = (KX_Scene*) m_auxilaryClientInfo; - PHY_IPhysicsEnvironment* physics_environment = kxscene->GetPhysicsEnvironment(); - PHY_IPhysicsController* physics_controller = gameobj->GetPhysicsController(); - - KX_GameObject *parent = gameobj->GetParent(); - if (!physics_controller && parent) - physics_controller = parent->GetPhysicsController(); - - KX_RayCast::Callback callback(this, physics_controller, oglmatrix); - if (!KX_RayCast::RayTest(physics_environment, frompoint, topoint, callback)) - { - // couldn't find something to cast the shadow on... - glMultMatrixf(oglmatrix); - } - else - { // we found the "ground", but the cast matrix doesn't take - // scaling in consideration, so we must apply the object scale - MT_Vector3 size = gameobj->GetSGNode()->GetLocalScale(); - glScalef(size[0], size[1], size[2]); - } - } else - { - - // 'normal' object - glMultMatrixf(oglmatrix); + if (GLEW_ARB_texture_cube_map) { + Disable(RAS_Rasterizer::RAS_TEXTURE_CUBE_MAP); } + Disable(RAS_Rasterizer::RAS_TEXTURE_2D); } -} -static void DisableForText() -{ - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); /* needed for texture fonts otherwise they render as wireframe */ - - glDisable(GL_BLEND); - glDisable(GL_ALPHA_TEST); - - glDisable(GL_LIGHTING); - glDisable(GL_COLOR_MATERIAL); - - if (GLEW_ARB_multitexture) { - for (int i=0; iDisableForText(); + SetFrontFace(true); /* the actual drawing */ glColor4fv(color); /* multiply the text matrix by the object matrix */ - BLF_enable(fontid, BLF_MATRIX|BLF_ASPECT); + BLF_enable(fontid, BLF_MATRIX | BLF_ASPECT); BLF_matrix(fontid, mat); /* aspect is the inverse scale that allows you to increase @@ -1561,163 +423,126 @@ void RAS_OpenGLRasterizer::RenderText3D( BLF_size(fontid, size, dpi); BLF_position(fontid, 0, 0, 0); - BLF_draw(fontid, text, 65535); + BLF_draw(fontid, text.c_str(), text.size()); - BLF_disable(fontid, BLF_MATRIX|BLF_ASPECT); + BLF_disable(fontid, BLF_MATRIX | BLF_ASPECT); + + m_rasterizer->SetAlphaBlend(GPU_BLEND_SOLID); } -void RAS_OpenGLRasterizer::RenderText2D( - RAS_TEXT_RENDER_MODE mode, - const char* text, - int xco, int yco, - int width, int height) +void RAS_OpenGLRasterizer::PushMatrix() { - /* This is a rather important line :( The gl-mode hasn't been left - * behind quite as neatly as we'd have wanted to. I don't know - * what cause it, though :/ .*/ - DisableForText(); - glDisable(GL_DEPTH_TEST); - - glMatrixMode(GL_PROJECTION); glPushMatrix(); - glLoadIdentity(); - - glOrtho(0, width, 0, height, -100, 100); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); +} - if (mode == RAS_TEXT_PADDED) { - /* draw in black first */ - glColor3ub(0, 0, 0); - BLF_size(blf_mono_font, 11, 72); - BLF_position(blf_mono_font, (float)xco+1, (float)(height-yco-1), 0.0f); - BLF_draw(blf_mono_font, text, 65535); /* XXX, use real len */ - } +void RAS_OpenGLRasterizer::PopMatrix() +{ + glPopMatrix(); +} - /* the actual drawing */ - glColor3ub(255, 255, 255); - BLF_size(blf_mono_font, 11, 72); - BLF_position(blf_mono_font, (float)xco, (float)(height-yco), 0.0f); - BLF_draw(blf_mono_font, text, 65535); /* XXX, use real len */ +void RAS_OpenGLRasterizer::SetMatrixMode(RAS_Rasterizer::MatrixMode mode) +{ + glMatrixMode(openGLMatrixModeEnums[mode]); +} - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - glEnable(GL_DEPTH_TEST); +void RAS_OpenGLRasterizer::MultMatrix(const float mat[16]) +{ + glMultMatrixf(mat); } -void RAS_OpenGLRasterizer::PushMatrix() +void RAS_OpenGLRasterizer::LoadMatrix(const float mat[16]) { - glPushMatrix(); + glLoadMatrixf(mat); } -void RAS_OpenGLRasterizer::PopMatrix() +void RAS_OpenGLRasterizer::LoadIdentity() { - glPopMatrix(); + glLoadIdentity(); } -void RAS_OpenGLRasterizer::MotionBlur() +void RAS_OpenGLRasterizer::MotionBlur(unsigned short state, float value) { - int state = GetMotionBlurState(); - float motionblurvalue; - if (state) - { - motionblurvalue = GetMotionBlurValue(); - if (state==1) - { + if (state) { + if (state == 1) { // bugfix:load color buffer into accum buffer for the first time(state=1) glAccum(GL_LOAD, 1.0f); - SetMotionBlurState(2); + m_rasterizer->SetMotionBlur(2); } - else if (motionblurvalue >= 0.0f && motionblurvalue <= 1.0f) { - glAccum(GL_MULT, motionblurvalue); - glAccum(GL_ACCUM, 1-motionblurvalue); + else if (value >= 0.0f && value <= 1.0f) { + glAccum(GL_MULT, value); + glAccum(GL_ACCUM, 1.0f - value); glAccum(GL_RETURN, 1.0f); glFlush(); } } } -void RAS_OpenGLRasterizer::SetClientObject(void* obj) -{ - if (m_clientobject != obj) - { - bool ccw = (obj == NULL || !((KX_GameObject*)obj)->IsNegativeScaling()); - SetFrontFace(ccw); - - m_clientobject = obj; - } -} - -void RAS_OpenGLRasterizer::SetAuxilaryClientInfo(void* inf) -{ - m_auxilaryClientInfo = inf; -} - void RAS_OpenGLRasterizer::PrintHardwareInfo() { - #define pprint(x) std::cout << x << std::endl; - - pprint("GL_VENDOR: " << glGetString(GL_VENDOR)); - pprint("GL_RENDERER: " << glGetString(GL_RENDERER)); - pprint("GL_VERSION: " << glGetString(GL_VERSION)); - bool support=0; - pprint("Supported Extensions..."); - pprint(" GL_ARB_shader_objects supported? "<< (GLEW_ARB_shader_objects?"yes.":"no.")); - - support= GLEW_ARB_vertex_shader; - pprint(" GL_ARB_vertex_shader supported? "<< (support?"yes.":"no.")); + CM_Message("GL_VENDOR: " << glGetString(GL_VENDOR)); + CM_Message("GL_RENDERER: " << glGetString(GL_RENDERER)); + CM_Message("GL_VERSION: " << glGetString(GL_VERSION)); + CM_Message("GL_SHADING_LANGUAGE_VERSION: " << glGetString(GL_SHADING_LANGUAGE_VERSION)); + bool support = 0; + CM_Message("Supported Extensions..."); + CM_Message(" GL_ARB_shader_objects supported? " << (GLEW_ARB_shader_objects ? "yes." : "no.")); + CM_Message(" GL_ARB_geometry_shader4 supported? " << (GLEW_ARB_geometry_shader4 ? "yes." : "no.")); + + support = GLEW_ARB_vertex_shader; + CM_Message(" GL_ARB_vertex_shader supported? " << (support ? "yes." : "no.")); if (support) { - pprint(" ----------Details----------"); - int max=0; - glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, (GLint*)&max); - pprint(" Max uniform components." << max); + CM_Message(" ----------Details----------"); + int max = 0; + glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, (GLint *)&max); + CM_Message(" Max uniform components." << max); - glGetIntegerv(GL_MAX_VARYING_FLOATS_ARB, (GLint*)&max); - pprint(" Max varying floats." << max); + glGetIntegerv(GL_MAX_VARYING_FLOATS_ARB, (GLint *)&max); + CM_Message(" Max varying floats." << max); - glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, (GLint*)&max); - pprint(" Max vertex texture units." << max); + glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, (GLint *)&max); + CM_Message(" Max vertex texture units." << max); - glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, (GLint*)&max); - pprint(" Max combined texture units." << max); - pprint(""); + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, (GLint *)&max); + CM_Message(" Max vertex attribs." << max); + + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, (GLint *)&max); + CM_Message(" Max combined texture units." << max); + CM_Message(""); } - support=GLEW_ARB_fragment_shader; - pprint(" GL_ARB_fragment_shader supported? "<< (support?"yes.":"no.")); + support = GLEW_ARB_fragment_shader; + CM_Message(" GL_ARB_fragment_shader supported? " << (support ? "yes." : "no.")); if (support) { - pprint(" ----------Details----------"); - int max=0; - glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, (GLint*)&max); - pprint(" Max uniform components." << max); - pprint(""); + CM_Message(" ----------Details----------"); + int max = 0; + glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, (GLint *)&max); + CM_Message(" Max uniform components." << max); + CM_Message(""); } support = GLEW_ARB_texture_cube_map; - pprint(" GL_ARB_texture_cube_map supported? "<< (support?"yes.":"no.")); + CM_Message(" GL_ARB_texture_cube_map supported? " << (support ? "yes." : "no.")); if (support) { - pprint(" ----------Details----------"); - int size=0; - glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, (GLint*)&size); - pprint(" Max cubemap size." << size); - pprint(""); + CM_Message(" ----------Details----------"); + int size = 0; + glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, (GLint *)&size); + CM_Message(" Max cubemap size." << size); + CM_Message(""); } support = GLEW_ARB_multitexture; - pprint(" GL_ARB_multitexture supported? "<< (support?"yes.":"no.")); + CM_Message(" GL_ARB_multitexture supported? " << (support ? "yes." : "no.")); if (support) { - pprint(" ----------Details----------"); - int units=0; - glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, (GLint*)&units); - pprint(" Max texture units available. " << units); - pprint(""); + CM_Message(" ----------Details----------"); + int units = 0; + glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, (GLint *)&units); + CM_Message(" Max texture units available. " << units); + CM_Message(""); } - pprint(" GL_ARB_texture_env_combine supported? "<< (GLEW_ARB_texture_env_combine?"yes.":"no.")); + CM_Message(" GL_ARB_texture_env_combine supported? " << (GLEW_ARB_texture_env_combine ? "yes." : "no.")); + + CM_Message(" GL_ARB_texture_non_power_of_two supported? " << (GPU_full_non_power_of_two_support() ? "yes." : "no.")); - pprint(" GL_ARB_texture_non_power_of_two supported " << (GPU_full_non_power_of_two_support()?"yes.":"no.")); + CM_Message(" GL_ARB_draw_instanced supported? " << (GLEW_ARB_draw_instanced ? "yes." : "no.")); } diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h index b288c3c5d8f5..92f31f8cf739 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h @@ -36,308 +36,107 @@ # pragma warning (disable:4786) #endif -#include "MT_CmMatrix4x4.h" -#include -#include -using namespace std; - -#include "RAS_IRasterizer.h" -#include "RAS_MaterialBucket.h" -#include "RAS_IPolygonMaterial.h" - -#include "BLI_utildefines.h" - -class RAS_IStorage; -class RAS_ICanvas; -class RAS_OpenGLLight; - -#define RAS_MAX_TEXCO 8 /* match in BL_Material */ -#define RAS_MAX_ATTRIB 16 /* match in BL_BlenderShader */ - -enum RAS_STORAGE_TYPE { - RAS_AUTO_STORAGE, - RAS_VA, - RAS_VBO, -}; - -struct OglDebugShape -{ - enum SHAPE_TYPE{ - LINE, - CIRCLE, - }; - SHAPE_TYPE m_type; - MT_Vector3 m_pos; - MT_Vector3 m_param; - MT_Vector3 m_param2; - MT_Vector3 m_color; -}; +#include "RAS_Rasterizer.h" /** * 3D rendering device context. */ -class RAS_OpenGLRasterizer : public RAS_IRasterizer +class RAS_OpenGLRasterizer { - RAS_ICanvas *m_2DCanvas; - - /* fogging vars */ - bool m_fogenabled; - - float m_redback; - float m_greenback; - float m_blueback; - float m_alphaback; - - float m_ambr; - float m_ambg; - float m_ambb; - double m_time; - MT_Matrix4x4 m_viewmatrix; - MT_Matrix4x4 m_viewinvmatrix; - MT_Point3 m_campos; - bool m_camortho; - bool m_camnegscale; - - StereoMode m_stereomode; - StereoEye m_curreye; - float m_eyeseparation; - float m_focallength; - bool m_setfocallength; - int m_noOfScanlines; - - short m_prevafvalue; - - /* motion blur */ - int m_motionblur; - float m_motionblurvalue; - - bool m_usingoverrideshader; +private: + class ScreenPlane + { + private: + unsigned int m_vbo; + unsigned int m_ibo; + unsigned int m_vao; - /* Render tools */ - void *m_clientobject; - void *m_auxilaryClientInfo; - std::vector m_lights; - int m_lastlightlayer; - bool m_lastlighting; - void *m_lastauxinfo; - unsigned int m_numgllights; + public: + ScreenPlane(); + ~ScreenPlane(); -protected: - int m_drawingmode; - TexCoGen m_texco[RAS_MAX_TEXCO]; - TexCoGen m_attrib[RAS_MAX_ATTRIB]; - int m_attrib_layer[RAS_MAX_ATTRIB]; - int m_texco_num; - int m_attrib_num; - /* int m_last_alphablend; */ - bool m_last_frontface; + void Render(); + }; - /* Stores the caching information for the last material activated. */ - RAS_IPolyMaterial::TCachingInfo m_materialCachingInfo; + /// Class used to render a screen plane. + ScreenPlane m_screenPlane; - /* Making use of a Strategy design pattern for storage behavior. - * Examples of concrete strategies: Vertex Arrays, VBOs, Immediate Mode*/ - int m_storage_type; - RAS_IStorage *m_storage; + RAS_Rasterizer *m_rasterizer; public: - double GetTime(); - RAS_OpenGLRasterizer(RAS_ICanvas *canv, RAS_STORAGE_TYPE storage); + RAS_OpenGLRasterizer(RAS_Rasterizer *rasterizer); virtual ~RAS_OpenGLRasterizer(); - /*enum DrawType - { - KX_BOUNDINGBOX = 1, - KX_WIREFRAME, - KX_SOLID, - KX_SHADED, - KX_TEXTURED - }; - - enum DepthMask - { - KX_DEPTHMASK_ENABLED =1, - KX_DEPTHMASK_DISABLED, - };*/ - virtual void SetDepthMask(DepthMask depthmask); - - virtual bool SetMaterial(const RAS_IPolyMaterial &mat); - virtual bool Init(); - virtual void Exit(); - virtual bool BeginFrame(double time); - virtual void ClearColorBuffer(); - virtual void ClearDepthBuffer(); - virtual void ClearCachingInfo(void); - virtual void EndFrame(); - virtual void SetRenderArea(); - - virtual void SetStereoMode(const StereoMode stereomode); - virtual RAS_IRasterizer::StereoMode GetStereoMode(); - virtual bool Stereo(); - virtual bool InterlacedStereo(); - virtual void SetEye(const StereoEye eye); - virtual StereoEye GetEye(); - virtual void SetEyeSeparation(const float eyeseparation); - virtual float GetEyeSeparation(); - virtual void SetFocalLength(const float focallength); - virtual float GetFocalLength(); - virtual RAS_IOffScreen *CreateOffScreen(int width, int height, int samples, int target); - virtual RAS_ISync *CreateSync(int type); - virtual void SwapBuffers(); - - virtual void IndexPrimitives(class RAS_MeshSlot &ms); - virtual void IndexPrimitives_3DText(class RAS_MeshSlot &ms, class RAS_IPolyMaterial *polymat); - virtual void DrawDerivedMesh(class RAS_MeshSlot &ms); - - virtual void SetProjectionMatrix(MT_CmMatrix4x4 &mat); - virtual void SetProjectionMatrix(const MT_Matrix4x4 &mat); - virtual void SetViewMatrix( - const MT_Matrix4x4 &mat, - const MT_Matrix3x3 &ori, - const MT_Point3 &pos, - const MT_Vector3 &scale, - bool perspective); - - virtual const MT_Point3& GetCameraPosition(); - virtual bool GetCameraOrtho(); - - virtual void SetFog(short type, float start, float dist, float intensity, float color[3]); - virtual void EnableFog(bool enable); - virtual void DisplayFog(); + unsigned short GetNumLights() const; - virtual void SetBackColor(float color[3]); + void Enable(RAS_Rasterizer::EnableBit bit); + void Disable(RAS_Rasterizer::EnableBit bit); + void EnableLight(unsigned short count); + void DisableLight(unsigned short count); - virtual void SetDrawingMode(int drawingmode); - virtual int GetDrawingMode(); + void SetDepthFunc(RAS_Rasterizer::DepthFunc func); + void SetDepthMask(RAS_Rasterizer::DepthMask depthmask); - virtual void SetCullFace(bool enable); - virtual void SetLines(bool enable); + void SetBlendFunc(RAS_Rasterizer::BlendFunc src, RAS_Rasterizer::BlendFunc dst); - virtual MT_Matrix4x4 GetFrustumMatrix( - float left, float right, float bottom, float top, - float frustnear, float frustfar, - float focallength, bool perspective); - virtual MT_Matrix4x4 GetOrthoMatrix( - float left, float right, float bottom, float top, - float frustnear, float frustfar); + unsigned int *MakeScreenshot(int x, int y, int width, int height); - virtual void SetSpecularity(float specX, float specY, float specZ, float specval); - virtual void SetShinyness(float shiny); - virtual void SetDiffuse(float difX, float difY, float difZ, float diffuse); - virtual void SetEmissive(float eX, float eY, float eZ, float e); + void Init(); + void Exit(); + void DrawOverlayPlane(); + void BeginFrame(); + void Clear(int clearbit); + void SetClearColor(float r, float g, float b, float a=1.0f); + void SetClearDepth(float d); + void SetColorMask(bool r, bool g, bool b, bool a); + void EndFrame(); - virtual void SetAmbientColor(float color[3]); - virtual void SetAmbient(float factor); + void SetViewport(int x, int y, int width, int height); + void GetViewport(int *rect); + void SetScissor(int x, int y, int width, int height); - virtual void SetPolygonOffset(float mult, float add); + void SetFog(short type, float start, float dist, float intensity, const mt::vec3& color); - virtual void FlushDebugShapes(SCA_IScene *scene); + void SetLines(bool enable); - virtual void DrawDebugLine(SCA_IScene *scene, const MT_Vector3 &from,const MT_Vector3 &to, const MT_Vector3 &color) - { - OglDebugShape line; - line.m_type = OglDebugShape::LINE; - line.m_pos= from; - line.m_param = to; - line.m_color = color; - m_debugShapes[scene].push_back(line); - } - - virtual void DrawDebugCircle(SCA_IScene *scene, const MT_Vector3 ¢er, const MT_Scalar radius, - const MT_Vector3 &color, const MT_Vector3 &normal, int nsector) - { - OglDebugShape line; - line.m_type = OglDebugShape::CIRCLE; - line.m_pos= center; - line.m_param = normal; - line.m_color = color; - line.m_param2.x() = radius; - line.m_param2.y() = (float) nsector; - m_debugShapes[scene].push_back(line); - } + void SetSpecularity(float specX, float specY, float specZ, float specval); + void SetShinyness(float shiny); + void SetDiffuse(float difX, float difY, float difZ, float diffuse); + void SetEmissive(float eX, float eY, float eZ, float e); - // We store each debug shape by scene. - std::map > m_debugShapes; + void SetAmbient(const mt::vec3& amb, float factor); - virtual void SetTexCoordNum(int num); - virtual void SetAttribNum(int num); - virtual void SetTexCoord(TexCoGen coords, int unit); - virtual void SetAttrib(TexCoGen coords, int unit, int layer = 0); + void SetPolygonOffset(float mult, float add); - void TexCoord(const RAS_TexVert &tv); - - const MT_Matrix4x4 &GetViewMatrix() const; - const MT_Matrix4x4 &GetViewInvMatrix() const; - - virtual void EnableMotionBlur(float motionblurvalue); - virtual void DisableMotionBlur(); - virtual float GetMotionBlurValue() { return m_motionblurvalue; } - virtual int GetMotionBlurState() { return m_motionblur; } - virtual void SetMotionBlurState(int newstate) - { - if (newstate < 0) - m_motionblur = 0; - else if (newstate > 2) - m_motionblur = 2; - else - m_motionblur = newstate; - } + void EnableClipPlane(unsigned short index, const mt::vec4& plane); + void DisableClipPlane(unsigned short index); - virtual void SetAlphaBlend(int alphablend); - virtual void SetFrontFace(bool ccw); - - virtual void SetAnisotropicFiltering(short level); - virtual short GetAnisotropicFiltering(); - - virtual void SetMipmapping(MipmapOption val); - virtual MipmapOption GetMipmapping(); - - virtual void SetUsingOverrideShader(bool val); - virtual bool GetUsingOverrideShader(); + void SetFrontFace(bool ccw); /** * Render Tools */ - void EnableOpenGLLights(); - void DisableOpenGLLights(); - void ProcessLighting(bool uselights, const MT_Transform &viewmat); + void EnableLights(); + void DisableLights(); + void ProcessLighting(bool uselights, const mt::mat3x4 &viewmat); - void RenderBox2D(int xco, int yco, int width, int height, float percentage); - void RenderText3D(int fontid, const char *text, int size, int dpi, + void DisableForText(); + void RenderText3D(int fontid, const std::string& text, int size, int dpi, const float color[4], const float mat[16], float aspect); - void RenderText2D(RAS_TEXT_RENDER_MODE mode, const char *text, - int xco, int yco, int width, int height); - - void applyTransform(float *oglmatrix, int objectdrawmode); void PushMatrix(); void PopMatrix(); + void MultMatrix(const float mat[16]); + void SetMatrixMode(RAS_Rasterizer::MatrixMode mode); + void LoadMatrix(const float mat[16]); + void LoadIdentity(); - /// \see KX_RayCast - bool RayHit(struct KX_ClientObjectInfo *client, class KX_RayCast *result, float *oglmatrix); - /// \see KX_RayCast - bool NeedRayCast(struct KX_ClientObjectInfo *, void *UNUSED(data)) { return true; } - - RAS_ILightObject* CreateLight(); - void AddLight(RAS_ILightObject* lightobject); - - void RemoveLight(RAS_ILightObject* lightobject); - int ApplyLights(int objectlayer, const MT_Transform& viewmat); - - void MotionBlur(); - - void SetClientObject(void *obj); - - void SetAuxilaryClientInfo(void *inf); + void MotionBlur(unsigned short state, float value); /** * Prints information about what the hardware supports. */ - virtual void PrintHardwareInfo(); - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_OpenGLRasterizer") -#endif + void PrintHardwareInfo(); }; #endif /* __RAS_OPENGLRASTERIZER_H__ */ diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp index 26b956cd74e3..55cb92fd17e9 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp @@ -27,12 +27,12 @@ #include "GPU_glew.h" -#include +#include "CM_Message.h" #include "RAS_OpenGLSync.h" RAS_OpenGLSync::RAS_OpenGLSync() - :m_sync(NULL) + :m_sync(nullptr) { } @@ -44,20 +44,20 @@ RAS_OpenGLSync::~RAS_OpenGLSync() bool RAS_OpenGLSync::Create(RAS_SYNC_TYPE type) { if (m_sync) { - printf("RAS_OpenGLSync::Create(): sync already exists, destroy first\n"); + CM_FunctionError("sync already exists, destroy first"); return false; } if (type != RAS_SYNC_TYPE_FENCE) { - printf("RAS_OpenGLSync::Create(): only RAS_SYNC_TYPE_FENCE are currently supported\n"); + CM_FunctionError("only RAS_SYNC_TYPE_FENCE are currently supported"); return false; } if (!GLEW_ARB_sync) { - printf("RAS_OpenGLSync::Create(): ARB_sync extension is needed to create sync object\n"); + CM_FunctionError("ARB_sync extension is needed to create sync object"); return false; } m_sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); if (!m_sync) { - printf("RAS_OpenGLSync::Create(): glFenceSync() failed"); + CM_FunctionError("glFenceSync() failed"); return false; } return true; @@ -67,7 +67,7 @@ void RAS_OpenGLSync::Destroy() { if (m_sync) { glDeleteSync(m_sync); - m_sync = NULL; + m_sync = nullptr; } } diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp deleted file mode 100644 index 85fab3753b40..000000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp +++ /dev/null @@ -1,259 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "RAS_StorageVA.h" - -#include "GPU_glew.h" - -RAS_StorageVA::RAS_StorageVA(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib, int *attrib_layer) : - m_drawingmode(RAS_IRasterizer::KX_TEXTURED), - m_texco_num(texco_num), - m_attrib_num(attrib_num), - m_last_texco_num(0), - m_last_attrib_num(0), - m_texco(texco), - m_attrib(attrib), - m_attrib_layer(attrib_layer) -{ -} - -RAS_StorageVA::~RAS_StorageVA() -{ -} - -bool RAS_StorageVA::Init() -{ - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - return true; -} - -void RAS_StorageVA::Exit() -{ -} - -void RAS_StorageVA::IndexPrimitives(class RAS_MeshSlot& ms) -{ - static const GLsizei stride = sizeof(RAS_TexVert); - bool wireframe = m_drawingmode <= RAS_IRasterizer::KX_WIREFRAME, use_color_array = true; - RAS_MeshSlot::iterator it; - GLenum drawmode; - - if (!wireframe) - EnableTextures(true); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - - // use glDrawElements to draw each vertexarray - for (ms.begin(it); !ms.end(it); ms.next(it)) { - if (it.totindex == 0) - continue; - - // drawing mode - if (it.array->m_type == RAS_DisplayArray::TRIANGLE) - drawmode = GL_TRIANGLES; - else if (it.array->m_type == RAS_DisplayArray::QUAD) - drawmode = GL_QUADS; - else - drawmode = GL_LINES; - - // colors - if (drawmode != GL_LINES && !wireframe) { - if (ms.m_bObjectColor) { - const MT_Vector4& rgba = ms.m_RGBAcolor; - - glDisableClientState(GL_COLOR_ARRAY); - glColor4d(rgba[0], rgba[1], rgba[2], rgba[3]); - use_color_array = false; - } - else { - glColor4f(0.0f, 0.0f, 0.0f, 1.0f); - glEnableClientState(GL_COLOR_ARRAY); - use_color_array = true; - } - } - else - glColor4f(0.0f, 0.0f, 0.0f, 1.0f); - - glVertexPointer(3, GL_FLOAT, stride, it.vertex->getXYZ()); - glNormalPointer(GL_FLOAT, stride, it.vertex->getNormal()); - - if (!wireframe) { - TexCoordPtr(it.vertex); - if (use_color_array) - glColorPointer(4, GL_UNSIGNED_BYTE, stride, it.vertex->getRGBA()); - } - - // here the actual drawing takes places - glDrawElements(drawmode, it.totindex, GL_UNSIGNED_SHORT, it.index); - } - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - if (!wireframe) { - glDisableClientState(GL_COLOR_ARRAY); - EnableTextures(false); - } -} - -void RAS_StorageVA::TexCoordPtr(const RAS_TexVert *tv) -{ - /* note: this function must closely match EnableTextures to enable/disable - * the right arrays, otherwise coordinate and attribute pointers from other - * materials can still be used and cause crashes */ - int unit; - - if (GLEW_ARB_multitexture) - { - for (unit = 0; unit < *m_texco_num; unit++) - { - glClientActiveTextureARB(GL_TEXTURE0_ARB+unit); - switch (m_texco[unit]) { - case RAS_IRasterizer::RAS_TEXCO_ORCO: - case RAS_IRasterizer::RAS_TEXCO_GLOB: - glTexCoordPointer(3, GL_FLOAT, sizeof(RAS_TexVert),tv->getXYZ()); - break; - case RAS_IRasterizer::RAS_TEXCO_UV: - glTexCoordPointer(2, GL_FLOAT, sizeof(RAS_TexVert),tv->getUV(unit)); - break; - case RAS_IRasterizer::RAS_TEXCO_NORM: - glTexCoordPointer(3, GL_FLOAT, sizeof(RAS_TexVert),tv->getNormal()); - break; - case RAS_IRasterizer::RAS_TEXTANGENT: - glTexCoordPointer(4, GL_FLOAT, sizeof(RAS_TexVert),tv->getTangent()); - break; - default: - break; - } - } - - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - - if (GLEW_ARB_vertex_program) { - for (unit = 0; unit < *m_attrib_num; unit++) { - switch (m_attrib[unit]) { - case RAS_IRasterizer::RAS_TEXCO_ORCO: - case RAS_IRasterizer::RAS_TEXCO_GLOB: - glVertexAttribPointerARB(unit, 3, GL_FLOAT, GL_FALSE, sizeof(RAS_TexVert), tv->getXYZ()); - break; - case RAS_IRasterizer::RAS_TEXCO_UV: - glVertexAttribPointerARB(unit, 2, GL_FLOAT, GL_FALSE, sizeof(RAS_TexVert), tv->getUV(m_attrib_layer[unit])); - break; - case RAS_IRasterizer::RAS_TEXCO_NORM: - glVertexAttribPointerARB(unit, 3, GL_FLOAT, GL_FALSE, sizeof(RAS_TexVert), tv->getNormal()); - break; - case RAS_IRasterizer::RAS_TEXTANGENT: - glVertexAttribPointerARB(unit, 4, GL_FLOAT, GL_FALSE, sizeof(RAS_TexVert), tv->getTangent()); - break; - case RAS_IRasterizer::RAS_TEXCO_VCOL: - glVertexAttribPointerARB(unit, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(RAS_TexVert), tv->getRGBA()); - break; - default: - break; - } - } - } -} - -void RAS_StorageVA::EnableTextures(bool enable) -{ - RAS_IRasterizer::TexCoGen *texco, *attrib; - int unit, texco_num, attrib_num; - - /* we cache last texcoords and attribs to ensure we disable the ones that - * were actually last set */ - if (enable) { - texco = m_texco; - texco_num = *m_texco_num; - attrib = m_attrib; - attrib_num = *m_attrib_num; - - memcpy(m_last_texco, m_texco, sizeof(RAS_IRasterizer::TexCoGen)*(*m_texco_num)); - m_last_texco_num = *m_texco_num; - memcpy(m_last_attrib, m_attrib, sizeof(RAS_IRasterizer::TexCoGen)*(*m_attrib_num)); - m_last_attrib_num = *m_attrib_num; - } - else { - texco = m_last_texco; - texco_num = m_last_texco_num; - attrib = m_last_attrib; - attrib_num = m_last_attrib_num; - } - - if (GLEW_ARB_multitexture) { - for (unit = 0; unit < texco_num; unit++) { - glClientActiveTextureARB(GL_TEXTURE0_ARB + unit); - - switch (texco[unit]) { - case RAS_IRasterizer::RAS_TEXCO_ORCO: - case RAS_IRasterizer::RAS_TEXCO_GLOB: - case RAS_IRasterizer::RAS_TEXCO_UV: - case RAS_IRasterizer::RAS_TEXCO_NORM: - case RAS_IRasterizer::RAS_TEXTANGENT: - if (enable) glEnableClientState(GL_TEXTURE_COORD_ARRAY); - else glDisableClientState(GL_TEXTURE_COORD_ARRAY); - break; - default: - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - break; - } - } - - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - else { - if (texco_num) { - if (enable) glEnableClientState(GL_TEXTURE_COORD_ARRAY); - else glDisableClientState(GL_TEXTURE_COORD_ARRAY); - } - } - - if (GLEW_ARB_vertex_program) { - for (unit = 0; unit < attrib_num; unit++) { - switch (attrib[unit]) { - case RAS_IRasterizer::RAS_TEXCO_ORCO: - case RAS_IRasterizer::RAS_TEXCO_GLOB: - case RAS_IRasterizer::RAS_TEXCO_UV: - case RAS_IRasterizer::RAS_TEXCO_NORM: - case RAS_IRasterizer::RAS_TEXTANGENT: - case RAS_IRasterizer::RAS_TEXCO_VCOL: - if (enable) glEnableVertexAttribArrayARB(unit); - else glDisableVertexAttribArrayARB(unit); - break; - default: - glDisableVertexAttribArrayARB(unit); - break; - } - } - } - - if (!enable) { - m_last_texco_num = 0; - m_last_attrib_num = 0; - } -} diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h deleted file mode 100644 index a5a3170ed77f..000000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef __KX_VERTEXARRAYSTORAGE -#define __KX_VERTEXARRAYSTORAGE - -#include "RAS_IStorage.h" -#include "RAS_IRasterizer.h" - -#include "RAS_OpenGLRasterizer.h" - -class RAS_StorageVA : public RAS_IStorage -{ - -public: - RAS_StorageVA(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib, int *attrib_layer); - virtual ~RAS_StorageVA(); - - virtual bool Init(); - virtual void Exit(); - - virtual void IndexPrimitives(RAS_MeshSlot& ms); - - virtual void SetDrawingMode(int drawingmode) {m_drawingmode = drawingmode;}; - -protected: - int m_drawingmode; - - int* m_texco_num; - int* m_attrib_num; - - int m_last_texco_num; - int m_last_attrib_num; - - RAS_IRasterizer::TexCoGen* m_texco; - RAS_IRasterizer::TexCoGen* m_attrib; - int* m_attrib_layer; - - RAS_IRasterizer::TexCoGen m_last_texco[RAS_MAX_TEXCO]; - RAS_IRasterizer::TexCoGen m_last_attrib[RAS_MAX_ATTRIB]; - - virtual void EnableTextures(bool enable); - virtual void TexCoordPtr(const RAS_TexVert *tv); - - -#ifdef WITH_CXX_GUARDEDALLOC -public: - void *operator new(size_t num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_StorageVA"); } - void operator delete( void *mem ) { MEM_freeN(mem); } -#endif -}; - -#endif //__KX_VERTEXARRAYSTORAGE diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp deleted file mode 100644 index 4ba5882a46e2..000000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#include "RAS_StorageVBO.h" -#include "RAS_MeshObject.h" - -#include "GPU_glew.h" - -VBO::VBO(RAS_DisplayArray *data, unsigned int indices) -{ - this->data = data; - this->size = data->m_vertex.size(); - this->indices = indices; - this->stride = sizeof(RAS_TexVert); - - // Determine drawmode - if (data->m_type == data->QUAD) - this->mode = GL_QUADS; - else if (data->m_type == data->TRIANGLE) - this->mode = GL_TRIANGLES; - else - this->mode = GL_LINE; - - // Generate Buffers - glGenBuffersARB(1, &this->ibo); - glGenBuffersARB(1, &this->vbo_id); - - // Fill the buffers with initial data - UpdateIndices(); - UpdateData(); - - // Establish offsets - this->vertex_offset = (void*)(((RAS_TexVert*)0)->getXYZ()); - this->normal_offset = (void*)(((RAS_TexVert*)0)->getNormal()); - this->tangent_offset = (void*)(((RAS_TexVert*)0)->getTangent()); - this->color_offset = (void*)(((RAS_TexVert*)0)->getRGBA()); - this->uv_offset = (void*)(((RAS_TexVert*)0)->getUV(0)); -} - -VBO::~VBO() -{ - glDeleteBuffersARB(1, &this->ibo); - glDeleteBuffersARB(1, &this->vbo_id); -} - -void VBO::UpdateData() -{ - glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->vbo_id); - glBufferData(GL_ARRAY_BUFFER, this->stride*this->size, &this->data->m_vertex[0], GL_STATIC_DRAW); -} - -void VBO::UpdateIndices() -{ - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, this->ibo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, data->m_index.size() * sizeof(GLushort), - &data->m_index[0], GL_STATIC_DRAW); -} - -void VBO::Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num, RAS_IRasterizer::TexCoGen* attrib, int *attrib_layer) -{ - int unit; - - // Bind buffers - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, this->ibo); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, this->vbo_id); - - // Vertexes - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, this->stride, this->vertex_offset); - - // Normals - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, this->stride, this->normal_offset); - - // Colors - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(4, GL_UNSIGNED_BYTE, this->stride, this->color_offset); - - for (unit = 0; unit < texco_num; ++unit) - { - glClientActiveTexture(GL_TEXTURE0_ARB + unit); - switch (texco[unit]) { - case RAS_IRasterizer::RAS_TEXCO_ORCO: - case RAS_IRasterizer::RAS_TEXCO_GLOB: - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(3, GL_FLOAT, this->stride, this->vertex_offset); - break; - case RAS_IRasterizer::RAS_TEXCO_UV: - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, this->stride, (void*)((intptr_t)this->uv_offset+(sizeof(GLfloat)*2*unit))); - break; - case RAS_IRasterizer::RAS_TEXCO_NORM: - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(3, GL_FLOAT, this->stride, this->normal_offset); - break; - case RAS_IRasterizer::RAS_TEXTANGENT: - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(4, GL_FLOAT, this->stride, this->tangent_offset); - break; - default: - break; - } - } - glClientActiveTextureARB(GL_TEXTURE0_ARB); - - if (GLEW_ARB_vertex_program) - { - for (unit = 0; unit < attrib_num; ++unit) - { - switch (attrib[unit]) { - case RAS_IRasterizer::RAS_TEXCO_ORCO: - case RAS_IRasterizer::RAS_TEXCO_GLOB: - glVertexAttribPointerARB(unit, 3, GL_FLOAT, GL_FALSE, this->stride, this->vertex_offset); - glEnableVertexAttribArrayARB(unit); - break; - case RAS_IRasterizer::RAS_TEXCO_UV: - glVertexAttribPointerARB(unit, 2, GL_FLOAT, GL_FALSE, this->stride, (void*)((intptr_t)this->uv_offset+attrib_layer[unit]*sizeof(GLfloat)*2)); - glEnableVertexAttribArrayARB(unit); - break; - case RAS_IRasterizer::RAS_TEXCO_NORM: - glVertexAttribPointerARB(unit, 2, GL_FLOAT, GL_FALSE, stride, this->normal_offset); - glEnableVertexAttribArrayARB(unit); - break; - case RAS_IRasterizer::RAS_TEXTANGENT: - glVertexAttribPointerARB(unit, 4, GL_FLOAT, GL_FALSE, this->stride, this->tangent_offset); - glEnableVertexAttribArrayARB(unit); - break; - case RAS_IRasterizer::RAS_TEXCO_VCOL: - glVertexAttribPointerARB(unit, 4, GL_UNSIGNED_BYTE, GL_TRUE, this->stride, this->color_offset); - glEnableVertexAttribArrayARB(unit); - default: - break; - } - } - } - - glDrawElements(this->mode, this->indices, GL_UNSIGNED_SHORT, 0); - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - if (GLEW_ARB_vertex_program) - { - for (int i = 0; i < attrib_num; ++i) - glDisableVertexAttribArrayARB(i); - } - - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); -} - -RAS_StorageVBO::RAS_StorageVBO(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib, int *attrib_layer): - m_drawingmode(RAS_IRasterizer::KX_TEXTURED), - m_texco_num(texco_num), - m_attrib_num(attrib_num), - m_texco(texco), - m_attrib(attrib), - m_attrib_layer(attrib_layer) -{ -} - -RAS_StorageVBO::~RAS_StorageVBO() -{ -} - -bool RAS_StorageVBO::Init() -{ - return true; -} - -void RAS_StorageVBO::Exit() -{ - VBOMap::iterator it = m_vbo_lookup.begin(); - while (it != m_vbo_lookup.end()) { - delete it->second; - ++it; - } - m_vbo_lookup.clear(); -} - -void RAS_StorageVBO::IndexPrimitives(RAS_MeshSlot& ms) -{ - RAS_MeshSlot::iterator it; - VBO *vbo; - - for (ms.begin(it); !ms.end(it); ms.next(it)) - { - vbo = m_vbo_lookup[it.array]; - - if (vbo == 0) - m_vbo_lookup[it.array] = vbo = new VBO(it.array, it.totindex); - - // Update the vbo - if (ms.m_mesh->MeshModified()) - { - vbo->UpdateData(); - } - - vbo->Draw(*m_texco_num, m_texco, *m_attrib_num, m_attrib, m_attrib_layer); - } -} diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h deleted file mode 100644 index c82b6a3206d4..000000000000 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifndef __KX_VERTEXBUFFEROBJECTSTORAGE -#define __KX_VERTEXBUFFEROBJECTSTORAGE - -#include -#include "GPU_glew.h" - -#include "RAS_IStorage.h" -#include "RAS_IRasterizer.h" - -#include "RAS_OpenGLRasterizer.h" - -class VBO -{ -public: - VBO(RAS_DisplayArray *data, unsigned int indices); - ~VBO(); - - void Draw(int texco_num, RAS_IRasterizer::TexCoGen* texco, int attrib_num, RAS_IRasterizer::TexCoGen* attrib, int *attrib_layer); - - void UpdateData(); - void UpdateIndices(); -private: - RAS_DisplayArray* data; - GLuint size; - GLuint stride; - GLuint indices; - GLenum mode; - GLuint ibo; - GLuint vbo_id; - - void* vertex_offset; - void* normal_offset; - void* color_offset; - void* tangent_offset; - void* uv_offset; -}; - -typedef std::map VBOMap; - -class RAS_StorageVBO : public RAS_IStorage -{ - -public: - RAS_StorageVBO(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib, int *attrib_layer); - virtual ~RAS_StorageVBO(); - - virtual bool Init(); - virtual void Exit(); - - virtual void IndexPrimitives(RAS_MeshSlot& ms); - - virtual void SetDrawingMode(int drawingmode) {m_drawingmode = drawingmode;}; - -protected: - int m_drawingmode; - - int* m_texco_num; - int* m_attrib_num; - - RAS_IRasterizer::TexCoGen* m_texco; - RAS_IRasterizer::TexCoGen* m_attrib; - int* m_attrib_layer; - - VBOMap m_vbo_lookup; - -#ifdef WITH_CXX_GUARDEDALLOC -public: - void *operator new(size_t num_bytes) { return MEM_mallocN(num_bytes, "GE:RAS_StorageVA"); } - void operator delete( void *mem ) { MEM_freeN(mem); } -#endif -}; - -#endif //__KX_VERTEXBUFFEROBJECTSTORAGE diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVao.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVao.cpp new file mode 100644 index 000000000000..29cc6870ff3a --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVao.cpp @@ -0,0 +1,132 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "RAS_DisplayArray.h" +#include "RAS_DisplayArrayStorage.h" +#include "RAS_StorageVao.h" +#include "RAS_StorageVbo.h" + +struct AttribData { + int size; + GLenum type; + bool normalized; +}; + +static const AttribData attribData[RAS_AttributeArray::RAS_ATTRIB_MAX] = { + {3, GL_FLOAT, false}, // RAS_ATTRIB_POS + {2, GL_FLOAT, false}, // RAS_ATTRIB_UV + {3, GL_FLOAT, false}, // RAS_ATTRIB_NORM + {4, GL_FLOAT, false}, // RAS_ATTRIB_TANGENT + {4, GL_UNSIGNED_BYTE, true} // RAS_ATTRIB_COLOR +}; + +RAS_StorageVao::RAS_StorageVao(const RAS_DisplayArrayLayout &layout, RAS_DisplayArrayStorage *arrayStorage, + const RAS_AttributeArray::AttribList& attribList) +{ + glGenVertexArrays(1, &m_id); + glBindVertexArray(m_id); + + RAS_StorageVbo *vbo = arrayStorage->GetVbo(); + vbo->BindVertexBuffer(); + vbo->BindIndexBuffer(); + + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, (const void *)layout.position); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, (const void *)layout.normal); + + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(4, GL_UNSIGNED_BYTE, 0, (const void *)layout.colors[0]); + + for (const RAS_AttributeArray::Attrib& attrib : attribList) { + const RAS_AttributeArray::AttribType type = attrib.m_type; + intptr_t offset = 0; + switch (type) { + case RAS_AttributeArray::RAS_ATTRIB_POS: + { + offset = layout.position; + break; + } + case RAS_AttributeArray::RAS_ATTRIB_UV: + { + offset = layout.uvs[attrib.m_layer]; + break; + } + case RAS_AttributeArray::RAS_ATTRIB_NORM: + { + offset = layout.normal; + break; + } + case RAS_AttributeArray::RAS_ATTRIB_TANGENT: + { + offset = layout.tangent; + break; + } + case RAS_AttributeArray::RAS_ATTRIB_COLOR: + { + offset = layout.colors[attrib.m_layer]; + break; + } + default: + { + BLI_assert(false); + break; + } + } + + const unsigned short loc = attrib.m_loc; + const AttribData& data = attribData[type]; + + if (attrib.m_texco) { + glClientActiveTexture(GL_TEXTURE0 + loc); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(data.size, data.type, 0, (const void *)offset); + } + else { + glEnableVertexAttribArray(loc); + glVertexAttribPointer(loc, data.size, data.type, data.normalized, 0, (const void *)offset); + } + } + + glClientActiveTexture(GL_TEXTURE0); + + // VBO are not tracked by the VAO excepted for IBO. + vbo->UnbindVertexBuffer(); + + glBindVertexArray(0); +} + +RAS_StorageVao::~RAS_StorageVao() +{ + glDeleteVertexArrays(1, &m_id); +} + +void RAS_StorageVao::BindPrimitives() +{ + glBindVertexArray(m_id); +} + +void RAS_StorageVao::UnbindPrimitives() +{ + glBindVertexArray(0); +} diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVao.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVao.h new file mode 100644 index 000000000000..a2a7743d852b --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVao.h @@ -0,0 +1,47 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __RAS_STORAGE_VAO_H__ +#define __RAS_STORAGE_VAO_H__ + +#include "RAS_AttributeArray.h" +#include "RAS_DisplayArray.h" + +#include "GPU_glew.h" + +struct RAS_DisplayArrayLayout; + +class RAS_StorageVao +{ +public: + RAS_StorageVao(const RAS_DisplayArrayLayout &layout, RAS_DisplayArrayStorage *arrayStorage, + const RAS_AttributeArray::AttribList& attribList); + ~RAS_StorageVao(); + + void BindPrimitives(); + void UnbindPrimitives(); + +private: + GLuint m_id; +}; + +#endif // __RAS_STORAGE_VAO_H__ diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVbo.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVbo.cpp new file mode 100644 index 000000000000..c29e1896bd4e --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVbo.cpp @@ -0,0 +1,148 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "RAS_StorageVbo.h" +#include "RAS_DisplayArray.h" + +RAS_StorageVbo::RAS_StorageVbo(RAS_DisplayArray *array) + :m_array(array), + m_indices(0), + m_mode(m_array->GetOpenGLPrimitiveType()) +{ + glGenBuffers(1, &m_ibo); + glGenBuffers(1, &m_vbo); +} + +RAS_StorageVbo::~RAS_StorageVbo() +{ + glDeleteBuffers(1, &m_ibo); + glDeleteBuffers(1, &m_vbo); +} + +void RAS_StorageVbo::BindVertexBuffer() +{ + glBindBuffer(GL_ARRAY_BUFFER, m_vbo); +} + +void RAS_StorageVbo::UnbindVertexBuffer() +{ + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +void RAS_StorageVbo::BindIndexBuffer() +{ + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo); +} + +void RAS_StorageVbo::UnbindIndexBuffer() +{ + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} + +template +static void copySubData(intptr_t offset, const std::vector& data) +{ + const unsigned int size = sizeof(Item) * data.size(); + glBufferSubData(GL_ARRAY_BUFFER, offset, size, data.data()); +} + +void RAS_StorageVbo::CopyVertexData(const RAS_DisplayArrayLayout& layout, unsigned int modifiedFlag) +{ + const RAS_DisplayArray::Format& format = m_array->GetFormat(); + const RAS_DisplayArray::VertexData& data = m_array->m_vertexData; + + if (modifiedFlag & RAS_DisplayArray::POSITION_MODIFIED) { + copySubData(layout.position, data.positions); + } + if (modifiedFlag & RAS_DisplayArray::NORMAL_MODIFIED) { + copySubData(layout.normal, data.normals); + } + if (modifiedFlag & RAS_DisplayArray::TANGENT_MODIFIED) { + copySubData(layout.tangent, data.tangents); + } + + if (modifiedFlag & RAS_DisplayArray::UVS_MODIFIED) { + for (unsigned short i = 0; i < format.uvSize; ++i) { + copySubData(layout.uvs[i], data.uvs[i]); + } + } + + if (modifiedFlag & RAS_DisplayArray::COLORS_MODIFIED) { + for (unsigned short i = 0; i < format.colorSize; ++i) { + copySubData(layout.colors[i], data.colors[i]); + } + } +} + +void RAS_StorageVbo::UpdateVertexData(unsigned int modifiedFlag) +{ + glBindBuffer(GL_ARRAY_BUFFER, m_vbo); + CopyVertexData(m_array->GetLayout(), modifiedFlag); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +void RAS_StorageVbo::UpdateSize() +{ + m_indices = m_array->GetPrimitiveIndexCount(); + + const RAS_DisplayArrayLayout layout = m_array->GetLayout(); + glBindBuffer(GL_ARRAY_BUFFER, m_vbo); + glBufferData(GL_ARRAY_BUFFER, layout.size, nullptr, GL_DYNAMIC_DRAW); + CopyVertexData(layout, RAS_DisplayArray::MESH_MODIFIED); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indices * sizeof(GLuint), m_array->m_primitiveIndices.data(), GL_DYNAMIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} + +unsigned int *RAS_StorageVbo::GetIndexMap() +{ + void *buffer = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, m_indices * sizeof(GLuint), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + + return (unsigned int *)buffer; +} + +void RAS_StorageVbo::FlushIndexMap() +{ + glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); +} + +void RAS_StorageVbo::IndexPrimitives() +{ + glDrawElements(m_mode, m_indices, GL_UNSIGNED_INT, 0); +} + +void RAS_StorageVbo::IndexPrimitivesInstancing(unsigned int numinstance) +{ + glDrawElementsInstancedARB(m_mode, m_indices, GL_UNSIGNED_INT, 0, numinstance); +} + +void RAS_StorageVbo::IndexPrimitivesBatching(const std::vector& indices, const std::vector& counts) +{ + glMultiDrawElements(m_mode, counts.data(), GL_UNSIGNED_INT, (const void **)indices.data(), counts.size()); +} diff --git a/source/gameengine/Ketsji/KX_IInterpolator.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVbo.h similarity index 53% rename from source/gameengine/Ketsji/KX_IInterpolator.h rename to source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVbo.h index 37d8ca9455cd..fe6706d19d5f 100644 --- a/source/gameengine/Ketsji/KX_IInterpolator.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVbo.h @@ -25,31 +25,46 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file KX_IInterpolator.h - * \ingroup ketsji - */ +#ifndef __RAS_STORAGE_VBO_H__ +#define __RAS_STORAGE_VBO_H__ -#ifndef __KX_IINTERPOLATOR_H__ -#define __KX_IINTERPOLATOR_H__ +#include "GPU_glew.h" #include -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif +struct RAS_DisplayArrayLayout; +class RAS_DisplayArray; + +class RAS_StorageVbo +{ +private: + RAS_DisplayArray *m_array; + unsigned int m_indices; + GLenum m_mode; + GLuint m_ibo; + GLuint m_vbo; + + void CopyVertexData(const RAS_DisplayArrayLayout& layout, unsigned int modifiedFlag); -class KX_IInterpolator { public: - virtual ~KX_IInterpolator() {} + RAS_StorageVbo(RAS_DisplayArray *array); + ~RAS_StorageVbo(); + + void BindVertexBuffer(); + void UnbindVertexBuffer(); - virtual void Execute(float currentTime) const = 0; + void BindIndexBuffer(); + void UnbindIndexBuffer(); + void UpdateVertexData(unsigned int modifiedFlag); + void UpdateSize(); + unsigned int *GetIndexMap(); + void FlushIndexMap(); -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:KX_IInterpolator") -#endif + void IndexPrimitives(); + void IndexPrimitivesInstancing(unsigned int numinstance); + void IndexPrimitivesBatching(const std::vector& indices, const std::vector& counts); }; -typedef std::vector T_InterpolatorList; -#endif +#endif // __RAS_STORAGE_VBO_H__ diff --git a/source/gameengine/Rasterizer/RAS_Polygon.cpp b/source/gameengine/Rasterizer/RAS_Polygon.cpp deleted file mode 100644 index 4ed9b20f3253..000000000000 --- a/source/gameengine/Rasterizer/RAS_Polygon.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Rasterizer/RAS_Polygon.cpp - * \ingroup bgerast - */ - -#ifdef _MSC_VER -# pragma warning (disable:4786) -#endif - -#include "RAS_Polygon.h" -#include "RAS_MaterialBucket.h" - -RAS_Polygon::RAS_Polygon(RAS_MaterialBucket* bucket, RAS_DisplayArray *darray, int numvert) -{ - m_bucket = bucket; - m_darray = darray; - m_offset[0] = m_offset[1] = m_offset[2] = m_offset[3] = 0; - m_numvert = numvert; - -// m_edgecode = 255; - m_polyflags = 0; -} - -int RAS_Polygon::VertexCount() -{ - return m_numvert; -} - -void RAS_Polygon::SetVertexOffset(int i, unsigned short offset) -{ - m_offset[i] = offset; -} - -RAS_TexVert *RAS_Polygon::GetVertex(int i) -{ - return &m_darray->m_vertex[m_offset[i]]; -} - -unsigned int RAS_Polygon::GetVertexOffsetAbsolute(unsigned short i) -{ - return m_offset[i] + m_darray->m_offset; -} - -/* -int RAS_Polygon::GetEdgeCode() -{ - return m_edgecode; -} - -void RAS_Polygon::SetEdgeCode(int edgecode) -{ - m_edgecode = edgecode; -}*/ - - -bool RAS_Polygon::IsVisible() -{ - return (m_polyflags & VISIBLE) != 0; -} - -void RAS_Polygon::SetVisible(bool visible) -{ - if (visible) m_polyflags |= VISIBLE; - else m_polyflags &= ~VISIBLE; -} - -bool RAS_Polygon::IsCollider() -{ - return (m_polyflags & COLLIDER) != 0; -} - -void RAS_Polygon::SetCollider(bool visible) -{ - if (visible) m_polyflags |= COLLIDER; - else m_polyflags &= ~COLLIDER; -} - -bool RAS_Polygon::IsTwoside() -{ - return (m_polyflags & TWOSIDE) != 0; -} - -void RAS_Polygon::SetTwoside(bool twoside) -{ - if (twoside) m_polyflags |= TWOSIDE; - else m_polyflags &= ~TWOSIDE; -} - -RAS_MaterialBucket* RAS_Polygon::GetMaterial() -{ - return m_bucket; -} - -RAS_DisplayArray* RAS_Polygon::GetDisplayArray() -{ - return m_darray; -} diff --git a/source/gameengine/Rasterizer/RAS_Polygon.h b/source/gameengine/Rasterizer/RAS_Polygon.h deleted file mode 100644 index 7fed42ff24a3..000000000000 --- a/source/gameengine/Rasterizer/RAS_Polygon.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file RAS_Polygon.h - * \ingroup bgerast - */ - -#ifndef __RAS_POLYGON_H__ -#define __RAS_POLYGON_H__ - -class RAS_DisplayArray; -class RAS_MaterialBucket; -class RAS_TexVert; - -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -/* polygon flags */ - -class RAS_Polygon -{ - /* location */ - RAS_MaterialBucket* m_bucket; - RAS_DisplayArray* m_darray; - unsigned short m_offset[4]; - unsigned short m_numvert; - - /* flags */ -#if 1 - unsigned short m_polyflags; -#else - unsigned char m_edgecode; - unsigned char m_polyflags; -#endif - -public: - enum { - VISIBLE = 1, - COLLIDER = 2, - TWOSIDE = 4 - }; - - RAS_Polygon(RAS_MaterialBucket* bucket, RAS_DisplayArray* darray, int numvert); - virtual ~RAS_Polygon() {}; - - int VertexCount(); - RAS_TexVert* GetVertex(int i); - - void SetVertexOffset(int i, unsigned short offset); - unsigned int GetVertexOffsetAbsolute(unsigned short i); - - // each bit is for a visible edge, starting with bit 1 for the first edge, bit 2 for second etc. - // - Not used yet! -/* int GetEdgeCode(); - void SetEdgeCode(int edgecode); */ - - bool IsVisible(); - void SetVisible(bool visible); - - bool IsCollider(); - void SetCollider(bool collider); - - bool IsTwoside(); - void SetTwoside(bool twoside); - - RAS_MaterialBucket* GetMaterial(); - RAS_DisplayArray* GetDisplayArray(); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_Polygon") -#endif -}; - -#endif diff --git a/source/gameengine/Expressions/intern/HashedPtr.cpp b/source/gameengine/Rasterizer/RAS_Query.cpp similarity index 58% rename from source/gameengine/Expressions/intern/HashedPtr.cpp rename to source/gameengine/Rasterizer/RAS_Query.cpp index 11d9482f9938..9690d5aafa59 100644 --- a/source/gameengine/Expressions/intern/HashedPtr.cpp +++ b/source/gameengine/Rasterizer/RAS_Query.cpp @@ -15,43 +15,58 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): Tristan Porteries. * * ***** END GPL LICENSE BLOCK ***** */ -/** \file gameengine/Expressions/KX_HashedPtr.cpp - * \ingroup expressions +/** \file RAS_Query.cpp + * \ingroup bgerast */ +#include "RAS_Query.h" +#include "RAS_OpenGLQuery.h" + +RAS_Query::RAS_Query() +{ +} + + +RAS_Query::RAS_Query(QueryType type) + :m_impl(new RAS_OpenGLQuery(type)) +{ +} -#include "EXP_HashedPtr.h" +RAS_Query::~RAS_Query() = default; +RAS_Query::RAS_Query(RAS_Query&& other) + :m_impl(std::move(other.m_impl)) +{ +} -CHashedPtr::CHashedPtr(void* val) : m_valptr(val) +void RAS_Query::Begin() { + m_impl->Begin(); } +void RAS_Query::End() +{ + m_impl->End(); +} -unsigned int CHashedPtr::hash() const +bool RAS_Query::Available() { -#if defined(_WIN64) - unsigned __int64 key = (unsigned __int64)m_valptr; -#else - unsigned long key = (unsigned long)m_valptr; -#endif + return m_impl->Available(); +} - key += ~(key << 16); - key ^= (key >> 5); - key += (key << 3); - key ^= (key >> 13); - key += ~(key << 9); - key ^= (key >> 17); +int RAS_Query::ResultNoWait() +{ + return m_impl->ResultNoWait(); +} - return (unsigned int)(key & 0xffffffff); +int RAS_Query::Result() +{ + return m_impl->Result(); } diff --git a/source/gameengine/Rasterizer/RAS_Query.h b/source/gameengine/Rasterizer/RAS_Query.h new file mode 100644 index 000000000000..a0d668baa5c6 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_Query.h @@ -0,0 +1,74 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is: all of this file. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_Query.h + * \ingroup bgerast + */ + +#ifndef __RAS_QUERY_H__ +#define __RAS_QUERY_H__ + +#include + +class RAS_OpenGLQuery; + +/** \brief Rasterizer query to access some rasterizer information like + * the number of samples passed, the number of primitives generated or the + * time spent to render. + */ +class RAS_Query +{ +private: + std::unique_ptr m_impl; + +public: + enum QueryType { + SAMPLES = 0, + ANY_SAMPLES, + ANY_SAMPLES_CONSERVATIVE, + PRIMITIVES, + TIME + }; + + RAS_Query(); + RAS_Query(QueryType type); + ~RAS_Query(); + + RAS_Query(const RAS_Query& other) = delete; + RAS_Query(RAS_Query&& other); + + /// Begin the query. + void Begin(); + /// End the query and made the functions Available, ResultNoWait and Result usable. + void End(); + + /// \return True when the query result is ready. + bool Available(); + /// \return The value of the query even if the query is not ready. + int ResultNoWait(); + /// \return The value of the query and wait in case the query result is not ready. + int Result(); +}; + +#endif // __RAS_QUERY_H__ diff --git a/source/gameengine/Rasterizer/RAS_Rasterizer.cpp b/source/gameengine/Rasterizer/RAS_Rasterizer.cpp new file mode 100644 index 000000000000..d1ca1e39de39 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_Rasterizer.cpp @@ -0,0 +1,1508 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Rasterizer/RAS_Rasterizer.cpp + * \ingroup bgerastogl + */ + +#include "RAS_Rasterizer.h" +#include "RAS_OpenGLRasterizer.h" +#include "RAS_OpenGLDebugDraw.h" +#include "RAS_IMaterial.h" +#include "RAS_DisplayArrayBucket.h" +#include "RAS_InstancingBuffer.h" + +#include "RAS_ICanvas.h" +#include "RAS_OffScreen.h" +#include "RAS_Rect.h" +#include "RAS_TextUser.h" +#include "RAS_ILightObject.h" + +#include "RAS_OpenGLLight.h" +#include "RAS_OpenGLSync.h" + +#include "GPU_draw.h" +#include "GPU_extensions.h" +#include "GPU_material.h" +#include "GPU_shader.h" +#include "GPU_framebuffer.h" +#include "GPU_texture.h" + +#include "BLI_math_vector.h" + +extern "C" { +# include "BKE_global.h" +# include "BLF_api.h" +} + +#include "MEM_guardedalloc.h" + +// XXX Clean these up <<< +#include "KX_RayCast.h" +#include "KX_GameObject.h" +// >>> + +#include "CM_Message.h" +#include "CM_List.h" + +RAS_Rasterizer::OffScreens::OffScreens() + :m_width(0), + m_height(0), + m_samples(0), + m_hdr(RAS_HDR_NONE) +{ +} + +RAS_Rasterizer::OffScreens::~OffScreens() +{ +} + +inline void RAS_Rasterizer::OffScreens::Update(RAS_ICanvas *canvas) +{ + const unsigned int width = canvas->GetWidth(); + const unsigned int height = canvas->GetHeight(); + + if (width == m_width && height == m_height) { + // No resize detected. + return; + } + + m_width = width; + m_height = height; + m_samples = canvas->GetSamples(); + m_hdr = canvas->GetHdrType(); + + // Destruct all off screens. + for (unsigned short i = 0; i < RAS_Rasterizer::RAS_OFFSCREEN_MAX; ++i) { + m_offScreens[i].reset(nullptr); + } +} + +inline RAS_OffScreen *RAS_Rasterizer::OffScreens::GetOffScreen(OffScreenType type) +{ + if (!m_offScreens[type]) { + // The offscreen need to be created now. + + // Check if the off screen type can support samples. + const bool sampleofs = type == RAS_OFFSCREEN_EYE_LEFT0 || + type == RAS_OFFSCREEN_EYE_RIGHT0; + + /* Some GPUs doesn't support high multisample value with GL_RGBA16F or GL_RGBA32F. + * To avoid crashing we check if the off screen was created and if not decremente + * the multisample value and try to create the off screen to find a supported value. + */ + for (int samples = m_samples; samples >= 0; --samples) { + // Get off screen mode : render buffer support for multisampled off screen. + GPUOffScreenMode mode = GPU_OFFSCREEN_MODE_NONE; + if (sampleofs && (samples > 0)) { + mode = (GPUOffScreenMode)(GPU_OFFSCREEN_RENDERBUFFER_COLOR | GPU_OFFSCREEN_RENDERBUFFER_DEPTH); + } + + // WARNING: Always respect the order from RAS_Rasterizer::HdrType. + static const GPUHDRType hdrEnums[] = { + GPU_HDR_NONE, // RAS_HDR_NONE + GPU_HDR_HALF_FLOAT, // RAS_HDR_HALF_FLOAT + GPU_HDR_FULL_FLOAT // RAS_HDR_FULL_FLOAT + }; + + RAS_OffScreen *ofs = new RAS_OffScreen(m_width, m_height, sampleofs ? samples : 0, hdrEnums[m_hdr], mode, nullptr, type); + if (!ofs->GetValid()) { + delete ofs; + continue; + } + + m_offScreens[type].reset(ofs); + m_samples = samples; + break; + } + + /* Creating an off screen restore the default frame buffer object. + * We have to rebind the last off screen. */ + RAS_OffScreen *lastOffScreen = RAS_OffScreen::GetLastOffScreen(); + if (lastOffScreen) { + lastOffScreen->Bind(); + } + } + + return m_offScreens[type].get(); +} + +RAS_Rasterizer::OffScreenType RAS_Rasterizer::NextFilterOffScreen(RAS_Rasterizer::OffScreenType index) +{ + switch (index) { + case RAS_OFFSCREEN_FILTER0: + { + return RAS_OFFSCREEN_FILTER1; + } + case RAS_OFFSCREEN_FILTER1: + // Passing a non-filter frame buffer is allowed. + default: + { + return RAS_OFFSCREEN_FILTER0; + } + } +} + +RAS_Rasterizer::OffScreenType RAS_Rasterizer::NextRenderOffScreen(RAS_Rasterizer::OffScreenType index) +{ + switch (index) { + case RAS_OFFSCREEN_EYE_LEFT0: + { + return RAS_OFFSCREEN_EYE_LEFT1; + } + case RAS_OFFSCREEN_EYE_LEFT1: + { + return RAS_OFFSCREEN_EYE_LEFT0; + } + case RAS_OFFSCREEN_EYE_RIGHT0: + { + return RAS_OFFSCREEN_EYE_RIGHT1; + } + case RAS_OFFSCREEN_EYE_RIGHT1: + { + return RAS_OFFSCREEN_EYE_RIGHT0; + } + // Passing a non-eye frame buffer is disallowed. + default: + { + BLI_assert(false); + return RAS_OFFSCREEN_EYE_LEFT0; + } + } +} + +// Each shader used to draw the offscreen to screen by color management. +GPUBuiltinShader offScreenToScreenShaderTable[RAS_Rasterizer::RAS_SHADER_TO_SCREEN_MAX][RAS_Rasterizer::RAS_COLOR_MANAGEMENT_MAX] = { + // Linear, sRGB + {GPU_SHADER_DRAW_FRAME_BUFFER, GPU_SHADER_DRAW_FRAME_BUFFER_SRGB}, // Normal + {GPU_SHADER_STEREO_STIPPLE, GPU_SHADER_STEREO_STIPPLE_SRGB}, // Stereo stipple + {GPU_SHADER_STEREO_ANAGLYPH, GPU_SHADER_STEREO_ANAGLYPH_SRGB} // Stereo anaglyph +}; + +RAS_Rasterizer::RAS_Rasterizer() + :m_time(0.0f), + m_ambient(mt::zero3), + m_viewmatrix(mt::mat4::Identity()), + m_viewinvmatrix(mt::mat4::Identity()), + m_campos(mt::zero3), + m_camortho(false), + m_camnegscale(false), + m_stereomode(RAS_STEREO_NOSTEREO), + m_curreye(RAS_STEREO_LEFTEYE), + m_eyeseparation(0.0f), + m_focallength(0.0f), + m_setfocallength(false), + m_noOfScanlines(32), + m_colorManagement(RAS_COLOR_MANAGEMENT_LINEAR), + m_motionblur(0), + m_motionblurvalue(-1.0f), + m_clientobject(nullptr), + m_auxilaryClientInfo(nullptr), + m_drawingmode(RAS_TEXTURED), + m_shadowMode(RAS_SHADOW_NONE), + m_invertFrontFace(false), + m_overrideShader(RAS_OVERRIDE_SHADER_NONE) +{ + m_impl.reset(new RAS_OpenGLRasterizer(this)); + m_debugDrawImpl.reset(new RAS_OpenGLDebugDraw()); + + m_numgllights = m_impl->GetNumLights(); + + m_state.frontFace = -1; + m_state.cullFace = -1; + m_state.polyOffset[0] = -1.0f; + m_state.polyOffset[1] = -1.0f; +} + +RAS_Rasterizer::~RAS_Rasterizer() +{ +} + +void RAS_Rasterizer::Enable(RAS_Rasterizer::EnableBit bit) +{ + m_impl->Enable(bit); +} + +void RAS_Rasterizer::Disable(RAS_Rasterizer::EnableBit bit) +{ + m_impl->Disable(bit); +} + +void RAS_Rasterizer::SetDepthFunc(RAS_Rasterizer::DepthFunc func) +{ + m_impl->SetDepthFunc(func); +} + +void RAS_Rasterizer::SetBlendFunc(BlendFunc src, BlendFunc dst) +{ + m_impl->SetBlendFunc(src, dst); +} + +void RAS_Rasterizer::SetAmbientColor(const mt::vec3& color) +{ + m_ambient = color; +} + +void RAS_Rasterizer::SetAmbient(float factor) +{ + m_impl->SetAmbient(m_ambient, factor); +} + +void RAS_Rasterizer::SetFog(short type, float start, float dist, float intensity, const mt::vec3& color) +{ + m_impl->SetFog(type, start, dist, intensity, color); +} + +void RAS_Rasterizer::Init() +{ + GPU_state_init(); + + Disable(RAS_BLEND); + Disable(RAS_ALPHA_TEST); + //m_last_alphablend = GPU_BLEND_SOLID; + GPU_set_material_alpha_blend(GPU_BLEND_SOLID); + + SetFrontFace(true); + + SetColorMask(true, true, true, true); + + m_impl->Init(); + + InitOverrideShadersInterface(); +} + +void RAS_Rasterizer::Exit() +{ + SetCullFace(true); + Enable(RAS_DEPTH_TEST); + + SetClearDepth(1.0f); + SetColorMask(true, true, true, true); + + SetClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + Clear(RAS_COLOR_BUFFER_BIT | RAS_DEPTH_BUFFER_BIT); + SetDepthMask(RAS_DEPTHMASK_ENABLED); + SetDepthFunc(RAS_LEQUAL); + SetBlendFunc(RAS_ONE, RAS_ZERO); + + Disable(RAS_POLYGON_STIPPLE); + + Disable(RAS_LIGHTING); + m_impl->Exit(); + + ResetGlobalDepthTexture(); + + EndFrame(); +} + +void RAS_Rasterizer::BeginFrame(double time) +{ + m_time = time; + + m_state.polyOffset[0] = -1.0f; + m_state.polyOffset[1] = -1.0f; + + SetCullFace(true); + Enable(RAS_DEPTH_TEST); + + Disable(RAS_BLEND); + Disable(RAS_ALPHA_TEST); + //m_last_alphablend = GPU_BLEND_SOLID; + GPU_set_material_alpha_blend(GPU_BLEND_SOLID); + + SetFrontFace(true); + + m_impl->BeginFrame(); + + Enable(RAS_MULTISAMPLE); + + Enable(RAS_SCISSOR_TEST); + + SetDepthFunc(RAS_LEQUAL); + + // Render Tools + m_clientobject = nullptr; + m_lastlightlayer = -1; + m_lastauxinfo = nullptr; + m_lastlighting = true; /* force disable in DisableLights() */ + + DisableLights(); +} + +void RAS_Rasterizer::EndFrame() +{ + SetColorMask(true, true, true, true); + + Disable(RAS_MULTISAMPLE); +} + +void RAS_Rasterizer::SetDrawingMode(RAS_Rasterizer::DrawType drawingmode) +{ + m_drawingmode = drawingmode; +} + +RAS_Rasterizer::DrawType RAS_Rasterizer::GetDrawingMode() +{ + return m_drawingmode; +} + +void RAS_Rasterizer::SetShadowMode(RAS_Rasterizer::ShadowType shadowmode) +{ + m_shadowMode = shadowmode; +} + +RAS_Rasterizer::ShadowType RAS_Rasterizer::GetShadowMode() +{ + return m_shadowMode; +} + +void RAS_Rasterizer::SetDepthMask(DepthMask depthmask) +{ + m_impl->SetDepthMask(depthmask); +} + +unsigned int *RAS_Rasterizer::MakeScreenshot(int x, int y, int width, int height) +{ + return m_impl->MakeScreenshot(x, y, width, height); +} + +void RAS_Rasterizer::Clear(int clearbit) +{ + m_impl->Clear(clearbit); +} + +void RAS_Rasterizer::SetClearColor(float r, float g, float b, float a) +{ + m_impl->SetClearColor(r, g, b, a); +} + +void RAS_Rasterizer::SetClearDepth(float d) +{ + m_impl->SetClearDepth(d); +} + +void RAS_Rasterizer::SetColorMask(bool r, bool g, bool b, bool a) +{ + m_impl->SetColorMask(r, g, b, a); +} + +void RAS_Rasterizer::DrawOverlayPlane() +{ + m_impl->DrawOverlayPlane(); +} + +void RAS_Rasterizer::UpdateOffScreens(RAS_ICanvas *canvas) +{ + m_offScreens.Update(canvas); +} + +RAS_OffScreen *RAS_Rasterizer::GetOffScreen(OffScreenType type) +{ + return m_offScreens.GetOffScreen(type); +} + +void RAS_Rasterizer::DrawOffScreen(RAS_OffScreen *srcOffScreen, RAS_OffScreen *dstOffScreen) +{ + if (srcOffScreen->GetSamples() > 0) { + srcOffScreen->Blit(dstOffScreen, true, true); + } + else { + srcOffScreen->BindColorTexture(0); + + GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_DRAW_FRAME_BUFFER); + GPU_shader_bind(shader); + + DrawOverlayPlane(); + + GPU_shader_unbind(); + + srcOffScreen->UnbindColorTexture(); + } +} + +void RAS_Rasterizer::DrawOffScreenToScreen(RAS_ICanvas *canvas, RAS_OffScreen *offScreen) +{ + if (offScreen->GetSamples() > 0) { + offScreen = offScreen->Blit(GetOffScreen(RAS_OFFSCREEN_EYE_LEFT1), true, false); + } + + const int *viewport = canvas->GetViewPort(); + SetViewport(viewport[0], viewport[1], viewport[2], viewport[3]); + SetScissor(viewport[0], viewport[1], viewport[2], viewport[3]); + + SetFrontFace(true); + SetDepthFunc(RAS_ALWAYS); + + RAS_OffScreen::RestoreScreen(); + + offScreen->BindColorTexture(0); + + GPUShader *shader = + GPU_shader_get_builtin_shader(offScreenToScreenShaderTable[RAS_SHADER_TO_SCREEN_NORMAL][m_colorManagement]); + GPU_shader_bind(shader); + + DrawOverlayPlane(); + + GPU_shader_unbind(); + + offScreen->UnbindColorTexture(); + + SetDepthFunc(RAS_LEQUAL); +} + +void RAS_Rasterizer::DrawStereoOffScreenToScreen(RAS_ICanvas *canvas, RAS_OffScreen *leftOffScreen, + RAS_OffScreen *rightOffScreen, StereoMode stereoMode) +{ + if (leftOffScreen->GetSamples() > 0) { + // Then leftOffScreen == RAS_OFFSCREEN_EYE_LEFT0. + leftOffScreen = leftOffScreen->Blit(GetOffScreen(RAS_OFFSCREEN_EYE_LEFT1), true, false); + } + + if (rightOffScreen->GetSamples() > 0) { + // Then rightOffScreen == RAS_OFFSCREEN_EYE_RIGHT0. + rightOffScreen = rightOffScreen->Blit(GetOffScreen(RAS_OFFSCREEN_EYE_RIGHT1), true, false); + } + + const int *viewport = canvas->GetViewPort(); + SetViewport(viewport[0], viewport[1], viewport[2], viewport[3]); + SetScissor(viewport[0], viewport[1], viewport[2], viewport[3]); + + SetFrontFace(true); + SetDepthFunc(RAS_ALWAYS); + + RAS_OffScreen::RestoreScreen(); + + if (stereoMode == RAS_STEREO_VINTERLACE || stereoMode == RAS_STEREO_INTERLACED) { + GPUShader *shader = + GPU_shader_get_builtin_shader(offScreenToScreenShaderTable[RAS_SHADER_TO_SCREEN_STEREO_STIPPLE][m_colorManagement]); + GPU_shader_bind(shader); + + OverrideShaderStereoStippleInterface *interface = (OverrideShaderStereoStippleInterface *)GPU_shader_get_interface(shader); + GPU_shader_uniform_int(shader, interface->stippleIdLoc, (stereoMode == RAS_STEREO_INTERLACED) ? 1 : 0); + } + else if (stereoMode == RAS_STEREO_ANAGLYPH) { + GPUShader *shader = + GPU_shader_get_builtin_shader(offScreenToScreenShaderTable[RAS_SHADER_TO_SCREEN_STEREO_ANAGLYPH][m_colorManagement]); + GPU_shader_bind(shader); + } + + leftOffScreen->BindColorTexture(0); + rightOffScreen->BindColorTexture(1); + + DrawOverlayPlane(); + + leftOffScreen->UnbindColorTexture(); + rightOffScreen->UnbindColorTexture(); + + GPU_shader_unbind(); + + SetDepthFunc(RAS_LEQUAL); +} + +RAS_Rect RAS_Rasterizer::GetRenderArea(RAS_ICanvas *canvas, StereoMode stereoMode, StereoEye eye) +{ + RAS_Rect area; + // only above/below stereo method needs viewport adjustment + switch (stereoMode) { + case RAS_STEREO_ABOVEBELOW: + { + switch (eye) { + case RAS_STEREO_LEFTEYE: + { + // upper half of window + area.SetLeft(0); + area.SetBottom(canvas->GetHeight() - (canvas->GetHeight() - m_noOfScanlines - 1) / 2); + + area.SetRight(canvas->GetMaxX()); + area.SetTop(canvas->GetMaxY()); + break; + } + case RAS_STEREO_RIGHTEYE: + { + // lower half of window + area.SetLeft(0); + area.SetBottom(0); + area.SetRight(canvas->GetMaxX()); + area.SetTop((canvas->GetMaxY() - m_noOfScanlines) / 2); + break; + } + } + break; + } + case RAS_STEREO_3DTVTOPBOTTOM: + { + switch (eye) { + case RAS_STEREO_LEFTEYE: + { + // upper half of window + area.SetLeft(0); + area.SetBottom(canvas->GetHeight() - canvas->GetHeight() / 2); + + area.SetRight(canvas->GetWidth() - 1); + area.SetTop(canvas->GetHeight() - 1); + break; + } + case RAS_STEREO_RIGHTEYE: + { + // lower half of window + area.SetLeft(0); + area.SetBottom(0); + area.SetRight(canvas->GetWidth() - 1); + area.SetTop((canvas->GetHeight() - 1) / 2); + break; + } + } + break; + } + case RAS_STEREO_SIDEBYSIDE: + { + switch (eye) { + case RAS_STEREO_LEFTEYE: + { + // Left half of window + area.SetLeft(0); + area.SetBottom(0); + area.SetRight((canvas->GetWidth() - 1) / 2); + area.SetTop(canvas->GetHeight() - 1); + break; + } + case RAS_STEREO_RIGHTEYE: + { + // Right half of window + area.SetLeft(canvas->GetWidth() / 2); + area.SetBottom(0); + area.SetRight(canvas->GetWidth() - 1); + area.SetTop(canvas->GetHeight() - 1); + break; + } + } + break; + } + default: + { + // every available pixel + area.SetLeft(0); + area.SetBottom(0); + area.SetRight(canvas->GetWidth() - 1); + area.SetTop(canvas->GetHeight() - 1); + break; + } + } + + return area; +} + +void RAS_Rasterizer::SetStereoMode(const StereoMode stereomode) +{ + m_stereomode = stereomode; +} + +RAS_Rasterizer::StereoMode RAS_Rasterizer::GetStereoMode() +{ + return m_stereomode; +} + +void RAS_Rasterizer::SetEye(const StereoEye eye) +{ + m_curreye = eye; +} + +RAS_Rasterizer::StereoEye RAS_Rasterizer::GetEye() +{ + return m_curreye; +} + +void RAS_Rasterizer::SetEyeSeparation(const float eyeseparation) +{ + m_eyeseparation = eyeseparation; +} + +float RAS_Rasterizer::GetEyeSeparation() +{ + return m_eyeseparation; +} + +void RAS_Rasterizer::SetFocalLength(const float focallength) +{ + m_focallength = focallength; + m_setfocallength = true; +} + +float RAS_Rasterizer::GetFocalLength() +{ + return m_focallength; +} + +RAS_ISync *RAS_Rasterizer::CreateSync(int type) +{ + RAS_ISync *sync = new RAS_OpenGLSync(); + + if (!sync->Create((RAS_ISync::RAS_SYNC_TYPE)type)) { + delete sync; + return nullptr; + } + return sync; +} + +const mt::mat4& RAS_Rasterizer::GetViewMatrix() const +{ + return m_viewmatrix; +} + +const mt::mat4& RAS_Rasterizer::GetViewInvMatrix() const +{ + return m_viewinvmatrix; +} + +void RAS_Rasterizer::IndexPrimitivesText(RAS_MeshSlot *ms) +{ + RAS_TextUser *textUser = (RAS_TextUser *)ms->m_meshUser; + + float mat[16]; + textUser->GetMatrix().Pack(mat); + + const mt::vec3& spacing = textUser->GetSpacing(); + const mt::vec3& offset = textUser->GetOffset(); + + mat[12] += offset[0]; + mat[13] += offset[1]; + mat[14] += offset[2]; + + for (unsigned short int i = 0, size = textUser->GetTexts().size(); i < size; ++i) { + if (i != 0) { + mat[12] -= spacing[0]; + mat[13] -= spacing[1]; + mat[14] -= spacing[2]; + } + RenderText3D(textUser->GetFontId(), textUser->GetTexts()[i], textUser->GetSize(), textUser->GetDpi(), + textUser->GetColor().Data(), mat, textUser->GetAspect()); + } +} + +void RAS_Rasterizer::SetProjectionMatrix(const mt::mat4 & mat) +{ + SetMatrixMode(RAS_PROJECTION); + LoadMatrix((float *)mat.Data()); + + m_camortho = (mat(3, 3) != 0.0f); +} + +mt::mat4 RAS_Rasterizer::GetFrustumMatrix(StereoMode stereoMode, StereoEye eye, float focallength, + float left, float right, float bottom, float top, float frustnear, float frustfar) +{ + // correction for stereo + if (stereoMode > RAS_STEREO_NOSTEREO) { + // if Rasterizer.setFocalLength is not called we use the camera focallength + if (!m_setfocallength) { + // if focallength is null we use a value known to be reasonable + m_focallength = (focallength == 0.0f) ? m_eyeseparation * 30.0f + : focallength; + } + + const float near_div_focallength = frustnear / m_focallength; + const float offset = 0.5f * m_eyeseparation * near_div_focallength; + switch (eye) { + case RAS_STEREO_LEFTEYE: + { + left += offset; + right += offset; + break; + } + case RAS_STEREO_RIGHTEYE: + { + left -= offset; + right -= offset; + break; + } + } + // leave bottom and top untouched + if (stereoMode == RAS_STEREO_3DTVTOPBOTTOM) { + // restore the vertical frustum because the 3DTV will + // expand the top and bottom part to the full size of the screen + bottom *= 2.0f; + top *= 2.0f; + } + } + + return GetFrustumMatrix(left, right, bottom, top, frustnear, frustfar); +} + +mt::mat4 RAS_Rasterizer::GetFrustumMatrix(float left, float right, float bottom, float top, float frustnear, float frustfar) +{ + return mt::mat4::Perspective(left, right, bottom, top, frustnear, frustfar); +} + +mt::mat4 RAS_Rasterizer::GetOrthoMatrix(float left, + float right, + float bottom, + float top, + float frustnear, + float frustfar) +{ + return mt::mat4::Ortho(left, right, bottom, top, frustnear, frustfar); +} + +// next arguments probably contain redundant info, for later... +mt::mat4 RAS_Rasterizer::GetViewMatrix(StereoMode stereoMode, StereoEye eye, const mt::mat3x4 &camtrans, bool perspective) +{ + // correction for stereo + if ((stereoMode != RAS_STEREO_NOSTEREO) && perspective) { + static const mt::vec3 unitViewDir = -mt::axisY3; // minus y direction, Blender convention + static const mt::vec3 unitViewupVec = mt::axisZ3; + + const mt::mat3& camOrientMat3x3 = camtrans.RotationMatrix().Transpose(); + // actual viewDir + const mt::vec3 viewDir = camOrientMat3x3 * unitViewDir; // this is the moto convention, vector on right hand side + // actual viewup vec + const mt::vec3 viewupVec = camOrientMat3x3 * unitViewupVec; + + // vector between eyes + const mt::vec3 eyeline = mt::cross(viewDir, viewupVec); + + mt::mat3x4 trans = camtrans; + switch (eye) { + case RAS_STEREO_LEFTEYE: + { + // translate to left by half the eye distance + const mt::mat3x4 transform(mt::mat3::Identity(), -eyeline *m_eyeseparation / 2.0f); + trans *= transform; + break; + } + case RAS_STEREO_RIGHTEYE: + { + // translate to right by half the eye distance + const mt::mat3x4 transform(mt::mat3::Identity(), eyeline *m_eyeseparation / 2.0f); + trans *= transform; + break; + } + } + + return mt::mat4::FromAffineTransform(trans); + } + + return mt::mat4::FromAffineTransform(camtrans); +} + +void RAS_Rasterizer::SetViewMatrix(const mt::mat4& viewmat, bool negscale) +{ + m_viewmatrix = viewmat; + m_viewinvmatrix = m_viewmatrix.Inverse(); + m_campos = m_viewinvmatrix.TranslationVector3D(); + m_camnegscale = negscale; + + SetMatrixMode(RAS_MODELVIEW); + LoadMatrix((float *)m_viewmatrix.Data()); +} + +void RAS_Rasterizer::SetViewMatrix(const mt::mat4& viewmat) +{ + SetViewMatrix(viewmat, false); +} + +void RAS_Rasterizer::SetViewMatrix(const mt::mat4 &viewmat, const mt::vec3& scale) +{ + mt::mat4 mat = viewmat; + for (unsigned short i = 0; i < 3; ++i) { + // Negate row scaling if the scale is negative. + if (scale[i] < 0.0f) { + for (unsigned short j = 0; j < 4; ++j) { + mat(i, j) *= -1.0f; + } + } + } + + const bool negscale = (scale.x * scale.y * scale.z) < 0.0f; + SetViewMatrix(mat, negscale); +} + +void RAS_Rasterizer::SetViewport(int x, int y, int width, int height) +{ + m_impl->SetViewport(x, y, width, height); +} + +void RAS_Rasterizer::GetViewport(int *rect) +{ + m_impl->GetViewport(rect); +} + +void RAS_Rasterizer::SetScissor(int x, int y, int width, int height) +{ + m_impl->SetScissor(x, y, width, height); +} + +const mt::vec3& RAS_Rasterizer::GetCameraPosition() +{ + return m_campos; +} + +bool RAS_Rasterizer::GetCameraOrtho() +{ + return m_camortho; +} + +void RAS_Rasterizer::SetCullFace(bool enable) +{ + if (enable == m_state.cullFace) { + return; + } + m_state.cullFace = enable; + + if (enable) { + Enable(RAS_CULL_FACE); + } + else { + Disable(RAS_CULL_FACE); + } +} + +void RAS_Rasterizer::EnableClipPlane(unsigned short index, const mt::vec4& plane) +{ + m_impl->EnableClipPlane(index, plane); +} + +void RAS_Rasterizer::DisableClipPlane(unsigned short index) +{ + m_impl->DisableClipPlane(index); +} + +void RAS_Rasterizer::SetLines(bool enable) +{ + m_impl->SetLines(enable); +} + +void RAS_Rasterizer::SetSpecularity(float specX, + float specY, + float specZ, + float specval) +{ + m_impl->SetSpecularity(specX, specY, specZ, specval); +} + +void RAS_Rasterizer::SetShinyness(float shiny) +{ + m_impl->SetShinyness(shiny); +} + +void RAS_Rasterizer::SetDiffuse(float difX, float difY, float difZ, float diffuse) +{ + m_impl->SetDiffuse(difX, difY, difZ, diffuse); +} + +void RAS_Rasterizer::SetEmissive(float eX, float eY, float eZ, float e) +{ + m_impl->SetEmissive(eX, eY, eZ, e); +} + +double RAS_Rasterizer::GetTime() +{ + return m_time; +} + +void RAS_Rasterizer::SetPolygonOffset(DrawType drawingMode, float mult, float add) +{ + if (m_state.polyOffset[0] == mult && m_state.polyOffset[1] == add) { + return; + } + + m_impl->SetPolygonOffset(mult, add); + + EnableBit mode = RAS_POLYGON_OFFSET_FILL; + if (drawingMode < RAS_TEXTURED) { + mode = RAS_POLYGON_OFFSET_LINE; + } + if (mult != 0.0f || add != 0.0f) { + Enable(mode); + } + else { + Disable(mode); + } + + m_state.polyOffset[0] = mult; + m_state.polyOffset[1] = add; +} + +void RAS_Rasterizer::EnableMotionBlur(float motionblurvalue) +{ + /* don't just set m_motionblur to 1, but check if it is 0 so + * we don't reset a motion blur that is already enabled */ + if (m_motionblur == 0) { + m_motionblur = 1; + } + m_motionblurvalue = motionblurvalue; +} + +void RAS_Rasterizer::DisableMotionBlur() +{ + m_motionblur = 0; + m_motionblurvalue = -1.0f; +} + +void RAS_Rasterizer::SetMotionBlur(unsigned short state) +{ + m_motionblur = state; +} + +void RAS_Rasterizer::SetAlphaBlend(int alphablend) +{ + GPU_set_material_alpha_blend(alphablend); +} + +void RAS_Rasterizer::SetFrontFace(bool ccw) +{ + // Invert the front face if the camera has a negative scale or if we force to inverse the front face. + ccw ^= (m_camnegscale || m_invertFrontFace); + + if (m_state.frontFace == ccw) { + return; + } + + m_impl->SetFrontFace(ccw); + + m_state.frontFace = ccw; +} + +void RAS_Rasterizer::SetInvertFrontFace(bool invert) +{ + m_invertFrontFace = invert; +} + +void RAS_Rasterizer::SetColorManagment(ColorManagement colorManagement) +{ + m_colorManagement = colorManagement; +} + +void RAS_Rasterizer::SetAnisotropicFiltering(short level) +{ + GPU_set_anisotropic(G.main, (float)level); +} + +short RAS_Rasterizer::GetAnisotropicFiltering() +{ + return (short)GPU_get_anisotropic(); +} + +void RAS_Rasterizer::SetMipmapping(MipmapOption val) +{ + switch (val) { + case RAS_Rasterizer::RAS_MIPMAP_LINEAR: + { + GPU_set_linear_mipmap(1); + GPU_set_mipmap(G.main, 1); + break; + } + case RAS_Rasterizer::RAS_MIPMAP_NEAREST: + { + GPU_set_linear_mipmap(0); + GPU_set_mipmap(G.main, 1); + break; + } + default: + { + GPU_set_linear_mipmap(0); + GPU_set_mipmap(G.main, 0); + } + } +} + +RAS_Rasterizer::MipmapOption RAS_Rasterizer::GetMipmapping() +{ + if (GPU_get_mipmap()) { + if (GPU_get_linear_mipmap()) { + return RAS_Rasterizer::RAS_MIPMAP_LINEAR; + } + else { + return RAS_Rasterizer::RAS_MIPMAP_NEAREST; + } + } + else { + return RAS_Rasterizer::RAS_MIPMAP_NONE; + } +} + +void RAS_Rasterizer::InitOverrideShadersInterface() +{ + // Find uniform location for FBO shaders. + + // Draw frame buffer shader. + for (unsigned short i = 0; i < RAS_COLOR_MANAGEMENT_MAX; ++i) { + { + GPUShader *shader = + GPU_shader_get_builtin_shader(offScreenToScreenShaderTable[RAS_SHADER_TO_SCREEN_NORMAL][i]); + if (!GPU_shader_get_interface(shader)) { + OverrideShaderDrawFrameBufferInterface *interface = (OverrideShaderDrawFrameBufferInterface *)MEM_mallocN(sizeof(OverrideShaderDrawFrameBufferInterface), "OverrideShaderDrawFrameBufferInterface"); + + interface->colorTexLoc = GPU_shader_get_uniform(shader, "colortex"); + + GPU_shader_bind(shader); + GPU_shader_uniform_int(shader, interface->colorTexLoc, 0); + GPU_shader_unbind(); + + GPU_shader_set_interface(shader, interface); + } + } + + // Stipple stereo shader. + { + GPUShader *shader = + GPU_shader_get_builtin_shader(offScreenToScreenShaderTable[RAS_SHADER_TO_SCREEN_STEREO_STIPPLE][i]); + if (!GPU_shader_get_interface(shader)) { + OverrideShaderStereoStippleInterface *interface = (OverrideShaderStereoStippleInterface *)MEM_mallocN(sizeof(OverrideShaderStereoStippleInterface), "OverrideShaderStereoStippleInterface"); + + interface->leftEyeTexLoc = GPU_shader_get_uniform(shader, "lefteyetex"); + interface->rightEyeTexLoc = GPU_shader_get_uniform(shader, "righteyetex"); + interface->stippleIdLoc = GPU_shader_get_uniform(shader, "stippleid"); + + GPU_shader_bind(shader); + GPU_shader_uniform_int(shader, interface->leftEyeTexLoc, 0); + GPU_shader_uniform_int(shader, interface->rightEyeTexLoc, 1); + GPU_shader_unbind(); + + GPU_shader_set_interface(shader, interface); + } + } + + // Anaglyph stereo shader. + { + GPUShader *shader = + GPU_shader_get_builtin_shader(offScreenToScreenShaderTable[RAS_SHADER_TO_SCREEN_STEREO_ANAGLYPH][i]); + if (!GPU_shader_get_interface(shader)) { + OverrideShaderStereoAnaglyph *interface = (OverrideShaderStereoAnaglyph *)MEM_mallocN(sizeof(OverrideShaderStereoAnaglyph), "OverrideShaderStereoAnaglyph"); + + interface->leftEyeTexLoc = GPU_shader_get_uniform(shader, "lefteyetex"); + interface->rightEyeTexLoc = GPU_shader_get_uniform(shader, "righteyetex"); + + GPU_shader_bind(shader); + GPU_shader_uniform_int(shader, interface->leftEyeTexLoc, 0); + GPU_shader_uniform_int(shader, interface->rightEyeTexLoc, 1); + GPU_shader_unbind(); + + GPU_shader_set_interface(shader, interface); + } + } + } +} + +GPUShader *RAS_Rasterizer::GetOverrideGPUShader(OverrideShaderType type) +{ + GPUShader *shader = nullptr; + switch (type) { + case RAS_OVERRIDE_SHADER_NONE: + { + break; + } + case RAS_OVERRIDE_SHADER_BLACK: + { + shader = GPU_shader_get_builtin_shader(GPU_SHADER_BLACK); + break; + } + case RAS_OVERRIDE_SHADER_BLACK_INSTANCING: + { + shader = GPU_shader_get_builtin_shader(GPU_SHADER_BLACK_INSTANCING); + break; + } + case RAS_OVERRIDE_SHADER_SHADOW_VARIANCE: + { + shader = GPU_shader_get_builtin_shader(GPU_SHADER_VSM_STORE); + break; + } + case RAS_OVERRIDE_SHADER_SHADOW_VARIANCE_INSTANCING: + { + shader = GPU_shader_get_builtin_shader(GPU_SHADER_VSM_STORE_INSTANCING); + break; + } + } + + return shader; +} + +void RAS_Rasterizer::SetOverrideShader(RAS_Rasterizer::OverrideShaderType type) +{ + if (type == m_overrideShader) { + return; + } + + GPUShader *shader = GetOverrideGPUShader(type); + if (shader) { + GPU_shader_bind(shader); + } + else { + GPU_shader_unbind(); + } + m_overrideShader = type; +} + +RAS_Rasterizer::OverrideShaderType RAS_Rasterizer::GetOverrideShader() +{ + return m_overrideShader; +} + +void RAS_Rasterizer::ActivateOverrideShaderInstancing(RAS_InstancingBuffer *buffer) +{ + GPUShader *shader = GetOverrideGPUShader(m_overrideShader); + if (shader) { + GPU_shader_bind_instancing_attrib(shader, (void *)buffer->GetMatrixOffset(), (void *)buffer->GetPositionOffset()); + } +} + +/** + * Render Tools + */ + +/* ProcessLighting performs lighting on objects. the layer is a bitfield that + * contains layer information. There are 20 'official' layers in blender. A + * light is applied on an object only when they are in the same layer. OpenGL + * has a maximum of 8 lights (simultaneous), so 20 * 8 lights are possible in + * a scene. */ + +void RAS_Rasterizer::ProcessLighting(bool uselights, const mt::mat3x4& viewmat) +{ + bool enable = false; + int layer = -1; + + /* find the layer */ + if (uselights) { + if (m_clientobject) { + layer = KX_GameObject::GetClientObject((KX_ClientObjectInfo *)m_clientobject)->GetLayer(); + } + } + + /* avoid state switching */ + if (m_lastlightlayer == layer && m_lastauxinfo == m_auxilaryClientInfo) { + return; + } + + m_lastlightlayer = layer; + m_lastauxinfo = m_auxilaryClientInfo; + + /* enable/disable lights as needed */ + if (layer >= 0) { + //enable = ApplyLights(layer, viewmat); + // taken from blender source, incompatibility between Blender Object / GameObject + KX_Scene *kxscene = (KX_Scene *)m_auxilaryClientInfo; + float glviewmat[16]; + unsigned int count; + std::vector::iterator lit = m_lights.begin(); + + for (count = 0; count < m_numgllights; count++) { + m_impl->DisableLight(count); + } + + viewmat.PackFromAffineTransform(glviewmat); + + PushMatrix(); + LoadMatrix(glviewmat); + for (lit = m_lights.begin(), count = 0; !(lit == m_lights.end()) && count < m_numgllights; ++lit) { + RAS_OpenGLLight *light = (*lit); + + if (light->ApplyFixedFunctionLighting(kxscene, layer, count)) { + count++; + } + } + PopMatrix(); + + enable = count > 0; + } + + if (enable) { + EnableLights(); + } + else { + DisableLights(); + } +} + +void RAS_Rasterizer::EnableLights() +{ + if (m_lastlighting == true) { + return; + } + + Enable(RAS_Rasterizer::RAS_LIGHTING); + Enable(RAS_Rasterizer::RAS_COLOR_MATERIAL); + + m_impl->EnableLights(); + + m_lastlighting = true; +} + +void RAS_Rasterizer::DisableLights() +{ + if (m_lastlighting == false) { + return; + } + + Disable(RAS_Rasterizer::RAS_LIGHTING); + Disable(RAS_Rasterizer::RAS_COLOR_MATERIAL); + + m_lastlighting = false; +} + +RAS_ILightObject *RAS_Rasterizer::CreateLight() +{ + return new RAS_OpenGLLight(this); +} + +void RAS_Rasterizer::AddLight(RAS_ILightObject *lightobject) +{ + RAS_OpenGLLight *gllight = static_cast(lightobject); + BLI_assert(gllight); + m_lights.push_back(gllight); +} + +void RAS_Rasterizer::RemoveLight(RAS_ILightObject *lightobject) +{ + RAS_OpenGLLight *gllight = static_cast(lightobject); + BLI_assert(gllight); + + CM_ListRemoveIfFound(m_lights, gllight); +} + +bool RAS_Rasterizer::RayHit(struct KX_ClientObjectInfo *client, KX_RayCast *result, RayCastTranform *raytransform) +{ + if (result->m_hitMesh) { + const RAS_Mesh::PolygonInfo poly = result->m_hitMesh->GetPolygon(result->m_hitPolygon); + if (!(poly.flags & RAS_Mesh::PolygonInfo::VISIBLE)) { + return false; + } + + const mt::mat4& origmat = raytransform->origmat; + float *mat = raytransform->mat; + const mt::vec3& scale = raytransform->scale; + const mt::vec3& point = result->m_hitPoint; + mt::vec3 resultnormal(result->m_hitNormal); + mt::vec3 left = origmat.GetColumn(0).xyz(); + mt::vec3 dir = -(mt::cross(left, resultnormal)).SafeNormalized(mt::axisX3); + left = (mt::cross(dir, resultnormal)).SafeNormalized(mt::axisX3); + // for the up vector, we take the 'resultnormal' returned by the physics + + // we found the "ground", but the cast matrix doesn't take + // scaling in consideration, so we must apply the object scale + left *= scale[0]; + dir *= scale[1]; + resultnormal *= scale[2]; + + float tmpmat[16] = { + left[0], left[1], left[2], 0.0f, + dir[0], dir[1], dir[2], 0.0f, + resultnormal[0], resultnormal[1], resultnormal[2], 0.0f, + point[0], point[1], point[2], 1.0f, + }; + memcpy(mat, tmpmat, sizeof(float) * 16); + + return true; + } + else { + return false; + } +} + +bool RAS_Rasterizer::NeedRayCast(KX_ClientObjectInfo *UNUSED(info), void *UNUSED(data)) +{ + return true; +} + +void RAS_Rasterizer::GetTransform(const mt::mat4& origmat, int objectdrawmode, float mat[16]) +{ + if (objectdrawmode == RAS_IMaterial::RAS_NORMAL) { + // 'normal' object + origmat.Pack(mat); + } + else if (ELEM(objectdrawmode, RAS_IMaterial::RAS_HALO, RAS_IMaterial::RAS_BILLBOARD)) { + // rotate the billboard/halo + //page 360/361 3D Game Engine Design, David Eberly for a discussion + // on screen aligned and axis aligned billboards + // assumed is that the preprocessor transformed all billboard polygons + // so that their normal points into the positive x direction (1.0f, 0.0f, 0.0f) + // when new parenting for objects is done, this rotation + // will be moved into the object + + mt::vec3 left; + if (m_camortho) { + left = m_viewmatrix.GetColumn(2).xyz().SafeNormalized(mt::axisX3); + } + else { + const mt::vec3 objpos(&origmat[12]); + const mt::vec3& campos = GetCameraPosition(); + left = (campos - objpos).SafeNormalized(mt::axisX3); + } + + mt::vec3 up = mt::vec3(&origmat[8]).SafeNormalized(mt::axisX3); + + // get scaling of halo object + const mt::vec3& scale = mt::vec3(len_v3(&origmat[0]), len_v3(&origmat[4]), len_v3(&origmat[8])); + + if (objectdrawmode & RAS_IMaterial::RAS_HALO) { + up = (up - mt::dot(up, left) * left).SafeNormalized(mt::axisX3); + } + else { + left = (left - mt::dot(up, left) * up).SafeNormalized(mt::axisX3); + } + + mt::vec3 dir = (mt::cross(up, left)).Normalized(); + + // we have calculated the row vectors, now we keep + // local scaling into account: + + left *= scale[0]; + dir *= scale[1]; + up *= scale[2]; + + const float tmpmat[16] = { + left[0], left[1], left[2], 0.0f, + dir[0], dir[1], dir[2], 0.0f, + up[0], up[1], up[2], 0.0f, + origmat[12], origmat[13], origmat[14], 1.0f, + }; + memcpy(mat, tmpmat, sizeof(float) * 16); + } + else { + // shadow must be cast to the ground, physics system needed here! + const mt::vec3 frompoint(&origmat[12]); + KX_GameObject *gameobj = KX_GameObject::GetClientObject((KX_ClientObjectInfo *)m_clientobject); + mt::vec3 direction = -mt::axisZ3; + + direction.Normalize(); + direction *= 100000.0f; + + const mt::vec3 topoint = frompoint + direction; + + KX_Scene *kxscene = (KX_Scene *)m_auxilaryClientInfo; + PHY_IPhysicsEnvironment *physics_environment = kxscene->GetPhysicsEnvironment(); + PHY_IPhysicsController *physics_controller = gameobj->GetPhysicsController(); + + KX_GameObject *parent = gameobj->GetParent(); + if (!physics_controller && parent) { + physics_controller = parent->GetPhysicsController(); + } + + RayCastTranform raytransform; + raytransform.origmat = origmat; + // On success mat is written in the ray test. + raytransform.mat = mat; + raytransform.scale = gameobj->NodeGetWorldScaling(); + + KX_RayCast::Callback callback(this, physics_controller, &raytransform); + if (!KX_RayCast::RayTest(physics_environment, frompoint, topoint, callback)) { + // couldn't find something to cast the shadow on... + origmat.Pack(mat); + } + } +} + +void RAS_Rasterizer::FlushDebug(RAS_ICanvas *canvas, RAS_DebugDraw *debugDraw) +{ + m_debugDrawImpl->Flush(this, canvas, debugDraw); +} + +void RAS_Rasterizer::DisableForText() +{ + SetAlphaBlend(GPU_BLEND_ALPHA); + SetLines(false); /* needed for texture fonts otherwise they render as wireframe */ + + SetCullFace(true); + + DisableLights(); + + m_impl->DisableForText(); +} + +void RAS_Rasterizer::RenderText3D(int fontid, const std::string& text, int size, int dpi, + const float color[4], const float mat[16], float aspect) +{ + m_impl->RenderText3D(fontid, text, size, dpi, color, mat, aspect); +} + +void RAS_Rasterizer::PushMatrix() +{ + m_impl->PushMatrix(); +} + +void RAS_Rasterizer::PopMatrix() +{ + m_impl->PopMatrix(); +} + +void RAS_Rasterizer::SetMatrixMode(RAS_Rasterizer::MatrixMode mode) +{ + m_impl->SetMatrixMode(mode); +} + +void RAS_Rasterizer::MultMatrix(const float mat[16]) +{ + m_impl->MultMatrix(mat); +} + +void RAS_Rasterizer::LoadMatrix(const float mat[16]) +{ + m_impl->LoadMatrix(mat); +} + +void RAS_Rasterizer::LoadIdentity() +{ + m_impl->LoadIdentity(); +} + +void RAS_Rasterizer::UpdateGlobalDepthTexture(RAS_OffScreen *offScreen) +{ + /* In case of multisamples the depth off screen must be blit to be used in shader. + * But the original off screen must be kept bound after the blit. */ + if (offScreen->GetSamples()) { + RAS_OffScreen *dstOffScreen = GetOffScreen(RAS_Rasterizer::RAS_OFFSCREEN_BLIT_DEPTH); + offScreen->Blit(dstOffScreen, false, true); + // Restore original off screen. + offScreen->Bind(); + offScreen = dstOffScreen; + } + + GPU_texture_set_global_depth(offScreen->GetDepthTexture()); +} + +void RAS_Rasterizer::ResetGlobalDepthTexture() +{ + GPU_texture_set_global_depth(nullptr); +} + +void RAS_Rasterizer::MotionBlur() +{ + m_impl->MotionBlur(m_motionblur, m_motionblurvalue); +} + +void RAS_Rasterizer::SetClientObject(void *obj) +{ + m_clientobject = obj; +} + +void RAS_Rasterizer::SetAuxilaryClientInfo(void *inf) +{ + m_auxilaryClientInfo = inf; +} + +void RAS_Rasterizer::PrintHardwareInfo() +{ + m_impl->PrintHardwareInfo(); +} diff --git a/source/gameengine/Rasterizer/RAS_Rasterizer.h b/source/gameengine/Rasterizer/RAS_Rasterizer.h new file mode 100644 index 000000000000..1631de35b575 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_Rasterizer.h @@ -0,0 +1,741 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_Rasterizer.h + * \ingroup bgerast + */ + +#ifndef __RAS_RASTERIZER_H__ +#define __RAS_RASTERIZER_H__ + +#ifdef _MSC_VER +# pragma warning (disable:4786) +#endif + +#include "mathfu.h" + +#include "RAS_Rect.h" + +#include +#include +#include +#include +#include + +class RAS_OpenGLRasterizer; +class RAS_OpenGLDebugDraw; +class RAS_OpenGLLight; +class RAS_ICanvas; +class RAS_OffScreen; +class RAS_MeshSlot; +class RAS_DebugDraw; +class RAS_InstancingBuffer; +class RAS_ILightObject; +class RAS_ISync; +struct KX_ClientObjectInfo; +class KX_RayCast; + +struct GPUShader; + +/** + * 3D rendering device context interface. + */ +class RAS_Rasterizer : public mt::SimdClassAllocator +{ +public: + /** + * Drawing types + */ + enum DrawType { + RAS_WIREFRAME = 0, + RAS_TEXTURED, + RAS_RENDERER, + RAS_SHADOW, + RAS_DRAW_MAX, + }; + + /** + * Valid SetDepthMask parameters + */ + enum DepthMask { + RAS_DEPTHMASK_ENABLED = 1, + RAS_DEPTHMASK_DISABLED, + }; + + /** + */ + enum { + RAS_BACKCULL = 16, // GEMAT_BACKCULL + }; + + /** + * Stereo mode types + */ + enum StereoMode { + RAS_STEREO_NOSTEREO = 1, + // WARNING: Not yet supported. + RAS_STEREO_QUADBUFFERED, + RAS_STEREO_ABOVEBELOW, + RAS_STEREO_INTERLACED, + RAS_STEREO_ANAGLYPH, + RAS_STEREO_SIDEBYSIDE, + RAS_STEREO_VINTERLACE, + RAS_STEREO_3DTVTOPBOTTOM, + + RAS_STEREO_MAXSTEREO + }; + + /** + * Render pass identifiers for stereo. + */ + enum StereoEye { + RAS_STEREO_LEFTEYE = 0, + RAS_STEREO_RIGHTEYE, + }; + + /** + * Mipmap options + */ + enum MipmapOption { + RAS_MIPMAP_NONE, + RAS_MIPMAP_NEAREST, + RAS_MIPMAP_LINEAR, + + RAS_MIPMAP_MAX, /* Should always be last */ + }; + + /** + * Override shaders + */ + enum OverrideShaderType { + RAS_OVERRIDE_SHADER_NONE, + RAS_OVERRIDE_SHADER_BLACK, + RAS_OVERRIDE_SHADER_BLACK_INSTANCING, + RAS_OVERRIDE_SHADER_SHADOW_VARIANCE, + RAS_OVERRIDE_SHADER_SHADOW_VARIANCE_INSTANCING, + }; + + enum ShadowType { + RAS_SHADOW_NONE, + RAS_SHADOW_SIMPLE, + RAS_SHADOW_VARIANCE, + }; + + enum EnableBit { + RAS_DEPTH_TEST = 0, + RAS_ALPHA_TEST, + RAS_SCISSOR_TEST, + RAS_TEXTURE_2D, + RAS_TEXTURE_CUBE_MAP, + RAS_BLEND, + RAS_COLOR_MATERIAL, + RAS_CULL_FACE, + RAS_LIGHTING, + RAS_MULTISAMPLE, + RAS_POLYGON_STIPPLE, + RAS_POLYGON_OFFSET_FILL, + RAS_POLYGON_OFFSET_LINE + }; + + enum DepthFunc { + RAS_NEVER = 0, + RAS_LEQUAL, + RAS_LESS, + RAS_ALWAYS, + RAS_GEQUAL, + RAS_GREATER, + RAS_NOTEQUAL, + RAS_EQUAL + }; + + enum BlendFunc { + RAS_ZERO = 0, + RAS_ONE, + RAS_SRC_COLOR, + RAS_ONE_MINUS_SRC_COLOR, + RAS_DST_COLOR, + RAS_ONE_MINUS_DST_COLOR, + RAS_SRC_ALPHA, + RAS_ONE_MINUS_SRC_ALPHA, + RAS_DST_ALPHA, + RAS_ONE_MINUS_DST_ALPHA, + RAS_SRC_ALPHA_SATURATE + }; + + enum MatrixMode { + RAS_PROJECTION = 0, + RAS_MODELVIEW, + RAS_TEXTURE, + RAS_MATRIX_MODE_MAX + }; + + enum ClearBit { + RAS_COLOR_BUFFER_BIT = 0x2, + RAS_DEPTH_BUFFER_BIT = 0x4, + RAS_STENCIL_BUFFER_BIT = 0x8 + }; + + enum OffScreenType { + RAS_OFFSCREEN_FILTER0, + RAS_OFFSCREEN_FILTER1, + RAS_OFFSCREEN_EYE_LEFT0, + RAS_OFFSCREEN_EYE_RIGHT0, + RAS_OFFSCREEN_EYE_LEFT1, + RAS_OFFSCREEN_EYE_RIGHT1, + RAS_OFFSCREEN_BLIT_DEPTH, + + RAS_OFFSCREEN_CUSTOM, + + RAS_OFFSCREEN_MAX, + }; + + enum HdrType { + RAS_HDR_NONE = 0, + RAS_HDR_HALF_FLOAT, + RAS_HDR_FULL_FLOAT, + RAS_HDR_MAX + }; + + enum ColorManagement { + RAS_COLOR_MANAGEMENT_LINEAR = 0, + RAS_COLOR_MANAGEMENT_SRGB, + RAS_COLOR_MANAGEMENT_MAX + }; + + enum ShaderToScreen { + RAS_SHADER_TO_SCREEN_NORMAL = 0, + RAS_SHADER_TO_SCREEN_STEREO_STIPPLE, + RAS_SHADER_TO_SCREEN_STEREO_ANAGLYPH, + RAS_SHADER_TO_SCREEN_MAX + }; + + /** Return the output frame buffer normally used for the input frame buffer + * index in case of filters render. + * \param index The input frame buffer, can be a non-filter frame buffer. + * \return The output filter frame buffer. + */ + static OffScreenType NextFilterOffScreen(OffScreenType index); + + /** Return the output frame buffer normally used for the input frame buffer + * index in case of simple render. + * \param index The input render frame buffer, can be a eye frame buffer. + * \return The output render frame buffer. + */ + static OffScreenType NextRenderOffScreen(OffScreenType index); + +private: + class OffScreens + { + private: + std::unique_ptr m_offScreens[RAS_OFFSCREEN_MAX]; + unsigned int m_width; + unsigned int m_height; + int m_samples; + HdrType m_hdr; + + public: + OffScreens(); + ~OffScreens(); + + void Update(RAS_ICanvas *canvas); + RAS_OffScreen *GetOffScreen(RAS_Rasterizer::OffScreenType type); + }; + + // All info used to compute the ray cast transform matrix. + struct RayCastTranform + { + /// The object scale. + mt::vec3 scale; + /// The original object matrix. + mt::mat4 origmat; + /// The output matrix. + float *mat; + }; + + /// \section Interfaces used for frame buffer shaders. + + struct OverrideShaderDrawFrameBufferInterface + { + int colorTexLoc; + }; + + struct OverrideShaderStereoStippleInterface + { + int leftEyeTexLoc; + int rightEyeTexLoc; + int stippleIdLoc; + }; + + struct OverrideShaderStereoAnaglyph + { + int leftEyeTexLoc; + int rightEyeTexLoc; + }; + + double m_time; + mt::vec3 m_ambient; + mt::mat4 m_viewmatrix; + mt::mat4 m_viewinvmatrix; + mt::vec3 m_campos; + bool m_camortho; + bool m_camnegscale; + + StereoMode m_stereomode; + StereoEye m_curreye; + float m_eyeseparation; + float m_focallength; + bool m_setfocallength; + int m_noOfScanlines; + + ColorManagement m_colorManagement; + + /* motion blur */ + unsigned short m_motionblur; + float m_motionblurvalue; + + /* Render tools */ + void *m_clientobject; + void *m_auxilaryClientInfo; + std::vector m_lights; + int m_lastlightlayer; + bool m_lastlighting; + void *m_lastauxinfo; + unsigned int m_numgllights; + + /// Class used to manage off screens used by the rasterizer. + OffScreens m_offScreens; + + DrawType m_drawingmode; + ShadowType m_shadowMode; + + bool m_invertFrontFace; + + /// States to reduce OpenGL calls. + struct { + char frontFace; + char cullFace; + float polyOffset[2]; + } m_state; + + OverrideShaderType m_overrideShader; + + std::unique_ptr m_impl; + std::unique_ptr m_debugDrawImpl; + + /// Initialize custom shader interface containing uniform location. + void InitOverrideShadersInterface(); + + /// Return GPUShader coresponding to the override shader enumeration. + GPUShader *GetOverrideGPUShader(OverrideShaderType type); + +public: + RAS_Rasterizer(); + virtual ~RAS_Rasterizer(); + + /** + * Enable capability + * \param bit Enable bit + */ + void Enable(EnableBit bit); + + /** + * Disable capability + * \param bit Enable bit + */ + void Disable(EnableBit bit); + + /** + * Set the value for Depth Buffer comparisons + * \param func Depth comparison function + */ + void SetDepthFunc(DepthFunc func); + + /** + * Set the blending equation. + * \param src The src value. + * \param dst The destination value. + */ + void SetBlendFunc(BlendFunc src, BlendFunc dst); + + /** + * Takes a screenshot + */ + unsigned int *MakeScreenshot(int x, int y, int width, int height); + + /** + * SetDepthMask enables or disables writing a fragment's depth value + * to the Z buffer. + */ + void SetDepthMask(DepthMask depthmask); + + /** + * Init initializes the renderer. + */ + void Init(); + + /** + * Exit cleans up the renderer. + */ + void Exit(); + + /** + * BeginFrame is called at the start of each frame. + */ + void BeginFrame(double time); + + /** + * EndFrame is called at the end of each frame. + */ + void EndFrame(); + + /** + * Clears a specified set of buffers + * \param clearbit What buffers to clear (separated by bitwise OR) + */ + void Clear(int clearbit); + + /** + * Set background color + */ + void SetClearColor(float r, float g, float b, float a=1.0f); + + /** + * Set background depth + */ + void SetClearDepth(float d); + + /** + * Set background color mask. + */ + void SetColorMask(bool r, bool g, bool b, bool a); + + /** + * Draw screen overlay plane with basic uv coordinates. + */ + void DrawOverlayPlane(); + + /// Update dimensions of all off screens. + void UpdateOffScreens(RAS_ICanvas *canvas); + + /** Return the corresponding off screen to off screen type. + * \param type The off screen type to return. + */ + RAS_OffScreen *GetOffScreen(OffScreenType type); + + /** Draw off screen without set viewport. + * Used to copy the frame buffer object to another. + * \param srcindex The input off screen index. + * \param dstindex The output off screen index. + */ + void DrawOffScreen(RAS_OffScreen *srcOffScreen, RAS_OffScreen *dstOffScreen); + + /** Draw off screen at the given index to screen. + * \param canvas The canvas containing the screen viewport. + * \param index The off screen index to read from. + */ + void DrawOffScreenToScreen(RAS_ICanvas *canvas, RAS_OffScreen *offScreen); + + /** Draw each stereo off screen to screen. + * \param canvas The canvas containing the screen viewport. + * \param lefteyeindex The left off screen index. + * \param righteyeindex The right off screen index. + * \param stereoMode The stereo category. + */ + void DrawStereoOffScreenToScreen(RAS_ICanvas *canvas, RAS_OffScreen *leftOffScreen, RAS_OffScreen *rightOffScreen, StereoMode stereoMode); + + /** + * GetRenderArea computes the render area from the 2d canvas. + */ + RAS_Rect GetRenderArea(RAS_ICanvas *canvas, StereoMode stereoMode, StereoEye eye); + + // Stereo Functions + /** + * SetStereoMode will set the stereo mode + */ + void SetStereoMode(const StereoMode stereomode); + + StereoMode GetStereoMode(); + + /** + * Sets which eye buffer subsequent primitives will be rendered to. + */ + void SetEye(const StereoEye eye); + StereoEye GetEye(); + + /** + * Sets the distance between eyes for stereo mode. + */ + void SetEyeSeparation(const float eyeseparation); + float GetEyeSeparation(); + + /** + * Sets the focal length for stereo mode. + */ + void SetFocalLength(const float focallength); + float GetFocalLength(); + + /** + * Create a sync object + * For use with offscreen render + */ + RAS_ISync *CreateSync(int type); + + /// Render text mesh slot using BLF functions. + void IndexPrimitivesText(RAS_MeshSlot *ms); + + /* This one should become our final version, methinks. */ + /** + * Set the projection matrix for the rasterizer. This projects + * from camera coordinates to window coordinates. + * \param mat The projection matrix. + */ + void SetProjectionMatrix(const mt::mat4 &mat); + + /// Get the modelview matrix according to the stereo settings. + mt::mat4 GetViewMatrix(StereoMode stereoMode, StereoEye eye, const mt::mat3x4 &camtrans, bool perspective); + /** + * Sets the modelview matrix. + */ + void SetViewMatrix(const mt::mat4 &viewmat, bool negscale); + void SetViewMatrix(const mt::mat4 &viewmat); + void SetViewMatrix(const mt::mat4 &viewmat, const mt::vec3& scale); + + /** + * Get/Set viewport area + */ + void SetViewport(int x, int y, int width, int height); + void GetViewport(int *rect); + + /** + * Set scissor mask + */ + void SetScissor(int x, int y, int width, int height); + + /** + */ + const mt::vec3& GetCameraPosition(); + bool GetCameraOrtho(); + + /** + * Fog + */ + void SetFog(short type, float start, float dist, float intensity, const mt::vec3& color); + + /** + * \param drawingmode = RAS_WIREFRAME, RAS_SOLID, RAS_SHADOW or RAS_TEXTURED. + */ + void SetDrawingMode(DrawType drawingmode); + + /** + * \return the current drawing mode: RAS_WIREFRAME, RAS_SOLID RAS_SHADOW or RAS_TEXTURED. + */ + DrawType GetDrawingMode(); + + /// \param shadowmode = RAS_SHADOW_SIMPLE, RAS_SHADOW_VARIANCE. + void SetShadowMode(ShadowType shadowmode); + + /// \return the current drawing mode: RAS_SHADOW_SIMPLE, RAS_SHADOW_VARIANCE. + ShadowType GetShadowMode(); + + /** + * Sets face culling + */ + void SetCullFace(bool enable); + + /// Set and enable clip plane. + void EnableClipPlane(unsigned short index, const mt::vec4& plane); + /// Disable clip plane + void DisableClipPlane(unsigned short index); + + /** + * Sets wireframe mode. + */ + void SetLines(bool enable); + + /** + */ + double GetTime(); + + /** + * Generates a projection matrix from the specified frustum and stereomode. + * \param eye The stereo eye. + * \param stereoMode The stereo category. + * \param focallength The stereo eye focal length. + * \param left the left clipping plane + * \param right the right clipping plane + * \param bottom the bottom clipping plane + * \param top the top clipping plane + * \param frustnear the near clipping plane + * \param frustfar the far clipping plane + * \return a 4x4 matrix representing the projection transform. + */ + mt::mat4 GetFrustumMatrix(StereoMode stereoMode, StereoEye eye, float focallength, + float left, float right, float bottom, float top, float frustnear, float frustfar); + + /** + * Generates a projection matrix from the specified frustum. + * \param left the left clipping plane + * \param right the right clipping plane + * \param bottom the bottom clipping plane + * \param top the top clipping plane + * \param frustnear the near clipping plane + * \param frustfar the far clipping plane + * \return a 4x4 matrix representing the projection transform. + */ + mt::mat4 GetFrustumMatrix(float left, float right, float bottom, float top, float frustnear, float frustfar); + + + /** + * Generates a orthographic projection matrix from the specified frustum. + * \param left the left clipping plane + * \param right the right clipping plane + * \param bottom the bottom clipping plane + * \param top the top clipping plane + * \param frustnear the near clipping plane + * \param frustfar the far clipping plane + * \return a 4x4 matrix representing the projection transform. + */ + mt::mat4 GetOrthoMatrix( + float left, float right, float bottom, float top, + float frustnear, float frustfar); + + /** + * Sets the specular color component of the lighting equation. + */ + void SetSpecularity(float specX, float specY, float specZ, float specval); + + /** + * Sets the specular exponent component of the lighting equation. + */ + void SetShinyness(float shiny); + + /** + * Sets the diffuse color component of the lighting equation. + */ + void SetDiffuse(float difX,float difY, float difZ, float diffuse); + + /** + * Sets the emissive color component of the lighting equation. + */ + void SetEmissive(float eX, float eY, float eZ, float e); + + void SetAmbientColor(const mt::vec3& color); + void SetAmbient(float factor); + + /** + * Sets a polygon offset. z depth will be: z1 = mult*z0 + add + */ + void SetPolygonOffset(DrawType drawingMode, float mult, float add); + + const mt::mat4 &GetViewMatrix() const; + const mt::mat4 &GetViewInvMatrix() const; + + void EnableMotionBlur(float motionblurvalue); + void DisableMotionBlur(); + void SetMotionBlur(unsigned short state); + + void SetAlphaBlend(int alphablend); + void SetFrontFace(bool ccw); + + void SetInvertFrontFace(bool invert); + + void SetColorManagment(ColorManagement colorManagement); + + void SetAnisotropicFiltering(short level); + short GetAnisotropicFiltering(); + + void SetMipmapping(MipmapOption val); + MipmapOption GetMipmapping(); + + void SetOverrideShader(OverrideShaderType type); + OverrideShaderType GetOverrideShader(); + void ActivateOverrideShaderInstancing(RAS_InstancingBuffer *buffer); + + /// \see KX_RayCast + bool RayHit(KX_ClientObjectInfo *client, KX_RayCast *result, RayCastTranform *raytransform); + /// \see KX_RayCast + bool NeedRayCast(KX_ClientObjectInfo *info, void *data); + + /** + * Render Tools + */ + void GetTransform(const mt::mat4& origmat, int objectdrawmode, float mat[16]); + + void FlushDebug(RAS_ICanvas *canvas, RAS_DebugDraw *debugDraw); + + void DisableForText(); + /** + * Renders 3D text string using BFL. + * \param fontid The id of the font. + * \param text The string to render. + * \param size The size of the text. + * \param dpi The resolution of the text. + * \param color The color of the object. + * \param mat The Matrix of the text object. + * \param aspect A scaling factor to compensate for the size. + */ + void RenderText3D( + int fontid, const std::string& text, int size, int dpi, + const float color[4], const float mat[16], float aspect); + + void EnableLights(); + void DisableLights(); + void ProcessLighting(bool uselights, const mt::mat3x4 &trans); + + void PushMatrix(); + void PopMatrix(); + void MultMatrix(const float mat[16]); + void SetMatrixMode(MatrixMode mode); + void LoadMatrix(const float mat[16]); + void LoadIdentity(); + + RAS_ILightObject *CreateLight(); + + void AddLight(RAS_ILightObject *lightobject); + + void RemoveLight(RAS_ILightObject *lightobject); + + /** Set the current off screen depth to the global depth texture used by materials. + * In case of mutlisample off screen a blit to RAS_OFFSCREEN_BLIT_DEPTH is procceed. + */ + void UpdateGlobalDepthTexture(RAS_OffScreen *offScreen); + /// Set the global depth texture to an empty texture. + void ResetGlobalDepthTexture(); + + void MotionBlur(); + + void SetClientObject(void *obj); + + void SetAuxilaryClientInfo(void *inf); + + /** + * Prints information about what the hardware supports. + */ + void PrintHardwareInfo(); +}; + +#endif /* __RAS_RASTERIZER_H__ */ diff --git a/source/gameengine/Rasterizer/RAS_Rect.h b/source/gameengine/Rasterizer/RAS_Rect.h index cd68b336b2a6..138e44656418 100644 --- a/source/gameengine/Rasterizer/RAS_Rect.h +++ b/source/gameengine/Rasterizer/RAS_Rect.h @@ -32,9 +32,7 @@ #ifndef __RAS_RECT_H__ #define __RAS_RECT_H__ -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif +#include /** * \section interface class. @@ -43,62 +41,79 @@ */ class RAS_Rect { -public: // todo: make a decent class, and make private - int m_x1, m_y1; - int m_x2, m_y2; +private: + int m_x1; + int m_y1; + int m_x2; + int m_y2; public: - RAS_Rect() : m_x1(0), m_y1(0), m_x2(0), m_y2(0) {} - int GetWidth( - ) const { + RAS_Rect() + :m_x1(0), + m_y1(0), + m_x2(0), + m_y2(0) + { + } + + int GetWidth() const + { + return m_x2 - m_x1 + 1; + } + int GetHeight() const + { + return m_y2 - m_y1 + 1; + } + + int GetMaxX() const + { return m_x2 - m_x1; } - int GetHeight( - ) const { + int GetMaxY() const + { return m_y2 - m_y1; } - int GetLeft( - ) const { + + int GetLeft() const + { return m_x1; } - int GetRight( - ) const { + int GetRight() const + { return m_x2; } - int GetBottom( - ) const { + int GetBottom() const + { return m_y1; } - int GetTop( - ) const { + int GetTop() const + { return m_y2; } - void SetLeft( - int x1) + void SetLeft(int x1) { m_x1 = x1; } - void SetBottom( - int y1) + void SetBottom(int y1) { m_y1 = y1; } - void SetRight( - int x2) + void SetRight(int x2) { m_x2 = x2; } - void SetTop( - int y2) + void SetTop(int y2) { m_y2 = y2; } +}; +inline std::ostream& operator<<(std::ostream& os, const RAS_Rect& rect) +{ + os << "(" << rect.GetLeft() << ", " << rect.GetBottom() << ", " << rect.GetRight() << ", " << rect.GetTop() << ")"; + return os; +} -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_Rect") -#endif -}; -#endif /* __RAS_RECT_H__ */ +#endif // __RAS_RECT_H__ diff --git a/source/gameengine/Rasterizer/RAS_Shader.cpp b/source/gameengine/Rasterizer/RAS_Shader.cpp new file mode 100644 index 000000000000..5aa41670b392 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_Shader.cpp @@ -0,0 +1,595 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Ketsji/RAS_Shader.cpp + * \ingroup bgerast + */ + +#include "RAS_Shader.h" +#include "RAS_Rasterizer.h" + +#include "BLI_utildefines.h" +#include "MEM_guardedalloc.h" + +#include "GPU_shader.h" + +#include // for memcpy + +#include "CM_Message.h" + +RAS_Shader::RAS_Uniform::RAS_Uniform(int data_size) + :m_loc(-1), + m_count(1), + m_dirty(true), + m_type(UNI_NONE), + m_dataLen(data_size) +{ +#ifdef SORT_UNIFORMS + m_data = (void *)MEM_mallocN(m_dataLen, "shader-uniform-alloc"); +#endif +} + +RAS_Shader::RAS_Uniform::~RAS_Uniform() +{ +#ifdef SORT_UNIFORMS + if (m_data) { + MEM_freeN(m_data); + m_data = nullptr; + } +#endif +} + +void RAS_Shader::RAS_Uniform::Apply(RAS_Shader *shader) +{ +#ifdef SORT_UNIFORMS + BLI_assert(m_type > UNI_NONE && m_type < UNI_MAX && m_data); + + if (!m_dirty) { + return; + } + + GPUShader *gpushader = shader->GetGPUShader(); + switch (m_type) { + case UNI_FLOAT: + { + float *f = (float *)m_data; + GPU_shader_uniform_vector(gpushader, m_loc, 1, m_count, (float *)f); + break; + } + case UNI_INT: + { + int *f = (int *)m_data; + GPU_shader_uniform_vector_int(gpushader, m_loc, 1, m_count, (int *)f); + break; + } + case UNI_FLOAT2: + { + float *f = (float *)m_data; + GPU_shader_uniform_vector(gpushader, m_loc, 2, m_count, (float *)f); + break; + } + case UNI_FLOAT3: + { + float *f = (float *)m_data; + GPU_shader_uniform_vector(gpushader, m_loc, 3, m_count, (float *)f); + break; + } + case UNI_FLOAT4: + { + float *f = (float *)m_data; + GPU_shader_uniform_vector(gpushader, m_loc, 4, m_count, (float *)f); + break; + } + case UNI_INT2: + { + int *f = (int *)m_data; + GPU_shader_uniform_vector_int(gpushader, m_loc, 2, m_count, (int *)f); + break; + } + case UNI_INT3: + { + int *f = (int *)m_data; + GPU_shader_uniform_vector_int(gpushader, m_loc, 3, m_count, (int *)f); + break; + } + case UNI_INT4: + { + int *f = (int *)m_data; + GPU_shader_uniform_vector_int(gpushader, m_loc, 4, m_count, (int *)f); + break; + } + case UNI_MAT4: + { + float *f = (float *)m_data; + GPU_shader_uniform_vector(gpushader, m_loc, 16, m_count, (float *)f); + break; + } + case UNI_MAT3: + { + float *f = (float *)m_data; + GPU_shader_uniform_vector(gpushader, m_loc, 9, m_count, (float *)f); + break; + } + } + m_dirty = false; +#endif +} + +void RAS_Shader::RAS_Uniform::SetData(int location, int type, unsigned int count, bool transpose) +{ +#ifdef SORT_UNIFORMS + m_type = type; + m_loc = location; + m_count = count; + m_dirty = true; +#endif +} + +int RAS_Shader::RAS_Uniform::GetLocation() +{ + return m_loc; +} + +void *RAS_Shader::RAS_Uniform::GetData() +{ + return m_data; +} + +RAS_Shader::UniformInfo::UniformInfo(const std::string& name, GPUShader *shader) + :nameHash(std::hash()(name)), + location(GPU_shader_get_uniform(shader, name.c_str())) +{ +} + +bool RAS_Shader::Ok() const +{ + return (m_shader && m_use); +} + +RAS_Shader::RAS_Shader() + :m_shader(nullptr), + m_use(false), + m_error(false), + m_dirty(true) +{ + for (unsigned short i = 0; i < MAX_PROGRAM; ++i) { + m_progs[i] = ""; + } +} + +RAS_Shader::~RAS_Shader() +{ + ClearUniforms(); + + DeleteShader(); +} + +void RAS_Shader::ClearUniforms() +{ + for (RAS_Uniform *uni : m_uniforms) { + delete uni; + } + m_uniforms.clear(); + + for (RAS_DefUniform *uni : m_preDef) { + delete uni; + } + m_preDef.clear(); +} + +RAS_Shader::RAS_Uniform *RAS_Shader::FindUniform(const int location) +{ +#ifdef SORT_UNIFORMS + for (RAS_Uniform *uni : m_uniforms) { + if (uni->GetLocation() == location) { + return uni; + } + } +#endif + return nullptr; +} + +void RAS_Shader::SetUniformfv(int location, int type, float *param, int size, unsigned int count, bool transpose) +{ +#ifdef SORT_UNIFORMS + RAS_Uniform *uni = FindUniform(location); + + if (uni) { + memcpy(uni->GetData(), param, size); + uni->SetData(location, type, count, transpose); + } + else { + uni = new RAS_Uniform(size); + memcpy(uni->GetData(), param, size); + uni->SetData(location, type, count, transpose); + m_uniforms.push_back(uni); + } + + m_dirty = true; +#endif +} + +void RAS_Shader::SetUniformiv(int location, int type, int *param, int size, unsigned int count, bool transpose) +{ +#ifdef SORT_UNIFORMS + RAS_Uniform *uni = FindUniform(location); + + if (uni) { + memcpy(uni->GetData(), param, size); + uni->SetData(location, type, count, transpose); + } + else { + uni = new RAS_Uniform(size); + memcpy(uni->GetData(), param, size); + uni->SetData(location, type, count, transpose); + m_uniforms.push_back(uni); + } + + m_dirty = true; +#endif +} + +void RAS_Shader::ApplyShader() +{ +#ifdef SORT_UNIFORMS + if (!m_dirty) { + return; + } + + for (unsigned int i = 0; i < m_uniforms.size(); i++) { + m_uniforms[i]->Apply(this); + } + + m_dirty = false; +#endif +} + +void RAS_Shader::UnloadShader() +{ + // +} + +void RAS_Shader::DeleteShader() +{ + if (m_shader) { + GPU_shader_free(m_shader); + m_shader = nullptr; + } +} + +std::string RAS_Shader::GetParsedProgram(ProgramType type) const +{ + std::string prog = m_progs[type]; + if (prog.empty()) { + return prog; + } + + const unsigned int pos = prog.find("#version"); + if (pos != -1) { + CM_Warning("found redundant #version directive in shader program, directive ignored."); + const unsigned int nline = prog.find("\n", pos); + prog.erase(pos, nline - pos); + } + + prog.insert(0, "#line 0\n"); + + return prog; +} + +bool RAS_Shader::LinkProgram() +{ + std::string vert; + std::string frag; + std::string geom; + + if (m_progs[VERTEX_PROGRAM].empty() || m_progs[FRAGMENT_PROGRAM].empty()) { + CM_Error("invalid GLSL sources."); + return false; + } + + vert = GetParsedProgram(VERTEX_PROGRAM); + frag = GetParsedProgram(FRAGMENT_PROGRAM); + geom = GetParsedProgram(GEOMETRY_PROGRAM); + m_shader = GPU_shader_create(vert.c_str(), frag.c_str(), geom.empty() ? nullptr : geom.c_str(), + nullptr, nullptr, 0, 0, 0); + if (!m_shader) { + m_error = true; + return false; + } + + ExtractUniformInfos(); + + m_error = false; + return true; +} + +void RAS_Shader::ValidateProgram() +{ + char *log = GPU_shader_validate(m_shader); + if (log) { + CM_Debug("---- GLSL Validation ----\n" << log); + MEM_freeN(log); + } +} + +void RAS_Shader::ExtractUniformInfos() +{ + m_uniformInfos.clear(); + + GPUUniformInfo *infos; + const unsigned int count = GPU_shader_get_uniform_infos(m_shader, &infos); + + for (unsigned short i = 0; i < count; ++i) { + const GPUUniformInfo& gpuinfo = infos[i]; + // Simple uniforms. + if (gpuinfo.size == 1) { + m_uniformInfos.emplace_back(gpuinfo.name, m_shader); + } + // Array uniforms. + else { + // Store the uniform base name. + const std::string baseName(gpuinfo.name, 0, strlen(gpuinfo.name) - 3); + m_uniformInfos.emplace_back(baseName, m_shader); + + // Store location of each uniform items: name[i]. + for (unsigned short i = 0; i < gpuinfo.size; ++i) { + const std::string name = baseName + '[' + std::to_string(i) + ']'; + m_uniformInfos.emplace_back(name, m_shader); + } + } + } + + if (infos) { + MEM_freeN(infos); + } + + // Sort uniforms per name hash for fast search. + std::sort(m_uniformInfos.begin(), m_uniformInfos.end()); +} + +bool RAS_Shader::GetError() +{ + return m_error; +} + +unsigned int RAS_Shader::GetProg() +{ + return GPU_shader_program(m_shader); +} + +GPUShader *RAS_Shader::GetGPUShader() +{ + return m_shader; +} + +void RAS_Shader::SetSampler(int loc, int unit) +{ + GPU_shader_uniform_int(m_shader, loc, unit); +} + +void RAS_Shader::BindProg() +{ + GPU_shader_bind(m_shader); +} + +void RAS_Shader::UnbindProg() +{ + GPU_shader_unbind(); +} + +void RAS_Shader::SetEnabled(bool enabled) +{ + m_use = enabled; +} + +bool RAS_Shader::GetEnabled() const +{ + return m_use; +} + +void RAS_Shader::Update(RAS_Rasterizer *rasty, const mt::mat4 &model) +{ + if (!Ok() || m_preDef.empty()) { + return; + } + + const mt::mat4 &view = rasty->GetViewMatrix(); + + for (RAS_DefUniform *uni : m_preDef) { + if (uni->m_loc == -1) { + continue; + } + + switch (uni->m_type) { + case MODELMATRIX: + { + SetUniform(uni->m_loc, model); + break; + } + case MODELMATRIX_TRANSPOSE: + { + SetUniform(uni->m_loc, model, true); + break; + } + case MODELMATRIX_INVERSE: + { + SetUniform(uni->m_loc, model.Inverse()); + break; + } + case MODELMATRIX_INVERSETRANSPOSE: + { + SetUniform(uni->m_loc, model.Inverse(), true); + break; + } + case MODELVIEWMATRIX: + { + SetUniform(uni->m_loc, view * model); + break; + } + case MODELVIEWMATRIX_TRANSPOSE: + { + mt::mat4 mat(view *model); + SetUniform(uni->m_loc, mat, true); + break; + } + case MODELVIEWMATRIX_INVERSE: + { + mt::mat4 mat(view *model); + SetUniform(uni->m_loc, mat.Inverse()); + break; + } + case MODELVIEWMATRIX_INVERSETRANSPOSE: + { + mt::mat4 mat(view *model); + SetUniform(uni->m_loc, mat.Inverse(), true); + break; + } + case CAM_POS: + { + mt::vec3 pos(rasty->GetCameraPosition()); + SetUniform(uni->m_loc, pos); + break; + } + case VIEWMATRIX: + { + SetUniform(uni->m_loc, view); + break; + } + case VIEWMATRIX_TRANSPOSE: + { + SetUniform(uni->m_loc, view, true); + break; + } + case VIEWMATRIX_INVERSE: + { + SetUniform(uni->m_loc, view.Inverse()); + break; + } + case VIEWMATRIX_INVERSETRANSPOSE: + { + SetUniform(uni->m_loc, view.Inverse(), true); + break; + } + case CONSTANT_TIMER: + { + SetUniform(uni->m_loc, (float)rasty->GetTime()); + break; + } + case EYE: + { + SetUniform(uni->m_loc, (rasty->GetEye() == RAS_Rasterizer::RAS_STEREO_LEFTEYE) ? 0.0f : 0.5f); + } + default: + { + break; + } + } + } +} + +int RAS_Shader::GetAttribLocation(const std::string& name) +{ + return GPU_shader_get_attribute(m_shader, name.c_str()); +} + +void RAS_Shader::BindAttribute(const std::string& attr, int loc) +{ + GPU_shader_bind_attribute(m_shader, loc, attr.c_str()); +} + +int RAS_Shader::GetUniformLocation(const std::string& name, bool debug) +{ + BLI_assert(m_shader != nullptr); + + const size_t hash = std::hash()(name); + // Use binary search based on hashed name. + std::vector::const_iterator it = std::lower_bound(m_uniformInfos.begin(), m_uniformInfos.end(), hash, + [](const UniformInfo& info, size_t hash){ return (info.nameHash < hash); }); + + if (it == m_uniformInfos.end() || it->nameHash != hash) { + if (debug) { + CM_Error("invalid uniform value: " << name << "."); + } + return -1; + } + return it->location; +} + +void RAS_Shader::SetUniform(int uniform, const mt::vec2 &vec) +{ + GPU_shader_uniform_vector(m_shader, uniform, 2, 1, vec.Data()); +} + +void RAS_Shader::SetUniform(int uniform, const mt::vec3 &vec) +{ + GPU_shader_uniform_vector(m_shader, uniform, 3, 1, vec.Data()); +} + +void RAS_Shader::SetUniform(int uniform, const mt::vec4 &vec) +{ + GPU_shader_uniform_vector(m_shader, uniform, 4, 1, vec.Data()); +} + +void RAS_Shader::SetUniform(int uniform, const unsigned int &val) +{ + GPU_shader_uniform_int(m_shader, uniform, val); +} + +void RAS_Shader::SetUniform(int uniform, const int val) +{ + GPU_shader_uniform_int(m_shader, uniform, val); +} + +void RAS_Shader::SetUniform(int uniform, const float &val) +{ + GPU_shader_uniform_float(m_shader, uniform, val); +} + +void RAS_Shader::SetUniform(int uniform, const mt::mat4 &vec, bool transpose) +{ + GPU_shader_uniform_vector(m_shader, uniform, 16, 1, (float *)vec.Data()); +} + +void RAS_Shader::SetUniform(int uniform, const mt::mat3 &vec, bool transpose) +{ + float value[9]; + vec.Pack(value); + GPU_shader_uniform_vector(m_shader, uniform, 9, 1, value); +} + +void RAS_Shader::SetUniform(int uniform, const float *val, int len) +{ + if (len >= 2 && len <= 4) { + GPU_shader_uniform_vector(m_shader, uniform, len, 1, (float *)val); + } + else { + BLI_assert(0); + } +} + +void RAS_Shader::SetUniform(int uniform, const int *val, int len) +{ + if (len >= 2 && len <= 4) { + GPU_shader_uniform_vector_int(m_shader, uniform, len, 1, (int *)val); + } + else { + BLI_assert(0); + } +} diff --git a/source/gameengine/Rasterizer/RAS_Shader.h b/source/gameengine/Rasterizer/RAS_Shader.h new file mode 100644 index 000000000000..2d967408927e --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_Shader.h @@ -0,0 +1,213 @@ + +/** \file RAS_Shader.h + * \ingroup bgerast + */ + +#ifndef __RAS_SHADER_H__ +#define __RAS_SHADER_H__ + +#include "mathfu.h" + +#include +#include +#include + +#define SORT_UNIFORMS 1 + +class RAS_Rasterizer; +struct GPUShader; + +/** + * RAS_Shader + * shader access + */ +class RAS_Shader +{ +public: + /** + * RAS_Uniform + * uniform storage + */ + class RAS_Uniform + { + private: + int m_loc; // Uniform location + unsigned int m_count; // Number of items + void *m_data; // Memory allocated for variable + bool m_dirty; // Caching variable + int m_type; // Enum UniformTypes + const int m_dataLen; // Length of our data + public: + RAS_Uniform(int data_size); + ~RAS_Uniform(); + + enum UniformTypes { + UNI_NONE = 0, + UNI_INT, + UNI_FLOAT, + UNI_INT2, + UNI_FLOAT2, + UNI_INT3, + UNI_FLOAT3, + UNI_INT4, + UNI_FLOAT4, + UNI_MAT3, + UNI_MAT4, + UNI_MAX + }; + + void Apply(RAS_Shader *shader); + void SetData(int location, int type, unsigned int count, bool transpose = false); + int GetLocation(); + void *GetData(); + }; + + /** + * RAS_DefUniform + * pre defined uniform storage + */ + class RAS_DefUniform + { + public: + RAS_DefUniform() + : + m_type(0), + m_loc(0), + m_flag(0) + { + } + + int m_type; + int m_loc; + unsigned int m_flag; + }; + + enum ProgramType { + VERTEX_PROGRAM = 0, + FRAGMENT_PROGRAM, + GEOMETRY_PROGRAM, + MAX_PROGRAM + }; + + enum GenType { + MODELVIEWMATRIX, + MODELVIEWMATRIX_TRANSPOSE, + MODELVIEWMATRIX_INVERSE, + MODELVIEWMATRIX_INVERSETRANSPOSE, + MODELMATRIX, + MODELMATRIX_TRANSPOSE, + MODELMATRIX_INVERSE, + MODELMATRIX_INVERSETRANSPOSE, + VIEWMATRIX, + VIEWMATRIX_TRANSPOSE, + VIEWMATRIX_INVERSE, + VIEWMATRIX_INVERSETRANSPOSE, + CAM_POS, + CONSTANT_TIMER, + EYE + }; + +protected: + struct UniformInfo + { + /// Hashed uniform name. + size_t nameHash; + /// Uniform location. + int location; + + /** Construct uniform info + * \param name The uniform name. + * \param shader The shader used to retrieve uniform location. + */ + UniformInfo(const std::string& name, GPUShader *shader); + + inline bool operator< (const UniformInfo& other) const + { + return (nameHash < other.nameHash); + } + }; + + // Uniform information sorted by hashed name value. + std::vector m_uniformInfos; + + typedef std::vector RAS_UniformVec; + typedef std::vector RAS_UniformVecDef; + + GPUShader *m_shader; + bool m_use; + std::string m_progs[MAX_PROGRAM]; + bool m_error; + bool m_dirty; + + // Stored uniform variables + RAS_UniformVec m_uniforms; + RAS_UniformVecDef m_preDef; + + /** Parse shader program to prevent redundant macro directives. + * \param type The program type to parse. + * \return The parsed program. + */ + std::string GetParsedProgram(ProgramType type) const; + + // Compiles and links the shader + virtual bool LinkProgram(); + void ValidateProgram(); + void ExtractUniformInfos(); + + // search by location + RAS_Uniform *FindUniform(const int location); + + // clears uniform data + void ClearUniforms(); + +public: + RAS_Shader(); + virtual ~RAS_Shader(); + + + bool GetError(); + bool Ok() const; + GPUShader *GetGPUShader(); + + unsigned int GetProg(); + + void BindProg(); + void UnbindProg(); + + void SetEnabled(bool enabled); + bool GetEnabled() const; + + // Apply methods : sets colected uniforms + void ApplyShader(); + void UnloadShader(); + void DeleteShader(); + + // Update predefined uniforms each render call + void Update(RAS_Rasterizer *rasty, const mt::mat4 &model); + + void SetSampler(int loc, int unit); + + void SetUniformfv(int location, int type, float *param, int size, unsigned int count, bool transpose = false); + void SetUniformiv(int location, int type, int *param, int size, unsigned int count, bool transpose = false); + int GetAttribLocation(const std::string& name); + void BindAttribute(const std::string& attr, int loc); + + /** Return uniform location in the shader. + * \param name The uniform name. + * \param debug Print message for unfound coresponding uniform name. + */ + int GetUniformLocation(const std::string& name, bool debug=true); + + void SetUniform(int uniform, const mt::vec2 &vec); + void SetUniform(int uniform, const mt::vec3 &vec); + void SetUniform(int uniform, const mt::vec4 &vec); + void SetUniform(int uniform, const mt::mat4 &vec, bool transpose = false); + void SetUniform(int uniform, const mt::mat3 &vec, bool transpose = false); + void SetUniform(int uniform, const float &val); + void SetUniform(int uniform, const float *val, int len); + void SetUniform(int uniform, const int *val, int len); + void SetUniform(int uniform, const unsigned int &val); + void SetUniform(int uniform, const int val); +}; + +#endif /* __RAS_SHADER_H__ */ diff --git a/source/gameengine/Rasterizer/RAS_TexVert.cpp b/source/gameengine/Rasterizer/RAS_TexVert.cpp deleted file mode 100644 index 6b178edde93d..000000000000 --- a/source/gameengine/Rasterizer/RAS_TexVert.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Rasterizer/RAS_TexVert.cpp - * \ingroup bgerast - */ - - -#include "RAS_TexVert.h" -#include "MT_Matrix4x4.h" -#include "BLI_math.h" - -RAS_TexVert::RAS_TexVert(const MT_Point3& xyz, - const MT_Point2 uvs[MAX_UNIT], - const MT_Vector4& tangent, - const unsigned int rgba, - const MT_Vector3& normal, - const bool flat, - const unsigned int origindex) -{ - xyz.getValue(m_localxyz); - SetRGBA(rgba); - SetNormal(normal); - tangent.getValue(m_tangent); - m_flag = (flat) ? FLAT: 0; - m_origindex = origindex; - m_unit = 2; - m_softBodyIndex = -1; - - for (int i = 0; i < MAX_UNIT; ++i) - { - uvs[i].getValue(m_uvs[i]); - } -} - -const MT_Point3& RAS_TexVert::xyz() -{ - g_pt3.setValue(m_localxyz); - return g_pt3; -} - -void RAS_TexVert::SetRGBA(const MT_Vector4& rgba) -{ - unsigned char *colp = (unsigned char*) &m_rgba; - colp[0] = (unsigned char) (rgba[0] * 255.0f); - colp[1] = (unsigned char) (rgba[1] * 255.0f); - colp[2] = (unsigned char) (rgba[2] * 255.0f); - colp[3] = (unsigned char) (rgba[3] * 255.0f); -} - - -void RAS_TexVert::SetXYZ(const MT_Point3& xyz) -{ - xyz.getValue(m_localxyz); -} - -void RAS_TexVert::SetXYZ(const float xyz[3]) -{ - copy_v3_v3(m_localxyz, xyz); -} - -void RAS_TexVert::SetUV(int index, const MT_Point2& uv) -{ - uv.getValue(m_uvs[index]); -} - -void RAS_TexVert::SetUV(int index, const float uv[2]) -{ - copy_v2_v2(m_uvs[index], uv); -} - -void RAS_TexVert::SetRGBA(const unsigned int rgba) -{ - m_rgba = rgba; -} - - -void RAS_TexVert::SetFlag(const short flag) -{ - m_flag = flag; -} - -void RAS_TexVert::SetUnit(const unsigned int u) -{ - m_unit = (u <= (unsigned int) MAX_UNIT) ? u: (unsigned int)MAX_UNIT; -} - -void RAS_TexVert::SetNormal(const MT_Vector3& normal) -{ - normal.getValue(m_normal); -} - -void RAS_TexVert::SetTangent(const MT_Vector3& tangent) -{ - tangent.getValue(m_tangent); -} - - -// compare two vertices, and return true if both are almost identical (they can be shared) -bool RAS_TexVert::closeTo(const RAS_TexVert* other) -{ - const float eps = FLT_EPSILON; - for (int i = 0; i < MAX_UNIT; i++) { - if (!compare_v2v2(m_uvs[i], other->m_uvs[i], eps)) { - return false; - } - } - - return (/* m_flag == other->m_flag && */ - /* at the moment the face only stores the smooth/flat setting so don't bother comparing it */ - (m_rgba == other->m_rgba) && - compare_v3v3(m_normal, other->m_normal, eps) && - compare_v3v3(m_tangent, other->m_tangent, eps) - /* don't bother comparing m_localxyz since we know there from the same vert */ - /* && compare_v3v3(m_localxyz, other->m_localxyz, eps))*/ - ); -} - -short RAS_TexVert::getFlag() const -{ - return m_flag; -} - - -unsigned int RAS_TexVert::getUnit() const -{ - return m_unit; -} - -void RAS_TexVert::Transform(const MT_Matrix4x4& mat, const MT_Matrix4x4& nmat) -{ - SetXYZ((mat * MT_Vector4(m_localxyz[0], m_localxyz[1], m_localxyz[2], 1.0f)).getValue()); - SetNormal((nmat * MT_Vector4(m_normal[0], m_normal[1], m_normal[2], 1.0f)).getValue()); - SetTangent((nmat * MT_Vector4(m_tangent[0], m_tangent[1], m_tangent[2], 1.0f)).getValue()); -} - -void RAS_TexVert::TransformUV(int index, const MT_Matrix4x4& mat) -{ - SetUV(index, (mat * MT_Vector4(m_uvs[index][0], m_uvs[index][1], 0.0f, 1.0f)).getValue()); -} diff --git a/source/gameengine/Rasterizer/RAS_TexVert.h b/source/gameengine/Rasterizer/RAS_TexVert.h deleted file mode 100644 index 6704f52fe69c..000000000000 --- a/source/gameengine/Rasterizer/RAS_TexVert.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file RAS_TexVert.h - * \ingroup bgerast - */ - -#ifndef __RAS_TEXVERT_H__ -#define __RAS_TEXVERT_H__ - - -#include "MT_Point3.h" -#include "MT_Point2.h" -#include "MT_Transform.h" - -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -static MT_Point3 g_pt3; -static MT_Point2 g_pt2; - -class RAS_TexVert -{ - - float m_localxyz[3]; // 3*4 = 12 - float m_uvs[8][2]; // 8*2*4=64 //8 = MAX_UNIT - unsigned int m_rgba; // 4 - float m_tangent[4]; // 4*4 = 16 - float m_normal[3]; // 3*4 = 12 - short m_flag; // 2 - short m_softBodyIndex; //2 - unsigned int m_unit; // 4 - unsigned int m_origindex; // 4 - char m_padding[8]; // 8 - //--------- - // 128 - // 32 bytes alignment improves performance on ATI cards. - -public: - enum { - FLAT = 1, - MAX_UNIT = 8 - }; - - short getFlag() const; - unsigned int getUnit() const; - - RAS_TexVert()// :m_xyz(0,0,0),m_uv(0,0),m_rgba(0) - {} - RAS_TexVert(const MT_Point3& xyz, - const MT_Point2 uvs[MAX_UNIT], - const MT_Vector4& tangent, - const unsigned int rgba, - const MT_Vector3& normal, - const bool flat, - const unsigned int origindex); - ~RAS_TexVert() {}; - - const float* getUV (int unit) const { - return m_uvs[unit]; - }; - - const float* getXYZ() const { - return m_localxyz; - }; - - const float* getNormal() const { - return m_normal; - } - - short int getSoftBodyIndex() const - { - return m_softBodyIndex; - } - - void setSoftBodyIndex(short int sbIndex) - { - m_softBodyIndex = sbIndex; - } - - const float* getTangent() const { - return m_tangent; - } - - const unsigned char* getRGBA() const { - return (unsigned char *) &m_rgba; - } - - unsigned int getOrigIndex() const { - return m_origindex; - } - - void SetXYZ(const MT_Point3& xyz); - void SetXYZ(const float xyz[3]); - void SetUV(int index, const MT_Point2& uv); - void SetUV(int index, const float uv[2]); - - void SetRGBA(const unsigned int rgba); - void SetNormal(const MT_Vector3& normal); - void SetTangent(const MT_Vector3& tangent); - void SetFlag(const short flag); - void SetUnit(const unsigned u); - - void SetRGBA(const MT_Vector4& rgba); - const MT_Point3& xyz(); - - void Transform(const class MT_Matrix4x4& mat, - const class MT_Matrix4x4& nmat); - void TransformUV(int index, const MT_Matrix4x4& mat); - - // compare two vertices, to test if they can be shared, used for - // splitting up based on uv's, colors, etc - bool closeTo(const RAS_TexVert* other); - - -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:RAS_TexVert") -#endif -}; - -#endif /* __RAS_TEXVERT_H__ */ diff --git a/source/gameengine/Rasterizer/RAS_TextUser.cpp b/source/gameengine/Rasterizer/RAS_TextUser.cpp new file mode 100644 index 000000000000..b2a5986ba861 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_TextUser.cpp @@ -0,0 +1,115 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is: all of this file. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_TextUser.cpp + * \ingroup bgerast + */ + +#include "RAS_TextUser.h" +#include "RAS_DisplayArrayBucket.h" + +RAS_TextUser::RAS_TextUser(void *clientobj, RAS_BoundingBox *boundingBox) + :RAS_MeshUser(clientobj, boundingBox, nullptr), + m_fontid(0), + m_size(0), + m_dpi(0), + m_aspect(0.0f), + m_offset(mt::zero3), + m_spacing(mt::zero3) +{ +} + +RAS_TextUser::~RAS_TextUser() +{ +} + +int RAS_TextUser::GetFontId() const +{ + return m_fontid; +} + +int RAS_TextUser::GetSize() const +{ + return m_size; +} + +int RAS_TextUser::GetDpi() const +{ + return m_dpi; +} + +float RAS_TextUser::GetAspect() const +{ + return m_aspect; +} + +const mt::vec3& RAS_TextUser::GetOffset() const +{ + return m_offset; +} + +const mt::vec3& RAS_TextUser::GetSpacing() const +{ + return m_spacing; +} + +const std::vector& RAS_TextUser::GetTexts() const +{ + return m_texts; +} + +void RAS_TextUser::SetFontId(int fontid) +{ + m_fontid = fontid; +} + +void RAS_TextUser::SetSize(int size) +{ + m_size = size; +} + +void RAS_TextUser::SetDpi(int dpi) +{ + m_dpi = dpi; +} + +void RAS_TextUser::SetAspect(float aspect) +{ + m_aspect = aspect; +} + +void RAS_TextUser::SetOffset(const mt::vec3& offset) +{ + m_offset = offset; +} + +void RAS_TextUser::SetSpacing(const mt::vec3& spacing) +{ + m_spacing = spacing; +} + +void RAS_TextUser::SetTexts(const std::vector& texts) +{ + m_texts = texts; +} diff --git a/source/gameengine/Rasterizer/RAS_TextUser.h b/source/gameengine/Rasterizer/RAS_TextUser.h new file mode 100644 index 000000000000..f6b4a98fffa0 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_TextUser.h @@ -0,0 +1,68 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is: all of this file. + * + * Contributor(s): Porteries Tristan. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_TextUser.h + * \ingroup bgerast + */ + +#ifndef __RAS_TEXT_USER_H__ +#define __RAS_TEXT_USER_H__ + +#include "RAS_MeshUser.h" + +#include + +class RAS_TextUser : public RAS_MeshUser +{ +private: + std::vector m_texts; + int m_fontid; + int m_size; + int m_dpi; + float m_aspect; + mt::vec3 m_offset; + mt::vec3 m_spacing; + +public: + RAS_TextUser(void *clientobj, RAS_BoundingBox *boundingBox); + virtual ~RAS_TextUser(); + + int GetFontId() const; + int GetSize() const; + int GetDpi() const; + float GetAspect() const; + const mt::vec3& GetOffset() const; + const mt::vec3& GetSpacing() const; + const std::vector& GetTexts() const; + + void SetFontId(int fontid); + void SetSize(int size); + void SetDpi(int dpi); + void SetAspect(float aspect); + void SetOffset(const mt::vec3& offset); + void SetSpacing(const mt::vec3& spacing); + void SetTexts(const std::vector& texts); +}; + +#endif // __RAS_TEXT_USER_H__ diff --git a/source/gameengine/Rasterizer/RAS_Texture.cpp b/source/gameengine/Rasterizer/RAS_Texture.cpp new file mode 100644 index 000000000000..bd43f6211b1d --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_Texture.cpp @@ -0,0 +1,98 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file gameengine/Ketsji/RAS_Texture.cpp + * \ingroup ketsji + */ + +#include "RAS_Texture.h" +#include "RAS_TextureRenderer.h" + +#include "GPU_glew.h" + +RAS_Texture::RAS_Texture() + :m_bindCode(-1), + m_name(""), + m_renderer(nullptr) +{ +} + +RAS_Texture::~RAS_Texture() +{ + // If the texture is free before the renderer (e.g lib free) then unregsiter ourself. + if (m_renderer) { + m_renderer->RemoveTextureUser(this); + } +} + +std::string& RAS_Texture::GetName() +{ + return m_name; +} + +void RAS_Texture::SetRenderer(RAS_TextureRenderer *renderer) +{ + m_renderer = renderer; +} + +RAS_TextureRenderer *RAS_Texture::GetRenderer() const +{ + return m_renderer; +} + +int RAS_Texture::GetCubeMapTextureType() +{ + return GL_TEXTURE_CUBE_MAP; +} + +int RAS_Texture::GetTexture2DType() +{ + return GL_TEXTURE_2D; +} + +const std::array& RAS_Texture::GetCubeMapTargets() +{ + static std::array targets{{ + GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, + GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB + }}; + + return targets; +} + +void RAS_Texture::DesactiveTextures() +{ + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, 0); +} + +int RAS_Texture::GetBindCode() const +{ + return m_bindCode; +} + +void RAS_Texture::SetBindCode(int bindcode) +{ + m_bindCode = bindcode; +} diff --git a/source/gameengine/Rasterizer/RAS_Texture.h b/source/gameengine/Rasterizer/RAS_Texture.h new file mode 100644 index 000000000000..a3a63a92dc92 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_Texture.h @@ -0,0 +1,91 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_Texture.h + * \ingroup ketsji + */ + +#ifndef __RAS_TEXTURE_H__ +#define __RAS_TEXTURE_H__ + +#include +#include + +struct MTex; +struct Tex; +struct Image; +struct GPUTexture; + +class RAS_TextureRenderer; + +class RAS_Texture +{ +protected: + int m_bindCode; + std::string m_name; + + RAS_TextureRenderer *m_renderer; + +public: + RAS_Texture(); + virtual ~RAS_Texture(); + + virtual bool Ok() const = 0; + virtual bool IsCubeMap() const = 0; + + virtual MTex *GetMTex() const = 0; + virtual Tex *GetTex() const = 0; + virtual Image *GetImage() const = 0; + virtual GPUTexture *GetGPUTexture() const = 0; + std::string& GetName(); + + void SetRenderer(RAS_TextureRenderer *renderer); + RAS_TextureRenderer *GetRenderer() const; + + virtual unsigned int GetTextureType() = 0; + + /// Return GL_TEXTURE_2D. + static int GetCubeMapTextureType(); + /// Return GL_TEXTURE_CUBE_MAP. + static int GetTexture2DType(); + /// Return all the OpenGL cube map face target, e.g GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB. + static const std::array& GetCubeMapTargets(); + + enum {MaxUnits = 8}; + + virtual void CheckValidTexture() = 0; + virtual void ActivateTexture(int unit) = 0; + virtual void DisableTexture() = 0; + + /** Set the current active OpenGL texture to the first texture + * and bind a null texture in this slot. + * This function must be used very carfully, normally only after + * that the user played with glActiveTexture and to make sure that + * it will not break the render. + * Only the first slot is affected all texture in greater slot are + * not affected but just unused as default. + */ + static void DesactiveTextures(); + + int GetBindCode() const; + void SetBindCode(int bindcode); +}; + +#endif // __RAS_TEXTURE_H__ diff --git a/source/gameengine/Rasterizer/RAS_TextureRenderer.cpp b/source/gameengine/Rasterizer/RAS_TextureRenderer.cpp new file mode 100644 index 000000000000..eed887177b5c --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_TextureRenderer.cpp @@ -0,0 +1,215 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Ulysse Martin, Tristan Porteries, Martins Upitis. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_TextureRenderer.cpp + * \ingroup bgerast + */ + +#include "RAS_TextureRenderer.h" +#include "RAS_Texture.h" +#include "RAS_Rasterizer.h" + +#include "GPU_texture.h" +#include "GPU_framebuffer.h" +#include "GPU_draw.h" + +#include "CM_List.h" + +#include "BKE_image.h" + +#include "BLI_utildefines.h" + +#include "DNA_texture_types.h" + +RAS_TextureRenderer::Face::Face(int target) + :m_fbo(nullptr), + m_rb(nullptr), + m_target(target) +{ +} + +RAS_TextureRenderer::Face::~Face() +{ +} + +void RAS_TextureRenderer::Face::AttachTexture(GPUTexture *tex) +{ + m_fbo = GPU_framebuffer_create(); + m_rb = GPU_renderbuffer_create(GPU_texture_width(tex), GPU_texture_height(tex), + 0, GPU_HDR_NONE, GPU_RENDERBUFFER_DEPTH, nullptr); + + GPU_framebuffer_texture_attach_target(m_fbo, tex, m_target, 0, nullptr); + GPU_framebuffer_renderbuffer_attach(m_fbo, m_rb, 0, nullptr); +} + +void RAS_TextureRenderer::Face::DetachTexture(GPUTexture *tex) +{ + if (m_fbo) { + GPU_framebuffer_texture_detach_target(tex, m_target); + } + if (m_rb) { + GPU_framebuffer_renderbuffer_detach(m_rb); + } + + if (m_fbo) { + GPU_framebuffer_free(m_fbo); + m_fbo = nullptr; + } + if (m_rb) { + GPU_renderbuffer_free(m_rb); + m_rb = nullptr; + } +} + +void RAS_TextureRenderer::Face::Bind() +{ + // Set the viewport in the same time. + GPU_framebuffer_bind_no_save(m_fbo, 0); +} + +RAS_TextureRenderer::RAS_TextureRenderer() + :m_gpuTex(nullptr), + m_useMipmap(false) +{ +} + +RAS_TextureRenderer::~RAS_TextureRenderer() +{ + for (Face& face : m_faces) { + face.DetachTexture(m_gpuTex); + } + + if (m_gpuTex) { + GPU_texture_free(m_gpuTex); + } + + /* This call has for side effect to ask regeneration of all textures + * depending of this image. + */ + for (RAS_Texture *texture : m_textureUsers) { + // Invalidate the renderer in each material texture users. + texture->SetRenderer(nullptr); + BKE_image_free_buffers(texture->GetImage()); + } +} + +void RAS_TextureRenderer::GetValidTexture() +{ + BLI_assert(!m_textureUsers.empty()); + + /* The gpu texture returned by all material textures are the same. + * We can so use the first material texture user. + */ + RAS_Texture *texture = m_textureUsers[0]; + texture->CheckValidTexture(); + GPUTexture *gputex = texture->GetGPUTexture(); + + if (m_gpuTex == gputex) { + // The gpu texture is the same. + return; + } + + if (m_gpuTex) { + for (Face& face : m_faces) { + face.DetachTexture(m_gpuTex); + } + + GPU_texture_free(m_gpuTex); + } + + m_gpuTex = gputex; + + // Increment reference to make sure the gpu texture will not be freed by someone else. + GPU_texture_ref(m_gpuTex); + + for (Face& face : m_faces) { + face.AttachTexture(m_gpuTex); + } + + Tex *tex = texture->GetTex(); + EnvMap *env = tex->env; + m_useMipmap = (env->filtering == ENVMAP_MIPMAP_MIPMAP) && GPU_get_mipmap(); + + if (!m_useMipmap) { + // Disable mipmaping. + GPU_texture_bind(m_gpuTex, 0); + GPU_texture_filter_mode(m_gpuTex, false, (env->filtering == ENVMAP_MIPMAP_LINEAR), false); + GPU_texture_unbind(m_gpuTex); + } +} + +unsigned short RAS_TextureRenderer::GetNumFaces() const +{ + return m_faces.size(); +} + +bool RAS_TextureRenderer::EqualTextureUser(RAS_Texture *texture) const +{ + for (RAS_Texture *user : m_textureUsers) { + if (user->GetMTex() == texture->GetMTex()) { + return true; + } + } + + return false; +} + +void RAS_TextureRenderer::AddTextureUser(RAS_Texture *texture) +{ + m_textureUsers.push_back(texture); + texture->SetRenderer(this); +} + +void RAS_TextureRenderer::RemoveTextureUser(RAS_Texture *texture) +{ + CM_ListRemoveIfFound(m_textureUsers, texture); + texture->SetRenderer(nullptr); +} + +void RAS_TextureRenderer::BeginRender(RAS_Rasterizer *rasty) +{ + GetValidTexture(); +} + +void RAS_TextureRenderer::EndRender(RAS_Rasterizer *rasty) +{ + if (m_useMipmap) { + GPU_texture_bind(m_gpuTex, 0); + GPU_texture_generate_mipmap(m_gpuTex); + GPU_texture_unbind(m_gpuTex); + } +} + +void RAS_TextureRenderer::BeginRenderFace(RAS_Rasterizer *rasty) +{ + // Clear only the depth texture because the background render will override the color texture. + rasty->Clear(RAS_Rasterizer::RAS_DEPTH_BUFFER_BIT); +} + +void RAS_TextureRenderer::EndRenderFace(RAS_Rasterizer *rasty) +{ +} + +void RAS_TextureRenderer::BindFace(unsigned short index) +{ + m_faces[index].Bind(); +} diff --git a/source/gameengine/Rasterizer/RAS_TextureRenderer.h b/source/gameengine/Rasterizer/RAS_TextureRenderer.h new file mode 100644 index 000000000000..ee221efea270 --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_TextureRenderer.h @@ -0,0 +1,100 @@ +/* +* ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +* Contributor(s): Ulysse Martin, Tristan Porteries, Martins Upitis. +* +* ***** END GPL LICENSE BLOCK ***** +*/ + +/** \file RAS_TextureRenderer.h +* \ingroup bgerast +*/ + +#ifndef __RAS_TEXTURE_RENDERER_H__ +#define __RAS_TEXTURE_RENDERER_H__ + +#include + +class RAS_Texture; +class RAS_Rasterizer; + +struct GPUFrameBuffer; +struct GPURenderBuffer; +struct GPUTexture; + +/** \brief This class is used to render something into a material texture (RAS_Texture). + * The render is made by faces added in the sub classes of RAS_TextureRenderer. + */ +class RAS_TextureRenderer +{ +protected: + class Face + { + private: + /// Planar FBO and RBO + GPUFrameBuffer *m_fbo; + GPURenderBuffer *m_rb; + int m_target; + + public: + Face(int target); + ~Face(); + + /// Bind the face frame buffer object. + void Bind(); + /// Recreate and attach frame buffer object and render buffer to the texture. + void AttachTexture(GPUTexture *tex); + /// Free and detach frame buffer object and render buffer to the texture. + void DetachTexture(GPUTexture *tex); + }; + + /// All the material texture users. + std::vector m_textureUsers; + + std::vector m_faces; + +private: + /// Planar texture to attach to frame buffer objects. + GPUTexture *m_gpuTex; + /** Obtain the latest planar texture, if it's not the same as before, + * then detach the previous planar texture and attach the new one. + */ + void GetValidTexture(); + + /// Use mipmapping? + bool m_useMipmap; + +public: + RAS_TextureRenderer(); + virtual ~RAS_TextureRenderer(); + + unsigned short GetNumFaces() const; + + /// Return true if the material texture use the same data than one of the texture user. + bool EqualTextureUser(RAS_Texture *texture) const; + void AddTextureUser(RAS_Texture *texture); + void RemoveTextureUser(RAS_Texture *texture); + + virtual void BeginRender(RAS_Rasterizer *rasty); + virtual void EndRender(RAS_Rasterizer *rasty); + virtual void BeginRenderFace(RAS_Rasterizer *rasty); + virtual void EndRenderFace(RAS_Rasterizer *rasty); + + void BindFace(unsigned short index); +}; + +#endif // __RAS_TEXTURE_RENDERER_H__ diff --git a/source/gameengine/Rasterizer/RAS_ObjectColor.h b/source/gameengine/Rasterizer/RAS_VertexInfo.cpp similarity index 77% rename from source/gameengine/Rasterizer/RAS_ObjectColor.h rename to source/gameengine/Rasterizer/RAS_VertexInfo.cpp index 77feffccffc5..1c2fc4eccebc 100644 --- a/source/gameengine/Rasterizer/RAS_ObjectColor.h +++ b/source/gameengine/Rasterizer/RAS_VertexInfo.cpp @@ -20,22 +20,23 @@ * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): Tristan Porteries. * * ***** END GPL LICENSE BLOCK ***** */ -/** \file RAS_ObjectColor.h +/** \file gameengine/Rasterizer/RAS_VertexInfo.cpp * \ingroup bgerast */ -#ifndef __RAS_OBJECTCOLOR_H__ -#define __RAS_OBJECTCOLOR_H__ +#include "RAS_VertexInfo.h" -struct RAS_ObjectColor { - float m_red; - float m_green; - float m_blue; -}; +RAS_VertexInfo::RAS_VertexInfo(unsigned int origindex, bool flat) + :m_origindex(origindex) +{ + m_flag = (flat) ? FLAT : 0; +} -#endif /* __RAS_OBJECTCOLOR_H__ */ +RAS_VertexInfo::~RAS_VertexInfo() +{ +} diff --git a/source/gameengine/Rasterizer/RAS_VertexInfo.h b/source/gameengine/Rasterizer/RAS_VertexInfo.h new file mode 100644 index 000000000000..bee1e41fb9ed --- /dev/null +++ b/source/gameengine/Rasterizer/RAS_VertexInfo.h @@ -0,0 +1,75 @@ +/* + * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Tristan Porteries. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file RAS_VertexInfo.h + * \ingroup bgerast + */ + +#ifndef __RAS_VERTEX_INFO_H__ +#define __RAS_VERTEX_INFO_H__ + +#include + +class RAS_VertexInfo +{ +public: + enum { + FLAT = 1, + }; + +private: + unsigned int m_origindex; + short m_softBodyIndex; + uint8_t m_flag; + +public: + RAS_VertexInfo(unsigned int origindex, bool flat); + ~RAS_VertexInfo(); + + inline const unsigned int GetOrigIndex() const + { + return m_origindex; + } + + inline short int GetSoftBodyIndex() const + { + return m_softBodyIndex; + } + + inline void SetSoftBodyIndex(short int sbIndex) + { + m_softBodyIndex = sbIndex; + } + + inline const uint8_t GetFlag() const + { + return m_flag; + } + + inline void SetFlag(const uint8_t flag) + { + m_flag = flag; + } +}; + + +#endif // __RAS_VERTEX_INFO_H__ diff --git a/source/gameengine/Rasterizer/RAS_texmatrix.cpp b/source/gameengine/Rasterizer/RAS_texmatrix.cpp deleted file mode 100644 index acaec16851b3..000000000000 --- a/source/gameengine/Rasterizer/RAS_texmatrix.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* - * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file gameengine/Rasterizer/RAS_texmatrix.cpp - * \ingroup bgerast - */ - - -#include "RAS_TexMatrix.h" - -void RAS_CalcTexMatrix(RAS_TexVert p[3],MT_Point3& origin,MT_Vector3& udir,MT_Vector3& vdir) -{ -// precondition: 3 vertices are non-collinear - - MT_Vector3 vec1 = p[1].xyz()-p[0].xyz(); - MT_Vector3 vec2 = p[2].xyz()-p[0].xyz(); - MT_Vector3 normal = vec1.cross(vec2); - normal.normalize(); - - // determine which coordinate we drop, ie. max coordinate in the normal - - - int ZCOORD = normal.closestAxis(); - int XCOORD = (ZCOORD+1)%3; - int YCOORD = (ZCOORD+2)%3; - - // ax+by+cz+d=0 - MT_Scalar d = -p[0].xyz().dot(normal); - - - MT_Matrix3x3 mat3( p[0].getUV(0)[0],p[0].getUV(0)[1], 1, - p[1].getUV(0)[0],p[1].getUV(0)[1], 1, - p[2].getUV(0)[0],p[2].getUV(0)[1], 1); - - - MT_Matrix3x3 mat3inv = mat3.inverse(); - - MT_Vector3 p123x(p[0].xyz()[XCOORD],p[1].xyz()[XCOORD],p[2].xyz()[XCOORD]); - MT_Vector3 resultx = mat3inv*p123x; - MT_Vector3 p123y(p[0].xyz()[YCOORD],p[1].xyz()[YCOORD],p[2].xyz()[YCOORD]); - MT_Vector3 resulty = mat3inv*p123y; - - // normal[ZCOORD] is not zero, because it's chosen to be maximal (absolute), and normal has length 1, - // so at least on of the coords is <> 0 - - //droppedvalue udir.dot(normal) =0 - MT_Scalar droppedu = -(resultx.x()*normal[XCOORD]+resulty.x()*normal[YCOORD])/normal[ZCOORD]; - udir[XCOORD] = resultx.x(); - udir[YCOORD] = resulty.x(); - udir[ZCOORD] = droppedu; - MT_Scalar droppedv = -(resultx.y()*normal[XCOORD]+resulty.y()*normal[YCOORD])/normal[ZCOORD]; - vdir[XCOORD] = resultx.y(); - vdir[YCOORD] = resulty.y(); - vdir[ZCOORD] = droppedv; - // droppedvalue b = -(ax+cz+d)/y; - MT_Scalar droppedvalue = -((resultx.z()*normal[XCOORD] + resulty.z()*normal[YCOORD]+d))/normal[ZCOORD]; - origin[XCOORD] = resultx.z(); - origin[YCOORD] = resulty.z(); - origin[ZCOORD] = droppedvalue; - - -} - -#ifdef _TEXOWNMAIN - -int main() -{ - - MT_Point2 puv0={0,0}; - MT_Point3 pxyz0 (0,0,128); - - MT_Scalar puv1[2] = {1,0}; - MT_Point3 pxyz1(128,0,128); - - MT_Scalar puv2[2] = {1,1}; - MT_Point3 pxyz2(128,0,0); - - RAS_TexVert p0(pxyz0,puv0); - RAS_TexVert p1(pxyz1,puv1); - RAS_TexVert p2(pxyz2,puv2); - - RAS_TexVert vertices[3] = - { - p0, - p1, - p2 - }; - - MT_Vector3 udir,vdir; - MT_Point3 origin; - CalcTexMatrix(vertices,origin,udir,vdir); - - MT_Point3 testpoint(128,32,64); - - MT_Scalar lenu = udir.length2(); - MT_Scalar lenv = vdir.length2(); - - MT_Scalar testu=((pxyz2-origin).dot(udir))/lenu; - MT_Scalar testv=((pxyz2-origin).dot(vdir))/lenv; - - - - - return 0; -} - -#endif // _TEXOWNMAIN diff --git a/source/gameengine/SceneGraph/CMakeLists.txt b/source/gameengine/SceneGraph/CMakeLists.txt index bbad429bbcd9..757bf7185d15 100644 --- a/source/gameengine/SceneGraph/CMakeLists.txt +++ b/source/gameengine/SceneGraph/CMakeLists.txt @@ -25,29 +25,35 @@ set(INC . + ../Common + ../../blender/blenlib ) set(INC_SYS - ../../../intern/moto/include + ../../../intern/debugbreak + ../../../intern/mathfu ) set(SRC SG_BBox.cpp SG_Controller.cpp - SG_IObject.cpp + SG_CullingNode.cpp + SG_Familly.cpp + SG_Frustum.cpp + SG_Interpolator.cpp SG_Node.cpp - SG_Spatial.cpp - SG_Tree.cpp SG_BBox.h SG_Controller.h + SG_CullingNode.h SG_DList.h - SG_IObject.h + SG_Familly.h + SG_Frustum.h + SG_Interpolator.h SG_Node.h SG_ParentRelation.h + SG_ScalarInterpolator.h SG_QList.h - SG_Spatial.h - SG_Tree.h ) blender_add_lib(ge_scenegraph "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/gameengine/SceneGraph/SG_BBox.cpp b/source/gameengine/SceneGraph/SG_BBox.cpp index 9eaba788435c..ddf04b1890ba 100644 --- a/source/gameengine/SceneGraph/SG_BBox.cpp +++ b/source/gameengine/SceneGraph/SG_BBox.cpp @@ -30,233 +30,72 @@ * \ingroup bgesg */ - -#include - #include "SG_BBox.h" -#include "SG_Node.h" -SG_BBox::SG_BBox() : - m_min(0.0f, 0.0f, 0.0f), - m_max(0.0f, 0.0f, 0.0f) +SG_BBox::SG_BBox() { + Set(mt::zero3, mt::zero3); } -SG_BBox::SG_BBox(const MT_Point3 &min, const MT_Point3 &max) : - m_min(min), - m_max(max) +SG_BBox::SG_BBox(const mt::vec3 &min, const mt::vec3 &max) { + Set(min, max); } -SG_BBox::SG_BBox(const SG_BBox &other, const MT_Transform &world) : - m_min(world(other.m_min)), - m_max(world(other.m_max)) +void SG_BBox::UpdateSphere() { - *this += world(MT_Point3(m_min[0], m_min[1], m_max[2])); - *this += world(MT_Point3(m_min[0], m_max[1], m_min[2])); - *this += world(MT_Point3(m_min[0], m_max[1], m_max[2])); - *this += world(MT_Point3(m_max[0], m_min[1], m_min[2])); - *this += world(MT_Point3(m_max[0], m_min[1], m_max[2])); - *this += world(MT_Point3(m_max[0], m_max[1], m_min[2])); + m_center = (m_max + m_min) * 0.5f; + m_radius = (m_center - m_min).Length(); } -SG_BBox::SG_BBox(const SG_BBox &other) : - m_min(other.m_min), - m_max(other.m_max) +const mt::vec3& SG_BBox::GetCenter() const { + return m_center; } -SG_BBox::~ SG_BBox() +const float SG_BBox::GetRadius() const { + return m_radius; } -SG_BBox& SG_BBox::operator +=(const MT_Point3 &point) +const mt::vec3& SG_BBox::GetMin() const { - if (point[0] < m_min[0]) - m_min[0] = point[0]; - else if (point[0] > m_max[0]) - m_max[0] = point[0]; - - if (point[1] < m_min[1]) - m_min[1] = point[1]; - else if (point[1] > m_max[1]) - m_max[1] = point[1]; - - if (point[2] < m_min[2]) - m_min[2] = point[2]; - else if (point[2] > m_max[2]) - m_max[2] = point[2]; - - return *this; + return m_min; } -SG_BBox& SG_BBox::operator += (const SG_BBox &bbox) +const mt::vec3& SG_BBox::GetMax() const { - *this += bbox.m_min; - *this += bbox.m_max; - - return *this; + return m_max; } -SG_BBox SG_BBox::operator +(const SG_BBox &bbox2) const +void SG_BBox::Get(mt::vec3& min, mt::vec3& max) const { - SG_BBox ret = *this; - ret += bbox2; - return ret; + min = m_min; + max = m_max; } -MT_Scalar SG_BBox::volume() const -{ - MT_Vector3 size = m_max - m_min; - return size[0]*size[1]*size[2]; -} -#if 0 -void SG_BBox::translate(const MT_Vector3& dx) +void SG_BBox::SetMin(const mt::vec3& min) { - m_min += dx; - m_max += dx; + m_min = min; + UpdateSphere(); } -void SG_BBox::scale(const MT_Vector3& size, const MT_Point3& point) +void SG_BBox::SetMax(const mt::vec3& max) { - MT_Vector3 center = (m_max - m_min)/2. + point; - m_max = (m_max - center)*size; - m_min = (m_min - center)*size; + m_max = max; + UpdateSphere(); } -#endif -SG_BBox SG_BBox::transform(const MT_Transform &world) const +void SG_BBox::Set(const mt::vec3& min, const mt::vec3& max) { - SG_BBox bbox(world(m_min), world(m_max)); - bbox += world(MT_Point3(m_min[0], m_min[1], m_max[2])); - bbox += world(MT_Point3(m_min[0], m_max[1], m_min[2])); - bbox += world(MT_Point3(m_min[0], m_max[1], m_max[2])); - bbox += world(MT_Point3(m_max[0], m_min[1], m_min[2])); - bbox += world(MT_Point3(m_max[0], m_min[1], m_max[2])); - bbox += world(MT_Point3(m_max[0], m_max[1], m_min[2])); - return bbox; + m_min = min; + m_max = max; + UpdateSphere(); } -bool SG_BBox::inside(const MT_Point3 &point) const +bool SG_BBox::Inside(const mt::vec3& point) const { return point[0] >= m_min[0] && point[0] <= m_max[0] && - point[1] >= m_min[1] && point[1] <= m_max[1] && - point[2] >= m_min[2] && point[2] <= m_max[2]; -} - -bool SG_BBox::inside(const SG_BBox& other) const -{ - return inside(other.m_min) && inside(other.m_max); -} - -bool SG_BBox::intersects(const SG_BBox& other) const -{ - return inside(other.m_min) != inside(other.m_max); -} - -bool SG_BBox::outside(const SG_BBox& other) const -{ - return !inside(other.m_min) && !inside(other.m_max); -} - -SG_BBox::intersect SG_BBox::test(const SG_BBox& other) const -{ - bool point1(inside(other.m_min)), point2(inside(other.m_max)); - - return point1?(point2?INSIDE:INTERSECT):(point2?INTERSECT:OUTSIDE); -} - -void SG_BBox::get(MT_Point3 *box, const MT_Transform &world) const -{ - *box++ = world(m_min); - *box++ = world(MT_Point3(m_min[0], m_min[1], m_max[2])); - *box++ = world(MT_Point3(m_min[0], m_max[1], m_min[2])); - *box++ = world(MT_Point3(m_min[0], m_max[1], m_max[2])); - *box++ = world(MT_Point3(m_max[0], m_min[1], m_min[2])); - *box++ = world(MT_Point3(m_max[0], m_min[1], m_max[2])); - *box++ = world(MT_Point3(m_max[0], m_max[1], m_min[2])); - *box++ = world(m_max); -} - -void SG_BBox::getaa(MT_Point3 *box, const MT_Transform &world) const -{ - const MT_Point3 min(world(m_min)), max(world(m_max)); - *box++ = min; - *box++ = MT_Point3(min[0], min[1], max[2]); - *box++ = MT_Point3(min[0], max[1], min[2]); - *box++ = MT_Point3(min[0], max[1], max[2]); - *box++ = MT_Point3(max[0], min[1], min[2]); - *box++ = MT_Point3(max[0], min[1], max[2]); - *box++ = MT_Point3(max[0], max[1], min[2]); - *box++ = max; -} - -void SG_BBox::getmm(MT_Point3 *box, const MT_Transform &world) const -{ - const MT_Point3 min(world(m_min)), max(world(m_max)); - *box++ = min; - *box++ = max; -} - -void SG_BBox::split(SG_BBox &left, SG_BBox &right) const -{ - MT_Scalar sizex = m_max[0] - m_min[0]; - MT_Scalar sizey = m_max[1] - m_min[1]; - MT_Scalar sizez = m_max[2] - m_min[2]; - if (sizex < sizey) - { - if (sizey > sizez) - { - left.m_min = m_min; - left.m_max[0] = m_max[0]; - left.m_max[1] = m_min[1] + sizey/2.0f; - left.m_max[2] = m_max[2]; - - right.m_min[0] = m_min[0]; - right.m_min[1] = m_min[1] + sizey/2.0f; - right.m_min[2] = m_min[2]; - right.m_max = m_max; - std::cout << "splity" << std::endl; - } - else { - left.m_min = m_min; - left.m_max[0] = m_max[0]; - left.m_max[1] = m_max[1]; - left.m_max[2] = m_min[2] + sizez/2.0f; - - right.m_min[0] = m_min[0]; - right.m_min[1] = m_min[1]; - right.m_min[2] = m_min[2] + sizez/2.0f; - right.m_max = m_max; - std::cout << "splitz" << std::endl; - } - } - else { - if (sizex > sizez) { - left.m_min = m_min; - left.m_max[0] = m_min[0] + sizex/2.0f; - left.m_max[1] = m_max[1]; - left.m_max[2] = m_max[2]; - - right.m_min[0] = m_min[0] + sizex/2.0f; - right.m_min[1] = m_min[1]; - right.m_min[2] = m_min[2]; - right.m_max = m_max; - std::cout << "splitx" << std::endl; - } - else { - left.m_min = m_min; - left.m_max[0] = m_max[0]; - left.m_max[1] = m_max[1]; - left.m_max[2] = m_min[2] + sizez/2.0f; - - right.m_min[0] = m_min[0]; - right.m_min[1] = m_min[1]; - right.m_min[2] = m_min[2] + sizez/2.0f; - right.m_max = m_max; - std::cout << "splitz" << std::endl; - } - } - - //std::cout << "Left: " << left.m_min << " -> " << left.m_max << " Right: " << right.m_min << " -> " << right.m_max << std::endl; + point[1] >= m_min[1] && point[1] <= m_max[1] && + point[2] >= m_min[2] && point[2] <= m_max[2]; } diff --git a/source/gameengine/SceneGraph/SG_BBox.h b/source/gameengine/SceneGraph/SG_BBox.h index 65fa417d25a6..d6819e642a30 100644 --- a/source/gameengine/SceneGraph/SG_BBox.h +++ b/source/gameengine/SceneGraph/SG_BBox.h @@ -33,18 +33,7 @@ #ifndef __SG_BBOX_H__ #define __SG_BBOX_H__ -#include "MT_Scalar.h" -#include "MT_Point3.h" -#include "MT_Vector3.h" -#include "MT_Transform.h" - -#include - -#ifdef WITH_CXX_GUARDEDALLOC -#include "MEM_guardedalloc.h" -#endif - -class SG_Node; +#include "mathfu.h" /** * Bounding box class. @@ -53,91 +42,38 @@ class SG_Node; */ class SG_BBox { - MT_Point3 m_min; - MT_Point3 m_max; -public: - typedef enum { INSIDE, INTERSECT, OUTSIDE } intersect; - SG_BBox(); - SG_BBox(const MT_Point3 &min, const MT_Point3 &max); - SG_BBox(const SG_BBox &other, const MT_Transform &world); - SG_BBox(const SG_BBox &other); - ~SG_BBox(); - - /** - * Enlarges the bounding box to contain the specified point. - */ - SG_BBox& operator +=(const MT_Point3 &point); - /** - * Enlarges the bounding box to contain the specified bound box. - */ - SG_BBox& operator +=(const SG_BBox &bbox); +private: + /// AABB data. + mt::vec3 m_min; + mt::vec3 m_max; - SG_BBox operator + (const SG_BBox &bbox2) const; -#if 0 - /** - * Translates the bounding box. - */ - void translate(const MT_Vector3 &dx); - /** - * Scales the bounding box about the optional point. - */ - void scale(const MT_Vector3 &size, const MT_Point3 &point = MT_Point3(0.0f, 0.0f, 0.0f)); -#endif - SG_BBox transform(const MT_Transform &world) const; - /** - * Computes the volume of the bounding box. - */ - MT_Scalar volume() const; + /// Sphere data. + mt::vec3 m_center; + float m_radius; - /** - * Test if the given point is inside this bounding box. - */ - bool inside(const MT_Point3 &point) const; + /// Update sphere data with current AABB data. + void UpdateSphere(); - /** - * Test if the given bounding box is inside this bounding box. - */ - bool inside(const SG_BBox &other) const; - - /** - * Test if the given bounding box is outside this bounding box. - */ - bool outside(const SG_BBox &other) const; - - /** - * Test if the given bounding box intersects this bounding box. - */ - bool intersects(const SG_BBox &other) const; - - /** - * Test the given bounding box with this bounding box. - */ - intersect test(const SG_BBox &other) const; +public: + SG_BBox(); + SG_BBox(const mt::vec3 &min, const mt::vec3 &max); + ~SG_BBox() = default; - /** - * Get the eight points that define this bounding box. - * - * \param world a world transform to apply to the produced points bounding box. - */ - void get(MT_Point3 *box, const MT_Transform &world) const; - /** - * Get the eight points that define this axis aligned bounding box. - * This differs from SG_BBox::get() in that the produced box will be world axis aligned. - * The maximum & minimum local points will be transformed *before* splitting to 8 points. - * \param world a world transform to be applied. - */ - void getaa(MT_Point3 *box, const MT_Transform &world) const; + const mt::vec3& GetCenter() const; + const float GetRadius() const; - void getmm(MT_Point3 *box, const MT_Transform &world) const; + const mt::vec3& GetMin() const; + const mt::vec3& GetMax() const; - void split(SG_BBox &left, SG_BBox &right) const; + void Get(mt::vec3& min, mt::vec3& max) const; - friend class SG_Tree; + void SetMin(const mt::vec3& min); + void SetMax(const mt::vec3& max); + void Set(const mt::vec3& min, const mt::vec3& max); -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("GE:SG_BBox") -#endif + /// Test if the given point is inside this bounding box. + bool Inside(const mt::vec3& point) const; }; -#endif /* __SG_BBOX_H__ */ +#endif // __SG_BBOX_H__ diff --git a/source/gameengine/SceneGraph/SG_Controller.cpp b/source/gameengine/SceneGraph/SG_Controller.cpp index 1731b572fbda..875ee2c6bb79 100644 --- a/source/gameengine/SceneGraph/SG_Controller.cpp +++ b/source/gameengine/SceneGraph/SG_Controller.cpp @@ -30,17 +30,47 @@ */ #include "SG_Controller.h" +#include "SG_Interpolator.h" - void -SG_Controller:: -SetObject(SG_IObject* obj) +#include // For intptr_t. + +SG_Controller::SG_Controller() + :m_modified(true), + m_time(0.0) { - m_pObject = obj; // no checks yet ? } - void -SG_Controller:: -ClearObject( -) { - m_pObject = NULL; +bool SG_Controller::Update(SG_Node *node) +{ + if (!m_modified) { + return false; + } + + m_modified = false; + + for (SG_Interpolator& interp : m_interpolators) { + interp.Execute(m_time); + } + + return true; +} + +void SG_Controller::SetSimulatedTime(double time) +{ + m_time = time; + m_modified = true; +} + +void SG_Controller::SetOption(SG_Controller::SG_ControllerOption option, bool value) +{ +} + +void SG_Controller::AddInterpolator(const SG_Interpolator& interp) +{ + m_interpolators.push_back(interp); +} + +bool SG_Controller::Empty() const +{ + return m_interpolators.empty(); } diff --git a/source/gameengine/SceneGraph/SG_Controller.h b/source/gameengine/SceneGraph/SG_Controller.h index 000be4f871a0..cd06cdaf8bfd 100644 --- a/source/gameengine/SceneGraph/SG_Controller.h +++ b/source/gameengine/SceneGraph/SG_Controller.h @@ -35,90 +35,57 @@ #ifndef __SG_CONTROLLER_H__ #define __SG_CONTROLLER_H__ -#include "SG_IObject.h" +#include "SG_Interpolator.h" + +class SG_Node; /** * A scenegraph controller */ class SG_Controller { + friend SG_Node; public: - SG_Controller( - ) : - m_pObject(NULL) { - } - - virtual - ~SG_Controller( - ) {}; - - virtual - bool - Update( - double time - )=0; - - virtual - void - SetObject ( - SG_IObject* object - ); - - void - ClearObject( - ); - - virtual - void - SetSimulatedTime( - double time - )=0; - - virtual - SG_Controller* - GetReplica( - class SG_Node* destnode - )=0; - - /** - * Hacky way of passing options to specific controllers - * \param option An integer identifying the option. - * \param value The value of this option. - * \attention This has been placed here to give sca-elements - * \attention some control over the controllers. This is - * \attention necessary because the identity of the controller - * \attention is lost on the way here. - */ - virtual - void - SetOption( - int option, - int value - )=0; - /** * Option-identifiers: SG_CONTR__